1
0
mirror of https://github.com/samba-team/samba.git synced 2025-12-02 00:23:50 +03:00

r20116: Start merging in the work done to create the new idmap subsystem.

Simo.
This commit is contained in:
Simo Sorce
2006-12-12 14:52:13 +00:00
committed by Gerald (Jerry) Carter
parent 67c4d5e73f
commit 50cd8bffee
42 changed files with 7075 additions and 4576 deletions

View File

@@ -283,7 +283,7 @@ LIBADS_OBJ = libads/ldap.o libads/ldap_printer.o libads/sasl.o \
libads/authdata.o libads/cldap.o
LIBADS_SERVER_OBJ = libads/util.o libads/kerberos_verify.o \
libads/ldap_schema.o sam/nss_info.o
libads/ldap_schema.o nsswitch/nss_info.o
SECRETS_OBJ = passdb/secrets.o passdb/machine_sid.o
@@ -619,7 +619,7 @@ NET_OBJ1 = utils/net.o utils/net_ads.o utils/net_domain.o utils/net_help.o \
NET_OBJ = $(NET_OBJ1) $(PARAM_OBJ) $(SECRETS_OBJ) $(LIBSMB_OBJ) \
$(RPC_PARSE_OBJ) $(PASSDB_OBJ) $(GROUPDB_OBJ) \
$(KRBCLIENT_OBJ) $(LIB_NONSMBD_OBJ) $(LIBADDNS_OBJ0) \
$(LIBMSRPC_OBJ) $(LIBMSRPC_GEN_OBJ) $(IDMAP_OBJ) \
$(LIBMSRPC_OBJ) $(LIBMSRPC_GEN_OBJ) \
$(LIBADS_OBJ) $(LIBADS_SERVER_OBJ) $(POPT_LIB_OBJ) \
$(SMBLDAP_OBJ) $(DCUTIL_OBJ) $(SERVER_MUTEX_OBJ) \
$(AFS_OBJ) $(AFS_SETTOKEN_OBJ) $(REGFIO_OBJ) $(READLINE_OBJ) \
@@ -745,7 +745,7 @@ PAM_SMBPASS_OBJ_0 = pam_smbpass/pam_smb_auth.o pam_smbpass/pam_smb_passwd.o \
$(SECRETS_OBJ) $(SMBLDAP_OBJ) $(LIBSAMBA_OBJ) \
$(RPC_PARSE_OBJ1) $(DOSERR_OBJ) $(LDB_OBJ)
IDMAP_OBJ = sam/idmap.o sam/idmap_util.o @IDMAP_STATIC@
IDMAP_OBJ = nsswitch/idmap.o nsswitch/idmap_cache.o nsswitch/idmap_util.o @IDMAP_STATIC@
WINBINDD_OBJ1 = \
nsswitch/winbindd.o \
@@ -805,7 +805,7 @@ LDB_OBJ = ${LDB_COMMON_OBJ} ${LDB_TDB_OBJ} ${LDB_LDAP_OBJ} ${LDB_MODULES_OBJ}
LDB_CMDLINE_OBJ = $(PARAM_OBJ) $(SECRETS_OBJ) $(LIBSMB_OBJ) \
$(RPC_PARSE_OBJ) $(PASSDB_OBJ) $(GROUPDB_OBJ) \
$(KRBCLIENT_OBJ) $(LIB_NONSMBD_OBJ) $(LIBADDNS_OBJ0) \
$(LIBMSRPC_OBJ) $(LIBMSRPC_GEN_OBJ) $(IDMAP_OBJ) \
$(LIBMSRPC_OBJ) $(LIBMSRPC_GEN_OBJ) \
$(LIBADS_OBJ) $(LIBADS_SERVER_OBJ) $(POPT_LIB_OBJ) \
$(SMBLDAP_OBJ) $(DCUTIL_OBJ) $(SERVER_MUTEX_OBJ) \
$(AFS_OBJ) $(AFS_SETTOKEN_OBJ) $(REGFIO_OBJ) $(READLINE_OBJ) \
@@ -1385,14 +1385,14 @@ bin/smbpasswd.@SHLIBEXT@: passdb/pdb_smbpasswd.o
@$(SHLD) $(LDSHFLAGS) -o $@ passdb/pdb_smbpasswd.o \
@SONAMEFLAG@`basename $@`
bin/rid.@SHLIBEXT@: sam/idmap_rid.o
bin/rid.@SHLIBEXT@: nsswitch/idmap_rid.o
@echo "Building plugin $@"
@$(SHLD) $(LDSHFLAGS) -o $@ sam/idmap_rid.o \
@$(SHLD) $(LDSHFLAGS) -o $@ nsswitch/idmap_rid.o \
@SONAMEFLAG@`basename $@`
bin/ad.@SHLIBEXT@: sam/idmap_ad.o
bin/ad.@SHLIBEXT@: nsswitch/idmap_ad.o
@echo "Building plugin $@"
@$(SHLD) $(LDSHFLAGS) -o $@ sam/idmap_ad.o \
@$(SHLD) $(LDSHFLAGS) -o $@ nsswitch/idmap_ad.o \
@SONAMEFLAG@`basename $@`
bin/weird.@SHLIBEXT@: $(DEVEL_HELP_WEIRD_OBJ)

View File

@@ -841,6 +841,8 @@ static struct nt_user_token *create_local_nt_token(TALLOC_CTX *mem_ctx,
NTSTATUS status;
gid_t gid;
DEBUG(10, ("Create local NT token for %s\n", sid_string_static(user_sid)));
if (!(result = TALLOC_ZERO_P(mem_ctx, NT_USER_TOKEN))) {
DEBUG(0, ("talloc failed\n"));
return NULL;
@@ -980,6 +982,7 @@ static struct nt_user_token *create_local_nt_token(TALLOC_CTX *mem_ctx,
NTSTATUS create_local_token(auth_serversupplied_info *server_info)
{
TALLOC_CTX *mem_ctx;
struct id_map *ids;
NTSTATUS status;
size_t i;
@@ -1027,17 +1030,27 @@ NTSTATUS create_local_token(auth_serversupplied_info *server_info)
server_info->groups = NULL;
/* Start at index 1, where the groups start. */
ids = talloc_zero_array(mem_ctx, struct id_map, server_info->ptok->num_sids);
for (i = 0; i < server_info->ptok->num_sids-1; i++) {
ids[i].sid = &server_info->ptok->user_sids[i + 1]; /* store the sids */
}
for (i=1; i<server_info->ptok->num_sids; i++) {
gid_t gid;
DOM_SID *sid = &server_info->ptok->user_sids[i];
if (!winbind_sids_to_unixids(ids, server_info->ptok->num_sids-1)) {
DEBUG(2, ("Query to map secondary SIDs failed!\n"));
}
if (!sid_to_gid(sid, &gid)) {
for (i = 0; i < server_info->ptok->num_sids-1; i++) {
if ( ! ids[i].mapped) {
DEBUG(10, ("Could not convert SID %s to gid, "
"ignoring it\n", sid_string_static(sid)));
"ignoring it\n", sid_string_static(ids[i].sid)));
continue;
}
if (!add_gid_to_array_unique(server_info, gid, &server_info->groups,
if ( ! ids[i].xid.type == ID_TYPE_UID) {
DEBUG(10, ("SID %s is a User ID (%u) not a Group ID, "
"ignoring it\n", sid_string_static(ids[i].sid), ids[i].xid.id));
continue;
}
if (!add_gid_to_array_unique(server_info, (gid_t)ids[i].xid.id, &server_info->groups,
&server_info->n_groups)) {
TALLOC_FREE(mem_ctx);
return NT_STATUS_NO_MEMORY;

View File

@@ -5843,6 +5843,8 @@ dnl Always built these modules static
MODULE_rpc_spoolss=STATIC
MODULE_rpc_srvsvc=STATIC
MODULE_idmap_tdb=STATIC
MODULE_idmap_passdb=STATIC
MODULE_idmap_nss=STATIC
AC_ARG_WITH(static-modules,
[ --with-static-modules=MODULES Comma-seperated list of names of modules to statically link in],
@@ -5886,11 +5888,13 @@ SMB_MODULE(rpc_rpcecho, \$(RPC_ECHO_OBJ), "bin/librpc_echo.$SHLIBEXT", RPC)
SMB_MODULE(rpc_unixinfo, \$(RPC_UNIXINFO_OBJ), "bin/librpc_unixinfo.$SHLIBEXT", RPC)
SMB_SUBSYSTEM(RPC,smbd/server.o)
SMB_MODULE(idmap_ldap, sam/idmap_ldap.o, "bin/ldap.$SHLIBEXT", IDMAP)
SMB_MODULE(idmap_tdb, sam/idmap_tdb.o, "bin/tdb.$SHLIBEXT", IDMAP)
SMB_MODULE(idmap_rid, sam/idmap_rid.o, "bin/rid.$SHLIBEXT", IDMAP)
SMB_MODULE(idmap_ad, sam/idmap_ad.o, "bin/ad.$SHLIBEXT", IDMAP)
SMB_SUBSYSTEM(IDMAP,sam/idmap.o)
SMB_MODULE(idmap_ldap, nsswitch/idmap_ldap.o, "bin/ldap.$SHLIBEXT", IDMAP)
SMB_MODULE(idmap_tdb, nsswitch/idmap_tdb.o, "bin/tdb.$SHLIBEXT", IDMAP)
SMB_MODULE(idmap_passdb, nsswitch/idmap_passdb.o, "bin/passdb.$SHLIBEXT", IDMAP)
SMB_MODULE(idmap_nss, nsswitch/idmap_nss.o, "bin/nss.$SHLIBEXT", IDMAP)
SMB_MODULE(idmap_rid, nsswitch/idmap_rid.o, "bin/rid.$SHLIBEXT", IDMAP)
SMB_MODULE(idmap_ad, nsswitch/idmap_ad.o, "bin/ad.$SHLIBEXT", IDMAP)
SMB_SUBSYSTEM(IDMAP, nsswitch/idmap.o)
SMB_MODULE(charset_weird, modules/weird.o, "bin/weird.$SHLIBEXT", CHARSET)
SMB_MODULE(charset_CP850, modules/CP850.o, "bin/CP850.$SHLIBEXT", CHARSET)

View File

@@ -59,7 +59,7 @@ do { \
DLIST_ADD(list, p); \
} while (0)
/* hook into the end of the list - needs a tmp pointer */
/* hook into the end of the list - needs the entry type */
#define DLIST_ADD_END(list, p, type) \
do { \
if (!(list)) { \

View File

@@ -32,29 +32,49 @@
/* The interface version specifier.
Updated to 3 for enum types by JRA. */
#define SMB_IDMAP_INTERFACE_VERSION 3
/* Updated to 4, completely new interface, SSS */
enum idmap_type { ID_USERID, ID_GROUPID };
#define SMB_IDMAP_INTERFACE_VERSION 4
#define IDMAP_FLAG_NONE 0x0
#define IDMAP_FLAG_QUERY_ONLY 0x1 /* Don't ever allocate, just query. */
#define IDMAP_FLAG_CACHE_ONLY 0x2 /* Only look in our local cache, not remote. */
struct idmap_domain {
DOM_SID *sid;
const char *name;
BOOL default_domain;
BOOL readonly;
void *private_data;
struct idmap_methods *methods;
};
/* Filled out by IDMAP backends */
struct idmap_methods {
/* Called when backend is first loaded */
NTSTATUS (*init)( const char *params );
NTSTATUS (*init)(struct idmap_domain *dom, const char *compat_params);
NTSTATUS (*allocate_id)(unid_t *id, enum idmap_type id_type);
NTSTATUS (*get_sid_from_id)(DOM_SID *sid, unid_t id, enum idmap_type id_type, int flags);
NTSTATUS (*get_id_from_sid)(unid_t *id, enum idmap_type *id_type, const DOM_SID *sid, int flags);
NTSTATUS (*set_mapping)(const DOM_SID *sid, unid_t id, enum idmap_type id_type);
NTSTATUS (*unixids_to_sids)(struct idmap_domain *dom, struct id_map **ids);
NTSTATUS (*sids_to_unixids)(struct idmap_domain *dom, struct id_map **ids);
NTSTATUS (*set_mapping)(struct idmap_domain *dom, const struct id_map *map);
NTSTATUS (*remove_mapping)(struct idmap_domain *dom, const struct id_map *map);
/* Called to dump backends data */
/* NOTE: caller must use talloc_free to free maps when done */
NTSTATUS (*dump_data)(struct idmap_domain *dom, struct id_map **maps, int *num_maps);
/* Called when backend is unloaded */
NTSTATUS (*close_fn)(struct idmap_domain *dom);
};
struct idmap_alloc_methods {
/* Called when backend is first loaded */
NTSTATUS (*init)(const char *compat_params);
NTSTATUS (*allocate_id)(struct unixid *id);
NTSTATUS (*get_id_hwm)(struct unixid *id);
NTSTATUS (*set_id_hwm)(struct unixid *id);
/* Called when backend is unloaded */
NTSTATUS (*close_fn)(void);
/* Called to dump backend status */
void (*status)(void);
};
#endif /* _IDMAP_H_ */

View File

@@ -393,6 +393,8 @@ struct pdb_methods
BOOL (*uid_to_rid)(struct pdb_methods *methods, uid_t uid,
uint32 *rid);
BOOL (*uid_to_sid)(struct pdb_methods *methods, uid_t uid,
DOM_SID *sid);
BOOL (*gid_to_sid)(struct pdb_methods *methods, gid_t gid,
DOM_SID *sid);
BOOL (*sid_to_id)(struct pdb_methods *methods, const DOM_SID *sid,

View File

@@ -273,6 +273,22 @@ typedef struct dom_sid {
#define dom_sid2 dom_sid
#define dom_sid28 dom_sid
enum id_type {
ID_TYPE_UID,
ID_TYPE_GID
};
struct unixid {
uint32_t id;
enum id_type type;
};
struct id_map {
DOM_SID *sid;
struct unixid xid;
BOOL mapped;
};
#include "librpc/ndr/misc.h"
#include "librpc/ndr/security.h"
#include "librpc/ndr/libndr.h"

View File

@@ -158,8 +158,12 @@ struct smbldap_state {
time_t last_ping;
/* retrive-once info */
const char *uri;
/* credentials */
BOOL anonimous;
char *bind_dn;
char *bind_secret;
BOOL paged_results;
unsigned int num_failures;

View File

@@ -803,12 +803,18 @@ static int rebindproc_with_state (LDAP * ld, char **whop, char **credp,
if (freeit) {
SAFE_FREE(*whop);
if (*credp) {
memset(*credp, '\0', strlen(*credp));
}
SAFE_FREE(*credp);
} else {
DEBUG(5,("rebind_proc_with_state: Rebinding as \"%s\"\n",
ldap_state->bind_dn));
ldap_state->bind_dn?ldap_state->bind_dn:"[Anonymous bind]"));
if (ldap_state->anonymous) {
*whop = NULL;
*credp = NULL;
} else {
*whop = SMB_STRDUP(ldap_state->bind_dn);
if (!*whop) {
return LDAP_NO_MEMORY;
@@ -818,6 +824,7 @@ static int rebindproc_with_state (LDAP * ld, char **whop, char **credp,
SAFE_FREE(*whop);
return LDAP_NO_MEMORY;
}
}
*methodp = LDAP_AUTH_SIMPLE;
}
@@ -844,7 +851,7 @@ static int rebindproc_connect_with_state (LDAP *ldap_struct,
int version;
DEBUG(5,("rebindproc_connect_with_state: Rebinding to %s as \"%s\"\n",
url, ldap_state->bind_dn));
url, ldap_state->bind_dn?ldap_state->bind_dn:"[Anonymous bind]"));
/* call START_TLS again (ldaps:// is handled by the OpenLDAP library
* itself) before rebinding to another LDAP server to avoid to expose
@@ -925,24 +932,22 @@ static int rebindproc_connect (LDAP * ld, LDAP_CONST char *url, int request,
static int smbldap_connect_system(struct smbldap_state *ldap_state, LDAP * ldap_struct)
{
int rc;
char *ldap_dn;
char *ldap_secret;
int version;
/* get the password */
if (!fetch_ldap_pw(&ldap_dn, &ldap_secret)) {
if (!ldap_state->anonimous && !ldap_state->bind_dn) {
/* get the default dn and password only if they are not set already */
if (!fetch_ldap_pw(&ldap_state->bind_dn, &ldap_state->bind_secret)) {
DEBUG(0, ("ldap_connect_system: Failed to retrieve password from secrets.tdb\n"));
return LDAP_INVALID_CREDENTIALS;
}
ldap_state->bind_dn = ldap_dn;
ldap_state->bind_secret = ldap_secret;
}
/* removed the sasl_bind_s "EXTERNAL" stuff, as my testsuite
(OpenLDAP) doesnt' seem to support it */
DEBUG(10,("ldap_connect_system: Binding to ldap server %s as \"%s\"\n",
ldap_state->uri, ldap_dn));
ldap_state->uri, ldap_state->bind_dn));
#ifdef HAVE_LDAP_SET_REBIND_PROC
#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
@@ -962,7 +967,7 @@ static int smbldap_connect_system(struct smbldap_state *ldap_state, LDAP * ldap_
#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
#endif
rc = ldap_simple_bind_s(ldap_struct, ldap_dn, ldap_secret);
rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret);
if (rc != LDAP_SUCCESS) {
char *ld_error = NULL;
@@ -971,7 +976,8 @@ static int smbldap_connect_system(struct smbldap_state *ldap_state, LDAP * ldap_
DEBUG(ldap_state->num_failures ? 2 : 0,
("failed to bind to server %s with dn=\"%s\" Error: %s\n\t%s\n",
ldap_state->uri,
ldap_dn ? ldap_dn : "(unknown)", ldap_err2string(rc),
ldap_state->bind_dn ? ldap_state->bind_dn : "[Anonymous bind]",
ldap_err2string(rc),
ld_error ? ld_error : "(unknown)"));
SAFE_FREE(ld_error);
ldap_state->num_failures++;
@@ -1078,8 +1084,6 @@ static NTSTATUS smbldap_close(struct smbldap_state *ldap_state)
DEBUG(5,("The connection to the LDAP server was closed\n"));
/* maybe free the results here --metze */
return NT_STATUS_OK;
}
@@ -1701,3 +1705,24 @@ BOOL smbldap_has_naming_context(LDAP *ld, const char *naming_context)
const char *attrs[] = { "namingContexts", NULL };
return smbldap_check_root_dse(ld, attrs, naming_context);
}
BOOL smbldap_set_creds(struct smbldap_state *ldap_state, BOOL anon, const char *dn, const char *secret)
{
ldap_state->anonimous = anon;
/* free any previously set credential */
SAFE_FREE(ldap_state->bind_dn);
if (ldap_state->bind_secret) {
/* make sure secrets are zeroed out of memory */
memset(ldap_state->bind_secret, '\0', strlen(ldap_state->bind_secret));
SAFE_FREE(ldap_state->bind_secret);
}
if ( ! anon) {
ldap_state->bind_dn = SMB_STRDUP(dn);
ldap_state->bind_secret = SMB_STRDUP(secret);
}
return True;
}

1299
source/nsswitch/idmap.c Normal file

File diff suppressed because it is too large Load Diff

707
source/nsswitch/idmap_ad.c Normal file
View File

@@ -0,0 +1,707 @@
/*
* idmap_ad: map between Active Directory and RFC 2307 or "Services for Unix" (SFU) Accounts
*
* Unix SMB/CIFS implementation.
*
* Winbind ADS backend functions
*
* Copyright (C) Andrew Tridgell 2001
* Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003
* Copyright (C) Gerald (Jerry) Carter 2004
* Copyright (C) Luke Howard 2001-2004
*
* 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"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_IDMAP
#define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
NTSTATUS init_module(void);
static ADS_STRUCT *ad_idmap_ads = NULL;
static char *attr_uidnumber = NULL;
static char *attr_gidnumber = NULL;
static ADS_STATUS ad_idmap_check_attr_mapping(ADS_STRUCT *ads)
{
ADS_STATUS status;
enum wb_posix_mapping map_type;
if (attr_uidnumber != NULL && attr_gidnumber != NULL) {
return ADS_ERROR(LDAP_SUCCESS);
}
SMB_ASSERT(ads->server.workgroup);
map_type = get_nss_info(ads->server.workgroup);
if ((map_type == WB_POSIX_MAP_SFU) ||
(map_type == WB_POSIX_MAP_RFC2307)) {
status = ads_check_posix_schema_mapping(ads, map_type);
if (ADS_ERR_OK(status)) {
attr_uidnumber = SMB_STRDUP(ads->schema.posix_uidnumber_attr);
attr_gidnumber = SMB_STRDUP(ads->schema.posix_gidnumber_attr);
ADS_ERROR_HAVE_NO_MEMORY(attr_uidnumber);
ADS_ERROR_HAVE_NO_MEMORY(attr_gidnumber);
return ADS_ERROR(LDAP_SUCCESS);
} else {
DEBUG(0,("ads_check_posix_schema_mapping failed: %s\n", ads_errstr(status)));
/* return status; */
}
}
/* fallback to XAD defaults */
attr_uidnumber = SMB_STRDUP("uidNumber");
attr_gidnumber = SMB_STRDUP("gidNumber");
ADS_ERROR_HAVE_NO_MEMORY(attr_uidnumber);
ADS_ERROR_HAVE_NO_MEMORY(attr_gidnumber);
return ADS_ERROR(LDAP_SUCCESS);
}
static ADS_STRUCT *ad_idmap_cached_connection(void)
{
ADS_STRUCT *ads;
ADS_STATUS status;
BOOL local = False;
if (ad_idmap_ads != NULL) {
ads = ad_idmap_ads;
/* check for a valid structure */
DEBUG(7, ("Current tickets expire at %d, time is now %d\n",
(uint32) ads->auth.expire, (uint32) time(NULL)));
if ( ads->config.realm && (ads->auth.expire > time(NULL))) {
return ads;
} else {
/* we own this ADS_STRUCT so make sure it goes away */
ads->is_mine = True;
ads_destroy( &ads );
ads_kdestroy(WINBIND_CCACHE_NAME);
ad_idmap_ads = NULL;
}
}
if (!local) {
/* we don't want this to affect the users ccache */
setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
}
ads = ads_init(lp_realm(), lp_workgroup(), NULL);
if (!ads) {
DEBUG(1,("ads_init failed\n"));
return NULL;
}
/* the machine acct password might have change - fetch it every time */
SAFE_FREE(ads->auth.password);
ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
SAFE_FREE(ads->auth.realm);
ads->auth.realm = SMB_STRDUP(lp_realm());
status = ads_connect(ads);
if (!ADS_ERR_OK(status)) {
DEBUG(1, ("ad_idmap_init: failed to connect to AD\n"));
ads_destroy(&ads);
return NULL;
}
ads->is_mine = False;
status = ad_idmap_check_attr_mapping(ads);
if (!ADS_ERR_OK(status)) {
DEBUG(1, ("ad_idmap_init: failed to check attribute mapping\n"));
return NULL;
}
ad_idmap_ads = ads;
return ads;
}
struct idmap_ad_context {
uint32_t filter_low_id, filter_high_id; /* Filter range */
};
/* Initialize and check conf is appropriate */
static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom, const char *params)
{
NTSTATUS ret;
struct idmap_ad_context *ctx;
char *config_option;
const char *range;
const char *tmp;
ADS_STRUCT *ads;
/* verify AD is reachable (not critical, we may just be offline at start) */
ads = ad_idmap_cached_connection();
if (ads == NULL) {
DEBUG(1, ("WARNING: Could not init an AD connection! Mapping might not work.\n"));
}
ctx = talloc_zero(dom, struct idmap_ad_context);
if ( ! ctx) {
DEBUG(0, ("Out of memory!\n"));
return NT_STATUS_NO_MEMORY;
}
config_option = talloc_asprintf(ctx, "idmap config %s", dom->name);
if ( ! config_option) {
DEBUG(0, ("Out of memory!\n"));
talloc_free(ctx);
return NT_STATUS_NO_MEMORY;
}
/* load ranges */
range = lp_parm_const_string(-1, config_option, "range", NULL);
if (range && range[0]) {
if ((sscanf(range, "%u - %u", &ctx->filter_low_id, &ctx->filter_high_id) != 2) ||
(ctx->filter_low_id > ctx->filter_high_id)) {
DEBUG(1, ("ERROR: invalid filter range [%s]", range));
ctx->filter_low_id = 0;
ctx->filter_high_id = 0;
}
}
/* idmap AD can work well only if it is the default module (trusts)
* with additional BUILTIN and alloc using TDB */
if ( ! dom->default_domain) {
DEBUG(1, ("WARNING: idmap_ad is not configured as the default domain.\n"
"For best results we suggest you to configure this module as\n"
"default and configure BULTIN to use idmap_tdb\n"
"ex: idmap domains = BUILTIN %s\n"
" idmap alloc config: range = 5000 - 9999\n"
" idmap config %s: default = yes\n"
" idmap config %s: backend = ad\n"
" idmap config %s: range = 10000 - 10000000 #this is optional\n"
"NOTE: make sure the ranges do not overlap\n",
dom->name, dom->name, dom->name, dom->name));
}
if ( ! dom->readonly) {
DEBUG(1, ("WARNING: forcing to readonly, as idmap_ad can't write on AD.\n"));
dom->readonly = true; /* force readonly */
}
dom->private_data = ctx;
talloc_free(config_option);
return NT_STATUS_OK;
}
#define IDMAP_AD_MAX_IDS 30
#define CHECK_ALLOC_DONE(mem) do { if (!mem) { DEBUG(0, ("Out of memory!\n")); ret = NT_STATUS_NO_MEMORY; goto done; } } while (0)
/* this function searches up to IDMAP_AD_MAX_IDS entries in maps for a match */
static struct id_map *find_map_by_id(struct id_map **maps, enum id_type type, uint32_t id)
{
int i;
for (i = 0; i < IDMAP_AD_MAX_IDS; i++) {
if (maps[i] == NULL) { /* end of the run */
return NULL;
}
if ((maps[i]->xid.type == type) && (maps[i]->xid.id == id)) {
return maps[i];
}
}
return NULL;
}
static NTSTATUS idmap_ad_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
{
NTSTATUS ret;
TALLOC_CTX *memctx;
struct idmap_ad_context *ctx;
ADS_STATUS rc;
ADS_STRUCT *ads;
const char *attrs[] = { "sAMAccountType",
"objectSid",
NULL, /* attr_uidnumber */
NULL, /* attr_gidnumber */
NULL };
LDAPMessage *res = NULL;
char *filter = NULL;
BOOL multi = False;
int idx = 0;
int bidx = 0;
int count;
int i;
ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
memctx = talloc_new(ctx);
if ( ! memctx) {
DEBUG(0, ("Out of memory!\n"));
return NT_STATUS_NO_MEMORY;
}
ads = ad_idmap_cached_connection();
if (ads == NULL) {
DEBUG(1, ("ADS uninitialized\n"));
ret = NT_STATUS_UNSUCCESSFUL;
goto done;
}
/* attr_uidnumber and attr_gidnumber are surely successfully initialized now */
attrs[2] = attr_uidnumber;
attrs[3] = attr_gidnumber;
if ( ! ids[1]) {
/* if we are requested just one mapping use the simple filter */
switch (ids[0]->xid.type) {
case ID_TYPE_UID:
filter = talloc_asprintf(memctx,
"(&(|(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d))(%s=%lu))",
ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
attr_uidnumber,
(unsigned long)ids[0]->xid.id);
break;
case ID_TYPE_GID:
filter = talloc_asprintf(memctx,
"(&(|(sAMAccountType=%d)(sAMAccountType=%d))(%s=%lu))",
ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP,
attr_gidnumber,
(unsigned long)ids[0]->xid.id);
break;
default:
DEBUG(3, ("Unknown ID type\n"));
ret = NT_STATUS_INVALID_PARAMETER;
goto done;
}
CHECK_ALLOC_DONE(filter);
DEBUG(10, ("Filter: [%s]\n", filter));
} else {
/* multiple mappings */
multi = True;
}
again:
if (multi) {
char *u_filter = NULL;
char *g_filter = NULL;
bidx = idx;
for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
switch (ids[idx]->xid.type) {
case ID_TYPE_UID:
if ( ! u_filter) {
u_filter = talloc_asprintf(memctx, "(&(|"
"(sAMAccountType=%d)"
"(sAMAccountType=%d)"
"(sAMAccountType=%d))(|",
ATYPE_NORMAL_ACCOUNT,
ATYPE_WORKSTATION_TRUST,
ATYPE_INTERDOMAIN_TRUST);
}
u_filter = talloc_asprintf_append(u_filter, "(%s=%lu)",
attr_uidnumber,
(unsigned long)ids[idx]->xid.id);
CHECK_ALLOC_DONE(u_filter);
break;
case ID_TYPE_GID:
if ( ! g_filter) {
g_filter = talloc_asprintf(memctx, "(&(|"
"(sAMAccountType=%d)"
"(sAMAccountType=%d))(|",
ATYPE_SECURITY_GLOBAL_GROUP,
ATYPE_SECURITY_LOCAL_GROUP);
}
g_filter = talloc_asprintf_append(g_filter, "(%s=%lu)",
attr_gidnumber,
(unsigned long)ids[idx]->xid.id);
CHECK_ALLOC_DONE(g_filter);
break;
default:
DEBUG(3, ("Unknown ID type\n"));
ids[idx]->mapped = false;
continue;
}
}
filter = talloc_asprintf(memctx, "(|");
CHECK_ALLOC_DONE(filter);
if ( u_filter) {
filter = talloc_asprintf_append(filter, "%s))", u_filter);
CHECK_ALLOC_DONE(filter);
TALLOC_FREE(u_filter);
}
if ( g_filter) {
filter = talloc_asprintf_append(filter, "%s))", g_filter);
CHECK_ALLOC_DONE(filter);
TALLOC_FREE(g_filter);
}
filter = talloc_asprintf_append(filter, ")");
CHECK_ALLOC_DONE(filter);
DEBUG(10, ("Filter: [%s]\n", filter));
} else {
bidx = 0;
idx = 1;
}
rc = ads_search_retry(ads, &res, filter, attrs);
if (!ADS_ERR_OK(rc)) {
DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
ret = NT_STATUS_UNSUCCESSFUL;
goto done;
}
count = ads_count_replies(ads, res);
if (count == 0) {
DEBUG(10, ("No IDs found\n"));
}
for (i = 0; i < count; i++) {
LDAPMessage *entry;
DOM_SID sid;
enum id_type type;
struct id_map *map;
uint32_t id;
uint32_t atype;
int n;
if (i == 0) { /* first entry */
entry = ads_first_entry(ads, res);
} else { /* following ones */
entry = ads_next_entry(ads, entry);
}
if ( ! entry) {
DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
continue;
}
/* first check if the SID is present */
if (!ads_pull_sid(ads, entry, "objectSid", &sid)) {
DEBUG(2, ("Could not retrieve SID from entry\n"));
continue;
}
/* get type */
if (!ads_pull_uint32(ads, entry, "sAMAccountType", &atype)) {
DEBUG(1, ("could not get SAM account type\n"));
continue;
}
switch (atype & 0xF0000000) {
case ATYPE_SECURITY_GLOBAL_GROUP:
case ATYPE_SECURITY_LOCAL_GROUP:
type = ID_TYPE_GID;
break;
case ATYPE_NORMAL_ACCOUNT:
case ATYPE_WORKSTATION_TRUST:
case ATYPE_INTERDOMAIN_TRUST:
type = ID_TYPE_UID;
break;
default:
DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
continue;
}
if (!ads_pull_uint32(ads, entry, (type==ID_TYPE_UID)?attr_uidnumber:attr_gidnumber, &id)) {
DEBUG(1, ("Could not get unix ID\n"));
continue;
}
if ((id == 0) ||
(ctx->filter_low_id && (id < ctx->filter_low_id)) ||
(ctx->filter_high_id && (id > ctx->filter_high_id))) {
DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
id, ctx->filter_low_id, ctx->filter_high_id));
continue;
}
map = find_map_by_id(&ids[bidx], type, id);
if (!map) {
DEBUG(2, ("WARNING: couldn't match result with requested ID\n"));
continue;
}
sid_copy(map->sid, &sid);
/* mapped */
map->mapped = True;
DEBUG(10, ("Mapped %s -> %lu (%d)\n",
sid_string_static(map->sid),
(unsigned long)map->xid.id,
map->xid.type));
}
if (res) {
ads_msgfree(ads, res);
}
if (multi && ids[idx]) { /* still some values to map */
goto again;
}
ret = NT_STATUS_OK;
done:
talloc_free(memctx);
return ret;
}
/* this function searches up to IDMAP_AD_MAX_IDS entries in maps for a match */
static struct id_map *find_map_by_sid(struct id_map **maps, DOM_SID *sid)
{
int i;
for (i = 0; i < IDMAP_AD_MAX_IDS; i++) {
if (maps[i] == NULL) { /* end of the run */
return NULL;
}
if (sid_equal(maps[i]->sid, sid)) {
return maps[i];
}
}
return NULL;
}
static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
{
NTSTATUS ret;
TALLOC_CTX *memctx;
struct idmap_ad_context *ctx;
ADS_STATUS rc;
ADS_STRUCT *ads;
const char *attrs[] = { "sAMAccountType",
"objectSid",
NULL, /* attr_uidnumber */
NULL, /* attr_gidnumber */
NULL };
LDAPMessage *res = NULL;
char *filter = NULL;
BOOL multi = False;
int idx = 0;
int bidx = 0;
int count;
int i;
ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
memctx = talloc_new(ctx);
if ( ! memctx) {
DEBUG(0, ("Out of memory!\n"));
return NT_STATUS_NO_MEMORY;
}
ads = ad_idmap_cached_connection();
if (ads == NULL) {
DEBUG(1, ("ADS uninitialized\n"));
ret = NT_STATUS_UNSUCCESSFUL;
goto done;
}
/* attr_uidnumber and attr_gidnumber are surely successfully initialized now */
attrs[2] = attr_uidnumber;
attrs[3] = attr_gidnumber;
if ( ! ids[1]) {
/* if we are requested just one mapping use the simple filter */
char *sidstr;
sidstr = sid_binstring(ids[0]->sid);
filter = talloc_asprintf(memctx, "(&(objectSid=%s)(|" /* the requested Sid */
"(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d)" /* user account types */
"(sAMAccountType=%d)(sAMAccountType=%d)))", /* group account types */
sidstr,
ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP);
if (! filter) {
free(sidstr);
ret = NT_STATUS_NO_MEMORY;
goto done;
}
CHECK_ALLOC_DONE(filter);
DEBUG(10, ("Filter: [%s]\n", filter));
} else {
/* multiple mappings */
multi = True;
}
again:
if (multi) {
char *sidstr;
filter = talloc_asprintf(memctx,
"(&(|"
"(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d)" /* user account types */
"(sAMAccountType=%d)(sAMAccountType=%d)" /* group account types */
")(|",
ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP);
CHECK_ALLOC_DONE(filter);
bidx = idx;
for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
sidstr = sid_binstring(ids[idx]->sid);
filter = talloc_asprintf_append(filter, "(objectSid=%s)", sidstr);
free(sidstr);
CHECK_ALLOC_DONE(filter);
}
filter = talloc_asprintf_append(filter, "))");
CHECK_ALLOC_DONE(filter);
DEBUG(10, ("Filter: [%s]\n", filter));
} else {
bidx = 0;
idx = 1;
}
rc = ads_search_retry(ads, &res, filter, attrs);
if (!ADS_ERR_OK(rc)) {
DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
ret = NT_STATUS_UNSUCCESSFUL;
goto done;
}
count = ads_count_replies(ads, res);
if (count == 0) {
DEBUG(10, ("No IDs found\n"));
}
for (i = 0; i < count; i++) {
LDAPMessage *entry;
DOM_SID sid;
enum id_type type;
struct id_map *map;
uint32_t id;
uint32_t atype;
int n;
if (i == 0) { /* first entry */
entry = ads_first_entry(ads, res);
} else { /* following ones */
entry = ads_next_entry(ads, entry);
}
if ( ! entry) {
DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
continue;
}
/* first check if the SID is present */
if (!ads_pull_sid(ads, entry, "objectSid", &sid)) {
DEBUG(2, ("Could not retrieve SID from entry\n"));
continue;
}
map = find_map_by_sid(&ids[bidx], &sid);
if (!map) {
DEBUG(2, ("WARNING: couldn't match result with requested SID\n"));
continue;
}
/* get type */
if (!ads_pull_uint32(ads, entry, "sAMAccountType", &atype)) {
DEBUG(1, ("could not get SAM account type\n"));
continue;
}
switch (atype & 0xF0000000) {
case ATYPE_SECURITY_GLOBAL_GROUP:
case ATYPE_SECURITY_LOCAL_GROUP:
type = ID_TYPE_GID;
break;
case ATYPE_NORMAL_ACCOUNT:
case ATYPE_WORKSTATION_TRUST:
case ATYPE_INTERDOMAIN_TRUST:
type = ID_TYPE_UID;
break;
default:
DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
continue;
}
if (!ads_pull_uint32(ads, entry, (type==ID_TYPE_UID)?attr_uidnumber:attr_gidnumber, &id)) {
DEBUG(1, ("Could not get unix ID\n"));
continue;
}
if ((id == 0) ||
(ctx->filter_low_id && (id < ctx->filter_low_id)) ||
(ctx->filter_high_id && (id > ctx->filter_high_id))) {
DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
id, ctx->filter_low_id, ctx->filter_high_id));
continue;
}
/* mapped */
map->xid.type = type;
map->xid.id = id;
map->mapped = True;
DEBUG(10, ("Mapped %s -> %lu (%d)\n",
sid_string_static(map->sid),
(unsigned long)map->xid.id,
map->xid.type));
}
if (res) {
ads_msgfree(ads, res);
}
if (multi && ids[idx]) { /* still some values to map */
goto again;
}
ret = NT_STATUS_OK;
done:
talloc_free(memctx);
return ret;
}
static NTSTATUS idmap_ad_close(struct idmap_domain *dom)
{
ADS_STRUCT *ads = ad_idmap_ads;
if (ads != NULL) {
/* we own this ADS_STRUCT so make sure it goes away */
ads->is_mine = True;
ads_destroy( &ads );
ad_idmap_ads = NULL;
}
SAFE_FREE(attr_uidnumber);
SAFE_FREE(attr_gidnumber);
return NT_STATUS_OK;
}
static struct idmap_methods ad_methods = {
.init = idmap_ad_initialize,
.unixids_to_sids = idmap_ad_unixids_to_sids,
.sids_to_unixids = idmap_ad_sids_to_unixids,
.close_fn = idmap_ad_close
};
/* support for new authentication subsystem */
NTSTATUS idmap_ad_init(void)
{
return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ad", &ad_methods);
}

View File

@@ -0,0 +1,530 @@
/*
Unix SMB/CIFS implementation.
ID Mapping Cache
based on gencache
Copyright (C) Simo Sorce 2006
Copyright (C) Rafal Szczesniak 2002
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"
#define TIMEOUT_LEN 12
#define IDMAP_CACHE_DATA_FMT "%12u/%s"
#define IDMAP_READ_CACHE_DATA_FMT_TEMPLATE "%%12u/%%%us"
struct idmap_cache_ctx {
TDB_CONTEXT *tdb;
};
static int idmap_cache_destructor(struct idmap_cache_ctx *cache)
{
int ret = 0;
if (cache && cache->tdb) {
ret = tdb_close(cache->tdb);
cache->tdb = NULL;
}
return ret;
}
struct idmap_cache_ctx *idmap_cache_init(TALLOC_CTX *memctx)
{
struct idmap_cache_ctx *cache;
char* cache_fname = NULL;
cache = talloc(memctx, struct idmap_cache_ctx);
if ( ! cache) {
DEBUG(0, ("Out of memory!\n"));
return NULL;
}
cache_fname = lock_path("idmap_cache.tdb");
DEBUG(10, ("Opening cache file at %s\n", cache_fname));
cache->tdb = tdb_open_log(cache_fname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
if (!cache->tdb) {
DEBUG(5, ("Attempt to open %s has failed.\n", cache_fname));
return NULL;
}
talloc_set_destructor(cache, idmap_cache_destructor);
return cache;
}
void idmap_cache_shutdown(struct idmap_cache_ctx *cache)
{
talloc_free(cache);
}
NTSTATUS idmap_cache_build_sidkey(TALLOC_CTX *ctx, char **sidkey, const struct id_map *id)
{
*sidkey = talloc_asprintf(ctx, "IDMAP/SID/%s", sid_string_static(id->sid));
if ( ! *sidkey) {
DEBUG(1, ("failed to build sidkey, OOM?\n"));
return NT_STATUS_NO_MEMORY;
}
return NT_STATUS_OK;
}
NTSTATUS idmap_cache_build_idkey(TALLOC_CTX *ctx, char **idkey, const struct id_map *id)
{
*idkey = talloc_asprintf(ctx, "IDMAP/%s/%lu",
(id->xid.type==ID_TYPE_UID)?"UID":"GID",
(unsigned long)id->xid.id);
if ( ! *idkey) {
DEBUG(1, ("failed to build idkey, OOM?\n"));
return NT_STATUS_NO_MEMORY;
}
return NT_STATUS_OK;
}
NTSTATUS idmap_cache_set(struct idmap_cache_ctx *cache, const struct id_map *id)
{
NTSTATUS ret;
time_t timeout = time(NULL) + lp_idmap_expire_time();
TDB_DATA keybuf, databuf;
char *sidkey;
char *idkey;
char *valstr;
ret = idmap_cache_build_sidkey(cache, &sidkey, id);
if (!NT_STATUS_IS_OK(ret)) return ret;
/* use sidkey as the local memory ctx */
ret = idmap_cache_build_idkey(sidkey, &idkey, id);
if (!NT_STATUS_IS_OK(ret)) {
goto done;
}
/* save SID -> ID */
/* use sidkey as the local memory ctx */
valstr = talloc_asprintf(sidkey, IDMAP_CACHE_DATA_FMT, (int)timeout, idkey);
if (!valstr) {
DEBUG(0, ("Out of memory!\n"));
ret = NT_STATUS_NO_MEMORY;
goto done;
}
keybuf.dptr = sidkey;
keybuf.dsize = strlen(sidkey)+1;
databuf.dptr = valstr;
databuf.dsize = strlen(valstr)+1;
DEBUG(10, ("Adding cache entry with key = %s; value = %s and timeout ="
" %s (%d seconds %s)\n", keybuf.dptr, valstr , ctime(&timeout),
(int)(timeout - time(NULL)),
timeout > time(NULL) ? "ahead" : "in the past"));
if (tdb_store(cache->tdb, keybuf, databuf, TDB_REPLACE) != 0) {
DEBUG(3, ("Failed to store cache entry!\n"));
ret = NT_STATUS_UNSUCCESSFUL;
goto done;
}
/* save ID -> SID */
/* use sidkey as the local memory ctx */
valstr = talloc_asprintf(sidkey, IDMAP_CACHE_DATA_FMT, (int)timeout, sidkey);
if (!valstr) {
DEBUG(0, ("Out of memory!\n"));
ret = NT_STATUS_NO_MEMORY;
goto done;
}
keybuf.dptr = idkey;
keybuf.dsize = strlen(idkey)+1;
databuf.dptr = valstr;
databuf.dsize = strlen(valstr)+1;
DEBUG(10, ("Adding cache entry with key = %s; value = %s and timeout ="
" %s (%d seconds %s)\n", keybuf.dptr, valstr, ctime(&timeout),
(int)(timeout - time(NULL)),
timeout > time(NULL) ? "ahead" : "in the past"));
if (tdb_store(cache->tdb, keybuf, databuf, TDB_REPLACE) != 0) {
DEBUG(3, ("Failed to store cache entry!\n"));
ret = NT_STATUS_UNSUCCESSFUL;
goto done;
}
ret = NT_STATUS_OK;
done:
talloc_free(sidkey);
return ret;
}
NTSTATUS idmap_cache_del(struct idmap_cache_ctx *cache, const struct id_map *id)
{
NTSTATUS ret;
TDB_DATA keybuf;
char *sidkey = NULL;
char *idkey = NULL;
ret = idmap_cache_build_sidkey(cache, &sidkey, id);
if (!NT_STATUS_IS_OK(ret)) return ret;
ret = idmap_cache_build_idkey(cache, &idkey, id);
if (!NT_STATUS_IS_OK(ret)) {
goto done;
}
/* delete SID */
keybuf.dptr = sidkey;
keybuf.dsize = strlen(sidkey)+1;
DEBUG(10, ("Deleting cache entry (key = %s)\n", keybuf.dptr));
if (tdb_delete(cache->tdb, keybuf) != 0) {
DEBUG(3, ("Failed to delete cache entry!\n"));
}
/* delete ID */
keybuf.dptr = idkey;
keybuf.dsize = strlen(idkey)+1;
DEBUG(10, ("Deleting cache entry (key = %s)\n", keybuf.dptr));
if (tdb_delete(cache->tdb, keybuf) != 0) {
DEBUG(3, ("Failed to delete cache entry!\n"));
}
done:
talloc_free(sidkey);
talloc_free(idkey);
return ret;
}
NTSTATUS idmap_cache_set_negative_sid(struct idmap_cache_ctx *cache, const struct id_map *id)
{
NTSTATUS ret;
time_t timeout = time(NULL) + lp_idmap_negative_time();
TDB_DATA keybuf, databuf;
char *sidkey;
char *valstr;
ret = idmap_cache_build_sidkey(cache, &sidkey, id);
if (!NT_STATUS_IS_OK(ret)) return ret;
/* use sidkey as the local memory ctx */
valstr = talloc_asprintf(sidkey, IDMAP_CACHE_DATA_FMT, (int)timeout, "IDMAP/NEGATIVE");
if (!valstr) {
DEBUG(0, ("Out of memory!\n"));
ret = NT_STATUS_NO_MEMORY;
goto done;
}
keybuf.dptr = sidkey;
keybuf.dsize = strlen(sidkey)+1;
databuf.dptr = valstr;
databuf.dsize = strlen(valstr)+1;
DEBUG(10, ("Adding cache entry with key = %s; value = %s and timeout ="
" %s (%d seconds %s)\n", keybuf.dptr, valstr, ctime(&timeout),
(int)(timeout - time(NULL)),
timeout > time(NULL) ? "ahead" : "in the past"));
if (tdb_store(cache->tdb, keybuf, databuf, TDB_REPLACE) != 0) {
DEBUG(3, ("Failed to store cache entry!\n"));
ret = NT_STATUS_UNSUCCESSFUL;
goto done;
}
done:
talloc_free(sidkey);
return ret;
}
NTSTATUS idmap_cache_set_negative_id(struct idmap_cache_ctx *cache, const struct id_map *id)
{
NTSTATUS ret;
time_t timeout = time(NULL) + lp_idmap_negative_time();
TDB_DATA keybuf, databuf;
char *idkey;
char *valstr;
ret = idmap_cache_build_idkey(cache, &idkey, id);
if (!NT_STATUS_IS_OK(ret)) return ret;
/* use idkey as the local memory ctx */
valstr = talloc_asprintf(idkey, IDMAP_CACHE_DATA_FMT, (int)timeout, "IDMAP/NEGATIVE");
if (!valstr) {
DEBUG(0, ("Out of memory!\n"));
ret = NT_STATUS_NO_MEMORY;
goto done;
}
keybuf.dptr = idkey;
keybuf.dsize = strlen(idkey)+1;
databuf.dptr = valstr;
databuf.dsize = strlen(valstr)+1;
DEBUG(10, ("Adding cache entry with key = %s; value = %s and timeout ="
" %s (%d seconds %s)\n", keybuf.dptr, valstr, ctime(&timeout),
(int)(timeout - time(NULL)),
timeout > time(NULL) ? "ahead" : "in the past"));
if (tdb_store(cache->tdb, keybuf, databuf, TDB_REPLACE) != 0) {
DEBUG(3, ("Failed to store cache entry!\n"));
ret = NT_STATUS_UNSUCCESSFUL;
goto done;
}
done:
talloc_free(idkey);
return ret;
}
NTSTATUS idmap_cache_fill_map(struct id_map *id, const char *value)
{
char *rem;
/* see if it is a sid */
if ( ! strncmp("IDMAP/SID/", value, 10)) {
if ( ! string_to_sid(id->sid, &value[10])) {
goto failed;
}
id->mapped = True;
return NT_STATUS_OK;
}
/* not a SID see if it is an UID or a GID */
if ( ! strncmp("IDMAP/UID/", value, 10)) {
/* a uid */
id->xid.type = ID_TYPE_UID;
} else if ( ! strncmp("IDMAP/GID/", value, 10)) {
/* a gid */
id->xid.type = ID_TYPE_GID;
} else {
/* a completely bogus value bail out */
goto failed;
}
id->xid.id = strtol(&value[10], &rem, 0);
if (*rem != '\0') {
goto failed;
}
id->mapped = True;
return NT_STATUS_OK;
failed:
DEBUG(1, ("invalid value: %s\n", value));
id->mapped = False;
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
BOOL idmap_cache_is_negative(const char *val)
{
if ( ! strcmp("IDMAP/NEGATIVE", val)) {
return True;
}
return False;
}
/* search the cahce for the SID an return a mapping if found *
*
* 3 cases are possible
*
* 1 map found
* in this case id->mapped = True and NT_STATUS_OK is returned
* 2 map not found
* in this case id->mapped = False and NT_STATUS_NONE_MAPPED is returned
* 3 negative cache found
* in this case id->mapped = False and NT_STATUS_OK is returned
*
* As a special case if the cache is expired NT_STATUS_SYNCHRONIZATION_REQUIRED
* is returned instead of NT_STATUS_OK. In this case revalidation of the cache
* is needed.
*/
NTSTATUS idmap_cache_map_sid(struct idmap_cache_ctx *cache, struct id_map *id)
{
NTSTATUS ret;
TDB_DATA keybuf, databuf;
time_t t;
char *sidkey;
char *endptr;
/* make sure it is marked as not mapped by default */
id->mapped = False;
ret = idmap_cache_build_sidkey(cache, &sidkey, id);
if (!NT_STATUS_IS_OK(ret)) return ret;
keybuf.dptr = sidkey;
keybuf.dsize = strlen(sidkey)+1;
databuf = tdb_fetch(cache->tdb, keybuf);
if (databuf.dptr == NULL) {
DEBUG(10, ("Cache entry with key = %s couldn't be found\n", sidkey));
return NT_STATUS_NONE_MAPPED;
}
t = strtol(databuf.dptr, &endptr, 10);
if ((endptr == NULL) || (*endptr != '/')) {
DEBUG(2, ("Invalid gencache data format: %s\n", databuf.dptr));
/* remove the entry */
tdb_delete(cache->tdb, keybuf);
ret = NT_STATUS_NONE_MAPPED;
goto done;
}
/* check it is not negative */
if (strcmp("IDMAP/NEGATIVE", endptr+1) != 0) {
DEBUG(10, ("Returning %s cache entry: key = %s, value = %s, "
"timeout = %s", t > time(NULL) ? "valid" :
"expired", sidkey, endptr+1, ctime(&t)));
/* this call if successful will also mark the entry as mapped */
ret = idmap_cache_fill_map(id, endptr+1);
if ( ! NT_STATUS_IS_OK(ret)) {
/* if not valid form delete the entry */
tdb_delete(cache->tdb, keybuf);
ret = NT_STATUS_NONE_MAPPED;
goto done;
}
/* here ret == NT_STATUS_OK and id->mapped = True */
if (t <= time(NULL)) {
/* We're expired, set an error code for upper layer */
ret = NT_STATUS_SYNCHRONIZATION_REQUIRED;
}
} else {
/* this is not mapped (id->mapped = False),
* and that's right as it was a negative cache hit */
ret = NT_STATUS_OK;
if (t <= time(NULL)) {
/* We're expired, delete the entry and return not mapped */
tdb_delete(cache->tdb, keybuf);
ret = NT_STATUS_NONE_MAPPED;
}
}
done:
SAFE_FREE(databuf.dptr);
talloc_free(sidkey);
return ret;
}
/* search the cahce for the ID an return a mapping if found *
*
* 3 cases are possible
*
* 1 map found
* in this case id->mapped = True and NT_STATUS_OK is returned
* 2 map not found
* in this case id->mapped = False and NT_STATUS_NONE_MAPPED is returned
* 3 negative cache found
* in this case id->mapped = False and NT_STATUS_OK is returned
*
* As a special case if the cache is expired NT_STATUS_SYNCHRONIZATION_REQUIRED
* is returned instead of NT_STATUS_OK. In this case revalidation of the cache
* is needed.
*/
NTSTATUS idmap_cache_map_id(struct idmap_cache_ctx *cache, struct id_map *id)
{
NTSTATUS ret;
TDB_DATA keybuf, databuf;
time_t t;
char *idkey;
char *endptr;
/* make sure it is marked as not mapped by default */
id->mapped = False;
ret = idmap_cache_build_idkey(cache, &idkey, id);
if (!NT_STATUS_IS_OK(ret)) return ret;
keybuf.dptr = idkey;
keybuf.dsize = strlen(idkey)+1;
databuf = tdb_fetch(cache->tdb, keybuf);
if (databuf.dptr == NULL) {
DEBUG(10, ("Cache entry with key = %s couldn't be found\n", idkey));
return NT_STATUS_NONE_MAPPED;
}
t = strtol(databuf.dptr, &endptr, 10);
if ((endptr == NULL) || (*endptr != '/')) {
DEBUG(2, ("Invalid gencache data format: %s\n", databuf.dptr));
/* remove the entry */
tdb_delete(cache->tdb, keybuf);
ret = NT_STATUS_NONE_MAPPED;
goto done;
}
/* check it is not negative */
if (strcmp("IDMAP/NEGATIVE", endptr+1) != 0) {
DEBUG(10, ("Returning %s cache entry: key = %s, value = %s, "
"timeout = %s", t > time(NULL) ? "valid" :
"expired", idkey, endptr+1, ctime(&t)));
/* this call if successful will also mark the entry as mapped */
ret = idmap_cache_fill_map(id, endptr+1);
if ( ! NT_STATUS_IS_OK(ret)) {
/* if not valid form delete the entry */
tdb_delete(cache->tdb, keybuf);
ret = NT_STATUS_NONE_MAPPED;
goto done;
}
/* here ret == NT_STATUS_OK and id->mapped = True */
if (t <= time(NULL)) {
/* We're expired, set an error code for upper layer */
ret = NT_STATUS_SYNCHRONIZATION_REQUIRED;
}
} else {
/* this is not mapped (id->mapped = False),
* and that's right as it was a negative cache hit */
ret = NT_STATUS_OK;
if (t <= time(NULL)) {
/* We're expired, delete the entry and return not mapped */
tdb_delete(cache->tdb, keybuf);
ret = NT_STATUS_NONE_MAPPED;
}
}
done:
SAFE_FREE(databuf.dptr);
talloc_free(idkey);
return ret;
}

1349
source/nsswitch/idmap_ldap.c Normal file

File diff suppressed because it is too large Load Diff

231
source/nsswitch/idmap_nss.c Normal file
View File

@@ -0,0 +1,231 @@
/*
Unix SMB/CIFS implementation.
idmap PASSDB 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 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"
#include "winbindd.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_IDMAP
/*****************************
Initialise idmap database.
*****************************/
static NTSTATUS idmap_nss_int_init(struct idmap_domain *dom, const char *compat_params)
{
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)
{
TALLOC_CTX *ctx;
struct winbindd_domain *wdom;
BOOL winbind_env;
int i;
wdom = find_lookup_domain_from_name(dom->name);
if (!wdom) {
DEBUG(2, ("Can't lookup domain %s\n", dom->name));
return NT_STATUS_NO_SUCH_DOMAIN;
}
ctx = talloc_new(dom);
if ( ! ctx) {
DEBUG(0, ("Out of memory!\n"));
return NT_STATUS_NO_MEMORY;
}
/* avoid any possible recursion in winbindd,
* these calls are aimed at getting info
* out of alternative nss dbs anyway */
winbind_env = winbind_env_set();
winbind_off();
for (i = 0; ids[i]; i++) {
struct passwd *pw;
struct group *gr;
const char *name;
enum lsa_SidType type;
switch (ids[i]->xid.type) {
case ID_TYPE_UID:
pw = getpwuid((uid_t)ids[i]->xid.id);
if (!pw) {
ids[i]->mapped = False;
continue;
}
name = pw->pw_name;
break;
case ID_TYPE_GID:
gr = getgrgid((gid_t)ids[i]->xid.id);
if (!gr) {
ids[i]->mapped = False;
continue;
}
name = gr->gr_name;
break;
default: /* ?? */
ids[i]->mapped = False;
continue;
}
/* Lookup name from PDC using lsa_lookup_names() */
if (!winbindd_lookup_sid_by_name(ctx, wdom, dom->name, name, ids[i]->sid, &type)) {
ids[i]->mapped = False;
continue;
}
/* make sure it is marked as unmapped if types do not match */
ids[i]->mapped = False;
switch (type) {
case SID_NAME_USER:
if (ids[i]->xid.type == ID_TYPE_UID) {
ids[i]->mapped = True;
}
break;
case SID_NAME_DOM_GRP:
case SID_NAME_ALIAS:
case SID_NAME_WKN_GRP:
if (ids[i]->xid.type == ID_TYPE_GID) {
ids[i]->mapped = True;
}
break;
default:
break;
}
}
/* allow winbindd calls again, if they were enabled */
if (!winbind_env) {
winbind_on();
}
talloc_free(ctx);
return NT_STATUS_OK;
}
/**********************************
lookup a set of sids.
**********************************/
static NTSTATUS idmap_nss_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
{
TALLOC_CTX *ctx;
BOOL winbind_env;
int i;
ctx = talloc_new(dom);
if ( ! ctx) {
DEBUG(0, ("Out of memory!\n"));
return NT_STATUS_NO_MEMORY;
}
/* avoid any possible recursion in winbindd,
* these calls are aimed at getting info
* out of alternative nss dbs anyway */
winbind_env = winbind_env_set();
winbind_off();
for (i = 0; ids[i]; i++) {
struct passwd *pw;
struct group *gr;
enum lsa_SidType type;
char *dom_name = NULL;
char *name = NULL;
if (!winbindd_lookup_name_by_sid(ctx, ids[i]->sid, &dom_name, &name, &type)) {
ids[i]->mapped = False;
continue;
}
/* make sure it is marked as unmapped if types do not match */
ids[i]->mapped = False;
switch (type) {
case SID_NAME_USER:
/* this will find also all lower case name and use username level */
pw = Get_Pwnam(name);
if (pw) {
ids[i]->xid.id = pw->pw_uid;
ids[i]->xid.type = ID_TYPE_UID;
ids[i]->mapped = True;
}
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]->mapped = True;
}
break;
default:
break;
}
TALLOC_FREE(dom_name);
TALLOC_FREE(name);
}
/* allow winbindd calls again, if they were enabled */
if (!winbind_env) {
winbind_on();
}
talloc_free(ctx);
return NT_STATUS_OK;
}
/**********************************
Close the idmap tdb instance
**********************************/
static NTSTATUS idmap_nss_close(struct idmap_domain *dom)
{
return NT_STATUS_OK;
}
static 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,
.close_fn = idmap_nss_close
};
NTSTATUS idmap_nss_init(void)
{
return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "nss", &nss_methods);
}

View File

@@ -0,0 +1,123 @@
/*
Unix SMB/CIFS implementation.
idmap PASSDB 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 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"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_IDMAP
/*****************************
Initialise idmap database.
*****************************/
static NTSTATUS idmap_pdb_init(struct idmap_domain *dom, const char *compat_params)
{
return NT_STATUS_OK;
}
/**********************************
lookup a set of unix ids.
**********************************/
static NTSTATUS idmap_pdb_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
{
int i;
for (i = 0; ids[i]; i++) {
switch (ids[i]->xid.type) {
case ID_TYPE_UID:
ids[i]->mapped = pdb_uid_to_sid((uid_t)ids[i]->xid.id, ids[i]->sid);
break;
case ID_TYPE_GID:
ids[i]->mapped = pdb_gid_to_sid((gid_t)ids[i]->xid.id, ids[i]->sid);
break;
default: /* ?? */
ids[i]->mapped = False;
}
}
return NT_STATUS_OK;
}
/**********************************
lookup a set of sids.
**********************************/
static NTSTATUS idmap_pdb_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
{
int i;
for (i = 0; ids[i]; i++) {
enum lsa_SidType type;
union unid_t id;
if (pdb_sid_to_id(ids[i]->sid, &id, &type)) {
switch (type) {
case SID_NAME_USER:
ids[i]->xid.id = id.uid;
ids[i]->xid.type = ID_TYPE_UID;
ids[i]->mapped = True;
break;
case SID_NAME_DOM_GRP:
case SID_NAME_ALIAS:
case SID_NAME_WKN_GRP:
ids[i]->xid.id = id.gid;
ids[i]->xid.type = ID_TYPE_GID;
ids[i]->mapped = True;
break;
default: /* ?? */
/* make sure it is marked as unmapped */
ids[i]->mapped = False;
break;
}
} else {
/* Query Failed */
ids[i]->mapped = False;
}
}
return NT_STATUS_OK;
}
/**********************************
Close the idmap tdb instance
**********************************/
static NTSTATUS idmap_pdb_close(struct idmap_domain *dom)
{
return NT_STATUS_OK;
}
static struct idmap_methods passdb_methods = {
.init = idmap_pdb_init,
.unixids_to_sids = idmap_pdb_unixids_to_sids,
.sids_to_unixids = idmap_pdb_sids_to_unixids,
.close_fn =idmap_pdb_close
};
NTSTATUS idmap_passdb_init(void)
{
return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "passdb", &passdb_methods);
}

262
source/nsswitch/idmap_rid.c Normal file
View File

@@ -0,0 +1,262 @@
/*
* idmap_rid: static map between Active Directory/NT RIDs and RFC 2307 accounts
* Copyright (C) Guenther Deschner, 2004
* Copyright (C) Sumit Bose, 2004
*
* 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"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_IDMAP
struct idmap_rid_context {
DOM_SID dom_sid;
uint32_t low_id;
uint32_t high_id;
uint32_t base_rid;
};
/* compat params can't be used because of the completely different way we support multiple domains in the new idmap */
static NTSTATUS idmap_rid_initialize(struct idmap_domain *dom, const char *compat_params)
{
NTSTATUS ret;
struct idmap_rid_context *ctx;
char *config_option = NULL;
const char *range;
ctx = talloc_zero(dom, struct idmap_rid_context);
if ( ! ctx) {
DEBUG(0, ("Out of memory!\n"));
return NT_STATUS_NO_MEMORY;
}
config_option = talloc_asprintf(ctx, "idmap config %s", dom->name);
if ( ! config_option) {
DEBUG(0, ("Out of memory!\n"));
ret = NT_STATUS_NO_MEMORY;
goto failed;
}
range = lp_parm_const_string(-1, config_option, "range", NULL);
if (( ! range) ||
(sscanf(range, "%u - %u", &ctx->low_id, &ctx->high_id) != 2) ||
(ctx->low_id > ctx->high_id)) {
ctx->low_id = 0;
ctx->high_id = 0;
}
if (( ! ctx->low_id) || ( ! ctx->high_id)) {
DEBUG(1, ("ERROR: Invalid configuration, ID range missing\n"));
ret = NT_STATUS_UNSUCCESSFUL;
goto failed;
}
ctx->base_rid = lp_parm_int(-1, config_option, "base_rid", 0);
sid_copy(&ctx->dom_sid, dom->sid);
dom->private_data = ctx;
talloc_free(config_option);
return NT_STATUS_OK;
failed:
talloc_free(ctx);
return ret;
}
static NTSTATUS idmap_rid_id_to_sid(struct idmap_rid_context *ctx, struct id_map *map)
{
char *domname, *name;
enum lsa_SidType sid_type;
if (!ctx || !map) {
return NT_STATUS_INVALID_PARAMETER;
}
/* apply filters before checking */
if ((map->xid.id < ctx->low_id) || (map->xid.id > ctx->high_id)) {
DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
map->xid.id, ctx->low_id, ctx->high_id));
return NT_STATUS_NONE_MAPPED;
}
sid_compose(map->sid, &ctx->dom_sid, map->xid.id - ctx->low_id + ctx->base_rid);
if (winbindd_lookup_name_by_sid(ctx, map->sid, &domname, &name, &sid_type)) {
switch (sid_type) {
case SID_NAME_USER:
if (map->xid.type != ID_TYPE_UID) {
/* wrong type */
DEBUG(5, ("Resulting SID is of wrong ID type\n"));
return NT_STATUS_NONE_MAPPED;
}
break;
case SID_NAME_DOM_GRP:
case SID_NAME_ALIAS:
case SID_NAME_WKN_GRP:
if (map->xid.type != ID_TYPE_GID) {
/* wrong type */
DEBUG(5, ("Resulting SID is of wrong ID type\n"));
return NT_STATUS_NONE_MAPPED;
}
break;
default:
/* invalid sid, let's just leave it unmapped */
DEBUG(10, ("SID %s is UNKNOWN, skip mapping\n", sid_string_static(map->sid)));
return NT_STATUS_NONE_MAPPED;
}
} else {
DEBUG(2, ("Failed: to resolve SID\n"));
return NT_STATUS_UNSUCCESSFUL;
}
map->mapped = True;
return NT_STATUS_OK;
}
/**********************************
Single sid to id lookup function.
**********************************/
static NTSTATUS idmap_rid_sid_to_id(struct idmap_rid_context *ctx, struct id_map *map)
{
char *domname, *name;
enum lsa_SidType sid_type;
uint32_t rid;
if (!ctx || !map) {
return NT_STATUS_INVALID_PARAMETER;
}
sid_peek_rid(map->sid, &rid);
map->xid.id = rid - ctx->base_rid + ctx->low_id;
/* check if this is a valid SID and set the type */
if (winbindd_lookup_name_by_sid(ctx, map->sid, &domname, &name, &sid_type)) {
switch (sid_type) {
case SID_NAME_USER:
map->xid.type = ID_TYPE_UID;
break;
case SID_NAME_DOM_GRP:
case SID_NAME_ALIAS:
case SID_NAME_WKN_GRP:
map->xid.type = ID_TYPE_GID;
break;
default:
/* invalid sid, let's just leave it unmapped */
DEBUG(10, ("SID %s is UNKNOWN, skip mapping\n", sid_string_static(map->sid)));
return NT_STATUS_NONE_MAPPED;
}
} else {
DEBUG(2, ("Failed: to resolve SID\n"));
return NT_STATUS_UNSUCCESSFUL;
}
/* apply filters before returning result */
if ((map->xid.id < ctx->low_id) || (map->xid.id > ctx->high_id)) {
DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
map->xid.id, ctx->low_id, ctx->high_id));
return NT_STATUS_NONE_MAPPED;
}
map->mapped = True;
return NT_STATUS_OK;
}
/**********************************
lookup a set of unix ids.
**********************************/
static NTSTATUS idmap_rid_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
{
struct idmap_rid_context *ctx;
NTSTATUS ret;
int i;
ctx = talloc_get_type(dom->private_data, struct idmap_rid_context);
for (i = 0; ids[i]; i++) {
/* make sure it is marked as unmapped before resolveing */
ids[i]->mapped = False;
ret = idmap_rid_id_to_sid(ctx, ids[i]);
if (( ! NT_STATUS_IS_OK(ret)) &&
( ! NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED))) {
/* some fatal error occurred, log it */
DEBUG(3, ("Unexpected error resolving an ID (%d)\n", ids[i]->xid.id));
}
}
return NT_STATUS_OK;
}
/**********************************
lookup a set of sids.
**********************************/
static NTSTATUS idmap_rid_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
{
struct idmap_rid_context *ctx;
NTSTATUS ret;
int i;
ctx = talloc_get_type(dom->private_data, struct idmap_rid_context);
for (i = 0; ids[i]; i++) {
/* make sure it is marked as unmapped before resolveing */
ids[i]->mapped = False;
ret = idmap_rid_sid_to_id(ctx, ids[i]);
if (( ! NT_STATUS_IS_OK(ret)) &&
( ! NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED))) {
/* some fatal error occurred, log it */
DEBUG(3, ("Unexpected error resolving a SID (%s)\n",
sid_string_static(ids[i]->sid)));
}
}
return NT_STATUS_OK;
}
static NTSTATUS idmap_rid_close(struct idmap_domain *dom)
{
struct idmap_tdb_context *ctx;
if (dom->private_data) {
TALLOC_FREE(dom->private_data);
}
return NT_STATUS_OK;
}
static struct idmap_methods rid_methods = {
.init = idmap_rid_initialize,
.unixids_to_sids = idmap_rid_unixids_to_sids,
.sids_to_unixids = idmap_rid_sids_to_unixids,
.close_fn = idmap_rid_close
};
NTSTATUS idmap_rid_init(void)
{
return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "rid", &rid_methods);
}

1213
source/nsswitch/idmap_tdb.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,160 @@
/*
Unix SMB/CIFS implementation.
ID Mapping
Copyright (C) Simo Sorce 2003
Copyright (C) Jeremy Allison 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 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"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_IDMAP
/*****************************************************************
Returns the SID mapped to the given UID.
If mapping is not possible returns an error.
*****************************************************************/
NTSTATUS idmap_uid_to_sid(DOM_SID *sid, uid_t uid)
{
NTSTATUS ret;
struct id_map map;
struct id_map *maps[2];
DEBUG(10,("uid = [%lu]\n", (unsigned long)uid));
map.sid = sid;
map.xid.type = ID_TYPE_UID;
map.xid.id = uid;
maps[0] = &map;
maps[1] = NULL;
ret = idmap_unixids_to_sids(maps);
if ( ! NT_STATUS_IS_OK(ret)) {
DEBUG(10, ("error mapping uid [%lu]\n", (unsigned long)uid));
return ret;
}
if ( ! map.mapped) {
DEBUG(10, ("uid [%lu] not mapped\n", (unsigned long)uid));
return NT_STATUS_NONE_MAPPED;
}
return NT_STATUS_OK;
}
/*****************************************************************
Returns SID mapped to the given GID.
If mapping is not possible returns an error.
*****************************************************************/
NTSTATUS idmap_gid_to_sid(DOM_SID *sid, gid_t gid)
{
NTSTATUS ret;
struct id_map map;
struct id_map *maps[2];
DEBUG(10,("gid = [%lu]\n", (unsigned long)gid));
map.sid = sid;
map.xid.type = ID_TYPE_GID;
map.xid.id = gid;
maps[0] = &map;
maps[1] = NULL;
ret = idmap_unixids_to_sids(maps);
if ( ! NT_STATUS_IS_OK(ret)) {
DEBUG(10, ("error mapping gid [%lu]\n", (unsigned long)gid));
return ret;
}
if ( ! map.mapped) {
DEBUG(10, ("gid [%lu] not mapped\n", (unsigned long)gid));
return NT_STATUS_NONE_MAPPED;
}
return NT_STATUS_OK;
}
/*****************************************************************
Returns the UID mapped to the given SID.
If mapping is not possible or SID maps to a GID returns an error.
*****************************************************************/
NTSTATUS idmap_sid_to_uid(DOM_SID *sid, uid_t *uid)
{
NTSTATUS ret;
struct id_map map;
struct id_map *maps[2];
DEBUG(10,("idmap_sid_to_uid: sid = [%s]\n", sid_string_static(sid)));
map.sid = sid;
maps[0] = &map;
maps[1] = NULL;
ret = idmap_sids_to_unixids(maps);
if ( ! NT_STATUS_IS_OK(ret)) {
DEBUG(10, ("error mapping sid [%s] to uid\n", sid_string_static(sid)));
return ret;
}
if (( ! map.mapped) || (map.xid.type != ID_TYPE_UID)) {
DEBUG(10, ("sid [%s] not mapped to an uid [%u,%u,%u]\n", sid_string_static(sid), map.mapped, map.xid.type, map.xid.id));
return NT_STATUS_NONE_MAPPED;
}
*uid = map.xid.id;
return NT_STATUS_OK;
}
/*****************************************************************
Returns the GID mapped to the given SID.
If mapping is not possible or SID maps to a UID returns an error.
*****************************************************************/
NTSTATUS idmap_sid_to_gid(DOM_SID *sid, gid_t *gid)
{
NTSTATUS ret;
struct id_map map;
struct id_map *maps[2];
DEBUG(10,("idmap_sid_to_gid: sid = [%s]\n", sid_string_static(sid)));
map.sid = sid;
maps[0] = &map;
maps[1] = NULL;
ret = idmap_sids_to_unixids(maps);
if ( ! NT_STATUS_IS_OK(ret)) {
DEBUG(10, ("error mapping sid [%s] to gid\n", sid_string_static(sid)));
return ret;
}
if (( ! map.mapped) || (map.xid.type != ID_TYPE_GID)) {
DEBUG(10, ("sid [%s] not mapped to an gid [%u,%u,%u]\n", sid_string_static(sid), map.mapped, map.xid.type, map.xid.id));
return NT_STATUS_NONE_MAPPED;
}
*gid = map.xid.id;
return NT_STATUS_OK;
}

View File

@@ -357,6 +357,74 @@ BOOL winbind_gid_to_sid(DOM_SID *sid, gid_t gid)
return (result == NSS_STATUS_SUCCESS);
}
/* Call winbindd to convert SID to uid */
BOOL winbind_sids_to_unixids(struct id_map *ids, int num_ids)
{
struct winbindd_request request;
struct winbindd_response response;
int result;
DOM_SID *sids;
int i;
/* Initialise request */
ZERO_STRUCT(request);
ZERO_STRUCT(response);
request.extra_len = num_ids * sizeof(DOM_SID);
sids = SMB_MALLOC(request.extra_len);
for (i = 0; i < num_ids; i++) {
sid_copy(&sids[i], ids[i].sid);
}
request.extra_data.data = (char *)sids;
/* Make request */
result = winbindd_request_response(WINBINDD_SIDS_TO_XIDS, &request, &response);
/* Copy out result */
if (result == NSS_STATUS_SUCCESS) {
struct unixid *wid = (struct unixid *)response.extra_data.data;
for (i = 0; i < num_ids; i++) {
if (wid[i].type == -1) {
ids[i].mapped = False;
} else {
ids[i].mapped = True;
ids[i].xid.type = wid[i].type;
ids[i].xid.id = wid[i].id;
}
}
}
SAFE_FREE(request.extra_data.data);
SAFE_FREE(response.extra_data.data);
return (result == NSS_STATUS_SUCCESS);
}
BOOL winbind_idmap_dump_maps(TALLOC_CTX *memctx, const char *file)
{
struct winbindd_request request;
struct winbindd_response response;
int result;
ZERO_STRUCT(request);
ZERO_STRUCT(response);
request.extra_data.data = SMB_STRDUP(file);
request.extra_len = strlen(request.extra_data.data) + 1;
result = winbindd_request_response(WINBINDD_DUMP_MAPS, &request, &response);
SAFE_FREE(request.extra_data.data);
return (result == NSS_STATUS_SUCCESS);
}
BOOL winbind_allocate_uid(uid_t *uid)
{
struct winbindd_request request;
@@ -407,6 +475,70 @@ BOOL winbind_allocate_gid(gid_t *gid)
return True;
}
BOOL winbind_set_mapping(const struct id_map *map)
{
struct winbindd_request request;
struct winbindd_response response;
int result;
/* Initialise request */
ZERO_STRUCT(request);
ZERO_STRUCT(response);
/* Make request */
request.data.dual_idmapset.id = map->xid.id;
request.data.dual_idmapset.type = map->xid.type;
sid_to_string(request.data.dual_idmapset.sid, map->sid);
result = winbindd_request_response(WINBINDD_SET_MAPPING, &request, &response);
return (result == NSS_STATUS_SUCCESS);
}
BOOL winbind_set_uid_hwm(unsigned long id)
{
struct winbindd_request request;
struct winbindd_response response;
int result;
/* Initialise request */
ZERO_STRUCT(request);
ZERO_STRUCT(response);
/* Make request */
request.data.dual_idmapset.id = id;
request.data.dual_idmapset.type = ID_TYPE_UID;
result = winbindd_request_response(WINBINDD_SET_HWM, &request, &response);
return (result == NSS_STATUS_SUCCESS);
}
BOOL winbind_set_gid_hwm(unsigned long id)
{
struct winbindd_request request;
struct winbindd_response response;
int result;
/* Initialise request */
ZERO_STRUCT(request);
ZERO_STRUCT(response);
/* Make request */
request.data.dual_idmapset.id = id;
request.data.dual_idmapset.type = ID_TYPE_GID;
result = winbindd_request_response(WINBINDD_SET_HWM, &request, &response);
return (result == NSS_STATUS_SUCCESS);
}
/* Fetch the list of groups a user is a member of from winbindd. This is
used by winbind_getgroups. */

View File

