Annotation of 43BSDTahoe/usr.bin/uucp/vms/validate.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.