r21616: Delay initialization of idmap and nss_info backends until necessary
authorGerald Carter <jerry@samba.org>
Thu, 1 Mar 2007 03:16:38 +0000 (03:16 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:18:18 +0000 (12:18 -0500)
so they can honor the offline logon state.
(This used to be commit 15b13dfe81e861b94077c94b80117a85a5ffb999)

source3/nsswitch/idmap.c
source3/nsswitch/idmap_cache.c
source3/nsswitch/nss_info.c
source3/nsswitch/winbindd.c
source3/nsswitch/winbindd_async.c
source3/nsswitch/winbindd_dual.c

index d69fd68e1031f27589ae9f8140caf8cdf63fa9be..a58959afe4c36586e6055d84258c6307d593b293 100644 (file)
@@ -225,9 +225,36 @@ NTSTATUS idmap_close(void)
 
 static const char *idmap_default_domain[] = { "default domain", NULL };
 
+/****************************************************************************
+ ****************************************************************************/
+
+NTSTATUS idmap_init_cache(void)
+{      
+       /* Always initialize the cache.  We'll have to delay initialization
+          of backends if we are offline */
+
+       if ( idmap_ctx ) {
+               return NT_STATUS_OK;
+       }       
+       
+       if ( (idmap_ctx = talloc_named_const(NULL, 0, "idmap_ctx")) == NULL ) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       if ( (idmap_cache = idmap_cache_init(idmap_ctx)) == NULL ) {
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ ****************************************************************************/
+
 NTSTATUS idmap_init(void)
 {      
        NTSTATUS ret;
+       static NTSTATUS backend_init_status = NT_STATUS_UNSUCCESSFUL;   
        struct idmap_domain *dom;
        char *compat_backend = NULL;
        char *compat_params = NULL;
@@ -238,16 +265,23 @@ NTSTATUS idmap_init(void)
        int compat = 0;
        int i;
 
-       if (idmap_ctx) {
-               return NT_STATUS_OK;
-       }
+       /* Always initialize the cache.  We'll have to delay initialization
+          of backends if we are offline */
 
-       if ( (idmap_ctx = talloc_named_const(NULL, 0, "idmap_ctx")) == NULL ) {
-               return NT_STATUS_NO_MEMORY;
+       ret = idmap_init_cache();
+       if ( !NT_STATUS_IS_OK(ret) )
+               return ret;
+
+       if ( NT_STATUS_IS_OK(backend_init_status) ) {
+               return NT_STATUS_OK;
        }
+       
+       /* We can't reliably call intialization code here unless 
+          we are online */
 
-       if ( (idmap_cache = idmap_cache_init(idmap_ctx)) == NULL ) {
-               return NT_STATUS_UNSUCCESSFUL;
+       if ( get_global_winbindd_state_offline() ) {
+               backend_init_status = NT_STATUS_FILE_IS_OFFLINE;
+               return backend_init_status;             
        }
 
        static_init_idmap;
@@ -559,11 +593,17 @@ NTSTATUS idmap_init(void)
        /* cleanpu temporary strings */
        TALLOC_FREE( compat_backend );
        
+       backend_init_status = NT_STATUS_OK;
+       
        return NT_STATUS_OK;
 
 done:
        DEBUG(0, ("Aborting IDMAP Initialization ...\n"));
        idmap_close();
+
+       /* save the init status for later checks */
+       backend_init_status = ret;
+       
        return ret;
 }
 
@@ -1067,6 +1107,14 @@ NTSTATUS idmap_unixids_to_sids(struct id_map **ids)
 
        /* let's see if there is any id mapping to be retieved from the backends */
        if (bi) {
+               /* Only do query if we are online */
+               if ( lp_winbind_offline_logon() &&
+                    get_global_winbindd_state_offline() )
+               {
+                       ret = NT_STATUS_FILE_IS_OFFLINE;
+                       goto done;
+               }
+
                ret = idmap_backends_unixids_to_sids(bids);
                IDMAP_CHECK_RET(ret);
 
@@ -1132,7 +1180,8 @@ NTSTATUS idmap_sids_to_unixids(struct id_map **ids)
                if ( ! NT_STATUS_IS_OK(ret)) {
 
                        if ( ! bids) {
-                               /* alloc space for ids to be resolved by backends (realloc ten by ten) */
+                               /* alloc space for ids to be resolved
+                                  by backends (realloc ten by ten) */
                                bids = talloc_array(ctx, struct id_map *, 10);
                                if ( ! bids) {
                                        DEBUG(1, ("Out of memory!\n"));
@@ -1164,6 +1213,14 @@ NTSTATUS idmap_sids_to_unixids(struct id_map **ids)
 
        /* let's see if there is any id mapping to be retieved from the backends */
        if (bids) {
+               /* Only do query if we are online */
+               if ( lp_winbind_offline_logon() &&
+                    get_global_winbindd_state_offline() )
+               {
+                       ret = NT_STATUS_FILE_IS_OFFLINE;
+                       goto done;
+               }
+               
                ret = idmap_backends_sids_to_unixids(bids);
                IDMAP_CHECK_RET(ret);
 
index 897dd9c4f5b5e8d6159c7245aa817bf28080bff2..caf5fe72b3a1bf96bb89a4955384980d918681a7 100644 (file)
@@ -22,6 +22,7 @@
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/
 
 #include "includes.h"
+#include "winbindd.h"
 
 #define TIMEOUT_LEN 12
 #define IDMAP_CACHE_DATA_FMT   "%12u/%s"
@@ -418,14 +419,34 @@ NTSTATUS idmap_cache_map_sid(struct idmap_cache_ctx *cache, struct id_map *id)
                /* here ret == NT_STATUS_OK and id->status = ID_MAPPED */
 
                if (t <= time(NULL)) {
-                       /* We're expired, set an error code for upper layer */
-                       ret = NT_STATUS_SYNCHRONIZATION_REQUIRED;
+                       /* If we've been told to be offline - stay in 
+                          that state... */
+                       if (lp_winbind_offline_logon() && 
+                           get_global_winbindd_state_offline()) 
+                       {
+                               DEBUG(10,("idmap_cache_map_sid: winbindd is "
+                                         "globally offline.\n"));
+                       } else {
+                               /* We're expired, set an error code
+                                  for upper layer */
+                               ret = NT_STATUS_SYNCHRONIZATION_REQUIRED;
+                       }                       
                }
        } else {
                if (t <= time(NULL)) {
-                       /* We're expired, delete the entry and return not mapped */
-                       tdb_delete(cache->tdb, keybuf);
-                       ret = NT_STATUS_NONE_MAPPED;
+                       /* If we've been told to be offline - stay in 
+                          that state... */
+                       if (lp_winbind_offline_logon() && 
+                           get_global_winbindd_state_offline()) 
+                       {
+                               DEBUG(10,("idmap_cache_map_sid: winbindd is "
+                                         "globally offline.\n"));
+                       } else {                                
+                               /* We're expired, delete the entry and return
+                                  not mapped */
+                               tdb_delete(cache->tdb, keybuf);
+                               ret = NT_STATUS_NONE_MAPPED;
+                       }                       
                } else {
                        /* this is not mapped as it was a negative cache hit */
                        id->status = ID_UNMAPPED;
@@ -508,14 +529,34 @@ NTSTATUS idmap_cache_map_id(struct idmap_cache_ctx *cache, struct id_map *id)
                /* here ret == NT_STATUS_OK and id->mapped = True */
 
                if (t <= time(NULL)) {
-                       /* We're expired, set an error code for upper layer */
-                       ret = NT_STATUS_SYNCHRONIZATION_REQUIRED;
+                       /* If we've been told to be offline - stay in
+                          that state... */
+                       if (lp_winbind_offline_logon() && 
+                           get_global_winbindd_state_offline()) 
+                       {
+                               DEBUG(10,("idmap_cache_map_sid: winbindd is "
+                                         "globally offline.\n"));
+                       } else {
+                               /* We're expired, set an error code
+                                  for upper layer */
+                               ret = NT_STATUS_SYNCHRONIZATION_REQUIRED;
+                       }                       
                }
        } else {
                if (t <= time(NULL)) {
-                       /* We're expired, delete the entry and return not mapped */
-                       tdb_delete(cache->tdb, keybuf);
-                       ret = NT_STATUS_NONE_MAPPED;
+                       /* If we've been told to be offline - stay in
+                          that state... */
+                       if (lp_winbind_offline_logon() && 
+                           get_global_winbindd_state_offline()) 
+                       {
+                               DEBUG(10,("idmap_cache_map_sid: winbindd is "
+                                         "globally offline.\n"));
+                       } else {
+                               /* We're expired, delete the entry and
+                                  return not mapped */
+                               tdb_delete(cache->tdb, keybuf);
+                               ret = NT_STATUS_NONE_MAPPED;
+                       }                       
                } else {
                        /* this is not mapped is it was a negative cache hit */
                        id->status = ID_UNMAPPED;
index 0b0caeee0222799fc1225b933c98ee86b791f346..d251629662903d74f1ba20ac20db0b34415027ff 100644 (file)
@@ -131,11 +131,17 @@ static BOOL parse_nss_parm( const char *config, char **backend, char **domain )
  NTSTATUS nss_init( const char **nss_list )
 {
        NTSTATUS status;
+       static NTSTATUS nss_initialized = NT_STATUS_UNSUCCESSFUL;
        int i;
        char *backend, *domain;
        struct nss_function_entry *nss_backend;
        struct nss_domain_entry *nss_domain;
 
+       /* check for previous successful initializations */
+
+       if ( NT_STATUS_IS_OK(nss_initialized) )
+               return NT_STATUS_OK;
+       
        /* The "template" backend should alqays be registered as it
           is a static module */
 
@@ -207,20 +213,25 @@ static BOOL parse_nss_parm( const char *config, char **backend, char **domain )
        }
        
                
+       nss_initialized = NT_STATUS_OK;
+       
        return NT_STATUS_OK;
 }
 
 /********************************************************************
  *******************************************************************/
 
- NTSTATUS nss_get_info( const char *domain, const DOM_SID *user_sid,
-                      TALLOC_CTX *ctx,
-                      ADS_STRUCT *ads, LDAPMessage *msg,
-                      char **homedir, char **shell, char **gecos,
-                      gid_t *p_gid)
+static struct nss_domain_entry *find_nss_domain( const char *domain )
 {
+       NTSTATUS status;        
        struct nss_domain_entry *p;
-       struct nss_info_methods *m;
+
+       status = nss_init( lp_winbind_nss_info() );
+       if ( !NT_STATUS_IS_OK(status) ) {
+               DEBUG(4,("nss_get_info: Failed to init nss_info API (%s)!\n",
+                        nt_errstr(status)));
+               return NULL;
+       }
        
        for ( p=nss_domain_list; p; p=p->next ) {
                if ( strequal( p->domain, domain ) )
@@ -231,12 +242,33 @@ static BOOL parse_nss_parm( const char *config, char **backend, char **domain )
 
        if ( !p ) {
                if ( !nss_domain_list ) {
-                       return NT_STATUS_NOT_FOUND;
+                       return NULL;
                }
                
                p = nss_domain_list;            
        }
 
+       return p;
+}
+
+/********************************************************************
+ *******************************************************************/
+
+ NTSTATUS nss_get_info( const char *domain, const DOM_SID *user_sid,
+                      TALLOC_CTX *ctx,
+                      ADS_STRUCT *ads, LDAPMessage *msg,
+                      char **homedir, char **shell, char **gecos,
+                      gid_t *p_gid)
+{
+       struct nss_domain_entry *p;
+       struct nss_info_methods *m;
+
+       if ( (p = find_nss_domain( domain )) == NULL ) {
+               DEBUG(4,("nss_get_info: Failed to find nss domain pointer for %s\n",
+                        domain ));
+               return NT_STATUS_NOT_FOUND;
+       }
+               
        m = p->backend->methods;
 
        return m->get_nss_info( p, user_sid, ctx, ads, msg, 
index ef6d4700cebd66d36dad1d6fe982023a7cbf0947..603cfeb85be987406b824591822b3af133ed9bbe 100644 (file)
@@ -1011,14 +1011,10 @@ int main(int argc, char **argv, char **envp)
 
        /* Winbind daemon initialisation */
 
-       if ( ! NT_STATUS_IS_OK(idmap_init()) ) {
-               DEBUG(1, ("Could not init idmap! - Sid/[UG]id mapping will not be available\n"));
+       if ( ! NT_STATUS_IS_OK(idmap_init_cache()) ) {
+               DEBUG(1, ("Could not init idmap cache!\n"));            
        }
 
-#ifdef WITH_ADS
-       nss_init( lp_winbind_nss_info() );
-#endif
-
        /* Unblock all signals we are interested in as they may have been
           blocked by the parent process. */
 
@@ -1047,6 +1043,7 @@ int main(int argc, char **argv, char **envp)
 
        pidfile_create("winbindd");
 
+#if 0  /* not finished yet */
        /* Ensure all cache and idmap caches are consistent
           before we startup. */
 
@@ -1060,6 +1057,7 @@ int main(int argc, char **argv, char **envp)
                }
                return execve(argv[0], argv, envp);
        }
+#endif
 
 #if HAVE_SETPGID
        /*
index cafaf1cb056484712e5403cd8c0c903b6e8324a3..aa48f513e9774af01d5121e799266cd088f81c5f 100644 (file)
@@ -535,7 +535,7 @@ void winbindd_sid2gid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
        request.cmd = WINBINDD_DUAL_SID2GID;
        sid_to_string(request.data.dual_sid2id.sid, sid);
 
-       DEBUG(7,("idmap_sid2gid_async: Resolving %s to a gid\n", 
+       DEBUG(7,("winbindd_sid2gid_async: Resolving %s to a gid\n", 
                request.data.dual_sid2id.sid));
 
        do_async(mem_ctx, idmap_child(), &request, winbindd_sid2gid_recv,
index edb4fa504b11420ba3c4095cca3bc53faa306b6c..6324de9a2d9dfae256b6750724ec69fda1e36ba4 100644 (file)
@@ -502,10 +502,26 @@ void winbind_msg_offline(int msg_type, struct process_id src,
                }
                DEBUG(5,("winbind_msg_offline: marking %s offline.\n", domain->name));
                set_domain_offline(domain);
+
+               /* Send an offline message to the idmap child when our
+                  primary domain goes offline */
+
+               if ( domain->primary ) {
+                       struct winbindd_child *idmap = idmap_child();
+
+                       if ( idmap->pid != 0 ) {
+                               message_send_pid(pid_to_procid(idmap->pid), 
+                                                MSG_WINBIND_OFFLINE, 
+                                                domain->name, 
+                                                strlen(domain->name)+1, 
+                                                False);
+                       }                       
+               }
        }
 
        for (child = children; child != NULL; child = child->next) {
-               /* Don't send message to idmap child. */
+               /* Don't send message to idmap child.  We've already
+                  done so above. */
                if (!child->domain || (child == idmap_child())) {
                        continue;
                }
@@ -556,6 +572,22 @@ void winbind_msg_online(int msg_type, struct process_id src,
 
                winbindd_flush_negative_conn_cache(domain);
                set_domain_online_request(domain);
+
+               /* Send an offline message to the idmap child when our
+                  primary domain goes offline */
+
+               if ( domain->primary ) {
+                       struct winbindd_child *idmap = idmap_child();
+                       
+                       if ( idmap->pid != 0 ) {
+                               message_send_pid(pid_to_procid(idmap->pid), 
+                                                MSG_WINBIND_ONLINE,
+                                                domain->name,
+                                                strlen(domain->name)+1, 
+                                                False);
+                       }
+                       
+               }
        }
 
        for (child = children; child != NULL; child = child->next) {