1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-24 21:34:56 +03:00

Fix bug 327 (again and I think for the last time). Make sure that

pam_smbpass.so will load ok.  Had to move some functions around to work
around dependency problems (hence the new passdb/lookup_sid.c)

Also make sure that libsmbclient.a is built and installed when
we support shared libraries.
(This used to be commit 780055f442)
This commit is contained in:
Gerald Carter 2003-08-27 20:52:56 +00:00
parent 2f70d0d9a7
commit c2983f9323
4 changed files with 493 additions and 467 deletions

View File

@ -282,7 +282,7 @@ PASSDB_GET_SET_OBJ = passdb/pdb_get_set.o
PASSDB_OBJ = $(PASSDB_GET_SET_OBJ) passdb/passdb.o passdb/pdb_interface.o \
passdb/machine_sid.o passdb/util_sam_sid.o passdb/pdb_compat.o \
passdb/privileges.o @PDB_STATIC@
passdb/privileges.o passdb/lookup_sid.o @PDB_STATIC@
XML_OBJ = passdb/pdb_xml.o
MYSQL_OBJ = passdb/pdb_mysql.o
@ -583,9 +583,8 @@ LIBSMBCLIENT_PICOBJS = $(LIBSMBCLIENT_OBJ:.o=.po)
PAM_SMBPASS_OBJ_0 = pam_smbpass/pam_smb_auth.o pam_smbpass/pam_smb_passwd.o \
pam_smbpass/pam_smb_acct.o pam_smbpass/support.o \
libsmb/smbencrypt.o libsmb/smbdes.o libsmb/nterr.o lib/dummyroot.o \
$(PARAM_OBJ) $(LIB_OBJ) $(PASSDB_OBJ) $(GROUPDB_OBJ) \
$(SECRETS_OBJ) $(UBIQX_OBJ) $(SMBLDAP_OBJ)
lib/dummyroot.o $(PARAM_OBJ) $(LIB_OBJ) $(PASSDB_OBJ) $(GROUPDB_OBJ) \
$(SECRETS_OBJ) $(UBIQX_OBJ) $(SMBLDAP_OBJ) $(LIBSAMBA_OBJ)
PAM_SMBPASS_PICOOBJ = $(PAM_SMBPASS_OBJ_0:.o=.po)

View File

@ -3178,6 +3178,8 @@ AC_ARG_WITH(libsmbclient,
*)
if test $BLDSHARED = true; then
INSTALLCLIENTCMD_SH="\$(INSTALLCMD)"
## build the static version of libsmbclient as well
INSTALLCLIENTCMD_A="\$(INSTALLCMD)"
LIBSMBCLIENT_SHARED=bin/libsmbclient.$SHLIBEXT
LIBSMBCLIENT=libsmbclient
AC_MSG_RESULT(yes)

488
source3/passdb/lookup_sid.c Normal file
View File

