Changed krb5_generate_authenticator to accept a princiapl instead of
[krb5.git] / src / lib / krb5 / krb / mk_req_ext.c
1 /*
2  * $Source$
3  * $Author$
4  *
5  * Copyright 1990,1991 by the Massachusetts Institute of Technology.
6  * All Rights Reserved.
7  *
8  * Export of this software from the United States of America may
9  *   require a specific license from the United States Government.
10  *   It is the responsibility of any person or organization contemplating
11  *   export to obtain such a license before exporting.
12  * 
13  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
14  * distribute this software and its documentation for any purpose and
15  * without fee is hereby granted, provided that the above copyright
16  * notice appear in all copies and that both that copyright notice and
17  * this permission notice appear in supporting documentation, and that
18  * the name of M.I.T. not be used in advertising or publicity pertaining
19  * to distribution of the software without specific, written prior
20  * permission.  M.I.T. makes no representations about the suitability of
21  * this software for any purpose.  It is provided "as is" without express
22  * or implied warranty.
23  * 
24  *
25  * krb5_mk_req_extended()
26  */
27
28 #if !defined(lint) && !defined(SABER)
29 static char rcsid_mk_req_ext_c[] =
30 "$Id$";
31 #endif  /* !lint & !SABER */
32
33 #include <krb5/krb5.h>
34 #include <krb5/asn1.h>
35
36 #include <krb5/libos.h>
37 #include <krb5/los-proto.h>
38
39 #include <krb5/ext-proto.h>
40
41 /*
42  Formats a KRB_AP_REQ message into outbuf, with more complete options than
43  krb_mk_req.
44
45  outbuf, ap_req_options, checksum, and ccache are used in the
46  same fashion as for krb5_mk_req.
47
48  creds is used to supply the credentials (ticket and session key) needed
49  to form the request.
50
51  if creds->ticket has no data (length == 0), then a ticket is obtained
52  from either the cache or the TGS, passing creds to krb5_get_credentials().
53  kdc_options specifies the options requested for the ticket to be used.
54  If a ticket with appropriate flags is not found in the cache, then these
55  options are passed on in a request to an appropriate KDC.
56
57  ap_req_options specifies the KRB_AP_REQ options desired.
58
59  if ap_req_options specifies AP_OPTS_USE_SESSION_KEY, then creds->ticket
60  must contain the appropriate ENC-TKT-IN-SKEY ticket.
61
62  checksum specifies the checksum to be used in the authenticator.
63
64  The outbuf buffer storage is allocated, and should be freed by the
65  caller when finished.
66
67  On an error return, the credentials pointed to by creds might have been
68  augmented with additional fields from the obtained credentials; the entire
69  credentials should be released by calling krb5_free_creds().
70
71  returns system errors
72 */
73
74 krb5_error_code
75 krb5_mk_req_extended(ap_req_options, checksum, kdc_options,
76                      sequence, newkey, ccache, creds, authentp, outbuf)
77 const krb5_flags ap_req_options;
78 const krb5_checksum *checksum;
79 const krb5_flags kdc_options;
80 krb5_int32 sequence;
81 krb5_keyblock **newkey;
82 krb5_ccache ccache;
83 krb5_creds *creds;
84 krb5_authenticator *authentp;
85 krb5_data *outbuf;
86 {
87     krb5_error_code retval;
88     krb5_ap_req request;
89     krb5_authenticator authent;
90     krb5_data *scratch;
91     krb5_enctype etype;
92     krb5_encrypt_block eblock;
93     krb5_data *toutbuf;
94
95     if ((ap_req_options & AP_OPTS_USE_SESSION_KEY) &&
96         !creds->ticket.length)
97         return(KRB5_NO_TKT_SUPPLIED);
98
99     if (!creds->ticket.length) {
100         /* go get creds */
101         if (retval = krb5_get_credentials(kdc_options,
102                                           ccache,
103                                           creds))
104             return(retval);
105     }
106     /* verify a valid etype is available */
107     if (!valid_keytype(creds->keyblock.keytype))
108         return KRB5_PROG_KEYTYPE_NOSUPP;
109
110     etype = krb5_keytype_array[creds->keyblock.keytype]->system->proto_enctype;
111
112     if (!valid_etype(etype))
113         return KRB5_PROG_ETYPE_NOSUPP;
114
115     request.ap_options = ap_req_options;
116     /* we need a native ticket */
117     if (retval = decode_krb5_ticket(&creds->ticket, &request.ticket))
118         return(retval);
119
120 #define cleanup_ticket() krb5_free_ticket(request.ticket)
121     if (newkey) {
122         if (retval = krb5_generate_subkey(&creds->keyblock, newkey)) {
123             cleanup_ticket();
124             return retval;
125         }
126     }
127 #define cleanup_key() {if (newkey) krb5_free_keyblock(*newkey);}
128     if (retval = krb5_generate_authenticator(&authent, creds->client, checksum,
129                                              newkey ? *newkey : 0,
130                                              sequence, creds->authdata)) {
131         cleanup_key();
132         cleanup_ticket();
133         return retval;
134     }
135     if (authentp) {
136             *authentp = authent;
137             /* Null out these fields, to prevent pointer sharing problems 
138              * The caller won't need these fields anyway, since they were
139              * supplied by the caller
140              */
141             authentp->client = NULL;
142             authentp->checksum = NULL; 
143     }
144     /* encode it before encrypting */
145     retval = encode_krb5_authenticator(&authent, &scratch);
146     if (retval) {
147         cleanup_key();
148         cleanup_ticket();
149         return(retval);
150     }
151
152 #define cleanup_scratch() { (void) memset(scratch->data, 0, scratch->length); \
153 krb5_free_data(scratch); }
154
155     /* put together an eblock for this encryption */
156
157     krb5_use_cstype(&eblock, etype);
158     request.authenticator.etype = etype;
159     request.authenticator.kvno = 0; /* XXX user set? */
160     request.authenticator.ciphertext.length =
161         krb5_encrypt_size(scratch->length, eblock.crypto_entry);
162     /* add padding area, and zero it */
163     if (!(scratch->data = realloc(scratch->data,
164                                   request.authenticator.ciphertext.length))) {
165         /* may destroy scratch->data */
166         xfree(scratch);
167         retval = ENOMEM;
168         goto clean_ticket;
169     }
170     memset(scratch->data + scratch->length, 0,
171           request.authenticator.ciphertext.length - scratch->length);
172     if (!(request.authenticator.ciphertext.data =
173           malloc(request.authenticator.ciphertext.length))) {
174         retval = ENOMEM;
175         goto clean_scratch;
176     }
177
178 #define cleanup_encpart() {\
179 (void) memset(request.authenticator.ciphertext.data, 0,\
180              request.authenticator.ciphertext.length); \
181 free(request.authenticator.ciphertext.data); \
182 request.authenticator.ciphertext.length = 0; \
183 request.authenticator.ciphertext.data = 0;}
184
185     /* do any necessary key pre-processing */
186     if (retval = krb5_process_key(&eblock, &creds->keyblock)) {
187         goto clean_encpart;
188     }
189
190 #define cleanup_prockey() {(void) krb5_finish_key(&eblock);}
191
192     /* call the encryption routine */
193     if (retval = krb5_encrypt((krb5_pointer) scratch->data,
194                               (krb5_pointer) request.authenticator.ciphertext.data,
195                               scratch->length, &eblock, 0)) {
196         goto clean_prockey;
197     }
198
199     /* authenticator now assembled-- do some cleanup */
200     cleanup_scratch();
201
202     if (retval = krb5_finish_key(&eblock)) {
203         cleanup_encpart();
204         return retval;
205     }
206
207     if (!(retval = encode_krb5_ap_req(&request, &toutbuf))) {
208         *outbuf = *toutbuf;
209         xfree(toutbuf);
210     }
211     cleanup_ticket();
212     cleanup_encpart();
213     return retval;
214
215  clean_prockey:
216     cleanup_prockey();
217  clean_encpart:
218     cleanup_encpart();
219  clean_scratch:
220     cleanup_scratch();
221  clean_ticket:
222     cleanup_key();
223     cleanup_ticket();
224
225     return retval;
226 }
227
228 static krb5_error_code
229 krb5_generate_authenticator(authent, client, cksum, key, seq_number, authorization)
230 krb5_authenticator *authent;
231 krb5_principal client;
232 const krb5_checksum *cksum;
233 krb5_keyblock *key;
234 krb5_int32 seq_number;
235 krb5_authdata **authorization;
236 {
237     authent->client = client;
238     authent->checksum = (krb5_checksum *)cksum;
239     authent->subkey = key;
240     authent->seq_number = seq_number;
241     authent->authorization_data = authorization;
242
243     return(krb5_us_timeofday(&authent->ctime, &authent->cusec));
244 }