edir_ldapext.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2017 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 
36 #if _SQUID_WINDOWS_ && !_SQUID_CYGWIN_
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 
54 #include <lber.h>
55 #include <ldap.h>
56 
57 #endif
58 #include <wchar.h>
59 
60 #include "edir_ldapext.h"
61 
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"
68 
69 #define NMAS_LDAP_EXT_VERSION 1
70 
71 #define SMB_MALLOC_ARRAY(type, nelem) calloc(sizeof(type), nelem)
72 #define DEBUG(level, args)
73 
74 /**********************************************************************
75  Take the request BER value and input data items and BER encodes the
76  data into the BER value
77 **********************************************************************/
78 
80  struct berval **requestBV,
81  const char *objectDN,
82  const char *password,
83  const char *password2)
84 {
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 
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;
112  ber_free(requestBer, 1);
113  return err;
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;
129  } else {
130  err = 0;
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  }
135  }
136 
137  if (requestBer) {
138  ber_free(requestBer, 1);
139  }
140 
141  return err;
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 
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)
157 {
158  unsigned int elemCnt = methodIDLen / sizeof(unsigned int);
159 
160  char *utf8ObjPtr=NULL;
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. */
173  BerElement *requestBer = ber_alloc();
174  if (!requestBer)
175  return LDAP_ENCODING_ERROR;
176 
177  /* BER encode the NMAS Version and the objectDN */
178  if (ber_printf(requestBer, "{io", NMAS_LDAP_EXT_VERSION, utf8ObjPtr, utf8ObjSize) < 0) {
179  ber_free(requestBer, 1);
180  return LDAP_ENCODING_ERROR;
181  }
182 
183  /* BER encode the MethodID Length and value */
184  if (ber_printf(requestBer, "{i{", methodIDLen) < 0) {
185  ber_free(requestBer, 1);
186  return LDAP_ENCODING_ERROR;
187  }
188 
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  }
194  }
195 
196  if (ber_printf(requestBer, "}}", 0) < 0) {
197  ber_free(requestBer, 1);
198  return LDAP_ENCODING_ERROR;
199  }
200 
201  if (putData) {
202  /* BER Encode the the tag and data */
203  if (ber_printf(requestBer, "oio}", utf8TagPtr, utf8TagSize, putDataLen, putData, putDataLen) < 0) {
204  ber_free(requestBer, 1);
205  return LDAP_ENCODING_ERROR;
206  }
207  } else {
208  /* BER Encode the the tag */
209  if (ber_printf(requestBer, "o}", utf8TagPtr, utf8TagSize) < 0) {
210  ber_free(requestBer, 1);
211  return LDAP_ENCODING_ERROR;
212  }
213  }
214 
215  /* Convert the BER we just built to a berval that we'll send with the extended request. */
216  if (static_cast<ber_tag_t>(ber_flatten(requestBer, requestBV)) == LBER_ERROR) {
217  ber_free(requestBer, 1);
218  return LDAP_ENCODING_ERROR;
219  }
220 
221  ber_free(requestBer, 1);
222  return 0; /* no error */
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 
232  struct berval *replyBV,
233  int *serverVersion,
234  size_t *retDataLen,
235  void *retData )
236 {
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;
244  } else if (retData) {
245  retOctStrLen = *retDataLen + 1;
246  retOctStr = (char*)SMB_MALLOC_ARRAY(char, retOctStrLen);
247  if (!retOctStr) {
248  err = LDAP_OPERATIONS_ERROR;
249  } else if (ber_scanf(replyBer, "{iis}", serverVersion, &err, retOctStr, &retOctStrLen) != LBER_ERROR) {
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 {
261  if (ber_scanf(replyBer, "{ii}", serverVersion, &err) == LBER_ERROR) {
262  if (!err) {
263  err = LDAP_DECODING_ERROR;
264  }
265  }
266  }
267 
268  if (replyBer) {
269  ber_free(replyBer, 1);
270  }
271 
272  if (retOctStr != NULL) {
273  memset(retOctStr, 0, retOctStrLen);
274  free(retOctStr);
275  }
276 
277  return err;
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 
285 static int getLoginConfig(
286  LDAP *ld,
287  char *objectDN,
288  unsigned int methodIDLen,
289  unsigned int *methodID,
290  char *tag,
291  size_t *dataLen,
292  void *data )
293 {
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) {
307  ;
308  } else if (!err && (err = ldap_extended_operation_s(ld, NMASLDAP_GET_LOGIN_CONFIG_REQUEST,
309  requestBV, NULL, NULL, &replyOID, &replyBV))) {
310  /* Call the ldap_extended_operation (synchronously) */
311  ;
312  } else if (!replyOID) {
313  /* Make sure there is a return OID */
314  err = LDAP_NOT_SUPPORTED;
315  } else if (strcmp(replyOID, NMASLDAP_GET_LOGIN_CONFIG_RESPONSE)) {
316  /* Is this what we were expecting to get back. */
317  err = LDAP_NOT_SUPPORTED;
318  } else if (!replyBV) {
319  /* Do we have a good returned berval? */
320 
321  /* No; returned berval means we experienced a rather drastic error. */
322  /* Return operations error. */
323  err = LDAP_OPERATIONS_ERROR;
324  } else {
325 
326  err = berDecodeLoginData(replyBV, &serverVersion, dataLen, data);
327 
328  if (serverVersion != NMAS_LDAP_EXT_VERSION) {
329  err = LDAP_OPERATIONS_ERROR;
330  }
331  }
332 
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;
349 }
350 
351 /**********************************************************************
352  Attempts to get the Simple Password
353 **********************************************************************/
354 
356  LDAP *ld,
357  char *objectDN,
358  size_t pwdLen,
359  char *pwd )
360 {
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;
369  pwdBuf = (char*)SMB_MALLOC_ARRAY(char, pwdBufLen); /* digest and null */
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;
407 }
408 
409 /**********************************************************************
410  Attempts to get the Universal Password
411 **********************************************************************/
412 
414  LDAP *ld,
415  char *objectDN,
416  size_t *pwdSize, /* in bytes */
417  unsigned char *pwd )
418 {
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;
434  pwdBuf = (char*)SMB_MALLOC_ARRAY(char, pwdBufLen+2);
435  if (pwdBuf == NULL) {
436  return LDAP_NO_MEMORY;
437  }
438 
439  err = berEncodePasswordData(&requestBV, objectDN, NULL, NULL);
440  if (err) {
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 */
446  err = LDAP_NOT_SUPPORTED;
447  } else if (strcmp(replyOID, NMASLDAP_GET_PASSWORD_RESPONSE)) {
448  /* Is this what we were expecting to get back. */
449  err = LDAP_NOT_SUPPORTED;
450  } else if (!replyBV) {
451  /* Do we have a good returned berval? */
452  /* No; returned berval means we experienced a rather drastic error. */
453  /* Return operations error. */
454  err = LDAP_OPERATIONS_ERROR;
455  } else {
456  err = berDecodeLoginData(replyBV, &serverVersion, &pwdBufLen, pwdBuf);
457 
458  if (serverVersion != NMAS_LDAP_EXT_VERSION) {
459  err = LDAP_OPERATIONS_ERROR;
460 
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 */
467  }
468  }
469 
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;
491 }
492 
493 /**********************************************************************
494  Get the user's password from NDS.
495  *********************************************************************/
496 
498  LDAP *ld,
499  char *object_dn,
500  size_t *pwd_len,
501  char *pwd )
502 {
503  int rc = -1;
504 
505  rc = nmasldap_get_password(ld, object_dn, pwd_len, (unsigned char *)pwd);
506  if (rc == LDAP_SUCCESS) {
507 #ifdef DEBUG_PASSWORD
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) {
518 #ifdef DEBUG_PASSWORD
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;
531 }
532 
static LDAP * ld
Definition: ldap_backend.cc:56
static int getLoginConfig(LDAP *ld, char *objectDN, unsigned int methodIDLen, unsigned int *methodID, char *tag, size_t *dataLen, void *data)
int i
Definition: membanger.c:49
#define NMASLDAP_GET_LOGIN_CONFIG_REQUEST
Definition: edir_ldapext.cc:62
#define NMASLDAP_GET_PASSWORD_RESPONSE
Definition: edir_ldapext.cc:67
#define NMAS_LDAP_EXT_VERSION
Definition: edir_ldapext.cc:69
#define NMASLDAP_GET_LOGIN_CONFIG_RESPONSE
Definition: edir_ldapext.cc:63
void const char HLPCB void * data
Definition: stub_helper.cc:16
static int berEncodePasswordData(struct berval **requestBV, const char *objectDN, const char *password, const char *password2)
Definition: edir_ldapext.cc:79
int nds_get_password(LDAP *ld, char *object_dn, size_t *pwd_len, char *pwd)
static int berDecodeLoginData(struct berval *replyBV, int *serverVersion, size_t *retDataLen, void *retData)
#define SMB_MALLOC_ARRAY(type, nelem)
Definition: edir_ldapext.cc:71
static int nmasldap_get_password(LDAP *ld, char *objectDN, size_t *pwdSize, unsigned char *pwd)
#define DEBUG(level, args)
Definition: edir_ldapext.cc:72
static int berEncodeLoginData(struct berval **requestBV, char *objectDN, unsigned int methodIDLen, unsigned int *methodID, char *tag, size_t putDataLen, void *putData)
#define NMASLDAP_GET_PASSWORD_REQUEST
Definition: edir_ldapext.cc:66
bool SIGHDLR int STUB void int
Definition: stub_tools.cc:68
static int nmasldap_get_simple_pwd(LDAP *ld, char *objectDN, size_t pwdLen, char *pwd)
#define NULL
Definition: types.h:166
#define free(a)
Definition: hash.c:31

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors