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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors