/****************************************************************************** * * * Module: PASSWD.C * * PWDencrypt() takes a textual password and encrypts it using VMS's * * own encryption algorithm. * * Parameters: * * 1) char *uname Username of the user * * 2) char *pwd Password to be encrypted * * 3) short salt Password encryption salt * * 4) long epwd[2] Quadword holds the encrypted password * * 5) char algo Encryption algorithm * * Return values: * * VMS status * * PWDget() retrieves the system authorization file, SYSUAF, for the * * specified user's password, password salt and encryption * * algorithm. Requires read access to SYSUAF. * * Parameters: * * 1) char *uname Username of the user * * 2) short *salt Word holds the password salt * * 3) long epwd[2] Quadword holds the encrypted password * * 4) char *algo Encryption algorithm * * Return values: * * VMS status * * PWDcheck() takes a username and a password and compare the given * * password with the one found in the given user's UAF record. * * Both the username and the password MUST be in uppercase. * * Parameters: * * 1) char *uname Username of the user * * 2) char *pwd Password to be checked * * Return values: * * 0 Invalid password * * 1 Valid password * * VMS status Otherwise * * * * Author: * * Terence Lee (DEC/HKO), 13-Dec-1989 * * * * Modification history: * * * ******************************************************************************/ #include #include #include #include "descr.h" #include "itmlst.h" #define UAF$C_USER_ID 1 #define UAF$C_VERSION1 1 #define UAF$C_KEYED_PART 52 #define UAF$C_AD_II 0 #define UAF$C_PURDY 1 #define UAF$C_PURDY_V 2 #define UAF$K_FIXED 644 #define UAF$C_FIXED 644 #define UAF$K_LENGTH 1412 #define UAF$C_LENGTH 1412 #define UAF$S_UAFDEF 1412 #define UAF$B_RTYPE 0 #define UAF$B_VERSION 1 #define UAF$W_USRDATOFF 2 #define UAF$S_USERNAME 32 #define UAF$T_USERNAME 4 #define UAF$T_USERNAME_TAG 35 #define UAF$L_UIC 36 #define UAF$W_MEM 36 #define UAF$W_GRP 38 #define UAF$L_SUB_ID 40 #define UAF$S_PARENT_ID 8 #define UAF$Q_PARENT_ID 44 #define UAF$S_ACCOUNT 32 #define UAF$T_ACCOUNT 52 #define UAF$S_OWNER 32 #define UAF$T_OWNER 84 #define UAF$S_DEFDEV 32 #define UAF$T_DEFDEV 116 #define UAF$S_DEFDIR 64 #define UAF$T_DEFDIR 148 #define UAF$S_LGICMD 64 #define UAF$T_LGICMD 212 #define UAF$S_DEFCLI 32 #define UAF$T_DEFCLI 276 #define UAF$S_CLITABLES 32 #define UAF$T_CLITABLES 308 #define UAF$S_PWD 8 #define UAF$Q_PWD 340 #define UAF$L_PWD 340 #define UAF$S_PWD2 8 #define UAF$Q_PWD2 348 #define UAF$W_LOGFAILS 356 #define UAF$W_SALT 358 #define UAF$B_ENCRYPT 360 #define UAF$B_ENCRYPT2 361 #define UAF$B_PWD_LENGTH 362 #define UAF$S_EXPIRATION 8 #define UAF$Q_EXPIRATION 364 #define UAF$S_PWD_LIFETIME 8 #define UAF$Q_PWD_LIFETIME 372 #define UAF$S_PWD_DATE 8 #define UAF$Q_PWD_DATE 380 #define UAF$S_PWD2_DATE 8 #define UAF$Q_PWD2_DATE 388 #define UAF$S_LASTLOGIN_I 8 #define UAF$Q_LASTLOGIN_I 396 #define UAF$S_LASTLOGIN_N 8 #define UAF$Q_LASTLOGIN_N 404 #define UAF$S_PRIV 8 #define UAF$Q_PRIV 412 #define UAF$S_DEF_PRIV 8 #define UAF$Q_DEF_PRIV 420 #define UAF$S_MIN_CLASS 20 #define UAF$R_MIN_CLASS 428 #define UAF$S_MAX_CLASS 20 #define UAF$R_MAX_CLASS 448 #define UAF$L_FLAGS 468 #define UAF$V_DISCTLY 0 #define UAF$V_DEFCLI 1 #define UAF$V_LOCKPWD 2 #define UAF$V_CAPTIVE 3 #define UAF$V_DISACNT 4 #define UAF$V_DISWELCOM 5 #define UAF$V_DISMAIL 6 #define UAF$V_NOMAIL 7 #define UAF$V_GENPWD 8 #define UAF$V_PWD_EXPIRED 9 #define UAF$V_PWD2_EXPIRED 10 #define UAF$V_AUDIT 11 #define UAF$V_DISREPORT 12 #define UAF$V_DISRECONNECT 13 #define UAF$V_AUTOLOGIN 14 #define UAF$V_DISFORCE_PWD_CHANGE 15 #define UAF$S_NETWORK_ACCESS_P 3 #define UAF$B_NETWORK_ACCESS_P 472 #define UAF$S_NETWORK_ACCESS_S 3 #define UAF$B_NETWORK_ACCESS_S 475 #define UAF$S_BATCH_ACCESS_P 3 #define UAF$B_BATCH_ACCESS_P 478 #define UAF$S_BATCH_ACCESS_S 3 #define UAF$B_BATCH_ACCESS_S 481 #define UAF$S_LOCAL_ACCESS_P 3 #define UAF$B_LOCAL_ACCESS_P 484 #define UAF$S_LOCAL_ACCESS_S 3 #define UAF$B_LOCAL_ACCESS_S 487 #define UAF$S_DIALUP_ACCESS_P 3 #define UAF$B_DIALUP_ACCESS_P 490 #define UAF$S_DIALUP_ACCESS_S 3 #define UAF$B_DIALUP_ACCESS_S 493 #define UAF$S_REMOTE_ACCESS_P 3 #define UAF$B_REMOTE_ACCESS_P 496 #define UAF$S_REMOTE_ACCESS_S 3 #define UAF$B_REMOTE_ACCESS_S 499 #define UAF$B_PRIMEDAYS 514 #define UAF$V_MONDAY 0 #define UAF$V_TUESDAY 1 #define UAF$V_WEDNESDAY 2 #define UAF$V_THURSDAY 3 #define UAF$V_FRIDAY 4 #define UAF$V_SATURDAY 5 #define UAF$V_SUNDAY 6 #define UAF$B_PRI 516 #define UAF$B_QUEPRI 517 #define UAF$W_MAXJOBS 518 #define UAF$W_MAXACCTJOBS 520 #define UAF$W_MAXDETACH 522 #define UAF$W_PRCCNT 524 #define UAF$W_BIOLM 526 #define UAF$W_DIOLM 528 #define UAF$W_TQCNT 530 #define UAF$W_ASTLM 532 #define UAF$W_ENQLM 534 #define UAF$W_FILLM 536 #define UAF$W_SHRFILLM 538 #define UAF$L_WSQUOTA 540 #define UAF$L_DFWSCNT 544 #define UAF$L_WSEXTENT 548 #define UAF$L_PGFLQUOTA 552 #define UAF$L_CPUTIM 556 #define UAF$L_BYTLM 560 #define UAF$L_PBYTLM 564 #define UAF$L_JTQUOTA 568 #define UAF$W_PROXY_LIM 572 #define UAF$W_PROXIES 574 #define UAF$W_ACCOUNT_LIM 576 #define UAF$W_ACCOUNTS 578 #define SYSfault(sts) (sts != SS$_NORMAL) typedef unsigned long ULong; static long autodin[16] = { /* autodin-II polynomial table for CRC. */ 000000000000,003555610144,007333420310,004666230254, 016667040620,015332650764,011554460530,012001270474, 035556101440,036003711504,032665521750,031330331614, 023331141260,020664751324,024002561170,027557371034 }; static long c[5][2] = { /* purdy polynomial coefficient. */ { -83,-1 }, /* c1. */ { -179,-1 }, /* c2. */ { -257,-1 }, /* c3. */ { -323,-1 }, /* c4. */ { -363,-1 } /* c5. */ }; static ULong sts; /* * lgi$hpwd() is the C version of the VAX/VMS password encryption * algorithim from facility login module hpwd. * Parameters: * 1) char *uname Username of the user * 2) char *pwd Password to be encrypted * 3) short salt Password encryption salt * 4) long epwd[2] Quadword holds the encrypted password * 5) char algo Encryption algorithm * Return values: * SS$_NORMAL Always success */ static int lgi$hpwd(uname,pwd,salt,epwd,algo) char *uname,*pwd; short salt; long epwd[]; char algo; { short *ptr1 = (short *)((char *)epwd + 3); char Una[13] = " "; switch (algo) { case UAF$C_AD_II: epwd[0] = lib$crc(autodin,&-1,descrS(pwd,0)); epwd[1] = 0; break; case UAF$C_PURDY: case UAF$C_PURDY_V: if (algo == UAF$C_PURDY_V) strcpy(Una,uname); else strncpy(Una,uname,strlen(uname)); epwd[0] = epwd[1] = 0; collapse(pwd,epwd); *ptr1 += salt; collapse(Una,epwd); purdy(epwd); break; } return(SS$_NORMAL); } /* * collapse() takes a string of bytes and collapse them into a quadword. * It does this by cycling around the bytes of the output buffer * adding in the bytes of the input string. * Parameters: * 1) char *s Input string * 2) long epwd[2] Quadword holds the encrypted password * Return values: * None */ static int collapse(s,epwd) char *s; long epwd[]; { register i; long mask = 0x0007; /* Select start byte from the quadword. */ char *ptr1 = s,*ptr2 = (char *)epwd; for (i = strlen(s); i; i--) *(ptr2 + (i & mask)) += *ptr1++; } /* * purdy() evaluates purdy polynomial. It computes f(u) = p(u) where * p is a prime of the form p^64-a. The function p is the * following polynomial: * x^n0 + x^n1 * c1 + x^3 * c2 + x^2 * c3 + x * c4 + c5 * Parameters: * 1) long epwd[2] Quadword holds the encrypted password * Return values: * None */ #define quadasgn(d,l,h) (d[0] = l,d[1] = h) #define quadcopy(s,d) (d[0] = s[0],d[1] = s[1]) static long a = 59,n0 = (1 << 24) - 3,n1 = (1 << 24) - 63; static int purdy(epwd) long epwd[]; { register i = 0; long power,rs1[2],rs2[2],rs3[2]; pqmod(epwd); /* * Get x^n1. */ quadcopy(epwd,rs2); power = n1; pqexp(rs2,power); /* * Get x^(n0 - n1) + c1. Obtain x^n0 + x^n1 * c1 by multiplying the * first two number. */ quadcopy(epwd,rs1); power = n0 - n1; pqexp(rs1,power); pqadd(c[i],rs1); pqmul(rs2,rs1,rs1); i++; /* * Get x * c2 + c3. Obtaining x^2 * c2 + x * c3 by multiplying x to * the result. */ quadcopy(epwd,rs2); pqmul(c[i],rs2,rs2); i++; pqadd(c[i],rs2); i++; quadcopy(epwd,rs3); pqmul(rs3,rs2,rs2); /* * Get x^2 * c2 + x * c3 + c4. Obtaining x^3 * c2 + x^2 * c3 + x * c4 * by multiply x to the last result. */ pqadd(c[i],rs2); i++; quadcopy(epwd,rs3); pqmul(rs3,rs2,rs2); /* * Add c5 and the first number to produce the result. */ pqadd(c[i],rs2); pqadd(rs2,rs1); quadcopy(rs1,epwd); } /* * pqexp() replaces the quadword num with num^p where p is of the * form p = 2^64 - a. * Parameters: * 1) long num[2] Quadword to be raised to the given power * 2) long power Raised to this power * Return values: * None */ static int pqexp(num,power) long num[],power; { long multi[2],save_num[2]; if (power <= 0) return; quadasgn(multi,1,0); quadcopy(num,save_num); for ( ; ; ) { if (power & 0x00000001) { pqmul(num,multi,num); quadcopy(num,multi); if ((power & 0xfffffffe) == 0) break; } pqmul(save_num,save_num,num); quadcopy(num,save_num); power >>= 1; } } /* * pqmod() replaces the quadword num with num mod p where p is of the * form p = 2^64 - a. * Parameters: * 1) long num[2] Quadword to be mod by p * Return values: * None */ static int pqmod(num) long num[]; { if ((ULong)num[0] < (ULong)-a) return; if ((ULong)num[1] < (ULong)-1) return; num[0] += a; num[1] += 1; } /* * pqmul() computes the product mulr * muld mod p where p is of the * form p = 2^64 - a. * The product may be form as the sum of four longword multiplications * which are scaled by powers of 2^32 by evaluating: * 2^64 * v * z + 2^32 * (v * y + u * z) + u * y * where u = muld[0] * v = muld[1] * y = mulr[0] * z = mulr[1] * Parameters: * 1) long mulr[2] Quadword multiplier * 2) long muld[2] Quadword multiplicand * 3) long prod[2] Quadword product * Return values: * None */ static int pqmul(mulr,muld,prod) long mulr[],muld[],prod[]; { long tmp[2],rs1[2],rs2[2]; /* * Get 2^32 * v * z. */ emulq(mulr[1],muld[1],tmp); pqmod(tmp); pqlsh(tmp); quadcopy(tmp,rs2); /* * Get v * y and add in the above sum. */ emulq(mulr[0],muld[1],tmp); pqmod(tmp); quadcopy(tmp,rs1); /* * Get u * z and add in the above sum. Obtain the first two * items by pqlsh() the sum. */ emulq(mulr[1],muld[0],tmp); pqmod(tmp); pqadd(tmp,rs1); pqadd(rs2,rs1); pqlsh(rs1); /* * Get u * y and add in the above sum. */ emulq(mulr[0],muld[0],tmp); pqmod(tmp); pqadd(tmp,rs1); quadcopy(rs1,prod); } /* * emulq() knows how to multiply two unsigned longwords, producing an * unsigned quadword product. * Parameters: * 1) long mulr Longword multiplier * 2) long muld Longword multiplicand * 3) long prod[2] Quadword product * Return values: * None */ static int emulq(mulr,muld,prod) long mulr,muld,prod[]; { long compensate = 0; lib$emul(&mulr,&muld,&0,prod); if (mulr < 0) compensate += muld; if (muld < 0) compensate += mulr; prod[1] += compensate; } /* * pqlsh() computes the product 2^32 * u mod p where p is of the * form p = 2^64 - a. * Parameters: * 1) long num[2] Quadword to be mod by p * Return values: * None */ #define ASH 32 static int pqlsh(num) long num[]; { long tmp[2],mask = 0x80000000; emulq(num[1],a,tmp); num[1] <<= ASH; num[1] |= (ULong)((mask >>= ASH - 1) & num[0]) >> (32 - ASH); num[0] <<= ASH; pqadd(tmp,num); } /* * pqadd() computes the sum add + sum mod p where p is of the * form p = 2^64 - a. * Parameters: * 1) long add[2] Quadword addend * 2) long sum[2] Quadword sum * Return values: * None */ static int pqadd(add,sum) long add[],sum[]; { register c0,c1; if ((ULong)sum[0] > (ULong)-1 - (ULong)add[0]) c0 = 1; else c0 = 0; sum[0] += add[0]; if ((ULong)(sum[1] + c0) > (ULong)-1 - (ULong)add[1]) c1 = 1; else c1 = 0; sum[1] += add[1] + c0; if (!c1 && (ULong)sum[1] < (ULong)-1) return; if ((ULong)sum[0] > (ULong)-1 - (ULong)a) c0 = 1; else c0 = 0; sum[0] += a; sum[1] += c0; } /* * PWDencrypt() takes a textual password and encrypts it using VMS's * own encryption algorithm. * Parameters: * 1) char *uname Username of the user * 2) char *pwd Password to be encrypted * 3) short salt Password encryption salt * 4) long epwd[2] Quadword holds the encrypted password * 5) char algo Encryption algorithm * Return values: * VMS status */ int PWDencrypt(uname,pwd,salt,epwd,algo) char *uname,*pwd; short salt; long epwd[]; char algo; { if (strlen(uname) > 12 || strlen(pwd) > 31) return(SS$_BADPARAM); sts = lgi$hpwd(uname,pwd,salt,epwd,algo); return(sts); } /* * PWDget() retrieves the system authorization file, SYSUAF, for the * specified user's password, password salt and encryption * algorithm. Requires read access to SYSUAF. * Parameters: * 1) char *uname Username of the user * 2) short *salt Word holds the password salt * 3) long epwd[2] Quadword holds the encrypted password * 4) char *algo Encryption algorithm * Return values: * VMS status */ int PWDget(uname,salt,epwd,algo) char *uname; short *salt; long epwd[]; char *algo; { itmlst_3 UAIitm[] = { 2,UAI$_SALT,salt,0,8,UAI$_PWD,epwd,0, 1,UAI$_ENCRYPT,algo,0,0,0,0,0 }; sts = sys$getuai(0,0,descrS(uname,0),UAIitm,0,0,0); return(sts); } /* * PWDcheck() takes a username and a password and compare the given * password with the one found in the given user's UAF record. * Both the username and the password MUST be in uppercase. * Parameters: * 1) char *uname Username of the user * 2) char *pwd Password to be checked * Return values: * 0 Invalid password * 1 Valid password * VMS status Otherwise */ int PWDcheck(uname,pwd) char *uname,*pwd; { short salt; long epwd_1[2],epwd_2[2]; char algo; sts = PWDget(uname,&salt,epwd_1,&algo); if (SYSfault(sts)) return(sts); sts = PWDencrypt(uname,pwd,salt,epwd_2,algo); if (SYSfault(sts)) return(sts); return(epwd_1[0] == epwd_2[0] && epwd_1[1] == epwd_2[1]); }