2 * Main coding by Elliot Lee <sopwith@redhat.com>, Red Hat Software.
4 * Copyright (c) Jan Rêkorajski, 1999.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, and the entire permission notice in its entirety,
11 * including the disclaimer of warranties.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote
16 * products derived from this software without specific prior
19 * ALTERNATIVELY, this product may be distributed under the terms of
20 * the GNU Public License, in which case the provisions of the GPL are
21 * required INSTEAD OF the above restrictions. (This clause is
22 * necessary due to a potential bad interaction between the GPL and
23 * the restrictions contained in a BSD-style copyright.)
25 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
26 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
35 * OF THE POSSIBILITY OF SUCH DAMAGE.
56 #include <time.h> /* for time() */
60 #include <sys/types.h>
63 #include <rpcsvc/yp_prot.h>
64 #include <rpcsvc/ypclnt.h>
70 #include <security/_pam_macros.h>
72 /* indicate the following groups are defined */
74 #define PAM_SM_PASSWORD
76 #include <security/pam_modules.h>
79 #include <security/pam_appl.h>
80 #endif /* LINUX_PAM */
86 #if !((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1))
87 extern int getrpcport(const char *host, unsigned long prognum,
88 unsigned long versnum, unsigned int proto);
89 #endif /* GNU libc 2.1 */
92 * PAM framework looks for these entry-points to pass control to the
93 * password changing module.
97 #include "./lckpwdf.-c"
100 extern char *bigcrypt(const char *key, const char *salt);
104 Gets in username (has to be done) from the calling program
105 Does authentication of user (only if we are not running as root)
106 Gets new password/checks for sanity
110 /* passwd/salt conversion macros */
112 #define ascii_to_bin(c) ((c)>='a'?(c-59):(c)>='A'?((c)-53):(c)-'.')
113 #define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.')
117 #define _UNIX_OLD_AUTHTOK "-UN*X-OLD-PASS"
118 #define _UNIX_NEW_AUTHTOK "-UN*X-NEW-PASS"
120 #define MAX_PASSWD_TRIES 3
121 #define PW_TMPFILE "/etc/npasswd"
122 #define SH_TMPFILE "/etc/nshadow"
123 #define CRACKLIB_DICTS "/usr/share/dict/cracklib_dict"
124 #define OPW_TMPFILE "/etc/security/nopasswd"
125 #define OLD_PASSWORDS_FILE "/etc/security/opasswd"
128 * i64c - convert an integer to a radix 64 character
130 static int i64c(int i)
140 if (i >= 2 && i <= 11)
141 return ('0' - 2 + i);
142 if (i >= 12 && i <= 37)
143 return ('A' - 12 + i);
144 if (i >= 38 && i <= 63)
145 return ('a' - 38 + i);
149 static char *crypt_md5_wrapper(const char *pass_new)
152 * Code lifted from Marek Michalkiewicz's shadow suite. (CG)
153 * removed use of static variables (AGM)
158 unsigned char result[16];
159 char *cp = (char *) result;
160 unsigned char tmp[16];
165 gettimeofday(&tv, (struct timezone *) 0);
166 GoodMD5Update(&ctx, (void *) &tv, sizeof tv);
168 GoodMD5Update(&ctx, (void *) &i, sizeof i);
170 GoodMD5Update(&ctx, (void *) &i, sizeof i);
171 GoodMD5Update(&ctx, result, sizeof result);
172 GoodMD5Final(tmp, &ctx);
173 strcpy(cp, "$1$"); /* magic for the MD5 */
175 for (i = 0; i < 8; i++)
176 *cp++ = i64c(tmp[i] & 077);
179 /* no longer need cleartext */
180 e = Goodcrypt_md5(pass_new, (const char *) result);
181 x = x_strdup(e); /* put e in malloc()ed memory */
182 _pam_overwrite(e); /* clean up */
187 static char *getNISserver(void)
193 if ((err = yp_get_default_domain(&domainname)) != 0) {
194 _log_err(LOG_WARNING, "can't get local yp domain: %s\n",
198 if ((err = yp_master(domainname, "passwd.byname", &master)) != 0) {
199 _log_err(LOG_WARNING, "can't find the master ypserver: %s\n",
203 port = getrpcport(master, YPPASSWDPROG, YPPASSWDPROC_UPDATE, IPPROTO_UDP);
205 _log_err(LOG_WARNING, "yppasswdd not running on NIS master host\n");
208 if (port >= IPPORT_RESERVED) {
209 _log_err(LOG_WARNING, "yppasswd daemon running on illegal port.\n");
215 static int check_old_password(const char *forwho, const char *newpass)
217 static char buf[16384];
218 char *s_luser, *s_uid, *s_npas, *s_pas;
219 int retval = PAM_SUCCESS;
222 opwfile = fopen(OLD_PASSWORDS_FILE, "r");
224 return PAM_AUTHTOK_ERR;
226 while (fgets(buf, 16380, opwfile)) {
227 if (!strncmp(buf, forwho, strlen(forwho))) {
228 buf[strlen(buf) - 1] = '\0';
229 s_luser = strtok(buf, ":,");
230 s_uid = strtok(NULL, ":,");
231 s_npas = strtok(NULL, ":,");
232 s_pas = strtok(NULL, ":,");
233 while (s_pas != NULL) {
234 if (!strcmp(Goodcrypt_md5(newpass, s_pas), s_pas)) {
235 retval = PAM_AUTHTOK_ERR;
238 s_pas = strtok(NULL, ":,");
248 static int save_old_password(const char *forwho, const char *oldpass, int howmany)
250 static char buf[16384];
251 static char nbuf[16384];
252 char *s_luser, *s_uid, *s_npas, *s_pas, *pass;
253 int retval = 0, npas;
254 FILE *pwfile, *opwfile;
258 struct passwd *pwd = NULL;
266 oldmask = umask(077);
267 pwfile = fopen(OPW_TMPFILE, "w");
269 opwfile = fopen(OLD_PASSWORDS_FILE, "r");
270 if (pwfile == NULL || opwfile == NULL)
271 return PAM_AUTHTOK_ERR;
272 chown(OPW_TMPFILE, 0, 0);
273 chmod(OPW_TMPFILE, 0600);
275 while (fgets(buf, 16380, opwfile)) {
276 if (!strncmp(buf, forwho, strlen(forwho))) {
277 buf[strlen(buf) - 1] = '\0';
278 s_luser = strtok(buf, ":");
279 s_uid = strtok(NULL, ":");
280 s_npas = strtok(NULL, ":");
281 s_pas = strtok(NULL, ":");
282 npas = strtol(s_npas, NULL, 10) + 1;
283 while (npas > howmany) {
284 s_pas = strpbrk(s_pas, ",");
289 pass = crypt_md5_wrapper(oldpass);
291 sprintf(nbuf, "%s:%s:%d:%s\n", s_luser, s_uid, npas, pass);
293 sprintf(nbuf, "%s:%s:%d:%s,%s\n", s_luser, s_uid, npas, s_pas, pass);
294 if (fputs(nbuf, pwfile) < 0) {
295 retval = PAM_AUTHTOK_ERR;
300 } else if (fputs(buf, pwfile) < 0) {
301 retval = PAM_AUTHTOK_ERR;
308 pwd = getpwnam(forwho);
310 retval = PAM_AUTHTOK_ERR;
313 pass = crypt_md5_wrapper(oldpass);
314 sprintf(nbuf, "%s:%d:1:%s\n", forwho, pwd->pw_uid, pass);
315 if (fputs(nbuf, pwfile) < 0) {
316 retval = PAM_AUTHTOK_ERR;
321 if (fclose(pwfile)) {
322 fprintf(stderr, "error writing entries to old passwords file: %s\n",
324 retval = PAM_AUTHTOK_ERR;
328 rename(OPW_TMPFILE, OLD_PASSWORDS_FILE);
335 static int _update_passwd(const char *forwho, char *towhat)
337 struct passwd *tmpent = NULL;
338 FILE *pwfile, *opwfile;
343 oldmask = umask(077);
344 pwfile = fopen(PW_TMPFILE, "w");
346 opwfile = fopen("/etc/passwd", "r");
347 if (pwfile == NULL || opwfile == NULL)
348 return PAM_AUTHTOK_ERR;
349 chown(PW_TMPFILE, 0, 0);
350 chmod(PW_TMPFILE, 0644);
351 tmpent = fgetpwent(opwfile);
353 if (!strcmp(tmpent->pw_name, forwho)) {
354 tmpent->pw_passwd = towhat;
356 if (putpwent(tmpent, pwfile)) {
357 fprintf(stderr, "error writing entry to password file: %s\n",
360 retval = PAM_AUTHTOK_ERR;
363 tmpent = fgetpwent(opwfile);
367 if (fclose(pwfile)) {
368 fprintf(stderr, "error writing entries to password file: %s\n",
370 retval = PAM_AUTHTOK_ERR;
374 rename(PW_TMPFILE, "/etc/passwd");
381 static int _update_shadow(const char *forwho, char *towhat)
383 struct spwd *spwdent = NULL, *stmpent = NULL;
384 FILE *pwfile, *opwfile;
389 spwdent = getspnam(forwho);
391 return PAM_USER_UNKNOWN;
392 oldmask = umask(077);
393 pwfile = fopen(SH_TMPFILE, "w");
395 opwfile = fopen("/etc/shadow", "r");
396 if (pwfile == NULL || opwfile == NULL)
397 return PAM_AUTHTOK_ERR;
398 chown(SH_TMPFILE, 0, 0);
399 chmod(SH_TMPFILE, 0600);
400 stmpent = fgetspent(opwfile);
402 if (!strcmp(stmpent->sp_namp, forwho)) {
403 stmpent->sp_pwdp = towhat;
404 stmpent->sp_lstchg = time(NULL) / (60 * 60 * 24);
406 D(("Set password %s for %s", stmpent->sp_pwdp, forwho));
408 if (putspent(stmpent, pwfile)) {
409 fprintf(stderr, "error writing entry to shadow file: %s\n",
412 retval = PAM_AUTHTOK_ERR;
415 stmpent = fgetspent(opwfile);
419 if (fclose(pwfile)) {
420 fprintf(stderr, "error writing entries to shadow file: %s\n",
422 retval = PAM_AUTHTOK_ERR;
426 rename(SH_TMPFILE, "/etc/shadow");
433 static int _do_setpass(const char *forwho, char *fromwhat, char *towhat,
434 unsigned int ctrl, int remember)
436 struct passwd *pwd = NULL;
442 pwd = getpwnam(forwho);
446 return PAM_AUTHTOK_ERR;
448 if (on(UNIX_NIS, ctrl)) {
449 struct timeval timeout;
450 struct yppasswd yppwd;
456 /* Make RPC call to NIS server */
457 if ((master = getNISserver()) == NULL)
458 return PAM_TRY_AGAIN;
460 /* Initialize password information */
461 yppwd.newpw.pw_passwd = pwd->pw_passwd;
462 yppwd.newpw.pw_name = pwd->pw_name;
463 yppwd.newpw.pw_uid = pwd->pw_uid;
464 yppwd.newpw.pw_gid = pwd->pw_gid;
465 yppwd.newpw.pw_gecos = pwd->pw_gecos;
466 yppwd.newpw.pw_dir = pwd->pw_dir;
467 yppwd.newpw.pw_shell = pwd->pw_shell;
468 yppwd.oldpass = fromwhat;
469 yppwd.newpw.pw_passwd = towhat;
471 D(("Set password %s for %s", yppwd.newpw.pw_passwd, forwho));
473 /* The yppasswd.x file said `unix authentication required',
474 * so I added it. This is the only reason it is in here.
475 * My yppasswdd doesn't use it, but maybe some others out there
478 clnt = clnt_create(master, YPPASSWDPROG, YPPASSWDVERS, "udp");
479 clnt->cl_auth = authunix_create_default();
480 memset((char *) &status, '\0', sizeof(status));
483 err = clnt_call(clnt, YPPASSWDPROC_UPDATE,
484 (xdrproc_t) xdr_yppasswd, (char *) &yppwd,
485 (xdrproc_t) xdr_int, (char *) &status,
490 retval = PAM_TRY_AGAIN;
492 fprintf(stderr, "Error while changing NIS password.\n");
493 retval = PAM_TRY_AGAIN;
495 printf("\nThe password has%s been changed on %s.\n",
496 (err || status) ? " not" : "", master);
498 auth_destroy(clnt->cl_auth);
500 if ((err || status) != 0) {
501 retval = PAM_TRY_AGAIN;
508 /* first, save old password */
509 if (save_old_password(forwho, fromwhat, remember)) {
510 return PAM_AUTHTOK_ERR;
512 if (on(UNIX_SHADOW, ctrl) || (strcmp(pwd->pw_passwd, "x") == 0)) {
513 retval = _update_shadow(forwho, towhat);
514 if (retval == PAM_SUCCESS)
515 retval = _update_passwd(forwho, "x");
517 retval = _update_passwd(forwho, towhat);
523 static int _unix_verify_shadow(const char *user, unsigned int ctrl)
525 struct passwd *pwd = NULL; /* Password and shadow password */
526 struct spwd *spwdent = NULL; /* file entries for the user */
528 int retval = PAM_SUCCESS;
530 /* UNIX passwords area */
532 pwd = getpwnam(user); /* Get password file entry... */
535 return PAM_AUTHINFO_UNAVAIL; /* We don't need to do the rest... */
537 if (strcmp(pwd->pw_passwd, "x") == 0) {
538 /* ...and shadow password file entry for this user, if shadowing
541 spwdent = getspnam(user);
545 return PAM_AUTHINFO_UNAVAIL;
547 if (strcmp(pwd->pw_passwd,"*NP*") == 0) { /* NIS+ */
550 save_uid = geteuid();
551 seteuid (pwd->pw_uid);
552 spwdent = getspnam( user );
556 return PAM_AUTHINFO_UNAVAIL;
561 if (spwdent != NULL) {
562 /* We have the user's information, now let's check if their account
563 has expired (60 * 60 * 24 = number of seconds in a day) */
565 if (off(UNIX__IAMROOT, ctrl)) {
566 /* Get the current number of days since 1970 */
567 curdays = time(NULL) / (60 * 60 * 24);
568 if ((curdays < (spwdent->sp_lstchg + spwdent->sp_min))
569 && (spwdent->sp_min != -1))
570 retval = PAM_AUTHTOK_ERR;
571 else if ((curdays > (spwdent->sp_lstchg + spwdent->sp_max + spwdent->sp_inact))
572 && (spwdent->sp_max != -1) && (spwdent->sp_inact != -1)
573 && (spwdent->sp_lstchg != 0))
575 * Their password change has been put off too long,
577 retval = PAM_ACCT_EXPIRED;
578 else if ((curdays > spwdent->sp_expire) && (spwdent->sp_expire != -1)
579 && (spwdent->sp_lstchg != 0))
581 * OR their account has just plain expired
583 retval = PAM_ACCT_EXPIRED;
589 static int _pam_unix_approve_pass(pam_handle_t * pamh
591 ,const char *pass_old
592 ,const char *pass_new)
596 int retval = PAM_SUCCESS;
598 D(("&new=%p, &old=%p", pass_old, pass_new));
599 D(("new=[%s]", pass_new));
600 D(("old=[%s]", pass_old));
602 if (pass_new == NULL || (pass_old && !strcmp(pass_old, pass_new))) {
603 if (on(UNIX_DEBUG, ctrl)) {
604 _log_err(LOG_DEBUG, "bad authentication token");
606 _make_remark(pamh, ctrl, PAM_ERROR_MSG, pass_new == NULL ?
607 "No password supplied" : "Password unchanged");
608 return PAM_AUTHTOK_ERR;
611 * if one wanted to hardwire authentication token strength
612 * checking this would be the place - AGM
615 retval = pam_get_item(pamh, PAM_USER, (const void **) &user);
616 if (retval != PAM_SUCCESS) {
617 if (on(UNIX_DEBUG, ctrl)) {
618 _log_err(LOG_ERR, "Can not get username");
619 return PAM_AUTHTOK_ERR;
622 if (off(UNIX__IAMROOT, ctrl)) {
624 remark = FascistCheck(pass_new, CRACKLIB_DICTS);
625 D(("called cracklib [%s]", remark));
627 if (strlen(pass_new) < 6)
628 remark = "You must choose a longer password";
629 D(("lenth check [%s]", remark));
631 if (on(UNIX_REMEMBER_PASSWD, ctrl))
632 if ((retval = check_old_password(user, pass_new)) != PAM_SUCCESS)
633 remark = "Password has been already used. Choose another.";
636 _make_remark(pamh, ctrl, PAM_ERROR_MSG, remark);
637 retval = PAM_AUTHTOK_ERR;
643 PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
644 int argc, const char **argv)
646 unsigned int ctrl, lctrl;
650 /* <DO NOT free() THESE> */
652 char *pass_old, *pass_new;
653 /* </DO NOT free() THESE> */
658 /* our current locking system requires that we lock the
659 entire password database. This avoids both livelock
661 /* These values for the number of attempts and the sleep time
662 are, of course, completely arbitrary.
663 My reading of the PAM docs is that, once pam_chauthtok() has been
664 called with PAM_UPDATE_AUTHTOK, we are obliged to take any
665 reasonable steps to make sure the token is updated; so retrying
666 for 1/10 sec. isn't overdoing it.
667 The other possibility is to call lckpwdf() on the first
668 pam_chauthtok() pass, and hold the lock until released in the
669 second pass--but is this guaranteed to work? -SRL */
671 while((retval = lckpwdf()) != 0 && i < 100) {
675 return PAM_AUTHTOK_LOCK_BUSY;
678 ctrl = _set_ctrl(flags, &remember, argc, argv);
681 * First get the name of a user
683 retval = pam_get_user(pamh, &user, "Username: ");
684 if (retval == PAM_SUCCESS) {
686 * Various libraries at various times have had bugs related to
687 * '+' or '-' as the first character of a user name. Don't take
688 * any chances here. Require that the username starts with an
689 * alphanumeric character.
691 if (user == NULL || !isalnum(*user)) {
692 _log_err(LOG_ERR, "bad username [%s]", user);
696 return PAM_USER_UNKNOWN;
698 if (retval == PAM_SUCCESS && on(UNIX_DEBUG, ctrl))
699 _log_err(LOG_DEBUG, "username [%s] obtained", user);
701 if (on(UNIX_DEBUG, ctrl))
702 _log_err(LOG_DEBUG, "password - could not identify user");
709 D(("Got username of %s", user));
712 * This is not an AUTH module!
714 if (on(UNIX__NONULL, ctrl))
715 set(UNIX__NULLOK, ctrl);
717 if (on(UNIX__PRELIM, ctrl)) {
719 * obtain and verify the current password (OLDAUTHTOK) for
726 if (_unix_blankpasswd(ctrl, user)) {
731 } else if (off(UNIX__IAMROOT, ctrl)) {
733 /* instruct user what is happening */
734 #define greeting "Changing password for "
735 Announce = (char *) malloc(sizeof(greeting) + strlen(user));
736 if (Announce == NULL) {
737 _log_err(LOG_CRIT, "password - out of memory");
743 (void) strcpy(Announce, greeting);
744 (void) strcpy(Announce + sizeof(greeting) - 1, user);
748 set(UNIX__OLD_PASSWD, lctrl);
749 retval = _unix_read_password(pamh, lctrl
751 ,"(current) UNIX password: "
754 ,(const char **) &pass_old);
757 if (retval != PAM_SUCCESS) {
759 ,"password - (old) token not obtained");
765 /* verify that this is the password for this user */
767 retval = _unix_verify_password(pamh, user, pass_old, ctrl);
769 D(("process run by root so do nothing this time around"));
771 retval = PAM_SUCCESS; /* root doesn't have too */
774 if (retval != PAM_SUCCESS) {
775 D(("Authentication failed"));
782 retval = pam_set_item(pamh, PAM_OLDAUTHTOK, (const void *) pass_old);
784 if (retval != PAM_SUCCESS) {
785 _log_err(LOG_CRIT, "failed to set PAM_OLDAUTHTOK");
787 retval = _unix_verify_shadow(user, ctrl);
788 if (retval == PAM_AUTHTOK_ERR) {
789 if (off(UNIX__IAMROOT, ctrl))
790 _make_remark(pamh, ctrl, PAM_ERROR_MSG,
791 "You must wait longer to change your password");
793 retval = PAM_SUCCESS;
795 } else if (on(UNIX__UPDATE, ctrl)) {
797 * tpass is used below to store the _pam_md() return; it
798 * should be _pam_delete()'d.
805 * obtain the proposed password
811 * get the old token back. NULL was ok only if root [at this
812 * point we assume that this has already been enforced on a
813 * previous call to this function].
816 if (off(UNIX_NOT_SET_PASS, ctrl)) {
817 retval = pam_get_item(pamh, PAM_OLDAUTHTOK
818 ,(const void **) &pass_old);
820 retval = pam_get_data(pamh, _UNIX_OLD_AUTHTOK
821 ,(const void **) &pass_old);
822 if (retval == PAM_NO_MODULE_DATA) {
823 retval = PAM_SUCCESS;
827 D(("pass_old [%s]", pass_old));
829 if (retval != PAM_SUCCESS) {
830 _log_err(LOG_NOTICE, "user not authenticated");
836 retval = _unix_verify_shadow(user, ctrl);
837 if (retval != PAM_SUCCESS) {
838 _log_err(LOG_NOTICE, "user not authenticated 2");
844 D(("get new password now"));
848 if (on(UNIX_USE_AUTHTOK, lctrl)) {
849 set(UNIX_USE_FIRST_PASS, lctrl);
852 retval = PAM_AUTHTOK_ERR;
853 while ((retval != PAM_SUCCESS) && (retry++ < MAX_PASSWD_TRIES)) {
855 * use_authtok is to force the use of a previously entered
856 * password -- needed for pluggable password strength checking
859 retval = _unix_read_password(pamh, lctrl
861 ,"Enter new UNIX password: "
862 ,"Retype new UNIX password: "
864 ,(const char **) &pass_new);
866 if (retval != PAM_SUCCESS) {
867 if (on(UNIX_DEBUG, ctrl)) {
869 ,"password - new password not obtained");
871 pass_old = NULL; /* tidy up */
877 D(("returned to _unix_chauthtok"));
880 * At this point we know who the user is and what they
881 * propose as their new password. Verify that the new
882 * password is acceptable.
885 if (pass_new[0] == '\0') { /* "\0" password = NULL */
888 retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new);
891 if (retval != PAM_SUCCESS) {
892 _log_err(LOG_NOTICE, "new password not acceptable");
893 _pam_overwrite(pass_new);
894 _pam_overwrite(pass_old);
895 pass_new = pass_old = NULL; /* tidy up */
902 * By reaching here we have approved the passwords and must now
903 * rebuild the password database file.
907 * First we encrypt the new password.
910 if (on(UNIX_MD5_PASS, ctrl)) {
911 tpass = crypt_md5_wrapper(pass_new);
914 * Salt manipulation is stolen from Rick Faith's passwd
915 * program. Sorry Rick :) -- alex
922 salt[0] = bin_to_ascii(tm & 0x3f);
923 salt[1] = bin_to_ascii((tm >> 6) & 0x3f);
926 if (off(UNIX_BIGCRYPT, ctrl) && strlen(pass_new) > 8) {
928 * to avoid using the _extensions_ of the bigcrypt()
929 * function we truncate the newly entered password
931 char *temp = malloc(9);
935 _log_err(LOG_CRIT, "out of memory for password");
936 _pam_overwrite(pass_new);
937 _pam_overwrite(pass_old);
938 pass_new = pass_old = NULL; /* tidy up */
944 /* copy first 8 bytes of password */
945 strncpy(temp, pass_new, 8);
948 /* no longer need cleartext */
949 e = bigcrypt(temp, salt);
953 _pam_delete(temp); /* tidy up */
957 /* no longer need cleartext */
958 e = bigcrypt(pass_new, salt);
965 D(("password processed"));
967 /* update the password database(s) -- race conditions..? */
969 retval = _do_setpass(user, pass_old, tpass, ctrl, remember);
970 _pam_overwrite(pass_new);
971 _pam_overwrite(pass_old);
973 pass_old = pass_new = NULL;
974 } else { /* something has broken with the module */
975 _log_err(LOG_ALERT, "password received unknown request");
979 D(("retval was %d", retval));
988 /* static module data */
990 struct pam_module _pam_unix_passwd_modstruct = {