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