@@ -234,11 +234,16 @@ static struct winbindd_dispatch_table {
{ WINBINDD_SID_TO_GID, winbindd_sid_to_gid, "SID_TO_GID" },
{ WINBINDD_UID_TO_SID, winbindd_uid_to_sid, "UID_TO_SID" },
{ WINBINDD_GID_TO_SID, winbindd_gid_to_sid, "GID_TO_SID" },
{ WINBINDD_SIDS_TO_XIDS, winbindd_sids_to_unixids, "SIDS_TO_XIDS" },
{ WINBINDD_ALLOCATE_UID, winbindd_allocate_uid, "ALLOCATE_UID" },
{ WINBINDD_ALLOCATE_GID, winbindd_allocate_gid, "ALLOCATE_GID" },
{ WINBINDD_SET_MAPPING, winbindd_set_mapping, "SET_MAPPING" },
{ WINBINDD_SET_HWM, winbindd_set_hwm, "SET_HWMS" },
/* Miscellaneous */
{ WINBINDD_DUMP_MAPS, winbindd_dump_maps, "DUMP_MAPS" },
{ WINBINDD_CHECK_MACHACC, winbindd_check_machine_acct, "CHECK_MACHACC" },
{ WINBINDD_PING, winbindd_ping, "PING" },
{ WINBINDD_INFO, winbindd_info, "INFO" },
@@ -877,8 +882,6 @@ static void process_loop(void)
/* Main function */
struct winbindd_state server_state; /* Server state information */
int main(int argc, char **argv, char **envp)
{
pstring logfile;
@@ -982,16 +985,10 @@ int main(int argc, char **argv, char **envp)
namecache_enable();
/* Check winbindd parameters are valid */
ZERO_STRUCT(server_state);
/* Winbind daemon initialisation */
if ( (!winbindd_param_init()) || (!winbindd_upgrade_idmap()) ||
(!idmap_init(lp_idmap_backend())) ) {
DEBUG(1, ("Could not init idmap -- netlogon proxy only\n"));
idmap_set_proxyonly();
if ( ! NT_STATUS_IS_OK(idmap_init()) ) {
DEBUG(1, ("Could not init idmap! - Sid/[UG]id mapping will not be available\n"));
}
/* Unblock all signals we are interested in as they may have been

View File

@@ -107,16 +107,6 @@ struct getpwent_user {
/* Server state structure */
struct winbindd_state {
/* User and group id pool */
uid_t uid_low, uid_high; /* Range of uids to allocate */
gid_t gid_low, gid_high; /* Range of gids to allocate */
};
extern struct winbindd_state server_state; /* Server information */
typedef struct {
char *acct_name;
char *full_name;

View File

@@ -112,7 +112,7 @@ void do_async_domain(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
&state->response, do_async_recv, state);
}
static void idmap_set_mapping_recv(TALLOC_CTX *mem_ctx, BOOL success,
static void winbindd_set_mapping_recv(TALLOC_CTX *mem_ctx, BOOL success,
struct winbindd_response *response,
void *c, void *private_data)
{
@@ -133,30 +133,26 @@ static void idmap_set_mapping_recv(TALLOC_CTX *mem_ctx, BOOL success,
cont(private_data, True);
}
void idmap_set_mapping_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
unid_t id, int id_type,
void winbindd_set_mapping_async(TALLOC_CTX *mem_ctx, const struct id_map *map,
void (*cont)(void *private_data, BOOL success),
void *private_data)
{
struct winbindd_request request;
ZERO_STRUCT(request);
request.cmd = WINBINDD_DUAL_IDMAPSET;
if (id_type == ID_USERID)
request.data.dual_idmapset.uid = id.uid;
else
request.data.dual_idmapset.gid = id.gid;
request.data.dual_idmapset.type = id_type;
sid_to_string(request.data.dual_idmapset.sid, sid);
request.cmd = WINBINDD_DUAL_SET_MAPPING;
request.data.dual_idmapset.id = map->xid.id;
request.data.dual_idmapset.type = map->xid.type;
sid_to_string(request.data.dual_idmapset.sid, map->sid);
do_async(mem_ctx, idmap_child(), &request, idmap_set_mapping_recv,
do_async(mem_ctx, idmap_child(), &request, winbindd_set_mapping_recv,
(void *)cont, private_data);
}
enum winbindd_result winbindd_dual_idmapset(struct winbindd_domain *domain,
enum winbindd_result winbindd_dual_set_mapping(struct winbindd_domain *domain,
struct winbindd_cli_state *state)
{
struct id_map map;
DOM_SID sid;
unid_t id;
NTSTATUS result;
DEBUG(3, ("[%5lu]: dual_idmapset\n", (unsigned long)state->pid));
@@ -164,60 +160,171 @@ enum winbindd_result winbindd_dual_idmapset(struct winbindd_domain *domain,
if (!string_to_sid(&sid, state->request.data.dual_idmapset.sid))
return WINBINDD_ERROR;
if (state->request.data.dual_idmapset.type == ID_USERID)
id.uid = state->request.data.dual_idmapset.uid;
else
id.gid = state->request.data.dual_idmapset.gid;
map.sid = &sid;
map.xid.id = state->request.data.dual_idmapset.id;
map.xid.type = state->request.data.dual_idmapset.type;
result = idmap_set_mapping(
&sid, id,
(enum idmap_type)state->request.data.dual_idmapset.type);
result = idmap_set_mapping(&map);
return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
}
static void idmap_sid2uid_recv(TALLOC_CTX *mem_ctx, BOOL success,
static void winbindd_set_hwm_recv(TALLOC_CTX *mem_ctx, BOOL success,
struct winbindd_response *response,
void *c, void *private_data);
void *c, void *private_data)
{
void (*cont)(void *priv, BOOL succ) = (void (*)(void *, BOOL))c;
void idmap_sid2uid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid, BOOL alloc,
void (*cont)(void *private_data, BOOL success, uid_t uid),
if (!success) {
DEBUG(5, ("Could not trigger idmap_set_hwm\n"));
cont(private_data, False);
return;
}
if (response->result != WINBINDD_OK) {
DEBUG(5, ("idmap_set_hwm returned an error\n"));
cont(private_data, False);
return;
}
cont(private_data, True);
}
void winbindd_set_hwm_async(TALLOC_CTX *mem_ctx, const struct unixid *xid,
void (*cont)(void *private_data, BOOL success),
void *private_data)
{
struct winbindd_request request;
ZERO_STRUCT(request);
request.cmd = WINBINDD_DUAL_SID2UID;
sid_to_string(request.data.dual_sid2id.sid, sid);
request.data.dual_sid2id.alloc = alloc;
do_async(mem_ctx, idmap_child(), &request, idmap_sid2uid_recv,
request.cmd = WINBINDD_DUAL_SET_HWM;
request.data.dual_idmapset.id = xid->id;
request.data.dual_idmapset.type = xid->type;
do_async(mem_ctx, idmap_child(), &request, winbindd_set_hwm_recv,
(void *)cont, private_data);
}
enum winbindd_result winbindd_dual_sid2uid(struct winbindd_domain *domain,
enum winbindd_result winbindd_dual_set_hwm(struct winbindd_domain *domain,
struct winbindd_cli_state *state)
{
DOM_SID sid;
struct unixid xid;
NTSTATUS result;
DEBUG(3, ("[%5lu]: sid to uid %s\n", (unsigned long)state->pid,
state->request.data.dual_sid2id.sid));
DEBUG(3, ("[%5lu]: dual_set_hwm\n", (unsigned long)state->pid));
if (!string_to_sid(&sid, state->request.data.dual_sid2id.sid)) {
DEBUG(1, ("Could not get convert sid %s from string\n",
state->request.data.dual_sid2id.sid));
xid.id = state->request.data.dual_idmapset.id;
xid.type = state->request.data.dual_idmapset.type;
switch (xid.type) {
case ID_TYPE_UID:
result = idmap_set_uid_hwm(&xid);
break;
case ID_TYPE_GID:
result = idmap_set_gid_hwm(&xid);
break;
default:
return WINBINDD_ERROR;
}
/* Find uid for this sid and return it, possibly ask the slow remote
* idmap */
result = idmap_sid_to_uid(&sid, &(state->response.data.uid),
state->request.data.dual_sid2id.alloc ?
0 : IDMAP_FLAG_QUERY_ONLY);
return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
}
static void idmap_sid2uid_recv(TALLOC_CTX *mem_ctx, BOOL success,
static void winbindd_sids2xids_recv(TALLOC_CTX *mem_ctx, BOOL success,
struct winbindd_response *response,
void *c, void *private_data)
{
void (*cont)(void *priv, BOOL succ, void *, int) =
(void (*)(void *, BOOL, void *, int))c;
if (!success) {
DEBUG(5, ("Could not trigger sids2xids\n"));
cont(private_data, False, NULL, 0);
return;
}
if (response->result != WINBINDD_OK) {
DEBUG(5, ("sids2xids returned an error\n"));
cont(private_data, False, NULL, 0);
return;
}
cont(private_data, True, response->extra_data.data, response->length - sizeof(response));
}
void winbindd_sids2xids_async(TALLOC_CTX *mem_ctx, void *sids, int size,
void (*cont)(void *private_data, BOOL success, void *data, int len),
void *private_data)
{
struct winbindd_request request;
ZERO_STRUCT(request);
request.cmd = WINBINDD_DUAL_SIDS2XIDS;
request.extra_data.data = sids;
request.extra_len = size;
do_async(mem_ctx, idmap_child(), &request, winbindd_sids2xids_recv,
(void *)cont, private_data);
}
enum winbindd_result winbindd_dual_sids2xids(struct winbindd_domain *domain,
struct winbindd_cli_state *state)
{
DOM_SID *sids;
struct unixid *xids;
struct id_map **ids;
NTSTATUS result;
int num, i;
DEBUG(3, ("[%5lu]: sids to unix ids\n", (unsigned long)state->pid));
sids = (DOM_SID *)state->request.extra_data.data;
num = state->request.extra_len / sizeof(DOM_SID);
ids = talloc_zero_array(state->mem_ctx, struct id_map *, num + 1);
if ( ! ids) {
DEBUG(0, ("Out of memory!\n"));
return WINBINDD_ERROR;
}
for (i = 0; i < num; i++) {
ids[i] = talloc(ids, struct id_map);
if ( ! ids[i]) {
DEBUG(0, ("Out of memory!\n"));
talloc_free(ids);
return WINBINDD_ERROR;
}
ids[i]->sid = &sids[i];
}
result = idmap_sids_to_unixids(ids);
if (NT_STATUS_IS_OK(result)) {
xids = SMB_MALLOC_ARRAY(struct unixid, num);
if ( ! xids) {
DEBUG(0, ("Out of memory!\n"));
talloc_free(ids);
return WINBINDD_ERROR;
}
for (i = 0; i < num; i++) {
if (ids[i]->mapped) {
xids[i].type = ids[i]->xid.type;
xids[i].id = ids[i]->xid.id;
} else {
xids[i].type = -1;
}
}
state->response.length = sizeof(state->response) + (sizeof(struct unixid) * num);
state->response.extra_data.data = xids;
} else {
DEBUG (2, ("idmap_sids_to_unixids returned an error: 0x%08x\n", NT_STATUS_V(result)));
talloc_free(ids);
return WINBINDD_ERROR;
}
talloc_free(ids);
return WINBINDD_OK;
}
static void winbindd_sid2uid_recv(TALLOC_CTX *mem_ctx, BOOL success,
struct winbindd_response *response,
void *c, void *private_data)
{
@@ -239,6 +346,41 @@ static void idmap_sid2uid_recv(TALLOC_CTX *mem_ctx, BOOL success,
cont(private_data, True, response->data.uid);
}
void winbindd_sid2uid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
void (*cont)(void *private_data, BOOL success, uid_t uid),
void *private_data)
{
struct winbindd_request request;
ZERO_STRUCT(request);
request.cmd = WINBINDD_DUAL_SID2UID;
sid_to_string(request.data.dual_sid2id.sid, sid);
do_async(mem_ctx, idmap_child(), &request, winbindd_sid2uid_recv,
(void *)cont, private_data);
}
enum winbindd_result winbindd_dual_sid2uid(struct winbindd_domain *domain,
struct winbindd_cli_state *state)
{
DOM_SID sid;
NTSTATUS result;
DEBUG(3, ("[%5lu]: sid to uid %s\n", (unsigned long)state->pid,
state->request.data.dual_sid2id.sid));
if (!string_to_sid(&sid, state->request.data.dual_sid2id.sid)) {
DEBUG(1, ("Could not get convert sid %s from string\n",
state->request.data.dual_sid2id.sid));
return WINBINDD_ERROR;
}
/* Find uid for this sid and return it, possibly ask the slow remote idmap */
result = idmap_sid_to_uid(&sid, &(state->response.data.uid));
return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
}
#if 0 /* not used */
static void uid2name_recv(TALLOC_CTX *mem_ctx, BOOL success,
struct winbindd_response *response,
void *c, void *private_data);
@@ -255,6 +397,7 @@ void winbindd_uid2name_async(TALLOC_CTX *mem_ctx, uid_t uid,
do_async(mem_ctx, idmap_child(), &request, uid2name_recv,
(void *)cont, private_data);
}
#endif /* not used */
enum winbindd_result winbindd_dual_uid2name(struct winbindd_domain *domain,
struct winbindd_cli_state *state)
@@ -275,6 +418,7 @@ enum winbindd_result winbindd_dual_uid2name(struct winbindd_domain *domain,
return WINBINDD_OK;
}
#if 0 /* not used */
static void uid2name_recv(TALLOC_CTX *mem_ctx, BOOL success,
struct winbindd_response *response,
void *c, void *private_data)
@@ -313,6 +457,7 @@ static void winbindd_name2uid_async(TALLOC_CTX *mem_ctx, const char *name,
do_async(mem_ctx, idmap_child(), &request, name2uid_recv,
(void *)cont, private_data);
}
#endif /* not used */
enum winbindd_result winbindd_dual_name2uid(struct winbindd_domain *domain,
struct winbindd_cli_state *state)
@@ -335,6 +480,7 @@ enum winbindd_result winbindd_dual_name2uid(struct winbindd_domain *domain,
return WINBINDD_OK;
}
#if 0 /* not used */
static void name2uid_recv(TALLOC_CTX *mem_ctx, BOOL success,
struct winbindd_response *response,
void *c, void *private_data)
@@ -356,63 +502,9 @@ static void name2uid_recv(TALLOC_CTX *mem_ctx, BOOL success,
cont(private_data, True, response->data.uid);
}
#endif /* not used */
static void idmap_sid2gid_recv(TALLOC_CTX *mem_ctx, BOOL success,
struct winbindd_response *response,
void *c, void *private_data);
void idmap_sid2gid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid, BOOL alloc,
void (*cont)(void *private_data, BOOL success, gid_t gid),
void *private_data)
{
struct winbindd_request request;
ZERO_STRUCT(request);
request.cmd = WINBINDD_DUAL_SID2GID;
sid_to_string(request.data.dual_sid2id.sid, sid);
DEBUG(7,("idmap_sid2gid_async: Resolving %s to a gid\n",
request.data.dual_sid2id.sid));
request.data.dual_sid2id.alloc = alloc;
do_async(mem_ctx, idmap_child(), &request, idmap_sid2gid_recv,
(void *)cont, private_data);
}
enum winbindd_result winbindd_dual_sid2gid(struct winbindd_domain *domain,
struct winbindd_cli_state *state)
{
DOM_SID sid;
NTSTATUS result;
DEBUG(3, ("[%5lu]: sid to gid %s\n", (unsigned long)state->pid,
state->request.data.dual_sid2id.sid));
if (!string_to_sid(&sid, state->request.data.dual_sid2id.sid)) {
DEBUG(1, ("Could not get convert sid %s from string\n",
state->request.data.dual_sid2id.sid));
return WINBINDD_ERROR;
}
/* Find gid for this sid and return it, possibly ask the slow remote
* idmap */
result = idmap_sid_to_gid(&sid, &state->response.data.gid,
state->request.data.dual_sid2id.alloc ?
0 : IDMAP_FLAG_QUERY_ONLY);
/* If the lookup failed, the perhaps we need to look
at the passdb for local groups */
if ( !NT_STATUS_IS_OK(result) ) {
if ( sid_to_gid( &sid, &(state->response.data.gid) ) ) {
result = NT_STATUS_OK;
}
}
return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
}
static void idmap_sid2gid_recv(TALLOC_CTX *mem_ctx, BOOL success,
static void winbindd_sid2gid_recv(TALLOC_CTX *mem_ctx, BOOL success,
struct winbindd_response *response,
void *c, void *private_data)
{
@@ -434,6 +526,46 @@ static void idmap_sid2gid_recv(TALLOC_CTX *mem_ctx, BOOL success,
cont(private_data, True, response->data.gid);
}
void winbindd_sid2gid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
void (*cont)(void *private_data, BOOL success, gid_t gid),
void *private_data)
{
struct winbindd_request request;
ZERO_STRUCT(request);
request.cmd = WINBINDD_DUAL_SID2GID;
sid_to_string(request.data.dual_sid2id.sid, sid);
DEBUG(7,("idmap_sid2gid_async: Resolving %s to a gid\n",
request.data.dual_sid2id.sid));
do_async(mem_ctx, idmap_child(), &request, winbindd_sid2gid_recv,
(void *)cont, private_data);
}
enum winbindd_result winbindd_dual_sid2gid(struct winbindd_domain *domain,
struct winbindd_cli_state *state)
{
DOM_SID sid;
NTSTATUS result;
DEBUG(3, ("[%5lu]: sid to gid %s\n", (unsigned long)state->pid,
state->request.data.dual_sid2id.sid));
if (!string_to_sid(&sid, state->request.data.dual_sid2id.sid)) {
DEBUG(1, ("Could not get convert sid %s from string\n",
state->request.data.dual_sid2id.sid));
return WINBINDD_ERROR;
}
/* Find gid for this sid and return it, possibly ask the slow remote idmap */
result = idmap_sid_to_gid(&sid, &state->response.data.gid);
DEBUG(10, ("winbindd_dual_sid2gid: 0x%08x - %s - %u\n", NT_STATUS_V(result), sid_string_static(&sid), state->response.data.gid));
return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
}
static void gid2name_recv(TALLOC_CTX *mem_ctx, BOOL success,
struct winbindd_response *response,
void *c, void *private_data)
@@ -485,6 +617,7 @@ enum winbindd_result winbindd_dual_gid2name(struct winbindd_domain *domain,
return WINBINDD_OK;
}
#if 0 /* not used */
static void name2gid_recv(TALLOC_CTX *mem_ctx, BOOL success,
struct winbindd_response *response,
void *c, void *private_data);
@@ -501,6 +634,7 @@ static void winbindd_name2gid_async(TALLOC_CTX *mem_ctx, const char *name,
do_async(mem_ctx, idmap_child(), &request, name2gid_recv,
(void *)cont, private_data);
}
#endif /* not used */
enum winbindd_result winbindd_dual_name2gid(struct winbindd_domain *domain,
struct winbindd_cli_state *state)
@@ -523,6 +657,7 @@ enum winbindd_result winbindd_dual_name2gid(struct winbindd_domain *domain,
return WINBINDD_OK;
}
#if 0 /* not used */
static void name2gid_recv(TALLOC_CTX *mem_ctx, BOOL success,
struct winbindd_response *response,
void *c, void *private_data)
@@ -544,7 +679,7 @@ static void name2gid_recv(TALLOC_CTX *mem_ctx, BOOL success,
cont(private_data, True, response->data.gid);
}
#endif /* not used */
static void lookupsid_recv(TALLOC_CTX *mem_ctx, BOOL success,
struct winbindd_response *response,
@@ -603,8 +738,8 @@ enum winbindd_result winbindd_dual_lookupsid(struct winbindd_domain *domain,
{
enum lsa_SidType type;
DOM_SID sid;
fstring name;
fstring dom_name;
char *name = NULL;
char *dom_name = NULL;
/* Ensure null termination */
state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
@@ -623,6 +758,8 @@ enum winbindd_result winbindd_dual_lookupsid(struct winbindd_domain *domain,
if (!winbindd_lookup_name_by_sid(state->mem_ctx, &sid, dom_name, name,
&type)) {
TALLOC_FREE(dom_name);
TALLOC_FREE(name);
return WINBINDD_ERROR;
}
@@ -630,6 +767,8 @@ enum winbindd_result winbindd_dual_lookupsid(struct winbindd_domain *domain,
fstrcpy(state->response.data.name.name, name);
state->response.data.name.type = type;
TALLOC_FREE(dom_name);
TALLOC_FREE(name);
return WINBINDD_OK;
}
@@ -1173,331 +1312,6 @@ static void gettoken_recvaliases(void *private_data, BOOL success,
state->cont(state->private_data, True, state->sids, state->num_sids);
}
struct sid2uid_state {
TALLOC_CTX *mem_ctx;
DOM_SID sid;
char *username;
uid_t uid;
void (*cont)(void *private_data, BOOL success, uid_t uid);
void *private_data;
};
static void sid2uid_lookup_sid_recv(void *private_data, BOOL success,
const char *dom_name, const char *name,
enum lsa_SidType type);
static void sid2uid_noalloc_recv(void *private_data, BOOL success, uid_t uid);
static void sid2uid_alloc_recv(void *private_data, BOOL success, uid_t uid);
static void sid2uid_name2uid_recv(void *private_data, BOOL success, uid_t uid);
static void sid2uid_set_mapping_recv(void *private_data, BOOL success);
void winbindd_sid2uid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
void (*cont)(void *private_data, BOOL success,
uid_t uid),
void *private_data)
{
struct sid2uid_state *state;
NTSTATUS result;
uid_t uid;
if (idmap_proxyonly()) {
DEBUG(10, ("idmap proxy only\n"));
cont(private_data, False, 0);
return;
}
/* Query only the local tdb, everything else might possibly block */
result = idmap_sid_to_uid(sid, &uid, IDMAP_FLAG_QUERY_ONLY|IDMAP_FLAG_CACHE_ONLY);
if (NT_STATUS_IS_OK(result)) {
cont(private_data, True, uid);
return;
}
state = TALLOC_ZERO_P(mem_ctx, struct sid2uid_state);
if (state == NULL) {
DEBUG(0, ("talloc failed\n"));
cont(private_data, False, 0);
return;
}
state->mem_ctx = mem_ctx;
state->sid = *sid;
state->cont = cont;
state->private_data = private_data;
/* Let's see if it's really a user before allocating a uid */
winbindd_lookupsid_async(mem_ctx, sid, sid2uid_lookup_sid_recv, state);
}
static void sid2uid_lookup_sid_recv(void *private_data, BOOL success,
const char *dom_name, const char *name,
enum lsa_SidType type)
{
struct sid2uid_state *state =
talloc_get_type_abort(private_data, struct sid2uid_state);
if (!success) {
DEBUG(5, ("Could not trigger lookup_sid\n"));
state->cont(state->private_data, False, 0);
return;
}
if ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER)) {
DEBUG(5, ("SID is not a user\n"));
state->cont(state->private_data, False, 0);
return;
}
state->username = talloc_strdup(state->mem_ctx, name);
/* Ask the possibly blocking remote IDMAP */
idmap_sid2uid_async(state->mem_ctx, &state->sid, False,
sid2uid_noalloc_recv, state);
}
static void sid2uid_noalloc_recv(void *private_data, BOOL success, uid_t uid)
{
struct sid2uid_state *state =
talloc_get_type_abort(private_data, struct sid2uid_state);
if (success) {
DEBUG(10, ("found uid for sid %s in remote backend\n",
sid_string_static(&state->sid)));
state->cont(state->private_data, True, uid);
return;
}
if (lp_winbind_trusted_domains_only() &&
(sid_compare_domain(&state->sid, &find_our_domain()->sid) == 0)) {
DEBUG(10, ("Trying to go via nss\n"));
winbindd_name2uid_async(state->mem_ctx, state->username,
sid2uid_name2uid_recv, state);
return;
}
/* To be done: Here we're going to try the unixinfo pipe */
/* Now allocate a uid */
idmap_sid2uid_async(state->mem_ctx, &state->sid, True,
sid2uid_alloc_recv, state);
}
static void sid2uid_alloc_recv(void *private_data, BOOL success, uid_t uid)
{
struct sid2uid_state *state =
talloc_get_type_abort(private_data, struct sid2uid_state);
if (!success) {
DEBUG(5, ("Could not allocate uid\n"));
state->cont(state->private_data, False, 0);
return;
}
state->cont(state->private_data, True, uid);
}
static void sid2uid_name2uid_recv(void *private_data, BOOL success, uid_t uid)
{
struct sid2uid_state *state =
talloc_get_type_abort(private_data, struct sid2uid_state);
unid_t id;
if (!success) {
DEBUG(5, ("Could not find uid for name %s\n",
state->username));
state->cont(state->private_data, False, 0);
return;
}
state->uid = uid;
id.uid = uid;
idmap_set_mapping_async(state->mem_ctx, &state->sid, id, ID_USERID,
sid2uid_set_mapping_recv, state);
}
static void sid2uid_set_mapping_recv(void *private_data, BOOL success)
{
struct sid2uid_state *state =
talloc_get_type_abort(private_data, struct sid2uid_state);
if (!success) {
DEBUG(5, ("Could not set ID mapping for sid %s\n",
sid_string_static(&state->sid)));
state->cont(state->private_data, False, 0);
return;
}
state->cont(state->private_data, True, state->uid);
}
struct sid2gid_state {
TALLOC_CTX *mem_ctx;
DOM_SID sid;
char *groupname;
gid_t gid;
void (*cont)(void *private_data, BOOL success, gid_t gid);
void *private_data;
};
static void sid2gid_lookup_sid_recv(void *private_data, BOOL success,
const char *dom_name, const char *name,
enum lsa_SidType type);
static void sid2gid_noalloc_recv(void *private_data, BOOL success, gid_t gid);
static void sid2gid_alloc_recv(void *private_data, BOOL success, gid_t gid);
static void sid2gid_name2gid_recv(void *private_data, BOOL success, gid_t gid);
static void sid2gid_set_mapping_recv(void *private_data, BOOL success);
void winbindd_sid2gid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
void (*cont)(void *private_data, BOOL success,
gid_t gid),
void *private_data)
{
struct sid2gid_state *state;
NTSTATUS result;
gid_t gid;
if (idmap_proxyonly()) {
DEBUG(10, ("idmap proxy only\n"));
cont(private_data, False, 0);
return;
}
/* Query only the local tdb, everything else might possibly block */
result = idmap_sid_to_gid(sid, &gid, IDMAP_FLAG_QUERY_ONLY|IDMAP_FLAG_CACHE_ONLY);
if (NT_STATUS_IS_OK(result)) {
cont(private_data, True, gid);
return;
}
state = TALLOC_ZERO_P(mem_ctx, struct sid2gid_state);
if (state == NULL) {
DEBUG(0, ("talloc failed\n"));
cont(private_data, False, 0);
return;
}
state->mem_ctx = mem_ctx;
state->sid = *sid;
state->cont = cont;
state->private_data = private_data;
/* Let's see if it's really a user before allocating a gid */
winbindd_lookupsid_async(mem_ctx, sid, sid2gid_lookup_sid_recv, state);
}
static void sid2gid_lookup_sid_recv(void *private_data, BOOL success,
const char *dom_name, const char *name,
enum lsa_SidType type)
{
struct sid2gid_state *state =
talloc_get_type_abort(private_data, struct sid2gid_state);
if (!success) {
DEBUG(5, ("Could not trigger lookup_sid\n"));
state->cont(state->private_data, False, 0);
return;
}
if (((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
(type != SID_NAME_WKN_GRP))) {
DEBUG(5, ("SID is not a group\n"));
state->cont(state->private_data, False, 0);
return;
}
state->groupname = talloc_strdup(state->mem_ctx, name);
/* Ask the possibly blocking remote IDMAP and allocate */
idmap_sid2gid_async(state->mem_ctx, &state->sid, False,
sid2gid_noalloc_recv, state);
}
static void sid2gid_noalloc_recv(void *private_data, BOOL success, gid_t gid)
{
struct sid2gid_state *state =
talloc_get_type_abort(private_data, struct sid2gid_state);
if (success) {
DEBUG(10, ("found gid for sid %s in remote backend\n",
sid_string_static(&state->sid)));
state->cont(state->private_data, True, gid);
return;
}
if (lp_winbind_trusted_domains_only() &&
(sid_compare_domain(&state->sid, &find_our_domain()->sid) == 0)) {
DEBUG(10, ("Trying to go via nss\n"));
winbindd_name2gid_async(state->mem_ctx, state->groupname,
sid2gid_name2gid_recv, state);
return;
}
/* To be done: Here we're going to try the unixinfo pipe */
/* Now allocate a gid */
idmap_sid2gid_async(state->mem_ctx, &state->sid, True,
sid2gid_alloc_recv, state);
}
static void sid2gid_alloc_recv(void *private_data, BOOL success, gid_t gid)
{
struct sid2gid_state *state =
talloc_get_type_abort(private_data, struct sid2gid_state);
if (!success) {
DEBUG(5, ("Could not allocate gid\n"));
state->cont(state->private_data, False, 0);
return;
}
state->cont(state->private_data, True, gid);
}
static void sid2gid_name2gid_recv(void *private_data, BOOL success, gid_t gid)
{
struct sid2gid_state *state =
talloc_get_type_abort(private_data, struct sid2gid_state);
unid_t id;
if (!success) {
DEBUG(5, ("Could not find gid for name %s\n",
state->groupname));
state->cont(state->private_data, False, 0);
return;
}
state->gid = gid;
id.gid = gid;
idmap_set_mapping_async(state->mem_ctx, &state->sid, id, ID_GROUPID,
sid2gid_set_mapping_recv, state);
}
static void sid2gid_set_mapping_recv(void *private_data, BOOL success)
{
struct sid2gid_state *state =
talloc_get_type_abort(private_data, struct sid2gid_state);
if (!success) {
DEBUG(5, ("Could not set ID mapping for sid %s\n",
sid_string_static(&state->sid)));
state->cont(state->private_data, False, 0);
return;
}
state->cont(state->private_data, True, state->gid);
}
static void query_user_recv(TALLOC_CTX *mem_ctx, BOOL success,
struct winbindd_response *response,
void *c, void *private_data)
@@ -1588,7 +1402,7 @@ enum winbindd_result winbindd_dual_uid2sid(struct winbindd_domain *domain,
(unsigned long) state->request.data.uid));
/* Find sid for this uid and return it, possibly ask the slow remote idmap */
result = idmap_uid_to_sid(&sid, state->request.data.uid, IDMAP_FLAG_NONE);
result = idmap_uid_to_sid(&sid, state->request.data.uid);
if (NT_STATUS_IS_OK(result)) {
sid_to_string(state->response.data.sid.sid, &sid);
@@ -1645,7 +1459,7 @@ enum winbindd_result winbindd_dual_gid2sid(struct winbindd_domain *domain,
(unsigned long) state->request.data.gid));
/* Find sid for this gid and return it, possibly ask the slow remote idmap */
result = idmap_gid_to_sid(&sid, state->request.data.gid, IDMAP_FLAG_NONE);
result = idmap_gid_to_sid(&sid, state->request.data.gid);
if (NT_STATUS_IS_OK(result)) {
sid_to_string(state->response.data.sid.sid, &sid);
@@ -1658,3 +1472,49 @@ enum winbindd_result winbindd_dual_gid2sid(struct winbindd_domain *domain,
return WINBINDD_ERROR;
}
static void winbindd_dump_id_maps_recv(TALLOC_CTX *mem_ctx, BOOL success,
struct winbindd_response *response,
void *c, void *private_data)
{
void (*cont)(void *priv, BOOL succ) =
(void (*)(void *, BOOL))c;
if (!success) {
DEBUG(5, ("Could not trigger a map dump\n"));
cont(private_data, False);
return;
}
if (response->result != WINBINDD_OK) {
DEBUG(5, ("idmap dump maps returned an error\n"));
cont(private_data, False);
return;
}
cont(private_data, True);
}
void winbindd_dump_maps_async(TALLOC_CTX *mem_ctx, void *data, int size,
void (*cont)(void *private_data, BOOL success),
void *private_data)
{
struct winbindd_request request;
ZERO_STRUCT(request);
request.cmd = WINBINDD_DUAL_DUMP_MAPS;
request.extra_data.data = data;
request.extra_len = size;
do_async(mem_ctx, idmap_child(), &request, winbindd_dump_id_maps_recv,
(void *)cont, private_data);
}
enum winbindd_result winbindd_dual_dump_maps(struct winbindd_domain *domain,
struct winbindd_cli_state *state)
{
DEBUG(3, ("[%5lu]: dual dump maps\n", (unsigned long)state->pid));
idmap_dump_maps((char *)state->request.extra_data.data);
return WINBINDD_OK;
}

View File

@@ -357,13 +357,16 @@ static struct winbindd_child_dispatch_table child_dispatch_table[] = {
{ WINBINDD_CHECK_MACHACC, winbindd_dual_check_machine_acct, "CHECK_MACHACC" },
{ WINBINDD_DUAL_SID2UID, winbindd_dual_sid2uid, "DUAL_SID2UID" },
{ WINBINDD_DUAL_SID2GID, winbindd_dual_sid2gid, "DUAL_SID2GID" },
{ WINBINDD_DUAL_SIDS2XIDS, winbindd_dual_sids2xids, "DUAL_SIDS2XIDS" },
{ WINBINDD_DUAL_UID2SID, winbindd_dual_uid2sid, "DUAL_UID2SID" },
{ WINBINDD_DUAL_GID2SID, winbindd_dual_gid2sid, "DUAL_GID2SID" },
{ WINBINDD_DUAL_UID2NAME, winbindd_dual_uid2name, "DUAL_UID2NAME" },
{ WINBINDD_DUAL_NAME2UID, winbindd_dual_name2uid, "DUAL_NAME2UID" },
{ WINBINDD_DUAL_GID2NAME, winbindd_dual_gid2name, "DUAL_GID2NAME" },
{ WINBINDD_DUAL_NAME2GID, winbindd_dual_name2gid, "DUAL_NAME2GID" },
{ WINBINDD_DUAL_IDMAPSET, winbindd_dual_idmapset, "DUAL_IDMAPSET" },
{ WINBINDD_DUAL_SET_MAPPING, winbindd_dual_set_mapping, "DUAL_SET_MAPPING" },
{ WINBINDD_DUAL_SET_HWM, winbindd_dual_set_hwm, "DUAL_SET_HWMS" },
{ WINBINDD_DUAL_DUMP_MAPS, winbindd_dual_dump_maps, "DUAL_DUMP_MAPS" },
{ WINBINDD_DUAL_USERINFO, winbindd_dual_userinfo, "DUAL_USERINFO" },
{ WINBINDD_ALLOCATE_UID, winbindd_dual_allocate_uid, "ALLOCATE_UID" },
{ WINBINDD_ALLOCATE_GID, winbindd_dual_allocate_gid, "ALLOCATE_GID" },

View File

@@ -124,9 +124,7 @@ static BOOL fill_grent_mem(struct winbindd_domain *domain,
if (sys_getpeereid(state->sock, &ret_uid)==0) {
/* We know who's asking - look up their SID if
it's one we've mapped before. */
status = idmap_uid_to_sid(&querying_user_sid,
ret_uid,
IDMAP_FLAG_QUERY_ONLY|IDMAP_FLAG_CACHE_ONLY);
status = idmap_uid_to_sid(&querying_user_sid, ret_uid);
if (NT_STATUS_IS_OK(status)) {
pquerying_user_sid = &querying_user_sid;
DEBUG(10,("fill_grent_mem: querying uid %u -> %s\n",
@@ -399,7 +397,7 @@ void winbindd_getgrnam(struct winbindd_cli_state *state)
/* Try to get the GID */
status = idmap_sid_to_gid(&group_sid, &gid, 0);
status = idmap_sid_to_gid(&group_sid, &gid);
if (NT_STATUS_IS_OK(status)) {
goto got_gid;
@@ -444,18 +442,20 @@ static void getgrgid_got_sid(struct winbindd_cli_state *state, DOM_SID group_sid
{
struct winbindd_domain *domain;
enum lsa_SidType name_type;
fstring dom_name;
fstring group_name;
char *dom_name = NULL;
char *group_name = NULL;
size_t gr_mem_len;
size_t num_gr_mem;
char *gr_mem;
/* Get name from sid */
if (!winbindd_lookup_name_by_sid(state->mem_ctx, &group_sid, dom_name,
group_name, &name_type)) {
if (!winbindd_lookup_name_by_sid(state->mem_ctx, &group_sid, &dom_name,
&group_name, &name_type)) {
DEBUG(1, ("could not lookup sid\n"));
request_error(state);
TALLOC_FREE(group_name);
TALLOC_FREE(dom_name);
return;
}
@@ -466,6 +466,8 @@ static void getgrgid_got_sid(struct winbindd_cli_state *state, DOM_SID group_sid
if (!domain) {
DEBUG(1,("Can't find domain from sid\n"));
request_error(state);
TALLOC_FREE(group_name);
TALLOC_FREE(dom_name);
return;
}
@@ -476,6 +478,8 @@ static void getgrgid_got_sid(struct winbindd_cli_state *state, DOM_SID group_sid
DEBUG(1, ("name '%s' is not a local or domain group: %d\n",
group_name, name_type));
request_error(state);
TALLOC_FREE(group_name);
TALLOC_FREE(dom_name);
return;
}
@@ -485,6 +489,8 @@ static void getgrgid_got_sid(struct winbindd_cli_state *state, DOM_SID group_sid
&num_gr_mem,
&gr_mem, &gr_mem_len)) {
request_error(state);
TALLOC_FREE(group_name);
TALLOC_FREE(dom_name);
return;
}
@@ -497,6 +503,9 @@ static void getgrgid_got_sid(struct winbindd_cli_state *state, DOM_SID group_sid
state->response.length += gr_mem_len;
state->response.extra_data.data = gr_mem;
TALLOC_FREE(group_name);
TALLOC_FREE(dom_name);
request_ok(state);
}
@@ -534,32 +543,10 @@ static void getgrgid_recv(void *private_data, BOOL success, const char *sid)
/* Return a group structure from a gid number */
void winbindd_getgrgid(struct winbindd_cli_state *state)
{
DOM_SID group_sid;
NTSTATUS status;
DEBUG(3, ("[%5lu]: getgrgid %lu\n", (unsigned long)state->pid,
(unsigned long)state->request.data.gid));
/* Bug out if the gid isn't in the winbind range */
if ((state->request.data.gid < server_state.gid_low) ||
(state->request.data.gid > server_state.gid_high)) {
request_error(state);
return;
}
/* Get sid from gid */
status = idmap_gid_to_sid(&group_sid, state->request.data.gid, IDMAP_FLAG_NONE);
if (NT_STATUS_IS_OK(status)) {
/* This is a remote one */
getgrgid_got_sid(state, group_sid);
return;
}
DEBUG(10,("winbindd_getgrgid: gid %lu not found in cache, try with the async interface\n",
(unsigned long)state->request.data.gid));
/* always use the async interface */
winbindd_gid2sid_async(state->mem_ctx, state->request.data.gid, getgrgid_recv, state);
}
@@ -855,8 +842,7 @@ void winbindd_getgrent(struct winbindd_cli_state *state)
sid_copy(&group_sid, &domain->sid);
sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid);
if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid,
&group_gid, 0))) {
if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &group_gid))) {
union unid_t id;
enum lsa_SidType type;

View File

@@ -35,7 +35,7 @@
/* Update this when you change the interface. */
#define WINBIND_INTERFACE_VERSION 17
#define WINBIND_INTERFACE_VERSION 18
/* Have to deal with time_t being 4 or 8 bytes due to structure alignment.
On a 64bit Linux box, we have to support a constant structure size
@@ -95,14 +95,19 @@ enum winbindd_cmd {
WINBINDD_SID_TO_UID,
WINBINDD_SID_TO_GID,
WINBINDD_SIDS_TO_XIDS,
WINBINDD_UID_TO_SID,
WINBINDD_GID_TO_SID,
WINBINDD_ALLOCATE_UID,
WINBINDD_ALLOCATE_GID,
WINBINDD_SET_MAPPING,
WINBINDD_SET_HWM,
/* Miscellaneous other stuff */
WINBINDD_DUMP_MAPS,
WINBINDD_CHECK_MACHACC, /* Check machine account pw works */
WINBINDD_PING, /* Just tell me winbind is running */
WINBINDD_INFO, /* Various bit of info. Currently just tidbits */
@@ -140,9 +145,12 @@ enum winbindd_cmd {
* between parent and children */
WINBINDD_DUAL_SID2UID,
WINBINDD_DUAL_SID2GID,
WINBINDD_DUAL_SIDS2XIDS,
WINBINDD_DUAL_UID2SID,
WINBINDD_DUAL_GID2SID,
WINBINDD_DUAL_IDMAPSET,
WINBINDD_DUAL_SET_MAPPING,
WINBINDD_DUAL_SET_HWM,
WINBINDD_DUAL_DUMP_MAPS,
/* Wrapper around possibly blocking unix nss calls */
WINBINDD_DUAL_UID2NAME,
@@ -286,13 +294,11 @@ struct winbindd_request {
struct {
fstring sid;
fstring name;
BOOL alloc;
} dual_sid2id;
struct {
int type;
uid_t uid;
gid_t gid;
fstring sid;
uint32 type;
uint32 id;
} dual_idmapset;
BOOL list_all_domains;

View File

@@ -167,45 +167,6 @@ struct winbindd_child *idmap_child(void)
/* Convert a sid to a uid. We assume we only have one rid attached to the
sid. */
static void sid2uid_recv(void *private_data, BOOL success, uid_t uid);
void winbindd_sid_to_uid(struct winbindd_cli_state *state)
{
DOM_SID sid;
NTSTATUS result;
/* Ensure null termination */
state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
DEBUG(3, ("[%5lu]: sid to uid %s\n", (unsigned long)state->pid,
state->request.data.sid));
if (idmap_proxyonly()) {
DEBUG(8, ("IDMAP proxy only\n"));
request_error(state);
return;
}
if (!string_to_sid(&sid, state->request.data.sid)) {
DEBUG(1, ("Could not get convert sid %s from string\n",
state->request.data.sid));
request_error(state);
return;
}
/* Query only the local tdb, everything else might possibly block */
result = idmap_sid_to_uid(&sid, &state->response.data.uid,
IDMAP_FLAG_QUERY_ONLY|IDMAP_FLAG_CACHE_ONLY);
if (NT_STATUS_IS_OK(result)) {
request_ok(state);
return;
}
winbindd_sid2uid_async(state->mem_ctx, &sid, sid2uid_recv, state);
}
static void sid2uid_recv(void *private_data, BOOL success, uid_t uid)
{
struct winbindd_cli_state *state =
@@ -222,28 +183,16 @@ static void sid2uid_recv(void *private_data, BOOL success, uid_t uid)
request_ok(state);
}
/* Convert a sid to a gid. We assume we only have one rid attached to the
sid.*/
static void sid2gid_recv(void *private_data, BOOL success, gid_t gid);
void winbindd_sid_to_gid(struct winbindd_cli_state *state)
void winbindd_sid_to_uid(struct winbindd_cli_state *state)
{
DOM_SID sid;
NTSTATUS result;
/* Ensure null termination */
state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
DEBUG(3, ("[%5lu]: sid to gid %s\n", (unsigned long)state->pid,
DEBUG(3, ("[%5lu]: sid to uid %s\n", (unsigned long)state->pid,
state->request.data.sid));
if (idmap_proxyonly()) {
DEBUG(8, ("IDMAP proxy only\n"));
request_error(state);
return;
}
if (!string_to_sid(&sid, state->request.data.sid)) {
DEBUG(1, ("Could not get convert sid %s from string\n",
state->request.data.sid));
@@ -251,19 +200,13 @@ void winbindd_sid_to_gid(struct winbindd_cli_state *state)
return;
}
/* Query only the local tdb, everything else might possibly block */
result = idmap_sid_to_gid(&sid, &state->response.data.gid,
IDMAP_FLAG_QUERY_ONLY|IDMAP_FLAG_CACHE_ONLY);
if (NT_STATUS_IS_OK(result)) {
request_ok(state);
return;
}
winbindd_sid2gid_async(state->mem_ctx, &sid, sid2gid_recv, state);
/* always use the async interface (may block) */
winbindd_sid2uid_async(state->mem_ctx, &sid, sid2uid_recv, state);
}
/* Convert a sid to a gid. We assume we only have one rid attached to the
sid.*/
static void sid2gid_recv(void *private_data, BOOL success, gid_t gid)
{
struct winbindd_cli_state *state =
@@ -280,57 +223,133 @@ static void sid2gid_recv(void *private_data, BOOL success, gid_t gid)
request_ok(state);
}
/* Convert a uid to a sid */
struct uid2sid_state {
struct winbindd_cli_state *cli_state;
uid_t uid;
fstring name;
DOM_SID sid;
enum lsa_SidType type;
};
static void uid2sid_uid2name_recv(void *private_data, BOOL success,
const char *username);
static void uid2sid_lookupname_recv(void *private_data, BOOL success,
const DOM_SID *sid,
enum lsa_SidType type);
static void uid2sid_idmap_set_mapping_recv(void *private_data, BOOL success);
static void uid2sid_recv(void *private_data, BOOL success, const char *sid);
void winbindd_uid_to_sid(struct winbindd_cli_state *state)
void winbindd_sid_to_gid(struct winbindd_cli_state *state)
{
DOM_SID sid;
NTSTATUS status;
DEBUG(3, ("[%5lu]: uid to sid %lu\n", (unsigned long)state->pid,
(unsigned long)state->request.data.uid));
/* Ensure null termination */
state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
if (idmap_proxyonly()) {
DEBUG(8, ("IDMAP proxy only\n"));
DEBUG(3, ("[%5lu]: sid to gid %s\n", (unsigned long)state->pid,
state->request.data.sid));
if (!string_to_sid(&sid, state->request.data.sid)) {
DEBUG(1, ("Could not get convert sid %s from string\n",
state->request.data.sid));
request_error(state);
return;
}
status = idmap_uid_to_sid(&sid, state->request.data.uid,
IDMAP_FLAG_QUERY_ONLY|IDMAP_FLAG_CACHE_ONLY);
/* always use the async interface (may block) */
winbindd_sid2gid_async(state->mem_ctx, &sid, sid2gid_recv, state);
}
if (NT_STATUS_IS_OK(status)) {
sid_to_string(state->response.data.sid.sid, &sid);
state->response.data.sid.type = SID_NAME_USER;
request_ok(state);
static void sids2xids_recv(void *private_data, BOOL success, void *data, int len)
{
struct winbindd_cli_state *state =
talloc_get_type_abort(private_data, struct winbindd_cli_state);
if (!success) {
DEBUG(5, ("Could not convert sids to xids\n"));
request_error(state);
return;
}
winbindd_uid2sid_async(state->mem_ctx, state->request.data.uid, uid2sid_recv, state);
state->response.extra_data.data = data;
state->response.length = sizeof(state->response) + len;
request_ok(state);
}
void winbindd_sids_to_unixids(struct winbindd_cli_state *state)
{
DEBUG(3, ("[%5lu]: sids to xids\n", (unsigned long)state->pid));
winbindd_sids2xids_async(state->mem_ctx,
state->request.extra_data.data,
state->request.extra_len,
sids2xids_recv, state);
}
static void set_mapping_recv(void *private_data, BOOL success)
{
struct winbindd_cli_state *state =
talloc_get_type_abort(private_data, struct winbindd_cli_state);
if (!success) {
DEBUG(5, ("Could not set sid mapping\n"));
request_error(state);
return;
}
request_ok(state);
}
void winbindd_set_mapping(struct winbindd_cli_state *state)
{
struct id_map map;
DOM_SID sid;
DEBUG(3, ("[%5lu]: set id map\n", (unsigned long)state->pid));
if ( ! state->privileged) {
DEBUG(0, ("Only root is allowed to set mappings!\n"));
request_error(state);
return;
}
if (!string_to_sid(&sid, state->request.data.dual_idmapset.sid)) {
DEBUG(1, ("Could not get convert sid %s from string\n",
state->request.data.sid));
request_error(state);
return;
}
map.sid = &sid;
map.xid.id = state->request.data.dual_idmapset.id;
map.xid.type = state->request.data.dual_idmapset.type;
winbindd_set_mapping_async(state->mem_ctx, &map,
set_mapping_recv, state);
}
static void set_hwm_recv(void *private_data, BOOL success)
{
struct winbindd_cli_state *state =
talloc_get_type_abort(private_data, struct winbindd_cli_state);
if (!success) {
DEBUG(5, ("Could not set sid mapping\n"));
request_error(state);
return;
}
request_ok(state);
}
void winbindd_set_hwm(struct winbindd_cli_state *state)
{
struct unixid xid;
DEBUG(3, ("[%5lu]: set hwm\n", (unsigned long)state->pid));
if ( ! state->privileged) {
DEBUG(0, ("Only root is allowed to set mappings!\n"));
request_error(state);
return;
}
xid.id = state->request.data.dual_idmapset.id;
xid.type = state->request.data.dual_idmapset.type;
winbindd_set_hwm_async(state->mem_ctx, &xid, set_hwm_recv, state);
}
/* Convert a uid to a sid */
static void uid2sid_recv(void *private_data, BOOL success, const char *sid)
{
struct winbindd_cli_state *state =
(struct winbindd_cli_state *)private_data;
struct uid2sid_state *uid2sid_state;
if (success) {
DEBUG(10,("uid2sid: uid %lu has sid %s\n",
@@ -341,141 +360,25 @@ static void uid2sid_recv(void *private_data, BOOL success, const char *sid)
return;
}
/* preexisitng mapping not found go on */
if (is_in_uid_range(state->request.data.uid)) {
/* This is winbind's, so we should better have succeeded
* above. */
request_error(state);
return;
}
/* The only chance that this is correct is that winbind trusted
* domains only = yes, and the user exists in nss and the domain. */
if (!lp_winbind_trusted_domains_only()) {
request_error(state);
return;
}
uid2sid_state = TALLOC_ZERO_P(state->mem_ctx, struct uid2sid_state);
if (uid2sid_state == NULL) {
DEBUG(0, ("talloc failed\n"));
request_error(state);
return;
}
uid2sid_state->cli_state = state;
uid2sid_state->uid = state->request.data.uid;
winbindd_uid2name_async(state->mem_ctx, state->request.data.uid,
uid2sid_uid2name_recv, uid2sid_state);
}
static void uid2sid_uid2name_recv(void *private_data, BOOL success,
const char *username)
void winbindd_uid_to_sid(struct winbindd_cli_state *state)
{
struct uid2sid_state *state =
talloc_get_type_abort(private_data, struct uid2sid_state);
DEBUG(3, ("[%5lu]: uid to sid %lu\n", (unsigned long)state->pid,
(unsigned long)state->request.data.uid));
DEBUG(10, ("uid2sid: uid %lu has name %s\n",
(unsigned long)state->uid, username));
fstrcpy(state->name, username);
if (!success) {
request_error(state->cli_state);
return;
}
winbindd_lookupname_async(state->cli_state->mem_ctx,
find_our_domain()->name, username,
uid2sid_lookupname_recv, state);
}
static void uid2sid_lookupname_recv(void *private_data, BOOL success,
const DOM_SID *sid, enum lsa_SidType type)
{
struct uid2sid_state *state =
talloc_get_type_abort(private_data, struct uid2sid_state);
unid_t id;
if ((!success) || (type != SID_NAME_USER)) {
request_error(state->cli_state);
return;
}
state->sid = *sid;
state->type = type;
id.uid = state->uid;
idmap_set_mapping_async(state->cli_state->mem_ctx, sid, id, ID_USERID,
uid2sid_idmap_set_mapping_recv, state );
}
static void uid2sid_idmap_set_mapping_recv(void *private_data, BOOL success)
{
struct uid2sid_state *state =
talloc_get_type_abort(private_data, struct uid2sid_state);
/* don't fail if we can't store it */
sid_to_string(state->cli_state->response.data.sid.sid, &state->sid);
state->cli_state->response.data.sid.type = state->type;
request_ok(state->cli_state);
/* always go via the async interface (may block) */
winbindd_uid2sid_async(state->mem_ctx, state->request.data.uid, uid2sid_recv, state);
}
/* Convert a gid to a sid */
struct gid2sid_state {
struct winbindd_cli_state *cli_state;
gid_t gid;
fstring name;
DOM_SID sid;
enum lsa_SidType type;
};
static void gid2sid_gid2name_recv(void *private_data, BOOL success,
const char *groupname);
static void gid2sid_lookupname_recv(void *private_data, BOOL success,
const DOM_SID *sid,
enum lsa_SidType type);
static void gid2sid_idmap_set_mapping_recv(void *private_data, BOOL success);
static void gid2sid_recv(void *private_data, BOOL success, const char *sid);
void winbindd_gid_to_sid(struct winbindd_cli_state *state)
{
DOM_SID sid;
NTSTATUS status;
DEBUG(3, ("[%5lu]: gid to sid %lu\n", (unsigned long)state->pid,
(unsigned long)state->request.data.gid));
if (idmap_proxyonly()) {
DEBUG(8, ("IDMAP proxy only\n"));
request_error(state);
return;
}
status = idmap_gid_to_sid(&sid, state->request.data.gid,
IDMAP_FLAG_QUERY_ONLY|IDMAP_FLAG_CACHE_ONLY);
if (NT_STATUS_IS_OK(status)) {
sid_to_string(state->response.data.sid.sid, &sid);
state->response.data.sid.type = SID_NAME_DOM_GRP;
request_ok(state);
return;
}
winbindd_gid2sid_async(state->mem_ctx, state->request.data.gid, gid2sid_recv, state);
}
static void gid2sid_recv(void *private_data, BOOL success, const char *sid)
{
struct winbindd_cli_state *state =
(struct winbindd_cli_state *)private_data;
struct gid2sid_state *gid2sid_state;
if (success) {
DEBUG(10,("gid2sid: gid %lu has sid %s\n",
@@ -486,92 +389,18 @@ static void gid2sid_recv(void *private_data, BOOL success, const char *sid)
return;
}
/* preexisitng mapping not found go on */
if (is_in_gid_range(state->request.data.gid)) {
/* This is winbind's, so we should better have succeeded
* above. */
request_error(state);
return;
}
/* The only chance that this is correct is that winbind trusted
* domains only = yes, and the user exists in nss and the domain. */
if (!lp_winbind_trusted_domains_only()) {
request_error(state);
return;
}
/* The only chance that this is correct is that winbind trusted
* domains only = yes, and the user exists in nss and the domain. */
gid2sid_state = TALLOC_ZERO_P(state->mem_ctx, struct gid2sid_state);
if (gid2sid_state == NULL) {
DEBUG(0, ("talloc failed\n"));
request_error(state);
return;
}
gid2sid_state->cli_state = state;
gid2sid_state->gid = state->request.data.gid;
winbindd_gid2name_async(state->mem_ctx, state->request.data.gid,
gid2sid_gid2name_recv, gid2sid_state);
}
static void gid2sid_gid2name_recv(void *private_data, BOOL success,
const char *username)
void winbindd_gid_to_sid(struct winbindd_cli_state *state)
{
struct gid2sid_state *state =
talloc_get_type_abort(private_data, struct gid2sid_state);
DEBUG(3, ("[%5lu]: gid to sid %lu\n", (unsigned long)state->pid,
(unsigned long)state->request.data.gid));
DEBUG(10, ("gid2sid: gid %lu has name %s\n",
(unsigned long)state->gid, username));
fstrcpy(state->name, username);
if (!success) {
request_error(state->cli_state);
return;
}
winbindd_lookupname_async(state->cli_state->mem_ctx,
find_our_domain()->name, username,
gid2sid_lookupname_recv, state);
}
static void gid2sid_lookupname_recv(void *private_data, BOOL success,
const DOM_SID *sid, enum lsa_SidType type)
{
struct gid2sid_state *state =
talloc_get_type_abort(private_data, struct gid2sid_state);
unid_t id;
if ((!success) ||
((type != SID_NAME_DOM_GRP) && (type!=SID_NAME_ALIAS))) {
request_error(state->cli_state);
return;
}
state->sid = *sid;
state->type = type;
id.gid = state->gid;
idmap_set_mapping_async(state->cli_state->mem_ctx, sid, id, ID_GROUPID,
gid2sid_idmap_set_mapping_recv, state );
}
static void gid2sid_idmap_set_mapping_recv(void *private_data, BOOL success)
{
struct gid2sid_state *state =
(struct gid2sid_state *)private_data;
/* don't fail if we can't store it */
sid_to_string(state->cli_state->response.data.sid.sid, &state->sid);
state->cli_state->response.data.sid.type = state->type;
request_ok(state->cli_state);
/* always use async calls (may block) */
winbindd_gid2sid_async(state->mem_ctx, state->request.data.gid, gid2sid_recv, state);
}
void winbindd_allocate_uid(struct winbindd_cli_state *state)
@@ -589,12 +418,12 @@ void winbindd_allocate_uid(struct winbindd_cli_state *state)
enum winbindd_result winbindd_dual_allocate_uid(struct winbindd_domain *domain,
struct winbindd_cli_state *state)
{
union unid_t id;
struct unixid xid;
if (!NT_STATUS_IS_OK(idmap_allocate_id(&id, ID_USERID))) {
if (!NT_STATUS_IS_OK(idmap_allocate_uid(&xid))) {
return WINBINDD_ERROR;
}
state->response.data.uid = id.uid;
state->response.data.uid = xid.id;
return WINBINDD_OK;
}
@@ -613,12 +442,42 @@ void winbindd_allocate_gid(struct winbindd_cli_state *state)
enum winbindd_result winbindd_dual_allocate_gid(struct winbindd_domain *domain,
struct winbindd_cli_state *state)
{
union unid_t id;
struct unixid xid;
if (!NT_STATUS_IS_OK(idmap_allocate_id(&id, ID_GROUPID))) {
if (!NT_STATUS_IS_OK(idmap_allocate_gid(&xid))) {
return WINBINDD_ERROR;
}
state->response.data.gid = id.gid;
state->response.data.gid = xid.id;
return WINBINDD_OK;
}
static void dump_maps_recv(void *private_data, BOOL success)
{
struct winbindd_cli_state *state =
talloc_get_type_abort(private_data, struct winbindd_cli_state);
if (!success) {
DEBUG(5, ("Could not dump maps\n"));
request_error(state);
return;
}
request_ok(state);
}
void winbindd_dump_maps(struct winbindd_cli_state *state)
{
if ( ! state->privileged) {
DEBUG(0, ("Only root is allowed to ask for an idmap dump!\n"));
request_error(state);
return;
}
DEBUG(3, ("[%5lu]: dump maps\n", (unsigned long)state->pid));
winbindd_dump_maps_async(state->mem_ctx,
state->request.extra_data.data,
state->request.extra_len,
dump_maps_recv, state);
}

View File

@@ -80,14 +80,14 @@ static BOOL winbindd_fill_pwent(char *dom_name, char *user_name,
/* Resolve the uid number */
if (!NT_STATUS_IS_OK(idmap_sid_to_uid(user_sid, &pw->pw_uid, 0))) {
if (!NT_STATUS_IS_OK(idmap_sid_to_uid(user_sid, &pw->pw_uid))) {
DEBUG(1, ("error getting user id for sid %s\n", sid_to_string(sid_string, user_sid)));
return False;
}
/* Resolve the gid number */
if (!NT_STATUS_IS_OK(idmap_sid_to_gid(group_sid, &pw->pw_gid, 0))) {
if (!NT_STATUS_IS_OK(idmap_sid_to_gid(group_sid, &pw->pw_gid))) {
DEBUG(1, ("error getting group id for sid %s\n", sid_to_string(sid_string, group_sid)));
return False;
}
@@ -404,30 +404,11 @@ static void getpwuid_recv(void *private_data, BOOL success, const char *sid)
/* Return a password structure given a uid number */
void winbindd_getpwuid(struct winbindd_cli_state *state)
{
DOM_SID user_sid;
NTSTATUS status;
/* Bug out if the uid isn't in the winbind range */
if ((state->request.data.uid < server_state.uid_low ) ||
(state->request.data.uid > server_state.uid_high)) {
request_error(state);
return;
}
DEBUG(3, ("[%5lu]: getpwuid %lu\n", (unsigned long)state->pid,
(unsigned long)state->request.data.uid));
status = idmap_uid_to_sid(&user_sid, state->request.data.uid,
IDMAP_FLAG_QUERY_ONLY | IDMAP_FLAG_CACHE_ONLY);
if (NT_STATUS_IS_OK(status)) {
winbindd_getpwsid(state, &user_sid);
return;
}
DEBUG(10,("Could not find SID for uid %lu in the cache. Querying idmap backend\n",
(unsigned long)state->request.data.uid));
/* always query idmap via the async interface */
/* if this turns to be too slow we will add here a direct query to the cache */
winbindd_uid2sid_async(state->mem_ctx, state->request.data.uid, getpwuid_recv, state);
}

View File

@@ -711,14 +711,11 @@ BOOL winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
**/
BOOL winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
DOM_SID *sid,
fstring dom_name,
fstring name,
char **dom_name,
char **name,
enum lsa_SidType *type)
{
char *names;
char *dom_names;
NTSTATUS result;
BOOL rv = False;
struct winbindd_domain *domain;
domain = find_lookup_domain_from_sid(sid);
@@ -730,19 +727,18 @@ BOOL winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
/* Lookup name */
result = domain->methods->sid_to_name(domain, mem_ctx, sid, &dom_names, &names, type);
result = domain->methods->sid_to_name(domain, mem_ctx, sid, dom_name, name, type);
/* Return name and type if successful */
if ((rv = NT_STATUS_IS_OK(result))) {
fstrcpy(dom_name, dom_names);
fstrcpy(name, names);
} else {
*type = SID_NAME_UNKNOWN;
fstrcpy(name, name_deadbeef);
if (NT_STATUS_IS_OK(result)) {
return True;
}
return rv;
*type = SID_NAME_UNKNOWN;
*name = talloc_strdup(mem_ctx, name_deadbeef);
return False;
}
/* Free state information held for {set,get,end}{pw,gr}ent() functions */
@@ -769,39 +765,6 @@ void free_getent_state(struct getent_state *state)
}
}
/* Parse winbindd related parameters */
BOOL winbindd_param_init(void)
{
/* Parse winbind uid and winbind_gid parameters */
if (!lp_idmap_uid(&server_state.uid_low, &server_state.uid_high)) {
DEBUG(0, ("winbindd: idmap uid range missing or invalid\n"));
DEBUG(0, ("winbindd: cannot continue, exiting.\n"));
return False;
}
if (!lp_idmap_gid(&server_state.gid_low, &server_state.gid_high)) {
DEBUG(0, ("winbindd: idmap gid range missing or invalid\n"));
DEBUG(0, ("winbindd: cannot continue, exiting.\n"));
return False;
}
return True;
}
BOOL is_in_uid_range(uid_t uid)
{
return ((uid >= server_state.uid_low) &&
(uid <= server_state.uid_high));
}
BOOL is_in_gid_range(gid_t gid)
{
return ((gid >= server_state.gid_low) &&
(gid <= server_state.gid_high));
}
/* Is this a domain which we may assume no DOMAIN\ prefix? */
static BOOL assume_domain(const char *domain)
@@ -1027,209 +990,6 @@ int winbindd_num_clients(void)
return _num_clients;
}
/*****************************************************************************
For idmap conversion: convert one record to new format
Ancient versions (eg 2.2.3a) of winbindd_idmap.tdb mapped DOMAINNAME/rid
instead of the SID.
*****************************************************************************/
static int convert_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA data, void *state)
{
struct winbindd_domain *domain;
char *p;
DOM_SID sid;
uint32 rid;
fstring keystr;
fstring dom_name;
TDB_DATA key2;
BOOL *failed = (BOOL *)state;
DEBUG(10,("Converting %s\n", key.dptr));
p = strchr(key.dptr, '/');
if (!p)
return 0;
*p = 0;
fstrcpy(dom_name, key.dptr);
*p++ = '/';
domain = find_domain_from_name(dom_name);
if (domain == NULL) {
/* We must delete the old record. */
DEBUG(0,("Unable to find domain %s\n", dom_name ));
DEBUG(0,("deleting record %s\n", key.dptr ));
if (tdb_delete(tdb, key) != 0) {
DEBUG(0, ("Unable to delete record %s\n", key.dptr));
*failed = True;
return -1;
}
return 0;
}
rid = atoi(p);
sid_copy(&sid, &domain->sid);
sid_append_rid(&sid, rid);
sid_to_string(keystr, &sid);
key2.dptr = keystr;
key2.dsize = strlen(keystr) + 1;
if (tdb_store(tdb, key2, data, TDB_INSERT) != 0) {
DEBUG(0,("Unable to add record %s\n", key2.dptr ));
*failed = True;
return -1;
}
if (tdb_store(tdb, data, key2, TDB_REPLACE) != 0) {
DEBUG(0,("Unable to update record %s\n", data.dptr ));
*failed = True;
return -1;
}
if (tdb_delete(tdb, key) != 0) {
DEBUG(0,("Unable to delete record %s\n", key.dptr ));
*failed = True;
return -1;
}
return 0;
}
/* These definitions are from sam/idmap_tdb.c. Replicated here just
out of laziness.... :-( */
/* High water mark keys */
#define HWM_GROUP "GROUP HWM"
#define HWM_USER "USER HWM"
/*****************************************************************************
Convert the idmap database from an older version.
*****************************************************************************/
static BOOL idmap_convert(const char *idmap_name)
{
int32 vers;
BOOL bigendianheader;
BOOL failed = False;
TDB_CONTEXT *idmap_tdb;
if (!(idmap_tdb = tdb_open_log(idmap_name, 0,
TDB_DEFAULT, O_RDWR,
0600))) {
DEBUG(0, ("idmap_convert: Unable to open idmap database\n"));
return False;
}
bigendianheader = (tdb_get_flags(idmap_tdb) & TDB_BIGENDIAN) ? True : False;
vers = tdb_fetch_int32(idmap_tdb, "IDMAP_VERSION");
if (((vers == -1) && bigendianheader) || (IREV(vers) == IDMAP_VERSION)) {
/* Arrggghh ! Bytereversed or old big-endian - make order independent ! */
/*
* high and low records were created on a
* big endian machine and will need byte-reversing.
*/
int32 wm;
wm = tdb_fetch_int32(idmap_tdb, HWM_USER);
if (wm != -1) {
wm = IREV(wm);
} else {
wm = server_state.uid_low;
}
if (tdb_store_int32(idmap_tdb, HWM_USER, wm) == -1) {
DEBUG(0, ("idmap_convert: Unable to byteswap user hwm in idmap database\n"));
tdb_close(idmap_tdb);
return False;
}
wm = tdb_fetch_int32(idmap_tdb, HWM_GROUP);
if (wm != -1) {
wm = IREV(wm);
} else {
wm = server_state.gid_low;
}
if (tdb_store_int32(idmap_tdb, HWM_GROUP, wm) == -1) {
DEBUG(0, ("idmap_convert: Unable to byteswap group hwm in idmap database\n"));
tdb_close(idmap_tdb);
return False;
}
}
/* the old format stored as DOMAIN/rid - now we store the SID direct */
tdb_traverse(idmap_tdb, convert_fn, &failed);
if (failed) {
DEBUG(0, ("Problem during conversion\n"));
tdb_close(idmap_tdb);
return False;
}
if (tdb_store_int32(idmap_tdb, "IDMAP_VERSION", IDMAP_VERSION) == -1) {
DEBUG(0, ("idmap_convert: Unable to dtore idmap version in databse\n"));
tdb_close(idmap_tdb);
return False;
}
tdb_close(idmap_tdb);
return True;
}
/*****************************************************************************
Convert the idmap database from an older version if necessary
*****************************************************************************/
BOOL winbindd_upgrade_idmap(void)
{
pstring idmap_name;
pstring backup_name;
SMB_STRUCT_STAT stbuf;
TDB_CONTEXT *idmap_tdb;
pstrcpy(idmap_name, lock_path("winbindd_idmap.tdb"));
if (!file_exist(idmap_name, &stbuf)) {
/* nothing to convert return */
return True;
}
if (!(idmap_tdb = tdb_open_log(idmap_name, 0,
TDB_DEFAULT, O_RDWR,
0600))) {
DEBUG(0, ("idmap_convert: Unable to open idmap database\n"));
return False;
}
if (tdb_fetch_int32(idmap_tdb, "IDMAP_VERSION") == IDMAP_VERSION) {
/* nothing to convert return */
tdb_close(idmap_tdb);
return True;
}
/* backup_tdb expects the tdb not to be open */
tdb_close(idmap_tdb);
DEBUG(0, ("Upgrading winbindd_idmap.tdb from an old version\n"));
pstrcpy(backup_name, idmap_name);
pstrcat(backup_name, ".bak");
if (backup_tdb(idmap_name, backup_name, 0) != 0) {
DEBUG(0, ("Could not backup idmap database\n"));
return False;
}
return idmap_convert(idmap_name);
}
NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
const DOM_SID *user_sid,

View File

@@ -180,7 +180,9 @@ typedef struct {
BOOL bWinbindNestedGroups;
BOOL bWinbindRefreshTickets;
BOOL bWinbindOfflineLogon;
char **szIdmapBackend;
char **szIdmapDomains;
char **szIdmapBackend; /* deprecated */
char **szIdmapAllocBackend;
char *szAddShareCommand;
char *szChangeShareCommand;
char *szDeleteShareCommand;
@@ -310,6 +312,8 @@ typedef struct {
int client_signing;
int server_signing;
int iUsershareMaxShares;
int iIdmapExpireTime;
int iIdmapNegativeTime;
BOOL bResetOnZeroVC;
param_opt_struct *param_opt;
@@ -1263,11 +1267,15 @@ static struct parm_struct parm_table[] = {
{N_("Winbind options"), P_SEP, P_SEPARATOR},
{"passdb expand explicit", P_BOOL, P_GLOBAL, &Globals.bPassdbExpandExplicit, NULL, NULL, FLAG_ADVANCED},
{"idmap backend", P_LIST, P_GLOBAL, &Globals.szIdmapBackend, NULL, NULL, FLAG_ADVANCED},
{"idmap uid", P_STRING, P_GLOBAL, &Globals.szIdmapUID, handle_idmap_uid, NULL, FLAG_ADVANCED},
{"winbind uid", P_STRING, P_GLOBAL, &Globals.szIdmapUID, handle_idmap_uid, NULL, FLAG_HIDE},
{"idmap gid", P_STRING, P_GLOBAL, &Globals.szIdmapGID, handle_idmap_gid, NULL, FLAG_ADVANCED},
{"winbind gid", P_STRING, P_GLOBAL, &Globals.szIdmapGID, handle_idmap_gid, NULL, FLAG_HIDE},
{"idmap domains", P_LIST, P_GLOBAL, &Globals.szIdmapDomains, NULL, NULL, FLAG_ADVANCED},
{"idmap backend", P_LIST, P_GLOBAL, &Globals.szIdmapBackend, NULL, NULL, FLAG_ADVANCED | FLAG_DEPRECATED },
{"idmap alloc backend", P_STRING, P_GLOBAL, &Globals.szIdmapAllocBackend, NULL, NULL, FLAG_ADVANCED},
{"idmap expire time", P_INTEGER, P_GLOBAL, &Globals.iIdmapExpireTime, NULL, NULL, FLAG_ADVANCED},
{"idmap negative time", P_INTEGER, P_GLOBAL, &Globals.iIdmapNegativeTime, NULL, NULL, FLAG_ADVANCED},
{"idmap uid", P_STRING, P_GLOBAL, &Globals.szIdmapUID, handle_idmap_uid, NULL, FLAG_ADVANCED | FLAG_DEPRECATED },
{"winbind uid", P_STRING, P_GLOBAL, &Globals.szIdmapUID, handle_idmap_uid, NULL, FLAG_HIDE | FLAG_DEPRECATED },
{"idmap gid", P_STRING, P_GLOBAL, &Globals.szIdmapGID, handle_idmap_gid, NULL, FLAG_ADVANCED | FLAG_DEPRECATED },
{"winbind gid", P_STRING, P_GLOBAL, &Globals.szIdmapGID, handle_idmap_gid, NULL, FLAG_HIDE | FLAG_DEPRECATED },
{"template homedir", P_STRING, P_GLOBAL, &Globals.szTemplateHomedir, NULL, NULL, FLAG_ADVANCED},
{"template shell", P_STRING, P_GLOBAL, &Globals.szTemplateShell, NULL, NULL, FLAG_ADVANCED},
{"winbind separator", P_STRING, P_GLOBAL, &Globals.szWinbindSeparator, NULL, NULL, FLAG_ADVANCED},
@@ -1627,6 +1635,9 @@ static void init_globals(BOOL first_time_only)
Globals.bWinbindRefreshTickets = False;
Globals.bWinbindOfflineLogon = False;
Globals.iIdmapExpireTime = 900; /* 15 minutes by default */
Globals.iIdmapNegativeTime = 120; /* 2 minutes by default */
Globals.bPassdbExpandExplicit = False;
Globals.name_cache_timeout = 660; /* In seconds */
@@ -1845,7 +1856,11 @@ FN_GLOBAL_BOOL(lp_winbind_nested_groups, &Globals.bWinbindNestedGroups)
FN_GLOBAL_BOOL(lp_winbind_refresh_tickets, &Globals.bWinbindRefreshTickets)
FN_GLOBAL_BOOL(lp_winbind_offline_logon, &Globals.bWinbindOfflineLogon)
FN_GLOBAL_LIST(lp_idmap_backend, &Globals.szIdmapBackend)
FN_GLOBAL_LIST(lp_idmap_domains, &Globals.szIdmapDomains)
FN_GLOBAL_LIST(lp_idmap_backend, &Globals.szIdmapBackend) /* deprecated */
FN_GLOBAL_STRING(lp_idmap_alloc_backend, &Globals.szIdmapAllocBackend)
FN_GLOBAL_INTEGER(lp_idmap_expire_time, &Globals.iIdmapExpireTime)
FN_GLOBAL_INTEGER(lp_idmap_negative_time, &Globals.iIdmapNegativeTime)
FN_GLOBAL_BOOL(lp_passdb_expand_explicit, &Globals.bPassdbExpandExplicit)
FN_GLOBAL_STRING(lp_ldap_suffix, &Globals.szLdapSuffix)

View File

@@ -1112,29 +1112,16 @@ void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
}
/*****************************************************************
*THE CANONICAL* convert uid_t to SID function.
*THE LEGACY* convert uid_t to SID function.
*****************************************************************/
void uid_to_sid(DOM_SID *psid, uid_t uid)
void legacy_uid_to_sid(DOM_SID *psid, uid_t uid)
{
uid_t low, high;
uint32 rid;
BOOL ret;
ZERO_STRUCTP(psid);
if (fetch_sid_from_uid_cache(psid, uid))
return;
if ((lp_winbind_trusted_domains_only() ||
(lp_idmap_uid(&low, &high) && (uid >= low) && (uid <= high))) &&
winbind_uid_to_sid(psid, uid)) {
DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
(unsigned int)uid, sid_string_static(psid)));
goto done;
}
become_root_uid_only();
ret = pdb_uid_to_rid(uid, &rid);
unbecome_root_uid_only();
@@ -1151,36 +1138,22 @@ void uid_to_sid(DOM_SID *psid, uid_t uid)
uid_to_unix_users_sid(uid, psid);
done:
DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid,
DEBUG(10,("LEGACY: uid %u -> sid %s\n", (unsigned int)uid,
sid_string_static(psid)));
store_uid_sid_cache(psid, uid);
return;
}
/*****************************************************************
*THE CANONICAL* convert gid_t to SID function.
*THE LEGACY* convert gid_t to SID function.
*****************************************************************/
void gid_to_sid(DOM_SID *psid, gid_t gid)
void legacy_gid_to_sid(DOM_SID *psid, gid_t gid)
{
BOOL ret;
gid_t low, high;
ZERO_STRUCTP(psid);
if (fetch_sid_from_gid_cache(psid, gid))
return;
if ((lp_winbind_trusted_domains_only() ||
(lp_idmap_gid(&low, &high) && (gid >= low) && (gid <= high))) &&
winbind_gid_to_sid(psid, gid)) {
DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
(unsigned int)gid, sid_string_static(psid)));
goto done;
}
become_root_uid_only();
ret = pdb_gid_to_sid(gid, psid);
unbecome_root_uid_only();
@@ -1195,29 +1168,20 @@ void gid_to_sid(DOM_SID *psid, gid_t gid)
gid_to_unix_groups_sid(gid, psid);
done:
DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid,
DEBUG(10,("LEGACY: gid %u -> sid %s\n", (unsigned int)gid,
sid_string_static(psid)));
store_gid_sid_cache(psid, gid);
return;
}
/*****************************************************************
*THE CANONICAL* convert SID to uid function.
*THE LEGACY* convert SID to uid function.
*****************************************************************/
BOOL sid_to_uid(const DOM_SID *psid, uid_t *puid)
BOOL legacy_sid_to_uid(const DOM_SID *psid, uid_t *puid)
{
enum lsa_SidType type;
uint32 rid;
gid_t gid;
if (fetch_uid_from_cache(puid, psid))
return True;
if (fetch_gid_from_cache(&gid, psid)) {
return False;
}
if (sid_peek_check_rid(&global_sid_Unix_Users, psid, &rid)) {
uid_t uid = rid;
@@ -1249,55 +1213,26 @@ BOOL sid_to_uid(const DOM_SID *psid, uid_t *puid)
return False;
}
if (winbind_lookup_sid(NULL, psid, NULL, NULL, &type)) {
if (type != SID_NAME_USER) {
DEBUG(10, ("sid_to_uid: sid %s is a %s\n",
sid_string_static(psid),
sid_type_lookup(type)));
return False;
}
if (!winbind_sid_to_uid(puid, psid)) {
DEBUG(5, ("sid_to_uid: winbind failed to allocate a "
"new uid for sid %s\n",
sid_string_static(psid)));
return False;
}
goto done;
}
/* TODO: Here would be the place to allocate both a gid and a uid for
* the SID in question */
return False;
done:
DEBUG(10,("sid_to_uid: %s -> %u\n", sid_string_static(psid),
DEBUG(10,("LEGACY: sid %s -> uid %u\n", sid_string_static(psid),
(unsigned int)*puid ));
store_uid_sid_cache(psid, *puid);
return True;
}
/*****************************************************************
*THE CANONICAL* convert SID to gid function.
*THE LEGACY* convert SID to gid function.
Group mapping is used for gids that maps to Wellknown SIDs
*****************************************************************/
BOOL sid_to_gid(const DOM_SID *psid, gid_t *pgid)
BOOL legacy_sid_to_gid(const DOM_SID *psid, gid_t *pgid)
{
uint32 rid;
GROUP_MAP map;
union unid_t id;
enum lsa_SidType type;
uid_t uid;
if (fetch_gid_from_cache(pgid, psid))
return True;
if (fetch_uid_from_cache(&uid, psid))
return False;
if (sid_peek_check_rid(&global_sid_Unix_Groups, psid, &rid)) {
gid_t gid = rid;
@@ -1344,33 +1279,137 @@ BOOL sid_to_gid(const DOM_SID *psid, gid_t *pgid)
return False;
}
if (!winbind_lookup_sid(NULL, psid, NULL, NULL, &type)) {
DEBUG(11,("sid_to_gid: no one knows the SID %s (tried local, "
"then winbind)\n", sid_string_static(psid)));
done:
DEBUG(10,("LEGACY: sid %s -> gid %u\n", sid_string_static(psid),
(unsigned int)*pgid ));
return True;
}
/*****************************************************************
*THE CANONICAL* convert uid_t to SID function.
*****************************************************************/
void uid_to_sid(DOM_SID *psid, uid_t uid)
{
ZERO_STRUCTP(psid);
if (fetch_sid_from_uid_cache(psid, uid))
return;
if (!winbind_uid_to_sid(psid, uid)) {
if (!winbind_ping()) {
DEBUG(2, ("WARNING: Winbindd not running, mapping ids with legacy code"));
return legacy_uid_to_sid(psid, uid);
}
DEBUG(5, ("uid_to_sid: winbind failed to find a sid for uid %u\n",
uid));
return;
}
DEBUG(10,("uid %u -> sid %s\n",
(unsigned int)uid, sid_string_static(psid)));
store_uid_sid_cache(psid, uid);
return;
}
/*****************************************************************
*THE CANONICAL* convert gid_t to SID function.
*****************************************************************/
void gid_to_sid(DOM_SID *psid, gid_t gid)
{
ZERO_STRUCTP(psid);
if (fetch_sid_from_gid_cache(psid, gid))
return;
if (!winbind_gid_to_sid(psid, gid)) {
if (!winbind_ping()) {
DEBUG(2, ("WARNING: Winbindd not running, mapping ids with legacy code"));
return legacy_gid_to_sid(psid, gid);
}
DEBUG(5, ("gid_to_sid: winbind failed to find a sid for gid %u\n",
gid));
return;
}
DEBUG(10,("gid %u -> sid %s\n",
(unsigned int)gid, sid_string_static(psid)));
store_gid_sid_cache(psid, gid);
return;
}
/*****************************************************************
*THE CANONICAL* convert SID to uid function.
*****************************************************************/
BOOL sid_to_uid(const DOM_SID *psid, uid_t *puid)
{
gid_t gid;
if (fetch_uid_from_cache(puid, psid))
return True;
if (fetch_gid_from_cache(&gid, psid)) {
return False;
}
/* winbindd knows it; Ensure this is a group sid */
if (!winbind_sid_to_uid(puid, psid)) {
if (!winbind_ping()) {
DEBUG(2, ("WARNING: Winbindd not running, mapping ids with legacy code"));
return legacy_sid_to_uid(psid, puid);
}
if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
(type != SID_NAME_WKN_GRP)) {
DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is "
"a %s\n", sid_type_lookup(type)));
DEBUG(5, ("winbind failed to find a uid for sid %s\n",
sid_string_static(psid)));
return False;
}
/* winbindd knows it and it is a type of group; sid_to_gid must succeed
or we are dead in the water */
/* TODO: Here would be the place to allocate both a gid and a uid for
* the SID in question */
DEBUG(10,("sid %s -> uid %u\n", sid_string_static(psid),
(unsigned int)*puid ));
store_uid_sid_cache(psid, *puid);
return True;
}
/*****************************************************************
*THE CANONICAL* convert SID to gid function.
Group mapping is used for gids that maps to Wellknown SIDs
*****************************************************************/
BOOL sid_to_gid(const DOM_SID *psid, gid_t *pgid)
{
uid_t uid;
if (fetch_gid_from_cache(pgid, psid))
return True;
if (fetch_uid_from_cache(&uid, psid))
return False;
/* Ask winbindd if it can map this sid to a gid.
* (Idmap will check it is a valid SID and of the right type) */
if ( !winbind_sid_to_gid(pgid, psid) ) {
DEBUG(10,("sid_to_gid: winbind failed to allocate a new gid "
"for sid %s\n", sid_string_static(psid)));
if (!winbind_ping()) {
DEBUG(2, ("WARNING: Winbindd not running, mapping ids with legacy code"));
return legacy_sid_to_uid(psid, pgid);
}
DEBUG(10,("winbind failed to find a gid for sid %s\n",
sid_string_static(psid)));
return False;
}
done:
DEBUG(10,("sid_to_gid: %s -> %u\n", sid_string_static(psid),
DEBUG(10,("sid %s -> gid %u\n", sid_string_static(psid),
(unsigned int)*pgid ));
store_gid_sid_cache(psid, *pgid);

View File

@@ -995,6 +995,12 @@ BOOL pdb_uid_to_rid(uid_t uid, uint32 *rid)
return pdb->uid_to_rid(pdb, uid, rid);
}
BOOL pdb_uid_to_sid(uid_t uid, DOM_SID *sid)
{
struct pdb_methods *pdb = pdb_get_methods();
return pdb->uid_to_sid(pdb, uid, sid);
}
BOOL pdb_gid_to_sid(gid_t gid, DOM_SID *sid)
{
struct pdb_methods *pdb = pdb_get_methods();
@@ -1161,8 +1167,8 @@ static NTSTATUS pdb_default_get_seq_num(struct pdb_methods *methods, time_t *seq
return NT_STATUS_OK;
}
static BOOL pdb_default_uid_to_rid(struct pdb_methods *methods, uid_t uid,
uint32 *rid)
static BOOL pdb_default_uid_to_sid(struct pdb_methods *methods, uid_t uid,
DOM_SID *sid)
{
struct samu *sampw = NULL;
struct passwd *unix_pw;
@@ -1193,15 +1199,31 @@ static BOOL pdb_default_uid_to_rid(struct pdb_methods *methods, uid_t uid,
return False;
}
ret = sid_peek_check_rid(get_global_sam_sid(),
pdb_get_user_sid(sampw), rid);
sid_copy(sid, pdb_get_user_sid(sampw));
TALLOC_FREE(sampw);
return True;
}
static BOOL pdb_default_uid_to_rid(struct pdb_methods *methods, uid_t uid,
uint32 *rid)
{
DOM_SID sid;
BOOL ret;
ret = pdb_default_uid_to_sid(methods, uid, &sid);
if (!ret) {
return ret;
}
ret = sid_peek_check_rid(get_global_sam_sid(), &sid, rid);
if (!ret) {
DEBUG(1, ("Could not peek rid out of sid %s\n",
sid_string_static(pdb_get_user_sid(sampw))));
sid_string_static(&sid)));
}
TALLOC_FREE(sampw);
return ret;
}
@@ -2015,6 +2037,7 @@ NTSTATUS make_pdb_method( struct pdb_methods **methods )
(*methods)->set_account_policy = pdb_default_set_account_policy;
(*methods)->get_seq_num = pdb_default_get_seq_num;
(*methods)->uid_to_rid = pdb_default_uid_to_rid;
(*methods)->uid_to_sid = pdb_default_uid_to_sid;
(*methods)->gid_to_sid = pdb_default_gid_to_sid;
(*methods)->sid_to_id = pdb_default_sid_to_id;

View File

@@ -1252,3 +1252,45 @@ BOOL secrets_restore_schannel_session_info(TALLOC_CTX *mem_ctx,
return True;
}
BOOL secrets_store_generic(const char *owner, const char *key, const char *secret)
{
char *tdbkey = NULL;
BOOL ret;
if (asprintf(&tdbkey, "SECRETS/GENERIC/%s/%s", owner, key) < 0) {
DEBUG(0, ("asprintf failed!\n"));
return False;
}
ret = secrets_store(tdbkey, secret, strlen(secret)+1);
SAFE_FREE(tdbkey);
return ret;
}
/*******************************************************************
Find the ldap password.
******************************************************************/
char *secrets_fetch_generic(const char *owner, const char *key)
{
char *secret = NULL;
char *tdbkey = NULL;
if (( ! owner) || ( ! key)) {
DEBUG(1, ("Invalid Paramters"));
return NULL;
}
if (asprintf(&tdbkey, "SECRETS/GENERIC/%s/%s", owner, key) < 0) {
DEBUG(0, ("Out of memory!\n"));
return NULL;
}
secret = (char *)secrets_fetch(tdbkey, NULL);
SAFE_FREE(tdbkey);
return secret;
}

View File

@@ -1,379 +0,0 @@
/*
Unix SMB/CIFS implementation.
ID Mapping
Copyright (C) Tim Potter 2000
Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
Copyright (C) Simo Sorce 2003
Copyright (C) Jeremy Allison 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 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"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_IDMAP
static_decl_idmap;
struct idmap_function_entry {
const char *name;
struct idmap_methods *methods;
struct idmap_function_entry *prev,*next;
};
static struct idmap_function_entry *backends = NULL;
static struct idmap_methods *cache_map;
static struct idmap_methods *remote_map;
static BOOL proxyonly = False;
/**********************************************************************
Get idmap methods. Don't allow tdb to be a remote method.
**********************************************************************/
static struct idmap_methods *get_methods(const char *name, BOOL cache_method)
{
struct idmap_function_entry *entry = backends;
for(entry = backends; entry; entry = entry->next) {
if (!cache_method && strequal(entry->name, "tdb"))
continue; /* tdb is only cache method. */
if (strequal(entry->name, name))
return entry->methods;
}
return NULL;
}
/**********************************************************************
Allow a module to register itself as a method.
**********************************************************************/
NTSTATUS smb_register_idmap(int version, const char *name, struct idmap_methods *methods)
{
struct idmap_function_entry *entry;
if ((version != SMB_IDMAP_INTERFACE_VERSION)) {
DEBUG(0, ("smb_register_idmap: Failed to register idmap module.\n"
"The module was compiled against SMB_IDMAP_INTERFACE_VERSION %d,\n"
"current SMB_IDMAP_INTERFACE_VERSION is %d.\n"
"Please recompile against the current version of samba!\n",
version, SMB_IDMAP_INTERFACE_VERSION));
return NT_STATUS_OBJECT_TYPE_MISMATCH;
}
if (!name || !name[0] || !methods) {
DEBUG(0,("smb_register_idmap: called with NULL pointer or empty name!\n"));
return NT_STATUS_INVALID_PARAMETER;
}
if (get_methods(name, False)) {
DEBUG(0,("smb_register_idmap: idmap module %s already registered!\n", name));
return NT_STATUS_OBJECT_NAME_COLLISION;
}
entry = SMB_XMALLOC_P(struct idmap_function_entry);
entry->name = smb_xstrdup(name);
entry->methods = methods;
DLIST_ADD(backends, entry);
DEBUG(5, ("smb_register_idmap: Successfully added idmap backend '%s'\n", name));
return NT_STATUS_OK;
}
/**********************************************************************
Initialise idmap cache and a remote backend (if configured).
**********************************************************************/
BOOL idmap_init(const char **remote_backend)
{
if (!backends)
static_init_idmap;
if (!cache_map) {
cache_map = get_methods("tdb", True);
if (!cache_map) {
DEBUG(0, ("idmap_init: could not find tdb cache backend!\n"));
return False;
}
if (!NT_STATUS_IS_OK(cache_map->init( NULL ))) {
DEBUG(0, ("idmap_init: could not initialise tdb cache backend!\n"));
return False;
}
}
if ((remote_map == NULL) && (remote_backend != NULL) &&
(*remote_backend != NULL) && (**remote_backend != '\0')) {
char *rem_backend = smb_xstrdup(*remote_backend);
fstring params = "";
char *pparams;
BOOL idmap_prefix_workaround = False;
/* get any mode parameters passed in */
if ( (pparams = strchr( rem_backend, ':' )) != NULL ) {
*pparams = '\0';
pparams++;
fstrcpy( params, pparams );
}
/* strip any leading idmap_ prefix of */
if ( strncmp( rem_backend, "idmap_", 6) == 0 ) {
rem_backend += 6;
idmap_prefix_workaround = True;
DEBUG(0, ("idmap_init: idmap backend uses deprecated 'idmap_' prefix. Please replace 'idmap_%s' by '%s' in %s\n", rem_backend, rem_backend, dyn_CONFIGFILE));
}
DEBUG(3, ("idmap_init: using '%s' as remote backend\n", rem_backend));
if((remote_map = get_methods(rem_backend, False)) ||
(NT_STATUS_IS_OK(smb_probe_module("idmap", rem_backend)) &&
(remote_map = get_methods(rem_backend, False)))) {
if (!NT_STATUS_IS_OK(remote_map->init(params))) {
DEBUG(0, ("idmap_init: failed to initialize remote backend!\n"));
return False;
}
} else {
DEBUG(0, ("idmap_init: could not load remote backend '%s'\n", rem_backend));
if (idmap_prefix_workaround)
rem_backend -= 6;
SAFE_FREE(rem_backend);
return False;
}
if (idmap_prefix_workaround)
rem_backend -= 6;
SAFE_FREE(rem_backend);
}
return True;
}
/**************************************************************************
Don't do id mapping. This is used to make winbind a netlogon proxy only.
**************************************************************************/
void idmap_set_proxyonly(void)
{
proxyonly = True;
}
BOOL idmap_proxyonly(void)
{
return proxyonly;
}
/**************************************************************************
This is a rare operation, designed to allow an explicit mapping to be
set up for a sid to a POSIX id.
**************************************************************************/
NTSTATUS idmap_set_mapping(const DOM_SID *sid, unid_t id, enum idmap_type id_type)
{
struct idmap_methods *map = remote_map;
DOM_SID tmp_sid;
if (proxyonly) {
return NT_STATUS_UNSUCCESSFUL;
}
if (sid_check_is_in_our_domain(sid)) {
DEBUG(3, ("Refusing to add SID %s to idmap, it's our own "
"domain\n", sid_string_static(sid)));
return NT_STATUS_ACCESS_DENIED;
}
if (sid_check_is_in_builtin(sid)) {
DEBUG(3, ("Refusing to add SID %s to idmap, it's our builtin "
"domain\n", sid_string_static(sid)));
return NT_STATUS_ACCESS_DENIED;
}
DEBUG(10, ("idmap_set_mapping: Set %s to %s %lu\n",
sid_string_static(sid),
(id_type == ID_USERID) ? "UID" : "GID",
(id_type == ID_USERID) ? (unsigned long)id.uid :
(unsigned long)id.gid));
if ( (NT_STATUS_IS_OK(cache_map->get_sid_from_id(&tmp_sid, id, id_type, IDMAP_FLAG_QUERY_ONLY))) &&
sid_equal(sid, &tmp_sid) ) {
/* Nothing to do, we already have that mapping */
DEBUG(10, ("idmap_set_mapping: Mapping already there\n"));
return NT_STATUS_OK;
}
if (map == NULL) {
/* Ok, we don't have a authoritative remote
mapping. So update our local cache only. */
map = cache_map;
}
return map->set_mapping(sid, id, id_type);
}
/**************************************************************************
Get ID from SID. This can create a mapping for a SID to a POSIX id.
**************************************************************************/
NTSTATUS idmap_get_id_from_sid(unid_t *id, enum idmap_type *id_type, const DOM_SID *sid, int flags)
{
NTSTATUS ret;
int cache_flags = flags;
if (proxyonly) {
return NT_STATUS_UNSUCCESSFUL;
}
if (sid_check_is_in_our_domain(sid)) {
DEBUG(9, ("sid %s is in our domain -- go look in passdb\n",
sid_string_static(sid)));
return NT_STATUS_NONE_MAPPED;
}
if (sid_check_is_in_builtin(sid)) {
DEBUG(9, ("sid %s is in builtin domain -- go look in passdb\n",
sid_string_static(sid)));
return NT_STATUS_NONE_MAPPED;
}
if (remote_map) {
/* We have a central remote idmap so only look in
cache, ensure we don't allocate */
cache_flags |= IDMAP_FLAG_QUERY_ONLY;
}
ret = cache_map->get_id_from_sid(id, id_type, sid, cache_flags);
if (NT_STATUS_IS_OK(ret)) {
return NT_STATUS_OK;
}
if ((remote_map == NULL) || (flags & IDMAP_FLAG_CACHE_ONLY)) {
return ret;
}
/* Ok, the mapping was not in the cache, give the remote map a try. */
ret = remote_map->get_id_from_sid(id, id_type, sid, flags);
if (NT_STATUS_IS_OK(ret)) {
/* The remote backend gave us a valid mapping, cache it. */
ret = cache_map->set_mapping(sid, *id, *id_type);
}
return ret;
}
/**************************************************************************
Get SID from ID. This must have been created before.
**************************************************************************/
NTSTATUS idmap_get_sid_from_id(DOM_SID *sid, unid_t id, enum idmap_type id_type, int flags)
{
NTSTATUS ret;
int cache_flags = flags;
if (proxyonly) {
return NT_STATUS_UNSUCCESSFUL;
}
if (remote_map) {
/* We have a central remote idmap so only look in
cache, ensure we don't allocate */
cache_flags |= IDMAP_FLAG_QUERY_ONLY;
}
ret = cache_map->get_sid_from_id(sid, id, id_type, cache_flags);
if (NT_STATUS_IS_OK(ret)) {
return ret;
}
if ((remote_map == NULL) || (flags & IDMAP_FLAG_CACHE_ONLY)) {
return ret;
}
/* Not in cache, ask our authoritative backend */
ret = remote_map->get_sid_from_id(sid, id, id_type, flags);
if (NT_STATUS_IS_OK(ret)) {
/* The remote backend gave us a valid mapping, cache it. */
ret = cache_map->set_mapping(sid, id, id_type);
}
return ret;
}
/**************************************************************************
Alloocate a new UNIX uid/gid
**************************************************************************/
NTSTATUS idmap_allocate_id(unid_t *id, enum idmap_type id_type)
{
/* we have to allocate from the authoritative backend */
if (proxyonly) {
return NT_STATUS_UNSUCCESSFUL;
}
if ( remote_map ) {
return remote_map->allocate_id( id, id_type );
}
return cache_map->allocate_id( id, id_type );
}
/**************************************************************************
Shutdown maps.
**************************************************************************/
NTSTATUS idmap_close(void)
{
NTSTATUS ret;
if (proxyonly) {
return NT_STATUS_OK;
}
ret = cache_map->close_fn();
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(3, ("idmap_close: failed to close local tdb cache!\n"));
}
cache_map = NULL;
if (remote_map) {
ret = remote_map->close_fn();
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(3, ("idmap_close: failed to close remote idmap repository!\n"));
}
remote_map = NULL;
}
return ret;
}
/**************************************************************************
Dump backend status.
**************************************************************************/
void idmap_status(void)
{
cache_map->status();
if (remote_map) {
remote_map->status();
}
}

View File

@@ -1,380 +0,0 @@
/*
* idmap_ad: map between Active Directory and RFC 2307 or "Services for Unix" (SFU) Accounts
*
* Unix SMB/CIFS implementation.
*
* Winbind ADS backend functions
*
* Copyright (C) Andrew Tridgell 2001
* Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003
* Copyright (C) Gerald (Jerry) Carter 2004
* Copyright (C) Luke Howard 2001-2004
*
* 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"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_IDMAP
#define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
NTSTATUS init_module(void);
static ADS_STRUCT *ad_idmap_ads = NULL;
static char *attr_uidnumber = NULL;
static char *attr_gidnumber = NULL;
static ADS_STATUS ad_idmap_check_attr_mapping(ADS_STRUCT *ads)
{
ADS_STATUS status;
enum wb_posix_mapping map_type;
if (attr_uidnumber != NULL && attr_gidnumber != NULL) {
return ADS_ERROR(LDAP_SUCCESS);
}
SMB_ASSERT(ads->server.workgroup);
map_type = get_nss_info(ads->server.workgroup);
if ((map_type == WB_POSIX_MAP_SFU) ||
(map_type == WB_POSIX_MAP_RFC2307)) {
status = ads_check_posix_schema_mapping(ads, map_type);
if (ADS_ERR_OK(status)) {
attr_uidnumber = SMB_STRDUP(ads->schema.posix_uidnumber_attr);
attr_gidnumber = SMB_STRDUP(ads->schema.posix_gidnumber_attr);
ADS_ERROR_HAVE_NO_MEMORY(attr_uidnumber);
ADS_ERROR_HAVE_NO_MEMORY(attr_gidnumber);
return ADS_ERROR(LDAP_SUCCESS);
} else {
DEBUG(0,("ads_check_posix_schema_mapping failed: %s\n", ads_errstr(status)));
/* return status; */
}
}
/* fallback to XAD defaults */
attr_uidnumber = SMB_STRDUP("uidNumber");
attr_gidnumber = SMB_STRDUP("gidNumber");
ADS_ERROR_HAVE_NO_MEMORY(attr_uidnumber);
ADS_ERROR_HAVE_NO_MEMORY(attr_gidnumber);
return ADS_ERROR(LDAP_SUCCESS);
}
static ADS_STRUCT *ad_idmap_cached_connection(void)
{
ADS_STRUCT *ads;
ADS_STATUS status;
BOOL local = False;
if (ad_idmap_ads != NULL) {
ads = ad_idmap_ads;
/* check for a valid structure */
DEBUG(7, ("Current tickets expire at %d, time is now %d\n",
(uint32) ads->auth.expire, (uint32) time(NULL)));
if ( ads->config.realm && (ads->auth.expire > time(NULL))) {
return ads;
} else {
/* we own this ADS_STRUCT so make sure it goes away */
ads->is_mine = True;
ads_destroy( &ads );
ads_kdestroy(WINBIND_CCACHE_NAME);
ad_idmap_ads = NULL;
}
}
if (!local) {
/* we don't want this to affect the users ccache */
setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
}
ads = ads_init(lp_realm(), lp_workgroup(), NULL);
if (!ads) {
DEBUG(1,("ads_init failed\n"));
return NULL;
}
/* the machine acct password might have change - fetch it every time */
SAFE_FREE(ads->auth.password);
ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
SAFE_FREE(ads->auth.realm);
ads->auth.realm = SMB_STRDUP(lp_realm());
status = ads_connect(ads);
if (!ADS_ERR_OK(status)) {
DEBUG(1, ("ad_idmap_init: failed to connect to AD\n"));
ads_destroy(&ads);
return NULL;
}
ads->is_mine = False;
status = ad_idmap_check_attr_mapping(ads);
if (!ADS_ERR_OK(status)) {
DEBUG(1, ("ad_idmap_init: failed to check attribute mapping\n"));
return NULL;
}
ad_idmap_ads = ads;
return ads;
}
/* no op */
static NTSTATUS ad_idmap_init(const char *uri)
{
return NT_STATUS_OK;
}
static NTSTATUS ad_idmap_get_sid_from_id(DOM_SID *sid, unid_t unid, enum idmap_type id_type, int flags)
{
ADS_STATUS rc;
NTSTATUS status = NT_STATUS_NONE_MAPPED;
const char *attrs[] = { "objectSid", NULL };
LDAPMessage *res = NULL;
LDAPMessage *msg = NULL;
char *expr = NULL;
fstring sid_string;
int count;
ADS_STRUCT *ads;
if (sid == NULL) {
return NT_STATUS_INVALID_PARAMETER;
}
ads = ad_idmap_cached_connection();
if (ads == NULL) {
DEBUG(1, ("ad_idmap_get_id_from_sid ADS uninitialized\n"));
return NT_STATUS_NOT_SUPPORTED;
}
switch (id_type) {
case ID_USERID:
if (asprintf(&expr, "(&(|(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d))(%s=%d))",
ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
ads->schema.posix_uidnumber_attr, (int)unid.uid) == -1) {
return NT_STATUS_NO_MEMORY;
}
break;
case ID_GROUPID:
if (asprintf(&expr, "(&(|(sAMAccountType=%d)(sAMAccountType=%d))(%s=%d))",
ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP,
ads->schema.posix_gidnumber_attr, (int)unid.gid) == -1) {
return NT_STATUS_NO_MEMORY;
}
break;
default:
return NT_STATUS_INVALID_PARAMETER;
break;
}
rc = ads_search_retry(ads, &res, expr, attrs);
free(expr);
if (!ADS_ERR_OK(rc)) {
DEBUG(1, ("ad_idmap_get_sid_from_id: ads_search: %s\n", ads_errstr(rc)));
goto done;
}
count = ads_count_replies(ads, res);
if (count == 0) {
DEBUG(1, ("ad_idmap_get_sid_from_id: ads_count_replies: no results\n"));
goto done;
} else if (count != 1) {
DEBUG(1, ("ad_idmap_get_sid_from_id: ads_count_replies: incorrect cardinality\n"));
goto done;
}
msg = ads_first_entry(ads, res);
if (msg == NULL) {
DEBUG(1, ("ad_idmap_get_sid_from_id: ads_first_entry: could not retrieve search result\n"));
goto done;
}
if (!ads_pull_sid(ads, msg, "objectSid", sid)) {
DEBUG(1, ("ad_idmap_get_sid_from_id: ads_pull_sid: could not retrieve SID from entry\n"));
goto done;
}
status = NT_STATUS_OK;
DEBUG(1, ("ad_idmap_get_sid_from_id mapped POSIX %s %d to SID [%s]\n",
(id_type == ID_GROUPID) ? "GID" : "UID", (int)unid.uid,
sid_to_string(sid_string, sid)));
done:
if (res != NULL) {
ads_msgfree(ads, res);
}
return status;
}
static NTSTATUS ad_idmap_get_id_from_sid(unid_t *unid, enum idmap_type *id_type, const DOM_SID *sid, int flags)
{
ADS_STATUS rc;
NTSTATUS status = NT_STATUS_NONE_MAPPED;
const char *attrs[] = { "sAMAccountType", ADS_ATTR_SFU_UIDNUMBER_OID,
ADS_ATTR_SFU_GIDNUMBER_OID,
ADS_ATTR_RFC2307_UIDNUMBER_OID,
ADS_ATTR_RFC2307_GIDNUMBER_OID,
NULL };
LDAPMessage *res = NULL;
LDAPMessage *msg = NULL;
char *expr = NULL;
uint32 atype, uid;
char *sidstr;
fstring sid_string;
int count;
ADS_STRUCT *ads;
if (unid == NULL) {
return NT_STATUS_INVALID_PARAMETER;
}
ads = ad_idmap_cached_connection();
if (ads == NULL) {
DEBUG(1, ("ad_idmap_get_id_from_sid ADS uninitialized\n"));
return NT_STATUS_NOT_SUPPORTED;
}
sidstr = sid_binstring(sid);
if (asprintf(&expr, "(objectSid=%s)", sidstr) == -1) {
free(sidstr);
return NT_STATUS_NO_MEMORY;
}
rc = ads_search_retry(ads, &res, expr, attrs);
free(sidstr);
free(expr);
if (!ADS_ERR_OK(rc)) {
DEBUG(1, ("ad_idmap_get_id_from_sid: ads_search: %s\n", ads_errstr(rc)));
goto done;
}
count = ads_count_replies(ads, res);
if (count == 0) {
DEBUG(1, ("ad_idmap_get_id_from_sid: ads_count_replies: no results\n"));
goto done;
} else if (count != 1) {
DEBUG(1, ("ad_idmap_get_id_from_sid: ads_count_replies: incorrect cardinality\n"));
goto done;
}
msg = ads_first_entry(ads, res);
if (msg == NULL) {
DEBUG(1, ("ad_idmap_get_id_from_sid: ads_first_entry: could not retrieve search result\n"));
goto done;
}
if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype)) {
DEBUG(1, ("ad_idmap_get_id_from_sid: ads_pull_uint32: could not read SAM account type\n"));
goto done;
}
switch (atype & 0xF0000000) {
case ATYPE_SECURITY_GLOBAL_GROUP:
case ATYPE_SECURITY_LOCAL_GROUP:
*id_type = ID_GROUPID;
break;
case ATYPE_NORMAL_ACCOUNT:
case ATYPE_WORKSTATION_TRUST:
case ATYPE_INTERDOMAIN_TRUST:
*id_type = ID_USERID;
break;
default:
DEBUG(1, ("ad_idmap_get_id_from_sid: unrecognized SAM account type %08x\n", atype));
goto done;
break;
}
if (!ads_pull_uint32(ads, msg, (*id_type == ID_GROUPID) ? attr_gidnumber : attr_uidnumber, &uid)) {
DEBUG(1, ("ad_idmap_get_id_from_sid: ads_pull_uint32: could not read attribute '%s'\n",
(*id_type == ID_GROUPID) ? attr_gidnumber : attr_uidnumber));
goto done;
}
unid->uid = (uid_t)uid;
status = NT_STATUS_OK;
DEBUG(1, ("ad_idmap_get_id_from_sid mapped SID [%s] to POSIX %s %d\n",
sid_to_string(sid_string, sid),
(*id_type == ID_GROUPID) ? "GID" : "UID", uid));
done:
if (res != NULL) {
ads_msgfree(ads, res);
}
return status;
}
static NTSTATUS ad_idmap_set_mapping(const DOM_SID *sid, unid_t id, enum idmap_type id_type)
{
/* Not supported, and probably won't be... */
/* (It's not particularly feasible with a single-master model.) */
return NT_STATUS_NOT_IMPLEMENTED;
}
static NTSTATUS ad_idmap_close(void)
{
ADS_STRUCT *ads = ad_idmap_ads;
if (ads != NULL) {
/* we own this ADS_STRUCT so make sure it goes away */
ads->is_mine = True;
ads_destroy( &ads );
ad_idmap_ads = NULL;
}
SAFE_FREE(attr_uidnumber);
SAFE_FREE(attr_gidnumber);
return NT_STATUS_OK;
}
static NTSTATUS ad_idmap_allocate_id(unid_t *id, enum idmap_type id_type)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
static void ad_idmap_status(void)
{
DEBUG(0, ("AD IDMAP Status not available\n"));
}
static struct idmap_methods ad_methods = {
ad_idmap_init,
ad_idmap_allocate_id,
ad_idmap_get_sid_from_id,
ad_idmap_get_id_from_sid,
ad_idmap_set_mapping,
ad_idmap_close,
ad_idmap_status
};
/* support for new authentication subsystem */
NTSTATUS idmap_ad_init(void)
{
return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ad", &ad_methods);
}

View File

@@ -1,542 +0,0 @@
/*
Unix SMB/CIFS implementation.
idmap LDAP backend
Copyright (C) Tim Potter 2000
Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
Copyright (C) Simo Sorce 2003
Copyright (C) Gerald 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"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_IDMAP
#include <lber.h>
#include <ldap.h>
#include "smbldap.h"
struct ldap_idmap_state {
struct smbldap_state *smbldap_state;
TALLOC_CTX *mem_ctx;
};
static struct ldap_idmap_state ldap_state;
/* number tries while allocating new id */
#define LDAP_MAX_ALLOC_ID 128
/***********************************************************************
This function cannot be called to modify a mapping, only set a new one
***********************************************************************/
static NTSTATUS ldap_set_mapping(const DOM_SID *sid, unid_t id, enum idmap_type id_type)
{
pstring dn;
pstring id_str;
fstring type;
LDAPMod **mods = NULL;
int rc = -1;
int ldap_op;
fstring sid_string;
LDAPMessage *entry = NULL;
sid_to_string( sid_string, sid );
ldap_op = LDAP_MOD_ADD;
pstr_sprintf(dn, "%s=%s,%s", get_attr_key2string( sidmap_attr_list, LDAP_ATTR_SID),
sid_string, lp_ldap_idmap_suffix());
if ( id_type == ID_USERID ) {
fstrcpy( type, get_attr_key2string( sidmap_attr_list, LDAP_ATTR_UIDNUMBER ) );
} else {
fstrcpy( type, get_attr_key2string( sidmap_attr_list, LDAP_ATTR_GIDNUMBER ) );
}
pstr_sprintf(id_str, "%lu", ((id_type == ID_USERID) ? (unsigned long)id.uid :
(unsigned long)id.gid));
smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_IDMAP_ENTRY );
smbldap_make_mod( ldap_state.smbldap_state->ldap_struct,
entry, &mods, type, id_str );
smbldap_make_mod( ldap_state.smbldap_state->ldap_struct,
entry, &mods,
get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID),
sid_string );
/* There may well be nothing at all to do */
if (mods) {
smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_SID_ENTRY );
rc = smbldap_add(ldap_state.smbldap_state, dn, mods);
ldap_mods_free( mods, True );
} else {
rc = LDAP_SUCCESS;
}
if (rc != LDAP_SUCCESS) {
char *ld_error = NULL;
ldap_get_option(ldap_state.smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
&ld_error);
DEBUG(0,("ldap_set_mapping_internals: Failed to %s mapping from %s to %lu [%s]\n",
(ldap_op == LDAP_MOD_ADD) ? "add" : "replace",
sid_string, (unsigned long)((id_type & ID_USERID) ? id.uid : id.gid), type));
DEBUG(0, ("ldap_set_mapping_internals: Error was: %s (%s)\n",
ld_error ? ld_error : "(NULL)", ldap_err2string (rc)));
return NT_STATUS_UNSUCCESSFUL;
}
DEBUG(10,("ldap_set_mapping: Successfully created mapping from %s to %lu [%s]\n",
sid_string, ((id_type & ID_USERID) ? (unsigned long)id.uid :
(unsigned long)id.gid), type));
return NT_STATUS_OK;
}
/*****************************************************************************
Allocate a new uid or gid
*****************************************************************************/
static NTSTATUS ldap_allocate_id(unid_t *id, enum idmap_type id_type)
{
NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
int rc = LDAP_SERVER_DOWN;
int count = 0;
LDAPMessage *result = NULL;
LDAPMessage *entry = NULL;
pstring id_str, new_id_str;
LDAPMod **mods = NULL;
const char *type;
char *dn = NULL;
const char **attr_list;
pstring filter;
uid_t luid, huid;
gid_t lgid, hgid;
if (id_type != ID_USERID && id_type != ID_GROUPID) {
return NT_STATUS_INVALID_PARAMETER;
}
type = (id_type == ID_USERID) ?
get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER ) :
get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
pstr_sprintf(filter, "(objectClass=%s)", LDAP_OBJ_IDPOOL);
attr_list = get_attr_list( NULL, idpool_attr_list );
rc = smbldap_search(ldap_state.smbldap_state, lp_ldap_idmap_suffix(),
LDAP_SCOPE_SUBTREE, filter,
attr_list, 0, &result);
TALLOC_FREE( attr_list );
if (rc != LDAP_SUCCESS) {
DEBUG(0,("ldap_allocate_id: %s object not found\n", LDAP_OBJ_IDPOOL));
goto out;
}
count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
if (count != 1) {
DEBUG(0,("ldap_allocate_id: single %s object not found\n", LDAP_OBJ_IDPOOL));
goto out;
}
dn = smbldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
if (!dn) {
goto out;
}
entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
if (!smbldap_get_single_pstring(ldap_state.smbldap_state->ldap_struct, entry, type, id_str)) {
DEBUG(0,("ldap_allocate_id: %s attribute not found\n",
type));
goto out;
}
/* this must succeed or else we wouldn't have initialized */
lp_idmap_uid( &luid, &huid);
lp_idmap_gid( &lgid, &hgid);
/* make sure we still have room to grow */
if (id_type == ID_USERID) {
id->uid = strtoul(id_str, NULL, 10);
if (id->uid > huid ) {
DEBUG(0,("ldap_allocate_id: Cannot allocate uid above %lu!\n",
(unsigned long)huid));
goto out;
}
} else {
id->gid = strtoul(id_str, NULL, 10);
if (id->gid > hgid ) {
DEBUG(0,("ldap_allocate_id: Cannot allocate gid above %lu!\n",
(unsigned long)hgid));
goto out;
}
}
pstr_sprintf(new_id_str, "%lu",
((id_type == ID_USERID) ? (unsigned long)id->uid :
(unsigned long)id->gid) + 1);
smbldap_set_mod( &mods, LDAP_MOD_DELETE, type, id_str );
smbldap_set_mod( &mods, LDAP_MOD_ADD, type, new_id_str );
if (mods == NULL) {
DEBUG(0,("ldap_allocate_id: smbldap_set_mod() failed.\n"));
goto out;
}
rc = smbldap_modify(ldap_state.smbldap_state, dn, mods);
ldap_mods_free( mods, True );
if (rc != LDAP_SUCCESS) {
DEBUG(1,("ldap_allocate_id: Failed to allocate new %s. ldap_modify() failed.\n",
type));
goto out;
}
ret = NT_STATUS_OK;
out:
SAFE_FREE(dn);
if (result != NULL)
ldap_msgfree(result);
return ret;
}
/*****************************************************************************
get a sid from an id
*****************************************************************************/
static NTSTATUS ldap_get_sid_from_id(DOM_SID *sid, unid_t id, enum idmap_type id_type, int flags)
{
LDAPMessage *result = NULL;
LDAPMessage *entry = NULL;
pstring sid_str;
pstring filter;
pstring suffix;
const char *type;
int rc;
int count;
NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
const char **attr_list;
if ( id_type == ID_USERID )
type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER );
else
type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
pstrcpy( suffix, lp_ldap_idmap_suffix() );
pstr_sprintf(filter, "(&(objectClass=%s)(%s=%lu))",
LDAP_OBJ_IDMAP_ENTRY, type,
((id_type & ID_USERID) ? (unsigned long)id.uid : (unsigned long)id.gid));
attr_list = get_attr_list( NULL, sidmap_attr_list );
rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE,
filter, attr_list, 0, &result);
if (rc != LDAP_SUCCESS) {
DEBUG(3,("ldap_get_isd_from_id: Failure looking up entry (%s)\n",
ldap_err2string(rc) ));
goto out;
}
count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
if (count != 1) {
DEBUG(0,("ldap_get_sid_from_id: mapping not found for %s: %lu\n",
type, ((id_type & ID_USERID) ? (unsigned long)id.uid :
(unsigned long)id.gid)));
goto out;
}
entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
if ( !smbldap_get_single_pstring(ldap_state.smbldap_state->ldap_struct, entry, LDAP_ATTRIBUTE_SID, sid_str) )
goto out;
if (!string_to_sid(sid, sid_str))
goto out;
ret = NT_STATUS_OK;
out:
TALLOC_FREE( attr_list );
if (result)
ldap_msgfree(result);
return ret;
}
/***********************************************************************
Get an id from a sid - urg. This is assuming the *output* parameter id_type
has been initialized with the correct needed type - ID_USERID or ID_GROUPID.
This *sucks* and is bad design and needs fixing. JRA.
***********************************************************************/
static NTSTATUS ldap_get_id_from_sid(unid_t *id, enum idmap_type *id_type, const DOM_SID *sid, int flags)
{
LDAPMessage *result = NULL;
LDAPMessage *entry = NULL;
pstring sid_str;
pstring filter;
pstring id_str;
const char *suffix;
const char *type;
int rc;
int count;
const char **attr_list;
char *dn = NULL;
NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
sid_to_string(sid_str, sid);
DEBUG(8,("ldap_get_id_from_sid: %s (%s)\n", sid_str,
(*id_type & ID_GROUPID ? "group" : "user") ));
suffix = lp_ldap_idmap_suffix();
pstr_sprintf(filter, "(&(objectClass=%s)(%s=%s))",
LDAP_OBJ_IDMAP_ENTRY, LDAP_ATTRIBUTE_SID, sid_str);
if ( *id_type == ID_GROUPID )
type = get_attr_key2string( sidmap_attr_list, LDAP_ATTR_GIDNUMBER );
else
type = get_attr_key2string( sidmap_attr_list, LDAP_ATTR_UIDNUMBER );
/* do the search and check for errors */
attr_list = get_attr_list( NULL, sidmap_attr_list );
rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE,
filter, attr_list, 0, &result);
if (rc != LDAP_SUCCESS) {
DEBUG(3,("ldap_get_id_from_sid: Failure looking up idmap entry (%s)\n",
ldap_err2string(rc) ));
goto out;
}
/* check for the number of entries returned */
count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
if ( count > 1 ) {
DEBUG(0, ("ldap_get_id_from_sid: (2nd) search %s returned [%d] entries!\n",
filter, count));
goto out;
}
/* try to allocate a new id if we still haven't found one */
if ( !count ) {
int i;
if (flags & IDMAP_FLAG_QUERY_ONLY) {
DEBUG(5,("ldap_get_id_from_sid: No matching entry found and QUERY_ONLY flag set\n"));
goto out;
}
DEBUG(8,("ldap_get_id_from_sid: Allocating new id\n"));
for (i = 0; i < LDAP_MAX_ALLOC_ID; i++) {
ret = ldap_allocate_id(id, *id_type);
if ( NT_STATUS_IS_OK(ret) )
break;
}
if ( !NT_STATUS_IS_OK(ret) ) {
DEBUG(0,("ldap_allocate_id: cannot acquire id lock!\n"));
goto out;
}
DEBUG(10,("ldap_get_id_from_sid: Allocated new %cid [%ul]\n",
(*id_type & ID_GROUPID ? 'g' : 'u'), (uint32)id->uid ));
ret = ldap_set_mapping(sid, *id, *id_type);
/* all done */
goto out;
}
DEBUG(10,("ldap_get_id_from_sid: success\n"));
entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
dn = smbldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
if (!dn)
goto out;
DEBUG(10, ("Found mapping entry at dn=%s, looking for %s\n", dn, type));
if ( smbldap_get_single_pstring(ldap_state.smbldap_state->ldap_struct, entry, type, id_str) ) {
if ( (*id_type == ID_USERID) )
id->uid = strtoul(id_str, NULL, 10);
else
id->gid = strtoul(id_str, NULL, 10);
ret = NT_STATUS_OK;
goto out;
}
out:
TALLOC_FREE( attr_list );
if (result)
ldap_msgfree(result);
SAFE_FREE(dn);
return ret;
}
/**********************************************************************
Verify the sambaUnixIdPool entry in the directiry.
**********************************************************************/
static NTSTATUS verify_idpool( void )
{
fstring filter;
int rc;
const char **attr_list;
LDAPMessage *result = NULL;
LDAPMod **mods = NULL;
int count;
fstr_sprintf( filter, "(objectclass=%s)", LDAP_OBJ_IDPOOL );
attr_list = get_attr_list( NULL, idpool_attr_list );
rc = smbldap_search(ldap_state.smbldap_state, lp_ldap_idmap_suffix(),
LDAP_SCOPE_SUBTREE, filter, attr_list, 0, &result);
TALLOC_FREE( attr_list );
if (rc != LDAP_SUCCESS)
return NT_STATUS_UNSUCCESSFUL;
count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
ldap_msgfree(result);
if ( count > 1 ) {
DEBUG(0,("ldap_idmap_init: multiple entries returned from %s (base == %s)\n",
filter, lp_ldap_idmap_suffix() ));
return NT_STATUS_UNSUCCESSFUL;
}
else if (count == 0) {
uid_t luid, huid;
gid_t lgid, hgid;
fstring uid_str, gid_str;
if ( !lp_idmap_uid(&luid, &huid) || !lp_idmap_gid( &lgid, &hgid ) ) {
DEBUG(0,("ldap_idmap_init: idmap uid/gid parameters not specified\n"));
return NT_STATUS_UNSUCCESSFUL;
}
fstr_sprintf( uid_str, "%lu", (unsigned long)luid );
fstr_sprintf( gid_str, "%lu", (unsigned long)lgid );
smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_IDPOOL );
smbldap_set_mod( &mods, LDAP_MOD_ADD,
get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER), uid_str );
smbldap_set_mod( &mods, LDAP_MOD_ADD,
get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER), gid_str );
if (mods) {
rc = smbldap_modify(ldap_state.smbldap_state, lp_ldap_idmap_suffix(), mods);
ldap_mods_free( mods, True );
} else {
return NT_STATUS_UNSUCCESSFUL;
}
}
return ( rc==LDAP_SUCCESS ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
}
/*****************************************************************************
Initialise idmap database.
*****************************************************************************/
static NTSTATUS ldap_idmap_init( const char *params )
{
NTSTATUS nt_status;
ldap_state.mem_ctx = talloc_init("idmap_ldap");
if (!ldap_state.mem_ctx) {
return NT_STATUS_NO_MEMORY;
}
/* assume location is the only parameter */
if (!NT_STATUS_IS_OK(nt_status =
smbldap_init(ldap_state.mem_ctx, params,
&ldap_state.smbldap_state))) {
talloc_destroy(ldap_state.mem_ctx);
return nt_status;
}
/* see if the idmap suffix and sub entries exists */
nt_status = verify_idpool();
if ( !NT_STATUS_IS_OK(nt_status) )
return nt_status;
return NT_STATUS_OK;
}
/*****************************************************************************
End the LDAP session
*****************************************************************************/
static NTSTATUS ldap_idmap_close(void)
{
smbldap_free_struct(&(ldap_state).smbldap_state);
talloc_destroy(ldap_state.mem_ctx);
DEBUG(5,("The connection to the LDAP server was closed\n"));
/* maybe free the results here --metze */
return NT_STATUS_OK;
}
/* This function doesn't make as much sense in an LDAP world since the calling
node doesn't really control the ID ranges */
static void ldap_idmap_status(void)
{
DEBUG(0, ("LDAP IDMAP Status not available\n"));
}
static struct idmap_methods ldap_methods = {
ldap_idmap_init,
ldap_allocate_id,
ldap_get_sid_from_id,
ldap_get_id_from_sid,
ldap_set_mapping,
ldap_idmap_close,
ldap_idmap_status
};
NTSTATUS idmap_ldap_init(void)
{
return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ldap", &ldap_methods);
}

View File

@@ -1,561 +0,0 @@
/*
* idmap_rid: static map between Active Directory/NT RIDs and RFC 2307 accounts
* Copyright (C) Guenther Deschner, 2004
* Copyright (C) Sumit Bose, 2004
*
* 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"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_IDMAP
NTSTATUS init_module(void);
struct dom_entry {
fstring name;
fstring sid;
uint32 min_id;
uint32 max_id;
};
typedef struct trust_dom_array {
int number;
struct dom_entry *dom;
} trust_dom_array;
static trust_dom_array trust;
static NTSTATUS rid_idmap_parse(const char *init_param,
uint32 num_domains,
fstring *domain_names,
DOM_SID *domain_sids,
uid_t u_low,
uid_t u_high)
{
const char *p;
int i;
fstring sid_str;
BOOL known_domain = False;
fstring tok;
p = init_param;
trust.number = 0;
/* falling back to automatic mapping when there were no options given */
if (!*init_param) {
DEBUG(3,("rid_idmap_parse: no domain list given or trusted domain-support deactivated, falling back to automatic mapping for own domain:\n"));
sid_to_string(sid_str, &domain_sids[0]);
fstrcpy(trust.dom[0].name, domain_names[0]);
fstrcpy(trust.dom[0].sid, sid_str);
trust.dom[0].min_id = u_low;
trust.dom[0].max_id = u_high;
trust.number = 1;
DEBUGADD(3,("rid_idmap_parse:\tdomain: [%s], sid: [%s], range=[%d-%d]\n",
trust.dom[0].name, trust.dom[0].sid, trust.dom[0].min_id, trust.dom[0].max_id));
return NT_STATUS_OK;
}
/* scan through the init_param-list */
while (next_token(&init_param, tok, LIST_SEP, sizeof(tok))) {
p = tok;
DEBUG(3,("rid_idmap_parse: parsing entry: %d\n", trust.number));
/* reinit sizes */
trust.dom = SMB_REALLOC_ARRAY(trust.dom, struct dom_entry,
trust.number+1);
if ( trust.dom == NULL ) {
return NT_STATUS_NO_MEMORY;
}
if (!next_token(&p, tok, "=", sizeof(tok))) {
DEBUG(0, ("rid_idmap_parse: no '=' sign found in domain list [%s]\n", init_param));
return NT_STATUS_UNSUCCESSFUL;
}
/* add the name */
fstrcpy(trust.dom[trust.number].name, tok);
DEBUGADD(3,("rid_idmap_parse:\tentry %d has name: [%s]\n", trust.number, trust.dom[trust.number].name));
/* add the domain-sid */
for (i=0; i<num_domains; i++) {
known_domain = False;
if (strequal(domain_names[i], trust.dom[trust.number].name)) {
sid_to_string(sid_str, &domain_sids[i]);
fstrcpy(trust.dom[trust.number].sid, sid_str);
DEBUGADD(3,("rid_idmap_parse:\tentry %d has sid: [%s]\n", trust.number, trust.dom[trust.number].sid));
known_domain = True;
break;
}
}
if (!known_domain) {
DEBUG(0,("rid_idmap_parse: your DC does not know anything about domain: [%s]\n", trust.dom[trust.number].name));
return NT_STATUS_INVALID_PARAMETER;
}
if (!next_token(&p, tok, "-", sizeof(tok))) {
DEBUG(0,("rid_idmap_parse: no mapping-range defined\n"));
return NT_STATUS_INVALID_PARAMETER;
}
/* add min_id */
trust.dom[trust.number].min_id = atoi(tok);
DEBUGADD(3,("rid_idmap_parse:\tentry %d has min_id: [%d]\n", trust.number, trust.dom[trust.number].min_id));
/* add max_id */
trust.dom[trust.number].max_id = atoi(p);
DEBUGADD(3,("rid_idmap_parse:\tentry %d has max_id: [%d]\n", trust.number, trust.dom[trust.number].max_id));
trust.number++;
}
return NT_STATUS_OK;
}
static NTSTATUS rid_idmap_get_domains(uint32 *num_domains, fstring **domain_names, DOM_SID **domain_sids)
{
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
struct cli_state *cli;
struct rpc_pipe_client *pipe_hnd;
TALLOC_CTX *mem_ctx;
POLICY_HND pol;
uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
fstring dc_name;
struct in_addr dc_ip;
const char *password = NULL;
const char *username = NULL;
const char *domain = NULL;
uint32 info_class = 5;
char *domain_name = NULL;
DOM_SID *domain_sid, sid;
fstring sid_str;
int i;
uint32 trusted_num_domains = 0;
char **trusted_domain_names;
DOM_SID *trusted_domain_sids;
uint32 enum_ctx = 0;
int own_domains = 2;
/* put the results together */
*num_domains = 2;
*domain_names = SMB_MALLOC_ARRAY(fstring, *num_domains);
*domain_sids = SMB_MALLOC_ARRAY(DOM_SID, *num_domains);
/* avoid calling a DC when trusted domains are not allowed anyway */
if (!lp_allow_trusted_domains()) {
fstrcpy((*domain_names)[0], lp_workgroup());
if (!secrets_fetch_domain_sid(lp_workgroup(), &sid)) {
DEBUG(0,("rid_idmap_get_domains: failed to retrieve domain sid\n"));
return status;
}
sid_copy(&(*domain_sids)[0], &sid);
/* add BUILTIN */
fstrcpy((*domain_names)[1], "BUILTIN");
sid_copy(&(*domain_sids)[1], &global_sid_Builtin);
return NT_STATUS_OK;
}
/* create mem_ctx */
if (!(mem_ctx = talloc_init("rid_idmap_get_trusted_domains"))) {
DEBUG(0, ("rid_idmap_get_domains: talloc_init() failed\n"));
return NT_STATUS_NO_MEMORY;
}
if (!get_dc_name(lp_workgroup(), 0, dc_name, &dc_ip)) {
DEBUG(1, ("rid_idmap_get_domains: could not get dc-name\n"));
return NT_STATUS_UNSUCCESSFUL;
}
/* open a connection to the dc */
username = (char *)secrets_fetch(SECRETS_AUTH_USER, NULL);
password = (char *)secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
domain = (char *)secrets_fetch(SECRETS_AUTH_DOMAIN, NULL);
if (username) {
if (!domain)
domain = smb_xstrdup(lp_workgroup());
if (!password)
password = smb_xstrdup("");
DEBUG(3, ("rid_idmap_get_domains: IPC$ connections done by user %s\\%s\n", domain, username));
} else {
DEBUG(3, ("rid_idmap_get_domains: IPC$ connections done anonymously\n"));
username = "";
domain = "";
password = "";
}
DEBUG(10, ("rid_idmap_get_domains: opening connection to [%s]\n", dc_name));
status = cli_full_connection(&cli, global_myname(), dc_name,
NULL, 0,
"IPC$", "IPC",
username,
lp_workgroup(),
password,
CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK, True, NULL);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("rid_idmap_get_domains: could not setup connection to dc\n"));
return status;
}
/* query the lsa-pipe */
pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_LSARPC, &status);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("rid_idmap_get_domains: could not setup connection to dc\n"));
goto out;
}
/* query policies */
status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, False, des_access,
&pol);
if (!NT_STATUS_IS_OK(status)) {
goto out;
}
status = rpccli_lsa_query_info_policy(pipe_hnd, mem_ctx, &pol,
info_class, &domain_name,
&domain_sid);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("rid_idmap_get_domains: cannot retrieve domain-info\n"));
goto out;
}
sid_to_string(sid_str, domain_sid);
DEBUG(10,("rid_idmap_get_domains: my domain: [%s], sid: [%s]\n", domain_name, sid_str));
/* scan trusted domains */
DEBUG(10, ("rid_idmap_get_domains: enumerating trusted domains\n"));
status = rpccli_lsa_enum_trust_dom(pipe_hnd, mem_ctx, &pol, &enum_ctx,
&trusted_num_domains,
&trusted_domain_names,
&trusted_domain_sids);
if (!NT_STATUS_IS_OK(status) &&
!NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES) &&
!NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
DEBUG(1, ("rid_idmap_get_domains: could not enumerate trusted domains\n"));
goto out;
}
/* show trusted domains */
DEBUG(10,("rid_idmap_get_domains: scan for trusted domains gave %d results:\n", trusted_num_domains));
for (i=0; i<trusted_num_domains; i++) {
sid_to_string(sid_str, &trusted_domain_sids[i]);
DEBUGADD(10,("rid_idmap_get_domains:\t#%d\tDOMAIN: [%s], SID: [%s]\n",
i, trusted_domain_names[i], sid_str));
}
if (!sid_equal(domain_sid, get_global_sam_sid()))
++own_domains;
/* put the results together */
*num_domains = trusted_num_domains + own_domains;
*domain_names = SMB_REALLOC_ARRAY(*domain_names, fstring,
*num_domains);
if (!*domain_names) {
goto out;
}
*domain_sids = SMB_REALLOC_ARRAY(*domain_sids, DOM_SID, *num_domains);
if (!*domain_sids) {
goto out;
}
/* first add mydomain */
fstrcpy((*domain_names)[0], domain_name);
sid_copy(&(*domain_sids)[0], domain_sid);
/* then add BUILTIN */
fstrcpy((*domain_names)[1], "BUILTIN");
sid_copy(&(*domain_sids)[1], &global_sid_Builtin);
/* then add my local sid */
if (!sid_equal(domain_sid, get_global_sam_sid())) {
fstrcpy((*domain_names)[2], global_myname());
sid_copy(&(*domain_sids)[2], get_global_sam_sid());
}
/* add trusted domains */
for (i=0; i<trusted_num_domains; i++) {
fstrcpy((*domain_names)[i+own_domains], trusted_domain_names[i]);
sid_copy(&((*domain_sids)[i+own_domains]), &(trusted_domain_sids[i]));
}
/* show complete domain list */
DEBUG(5,("rid_idmap_get_domains: complete domain-list has %d entries:\n", *num_domains));
for (i=0; i<*num_domains; i++) {
sid_to_string(sid_str, &((*domain_sids)[i]));
DEBUGADD(5,("rid_idmap_get_domains:\t#%d\tdomain: [%s], sid: [%s]\n",
i, (*domain_names)[i], sid_str ));
}
status = NT_STATUS_OK;
out:
rpccli_lsa_Close(pipe_hnd, mem_ctx, &pol);
cli_rpc_pipe_close(pipe_hnd);
talloc_destroy(mem_ctx);
cli_shutdown(cli);
return status;
}
static NTSTATUS rid_idmap_init(const char *init_param)
{
int i, j;
uid_t u_low, u_high;
gid_t g_low, g_high;
uint32 num_domains = 0;
fstring *domain_names;
DOM_SID *domain_sids;
NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
trust.dom = NULL;
/* basic sanity checks */
if (!lp_idmap_uid(&u_low, &u_high) || !lp_idmap_gid(&g_low, &g_high)) {
DEBUG(0, ("rid_idmap_init: cannot get required global idmap-ranges.\n"));
return nt_status;
}
if (u_low != g_low || u_high != g_high) {
DEBUG(0, ("rid_idmap_init: range defined in \"idmap uid\" must match range of \"idmap gid\".\n"));
return nt_status;
}
if (lp_allow_trusted_domains()) {
#if IDMAP_RID_SUPPORT_TRUSTED_DOMAINS
DEBUG(3,("rid_idmap_init: enabling trusted-domain-mapping\n"));
#else
DEBUG(0,("rid_idmap_init: idmap_rid does not work with trusted domains\n"));
DEBUGADD(0,("rid_idmap_init: please set \"allow trusted domains\" to \"no\" when using idmap_rid\n"));
return nt_status;
#endif
}
/* init sizes */
trust.dom = SMB_MALLOC_P(struct dom_entry);
if (trust.dom == NULL) {
return NT_STATUS_NO_MEMORY;
}
/* retrieve full domain list */
nt_status = rid_idmap_get_domains(&num_domains, &domain_names, &domain_sids);
if (!NT_STATUS_IS_OK(nt_status) &&
!NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_MORE_ENTRIES) &&
!NT_STATUS_EQUAL(nt_status, STATUS_MORE_ENTRIES)) {
DEBUG(0, ("rid_idmap_init: cannot fetch sids for domain and/or trusted-domains from domain-controller.\n"));
return nt_status;
}
/* parse the init string */
nt_status = rid_idmap_parse(init_param, num_domains, domain_names, domain_sids, u_low, u_high);
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(0, ("rid_idmap_init: cannot parse module-configuration\n"));
goto out;
}
nt_status = NT_STATUS_INVALID_PARAMETER;
/* some basic sanity checks */
for (i=0; i<trust.number; i++) {
if (trust.dom[i].min_id > trust.dom[i].max_id) {
DEBUG(0, ("rid_idmap_init: min_id (%d) has to be smaller than max_id (%d) for domain [%s]\n",
trust.dom[i].min_id, trust.dom[i].max_id, trust.dom[i].name));
goto out;
}
if (trust.dom[i].min_id < u_low || trust.dom[i].max_id > u_high) {
DEBUG(0, ("rid_idmap_init: mapping of domain [%s] (%d-%d) has to fit into global idmap range (%d-%d).\n",
trust.dom[i].name, trust.dom[i].min_id, trust.dom[i].max_id, u_low, u_high));
goto out;
}
}
/* check for overlaps */
for (i=0; i<trust.number-1; i++) {
for (j=i+1; j<trust.number; j++) {
if (trust.dom[i].min_id <= trust.dom[j].max_id && trust.dom[j].min_id <= trust.dom[i].max_id) {
DEBUG(0, ("rid_idmap_init: the ranges of domain [%s] and [%s] overlap\n",
trust.dom[i+1].name, trust.dom[i].name));
goto out;
}
}
}
DEBUG(3, ("rid_idmap_init: using %d mappings:\n", trust.number));
for (i=0; i<trust.number; i++) {
DEBUGADD(3, ("rid_idmap_init:\tdomain: [%s], sid: [%s], min_id: [%d], max_id: [%d]\n",
trust.dom[i].name, trust.dom[i].sid, trust.dom[i].min_id, trust.dom[i].max_id));
}
nt_status = NT_STATUS_OK;
out:
SAFE_FREE(domain_names);
SAFE_FREE(domain_sids);
return nt_status;
}
static NTSTATUS rid_idmap_get_sid_from_id(DOM_SID *sid, unid_t unid, enum idmap_type id_type, int flags)
{
fstring sid_string;
int i;
DOM_SID sidstr;
/* find range */
for (i=0; i<trust.number; i++) {
if (trust.dom[i].min_id <= unid.uid && trust.dom[i].max_id >= unid.uid )
break;
}
if (i == trust.number) {
DEBUG(0,("rid_idmap_get_sid_from_id: no suitable range available for id: %d\n", unid.uid));
return NT_STATUS_INVALID_PARAMETER;
}
/* use lower-end of idmap-range as offset for users and groups*/
unid.uid -= trust.dom[i].min_id;
if (!trust.dom[i].sid)
return NT_STATUS_INVALID_PARAMETER;
string_to_sid(&sidstr, trust.dom[i].sid);
sid_copy(sid, &sidstr);
if (!sid_append_rid( sid, (unsigned long)unid.uid )) {
DEBUG(0,("rid_idmap_get_sid_from_id: could not append rid to domain sid\n"));
return NT_STATUS_NO_MEMORY;
}
DEBUG(3, ("rid_idmap_get_sid_from_id: mapped POSIX %s %d to SID [%s]\n",
(id_type == ID_GROUPID) ? "GID" : "UID", unid.uid,
sid_to_string(sid_string, sid)));
return NT_STATUS_OK;
}
static NTSTATUS rid_idmap_get_id_from_sid(unid_t *unid, enum idmap_type *id_type, const DOM_SID *sid, int flags)
{
fstring sid_string;
int i;
uint32 rid;
DOM_SID sidstr;
/* check if we have a mapping for the sid */
for (i=0; i<trust.number; i++) {
if (!trust.dom[i].sid) {
return NT_STATUS_INVALID_PARAMETER;
}
string_to_sid(&sidstr, trust.dom[i].sid);
if ( sid_compare_domain(sid, &sidstr) == 0 )
break;
}
if (i == trust.number) {
DEBUG(0,("rid_idmap_get_id_from_sid: no suitable range available for sid: %s\n",
sid_string_static(sid)));
return NT_STATUS_INVALID_PARAMETER;
}
if (!sid_peek_rid(sid, &rid)) {
DEBUG(0,("rid_idmap_get_id_from_sid: could not peek rid\n"));
return NT_STATUS_INVALID_PARAMETER;
}
/* use lower-end of idmap-range as offset for users and groups */
unid->uid = rid + trust.dom[i].min_id;
if (unid->uid > trust.dom[i].max_id) {
DEBUG(0,("rid_idmap_get_id_from_sid: rid: %d (%s: %d) too high for mapping of domain: %s (%d-%d)\n",
rid, (*id_type == ID_GROUPID) ? "GID" : "UID", unid->uid, trust.dom[i].name,
trust.dom[i].min_id, trust.dom[i].max_id));
return NT_STATUS_INVALID_PARAMETER;
}
if (unid->uid < trust.dom[i].min_id) {
DEBUG(0,("rid_idmap_get_id_from_sid: rid: %d (%s: %d) too low for mapping of domain: %s (%d-%d)\n",
rid, (*id_type == ID_GROUPID) ? "GID" : "UID", unid->uid,
trust.dom[i].name, trust.dom[i].min_id, trust.dom[i].max_id));
return NT_STATUS_INVALID_PARAMETER;
}
DEBUG(3,("rid_idmap_get_id_from_sid: mapped SID [%s] to POSIX %s %d\n",
sid_to_string(sid_string, sid),
(*id_type == ID_GROUPID) ? "GID" : "UID", unid->uid));
return NT_STATUS_OK;
}
static NTSTATUS rid_idmap_set_mapping(const DOM_SID *sid, unid_t id, enum idmap_type id_type)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
static NTSTATUS rid_idmap_close(void)
{
SAFE_FREE(trust.dom);
return NT_STATUS_OK;
}
static NTSTATUS rid_idmap_allocate_id(unid_t *id, enum idmap_type id_type)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
static void rid_idmap_status(void)
{
DEBUG(0, ("RID IDMAP Status not available\n"));
}
static struct idmap_methods rid_methods = {
rid_idmap_init,
rid_idmap_allocate_id,
rid_idmap_get_sid_from_id,
rid_idmap_get_id_from_sid,
rid_idmap_set_mapping,
rid_idmap_close,
rid_idmap_status
};
NTSTATUS idmap_rid_init(void)
{
return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "rid", &rid_methods);
}

