/*
#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 <sys/types.h>
#include <sys/param.h>
#include <stdio.h>
#include <ctype.h>
#include <limits.h>
#include <grp.h>
#include <pwd.h>
#include <utmp.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif
#if defined(HAVE_UNISTD_H)
# include <unistd.h>
#endif
#ifdef HAVE_STRING_H
# if !defined(STDC_HEADERS) && defined(HAVE_MEMORY_H)
# include <memory.h>
# endif
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#ifdef __STDC__
# include <stdarg.h>
#else
# include <varargs.h>
#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:
*/
syntax highlighted by Code2HTML, v. 0.9.1