s3-talloc Change TALLOC_ZERO_P() to talloc_zero()
[nivanova/samba-autobuild/.git] / source3 / winbindd / nss_info.c
index 29393a565eff40edf28d9b25788965aabceaf663..a3f95c649351e7e7ce052fc3938d8e296fa3e4da 100644 (file)
@@ -3,6 +3,7 @@
    Idmap NSS headers
 
    Copyright (C) Gerald Carter             2006
+   Copyright (C) Michael Adam 2008
 
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
 */
 
 #include "includes.h"
+#include "ads.h"
 #include "nss_info.h"
 
 static struct nss_function_entry *backends = NULL;
+static struct nss_function_entry *default_backend = NULL;
 static struct nss_domain_entry *nss_domain_list = NULL;
 
 /**********************************************************************
@@ -85,8 +88,6 @@ static struct nss_function_entry *nss_get_backend(const char *name )
 static bool parse_nss_parm( const char *config, char **backend, char **domain )
 {
        char *p;
-       char *q;
-       int len;
 
        *backend = *domain = NULL;
 
@@ -108,17 +109,44 @@ static bool parse_nss_parm( const char *config, char **backend, char **domain )
                *domain = SMB_STRDUP( p+1 );
        }
 
-       len = PTR_DIFF(p,config)+1;
-       if ( (q = SMB_MALLOC_ARRAY( char, len )) == NULL ) {
-               SAFE_FREE( *backend );
-               return False;
+       *backend = SMB_STRNDUP(config, PTR_DIFF(p, config));
+       return (*backend != NULL);
+}
+
+static NTSTATUS nss_domain_list_add_domain(const char *domain,
+                                          struct nss_function_entry *nss_backend)
+{
+       struct nss_domain_entry *nss_domain;
+
+       nss_domain = talloc_zero(nss_domain_list, struct nss_domain_entry);
+       if (!nss_domain) {
+               DEBUG(0, ("nss_domain_list_add_domain: talloc() failure!\n"));
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       nss_domain->backend = nss_backend;
+       if (domain) {
+               nss_domain->domain  = talloc_strdup(nss_domain, domain);
+               if (!nss_domain->domain) {
+                       DEBUG(0, ("nss_domain_list_add_domain: talloc() "
+                                 "failure!\n"));
+                       TALLOC_FREE(nss_domain);
+                       return NT_STATUS_NO_MEMORY;
+               }
+       }
+
+       nss_domain->init_status = nss_domain->backend->methods->init(nss_domain);
+       if (!NT_STATUS_IS_OK(nss_domain->init_status))  {
+               DEBUG(0, ("nss_init: Failed to init backend '%s' for domain "
+                         "'%s'!\n", nss_backend->name, nss_domain->domain));
        }
 
-       StrnCpy( q, config, len-1);
-       q[len-1] = '\0';
-       *backend = q;
+       DLIST_ADD(nss_domain_list, nss_domain);
 
-       return True;
+       DEBUG(10, ("Added domain '%s' with backend '%s' to nss_domain_list.\n",
+                  domain, nss_backend->name));
+
+       return NT_STATUS_OK;
 }
 
 /********************************************************************
@@ -126,24 +154,25 @@ static bool parse_nss_parm( const char *config, char **backend, char **domain )
  to initialize the state on a per domain basis.
  *******************************************************************/
 
- NTSTATUS nss_init( const char **nss_list )
+static NTSTATUS nss_init(const char **nss_list)
 {
        NTSTATUS status;
-       static NTSTATUS nss_initialized = NT_STATUS_UNSUCCESSFUL;
+       static bool nss_initialized = false;
        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) )
+       if (nss_initialized) {
                return NT_STATUS_OK;
+       }
 
-       /* The "template" backend should alqays be registered as it
+       /* The "template" backend should always be registered as it
           is a static module */
 
