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