home *** CD-ROM | disk | FTP | other *** search
/ Serving the Web / ServingTheWeb1995.disc1of1.iso / linux / slacksrce / contrib / samba / samba-1.8 / samba-1 / samba-1.8.05 / chgpasswd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-27  |  11.0 KB  |  422 lines

  1. #ifdef ALLOW_CHANGE_PASSWORD
  2. /* fork a child process to exec passwd and write to its
  3. * tty to change a users password. This is running as the
  4. * user who is attempting to change the password.
  5. */
  6.  
  7. /* 
  8.  * This code was copied/borrowed and stolen from various sources.
  9.  * The primary source was the poppasswd.c from the authors of POPMail. This software
  10.  * was included as a client to change passwords using the 'passwd' program
  11.  * on the remote machine.
  12.  *
  13.  * It has been dissected and recreated in a form that allows passwd changing for
  14.  * a valid user (user is already validated BEFORE this routine is run). It compares
  15.  * the user name to those in the LOCAL password file and, if they are found, it 
  16.  * runs 'passwd.'  If not, however, it assumes, since the person has already been 
  17.  * validated, that they are an NIS user and it uses 'yppasswd.' 
  18.  *
  19.  * This routine is called by set_user_password() in password.c only if ALLOW_PASSWORD_CHANGE
  20.  * is defined in the compiler directives located in the Makefile.
  21.  *
  22.  *
  23.  * This code has been hacked by Bob Nance (nance@niehs.nih.gov) and Evan Patterson
  24.  * (patters2@niehs.nih.gov) at the National Institute of Environmental Health Sciences
  25.  * and rights to modify, distribute or incorporate this change to the CAP suite or
  26.  * using it for any other reason are granted, so long as this disclaimer is left intact.
  27.  */
  28.  
  29. #include "includes.h"
  30. #include "loadparm.h"
  31.  
  32. #define MINPASSWDLENGTH 5
  33. #define BUFSIZE 512
  34.  
  35. #define DLINE DEBUG(5,("DLINE %s %d\n",__FILE__,__LINE__))
  36.  
  37. extern int DEBUGLEVEL;
  38. static char *P1[] =
  39.    {"Old password:",
  40.        "Old NIS password:",
  41.     "Changing password for *.\nOld password:",
  42.     "Changing password for * on *.\nOld password:",
  43.     "Changing NIS password for * on *.\nOld password:",
  44.     "Changing password for *\n*'s Old password:",
  45.     "Changing password for *\nOld password: ",     /* for ULTRIX */
  46.     "Changing password for *.\n\nNew password:",   /* for OSF/1 */
  47.     "Changing NIS password for *\nOld NIS password:",
  48.     ""};
  49.  
  50. static char *P2[] =
  51.    {"\nRe-enter new password:",
  52.     "\nRetype new password:",
  53.     "\nEnter the new password again:",
  54.     "\n*Re-enter *'s new password:",
  55.     "\nVerify:",
  56.     "\nVerify: ",              /* for ULTRIX */
  57.     "\nWarning, only the first 8 characters of the password are significant.\nVerify: ",      /* for ULTRIX */
  58.     ""};
  59.     
  60. static char *P4[] =
  61.    {"\n",
  62.     "NIS entry changed on *\n",
  63.     "\nNIS passwd changed on *\n",
  64.     ""};
  65.  
  66. /* P5 was added to allow users to enter passwords that contained all lower-
  67.    case letters and no punctuation or numbers. This is not the best way of
  68.    doing it, but it allows Mac users to use simple passwords. We felt that,
  69.    since no users had interactive access to the machine, we weren't comprom-
  70.    izing system security TOO much. 
  71. */
  72.  
  73. static char *P5[] =
  74. {"\nPlease don't use an all-lower case password.\nUnusual capitalization, control characters or digits are suggested.\nNew password:",""};
  75.  
  76. static int findpty (char **slave);
  77. static int talktochild(int master,char *oldpass,char *newpass,char *emess);
  78. static int dochild(int master,char *slavedev,char *name,char *oldpass,char *newpass);
  79. static int expect(int master,char **expected,char *buf);
  80. static void getemess (int master,char **expected,char *buf);
  81. static void writestring (int fd,char *s);
  82. static int match(char *str,char *pat);
  83.  
  84.  
  85.  
  86.  
  87. BOOL chgpasswd(name,oldpass,newpass)
  88.      char *name, *oldpass, *newpass;
  89. {
  90.   char emess[255];
  91.   char *slavedev;
  92.   struct passwd *getpwnam();
  93.   int master;
  94.   pid_t pid, wpid;
  95.   int wstat;
  96.   int putpwent();
  97.   
  98.   strlower(name); 
  99.   DEBUG(3,("Password change for user: %s\n",name));
  100.   
  101.   /* Take the passed information and test it for minimum criteria */
  102.   /* Minimum password length */
  103.   DLINE;
  104.   if (strlen(newpass) < MINPASSWDLENGTH) /* too short, must be at least MINPASSWDLENGTH */ 
  105.     {
  106.       DEBUG(2,("Password Change: %s, New password is shorter than MINPASSWDLENGTH\n",name));
  107.       return (False);        /* inform the user */
  108.     }
  109.   
  110.   /* Password is same as old password */
  111.   DLINE;
  112.   if (strncmp(oldpass,newpass,8) == 0) /* don't allow same password */
  113.     {
  114.       DEBUG(2,("Password Change: %s, New password is same as old\n",name)); /* log the attempt */
  115.       return (False);        /* inform the user */
  116.     }
  117.  
  118.   /* That done, let's attempt to actually change the password */
  119.   /* allocate a pseudo-terminal device */
  120.   DLINE;
  121.   if ((master = findpty (&slavedev)) < 0)
  122.     {
  123.       DEBUG(3,("Cannot Allocate pty for password change: %s",name));
  124.       return(False);
  125.     }
  126.   DLINE;
  127.   if ((pid = fork()) < 0)
  128.     {
  129.       DEBUG(3,("Cannot fork() child for password change: %s",name));
  130.       return(False);
  131.     }
  132.  
  133.   DLINE;
  134.  
  135.   /* we now have a pty */
  136.   if (pid > 0){            /* This is the parent process */
  137.   DLINE;
  138.     if (talktochild (master, oldpass, newpass, emess) == False)
  139.       {
  140.     DEBUG(3,("Child failed to change password: %s\n",name));
  141.     return(False);
  142.       }
  143.   DLINE;
  144.     if ((wpid = waitpid (pid, &wstat, 0)) < 0) {
  145.       DEBUG(3,("The process is no longer waiting!\n\n"));
  146.       return(False);
  147.     }
  148.     if (pid != wpid) {
  149.       DEBUG(3,("We were waiting for the wrong process ID\n"));    
  150.       return(False);
  151.     }
  152.     if (WIFEXITED (wstat) == 0) {
  153.       DEBUG(3,("The process exited while we were waiting\n"));
  154.       return(False);
  155.     }
  156.     if (WEXITSTATUS (wstat) != 0) {
  157.       DEBUG(3,("The status of the process exiting was incorrect\n"));
  158.       return(False);
  159.     }
  160.   }
  161.   else                /* CHILD */
  162.     {
  163.       DLINE;
  164.       dochild (master, slavedev, name, oldpass, newpass);
  165.     }
  166.   DEBUG(3,("Password change successful for user %s\n",name));
  167.   return (True);
  168. }
  169.  
  170.  
  171. static int dochild (master, slavedev, name, oldpass, newpass)
  172.      int master;
  173.      char *slavedev, *name, *oldpass, *newpass;
  174. {
  175.   char *command, *dummy;
  176.   int slave;
  177.   struct termios stermios;
  178.   char *passwordprogram=lp_passwd_program();
  179.   char *shortname="passwd";
  180.     
  181.   command="";
  182.   dummy="";
  183.   passwordprogram = lp_passwd_program();
  184.  
  185.   /* Start new session - gets rid of controlling terminal. */
  186.   if (setsid() < 0) {
  187.     DEBUG(3,("Weirdness, couldn't let go of controlling terminal\n"));
  188.     return(False);
  189.   }
  190.  
  191.   /* Open slave pty and acquire as new controlling terminal. */
  192.   if ((slave = open(slavedev, O_RDWR)) < 0) {
  193.     DEBUG(3,("More weirdness, could not read/write to new pty\n"));
  194.     return(False);
  195.   }
  196.   ioctl(slave,TIOCSCTTY,0);
  197.  
  198.   /* Close master. */
  199.   close(master);
  200.  
  201.   /* Make slave stdin/out/err of child. */
  202.  
  203.   if (dup2(slave, STDIN_FILENO) != STDIN_FILENO) {
  204.     DEBUG(3,("Could not re-direct stdin\n"));
  205.     return(False);
  206.   }
  207.   if (dup2(slave, STDOUT_FILENO) != STDOUT_FILENO) {
  208.     DEBUG(3,("Could not re-direct stdout\n"));
  209.     return(False);
  210.   }
  211.   if (dup2(slave, STDERR_FILENO) != STDERR_FILENO) {
  212.     DEBUG(3,("Could not re-direct stderr\n"));
  213.     return(False);
  214.   }
  215.   if (slave > 2) close(slave);
  216.  
  217.   /* Set proper terminal attributes - no echo, canonical input processing,
  218.      no map NL to CR/NL on output. */
  219.  
  220.   if (tcgetattr(0, &stermios) < 0) {
  221.     DEBUG(3,("could not read default terminal attributes on pty\n"));
  222.     return(False);
  223.   }
  224.   stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
  225.   stermios.c_lflag |= ICANON;
  226.   stermios.c_oflag &= ~(ONLCR);
  227.   if (tcsetattr(0, TCSANOW, &stermios) < 0) {
  228.     DEBUG(3,("could not set attributes of pty\n"));
  229.     return(False);
  230.   }
  231.  
  232.   /* execl() password-change application */
  233.   command=NULL;
  234.   if (execl(passwordprogram, shortname, name, (char*)0) < 0) {
  235.     DEBUG(3,("Bad status returned from %s",command));
  236.     return(False);
  237.   }            
  238.   return(True);
  239. }
  240.  
  241. static int talktochild (master, oldpass, newpass, emess)
  242.      int master;
  243.      char *oldpass, *newpass, *emess;
  244. {
  245.   char buf[BUFSIZE];
  246.   char pswd[BUFSIZE+1];
  247.   
  248.   *emess = 0;
  249.   sleep(1);
  250.   if (!expect(master, P1, buf)) /* Compare what is on the pty with what is stored in P1 */
  251. {
  252.   DEBUG(3,("P1 not correct: %s",buf));
  253.   getemess(master, P1, buf);
  254.   strcpy(emess,buf);
  255.   DEBUG(3,("P1 not correct: %s",emess));
  256.   return (False);
  257. }
  258.   sleep(1);
  259.   sprintf(pswd, "%s\n", newpass);
  260.   writestring(master, pswd);
  261.  
  262.   if (!expect(master, P2, buf)) 
  263.     {
  264.       /* expect CLEARS buf and gets a new copy of it from the TTY */
  265.       if (strncmp(P5[0],buf,strlen(buf))!=0) 
  266.     { 
  267.       DEBUG(3,("P5 and P3 not correct \n\n"));
  268.       return (False);
  269.     } 
  270.       else 
  271.     {
  272.       writestring(master, pswd);
  273.       sleep(1);
  274.             if( !expect(master,P5,buf) && (strncmp(P5[0],buf,strlen(buf))!=0)) 
  275.         {
  276.           DEBUG(3,("P5 not correct\n"));
  277.           return (False);
  278.         }
  279.       writestring(master, pswd);
  280.       sleep(1);
  281.       if( !expect(master,P5,buf) && (strncmp(P5[0],buf,strlen(buf))!=0))
  282.         {
  283.           DEBUG(3,("P5 not correct\n"));
  284.           return (False);
  285.         }
  286.       writestring(master,pswd);      
  287.       sleep(1);
  288.       if(!expect(master,P2,buf) && (strncmp(P5[0],buf,strlen(buf))!=0))
  289.         {
  290.           DEBUG(3,("P2 not correct\n"));
  291.           return (False);
  292.         }
  293.     }
  294.     }
  295.   writestring(master, pswd);
  296.   sleep(1);
  297.   if (!expect(master, P4, buf)) 
  298.     {
  299.       DEBUG(3,("P4 not correct: %s\n",buf));
  300.       return (False);
  301.     }
  302.   return (True);
  303. }
  304.  
  305. static int expect (master, expected, buf)
  306.      int master;
  307.      char **expected;
  308.      char *buf;
  309. {
  310.   int n, m;
  311.   char **s;
  312.   int initialSegment;
  313.   int result;
  314.  
  315.   n = 0;
  316.   buf[0] = 0;
  317.   while (1) {
  318.     if (n >= BUFSIZE-1) {
  319.       return False;
  320.     }
  321.     m = read(master, buf+n, BUFSIZE-1-n);
  322.     if (m < 0) {
  323.       return False;
  324.     }
  325.     n += m;
  326.     buf[n] = 0;
  327.     initialSegment = 0;
  328.     for (s = expected; **s != 0; s++) {
  329.       result = match(buf, *s);
  330.       if (result == 2) return True;
  331.       initialSegment = initialSegment || result == 1; 
  332.     }
  333.     if (!initialSegment) return False;
  334.   }
  335. }
  336.  
  337. static int match (str, pat)
  338.      char *str;
  339.      char *pat;
  340. {
  341.   int result;
  342.   
  343.   for (; *str && *pat && *pat != '*'; str++, pat++) 
  344.     if (tolower(*str) != tolower(*pat)) return 0;
  345.   if (*str == 0) return *pat == 0 ? 2 : 1;
  346.   if (*pat == 0) return 0;
  347.   for (; *str; str++) if ((result = match(str, pat+1)) != 0) return result;
  348.   return 0; 
  349. }
  350.  
  351. static void getemess (master, expected, buf)
  352.      int master;
  353.      char **expected;
  354.      char *buf;
  355. {
  356.   int n, m;
  357.   char **s;
  358.   char *p, *q;
  359.   
  360.   n = strlen(buf);
  361.   while (1) {
  362.     for (s = expected; **s != 0; s++) {
  363.       for (p = buf; *p; p++) {
  364.     if (match(p, *s) == 2) {
  365.       *p = 0;
  366.       for (q = buf; *q; q++) if (*q == '\n') *q = ' ';
  367.       return;
  368.     }
  369.       }
  370.     }
  371.     if (n >= BUFSIZE-1) {
  372.       return;
  373.     }
  374.     m = read(master, buf+n, BUFSIZE+1-n);
  375.     if (m < 0) {
  376.       return;
  377.     }
  378.     n += m;
  379.     buf[n] = 0;
  380.   }
  381. }
  382.  
  383. void writestring (int fd,char *s)
  384. {
  385.   int l;
  386.   
  387.   l = strlen (s);
  388.   write (fd, s, l);
  389. }
  390.  
  391. static int findpty (char **slave)
  392. {
  393.   int master;
  394.   static char line[12] = "/dev/ptyXX";
  395.   void *dirp;
  396.   struct DIRECT *dp;
  397.   
  398.   dirp = (void *)opendir("/dev");
  399.   if (!dirp) return(-1);
  400.   while ((dp = readdir(dirp)) != NULL) {
  401.     if (strncmp(dp->d_name, "pty", 3) == 0 && strlen(dp->d_name) == 5) {
  402.       line[8] = dp->d_name[3];
  403.       line[9] = dp->d_name[4];
  404.       if ((master = open(line, O_RDWR)) >= 0) {
  405.     line[5] = 't';
  406.     *slave = line;
  407.     closedir(dirp);
  408.   DLINE;
  409.     return (master);
  410.       }
  411.     }
  412.   }
  413.   closedir(dirp);
  414.   return (-1);
  415. }
  416. #else
  417. int dummy_chgpasswd(void)
  418. {
  419.   return(0);
  420. }
  421. #endif
  422.