s3:registry: add a new function regval_ctr_value_byname()
[Samba.git] / source3 / passdb / pdb_nds.c
blob56375a813f621a6a095b278f52577753d8443d9a
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"
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"
37 #define NMAS_LDAP_EXT_VERSION 1
39 /**********************************************************************
40 Take the request BER value and input data items and BER encodes the
41 data into the BER value
42 **********************************************************************/
44 static int berEncodePasswordData(
45 struct berval **requestBV,
46 const char *objectDN,
47 const char *password,
48 const char *password2)
50 int err = 0, rc=0;
51 BerElement *requestBer = NULL;
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;
61 /* Convert objectDN and tag strings from Unicode to UTF-8 */
62 utf8ObjSize = strlen(objectDN)+1;
63 utf8ObjPtr = objectDN;
65 if (password != NULL)
67 utf8PwdSize = strlen(password)+1;
68 utf8PwdPtr = password;
71 if (password2 != NULL)
73 utf8Pwd2Size = strlen(password2)+1;
74 utf8Pwd2Ptr = password2;
77 /* Allocate a BerElement for the request parameters. */
78 if((requestBer = ber_alloc()) == NULL)
80 err = LDAP_ENCODING_ERROR;
81 goto Cleanup;
84 if (password != NULL && password2 != NULL)
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);
89 else if (password != NULL)
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);
94 else
96 /* BER encode the NMAS Version and the objectDN */
97 rc = ber_printf(requestBer, "{io}", NMAS_LDAP_EXT_VERSION, utf8ObjPtr, utf8ObjSize);
100 if (rc < 0)
102 err = LDAP_ENCODING_ERROR;
103 goto Cleanup;
105 else
107 err = 0;
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)
113 err = LDAP_ENCODING_ERROR;
114 goto Cleanup;
117 Cleanup:
119 if(requestBer)
121 ber_free(requestBer, 1);
124 return err;
127 /**********************************************************************
128 Take the request BER value and input data items and BER encodes the
129 data into the BER value
130 **********************************************************************/
132 static 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)
141 int err = 0;
142 BerElement *requestBer = NULL;
144 unsigned int i;
145 unsigned int elemCnt = methodIDLen / sizeof(unsigned int);
147 char *utf8ObjPtr=NULL;
148 int utf8ObjSize = 0;
150 char *utf8TagPtr = NULL;
151 int utf8TagSize = 0;
153 utf8ObjPtr = objectDN;
154 utf8ObjSize = strlen(utf8ObjPtr)+1;
156 utf8TagPtr = tag;
157 utf8TagSize = strlen(utf8TagPtr)+1;
159 /* Allocate a BerElement for the request parameters. */
160 if((requestBer = ber_alloc()) == NULL)
162 err = LDAP_ENCODING_ERROR;
163 goto Cleanup;
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;
169 /* BER encode the MethodID Length and value */
170 if (!err)
172 err = (ber_printf(requestBer, "{i{", methodIDLen) < 0) ? LDAP_ENCODING_ERROR : 0;
175 for (i = 0; !err && i < elemCnt; i++)
177 err = (ber_printf(requestBer, "i", methodID[i]) < 0) ? LDAP_ENCODING_ERROR : 0;
180 if (!err)
182 err = (ber_printf(requestBer, "}}", 0) < 0) ? LDAP_ENCODING_ERROR : 0;
185 if(putData)
187 /* BER Encode the the tag and data */
188 err = (ber_printf(requestBer, "oio}", utf8TagPtr, utf8TagSize, putDataLen, putData, putDataLen) < 0) ? LDAP_ENCODING_ERROR : 0;
190 else
192 /* BER Encode the the tag */
193 err = (ber_printf(requestBer, "o}", utf8TagPtr, utf8TagSize) < 0) ? LDAP_ENCODING_ERROR : 0;
196 if (err)
198 goto Cleanup;
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)
204 err = LDAP_ENCODING_ERROR;
205 goto Cleanup;
208 Cleanup:
210 if(requestBer)
212 ber_free(requestBer, 1);
215 return err;
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 **********************************************************************/
224 static int berDecodeLoginData(
225 struct berval *replyBV,
226 int *serverVersion,
227 size_t *retDataLen,
228 void *retData )
230 int err = 0;
231 BerElement *replyBer = NULL;
232 char *retOctStr = NULL;
233 size_t retOctStrLen = 0;
235 if((replyBer = ber_init(replyBV)) == NULL)
237 err = LDAP_OPERATIONS_ERROR;
238 goto Cleanup;
241 if(retData)
243 retOctStrLen = *retDataLen + 1;
244 retOctStr = SMB_MALLOC_ARRAY(char, retOctStrLen);
245 if(!retOctStr)
247 err = LDAP_OPERATIONS_ERROR;
248 goto Cleanup;
251 if(ber_scanf(replyBer, "{iis}", serverVersion, &err, retOctStr, &retOctStrLen) != -1)
253 if (*retDataLen >= retOctStrLen)
255 memcpy(retData, retOctStr, retOctStrLen);
257 else if (!err)
259 err = LDAP_NO_MEMORY;
262 *retDataLen = retOctStrLen;
264 else if (!err)
266 err = LDAP_DECODING_ERROR;
269 else
271 if(ber_scanf(replyBer, "{ii}", serverVersion, &err) == -1)
273 if (!err)
275 err = LDAP_DECODING_ERROR;
280 Cleanup:
282 if(replyBer)
284 ber_free(replyBer, 1);
287 if (retOctStr != NULL)
289 memset(retOctStr, 0, retOctStrLen);
290 free(retOctStr);
293 return err;
296 /**********************************************************************
297 Retrieves data in the login configuration of the specified object
298 that is tagged with the specified methodID and tag.
299 **********************************************************************/
301 static 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 )
310 int err = 0;
311 struct berval *requestBV = NULL;
312 char *replyOID = NULL;
313 struct berval *replyBV = NULL;
314 int serverVersion = 0;
316 /* Validate unicode parameters. */
317 if((strlen(objectDN) == 0) || ld == NULL)
319 return LDAP_NO_SUCH_ATTRIBUTE;
322 err = berEncodeLoginData(&requestBV, objectDN, methodIDLen, methodID, tag, 0, NULL);
323 if(err)
325 goto Cleanup;
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)))
332 goto Cleanup;
335 /* Make sure there is a return OID */
336 if(!replyOID)
338 err = LDAP_NOT_SUPPORTED;
339 goto Cleanup;
342 /* Is this what we were expecting to get back. */
343 if(strcmp(replyOID, NMASLDAP_GET_LOGIN_CONFIG_RESPONSE))
345 err = LDAP_NOT_SUPPORTED;
346 goto Cleanup;
349 /* Do we have a good returned berval? */
350 if(!replyBV)
352 /* No; returned berval means we experienced a rather drastic error. */
353 /* Return operations error. */
354 err = LDAP_OPERATIONS_ERROR;
355 goto Cleanup;
358 err = berDecodeLoginData(replyBV, &serverVersion, dataLen, data);
360 if(serverVersion != NMAS_LDAP_EXT_VERSION)
362 err = LDAP_OPERATIONS_ERROR;
363 goto Cleanup;
366 Cleanup:
368 if(replyBV)
370 ber_bvfree(replyBV);
373 /* Free the return OID string if one was returned. */
374 if(replyOID)
376 ldap_memfree(replyOID);
379 /* Free memory allocated while building the request ber and berval. */
380 if(requestBV)
382 ber_bvfree(requestBV);
385 /* Return the appropriate error/success code. */
386 return err;
389 /**********************************************************************
390 Attempts to get the Simple Password
391 **********************************************************************/
393 static int nmasldap_get_simple_pwd(
394 LDAP *ld,
395 char *objectDN,
396 size_t pwdLen,
397 char *pwd )
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;
406 bufferLen = pwdBufLen = pwdLen+2;
407 pwdBuf = SMB_MALLOC_ARRAY(char, pwdBufLen); /* digest and null */
408 if(pwdBuf == NULL)
410 return LDAP_NO_MEMORY;
413 err = getLoginConfig(ld, objectDN, methodIDLen, &methodID, tag, &pwdBufLen, pwdBuf);
414 if (err == 0)
416 if (pwdBufLen !=0)
418 pwdBuf[pwdBufLen] = 0; /* null terminate */
420 switch (pwdBuf[0])
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;
433 if (!err)
435 if (pwdLen >= pwdBufLen-1)
437 memcpy(pwd, &pwdBuf[1], pwdBufLen-1); /* skip digest tag and include null */
439 else
441 err = LDAP_NO_MEMORY;
447 if (pwdBuf != NULL)
449 memset(pwdBuf, 0, bufferLen);
450 free(pwdBuf);
453 return err;
457 /**********************************************************************
458 Attempts to set the Universal Password
459 **********************************************************************/
461 static int nmasldap_set_password(
462 LDAP *ld,
463 const char *objectDN,
464 const char *pwd )
466 int err = 0;
468 struct berval *requestBV = NULL;
469 char *replyOID = NULL;
470 struct berval *replyBV = NULL;
471 int serverVersion;
473 /* Validate char parameters. */
474 if(objectDN == NULL || (strlen(objectDN) == 0) || pwd == NULL || ld == NULL)
476 return LDAP_NO_SUCH_ATTRIBUTE;
479 err = berEncodePasswordData(&requestBV, objectDN, pwd, NULL);
480 if(err)
482 goto Cleanup;
485 /* Call the ldap_extended_operation (synchronously) */
486 if((err = ldap_extended_operation_s(ld, NMASLDAP_SET_PASSWORD_REQUEST, requestBV, NULL, NULL, &replyOID, &replyBV)))
488 goto Cleanup;
491 /* Make sure there is a return OID */
492 if(!replyOID)
494 err = LDAP_NOT_SUPPORTED;
495 goto Cleanup;
498 /* Is this what we were expecting to get back. */
499 if(strcmp(replyOID, NMASLDAP_SET_PASSWORD_RESPONSE))
501 err = LDAP_NOT_SUPPORTED;
502 goto Cleanup;
505 /* Do we have a good returned berval? */
506 if(!replyBV)
508 /* No; returned berval means we experienced a rather drastic error. */
509 /* Return operations error. */
510 err = LDAP_OPERATIONS_ERROR;
511 goto Cleanup;
514 err = berDecodeLoginData(replyBV, &serverVersion, NULL, NULL);
516 if(serverVersion != NMAS_LDAP_EXT_VERSION)
518 err = LDAP_OPERATIONS_ERROR;
519 goto Cleanup;
522 Cleanup:
524 if(replyBV)
526 ber_bvfree(replyBV);
529 /* Free the return OID string if one was returned. */
530 if(replyOID)
532 ldap_memfree(replyOID);
535 /* Free memory allocated while building the request ber and berval. */
536 if(requestBV)
538 ber_bvfree(requestBV);
541 /* Return the appropriate error/success code. */
542 return err;
545 /**********************************************************************
546 Attempts to get the Universal Password
547 **********************************************************************/
549 static int nmasldap_get_password(
550 LDAP *ld,
551 char *objectDN,
552 size_t *pwdSize, /* in bytes */
553 unsigned char *pwd )
555 int err = 0;
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;
564 /* Validate char parameters. */
565 if(objectDN == NULL || (strlen(objectDN) == 0) || pwdSize == NULL || ld == NULL)
567 return LDAP_NO_SUCH_ATTRIBUTE;
570 bufferLen = pwdBufLen = *pwdSize;
571 pwdBuf = SMB_MALLOC_ARRAY(char, pwdBufLen+2);
572 if(pwdBuf == NULL)
574 return LDAP_NO_MEMORY;
577 err = berEncodePasswordData(&requestBV, objectDN, NULL, NULL);
578 if(err)
580 goto Cleanup;
583 /* Call the ldap_extended_operation (synchronously) */
584 if((err = ldap_extended_operation_s(ld, NMASLDAP_GET_PASSWORD_REQUEST, requestBV, NULL, NULL, &replyOID, &replyBV)))
586 goto Cleanup;
589 /* Make sure there is a return OID */
590 if(!replyOID)
592 err = LDAP_NOT_SUPPORTED;
593 goto Cleanup;
596 /* Is this what we were expecting to get back. */
597 if(strcmp(replyOID, NMASLDAP_GET_PASSWORD_RESPONSE))
599 err = LDAP_NOT_SUPPORTED;
600 goto Cleanup;
603 /* Do we have a good returned berval? */
604 if(!replyBV)
606 /* No; returned berval means we experienced a rather drastic error. */
607 /* Return operations error. */
608 err = LDAP_OPERATIONS_ERROR;
609 goto Cleanup;
612 err = berDecodeLoginData(replyBV, &serverVersion, &pwdBufLen, pwdBuf);
614 if(serverVersion != NMAS_LDAP_EXT_VERSION)
616 err = LDAP_OPERATIONS_ERROR;
617 goto Cleanup;
620 if (!err && pwdBufLen != 0)
622 if (*pwdSize >= pwdBufLen+1 && pwd != NULL)
624 memcpy(pwd, pwdBuf, pwdBufLen);
625 pwd[pwdBufLen] = 0; /* add null termination */
627 *pwdSize = pwdBufLen; /* does not include null termination */
630 Cleanup:
632 if(replyBV)
634 ber_bvfree(replyBV);
637 /* Free the return OID string if one was returned. */
638 if(replyOID)
640 ldap_memfree(replyOID);
643 /* Free memory allocated while building the request ber and berval. */
644 if(requestBV)
646 ber_bvfree(requestBV);
649 if (pwdBuf != NULL)
651 memset(pwdBuf, 0, bufferLen);
652 free(pwdBuf);
655 /* Return the appropriate error/success code. */
656 return err;
659 /**********************************************************************
660 Get the user's password from NDS.
661 *********************************************************************/
663 int pdb_nds_get_password(
664 struct smbldap_state *ldap_state,
665 char *object_dn,
666 size_t *pwd_len,
667 char *pwd )
669 LDAP *ld = ldap_state->ldap_struct;
670 int rc = -1;
672 rc = nmasldap_get_password(ld, object_dn, pwd_len, (unsigned char *)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));
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;
696 /* We got the password */
697 return LDAP_SUCCESS;
700 /**********************************************************************
701 Set the users NDS, Universal and Simple passwords.
702 ********************************************************************/
704 int pdb_nds_set_password(
705 struct smbldap_state *ldap_state,
706 char *object_dn,
707 const char *pwd )
709 LDAP *ld = ldap_state->ldap_struct;
710 int rc = -1;
711 LDAPMod **tmpmods = NULL;
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 char *ld_error = NULL;
718 ldap_get_option(ld, LDAP_OPT_ERROR_STRING, &ld_error);
720 /* This will fail if Universal Password is not enabled for the user's context */
721 DEBUG(3,("NDS Universal Password could not be changed for user %s: %s (%s)\n",
722 object_dn, ldap_err2string(rc), ld_error?ld_error:"unknown"));
723 SAFE_FREE(ld_error);
726 /* Set eDirectory Password */
727 smbldap_set_mod(&tmpmods, LDAP_MOD_REPLACE, "userPassword", pwd);
728 rc = smbldap_modify(ldap_state, object_dn, tmpmods);
730 return rc;
733 /**********************************************************************
734 Allow ldap server to update internal login attempt counters by
735 performing a simple bind. If the samba authentication failed attempt
736 the bind with a bogus, randomly generated password to count the
737 failed attempt. If the bind fails even though samba authentication
738 succeeded, this would indicate that the user's account is disabled,
739 time restrictions are in place or some other password policy
740 violation.
741 *********************************************************************/
743 static NTSTATUS pdb_nds_update_login_attempts(struct pdb_methods *methods,
744 struct samu *sam_acct, bool success)
746 struct ldapsam_privates *ldap_state;
748 if ((!methods) || (!sam_acct)) {
749 DEBUG(3,("pdb_nds_update_login_attempts: invalid parameter.\n"));
750 return NT_STATUS_MEMORY_NOT_ALLOCATED;
753 ldap_state = (struct ldapsam_privates *)methods->private_data;
755 if (ldap_state) {
756 /* Attempt simple bind with user credentials to update eDirectory
757 password policy */
758 int rc = 0;
759 char *dn;
760 LDAPMessage *result = NULL;
761 LDAPMessage *entry = NULL;
762 const char **attr_list;
763 size_t pwd_len;
764 char clear_text_pw[512];
765 LDAP *ld = NULL;
766 const char *username = pdb_get_username(sam_acct);
767 bool got_clear_text_pw = False;
769 DEBUG(5,("pdb_nds_update_login_attempts: %s login for %s\n",
770 success ? "Successful" : "Failed", username));
772 result = (LDAPMessage *)pdb_get_backend_private_data(sam_acct, methods);
773 if (!result) {
774 attr_list = get_userattr_list(NULL,
775 ldap_state->schema_ver);
776 rc = ldapsam_search_suffix_by_name(ldap_state, username, &result, attr_list );
777 TALLOC_FREE( attr_list );
778 if (rc != LDAP_SUCCESS) {
779 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
781 pdb_set_backend_private_data(sam_acct, result, NULL,
782 methods, PDB_CHANGED);
783 talloc_autofree_ldapmsg(sam_acct, result);
786 if (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result) == 0) {
787 DEBUG(0, ("pdb_nds_update_login_attempts: No user to modify!\n"));
788 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
791 entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, result);
792 dn = smbldap_talloc_dn(talloc_tos(), ldap_state->smbldap_state->ldap_struct, entry);
793 if (!dn) {
794 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
797 DEBUG(3, ("pdb_nds_update_login_attempts: username %s found dn '%s'\n", username, dn));
799 pwd_len = sizeof(clear_text_pw);
800 if (success == True) {
801 if (pdb_nds_get_password(ldap_state->smbldap_state, dn, &pwd_len, clear_text_pw) == LDAP_SUCCESS) {
802 /* Got clear text password. Use simple ldap bind */
803 got_clear_text_pw = True;
805 } else {
806 generate_random_buffer((unsigned char *)clear_text_pw, 24);
807 clear_text_pw[24] = '\0';
808 DEBUG(5,("pdb_nds_update_login_attempts: using random password %s\n", clear_text_pw));
811 if((success != True) || (got_clear_text_pw == True)) {
813 rc = smb_ldap_setup_full_conn(&ld, ldap_state->location);
814 if (rc) {
815 TALLOC_FREE(dn);
816 return NT_STATUS_INVALID_CONNECTION;
819 /* Attempt simple bind with real or bogus password */
820 rc = ldap_simple_bind_s(ld, dn, clear_text_pw);
821 ldap_unbind(ld);
822 if (rc == LDAP_SUCCESS) {
823 DEBUG(5,("pdb_nds_update_login_attempts: ldap_simple_bind_s Successful for %s\n", username));
824 } else {
825 NTSTATUS nt_status = NT_STATUS_ACCOUNT_RESTRICTION;
826 DEBUG(5,("pdb_nds_update_login_attempts: ldap_simple_bind_s Failed for %s\n", username));
827 switch(rc) {
828 case LDAP_INVALID_CREDENTIALS:
829 nt_status = NT_STATUS_WRONG_PASSWORD;
830 break;
831 case LDAP_UNWILLING_TO_PERFORM:
832 /* eDir returns this if the account was disabled. */
833 /* The problem is we don't know if the given
834 password was correct for this account or
835 not. We have to return more info than we
836 should and tell the client NT_STATUS_ACCOUNT_DISABLED
837 so they don't think the password was bad. JRA. */
838 nt_status = NT_STATUS_ACCOUNT_DISABLED;
839 break;
840 default:
841 break;
843 return nt_status;
846 TALLOC_FREE(dn);
849 return NT_STATUS_OK;
852 /**********************************************************************
853 Intitalise the parts of the pdb_methods structuire that are common
854 to NDS_ldapsam modes
855 *********************************************************************/
857 static NTSTATUS pdb_init_NDS_ldapsam_common(struct pdb_methods **pdb_method, const char *location)
859 struct ldapsam_privates *ldap_state =
860 (struct ldapsam_privates *)((*pdb_method)->private_data);
862 /* Mark this as eDirectory ldap */
863 ldap_state->is_nds_ldap = True;
865 /* Add pdb_nds specific method for updating login attempts. */
866 (*pdb_method)->update_login_attempts = pdb_nds_update_login_attempts;
868 /* Save location for use in pdb_nds_update_login_attempts */
869 ldap_state->location = SMB_STRDUP(location);
871 return NT_STATUS_OK;
875 /**********************************************************************
876 Initialise the 'nds compat' mode for pdb_ldap
877 *********************************************************************/
879 static NTSTATUS pdb_init_NDS_ldapsam_compat(struct pdb_methods **pdb_method, const char *location)
881 NTSTATUS nt_status = pdb_init_ldapsam_compat(pdb_method, location);
883 (*pdb_method)->name = "NDS_ldapsam_compat";
885 pdb_init_NDS_ldapsam_common(pdb_method, location);
887 return nt_status;
891 /**********************************************************************
892 Initialise the 'nds' normal mode for pdb_ldap
893 *********************************************************************/
895 static NTSTATUS pdb_init_NDS_ldapsam(struct pdb_methods **pdb_method, const char *location)
897 NTSTATUS nt_status = pdb_init_ldapsam(pdb_method, location);
899 (*pdb_method)->name = "NDS_ldapsam";
901 pdb_init_NDS_ldapsam_common(pdb_method, location);
903 return nt_status;
906 NTSTATUS pdb_nds_init(void)
908 NTSTATUS nt_status;
909 if (!NT_STATUS_IS_OK(nt_status = smb_register_passdb(PASSDB_INTERFACE_VERSION, "NDS_ldapsam", pdb_init_NDS_ldapsam)))
910 return nt_status;
912 if (!NT_STATUS_IS_OK(nt_status = smb_register_passdb(PASSDB_INTERFACE_VERSION, "NDS_ldapsam_compat", pdb_init_NDS_ldapsam_compat)))
913 return nt_status;
915 return NT_STATUS_OK;