Home | History | Annotate | Download | only in keytab
      1 /*
      2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 
      6 /*
      7  * lib/krb5/keytab/srvtab/kts_resolv.c
      8  *
      9  * Copyright 1990,1991,2002 by the Massachusetts Institute of Technology.
     10  * All Rights Reserved.
     11  *
     12  * Export of this software from the United States of America may
     13  *   require a specific license from the United States Government.
     14  *   It is the responsibility of any person or organization contemplating
     15  *   export to obtain such a license before exporting.
     16  *
     17  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
     18  * distribute this software and its documentation for any purpose and
     19  * without fee is hereby granted, provided that the above copyright
     20  * notice appear in all copies and that both that copyright notice and
     21  * this permission notice appear in supporting documentation, and that
     22  * the name of M.I.T. not be used in advertising or publicity pertaining
     23  * to distribution of the software without specific, written prior
     24  * permission.  Furthermore if you modify this software you must label
     25  * your software as modified software and not distribute it in such a
     26  * fashion that it might be confused with the original M.I.T. software.
     27  * M.I.T. makes no representations about the suitability of
     28  * this software for any purpose.  It is provided "as is" without express
     29  * or implied warranty.
     30  */
     31 
     32 #include "k5-int.h"
     33 #include <stdio.h>
     34 
     35 /*
     36  * Constants
     37  */
     38 #define IGNORE_VNO 0
     39 #define IGNORE_ENCTYPE 0
     40 
     41 #define KRB5_KT_VNO_1	0x0501	/* krb v5, keytab version 1 (DCE compat) */
     42 #define KRB5_KT_VNO	0x0502	/* krb v5, keytab version 2 (standard)  */
     43 
     44 #define KRB5_KT_DEFAULT_VNO KRB5_KT_VNO
     45 
     46 /*
     47  * Types
     48  */
     49 typedef struct _krb5_ktsrvtab_data {
     50     char *name;			/* Name of the file */
     51     FILE *openf;		/* open file, if any. */
     52 } krb5_ktsrvtab_data;
     53 
     54 /*
     55  * Macros
     56  */
     57 #define KTPRIVATE(id) ((krb5_ktsrvtab_data *)(id)->data)
     58 #define KTFILENAME(id) (((krb5_ktsrvtab_data *)(id)->data)->name)
     59 #define KTFILEP(id) (((krb5_ktsrvtab_data *)(id)->data)->openf)
     60 
     61 extern const struct _krb5_kt_ops krb5_kts_ops;
     62 
     63 static krb5_error_code KRB5_CALLCONV krb5_ktsrvtab_resolve
     64 	(krb5_context,
     65 		   const char *,
     66 		   krb5_keytab *);
     67 
     68 static krb5_error_code KRB5_CALLCONV krb5_ktsrvtab_get_name
     69 	(krb5_context,
     70 		   krb5_keytab,
     71 		   char *,
     72 		   unsigned int);
     73 
     74 static krb5_error_code KRB5_CALLCONV krb5_ktsrvtab_close
     75 	(krb5_context,
     76 		   krb5_keytab);
     77 
     78 static krb5_error_code KRB5_CALLCONV krb5_ktsrvtab_get_entry
     79 	(krb5_context,
     80 		   krb5_keytab,
     81 		   krb5_const_principal,
     82 		   krb5_kvno,
     83 		   krb5_enctype,
     84 		   krb5_keytab_entry *);
     85 
     86 static krb5_error_code KRB5_CALLCONV krb5_ktsrvtab_start_seq_get
     87 	(krb5_context,
     88 		   krb5_keytab,
     89 		   krb5_kt_cursor *);
     90 
     91 static krb5_error_code KRB5_CALLCONV krb5_ktsrvtab_get_next
     92 	(krb5_context,
     93 		   krb5_keytab,
     94 		   krb5_keytab_entry *,
     95 		   krb5_kt_cursor *);
     96 
     97 static krb5_error_code KRB5_CALLCONV krb5_ktsrvtab_end_get
     98 	(krb5_context,
     99 		   krb5_keytab,
    100 		   krb5_kt_cursor *);
    101 
    102 static krb5_error_code krb5_ktsrvint_open
    103 	(krb5_context,
    104 		   krb5_keytab);
    105 
    106 static krb5_error_code krb5_ktsrvint_close
    107 	(krb5_context,
    108 		   krb5_keytab);
    109 
    110 static krb5_error_code krb5_ktsrvint_read_entry
    111 	(krb5_context,
    112 		   krb5_keytab,
    113 		   krb5_keytab_entry *);
    114 
    115 /*
    116  * This is an implementation specific resolver.  It returns a keytab id
    117  * initialized with srvtab keytab routines.
    118  */
    119 
    120 static krb5_error_code KRB5_CALLCONV
    121 krb5_ktsrvtab_resolve(krb5_context context, const char *name, krb5_keytab *id)
    122 {
    123     krb5_ktsrvtab_data *data;
    124     FILE *fp;
    125 
    126     /* Make sure we can open the srvtab file for reading. */
    127     /* Solaris Kerberos */
    128     fp = fopen(name, "rF");
    129     if (!fp)
    130 	return(errno);
    131     fclose(fp);
    132 
    133     if ((*id = (krb5_keytab) malloc(sizeof(**id))) == NULL)
    134 	return(ENOMEM);
    135 
    136     (*id)->ops = &krb5_kts_ops;
    137     data = (krb5_ktsrvtab_data *)malloc(sizeof(krb5_ktsrvtab_data));
    138     if (data == NULL) {
    139 	krb5_xfree(*id);
    140 	return(ENOMEM);
    141     }
    142 
    143     data->name = (char *)malloc(strlen(name) + 1);
    144     if (data->name == NULL) {
    145 	krb5_xfree(data);
    146 	krb5_xfree(*id);
    147 	return(ENOMEM);
    148     }
    149 
    150     (void) strcpy(data->name, name);
    151     data->openf = 0;
    152 
    153     (*id)->data = (krb5_pointer)data;
    154     (*id)->magic = KV5M_KEYTAB;
    155     return(0);
    156 }
    157 
    158 /*
    159  * "Close" a file-based keytab and invalidate the id.  This means
    160  * free memory hidden in the structures.
    161  */
    162 
    163 krb5_error_code KRB5_CALLCONV
    164 krb5_ktsrvtab_close(krb5_context context, krb5_keytab id)
    165   /*
    166    * This routine is responsible for freeing all memory allocated
    167    * for this keytab.  There are no system resources that need
    168    * to be freed nor are there any open files.
    169    *
    170    * This routine should undo anything done by krb5_ktsrvtab_resolve().
    171    */
    172 {
    173     krb5_xfree(KTFILENAME(id));
    174     krb5_xfree(id->data);
    175     id->ops = 0;
    176     krb5_xfree(id);
    177     return (0);
    178 }
    179 
    180 /*
    181  * This is the get_entry routine for the file based keytab implementation.
    182  * It opens the keytab file, and either retrieves the entry or returns
    183  * an error.
    184  */
    185 
    186 krb5_error_code KRB5_CALLCONV
    187 krb5_ktsrvtab_get_entry(krb5_context context, krb5_keytab id, krb5_const_principal principal, krb5_kvno kvno, krb5_enctype enctype, krb5_keytab_entry *entry)
    188 {
    189     krb5_keytab_entry best_entry, ent;
    190     krb5_error_code kerror = 0;
    191     int found_wrong_kvno = 0;
    192 
    193     /* Open the srvtab. */
    194     if ((kerror = krb5_ktsrvint_open(context, id)))
    195 	return(kerror);
    196 
    197     /* srvtab files only have DES_CBC_CRC keys. */
    198     switch (enctype) {
    199     case ENCTYPE_DES_CBC_CRC:
    200     case ENCTYPE_DES_CBC_MD5:
    201     case ENCTYPE_DES_CBC_MD4:
    202     case ENCTYPE_DES_CBC_RAW:
    203     case IGNORE_ENCTYPE:
    204 	break;
    205     default:
    206 	return KRB5_KT_NOTFOUND;
    207     }
    208 
    209     best_entry.principal = 0;
    210     best_entry.vno = 0;
    211     best_entry.key.contents = 0;
    212     while ((kerror = krb5_ktsrvint_read_entry(context, id, &ent)) == 0) {
    213 	ent.key.enctype = enctype;
    214 	if (krb5_principal_compare(context, principal, ent.principal)) {
    215 	    if (kvno == IGNORE_VNO) {
    216 		if (!best_entry.principal || (best_entry.vno < ent.vno)) {
    217 		    krb5_kt_free_entry(context, &best_entry);
    218 		    best_entry = ent;
    219 		}
    220 	    } else {
    221 		if (ent.vno == kvno) {
    222 		    best_entry = ent;
    223 		    break;
    224 		} else {
    225 		    found_wrong_kvno = 1;
    226 		}
    227 	    }
    228 	} else {
    229 	    krb5_kt_free_entry(context, &ent);
    230 	}
    231     }
    232     if (kerror == KRB5_KT_END) {
    233 	 if (best_entry.principal)
    234 	      kerror = 0;
    235 	 else if (found_wrong_kvno)
    236 	      kerror = KRB5_KT_KVNONOTFOUND;
    237 	 else
    238 	      kerror = KRB5_KT_NOTFOUND;
    239     }
    240     if (kerror) {
    241 	(void) krb5_ktsrvint_close(context, id);
    242 	krb5_kt_free_entry(context, &best_entry);
    243 	return kerror;
    244     }
    245     if ((kerror = krb5_ktsrvint_close(context, id)) != 0) {
    246 	krb5_kt_free_entry(context, &best_entry);
    247 	return kerror;
    248     }
    249     *entry = best_entry;
    250     return 0;
    251 }
    252 
    253 /*
    254  * Get the name of the file containing a srvtab-based keytab.
    255  */
    256 
    257 krb5_error_code KRB5_CALLCONV
    258 krb5_ktsrvtab_get_name(krb5_context context, krb5_keytab id, char *name, unsigned int len)
    259   /*
    260    * This routine returns the name of the name of the file associated with
    261    * this srvtab-based keytab.  The name is prefixed with PREFIX:, so that
    262    * trt will happen if the name is passed back to resolve.
    263    */
    264 {
    265     memset(name, 0, len);
    266 
    267     if (len < strlen(id->ops->prefix)+2)
    268 	return(KRB5_KT_NAME_TOOLONG);
    269     strcpy(name, id->ops->prefix);
    270     name += strlen(id->ops->prefix);
    271     name[0] = ':';
    272     name++;
    273     len -= strlen(id->ops->prefix)+1;
    274 
    275     /* Solaris Kerberos */
    276     if (len < strlen(KTFILENAME(id))+1)
    277 	return(KRB5_KT_NAME_TOOLONG);
    278     strcpy(name, KTFILENAME(id));
    279     /* strcpy will NUL-terminate the destination */
    280 
    281     return(0);
    282 }
    283 
    284 /*
    285  * krb5_ktsrvtab_start_seq_get()
    286  */
    287 
    288 krb5_error_code KRB5_CALLCONV
    289 krb5_ktsrvtab_start_seq_get(krb5_context context, krb5_keytab id, krb5_kt_cursor *cursorp)
    290 {
    291     krb5_error_code retval;
    292     long *fileoff;
    293 
    294     if ((retval = krb5_ktsrvint_open(context, id)))
    295 	return retval;
    296 
    297     if (!(fileoff = (long *)malloc(sizeof(*fileoff)))) {
    298 	krb5_ktsrvint_close(context, id);
    299 	return ENOMEM;
    300     }
    301     *fileoff = ftell(KTFILEP(id));
    302     *cursorp = (krb5_kt_cursor)fileoff;
    303 
    304     return 0;
    305 }
    306 
    307 /*
    308  * krb5_ktsrvtab_get_next()
    309  */
    310 
    311 krb5_error_code KRB5_CALLCONV
    312 krb5_ktsrvtab_get_next(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry, krb5_kt_cursor *cursor)
    313 {
    314     long *fileoff = (long *)*cursor;
    315     krb5_keytab_entry cur_entry;
    316     krb5_error_code kerror;
    317 
    318     if (fseek(KTFILEP(id), *fileoff, 0) == -1)
    319 	return KRB5_KT_END;
    320     if ((kerror = krb5_ktsrvint_read_entry(context, id, &cur_entry)))
    321 	return kerror;
    322     *fileoff = ftell(KTFILEP(id));
    323     *entry = cur_entry;
    324     return 0;
    325 }
    326 
    327 /*
    328  * krb5_ktsrvtab_end_get()
    329  */
    330 
    331 krb5_error_code KRB5_CALLCONV
    332 krb5_ktsrvtab_end_get(krb5_context context, krb5_keytab id, krb5_kt_cursor *cursor)
    333 {
    334     krb5_xfree(*cursor);
    335     return krb5_ktsrvint_close(context, id);
    336 }
    337 
    338 /*
    339  * krb5_kts_ops
    340  */
    341 
    342 const struct _krb5_kt_ops krb5_kts_ops = {
    343     0,
    344     "SRVTAB", 	/* Prefix -- this string should not appear anywhere else! */
    345     krb5_ktsrvtab_resolve,
    346     krb5_ktsrvtab_get_name,
    347     krb5_ktsrvtab_close,
    348     krb5_ktsrvtab_get_entry,
    349     krb5_ktsrvtab_start_seq_get,
    350     krb5_ktsrvtab_get_next,
    351     krb5_ktsrvtab_end_get,
    352     0,
    353     0,
    354     0
    355 };
    356 
    357 /*
    358  * formerly: lib/krb5/keytab/srvtab/kts_util.c
    359  *
    360  * Copyright (c) Hewlett-Packard Company 1991
    361  * Released to the Massachusetts Institute of Technology for inclusion
    362  * in the Kerberos source code distribution.
    363  *
    364  * Copyright 1990,1991 by the Massachusetts Institute of Technology.
    365  * All Rights Reserved.
    366  *
    367  * Export of this software from the United States of America may
    368  *   require a specific license from the United States Government.
    369  *   It is the responsibility of any person or organization contemplating
    370  *   export to obtain such a license before exporting.
    371  *
    372  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
    373  * distribute this software and its documentation for any purpose and
    374  * without fee is hereby granted, provided that the above copyright
    375  * notice appear in all copies and that both that copyright notice and
    376  * this permission notice appear in supporting documentation, and that
    377  * the name of M.I.T. not be used in advertising or publicity pertaining
    378  * to distribution of the software without specific, written prior
    379  * permission.  Furthermore if you modify this software you must label
    380  * your software as modified software and not distribute it in such a
    381  * fashion that it might be confused with the original M.I.T. software.
    382  * M.I.T. makes no representations about the suitability of
    383  * this software for any purpose.  It is provided "as is" without express
    384  * or implied warranty.
    385  *
    386  *
    387  * This function contains utilities for the srvtab based implementation
    388  * of the keytab.  There are no public functions in this file.
    389  */
    390 
    391 #include <stdio.h>
    392 
    393 #ifdef ANSI_STDIO
    394 /* Solaris Kerberos */
    395 #define		READ_MODE	"rbF"
    396 #else
    397 /* Solaris Kerberos */
    398 #define		READ_MODE	"rF"
    399 #endif
    400 
    401 /* The maximum sizes for V4 aname, realm, sname, and instance +1 */
    402 /* Taken from krb.h */
    403 #define 	ANAME_SZ	40
    404 #define		REALM_SZ	40
    405 #define		SNAME_SZ	40
    406 #define		INST_SZ		40
    407 
    408 static krb5_error_code
    409 read_field(FILE *fp, char *s, int len)
    410 {
    411     int c;
    412 
    413     while ((c = getc(fp)) != 0) {
    414 	if (c == EOF || len <= 1)
    415 	    return KRB5_KT_END;
    416 	*s = c;
    417 	s++;
    418 	len--;
    419     }
    420     *s = 0;
    421     return 0;
    422 }
    423 
    424 krb5_error_code
    425 krb5_ktsrvint_open(krb5_context context, krb5_keytab id)
    426 {
    427     KTFILEP(id) = fopen(KTFILENAME(id), READ_MODE);
    428     if (!KTFILEP(id))
    429 	return errno;
    430     return 0;
    431 }
    432 
    433 krb5_error_code
    434 krb5_ktsrvint_close(krb5_context context, krb5_keytab id)
    435 {
    436     if (!KTFILEP(id))
    437 	return 0;
    438     (void) fclose(KTFILEP(id));
    439     KTFILEP(id) = 0;
    440     return 0;
    441 }
    442 
    443 krb5_error_code
    444 krb5_ktsrvint_read_entry(krb5_context context, krb5_keytab id, krb5_keytab_entry *ret_entry)
    445 {
    446     FILE *fp;
    447     char name[SNAME_SZ], instance[INST_SZ], realm[REALM_SZ];
    448     unsigned char key[8];
    449     int vno;
    450     krb5_error_code kerror;
    451 
    452     /* Read in an entry from the srvtab file. */
    453     fp = KTFILEP(id);
    454     kerror = read_field(fp, name, sizeof(name));
    455     if (kerror != 0)
    456 	return kerror;
    457     kerror = read_field(fp, instance, sizeof(instance));
    458     if (kerror != 0)
    459 	return kerror;
    460     kerror = read_field(fp, realm, sizeof(realm));
    461     if (kerror != 0)
    462 	return kerror;
    463     vno = getc(fp);
    464     if (vno == EOF)
    465 	return KRB5_KT_END;
    466     if (fread(key, 1, sizeof(key), fp) != sizeof(key))
    467 	return KRB5_KT_END;
    468 
    469     /* Fill in ret_entry with the data we read.  Everything maps well
    470      * except for the timestamp, which we don't have a value for.  For
    471      * now we just set it to 0. */
    472     memset(ret_entry, 0, sizeof(*ret_entry));
    473     ret_entry->magic = KV5M_KEYTAB_ENTRY;
    474     kerror = krb5_425_conv_principal(context, name, instance, realm,
    475 				     &ret_entry->principal);
    476     if (kerror != 0)
    477 	return kerror;
    478     ret_entry->vno = vno;
    479     ret_entry->timestamp = 0;
    480     ret_entry->key.enctype = ENCTYPE_DES_CBC_CRC;
    481     ret_entry->key.magic = KV5M_KEYBLOCK;
    482     ret_entry->key.length = sizeof(key);
    483     ret_entry->key.contents = malloc(sizeof(key));
    484     if (!ret_entry->key.contents) {
    485 	krb5_free_principal(context, ret_entry->principal);
    486 	return ENOMEM;
    487     }
    488     memcpy(ret_entry->key.contents, key, sizeof(key));
    489 
    490     return 0;
    491 }
    492