r5349: After talking with Jerry, reverted the addition of account policies to
[bbaumbach/samba-autobuild/.git] / source3 / lib / smbldap.c
index e66fb3640cfc6601290b981dc10feefeb8aa95fc..7aeecb89d6fd7479b2e5015237f342e3edfaf269 100644 (file)
@@ -1,5 +1,5 @@
 /* 
-   Unix SMB/CIFS mplementation.
+   Unix SMB/CIFS implementation.
    LDAP protocol helper functions for SAMBA
    Copyright (C) Jean François Micouleau       1998
    Copyright (C) Gerald Carter                 2001-2003
@@ -54,7 +54,7 @@ ATTRIB_MAP_ENTRY attrib_map_v22[] = {
        { LDAP_ATTR_CN,                 "cn"            },
        { LDAP_ATTR_DISPLAY_NAME,       "displayName"   },
        { LDAP_ATTR_HOME_PATH,          "smbHome"       },
-       { LDAP_ATTR_HOME_DRIVE,         "homeDrives"    },
+       { LDAP_ATTR_HOME_DRIVE,         "homeDrive    },
        { LDAP_ATTR_LOGON_SCRIPT,       "scriptPath"    },
        { LDAP_ATTR_PROFILE_PATH,       "profilePath"   },
        { LDAP_ATTR_DESC,               "description"   },
@@ -66,6 +66,29 @@ ATTRIB_MAP_ENTRY attrib_map_v22[] = {
        { LDAP_ATTR_DOMAIN,             "domain"        },
        { LDAP_ATTR_OBJCLASS,           "objectClass"   },
        { LDAP_ATTR_ACB_INFO,           "acctFlags"     },
+       { LDAP_ATTR_MOD_TIMESTAMP,      "modifyTimestamp"       },
+       { LDAP_ATTR_LIST_END,           NULL            }
+};
+
+ATTRIB_MAP_ENTRY attrib_map_to_delete_v22[] = {
+       { LDAP_ATTR_PWD_LAST_SET,       "pwdLastSet"    },
+       { LDAP_ATTR_PWD_CAN_CHANGE,     "pwdCanChange"  },
+       { LDAP_ATTR_PWD_MUST_CHANGE,    "pwdMustChange" },
+       { LDAP_ATTR_LOGON_TIME,         "logonTime"     },
+       { LDAP_ATTR_LOGOFF_TIME,        "logoffTime"    },
+       { LDAP_ATTR_KICKOFF_TIME,       "kickoffTime"   },
+       { LDAP_ATTR_DISPLAY_NAME,       "displayName"   },
+       { LDAP_ATTR_HOME_PATH,          "smbHome"       },
+       { LDAP_ATTR_HOME_DRIVE,         "homeDrives"    },
+       { LDAP_ATTR_LOGON_SCRIPT,       "scriptPath"    },
+       { LDAP_ATTR_PROFILE_PATH,       "profilePath"   },
+       { LDAP_ATTR_USER_WKS,           "userWorkstations"},
+       { LDAP_ATTR_USER_RID,           "rid"           },
+       { LDAP_ATTR_PRIMARY_GROUP_RID,  "primaryGroupID"},
+       { LDAP_ATTR_LMPW,               "lmPassword"    },
+       { LDAP_ATTR_NTPW,               "ntPassword"    },
+       { LDAP_ATTR_DOMAIN,             "domain"        },
+       { LDAP_ATTR_ACB_INFO,           "acctFlags"     },
        { LDAP_ATTR_LIST_END,           NULL            }
 };
 
@@ -106,6 +129,32 @@ ATTRIB_MAP_ENTRY attrib_map_v30[] = {
        { LDAP_ATTR_LIST_END,           NULL                    }
 };
 
+ATTRIB_MAP_ENTRY attrib_map_to_delete_v30[] = {
+       { LDAP_ATTR_PWD_LAST_SET,       "sambaPwdLastSet"       },
+       { LDAP_ATTR_PWD_CAN_CHANGE,     "sambaPwdCanChange"     },
+       { LDAP_ATTR_PWD_MUST_CHANGE,    "sambaPwdMustChange"    },
+       { LDAP_ATTR_LOGON_TIME,         "sambaLogonTime"        },
+       { LDAP_ATTR_LOGOFF_TIME,        "sambaLogoffTime"       },
+       { LDAP_ATTR_KICKOFF_TIME,       "sambaKickoffTime"      },
+       { LDAP_ATTR_HOME_DRIVE,         "sambaHomeDrive"        },
+       { LDAP_ATTR_HOME_PATH,          "sambaHomePath"         },
+       { LDAP_ATTR_LOGON_SCRIPT,       "sambaLogonScript"      },
+       { LDAP_ATTR_PROFILE_PATH,       "sambaProfilePath"      },
+       { LDAP_ATTR_USER_WKS,           "sambaUserWorkstations" },
+       { LDAP_ATTR_USER_SID,           LDAP_ATTRIBUTE_SID      },
+       { LDAP_ATTR_PRIMARY_GROUP_SID,  "sambaPrimaryGroupSID"  },
+       { LDAP_ATTR_LMPW,               "sambaLMPassword"       },
+       { LDAP_ATTR_NTPW,               "sambaNTPassword"       },
+       { LDAP_ATTR_DOMAIN,             "sambaDomainName"       },
+       { LDAP_ATTR_ACB_INFO,           "sambaAcctFlags"        },
+       { LDAP_ATTR_MUNGED_DIAL,        "sambaMungedDial"       },
+       { LDAP_ATTR_BAD_PASSWORD_COUNT, "sambaBadPasswordCount" },
+       { LDAP_ATTR_BAD_PASSWORD_TIME,  "sambaBadPasswordTime"  },
+       { LDAP_ATTR_PWD_HISTORY,        "sambaPasswordHistory"  },
+       { LDAP_ATTR_LOGON_HOURS,        "sambaLogonHours"       },
+       { LDAP_ATTR_LIST_END,           NULL                    }
+};
+
 /* attributes used for allocating RIDs */
 
 ATTRIB_MAP_ENTRY dominfo_attr_list[] = {
@@ -190,7 +239,7 @@ ATTRIB_MAP_ENTRY sidmap_attr_list[] = {
                i++;
        i++;
 
-       names = (char**)malloc( sizeof(char*)*i );
+       names = SMB_MALLOC_ARRAY( char*, i );
        if ( !names ) {
                DEBUG(0,("get_attr_list: out of memory\n"));
                return NULL;
@@ -198,7 +247,7 @@ ATTRIB_MAP_ENTRY sidmap_attr_list[] = {
 
        i = 0;
        while ( table[i].attrib != LDAP_ATTR_LIST_END ) {
-               names[i] = strdup( table[i].name );
+               names[i] = SMB_STRDUP( table[i].name );
                i++;
        }
        names[i] = NULL;
@@ -246,7 +295,7 @@ static BOOL fetch_ldap_pw(char **dn, char** pw)
        if (!size) {
                /* Upgrade 2.2 style entry */
                char *p;
-               char* old_style_key = strdup(*dn);
+               char* old_style_key = SMB_STRDUP(*dn);
                char *data;
                fstring old_style_pw;
                
@@ -359,7 +408,7 @@ static BOOL fetch_ldap_pw(char **dn, char** pw)
 #endif
 
        if (mods == NULL) {
-               mods = (LDAPMod **) malloc(sizeof(LDAPMod *));
+               mods = SMB_MALLOC_P(LDAPMod *);
                if (mods == NULL) {
                        DEBUG(0, ("make_a_mod: out of memory!\n"));
                        return;
@@ -373,19 +422,19 @@ static BOOL fetch_ldap_pw(char **dn, char** pw)
        }
 
        if (mods[i] == NULL) {
-               mods = (LDAPMod **) Realloc (mods, (i + 2) * sizeof (LDAPMod *));
+               mods = SMB_REALLOC_ARRAY (mods, LDAPMod *, i + 2);
                if (mods == NULL) {
                        DEBUG(0, ("make_a_mod: out of memory!\n"));
                        return;
                }
-               mods[i] = (LDAPMod *) malloc(sizeof(LDAPMod));
+               mods[i] = SMB_MALLOC_P(LDAPMod);
                if (mods[i] == NULL) {
                        DEBUG(0, ("make_a_mod: out of memory!\n"));
                        return;
                }
                mods[i]->mod_op = modop;
                mods[i]->mod_values = NULL;
-               mods[i]->mod_type = strdup(attribute);
+               mods[i]->mod_type = SMB_STRDUP(attribute);
                mods[i + 1] = NULL;
        }
 
@@ -396,8 +445,7 @@ static BOOL fetch_ldap_pw(char **dn, char** pw)
                if (mods[i]->mod_values != NULL) {
                        for (; mods[i]->mod_values[j] != NULL; j++);
                }
-               mods[i]->mod_values = (char **)Realloc(mods[i]->mod_values,
-                                              (j + 2) * sizeof (char *));
+               mods[i]->mod_values = SMB_REALLOC_ARRAY(mods[i]->mod_values, char *, j + 2);
                                               
                if (mods[i]->mod_values == NULL) {
                        DEBUG (0, ("make_a_mod: Memory allocation failure!\n"));
@@ -428,6 +476,12 @@ static BOOL fetch_ldap_pw(char **dn, char** pw)
        char oldval[2048]; /* current largest allowed value is mungeddial */
        BOOL existed;
 
+       if (attribute == NULL) {
+               /* This can actually happen for ldapsam_compat where we for
+                * example don't have a password history */
+               return;
+       }
+
        if (existing != NULL) {
                existed = smbldap_get_single_attribute(ldap_struct, existing, attribute, oldval, sizeof(oldval));
        } else {
@@ -519,7 +573,7 @@ static void smbldap_store_state(LDAP *ld, struct smbldap_state *smbldap_state)
                return;
        }
 
-       t = smb_xmalloc(sizeof(*t));
+       t = SMB_XMALLOC_P(struct smbldap_state_lookup);
        ZERO_STRUCTP(t);
        
        DLIST_ADD_END(smbldap_state_lookup_list, t, tmp);
@@ -663,11 +717,11 @@ static int rebindproc_with_state  (LDAP * ld, char **whop, char **credp,
                DEBUG(5,("rebind_proc_with_state: Rebinding as \"%s\"\n", 
                          ldap_state->bind_dn));
 
-               *whop = strdup(ldap_state->bind_dn);
+               *whop = SMB_STRDUP(ldap_state->bind_dn);
                if (!*whop) {
                        return LDAP_NO_MEMORY;
                }
-               *credp = strdup(ldap_state->bind_secret);
+               *credp = SMB_STRDUP(ldap_state->bind_secret);
                if (!*credp) {
                        SAFE_FREE(*whop);
                        return LDAP_NO_MEMORY;
@@ -752,6 +806,7 @@ static int smbldap_connect_system(struct smbldap_state *ldap_state, LDAP * ldap_
        int rc;
        char *ldap_dn;
        char *ldap_secret;
+       int version;
 
        /* get the password */
        if (!fetch_ldap_pw(&ldap_dn, &ldap_secret)) {
@@ -791,7 +846,8 @@ static int smbldap_connect_system(struct smbldap_state *ldap_state, LDAP * ldap_
                ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
                                &ld_error);
                DEBUG(ldap_state->num_failures ? 2 : 0,
-                     ("failed to bind to server with dn= %s Error: %s\n\t%s\n",
+                     ("failed to bind to server %s with dn=\"%s\" Error: %s\n\t%s\n",
+                              ldap_state->uri,
                               ldap_dn ? ldap_dn : "(unknown)", ldap_err2string(rc),
                               ld_error ? ld_error : "(unknown)"));
                SAFE_FREE(ld_error);
@@ -801,7 +857,14 @@ static int smbldap_connect_system(struct smbldap_state *ldap_state, LDAP * ldap_
 
        ldap_state->num_failures = 0;
 
+       ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version);
+
+       if (smbldap_has_control(ldap_state, ADS_PAGE_CTL_OID) && version == 3) {
+               ldap_state->paged_results = True;
+       }
+
        DEBUG(3, ("ldap_connect_system: succesful connection to the LDAP server\n"));
+       DEBUGADD(3, ("ldap_connect_system: LDAP server %s support paged results\n", ldap_state->paged_results?"does":"does not"));
        return rc;
 }
 
@@ -852,6 +915,7 @@ static int smbldap_open(struct smbldap_state *ldap_state)
 
 
        ldap_state->last_ping = time(NULL);
+       ldap_state->pid = sys_getpid();
        DEBUG(4,("The LDAP server is succesfully connected\n"));
 
        return LDAP_SUCCESS;
@@ -910,6 +974,9 @@ static int another_ldap_try(struct smbldap_state *ldap_state, int *rc,
                got_alarm = False;
                old_handler = CatchSignal(SIGALRM, gotalarm_sig);
                alarm(endtime - now);
+
+               if (ldap_state->pid != sys_getpid())
+                       smbldap_close(ldap_state);
        }
 
        while (1) {
@@ -919,6 +986,7 @@ static int another_ldap_try(struct smbldap_state *ldap_state, int *rc,
 
                *attempts += 1;
 
+               smbldap_close(ldap_state);
                open_rc = smbldap_open(ldap_state);
 
                if (open_rc == LDAP_SUCCESS) {
@@ -1152,7 +1220,7 @@ void smbldap_free_struct(struct smbldap_state **ldap_state)
 
 NTSTATUS smbldap_init(TALLOC_CTX *mem_ctx, const char *location, struct smbldap_state **smbldap_state) 
 {
-       *smbldap_state = talloc_zero(mem_ctx, sizeof(**smbldap_state));
+       *smbldap_state = TALLOC_ZERO_P(mem_ctx, struct smbldap_state);
        if (!*smbldap_state) {
                DEBUG(0, ("talloc() failed for ldapsam private_data!\n"));
                return NT_STATUS_NO_MEMORY;
@@ -1372,3 +1440,96 @@ char *smbldap_get_dn(LDAP *ld, LDAPMessage *entry)
        return unix_dn;
 }
 
+/*******************************************************************
+ Check if root-dse has a certain Control or Extension
+********************************************************************/
+
+static BOOL smbldap_check_root_dse(struct smbldap_state *ldap_state, const char **attrs, const char *value) 
+{
+       LDAPMessage *msg = NULL;
+       LDAPMessage *entry = NULL;
+       char **values = NULL;
+       int rc, num_result, num_values, i;
+       BOOL result = False;
+
+       if (!attrs[0]) {
+               DEBUG(3,("smbldap_check_root_dse: nothing to look for\n"));
+               return False;
+       }
+
+       if (!strequal(attrs[0], "supportedExtension") && 
+           !strequal(attrs[0], "supportedControl")) {
+               DEBUG(3,("smbldap_check_root_dse: no idea what to query root-dse for: %s ?\n", attrs[0]));
+               return False;
+       }
+
+       rc = ldap_search_s(ldap_state->ldap_struct, "", LDAP_SCOPE_BASE, 
+                          "(objectclass=*)", attrs, 0 , &msg);
+
+       if (rc != LDAP_SUCCESS) {
+               DEBUG(3,("smbldap_check_root_dse: Could not search rootDSE\n"));
+               return False;
+       }
+
+       num_result = ldap_count_entries(ldap_state->ldap_struct, msg);
+
+       if (num_result != 1) {
+               DEBUG(3,("smbldap_check_root_dse: Expected one rootDSE, got %d\n", num_result));
+               goto done;
+       }
+
+       entry = ldap_first_entry(ldap_state->ldap_struct, msg);
+
+       if (entry == NULL) {
+               DEBUG(3,("smbldap_check_root_dse: Could not retrieve rootDSE\n"));
+               goto done;
+       }
+
+       values = ldap_get_values(ldap_state->ldap_struct, entry, attrs[0]);
+
+       if (values == NULL) {
+               DEBUG(5,("smbldap_check_root_dse: LDAP Server does not support any %s\n", attrs[0]));
+               goto done;
+       }
+
+       num_values = ldap_count_values(values);
+
+       if (num_values == 0) {
+               DEBUG(5,("smbldap_check_root_dse: LDAP Server does not have any %s\n", attrs[0]));
+               goto done;
+       }
+
+       for (i=0; i<num_values; i++) {
+               if (strcmp(values[i], value) == 0)
+                       result = True;
+       }
+
+
+ done:
+       if (values != NULL)
+               ldap_value_free(values);
+       if (msg != NULL)
+               ldap_msgfree(msg);
+
+       return result;
+}
+
+/*******************************************************************
+ Check if LDAP-Server supports a certain Control (OID in string format)
+********************************************************************/
+
+BOOL smbldap_has_control(struct smbldap_state *ldap_state, const char *control)
+{
+       const char *attrs[] = { "supportedControl", NULL };
+       return smbldap_check_root_dse(ldap_state, attrs, control);
+}
+
+/*******************************************************************
+ Check if LDAP-Server supports a certain Extension (OID in string format)
+********************************************************************/
+
+BOOL smbldap_has_extension(struct smbldap_state *ldap_state, const char *extension)
+{
+       const char *attrs[] = { "supportedExtension", NULL };
+       return smbldap_check_root_dse(ldap_state, attrs, extension);
+}