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