1/* 2 * Copyright (c) 1997 - 2001 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 "kdc_locl.h" 35 36struct timeval _kdc_now; 37 38krb5_error_code 39_kdc_db_fetch(krb5_context context, 40 krb5_kdc_configuration *config, 41 krb5_const_principal principal, 42 unsigned flags, 43 krb5int32 *kvno_ptr, 44 HDB **db, 45 hdb_entry_ex **h) 46{ 47 hdb_entry_ex *ent; 48 krb5_error_code ret = HDB_ERR_NOENTRY; 49 unsigned i; 50 unsigned kvno = 0; 51 krb5_principal enterprise_principal = NULL; 52 krb5_const_principal princ = principal; 53 54 *h = NULL; 55 56 if (kvno_ptr) { 57 kvno = *kvno_ptr; 58 flags |= HDB_F_KVNO_SPECIFIED; 59 } 60 61 ent = calloc(1, sizeof (*ent)); 62 if (ent == NULL) 63 return krb5_enomem(context); 64 65 if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) { 66 if (principal->name.name_string.len != 1) { 67 ret = KRB5_PARSE_MALFORMED; 68 krb5_set_error_message(context, ret, 69 "malformed request: " 70 "enterprise name with %d name components", 71 principal->name.name_string.len); 72 goto out; 73 } 74 ret = krb5_parse_name(context, principal->name.name_string.val[0], 75 &enterprise_principal); 76 if (ret) 77 goto out; 78 } 79 80 for (i = 0; i < config->num_db; i++) { 81 ret = config->db[i]->hdb_open(context, config->db[i], O_RDONLY, 0); 82 if (ret) { 83 const char *msg = krb5_get_error_message(context, ret); 84 kdc_log(context, config, 0, "Failed to open database: %s", msg); 85 krb5_free_error_message(context, msg); 86 continue; 87 } 88 89 if (config->db[i]->hdb_capability_flags & HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL) 90 princ = principal; 91 else if (enterprise_principal) 92 princ = enterprise_principal; 93 94 ret = config->db[i]->hdb_fetch_kvno(context, 95 config->db[i], 96 princ, 97 flags | HDB_F_DECRYPT, 98 kvno, 99 ent); 100 config->db[i]->hdb_close(context, config->db[i]); 101 102 if (ret == 0) { 103 if (db) 104 *db = config->db[i]; 105 *h = ent; 106 ent = NULL; 107 goto out; 108 } 109 } 110 111 ret = HDB_ERR_NOENTRY; 112 krb5_set_error_message(context, ret, "no such entry found in hdb"); 113 114out: 115 krb5_free_principal(context, enterprise_principal); 116 free(ent); 117 return ret; 118} 119 120void 121_kdc_free_ent(krb5_context context, hdb_entry_ex *ent) 122{ 123 hdb_free_entry (context, ent); 124 free (ent); 125} 126 127/* 128 * Use the order list of preferred encryption types and sort the 129 * available keys and return the most preferred key. 130 */ 131 132krb5_error_code 133_kdc_get_preferred_key(krb5_context context, 134 krb5_kdc_configuration *config, 135 hdb_entry_ex *h, 136 const char *name, 137 krb5_enctype *enctype, 138 Key **key) 139{ 140 krb5_error_code ret; 141 unsigned i; 142 143 if (config->use_strongest_server_key) { 144 const krb5_enctype *p = krb5_kerberos_enctypes(context); 145 146 for (i = 0; p[i] != (krb5_enctype)ETYPE_NULL; i++) { 147 if (krb5_enctype_valid(context, p[i]) != 0) 148 continue; 149 ret = hdb_enctype2key(context, &h->entry, p[i], key); 150 if (ret != 0) 151 continue; 152 if (enctype != NULL) 153 *enctype = p[i]; 154 return 0; 155 } 156 } else { 157 *key = NULL; 158 159 for (i = 0; i < h->entry.keys.len; i++) { 160 if (krb5_enctype_valid(context, h->entry.keys.val[i].key.keytype) 161 != 0) 162 continue; 163 ret = hdb_enctype2key(context, &h->entry, 164 h->entry.keys.val[i].key.keytype, key); 165 if (ret != 0) 166 continue; 167 if (enctype != NULL) 168 *enctype = (*key)->key.keytype; 169 return 0; 170 } 171 } 172 173 krb5_set_error_message(context, EINVAL, 174 "No valid kerberos key found for %s", name); 175 return EINVAL; /* XXX */ 176} 177 178/* 179 * If we have entry->etypes, use that, otherwise require there is 180 * symmetric keys for the enctype needed. 181 */ 182 183static krb5_error_code 184entry_check_enctype(krb5_context context, 185 const hdb_entry_ex *entry, 186 krb5_enctype etype) 187{ 188 krb5_error_code ret; 189 190 ret = krb5_enctype_valid(context, etype); 191 if (ret) 192 return ret; 193 194 if (entry->entry.etypes) { 195 size_t n; 196 197 for (n = 0; n < entry->entry.etypes->len; n++) 198 if (entry->entry.etypes->val[n] == (unsigned int)etype) 199 return 0; 200 } else { 201 Key *key; 202 203 ret = hdb_enctype2key(context, &entry->entry, etype, &key); 204 if (ret == 0) 205 return 0; 206 } 207 return KRB5KDC_ERR_ETYPE_NOSUPP; 208} 209 210krb5_error_code 211_kdc_get_preferred_enctype(krb5_context context, 212 krb5_kdc_configuration *config, 213 const hdb_entry_ex *entry, 214 const char *name, 215 krb5_enctype *etypes, 216 unsigned num_etypes, 217 krb5_enctype *etype) 218{ 219 unsigned n, m; 220 221 if (config->use_strongest_server_key) { 222 const krb5_enctype *p = krb5_kerberos_enctypes(context); 223 224 for (n = 0; p[n] != (krb5_enctype)ETYPE_NULL; n++) { 225 226 if (entry_check_enctype(context, entry, p[n]) != 0) 227 continue; 228 229 for (m = 0; m < num_etypes; m++) { 230 if (etypes[m] == p[n]) { 231 *etype = p[n]; 232 return 0; 233 } 234 } 235 } 236 } else { 237 for (n = 0; n < num_etypes; n++) { 238 239 if (entry_check_enctype(context, entry, etypes[n]) != 0) 240 continue; 241 242 *etype = etypes[n]; 243 return 0; 244 } 245 } 246 247 krb5_set_error_message(context, KRB5KDC_ERR_ETYPE_NOSUPP, 248 "No valid enctype found for %s", name); 249 return KRB5KDC_ERR_ETYPE_NOSUPP; 250} 251 252 253/* 254 * verify the flags on `client' and `server', returning 0 255 * if they are OK and generating an error messages and returning 256 * and error code otherwise. 257 */ 258 259krb5_error_code 260kdc_check_flags(krb5_context context, 261 krb5_kdc_configuration *config, 262 hdb_entry_ex *client_ex, const char *client_name, 263 hdb_entry_ex *server_ex, const char *server_name, 264 krb5_boolean is_as_req) 265{ 266 if(client_ex != NULL) { 267 hdb_entry *client = &client_ex->entry; 268 269 /* check client */ 270 if (client->flags.locked_out) { 271 kdc_log(context, config, 0, 272 "Client (%s) is locked out", client_name); 273 return KRB5KDC_ERR_POLICY; 274 } 275 276 if (client->flags.invalid) { 277 kdc_log(context, config, 0, 278 "Client (%s) has invalid bit set", client_name); 279 return KRB5KDC_ERR_POLICY; 280 } 281 282 if(!client->flags.client){ 283 kdc_log(context, config, 0, 284 "Principal may not act as client -- %s", client_name); 285 return KRB5KDC_ERR_POLICY; 286 } 287 288 if (client->valid_start && *client->valid_start > kdc_time) { 289 char starttime_str[100]; 290 krb5_format_time(context, *client->valid_start, 291 starttime_str, sizeof(starttime_str), TRUE); 292 kdc_log(context, config, 0, 293 "Client not yet valid until %s -- %s", 294 starttime_str, client_name); 295 return KRB5KDC_ERR_CLIENT_NOTYET; 296 } 297 298 if (client->valid_end && *client->valid_end < kdc_time) { 299 char endtime_str[100]; 300 krb5_format_time(context, *client->valid_end, 301 endtime_str, sizeof(endtime_str), TRUE); 302 kdc_log(context, config, 0, 303 "Client expired at %s -- %s", 304 endtime_str, client_name); 305 return KRB5KDC_ERR_NAME_EXP; 306 } 307 308 if (client->flags.require_pwchange && 309 (server_ex == NULL || !server_ex->entry.flags.change_pw)) { 310 kdc_log(context, config, 0, 311 "Client's key must be changed -- %s", client_name); 312 return KRB5KDC_ERR_KEY_EXPIRED; 313 } 314 315 if (client->pw_end && *client->pw_end < kdc_time 316 && (server_ex == NULL || !server_ex->entry.flags.change_pw)) { 317 char pwend_str[100]; 318 krb5_format_time(context, *client->pw_end, 319 pwend_str, sizeof(pwend_str), TRUE); 320 kdc_log(context, config, 0, 321 "Client's key has expired at %s -- %s", 322 pwend_str, client_name); 323 return KRB5KDC_ERR_KEY_EXPIRED; 324 } 325 } 326 327 /* check server */ 328 329 if (server_ex != NULL) { 330 hdb_entry *server = &server_ex->entry; 331 332 if (server->flags.locked_out) { 333 kdc_log(context, config, 0, 334 "Client server locked out -- %s", server_name); 335 return KRB5KDC_ERR_POLICY; 336 } 337 if (server->flags.invalid) { 338 kdc_log(context, config, 0, 339 "Server has invalid flag set -- %s", server_name); 340 return KRB5KDC_ERR_POLICY; 341 } 342 343 if(!server->flags.server){ 344 kdc_log(context, config, 0, 345 "Principal may not act as server -- %s", server_name); 346 return KRB5KDC_ERR_POLICY; 347 } 348 349 if(!is_as_req && server->flags.initial) { 350 kdc_log(context, config, 0, 351 "AS-REQ is required for server -- %s", server_name); 352 return KRB5KDC_ERR_POLICY; 353 } 354 355 if (server->valid_start && *server->valid_start > kdc_time) { 356 char starttime_str[100]; 357 krb5_format_time(context, *server->valid_start, 358 starttime_str, sizeof(starttime_str), TRUE); 359 kdc_log(context, config, 0, 360 "Server not yet valid until %s -- %s", 361 starttime_str, server_name); 362 return KRB5KDC_ERR_SERVICE_NOTYET; 363 } 364 365 if (server->valid_end && *server->valid_end < kdc_time) { 366 char endtime_str[100]; 367 krb5_format_time(context, *server->valid_end, 368 endtime_str, sizeof(endtime_str), TRUE); 369 kdc_log(context, config, 0, 370 "Server expired at %s -- %s", 371 endtime_str, server_name); 372 return KRB5KDC_ERR_SERVICE_EXP; 373 } 374 375 if (server->pw_end && *server->pw_end < kdc_time) { 376 char pwend_str[100]; 377 krb5_format_time(context, *server->pw_end, 378 pwend_str, sizeof(pwend_str), TRUE); 379 kdc_log(context, config, 0, 380 "Server's key has expired at %s -- %s", 381 pwend_str, server_name); 382 return KRB5KDC_ERR_KEY_EXPIRED; 383 } 384 } 385 return 0; 386} 387