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