home *** CD-ROM | disk | FTP | other *** search
/ ftp.qualcomm.com / 2014.06.ftp.qualcomm.com.tar / ftp.qualcomm.com / eudora / servers / unix / password / pwserve-4 < prev    next >
Text File  |  1997-03-26  |  22KB  |  768 lines

  1. /*
  2.  * poppassd.c
  3.  *
  4.  * John Norstad
  5.  * Northwestern University
  6.  * j-norstad@nwu.edu
  7.  *
  8.  * IMPORTANT NOTE:
  9.  *
  10.  * Please do not write to me asking for help getting this program running
  11.  * on your system. You are on your own. If you send me email about this
  12.  * program, I will not read it, and I will not reply to it. Sorry, but the
  13.  * only alternative is to not distribute it at all.
  14.  *
  15.  * Based on earlier versions by Roy Smith <roy@nyu.edu> and Daniel
  16.  * L. Leavitt <dll.mitre.org>.
  17. #!/bin/sh
  18. # This is a shell archive (shar 3.32)
  19. # made 01/28/1994 20:35 UTC by sdorner@ux1.cso.uiuc.edu
  20. # Source directory /cso/staff/sdorner
  21. #
  22. # existing files WILL be overwritten
  23. #
  24. # This shar contains:
  25. # length  mode       name
  26. # ------ ---------- ------------------------------------------
  27. #    345 -rw-r--r-- poppassd/Makefile
  28. #    138 -rw-r--r-- poppassd/README
  29. #  18598 -rw-r--r-- poppassd/poppassd.c
  30. #
  31. if touch 2>&1 | fgrep 'amc' > /dev/null
  32.  then TOUCH=touch
  33.  else TOUCH=true
  34. fi
  35. # ============= poppassd/Makefile ==============
  36. if test ! -d 'poppassd'; then
  37.     echo "x - creating directory poppassd"
  38.     mkdir 'poppassd'
  39. fi
  40. echo "x - extracting poppassd/Makefile (Text)"
  41. sed 's/^X//' << 'SHAR_EOF' > poppassd/Makefile &&
  42. XBINDIR = /usr/etc
  43. XLIBDIR = 
  44. XCFLAGS = -g
  45. XLFLAGS = -g
  46. XCCM = cc -Em
  47. X
  48. XOBJECTS = poppassd.o
  49. XLIBS =
  50. X
  51. Xpoppassd: $(OBJECTS)
  52. X    cc -o poppassd $(LFLAGS) $(OBJECTS) $(LIBS)
  53. X
  54. Xinstall: poppassd
  55. X    install -g bin -o root -m 500 poppassd $(BINDIR)
  56. X
  57. Xclean:
  58. X    rm -f *.o *~* core Makefile.new Makefile.bak poppassd
  59. X
  60. Xpoppassd.o: poppassd.c
  61. X    cc -c $(CFLAGS) poppassd.c
  62. SHAR_EOF
  63. $TOUCH -am 0128143394 poppassd/Makefile &&
  64. chmod 0644 poppassd/Makefile ||
  65. echo "restore of poppassd/Makefile failed"
  66. set `wc -c poppassd/Makefile`;Wc_c=$1
  67. if test "$Wc_c" != "345"; then
  68.     echo original size 345, current size $Wc_c
  69. fi
  70. # ============= poppassd/README ==============
  71. echo "x - extracting poppassd/README (Text)"
  72. sed 's/^X//' << 'SHAR_EOF' > poppassd/README &&
  73. Xpoppassd is a password change server for Eudora and NUPOP.
  74. XSee the poppassd.c source file for more details and
  75. Xinstallation instructions.
  76. SHAR_EOF
  77. $TOUCH -am 0128143394 poppassd/README &&
  78. chmod 0644 poppassd/README ||
  79. echo "restore of poppassd/README failed"
  80. set `wc -c poppassd/README`;Wc_c=$1
  81. if test "$Wc_c" != "138"; then
  82.     echo original size 138, current size $Wc_c
  83. fi
  84. # ============= poppassd/poppassd.c ==============
  85. echo "x - extracting poppassd/poppassd.c (Text)"
  86. sed 's/^X//' << 'SHAR_EOF' > poppassd/poppassd.c &&
  87. X/*
  88. X * poppassd.c
  89. X *
  90. X * A Eudora and NUPOP change password server.
  91. X *
  92. X * John Norstad
  93. X * Academic Computing and Network Services
  94. X * Northwestern University
  95. X * j-norstad@nwu.edu
  96. X *
  97. X * Based on earlier versions by Roy Smith <roy@nyu.edu> and Daniel
  98. X * L. Leavitt <dll.mitre.org>.
  99. X * 
  100. X * Doesn't actually change any passwords itself.  It simply listens for
  101. X * incoming requests, gathers the required information (user name, old
  102. X * password, new password) and executes /bin/passwd, talking to it over
  103. X * a pseudo-terminal pair.  The advantage of this is that we don't need
  104. X * to have any knowledge of either the password file format (which may
  105. X * include dbx files that need to be rebuilt) or of any file locking
  106. X * protocol /bin/passwd and cohorts may use (and which isn't documented).
  107. X *
  108. X * The current version has been tested at NU under SunOS release 4.1.2 
  109. X * and 4.1.3, and under HP-UX 8.02 and 9.01. We have tested the server 
  110. X * with both Eudora 1.3.1 and NUPOP 2.0.
  111. X *
  112. X * Other sites report that this version also works under AIX and NIS,
  113. X * and with PC Eudora.
  114. X *
  115. X * Note that unencrypted passwords are transmitted over the network.  If
  116. X * this bothers you, think hard about whether you want to implement the
  117. X * password changing feature.  On the other hand, it's no worse than what
  118. X * happens when you run /bin/passwd while connected via telnet or rlogin.
  119. X * Well, maybe it is, since the use of a dedicated port makes it slightly
  120. X * easier for a network snooper to snarf passwords off the wire.
  121. X *
  122. X * NOTE: In addition to the security issue outlined in the above paragraph,
  123. X * you should be aware that this program is going to be run as root by
  124. X * ordinary users and it mucks around with the password file.  This should
  125. X * set alarms off in your head.  I think I've devised a pretty foolproof
  126. X * way to ensure that security is maintained, but I'm no security expert and
  127. X * you would be a fool to install this without first reading the code and
  128. X * ensuring yourself that what I consider safe is good enough for you.  If
  129. X * something goes wrong, it's your fault, not mine.
  130. X *
  131. X * The front-end code (which talks to the client) is directly 
  132. X * descended from Leavitt's original version.  The back-end pseudo-tty stuff 
  133. X * (which talks to /bin/password) is directly descended from Smith's
  134. X * version, with changes for SunOS and HP-UX by Norstad (with help from
  135. X * sample code in "Advanced Programming in the UNIX Environment"
  136. X * by W. Richard Stevens). The code to report /bin/passwd error messages
  137. X * back to the client in the final 500 response, and a new version of the
  138. X * code to find the next free pty, is by Norstad.
  139. X *        
  140. X * Should be owned by root, and executable only by root.  It can be started
  141. X * with an entry in /etc/inetd.conf such as the following:
  142. X *
  143. X * poppassd stream tcp nowait root /usr/local/bin/poppassd poppassd
  144. X * 
  145. X * and in /etc/services:
  146. X * 
  147. X * poppassd    106/tcp
  148. X *
  149. X * Logs to the local2 facility. Should have an entry in /etc/syslog.conf
  150. X * like the following:
  151. X *
  152. X * local2.err    /var/adm/poppassd-log
  153. X */
  154. X/* Modification history.
  155. X *
  156. X * 06/09/93. Version 1.0.
  157. X *
  158. X * 06/29/93. Version 1.1.
  159. X * Include program name 'poppassd' and version number in initial 
  160. X *    hello message.
  161. X * Case insensitive command keywords (user, pass, newpass, quit).
  162. X *    Fixes problem reported by Raoul Schaffner with PC Eudora.
  163. X * Read 'quit' command from client instead of just terminating after 
  164. X *    password change.
  165. X * Add new code for NIS support (contributed by Max Caines).
  166. X *
  167. X * 08/31/93. Version 1.2.
  168. X * Generalized the expected string matching to solve several problems
  169. X *    with NIS and AIX. The new "*" character in pattern strings
  170. X *    matches any sequence of 0 or more characters.
  171. X * Fix an error in the "getemess" function which could cause the
  172. X *    program to hang if more than one string was defined in the
  173. X *    P2 array.
  174. X */
  175. X
  176. X/* Steve Dorner's description of the simple protocol:
  177. X *
  178. X * The server's responses should be like an FTP server's responses; 
  179. X * 1xx for in progress, 2xx for success, 3xx for more information
  180. X * needed, 4xx for temporary failure, and 5xx for permanent failure.  
  181. X * Putting it all together, here's a sample conversation:
  182. X *
  183. X *   S: 200 hello\r\n
  184. X *   E: user yourloginname\r\n
  185. X *   S: 300 please send your password now\r\n
  186. X *   E: pass yourcurrentpassword\r\n
  187. X *   S: 200 My, that was tasty\r\n
  188. X *   E: newpass yournewpassword\r\n
  189. X *   S: 200 Happy to oblige\r\n
  190. X *   E: quit\r\n
  191. X *   S: 200 Bye-bye\r\n
  192. X *   S: <closes connection>
  193. X *   E: <closes connection>
  194. X */
  195. X#define VERSION "1.2"
  196. X
  197. X#define SUCCESS 1
  198. X#define FAILURE 0
  199. X#define BUFSIZE 512
  200. X
  201. X#include <sys/types.h>
  202. X#include <sys/stat.h>
  203. X#include <sys/wait.h>
  204. X#include <unistd.h>
  205. X#include <fcntl.h>
  206. X#include <syslog.h>
  207. X#include <stdlib.h>
  208. X#include <stdio.h>
  209. X#include <ctype.h>
  210. X#include <strings.h>
  211. X#include <errno.h>
  212. X#include <varargs.h>
  213. X#include <pwd.h>
  214. X#include <string.h>
  215. X#include <termios.h>
  216. X#include <dirent.h>
  217. X
  218. X
  219. X/* Prompt strings expected from the "passwd" command. If you want
  220. X * to port this program to yet another flavor of UNIX, you may need to add
  221. X * more prompt strings here.
  222. X *
  223. X * Each prompt is defined as an array of pointers to alternate 
  224. X * strings, terminated by an empty string. In the strings, '*'
  225. X * matches any sequence of 0 or more characters. Pattern matching
  226. X * is case-insensitive.
  227. X */
  228. X
  229. Xstatic char *P1[] =
  230. X   {"Old password:",
  231. X    "Changing password for *.\nOld password:",
  232. X    "Changing password for * on *.\nOld password:",
  233. X    "Changing NIS password for * on *.\nOld password:",
  234. X    "Changing password for *\n*'s Old password:",
  235. X    ""};
  236. X
  237. Xstatic char *P2[] =
  238. X   {"\nNew password:",
  239. X    "\n*'s New password:",
  240. X    ""};
  241. X
  242. Xstatic char *P3[] =
  243. X   {"\nRe-enter new password:",
  244. X    "\nRetype new password:",
  245. X    "\nEnter the new password again:",
  246. X    "\n*Re-enter *'s new password:",
  247. X    "\nVerify:",
  248. X    ""};
  249. X    
  250. Xstatic char *P4[] =
  251. X   {"\n",
  252. X    "NIS entry changed on *\n",
  253. X    ""};
  254. X
  255. X
  256. Xmain (argc, argv)
  257. Xint argc;
  258. Xchar *argv[];
  259. X{
  260. X     char line[BUFSIZE];
  261. X     char user[BUFSIZE];
  262. X     char oldpass[BUFSIZE];
  263. X     char newpass[BUFSIZE];
  264. X     char emess[BUFSIZE];
  265. X     char *slavedev;
  266. X     struct passwd *pw, *getpwnam();
  267. X     int c, master;
  268. X     pid_t pid, wpid;
  269. X     int wstat;
  270. X     
  271. X     *user = *oldpass = *newpass = 0;
  272. X     
  273. X     if (openlog ("poppassd", LOG_PID, LOG_LOCAL2) < 0)
  274. X     {
  275. X      WriteToClient ("500 Can't open syslog.");
  276. X           exit (1);
  277. X     }
  278. X     
  279. X     WriteToClient ("200 poppassd v%s hello, who are you?", VERSION);
  280. X     ReadFromClient (line);
  281. X     sscanf (line, "user %s", user) ;
  282. X     if (strlen (user) == 0)
  283. X     {
  284. X      WriteToClient ("500 Username required.");
  285. X      exit(1);
  286. X     }
  287. X
  288. X     WriteToClient ("200 your password please.");
  289. X     ReadFromClient (line);
  290. X     sscanf (line, "pass %s", oldpass) ;
  291. X     if (strlen (oldpass) == 0)
  292. X     {
  293. X      WriteToClient ("500 Password required.");
  294. X      exit(1);
  295. X     }
  296. X     
  297. X     if ((pw = getpwnam (user)) == NULL)
  298. X     {
  299. X      WriteToClient ("500 Unknown user, %s.", user);
  300. X      exit(1);
  301. X     }
  302. X
  303. X     if (chkPass (user, oldpass, pw) == FAILURE)
  304. X     {
  305. X      WriteToClient ("500 Old password is incorrect.");
  306. X      exit(1);
  307. X     }
  308. X
  309. X     WriteToClient ("200 your new password please.");
  310. X     ReadFromClient (line);
  311. X     sscanf (line, "newpass %s", newpass);
  312. X     
  313. X     /* new pass required */
  314. X     if (strlen (newpass) == 0)
  315. X     {
  316. X      WriteToClient ("500 New password required.");
  317. X      exit(1);
  318. X     }
  319. X     /* get pty to talk to password program */
  320. X     if ((master = findpty (&slavedev)) < 0)
  321. X     {
  322. X      syslog (LOG_ERR, "can't find pty");
  323. X          WriteToClient("500 Server busy - try again later.");
  324. X      exit (1);
  325. X     }
  326. X     
  327. X     /* fork child process to talk to password program */
  328. X     if ((pid = fork()) < 0)     /* Error, can't fork */
  329. X     {
  330. X      syslog (LOG_ERR, "can't fork for passwd: %m");
  331. X      WriteToClient ("500 Server error (can't fork passwd), get help!");
  332. X      exit (1);
  333. X     }
  334. X
  335. X     if (pid)   /* Parent */
  336. X     {
  337. X      sleep (1);    /* Make sure child is ready.  Is this really needed? */
  338. X      if (talktochild (master, user, oldpass, newpass, emess) == FAILURE)
  339. X      {
  340. X           syslog (LOG_ERR, "failed attempt by %s", user);
  341. X           if (*emess == '\0') {
  342. X              WriteToClient ("500 Unable to change password." );
  343. X               } else {
  344. X          WriteToClient ("500 %s", emess);
  345. X               }
  346. X           exit(1);
  347. X      }
  348. X
  349. X      if ((wpid = waitpid (pid, &wstat, 0)) < 0)
  350. X      {
  351. X           syslog (LOG_ERR, "wait for /bin/passwd child failed: %m");
  352. X           WriteToClient ("500 Server error (wait failed), get help!");
  353. X           exit (1);
  354. X      }
  355. X
  356. X      if (pid != wpid)
  357. X      {
  358. X           syslog (LOG_ERR, "wrong child (/bin/passwd waited for!");
  359. X           WriteToClient ("500 Server error (wrong child), get help!");
  360. X           exit (1);
  361. X      }
  362. X
  363. X      if (WIFEXITED (wstat) == 0)
  364. X      {
  365. X           syslog (LOG_ERR, "child (/bin/passwd) killed?");
  366. X           WriteToClient ("500 Server error (funny wstat), get help!");
  367. X           exit (1);
  368. X      }
  369. X
  370. X      if (WEXITSTATUS (wstat) != 0)
  371. X      {
  372. X           syslog (LOG_ERR, "child (/bin/passwd) exited abnormally");
  373. X           WriteToClient ("500 Server error (abnormal exit), get help!");
  374. X           exit (1);
  375. X      }
  376. X
  377. X      syslog (LOG_ERR, "password changed for %s", user);
  378. X      WriteToClient ("200 Password changed, thank-you.");
  379. X
  380. X          ReadFromClient (line);
  381. X      if (strncmp(line, "quit", 4) != 0) {
  382. X          WriteToClient("500 Quit required.");
  383. X        exit (1);
  384. X      }
  385. X      
  386. X      WriteToClient("200 Bye.");
  387. X      exit (0);
  388. X     }
  389. X     else      /* Child */
  390. X     {
  391. X      /*
  392. X       * Become the user trying who's password is being changed.  We're
  393. X       * about to exec /bin/passwd with is setuid root anyway, but this
  394. X       * way it looks to the child completely like it's being run by
  395. X       * the normal user, which makes it do its own password verification
  396. X       * before doing any thing.  In theory, we've already verified the
  397. X       * password, but this extra level of checking doesn't hurt.  Besides,
  398. X       * the way I do it here, if somebody manages to change somebody
  399. X       * else's password, you can complain to your vendor about security
  400. X       * holes, not to me!
  401. X       */
  402. X      setuid (pw->pw_uid);
  403. X      setgid (pw->pw_gid);
  404. X      dochild (master, slavedev, user);
  405. X     }
  406. X}
  407. X
  408. X/*
  409. X * dochild
  410. X *
  411. X * Do child stuff - set up slave pty and execl /bin/passwd.
  412. X *
  413. X * Code adapted from "Advanced Programming in the UNIX Environment"
  414. X * by W. Richard Stevens.
  415. X *
  416. X */
  417. X
  418. Xdochild (master, slavedev, user)
  419. Xint master;
  420. Xchar *slavedev, *user;
  421. X{
  422. X   int slave;
  423. X   struct termios stermios;
  424. X
  425. X   /* Start new session - gets rid of controlling terminal. */
  426. X   
  427. X   if (setsid() < 0) {
  428. X      syslog(LOG_ERR, "setsid failed: %m");
  429. X      return(0);
  430. X   }
  431. X
  432. X   /* Open slave pty and acquire as new controlling terminal. */
  433. X
  434. X   if ((slave = open(slavedev, O_RDWR)) < 0) {
  435. X      syslog(LOG_ERR, "can't open slave pty: %m");
  436. X      return(0);
  437. X   }
  438. X
  439. X   /* Close master. */
  440. X
  441. X   close(master);
  442. X
  443. X   /* Make slave stdin/out/err of child. */
  444. X
  445. X   if (dup2(slave, STDIN_FILENO) != STDIN_FILENO) {
  446. X      syslog(LOG_ERR, "dup2 error to stdin: %m");
  447. X      return(0);
  448. X   }
  449. X   if (dup2(slave, STDOUT_FILENO) != STDOUT_FILENO) {
  450. X      syslog(LOG_ERR, "dup2 error to stdout: %m");
  451. X      return(0);
  452. X   }
  453. X   if (dup2(slave, STDERR_FILENO) != STDERR_FILENO) {
  454. X      syslog(LOG_ERR, "dup2 error to stderr: %m");
  455. X      return(0);
  456. X   }
  457. X   if (slave > 2) close(slave);
  458. X
  459. X   /* Set proper terminal attributes - no echo, canonical input processing,
  460. X      no map NL to CR/NL on output. */
  461. X
  462. X   if (tcgetattr(0, &stermios) < 0) {
  463. X      syslog(LOG_ERR, "tcgetattr error: %m");
  464. X      return(0);
  465. X   }
  466. X   stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
  467. X   stermios.c_lflag |= ICANON;
  468. X   stermios.c_oflag &= ~(ONLCR);
  469. X   if (tcsetattr(0, TCSANOW, &stermios) < 0) {
  470. X      syslog(LOG_ERR, "tcsetattr error: %m");
  471. X      return(0);
  472. X   }
  473. X
  474. X   /* Fork /bin/passwd. */
  475. X
  476. X   if (execl("/bin/passwd", "passwd", user, (char*)0) < 0) {
  477. X      syslog(LOG_ERR, "can't exec /bin/passwd: %m");
  478. X      return(0);
  479. X   }
  480. X}
  481. X
  482. X
  483. X/*
  484. X * findpty()
  485. X *
  486. X * Finds the first available pseudo-terminal master/slave pair.  The master
  487. X * side is opened and a fd returned as the function value.  A pointer to the
  488. X * name of the slave side (i.e. "/dev/ttyp0") is returned in the argument,
  489. X * which should be a char**.  The name itself is stored in a static buffer.
  490. X *
  491. X * A negative value is returned on any sort of error.
  492. X *
  493. X * Modified by Norstad to remove assumptions about number of pty's allocated
  494. X * on this UNIX box.
  495. X */
  496. Xfindpty (slave)
  497. Xchar **slave;
  498. X{
  499. X   int master;
  500. X   static char *line = "/dev/ptyXX";
  501. X   DIR *dirp;
  502. X   struct dirent *dp;
  503. X
  504. X   dirp = opendir("/dev");
  505. X   while ((dp = readdir(dirp)) != NULL) {
  506. X      if (strncmp(dp->d_name, "pty", 3) == 0 && strlen(dp->d_name) == 5) {
  507. X         line[8] = dp->d_name[3];
  508. X         line[9] = dp->d_name[4];
  509. X         if ((master = open(line, O_RDWR)) >= 0) {
  510. X            line[5] = 't';
  511. X            *slave = line;
  512. X            closedir(dirp);
  513. X            return (master);
  514. X         }
  515. X      }
  516. X   }
  517. X   closedir(dirp);
  518. X   return (-1);
  519. X}
  520. X
  521. X/*
  522. X * writestring()
  523. X *
  524. X * Write a string in a single write() system call.
  525. X */
  526. Xwritestring (fd, s)
  527. Xchar *s;
  528. X{
  529. X     int l;
  530. X
  531. X     l = strlen (s);
  532. X     write (fd, s, l);
  533. X}
  534. X
  535. X/*
  536. X * talktochild()
  537. X *
  538. X * Handles the conversation between the parent and child (password program)
  539. X * processes.
  540. X *
  541. X * Returns SUCCESS is the conversation is completed without any problems,
  542. X * FAILURE if any errors are encountered (in which case, it can be assumed
  543. X * that the password wasn't changed).
  544. X */
  545. Xtalktochild (master, user, oldpass, newpass, emess)
  546. Xint master;
  547. Xchar *user, *oldpass, *newpass, *emess;
  548. X{
  549. X     char buf[BUFSIZE];
  550. X     char pswd[BUFSIZE+1];
  551. X     int m, n;
  552. X
  553. X     *emess = 0;
  554. X
  555. X     if (!expect(master, P1, buf)) return FAILURE;
  556. X
  557. X     sprintf(pswd, "%s\n", oldpass);
  558. X     writestring(master, pswd);
  559. X
  560. X     if (!expect(master, P2, buf)) return FAILURE;
  561. X
  562. X     sprintf(pswd, "%s\n", newpass);
  563. X     writestring(master, pswd);
  564. X
  565. X     if (!expect(master, P3, buf)) {
  566. X        getemess(master, P2, buf);
  567. X    strcpy(emess, buf);
  568. X    return FAILURE;
  569. X     }
  570. X
  571. X     writestring(master, pswd);
  572. X
  573. X     if (!expect(master, P4, buf)) return FAILURE;
  574. X
  575. X     return SUCCESS;
  576. X}
  577. X
  578. X/*
  579. X * match ()
  580. X *
  581. X * Matches a string against a pattern. Wild-card characters '*' in
  582. X * the pattern match any sequence of 0 or more characters in the string.
  583. X * The match is case-insensitive.
  584. X *
  585. X * Entry: str = string.
  586. X *        pat = pattern.
  587. X *
  588. X * Exit:  function result =
  589. X *        0 if no match.
  590. X *        1 if the string matches some initial segment of
  591. X *          the pattern.
  592. X *        2 if the string matches the full pattern.
  593. X */
  594. Xmatch (str, pat)
  595. Xchar *str;
  596. Xchar *pat;
  597. X{
  598. X   int result;
  599. X   
  600. X   for (; *str && *pat && *pat != '*'; str++, pat++) 
  601. X      if (tolower(*str) != tolower(*pat)) return 0;
  602. X   if (*str == 0) return *pat == 0 ? 2 : 1;
  603. X   if (*pat == 0) return 0;
  604. X   for (; *str; str++) if ((result = match(str, pat+1)) != 0) return result;
  605. X   return 0; 
  606. X}
  607. X
  608. X/*
  609. X * expect ()
  610. X *
  611. X * Reads 'passwd' command output and compares it to expected output.
  612. X *
  613. X * Entry: master = fid of master pty.
  614. X *      expected = pointer to array of pointers to alternate expected
  615. X *            strings, terminated by an empty string.
  616. X *        buf = pointer to buffer.
  617. X *
  618. X * Exit:  function result = SUCCESS if output matched, FAILURE if not.
  619. X *        buf = the text read from the slave.
  620. X *
  621. X * Text is read from the slave and accumulated in buf. As long as
  622. X * the text accumulated so far is an initial segment of at least 
  623. X * one of the expected strings, the function continues the read.
  624. X * As soon as one of full expected strings has been read, the
  625. X * function returns SUCCESS. As soon as the text accumulated so far
  626. X * is not an initial segment of or exact match for at least one of 
  627. X * the expected strings, the function returns FAILURE.
  628. X */
  629. Xexpect (master, expected, buf)
  630. Xint master;
  631. Xchar **expected;
  632. Xchar *buf;
  633. X{
  634. X     int n, m;
  635. X     char **s;
  636. X     int initialSegment;
  637. X     int result;
  638. X     
  639. X     n = 0;
  640. X     buf[0] = 0;
  641. X     while (1) {
  642. X         if (n >= BUFSIZE-1) {
  643. X       syslog(LOG_ERR, "buffer overflow on read from child");
  644. X       return FAILURE;
  645. X    }
  646. X         m = read(master, buf+n, BUFSIZE-1-n);
  647. X    if (m < 0) {
  648. X       syslog(LOG_ERR, "read error from child: %m");
  649. X       return FAILURE;
  650. X    }
  651. X    n += m;
  652. X    buf[n] = 0;
  653. X    initialSegment = 0;
  654. X        for (s = expected; **s != 0; s++) {
  655. X           result = match(buf, *s);
  656. X       if (result == 2) return SUCCESS;
  657. X       initialSegment = initialSegment || result == 1; 
  658. X    }
  659. X    if (!initialSegment) return FAILURE;
  660. X     }
  661. X}
  662. X
  663. X/*
  664. X * getemess()
  665. X *
  666. X * This function accumulates a 'passwd' command error message issued
  667. X * after the first copy of the password has been sent.
  668. X *
  669. X * Entry: master = fid of master pty.
  670. X *      expected = pointer to array of pointers to alternate expected
  671. X *            strings for first password prompt, terminated by an 
  672. X *            empty string.
  673. X *        buf = pointer to buffer containing text read so far.
  674. X *
  675. X * Exit:  buf = the error message read from the slave.
  676. X *
  677. X * Text is read from the slave and accumulated in buf until the text
  678. X * at the end of the buffer is an exact match for one of the expected
  679. X * prompt strings. The expected prompt string is removed from the buffer,
  680. X * returning just the error message text. Newlines in the error message
  681. X * text are replaced by spaces.
  682. X */
  683. Xgetemess (master, expected, buf)
  684. Xint master;
  685. Xchar **expected;
  686. Xchar *buf;
  687. X{
  688. X   int n, m;
  689. X   char **s;
  690. X   char *p, *q;
  691. X
  692. X   n = strlen(buf);
  693. X   while (1) {
  694. X      for (s = expected; **s != 0; s++) {
  695. X         for (p = buf; *p; p++) {
  696. X            if (match(p, *s) == 2) {
  697. X               *p = 0;
  698. X               for (q = buf; *q; q++) if (*q == '\n') *q = ' ';
  699. X               return;
  700. X            }
  701. X         }
  702. X      }
  703. X      if (n >= BUFSIZE-1) {
  704. X     syslog(LOG_ERR, "buffer overflow on read from child");
  705. X     return;
  706. X      }
  707. X      m = read(master, buf+n, BUFSIZE+1-n);
  708. X      if (m < 0) {
  709. X     syslog(LOG_ERR, "read error from child: %m");
  710. X     return;
  711. X      }
  712. X      n += m;
  713. X      buf[n] = 0;
  714. X   }
  715. X}
  716. X
  717. XWriteToClient (fmt, va_alist)
  718. Xchar *fmt;
  719. Xva_dcl
  720. X{
  721. X    va_list ap;
  722. X    
  723. X    va_start (ap);
  724. X    vfprintf (stdout, fmt, ap);
  725. X    fputs ("\r\n", stdout );
  726. X    fflush (stdout);
  727. X    va_end (ap);
  728. X}
  729. X
  730. XReadFromClient (line)
  731. Xchar *line;
  732. X{
  733. X    char *sp;
  734. X    int i;
  735. X
  736. X    strcpy (line, "");
  737. X    fgets (line, BUFSIZE, stdin);
  738. X    if ((sp = strchr(line, '\n')) != NULL) *sp = '\0'; 
  739. X    if ((sp = strchr(line, '\r')) != NULL) *sp = '\0'; 
  740. X    
  741. X    /* convert initial keyword on line to lower case. */
  742. X    
  743. X    for (sp = line; isalpha(*sp); sp++) *sp = tolower(*sp);
  744. X}
  745. X
  746. Xint chkPass (user, pass, pw)
  747. Xchar *user;
  748. Xchar *pass;
  749. Xstruct passwd *pw;
  750. X{
  751. X     /*  Compare the supplied password with the password file entry */
  752. X     if (strcmp (crypt (pass, pw->pw_passwd), pw->pw_passwd) != 0)
  753. X      return (FAILURE);
  754. X     else 
  755. X      return (SUCCESS);
  756. X}
  757. SHAR_EOF
  758. $TOUCH -am 0128143394 poppassd/poppassd.c &&
  759. chmod 0644 poppassd/poppassd.c ||
  760. echo "restore of poppassd/poppassd.c failed"
  761. set `wc -c poppassd/poppassd.c`;Wc_c=$1
  762. if test "$Wc_c" != "18598"; then
  763.     echo original size 18598, current size $Wc_c
  764. fi
  765. exit 0
  766.