1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  *
25  *	nis/getpwnam.c -- "nis" backend for nsswitch "passwd" database
26  */
27 
28 #include <pwd.h>
29 #include "nis_common.h"
30 
31 static nss_status_t
32 getbyname(be, a)
33 	nis_backend_ptr_t	be;
34 	void			*a;
35 {
36 	nss_XbyY_args_t		*argp = (nss_XbyY_args_t *)a;
37 
38 	return (_nss_nis_lookup(be, argp, 0,
39 				"passwd.byname", argp->key.name, 0));
40 }
41 
42 static nss_status_t
43 getbyuid(be, a)
44 	nis_backend_ptr_t	be;
45 	void			*a;
46 {
47 	nss_XbyY_args_t		*argp = (nss_XbyY_args_t *)a;
48 	char			uidstr[12];	/* More than enough */
49 
50 	if (argp->key.uid > MAXUID)
51 		return (NSS_NOTFOUND);
52 	(void) snprintf(uidstr, 12, "%u", argp->key.uid);
53 	return (_nss_nis_lookup(be, argp, 0, "passwd.byuid", uidstr, 0));
54 }
55 
56 /*
57  * Validates passwd entry replacing uid/gid > MAXUID by ID_NOBODY.
58  */
59 int
60 validate_passwd_ids(char **linepp, int *linelenp, int allocbuf)
61 {
62 	char	*linep, *limit, *uidp, *gidp, *newline;
63 	uid_t	uid;
64 	gid_t	gid;
65 	ulong_t	uidl, gidl;
66 	int	olduidlen, oldgidlen, idlen;
67 	int	linelen = *linelenp, newlinelen;
68 
69 	linep = *linepp;
70 	limit = linep + linelen;
71 
72 	/* +/- entries valid for compat source only */
73 	if (linelen == 0 || *linep == '+' || *linep == '-')
74 		return (NSS_STR_PARSE_SUCCESS);
75 
76 	while (linep < limit && *linep++ != ':') /* skip username */
77 		continue;
78 	while (linep < limit && *linep++ != ':') /* skip password */
79 		continue;
80 	if (linep == limit)
81 		return (NSS_STR_PARSE_PARSE);
82 
83 	uidp = linep;
84 	uidl = strtoul(uidp, (char **)&linep, 10); /* grab uid */
85 	olduidlen = linep - uidp;
86 	if (++linep >= limit || olduidlen == 0)
87 		return (NSS_STR_PARSE_PARSE);
88 
89 	gidp = linep;
90 	gidl = strtoul(gidp, (char **)&linep, 10); /* grab gid */
91 	oldgidlen = linep - gidp;
92 	if (linep >= limit || oldgidlen == 0)
93 		return (NSS_STR_PARSE_PARSE);
94 
95 	if (uidl <= MAXUID && gidl <= MAXUID)
96 		return (NSS_STR_PARSE_SUCCESS);
97 	uid = (uidl > MAXUID) ? UID_NOBODY : (uid_t)uidl;
98 	gid = (gidl > MAXUID) ? GID_NOBODY : (gid_t)gidl;
99 
100 	/* Check if we have enough space in the buffer */
101 	idlen = snprintf(NULL, 0, "%u:%u", uid, gid);
102 	newlinelen = linelen + idlen - olduidlen - oldgidlen - 1;
103 	if (newlinelen > linelen) {
104 		/* need a larger buffer */
105 		if (!allocbuf || (newline = malloc(newlinelen + 1)) == NULL)
106 			return (NSS_STR_PARSE_ERANGE);
107 		/* Replace ephemeral ids by ID_NOBODY in the new buffer */
108 		*(uidp - 1) = '\0';
109 		(void) snprintf(newline, newlinelen + 1, "%s:%u:%u%s",
110 		    *linepp, uid, gid, linep);
111 		free(*linepp);
112 		*linepp = newline;
113 		*linelenp = newlinelen;
114 		return (NSS_STR_PARSE_SUCCESS);
115 	}
116 
117 	/* Replace ephemeral ids by ID_NOBODY in the same buffer */
118 	(void) bcopy(linep, uidp + idlen, limit - linep + 1);
119 	(void) snprintf(uidp, idlen + 1, "%u:%u", uid, gid);
120 	*(uidp + idlen) = ':'; /* restore : that was overwritten by snprintf */
121 	*linelenp = newlinelen;
122 	return (NSS_STR_PARSE_SUCCESS);
123 }
124 
125 static nis_backend_op_t passwd_ops[] = {
126 	_nss_nis_destr,
127 	_nss_nis_endent,
128 	_nss_nis_setent,
129 	_nss_nis_getent_rigid,
130 	getbyname,
131 	getbyuid
132 };
133 
134 /*ARGSUSED*/
135 nss_backend_t *
136 _nss_nis_passwd_constr(dummy1, dummy2, dummy3)
137 	const char	*dummy1, *dummy2, dummy3;
138 {
139 	return (_nss_nis_constr(passwd_ops,
140 				sizeof (passwd_ops) / sizeof (passwd_ops[0]),
141 				"passwd.byname"));
142 }
143