View File

@@ -1,447 +0,0 @@
/*
Unix SMB/CIFS implementation.
idmap LDAP backend
Copyright (C) Tim Potter 2000
Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
Copyright (C) Simo Sorce 2003
Copyright (C) Gerald 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"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_IDMAP
struct ldap_connection *ldap_conn = NULL;
/* number tries while allocating new id */
#define LDAP_MAX_ALLOC_ID 128
/***********************************************************************
This function cannot be called to modify a mapping, only set a new one
***********************************************************************/
static NTSTATUS ldap_set_mapping(const DOM_SID *sid, unid_t id, int id_type)
{
NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
pstring id_str;
const char *type;
fstring sid_string;
struct ldap_message *msg;
struct ldap_message *mod_res = NULL;
char *mod;
type = (id_type & ID_USERID) ? "uidNumber" : "gidNumber";
sid_to_string( sid_string, sid );
pstr_sprintf(id_str, "%lu",
((id_type & ID_USERID) ?
(unsigned long)id.uid : (unsigned long)id.gid));
asprintf(&mod,
"dn: sambaSID=%s,%s\n"
"changetype: add\n"
"objectClass: sambaIdmapEntry\n"
"objectClass: sambaSidEntry\n"
"sambaSID: %s\n"
"%s: %lu\n",
sid_string, lp_ldap_idmap_suffix(), sid_string, type,
((id_type & ID_USERID) ?
(unsigned long)id.uid : (unsigned long)id.gid));
msg = ldap_ldif2msg(mod);
SAFE_FREE(mod);
if (msg == NULL)
return NT_STATUS_NO_MEMORY;
mod_res = ldap_transaction(ldap_conn, msg);
if ((mod_res == NULL) || (mod_res->r.ModifyResponse.resultcode != 0))
goto out;
ret = NT_STATUS_OK;
out:
destroy_ldap_message(msg);
destroy_ldap_message(mod_res);
return ret;
}
/*****************************************************************************
Allocate a new uid or gid
*****************************************************************************/
static NTSTATUS ldap_allocate_id(unid_t *id, enum idmap_type id_type)
{
NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
uid_t luid, huid;
gid_t lgid, hgid;
const char *attrs[] = { "uidNumber", "gidNumber" };
struct ldap_message *idpool_s = NULL;
struct ldap_message *idpool = NULL;
struct ldap_message *mod_msg = NULL;
struct ldap_message *mod_res = NULL;
int value;
const char *id_attrib;
char *mod;
if (id_type != ID_USERID && id_type != ID_GROUPID) {
return NT_STATUS_INVALID_PARAMETER;
}
id_attrib = (id_type == ID_USERID) ? "uidNumber" : "gidNumber";
idpool_s = new_ldap_search_message(lp_ldap_suffix(),
LDAP_SEARCH_SCOPE_SUB,
"(objectclass=sambaUnixIdPool)",
2, attrs);
if (idpool_s == NULL)
return NT_STATUS_NO_MEMORY;
idpool = ldap_searchone(ldap_conn, idpool_s, NULL);
if (idpool == NULL)
goto out;
if (!ldap_find_single_int(idpool, id_attrib, &value))
goto out;
/* this must succeed or else we wouldn't have initialized */
lp_idmap_uid( &luid, &huid);
lp_idmap_gid( &lgid, &hgid);
/* make sure we still have room to grow */
if (id_type == ID_USERID) {
id->uid = value;
if (id->uid > huid ) {
DEBUG(0,("ldap_allocate_id: Cannot allocate uid "
"above %lu!\n", (unsigned long)huid));
goto out;
}
}
else {
id->gid = value;
if (id->gid > hgid ) {
DEBUG(0,("ldap_allocate_id: Cannot allocate gid "
"above %lu!\n", (unsigned long)hgid));
goto out;
}
}
asprintf(&mod,
"dn: %s\n"
"changetype: modify\n"
"delete: %s\n"
"%s: %d\n"
"-\n"
"add: %s\n"
"%s: %d\n",
idpool->r.SearchResultEntry.dn, id_attrib, id_attrib, value,
id_attrib, id_attrib, value+1);
mod_msg = ldap_ldif2msg(mod);
SAFE_FREE(mod);
if (mod_msg == NULL)
goto out;
mod_res = ldap_transaction(ldap_conn, mod_msg);
if ((mod_res == NULL) || (mod_res->r.ModifyResponse.resultcode != 0))
goto out;
ret = NT_STATUS_OK;
out:
destroy_ldap_message(idpool_s);
destroy_ldap_message(idpool);
destroy_ldap_message(mod_msg);
destroy_ldap_message(mod_res);
return ret;
}
/*****************************************************************************
get a sid from an id
*****************************************************************************/
static NTSTATUS ldap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
{
pstring filter;
const char *type;
NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
const char *attr_list[] = { "sambaSID" };
struct ldap_message *msg;
struct ldap_message *entry = NULL;
char *sid_str;
type = (id_type & ID_USERID) ? "uidNumber" : "gidNumber";
pstr_sprintf(filter, "(&(objectClass=%s)(%s=%lu))", "sambaIdmapEntry",
type,
((id_type & ID_USERID) ?
(unsigned long)id.uid : (unsigned long)id.gid));
msg = new_ldap_search_message(lp_ldap_idmap_suffix(),
LDAP_SEARCH_SCOPE_SUB,
filter, 1, attr_list);
if (msg == NULL)
return NT_STATUS_NO_MEMORY;
entry = ldap_searchone(ldap_conn, msg, NULL);
if (entry == NULL)
goto out;
if (!ldap_find_single_string(entry, "sambaSID", entry->mem_ctx,
&sid_str))
goto out;
if (!string_to_sid(sid, sid_str))
goto out;
ret = NT_STATUS_OK;
out:
destroy_ldap_message(msg);
destroy_ldap_message(entry);
return ret;
}
/***********************************************************************
Get an id from a sid
***********************************************************************/
static NTSTATUS ldap_get_id_from_sid(unid_t *id, int *id_type,
const DOM_SID *sid)
{
pstring filter;
const char *type;
NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
struct ldap_message *msg;
struct ldap_message *entry = NULL;
int i;
DEBUG(8,("ldap_get_id_from_sid: %s (%s)\n", sid_string_static(sid),
(*id_type & ID_GROUPID ? "group" : "user") ));
type = ((*id_type) & ID_USERID) ? "uidNumber" : "gidNumber";
pstr_sprintf(filter, "(&(objectClass=%s)(%s=%s))",
"sambaIdmapEntry", "sambaSID", sid_string_static(sid));
msg = new_ldap_search_message(lp_ldap_idmap_suffix(),
LDAP_SEARCH_SCOPE_SUB,
filter, 1, &type);
if (msg == NULL)
return NT_STATUS_NO_MEMORY;
entry = ldap_searchone(ldap_conn, msg, NULL);
if (entry != NULL) {
int value;
if (!ldap_find_single_int(entry, type, &value))
goto out;
if ((*id_type) & ID_USERID)
id->uid = value;
else
id->gid = value;
ret = NT_STATUS_OK;
goto out;
}
if ((*id_type) & ID_QUERY_ONLY)
goto out;
/* Allocate a new RID */
for (i = 0; i < LDAP_MAX_ALLOC_ID; i++) {
ret = ldap_allocate_id(id, *id_type);
if ( NT_STATUS_IS_OK(ret) )
break;
}
if ( !NT_STATUS_IS_OK(ret) ) {
DEBUG(0,("Could not allocate id\n"));
goto out;
}
DEBUG(10,("ldap_get_id_from_sid: Allocated new %cid [%ul]\n",
(*id_type & ID_GROUPID ? 'g' : 'u'), (uint32)id->uid ));
ret = ldap_set_mapping(sid, *id, *id_type);
out:
destroy_ldap_message(msg);
destroy_ldap_message(entry);
return ret;
}
/**********************************************************************
Verify the sambaUnixIdPool entry in the directory.
**********************************************************************/
static NTSTATUS verify_idpool(void)
{
const char *attr_list[3] = { "uidnumber", "gidnumber", "objectclass" };
BOOL result;
char *mod;
struct ldap_message *msg, *entry, *res;
uid_t luid, huid;
gid_t lgid, hgid;
msg = new_ldap_search_message(lp_ldap_suffix(),
LDAP_SEARCH_SCOPE_SUB,
"(objectClass=sambaUnixIdPool)",
3, attr_list);
if (msg == NULL)
return NT_STATUS_NO_MEMORY;
entry = ldap_searchone(ldap_conn, msg, NULL);
result = (entry != NULL);
destroy_ldap_message(msg);
destroy_ldap_message(entry);
if (result)
return NT_STATUS_OK;
if ( !lp_idmap_uid(&luid, &huid) || !lp_idmap_gid( &lgid, &hgid ) ) {
DEBUG(3,("ldap_idmap_init: idmap uid/gid parameters not "
"specified\n"));
return NT_STATUS_UNSUCCESSFUL;
}
asprintf(&mod,
"dn: %s\n"
"changetype: modify\n"
"add: objectClass\n"
"objectClass: sambaUnixIdPool\n"
"-\n"
"add: uidNumber\n"
"uidNumber: %lu\n"
"-\n"
"add: gidNumber\n"
"gidNumber: %lu\n",
lp_ldap_idmap_suffix(),
(unsigned long)luid, (unsigned long)lgid);
msg = ldap_ldif2msg(mod);
SAFE_FREE(mod);
if (msg == NULL)
return NT_STATUS_NO_MEMORY;
res = ldap_transaction(ldap_conn, msg);
if ((res == NULL) || (res->r.ModifyResponse.resultcode != 0)) {
destroy_ldap_message(msg);
destroy_ldap_message(res);
DEBUG(5, ("Could not add sambaUnixIdPool\n"));
return NT_STATUS_UNSUCCESSFUL;
}
destroy_ldap_message(msg);
destroy_ldap_message(res);
return NT_STATUS_OK;
}
/*****************************************************************************
Initialise idmap database.
*****************************************************************************/
static NTSTATUS ldap_idmap_init( char *params )
{
NTSTATUS nt_status;
char *dn, *pw;
ldap_conn = new_ldap_connection();
if (!fetch_ldap_pw(&dn, &pw))
return NT_STATUS_UNSUCCESSFUL;
ldap_conn->auth_dn = talloc_strdup(ldap_conn->mem_ctx, dn);
ldap_conn->simple_pw = talloc_strdup(ldap_conn->mem_ctx, pw);
SAFE_FREE(dn);
SAFE_FREE(pw);
if (!ldap_setup_connection(ldap_conn, params, NULL, NULL))
return NT_STATUS_UNSUCCESSFUL;
/* see if the idmap suffix and sub entries exists */
nt_status = verify_idpool();
if ( !NT_STATUS_IS_OK(nt_status) )
return nt_status;
return NT_STATUS_OK;
}
/*****************************************************************************
End the LDAP session
*****************************************************************************/
static NTSTATUS ldap_idmap_close(void)
{
DEBUG(5,("The connection to the LDAP server was closed\n"));
/* maybe free the results here --metze */
return NT_STATUS_OK;
}
/* This function doesn't make as much sense in an LDAP world since the calling
node doesn't really control the ID ranges */
static void ldap_idmap_status(void)
{
DEBUG(0, ("LDAP IDMAP Status not available\n"));
}
static struct idmap_methods ldap_methods = {
ldap_idmap_init,
ldap_allocate_id,
ldap_get_sid_from_id,
ldap_get_id_from_sid,
ldap_set_mapping,
ldap_idmap_close,
ldap_idmap_status
};
NTSTATUS idmap_smbldap_init(void)
{
return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "smbldap", &ldap_methods);
}

