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