root/source3/passdb/pdb_nds.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. berEncodePasswordData
  2. berEncodeLoginData
  3. berDecodeLoginData
  4. getLoginConfig
  5. nmasldap_get_simple_pwd
  6. nmasldap_set_password
  7. nmasldap_get_password
  8. pdb_nds_get_password
  9. pdb_nds_set_password
  10. pdb_nds_update_login_attempts
  11. pdb_init_NDS_ldapsam_common
  12. pdb_init_NDS_ldapsam_compat
  13. pdb_init_NDS_ldapsam
  14. pdb_nds_init

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

/* [<][>][^][v][top][bottom][index][help] */