The branch, master has been updated
       via  3a01ef710d4 tests: Add a test for the idmap_nss : use_upn setting
       via  086a90d52b0 idmap_nss: Install a messaging filter to reload the 
configuration
       via  a7a4d8e5333 idmap_nss: Add a parameter to use UPNs instead of plain 
names
       via  c8e4777a921 idmap_nss: Increase debug on failures
       via  de2f59c61a0 docs: Document idmap_nss "range" option
       via  8e1f2ee5f7c s3:winbind: Register a messaging filter foreach domain 
child
       via  c35937054cd s3:winbind: talloc the static locator child
       via  e3d0574d796 s3:winbind: talloc the static idmap child
      from  f642aff5544 buildtools: Remove ‘keep_underscore’ parameter

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 3a01ef710d4f0c11013214a4f8637ebdac8d9f5e
Author: Samuel Cabrero <scabr...@samba.org>
Date:   Tue Dec 12 21:17:50 2023 +0100

    tests: Add a test for the idmap_nss : use_upn setting
    
    Signed-off-by: Samuel Cabrero <scabr...@samba.org>
    Reviewed-by: Alexander Bokovoy <a...@samba.org>
    
    Autobuild-User(master): Samuel Cabrero <scabr...@samba.org>
    Autobuild-Date(master): Wed Dec 13 16:05:19 UTC 2023 on atb-devel-224

commit 086a90d52b0c4bd388bf5707159ae1a727f8e400
Author: Samuel Cabrero <scabr...@samba.org>
Date:   Tue Dec 12 16:02:33 2023 +0100

    idmap_nss: Install a messaging filter to reload the configuration
    
    Signed-off-by: Samuel Cabrero <scabr...@samba.org>
    Reviewed-by: Alexander Bokovoy <a...@samba.org>

commit a7a4d8e53332f8cae68462afab7dec86c991d96f
Author: Samuel Cabrero <scabr...@suse.de>
Date:   Mon Nov 27 08:05:29 2023 +0100

    idmap_nss: Add a parameter to use UPNs instead of plain names
    
    idmap config <DOMAIN> : backend = nss
    idmap config <DOMAIN> : use_upn = yes|no
    
    When translating a Unix ID to a SID the module calls get[pwu|grg]id() but 
the
    name returned by some NSS modules might be a UPN instead of a plain name. If
    the new parameter is enabled the returned name will be parsed and correctly
    handled.
    
    On the other hand, when translating a SID to a Unix ID the module first
    resolves the SID to a domain + name, and then calls get[pw|gr]name() with 
the
    plain name, or the UPN if the new parameter is enabled.
    
    Signed-off-by: Samuel Cabrero <scabr...@samba.org>
    Reviewed-by: Alexander Bokovoy <a...@samba.org>

commit c8e4777a921132082ee6421b2b456c82028fed46
Author: Samuel Cabrero <scabr...@samba.org>
Date:   Wed Nov 29 12:55:13 2023 +0100

    idmap_nss: Increase debug on failures
    
    Signed-off-by: Samuel Cabrero <scabr...@samba.org>
    Reviewed-by: Alexander Bokovoy <a...@samba.org>

commit de2f59c61a0549c54546704c07a1f41410fc50d7
Author: Samuel Cabrero <scabr...@suse.de>
Date:   Mon Nov 27 10:20:05 2023 +0100

    docs: Document idmap_nss "range" option
    
    Signed-off-by: Samuel Cabrero <scabr...@samba.org>
    Reviewed-by: Alexander Bokovoy <a...@samba.org>

commit 8e1f2ee5f7c5b3ee4edfa7beca289889a4e99cca
Author: Samuel Cabrero <scabr...@samba.org>
Date:   Tue Dec 12 15:55:20 2023 +0100

    s3:winbind: Register a messaging filter foreach domain child
    
    Instead of registering the "classic" callback for MSG_SMB_CONF_UPDATED,
    install a message filter to allow other parts of the code to also
    listen for this message because classic callbacks are delivered only
    once (see commit a2436b67e5dd47d955a3bea2b83e0693b627ab96).
    
    Signed-off-by: Samuel Cabrero <scabr...@samba.org>
    Reviewed-by: Alexander Bokovoy <a...@samba.org>

