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