@ -0,0 +1,488 @@
/*
Unix SMB/CIFS implementation.
uid/user handling
Copyright (C) Andrew Tridgell 1992-1998
Copyright (C) Gerald (Jerry) Carter 2003
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
/*****************************************************************
*THE CANONICAL* convert name to SID function.
Tries local lookup first - for local domains - then uses winbind.
*****************************************************************/
BOOL lookup_name(const char *domain, const char *name, DOM_SID *psid, enum SID_NAME_USE *name_type)
{
fstring sid;
BOOL local_lookup = False;
*name_type = SID_NAME_UNKNOWN;
/* If we are looking up a domain user, make sure it is
for the local machine only */
if (strequal(global_myname(), domain)) {
local_lookup = True;
} else if (lp_server_role() == ROLE_DOMAIN_PDC ||
lp_server_role() == ROLE_DOMAIN_BDC) {
if (strequal(domain, lp_workgroup())) {
local_lookup = True;
}
}
if (local_lookup) {
if (local_lookup_name(name, psid, name_type)) {
DEBUG(10,
("lookup_name: (local) [%s]\\[%s] -> SID %s (type %s: %u)\n",
domain, name, sid_to_string(sid,psid),
sid_type_lookup(*name_type), (unsigned int)*name_type));
return True;
}
} else {
/* Remote */
if (winbind_lookup_name(domain, name, psid, name_type)) {
DEBUG(10,("lookup_name (winbindd): [%s]\\[%s] -> SID %s (type %u)\n",
domain, name, sid_to_string(sid, psid),
(unsigned int)*name_type));
return True;
}
}
DEBUG(10, ("lookup_name: %s lookup for [%s]\\[%s] failed\n",
local_lookup ? "local" : "winbind", domain, name));
return False;
}
/*****************************************************************
*THE CANONICAL* convert SID to name function.
Tries local lookup first - for local sids, then tries winbind.
*****************************************************************/
BOOL lookup_sid(DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAME_USE *name_type)
{
if (!name_type)
return False;
*name_type = SID_NAME_UNKNOWN;
/* Check if this is our own sid. This should perhaps be done by
winbind? For the moment handle it here. */
if (sid->num_auths == 5) {
DOM_SID tmp_sid;
uint32 rid;
sid_copy(&tmp_sid, sid);
sid_split_rid(&tmp_sid, &rid);
if (sid_equal(get_global_sam_sid(), &tmp_sid)) {
return map_domain_sid_to_name(&tmp_sid, dom_name) &&
local_lookup_sid(sid, name, name_type);
}
}
if (!winbind_lookup_sid(sid, dom_name, name, name_type)) {
fstring sid_str;
DOM_SID tmp_sid;
uint32 rid;
DEBUG(10,("lookup_sid: winbind lookup for SID %s failed - trying local.\n", sid_to_string(sid_str, sid) ));
sid_copy(&tmp_sid, sid);
sid_split_rid(&tmp_sid, &rid);
return map_domain_sid_to_name(&tmp_sid, dom_name) &&
lookup_known_rid(&tmp_sid, rid, name, name_type);
}
return True;
}
/*****************************************************************
Id mapping cache. This is to avoid Winbind mappings already
seen by smbd to be queried too frequently, keeping winbindd
busy, and blocking smbd while winbindd is busy with other
stuff. Written by Michael Steffens <michael.steffens@hp.com>,
modified to use linked lists by jra.
*****************************************************************/
#define MAX_UID_SID_CACHE_SIZE 100
#define TURNOVER_UID_SID_CACHE_SIZE 10
#define MAX_GID_SID_CACHE_SIZE 100
#define TURNOVER_GID_SID_CACHE_SIZE 10
static size_t n_uid_sid_cache = 0;
static size_t n_gid_sid_cache = 0;
static struct uid_sid_cache {
struct uid_sid_cache *next, *prev;
uid_t uid;
DOM_SID sid;
enum SID_NAME_USE sidtype;
} *uid_sid_cache_head;
static struct gid_sid_cache {
struct gid_sid_cache *next, *prev;
gid_t gid;
DOM_SID sid;
enum SID_NAME_USE sidtype;
} *gid_sid_cache_head;
/*****************************************************************
Find a SID given a uid.
*****************************************************************/
static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
{
struct uid_sid_cache *pc;
for (pc = uid_sid_cache_head; pc; pc = pc->next) {
if (pc->uid == uid) {
fstring sid;
*psid = pc->sid;
DEBUG(3,("fetch sid from uid cache %u -> %s\n",
(unsigned int)uid, sid_to_string(sid, psid)));
DLIST_PROMOTE(uid_sid_cache_head, pc);
return True;
}
}
return False;
}
/*****************************************************************
Find a uid given a SID.
*****************************************************************/
static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
{
struct uid_sid_cache *pc;
for (pc = uid_sid_cache_head; pc; pc = pc->next) {
if (sid_compare(&pc->sid, psid) == 0) {
fstring sid;
*puid = pc->uid;
DEBUG(3,("fetch uid from cache %u -> %s\n",
(unsigned int)*puid, sid_to_string(sid, psid)));
DLIST_PROMOTE(uid_sid_cache_head, pc);
return True;
}
}
return False;
}
/*****************************************************************
Store uid to SID mapping in cache.
*****************************************************************/
static void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
{
struct uid_sid_cache *pc;
if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
/* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
struct uid_sid_cache *pc_next;
size_t i;
for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
;
for(; pc; pc = pc_next) {
pc_next = pc->next;
DLIST_REMOVE(uid_sid_cache_head,pc);
SAFE_FREE(pc);
n_uid_sid_cache--;
}
}
pc = (struct uid_sid_cache *)malloc(sizeof(struct uid_sid_cache));
if (!pc)
return;
pc->uid = uid;
sid_copy(&pc->sid, psid);
DLIST_ADD(uid_sid_cache_head, pc);
n_uid_sid_cache++;
}
/*****************************************************************
Find a SID given a gid.
*****************************************************************/
static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
{
struct gid_sid_cache *pc;
for (pc = gid_sid_cache_head; pc; pc = pc->next) {
if (pc->gid == gid) {
fstring sid;
*psid = pc->sid;
DEBUG(3,("fetch sid from gid cache %u -> %s\n",
(unsigned int)gid, sid_to_string(sid, psid)));
DLIST_PROMOTE(gid_sid_cache_head, pc);
return True;
}
}
return False;
}
/*****************************************************************
Find a gid given a SID.
*****************************************************************/
static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
{
struct gid_sid_cache *pc;
for (pc = gid_sid_cache_head; pc; pc = pc->next) {
if (sid_compare(&pc->sid, psid) == 0) {
fstring sid;
*pgid = pc->gid;
DEBUG(3,("fetch uid from cache %u -> %s\n",
(unsigned int)*pgid, sid_to_string(sid, psid)));
DLIST_PROMOTE(gid_sid_cache_head, pc);
return True;
}
}
return False;
}
/*****************************************************************
Store gid to SID mapping in cache.
*****************************************************************/
static void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
{
struct gid_sid_cache *pc;
if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
/* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
struct gid_sid_cache *pc_next;
size_t i;
for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
;
for(; pc; pc = pc_next) {
pc_next = pc->next;
DLIST_REMOVE(gid_sid_cache_head,pc);
SAFE_FREE(pc);
n_gid_sid_cache--;
}
}
pc = (struct gid_sid_cache *)malloc(sizeof(struct gid_sid_cache));
if (!pc)
return;
pc->gid = gid;
sid_copy(&pc->sid, psid);
DLIST_ADD(gid_sid_cache_head, pc);
n_gid_sid_cache++;
}
/*****************************************************************
*THE CANONICAL* convert uid_t to SID function.
*****************************************************************/
NTSTATUS uid_to_sid(DOM_SID *psid, uid_t uid)
{
uid_t low, high;
fstring sid;
ZERO_STRUCTP(psid);
if (fetch_sid_from_uid_cache(psid, uid))
return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
if (lp_idmap_uid(&low, &high) && uid >= low && uid <= high) {
if (winbind_uid_to_sid(psid, uid)) {
DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
(unsigned int)uid, sid_to_string(sid, psid)));
if (psid)
store_uid_sid_cache(psid, uid);
return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
}
}
if (!local_uid_to_sid(psid, uid)) {
DEBUG(10,("uid_to_sid: local %u failed to map to sid\n", (unsigned int)uid ));
return NT_STATUS_UNSUCCESSFUL;
}
DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid, sid_to_string(sid, psid)));
store_uid_sid_cache(psid, uid);
return NT_STATUS_OK;
}
/*****************************************************************
*THE CANONICAL* convert gid_t to SID function.
*****************************************************************/
NTSTATUS gid_to_sid(DOM_SID *psid, gid_t gid)
{
gid_t low, high;
fstring sid;
ZERO_STRUCTP(psid);
if (fetch_sid_from_gid_cache(psid, gid))
return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
if (lp_idmap_gid(&low, &high) && gid >= low && gid <= high) {
if (winbind_gid_to_sid(psid, gid)) {
DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
(unsigned int)gid, sid_to_string(sid, psid)));
if (psid)
store_gid_sid_cache(psid, gid);
return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
}
}
if (!local_gid_to_sid(psid, gid)) {
DEBUG(10,("gid_to_sid: local %u failed to map to sid\n", (unsigned int)gid ));
return NT_STATUS_UNSUCCESSFUL;
}
DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid, sid_to_string(sid, psid)));
store_gid_sid_cache(psid, gid);
return NT_STATUS_OK;
}
/*****************************************************************
*THE CANONICAL* convert SID to uid function.
*****************************************************************/
NTSTATUS sid_to_uid(const DOM_SID *psid, uid_t *puid)
{
fstring dom_name, name, sid_str;
enum SID_NAME_USE name_type;
if (fetch_uid_from_cache(puid, psid))
return NT_STATUS_OK;
/* if this is our SID then go straight to a local lookup */
if ( sid_compare_domain(get_global_sam_sid(), psid) == 0 ) {
DEBUG(10,("sid_to_uid: my domain (%s) - trying local.\n",
sid_string_static(psid) ));
if ( local_sid_to_uid(puid, psid, &name_type) )
goto success;
DEBUG(10,("sid_to_uid: local lookup failed\n"));
return NT_STATUS_UNSUCCESSFUL;
}
/* If it is not our local domain, only hope is winbindd */
if ( !winbind_lookup_sid(psid, dom_name, name, &name_type) ) {
DEBUG(10,("sid_to_uid: winbind lookup for non-local sid %s failed\n",
sid_string_static(psid) ));
return NT_STATUS_UNSUCCESSFUL;
}
/* If winbindd does know the SID, ensure this is a user */
if (name_type != SID_NAME_USER) {
DEBUG(10,("sid_to_uid: winbind lookup succeeded but SID is not a user (%u)\n",
(unsigned int)name_type ));
return NT_STATUS_INVALID_PARAMETER;
}
/* get the uid. Has to work or else we are dead in the water */
if ( !winbind_sid_to_uid(puid, psid) ) {
DEBUG(10,("sid_to_uid: winbind failed to allocate a new uid for sid %s\n",
sid_to_string(sid_str, psid) ));
return NT_STATUS_UNSUCCESSFUL;
}
success:
DEBUG(10,("sid_to_uid: %s -> %u\n", sid_to_string(sid_str, psid),
(unsigned int)*puid ));
store_uid_sid_cache(psid, *puid);
return NT_STATUS_OK;
}
/*****************************************************************
*THE CANONICAL* convert SID to gid function.
Group mapping is used for gids that maps to Wellknown SIDs
*****************************************************************/
NTSTATUS sid_to_gid(const DOM_SID *psid, gid_t *pgid)
{
fstring dom_name, name, sid_str;
enum SID_NAME_USE name_type;
if (fetch_gid_from_cache(pgid, psid))
return NT_STATUS_OK;
/*
* First we must look up the name and decide if this is a group sid.
* Group mapping can deal with foreign SIDs
*/
if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) {
DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed - trying local.\n",
sid_to_string(sid_str, psid) ));
if ( local_sid_to_gid(pgid, psid, &name_type) )
goto success;
DEBUG(10,("sid_to_gid: no one knows this SID\n"));
return NT_STATUS_UNSUCCESSFUL;
}
/* winbindd knows it; Ensure this is a group sid */
if ((name_type != SID_NAME_DOM_GRP) && (name_type != SID_NAME_ALIAS) && (name_type != SID_NAME_WKN_GRP)) {
DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is not a known group (%u)\n",
(unsigned int)name_type ));
/* winbindd is running and knows about this SID. Just the wrong type.
Don't fallback to a local lookup here */
return NT_STATUS_INVALID_PARAMETER;
}
/* winbindd knows it and it is a type of group; sid_to_gid must succeed
or we are dead in the water */
if ( !winbind_sid_to_gid(pgid, psid) ) {
DEBUG(10,("sid_to_uid: winbind failed to allocate a new gid for sid %s\n",
sid_to_string(sid_str, psid) ));
return NT_STATUS_UNSUCCESSFUL;
}
success:
DEBUG(10,("sid_to_gid: %s -> %u\n", sid_to_string(sid_str, psid),
(unsigned int)*pgid ));
store_gid_sid_cache(psid, *pgid);
return NT_STATUS_OK;
}

