/*
** Copyright 1998 - 2007 Double Precision, Inc.
** See COPYING for distribution information.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "dbobj.h"
#include "userdb.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <time.h>
#include <sys/types.h>
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
static const char rcsid[]="$Id: userdb.c,v 1.10 2007/04/14 03:02:46 mrsam Exp $";
static struct dbobj d;
static time_t dt;
static ino_t di;
static int initialized=0;
int userdb_debug_level=0;
/* Open userdb.dat, if already opened, see if it changed, if so reopen */
void userdb_init(const char *n)
{
struct stat stat_buf;
if (initialized)
{
if (stat(n, &stat_buf) ||
stat_buf.st_mtime != dt ||
stat_buf.st_ino != di)
{
dbobj_close(&d);
initialized=0;
dt=stat_buf.st_mtime;
di=stat_buf.st_ino;
}
}
else if (stat(n, &stat_buf))
{
if (userdb_debug_level)
fprintf(stderr,
"DEBUG: userdb: unable to stat %s: %s\n",
n, strerror(errno));
return;
}
else
{
dt=stat_buf.st_mtime;
di=stat_buf.st_ino;
}
if (!initialized)
{
if (dbobj_open(&d, n, "R"))
{
if (userdb_debug_level)
fprintf(stderr,
"DEBUG: userdb: failed to open %s\n",
n);
return;
}
if (userdb_debug_level)
fprintf(stderr, "DEBUG: userdb: opened %s\n", n);
initialized=1;
}
}
void userdb_close()
{
if (initialized)
{
dbobj_close(&d);
initialized=0;
}
userdb_debug_level=0;
}
void userdb_set_debug(int lvl)
{
userdb_debug_level = lvl;
}
/* Fetch a record from userdb.dat */
char *userdb(const char *u)
{
char *p,*q;
size_t l;
if (!initialized)
{
errno=ENOENT;
return (0);
}
q=dbobj_fetch(&d, u, strlen(u), &l, "");
if (!q)
{
if (userdb_debug_level)
fprintf(stderr, "DEBUG: userdb: entry not found\n");
errno=ENOENT;
return(0);
}
p=malloc(l+1);
if (!p)
{
free(q);
return (0);
}
if (l) memcpy(p, q, l);
free(q);
p[l]=0;
return (p);
}
/* Return a pointer to a specific field in this record */
const char *userdb_get(const char *u, const char *n, int *l)
{
int nl=strlen(n);
while (u && *u)
{
if (memcmp(u, n, nl) == 0 &&
(u[nl] == 0 || u[nl] == '=' || u[nl] == '|'))
{
u += nl;
*l=0;
if (*u == '=')
{
++u;
while ( u[*l] && u[*l] != '|')
++ *l;
}
return (u);
}
u=strchr(u, '|');
if (u) ++u;
}
return (0);
}
/* Extract field as an unsigned int */
unsigned userdb_getu(const char *u, const char *n, unsigned defnum)
{
int l;
const char *p;
if ((p=userdb_get(u, n, &l)) != 0)
{
defnum=0;
while (l && *p >= '0' && *p <= '9')
{
defnum = defnum * 10 + (*p++ - '0');
--l;
}
}
return (defnum);
}
/* Extract a field into a dynamically allocated buffer */
char *userdb_gets(const char *u, const char *n)
{
int l;
const char *p;
char *q;
if ((p=userdb_get(u, n, &l)) != 0)
{
q=malloc(l+1);
if (!q)
return (0);
if (l) memcpy(q, p, l);
q[l]=0;
return (q);
}
errno=ENOENT;
return (0);
}
/* Create a userdbs structure based upon a uid (reverse lookup) */
struct userdbs *userdb_createsuid(uid_t u)
{
char buf[80];
char *p=buf+sizeof(buf)-1, *q;
struct userdbs *s;
/* Lookup uid= record */
*p=0;
*--p='=';
do
{
*--p= "0123456789"[u % 10];
u=u/10;
} while (u);
p=userdb(p);
if (!p) return (0);
/* Have account name, now look it up. */
q=userdb(p);
if (!q)
{
free(p);
return (0);
}
s=userdb_creates(q);
if (s)
s->udb_name=p;
else
free(p);
free(q);
return (s);
}
static struct userdbs *userdb_enum(char *key, size_t keylen,
char *val, size_t vallen)
{
if (key)
{
char *valz=malloc(vallen+1);
if (valz)
{
struct userdbs *udbs;
memcpy(valz, val, vallen);
valz[vallen]=0;
udbs=userdb_creates(valz);
if (udbs)
{
if ((udbs->udb_name=malloc(keylen+1)) != NULL)
{
memcpy(udbs->udb_name, key, keylen);
udbs->udb_name[keylen]=0;
free(valz);
return udbs;
}
userdb_frees(udbs);
}
free(valz);
}
}
return NULL;
}
struct userdbs *userdb_enum_first()
{
char *val;
size_t vallen;
size_t keylen;
char *key=dbobj_firstkey(&d, &keylen, &val, &vallen);
if (key)
{
struct userdbs *udbs=userdb_enum(key, keylen, val, vallen);
free(val);
if (udbs)
return udbs;
/* Could be a reverse UID entry */
return userdb_enum_next();
}
return NULL;
}
struct userdbs *userdb_enum_next()
{
char *val;
size_t vallen;
size_t keylen;
char *key;
while ((key=dbobj_nextkey(&d, &keylen, &val, &vallen)) != NULL)
{
struct userdbs *udbs=userdb_enum(key, keylen, val, vallen);
free(val);
if (udbs)
return udbs;
}
return NULL;
}
/* Extracted a userdb.dat record, convert it to a userdbs structure */
struct userdbs *userdb_creates(const char *u)
{
struct userdbs *udbs=(struct userdbs *)malloc(sizeof(struct userdbs));
char *s;
if (!udbs) return (0);
memset((char *)udbs, 0, sizeof(*udbs));
if ((udbs->udb_dir=userdb_gets(u, "home")) == 0)
{
if (userdb_debug_level)
fprintf(stderr,
"DEBUG: userdb: required value 'home' is missing\n");
userdb_frees(udbs);
return (0);
}
if ((s=userdb_gets(u, "uid")) != 0)
{
udbs->udb_uid=atol(s);
free(s);
if ((s=userdb_gets(u, "gid")) != 0)
{
udbs->udb_gid=atol(s);
free(s);
if ((s=userdb_gets(u, "shell")) != 0)
udbs->udb_shell=s;
else if (errno != ENOENT)
{
userdb_frees(udbs);
return (0);
}
if ((s=userdb_gets(u, "mail")) != 0)
udbs->udb_mailbox=s;
else if (errno != ENOENT)
{
userdb_frees(udbs);
return (0);
}
if ((s=userdb_gets(u, "quota")) != 0)
udbs->udb_quota=s;
else if (errno != ENOENT)
{
userdb_frees(udbs);
return (0);
}
if ((s=userdb_gets(u, "gecos")) != 0)
udbs->udb_gecos=s;
else if (errno != ENOENT)
{
userdb_frees(udbs);
return (0);
}
if ((s=userdb_gets(u, "options")) != 0)
udbs->udb_options=s;
else if (errno != ENOENT)
{
userdb_frees(udbs);
return (0);
}
udbs->udb_source=userdb_gets(u, "_");
if (userdb_debug_level)
fprintf(stderr,
"DEBUG: userdb: home=%s, uid=%ld, gid=%ld, shell=%s, "
"mail=%s, quota=%s, gecos=%s, options=%s\n",
udbs->udb_dir ? udbs->udb_dir : "<unset>",
(long)udbs->udb_uid, (long)udbs->udb_gid,
udbs->udb_shell ? udbs->udb_shell : "<unset>",
udbs->udb_mailbox ? udbs->udb_mailbox : "<unset>",
udbs->udb_quota ? udbs->udb_quota : "<unset>",
udbs->udb_gecos ? udbs->udb_gecos : "<unset>",
udbs->udb_options ? udbs->udb_options : "<unset>");
return (udbs);
}
else
if (userdb_debug_level)
fprintf(stderr,
"DEBUG: userdb: required value 'gid' is missing\n");
}
else
if (userdb_debug_level)
fprintf(stderr,
"DEBUG: userdb: required value 'uid' is missing\n");
userdb_frees(udbs);
return (0);
}
void userdb_frees(struct userdbs *u)
{
if (u->udb_options) free(u->udb_options);
if (u->udb_name) free(u->udb_name);
if (u->udb_gecos) free(u->udb_gecos);
if (u->udb_dir) free(u->udb_dir);
if (u->udb_shell) free(u->udb_shell);
if (u->udb_mailbox) free(u->udb_mailbox);
if (u->udb_quota) free(u->udb_quota);
if (u->udb_source) free(u->udb_source);
free(u);
}
syntax highlighted by Code2HTML, v. 0.9.1