home *** CD-ROM | disk | FTP | other *** search
- #ifdef ALLOW_CHANGE_PASSWORD
- /* fork a child process to exec passwd and write to its
- * tty to change a users password. This is running as the
- * user who is attempting to change the password.
- */
-
- /*
- * This code was copied/borrowed and stolen from various sources.
- * The primary source was the poppasswd.c from the authors of POPMail. This software
- * was included as a client to change passwords using the 'passwd' program
- * on the remote machine.
- *
- * It has been dissected and recreated in a form that allows passwd changing for
- * a valid user (user is already validated BEFORE this routine is run). It compares
- * the user name to those in the LOCAL password file and, if they are found, it
- * runs 'passwd.' If not, however, it assumes, since the person has already been
- * validated, that they are an NIS user and it uses 'yppasswd.'
- *
- * This routine is called by set_user_password() in password.c only if ALLOW_PASSWORD_CHANGE
- * is defined in the compiler directives located in the Makefile.
- *
- *
- * This code has been hacked by Bob Nance (nance@niehs.nih.gov) and Evan Patterson
- * (patters2@niehs.nih.gov) at the National Institute of Environmental Health Sciences
- * and rights to modify, distribute or incorporate this change to the CAP suite or
- * using it for any other reason are granted, so long as this disclaimer is left intact.
- */
-
- #include "includes.h"
- #include "loadparm.h"
-
- #define MINPASSWDLENGTH 5
- #define BUFSIZE 512
-
- #define DLINE DEBUG(5,("DLINE %s %d\n",__FILE__,__LINE__))
-
- extern int DEBUGLEVEL;
- static char *P1[] =
- {"Old password:",
- "Old NIS password:",
- "Changing password for *.\nOld password:",
- "Changing password for * on *.\nOld password:",
- "Changing NIS password for * on *.\nOld password:",
- "Changing password for *\n*'s Old password:",
- "Changing password for *\nOld password: ", /* for ULTRIX */
- "Changing password for *.\n\nNew password:", /* for OSF/1 */
- "Changing NIS password for *\nOld NIS password:",
- ""};
-
- static char *P2[] =
- {"\nRe-enter new password:",
- "\nRetype new password:",
- "\nEnter the new password again:",
- "\n*Re-enter *'s new password:",
- "\nVerify:",
- "\nVerify: ", /* for ULTRIX */
- "\nWarning, only the first 8 characters of the password are significant.\nVerify: ", /* for ULTRIX */
- ""};
-
- static char *P4[] =
- {"\n",
- "NIS entry changed on *\n",
- "\nNIS passwd changed on *\n",
- ""};
-
- /* P5 was added to allow users to enter passwords that contained all lower-
- case letters and no punctuation or numbers. This is not the best way of
- doing it, but it allows Mac users to use simple passwords. We felt that,
- since no users had interactive access to the machine, we weren't comprom-
- izing system security TOO much.
- */
-
- static char *P5[] =
- {"\nPlease don't use an all-lower case password.\nUnusual capitalization, control characters or digits are suggested.\nNew password:",""};
-
- static int findpty (char **slave);
- static int talktochild(int master,char *oldpass,char *newpass,char *emess);
- static int dochild(int master,char *slavedev,char *name,char *oldpass,char *newpass);
- static int expect(int master,char **expected,char *buf);
- static void getemess (int master,char **expected,char *buf);
- static void writestring (int fd,char *s);
- static int match(char *str,char *pat);
-
-
-
-
- BOOL chgpasswd(name,oldpass,newpass)
- char *name, *oldpass, *newpass;
- {
- char emess[255];
- char *slavedev;
- struct passwd *getpwnam();
- int master;
- pid_t pid, wpid;
- int wstat;
- int putpwent();
-
- strlower(name);
- DEBUG(3,("Password change for user: %s\n",name));
-
- /* Take the passed information and test it for minimum criteria */
- /* Minimum password length */
- DLINE;
- if (strlen(newpass) < MINPASSWDLENGTH) /* too short, must be at least MINPASSWDLENGTH */
- {
- DEBUG(2,("Password Change: %s, New password is shorter than MINPASSWDLENGTH\n",name));
- return (False); /* inform the user */
- }
-
- /* Password is same as old password */
- DLINE;
- if (strncmp(oldpass,newpass,8) == 0) /* don't allow same password */
- {
- DEBUG(2,("Password Change: %s, New password is same as old\n",name)); /* log the attempt */
- return (False); /* inform the user */
- }
-
- /* That done, let's attempt to actually change the password */
- /* allocate a pseudo-terminal device */
- DLINE;
- if ((master = findpty (&slavedev)) < 0)
- {
- DEBUG(3,("Cannot Allocate pty for password change: %s",name));
- return(False);
- }
- DLINE;
- if ((pid = fork()) < 0)
- {
- DEBUG(3,("Cannot fork() child for password change: %s",name));
- return(False);
- }
-
- DLINE;
-
- /* we now have a pty */
- if (pid > 0){ /* This is the parent process */
- DLINE;
- if (talktochild (master, oldpass, newpass, emess) == False)
- {
- DEBUG(3,("Child failed to change password: %s\n",name));
- return(False);
- }
- DLINE;
- if ((wpid = waitpid (pid, &wstat, 0)) < 0) {
- DEBUG(3,("The process is no longer waiting!\n\n"));
- return(False);
- }
- if (pid != wpid) {
- DEBUG(3,("We were waiting for the wrong process ID\n"));
- return(False);
- }
- if (WIFEXITED (wstat) == 0) {
- DEBUG(3,("The process exited while we were waiting\n"));
- return(False);
- }
- if (WEXITSTATUS (wstat) != 0) {
- DEBUG(3,("The status of the process exiting was incorrect\n"));
- return(False);
- }
- }
- else /* CHILD */
- {
- DLINE;
- dochild (master, slavedev, name, oldpass, newpass);
- }
- DEBUG(3,("Password change successful for user %s\n",name));
- return (True);
- }
-
-
- static int dochild (master, slavedev, name, oldpass, newpass)
- int master;
- char *slavedev, *name, *oldpass, *newpass;
- {
- char *command, *dummy;
- int slave;
- struct termios stermios;
- char *passwordprogram=lp_passwd_program();
- char *shortname="passwd";
-
- command="";
- dummy="";
- passwordprogram = lp_passwd_program();
-
- /* Start new session - gets rid of controlling terminal. */
- if (setsid() < 0) {
- DEBUG(3,("Weirdness, couldn't let go of controlling terminal\n"));
- return(False);
- }
-
- /* Open slave pty and acquire as new controlling terminal. */
- if ((slave = open(slavedev, O_RDWR)) < 0) {
- DEBUG(3,("More weirdness, could not read/write to new pty\n"));
- return(False);
- }
- ioctl(slave,TIOCSCTTY,0);
-
- /* Close master. */
- close(master);
-
- /* Make slave stdin/out/err of child. */
-
- if (dup2(slave, STDIN_FILENO) != STDIN_FILENO) {
- DEBUG(3,("Could not re-direct stdin\n"));
- return(False);
- }
- if (dup2(slave, STDOUT_FILENO) != STDOUT_FILENO) {
- DEBUG(3,("Could not re-direct stdout\n"));
- return(False);
- }
- if (dup2(slave, STDERR_FILENO) != STDERR_FILENO) {
- DEBUG(3,("Could not re-direct stderr\n"));
- return(False);
- }
- if (slave > 2) close(slave);
-
- /* Set proper terminal attributes - no echo, canonical input processing,
- no map NL to CR/NL on output. */
-
- if (tcgetattr(0, &stermios) < 0) {
- DEBUG(3,("could not read default terminal attributes on pty\n"));
- return(False);
- }
- stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
- stermios.c_lflag |= ICANON;
- stermios.c_oflag &= ~(ONLCR);
- if (tcsetattr(0, TCSANOW, &stermios) < 0) {
- DEBUG(3,("could not set attributes of pty\n"));
- return(False);
- }
-
- /* execl() password-change application */
- command=NULL;
- if (execl(passwordprogram, shortname, name, (char*)0) < 0) {
- DEBUG(3,("Bad status returned from %s",command));
- return(False);
- }
- return(True);
- }
-
- static int talktochild (master, oldpass, newpass, emess)
- int master;
- char *oldpass, *newpass, *emess;
- {
- char buf[BUFSIZE];
- char pswd[BUFSIZE+1];
-
- *emess = 0;
- sleep(1);
- if (!expect(master, P1, buf)) /* Compare what is on the pty with what is stored in P1 */
- {
- DEBUG(3,("P1 not correct: %s",buf));
- getemess(master, P1, buf);
- strcpy(emess,buf);
- DEBUG(3,("P1 not correct: %s",emess));
- return (False);
- }
- sleep(1);
- sprintf(pswd, "%s\n", newpass);
- writestring(master, pswd);
-
- if (!expect(master, P2, buf))
- {
- /* expect CLEARS buf and gets a new copy of it from the TTY */
- if (strncmp(P5[0],buf,strlen(buf))!=0)
- {
- DEBUG(3,("P5 and P3 not correct \n\n"));
- return (False);
- }
- else
- {
- writestring(master, pswd);
- sleep(1);
- if( !expect(master,P5,buf) && (strncmp(P5[0],buf,strlen(buf))!=0))
- {
- DEBUG(3,("P5 not correct\n"));
- return (False);
- }
- writestring(master, pswd);
- sleep(1);
- if( !expect(master,P5,buf) && (strncmp(P5[0],buf,strlen(buf))!=0))
- {
- DEBUG(3,("P5 not correct\n"));
- return (False);
- }
- writestring(master,pswd);
- sleep(1);
- if(!expect(master,P2,buf) && (strncmp(P5[0],buf,strlen(buf))!=0))
- {
- DEBUG(3,("P2 not correct\n"));
- return (False);
- }
- }
- }
- writestring(master, pswd);
- sleep(1);
- if (!expect(master, P4, buf))
- {
- DEBUG(3,("P4 not correct: %s\n",buf));
- return (False);
- }
- return (True);
- }
-
- static int expect (master, expected, buf)
- int master;
- char **expected;
- char *buf;
- {
- int n, m;
- char **s;
- int initialSegment;
- int result;
-
- n = 0;
- buf[0] = 0;
- while (1) {
- if (n >= BUFSIZE-1) {
- return False;
- }
- m = read(master, buf+n, BUFSIZE-1-n);
- if (m < 0) {
- return False;
- }
- n += m;
- buf[n] = 0;
- initialSegment = 0;
- for (s = expected; **s != 0; s++) {
- result = match(buf, *s);
- if (result == 2) return True;
- initialSegment = initialSegment || result == 1;
- }
- if (!initialSegment) return False;
- }
- }
-
- static int match (str, pat)
- char *str;
- char *pat;
- {
- int result;
-
- for (; *str && *pat && *pat != '*'; str++, pat++)
- if (tolower(*str) != tolower(*pat)) return 0;
- if (*str == 0) return *pat == 0 ? 2 : 1;
- if (*pat == 0) return 0;
- for (; *str; str++) if ((result = match(str, pat+1)) != 0) return result;
- return 0;
- }
-
- static void getemess (master, expected, buf)
- int master;
- char **expected;
- char *buf;
- {
- int n, m;
- char **s;
- char *p, *q;
-
- n = strlen(buf);
- while (1) {
- for (s = expected; **s != 0; s++) {
- for (p = buf; *p; p++) {
- if (match(p, *s) == 2) {
- *p = 0;
- for (q = buf; *q; q++) if (*q == '\n') *q = ' ';
- return;
- }
- }
- }
- if (n >= BUFSIZE-1) {
- return;
- }
- m = read(master, buf+n, BUFSIZE+1-n);
- if (m < 0) {
- return;
- }
- n += m;
- buf[n] = 0;
- }
- }
-
- void writestring (int fd,char *s)
- {
- int l;
-
- l = strlen (s);
- write (fd, s, l);
- }
-
- static int findpty (char **slave)
- {
- int master;
- static char line[12] = "/dev/ptyXX";
- void *dirp;
- struct DIRECT *dp;
-
- dirp = (void *)opendir("/dev");
- if (!dirp) return(-1);
- while ((dp = readdir(dirp)) != NULL) {
- if (strncmp(dp->d_name, "pty", 3) == 0 && strlen(dp->d_name) == 5) {
- line[8] = dp->d_name[3];
- line[9] = dp->d_name[4];
- if ((master = open(line, O_RDWR)) >= 0) {
- line[5] = 't';
- *slave = line;
- closedir(dirp);
- DLINE;
- return (master);
- }
- }
- }
- closedir(dirp);
- return (-1);
- }
- #else
- int dummy_chgpasswd(void)
- {
- return(0);
- }
- #endif
-