]> git.ipfire.org Git - thirdparty/squid.git/blame - helpers/digest_auth/eDirectory/edir_ldapext.cc
Renamed squid.h to squid-old.h and config.h to squid.h
[thirdparty/squid.git] / helpers / digest_auth / eDirectory / edir_ldapext.cc
CommitLineData
26ac0430 1/*
591c3246 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
89f77e43 5 *
591c3246 6 * Original copyright & license follows:
89f77e43 7 *
591c3246 8 * Copyright (C) Vince Brimhall 2004-2005
26ac0430 9 *
591c3246 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.
26ac0430 14 *
591c3246 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.
26ac0430 19 *
591c3246 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.
26ac0430 23 *
591c3246 24*/
f7f3304a 25#include "squid.h"
f971fe39 26
f5a88a5e 27#include "digest_common.h"
28
1191b93b 29#if _SQUID_MSWIN_ /* Native Windows port and MinGW */
f5a88a5e 30
31#define snprintf _snprintf
32#include <windows.h>
33#include <winldap.h>
34#include <winber.h>
35#ifndef LDAPAPI
36#define LDAPAPI __cdecl
37#endif
38#ifdef LDAP_VERSION3
39#ifndef LDAP_OPT_X_TLS
40#define LDAP_OPT_X_TLS 0x6000
41#endif
42#define ber_alloc() ber_alloc_t(0)
43#endif /* LDAP_VERSION3 */
44
45#else
46
f971fe39 47#include <lber.h>
48#include <ldap.h>
f5a88a5e 49
50#endif
591c3246 51#include <wchar.h>
e9505fad 52
53#include "edir_ldapext.h"
54
591c3246 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"
89f77e43 61
591c3246 62#define NMAS_LDAP_EXT_VERSION 1
89f77e43 63
591c3246 64#define SMB_MALLOC_ARRAY(type, nelem) calloc(sizeof(type), nelem)
65#define DEBUG(level, args)
89f77e43 66
591c3246 67/**********************************************************************
68 Take the request BER value and input data items and BER encodes the
69 data into the BER value
70**********************************************************************/
89f77e43 71
591c3246 72static int berEncodePasswordData(
26ac0430
AJ
73 struct berval **requestBV,
74 const char *objectDN,
75 const char *password,
76 const char *password2)
591c3246 77{
26ac0430
AJ
78 int err = 0, rc=0;
79 BerElement *requestBer = NULL;
80
81 const char * utf8ObjPtr = NULL;
82 int utf8ObjSize = 0;
83 const char * utf8PwdPtr = NULL;
84 int utf8PwdSize = 0;
85 const char * utf8Pwd2Ptr = NULL;
86 int utf8Pwd2Size = 0;
87
88
89 /* Convert objectDN and tag strings from Unicode to UTF-8 */
90 utf8ObjSize = strlen(objectDN)+1;
91 utf8ObjPtr = objectDN;
92
93 if (password != NULL) {
94 utf8PwdSize = strlen(password)+1;
95 utf8PwdPtr = password;
96 }
97
98 if (password2 != NULL) {
99 utf8Pwd2Size = strlen(password2)+1;
100 utf8Pwd2Ptr = password2;
101 }
102
103 /* Allocate a BerElement for the request parameters. */
104 if ((requestBer = ber_alloc()) == NULL) {
105 err = LDAP_ENCODING_ERROR;
56ff4687
AJ
106 ber_free(requestBer, 1);
107 return err;
26ac0430
AJ
108 }
109
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);
116 } else {
117 /* BER encode the NMAS Version and the objectDN */
118 rc = ber_printf(requestBer, "{io}", NMAS_LDAP_EXT_VERSION, utf8ObjPtr, utf8ObjSize);
119 }
120
121 if (rc < 0) {
122 err = LDAP_ENCODING_ERROR;
26ac0430
AJ
123 } else {
124 err = 0;
56ff4687
AJ
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;
128 }
26ac0430
AJ
129 }
130
26ac0430
AJ
131 if (requestBer) {
132 ber_free(requestBer, 1);
133 }
591c3246 134
26ac0430 135 return err;
591c3246 136}
137
138/**********************************************************************
139 Take the request BER value and input data items and BER encodes the
140 data into the BER value
141**********************************************************************/
142
143static int berEncodeLoginData(
26ac0430
AJ
144 struct berval **requestBV,
145 char *objectDN,
146 unsigned int methodIDLen,
147 unsigned int *methodID,
148 char *tag,
149 size_t putDataLen,
150 void *putData)
89f77e43 151{
26ac0430
AJ
152 int err = 0;
153 BerElement *requestBer = NULL;
154
155 unsigned int i;
156 unsigned int elemCnt = methodIDLen / sizeof(unsigned int);
157
158 char *utf8ObjPtr=NULL;
159 int utf8ObjSize = 0;
160
161 char *utf8TagPtr = NULL;
162 int utf8TagSize = 0;
163
164 utf8ObjPtr = objectDN;
165 utf8ObjSize = strlen(utf8ObjPtr)+1;
166
167 utf8TagPtr = tag;
168 utf8TagSize = strlen(utf8TagPtr)+1;
169
170 /* Allocate a BerElement for the request parameters. */
171 if ((requestBer = ber_alloc()) == NULL) {
172 err = LDAP_ENCODING_ERROR;
56ff4687 173 return err;
26ac0430
AJ
174 }
175
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;
178
179 /* BER encode the MethodID Length and value */
180 if (!err) {
181 err = (ber_printf(requestBer, "{i{", methodIDLen) < 0) ? LDAP_ENCODING_ERROR : 0;
182 }
183
184 for (i = 0; !err && i < elemCnt; i++) {
185 err = (ber_printf(requestBer, "i", methodID[i]) < 0) ? LDAP_ENCODING_ERROR : 0;
186 }
187
188 if (!err) {
189 err = (ber_printf(requestBer, "}}", 0) < 0) ? LDAP_ENCODING_ERROR : 0;
190 }
191
192 if (putData) {
193 /* BER Encode the the tag and data */
194 err = (ber_printf(requestBer, "oio}", utf8TagPtr, utf8TagSize, putDataLen, putData, putDataLen) < 0) ? LDAP_ENCODING_ERROR : 0;
195 } else {
196 /* BER Encode the the tag */
197 err = (ber_printf(requestBer, "o}", utf8TagPtr, utf8TagSize) < 0) ? LDAP_ENCODING_ERROR : 0;
198 }
199
26ac0430 200 /* Convert the BER we just built to a berval that we'll send with the extended request. */
56ff4687 201 if (!err && (ber_tag_t)ber_flatten(requestBer, requestBV) == LBER_ERROR) {
26ac0430 202 err = LDAP_ENCODING_ERROR;
26ac0430 203 }
591c3246 204
26ac0430
AJ
205 if (requestBer) {
206 ber_free(requestBer, 1);
207 }
591c3246 208
26ac0430 209 return err;
591c3246 210}
211
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**********************************************************************/
217
218static int berDecodeLoginData(
26ac0430
AJ
219 struct berval *replyBV,
220 int *serverVersion,
221 size_t *retDataLen,
222 void *retData )
89f77e43 223{
26ac0430
AJ
224 int err = 0;
225 BerElement *replyBer = NULL;
226 char *retOctStr = NULL;
227 size_t retOctStrLen = 0;
228
229 if ((replyBer = ber_init(replyBV)) == NULL) {
230 err = LDAP_OPERATIONS_ERROR;
feec68a0 231 } else if (retData) {
26ac0430 232 retOctStrLen = *retDataLen + 1;
56ff4687 233 retOctStr = (char*)SMB_MALLOC_ARRAY(char, retOctStrLen);
26ac0430
AJ
234 if (!retOctStr) {
235 err = LDAP_OPERATIONS_ERROR;
feec68a0 236 } else if (ber_scanf(replyBer, "{iis}", serverVersion, &err, retOctStr, &retOctStrLen) != LBER_ERROR) {
26ac0430
AJ
237 if (*retDataLen >= retOctStrLen) {
238 memcpy(retData, retOctStr, retOctStrLen);
239 } else if (!err) {
240 err = LDAP_NO_MEMORY;
241 }
242
243 *retDataLen = retOctStrLen;
244 } else if (!err) {
245 err = LDAP_DECODING_ERROR;
246 }
247 } else {
56ff4687 248 if (ber_scanf(replyBer, "{ii}", serverVersion, &err) == LBER_ERROR) {
26ac0430
AJ
249 if (!err) {
250 err = LDAP_DECODING_ERROR;
251 }
252 }
253 }
591c3246 254
26ac0430
AJ
255 if (replyBer) {
256 ber_free(replyBer, 1);
257 }
591c3246 258
26ac0430
AJ
259 if (retOctStr != NULL) {
260 memset(retOctStr, 0, retOctStrLen);
261 free(retOctStr);
262 }
591c3246 263
26ac0430 264 return err;
591c3246 265}
266
267/**********************************************************************
268 Retrieves data in the login configuration of the specified object
269 that is tagged with the specified methodID and tag.
270**********************************************************************/
271
272static int getLoginConfig(
26ac0430
AJ
273 LDAP *ld,
274 char *objectDN,
275 unsigned int methodIDLen,
276 unsigned int *methodID,
277 char *tag,
278 size_t *dataLen,
279 void *data )
89f77e43 280{
26ac0430
AJ
281 int err = 0;
282 struct berval *requestBV = NULL;
283 char *replyOID = NULL;
284 struct berval *replyBV = NULL;
285 int serverVersion = 0;
286
287 /* Validate unicode parameters. */
288 if ((strlen(objectDN) == 0) || ld == NULL) {
289 return LDAP_NO_SUCH_ATTRIBUTE;
290 }
291
292 err = berEncodeLoginData(&requestBV, objectDN, methodIDLen, methodID, tag, 0, NULL);
293 if (err) {
56ff4687
AJ
294 ;
295 } else if (!err && (err = ldap_extended_operation_s(ld, NMASLDAP_GET_LOGIN_CONFIG_REQUEST,
feec68a0 296 requestBV, NULL, NULL, &replyOID, &replyBV))) {
56ff4687
AJ
297 /* Call the ldap_extended_operation (synchronously) */
298 ;
299 } else if (!replyOID) {
300 /* Make sure there is a return OID */
26ac0430 301 err = LDAP_NOT_SUPPORTED;
56ff4687
AJ
302 } else if (strcmp(replyOID, NMASLDAP_GET_LOGIN_CONFIG_RESPONSE)) {
303 /* Is this what we were expecting to get back. */
26ac0430 304 err = LDAP_NOT_SUPPORTED;
56ff4687
AJ
305 } else if (!replyBV) {
306 /* Do we have a good returned berval? */
26ac0430 307
26ac0430
AJ
308 /* No; returned berval means we experienced a rather drastic error. */
309 /* Return operations error. */
310 err = LDAP_OPERATIONS_ERROR;
56ff4687 311 } else {
26ac0430 312
56ff4687 313 err = berDecodeLoginData(replyBV, &serverVersion, dataLen, data);
26ac0430 314
56ff4687
AJ
315 if (serverVersion != NMAS_LDAP_EXT_VERSION) {
316 err = LDAP_OPERATIONS_ERROR;
317 }
26ac0430 318 }
591c3246 319
26ac0430
AJ
320 if (replyBV) {
321 ber_bvfree(replyBV);
322 }
323
324 /* Free the return OID string if one was returned. */
325 if (replyOID) {
326 ldap_memfree(replyOID);
327 }
328
329 /* Free memory allocated while building the request ber and berval. */
330 if (requestBV) {
331 ber_bvfree(requestBV);
332 }
333
334 /* Return the appropriate error/success code. */
335 return err;
591c3246 336}
337
338/**********************************************************************
339 Attempts to get the Simple Password
340**********************************************************************/
341
342static int nmasldap_get_simple_pwd(
26ac0430
AJ
343 LDAP *ld,
344 char *objectDN,
345 size_t pwdLen,
346 char *pwd )
591c3246 347{
26ac0430
AJ
348 int err = 0;
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};
352 char *pwdBuf=NULL;
353 size_t pwdBufLen, bufferLen;
354
355 bufferLen = pwdBufLen = pwdLen+2;
56ff4687 356 pwdBuf = (char*)SMB_MALLOC_ARRAY(char, pwdBufLen); /* digest and null */
26ac0430
AJ
357 if (pwdBuf == NULL) {
358 return LDAP_NO_MEMORY;
359 }
360
361 err = getLoginConfig(ld, objectDN, methodIDLen, &methodID, tag, &pwdBufLen, pwdBuf);
362 if (err == 0) {
363 if (pwdBufLen !=0) {
364 pwdBuf[pwdBufLen] = 0; /* null terminate */
365
366 switch (pwdBuf[0]) {
367 case 1: /* cleartext password */
368 break;
369 case 2: /* SHA1 HASH */
370 case 3: /* MD5_ID */
371 case 4: /* UNIXCrypt_ID */
372 case 8: /* SSHA_ID */
373 default: /* Unknown digest */
374 err = LDAP_INAPPROPRIATE_AUTH; /* only return clear text */
375 break;
376 }
377
378 if (!err) {
379 if (pwdLen >= pwdBufLen-1) {
380 memcpy(pwd, &pwdBuf[1], pwdBufLen-1); /* skip digest tag and include null */
381 } else {
382 err = LDAP_NO_MEMORY;
383 }
384 }
385 }
386 }
387
388 if (pwdBuf != NULL) {
389 memset(pwdBuf, 0, bufferLen);
390 free(pwdBuf);
391 }
392
393 return err;
591c3246 394}
395
396
397/**********************************************************************
398 Attempts to get the Universal Password
399**********************************************************************/
400
401static int nmasldap_get_password(
26ac0430
AJ
402 LDAP *ld,
403 char *objectDN,
404 size_t *pwdSize, /* in bytes */
405 unsigned char *pwd )
591c3246 406{
26ac0430
AJ
407 int err = 0;
408
409 struct berval *requestBV = NULL;
410 char *replyOID = NULL;
411 struct berval *replyBV = NULL;
412 int serverVersion;
413 char *pwdBuf;
414 size_t pwdBufLen, bufferLen;
415
416 /* Validate char parameters. */
417 if (objectDN == NULL || (strlen(objectDN) == 0) || pwdSize == NULL || ld == NULL) {
418 return LDAP_NO_SUCH_ATTRIBUTE;
419 }
420
421 bufferLen = pwdBufLen = *pwdSize;
56ff4687 422 pwdBuf = (char*)SMB_MALLOC_ARRAY(char, pwdBufLen+2);
26ac0430
AJ
423 if (pwdBuf == NULL) {
424 return LDAP_NO_MEMORY;
425 }
426
427 err = berEncodePasswordData(&requestBV, objectDN, NULL, NULL);
428 if (err) {
56ff4687
AJ
429 ;
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 */
26ac0430 434 err = LDAP_NOT_SUPPORTED;
56ff4687
AJ
435 } else if (strcmp(replyOID, NMASLDAP_GET_PASSWORD_RESPONSE)) {
436 /* Is this what we were expecting to get back. */
26ac0430 437 err = LDAP_NOT_SUPPORTED;
56ff4687
AJ
438 } else if (!replyBV) {
439 /* Do we have a good returned berval? */
26ac0430
AJ
440 /* No; returned berval means we experienced a rather drastic error. */
441 /* Return operations error. */
442 err = LDAP_OPERATIONS_ERROR;
56ff4687
AJ
443 } else {
444 err = berDecodeLoginData(replyBV, &serverVersion, &pwdBufLen, pwdBuf);
26ac0430 445
56ff4687
AJ
446 if (serverVersion != NMAS_LDAP_EXT_VERSION) {
447 err = LDAP_OPERATIONS_ERROR;
26ac0430 448
56ff4687
AJ
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 */
453 }
454 *pwdSize = pwdBufLen; /* does not include null termination */
26ac0430 455 }
26ac0430 456 }
591c3246 457
26ac0430
AJ
458 if (replyBV) {
459 ber_bvfree(replyBV);
460 }
461
462 /* Free the return OID string if one was returned. */
463 if (replyOID) {
464 ldap_memfree(replyOID);
465 }
466
467 /* Free memory allocated while building the request ber and berval. */
468 if (requestBV) {
469 ber_bvfree(requestBV);
470 }
471
472 if (pwdBuf != NULL) {
473 memset(pwdBuf, 0, bufferLen);
474 free(pwdBuf);
475 }
476
477 /* Return the appropriate error/success code. */
478 return err;
591c3246 479}
480
481/**********************************************************************
482 Get the user's password from NDS.
483 *********************************************************************/
484
485int nds_get_password(
26ac0430
AJ
486 LDAP *ld,
487 char *object_dn,
488 size_t *pwd_len,
489 char *pwd )
591c3246 490{
26ac0430 491 int rc = -1;
591c3246 492
26ac0430
AJ
493 rc = nmasldap_get_password(ld, object_dn, pwd_len, (unsigned char *)pwd);
494 if (rc == LDAP_SUCCESS) {
591c3246 495#ifdef DEBUG_PASSWORD
26ac0430
AJ
496 DEBUG(100,("nmasldap_get_password returned %s for %s\n", pwd, object_dn));
497#endif
498 DEBUG(5, ("NDS Universal Password retrieved for %s\n", object_dn));
499 } else {
500 DEBUG(3, ("NDS Universal Password NOT retrieved for %s\n", object_dn));
501 }
502
503 if (rc != LDAP_SUCCESS) {
504 rc = nmasldap_get_simple_pwd(ld, object_dn, *pwd_len, pwd);
505 if (rc == LDAP_SUCCESS) {
591c3246 506#ifdef DEBUG_PASSWORD
26ac0430
AJ
507 DEBUG(100,("nmasldap_get_simple_pwd returned %s for %s\n", pwd, object_dn));
508#endif
509 DEBUG(5, ("NDS Simple Password retrieved for %s\n", object_dn));
510 } else {
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;
514 }
515 }
516
517 /* We got the password */
518 return LDAP_SUCCESS;
591c3246 519}
520