]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - crypto/heimdal/lib/krb5/get_in_tkt.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / crypto / heimdal / lib / krb5 / get_in_tkt.c
1 /*
2  * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #include "krb5_locl.h"
35
36 #ifndef HEIMDAL_SMALLER
37
38 static krb5_error_code
39 make_pa_enc_timestamp(krb5_context context, PA_DATA *pa,
40                       krb5_enctype etype, krb5_keyblock *key)
41 {
42     PA_ENC_TS_ENC p;
43     unsigned char *buf;
44     size_t buf_size;
45     size_t len = 0;
46     EncryptedData encdata;
47     krb5_error_code ret;
48     int32_t usec;
49     int usec2;
50     krb5_crypto crypto;
51
52     krb5_us_timeofday (context, &p.patimestamp, &usec);
53     usec2         = usec;
54     p.pausec      = &usec2;
55
56     ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC, buf, buf_size, &p, &len, ret);
57     if (ret)
58         return ret;
59     if(buf_size != len)
60         krb5_abortx(context, "internal error in ASN.1 encoder");
61     ret = krb5_crypto_init(context, key, 0, &crypto);
62     if (ret) {
63         free(buf);
64         return ret;
65     }
66     ret = krb5_encrypt_EncryptedData(context,
67                                      crypto,
68                                      KRB5_KU_PA_ENC_TIMESTAMP,
69                                      buf,
70                                      len,
71                                      0,
72                                      &encdata);
73     free(buf);
74     krb5_crypto_destroy(context, crypto);
75     if (ret)
76         return ret;
77
78     ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_size, &encdata, &len, ret);
79     free_EncryptedData(&encdata);
80     if (ret)
81         return ret;
82     if(buf_size != len)
83         krb5_abortx(context, "internal error in ASN.1 encoder");
84     pa->padata_type = KRB5_PADATA_ENC_TIMESTAMP;
85     pa->padata_value.length = len;
86     pa->padata_value.data = buf;
87     return 0;
88 }
89
90 static krb5_error_code
91 add_padata(krb5_context context,
92            METHOD_DATA *md,
93            krb5_principal client,
94            krb5_key_proc key_proc,
95            krb5_const_pointer keyseed,
96            krb5_enctype *enctypes,
97            unsigned netypes,
98            krb5_salt *salt)
99 {
100     krb5_error_code ret;
101     PA_DATA *pa2;
102     krb5_salt salt2;
103     krb5_enctype *ep;
104     size_t i;
105
106     if(salt == NULL) {
107         /* default to standard salt */
108         ret = krb5_get_pw_salt (context, client, &salt2);
109         if (ret)
110             return ret;
111         salt = &salt2;
112     }
113     if (!enctypes) {
114         enctypes = context->etypes;
115         netypes = 0;
116         for (ep = enctypes; *ep != ETYPE_NULL; ep++)
117             netypes++;
118     }
119     pa2 = realloc (md->val, (md->len + netypes) * sizeof(*md->val));
120     if (pa2 == NULL) {
121         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
122         return ENOMEM;
123     }
124     md->val = pa2;
125
126     for (i = 0; i < netypes; ++i) {
127         krb5_keyblock *key;
128
129         ret = (*key_proc)(context, enctypes[i], *salt, keyseed, &key);
130         if (ret)
131             continue;
132         ret = make_pa_enc_timestamp (context, &md->val[md->len],
133                                      enctypes[i], key);
134         krb5_free_keyblock (context, key);
135         if (ret)
136             return ret;
137         ++md->len;
138     }
139     if(salt == &salt2)
140         krb5_free_salt(context, salt2);
141     return 0;
142 }
143
144 static krb5_error_code
145 init_as_req (krb5_context context,
146              KDCOptions opts,
147              krb5_creds *creds,
148              const krb5_addresses *addrs,
149              const krb5_enctype *etypes,
150              const krb5_preauthtype *ptypes,
151              const krb5_preauthdata *preauth,
152              krb5_key_proc key_proc,
153              krb5_const_pointer keyseed,
154              unsigned nonce,
155              AS_REQ *a)
156 {
157     krb5_error_code ret;
158     krb5_salt salt;
159
160     memset(a, 0, sizeof(*a));
161
162     a->pvno = 5;
163     a->msg_type = krb_as_req;
164     a->req_body.kdc_options = opts;
165     a->req_body.cname = malloc(sizeof(*a->req_body.cname));
166     if (a->req_body.cname == NULL) {
167         ret = ENOMEM;
168         krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
169         goto fail;
170     }
171     a->req_body.sname = malloc(sizeof(*a->req_body.sname));
172     if (a->req_body.sname == NULL) {
173         ret = ENOMEM;
174         krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
175         goto fail;
176     }
177     ret = _krb5_principal2principalname (a->req_body.cname, creds->client);
178     if (ret)
179         goto fail;
180     ret = _krb5_principal2principalname (a->req_body.sname, creds->server);
181     if (ret)
182         goto fail;
183     ret = copy_Realm(&creds->client->realm, &a->req_body.realm);
184     if (ret)
185         goto fail;
186
187     if(creds->times.starttime) {
188         a->req_body.from = malloc(sizeof(*a->req_body.from));
189         if (a->req_body.from == NULL) {
190             ret = ENOMEM;
191             krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
192             goto fail;
193         }
194         *a->req_body.from = creds->times.starttime;
195     }
196     if(creds->times.endtime){
197         ALLOC(a->req_body.till, 1);
198         *a->req_body.till = creds->times.endtime;
199     }
200     if(creds->times.renew_till){
201         a->req_body.rtime = malloc(sizeof(*a->req_body.rtime));
202         if (a->req_body.rtime == NULL) {
203             ret = ENOMEM;
204             krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
205             goto fail;
206         }
207         *a->req_body.rtime = creds->times.renew_till;
208     }
209     a->req_body.nonce = nonce;
210     ret = _krb5_init_etype(context,
211                            KRB5_PDU_AS_REQUEST,
212                            &a->req_body.etype.len,
213                            &a->req_body.etype.val,
214                            etypes);
215     if (ret)
216         goto fail;
217
218     /*
219      * This means no addresses
220      */
221
222     if (addrs && addrs->len == 0) {
223         a->req_body.addresses = NULL;
224     } else {
225         a->req_body.addresses = malloc(sizeof(*a->req_body.addresses));
226         if (a->req_body.addresses == NULL) {
227             ret = ENOMEM;
228             krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
229             goto fail;
230         }
231
232         if (addrs)
233             ret = krb5_copy_addresses(context, addrs, a->req_body.addresses);
234         else {
235             ret = krb5_get_all_client_addrs (context, a->req_body.addresses);
236             if(ret == 0 && a->req_body.addresses->len == 0) {
237                 free(a->req_body.addresses);
238                 a->req_body.addresses = NULL;
239             }
240         }
241         if (ret)
242             return ret;
243     }
244
245     a->req_body.enc_authorization_data = NULL;
246     a->req_body.additional_tickets = NULL;
247
248     if(preauth != NULL) {
249         size_t i;
250         ALLOC(a->padata, 1);
251         if(a->padata == NULL) {
252             ret = ENOMEM;
253             krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
254             goto fail;
255         }
256         a->padata->val = NULL;
257         a->padata->len = 0;
258         for(i = 0; i < preauth->len; i++) {
259             if(preauth->val[i].type == KRB5_PADATA_ENC_TIMESTAMP){
260                 size_t j;
261
262                 for(j = 0; j < preauth->val[i].info.len; j++) {
263                     krb5_salt *sp = &salt;
264                     if(preauth->val[i].info.val[j].salttype)
265                         salt.salttype = *preauth->val[i].info.val[j].salttype;
266                     else
267                         salt.salttype = KRB5_PW_SALT;
268                     if(preauth->val[i].info.val[j].salt)
269                         salt.saltvalue = *preauth->val[i].info.val[j].salt;
270                     else
271                         if(salt.salttype == KRB5_PW_SALT)
272                             sp = NULL;
273                         else
274                             krb5_data_zero(&salt.saltvalue);
275                     ret = add_padata(context, a->padata, creds->client,
276                                      key_proc, keyseed,
277                                      &preauth->val[i].info.val[j].etype, 1,
278                                      sp);
279                     if (ret == 0)
280                         break;
281                 }
282             }
283         }
284     } else
285     /* not sure this is the way to use `ptypes' */
286     if (ptypes == NULL || *ptypes == KRB5_PADATA_NONE)
287         a->padata = NULL;
288     else if (*ptypes ==  KRB5_PADATA_ENC_TIMESTAMP) {
289         ALLOC(a->padata, 1);
290         if (a->padata == NULL) {
291             ret = ENOMEM;
292             krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
293             goto fail;
294         }
295         a->padata->len = 0;
296         a->padata->val = NULL;
297
298         /* make a v5 salted pa-data */
299         add_padata(context, a->padata, creds->client,
300                    key_proc, keyseed, a->req_body.etype.val,
301                    a->req_body.etype.len, NULL);
302
303         /* make a v4 salted pa-data */
304         salt.salttype = KRB5_PW_SALT;
305         krb5_data_zero(&salt.saltvalue);
306         add_padata(context, a->padata, creds->client,
307                    key_proc, keyseed, a->req_body.etype.val,
308                    a->req_body.etype.len, &salt);
309     } else {
310         ret = KRB5_PREAUTH_BAD_TYPE;
311         krb5_set_error_message (context, ret,
312                                 N_("pre-auth type %d not supported", ""),
313                                *ptypes);
314         goto fail;
315     }
316     return 0;
317 fail:
318     free_AS_REQ(a);
319     return ret;
320 }
321
322 static int
323 set_ptypes(krb5_context context,
324            KRB_ERROR *error,
325            const krb5_preauthtype **ptypes,
326            krb5_preauthdata **preauth)
327 {
328     static krb5_preauthdata preauth2;
329     static krb5_preauthtype ptypes2[] = { KRB5_PADATA_ENC_TIMESTAMP, KRB5_PADATA_NONE };
330
331     if(error->e_data) {
332         METHOD_DATA md;
333         size_t i;
334         decode_METHOD_DATA(error->e_data->data,
335                            error->e_data->length,
336                            &md,
337                            NULL);
338         for(i = 0; i < md.len; i++){
339             switch(md.val[i].padata_type){
340             case KRB5_PADATA_ENC_TIMESTAMP:
341                 *ptypes = ptypes2;
342                 break;
343             case KRB5_PADATA_ETYPE_INFO:
344                 *preauth = &preauth2;
345                 ALLOC_SEQ(*preauth, 1);
346                 (*preauth)->val[0].type = KRB5_PADATA_ENC_TIMESTAMP;
347                 decode_ETYPE_INFO(md.val[i].padata_value.data,
348                                   md.val[i].padata_value.length,
349                                   &(*preauth)->val[0].info,
350                                   NULL);
351                 break;
352             default:
353                 break;
354             }
355         }
356         free_METHOD_DATA(&md);
357     } else {
358         *ptypes = ptypes2;
359     }
360     return(1);
361 }
362
363 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
364 krb5_get_in_cred(krb5_context context,
365                  krb5_flags options,
366                  const krb5_addresses *addrs,
367                  const krb5_enctype *etypes,
368                  const krb5_preauthtype *ptypes,
369                  const krb5_preauthdata *preauth,
370                  krb5_key_proc key_proc,
371                  krb5_const_pointer keyseed,
372                  krb5_decrypt_proc decrypt_proc,
373                  krb5_const_pointer decryptarg,
374                  krb5_creds *creds,
375                  krb5_kdc_rep *ret_as_reply)
376     KRB5_DEPRECATED_FUNCTION("Use X instead")
377 {
378     krb5_error_code ret;
379     AS_REQ a;
380     krb5_kdc_rep rep;
381     krb5_data req, resp;
382     size_t len = 0;
383     krb5_salt salt;
384     krb5_keyblock *key;
385     size_t size;
386     KDCOptions opts;
387     PA_DATA *pa;
388     krb5_enctype etype;
389     krb5_preauthdata *my_preauth = NULL;
390     unsigned nonce;
391     int done;
392
393     opts = int2KDCOptions(options);
394
395     krb5_generate_random_block (&nonce, sizeof(nonce));
396     nonce &= 0xffffffff;
397
398     do {
399         done = 1;
400         ret = init_as_req (context,
401                            opts,
402                            creds,
403                            addrs,
404                            etypes,
405                            ptypes,
406                            preauth,
407                            key_proc,
408                            keyseed,
409                            nonce,
410                            &a);
411         if (my_preauth) {
412             free_ETYPE_INFO(&my_preauth->val[0].info);
413             free (my_preauth->val);
414             my_preauth = NULL;
415         }
416         if (ret)
417             return ret;
418
419         ASN1_MALLOC_ENCODE(AS_REQ, req.data, req.length, &a, &len, ret);
420         free_AS_REQ(&a);
421         if (ret)
422             return ret;
423         if(len != req.length)
424             krb5_abortx(context, "internal error in ASN.1 encoder");
425
426         ret = krb5_sendto_kdc (context, &req, &creds->client->realm, &resp);
427         krb5_data_free(&req);
428         if (ret)
429             return ret;
430
431         memset (&rep, 0, sizeof(rep));
432         ret = decode_AS_REP(resp.data, resp.length, &rep.kdc_rep, &size);
433         if(ret) {
434             /* let's try to parse it as a KRB-ERROR */
435             KRB_ERROR error;
436             int ret2;
437
438             ret2 = krb5_rd_error(context, &resp, &error);
439             if(ret2 && resp.data && ((char*)resp.data)[0] == 4)
440                 ret = KRB5KRB_AP_ERR_V4_REPLY;
441             krb5_data_free(&resp);
442             if (ret2 == 0) {
443                 ret = krb5_error_from_rd_error(context, &error, creds);
444                 /* if no preauth was set and KDC requires it, give it
445                    one more try */
446                 if (!ptypes && !preauth
447                     && ret == KRB5KDC_ERR_PREAUTH_REQUIRED
448 #if 0
449                         || ret == KRB5KDC_ERR_BADOPTION
450 #endif
451                     && set_ptypes(context, &error, &ptypes, &my_preauth)) {
452                     done = 0;
453                     preauth = my_preauth;
454                     krb5_free_error_contents(context, &error);
455                     krb5_clear_error_message(context);
456                     continue;
457                 }
458                 if(ret_as_reply)
459                     ret_as_reply->error = error;
460                 else
461                     free_KRB_ERROR (&error);
462                 return ret;
463             }
464             return ret;
465         }
466         krb5_data_free(&resp);
467     } while(!done);
468
469     pa = NULL;
470     etype = rep.kdc_rep.enc_part.etype;
471     if(rep.kdc_rep.padata){
472         int i = 0;
473         pa = krb5_find_padata(rep.kdc_rep.padata->val, rep.kdc_rep.padata->len,
474                               KRB5_PADATA_PW_SALT, &i);
475         if(pa == NULL) {
476             i = 0;
477             pa = krb5_find_padata(rep.kdc_rep.padata->val,
478                                   rep.kdc_rep.padata->len,
479                                   KRB5_PADATA_AFS3_SALT, &i);
480         }
481     }
482     if(pa) {
483         salt.salttype = (krb5_salttype)pa->padata_type;
484         salt.saltvalue = pa->padata_value;
485
486         ret = (*key_proc)(context, etype, salt, keyseed, &key);
487     } else {
488         /* make a v5 salted pa-data */
489         ret = krb5_get_pw_salt (context, creds->client, &salt);
490
491         if (ret)
492             goto out;
493         ret = (*key_proc)(context, etype, salt, keyseed, &key);
494         krb5_free_salt(context, salt);
495     }
496     if (ret)
497         goto out;
498
499     {
500         unsigned flags = EXTRACT_TICKET_TIMESYNC;
501         if (opts.request_anonymous)
502             flags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH;
503
504         ret = _krb5_extract_ticket(context,
505                                    &rep,
506                                    creds,
507                                    key,
508                                    keyseed,
509                                    KRB5_KU_AS_REP_ENC_PART,
510                                    NULL,
511                                    nonce,
512                                    flags,
513                                    decrypt_proc,
514                                    decryptarg);
515     }
516     memset (key->keyvalue.data, 0, key->keyvalue.length);
517     krb5_free_keyblock_contents (context, key);
518     free (key);
519
520 out:
521     if (ret == 0 && ret_as_reply)
522         *ret_as_reply = rep;
523     else
524         krb5_free_kdc_rep (context, &rep);
525     return ret;
526 }
527
528 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
529 krb5_get_in_tkt(krb5_context context,
530                 krb5_flags options,
531                 const krb5_addresses *addrs,
532                 const krb5_enctype *etypes,
533                 const krb5_preauthtype *ptypes,
534                 krb5_key_proc key_proc,
535                 krb5_const_pointer keyseed,
536                 krb5_decrypt_proc decrypt_proc,
537                 krb5_const_pointer decryptarg,
538                 krb5_creds *creds,
539                 krb5_ccache ccache,
540                 krb5_kdc_rep *ret_as_reply)
541     KRB5_DEPRECATED_FUNCTION("Use X instead")
542 {
543     krb5_error_code ret;
544
545     ret = krb5_get_in_cred (context,
546                             options,
547                             addrs,
548                             etypes,
549                             ptypes,
550                             NULL,
551                             key_proc,
552                             keyseed,
553                             decrypt_proc,
554                             decryptarg,
555                             creds,
556                             ret_as_reply);
557     if(ret)
558         return ret;
559     if (ccache)
560         ret = krb5_cc_store_cred (context, ccache, creds);
561     return ret;
562 }
563
564 #endif /* HEIMDAL_SMALLER */