-       if ( (nss_backend = nss_get_backend( "template" )) == NULL ) {
+       nss_backend = nss_get_backend("template");
+       if (nss_backend == NULL) {
                static_init_nss_info;
        }
 
@@ -163,45 +192,50 @@ static bool parse_nss_parm( const char *config, char **backend, char **domain )
 
                /* validate the backend */
 
-               if ( (nss_backend = nss_get_backend( backend )) == NULL ) {
-                       /* attempt to register the backend */
-                       status = smb_probe_module( "nss_info", backend );
+               nss_backend = nss_get_backend(backend);
+               if (nss_backend == NULL) {
+                       /*
+                        * This is a freaking hack. We don't have proper
+                        * modules for nss_info backends. Right now we have
+                        * our standard nss_info backends in the ad backend.
+                        */
+                       status = smb_probe_module("idmap", "ad");
                        if ( !NT_STATUS_IS_OK(status) ) {
                                continue;
                        }
+               }
 
-                       /* try again */
-                       if ( (nss_backend = nss_get_backend( backend )) == NULL ) {
-                               DEBUG(0,("nss_init: unregistered backend %s!.  Skipping\n",
-                                        backend));
+               nss_backend = nss_get_backend(backend);
+               if (nss_backend == NULL) {
+                       /* attempt to register the backend */
+                       status = smb_probe_module( "nss_info", backend );
+                       if ( !NT_STATUS_IS_OK(status) ) {
                                continue;
                        }
                }
 
-               /* fill in the nss_domain_entry and add it to the
-                  list of domains */
-
-               nss_domain = TALLOC_ZERO_P( nss_domain_list, struct nss_domain_entry );
-               if ( !nss_domain ) {
-                       DEBUG(0,("nss_init: talloc() failure!\n"));
-                       return NT_STATUS_NO_MEMORY;
+               /* try again */
+               nss_backend = nss_get_backend(backend);
+               if (nss_backend == NULL) {
+                       DEBUG(0, ("nss_init: unregistered backend %s!. "
+                                 "Skipping\n", backend));
+                       continue;
                }
 
-               nss_domain->backend = nss_backend;
-               nss_domain->domain  = talloc_strdup( nss_domain, domain );
-
-               /* Try to init and ave the result */
-
-               nss_domain->init_status = nss_domain->backend->methods->init( nss_domain );
-               DLIST_ADD( nss_domain_list, nss_domain );
-               if ( !NT_STATUS_IS_OK(nss_domain->init_status) ) {
-                       DEBUG(0,("nss_init: Failed to init backend for %s domain!\n", 
-                                nss_domain->domain));
+               /*
+                * The first config item of the list without an explicit domain
+                * is treated as the default nss info backend.
+                */
+               if ((domain == NULL) && (default_backend == NULL)) {
+                       DEBUG(10, ("nss_init: using '%s' as default backend.\n",
+                                  backend));
+                       default_backend = nss_backend;
                }
 
-               DEBUG(10, ("nss_init: nss domain initialized: "
-                          "domain = '%s', backend = '%s'\n",
-                          domain, backend));
+               status = nss_domain_list_add_domain(domain, nss_backend);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
 
                /* cleanup */
 
@@ -214,10 +248,10 @@ static bool parse_nss_parm( const char *config, char **backend, char **domain )
                         "Defaulting to \"template\".\n"));
 
 
-               /* we shouild default to use template here */
+               /* we should default to use template here */
        }
 
-       nss_initialized = NT_STATUS_OK;
+       nss_initialized = true;
 
        return NT_STATUS_OK;
 }
@@ -232,8 +266,8 @@ static struct nss_domain_entry *find_nss_domain( const char *domain )
 
        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)));
+               DEBUG(4,("find_nss_domain: Failed to init nss_info API "
+                        "(%s)!\n", nt_errstr(status)));
                return NULL;
        }
 
@@ -242,13 +276,23 @@ static struct nss_domain_entry *find_nss_domain( const char *domain )
                        break;
        }
 
-       /* If we didn't find a match, then use the default nss info */
+       /* If we didn't find a match, then use the default nss backend */
 
        if ( !p ) {
-               if ( !nss_domain_list ) {
+               if (!default_backend) {
+                       return NULL;
+               }
+
+               status = nss_domain_list_add_domain(domain, default_backend);
+               if (!NT_STATUS_IS_OK(status)) {
                        return NULL;
                }
 
+               /*
+                * HACK ALERT:
+                * Here, we use the fact that the new domain was added at
+                * the beginning of the list...
+                */
                p = nss_domain_list;
        }
 
@@ -262,11 +306,10 @@ static struct nss_domain_entry *find_nss_domain( const char *domain )
 /********************************************************************
  *******************************************************************/
 
- NTSTATUS nss_get_info( const char *domain, const DOM_SID *user_sid,
+NTSTATUS nss_get_info( const char *domain, const struct dom_sid *user_sid,
                       TALLOC_CTX *ctx,
-                      ADS_STRUCT *ads, LDAPMessage *msg,
-                      char **homedir, char **shell, char **gecos,
-                      gid_t *p_gid)
+                      const char **homedir, const char **shell,
+                      const char **gecos, gid_t *p_gid)
 {
        struct nss_domain_entry *p;
        struct nss_info_methods *m;
@@ -282,7 +325,7 @@ static struct nss_domain_entry *find_nss_domain( const char *domain )
 
        m = p->backend->methods;
 
-       return m->get_nss_info( p, user_sid, ctx, ads, msg,
+       return m->get_nss_info( p, user_sid, ctx,
                                homedir, shell, gecos, p_gid );
 }