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