10Sstevel@tonic-gate /* 2*1692Ssemery * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 30Sstevel@tonic-gate * Use is subject to license terms. 40Sstevel@tonic-gate */ 50Sstevel@tonic-gate 60Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 70Sstevel@tonic-gate 80Sstevel@tonic-gate /* 90Sstevel@tonic-gate * kadmin/ktutil/ktutil_funcs.c 100Sstevel@tonic-gate * 110Sstevel@tonic-gate *(C) Copyright 1995, 1996 by the Massachusetts Institute of Technology. 120Sstevel@tonic-gate * All Rights Reserved. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * Export of this software from the United States of America may 150Sstevel@tonic-gate * require a specific license from the United States Government. 160Sstevel@tonic-gate * It is the responsibility of any person or organization contemplating 170Sstevel@tonic-gate * export to obtain such a license before exporting. 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 200Sstevel@tonic-gate * distribute this software and its documentation for any purpose and 210Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright 220Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and 230Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that 240Sstevel@tonic-gate * the name of M.I.T. not be used in advertising or publicity pertaining 250Sstevel@tonic-gate * to distribution of the software without specific, written prior 260Sstevel@tonic-gate * permission. Furthermore if you modify this software you must label 270Sstevel@tonic-gate * your software as modified software and not distribute it in such a 280Sstevel@tonic-gate * fashion that it might be confused with the original M.I.T. software. 290Sstevel@tonic-gate * M.I.T. makes no representations about the suitability of 300Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express 310Sstevel@tonic-gate * or implied warranty. 320Sstevel@tonic-gate * 330Sstevel@tonic-gate * Utility functions for ktutil. 340Sstevel@tonic-gate */ 350Sstevel@tonic-gate 360Sstevel@tonic-gate #include "k5-int.h" 370Sstevel@tonic-gate #include "ktutil.h" 380Sstevel@tonic-gate #ifdef KRB5_KRB4_COMPAT 390Sstevel@tonic-gate #include "kerberosIV/krb.h" 400Sstevel@tonic-gate #include <stdio.h> 410Sstevel@tonic-gate #endif 420Sstevel@tonic-gate #include <string.h> 430Sstevel@tonic-gate #include <ctype.h> 440Sstevel@tonic-gate #include <libintl.h> 450Sstevel@tonic-gate 460Sstevel@tonic-gate /* 470Sstevel@tonic-gate * Free a kt_list 480Sstevel@tonic-gate */ 490Sstevel@tonic-gate krb5_error_code ktutil_free_kt_list(context, list) 500Sstevel@tonic-gate krb5_context context; 510Sstevel@tonic-gate krb5_kt_list list; 520Sstevel@tonic-gate { 530Sstevel@tonic-gate krb5_kt_list lp, prev; 540Sstevel@tonic-gate krb5_error_code retval = 0; 550Sstevel@tonic-gate 560Sstevel@tonic-gate for (lp = list; lp;) { 570Sstevel@tonic-gate retval = krb5_kt_free_entry(context, lp->entry); 580Sstevel@tonic-gate free((char *)lp->entry); 590Sstevel@tonic-gate if (retval) 600Sstevel@tonic-gate break; 610Sstevel@tonic-gate prev = lp; 620Sstevel@tonic-gate lp = lp->next; 630Sstevel@tonic-gate free((char *)prev); 640Sstevel@tonic-gate } 650Sstevel@tonic-gate return retval; 660Sstevel@tonic-gate } 670Sstevel@tonic-gate 680Sstevel@tonic-gate /* 690Sstevel@tonic-gate * Delete a numbered entry in a kt_list. Takes a pointer to a kt_list 700Sstevel@tonic-gate * in case head gets deleted. 710Sstevel@tonic-gate */ 720Sstevel@tonic-gate krb5_error_code ktutil_delete(context, list, index) 730Sstevel@tonic-gate krb5_context context; 740Sstevel@tonic-gate krb5_kt_list *list; 750Sstevel@tonic-gate int index; 760Sstevel@tonic-gate { 770Sstevel@tonic-gate krb5_kt_list lp, prev; 780Sstevel@tonic-gate int i; 790Sstevel@tonic-gate 800Sstevel@tonic-gate for (lp = *list, i = 1; lp; prev = lp, lp = lp->next, i++) { 810Sstevel@tonic-gate if (i == index) { 820Sstevel@tonic-gate if (i == 1) 830Sstevel@tonic-gate *list = lp->next; 840Sstevel@tonic-gate else 850Sstevel@tonic-gate prev->next = lp->next; 860Sstevel@tonic-gate lp->next = NULL; 870Sstevel@tonic-gate return ktutil_free_kt_list(context, lp); 880Sstevel@tonic-gate } 890Sstevel@tonic-gate } 900Sstevel@tonic-gate return EINVAL; 910Sstevel@tonic-gate } 920Sstevel@tonic-gate 930Sstevel@tonic-gate /* 940Sstevel@tonic-gate * Create a new keytab entry and add it to the keytab list. 950Sstevel@tonic-gate * Based on the value of use_pass, either prompt the user for a 960Sstevel@tonic-gate * password or key. If the keytab list is NULL, allocate a new 970Sstevel@tonic-gate * one first. 980Sstevel@tonic-gate */ 990Sstevel@tonic-gate krb5_error_code ktutil_add(context, list, princ_str, kvno, 1000Sstevel@tonic-gate enctype_str, use_pass) 1010Sstevel@tonic-gate krb5_context context; 1020Sstevel@tonic-gate krb5_kt_list *list; 1030Sstevel@tonic-gate char *princ_str; 1040Sstevel@tonic-gate krb5_kvno kvno; 1050Sstevel@tonic-gate char *enctype_str; 1060Sstevel@tonic-gate int use_pass; 1070Sstevel@tonic-gate { 1080Sstevel@tonic-gate krb5_keytab_entry *entry; 1090Sstevel@tonic-gate krb5_kt_list lp = NULL, prev = NULL; 1100Sstevel@tonic-gate krb5_principal princ; 1110Sstevel@tonic-gate krb5_enctype enctype; 1120Sstevel@tonic-gate krb5_timestamp now; 1130Sstevel@tonic-gate krb5_error_code retval; 1140Sstevel@tonic-gate krb5_data password, salt; 1150Sstevel@tonic-gate krb5_keyblock key; 1160Sstevel@tonic-gate char buf[BUFSIZ]; 1170Sstevel@tonic-gate char promptstr[1024]; 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate char *cp; 1200Sstevel@tonic-gate int i, tmp, pwsize = BUFSIZ; 1210Sstevel@tonic-gate 1220Sstevel@tonic-gate retval = krb5_parse_name(context, princ_str, &princ); 1230Sstevel@tonic-gate if (retval) 1240Sstevel@tonic-gate return retval; 1250Sstevel@tonic-gate /* now unparse in order to get the default realm appended 1260Sstevel@tonic-gate to princ_str, if no realm was specified */ 1270Sstevel@tonic-gate retval = krb5_unparse_name(context, princ, &princ_str); 1280Sstevel@tonic-gate if (retval) 1290Sstevel@tonic-gate return retval; 1300Sstevel@tonic-gate retval = krb5_string_to_enctype(enctype_str, &enctype); 1310Sstevel@tonic-gate if (retval) 1320Sstevel@tonic-gate return KRB5_BAD_ENCTYPE; 1330Sstevel@tonic-gate retval = krb5_timeofday(context, &now); 1340Sstevel@tonic-gate if (retval) 1350Sstevel@tonic-gate return retval; 1360Sstevel@tonic-gate 1370Sstevel@tonic-gate if (*list) { 1380Sstevel@tonic-gate /* point lp at the tail of the list */ 1390Sstevel@tonic-gate for (lp = *list; lp->next; lp = lp->next); 1400Sstevel@tonic-gate } 1410Sstevel@tonic-gate entry = (krb5_keytab_entry *) malloc(sizeof(krb5_keytab_entry)); 1420Sstevel@tonic-gate if (!entry) { 1430Sstevel@tonic-gate return ENOMEM; 1440Sstevel@tonic-gate } 1450Sstevel@tonic-gate memset((char *) entry, 0, sizeof(*entry)); 1460Sstevel@tonic-gate 1470Sstevel@tonic-gate if (!lp) { /* if list is empty, start one */ 1480Sstevel@tonic-gate lp = (krb5_kt_list) malloc(sizeof(krb5_kt_list)); 1490Sstevel@tonic-gate if (!lp) { 1500Sstevel@tonic-gate return ENOMEM; 1510Sstevel@tonic-gate } 1520Sstevel@tonic-gate } else { 1530Sstevel@tonic-gate lp->next = (krb5_kt_list) malloc(sizeof(krb5_kt_list)); 1540Sstevel@tonic-gate if (!lp->next) { 1550Sstevel@tonic-gate return ENOMEM; 1560Sstevel@tonic-gate } 1570Sstevel@tonic-gate prev = lp; 1580Sstevel@tonic-gate lp = lp->next; 1590Sstevel@tonic-gate } 1600Sstevel@tonic-gate lp->next = NULL; 1610Sstevel@tonic-gate lp->entry = entry; 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate if (use_pass) { 1640Sstevel@tonic-gate password.length = pwsize; 1650Sstevel@tonic-gate password.data = (char *) malloc(pwsize); 1660Sstevel@tonic-gate if (!password.data) { 1670Sstevel@tonic-gate retval = ENOMEM; 1680Sstevel@tonic-gate goto cleanup; 1690Sstevel@tonic-gate } 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate (void) snprintf(promptstr, sizeof(promptstr), 172*1692Ssemery gettext("Password for %.1000s"), princ_str); 1730Sstevel@tonic-gate retval = krb5_read_password(context, promptstr, NULL, password.data, 1740Sstevel@tonic-gate &password.length); 1750Sstevel@tonic-gate if (retval) 1760Sstevel@tonic-gate goto cleanup; 1770Sstevel@tonic-gate retval = krb5_principal2salt(context, princ, &salt); 1780Sstevel@tonic-gate if (retval) 1790Sstevel@tonic-gate goto cleanup; 1800Sstevel@tonic-gate retval = krb5_c_string_to_key(context, enctype, &password, 1810Sstevel@tonic-gate &salt, &key); 1820Sstevel@tonic-gate if (retval) 1830Sstevel@tonic-gate goto cleanup; 1840Sstevel@tonic-gate memset(password.data, 0, password.length); 1850Sstevel@tonic-gate password.length = 0; 1860Sstevel@tonic-gate memcpy(&lp->entry->key, &key, sizeof(krb5_keyblock)); 1870Sstevel@tonic-gate } else { 1880Sstevel@tonic-gate printf(gettext("Key for %s (hex): "), princ_str); 1890Sstevel@tonic-gate fgets(buf, BUFSIZ, stdin); 1900Sstevel@tonic-gate /* 1910Sstevel@tonic-gate * We need to get rid of the trailing '\n' from fgets. 1920Sstevel@tonic-gate * If we have an even number of hex digits (as we should), 1930Sstevel@tonic-gate * write a '\0' over the '\n'. If for some reason we have 1940Sstevel@tonic-gate * an odd number of hex digits, force an even number of hex 1950Sstevel@tonic-gate * digits by writing a '0' into the last position (the string 1960Sstevel@tonic-gate * will still be null-terminated). 1970Sstevel@tonic-gate */ 1980Sstevel@tonic-gate buf[strlen(buf) - 1] = strlen(buf) % 2 ? '\0' : '0'; 1990Sstevel@tonic-gate if (strlen(buf) == 0) { 2000Sstevel@tonic-gate fprintf(stderr, "addent: %s", gettext("Error reading key.\n")); 2010Sstevel@tonic-gate retval = 0; 2020Sstevel@tonic-gate goto cleanup; 2030Sstevel@tonic-gate } 2040Sstevel@tonic-gate 2050Sstevel@tonic-gate lp->entry->key.enctype = enctype; 2060Sstevel@tonic-gate lp->entry->key.contents = (krb5_octet *) malloc((strlen(buf) + 1) / 2); 2070Sstevel@tonic-gate if (!lp->entry->key.contents) { 2080Sstevel@tonic-gate retval = ENOMEM; 2090Sstevel@tonic-gate goto cleanup; 2100Sstevel@tonic-gate } 2110Sstevel@tonic-gate 2120Sstevel@tonic-gate i = 0; 2130Sstevel@tonic-gate for (cp = buf; *cp; cp += 2) { 2140Sstevel@tonic-gate if (!isxdigit(cp[0]) || !isxdigit(cp[1])) { 2150Sstevel@tonic-gate fprintf(stderr, "addent: %s", 2160Sstevel@tonic-gate gettext("Illegal character in key.\n")); 2170Sstevel@tonic-gate retval = 0; 2180Sstevel@tonic-gate goto cleanup; 2190Sstevel@tonic-gate } 2200Sstevel@tonic-gate sscanf(cp, "%02x", &tmp); 2210Sstevel@tonic-gate lp->entry->key.contents[i++] = (krb5_octet) tmp; 2220Sstevel@tonic-gate } 2230Sstevel@tonic-gate lp->entry->key.length = i; 2240Sstevel@tonic-gate } 2250Sstevel@tonic-gate lp->entry->principal = princ; 2260Sstevel@tonic-gate lp->entry->vno = kvno; 2270Sstevel@tonic-gate lp->entry->timestamp = now; 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate if (!*list) 2300Sstevel@tonic-gate *list = lp; 2310Sstevel@tonic-gate 2320Sstevel@tonic-gate return 0; 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate cleanup: 2350Sstevel@tonic-gate if (prev) 2360Sstevel@tonic-gate prev->next = NULL; 2370Sstevel@tonic-gate ktutil_free_kt_list(context, lp); 2380Sstevel@tonic-gate return retval; 2390Sstevel@tonic-gate } 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate /* 2420Sstevel@tonic-gate * Read in a keytab and append it to list. If list starts as NULL, 2430Sstevel@tonic-gate * allocate a new one if necessary. 2440Sstevel@tonic-gate */ 2450Sstevel@tonic-gate krb5_error_code ktutil_read_keytab(context, name, list) 2460Sstevel@tonic-gate krb5_context context; 2470Sstevel@tonic-gate char *name; 2480Sstevel@tonic-gate krb5_kt_list *list; 2490Sstevel@tonic-gate { 2500Sstevel@tonic-gate krb5_kt_list lp = NULL, tail = NULL, back = NULL; 2510Sstevel@tonic-gate krb5_keytab kt; 2520Sstevel@tonic-gate krb5_keytab_entry *entry; 2530Sstevel@tonic-gate krb5_kt_cursor cursor; 2540Sstevel@tonic-gate krb5_error_code retval = 0; 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate if (*list) { 2570Sstevel@tonic-gate /* point lp at the tail of the list */ 2580Sstevel@tonic-gate for (lp = *list; lp->next; lp = lp->next); 2590Sstevel@tonic-gate back = lp; 2600Sstevel@tonic-gate } 2610Sstevel@tonic-gate retval = krb5_kt_resolve(context, name, &kt); 2620Sstevel@tonic-gate if (retval) 2630Sstevel@tonic-gate return retval; 2640Sstevel@tonic-gate retval = krb5_kt_start_seq_get(context, kt, &cursor); 2650Sstevel@tonic-gate if (retval) 2660Sstevel@tonic-gate goto close_kt; 2670Sstevel@tonic-gate for (;;) { 2680Sstevel@tonic-gate entry = (krb5_keytab_entry *)malloc(sizeof (krb5_keytab_entry)); 2690Sstevel@tonic-gate if (!entry) { 2700Sstevel@tonic-gate retval = ENOMEM; 2710Sstevel@tonic-gate break; 2720Sstevel@tonic-gate } 2730Sstevel@tonic-gate memset((char *)entry, 0, sizeof (*entry)); 2740Sstevel@tonic-gate retval = krb5_kt_next_entry(context, kt, entry, &cursor); 2750Sstevel@tonic-gate if (retval) 2760Sstevel@tonic-gate break; 2770Sstevel@tonic-gate 2780Sstevel@tonic-gate if (!lp) { /* if list is empty, start one */ 2790Sstevel@tonic-gate lp = (krb5_kt_list)malloc(sizeof (*lp)); 2800Sstevel@tonic-gate if (!lp) { 2810Sstevel@tonic-gate retval = ENOMEM; 2820Sstevel@tonic-gate break; 2830Sstevel@tonic-gate } 2840Sstevel@tonic-gate } else { 2850Sstevel@tonic-gate lp->next = (krb5_kt_list)malloc(sizeof (*lp)); 2860Sstevel@tonic-gate if (!lp->next) { 2870Sstevel@tonic-gate retval = ENOMEM; 2880Sstevel@tonic-gate break; 2890Sstevel@tonic-gate } 2900Sstevel@tonic-gate lp = lp->next; 2910Sstevel@tonic-gate } 2920Sstevel@tonic-gate if (!tail) 2930Sstevel@tonic-gate tail = lp; 2940Sstevel@tonic-gate lp->next = NULL; 2950Sstevel@tonic-gate lp->entry = entry; 2960Sstevel@tonic-gate } 2970Sstevel@tonic-gate if (entry) 2980Sstevel@tonic-gate free((char *)entry); 2990Sstevel@tonic-gate if (retval) 3000Sstevel@tonic-gate if (retval == KRB5_KT_END) 3010Sstevel@tonic-gate retval = 0; 3020Sstevel@tonic-gate else { 3030Sstevel@tonic-gate ktutil_free_kt_list(context, tail); 3040Sstevel@tonic-gate tail = NULL; 3050Sstevel@tonic-gate if (back) 3060Sstevel@tonic-gate back->next = NULL; 3070Sstevel@tonic-gate } 3080Sstevel@tonic-gate if (!*list) 3090Sstevel@tonic-gate *list = tail; 3100Sstevel@tonic-gate krb5_kt_end_seq_get(context, kt, &cursor); 3110Sstevel@tonic-gate close_kt: 3120Sstevel@tonic-gate krb5_kt_close(context, kt); 3130Sstevel@tonic-gate return retval; 3140Sstevel@tonic-gate } 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate /* 3170Sstevel@tonic-gate * Takes a kt_list and writes it to the named keytab. 3180Sstevel@tonic-gate */ 3190Sstevel@tonic-gate krb5_error_code ktutil_write_keytab(context, list, name) 3200Sstevel@tonic-gate krb5_context context; 3210Sstevel@tonic-gate krb5_kt_list list; 3220Sstevel@tonic-gate char *name; 3230Sstevel@tonic-gate { 3240Sstevel@tonic-gate krb5_kt_list lp; 3250Sstevel@tonic-gate krb5_keytab kt; 3260Sstevel@tonic-gate char ktname[MAXPATHLEN+sizeof("WRFILE:")+1]; 3270Sstevel@tonic-gate krb5_error_code retval = 0; 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate strcpy(ktname, "WRFILE:"); 3300Sstevel@tonic-gate if (strlen (name) >= MAXPATHLEN) 3310Sstevel@tonic-gate return ENAMETOOLONG; 3320Sstevel@tonic-gate strncat (ktname, name, MAXPATHLEN); 3330Sstevel@tonic-gate retval = krb5_kt_resolve(context, ktname, &kt); 3340Sstevel@tonic-gate if (retval) 3350Sstevel@tonic-gate return retval; 3360Sstevel@tonic-gate for (lp = list; lp; lp = lp->next) { 3370Sstevel@tonic-gate retval = krb5_kt_add_entry(context, kt, lp->entry); 3380Sstevel@tonic-gate if (retval) 3390Sstevel@tonic-gate break; 3400Sstevel@tonic-gate } 3410Sstevel@tonic-gate krb5_kt_close(context, kt); 3420Sstevel@tonic-gate return retval; 3430Sstevel@tonic-gate } 3440Sstevel@tonic-gate 3450Sstevel@tonic-gate #ifdef KRB5_KRB4_COMPAT 3460Sstevel@tonic-gate /* 3470Sstevel@tonic-gate * getstr() takes a file pointer, a string and a count. It reads from 3480Sstevel@tonic-gate * the file until either it has read "count" characters, or until it 3490Sstevel@tonic-gate * reads a null byte. When finished, what has been read exists in the 3500Sstevel@tonic-gate * given string "s". If "count" characters were actually read, the 3510Sstevel@tonic-gate * last is changed to a null, so the returned string is always null- 3520Sstevel@tonic-gate * terminated. getstr() returns the number of characters read, 3530Sstevel@tonic-gate * including the null terminator. 3540Sstevel@tonic-gate */ 3550Sstevel@tonic-gate 3560Sstevel@tonic-gate int getstr(fp, s, n) 3570Sstevel@tonic-gate FILE *fp; 3580Sstevel@tonic-gate register char *s; 3590Sstevel@tonic-gate int n; 3600Sstevel@tonic-gate { 3610Sstevel@tonic-gate register count = n; 3620Sstevel@tonic-gate while (fread(s, 1, 1, fp) > 0 && --count) 3630Sstevel@tonic-gate if (*s++ == '\0') 3640Sstevel@tonic-gate return (n - count); 3650Sstevel@tonic-gate *s = '\0'; 3660Sstevel@tonic-gate return (n - count); 3670Sstevel@tonic-gate } 3680Sstevel@tonic-gate 3690Sstevel@tonic-gate /* 3700Sstevel@tonic-gate * Read in a named krb4 srvtab and append to list. Allocate new list 3710Sstevel@tonic-gate * if needed. 3720Sstevel@tonic-gate */ 3730Sstevel@tonic-gate krb5_error_code ktutil_read_srvtab(context, name, list) 3740Sstevel@tonic-gate krb5_context context; 3750Sstevel@tonic-gate char *name; 3760Sstevel@tonic-gate krb5_kt_list *list; 3770Sstevel@tonic-gate { 3780Sstevel@tonic-gate krb5_kt_list lp = NULL, tail = NULL, back = NULL; 3790Sstevel@tonic-gate krb5_keytab_entry *entry; 3800Sstevel@tonic-gate krb5_error_code retval = 0; 3810Sstevel@tonic-gate char sname[SNAME_SZ]; /* name of service */ 3820Sstevel@tonic-gate char sinst[INST_SZ]; /* instance of service */ 3830Sstevel@tonic-gate char srealm[REALM_SZ]; /* realm of service */ 3840Sstevel@tonic-gate unsigned char kvno; /* key version number */ 3850Sstevel@tonic-gate des_cblock key; 3860Sstevel@tonic-gate FILE *fp; 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate if (*list) { 3890Sstevel@tonic-gate /* point lp at the tail of the list */ 3900Sstevel@tonic-gate for (lp = *list; lp->next; lp = lp->next); 3910Sstevel@tonic-gate back = lp; 3920Sstevel@tonic-gate } 3930Sstevel@tonic-gate fp = fopen(name, "r"); 3940Sstevel@tonic-gate if (!fp) 3950Sstevel@tonic-gate return EIO; 3960Sstevel@tonic-gate for (;;) { 3970Sstevel@tonic-gate entry = (krb5_keytab_entry *)malloc(sizeof (krb5_keytab_entry)); 3980Sstevel@tonic-gate if (!entry) { 3990Sstevel@tonic-gate retval = ENOMEM; 4000Sstevel@tonic-gate break; 4010Sstevel@tonic-gate } 4020Sstevel@tonic-gate memset((char *)entry, 0, sizeof (*entry)); 4030Sstevel@tonic-gate memset(sname, 0, sizeof (sname)); 4040Sstevel@tonic-gate memset(sinst, 0, sizeof (sinst)); 4050Sstevel@tonic-gate memset(srealm, 0, sizeof (srealm)); 4060Sstevel@tonic-gate if (!(getstr(fp, sname, SNAME_SZ) > 0 && 4070Sstevel@tonic-gate getstr(fp, sinst, INST_SZ) > 0 && 4080Sstevel@tonic-gate getstr(fp, srealm, REALM_SZ) > 0 && 4090Sstevel@tonic-gate fread(&kvno, 1, 1, fp) > 0 && 4100Sstevel@tonic-gate fread((char *)key, sizeof (key), 1, fp) > 0)) 4110Sstevel@tonic-gate break; 4120Sstevel@tonic-gate entry->magic = KV5M_KEYTAB_ENTRY; 4130Sstevel@tonic-gate entry->timestamp = 0; /* XXX */ 4140Sstevel@tonic-gate entry->vno = kvno; 4150Sstevel@tonic-gate retval = krb5_425_conv_principal(context, 4160Sstevel@tonic-gate sname, sinst, srealm, 4170Sstevel@tonic-gate &entry->principal); 4180Sstevel@tonic-gate if (retval) 4190Sstevel@tonic-gate break; 4200Sstevel@tonic-gate entry->key.magic = KV5M_KEYBLOCK; 4210Sstevel@tonic-gate entry->key.enctype = ENCTYPE_DES_CBC_CRC; 4220Sstevel@tonic-gate entry->key.length = sizeof (key); 4230Sstevel@tonic-gate entry->key.contents = (krb5_octet *)malloc(sizeof (key)); 4240Sstevel@tonic-gate if (!entry->key.contents) { 4250Sstevel@tonic-gate retval = ENOMEM; 4260Sstevel@tonic-gate break; 4270Sstevel@tonic-gate } 4280Sstevel@tonic-gate memcpy((char *)entry->key.contents, (char *)key, sizeof (key)); 4290Sstevel@tonic-gate if (!lp) { /* if list is empty, start one */ 4300Sstevel@tonic-gate lp = (krb5_kt_list)malloc(sizeof (*lp)); 4310Sstevel@tonic-gate if (!lp) { 4320Sstevel@tonic-gate retval = ENOMEM; 4330Sstevel@tonic-gate break; 4340Sstevel@tonic-gate } 4350Sstevel@tonic-gate } else { 4360Sstevel@tonic-gate lp->next = (krb5_kt_list)malloc(sizeof (*lp)); 4370Sstevel@tonic-gate if (!lp->next) { 4380Sstevel@tonic-gate retval = ENOMEM; 4390Sstevel@tonic-gate break; 4400Sstevel@tonic-gate } 4410Sstevel@tonic-gate lp = lp->next; 4420Sstevel@tonic-gate } 4430Sstevel@tonic-gate lp->next = NULL; 4440Sstevel@tonic-gate lp->entry = entry; 4450Sstevel@tonic-gate if (!tail) 4460Sstevel@tonic-gate tail = lp; 4470Sstevel@tonic-gate } 4480Sstevel@tonic-gate if (entry) { 4490Sstevel@tonic-gate if (entry->magic == KV5M_KEYTAB_ENTRY) 4500Sstevel@tonic-gate krb5_kt_free_entry(context, entry); 4510Sstevel@tonic-gate free((char *)entry); 4520Sstevel@tonic-gate } 4530Sstevel@tonic-gate if (retval) { 4540Sstevel@tonic-gate ktutil_free_kt_list(context, tail); 4550Sstevel@tonic-gate tail = NULL; 4560Sstevel@tonic-gate if (back) 4570Sstevel@tonic-gate back->next = NULL; 4580Sstevel@tonic-gate } 4590Sstevel@tonic-gate if (!*list) 4600Sstevel@tonic-gate *list = tail; 4610Sstevel@tonic-gate fclose(fp); 4620Sstevel@tonic-gate return retval; 4630Sstevel@tonic-gate } 4640Sstevel@tonic-gate 4650Sstevel@tonic-gate /* 4660Sstevel@tonic-gate * Writes a kt_list out to a krb4 srvtab file. Note that it first 4670Sstevel@tonic-gate * prunes the kt_list so that it won't contain any keys that are not 4680Sstevel@tonic-gate * the most recent, and ignores keys that are not ENCTYPE_DES. 4690Sstevel@tonic-gate */ 4700Sstevel@tonic-gate krb5_error_code ktutil_write_srvtab(context, list, name) 4710Sstevel@tonic-gate krb5_context context; 4720Sstevel@tonic-gate krb5_kt_list list; 4730Sstevel@tonic-gate char *name; 4740Sstevel@tonic-gate { 4750Sstevel@tonic-gate krb5_kt_list lp, lp1, prev, pruned = NULL; 4760Sstevel@tonic-gate krb5_error_code retval = 0; 4770Sstevel@tonic-gate FILE *fp; 4780Sstevel@tonic-gate char sname[SNAME_SZ]; 4790Sstevel@tonic-gate char sinst[INST_SZ]; 4800Sstevel@tonic-gate char srealm[REALM_SZ]; 4810Sstevel@tonic-gate 4820Sstevel@tonic-gate /* First do heinous stuff to prune the list. */ 4830Sstevel@tonic-gate for (lp = list; lp; lp = lp->next) { 4840Sstevel@tonic-gate if ((lp->entry->key.enctype != ENCTYPE_DES_CBC_CRC) && 4850Sstevel@tonic-gate (lp->entry->key.enctype != ENCTYPE_DES_CBC_MD5) && 4860Sstevel@tonic-gate (lp->entry->key.enctype != ENCTYPE_DES_CBC_MD4) && 4870Sstevel@tonic-gate (lp->entry->key.enctype != ENCTYPE_DES_CBC_RAW)) 4880Sstevel@tonic-gate continue; 4890Sstevel@tonic-gate 4900Sstevel@tonic-gate for (lp1 = pruned; lp1; prev = lp1, lp1 = lp1->next) { 4910Sstevel@tonic-gate /* Hunt for the current principal in the pruned list */ 4920Sstevel@tonic-gate if (krb5_principal_compare(context, 4930Sstevel@tonic-gate lp->entry->principal, 4940Sstevel@tonic-gate lp1->entry->principal)) 4950Sstevel@tonic-gate break; 4960Sstevel@tonic-gate } 4970Sstevel@tonic-gate if (!lp1) { /* need to add entry to tail of pruned list */ 4980Sstevel@tonic-gate if (!pruned) { 4990Sstevel@tonic-gate pruned = (krb5_kt_list) malloc(sizeof (*pruned)); 5000Sstevel@tonic-gate if (!pruned) 5010Sstevel@tonic-gate return ENOMEM; 5020Sstevel@tonic-gate memset((char *) pruned, 0, sizeof(*pruned)); 5030Sstevel@tonic-gate lp1 = pruned; 5040Sstevel@tonic-gate } else { 5050Sstevel@tonic-gate prev->next 5060Sstevel@tonic-gate = (krb5_kt_list) malloc(sizeof (*pruned)); 5070Sstevel@tonic-gate if (!prev->next) { 5080Sstevel@tonic-gate retval = ENOMEM; 5090Sstevel@tonic-gate goto free_pruned; 5100Sstevel@tonic-gate } 5110Sstevel@tonic-gate memset((char *) prev->next, 0, sizeof(*pruned)); 5120Sstevel@tonic-gate lp1 = prev->next; 5130Sstevel@tonic-gate } 5140Sstevel@tonic-gate lp1->entry = lp->entry; 5150Sstevel@tonic-gate } else if (lp1->entry->vno < lp->entry->vno) 5160Sstevel@tonic-gate /* Check if lp->entry is newer kvno; if so, update */ 5170Sstevel@tonic-gate lp1->entry = lp->entry; 5180Sstevel@tonic-gate } 5190Sstevel@tonic-gate fp = fopen(name, "w"); 5200Sstevel@tonic-gate if (!fp) { 5210Sstevel@tonic-gate retval = EIO; 5220Sstevel@tonic-gate goto free_pruned; 5230Sstevel@tonic-gate } 5240Sstevel@tonic-gate for (lp = pruned; lp; lp = lp->next) { 5250Sstevel@tonic-gate unsigned char kvno; 5260Sstevel@tonic-gate kvno = (unsigned char) lp->entry->vno; 5270Sstevel@tonic-gate retval = krb5_524_conv_principal(context, 5280Sstevel@tonic-gate lp->entry->principal, 5290Sstevel@tonic-gate sname, sinst, srealm); 5300Sstevel@tonic-gate if (retval) 5310Sstevel@tonic-gate break; 5320Sstevel@tonic-gate fwrite(sname, strlen(sname) + 1, 1, fp); 5330Sstevel@tonic-gate fwrite(sinst, strlen(sinst) + 1, 1, fp); 5340Sstevel@tonic-gate fwrite(srealm, strlen(srealm) + 1, 1, fp); 5350Sstevel@tonic-gate fwrite((char *)&kvno, 1, 1, fp); 5360Sstevel@tonic-gate fwrite((char *)lp->entry->key.contents, 5370Sstevel@tonic-gate sizeof (des_cblock), 1, fp); 5380Sstevel@tonic-gate } 5390Sstevel@tonic-gate fclose(fp); 5400Sstevel@tonic-gate free_pruned: 5410Sstevel@tonic-gate /* 5420Sstevel@tonic-gate * Loop over and free the pruned list; don't use free_kt_list 5430Sstevel@tonic-gate * because that kills the entries. 5440Sstevel@tonic-gate */ 5450Sstevel@tonic-gate for (lp = pruned; lp;) { 5460Sstevel@tonic-gate prev = lp; 5470Sstevel@tonic-gate lp = lp->next; 5480Sstevel@tonic-gate free((char *)prev); 5490Sstevel@tonic-gate } 5500Sstevel@tonic-gate return retval; 5510Sstevel@tonic-gate } 5520Sstevel@tonic-gate #endif /* KRB5_KRB4_COMPAT */ 553