1 /* 2 * Copyright (c) 1997, 1998, 1999 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 RCSID("$Id: keytab.c,v 1.45 2000/01/02 00:31:20 assar Exp $"); 37 38 /* 39 * Register a new keytab in `ops' 40 * Return 0 or an error. 41 */ 42 43 krb5_error_code 44 krb5_kt_register(krb5_context context, 45 const krb5_kt_ops *ops) 46 { 47 struct krb5_keytab_data *tmp; 48 49 tmp = realloc(context->kt_types, 50 (context->num_kt_types + 1) * sizeof(*context->kt_types)); 51 if(tmp == NULL) 52 return ENOMEM; 53 memcpy(&tmp[context->num_kt_types], ops, 54 sizeof(tmp[context->num_kt_types])); 55 context->kt_types = tmp; 56 context->num_kt_types++; 57 return 0; 58 } 59 60 /* 61 * Resolve the keytab name (of the form `type:residual') in `name' 62 * into a keytab in `id'. 63 * Return 0 or an error 64 */ 65 66 krb5_error_code 67 krb5_kt_resolve(krb5_context context, 68 const char *name, 69 krb5_keytab *id) 70 { 71 krb5_keytab k; 72 int i; 73 const char *type, *residual; 74 size_t type_len; 75 krb5_error_code ret; 76 77 residual = strchr(name, ':'); 78 if(residual == NULL) { 79 type = "FILE"; 80 type_len = strlen(type); 81 residual = name; 82 } else { 83 type = name; 84 type_len = residual - name; 85 residual++; 86 } 87 88 for(i = 0; i < context->num_kt_types; i++) { 89 if(strncmp(type, context->kt_types[i].prefix, type_len) == 0) 90 break; 91 } 92 if(i == context->num_kt_types) 93 return KRB5_KT_UNKNOWN_TYPE; 94 95 k = malloc (sizeof(*k)); 96 if (k == NULL) 97 return ENOMEM; 98 memcpy(k, &context->kt_types[i], sizeof(*k)); 99 k->data = NULL; 100 ret = (*k->resolve)(context, residual, k); 101 if(ret) { 102 free(k); 103 k = NULL; 104 } 105 *id = k; 106 return ret; 107 } 108 109 /* 110 * copy the name of the default keytab into `name'. 111 * Return 0 or KRB5_CONFIG_NOTENUFSPACE if `namesize' is too short. 112 */ 113 114 krb5_error_code 115 krb5_kt_default_name(krb5_context context, char *name, size_t namesize) 116 { 117 strncpy(name, context->default_keytab, namesize); 118 if(strlen(context->default_keytab) >= namesize) 119 return KRB5_CONFIG_NOTENUFSPACE; 120 return 0; 121 } 122 123 /* 124 * Set `id' to the default keytab. 125 * Return 0 or an error. 126 */ 127 128 krb5_error_code 129 krb5_kt_default(krb5_context context, krb5_keytab *id) 130 { 131 return krb5_kt_resolve (context, context->default_keytab, id); 132 } 133 134 /* 135 * Read the key identified by `(principal, vno, enctype)' from the 136 * keytab in `keyprocarg' (the default if == NULL) into `*key'. 137 * Return 0 or an error. 138 */ 139 140 krb5_error_code 141 krb5_kt_read_service_key(krb5_context context, 142 krb5_pointer keyprocarg, 143 krb5_principal principal, 144 krb5_kvno vno, 145 krb5_enctype enctype, 146 krb5_keyblock **key) 147 { 148 krb5_keytab keytab; 149 krb5_keytab_entry entry; 150 krb5_error_code ret; 151 152 if (keyprocarg) 153 ret = krb5_kt_resolve (context, keyprocarg, &keytab); 154 else 155 ret = krb5_kt_default (context, &keytab); 156 157 if (ret) 158 return ret; 159 160 ret = krb5_kt_get_entry (context, keytab, principal, vno, enctype, &entry); 161 krb5_kt_close (context, keytab); 162 if (ret) 163 return ret; 164 ret = krb5_copy_keyblock (context, &entry.keyblock, key); 165 krb5_kt_free_entry(context, &entry); 166 return ret; 167 } 168 169 /* 170 * Retrieve the name of the keytab `keytab' into `name', `namesize' 171 * Return 0 or an error. 172 */ 173 174 krb5_error_code 175 krb5_kt_get_name(krb5_context context, 176 krb5_keytab keytab, 177 char *name, 178 size_t namesize) 179 { 180 return (*keytab->get_name)(context, keytab, name, namesize); 181 } 182 183 /* 184 * Finish using the keytab in `id'. All resources will be released. 185 * Return 0 or an error. 186 */ 187 188 krb5_error_code 189 krb5_kt_close(krb5_context context, 190 krb5_keytab id) 191 { 192 krb5_error_code ret; 193 194 ret = (*id->close)(context, id); 195 if(ret == 0) 196 free(id); 197 return ret; 198 } 199 200 /* 201 * Compare `entry' against `principal, vno, enctype'. 202 * Any of `principal, vno, enctype' might be 0 which acts as a wildcard. 203 * Return TRUE if they compare the same, FALSE otherwise. 204 */ 205 206 krb5_boolean 207 krb5_kt_compare(krb5_context context, 208 krb5_keytab_entry *entry, 209 krb5_const_principal principal, 210 krb5_kvno vno, 211 krb5_enctype enctype) 212 { 213 if(principal != NULL && 214 !krb5_principal_compare(context, entry->principal, principal)) 215 return FALSE; 216 if(vno && vno != entry->vno) 217 return FALSE; 218 if(enctype && enctype != entry->keyblock.keytype) 219 return FALSE; 220 return TRUE; 221 } 222 223 /* 224 * Retrieve the keytab entry for `principal, kvno, enctype' into `entry' 225 * from the keytab `id'. 226 * Return 0 or an error. 227 */ 228 229 krb5_error_code 230 krb5_kt_get_entry(krb5_context context, 231 krb5_keytab id, 232 krb5_const_principal principal, 233 krb5_kvno kvno, 234 krb5_enctype enctype, 235 krb5_keytab_entry *entry) 236 { 237 krb5_keytab_entry tmp; 238 krb5_error_code ret; 239 krb5_kt_cursor cursor; 240 241 if(id->get) 242 return (*id->get)(context, id, principal, kvno, enctype, entry); 243 244 ret = krb5_kt_start_seq_get (context, id, &cursor); 245 if (ret) 246 return KRB5_KT_NOTFOUND; /* XXX i.e. file not found */ 247 248 entry->vno = 0; 249 while (krb5_kt_next_entry(context, id, &tmp, &cursor) == 0) { 250 if (krb5_kt_compare(context, &tmp, principal, 0, enctype)) { 251 if (kvno == tmp.vno) { 252 krb5_kt_copy_entry_contents (context, &tmp, entry); 253 krb5_kt_free_entry (context, &tmp); 254 krb5_kt_end_seq_get(context, id, &cursor); 255 return 0; 256 } else if (kvno == 0 && tmp.vno > entry->vno) { 257 if (entry->vno) 258 krb5_kt_free_entry (context, entry); 259 krb5_kt_copy_entry_contents (context, &tmp, entry); 260 } 261 } 262 krb5_kt_free_entry(context, &tmp); 263 } 264 krb5_kt_end_seq_get (context, id, &cursor); 265 if (entry->vno) 266 return 0; 267 else 268 return KRB5_KT_NOTFOUND; 269 } 270 271 /* 272 * Copy the contents of `in' into `out'. 273 * Return 0 or an error. 274 */ 275 276 krb5_error_code 277 krb5_kt_copy_entry_contents(krb5_context context, 278 const krb5_keytab_entry *in, 279 krb5_keytab_entry *out) 280 { 281 krb5_error_code ret; 282 283 memset(out, 0, sizeof(*out)); 284 out->vno = in->vno; 285 286 ret = krb5_copy_principal (context, in->principal, &out->principal); 287 if (ret) 288 goto fail; 289 ret = krb5_copy_keyblock_contents (context, 290 &in->keyblock, 291 &out->keyblock); 292 if (ret) 293 goto fail; 294 out->timestamp = in->timestamp; 295 return 0; 296 fail: 297 krb5_kt_free_entry (context, out); 298 return ret; 299 } 300 301 /* 302 * Free the contents of `entry'. 303 */ 304 305 krb5_error_code 306 krb5_kt_free_entry(krb5_context context, 307 krb5_keytab_entry *entry) 308 { 309 krb5_free_principal (context, entry->principal); 310 krb5_free_keyblock_contents (context, &entry->keyblock); 311 return 0; 312 } 313 314 #if 0 315 static int 316 xxxlock(int fd, int write) 317 { 318 if(flock(fd, (write ? LOCK_EX : LOCK_SH) | LOCK_NB) < 0) { 319 sleep(1); 320 if(flock(fd, (write ? LOCK_EX : LOCK_SH) | LOCK_NB) < 0) 321 return -1; 322 } 323 return 0; 324 } 325 326 static void 327 xxxunlock(int fd) 328 { 329 flock(fd, LOCK_UN); 330 } 331 #endif 332 333 /* 334 * Set `cursor' to point at the beginning of `id'. 335 * Return 0 or an error. 336 */ 337 338 krb5_error_code 339 krb5_kt_start_seq_get(krb5_context context, 340 krb5_keytab id, 341 krb5_kt_cursor *cursor) 342 { 343 if(id->start_seq_get == NULL) 344 return HEIM_ERR_OPNOTSUPP; 345 return (*id->start_seq_get)(context, id, cursor); 346 } 347 348 /* 349 * Get the next entry from `id' pointed to by `cursor' and advance the 350 * `cursor'. 351 * Return 0 or an error. 352 */ 353 354 krb5_error_code 355 krb5_kt_next_entry(krb5_context context, 356 krb5_keytab id, 357 krb5_keytab_entry *entry, 358 krb5_kt_cursor *cursor) 359 { 360 if(id->next_entry == NULL) 361 return HEIM_ERR_OPNOTSUPP; 362 return (*id->next_entry)(context, id, entry, cursor); 363 } 364 365 /* 366 * Release all resources associated with `cursor'. 367 */ 368 369 krb5_error_code 370 krb5_kt_end_seq_get(krb5_context context, 371 krb5_keytab id, 372 krb5_kt_cursor *cursor) 373 { 374 if(id->end_seq_get == NULL) 375 return HEIM_ERR_OPNOTSUPP; 376 return (*id->end_seq_get)(context, id, cursor); 377 } 378 379 /* 380 * Add the entry in `entry' to the keytab `id'. 381 * Return 0 or an error. 382 */ 383 384 krb5_error_code 385 krb5_kt_add_entry(krb5_context context, 386 krb5_keytab id, 387 krb5_keytab_entry *entry) 388 { 389 if(id->add == NULL) 390 return KRB5_KT_NOWRITE; 391 return (*id->add)(context, id,entry); 392 } 393 394 /* 395 * Remove the entry `entry' from the keytab `id'. 396 * Return 0 or an error. 397 */ 398 399 krb5_error_code 400 krb5_kt_remove_entry(krb5_context context, 401 krb5_keytab id, 402 krb5_keytab_entry *entry) 403 { 404 if(id->remove == NULL) 405 return KRB5_KT_NOWRITE; 406 return (*id->remove)(context, id, entry); 407 } 408