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