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