LCOV - code coverage report
Current view: top level - source3/lib - smbldap.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 12 806 1.5 %
Date: 2024-04-21 15:09:00 Functions: 2 57 3.5 %

          Line data    Source code
       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-2003
       6             :    Copyright (C) Shahms King                    2001
       7             :    Copyright (C) Andrew Bartlett                2002-2003
       8             :    Copyright (C) Stefan (metze) Metzmacher      2002-2003
       9             : 
      10             :    This program is free software; you can redistribute it and/or modify
      11             :    it under the terms of the GNU General Public License as published by
      12             :    the Free Software Foundation; either version 3 of the License, or
      13             :    (at your option) any later version.
      14             : 
      15             :    This program is distributed in the hope that it will be useful,
      16             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :    GNU General Public License for more details.
      19             : 
      20             :    You should have received a copy of the GNU General Public License
      21             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      22             : 
      23             : */
      24             : 
      25             : #include "includes.h"
      26             : #include "smbldap.h"
      27             : #include "../libcli/security/security.h"
      28             : #include <tevent.h>
      29             : #include "lib/param/loadparm.h"
      30             : 
      31             : /* Try not to hit the up or down server forever */
      32             : 
      33             : #define SMBLDAP_DONT_PING_TIME 10       /* ping only all 10 seconds */
      34             : #define SMBLDAP_NUM_RETRIES 8           /* retry only 8 times */
      35             : 
      36             : #define SMBLDAP_IDLE_TIME 150           /* After 2.5 minutes disconnect */
      37             : 
      38             : struct smbldap_state {
      39             :         LDAP *ldap_struct;
      40             :         pid_t pid;
      41             :         time_t last_ping; /* monotonic */
      42             :         /* retrieve-once info */
      43             :         const char *uri;
      44             : 
      45             :         /* credentials */
      46             :         bool anonymous;
      47             :         char *bind_dn;
      48             :         char *bind_secret;
      49             :         smbldap_bind_callback_fn bind_callback;
      50             :         void *bind_callback_data;
      51             : 
      52             :         bool paged_results;
      53             : 
      54             :         unsigned int num_failures;
      55             : 
      56             :         time_t last_use; /* monotonic */
      57             :         struct tevent_context *tevent_context;
      58             :         struct tevent_timer *idle_event;
      59             : 
      60             :         struct timeval last_rebind; /* monotonic */
      61             : };
      62             : 
      63           0 : LDAP *smbldap_get_ldap(struct smbldap_state *state)
      64             : {
      65           0 :         return state->ldap_struct;
      66             : }
      67             : 
      68           0 : bool smbldap_get_paged_results(struct smbldap_state *state)
      69             : {
      70           0 :         return state->paged_results;
      71             : }
      72             : 
      73           0 : void smbldap_set_paged_results(struct smbldap_state *state,
      74             :                                bool paged_results)
      75             : {
      76           0 :         state->paged_results = paged_results;
      77           0 : }
      78             : 
      79           0 : void smbldap_set_bind_callback(struct smbldap_state *state,
      80             :                                smbldap_bind_callback_fn callback,
      81             :                                void *callback_data)
      82             : {
      83           0 :         state->bind_callback = callback;
      84           0 :         state->bind_callback_data = callback_data;
      85           0 : }
      86             : /*******************************************************************
      87             :  Search an attribute and return the first value found.
      88             : ******************************************************************/
      89             : 
      90           0 :  bool smbldap_get_single_attribute (LDAP * ldap_struct, LDAPMessage * entry,
      91             :                                     const char *attribute, char *value,
      92             :                                     int max_len)
      93             : {
      94           0 :         char **values;
      95           0 :         size_t size = 0;
      96             : 
      97           0 :         if ( !attribute )
      98           0 :                 return False;
      99             : 
     100           0 :         value[0] = '\0';
     101             : 
     102           0 :         if ((values = ldap_get_values (ldap_struct, entry, attribute)) == NULL) {
     103           0 :                 DEBUG (10, ("smbldap_get_single_attribute: [%s] = [<does not exist>]\n", attribute));
     104             : 
     105           0 :                 return False;
     106             :         }
     107             : 
     108           0 :         if (!convert_string(CH_UTF8, CH_UNIX,values[0], -1, value, max_len, &size)) {
     109           0 :                 DEBUG(1, ("smbldap_get_single_attribute: string conversion of [%s] = [%s] failed!\n",
     110             :                           attribute, values[0]));
     111           0 :                 ldap_value_free(values);
     112           0 :                 return False;
     113             :         }
     114             : 
     115           0 :         ldap_value_free(values);
     116             : #ifdef DEBUG_PASSWORDS
     117             :         DEBUG (100, ("smbldap_get_single_attribute: [%s] = [%s]\n", attribute, value));
     118             : #endif
     119           0 :         return True;
     120             : }
     121             : 
     122           0 :  char * smbldap_talloc_single_attribute(LDAP *ldap_struct, LDAPMessage *entry,
     123             :                                         const char *attribute,
     124             :                                         TALLOC_CTX *mem_ctx)
     125             : {
     126           0 :         char **values;
     127           0 :         char *result;
     128           0 :         size_t converted_size;
     129             : 
     130           0 :         if (attribute == NULL) {
     131           0 :                 return NULL;
     132             :         }
     133             : 
     134           0 :         values = ldap_get_values(ldap_struct, entry, attribute);
     135             : 
     136           0 :         if (values == NULL) {
     137           0 :                 DEBUG(10, ("attribute %s does not exist\n", attribute));
     138           0 :                 return NULL;
     139             :         }
     140             : 
     141           0 :         if (ldap_count_values(values) != 1) {
     142           0 :                 DEBUG(10, ("attribute %s has %d values, expected only one\n",
     143             :                            attribute, ldap_count_values(values)));
     144           0 :                 ldap_value_free(values);
     145           0 :                 return NULL;
     146             :         }
     147             : 
     148           0 :         if (!pull_utf8_talloc(mem_ctx, &result, values[0], &converted_size)) {
     149           0 :                 DEBUG(10, ("pull_utf8_talloc failed\n"));
     150           0 :                 ldap_value_free(values);
     151           0 :                 return NULL;
     152             :         }
     153             : 
     154           0 :         ldap_value_free(values);
     155             : 
     156             : #ifdef DEBUG_PASSWORDS
     157             :         DEBUG (100, ("smbldap_get_single_attribute: [%s] = [%s]\n",
     158             :                      attribute, result));
     159             : #endif
     160           0 :         return result;
     161             : }
     162             : 
     163           0 :  char * smbldap_talloc_first_attribute(LDAP *ldap_struct, LDAPMessage *entry,
     164             :                                        const char *attribute,
     165             :                                        TALLOC_CTX *mem_ctx)
     166             : {
     167           0 :         char **values;
     168           0 :         char *result;
     169           0 :         size_t converted_size;
     170             : 
     171           0 :         if (attribute == NULL) {
     172           0 :                 return NULL;
     173             :         }
     174             : 
     175           0 :         values = ldap_get_values(ldap_struct, entry, attribute);
     176             : 
     177           0 :         if (values == NULL) {
     178           0 :                 DEBUG(10, ("attribute %s does not exist\n", attribute));
     179           0 :                 return NULL;
     180             :         }
     181             : 
     182           0 :         if (!pull_utf8_talloc(mem_ctx, &result, values[0], &converted_size)) {
     183           0 :                 DEBUG(10, ("pull_utf8_talloc failed\n"));
     184           0 :                 ldap_value_free(values);
     185           0 :                 return NULL;
     186             :         }
     187             : 
     188           0 :         ldap_value_free(values);
     189             : 
     190             : #ifdef DEBUG_PASSWORDS
     191             :         DEBUG (100, ("smbldap_get_first_attribute: [%s] = [%s]\n",
     192             :                      attribute, result));
     193             : #endif
     194           0 :         return result;
     195             : }
     196             : 
     197           0 :  char * smbldap_talloc_smallest_attribute(LDAP *ldap_struct, LDAPMessage *entry,
     198             :                                           const char *attribute,
     199             :                                           TALLOC_CTX *mem_ctx)
     200             : {
     201           0 :         char **values;
     202           0 :         char *result;
     203           0 :         size_t converted_size;
     204           0 :         int i, num_values;
     205             : 
     206           0 :         if (attribute == NULL) {
     207           0 :                 return NULL;
     208             :         }
     209             : 
     210           0 :         values = ldap_get_values(ldap_struct, entry, attribute);
     211             : 
     212           0 :         if (values == NULL) {
     213           0 :                 DEBUG(10, ("attribute %s does not exist\n", attribute));
     214           0 :                 return NULL;
     215             :         }
     216             : 
     217           0 :         if (!pull_utf8_talloc(mem_ctx, &result, values[0], &converted_size)) {
     218           0 :                 DEBUG(10, ("pull_utf8_talloc failed\n"));
     219           0 :                 ldap_value_free(values);
     220           0 :                 return NULL;
     221             :         }
     222             : 
     223           0 :         num_values = ldap_count_values(values);
     224             : 
     225           0 :         for (i=1; i<num_values; i++) {
     226           0 :                 char *tmp;
     227             : 
     228           0 :                 if (!pull_utf8_talloc(mem_ctx, &tmp, values[i],
     229             :                                       &converted_size)) {
     230           0 :                         DEBUG(10, ("pull_utf8_talloc failed\n"));
     231           0 :                         TALLOC_FREE(result);
     232           0 :                         ldap_value_free(values);
     233           0 :                         return NULL;
     234             :                 }
     235             : 
     236           0 :                 if (strcasecmp_m(tmp, result) < 0) {
     237           0 :                         TALLOC_FREE(result);
     238           0 :                         result = tmp;
     239             :                 } else {
     240           0 :                         TALLOC_FREE(tmp);
     241             :                 }
     242             :         }
     243             : 
     244           0 :         ldap_value_free(values);
     245             : 
     246             : #ifdef DEBUG_PASSWORDS
     247             :         DEBUG (100, ("smbldap_get_single_attribute: [%s] = [%s]\n",
     248             :                      attribute, result));
     249             : #endif
     250           0 :         return result;
     251             : }
     252             : 
     253         178 :  bool smbldap_talloc_single_blob(TALLOC_CTX *mem_ctx, LDAP *ld,
     254             :                                  LDAPMessage *msg, const char *attrib,
     255             :                                  DATA_BLOB *blob)
     256             : {
     257           0 :         struct berval **values;
     258             : 
     259         178 :         values = ldap_get_values_len(ld, msg, attrib);
     260         178 :         if (!values) {
     261           0 :                 return false;
     262             :         }
     263             : 
     264         178 :         if (ldap_count_values_len(values) != 1) {
     265           0 :                 DEBUG(10, ("Expected one value for %s, got %d\n", attrib,
     266             :                            ldap_count_values_len(values)));
     267           0 :                 return false;
     268             :         }
     269             : 
     270         178 :         *blob = data_blob_talloc(mem_ctx, values[0]->bv_val,
     271             :                                  values[0]->bv_len);
     272         178 :         ldap_value_free_len(values);
     273             : 
     274         178 :         return (blob->data != NULL);
     275             : }
     276             : 
     277         178 :  bool smbldap_pull_sid(LDAP *ld, LDAPMessage *msg, const char *attrib,
     278             :                        struct dom_sid *sid)
     279             : {
     280           0 :         DATA_BLOB blob;
     281           0 :         ssize_t ret;
     282             : 
     283         178 :         if (!smbldap_talloc_single_blob(talloc_tos(), ld, msg, attrib,
     284             :                                         &blob)) {
     285           0 :                 return false;
     286             :         }
     287         178 :         ret = sid_parse(blob.data, blob.length, sid);
     288         178 :         TALLOC_FREE(blob.data);
     289         178 :         return (ret != -1);
     290             : }
     291             : 
     292           0 :  static int ldapmsg_destructor(LDAPMessage **result) {
     293           0 :         ldap_msgfree(*result);
     294           0 :         return 0;
     295             : }
     296             : 
     297           0 :  void smbldap_talloc_autofree_ldapmsg(TALLOC_CTX *mem_ctx, LDAPMessage *result)
     298             : {
     299           0 :         LDAPMessage **handle;
     300             : 
     301           0 :         if (result == NULL) {
     302           0 :                 return;
     303             :         }
     304             : 
     305           0 :         handle = talloc(mem_ctx, LDAPMessage *);
     306           0 :         SMB_ASSERT(handle != NULL);
     307             : 
     308           0 :         *handle = result;
     309           0 :         talloc_set_destructor(handle, ldapmsg_destructor);
     310             : }
     311             : 
     312           0 :  static int ldapmod_destructor(LDAPMod ***mod) {
     313           0 :         ldap_mods_free(*mod, True);
     314           0 :         return 0;
     315             : }
     316             : 
     317           0 :  void smbldap_talloc_autofree_ldapmod(TALLOC_CTX *mem_ctx, LDAPMod **mod)
     318             : {
     319           0 :         LDAPMod ***handle;
     320             : 
     321           0 :         if (mod == NULL) {
     322           0 :                 return;
     323             :         }
     324             : 
     325           0 :         handle = talloc(mem_ctx, LDAPMod **);
     326           0 :         SMB_ASSERT(handle != NULL);
     327             : 
     328           0 :         *handle = mod;
     329           0 :         talloc_set_destructor(handle, ldapmod_destructor);
     330             : }
     331             : 
     332             : /************************************************************************
     333             :  Routine to manage the LDAPMod structure array
     334             :  manage memory used by the array, by each struct, and values
     335             :  ***********************************************************************/
     336             : 
     337           0 : static void smbldap_set_mod_internal(LDAPMod *** modlist, int modop, const char *attribute, const char *value, const DATA_BLOB *blob)
     338             : {
     339           0 :         LDAPMod **mods;
     340           0 :         int i;
     341           0 :         int j;
     342             : 
     343           0 :         mods = *modlist;
     344             : 
     345             :         /* sanity checks on the mod values */
     346             : 
     347           0 :         if (attribute == NULL || *attribute == '\0') {
     348           0 :                 return;
     349             :         }
     350             : 
     351             : #if 0   /* commented out after discussion with abartlet.  Do not re-enable.
     352             :            left here so other do not re-add similar code   --jerry */
     353             :         if (value == NULL || *value == '\0')
     354             :                 return;
     355             : #endif
     356             : 
     357           0 :         if (mods == NULL) {
     358           0 :                 mods = SMB_MALLOC_P(LDAPMod *);
     359           0 :                 if (mods == NULL) {
     360           0 :                         smb_panic("smbldap_set_mod: out of memory!");
     361             :                         /* notreached. */
     362             :                 }
     363           0 :                 mods[0] = NULL;
     364             :         }
     365             : 
     366           0 :         for (i = 0; mods[i] != NULL; ++i) {
     367           0 :                 if (mods[i]->mod_op == modop && strequal(mods[i]->mod_type, attribute))
     368           0 :                         break;
     369             :         }
     370             : 
     371           0 :         if (mods[i] == NULL) {
     372           0 :                 mods = SMB_REALLOC_ARRAY (mods, LDAPMod *, i + 2);
     373           0 :                 if (mods == NULL) {
     374           0 :                         smb_panic("smbldap_set_mod: out of memory!");
     375             :                         /* notreached. */
     376             :                 }
     377           0 :                 mods[i] = SMB_MALLOC_P(LDAPMod);
     378           0 :                 if (mods[i] == NULL) {
     379           0 :                         smb_panic("smbldap_set_mod: out of memory!");
     380             :                         /* notreached. */
     381             :                 }
     382           0 :                 mods[i]->mod_op = modop;
     383           0 :                 mods[i]->mod_values = NULL;
     384           0 :                 mods[i]->mod_type = SMB_STRDUP(attribute);
     385           0 :                 mods[i + 1] = NULL;
     386             :         }
     387             : 
     388           0 :         if (blob && (modop & LDAP_MOD_BVALUES)) {
     389           0 :                 j = 0;
     390           0 :                 if (mods[i]->mod_bvalues != NULL) {
     391           0 :                         for (; mods[i]->mod_bvalues[j] != NULL; j++);
     392             :                 }
     393           0 :                 mods[i]->mod_bvalues = SMB_REALLOC_ARRAY(mods[i]->mod_bvalues, struct berval *, j + 2);
     394             : 
     395           0 :                 if (mods[i]->mod_bvalues == NULL) {
     396           0 :                         smb_panic("smbldap_set_mod: out of memory!");
     397             :                         /* notreached. */
     398             :                 }
     399             : 
     400           0 :                 mods[i]->mod_bvalues[j] = SMB_MALLOC_P(struct berval);
     401           0 :                 SMB_ASSERT(mods[i]->mod_bvalues[j] != NULL);
     402             : 
     403           0 :                 mods[i]->mod_bvalues[j]->bv_val = (char *)smb_memdup(blob->data, blob->length);
     404           0 :                 SMB_ASSERT(mods[i]->mod_bvalues[j]->bv_val != NULL);
     405           0 :                 mods[i]->mod_bvalues[j]->bv_len = blob->length;
     406             : 
     407           0 :                 mods[i]->mod_bvalues[j + 1] = NULL;
     408           0 :         } else if (value != NULL) {
     409           0 :                 char *utf8_value = NULL;
     410           0 :                 size_t converted_size;
     411             : 
     412           0 :                 j = 0;
     413           0 :                 if (mods[i]->mod_values != NULL) {
     414           0 :                         for (; mods[i]->mod_values[j] != NULL; j++);
     415             :                 }
     416           0 :                 mods[i]->mod_values = SMB_REALLOC_ARRAY(mods[i]->mod_values, char *, j + 2);
     417             : 
     418           0 :                 if (mods[i]->mod_values == NULL) {
     419           0 :                         smb_panic("smbldap_set_mod: out of memory!");
     420             :                         /* notreached. */
     421             :                 }
     422             : 
     423           0 :                 if (!push_utf8_talloc(talloc_tos(), &utf8_value, value, &converted_size)) {
     424           0 :                         smb_panic("smbldap_set_mod: String conversion failure!");
     425             :                         /* notreached. */
     426             :                 }
     427             : 
     428           0 :                 mods[i]->mod_values[j] = SMB_STRDUP(utf8_value);
     429           0 :                 TALLOC_FREE(utf8_value);
     430           0 :                 SMB_ASSERT(mods[i]->mod_values[j] != NULL);
     431             : 
     432           0 :                 mods[i]->mod_values[j + 1] = NULL;
     433             :         }
     434           0 :         *modlist = mods;
     435             : }
     436             : 
     437           0 :  void smbldap_set_mod (LDAPMod *** modlist, int modop, const char *attribute, const char *value)
     438             : {
     439           0 :         smbldap_set_mod_internal(modlist, modop, attribute, value, NULL);
     440           0 : }
     441             : 
     442           0 :  void smbldap_set_mod_blob(LDAPMod *** modlist, int modop, const char *attribute, const DATA_BLOB *value)
     443             : {
     444           0 :         smbldap_set_mod_internal(modlist, modop | LDAP_MOD_BVALUES, attribute, NULL, value);
     445           0 : }
     446             : 
     447             : /**********************************************************************
     448             :   Set attribute to newval in LDAP, regardless of what value the
     449             :   attribute had in LDAP before.
     450             : *********************************************************************/
     451             : 
     452           0 : static void smbldap_make_mod_internal(LDAP *ldap_struct, LDAPMessage *existing,
     453             :                                       LDAPMod ***mods,
     454             :                                       const char *attribute, int op,
     455             :                                       const char *newval,
     456             :                                       const DATA_BLOB *newblob)
     457             : {
     458           0 :         char oldval[2048]; /* current largest allowed value is mungeddial */
     459           0 :         bool existed;
     460           0 :         DATA_BLOB oldblob = data_blob_null;
     461             : 
     462           0 :         if (existing != NULL) {
     463           0 :                 if (op & LDAP_MOD_BVALUES) {
     464           0 :                         existed = smbldap_talloc_single_blob(talloc_tos(), ldap_struct, existing, attribute, &oldblob);
     465             :                 } else {
     466           0 :                         existed = smbldap_get_single_attribute(ldap_struct, existing, attribute, oldval, sizeof(oldval));
     467             :                 }
     468             :         } else {
     469           0 :                 existed = False;
     470           0 :                 *oldval = '\0';
     471             :         }
     472             : 
     473           0 :         if (existed) {
     474           0 :                 bool equal = false;
     475           0 :                 if (op & LDAP_MOD_BVALUES) {
     476           0 :                         equal = (newblob && (data_blob_cmp(&oldblob, newblob) == 0));
     477             :                 } else {
     478             :                         /* all of our string attributes are case insensitive */
     479           0 :                         equal = (newval && (strcasecmp_m(oldval, newval) == 0));
     480             :                 }
     481             : 
     482           0 :                 if (equal) {
     483             :                         /* Believe it or not, but LDAP will deny a delete and
     484             :                            an add at the same time if the values are the
     485             :                            same... */
     486           0 :                         DEBUG(10,("smbldap_make_mod: attribute |%s| not changed.\n", attribute));
     487           0 :                         return;
     488             :                 }
     489             : 
     490             :                 /* There has been no value before, so don't delete it.
     491             :                  * Here's a possible race: We might end up with
     492             :                  * duplicate attributes */
     493             :                 /* By deleting exactly the value we found in the entry this
     494             :                  * should be race-free in the sense that the LDAP-Server will
     495             :                  * deny the complete operation if somebody changed the
     496             :                  * attribute behind our back. */
     497             :                 /* This will also allow modifying single valued attributes
     498             :                  * in Novell NDS. In NDS you have to first remove attribute and then
     499             :                  * you could add new value */
     500             : 
     501           0 :                 if (op & LDAP_MOD_BVALUES) {
     502           0 :                         DEBUG(10,("smbldap_make_mod: deleting attribute |%s| blob\n", attribute));
     503           0 :                         smbldap_set_mod_blob(mods, LDAP_MOD_DELETE, attribute, &oldblob);
     504             :                 } else {
     505           0 :                         DEBUG(10,("smbldap_make_mod: deleting attribute |%s| values |%s|\n", attribute, oldval));
     506           0 :                         smbldap_set_mod(mods, LDAP_MOD_DELETE, attribute, oldval);
     507             :                 }
     508             :         }
     509             : 
     510             :         /* Regardless of the real operation (add or modify)
     511             :            we add the new value here. We rely on deleting
     512             :            the old value, should it exist. */
     513             : 
     514           0 :         if (op & LDAP_MOD_BVALUES) {
     515           0 :                 if (newblob && newblob->length) {
     516           0 :                         DEBUG(10,("smbldap_make_mod: adding attribute |%s| blob\n", attribute));
     517           0 :                         smbldap_set_mod_blob(mods, LDAP_MOD_ADD, attribute, newblob);
     518             :                 }
     519             :         } else {
     520           0 :                 if ((newval != NULL) && (strlen(newval) > 0)) {
     521           0 :                         DEBUG(10,("smbldap_make_mod: adding attribute |%s| value |%s|\n", attribute, newval));
     522           0 :                         smbldap_set_mod(mods, LDAP_MOD_ADD, attribute, newval);
     523             :                 }
     524             :         }
     525             : }
     526             : 
     527           0 :  void smbldap_make_mod(LDAP *ldap_struct, LDAPMessage *existing,
     528             :                       LDAPMod ***mods,
     529             :                       const char *attribute, const char *newval)
     530             : {
     531           0 :         smbldap_make_mod_internal(ldap_struct, existing, mods, attribute,
     532             :                                   0, newval, NULL);
     533           0 : }
     534             : 
     535           0 :  void smbldap_make_mod_blob(LDAP *ldap_struct, LDAPMessage *existing,
     536             :                             LDAPMod ***mods,
     537             :                             const char *attribute, const DATA_BLOB *newblob)
     538             : {
     539           0 :         smbldap_make_mod_internal(ldap_struct, existing, mods, attribute,
     540             :                                   LDAP_MOD_BVALUES, NULL, newblob);
     541           0 : }
     542             : 
     543             : /**********************************************************************
     544             :  Some variants of the LDAP rebind code do not pass in the third 'arg'
     545             :  pointer to a void*, so we try and work around it by assuming that the
     546             :  value of the 'LDAP *' pointer is the same as the one we had passed in
     547             :  **********************************************************************/
     548             : 
     549             : struct smbldap_state_lookup {
     550             :         LDAP *ld;
     551             :         struct smbldap_state *smbldap_state;
     552             :         struct smbldap_state_lookup *prev, *next;
     553             : };
     554             : 
     555             : static struct smbldap_state_lookup *smbldap_state_lookup_list;
     556             : 
     557           0 : static struct smbldap_state *smbldap_find_state(LDAP *ld)
     558             : {
     559           0 :         struct smbldap_state_lookup *t;
     560             : 
     561           0 :         for (t = smbldap_state_lookup_list; t; t = t->next) {
     562           0 :                 if (t->ld == ld) {
     563           0 :                         return t->smbldap_state;
     564             :                 }
     565             :         }
     566           0 :         return NULL;
     567             : }
     568             : 
     569           0 : static void smbldap_delete_state(struct smbldap_state *smbldap_state)
     570             : {
     571           0 :         struct smbldap_state_lookup *t;
     572             : 
     573           0 :         for (t = smbldap_state_lookup_list; t; t = t->next) {
     574           0 :                 if (t->smbldap_state == smbldap_state) {
     575           0 :                         DLIST_REMOVE(smbldap_state_lookup_list, t);
     576           0 :                         SAFE_FREE(t);
     577           0 :                         return;
     578             :                 }
     579             :         }
     580             : }
     581             : 
     582           0 : static void smbldap_store_state(LDAP *ld, struct smbldap_state *smbldap_state)
     583             : {
     584           0 :         struct smbldap_state *tmp_ldap_state;
     585           0 :         struct smbldap_state_lookup *t;
     586             : 
     587           0 :         if ((tmp_ldap_state = smbldap_find_state(ld))) {
     588           0 :                 SMB_ASSERT(tmp_ldap_state == smbldap_state);
     589           0 :                 return;
     590             :         }
     591             : 
     592           0 :         t = SMB_XMALLOC_P(struct smbldap_state_lookup);
     593           0 :         ZERO_STRUCTP(t);
     594             : 
     595           0 :         DLIST_ADD_END(smbldap_state_lookup_list, t);
     596           0 :         t->ld = ld;
     597           0 :         t->smbldap_state = smbldap_state;
     598             : }
     599             : 
     600             : /********************************************************************
     601             :  start TLS on an existing LDAP connection per config
     602             : *******************************************************************/
     603             : 
     604           0 : int smbldap_start_tls(LDAP *ldap_struct, int version)
     605             : {
     606           0 :         if (lp_ldap_ssl() != LDAP_SSL_START_TLS) {
     607           0 :                 return LDAP_SUCCESS;
     608             :         }
     609             : 
     610           0 :         return smbldap_start_tls_start(ldap_struct, version);
     611             : }
     612             : 
     613             : /********************************************************************
     614             :  start TLS on an existing LDAP connection unconditionally
     615             : *******************************************************************/
     616             : 
     617           0 : int smbldap_start_tls_start(LDAP *ldap_struct, int version)
     618             : {
     619             : #ifdef LDAP_OPT_X_TLS
     620           0 :         int rc,tls;
     621             : 
     622             :         /* check if we use ldaps already */
     623           0 :         ldap_get_option(ldap_struct, LDAP_OPT_X_TLS, &tls);
     624           0 :         if (tls == LDAP_OPT_X_TLS_HARD) {
     625           0 :                 return LDAP_SUCCESS;
     626             :         }
     627             : 
     628           0 :         if (version != LDAP_VERSION3) {
     629           0 :                 DEBUG(0, ("Need LDAPv3 for Start TLS\n"));
     630           0 :                 return LDAP_OPERATIONS_ERROR;
     631             :         }
     632             : 
     633           0 :         if ((rc = ldap_start_tls_s (ldap_struct, NULL, NULL)) != LDAP_SUCCESS)  {
     634           0 :                 DEBUG(0,("Failed to issue the StartTLS instruction: %s\n",
     635             :                          ldap_err2string(rc)));
     636           0 :                 return rc;
     637             :         }
     638             : 
     639           0 :         DEBUG (3, ("StartTLS issued: using a TLS connection\n"));
     640           0 :         return LDAP_SUCCESS;
     641             : #else
     642             :         DEBUG(0,("StartTLS not supported by LDAP client libraries!\n"));
     643             :         return LDAP_OPERATIONS_ERROR;
     644             : #endif
     645             : }
     646             : 
     647             : /********************************************************************
     648             :  setup a connection to the LDAP server based on a uri
     649             : *******************************************************************/
     650             : 
     651           0 : static int smb_ldap_setup_conn(LDAP **ldap_struct, const char *uri)
     652             : {
     653           0 :         int rc;
     654             : 
     655           0 :         DEBUG(10, ("smb_ldap_setup_connection: %s\n", uri));
     656             : 
     657             : #ifdef HAVE_LDAP_INITIALIZE
     658             : 
     659           0 :         rc = ldap_initialize(ldap_struct, uri);
     660           0 :         if (rc) {
     661           0 :                 DEBUG(0, ("ldap_initialize: %s\n", ldap_err2string(rc)));
     662           0 :                 return rc;
     663             :         }
     664             : 
     665           0 :         if (lp_ldap_follow_referral() != Auto) {
     666           0 :                 rc = ldap_set_option(*ldap_struct, LDAP_OPT_REFERRALS,
     667           0 :                      lp_ldap_follow_referral() ? LDAP_OPT_ON : LDAP_OPT_OFF);
     668           0 :                 if (rc != LDAP_SUCCESS)
     669           0 :                         DEBUG(0, ("Failed to set LDAP_OPT_REFERRALS: %s\n",
     670             :                                 ldap_err2string(rc)));
     671             :         }
     672             : 
     673             : #else
     674             : 
     675             :         /* Parse the string manually */
     676             : 
     677             :         {
     678             :                 int port = 0;
     679             :                 fstring protocol;
     680             :                 fstring host;
     681             :                 SMB_ASSERT(sizeof(protocol)>10 && sizeof(host)>254);
     682             : 
     683             : 
     684             :                 /* skip leading "URL:" (if any) */
     685             :                 if ( strnequal( uri, "URL:", 4 ) ) {
     686             :                         uri += 4;
     687             :                 }
     688             : 
     689             :                 sscanf(uri, "%10[^:]://%254[^:/]:%d", protocol, host, &port);
     690             : 
     691             :                 if (port == 0) {
     692             :                         if (strequal(protocol, "ldap")) {
     693             :                                 port = LDAP_PORT;
     694             :                         } else if (strequal(protocol, "ldaps")) {
     695             :                                 port = LDAPS_PORT;
     696             :                         } else {
     697             :                                 DEBUG(0, ("unrecognised protocol (%s)!\n", protocol));
     698             :                         }
     699             :                 }
     700             : 
     701             :                 if ((*ldap_struct = ldap_init(host, port)) == NULL)     {
     702             :                         DEBUG(0, ("ldap_init failed !\n"));
     703             :                         return LDAP_OPERATIONS_ERROR;
     704             :                 }
     705             : 
     706             :                 if (strequal(protocol, "ldaps")) {
     707             : #ifdef LDAP_OPT_X_TLS
     708             :                         int tls = LDAP_OPT_X_TLS_HARD;
     709             :                         if (ldap_set_option (*ldap_struct, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS)
     710             :                         {
     711             :                                 DEBUG(0, ("Failed to setup a TLS session\n"));
     712             :                         }
     713             : 
     714             :                         DEBUG(3,("LDAPS option set...!\n"));
     715             : #else
     716             :                         DEBUG(0,("smbldap_open_connection: Secure connection not supported by LDAP client libraries!\n"));
     717             :                         return LDAP_OPERATIONS_ERROR;
     718             : #endif /* LDAP_OPT_X_TLS */
     719             :                 }
     720             :         }
     721             : 
     722             :         /* now set connection timeout */
     723             : #ifdef LDAP_X_OPT_CONNECT_TIMEOUT /* Netscape */
     724             :         {
     725             :                 int ct = lp_ldap_connection_timeout()*1000;
     726             :                 rc = ldap_set_option(*ldap_struct, LDAP_X_OPT_CONNECT_TIMEOUT, &ct);
     727             :                 if (rc != LDAP_SUCCESS) {
     728             :                         DEBUG(0,("Failed to setup an ldap connection timeout %d: %s\n",
     729             :                                 ct, ldap_err2string(rc)));
     730             :                 }
     731             :         }
     732             : #elif defined (LDAP_OPT_NETWORK_TIMEOUT) /* OpenLDAP */
     733             :         {
     734             :                 struct timeval ct;
     735             :                 ct.tv_usec = 0;
     736             :                 ct.tv_sec = lp_ldap_connection_timeout();
     737             :                 rc = ldap_set_option(*ldap_struct, LDAP_OPT_NETWORK_TIMEOUT, &ct);
     738             :                 if (rc != LDAP_SUCCESS) {
     739             :                         DEBUG(0,("Failed to setup an ldap connection timeout %d: %s\n",
     740             :                                 (int)ct.tv_sec, ldap_err2string(rc)));
     741             :                 }
     742             :         }
     743             : #endif
     744             : 
     745             : #endif /* HAVE_LDAP_INITIALIZE */
     746           0 :         return LDAP_SUCCESS;
     747             : }
     748             : 
     749             : /********************************************************************
     750             :  try to upgrade to Version 3 LDAP if not already, in either case return current
     751             :  version
     752             :  *******************************************************************/
     753             : 
     754           0 : static int smb_ldap_upgrade_conn(LDAP *ldap_struct, int *new_version)
     755             : {
     756           0 :         int version;
     757           0 :         int rc;
     758             : 
     759             :         /* assume the worst */
     760           0 :         *new_version = LDAP_VERSION2;
     761             : 
     762           0 :         rc = ldap_get_option(ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version);
     763           0 :         if (rc) {
     764           0 :                 return rc;
     765             :         }
     766             : 
     767           0 :         if (version == LDAP_VERSION3) {
     768           0 :                 *new_version = LDAP_VERSION3;
     769           0 :                 return LDAP_SUCCESS;
     770             :         }
     771             : 
     772             :         /* try upgrade */
     773           0 :         version = LDAP_VERSION3;
     774           0 :         rc = ldap_set_option (ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version);
     775           0 :         if (rc) {
     776           0 :                 return rc;
     777             :         }
     778             : 
     779           0 :         *new_version = LDAP_VERSION3;
     780           0 :         return LDAP_SUCCESS;
     781             : }
     782             : 
     783             : /*******************************************************************
     784             :  open a connection to the ldap server (just until the bind)
     785             :  ******************************************************************/
     786             : 
     787           0 : int smbldap_setup_full_conn(LDAP **ldap_struct, const char *uri)
     788             : {
     789           0 :         int rc, version;
     790             : 
     791           0 :         rc = smb_ldap_setup_conn(ldap_struct, uri);
     792           0 :         if (rc) {
     793           0 :                 return rc;
     794             :         }
     795             : 
     796           0 :         rc = smb_ldap_upgrade_conn(*ldap_struct, &version);
     797           0 :         if (rc) {
     798           0 :                 return rc;
     799             :         }
     800             : 
     801           0 :         rc = smbldap_start_tls(*ldap_struct, version);
     802           0 :         if (rc) {
     803           0 :                 return rc;
     804             :         }
     805             : 
     806           0 :         return LDAP_SUCCESS;
     807             : }
     808             : 
     809             : /*******************************************************************
     810             :  open a connection to the ldap server.
     811             : ******************************************************************/
     812           0 : static int smbldap_open_connection (struct smbldap_state *ldap_state)
     813             : 
     814             : {
     815           0 :         int rc = LDAP_SUCCESS;
     816           0 :         int version;
     817           0 :         int deref;
     818           0 :         LDAP **ldap_struct = &ldap_state->ldap_struct;
     819             : 
     820           0 :         rc = smb_ldap_setup_conn(ldap_struct, ldap_state->uri);
     821           0 :         if (rc) {
     822           0 :                 return rc;
     823             :         }
     824             : 
     825             :         /* Store the LDAP pointer in a lookup list */
     826             : 
     827           0 :         smbldap_store_state(*ldap_struct, ldap_state);
     828             : 
     829             :         /* Upgrade to LDAPv3 if possible */
     830             : 
     831           0 :         rc = smb_ldap_upgrade_conn(*ldap_struct, &version);
     832           0 :         if (rc) {
     833           0 :                 return rc;
     834             :         }
     835             : 
     836             :         /* Start TLS if required */
     837             : 
     838           0 :         rc = smbldap_start_tls(*ldap_struct, version);
     839           0 :         if (rc) {
     840           0 :                 return rc;
     841             :         }
     842             : 
     843             :         /* Set alias dereferencing method */
     844           0 :         deref = lp_ldap_deref();
     845           0 :         if (deref != -1) {
     846           0 :                 if (ldap_set_option (*ldap_struct, LDAP_OPT_DEREF, &deref) != LDAP_OPT_SUCCESS) {
     847           0 :                         DEBUG(1,("smbldap_open_connection: Failed to set dereferencing method: %d\n", deref));
     848             :                 } else {
     849           0 :                         DEBUG(5,("Set dereferencing method: %d\n", deref));
     850             :                 }
     851             :         }
     852             : 
     853           0 :         DEBUG(2, ("smbldap_open_connection: connection opened\n"));
     854           0 :         return rc;
     855             : }
     856             : 
     857             : /*******************************************************************
     858             :  a rebind function for authenticated referrals
     859             :  This version takes a void* that we can shove useful stuff in :-)
     860             : ******************************************************************/
     861             : #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
     862             : #else
     863             : static int rebindproc_with_state  (LDAP * ld, char **whop, char **credp,
     864             :                                    int *methodp, int freeit, void *arg)
     865             : {
     866             :         struct smbldap_state *ldap_state = arg;
     867             :         struct timespec ts;
     868             : 
     869             :         /** @TODO Should we be doing something to check what servers we rebind to?
     870             :             Could we get a referral to a machine that we don't want to give our
     871             :             username and password to? */
     872             : 
     873             :         if (freeit) {
     874             :                 SAFE_FREE(*whop);
     875             :                 if (*credp) {
     876             :                         memset(*credp, '\0', strlen(*credp));
     877             :                 }
     878             :                 SAFE_FREE(*credp);
     879             :         } else {
     880             :                 DEBUG(5,("rebind_proc_with_state: Rebinding as \"%s\"\n",
     881             :                           ldap_state->bind_dn?ldap_state->bind_dn:"[Anonymous bind]"));
     882             : 
     883             :                 if (ldap_state->anonymous) {
     884             :                         *whop = NULL;
     885             :                         *credp = NULL;
     886             :                 } else {
     887             :                         *whop = SMB_STRDUP(ldap_state->bind_dn);
     888             :                         if (!*whop) {
     889             :                                 return LDAP_NO_MEMORY;
     890             :                         }
     891             :                         *credp = SMB_STRDUP(ldap_state->bind_secret);
     892             :                         if (!*credp) {
     893             :                                 SAFE_FREE(*whop);
     894             :                                 return LDAP_NO_MEMORY;
     895             :                         }
     896             :                 }
     897             :                 *methodp = LDAP_AUTH_SIMPLE;
     898             :         }
     899             : 
     900             :         clock_gettime_mono(&ts);
     901             :         ldap_state->last_rebind = convert_timespec_to_timeval(ts);
     902             : 
     903             :         return 0;
     904             : }
     905             : #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
     906             : 
     907             : /*******************************************************************
     908             :  a rebind function for authenticated referrals
     909             :  This version takes a void* that we can shove useful stuff in :-)
     910             :  and actually does the connection.
     911             : ******************************************************************/
     912             : #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
     913           0 : static int rebindproc_connect_with_state (LDAP *ldap_struct,
     914             :                                           LDAP_CONST char *url,
     915             :                                           ber_tag_t request,
     916             :                                           ber_int_t msgid, void *arg)
     917             : {
     918           0 :         struct smbldap_state *ldap_state =
     919             :                 (struct smbldap_state *)arg;
     920           0 :         int rc;
     921           0 :         struct timespec ts;
     922           0 :         int version;
     923             : 
     924           0 :         DEBUG(5,("rebindproc_connect_with_state: Rebinding to %s as \"%s\"\n",
     925             :                  url, ldap_state->bind_dn?ldap_state->bind_dn:"[Anonymous bind]"));
     926             : 
     927             :         /* call START_TLS again (ldaps:// is handled by the OpenLDAP library
     928             :          * itself) before rebinding to another LDAP server to avoid to expose
     929             :          * our credentials. At least *try* to secure the connection - Guenther */
     930             : 
     931           0 :         smb_ldap_upgrade_conn(ldap_struct, &version);
     932           0 :         smbldap_start_tls(ldap_struct, version);
     933             : 
     934             :         /** @TODO Should we be doing something to check what servers we rebind to?
     935             :             Could we get a referral to a machine that we don't want to give our
     936             :             username and password to? */
     937             : 
     938           0 :         rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret);
     939             : 
     940             :         /* only set the last rebind timestamp when we did rebind after a
     941             :          * non-read LDAP operation. That way we avoid the replication sleep
     942             :          * after a simple redirected search operation - Guenther */
     943             : 
     944           0 :         switch (request) {
     945             : 
     946           0 :                 case LDAP_REQ_MODIFY:
     947             :                 case LDAP_REQ_ADD:
     948             :                 case LDAP_REQ_DELETE:
     949             :                 case LDAP_REQ_MODDN:
     950             :                 case LDAP_REQ_EXTENDED:
     951           0 :                         DEBUG(10,("rebindproc_connect_with_state: "
     952             :                                 "setting last_rebind timestamp "
     953             :                                 "(req: 0x%02x)\n", (unsigned int)request));
     954           0 :                         clock_gettime_mono(&ts);
     955           0 :                         ldap_state->last_rebind = convert_timespec_to_timeval(ts);
     956           0 :                         break;
     957           0 :                 default:
     958           0 :                         ZERO_STRUCT(ldap_state->last_rebind);
     959           0 :                         break;
     960             :         }
     961             : 
     962           0 :         return rc;
     963             : }
     964             : #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
     965             : 
     966             : /*******************************************************************
     967             :  Add a rebind function for authenticated referrals
     968             : ******************************************************************/
     969             : #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
     970             : #else
     971             : # if LDAP_SET_REBIND_PROC_ARGS == 2
     972             : static int rebindproc (LDAP *ldap_struct, char **whop, char **credp,
     973             :                        int *method, int freeit )
     974             : {
     975             :         struct smbldap_state *ldap_state = smbldap_find_state(ldap_struct);
     976             : 
     977             :         return rebindproc_with_state(ldap_struct, whop, credp,
     978             :                                      method, freeit, ldap_state);
     979             : }
     980             : # endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/
     981             : #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
     982             : 
     983             : /*******************************************************************
     984             :  a rebind function for authenticated referrals
     985             :  this also does the connection, but no void*.
     986             : ******************************************************************/
     987             : #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
     988             : # if LDAP_SET_REBIND_PROC_ARGS == 2
     989             : static int rebindproc_connect (LDAP * ld, LDAP_CONST char *url, int request,
     990             :                                ber_int_t msgid)
     991             : {
     992             :         struct smbldap_state *ldap_state = smbldap_find_state(ld);
     993             : 
     994             :         return rebindproc_connect_with_state(ld, url, (ber_tag_t)request, msgid,
     995             :                                              ldap_state);
     996             : }
     997             : # endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/
     998             : #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
     999             : 
    1000             : /*******************************************************************
    1001             :  connect to the ldap server under system privilege.
    1002             : ******************************************************************/
    1003           0 : static int smbldap_connect_system(struct smbldap_state *ldap_state)
    1004             : {
    1005           0 :         LDAP *ldap_struct = smbldap_get_ldap(ldap_state);
    1006           0 :         int rc;
    1007           0 :         int version;
    1008             : 
    1009             :         /* removed the sasl_bind_s "EXTERNAL" stuff, as my testsuite
    1010             :            (OpenLDAP) doesn't seem to support it */
    1011             : 
    1012           0 :         DEBUG(10,("ldap_connect_system: Binding to ldap server %s as \"%s\"\n",
    1013             :                   ldap_state->uri, ldap_state->bind_dn));
    1014             : 
    1015             : #ifdef HAVE_LDAP_SET_REBIND_PROC
    1016             : #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
    1017             : # if LDAP_SET_REBIND_PROC_ARGS == 2
    1018             :         ldap_set_rebind_proc(ldap_struct, &rebindproc_connect);
    1019             : # endif
    1020             : # if LDAP_SET_REBIND_PROC_ARGS == 3
    1021           0 :         ldap_set_rebind_proc(ldap_struct, &rebindproc_connect_with_state, (void *)ldap_state);
    1022             : # endif
    1023             : #else /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
    1024             : # if LDAP_SET_REBIND_PROC_ARGS == 2
    1025             :         ldap_set_rebind_proc(ldap_struct, &rebindproc);
    1026             : # endif
    1027             : # if LDAP_SET_REBIND_PROC_ARGS == 3
    1028             :         ldap_set_rebind_proc(ldap_struct, &rebindproc_with_state, (void *)ldap_state);
    1029             : # endif
    1030             : #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
    1031             : #endif
    1032             : 
    1033             :         /* When there is an alternative bind callback is set,
    1034             :            attempt to use it to perform the bind */
    1035           0 :         if (ldap_state->bind_callback != NULL) {
    1036             :                 /* We have to allow bind callback to be run under become_root/unbecome_root
    1037             :                    to make sure within smbd the callback has proper write access to its resources,
    1038             :                    like credential cache. This is similar to passdb case where this callback is supposed
    1039             :                    to be used. When used outside smbd, become_root()/unbecome_root() are no-op.
    1040             :                 */
    1041           0 :                 become_root();
    1042           0 :                 rc = ldap_state->bind_callback(ldap_struct, ldap_state, ldap_state->bind_callback_data);
    1043           0 :                 unbecome_root();
    1044             :         } else {
    1045           0 :                 rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret);
    1046             :         }
    1047             : 
    1048           0 :         if (rc != LDAP_SUCCESS) {
    1049           0 :                 char *ld_error = NULL;
    1050           0 :                 ldap_get_option(smbldap_get_ldap(ldap_state),
    1051             :                                 LDAP_OPT_ERROR_STRING,
    1052             :                                 &ld_error);
    1053           0 :                 DEBUG(ldap_state->num_failures ? 2 : 0,
    1054             :                       ("failed to bind to server %s with dn=\"%s\" Error: %s\n\t%s\n",
    1055             :                                ldap_state->uri,
    1056             :                                ldap_state->bind_dn ? ldap_state->bind_dn : "[Anonymous bind]",
    1057             :                                ldap_err2string(rc),
    1058             :                                ld_error ? ld_error : "(unknown)"));
    1059           0 :                 SAFE_FREE(ld_error);
    1060           0 :                 ldap_state->num_failures++;
    1061           0 :                 goto done;
    1062             :         }
    1063             : 
    1064           0 :         ldap_state->num_failures = 0;
    1065           0 :         ldap_state->paged_results = False;
    1066             : 
    1067           0 :         ldap_get_option(smbldap_get_ldap(ldap_state),
    1068             :                         LDAP_OPT_PROTOCOL_VERSION, &version);
    1069             : 
    1070           0 :         if (smbldap_has_control(smbldap_get_ldap(ldap_state), ADS_PAGE_CTL_OID)
    1071           0 :             && version == 3) {
    1072           0 :                 ldap_state->paged_results = True;
    1073             :         }
    1074             : 
    1075           0 :         DEBUG(3, ("ldap_connect_system: successful connection to the LDAP server\n"));
    1076           0 :         DEBUGADD(10, ("ldap_connect_system: LDAP server %s support paged results\n",
    1077             :                 ldap_state->paged_results ? "does" : "does not"));
    1078           0 : done:
    1079           0 :         if (rc != 0) {
    1080           0 :                 ldap_unbind(ldap_struct);
    1081           0 :                 ldap_state->ldap_struct = NULL;
    1082             :         }
    1083           0 :         return rc;
    1084             : }
    1085             : 
    1086             : static void smbldap_idle_fn(struct tevent_context *tevent_ctx,
    1087             :                             struct tevent_timer *te,
    1088             :                             struct timeval now_abs,
    1089             :                             void *private_data);
    1090             : 
    1091             : /**********************************************************************
    1092             :  Connect to LDAP server (called before every ldap operation)
    1093             : *********************************************************************/
    1094           0 : static int smbldap_open(struct smbldap_state *ldap_state)
    1095             : {
    1096           0 :         int rc, opt_rc;
    1097           0 :         bool reopen = False;
    1098           0 :         SMB_ASSERT(ldap_state);
    1099             : 
    1100           0 :         if ((smbldap_get_ldap(ldap_state) != NULL) &&
    1101           0 :             ((ldap_state->last_ping + SMBLDAP_DONT_PING_TIME) <
    1102           0 :              time_mono(NULL))) {
    1103             : 
    1104             : #ifdef HAVE_UNIXSOCKET
    1105           0 :                 struct sockaddr_un addr;
    1106             : #else
    1107             :                 struct sockaddr_storage addr;
    1108             : #endif
    1109           0 :                 socklen_t len = sizeof(addr);
    1110           0 :                 int sd;
    1111             : 
    1112           0 :                 opt_rc = ldap_get_option(smbldap_get_ldap(ldap_state),
    1113             :                                          LDAP_OPT_DESC, &sd);
    1114           0 :                 if (opt_rc == 0 && (getpeername(sd, (struct sockaddr *) &addr, &len)) < 0 )
    1115           0 :                         reopen = True;
    1116             : 
    1117             : #ifdef HAVE_UNIXSOCKET
    1118           0 :                 if (opt_rc == 0 && addr.sun_family == AF_UNIX)
    1119           0 :                         reopen = True;
    1120             : #endif
    1121           0 :                 if (reopen) {
    1122             :                         /* the other end has died. reopen. */
    1123           0 :                         ldap_unbind(smbldap_get_ldap(ldap_state));
    1124           0 :                         ldap_state->ldap_struct = NULL;
    1125           0 :                         ldap_state->last_ping = (time_t)0;
    1126             :                 } else {
    1127           0 :                         ldap_state->last_ping = time_mono(NULL);
    1128             :                 }
    1129             :         }
    1130             : 
    1131           0 :         if (smbldap_get_ldap(ldap_state) != NULL) {
    1132           0 :                 DEBUG(11,("smbldap_open: already connected to the LDAP server\n"));
    1133           0 :                 return LDAP_SUCCESS;
    1134             :         }
    1135             : 
    1136           0 :         if ((rc = smbldap_open_connection(ldap_state))) {
    1137           0 :                 return rc;
    1138             :         }
    1139             : 
    1140           0 :         if ((rc = smbldap_connect_system(ldap_state))) {
    1141           0 :                 return rc;
    1142             :         }
    1143             : 
    1144             : 
    1145           0 :         ldap_state->last_ping = time_mono(NULL);
    1146           0 :         ldap_state->pid = getpid();
    1147             : 
    1148           0 :         TALLOC_FREE(ldap_state->idle_event);
    1149             : 
    1150           0 :         if (ldap_state->tevent_context != NULL) {
    1151           0 :                 ldap_state->idle_event = tevent_add_timer(
    1152             :                         ldap_state->tevent_context, ldap_state,
    1153             :                         timeval_current_ofs(SMBLDAP_IDLE_TIME, 0),
    1154             :                         smbldap_idle_fn, ldap_state);
    1155             :         }
    1156             : 
    1157           0 :         DEBUG(4,("The LDAP server is successfully connected\n"));
    1158             : 
    1159           0 :         return LDAP_SUCCESS;
    1160             : }
    1161             : 
    1162             : /**********************************************************************
    1163             : Disconnect from LDAP server
    1164             : *********************************************************************/
    1165           0 : static NTSTATUS smbldap_close(struct smbldap_state *ldap_state)
    1166             : {
    1167           0 :         if (!ldap_state)
    1168           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1169             : 
    1170           0 :         if (smbldap_get_ldap(ldap_state) != NULL) {
    1171           0 :                 ldap_unbind(smbldap_get_ldap(ldap_state));
    1172           0 :                 ldap_state->ldap_struct = NULL;
    1173             :         }
    1174             : 
    1175           0 :         smbldap_delete_state(ldap_state);
    1176             : 
    1177           0 :         TALLOC_FREE(ldap_state->idle_event);
    1178             : 
    1179           0 :         DEBUG(5,("The connection to the LDAP server was closed\n"));
    1180             :         /* maybe free the results here --metze */
    1181             : 
    1182           0 :         return NT_STATUS_OK;
    1183             : }
    1184             : 
    1185             : static SIG_ATOMIC_T got_alarm;
    1186             : 
    1187           0 : static void gotalarm_sig(int dummy)
    1188             : {
    1189           0 :         got_alarm = 1;
    1190           0 : }
    1191             : 
    1192           0 : static time_t calc_ldap_abs_endtime(int ldap_to)
    1193             : {
    1194           0 :         if (ldap_to == 0) {
    1195             :                 /* No timeout - don't
    1196             :                    return a value for
    1197             :                    the alarm. */
    1198           0 :                 return (time_t)0;
    1199             :         }
    1200             : 
    1201             :         /* Make the alarm time one second beyond
    1202             :            the timeout we're setting for the
    1203             :            remote search timeout, to allow that
    1204             :            to fire in preference. */
    1205             : 
    1206           0 :         return time_mono(NULL)+ldap_to+1;
    1207             : }
    1208             : 
    1209           0 : static int end_ldap_local_alarm(time_t absolute_endtime, int rc)
    1210             : {
    1211           0 :         if (absolute_endtime) {
    1212           0 :                 alarm(0);
    1213           0 :                 CatchSignal(SIGALRM, SIG_IGN);
    1214           0 :                 if (got_alarm) {
    1215             :                         /* Client timeout error code. */
    1216           0 :                         got_alarm = 0;
    1217           0 :                         return LDAP_TIMEOUT;
    1218             :                 }
    1219             :         }
    1220           0 :         return rc;
    1221             : }
    1222             : 
    1223           0 : static void setup_ldap_local_alarm(struct smbldap_state *ldap_state, time_t absolute_endtime)
    1224             : {
    1225           0 :         time_t now = time_mono(NULL);
    1226             : 
    1227           0 :         if (absolute_endtime) {
    1228           0 :                 got_alarm = 0;
    1229           0 :                 CatchSignal(SIGALRM, gotalarm_sig);
    1230           0 :                 alarm(absolute_endtime - now);
    1231             :         }
    1232             : 
    1233           0 :         if (ldap_state->pid != getpid()) {
    1234           0 :                 smbldap_close(ldap_state);
    1235             :         }
    1236           0 : }
    1237             : 
    1238           0 : static void get_ldap_errs(struct smbldap_state *ldap_state, char **pp_ld_error, int *p_ld_errno)
    1239             : {
    1240           0 :         ldap_get_option(smbldap_get_ldap(ldap_state),
    1241             :                         LDAP_OPT_ERROR_NUMBER, p_ld_errno);
    1242             : 
    1243           0 :         ldap_get_option(smbldap_get_ldap(ldap_state),
    1244             :                         LDAP_OPT_ERROR_STRING, pp_ld_error);
    1245           0 : }
    1246             : 
    1247           0 : static int get_cached_ldap_connect(struct smbldap_state *ldap_state, time_t abs_endtime)
    1248             : {
    1249           0 :         int attempts = 0;
    1250             : 
    1251           0 :         while (1) {
    1252           0 :                 int rc;
    1253           0 :                 time_t now;
    1254             : 
    1255           0 :                 now = time_mono(NULL);
    1256           0 :                 ldap_state->last_use = now;
    1257             : 
    1258           0 :                 if (abs_endtime && now > abs_endtime) {
    1259           0 :                         smbldap_close(ldap_state);
    1260           0 :                         return LDAP_TIMEOUT;
    1261             :                 }
    1262             : 
    1263           0 :                 rc = smbldap_open(ldap_state);
    1264             : 
    1265           0 :                 if (rc == LDAP_SUCCESS) {
    1266           0 :                         return LDAP_SUCCESS;
    1267             :                 }
    1268             : 
    1269           0 :                 attempts++;
    1270           0 :                 DEBUG(1, ("Connection to LDAP server failed for the "
    1271             :                         "%d try!\n", attempts));
    1272             : 
    1273           0 :                 if (rc == LDAP_INSUFFICIENT_ACCESS) {
    1274             :                         /* The fact that we are non-root or any other
    1275             :                          * access-denied condition will not change in the next
    1276             :                          * round of trying */
    1277           0 :                         return rc;
    1278             :                 }
    1279             : 
    1280           0 :                 if (got_alarm) {
    1281           0 :                         smbldap_close(ldap_state);
    1282           0 :                         return LDAP_TIMEOUT;
    1283             :                 }
    1284             : 
    1285           0 :                 smb_msleep(1000);
    1286             : 
    1287           0 :                 if (got_alarm) {
    1288           0 :                         smbldap_close(ldap_state);
    1289           0 :                         return LDAP_TIMEOUT;
    1290             :                 }
    1291             :         }
    1292             : }
    1293             : 
    1294             : /*********************************************************************
    1295             :  ********************************************************************/
    1296             : 
    1297           0 : static int smbldap_search_ext(struct smbldap_state *ldap_state,
    1298             :                               const char *base, int scope, const char *filter,
    1299             :                               const char *attrs[], int attrsonly,
    1300             :                               LDAPControl **sctrls, LDAPControl **cctrls,
    1301             :                               int sizelimit, LDAPMessage **res)
    1302             : {
    1303           0 :         int             rc = LDAP_SERVER_DOWN;
    1304           0 :         char           *utf8_filter;
    1305           0 :         int             to = lp_ldap_timeout();
    1306           0 :         time_t          abs_endtime = calc_ldap_abs_endtime(to);
    1307           0 :         struct          timeval timeout;
    1308           0 :         struct          timeval *timeout_ptr = NULL;
    1309           0 :         size_t          converted_size;
    1310             : 
    1311           0 :         SMB_ASSERT(ldap_state);
    1312             : 
    1313           0 :         DEBUG(5,("smbldap_search_ext: base => [%s], filter => [%s], "
    1314             :                  "scope => [%d]\n", base, filter, scope));
    1315             : 
    1316           0 :         if (ldap_state->last_rebind.tv_sec > 0) {
    1317           0 :                 struct timeval  tval;
    1318           0 :                 struct timespec ts;
    1319           0 :                 int64_t tdiff = 0;
    1320           0 :                 int             sleep_time = 0;
    1321             : 
    1322           0 :                 clock_gettime_mono(&ts);
    1323           0 :                 tval = convert_timespec_to_timeval(ts);
    1324             : 
    1325           0 :                 tdiff = usec_time_diff(&tval, &ldap_state->last_rebind);
    1326           0 :                 tdiff /= 1000; /* Convert to milliseconds. */
    1327             : 
    1328           0 :                 sleep_time = lp_ldap_replication_sleep()-(int)tdiff;
    1329           0 :                 sleep_time = MIN(sleep_time, MAX_LDAP_REPLICATION_SLEEP_TIME);
    1330             : 
    1331           0 :                 if (sleep_time > 0) {
    1332             :                         /* we wait for the LDAP replication */
    1333           0 :                         DEBUG(5,("smbldap_search_ext: waiting %d milliseconds "
    1334             :                                  "for LDAP replication.\n",sleep_time));
    1335           0 :                         smb_msleep(sleep_time);
    1336           0 :                         DEBUG(5,("smbldap_search_ext: go on!\n"));
    1337             :                 }
    1338           0 :                 ZERO_STRUCT(ldap_state->last_rebind);
    1339             :         }
    1340             : 
    1341           0 :         if (!push_utf8_talloc(talloc_tos(), &utf8_filter, filter, &converted_size)) {
    1342           0 :                 return LDAP_NO_MEMORY;
    1343             :         }
    1344             : 
    1345             :         /* Setup remote timeout for the ldap_search_ext_s call. */
    1346           0 :         if (to) {
    1347           0 :                 timeout.tv_sec = to;
    1348           0 :                 timeout.tv_usec = 0;
    1349           0 :                 timeout_ptr = &timeout;
    1350             :         }
    1351             : 
    1352           0 :         setup_ldap_local_alarm(ldap_state, abs_endtime);
    1353             : 
    1354           0 :         while (1) {
    1355           0 :                 char *ld_error = NULL;
    1356           0 :                 int ld_errno;
    1357             : 
    1358           0 :                 rc = get_cached_ldap_connect(ldap_state, abs_endtime);
    1359           0 :                 if (rc != LDAP_SUCCESS) {
    1360           0 :                         break;
    1361             :                 }
    1362             : 
    1363           0 :                 rc = ldap_search_ext_s(smbldap_get_ldap(ldap_state),
    1364             :                                        base, scope,
    1365             :                                        utf8_filter,
    1366             :                                        discard_const_p(char *, attrs),
    1367             :                                        attrsonly, sctrls, cctrls, timeout_ptr,
    1368             :                                        sizelimit, res);
    1369           0 :                 if (rc == LDAP_SUCCESS) {
    1370           0 :                         break;
    1371             :                 }
    1372             : 
    1373           0 :                 get_ldap_errs(ldap_state, &ld_error, &ld_errno);
    1374             : 
    1375           0 :                 DEBUG(10, ("Failed search for base: %s, error: %d (%s) "
    1376             :                            "(%s)\n", base, ld_errno,
    1377             :                            ldap_err2string(rc),
    1378             :                            ld_error ? ld_error : "unknown"));
    1379           0 :                 SAFE_FREE(ld_error);
    1380             : 
    1381           0 :                 if (ld_errno != LDAP_SERVER_DOWN) {
    1382           0 :                         break;
    1383             :                 }
    1384           0 :                 ldap_unbind(smbldap_get_ldap(ldap_state));
    1385           0 :                 ldap_state->ldap_struct = NULL;
    1386             :         }
    1387             : 
    1388           0 :         TALLOC_FREE(utf8_filter);
    1389           0 :         return end_ldap_local_alarm(abs_endtime, rc);
    1390             : }
    1391             : 
    1392           0 : int smbldap_search(struct smbldap_state *ldap_state,
    1393             :                    const char *base, int scope, const char *filter,
    1394             :                    const char *attrs[], int attrsonly,
    1395             :                    LDAPMessage **res)
    1396             : {
    1397           0 :         return smbldap_search_ext(ldap_state, base, scope, filter, attrs,
    1398             :                                   attrsonly, NULL, NULL, LDAP_NO_LIMIT, res);
    1399             : }
    1400             : 
    1401           0 : int smbldap_search_paged(struct smbldap_state *ldap_state,
    1402             :                          const char *base, int scope, const char *filter,
    1403             :                          const char **attrs, int attrsonly, int pagesize,
    1404             :                          LDAPMessage **res, void **cookie)
    1405             : {
    1406           0 :         LDAPControl     pr;
    1407           0 :         LDAPControl     **rcontrols;
    1408           0 :         LDAPControl     *controls[2] = { NULL, NULL};
    1409           0 :         BerElement      *cookie_be = NULL;
    1410           0 :         struct berval   *cookie_bv = NULL;
    1411           0 :         int             tmp = 0, i, rc;
    1412           0 :         bool            critical = True;
    1413             : 
    1414           0 :         *res = NULL;
    1415             : 
    1416           0 :         DEBUG(3,("smbldap_search_paged: base => [%s], filter => [%s],"
    1417             :                  "scope => [%d], pagesize => [%d]\n",
    1418             :                  base, filter, scope, pagesize));
    1419             : 
    1420           0 :         cookie_be = ber_alloc_t(LBER_USE_DER);
    1421           0 :         if (cookie_be == NULL) {
    1422           0 :                 DEBUG(0,("smbldap_create_page_control: ber_alloc_t returns "
    1423             :                          "NULL\n"));
    1424           0 :                 return LDAP_NO_MEMORY;
    1425             :         }
    1426             : 
    1427             :         /* construct cookie */
    1428           0 :         if (*cookie != NULL) {
    1429           0 :                 ber_printf(cookie_be, "{iO}", (ber_int_t) pagesize, *cookie);
    1430           0 :                 ber_bvfree((struct berval *)*cookie); /* don't need it from last time */
    1431           0 :                 *cookie = NULL;
    1432             :         } else {
    1433           0 :                 ber_printf(cookie_be, "{io}", (ber_int_t) pagesize, "", 0);
    1434             :         }
    1435           0 :         ber_flatten(cookie_be, &cookie_bv);
    1436             : 
    1437           0 :         pr.ldctl_oid = discard_const_p(char, ADS_PAGE_CTL_OID);
    1438           0 :         pr.ldctl_iscritical = (char) critical;
    1439           0 :         pr.ldctl_value.bv_len = cookie_bv->bv_len;
    1440           0 :         pr.ldctl_value.bv_val = cookie_bv->bv_val;
    1441             : 
    1442           0 :         controls[0] = &pr;
    1443           0 :         controls[1] = NULL;
    1444             : 
    1445           0 :         rc = smbldap_search_ext(ldap_state, base, scope, filter, attrs,
    1446             :                                  0, controls, NULL, LDAP_NO_LIMIT, res);
    1447             : 
    1448           0 :         ber_free(cookie_be, 1);
    1449           0 :         ber_bvfree(cookie_bv);
    1450             : 
    1451           0 :         if (rc != 0) {
    1452           0 :                 DEBUG(3,("smbldap_search_paged: smbldap_search_ext(%s) "
    1453             :                          "failed with [%s]\n", filter, ldap_err2string(rc)));
    1454           0 :                 goto done;
    1455             :         }
    1456             : 
    1457           0 :         DEBUG(3,("smbldap_search_paged: search was successful\n"));
    1458             : 
    1459           0 :         rc = ldap_parse_result(smbldap_get_ldap(ldap_state), *res, NULL, NULL,
    1460             :                                NULL, NULL, &rcontrols,  0);
    1461           0 :         if (rc != 0) {
    1462           0 :                 DEBUG(3,("smbldap_search_paged: ldap_parse_result failed " \
    1463             :                          "with [%s]\n", ldap_err2string(rc)));
    1464           0 :                 goto done;
    1465             :         }
    1466             : 
    1467           0 :         if (rcontrols == NULL)
    1468           0 :                 goto done;
    1469             : 
    1470           0 :         for (i=0; rcontrols[i]; i++) {
    1471             : 
    1472           0 :                 if (strcmp(ADS_PAGE_CTL_OID, rcontrols[i]->ldctl_oid) != 0)
    1473           0 :                         continue;
    1474             : 
    1475           0 :                 cookie_be = ber_init(&rcontrols[i]->ldctl_value);
    1476           0 :                 ber_scanf(cookie_be,"{iO}", &tmp, &cookie_bv);
    1477             :                 /* the berval is the cookie, but must be freed when it is all
    1478             :                    done */
    1479           0 :                 if (cookie_bv->bv_len)
    1480           0 :                         *cookie=ber_bvdup(cookie_bv);
    1481             :                 else
    1482           0 :                         *cookie=NULL;
    1483           0 :                 ber_bvfree(cookie_bv);
    1484           0 :                 ber_free(cookie_be, 1);
    1485           0 :                 break;
    1486             :         }
    1487           0 :         ldap_controls_free(rcontrols);
    1488           0 : done:
    1489           0 :         return rc;
    1490             : }
    1491             : 
    1492           0 : int smbldap_modify(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs[])
    1493             : {
    1494           0 :         int             rc = LDAP_SERVER_DOWN;
    1495           0 :         char           *utf8_dn;
    1496           0 :         time_t          abs_endtime = calc_ldap_abs_endtime(lp_ldap_timeout());
    1497           0 :         size_t          converted_size;
    1498             : 
    1499           0 :         SMB_ASSERT(ldap_state);
    1500             : 
    1501           0 :         DEBUG(5,("smbldap_modify: dn => [%s]\n", dn ));
    1502             : 
    1503           0 :         if (!push_utf8_talloc(talloc_tos(), &utf8_dn, dn, &converted_size)) {
    1504           0 :                 return LDAP_NO_MEMORY;
    1505             :         }
    1506             : 
    1507           0 :         setup_ldap_local_alarm(ldap_state, abs_endtime);
    1508             : 
    1509           0 :         while (1) {
    1510           0 :                 char *ld_error = NULL;
    1511           0 :                 int ld_errno;
    1512             : 
    1513           0 :                 rc = get_cached_ldap_connect(ldap_state, abs_endtime);
    1514           0 :                 if (rc != LDAP_SUCCESS) {
    1515           0 :                         break;
    1516             :                 }
    1517             : 
    1518           0 :                 rc = ldap_modify_s(smbldap_get_ldap(ldap_state), utf8_dn,
    1519             :                                    attrs);
    1520           0 :                 if (rc == LDAP_SUCCESS) {
    1521           0 :                         break;
    1522             :                 }
    1523             : 
    1524           0 :                 get_ldap_errs(ldap_state, &ld_error, &ld_errno);
    1525             : 
    1526           0 :                 DEBUG(10, ("Failed to modify dn: %s, error: %d (%s) "
    1527             :                            "(%s)\n", dn, ld_errno,
    1528             :                            ldap_err2string(rc),
    1529             :                            ld_error ? ld_error : "unknown"));
    1530           0 :                 SAFE_FREE(ld_error);
    1531             : 
    1532           0 :                 if (ld_errno != LDAP_SERVER_DOWN) {
    1533           0 :                         break;
    1534             :                 }
    1535           0 :                 ldap_unbind(smbldap_get_ldap(ldap_state));
    1536           0 :                 ldap_state->ldap_struct = NULL;
    1537             :         }
    1538             : 
    1539           0 :         TALLOC_FREE(utf8_dn);
    1540           0 :         return end_ldap_local_alarm(abs_endtime, rc);
    1541             : }
    1542             : 
    1543           0 : int smbldap_add(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs[])
    1544             : {
    1545           0 :         int             rc = LDAP_SERVER_DOWN;
    1546           0 :         char           *utf8_dn;
    1547           0 :         time_t          abs_endtime = calc_ldap_abs_endtime(lp_ldap_timeout());
    1548           0 :         size_t          converted_size;
    1549             : 
    1550           0 :         SMB_ASSERT(ldap_state);
    1551             : 
    1552           0 :         DEBUG(5,("smbldap_add: dn => [%s]\n", dn ));
    1553             : 
    1554           0 :         if (!push_utf8_talloc(talloc_tos(), &utf8_dn, dn, &converted_size)) {
    1555           0 :                 return LDAP_NO_MEMORY;
    1556             :         }
    1557             : 
    1558           0 :         setup_ldap_local_alarm(ldap_state, abs_endtime);
    1559             : 
    1560           0 :         while (1) {
    1561           0 :                 char *ld_error = NULL;
    1562           0 :                 int ld_errno;
    1563             : 
    1564           0 :                 rc = get_cached_ldap_connect(ldap_state, abs_endtime);
    1565           0 :                 if (rc != LDAP_SUCCESS) {
    1566           0 :                         break;
    1567             :                 }
    1568             : 
    1569           0 :                 rc = ldap_add_s(smbldap_get_ldap(ldap_state), utf8_dn, attrs);
    1570           0 :                 if (rc == LDAP_SUCCESS) {
    1571           0 :                         break;
    1572             :                 }
    1573             : 
    1574           0 :                 get_ldap_errs(ldap_state, &ld_error, &ld_errno);
    1575             : 
    1576           0 :                 DEBUG(10, ("Failed to add dn: %s, error: %d (%s) "
    1577             :                            "(%s)\n", dn, ld_errno,
    1578             :                            ldap_err2string(rc),
    1579             :                            ld_error ? ld_error : "unknown"));
    1580           0 :                 SAFE_FREE(ld_error);
    1581             : 
    1582           0 :                 if (ld_errno != LDAP_SERVER_DOWN) {
    1583           0 :                         break;
    1584             :                 }
    1585           0 :                 ldap_unbind(smbldap_get_ldap(ldap_state));
    1586           0 :                 ldap_state->ldap_struct = NULL;
    1587             :         }
    1588             : 
    1589           0 :         TALLOC_FREE(utf8_dn);
    1590           0 :         return end_ldap_local_alarm(abs_endtime, rc);
    1591             : }
    1592             : 
    1593           0 : int smbldap_delete(struct smbldap_state *ldap_state, const char *dn)
    1594             : {
    1595           0 :         int             rc = LDAP_SERVER_DOWN;
    1596           0 :         char           *utf8_dn;
    1597           0 :         time_t          abs_endtime = calc_ldap_abs_endtime(lp_ldap_timeout());
    1598           0 :         size_t          converted_size;
    1599             : 
    1600           0 :         SMB_ASSERT(ldap_state);
    1601             : 
    1602           0 :         DEBUG(5,("smbldap_delete: dn => [%s]\n", dn ));
    1603             : 
    1604           0 :         if (!push_utf8_talloc(talloc_tos(), &utf8_dn, dn, &converted_size)) {
    1605           0 :                 return LDAP_NO_MEMORY;
    1606             :         }
    1607             : 
    1608           0 :         setup_ldap_local_alarm(ldap_state, abs_endtime);
    1609             : 
    1610           0 :         while (1) {
    1611           0 :                 char *ld_error = NULL;
    1612           0 :                 int ld_errno;
    1613             : 
    1614           0 :                 rc = get_cached_ldap_connect(ldap_state, abs_endtime);
    1615           0 :                 if (rc != LDAP_SUCCESS) {
    1616           0 :                         break;
    1617             :                 }
    1618             : 
    1619           0 :                 rc = ldap_delete_s(smbldap_get_ldap(ldap_state), utf8_dn);
    1620           0 :                 if (rc == LDAP_SUCCESS) {
    1621           0 :                         break;
    1622             :                 }
    1623             : 
    1624           0 :                 get_ldap_errs(ldap_state, &ld_error, &ld_errno);
    1625             : 
    1626           0 :                 DEBUG(10, ("Failed to delete dn: %s, error: %d (%s) "
    1627             :                            "(%s)\n", dn, ld_errno,
    1628             :                            ldap_err2string(rc),
    1629             :                            ld_error ? ld_error : "unknown"));
    1630           0 :                 SAFE_FREE(ld_error);
    1631             : 
    1632           0 :                 if (ld_errno != LDAP_SERVER_DOWN) {
    1633           0 :                         break;
    1634             :                 }
    1635           0 :                 ldap_unbind(smbldap_get_ldap(ldap_state));
    1636           0 :                 ldap_state->ldap_struct = NULL;
    1637             :         }
    1638             : 
    1639           0 :         TALLOC_FREE(utf8_dn);
    1640           0 :         return end_ldap_local_alarm(abs_endtime, rc);
    1641             : }
    1642             : 
    1643           0 : int smbldap_extended_operation(struct smbldap_state *ldap_state,
    1644             :                                LDAP_CONST char *reqoid, struct berval *reqdata,
    1645             :                                LDAPControl **serverctrls, LDAPControl **clientctrls,
    1646             :                                char **retoidp, struct berval **retdatap)
    1647             : {
    1648           0 :         int             rc = LDAP_SERVER_DOWN;
    1649           0 :         time_t          abs_endtime = calc_ldap_abs_endtime(lp_ldap_timeout());
    1650             : 
    1651           0 :         if (!ldap_state)
    1652           0 :                 return (-1);
    1653             : 
    1654           0 :         setup_ldap_local_alarm(ldap_state, abs_endtime);
    1655             : 
    1656           0 :         while (1) {
    1657           0 :                 char *ld_error = NULL;
    1658           0 :                 int ld_errno;
    1659             : 
    1660           0 :                 rc = get_cached_ldap_connect(ldap_state, abs_endtime);
    1661           0 :                 if (rc != LDAP_SUCCESS) {
    1662           0 :                         break;
    1663             :                 }
    1664             : 
    1665           0 :                 rc = ldap_extended_operation_s(smbldap_get_ldap(ldap_state),
    1666             :                                                reqoid,
    1667             :                                                reqdata, serverctrls,
    1668             :                                                clientctrls, retoidp, retdatap);
    1669           0 :                 if (rc == LDAP_SUCCESS) {
    1670           0 :                         break;
    1671             :                 }
    1672             : 
    1673           0 :                 get_ldap_errs(ldap_state, &ld_error, &ld_errno);
    1674             : 
    1675           0 :                 DEBUG(10, ("Extended operation failed with error: "
    1676             :                            "%d (%s) (%s)\n", ld_errno,
    1677             :                            ldap_err2string(rc),
    1678             :                            ld_error ? ld_error : "unknown"));
    1679           0 :                 SAFE_FREE(ld_error);
    1680             : 
    1681           0 :                 if (ld_errno != LDAP_SERVER_DOWN) {
    1682           0 :                         break;
    1683             :                 }
    1684           0 :                 ldap_unbind(smbldap_get_ldap(ldap_state));
    1685           0 :                 ldap_state->ldap_struct = NULL;
    1686             :         }
    1687             : 
    1688           0 :         return end_ldap_local_alarm(abs_endtime, rc);
    1689             : }
    1690             : 
    1691             : /*******************************************************************
    1692             :  run the search by name.
    1693             : ******************************************************************/
    1694           0 : int smbldap_search_suffix (struct smbldap_state *ldap_state,
    1695             :                            const char *filter, const char **search_attr,
    1696             :                            LDAPMessage ** result)
    1697             : {
    1698           0 :         return smbldap_search(ldap_state, lp_ldap_suffix(),
    1699             :                               LDAP_SCOPE_SUBTREE,
    1700             :                               filter, search_attr, 0, result);
    1701             : }
    1702             : 
    1703           0 : static void smbldap_idle_fn(struct tevent_context *tevent_ctx,
    1704             :                             struct tevent_timer *te,
    1705             :                             struct timeval now_abs,
    1706             :                             void *private_data)
    1707             : {
    1708           0 :         struct smbldap_state *state = (struct smbldap_state *)private_data;
    1709             : 
    1710           0 :         TALLOC_FREE(state->idle_event);
    1711             : 
    1712           0 :         if (smbldap_get_ldap(state) == NULL) {
    1713           0 :                 DEBUG(10,("ldap connection not connected...\n"));
    1714           0 :                 return;
    1715             :         }
    1716             : 
    1717           0 :         if ((state->last_use+SMBLDAP_IDLE_TIME) > time_mono(NULL)) {
    1718           0 :                 DEBUG(10,("ldap connection not idle...\n"));
    1719             : 
    1720             :                 /* this needs to be made monotonic clock aware inside tevent: */
    1721           0 :                 state->idle_event = tevent_add_timer(
    1722             :                         tevent_ctx, state,
    1723             :                         timeval_add(&now_abs, SMBLDAP_IDLE_TIME, 0),
    1724             :                         smbldap_idle_fn,
    1725             :                         private_data);
    1726           0 :                 return;
    1727             :         }
    1728             : 
    1729           0 :         DEBUG(7,("ldap connection idle...closing connection\n"));
    1730           0 :         smbldap_close(state);
    1731             : }
    1732             : 
    1733             : /**********************************************************************
    1734             :  Housekeeping
    1735             :  *********************************************************************/
    1736             : 
    1737           0 : void smbldap_free_struct(struct smbldap_state **ldap_state)
    1738             : {
    1739           0 :         smbldap_close(*ldap_state);
    1740             : 
    1741           0 :         if ((*ldap_state)->bind_secret) {
    1742           0 :                 memset((*ldap_state)->bind_secret, '\0', strlen((*ldap_state)->bind_secret));
    1743             :         }
    1744             : 
    1745           0 :         SAFE_FREE((*ldap_state)->bind_dn);
    1746           0 :         BURN_FREE_STR((*ldap_state)->bind_secret);
    1747           0 :         smbldap_set_bind_callback(*ldap_state, NULL, NULL);
    1748             : 
    1749           0 :         TALLOC_FREE(*ldap_state);
    1750             : 
    1751             :         /* No need to free any further, as it is talloc()ed */
    1752           0 : }
    1753             : 
    1754           0 : static int smbldap_state_destructor(struct smbldap_state *state)
    1755             : {
    1756           0 :         smbldap_free_struct(&state);
    1757           0 :         return 0;
    1758             : }
    1759             : 
    1760             : 
    1761             : /**********************************************************************
    1762             :  Initialise the 'general' ldap structures, on which ldap operations may be conducted
    1763             :  *********************************************************************/
    1764             : 
    1765           0 : NTSTATUS smbldap_init(TALLOC_CTX *mem_ctx, struct tevent_context *tevent_ctx,
    1766             :                       const char *location,
    1767             :                       bool anon,
    1768             :                       const char *bind_dn,
    1769             :                       const char *bind_secret,
    1770             :                       struct smbldap_state **smbldap_state)
    1771             : {
    1772           0 :         *smbldap_state = talloc_zero(mem_ctx, struct smbldap_state);
    1773           0 :         if (!*smbldap_state) {
    1774           0 :                 DEBUG(0, ("talloc() failed for ldapsam private_data!\n"));
    1775           0 :                 return NT_STATUS_NO_MEMORY;
    1776             :         }
    1777             : 
    1778           0 :         if (location) {
    1779           0 :                 (*smbldap_state)->uri = talloc_strdup(mem_ctx, location);
    1780             :         } else {
    1781           0 :                 (*smbldap_state)->uri = "ldap://localhost";
    1782             :         }
    1783             : 
    1784           0 :         (*smbldap_state)->tevent_context = tevent_ctx;
    1785             : 
    1786           0 :         if (bind_dn && bind_secret) {
    1787           0 :                 smbldap_set_creds(*smbldap_state, anon, bind_dn, bind_secret);
    1788             :         }
    1789             : 
    1790           0 :         talloc_set_destructor(*smbldap_state, smbldap_state_destructor);
    1791           0 :         return NT_STATUS_OK;
    1792             : }
    1793             : 
    1794           0 :  char *smbldap_talloc_dn(TALLOC_CTX *mem_ctx, LDAP *ld,
    1795             :                          LDAPMessage *entry)
    1796             : {
    1797           0 :         char *utf8_dn, *unix_dn;
    1798           0 :         size_t converted_size;
    1799             : 
    1800           0 :         utf8_dn = ldap_get_dn(ld, entry);
    1801           0 :         if (!utf8_dn) {
    1802           0 :                 DEBUG (5, ("smbldap_talloc_dn: ldap_get_dn failed\n"));
    1803           0 :                 return NULL;
    1804             :         }
    1805           0 :         if (!pull_utf8_talloc(mem_ctx, &unix_dn, utf8_dn, &converted_size)) {
    1806           0 :                 DEBUG (0, ("smbldap_talloc_dn: String conversion failure utf8 "
    1807             :                            "[%s]\n", utf8_dn));
    1808           0 :                 return NULL;
    1809             :         }
    1810           0 :         ldap_memfree(utf8_dn);
    1811           0 :         return unix_dn;
    1812             : }
    1813             : 
    1814             : /*******************************************************************
    1815             :  Check if root-dse has a certain Control or Extension
    1816             : ********************************************************************/
    1817             : 
    1818           0 : static bool smbldap_check_root_dse(LDAP *ld, const char **attrs, const char *value)
    1819             : {
    1820           0 :         LDAPMessage *msg = NULL;
    1821           0 :         LDAPMessage *entry = NULL;
    1822           0 :         char **values = NULL;
    1823           0 :         int rc, num_result, num_values, i;
    1824           0 :         bool result = False;
    1825             : 
    1826           0 :         if (!attrs[0]) {
    1827           0 :                 DEBUG(3,("smbldap_check_root_dse: nothing to look for\n"));
    1828           0 :                 return False;
    1829             :         }
    1830             : 
    1831           0 :         if (!strequal(attrs[0], "supportedExtension") &&
    1832           0 :             !strequal(attrs[0], "supportedControl") &&
    1833           0 :             !strequal(attrs[0], "namingContexts")) {
    1834           0 :                 DEBUG(3,("smbldap_check_root_dse: no idea what to query root-dse for: %s ?\n", attrs[0]));
    1835           0 :                 return False;
    1836             :         }
    1837             : 
    1838           0 :         rc = ldap_search_s(ld, "", LDAP_SCOPE_BASE,
    1839             :                            "(objectclass=*)", discard_const_p(char *, attrs), 0 , &msg);
    1840             : 
    1841           0 :         if (rc != LDAP_SUCCESS) {
    1842           0 :                 DEBUG(3,("smbldap_check_root_dse: Could not search rootDSE\n"));
    1843           0 :                 return False;
    1844             :         }
    1845             : 
    1846           0 :         num_result = ldap_count_entries(ld, msg);
    1847             : 
    1848           0 :         if (num_result != 1) {
    1849           0 :                 DEBUG(3,("smbldap_check_root_dse: Expected one rootDSE, got %d\n", num_result));
    1850           0 :                 goto done;
    1851             :         }
    1852             : 
    1853           0 :         entry = ldap_first_entry(ld, msg);
    1854             : 
    1855           0 :         if (entry == NULL) {
    1856           0 :                 DEBUG(3,("smbldap_check_root_dse: Could not retrieve rootDSE\n"));
    1857           0 :                 goto done;
    1858             :         }
    1859             : 
    1860           0 :         values = ldap_get_values(ld, entry, attrs[0]);
    1861             : 
    1862           0 :         if (values == NULL) {
    1863           0 :                 DEBUG(5,("smbldap_check_root_dse: LDAP Server does not support any %s\n", attrs[0]));
    1864           0 :                 goto done;
    1865             :         }
    1866             : 
    1867           0 :         num_values = ldap_count_values(values);
    1868             : 
    1869           0 :         if (num_values == 0) {
    1870           0 :                 DEBUG(5,("smbldap_check_root_dse: LDAP Server does not have any %s\n", attrs[0]));
    1871           0 :                 goto done;
    1872             :         }
    1873             : 
    1874           0 :         for (i=0; i<num_values; i++) {
    1875           0 :                 if (strcmp(values[i], value) == 0)
    1876           0 :                         result = True;
    1877             :         }
    1878             : 
    1879             : 
    1880           0 :  done:
    1881           0 :         if (values != NULL)
    1882           0 :                 ldap_value_free(values);
    1883           0 :         if (msg != NULL)
    1884           0 :                 ldap_msgfree(msg);
    1885             : 
    1886           0 :         return result;
    1887             : 
    1888             : }
    1889             : 
    1890             : /*******************************************************************
    1891             :  Check if LDAP-Server supports a certain Control (OID in string format)
    1892             : ********************************************************************/
    1893             : 
    1894           0 : bool smbldap_has_control(LDAP *ld, const char *control)
    1895             : {
    1896           0 :         const char *attrs[] = { "supportedControl", NULL };
    1897           0 :         return smbldap_check_root_dse(ld, attrs, control);
    1898             : }
    1899             : 
    1900             : /*******************************************************************
    1901             :  Check if LDAP-Server supports a certain Extension (OID in string format)
    1902             : ********************************************************************/
    1903             : 
    1904           0 : bool smbldap_has_extension(LDAP *ld, const char *extension)
    1905             : {
    1906           0 :         const char *attrs[] = { "supportedExtension", NULL };
    1907           0 :         return smbldap_check_root_dse(ld, attrs, extension);
    1908             : }
    1909             : 
    1910             : /*******************************************************************
    1911             :  Check if LDAP-Server holds a given namingContext
    1912             : ********************************************************************/
    1913             : 
    1914           0 : bool smbldap_has_naming_context(LDAP *ld, const char *naming_context)
    1915             : {
    1916           0 :         const char *attrs[] = { "namingContexts", NULL };
    1917           0 :         return smbldap_check_root_dse(ld, attrs, naming_context);
    1918             : }
    1919             : 
    1920           0 : bool smbldap_set_creds(struct smbldap_state *ldap_state, bool anon, const char *dn, const char *secret)
    1921             : {
    1922           0 :         ldap_state->anonymous = anon;
    1923             : 
    1924             :         /* free any previously set credential */
    1925             : 
    1926           0 :         SAFE_FREE(ldap_state->bind_dn);
    1927           0 :         smbldap_set_bind_callback(ldap_state, NULL, NULL);
    1928             : 
    1929           0 :         if (ldap_state->bind_secret) {
    1930             :                 /* make sure secrets are zeroed out of memory */
    1931           0 :                 memset(ldap_state->bind_secret, '\0', strlen(ldap_state->bind_secret));
    1932           0 :                 SAFE_FREE(ldap_state->bind_secret);
    1933             :         }
    1934             : 
    1935           0 :         if ( ! anon) {
    1936           0 :                 ldap_state->bind_dn = SMB_STRDUP(dn);
    1937           0 :                 ldap_state->bind_secret = SMB_STRDUP(secret);
    1938             :         }
    1939             : 
    1940           0 :         return True;
    1941             : }

Generated by: LCOV version 1.14