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:
parent
c8e4777a92
commit
a7a4d8e533
@ -42,6 +42,25 @@
|
||||
remotely defined IDs.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>use_upn = <yes | no></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>
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user