/* * Copyright 2000, International Business Machines Corporation and others. * All Rights Reserved. * * This software has been released under the terms of the IBM Public * License. For details, see the LICENSE file in the top-level source * directory or online at http://www.openafs.org/dl/license10.html */ #include #if defined(UKERNEL) #include "afs/param.h" #else #include #endif RCSID ("$Header$"); #if defined(UKERNEL) #include "afs/sysincludes.h" #include "afsincludes.h" #include "afs/stds.h" #include "afs/pthread_glock.h" #include "afs/cellconfig.h" #include "afs/afsutil.h" #include "afs/auth.h" #include "afs/kauth.h" #include "afs/kautils.h" #include "afs/pthread_glock.h" #include "des/des.h" #else /* defined(UKERNEL) */ #include #include #include #ifdef AFS_NT40_ENV #include #include #endif #ifdef HAVE_STRING_H #include #else #ifdef HAVE_STRINGS_H #include #endif #endif #ifdef HAVE_UNISTD_H #define __USE_XOPEN #include #endif #include #include #include #include "kauth.h" #include "kautils.h" #endif /* defined(UKERNEL) */ /* This defines the Andrew string_to_key function. It accepts a password string as input and converts it via a one-way encryption algorithm to a DES encryption key. It is compatible with the original Andrew authentication service password database. */ static void Andrew_StringToKey(char *str, char *cell, /* cell for password */ struct ktc_encryptionKey *key) { char password[8 + 1]; /* crypt's limit is 8 chars anyway */ int i; int passlen; memset(key, 0, sizeof(struct ktc_encryptionKey)); strncpy(password, cell, 8); passlen = strlen(str); if (passlen > 8) passlen = 8; for (i = 0; i < passlen; i++) password[i] ^= str[i]; for (i = 0; i < 8; i++) if (password[i] == '\0') password[i] = 'X'; /* crypt only considers the first 8 characters of password but for some * reason returns eleven characters of result (plus the two salt chars). */ strncpy((char *)key, (char *)crypt(password, "p1") + 2, sizeof(struct ktc_encryptionKey)); /* parity is inserted into the LSB so leftshift each byte up one bit. This * allows ascii characters with a zero MSB to retain as much significance * as possible. */ { char *keybytes = (char *)key; unsigned int temp; for (i = 0; i < 8; i++) { temp = (unsigned int)keybytes[i]; keybytes[i] = (unsigned char)(temp << 1); } } des_fixup_key_parity(key); } static void StringToKey(char *str, char *cell, /* cell for password */ struct ktc_encryptionKey *key) { des_key_schedule schedule; char temp_key[8]; char ivec[8]; char password[BUFSIZ]; int passlen; strncpy(password, str, sizeof(password)); if ((passlen = strlen(password)) < sizeof(password) - 1) strncat(password, cell, sizeof(password) - passlen); if ((passlen = strlen(password)) > sizeof(password)) passlen = sizeof(password); memcpy(ivec, "kerberos", 8); memcpy(temp_key, "kerberos", 8); des_fixup_key_parity(temp_key); des_key_sched(temp_key, schedule); des_cbc_cksum(password, ivec, passlen, schedule, ivec); memcpy(temp_key, ivec, 8); des_fixup_key_parity(temp_key); des_key_sched(temp_key, schedule); des_cbc_cksum(password, key, passlen, schedule, ivec); des_fixup_key_parity(key); } void ka_StringToKey(char *str, char *cell, /* cell for password */ struct ktc_encryptionKey *key) { char realm[MAXKTCREALMLEN]; afs_int32 code; LOCK_GLOBAL_MUTEX; code = ka_CellToRealm(cell, realm, 0 /*local */ ); if (code) /* just take his word for it */ strncpy(realm, cell, sizeof(realm)); else /* for backward compatibility */ lcstring(realm, realm, sizeof(realm)); if (strlen(str) > 8) StringToKey(str, realm, key); else Andrew_StringToKey(str, realm, key); UNLOCK_GLOBAL_MUTEX; } /* This prints out a prompt and reads a string from the terminal, turning off echoing. If verify is requested it requests that the string be entered again and the two strings are compared. The string is then converted to a DES encryption key. */ /* Errors: KAREADPW - some error returned from read_pw_string */ afs_int32 ka_ReadPassword(char *prompt, int verify, char *cell, struct ktc_encryptionKey *key) { char password[BUFSIZ]; afs_int32 code; LOCK_GLOBAL_MUTEX; memset(key, 0, sizeof(struct ktc_encryptionKey)); code = read_pw_string(password, sizeof(password), prompt, verify); if (code) { UNLOCK_GLOBAL_MUTEX; return KAREADPW; } if (strlen(password) == 0) { UNLOCK_GLOBAL_MUTEX; return KANULLPASSWORD; } ka_StringToKey(password, cell, key); UNLOCK_GLOBAL_MUTEX; return 0; } /* This performs the backslash quoting defined by AC_ParseLoginName. */ static char map_char(str, ip) char *str; int *ip; { char c = str[*ip]; if (c == '\\') { c = str[++(*ip)]; if ((c >= '0') && (c <= '7')) { c = c - '0'; c = (c * 8) + (str[++(*ip)] - '0'); c = (c * 8) + (str[++(*ip)] - '0'); } } return c; } /* This routine parses a string that might be entered by a user from the terminal. It defines a syntax to allow a user to specify his identity in terms of his name, instance and cell with a single string. These three output strings must be allocated by the caller to their maximum length. The syntax is very simple: the first dot ('.') separates the name from the instance and the first atsign ('@') begins the cell name. A backslash ('\') can be used to quote these special characters. A backslash followed by an octal digit (zero through seven) introduces a three digit octal number which is interpreted as the ascii value of a single character. */ /* Errors: KABADARGUMENT - if no output parameters are specified. KABADNAME - if a component of the user name is too long or if a cell was specified but the cell parameter was null. */ afs_int32 ka_ParseLoginName(char *login, char name[MAXKTCNAMELEN], char inst[MAXKTCNAMELEN], char cell[MAXKTCREALMLEN]) { int login_len = strlen(login); char rc, c; int i, j; #define READNAME 1 #define READINST 2 #define READCELL 3 int reading; if (!name) return KABADARGUMENT; strcpy(name, ""); if (inst) strcpy(inst, ""); if (cell) strcpy(cell, ""); reading = READNAME; i = 0; j = 0; while (i < login_len) { rc = login[i]; c = map_char(login, &i); switch (reading) { case READNAME: if (rc == '@') { name[j] = 0; /* finish name */ reading = READCELL; /* but instance is null */ j = 0; break; } if (inst && (rc == '.')) { name[j] = 0; /* finish name */ reading = READINST; j = 0; break; } if (j >= MAXKTCNAMELEN - 1) return KABADNAME; name[j++] = c; break; case READINST: if (!inst) return KABADNAME; if (rc == '@') { inst[j] = 0; /* finish name */ reading = READCELL; j = 0; break; } if (j >= MAXKTCNAMELEN - 1) return KABADNAME; inst[j++] = c; break; case READCELL: if (!cell) return KABADNAME; if (j >= MAXKTCREALMLEN - 1) return KABADNAME; cell[j++] = c; break; } i++; } if (reading == READNAME) name[j] = 0; else if (reading == READINST) { if (inst) inst[j] = 0; else return KABADNAME; } else if (reading == READCELL) { if (cell) cell[j] = 0; else return KABADNAME; } /* the cell is really an authDomain and therefore is really a realm */ if (cell) ucstring(cell, cell, MAXKTCREALMLEN); return 0; } /* Client side applications should call this to initialize error tables and connect to the correct CellServDB file. */ afs_int32 ka_Init(int flags) { /* reserved for future use. */ afs_int32 code; static int inited = 0; LOCK_GLOBAL_MUTEX; if (inited) { UNLOCK_GLOBAL_MUTEX; return 0; } inited++; initialize_U_error_table(); initialize_KA_error_table(); initialize_RXK_error_table(); initialize_KTC_error_table(); initialize_ACFG_error_table(); code = ka_CellConfig(AFSDIR_CLIENT_ETC_DIRPATH); UNLOCK_GLOBAL_MUTEX; if (code) return code; return 0; } #ifdef MAIN int main(void) { struct ktc_encryptionKey key; int code; char line[256]; char name[MAXKTCNAMELEN]; char instance[MAXKTCNAMELEN]; char cell[MAXKTCREALMLEN]; printf("Enter login:"); fgets(line, 255, stdin); ka_ParseLoginName(line, name, instance, cell); printf("'%s' '%s' '%s'\n", name, instance, cell); } #endif /* MAIN */