Annotation of 43BSD/usr.bin/uucp/vms/validate.c, revision 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.