1 1.1 elric /* $NetBSD: keytab.c,v 1.3 2023/06/19 21:41:44 christos Exp $ */ 2 1.1 elric 3 1.1 elric /* 4 1.1 elric * Copyright (c) 1997 - 2005 Kungliga Tekniska Hgskolan 5 1.1 elric * (Royal Institute of Technology, Stockholm, Sweden). 6 1.1 elric * All rights reserved. 7 1.1 elric * 8 1.1 elric * Redistribution and use in source and binary forms, with or without 9 1.1 elric * modification, are permitted provided that the following conditions 10 1.1 elric * are met: 11 1.1 elric * 12 1.1 elric * 1. Redistributions of source code must retain the above copyright 13 1.1 elric * notice, this list of conditions and the following disclaimer. 14 1.1 elric * 15 1.1 elric * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 elric * notice, this list of conditions and the following disclaimer in the 17 1.1 elric * documentation and/or other materials provided with the distribution. 18 1.1 elric * 19 1.1 elric * 3. Neither the name of the Institute nor the names of its contributors 20 1.1 elric * may be used to endorse or promote products derived from this software 21 1.1 elric * without specific prior written permission. 22 1.1 elric * 23 1.1 elric * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 1.1 elric * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 1.1 elric * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 1.1 elric * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 1.1 elric * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 1.1 elric * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 1.1 elric * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 1.1 elric * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 1.1 elric * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 1.1 elric * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 1.1 elric * SUCH DAMAGE. 34 1.1 elric */ 35 1.1 elric 36 1.1 elric #include "krb5_locl.h" 37 1.1 elric 38 1.1 elric /** 39 1.1 elric * @page krb5_keytab_intro The keytab handing functions 40 1.1 elric * @section section_krb5_keytab Kerberos Keytabs 41 1.1 elric * 42 1.1 elric * See the library functions here: @ref krb5_keytab 43 1.1 elric * 44 1.1 elric * Keytabs are long term key storage for servers, their equvalment of 45 1.1 elric * password files. 46 1.1 elric * 47 1.1 elric * Normally the only function that useful for server are to specify 48 1.1 elric * what keytab to use to other core functions like krb5_rd_req() 49 1.1 elric * krb5_kt_resolve(), and krb5_kt_close(). 50 1.1 elric * 51 1.1 elric * @subsection krb5_keytab_names Keytab names 52 1.1 elric * 53 1.1 elric * A keytab name is on the form type:residual. The residual part is 54 1.1 elric * specific to each keytab-type. 55 1.2 christos * 56 1.1 elric * When a keytab-name is resolved, the type is matched with an internal 57 1.1 elric * list of keytab types. If there is no matching keytab type, 58 1.1 elric * the default keytab is used. The current default type is FILE. 59 1.1 elric * 60 1.1 elric * The default value can be changed in the configuration file 61 1.1 elric * /etc/krb5.conf by setting the variable 62 1.1 elric * [defaults]default_keytab_name. 63 1.1 elric * 64 1.1 elric * The keytab types that are implemented in Heimdal are: 65 1.2 christos * - file 66 1.1 elric * store the keytab in a file, the type's name is FILE . The 67 1.1 elric * residual part is a filename. For compatibility with other 68 1.1 elric * Kerberos implemtation WRFILE and JAVA14 is also accepted. WRFILE 69 1.1 elric * has the same format as FILE. JAVA14 have a format that is 70 1.1 elric * compatible with older versions of MIT kerberos and SUN's Java 71 1.1 elric * based installation. They store a truncted kvno, so when the knvo 72 1.1 elric * excess 255, they are truncted in this format. 73 1.1 elric * 74 1.1 elric * - keytab 75 1.1 elric * store the keytab in a AFS keyfile (usually /usr/afs/etc/KeyFile ), 76 1.1 elric * the type's name is AFSKEYFILE. The residual part is a filename. 77 1.1 elric * 78 1.1 elric * - memory 79 1.1 elric * The keytab is stored in a memory segment. This allows sensitive 80 1.1 elric * and/or temporary data not to be stored on disk. The type's name 81 1.1 elric * is MEMORY. Each MEMORY keytab is referenced counted by and 82 1.1 elric * opened by the residual name, so two handles can point to the 83 1.1 elric * same memory area. When the last user closes using krb5_kt_close() 84 1.1 elric * the keytab, the keys in they keytab is memset() to zero and freed 85 1.1 elric * and can no longer be looked up by name. 86 1.1 elric * 87 1.1 elric * 88 1.1 elric * @subsection krb5_keytab_example Keytab example 89 1.1 elric * 90 1.1 elric * This is a minimalistic version of ktutil. 91 1.1 elric * 92 1.1 elric * @code 93 1.1 elric int 94 1.1 elric main (int argc, char **argv) 95 1.1 elric { 96 1.1 elric krb5_context context; 97 1.1 elric krb5_keytab keytab; 98 1.1 elric krb5_kt_cursor cursor; 99 1.1 elric krb5_keytab_entry entry; 100 1.1 elric krb5_error_code ret; 101 1.1 elric char *principal; 102 1.1 elric 103 1.1 elric if (krb5_init_context (&context) != 0) 104 1.1 elric errx(1, "krb5_context"); 105 1.1 elric 106 1.1 elric ret = krb5_kt_default (context, &keytab); 107 1.1 elric if (ret) 108 1.1 elric krb5_err(context, 1, ret, "krb5_kt_default"); 109 1.1 elric 110 1.1 elric ret = krb5_kt_start_seq_get(context, keytab, &cursor); 111 1.1 elric if (ret) 112 1.1 elric krb5_err(context, 1, ret, "krb5_kt_start_seq_get"); 113 1.1 elric while((ret = krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0){ 114 1.1 elric krb5_unparse_name(context, entry.principal, &principal); 115 1.1 elric printf("principal: %s\n", principal); 116 1.1 elric free(principal); 117 1.1 elric krb5_kt_free_entry(context, &entry); 118 1.1 elric } 119 1.1 elric ret = krb5_kt_end_seq_get(context, keytab, &cursor); 120 1.1 elric if (ret) 121 1.1 elric krb5_err(context, 1, ret, "krb5_kt_end_seq_get"); 122 1.1 elric ret = krb5_kt_close(context, keytab); 123 1.1 elric if (ret) 124 1.1 elric krb5_err(context, 1, ret, "krb5_kt_close"); 125 1.1 elric krb5_free_context(context); 126 1.1 elric return 0; 127 1.1 elric } 128 1.1 elric * @endcode 129 1.1 elric * 130 1.1 elric */ 131 1.1 elric 132 1.1 elric 133 1.1 elric /** 134 1.1 elric * Register a new keytab backend. 135 1.1 elric * 136 1.1 elric * @param context a Keberos context. 137 1.1 elric * @param ops a backend to register. 138 1.1 elric * 139 1.1 elric * @return Return an error code or 0, see krb5_get_error_message(). 140 1.1 elric * 141 1.1 elric * @ingroup krb5_keytab 142 1.1 elric */ 143 1.1 elric 144 1.1 elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 145 1.1 elric krb5_kt_register(krb5_context context, 146 1.1 elric const krb5_kt_ops *ops) 147 1.1 elric { 148 1.1 elric struct krb5_keytab_data *tmp; 149 1.1 elric 150 1.1 elric if (strlen(ops->prefix) > KRB5_KT_PREFIX_MAX_LEN - 1) { 151 1.1 elric krb5_set_error_message(context, KRB5_KT_BADNAME, 152 1.1 elric N_("can't register cache type, prefix too long", "")); 153 1.1 elric return KRB5_KT_BADNAME; 154 1.1 elric } 155 1.1 elric 156 1.1 elric tmp = realloc(context->kt_types, 157 1.1 elric (context->num_kt_types + 1) * sizeof(*context->kt_types)); 158 1.2 christos if(tmp == NULL) 159 1.2 christos return krb5_enomem(context); 160 1.1 elric memcpy(&tmp[context->num_kt_types], ops, 161 1.1 elric sizeof(tmp[context->num_kt_types])); 162 1.1 elric context->kt_types = tmp; 163 1.1 elric context->num_kt_types++; 164 1.1 elric return 0; 165 1.1 elric } 166 1.1 elric 167 1.1 elric static const char * 168 1.1 elric keytab_name(const char *name, const char **type, size_t *type_len) 169 1.1 elric { 170 1.1 elric const char *residual; 171 1.1 elric 172 1.1 elric residual = strchr(name, ':'); 173 1.1 elric 174 1.1 elric if (residual == NULL || 175 1.2 christos ISPATHSEP(name[0]) 176 1.1 elric #ifdef _WIN32 177 1.1 elric /* Avoid treating <drive>:<path> as a keytab type 178 1.1 elric * specification */ 179 1.1 elric || name + 1 == residual 180 1.1 elric #endif 181 1.1 elric ) { 182 1.1 elric 183 1.1 elric *type = "FILE"; 184 1.1 elric *type_len = strlen(*type); 185 1.1 elric residual = name; 186 1.1 elric } else { 187 1.1 elric *type = name; 188 1.1 elric *type_len = residual - name; 189 1.1 elric residual++; 190 1.1 elric } 191 1.1 elric 192 1.1 elric return residual; 193 1.1 elric } 194 1.1 elric 195 1.1 elric /** 196 1.1 elric * Resolve the keytab name (of the form `type:residual') in `name' 197 1.1 elric * into a keytab in `id'. 198 1.1 elric * 199 1.1 elric * @param context a Keberos context. 200 1.1 elric * @param name name to resolve 201 1.1 elric * @param id resulting keytab, free with krb5_kt_close(). 202 1.1 elric * 203 1.1 elric * @return Return an error code or 0, see krb5_get_error_message(). 204 1.1 elric * 205 1.1 elric * @ingroup krb5_keytab 206 1.1 elric */ 207 1.1 elric 208 1.1 elric 209 1.1 elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 210 1.1 elric krb5_kt_resolve(krb5_context context, 211 1.1 elric const char *name, 212 1.1 elric krb5_keytab *id) 213 1.1 elric { 214 1.1 elric krb5_keytab k; 215 1.1 elric int i; 216 1.1 elric const char *type, *residual; 217 1.1 elric size_t type_len; 218 1.1 elric krb5_error_code ret; 219 1.1 elric 220 1.1 elric residual = keytab_name(name, &type, &type_len); 221 1.1 elric 222 1.1 elric for(i = 0; i < context->num_kt_types; i++) { 223 1.1 elric if(strncasecmp(type, context->kt_types[i].prefix, type_len) == 0) 224 1.1 elric break; 225 1.1 elric } 226 1.1 elric if(i == context->num_kt_types) { 227 1.1 elric krb5_set_error_message(context, KRB5_KT_UNKNOWN_TYPE, 228 1.1 elric N_("unknown keytab type %.*s", "type"), 229 1.1 elric (int)type_len, type); 230 1.1 elric return KRB5_KT_UNKNOWN_TYPE; 231 1.1 elric } 232 1.1 elric 233 1.1 elric k = malloc (sizeof(*k)); 234 1.2 christos if (k == NULL) 235 1.2 christos return krb5_enomem(context); 236 1.1 elric memcpy(k, &context->kt_types[i], sizeof(*k)); 237 1.1 elric k->data = NULL; 238 1.1 elric ret = (*k->resolve)(context, residual, k); 239 1.1 elric if(ret) { 240 1.1 elric free(k); 241 1.1 elric k = NULL; 242 1.1 elric } 243 1.1 elric *id = k; 244 1.1 elric return ret; 245 1.1 elric } 246 1.1 elric 247 1.2 christos /* 248 1.2 christos * Default ktname from context with possible environment 249 1.2 christos * override 250 1.2 christos */ 251 1.2 christos static const char *default_ktname(krb5_context context) 252 1.2 christos { 253 1.2 christos const char *tmp = NULL; 254 1.2 christos 255 1.2 christos if(!issuid()) 256 1.2 christos tmp = getenv("KRB5_KTNAME"); 257 1.2 christos if(tmp != NULL) 258 1.2 christos return tmp; 259 1.2 christos return context->default_keytab; 260 1.2 christos } 261 1.2 christos 262 1.1 elric /** 263 1.1 elric * copy the name of the default keytab into `name'. 264 1.1 elric * 265 1.1 elric * @param context a Keberos context. 266 1.1 elric * @param name buffer where the name will be written 267 1.1 elric * @param namesize length of name 268 1.1 elric * 269 1.1 elric * @return Return an error code or 0, see krb5_get_error_message(). 270 1.1 elric * 271 1.1 elric * @ingroup krb5_keytab 272 1.1 elric */ 273 1.1 elric 274 1.1 elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 275 1.1 elric krb5_kt_default_name(krb5_context context, char *name, size_t namesize) 276 1.1 elric { 277 1.2 christos if (strlcpy (name, default_ktname(context), namesize) >= namesize) { 278 1.1 elric krb5_clear_error_message (context); 279 1.1 elric return KRB5_CONFIG_NOTENUFSPACE; 280 1.1 elric } 281 1.1 elric return 0; 282 1.1 elric } 283 1.1 elric 284 1.1 elric /** 285 1.1 elric * Copy the name of the default modify keytab into `name'. 286 1.1 elric * 287 1.1 elric * @param context a Keberos context. 288 1.1 elric * @param name buffer where the name will be written 289 1.1 elric * @param namesize length of name 290 1.1 elric * 291 1.1 elric * @return Return an error code or 0, see krb5_get_error_message(). 292 1.1 elric * 293 1.1 elric * @ingroup krb5_keytab 294 1.1 elric */ 295 1.1 elric 296 1.1 elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 297 1.1 elric krb5_kt_default_modify_name(krb5_context context, char *name, size_t namesize) 298 1.1 elric { 299 1.2 christos const char *kt; 300 1.2 christos 301 1.1 elric if(context->default_keytab_modify == NULL) { 302 1.2 christos kt = default_ktname(context); 303 1.2 christos 304 1.2 christos if (strncasecmp(kt, "ANY:", 4) == 0) { 305 1.2 christos size_t len = strcspn(kt + 4, ","); 306 1.2 christos if (len >= namesize) { 307 1.1 elric krb5_clear_error_message(context); 308 1.1 elric return KRB5_CONFIG_NOTENUFSPACE; 309 1.1 elric } 310 1.2 christos strlcpy(name, kt + 4, namesize); 311 1.1 elric name[len] = '\0'; 312 1.1 elric return 0; 313 1.1 elric } 314 1.1 elric } else 315 1.1 elric kt = context->default_keytab_modify; 316 1.1 elric if (strlcpy (name, kt, namesize) >= namesize) { 317 1.1 elric krb5_clear_error_message (context); 318 1.1 elric return KRB5_CONFIG_NOTENUFSPACE; 319 1.1 elric } 320 1.1 elric return 0; 321 1.1 elric } 322 1.1 elric 323 1.1 elric /** 324 1.1 elric * Set `id' to the default keytab. 325 1.1 elric * 326 1.1 elric * @param context a Keberos context. 327 1.1 elric * @param id the new default keytab. 328 1.1 elric * 329 1.1 elric * @return Return an error code or 0, see krb5_get_error_message(). 330 1.1 elric * 331 1.1 elric * @ingroup krb5_keytab 332 1.1 elric */ 333 1.1 elric 334 1.1 elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 335 1.1 elric krb5_kt_default(krb5_context context, krb5_keytab *id) 336 1.1 elric { 337 1.2 christos return krb5_kt_resolve (context, default_ktname(context), id); 338 1.1 elric } 339 1.1 elric 340 1.1 elric /** 341 1.1 elric * Read the key identified by `(principal, vno, enctype)' from the 342 1.1 elric * keytab in `keyprocarg' (the default if == NULL) into `*key'. 343 1.1 elric * 344 1.1 elric * @param context a Keberos context. 345 1.1 elric * @param keyprocarg 346 1.1 elric * @param principal 347 1.1 elric * @param vno 348 1.1 elric * @param enctype 349 1.1 elric * @param key 350 1.1 elric * 351 1.1 elric * @return Return an error code or 0, see krb5_get_error_message(). 352 1.1 elric * 353 1.1 elric * @ingroup krb5_keytab 354 1.1 elric */ 355 1.1 elric 356 1.1 elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 357 1.1 elric krb5_kt_read_service_key(krb5_context context, 358 1.1 elric krb5_pointer keyprocarg, 359 1.1 elric krb5_principal principal, 360 1.1 elric krb5_kvno vno, 361 1.1 elric krb5_enctype enctype, 362 1.1 elric krb5_keyblock **key) 363 1.1 elric { 364 1.3 christos krb5_keytab keytab = NULL; /* Quiet lint */ 365 1.1 elric krb5_keytab_entry entry; 366 1.1 elric krb5_error_code ret; 367 1.1 elric 368 1.3 christos memset(&entry, 0, sizeof(entry)); 369 1.1 elric if (keyprocarg) 370 1.1 elric ret = krb5_kt_resolve (context, keyprocarg, &keytab); 371 1.1 elric else 372 1.1 elric ret = krb5_kt_default (context, &keytab); 373 1.1 elric 374 1.1 elric if (ret) 375 1.1 elric return ret; 376 1.1 elric 377 1.1 elric ret = krb5_kt_get_entry (context, keytab, principal, vno, enctype, &entry); 378 1.3 christos if (ret == 0) { 379 1.3 christos ret = krb5_copy_keyblock (context, &entry.keyblock, key); 380 1.3 christos krb5_kt_free_entry(context, &entry); 381 1.3 christos } 382 1.1 elric krb5_kt_close (context, keytab); 383 1.1 elric return ret; 384 1.1 elric } 385 1.1 elric 386 1.1 elric /** 387 1.1 elric * Return the type of the `keytab' in the string `prefix of length 388 1.1 elric * `prefixsize'. 389 1.1 elric * 390 1.1 elric * @param context a Keberos context. 391 1.1 elric * @param keytab the keytab to get the prefix for 392 1.1 elric * @param prefix prefix buffer 393 1.1 elric * @param prefixsize length of prefix buffer 394 1.1 elric * 395 1.1 elric * @return Return an error code or 0, see krb5_get_error_message(). 396 1.1 elric * 397 1.1 elric * @ingroup krb5_keytab 398 1.1 elric */ 399 1.1 elric 400 1.1 elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 401 1.1 elric krb5_kt_get_type(krb5_context context, 402 1.1 elric krb5_keytab keytab, 403 1.1 elric char *prefix, 404 1.1 elric size_t prefixsize) 405 1.1 elric { 406 1.1 elric strlcpy(prefix, keytab->prefix, prefixsize); 407 1.1 elric return 0; 408 1.1 elric } 409 1.1 elric 410 1.1 elric /** 411 1.1 elric * Retrieve the name of the keytab `keytab' into `name', `namesize' 412 1.1 elric * 413 1.1 elric * @param context a Keberos context. 414 1.1 elric * @param keytab the keytab to get the name for. 415 1.1 elric * @param name name buffer. 416 1.1 elric * @param namesize size of name buffer. 417 1.1 elric * 418 1.1 elric * @return Return an error code or 0, see krb5_get_error_message(). 419 1.1 elric * 420 1.1 elric * @ingroup krb5_keytab 421 1.1 elric */ 422 1.1 elric 423 1.1 elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 424 1.1 elric krb5_kt_get_name(krb5_context context, 425 1.1 elric krb5_keytab keytab, 426 1.1 elric char *name, 427 1.1 elric size_t namesize) 428 1.1 elric { 429 1.1 elric return (*keytab->get_name)(context, keytab, name, namesize); 430 1.1 elric } 431 1.1 elric 432 1.1 elric /** 433 1.1 elric * Retrieve the full name of the keytab `keytab' and store the name in 434 1.1 elric * `str'. 435 1.1 elric * 436 1.1 elric * @param context a Keberos context. 437 1.1 elric * @param keytab keytab to get name for. 438 1.1 elric * @param str the name of the keytab name, usee krb5_xfree() to free 439 1.1 elric * the string. On error, *str is set to NULL. 440 1.1 elric * 441 1.1 elric * @return Return an error code or 0, see krb5_get_error_message(). 442 1.1 elric * 443 1.1 elric * @ingroup krb5_keytab 444 1.1 elric */ 445 1.1 elric 446 1.1 elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 447 1.1 elric krb5_kt_get_full_name(krb5_context context, 448 1.1 elric krb5_keytab keytab, 449 1.1 elric char **str) 450 1.1 elric { 451 1.1 elric char type[KRB5_KT_PREFIX_MAX_LEN]; 452 1.1 elric char name[MAXPATHLEN]; 453 1.1 elric krb5_error_code ret; 454 1.2 christos 455 1.1 elric *str = NULL; 456 1.1 elric 457 1.1 elric ret = krb5_kt_get_type(context, keytab, type, sizeof(type)); 458 1.1 elric if (ret) 459 1.1 elric return ret; 460 1.1 elric 461 1.1 elric ret = krb5_kt_get_name(context, keytab, name, sizeof(name)); 462 1.1 elric if (ret) 463 1.1 elric return ret; 464 1.1 elric 465 1.1 elric if (asprintf(str, "%s:%s", type, name) == -1) { 466 1.1 elric *str = NULL; 467 1.2 christos return krb5_enomem(context); 468 1.1 elric } 469 1.1 elric 470 1.1 elric return 0; 471 1.1 elric } 472 1.1 elric 473 1.1 elric /** 474 1.1 elric * Finish using the keytab in `id'. All resources will be released, 475 1.1 elric * even on errors. 476 1.1 elric * 477 1.1 elric * @param context a Keberos context. 478 1.1 elric * @param id keytab to close. 479 1.1 elric * 480 1.1 elric * @return Return an error code or 0, see krb5_get_error_message(). 481 1.1 elric * 482 1.1 elric * @ingroup krb5_keytab 483 1.1 elric */ 484 1.1 elric 485 1.1 elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 486 1.1 elric krb5_kt_close(krb5_context context, 487 1.1 elric krb5_keytab id) 488 1.1 elric { 489 1.3 christos krb5_error_code ret = 0; 490 1.1 elric 491 1.3 christos if (id) { 492 1.3 christos ret = (id->close)(context, id); 493 1.3 christos memset(id, 0, sizeof(*id)); 494 1.3 christos free(id); 495 1.3 christos } 496 1.1 elric return ret; 497 1.1 elric } 498 1.1 elric 499 1.1 elric /** 500 1.1 elric * Destroy (remove) the keytab in `id'. All resources will be released, 501 1.1 elric * even on errors, does the equvalment of krb5_kt_close() on the resources. 502 1.1 elric * 503 1.1 elric * @param context a Keberos context. 504 1.1 elric * @param id keytab to destroy. 505 1.1 elric * 506 1.1 elric * @return Return an error code or 0, see krb5_get_error_message(). 507 1.1 elric * 508 1.1 elric * @ingroup krb5_keytab 509 1.1 elric */ 510 1.1 elric 511 1.1 elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 512 1.1 elric krb5_kt_destroy(krb5_context context, 513 1.1 elric krb5_keytab id) 514 1.1 elric { 515 1.1 elric krb5_error_code ret; 516 1.1 elric 517 1.1 elric ret = (*id->destroy)(context, id); 518 1.1 elric krb5_kt_close(context, id); 519 1.1 elric return ret; 520 1.1 elric } 521 1.1 elric 522 1.1 elric /* 523 1.1 elric * Match any aliases in keytab `entry' with `principal'. 524 1.1 elric */ 525 1.1 elric 526 1.1 elric static krb5_boolean 527 1.2 christos compare_aliases(krb5_context context, 528 1.1 elric krb5_keytab_entry *entry, 529 1.1 elric krb5_const_principal principal) 530 1.1 elric { 531 1.1 elric unsigned int i; 532 1.1 elric if (entry->aliases == NULL) 533 1.1 elric return FALSE; 534 1.1 elric for (i = 0; i < entry->aliases->len; i++) 535 1.1 elric if (krb5_principal_compare(context, &entry->aliases->val[i], principal)) 536 1.1 elric return TRUE; 537 1.1 elric return FALSE; 538 1.1 elric } 539 1.1 elric 540 1.1 elric /** 541 1.1 elric * Compare `entry' against `principal, vno, enctype'. 542 1.1 elric * Any of `principal, vno, enctype' might be 0 which acts as a wildcard. 543 1.1 elric * Return TRUE if they compare the same, FALSE otherwise. 544 1.1 elric * 545 1.1 elric * @param context a Keberos context. 546 1.1 elric * @param entry an entry to match with. 547 1.1 elric * @param principal principal to match, NULL matches all principals. 548 1.1 elric * @param vno key version to match, 0 matches all key version numbers. 549 1.1 elric * @param enctype encryption type to match, 0 matches all encryption types. 550 1.1 elric * 551 1.1 elric * @return Return TRUE or match, FALSE if not matched. 552 1.1 elric * 553 1.1 elric * @ingroup krb5_keytab 554 1.1 elric */ 555 1.1 elric 556 1.1 elric KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 557 1.1 elric krb5_kt_compare(krb5_context context, 558 1.1 elric krb5_keytab_entry *entry, 559 1.1 elric krb5_const_principal principal, 560 1.1 elric krb5_kvno vno, 561 1.1 elric krb5_enctype enctype) 562 1.1 elric { 563 1.2 christos /* krb5_principal_compare() does not special-case the referral realm */ 564 1.2 christos if (principal != NULL && strcmp(principal->realm, "") == 0 && 565 1.2 christos !(krb5_principal_compare_any_realm(context, entry->principal, principal) || 566 1.2 christos compare_aliases(context, entry, principal))) { 567 1.2 christos return FALSE; 568 1.2 christos } else if (principal != NULL && strcmp(principal->realm, "") != 0 && 569 1.2 christos !(krb5_principal_compare(context, entry->principal, principal) || 570 1.2 christos compare_aliases(context, entry, principal))) { 571 1.1 elric return FALSE; 572 1.2 christos } 573 1.2 christos if (vno && vno != entry->vno) 574 1.1 elric return FALSE; 575 1.2 christos if (enctype && enctype != entry->keyblock.keytype) 576 1.1 elric return FALSE; 577 1.1 elric return TRUE; 578 1.1 elric } 579 1.1 elric 580 1.2 christos KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 581 1.1 elric _krb5_kt_principal_not_found(krb5_context context, 582 1.1 elric krb5_error_code ret, 583 1.1 elric krb5_keytab id, 584 1.1 elric krb5_const_principal principal, 585 1.1 elric krb5_enctype enctype, 586 1.1 elric int kvno) 587 1.1 elric { 588 1.1 elric char princ[256], kvno_str[25], *kt_name; 589 1.1 elric char *enctype_str = NULL; 590 1.2 christos 591 1.1 elric krb5_unparse_name_fixed (context, principal, princ, sizeof(princ)); 592 1.1 elric krb5_kt_get_full_name (context, id, &kt_name); 593 1.2 christos if (enctype) 594 1.2 christos krb5_enctype_to_string(context, enctype, &enctype_str); 595 1.2 christos 596 1.1 elric if (kvno) 597 1.1 elric snprintf(kvno_str, sizeof(kvno_str), "(kvno %d)", kvno); 598 1.1 elric else 599 1.1 elric kvno_str[0] = '\0'; 600 1.2 christos 601 1.1 elric krb5_set_error_message (context, ret, 602 1.1 elric N_("Failed to find %s%s in keytab %s (%s)", 603 1.1 elric "principal, kvno, keytab file, enctype"), 604 1.1 elric princ, 605 1.1 elric kvno_str, 606 1.1 elric kt_name ? kt_name : "unknown keytab", 607 1.1 elric enctype_str ? enctype_str : "unknown enctype"); 608 1.1 elric free(kt_name); 609 1.2 christos if (enctype_str) 610 1.2 christos free(enctype_str); 611 1.1 elric return ret; 612 1.1 elric } 613 1.1 elric 614 1.2 christos static krb5_error_code 615 1.2 christos krb5_kt_get_entry_wrapped(krb5_context context, 616 1.2 christos krb5_keytab id, 617 1.2 christos krb5_const_principal principal, 618 1.2 christos krb5_kvno kvno, 619 1.2 christos krb5_enctype enctype, 620 1.2 christos krb5_keytab_entry *entry) 621 1.1 elric { 622 1.1 elric krb5_keytab_entry tmp; 623 1.1 elric krb5_error_code ret; 624 1.1 elric krb5_kt_cursor cursor; 625 1.1 elric 626 1.1 elric if(id->get) 627 1.1 elric return (*id->get)(context, id, principal, kvno, enctype, entry); 628 1.1 elric 629 1.3 christos memset(&tmp, 0, sizeof(tmp)); 630 1.1 elric ret = krb5_kt_start_seq_get (context, id, &cursor); 631 1.1 elric if (ret) { 632 1.1 elric /* This is needed for krb5_verify_init_creds, but keep error 633 1.1 elric * string from previous error for the human. */ 634 1.1 elric context->error_code = KRB5_KT_NOTFOUND; 635 1.1 elric return KRB5_KT_NOTFOUND; 636 1.1 elric } 637 1.1 elric 638 1.1 elric entry->vno = 0; 639 1.1 elric while (krb5_kt_next_entry(context, id, &tmp, &cursor) == 0) { 640 1.1 elric if (krb5_kt_compare(context, &tmp, principal, 0, enctype)) { 641 1.1 elric /* the file keytab might only store the lower 8 bits of 642 1.1 elric the kvno, so only compare those bits */ 643 1.1 elric if (kvno == tmp.vno 644 1.1 elric || (tmp.vno < 256 && kvno % 256 == tmp.vno)) { 645 1.1 elric krb5_kt_copy_entry_contents (context, &tmp, entry); 646 1.1 elric krb5_kt_free_entry (context, &tmp); 647 1.1 elric krb5_kt_end_seq_get(context, id, &cursor); 648 1.1 elric return 0; 649 1.1 elric } else if (kvno == 0 && tmp.vno > entry->vno) { 650 1.1 elric if (entry->vno) 651 1.1 elric krb5_kt_free_entry (context, entry); 652 1.1 elric krb5_kt_copy_entry_contents (context, &tmp, entry); 653 1.1 elric } 654 1.1 elric } 655 1.1 elric krb5_kt_free_entry(context, &tmp); 656 1.1 elric } 657 1.1 elric krb5_kt_end_seq_get (context, id, &cursor); 658 1.1 elric if (entry->vno == 0) 659 1.1 elric return _krb5_kt_principal_not_found(context, KRB5_KT_NOTFOUND, 660 1.1 elric id, principal, enctype, kvno); 661 1.1 elric return 0; 662 1.1 elric } 663 1.1 elric 664 1.1 elric /** 665 1.2 christos * Retrieve the keytab entry for `principal, kvno, enctype' into `entry' 666 1.2 christos * from the keytab `id'. Matching is done like krb5_kt_compare(). 667 1.2 christos * 668 1.2 christos * @param context a Keberos context. 669 1.2 christos * @param id a keytab. 670 1.2 christos * @param principal principal to match, NULL matches all principals. 671 1.2 christos * @param kvno key version to match, 0 matches all key version numbers. 672 1.2 christos * @param enctype encryption type to match, 0 matches all encryption types. 673 1.2 christos * @param entry the returned entry, free with krb5_kt_free_entry(). 674 1.2 christos * 675 1.2 christos * @return Return an error code or 0, see krb5_get_error_message(). 676 1.2 christos * 677 1.2 christos * @ingroup krb5_keytab 678 1.2 christos */ 679 1.2 christos 680 1.2 christos KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 681 1.2 christos krb5_kt_get_entry(krb5_context context, 682 1.2 christos krb5_keytab id, 683 1.2 christos krb5_const_principal principal, 684 1.2 christos krb5_kvno kvno, 685 1.2 christos krb5_enctype enctype, 686 1.2 christos krb5_keytab_entry *entry) 687 1.2 christos { 688 1.2 christos krb5_error_code ret; 689 1.2 christos krb5_const_principal try_princ; 690 1.2 christos krb5_name_canon_iterator name_canon_iter; 691 1.2 christos 692 1.2 christos if (!principal) 693 1.2 christos return krb5_kt_get_entry_wrapped(context, id, principal, kvno, enctype, 694 1.2 christos entry); 695 1.2 christos 696 1.2 christos ret = krb5_name_canon_iterator_start(context, principal, &name_canon_iter); 697 1.2 christos if (ret) 698 1.2 christos return ret; 699 1.2 christos 700 1.2 christos do { 701 1.2 christos ret = krb5_name_canon_iterate(context, &name_canon_iter, &try_princ, 702 1.2 christos NULL); 703 1.2 christos if (ret) 704 1.2 christos break; 705 1.2 christos if (try_princ == NULL) { 706 1.2 christos ret = KRB5_KT_NOTFOUND; 707 1.2 christos continue; 708 1.2 christos } 709 1.2 christos ret = krb5_kt_get_entry_wrapped(context, id, try_princ, kvno, 710 1.2 christos enctype, entry); 711 1.2 christos } while (ret == KRB5_KT_NOTFOUND && name_canon_iter); 712 1.2 christos 713 1.2 christos if (ret != KRB5_KT_NOTFOUND) 714 1.2 christos krb5_set_error_message(context, ret, 715 1.2 christos N_("Name canon failed while searching keytab", 716 1.2 christos "")); 717 1.2 christos krb5_free_name_canon_iterator(context, name_canon_iter); 718 1.2 christos return ret; 719 1.2 christos } 720 1.2 christos 721 1.2 christos /** 722 1.1 elric * Copy the contents of `in' into `out'. 723 1.1 elric * 724 1.1 elric * @param context a Keberos context. 725 1.1 elric * @param in the keytab entry to copy. 726 1.1 elric * @param out the copy of the keytab entry, free with krb5_kt_free_entry(). 727 1.1 elric * 728 1.1 elric * @return Return an error code or 0, see krb5_get_error_message(). 729 1.1 elric * 730 1.1 elric * @ingroup krb5_keytab 731 1.1 elric */ 732 1.1 elric 733 1.1 elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 734 1.1 elric krb5_kt_copy_entry_contents(krb5_context context, 735 1.1 elric const krb5_keytab_entry *in, 736 1.1 elric krb5_keytab_entry *out) 737 1.1 elric { 738 1.1 elric krb5_error_code ret; 739 1.1 elric 740 1.1 elric memset(out, 0, sizeof(*out)); 741 1.1 elric 742 1.1 elric ret = krb5_copy_principal (context, in->principal, &out->principal); 743 1.1 elric if (ret) 744 1.3 christos return ret; 745 1.1 elric ret = krb5_copy_keyblock_contents (context, 746 1.1 elric &in->keyblock, 747 1.1 elric &out->keyblock); 748 1.3 christos if (ret) { 749 1.3 christos krb5_free_principal(context, out->principal); 750 1.3 christos memset(out, 0, sizeof(*out)); 751 1.3 christos return ret; 752 1.3 christos } 753 1.3 christos out->vno = in->vno; 754 1.1 elric out->timestamp = in->timestamp; 755 1.1 elric return 0; 756 1.1 elric } 757 1.1 elric 758 1.1 elric /** 759 1.1 elric * Free the contents of `entry'. 760 1.1 elric * 761 1.1 elric * @param context a Keberos context. 762 1.1 elric * @param entry the entry to free 763 1.1 elric * 764 1.1 elric * @return Return an error code or 0, see krb5_get_error_message(). 765 1.1 elric * 766 1.1 elric * @ingroup krb5_keytab 767 1.1 elric */ 768 1.1 elric 769 1.1 elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 770 1.1 elric krb5_kt_free_entry(krb5_context context, 771 1.1 elric krb5_keytab_entry *entry) 772 1.1 elric { 773 1.1 elric krb5_free_principal (context, entry->principal); 774 1.1 elric krb5_free_keyblock_contents (context, &entry->keyblock); 775 1.1 elric memset(entry, 0, sizeof(*entry)); 776 1.1 elric return 0; 777 1.1 elric } 778 1.1 elric 779 1.1 elric /** 780 1.1 elric * Set `cursor' to point at the beginning of `id'. 781 1.1 elric * 782 1.1 elric * @param context a Keberos context. 783 1.1 elric * @param id a keytab. 784 1.1 elric * @param cursor a newly allocated cursor, free with krb5_kt_end_seq_get(). 785 1.1 elric * 786 1.1 elric * @return Return an error code or 0, see krb5_get_error_message(). 787 1.1 elric * 788 1.1 elric * @ingroup krb5_keytab 789 1.1 elric */ 790 1.1 elric 791 1.1 elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 792 1.1 elric krb5_kt_start_seq_get(krb5_context context, 793 1.1 elric krb5_keytab id, 794 1.1 elric krb5_kt_cursor *cursor) 795 1.1 elric { 796 1.1 elric if(id->start_seq_get == NULL) { 797 1.1 elric krb5_set_error_message(context, HEIM_ERR_OPNOTSUPP, 798 1.1 elric N_("start_seq_get is not supported " 799 1.1 elric "in the %s keytab type", ""), 800 1.1 elric id->prefix); 801 1.1 elric return HEIM_ERR_OPNOTSUPP; 802 1.1 elric } 803 1.1 elric return (*id->start_seq_get)(context, id, cursor); 804 1.1 elric } 805 1.1 elric 806 1.1 elric /** 807 1.1 elric * Get the next entry from keytab, advance the cursor. On last entry 808 1.1 elric * the function will return KRB5_KT_END. 809 1.1 elric * 810 1.1 elric * @param context a Keberos context. 811 1.1 elric * @param id a keytab. 812 1.1 elric * @param entry the returned entry, free with krb5_kt_free_entry(). 813 1.1 elric * @param cursor the cursor of the iteration. 814 1.1 elric * 815 1.1 elric * @return Return an error code or 0, see krb5_get_error_message(). 816 1.1 elric * 817 1.1 elric * @ingroup krb5_keytab 818 1.1 elric */ 819 1.1 elric 820 1.1 elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 821 1.1 elric krb5_kt_next_entry(krb5_context context, 822 1.1 elric krb5_keytab id, 823 1.1 elric krb5_keytab_entry *entry, 824 1.1 elric krb5_kt_cursor *cursor) 825 1.1 elric { 826 1.1 elric if(id->next_entry == NULL) { 827 1.1 elric krb5_set_error_message(context, HEIM_ERR_OPNOTSUPP, 828 1.1 elric N_("next_entry is not supported in the %s " 829 1.1 elric " keytab", ""), 830 1.1 elric id->prefix); 831 1.1 elric return HEIM_ERR_OPNOTSUPP; 832 1.1 elric } 833 1.1 elric return (*id->next_entry)(context, id, entry, cursor); 834 1.1 elric } 835 1.1 elric 836 1.1 elric /** 837 1.1 elric * Release all resources associated with `cursor'. 838 1.1 elric * 839 1.1 elric * @param context a Keberos context. 840 1.1 elric * @param id a keytab. 841 1.1 elric * @param cursor the cursor to free. 842 1.1 elric * 843 1.1 elric * @return Return an error code or 0, see krb5_get_error_message(). 844 1.1 elric * 845 1.1 elric * @ingroup krb5_keytab 846 1.1 elric */ 847 1.1 elric 848 1.1 elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 849 1.1 elric krb5_kt_end_seq_get(krb5_context context, 850 1.1 elric krb5_keytab id, 851 1.1 elric krb5_kt_cursor *cursor) 852 1.1 elric { 853 1.1 elric if(id->end_seq_get == NULL) { 854 1.1 elric krb5_set_error_message(context, HEIM_ERR_OPNOTSUPP, 855 1.1 elric "end_seq_get is not supported in the %s " 856 1.1 elric " keytab", id->prefix); 857 1.1 elric return HEIM_ERR_OPNOTSUPP; 858 1.1 elric } 859 1.1 elric return (*id->end_seq_get)(context, id, cursor); 860 1.1 elric } 861 1.1 elric 862 1.1 elric /** 863 1.1 elric * Add the entry in `entry' to the keytab `id'. 864 1.1 elric * 865 1.1 elric * @param context a Keberos context. 866 1.1 elric * @param id a keytab. 867 1.1 elric * @param entry the entry to add 868 1.1 elric * 869 1.1 elric * @return Return an error code or 0, see krb5_get_error_message(). 870 1.1 elric * 871 1.1 elric * @ingroup krb5_keytab 872 1.1 elric */ 873 1.1 elric 874 1.1 elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 875 1.1 elric krb5_kt_add_entry(krb5_context context, 876 1.1 elric krb5_keytab id, 877 1.1 elric krb5_keytab_entry *entry) 878 1.1 elric { 879 1.1 elric if(id->add == NULL) { 880 1.1 elric krb5_set_error_message(context, KRB5_KT_NOWRITE, 881 1.1 elric N_("Add is not supported in the %s keytab", ""), 882 1.1 elric id->prefix); 883 1.1 elric return KRB5_KT_NOWRITE; 884 1.1 elric } 885 1.1 elric entry->timestamp = time(NULL); 886 1.1 elric return (*id->add)(context, id,entry); 887 1.1 elric } 888 1.1 elric 889 1.1 elric /** 890 1.1 elric * Remove an entry from the keytab, matching is done using 891 1.1 elric * krb5_kt_compare(). 892 1.1 elric 893 1.1 elric * @param context a Keberos context. 894 1.1 elric * @param id a keytab. 895 1.1 elric * @param entry the entry to remove 896 1.1 elric * 897 1.1 elric * @return Return an error code or 0, see krb5_get_error_message(). 898 1.1 elric * 899 1.1 elric * @ingroup krb5_keytab 900 1.1 elric */ 901 1.1 elric 902 1.1 elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 903 1.1 elric krb5_kt_remove_entry(krb5_context context, 904 1.1 elric krb5_keytab id, 905 1.1 elric krb5_keytab_entry *entry) 906 1.1 elric { 907 1.1 elric if(id->remove == NULL) { 908 1.1 elric krb5_set_error_message(context, KRB5_KT_NOWRITE, 909 1.1 elric N_("Remove is not supported in the %s keytab", ""), 910 1.1 elric id->prefix); 911 1.1 elric return KRB5_KT_NOWRITE; 912 1.1 elric } 913 1.1 elric return (*id->remove)(context, id, entry); 914 1.1 elric } 915 1.1 elric 916 1.1 elric /** 917 1.1 elric * Return true if the keytab exists and have entries 918 1.1 elric * 919 1.1 elric * @param context a Keberos context. 920 1.1 elric * @param id a keytab. 921 1.1 elric * 922 1.1 elric * @return Return an error code or 0, see krb5_get_error_message(). 923 1.1 elric * 924 1.1 elric * @ingroup krb5_keytab 925 1.1 elric */ 926 1.1 elric 927 1.2 christos KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 928 1.1 elric krb5_kt_have_content(krb5_context context, 929 1.1 elric krb5_keytab id) 930 1.1 elric { 931 1.1 elric krb5_keytab_entry entry; 932 1.1 elric krb5_kt_cursor cursor; 933 1.1 elric krb5_error_code ret; 934 1.1 elric char *name; 935 1.1 elric 936 1.3 christos memset(&entry, 0, sizeof(entry)); 937 1.1 elric ret = krb5_kt_start_seq_get(context, id, &cursor); 938 1.1 elric if (ret) 939 1.1 elric goto notfound; 940 1.1 elric 941 1.1 elric ret = krb5_kt_next_entry(context, id, &entry, &cursor); 942 1.1 elric krb5_kt_end_seq_get(context, id, &cursor); 943 1.1 elric if (ret) 944 1.1 elric goto notfound; 945 1.1 elric 946 1.1 elric krb5_kt_free_entry(context, &entry); 947 1.1 elric 948 1.1 elric return 0; 949 1.1 elric 950 1.1 elric notfound: 951 1.1 elric ret = krb5_kt_get_full_name(context, id, &name); 952 1.1 elric if (ret == 0) { 953 1.1 elric krb5_set_error_message(context, KRB5_KT_NOTFOUND, 954 1.1 elric N_("No entry in keytab: %s", ""), name); 955 1.1 elric free(name); 956 1.1 elric } 957 1.1 elric return KRB5_KT_NOTFOUND; 958 1.1 elric } 959