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