/* #ident "@(#)smail/src:RELEASE-3_2_0_121:pwcache.c,v 1.32 2005/07/11 19:22:09 woods Exp" */ /* * Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll * Copyright (C) 1992 Ronald S. Karr * * See the file COPYING, distributed with smail, for restriction * and warranty information. */ /* * pwcache: * manage a passwd and group entry cache. * * The mailer can make a large number of acesses to the passwd and * group files while processing a message. To increase the efficiency * of this, we maintain a cache of entries read from each of these * files. */ #include "defs.h" #include #include #include #include #include #include #include #include #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #if defined(HAVE_UNISTD_H) # include #endif #ifdef HAVE_STRING_H # if !defined(STDC_HEADERS) && defined(HAVE_MEMORY_H) # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef __STDC__ # include #else # include #endif #include "smail.h" #include "alloc.h" #include "list.h" #include "main.h" #include "addr.h" #include "exitcodes.h" #include "log.h" #include "hash.h" #include "smailstring.h" #include "dys.h" #include "extern.h" #include "debug.h" #include "smailport.h" /* functions local to this file */ static void fill_pw_cache __P((struct passwd *)); static void fill_gr_cache __P((struct group *)); /* * There are separate caches for four mappings: * * uid->username gid->groupname username->uid groupname->gid */ /* number of entries in each cache */ #ifdef SMALL_MEMORY # define N_CACHE 16 #else # define N_CACHE 128 #endif /* invalid names will begin with this char */ #define BAD_NAME (':') /* XXX assumes unix passwd format */ /* invalid ID's are set to this ID */ #define BAD_ID BOGUS_USER /* should be (-1) */ static struct hash_table *uid_cache = NULL; /* uid->username cache */ static struct hash_table *gid_cache = NULL; /* gid->groupname cache */ static struct hash_table *user_cache = NULL; /* username->uid cache */ static struct hash_table *group_cache = NULL; /* groupname->gid cache */ static struct passwd pwbyid_ret; /* * uid->username, through cache */ struct passwd * getpwbyuid(uid) uid_t uid; { struct passwd *entp; static char uid_buf[MAXLONG_B10_DIGITS + 1]; if (uid_cache == NULL) { uid_cache = new_hash_table(N_CACHE, (struct block *) NULL, /* XXX pwcache block */ HASH_DEFAULT); } (void) sprintf(uid_buf, "%u", (unsigned int) uid); if (lookup_in_hash(uid_buf, (void **) &entp, (size_t *) NULL, uid_cache) == ALREADY_HASHED) { if (entp->pw_name[0] == BAD_NAME) { return NULL; } pwbyid_ret = *entp; /* use our own local storage */ return &pwbyid_ret; } else { struct passwd ent; /* may add to uid_cache as BAD_NAME */ register struct passwd *pw; setpwent(); pw = getpwuid(uid); if (! pw) { ent.pw_uid = uid; ent.pw_name[0] = BAD_NAME; (void) add_to_hash(uid_buf, (void *) &ent, sizeof(ent), uid_cache); return NULL; } if (user_cache == NULL) { user_cache = new_hash_table(N_CACHE, (struct block *) NULL, /* XXX pwcache block */ HASH_DEFAULT); } fill_pw_cache(pw); pwbyid_ret = *pw; /* use our own local storage */ return &pwbyid_ret; } } static struct group grbyid_ret; /* * gid->groupname, through cache */ struct group * getgrbygid(gid) gid_t gid; { struct group *entp; static char gid_buf[MAXLONG_B10_DIGITS + 1]; if (gid_cache == NULL) { gid_cache = new_hash_table(N_CACHE, (struct block *) NULL, /* XXX grcache block */ HASH_DEFAULT); } (void) sprintf(gid_buf, "%u", (unsigned int) gid); if (lookup_in_hash(gid_buf, (void **) &entp, (size_t *) NULL, gid_cache) == ALREADY_HASHED) { if (entp->gr_name[0] == BAD_NAME) { return NULL; } grbyid_ret = *entp; /* use our own local storage */ return &grbyid_ret; } else { struct group ent; /* may add to gid_cache as BAD_NAME */ register struct group *gr; setgrent(); gr = getgrgid(gid); if (! gr) { ent.gr_gid = gid; ent.gr_name[0] = BAD_NAME; (void) add_to_hash(gid_buf, (void *) &ent, sizeof(ent), gid_cache); return NULL; } if (group_cache == NULL) { group_cache = new_hash_table(N_CACHE, (struct block *) NULL, /* XXX grcache block */ HASH_DEFAULT); } fill_gr_cache(gr); grbyid_ret = *gr; /* use our own local storage */ return &grbyid_ret; } } static struct passwd pwbynm_ret; /* * username->uid, through cache */ struct passwd * getpwbyname(icase, user) int icase; char *user; { struct passwd *entp; DEBUG2(DBG_HASH_HI, "getpwbyname(): called for %s username: '%s'\n", icase ? "caseless" : "exact", user); if (user_cache == NULL) { user_cache = new_hash_table(N_CACHE, (struct block *) NULL, /* XXX pwcache block */ HASH_DEFAULT); } if (lookup_in_hash(user, (void **) &entp, (size_t *) NULL, user_cache) == ALREADY_HASHED) { if (entp->pw_uid == BAD_ID) { DEBUG1(DBG_HASH_HI, "getpwbyname(): found previously cached BAD_ID: '%s'\n", user); return NULL; } pwbynm_ret = *entp; /* use our own local storage */ return &pwbynm_ret; } else { struct passwd ent; /* may add to user_cache as BAD_ID */ register struct passwd *pw; ent.pw_name = COPY_STRING(user); if (icase) { str2lower(ent.pw_name); } setpwent(); pw = getpwnam(ent.pw_name); if (! pw) { DEBUG1(DBG_HASH_MID, "getpwbyname(): caching invalid username: '%s'\n", user); ent.pw_uid = BAD_ID; (void) add_to_hash(user, (void *) &ent, sizeof(ent), user_cache); return NULL; } if (uid_cache == NULL) { uid_cache = new_hash_table(N_CACHE, (struct block *) NULL, /* XXX pwcache block */ HASH_DEFAULT); } fill_pw_cache(pw); pwbynm_ret = *pw; /* use our own local storage */ xfree(ent.pw_name); return &pwbynm_ret; } } static struct group grbynm_ret; /* * groupname->gid, through cache */ struct group * getgrbyname(group) char *group; { struct group *entp; if (group_cache == NULL) { group_cache = new_hash_table(N_CACHE, (struct block *) NULL, /* XXX grcache block */ HASH_DEFAULT); } if (lookup_in_hash(group, (void **) &entp, (size_t *) NULL, group_cache) == ALREADY_HASHED) { if (entp->gr_gid == BAD_ID) { DEBUG1(DBG_HASH_HI, "getgrbyname(): found previously cached BAD_ID: '%s'\n", group); return NULL; } grbynm_ret = *entp; /* use our own local storage */ return &grbynm_ret; } else { struct group ent; /* may add to group_cache as BAD_ID */ register struct group *gr; ent.gr_name = group; setgrent(); gr = getgrnam(ent.gr_name); if (! gr) { DEBUG1(DBG_HASH_MID, "getgrbyname(): caching invalid groupname: '%s'\n", group); ent.gr_gid = BAD_ID; (void) add_to_hash(group, (void *) &ent, sizeof(ent), group_cache); return NULL; } if (gid_cache == NULL) { gid_cache = new_hash_table(N_CACHE, (struct block *) NULL, /* XXX grcache block */ HASH_DEFAULT); } fill_gr_cache(gr); grbynm_ret = *gr; /* use our own local storage */ return &grbynm_ret; } } /* fill the uid and username caches from a passwd file entry */ static void fill_pw_cache(pw) register struct passwd *pw; { struct passwd newpw; char uid_buf[MAXLONG_B10_DIGITS + 1]; /* NOTE: only fills the fields we care about... */ memset((void *) &newpw, '\0', sizeof(newpw)); newpw.pw_name = COPY_STRING(pw->pw_name); /* XXX alloc in pwcache block... */ newpw.pw_gecos = COPY_STRING(pw->pw_gecos); /* XXX alloc in pwcache block... */ newpw.pw_uid = pw->pw_uid; newpw.pw_gid = pw->pw_gid; newpw.pw_dir = COPY_STRING(pw->pw_dir); /* XXX alloc in pwcache block... */ (void) add_to_hash(pw->pw_name, (void *) &newpw, sizeof(newpw), user_cache); (void) sprintf(uid_buf, "%u", (unsigned int) pw->pw_uid); (void) add_to_hash(uid_buf, (void *) &newpw, sizeof(newpw), uid_cache); return; } /* fill the gid and groupname caches from a group file entry */ static void fill_gr_cache(gr) register struct group *gr; { struct group newgr; char gid_buf[MAXLONG_B10_DIGITS + 1]; /* NOTE: only fills the fields we care about... */ memset((void *) &newgr, '\0', sizeof(newgr)); newgr.gr_name = COPY_STRING(gr->gr_name); /* XXX alloc in grcache block... */ newgr.gr_gid = gr->gr_gid; (void) add_to_hash(gr->gr_name, (void *) &newgr, sizeof(newgr), group_cache); (void) sprintf(gid_buf, "%u", (unsigned int) gr->gr_gid); (void) add_to_hash(gid_buf, (void *) &newgr, sizeof(newgr), gid_cache); return; } /* * Local Variables: * c-file-style: "smail" * End: */