s3-smbldap: make smbldap public library and maintain its ABI
[Samba.git] / source3 / passdb / pdb_nds.c
blob3e1bdfc15147727c9fca52ba77a47f33cfad01c6
1 /*
2 Unix SMB/CIFS mplementation.
3 NDS LDAP helper functions for SAMBA
4 Copyright (C) Vince Brimhall 2004-2005
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.
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.
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/>.
21 #include "includes.h"
22 #include "passdb.h"
24 #include <lber.h>
25 #include <ldap.h>
26 #include <wchar.h>
28 #include "smbldap.h"
29 #include "passdb/pdb_ldap.h"
30 #include "passdb/pdb_nds.h"
32 #define NMASLDAP_GET_LOGIN_CONFIG_REQUEST "2.16.840.1.113719.1.39.42.100.3"
33 #define NMASLDAP_GET_LOGIN_CONFIG_RESPONSE "2.16.840.1.113719.1.39.42.100.4"
34 #define NMASLDAP_SET_PASSWORD_REQUEST "2.16.840.1.113719.1.39.42.100.11"
35 #define NMASLDAP_SET_PASSWORD_RESPONSE "2.16.840.1.113719.1.39.42.100.12"
36 #define NMASLDAP_GET_PASSWORD_REQUEST "2.16.840.1.113719.1.39.42.100.13"
37 #define NMASLDAP_GET_PASSWORD_RESPONSE "2.16.840.1.113719.1.39.42.100.14"
39 #define NMAS_LDAP_EXT_VERSION 1
41 /**********************************************************************
42 Take the request BER value and input data items and BER encodes the
43 data into the BER value
44 **********************************************************************/
46 static int berEncodePasswordData(
47 struct berval **requestBV,
48 const char *objectDN,
49 const char *password,
50 const char *password2)
52 int err = 0, rc=0;
53 BerElement *requestBer = NULL;
55 const char * utf8ObjPtr = NULL;
56 int utf8ObjSize = 0;
57 const char * utf8PwdPtr = NULL;
58 int utf8PwdSize = 0;
59 const char * utf8Pwd2Ptr = NULL;
60 int utf8Pwd2Size = 0;
63 /* Convert objectDN and tag strings from Unicode to UTF-8 */
64 utf8ObjSize = strlen(objectDN)+1;
65 utf8ObjPtr = objectDN;
67 if (password != NULL)
69 utf8PwdSize = strlen(password)+1;
70 utf8PwdPtr = password;
73 if (password2 != NULL)
75 utf8Pwd2Size = strlen(password2)+1;
76 utf8Pwd2Ptr = password2;
79 /* Allocate a BerElement for the request parameters. */
80 if((requestBer = ber_alloc()) == NULL)
82 err = LDAP_ENCODING_ERROR;
83 goto Cleanup;
86 if (password != NULL && password2 != NULL)
88 /* BER encode the NMAS Version, the objectDN, and the password */
89 rc = ber_printf(requestBer, "{iooo}", NMAS_LDAP_EXT_VERSION, utf8ObjPtr, utf8ObjSize, utf8PwdPtr, utf8PwdSize, utf8Pwd2Ptr, utf8Pwd2Size);
91 else if (password != NULL)
93 /* BER encode the NMAS Version, the objectDN, and the password */
94 rc = ber_printf(requestBer, "{ioo}", NMAS_LDAP_EXT_VERSION, utf8ObjPtr, utf8ObjSize, utf8PwdPtr, utf8PwdSize);
96 else
98 /* BER encode the NMAS Version and the objectDN */
99 rc = ber_printf(requestBer, "{io}", NMAS_LDAP_EXT_VERSION, utf8ObjPtr, utf8ObjSize);
102 if (rc < 0)
104 err = LDAP_ENCODING_ERROR;
105 goto Cleanup;
107 else
109 err = 0;
112 /* Convert the BER we just built to a berval that we'll send with the extended request. */
113 if(ber_flatten(requestBer, requestBV) == LBER_ERROR)
115 err = LDAP_ENCODING_ERROR;
116 goto Cleanup;
119 Cleanup:
121 if(requestBer)
123 ber_free(requestBer, 1);
126 return err;
129 /**********************************************************************
130 Take the request BER value and input data items and BER encodes the
131 data into the BER value
132 **********************************************************************/
134 static int berEncodeLoginData(
135 struct berval **requestBV,
136 char *objectDN,
137 unsigned int methodIDLen,
138 unsigned int *methodID,
139 char *tag,
140 size_t putDataLen,
141 void *putData)
143 int err = 0;
144 BerElement *requestBer = NULL;
146 unsigned int i;
147 unsigned int elemCnt = methodIDLen / sizeof(unsigned int);
149 char *utf8ObjPtr=NULL;
150 int utf8ObjSize = 0;
152 char *utf8TagPtr = NULL;
153 int utf8TagSize = 0;
155 utf8ObjPtr = objectDN;
156 utf8ObjSize = strlen(utf8ObjPtr)+1;
158 utf8TagPtr = tag;
159 utf8TagSize = strlen(utf8TagPtr)+1;
161 /* Allocate a BerElement for the request parameters. */
162 if((requestBer = ber_alloc()) == NULL)
164 err = LDAP_ENCODING_ERROR;
165 goto Cleanup;
168 /* BER encode the NMAS Version and the objectDN */
169 err = (ber_printf(requestBer, "{io", NMAS_LDAP_EXT_VERSION, utf8ObjPtr, utf8ObjSize) < 0) ? LDAP_ENCODING_ERROR : 0;
171 /* BER encode the MethodID Length and value */
172 if (!err)
174 err = (ber_printf(requestBer, "{i{", methodIDLen) < 0) ? LDAP_ENCODING_ERROR : 0;
177 for (i = 0; !err && i < elemCnt; i++)
179 err = (ber_printf(requestBer, "i", methodID[i]) < 0) ? LDAP_ENCODING_ERROR : 0;
182 if (!err)
184 err = (ber_printf(requestBer, "}}", 0) < 0) ? LDAP_ENCODING_ERROR : 0;
187 if(putData)
189 /* BER Encode the the tag and data */
190 err = (ber_printf(requestBer, "oio}", utf8TagPtr, utf8TagSize, putDataLen, putData, putDataLen) < 0) ? LDAP_ENCODING_ERROR : 0;
192 else
194 /* BER Encode the the tag */
195 err = (ber_printf(requestBer, "o}", utf8TagPtr, utf8TagSize) < 0) ? LDAP_ENCODING_ERROR : 0;
198 if (err)
200 goto Cleanup;
203 /* Convert the BER we just built to a berval that we'll send with the extended request. */
204 if(ber_flatten(requestBer, requestBV) == LBER_ERROR)
206 err = LDAP_ENCODING_ERROR;
207 goto Cleanup;
210 Cleanup:
212 if(requestBer)
214 ber_free(requestBer, 1);
217 return err;
220 /**********************************************************************
221 Takes the reply BER Value and decodes the NMAS server version and
222 return code and if a non null retData buffer was supplied, tries to
223 decode the the return data and length
224 **********************************************************************/
226 static int berDecodeLoginData(
227 struct berval *replyBV,
228 int *serverVersion,
229 size_t *retDataLen,
230 void *retData )
232 int err = 0;
233 BerElement *replyBer = NULL;
234 char *retOctStr = NULL;
235 size_t retOctStrLen = 0;
237 if((replyBer = ber_init(replyBV)) == NULL)
239 err = LDAP_OPERATIONS_ERROR;
240 goto Cleanup;
243 if(retData)
245 retOctStrLen = *retDataLen + 1;
246 retOctStr = SMB_MALLOC_ARRAY(char, retOctStrLen);
247 if(!retOctStr)
249 err = LDAP_OPERATIONS_ERROR;
250 goto Cleanup;
253 if(ber_scanf(replyBer, "{iis}", serverVersion, &err, retOctStr, &retOctStrLen) != -1)
255 if (*retDataLen >= retOctStrLen)
257 memcpy(retData, retOctStr, retOctStrLen);
259 else if (!err)
261 err = LDAP_NO_MEMORY;
264 *retDataLen = retOctStrLen;
266 else if (!err)
268 err = LDAP_DECODING_ERROR;
271 else
273 if(ber_scanf(replyBer, "{ii}", serverVersion, &err) == -1)
275 if (!err)
277 err = LDAP_DECODING_ERROR;
282 Cleanup:
284 if(replyBer)
286 ber_free(replyBer, 1);
289 if (retOctStr != NULL)
291 memset(retOctStr, 0, retOctStrLen);
292 free(retOctStr);
295 return err;
298 /**********************************************************************
299 Retrieves data in the login configuration of the specified object
300 that is tagged with the specified methodID and tag.
301 **********************************************************************/
303 static int getLoginConfig(
304 LDAP *ld,
305 char *objectDN,
306 unsigned int methodIDLen,
307 unsigned int *methodID,
308 char *tag,
309 size_t *dataLen,
310 void *data )
312 int err = 0;
313 struct berval *requestBV = NULL;
314 char *replyOID = NULL;
315 struct berval *replyBV = NULL;
316 int serverVersion = 0;
318 /* Validate unicode parameters. */
319 if((strlen(objectDN) == 0) || ld == NULL)
321 return LDAP_NO_SUCH_ATTRIBUTE;
324 err = berEncodeLoginData(&requestBV, objectDN, methodIDLen, methodID, tag, 0, NULL);
325 if(err)
327 goto Cleanup;
330 /* Call the ldap_extended_operation (synchronously) */
331 if((err = ldap_extended_operation_s(ld, NMASLDAP_GET_LOGIN_CONFIG_REQUEST,
332 requestBV, NULL, NULL, &replyOID, &replyBV)))
334 goto Cleanup;
337 /* Make sure there is a return OID */
338 if(!replyOID)
340 err = LDAP_NOT_SUPPORTED;
341 goto Cleanup;
344 /* Is this what we were expecting to get back. */
345 if(strcmp(replyOID, NMASLDAP_GET_LOGIN_CONFIG_RESPONSE))
347 err = LDAP_NOT_SUPPORTED;
348 goto Cleanup;
351 /* Do we have a good returned berval? */
352 if(!replyBV)
354 /* No; returned berval means we experienced a rather drastic error. */
355 /* Return operations error. */
356 err = LDAP_OPERATIONS_ERROR;
357 goto Cleanup;
360 err = berDecodeLoginData(replyBV, &serverVersion, dataLen, data);
362 if(serverVersion != NMAS_LDAP_EXT_VERSION)
364 err = LDAP_OPERATIONS_ERROR;
365 goto Cleanup;
368 Cleanup:
370 if(replyBV)
372 ber_bvfree(replyBV);
375 /* Free the return OID string if one was returned. */
376 if(replyOID)
378 ldap_memfree(replyOID);
381 /* Free memory allocated while building the request ber and berval. */
382 if(requestBV)
384 ber_bvfree(requestBV);
387 /* Return the appropriate error/success code. */
388 return err;
391 /**********************************************************************
392 Attempts to get the Simple Password
393 **********************************************************************/
395 static int nmasldap_get_simple_pwd(
396 LDAP *ld,
397 char *objectDN,
398 size_t pwdLen,
399 char *pwd )
401 int err = 0;
402 unsigned int methodID = 0;
403 unsigned int methodIDLen = sizeof(methodID);
404 char tag[] = {'P','A','S','S','W','O','R','D',' ','H','A','S','H',0};
405 char *pwdBuf=NULL;
406 size_t pwdBufLen, bufferLen;
408 bufferLen = pwdBufLen = pwdLen+2;
409 pwdBuf = SMB_MALLOC_ARRAY(char, pwdBufLen); /* digest and null */
410 if(pwdBuf == NULL)
412 return LDAP_NO_MEMORY;
415 err = getLoginConfig(ld, objectDN, methodIDLen, &methodID, tag, &pwdBufLen, pwdBuf);
416 if (err == 0)
418 if (pwdBufLen !=0)
420 pwdBuf[pwdBufLen] = 0; /* null terminate */
422 switch (pwdBuf[0])
424 case 1: /* cleartext password */
425 break;
426 case 2: /* SHA1 HASH */
427 case 3: /* MD5_ID */
428 case 4: /* UNIXCrypt_ID */
429 case 8: /* SSHA_ID */
430 default: /* Unknown digest */
431 err = LDAP_INAPPROPRIATE_AUTH; /* only return clear text */
432 break;
435 if (!err)
437 if (pwdLen >= pwdBufLen-1)
439 memcpy(pwd, &pwdBuf[1], pwdBufLen-1); /* skip digest tag and include null */
441 else
443 err = LDAP_NO_MEMORY;
449 if (pwdBuf != NULL)
451 memset(pwdBuf, 0, bufferLen);
452 free(pwdBuf);
455 return err;
459 /**********************************************************************
460 Attempts to set the Universal Password
461 **********************************************************************/
463 static int nmasldap_set_password(
464 LDAP *ld,
465 const char *objectDN,
466 const char *pwd )
468 int err = 0;
470 struct berval *requestBV = NULL;
471 char *replyOID = NULL;
472 struct berval *replyBV = NULL;
473 int serverVersion;
475 /* Validate char parameters. */
476 if(objectDN == NULL || (strlen(objectDN) == 0) || pwd == NULL || ld == NULL)
478 return LDAP_NO_SUCH_ATTRIBUTE;
481 err = berEncodePasswordData(&requestBV, objectDN, pwd, NULL);
482 if(err)
484 goto Cleanup;
487 /* Call the ldap_extended_operation (synchronously) */
488 if((err = ldap_extended_operation_s(ld, NMASLDAP_SET_PASSWORD_REQUEST, requestBV, NULL, NULL, &replyOID, &replyBV)))
490 goto Cleanup;
493 /* Make sure there is a return OID */
494 if(!replyOID)
496 err = LDAP_NOT_SUPPORTED;
497 goto Cleanup;
500 /* Is this what we were expecting to get back. */
501 if(strcmp(replyOID, NMASLDAP_SET_PASSWORD_RESPONSE))
503 err = LDAP_NOT_SUPPORTED;
504 goto Cleanup;
507 /* Do we have a good returned berval? */
508 if(!replyBV)
510 /* No; returned berval means we experienced a rather drastic error. */
511 /* Return operations error. */
512 err = LDAP_OPERATIONS_ERROR;
513 goto Cleanup;
516 err = berDecodeLoginData(replyBV, &serverVersion, NULL, NULL);
518 if(serverVersion != NMAS_LDAP_EXT_VERSION)
520 err = LDAP_OPERATIONS_ERROR;
521 goto Cleanup;
524 Cleanup:
526 if(replyBV)
528 ber_bvfree(replyBV);
531 /* Free the return OID string if one was returned. */
532 if(replyOID)
534 ldap_memfree(replyOID);
537 /* Free memory allocated while building the request ber and berval. */
538 if(requestBV)
540 ber_bvfree(requestBV);
543 /* Return the appropriate error/success code. */
544 return err;
547 /**********************************************************************
548 Attempts to get the Universal Password
549 **********************************************************************/
551 static int nmasldap_get_password(
552 LDAP *ld,
553 char *objectDN,
554 size_t *pwdSize, /* in bytes */
555 unsigned char *pwd )
557 int err = 0;
559 struct berval *requestBV = NULL;
560 char *replyOID = NULL;
561 struct berval *replyBV = NULL;
562 int serverVersion;
563 char *pwdBuf;
564 size_t pwdBufLen, bufferLen;
566 /* Validate char parameters. */
567 if(objectDN == NULL || (strlen(objectDN) == 0) || pwdSize == NULL || ld == NULL)
569 return LDAP_NO_SUCH_ATTRIBUTE;
572 bufferLen = pwdBufLen = *pwdSize;
573 pwdBuf = SMB_MALLOC_ARRAY(char, pwdBufLen+2);
574 if(pwdBuf == NULL)
576 return LDAP_NO_MEMORY;
579 err = berEncodePasswordData(&requestBV, objectDN, NULL, NULL);
580 if(err)
582 goto Cleanup;
585 /* Call the ldap_extended_operation (synchronously) */
586 if((err = ldap_extended_operation_s(ld, NMASLDAP_GET_PASSWORD_REQUEST, requestBV, NULL, NULL, &replyOID, &replyBV)))
588 goto Cleanup;
591 /* Make sure there is a return OID */
592 if(!replyOID)
594 err = LDAP_NOT_SUPPORTED;
595 goto Cleanup;
598 /* Is this what we were expecting to get back. */
599 if(strcmp(replyOID, NMASLDAP_GET_PASSWORD_RESPONSE))
601 err = LDAP_NOT_SUPPORTED;
602 goto Cleanup;
605 /* Do we have a good returned berval? */
606 if(!replyBV)
608 /* No; returned berval means we experienced a rather drastic error. */
609 /* Return operations error. */
610 err = LDAP_OPERATIONS_ERROR;
611 goto Cleanup;
614 err = berDecodeLoginData(replyBV, &serverVersion, &pwdBufLen, pwdBuf);
616 if(serverVersion != NMAS_LDAP_EXT_VERSION)
618 err = LDAP_OPERATIONS_ERROR;
619 goto Cleanup;
622 if (!err && pwdBufLen != 0)
624 if (*pwdSize >= pwdBufLen+1 && pwd != NULL)
626 memcpy(pwd, pwdBuf, pwdBufLen);
627 pwd[pwdBufLen] = 0; /* add null termination */
629 *pwdSize = pwdBufLen; /* does not include null termination */
632 Cleanup:
634 if(replyBV)
636 ber_bvfree(replyBV);
639 /* Free the return OID string if one was returned. */
640 if(replyOID)
642 ldap_memfree(replyOID);
645 /* Free memory allocated while building the request ber and berval. */
646 if(requestBV)
648 ber_bvfree(requestBV);
651 if (pwdBuf != NULL)
653 memset(pwdBuf, 0, bufferLen);
654 free(pwdBuf);
657 /* Return the appropriate error/success code. */
658 return err;
661 /**********************************************************************
662 Get the user's password from NDS.
663 *********************************************************************/
665 int pdb_nds_get_password(
666 struct smbldap_state *ldap_state,
667 char *object_dn,
668 size_t *pwd_len,
669 char *pwd )
671 LDAP *ld = ldap_state->ldap_struct;
672 int rc = -1;
674 rc = nmasldap_get_password(ld, object_dn, pwd_len, (unsigned char *)pwd);
675 if (rc == LDAP_SUCCESS) {
676 #ifdef DEBUG_PASSWORD
677 DEBUG(100,("nmasldap_get_password returned %s for %s\n", pwd, object_dn));
678 #endif
679 DEBUG(5, ("NDS Universal Password retrieved for %s\n", object_dn));
680 } else {
681 DEBUG(3, ("NDS Universal Password NOT retrieved for %s\n", object_dn));
684 if (rc != LDAP_SUCCESS) {
685 rc = nmasldap_get_simple_pwd(ld, object_dn, *pwd_len, pwd);
686 if (rc == LDAP_SUCCESS) {
687 #ifdef DEBUG_PASSWORD
688 DEBUG(100,("nmasldap_get_simple_pwd returned %s for %s\n", pwd, object_dn));
689 #endif
690 DEBUG(5, ("NDS Simple Password retrieved for %s\n", object_dn));
691 } else {
692 /* We couldn't get the password */
693 DEBUG(3, ("NDS Simple Password NOT retrieved for %s\n", object_dn));
694 return LDAP_INVALID_CREDENTIALS;
698 /* We got the password */
699 return LDAP_SUCCESS;
702 /**********************************************************************
703 Set the users NDS, Universal and Simple passwords.
704 ********************************************************************/
706 int pdb_nds_set_password(
707 struct smbldap_state *ldap_state,
708 char *object_dn,
709 const char *pwd )
711 LDAP *ld = ldap_state->ldap_struct;
712 int rc = -1;
713 LDAPMod **tmpmods = NULL;
715 rc = nmasldap_set_password(ld, object_dn, pwd);
716 if (rc == LDAP_SUCCESS) {
717 DEBUG(5,("NDS Universal Password changed for user %s\n", object_dn));
718 } else {
719 char *ld_error = NULL;
720 ldap_get_option(ld, LDAP_OPT_ERROR_STRING, &ld_error);
722 /* This will fail if Universal Password is not enabled for the user's context */
723 DEBUG(3,("NDS Universal Password could not be changed for user %s: %s (%s)\n",
724 object_dn, ldap_err2string(rc), ld_error?ld_error:"unknown"));
725 SAFE_FREE(ld_error);
728 /* Set eDirectory Password */
729 smbldap_set_mod(&tmpmods, LDAP_MOD_REPLACE, "userPassword", pwd);
730 rc = smbldap_modify(ldap_state, object_dn, tmpmods);
732 return rc;
735 /**********************************************************************
736 Allow ldap server to update internal login attempt counters by
737 performing a simple bind. If the samba authentication failed attempt
738 the bind with a bogus, randomly generated password to count the
739 failed attempt. If the bind fails even though samba authentication
740 succeeded, this would indicate that the user's account is disabled,
741 time restrictions are in place or some other password policy
742 violation.
743 *********************************************************************/
745 static NTSTATUS pdb_nds_update_login_attempts(struct pdb_methods *methods,
746 struct samu *sam_acct, bool success)
748 struct ldapsam_privates *ldap_state;
750 if ((!methods) || (!sam_acct)) {
751 DEBUG(3,("pdb_nds_update_login_attempts: invalid parameter.\n"));
752 return NT_STATUS_MEMORY_NOT_ALLOCATED;
755 ldap_state = (struct ldapsam_privates *)methods->private_data;
757 if (ldap_state) {
758 /* Attempt simple bind with user credentials to update eDirectory
759 password policy */
760 int rc = 0;
761 char *dn;
762 LDAPMessage *result = NULL;
763 LDAPMessage *entry = NULL;
764 const char **attr_list;
765 size_t pwd_len;
766 char clear_text_pw[512];
767 LDAP *ld = NULL;
768 const char *username = pdb_get_username(sam_acct);
769 bool got_clear_text_pw = False;
771 DEBUG(5,("pdb_nds_update_login_attempts: %s login for %s\n",
772 success ? "Successful" : "Failed", username));
774 result = (LDAPMessage *)pdb_get_backend_private_data(sam_acct, methods);
775 if (!result) {
776 attr_list = get_userattr_list(NULL,
777 ldap_state->schema_ver);
778 rc = ldapsam_search_suffix_by_name(ldap_state, username, &result, attr_list );
779 TALLOC_FREE( attr_list );
780 if (rc != LDAP_SUCCESS) {
781 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
783 pdb_set_backend_private_data(sam_acct, result, NULL,
784 methods, PDB_CHANGED);
785 smbldap_talloc_autofree_ldapmsg(sam_acct, result);
788 if (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result) == 0) {
789 DEBUG(0, ("pdb_nds_update_login_attempts: No user to modify!\n"));
790 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
793 entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, result);
794 dn = smbldap_talloc_dn(talloc_tos(), ldap_state->smbldap_state->ldap_struct, entry);
795 if (!dn) {
796 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
799 DEBUG(3, ("pdb_nds_update_login_attempts: username %s found dn '%s'\n", username, dn));
801 pwd_len = sizeof(clear_text_pw);
802 if (success == True) {
803 if (pdb_nds_get_password(ldap_state->smbldap_state, dn, &pwd_len, clear_text_pw) == LDAP_SUCCESS) {
804 /* Got clear text password. Use simple ldap bind */
805 got_clear_text_pw = True;
807 } else {
808 generate_random_buffer((unsigned char *)clear_text_pw, 24);
809 clear_text_pw[24] = '\0';
810 DEBUG(5,("pdb_nds_update_login_attempts: using random password %s\n", clear_text_pw));
813 if((success != True) || (got_clear_text_pw == True)) {
815 rc = smbldap_setup_full_conn(&ld, ldap_state->location);
816 if (rc) {
817 TALLOC_FREE(dn);
818 return NT_STATUS_INVALID_CONNECTION;
821 /* Attempt simple bind with real or bogus password */
822 rc = ldap_simple_bind_s(ld, dn, clear_text_pw);
823 ldap_unbind(ld);
824 if (rc == LDAP_SUCCESS) {
825 DEBUG(5,("pdb_nds_update_login_attempts: ldap_simple_bind_s Successful for %s\n", username));
826 } else {
827 NTSTATUS nt_status = NT_STATUS_ACCOUNT_RESTRICTION;
828 DEBUG(5,("pdb_nds_update_login_attempts: ldap_simple_bind_s Failed for %s\n", username));
829 switch(rc) {
830 case LDAP_INVALID_CREDENTIALS:
831 nt_status = NT_STATUS_WRONG_PASSWORD;
832 break;
833 case LDAP_UNWILLING_TO_PERFORM:
834 /* eDir returns this if the account was disabled. */
835 /* The problem is we don't know if the given
836 password was correct for this account or
837 not. We have to return more info than we
838 should and tell the client NT_STATUS_ACCOUNT_DISABLED
839 so they don't think the password was bad. JRA. */
840 nt_status = NT_STATUS_ACCOUNT_DISABLED;
841 break;
842 default:
843 break;
845 return nt_status;
848 TALLOC_FREE(dn);
851 return NT_STATUS_OK;
854 /**********************************************************************
855 Intitalise the parts of the pdb_methods structuire that are common
856 to NDS_ldapsam modes
857 *********************************************************************/
859 static NTSTATUS pdb_init_NDS_ldapsam_common(struct pdb_methods **pdb_method, const char *location)
861 struct ldapsam_privates *ldap_state =
862 (struct ldapsam_privates *)((*pdb_method)->private_data);
864 /* Mark this as eDirectory ldap */
865 ldap_state->is_nds_ldap = True;
867 /* Add pdb_nds specific method for updating login attempts. */
868 (*pdb_method)->update_login_attempts = pdb_nds_update_login_attempts;
870 /* Save location for use in pdb_nds_update_login_attempts */
871 ldap_state->location = SMB_STRDUP(location);
873 return NT_STATUS_OK;
876 /**********************************************************************
877 Initialise the 'nds' normal mode for pdb_ldap
878 *********************************************************************/
880 static NTSTATUS pdb_init_NDS_ldapsam(struct pdb_methods **pdb_method, const char *location)
882 NTSTATUS nt_status = pdb_init_ldapsam(pdb_method, location);
884 (*pdb_method)->name = "NDS_ldapsam";
886 pdb_init_NDS_ldapsam_common(pdb_method, location);
888 return nt_status;
891 NTSTATUS pdb_nds_init(void)
893 NTSTATUS nt_status;
894 if (!NT_STATUS_IS_OK(nt_status = smb_register_passdb(PASSDB_INTERFACE_VERSION, "NDS_ldapsam", pdb_init_NDS_ldapsam)))
895 return nt_status;
897 return NT_STATUS_OK;