View File

@@ -1,693 +0,0 @@
/*
Unix SMB/CIFS implementation.
idmap TDB backend
Copyright (C) Tim Potter 2000
Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
Copyright (C) Simo Sorce 2003
Copyright (C) Jeremy Allison 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 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"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_IDMAP
/* High water mark keys */
#define HWM_GROUP "GROUP HWM"
#define HWM_USER "USER HWM"
/* Globals */
static TDB_CONTEXT *idmap_tdb;
static struct idmap_state {
/* User and group id pool */
uid_t uid_low, uid_high; /* Range of uids to allocate */
gid_t gid_low, gid_high; /* Range of gids to allocate */
} idmap_state;
/**********************************************************************
Allocate either a user or group id from the pool
**********************************************************************/
static NTSTATUS db_allocate_id(unid_t *id, enum idmap_type id_type)
{
BOOL ret;
int hwm;
/* Get current high water mark */
switch (id_type) {
case ID_USERID:
if ((hwm = tdb_fetch_int32(idmap_tdb, HWM_USER)) == -1) {
return NT_STATUS_INTERNAL_DB_ERROR;
}
/* check it is in the range */
if (hwm > idmap_state.uid_high) {
DEBUG(0, ("idmap Fatal Error: UID range full!! (max: %lu)\n",
(unsigned long)idmap_state.uid_high));
return NT_STATUS_UNSUCCESSFUL;
}
/* fetch a new id and increment it */
ret = tdb_change_uint32_atomic(idmap_tdb, HWM_USER, (unsigned int *)&hwm, 1);
if (!ret) {
DEBUG(0, ("idmap_tdb: Fatal error while fetching a new id\n!"));
return NT_STATUS_UNSUCCESSFUL;
}
/* recheck it is in the range */
if (hwm > idmap_state.uid_high) {
DEBUG(0, ("idmap Fatal Error: UID range full!! (max: %lu)\n",
(unsigned long)idmap_state.uid_high));
return NT_STATUS_UNSUCCESSFUL;
}
(*id).uid = hwm;
DEBUG(10,("db_allocate_id: ID_USERID (*id).uid = %d\n", (unsigned int)hwm));
break;
case ID_GROUPID:
if ((hwm = tdb_fetch_int32(idmap_tdb, HWM_GROUP)) == -1) {
return NT_STATUS_INTERNAL_DB_ERROR;
}
/* check it is in the range */
if (hwm > idmap_state.gid_high) {
DEBUG(0, ("idmap Fatal Error: GID range full!! (max: %lu)\n",
(unsigned long)idmap_state.gid_high));
return NT_STATUS_UNSUCCESSFUL;
}
/* fetch a new id and increment it */
ret = tdb_change_uint32_atomic(idmap_tdb, HWM_GROUP, (unsigned int *)&hwm, 1);
if (!ret) {
DEBUG(0, ("idmap_tdb: Fatal error while fetching a new id\n!"));
return NT_STATUS_UNSUCCESSFUL;
}
/* recheck it is in the range */
if (hwm > idmap_state.gid_high) {
DEBUG(0, ("idmap Fatal Error: GID range full!! (max: %lu)\n",
(unsigned long)idmap_state.gid_high));
return NT_STATUS_UNSUCCESSFUL;
}
(*id).gid = hwm;
DEBUG(10,("db_allocate_id: ID_GROUPID (*id).gid = %d\n", (unsigned int)hwm));
break;
default:
return NT_STATUS_INVALID_PARAMETER;
}
return NT_STATUS_OK;
}
/* Get a sid from an id - internal non-reverse map checking function. */
static NTSTATUS db_internal_get_sid_from_id(DOM_SID *sid, unid_t id, enum idmap_type id_type)
{
TDB_DATA key, data;
TALLOC_CTX *memctx;
NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
if ((memctx = talloc_new(NULL)) == NULL) {
DEBUG(0, ("ERROR: Out of memory!\n"));
return NT_STATUS_NO_MEMORY;
}
switch (id_type) {
case ID_USERID:
key.dptr = talloc_asprintf(memctx, "UID %lu", (unsigned long)id.uid);
break;
case ID_GROUPID:
key.dptr = talloc_asprintf(memctx, "GID %lu", (unsigned long)id.gid);
break;
default:
ret = NT_STATUS_INVALID_PARAMETER;
goto done;
}
if (key.dptr == NULL) {
DEBUG(0, ("ERROR: Out of memory!\n"));
ret = NT_STATUS_NO_MEMORY;
goto done;
}
key.dsize = strlen(key.dptr) + 1;
DEBUG(10,("db_internal_get_sid_from_id: fetching record %s\n", key.dptr));
data = tdb_fetch(idmap_tdb, key);
if (data.dptr) {
if (string_to_sid(sid, data.dptr)) {
DEBUG(10,("db_internal_get_sid_from_id: fetching record %s -> %s\n", key.dptr, data.dptr ));
ret = NT_STATUS_OK;
}
SAFE_FREE(data.dptr);
}
done:
talloc_free(memctx);
return ret;
}
/* Get an id from a sid - internal non-reverse map checking function. */
static NTSTATUS db_internal_get_id_from_sid(unid_t *id, enum idmap_type *id_type, const DOM_SID *sid)
{
NTSTATUS ret;
TDB_DATA key, data;
TALLOC_CTX *memctx;
unsigned long rec_id;
if ((memctx = talloc_new(NULL)) == NULL) {
DEBUG(0, ("ERROR: Out of memory!\n"));
return NT_STATUS_NO_MEMORY;
}
/* Check if sid is present in database */
if ((key.dptr = talloc_asprintf(memctx, "%s", sid_string_static(sid))) == NULL) {
DEBUG(0, ("ERROR: Out of memory!\n"));
ret = NT_STATUS_NO_MEMORY;
goto done;
}
key.dsize = strlen(key.dptr) + 1;
DEBUG(10,("db_internal_get_id_from_sid: fetching record %s\n", key.dptr));
data = tdb_fetch(idmap_tdb, key);
if (!data.dptr) {
DEBUG(10,("db_internal_get_id_from_sid: record %s not found\n", key.dptr));
ret = NT_STATUS_NO_SUCH_USER;
goto done;
} else {
DEBUG(10,("db_internal_get_id_from_sid: record %s -> %s\n", key.dptr, data.dptr));
}
/* What type of record is this ? */
/* Try and parse and return a uid */
if (sscanf(data.dptr, "UID %lu", &rec_id) == 1) {
id->uid = (uid_t)rec_id;
*id_type = ID_USERID;
DEBUG(10,("db_internal_get_id_from_sid: fetching uid record %s -> %s \n",
key.dptr, data.dptr ));
ret = NT_STATUS_OK;
} else if (sscanf(data.dptr, "GID %lu", &rec_id) == 1) { /* Try a GID record. */
id->gid = (uid_t)rec_id;
*id_type = ID_GROUPID;
DEBUG(10,("db_internal_get_id_from_sid: fetching gid record %s -> %s \n",
key.dptr, data.dptr ));
ret = NT_STATUS_OK;
} else {
/* Unknown record type ! */
ret = NT_STATUS_INTERNAL_DB_ERROR;
}
SAFE_FREE(data.dptr);
done:
talloc_free(memctx);
return ret;
}
/* Get a sid from an id - internal non-reverse map checking function. */
static NTSTATUS db_get_sid_from_id(DOM_SID *sid, unid_t id, enum idmap_type id_type, int flags)
{
NTSTATUS ret;
unid_t tmp_id;
enum idmap_type tmp_id_type;
ret = db_internal_get_sid_from_id(sid, id, id_type);
if (!NT_STATUS_IS_OK(ret)) {
return ret;
}
/* Ensure the reverse mapping exists. */
ret = db_internal_get_id_from_sid(&tmp_id, &tmp_id_type, sid);
if (NT_STATUS_IS_OK(ret)) {
/* Check the reverse mapping is the same. */
if (tmp_id.uid != id.uid || tmp_id_type != id_type) {
DEBUG(10,("db_get_sid_from_id: reverse mapping mismatch "
"tmp_id = %u, id = %u, tmp_id_type = %u, id_type = %u\n",
(unsigned int)tmp_id.uid, (unsigned int)id.uid,
(unsigned int)tmp_id_type, (unsigned int)id_type ));
return NT_STATUS_NO_SUCH_USER;
}
}
return ret;
}
/***********************************************************************
Why is this function internal and not part of the interface ?????
This *sucks* and is bad design and needs fixing. JRA.
***********************************************************************/
static NTSTATUS db_internal_allocate_new_id_for_sid(unid_t *id, enum idmap_type *id_type, const DOM_SID *sid)
{
NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
TDB_DATA sid_data;
TDB_DATA ugid_data;
TALLOC_CTX *memctx;
if ((memctx = talloc_new(NULL)) == NULL) {
DEBUG(0, ("ERROR: Out of memory!\n"));
return NT_STATUS_NO_MEMORY;
}
if ((sid_data.dptr = talloc_asprintf(memctx, "%s", sid_string_static(sid))) == NULL) {
DEBUG(0, ("ERROR: Out of memory!\n"));
talloc_free(memctx);
return NT_STATUS_NO_MEMORY;
}
sid_data.dsize = strlen(sid_data.dptr) + 1;
/* Lock the record for this SID. */
if (tdb_chainlock(idmap_tdb, sid_data) != 0) {
DEBUG(10,("db_internal_allocate_new_id_for_sid: failed to lock record %s. Error %s\n",
sid_data.dptr, tdb_errorstr(idmap_tdb) ));
talloc_free(memctx);
return NT_STATUS_UNSUCCESSFUL;
}
do {
/* Allocate a new id for this sid */
ret = db_allocate_id(id, *id_type);
if (!NT_STATUS_IS_OK(ret)) {
goto done;
}
/* Store the UID side */
/* Store new id */
if (*id_type == ID_USERID) {
ugid_data.dptr = talloc_asprintf(memctx, "UID %lu",
(unsigned long)((*id).uid));
} else {
ugid_data.dptr = talloc_asprintf(memctx, "GID %lu",
(unsigned long)((*id).gid));
}
if (ugid_data.dptr == NULL) {
DEBUG(0, ("ERROR: Out of memory!\n"));
ret = NT_STATUS_NO_MEMORY;
goto done;
}
ugid_data.dsize = strlen(ugid_data.dptr) + 1;
DEBUG(10,("db_internal_allocate_new_id_for_sid: storing %s -> %s\n",
ugid_data.dptr, sid_data.dptr ));
if (tdb_store(idmap_tdb, ugid_data, sid_data, TDB_INSERT) != -1) {
ret = NT_STATUS_OK;
break;
}
if (tdb_error(idmap_tdb) != TDB_ERR_EXISTS) {
DEBUG(10,("db_internal_allocate_new_id_for_sid: error %s\n", tdb_errorstr(idmap_tdb)));
}
ret = NT_STATUS_INTERNAL_DB_ERROR;
} while (tdb_error(idmap_tdb) == TDB_ERR_EXISTS);
if (NT_STATUS_IS_OK(ret)) {
DEBUG(10,("db_internal_allocate_new_id_for_sid: storing %s -> %s\n",
sid_data.dptr, ugid_data.dptr ));
if (tdb_store(idmap_tdb, sid_data, ugid_data, TDB_REPLACE) == -1) {
DEBUG(10,("db_internal_allocate_new_id_for_sid: error %s\n", tdb_errorstr(idmap_tdb) ));
ret = NT_STATUS_INTERNAL_DB_ERROR;
}
}
done:
tdb_chainunlock(idmap_tdb, sid_data);
talloc_free(memctx);
return ret;
}
/***********************************************************************
Get an id from a sid - urg. This is assuming the *output* parameter id_type
has been initialized with the correct needed type - ID_USERID or ID_GROUPID.
This function also allocates new mappings ! WTF ??????
This *sucks* and is bad design and needs fixing. JRA.
***********************************************************************/
static NTSTATUS db_get_id_from_sid(unid_t *id, enum idmap_type *id_type, const DOM_SID *sid, int flags)
{
NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
enum idmap_type tmp_id_type = *id_type;
DEBUG(10,("db_get_id_from_sid %s\n", sid_string_static(sid)));
ret = db_internal_get_id_from_sid(id, &tmp_id_type, sid);
if (NT_STATUS_IS_OK(ret)) {
DOM_SID sid_tmp;
/* Check the reverse mapping is the same. Remember *id_type was set as a parameter
to this call... */
if (tmp_id_type != *id_type) {
DEBUG(10,("db_get_sid_from_id: sid %s reverse mapping mismatch "
"tmp_id_type = %u, id_type = %u\n",
sid_string_static(sid),
(unsigned int)tmp_id_type, (unsigned int)(*id_type) ));
return NT_STATUS_NO_SUCH_USER;
}
ret = db_internal_get_sid_from_id(&sid_tmp, *id, *id_type);
if (NT_STATUS_IS_OK(ret)) {
if (!sid_equal(&sid_tmp, sid)) {
DEBUG(10,("db_get_sid_from_id: sid %s reverse mapping SID mismatch"
"id = %u, id_type = %u\n",
sid_string_static(sid),
(unsigned int)id->uid, (unsigned int)(*id_type) ));
return NT_STATUS_NO_SUCH_USER;
}
}
return ret;
}
if (flags & IDMAP_FLAG_QUERY_ONLY) {
return ret;
}
/* We're in to bad design territory.... This call is now
*allocating* and storing a new mapping for sid -> id. This SHOULD
NOT BE DONE HERE ! There needs to be a separate upper
level call for this... I think the reason this was badly
designed this way was the desire to reuse cache code with
a tdb idmap implementation. They MUST be separated ! JRA */
return db_internal_allocate_new_id_for_sid(id, id_type, sid);
}
static NTSTATUS db_set_mapping(const DOM_SID *sid, unid_t id, enum idmap_type id_type)
{
NTSTATUS ret;
TDB_DATA ksid, kid, data;
TALLOC_CTX *memctx;
DEBUG(10,("db_set_mapping: id_type = 0x%x\n", (unsigned int)id_type));
if ((memctx = talloc_new(NULL)) == NULL) {
DEBUG(0, ("ERROR: Out of memory!\n"));
return NT_STATUS_NO_MEMORY;
}
if ((ksid.dptr = talloc_asprintf(memctx, "%s", sid_string_static(sid))) == NULL) {
DEBUG(0, ("ERROR: Out of memory!\n"));
ret = NT_STATUS_NO_MEMORY;
goto done;
}
ksid.dsize = strlen(ksid.dptr) + 1;
if (id_type == ID_USERID) {
kid.dptr = talloc_asprintf(memctx, "UID %lu", (unsigned long)id.uid);
} else {
kid.dptr = talloc_asprintf(memctx, "GID %lu", (unsigned long)id.gid);
}
if (kid.dptr == NULL) {
DEBUG(0, ("ERROR: Out of memory!\n"));
ret = NT_STATUS_NO_MEMORY;
goto done;
}
kid.dsize = strlen(kid.dptr) + 1;
/* *DELETE* prevoius mappings if any.
* This is done both SID and [U|G]ID passed in */
/* Lock the record for this SID. */
if (tdb_chainlock(idmap_tdb, ksid) != 0) {
DEBUG(10,("db_set_mapping: failed to lock record %s. Error %s\n",
ksid.dptr, tdb_errorstr(idmap_tdb) ));
return NT_STATUS_UNSUCCESSFUL;
}
DEBUG(10,("db_set_mapping: fetching %s\n", ksid.dptr));
data = tdb_fetch(idmap_tdb, ksid);
if (data.dptr) {
DEBUG(10,("db_set_mapping: deleting %s and %s\n", data.dptr, ksid.dptr ));
tdb_delete(idmap_tdb, data);
tdb_delete(idmap_tdb, ksid);
SAFE_FREE(data.dptr);
}
data = tdb_fetch(idmap_tdb, kid);
if (data.dptr) {
DEBUG(10,("db_set_mapping: deleting %s and %s\n", data.dptr, kid.dptr ));
tdb_delete(idmap_tdb, data);
tdb_delete(idmap_tdb, kid);
SAFE_FREE(data.dptr);
}
if (tdb_store(idmap_tdb, ksid, kid, TDB_INSERT) == -1) {
DEBUG(0, ("idb_set_mapping: tdb_store 1 error: %s\n", tdb_errorstr(idmap_tdb)));
tdb_chainunlock(idmap_tdb, ksid);
ret = NT_STATUS_UNSUCCESSFUL;
goto done;
}
if (tdb_store(idmap_tdb, kid, ksid, TDB_INSERT) == -1) {
DEBUG(0, ("idb_set_mapping: tdb_store 2 error: %s\n", tdb_errorstr(idmap_tdb)));
tdb_chainunlock(idmap_tdb, ksid);
ret = NT_STATUS_UNSUCCESSFUL;
goto done;
}
tdb_chainunlock(idmap_tdb, ksid);
DEBUG(10,("db_set_mapping: stored %s -> %s and %s -> %s\n", ksid.dptr, kid.dptr, kid.dptr, ksid.dptr ));
ret = NT_STATUS_OK;
done:
talloc_free(memctx);
return ret;
}
/*****************************************************************************
Initialise idmap database.
*****************************************************************************/
static NTSTATUS db_idmap_init( const char *params )
{
SMB_STRUCT_STAT stbuf;
char *tdbfile = NULL;
int32 version;
BOOL tdb_is_new = False;
/* use the old database if present */
tdbfile = SMB_STRDUP(lock_path("winbindd_idmap.tdb"));
if (!tdbfile) {
DEBUG(0, ("idmap_init: out of memory!\n"));
return NT_STATUS_NO_MEMORY;
}
if (!file_exist(tdbfile, &stbuf)) {
tdb_is_new = True;
}
DEBUG(10,("db_idmap_init: Opening tdbfile %s\n", tdbfile ));
/* Open idmap repository */
if (!(idmap_tdb = tdb_open_log(tdbfile, 0,
TDB_DEFAULT, O_RDWR | O_CREAT,
0644))) {
DEBUG(0, ("idmap_init: Unable to open idmap database\n"));
SAFE_FREE(tdbfile);
return NT_STATUS_UNSUCCESSFUL;
}
SAFE_FREE(tdbfile);
if (tdb_is_new) {
/* the file didn't existed before opening it, let's
* store idmap version as nobody else yet opened and
* stored it. I do not like this method but didn't
* found a way to understand if an opened tdb have
* been just created or not --- SSS */
tdb_store_int32(idmap_tdb, "IDMAP_VERSION", IDMAP_VERSION);
}
/* check against earlier versions */
version = tdb_fetch_int32(idmap_tdb, "IDMAP_VERSION");
if (version != IDMAP_VERSION) {
DEBUG(0, ("idmap_init: Unable to open idmap database, it's in an old format!\n"));
return NT_STATUS_INTERNAL_DB_ERROR;
}
/* Create high water marks for group and user id */
if (!lp_idmap_uid(&idmap_state.uid_low, &idmap_state.uid_high)) {
DEBUG(1, ("idmap uid range missing or invalid\n"));
DEBUGADD(1, ("idmap will be unable to map foreign SIDs\n"));
} else {
if (tdb_fetch_int32(idmap_tdb, HWM_USER) == -1) {
if (tdb_store_int32(idmap_tdb, HWM_USER, idmap_state.uid_low) == -1) {
DEBUG(0, ("idmap_init: Unable to initialise user hwm in idmap database\n"));
return NT_STATUS_INTERNAL_DB_ERROR;
}
}
}
if (!lp_idmap_gid(&idmap_state.gid_low, &idmap_state.gid_high)) {
DEBUG(1, ("idmap gid range missing or invalid\n"));
DEBUGADD(1, ("idmap will be unable to map foreign SIDs\n"));
} else {
if (tdb_fetch_int32(idmap_tdb, HWM_GROUP) == -1) {
if (tdb_store_int32(idmap_tdb, HWM_GROUP, idmap_state.gid_low) == -1) {
DEBUG(0, ("idmap_init: Unable to initialise group hwm in idmap database\n"));
return NT_STATUS_INTERNAL_DB_ERROR;
}
}
}
return NT_STATUS_OK;
}
/* Close the tdb */
static NTSTATUS db_idmap_close(void)
{
if (idmap_tdb) {
if (tdb_close(idmap_tdb) == 0) {
return NT_STATUS_OK;
} else {
return NT_STATUS_UNSUCCESSFUL;
}
}
return NT_STATUS_OK;
}
/* Dump status information to log file. Display different stuff based on
the debug level:
Debug Level Information Displayed
=================================================================
0 Percentage of [ug]id range allocated
0 High water marks (next allocated ids)
*/
#define DUMP_INFO 0
static void db_idmap_status(void)
{
int user_hwm, group_hwm;
DEBUG(0, ("winbindd idmap status:\n"));
/* Get current high water marks */
if ((user_hwm = tdb_fetch_int32(idmap_tdb, HWM_USER)) == -1) {
DEBUG(DUMP_INFO,
("\tCould not get userid high water mark!\n"));
}
if ((group_hwm = tdb_fetch_int32(idmap_tdb, HWM_GROUP)) == -1) {
DEBUG(DUMP_INFO,
("\tCould not get groupid high water mark!\n"));
}
/* Display next ids to allocate */
if (user_hwm != -1) {
DEBUG(DUMP_INFO,
("\tNext userid to allocate is %d\n", user_hwm));
}
if (group_hwm != -1) {
DEBUG(DUMP_INFO,
("\tNext groupid to allocate is %d\n", group_hwm));
}
/* Display percentage of id range already allocated. */
if (user_hwm != -1) {
int num_users = user_hwm - idmap_state.uid_low;
int total_users =
idmap_state.uid_high - idmap_state.uid_low;
DEBUG(DUMP_INFO,
("\tUser id range is %d%% full (%d of %d)\n",
num_users * 100 / total_users, num_users,
total_users));
}
if (group_hwm != -1) {
int num_groups = group_hwm - idmap_state.gid_low;
int total_groups =
idmap_state.gid_high - idmap_state.gid_low;
DEBUG(DUMP_INFO,
("\tGroup id range is %d%% full (%d of %d)\n",
num_groups * 100 / total_groups, num_groups,
total_groups));
}
/* Display complete mapping of users and groups to rids */
}
/**********************************************************************
Return the TDB_CONTEXT* for winbindd_idmap. I **really** feel
dirty doing this, but not so dirty that I want to create another
tdb
***********************************************************************/
TDB_CONTEXT *idmap_tdb_handle( void )
{
if ( idmap_tdb )
return idmap_tdb;
/* go ahead an open it; db_idmap_init() doesn't use any params
right now */
db_idmap_init( NULL );
if ( idmap_tdb )
return idmap_tdb;
return NULL;
}
static struct idmap_methods db_methods = {
db_idmap_init,
db_allocate_id,
db_get_sid_from_id,
db_get_id_from_sid,
db_set_mapping,
db_idmap_close,
db_idmap_status
};
NTSTATUS idmap_tdb_init(void)
{
return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "tdb", &db_methods);
}

