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.
24 * Copyright (c) 2016 by Delphix. All rights reserved.
37 #include <nss_dbdefs.h>
44 #include "passwdutil.h"
48 #define MAX_INT_LEN 11 /* 10+1 %d buflen for words/ints [not longs] */
50 #define STRDUP_OR_RET(to, from) \
51 if ((to = strdup(from)) == NULL) \
54 #define STRDUP_OR_ERR(to, from, err) \
55 if (((to) = strdup(from)) == NULL) \
58 #define NUM_TO_STR(to, from) \
60 char nb[MAX_INT_LEN]; \
61 if (snprintf(nb, MAX_INT_LEN, "%d", (from)) >= MAX_INT_LEN) \
63 STRDUP_OR_RET(to, nb); \
66 #define NEW_ATTR(p, i, attr, val) \
68 p[i] = new_attr(attr, (val)); \
74 int ldap_getattr(char *name
, attrlist
*item
, pwu_repository_t
*rep
);
75 int ldap_getpwnam(char *name
, attrlist
*items
, pwu_repository_t
*rep
,
77 int ldap_update(attrlist
*items
, pwu_repository_t
*rep
, void *buf
);
78 int ldap_putpwnam(char *name
, char *oldpw
, pwu_repository_t
*rep
, void *buf
);
79 int ldap_user_to_authenticate(char *name
, pwu_repository_t
*rep
,
80 char **auth_user
, int *privileged
);
83 * ldap function pointer table, used by passwdutil_init to initialize
84 * the global Repository-OPerations table "rops"
86 struct repops ldap_repops
= {
87 NULL
, /* checkhistory */
92 ldap_user_to_authenticate
,
98 * structure used to keep state between get/update/put calls
101 char *passwd
; /* encrypted password */
103 ns_ldap_attr_t
**pattrs
; /* passwd attrs */
104 int npattrs
; /* max attrs */
106 ns_ldap_attr_t
**sattrs
; /* passwd attrs */
107 int nsattrs
; /* max attrs */
108 boolean_t shadow_update_enabled
; /* shadow update configured */
112 * The following define's are taken from
113 * usr/src/lib/nsswitch/ldap/common/getpwnam.c
116 /* passwd attributes filters */
118 #define _PWD_UID "uid"
119 #define _PWD_USERPASSWORD "userpassword"
120 #define _PWD_UIDNUMBER "uidnumber"
121 #define _PWD_GIDNUMBER "gidnumber"
122 #define _PWD_GECOS "gecos"
123 #define _PWD_DESCRIPTION "description"
124 #define _PWD_HOMEDIRECTORY "homedirectory"
125 #define _PWD_LOGINSHELL "loginshell"
127 #define _PWD_MAX_ATTR 10 /* 9+NULL */
129 /* shadow attributes filters */
130 #define _S_LASTCHANGE "shadowlastchange"
131 #define _S_MIN "shadowmin"
132 #define _S_MAX "shadowmax"
133 #define _S_WARNING "shadowwarning"
134 #define _S_INACTIVE "shadowinactive"
135 #define _S_EXPIRE "shadowexpire"
136 #define _S_FLAG "shadowflag"
138 #define _S_MAX_ATTR 8 /* 7+NULL */
141 * Frees up an ldapbuf_t
145 free_ldapbuf(ldapbuf_t
*p
)
152 (void) memset(p
->passwd
, 0, strlen(p
->passwd
));
160 for (i
= 0; i
< p
->npattrs
; i
++) {
161 if (p
->pattrs
[i
] != NULL
) {
162 free(p
->pattrs
[i
]->attrvalue
[0]);
169 for (i
= 0; i
< p
->nsattrs
; i
++) {
170 if (p
->sattrs
[i
] != NULL
) {
171 free(p
->sattrs
[i
]->attrvalue
[0]);
180 * int ldap_user_to_authenticate(user, rep, auth_user, privileged)
182 * If the Shadow Update functionality is enabled, then we check to
183 * see if the caller has 0 as the euid or has all zone privs. If so,
184 * the caller would be able to modify shadow(4) data stored on the
185 * LDAP server. Otherwise, when LDAP Shadow Update is not enabled,
186 * we can't determine whether the user is "privileged" in the LDAP
187 * sense. The operation should be attempted and will succeed if the
188 * user had privileges. For our purposes, we say that the user is
189 * privileged if they are attempting to change another user's
190 * password attributes.
193 ldap_user_to_authenticate(char *user
, pwu_repository_t
*rep
,
194 char **auth_user
, int *privileged
)
198 uid_t priviledged_uid
;
199 int res
= PWU_SUCCESS
;
201 if (strcmp(user
, "root") == 0)
202 return (PWU_NOT_FOUND
);
204 if ((pw
= getpwnam_from(user
, rep
, REP_LDAP
)) == NULL
)
205 return (PWU_NOT_FOUND
);
210 * need equivalent of write access to /etc/shadow
211 * the privilege escalation model is euid == 0 || all zone privs
213 if (__ns_ldap_is_shadow_update_enabled()) {
216 priv
= (geteuid() == 0);
218 priv_set_t
*ps
= priv_allocset(); /* caller */
219 priv_set_t
*zs
; /* zone */
221 (void) getppriv(PRIV_EFFECTIVE
, ps
);
222 zs
= priv_str_to_set("zone", ",", NULL
);
223 priv
= priv_isequalset(ps
, zs
);
228 * priv can change anyone's password,
229 * only root isn't prompted.
231 *privileged
= 0; /* for proper prompting */
237 } else if (uid
== pw
->pw_uid
) {
238 STRDUP_OR_ERR(*auth_user
, user
, res
);
246 if (uid
== pw
->pw_uid
) {
247 /* changing our own, not privileged */
249 STRDUP_OR_RET(*auth_user
, user
);
256 * specific case for root
257 * we want 'user' to be authenticated.
260 priviledged_uid
= pw
->pw_uid
;
262 priviledged_uid
= uid
;
264 if (getpwuid_r(priviledged_uid
, &pwr
, pwd_buf
,
265 sizeof (pwd_buf
)) != NULL
) {
266 STRDUP_OR_ERR(*auth_user
, pwr
.pw_name
, res
);
268 /* hmm. can't find name of current user...??? */
270 if ((*auth_user
= malloc(MAX_INT_LEN
)) == NULL
) {
273 (void) snprintf(*auth_user
, MAX_INT_LEN
, "%d",
283 * int ldap_getattr(name, item, rep)
285 * retrieve attributes specified in "item" for user "name".
289 ldap_getattr(char *name
, attrlist
*items
, pwu_repository_t
*rep
)
294 struct passwd
*pw
= NULL
;
295 struct spwd
*spw
= NULL
;
297 res
= ldap_getpwnam(name
, items
, rep
, (void **)&ldapbuf
);
298 if (res
!= PWU_SUCCESS
)
304 for (w
= items
; res
== PWU_SUCCESS
&& w
!= NULL
; w
= w
->next
) {
307 STRDUP_OR_ERR(w
->data
.val_s
, pw
->pw_name
, res
);
310 STRDUP_OR_ERR(w
->data
.val_s
, pw
->pw_comment
, res
);
313 STRDUP_OR_ERR(w
->data
.val_s
, pw
->pw_gecos
, res
);
316 STRDUP_OR_ERR(w
->data
.val_s
, pw
->pw_dir
, res
);
319 STRDUP_OR_ERR(w
->data
.val_s
, pw
->pw_shell
, res
);
322 case ATTR_PASSWD_SERVER_POLICY
:
323 STRDUP_OR_ERR(w
->data
.val_s
, spw
->sp_pwdp
, res
);
326 STRDUP_OR_ERR(w
->data
.val_s
, pw
->pw_age
, res
);
329 STRDUP_OR_ERR(w
->data
.val_s
, "ldap", res
);
334 w
->data
.val_i
= pw
->pw_uid
;
337 w
->data
.val_i
= pw
->pw_gid
;
340 if (ldapbuf
->shadow_update_enabled
)
341 w
->data
.val_i
= spw
->sp_lstchg
;
346 if (ldapbuf
->shadow_update_enabled
)
347 w
->data
.val_i
= spw
->sp_min
;
352 if (ldapbuf
->shadow_update_enabled
)
353 w
->data
.val_i
= spw
->sp_max
;
358 if (ldapbuf
->shadow_update_enabled
)
359 w
->data
.val_i
= spw
->sp_warn
;
364 if (ldapbuf
->shadow_update_enabled
)
365 w
->data
.val_i
= spw
->sp_inact
;
370 if (ldapbuf
->shadow_update_enabled
)
371 w
->data
.val_i
= spw
->sp_expire
;
376 if (ldapbuf
->shadow_update_enabled
)
377 w
->data
.val_i
= spw
->sp_flag
;
379 case ATTR_FAILED_LOGINS
:
380 w
->data
.val_i
= spw
->sp_flag
& FAILCOUNT_MASK
;
388 free_ldapbuf(ldapbuf
);
394 * int ldap_getpwnam(name, items, rep, buf)
396 * There is no need to get the old values from the ldap
397 * server, as the update will update each item individually.
398 * Therefore, we only allocate a buffer that will be used by
399 * _update and _putpwnam to hold the attributes to update.
401 * Only when we're about to update a password, we need to retrieve
402 * the old password since it contains salt-information.
406 ldap_getpwnam(char *name
, attrlist
*items
, pwu_repository_t
*rep
,
413 * [sp]attrs is treated as NULL terminated
416 ldapbuf
= calloc(1, sizeof (ldapbuf_t
));
420 ldapbuf
->pattrs
= calloc(_PWD_MAX_ATTR
, sizeof (ns_ldap_attr_t
*));
421 if (ldapbuf
->pattrs
== NULL
)
423 ldapbuf
->npattrs
= _PWD_MAX_ATTR
;
425 ldapbuf
->sattrs
= calloc(_S_MAX_ATTR
, sizeof (ns_ldap_attr_t
*));
426 if (ldapbuf
->sattrs
== NULL
)
428 ldapbuf
->nsattrs
= _S_MAX_ATTR
;
430 res
= dup_pw(&ldapbuf
->pwd
, getpwnam_from(name
, rep
, REP_LDAP
));
431 if (res
!= PWU_SUCCESS
)
434 res
= dup_spw(&ldapbuf
->spwd
, getspnam_from(name
, rep
, REP_LDAP
));
435 if (res
!= PWU_SUCCESS
)
438 char *spw
= ldapbuf
->spwd
->sp_pwdp
;
439 if (spw
!= NULL
&& *spw
!= '\0') {
440 ldapbuf
->passwd
= strdup(spw
);
441 if (ldapbuf
->passwd
== NULL
)
444 ldapbuf
->passwd
= NULL
;
447 /* remember if shadow update is enabled */
448 ldapbuf
->shadow_update_enabled
= __ns_ldap_is_shadow_update_enabled();
450 *buf
= (void *)ldapbuf
;
451 return (PWU_SUCCESS
);
454 free_ldapbuf(ldapbuf
);
460 * new_attr(name, value)
462 * create a new LDAP attribute to be sent to the server
465 new_attr(char *name
, char *value
)
469 tmp
= malloc(sizeof (*tmp
));
471 tmp
->attrname
= name
;
472 tmp
->attrvalue
= (char **)calloc(2, sizeof (char *));
473 if (tmp
->attrvalue
== NULL
) {
477 tmp
->attrvalue
[0] = value
;
478 tmp
->value_count
= 1;
487 * returns '1' if a ATTR_MAX with value != -1 is present. (in other words:
488 * if password aging is to be turned on).
491 max_present(attrlist
*list
)
494 if (list
->type
== ATTR_MAX
&& list
->data
.val_i
!= -1)
502 * attr_addmod(attrs, idx, item, val)
504 * Adds or updates attribute 'item' in ldap_attrs list to value
505 * update idx if item is added
506 * return: -1 - PWU_NOMEM/error, 0 - success
509 attr_addmod(ns_ldap_attr_t
**attrs
, int *idx
, char *item
, int value
)
511 char numbuf
[MAX_INT_LEN
], *strp
;
514 /* stringize the value or abort */
515 if (snprintf(numbuf
, MAX_INT_LEN
, "%d", value
) >= MAX_INT_LEN
)
518 /* check for existence and modify existing */
519 for (i
= 0; i
< *idx
; i
++) {
520 if (attrs
[i
] != NULL
&&
521 strcmp(item
, attrs
[i
]->attrname
) == 0) {
522 strp
= strdup(numbuf
);
525 free(attrs
[i
]->attrvalue
[0]);
526 attrs
[i
]->attrvalue
[0] = strp
;
531 strp
= strdup(numbuf
);
534 attrs
[*idx
] = new_attr(item
, strp
);
535 if (attrs
[*idx
] == NULL
)
542 * ldap_update(items, rep, buf)
544 * create LDAP attributes in 'buf' for each attribute in 'items'.
548 ldap_update(attrlist
*items
, pwu_repository_t
*rep
, void *buf
)
551 ldapbuf_t
*ldapbuf
= (ldapbuf_t
*)buf
;
553 ns_ldap_attr_t
**pattrs
= ldapbuf
->pattrs
;
555 ns_ldap_attr_t
**sattrs
= ldapbuf
->sattrs
;
562 int rc
= PWU_SUCCESS
;
563 int aging_needed
= 0;
570 * if sp_max==0 and shadow update is enabled:
571 * disable passwd aging after updating the password
573 disable_aging
= (spw
!= NULL
&& spw
->sp_max
== 0 &&
574 ldapbuf
->shadow_update_enabled
);
576 for (p
= items
; p
!= NULL
; p
= p
->next
) {
580 * There is a special case for ldap: if the
581 * password is to be deleted (-d to passwd),
582 * p->data.val_s will be NULL.
584 if (p
->data
.val_s
== NULL
) {
585 if (!ldapbuf
->shadow_update_enabled
)
586 return (PWU_CHANGE_NOT_ALLOWED
);
588 sizeof ("{crypt}" NS_LDAP_NO_UNIX_PASSWORD
);
589 val
= malloc(cryptlen
);
592 (void) snprintf(val
, cryptlen
,
593 "{crypt}" NS_LDAP_NO_UNIX_PASSWORD
);
594 } else { /* not deleting password */
595 salt
= crypt_gensalt(ldapbuf
->passwd
,
602 /* algorithm problem? */
603 syslog(LOG_AUTH
| LOG_ALERT
,
604 "passwdutil: crypt_gensalt "
606 return (PWU_UPDATE_FAILED
);
609 pwd
= crypt(p
->data
.val_s
, salt
);
611 cryptlen
= strlen(pwd
) + sizeof ("{crypt}");
612 val
= malloc(cryptlen
);
615 (void) snprintf(val
, cryptlen
,
620 * If not managing passwordAccount,
621 * insert the new password in the
622 * passwd attr array and break.
624 if (!ldapbuf
->shadow_update_enabled
) {
625 NEW_ATTR(pattrs
, pidx
,
626 _PWD_USERPASSWORD
, val
);
631 * Managing passwordAccount, insert the
632 * new password, along with lastChange and
633 * shadowFlag, in the shadow attr array.
635 NEW_ATTR(sattrs
, sidx
, _PWD_USERPASSWORD
, val
);
637 if (attr_addmod(sattrs
, &sidx
, _S_LASTCHANGE
,
640 spw
->sp_lstchg
= DAY_NOW_32
;
642 if (attr_addmod(sattrs
, &sidx
, _S_FLAG
,
643 spw
->sp_flag
& ~FAILCOUNT_MASK
) < 0)
645 spw
->sp_flag
&= ~FAILCOUNT_MASK
; /* reset count */
648 case ATTR_PASSWD_SERVER_POLICY
:
650 * For server policy, don't crypt the password,
651 * send the password as is to the server and
652 * let the LDAP server do its own password
655 STRDUP_OR_RET(val
, p
->data
.val_s
);
657 NEW_ATTR(pattrs
, pidx
, _PWD_USERPASSWORD
, val
);
661 NEW_ATTR(pattrs
, pidx
, _PWD_DESCRIPTION
, p
->data
.val_s
);
664 if (!ldapbuf
->shadow_update_enabled
) {
665 NEW_ATTR(pattrs
, pidx
, _PWD_GECOS
,
668 NEW_ATTR(sattrs
, sidx
, _PWD_GECOS
,
673 if (!ldapbuf
->shadow_update_enabled
) {
674 NEW_ATTR(pattrs
, pidx
, _PWD_HOMEDIRECTORY
,
677 NEW_ATTR(sattrs
, sidx
, _PWD_HOMEDIRECTORY
,
682 if (!ldapbuf
->shadow_update_enabled
) {
683 NEW_ATTR(pattrs
, pidx
, _PWD_LOGINSHELL
,
686 NEW_ATTR(sattrs
, sidx
, _PWD_LOGINSHELL
,
690 /* We don't update NAME, UID, GID */
694 /* Unsupported item */
697 case ATTR_LOCK_ACCOUNT
:
698 if (!ldapbuf
->shadow_update_enabled
)
699 break; /* not managing passwordAccount */
700 if (spw
->sp_pwdp
== NULL
) {
701 spw
->sp_pwdp
= LOCKSTRING
;
702 } else if ((strncmp(spw
->sp_pwdp
, LOCKSTRING
,
703 sizeof (LOCKSTRING
)-1) != 0) &&
704 (strcmp(spw
->sp_pwdp
, NOLOGINSTRING
) != 0)) {
705 len
= sizeof (LOCKSTRING
)-1 +
706 strlen(spw
->sp_pwdp
) + 1 +
712 (void) strlcpy(pwd
, "{crypt}", len
);
713 (void) strlcat(pwd
, LOCKSTRING
, len
);
714 (void) strlcat(pwd
, spw
->sp_pwdp
, len
);
717 NEW_ATTR(sattrs
, sidx
, _PWD_USERPASSWORD
,
720 if (attr_addmod(sattrs
, &sidx
, _S_LASTCHANGE
,
723 spw
->sp_lstchg
= DAY_NOW_32
;
726 case ATTR_UNLOCK_ACCOUNT
:
727 if (!ldapbuf
->shadow_update_enabled
)
728 break; /* not managing passwordAccount */
730 strncmp(spw
->sp_pwdp
, LOCKSTRING
,
731 sizeof (LOCKSTRING
)-1) == 0) {
732 len
= (sizeof ("{crypt}") -
733 sizeof (LOCKSTRING
)) +
734 strlen(spw
->sp_pwdp
) + 1;
739 (void) strlcpy(pwd
, "{crypt}", len
);
740 (void) strlcat(pwd
, spw
->sp_pwdp
+
741 sizeof (LOCKSTRING
)-1, len
);
745 NEW_ATTR(sattrs
, sidx
, _PWD_USERPASSWORD
,
747 if (attr_addmod(sattrs
, &sidx
, _S_LASTCHANGE
,
750 spw
->sp_lstchg
= DAY_NOW_32
;
754 case ATTR_NOLOGIN_ACCOUNT
:
755 if (!ldapbuf
->shadow_update_enabled
)
756 break; /* not managing passwordAccount */
758 STRDUP_OR_RET(spw
->sp_pwdp
, "{crypt}" NOLOGINSTRING
);
759 NEW_ATTR(sattrs
, sidx
, _PWD_USERPASSWORD
, spw
->sp_pwdp
);
760 if (attr_addmod(sattrs
, &sidx
, _S_LASTCHANGE
,
763 spw
->sp_lstchg
= DAY_NOW_32
;
766 case ATTR_EXPIRE_PASSWORD
:
767 if (!ldapbuf
->shadow_update_enabled
)
768 break; /* not managing passwordAccount */
770 NEW_ATTR(sattrs
, sidx
, _S_LASTCHANGE
, val
);
774 if (!ldapbuf
->shadow_update_enabled
)
775 break; /* not managing passwordAccount */
776 NUM_TO_STR(val
, p
->data
.val_i
);
777 NEW_ATTR(sattrs
, sidx
, _S_LASTCHANGE
, val
);
781 if (!ldapbuf
->shadow_update_enabled
)
782 break; /* not managing passwordAccount */
783 if (spw
->sp_max
== -1 && p
->data
.val_i
!= -1 &&
784 max_present(p
->next
) == 0)
785 return (PWU_AGING_DISABLED
);
786 NUM_TO_STR(val
, p
->data
.val_i
);
787 NEW_ATTR(sattrs
, sidx
, _S_MIN
, val
);
792 if (!ldapbuf
->shadow_update_enabled
)
793 break; /* not managing passwordAccount */
794 if (p
->data
.val_i
== -1) {
795 /* Turn off aging. Reset min and warn too */
796 spw
->sp_max
= spw
->sp_min
= spw
->sp_warn
= -1;
798 NEW_ATTR(sattrs
, sidx
, _S_MIN
, val
);
800 NEW_ATTR(sattrs
, sidx
, _S_WARNING
, val
);
802 /* Turn account aging on */
803 if (spw
->sp_min
== -1) {
805 * minage was not set with command-
806 * line option: set to zero
810 NEW_ATTR(sattrs
, sidx
, _S_MIN
,
814 * If aging was turned off, we update lstchg.
815 * We take care not to update lstchg if the
816 * user has no password, otherwise the user
817 * might not be required to provide a password
818 * the next time they log in.
820 * Also, if lstchg != -1 (i.e., not set)
821 * we keep the old value.
823 if (spw
->sp_max
== -1 &&
824 spw
->sp_pwdp
!= NULL
&& *spw
->sp_pwdp
&&
825 spw
->sp_lstchg
== -1) {
826 if (attr_addmod(sattrs
, &sidx
,
830 spw
->sp_lstchg
= DAY_NOW_32
;
833 NUM_TO_STR(val
, p
->data
.val_i
);
834 NEW_ATTR(sattrs
, sidx
, _S_MAX
, val
);
839 if (!ldapbuf
->shadow_update_enabled
)
840 break; /* not managing passwordAccount */
841 if (spw
->sp_max
== -1 &&
842 p
->data
.val_i
!= -1 && max_present(p
->next
) == 0)
843 return (PWU_AGING_DISABLED
);
844 NUM_TO_STR(val
, p
->data
.val_i
);
845 NEW_ATTR(sattrs
, sidx
, _S_WARNING
, val
);
849 if (!ldapbuf
->shadow_update_enabled
)
850 break; /* not managing passwordAccount */
851 NUM_TO_STR(val
, p
->data
.val_i
);
852 NEW_ATTR(sattrs
, sidx
, _S_INACTIVE
, val
);
856 if (!ldapbuf
->shadow_update_enabled
)
857 break; /* not managing passwordAccount */
858 NUM_TO_STR(val
, p
->data
.val_i
);
859 NEW_ATTR(sattrs
, sidx
, _S_EXPIRE
, val
);
863 if (!ldapbuf
->shadow_update_enabled
)
864 break; /* not managing passwordAccount */
865 NUM_TO_STR(val
, p
->data
.val_i
);
866 NEW_ATTR(sattrs
, sidx
, _S_FLAG
, val
);
868 case ATTR_INCR_FAILED_LOGINS
:
869 if (!ldapbuf
->shadow_update_enabled
) {
870 rc
= PWU_CHANGE_NOT_ALLOWED
;
871 break; /* not managing passwordAccount */
873 count
= (spw
->sp_flag
& FAILCOUNT_MASK
) + 1;
874 spw
->sp_flag
&= ~FAILCOUNT_MASK
;
875 spw
->sp_flag
|= min(FAILCOUNT_MASK
, count
);
876 p
->data
.val_i
= count
;
877 NUM_TO_STR(val
, spw
->sp_flag
);
878 NEW_ATTR(sattrs
, sidx
, _S_FLAG
, val
);
880 case ATTR_RST_FAILED_LOGINS
:
881 if (!ldapbuf
->shadow_update_enabled
) {
882 rc
= PWU_CHANGE_NOT_ALLOWED
;
883 break; /* not managing passwordAccount */
885 p
->data
.val_i
= spw
->sp_flag
& FAILCOUNT_MASK
;
886 spw
->sp_flag
&= ~FAILCOUNT_MASK
;
887 NUM_TO_STR(val
, spw
->sp_flag
);
888 NEW_ATTR(sattrs
, sidx
, _S_FLAG
, val
);
896 * If the ldap client is configured with shadow update enabled,
897 * then what should the new aging values look like?
899 * There are a number of different conditions
901 * a) aging is already configured: don't touch it
903 * b) disable_aging is set: disable aging
905 * c) aging is not configured: turn on default aging;
907 * b) and c) of course only if aging_needed and !aging_set.
908 * (i.e., password changed, and aging values not changed)
911 if (ldapbuf
->shadow_update_enabled
&& spw
!= NULL
&& spw
->sp_max
<= 0) {
912 /* a) aging not yet configured */
913 if (aging_needed
&& !aging_set
) {
915 /* b) turn off aging */
916 spw
->sp_min
= spw
->sp_max
= spw
->sp_warn
= -1;
917 if (attr_addmod(sattrs
, &sidx
, _S_MIN
, -1) < 0)
919 if (attr_addmod(sattrs
, &sidx
, _S_MAX
, -1) < 0)
921 if (attr_addmod(sattrs
, &sidx
, _S_WARNING
,
926 turn_on_default_aging(spw
);
928 if (attr_addmod(sattrs
, &sidx
, _S_MIN
,
931 if (attr_addmod(sattrs
, &sidx
, _S_MAX
,
934 if (attr_addmod(sattrs
, &sidx
,
935 _S_WARNING
, spw
->sp_warn
) < 0)
948 * ldap_to_pwu_code(error, pwd_status)
950 * translation from LDAP return values and PWU return values
953 ldap_to_pwu_code(int error
, int pwd_status
)
956 case NS_LDAP_SUCCESS
: return (PWU_SUCCESS
);
957 case NS_LDAP_OP_FAILED
: return (PWU_DENIED
);
958 case NS_LDAP_NOTFOUND
: return (PWU_NOT_FOUND
);
959 case NS_LDAP_MEMORY
: return (PWU_NOMEM
);
960 case NS_LDAP_CONFIG
: return (PWU_NOT_FOUND
);
961 case NS_LDAP_INTERNAL
:
962 switch (pwd_status
) {
963 case NS_PASSWD_EXPIRED
:
965 case NS_PASSWD_CHANGE_NOT_ALLOWED
:
966 return (PWU_CHANGE_NOT_ALLOWED
);
967 case NS_PASSWD_TOO_SHORT
:
968 return (PWU_PWD_TOO_SHORT
);
969 case NS_PASSWD_INVALID_SYNTAX
:
970 return (PWU_PWD_INVALID
);
971 case NS_PASSWD_IN_HISTORY
:
972 return (PWU_PWD_IN_HISTORY
);
973 case NS_PASSWD_WITHIN_MIN_AGE
:
974 return (PWU_WITHIN_MIN_AGE
);
976 return (PWU_SYSTEM_ERROR
);
978 default: return (PWU_SYSTEM_ERROR
);
983 ldap_replaceattr(const char *dn
, ns_ldap_attr_t
**attrs
, const char *binddn
,
984 const char *pwd
, int *pwd_status
, int flags
)
986 int result
= NS_LDAP_OP_FAILED
;
989 char **certpath
= NULL
;
991 ns_auth_t
**authpp
= NULL
;
992 ns_auth_t
*authp
= NULL
;
994 ns_ldap_error_t
*errorp
= NULL
;
996 debug("%s: replace_ldapattr()", __FILE__
);
998 if ((credp
= (ns_cred_t
*)calloc(1, sizeof (ns_cred_t
))) == NULL
)
999 return (NS_LDAP_MEMORY
); /* map to PWU_NOMEM */
1001 /* for admin shadow update, dn and pwd will be set later in libsldap */
1002 if ((flags
& NS_LDAP_UPDATE_SHADOW
) == 0) {
1003 /* Fill in the user name and password */
1004 if (dn
== NULL
|| pwd
== NULL
)
1006 credp
->cred
.unix_cred
.userID
= strdup(binddn
);
1007 credp
->cred
.unix_cred
.passwd
= strdup(pwd
);
1010 /* get host certificate path, if one is configured */
1011 ldaprc
= __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P
,
1012 (void ***)&certpath
, &errorp
);
1013 if (ldaprc
!= NS_LDAP_SUCCESS
)
1016 if (certpath
&& *certpath
)
1017 credp
->hostcertpath
= *certpath
;
1019 /* Load the service specific authentication method */
1020 ldaprc
= __ns_ldap_getServiceAuthMethods("passwd-cmd", &authpp
,
1023 if (ldaprc
!= NS_LDAP_SUCCESS
)
1027 * if authpp is null, there is no serviceAuthenticationMethod
1028 * try default authenticationMethod
1030 if (authpp
== NULL
) {
1031 ldaprc
= __ns_ldap_getParam(NS_LDAP_AUTH_P
, (void ***)&authpp
,
1033 if (ldaprc
!= NS_LDAP_SUCCESS
)
1038 * if authpp is still null, then can not authenticate, syslog
1039 * error message and return error
1041 if (authpp
== NULL
) {
1043 "passwdutil: no legal LDAP authentication method configured");
1044 result
= NS_LDAP_OP_FAILED
;
1049 * Walk the array and try all authentication methods in order except
1052 for (app
= authpp
; *app
; app
++) {
1054 /* what about disabling other mechanisms? "tls:sasl/EXTERNAL" */
1055 if (authp
->type
== NS_LDAP_AUTH_NONE
)
1058 credp
->auth
.type
= authp
->type
;
1059 credp
->auth
.tlstype
= authp
->tlstype
;
1060 credp
->auth
.saslmech
= authp
->saslmech
;
1061 credp
->auth
.saslopt
= authp
->saslopt
;
1063 ldaprc
= __ns_ldap_repAttr("shadow", dn
,
1064 (const ns_ldap_attr_t
* const *)attrs
,
1065 credp
, flags
, &errorp
);
1066 if (ldaprc
== NS_LDAP_SUCCESS
) {
1067 result
= NS_LDAP_SUCCESS
;
1072 * if change not allowed due to configuration, indicate so
1075 if (ldaprc
== NS_LDAP_CONFIG
&&
1076 errorp
->status
== NS_CONFIG_NOTALLOW
) {
1077 result
= NS_LDAP_CONFIG
;
1078 *pwd_status
= NS_PASSWD_CHANGE_NOT_ALLOWED
;
1083 * other errors might need to be added to this list, for
1084 * the current supported mechanisms this is sufficient
1086 if ((ldaprc
== NS_LDAP_INTERNAL
) &&
1087 (errorp
->pwd_mgmt
.status
== NS_PASSWD_GOOD
) &&
1088 ((errorp
->status
== LDAP_INAPPROPRIATE_AUTH
) ||
1089 (errorp
->status
== LDAP_INVALID_CREDENTIALS
))) {
1095 * If there is error related to password policy,
1096 * return it to caller
1098 if ((ldaprc
== NS_LDAP_INTERNAL
) &&
1099 errorp
->pwd_mgmt
.status
!= NS_PASSWD_GOOD
) {
1100 *pwd_status
= errorp
->pwd_mgmt
.status
;
1104 *pwd_status
= NS_PASSWD_GOOD
;
1106 /* we don't really care about the error, just clean it up */
1108 (void) __ns_ldap_freeError(&errorp
);
1110 if (authstried
== 0) {
1112 "passwdutil: no legal LDAP authentication method configured");
1113 result
= NS_LDAP_CONFIG
;
1116 result
= NS_LDAP_OP_FAILED
; /* map to PWU_DENIED */
1120 (void) __ns_ldap_freeCred(&credp
);
1123 (void) __ns_ldap_freeParam((void ***)&authpp
);
1126 (void) __ns_ldap_freeError(&errorp
);
1133 * ldap_putpwnam(name, oldpw, rep, buf)
1135 * update the LDAP server with the attributes contained in 'buf'.
1139 ldap_putpwnam(char *name
, char *oldpw
, pwu_repository_t
*rep
, void *buf
)
1142 char *dn
; /* dn of user whose attributes we are changing */
1143 char *binddn
; /* dn of user who is performing the change */
1144 ns_ldap_error_t
*errorp
;
1145 ldapbuf_t
*ldapbuf
= (ldapbuf_t
*)buf
;
1146 ns_ldap_attr_t
**pattrs
= ldapbuf
->pattrs
;
1147 ns_ldap_attr_t
**sattrs
= ldapbuf
->sattrs
;
1152 if (strcmp(name
, "root") == 0)
1153 return (PWU_NOT_FOUND
);
1156 * convert name of user whose attributes we are changing
1157 * to a distinguished name
1159 res
= __ns_ldap_uid2dn(name
, &dn
, NULL
, &errorp
);
1160 if (res
!= NS_LDAP_SUCCESS
)
1163 /* update shadow via ldap_cachemgr if it is enabled */
1164 if (ldapbuf
->shadow_update_enabled
&&
1165 sattrs
!= NULL
&& sattrs
[0] != NULL
) {
1167 * flag NS_LDAP_UPDATE_SHADOW indicates the shadow update
1168 * should be done via ldap_cachemgr
1170 res
= ldap_replaceattr(dn
, sattrs
, NULL
, NULL
, &pwd_status
,
1171 NS_LDAP_UPDATE_SHADOW
);
1176 * The LDAP server checks whether we are permitted to perform
1177 * the requested change. We need to send the name of the user
1178 * who is executing this piece of code, together with his
1179 * current password to the server.
1180 * If this is executed by a normal user changing his/her own
1181 * password, this will simply be the OLD password that is to
1183 * Specific case if the user who is executing this piece
1184 * of code is root. We will then issue the LDAP request
1185 * with the DN of the user we want to change the passwd of.
1189 * create a dn for the user who is executing this code
1193 if ((pw
= getpwnam_from(name
, rep
, REP_LDAP
)) == NULL
) {
1194 res
= NS_LDAP_OP_FAILED
;
1197 } else if ((pw
= getpwuid_from(uid
, rep
, REP_LDAP
)) == NULL
) {
1199 * User executing this code is not known to the LDAP
1200 * server. This operation is to be denied
1202 res
= NS_LDAP_OP_FAILED
;
1206 res
= __ns_ldap_uid2dn(pw
->pw_name
, &binddn
, NULL
, &errorp
);
1207 if (res
!= NS_LDAP_SUCCESS
)
1210 if (pattrs
&& pattrs
[0] != NULL
) {
1211 res
= ldap_replaceattr(dn
, pattrs
, binddn
, oldpw
,
1214 res
= NS_LDAP_OP_FAILED
;
1217 free_ldapbuf(ldapbuf
);
1220 return (ldap_to_pwu_code(res
, pwd_status
));