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