View File

@ -437,467 +437,4 @@ void add_supplementary_nt_login_groups(int *n_groups, gid_t **pp_groups, NT_USER
*pptok = new_tok;
}
/*****************************************************************
*THE CANONICAL* convert name to SID function.
Tries local lookup first - for local domains - then uses winbind.
*****************************************************************/
BOOL lookup_name(const char *domain, const char *name, DOM_SID *psid, enum SID_NAME_USE *name_type)
{
fstring sid;
BOOL local_lookup = False;
*name_type = SID_NAME_UNKNOWN;
/* If we are looking up a domain user, make sure it is
for the local machine only */
if (strequal(global_myname(), domain)) {
local_lookup = True;
} else if (lp_server_role() == ROLE_DOMAIN_PDC ||
lp_server_role() == ROLE_DOMAIN_BDC) {
if (strequal(domain, lp_workgroup())) {
local_lookup = True;
}
}
if (local_lookup) {
if (local_lookup_name(name, psid, name_type)) {
DEBUG(10,
("lookup_name: (local) [%s]\\[%s] -> SID %s (type %s: %u)\n",
domain, name, sid_to_string(sid,psid),
sid_type_lookup(*name_type), (unsigned int)*name_type));
return True;
}
} else {
/* Remote */
if (winbind_lookup_name(domain, name, psid, name_type)) {
DEBUG(10,("lookup_name (winbindd): [%s]\\[%s] -> SID %s (type %u)\n",
domain, name, sid_to_string(sid, psid),
(unsigned int)*name_type));
return True;
}
}
DEBUG(10, ("lookup_name: %s lookup for [%s]\\[%s] failed\n",
local_lookup ? "local" : "winbind", domain, name));
return False;
}
/*****************************************************************
*THE CANONICAL* convert SID to name function.
Tries local lookup first - for local sids, then tries winbind.
*****************************************************************/
BOOL lookup_sid(DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAME_USE *name_type)
{
if (!name_type)
return False;
*name_type = SID_NAME_UNKNOWN;
/* Check if this is our own sid. This should perhaps be done by
winbind? For the moment handle it here. */
if (sid->num_auths == 5) {
DOM_SID tmp_sid;
uint32 rid;
sid_copy(&tmp_sid, sid);
sid_split_rid(&tmp_sid, &rid);
if (sid_equal(get_global_sam_sid(), &tmp_sid)) {
return map_domain_sid_to_name(&tmp_sid, dom_name) &&
local_lookup_sid(sid, name, name_type);
}
}
if (!winbind_lookup_sid(sid, dom_name, name, name_type)) {
fstring sid_str;
DOM_SID tmp_sid;
uint32 rid;
DEBUG(10,("lookup_sid: winbind lookup for SID %s failed - trying local.\n", sid_to_string(sid_str, sid) ));
sid_copy(&tmp_sid, sid);
sid_split_rid(&tmp_sid, &rid);
return map_domain_sid_to_name(&tmp_sid, dom_name) &&
lookup_known_rid(&tmp_sid, rid, name, name_type);
}
return True;
}
/*****************************************************************
Id mapping cache. This is to avoid Winbind mappings already
seen by smbd to be queried too frequently, keeping winbindd
busy, and blocking smbd while winbindd is busy with other
stuff. Written by Michael Steffens <michael.steffens@hp.com>,
modified to use linked lists by jra.
*****************************************************************/
#define MAX_UID_SID_CACHE_SIZE 100
#define TURNOVER_UID_SID_CACHE_SIZE 10
#define MAX_GID_SID_CACHE_SIZE 100
#define TURNOVER_GID_SID_CACHE_SIZE 10
static size_t n_uid_sid_cache = 0;
static size_t n_gid_sid_cache = 0;
static struct uid_sid_cache {
struct uid_sid_cache *next, *prev;
uid_t uid;
DOM_SID sid;
enum SID_NAME_USE sidtype;
} *uid_sid_cache_head;
static struct gid_sid_cache {
struct gid_sid_cache *next, *prev;
gid_t gid;
DOM_SID sid;
enum SID_NAME_USE sidtype;
} *gid_sid_cache_head;
/*****************************************************************
Find a SID given a uid.
*****************************************************************/
static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
{
struct uid_sid_cache *pc;
for (pc = uid_sid_cache_head; pc; pc = pc->next) {
if (pc->uid == uid) {
fstring sid;
*psid = pc->sid;
DEBUG(3,("fetch sid from uid cache %u -> %s\n",
(unsigned int)uid, sid_to_string(sid, psid)));
DLIST_PROMOTE(uid_sid_cache_head, pc);
return True;
}
}
return False;
}
/*****************************************************************
Find a uid given a SID.
*****************************************************************/
static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
{
struct uid_sid_cache *pc;
for (pc = uid_sid_cache_head; pc; pc = pc->next) {
if (sid_compare(&pc->sid, psid) == 0) {
fstring sid;
*puid = pc->uid;
DEBUG(3,("fetch uid from cache %u -> %s\n",
(unsigned int)*puid, sid_to_string(sid, psid)));
DLIST_PROMOTE(uid_sid_cache_head, pc);
return True;
}
}
return False;
}
/*****************************************************************
Store uid to SID mapping in cache.
*****************************************************************/
static void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
{
struct uid_sid_cache *pc;
if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
/* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
struct uid_sid_cache *pc_next;
size_t i;
for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
;
for(; pc; pc = pc_next) {
pc_next = pc->next;
DLIST_REMOVE(uid_sid_cache_head,pc);
SAFE_FREE(pc);
n_uid_sid_cache--;
}
}
pc = (struct uid_sid_cache *)malloc(sizeof(struct uid_sid_cache));
if (!pc)
return;
pc->uid = uid;
sid_copy(&pc->sid, psid);
DLIST_ADD(uid_sid_cache_head, pc);
n_uid_sid_cache++;
}
/*****************************************************************
Find a SID given a gid.
*****************************************************************/
static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
{
struct gid_sid_cache *pc;
for (pc = gid_sid_cache_head; pc; pc = pc->next) {
if (pc->gid == gid) {
fstring sid;
*psid = pc->sid;
DEBUG(3,("fetch sid from gid cache %u -> %s\n",
(unsigned int)gid, sid_to_string(sid, psid)));
DLIST_PROMOTE(gid_sid_cache_head, pc);
return True;
}
}
return False;
}
/*****************************************************************
Find a gid given a SID.
*****************************************************************/
static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
{
struct gid_sid_cache *pc;
for (pc = gid_sid_cache_head; pc; pc = pc->next) {
if (sid_compare(&pc->sid, psid) == 0) {
fstring sid;
*pgid = pc->gid;
DEBUG(3,("fetch uid from cache %u -> %s\n",
(unsigned int)*pgid, sid_to_string(sid, psid)));
DLIST_PROMOTE(gid_sid_cache_head, pc);
return True;
}
}
return False;
}
/*****************************************************************
Store gid to SID mapping in cache.
*****************************************************************/
static void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
{
struct gid_sid_cache *pc;
if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
/* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
struct gid_sid_cache *pc_next;
size_t i;
for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
;
for(; pc; pc = pc_next) {
pc_next = pc->next;
DLIST_REMOVE(gid_sid_cache_head,pc);
SAFE_FREE(pc);
n_gid_sid_cache--;
}
}
pc = (struct gid_sid_cache *)malloc(sizeof(struct gid_sid_cache));
if (!pc)
return;
pc->gid = gid;
sid_copy(&pc->sid, psid);
DLIST_ADD(gid_sid_cache_head, pc);
n_gid_sid_cache++;
}
/*****************************************************************
*THE CANONICAL* convert uid_t to SID function.
*****************************************************************/
NTSTATUS uid_to_sid(DOM_SID *psid, uid_t uid)
{
uid_t low, high;
fstring sid;
ZERO_STRUCTP(psid);
if (fetch_sid_from_uid_cache(psid, uid))
return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
if (lp_idmap_uid(&low, &high) && uid >= low && uid <= high) {
if (winbind_uid_to_sid(psid, uid)) {
DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
(unsigned int)uid, sid_to_string(sid, psid)));
if (psid)
store_uid_sid_cache(psid, uid);
return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
}
}
if (!local_uid_to_sid(psid, uid)) {
DEBUG(10,("uid_to_sid: local %u failed to map to sid\n", (unsigned int)uid ));
return NT_STATUS_UNSUCCESSFUL;
}
DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid, sid_to_string(sid, psid)));
store_uid_sid_cache(psid, uid);
return NT_STATUS_OK;
}
/*****************************************************************
*THE CANONICAL* convert gid_t to SID function.
*****************************************************************/
NTSTATUS gid_to_sid(DOM_SID *psid, gid_t gid)
{
gid_t low, high;
fstring sid;
ZERO_STRUCTP(psid);
if (fetch_sid_from_gid_cache(psid, gid))
return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
if (lp_idmap_gid(&low, &high) && gid >= low && gid <= high) {
if (winbind_gid_to_sid(psid, gid)) {
DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
(unsigned int)gid, sid_to_string(sid, psid)));
if (psid)
store_gid_sid_cache(psid, gid);
return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
}
}
if (!local_gid_to_sid(psid, gid)) {
DEBUG(10,("gid_to_sid: local %u failed to map to sid\n", (unsigned int)gid ));
return NT_STATUS_UNSUCCESSFUL;
}
DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid, sid_to_string(sid, psid)));
store_gid_sid_cache(psid, gid);
return NT_STATUS_OK;
}
/*****************************************************************
*THE CANONICAL* convert SID to uid function.
*****************************************************************/
NTSTATUS sid_to_uid(const DOM_SID *psid, uid_t *puid)
{
fstring dom_name, name, sid_str;
enum SID_NAME_USE name_type;
if (fetch_uid_from_cache(puid, psid))
return NT_STATUS_OK;
/* if this is our SID then go straight to a local lookup */
if ( sid_compare_domain(get_global_sam_sid(), psid) == 0 ) {
DEBUG(10,("sid_to_uid: my domain (%s) - trying local.\n",
sid_string_static(psid) ));
if ( local_sid_to_uid(puid, psid, &name_type) )
goto success;
DEBUG(10,("sid_to_uid: local lookup failed\n"));
return NT_STATUS_UNSUCCESSFUL;
}
/* If it is not our local domain, only hope is winbindd */
if ( !winbind_lookup_sid(psid, dom_name, name, &name_type) ) {
DEBUG(10,("sid_to_uid: winbind lookup for non-local sid %s failed\n",
sid_string_static(psid) ));
return NT_STATUS_UNSUCCESSFUL;
}
/* If winbindd does know the SID, ensure this is a user */
if (name_type != SID_NAME_USER) {
DEBUG(10,("sid_to_uid: winbind lookup succeeded but SID is not a user (%u)\n",
(unsigned int)name_type ));
return NT_STATUS_INVALID_PARAMETER;
}
/* get the uid. Has to work or else we are dead in the water */
if ( !winbind_sid_to_uid(puid, psid) ) {
DEBUG(10,("sid_to_uid: winbind failed to allocate a new uid for sid %s\n",
sid_to_string(sid_str, psid) ));
return NT_STATUS_UNSUCCESSFUL;
}
success:
DEBUG(10,("sid_to_uid: %s -> %u\n", sid_to_string(sid_str, psid),
(unsigned int)*puid ));
store_uid_sid_cache(psid, *puid);
return NT_STATUS_OK;
}
/*****************************************************************
*THE CANONICAL* convert SID to gid function.
Group mapping is used for gids that maps to Wellknown SIDs
*****************************************************************/
NTSTATUS sid_to_gid(const DOM_SID *psid, gid_t *pgid)
{
fstring dom_name, name, sid_str;
enum SID_NAME_USE name_type;
if (fetch_gid_from_cache(pgid, psid))
return NT_STATUS_OK;
/*
* First we must look up the name and decide if this is a group sid.
* Group mapping can deal with foreign SIDs
*/
if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) {
DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed - trying local.\n",
sid_to_string(sid_str, psid) ));
if ( local_sid_to_gid(pgid, psid, &name_type) )
goto success;
DEBUG(10,("sid_to_gid: no one knows this SID\n"));
return NT_STATUS_UNSUCCESSFUL;
}
/* winbindd knows it; Ensure this is a group sid */
if ((name_type != SID_NAME_DOM_GRP) && (name_type != SID_NAME_ALIAS) && (name_type != SID_NAME_WKN_GRP)) {
DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is not a known group (%u)\n",
(unsigned int)name_type ));
/* winbindd is running and knows about this SID. Just the wrong type.
Don't fallback to a local lookup here */
return NT_STATUS_INVALID_PARAMETER;
}
/* winbindd knows it and it is a type of group; sid_to_gid must succeed
or we are dead in the water */
if ( !winbind_sid_to_gid(pgid, psid) ) {
DEBUG(10,("sid_to_uid: winbind failed to allocate a new gid for sid %s\n",
sid_to_string(sid_str, psid) ));
return NT_STATUS_UNSUCCESSFUL;
}
success:
DEBUG(10,("sid_to_gid: %s -> %u\n", sid_to_string(sid_str, psid),
(unsigned int)*pgid ));
store_gid_sid_cache(psid, *pgid);
return NT_STATUS_OK;
}