dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / passwdutil / ldap_attr.c
blob0340b884202d4706ca9d71017a4a1a99c5bd5e2b
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;
253 struct passwd *pwdp;
255 *privileged = 1;
257 * specific case for root
258 * we want 'user' to be authenticated.
260 if (uid == 0) {
261 priviledged_uid = pw->pw_uid;
262 } else {
263 priviledged_uid = uid;
265 getpwuid_r(priviledged_uid, &pwr, pwd_buf,
266 sizeof (pwd_buf), &pwdp);
267 if (pwdp) {
268 STRDUP_OR_ERR(*auth_user, pwr.pw_name, res);
269 } else {
270 /* hmm. can't find name of current user...??? */
272 if ((*auth_user = malloc(MAX_INT_LEN)) == NULL) {
273 res = PWU_NOMEM;
274 } else {
275 (void) snprintf(*auth_user, MAX_INT_LEN, "%d",
276 (int)uid);
281 return (res);
285 * int ldap_getattr(name, item, rep)
287 * retrieve attributes specified in "item" for user "name".
289 /*ARGSUSED*/
291 ldap_getattr(char *name, attrlist *items, pwu_repository_t *rep)
293 attrlist *w;
294 int res;
295 ldapbuf_t *ldapbuf;
296 struct passwd *pw = NULL;
297 struct spwd *spw = NULL;
299 res = ldap_getpwnam(name, items, rep, (void **)&ldapbuf);
300 if (res != PWU_SUCCESS)
301 return (res);
303 pw = ldapbuf->pwd;
304 spw = ldapbuf->spwd;
306 for (w = items; res == PWU_SUCCESS && w != NULL; w = w->next) {
307 switch (w->type) {
308 case ATTR_NAME:
309 STRDUP_OR_ERR(w->data.val_s, pw->pw_name, res);
310 break;
311 case ATTR_COMMENT:
312 STRDUP_OR_ERR(w->data.val_s, pw->pw_comment, res);
313 break;
314 case ATTR_GECOS:
315 STRDUP_OR_ERR(w->data.val_s, pw->pw_gecos, res);
316 break;
317 case ATTR_HOMEDIR:
318 STRDUP_OR_ERR(w->data.val_s, pw->pw_dir, res);
319 break;
320 case ATTR_SHELL:
321 STRDUP_OR_ERR(w->data.val_s, pw->pw_shell, res);
322 break;
323 case ATTR_PASSWD:
324 case ATTR_PASSWD_SERVER_POLICY:
325 STRDUP_OR_ERR(w->data.val_s, spw->sp_pwdp, res);
326 break;
327 case ATTR_AGE:
328 STRDUP_OR_ERR(w->data.val_s, pw->pw_age, res);
329 break;
330 case ATTR_REP_NAME:
331 STRDUP_OR_ERR(w->data.val_s, "ldap", res);
332 break;
334 /* integer values */
335 case ATTR_UID:
336 w->data.val_i = pw->pw_uid;
337 break;
338 case ATTR_GID:
339 w->data.val_i = pw->pw_gid;
340 break;
341 case ATTR_LSTCHG:
342 if (ldapbuf->shadow_update_enabled)
343 w->data.val_i = spw->sp_lstchg;
344 else
345 w->data.val_i = -1;
346 break;
347 case ATTR_MIN:
348 if (ldapbuf->shadow_update_enabled)
349 w->data.val_i = spw->sp_min;
350 else
351 w->data.val_i = -1;
352 break;
353 case ATTR_MAX:
354 if (ldapbuf->shadow_update_enabled)
355 w->data.val_i = spw->sp_max;
356 else
357 w->data.val_i = -1;
358 break;
359 case ATTR_WARN:
360 if (ldapbuf->shadow_update_enabled)
361 w->data.val_i = spw->sp_warn;
362 else
363 w->data.val_i = -1;
364 break;
365 case ATTR_INACT:
366 if (ldapbuf->shadow_update_enabled)
367 w->data.val_i = spw->sp_inact;
368 else
369 w->data.val_i = -1;
370 break;
371 case ATTR_EXPIRE:
372 if (ldapbuf->shadow_update_enabled)
373 w->data.val_i = spw->sp_expire;
374 else
375 w->data.val_i = -1;
376 break;
377 case ATTR_FLAG:
378 if (ldapbuf->shadow_update_enabled)
379 w->data.val_i = spw->sp_flag;
380 break;
381 case ATTR_FAILED_LOGINS:
382 w->data.val_i = spw->sp_flag & FAILCOUNT_MASK;
383 break;
384 default:
385 break;
389 out:
390 free_ldapbuf(ldapbuf);
391 free(ldapbuf);
392 return (res);
396 * int ldap_getpwnam(name, items, rep, buf)
398 * There is no need to get the old values from the ldap
399 * server, as the update will update each item individually.
400 * Therefore, we only allocate a buffer that will be used by
401 * _update and _putpwnam to hold the attributes to update.
403 * Only when we're about to update a password, we need to retrieve
404 * the old password since it contains salt-information.
406 /*ARGSUSED*/
408 ldap_getpwnam(char *name, attrlist *items, pwu_repository_t *rep,
409 void **buf)
411 ldapbuf_t *ldapbuf;
412 int res = PWU_NOMEM;
415 * [sp]attrs is treated as NULL terminated
418 ldapbuf = calloc(1, sizeof (ldapbuf_t));
419 if (ldapbuf == NULL)
420 return (PWU_NOMEM);
422 ldapbuf->pattrs = calloc(_PWD_MAX_ATTR, sizeof (ns_ldap_attr_t *));
423 if (ldapbuf->pattrs == NULL)
424 goto out;
425 ldapbuf->npattrs = _PWD_MAX_ATTR;
427 ldapbuf->sattrs = calloc(_S_MAX_ATTR, sizeof (ns_ldap_attr_t *));
428 if (ldapbuf->sattrs == NULL)
429 goto out;
430 ldapbuf->nsattrs = _S_MAX_ATTR;
432 res = dup_pw(&ldapbuf->pwd, getpwnam_from(name, rep, REP_LDAP));
433 if (res != PWU_SUCCESS)
434 goto out;
436 res = dup_spw(&ldapbuf->spwd, getspnam_from(name, rep, REP_LDAP));
437 if (res != PWU_SUCCESS)
438 goto out;
439 else {
440 char *spw = ldapbuf->spwd->sp_pwdp;
441 if (spw != NULL && *spw != '\0') {
442 ldapbuf->passwd = strdup(spw);
443 if (ldapbuf->passwd == NULL)
444 goto out;
445 } else
446 ldapbuf->passwd = NULL;
449 /* remember if shadow update is enabled */
450 ldapbuf->shadow_update_enabled = __ns_ldap_is_shadow_update_enabled();
452 *buf = (void *)ldapbuf;
453 return (PWU_SUCCESS);
455 out:
456 free_ldapbuf(ldapbuf);
457 free(ldapbuf);
458 return (res);
462 * new_attr(name, value)
464 * create a new LDAP attribute to be sent to the server
466 ns_ldap_attr_t *
467 new_attr(char *name, char *value)
469 ns_ldap_attr_t *tmp;
471 tmp = malloc(sizeof (*tmp));
472 if (tmp != NULL) {
473 tmp->attrname = name;
474 tmp->attrvalue = (char **)calloc(2, sizeof (char *));
475 if (tmp->attrvalue == NULL) {
476 free(tmp);
477 return (NULL);
479 tmp->attrvalue[0] = value;
480 tmp->value_count = 1;
483 return (tmp);
487 * max_present(list)
489 * returns '1' if a ATTR_MAX with value != -1 is present. (in other words:
490 * if password aging is to be turned on).
492 static int
493 max_present(attrlist *list)
495 while (list != NULL)
496 if (list->type == ATTR_MAX && list->data.val_i != -1)
497 return (1);
498 else
499 list = list->next;
500 return (0);
504 * attr_addmod(attrs, idx, item, val)
506 * Adds or updates attribute 'item' in ldap_attrs list to value
507 * update idx if item is added
508 * return: -1 - PWU_NOMEM/error, 0 - success
510 static int
511 attr_addmod(ns_ldap_attr_t **attrs, int *idx, char *item, int value)
513 char numbuf[MAX_INT_LEN], *strp;
514 int i;
516 /* stringize the value or abort */
517 if (snprintf(numbuf, MAX_INT_LEN, "%d", value) >= MAX_INT_LEN)
518 return (-1);
520 /* check for existence and modify existing */
521 for (i = 0; i < *idx; i++) {
522 if (attrs[i] != NULL &&
523 strcmp(item, attrs[i]->attrname) == 0) {
524 strp = strdup(numbuf);
525 if (strp == NULL)
526 return (-1);
527 free(attrs[i]->attrvalue[0]);
528 attrs[i]->attrvalue[0] = strp;
529 return (0);
532 /* else add */
533 strp = strdup(numbuf);
534 if (strp == NULL)
535 return (-1);
536 attrs[*idx] = new_attr(item, strp);
537 if (attrs[*idx] == NULL)
538 return (-1);
539 (*idx)++;
540 return (0);
544 * ldap_update(items, rep, buf)
546 * create LDAP attributes in 'buf' for each attribute in 'items'.
548 /*ARGSUSED*/
550 ldap_update(attrlist *items, pwu_repository_t *rep, void *buf)
552 attrlist *p;
553 ldapbuf_t *ldapbuf = (ldapbuf_t *)buf;
554 struct spwd *spw;
555 ns_ldap_attr_t **pattrs = ldapbuf->pattrs;
556 int pidx = 0;
557 ns_ldap_attr_t **sattrs = ldapbuf->sattrs;
558 int sidx = 0;
559 char *pwd, *val;
560 char *salt;
561 size_t cryptlen;
562 int len;
563 int count;
564 int rc = PWU_SUCCESS;
565 int aging_needed = 0;
566 int aging_set = 0;
567 int disable_aging;
569 spw = ldapbuf->spwd;
572 * if sp_max==0 and shadow update is enabled:
573 * disable passwd aging after updating the password
575 disable_aging = (spw != NULL && spw->sp_max == 0 &&
576 ldapbuf->shadow_update_enabled);
578 for (p = items; p != NULL; p = p->next) {
579 switch (p->type) {
580 case ATTR_PASSWD:
582 * There is a special case for ldap: if the
583 * password is to be deleted (-d to passwd),
584 * p->data.val_s will be NULL.
586 if (p->data.val_s == NULL) {
587 if (!ldapbuf->shadow_update_enabled)
588 return (PWU_CHANGE_NOT_ALLOWED);
589 cryptlen =
590 sizeof ("{crypt}" NS_LDAP_NO_UNIX_PASSWORD);
591 val = malloc(cryptlen);
592 if (val == NULL)
593 return (PWU_NOMEM);
594 (void) snprintf(val, cryptlen,
595 "{crypt}" NS_LDAP_NO_UNIX_PASSWORD);
596 } else { /* not deleting password */
597 salt = crypt_gensalt(ldapbuf->passwd,
598 ldapbuf->pwd);
600 if (salt == NULL) {
601 if (errno == ENOMEM)
602 return (PWU_NOMEM);
604 /* algorithm problem? */
605 syslog(LOG_AUTH | LOG_ALERT,
606 "passwdutil: crypt_gensalt "
607 "%m");
608 return (PWU_UPDATE_FAILED);
611 pwd = crypt(p->data.val_s, salt);
612 free(salt);
613 cryptlen = strlen(pwd) + sizeof ("{crypt}");
614 val = malloc(cryptlen);
615 if (val == NULL)
616 return (PWU_NOMEM);
617 (void) snprintf(val, cryptlen,
618 "{crypt}%s", pwd);
622 * If not managing passwordAccount,
623 * insert the new password in the
624 * passwd attr array and break.
626 if (!ldapbuf->shadow_update_enabled) {
627 NEW_ATTR(pattrs, pidx,
628 _PWD_USERPASSWORD, val);
629 break;
633 * Managing passwordAccount, insert the
634 * new password, along with lastChange and
635 * shadowFlag, in the shadow attr array.
637 NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD, val);
639 if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
640 DAY_NOW_32) < 0)
641 return (PWU_NOMEM);
642 spw->sp_lstchg = DAY_NOW_32;
644 if (attr_addmod(sattrs, &sidx, _S_FLAG,
645 spw->sp_flag & ~FAILCOUNT_MASK) < 0)
646 return (PWU_NOMEM);
647 spw->sp_flag &= ~FAILCOUNT_MASK; /* reset count */
648 aging_needed = 1;
649 break;
650 case ATTR_PASSWD_SERVER_POLICY:
652 * For server policy, don't crypt the password,
653 * send the password as is to the server and
654 * let the LDAP server do its own password
655 * encryption
657 STRDUP_OR_RET(val, p->data.val_s);
659 NEW_ATTR(pattrs, pidx, _PWD_USERPASSWORD, val);
660 break;
661 case ATTR_COMMENT:
662 /* XX correct? */
663 NEW_ATTR(pattrs, pidx, _PWD_DESCRIPTION, p->data.val_s);
664 break;
665 case ATTR_GECOS:
666 if (!ldapbuf->shadow_update_enabled) {
667 NEW_ATTR(pattrs, pidx, _PWD_GECOS,
668 p->data.val_s);
669 } else {
670 NEW_ATTR(sattrs, sidx, _PWD_GECOS,
671 p->data.val_s);
673 break;
674 case ATTR_HOMEDIR:
675 if (!ldapbuf->shadow_update_enabled) {
676 NEW_ATTR(pattrs, pidx, _PWD_HOMEDIRECTORY,
677 p->data.val_s);
678 } else {
679 NEW_ATTR(sattrs, sidx, _PWD_HOMEDIRECTORY,
680 p->data.val_s);
682 break;
683 case ATTR_SHELL:
684 if (!ldapbuf->shadow_update_enabled) {
685 NEW_ATTR(pattrs, pidx, _PWD_LOGINSHELL,
686 p->data.val_s);
687 } else {
688 NEW_ATTR(sattrs, sidx, _PWD_LOGINSHELL,
689 p->data.val_s);
691 break;
692 /* We don't update NAME, UID, GID */
693 case ATTR_NAME:
694 case ATTR_UID:
695 case ATTR_GID:
696 /* Unsupported item */
697 case ATTR_AGE:
698 break;
699 case ATTR_LOCK_ACCOUNT:
700 if (!ldapbuf->shadow_update_enabled)
701 break; /* not managing passwordAccount */
702 if (spw->sp_pwdp == NULL) {
703 spw->sp_pwdp = LOCKSTRING;
704 } else if ((strncmp(spw->sp_pwdp, LOCKSTRING,
705 sizeof (LOCKSTRING)-1) != 0) &&
706 (strcmp(spw->sp_pwdp, NOLOGINSTRING) != 0)) {
707 len = sizeof (LOCKSTRING)-1 +
708 strlen(spw->sp_pwdp) + 1 +
709 sizeof ("{crypt}");
710 pwd = malloc(len);
711 if (pwd == NULL) {
712 return (PWU_NOMEM);
714 (void) strlcpy(pwd, "{crypt}", len);
715 (void) strlcat(pwd, LOCKSTRING, len);
716 (void) strlcat(pwd, spw->sp_pwdp, len);
717 free(spw->sp_pwdp);
718 spw->sp_pwdp = pwd;
719 NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD,
720 spw->sp_pwdp);
722 if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
723 DAY_NOW_32) < 0)
724 return (PWU_NOMEM);
725 spw->sp_lstchg = DAY_NOW_32;
726 break;
728 case ATTR_UNLOCK_ACCOUNT:
729 if (!ldapbuf->shadow_update_enabled)
730 break; /* not managing passwordAccount */
731 if (spw->sp_pwdp &&
732 strncmp(spw->sp_pwdp, LOCKSTRING,
733 sizeof (LOCKSTRING)-1) == 0) {
734 len = (sizeof ("{crypt}") -
735 sizeof (LOCKSTRING)) +
736 strlen(spw->sp_pwdp) + 1;
737 pwd = malloc(len);
738 if (pwd == NULL) {
739 return (PWU_NOMEM);
741 (void) strlcpy(pwd, "{crypt}", len);
742 (void) strlcat(pwd, spw->sp_pwdp +
743 sizeof (LOCKSTRING)-1, len);
744 free(spw->sp_pwdp);
745 spw->sp_pwdp = pwd;
747 NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD,
748 spw->sp_pwdp);
749 if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
750 DAY_NOW_32) < 0)
751 return (PWU_NOMEM);
752 spw->sp_lstchg = DAY_NOW_32;
754 break;
756 case ATTR_NOLOGIN_ACCOUNT:
757 if (!ldapbuf->shadow_update_enabled)
758 break; /* not managing passwordAccount */
759 free(spw->sp_pwdp);
760 STRDUP_OR_RET(spw->sp_pwdp, "{crypt}" NOLOGINSTRING);
761 NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD, spw->sp_pwdp);
762 if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
763 DAY_NOW_32) < 0)
764 return (PWU_NOMEM);
765 spw->sp_lstchg = DAY_NOW_32;
766 break;
768 case ATTR_EXPIRE_PASSWORD:
769 if (!ldapbuf->shadow_update_enabled)
770 break; /* not managing passwordAccount */
771 NUM_TO_STR(val, 0);
772 NEW_ATTR(sattrs, sidx, _S_LASTCHANGE, val);
773 break;
775 case ATTR_LSTCHG:
776 if (!ldapbuf->shadow_update_enabled)
777 break; /* not managing passwordAccount */
778 NUM_TO_STR(val, p->data.val_i);
779 NEW_ATTR(sattrs, sidx, _S_LASTCHANGE, val);
780 break;
782 case ATTR_MIN:
783 if (!ldapbuf->shadow_update_enabled)
784 break; /* not managing passwordAccount */
785 if (spw->sp_max == -1 && p->data.val_i != -1 &&
786 max_present(p->next) == 0)
787 return (PWU_AGING_DISABLED);
788 NUM_TO_STR(val, p->data.val_i);
789 NEW_ATTR(sattrs, sidx, _S_MIN, val);
790 aging_set = 1;
791 break;
793 case ATTR_MAX:
794 if (!ldapbuf->shadow_update_enabled)
795 break; /* not managing passwordAccount */
796 if (p->data.val_i == -1) {
797 /* Turn off aging. Reset min and warn too */
798 spw->sp_max = spw->sp_min = spw->sp_warn = -1;
799 NUM_TO_STR(val, -1);
800 NEW_ATTR(sattrs, sidx, _S_MIN, val);
801 NUM_TO_STR(val, -1);
802 NEW_ATTR(sattrs, sidx, _S_WARNING, val);
803 } else {
804 /* Turn account aging on */
805 if (spw->sp_min == -1) {
807 * minage was not set with command-
808 * line option: set to zero
810 spw->sp_min = 0;
811 NUM_TO_STR(val, 0);
812 NEW_ATTR(sattrs, sidx, _S_MIN,
813 val);
816 * If aging was turned off, we update lstchg.
817 * We take care not to update lstchg if the
818 * user has no password, otherwise the user
819 * might not be required to provide a password
820 * the next time they log in.
822 * Also, if lstchg != -1 (i.e., not set)
823 * we keep the old value.
825 if (spw->sp_max == -1 &&
826 spw->sp_pwdp != NULL && *spw->sp_pwdp &&
827 spw->sp_lstchg == -1) {
828 if (attr_addmod(sattrs, &sidx,
829 _S_LASTCHANGE,
830 DAY_NOW_32) < 0)
831 return (PWU_NOMEM);
832 spw->sp_lstchg = DAY_NOW_32;
835 NUM_TO_STR(val, p->data.val_i);
836 NEW_ATTR(sattrs, sidx, _S_MAX, val);
837 aging_set = 1;
838 break;
840 case ATTR_WARN:
841 if (!ldapbuf->shadow_update_enabled)
842 break; /* not managing passwordAccount */
843 if (spw->sp_max == -1 &&
844 p->data.val_i != -1 && max_present(p->next) == 0)
845 return (PWU_AGING_DISABLED);
846 NUM_TO_STR(val, p->data.val_i);
847 NEW_ATTR(sattrs, sidx, _S_WARNING, val);
848 break;
850 case ATTR_INACT:
851 if (!ldapbuf->shadow_update_enabled)
852 break; /* not managing passwordAccount */
853 NUM_TO_STR(val, p->data.val_i);
854 NEW_ATTR(sattrs, sidx, _S_INACTIVE, val);
855 break;
857 case ATTR_EXPIRE:
858 if (!ldapbuf->shadow_update_enabled)
859 break; /* not managing passwordAccount */
860 NUM_TO_STR(val, p->data.val_i);
861 NEW_ATTR(sattrs, sidx, _S_EXPIRE, val);
862 break;
864 case ATTR_FLAG:
865 if (!ldapbuf->shadow_update_enabled)
866 break; /* not managing passwordAccount */
867 NUM_TO_STR(val, p->data.val_i);
868 NEW_ATTR(sattrs, sidx, _S_FLAG, val);
869 break;
870 case ATTR_INCR_FAILED_LOGINS:
871 if (!ldapbuf->shadow_update_enabled) {
872 rc = PWU_CHANGE_NOT_ALLOWED;
873 break; /* not managing passwordAccount */
875 count = (spw->sp_flag & FAILCOUNT_MASK) + 1;
876 spw->sp_flag &= ~FAILCOUNT_MASK;
877 spw->sp_flag |= min(FAILCOUNT_MASK, count);
878 p->data.val_i = count;
879 NUM_TO_STR(val, spw->sp_flag);
880 NEW_ATTR(sattrs, sidx, _S_FLAG, val);
881 break;
882 case ATTR_RST_FAILED_LOGINS:
883 if (!ldapbuf->shadow_update_enabled) {
884 rc = PWU_CHANGE_NOT_ALLOWED;
885 break; /* not managing passwordAccount */
887 p->data.val_i = spw->sp_flag & FAILCOUNT_MASK;
888 spw->sp_flag &= ~FAILCOUNT_MASK;
889 NUM_TO_STR(val, spw->sp_flag);
890 NEW_ATTR(sattrs, sidx, _S_FLAG, val);
891 break;
892 default:
893 break;
898 * If the ldap client is configured with shadow update enabled,
899 * then what should the new aging values look like?
901 * There are a number of different conditions
903 * a) aging is already configured: don't touch it
905 * b) disable_aging is set: disable aging
907 * c) aging is not configured: turn on default aging;
909 * b) and c) of course only if aging_needed and !aging_set.
910 * (i.e., password changed, and aging values not changed)
913 if (ldapbuf->shadow_update_enabled && spw != NULL && spw->sp_max <= 0) {
914 /* a) aging not yet configured */
915 if (aging_needed && !aging_set) {
916 if (disable_aging) {
917 /* b) turn off aging */
918 spw->sp_min = spw->sp_max = spw->sp_warn = -1;
919 if (attr_addmod(sattrs, &sidx, _S_MIN, -1) < 0)
920 return (PWU_NOMEM);
921 if (attr_addmod(sattrs, &sidx, _S_MAX, -1) < 0)
922 return (PWU_NOMEM);
923 if (attr_addmod(sattrs, &sidx, _S_WARNING,
924 -1) < 0)
925 return (PWU_NOMEM);
926 } else {
927 /* c) */
928 turn_on_default_aging(spw);
930 if (attr_addmod(sattrs, &sidx, _S_MIN,
931 spw->sp_min) < 0)
932 return (PWU_NOMEM);
933 if (attr_addmod(sattrs, &sidx, _S_MAX,
934 spw->sp_max) < 0)
935 return (PWU_NOMEM);
936 if (attr_addmod(sattrs, &sidx,
937 _S_WARNING, spw->sp_warn) < 0)
938 return (PWU_NOMEM);
943 pattrs[pidx] = NULL;
944 sattrs[sidx] = NULL;
946 return (rc);
950 * ldap_to_pwu_code(error, pwd_status)
952 * translation from LDAP return values and PWU return values
955 ldap_to_pwu_code(int error, int pwd_status)
957 switch (error) {
958 case NS_LDAP_SUCCESS: return (PWU_SUCCESS);
959 case NS_LDAP_OP_FAILED: return (PWU_DENIED);
960 case NS_LDAP_NOTFOUND: return (PWU_NOT_FOUND);
961 case NS_LDAP_MEMORY: return (PWU_NOMEM);
962 case NS_LDAP_CONFIG: return (PWU_NOT_FOUND);
963 case NS_LDAP_INTERNAL:
964 switch (pwd_status) {
965 case NS_PASSWD_EXPIRED:
966 return (PWU_DENIED);
967 case NS_PASSWD_CHANGE_NOT_ALLOWED:
968 return (PWU_CHANGE_NOT_ALLOWED);
969 case NS_PASSWD_TOO_SHORT:
970 return (PWU_PWD_TOO_SHORT);
971 case NS_PASSWD_INVALID_SYNTAX:
972 return (PWU_PWD_INVALID);
973 case NS_PASSWD_IN_HISTORY:
974 return (PWU_PWD_IN_HISTORY);
975 case NS_PASSWD_WITHIN_MIN_AGE:
976 return (PWU_WITHIN_MIN_AGE);
977 default:
978 return (PWU_SYSTEM_ERROR);
980 default: return (PWU_SYSTEM_ERROR);
985 ldap_replaceattr(const char *dn, ns_ldap_attr_t **attrs, const char *binddn,
986 const char *pwd, int *pwd_status, int flags)
988 int result = NS_LDAP_OP_FAILED;
989 int ldaprc;
990 int authstried = 0;
991 char **certpath = NULL;
992 ns_auth_t **app;
993 ns_auth_t **authpp = NULL;
994 ns_auth_t *authp = NULL;
995 ns_cred_t *credp;
996 ns_ldap_error_t *errorp = NULL;
998 debug("%s: replace_ldapattr()", __FILE__);
1000 if ((credp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t))) == NULL)
1001 return (NS_LDAP_MEMORY); /* map to PWU_NOMEM */
1003 /* for admin shadow update, dn and pwd will be set later in libsldap */
1004 if ((flags & NS_LDAP_UPDATE_SHADOW) == 0) {
1005 /* Fill in the user name and password */
1006 if (dn == NULL || pwd == NULL)
1007 goto out;
1008 credp->cred.unix_cred.userID = strdup(binddn);
1009 credp->cred.unix_cred.passwd = strdup(pwd);
1012 /* get host certificate path, if one is configured */
1013 ldaprc = __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P,
1014 (void ***)&certpath, &errorp);
1015 if (ldaprc != NS_LDAP_SUCCESS)
1016 goto out;
1018 if (certpath && *certpath)
1019 credp->hostcertpath = *certpath;
1021 /* Load the service specific authentication method */
1022 ldaprc = __ns_ldap_getServiceAuthMethods("passwd-cmd", &authpp,
1023 &errorp);
1025 if (ldaprc != NS_LDAP_SUCCESS)
1026 goto out;
1029 * if authpp is null, there is no serviceAuthenticationMethod
1030 * try default authenticationMethod
1032 if (authpp == NULL) {
1033 ldaprc = __ns_ldap_getParam(NS_LDAP_AUTH_P, (void ***)&authpp,
1034 &errorp);
1035 if (ldaprc != NS_LDAP_SUCCESS)
1036 goto out;
1040 * if authpp is still null, then can not authenticate, syslog
1041 * error message and return error
1043 if (authpp == NULL) {
1044 syslog(LOG_ERR,
1045 "passwdutil: no legal LDAP authentication method configured");
1046 result = NS_LDAP_OP_FAILED;
1047 goto out;
1051 * Walk the array and try all authentication methods in order except
1052 * for "none".
1054 for (app = authpp; *app; app++) {
1055 authp = *app;
1056 /* what about disabling other mechanisms? "tls:sasl/EXTERNAL" */
1057 if (authp->type == NS_LDAP_AUTH_NONE)
1058 continue;
1059 authstried++;
1060 credp->auth.type = authp->type;
1061 credp->auth.tlstype = authp->tlstype;
1062 credp->auth.saslmech = authp->saslmech;
1063 credp->auth.saslopt = authp->saslopt;
1065 ldaprc = __ns_ldap_repAttr("shadow", dn,
1066 (const ns_ldap_attr_t * const *)attrs,
1067 credp, flags, &errorp);
1068 if (ldaprc == NS_LDAP_SUCCESS) {
1069 result = NS_LDAP_SUCCESS;
1070 goto out;
1074 * if change not allowed due to configuration, indicate so
1075 * to the caller
1077 if (ldaprc == NS_LDAP_CONFIG &&
1078 errorp->status == NS_CONFIG_NOTALLOW) {
1079 result = NS_LDAP_CONFIG;
1080 *pwd_status = NS_PASSWD_CHANGE_NOT_ALLOWED;
1081 goto out;
1085 * other errors might need to be added to this list, for
1086 * the current supported mechanisms this is sufficient
1088 if ((ldaprc == NS_LDAP_INTERNAL) &&
1089 (errorp->pwd_mgmt.status == NS_PASSWD_GOOD) &&
1090 ((errorp->status == LDAP_INAPPROPRIATE_AUTH) ||
1091 (errorp->status == LDAP_INVALID_CREDENTIALS))) {
1092 result = ldaprc;
1093 goto out;
1097 * If there is error related to password policy,
1098 * return it to caller
1100 if ((ldaprc == NS_LDAP_INTERNAL) &&
1101 errorp->pwd_mgmt.status != NS_PASSWD_GOOD) {
1102 *pwd_status = errorp->pwd_mgmt.status;
1103 result = ldaprc;
1104 goto out;
1105 } else
1106 *pwd_status = NS_PASSWD_GOOD;
1108 /* we don't really care about the error, just clean it up */
1109 if (errorp)
1110 (void) __ns_ldap_freeError(&errorp);
1112 if (authstried == 0) {
1113 syslog(LOG_ERR,
1114 "passwdutil: no legal LDAP authentication method configured");
1115 result = NS_LDAP_CONFIG;
1116 goto out;
1118 result = NS_LDAP_OP_FAILED; /* map to PWU_DENIED */
1120 out:
1121 if (credp)
1122 (void) __ns_ldap_freeCred(&credp);
1124 if (authpp)
1125 (void) __ns_ldap_freeParam((void ***)&authpp);
1127 if (errorp)
1128 (void) __ns_ldap_freeError(&errorp);
1130 return (result);
1135 * ldap_putpwnam(name, oldpw, rep, buf)
1137 * update the LDAP server with the attributes contained in 'buf'.
1139 /*ARGSUSED*/
1141 ldap_putpwnam(char *name, char *oldpw, pwu_repository_t *rep, void *buf)
1143 int res;
1144 char *dn; /* dn of user whose attributes we are changing */
1145 char *binddn; /* dn of user who is performing the change */
1146 ns_ldap_error_t *errorp;
1147 ldapbuf_t *ldapbuf = (ldapbuf_t *)buf;
1148 ns_ldap_attr_t **pattrs = ldapbuf->pattrs;
1149 ns_ldap_attr_t **sattrs = ldapbuf->sattrs;
1150 struct passwd *pw;
1151 int pwd_status;
1152 uid_t uid;
1154 if (strcmp(name, "root") == 0)
1155 return (PWU_NOT_FOUND);
1158 * convert name of user whose attributes we are changing
1159 * to a distinguished name
1161 res = __ns_ldap_uid2dn(name, &dn, NULL, &errorp);
1162 if (res != NS_LDAP_SUCCESS)
1163 goto out;
1165 /* update shadow via ldap_cachemgr if it is enabled */
1166 if (ldapbuf->shadow_update_enabled &&
1167 sattrs != NULL && sattrs[0] != NULL) {
1169 * flag NS_LDAP_UPDATE_SHADOW indicates the shadow update
1170 * should be done via ldap_cachemgr
1172 res = ldap_replaceattr(dn, sattrs, NULL, NULL, &pwd_status,
1173 NS_LDAP_UPDATE_SHADOW);
1174 goto out;
1178 * The LDAP server checks whether we are permitted to perform
1179 * the requested change. We need to send the name of the user
1180 * who is executing this piece of code, together with his
1181 * current password to the server.
1182 * If this is executed by a normal user changing his/her own
1183 * password, this will simply be the OLD password that is to
1184 * be changed.
1185 * Specific case if the user who is executing this piece
1186 * of code is root. We will then issue the LDAP request
1187 * with the DN of the user we want to change the passwd of.
1191 * create a dn for the user who is executing this code
1193 uid = getuid();
1194 if (uid == 0) {
1195 if ((pw = getpwnam_from(name, rep, REP_LDAP)) == NULL) {
1196 res = NS_LDAP_OP_FAILED;
1197 goto out;
1199 } else if ((pw = getpwuid_from(uid, rep, REP_LDAP)) == NULL) {
1201 * User executing this code is not known to the LDAP
1202 * server. This operation is to be denied
1204 res = NS_LDAP_OP_FAILED;
1205 goto out;
1208 res = __ns_ldap_uid2dn(pw->pw_name, &binddn, NULL, &errorp);
1209 if (res != NS_LDAP_SUCCESS)
1210 goto out;
1212 if (pattrs && pattrs[0] != NULL) {
1213 res = ldap_replaceattr(dn, pattrs, binddn, oldpw,
1214 &pwd_status, 0);
1215 } else
1216 res = NS_LDAP_OP_FAILED;
1218 out:
1219 free_ldapbuf(ldapbuf);
1220 free(dn);
1222 return (ldap_to_pwu_code(res, pwd_status));