/ kcm / acquire.c
acquire.c
  1  /*
  2   * Copyright (c) 2005, PADL Software Pty Ltd.
  3   * All rights reserved.
  4   *
  5   * Redistribution and use in source and binary forms, with or without
  6   * modification, are permitted provided that the following conditions
  7   * are met:
  8   *
  9   * 1. Redistributions of source code must retain the above copyright
 10   *    notice, this list of conditions and the following disclaimer.
 11   *
 12   * 2. Redistributions in binary form must reproduce the above copyright
 13   *    notice, this list of conditions and the following disclaimer in the
 14   *    documentation and/or other materials provided with the distribution.
 15   *
 16   * 3. Neither the name of PADL Software nor the names of its contributors
 17   *    may be used to endorse or promote products derived from this software
 18   *    without specific prior written permission.
 19   *
 20   * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
 21   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 23   * ARE DISCLAIMED.  IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
 24   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 25   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 26   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 27   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 28   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 29   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 30   * SUCH DAMAGE.
 31   */
 32  
 33  #include "kcm_locl.h"
 34  
 35  /*
 36   * Get a new ticket using a keytab/password and swap it into
 37   * an existing redentials cache
 38   */
 39  
 40  krb5_error_code
 41  kcm_ccache_acquire_locked(krb5_context context,
 42  		   kcm_ccache ccache,
 43  		   time_t *expire)
 44  {
 45      krb5_error_code ret = 0;
 46      krb5_creds cred;
 47      krb5_const_realm realm;
 48      krb5_get_init_creds_opt *opt = NULL;
 49      krb5_ccache_data ccdata;
 50      char *in_tkt_service = NULL;
 51  
 52      *expire = 0;
 53      memset(&cred, 0, sizeof(cred));
 54  
 55      KCM_ASSERT_VALID(ccache);
 56  
 57      /* We need a cached key or keytab to acquire credentials */
 58      if (ccache->flags & KCM_FLAGS_USE_PASSWORD) {
 59  	if (ccache->password == NULL) {
 60  	    krb5_abortx(context,
 61  			"kcm_ccache_acquire: KCM_FLAGS_USE_PASSWORD without password");
 62  	}
 63      } else if (ccache->flags & KCM_FLAGS_USE_KEYTAB) {
 64  	if (ccache->keytab == NULL) {
 65  	    krb5_abortx(context,
 66  			"kcm_ccache_acquire: KCM_FLAGS_USE_KEYTAB without keytab");
 67  	}
 68      } else {
 69  	kcm_log(0, "Cannot acquire initial credentials for cache %s without key",
 70  		ccache->name);
 71  	return KRB5_FCC_INTERNAL;
 72      }
 73  
 74      /* Fake up an internal ccache */
 75      kcm_internal_ccache(context, ccache, &ccdata);
 76  
 77      /* Now, actually acquire the creds */
 78      if (ccache->server != NULL) {
 79  	ret = krb5_unparse_name(context, ccache->server, &in_tkt_service);
 80  	if (ret) {
 81  	    kcm_log(0, "Failed to unparse service name for cache %s",
 82  		    ccache->name);
 83  	    return ret;
 84  	}
 85      }
 86  
 87      realm = krb5_principal_get_realm(context, ccache->client);
 88  
 89      ret = krb5_get_init_creds_opt_alloc(context, &opt);
 90      if (ret)
 91  	goto out;
 92      krb5_get_init_creds_opt_set_default_flags(context, "kcm", realm, opt);
 93      if (ccache->tkt_life != 0)
 94  	krb5_get_init_creds_opt_set_tkt_life(opt, ccache->tkt_life);
 95      if (ccache->renew_life != 0)
 96  	krb5_get_init_creds_opt_set_renew_life(opt, ccache->renew_life);
 97  
 98      if (ccache->flags & KCM_FLAGS_USE_PASSWORD) {
 99  	ret = krb5_get_init_creds_password(context,
100  					   &cred,
101  					   ccache->client,
102  					   ccache->password,
103  					   NULL,
104  					   NULL,
105  					   0,
106  					   in_tkt_service,
107  					   opt);
108      } else {
109  	ret = krb5_get_init_creds_keytab(context,
110  					 &cred,
111  					 ccache->client,
112  					 ccache->keytab,
113  					 0,
114  					 in_tkt_service,
115  					 opt);
116      }
117  
118      if (ret) {
119  	const char *msg = krb5_get_error_message(context, ret);
120  	kcm_log(0, "Failed to acquire credentials for cache %s: %s",
121  		ccache->name, msg);
122  	krb5_free_error_message(context, msg);
123  	if (in_tkt_service != NULL)
124  	    free(in_tkt_service);
125  	goto out;
126      }
127  
128      if (in_tkt_service != NULL)
129  	free(in_tkt_service);
130  
131      /* Swap them in */
132      kcm_ccache_remove_creds_internal(context, ccache);
133  
134      ret = kcm_ccache_store_cred_internal(context, ccache, &cred, NULL, 0);
135      if (ret) {
136  	const char *msg = krb5_get_error_message(context, ret);
137  	kcm_log(0, "Failed to store credentials for cache %s: %s",
138  		ccache->name, msg);
139  	krb5_free_error_message(context, msg);
140  	krb5_free_cred_contents(context, &cred);
141  	goto out;
142      }
143  
144      *expire = cred.times.endtime;
145  
146  out:
147      if (opt)
148  	krb5_get_init_creds_opt_free(context, opt);
149  
150      return ret;
151  }