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 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 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 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 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 * 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 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 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 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 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 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 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