home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / UNIX / Mail / qpopper-2.4-MIHS / popauth.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-11-16  |  13.9 KB  |  682 lines

  1. /*
  2.  * Copyright (c) 1997 by Qualcomm Incorporated.
  3.  */
  4.  
  5. /*  */
  6. /* popauth.c - manipulate POP authorization DB */
  7. #include <config.h>
  8. #ifdef GDBM
  9. # include <gdbm.h>
  10. #else
  11. # if HAVE_NDBM_H
  12. #  include <ndbm.h>
  13. # else
  14. #  if HAVE_DBM_H
  15. #   include <dbm.h>
  16. #  endif
  17. # endif
  18. #endif
  19. #include <pwd.h>
  20. #include <stdio.h>
  21. #ifdef __STDC__
  22. #include <stdlib.h>
  23. #include <stdarg.h>
  24. #else
  25. #include <varargs.h>
  26. #endif
  27. #include <sys/types.h>
  28. #include <sys/stat.h>
  29. #include <fcntl.h>
  30. #include <errno.h>
  31. #include <string.h>
  32.  
  33. #ifndef HAVE_BCOPY
  34. #define bcopy(src,dest,len)    (void) (memcpy(dest,src,len))
  35. #define bzero(dest,len)      (void) (memset(dest, (char)NULL, len))
  36. #define bcmp(b1,b2,n)        memcmp(b1,b2,n)
  37. #endif
  38. #ifndef HAVE_INDEX
  39. # define index(s,c)        strchr(s,c)
  40. # define rindex(s,c)        strrchr(s,c)
  41. #endif
  42. #include <flock.h>
  43. #if HAVE_STRINGS_H
  44. #include <strings.h>
  45. #endif
  46. #if HAVE_SYS_FILE_H
  47. #include <sys/file.h>
  48. #endif
  49.  
  50. #ifdef BSDI
  51. #define BSD44_DBM
  52. #endif
  53.  
  54. #ifdef NEED_STRERROR
  55. char *strerror();
  56. #endif
  57.  
  58. #define    UID_T    uid_t
  59.  
  60. static struct swit {
  61.     char *name;
  62. } switches[] = {
  63. #define    INITSW    0
  64.     "init", 
  65. #define    LISTSW    1
  66.     "list", 
  67. #define    USERSW    2
  68.     "user", 
  69. #define    DELESW    3
  70.     "delete", 
  71.  
  72.     NULL,
  73. };
  74.  
  75. static char   *program;
  76.  
  77. #ifdef __STDC__
  78. static void
  79. adios(const char *fmt, ...)
  80. #else
  81. static void
  82. adios(va_alist)
  83. va_dcl
  84. #endif
  85. {
  86.     va_list ap;
  87. #ifndef __STDC__
  88.     char *fmt;
  89. #endif
  90.  
  91.     (void) fprintf(stderr, "%s: ", program);
  92. #ifdef __STDC__
  93.     va_start(ap, fmt);
  94. #else
  95.     va_start(ap);
  96.     fmt = va_arg(ap, char *);
  97. #endif
  98.     (void) vfprintf(stderr, fmt, ap);
  99.     (void) fprintf(stderr, "\n");
  100.     va_end(fmt);
  101.     exit(1);
  102.     /*NOTREACHED*/
  103. }
  104.  
  105. #ifndef HAVE_STRDUP
  106. #include <stddef.h>
  107.  
  108. char *
  109. strdup(str)
  110.         char *str;
  111. {
  112.     int len;
  113.     char *copy;
  114.  
  115.     len = strlen(str) + 1;
  116.     if (!(copy = malloc((u_int)len)))
  117.     return((char *)NULL);
  118.     bcopy(str, copy, len);
  119.     return(copy);
  120. }
  121. #endif
  122.  
  123. /*
  124.  * Obscure password so a cleartext search doesn't come up with
  125.  * something interesting.
  126.  *
  127.  */
  128.  
  129. char *
  130. obscure(string)
  131. char *string;
  132. {
  133.     unsigned char *cp, *newstr;
  134.  
  135.     cp = newstr = (unsigned char *)strdup(string);
  136.  
  137.     while (*cp) {
  138.         *cp++ ^= 0xff;
  139.     }
  140.  
  141.     return((char *)newstr);
  142. }
  143.  
  144. /* Use GNU_PASS for longer passwords on systems that support termios */
  145.  
  146. #ifndef GNU_PASS
  147. char *getpass();
  148. #else
  149.  
  150. /* Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
  151. This file is part of the GNU C Library.
  152.  
  153. The GNU C Library is free software; you can redistribute it and/or
  154. modify it under the terms of the GNU Library General Public License as
  155. published by the Free Software Foundation; either version 2 of the
  156. License, or (at your option) any later version.
  157.  
  158. The GNU C Library is distributed in the hope that it will be useful,
  159. but WITHOUT ANY WARRANTY; without even the implied warranty of
  160. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  161. Library General Public License for more details.
  162.  
  163. You should have received a copy of the GNU Library General Public
  164. License along with the GNU C Library; see the file COPYING.LIB.  If
  165. not, write to the Free Software Foundation, Inc., 675 Mass Ave,
  166. Cambridge, MA 02139, USA.  */
  167.  
  168. /* It is desireable to use this bit on systems that have it.
  169.    The only bit of terminal state we want to twiddle is echoing, which is
  170.    done in software; there is no need to change the state of the terminal
  171.    hardware.  */
  172.  
  173. #include <stdio.h>
  174. #include <termios.h>
  175. #include <unistd.h>
  176.  
  177. #ifndef TCSASOFT
  178. #define TCSASOFT 0
  179. #endif
  180.  
  181. #ifdef SSIZET
  182. typedef SSIZET ssize_t;
  183. #endif
  184.  
  185. char *
  186. getpass (prompt)
  187. #if defined(HPUX)
  188. char *prompt;
  189. #else
  190. const char *prompt;
  191. #endif
  192. {
  193.   FILE *in, *out;
  194.   struct termios t;
  195.   int echo_off;
  196.   static char *buf = NULL;
  197.   static size_t bufsize = 0;
  198.   ssize_t nread;
  199.  
  200.   /* Try to write to and read from the terminal if we can.
  201.      If we can't open the terminal, use stderr and stdin.  */
  202.  
  203.   in = fopen ("/dev/tty", "w+");
  204.   if (in == NULL)
  205.     {
  206.       in = stdin;
  207.       out = stderr;
  208.     }
  209.   else
  210.     out = in;
  211.  
  212.   /* Turn echoing off if it is on now.  */
  213.  
  214.   if (tcgetattr (fileno (in), &t) == 0)
  215.     {
  216.       if (t.c_lflag & ECHO)
  217.     {
  218.       t.c_lflag &= ~ECHO;
  219.       echo_off = tcsetattr (fileno (in), TCSAFLUSH|TCSASOFT, &t) == 0;
  220.       t.c_lflag |= ECHO;
  221.     }
  222.       else
  223.     echo_off = 0;
  224.     }
  225.   else
  226.     echo_off = 0;
  227.  
  228.   /* Write the prompt.  */
  229.   fputs (prompt, out);
  230.   fflush (out);
  231.  
  232.   /* Read the password.  */
  233. #ifdef NO_GETLINE
  234.   bufsize = 256;
  235.   buf = (char *)malloc(256);
  236.   nread = (fgets(buf, (size_t)bufsize, in) == NULL) ? 1 : strlen(buf);
  237.   rewind(in);
  238.   fputc('\n', out);
  239. #else
  240.   nread = __getline (&buf, &bufsize, in);
  241. #endif
  242.   if (nread < 0 && buf != NULL)
  243.     buf[0] = '\0';
  244.   else if (buf[nread - 1] == '\n')
  245.     /* Remove the newline.  */
  246.     buf[nread - 1] = '\0';
  247.  
  248.   /* Restore echoing.  */
  249.   if (echo_off)
  250.     (void) tcsetattr (fileno (in), TCSAFLUSH|TCSASOFT, &t);
  251.  
  252.   if (in != stdin)
  253.     /* We opened the terminal; now close it.  */
  254.     fclose (in);
  255.  
  256.   return buf;
  257. }
  258. #endif
  259.  
  260. /* ARGSUSED */
  261.  
  262. main (argc, argv)
  263. int    argc;
  264. char   *argv[];
  265. {
  266.     UID_T   myuid;
  267.     int        flags,
  268.         i,
  269.         delesw = 0,
  270.         initsw = 0,
  271.         insist,
  272.         listsw = 0,
  273.         popuser = 0;
  274.     long    clock;
  275.     char   *bp,
  276.        *cp,
  277.        *usersw = NULL,
  278.         buf[100],
  279.         obuf[100];
  280.     struct  passwd *pw;
  281.     datum   key,
  282.         value;
  283. #ifdef GDBM
  284.     GDBM_FILE db;
  285.     char     apop_file[BUFSIZ];
  286. #else 
  287.     DBM    *db;
  288.     char    apop_dir[BUFSIZ];
  289. #ifndef BSD44_DBM
  290.     char    apop_pag[BUFSIZ];
  291. #endif
  292. #endif
  293.     int     f;
  294.  
  295.     program = argv[0];
  296.     argv++;
  297.     argc--;
  298.  
  299.     while (argc > 0) {
  300.     cp = argv[0];
  301.     if (*cp == '-') {
  302.         int i, v;
  303.  
  304.         i = 0;
  305.         v = -1;
  306.         for(i = 0; switches[i].name; i++) {
  307.         if(strcmp(&cp[1], switches[i].name) == 0) {
  308.             v = i;
  309.             break;
  310.         }
  311.         }
  312.         cp++;
  313.         switch (v) {
  314.         default:
  315.             adios ("-%s unknown option", cp);
  316.         case INITSW:
  317.             initsw = 1, listsw = 0; delesw = 0;
  318.             break;
  319.         case LISTSW:
  320.             listsw = 1, initsw = 0; delesw = 0;
  321.             break;
  322.         case DELESW:
  323.             delesw = 1, initsw = 0; listsw = 0;
  324.             if (argc < 2 || argv[1][0] == '-')
  325.             adios ("missing argument to %s", argv[0]);
  326.             usersw = argv[1];
  327.             argc--;
  328.             argv++;
  329.             break;
  330.         case USERSW:
  331.             if (argc < 2 || argv[1][0] == '-')
  332.             adios ("missing argument to %s", argv[0]);
  333.             usersw = argv[1];
  334.             argc--;
  335.             argv++;
  336.             if (delesw)
  337.             fprintf(stderr, "Warning: user '%s' will now be deleted\n", usersw);
  338.             break;
  339.         }
  340.     }
  341.     else
  342.         adios ("usage: %s [[-init]|[-list]|[-user name]|[-delete name]]", program);
  343.     argc--;
  344.     argv++;
  345.     }
  346.  
  347.  
  348. #ifndef    APOP
  349.     adios ("not compiled with APOP option");
  350. #else
  351.  
  352.     myuid = getuid();
  353.  
  354.     if ((pw = getpwnam (POPUID)) == NULL)
  355.     adios ("\"%s\": user-id unknown", POPUID);
  356.  
  357.     if (pw->pw_uid == myuid)
  358.     popuser = 1;
  359.  
  360.     if (myuid && !popuser && (delesw || initsw || listsw || (usersw != NULL)))
  361.     adios("Only superuser or user '%s' can perform the requested function",
  362.         POPUID);
  363.  
  364.     if (myuid && initsw)
  365.     adios("Only superuser can init the database");
  366. #ifdef GDBM
  367.     (void) strncpy(apop_file, APOP, sizeof(apop_file) - 1);
  368.     apop_file[sizeof(apop_file)-1] = '\0';
  369. #else
  370.     (void) strncpy(apop_dir, APOP, sizeof(apop_dir) - 5);
  371. #ifdef BSD44_DBM
  372.     (void) strcat(apop_dir, ".db");
  373. #else
  374.     (void) strncpy(apop_pag, APOP, sizeof(apop_pag) - 5);
  375.     (void) strcat(apop_pag, ".pag");
  376.     (void) strcat(apop_dir, ".dir");
  377. #endif
  378. #endif
  379.  
  380.     if (delesw) {
  381.     if (myuid && !popuser)
  382.         adios ("Only root or %s may delete entries", POPUID);
  383.  
  384. #ifdef GDBM
  385.     if ((db = gdbm_open(apop_file,512,GDBM_WRITER,0,0)) == NULL)
  386. #else
  387.     if ((db = dbm_open (APOP, O_RDWR, 0)) == NULL)
  388. #endif
  389.         adios ("%s: unable to open POP authorization DB", APOP);
  390.     
  391.     key.dsize = strlen (key.dptr = usersw) + 1;
  392.  
  393. #ifdef GDBM
  394.     value = gdbm_fetch(db, key);
  395. #else
  396.     value = dbm_fetch(db, key);
  397. #endif
  398.     if (value.dptr == NULL)
  399.         adios("User '%s' not found in apop database", usersw);
  400.  
  401. #ifdef GDBM
  402.     if (gdbm_delete(db,key) < 0)
  403. #else
  404.     if (dbm_delete(db, key) < 0)
  405. #endif
  406.         adios("Unable to delete user '%s' from apop database", usersw);
  407.  
  408. #ifdef GDBM
  409.     gdbm_close (db);
  410. #else
  411.     dbm_close (db);
  412. #endif
  413.  
  414.     exit (0);
  415.     }
  416.  
  417.     if (initsw) {
  418.     struct stat st;
  419.  
  420.     setuid(myuid);
  421.  
  422. #ifdef GDBM
  423.     if (stat (apop_file, &st) != -1) 
  424. #else
  425.     if (stat (apop_dir, &st) != -1) 
  426. #endif
  427.     {
  428.         char ibuf[30];
  429.         
  430.         printf("Really initialize POP authorization DB? ");
  431.         if(fgets(ibuf, sizeof(ibuf), stdin) == NULL || ibuf[0] != 'y')
  432.         exit (1);
  433. #ifdef GDBM
  434.         (void) unlink (apop_file);
  435. #else
  436.         (void) unlink (apop_dir);
  437. # ifndef BSD44_DBM
  438.         (void) unlink (apop_pag);
  439. # endif
  440. #endif
  441.     }
  442. #ifdef GDBM
  443.     if ((db = gdbm_open (apop_file, 512, GDBM_WRCREAT, 0600, 0)) == NULL)
  444.         adios ("unable to create POP authorization DB: %s", 
  445.             strerror(errno));
  446.     gdbm_close (db);
  447.     if (chown (apop_file, pw->pw_uid, pw->pw_gid) == -1)
  448.         adios ("error setting ownership of POP authorization for %s : %s", 
  449.         apop_file, strerror(errno));
  450. #else
  451.     if ((db = dbm_open (APOP, O_RDWR | O_CREAT, 0600)) == NULL)
  452.         adios ("unable to create POP authorization DB: %s", 
  453.             strerror(errno));
  454.     dbm_close (db);
  455.     if (chown (apop_dir, pw->pw_uid, pw->pw_gid) == -1 
  456. #ifndef BSD44_DBM
  457.      || chown (apop_pag, pw->pw_uid, pw->pw_gid) == -1
  458. #endif
  459.         )
  460.         adios ("error setting ownership of POP authorization DB: %s", 
  461.         strerror(errno));
  462. #endif
  463.  
  464.     exit (0);
  465.     }
  466.  
  467. #ifdef GDBM
  468.     if ((db = gdbm_open (apop_file, 512, GDBM_READER, 0, 0)) == NULL)
  469. #else
  470.     if ((db = dbm_open (APOP, O_RDONLY, 0)) == NULL)
  471. #endif
  472.         adios ("unable to open POP authorization DB: %s", strerror(errno));
  473.  
  474. /* this one opens again the already open file by gdbm_open, or dbm_open above
  475. #ifdef GDBM
  476.     if ((f = open (apop_file, listsw ? O_RDONLY : O_RDWR)) == -1)
  477.         adios ("%s: unable to open POP authorization DB", apop_file);
  478.     if (flock (f, LOCK_SH) == -1)
  479.         adios ("%s: unable to lock POP authorization DB", apop_file);
  480. #else
  481.     if ((f = open (apop_dir, listsw ? O_RDONLY : O_RDWR)) == -1)
  482.         adios ("%s: unable to open POP authorization DB", apop_dir);
  483.     if (flock (f, LOCK_SH) == -1)
  484.         adios ("%s: unable to lock POP authorization DB", apop_dir);
  485. #endif
  486. */
  487.  
  488. #ifdef GDBM
  489.     f = db->dummy[4]; /* file descriptor for apop_file */
  490.     if (flock (f, LOCK_SH) == -1) {
  491.         gdbm_close (db);
  492.         adios ("%s: unable to lock POP authorization DB", apop_file);
  493.     }
  494. #else
  495.     f = db->dbm_dirf; /* file descriptor for apop_dir */
  496.     if (flock (f, LOCK_SH) == -1) {
  497.         dbm_close (db);
  498.         adios ("%s: unable to lock POP authorization DB", apop_dir);
  499.     }
  500. #endif
  501.  
  502.  
  503.     if (listsw) {
  504.     if (usersw) {
  505.         key.dsize = strlen (key.dptr = usersw) + 1;
  506. #ifdef GDBM
  507.         value = gdbm_fetch (db, key);
  508. #else
  509.         value = dbm_fetch (db, key);
  510. #endif
  511.         if (value.dptr == NULL)
  512.         adios ("no such entry in POP authorization DB");
  513.         printf ("%s\n", key.dptr);
  514.     }
  515.     else
  516. #ifdef GDBM
  517.         for (key = gdbm_firstkey (db); key.dptr; key = gdbm_nextkey (db,key)) 
  518. #else
  519.         for (key = dbm_firstkey (db); key.dptr; key = dbm_nextkey (db)) 
  520. #endif
  521.         {
  522.         printf ("%s", key.dptr);
  523. #ifdef GDBM
  524.         value = gdbm_fetch (db, key);
  525. #else
  526.         value = dbm_fetch (db, key);
  527. #endif
  528.         if (value.dptr == NULL)
  529.             printf (" - no information?!?\n");
  530.         else {
  531.             printf ("\n");
  532.         }
  533.         }
  534.  
  535. #ifdef GDBM
  536.     gdbm_close (db);
  537. #else
  538.     dbm_close (db);
  539. #endif
  540.  
  541.     exit (0);
  542.     }
  543.  
  544.     if (usersw == NULL) {
  545.     if ((pw = getpwuid(myuid)) == NULL)
  546.         adios("Sorry, don't know who uid %d is.", myuid);
  547.     usersw = pw->pw_name;
  548.     } else {
  549.     if ((pw = getpwnam(usersw)) == NULL)
  550.         adios("Sorry, don't know who uid %s is.", usersw);
  551.     usersw = pw->pw_name;
  552.     }
  553.  
  554.     fprintf (stderr, "Changing POP password for %s.\n", usersw);
  555.  
  556.     key.dsize = strlen (key.dptr = usersw) + 1;
  557. #ifdef GDBM
  558.     value = gdbm_fetch (db, key);
  559. #else
  560.     value = dbm_fetch (db, key);
  561. #endif
  562.     if (myuid && !popuser && value.dptr != NULL) {
  563.     if (((i = strlen(strncpy(obuf, getpass("Old password:"), sizeof(obuf)))) == 0) ||
  564.         ((value.dsize - 1) != i) ||
  565.         (strncmp(obuf, value.dptr, i) &&
  566.              strncmp(obuf, obscure(value.dptr), i))) {
  567.         adios("Sorry, password entered incorrectly\n");
  568.     }
  569.     }
  570. #ifdef GDBM
  571.     gdbm_close (db);
  572. #else
  573.     dbm_close (db);
  574. #endif
  575.  
  576. #ifdef    lint
  577.     flags = 0;
  578. #endif    /* lint */
  579.     for (insist = 0; insist < 2; insist++) {
  580.     int    i;
  581.     char    c;
  582.  
  583.     if (insist)
  584.         printf ("Please use %s.\n",
  585.             flags == 1 ? "at least one non-numeric character"
  586.             : "a longer password");
  587.  
  588.     if (((i = strlen(strncpy(buf, getpass("New password:"), sizeof(buf)))) == 0) ||
  589.           !strncmp(buf, obuf, i)) {
  590.         fprintf (stderr, "Password unchanged.\n");
  591.         exit (1);
  592.     }
  593.  
  594.     flags = 0;
  595.     for (cp = buf; c = *cp++;)
  596.         if (c >= 'a' && c <= 'z')
  597.         flags |= 2;
  598.         else
  599.         if (c >= 'A' && c <= 'Z')
  600.             flags |= 4;
  601.         else
  602.             if (c >= '0' && c <= '9')
  603.             flags |= 1;
  604.             else
  605.             flags |= 8;
  606.  
  607.     if ((flags >= 7 && i >= 4)
  608.         || ((flags == 2 || flags == 4) && i >= 6)
  609.         || ((flags == 3 || flags == 5 || flags == 6) && i >= 5))
  610.         break;
  611.     }
  612.  
  613.     if (strcmp(buf, getpass("Retype new password:"))) {
  614.     fprintf (stderr, "Mismatch - password unchanged.\n");
  615.     exit (1);
  616.     }
  617.  
  618. #ifdef GDBM
  619.     if ((db = gdbm_open(apop_file, 512, GDBM_WRITER, 0, 0)) == NULL)
  620. #else
  621.     if ((db = dbm_open(APOP, O_RDWR, 0)) == NULL)
  622. #endif
  623.         adios("%s: unable to open POP authorization DB", APOP);
  624.  
  625. /*
  626.     if (flock(f, LOCK_EX) == -1)
  627.     adios("%s: unable to lock POP authorization DB", 
  628. #ifdef GDBM
  629.     apop_file
  630. #else
  631.     apop_dir
  632. #endif
  633.     );
  634. */
  635.  
  636. #ifdef GDBM
  637. if (flock(f, LOCK_EX) == -1) {
  638.     gdbm_close(db);
  639.     adios("%s: unable to lock POP authorization DB", apop_file);
  640.     }
  641. #else
  642. if (flock(f, LOCK_EX) == -1) {
  643.     dbm_close(db);
  644.     adios("%s: unable to lock POP authorization DB", apop_dir);
  645.     }
  646. #endif
  647.  
  648.     key.dsize = strlen (key.dptr = usersw) + 1;
  649.  
  650.     value.dptr = obscure(buf);
  651.     value.dsize = strlen(value.dptr) + 1;
  652.  
  653. #ifdef GDBM
  654.     if (gdbm_store (db, key, value, GDBM_REPLACE))
  655.     adios ("POP authorization DB may be corrupt?!?");
  656.     gdbm_close (db);
  657. #else
  658.     if (dbm_store (db, key, value, DBM_REPLACE))
  659.     adios ("POP authorization DB may be corrupt?!?");
  660.     dbm_close (db);
  661. #endif
  662. #endif
  663.  
  664.     exit (0);
  665.     /* NOTREACHED */
  666. }
  667.  
  668. #ifdef NEED_STRERROR
  669. char *
  670. strerror(e)
  671.     int e;
  672. {
  673.     extern char *sys_errlist[];
  674.     extern int sys_nerr;
  675.  
  676.     if(e < sys_nerr)
  677.         return(sys_errlist[e]);
  678.     else
  679.         return("unknown error");
  680. }
  681. #endif
  682.