1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
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.
25 * Copyright 2024 OmniOS Community Edition (OmniOSce) Association.
26 */
27
28 #include <stdio.h>
29 #include <errno.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <macros.h>
34 #include <priv.h>
35
36 #include "ns_sldap.h"
37
38 #include <nss_dbdefs.h>
39 #include <nsswitch.h>
40
41 #include <pwd.h>
42 #include <shadow.h>
43 #include <syslog.h>
44
45 #include "passwdutil.h"
46
47 #include "utils.h"
48
49 #define MAX_INT_LEN 11 /* 10+1 %d buflen for words/ints [not longs] */
50
51 #define STRDUP_OR_RET(to, from) \
52 if ((to = strdup(from)) == NULL) \
53 return (PWU_NOMEM);
54
55 #define STRDUP_OR_ERR(to, from, err) \
56 if (((to) = strdup(from)) == NULL) \
57 (err) = PWU_NOMEM;
58
59 #define NUM_TO_STR(to, from) \
60 { \
61 char nb[MAX_INT_LEN]; \
62 if (snprintf(nb, MAX_INT_LEN, "%d", (from)) >= MAX_INT_LEN) \
63 return (PWU_NOMEM); \
64 STRDUP_OR_RET(to, nb); \
65 }
66
67 #define NEW_ATTR(p, i, attr, val) \
68 { \
69 p[i] = new_attr(attr, (val)); \
70 if (p[i] == NULL) \
71 return (PWU_NOMEM); \
72 i++; \
73 }
74
75 int ldap_getattr(const char *name, attrlist *item, pwu_repository_t *rep);
76 int ldap_getpwnam(const char *name, attrlist *items, pwu_repository_t *rep,
77 void **buf);
78 int ldap_update(attrlist *items, pwu_repository_t *rep, void *buf);
79 int ldap_putpwnam(const char *name, const char *oldpw, pwu_repository_t *rep,
80 void *buf);
81 int ldap_user_to_authenticate(const char *name, pwu_repository_t *rep,
82 char **auth_user, int *privileged);
83
84 /*
85 * ldap function pointer table, used by passwdutil_init to initialize
86 * the global Repository-OPerations table "rops"
87 */
88 struct repops ldap_repops = {
89 NULL, /* checkhistory */
90 ldap_getattr,
91 ldap_getpwnam,
92 ldap_update,
93 ldap_putpwnam,
94 ldap_user_to_authenticate,
95 NULL, /* lock */
96 NULL /* unlock */
97 };
98
99 /*
100 * structure used to keep state between get/update/put calls
101 */
102 typedef struct {
103 char *passwd; /* encrypted password */
104 struct passwd *pwd;
105 ns_ldap_attr_t **pattrs; /* passwd attrs */
106 int npattrs; /* max attrs */
107 struct spwd *spwd;
108 ns_ldap_attr_t **sattrs; /* passwd attrs */
109 int nsattrs; /* max attrs */
110 boolean_t shadow_update_enabled; /* shadow update configured */
111 } ldapbuf_t;
112
113 /*
114 * The following define's are taken from
115 * usr/src/lib/nsswitch/ldap/common/getpwnam.c
116 */
117
118 /* passwd attributes filters */
119 #define _PWD_CN "cn"
120 #define _PWD_UID "uid"
121 #define _PWD_USERPASSWORD "userpassword"
122 #define _PWD_UIDNUMBER "uidnumber"
123 #define _PWD_GIDNUMBER "gidnumber"
124 #define _PWD_GECOS "gecos"
125 #define _PWD_DESCRIPTION "description"
126 #define _PWD_HOMEDIRECTORY "homedirectory"
127 #define _PWD_LOGINSHELL "loginshell"
128
129 #define _PWD_MAX_ATTR 10 /* 9+NULL */
130
131 /* shadow attributes filters */
132 #define _S_LASTCHANGE "shadowlastchange"
133 #define _S_MIN "shadowmin"
134 #define _S_MAX "shadowmax"
135 #define _S_WARNING "shadowwarning"
136 #define _S_INACTIVE "shadowinactive"
137 #define _S_EXPIRE "shadowexpire"
138 #define _S_FLAG "shadowflag"
139
140 #define _S_MAX_ATTR 8 /* 7+NULL */
141
142 /*
143 * Frees up an ldapbuf_t
144 */
145
146 static void
free_ldapbuf(ldapbuf_t * p)147 free_ldapbuf(ldapbuf_t *p)
148 {
149 int i;
150
151 if (p == NULL)
152 return;
153 if (p->passwd) {
154 (void) memset(p->passwd, 0, strlen(p->passwd));
155 free(p->passwd);
156 }
157 if (p->pwd)
158 free_pwd(p->pwd);
159 if (p->spwd)
160 free_spwd(p->spwd);
161 if (p->pattrs) {
162 for (i = 0; i < p->npattrs; i++) {
163 if (p->pattrs[i] != NULL) {
164 free(p->pattrs[i]->attrvalue[0]);
165 free(p->pattrs[i]);
166 }
167 }
168 free(p->pattrs);
169 }
170 if (p->sattrs) {
171 for (i = 0; i < p->nsattrs; i++) {
172 if (p->sattrs[i] != NULL) {
173 free(p->sattrs[i]->attrvalue[0]);
174 free(p->sattrs[i]);
175 }
176 }
177 free(p->sattrs);
178 }
179 }
180
181 /*
182 * int ldap_user_to_authenticate(user, rep, auth_user, privileged)
183 *
184 * If the Shadow Update functionality is enabled, then we check to
185 * see if the caller has 0 as the euid or has all zone privs. If so,
186 * the caller would be able to modify shadow(5) data stored on the
187 * LDAP server. Otherwise, when LDAP Shadow Update is not enabled,
188 * we can't determine whether the user is "privileged" in the LDAP
189 * sense. The operation should be attempted and will succeed if the
190 * user had privileges. For our purposes, we say that the user is
191 * privileged if they are attempting to change another user's
192 * password attributes.
193 */
194 int
ldap_user_to_authenticate(const char * user,pwu_repository_t * rep,char ** auth_user,int * privileged)195 ldap_user_to_authenticate(const char *user, pwu_repository_t *rep,
196 char **auth_user, int *privileged)
197 {
198 struct passwd *pw;
199 uid_t uid;
200 uid_t priviledged_uid;
201 int res = PWU_SUCCESS;
202
203 if (strcmp(user, "root") == 0)
204 return (PWU_NOT_FOUND);
205
206 if ((pw = getpwnam_from(user, rep, REP_LDAP)) == NULL)
207 return (PWU_NOT_FOUND);
208
209 uid = getuid();
210
211 /*
212 * need equivalent of write access to /etc/shadow
213 * the privilege escalation model is euid == 0 || all zone privs
214 */
215 if (__ns_ldap_is_shadow_update_enabled()) {
216 boolean_t priv;
217
218 priv = (geteuid() == 0);
219 if (!priv) {
220 priv_set_t *ps = priv_allocset(); /* caller */
221 priv_set_t *zs; /* zone */
222
223 (void) getppriv(PRIV_EFFECTIVE, ps);
224 zs = priv_str_to_set("zone", ",", NULL);
225 priv = priv_isequalset(ps, zs);
226 priv_freeset(ps);
227 priv_freeset(zs);
228 }
229 /*
230 * priv can change anyone's password,
231 * only root isn't prompted.
232 */
233 *privileged = 0; /* for proper prompting */
234 if (priv) {
235 if (uid == 0) {
236 *privileged = 1;
237 *auth_user = NULL;
238 return (res);
239 } else if (uid == pw->pw_uid) {
240 STRDUP_OR_ERR(*auth_user, user, res);
241 return (res);
242 }
243 }
244
245 return (PWU_DENIED);
246 }
247
248 if (uid == pw->pw_uid) {
249 /* changing our own, not privileged */
250 *privileged = 0;
251 STRDUP_OR_RET(*auth_user, user);
252 } else {
253 char pwd_buf[1024];
254 struct passwd pwr;
255
256 *privileged = 1;
257 /*
258 * specific case for root
259 * we want 'user' to be authenticated.
260 */
261 if (uid == 0) {
262 priviledged_uid = pw->pw_uid;
263 } else {
264 priviledged_uid = uid;
265 }
266 if (getpwuid_r(priviledged_uid, &pwr, pwd_buf,
267 sizeof (pwd_buf)) != NULL) {
268 STRDUP_OR_ERR(*auth_user, pwr.pw_name, res);
269 } else {
270 /* hmm. can't find name of current user...??? */
271
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);
277 }
278 }
279 }
280
281 return (res);
282 }
283
284 /*
285 * int ldap_getattr(name, item, rep)
286 *
287 * retrieve attributes specified in "item" for user "name".
288 */
289 /*ARGSUSED*/
290 int
ldap_getattr(const char * name,attrlist * items,pwu_repository_t * rep)291 ldap_getattr(const char *name, attrlist *items, pwu_repository_t *rep)
292 {
293 attrlist *w;
294 int res;
295 ldapbuf_t *ldapbuf;
296 struct passwd *pw = NULL;
297 struct spwd *spw = NULL;
298
299 res = ldap_getpwnam(name, items, rep, (void **)&ldapbuf);
300 if (res != PWU_SUCCESS)
301 return (res);
302
303 pw = ldapbuf->pwd;
304 spw = ldapbuf->spwd;
305
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;
333
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;
386 }
387 }
388
389 free_ldapbuf(ldapbuf);
390 free(ldapbuf);
391 return (res);
392 }
393
394 /*
395 * int ldap_getpwnam(name, items, rep, buf)
396 *
397 * There is no need to get the old values from the ldap
398 * server, as the update will update each item individually.
399 * Therefore, we only allocate a buffer that will be used by
400 * _update and _putpwnam to hold the attributes to update.
401 *
402 * Only when we're about to update a password, we need to retrieve
403 * the old password since it contains salt-information.
404 */
405 /*ARGSUSED*/
406 int
ldap_getpwnam(const char * name,attrlist * items,pwu_repository_t * rep,void ** buf)407 ldap_getpwnam(const char *name, attrlist *items, pwu_repository_t *rep,
408 void **buf)
409 {
410 ldapbuf_t *ldapbuf;
411 int res = PWU_NOMEM;
412
413 /*
414 * [sp]attrs is treated as NULL terminated
415 */
416
417 ldapbuf = calloc(1, sizeof (ldapbuf_t));
418 if (ldapbuf == NULL)
419 return (PWU_NOMEM);
420
421 ldapbuf->pattrs = calloc(_PWD_MAX_ATTR, sizeof (ns_ldap_attr_t *));
422 if (ldapbuf->pattrs == NULL)
423 goto out;
424 ldapbuf->npattrs = _PWD_MAX_ATTR;
425
426 ldapbuf->sattrs = calloc(_S_MAX_ATTR, sizeof (ns_ldap_attr_t *));
427 if (ldapbuf->sattrs == NULL)
428 goto out;
429 ldapbuf->nsattrs = _S_MAX_ATTR;
430
431 res = dup_pw(&ldapbuf->pwd, getpwnam_from(name, rep, REP_LDAP));
432 if (res != PWU_SUCCESS)
433 goto out;
434
435 res = dup_spw(&ldapbuf->spwd, getspnam_from(name, rep, REP_LDAP));
436 if (res != PWU_SUCCESS)
437 goto out;
438 else {
439 char *spw = ldapbuf->spwd->sp_pwdp;
440 if (spw != NULL && *spw != '\0') {
441 ldapbuf->passwd = strdup(spw);
442 if (ldapbuf->passwd == NULL)
443 goto out;
444 } else
445 ldapbuf->passwd = NULL;
446 }
447
448 /* remember if shadow update is enabled */
449 ldapbuf->shadow_update_enabled = __ns_ldap_is_shadow_update_enabled();
450
451 *buf = (void *)ldapbuf;
452 return (PWU_SUCCESS);
453
454 out:
455 free_ldapbuf(ldapbuf);
456 free(ldapbuf);
457 return (res);
458 }
459
460 /*
461 * new_attr(name, value)
462 *
463 * create a new LDAP attribute to be sent to the server
464 */
465 ns_ldap_attr_t *
new_attr(char * name,char * value)466 new_attr(char *name, char *value)
467 {
468 ns_ldap_attr_t *tmp;
469
470 tmp = malloc(sizeof (*tmp));
471 if (tmp != NULL) {
472 tmp->attrname = name;
473 tmp->attrvalue = (char **)calloc(2, sizeof (char *));
474 if (tmp->attrvalue == NULL) {
475 free(tmp);
476 return (NULL);
477 }
478 tmp->attrvalue[0] = value;
479 tmp->value_count = 1;
480 }
481
482 return (tmp);
483 }
484
485 /*
486 * max_present(list)
487 *
488 * returns '1' if a ATTR_MAX with value != -1 is present. (in other words:
489 * if password aging is to be turned on).
490 */
491 static int
max_present(attrlist * list)492 max_present(attrlist *list)
493 {
494 while (list != NULL)
495 if (list->type == ATTR_MAX && list->data.val_i != -1)
496 return (1);
497 else
498 list = list->next;
499 return (0);
500 }
501
502 /*
503 * attr_addmod(attrs, idx, item, val)
504 *
505 * Adds or updates attribute 'item' in ldap_attrs list to value
506 * update idx if item is added
507 * return: -1 - PWU_NOMEM/error, 0 - success
508 */
509 static int
attr_addmod(ns_ldap_attr_t ** attrs,int * idx,char * item,int value)510 attr_addmod(ns_ldap_attr_t **attrs, int *idx, char *item, int value)
511 {
512 char numbuf[MAX_INT_LEN], *strp;
513 int i;
514
515 /* stringize the value or abort */
516 if (snprintf(numbuf, MAX_INT_LEN, "%d", value) >= MAX_INT_LEN)
517 return (-1);
518
519 /* check for existence and modify existing */
520 for (i = 0; i < *idx; i++) {
521 if (attrs[i] != NULL &&
522 strcmp(item, attrs[i]->attrname) == 0) {
523 strp = strdup(numbuf);
524 if (strp == NULL)
525 return (-1);
526 free(attrs[i]->attrvalue[0]);
527 attrs[i]->attrvalue[0] = strp;
528 return (0);
529 }
530 }
531 /* else add */
532 strp = strdup(numbuf);
533 if (strp == NULL)
534 return (-1);
535 attrs[*idx] = new_attr(item, strp);
536 if (attrs[*idx] == NULL)
537 return (-1);
538 (*idx)++;
539 return (0);
540 }
541
542 /*
543 * ldap_update(items, rep, buf)
544 *
545 * create LDAP attributes in 'buf' for each attribute in 'items'.
546 */
547 /*ARGSUSED*/
548 int
ldap_update(attrlist * items,pwu_repository_t * rep,void * buf)549 ldap_update(attrlist *items, pwu_repository_t *rep, void *buf)
550 {
551 attrlist *p;
552 ldapbuf_t *ldapbuf = (ldapbuf_t *)buf;
553 struct spwd *spw;
554 ns_ldap_attr_t **pattrs = ldapbuf->pattrs;
555 int pidx = 0;
556 ns_ldap_attr_t **sattrs = ldapbuf->sattrs;
557 int sidx = 0;
558 char *pwd, *val;
559 char *salt;
560 size_t cryptlen;
561 int len;
562 int count;
563 int rc = PWU_SUCCESS;
564 int aging_needed = 0;
565 int aging_set = 0;
566 int disable_aging;
567
568 spw = ldapbuf->spwd;
569
570 /*
571 * if sp_max==0 and shadow update is enabled:
572 * disable passwd aging after updating the password
573 */
574 disable_aging = (spw != NULL && spw->sp_max == 0 &&
575 ldapbuf->shadow_update_enabled);
576
577 for (p = items; p != NULL; p = p->next) {
578 switch (p->type) {
579 case ATTR_PASSWD:
580 /*
581 * There is a special case for ldap: if the
582 * password is to be deleted (-d to passwd),
583 * p->data.val_s will be NULL.
584 */
585 if (p->data.val_s == NULL) {
586 if (!ldapbuf->shadow_update_enabled)
587 return (PWU_CHANGE_NOT_ALLOWED);
588 cryptlen =
589 sizeof ("{crypt}" NS_LDAP_NO_UNIX_PASSWORD);
590 val = malloc(cryptlen);
591 if (val == NULL)
592 return (PWU_NOMEM);
593 (void) snprintf(val, cryptlen,
594 "{crypt}" NS_LDAP_NO_UNIX_PASSWORD);
595 } else { /* not deleting password */
596 salt = crypt_gensalt(ldapbuf->passwd,
597 ldapbuf->pwd);
598
599 if (salt == NULL) {
600 if (errno == ENOMEM)
601 return (PWU_NOMEM);
602
603 /* algorithm problem? */
604 syslog(LOG_AUTH | LOG_ALERT,
605 "passwdutil: crypt_gensalt "
606 "%m");
607 return (PWU_UPDATE_FAILED);
608 }
609
610 pwd = crypt(p->data.val_s, salt);
611 free(salt);
612 cryptlen = strlen(pwd) + sizeof ("{crypt}");
613 val = malloc(cryptlen);
614 if (val == NULL)
615 return (PWU_NOMEM);
616 (void) snprintf(val, cryptlen,
617 "{crypt}%s", pwd);
618 }
619
620 /*
621 * If not managing passwordAccount,
622 * insert the new password in the
623 * passwd attr array and break.
624 */
625 if (!ldapbuf->shadow_update_enabled) {
626 NEW_ATTR(pattrs, pidx,
627 _PWD_USERPASSWORD, val);
628 break;
629 }
630
631 /*
632 * Managing passwordAccount, insert the
633 * new password, along with lastChange and
634 * shadowFlag, in the shadow attr array.
635 */
636 NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD, val);
637
638 if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
639 DAY_NOW_32) < 0)
640 return (PWU_NOMEM);
641 spw->sp_lstchg = DAY_NOW_32;
642
643 if (attr_addmod(sattrs, &sidx, _S_FLAG,
644 spw->sp_flag & ~FAILCOUNT_MASK) < 0)
645 return (PWU_NOMEM);
646 spw->sp_flag &= ~FAILCOUNT_MASK; /* reset count */
647 aging_needed = 1;
648 break;
649 case ATTR_PASSWD_SERVER_POLICY:
650 /*
651 * For server policy, don't crypt the password,
652 * send the password as is to the server and
653 * let the LDAP server do its own password
654 * encryption
655 */
656 STRDUP_OR_RET(val, p->data.val_s);
657
658 NEW_ATTR(pattrs, pidx, _PWD_USERPASSWORD, val);
659 break;
660 case ATTR_COMMENT:
661 /* XX correct? */
662 NEW_ATTR(pattrs, pidx, _PWD_DESCRIPTION, p->data.val_s);
663 break;
664 case ATTR_GECOS:
665 if (!ldapbuf->shadow_update_enabled) {
666 NEW_ATTR(pattrs, pidx, _PWD_GECOS,
667 p->data.val_s);
668 } else {
669 NEW_ATTR(sattrs, sidx, _PWD_GECOS,
670 p->data.val_s);
671 }
672 break;
673 case ATTR_HOMEDIR:
674 if (!ldapbuf->shadow_update_enabled) {
675 NEW_ATTR(pattrs, pidx, _PWD_HOMEDIRECTORY,
676 p->data.val_s);
677 } else {
678 NEW_ATTR(sattrs, sidx, _PWD_HOMEDIRECTORY,
679 p->data.val_s);
680 }
681 break;
682 case ATTR_SHELL:
683 if (!ldapbuf->shadow_update_enabled) {
684 NEW_ATTR(pattrs, pidx, _PWD_LOGINSHELL,
685 p->data.val_s);
686 } else {
687 NEW_ATTR(sattrs, sidx, _PWD_LOGINSHELL,
688 p->data.val_s);
689 }
690 break;
691 /* We don't update NAME, UID, GID */
692 case ATTR_NAME:
693 case ATTR_UID:
694 case ATTR_GID:
695 /* Unsupported item */
696 case ATTR_AGE:
697 break;
698 case ATTR_LOCK_ACCOUNT:
699 if (!ldapbuf->shadow_update_enabled)
700 break; /* not managing passwordAccount */
701 if (spw->sp_pwdp == NULL) {
702 spw->sp_pwdp = LOCKSTRING;
703 } else if ((strncmp(spw->sp_pwdp, LOCKSTRING,
704 sizeof (LOCKSTRING)-1) != 0) &&
705 (strcmp(spw->sp_pwdp, NOLOGINSTRING) != 0)) {
706 len = sizeof (LOCKSTRING)-1 +
707 strlen(spw->sp_pwdp) + 1 +
708 sizeof ("{crypt}");
709 pwd = malloc(len);
710 if (pwd == NULL) {
711 return (PWU_NOMEM);
712 }
713 (void) strlcpy(pwd, "{crypt}", len);
714 (void) strlcat(pwd, LOCKSTRING, len);
715 (void) strlcat(pwd, spw->sp_pwdp, len);
716 free(spw->sp_pwdp);
717 spw->sp_pwdp = pwd;
718 NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD,
719 spw->sp_pwdp);
720 }
721 if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
722 DAY_NOW_32) < 0)
723 return (PWU_NOMEM);
724 spw->sp_lstchg = DAY_NOW_32;
725 break;
726
727 case ATTR_UNLOCK_ACCOUNT:
728 if (!ldapbuf->shadow_update_enabled)
729 break; /* not managing passwordAccount */
730 if (spw->sp_pwdp &&
731 strncmp(spw->sp_pwdp, LOCKSTRING,
732 sizeof (LOCKSTRING)-1) == 0) {
733 len = (sizeof ("{crypt}") -
734 sizeof (LOCKSTRING)) +
735 strlen(spw->sp_pwdp) + 1;
736 pwd = malloc(len);
737 if (pwd == NULL) {
738 return (PWU_NOMEM);
739 }
740 (void) strlcpy(pwd, "{crypt}", len);
741 (void) strlcat(pwd, spw->sp_pwdp +
742 sizeof (LOCKSTRING)-1, len);
743 free(spw->sp_pwdp);
744 spw->sp_pwdp = pwd;
745
746 NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD,
747 spw->sp_pwdp);
748 if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
749 DAY_NOW_32) < 0)
750 return (PWU_NOMEM);
751 spw->sp_lstchg = DAY_NOW_32;
752 }
753 break;
754
755 case ATTR_NOLOGIN_ACCOUNT:
756 if (!ldapbuf->shadow_update_enabled)
757 break; /* not managing passwordAccount */
758 free(spw->sp_pwdp);
759 STRDUP_OR_RET(spw->sp_pwdp, "{crypt}" NOLOGINSTRING);
760 NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD, spw->sp_pwdp);
761 if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
762 DAY_NOW_32) < 0)
763 return (PWU_NOMEM);
764 spw->sp_lstchg = DAY_NOW_32;
765 break;
766
767 case ATTR_EXPIRE_PASSWORD:
768 if (!ldapbuf->shadow_update_enabled)
769 break; /* not managing passwordAccount */
770 NUM_TO_STR(val, 0);
771 NEW_ATTR(sattrs, sidx, _S_LASTCHANGE, val);
772 break;
773
774 case ATTR_LSTCHG:
775 if (!ldapbuf->shadow_update_enabled)
776 break; /* not managing passwordAccount */
777 NUM_TO_STR(val, p->data.val_i);
778 NEW_ATTR(sattrs, sidx, _S_LASTCHANGE, val);
779 break;
780
781 case ATTR_MIN:
782 if (!ldapbuf->shadow_update_enabled)
783 break; /* not managing passwordAccount */
784 if (spw->sp_max == -1 && p->data.val_i != -1 &&
785 max_present(p->next) == 0)
786 return (PWU_AGING_DISABLED);
787 NUM_TO_STR(val, p->data.val_i);
788 NEW_ATTR(sattrs, sidx, _S_MIN, val);
789 aging_set = 1;
790 break;
791
792 case ATTR_MAX:
793 if (!ldapbuf->shadow_update_enabled)
794 break; /* not managing passwordAccount */
795 if (p->data.val_i == -1) {
796 /* Turn off aging. Reset min and warn too */
797 spw->sp_max = spw->sp_min = spw->sp_warn = -1;
798 NUM_TO_STR(val, -1);
799 NEW_ATTR(sattrs, sidx, _S_MIN, val);
800 NUM_TO_STR(val, -1);
801 NEW_ATTR(sattrs, sidx, _S_WARNING, val);
802 } else {
803 /* Turn account aging on */
804 if (spw->sp_min == -1) {
805 /*
806 * minage was not set with command-
807 * line option: set to zero
808 */
809 spw->sp_min = 0;
810 NUM_TO_STR(val, 0);
811 NEW_ATTR(sattrs, sidx, _S_MIN,
812 val);
813 }
814 /*
815 * If aging was turned off, we update lstchg.
816 * We take care not to update lstchg if the
817 * user has no password, otherwise the user
818 * might not be required to provide a password
819 * the next time they log in.
820 *
821 * Also, if lstchg != -1 (i.e., not set)
822 * we keep the old value.
823 */
824 if (spw->sp_max == -1 &&
825 spw->sp_pwdp != NULL && *spw->sp_pwdp &&
826 spw->sp_lstchg == -1) {
827 if (attr_addmod(sattrs, &sidx,
828 _S_LASTCHANGE,
829 DAY_NOW_32) < 0)
830 return (PWU_NOMEM);
831 spw->sp_lstchg = DAY_NOW_32;
832 }
833 }
834 NUM_TO_STR(val, p->data.val_i);
835 NEW_ATTR(sattrs, sidx, _S_MAX, val);
836 aging_set = 1;
837 break;
838
839 case ATTR_WARN:
840 if (!ldapbuf->shadow_update_enabled)
841 break; /* not managing passwordAccount */
842 if (spw->sp_max == -1 &&
843 p->data.val_i != -1 && max_present(p->next) == 0)
844 return (PWU_AGING_DISABLED);
845 NUM_TO_STR(val, p->data.val_i);
846 NEW_ATTR(sattrs, sidx, _S_WARNING, val);
847 break;
848
849 case ATTR_INACT:
850 if (!ldapbuf->shadow_update_enabled)
851 break; /* not managing passwordAccount */
852 NUM_TO_STR(val, p->data.val_i);
853 NEW_ATTR(sattrs, sidx, _S_INACTIVE, val);
854 break;
855
856 case ATTR_EXPIRE:
857 if (!ldapbuf->shadow_update_enabled)
858 break; /* not managing passwordAccount */
859 NUM_TO_STR(val, p->data.val_i);
860 NEW_ATTR(sattrs, sidx, _S_EXPIRE, val);
861 break;
862
863 case ATTR_FLAG:
864 if (!ldapbuf->shadow_update_enabled)
865 break; /* not managing passwordAccount */
866 NUM_TO_STR(val, p->data.val_i);
867 NEW_ATTR(sattrs, sidx, _S_FLAG, val);
868 break;
869 case ATTR_INCR_FAILED_LOGINS:
870 if (!ldapbuf->shadow_update_enabled) {
871 rc = PWU_CHANGE_NOT_ALLOWED;
872 break; /* not managing passwordAccount */
873 }
874 count = (spw->sp_flag & FAILCOUNT_MASK) + 1;
875 spw->sp_flag &= ~FAILCOUNT_MASK;
876 spw->sp_flag |= min(FAILCOUNT_MASK, count);
877 p->data.val_i = count;
878 NUM_TO_STR(val, spw->sp_flag);
879 NEW_ATTR(sattrs, sidx, _S_FLAG, val);
880 break;
881 case ATTR_RST_FAILED_LOGINS:
882 if (!ldapbuf->shadow_update_enabled) {
883 rc = PWU_CHANGE_NOT_ALLOWED;
884 break; /* not managing passwordAccount */
885 }
886 p->data.val_i = spw->sp_flag & FAILCOUNT_MASK;
887 spw->sp_flag &= ~FAILCOUNT_MASK;
888 NUM_TO_STR(val, spw->sp_flag);
889 NEW_ATTR(sattrs, sidx, _S_FLAG, val);
890 break;
891 default:
892 break;
893 }
894 }
895
896 /*
897 * If the ldap client is configured with shadow update enabled,
898 * then what should the new aging values look like?
899 *
900 * There are a number of different conditions
901 *
902 * a) aging is already configured: don't touch it
903 *
904 * b) disable_aging is set: disable aging
905 *
906 * c) aging is not configured: turn on default aging;
907 *
908 * b) and c) of course only if aging_needed and !aging_set.
909 * (i.e., password changed, and aging values not changed)
910 */
911
912 if (ldapbuf->shadow_update_enabled && spw != NULL && spw->sp_max <= 0) {
913 /* a) aging not yet configured */
914 if (aging_needed && !aging_set) {
915 if (disable_aging) {
916 /* b) turn off aging */
917 spw->sp_min = spw->sp_max = spw->sp_warn = -1;
918 if (attr_addmod(sattrs, &sidx, _S_MIN, -1) < 0)
919 return (PWU_NOMEM);
920 if (attr_addmod(sattrs, &sidx, _S_MAX, -1) < 0)
921 return (PWU_NOMEM);
922 if (attr_addmod(sattrs, &sidx, _S_WARNING,
923 -1) < 0)
924 return (PWU_NOMEM);
925 } else {
926 /* c) */
927 turn_on_default_aging(spw);
928
929 if (attr_addmod(sattrs, &sidx, _S_MIN,
930 spw->sp_min) < 0)
931 return (PWU_NOMEM);
932 if (attr_addmod(sattrs, &sidx, _S_MAX,
933 spw->sp_max) < 0)
934 return (PWU_NOMEM);
935 if (attr_addmod(sattrs, &sidx,
936 _S_WARNING, spw->sp_warn) < 0)
937 return (PWU_NOMEM);
938 }
939 }
940 }
941
942 pattrs[pidx] = NULL;
943 sattrs[sidx] = NULL;
944
945 return (rc);
946 }
947
948 /*
949 * ldap_to_pwu_code(error, pwd_status)
950 *
951 * translation from LDAP return values and PWU return values
952 */
953 int
ldap_to_pwu_code(int error,int pwd_status)954 ldap_to_pwu_code(int error, int pwd_status)
955 {
956 switch (error) {
957 case NS_LDAP_SUCCESS: return (PWU_SUCCESS);
958 case NS_LDAP_OP_FAILED: return (PWU_DENIED);
959 case NS_LDAP_NOTFOUND: return (PWU_NOT_FOUND);
960 case NS_LDAP_MEMORY: return (PWU_NOMEM);
961 case NS_LDAP_CONFIG: return (PWU_NOT_FOUND);
962 case NS_LDAP_INTERNAL:
963 switch (pwd_status) {
964 case NS_PASSWD_EXPIRED:
965 return (PWU_DENIED);
966 case NS_PASSWD_CHANGE_NOT_ALLOWED:
967 return (PWU_CHANGE_NOT_ALLOWED);
968 case NS_PASSWD_TOO_SHORT:
969 return (PWU_PWD_TOO_SHORT);
970 case NS_PASSWD_INVALID_SYNTAX:
971 return (PWU_PWD_INVALID);
972 case NS_PASSWD_IN_HISTORY:
973 return (PWU_PWD_IN_HISTORY);
974 case NS_PASSWD_WITHIN_MIN_AGE:
975 return (PWU_WITHIN_MIN_AGE);
976 default:
977 return (PWU_SYSTEM_ERROR);
978 }
979 default: return (PWU_SYSTEM_ERROR);
980 }
981 }
982
983 int
ldap_replaceattr(const char * dn,ns_ldap_attr_t ** attrs,const char * binddn,const char * pwd,int * pwd_status,int flags)984 ldap_replaceattr(const char *dn, ns_ldap_attr_t **attrs, const char *binddn,
985 const char *pwd, int *pwd_status, int flags)
986 {
987 int result = NS_LDAP_OP_FAILED;
988 int ldaprc;
989 int authstried = 0;
990 char **certpath = NULL;
991 ns_auth_t **app;
992 ns_auth_t **authpp = NULL;
993 ns_auth_t *authp = NULL;
994 ns_cred_t *credp;
995 ns_ldap_error_t *errorp = NULL;
996
997 debug("%s: replace_ldapattr()", __FILE__);
998
999 if ((credp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t))) == NULL)
1000 return (NS_LDAP_MEMORY); /* map to PWU_NOMEM */
1001
1002 /* for admin shadow update, dn and pwd will be set later in libsldap */
1003 if ((flags & NS_LDAP_UPDATE_SHADOW) == 0) {
1004 /* Fill in the user name and password */
1005 if (dn == NULL || pwd == NULL)
1006 goto out;
1007 credp->cred.unix_cred.userID = strdup(binddn);
1008 credp->cred.unix_cred.passwd = strdup(pwd);
1009 }
1010
1011 /* get host certificate path, if one is configured */
1012 ldaprc = __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P,
1013 (void ***)&certpath, &errorp);
1014 if (ldaprc != NS_LDAP_SUCCESS)
1015 goto out;
1016
1017 if (certpath && *certpath)
1018 credp->hostcertpath = *certpath;
1019
1020 /* Load the service specific authentication method */
1021 ldaprc = __ns_ldap_getServiceAuthMethods("passwd-cmd", &authpp,
1022 &errorp);
1023
1024 if (ldaprc != NS_LDAP_SUCCESS)
1025 goto out;
1026
1027 /*
1028 * if authpp is null, there is no serviceAuthenticationMethod
1029 * try default authenticationMethod
1030 */
1031 if (authpp == NULL) {
1032 ldaprc = __ns_ldap_getParam(NS_LDAP_AUTH_P, (void ***)&authpp,
1033 &errorp);
1034 if (ldaprc != NS_LDAP_SUCCESS)
1035 goto out;
1036 }
1037
1038 /*
1039 * if authpp is still null, then can not authenticate, syslog
1040 * error message and return error
1041 */
1042 if (authpp == NULL) {
1043 syslog(LOG_ERR,
1044 "passwdutil: no legal LDAP authentication method configured");
1045 result = NS_LDAP_OP_FAILED;
1046 goto out;
1047 }
1048
1049 /*
1050 * Walk the array and try all authentication methods in order except
1051 * for "none".
1052 */
1053 for (app = authpp; *app; app++) {
1054 authp = *app;
1055 /* what about disabling other mechanisms? "tls:sasl/EXTERNAL" */
1056 if (authp->type == NS_LDAP_AUTH_NONE)
1057 continue;
1058 authstried++;
1059 credp->auth.type = authp->type;
1060 credp->auth.tlstype = authp->tlstype;
1061 credp->auth.saslmech = authp->saslmech;
1062 credp->auth.saslopt = authp->saslopt;
1063
1064 ldaprc = __ns_ldap_repAttr("shadow", dn,
1065 (const ns_ldap_attr_t * const *)attrs,
1066 credp, flags, &errorp);
1067 if (ldaprc == NS_LDAP_SUCCESS) {
1068 result = NS_LDAP_SUCCESS;
1069 goto out;
1070 }
1071
1072 /*
1073 * if change not allowed due to configuration, indicate so
1074 * to the caller
1075 */
1076 if (ldaprc == NS_LDAP_CONFIG &&
1077 errorp->status == NS_CONFIG_NOTALLOW) {
1078 result = NS_LDAP_CONFIG;
1079 *pwd_status = NS_PASSWD_CHANGE_NOT_ALLOWED;
1080 goto out;
1081 }
1082
1083 /*
1084 * other errors might need to be added to this list, for
1085 * the current supported mechanisms this is sufficient
1086 */
1087 if ((ldaprc == NS_LDAP_INTERNAL) &&
1088 (errorp->pwd_mgmt.status == NS_PASSWD_GOOD) &&
1089 ((errorp->status == LDAP_INAPPROPRIATE_AUTH) ||
1090 (errorp->status == LDAP_INVALID_CREDENTIALS))) {
1091 result = ldaprc;
1092 goto out;
1093 }
1094
1095 /*
1096 * If there is error related to password policy,
1097 * return it to caller
1098 */
1099 if ((ldaprc == NS_LDAP_INTERNAL) &&
1100 errorp->pwd_mgmt.status != NS_PASSWD_GOOD) {
1101 *pwd_status = errorp->pwd_mgmt.status;
1102 result = ldaprc;
1103 goto out;
1104 } else
1105 *pwd_status = NS_PASSWD_GOOD;
1106
1107 /* we don't really care about the error, just clean it up */
1108 if (errorp)
1109 (void) __ns_ldap_freeError(&errorp);
1110 }
1111 if (authstried == 0) {
1112 syslog(LOG_ERR,
1113 "passwdutil: no legal LDAP authentication method configured");
1114 result = NS_LDAP_CONFIG;
1115 goto out;
1116 }
1117 result = NS_LDAP_OP_FAILED; /* map to PWU_DENIED */
1118
1119 out:
1120 if (credp)
1121 (void) __ns_ldap_freeCred(&credp);
1122
1123 if (authpp)
1124 (void) __ns_ldap_freeParam((void ***)&authpp);
1125
1126 if (errorp)
1127 (void) __ns_ldap_freeError(&errorp);
1128
1129 return (result);
1130 }
1131
1132
1133 /*
1134 * ldap_putpwnam(name, oldpw, rep, buf)
1135 *
1136 * update the LDAP server with the attributes contained in 'buf'.
1137 */
1138 /*ARGSUSED*/
1139 int
ldap_putpwnam(const char * name,const char * oldpw,pwu_repository_t * rep,void * buf)1140 ldap_putpwnam(const char *name, const char *oldpw, pwu_repository_t *rep,
1141 void *buf)
1142 {
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;
1153
1154 if (strcmp(name, "root") == 0)
1155 return (PWU_NOT_FOUND);
1156
1157 /*
1158 * convert name of user whose attributes we are changing
1159 * to a distinguished name
1160 */
1161 res = __ns_ldap_uid2dn(name, &dn, NULL, &errorp);
1162 if (res != NS_LDAP_SUCCESS)
1163 goto out;
1164
1165 /* update shadow via ldap_cachemgr if it is enabled */
1166 if (ldapbuf->shadow_update_enabled &&
1167 sattrs != NULL && sattrs[0] != NULL) {
1168 /*
1169 * flag NS_LDAP_UPDATE_SHADOW indicates the shadow update
1170 * should be done via ldap_cachemgr
1171 */
1172 res = ldap_replaceattr(dn, sattrs, NULL, NULL, &pwd_status,
1173 NS_LDAP_UPDATE_SHADOW);
1174 goto out;
1175 }
1176
1177 /*
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.
1188 */
1189
1190 /*
1191 * create a dn for the user who is executing this code
1192 */
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;
1198 }
1199 } else if ((pw = getpwuid_from(uid, rep, REP_LDAP)) == NULL) {
1200 /*
1201 * User executing this code is not known to the LDAP
1202 * server. This operation is to be denied
1203 */
1204 res = NS_LDAP_OP_FAILED;
1205 goto out;
1206 }
1207
1208 res = __ns_ldap_uid2dn(pw->pw_name, &binddn, NULL, &errorp);
1209 if (res != NS_LDAP_SUCCESS)
1210 goto out;
1211
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;
1217
1218 out:
1219 free_ldapbuf(ldapbuf);
1220 free(dn);
1221
1222 return (ldap_to_pwu_code(res, pwd_status));
1223 }
1224