home *** CD-ROM | disk | FTP | other *** search
/ Atari FTP / ATARI_FTP_0693.zip / ATARI_FTP_0693 / Mint / mntlib32.zoo / getpw.c < prev    next >
C/C++ Source or Header  |  1993-06-17  |  13KB  |  459 lines

  1. /*
  2. Subject:  v08i080:  Public-domain getpw*(3) routines
  3. Newsgroups: mod.sources
  4. Approved: mirror!rs
  5.  
  6. Submitted by: emoryu1!emoryu2!arnold (Arnold D. Robbins)
  7. Mod.sources: Volume 8, Issue 80
  8. Archive-name: getpw
  9.  
  10. Here is public domain re-implementation of the getpwent(3) routines. I have
  11. not included a manual page, since every Unix system has one. I also haven't
  12. even bothered to include a <pwd.h> file; you should be able to use the one
  13. on your system.
  14.  
  15. There is one additional routine:
  16.       setpwfile (file)
  17.       char *file;
  18. which will cause the routines to find password records from a file besides
  19. /etc/passwd.  This is useful should you need to use saved password files,
  20. for instance in doing Unix accounting, where you wish to keep info around on
  21. old accounts, but take the old accounts out of the live password file.
  22. (Can you guess why I just whipped these up?)
  23.  
  24. To switch files, call setpwfile as the very first thing, or call endpwent(),
  25. then setpwfile ("/some/file").
  26.  
  27. Anyway, I hope this is useful to somene out there.
  28. Arnold Robbins
  29. arnold@emoryu1.{CSNET, UUCP, ARPA, BITNET}
  30. */
  31.  
  32. /* minorly customized by ERS for the MiNT library */
  33.  
  34. /****************************************************************/
  35. /* Module name:   getpw.c                                       */
  36. /* Library name:  mintlibs for Atari ST                         */
  37. /* Author:        Hildo Biersma (boender@dutiws.twi.tudelft.nl) */
  38. /* Date:          January 29, 1993                              */
  39. /* Revision:      1 (add password aging, add System V routines, */
  40. /*                   include three man pages, add example code) */
  41. /****************************************************************/
  42.  
  43. /*
  44. NAME
  45.     getpw - get name from UID
  46.  
  47. SYNOPSIS
  48.     #include <pwd.h>
  49.  
  50.     int getpw(int uid, char *buf);
  51.  
  52. DESCRIPTION
  53.     getpw searches the password file for a user id number that
  54.     equals uid, copies the line of the password file in which uid
  55.     was found into the array pointed to by buf, and returns 0.
  56.     getpw returns non-zero if uid cannot be found.
  57.  
  58.     This routine is included only for compatibility with old UN*X
  59.     systems and should not be used in any new programs; see
  60.     getpwent for routines to use instead.
  61.  
  62. FILES
  63.     /etc/passwd
  64.  
  65. SEE ALSO
  66.     getpwent
  67.  
  68. AUTHOR
  69.     Hildo Biersma, with the help of a UN*X System V man page.
  70. */
  71.  
  72. /*
  73. NAME
  74.     getpwent, getpwuid, getpwnam, setpwent, endpwent,
  75.     fgetpwent, setpwfile - get password file entry
  76.  
  77. SYNOPSIS
  78.     #include <stdio.h>  // Only needed for fgetpwent
  79.     #include <pwd.h>
  80.  
  81.     struct passwd *getpwent(void);
  82.  
  83.     struct passwd *getpwuid(int uid);
  84.  
  85.     struct passwd *getpwnam(const char *name);
  86.  
  87.     void setpwent(void);
  88.  
  89.     void endpwent(void);
  90.  
  91.     struct passwd *fgetpwent(FILE *f);
  92.  
  93.     void setpwfile(const char *name);
  94.  
  95. DESCRIPTION
  96.     getpwent, getpwuid and getpwnam each returns a pointer to an
  97.     object containing the broken-out fields of a line in the
  98.     /etc/passwd file.
  99.     Each line in the file contains a "passwd" structure, declared
  100.     in the <pwd.h> header file. For the definition of this structure
  101.     and the meaning of the fields, see the <pwd.h> header file.
  102.  
  103.     getpwent when first called returns a pointer to the first
  104.     passwd structure in the file; thereafter, it returns a pointer
  105.     to the next passwd structure in the file; so successive calls
  106.     can be used to search the entire file.
  107.  
  108.     getpwuid searches from the beginning of the file until a
  109.     numerical user ID is found matching uid is found and returns
  110.     a pointer to the particular structure in which it was found.
  111.     Thus, it cannot be found to search for several users having
  112.     duplicate numerical user IDs.
  113.  
  114.     getpwnam searches from the beginning of the file until a
  115.     login name matching name is found and returns a pointer to
  116.     the particular structure in which it was found.
  117.  
  118.     If an EOF or an error is encountered on reading, getpwent,
  119.     getpwuid and getpwnam return a NULL pointer.
  120.  
  121.     A call to setpwent has the effect of rewinding the password
  122.     file to allow repeated searches.
  123.  
  124.     endpwent may be called to close the password file when
  125.     processing is complete.
  126.  
  127.     fgetpwent returns a pointer to the next passwd structure in
  128.     the stream f, which matches the format of /etc/passwd.
  129.  
  130.     setpwfile will set the password file to be read from by all
  131.     the above routines except fgetpwent.   
  132.  
  133. FILES
  134.     /etc/passwd
  135.  
  136. SEE ALSO
  137.     getlogin, getgrent, putpwent
  138.  
  139. NOTES
  140.     All information is contained in a static area, so it must
  141.     be copied if it is to be saved.
  142.  
  143.     Password aging is supported.
  144.  
  145.     In order not to suffer from possible future changes in the
  146.     format of the passwd file or in the passwd structure,
  147.     these routines should always be used for reading from file,
  148.     while putpwent should always be used for writing to file.
  149.  
  150.     These routines expect the passwd file to be of type text,
  151.     and can therefore read both DOS and UN*X format files.
  152.  
  153. AUTHORS
  154.     Arnold D. Robbins - original version
  155.     Eric Smith        - adapted for the mintlibs
  156.     Hildo Biersma     - included System V routines and password aging
  157. */
  158.  
  159. /*
  160. PASSWORD AGING
  161.  
  162. DESCRIPTION
  163.     Password aging is in effect for a particular user if his
  164.     encrypted password in the password file is followed by a
  165.     comma and a non-null string of characters from the 
  166.     alphabet (., /, 0-9, A-Z, a-z) also used for the encrypted
  167.     password. (Such a string must be introduced in the first
  168.     place by the super-user.)
  169.  
  170.     The first character of the age, M say, denotes the maximum
  171.     number of weeks for which a password is valid. A user who
  172.     attempts to login after his password has expired should be
  173.     forced to supply a new one. The next character, N say,
  174.     denotes the minimum number of weeks which must expire
  175.     before the password may be changed. The remaining characters
  176.     define the week (counted from the beginning of 1970) when
  177.     the password was last changed. (A null string is equivalent
  178.     to zero.) M and N have numerical values in the range 0-63
  179.     that correspond to the 64-character alphabet mentioned
  180.     above (i.e., / = 1 week; z = 63 weeks). If M = N = 0
  181.     (derived from the string . or ..) the user should be forced
  182.     to change his password the next time he logs in (and the
  183.     "age" should disappear from his entry in the password file).
  184.     If N > M (signified, e.g., by the string /.) only the
  185.     super-user should be able to change the password.
  186.  
  187. SEE ALSO
  188.     a64l, getpwent, putpwent
  189.  
  190. NOTE
  191.     The compliance with password aging in MiNT is a joke, since
  192.     users are not forced to login. Also, the current login program
  193.     supplied in init(1) does not support password aging. This may
  194.     change in the future.
  195. */
  196.  
  197. /*
  198.   FIXME:
  199.   - test *thoroughly*
  200.   - write example code for modifying passwd files, include below
  201. */  
  202.     
  203. #include <stdio.h>
  204. #include <pwd.h>
  205. #include <unistd.h>
  206. #include <string.h>
  207. #include <stdlib.h>
  208.  
  209. static char *pwdfile = "/etc/passwd"; /* default passwd file */
  210.  
  211. static FILE *fp = NULL;
  212. static struct passwd curentry;    /* static data to return */
  213.  
  214. static int nextent __PROTO((FILE *fp));
  215.  
  216. /* Get name from uid */
  217. int getpw(uid, buf)
  218. int uid;
  219. char *buf;
  220. {
  221.   FILE *pw;
  222.   char line[256]; /* Assume this will always be enough */
  223.   char *ptr;
  224.  
  225.   if ((pw = fopen("/etc/passwd", "rt")) == NULL)
  226.     return(-1); /* Failure: file could not be opened */
  227.  
  228.   line[255] = 0x00;
  229.   while (!feof(pw))
  230.   {
  231.     fgets(line, 255, pw);
  232.     if ((ptr = strchr(line, ':')) != NULL) /* Password field found */
  233.       if ((ptr = strchr(ptr + 1, ':')) != NULL) /* UID field found */
  234.         if (atoi(ptr + 1) == uid)
  235.         {
  236.           strcpy(buf, line);
  237.           return(0); /* Success */
  238.         }
  239.   }
  240.   return(-1); /* Failure */
  241. } /* End of getpw() */
  242.  
  243. /* Set the name of the passwd file */
  244. void setpwfile(cp)
  245. char *cp;
  246. {
  247.   endpwent();
  248.   if (cp != NULL)
  249.     pwdfile = cp;
  250. } /* End of setpwfile() */
  251.  
  252. /* Rewind the passwd file */
  253. void setpwent()
  254. {
  255.   if (fp != NULL)
  256.     rewind(fp);
  257.   else if ((fp = fopen (pwdfile, "rt")) == NULL)
  258.   {
  259. #ifdef VERBOSE
  260.     fprintf (stderr, "setpwent: %s non-existant or unreadable.\n", pwdfile);
  261. #endif
  262.   }
  263. } /* End of setpwent() */
  264.  
  265. /* End passwd file processing */
  266. void endpwent()
  267. {
  268.   if (fp != NULL)
  269.   {
  270.     fclose (fp);
  271.     fp = NULL;
  272.   }
  273. } /* End of endpwent() */
  274.  
  275. /* Get the next passwd entry from the passwd file */
  276. struct passwd *getpwent()
  277. {
  278.   if (fp == NULL)
  279.   {
  280.     setpwent();
  281.     if (fp == NULL)
  282.       return(NULL);
  283.   }
  284.  
  285.   if (nextent(fp) == 0)
  286.     return(NULL);
  287.   else
  288.     return(&curentry);
  289. } /* End of getpwent() */
  290.  
  291. /* Get first passwd entry from file with pw_uid matching uid */
  292. struct passwd *getpwuid(uid)
  293. int uid;
  294. {
  295.   setpwent();
  296.   while (nextent(fp) != 0)
  297.     if (curentry.pw_uid == uid)
  298.       return(&curentry);
  299.  
  300.   return(NULL);
  301. } /* End of getpwuid() */
  302.  
  303. /* Get first passwd entry from file with pw_name matching name */
  304. struct passwd *getpwnam(name)
  305. const char *name;
  306. {
  307.   setpwent();
  308.  
  309.   while (nextent(fp) != 0)
  310.     if (strcmp(curentry.pw_name, name) == 0)
  311.       return(&curentry);
  312.  
  313.   return(NULL);
  314. } /* End of getpwnam() */
  315.  
  316. /* Read the next password structure from a given file */
  317. struct passwd *fgetpwent(f)
  318. FILE *f;
  319. {
  320.   if (f == NULL)
  321.     return(NULL); /* Failure */
  322.  
  323.   if (nextent(f) != 0)
  324.     return(&curentry); /* Success */
  325.  
  326.   return(NULL); /* Failure */
  327. } /* End of fgetpwent() */
  328.  
  329. #if defined(atarist) || defined(__SOZOBON__)
  330. static char savbuf[256];  /* BUFSIZ seems bigger than necessary! */
  331. #else
  332. static char savbuf[BUFSIZ];
  333. #endif
  334.  
  335. /* Static function getting next entry from passwd file */    
  336. static int nextent(fp)
  337. FILE *fp;
  338. {
  339.   char *cp;
  340.  
  341.   if (fp == NULL)
  342.   {
  343.     setpwent();
  344.     if (fp == NULL)
  345.       return(0);
  346.   }
  347.  
  348.   while (fgets(savbuf, (int)sizeof(savbuf), fp) != NULL)
  349.   {
  350.     curentry.pw_age = NULL;
  351.  
  352.     for (cp = savbuf; ((*cp != 0x00) && (*cp != ':')); cp++)
  353.       ;
  354.     curentry.pw_name = savbuf;
  355.     *cp++ = 0x00;
  356.     curentry.pw_passwd = cp;
  357.     for (; ((*cp != 0x00) && (*cp != ':')); cp++)
  358.       if ((*cp == ',') && (curentry.pw_age == NULL))
  359.       {
  360.         /* Password age field found */
  361.         *cp++ = 0x00;
  362.         curentry.pw_age = cp;
  363.       }
  364.     *cp++ = 0x00;
  365.     curentry.pw_uid = atoi(cp);
  366.     for (; ((*cp != 0x00) && (*cp != ':')); cp++)
  367.       ;
  368.     *cp++ = 0x00;
  369.     curentry.pw_gid = atoi(cp);
  370.     for (; ((*cp != 0x00) && (*cp != ':')); cp++)
  371.       ;
  372.     *cp++ = 0x00;
  373.     curentry.pw_gecos = cp;
  374.     curentry.pw_comment = cp;
  375.     for (; ((*cp != 0x00) && (*cp != ':')); cp++)
  376.       ;
  377.     *cp++ = 0x00;
  378.     curentry.pw_dir = cp;
  379.     for (; ((*cp != 0x00) && (*cp != ':')); cp++)
  380.       ;
  381.     *cp++ = 0x00;
  382.     curentry.pw_shell = cp;
  383.     for (; ((*cp != 0x00) && (*cp != ':') && (*cp != '\n')); cp++)
  384.       ;
  385.     *cp = 0x00;
  386.     if (curentry.pw_age == NULL)
  387.       curentry.pw_age = cp; /* Don't return NULL, return a null string */
  388.     return(1);
  389.   }
  390.   return(0);
  391. } /* End of nextent() */
  392.  
  393. /* Old test program removed - Hildo Biersma */
  394. #ifdef EXAMPLE
  395.  
  396. /*
  397. EXAMPLE PROGRAM
  398.  
  399. DESCRIPTION
  400.     Read all lines from the password file and print all users
  401.     with password aging info. Also print a description of
  402.     the meaning of the aging information of this user.
  403.  
  404. AUTHOR
  405.     Hildo Biersma (boender@dutiws.twi.tudelft.nl)
  406.  
  407. STATUS
  408.     Example code; in the public domain.
  409. */
  410.  
  411. #include <support.h>
  412.  
  413. void main()
  414. {
  415.   struct passwd *this_entry;
  416.   int max_age, min_age;
  417.   char *ptr, min[2], max[2];
  418.   time_t time;
  419.   
  420.   min[1] = max[1] = 0x00;
  421.   while ((this_entry = getpwent()) != NULL)
  422.     if ((this_entry->pw_age[0]) != 0x00)
  423.     {
  424.       if ((max[0] = this_entry->pw_age[0]) != 0x00)
  425.       {
  426.         max_age = (int)a64l(max);
  427.         if ((min[0] = this_entry->pw_age[1]) != 0x00)
  428.         {
  429.           min_age = (int)a64l(min);
  430.           ptr = this_entry->pw_age + 2;
  431.           time = a64l(ptr) * (3600L * 24 * 7); /* Seconds per week */
  432.         }
  433.         else
  434.           time = 0L;
  435.       }
  436.       else
  437.       {
  438.         min_age = 0;
  439.         time = 0L;
  440.       }
  441.       fprintf(stdout, "Name: %s, UID: %d.\n", this_entry->pw_name,
  442.               this_entry->pw_uid);
  443.       if ((max_age == 0) && (min_age == 0))
  444.         fprintf(stdout, "User should change password on next login.\n\n");
  445.       else if (min_age > max_age)
  446.         fprintf(stdout, "Only super-user may change password.\n\n");
  447.       else
  448.       {
  449.         fprintf(stdout, "Must change every %d weeks.\n", max_age);
  450.         fprintf(stdout, "May change every %d weeks.\n", min_age);
  451.         fprintf(stdout, "Last changed in week starting %s\n\n",
  452.                 ctime(&time));
  453.       }
  454.     }
  455.     
  456.   endpwent();
  457. } /* End of main() */
  458. #endif /* EXAMPLE */
  459.