2 * NDS LDAP helper functions
3 * Copied From Samba-3.0.24 pdb_nds.c and trimmed down to the
4 * limited functionality needed to access the plain text password only
6 * Original copyright & license follows:
8 * Copyright (C) Vince Brimhall 2004-2005
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #include "digest_common.h"
29 #if _SQUID_MSWIN_ /* Native Windows port and MinGW */
31 #define snprintf _snprintf
36 #define LDAPAPI __cdecl
39 #ifndef LDAP_OPT_X_TLS
40 #define LDAP_OPT_X_TLS 0x6000
42 #define ber_alloc() ber_alloc_t(0)
43 #endif /* LDAP_VERSION3 */
53 #include "edir_ldapext.h"
55 #define NMASLDAP_GET_LOGIN_CONFIG_REQUEST "2.16.840.1.113719.1.39.42.100.3"
56 #define NMASLDAP_GET_LOGIN_CONFIG_RESPONSE "2.16.840.1.113719.1.39.42.100.4"
57 #define NMASLDAP_SET_PASSWORD_REQUEST "2.16.840.1.113719.1.39.42.100.11"
58 #define NMASLDAP_SET_PASSWORD_RESPONSE "2.16.840.1.113719.1.39.42.100.12"
59 #define NMASLDAP_GET_PASSWORD_REQUEST "2.16.840.1.113719.1.39.42.100.13"
60 #define NMASLDAP_GET_PASSWORD_RESPONSE "2.16.840.1.113719.1.39.42.100.14"
62 #define NMAS_LDAP_EXT_VERSION 1
64 #define SMB_MALLOC_ARRAY(type, nelem) calloc(sizeof(type), nelem)
65 #define DEBUG(level, args)
67 /**********************************************************************
68 Take the request BER value and input data items and BER encodes the
69 data into the BER value
70 **********************************************************************/
72 static int berEncodePasswordData(
73 struct berval
**requestBV
,
76 const char *password2
)
79 BerElement
*requestBer
= NULL
;
81 const char * utf8ObjPtr
= NULL
;
83 const char * utf8PwdPtr
= NULL
;
85 const char * utf8Pwd2Ptr
= NULL
;
89 /* Convert objectDN and tag strings from Unicode to UTF-8 */
90 utf8ObjSize
= strlen(objectDN
)+1;
91 utf8ObjPtr
= objectDN
;
93 if (password
!= NULL
) {
94 utf8PwdSize
= strlen(password
)+1;
95 utf8PwdPtr
= password
;
98 if (password2
!= NULL
) {
99 utf8Pwd2Size
= strlen(password2
)+1;
100 utf8Pwd2Ptr
= password2
;
103 /* Allocate a BerElement for the request parameters. */
104 if ((requestBer
= ber_alloc()) == NULL
) {
105 err
= LDAP_ENCODING_ERROR
;
106 ber_free(requestBer
, 1);
110 if (password
!= NULL
&& password2
!= NULL
) {
111 /* BER encode the NMAS Version, the objectDN, and the password */
112 rc
= ber_printf(requestBer
, "{iooo}", NMAS_LDAP_EXT_VERSION
, utf8ObjPtr
, utf8ObjSize
, utf8PwdPtr
, utf8PwdSize
, utf8Pwd2Ptr
, utf8Pwd2Size
);
113 } else if (password
!= NULL
) {
114 /* BER encode the NMAS Version, the objectDN, and the password */
115 rc
= ber_printf(requestBer
, "{ioo}", NMAS_LDAP_EXT_VERSION
, utf8ObjPtr
, utf8ObjSize
, utf8PwdPtr
, utf8PwdSize
);
117 /* BER encode the NMAS Version and the objectDN */
118 rc
= ber_printf(requestBer
, "{io}", NMAS_LDAP_EXT_VERSION
, utf8ObjPtr
, utf8ObjSize
);
122 err
= LDAP_ENCODING_ERROR
;
125 /* Convert the BER we just built to a berval that we'll send with the extended request. */
126 if ((ber_tag_t
)ber_flatten(requestBer
, requestBV
) == LBER_ERROR
) {
127 err
= LDAP_ENCODING_ERROR
;
132 ber_free(requestBer
, 1);
138 /**********************************************************************
139 Take the request BER value and input data items and BER encodes the
140 data into the BER value
141 **********************************************************************/
143 static int berEncodeLoginData(
144 struct berval
**requestBV
,
146 unsigned int methodIDLen
,
147 unsigned int *methodID
,
153 BerElement
*requestBer
= NULL
;
156 unsigned int elemCnt
= methodIDLen
/ sizeof(unsigned int);
158 char *utf8ObjPtr
=NULL
;
161 char *utf8TagPtr
= NULL
;
164 utf8ObjPtr
= objectDN
;
165 utf8ObjSize
= strlen(utf8ObjPtr
)+1;
168 utf8TagSize
= strlen(utf8TagPtr
)+1;
170 /* Allocate a BerElement for the request parameters. */
171 if ((requestBer
= ber_alloc()) == NULL
) {
172 err
= LDAP_ENCODING_ERROR
;
176 /* BER encode the NMAS Version and the objectDN */
177 err
= (ber_printf(requestBer
, "{io", NMAS_LDAP_EXT_VERSION
, utf8ObjPtr
, utf8ObjSize
) < 0) ? LDAP_ENCODING_ERROR
: 0;
179 /* BER encode the MethodID Length and value */
181 err
= (ber_printf(requestBer
, "{i{", methodIDLen
) < 0) ? LDAP_ENCODING_ERROR
: 0;
184 for (i
= 0; !err
&& i
< elemCnt
; i
++) {
185 err
= (ber_printf(requestBer
, "i", methodID
[i
]) < 0) ? LDAP_ENCODING_ERROR
: 0;
189 err
= (ber_printf(requestBer
, "}}", 0) < 0) ? LDAP_ENCODING_ERROR
: 0;
193 /* BER Encode the the tag and data */
194 err
= (ber_printf(requestBer
, "oio}", utf8TagPtr
, utf8TagSize
, putDataLen
, putData
, putDataLen
) < 0) ? LDAP_ENCODING_ERROR
: 0;
196 /* BER Encode the the tag */
197 err
= (ber_printf(requestBer
, "o}", utf8TagPtr
, utf8TagSize
) < 0) ? LDAP_ENCODING_ERROR
: 0;
200 /* Convert the BER we just built to a berval that we'll send with the extended request. */
201 if (!err
&& (ber_tag_t
)ber_flatten(requestBer
, requestBV
) == LBER_ERROR
) {
202 err
= LDAP_ENCODING_ERROR
;
206 ber_free(requestBer
, 1);
212 /**********************************************************************
213 Takes the reply BER Value and decodes the NMAS server version and
214 return code and if a non null retData buffer was supplied, tries to
215 decode the the return data and length
216 **********************************************************************/
218 static int berDecodeLoginData(
219 struct berval
*replyBV
,
225 BerElement
*replyBer
= NULL
;
226 char *retOctStr
= NULL
;
227 size_t retOctStrLen
= 0;
229 if ((replyBer
= ber_init(replyBV
)) == NULL
) {
230 err
= LDAP_OPERATIONS_ERROR
;
231 } else if (retData
) {
232 retOctStrLen
= *retDataLen
+ 1;
233 retOctStr
= (char*)SMB_MALLOC_ARRAY(char, retOctStrLen
);
235 err
= LDAP_OPERATIONS_ERROR
;
236 } else if (ber_scanf(replyBer
, "{iis}", serverVersion
, &err
, retOctStr
, &retOctStrLen
) != LBER_ERROR
) {
237 if (*retDataLen
>= retOctStrLen
) {
238 memcpy(retData
, retOctStr
, retOctStrLen
);
240 err
= LDAP_NO_MEMORY
;
243 *retDataLen
= retOctStrLen
;
245 err
= LDAP_DECODING_ERROR
;
248 if (ber_scanf(replyBer
, "{ii}", serverVersion
, &err
) == LBER_ERROR
) {
250 err
= LDAP_DECODING_ERROR
;
256 ber_free(replyBer
, 1);
259 if (retOctStr
!= NULL
) {
260 memset(retOctStr
, 0, retOctStrLen
);
267 /**********************************************************************
268 Retrieves data in the login configuration of the specified object
269 that is tagged with the specified methodID and tag.
270 **********************************************************************/
272 static int getLoginConfig(
275 unsigned int methodIDLen
,
276 unsigned int *methodID
,
282 struct berval
*requestBV
= NULL
;
283 char *replyOID
= NULL
;
284 struct berval
*replyBV
= NULL
;
285 int serverVersion
= 0;
287 /* Validate unicode parameters. */
288 if ((strlen(objectDN
) == 0) || ld
== NULL
) {
289 return LDAP_NO_SUCH_ATTRIBUTE
;
292 err
= berEncodeLoginData(&requestBV
, objectDN
, methodIDLen
, methodID
, tag
, 0, NULL
);
295 } else if (!err
&& (err
= ldap_extended_operation_s(ld
, NMASLDAP_GET_LOGIN_CONFIG_REQUEST
,
296 requestBV
, NULL
, NULL
, &replyOID
, &replyBV
))) {
297 /* Call the ldap_extended_operation (synchronously) */
299 } else if (!replyOID
) {
300 /* Make sure there is a return OID */
301 err
= LDAP_NOT_SUPPORTED
;
302 } else if (strcmp(replyOID
, NMASLDAP_GET_LOGIN_CONFIG_RESPONSE
)) {
303 /* Is this what we were expecting to get back. */
304 err
= LDAP_NOT_SUPPORTED
;
305 } else if (!replyBV
) {
306 /* Do we have a good returned berval? */
308 /* No; returned berval means we experienced a rather drastic error. */
309 /* Return operations error. */
310 err
= LDAP_OPERATIONS_ERROR
;
313 err
= berDecodeLoginData(replyBV
, &serverVersion
, dataLen
, data
);
315 if (serverVersion
!= NMAS_LDAP_EXT_VERSION
) {
316 err
= LDAP_OPERATIONS_ERROR
;
324 /* Free the return OID string if one was returned. */
326 ldap_memfree(replyOID
);
329 /* Free memory allocated while building the request ber and berval. */
331 ber_bvfree(requestBV
);
334 /* Return the appropriate error/success code. */
338 /**********************************************************************
339 Attempts to get the Simple Password
340 **********************************************************************/
342 static int nmasldap_get_simple_pwd(
349 unsigned int methodID
= 0;
350 unsigned int methodIDLen
= sizeof(methodID
);
351 char tag
[] = {'P','A','S','S','W','O','R','D',' ','H','A','S','H',0};
353 size_t pwdBufLen
, bufferLen
;
355 bufferLen
= pwdBufLen
= pwdLen
+2;
356 pwdBuf
= (char*)SMB_MALLOC_ARRAY(char, pwdBufLen
); /* digest and null */
357 if (pwdBuf
== NULL
) {
358 return LDAP_NO_MEMORY
;
361 err
= getLoginConfig(ld
, objectDN
, methodIDLen
, &methodID
, tag
, &pwdBufLen
, pwdBuf
);
364 pwdBuf
[pwdBufLen
] = 0; /* null terminate */
367 case 1: /* cleartext password */
369 case 2: /* SHA1 HASH */
371 case 4: /* UNIXCrypt_ID */
372 case 8: /* SSHA_ID */
373 default: /* Unknown digest */
374 err
= LDAP_INAPPROPRIATE_AUTH
; /* only return clear text */
379 if (pwdLen
>= pwdBufLen
-1) {
380 memcpy(pwd
, &pwdBuf
[1], pwdBufLen
-1); /* skip digest tag and include null */
382 err
= LDAP_NO_MEMORY
;
388 if (pwdBuf
!= NULL
) {
389 memset(pwdBuf
, 0, bufferLen
);
397 /**********************************************************************
398 Attempts to get the Universal Password
399 **********************************************************************/
401 static int nmasldap_get_password(
404 size_t *pwdSize
, /* in bytes */
409 struct berval
*requestBV
= NULL
;
410 char *replyOID
= NULL
;
411 struct berval
*replyBV
= NULL
;
414 size_t pwdBufLen
, bufferLen
;
416 /* Validate char parameters. */
417 if (objectDN
== NULL
|| (strlen(objectDN
) == 0) || pwdSize
== NULL
|| ld
== NULL
) {
418 return LDAP_NO_SUCH_ATTRIBUTE
;
421 bufferLen
= pwdBufLen
= *pwdSize
;
422 pwdBuf
= (char*)SMB_MALLOC_ARRAY(char, pwdBufLen
+2);
423 if (pwdBuf
== NULL
) {
424 return LDAP_NO_MEMORY
;
427 err
= berEncodePasswordData(&requestBV
, objectDN
, NULL
, NULL
);
430 } else if ((err
= ldap_extended_operation_s(ld
, NMASLDAP_GET_PASSWORD_REQUEST
, requestBV
, NULL
, NULL
, &replyOID
, &replyBV
))) {
431 ; /* Call the ldap_extended_operation (synchronously) */
432 } else if (!replyOID
) {
433 /* Make sure there is a return OID */
434 err
= LDAP_NOT_SUPPORTED
;
435 } else if (strcmp(replyOID
, NMASLDAP_GET_PASSWORD_RESPONSE
)) {
436 /* Is this what we were expecting to get back. */
437 err
= LDAP_NOT_SUPPORTED
;
438 } else if (!replyBV
) {
439 /* Do we have a good returned berval? */
440 /* No; returned berval means we experienced a rather drastic error. */
441 /* Return operations error. */
442 err
= LDAP_OPERATIONS_ERROR
;
444 err
= berDecodeLoginData(replyBV
, &serverVersion
, &pwdBufLen
, pwdBuf
);
446 if (serverVersion
!= NMAS_LDAP_EXT_VERSION
) {
447 err
= LDAP_OPERATIONS_ERROR
;
449 } else if (!err
&& pwdBufLen
!= 0) {
450 if (*pwdSize
>= pwdBufLen
+1 && pwd
!= NULL
) {
451 memcpy(pwd
, pwdBuf
, pwdBufLen
);
452 pwd
[pwdBufLen
] = 0; /* add null termination */
454 *pwdSize
= pwdBufLen
; /* does not include null termination */
462 /* Free the return OID string if one was returned. */
464 ldap_memfree(replyOID
);
467 /* Free memory allocated while building the request ber and berval. */
469 ber_bvfree(requestBV
);
472 if (pwdBuf
!= NULL
) {
473 memset(pwdBuf
, 0, bufferLen
);
477 /* Return the appropriate error/success code. */
481 /**********************************************************************
482 Get the user's password from NDS.
483 *********************************************************************/
485 int nds_get_password(
493 rc
= nmasldap_get_password(ld
, object_dn
, pwd_len
, (unsigned char *)pwd
);
494 if (rc
== LDAP_SUCCESS
) {
495 #ifdef DEBUG_PASSWORD
496 DEBUG(100,("nmasldap_get_password returned %s for %s\n", pwd
, object_dn
));
498 DEBUG(5, ("NDS Universal Password retrieved for %s\n", object_dn
));
500 DEBUG(3, ("NDS Universal Password NOT retrieved for %s\n", object_dn
));
503 if (rc
!= LDAP_SUCCESS
) {
504 rc
= nmasldap_get_simple_pwd(ld
, object_dn
, *pwd_len
, pwd
);
505 if (rc
== LDAP_SUCCESS
) {
506 #ifdef DEBUG_PASSWORD
507 DEBUG(100,("nmasldap_get_simple_pwd returned %s for %s\n", pwd
, object_dn
));
509 DEBUG(5, ("NDS Simple Password retrieved for %s\n", object_dn
));
511 /* We couldn't get the password */
512 DEBUG(3, ("NDS Simple Password NOT retrieved for %s\n", object_dn
));
513 return LDAP_INVALID_CREDENTIALS
;
517 /* We got the password */