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

  1. Posted-From: The MITRE Corporation, Bedford, MA
  2. To: sdorner@qualcomm.com (Steve Dorner)
  3. From: dll@mitre.org (Daniel L. Leavitt)
  4. Subject: Re: Change password server 
  5. Date: Tue, 10 Nov 92 10:56:29 EST
  6. Sender: dll@mbunix.mitre.org
  7.  
  8.  
  9. Steve,
  10.  
  11.         Here it is.  This is the first such program I've ever written so I'd appreciate
  12. any constructive comments if anyone cares to send me any.  
  13.  
  14. -Dan
  15.  
  16.  
  17. --------------
  18. /* 
  19.  * poppassd.c  Update passwords on the UNIX system from the Eudora "Change Password"
  20.  *             client.  Keeps a log of change attempts in /etc/poppassd.log but 
  21.  *             suppresses recording of passwords given by the client.
  22.  *             
  23.  *             Must be owned by root, and executable only by root.  It can be started 
  24.  *             with an entry in /etc/inetd.conf such as the following:
  25.  *
  26.  *                 poppassd stream tcp nowait root  /usr/local/poppassd/poppassd poppassd
  27.  * 
  28.  *             and in /etc/services:
  29.  * 
  30.  *                 ppassd        106/tcp
  31.  *
  32.  */
  33.  
  34. #include <stdio.h>
  35. #include <string.h>
  36. #include <pwd.h>
  37. #include <signal.h>
  38. #include <unistd.h>
  39. #include <varargs.h>
  40. #include <sys/wait.h>
  41. #include <sys/socket.h>
  42. #include <netinet/in.h>
  43. #include <netdb.h>
  44. #include <sys/types.h>
  45. #include <sys/file.h>
  46. #include <time.h>
  47.  
  48. #define PF_PLATE        "./ptmpXXXXX"   /* original temporary file */
  49. #define PF_TEMP         "./ptmp"        /* lock file */
  50.  
  51. #define PW_CHANGED      0               /* a OK */
  52. #define PW_CANTLOCK     -1              /* error code -- locking failed */
  53. #define PW_CANTOPEN     -2              /* error code -- open failed */
  54. #define PW_CANTRENAME   -3              /* error code -- rename failed */
  55. #define PW_NOCHANGE     -4              /* error code -- no passwd entry */
  56.  
  57. #define SUCCESS 1
  58. #define FAILURE 0
  59. #define BUFSIZE 255
  60. #define MAXARGS 32
  61. #define SUPPRESS 1
  62.  
  63. #define FI_NULL ((FILE *) NULL)                /* NULL file pointer */
  64. #define TI_NULL ((time_t *) NULL)      /* NULL time pointer */
  65.  
  66.  
  67. /*
  68.  * library functions
  69.  */
  70. extern char *mktemp();                  /* makes a temp file name */
  71.  
  72. /*
  73.  * global variables
  74.  */
  75. char *pf_name = "passwd";               /* password file name */
  76. char *pf_tnam;                          /* name of temporary file */
  77. FILE *pf_fp;                            /* pointer to real password file */
  78. FILE *pf_tfp;                           /* pointer to temporary file */
  79. FILE *log;
  80. time_t gNow;
  81. char gDate[BUFSIZE];
  82.  
  83. main (argc, argv)
  84. int argc;
  85. char *argv[];
  86. {
  87.  
  88.         char line[BUFSIZE];
  89.         char user[BUFSIZE];
  90.         char pass[BUFSIZE];
  91.         char newpass[BUFSIZE];
  92.         char logFile[BUFSIZE];
  93.         struct passwd *pw;
  94.  
  95.         chdir( "/etc" );
  96.         sprintf(logFile, "/etc/%s.log", argv[0]);
  97.         strcpy( user, "" );
  98.         strcpy( pass, "" );
  99.         strcpy( newpass, "" );
  100.  
  101.         /*
  102.          * Open the logfile for append
  103.          */
  104.         if ( !( log = fopen( logFile, "a+" )) ) {
  105.                 WriteToClient( "500 Can't open %s.", logFile );
  106.                 exit(1);
  107.         }
  108.         
  109. #if 0
  110.         The server's responses should be like an FTP server's responses; 
  111.         1xx for in progress, 2xx for success, 3xx for more information
  112.         needed, 4xx for temporary failure, and 5xx for permanent failure.  
  113.         Putting it all together, here's a sample conversation:
  114.  
  115.         S: 200 hello\r\n
  116.         E: user yourloginname\r\n
  117.         S: 300 please send your password now\r\n
  118.         E: pass yourcurrentpassword\r\n
  119.         S: 200 My, that was tasty\r\n
  120.         E: newpass yournewpassword\r\n
  121.         S: 200 Happy to oblige\r\n
  122.         E: quit\r\n
  123.         S: 200 Bye-bye\r\n
  124.         S: <closes connection>
  125.         E: <closes connection>
  126. #endif
  127.  
  128.         WhoAreYou();
  129.  
  130.         WriteToClient( "200 hello, who are you?" );
  131.         ReadFromClient( line, 0 );
  132.         sscanf(line, "user %s", user) ;
  133.         if ( strlen(user) == 0 ) {
  134.                 WriteToClient( "500 username required." );
  135.                 exit(1);
  136.         }
  137.  
  138.         WriteToClient( "200 your password please." );
  139.         ReadFromClient( line, SUPPRESS );
  140.         sscanf( line, "pass %s", pass) ;
  141.         if ( strlen(pass) == 0 ) {
  142.                 WriteToClient( "500 password required." );
  143.                 exit(1);
  144.         }
  145.  
  146.         WriteToClient( "200 your new password please." );
  147.         ReadFromClient( line, SUPPRESS );
  148.         sscanf( line, "newpass %s", newpass );
  149.  
  150.         /* new pass required */
  151.         if ( strlen(newpass) == 0 ) {
  152.                 WriteToClient( "500 new password required." );
  153.                 exit(1);
  154.         }
  155.         /* new pass must be 6 char or longer */
  156.         else if ( strlen(newpass) < 6 ) {
  157.                 WriteToClient( "500 New password too short" );
  158.                 exit(1);
  159.         }
  160.         /* new pass must be different from old pass */
  161.         else if ( !strcmp(pass, newpass) ) {
  162.                 WriteToClient( "500 New password must be different." );
  163.                 exit(1);
  164.         }
  165.  
  166.         /* test for valid user */
  167.         if ( (pw=getpwnam(user)) == NULL ) {
  168.                 WriteToClient( "500 Unknown user, %s.", user);
  169.                 exit(1);
  170.         }
  171.  
  172.         /* authenticate user */
  173.         if ( chkPass( user, pass, pw ) == FAILURE ) {
  174.                 WriteToClient( "500 Authentication failure.");
  175.                 exit(1);
  176.         }
  177.                 
  178.         if ( setPass( user, pass, newpass, pw ) == FAILURE ) { 
  179.                 WriteToClient( "500 Unable to change password." );
  180.                 exit(1);
  181.         }
  182.  
  183.         WriteToClient( "200 Password changed, thank-you." );
  184.         return(1);
  185. }
  186.  
  187.  
  188. WhoAreYou()
  189. {
  190.         struct sockaddr_in bobby;
  191.         int   bobbyLen = sizeof(struct sockaddr);
  192.         struct passwd *pw;
  193.         char   *inet_ntoa();
  194.         char   *ttyname();
  195.  
  196.         fputs( "\n", log );
  197.  
  198.         if (isatty(fileno(stdin))) {
  199.                 pw = getpwuid(getuid());
  200.                 WriteLog( "Connection on %s by %s",
  201.                         ttyname(fileno(stdin)), pw->pw_name);
  202.         }
  203.  
  204.         else if (lseek(fileno(stdin), 0, L_INCR) >= 0) {
  205.                 pw = getpwuid(getuid());
  206.                 WriteLog( "Connection on FILE by %s", pw->pw_name);
  207.         }
  208.  
  209.         else if (getpeername(fileno(stdin), (struct sockaddr *)&bobby, 
  210.                         &bobbyLen) < 0) {
  211.                 pw = getpwuid(getuid());
  212.                 WriteLog( "Connection on PIPE by %s", pw->pw_name);
  213.         }
  214.  
  215.         else {
  216. #               if defined(sparc) && __GNUC__ == 1 
  217.                         WriteLog( "NET connection from  %s", 
  218.                                 inet_ntoa(&bobby.sin_addr));
  219. #               else
  220.                         WriteLog( "NET connection from %s", 
  221.                                 inet_ntoa(bobby.sin_addr));
  222. #               endif
  223.         }
  224. }
  225.  
  226. WriteToClient( va_alist )
  227. va_dcl
  228. {
  229.         va_list ap;
  230.         char *fmt;      
  231.         char *args[MAXARGS];
  232.         int argno = 0;
  233.         char string[BUFSIZE];
  234.         
  235.         UpdateTime( );
  236.  
  237.         va_start( ap );
  238.         fmt = va_arg(ap, char *);
  239.         while ((args[argno++] = va_arg(ap, char *)) != (char *)0)
  240.                     ;
  241.  
  242.         vfprintf(stdout, fmt, args);
  243.         fputs("\r\n", stdout );
  244.         fflush(stdout);
  245.  
  246.         vsprintf(string, fmt, args);
  247.         WriteLog( "Server> %s", string );
  248.  
  249.         va_end( ap );
  250. }
  251.  
  252. ReadFromClient( line , suppress)
  253. char *line;
  254. int suppress;
  255. {
  256.         char *sp;
  257.         int i;
  258.  
  259.         UpdateTime();
  260.         strcpy(line, "" );
  261.         fgets( line, BUFSIZE, stdin );
  262.         if (( sp = strchr(line, '\n')) != NULL ) *sp = '\0'; 
  263.         if (( sp = strchr(line, '\r')) != NULL ) *sp = '\0'; 
  264.         if ( suppress )
  265.                 WriteLog( "Client> ..." );
  266.         else
  267.                 WriteLog( "Client> %s", line );
  268. }
  269.  
  270. UpdateTime( )
  271. {
  272.         struct tm *date;
  273.         
  274.         gNow = time( NULL );            /* get current calendar time */
  275.         date = localtime( &gNow );      /* convert it to a broken-down time */
  276.         strftime( gDate, BUFSIZE, "%b %d %H:%M:%S", date );
  277. }
  278.  
  279. WriteLog( va_alist )
  280. va_dcl
  281. {
  282.         va_list ap;
  283.         char *fmt;      
  284.         char *args[MAXARGS];
  285.         int argno = 0;
  286.         UpdateTime( );
  287.  
  288.  
  289.         va_start( ap );
  290.         fmt = va_arg(ap, char *);
  291.         while ((args[argno++] = va_arg(ap, char *)) != (char *)0)
  292.                     ;
  293.         fprintf( log, "%s: ", gDate );
  294.         vfprintf(log, fmt, args);
  295.         fputs( "\n", log );
  296.         fflush(log);
  297.         va_end( ap );
  298. }
  299.  
  300. int chkPass( user, pass, pw )
  301. char *user;
  302. char *pass;
  303. struct passwd *pw;
  304. {
  305.         /*  Compare the supplied password with the password file entry */
  306.         if (strcmp (crypt (pass, pw->pw_passwd), pw->pw_passwd) != 0)
  307.                 return ( FAILURE );
  308.         else 
  309.                 return ( SUCCESS );
  310. }
  311.  
  312.  
  313.  
  314.  
  315. makesalt( c )
  316. char c[2];                      /* salt characters */
  317. {
  318.         register long salt;             /* used to compute a salt */
  319.         register int i;                 /* counter in a for loop */
  320.  
  321.         /*
  322.          * just mix a few things up for the salt ...
  323.          * no rhyme or reason here
  324.          */
  325.         salt = (((long) time(TI_NULL))&0x3f) | (getpid() << 5);
  326.  
  327.         /*
  328.          * use the bottom 12 bits and map them into the legal alphabet
  329.          */
  330.         for(i = 0; i < 2; i++){
  331.                 c[i] = (salt & 0x3f) + '.';
  332.                 if (c[i] > '9')
  333.                         c[i] += 7;
  334.                 if (c[i] > 'Z')
  335.                         c[i] += 6;
  336.                 salt >>= 6;
  337.         }
  338. }
  339.  
  340.  
  341. setPass( user, pass, newpass, pw )
  342. char *user;
  343. char *pass;
  344. char *newpass;
  345. struct passwd *pw;
  346. {
  347.  
  348.         char saltc[2];          /* the password's salt */
  349.  
  350.         makesalt(saltc);
  351.         strcpy( pw->pw_passwd, crypt(newpass, saltc));
  352.  
  353.         if ( UpdatePasswordFile( pw ) == PW_CHANGED )
  354.                 return (SUCCESS);
  355.         else
  356.                 return (FAILURE);
  357. }
  358.  
  359.  
  360.  
  361. UpdatePasswordFile(p)
  362. struct passwd *p;               /* new password structure */
  363. {
  364.         char nbuf[BUFSIZ];              /* buffer for passwords being read */
  365.         char obuf[BUFSIZ];              /* buffer for new entry */
  366.         register char *q, *s;           /* used for quick name comparison */
  367.         int retval = PW_NOCHANGE;       /* return value */
  368.  
  369.         /*
  370.          * disable ALL signals at this point
  371.          */
  372.         sigoff();
  373.  
  374.         /*
  375.          * open the temporary password file
  376.          */
  377.         umask(022);
  378.         pf_tnam = mktemp(PF_PLATE);
  379.         if ((pf_tfp = fopen(pf_tnam, "w")) == FI_NULL){
  380.                 retval = PW_CANTOPEN;
  381.                 goto cantlock;
  382.         }
  383.  
  384.         /*
  385.          * lock the password file
  386.          */
  387.         if (link(pf_tnam, PF_TEMP) < 0){
  388.                 retval = PW_CANTLOCK;
  389.                 goto cantlock;
  390.         }
  391.         
  392.         /*
  393.          * copy the new password structure
  394.          */
  395.         sprintf(obuf, "%s:%s:%d:%d:%s:%s:%s\n",
  396.                         p->pw_name, p->pw_passwd, p->pw_uid, p->pw_gid,
  397.                         p->pw_gecos, p->pw_dir, p->pw_shell);
  398.  
  399.         /*
  400.          * open the password file
  401.          */
  402.         if ((pf_fp = fopen(pf_name, "r")) == FI_NULL){
  403.                 retval = PW_CANTOPEN;
  404.                 goto getout;
  405.         }
  406.  
  407.  
  408.         /*
  409.          * copy the password file into the temporary one
  410.          */
  411.         while(fgets(nbuf, BUFSIZ, pf_fp) != NULL){
  412.                 for(s = nbuf, q = p->pw_name; *s && *s != ':'; s++, q++)
  413.                         if (*s != *q)
  414.                                 break;
  415.                 if (*s == ':' && *q == '\0') {
  416.                         fputs(obuf, pf_tfp);
  417.                         retval = PW_CHANGED;
  418.                 } else 
  419.                         fputs(nbuf, pf_tfp);
  420.         }
  421.         if (retval == PW_NOCHANGE) {
  422.                 goto getout;
  423.         }
  424.  
  425.         /*
  426.          * close the temporary file and the real one
  427.          */
  428.         (void) fclose(pf_tfp);
  429.         pf_tfp = FI_NULL;
  430.         (void) fclose(pf_fp);
  431.         pf_fp = FI_NULL;
  432.  
  433.         /*
  434.          * now relink; note the lock file is still there
  435.          */
  436.         if ( unlink(pf_name) >= 0
  437.                 && link(pf_tnam, pf_name) >= 0
  438.                 && unlink(pf_tnam) >= 0){
  439.                 retval = PW_CHANGED;
  440.         }
  441.         else
  442.                 retval = PW_CANTRENAME;
  443.  
  444. getout:
  445.         /*
  446.          * Only remove lock file if this program obtained it
  447.          */
  448.          (void) unlink(PF_TEMP); 
  449.  
  450. cantlock:
  451.         /* some clean up */
  452.         if (pf_tfp != FI_NULL)
  453.                 (void) fclose(pf_tfp);
  454.         if (pf_fp != FI_NULL)
  455.                 (void) fclose(pf_fp);
  456.         (void) unlink(pf_tnam);
  457.  
  458.         sigon(); /* re-enable ALL signals at this point */
  459.  
  460.         return(retval);
  461. }
  462.  
  463.  
  464. /*
  465.  * signal handling routines
  466.  */
  467. void (*trap[NSIG])();           /* values returned by signal() */
  468.  
  469.  
  470. /*
  471.  * disable ALL signal trapping
  472.  */
  473. sigoff()
  474. {
  475.         register int i;         /* counter in a for loop */
  476.  
  477.         for(i = 0; i < NSIG; i++)
  478.                 (void) signal(i, SIG_IGN);
  479. }
  480.  
  481. /*
  482.  * restore to the initial setting all signals
  483.  */
  484. sigon()
  485. {
  486.         register int i;         /* counter in a for loop */
  487.  
  488.         for(i = 0; i < NSIG; i++)
  489.                 (void) signal(i, trap[i]);
  490.  
  491. }
  492.  
  493.  
  494.  
  495.  
  496.  
  497.