v3-4-test: Protect against invalid winbindd_cache entries
[obnox/samba-ctdb.git] / source3 / winbindd / winbindd_cache.c
index 360e915bc47542e9ac52e3df6618ef3e0de1297f..7df3bf323d8fd0c839cc06094fa84a9776d65098 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "includes.h"
 #include "winbindd.h"
+#include "tdb_validate.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_WINBIND
@@ -33,7 +34,6 @@
 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
 
 extern struct winbindd_methods reconnect_methods;
-extern bool opt_nocache;
 #ifdef HAVE_ADS
 extern struct winbindd_methods ads_methods;
 #endif
@@ -486,7 +486,9 @@ static void refresh_sequence_number(struct winbindd_domain *domain, bool force)
        time_diff = t - domain->last_seq_check;
 
        /* see if we have to refetch the domain sequence number */
-       if (!force && (time_diff < cache_time)) {
+       if (!force && (time_diff < cache_time) &&
+                       (domain->sequence_number != DOM_SEQUENCE_NONE) &&
+                       NT_STATUS_IS_OK(domain->last_status)) {
                DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain->name));
                goto done;
        }
@@ -495,8 +497,11 @@ static void refresh_sequence_number(struct winbindd_domain *domain, bool force)
        /* this will update the timestamp as well */
        
        status = fetch_cache_seqnum( domain, t );
-       if ( NT_STATUS_IS_OK(status) )
-               goto done;      
+       if (NT_STATUS_IS_OK(status) &&
+                       (domain->sequence_number != DOM_SEQUENCE_NONE) &&
+                       NT_STATUS_IS_OK(domain->last_status)) {
+               goto done;
+       }
 
        /* important! make sure that we know if this is a native 
           mode domain or not.  And that we can contact it. */
@@ -626,7 +631,7 @@ static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
        char *kstr;
        struct cache_entry *centry;
 
-       if (opt_nocache) {
+       if (!winbindd_use_cache()) {
                return NULL;
        }
 
@@ -828,7 +833,7 @@ static void centry_end(struct cache_entry *centry, const char *format, ...)
        char *kstr;
        TDB_DATA key, data;
 
-       if (opt_nocache) {
+       if (!winbindd_use_cache()) {
                return;
        }
 
@@ -1803,7 +1808,8 @@ static NTSTATUS rids_to_names(struct winbindd_domain *domain,
 
                        (*names)[i] = centry_string(centry, *names);
 
-               } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
+               } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)
+                          || NT_STATUS_EQUAL(centry->status, STATUS_SOME_UNMAPPED)) {
                        have_unmapped = true;
 
                } else {
@@ -2532,9 +2538,11 @@ bool init_wcache(void)
                return true;
 
        /* when working offline we must not clear the cache on restart */
-       wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
+       wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
                                WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE, 
-                               lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST), 
+                               ( lp_winbind_offline_logon()
+                                 ? TDB_DEFAULT
+                                 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST | TDB_INCOMPATIBLE_HASH ),
                                O_RDWR|O_CREAT, 0600);
 
        if (wcache->tdb == NULL) {
@@ -2575,9 +2583,9 @@ bool initialize_winbindd_cache(void)
                tdb_close(wcache->tdb);
                wcache->tdb = NULL;
 
-               if (unlink(lock_path("winbindd_cache.tdb")) == -1) {
+               if (unlink(cache_path("winbindd_cache.tdb")) == -1) {
                        DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
-                               lock_path("winbindd_cache.tdb"),
+                               cache_path("winbindd_cache.tdb"),
                                strerror(errno) ));
                        return false;
                }
@@ -2619,9 +2627,9 @@ void cache_store_response(pid_t pid, struct winbindd_response *response)
                return;
 
        DEBUG(10, ("Storing response for pid %d, len %d\n",
-                  pid, response->length));
+                  (int)pid, response->length));
 
-       fstr_sprintf(key_str, "DR/%d", pid);
+       fstr_sprintf(key_str, "DR/%d", (int)pid);
        if (tdb_store(wcache->tdb, string_tdb_data(key_str), 
                      make_tdb_data((uint8 *)response, sizeof(*response)),
                      TDB_REPLACE) == -1)
@@ -2635,7 +2643,7 @@ void cache_store_response(pid_t pid, struct winbindd_response *response)
        DEBUG(10, ("Storing extra data: len=%d\n",
                   (int)(response->length - sizeof(*response))));
 
