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.
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
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
) {
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
)
77 *dn
= smb_xstrdup(lp_ldap_admin_dn());
79 if (asprintf(&key
, "%s/%s", SECRETS_LDAP_BIND_PW
, *dn
) < 0) {
81 DEBUG(0, ("smb_ldap_fetch_pw: asprintf failed!\n"));
84 *pw
=secrets_fetch(key
, &size
);
87 /* Upgrade 2.2 style entry */
89 char* old_style_key
= strdup(*dn
);
94 DEBUG(0, ("smb_ldap_fetch_pw: strdup failed!\n"));
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
);
109 strncpy(old_style_pw
, data
, size
);
110 old_style_pw
[size
] = 0;
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
);
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
);
132 /*******************************************************************
133 open a connection to the ldap server.
134 ******************************************************************/
135 int smb_ldap_open_connection (struct smb_ldap_privates
*ldap_state
,
138 int rc
= LDAP_SUCCESS
;
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
)));
152 /* Parse the string manually */
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 ) {
166 sscanf(p
, "%10[^:]://%254s[^:]:%d", protocol
, host
, &port
);
169 if (strequal(protocol
, "ldap")) {
171 } else if (strequal(protocol
, "ldaps")) {
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"));
193 DEBUG(0,("smb_ldap_open_connection: Secure connection not supported by LDAP client libraries!\n"));
194 return LDAP_OPERATIONS_ERROR
;
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
) {
213 if (lp_ldap_ssl() == LDAP_SSL_START_TLS
) {
214 #ifdef LDAP_OPT_X_TLS
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
)));
222 DEBUG (3, ("StartTLS issued: using a TLS connection\n"));
225 DEBUG(0, ("Need LDAPv3 for Start TLS\n"));
226 return LDAP_OPERATIONS_ERROR
;
229 DEBUG(0,("smb_ldap_open_connection: StartTLS not supported by LDAP client libraries!\n"));
230 return LDAP_OPERATIONS_ERROR
;
234 DEBUG(2, ("smb_ldap_open_connection: connection opened\n"));
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)
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? */
256 memset(*credp
, '\0', strlen(*credp
));
259 DEBUG(5,("rebind_proc_with_state: Rebinding as \"%s\"\n",
260 ldap_state
->bind_dn
));
262 *whop
= strdup(ldap_state
->bind_dn
);
264 return LDAP_NO_MEMORY
;
266 *credp
= strdup(ldap_state
->bind_secret
);
269 return LDAP_NO_MEMORY
;
271 *methodp
= LDAP_AUTH_SIMPLE
;
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
,
286 ber_int_t msgid
, void *arg
)
288 struct smb_ldap_privates
*ldap_state
= arg
;
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
);
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)
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
,
328 return rebindproc_connect_with_state(ld
, url
, (ber_tag_t
)request
, msgid
,
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
,
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
);
368 # if LDAP_SET_REBIND_PROC_ARGS == 3
369 ldap_set_rebind_proc(ldap_struct
, &rebindproc_connect_with_state
, (void *)ldap_state
);
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
);
375 # if LDAP_SET_REBIND_PROC_ARGS == 3
376 ldap_set_rebind_proc(ldap_struct
, &rebindproc_with_state
, (void *)ldap_state
);
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
) {
384 ldap_get_option(ldap_state
->ldap_struct
, LDAP_OPT_ERROR_STRING
,
387 ("failed to bind to server with dn= %s Error: %s\n\t%s\n",
388 ldap_dn
, ldap_err2string(rc
),
394 DEBUG(2, ("ldap_connect_system: succesful connection to the LDAP server\n"));
398 /**********************************************************************
399 Connect to LDAP server
400 *********************************************************************/
401 int smb_ldap_open(struct smb_ldap_privates
*ldap_state
)
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
;
413 if ((ldap_state
->ldap_struct
!= NULL
) && ((ldap_state
->last_ping
+ SMB_LDAP_DONT_PING_TIME
) < time(NULL
))) {
414 struct sockaddr_un addr
;
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;
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"));
433 if ((rc
= smb_ldap_open_connection(ldap_state
, &ldap_state
->ldap_struct
))) {
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
;
444 ldap_state
->last_ping
= time(NULL
);
445 DEBUG(4,("The LDAP server is succesful connected\n"));
450 /**********************************************************************
451 Disconnect from LDAP server
452 *********************************************************************/
453 NTSTATUS
smb_ldap_close(struct smb_ldap_privates
*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 */
469 static int smb_ldap_retry_open(struct smb_ldap_privates
*ldap_state
, int *attempts
)
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);
481 if ((rc
= smb_ldap_open(ldap_state
))) {
482 DEBUG(0,("Connection to LDAP Server failed for the %d try!\n",*attempts
));
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
,
495 int rc
= LDAP_SERVER_DOWN
;
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
)
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
);
517 int smb_ldap_modify(struct smb_ldap_privates
*ldap_state
, char *dn
,
520 int rc
= LDAP_SERVER_DOWN
;
526 while ((rc
== LDAP_SERVER_DOWN
) && (attempts
< 8)) {
528 if ((rc
= smb_ldap_retry_open(ldap_state
,&attempts
)) != LDAP_SUCCESS
)
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
);
542 int smb_ldap_add(struct smb_ldap_privates
*ldap_state
, const char *dn
,
545 int rc
= LDAP_SERVER_DOWN
;
551 while ((rc
== LDAP_SERVER_DOWN
) && (attempts
< 8)) {
553 if ((rc
= smb_ldap_retry_open(ldap_state
,&attempts
)) != LDAP_SUCCESS
)
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
);
567 int smb_ldap_delete(struct smb_ldap_privates
*ldap_state
, char *dn
)
569 int rc
= LDAP_SERVER_DOWN
;
575 while ((rc
== LDAP_SERVER_DOWN
) && (attempts
< 8)) {
577 if ((rc
= smb_ldap_retry_open(ldap_state
,&attempts
)) != LDAP_SUCCESS
)
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
);
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
;
604 while ((rc
== LDAP_SERVER_DOWN
) && (attempts
< 8)) {
606 if ((rc
= smb_ldap_retry_open(ldap_state
,&attempts
)) != LDAP_SUCCESS
)
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
);
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
)
628 if ((values
= ldap_get_values (ldap_struct
, entry
, attribute
)) == NULL
) {
630 DEBUG (10, ("smb_ldap_get_single_attribute: [%s] = [<does not exist>]\n", attribute
));
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
));
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
)
658 if (attribute
== NULL
|| *attribute
== '\0')
661 if (value
== NULL
|| *value
== '\0')
666 mods
= (LDAPMod
**) malloc(sizeof(LDAPMod
*));
669 DEBUG(0, ("smb_ldap_make_a_mod: out of memory!\n"));
675 for (i
= 0; mods
[i
] != NULL
; ++i
) {
676 if (mods
[i
]->mod_op
== modop
&& !strcasecmp(mods
[i
]->mod_type
, attribute
))
682 mods
= (LDAPMod
**) Realloc (mods
, (i
+ 2) * sizeof (LDAPMod
*));
685 DEBUG(0, ("smb_ldap_make_a_mod: out of memory!\n"));
688 mods
[i
] = (LDAPMod
*) malloc(sizeof(LDAPMod
));
691 DEBUG(0, ("smb_ldap_make_a_mod: out of memory!\n"));
694 mods
[i
]->mod_op
= modop
;
695 mods
[i
]->mod_values
= NULL
;
696 mods
[i
]->mod_type
= strdup(attribute
);
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"));
713 mods
[i
]->mod_values
[j
] = strdup(value
);
714 mods
[i
]->mod_values
[j
+ 1] = NULL
;