1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00

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 <scabrero@samba.org>
Reviewed-by: Alexander Bokovoy <ab@samba.org>
This commit is contained in:
Samuel Cabrero 2023-11-27 08:05:29 +01:00 committed by Samuel Cabrero
parent c8e4777a92
commit a7a4d8e533
2 changed files with 197 additions and 14 deletions

View File

@ -42,6 +42,25 @@
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>
@ -76,4 +95,4 @@
</para>
</refsect1>
</refentry>
</refentry>

View File

@ -1,4 +1,4 @@
/*
/*
Unix SMB/CIFS implementation.
idmap NSS backend
@ -30,12 +30,103 @@
#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;
}
/*****************************
Initialise idmap database.
*****************************/
static NTSTATUS idmap_nss_int_init(struct idmap_domain *dom)
{
struct idmap_nss_context *ctx = NULL;
NTSTATUS status;
status = idmap_nss_context_create(dom, dom, &ctx);
if (NT_STATUS_IS_ERR(status)) {
return status;
}
dom->private_data = ctx;
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 +136,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,7 +158,6 @@ 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:
@ -96,16 +195,52 @@ static NTSTATUS idmap_nss_unixids_to_sids(struct idmap_domain *dom, struct id_ma
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;
if (!ret) {
/* TODO: how do we know if the name is really not mapped,
* or something just failed ? */
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;
}
}
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;
}
@ -141,8 +276,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;
@ -155,6 +299,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
@ -185,13 +331,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;
@ -205,7 +368,7 @@ static NTSTATUS idmap_nss_sids_to_unixids(struct idmap_domain *dom, struct id_ma
case SID_NAME_ALIAS:
case SID_NAME_WKN_GRP:
gr = getgrnam(name);
gr = getgrnam(sname);
if (gr) {
ids[i]->xid.id = gr->gr_gid;
ids[i]->xid.type = ID_TYPE_GID;
@ -219,6 +382,7 @@ static NTSTATUS idmap_nss_sids_to_unixids(struct idmap_domain *dom, struct id_ma
}
TALLOC_FREE(domain);
TALLOC_FREE(name);
TALLOC_FREE(fqdn);
}
return NT_STATUS_OK;
}