/ lib / krb5 / verify_init.c
verify_init.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  KRB5_LIB_FUNCTION void KRB5_LIB_CALL
 37  krb5_verify_init_creds_opt_init(krb5_verify_init_creds_opt *options)
 38  {
 39      memset (options, 0, sizeof(*options));
 40  }
 41  
 42  KRB5_LIB_FUNCTION void KRB5_LIB_CALL
 43  krb5_verify_init_creds_opt_set_ap_req_nofail(krb5_verify_init_creds_opt *options,
 44  					     int ap_req_nofail)
 45  {
 46      options->flags |= KRB5_VERIFY_INIT_CREDS_OPT_AP_REQ_NOFAIL;
 47      options->ap_req_nofail = ap_req_nofail;
 48  }
 49  
 50  KRB5_LIB_FUNCTION void KRB5_LIB_CALL
 51  krb5_verify_init_creds_opt_set_service(krb5_verify_init_creds_opt *options,
 52  				       const char *service)
 53  {
 54      options->service = service;
 55  }
 56  
 57  /*
 58   *
 59   */
 60  
 61  static krb5_boolean
 62  fail_verify_is_ok (krb5_context context,
 63  		   krb5_verify_init_creds_opt *options)
 64  {
 65      if ((options->flags & KRB5_VERIFY_INIT_CREDS_OPT_AP_REQ_NOFAIL
 66  	 && options->ap_req_nofail != 0)
 67  	|| krb5_config_get_bool (context,
 68  				 NULL,
 69  				 "libdefaults",
 70  				 "verify_ap_req_nofail",
 71  				 NULL))
 72  	return FALSE;
 73      else
 74  	return TRUE;
 75  }
 76  
 77  KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
 78  krb5_verify_init_creds(krb5_context context,
 79  		       krb5_creds *creds,
 80  		       krb5_principal ap_req_server,
 81  		       krb5_keytab ap_req_keytab,
 82  		       krb5_ccache *ccache,
 83  		       krb5_verify_init_creds_opt *options)
 84  {
 85      krb5_error_code ret;
 86      krb5_data req;
 87      krb5_ccache local_ccache = NULL;
 88      krb5_creds *new_creds = NULL;
 89      krb5_auth_context auth_context = NULL;
 90      krb5_principal server = NULL;
 91      krb5_keytab keytab = NULL;
 92      const char *service = "host";
 93  
 94      if (options && options->service)
 95  	service = options->service;
 96  
 97      krb5_data_zero (&req);
 98  
 99      if (ap_req_server == NULL) {
100  
101  	ret = krb5_sname_to_principal(context,
102  				      NULL,
103  				      service,
104  				      KRB5_NT_SRV_HST,
105  				      &server);
106  	if (ret) {
107  	    if (fail_verify_is_ok(context, options))
108  		ret = 0;
109  	    goto cleanup;
110  	}
111      } else
112  	server = ap_req_server;
113  
114      if (ap_req_keytab == NULL) {
115  	ret = krb5_kt_default (context, &keytab);
116  	if (ret)
117  	    goto cleanup;
118      } else
119  	keytab = ap_req_keytab;
120  
121      if (ccache && *ccache)
122  	local_ccache = *ccache;
123      else {
124  	ret = krb5_cc_new_unique(context, krb5_cc_type_memory,
125  				 NULL, &local_ccache);
126  	if (ret)
127  	    goto cleanup;
128  	ret = krb5_cc_initialize (context,
129  				  local_ccache,
130  				  creds->client);
131  	if (ret)
132  	    goto cleanup;
133  	ret = krb5_cc_store_cred (context,
134  				  local_ccache,
135  				  creds);
136  	if (ret)
137  	    goto cleanup;
138      }
139  
140      if (!krb5_principal_compare (context, server, creds->server)) {
141  	krb5_creds match_cred;
142  
143  	memset (&match_cred, 0, sizeof(match_cred));
144  
145  	match_cred.client = creds->client;
146  	match_cred.server = server;
147  
148  	ret = krb5_get_credentials (context,
149  				    0,
150  				    local_ccache,
151  				    &match_cred,
152  				    &new_creds);
153  	if (ret) {
154  	    if (fail_verify_is_ok (context, options))
155  		ret = 0;
156  	    goto cleanup;
157  	}
158  	creds = new_creds;
159      }
160  
161      ret = krb5_mk_req_extended (context,
162  				&auth_context,
163  				0,
164  				NULL,
165  				creds,
166  				&req);
167  
168      krb5_auth_con_free (context, auth_context);
169      auth_context = NULL;
170  
171      if (ret)
172  	goto cleanup;
173  
174      ret = krb5_rd_req (context,
175  		       &auth_context,
176  		       &req,
177  		       server,
178  		       keytab,
179  		       0,
180  		       NULL);
181  
182      if (ret == KRB5_KT_NOTFOUND && fail_verify_is_ok (context, options))
183  	ret = 0;
184  cleanup:
185      if (auth_context)
186  	krb5_auth_con_free (context, auth_context);
187      krb5_data_free (&req);
188      if (new_creds != NULL)
189  	krb5_free_creds (context, new_creds);
190      if (ap_req_server == NULL && server)
191  	krb5_free_principal (context, server);
192      if (ap_req_keytab == NULL && keytab)
193  	krb5_kt_close (context, keytab);
194      if (local_ccache != NULL
195  	&&
196  	(ccache == NULL
197  	 || (ret != 0 && *ccache == NULL)))
198  	krb5_cc_destroy (context, local_ccache);
199  
200      if (ret == 0 && ccache != NULL && *ccache == NULL)
201  	*ccache = local_ccache;
202  
203      return ret;
204  }
205  
206  /**
207   * Validate the newly fetch credential, see also krb5_verify_init_creds().
208   *
209   * @param context a Kerberos 5 context
210   * @param creds the credentials to verify
211   * @param client the client name to match up
212   * @param ccache the credential cache to use
213   * @param service a service name to use, used with
214   *        krb5_sname_to_principal() to build a hostname to use to
215   *        verify.
216   *
217   * @ingroup krb5_ccache
218   */
219  
220  KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
221  krb5_get_validated_creds(krb5_context context,
222  			 krb5_creds *creds,
223  			 krb5_principal client,
224  			 krb5_ccache ccache,
225  			 char *service)
226  {
227      krb5_verify_init_creds_opt vopt;
228      krb5_principal server;
229      krb5_error_code ret;
230  
231      if (krb5_principal_compare(context, creds->client, client) != TRUE) {
232  	krb5_set_error_message(context, KRB5_PRINC_NOMATCH,
233  			       N_("Validation credentials and client "
234  				  "doesn't match", ""));
235  	return KRB5_PRINC_NOMATCH;
236      }
237  
238      ret = krb5_sname_to_principal (context, NULL, service,
239  				   KRB5_NT_SRV_HST, &server);
240      if(ret)
241  	return ret;
242  
243      krb5_verify_init_creds_opt_init(&vopt);
244  
245      ret = krb5_verify_init_creds(context, creds, server, NULL, NULL, &vopt);
246      krb5_free_principal(context, server);
247  
248      return ret;
249  }