Windows global stuff:
[krb5.git] / src / lib / krb5 / krb / get_fcreds.c
1 /*
2  * lib/krb5/krb/get_fcreds.c
3  *
4  * Copyright 1994 by the Massachusetts Institute of Technology.
5  * All Rights Reserved.
6  *
7  * Export of this software from the United States of America may
8  *   require a specific license from the United States Government.
9  *   It is the responsibility of any person or organization contemplating
10  *   export to obtain such a license before exporting.
11  * 
12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13  * distribute this software and its documentation for any purpose and
14  * without fee is hereby granted, provided that the above copyright
15  * notice appear in all copies and that both that copyright notice and
16  * this permission notice appear in supporting documentation, and that
17  * the name of M.I.T. not be used in advertising or publicity pertaining
18  * to distribution of the software without specific, written prior
19  * permission.  M.I.T. makes no representations about the suitability of
20  * this software for any purpose.  It is provided "as is" without express
21  * or implied warranty.
22  * 
23  * krb5_get_for_creds()
24  */
25
26 /* XXX This API is going to change; what's here isn't general enough! XXX */
27 /* XXX Once we finalize the API, it should go into func-proto.h and */
28 /* into the API doc. */
29
30 /* General-purpose forwarding routines. These routines may be put into */
31 /* libkrb5.a to allow widespread use */ 
32
33 #define NEED_SOCKETS
34 #include "k5-int.h"
35 #include <stdio.h>
36
37 #define KRB5_DEFAULT_LIFE 60*60*8   /* 8 hours */
38 /* helper function: convert flags to necessary KDC options */
39 #define flags2options(flags) (flags & KDC_TKT_COMMON_MASK)
40
41 /* Get a TGT for use at the remote host */
42 krb5_error_code
43 krb5_get_for_creds(context, sumtype, rhost, client, enc_key, 
44                    forwardable, outbuf)
45     krb5_context context;
46     const krb5_cksumtype sumtype;
47     char *rhost;
48     krb5_principal client;
49     krb5_keyblock *enc_key;
50     int forwardable;      /* Should forwarded TGT also be forwardable? */
51     krb5_data *outbuf;
52 {
53     struct hostent *hp;
54     krb5_enctype etype;
55     krb5_address **addrs;
56     krb5_error_code retval;
57     krb5_kdc_rep *dec_rep = 0;
58     krb5_error *err_reply;
59     krb5_response tgsrep;
60     krb5_creds creds, tgt;
61     krb5_ccache cc;
62     krb5_flags kdcoptions;
63     krb5_timestamp now;
64     char *remote_host = 0;
65     char **hrealms = 0;
66     int i;
67
68     memset((char *)&creds, 0, sizeof(creds));
69     memset((char *)&tgsrep, 0, sizeof(tgsrep));
70
71     if (!rhost || !(hp = gethostbyname(rhost)))
72       return KRB5_ERR_BAD_HOSTNAME;
73
74     remote_host = (char *) malloc(strlen(hp->h_name)+1);
75     if (!remote_host) {
76         retval = ENOMEM;
77         goto errout;
78     }   
79     strcpy(remote_host, hp->h_name);
80
81     if (retval = krb5_get_host_realm(context, remote_host, &hrealms))
82         goto errout;
83     if (!hrealms[0]) {
84         retval = KRB5_ERR_HOST_REALM_UNKNOWN;
85         goto errout;
86     }
87
88     /* Count elements */
89     for(i=0; hp->h_addr_list[i]; i++);
90
91     addrs = (krb5_address **) malloc ((i+1)*sizeof(*addrs));
92     if (!addrs) {
93         retval = ENOMEM;
94         goto errout;
95     }
96     memset(addrs, 0, (i+1)*sizeof(*addrs));
97     
98     for(i=0; hp->h_addr_list[i]; i++) {
99         addrs[i] = (krb5_address *) malloc(sizeof(krb5_address));
100         if (!addrs[i]) {
101             retval = ENOMEM;
102             goto errout;
103         }
104         addrs[i]->addrtype = hp->h_addrtype;
105         addrs[i]->length   = hp->h_length;
106         addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
107         if (!addrs[i]->contents) {
108             retval = ENOMEM;
109             goto errout;
110         }
111         memcpy ((char *)addrs[i]->contents, hp->h_addr_list[i],
112                 addrs[i]->length);
113     }
114     addrs[i] = 0;
115
116     if (retval = krb5_copy_principal(context, client, &creds.client))
117         goto errout;
118     
119     if (retval = krb5_build_principal_ext(context, &creds.server,
120                                           strlen(hrealms[0]),
121                                           hrealms[0],
122                                           KRB5_TGS_NAME_SIZE,
123                                           KRB5_TGS_NAME,
124                                           client->realm.length,
125                                           client->realm.data,
126                                           0))
127         goto errout;
128         
129     creds.times.starttime = 0;
130     if (retval = krb5_timeofday(context, &now))
131         goto errout;
132
133     creds.times.endtime = now + KRB5_DEFAULT_LIFE;
134     creds.times.renew_till = 0;
135     
136     if (retval = krb5_cc_default(context, &cc))
137         goto errout;
138
139     /* fetch tgt directly from cache */
140     retval = krb5_cc_retrieve_cred (context, cc, KRB5_TC_MATCH_SRV_NAMEONLY,
141                                     &creds, &tgt);
142     krb5_cc_close(context, cc);
143     if (retval)
144         goto errout;
145
146     /* tgt->client must be equal to creds.client */
147     if (!krb5_principal_compare(context, tgt.client, creds.client)) {
148         retval = KRB5_PRINC_NOMATCH;
149         goto errout;
150     }
151
152     if (!tgt.ticket.length) {
153         retval = KRB5_NO_TKT_SUPPLIED;
154         goto errout;
155     }
156
157     kdcoptions = flags2options(tgt.ticket_flags)|KDC_OPT_FORWARDED;
158
159     if (!forwardable) /* Reset KDC_OPT_FORWARDABLE */
160       kdcoptions &= ~(KDC_OPT_FORWARDABLE);
161
162     if (retval = krb5_send_tgs(context, kdcoptions, &creds.times, NULL, 
163                                sumtype, tgt.server, addrs, creds.authdata,
164                                0,               /* no padata */
165                                0,               /* no second ticket */
166                                &tgt, &tgsrep))
167         goto errout;
168
169     switch (tgsrep.message_type) {
170     case KRB5_TGS_REP:
171         break;
172     case KRB5_ERROR:
173     default:
174         if (!krb5_is_krb_error(&tgsrep.response)) {
175             retval = KRB5KRB_AP_ERR_MSG_TYPE;
176             goto errout;
177         } else {
178             if (retval = decode_krb5_error(&tgsrep.response, &err_reply))
179                 goto errout;
180         }
181
182         retval = err_reply->error + ERROR_TABLE_BASE_krb5;
183
184         krb5_free_error(context, err_reply);
185         goto errout;
186     }
187     
188     etype = tgt.keyblock.etype;
189     if (retval = krb5_decode_kdc_rep(context, &tgsrep.response,
190                                      &tgt.keyblock,
191                                      etype, /* enctype */
192                                      &dec_rep))
193         goto errout;
194     
195     if (dec_rep->msg_type != KRB5_TGS_REP) {
196         retval = KRB5KRB_AP_ERR_MSG_TYPE;
197         goto errout;
198     }
199     
200     /* now it's decrypted and ready for prime time */
201
202     if (!krb5_principal_compare(context, dec_rep->client, tgt.client)) {
203         retval = KRB5_KDCREP_MODIFIED;
204         goto errout;
205     }
206
207     retval = krb5_mk_cred(context, dec_rep, etype, enc_key, 0, 0, outbuf);
208     
209 errout:
210     if (remote_host)
211         free(remote_host);
212     if (hrealms)
213         krb5_xfree(hrealms);
214     if (addrs)
215         krb5_free_addresses(context, addrs);
216     krb5_free_cred_contents(context, &creds);
217     if (tgsrep.response.data)
218         free(tgsrep.response.data);
219     if (dec_rep)
220         krb5_free_kdc_rep(context, dec_rep); 
221     return retval;
222 }