dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / passwdutil / nis_attr.c
blob157601f8d60f457fd6ac55b927fc94c32aac2332
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <stdio.h>
27 #include <errno.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/errno.h>
31 #include <pwd.h>
32 #include <unistd.h>
33 #include <syslog.h>
35 #include <netdb.h>
37 #include <rpc/rpc.h>
38 #include <rpcsvc/yppasswd.h>
39 #include <rpcsvc/ypclnt.h>
40 #include <rpcsvc/yp_prot.h>
42 #include "passwdutil.h"
44 int nis_getattr(char *name, attrlist *item, pwu_repository_t *rep);
45 int nis_getpwnam(char *name, attrlist *items, pwu_repository_t *rep,
46 void **buf);
47 int nis_update(attrlist *items, pwu_repository_t *rep, void *buf);
48 int nis_putpwnam(char *name, char *oldpw, pwu_repository_t *rep, void *buf);
49 int nis_user_to_authenticate(char *user, pwu_repository_t *rep,
50 char **auth_user, int *privileged);
53 * nis function pointer table, used by passwdutil_init to initialize
54 * the global Repository-OPerations table "rops"
56 struct repops nis_repops = {
57 NULL, /* checkhistory */
58 nis_getattr,
59 nis_getpwnam,
60 nis_update,
61 nis_putpwnam,
62 nis_user_to_authenticate,
63 NULL, /* lock */
64 NULL /* unlock */
68 * structure used to keep state between get/update/put calls
70 typedef struct {
71 char *domain;
72 char *master;
73 char *scratch;
74 int scratchlen;
75 char *c2scratch;
76 int c2scratchlen;
77 struct passwd *pwd;
78 } nisbuf_t;
81 * Are we a 'privileged' process? Yes if we are running on the
82 * NIS server AND we are root...
84 int
85 nis_privileged(nisbuf_t *nisbuf)
87 char thishost[MAXHOSTNAMELEN];
88 if (gethostname(thishost, sizeof (thishost)) == -1) {
89 syslog(LOG_ERR, "passwdutil.so: Can't get hostname");
90 return (0);
93 if (strcmp(nisbuf->master, thishost) != 0)
94 return (0);
96 /* We're running on the NIS server. */
97 return (getuid() == 0);
101 * nis_to_pwd()
103 * convert password-entry-line to "struct passwd"
105 void
106 nis_to_pwd(char *nis, struct passwd *pwd)
108 pwd->pw_name = strsep(&nis, ":");
109 pwd->pw_passwd = strsep(&nis, ":");
110 pwd->pw_uid = atoi(strsep(&nis, ":"));
111 pwd->pw_gid = atoi(strsep(&nis, ":"));
112 pwd->pw_gecos = strsep(&nis, ":");
113 pwd->pw_dir = strsep(&nis, ":");
114 pwd->pw_shell = nis;
115 if (pwd->pw_shell[0])
116 pwd->pw_shell[strlen(pwd->pw_shell)-1] = '\0';
120 * nis_user_to_authenticate(name, rep, auth_user, privileged)
123 /*ARGSUSED*/
125 nis_user_to_authenticate(char *user, pwu_repository_t *rep,
126 char **auth_user, int *privileged)
128 nisbuf_t *buf = NULL;
129 int res;
130 attrlist attr_tmp[1];
131 uid_t uid;
134 * special NIS case: don't bother to get "root" from NIS
136 if (strcmp(user, "root") == 0)
137 return (PWU_NOT_FOUND);
139 attr_tmp[0].type = ATTR_UID;
140 attr_tmp[0].next = NULL;
142 res = nis_getpwnam(user, &attr_tmp[0], rep, (void **)&buf);
144 if (res != PWU_SUCCESS)
145 return (res);
147 if (nis_privileged(buf)) {
148 *privileged = 1;
149 *auth_user = NULL;
150 res = PWU_SUCCESS;
151 } else {
152 uid = getuid();
154 *privileged = (uid == (uid_t)0);
156 /* root, or user herself can change attributes */
157 if (uid == 0 || uid == buf->pwd->pw_uid) {
158 *auth_user = strdup(user);
159 res = PWU_SUCCESS;
160 } else {
161 res = PWU_DENIED;
166 * Do not release buf->domain.
167 * It's been set by yp_get_default_domain()
168 * and must not be freed.
169 * See man page yp_get_default_domain(3NSL)
170 * for details.
172 free(buf->master);
173 free(buf->scratch);
174 free(buf->c2scratch);
175 free(buf->pwd);
176 free(buf);
178 return (res);
183 * nis_getattr(name, items, rep)
185 * get account attributes specified in 'items'
188 nis_getattr(char *name, attrlist *items, pwu_repository_t *rep)
190 nisbuf_t *nisbuf = NULL;
191 struct passwd *pw;
192 attrlist *w;
193 int res;
195 res = nis_getpwnam(name, items, rep, (void **)&nisbuf);
196 if (res != PWU_SUCCESS)
197 return (res);
199 pw = nisbuf->pwd;
201 for (w = items; w != NULL; w = w->next) {
202 switch (w->type) {
203 case ATTR_NAME:
204 if ((w->data.val_s = strdup(pw->pw_name)) == NULL)
205 res = PWU_NOMEM;
206 break;
207 case ATTR_COMMENT:
208 if ((w->data.val_s = strdup(pw->pw_comment)) == NULL)
209 res = PWU_NOMEM;
210 break;
211 case ATTR_GECOS:
212 if ((w->data.val_s = strdup(pw->pw_gecos)) == NULL)
213 res = PWU_NOMEM;
214 break;
215 case ATTR_HOMEDIR:
216 if ((w->data.val_s = strdup(pw->pw_dir)) == NULL)
217 res = PWU_NOMEM;
218 break;
219 case ATTR_SHELL:
220 if ((w->data.val_s = strdup(pw->pw_shell)) == NULL)
221 res = PWU_NOMEM;
222 break;
223 case ATTR_PASSWD:
224 case ATTR_PASSWD_SERVER_POLICY:
225 if ((w->data.val_s = strdup(pw->pw_passwd)) == NULL)
226 res = PWU_NOMEM;
227 break;
228 case ATTR_REP_NAME:
229 if ((w->data.val_s = strdup("nis")) == NULL)
230 res = PWU_NOMEM;
231 break;
233 /* integer values */
234 case ATTR_UID:
235 w->data.val_i = nisbuf->pwd->pw_uid;
236 break;
237 case ATTR_GID:
238 w->data.val_i = nisbuf->pwd->pw_gid;
239 break;
240 case ATTR_LSTCHG:
241 case ATTR_MIN:
242 case ATTR_MAX:
243 case ATTR_WARN:
244 case ATTR_INACT:
245 case ATTR_EXPIRE:
246 case ATTR_FLAG:
247 case ATTR_AGE:
248 w->data.val_i = -1; /* not used for NIS */
249 break;
250 default:
251 break;
256 * Do not release nisbuf->domain.
257 * It's been set by yp_get_default_domain()
258 * and must not be freed.
259 * See man page yp_get_default_domain(3NSL)
260 * for details.
262 free(nisbuf->master);
263 free(nisbuf->scratch);
264 free(nisbuf->c2scratch);
265 free(nisbuf->pwd);
266 free(nisbuf);
268 return (res);
272 * nis_getpwnam(name, items, rep)
274 * Get the account information of user 'name'
276 /*ARGSUSED*/
278 nis_getpwnam(char *name, attrlist *items, pwu_repository_t *rep,
279 void **buf)
281 nisbuf_t *nisbuf;
282 int nisresult;
284 nisbuf = calloc(sizeof (*nisbuf), 1);
285 if (nisbuf == NULL)
286 return (PWU_NOMEM);
288 nisbuf->pwd = malloc(sizeof (struct passwd));
289 if (nisbuf->pwd == NULL) {
290 free(nisbuf);
291 return (PWU_NOMEM);
295 * Do not release nisbuf->domain.
296 * It is going to be set by yp_get_default_domain()
297 * and must not be freed.
298 * See man page yp_get_default_domain(3NSL)
299 * for details.
301 if (yp_get_default_domain(&nisbuf->domain) != 0) {
302 syslog(LOG_ERR, "passwdutil.so: can't get domain");
303 free(nisbuf->pwd);
304 free(nisbuf);
305 return (PWU_SERVER_ERROR);
308 if (yp_master(nisbuf->domain, "passwd.byname", &nisbuf->master) != 0) {
309 syslog(LOG_ERR,
310 "passwdutil.so: can't get master for passwd map");
311 free(nisbuf->master);
312 free(nisbuf->pwd);
313 free(nisbuf);
314 return (PWU_SERVER_ERROR);
317 nisresult = yp_match(nisbuf->domain, "passwd.byname", name,
318 strlen(name), &(nisbuf->scratch),
319 &(nisbuf->scratchlen));
320 if (nisresult != 0) {
321 (void) free(nisbuf->pwd);
322 if (nisbuf->scratch)
323 (void) free(nisbuf->scratch);
324 if (nisbuf->master)
325 (void) free(nisbuf->master);
326 (void) free(nisbuf);
327 return (PWU_NOT_FOUND);
330 nis_to_pwd(nisbuf->scratch, nisbuf->pwd);
333 * check for the C2 security flag "##" in the passwd field.
334 * If the first 2 chars in the passwd field is "##", get
335 * the user's passwd from passwd.adjunct.byname map.
336 * The lookup to this passwd.adjunct.byname map will only
337 * succeed if the caller's uid is 0 because only root user
338 * can use privilege port.
340 if (nisbuf->pwd->pw_passwd[0] == '#' &&
341 nisbuf->pwd->pw_passwd[1] == '#') {
342 char *key = &nisbuf->pwd->pw_passwd[2];
343 int keylen;
344 char *p;
346 keylen = strlen(key);
348 nisresult = yp_match(nisbuf->domain, "passwd.adjunct.byname",
349 key, keylen, &(nisbuf->c2scratch),
350 &(nisbuf->c2scratchlen));
352 if (nisresult == 0 && nisbuf->c2scratch != NULL) {
353 /* Skip username (first field), and pick up password */
354 p = nisbuf->c2scratch;
355 (void) strsep(&p, ":");
356 nisbuf->pwd->pw_passwd = strsep(&p, ":");
360 *buf = (void *)nisbuf;
362 return (PWU_SUCCESS);
366 * nis_update(items, rep, buf)
368 * update the information in "buf" with the attribute/values
369 * specified in "items".
371 /*ARGSUSED*/
373 nis_update(attrlist *items, pwu_repository_t *rep, void *buf)
375 attrlist *p;
376 nisbuf_t *nisbuf = (nisbuf_t *)buf;
377 char *salt;
379 for (p = items; p != NULL; p = p->next) {
380 switch (p->type) {
381 case ATTR_NAME:
382 break;
384 * Nothing special needs to be done for
385 * server policy
387 case ATTR_PASSWD:
388 case ATTR_PASSWD_SERVER_POLICY:
389 salt = crypt_gensalt(
390 nisbuf->pwd->pw_passwd, nisbuf->pwd);
392 if (salt == NULL) {
393 if (errno == ENOMEM)
394 return (PWU_NOMEM);
395 else {
396 /* algorithm problem? */
397 syslog(LOG_AUTH | LOG_ALERT,
398 "passwdutil: crypt_gensalt "
399 "%m");
400 return (PWU_UPDATE_FAILED);
403 nisbuf->pwd->pw_passwd = crypt(p->data.val_s, salt);
404 free(salt);
405 break;
406 case ATTR_UID:
407 nisbuf->pwd->pw_uid = (uid_t)p->data.val_i;
408 break;
409 case ATTR_GID:
410 nisbuf->pwd->pw_gid = (gid_t)p->data.val_i;
411 break;
412 case ATTR_AGE:
413 nisbuf->pwd->pw_age = p->data.val_s;
414 break;
415 case ATTR_COMMENT:
416 nisbuf->pwd->pw_comment = p->data.val_s;
417 break;
418 case ATTR_GECOS:
419 nisbuf->pwd->pw_gecos = p->data.val_s;
420 break;
421 case ATTR_HOMEDIR:
422 nisbuf->pwd->pw_dir = p->data.val_s;
423 break;
424 case ATTR_SHELL:
425 nisbuf->pwd->pw_shell = p->data.val_s;
426 break;
427 case ATTR_LSTCHG:
428 case ATTR_MIN:
429 case ATTR_MAX:
430 case ATTR_WARN:
431 case ATTR_INACT:
432 case ATTR_EXPIRE:
433 case ATTR_FLAG:
434 default:
435 break;
438 return (PWU_SUCCESS);
442 * nis_putpwnam(name, oldpw, rep, buf)
444 * Update the NIS server. The passwd structure in buf will be sent to
445 * the server for user "name" authenticating with password "oldpw".
447 /*ARGSUSED*/
449 nis_putpwnam(char *name, char *oldpw, pwu_repository_t *rep,
450 void *buf)
452 nisbuf_t *nisbuf = (nisbuf_t *)buf;
453 struct yppasswd yppasswd;
454 struct netconfig *nconf;
455 int ok;
456 enum clnt_stat ans;
457 CLIENT *client;
458 struct timeval timeout;
460 if (strcmp(name, "root") == 0)
461 return (PWU_NOT_FOUND);
463 yppasswd.oldpass = oldpw ? oldpw : "";
464 yppasswd.newpw = *nisbuf->pwd;
467 * If we are privileged, we create a ticlts connection to the
468 * NIS server so that it can check our credentials
470 if (nis_privileged(nisbuf)) {
471 nconf = getnetconfigent("ticlts");
472 if (!nconf) {
473 syslog(LOG_ERR,
474 "passwdutil.so: Couldn't get netconfig entry");
475 return (PWU_SYSTEM_ERROR);
477 client = clnt_tp_create(nisbuf->master, YPPASSWDPROG,
478 YPPASSWDVERS, nconf);
479 freenetconfigent(nconf);
480 } else {
481 /* Try IPv6 first */
482 client = clnt_create(nisbuf->master, YPPASSWDPROG,
483 YPPASSWDVERS, "udp6");
484 if (client == NULL)
485 client = clnt_create(nisbuf->master, YPPASSWDPROG,
486 YPPASSWDVERS, "udp");
489 if (client == NULL) {
490 syslog(LOG_ERR,
491 "passwdutil.so: couldn't create client to YP master");
492 return (PWU_SERVER_ERROR);
495 timeout.tv_usec = 0;
496 timeout.tv_sec = 55; /* ndp uses 55 seconds */
498 ans = CLNT_CALL(client, YPPASSWDPROC_UPDATE, xdr_yppasswd,
499 (char *)&yppasswd, xdr_int, (char *)&ok, timeout);
501 if (nisbuf->pwd)
502 (void) free(nisbuf->pwd);
503 if (nisbuf->master)
504 (void) free(nisbuf->master);
505 if (nisbuf->scratch)
506 (void) free(nisbuf->scratch);
507 if (nisbuf->c2scratch)
508 (void) free(nisbuf->c2scratch);
510 (void) clnt_destroy(client);
512 if (ans != RPC_SUCCESS) {
513 return (PWU_UPDATE_FAILED);
516 /* These errors are obtained from the yppasswdd.c code */
517 switch (ok) {
518 case 2: return (PWU_DENIED);
519 case 8: return (PWU_BUSY);
520 case 9: return (PWU_SERVER_ERROR);
521 case 4: return (PWU_NOT_FOUND);
522 case 3: return (PWU_NO_CHANGE);
523 case 7: return (PWU_DENIED);
524 case 0: return (PWU_SUCCESS);
525 default: return (PWU_SYSTEM_ERROR);