xref: /illumos-gate/usr/src/lib/passwdutil/nss_attr.c (revision 068cf9dc70b00292d5e5ff1ab17f1b046215d6f6)
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  * Copyright 2024 OmniOS Community Edition (OmniOSce) Association.
25  */
26 
27 #include <sys/types.h>
28 #include <errno.h>
29 #include <stdlib.h>
30 #include <pwd.h>
31 #include <shadow.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <nss_dbdefs.h>
36 
37 #include "passwdutil.h"
38 
39 /* from files_attr.c */
40 struct passwd *private_getpwnam_r(const char *name, struct passwd *result,
41     char *buffer, int buflen);
42 
43 int nss_getattr(const char *name, attrlist *item, pwu_repository_t *rep);
44 int nss_getpwnam(const char *name, attrlist *items, pwu_repository_t *rep,
45     void **buf);
46 
47 /*
48  * nss function pointer table, used by passwdutil_init to initialize
49  * the global Repository-OPerations table "rops"
50  */
51 struct repops nss_repops = {
52 	NULL,		/* checkhistory */
53 	nss_getattr,
54 	nss_getpwnam,
55 	NULL,		/* update */
56 	NULL,		/* putpwnam */
57 	NULL,		/* user_to_authenticate */
58 	NULL,		/* lock */
59 	NULL		/* unlock */
60 };
61 
62 /*
63  * this structure defines the buffer used to keep state between
64  * get/update/put calls
65  */
66 struct pwbuf {
67 	struct passwd *pwd;
68 	char   *pwd_scratch;
69 	struct spwd *spwd;
70 	char   *spwd_scratch;
71 	char   *rep_name;
72 };
73 
74 /*
75  * We should use sysconf, but there is no sysconf name for SHADOW
76  * so we use these from nss_dbdefs
77  */
78 #define	PWD_SCRATCH_SIZE NSS_LINELEN_PASSWD
79 #define	SPW_SCRATCH_SIZE NSS_LINELEN_SHADOW
80 
81 
82 /*
83  * nss_getpwnam(name, items, rep, buf)
84  *
85  */
86 /*ARGSUSED*/
87 int
88 nss_getpwnam(const char *name, attrlist *items, pwu_repository_t *rep,
89     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_LDAP)
194 			pwbuf->rep_name = "ldap";
195 		else if (repositories & REP_COMPAT_NIS)
196 			pwbuf->rep_name = "nis";
197 		else
198 			pwbuf->rep_name = "nss";
199 	} else
200 		pwbuf->rep_name = "nss";
201 
202 	return (PWU_SUCCESS);
203 error:
204 	if (pwbuf->pwd) free(pwbuf->pwd);
205 	if (pwbuf->pwd_scratch) free(pwbuf->pwd_scratch);
206 	if (pwbuf->spwd) free(pwbuf->spwd);
207 	if (pwbuf->spwd_scratch) free(pwbuf->spwd_scratch);
208 	free(pwbuf);
209 	*buf = NULL;
210 
211 	return (err);
212 }
213 
214 
215 /*
216  * nss_getattr(name, items, rep)
217  *
218  * Get attributes specified in list 'items'
219  */
220 int
221 nss_getattr(const char *name, attrlist *items, pwu_repository_t *rep)
222 {
223 	struct pwbuf *pwbuf;
224 	struct passwd *pw;
225 	struct spwd *spw;
226 	attrlist *w;
227 	int res = 0;
228 
229 	res = nss_getpwnam(name, items, rep, (void **)&pwbuf);
230 	if (res != PWU_SUCCESS)
231 		return (res);
232 
233 	pw = pwbuf->pwd;
234 	spw = pwbuf->spwd;
235 
236 	for (w = items; res == PWU_SUCCESS && w != NULL; w = w->next) {
237 		switch (w->type) {
238 		case ATTR_NAME:
239 			if ((w->data.val_s = strdup(pw->pw_name)) == NULL)
240 				res = PWU_NOMEM;
241 			break;
242 		case ATTR_COMMENT:
243 			if ((w->data.val_s = strdup(pw->pw_comment)) == NULL)
244 				res = PWU_NOMEM;
245 			break;
246 		case ATTR_GECOS:
247 			if ((w->data.val_s = strdup(pw->pw_gecos)) == NULL)
248 				res = PWU_NOMEM;
249 			break;
250 		case ATTR_HOMEDIR:
251 			if ((w->data.val_s = strdup(pw->pw_dir)) == NULL)
252 				res = PWU_NOMEM;
253 			break;
254 		case ATTR_SHELL:
255 			if ((w->data.val_s = strdup(pw->pw_shell)) == NULL)
256 				res = PWU_NOMEM;
257 			break;
258 		/*
259 		 * Nothing special needs to be done for
260 		 * server policy
261 		 */
262 		case ATTR_PASSWD:
263 		case ATTR_PASSWD_SERVER_POLICY:
264 			if ((w->data.val_s = strdup(spw->sp_pwdp)) == NULL)
265 				res = PWU_NOMEM;
266 			break;
267 		case ATTR_AGE:
268 			if ((w->data.val_s = strdup(pw->pw_age)) == NULL)
269 				res = PWU_NOMEM;
270 			break;
271 		case ATTR_REP_NAME:
272 			if ((w->data.val_s = strdup(pwbuf->rep_name)) == NULL)
273 				res = PWU_NOMEM;
274 			break;
275 
276 		/* integer values */
277 		case ATTR_UID:
278 			w->data.val_i = pw->pw_uid;
279 			break;
280 		case ATTR_GID:
281 			w->data.val_i = pw->pw_gid;
282 			break;
283 		case ATTR_LSTCHG:
284 			w->data.val_i = spw->sp_lstchg;
285 			break;
286 		case ATTR_MIN:
287 			w->data.val_i = spw->sp_min;
288 			break;
289 		case ATTR_MAX:
290 			w->data.val_i = spw->sp_max;
291 			break;
292 		case ATTR_WARN:
293 			w->data.val_i = spw->sp_warn;
294 			break;
295 		case ATTR_INACT:
296 			w->data.val_i = spw->sp_inact;
297 			break;
298 		case ATTR_EXPIRE:
299 			w->data.val_i = spw->sp_expire;
300 			break;
301 		case ATTR_FLAG:
302 			w->data.val_i = spw->sp_flag;
303 			break;
304 		case ATTR_FAILED_LOGINS:
305 			w->data.val_i = spw->sp_flag & FAILCOUNT_MASK;
306 			break;
307 		default:
308 			break;
309 		}
310 	}
311 
312 	if (pwbuf->pwd) free(pwbuf->pwd);
313 	if (pwbuf->pwd_scratch) free(pwbuf->pwd_scratch);
314 	if (pwbuf->spwd) free(pwbuf->spwd);
315 	if (pwbuf->spwd_scratch) free(pwbuf->spwd_scratch);
316 	free(pwbuf);
317 
318 	return (res);
319 }
320