8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / passwdutil / ldap_attr.c
blob4c43eb7adb04f5522b5131214c4361e5d75156d1
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.
24 * Copyright (c) 2016 by Delphix. All rights reserved.
27 #include <stdio.h>
28 #include <errno.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <macros.h>
33 #include <priv.h>
35 #include "ns_sldap.h"
37 #include <nss_dbdefs.h>
38 #include <nsswitch.h>
40 #include <pwd.h>
41 #include <shadow.h>
42 #include <syslog.h>
44 #include "passwdutil.h"
46 #include "utils.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) \
52 return (PWU_NOMEM);
54 #define STRDUP_OR_ERR(to, from, err) \
55 if (((to) = strdup(from)) == NULL) \
56 (err) = PWU_NOMEM;
58 #define NUM_TO_STR(to, from) \
59 { \
60 char nb[MAX_INT_LEN]; \
61 if (snprintf(nb, MAX_INT_LEN, "%d", (from)) >= MAX_INT_LEN) \
62 return (PWU_NOMEM); \
63 STRDUP_OR_RET(to, nb); \
66 #define NEW_ATTR(p, i, attr, val) \
67 { \
68 p[i] = new_attr(attr, (val)); \
69 if (p[i] == NULL) \
70 return (PWU_NOMEM); \
71 i++; \
74 int ldap_getattr(char *name, attrlist *item, pwu_repository_t *rep);
75 int ldap_getpwnam(char *name, attrlist *items, pwu_repository_t *rep,
76 void **buf);
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 */
88 ldap_getattr,
89 ldap_getpwnam,
90 ldap_update,
91 ldap_putpwnam,
92 ldap_user_to_authenticate,
93 NULL, /* lock */
94 NULL /* unlock */
98 * structure used to keep state between get/update/put calls
100 typedef struct {
101 char *passwd; /* encrypted password */
102 struct passwd *pwd;
103 ns_ldap_attr_t **pattrs; /* passwd attrs */
104 int npattrs; /* max attrs */
105 struct spwd *spwd;
106 ns_ldap_attr_t **sattrs; /* passwd attrs */
107 int nsattrs; /* max attrs */
108 boolean_t shadow_update_enabled; /* shadow update configured */
109 } ldapbuf_t;
112 * The following define's are taken from
113 * usr/src/lib/nsswitch/ldap/common/getpwnam.c
116 /* passwd attributes filters */
117 #define _PWD_CN "cn"
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
144 static void
145 free_ldapbuf(ldapbuf_t *p)
147 int i;
149 if (p == NULL)
150 return;
151 if (p->passwd) {
152 (void) memset(p->passwd, 0, strlen(p->passwd));
153 free(p->passwd);
155 if (p->pwd)
156 free_pwd(p->pwd);
157 if (p->spwd)
158 free_spwd(p->spwd);
159 if (p->pattrs) {
160 for (i = 0; i < p->npattrs; i++) {
161 if (p->pattrs[i] != NULL) {
162 free(p->pattrs[i]->attrvalue[0]);
163 free(p->pattrs[i]);
166 free(p->pattrs);
168 if (p->sattrs) {
169 for (i = 0; i < p->nsattrs; i++) {
170 if (p->sattrs[i] != NULL) {
171 free(p->sattrs[i]->attrvalue[0]);
172 free(p->sattrs[i]);
175 free(p->sattrs);
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)
196 struct passwd *pw;
197 uid_t uid;
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);
207 uid = getuid();
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()) {
214 boolean_t priv;
216 priv = (geteuid() == 0);
217 if (!priv) {
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);
224 priv_freeset(ps);
225 priv_freeset(zs);
228 * priv can change anyone's password,
229 * only root isn't prompted.
231 *privileged = 0; /* for proper prompting */
232 if (priv) {
233 if (uid == 0) {
234 *privileged = 1;
235 *auth_user = NULL;
236 return (res);
237 } else if (uid == pw->pw_uid) {
238 STRDUP_OR_ERR(*auth_user, user, res);
239 return (res);
243 return (PWU_DENIED);
246 if (uid == pw->pw_uid) {
247 /* changing our own, not privileged */
248 *privileged = 0;
249 STRDUP_OR_RET(*auth_user, user);
250 } else {
251 char pwd_buf[1024];
252 struct passwd pwr;
254 *privileged = 1;
256 * specific case for root
257 * we want 'user' to be authenticated.
259 if (uid == 0) {
260 priviledged_uid = pw->pw_uid;
261 } else {
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);
267 } else {
268 /* hmm. can't find name of current user...??? */
270 if ((*auth_user = malloc(MAX_INT_LEN)) == NULL) {
271 res = PWU_NOMEM;
272 } else {
273 (void) snprintf(*auth_user, MAX_INT_LEN, "%d",
274 (int)uid);
279 return (res);
283 * int ldap_getattr(name, item, rep)
285 * retrieve attributes specified in "item" for user "name".
287 /*ARGSUSED*/
289 ldap_getattr(char *name, attrlist *items, pwu_repository_t *rep)
291 attrlist *w;
292 int res;
293 ldapbuf_t *ldapbuf;
294 struct passwd *pw = NULL;
295 struct spwd *spw = NULL;
297 res = ldap_getpwnam(name, items, rep, (void **)&ldapbuf);
298 if (res != PWU_SUCCESS)
299 return (res);
301 pw = ldapbuf->pwd;
302 spw = ldapbuf->spwd;
304 for (w = items; res == PWU_SUCCESS && w != NULL; w = w->next) {
305 switch (w->type) {
306 case ATTR_NAME:
307 STRDUP_OR_ERR(w->data.val_s, pw->pw_name, res);
308 break;
309 case ATTR_COMMENT:
310 STRDUP_OR_ERR(w->data.val_s, pw->pw_comment, res);
311 break;
312 case ATTR_GECOS:
313 STRDUP_OR_ERR(w->data.val_s, pw->pw_gecos, res);
314 break;
315 case ATTR_HOMEDIR:
316 STRDUP_OR_ERR(w->data.val_s, pw->pw_dir, res);
317 break;
318 case ATTR_SHELL:
319 STRDUP_OR_ERR(w->data.val_s, pw->pw_shell, res);
320 break;
321 case ATTR_PASSWD:
322 case ATTR_PASSWD_SERVER_POLICY:
323 STRDUP_OR_ERR(w->data.val_s, spw->sp_pwdp, res);
324 break;
325 case ATTR_AGE:
326 STRDUP_OR_ERR(w->data.val_s, pw->pw_age, res);
327 break;
328 case ATTR_REP_NAME:
329 STRDUP_OR_ERR(w->data.val_s, "ldap", res);
330 break;
332 /* integer values */
333 case ATTR_UID:
334 w->data.val_i = pw->pw_uid;
335 break;
336 case ATTR_GID:
337 w->data.val_i = pw->pw_gid;
338 break;
339 case ATTR_LSTCHG:
340 if (ldapbuf->shadow_update_enabled)
341 w->data.val_i = spw->sp_lstchg;
342 else
343 w->data.val_i = -1;
344 break;
345 case ATTR_MIN:
346 if (ldapbuf->shadow_update_enabled)
347 w->data.val_i = spw->sp_min;
348 else
349 w->data.val_i = -1;
350 break;
351 case ATTR_MAX:
352 if (ldapbuf->shadow_update_enabled)
353 w->data.val_i = spw->sp_max;
354 else
355 w->data.val_i = -1;
356 break;
357 case ATTR_WARN:
358 if (ldapbuf->shadow_update_enabled)
359 w->data.val_i = spw->sp_warn;
360 else
361 w->data.val_i = -1;
362 break;
363 case ATTR_INACT:
364 if (ldapbuf->shadow_update_enabled)
365 w->data.val_i = spw->sp_inact;
366 else
367 w->data.val_i = -1;
368 break;
369 case ATTR_EXPIRE:
370 if (ldapbuf->shadow_update_enabled)
371 w->data.val_i = spw->sp_expire;
372 else
373 w->data.val_i = -1;
374 break;
375 case ATTR_FLAG:
376 if (ldapbuf->shadow_update_enabled)
377 w->data.val_i = spw->sp_flag;
378 break;
379 case ATTR_FAILED_LOGINS:
380 w->data.val_i = spw->sp_flag & FAILCOUNT_MASK;
381 break;
382 default:
383 break;
387 out:
388 free_ldapbuf(ldapbuf);
389 free(ldapbuf);
390 return (res);
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.
404 /*ARGSUSED*/
406 ldap_getpwnam(char *name, attrlist *items, pwu_repository_t *rep,
407 void **buf)
409 ldapbuf_t *ldapbuf;
410 int res = PWU_NOMEM;
413 * [sp]attrs is treated as NULL terminated
416 ldapbuf = calloc(1, sizeof (ldapbuf_t));
417 if (ldapbuf == NULL)
418 return (PWU_NOMEM);
420 ldapbuf->pattrs = calloc(_PWD_MAX_ATTR, sizeof (ns_ldap_attr_t *));
421 if (ldapbuf->pattrs == NULL)
422 goto out;
423 ldapbuf->npattrs = _PWD_MAX_ATTR;
425 ldapbuf->sattrs = calloc(_S_MAX_ATTR, sizeof (ns_ldap_attr_t *));
426 if (ldapbuf->sattrs == NULL)
427 goto out;
428 ldapbuf->nsattrs = _S_MAX_ATTR;
430 res = dup_pw(&ldapbuf->pwd, getpwnam_from(name, rep, REP_LDAP));
431 if (res != PWU_SUCCESS)
432 goto out;
434 res = dup_spw(&ldapbuf->spwd, getspnam_from(name, rep, REP_LDAP));
435 if (res != PWU_SUCCESS)
436 goto out;
437 else {
438 char *spw = ldapbuf->spwd->sp_pwdp;
439 if (spw != NULL && *spw != '\0') {
440 ldapbuf->passwd = strdup(spw);
441 if (ldapbuf->passwd == NULL)
442 goto out;
443 } else
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);
453 out:
454 free_ldapbuf(ldapbuf);
455 free(ldapbuf);
456 return (res);
460 * new_attr(name, value)
462 * create a new LDAP attribute to be sent to the server
464 ns_ldap_attr_t *
465 new_attr(char *name, char *value)
467 ns_ldap_attr_t *tmp;
469 tmp = malloc(sizeof (*tmp));
470 if (tmp != NULL) {
471 tmp->attrname = name;
472 tmp->attrvalue = (char **)calloc(2, sizeof (char *));
473 if (tmp->attrvalue == NULL) {
474 free(tmp);
475 return (NULL);
477 tmp->attrvalue[0] = value;
478 tmp->value_count = 1;
481 return (tmp);
485 * max_present(list)
487 * returns '1' if a ATTR_MAX with value != -1 is present. (in other words:
488 * if password aging is to be turned on).
490 static int
491 max_present(attrlist *list)
493 while (list != NULL)
494 if (list->type == ATTR_MAX && list->data.val_i != -1)
495 return (1);
496 else
497 list = list->next;
498 return (0);
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
508 static int
509 attr_addmod(ns_ldap_attr_t **attrs, int *idx, char *item, int value)
511 char numbuf[MAX_INT_LEN], *strp;
512 int i;
514 /* stringize the value or abort */
515 if (snprintf(numbuf, MAX_INT_LEN, "%d", value) >= MAX_INT_LEN)
516 return (-1);
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);
523 if (strp == NULL)
524 return (-1);
525 free(attrs[i]->attrvalue[0]);
526 attrs[i]->attrvalue[0] = strp;
527 return (0);
530 /* else add */
531 strp = strdup(numbuf);
532 if (strp == NULL)
533 return (-1);
534 attrs[*idx] = new_attr(item, strp);
535 if (attrs[*idx] == NULL)
536 return (-1);
537 (*idx)++;
538 return (0);
542 * ldap_update(items, rep, buf)
544 * create LDAP attributes in 'buf' for each attribute in 'items'.
546 /*ARGSUSED*/
548 ldap_update(attrlist *items, pwu_repository_t *rep, void *buf)
550 attrlist *p;
551 ldapbuf_t *ldapbuf = (ldapbuf_t *)buf;
552 struct spwd *spw;
553 ns_ldap_attr_t **pattrs = ldapbuf->pattrs;
554 int pidx = 0;
555 ns_ldap_attr_t **sattrs = ldapbuf->sattrs;
556 int sidx = 0;
557 char *pwd, *val;
558 char *salt;
559 size_t cryptlen;
560 int len;
561 int count;
562 int rc = PWU_SUCCESS;
563 int aging_needed = 0;
564 int aging_set = 0;
565 int disable_aging;
567 spw = ldapbuf->spwd;
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) {
577 switch (p->type) {
578 case ATTR_PASSWD:
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);
587 cryptlen =
588 sizeof ("{crypt}" NS_LDAP_NO_UNIX_PASSWORD);
589 val = malloc(cryptlen);
590 if (val == NULL)
591 return (PWU_NOMEM);
592 (void) snprintf(val, cryptlen,
593 "{crypt}" NS_LDAP_NO_UNIX_PASSWORD);
594 } else { /* not deleting password */
595 salt = crypt_gensalt(ldapbuf->passwd,
596 ldapbuf->pwd);
598 if (salt == NULL) {
599 if (errno == ENOMEM)
600 return (PWU_NOMEM);
602 /* algorithm problem? */
603 syslog(LOG_AUTH | LOG_ALERT,
604 "passwdutil: crypt_gensalt "
605 "%m");
606 return (PWU_UPDATE_FAILED);
609 pwd = crypt(p->data.val_s, salt);
610 free(salt);
611 cryptlen = strlen(pwd) + sizeof ("{crypt}");
612 val = malloc(cryptlen);
613 if (val == NULL)
614 return (PWU_NOMEM);
615 (void) snprintf(val, cryptlen,
616 "{crypt}%s", pwd);
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);
627 break;
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,
638 DAY_NOW_32) < 0)
639 return (PWU_NOMEM);
640 spw->sp_lstchg = DAY_NOW_32;
642 if (attr_addmod(sattrs, &sidx, _S_FLAG,
643 spw->sp_flag & ~FAILCOUNT_MASK) < 0)
644 return (PWU_NOMEM);
645 spw->sp_flag &= ~FAILCOUNT_MASK; /* reset count */
646 aging_needed = 1;
647 break;
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
653 * encryption
655 STRDUP_OR_RET(val, p->data.val_s);
657 NEW_ATTR(pattrs, pidx, _PWD_USERPASSWORD, val);
658 break;
659 case ATTR_COMMENT:
660 /* XX correct? */
661 NEW_ATTR(pattrs, pidx, _PWD_DESCRIPTION, p->data.val_s);
662 break;
663 case ATTR_GECOS:
664 if (!ldapbuf->shadow_update_enabled) {
665 NEW_ATTR(pattrs, pidx, _PWD_GECOS,
666 p->data.val_s);
667 } else {
668 NEW_ATTR(sattrs, sidx, _PWD_GECOS,
669 p->data.val_s);
671 break;
672 case ATTR_HOMEDIR:
673 if (!ldapbuf->shadow_update_enabled) {
674 NEW_ATTR(pattrs, pidx, _PWD_HOMEDIRECTORY,
675 p->data.val_s);
676 } else {
677 NEW_ATTR(sattrs, sidx, _PWD_HOMEDIRECTORY,
678 p->data.val_s);
680 break;
681 case ATTR_SHELL:
682 if (!ldapbuf->shadow_update_enabled) {
683 NEW_ATTR(pattrs, pidx, _PWD_LOGINSHELL,
684 p->data.val_s);
685 } else {
686 NEW_ATTR(sattrs, sidx, _PWD_LOGINSHELL,
687 p->data.val_s);
689 break;
690 /* We don't update NAME, UID, GID */
691 case ATTR_NAME:
692 case ATTR_UID:
693 case ATTR_GID:
694 /* Unsupported item */
695 case ATTR_AGE:
696 break;
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 +
707 sizeof ("{crypt}");
708 pwd = malloc(len);
709 if (pwd == NULL) {
710 return (PWU_NOMEM);
712 (void) strlcpy(pwd, "{crypt}", len);
713 (void) strlcat(pwd, LOCKSTRING, len);
714 (void) strlcat(pwd, spw->sp_pwdp, len);
715 free(spw->sp_pwdp);
716 spw->sp_pwdp = pwd;
717 NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD,
718 spw->sp_pwdp);
720 if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
721 DAY_NOW_32) < 0)
722 return (PWU_NOMEM);
723 spw->sp_lstchg = DAY_NOW_32;
724 break;
726 case ATTR_UNLOCK_ACCOUNT:
727 if (!ldapbuf->shadow_update_enabled)
728 break; /* not managing passwordAccount */
729 if (spw->sp_pwdp &&
730 strncmp(spw->sp_pwdp, LOCKSTRING,
731 sizeof (LOCKSTRING)-1) == 0) {
732 len = (sizeof ("{crypt}") -
733 sizeof (LOCKSTRING)) +
734 strlen(spw->sp_pwdp) + 1;
735 pwd = malloc(len);
736 if (pwd == NULL) {
737 return (PWU_NOMEM);
739 (void) strlcpy(pwd, "{crypt}", len);
740 (void) strlcat(pwd, spw->sp_pwdp +
741 sizeof (LOCKSTRING)-1, len);
742 free(spw->sp_pwdp);
743 spw->sp_pwdp = pwd;
745 NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD,
746 spw->sp_pwdp);
747 if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
748 DAY_NOW_32) < 0)
749 return (PWU_NOMEM);
750 spw->sp_lstchg = DAY_NOW_32;
752 break;
754 case ATTR_NOLOGIN_ACCOUNT:
755 if (!ldapbuf->shadow_update_enabled)
756 break; /* not managing passwordAccount */
757 free(spw->sp_pwdp);
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,
761 DAY_NOW_32) < 0)
762 return (PWU_NOMEM);
763 spw->sp_lstchg = DAY_NOW_32;
764 break;
766 case ATTR_EXPIRE_PASSWORD:
767 if (!ldapbuf->shadow_update_enabled)
768 break; /* not managing passwordAccount */
769 NUM_TO_STR(val, 0);
770 NEW_ATTR(sattrs, sidx, _S_LASTCHANGE, val);
771 break;
773 case ATTR_LSTCHG:
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);
778 break;
780 case ATTR_MIN:
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);
788 aging_set = 1;
789 break;
791 case ATTR_MAX:
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;
797 NUM_TO_STR(val, -1);
798 NEW_ATTR(sattrs, sidx, _S_MIN, val);
799 NUM_TO_STR(val, -1);
800 NEW_ATTR(sattrs, sidx, _S_WARNING, val);
801 } else {
802 /* Turn account aging on */
803 if (spw->sp_min == -1) {
805 * minage was not set with command-
806 * line option: set to zero
808 spw->sp_min = 0;
809 NUM_TO_STR(val, 0);
810 NEW_ATTR(sattrs, sidx, _S_MIN,
811 val);
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,
827 _S_LASTCHANGE,
828 DAY_NOW_32) < 0)
829 return (PWU_NOMEM);
830 spw->sp_lstchg = DAY_NOW_32;
833 NUM_TO_STR(val, p->data.val_i);
834 NEW_ATTR(sattrs, sidx, _S_MAX, val);
835 aging_set = 1;
836 break;
838 case ATTR_WARN:
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);
846 break;
848 case ATTR_INACT:
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);
853 break;
855 case ATTR_EXPIRE:
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);
860 break;
862 case ATTR_FLAG:
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);
867 break;
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);
879 break;
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);
889 break;
890 default:
891 break;
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) {
914 if (disable_aging) {
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)
918 return (PWU_NOMEM);
919 if (attr_addmod(sattrs, &sidx, _S_MAX, -1) < 0)
920 return (PWU_NOMEM);
921 if (attr_addmod(sattrs, &sidx, _S_WARNING,
922 -1) < 0)
923 return (PWU_NOMEM);
924 } else {
925 /* c) */
926 turn_on_default_aging(spw);
928 if (attr_addmod(sattrs, &sidx, _S_MIN,
929 spw->sp_min) < 0)
930 return (PWU_NOMEM);
931 if (attr_addmod(sattrs, &sidx, _S_MAX,
932 spw->sp_max) < 0)
933 return (PWU_NOMEM);
934 if (attr_addmod(sattrs, &sidx,
935 _S_WARNING, spw->sp_warn) < 0)
936 return (PWU_NOMEM);
941 pattrs[pidx] = NULL;
942 sattrs[sidx] = NULL;
944 return (rc);
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)
955 switch (error) {
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:
964 return (PWU_DENIED);
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);
975 default:
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;
987 int ldaprc;
988 int authstried = 0;
989 char **certpath = NULL;
990 ns_auth_t **app;
991 ns_auth_t **authpp = NULL;
992 ns_auth_t *authp = NULL;
993 ns_cred_t *credp;
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)
1005 goto out;
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)
1014 goto out;
1016 if (certpath && *certpath)
1017 credp->hostcertpath = *certpath;
1019 /* Load the service specific authentication method */
1020 ldaprc = __ns_ldap_getServiceAuthMethods("passwd-cmd", &authpp,
1021 &errorp);
1023 if (ldaprc != NS_LDAP_SUCCESS)
1024 goto out;
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,
1032 &errorp);
1033 if (ldaprc != NS_LDAP_SUCCESS)
1034 goto out;
1038 * if authpp is still null, then can not authenticate, syslog
1039 * error message and return error
1041 if (authpp == NULL) {
1042 syslog(LOG_ERR,
1043 "passwdutil: no legal LDAP authentication method configured");
1044 result = NS_LDAP_OP_FAILED;
1045 goto out;
1049 * Walk the array and try all authentication methods in order except
1050 * for "none".
1052 for (app = authpp; *app; app++) {
1053 authp = *app;
1054 /* what about disabling other mechanisms? "tls:sasl/EXTERNAL" */
1055 if (authp->type == NS_LDAP_AUTH_NONE)
1056 continue;
1057 authstried++;
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;
1068 goto out;
1072 * if change not allowed due to configuration, indicate so
1073 * to the caller
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;
1079 goto out;
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))) {
1090 result = ldaprc;
1091 goto out;
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;
1101 result = ldaprc;
1102 goto out;
1103 } else
1104 *pwd_status = NS_PASSWD_GOOD;
1106 /* we don't really care about the error, just clean it up */
1107 if (errorp)
1108 (void) __ns_ldap_freeError(&errorp);
1110 if (authstried == 0) {
1111 syslog(LOG_ERR,
1112 "passwdutil: no legal LDAP authentication method configured");
1113 result = NS_LDAP_CONFIG;
1114 goto out;
1116 result = NS_LDAP_OP_FAILED; /* map to PWU_DENIED */
1118 out:
1119 if (credp)
1120 (void) __ns_ldap_freeCred(&credp);
1122 if (authpp)
1123 (void) __ns_ldap_freeParam((void ***)&authpp);
1125 if (errorp)
1126 (void) __ns_ldap_freeError(&errorp);
1128 return (result);
1133 * ldap_putpwnam(name, oldpw, rep, buf)
1135 * update the LDAP server with the attributes contained in 'buf'.
1137 /*ARGSUSED*/
1139 ldap_putpwnam(char *name, char *oldpw, pwu_repository_t *rep, void *buf)
1141 int res;
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;
1148 struct passwd *pw;
1149 int pwd_status;
1150 uid_t uid;
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)
1161 goto out;
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);
1172 goto out;
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
1182 * be changed.
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
1191 uid = getuid();
1192 if (uid == 0) {
1193 if ((pw = getpwnam_from(name, rep, REP_LDAP)) == NULL) {
1194 res = NS_LDAP_OP_FAILED;
1195 goto out;
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;
1203 goto out;
1206 res = __ns_ldap_uid2dn(pw->pw_name, &binddn, NULL, &errorp);
1207 if (res != NS_LDAP_SUCCESS)
1208 goto out;
1210 if (pattrs && pattrs[0] != NULL) {
1211 res = ldap_replaceattr(dn, pattrs, binddn, oldpw,
1212 &pwd_status, 0);
1213 } else
1214 res = NS_LDAP_OP_FAILED;
1216 out:
1217 free_ldapbuf(ldapbuf);
1218 free(dn);
1220 return (ldap_to_pwu_code(res, pwd_status));