1/*
2 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (c) 1996,1999 by Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#if defined(LIBC_SCCS) && !defined(lint)
19static const char rcsid[] = "$Id: nis_pw.c,v 1.4 2005/04/27 04:56:33 sra Exp $";
20#endif /* LIBC_SCCS and not lint */
21
22/* Imports */
23
24#include "port_before.h"
25
26#if !defined(WANT_IRS_PW) || !defined(WANT_IRS_NIS)
27static int __bind_irs_pw_unneeded;
28#else
29
30#include <sys/param.h>
31#include <sys/types.h>
32#include <netinet/in.h>
33#include <arpa/nameser.h>
34#include <resolv.h>
35#include <isc/memcluster.h>
36#include <rpc/rpc.h>
37#include <rpc/xdr.h>
38#include <rpcsvc/yp_prot.h>
39#include <rpcsvc/ypclnt.h>
40
41#include <errno.h>
42#include <fcntl.h>
43#include <pwd.h>
44#include <stdio.h>
45#include <stdlib.h>
46#include <string.h>
47#include <unistd.h>
48
49#include <isc/memcluster.h>
50
51#include <irs.h>
52
53#include "port_after.h"
54
55#include "irs_p.h"
56#include "nis_p.h"
57
58/* Definitions */
59
60struct pvt {
61	int		needrewind;
62	char *		nis_domain;
63	char *		curkey_data;
64	int		curkey_len;
65	char *		curval_data;
66	int		curval_len;
67	struct passwd 	passwd;
68	char *		pwbuf;
69};
70
71enum do_what { do_none = 0x0, do_key = 0x1, do_val = 0x2, do_all = 0x3 };
72
73static /*const*/ char passwd_byname[] =	"passwd.byname";
74static /*const*/ char passwd_byuid[] =	"passwd.byuid";
75
76/* Forward */
77
78static void			pw_close(struct irs_pw *);
79static struct passwd *		pw_next(struct irs_pw *);
80static struct passwd *		pw_byname(struct irs_pw *, const char *);
81static struct passwd *		pw_byuid(struct irs_pw *, uid_t);
82static void			pw_rewind(struct irs_pw *);
83static void			pw_minimize(struct irs_pw *);
84
85static struct passwd *		makepasswdent(struct irs_pw *);
86static void			nisfree(struct pvt *, enum do_what);
87
88/* Public */
89
90struct irs_pw *
91irs_nis_pw(struct irs_acc *this) {
92	struct irs_pw *pw;
93	struct pvt *pvt;
94
95        if (!(pw = memget(sizeof *pw))) {
96                errno = ENOMEM;
97                return (NULL);
98        }
99        memset(pw, 0x5e, sizeof *pw);
100        if (!(pvt = memget(sizeof *pvt))) {
101                memput(pw, sizeof *pw);
102                errno = ENOMEM;
103                return (NULL);
104        }
105        memset(pvt, 0, sizeof *pvt);
106	pvt->needrewind = 1;
107	pvt->nis_domain = ((struct nis_p *)this->private)->domain;
108	pw->private = pvt;
109	pw->close = pw_close;
110	pw->next = pw_next;
111	pw->byname = pw_byname;
112	pw->byuid = pw_byuid;
113	pw->rewind = pw_rewind;
114	pw->minimize = pw_minimize;
115	pw->res_get = NULL;
116	pw->res_set = NULL;
117	return (pw);
118}
119
120/* Methods */
121
122static void
123pw_close(struct irs_pw *this) {
124	struct pvt *pvt = (struct pvt *)this->private;
125
126	if (pvt->pwbuf)
127		free(pvt->pwbuf);
128	nisfree(pvt, do_all);
129	memput(pvt, sizeof *pvt);
130	memput(this, sizeof *this);
131}
132
133static struct passwd *
134pw_next(struct irs_pw *this) {
135	struct pvt *pvt = (struct pvt *)this->private;
136	struct passwd *rval;
137	int r;
138
139	do {
140		if (pvt->needrewind) {
141			nisfree(pvt, do_all);
142			r = yp_first(pvt->nis_domain, passwd_byname,
143				     &pvt->curkey_data, &pvt->curkey_len,
144				     &pvt->curval_data, &pvt->curval_len);
145			pvt->needrewind = 0;
146		} else {
147			char *newkey_data;
148			int newkey_len;
149
150			nisfree(pvt, do_val);
151			r = yp_next(pvt->nis_domain, passwd_byname,
152				    pvt->curkey_data, pvt->curkey_len,
153				    &newkey_data, &newkey_len,
154				    &pvt->curval_data, &pvt->curval_len);
155			nisfree(pvt, do_key);
156			pvt->curkey_data = newkey_data;
157			pvt->curkey_len = newkey_len;
158		}
159		if (r != 0) {
160			errno = ENOENT;
161			return (NULL);
162		}
163		rval = makepasswdent(this);
164	} while (rval == NULL);
165	return (rval);
166}
167
168static struct passwd *
169pw_byname(struct irs_pw *this, const char *name) {
170	struct pvt *pvt = (struct pvt *)this->private;
171	int r;
172	char *tmp;
173
174	nisfree(pvt, do_val);
175	DE_CONST(name, tmp);
176	r = yp_match(pvt->nis_domain, passwd_byname, tmp, strlen(tmp),
177		     &pvt->curval_data, &pvt->curval_len);
178	if (r != 0) {
179		errno = ENOENT;
180		return (NULL);
181	}
182	return (makepasswdent(this));
183}
184
185static struct passwd *
186pw_byuid(struct irs_pw *this, uid_t uid) {
187	struct pvt *pvt = (struct pvt *)this->private;
188	char tmp[sizeof "4294967295"];
189	int r;
190
191	nisfree(pvt, do_val);
192	(void) sprintf(tmp, "%u", (unsigned int)uid);
193	r = yp_match(pvt->nis_domain, passwd_byuid, tmp, strlen(tmp),
194		     &pvt->curval_data, &pvt->curval_len);
195	if (r != 0) {
196		errno = ENOENT;
197		return (NULL);
198	}
199	return (makepasswdent(this));
200}
201
202static void
203pw_rewind(struct irs_pw *this) {
204	struct pvt *pvt = (struct pvt *)this->private;
205
206	pvt->needrewind = 1;
207}
208
209static void
210pw_minimize(struct irs_pw *this) {
211	UNUSED(this);
212	/* NOOP */
213}
214
215/* Private */
216
217static struct passwd *
218makepasswdent(struct irs_pw *this) {
219	struct pvt *pvt = (struct pvt *)this->private;
220	char *cp;
221
222	memset(&pvt->passwd, 0, sizeof pvt->passwd);
223	if (pvt->pwbuf)
224		free(pvt->pwbuf);
225	pvt->pwbuf = pvt->curval_data;
226	pvt->curval_data = NULL;
227
228	cp = pvt->pwbuf;
229	pvt->passwd.pw_name = cp;
230	if (!(cp = strchr(cp, ':')))
231		goto cleanup;
232#ifdef HAS_PW_CLASS
233	pvt->passwd.pw_class = cp;	/*%< Needs to point at a \0. */
234#endif
235	*cp++ = '\0';
236
237	pvt->passwd.pw_passwd = cp;
238	if (!(cp = strchr(cp, ':')))
239		goto cleanup;
240	*cp++ = '\0';
241
242	pvt->passwd.pw_uid = atoi(cp);
243	if (!(cp = strchr(cp, ':')))
244		goto cleanup;
245	*cp++ = '\0';
246
247	pvt->passwd.pw_gid = atoi(cp);
248	if (!(cp = strchr(cp, ':')))
249		goto cleanup;
250	*cp++ = '\0';
251
252	pvt->passwd.pw_gecos = cp;
253	if (!(cp = strchr(cp, ':')))
254		goto cleanup;
255	*cp++ = '\0';
256
257	pvt->passwd.pw_dir = cp;
258	if (!(cp = strchr(cp, ':')))
259		goto cleanup;
260	*cp++ = '\0';
261
262	pvt->passwd.pw_shell = cp;
263
264	if ((cp = strchr(cp, '\n')) != NULL)
265		*cp = '\0';
266
267	return (&pvt->passwd);
268
269 cleanup:
270	free(pvt->pwbuf);
271	pvt->pwbuf = NULL;
272	return (NULL);
273}
274
275static void
276nisfree(struct pvt *pvt, enum do_what do_what) {
277	if ((do_what & do_key) && pvt->curkey_data) {
278		free(pvt->curkey_data);
279		pvt->curkey_data = NULL;
280	}
281	if ((do_what & do_val) && pvt->curval_data) {
282		free(pvt->curval_data);
283		pvt->curval_data = NULL;
284	}
285}
286
287#endif /* WANT_IRS_PW && WANT_IRS_NIS */
288/*! \file */
289