View File

@@ -1,127 +0,0 @@
/*
Unix SMB/CIFS implementation.
ID Mapping
Copyright (C) Simo Sorce 2003
Copyright (C) Jeremy Allison 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 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"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_IDMAP
/*****************************************************************
Returns SID pointer.
*****************************************************************/
NTSTATUS idmap_uid_to_sid(DOM_SID *sid, uid_t uid, int flags)
{
unid_t id;
DEBUG(10,("idmap_uid_to_sid: uid = [%lu]\n", (unsigned long)uid));
id.uid = uid;
return idmap_get_sid_from_id(sid, id, ID_USERID, flags);
}
/*****************************************************************
Group mapping is used for gids that maps to Wellknown SIDs
Returns SID pointer.
*****************************************************************/
NTSTATUS idmap_gid_to_sid(DOM_SID *sid, gid_t gid, int flags)
{
unid_t id;
DEBUG(10,("idmap_gid_to_sid: gid = [%lu]\n", (unsigned long)gid));
id.gid = gid;
return idmap_get_sid_from_id(sid, id, ID_GROUPID, flags);
}
/*****************************************************************
if it is a foreign sid or it is in idmap rid range check idmap,
otherwise falls back to the legacy algorithmic mapping.
Returns True if this name is a user sid and the conversion
was done correctly, False if not.
*****************************************************************/
NTSTATUS idmap_sid_to_uid(const DOM_SID *sid, uid_t *uid, int flags)
{
NTSTATUS ret;
enum idmap_type id_type;
unid_t id;
DEBUG(10,("idmap_sid_to_uid: sid = [%s]\n", sid_string_static(sid)));
/* For the LDAP and tdb backends we must *KNOW* what we're looking for.
This interface design *SUCKS* ! JRA. */
id_type = ID_USERID;
ret = idmap_get_id_from_sid(&id, &id_type, sid, flags);
if (!NT_STATUS_IS_OK(ret)) {
return ret;
}
if (id_type != ID_USERID) {
return NT_STATUS_NONE_MAPPED;
}
DEBUG(10,("idmap_sid_to_uid: uid = [%lu]\n", (unsigned long)id.uid));
*uid = id.uid;
return NT_STATUS_OK;
}
/*****************************************************************
*THE CANONICAL* convert SID to gid function.
if it is a foreign sid or it is in idmap rid range check idmap,
otherwise falls back to the legacy algorithmic mapping.
Group mapping is used for gids that maps to Wellknown SIDs
Returns True if this name is a user sid and the conversion
was done correctly, False if not.
*****************************************************************/
NTSTATUS idmap_sid_to_gid(const DOM_SID *sid, gid_t *gid, int flags)
{
NTSTATUS ret;
enum idmap_type id_type;
unid_t id;
DEBUG(10,("sid_to_gid: sid = [%s]\n", sid_string_static(sid)));
/* For the LDAP and tdb backends we must *KNOW* what we're looking for.
This interface design *SUCKS* ! JRA. */
id_type = ID_GROUPID;
ret = idmap_get_id_from_sid(&id, &id_type, sid, flags);
if (!NT_STATUS_IS_OK(ret)) {
return ret;
}
if (id_type != ID_GROUPID) {
return NT_STATUS_NONE_MAPPED;
}
DEBUG(10,("idmap_sid_to_gid: gid = [%lu]\n", (unsigned long)id.gid));
*gid = id.gid;
return NT_STATUS_OK;
}