commit c35937054cd69580bbf5e3252fd9a1e8958f2f7b
Author: Samuel Cabrero <scabr...@samba.org>
Date:   Tue Dec 12 15:49:07 2023 +0100

    s3:winbind: talloc the static locator child
    
    Next commits will use talloc_get_type_abort() to get the reference.
    
    Signed-off-by: Samuel Cabrero <scabr...@samba.org>
    Reviewed-by: Alexander Bokovoy <a...@samba.org>

commit e3d0574d7969b00723a6b3041a796dd4f29726e8
Author: Samuel Cabrero <scabr...@samba.org>
Date:   Tue Dec 12 15:44:21 2023 +0100

    s3:winbind: talloc the static idmap child
    
    Next commits will use talloc_get_type_abort() to get the reference.
    
    Signed-off-by: Samuel Cabrero <scabr...@samba.org>
    Reviewed-by: Alexander Bokovoy <a...@samba.org>

-----------------------------------------------------------------------

Summary of changes:
 docs-xml/manpages/idmap_nss.8.xml        |  38 +++++
 nsswitch/tests/test_idmap_nss_use_upn.sh |  79 ++++++++++
 source3/selftest/tests.py                |   4 +-
 source3/winbindd/idmap_nss.c             | 249 +++++++++++++++++++++++++++++--
 source3/winbindd/winbindd.c              |  13 +-
 source3/winbindd/winbindd_dual.c         |  34 +++--
 source3/winbindd/winbindd_idmap.c        |  29 ++--
 source3/winbindd/winbindd_locator.c      |  21 ++-
 source3/winbindd/winbindd_proto.h        |   4 +-
 9 files changed, 425 insertions(+), 46 deletions(-)
 create mode 100755 nsswitch/tests/test_idmap_nss_use_upn.sh


Changeset truncated at 500 lines:

diff --git a/docs-xml/manpages/idmap_nss.8.xml 
b/docs-xml/manpages/idmap_nss.8.xml
index fc03445df2c..a9c6eceedbc 100644
--- a/docs-xml/manpages/idmap_nss.8.xml
+++ b/docs-xml/manpages/idmap_nss.8.xml
@@ -27,6 +27,44 @@
        </para>
 </refsynopsisdiv>
 
+<refsect1>
+       <title>IDMAP OPTIONS</title>
+
+       <variablelist>
+               <varlistentry>
+               <term>range = low - high</term>
+               <listitem><para>
+                       Defines the available matching UID and GID range for 
which the
+                       backend is authoritative. Note that the range acts as a 
filter.
+                       Returned UIDs or GIDs by NSS modules that fall outside 
the range
+                       are ignored and the corresponding maps discarded. It is 
intended
+                       as a way to avoid accidental UID/GID overlaps between 
local and
+                       remotely defined IDs.
+               </para></listitem>
+               </varlistentry>
+
+               <varlistentry>
+               <term>use_upn = &lt;yes | no&gt;</term>
+               <listitem>
+               <para>
+                       Some NSS modules can return and handle UPNs and/or 
down-level
+                       logon names (e.g., DOMAIN\user or user@REALM).
+               </para>
+               <para>
+                       If this parameter is enabled the returned names from 
NSS will be
+                       parsed and the resulting namespace will be used as the 
authoritative
+                       namespace instead of the IDMAP domain name. Also, 
down-level logon
+                       names will be sent to NSS instead of the plain username 
to give NSS
+                       modules a hint about the user's correct domain.
+               </para>
+               <para>Default: no</para>
+               </listitem>
+               </varlistentry>
+
+       </variablelist>
+</refsect1>
+
+
 <refsect1>
        <title>EXAMPLES</title>
 
