/ lib / krb5 / get_in_tkt.c
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  				   KRB5_KU_AS_REP_ENC_PART,
509  				   NULL,
510  				   nonce,
511  				   flags,
512  				   NULL,
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 */