1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00
samba-mirror/source3/winbindd/idmap_nss.c
Stefan Metzmacher bfd093648b CVE-2020-25727: idmap_nss: verify that the name of the sid belongs to the configured domain
We already check the sid belongs to the domain, but checking the name
too feels better and make it easier to understand.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14901

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
2021-11-15 18:10:28 +00:00

228 lines
5.2 KiB
C

/*
Unix SMB/CIFS implementation.
idmap NSS backend
Copyright (C) Simo Sorce 2006
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "system/passwd.h"
#include "winbindd.h"
#include "nsswitch/winbind_client.h"
#include "idmap.h"
#include "lib/winbind_util.h"
#include "libcli/security/dom_sid.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_IDMAP
/*****************************
Initialise idmap database.
*****************************/
static NTSTATUS idmap_nss_int_init(struct idmap_domain *dom)
{
return NT_STATUS_OK;
}
/**********************************
lookup a set of unix ids.
**********************************/
static NTSTATUS idmap_nss_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
{
int i;
/* initialize the status to avoid suprise */
for (i = 0; ids[i]; i++) {
ids[i]->status = ID_UNKNOWN;
}
for (i = 0; ids[i]; i++) {
struct passwd *pw;
struct group *gr;
const char *name;
struct dom_sid sid;
enum lsa_SidType type;
bool ret;
switch (ids[i]->xid.type) {
case ID_TYPE_UID:
pw = getpwuid((uid_t)ids[i]->xid.id);
if (!pw) {
ids[i]->status = ID_UNMAPPED;
continue;
}
name = pw->pw_name;
break;
case ID_TYPE_GID:
gr = getgrgid((gid_t)ids[i]->xid.id);
if (!gr) {
ids[i]->status = ID_UNMAPPED;
continue;
}
name = gr->gr_name;
break;
default: /* ?? */
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 (!ret) {
/* TODO: how do we know if the name is really not mapped,
* or something just failed ? */
ids[i]->status = ID_UNMAPPED;
continue;
}
switch (type) {
case SID_NAME_USER:
if (ids[i]->xid.type == ID_TYPE_UID) {
sid_copy(ids[i]->sid, &sid);
ids[i]->status = ID_MAPPED;
}
break;
case SID_NAME_DOM_GRP:
case SID_NAME_ALIAS:
case SID_NAME_WKN_GRP:
if (ids[i]->xid.type == ID_TYPE_GID) {
sid_copy(ids[i]->sid, &sid);
ids[i]->status = ID_MAPPED;
}
break;
default:
ids[i]->status = ID_UNKNOWN;
break;
}
}
return NT_STATUS_OK;
}
/**********************************
lookup a set of sids.
**********************************/
static NTSTATUS idmap_nss_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
{
int i;
/* initialize the status to avoid suprise */
for (i = 0; ids[i]; i++) {
ids[i]->status = ID_UNKNOWN;
}
for (i = 0; ids[i]; i++) {
struct group *gr;
enum lsa_SidType type;
const char *_domain = NULL;
const char *_name = NULL;
char *domain = NULL;
char *name = NULL;
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_sid(talloc_tos(),
ids[i]->sid,
&_domain,
&_name,
&type);
(void)winbind_off();
if (!ret) {
/* TODO: how do we know if the name is really not mapped,
* or something just failed ? */
ids[i]->status = ID_UNMAPPED;
continue;
}
domain = discard_const_p(char, _domain);
name = discard_const_p(char, _name);
if (!strequal(domain, dom->name)) {
struct dom_sid_buf buf;
DBG_ERR("DOMAIN[%s] ignoring SID[%s] belongs to %s [%s\\%s]\n",
dom->name, dom_sid_str_buf(ids[i]->sid, &buf),
sid_type_lookup(type), domain, name);
ids[i]->status = ID_UNMAPPED;
continue;
}
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);
if (pw) {
ids[i]->xid.id = pw->pw_uid;
ids[i]->xid.type = ID_TYPE_UID;
ids[i]->status = ID_MAPPED;
}
TALLOC_FREE(pw);
break;
}
case SID_NAME_DOM_GRP:
case SID_NAME_ALIAS:
case SID_NAME_WKN_GRP:
gr = getgrnam(name);
if (gr) {
ids[i]->xid.id = gr->gr_gid;
ids[i]->xid.type = ID_TYPE_GID;
ids[i]->status = ID_MAPPED;
}
break;
default:
ids[i]->status = ID_UNKNOWN;
break;
}
TALLOC_FREE(domain);
TALLOC_FREE(name);
}
return NT_STATUS_OK;
}
/**********************************
Close the idmap tdb instance
**********************************/
static const struct idmap_methods nss_methods = {
.init = idmap_nss_int_init,
.unixids_to_sids = idmap_nss_unixids_to_sids,
.sids_to_unixids = idmap_nss_sids_to_unixids,
};
NTSTATUS idmap_nss_init(TALLOC_CTX *mem_ctx)
{
return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "nss", &nss_methods);
}