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 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  *	nis/getspent.c -- "nis" backend for nsswitch "shadow" database
27  */
28 
29 #include <shadow.h>
30 #include <string.h>
31 #include "nis_common.h"
32 
33 /*
34  * Most of the information in a struct spwd simply isn't available from the
35  * YP maps, we dummy out all the numeric fields and just get sp_namp and
36  * sp_pwdp (name and password) from the YP passwd map.  Thus we don't
37  * use the str2ent() routine that's passed to us, but instead have our
38  * own dummy routine:
39  *
40  * Return values: 0 = success, 1 = parse error, 2 = erange ...
41  * The structure pointer passed in is a structure in the caller's space
42  * wherein the field pointers would be set to areas in the buffer if
43  * need be. instring and buffer should be separate areas. Let's not
44  * fight over crumbs.
45  */
46 static int
nis_str2spent(instr,lenstr,ent,buffer,buflen)47 nis_str2spent(instr, lenstr, ent, buffer, buflen)
48 	const char		*instr;
49 	int			lenstr;
50 	void	*ent; /* it is really (struct spwd *) */
51 	char	*buffer;
52 	int	buflen;
53 {
54 	struct spwd		*spwd	= (struct spwd *)ent;
55 	char			*p, *q, *r;
56 
57 	/*
58 	 * We know that instr != 0 because we're in 'nis', not 'files'
59 	 */
60 	if ((p = memchr(instr, ':', lenstr)) == 0) {
61 		return (NSS_STR_PARSE_PARSE);
62 	}
63 	if ((q = memchr(p + 1, ':', lenstr - (p + 1 - instr))) == 0) {
64 		return (NSS_STR_PARSE_PARSE);
65 	}
66 	/* Don't bother checking the rest of the YP passwd entry... */
67 
68 	if (q + 1 - instr > buflen) {
69 		return (NSS_STR_PARSE_ERANGE);
70 	}
71 	/*
72 	 * "name:password" is copied
73 	 */
74 	(void) memcpy(buffer, instr, q - instr);
75 	if (spwd) {
76 		buffer[p - instr] = '\0';
77 		buffer[q - instr] = '\0';
78 
79 		spwd->sp_namp	= buffer;
80 		spwd->sp_pwdp	= buffer + (p + 1 - instr);
81 		spwd->sp_lstchg	= -1;
82 		spwd->sp_min	= -1;
83 		spwd->sp_max	= -1;
84 		spwd->sp_warn	= -1;
85 		spwd->sp_inact	= -1;
86 		spwd->sp_expire	= -1;
87 		spwd->sp_flag	= 0;
88 	} else {
89 		/*
90 		 *  NSS2: nscd is running. Return files format.
91 		 *
92 		 *  name:password:::::::
93 		 */
94 		r = buffer + (q - instr);
95 		*r = '\0';
96 		if (strlcat(buffer, ":::::::", buflen) >= buflen)
97 			return (NSS_STR_PARSE_ERANGE);
98 	}
99 	return (NSS_STR_PARSE_SUCCESS);
100 }
101 
102 typedef int	(*cstr2ent_t)(const char *, int, void *, char *, int);
103 
104 static nss_status_t
getbyname(be,a)105 getbyname(be, a)
106 	nis_backend_ptr_t	be;
107 	void			*a;
108 {
109 	nss_XbyY_args_t		*argp = (nss_XbyY_args_t *)a;
110 	cstr2ent_t		save_c2e;
111 	nss_status_t		res;
112 	struct spwd 		*spwd;
113 	char			*p;
114 
115 	save_c2e	= argp->str2ent;
116 	argp->str2ent	= nis_str2spent;
117 	res = _nss_nis_lookup(be, argp, 0, "passwd.byname", argp->key.name, 0);
118 	spwd = (struct spwd *)argp->buf.result;
119 	/*
120 	 * check for the C2 security flag "##" in the passwd field.
121 	 * If the first 2 chars in the passwd field is "##", get
122 	 * the user's passwd from passwd.adjunct.byname map.
123 	 * The lookup to this passwd.adjunct.byname map will only
124 	 * succeed if the caller's uid is 0 because only root user
125 	 * can use privilege port.
126 	 */
127 	if (res == NSS_SUCCESS) {
128 		if (spwd) {
129 			if ((spwd->sp_pwdp) && (*(spwd->sp_pwdp) == '#') &&
130 				(*(spwd->sp_pwdp + 1) == '#')) {
131 			/* get password from passwd.adjunct.byname */
132 				res = _nss_nis_lookup_rsvdport(be, argp, 0,
133 						"passwd.adjunct.byname",
134 						argp->key.name, 0);
135 			}
136 		} else {
137 			/*
138 			 * getent request from nscd
139 			 */
140 			if ((p = memchr(argp->buf.buffer, ':',
141 					argp->buf.buflen)) == NULL)
142 				return (NSS_STR_PARSE_PARSE);
143 			if (strncmp(p + 1, "##", 2) == 0)
144 				/* get password from passwd.adjunct.byname */
145 				res = _nss_nis_lookup_rsvdport(be, argp, 0,
146 						"passwd.adjunct.byname",
147 						argp->key.name, 0);
148 			if (res ==  NSS_SUCCESS) {
149 				argp->returnval = argp->buf.buffer;
150 				argp->returnlen = strlen(argp->buf.buffer);
151 			}
152 		}
153 	}
154 
155 	argp->str2ent	= save_c2e;
156 	return (res);
157 }
158 
159 #define	NIS_SP_GETENT
160 
161 #ifdef	NIS_SP_GETENT
162 
163 static nss_status_t
getent(be,a)164 getent(be, a)
165 	nis_backend_ptr_t	be;
166 	void			*a;
167 {
168 	nss_XbyY_args_t		*argp = (nss_XbyY_args_t *)a;
169 	cstr2ent_t		save_c2e;
170 	nss_status_t		res;
171 	struct spwd 		*spwd;
172 	char			*p;
173 
174 	save_c2e	= argp->str2ent;
175 	argp->str2ent	= nis_str2spent;
176 	res = _nss_nis_getent_rigid(be, argp);
177 	spwd = (struct spwd *)argp->buf.result;
178 	/*
179 	 * check for the C2 security flag "##" in the passwd field.
180 	 * If the first 2 chars in the passwd field is "##", get
181 	 * the user's passwd from passwd.adjunct.byname map.
182 	 * The lookup to this passwd.adjunct.byname map will only
183 	 * succeed if the caller's uid is 0 because only root user
184 	 * can use privilege port.
185 	 */
186 	if (res == NSS_SUCCESS) {
187 		if (spwd) {
188 			if ((spwd->sp_pwdp) && (*(spwd->sp_pwdp) == '#') &&
189 				(*(spwd->sp_pwdp + 1) == '#')) {
190 				/* get password from passwd.adjunct.byname */
191 				res = _nss_nis_lookup_rsvdport(be, argp, 0,
192 					"passwd.adjunct.byname",
193 					spwd->sp_namp, 0);
194 			}
195 		} else {
196 			/*
197 			 * getent request from nscd
198 			 */
199 			if ((p = memchr(argp->buf.buffer, ':',
200 					argp->buf.buflen)) == NULL)
201 				return (NSS_STR_PARSE_PARSE);
202 			if (strncmp(p + 1, "##", 2) == 0) {
203 				/* need the name for the next search */
204 				*p = '\0';
205 				/* get password from passwd.adjunct.byname */
206 				res = _nss_nis_lookup_rsvdport(be, argp, 0,
207 					"passwd.adjunct.byname", p, 0);
208 			}
209 			if (res ==  NSS_SUCCESS) {
210 				argp->returnval = argp->buf.buffer;
211 				argp->returnlen = strlen(argp->buf.buffer);
212 			}
213 		}
214 	}
215 
216 	argp->str2ent	= save_c2e;
217 	return (res);
218 }
219 
220 #endif	/* NIS_SP_GETENT */
221 
222 static nis_backend_op_t shadow_ops[] = {
223 	_nss_nis_destr,
224 	_nss_nis_endent,
225 	_nss_nis_setent,
226 #ifdef	NIS_SP_GETENT
227 	getent,
228 #else
229 	0,
230 #endif	/* NIS_SP_GETENT */
231 	getbyname
232 };
233 
234 /*ARGSUSED*/
235 nss_backend_t *
_nss_nis_shadow_constr(dummy1,dummy2,dummy3)236 _nss_nis_shadow_constr(dummy1, dummy2, dummy3)
237 	const char	*dummy1, *dummy2, *dummy3;
238 {
239 	return (_nss_nis_constr(shadow_ops,
240 				sizeof (shadow_ops) / sizeof (shadow_ops[0]),
241 				"passwd.byname"));
242 }
243