Remove autogenerated file.
[Samba/gebeck_regimport.git] / source3 / lib / ldap.c
blob917e03a871c807d81f76c30e216ac99d4191fafc
1 /*
2 Unix SMB/CIFS implementation.
3 LDAP protocol helper functions for SAMBA
4 Copyright (C) Jean François Micouleau 1998
5 Copyright (C) Gerald Carter 2001
6 Copyright (C) Shahms King 2001
7 Copyright (C) Andrew Bartlett 2002
8 Copyright (C) Stefan (metze) Metzmacher 2002
9 Copyright (C) Jim McDonough 2003
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #include "includes.h"
29 #ifdef HAVE_LDAP
30 /* TODO:
31 * persistent connections: if using NSS LDAP, many connections are made
32 * however, using only one within Samba would be nice
34 * Clean up SSL stuff, compile on OpenLDAP 1.x, 2.x, and Netscape SDK
36 * Other LDAP based login attributes: accountExpires, etc.
37 * (should be the domain of Samba proper, but the sam_password/SAM_ACCOUNT
38 * structures don't have fields for some of these attributes)
40 * SSL is done, but can't get the certificate based authentication to work
41 * against on my test platform (Linux 2.4, OpenLDAP 2.x)
44 /* NOTE: this will NOT work against an Active Directory server
45 * due to the fact that the two password fields cannot be retrieved
46 * from a server; recommend using security = domain in this situation
47 * and/or winbind
50 #include "smb_ldap.h"
52 /* We need an internal mapping of LDAP * -> smb_ldap_privates so we implement
53 it in terms of a VK list. It's a little backwards but its quite efficent */
54 static struct smb_ldap_privates *head;
56 static struct smb_ldap_privates *get_internal(LDAP *ldap_struct)
58 struct smb_ldap_privates *ret = head;
60 while (NULL != ret && ret->ldap_struct != ldap_struct) {
61 ret = ret->next;
64 return ret;
67 #define SMB_LDAP_DONT_PING_TIME 10 /* ping only all 10 seconds */
69 /*******************************************************************
70 find the ldap password
71 ******************************************************************/
72 static BOOL smb_ldap_fetch_pw(char **dn, char** pw)
74 char *key = NULL;
75 size_t size;
77 *dn = smb_xstrdup(lp_ldap_admin_dn());
79 if (asprintf(&key, "%s/%s", SECRETS_LDAP_BIND_PW, *dn) < 0) {
80 SAFE_FREE(*dn);
81 DEBUG(0, ("smb_ldap_fetch_pw: asprintf failed!\n"));
84 *pw=secrets_fetch(key, &size);
85 SAFE_FREE(key);
86 if (!size) {
87 /* Upgrade 2.2 style entry */
88 char *p;
89 char* old_style_key = strdup(*dn);
90 char *data;
91 fstring old_style_pw;
93 if (!old_style_key) {
94 DEBUG(0, ("smb_ldap_fetch_pw: strdup failed!\n"));
95 return False;
98 for (p=old_style_key; *p; p++)
99 if (*p == ',') *p = '/';
101 data=secrets_fetch(old_style_key, &size);
102 if (!size && size < sizeof(old_style_pw)) {
103 DEBUG(0,("fetch_ldap_pw: neither ldap secret retrieved!\n"));
104 SAFE_FREE(old_style_key);
105 SAFE_FREE(*dn);
106 return False;
109 strncpy(old_style_pw, data, size);
110 old_style_pw[size] = 0;
112 SAFE_FREE(data);
114 if (!secrets_store_ldap_pw(*dn, old_style_pw)) {
115 DEBUG(0,("fetch_ldap_pw: ldap secret could not be upgraded!\n"));
116 SAFE_FREE(old_style_key);
117 SAFE_FREE(*dn);
118 return False;
120 if (!secrets_delete(old_style_key)) {
121 DEBUG(0,("fetch_ldap_pw: old ldap secret could not be deleted!\n"));
124 SAFE_FREE(old_style_key);
126 *pw = smb_xstrdup(old_style_pw);
129 return True;
132 /*******************************************************************
133 open a connection to the ldap server.
134 ******************************************************************/
135 int smb_ldap_open_connection (struct smb_ldap_privates *ldap_state,
136 LDAP ** ldap_struct)
138 int rc = LDAP_SUCCESS;
139 int version;
140 BOOL ldap_v3 = False;
142 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
143 DEBUG(10, ("smb_ldap_open_connection: %s\n", ldap_state->uri));
145 if ((rc = ldap_initialize(ldap_struct, ldap_state->uri)) != LDAP_SUCCESS) {
146 DEBUG(0, ("ldap_initialize: %s\n", ldap_err2string(rc)));
147 return rc;
150 #else
152 /* Parse the string manually */
155 int port = 0;
156 fstring protocol;
157 fstring host;
158 const char *p = ldap_state->uri;
159 SMB_ASSERT(sizeof(protocol)>10 && sizeof(host)>254);
161 /* skip leading "URL:" (if any) */
162 if ( strncasecmp( p, "URL:", 4 ) == 0 ) {
163 p += 4;
166 sscanf(p, "%10[^:]://%254s[^:]:%d", protocol, host, &port);
168 if (port == 0) {
169 if (strequal(protocol, "ldap")) {
170 port = LDAP_PORT;
171 } else if (strequal(protocol, "ldaps")) {
172 port = LDAPS_PORT;
173 } else {
174 DEBUG(0, ("unrecognised protocol (%s)!\n", protocol));
178 if ((*ldap_struct = ldap_init(host, port)) == NULL) {
179 DEBUG(0, ("ldap_init failed !\n"));
180 return LDAP_OPERATIONS_ERROR;
183 if (strequal(protocol, "ldaps")) {
184 #ifdef LDAP_OPT_X_TLS
185 int tls = LDAP_OPT_X_TLS_HARD;
186 if (ldap_set_option (*ldap_struct, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS)
188 DEBUG(0, ("Failed to setup a TLS session\n"));
191 DEBUG(3,("LDAPS option set...!\n"));
192 #else
193 DEBUG(0,("smb_ldap_open_connection: Secure connection not supported by LDAP client libraries!\n"));
194 return LDAP_OPERATIONS_ERROR;
195 #endif
198 #endif
200 if (ldap_get_option(*ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS)
202 if (version != LDAP_VERSION3)
204 version = LDAP_VERSION3;
205 if (ldap_set_option (*ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS) {
206 ldap_v3 = True;
208 } else {
209 ldap_v3 = True;
213 if (lp_ldap_ssl() == LDAP_SSL_START_TLS) {
214 #ifdef LDAP_OPT_X_TLS
215 if (ldap_v3) {
216 if ((rc = ldap_start_tls_s (*ldap_struct, NULL, NULL)) != LDAP_SUCCESS)
218 DEBUG(0,("Failed to issue the StartTLS instruction: %s\n",
219 ldap_err2string(rc)));
220 return rc;
222 DEBUG (3, ("StartTLS issued: using a TLS connection\n"));
223 } else {
225 DEBUG(0, ("Need LDAPv3 for Start TLS\n"));
226 return LDAP_OPERATIONS_ERROR;
228 #else
229 DEBUG(0,("smb_ldap_open_connection: StartTLS not supported by LDAP client libraries!\n"));
230 return LDAP_OPERATIONS_ERROR;
231 #endif
234 DEBUG(2, ("smb_ldap_open_connection: connection opened\n"));
235 return rc;
239 /*******************************************************************
240 a rebind function for authenticated referrals
241 This version takes a void* that we can shove useful stuff in :-)
242 ******************************************************************/
243 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
244 #else
245 static int rebindproc_with_state (LDAP * ld, char **whop, char **credp,
246 int *methodp, int freeit, void *arg)
248 struct smb_ldap_privates *ldap_state = arg;
250 /** @TODO Should we be doing something to check what servers we rebind to?
251 Could we get a referral to a machine that we don't want to give our
252 username and password to? */
254 if (freeit) {
255 SAFE_FREE(*whop);
256 memset(*credp, '\0', strlen(*credp));
257 SAFE_FREE(*credp);
258 } else {
259 DEBUG(5,("rebind_proc_with_state: Rebinding as \"%s\"\n",
260 ldap_state->bind_dn));
262 *whop = strdup(ldap_state->bind_dn);
263 if (!*whop) {
264 return LDAP_NO_MEMORY;
266 *credp = strdup(ldap_state->bind_secret);
267 if (!*credp) {
268 SAFE_FREE(*whop);
269 return LDAP_NO_MEMORY;
271 *methodp = LDAP_AUTH_SIMPLE;
273 return 0;
275 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
277 /*******************************************************************
278 a rebind function for authenticated referrals
279 This version takes a void* that we can shove useful stuff in :-)
280 and actually does the connection.
281 ******************************************************************/
282 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
283 static int rebindproc_connect_with_state (LDAP *ldap_struct,
284 LDAP_CONST char *url,
285 ber_tag_t request,
286 ber_int_t msgid, void *arg)
288 struct smb_ldap_privates *ldap_state = arg;
289 int rc;
290 DEBUG(5,("rebindproc_connect_with_state: Rebinding as \"%s\"\n",
291 ldap_state->bind_dn));
293 /** @TODO Should we be doing something to check what servers we rebind to?
294 Could we get a referral to a machine that we don't want to give our
295 username and password to? */
297 rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret);
299 return rc;
301 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
303 /*******************************************************************
304 Add a rebind function for authenticated referrals
305 ******************************************************************/
306 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
307 #else
308 # if LDAP_SET_REBIND_PROC_ARGS == 2
309 static int rebindproc (LDAP *ldap_struct, char **whop, char **credp,
310 int *method, int freeit )
312 return rebindproc_with_state(ldap_struct, whop, credp,
313 method, freeit, get_internal(ldap_struct));
316 # endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/
317 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
319 /*******************************************************************
320 a rebind function for authenticated referrals
321 this also does the connection, but no void*.
322 ******************************************************************/
323 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
324 # if LDAP_SET_REBIND_PROC_ARGS == 2
325 static int rebindproc_connect (LDAP * ld, LDAP_CONST char *url, int request,
326 ber_int_t msgid)
328 return rebindproc_connect_with_state(ld, url, (ber_tag_t)request, msgid,
329 get_internal(ld));
331 # endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/
332 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
334 /*******************************************************************
335 connect to the ldap server under system privilege.
336 ******************************************************************/
337 int smb_ldap_connect_system(struct smb_ldap_privates *ldap_state,
338 LDAP * ldap_struct)
340 int rc;
341 char *ldap_dn;
342 char *ldap_secret;
344 if (NULL == get_internal(ldap_struct)) {
345 ldap_state->next = head;
348 /* get the password */
349 if (!smb_ldap_fetch_pw(&ldap_dn, &ldap_secret))
351 DEBUG(0, ("ldap_connect_system: Failed to retrieve password from secrets.tdb\n"));
352 return LDAP_INVALID_CREDENTIALS;
355 ldap_state->bind_dn = ldap_dn;
356 ldap_state->bind_secret = ldap_secret;
358 /* removed the sasl_bind_s "EXTERNAL" stuff, as my testsuite
359 (OpenLDAP) doesnt' seem to support it */
361 DEBUG(10,("ldap_connect_system: Binding to ldap server %s as \"%s\"\n",
362 ldap_state->uri, ldap_dn));
364 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
365 # if LDAP_SET_REBIND_PROC_ARGS == 2
366 ldap_set_rebind_proc(ldap_struct, &rebindproc_connect);
367 # endif
368 # if LDAP_SET_REBIND_PROC_ARGS == 3
369 ldap_set_rebind_proc(ldap_struct, &rebindproc_connect_with_state, (void *)ldap_state);
370 # endif
371 #else /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
372 # if LDAP_SET_REBIND_PROC_ARGS == 2
373 ldap_set_rebind_proc(ldap_struct, &rebindproc);
374 # endif
375 # if LDAP_SET_REBIND_PROC_ARGS == 3
376 ldap_set_rebind_proc(ldap_struct, &rebindproc_with_state, (void *)ldap_state);
377 # endif
378 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
380 rc = ldap_simple_bind_s(ldap_struct, ldap_dn, ldap_secret);
382 if (rc != LDAP_SUCCESS) {
383 char *ld_error;
384 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
385 &ld_error);
386 DEBUG(0,
387 ("failed to bind to server with dn= %s Error: %s\n\t%s\n",
388 ldap_dn, ldap_err2string(rc),
389 ld_error));
390 free(ld_error);
391 return rc;
394 DEBUG(2, ("ldap_connect_system: succesful connection to the LDAP server\n"));
395 return rc;
398 /**********************************************************************
399 Connect to LDAP server
400 *********************************************************************/
401 int smb_ldap_open(struct smb_ldap_privates *ldap_state)
403 int rc;
404 SMB_ASSERT(ldap_state);
406 #ifndef NO_LDAP_SECURITY
407 if (geteuid() != 0) {
408 DEBUG(0, ("smb_ldap_open: cannot access LDAP when not root..\n"));
409 return LDAP_INSUFFICIENT_ACCESS;
411 #endif
413 if ((ldap_state->ldap_struct != NULL) && ((ldap_state->last_ping + SMB_LDAP_DONT_PING_TIME) < time(NULL))) {
414 struct sockaddr_un addr;
415 socklen_t len;
416 int sd;
417 if (ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_DESC, &sd) == 0 &&
418 getpeername(sd, (struct sockaddr *) &addr, &len) < 0) {
419 /* the other end has died. reopen. */
420 ldap_unbind_ext(ldap_state->ldap_struct, NULL, NULL);
421 ldap_state->ldap_struct = NULL;
422 ldap_state->last_ping = (time_t)0;
423 } else {
424 ldap_state->last_ping = time(NULL);
428 if (ldap_state->ldap_struct != NULL) {
429 DEBUG(5,("smb_ldap_open: allready connected to the LDAP server\n"));
430 return LDAP_SUCCESS;
433 if ((rc = smb_ldap_open_connection(ldap_state, &ldap_state->ldap_struct))) {
434 return rc;
437 if ((rc = smb_ldap_connect_system(ldap_state, ldap_state->ldap_struct))) {
438 ldap_unbind_ext(ldap_state->ldap_struct, NULL, NULL);
439 ldap_state->ldap_struct = NULL;
440 return rc;
444 ldap_state->last_ping = time(NULL);
445 DEBUG(4,("The LDAP server is succesful connected\n"));
447 return LDAP_SUCCESS;
450 /**********************************************************************
451 Disconnect from LDAP server
452 *********************************************************************/
453 NTSTATUS smb_ldap_close(struct smb_ldap_privates *ldap_state)
455 if (!ldap_state)
456 return NT_STATUS_INVALID_PARAMETER;
458 if (ldap_state->ldap_struct != NULL) {
459 ldap_unbind_ext(ldap_state->ldap_struct, NULL, NULL);
460 ldap_state->ldap_struct = NULL;
463 DEBUG(5,("The connection to the LDAP server was closed\n"));
464 /* maybe free the results here --metze */
466 return NT_STATUS_OK;
469 static int smb_ldap_retry_open(struct smb_ldap_privates *ldap_state, int *attempts)
471 int rc;
473 SMB_ASSERT(ldap_state && attempts);
475 if (*attempts != 0) {
476 /* we retry after 0.5, 2, 4.5, 8, 12.5, 18, 24.5 seconds */
477 msleep((((*attempts)*(*attempts))/2)*1000);
479 (*attempts)++;
481 if ((rc = smb_ldap_open(ldap_state))) {
482 DEBUG(0,("Connection to LDAP Server failed for the %d try!\n",*attempts));
483 return rc;
486 return LDAP_SUCCESS;
490 int smb_ldap_search(struct smb_ldap_privates *ldap_state,
491 const char *base, int scope, const char *filter,
492 const char *attrs[], int attrsonly,
493 LDAPMessage **res)
495 int rc = LDAP_SERVER_DOWN;
496 int attempts = 0;
498 SMB_ASSERT(ldap_state);
500 while ((rc == LDAP_SERVER_DOWN) && (attempts < 8)) {
502 if ((rc = smb_ldap_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
503 continue;
505 rc = ldap_search_s(ldap_state->ldap_struct, base, scope,
506 filter, (char **)attrs, attrsonly, res);
509 if (rc == LDAP_SERVER_DOWN) {
510 DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
511 smb_ldap_close(ldap_state);
514 return rc;
517 int smb_ldap_modify(struct smb_ldap_privates *ldap_state, char *dn,
518 LDAPMod *attrs[])
520 int rc = LDAP_SERVER_DOWN;
521 int attempts = 0;
523 if (!ldap_state)
524 return (-1);
526 while ((rc == LDAP_SERVER_DOWN) && (attempts < 8)) {
528 if ((rc = smb_ldap_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
529 continue;
531 rc = ldap_modify_s(ldap_state->ldap_struct, dn, attrs);
534 if (rc == LDAP_SERVER_DOWN) {
535 DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
536 smb_ldap_close(ldap_state);
539 return rc;
542 int smb_ldap_add(struct smb_ldap_privates *ldap_state, const char *dn,
543 LDAPMod *attrs[])
545 int rc = LDAP_SERVER_DOWN;
546 int attempts = 0;
548 if (!ldap_state)
549 return (-1);
551 while ((rc == LDAP_SERVER_DOWN) && (attempts < 8)) {
553 if ((rc = smb_ldap_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
554 continue;
556 rc = ldap_add_s(ldap_state->ldap_struct, dn, attrs);
559 if (rc == LDAP_SERVER_DOWN) {
560 DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
561 smb_ldap_close(ldap_state);
564 return rc;
567 int smb_ldap_delete(struct smb_ldap_privates *ldap_state, char *dn)
569 int rc = LDAP_SERVER_DOWN;
570 int attempts = 0;
572 if (!ldap_state)
573 return (-1);
575 while ((rc == LDAP_SERVER_DOWN) && (attempts < 8)) {
577 if ((rc = smb_ldap_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
578 continue;
580 rc = ldap_delete_s(ldap_state->ldap_struct, dn);
583 if (rc == LDAP_SERVER_DOWN) {
584 DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
585 smb_ldap_close(ldap_state);
588 return rc;
591 int smb_ldap_extended_operation(struct smb_ldap_privates *ldap_state,
592 LDAP_CONST char *reqoid,
593 struct berval *reqdata,
594 LDAPControl **serverctrls,
595 LDAPControl **clientctrls, char **retoidp,
596 struct berval **retdatap)
598 int rc = LDAP_SERVER_DOWN;
599 int attempts = 0;
601 if (!ldap_state)
602 return (-1);
604 while ((rc == LDAP_SERVER_DOWN) && (attempts < 8)) {
606 if ((rc = smb_ldap_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
607 continue;
609 rc = ldap_extended_operation_s(ldap_state->ldap_struct, reqoid, reqdata, serverctrls, clientctrls, retoidp, retdatap);
612 if (rc == LDAP_SERVER_DOWN) {
613 DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
614 smb_ldap_close(ldap_state);
617 return rc;
620 /*******************************************************************
621 search an attribute and return the first value found.
622 ******************************************************************/
623 BOOL smb_ldap_get_single_attribute (LDAP * ldap_struct, LDAPMessage * entry,
624 const char *attribute, pstring value)
626 char **values;
628 if ((values = ldap_get_values (ldap_struct, entry, attribute)) == NULL) {
629 value = NULL;
630 DEBUG (10, ("smb_ldap_get_single_attribute: [%s] = [<does not exist>]\n", attribute));
632 return False;
635 pstrcpy(value, values[0]);
636 ldap_value_free(values);
637 #ifdef DEBUG_PASSWORDS
638 DEBUG (100, ("smb_ldap_get_single_attribute: [%s] = [%s]\n", attribute, value));
639 #endif
640 return True;
644 /************************************************************************
645 Routine to manage the LDAPMod structure array
646 manage memory used by the array, by each struct, and values
648 ************************************************************************/
649 void smb_ldap_make_a_mod (LDAPMod *** modlist, int modop,
650 const char *attribute, const char *value)
652 LDAPMod **mods;
653 int i;
654 int j;
656 mods = *modlist;
658 if (attribute == NULL || *attribute == '\0')
659 return;
661 if (value == NULL || *value == '\0')
662 return;
664 if (mods == NULL)
666 mods = (LDAPMod **) malloc(sizeof(LDAPMod *));
667 if (mods == NULL)
669 DEBUG(0, ("smb_ldap_make_a_mod: out of memory!\n"));
670 return;
672 mods[0] = NULL;
675 for (i = 0; mods[i] != NULL; ++i) {
676 if (mods[i]->mod_op == modop && !strcasecmp(mods[i]->mod_type, attribute))
677 break;
680 if (mods[i] == NULL)
682 mods = (LDAPMod **) Realloc (mods, (i + 2) * sizeof (LDAPMod *));
683 if (mods == NULL)
685 DEBUG(0, ("smb_ldap_make_a_mod: out of memory!\n"));
686 return;
688 mods[i] = (LDAPMod *) malloc(sizeof(LDAPMod));
689 if (mods[i] == NULL)
691 DEBUG(0, ("smb_ldap_make_a_mod: out of memory!\n"));
692 return;
694 mods[i]->mod_op = modop;
695 mods[i]->mod_values = NULL;
696 mods[i]->mod_type = strdup(attribute);
697 mods[i + 1] = NULL;
700 if (value != NULL)
702 j = 0;
703 if (mods[i]->mod_values != NULL) {
704 for (; mods[i]->mod_values[j] != NULL; j++);
706 mods[i]->mod_values = (char **)Realloc(mods[i]->mod_values,
707 (j + 2) * sizeof (char *));
709 if (mods[i]->mod_values == NULL) {
710 DEBUG (0, ("smb_ldap_make_a_mod: Memory allocation failure!\n"));
711 return;
713 mods[i]->mod_values[j] = strdup(value);
714 mods[i]->mod_values[j + 1] = NULL;
716 *modlist = mods;
719 #endif