1 /* $NetBSD: misc.c,v 1.2 2017/01/28 21:31:44 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include "kdc_locl.h" 37 38 static int 39 name_type_ok(krb5_context context, 40 krb5_kdc_configuration *config, 41 krb5_const_principal principal) 42 { 43 int nt = krb5_principal_get_type(context, principal); 44 45 if (!krb5_principal_is_krbtgt(context, principal)) 46 return 1; 47 if (nt == KRB5_NT_SRV_INST || nt == KRB5_NT_UNKNOWN) 48 return 1; 49 if (config->strict_nametypes == 0) 50 return 1; 51 return 0; 52 } 53 54 struct timeval _kdc_now; 55 56 krb5_error_code 57 _kdc_db_fetch(krb5_context context, 58 krb5_kdc_configuration *config, 59 krb5_const_principal principal, 60 unsigned flags, 61 krb5uint32 *kvno_ptr, 62 HDB **db, 63 hdb_entry_ex **h) 64 { 65 hdb_entry_ex *ent = NULL; 66 krb5_error_code ret = HDB_ERR_NOENTRY; 67 int i; 68 unsigned kvno = 0; 69 krb5_principal enterprise_principal = NULL; 70 krb5_const_principal princ; 71 72 *h = NULL; 73 74 if (!name_type_ok(context, config, principal)) 75 goto out2; 76 77 if (kvno_ptr != NULL && *kvno_ptr != 0) { 78 kvno = *kvno_ptr; 79 flags |= HDB_F_KVNO_SPECIFIED; 80 } else { 81 flags |= HDB_F_ALL_KVNOS; 82 } 83 84 ent = calloc(1, sizeof (*ent)); 85 if (ent == NULL) 86 return krb5_enomem(context); 87 88 if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) { 89 if (principal->name.name_string.len != 1) { 90 ret = KRB5_PARSE_MALFORMED; 91 krb5_set_error_message(context, ret, 92 "malformed request: " 93 "enterprise name with %d name components", 94 principal->name.name_string.len); 95 goto out; 96 } 97 ret = krb5_parse_name(context, principal->name.name_string.val[0], 98 &enterprise_principal); 99 if (ret) 100 goto out; 101 } 102 103 for (i = 0; i < config->num_db; i++) { 104 ret = config->db[i]->hdb_open(context, config->db[i], O_RDONLY, 0); 105 if (ret) { 106 const char *msg = krb5_get_error_message(context, ret); 107 kdc_log(context, config, 0, "Failed to open database: %s", msg); 108 krb5_free_error_message(context, msg); 109 continue; 110 } 111 112 princ = principal; 113 if (!(config->db[i]->hdb_capability_flags & HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL) && enterprise_principal) 114 princ = enterprise_principal; 115 116 ret = config->db[i]->hdb_fetch_kvno(context, 117 config->db[i], 118 princ, 119 flags | HDB_F_DECRYPT, 120 kvno, 121 ent); 122 config->db[i]->hdb_close(context, config->db[i]); 123 124 switch (ret) { 125 case HDB_ERR_WRONG_REALM: 126 /* 127 * the ent->entry.principal just contains hints for the client 128 * to retry. This is important for enterprise principal routing 129 * between trusts. 130 */ 131 /* fall through */ 132 case 0: 133 if (db) 134 *db = config->db[i]; 135 *h = ent; 136 ent = NULL; 137 goto out; 138 139 case HDB_ERR_NOENTRY: 140 /* Check the other databases */ 141 continue; 142 143 default: 144 /* 145 * This is really important, because errors like 146 * HDB_ERR_NOT_FOUND_HERE (used to indicate to Samba that 147 * the RODC on which this code is running does not have 148 * the key we need, and so a proxy to the KDC is required) 149 * have specific meaning, and need to be propogated up. 150 */ 151 goto out; 152 } 153 } 154 155 out2: 156 if (ret == HDB_ERR_NOENTRY) { 157 krb5_set_error_message(context, ret, "no such entry found in hdb"); 158 } 159 out: 160 krb5_free_principal(context, enterprise_principal); 161 free(ent); 162 return ret; 163 } 164 165 void 166 _kdc_free_ent(krb5_context context, hdb_entry_ex *ent) 167 { 168 hdb_free_entry (context, ent); 169 free (ent); 170 } 171 172 /* 173 * Use the order list of preferred encryption types and sort the 174 * available keys and return the most preferred key. 175 */ 176 177 krb5_error_code 178 _kdc_get_preferred_key(krb5_context context, 179 krb5_kdc_configuration *config, 180 hdb_entry_ex *h, 181 const char *name, 182 krb5_enctype *enctype, 183 Key **key) 184 { 185 krb5_error_code ret; 186 int i; 187 188 if (config->use_strongest_server_key) { 189 const krb5_enctype *p = krb5_kerberos_enctypes(context); 190 191 for (i = 0; p[i] != (krb5_enctype)ETYPE_NULL; i++) { 192 if (krb5_enctype_valid(context, p[i]) != 0 && 193 !_kdc_is_weak_exception(h->entry.principal, p[i])) 194 continue; 195 ret = hdb_enctype2key(context, &h->entry, NULL, p[i], key); 196 if (ret != 0) 197 continue; 198 if (enctype != NULL) 199 *enctype = p[i]; 200 return 0; 201 } 202 } else { 203 *key = NULL; 204 205 for (i = 0; i < h->entry.keys.len; i++) { 206 if (krb5_enctype_valid(context, h->entry.keys.val[i].key.keytype) != 0 && 207 !_kdc_is_weak_exception(h->entry.principal, h->entry.keys.val[i].key.keytype)) 208 continue; 209 ret = hdb_enctype2key(context, &h->entry, NULL, 210 h->entry.keys.val[i].key.keytype, key); 211 if (ret != 0) 212 continue; 213 if (enctype != NULL) 214 *enctype = (*key)->key.keytype; 215 return 0; 216 } 217 } 218 219 krb5_set_error_message(context, EINVAL, 220 "No valid kerberos key found for %s", name); 221 return EINVAL; /* XXX */ 222 } 223 224