|
|
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.