source: branches/samba-3.2.x/source/passdb/pdb_nds.c

Last change on this file was 133, checked in by Paul Smedley, 17 years ago

Update trunk to 3.2.0pre3

File size: 22.6 KB
Line 
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
43static int berEncodePasswordData(
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
116Cleanup:
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
131static int berEncodeLoginData(
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
207Cleanup:
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
223static int berDecodeLoginData(
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
279Cleanup:
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
300static int getLoginConfig(
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
365Cleanup:
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
392static int nmasldap_get_simple_pwd(
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
460static int nmasldap_set_password(
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
521Cleanup:
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
548static int nmasldap_get_password(
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
629Cleanup:
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
662int pdb_nds_get_password(
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
703int pdb_nds_set_password(
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
742static NTSTATUS pdb_nds_update_login_attempts(struct pdb_methods *methods,
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_get_dn(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 return NT_STATUS_INVALID_CONNECTION;
815 }
816
817 /* Attempt simple bind with real or bogus password */
818 rc = ldap_simple_bind_s(ld, dn, clear_text_pw);
819 ldap_unbind(ld);
820 if (rc == LDAP_SUCCESS) {
821 DEBUG(5,("pdb_nds_update_login_attempts: ldap_simple_bind_s Successful for %s\n", username));
822 } else {
823 NTSTATUS nt_status = NT_STATUS_ACCOUNT_RESTRICTION;
824 DEBUG(5,("pdb_nds_update_login_attempts: ldap_simple_bind_s Failed for %s\n", username));
825 switch(rc) {
826 case LDAP_INVALID_CREDENTIALS:
827 nt_status = NT_STATUS_WRONG_PASSWORD;
828 break;
829 case LDAP_UNWILLING_TO_PERFORM:
830 /* eDir returns this if the account was disabled. */
831 /* The problem is we don't know if the given
832 password was correct for this account or
833 not. We have to return more info than we
834 should and tell the client NT_STATUS_ACCOUNT_DISABLED
835 so they don't think the password was bad. JRA. */
836 nt_status = NT_STATUS_ACCOUNT_DISABLED;
837 break;
838 default:
839 break;
840 }
841 return nt_status;
842 }
843 }
844 }
845
846 return NT_STATUS_OK;
847}
848
849/**********************************************************************
850 Intitalise the parts of the pdb_methods structuire that are common
851 to NDS_ldapsam modes
852 *********************************************************************/
853
854static NTSTATUS pdb_init_NDS_ldapsam_common(struct pdb_methods **pdb_method, const char *location)
855{
856 struct ldapsam_privates *ldap_state =
857 (struct ldapsam_privates *)((*pdb_method)->private_data);
858
859 /* Mark this as eDirectory ldap */
860 ldap_state->is_nds_ldap = True;
861
862 /* Add pdb_nds specific method for updating login attempts. */
863 (*pdb_method)->update_login_attempts = pdb_nds_update_login_attempts;
864
865 /* Save location for use in pdb_nds_update_login_attempts */
866 ldap_state->location = SMB_STRDUP(location);
867
868 return NT_STATUS_OK;
869}
870
871
872/**********************************************************************
873 Initialise the 'nds compat' mode for pdb_ldap
874 *********************************************************************/
875
876static NTSTATUS pdb_init_NDS_ldapsam_compat(struct pdb_methods **pdb_method, const char *location)
877{
878 NTSTATUS nt_status = pdb_init_ldapsam_compat(pdb_method, location);
879
880 (*pdb_method)->name = "NDS_ldapsam_compat";
881
882 pdb_init_NDS_ldapsam_common(pdb_method, location);
883
884 return nt_status;
885}
886
887
888/**********************************************************************
889 Initialise the 'nds' normal mode for pdb_ldap
890 *********************************************************************/
891
892static NTSTATUS pdb_init_NDS_ldapsam(struct pdb_methods **pdb_method, const char *location)
893{
894 NTSTATUS nt_status = pdb_init_ldapsam(pdb_method, location);
895
896 (*pdb_method)->name = "NDS_ldapsam";
897
898 pdb_init_NDS_ldapsam_common(pdb_method, location);
899
900 return nt_status;
901}
902
903NTSTATUS pdb_nds_init(void)
904{
905 NTSTATUS nt_status;
906 if (!NT_STATUS_IS_OK(nt_status = smb_register_passdb(PASSDB_INTERFACE_VERSION, "NDS_ldapsam", pdb_init_NDS_ldapsam)))
907 return nt_status;
908
909 if (!NT_STATUS_IS_OK(nt_status = smb_register_passdb(PASSDB_INTERFACE_VERSION, "NDS_ldapsam_compat", pdb_init_NDS_ldapsam_compat)))
910 return nt_status;
911
912 return NT_STATUS_OK;
913}
Note: See TracBrowser for help on using the repository browser.