# /* getpw.c * * Get all the usernames and login directories from the password file. * Store them in a calloc'ed array. This is an efficiency hack to * avoid having to read through the entire password file each time * a message is delivered. To increase the speed, the array is * sorted by uname so binary searching will work. * getpwf is also responsible for finding the Daemon's user name in * the password file and storing it in the external array me. */ #include #include #include "rqfile.h" #include "extern.h" #define NOPWENT 256 /* max. password entries */ struct pwent { /* saved contents of password file */ char *pw_name; /* user name */ char *pw_hdir; /* home directory */ } entries[NOPWENT]; char pwfile[] = "/etc/passwd"; /* password file name */ int pwmod[2]; /* password file modified time */ int npwent; /* number of password file entries */ int pwcmp (); /* password compare routine */ getpwf () { register struct pwent *pwp; /* ptr. to current password ent. */ register char *cp; /* ptr. to current alloc. */ FILE *fpasswd; /* password file */ char line[NAMSIZ]; /* password file line */ char name[NAMSIZ]; /* current username */ char hdir[NAMSIZ]; /* his home directory */ int nsiz, dsiz; /* name & directory lengths */ struct inode buf; /* buffer for stat call */ int myuid, uid; /* daemon's uid, current uid */ if ((stat (pwfile, &buf)) < 0) faterr ("can't find password file\n"); pwmod[0] = buf.modtime[0]; pwmod[1] = buf.modtime[1]; myuid = getuid(); if ( (fpasswd = fopen(pwfile,"r")) == NULL) faterr ("can't open password file\n"); pwp = entries; npwent = 0; while (fgets(line, sizeof(line), fpasswd) != NULL) { sscanf(line, "%32[^:]:%*[^:]:%d:%*[^:]:%*[^:]:%32[^:]:%*s", name, &uid, hdir); if (uid == myuid) /* is this my entry? */ strcpy (me, name); /* yes; save my name */ nsiz = strlen (name); dsiz = strlen (hdir); if ((cp = alloc (nsiz + dsiz + 2)) == -1) faterr ("can't alloc for password file\n"); pwp->pw_name = cp; lccpy (cp, name); cp += nsiz + 1; pwp->pw_hdir = cp; strcpy (cp, hdir); if (++pwp >= &entries[NOPWENT]) faterr ("password file too large\n"); npwent++; } fclose (fpasswd); qsort (entries, npwent, sizeof (struct pwent), &pwcmp); } /* Check if password file was modified; if so, update saved password entries. * Called each time the mail daemon is awakened. */ chkpwd () { struct inode buf; /* buf for stat call */ register struct pwent *pwp; /* ptr. to current password ent. */ register int i; /* index in entries array */ if ((stat (pwfile, &buf)) < 0) faterr ("can't find password file\n"); if (pwmod[0] == buf.modtime[0] && pwmod[1] == buf.modtime[1]) return; for (pwp = entries, i = 0; i < npwent; i++, pwp++) { free (pwp->pw_name); pwp->pw_name = NULL; pwp->pw_hdir = NULL; } getpwf (); } /* Find the password file entry for the specified user, if one exists. * Return that user's home directory, or NULL if no such user exists. * Uses a binary search for speed. */ getpwent (uname, hdir) char *uname; /* user name to be found */ char *hdir; /* user's home directory */ { register int pwp; /* password entry index */ struct pwent pe; /* temp entry for compares */ pe.pw_name = uname; pe.pw_hdir = hdir; if ((pwp = binsrch ((char *)&pe, (char *)entries, npwent, sizeof (struct pwent), &pwcmp)) == -1) return (NULL); strcpy (hdir, entries[pwp].pw_hdir); return (hdir); } /* Compare two password entries on the uname field. Returns <, =, or * > 0 as the first uname is lexically less than, equal to, or greater * than the second. */ pwcmp (pent1, pent2) register struct pwent *pent1; register struct pwent *pent2; { return (lwccmp (&pent1->pw_name, &pent2->pw_name)); } #define tolower(c) ((c) >= 'A' && (c) <= 'Z' ? (c) + 'a' - 'A' : (c)) /* Lower-case copy a string. Used for user names - all are mapped into * lower-case. */ lccpy(to, from) register char *to, *from; { while (*from != '\0') { *to++ = tolower(*from); from++; } *to = '\0'; }