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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
30 #include <sys/errno.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
,
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 */
62 nis_user_to_authenticate
,
68 * structure used to keep state between get/update/put calls
81 * Are we a 'privileged' process? Yes if we are running on the
82 * NIS server AND we are root...
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");
93 if (strcmp(nisbuf
->master
, thishost
) != 0)
96 /* We're running on the NIS server. */
97 return (getuid() == 0);
103 * convert password-entry-line to "struct passwd"
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
, ":");
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)
125 nis_user_to_authenticate(char *user
, pwu_repository_t
*rep
,
126 char **auth_user
, int *privileged
)
128 nisbuf_t
*buf
= NULL
;
130 attrlist attr_tmp
[1];
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
)
147 if (nis_privileged(buf
)) {
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
);
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)
174 free(buf
->c2scratch
);
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
;
195 res
= nis_getpwnam(name
, items
, rep
, (void **)&nisbuf
);
196 if (res
!= PWU_SUCCESS
)
201 for (w
= items
; w
!= NULL
; w
= w
->next
) {
204 if ((w
->data
.val_s
= strdup(pw
->pw_name
)) == NULL
)
208 if ((w
->data
.val_s
= strdup(pw
->pw_comment
)) == NULL
)
212 if ((w
->data
.val_s
= strdup(pw
->pw_gecos
)) == NULL
)
216 if ((w
->data
.val_s
= strdup(pw
->pw_dir
)) == NULL
)
220 if ((w
->data
.val_s
= strdup(pw
->pw_shell
)) == NULL
)
224 case ATTR_PASSWD_SERVER_POLICY
:
225 if ((w
->data
.val_s
= strdup(pw
->pw_passwd
)) == NULL
)
229 if ((w
->data
.val_s
= strdup("nis")) == NULL
)
235 w
->data
.val_i
= nisbuf
->pwd
->pw_uid
;
238 w
->data
.val_i
= nisbuf
->pwd
->pw_gid
;
248 w
->data
.val_i
= -1; /* not used for NIS */
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)
262 free(nisbuf
->master
);
263 free(nisbuf
->scratch
);
264 free(nisbuf
->c2scratch
);
272 * nis_getpwnam(name, items, rep)
274 * Get the account information of user 'name'
278 nis_getpwnam(char *name
, attrlist
*items
, pwu_repository_t
*rep
,
284 nisbuf
= calloc(sizeof (*nisbuf
), 1);
288 nisbuf
->pwd
= malloc(sizeof (struct passwd
));
289 if (nisbuf
->pwd
== NULL
) {
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)
301 if (yp_get_default_domain(&nisbuf
->domain
) != 0) {
302 syslog(LOG_ERR
, "passwdutil.so: can't get domain");
305 return (PWU_SERVER_ERROR
);
308 if (yp_master(nisbuf
->domain
, "passwd.byname", &nisbuf
->master
) != 0) {
310 "passwdutil.so: can't get master for passwd map");
311 free(nisbuf
->master
);
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
);
323 (void) free(nisbuf
->scratch
);
325 (void) free(nisbuf
->master
);
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];
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".
373 nis_update(attrlist
*items
, pwu_repository_t
*rep
, void *buf
)
376 nisbuf_t
*nisbuf
= (nisbuf_t
*)buf
;
379 for (p
= items
; p
!= NULL
; p
= p
->next
) {
384 * Nothing special needs to be done for
388 case ATTR_PASSWD_SERVER_POLICY
:
389 salt
= crypt_gensalt(
390 nisbuf
->pwd
->pw_passwd
, nisbuf
->pwd
);
396 /* algorithm problem? */
397 syslog(LOG_AUTH
| LOG_ALERT
,
398 "passwdutil: crypt_gensalt "
400 return (PWU_UPDATE_FAILED
);
403 nisbuf
->pwd
->pw_passwd
= crypt(p
->data
.val_s
, salt
);
407 nisbuf
->pwd
->pw_uid
= (uid_t
)p
->data
.val_i
;
410 nisbuf
->pwd
->pw_gid
= (gid_t
)p
->data
.val_i
;
413 nisbuf
->pwd
->pw_age
= p
->data
.val_s
;
416 nisbuf
->pwd
->pw_comment
= p
->data
.val_s
;
419 nisbuf
->pwd
->pw_gecos
= p
->data
.val_s
;
422 nisbuf
->pwd
->pw_dir
= p
->data
.val_s
;
425 nisbuf
->pwd
->pw_shell
= p
->data
.val_s
;
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".
449 nis_putpwnam(char *name
, char *oldpw
, pwu_repository_t
*rep
,
452 nisbuf_t
*nisbuf
= (nisbuf_t
*)buf
;
453 struct yppasswd yppasswd
;
454 struct netconfig
*nconf
;
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");
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
);
482 client
= clnt_create(nisbuf
->master
, YPPASSWDPROG
,
483 YPPASSWDVERS
, "udp6");
485 client
= clnt_create(nisbuf
->master
, YPPASSWDPROG
,
486 YPPASSWDVERS
, "udp");
489 if (client
== NULL
) {
491 "passwdutil.so: couldn't create client to YP master");
492 return (PWU_SERVER_ERROR
);
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
);
502 (void) free(nisbuf
->pwd
);
504 (void) free(nisbuf
->master
);
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 */
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
);