LCOV - code coverage report
Current view: top level - source3/lib - smbldap.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 12 741 1.6 %
Date: 2021-09-23 10:06:22 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             :         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             :         char **values;
     127             :         char *result;
     128             :         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             :         char **values;
     168             :         char *result;
     169             :         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             :         char **values;
     202             :         char *result;
     203             :         size_t converted_size;
     204             :         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             :                 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         192 :  bool smbldap_talloc_single_blob(TALLOC_CTX *mem_ctx, LDAP *ld,
     254             :                                  LDAPMessage *msg, const char *attrib,
     255             :                                  DATA_BLOB *blob)
     256             : {
     257             :         struct berval **values;
     258             : 
     259         192 :         values = ldap_get_values_len(ld, msg, attrib);
     260         192 :         if (!values) {
     261           0 :                 return false;
     262             :         }
     263             : 
     264         192 :         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         192 :         *blob = data_blob_talloc(mem_ctx, values[0]->bv_val,
     271             :                                  values[0]->bv_len);
     272         192 :         ldap_value_free_len(values);
     273             : 
     274         192 :         return (blob->data != NULL);
     275             : }
     276             : 
     277         192 :  bool smbldap_pull_sid(LDAP *ld, LDAPMessage *msg, const char *attrib,
     278             :                        struct dom_sid *sid)
     279             : {
     280             :         DATA_BLOB blob;
     281             :         ssize_t ret;
     282             : 
     283         192 :         if (!smbldap_talloc_single_blob(talloc_tos(), ld, msg, attrib,
     284             :                                         &blob)) {
     285           0 :                 return false;
     286             :         }
     287         192 :         ret = sid_parse(blob.data, blob.length, sid);
     288         192 :         TALLOC_FREE(blob.data);
     289         192 :         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             :         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             :         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             :         LDAPMod **mods;
     340             :         int i;
     341             :         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             :                 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             :         char oldval[2048]; /* current largest allowed value is mungeddial */
     459             :         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 varients 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             :         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             :         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             :         struct smbldap_state *tmp_ldap_state;
     585             :         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             :         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             :         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           0 :         return LDAP_SUCCESS;
     674             : #else 
     675             : 
     676             :         /* Parse the string manually */
     677             : 
     678             :         {
     679             :                 int port = 0;
     680             :                 fstring protocol;
     681             :                 fstring host;
     682             :                 SMB_ASSERT(sizeof(protocol)>10 && sizeof(host)>254);
     683             : 
     684             : 
     685             :                 /* skip leading "URL:" (if any) */
     686             :                 if ( strnequal( uri, "URL:", 4 ) ) {
     687             :                         uri += 4;
     688             :                 }
     689             : 
     690             :                 sscanf(uri, "%10[^:]://%254[^:/]:%d", protocol, host, &port);
     691             : 
     692             :                 if (port == 0) {
     693             :                         if (strequal(protocol, "ldap")) {
     694             :                                 port = LDAP_PORT;
     695             :                         } else if (strequal(protocol, "ldaps")) {
     696             :                                 port = LDAPS_PORT;
     697             :                         } else {
     698             :                                 DEBUG(0, ("unrecognised protocol (%s)!\n", protocol));
     699             :                         }
     700             :                 }
     701             : 
     702             :                 if ((*ldap_struct = ldap_init(host, port)) == NULL)     {
     703             :                         DEBUG(0, ("ldap_init failed !\n"));
     704             :                         return LDAP_OPERATIONS_ERROR;
     705             :                 }
     706             : 
     707             :                 if (strequal(protocol, "ldaps")) {
     708             : #ifdef LDAP_OPT_X_TLS
     709             :                         int tls = LDAP_OPT_X_TLS_HARD;
     710             :                         if (ldap_set_option (*ldap_struct, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS)
     711             :                         {
     712             :                                 DEBUG(0, ("Failed to setup a TLS session\n"));
     713             :                         }
     714             : 
     715             :                         DEBUG(3,("LDAPS option set...!\n"));
     716             : #else
     717             :                         DEBUG(0,("smbldap_open_connection: Secure connection not supported by LDAP client libraries!\n"));
     718             :                         return LDAP_OPERATIONS_ERROR;
     719             : #endif /* LDAP_OPT_X_TLS */
     720             :                 }
     721             :         }
     722             : #endif /* HAVE_LDAP_INITIALIZE */
     723             : 
     724             :         /* now set connection timeout */
     725             : #ifdef LDAP_X_OPT_CONNECT_TIMEOUT /* Netscape */
     726             :         {
     727             :                 int ct = lp_ldap_connection_timeout()*1000;
     728             :                 rc = ldap_set_option(*ldap_struct, LDAP_X_OPT_CONNECT_TIMEOUT, &ct);
     729             :                 if (rc != LDAP_SUCCESS) {
     730             :                         DEBUG(0,("Failed to setup an ldap connection timeout %d: %s\n",
     731             :                                 ct, ldap_err2string(rc)));
     732             :                 }
     733             :         }
     734             : #elif defined (LDAP_OPT_NETWORK_TIMEOUT) /* OpenLDAP */
     735             :         {
     736             :                 struct timeval ct;
     737             :                 ct.tv_usec = 0;
     738             :                 ct.tv_sec = lp_ldap_connection_timeout();
     739             :                 rc = ldap_set_option(*ldap_struct, LDAP_OPT_NETWORK_TIMEOUT, &ct);
     740             :                 if (rc != LDAP_SUCCESS) {
     741             :                         DEBUG(0,("Failed to setup an ldap connection timeout %d: %s\n",
     742             :                                 (int)ct.tv_sec, ldap_err2string(rc)));
     743             :                 }
     744             :         }
     745             : #endif
     746             : 
     747             :         return LDAP_SUCCESS;
     748             : }
     749             : 
     750             : /********************************************************************
     751             :  try to upgrade to Version 3 LDAP if not already, in either case return current
     752             :  version 
     753             :  *******************************************************************/
     754             : 
     755           0 : static int smb_ldap_upgrade_conn(LDAP *ldap_struct, int *new_version)
     756             : {
     757             :         int version;
     758             :         int rc;
     759             : 
     760             :         /* assume the worst */
     761           0 :         *new_version = LDAP_VERSION2;
     762             : 
     763           0 :         rc = ldap_get_option(ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version);
     764           0 :         if (rc) {
     765           0 :                 return rc;
     766             :         }
     767             : 
     768           0 :         if (version == LDAP_VERSION3) {
     769           0 :                 *new_version = LDAP_VERSION3;
     770           0 :                 return LDAP_SUCCESS;
     771             :         }
     772             : 
     773             :         /* try upgrade */
     774           0 :         version = LDAP_VERSION3;
     775           0 :         rc = ldap_set_option (ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version);
     776           0 :         if (rc) {
     777           0 :                 return rc;
     778             :         }
     779             : 
     780           0 :         *new_version = LDAP_VERSION3;
     781           0 :         return LDAP_SUCCESS;
     782             : }
     783             : 
     784             : /*******************************************************************
     785             :  open a connection to the ldap server (just until the bind)
     786             :  ******************************************************************/
     787             : 
     788           0 : int smbldap_setup_full_conn(LDAP **ldap_struct, const char *uri)
     789             : {
     790             :         int rc, version;
     791             : 
     792           0 :         rc = smb_ldap_setup_conn(ldap_struct, uri);
     793           0 :         if (rc) {
     794           0 :                 return rc;
     795             :         }
     796             : 
     797           0 :         rc = smb_ldap_upgrade_conn(*ldap_struct, &version);
     798           0 :         if (rc) {
     799           0 :                 return rc;
     800             :         }
     801             : 
     802           0 :         rc = smbldap_start_tls(*ldap_struct, version);
     803           0 :         if (rc) {
     804           0 :                 return rc;
     805             :         }
     806             : 
     807           0 :         return LDAP_SUCCESS;
     808             : }
     809             : 
     810             : /*******************************************************************
     811             :  open a connection to the ldap server.
     812             : ******************************************************************/
     813           0 : static int smbldap_open_connection (struct smbldap_state *ldap_state)
     814             : 
     815             : {
     816           0 :         int rc = LDAP_SUCCESS;
     817             :         int version;
     818             :         int deref;
     819           0 :         LDAP **ldap_struct = &ldap_state->ldap_struct;
     820             : 
     821           0 :         rc = smb_ldap_setup_conn(ldap_struct, ldap_state->uri);
     822           0 :         if (rc) {
     823           0 :                 return rc;
     824             :         }
     825             : 
     826             :         /* Store the LDAP pointer in a lookup list */
     827             : 
     828           0 :         smbldap_store_state(*ldap_struct, ldap_state);
     829             : 
     830             :         /* Upgrade to LDAPv3 if possible */
     831             : 
     832           0 :         rc = smb_ldap_upgrade_conn(*ldap_struct, &version);
     833           0 :         if (rc) {
     834           0 :                 return rc;
     835             :         }
     836             : 
     837             :         /* Start TLS if required */
     838             : 
     839           0 :         rc = smbldap_start_tls(*ldap_struct, version);
     840           0 :         if (rc) {
     841           0 :                 return rc;
     842             :         }
     843             : 
     844             :         /* Set alias dereferencing method */
     845           0 :         deref = lp_ldap_deref();
     846           0 :         if (deref != -1) {
     847           0 :                 if (ldap_set_option (*ldap_struct, LDAP_OPT_DEREF, &deref) != LDAP_OPT_SUCCESS) {
     848           0 :                         DEBUG(1,("smbldap_open_connection: Failed to set dereferencing method: %d\n", deref));
     849             :                 } else {
     850           0 :                         DEBUG(5,("Set dereferencing method: %d\n", deref));
     851             :                 }
     852             :         }
     853             : 
     854           0 :         DEBUG(2, ("smbldap_open_connection: connection opened\n"));
     855           0 :         return rc;
     856             : }
     857             : 
     858             : /*******************************************************************
     859             :  a rebind function for authenticated referrals
     860             :  This version takes a void* that we can shove useful stuff in :-)
     861             : ******************************************************************/
     862             : #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
     863             : #else
     864             : static int rebindproc_with_state  (LDAP * ld, char **whop, char **credp, 
     865             :                                    int *methodp, int freeit, void *arg)
     866             : {
     867             :         struct smbldap_state *ldap_state = arg;
     868             :         struct timespec ts;
     869             : 
     870             :         /** @TODO Should we be doing something to check what servers we rebind to?
     871             :             Could we get a referral to a machine that we don't want to give our
     872             :             username and password to? */
     873             : 
     874             :         if (freeit) {
     875             :                 SAFE_FREE(*whop);
     876             :                 if (*credp) {
     877             :                         memset(*credp, '\0', strlen(*credp));
     878             :                 }
     879             :                 SAFE_FREE(*credp);
     880             :         } else {
     881             :                 DEBUG(5,("rebind_proc_with_state: Rebinding as \"%s\"\n", 
     882             :                           ldap_state->bind_dn?ldap_state->bind_dn:"[Anonymous bind]"));
     883             : 
     884             :                 if (ldap_state->anonymous) {
     885             :                         *whop = NULL;
     886             :                         *credp = NULL;
     887             :                 } else {
     888             :                         *whop = SMB_STRDUP(ldap_state->bind_dn);
     889             :                         if (!*whop) {
     890             :                                 return LDAP_NO_MEMORY;
     891             :                         }
     892             :                         *credp = SMB_STRDUP(ldap_state->bind_secret);
     893             :                         if (!*credp) {
     894             :                                 SAFE_FREE(*whop);
     895             :                                 return LDAP_NO_MEMORY;
     896             :                         }
     897             :                 }
     898             :                 *methodp = LDAP_AUTH_SIMPLE;
     899             :         }
     900             : 
     901             :         clock_gettime_mono(&ts);
     902             :         ldap_state->last_rebind = convert_timespec_to_timeval(ts);
     903             : 
     904             :         return 0;
     905             : }
     906             : #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
     907             : 
     908             : /*******************************************************************
     909             :  a rebind function for authenticated referrals
     910             :  This version takes a void* that we can shove useful stuff in :-)
     911             :  and actually does the connection.
     912             : ******************************************************************/
     913             : #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
     914           0 : static int rebindproc_connect_with_state (LDAP *ldap_struct, 
     915             :                                           LDAP_CONST char *url, 
     916             :                                           ber_tag_t request,
     917             :                                           ber_int_t msgid, void *arg)
     918             : {
     919           0 :         struct smbldap_state *ldap_state =
     920             :                 (struct smbldap_state *)arg;
     921             :         int rc;
     922             :         struct timespec ts;
     923             :         int version;
     924             : 
     925           0 :         DEBUG(5,("rebindproc_connect_with_state: Rebinding to %s as \"%s\"\n", 
     926             :                  url, ldap_state->bind_dn?ldap_state->bind_dn:"[Anonymous bind]"));
     927             : 
     928             :         /* call START_TLS again (ldaps:// is handled by the OpenLDAP library
     929             :          * itself) before rebinding to another LDAP server to avoid to expose
     930             :          * our credentials. At least *try* to secure the connection - Guenther */
     931             : 
     932           0 :         smb_ldap_upgrade_conn(ldap_struct, &version);
     933           0 :         smbldap_start_tls(ldap_struct, version);
     934             : 
     935             :         /** @TODO Should we be doing something to check what servers we rebind to?
     936             :             Could we get a referral to a machine that we don't want to give our
     937             :             username and password to? */
     938             : 
     939           0 :         rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret);
     940             : 
     941             :         /* only set the last rebind timestamp when we did rebind after a
     942             :          * non-read LDAP operation. That way we avoid the replication sleep
     943             :          * after a simple redirected search operation - Guenther */
     944             : 
     945           0 :         switch (request) {
     946             : 
     947           0 :                 case LDAP_REQ_MODIFY:
     948             :                 case LDAP_REQ_ADD:
     949             :                 case LDAP_REQ_DELETE:
     950             :                 case LDAP_REQ_MODDN:
     951             :                 case LDAP_REQ_EXTENDED:
     952           0 :                         DEBUG(10,("rebindproc_connect_with_state: "
     953             :                                 "setting last_rebind timestamp "
     954             :                                 "(req: 0x%02x)\n", (unsigned int)request));
     955           0 :                         clock_gettime_mono(&ts);
     956           0 :                         ldap_state->last_rebind = convert_timespec_to_timeval(ts);
     957           0 :                         break;
     958           0 :                 default:
     959           0 :                         ZERO_STRUCT(ldap_state->last_rebind);
     960           0 :                         break;
     961             :         }
     962             : 
     963           0 :         return rc;
     964             : }
     965             : #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
     966             : 
     967             : /*******************************************************************
     968             :  Add a rebind function for authenticated referrals
     969             : ******************************************************************/
     970             : #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
     971             : #else
     972             : # if LDAP_SET_REBIND_PROC_ARGS == 2
     973             : static int rebindproc (LDAP *ldap_struct, char **whop, char **credp,
     974             :                        int *method, int freeit )
     975             : {
     976             :         struct smbldap_state *ldap_state = smbldap_find_state(ldap_struct);
     977             : 
     978             :         return rebindproc_with_state(ldap_struct, whop, credp,
     979             :                                      method, freeit, ldap_state);
     980             : }
     981             : # endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/
     982             : #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
     983             : 
     984             : /*******************************************************************
     985             :  a rebind function for authenticated referrals
     986             :  this also does the connection, but no void*.
     987             : ******************************************************************/
     988             : #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
     989             : # if LDAP_SET_REBIND_PROC_ARGS == 2
     990             : static int rebindproc_connect (LDAP * ld, LDAP_CONST char *url, int request,
     991             :                                ber_int_t msgid)
     992             : {
     993             :         struct smbldap_state *ldap_state = smbldap_find_state(ld);
     994             : 
     995             :         return rebindproc_connect_with_state(ld, url, (ber_tag_t)request, msgid, 
     996             :                                              ldap_state);
     997             : }
     998             : # endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/
     999             : #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
    1000             : 
    1001             : /*******************************************************************
    1002             :  connect to the ldap server under system privilege.
    1003             : ******************************************************************/
    1004           0 : static int smbldap_connect_system(struct smbldap_state *ldap_state)
    1005             : {
    1006           0 :         LDAP *ldap_struct = smbldap_get_ldap(ldap_state);
    1007             :         int rc;
    1008             :         int version;
    1009             : 
    1010             :         /* removed the sasl_bind_s "EXTERNAL" stuff, as my testsuite 
    1011             :            (OpenLDAP) doesn't seem to support it */
    1012             : 
    1013           0 :         DEBUG(10,("ldap_connect_system: Binding to ldap server %s as \"%s\"\n",
    1014             :                   ldap_state->uri, ldap_state->bind_dn));
    1015             : 
    1016             : #ifdef HAVE_LDAP_SET_REBIND_PROC
    1017             : #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
    1018             : # if LDAP_SET_REBIND_PROC_ARGS == 2     
    1019             :         ldap_set_rebind_proc(ldap_struct, &rebindproc_connect);     
    1020             : # endif
    1021             : # if LDAP_SET_REBIND_PROC_ARGS == 3     
    1022           0 :         ldap_set_rebind_proc(ldap_struct, &rebindproc_connect_with_state, (void *)ldap_state);      
    1023             : # endif
    1024             : #else /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
    1025             : # if LDAP_SET_REBIND_PROC_ARGS == 2     
    1026             :         ldap_set_rebind_proc(ldap_struct, &rebindproc);     
    1027             : # endif
    1028             : # if LDAP_SET_REBIND_PROC_ARGS == 3     
    1029             :         ldap_set_rebind_proc(ldap_struct, &rebindproc_with_state, (void *)ldap_state);      
    1030             : # endif
    1031             : #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
    1032             : #endif
    1033             : 
    1034             :         /* When there is an alternative bind callback is set,
    1035             :            attempt to use it to perform the bind */
    1036           0 :         if (ldap_state->bind_callback != NULL) {
    1037             :                 /* We have to allow bind callback to be run under become_root/unbecome_root
    1038             :                    to make sure within smbd the callback has proper write access to its resources,
    1039             :                    like credential cache. This is similar to passdb case where this callback is supposed
    1040             :                    to be used. When used outside smbd, become_root()/unbecome_root() are no-op.
    1041             :                 */
    1042           0 :                 become_root();
    1043           0 :                 rc = ldap_state->bind_callback(ldap_struct, ldap_state, ldap_state->bind_callback_data);
    1044           0 :                 unbecome_root();
    1045             :         } else {
    1046           0 :                 rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret);
    1047             :         }
    1048             : 
    1049           0 :         if (rc != LDAP_SUCCESS) {
    1050           0 :                 char *ld_error = NULL;
    1051           0 :                 ldap_get_option(smbldap_get_ldap(ldap_state),
    1052             :                                 LDAP_OPT_ERROR_STRING,
    1053             :                                 &ld_error);
    1054           0 :                 DEBUG(ldap_state->num_failures ? 2 : 0,
    1055             :                       ("failed to bind to server %s with dn=\"%s\" Error: %s\n\t%s\n",
    1056             :                                ldap_state->uri,
    1057             :                                ldap_state->bind_dn ? ldap_state->bind_dn : "[Anonymous bind]",
    1058             :                                ldap_err2string(rc),
    1059             :                                ld_error ? ld_error : "(unknown)"));
    1060           0 :                 SAFE_FREE(ld_error);
    1061           0 :                 ldap_state->num_failures++;
    1062           0 :                 goto done;
    1063             :         }
    1064             : 
    1065           0 :         ldap_state->num_failures = 0;
    1066           0 :         ldap_state->paged_results = False;
    1067             : 
    1068           0 :         ldap_get_option(smbldap_get_ldap(ldap_state),
    1069             :                         LDAP_OPT_PROTOCOL_VERSION, &version);
    1070             : 
    1071           0 :         if (smbldap_has_control(smbldap_get_ldap(ldap_state), ADS_PAGE_CTL_OID)
    1072           0 :             && version == 3) {
    1073           0 :                 ldap_state->paged_results = True;
    1074             :         }
    1075             : 
    1076           0 :         DEBUG(3, ("ldap_connect_system: successful connection to the LDAP server\n"));
    1077           0 :         DEBUGADD(10, ("ldap_connect_system: LDAP server %s support paged results\n", 
    1078             :                 ldap_state->paged_results ? "does" : "does not"));
    1079           0 : done:
    1080           0 :         if (rc != 0) {
    1081           0 :                 ldap_unbind(ldap_struct);
    1082           0 :                 ldap_state->ldap_struct = NULL;
    1083             :         }
    1084           0 :         return rc;
    1085             : }
    1086             : 
    1087             : static void smbldap_idle_fn(struct tevent_context *tevent_ctx,
    1088             :                             struct tevent_timer *te,
    1089             :                             struct timeval now_abs,
    1090             :                             void *private_data);
    1091             : 
    1092             : /**********************************************************************
    1093             :  Connect to LDAP server (called before every ldap operation)
    1094             : *********************************************************************/
    1095           0 : static int smbldap_open(struct smbldap_state *ldap_state)
    1096             : {
    1097             :         int rc, opt_rc;
    1098           0 :         bool reopen = False;
    1099           0 :         SMB_ASSERT(ldap_state);
    1100             : 
    1101           0 :         if ((smbldap_get_ldap(ldap_state) != NULL) &&
    1102           0 :             ((ldap_state->last_ping + SMBLDAP_DONT_PING_TIME) <
    1103           0 :              time_mono(NULL))) {
    1104             : 
    1105             : #ifdef HAVE_UNIXSOCKET
    1106             :                 struct sockaddr_un addr;
    1107             : #else
    1108             :                 struct sockaddr_storage addr;
    1109             : #endif
    1110           0 :                 socklen_t len = sizeof(addr);
    1111             :                 int sd;
    1112             : 
    1113           0 :                 opt_rc = ldap_get_option(smbldap_get_ldap(ldap_state),
    1114             :                                          LDAP_OPT_DESC, &sd);
    1115           0 :                 if (opt_rc == 0 && (getpeername(sd, (struct sockaddr *) &addr, &len)) < 0 )
    1116           0 :                         reopen = True;
    1117             : 
    1118             : #ifdef HAVE_UNIXSOCKET
    1119           0 :                 if (opt_rc == 0 && addr.sun_family == AF_UNIX)
    1120           0 :                         reopen = True;
    1121             : #endif
    1122           0 :                 if (reopen) {
    1123             :                         /* the other end has died. reopen. */
    1124           0 :                         ldap_unbind(smbldap_get_ldap(ldap_state));
    1125           0 :                         ldap_state->ldap_struct = NULL;
    1126           0 :                         ldap_state->last_ping = (time_t)0;
    1127             :                 } else {
    1128           0 :                         ldap_state->last_ping = time_mono(NULL);
    1129             :                 } 
    1130             :         }
    1131             : 
    1132           0 :         if (smbldap_get_ldap(ldap_state) != NULL) {
    1133           0 :                 DEBUG(11,("smbldap_open: already connected to the LDAP server\n"));
    1134           0 :                 return LDAP_SUCCESS;
    1135             :         }
    1136             : 
    1137           0 :         if ((rc = smbldap_open_connection(ldap_state))) {
    1138           0 :                 return rc;
    1139             :         }
    1140             : 
    1141           0 :         if ((rc = smbldap_connect_system(ldap_state))) {
    1142           0 :                 return rc;
    1143             :         }
    1144             : 
    1145             : 
    1146           0 :         ldap_state->last_ping = time_mono(NULL);
    1147           0 :         ldap_state->pid = getpid();
    1148             : 
    1149           0 :         TALLOC_FREE(ldap_state->idle_event);
    1150             : 
    1151           0 :         if (ldap_state->tevent_context != NULL) {
    1152           0 :                 ldap_state->idle_event = tevent_add_timer(
    1153             :                         ldap_state->tevent_context, ldap_state,
    1154             :                         timeval_current_ofs(SMBLDAP_IDLE_TIME, 0),
    1155             :                         smbldap_idle_fn, ldap_state);
    1156             :         }
    1157             : 
    1158           0 :         DEBUG(4,("The LDAP server is successfully connected\n"));
    1159             : 
    1160           0 :         return LDAP_SUCCESS;
    1161             : }
    1162             : 
    1163             : /**********************************************************************
    1164             : Disconnect from LDAP server 
    1165             : *********************************************************************/
    1166           0 : static NTSTATUS smbldap_close(struct smbldap_state *ldap_state)
    1167             : {
    1168           0 :         if (!ldap_state)
    1169           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1170             : 
    1171           0 :         if (smbldap_get_ldap(ldap_state) != NULL) {
    1172           0 :                 ldap_unbind(smbldap_get_ldap(ldap_state));
    1173           0 :                 ldap_state->ldap_struct = NULL;
    1174             :         }
    1175             : 
    1176           0 :         smbldap_delete_state(ldap_state);
    1177             : 
    1178           0 :         TALLOC_FREE(ldap_state->idle_event);
    1179             : 
    1180           0 :         DEBUG(5,("The connection to the LDAP server was closed\n"));
    1181             :         /* maybe free the results here --metze */
    1182             : 
    1183           0 :         return NT_STATUS_OK;
    1184             : }
    1185             : 
    1186             : static SIG_ATOMIC_T got_alarm;
    1187             : 
    1188           0 : static void gotalarm_sig(int dummy)
    1189             : {
    1190           0 :         got_alarm = 1;
    1191           0 : }
    1192             : 
    1193           0 : static time_t calc_ldap_abs_endtime(int ldap_to)
    1194             : {
    1195           0 :         if (ldap_to == 0) {
    1196             :                 /* No timeout - don't
    1197             :                    return a value for
    1198             :                    the alarm. */
    1199           0 :                 return (time_t)0;
    1200             :         }
    1201             : 
    1202             :         /* Make the alarm time one second beyond
    1203             :            the timout we're setting for the
    1204             :            remote search timeout, to allow that
    1205             :            to fire in preference. */
    1206             : 
    1207           0 :         return time_mono(NULL)+ldap_to+1;
    1208             : }
    1209             : 
    1210           0 : static int end_ldap_local_alarm(time_t absolute_endtime, int rc)
    1211             : {
    1212           0 :         if (absolute_endtime) {
    1213           0 :                 alarm(0);
    1214           0 :                 CatchSignal(SIGALRM, SIG_IGN);
    1215           0 :                 if (got_alarm) {
    1216             :                         /* Client timeout error code. */
    1217           0 :                         got_alarm = 0;
    1218           0 :                         return LDAP_TIMEOUT;
    1219             :                 }
    1220             :         }
    1221           0 :         return rc;
    1222             : }
    1223             : 
    1224           0 : static void setup_ldap_local_alarm(struct smbldap_state *ldap_state, time_t absolute_endtime)
    1225             : {
    1226           0 :         time_t now = time_mono(NULL);
    1227             : 
    1228           0 :         if (absolute_endtime) {
    1229           0 :                 got_alarm = 0;
    1230           0 :                 CatchSignal(SIGALRM, gotalarm_sig);
    1231           0 :                 alarm(absolute_endtime - now);
    1232             :         }
    1233             : 
    1234           0 :         if (ldap_state->pid != getpid()) {
    1235           0 :                 smbldap_close(ldap_state);
    1236             :         }
    1237           0 : }
    1238             : 
    1239           0 : static void get_ldap_errs(struct smbldap_state *ldap_state, char **pp_ld_error, int *p_ld_errno)
    1240             : {
    1241           0 :         ldap_get_option(smbldap_get_ldap(ldap_state),
    1242             :                         LDAP_OPT_ERROR_NUMBER, p_ld_errno);
    1243             : 
    1244           0 :         ldap_get_option(smbldap_get_ldap(ldap_state),
    1245             :                         LDAP_OPT_ERROR_STRING, pp_ld_error);
    1246           0 : }
    1247             : 
    1248           0 : static int get_cached_ldap_connect(struct smbldap_state *ldap_state, time_t abs_endtime)
    1249             : {
    1250           0 :         int attempts = 0;
    1251             : 
    1252           0 :         while (1) {
    1253             :                 int rc;
    1254             :                 time_t now;
    1255             : 
    1256           0 :                 now = time_mono(NULL);
    1257           0 :                 ldap_state->last_use = now;
    1258             : 
    1259           0 :                 if (abs_endtime && now > abs_endtime) {
    1260           0 :                         smbldap_close(ldap_state);
    1261           0 :                         return LDAP_TIMEOUT;
    1262             :                 }
    1263             : 
    1264           0 :                 rc = smbldap_open(ldap_state);
    1265             : 
    1266           0 :                 if (rc == LDAP_SUCCESS) {
    1267           0 :                         return LDAP_SUCCESS;
    1268             :                 }
    1269             : 
    1270           0 :                 attempts++;
    1271           0 :                 DEBUG(1, ("Connection to LDAP server failed for the "
    1272             :                         "%d try!\n", attempts));
    1273             : 
    1274           0 :                 if (rc == LDAP_INSUFFICIENT_ACCESS) {
    1275             :                         /* The fact that we are non-root or any other
    1276             :                          * access-denied condition will not change in the next
    1277             :                          * round of trying */
    1278           0 :                         return rc;
    1279             :                 }
    1280             : 
    1281           0 :                 if (got_alarm) {
    1282           0 :                         smbldap_close(ldap_state);
    1283           0 :                         return LDAP_TIMEOUT;
    1284             :                 }
    1285             : 
    1286           0 :                 smb_msleep(1000);
    1287             : 
    1288           0 :                 if (got_alarm) {
    1289           0 :                         smbldap_close(ldap_state);
    1290           0 :                         return LDAP_TIMEOUT;
    1291             :                 }
    1292             :         }
    1293             : }
    1294             : 
    1295             : /*********************************************************************
    1296             :  ********************************************************************/
    1297             : 
    1298           0 : static int smbldap_search_ext(struct smbldap_state *ldap_state,
    1299             :                               const char *base, int scope, const char *filter, 
    1300             :                               const char *attrs[], int attrsonly,
    1301             :                               LDAPControl **sctrls, LDAPControl **cctrls, 
    1302             :                               int sizelimit, LDAPMessage **res)
    1303             : {
    1304           0 :         int             rc = LDAP_SERVER_DOWN;
    1305             :         char           *utf8_filter;
    1306           0 :         int             to = lp_ldap_timeout();
    1307           0 :         time_t          abs_endtime = calc_ldap_abs_endtime(to);
    1308             :         struct          timeval timeout;
    1309           0 :         struct          timeval *timeout_ptr = NULL;
    1310             :         size_t          converted_size;
    1311             : 
    1312           0 :         SMB_ASSERT(ldap_state);
    1313             : 
    1314           0 :         DEBUG(5,("smbldap_search_ext: base => [%s], filter => [%s], "
    1315             :                  "scope => [%d]\n", base, filter, scope));
    1316             : 
    1317           0 :         if (ldap_state->last_rebind.tv_sec > 0) {
    1318             :                 struct timeval  tval;
    1319             :                 struct timespec ts;
    1320           0 :                 int64_t tdiff = 0;
    1321           0 :                 int             sleep_time = 0;
    1322             : 
    1323           0 :                 clock_gettime_mono(&ts);
    1324           0 :                 tval = convert_timespec_to_timeval(ts);
    1325             : 
    1326           0 :                 tdiff = usec_time_diff(&tval, &ldap_state->last_rebind);
    1327           0 :                 tdiff /= 1000; /* Convert to milliseconds. */
    1328             : 
    1329           0 :                 sleep_time = lp_ldap_replication_sleep()-(int)tdiff;
    1330           0 :                 sleep_time = MIN(sleep_time, MAX_LDAP_REPLICATION_SLEEP_TIME);
    1331             : 
    1332           0 :                 if (sleep_time > 0) {
    1333             :                         /* we wait for the LDAP replication */
    1334           0 :                         DEBUG(5,("smbldap_search_ext: waiting %d milliseconds "
    1335             :                                  "for LDAP replication.\n",sleep_time));
    1336           0 :                         smb_msleep(sleep_time);
    1337           0 :                         DEBUG(5,("smbldap_search_ext: go on!\n"));
    1338             :                 }
    1339           0 :                 ZERO_STRUCT(ldap_state->last_rebind);
    1340             :         }
    1341             : 
    1342           0 :         if (!push_utf8_talloc(talloc_tos(), &utf8_filter, filter, &converted_size)) {
    1343           0 :                 return LDAP_NO_MEMORY;
    1344             :         }
    1345             : 
    1346             :         /* Setup remote timeout for the ldap_search_ext_s call. */
    1347           0 :         if (to) {
    1348           0 :                 timeout.tv_sec = to;
    1349           0 :                 timeout.tv_usec = 0;
    1350           0 :                 timeout_ptr = &timeout;
    1351             :         }
    1352             : 
    1353           0 :         setup_ldap_local_alarm(ldap_state, abs_endtime);
    1354             : 
    1355           0 :         while (1) {
    1356           0 :                 char *ld_error = NULL;
    1357             :                 int ld_errno;
    1358             : 
    1359           0 :                 rc = get_cached_ldap_connect(ldap_state, abs_endtime);
    1360           0 :                 if (rc != LDAP_SUCCESS) {
    1361           0 :                         break;
    1362             :                 }
    1363             : 
    1364           0 :                 rc = ldap_search_ext_s(smbldap_get_ldap(ldap_state),
    1365             :                                        base, scope,
    1366             :                                        utf8_filter,
    1367             :                                        discard_const_p(char *, attrs),
    1368             :                                        attrsonly, sctrls, cctrls, timeout_ptr,
    1369             :                                        sizelimit, res);
    1370           0 :                 if (rc == LDAP_SUCCESS) {
    1371           0 :                         break;
    1372             :                 }
    1373             : 
    1374           0 :                 get_ldap_errs(ldap_state, &ld_error, &ld_errno);
    1375             : 
    1376           0 :                 DEBUG(10, ("Failed search for base: %s, error: %d (%s) "
    1377             :                            "(%s)\n", base, ld_errno,
    1378             :                            ldap_err2string(rc),
    1379             :                            ld_error ? ld_error : "unknown"));
    1380           0 :                 SAFE_FREE(ld_error);
    1381             : 
    1382           0 :                 if (ld_errno != LDAP_SERVER_DOWN) {
    1383           0 :                         break;
    1384             :                 }
    1385           0 :                 ldap_unbind(smbldap_get_ldap(ldap_state));
    1386           0 :                 ldap_state->ldap_struct = NULL;
    1387             :         }
    1388             : 
    1389           0 :         TALLOC_FREE(utf8_filter);
    1390           0 :         return end_ldap_local_alarm(abs_endtime, rc);
    1391             : }
    1392             : 
    1393           0 : int smbldap_search(struct smbldap_state *ldap_state, 
    1394             :                    const char *base, int scope, const char *filter, 
    1395             :                    const char *attrs[], int attrsonly, 
    1396             :                    LDAPMessage **res)
    1397             : {
    1398           0 :         return smbldap_search_ext(ldap_state, base, scope, filter, attrs,
    1399             :                                   attrsonly, NULL, NULL, LDAP_NO_LIMIT, res);
    1400             : }
    1401             : 
    1402           0 : int smbldap_search_paged(struct smbldap_state *ldap_state, 
    1403             :                          const char *base, int scope, const char *filter, 
    1404             :                          const char **attrs, int attrsonly, int pagesize,
    1405             :                          LDAPMessage **res, void **cookie)
    1406             : {
    1407             :         LDAPControl     pr;
    1408             :         LDAPControl     **rcontrols;
    1409           0 :         LDAPControl     *controls[2] = { NULL, NULL};
    1410           0 :         BerElement      *cookie_be = NULL;
    1411           0 :         struct berval   *cookie_bv = NULL;
    1412           0 :         int             tmp = 0, i, rc;
    1413           0 :         bool            critical = True;
    1414             : 
    1415           0 :         *res = NULL;
    1416             : 
    1417           0 :         DEBUG(3,("smbldap_search_paged: base => [%s], filter => [%s],"
    1418             :                  "scope => [%d], pagesize => [%d]\n",
    1419             :                  base, filter, scope, pagesize));
    1420             : 
    1421           0 :         cookie_be = ber_alloc_t(LBER_USE_DER);
    1422           0 :         if (cookie_be == NULL) {
    1423           0 :                 DEBUG(0,("smbldap_create_page_control: ber_alloc_t returns "
    1424             :                          "NULL\n"));
    1425           0 :                 return LDAP_NO_MEMORY;
    1426             :         }
    1427             : 
    1428             :         /* construct cookie */
    1429           0 :         if (*cookie != NULL) {
    1430           0 :                 ber_printf(cookie_be, "{iO}", (ber_int_t) pagesize, *cookie);
    1431           0 :                 ber_bvfree((struct berval *)*cookie); /* don't need it from last time */
    1432           0 :                 *cookie = NULL;
    1433             :         } else {
    1434           0 :                 ber_printf(cookie_be, "{io}", (ber_int_t) pagesize, "", 0);
    1435             :         }
    1436           0 :         ber_flatten(cookie_be, &cookie_bv);
    1437             : 
    1438           0 :         pr.ldctl_oid = discard_const_p(char, ADS_PAGE_CTL_OID);
    1439           0 :         pr.ldctl_iscritical = (char) critical;
    1440           0 :         pr.ldctl_value.bv_len = cookie_bv->bv_len;
    1441           0 :         pr.ldctl_value.bv_val = cookie_bv->bv_val;
    1442             : 
    1443           0 :         controls[0] = &pr;
    1444           0 :         controls[1] = NULL;
    1445             : 
    1446           0 :         rc = smbldap_search_ext(ldap_state, base, scope, filter, attrs, 
    1447             :                                  0, controls, NULL, LDAP_NO_LIMIT, res);
    1448             : 
    1449           0 :         ber_free(cookie_be, 1);
    1450           0 :         ber_bvfree(cookie_bv);
    1451             : 
    1452           0 :         if (rc != 0) {
    1453           0 :                 DEBUG(3,("smbldap_search_paged: smbldap_search_ext(%s) "
    1454             :                          "failed with [%s]\n", filter, ldap_err2string(rc)));
    1455           0 :                 goto done;
    1456             :         }
    1457             : 
    1458           0 :         DEBUG(3,("smbldap_search_paged: search was successful\n"));
    1459             : 
    1460           0 :         rc = ldap_parse_result(smbldap_get_ldap(ldap_state), *res, NULL, NULL,
    1461             :                                NULL, NULL, &rcontrols,  0);
    1462           0 :         if (rc != 0) {
    1463           0 :                 DEBUG(3,("smbldap_search_paged: ldap_parse_result failed " \
    1464             :                          "with [%s]\n", ldap_err2string(rc)));
    1465           0 :                 goto done;
    1466             :         }
    1467             : 
    1468           0 :         if (rcontrols == NULL)
    1469           0 :                 goto done;
    1470             : 
    1471           0 :         for (i=0; rcontrols[i]; i++) {
    1472             : 
    1473           0 :                 if (strcmp(ADS_PAGE_CTL_OID, rcontrols[i]->ldctl_oid) != 0)
    1474           0 :                         continue;
    1475             : 
    1476           0 :                 cookie_be = ber_init(&rcontrols[i]->ldctl_value);
    1477           0 :                 ber_scanf(cookie_be,"{iO}", &tmp, &cookie_bv);
    1478             :                 /* the berval is the cookie, but must be freed when it is all
    1479             :                    done */
    1480           0 :                 if (cookie_bv->bv_len)
    1481           0 :                         *cookie=ber_bvdup(cookie_bv);
    1482             :                 else
    1483           0 :                         *cookie=NULL;
    1484           0 :                 ber_bvfree(cookie_bv);
    1485           0 :                 ber_free(cookie_be, 1);
    1486           0 :                 break;
    1487             :         }
    1488           0 :         ldap_controls_free(rcontrols);
    1489           0 : done:   
    1490           0 :         return rc;
    1491             : }
    1492             : 
    1493           0 : int smbldap_modify(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs[])
    1494             : {
    1495           0 :         int             rc = LDAP_SERVER_DOWN;
    1496             :         char           *utf8_dn;
    1497           0 :         time_t          abs_endtime = calc_ldap_abs_endtime(lp_ldap_timeout());
    1498             :         size_t          converted_size;
    1499             : 
    1500           0 :         SMB_ASSERT(ldap_state);
    1501             : 
    1502           0 :         DEBUG(5,("smbldap_modify: dn => [%s]\n", dn ));
    1503             : 
    1504           0 :         if (!push_utf8_talloc(talloc_tos(), &utf8_dn, dn, &converted_size)) {
    1505           0 :                 return LDAP_NO_MEMORY;
    1506             :         }
    1507             : 
    1508           0 :         setup_ldap_local_alarm(ldap_state, abs_endtime);
    1509             : 
    1510           0 :         while (1) {
    1511           0 :                 char *ld_error = NULL;
    1512             :                 int ld_errno;
    1513             : 
    1514           0 :                 rc = get_cached_ldap_connect(ldap_state, abs_endtime);
    1515           0 :                 if (rc != LDAP_SUCCESS) {
    1516           0 :                         break;
    1517             :                 }
    1518             : 
    1519           0 :                 rc = ldap_modify_s(smbldap_get_ldap(ldap_state), utf8_dn,
    1520             :                                    attrs);
    1521           0 :                 if (rc == LDAP_SUCCESS) {
    1522           0 :                         break;
    1523             :                 }
    1524             : 
    1525           0 :                 get_ldap_errs(ldap_state, &ld_error, &ld_errno);
    1526             : 
    1527           0 :                 DEBUG(10, ("Failed to modify dn: %s, error: %d (%s) "
    1528             :                            "(%s)\n", dn, ld_errno,
    1529             :                            ldap_err2string(rc),
    1530             :                            ld_error ? ld_error : "unknown"));
    1531           0 :                 SAFE_FREE(ld_error);
    1532             : 
    1533           0 :                 if (ld_errno != LDAP_SERVER_DOWN) {
    1534           0 :                         break;
    1535             :                 }
    1536           0 :                 ldap_unbind(smbldap_get_ldap(ldap_state));
    1537           0 :                 ldap_state->ldap_struct = NULL;
    1538             :         }
    1539             : 
    1540           0 :         TALLOC_FREE(utf8_dn);
    1541           0 :         return end_ldap_local_alarm(abs_endtime, rc);
    1542             : }
    1543             : 
    1544           0 : int smbldap_add(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs[])
    1545             : {
    1546           0 :         int             rc = LDAP_SERVER_DOWN;
    1547             :         char           *utf8_dn;
    1548           0 :         time_t          abs_endtime = calc_ldap_abs_endtime(lp_ldap_timeout());
    1549             :         size_t          converted_size;
    1550             : 
    1551           0 :         SMB_ASSERT(ldap_state);
    1552             : 
    1553           0 :         DEBUG(5,("smbldap_add: dn => [%s]\n", dn ));
    1554             : 
    1555           0 :         if (!push_utf8_talloc(talloc_tos(), &utf8_dn, dn, &converted_size)) {
    1556           0 :                 return LDAP_NO_MEMORY;
    1557             :         }
    1558             : 
    1559           0 :         setup_ldap_local_alarm(ldap_state, abs_endtime);
    1560             : 
    1561           0 :         while (1) {
    1562           0 :                 char *ld_error = NULL;
    1563             :                 int ld_errno;
    1564             : 
    1565           0 :                 rc = get_cached_ldap_connect(ldap_state, abs_endtime);
    1566           0 :                 if (rc != LDAP_SUCCESS) {
    1567           0 :                         break;
    1568             :                 }
    1569             : 
    1570           0 :                 rc = ldap_add_s(smbldap_get_ldap(ldap_state), utf8_dn, attrs);
    1571           0 :                 if (rc == LDAP_SUCCESS) {
    1572           0 :                         break;
    1573             :                 }
    1574             : 
    1575           0 :                 get_ldap_errs(ldap_state, &ld_error, &ld_errno);
    1576             : 
    1577           0 :                 DEBUG(10, ("Failed to add dn: %s, error: %d (%s) "
    1578             :                            "(%s)\n", dn, ld_errno,
    1579             :                            ldap_err2string(rc),
    1580             :                            ld_error ? ld_error : "unknown"));
    1581           0 :                 SAFE_FREE(ld_error);
    1582             : 
    1583           0 :                 if (ld_errno != LDAP_SERVER_DOWN) {
    1584           0 :                         break;
    1585             :                 }
    1586           0 :                 ldap_unbind(smbldap_get_ldap(ldap_state));
    1587           0 :                 ldap_state->ldap_struct = NULL;
    1588             :         }
    1589             : 
    1590           0 :         TALLOC_FREE(utf8_dn);
    1591           0 :         return end_ldap_local_alarm(abs_endtime, rc);
    1592             : }
    1593             : 
    1594           0 : int smbldap_delete(struct smbldap_state *ldap_state, const char *dn)
    1595             : {
    1596           0 :         int             rc = LDAP_SERVER_DOWN;
    1597             :         char           *utf8_dn;
    1598           0 :         time_t          abs_endtime = calc_ldap_abs_endtime(lp_ldap_timeout());
    1599             :         size_t          converted_size;
    1600             : 
    1601           0 :         SMB_ASSERT(ldap_state);
    1602             : 
    1603           0 :         DEBUG(5,("smbldap_delete: dn => [%s]\n", dn ));
    1604             : 
    1605           0 :         if (!push_utf8_talloc(talloc_tos(), &utf8_dn, dn, &converted_size)) {
    1606           0 :                 return LDAP_NO_MEMORY;
    1607             :         }
    1608             : 
    1609           0 :         setup_ldap_local_alarm(ldap_state, abs_endtime);
    1610             : 
    1611           0 :         while (1) {
    1612           0 :                 char *ld_error = NULL;
    1613             :                 int ld_errno;
    1614             : 
    1615           0 :                 rc = get_cached_ldap_connect(ldap_state, abs_endtime);
    1616           0 :                 if (rc != LDAP_SUCCESS) {
    1617           0 :                         break;
    1618             :                 }
    1619             : 
    1620           0 :                 rc = ldap_delete_s(smbldap_get_ldap(ldap_state), utf8_dn);
    1621           0 :                 if (rc == LDAP_SUCCESS) {
    1622           0 :                         break;
    1623             :                 }
    1624             : 
    1625           0 :                 get_ldap_errs(ldap_state, &ld_error, &ld_errno);
    1626             : 
    1627           0 :                 DEBUG(10, ("Failed to delete dn: %s, error: %d (%s) "
    1628             :                            "(%s)\n", dn, ld_errno,
    1629             :                            ldap_err2string(rc),
    1630             :                            ld_error ? ld_error : "unknown"));
    1631           0 :                 SAFE_FREE(ld_error);
    1632             : 
    1633           0 :                 if (ld_errno != LDAP_SERVER_DOWN) {
    1634           0 :                         break;
    1635             :                 }
    1636           0 :                 ldap_unbind(smbldap_get_ldap(ldap_state));
    1637           0 :                 ldap_state->ldap_struct = NULL;
    1638             :         }
    1639             : 
    1640           0 :         TALLOC_FREE(utf8_dn);
    1641           0 :         return end_ldap_local_alarm(abs_endtime, rc);
    1642             : }
    1643             : 
    1644           0 : int smbldap_extended_operation(struct smbldap_state *ldap_state, 
    1645             :                                LDAP_CONST char *reqoid, struct berval *reqdata, 
    1646             :                                LDAPControl **serverctrls, LDAPControl **clientctrls, 
    1647             :                                char **retoidp, struct berval **retdatap)
    1648             : {
    1649           0 :         int             rc = LDAP_SERVER_DOWN;
    1650           0 :         time_t          abs_endtime = calc_ldap_abs_endtime(lp_ldap_timeout());
    1651             : 
    1652           0 :         if (!ldap_state)
    1653           0 :                 return (-1);
    1654             : 
    1655           0 :         setup_ldap_local_alarm(ldap_state, abs_endtime);
    1656             : 
    1657           0 :         while (1) {
    1658           0 :                 char *ld_error = NULL;
    1659             :                 int ld_errno;
    1660             : 
    1661           0 :                 rc = get_cached_ldap_connect(ldap_state, abs_endtime);
    1662           0 :                 if (rc != LDAP_SUCCESS) {
    1663           0 :                         break;
    1664             :                 }
    1665             : 
    1666           0 :                 rc = ldap_extended_operation_s(smbldap_get_ldap(ldap_state),
    1667             :                                                reqoid,
    1668             :                                                reqdata, serverctrls,
    1669             :                                                clientctrls, retoidp, retdatap);
    1670           0 :                 if (rc == LDAP_SUCCESS) {
    1671           0 :                         break;
    1672             :                 }
    1673             : 
    1674           0 :                 get_ldap_errs(ldap_state, &ld_error, &ld_errno);
    1675             : 
    1676           0 :                 DEBUG(10, ("Extended operation failed with error: "
    1677             :                            "%d (%s) (%s)\n", ld_errno,
    1678             :                            ldap_err2string(rc),
    1679             :                            ld_error ? ld_error : "unknown"));
    1680           0 :                 SAFE_FREE(ld_error);
    1681             : 
    1682           0 :                 if (ld_errno != LDAP_SERVER_DOWN) {
    1683           0 :                         break;
    1684             :                 }
    1685           0 :                 ldap_unbind(smbldap_get_ldap(ldap_state));
    1686           0 :                 ldap_state->ldap_struct = NULL;
    1687             :         }
    1688             : 
    1689           0 :         return end_ldap_local_alarm(abs_endtime, rc);
    1690             : }
    1691             : 
    1692             : /*******************************************************************
    1693             :  run the search by name.
    1694             : ******************************************************************/
    1695           0 : int smbldap_search_suffix (struct smbldap_state *ldap_state,
    1696             :                            const char *filter, const char **search_attr,
    1697             :                            LDAPMessage ** result)
    1698             : {
    1699           0 :         return smbldap_search(ldap_state, lp_ldap_suffix(),
    1700             :                               LDAP_SCOPE_SUBTREE,
    1701             :                               filter, search_attr, 0, result);
    1702             : }
    1703             : 
    1704           0 : static void smbldap_idle_fn(struct tevent_context *tevent_ctx,
    1705             :                             struct tevent_timer *te,
    1706             :                             struct timeval now_abs,
    1707             :                             void *private_data)
    1708             : {
    1709           0 :         struct smbldap_state *state = (struct smbldap_state *)private_data;
    1710             : 
    1711           0 :         TALLOC_FREE(state->idle_event);
    1712             : 
    1713           0 :         if (smbldap_get_ldap(state) == NULL) {
    1714           0 :                 DEBUG(10,("ldap connection not connected...\n"));
    1715           0 :                 return;
    1716             :         }
    1717             : 
    1718           0 :         if ((state->last_use+SMBLDAP_IDLE_TIME) > time_mono(NULL)) {
    1719           0 :                 DEBUG(10,("ldap connection not idle...\n"));
    1720             : 
    1721             :                 /* this needs to be made monotonic clock aware inside tevent: */
    1722           0 :                 state->idle_event = tevent_add_timer(
    1723             :                         tevent_ctx, state,
    1724             :                         timeval_add(&now_abs, SMBLDAP_IDLE_TIME, 0),
    1725             :                         smbldap_idle_fn,
    1726             :                         private_data);
    1727           0 :                 return;
    1728             :         }
    1729             : 
    1730           0 :         DEBUG(7,("ldap connection idle...closing connection\n"));
    1731           0 :         smbldap_close(state);
    1732             : }
    1733             : 
    1734             : /**********************************************************************
    1735             :  Housekeeping
    1736             :  *********************************************************************/
    1737             : 
    1738           0 : void smbldap_free_struct(struct smbldap_state **ldap_state) 
    1739             : {
    1740           0 :         smbldap_close(*ldap_state);
    1741             : 
    1742           0 :         if ((*ldap_state)->bind_secret) {
    1743           0 :                 memset((*ldap_state)->bind_secret, '\0', strlen((*ldap_state)->bind_secret));
    1744             :         }
    1745             : 
    1746           0 :         SAFE_FREE((*ldap_state)->bind_dn);
    1747           0 :         SAFE_FREE((*ldap_state)->bind_secret);
    1748           0 :         smbldap_set_bind_callback(*ldap_state, NULL, NULL);
    1749             : 
    1750           0 :         TALLOC_FREE(*ldap_state);
    1751             : 
    1752             :         /* No need to free any further, as it is talloc()ed */
    1753           0 : }
    1754             : 
    1755           0 : static int smbldap_state_destructor(struct smbldap_state *state)
    1756             : {
    1757           0 :         smbldap_free_struct(&state);
    1758           0 :         return 0;
    1759             : }
    1760             : 
    1761             : 
    1762             : /**********************************************************************
    1763             :  Intitalise the 'general' ldap structures, on which ldap operations may be conducted
    1764             :  *********************************************************************/
    1765             : 
    1766           0 : NTSTATUS smbldap_init(TALLOC_CTX *mem_ctx, struct tevent_context *tevent_ctx,
    1767             :                       const char *location,
    1768             :                       bool anon,
    1769             :                       const char *bind_dn,
    1770             :                       const char *bind_secret,
    1771             :                       struct smbldap_state **smbldap_state)
    1772             : {
    1773           0 :         *smbldap_state = talloc_zero(mem_ctx, struct smbldap_state);
    1774           0 :         if (!*smbldap_state) {
    1775           0 :                 DEBUG(0, ("talloc() failed for ldapsam private_data!\n"));
    1776           0 :                 return NT_STATUS_NO_MEMORY;
    1777             :         }
    1778             : 
    1779           0 :         if (location) {
    1780           0 :                 (*smbldap_state)->uri = talloc_strdup(mem_ctx, location);
    1781             :         } else {
    1782           0 :                 (*smbldap_state)->uri = "ldap://localhost";
    1783             :         }
    1784             : 
    1785           0 :         (*smbldap_state)->tevent_context = tevent_ctx;
    1786             : 
    1787           0 :         if (bind_dn && bind_secret) {
    1788           0 :                 smbldap_set_creds(*smbldap_state, anon, bind_dn, bind_secret);
    1789             :         }
    1790             : 
    1791           0 :         talloc_set_destructor(*smbldap_state, smbldap_state_destructor);
    1792           0 :         return NT_STATUS_OK;
    1793             : }
    1794             : 
    1795           0 :  char *smbldap_talloc_dn(TALLOC_CTX *mem_ctx, LDAP *ld,
    1796             :                          LDAPMessage *entry)
    1797             : {
    1798             :         char *utf8_dn, *unix_dn;
    1799             :         size_t converted_size;
    1800             : 
    1801           0 :         utf8_dn = ldap_get_dn(ld, entry);
    1802           0 :         if (!utf8_dn) {
    1803           0 :                 DEBUG (5, ("smbldap_talloc_dn: ldap_get_dn failed\n"));
    1804           0 :                 return NULL;
    1805             :         }
    1806           0 :         if (!pull_utf8_talloc(mem_ctx, &unix_dn, utf8_dn, &converted_size)) {
    1807           0 :                 DEBUG (0, ("smbldap_talloc_dn: String conversion failure utf8 "
    1808             :                            "[%s]\n", utf8_dn));
    1809           0 :                 return NULL;
    1810             :         }
    1811           0 :         ldap_memfree(utf8_dn);
    1812           0 :         return unix_dn;
    1813             : }
    1814             : 
    1815             : /*******************************************************************
    1816             :  Check if root-dse has a certain Control or Extension
    1817             : ********************************************************************/
    1818             : 
    1819           0 : static bool smbldap_check_root_dse(LDAP *ld, const char **attrs, const char *value) 
    1820             : {
    1821           0 :         LDAPMessage *msg = NULL;
    1822           0 :         LDAPMessage *entry = NULL;
    1823           0 :         char **values = NULL;
    1824             :         int rc, num_result, num_values, i;
    1825           0 :         bool result = False;
    1826             : 
    1827           0 :         if (!attrs[0]) {
    1828           0 :                 DEBUG(3,("smbldap_check_root_dse: nothing to look for\n"));
    1829           0 :                 return False;
    1830             :         }
    1831             : 
    1832           0 :         if (!strequal(attrs[0], "supportedExtension") && 
    1833           0 :             !strequal(attrs[0], "supportedControl") && 
    1834           0 :             !strequal(attrs[0], "namingContexts")) {
    1835           0 :                 DEBUG(3,("smbldap_check_root_dse: no idea what to query root-dse for: %s ?\n", attrs[0]));
    1836           0 :                 return False;
    1837             :         }
    1838             : 
    1839           0 :         rc = ldap_search_s(ld, "", LDAP_SCOPE_BASE, 
    1840             :                            "(objectclass=*)", discard_const_p(char *, attrs), 0 , &msg);
    1841             : 
    1842           0 :         if (rc != LDAP_SUCCESS) {
    1843           0 :                 DEBUG(3,("smbldap_check_root_dse: Could not search rootDSE\n"));
    1844           0 :                 return False;
    1845             :         }
    1846             : 
    1847           0 :         num_result = ldap_count_entries(ld, msg);
    1848             : 
    1849           0 :         if (num_result != 1) {
    1850           0 :                 DEBUG(3,("smbldap_check_root_dse: Expected one rootDSE, got %d\n", num_result));
    1851           0 :                 goto done;
    1852             :         }
    1853             : 
    1854           0 :         entry = ldap_first_entry(ld, msg);
    1855             : 
    1856           0 :         if (entry == NULL) {
    1857           0 :                 DEBUG(3,("smbldap_check_root_dse: Could not retrieve rootDSE\n"));
    1858           0 :                 goto done;
    1859             :         }
    1860             : 
    1861           0 :         values = ldap_get_values(ld, entry, attrs[0]);
    1862             : 
    1863           0 :         if (values == NULL) {
    1864           0 :                 DEBUG(5,("smbldap_check_root_dse: LDAP Server does not support any %s\n", attrs[0]));
    1865           0 :                 goto done;
    1866             :         }
    1867             : 
    1868           0 :         num_values = ldap_count_values(values);
    1869             : 
    1870           0 :         if (num_values == 0) {
    1871           0 :                 DEBUG(5,("smbldap_check_root_dse: LDAP Server does not have any %s\n", attrs[0]));
    1872           0 :                 goto done;
    1873             :         }
    1874             : 
    1875           0 :         for (i=0; i<num_values; i++) {
    1876           0 :                 if (strcmp(values[i], value) == 0)
    1877           0 :                         result = True;
    1878             :         }
    1879             : 
    1880             : 
    1881           0 :  done:
    1882           0 :         if (values != NULL)
    1883           0 :                 ldap_value_free(values);
    1884           0 :         if (msg != NULL)
    1885           0 :                 ldap_msgfree(msg);
    1886             : 
    1887           0 :         return result;
    1888             : 
    1889             : }
    1890             : 
    1891             : /*******************************************************************
    1892             :  Check if LDAP-Server supports a certain Control (OID in string format)
    1893             : ********************************************************************/
    1894             : 
    1895           0 : bool smbldap_has_control(LDAP *ld, const char *control)
    1896             : {
    1897           0 :         const char *attrs[] = { "supportedControl", NULL };
    1898           0 :         return smbldap_check_root_dse(ld, attrs, control);
    1899             : }
    1900             : 
    1901             : /*******************************************************************
    1902             :  Check if LDAP-Server supports a certain Extension (OID in string format)
    1903             : ********************************************************************/
    1904             : 
    1905           0 : bool smbldap_has_extension(LDAP *ld, const char *extension)
    1906             : {
    1907           0 :         const char *attrs[] = { "supportedExtension", NULL };
    1908           0 :         return smbldap_check_root_dse(ld, attrs, extension);
    1909             : }
    1910             : 
    1911             : /*******************************************************************
    1912             :  Check if LDAP-Server holds a given namingContext
    1913             : ********************************************************************/
    1914             : 
    1915           0 : bool smbldap_has_naming_context(LDAP *ld, const char *naming_context)
    1916             : {
    1917           0 :         const char *attrs[] = { "namingContexts", NULL };
    1918           0 :         return smbldap_check_root_dse(ld, attrs, naming_context);
    1919             : }
    1920             : 
    1921           0 : bool smbldap_set_creds(struct smbldap_state *ldap_state, bool anon, const char *dn, const char *secret)
    1922             : {
    1923           0 :         ldap_state->anonymous = anon;
    1924             : 
    1925             :         /* free any previously set credential */
    1926             : 
    1927           0 :         SAFE_FREE(ldap_state->bind_dn);
    1928           0 :         smbldap_set_bind_callback(ldap_state, NULL, NULL);
    1929             : 
    1930           0 :         if (ldap_state->bind_secret) {
    1931             :                 /* make sure secrets are zeroed out of memory */
    1932           0 :                 memset(ldap_state->bind_secret, '\0', strlen(ldap_state->bind_secret));
    1933           0 :                 SAFE_FREE(ldap_state->bind_secret);
    1934             :         }
    1935             : 
    1936           0 :         if ( ! anon) {
    1937           0 :                 ldap_state->bind_dn = SMB_STRDUP(dn);
    1938           0 :                 ldap_state->bind_secret = SMB_STRDUP(secret);
    1939             :         }
    1940             : 
    1941           0 :         return True;
    1942             : }

Generated by: LCOV version 1.13