xref: /illumos-gate/usr/src/lib/passwdutil/nss_attr.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/types.h>
29 #include <errno.h>
30 #include <stdlib.h>
31 #include <pwd.h>
32 #include <shadow.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <nss_dbdefs.h>
37 
38 #include "passwdutil.h"
39 
40 /* from files_attr.c */
41 struct passwd *private_getpwnam_r(const char *name, struct passwd *result,
42     char *buffer, int buflen);
43 
44 int nss_getattr(char *name, attrlist *item, pwu_repository_t *rep);
45 int nss_getpwnam(char *name, attrlist *items, pwu_repository_t *rep,
46     void **buf);
47 
48 /*
49  * nss function pointer table, used by passwdutil_init to initialize
50  * the global Repository-OPerations table "rops"
51  */
52 struct repops nss_repops = {
53 	NULL,		/* checkhistory */
54 	nss_getattr,
55 	nss_getpwnam,
56 	NULL,		/* update */
57 	NULL,		/* putpwnam */
58 	NULL,		/* user_to_authenticate */
59 	NULL,		/* lock */
60 	NULL		/* unlock */
61 };
62 
63 /*
64  * this structure defines the buffer used to keep state between
65  * get/update/put calls
66  */
67 struct pwbuf {
68 	struct passwd *pwd;
69 	char   *pwd_scratch;
70 	struct spwd *spwd;
71 	char   *spwd_scratch;
72 	char   *rep_name;
73 };
74 
75 /*
76  * We should use sysconf, but there is no sysconf name for SHADOW
77  * so we use these from nss_dbdefs
78  */
79 #define	PWD_SCRATCH_SIZE NSS_LINELEN_PASSWD
80 #define	SPW_SCRATCH_SIZE NSS_LINELEN_SHADOW
81 
82 
83 /*
84  * nss_getpwnam(name, items, rep, buf)
85  *
86  */
87 /*ARGSUSED*/
88 int
89 nss_getpwnam(char *name, attrlist *items, pwu_repository_t *rep, void **buf)
90 {
91 	attrlist *p;
92 	struct pwbuf *pwbuf;
93 	int repositories = REP_ERANGE;	/* changed if ATTR_REP_NAME is set */
94 	int err = PWU_SUCCESS;
95 
96 	*buf = calloc(1, sizeof (struct pwbuf));
97 	pwbuf = (struct pwbuf *)*buf;
98 	if (pwbuf == NULL)
99 		return (PWU_NOMEM);
100 
101 	/*
102 	 * determine which password structure (/etc/passwd or /etc/shadow)
103 	 * we need for the items we need to update
104 	 */
105 	for (p = items; p != NULL; p = p->next) {
106 		switch (p->type) {
107 		case ATTR_NAME:
108 		case ATTR_UID:
109 		case ATTR_GID:
110 		case ATTR_AGE:
111 		case ATTR_COMMENT:
112 		case ATTR_GECOS:
113 		case ATTR_HOMEDIR:
114 		case ATTR_SHELL:
115 			if (pwbuf->pwd == NULL)
116 				pwbuf->pwd = (struct passwd *)
117 				    malloc(sizeof (struct passwd));
118 			if (pwbuf->pwd == NULL) {
119 				errno = ENOMEM;
120 				if (pwbuf->spwd)
121 					free(pwbuf->spwd);
122 				return (PWU_NOMEM);
123 			}
124 			break;
125 		case ATTR_PASSWD:
126 		case ATTR_PASSWD_SERVER_POLICY:
127 		case ATTR_LSTCHG:
128 		case ATTR_MIN:
129 		case ATTR_MAX:
130 		case ATTR_WARN:
131 		case ATTR_INACT:
132 		case ATTR_EXPIRE:
133 		case ATTR_FLAG:
134 		case ATTR_LOCK_ACCOUNT:
135 		case ATTR_EXPIRE_PASSWORD:
136 		case ATTR_FAILED_LOGINS:
137 			if (pwbuf->spwd == NULL)
138 				pwbuf->spwd = (struct spwd *)
139 				    malloc(sizeof (struct spwd));
140 			if (pwbuf->spwd == NULL) {
141 				errno = ENOMEM;
142 				if (pwbuf->pwd)
143 					free(pwbuf->pwd);
144 				return (PWU_NOMEM);
145 			}
146 			break;
147 		case ATTR_REP_NAME:
148 			/* get the compat names (REP_COMPAT_*) */
149 			repositories = get_ns(rep, PWU_READ);
150 			break;
151 		default:
152 			/*
153 			 * Some other repository might have different values
154 			 * so we ignore those.
155 			 */
156 			break;
157 		}
158 	}
159 
160 	if (pwbuf->pwd) {
161 		if ((pwbuf->pwd_scratch = malloc(PWD_SCRATCH_SIZE)) == NULL) {
162 			err = PWU_NOMEM;
163 			goto error;
164 		}
165 		if (getpwnam_r(name, pwbuf->pwd, pwbuf->pwd_scratch,
166 		    PWD_SCRATCH_SIZE) == NULL) {
167 			err = PWU_NOT_FOUND;
168 			goto error;
169 		}
170 	}
171 
172 	if (pwbuf->spwd) {
173 		if ((pwbuf->spwd_scratch = malloc(SPW_SCRATCH_SIZE)) == NULL) {
174 			err = PWU_NOMEM;
175 			goto error;
176 		}
177 		if (getspnam_r(name, pwbuf->spwd, pwbuf->spwd_scratch,
178 		    SPW_SCRATCH_SIZE) == NULL) {
179 			err = PWU_NOT_FOUND;
180 			goto error;
181 		}
182 	}
183 
184 	/* pwbuf->rep_name tells us where the user in fact comes from */
185 	if (repositories != REP_ERANGE) {
186 		struct passwd pwd;
187 		char pwd_scratch[PWD_SCRATCH_SIZE];
188 
189 		/* can we find the user locally? */
190 		if (private_getpwnam_r(name, &pwd, pwd_scratch,
191 		    PWD_SCRATCH_SIZE) != NULL)
192 			pwbuf->rep_name = "files";
193 		else if (repositories & REP_COMPAT_NISPLUS)
194 			pwbuf->rep_name = "nisplus";
195 		else if (repositories & REP_COMPAT_LDAP)
196 			pwbuf->rep_name = "ldap";
197 		else if (repositories & REP_COMPAT_NIS)
198 			pwbuf->rep_name = "nis";
199 		else
200 			pwbuf->rep_name = "nss";
201 	} else
202 		pwbuf->rep_name = "nss";
203 
204 	return (PWU_SUCCESS);
205 error:
206 	if (pwbuf->pwd) free(pwbuf->pwd);
207 	if (pwbuf->pwd_scratch) free(pwbuf->pwd_scratch);
208 	if (pwbuf->spwd) free(pwbuf->spwd);
209 	if (pwbuf->spwd_scratch) free(pwbuf->spwd_scratch);
210 	free(pwbuf);
211 	*buf = NULL;
212 
213 	return (err);
214 }
215 
216 
217 /*
218  * nss_getattr(name, items, rep)
219  *
220  * Get attributes specified in list 'items'
221  */
222 int
223 nss_getattr(char *name, attrlist *items, pwu_repository_t *rep)
224 {
225 	struct pwbuf *pwbuf;
226 	struct passwd *pw;
227 	struct spwd *spw;
228 	attrlist *w;
229 	int res = 0;
230 
231 	res = nss_getpwnam(name, items, rep, (void **)&pwbuf);
232 	if (res != PWU_SUCCESS)
233 		return (res);
234 
235 	pw = pwbuf->pwd;
236 	spw = pwbuf->spwd;
237 
238 	for (w = items; res == PWU_SUCCESS && w != NULL; w = w->next) {
239 		switch (w->type) {
240 		case ATTR_NAME:
241 			if ((w->data.val_s = strdup(pw->pw_name)) == NULL)
242 				res = PWU_NOMEM;
243 			break;
244 		case ATTR_COMMENT:
245 			if ((w->data.val_s = strdup(pw->pw_comment)) == NULL)
246 				res = PWU_NOMEM;
247 			break;
248 		case ATTR_GECOS:
249 			if ((w->data.val_s = strdup(pw->pw_gecos)) == NULL)
250 				res = PWU_NOMEM;
251 			break;
252 		case ATTR_HOMEDIR:
253 			if ((w->data.val_s = strdup(pw->pw_dir)) == NULL)
254 				res = PWU_NOMEM;
255 			break;
256 		case ATTR_SHELL:
257 			if ((w->data.val_s = strdup(pw->pw_shell)) == NULL)
258 				res = PWU_NOMEM;
259 			break;
260 		/*
261 		 * Nothing special needs to be done for
262 		 * server policy
263 		 */
264 		case ATTR_PASSWD:
265 		case ATTR_PASSWD_SERVER_POLICY:
266 			if ((w->data.val_s = strdup(spw->sp_pwdp)) == NULL)
267 				res = PWU_NOMEM;
268 			break;
269 		case ATTR_AGE:
270 			if ((w->data.val_s = strdup(pw->pw_age)) == NULL)
271 				res = PWU_NOMEM;
272 			break;
273 		case ATTR_REP_NAME:
274 			if ((w->data.val_s = strdup(pwbuf->rep_name)) == NULL)
275 				res = PWU_NOMEM;
276 			break;
277 
278 		/* integer values */
279 		case ATTR_UID:
280 			w->data.val_i = pw->pw_uid;
281 			break;
282 		case ATTR_GID:
283 			w->data.val_i = pw->pw_gid;
284 			break;
285 		case ATTR_LSTCHG:
286 			w->data.val_i = spw->sp_lstchg;
287 			break;
288 		case ATTR_MIN:
289 			w->data.val_i = spw->sp_min;
290 			break;
291 		case ATTR_MAX:
292 			w->data.val_i = spw->sp_max;
293 			break;
294 		case ATTR_WARN:
295 			w->data.val_i = spw->sp_warn;
296 			break;
297 		case ATTR_INACT:
298 			w->data.val_i = spw->sp_inact;
299 			break;
300 		case ATTR_EXPIRE:
301 			w->data.val_i = spw->sp_expire;
302 			break;
303 		case ATTR_FLAG:
304 			w->data.val_i = spw->sp_flag;
305 			break;
306 		case ATTR_FAILED_LOGINS:
307 			w->data.val_i = spw->sp_flag & FAILCOUNT_MASK;
308 			break;
309 		default:
310 			break;
311 		}
312 	}
313 
314 	if (pwbuf->pwd) free(pwbuf->pwd);
315 	if (pwbuf->pwd_scratch) free(pwbuf->pwd_scratch);
316 	if (pwbuf->spwd) free(pwbuf->spwd);
317 	if (pwbuf->spwd_scratch) free(pwbuf->spwd_scratch);
318 	free(pwbuf);
319 
320 	return (res);
321 }
322