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 out:
390 free_ldapbuf(ldapbuf);
391 free(ldapbuf);
392 return (res);
393 }
394
395 /*
396 * int ldap_getpwnam(name, items, rep, buf)
397 *
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.
402 *
403 * Only when we're about to update a password, we need to retrieve
404 * the old password since it contains salt-information.
405 */
406 /*ARGSUSED*/
407 int
ldap_getpwnam(const char * name,attrlist * items,pwu_repository_t * rep,void ** buf)408 ldap_getpwnam(const char *name, attrlist *items, pwu_repository_t *rep,
409 void **buf)
410 {
411 ldapbuf_t *ldapbuf;
412 int res = PWU_NOMEM;
413
414 /*
415 * [sp]attrs is treated as NULL terminated
416 */
417
418 ldapbuf = calloc(1, sizeof (ldapbuf_t));
419 if (ldapbuf == NULL)
420 return (PWU_NOMEM);
421
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;
426
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;
431
432 res = dup_pw(&ldapbuf->pwd, getpwnam_from(name, rep, REP_LDAP));
433 if (res != PWU_SUCCESS)
434 goto out;
435
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;
447 }
448
449 /* remember if shadow update is enabled */
450 ldapbuf->shadow_update_enabled = __ns_ldap_is_shadow_update_enabled();
451
452 *buf = (void *)ldapbuf;
453 return (PWU_SUCCESS);
454
455 out:
456 free_ldapbuf(ldapbuf);
457 free(ldapbuf);
458 return (res);
459 }
460
461 /*
462 * new_attr(name, value)
463 *
464 * create a new LDAP attribute to be sent to the server
465 */
466 ns_ldap_attr_t *
new_attr(char * name,char * value)467 new_attr(char *name, char *value)
468 {
469 ns_ldap_attr_t *tmp;
470
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);
478 }
479 tmp->attrvalue[0] = value;
480 tmp->value_count = 1;
481 }
482
483 return (tmp);
484 }
485
486 /*
487 * max_present(list)
488 *
489 * returns '1' if a ATTR_MAX with value != -1 is present. (in other words:
490 * if password aging is to be turned on).
491 */
492 static int
max_present(attrlist * list)493 max_present(attrlist *list)
494 {
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);
501 }
502
503 /*
504 * attr_addmod(attrs, idx, item, val)
505 *
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
509 */
510 static int
attr_addmod(ns_ldap_attr_t ** attrs,int * idx,char * item,int value)511 attr_addmod(ns_ldap_attr_t **attrs, int *idx, char *item, int value)
512 {
513 char numbuf[MAX_INT_LEN], *strp;
514 int i;
515
516 /* stringize the value or abort */
517 if (snprintf(numbuf, MAX_INT_LEN, "%d", value) >= MAX_INT_LEN)
518 return (-1);
519
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);
530 }
531 }
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);
541 }
542
543 /*
544 * ldap_update(items, rep, buf)
545 *
546 * create LDAP attributes in 'buf' for each attribute in 'items'.
547 */
548 /*ARGSUSED*/
549 int
ldap_update(attrlist * items,pwu_repository_t * rep,void * buf)550 ldap_update(attrlist *items, pwu_repository_t *rep, void *buf)
551 {
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;
568
569 spw = ldapbuf->spwd;
570
571 /*
572 * if sp_max==0 and shadow update is enabled:
573 * disable passwd aging after updating the password
574 */
575 disable_aging = (spw != NULL && spw->sp_max == 0 &&
576 ldapbuf->shadow_update_enabled);
577
578 for (p = items; p != NULL; p = p->next) {
579 switch (p->type) {
580 case ATTR_PASSWD:
581 /*
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.
585 */
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);
599
600 if (salt == NULL) {
601 if (errno == ENOMEM)
602 return (PWU_NOMEM);
603
604 /* algorithm problem? */
605 syslog(LOG_AUTH | LOG_ALERT,
606 "passwdutil: crypt_gensalt "
607 "%m");
608 return (PWU_UPDATE_FAILED);
609 }
610
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);
619 }
620
621 /*
622 * If not managing passwordAccount,
623 * insert the new password in the
624 * passwd attr array and break.
625 */
626 if (!ldapbuf->shadow_update_enabled) {
627 NEW_ATTR(pattrs, pidx,
628 _PWD_USERPASSWORD, val);
629 break;
630 }
631
632 /*
633 * Managing passwordAccount, insert the
634 * new password, along with lastChange and
635 * shadowFlag, in the shadow attr array.
636 */
637 NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD, val);
638
639 if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
640 DAY_NOW_32) < 0)
641 return (PWU_NOMEM);
642 spw->sp_lstchg = DAY_NOW_32;
643
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:
651 /*
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
656 */
657 STRDUP_OR_RET(val, p->data.val_s);
658
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);
672 }
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);
681 }
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);
690 }
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);
713 }
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);
721 }
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;
727
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);
740 }
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;
746
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;
753 }
754 break;
755
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;
767
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;
774
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;
781
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;
792
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) {
806 /*
807 * minage was not set with command-
808 * line option: set to zero
809 */
810 spw->sp_min = 0;
811 NUM_TO_STR(val, 0);
812 NEW_ATTR(sattrs, sidx, _S_MIN,
813 val);
814 }
815 /*
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.
821 *
822 * Also, if lstchg != -1 (i.e., not set)
823 * we keep the old value.
824 */
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;
833 }
834 }
835 NUM_TO_STR(val, p->data.val_i);
836 NEW_ATTR(sattrs, sidx, _S_MAX, val);
837 aging_set = 1;
838 break;
839
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;
849
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;
856
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;
863
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 */
874 }
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 */
886 }
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;
894 }
895 }
896
897 /*
898 * If the ldap client is configured with shadow update enabled,
899 * then what should the new aging values look like?
900 *
901 * There are a number of different conditions
902 *
903 * a) aging is already configured: don't touch it
904 *
905 * b) disable_aging is set: disable aging
906 *
907 * c) aging is not configured: turn on default aging;
908 *
909 * b) and c) of course only if aging_needed and !aging_set.
910 * (i.e., password changed, and aging values not changed)
911 */
912
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);
929
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);
939 }
940 }
941 }
942
943 pattrs[pidx] = NULL;
944 sattrs[sidx] = NULL;
945
946 return (rc);
947 }
948
949 /*
950 * ldap_to_pwu_code(error, pwd_status)
951 *
952 * translation from LDAP return values and PWU return values
953 */
954 int
ldap_to_pwu_code(int error,int pwd_status)955 ldap_to_pwu_code(int error, int pwd_status)
956 {
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);
979 }
980 default: return (PWU_SYSTEM_ERROR);
981 }
982 }
983
984 int
ldap_replaceattr(const char * dn,ns_ldap_attr_t ** attrs,const char * binddn,const char * pwd,int * pwd_status,int flags)985 ldap_replaceattr(const char *dn, ns_ldap_attr_t **attrs, const char *binddn,
986 const char *pwd, int *pwd_status, int flags)
987 {
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;
997
998 debug("%s: replace_ldapattr()", __FILE__);
999
1000 if ((credp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t))) == NULL)
1001 return (NS_LDAP_MEMORY); /* map to PWU_NOMEM */
1002
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);
1010 }
1011
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;
1017
1018 if (certpath && *certpath)
1019 credp->hostcertpath = *certpath;
1020
1021 /* Load the service specific authentication method */
1022 ldaprc = __ns_ldap_getServiceAuthMethods("passwd-cmd", &authpp,
1023 &errorp);
1024
1025 if (ldaprc != NS_LDAP_SUCCESS)
1026 goto out;
1027
1028 /*
1029 * if authpp is null, there is no serviceAuthenticationMethod
1030 * try default authenticationMethod
1031 */
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;
1037 }
1038
1039 /*
1040 * if authpp is still null, then can not authenticate, syslog
1041 * error message and return error
1042 */
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;
1048 }
1049
1050 /*
1051 * Walk the array and try all authentication methods in order except
1052 * for "none".
1053 */
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;
1064
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;
1071 }
1072
1073 /*
1074 * if change not allowed due to configuration, indicate so
1075 * to the caller
1076 */
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;
1082 }
1083
1084 /*
1085 * other errors might need to be added to this list, for
1086 * the current supported mechanisms this is sufficient
1087 */
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;
1094 }
1095
1096 /*
1097 * If there is error related to password policy,
1098 * return it to caller
1099 */
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;
1107
1108 /* we don't really care about the error, just clean it up */
1109 if (errorp)
1110 (void) __ns_ldap_freeError(&errorp);
1111 }
1112 if (authstried == 0) {
1113 syslog(LOG_ERR,
1114 "passwdutil: no legal LDAP authentication method configured");
1115 result = NS_LDAP_CONFIG;
1116 goto out;
1117 }
1118 result = NS_LDAP_OP_FAILED; /* map to PWU_DENIED */
1119
1120 out:
1121 if (credp)
1122 (void) __ns_ldap_freeCred(&credp);
1123
1124 if (authpp)
1125 (void) __ns_ldap_freeParam((void ***)&authpp);
1126
1127 if (errorp)
1128 (void) __ns_ldap_freeError(&errorp);
1129
1130 return (result);
1131 }
1132
1133
1134 /*
1135 * ldap_putpwnam(name, oldpw, rep, buf)
1136 *
1137 * update the LDAP server with the attributes contained in 'buf'.
1138 */
1139 /*ARGSUSED*/
1140 int
ldap_putpwnam(const char * name,const char * oldpw,pwu_repository_t * rep,void * buf)1141 ldap_putpwnam(const char *name, const char *oldpw, pwu_repository_t *rep,
1142 void *buf)
1143 {
1144 int res;
1145 char *dn; /* dn of user whose attributes we are changing */
1146 char *binddn; /* dn of user who is performing the change */
1147 ns_ldap_error_t *errorp;
1148 ldapbuf_t *ldapbuf = (ldapbuf_t *)buf;
1149 ns_ldap_attr_t **pattrs = ldapbuf->pattrs;
1150 ns_ldap_attr_t **sattrs = ldapbuf->sattrs;
1151 struct passwd *pw;
1152 int pwd_status;
1153 uid_t uid;
1154
1155 if (strcmp(name, "root") == 0)
1156 return (PWU_NOT_FOUND);
1157
1158 /*
1159 * convert name of user whose attributes we are changing
1160 * to a distinguished name
1161 */
1162 res = __ns_ldap_uid2dn(name, &dn, NULL, &errorp);
1163 if (res != NS_LDAP_SUCCESS)
1164 goto out;
1165
1166 /* update shadow via ldap_cachemgr if it is enabled */
1167 if (ldapbuf->shadow_update_enabled &&
1168 sattrs != NULL && sattrs[0] != NULL) {
1169 /*
1170 * flag NS_LDAP_UPDATE_SHADOW indicates the shadow update
1171 * should be done via ldap_cachemgr
1172 */
1173 res = ldap_replaceattr(dn, sattrs, NULL, NULL, &pwd_status,
1174 NS_LDAP_UPDATE_SHADOW);
1175 goto out;
1176 }
1177
1178 /*
1179 * The LDAP server checks whether we are permitted to perform
1180 * the requested change. We need to send the name of the user
1181 * who is executing this piece of code, together with his
1182 * current password to the server.
1183 * If this is executed by a normal user changing his/her own
1184 * password, this will simply be the OLD password that is to
1185 * be changed.
1186 * Specific case if the user who is executing this piece
1187 * of code is root. We will then issue the LDAP request
1188 * with the DN of the user we want to change the passwd of.
1189 */
1190
1191 /*
1192 * create a dn for the user who is executing this code
1193 */
1194 uid = getuid();
1195 if (uid == 0) {
1196 if ((pw = getpwnam_from(name, rep, REP_LDAP)) == NULL) {
1197 res = NS_LDAP_OP_FAILED;
1198 goto out;
1199 }
1200 } else if ((pw = getpwuid_from(uid, rep, REP_LDAP)) == NULL) {
1201 /*
1202 * User executing this code is not known to the LDAP
1203 * server. This operation is to be denied
1204 */
1205 res = NS_LDAP_OP_FAILED;
1206 goto out;
1207 }
1208
1209 res = __ns_ldap_uid2dn(pw->pw_name, &binddn, NULL, &errorp);
1210 if (res != NS_LDAP_SUCCESS)
1211 goto out;
1212
1213 if (pattrs && pattrs[0] != NULL) {
1214 res = ldap_replaceattr(dn, pattrs, binddn, oldpw,
1215 &pwd_status, 0);
1216 } else
1217 res = NS_LDAP_OP_FAILED;
1218
1219 out:
1220 free_ldapbuf(ldapbuf);
1221 free(dn);
1222
1223 return (ldap_to_pwu_code(res, pwd_status));
1224 }
1225