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)
177 free(buf
->c2scratch
);
186 * nis_getattr(name, items, rep)
188 * get account attributes specified in 'items'
191 nis_getattr(char *name
, attrlist
*items
, pwu_repository_t
*rep
)
193 nisbuf_t
*nisbuf
= NULL
;
198 res
= nis_getpwnam(name
, items
, rep
, (void **)&nisbuf
);
199 if (res
!= PWU_SUCCESS
)
204 for (w
= items
; w
!= NULL
; w
= w
->next
) {
207 if ((w
->data
.val_s
= strdup(pw
->pw_name
)) == NULL
)
211 if ((w
->data
.val_s
= strdup(pw
->pw_comment
)) == NULL
)
215 if ((w
->data
.val_s
= strdup(pw
->pw_gecos
)) == NULL
)
219 if ((w
->data
.val_s
= strdup(pw
->pw_dir
)) == NULL
)
223 if ((w
->data
.val_s
= strdup(pw
->pw_shell
)) == NULL
)
227 case ATTR_PASSWD_SERVER_POLICY
:
228 if ((w
->data
.val_s
= strdup(pw
->pw_passwd
)) == NULL
)
232 if ((w
->data
.val_s
= strdup("nis")) == NULL
)
238 w
->data
.val_i
= nisbuf
->pwd
->pw_uid
;
241 w
->data
.val_i
= nisbuf
->pwd
->pw_gid
;
251 w
->data
.val_i
= -1; /* not used for NIS */
259 * Do not release nisbuf->domain.
260 * It's been set by yp_get_default_domain()
261 * and must not be freed.
262 * See man page yp_get_default_domain(3NSL)
266 free(nisbuf
->master
);
268 free(nisbuf
->scratch
);
269 if (nisbuf
->c2scratch
)
270 free(nisbuf
->c2scratch
);
278 * nis_getpwnam(name, items, rep)
280 * Get the account information of user 'name'
284 nis_getpwnam(char *name
, attrlist
*items
, pwu_repository_t
*rep
,
290 nisbuf
= calloc(sizeof (*nisbuf
), 1);
294 nisbuf
->pwd
= malloc(sizeof (struct passwd
));
295 if (nisbuf
->pwd
== NULL
) {
301 * Do not release nisbuf->domain.
302 * It is going to be set by yp_get_default_domain()
303 * and must not be freed.
304 * See man page yp_get_default_domain(3NSL)
307 if (yp_get_default_domain(&nisbuf
->domain
) != 0) {
308 syslog(LOG_ERR
, "passwdutil.so: can't get domain");
311 return (PWU_SERVER_ERROR
);
314 if (yp_master(nisbuf
->domain
, "passwd.byname", &nisbuf
->master
) != 0) {
316 "passwdutil.so: can't get master for passwd map");
318 free(nisbuf
->master
);
321 return (PWU_SERVER_ERROR
);
324 nisresult
= yp_match(nisbuf
->domain
, "passwd.byname", name
,
325 strlen(name
), &(nisbuf
->scratch
),
326 &(nisbuf
->scratchlen
));
327 if (nisresult
!= 0) {
328 (void) free(nisbuf
->pwd
);
330 (void) free(nisbuf
->scratch
);
332 (void) free(nisbuf
->master
);
334 return (PWU_NOT_FOUND
);
337 nis_to_pwd(nisbuf
->scratch
, nisbuf
->pwd
);
340 * check for the C2 security flag "##" in the passwd field.
341 * If the first 2 chars in the passwd field is "##", get
342 * the user's passwd from passwd.adjunct.byname map.
343 * The lookup to this passwd.adjunct.byname map will only
344 * succeed if the caller's uid is 0 because only root user
345 * can use privilege port.
347 if (nisbuf
->pwd
->pw_passwd
[0] == '#' &&
348 nisbuf
->pwd
->pw_passwd
[1] == '#') {
349 char *key
= &nisbuf
->pwd
->pw_passwd
[2];
353 keylen
= strlen(key
);
355 nisresult
= yp_match(nisbuf
->domain
, "passwd.adjunct.byname",
356 key
, keylen
, &(nisbuf
->c2scratch
),
357 &(nisbuf
->c2scratchlen
));
359 if (nisresult
== 0 && nisbuf
->c2scratch
!= NULL
) {
360 /* Skip username (first field), and pick up password */
361 p
= nisbuf
->c2scratch
;
362 (void) strsep(&p
, ":");
363 nisbuf
->pwd
->pw_passwd
= strsep(&p
, ":");
367 *buf
= (void *)nisbuf
;
369 return (PWU_SUCCESS
);
373 * nis_update(items, rep, buf)
375 * update the information in "buf" with the attribute/values
376 * specified in "items".
380 nis_update(attrlist
*items
, pwu_repository_t
*rep
, void *buf
)
383 nisbuf_t
*nisbuf
= (nisbuf_t
*)buf
;
386 for (p
= items
; p
!= NULL
; p
= p
->next
) {
391 * Nothing special needs to be done for
395 case ATTR_PASSWD_SERVER_POLICY
:
396 salt
= crypt_gensalt(
397 nisbuf
->pwd
->pw_passwd
, nisbuf
->pwd
);
403 /* algorithm problem? */
404 syslog(LOG_AUTH
| LOG_ALERT
,
405 "passwdutil: crypt_gensalt "
407 return (PWU_UPDATE_FAILED
);
410 nisbuf
->pwd
->pw_passwd
= crypt(p
->data
.val_s
, salt
);
414 nisbuf
->pwd
->pw_uid
= (uid_t
)p
->data
.val_i
;
417 nisbuf
->pwd
->pw_gid
= (gid_t
)p
->data
.val_i
;
420 nisbuf
->pwd
->pw_age
= p
->data
.val_s
;
423 nisbuf
->pwd
->pw_comment
= p
->data
.val_s
;
426 nisbuf
->pwd
->pw_gecos
= p
->data
.val_s
;
429 nisbuf
->pwd
->pw_dir
= p
->data
.val_s
;
432 nisbuf
->pwd
->pw_shell
= p
->data
.val_s
;
445 return (PWU_SUCCESS
);
449 * nis_putpwnam(name, oldpw, rep, buf)
451 * Update the NIS server. The passwd structure in buf will be sent to
452 * the server for user "name" authenticating with password "oldpw".
456 nis_putpwnam(char *name
, char *oldpw
, pwu_repository_t
*rep
,
459 nisbuf_t
*nisbuf
= (nisbuf_t
*)buf
;
460 struct yppasswd yppasswd
;
461 struct netconfig
*nconf
;
465 struct timeval timeout
;
467 if (strcmp(name
, "root") == 0)
468 return (PWU_NOT_FOUND
);
470 yppasswd
.oldpass
= oldpw
? oldpw
: "";
471 yppasswd
.newpw
= *nisbuf
->pwd
;
474 * If we are privileged, we create a ticlts connection to the
475 * NIS server so that it can check our credentials
477 if (nis_privileged(nisbuf
)) {
478 nconf
= getnetconfigent("ticlts");
481 "passwdutil.so: Couldn't get netconfig entry");
482 return (PWU_SYSTEM_ERROR
);
484 client
= clnt_tp_create(nisbuf
->master
, YPPASSWDPROG
,
485 YPPASSWDVERS
, nconf
);
486 freenetconfigent(nconf
);
489 client
= clnt_create(nisbuf
->master
, YPPASSWDPROG
,
490 YPPASSWDVERS
, "udp6");
492 client
= clnt_create(nisbuf
->master
, YPPASSWDPROG
,
493 YPPASSWDVERS
, "udp");
496 if (client
== NULL
) {
498 "passwdutil.so: couldn't create client to YP master");
499 return (PWU_SERVER_ERROR
);
503 timeout
.tv_sec
= 55; /* ndp uses 55 seconds */
505 ans
= CLNT_CALL(client
, YPPASSWDPROC_UPDATE
, xdr_yppasswd
,
506 (char *)&yppasswd
, xdr_int
, (char *)&ok
, timeout
);
509 (void) free(nisbuf
->pwd
);
511 (void) free(nisbuf
->master
);
513 (void) free(nisbuf
->scratch
);
514 if (nisbuf
->c2scratch
)
515 (void) free(nisbuf
->c2scratch
);
517 (void) clnt_destroy(client
);
519 if (ans
!= RPC_SUCCESS
) {
520 return (PWU_UPDATE_FAILED
);
523 /* These errors are obtained from the yppasswdd.c code */
525 case 2: return (PWU_DENIED
);
526 case 8: return (PWU_BUSY
);
527 case 9: return (PWU_SERVER_ERROR
);
528 case 4: return (PWU_NOT_FOUND
);
529 case 3: return (PWU_NO_CHANGE
);
530 case 7: return (PWU_DENIED
);
531 case 0: return (PWU_SUCCESS
);
532 default: return (PWU_SYSTEM_ERROR
);