copyright notice updates from 1.1 branch
[krb5.git] / src / lib / krb5 / krb / mk_req_ext.c
1 /*
2  * lib/krb5/krb/mk_req_ext.c
3  *
4  * Copyright 1990,1991 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.  Furthermore if you modify this software you must label
20  * your software as modified software and not distribute it in such a
21  * fashion that it might be confused with the original M.I.T. software.
22  * M.I.T. makes no representations about the suitability of
23  * this software for any purpose.  It is provided "as is" without express
24  * or implied warranty.
25  * 
26  *
27  * krb5_mk_req_extended()
28  */
29
30
31 #include "k5-int.h"
32 #include "auth_con.h"
33
34 /*
35  Formats a KRB_AP_REQ message into outbuf, with more complete options than
36  krb_mk_req.
37
38  outbuf, ap_req_options, checksum, and ccache are used in the
39  same fashion as for krb5_mk_req.
40
41  creds is used to supply the credentials (ticket and session key) needed
42  to form the request.
43
44  if creds->ticket has no data (length == 0), then a ticket is obtained
45  from either the cache or the TGS, passing creds to krb5_get_credentials().
46  kdc_options specifies the options requested for the ticket to be used.
47  If a ticket with appropriate flags is not found in the cache, then these
48  options are passed on in a request to an appropriate KDC.
49
50  ap_req_options specifies the KRB_AP_REQ options desired.
51
52  if ap_req_options specifies AP_OPTS_USE_SESSION_KEY, then creds->ticket
53  must contain the appropriate ENC-TKT-IN-SKEY ticket.
54
55  checksum specifies the checksum to be used in the authenticator.
56
57  The outbuf buffer storage is allocated, and should be freed by the
58  caller when finished.
59
60  On an error return, the credentials pointed to by creds might have been
61  augmented with additional fields from the obtained credentials; the entire
62  credentials should be released by calling krb5_free_creds().
63
64  returns system errors
65 */
66
67 static krb5_error_code 
68 krb5_generate_authenticator PROTOTYPE((krb5_context,
69                                        krb5_authenticator *, krb5_principal,
70                                        const krb5_checksum *, krb5_keyblock *,
71                                        krb5_int32, krb5_authdata ** ));
72
73 KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
74 krb5_mk_req_extended(context, auth_context, ap_req_options, in_data, in_creds,
75                      outbuf)
76     krb5_context          context;
77     krb5_auth_context   FAR * auth_context;
78     const krb5_flags      ap_req_options;
79     krb5_data           FAR * in_data;
80     krb5_creds          FAR * in_creds;
81     krb5_data           FAR * outbuf;
82 {
83     krb5_error_code       retval;
84     krb5_checksum         checksum;
85     krb5_checksum         *checksump = 0;
86     krb5_auth_context     new_auth_context;
87
88     krb5_ap_req request;
89     krb5_data *scratch = 0;
90     krb5_data *toutbuf;
91
92     request.ap_options = ap_req_options & AP_OPTS_WIRE_MASK;
93     request.authenticator.ciphertext.data = 0;
94     request.ticket = 0;
95     
96     if (!in_creds->ticket.length) 
97         return(KRB5_NO_TKT_SUPPLIED);
98
99     /* we need a native ticket */
100     if ((retval = decode_krb5_ticket(&(in_creds)->ticket, &request.ticket)))
101         return(retval);
102     
103     /* verify that the ticket is not expired */
104     if ((retval = krb5_validate_times(context, &in_creds->times)) != 0)
105         goto cleanup;
106
107     /* generate auth_context if needed */
108     if (*auth_context == NULL) {
109         if ((retval = krb5_auth_con_init(context, &new_auth_context)))
110             goto cleanup;
111         *auth_context = new_auth_context;
112     }
113
114     /* set auth context keyblock */
115     if ((retval = krb5_copy_keyblock(context, &in_creds->keyblock, 
116                                      &((*auth_context)->keyblock))))
117         goto cleanup;
118
119     /* generate seq number if needed */
120     if ((((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE)
121      || ((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE))
122       && ((*auth_context)->local_seq_number == 0)) 
123         if ((retval = krb5_generate_seq_number(context, &in_creds->keyblock,
124                                      &(*auth_context)->local_seq_number)))
125             goto cleanup;
126         
127
128     /* generate subkey if needed */
129     if ((ap_req_options & AP_OPTS_USE_SUBKEY)&&(!(*auth_context)->local_subkey))
130         if ((retval = krb5_generate_subkey(context, &(in_creds)->keyblock, 
131                                            &(*auth_context)->local_subkey)))
132             goto cleanup;
133
134     if (in_data) {
135         if ((*auth_context)->req_cksumtype == 0x8003) {
136             /* XXX Special hack for GSSAPI */
137             checksum.checksum_type = 0x8003;
138             checksum.length = in_data->length;
139             checksum.contents = (krb5_octet *) in_data->data;
140         } else {
141             if ((retval = krb5_c_make_checksum(context, 
142                                                (*auth_context)->req_cksumtype,
143                                                (*auth_context)->keyblock,
144                                                KRB5_KEYUSAGE_AP_REQ_AUTH_CKSUM,
145                                                in_data, &checksum)))
146                 goto cleanup_cksum;
147         }
148         checksump = &checksum;
149     }
150
151     /* Generate authenticator */
152     if (((*auth_context)->authentp = (krb5_authenticator *)malloc(sizeof(
153                                         krb5_authenticator))) == NULL) {
154         retval = ENOMEM;
155         goto cleanup_cksum;
156     }
157
158     if ((retval = krb5_generate_authenticator(context,
159                                               (*auth_context)->authentp,
160                                               (in_creds)->client, checksump,
161                                               (*auth_context)->local_subkey,
162                                               (*auth_context)->local_seq_number,
163                                               (in_creds)->authdata)))
164         goto cleanup_cksum;
165         
166     /* encode the authenticator */
167     if ((retval = encode_krb5_authenticator((*auth_context)->authentp,
168                                             &scratch)))
169         goto cleanup_cksum;
170     
171     /* Null out these fields, to prevent pointer sharing problems;
172      * they were supplied by the caller
173      */
174     (*auth_context)->authentp->client = NULL;
175     (*auth_context)->authentp->checksum = NULL;
176     (*auth_context)->authentp->authorization_data = NULL;
177
178     /* call the encryption routine */
179     if ((retval = krb5_encrypt_helper(context, &in_creds->keyblock,
180                                       KRB5_KEYUSAGE_AP_REQ_AUTH,
181                                       scratch, &request.authenticator)))
182         goto cleanup_cksum;
183
184     if ((retval = encode_krb5_ap_req(&request, &toutbuf)))
185         goto cleanup_cksum;
186 #ifdef HAVE_C_STRUCTURE_ASSIGNMENT
187     *outbuf = *toutbuf;
188 #else
189     memcpy(outbuf, toutbuf, sizeof(krb5_data));
190 #endif
191
192     krb5_xfree(toutbuf);
193
194 cleanup_cksum:
195     if (checksump && checksump->checksum_type != 0x8003)
196       free(checksump->contents);
197
198 cleanup:
199     if (request.ticket)
200         krb5_free_ticket(context, request.ticket);
201     if (request.authenticator.ciphertext.data) {
202         (void) memset(request.authenticator.ciphertext.data, 0,
203                       request.authenticator.ciphertext.length);
204         free(request.authenticator.ciphertext.data);
205     }
206     if (scratch) {
207         memset(scratch->data, 0, scratch->length);
208         krb5_xfree(scratch->data);
209         krb5_xfree(scratch);
210     }
211     return retval;
212 }
213
214 static krb5_error_code
215 krb5_generate_authenticator(context, authent, client, cksum, key, seq_number, authorization)
216     krb5_context context;
217     krb5_authenticator *authent;
218     krb5_principal client;
219     const krb5_checksum *cksum;
220     krb5_keyblock *key;
221     krb5_int32 seq_number;
222     krb5_authdata **authorization;
223 {
224     krb5_error_code retval;
225     
226     authent->client = client;
227     authent->checksum = (krb5_checksum *)cksum;
228     if (key) {
229         retval = krb5_copy_keyblock(context, key, &authent->subkey);
230         if (retval)
231             return retval;
232     } else
233         authent->subkey = 0;
234     authent->seq_number = seq_number;
235     authent->authorization_data = authorization;
236
237     return(krb5_us_timeofday(context, &authent->ctime, &authent->cusec));
238 }