diff options
Diffstat (limited to 'source/lib')
-rw-r--r-- | source/lib/charcnv.c | 24 | ||||
-rw-r--r-- | source/lib/gencache.c | 29 | ||||
-rw-r--r-- | source/lib/smbldap.c | 734 | ||||
-rw-r--r-- | source/lib/substitute.c | 8 | ||||
-rw-r--r-- | source/lib/system_smbd.c | 24 | ||||
-rw-r--r-- | source/lib/time.c | 3 | ||||
-rw-r--r-- | source/lib/username.c | 70 | ||||
-rw-r--r-- | source/lib/util.c | 5 | ||||
-rw-r--r-- | source/lib/util_str.c | 59 | ||||
-rw-r--r-- | source/lib/util_uuid.c | 6 | ||||
-rw-r--r-- | source/lib/wins_srv.c | 20 |
11 files changed, 913 insertions, 69 deletions
diff --git a/source/lib/charcnv.c b/source/lib/charcnv.c index 708ef343e1a..55cf73d2b11 100644 --- a/source/lib/charcnv.c +++ b/source/lib/charcnv.c @@ -55,6 +55,30 @@ static const char *charset_name(charset_t ch) else if (ch == CH_DISPLAY) ret = lp_display_charset(); else if (ch == CH_UTF8) ret = "UTF8"; +#if defined(HAVE_NL_LANGINFO) && defined(CODESET) + if (ret && strcasecmp(ret, "LOCALE") == 0) { + const char *ln = NULL; + +#ifdef HAVE_SETLOCALE + setlocale(LC_ALL, ""); +#endif + ln = nl_langinfo(CODESET); + if (ln) { + /* Check whether the charset name is supported + by iconv */ + smb_iconv_t handle = smb_iconv_open(ln,"UCS-2LE"); + if (handle == (smb_iconv_t) -1) { + DEBUG(5,("Locale charset '%s' unsupported, using ASCII instead\n", ln)); + ln = NULL; + } else { + DEBUG(5,("Substituting charset '%s' for LOCALE\n", ln)); + smb_iconv_close(handle); + } + } + ret = ln; + } +#endif + if (!ret || !*ret) ret = "ASCII"; return ret; } diff --git a/source/lib/gencache.c b/source/lib/gencache.c index 40b4d1390dc..f3740e3e127 100644 --- a/source/lib/gencache.c +++ b/source/lib/gencache.c @@ -319,9 +319,8 @@ void gencache_iterate(void (*fn)(const char* key, const char *value, time_t time while (node) { /* ensure null termination of the key string */ - node->node_key.dptr[node->node_key.dsize] = '\0'; - keystr = node->node_key.dptr; - + keystr = strndup(node->node_key.dptr, node->node_key.dsize); + /* * We don't use gencache_get function, because we need to iterate through * all of the entries. Validity verification is up to fn routine. @@ -329,6 +328,8 @@ void gencache_iterate(void (*fn)(const char* key, const char *value, time_t time databuf = tdb_fetch(cache, node->node_key); if (!databuf.dptr || databuf.dsize <= TIMEOUT_LEN) { SAFE_FREE(databuf.dptr); + SAFE_FREE(keystr); + node = node->next; continue; } entry = strndup(databuf.dptr, databuf.dsize); @@ -342,8 +343,30 @@ void gencache_iterate(void (*fn)(const char* key, const char *value, time_t time SAFE_FREE(valstr); SAFE_FREE(entry); + SAFE_FREE(keystr); node = node->next; } tdb_search_list_free(first_node); } + +/******************************************************************** + lock a key +********************************************************************/ + +int gencache_lock_entry( const char *key ) +{ + return tdb_lock_bystring(cache, key, 0); +} + +/******************************************************************** + unlock a key +********************************************************************/ + +void gencache_unlock_entry( const char *key ) +{ + tdb_unlock_bystring(cache, key); + return; +} + + diff --git a/source/lib/smbldap.c b/source/lib/smbldap.c index bb37222d5af..84017873177 100644 --- a/source/lib/smbldap.c +++ b/source/lib/smbldap.c @@ -1,7 +1,11 @@ /* Unix SMB/CIFS mplementation. LDAP protocol helper functions for SAMBA + Copyright (C) Jean François Micouleau 1998 Copyright (C) Gerald Carter 2001-2003 + Copyright (C) Shahms King 2001 + Copyright (C) Andrew Bartlett 2002-2003 + Copyright (C) Stefan (metze) Metzmacher 2002 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,6 +26,16 @@ #include "includes.h" #include "smbldap.h" +#ifndef LDAP_OPT_SUCCESS +#define LDAP_OPT_SUCCESS 0 +#endif + +/* Try not to hit the up or down server forever */ + +#define SMBLDAP_DONT_PING_TIME 10 /* ping only all 10 seconds */ +#define SMBLDAP_NUM_RETRIES 8 /* retry only 8 times */ + + /* attributes used by Samba 2.2 */ ATTRIB_MAP_ENTRY attrib_map_v22[] = { @@ -133,7 +147,7 @@ ATTRIB_MAP_ENTRY sidmap_attr_list[] = { perform a simple table lookup and return the attribute name **********************************************************************/ -const char* get_attr_key2string( ATTRIB_MAP_ENTRY table[], int key ) + const char* get_attr_key2string( ATTRIB_MAP_ENTRY table[], int key ) { int i = 0; @@ -151,7 +165,7 @@ const char* get_attr_key2string( ATTRIB_MAP_ENTRY table[], int key ) Return the list of attribute names from a mapping table **********************************************************************/ -char** get_attr_list( ATTRIB_MAP_ENTRY table[] ) + char** get_attr_list( ATTRIB_MAP_ENTRY table[] ) { char **names; int i = 0; @@ -180,7 +194,7 @@ char** get_attr_list( ATTRIB_MAP_ENTRY table[] ) Cleanup ********************************************************************/ -void free_attr_list( char **list ) + void free_attr_list( char **list ) { int i = 0; @@ -262,7 +276,7 @@ BOOL fetch_ldap_pw(char **dn, char** pw) manage memory used by the array, by each struct, and values ***********************************************************************/ -void ldap_set_mod (LDAPMod *** modlist, int modop, const char *attribute, const char *value) + void smbldap_set_mod (LDAPMod *** modlist, int modop, const char *attribute, const char *value) { LDAPMod **mods; int i; @@ -344,3 +358,715 @@ void ldap_set_mod (LDAPMod *** modlist, int modop, const char *attribute, const *modlist = mods; } + +/********************************************************************** + Set attribute to newval in LDAP, regardless of what value the + attribute had in LDAP before. +*********************************************************************/ + void smbldap_make_mod(LDAP *ldap_struct, LDAPMessage *existing, + LDAPMod ***mods, + const char *attribute, const char *newval) +{ + char **values = NULL; + + if (existing != NULL) { + values = ldap_get_values(ldap_struct, existing, attribute); + } + + /* all of our string attributes are case insensitive */ + + if ((values != NULL) && (values[0] != NULL) && + StrCaseCmp(values[0], newval) == 0) + { + + /* Believe it or not, but LDAP will deny a delete and + an add at the same time if the values are the + same... */ + + ldap_value_free(values); + return; + } + + /* Regardless of the real operation (add or modify) + we add the new value here. We rely on deleting + the old value, should it exist. */ + + if ((newval != NULL) && (strlen(newval) > 0)) { + smbldap_set_mod(mods, LDAP_MOD_ADD, attribute, newval); + } + + if (values == NULL) { + /* There has been no value before, so don't delete it. + Here's a possible race: We might end up with + duplicate attributes */ + return; + } + + /* By deleting exactly the value we found in the entry this + should be race-free in the sense that the LDAP-Server will + deny the complete operation if somebody changed the + attribute behind our back. */ + + smbldap_set_mod(mods, LDAP_MOD_DELETE, attribute, values[0]); + ldap_value_free(values); +} + + +/********************************************************************** + Some varients of the LDAP rebind code do not pass in the third 'arg' + pointer to a void*, so we try and work around it by assuming that the + value of the 'LDAP *' pointer is the same as the one we had passed in + **********************************************************************/ + +struct smbldap_state_lookup { + LDAP *ld; + struct smbldap_state *smbldap_state; + struct smbldap_state_lookup *prev, *next; +}; + +static struct smbldap_state_lookup *smbldap_state_lookup_list; + +static struct smbldap_state *smbldap_find_state(LDAP *ld) +{ + struct smbldap_state_lookup *t; + + for (t = smbldap_state_lookup_list; t; t = t->next) { + if (t->ld == ld) { + return t->smbldap_state; + } + } + return NULL; +} + +static void smbldap_delete_state(struct smbldap_state *smbldap_state) +{ + struct smbldap_state_lookup *t; + + for (t = smbldap_state_lookup_list; t; t = t->next) { + if (t->smbldap_state == smbldap_state) { + DLIST_REMOVE(smbldap_state_lookup_list, t); + SAFE_FREE(t); + return; + } + } +} + +static void smbldap_store_state(LDAP *ld, struct smbldap_state *smbldap_state) +{ + struct smbldap_state *tmp_ldap_state; + struct smbldap_state_lookup *t; + struct smbldap_state_lookup *tmp; + + if ((tmp_ldap_state = smbldap_find_state(ld))) { + SMB_ASSERT(tmp_ldap_state == smbldap_state); + return; + } + + t = smb_xmalloc(sizeof(*t)); + ZERO_STRUCTP(t); + + DLIST_ADD_END(smbldap_state_lookup_list, t, tmp); + t->ld = ld; + t->smbldap_state = smbldap_state; +} + +/******************************************************************* + open a connection to the ldap server. +******************************************************************/ +static int smbldap_open_connection (struct smbldap_state *ldap_state) + +{ + int rc = LDAP_SUCCESS; + int version; + BOOL ldap_v3 = False; + LDAP **ldap_struct = &ldap_state->ldap_struct; + +#ifdef HAVE_LDAP_INITIALIZE + DEBUG(10, ("smbldap_open_connection: %s\n", ldap_state->uri)); + + if ((rc = ldap_initialize(ldap_struct, ldap_state->uri)) != LDAP_SUCCESS) { + DEBUG(0, ("ldap_initialize: %s\n", ldap_err2string(rc))); + return rc; + } +#else + + /* Parse the string manually */ + + { + int port = 0; + fstring protocol; + fstring host; + const char *p = ldap_state->uri; + SMB_ASSERT(sizeof(protocol)>10 && sizeof(host)>254); + + /* skip leading "URL:" (if any) */ + if ( strncasecmp( p, "URL:", 4 ) == 0 ) { + p += 4; + } + + sscanf(p, "%10[^:]://%254s[^:]:%d", protocol, host, &port); + + if (port == 0) { + if (strequal(protocol, "ldap")) { + port = LDAP_PORT; + } else if (strequal(protocol, "ldaps")) { + port = LDAPS_PORT; + } else { + DEBUG(0, ("unrecognised protocol (%s)!\n", protocol)); + } + } + + if ((*ldap_struct = ldap_init(host, port)) == NULL) { + DEBUG(0, ("ldap_init failed !\n")); + return LDAP_OPERATIONS_ERROR; + } + + if (strequal(protocol, "ldaps")) { +#ifdef LDAP_OPT_X_TLS + int tls = LDAP_OPT_X_TLS_HARD; + if (ldap_set_option (*ldap_struct, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS) + { + DEBUG(0, ("Failed to setup a TLS session\n")); + } + + DEBUG(3,("LDAPS option set...!\n")); +#else + DEBUG(0,("smbldap_open_connection: Secure connection not supported by LDAP client libraries!\n")); + return LDAP_OPERATIONS_ERROR; +#endif + } + } +#endif + + /* Store the LDAP pointer in a lookup list */ + + smbldap_store_state(*ldap_struct, ldap_state); + + /* Upgrade to LDAPv3 if possible */ + + if (ldap_get_option(*ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS) + { + if (version != LDAP_VERSION3) + { + version = LDAP_VERSION3; + if (ldap_set_option (*ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS) { + ldap_v3 = True; + } + } else { + ldap_v3 = True; + } + } + + if (lp_ldap_ssl() == LDAP_SSL_START_TLS) { +#ifdef LDAP_OPT_X_TLS + if (ldap_v3) { + if ((rc = ldap_start_tls_s (*ldap_struct, NULL, NULL)) != LDAP_SUCCESS) + { + DEBUG(0,("Failed to issue the StartTLS instruction: %s\n", + ldap_err2string(rc))); + return rc; + } + DEBUG (3, ("StartTLS issued: using a TLS connection\n")); + } else { + + DEBUG(0, ("Need LDAPv3 for Start TLS\n")); + return LDAP_OPERATIONS_ERROR; + } +#else + DEBUG(0,("smbldap_open_connection: StartTLS not supported by LDAP client libraries!\n")); + return LDAP_OPERATIONS_ERROR; +#endif + } + + DEBUG(2, ("smbldap_open_connection: connection opened\n")); + return rc; +} + + +/******************************************************************* + a rebind function for authenticated referrals + This version takes a void* that we can shove useful stuff in :-) +******************************************************************/ +#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) +#else +static int rebindproc_with_state (LDAP * ld, char **whop, char **credp, + int *methodp, int freeit, void *arg) +{ + struct smbldap_state *ldap_state = arg; + + /** @TODO Should we be doing something to check what servers we rebind to? + Could we get a referral to a machine that we don't want to give our + username and password to? */ + + if (freeit) { + SAFE_FREE(*whop); + memset(*credp, '\0', strlen(*credp)); + SAFE_FREE(*credp); + } else { + DEBUG(5,("rebind_proc_with_state: Rebinding as \"%s\"\n", + ldap_state->bind_dn)); + + *whop = strdup(ldap_state->bind_dn); + if (!*whop) { + return LDAP_NO_MEMORY; + } + *credp = strdup(ldap_state->bind_secret); + if (!*credp) { + SAFE_FREE(*whop); + return LDAP_NO_MEMORY; + } + *methodp = LDAP_AUTH_SIMPLE; + } + return 0; +} +#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/ + +/******************************************************************* + a rebind function for authenticated referrals + This version takes a void* that we can shove useful stuff in :-) + and actually does the connection. +******************************************************************/ +#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) +static int rebindproc_connect_with_state (LDAP *ldap_struct, + LDAP_CONST char *url, + ber_tag_t request, + ber_int_t msgid, void *arg) +{ + struct smbldap_state *ldap_state = arg; + int rc; + DEBUG(5,("rebindproc_connect_with_state: Rebinding as \"%s\"\n", + ldap_state->bind_dn)); + + /** @TODO Should we be doing something to check what servers we rebind to? + Could we get a referral to a machine that we don't want to give our + username and password to? */ + + rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret); + + return rc; +} +#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/ + +/******************************************************************* + Add a rebind function for authenticated referrals +******************************************************************/ +#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) +#else +# if LDAP_SET_REBIND_PROC_ARGS == 2 +static int rebindproc (LDAP *ldap_struct, char **whop, char **credp, + int *method, int freeit ) +{ + struct smbldap_state *ldap_state = smbldap_find_state(ldap_struct); + + return rebindproc_with_state(ldap_struct, whop, credp, + method, freeit, ldap_state); + +} +# endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/ +#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/ + +/******************************************************************* + a rebind function for authenticated referrals + this also does the connection, but no void*. +******************************************************************/ +#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) +# if LDAP_SET_REBIND_PROC_ARGS == 2 +static int rebindproc_connect (LDAP * ld, LDAP_CONST char *url, int request, + ber_int_t msgid) +{ + struct smbldap_state *ldap_state = smbldap_find_state(ld); + + return rebindproc_connect_with_state(ld, url, (ber_tag_t)request, msgid, + ldap_state); +} +# endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/ +#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/ + +/******************************************************************* + connect to the ldap server under system privilege. +******************************************************************/ +static int smbldap_connect_system(struct smbldap_state *ldap_state, LDAP * ldap_struct) +{ + int rc; + char *ldap_dn; + char *ldap_secret; + + /* get the password */ + if (!fetch_ldap_pw(&ldap_dn, &ldap_secret)) + { + DEBUG(0, ("ldap_connect_system: Failed to retrieve password from secrets.tdb\n")); + return LDAP_INVALID_CREDENTIALS; + } + + ldap_state->bind_dn = ldap_dn; + ldap_state->bind_secret = ldap_secret; + + /* removed the sasl_bind_s "EXTERNAL" stuff, as my testsuite + (OpenLDAP) doesnt' seem to support it */ + + DEBUG(10,("ldap_connect_system: Binding to ldap server %s as \"%s\"\n", + ldap_state->uri, ldap_dn)); + +#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) +# if LDAP_SET_REBIND_PROC_ARGS == 2 + ldap_set_rebind_proc(ldap_struct, &rebindproc_connect); +# endif +# if LDAP_SET_REBIND_PROC_ARGS == 3 + ldap_set_rebind_proc(ldap_struct, &rebindproc_connect_with_state, (void *)ldap_state); +# endif +#else /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/ +# if LDAP_SET_REBIND_PROC_ARGS == 2 + ldap_set_rebind_proc(ldap_struct, &rebindproc); +# endif +# if LDAP_SET_REBIND_PROC_ARGS == 3 + ldap_set_rebind_proc(ldap_struct, &rebindproc_with_state, (void *)ldap_state); +# endif +#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/ + + rc = ldap_simple_bind_s(ldap_struct, ldap_dn, ldap_secret); + + if (rc != LDAP_SUCCESS) { + char *ld_error = NULL; + ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, + &ld_error); + DEBUG(ldap_state->num_failures ? 2 : 0, + ("failed to bind to server with dn= %s Error: %s\n\t%s\n", + ldap_dn ? ldap_dn : "(unknown)", ldap_err2string(rc), + ld_error ? ld_error : "(unknown)")); + SAFE_FREE(ld_error); + ldap_state->num_failures++; + return rc; + } + + ldap_state->num_failures = 0; + + DEBUG(3, ("ldap_connect_system: succesful connection to the LDAP server\n")); + return rc; +} + +/********************************************************************** +Connect to LDAP server (called before every ldap operation) +*********************************************************************/ +static int smbldap_open(struct smbldap_state *ldap_state) +{ + int rc; + SMB_ASSERT(ldap_state); + +#ifndef NO_LDAP_SECURITY + if (geteuid() != 0) { + DEBUG(0, ("smbldap_open: cannot access LDAP when not root..\n")); + return LDAP_INSUFFICIENT_ACCESS; + } +#endif + + if ((ldap_state->ldap_struct != NULL) && ((ldap_state->last_ping + SMBLDAP_DONT_PING_TIME) < time(NULL))) { + struct sockaddr_un addr; + socklen_t len = sizeof(addr); + int sd; + if (ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_DESC, &sd) == 0 && + getpeername(sd, (struct sockaddr *) &addr, &len) < 0) { + /* the other end has died. reopen. */ + ldap_unbind_ext(ldap_state->ldap_struct, NULL, NULL); + ldap_state->ldap_struct = NULL; + ldap_state->last_ping = (time_t)0; + } else { + ldap_state->last_ping = time(NULL); + } + } + + if (ldap_state->ldap_struct != NULL) { + DEBUG(5,("smbldap_open: already connected to the LDAP server\n")); + return LDAP_SUCCESS; + } + + if ((rc = smbldap_open_connection(ldap_state))) { + return rc; + } + + if ((rc = smbldap_connect_system(ldap_state, ldap_state->ldap_struct))) { + ldap_unbind_ext(ldap_state->ldap_struct, NULL, NULL); + ldap_state->ldap_struct = NULL; + return rc; + } + + + ldap_state->last_ping = time(NULL); + DEBUG(4,("The LDAP server is succesful connected\n")); + + return LDAP_SUCCESS; +} + +/********************************************************************** +Disconnect from LDAP server +*********************************************************************/ +static NTSTATUS smbldap_close(struct smbldap_state *ldap_state) +{ + if (!ldap_state) + return NT_STATUS_INVALID_PARAMETER; + + if (ldap_state->ldap_struct != NULL) { + ldap_unbind_ext(ldap_state->ldap_struct, NULL, NULL); + ldap_state->ldap_struct = NULL; + } + + smbldap_delete_state(ldap_state); + + DEBUG(5,("The connection to the LDAP server was closed\n")); + /* maybe free the results here --metze */ + + + + return NT_STATUS_OK; +} + +static int smbldap_retry_open(struct smbldap_state *ldap_state, int *attempts) +{ + int rc; + + SMB_ASSERT(ldap_state && attempts); + + if (*attempts != 0) { + unsigned int sleep_time; + uint8 rand_byte; + + /* Sleep for a random timeout */ + rand_byte = (char)(sys_random()); + + sleep_time = (((*attempts)*(*attempts))/2)*rand_byte*2; + /* we retry after (0.5, 1, 2, 3, 4.5, 6) seconds + on average. + */ + DEBUG(3, ("Sleeping for %u milliseconds before reconnecting\n", + sleep_time)); + msleep(sleep_time); + } + (*attempts)++; + + if ((rc = smbldap_open(ldap_state))) { + DEBUG(1,("Connection to LDAP Server failed for the %d try!\n",*attempts)); + return rc; + } + + return LDAP_SUCCESS; +} + + +/********************************************************************* + ********************************************************************/ + +int smbldap_search(struct smbldap_state *ldap_state, + const char *base, int scope, const char *filter, + char *attrs[], int attrsonly, + LDAPMessage **res) +{ + int rc = LDAP_SERVER_DOWN; + int attempts = 0; + char *utf8_filter; + + SMB_ASSERT(ldap_state); + + if (push_utf8_allocate(&utf8_filter, filter) == (size_t)-1) { + return LDAP_NO_MEMORY; + } + + while ((rc == LDAP_SERVER_DOWN) && (attempts < SMBLDAP_NUM_RETRIES)) { + + if ((rc = smbldap_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS) + continue; + + rc = ldap_search_s(ldap_state->ldap_struct, base, scope, + utf8_filter, attrs, attrsonly, res); + } + + if (rc == LDAP_SERVER_DOWN) { + DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO)); + smbldap_close(ldap_state); + } + + SAFE_FREE(utf8_filter); + return rc; +} + +int smbldap_modify(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs[]) +{ + int rc = LDAP_SERVER_DOWN; + int attempts = 0; + char *utf8_dn; + + SMB_ASSERT(ldap_state); + + if (push_utf8_allocate(&utf8_dn, dn) == (size_t)-1) { + return LDAP_NO_MEMORY; + } + + while ((rc == LDAP_SERVER_DOWN) && (attempts < SMBLDAP_NUM_RETRIES)) { + + if ((rc = smbldap_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS) + continue; + + rc = ldap_modify_s(ldap_state->ldap_struct, utf8_dn, attrs); + } + + if (rc == LDAP_SERVER_DOWN) { + DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO)); + smbldap_close(ldap_state); + } + + SAFE_FREE(utf8_dn); + return rc; +} + +int smbldap_add(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs[]) +{ + int rc = LDAP_SERVER_DOWN; + int attempts = 0; + char *utf8_dn; + + SMB_ASSERT(ldap_state); + + if (push_utf8_allocate(&utf8_dn, dn) == (size_t)-1) { + return LDAP_NO_MEMORY; + } + + while ((rc == LDAP_SERVER_DOWN) && (attempts < SMBLDAP_NUM_RETRIES)) { + + if ((rc = smbldap_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS) + continue; + + rc = ldap_add_s(ldap_state->ldap_struct, utf8_dn, attrs); + } + + if (rc == LDAP_SERVER_DOWN) { + DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO)); + smbldap_close(ldap_state); + } + + SAFE_FREE(utf8_dn); + return rc; +} + +int smbldap_delete(struct smbldap_state *ldap_state, const char *dn) +{ + int rc = LDAP_SERVER_DOWN; + int attempts = 0; + char *utf8_dn; + + SMB_ASSERT(ldap_state); + + if (push_utf8_allocate(&utf8_dn, dn) == (size_t)-1) { + return LDAP_NO_MEMORY; + } + + while ((rc == LDAP_SERVER_DOWN) && (attempts < SMBLDAP_NUM_RETRIES)) { + + if ((rc = smbldap_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS) + continue; + + rc = ldap_delete_s(ldap_state->ldap_struct, utf8_dn); + } + + if (rc == LDAP_SERVER_DOWN) { + DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO)); + smbldap_close(ldap_state); + } + + SAFE_FREE(utf8_dn); + return rc; +} + +int smbldap_extended_operation(struct smbldap_state *ldap_state, + LDAP_CONST char *reqoid, struct berval *reqdata, + LDAPControl **serverctrls, LDAPControl **clientctrls, + char **retoidp, struct berval **retdatap) +{ + int rc = LDAP_SERVER_DOWN; + int attempts = 0; + + if (!ldap_state) + return (-1); + + while ((rc == LDAP_SERVER_DOWN) && (attempts < SMBLDAP_NUM_RETRIES)) { + + if ((rc = smbldap_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS) + continue; + + rc = ldap_extended_operation_s(ldap_state->ldap_struct, reqoid, reqdata, + serverctrls, clientctrls, retoidp, retdatap); + } + + if (rc == LDAP_SERVER_DOWN) { + DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO)); + smbldap_close(ldap_state); + } + + return rc; +} + +/******************************************************************* + run the search by name. +******************************************************************/ +int smbldap_search_suffix (struct smbldap_state *ldap_state, const char *filter, + char **search_attr, LDAPMessage ** result) +{ + int scope = LDAP_SCOPE_SUBTREE; + int rc; + + DEBUG(2, ("smbldap_search_suffix: searching for:[%s]\n", filter)); + + rc = smbldap_search(ldap_state, lp_ldap_suffix(), scope, filter, search_attr, 0, result); + + if (rc != LDAP_SUCCESS) { + char *ld_error = NULL; + ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, + &ld_error); + DEBUG(0,("smbldap_search_suffix: Problem during the LDAP search: %s (%s)\n", + ld_error?ld_error:"(unknown)", ldap_err2string (rc))); + DEBUG(3,("smbldap_search_suffix: Query was: %s, %s\n", lp_ldap_suffix(), + filter)); + SAFE_FREE(ld_error); + } + + return rc; +} + +/********************************************************************** + Housekeeping + *********************************************************************/ + +void smbldap_free_struct(struct smbldap_state **ldap_state) +{ + smbldap_close(*ldap_state); + + if ((*ldap_state)->bind_secret) { + memset((*ldap_state)->bind_secret, '\0', strlen((*ldap_state)->bind_secret)); + } + + SAFE_FREE((*ldap_state)->bind_dn); + SAFE_FREE((*ldap_state)->bind_secret); + + *ldap_state = NULL; + + /* No need to free any further, as it is talloc()ed */ +} + + +/********************************************************************** + Intitalise the 'general' ldap structures, on which ldap operations may be conducted + *********************************************************************/ + +NTSTATUS smbldap_init(TALLOC_CTX *mem_ctx, const char *location, struct smbldap_state **smbldap_state) +{ + *smbldap_state = talloc_zero(mem_ctx, sizeof(**smbldap_state)); + if (!*smbldap_state) { + DEBUG(0, ("talloc() failed for ldapsam private_data!\n")); + return NT_STATUS_NO_MEMORY; + } + + if (location) { + (*smbldap_state)->uri = talloc_strdup(mem_ctx, location); + } else { + (*smbldap_state)->uri = "ldap://localhost"; + } + return NT_STATUS_OK; +} + diff --git a/source/lib/substitute.c b/source/lib/substitute.c index 7ba86481560..a53a50a060e 100644 --- a/source/lib/substitute.c +++ b/source/lib/substitute.c @@ -650,7 +650,7 @@ char *talloc_sub_advanced(TALLOC_CTX *mem_ctx, const char *connectpath, gid_t gid, const char *smb_name, - char *str) + const char *str) { char *a, *t; a = alloc_sub_advanced(snum, user, connectpath, gid, smb_name, str); @@ -662,7 +662,7 @@ char *talloc_sub_advanced(TALLOC_CTX *mem_ctx, char *alloc_sub_advanced(int snum, const char *user, const char *connectpath, gid_t gid, - const char *smb_name, char *str) + const char *smb_name, const char *str) { char *a_string, *ret_string; char *b, *p, *s, *t, *h; @@ -736,14 +736,14 @@ void standard_sub_conn(connection_struct *conn, char *str, size_t len) conn->gid, smb_user_name, str, len); } -char *talloc_sub_conn(TALLOC_CTX *mem_ctx, connection_struct *conn, char *str) +char *talloc_sub_conn(TALLOC_CTX *mem_ctx, connection_struct *conn, const char *str) { return talloc_sub_advanced(mem_ctx, SNUM(conn), conn->user, conn->connectpath, conn->gid, smb_user_name, str); } -char *alloc_sub_conn(connection_struct *conn, char *str) +char *alloc_sub_conn(connection_struct *conn, const char *str) { return alloc_sub_advanced(SNUM(conn), conn->user, conn->connectpath, conn->gid, smb_user_name, str); diff --git a/source/lib/system_smbd.c b/source/lib/system_smbd.c index 3ae0a6395ed..3498307acb5 100644 --- a/source/lib/system_smbd.c +++ b/source/lib/system_smbd.c @@ -107,13 +107,31 @@ static int getgrouplist_internals(const char *user, gid_t gid, gid_t *groups, in int sys_getgrouplist(const char *user, gid_t gid, gid_t *groups, int *grpcnt) { + char *p; + int retval; + + DEBUG(10,("sys_getgrouplist: user [%s]\n", user)); + + /* see if we should disable winbindd lookups for local users */ + if ( (p = strchr(user, *lp_winbind_separator())) == NULL ) { + if ( setenv(WINBINDD_DONT_ENV, "1", 1) == -1 ) + DEBUG(0,("sys_getgroup_list: Insufficient environment space for %s\n", + WINBINDD_DONT_ENV)); + else + DEBUG(10,("sys_getgrouplist(): disabled winbindd for group lookup [user == %s]\n", + user)); + } + #ifdef HAVE_GETGROUPLIST - return getgrouplist(user, gid, groups, grpcnt); + retval = getgrouplist(user, gid, groups, grpcnt); #else - int retval; become_root(); retval = getgrouplist_internals(user, gid, groups, grpcnt); unbecome_root(); - return retval; #endif + + /* allow winbindd lookups */ + setenv( WINBINDD_DONT_ENV, "0", 1); + + return retval; } diff --git a/source/lib/time.c b/source/lib/time.c index f76a1bdc0d8..5309711a056 100644 --- a/source/lib/time.c +++ b/source/lib/time.c @@ -308,7 +308,8 @@ time_t nt_time_to_unix(NTTIME *nt) time_t l_time_min = TIME_T_MIN; time_t l_time_max = TIME_T_MAX; - if (nt->high == 0) return(0); + if (nt->high == 0 || (nt->high == 0xffffffff && nt->low == 0xffffffff)) + return(0); d = ((double)nt->high)*4.0*(double)(1<<30); d += (nt->low&0xFFF00000); diff --git a/source/lib/username.c b/source/lib/username.c index d8f4ff80edb..0005372a8f8 100644 --- a/source/lib/username.c +++ b/source/lib/username.c @@ -325,11 +325,12 @@ static BOOL user_in_netgroup_list(const char *user, const char *ngname) static BOOL user_in_winbind_group_list(const char *user, const char *gname, BOOL *winbind_answered) { - int num_groups; int i; - gid_t *groups = NULL; gid_t gid, gid_low, gid_high; BOOL ret = False; + static gid_t *groups = NULL; + static int num_groups = 0; + static fstring last_user = ""; *winbind_answered = False; @@ -349,27 +350,44 @@ static BOOL user_in_winbind_group_list(const char *user, const char *gname, BOOL goto err; } - /* - * Get the gid's that this user belongs to. - */ - - if ((num_groups = winbind_getgroups(user, 0, NULL)) == -1) - return False; + /* try to user the last user we looked up */ + /* otherwise fall back to lookups */ + + if ( !strequal( last_user, user ) || !groups ) + { + /* clear any cached information */ + + SAFE_FREE(groups); + fstrcpy( last_user, "" ); + + /* + * Get the gid's that this user belongs to. + */ - if (num_groups == 0) { - *winbind_answered = True; - return False; - } + if ((num_groups = winbind_getgroups(user, &groups)) == -1) + return False; + + if ( num_groups == -1 ) + return False; - if ((groups = (gid_t *)malloc(sizeof(gid_t) * num_groups )) == NULL) { - DEBUG(0,("user_in_winbind_group_list: malloc fail.\n")); - goto err; - } + if ( num_groups == 0 ) { + *winbind_answered = True; + return False; + } + + /* save the last username */ + + fstrcpy( last_user, user ); + + } + else + DEBUG(10,("user_in_winbind_group_list: using cached user groups for [%s]\n", user)); - if ((num_groups = winbind_getgroups(user, num_groups, groups)) == -1) { - DEBUG(0,("user_in_winbind_group_list: second winbind_getgroups call \ -failed with error %s\n", strerror(errno) )); - goto err; + if ( DEBUGLEVEL >= 10 ) { + DEBUG(10,("user_in_winbind_group_list: using groups -- ")); + for ( i=0; i<num_groups; i++ ) + DEBUGADD(10,("%d ", groups[i])); + DEBUGADD(10,("\n")); } /* @@ -571,10 +589,16 @@ BOOL user_in_list(const char *user,const char **list, gid_t *groups, size_t n_gr fstrcpy(domain, *list); domain[PTR_DIFF(p, *list)] = 0; - /* Check to see if name is a Windows group */ - if (winbind_lookup_name(domain, groupname, &g_sid, &name_type) && name_type == SID_NAME_DOM_GRP) { + /* Check to see if name is a Windows group; Win2k native mode DCs + will return domain local groups; while NT4 or mixed mode 2k DCs + will not */ + + if ( winbind_lookup_name(NULL, *list, &g_sid, &name_type) + && ( name_type==SID_NAME_DOM_GRP || + (strequal(lp_workgroup(), domain) && name_type==SID_NAME_ALIAS) ) ) + { - /* Check if user name is in the Windows group */ + /* Check if user name is in the Windows group */ ret = user_in_winbind_group_list(user, *list, &winbind_answered); if (winbind_answered && ret == True) { diff --git a/source/lib/util.c b/source/lib/util.c index 95d3403a7cd..a99e2163db5 100644 --- a/source/lib/util.c +++ b/source/lib/util.c @@ -2345,9 +2345,9 @@ BOOL mask_match(const char *string, char *pattern, BOOL is_case_sensitive) Recursive routine that is called by unix_wild_match. *********************************************************/ -static BOOL unix_do_match(char *regexp, char *str) +static BOOL unix_do_match(const char *regexp, const char *str) { - char *p; + const char *p; for( p = regexp; *p && *str; ) { @@ -2467,6 +2467,7 @@ BOOL unix_wild_match(const char *pattern, const char *string) return unix_do_match(p2, s2) == 0; } + #ifdef __INSURE__ /******************************************************************* diff --git a/source/lib/util_str.c b/source/lib/util_str.c index 87a8ea2eb19..af8d6aa04ca 100644 --- a/source/lib/util_str.c +++ b/source/lib/util_str.c @@ -38,6 +38,7 @@ BOOL next_token(const char **ptr,char *buff, const char *sep, size_t bufsize) { const char *s; + char *pbuf; BOOL quoted; size_t len=1; @@ -59,17 +60,18 @@ BOOL next_token(const char **ptr,char *buff, const char *sep, size_t bufsize) return(False); /* copy over the token */ + pbuf = buff; for (quoted = False; len < bufsize && *s && (quoted || !strchr_m(sep,*s)); s++) { if (*s == '\"') { quoted = !quoted; } else { len++; - *buff++ = *s; + *pbuf++ = *s; } } *ptr = (*s) ? s+1 : s; - *buff = 0; + *pbuf = 0; return(True); } @@ -1469,6 +1471,7 @@ BOOL str_list_substitute(char **list, const char *pattern, const char *insert) #define IPSTR_LIST_SEP "," +#define IPSTR_LIST_CHAR ',' /** * Add ip string representation to ipstr list. Used also @@ -1483,19 +1486,20 @@ BOOL str_list_substitute(char **list, const char *pattern, const char *insert) * reallocated to new length **/ -char* ipstr_list_add(char** ipstr_list, const struct in_addr *ip) +char* ipstr_list_add(char** ipstr_list, const struct ip_service *service) { char* new_ipstr = NULL; /* arguments checking */ - if (!ipstr_list || !ip) return NULL; + if (!ipstr_list || !service) return NULL; /* attempt to convert ip to a string and append colon separator to it */ if (*ipstr_list) { - asprintf(&new_ipstr, "%s%s%s", *ipstr_list, IPSTR_LIST_SEP,inet_ntoa(*ip)); + asprintf(&new_ipstr, "%s%s%s:%d", *ipstr_list, IPSTR_LIST_SEP, + inet_ntoa(service->ip), service->port); SAFE_FREE(*ipstr_list); } else { - asprintf(&new_ipstr, "%s", inet_ntoa(*ip)); + asprintf(&new_ipstr, "%s:%d", inet_ntoa(service->ip), service->port); } *ipstr_list = new_ipstr; return *ipstr_list; @@ -1512,7 +1516,7 @@ char* ipstr_list_add(char** ipstr_list, const struct in_addr *ip) * @return pointer to allocated ip string **/ -char* ipstr_list_make(char** ipstr_list, const struct in_addr* ip_list, int ip_count) +char* ipstr_list_make(char** ipstr_list, const struct ip_service* ip_list, int ip_count) { int i; @@ -1531,7 +1535,8 @@ char* ipstr_list_make(char** ipstr_list, const struct in_addr* ip_list, int ip_c /** * Parse given ip string list into array of ip addresses - * (as in_addr structures) + * (as ip_service structures) + * e.g. 192.168.1.100:389,192.168.1.78, ... * * @param ipstr ip string list to be parsed * @param ip_list pointer to array of ip addresses which is @@ -1539,28 +1544,40 @@ char* ipstr_list_make(char** ipstr_list, const struct in_addr* ip_list, int ip_c * @return number of succesfully parsed addresses **/ -int ipstr_list_parse(const char* ipstr_list, struct in_addr** ip_list) +int ipstr_list_parse(const char* ipstr_list, struct ip_service **ip_list) { fstring token_str; - int count; + size_t count; + int i; - if (!ipstr_list || !ip_list) return 0; + if (!ipstr_list || !ip_list) + return 0; + + count = count_chars(ipstr_list, IPSTR_LIST_CHAR) + 1; + if ( (*ip_list = (struct ip_service*)malloc(count * sizeof(struct ip_service))) == NULL ) { + DEBUG(0,("ipstr_list_parse: malloc failed for %d entries\n", count)); + return 0; + } - for (*ip_list = NULL, count = 0; - next_token(&ipstr_list, token_str, IPSTR_LIST_SEP, FSTRING_LEN); - count++) { - + for ( i=0; + next_token(&ipstr_list, token_str, IPSTR_LIST_SEP, FSTRING_LEN) && i<count; + i++ ) + { struct in_addr addr; + unsigned port = 0; + char *p = strchr(token_str, ':'); + + if (p) { + *p = 0; + port = atoi(p+1); + } /* convert single token to ip address */ if ( (addr.s_addr = inet_addr(token_str)) == INADDR_NONE ) break; - - /* prepare place for another in_addr structure */ - *ip_list = Realloc(*ip_list, (count + 1) * sizeof(struct in_addr)); - if (!*ip_list) return -1; - - (*ip_list)[count] = addr; + + (*ip_list)[i].ip = addr; + (*ip_list)[i].port = port; } return count; diff --git a/source/lib/util_uuid.c b/source/lib/util_uuid.c index 699f2cd6325..83553ec28ec 100644 --- a/source/lib/util_uuid.c +++ b/source/lib/util_uuid.c @@ -58,7 +58,7 @@ static void uuid_unpack(const GUID in, struct uuid *uu) memcpy(uu->node, ptr+10, 6); } -void uuid_generate_random(GUID *out) +void smb_uuid_generate_random(GUID *out) { GUID tmp; struct uuid uu; @@ -71,7 +71,7 @@ void uuid_generate_random(GUID *out) uuid_pack(&uu, out); } -char *guid_to_string(const GUID in) +char *smb_uuid_to_string(const GUID in) { struct uuid uu; char *out; @@ -87,7 +87,7 @@ char *guid_to_string(const GUID in) return out; } -const char *uuid_string_static(const GUID in) +const char *smb_uuid_string_static(const GUID in) { struct uuid uu; static char out[37]; diff --git a/source/lib/wins_srv.c b/source/lib/wins_srv.c index 3372f74dcbe..4a54762fde7 100644 --- a/source/lib/wins_srv.c +++ b/source/lib/wins_srv.c @@ -70,14 +70,24 @@ static char *wins_srv_keystr(struct in_addr wins_ip, struct in_addr src_ip) { - char *keystr; + char *keystr = NULL, *wins_ip_addr = NULL, *src_ip_addr = NULL; - if (asprintf(&keystr, WINS_SRV_FMT, inet_ntoa(wins_ip), - inet_ntoa(src_ip)) == -1) { - DEBUG(0, ("wins_srv_is_dead: malloc error\n")); - return NULL; + wins_ip_addr = strdup(inet_ntoa(wins_ip)); + src_ip_addr = strdup(inet_ntoa(src_ip)); + + if ( !wins_ip_addr || !src_ip_addr ) { + DEBUG(0,("wins_srv_keystr: malloc error\n")); + goto done; } + if (asprintf(&keystr, WINS_SRV_FMT, wins_ip_addr, src_ip_addr) == -1) { + DEBUG(0, (": ns_srv_keystr: malloc error for key string\n")); + } + +done: + SAFE_FREE(wins_ip_addr); + SAFE_FREE(src_ip_addr); + return keystr; } |