1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stdio.h> 27 #include <errno.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <unistd.h> 31 #include <macros.h> 32 #include <priv.h> 33 34 #include "ns_sldap.h" 35 36 #include <nss_dbdefs.h> 37 #include <nsswitch.h> 38 39 #include <pwd.h> 40 #include <shadow.h> 41 #include <syslog.h> 42 43 #include "passwdutil.h" 44 45 #include "utils.h" 46 47 #define MAX_INT_LEN 11 /* 10+1 %d buflen for words/ints [not longs] */ 48 49 #define STRDUP_OR_RET(to, from) \ 50 if ((to = strdup(from)) == NULL) \ 51 return (PWU_NOMEM); 52 53 #define STRDUP_OR_ERR(to, from, err) \ 54 if (((to) = strdup(from)) == NULL) \ 55 (err) = PWU_NOMEM; 56 57 #define NUM_TO_STR(to, from) \ 58 { \ 59 char nb[MAX_INT_LEN]; \ 60 if (snprintf(nb, MAX_INT_LEN, "%d", (from)) >= MAX_INT_LEN) \ 61 return (PWU_NOMEM); \ 62 STRDUP_OR_RET(to, nb); \ 63 } 64 65 #define NEW_ATTR(p, i, attr, val) \ 66 { \ 67 p[i] = new_attr(attr, (val)); \ 68 if (p[i] == NULL) \ 69 return (PWU_NOMEM); \ 70 i++; \ 71 } 72 73 int ldap_getattr(char *name, attrlist *item, pwu_repository_t *rep); 74 int ldap_getpwnam(char *name, attrlist *items, pwu_repository_t *rep, 75 void **buf); 76 int ldap_update(attrlist *items, pwu_repository_t *rep, void *buf); 77 int ldap_putpwnam(char *name, char *oldpw, char *dummy, 78 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 he/she is 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 len = sizeof (LOCKSTRING)-1 + 705 strlen(spw->sp_pwdp) + 1 + 706 sizeof ("{crypt}"); 707 pwd = malloc(len); 708 if (pwd == NULL) { 709 return (PWU_NOMEM); 710 } 711 (void) strlcpy(pwd, "{crypt}", len); 712 (void) strlcat(pwd, LOCKSTRING, len); 713 (void) strlcat(pwd, spw->sp_pwdp, len); 714 free(spw->sp_pwdp); 715 spw->sp_pwdp = pwd; 716 NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD, 717 spw->sp_pwdp); 718 } 719 if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE, 720 DAY_NOW_32) < 0) 721 return (PWU_NOMEM); 722 spw->sp_lstchg = DAY_NOW_32; 723 break; 724 725 case ATTR_UNLOCK_ACCOUNT: 726 if (!ldapbuf->shadow_update_enabled) 727 break; /* not managing passwordAccount */ 728 if (spw->sp_pwdp && 729 strncmp(spw->sp_pwdp, LOCKSTRING, 730 sizeof (LOCKSTRING)-1) == 0) { 731 len = (sizeof ("{crypt}") - 732 sizeof (LOCKSTRING)) + 733 strlen(spw->sp_pwdp) + 1; 734 pwd = malloc(len); 735 if (pwd == NULL) { 736 return (PWU_NOMEM); 737 } 738 (void) strlcpy(pwd, "{crypt}", len); 739 (void) strlcat(pwd, spw->sp_pwdp + 740 sizeof (LOCKSTRING)-1, len); 741 free(spw->sp_pwdp); 742 spw->sp_pwdp = pwd; 743 744 NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD, 745 spw->sp_pwdp); 746 if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE, 747 DAY_NOW_32) < 0) 748 return (PWU_NOMEM); 749 spw->sp_lstchg = DAY_NOW_32; 750 } 751 break; 752 753 case ATTR_NOLOGIN_ACCOUNT: 754 if (!ldapbuf->shadow_update_enabled) 755 break; /* not managing passwordAccount */ 756 free(spw->sp_pwdp); 757 STRDUP_OR_RET(spw->sp_pwdp, "{crypt}" NOLOGINSTRING); 758 NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD, spw->sp_pwdp); 759 if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE, 760 DAY_NOW_32) < 0) 761 return (PWU_NOMEM); 762 spw->sp_lstchg = DAY_NOW_32; 763 break; 764 765 case ATTR_EXPIRE_PASSWORD: 766 if (!ldapbuf->shadow_update_enabled) 767 break; /* not managing passwordAccount */ 768 NUM_TO_STR(val, 0); 769 NEW_ATTR(sattrs, sidx, _S_LASTCHANGE, val); 770 break; 771 772 case ATTR_LSTCHG: 773 if (!ldapbuf->shadow_update_enabled) 774 break; /* not managing passwordAccount */ 775 NUM_TO_STR(val, p->data.val_i); 776 NEW_ATTR(sattrs, sidx, _S_LASTCHANGE, val); 777 break; 778 779 case ATTR_MIN: 780 if (!ldapbuf->shadow_update_enabled) 781 break; /* not managing passwordAccount */ 782 if (spw->sp_max == -1 && p->data.val_i != -1 && 783 max_present(p->next) == 0) 784 return (PWU_AGING_DISABLED); 785 NUM_TO_STR(val, p->data.val_i); 786 NEW_ATTR(sattrs, sidx, _S_MIN, val); 787 aging_set = 1; 788 break; 789 790 case ATTR_MAX: 791 if (!ldapbuf->shadow_update_enabled) 792 break; /* not managing passwordAccount */ 793 if (p->data.val_i == -1) { 794 /* Turn off aging. Reset min and warn too */ 795 spw->sp_max = spw->sp_min = spw->sp_warn = -1; 796 NUM_TO_STR(val, -1); 797 NEW_ATTR(sattrs, sidx, _S_MIN, val); 798 NUM_TO_STR(val, -1); 799 NEW_ATTR(sattrs, sidx, _S_WARNING, val); 800 } else { 801 /* Turn account aging on */ 802 if (spw->sp_min == -1) { 803 /* 804 * minage was not set with command- 805 * line option: set to zero 806 */ 807 spw->sp_min = 0; 808 NUM_TO_STR(val, 0); 809 NEW_ATTR(sattrs, sidx, _S_MIN, 810 val); 811 } 812 /* 813 * If aging was turned off, we update lstchg. 814 * We take care not to update lstchg if the 815 * user has no password, otherwise the user 816 * might not be required to provide a password 817 * the next time [s]he logs in. 818 * 819 * Also, if lstchg != -1 (i.e., not set) 820 * we keep the old value. 821 */ 822 if (spw->sp_max == -1 && 823 spw->sp_pwdp != NULL && *spw->sp_pwdp && 824 spw->sp_lstchg == -1) { 825 if (attr_addmod(sattrs, &sidx, 826 _S_LASTCHANGE, 827 DAY_NOW_32) < 0) 828 return (PWU_NOMEM); 829 spw->sp_lstchg = DAY_NOW_32; 830 } 831 } 832 NUM_TO_STR(val, p->data.val_i); 833 NEW_ATTR(sattrs, sidx, _S_MAX, val); 834 aging_set = 1; 835 break; 836 837 case ATTR_WARN: 838 if (!ldapbuf->shadow_update_enabled) 839 break; /* not managing passwordAccount */ 840 if (spw->sp_max == -1 && 841 p->data.val_i != -1 && max_present(p->next) == 0) 842 return (PWU_AGING_DISABLED); 843 NUM_TO_STR(val, p->data.val_i); 844 NEW_ATTR(sattrs, sidx, _S_WARNING, val); 845 break; 846 847 case ATTR_INACT: 848 if (!ldapbuf->shadow_update_enabled) 849 break; /* not managing passwordAccount */ 850 NUM_TO_STR(val, p->data.val_i); 851 NEW_ATTR(sattrs, sidx, _S_INACTIVE, val); 852 break; 853 854 case ATTR_EXPIRE: 855 if (!ldapbuf->shadow_update_enabled) 856 break; /* not managing passwordAccount */ 857 NUM_TO_STR(val, p->data.val_i); 858 NEW_ATTR(sattrs, sidx, _S_EXPIRE, val); 859 break; 860 861 case ATTR_FLAG: 862 if (!ldapbuf->shadow_update_enabled) 863 break; /* not managing passwordAccount */ 864 NUM_TO_STR(val, p->data.val_i); 865 NEW_ATTR(sattrs, sidx, _S_FLAG, val); 866 break; 867 case ATTR_INCR_FAILED_LOGINS: 868 if (!ldapbuf->shadow_update_enabled) { 869 rc = PWU_CHANGE_NOT_ALLOWED; 870 break; /* not managing passwordAccount */ 871 } 872 count = (spw->sp_flag & FAILCOUNT_MASK) + 1; 873 spw->sp_flag &= ~FAILCOUNT_MASK; 874 spw->sp_flag |= min(FAILCOUNT_MASK, count); 875 p->data.val_i = count; 876 NUM_TO_STR(val, spw->sp_flag); 877 NEW_ATTR(sattrs, sidx, _S_FLAG, val); 878 break; 879 case ATTR_RST_FAILED_LOGINS: 880 if (!ldapbuf->shadow_update_enabled) { 881 rc = PWU_CHANGE_NOT_ALLOWED; 882 break; /* not managing passwordAccount */ 883 } 884 p->data.val_i = spw->sp_flag & FAILCOUNT_MASK; 885 spw->sp_flag &= ~FAILCOUNT_MASK; 886 NUM_TO_STR(val, spw->sp_flag); 887 NEW_ATTR(sattrs, sidx, _S_FLAG, val); 888 break; 889 default: 890 break; 891 } 892 } 893 894 /* 895 * If the ldap client is configured with shadow update enabled, 896 * then what should the new aging values look like? 897 * 898 * There are a number of different conditions 899 * 900 * a) aging is already configured: don't touch it 901 * 902 * b) disable_aging is set: disable aging 903 * 904 * c) aging is not configured: turn on default aging; 905 * 906 * b) and c) of course only if aging_needed and !aging_set. 907 * (i.e., password changed, and aging values not changed) 908 */ 909 910 if (ldapbuf->shadow_update_enabled && spw != NULL && spw->sp_max <= 0) { 911 /* a) aging not yet configured */ 912 if (aging_needed && !aging_set) { 913 if (disable_aging) { 914 /* b) turn off aging */ 915 spw->sp_min = spw->sp_max = spw->sp_warn = -1; 916 if (attr_addmod(sattrs, &sidx, _S_MIN, -1) < 0) 917 return (PWU_NOMEM); 918 if (attr_addmod(sattrs, &sidx, _S_MAX, -1) < 0) 919 return (PWU_NOMEM); 920 if (attr_addmod(sattrs, &sidx, _S_WARNING, 921 -1) < 0) 922 return (PWU_NOMEM); 923 } else { 924 /* c) */ 925 turn_on_default_aging(spw); 926 927 if (attr_addmod(sattrs, &sidx, _S_MIN, 928 spw->sp_min) < 0) 929 return (PWU_NOMEM); 930 if (attr_addmod(sattrs, &sidx, _S_MAX, 931 spw->sp_max) < 0) 932 return (PWU_NOMEM); 933 if (attr_addmod(sattrs, &sidx, 934 _S_WARNING, spw->sp_warn) < 0) 935 return (PWU_NOMEM); 936 } 937 } 938 } 939 940 pattrs[pidx] = NULL; 941 sattrs[sidx] = NULL; 942 943 return (rc); 944 } 945 946 /* 947 * ldap_to_pwu_code(error, pwd_status) 948 * 949 * translation from LDAP return values and PWU return values 950 */ 951 int 952 ldap_to_pwu_code(int error, int pwd_status) 953 { 954 switch (error) { 955 case NS_LDAP_SUCCESS: return (PWU_SUCCESS); 956 case NS_LDAP_OP_FAILED: return (PWU_DENIED); 957 case NS_LDAP_NOTFOUND: return (PWU_NOT_FOUND); 958 case NS_LDAP_MEMORY: return (PWU_NOMEM); 959 case NS_LDAP_CONFIG: return (PWU_NOT_FOUND); 960 case NS_LDAP_INTERNAL: 961 switch (pwd_status) { 962 case NS_PASSWD_EXPIRED: 963 return (PWU_DENIED); 964 case NS_PASSWD_CHANGE_NOT_ALLOWED: 965 return (PWU_CHANGE_NOT_ALLOWED); 966 case NS_PASSWD_TOO_SHORT: 967 return (PWU_PWD_TOO_SHORT); 968 case NS_PASSWD_INVALID_SYNTAX: 969 return (PWU_PWD_INVALID); 970 case NS_PASSWD_IN_HISTORY: 971 return (PWU_PWD_IN_HISTORY); 972 case NS_PASSWD_WITHIN_MIN_AGE: 973 return (PWU_WITHIN_MIN_AGE); 974 default: 975 return (PWU_SYSTEM_ERROR); 976 } 977 default: return (PWU_SYSTEM_ERROR); 978 } 979 } 980 981 int 982 ldap_replaceattr(const char *dn, ns_ldap_attr_t **attrs, const char *binddn, 983 const char *pwd, int *pwd_status, int flags) 984 { 985 int result = NS_LDAP_OP_FAILED; 986 int ldaprc; 987 int authstried = 0; 988 char **certpath = NULL; 989 ns_auth_t **app; 990 ns_auth_t **authpp = NULL; 991 ns_auth_t *authp = NULL; 992 ns_cred_t *credp; 993 ns_ldap_error_t *errorp = NULL; 994 995 debug("%s: replace_ldapattr()", __FILE__); 996 997 if ((credp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t))) == NULL) 998 return (NS_LDAP_MEMORY); /* map to PWU_NOMEM */ 999 1000 /* for admin shadow update, dn and pwd will be set later in libsldap */ 1001 if ((flags & NS_LDAP_UPDATE_SHADOW) == 0) { 1002 /* Fill in the user name and password */ 1003 if (dn == NULL || pwd == NULL) 1004 goto out; 1005 credp->cred.unix_cred.userID = strdup(binddn); 1006 credp->cred.unix_cred.passwd = strdup(pwd); 1007 } 1008 1009 /* get host certificate path, if one is configured */ 1010 ldaprc = __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P, 1011 (void ***)&certpath, &errorp); 1012 if (ldaprc != NS_LDAP_SUCCESS) 1013 goto out; 1014 1015 if (certpath && *certpath) 1016 credp->hostcertpath = *certpath; 1017 1018 /* Load the service specific authentication method */ 1019 ldaprc = __ns_ldap_getServiceAuthMethods("passwd-cmd", &authpp, 1020 &errorp); 1021 1022 if (ldaprc != NS_LDAP_SUCCESS) 1023 goto out; 1024 1025 /* 1026 * if authpp is null, there is no serviceAuthenticationMethod 1027 * try default authenticationMethod 1028 */ 1029 if (authpp == NULL) { 1030 ldaprc = __ns_ldap_getParam(NS_LDAP_AUTH_P, (void ***)&authpp, 1031 &errorp); 1032 if (ldaprc != NS_LDAP_SUCCESS) 1033 goto out; 1034 } 1035 1036 /* 1037 * if authpp is still null, then can not authenticate, syslog 1038 * error message and return error 1039 */ 1040 if (authpp == NULL) { 1041 syslog(LOG_ERR, 1042 "passwdutil: no legal LDAP authentication method configured"); 1043 result = NS_LDAP_OP_FAILED; 1044 goto out; 1045 } 1046 1047 /* 1048 * Walk the array and try all authentication methods in order except 1049 * for "none". 1050 */ 1051 for (app = authpp; *app; app++) { 1052 authp = *app; 1053 /* what about disabling other mechanisms? "tls:sasl/EXTERNAL" */ 1054 if (authp->type == NS_LDAP_AUTH_NONE) 1055 continue; 1056 authstried++; 1057 credp->auth.type = authp->type; 1058 credp->auth.tlstype = authp->tlstype; 1059 credp->auth.saslmech = authp->saslmech; 1060 credp->auth.saslopt = authp->saslopt; 1061 1062 ldaprc = __ns_ldap_repAttr("shadow", dn, 1063 (const ns_ldap_attr_t * const *)attrs, 1064 credp, flags, &errorp); 1065 if (ldaprc == NS_LDAP_SUCCESS) { 1066 result = NS_LDAP_SUCCESS; 1067 goto out; 1068 } 1069 1070 /* 1071 * if change not allowed due to configuration, indicate so 1072 * to the caller 1073 */ 1074 if (ldaprc == NS_LDAP_CONFIG && 1075 errorp->status == NS_CONFIG_NOTALLOW) { 1076 result = NS_LDAP_CONFIG; 1077 *pwd_status = NS_PASSWD_CHANGE_NOT_ALLOWED; 1078 goto out; 1079 } 1080 1081 /* 1082 * other errors might need to be added to this list, for 1083 * the current supported mechanisms this is sufficient 1084 */ 1085 if ((ldaprc == NS_LDAP_INTERNAL) && 1086 (errorp->pwd_mgmt.status == NS_PASSWD_GOOD) && 1087 ((errorp->status == LDAP_INAPPROPRIATE_AUTH) || 1088 (errorp->status == LDAP_INVALID_CREDENTIALS))) { 1089 result = ldaprc; 1090 goto out; 1091 } 1092 1093 /* 1094 * If there is error related to password policy, 1095 * return it to caller 1096 */ 1097 if ((ldaprc == NS_LDAP_INTERNAL) && 1098 errorp->pwd_mgmt.status != NS_PASSWD_GOOD) { 1099 *pwd_status = errorp->pwd_mgmt.status; 1100 result = ldaprc; 1101 goto out; 1102 } else 1103 *pwd_status = NS_PASSWD_GOOD; 1104 1105 /* we don't really care about the error, just clean it up */ 1106 if (errorp) 1107 (void) __ns_ldap_freeError(&errorp); 1108 } 1109 if (authstried == 0) { 1110 syslog(LOG_ERR, 1111 "passwdutil: no legal LDAP authentication method configured"); 1112 result = NS_LDAP_CONFIG; 1113 goto out; 1114 } 1115 result = NS_LDAP_OP_FAILED; /* map to PWU_DENIED */ 1116 1117 out: 1118 if (credp) 1119 (void) __ns_ldap_freeCred(&credp); 1120 1121 if (authpp) 1122 (void) __ns_ldap_freeParam((void ***)&authpp); 1123 1124 if (errorp) 1125 (void) __ns_ldap_freeError(&errorp); 1126 1127 return (result); 1128 } 1129 1130 1131 /* 1132 * ldap_putpwnam(name, oldpw, dummy, rep, buf) 1133 * 1134 * update the LDAP server with the attributes contained in 'buf'. 1135 * The dummy parameter is a placeholder for NIS+ where the old 1136 * RPC password is passwd. 1137 */ 1138 /*ARGSUSED*/ 1139 int 1140 ldap_putpwnam(char *name, char *oldpw, char *dummy, 1141 pwu_repository_t *rep, 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