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