View File

@@ -20,188 +20,92 @@
#include "includes.h"
#include "utils/net.h"
/***********************************************************
Helper function for net_idmap_dump. Dump one entry.
**********************************************************/
static int net_idmap_dump_one_entry(TDB_CONTEXT *tdb,
TDB_DATA key,
TDB_DATA data,
void *unused)
{
if (strcmp(key.dptr, "USER HWM") == 0) {
printf("USER HWM %d\n", IVAL(data.dptr,0));
return 0;
}
if (strcmp(key.dptr, "GROUP HWM") == 0) {
printf("GROUP HWM %d\n", IVAL(data.dptr,0));
return 0;
}
if (strncmp(key.dptr, "S-", 2) != 0)
return 0;
printf("%s %s\n", data.dptr, key.dptr);
return 0;
}
#define ALLOC_CHECK(mem) do { \
if (!mem) { \
d_fprintf(stderr, "Out of memory!\n"); \
talloc_free(ctx); \
return -1; \
} } while(0)
/***********************************************************
Dump the current idmap
**********************************************************/
static int net_idmap_dump(int argc, const char **argv)
{
TDB_CONTEXT *idmap_tdb;
TALLOC_CTX *ctx;
char *filename;
if ( argc != 1 )
return net_help_idmap( argc, argv );
if (argc != 1) {
return net_help_idmap(argc, argv);
}
idmap_tdb = tdb_open_log(argv[0], 0, TDB_DEFAULT, O_RDONLY, 0);
if (idmap_tdb == NULL) {
d_fprintf(stderr, "Could not open idmap: %s\n", argv[0]);
if (! winbind_ping()) {
d_fprintf(stderr, "To use net idmap Winbindd must be running.\n");
return -1;
}
tdb_traverse(idmap_tdb, net_idmap_dump_one_entry, NULL);
ctx = talloc_new(NULL);
ALLOC_CHECK(ctx);
tdb_close(idmap_tdb);
filename = talloc_strdup(ctx, argv[0]);
ALLOC_CHECK(filename);
return 0;
}
/* filename must be absolute */
if (*filename != '/') {
char path[4096];
/***********************************************************
Fix up the HWMs after a idmap restore.
**********************************************************/
struct hwms {
BOOL ok;
uid_t user_hwm;
gid_t group_hwm;
};
static int net_idmap_find_max_id(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA data,
void *handle)
{
struct hwms *hwms = (struct hwms *)handle;
void *idptr = NULL;
BOOL isgid = False;
int id;
if (strncmp(key.dptr, "S-", 2) != 0)
return 0;
if (sscanf(data.dptr, "GID %d", &id) == 1) {
idptr = (void *)&hwms->group_hwm;
isgid = True;
}
if (sscanf(data.dptr, "UID %d", &id) == 1) {
idptr = (void *)&hwms->user_hwm;
isgid = False;
}
if (idptr == NULL) {
d_fprintf(stderr, "Illegal idmap entry: [%s]->[%s]\n",
key.dptr, data.dptr);
hwms->ok = False;
filename = getcwd(path, 4095);
if ( ! filename) {
d_fprintf(stderr, "Failed to obtain full output file path");
talloc_free(ctx);
return -1;
}
if (isgid) {
if (hwms->group_hwm <= (gid_t)id) {
hwms->group_hwm = (gid_t)(id+1);
}
} else {
if (hwms->user_hwm <= (uid_t)id) {
hwms->user_hwm = (uid_t)(id+1);
}
filename = talloc_asprintf(ctx, "%s/%s", path, argv[0]);
ALLOC_CHECK(filename);
}
if ( ! winbind_idmap_dump_maps(ctx, filename)) {
d_fprintf(stderr, "Failed to obtain idmap data from winbindd\n");
talloc_free(ctx);
return -1;
}
talloc_free(ctx);
return 0;
}
static NTSTATUS net_idmap_fixup_hwm(void)
{
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
TDB_CONTEXT *idmap_tdb;
char *tdbfile = NULL;
struct hwms hwms;
struct hwms highest;
if (!lp_idmap_uid(&hwms.user_hwm, &highest.user_hwm) ||
!lp_idmap_gid(&hwms.group_hwm, &highest.group_hwm)) {
d_fprintf(stderr, "idmap range missing\n");
return NT_STATUS_UNSUCCESSFUL;
}
tdbfile = SMB_STRDUP(lock_path("winbindd_idmap.tdb"));
if (!tdbfile) {
DEBUG(0, ("idmap_init: out of memory!\n"));
return NT_STATUS_NO_MEMORY;
}
idmap_tdb = tdb_open_log(tdbfile, 0, TDB_DEFAULT, O_RDWR, 0);
if (idmap_tdb == NULL) {
d_fprintf(stderr, "Could not open idmap: %s\n", tdbfile);
return NT_STATUS_NO_SUCH_FILE;
}
hwms.ok = True;
tdb_traverse(idmap_tdb, net_idmap_find_max_id, &hwms);
if (!hwms.ok) {
goto done;
}
d_printf("USER HWM: %d GROUP HWM: %d\n",
hwms.user_hwm, hwms.group_hwm);
if (hwms.user_hwm >= highest.user_hwm) {
d_fprintf(stderr, "Highest UID out of uid range\n");
goto done;
}
if (hwms.group_hwm >= highest.group_hwm) {
d_fprintf(stderr, "Highest GID out of gid range\n");
goto done;
}
if ((tdb_store_int32(idmap_tdb, "USER HWM", (int32)hwms.user_hwm) != 0) ||
(tdb_store_int32(idmap_tdb, "GROUP HWM", (int32)hwms.group_hwm) != 0)) {
d_fprintf(stderr, "Could not store HWMs\n");
goto done;
}
result = NT_STATUS_OK;
done:
tdb_close(idmap_tdb);
return result;
}
/***********************************************************
Write entries from stdin to current local idmap
**********************************************************/
static int net_idmap_restore(int argc, const char **argv)
{
if (!idmap_init(lp_idmap_backend())) {
d_fprintf(stderr, "Could not init idmap\n");
TALLOC_CTX *ctx;
FILE *input;
if (! winbind_ping()) {
d_fprintf(stderr, "To use net idmap Winbindd must be running.\n");
return -1;
}
while (!feof(stdin)) {
fstring line, sid_string, fmt_string1, fmt_string2;
int len;
unid_t id;
enum idmap_type type;
unsigned long idval;
DOM_SID sid;
ctx = talloc_new(NULL);
ALLOC_CHECK(ctx);
if (fgets(line, sizeof(line)-1, stdin) == NULL)
if (argc == 1) {
input = fopen(argv[0], "r");
} else {
input = stdin;
}
while (!feof(input)) {
char line[128], sid_string[128];
int len;
DOM_SID sid;
struct id_map map;
unsigned long idval;
if (fgets(line, 127, input) == NULL)
break;
len = strlen(line);
@@ -209,39 +113,50 @@ static int net_idmap_restore(int argc, const char **argv)
if ( (len > 0) && (line[len-1] == '\n') )
line[len-1] = '\0';
snprintf(fmt_string1, sizeof(fmt_string1), "GID %%ul %%%us", FSTRING_LEN);
snprintf(fmt_string2, sizeof(fmt_string2), "UID %%ul %%%us", FSTRING_LEN);
if (sscanf(line, fmt_string1, &idval, sid_string) == 2) {
type = ID_GROUPID;
id.gid = (gid_t)idval;
} else if (sscanf(line, fmt_string2, &idval, sid_string) == 2) {
type = ID_USERID;
id.uid = (uid_t)idval;
if (sscanf(line, "GID %lu %128s", &idval, sid_string) == 2) {
map.xid.type = ID_TYPE_GID;
map.xid.id = idval;
} else if (sscanf(line, "UID %lu %128s", &idval, sid_string) == 2) {
map.xid.type = ID_TYPE_UID;
map.xid.id = idval;
} else if (sscanf(line, "USER HWM %lu", &idval) == 1) {
/* set uid hwm */
if (! winbind_set_uid_hwm(idval)) {
d_fprintf(stderr, "Could not set USER HWM\n");
}
continue;
} else if (sscanf(line, "GROUP HWM %lu", &idval) == 1) {
/* set gid hwm */
if (! winbind_set_gid_hwm(idval)) {
d_fprintf(stderr, "Could not set GROUP HWM\n");
}
continue;
} else {
d_printf("ignoring invalid line [%s]\n", line);
d_fprintf(stderr, "ignoring invalid line [%s]\n", line);
continue;
}
if (!string_to_sid(&sid, sid_string)) {
d_printf("ignoring invalid sid [%s]\n", sid_string);
d_fprintf(stderr, "ignoring invalid sid [%s]\n", sid_string);
continue;
}
map.sid = &sid;
if (!NT_STATUS_IS_OK(idmap_set_mapping(&sid, id, type))) {
if (!winbind_set_mapping(&map)) {
d_fprintf(stderr, "Could not set mapping of %s %lu to sid %s\n",
(type == ID_GROUPID) ? "GID" : "UID",
(type == ID_GROUPID) ? (unsigned long)id.gid:
(unsigned long)id.uid,
sid_string_static(&sid));
(map.xid.type == ID_TYPE_GID) ? "GID" : "UID",
(unsigned long)map.xid.id, sid_string_static(map.sid));
continue;
}
}
idmap_close();
if (input != stdin) {
fclose(input);
}
return NT_STATUS_IS_OK(net_idmap_fixup_hwm()) ? 0 : -1;
talloc_free(ctx);
return 0;
}
/***********************************************************
@@ -249,62 +164,122 @@ static int net_idmap_restore(int argc, const char **argv)
**********************************************************/
static int net_idmap_delete(int argc, const char **argv)
{
TDB_CONTEXT *idmap_tdb;
TDB_DATA key, data;
fstring sid;
if (argc != 2)
return net_help_idmap(argc, argv);
idmap_tdb = tdb_open_log(argv[0], 0, TDB_DEFAULT, O_RDWR, 0);
if (idmap_tdb == NULL) {
d_fprintf(stderr, "Could not open idmap: %s\n", argv[0]);
d_printf("Not Implemented yet\n");
return -1;
}
static int net_idmap_set(int argc, const char **argv)
{
d_printf("Not Implemented yet\n");
return -1;
}
BOOL idmap_store_secret(const char *backend, bool alloc,
const char *domain, const char *identity,
const char *secret)
{
char *tmp;
int r;
BOOL ret;
if (alloc) {
r = asprintf(&tmp, "IDMAP_ALLOC_%s", backend);
} else {
r = asprintf(&tmp, "IDMAP_%s_%s", backend, domain);
}
fstrcpy(sid, argv[1]);
if (r < 0) return false;
if (strncmp(sid, "S-1-5-", strlen("S-1-5-")) != 0) {
d_fprintf(stderr, "Can only delete SIDs, %s is does not start with "
"S-1-5-\n", sid);
return -1;
}
strupper_m(tmp); /* make sure the key is case insensitive */
ret = secrets_store_generic(tmp, identity, secret);
key.dptr = sid;
key.dsize = strlen(key.dptr)+1;
data = tdb_fetch(idmap_tdb, key);
if (data.dptr == NULL) {
d_fprintf(stderr, "Could not find sid %s\n", argv[1]);
return -1;
}
if (tdb_delete(idmap_tdb, key) != 0) {
d_fprintf(stderr, "Could not delete key %s\n", argv[1]);
return -1;
}
if (tdb_delete(idmap_tdb, data) != 0) {
d_fprintf(stderr, "Could not delete key %s\n", data.dptr);
return -1;
}
return 0;
free(tmp);
return ret;
}
static int net_idmap_secret(int argc, const char **argv)
{
TALLOC_CTX *ctx;
const char *secret;
const char *dn;
char *domain;
char *backend;
char *opt = NULL;
BOOL ret;
if (argc != 2) {
return net_help_idmap(argc, argv);
}
secret = argv[1];
ctx = talloc_new(NULL);
ALLOC_CHECK(ctx);
if (strcmp(argv[0], "alloc") == 0) {
domain = NULL;
backend = lp_idmap_alloc_backend();
} else {
domain = talloc_strdup(ctx, argv[0]);
ALLOC_CHECK(domain);
opt = talloc_asprintf(ctx, "idmap config %s", domain);
ALLOC_CHECK(opt);
backend = talloc_strdup(ctx, lp_parm_const_string(-1, opt, "backend", "tdb"));
ALLOC_CHECK(backend);
}
if ( ( ! backend) || ( ! strequal(backend, "ldap"))) {
d_fprintf(stderr, "The only currently supported backend is LDAP\n");
talloc_free(ctx);
return -1;
}
if (domain) {
dn = lp_parm_const_string(-1, opt, "ldap_user_dn", NULL);
if ( ! dn) {
d_fprintf(stderr, "Missing ldap_user_dn option for domain %s\n", domain);
talloc_free(ctx);
return -1;
}
ret = idmap_store_secret("ldap", false, domain, dn, secret);
} else {
dn = lp_parm_const_string(-1, "idmap alloc config", "ldap_user_dn", NULL);
if ( ! dn) {
d_fprintf(stderr, "Missing ldap_user_dn option for alloc backend\n");
talloc_free(ctx);
return -1;
}
ret = idmap_store_secret("ldap", true, NULL, dn, secret);
}
if ( ! ret) {
d_fprintf(stderr, "Failed to store secret\n");
talloc_free(ctx);
return -1;
}
d_printf("Secret stored\n");
return 0;
}
int net_help_idmap(int argc, const char **argv)
{
d_printf("net idmap dump <tdbfile>"\
"\n Dump current id mapping\n");
d_printf("net idmap dump <outputfile>\n"\
" Dump current id mapping\n");
d_printf("net idmap restore"\
"\n Restore entries from stdin to current local idmap\n");
d_printf("net idmap restore\n"\
" Restore entries from stdin\n");
/* Deliberately *not* document net idmap delete */
d_printf("net idmap secret <DOMAIN>|alloc <secret>\n"\
" Set the secret for the specified DOMAIN (or the alloc module)\n");
return -1;
}
@@ -316,7 +291,9 @@ int net_idmap(int argc, const char **argv)
struct functable func[] = {
{"dump", net_idmap_dump},
{"restore", net_idmap_restore},
{"setmap", net_idmap_set },
{"delete", net_idmap_delete},
{"secret", net_idmap_secret},
{"help", net_help_idmap},
{NULL, NULL}
};