1/* 2 Unix SMB/CIFS mplementation. 3 NDS LDAP helper functions for SAMBA 4 Copyright (C) Vince Brimhall 2004-2005 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 20*/ 21 22#include "includes.h" 23 24#include <lber.h> 25#include <ldap.h> 26#include <wchar.h> 27 28#include "smbldap.h" 29 30#define NMASLDAP_GET_LOGIN_CONFIG_REQUEST "2.16.840.1.113719.1.39.42.100.3" 31#define NMASLDAP_GET_LOGIN_CONFIG_RESPONSE "2.16.840.1.113719.1.39.42.100.4" 32#define NMASLDAP_SET_PASSWORD_REQUEST "2.16.840.1.113719.1.39.42.100.11" 33#define NMASLDAP_SET_PASSWORD_RESPONSE "2.16.840.1.113719.1.39.42.100.12" 34#define NMASLDAP_GET_PASSWORD_REQUEST "2.16.840.1.113719.1.39.42.100.13" 35#define NMASLDAP_GET_PASSWORD_RESPONSE "2.16.840.1.113719.1.39.42.100.14" 36 37#define NMAS_LDAP_EXT_VERSION 1 38 39/********************************************************************** 40 Take the request BER value and input data items and BER encodes the 41 data into the BER value 42**********************************************************************/ 43 44static int berEncodePasswordData( 45 struct berval **requestBV, 46 const char *objectDN, 47 const char *password, 48 const char *password2) 49{ 50 int err = 0, rc=0; 51 BerElement *requestBer = NULL; 52 53 const char * utf8ObjPtr = NULL; 54 int utf8ObjSize = 0; 55 const char * utf8PwdPtr = NULL; 56 int utf8PwdSize = 0; 57 const char * utf8Pwd2Ptr = NULL; 58 int utf8Pwd2Size = 0; 59 60 61 /* Convert objectDN and tag strings from Unicode to UTF-8 */ 62 utf8ObjSize = strlen(objectDN)+1; 63 utf8ObjPtr = objectDN; 64 65 if (password != NULL) 66 { 67 utf8PwdSize = strlen(password)+1; 68 utf8PwdPtr = password; 69 } 70 71 if (password2 != NULL) 72 { 73 utf8Pwd2Size = strlen(password2)+1; 74 utf8Pwd2Ptr = password2; 75 } 76 77 /* Allocate a BerElement for the request parameters. */ 78 if((requestBer = ber_alloc()) == NULL) 79 { 80 err = LDAP_ENCODING_ERROR; 81 goto Cleanup; 82 } 83 84 if (password != NULL && password2 != NULL) 85 { 86 /* BER encode the NMAS Version, the objectDN, and the password */ 87 rc = ber_printf(requestBer, "{iooo}", NMAS_LDAP_EXT_VERSION, utf8ObjPtr, utf8ObjSize, utf8PwdPtr, utf8PwdSize, utf8Pwd2Ptr, utf8Pwd2Size); 88 } 89 else if (password != NULL) 90 { 91 /* BER encode the NMAS Version, the objectDN, and the password */ 92 rc = ber_printf(requestBer, "{ioo}", NMAS_LDAP_EXT_VERSION, utf8ObjPtr, utf8ObjSize, utf8PwdPtr, utf8PwdSize); 93 } 94 else 95 { 96 /* BER encode the NMAS Version and the objectDN */ 97 rc = ber_printf(requestBer, "{io}", NMAS_LDAP_EXT_VERSION, utf8ObjPtr, utf8ObjSize); 98 } 99 100 if (rc < 0) 101 { 102 err = LDAP_ENCODING_ERROR; 103 goto Cleanup; 104 } 105 else 106 { 107 err = 0; 108 } 109 110 /* Convert the BER we just built to a berval that we'll send with the extended request. */ 111 if(ber_flatten(requestBer, requestBV) == LBER_ERROR) 112 { 113 err = LDAP_ENCODING_ERROR; 114 goto Cleanup; 115 } 116 117Cleanup: 118 119 if(requestBer) 120 { 121 ber_free(requestBer, 1); 122 } 123 124 return err; 125} 126 127/********************************************************************** 128 Take the request BER value and input data items and BER encodes the 129 data into the BER value 130**********************************************************************/ 131 132static int berEncodeLoginData( 133 struct berval **requestBV, 134 char *objectDN, 135 unsigned int methodIDLen, 136 unsigned int *methodID, 137 char *tag, 138 size_t putDataLen, 139 void *putData) 140{ 141 int err = 0; 142 BerElement *requestBer = NULL; 143 144 unsigned int i; 145 unsigned int elemCnt = methodIDLen / sizeof(unsigned int); 146 147 char *utf8ObjPtr=NULL; 148 int utf8ObjSize = 0; 149 150 char *utf8TagPtr = NULL; 151 int utf8TagSize = 0; 152 153 utf8ObjPtr = objectDN; 154 utf8ObjSize = strlen(utf8ObjPtr)+1; 155 156 utf8TagPtr = tag; 157 utf8TagSize = strlen(utf8TagPtr)+1; 158 159 /* Allocate a BerElement for the request parameters. */ 160 if((requestBer = ber_alloc()) == NULL) 161 { 162 err = LDAP_ENCODING_ERROR; 163 goto Cleanup; 164 } 165 166 /* BER encode the NMAS Version and the objectDN */ 167 err = (ber_printf(requestBer, "{io", NMAS_LDAP_EXT_VERSION, utf8ObjPtr, utf8ObjSize) < 0) ? LDAP_ENCODING_ERROR : 0; 168 169 /* BER encode the MethodID Length and value */ 170 if (!err) 171 { 172 err = (ber_printf(requestBer, "{i{", methodIDLen) < 0) ? LDAP_ENCODING_ERROR : 0; 173 } 174 175 for (i = 0; !err && i < elemCnt; i++) 176 { 177 err = (ber_printf(requestBer, "i", methodID[i]) < 0) ? LDAP_ENCODING_ERROR : 0; 178 } 179 180 if (!err) 181 { 182 err = (ber_printf(requestBer, "}}", 0) < 0) ? LDAP_ENCODING_ERROR : 0; 183 } 184 185 if(putData) 186 { 187 /* BER Encode the the tag and data */ 188 err = (ber_printf(requestBer, "oio}", utf8TagPtr, utf8TagSize, putDataLen, putData, putDataLen) < 0) ? LDAP_ENCODING_ERROR : 0; 189 } 190 else 191 { 192 /* BER Encode the the tag */ 193 err = (ber_printf(requestBer, "o}", utf8TagPtr, utf8TagSize) < 0) ? LDAP_ENCODING_ERROR : 0; 194 } 195 196 if (err) 197 { 198 goto Cleanup; 199 } 200 201 /* Convert the BER we just built to a berval that we'll send with the extended request. */ 202 if(ber_flatten(requestBer, requestBV) == LBER_ERROR) 203 { 204 err = LDAP_ENCODING_ERROR; 205 goto Cleanup; 206 } 207 208Cleanup: 209 210 if(requestBer) 211 { 212 ber_free(requestBer, 1); 213 } 214 215 return err; 216} 217 218/********************************************************************** 219 Takes the reply BER Value and decodes the NMAS server version and 220 return code and if a non null retData buffer was supplied, tries to 221 decode the the return data and length 222**********************************************************************/ 223 224static int berDecodeLoginData( 225 struct berval *replyBV, 226 int *serverVersion, 227 size_t *retDataLen, 228 void *retData ) 229{ 230 int rc=0, err = 0; 231 BerElement *replyBer = NULL; 232 char *retOctStr = NULL; 233 size_t retOctStrLen = 0; 234 235 if((replyBer = ber_init(replyBV)) == NULL) 236 { 237 err = LDAP_OPERATIONS_ERROR; 238 goto Cleanup; 239 } 240 241 if(retData) 242 { 243 retOctStrLen = *retDataLen + 1; 244 retOctStr = (char *)malloc(retOctStrLen); 245 if(!retOctStr) 246 { 247 err = LDAP_OPERATIONS_ERROR; 248 goto Cleanup; 249 } 250 251 if( (rc = ber_scanf(replyBer, "{iis}", serverVersion, &err, retOctStr, &retOctStrLen)) != -1) 252 { 253 if (*retDataLen >= retOctStrLen) 254 { 255 memcpy(retData, retOctStr, retOctStrLen); 256 } 257 else if (!err) 258 { 259 err = LDAP_NO_MEMORY; 260 } 261 262 *retDataLen = retOctStrLen; 263 } 264 else if (!err) 265 { 266 err = LDAP_DECODING_ERROR; 267 } 268 } 269 else 270 { 271 if( (rc = ber_scanf(replyBer, "{ii}", serverVersion, &err)) == -1) 272 { 273 if (!err) 274 { 275 err = LDAP_DECODING_ERROR; 276 } 277 } 278 } 279 280Cleanup: 281 282 if(replyBer) 283 { 284 ber_free(replyBer, 1); 285 } 286 287 if (retOctStr != NULL) 288 { 289 memset(retOctStr, 0, retOctStrLen); 290 free(retOctStr); 291 } 292 293 return err; 294} 295 296/********************************************************************** 297 Retrieves data in the login configuration of the specified object 298 that is tagged with the specified methodID and tag. 299**********************************************************************/ 300 301static int getLoginConfig( 302 LDAP *ld, 303 char *objectDN, 304 unsigned int methodIDLen, 305 unsigned int *methodID, 306 char *tag, 307 size_t *dataLen, 308 void *data ) 309{ 310 int err = 0; 311 struct berval *requestBV = NULL; 312 char *replyOID = NULL; 313 struct berval *replyBV = NULL; 314 int serverVersion = 0; 315 316 /* Validate unicode parameters. */ 317 if((strlen(objectDN) == 0) || ld == NULL) 318 { 319 return LDAP_NO_SUCH_ATTRIBUTE; 320 } 321 322 err = berEncodeLoginData(&requestBV, objectDN, methodIDLen, methodID, tag, 0, NULL); 323 if(err) 324 { 325 goto Cleanup; 326 } 327 328 /* Call the ldap_extended_operation (synchronously) */ 329 if((err = ldap_extended_operation_s(ld, NMASLDAP_GET_LOGIN_CONFIG_REQUEST, 330 requestBV, NULL, NULL, &replyOID, &replyBV))) 331 { 332 goto Cleanup; 333 } 334 335 /* Make sure there is a return OID */ 336 if(!replyOID) 337 { 338 err = LDAP_NOT_SUPPORTED; 339 goto Cleanup; 340 } 341 342 /* Is this what we were expecting to get back. */ 343 if(strcmp(replyOID, NMASLDAP_GET_LOGIN_CONFIG_RESPONSE)) 344 { 345 err = LDAP_NOT_SUPPORTED; 346 goto Cleanup; 347 } 348 349 /* Do we have a good returned berval? */ 350 if(!replyBV) 351 { 352 /* No; returned berval means we experienced a rather drastic error. */ 353 /* Return operations error. */ 354 err = LDAP_OPERATIONS_ERROR; 355 goto Cleanup; 356 } 357 358 err = berDecodeLoginData(replyBV, &serverVersion, dataLen, data); 359 360 if(serverVersion != NMAS_LDAP_EXT_VERSION) 361 { 362 err = LDAP_OPERATIONS_ERROR; 363 goto Cleanup; 364 } 365 366Cleanup: 367 368 if(replyBV) 369 { 370 ber_bvfree(replyBV); 371 } 372 373 /* Free the return OID string if one was returned. */ 374 if(replyOID) 375 { 376 ldap_memfree(replyOID); 377 } 378 379 /* Free memory allocated while building the request ber and berval. */ 380 if(requestBV) 381 { 382 ber_bvfree(requestBV); 383 } 384 385 /* Return the appropriate error/success code. */ 386 return err; 387} 388 389/********************************************************************** 390 Attempts to get the Simple Password 391**********************************************************************/ 392 393static int nmasldap_get_simple_pwd( 394 LDAP *ld, 395 char *objectDN, 396 size_t pwdLen, 397 char *pwd ) 398{ 399 int err = 0; 400 unsigned int methodID = 0; 401 unsigned int methodIDLen = sizeof(methodID); 402 char tag[] = {'P','A','S','S','W','O','R','D',' ','H','A','S','H',0}; 403 char *pwdBuf=NULL; 404 size_t pwdBufLen, bufferLen; 405 406 bufferLen = pwdBufLen = pwdLen+2; 407 pwdBuf = (char *)malloc(pwdBufLen); /* digest and null */ 408 if(pwdBuf == NULL) 409 { 410 return LDAP_NO_MEMORY; 411 } 412 413 err = getLoginConfig(ld, objectDN, methodIDLen, &methodID, tag, &pwdBufLen, pwdBuf); 414 if (err == 0) 415 { 416 if (pwdBufLen !=0) 417 { 418 pwdBuf[pwdBufLen] = 0; /* null terminate */ 419 420 switch (pwdBuf[0]) 421 { 422 case 1: /* cleartext password */ 423 break; 424 case 2: /* SHA1 HASH */ 425 case 3: /* MD5_ID */ 426 case 4: /* UNIXCrypt_ID */ 427 case 8: /* SSHA_ID */ 428 default: /* Unknown digest */ 429 err = LDAP_INAPPROPRIATE_AUTH; /* only return clear text */ 430 break; 431 } 432 433 if (!err) 434 { 435 if (pwdLen >= pwdBufLen-1) 436 { 437 memcpy(pwd, &pwdBuf[1], pwdBufLen-1); /* skip digest tag and include null */ 438 } 439 else 440 { 441 err = LDAP_NO_MEMORY; 442 } 443 } 444 } 445 } 446 447 if (pwdBuf != NULL) 448 { 449 memset(pwdBuf, 0, bufferLen); 450 free(pwdBuf); 451 } 452 453 return err; 454} 455 456 457/********************************************************************** 458 Attempts to set the Universal Password 459**********************************************************************/ 460 461static int nmasldap_set_password( 462 LDAP *ld, 463 const char *objectDN, 464 const char *pwd ) 465{ 466 int err = 0; 467 468 struct berval *requestBV = NULL; 469 char *replyOID = NULL; 470 struct berval *replyBV = NULL; 471 int serverVersion; 472 473 /* Validate char parameters. */ 474 if(objectDN == NULL || (strlen(objectDN) == 0) || pwd == NULL || ld == NULL) 475 { 476 return LDAP_NO_SUCH_ATTRIBUTE; 477 } 478 479 err = berEncodePasswordData(&requestBV, objectDN, pwd, NULL); 480 if(err) 481 { 482 goto Cleanup; 483 } 484 485 /* Call the ldap_extended_operation (synchronously) */ 486 if((err = ldap_extended_operation_s(ld, NMASLDAP_SET_PASSWORD_REQUEST, requestBV, NULL, NULL, &replyOID, &replyBV))) 487 { 488 goto Cleanup; 489 } 490 491 /* Make sure there is a return OID */ 492 if(!replyOID) 493 { 494 err = LDAP_NOT_SUPPORTED; 495 goto Cleanup; 496 } 497 498 /* Is this what we were expecting to get back. */ 499 if(strcmp(replyOID, NMASLDAP_SET_PASSWORD_RESPONSE)) 500 { 501 err = LDAP_NOT_SUPPORTED; 502 goto Cleanup; 503 } 504 505 /* Do we have a good returned berval? */ 506 if(!replyBV) 507 { 508 /* No; returned berval means we experienced a rather drastic error. */ 509 /* Return operations error. */ 510 err = LDAP_OPERATIONS_ERROR; 511 goto Cleanup; 512 } 513 514 err = berDecodeLoginData(replyBV, &serverVersion, NULL, NULL); 515 516 if(serverVersion != NMAS_LDAP_EXT_VERSION) 517 { 518 err = LDAP_OPERATIONS_ERROR; 519 goto Cleanup; 520 } 521 522Cleanup: 523 524 if(replyBV) 525 { 526 ber_bvfree(replyBV); 527 } 528 529 /* Free the return OID string if one was returned. */ 530 if(replyOID) 531 { 532 ldap_memfree(replyOID); 533 } 534 535 /* Free memory allocated while building the request ber and berval. */ 536 if(requestBV) 537 { 538 ber_bvfree(requestBV); 539 } 540 541 /* Return the appropriate error/success code. */ 542 return err; 543} 544 545/********************************************************************** 546 Attempts to get the Universal Password 547**********************************************************************/ 548 549static int nmasldap_get_password( 550 LDAP *ld, 551 char *objectDN, 552 size_t *pwdSize, /* in bytes */ 553 char *pwd ) 554{ 555 int err = 0; 556 557 struct berval *requestBV = NULL; 558 char *replyOID = NULL; 559 struct berval *replyBV = NULL; 560 int serverVersion; 561 char *pwdBuf; 562 size_t pwdBufLen, bufferLen; 563 564 /* Validate char parameters. */ 565 if(objectDN == NULL || (strlen(objectDN) == 0) || pwdSize == NULL || ld == NULL) 566 { 567 return LDAP_NO_SUCH_ATTRIBUTE; 568 } 569 570 bufferLen = pwdBufLen = *pwdSize; 571 pwdBuf = (char *)malloc(pwdBufLen+2); 572 if(pwdBuf == NULL) 573 { 574 return LDAP_NO_MEMORY; 575 } 576 577 err = berEncodePasswordData(&requestBV, objectDN, NULL, NULL); 578 if(err) 579 { 580 goto Cleanup; 581 } 582 583 /* Call the ldap_extended_operation (synchronously) */ 584 if((err = ldap_extended_operation_s(ld, NMASLDAP_GET_PASSWORD_REQUEST, requestBV, NULL, NULL, &replyOID, &replyBV))) 585 { 586 goto Cleanup; 587 } 588 589 /* Make sure there is a return OID */ 590 if(!replyOID) 591 { 592 err = LDAP_NOT_SUPPORTED; 593 goto Cleanup; 594 } 595 596 /* Is this what we were expecting to get back. */ 597 if(strcmp(replyOID, NMASLDAP_GET_PASSWORD_RESPONSE)) 598 { 599 err = LDAP_NOT_SUPPORTED; 600 goto Cleanup; 601 } 602 603 /* Do we have a good returned berval? */ 604 if(!replyBV) 605 { 606 /* No; returned berval means we experienced a rather drastic error. */ 607 /* Return operations error. */ 608 err = LDAP_OPERATIONS_ERROR; 609 goto Cleanup; 610 } 611 612 err = berDecodeLoginData(replyBV, &serverVersion, &pwdBufLen, pwdBuf); 613 614 if(serverVersion != NMAS_LDAP_EXT_VERSION) 615 { 616 err = LDAP_OPERATIONS_ERROR; 617 goto Cleanup; 618 } 619 620 if (!err && pwdBufLen != 0) 621 { 622 if (*pwdSize >= pwdBufLen+1 && pwd != NULL) 623 { 624 memcpy(pwd, pwdBuf, pwdBufLen); 625 pwd[pwdBufLen] = 0; /* add null termination */ 626 } 627 *pwdSize = pwdBufLen; /* does not include null termination */ 628 } 629 630Cleanup: 631 632 if(replyBV) 633 { 634 ber_bvfree(replyBV); 635 } 636 637 /* Free the return OID string if one was returned. */ 638 if(replyOID) 639 { 640 ldap_memfree(replyOID); 641 } 642 643 /* Free memory allocated while building the request ber and berval. */ 644 if(requestBV) 645 { 646 ber_bvfree(requestBV); 647 } 648 649 if (pwdBuf != NULL) 650 { 651 memset(pwdBuf, 0, bufferLen); 652 free(pwdBuf); 653 } 654 655 /* Return the appropriate error/success code. */ 656 return err; 657} 658 659/********************************************************************** 660 Get the user's password from NDS. 661 *********************************************************************/ 662 663int pdb_nds_get_password( 664 struct smbldap_state *ldap_state, 665 char *object_dn, 666 int *pwd_len, 667 char *pwd ) 668{ 669 LDAP *ld = ldap_state->ldap_struct; 670 int rc = -1; 671 672 rc = nmasldap_get_password(ld, object_dn, pwd_len, pwd); 673 if (rc == LDAP_SUCCESS) { 674#ifdef DEBUG_PASSWORD 675 DEBUG(100,("nmasldap_get_password returned %s for %s\n", pwd, object_dn)); 676#endif 677 DEBUG(5, ("NDS Universal Password retrieved for %s\n", object_dn)); 678 } else { 679 DEBUG(3, ("NDS Universal Password NOT retrieved for %s\n", object_dn)); 680 } 681 682 if (rc != LDAP_SUCCESS) { 683 rc = nmasldap_get_simple_pwd(ld, object_dn, *pwd_len, pwd); 684 if (rc == LDAP_SUCCESS) { 685#ifdef DEBUG_PASSWORD 686 DEBUG(100,("nmasldap_get_simple_pwd returned %s for %s\n", pwd, object_dn)); 687#endif 688 DEBUG(5, ("NDS Simple Password retrieved for %s\n", object_dn)); 689 } else { 690 /* We couldn't get the password */ 691 DEBUG(3, ("NDS Simple Password NOT retrieved for %s\n", object_dn)); 692 return LDAP_INVALID_CREDENTIALS; 693 } 694 } 695 696 /* We got the password */ 697 return LDAP_SUCCESS; 698} 699 700/********************************************************************** 701 Set the users NDS, Universal and Simple passwords. 702 ********************************************************************/ 703 704int pdb_nds_set_password( 705 struct smbldap_state *ldap_state, 706 char *object_dn, 707 const char *pwd ) 708{ 709 LDAP *ld = ldap_state->ldap_struct; 710 int rc = -1; 711 LDAPMod **tmpmods = NULL; 712 713 rc = nmasldap_set_password(ld, object_dn, pwd); 714 if (rc == LDAP_SUCCESS) { 715 DEBUG(5,("NDS Universal Password changed for user %s\n", object_dn)); 716 } else { 717 /* This will fail if Universal Password is not enabled for the user's context */ 718 DEBUG(3,("NDS Universal Password could not be changed for user %s: %d\n", 719 object_dn, rc)); 720 } 721 722 /* Set eDirectory Password */ 723 smbldap_set_mod(&tmpmods, LDAP_MOD_REPLACE, "userPassword", pwd); 724 rc = smbldap_modify(ldap_state, object_dn, tmpmods); 725 726 return rc; 727} 728 729/********************************************************************** 730 Allow ldap server to update internal login attempt counters by 731 performing a simple bind. If the samba authentication failed attempt 732 the bind with a bogus, randomly generated password to count the 733 failed attempt. If the bind fails even though samba authentication 734 succeeded, this would indicate that the user's account is disabled, 735 time restrictions are in place or some other password policy 736 violation. 737*********************************************************************/ 738 739static NTSTATUS pdb_nds_update_login_attempts(struct pdb_methods *methods, 740 SAM_ACCOUNT *sam_acct, BOOL success) 741{ 742 struct ldapsam_privates *ldap_state; 743 744 if ((!methods) || (!sam_acct)) { 745 DEBUG(3,("pdb_nds_update_login_attempts: invalid parameter.\n")); 746 return NT_STATUS_MEMORY_NOT_ALLOCATED; 747 } 748 749 ldap_state = (struct ldapsam_privates *)methods->private_data; 750 751 if (ldap_state) { 752 /* Attempt simple bind with user credentials to update eDirectory 753 password policy */ 754 int rc = 0; 755 char *dn; 756 LDAPMessage *result = NULL; 757 LDAPMessage *entry = NULL; 758 const char **attr_list; 759 size_t pwd_len; 760 uchar clear_text_pw[512]; 761 const char *p = NULL; 762 LDAP *ld = NULL; 763 int ldap_port = 0; 764 char protocol[12]; 765 char ldap_server[256]; 766 const char *username = pdb_get_username(sam_acct); 767 BOOL got_clear_text_pw = False; 768 769 DEBUG(5,("pdb_nds_update_login_attempts: %s login for %s\n", 770 success ? "Successful" : "Failed", username)); 771 772 result = pdb_get_backend_private_data(sam_acct, methods); 773 if (!result) { 774 attr_list = get_userattr_list(ldap_state->schema_ver); 775 rc = ldapsam_search_suffix_by_name(ldap_state, username, &result, attr_list ); 776 free_attr_list( attr_list ); 777 if (rc != LDAP_SUCCESS) { 778 return NT_STATUS_OBJECT_NAME_NOT_FOUND; 779 } 780 pdb_set_backend_private_data(sam_acct, result, private_data_free_fn, methods, PDB_CHANGED); 781 } 782 783 if (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result) == 0) { 784 DEBUG(0, ("pdb_nds_update_login_attempts: No user to modify!\n")); 785 return NT_STATUS_OBJECT_NAME_NOT_FOUND; 786 } 787 788 entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, result); 789 dn = smbldap_get_dn(ldap_state->smbldap_state->ldap_struct, entry); 790 if (!dn) { 791 return NT_STATUS_OBJECT_NAME_NOT_FOUND; 792 } 793 794 DEBUG(3, ("pdb_nds_update_login_attempts: username %s found dn '%s'\n", username, dn)); 795 796 pwd_len = sizeof(clear_text_pw); 797 if (success == True) { 798 if (pdb_nds_get_password(ldap_state->smbldap_state, dn, &pwd_len, clear_text_pw) == LDAP_SUCCESS) { 799 /* Got clear text password. Use simple ldap bind */ 800 got_clear_text_pw = True; 801 } 802 } else { 803 generate_random_buffer(clear_text_pw, 24); 804 clear_text_pw[24] = '\0'; 805 DEBUG(5,("pdb_nds_update_login_attempts: using random password %s\n", clear_text_pw)); 806 } 807 808 /* Parse the location string */ 809 p = ldap_state->location; 810 811 /* skip leading "URL:" (if any) */ 812 if ( strnequal( p, "URL:", 4 ) ) { 813 p += 4; 814 } 815 816 sscanf(p, "%10[^:]://%254[^:/]:%d", protocol, ldap_server, &ldap_port); 817 818 if (ldap_port == 0) { 819 if (strequal(protocol, "ldap")) { 820 ldap_port = LDAP_PORT; 821 } else if (strequal(protocol, "ldaps")) { 822 ldap_port = LDAPS_PORT; 823 } else { 824 DEBUG(0, ("unrecognised protocol (%s)!\n", protocol)); 825 } 826 } 827 828 ld = ldap_init(ldap_server, ldap_port); 829 830 if(ld != NULL) { 831 int version; 832 833 /* LDAP version 3 required for ldap_sasl */ 834 if (ldap_get_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS) { 835 if (version != LDAP_VERSION3) { 836 version = LDAP_VERSION3; 837 if (ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS) { 838 DEBUG(4, ("pdb_nds_update_login_attempts: Set protocol version to LDAP_VERSION3\n")); 839 } 840 } 841 } 842 843 /* Turn on ssl if required */ 844 if(strequal(protocol, "ldaps")) { 845 int tls = LDAP_OPT_X_TLS_HARD; 846 if (ldap_set_option (ld, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS) { 847 DEBUG(1, ("pdb_nds_update_login_attempts: Failed to setup a TLS session\n")); 848 } else { 849 DEBUG(4, ("pdb_nds_update_login_attempts: Activated TLS on session\n")); 850 } 851 } 852 } 853 854 if((success != True) || (got_clear_text_pw == True)) { 855 /* Attempt simple bind with real or bogus password */ 856 rc = ldap_simple_bind_s(ld, dn, clear_text_pw); 857 if (rc == LDAP_SUCCESS) { 858 DEBUG(5,("pdb_nds_update_login_attempts: ldap_simple_bind_s Successful for %s\n", username)); 859 ldap_unbind_ext(ld, NULL, NULL); 860 } else { 861 NTSTATUS nt_status = NT_STATUS_ACCOUNT_RESTRICTION; 862 DEBUG(5,("pdb_nds_update_login_attempts: ldap_simple_bind_s Failed for %s\n", username)); 863 switch(rc) { 864 case LDAP_INVALID_CREDENTIALS: 865 nt_status = NT_STATUS_WRONG_PASSWORD; 866 break; 867 default: 868 break; 869 } 870 return nt_status; 871 } 872 } 873 } 874 875 return NT_STATUS_OK; 876} 877 878/********************************************************************** 879 Intitalise the parts of the pdb_context that are common to NDS_ldapsam modes 880 *********************************************************************/ 881 882static NTSTATUS pdb_init_NDS_ldapsam_common(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location) 883{ 884 struct ldapsam_privates *ldap_state = (*pdb_method)->private_data; 885 886 /* Mark this as eDirectory ldap */ 887 ldap_state->is_nds_ldap = True; 888 889 /* Add pdb_nds specific method for updating login attempts. */ 890 (*pdb_method)->update_login_attempts = pdb_nds_update_login_attempts; 891 892 /* Save location for use in pdb_nds_update_login_attempts */ 893 ldap_state->location = strdup(location); 894 895 return NT_STATUS_OK; 896} 897 898 899/********************************************************************** 900 Initialise the 'nds compat' mode for pdb_ldap 901 *********************************************************************/ 902 903static NTSTATUS pdb_init_NDS_ldapsam_compat(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location) 904{ 905 NTSTATUS nt_status = pdb_init_ldapsam_compat(pdb_context, pdb_method, location); 906 907 (*pdb_method)->name = "NDS_ldapsam_compat"; 908 909 pdb_init_NDS_ldapsam_common(pdb_context, pdb_method, location); 910 911 return nt_status; 912} 913 914 915/********************************************************************** 916 Initialise the 'nds' normal mode for pdb_ldap 917 *********************************************************************/ 918 919static NTSTATUS pdb_init_NDS_ldapsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location) 920{ 921 NTSTATUS nt_status = pdb_init_ldapsam(pdb_context, pdb_method, location); 922 923 (*pdb_method)->name = "NDS_ldapsam"; 924 925 pdb_init_NDS_ldapsam_common(pdb_context, pdb_method, location); 926 927 return nt_status; 928} 929 930NTSTATUS pdb_nds_init(void) 931{ 932 NTSTATUS nt_status; 933 if (!NT_STATUS_IS_OK(nt_status = smb_register_passdb(PASSDB_INTERFACE_VERSION, "NDS_ldapsam", pdb_init_NDS_ldapsam))) 934 return nt_status; 935 936 if (!NT_STATUS_IS_OK(nt_status = smb_register_passdb(PASSDB_INTERFACE_VERSION, "NDS_ldapsam_compat", pdb_init_NDS_ldapsam_compat))) 937 return nt_status; 938 939 return NT_STATUS_OK; 940} 941