1/*++
2/* NAME
3/*	dict_unix 3
4/* SUMMARY
5/*	dictionary manager interface to UNIX tables
6/* SYNOPSIS
7/*	#include <dict_unix.h>
8/*
9/*	DICT	*dict_unix_open(map, dummy, dict_flags)
10/*	const char *map;
11/*	int	dummy;
12/*	int	dict_flags;
13/* DESCRIPTION
14/*	dict_unix_open() makes the specified UNIX table accessible via
15/*	the generic dictionary operations described in dict_open(3).
16/*	The \fIdummy\fR argument is not used.
17/*
18/*	Known map names:
19/* .IP passwd.byname
20/*	The table is the UNIX password database. The key is a login name.
21/*	The result is a password file entry in passwd(5) format.
22/* .IP group.byname
23/*	The table is the UNIX group database. The key is a group name.
24/*	The result is a group file entry in group(5) format.
25/* SEE ALSO
26/*	dict(3) generic dictionary manager
27/* DIAGNOSTICS
28/*	Fatal errors: out of memory, unknown map name, attempt to update map.
29/* LICENSE
30/* .ad
31/* .fi
32/*	The Secure Mailer license must be distributed with this software.
33/* AUTHOR(S)
34/*	Wietse Venema
35/*	IBM T.J. Watson Research
36/*	P.O. Box 704
37/*	Yorktown Heights, NY 10598, USA
38/*--*/
39
40/* System library. */
41
42#include "sys_defs.h"
43#include <unistd.h>
44#include <errno.h>
45#include <string.h>
46#include <pwd.h>
47#include <grp.h>
48
49/* Utility library. */
50
51#include "msg.h"
52#include "mymalloc.h"
53#include "vstring.h"
54#include "stringops.h"
55#include "dict.h"
56#include "dict_unix.h"
57
58/* Application-specific. */
59
60typedef struct {
61    DICT    dict;			/* generic members */
62} DICT_UNIX;
63
64/* dict_unix_getpwnam - find password table entry */
65
66static const char *dict_unix_getpwnam(DICT *dict, const char *key)
67{
68    struct passwd *pwd;
69    static VSTRING *buf;
70    static int sanity_checked;
71
72    dict->error = 0;
73
74    /*
75     * Optionally fold the key.
76     */
77    if (dict->flags & DICT_FLAG_FOLD_FIX) {
78	if (dict->fold_buf == 0)
79	    dict->fold_buf = vstring_alloc(10);
80	vstring_strcpy(dict->fold_buf, key);
81	key = lowercase(vstring_str(dict->fold_buf));
82    }
83    if ((pwd = getpwnam(key)) == 0) {
84	if (sanity_checked == 0) {
85	    sanity_checked = 1;
86	    errno = 0;
87	    if (getpwuid(0) == 0) {
88		msg_warn("cannot access UNIX password database: %m");
89		dict->error = DICT_ERR_RETRY;
90	    }
91	}
92	return (0);
93    } else {
94	if (buf == 0)
95	    buf = vstring_alloc(10);
96	sanity_checked = 1;
97	vstring_sprintf(buf, "%s:%s:%ld:%ld:%s:%s:%s",
98			pwd->pw_name, pwd->pw_passwd, (long) pwd->pw_uid,
99			(long) pwd->pw_gid, pwd->pw_gecos, pwd->pw_dir,
100			pwd->pw_shell);
101	return (vstring_str(buf));
102    }
103}
104
105/* dict_unix_getgrnam - find group table entry */
106
107static const char *dict_unix_getgrnam(DICT *dict, const char *key)
108{
109    struct group *grp;
110    static VSTRING *buf;
111    char  **cpp;
112    static int sanity_checked;
113
114    dict->error = 0;
115
116    /*
117     * Optionally fold the key.
118     */
119    if (dict->flags & DICT_FLAG_FOLD_FIX) {
120	if (dict->fold_buf == 0)
121	    dict->fold_buf = vstring_alloc(10);
122	vstring_strcpy(dict->fold_buf, key);
123	key = lowercase(vstring_str(dict->fold_buf));
124    }
125    if ((grp = getgrnam(key)) == 0) {
126	if (sanity_checked == 0) {
127	    sanity_checked = 1;
128	    errno = 0;
129	    if (getgrgid(0) == 0) {
130		msg_warn("cannot access UNIX group database: %m");
131		dict->error = DICT_ERR_RETRY;
132	    }
133	}
134	return (0);
135    } else {
136	if (buf == 0)
137	    buf = vstring_alloc(10);
138	sanity_checked = 1;
139	vstring_sprintf(buf, "%s:%s:%ld:",
140			grp->gr_name, grp->gr_passwd, (long) grp->gr_gid);
141	for (cpp = grp->gr_mem; *cpp; cpp++) {
142	    vstring_strcat(buf, *cpp);
143	    if (cpp[1])
144		VSTRING_ADDCH(buf, ',');
145	}
146	VSTRING_TERMINATE(buf);
147	return (vstring_str(buf));
148    }
149}
150
151/* dict_unix_close - close UNIX map */
152
153static void dict_unix_close(DICT *dict)
154{
155    if (dict->fold_buf)
156	vstring_free(dict->fold_buf);
157    dict_free(dict);
158}
159
160/* dict_unix_open - open UNIX map */
161
162DICT   *dict_unix_open(const char *map, int open_flags, int dict_flags)
163{
164    DICT_UNIX *dict_unix;
165    struct dict_unix_lookup {
166	char   *name;
167	const char *(*lookup) (DICT *, const char *);
168    };
169    static struct dict_unix_lookup dict_unix_lookup[] = {
170	"passwd.byname", dict_unix_getpwnam,
171	"group.byname", dict_unix_getgrnam,
172	0,
173    };
174    struct dict_unix_lookup *lp;
175
176    /*
177     * Sanity checks.
178     */
179    if (open_flags != O_RDONLY)
180	return (dict_surrogate(DICT_TYPE_UNIX, map, open_flags, dict_flags,
181			       "%s:%s map requires O_RDONLY access mode",
182			       DICT_TYPE_UNIX, map));
183
184    /*
185     * "Open" the database.
186     */
187    for (lp = dict_unix_lookup; /* void */ ; lp++) {
188	if (lp->name == 0)
189	    return (dict_surrogate(DICT_TYPE_UNIX, map, open_flags, dict_flags,
190			      "unknown table: %s:%s", DICT_TYPE_UNIX, map));
191	if (strcmp(map, lp->name) == 0)
192	    break;
193    }
194    dict_unix = (DICT_UNIX *) dict_alloc(DICT_TYPE_UNIX, map,
195					 sizeof(*dict_unix));
196    dict_unix->dict.lookup = lp->lookup;
197    dict_unix->dict.close = dict_unix_close;
198    dict_unix->dict.flags = dict_flags | DICT_FLAG_FIXED;
199    if (dict_flags & DICT_FLAG_FOLD_FIX)
200	dict_unix->dict.fold_buf = vstring_alloc(10);
201    dict_unix->dict.owner.status = DICT_OWNER_TRUSTED;
202
203    return (DICT_DEBUG (&dict_unix->dict));
204}
205