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
nss_getpwnam(const char * name,attrlist * items,pwu_repository_t * rep,void ** buf)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
nss_getattr(const char * name,attrlist * items,pwu_repository_t * rep)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