home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1995 August / NEBULA.mdf / SourceCode / libcs / getpwwho.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-11  |  8.0 KB  |  275 lines

  1. /*
  2.  * Copyright (c) 1990 Carnegie Mellon University
  3.  * All Rights Reserved.
  4.  * 
  5.  * Permission to use, copy, modify and distribute this software and its
  6.  * documentation is hereby granted, provided that both the copyright
  7.  * notice and this permission notice appear in all copies of the
  8.  * software, derivative works or modified versions, and any portions
  9.  * thereof, and that both notices appear in supporting documentation.
  10.  *
  11.  * THE SOFTWARE IS PROVIDED "AS IS" AND CARNEGIE MELLON UNIVERSITY
  12.  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
  13.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT
  14.  * SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR ANY SPECIAL, DIRECT,
  15.  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
  16.  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
  17.  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  18.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  19.  *
  20.  * Users of this software agree to return to Carnegie Mellon any
  21.  * improvements or extensions that they make and grant Carnegie the
  22.  * rights to redistribute these changes.
  23.  *
  24.  * Export of this software is permitted only after complying with the
  25.  * regulations of the U.S. Deptartment of Commerce relating to the
  26.  * Export of Technical Data.
  27.  */
  28. /*
  29.  **********************************************************************
  30.  * HISTORY
  31.  * $Log:    getpwwho.c,v $
  32.  * Revision 1.3  90/12/11  17:55:13  mja
  33.  *     Add copyright/disclaimer for distribution.
  34.  * 
  35.  * 11-Aug-88  Glenn Marcy (gm0w) at Carnegie-Mellon University
  36.  *    Mapped ulstr to strcase compare.
  37.  *
  38.  * 05-Mar-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
  39.  *    Removed all special gecos code for 4.2 version.
  40.  *
  41.  * 03-Jan-86  Rudy Nedved (ern) at Carnegie-Mellon University
  42.  *    Basically the entire module was re-written. Parts of the getpwambig
  43.  *    routine are from the old package but that is it. The new code was
  44.  *    written using the CMU TOPS-10 SAIL library algorithm for parsing
  45.  *    account file names. The original motivation for this routine was
  46.  *    based on the visible actions of that algorithm, it might as well
  47.  *    used the actually algorithm.
  48.  *    
  49.  *    Hopefully all the compatibility issues have been handled. The
  50.  *    getpwwho(NULL) behavior is handled and the special loading of
  51.  *    middle names into the first name is handled.
  52.  *    
  53.  *    I would have coded the routine to really handle things in a mail
  54.  *    context but that is suppose to be handled by the network name
  55.  *    database.
  56.  *
  57.  * 06-Jan-84  Eric Patterson (egp) at Carnegie-Mellon University
  58.  *    Fixed bug:  if a string exactly matches some name, but is also a
  59.  *    substring of some other name, no ambiguity is observed.
  60.  *
  61.  * 18-Dec-81  Mike Accetta (mja) at Carnegie-Mellon University
  62.  *    Fixed two bugs:
  63.  *    1) adjusted length passed to FoldEQ() to a maximum so that login name
  64.  *       comparison never succeeds on a partial match.
  65.  *    2) added check for exact match after IsName() succeeds in case the
  66.  *       full name is a substring of some other full name with which it
  67.  *       would otherwise be ambiguous.
  68.  *
  69.  * 07-Dec-81  James Gosling (jag) at Carnegie-Mellon University
  70.  *    Now does case-folded compares on login ID's.  eg. "ern" and "ERN"
  71.  *    match.
  72.  *
  73.  * 11-Dec-80  Mike Accetta(mja) at Carnegie-Mellon University
  74.  *    Changed to convert all separator characters to spaces when
  75.  *    copying name into internal buffer so that dots in names with
  76.  *    more than two parts will match password file entries.
  77.  *
  78.  * 03-Dec-80  Mike Accetta (mja) at Carnegie-Mellon University
  79.  *    Changed to treat everything before last blank in name as first
  80.  *    name and modified to close password file when called with null
  81.  *    pointer.
  82.  *
  83.  * 29-Nov-80  Mike Accetta (mja) at Carnegie-Mellon University
  84.  *    Changed to allow '.' as separator in names.
  85.  *
  86.  * 07-Nov-80  Mike Accetta (mja) at Carnegie-Mellon University
  87.  *    Removed reference to (extinct) alias name.
  88.  *
  89.  **********************************************************************
  90.  */
  91.  
  92. #include <stdio.h>
  93. #include <ctype.h>
  94. #include <pwd.h>
  95. extern struct passwd *getpwent();
  96.  
  97. #define MAXNAME 100
  98. static char FirstPart[MAXNAME],LastPart[MAXNAME];
  99. static char ThisFirst[MAXNAME],ThisLast[MAXNAME];
  100. static int ExactFirst,ExactLast;
  101. static int MatchLevel,Matches,ambigstate;
  102.  
  103. /*
  104.  * break the supplied name down in to last name and first name(s).
  105.  * Translate dots into spaces. Note: middle names are part of the
  106.  * first name.
  107.  */
  108. static BreakDown(name,firsts,last)
  109. char *name,*firsts,*last;
  110. {
  111.     register char *p,*lp;
  112.  
  113.     strncpy(firsts,name,MAXNAME);
  114.     lp = (char *)0;
  115.     p = firsts;
  116.     while (*p) {
  117.     if (*p == '.' || *p == ' ') {
  118.         *(lp = p++) = ' ';
  119.     }
  120.     else
  121.         p++; 
  122.     }
  123.     if (lp != (char *)0) {
  124.     strncpy(last,lp+1,MAXNAME);
  125.     *lp = '\0';
  126.     }
  127.     else {
  128.     strncpy(last,firsts,MAXNAME);
  129.     *firsts = '\0';
  130.     }
  131.  
  132. }
  133.  
  134. /*
  135.  * We could just do a getpwuid() at the end of the name search
  136.  * but this causes alot of extra time spent and for mail and finger
  137.  * clients this is highly irritating especially on a loaded machine
  138.  * with many entries in the /etc/passwd file. On of these days, an
  139.  * additional binary index will be available making lookups on uid
  140.  * and login names fast.
  141.  */
  142. static pw_entry_save(bufp,valp)
  143. char **bufp;
  144. register char *valp;
  145. {
  146.     register char *p;
  147.  
  148.     p = *bufp;
  149.     while ((*p++ = *valp++) != '\0');
  150.     *bufp = p;
  151. }
  152. static struct passwd *copypw(pw)
  153. struct passwd *pw;
  154. {
  155.     static struct passwd mypw;
  156.     static char mybuf[BUFSIZ+1];
  157.     char *p;
  158.  
  159.     mypw = *pw;    /* copy things like pw_uid, pw_gid, etc. */
  160.     p = mybuf;
  161.     mypw.pw_name = p; pw_entry_save(&p,pw->pw_name);
  162.     mypw.pw_passwd = p; pw_entry_save(&p,pw->pw_passwd);
  163.     mypw.pw_comment = p; pw_entry_save(&p,pw->pw_comment);
  164.     mypw.pw_gecos = p; pw_entry_save(&p,pw->pw_gecos);
  165.     mypw.pw_dir = p; pw_entry_save(&p,pw->pw_dir);
  166.     mypw.pw_shell = p; pw_entry_save(&p,pw->pw_shell);
  167.  
  168.     return &mypw;
  169. }
  170.  
  171. static struct passwd *scanpw(stop)
  172. int stop;
  173. {
  174.     struct passwd *bestpw,*pw;
  175.  
  176.     bestpw = (struct passwd *) 0;
  177.  
  178.     while (pw = getpwent()) {
  179.     /* handle login ids, exact Matches win always */
  180.     if (*FirstPart == '\0' && strcasecmp(LastPart,pw->pw_name) == 0) {
  181.         Matches = 1;
  182.         MatchLevel = 7777777;    /* large number */
  183.         return copypw(pw);
  184.     }
  185.     /* check out names */
  186.     BreakDown(pw->pw_gecos,ThisFirst,ThisLast);
  187.     if (namecheck(ThisLast,LastPart,ExactLast)) {
  188.         /* last match */
  189.         if (namecheck(ThisFirst,FirstPart,ExactFirst)) {
  190.         /* both match */
  191.         if (!ExactLast)
  192.             if (strcasecmp(ThisLast,LastPart) == 0)
  193.             ExactLast = 1;
  194.         if (ExactLast && !ExactFirst)
  195.             if (strcasecmp(ThisFirst,FirstPart) == 0)
  196.             ExactFirst = 1;
  197.         /* see if we got something better */
  198.         if (MatchLevel < (ExactFirst + ExactLast)) {
  199.             MatchLevel = ExactFirst + ExactLast;
  200.             bestpw = copypw(pw);
  201.             Matches = 1;
  202.             if (stop) 
  203.             return bestpw;
  204.         }
  205.         else if (MatchLevel == (ExactFirst + ExactLast)) {
  206.             Matches++;
  207.             bestpw = copypw(pw);
  208.             if (stop) 
  209.             return bestpw;
  210.         }
  211.         }
  212.     }
  213.     }
  214.     return bestpw;
  215. }
  216.  
  217. struct passwd  *getpwwho (name)
  218. char   *name;
  219. {
  220.     struct passwd *pw;
  221.  
  222.     /* initialize a few things */
  223.     MatchLevel = -1;
  224.     Matches = 0;
  225.     ExactFirst = ExactLast = 0;
  226.     ambigstate = -1;
  227.  
  228.     /* NULL for a name is a no-op...used to clear some internal state */
  229.     if (name == NULL)
  230.     return (struct passwd *) 0;
  231.  
  232.     /* break down the probe name for comparisons */
  233.     BreakDown(name,FirstPart,LastPart);
  234.  
  235.     /* now search thru the password file for Matches */
  236.     setpwent();
  237.     pw = scanpw(0);
  238.     endpwent();
  239.  
  240.     /* see what we got */
  241.     if (Matches == 0)
  242.     return (struct passwd *)0;
  243.     else if (Matches == 1)
  244.     return pw;
  245.     ambigstate = 0;
  246.     return (struct passwd *)-1;
  247. }
  248.  
  249. struct passwd  *getpwambig ()
  250. {
  251.     struct passwd *pw;
  252.  
  253.     if (ambigstate < 0)
  254.     return 0;
  255.     if (ambigstate++ == 0) {
  256.     Matches = 0;
  257.     setpwent();
  258.     }
  259.     pw = scanpw(1);
  260.     if (pw == 0) {
  261.     ambigstate = -1;
  262.     endpwent();
  263.     }
  264.     return pw;
  265. }
  266.  
  267. static namecheck(a,b,exact)
  268. char *a, *b;
  269. int exact;
  270. {
  271.     if (exact) return(strcasecmp(a,b) == 0);
  272.     if (*b == 0) return 1;
  273.     return(strncasecmp(a,b,strlen(b)) == 0);
  274. }
  275.