|
|
1.1 ! root 1: /* ! 2: * ! 3: * Routines to deal with the VMS User Authorization File: ! 4: * ! 5: * get_vms_uaf_record(name,uaf); ! 6: * validate_vms_user(name,password,uaf); ! 7: * hash_vms_password(output_buf,input_buf,input_len,username,type,salt); ! 8: * ! 9: * ! 10: */ ! 11: ! 12: ! 13: /* ! 14: * Includes ! 15: */ ! 16: #include <vms/fab.h> /* File access block */ ! 17: #include <vms/rab.h> /* Record access block */ ! 18: #include <vms/rmsdef.h> /* RMS return codes */ ! 19: #include <vms/ssdef.h> /* System service return codes */ ! 20: #include <vms/uafdef.h> /* Authorization file records */ ! 21: #include <vms/logdef.h> /* Logical name table seach masks */ ! 22: ! 23: /* ! 24: * defines ! 25: */ ! 26: #define RETRY_RLK 2 /* number of retries if record locked */ ! 27: #define SLEEP_RLK 75 /* MS to sleep before retrying a GET */ ! 28: #define RECSIZ 80 /* Maximum length for password string */ ! 29: #define UAFNAME "SYSUAF" /* Name of authorization file */ ! 30: #define UAFSIZE 6 /* Size of above */ ! 31: #define DEFNAME "SYS$SYSTEM:.DAT" /* Default path to authorization file */ ! 32: #define DEFSIZE 15 /* Size of above */ ! 33: #define DEFUSER "DEFAULT " /* "Default user" name */ ! 34: ! 35: #define UAF$_NORMAL 1 /* Normal completion */ ! 36: #define UAF$_INVUSR -2 /* Invalid User Name */ ! 37: #define UAF$_INVPWD -4 /* Invalid Password */ ! 38: ! 39: #define UAF$S_USERNAME 12 /* User Name Size */ ! 40: #define UAF$S_PWD 8 /* Password Size */ ! 41: ! 42: struct descr {int size; char *ptr;}; /* VMS descriptor */ ! 43: ! 44: /* ! 45: * OWN STORAGE: ! 46: */ ! 47: static int wakedelta[] = {-10*1000*SLEEP_RLK,-1}; ! 48: ! 49: ! 50: /* ! 51: * ! 52: * status = get_vms_uaf_record(name,uaf); ! 53: * ! 54: */ ! 55: int get_vms_uaf_record(name,uaf) ! 56: char *name; ! 57: register struct uaf *uaf; ! 58: { ! 59: struct FAB fab; ! 60: struct RAB rab; ! 61: unsigned int old_privs[2],new_privs[2]; ! 62: int status; ! 63: int default_user = 1; ! 64: register int i; ! 65: register char *cp,*cp1,*cp2; ! 66: ! 67: /* ! 68: * Zero the fab and rab ! 69: */ ! 70: bzero(&fab,sizeof(fab)); ! 71: bzero(&rab,sizeof(rab)); ! 72: /* ! 73: * Setup the fab ! 74: */ ! 75: fab.fab$b_bid = FAB$C_BID; ! 76: fab.fab$b_bln = sizeof(fab); ! 77: fab.fab$l_fna = UAFNAME; ! 78: fab.fab$b_fns = UAFSIZE; ! 79: fab.fab$l_dna = DEFNAME; ! 80: fab.fab$b_dns = DEFSIZE; ! 81: fab.fab$b_dsbmsk = (1<<LOG$C_GROUP) | (1<<LOG$C_PROCESS); ! 82: fab.fab$b_fac |= FAB$M_GET; ! 83: fab.fab$b_shr = (FAB$M_GET|FAB$M_PUT|FAB$M_UPD|FAB$M_DEL); ! 84: fab.fab$b_org = FAB$C_IDX; ! 85: fab.fab$b_rfm = FAB$C_VAR; ! 86: /* ! 87: * setup the rab ! 88: */ ! 89: rab.rab$b_bid = RAB$C_BID; ! 90: rab.rab$b_bln = sizeof(rab); ! 91: rab.rab$b_rac = RAB$C_KEY; ! 92: rab.rab$l_rop |= RAB$M_NLK; ! 93: rab.rab$b_mbc = 10; ! 94: rab.rab$w_usz = sizeof(struct uaf); ! 95: rab.rab$l_ubf = (char *)uaf; ! 96: rab.rab$l_kbfpbf.rab$l_kbf = (unsigned long int *)uaf; ! 97: rab.rab$b_kszpsz.rab$b_ksz = UAF$S_USERNAME; ! 98: rab.rab$l_fab = &fab; ! 99: /* ! 100: * Enable all privileges that we are authorized to have just to ! 101: * enhance the possibility of accessing the SYSUAF file. ! 102: */ ! 103: new_privs[0] = -1; new_privs[1] = -1; ! 104: sys$setprv(1,new_privs,0,old_privs); ! 105: /* ! 106: * Open the File and connect the RAB ! 107: */ ! 108: status = sys$open(&fab); ! 109: if (!(status & 1)) { ! 110: if ((status == RMS$_SNE) || ! 111: (status == RMS$_SPE) || ! 112: (status == RMS$_DME)) { ! 113: fab.fab$b_shr = 0; ! 114: status = sys$open(&fab); ! 115: if (!(status & 1)) goto exit; ! 116: } else goto exit; ! 117: } ! 118: status = sys$connect(&rab); ! 119: if (!(status & 1)) goto exit; ! 120: /* ! 121: * Move the USERNAME to the uaf$t_username field (as a buffer) ! 122: * uppercaseify it along the way and check it against the ! 123: * username "DEFAULT" (which is not a real username). Pad ! 124: * the uaf$t_username field with blanks. ! 125: */ ! 126: i = UAF$S_USERNAME; ! 127: cp = name; ! 128: cp1 = uaf->uaf$t_username; ! 129: cp2 = DEFUSER; ! 130: while(--i >= 0) { ! 131: if (*cp == 0) break; ! 132: if (*cp != *cp2++) default_user = 0; ! 133: *cp1++ = ((*cp >= 'a') && (*cp <= 'z')) ? ! 134: *cp++ + ('A' - 'a') : *cp++; ! 135: } ! 136: i++; ! 137: while(--i >= 0) { ! 138: *cp1++ = ' '; ! 139: if (*cp2++ != ' ') default_user = 0; ! 140: } ! 141: /* ! 142: * The "DEFAULT" user is illegal! ! 143: */ ! 144: if (default_user) { ! 145: status = UAF$_INVUSR; ! 146: goto exit; ! 147: } ! 148: /* ! 149: * Look up the User's UAF record ! 150: */ ! 151: status = get_record(&rab); ! 152: if (status == RMS$_RNF) status = UAF$_INVUSR; ! 153: ! 154: exit: ! 155: /* ! 156: * Done: close the file, release privileges and return status ! 157: */ ! 158: sys$disconnect(&rab); ! 159: sys$close(&fab); ! 160: sys$setprv(0,new_privs,0,0); ! 161: sys$setprv(1,old_privs,0,0); ! 162: return(status); ! 163: } ! 164: ! 165: ! 166: /* ! 167: * Read the record and deal with file locking ! 168: */ ! 169: static get_record(rab) ! 170: struct RAB *rab; ! 171: { ! 172: int retries = RETRY_RLK; ! 173: int status; ! 174: ! 175: /* ! 176: * Re-try the appropriate number of times ! 177: */ ! 178: while(1) { ! 179: /* ! 180: * Get the record ! 181: */ ! 182: status = sys$get(rab); ! 183: /* ! 184: * If the return code is not "Record Locked" it is either ! 185: * a success or error that we can't handle, return it. ! 186: */ ! 187: if (status != RMS$_RLK) break; ! 188: /* ! 189: * Record Locked: If retries exceeded, return error ! 190: */ ! 191: if (--retries < 0) break; ! 192: /* ! 193: * Retry: Sleep first ! 194: */ ! 195: status = sys$schdwk(0,0,wakedelta,0); ! 196: if (status & 1) sys$hiber(); ! 197: } ! 198: /* ! 199: * Done: Return status ! 200: */ ! 201: return(status); ! 202: } ! 203: ! 204: ! 205: /* ! 206: * ! 207: * Validate a UserName/Password pair and return the user's UAF record ! 208: * ! 209: */ ! 210: int validate_vms_user(name,password,uaf) ! 211: char *name; ! 212: char *password; ! 213: register struct uaf *uaf; ! 214: { ! 215: char password_buf[RECSIZ]; ! 216: char username_buf[UAF$S_USERNAME]; ! 217: char encrypt_buf[UAF$S_PWD]; ! 218: register int i; ! 219: register char *cp,*cp1; ! 220: ! 221: /* ! 222: * Get the User's UAF record ! 223: */ ! 224: i = get_vms_uaf_record(name,uaf); ! 225: if (!(i & 1)) return(i); ! 226: /* ! 227: * Limit the username to "UAF$S_USERNAME" size while copying and ! 228: * uppercasifying it. Pad with spaces to "UAF$S_USERNAME" size. ! 229: */ ! 230: i = UAF$S_USERNAME; ! 231: cp = name; ! 232: cp1 = username_buf; ! 233: while(--i >= 0) { ! 234: if (*cp == 0) break; ! 235: *cp1++ = ((*cp >= 'a') && (*cp <= 'z')) ? ! 236: *cp++ + ('A' - 'a') : *cp++; ! 237: } ! 238: i++; ! 239: while(--i >= 0) *cp1++ = ' '; ! 240: /* ! 241: * Limit the password to "RECSIZ" size while copying and ! 242: * uppercasifying it. ! 243: */ ! 244: i = RECSIZ; ! 245: cp = password; ! 246: cp1 = password_buf; ! 247: while(--i >= 0) { ! 248: if (*cp == 0) break; ! 249: *cp1++ = ((*cp >= 'a') && (*cp <= 'z')) ? ! 250: *cp++ + ('A' - 'a') : *cp++; ! 251: } ! 252: i = (RECSIZ - 1) - i; /* Compute size of password string */ ! 253: /* ! 254: * Encrypt the password ! 255: */ ! 256: hash_vms_password(encrypt_buf,password_buf,i,username_buf, ! 257: uaf->uaf$b_encrypt,uaf->uaf$w_salt); ! 258: if (bcmp(encrypt_buf,uaf->uaf$l_pwd,UAF$S_PWD) == 0) ! 259: return(UAF$_NORMAL); ! 260: else return(UAF$_INVPWD); ! 261: } ! 262: ! 263: ! 264: /* ! 265: * ! 266: * PASSWORD SMASHING CODE: ! 267: * The real bit hacking is done in "asm" statements, since ! 268: * "C" is poorly suited towards quad-word arithmetic! ! 269: * ! 270: */ ! 271: ! 272: /* ! 273: * AUTODIN II CRC Coefficients: ! 274: */ ! 275: static unsigned long autodin[] = { ! 276: 000000000000,003555610144,007333420310,004666230254, ! 277: 016667040620,015332650764,011554460530,012001270474, ! 278: 035556101440,036003711504,032665521750,031330331614, ! 279: 023331141260,020664751324,024002561170,027557371034 ! 280: }; ! 281: ! 282: ! 283: /* ! 284: * PURDY Polynomial Coefficients ! 285: */ ! 286: static long c[] = { ! 287: -83, -1, /* C1 */ ! 288: -179, -1, /* C2 */ ! 289: -257, -1, /* C3 */ ! 290: -323, -1, /* C4 */ ! 291: -363, -1 /* C5 */ ! 292: }; ! 293: ! 294: /* ! 295: * Hashing routine ! 296: */ ! 297: hash_vms_password(output_buf,input_buf,input_length,username,type,salt) ! 298: char *output_buf,*input_buf,*username; ! 299: unsigned short salt; ! 300: { ! 301: register int i; ! 302: register char *cp; ! 303: ! 304: /* ! 305: * Dispatch on encryption type ! 306: */ ! 307: if (type == 0) { ! 308: /* ! 309: * AUTODIN II CRC: ! 310: */ ! 311: crc(autodin,-1,input_length,input_buf,output_buf); ! 312: return; ! 313: } else { ! 314: /* ! 315: * PURDY: ! 316: */ ! 317: ! 318: i = 8; ! 319: cp = output_buf; ! 320: while(--i >= 0) *cp++ = 0; /* Init output buffer */ ! 321: /* ! 322: * Collapse the password into a quadword ! 323: */ ! 324: collapse(input_length,input_buf,output_buf); ! 325: /* ! 326: * Add salt to middle of quadword ! 327: */ ! 328: *((unsigned short *)(output_buf+3)) += salt; ! 329: /* ! 330: * Collapse the username into the quadword ! 331: */ ! 332: collapse(/*UAF$S_USERNAME*/12,username,output_buf); ! 333: /* ! 334: * Compute the PURDY polynomial: ! 335: */ ! 336: purdy(output_buf,c); ! 337: } ! 338: } ! 339: ! 340: /* ! 341: * CRC routine: ! 342: */ ! 343: static crc(table,initial_crc,input_len,input_buf,output_buf) ! 344: { ! 345: asm(" crc *4(ap),8(ap),12(ap),*16(ap)"); ! 346: asm(" clrl r1"); ! 347: asm(" movq r0,*20(ap)"); ! 348: } ! 349: ! 350: /* ! 351: * Routine to collapse a string into a quadword: ! 352: */ ! 353: static collapse(input_len,input_buf,output_buf) ! 354: register unsigned char *input_buf; ! 355: register int input_len; ! 356: register unsigned char *output_buf; ! 357: { ! 358: while(input_len > 0) { ! 359: output_buf[input_len & ~(-8)] += *input_buf++; ! 360: input_len--; ! 361: } ! 362: } ! 363: ! 364: ! 365: /* ! 366: * ! 367: * GROMMY STUFF TO COMPUTE THE PURDY POLYNOMIAL ! 368: * ! 369: */ ! 370: static purdy(U,C) ! 371: { ! 372: /* ! 373: * This routine computes f(U) = p(U) mod P. Where P is a prime of the form ! 374: * P = 2^64 - a. The function p is the following polynomial: ! 375: * X^n0 + X^n1*C1 + X^3*C2 + X^2*C3 + X*C4 + C5 ! 376: * The input U is an unsigned quadword. ! 377: */ ! 378: asm(" .set A,59"); /* 2^64 -59 is the biggest quad prime */ ! 379: ! 380: asm(" movq *4(ap),-(sp)"); /* Push U */ ! 381: asm(" bsbw PQMOD_R0"); /* Ensure U less than P */ ! 382: asm(" movaq (sp),r4"); /* Maintain a pointer to X*/ ! 383: asm(" pushl 8(ap)"); ! 384: asm(" movl (sp)+,r5"); /* Point to the table of coefficients */ ! 385: asm(" movq (r4),-(sp)"); ! 386: asm(" pushl $((1<<24)-63)");/* n1 */ ! 387: asm(" bsbb PQEXP_R3"); /* X^n1 */ ! 388: asm(" movq (r4),-(sp)"); ! 389: asm(" pushl $((1<<24)-3)"); ! 390: asm(" subl2 $((1<<24)-63),(sp)");/* n0-n1 */ ! 391: asm(" bsbb PQEXP_R3"); ! 392: asm(" movq (r5)+,-(sp)"); /* C1 */ ! 393: asm(" bsbw PQADD_R0"); /* X^(n0 - n1) + C1 */ ! 394: asm(" bsbw PQMUL_R2"); /* X^n0 + X^n1*C1 */ ! 395: asm(" movq (r5)+,-(sp)"); /* C2 */ ! 396: asm(" movq (r4),-(sp)"); ! 397: asm(" bsbw PQMUL_R2"); /* X*C2 */ ! 398: asm(" movq (r5)+,-(sp)"); /* C3 */ ! 399: asm(" bsbw PQADD_R0"); /* X*C2 + C3 */ ! 400: asm(" movq (r4),-(sp)"); ! 401: asm(" bsbb PQMUL_R2"); /* X^2*C2 + X*C3 */ ! 402: asm(" movq (r5)+,-(sp)"); /* C4 */ ! 403: asm(" bsbw PQADD_R0"); /* X^2*C2 + X*C3 + C4 */ ! 404: asm(" movq (r4),-(sp)"); ! 405: asm(" bsbb PQMUL_R2"); /* X^3*C2 + X^2*C3 + C4*X */ ! 406: asm(" movq (r5)+,-(sp)"); /* C5 */ ! 407: asm(" bsbw PQADD_R0"); /* X^3*C2 + X^2*C3 + C4*X + C5 */ ! 408: asm(" bsbw PQADD_R0"); /* Add in the high order terms */ ! 409: asm(" movq (sp)+,*4(ap)"); /* Replace U with f(X) */ ! 410: asm(" movl $1,r0"); ! 411: asm(" ret"); ! 412: ! 413: ! 414: /* Replaces the inputs with U^n mod P where P is of the form */ ! 415: /* P = 2^64 - a. */ ! 416: /* U is a quadword, n is an unsigned longword. */ ! 417: ! 418: asm("PQEXP_R3:"); ! 419: asm(" popr $8"); /* Record return address */ ! 420: asm(" movq $1,-(sp)"); /* Initialize */ ! 421: asm(" movq 8+4(sp),-(sp)");/* Copy U to top of stack for speed */ ! 422: asm(" tstl 8+8(sp)"); /* Only handle n greater than */ ! 423: asm(" beqlu 3f"); ! 424: asm("1: blbc 8+8(sp),2f"); ! 425: asm(" movq (sp),-(sp)"); /* Copy the current power of U */ ! 426: asm(" movq 8+8(sp),-(sp)");/* Multiply with current value */ ! 427: asm(" bsbb PQMUL_R2"); ! 428: asm(" movq (sp)+,8(sp)"); /* Replace current value */ ! 429: asm(" cmpzv $1,$31,8+8(sp),$0"); ! 430: asm(" beqlu 3f"); ! 431: asm("2: movq (sp),-(sp)"); /* Proceed to next power of U */ ! 432: asm(" bsbb PQMUL_R2"); ! 433: asm(" extzv $1,$31,8+8(sp),8+8(sp)"); ! 434: asm(" brb 1b"); ! 435: asm("3: movq 8(sp),8+8+4(sp)");/* Copy the return value */ ! 436: asm(" movaq 8+8+4(sp),sp"); /* Discard the exponent */ ! 437: asm(" jmp (r3)"); /* return */ ! 438: ! 439: /* Replaces the quadword U on the stack with U mod P where P is of the */ ! 440: /* form P = 2^64 - a. */ ! 441: asm(" .set U,0"); /* Low longword of U */ ! 442: asm(" .set V,U+4"); /* High longword of U */ ! 443: asm(" .set Y,U+8"); /* Low longword of Y */ ! 444: asm(" .set Z,Y+4"); /* High longword of Y */ ! 445: asm("PQMOD_R0:"); ! 446: asm(" popr $1"); /* Record return address */ ! 447: asm(" cmpl V(sp),$-1"); /* Replace U with U mod P */ ! 448: asm(" blssu 1f"); ! 449: asm(" cmpl U(sp),$-A"); ! 450: asm(" blssu 1f"); ! 451: asm(" addl2 $A,U(sp)"); ! 452: asm(" adwc $0,V(sp)"); ! 453: asm("1: jmp (r0)"); /* return */ ! 454: ! 455: ! 456: /* Computes the product U*Y mod P where P is of the form ! 457: * P = 2^64 - a. U, Y are quadwords less than P. The product ! 458: * replaces U and Y on the stack. ! 459: * ! 460: * The product may be formed as the sum of four longword ! 461: * multiplications which are scaled by powers of 2^32 by evaluating: ! 462: * 2^64*v*z + 2^32*(v*y + u*z) + u*y ! 463: * The result is computed such that division by the modulus P ! 464: * is avoided. ! 465: */ ! 466: asm("PQMUL_R2:"); ! 467: asm(" popr $2"); /* Record return address */ ! 468: asm(" movl sp,r2"); /* Record initial stack value */ ! 469: asm(" pushl Z(r2)"); ! 470: asm(" pushl V(r2)"); ! 471: asm(" bsbb EMULQ"); ! 472: asm(" bsbb PQMOD_R0"); ! 473: asm(" bsbb PQLSH_R0"); /* Obtain 2^32*v*z */ ! 474: asm(" pushl Y(r2)"); ! 475: asm(" pushl V(r2)"); ! 476: asm(" bsbb EMULQ"); ! 477: asm(" bsbb PQMOD_R0"); ! 478: asm(" pushl Z(r2)"); ! 479: asm(" pushl U(r2)"); ! 480: asm(" bsbb EMULQ"); ! 481: asm(" bsbb PQMOD_R0"); ! 482: asm(" bsbb PQADD_R0"); /* Obtain (v*y + u*z) */ ! 483: asm(" bsbb PQADD_R0"); /* Add in 2^32*v*z */ ! 484: asm(" bsbb PQLSH_R0"); /* Obtain the first two terms */ ! 485: asm(" pushl Y(r2)"); ! 486: asm(" pushl U(r2)"); ! 487: asm(" bsbb EMULQ"); ! 488: asm(" bsbb PQMOD_R0"); /* Obtain the third term: u*y */ ! 489: asm(" bsbb PQADD_R0"); /* Add it in */ ! 490: asm(" movq (sp)+,Y(r2)"); /* Copy the return value */ ! 491: asm(" movaq Y(r2),sp"); /* Point the stack to the return value */ ! 492: asm(" jmp (r1)"); /* return */ ! 493: ! 494: ! 495: /* This routine knows how to multiply two unsigned longwords, ! 496: * replacing them with the unsigned quadword product on the stack. ! 497: */ ! 498: ! 499: asm("EMULQ:"); ! 500: asm(" emul 4(sp),8(sp),$0,-(sp)"); ! 501: asm(" clrl -(sp)"); ! 502: asm(" tstl 4+8+4(sp)"); /* Check both longwords to see if we */ ! 503: asm(" bgeq 1f"); /* must compensate for the unsigned ! 504: bias. */ ! 505: asm(" addl2 4+8+8(sp),(sp)"); ! 506: asm("1: tstl 4+8+8(sp)"); ! 507: asm(" bgeq 2f"); ! 508: asm(" addl2 4+8+4(sp),(sp)"); ! 509: asm("2: addl2 (sp)+,4(sp)"); /* Add in the compensation. */ ! 510: asm(" movq (sp)+,4(sp)"); /* Replace the longwords with their ! 511: product. */ ! 512: asm(" rsb"); ! 513: ! 514: /* ! 515: * Computes the product 2^32*U mod P where P is of the form ! 516: * P = 2^64 - a. U is a quadword less than P. The product replaces ! 517: * U on the stack. ! 518: * ! 519: * This routine is used by PQMUL in the formation of quadword ! 520: * products in such a way as to avoid division by the modulus P. ! 521: * The product 2^64*v + 2^32*u is congruent a*v + 2^32*u mod P ! 522: * (where u, v are longwords). ! 523: */ ! 524: asm("PQLSH_R0:"); ! 525: asm(" popr $1"); /* Record return address */ ! 526: asm(" pushl V(sp)"); ! 527: asm(" pushl $A"); ! 528: asm(" bsbb EMULQ"); /* Push a*v */ ! 529: asm(" ashq $32,Y(sp),Y(sp)");/* Form Y = 2^32*u */ ! 530: asm(" brb PQADD_R0_1"); /* Return the sum U + Y mod P. */ ! 531: ! 532: /* ! 533: * Computes the sum U + Y mod P where P is of the form P = 2^64 - a. ! 534: * U, Y are quadwords less than P. The sum replaces U and Y on ! 535: * the stack. ! 536: */ ! 537: asm("PQADD_R0:"); ! 538: asm(" popr $1"); /* Record return address */ ! 539: asm("PQADD_R0_1:"); ! 540: asm(" addl2 U(sp),Y(sp)") /* Add the low longwords */ ! 541: asm(" adwc V(sp),Z(sp)"); /* Add the high longwords with the carry */ ! 542: asm(" bcs 2f"); /* If the result is greater than a quadword */ ! 543: asm(" cmpl Z(sp),$-1"); ! 544: asm(" blssu 3f"); ! 545: asm(" cmpl Y(sp),$-A"); /* or simply greater than or equal to P */ ! 546: asm(" blssu 3f"); ! 547: asm("2: addl2 $A,Y(sp)"); /* we must subtract P.*/ ! 548: asm(" adwc $0,Z(sp)"); ! 549: asm("3: movaq Y(sp),sp"); /* Point the stack to the return value */ ! 550: asm(" jmp (r0)"); /* return */ ! 551: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.