-       fstr_sprintf(key_str, "DE/%d", pid);
+       fstr_sprintf(key_str, "DE/%d", (int)pid);
        if (tdb_store(wcache->tdb, string_tdb_data(key_str),
                      make_tdb_data((uint8 *)response->extra_data.data,
                                    response->length - sizeof(*response)),
@@ -2645,7 +2653,7 @@ void cache_store_response(pid_t pid, struct winbindd_response *response)
        /* We could not store the extra data, make sure the tdb does not
         * contain a main record with wrong dangling extra data */
 
-       fstr_sprintf(key_str, "DR/%d", pid);
+       fstr_sprintf(key_str, "DR/%d", (int)pid);
        tdb_delete(wcache->tdb, string_tdb_data(key_str));
 
        return;
@@ -2659,9 +2667,9 @@ bool cache_retrieve_response(pid_t pid, struct winbindd_response * response)
        if (!init_wcache())
                return false;
 
-       DEBUG(10, ("Retrieving response for pid %d\n", pid));
+       DEBUG(10, ("Retrieving response for pid %d\n", (int)pid));
 
-       fstr_sprintf(key_str, "DR/%d", pid);
+       fstr_sprintf(key_str, "DR/%d", (int)pid);
        data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
 
        if (data.dptr == NULL)
@@ -2683,7 +2691,7 @@ bool cache_retrieve_response(pid_t pid, struct winbindd_response * response)
        DEBUG(10, ("Retrieving extra data length=%d\n",
                   (int)(response->length - sizeof(*response))));
 
-       fstr_sprintf(key_str, "DE/%d", pid);
+       fstr_sprintf(key_str, "DE/%d", (int)pid);
        data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
 
        if (data.dptr == NULL) {
@@ -2710,10 +2718,10 @@ void cache_cleanup_response(pid_t pid)
        if (!init_wcache())
                return;
 
-       fstr_sprintf(key_str, "DR/%d", pid);
+       fstr_sprintf(key_str, "DR/%d", (int)pid);
        tdb_delete(wcache->tdb, string_tdb_data(key_str));
 
-       fstr_sprintf(key_str, "DE/%d", pid);
+       fstr_sprintf(key_str, "DE/%d", (int)pid);
        tdb_delete(wcache->tdb, string_tdb_data(key_str));
 
        return;
@@ -2855,13 +2863,16 @@ void wcache_flush_cache(void)
                tdb_close(wcache->tdb);
                wcache->tdb = NULL;
        }
-       if (opt_nocache)
+       if (!winbindd_use_cache()) {
                return;
+       }
 
        /* when working offline we must not clear the cache on restart */
-       wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
+       wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
                                WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE, 
-                               lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST), 
+                               ( lp_winbind_offline_logon()
+                                 ? TDB_DEFAULT
+                                 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST | TDB_INCOMPATIBLE_HASH ),
                                O_RDWR|O_CREAT, 0600);
 
        if (!wcache->tdb) {
@@ -3688,7 +3699,7 @@ static void validate_panic(const char *const why)
 int winbindd_validate_cache(void)
 {
        int ret = -1;
-       const char *tdb_path = lock_path("winbindd_cache.tdb");
+       const char *tdb_path = cache_path("winbindd_cache.tdb");
        TDB_CONTEXT *tdb = NULL;
 
        DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
@@ -3699,7 +3710,7 @@ int winbindd_validate_cache(void)
                           WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
                           ( lp_winbind_offline_logon() 
                             ? TDB_DEFAULT 
-                            : TDB_DEFAULT | TDB_CLEAR_IF_FIRST ),
+                            : TDB_DEFAULT | TDB_CLEAR_IF_FIRST | TDB_INCOMPATIBLE_HASH ),
                           O_RDWR|O_CREAT, 
                           0600);
        if (!tdb) {
@@ -3730,7 +3741,7 @@ done:
 int winbindd_validate_cache_nobackup(void)
 {
        int ret = -1;
-       const char *tdb_path = lock_path("winbindd_cache.tdb");
+       const char *tdb_path = cache_path("winbindd_cache.tdb");
 
        DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
        smb_panic_fn = validate_panic;
@@ -3852,7 +3863,9 @@ static TDB_DATA make_tdc_key( const char *domain_name )
        }
               
                
-       asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name );
+       if (asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name ) == -1) {
+               return key;
+       }
        key = string_term_tdb_data(keystr);
        
        return key;     
@@ -4222,7 +4235,14 @@ do_query:
        nt_status = nss_get_info( domain->name, user_sid, ctx, ads, msg, 
                                  homedir, shell, gecos, p_gid );
 
+       DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status)));
+
        if ( NT_STATUS_IS_OK(nt_status) ) {
+               DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir));
+                DEBUGADD(10, ("\tshell = '%s'\n", *shell));
+                DEBUGADD(10, ("\tgecos = '%s'\n", *gecos));
+                DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid));
+
                wcache_save_user_pwinfo( domain, nt_status, user_sid,
                                         *homedir, *shell, *gecos, *p_gid );
        }