/* MODULE HTPasswd.c ** PASSWORD FILE ROUTINES ** ** AUTHORS: ** AL Ari Luotonen luotonen@dxcern.cern.ch ** MD Mark Donszelmann duns@vxdeop.cern.ch ** ** HISTORY: ** 7 Nov 93 MD free for crypt taken out (static data returned) ** ** ** BUGS: ** ** */ #include #include "HTUtils.h" #include "HTAAUtil.h" /* Common parts of AA */ #include "HTAAFile.h" /* File routines */ #include "HTPasswd.h" /* Implemented here */ #include "tcp.h" /* FROMASCII() */ extern char *crypt(); PRIVATE char salt_chars [65] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./"; /* PRIVATE next_rec() ** GO TO THE BEGINNING OF THE NEXT RECORD ** Otherwise like HTAAFile_nextRec() but ** does not handle continuation lines ** (because password file has none). ** ON ENTRY: ** fp is the password file from which records are read from. ** ** ON EXIT: ** returns nothing. File read pointer is located at the beginning ** of the next record. */ PRIVATE void next_rec ARGS1(FILE *, fp) { int ch = getc(fp); while (ch != EOF && ch != CR && ch != LF) ch = getc(fp); /* Skip until end-of-line */ while (ch != EOF && (ch == CR || ch == LF)) /*Skip carriage returns and linefeeds*/ ch = getc(fp); if (ch != EOF) ungetc(ch, fp); } /* PUBLIC HTAA_encryptPasswd() ** ENCRYPT PASSWORD TO THE FORM THAT IT IS SAVED ** IN THE PASSWORD FILE. ** ON ENTRY: ** password is a string of arbitrary lenght. ** ** ON EXIT: ** returns password in one-way encrypted form. ** ** NOTE: ** Uses currently the C library function crypt(), which ** only accepts at most 8 characters long strings and produces ** always 13 characters long strings. This function is ** called repeatedly so that longer strings can be encrypted. ** This is of course not as safe as encrypting the entire ** string at once, but then again, we are not that paranoid ** about the security inside the machine. ** */ PUBLIC char *HTAA_encryptPasswd ARGS1(CONST char *, password) { char salt[3]; char chunk[9]; char *result; char *tmp; CONST char *cur = password; int len = strlen(password); extern time_t theTime; int random = (int)theTime; /* This is random enough */ if (!(result = (char*)malloc(13*(((int)strlen(password)+7)/8) + 1))) outofmem(__FILE__, "HTAA_encryptPasswd"); *result = (char)0; while (len > 0) { salt[0] = salt_chars[random%64]; salt[1] = salt_chars[(random/64)%64]; salt[2] = (char)0; strncpy(chunk, cur, 8); chunk[8] = (char)0; tmp = crypt((char*)password, salt); /*crypt() doesn't change its args*/ strcat(result, tmp); cur += 8; len -= 8; } /* while */ return result; } /* PUBLIC HTAA_passwdMatch() ** VERIFY THE CORRECTNESS OF A GIVEN PASSWORD ** AGAINST A ONE-WAY ENCRYPTED FORM OF PASSWORD. ** ON ENTRY: ** password is cleartext password. ** encrypted is one-way encrypted password, as returned ** by function HTAA_encryptPasswd(). ** This is typically read from the password ** file. ** ** ON EXIT: ** returns YES, if password matches the encrypted one. ** NO, if not, or if either parameter is NULL. ** FIX: ** Only the length of original encrypted password is ** checked -- longer given passwords are accepted if ** common length is correct (but not shorter). ** This is to allow interoperation of servers and clients ** who have a hard-coded limit of 8 to password. */ PUBLIC BOOL HTAA_passwdMatch ARGS2(CONST char *, password, CONST char *, encrypted) { char *result; int len; int status; if (!password || !encrypted) return NO; len = 13*(((int)strlen(password)+7)/8); if (len < (int)strlen(encrypted)) return NO; if (!(result = (char*)malloc(len + 1))) outofmem(__FILE__, "HTAA_encryptPasswd"); *result = (char)0; while (len > 0) { char salt[3]; char chunk[9]; CONST char *cur1 = password; CONST char *cur2 = encrypted; char *tmp; salt[0] = *cur2; salt[1] = *(cur2+1); salt[2] = (char)0; strncpy(chunk, cur1, 8); chunk[8] = (char)0; tmp = crypt((char*)password, salt); strcat(result, tmp); cur1 += 8; cur2 += 13; len -= 13; } /* while */ status = strncmp(result, encrypted, strlen(encrypted)); CTRACE(stderr, "Passwd...... Matching encrypted \"%s\" with \"%s\" => %s\n", result, encrypted, (status==0 ? "-OK-" : "-INCORRECT-")); free(result); if (status==0) return YES; else return NO; } /* PUBLIC HTAAFile_readPasswdRec() ** READ A RECORD FROM THE PASSWORD FILE ** ON ENTRY: ** fp open password file ** out_username buffer to put the read username, must be at ** least MAX_USERNAME_LEN+1 characters long. ** out_passwd buffer to put the read password, must be at ** least MAX_PASSWORD_LEN+1 characters long. ** ON EXIT: ** returns EOF on end of file, ** otherwise the number of read fields ** (i.e. in a correct case returns 2). ** out_username contains the null-terminated read username. ** out_password contains the null-terminated read password. ** ** FORMAT OF PASSWORD FILE: ** username:password:maybe real name or other stuff ** (may include even colons) ** ** There may be whitespace (blanks or tabs) in the beginning and ** the end of each field. They are ignored. */ PUBLIC int HTAAFile_readPasswdRec ARGS3(FILE *, fp, char *, out_username, char *, out_password) { int terminator = HTAAFile_readField(fp, out_username, MAX_USERNAME_LEN); if (terminator == EOF) { /* End of file */ return EOF; } else if (terminator == CR || terminator == LF) { /* End of line */ next_rec(fp); return 1; } else { HTAAFile_readField(fp, out_password, MAX_PASSWORD_LEN); next_rec(fp); return 2; } } /* PUBLIC HTAA_checkPassword() ** CHECK A USERNAME-PASSWORD PAIR ** ON ENTRY: ** username is a null-terminated string containing ** the client's username. ** password is a null-terminated string containing ** the client's corresponding password. ** filename is a null-terminated absolute filename ** for password file. ** If NULL or empty, the value of ** PASSWD_FILE is used. ** ON EXIT: ** returns YES, if the username-password pair was correct. ** NO, otherwise; also, if open fails. */ PUBLIC BOOL HTAA_checkPassword ARGS3(CONST char *, username, CONST char *, password, CONST char *, filename) { FILE *fp = NULL; char user[MAX_USERNAME_LEN+1]; char pw[MAX_PASSWORD_LEN+1]; int status; if (filename && *filename) fp = fopen(filename,"r"); else fp = fopen(PASSWD_FILE,"r"); if (!fp) { CTRACE(stderr, "ERROR....... Unable to open password file \"%s\"\n", (filename && *filename ? filename : PASSWD_FILE)); return NO; } *pw = '\0'; do { if (2 == (status = HTAAFile_readPasswdRec(fp,user,pw))) { CTRACE(stderr, "Matching.... username \"%s\" agains pwrec \"%s:%s\"\n", username, user, pw); if (username && user && !strcmp(username,user)) { /* User's record found */ if (*pw) { /* So password is required for this user */ if (!password || !HTAA_passwdMatch(password,pw)) /* Check the pw */ status = EOF; /* If wrong, indicate it with EOF */ } break; /* exit loop */ } /* if username found */ } /* if record is ok */ } while (status != EOF); fclose(fp); CTRACE(stderr,"%s... password for %s\n", ((status != EOF) ? "Correct.." : "INCORRECT"), username); if (status == EOF) return NO; /* We traversed to the end without luck */ else return YES; /* The user was found */ }