static int hash_password ( uaf_qword *output_hash, string *password, unsigned char encrypt, unsigned short salt, string *username) { string *r3; /* Holds descriptors for COLLAPSE_R2 */ quad *r4; /* Address of the output buffer */ uaf_lword r5; /* Length of username */ char r7 = 0, /* Flag for encryption method # 3 */ *bytptr; /* Pointer for adding in random salt */ quad qword; /* Quadword form of the output buffer */ char uname[13]; /* buffer for padded username (PURDY) */ /* ------------------------------------------------------------------------ */ /* Check for invalid parameters */ if ((encrypt < 1) || (encrypt > 3)) { puts("BAD BAD!"); return -1; // exit(SS$_BADPARAM); } if (username->dsc$w_length > 31) { puts("2"); printf("Internal coding error, username is more than 31 bytes long.\n"); exit(SS$_ABORT); } /* Setup pointer references */ r3 = password; /* 1st COLLAPSE uses the password desc. */ r4 = &qword; /* @r4..@r4+7 equals obuf */ r5 = username->dsc$w_length; r7 = (encrypt == 3); /* Clear the output buffer (zero the quadword) */ r4->ulw[0] = 0; r4->ulw[1] = 0; UAF_QW_SET(*output_hash,0); /* Check for the null password and return zero as the hash value if so */ if (password->dsc$w_length == 0) { return SS$_NORMAL; } switch (encrypt) { int ulen; case UAI$C_AD_II: /* CRC algorithm with Autodin II poly */ /* As yet unsupported */ return SS$_BADPARAM; case UAI$C_PURDY: /* Purdy algorithm */ /* Use a blank padded username */ strncpy(uname," ",sizeof(uname)); strncpy(uname, username->dsc$a_pointer, r5); username->dsc$a_pointer = (char *)&uname; username->dsc$w_length = 12; break; case UAI$C_PURDY_V: /* Purdy with blanks stripped */ case UAI$C_PURDY_S: /* Hickory algorithm; Purdy_V with rotation */ /* Check padding. Don't count blanks in the string length. * Remember: r6->username_descriptor the first word is length, then * 2 bytes of class information (4 bytes total), then the address of the * buffer. Usernames can not be longer than 31 characters. */ for ( ulen = username->dsc$w_length; ulen > 0; ulen-- ) { if ( username->dsc$a_pointer[ulen-1] != ' ' ) break; username->dsc$w_length--; } /* If Purdy_S: Bytes 0-1 => plaintext length */ if (r7) { r4->ulw[0] = password->dsc$w_length; } break; } /* Collapse the password to a quadword U; buffer pointed to by r4 */ COLLAPSE_R2 (r3, r4, r7); /* r3 already points to password descriptor */ /* Add random salt into the middle of U */ /* This has to be done byte-wise because the Sun will not allow you */ /* to add unaligned words, or it will give you a bus error and core dump :) */ bytptr = &r4->b[3+1]; *bytptr += (char)(salt>>8); /* Add the high byte */ /* Check for carry out of the low byte */ bytptr--; if ( (short)((unsigned char)*bytptr + (unsigned char)(salt & 0xff)) > 255) { *(bytptr + 1) += 1; /* Account for the carry */ } *bytptr += (char)(salt & 0xff); /* Add the low byte */ /* Collapse the username into the quadword */ r3 = username; /* Point r3 to the valid username desriptor */ COLLAPSE_R2 (r3, r4, r7); /* U (qword) contains the 8 character output buffer in quadword format */ /* Run U through the polynomial mod P */ Purdy (r4); /* Write qword (*r4) back into the output buffer */ *((quad *) output_hash) = qword; /* Normal exit */ return SS$_NORMAL; } /* LGI$HPWD */
static void process_file(char *infile) { int i, status, lnum, is_raw; FILE *listf, *rawf; char line[4096], *lf, *username, *suffix, *directory, *prefix; char encoded[UAF_ENCODE_SIZE], *result; struct uaf_hash_info pwd, pwd2; struct uaf_account_info acct; struct uaf_rec rec; /* raw record */ uaf_qword null_hash; is_raw = 1; #ifdef VMS if (strcmp(infile, "$") == 0) { is_raw = 0; infile = "SYSUAF.LIS"; spawn_authorize(infile); } else if (infile[0] == '~') { is_raw = 0; infile = "useruaf.lis"; single_user(infile, &argv[1][1]); } else if ((infile[0] != '/') && (0 != strncmp(infile, "./", 2))) { is_raw = 0; } #endif if (is_raw) { rawf = fopen(infile, "rb"); listf = (FILE *) 0; } else { listf = fopen(infile, "r"); rawf = (FILE *) 0; } if (!listf && !rawf) { fprintf(stderr, "File open failure on '%s'\n", infile); if (rawf) fclose(rawf); return; } /* * Convert each input line to a corresponding passwd file line. */ uaf_init(); UAF_QW_SET(null_hash, 0); lnum = 0; while (1) { char *priv_summary; if (is_raw) { /* * Input file is raw UAF file records, call function in uaf_encode * module to extract passwword and other information. */ if (1 != fread(&rec, sizeof(rec), 1, rawf)) break; status = uaf_extract_from_raw(&rec, sizeof(rec), &pwd, &pwd2, &acct, &prefix, &priv_summary); } else { /* * Input is a authorize utility brief listing, trim carriage control. */ if (!fgets(line, sizeof(line), listf)) break; lf = strchr(line, '\n'); if (lf) *lf = '\0'; lnum++; if (strlen(line) < 21) continue; /* line too short, ignore */ /* * Extract summary data and username from line. */ prefix = ""; if (strlen(line) > 69) { directory = &line[69]; if (strcmp(directory, "Disuser") == 0) prefix = "/disuser"; if (strcmp(directory, "Expired") == 0) prefix = "/expired"; } if (strlen(line) > 59) { priv_summary = &line[59]; for (i = 0; priv_summary[i]; i++) { if (priv_summary[i] == ' ') { priv_summary[i] = '\0'; break; } } } else { priv_summary = "unknown"; } username = &line[21]; for (i = 0; username[i]; i++) { if (username[i] == ' ') { username[i] = '\0'; break; } } /* * Use $GETUAI to get info needed to populate fields of passwd file * line. Be lazy and use dummy string for home_dir (to avoid dealing * with colon in VMS file specification). */ if (strcmp(username, "Username") == 0) continue; /* header line */ status = uaf_getuai_info(username, &pwd, &pwd2, &acct); } if (status & 1) { /* * Output user data as passwd-like text line. */ if (UAF_QW_EQL(pwd2.hash, null_hash)) suffix = ""; else suffix = ".1"; /* flag as primary of 2 */ result = uaf_hash_encode(&pwd, encoded); fprintf(stdout, "%s%s:%s:%d:%d:%s:/%s%s%s/%s:%s\n", colon_blow(pwd.username.s), suffix, result, acct.uic[0], acct.uic[1], colon_blow(acct.owner), (pwd.flags & UAI$M_PWDMIX) ? "Users" : "USERS", prefix[0] ? "/" : "", prefix, priv_summary, colon_blow(acct.shell)); if (suffix[0] == '.') { /* * secondary password present. */ result = uaf_hash_encode(&pwd2, encoded); fprintf(stdout, "%s%s:%s:%d:%d:%s:/%s%s%s/%s:%s\n", colon_blow(pwd.username.s), suffix, result, acct.uic[0], acct.uic[1], colon_blow(acct.owner), (pwd. flags & UAI$M_PWDMIX) ? "Users" : "USERS", prefix[0] ? "/" : "", prefix, priv_summary, colon_blow(acct.shell)); } } else { fprintf(stderr, "Error fetching UAF information, %s\n", prefix); return; } } if (is_raw) fclose(rawf); else fclose(listf); }