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