diff --git a/nsswitch/tests/test_idmap_nss_use_upn.sh 
b/nsswitch/tests/test_idmap_nss_use_upn.sh
new file mode 100755
index 00000000000..df2c67203d8
--- /dev/null
+++ b/nsswitch/tests/test_idmap_nss_use_upn.sh
@@ -0,0 +1,79 @@
+#!/bin/sh
+
+wbinfo="$BINDIR/wbinfo"
+smbcontrol="$BINDIR/smbcontrol"
+net="$BINDIR/net"
+global_inject_conf=$(dirname $SMB_CONF_PATH)/global_inject.conf
+
+failed=0
+
+. $(dirname $0)/../../testprogs/blackbox/subunit.sh
+
+# Reset idmap_nss configuration and clear cache
+echo "idmap config $DOMAIN : use_upn = no" >$global_inject_conf
+$smbcontrol winbindd reload-config
+if [ $? -ne 0 ]; then
+       echo "Could not reload config" | subunit_fail_test 
"test_idmap_nss_use_upn"
+fi
+
+$net cache flush
+if [ $? -ne 0 ]; then
+       echo "Could not flush cache" | subunit_fail_test 
"test_idmap_nss_use_upn"
+fi
+
+# Get the user SID
+USER="bob"
+USER_SID=$($wbinfo --name-to-sid="$USER")
+if [ $? -ne 0 ]; then
+       echo "Could not find SID for user '$USER'" | subunit_fail_test 
"test_idmap_nss_use_upn"
+       exit 1
+fi
+
+USER_SID=$(echo $USER_SID | cut -d " " -f 1)
+if [ $? -ne 0 ]; then
+       echo "Could not find SID for user '$USER'" | subunit_fail_test 
"test_idmap_nss_use_upn"
+       exit 1
+fi
+
+testit "SID to UID (use_upn = no)" $wbinfo --sid-to-uid=${USER_SID} || 
failed=$(expr $failed + 1)
+
+echo "idmap config $DOMAIN : use_upn = yes" >$global_inject_conf
+$smbcontrol winbindd reload-config
+if [ $? -ne 0 ]; then
+       echo "Could not reload config" | subunit_fail_test 
"test_idmap_nss_use_upn"
+fi
+
+$net cache flush
+if [ $? -ne 0 ]; then
+       echo "Could not flush cache" | subunit_fail_test 
"test_idmap_nss_use_upn"
+fi
+
+# The following test will fail because idmap_nss will search ADDOMAIN/bob, 
which does not
+# exists in NSS_WRAPPER_PASSWD
+testit_expect_failure "SID to UID (use_upn = yes)" $wbinfo 
--sid-to-uid=${USER_SID} || failed=$(expr $failed + 1)
+
+$net cache flush
+if [ $? -ne 0 ]; then
+       echo "Could not flush cache" | subunit_fail_test 
"test_idmap_nss_use_upn"
+fi
+
+# Add the ADDOMAIN/bob temporarily
+ENTRY="$(getent passwd bob)"
+ENTRY="$DOMAIN/${ENTRY}"
+sed -i "1i ${ENTRY}" $NSS_WRAPPER_PASSWD
+testit "Get user UID (use_upn = yes)" $wbinfo --sid-to-uid=${USER_SID} || 
failed=$(expr $failed + 1)
+sed -i "1d" $NSS_WRAPPER_PASSWD
+
+# Reset config
+echo "idmap config $DOMAIN : use_upn = no" >$global_inject_conf
+$smbcontrol winbindd reload-config
+if [ $? -ne 0 ]; then
+       echo "Could not reload config" | subunit_fail_test 
"test_idmap_nss_use_upn"
+fi
+
+$net cache flush
+if [ $? -ne 0 ]; then
+       echo "Could not flush cache" | subunit_fail_test 
"test_idmap_nss_use_upn"
+fi
+
+exit $failed
diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index 30740d66dcf..679ff4e9916 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -1106,7 +1106,7 @@ rpc = ["rpc.authcontext",
 
 local = ["local.nss"]
 
-idmap = ["idmap.rfc2307", "idmap.alloc", "idmap.rid", "idmap.ad"]
+idmap = ["idmap.rfc2307", "idmap.alloc", "idmap.rid", "idmap.ad", "idmap.nss"]
 
 rap = ["rap.basic", "rap.rpc", "rap.printing", "rap.sam"]
 
@@ -1217,6 +1217,8 @@ for t in tests:
                        '$DC_SERVER', '$DC_USERNAME', '$DC_PASSWORD'])
     elif t == "idmap.alloc":
         plantestsuite(t, "ad_member_rfc2307", [os.path.join(samba3srcdir, 
"../nsswitch/tests/test_idmap_nss.sh"), '$DOMAIN'])
+    elif t == "idmap.nss":
+        plantestsuite(t, "ad_member_idmap_nss:local", 
[os.path.join(samba3srcdir, "../nsswitch/tests/test_idmap_nss_use_upn.sh")])
     elif t == "idmap.rid":
         plantestsuite(t, "ad_member_idmap_rid", [os.path.join(samba3srcdir, 
"../nsswitch/tests/test_idmap_rid.sh"), '$DOMAIN', '2000000'])
         plantestsuite(t,
diff --git a/source3/winbindd/idmap_nss.c b/source3/winbindd/idmap_nss.c
index 642d5141784..0af25362219 100644
--- a/source3/winbindd/idmap_nss.c
+++ b/source3/winbindd/idmap_nss.c
@@ -1,4 +1,4 @@
-/* 
+/*
    Unix SMB/CIFS implementation.
 
    idmap NSS backend
@@ -26,16 +26,150 @@
 #include "idmap.h"
 #include "lib/winbind_util.h"
 #include "libcli/security/dom_sid.h"
+#include "lib/global_contexts.h"
+#include "messages.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_IDMAP
 
+struct idmap_nss_context {
+       struct idmap_domain *dom;
+       bool use_upn;
+};
+
+static int idmap_nss_context_destructor(struct idmap_nss_context *ctx)
+{
+       if ((ctx->dom != NULL) && (ctx->dom->private_data == ctx)) {
+               ctx->dom->private_data = NULL;
+       }
+       return 0;
+}
+
+static NTSTATUS idmap_nss_context_create(TALLOC_CTX *mem_ctx,
+                                        struct idmap_domain *dom,
+                                        struct idmap_nss_context **pctx)
+{
+       struct idmap_nss_context *ctx = NULL;
+
+       ctx = talloc_zero(mem_ctx, struct idmap_nss_context);
+       if (ctx == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       ctx->dom = dom;
+
+       talloc_set_destructor(ctx, idmap_nss_context_destructor);
+
+       ctx->use_upn = idmap_config_bool(dom->name, "use_upn", false);
+
+       *pctx = ctx;
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS idmap_nss_get_context(struct idmap_domain *dom,
+                                     struct idmap_nss_context **pctx)
+{
+       struct idmap_nss_context *ctx = NULL;
+       NTSTATUS status;
+
+       if (dom->private_data != NULL) {
+               *pctx = talloc_get_type_abort(dom->private_data,
+                                             struct idmap_nss_context);
+               return NT_STATUS_OK;
+       }
+
+       status = idmap_nss_context_create(dom, dom, &ctx);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_WARNING("idmap_nss_context_create failed: %s\n",
+                           nt_errstr(status));
+               return status;
+       }
+
+       dom->private_data = ctx;
+       *pctx = ctx;
+       return NT_STATUS_OK;
+}
+
+static bool idmap_nss_msg_filter(struct messaging_rec *rec, void *private_data)
+{
+       struct idmap_domain *dom = talloc_get_type_abort(private_data,
+                      struct idmap_domain);
+       struct idmap_nss_context *ctx = NULL;
+       NTSTATUS status;
+       bool ret;
+
+       if (rec->msg_type == MSG_SMB_CONF_UPDATED) {
+               ret = lp_load_global(get_dyn_CONFIGFILE());
+               if (!ret) {
+                       DBG_WARNING("Failed to reload configuration\n");
+                       return false;
+               }
+
+               status = idmap_nss_get_context(dom, &ctx);
+               if (NT_STATUS_IS_ERR(status)) {
+                       DBG_WARNING("Failed to get idmap nss context: %s\n",
+                                       nt_errstr(status));
+                       return false;
+               }
+
+               ctx->use_upn = idmap_config_bool(dom->name, "use_upn", false);
+       }
+
+       return false;
+}
+
 /*****************************
  Initialise idmap database.
 *****************************/
 
 static NTSTATUS idmap_nss_int_init(struct idmap_domain *dom)
 {
+       struct idmap_nss_context *ctx = NULL;
+       NTSTATUS status;
+       struct messaging_context *msg_ctx = global_messaging_context();
+       struct tevent_req *req = NULL;
+
+       status = idmap_nss_context_create(dom, dom, &ctx);
+       if (NT_STATUS_IS_ERR(status)) {
+               return status;
+       }
+
+       dom->private_data = ctx;
+
+       req = messaging_filtered_read_send(
+                       dom,
+                       messaging_tevent_context(msg_ctx),
+                       msg_ctx,
+                       idmap_nss_msg_filter,
+                       dom);
+       if (req == NULL) {
+               DBG_WARNING("messaging_filtered_read_send failed\n");
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       return status;
+}
+
+static NTSTATUS idmap_nss_lookup_name(const char *namespace,
+                                     const char *username,
+                                     struct dom_sid *sid,
+                                     enum lsa_SidType *type)
+{
+       bool ret;
+
+       /*
+        * By default calls to winbindd are disabled
+        * the following call will not recurse so this is safe
+        */
+       (void)winbind_on();
+       ret = winbind_lookup_name(namespace, username, sid, type);
+       (void)winbind_off();
+
+       if (!ret) {
+               DBG_NOTICE("Failed to lookup name [%s] in namespace [%s]\n",
+                          username, namespace);
+               return NT_STATUS_NOT_FOUND;
+       }
+
        return NT_STATUS_OK;
 }
 
@@ -45,8 +179,17 @@ static NTSTATUS idmap_nss_int_init(struct idmap_domain *dom)
 
 static NTSTATUS idmap_nss_unixids_to_sids(struct idmap_domain *dom, struct 
id_map **ids)
 {
+       struct idmap_nss_context *ctx = NULL;
+       NTSTATUS status;
        int i;
 
+       status = idmap_nss_get_context(dom, &ctx);
+       if (NT_STATUS_IS_ERR(status)) {
+               DBG_WARNING("Failed to get idmap nss context: %s\n",
+                           nt_errstr(status));
+               return status;
+       }
+
        /* initialize the status to avoid surprise */
        for (i = 0; ids[i]; i++) {
                ids[i]->status = ID_UNKNOWN;
@@ -58,42 +201,89 @@ static NTSTATUS idmap_nss_unixids_to_sids(struct 
idmap_domain *dom, struct id_ma
                const char *name;
                struct dom_sid sid;
                enum lsa_SidType type;
-               bool ret;
 
                switch (ids[i]->xid.type) {
                case ID_TYPE_UID:
+                       errno = 0;
                        pw = getpwuid((uid_t)ids[i]->xid.id);
-
                        if (!pw) {
+                               DBG_DEBUG("getpwuid(%lu) failed: %s\n",
+                                         (unsigned long)ids[i]->xid.id,
+                                         errno != 0
+                                         ? strerror(errno)
+                                         : "not found");
                                ids[i]->status = ID_UNMAPPED;
                                continue;
                        }
                        name = pw->pw_name;
                        break;
                case ID_TYPE_GID:
+                       errno = 0;
                        gr = getgrgid((gid_t)ids[i]->xid.id);
-
                        if (!gr) {
+                               DBG_DEBUG("getgrgid(%lu) failed: %s\n",
+                                         (unsigned long)ids[i]->xid.id,
+                                         errno != 0
+                                         ? strerror(errno)
+                                         : "not found");
                                ids[i]->status = ID_UNMAPPED;
                                continue;
                        }
                        name = gr->gr_name;
                        break;
                default: /* ?? */
+                       DBG_WARNING("Unexpected xid type %d\n",
+                                   ids[i]->xid.type);
                        ids[i]->status = ID_UNKNOWN;
                        continue;
                }
 
-               /* by default calls to winbindd are disabled
-                  the following call will not recurse so this is safe */
-               (void)winbind_on();
                /* Lookup name from PDC using lsa_lookup_names() */
-               ret = winbind_lookup_name(dom->name, name, &sid, &type);
-               (void)winbind_off();
+               if (ctx->use_upn) {
+                       char *p = NULL;
+                       const char *namespace = NULL;
+                       const char *domname = NULL;
+                       const char *domuser = NULL;
+
+                       p = strstr(name, lp_winbind_separator());
+                       if (p != NULL) {
+                               *p = '\0';
+                               domname = name;
+                               namespace = domname;
+                               domuser = p + 1;
+                       } else {
+                               p = strchr(name, '@');
+                               if (p != NULL) {
+                                       *p = '\0';
+                                       namespace = p + 1;
+                                       domname = "";
+                                       domuser = name;
+                               } else {
+                                       namespace = dom->name;
+                                       domuser = name;
+                               }
+                       }
 
-               if (!ret) {
-                       /* TODO: how do we know if the name is really not 
mapped,
-                        * or something just failed ? */
+                       DBG_DEBUG("Using namespace [%s] from UPN instead "
+                                 "of [%s] to lookup the name [%s]\n",
+                                 namespace, dom->name, domuser);
+
+                       status = idmap_nss_lookup_name(namespace,
+                                                      domuser,
+                                                      &sid,
+                                                      &type);
+               } else {
+                       status = idmap_nss_lookup_name(dom->name,
+                                                      name,
+                                                      &sid,
+                                                      &type);
+                }
+
+               if (NT_STATUS_IS_ERR(status)) {
+                       /*
+                        * TODO: how do we know if the name is really
+                        * not mapped, or something just failed ?
+                        */
                        ids[i]->status = ID_UNMAPPED;
                        continue;
                }
@@ -129,8 +319,17 @@ static NTSTATUS idmap_nss_unixids_to_sids(struct 
idmap_domain *dom, struct id_ma
 
 static NTSTATUS idmap_nss_sids_to_unixids(struct idmap_domain *dom, struct 
id_map **ids)
 {
+       struct idmap_nss_context *ctx = NULL;
+       NTSTATUS status;
        int i;
 
+       status = idmap_nss_get_context(dom, &ctx);
+       if (NT_STATUS_IS_ERR(status)) {
+               DBG_WARNING("Failed to get idmap nss context: %s\n",
+                           nt_errstr(status));
+               return status;
+       }
+
        /* initialize the status to avoid surprise */
        for (i = 0; ids[i]; i++) {
                ids[i]->status = ID_UNKNOWN;
@@ -143,6 +342,8 @@ static NTSTATUS idmap_nss_sids_to_unixids(struct 
idmap_domain *dom, struct id_ma
                const char *_name = NULL;
                char *domain = NULL;
                char *name = NULL;
+               char *fqdn = NULL;
+               char *sname = NULL;
                bool ret;
 
                /* by default calls to winbindd are disabled
@@ -173,13 +374,30 @@ static NTSTATUS idmap_nss_sids_to_unixids(struct 
idmap_domain *dom, struct id_ma
                        continue;
                }
 
+               if (ctx->use_upn) {
+                       fqdn = talloc_asprintf(talloc_tos(),
+                                              "%s%s%s",
+                                              domain,
+                                              lp_winbind_separator(),
+                                              name);
+                       if (fqdn == NULL) {
+                               DBG_ERR("No memory\n");
+                               ids[i]->status = ID_UNMAPPED;
+                               continue;
+                       }
+                       DBG_DEBUG("Using UPN [%s] instead of plain name [%s]\n",
+                                 fqdn, name);
+                       sname = fqdn;
+               } else {
+                       sname = name;
+               }
+
                switch (type) {
                case SID_NAME_USER: {
                        struct passwd *pw;
 
                        /* this will find also all lower case name and use 
username level */
-
-                       pw = Get_Pwnam_alloc(talloc_tos(), name);
+                       pw = Get_Pwnam_alloc(talloc_tos(), sname);
                        if (pw) {
                                ids[i]->xid.id = pw->pw_uid;
                                ids[i]->xid.type = ID_TYPE_UID;
@@ -193,7 +411,7 @@ static NTSTATUS idmap_nss_sids_to_unixids(struct 
idmap_domain *dom, struct id_ma
                case SID_NAME_ALIAS:
                case SID_NAME_WKN_GRP:
 


-- 
Samba Shared Repository

Reply via email to