diff options
author | Simo Sorce <idra@samba.org> | 2006-12-12 14:52:13 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 12:16:25 -0500 |
commit | 4225f9a4bd5eece4d57820bbabb7b882610aa7cc (patch) | |
tree | e9dc08eba6d786b9ca17d784244cea7f3829d832 /source3 | |
parent | 18f9156d96cba17adc199d0e8c4cf1d6c9ae1960 (diff) | |
download | samba-4225f9a4bd5eece4d57820bbabb7b882610aa7cc.tar.gz samba-4225f9a4bd5eece4d57820bbabb7b882610aa7cc.tar.bz2 samba-4225f9a4bd5eece4d57820bbabb7b882610aa7cc.zip |
r20116: Start merging in the work done to create the new idmap subsystem.
Simo.
(This used to be commit 50cd8bffeeed2cac755f75fc3d76fe41c451976b)
Diffstat (limited to 'source3')
42 files changed, 7013 insertions, 4514 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in index c175685ce5..85d7d14a06 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -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) diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c index 870dc9b5d0..709d77bb36 100644 --- a/source3/auth/auth_util.c +++ b/source3/auth/auth_util.c @@ -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,23 +1030,33 @@ 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; } } - + debug_nt_user_token(DBGC_AUTH, 10, server_info->ptok); status = log_nt_token(mem_ctx, server_info->ptok); diff --git a/source3/configure.in b/source3/configure.in index c534d870a1..f8f0c18831 100644 --- a/source3/configure.in +++ b/source3/configure.in @@ -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) diff --git a/source3/include/dlinklist.h b/source3/include/dlinklist.h index f267e77ea6..e590bc3e7e 100644 --- a/source3/include/dlinklist.h +++ b/source3/include/dlinklist.h @@ -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)) { \ diff --git a/source3/include/idmap.h b/source3/include/idmap.h index ee248ef26f..069aaa73a3 100644 --- a/source3/include/idmap.h +++ b/source3/include/idmap.h @@ -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 (*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); - 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); + /* 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)(void); + NTSTATUS (*close_fn)(struct idmap_domain *dom); +}; + +struct idmap_alloc_methods { - /* Called to dump backend status */ - void (*status)(void); + /* 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); }; + #endif /* _IDMAP_H_ */ diff --git a/source3/include/passdb.h b/source3/include/passdb.h index 9dc6d60eb0..092904ab60 100644 --- a/source3/include/passdb.h +++ b/source3/include/passdb.h @@ -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, diff --git a/source3/include/smb.h b/source3/include/smb.h index aefc06548e..0e06ce1d79 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -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" diff --git a/source3/include/smbldap.h b/source3/include/smbldap.h index ae54e66b36..b261ca82fd 100644 --- a/source3/include/smbldap.h +++ b/source3/include/smbldap.h @@ -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; diff --git a/source3/lib/smbldap.c b/source3/lib/smbldap.c index 85dd5fa3d6..2fe0d5b86e 100644 --- a/source3/lib/smbldap.c +++ b/source3/lib/smbldap.c @@ -803,20 +803,27 @@ static int rebindproc_with_state (LDAP * ld, char **whop, char **credp, if (freeit) { SAFE_FREE(*whop); - memset(*credp, '\0', strlen(*credp)); + 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]")); - *whop = SMB_STRDUP(ldap_state->bind_dn); - if (!*whop) { - return LDAP_NO_MEMORY; - } - *credp = SMB_STRDUP(ldap_state->bind_secret); - if (!*credp) { - SAFE_FREE(*whop); - return LDAP_NO_MEMORY; + if (ldap_state->anonymous) { + *whop = NULL; + *credp = NULL; + } else { + *whop = SMB_STRDUP(ldap_state->bind_dn); + if (!*whop) { + return LDAP_NO_MEMORY; + } + *credp = SMB_STRDUP(ldap_state->bind_secret); + if (!*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)) { - DEBUG(0, ("ldap_connect_system: Failed to retrieve password from secrets.tdb\n")); - return LDAP_INVALID_CREDENTIALS; - } + if (!ldap_state->anonimous && !ldap_state->bind_dn) { - ldap_state->bind_dn = ldap_dn; - ldap_state->bind_secret = ldap_secret; + /* 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; + } + } /* 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; +} diff --git a/source3/nsswitch/idmap.c b/source3/nsswitch/idmap.c new file mode 100644 index 0000000000..42e3f7abb0 --- /dev/null +++ b/source3/nsswitch/idmap.c @@ -0,0 +1,1299 @@ +/* + 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" +#include "winbindd.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_IDMAP + +static_decl_idmap; + +struct idmap_backend { + const char *name; + struct idmap_methods *methods; + struct idmap_backend *prev, *next; +}; + +struct idmap_alloc_backend { + const char *name; + struct idmap_alloc_methods *methods; + struct idmap_alloc_backend *prev, *next; +}; + +struct idmap_cache_ctx; + +static TALLOC_CTX *idmap_ctx = NULL; +static struct idmap_cache_ctx *idmap_cache; + +static struct idmap_backend *backends = NULL; +static struct idmap_domain **idmap_domains = NULL; +static int num_domains = 0; +static int pdb_dom_num = -1; +static int def_dom_num = -1; + +static struct idmap_alloc_backend *alloc_backends = NULL; +static struct idmap_alloc_methods *alloc_methods = NULL; + +#define IDMAP_CHECK_RET(ret) do { if ( ! NT_STATUS_IS_OK(ret)) { DEBUG(2, ("ERROR: NTSTATUS = 0x%08x\n", NT_STATUS_V(ret))); goto done; } } while(0) +#define IDMAP_CHECK_ALLOC(mem) do { if (!mem) { DEBUG(0, ("Out of memory!\n")); ret = NT_STATUS_NO_MEMORY; goto done; } } while(0) + +static struct idmap_methods *get_methods(struct idmap_backend *be, const char *name) +{ + struct idmap_backend *b; + + for (b = be; b; b = b->next) { + if (strequal(b->name, name)) { + return b->methods; + } + } + + return NULL; +} + +static struct idmap_alloc_methods *get_alloc_methods(struct idmap_alloc_backend *be, const char *name) +{ + struct idmap_alloc_backend *b; + + for (b = be; b; b = b->next) { + if (strequal(b->name, name)) { + return b->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_methods *test; + struct idmap_backend *entry; + + if (!idmap_ctx) { + return NT_STATUS_INTERNAL_DB_ERROR; + } + + if ((version != SMB_IDMAP_INTERFACE_VERSION)) { + DEBUG(0, ("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,("Called with NULL pointer or empty name!\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + test = get_methods(backends, name); + if (test) { + DEBUG(0,("Idmap module %s already registered!\n", name)); + return NT_STATUS_OBJECT_NAME_COLLISION; + } + + entry = talloc(idmap_ctx, struct idmap_backend); + if ( ! entry) { + DEBUG(0,("Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + entry->name = talloc_strdup(idmap_ctx, name); + if ( ! entry->name) { + DEBUG(0,("Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + entry->methods = methods; + + DLIST_ADD(backends, entry); + DEBUG(5, ("Successfully added idmap backend '%s'\n", name)); + return NT_STATUS_OK; +} + +/********************************************************************** + Allow a module to register itself as a method. +**********************************************************************/ + +NTSTATUS smb_register_idmap_alloc(int version, const char *name, struct idmap_alloc_methods *methods) +{ + struct idmap_alloc_methods *test; + struct idmap_alloc_backend *entry; + + if (!idmap_ctx) { + return NT_STATUS_INTERNAL_DB_ERROR; + } + + if ((version != SMB_IDMAP_INTERFACE_VERSION)) { + DEBUG(0, ("Failed to register idmap alloc 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,("Called with NULL pointer or empty name!\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + test = get_alloc_methods(alloc_backends, name); + if (test) { + DEBUG(0,("idmap_alloc module %s already registered!\n", name)); + return NT_STATUS_OBJECT_NAME_COLLISION; + } + + entry = talloc(idmap_ctx, struct idmap_alloc_backend); + if ( ! entry) { + DEBUG(0,("Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + entry->name = talloc_strdup(idmap_ctx, name); + if ( ! entry->name) { + DEBUG(0,("Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + entry->methods = methods; + + DLIST_ADD(alloc_backends, entry); + DEBUG(5, ("Successfully added idmap alloc backend '%s'\n", name)); + return NT_STATUS_OK; +} + +static int close_domain_destructor(struct idmap_domain *dom) +{ + NTSTATUS ret; + + ret = dom->methods->close_fn(dom); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(3, ("Failed to close idmap domain [%s]!\n", dom->name)); + } + + return 0; +} + +/************************************************************************** + Shutdown. +**************************************************************************/ + +NTSTATUS idmap_close(void) +{ + /* close the alloc backend first before freeing idmap_ctx */ + if (alloc_methods) { + alloc_methods->close_fn(); + alloc_methods = NULL; + } + alloc_backends = NULL; + + /* this talloc_free call will fire the talloc destructors + * that will free all active backends resources */ + TALLOC_FREE(idmap_ctx); + idmap_cache = NULL; + idmap_domains = NULL; + backends = NULL; + + return NT_STATUS_OK; +} + +/********************************************************************** + Initialise idmap cache and a remote backend (if configured). +**********************************************************************/ + +static const char *idmap_default_domain[] = { "default domain", NULL }; + +NTSTATUS idmap_init(void) +{ + NTSTATUS ret; + struct idmap_domain *dom; + const char *compat_backend = NULL; + const char *compat_params = NULL; + const char **dom_list = NULL; + char *alloc_backend; + BOOL default_already_defined = False; + BOOL pri_dom_is_in_list = False; + int compat = 0; + int i; + + if (idmap_ctx) { + return NT_STATUS_OK; + } + + idmap_ctx = talloc_named_const(NULL, 0, "IDMAP MEMORY CONTEXT"); + if ( ! idmap_ctx) { + return NT_STATUS_NO_MEMORY; + } + + /* init cache */ + idmap_cache = idmap_cache_init(idmap_ctx); + if ( ! idmap_cache) { + return NT_STATUS_UNSUCCESSFUL; + } + + /* register static backends */ + static_init_idmap; + + if ((dom_list = lp_idmap_domains()) != NULL) { + if (lp_idmap_backend()) { + DEBUG(0, ("WARNING: idmap backend and idmap domains are mutually excusive!\n")); + DEBUGADD(0, (" idmap backend option will be IGNORED!\n")); + } + + } else if (lp_idmap_backend()) { + const char **compat_list = lp_idmap_backend(); + const char *p; + + DEBUG(0, ("WARNING: idmap backend is deprecated!\n")); + compat = 1; + + /* strip any leading idmap_ prefix of */ + if (strncmp(*compat_list, "idmap_", 6) == 0 ) { + p = *compat_list += 6; + DEBUG(0, ("WARNING: idmap backend uses obsolete and deprecated 'idmap_' prefix.\n")); + DEBUGADD(0, (" Please replace 'idmap_%s' by '%s' in %s\n", p, p, dyn_CONFIGFILE)); + compat_backend = p; + } else { + compat_backend = *compat_list; + } + + if ((p = strchr(compat_backend, ':')) != NULL) { + compat_params = p + 1; + } + } + + if ( ! dom_list) { + dom_list = idmap_default_domain; + } + + /*************************** + * initialize idmap domains + */ + DEBUG(1, ("Initializing idmap domains\n")); + + for (i = 0; dom_list[i]; i++) { + const char *parm_backend; + char *config_option; + + if (strequal(dom_list[i], lp_workgroup())) { + pri_dom_is_in_list = True; + } + /* init domain */ + + dom = talloc_zero(idmap_ctx, struct idmap_domain); + IDMAP_CHECK_ALLOC(dom); + + dom->name = talloc_strdup(dom, dom_list[i]); + IDMAP_CHECK_ALLOC(dom->name); + + config_option = talloc_asprintf(dom, "idmap config %s", dom->name); + IDMAP_CHECK_ALLOC(config_option); + + /* default or specific ? */ + + dom->default_domain = lp_parm_bool(-1, config_option, "default", False); + if (dom->default_domain || + strequal(dom_list[i], idmap_default_domain[0])) { + /* the default domain is a cacth all domain + * so no specific domain sid is provided */ + dom->sid = NULL; + /* make sure this is set even when we match idmap_default_domain[0] */ + dom->default_domain = True; + + if (lp_parm_const_string(-1, config_option, "domain sid", NULL)) { + DEBUG(1, ("WARNING: Can't force a /domain sid/ on the DEFAULT domain, Ignoring!")); + } + + /* only one default domain is permitted */ + if (default_already_defined) { + DEBUG(1, ("ERROR: Multiple domains defined as default!\n")); + ret = NT_STATUS_INVALID_PARAMETER; + goto done; + } + + default_already_defined = True; + + } else { + const char *sid; + + sid = lp_parm_const_string(-1, config_option, "domain sid", NULL); + if (sid) { + dom->sid = string_sid_talloc(dom, sid); + } else { + struct winbindd_domain *wdom = find_domain_from_name(dom->name); + if (wdom) { + dom->sid = sid_dup_talloc(dom, &wdom->sid); + IDMAP_CHECK_ALLOC(dom->sid); + } + } + + if ( ! dom->sid) { + DEBUG(1, ("ERROR: Could not find DOMAIN SID for domain %s\n", dom->name)); + DEBUGADD(1, (" Consider to set explicitly the /domain sid/ option\n")); + ret = NT_STATUS_NO_SUCH_DOMAIN; + goto done; + } + } + + /* is this a readonly domain ? */ + dom->readonly = lp_parm_bool(-1, config_option, "readonly", False); + + /* find associated backend (default: tdb) */ + if (compat) { + parm_backend = talloc_strdup(idmap_ctx, compat_backend); + } else { + parm_backend = + talloc_strdup(idmap_ctx, + lp_parm_const_string(-1, config_option, "backend", "tdb")); + } + IDMAP_CHECK_ALLOC(parm_backend); + + /* get the backend methods for this domain */ + dom->methods = get_methods(backends, parm_backend); + + if ( ! dom->methods) { + ret = smb_probe_module("idmap", parm_backend); + if (NT_STATUS_IS_OK(ret)) { + dom->methods = get_methods(backends, parm_backend); + } + } + if ( ! dom->methods) { + DEBUG(0, ("ERROR: Could not get methods for backend %s\n", parm_backend)); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + /* check the set_mapping function exists otherwise mark the module as readonly */ + if ( ! dom->methods->set_mapping) { + dom->readonly = True; + } + + /* now that we have methods, set the destructor for this domain */ + talloc_set_destructor(dom, close_domain_destructor); + + /* Finally instance a backend copy for this domain */ + ret = dom->methods->init(dom, compat_params); + if ( ! NT_STATUS_IS_OK(ret)) { + DEBUG(0, ("ERROR: Initialization failed for backend %s (domain %s)\n", + parm_backend, dom->name)); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + idmap_domains = talloc_realloc(idmap_ctx, idmap_domains, struct idmap_domain *, i+1); + if ( ! idmap_domains) { + DEBUG(0, ("Out of memory!\n")); + ret = NT_STATUS_NO_MEMORY; + goto done; + } + idmap_domains[i] = dom; + + if (dom->default_domain) { /* save default domain position for future uses */ + def_dom_num = i; + } + + DEBUG(10, ("Domain %s - Sid %s - Backend %s - %sdefault - %sreadonly\n", + dom->name, sid_string_static(dom->sid), parm_backend, + dom->default_domain?"":"not ", dom->readonly?"":"not ")); + + talloc_free(config_option); + } + + /* save the number of domains we have */ + num_domains = i; + + /* automatically add idmap_nss backend if needed */ + if ((lp_server_role() == ROLE_DOMAIN_MEMBER) && + ( ! pri_dom_is_in_list) && + lp_winbind_trusted_domains_only()) { + DOM_SID our_sid; + + if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) { + DEBUG(0, ("Could not fetch our SID - did we join?\n")); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + dom = talloc_zero(idmap_ctx, struct idmap_domain); + IDMAP_CHECK_ALLOC(dom); + + dom->name = talloc_strdup(dom, lp_workgroup()); + IDMAP_CHECK_ALLOC(dom->name); + + dom->default_domain = False; + dom->readonly = True; + + dom->sid = sid_dup_talloc(dom, &our_sid); + IDMAP_CHECK_ALLOC(dom->sid); + + /* get the backend methods for passdb */ + dom->methods = get_methods(backends, "nss"); + + /* (the nss module is always statically linked) */ + if ( ! dom->methods) { + DEBUG(0, ("ERROR: Could not get methods for idmap_nss ?!\n")); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + /* now that we have methods, set the destructor for this domain */ + talloc_set_destructor(dom, close_domain_destructor); + + /* Finally instance a backend copy for this domain */ + ret = dom->methods->init(dom, compat_params); + if ( ! NT_STATUS_IS_OK(ret)) { + DEBUG(0, ("ERROR: Initialization failed for idmap_nss ?!\n")); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + idmap_domains = talloc_realloc(idmap_ctx, idmap_domains, struct idmap_domain *, num_domains+1); + if ( ! idmap_domains) { + DEBUG(0, ("Out of memory!\n")); + ret = NT_STATUS_NO_MEMORY; + goto done; + } + idmap_domains[num_domains] = dom; + + DEBUG(10, ("Domain %s - Sid %s - Backend nss - not default - readonly\n", + dom->name, sid_string_static(dom->sid))); + + num_domains++; + } + + /**** automatically add idmap_passdb backend ****/ + dom = talloc_zero(idmap_ctx, struct idmap_domain); + IDMAP_CHECK_ALLOC(dom); + + dom->name = talloc_strdup(dom, get_global_sam_name()); + IDMAP_CHECK_ALLOC(dom->name); + + dom->default_domain = False; + dom->readonly = True; + + dom->sid = sid_dup_talloc(dom, get_global_sam_sid()); + IDMAP_CHECK_ALLOC(dom->sid); + + /* get the backend methods for passdb */ + dom->methods = get_methods(backends, "passdb"); + + /* (the passdb module is always statically linked) */ + if ( ! dom->methods) { + DEBUG(0, ("ERROR: Could not get methods for idmap_passdb ?!\n")); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + /* now that we have methods, set the destructor for this domain */ + talloc_set_destructor(dom, close_domain_destructor); + + /* Finally instance a backend copy for this domain */ + ret = dom->methods->init(dom, compat_params); + if ( ! NT_STATUS_IS_OK(ret)) { + DEBUG(0, ("ERROR: Initialization failed for idmap_passdb ?!\n")); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + idmap_domains = talloc_realloc(idmap_ctx, idmap_domains, struct idmap_domain *, num_domains+1); + if ( ! idmap_domains) { + DEBUG(0, ("Out of memory!\n")); + ret = NT_STATUS_NO_MEMORY; + goto done; + } + idmap_domains[num_domains] = dom; + + /* needed to handle special BUILTIN and wellknown SIDs cases */ + pdb_dom_num = num_domains; + + DEBUG(10, ("Domain %s - Sid %s - Backend passdb - not default - readonly\n", + dom->name, sid_string_static(dom->sid))); + DEBUGADD(10, (" (special: includes handling BUILTIN and Wellknown SIDs as well)\n")); + + num_domains++; + /**** finished adding idmap_passdb backend ****/ + + /* sort domains so that the default is the last one */ + if (def_dom_num != num_domains-1) { /* default is not last, move it */ + struct idmap_domain *tmp; + + if (pdb_dom_num > def_dom_num) { + pdb_dom_num --; + + } else if (pdb_dom_num == def_dom_num) { /* ?? */ + pdb_dom_num = num_domains - 1; + } + + tmp = idmap_domains[def_dom_num]; + + for (i = def_dom_num; i < num_domains-1; i++) { + idmap_domains[i] = idmap_domains[i+1]; + } + idmap_domains[i] = tmp; + def_dom_num = i; + } + + + /*************************** + * initialize alloc module + */ + DEBUG(1, ("Initializing idmap alloc module\n")); + + if (compat) { + alloc_backend = talloc_strdup(idmap_ctx, compat_backend); + } else { + char *ab = lp_idmap_alloc_backend(); + + if (ab && (ab[0] != '\0')) { + alloc_backend = talloc_strdup(idmap_ctx, lp_idmap_alloc_backend()); + } else { + alloc_backend = talloc_strdup(idmap_ctx, "tdb"); + } + } + IDMAP_CHECK_ALLOC(alloc_backend); + + alloc_methods = get_alloc_methods(alloc_backends, alloc_backend); + if ( ! alloc_methods) { + ret = smb_probe_module("idmap", alloc_backend); + if (NT_STATUS_IS_OK(ret)) { + alloc_methods = get_alloc_methods(alloc_backends, alloc_backend); + } + } + if ( ! alloc_methods) { + DEBUG(0, ("ERROR: Could not get methods for alloc backend %s\n", alloc_backend)); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + ret = alloc_methods->init(compat_params); + if ( ! NT_STATUS_IS_OK(ret)) { + DEBUG(0, ("ERROR: Initialization failed for alloc backend %s\n", alloc_backend)); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + return NT_STATUS_OK; + +done: + DEBUG(0, ("Aborting IDMAP Initialization ...\n")); + idmap_close(); + return ret; +} + +/************************************************************************** + idmap allocator interface functions +**************************************************************************/ + +NTSTATUS idmap_allocate_uid(struct unixid *id) +{ + NTSTATUS ret; + + if (! NT_STATUS_IS_OK(ret = idmap_init())) { + return ret; + } + + id->type = ID_TYPE_UID; + return alloc_methods->allocate_id(id); +} + +NTSTATUS idmap_allocate_gid(struct unixid *id) +{ + NTSTATUS ret; + + if (! NT_STATUS_IS_OK(ret = idmap_init())) { + return ret; + } + + id->type = ID_TYPE_GID; + return alloc_methods->allocate_id(id); +} + +NTSTATUS idmap_set_uid_hwm(struct unixid *id) +{ + NTSTATUS ret; + + if (! NT_STATUS_IS_OK(ret = idmap_init())) { + return ret; + } + + id->type = ID_TYPE_UID; + return alloc_methods->set_id_hwm(id); +} + +NTSTATUS idmap_set_gid_hwm(struct unixid *id) +{ + NTSTATUS ret; + + if (! NT_STATUS_IS_OK(ret = idmap_init())) { + return ret; + } + + id->type = ID_TYPE_GID; + return alloc_methods->set_id_hwm(id); +} + +/********************************************************* + Check if creating a mapping is permitted for the domain +*********************************************************/ + +static NTSTATUS idmap_can_map(const struct id_map *map, struct idmap_domain **ret_dom) +{ + struct idmap_domain *dom; + int i; + + /* Check we do not create mappings for our own local domain, or BUILTIN or special SIDs */ + if ((sid_compare_domain(map->sid, get_global_sam_sid()) == 0) || + sid_check_is_in_builtin(map->sid) || + sid_check_is_in_wellknown_domain(map->sid)) { + DEBUG(10, ("We are not supposed to create mappings for our own domains (local, builtin, specials)\n")); + return NT_STATUS_UNSUCCESSFUL; + } + + /* Special check for trusted domain only = Yes */ + if (lp_winbind_trusted_domains_only()) { + struct winbindd_domain *wdom = find_our_domain(); + if (wdom && (sid_compare_domain(map->sid, &wdom->sid) == 0)) { + DEBUG(10, ("We are not supposed to create mappings for our primary domain when <trusted domain only> is True\n")); + DEBUGADD(10, ("Leave [%s] unmapped\n", sid_string_static(map->sid))); + return NT_STATUS_UNSUCCESSFUL; + } + } + + for (i = 0, dom = NULL; i < num_domains; i++) { + if ((idmap_domains[i]->default_domain) || /* ok set it into the default domain */ + (sid_compare_domain(idmap_domains[i]->sid, map->sid) == 0)) { /* ok found a specific domain */ + dom = idmap_domains[i]; + break; + } + } + + if (! dom) { + /* huh, couldn't find a suitable domain, let's just leave it unmapped */ + DEBUG(10, ("Could not find imdap backend for SID %s", sid_string_static(map->sid))); + return NT_STATUS_NO_SUCH_DOMAIN; + } + + if (dom->readonly) { + /* ouch the domain is read only, let's just leave it unmapped */ + DEBUG(10, ("imdap backend for SID %s is READONLY!\n", sid_string_static(map->sid))); + return NT_STATUS_UNSUCCESSFUL; + } + + *ret_dom = dom; + return NT_STATUS_OK; +} + +static NTSTATUS idmap_new_mapping(TALLOC_CTX *ctx, struct id_map *map) +{ + NTSTATUS ret; + struct idmap_domain *dom; + char *domname, *name; + enum lsa_SidType sid_type; + + ret = idmap_can_map(map, &dom); + if ( ! NT_STATUS_IS_OK(ret)) { + return NT_STATUS_NONE_MAPPED; + } + + /* check if this is a valid SID and then map it */ + if (winbindd_lookup_name_by_sid(ctx, map->sid, &domname, &name, &sid_type)) { + switch (sid_type) { + case SID_NAME_USER: + ret = idmap_allocate_uid(&map->xid); + if ( ! NT_STATUS_IS_OK(ret)) { + /* can't allocate id, let's just leave it unmapped */ + DEBUG(2, ("uid allocation failed! Can't create mapping\n")); + return NT_STATUS_NONE_MAPPED; + } + break; + case SID_NAME_DOM_GRP: + case SID_NAME_ALIAS: + case SID_NAME_WKN_GRP: + ret = idmap_allocate_gid(&map->xid); + if ( ! NT_STATUS_IS_OK(ret)) { + /* can't allocate id, let's just leave it unmapped */ + DEBUG(2, ("gid allocation failed! Can't create mapping\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; + } + + /* ok, got a new id, let's set a mapping */ + map->mapped = True; + + DEBUG(10, ("Setting mapping: %s <-> %s %lu\n", + sid_string_static(map->sid), + (map->xid.type == ID_TYPE_UID) ? "UID" : "GID", + (unsigned long)map->xid.id)); + ret = dom->methods->set_mapping(dom, map); + + if ( ! NT_STATUS_IS_OK(ret)) { + /* something wrong here :-( */ + DEBUG(2, ("Failed to commit mapping\n!")); + + /* TODO: would it make sense to have an "unalloc_id function?" */ + + return NT_STATUS_NONE_MAPPED; + } + } else { + DEBUG(2,("Invalid SID, not mapping %s (type %d)\n", + sid_string_static(map->sid), sid_type)); + return NT_STATUS_NONE_MAPPED; + } + + return NT_STATUS_OK; +} + +static NTSTATUS idmap_backends_set_mapping(const struct id_map *map) +{ + struct idmap_domain *dom; + NTSTATUS ret; + + DEBUG(10, ("Setting mapping %s <-> %s %lu\n", + sid_string_static(map->sid), + (map->xid.type == ID_TYPE_UID) ? "UID" : "GID", + (unsigned long)map->xid.id)); + + ret = idmap_can_map(map, &dom); + if ( ! NT_STATUS_IS_OK(ret)) { + return ret; + } + + DEBUG(10, ("set_mapping for domain %s(%s)\n", dom->name, sid_string_static(dom->sid))); + + return dom->methods->set_mapping(dom, map); +} + +static NTSTATUS idmap_backends_unixids_to_sids(struct id_map **ids) +{ + struct idmap_domain *dom; + struct id_map **_ids; + TALLOC_CTX *ctx; + NTSTATUS ret; + int i, u, n; + + if (!ids || !*ids) { + DEBUG(1, ("Invalid list of maps\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + ctx = talloc_named_const(NULL, 0, "idmap_backends_unixids_to_sids ctx"); + if ( ! ctx) { + DEBUG(0, ("Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + DEBUG(10, ("Query backends to map ids->sids\n")); + + /* start from the default (the last one) and then if there are still + * unmapped entries cycle through the others */ + + _ids = ids; + + /* make sure all maps are marked as false */ + for (i = 0; _ids[i]; i++) { + _ids[i]->mapped = False; + } + + for (n = num_domains-1; n >= 0; n--) { /* cycle backwards */ + struct id_map **unmapped = NULL; + + dom = idmap_domains[n]; + + DEBUG(10, ("Query sids from domain %s(%s)\n", dom->name, sid_string_static(dom->sid))); + + ret = dom->methods->unixids_to_sids(dom, _ids); + IDMAP_CHECK_RET(ret); + + TALLOC_FREE(unmapped); + + for (i = 0, u = 0; _ids[i]; i++) { + if (_ids[i]->mapped == False) { + unmapped = talloc_realloc(ctx, unmapped, struct id_map *, u + 2); + IDMAP_CHECK_ALLOC(unmapped); + unmapped[u] = _ids[i]; + u++; + } + } + if (unmapped) { + /* terminate the unmapped list */ + unmapped[u] = NULL; + } else { /* no more unmapped entries, get out */ + break; + } + + _ids = unmapped; + } + + if (!_ids) { + /* there are still unmapped ids, map them to the unix users/groups domains */ + for (i = 0; _ids[i]; i++) { + switch (_ids[i]->xid.type) { + case ID_TYPE_UID: + uid_to_unix_users_sid((uid_t)_ids[i]->xid.id, _ids[i]->sid); + _ids[i]->mapped = True; + break; + case ID_TYPE_GID: + gid_to_unix_groups_sid((gid_t)_ids[i]->xid.id, _ids[i]->sid); + _ids[i]->mapped = True; + break; + default: /* what?! */ + _ids[i]->mapped = False; + break; + } + } + } + + ret = NT_STATUS_OK; + +done: + talloc_free(ctx); + return ret; +} + +static NTSTATUS idmap_backends_sids_to_unixids(struct id_map **ids) +{ + struct id_map ***dom_ids; + struct idmap_domain *dom; + TALLOC_CTX *ctx; + NTSTATUS ret; + int i, *counters; + + if (!ids || !*ids) { + DEBUG(1, ("Invalid list of maps\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + ctx = talloc_named_const(NULL, 0, "idmap_backends_sids_to_unixids ctx"); + if ( ! ctx) { + DEBUG(1, ("failed to allocate talloc context, OOM?\n")); + return NT_STATUS_NO_MEMORY; + } + + DEBUG(10, ("Query backends to map sids->ids\n")); + + /* split list per domain */ + dom_ids = talloc_zero_array(ctx, struct id_map **, num_domains); + IDMAP_CHECK_ALLOC(dom_ids); + counters = talloc_zero_array(ctx, int, num_domains); + + for (i = 0; ids[i]; i++) { + int dom_num; + + /* make sure they are unmapped by default */ + ids[i]->mapped = False; + + for (dom_num = 0, dom = NULL; dom_num < num_domains; dom_num++) { + if (idmap_domains[dom_num]->default_domain) { + /* we got to the default domain */ + dom = idmap_domains[dom_num]; + break; + } + if (sid_compare_domain(idmap_domains[dom_num]->sid, ids[i]->sid) == 0) { + dom = idmap_domains[dom_num]; + break; + } + } + if (( ! dom) || dom->default_domain) { + /* handle BUILTIN or Special SIDs + * and prevent them from falling into the default domain space */ + if ((sid_check_is_in_builtin(ids[i]->sid) || + sid_check_is_in_wellknown_domain(ids[i]->sid))) { + + if (pdb_dom_num != -1) { + dom = idmap_domains[pdb_dom_num]; + dom_num = pdb_dom_num; + } else { + dom = NULL; + } + } + } + if ( ! dom) { + /* no dom move on */ + continue; + } + + DEBUG(10, ("SID %s is being handled by %s(%d)\n", + sid_string_static(ids[i]->sid), + dom?dom->name:"none", + dom_num)); + + dom_ids[dom_num] = talloc_realloc(ctx, dom_ids[dom_num], struct id_map *, counters[dom_num] + 2); + IDMAP_CHECK_ALLOC(dom_ids[dom_num]); + + dom_ids[dom_num][counters[dom_num]] = ids[i]; + counters[dom_num]++; + dom_ids[dom_num][counters[dom_num]] = NULL; + } + + /* ok all the ids have been dispatched in the right queues + * let's cycle through the filled ones */ + + for (i = 0; i < num_domains; i++) { + if (dom_ids[i]) { /* ok, we have ids in this one */ + dom = idmap_domains[i]; + DEBUG(10, ("Query ids from domain %s(%s)\n", dom->name, sid_string_static(dom->sid))); + ret = dom->methods->sids_to_unixids(dom, dom_ids[i]); + IDMAP_CHECK_RET(ret); + } + } + + /* ok all the backends have been contacted at this point */ + /* let's see if we have any unmapped SID left and act accordingly */ + + for (i = 0; ids[i]; i++) { + if ( ! ids[i]->mapped) { /* ok this is an unmapped one, see if we can map it */ + ret = idmap_new_mapping(ctx, ids[i]); + if (NT_STATUS_IS_OK(ret)) { + /* successfully mapped */ + ids[i]->mapped = True; + } else if (NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED)) { + /* could not map it */ + ids[i]->mapped = False; + } else{ + /* Something very bad happened down there */ + goto done; + } + } + } + + ret = NT_STATUS_OK; + +done: + talloc_free(ctx); + return ret; +} + +/************************************************************************** + idmap interface functions +**************************************************************************/ + +NTSTATUS idmap_unixids_to_sids(struct id_map **ids) +{ + TALLOC_CTX *ctx; + NTSTATUS ret; + struct id_map **bids; + int i, bi; + int bn = 0; + + if (! NT_STATUS_IS_OK(ret = idmap_init())) { + return ret; + } + + if (!ids || !*ids) { + DEBUG(1, ("Invalid list of maps\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + ctx = talloc_named_const(NULL, 0, "idmap_unixids_to_sids ctx"); + if ( ! ctx) { + DEBUG(1, ("failed to allocate talloc context, OOM?\n")); + return NT_STATUS_NO_MEMORY; + } + + /* no ids to be asked to the backends by default */ + bids = NULL; + bi = 0; + + for (i = 0; ids[i]; i++) { + + if ( ! ids[i]->sid) { + DEBUG(1, ("invalid null SID in id_map array")); + talloc_free(ctx); + return NT_STATUS_INVALID_PARAMETER; + } + + ret = idmap_cache_map_id(idmap_cache, ids[i]); + + /* TODO: handle NT_STATUS_SYNCHRONIZATION_REQUIRED for disconnected mode */ + + if ( ! NT_STATUS_IS_OK(ret)) { + + if ( ! bids) { + /* alloc space for ids to be resolved by backends (realloc ten by ten) */ + bids = talloc_array(ctx, struct id_map *, 10); + if ( ! bids) { + DEBUG(1, ("Out of memory!\n")); + talloc_free(ctx); + return NT_STATUS_NO_MEMORY; + } + bn = 10; + } + + /* add this id to the ones to be retrieved from the backends */ + bids[bi] = ids[i]; + bi++; + + /* check if we need to allocate new space on the rids array */ + if (bi == bn) { + bn += 10; + bids = talloc_realloc(ctx, bids, struct id_map *, bn); + if ( ! bids) { + DEBUG(1, ("Out of memory!\n")); + talloc_free(ctx); + return NT_STATUS_NO_MEMORY; + } + } + + /* make sure the last element is NULL */ + bids[bi] = NULL; + } + } + + /* let's see if there is any id mapping to be retieved from the backends */ + if (bi) { + ret = idmap_backends_unixids_to_sids(bids); + IDMAP_CHECK_RET(ret); + + /* update the cache */ + for (i = 0; i < bi; i++) { + if (bids[i]->mapped) { + ret = idmap_cache_set(idmap_cache, bids[i]); + } else { + ret = idmap_cache_set_negative_id(idmap_cache, bids[i]); + } + IDMAP_CHECK_RET(ret); + } + } + + ret = NT_STATUS_OK; +done: + talloc_free(ctx); + return ret; +} + +NTSTATUS idmap_sids_to_unixids(struct id_map **ids) +{ + TALLOC_CTX *ctx; + NTSTATUS ret; + struct id_map **bids; + int i, bi; + int bn = 0; + + if (! NT_STATUS_IS_OK(ret = idmap_init())) { + return ret; + } + + if (!ids || !*ids) { + DEBUG(1, ("Invalid list of maps\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + ctx = talloc_named_const(NULL, 0, "idmap_sids_to_unixids ctx"); + if ( ! ctx) { + DEBUG(1, ("failed to allocate talloc context, OOM?\n")); + return NT_STATUS_NO_MEMORY; + } + + /* no ids to be asked to the backends by default */ + bids = NULL; + bi = 0; + + for (i = 0; ids[i]; i++) { + + if ( ! ids[i]->sid) { + DEBUG(1, ("invalid null SID in id_map array\n")); + talloc_free(ctx); + return NT_STATUS_INVALID_PARAMETER; + } + + ret = idmap_cache_map_sid(idmap_cache, ids[i]); + + /* TODO: handle NT_STATUS_SYNCHRONIZATION_REQUIRED for disconnected mode */ + + if ( ! NT_STATUS_IS_OK(ret)) { + + if ( ! bids) { + /* alloc space for ids to be resolved by backends (realloc ten by ten) */ + bids = talloc_array(ctx, struct id_map *, 10); + if ( ! bids) { + DEBUG(1, ("Out of memory!\n")); + talloc_free(ctx); + return NT_STATUS_NO_MEMORY; + } + bn = 10; + } + + /* add this id to the ones to be retrieved from the backends */ + bids[bi] = ids[i]; + bi++; + + /* check if we need to allocate new space on the ids array */ + if (bi == bn) { + bn += 10; + bids = talloc_realloc(ctx, bids, struct id_map *, bn); + if ( ! bids) { + DEBUG(1, ("Out of memory!\n")); + talloc_free(ctx); + return NT_STATUS_NO_MEMORY; + } + } + + /* make sure the last element is NULL */ + bids[bi] = NULL; + } + } + + /* let's see if there is any id mapping to be retieved from the backends */ + if (bids) { + ret = idmap_backends_sids_to_unixids(bids); + IDMAP_CHECK_RET(ret); + + /* update the cache */ + for (i = 0; bids[i]; i++) { + if (bids[i]->mapped) { + ret = idmap_cache_set(idmap_cache, bids[i]); + } else { + ret = idmap_cache_set_negative_sid(idmap_cache, bids[i]); + } + IDMAP_CHECK_RET(ret); + } + } + + ret = NT_STATUS_OK; +done: + talloc_free(ctx); + return ret; +} + +NTSTATUS idmap_set_mapping(const struct id_map *id) +{ + TALLOC_CTX *ctx; + NTSTATUS ret; + + if (! NT_STATUS_IS_OK(ret = idmap_init())) { + return ret; + } + + /* sanity checks */ + if ((id->sid == NULL) || (! id->mapped)) { + DEBUG(1, ("NULL SID or unmapped entry\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + /* TODO: check uid/gid range ? */ + + ctx = talloc_named_const(NULL, 0, "idmap_set_mapping ctx"); + if ( ! ctx) { + DEBUG(1, ("failed to allocate talloc context, OOM?\n")); + return NT_STATUS_NO_MEMORY; + } + + /* set the new mapping */ + ret = idmap_backends_set_mapping(id); + IDMAP_CHECK_RET(ret); + + /* set the mapping in the cache */ + ret = idmap_cache_set(idmap_cache, id); + IDMAP_CHECK_RET(ret); + +done: + talloc_free(ctx); + return ret; +} + +/************************************************************************** + Dump backend status. +**************************************************************************/ + +void idmap_dump_maps(char *logfile) +{ + NTSTATUS ret; + struct unixid allid; + struct id_map *maps; + int num_maps; + FILE *dump; + int i; + + if (! NT_STATUS_IS_OK(ret = idmap_init())) { + return; + } + + dump = fopen(logfile, "w"); + if ( ! dump) { + DEBUG(0, ("Unable to open open stream for file [%s], errno: %d\n", logfile, errno)); + return; + } + + allid.type = ID_TYPE_UID; + allid.id = 0; + alloc_methods->get_id_hwm(&allid); + fprintf(dump, "USER HWM %lu\n", (unsigned long)allid.id); + + allid.type = ID_TYPE_GID; + allid.id = 0; + alloc_methods->get_id_hwm(&allid); + fprintf(dump, "GROUP HWM %lu\n", (unsigned long)allid.id); + + maps = talloc(idmap_ctx, struct id_map); + num_maps = 0; + + for (i = 0; i < num_domains; i++) { + if (idmap_domains[i]->methods->dump_data) { + idmap_domains[i]->methods->dump_data(idmap_domains[i], &maps, &num_maps); + } + } + + for (i = 0; i < num_maps; i++) { + switch (maps[i].xid.type) { + case ID_TYPE_UID: + fprintf(dump, "UID %lu %s\n", + (unsigned long)maps[i].xid.id, + sid_string_static(maps[i].sid)); + break; + case ID_TYPE_GID: + fprintf(dump, "GID %lu %s\n", + (unsigned long)maps[i].xid.id, + sid_string_static(maps[i].sid)); + break; + } + } + + fflush(dump); + fclose(dump); +} + +const char *idmap_fecth_secret(const char *backend, bool alloc, + const char *domain, const char *identity) +{ + char *tmp, *ret; + int r; + + if (alloc) { + r = asprintf(&tmp, "IDMAP_ALLOC_%s", backend); + } else { + r = asprintf(&tmp, "IDMAP_%s_%s", backend, domain); + } + + if (r < 0) return NULL; + + strupper_m(tmp); /* make sure the key is case insensitive */ + ret = secrets_fetch_generic(tmp, identity); + + free(tmp); + return ret; +} diff --git a/source3/nsswitch/idmap_ad.c b/source3/nsswitch/idmap_ad.c new file mode 100644 index 0000000000..00438d8ab0 --- /dev/null +++ b/source3/nsswitch/idmap_ad.c @@ -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); +} + diff --git a/source3/nsswitch/idmap_cache.c b/source3/nsswitch/idmap_cache.c new file mode 100644 index 0000000000..535083fb2b --- /dev/null +++ b/source3/nsswitch/idmap_cache.c @@ -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; +} + diff --git a/source3/nsswitch/idmap_ldap.c b/source3/nsswitch/idmap_ldap.c new file mode 100644 index 0000000000..baa926d479 --- /dev/null +++ b/source3/nsswitch/idmap_ldap.c @@ -0,0 +1,1349 @@ +/* + Unix SMB/CIFS implementation. + + idmap LDAP backend + + Copyright (C) Tim Potter 2000 + Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003 + Copyright (C) Gerald Carter 2003 + Copyright (C) Simo Sorce 2003-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 + +#include <lber.h> +#include <ldap.h> + +#include "smbldap.h" + +struct idmap_ldap_alloc_context { + struct smbldap_state *smbldap_state; + char *url; + char *suffix; + char *user_dn; + uid_t low_uid, high_uid; /* Range of uids */ + gid_t low_gid, high_gid; /* Range of gids */ + +}; + +#define CHECK_ALLOC_DONE(mem) do { if (!mem) { DEBUG(0, ("Out of memory!\n")); ret = NT_STATUS_NO_MEMORY; goto done; } } while (0) + +/********************************************************************** + IDMAP ALLOC TDB BACKEND +**********************************************************************/ + +static struct idmap_ldap_alloc_context *idmap_alloc_ldap; + +/********************************************************************** + Verify the sambaUnixIdPool entry in the directory. +**********************************************************************/ + +static NTSTATUS verify_idpool(void) +{ + NTSTATUS ret; + TALLOC_CTX *ctx; + LDAPMessage *result = NULL; + LDAPMod **mods = NULL; + const char **attr_list; + char *filter; + int count; + int rc; + + if ( ! idmap_alloc_ldap) { + return NT_STATUS_UNSUCCESSFUL; + } + + ctx = talloc_new(idmap_alloc_ldap); + if ( ! ctx) { + DEBUG(0, ("Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + filter = talloc_asprintf(ctx, "(objectclass=%s)", LDAP_OBJ_IDPOOL); + CHECK_ALLOC_DONE(filter); + + attr_list = get_attr_list(ctx, idpool_attr_list); + CHECK_ALLOC_DONE(attr_list); + + rc = smbldap_search(idmap_alloc_ldap->smbldap_state, + idmap_alloc_ldap->suffix, + LDAP_SCOPE_SUBTREE, + filter, + attr_list, + 0, + &result); + + if (rc != LDAP_SUCCESS) { + return NT_STATUS_UNSUCCESSFUL; + } + + count = ldap_count_entries(idmap_alloc_ldap->smbldap_state->ldap_struct, result); + + ldap_msgfree(result); + + if ( count > 1 ) { + DEBUG(0,("Multiple entries returned from %s (base == %s)\n", + filter, idmap_alloc_ldap->suffix)); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + else if (count == 0) { + char *uid_str, *gid_str; + + uid_str = talloc_asprintf(ctx, "%lu", (unsigned long)idmap_alloc_ldap->low_uid); + gid_str = talloc_asprintf(ctx, "%lu", (unsigned long)idmap_alloc_ldap->low_gid); + + 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(idmap_alloc_ldap->smbldap_state, + idmap_alloc_ldap->suffix, + mods); + ldap_mods_free(mods, True); + } else { + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + } + + ret = (rc == LDAP_SUCCESS)?NT_STATUS_OK:NT_STATUS_UNSUCCESSFUL; +done: + talloc_free(ctx); + return ret; +} + +/***************************************************************************** + Initialise idmap database. +*****************************************************************************/ + +static NTSTATUS idmap_ldap_alloc_init(const char *params) +{ + NTSTATUS nt_status; + const char *secret; + const char *range; + const char *tmp; + uint32_t low_id = 0; + uint32_t high_id = 0; + + idmap_alloc_ldap = talloc_zero(NULL, struct idmap_ldap_alloc_context); + if (!idmap_alloc_ldap) { + DEBUG(0, ("Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + /* load ranges */ + idmap_alloc_ldap->low_uid = 0; + idmap_alloc_ldap->high_uid = 0; + idmap_alloc_ldap->low_gid = 0; + idmap_alloc_ldap->high_gid = 0; + + range = lp_parm_const_string(-1, "idmap alloc config", "range", NULL); + if (range && range[0]) { + if (sscanf(range, "%u - %u", &low_id, &high_id) == 2) { + if (low_id < high_id) { + idmap_alloc_ldap->low_gid = idmap_alloc_ldap->low_uid = low_id; + idmap_alloc_ldap->high_gid = idmap_alloc_ldap->high_uid = high_id; + } else { + DEBUG(1, ("ERROR: invalid idmap alloc range [%s]", range)); + } + } else { + DEBUG(1, ("ERROR: invalid syntax for idmap alloc config:range [%s]", range)); + } + } + + if (lp_idmap_uid(&low_id, &high_id)) { + idmap_alloc_ldap->low_uid = low_id; + idmap_alloc_ldap->high_uid = high_id; + } + + if (lp_idmap_gid(&low_id, &high_id)) { + idmap_alloc_ldap->low_gid = low_id; + idmap_alloc_ldap->high_gid= high_id; + } + + if (idmap_alloc_ldap->high_uid <= idmap_alloc_ldap->low_uid) { + DEBUG(1, ("idmap uid range missing or invalid\n")); + DEBUGADD(1, ("idmap will be unable to map foreign SIDs\n")); + talloc_free(idmap_alloc_ldap); + return NT_STATUS_UNSUCCESSFUL; + } + + if (idmap_alloc_ldap->high_gid <= idmap_alloc_ldap->low_gid) { + DEBUG(1, ("idmap gid range missing or invalid\n")); + DEBUGADD(1, ("idmap will be unable to map foreign SIDs\n")); + talloc_free(idmap_alloc_ldap); + return NT_STATUS_UNSUCCESSFUL; + } + + if (params && *params) { + /* assume location is the only parameter */ + idmap_alloc_ldap->url = talloc_strdup(idmap_alloc_ldap, params); + } else { + tmp = lp_parm_const_string(-1, "idmap alloc config", "ldap_url", NULL); + + if ( ! tmp) { + DEBUG(1, ("ERROR: missing idmap ldap url\n")); + talloc_free(idmap_alloc_ldap); + return NT_STATUS_UNSUCCESSFUL; + } + + idmap_alloc_ldap->url = talloc_strdup(idmap_alloc_ldap, tmp); + } + if ( ! idmap_alloc_ldap->url) { + talloc_free(idmap_alloc_ldap); + DEBUG(0, ("Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + tmp = lp_ldap_idmap_suffix(); + if ( ! tmp || ! *tmp) { + tmp = lp_parm_const_string(-1, "idmap alloc config", "ldap_base_dn", NULL); + } + if ( ! tmp) { + tmp = lp_ldap_suffix(); + if (tmp) { + DEBUG(1, ("WARNING: Trying to use the global ldap suffix(%s)\n", tmp)); + DEBUGADD(1, ("as suffix. This may not be what you want!\n")); + } + } + if ( ! tmp) { + DEBUG(1, ("ERROR: missing idmap ldap suffix\n")); + talloc_free(idmap_alloc_ldap); + return NT_STATUS_UNSUCCESSFUL; + } + idmap_alloc_ldap->suffix = talloc_strdup(idmap_alloc_ldap, tmp); + if ( ! idmap_alloc_ldap->suffix) { + talloc_free(idmap_alloc_ldap); + DEBUG(0, ("Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + tmp = lp_parm_const_string(-1, "idmap alloc config", "ldap_user_dn", NULL); + + if ( ! tmp) { + tmp = lp_ldap_admin_dn(); + } + if (! tmp || ! *tmp) { + DEBUG(1, ("ERROR: missing idmap ldap user dn\n")); + talloc_free(idmap_alloc_ldap); + return NT_STATUS_UNSUCCESSFUL; + } + + idmap_alloc_ldap->user_dn = talloc_strdup(idmap_alloc_ldap, tmp); + if ( ! idmap_alloc_ldap->user_dn) { + talloc_free(idmap_alloc_ldap); + DEBUG(0, ("Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + if (!NT_STATUS_IS_OK(nt_status = + smbldap_init(idmap_alloc_ldap, idmap_alloc_ldap->url, + &idmap_alloc_ldap->smbldap_state))) { + DEBUG(1, ("ERROR: smbldap_init (%s) failed!\n", + idmap_alloc_ldap->url)); + talloc_free(idmap_alloc_ldap); + return nt_status; + } + + /* fetch credentials from secrets.tdb */ + secret = idmap_fecth_secret("ldap", true, NULL, idmap_alloc_ldap->user_dn); + if (!secret) { + DEBUG(1, ("ERROR: unable to fetch auth credentials\n")); + talloc_free(idmap_alloc_ldap); + return NT_STATUS_ACCESS_DENIED; + } + /* now set credentials */ + smbldap_set_creds(idmap_alloc_ldap->smbldap_state, false, idmap_alloc_ldap->user_dn, secret); + + /* see if the idmap suffix and sub entries exists */ + nt_status = verify_idpool(); + if (!NT_STATUS_IS_OK(nt_status)) { + talloc_free(idmap_alloc_ldap); + return nt_status; + } + + return NT_STATUS_OK; +} + +/******************************** + Allocate a new uid or gid +********************************/ + +static NTSTATUS idmap_ldap_allocate_id(struct unixid *xid) +{ + TALLOC_CTX *ctx; + NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + int rc = LDAP_SERVER_DOWN; + int count = 0; + LDAPMessage *result = NULL; + LDAPMessage *entry = NULL; + LDAPMod **mods = NULL; + char *id_str; + char *new_id_str; + char *filter = NULL; + const char *dn = NULL; + const char **attr_list; + const char *type; + + if ( ! idmap_alloc_ldap) { + return NT_STATUS_UNSUCCESSFUL; + } + + ctx = talloc_new(idmap_alloc_ldap); + if ( ! ctx) { + DEBUG(0, ("Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + /* get type */ + switch (xid->type) { + + case ID_TYPE_UID: + type = get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER); + break; + + case ID_TYPE_GID: + type = get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER); + break; + + default: + DEBUG(2, ("Invalid ID type (0x%x)\n", xid->type)); + return NT_STATUS_INVALID_PARAMETER; + } + + filter = talloc_asprintf(ctx, "(objectClass=%s)", LDAP_OBJ_IDPOOL); + CHECK_ALLOC_DONE(filter); + + attr_list = get_attr_list(ctx, idpool_attr_list); + CHECK_ALLOC_DONE(attr_list); + + DEBUG(10, ("Search of the id pool (filter: %s)\n", filter)); + + rc = smbldap_search(idmap_alloc_ldap->smbldap_state, + idmap_alloc_ldap->suffix, + LDAP_SCOPE_SUBTREE, filter, + attr_list, 0, &result); + + if (rc != LDAP_SUCCESS) { + DEBUG(0,("%s object not found\n", LDAP_OBJ_IDPOOL)); + goto done; + } + + talloc_autofree_ldapmsg(ctx, result); + + count = ldap_count_entries(idmap_alloc_ldap->smbldap_state->ldap_struct, result); + if (count != 1) { + DEBUG(0,("Single %s object not found\n", LDAP_OBJ_IDPOOL)); + goto done; + } + + entry = ldap_first_entry(idmap_alloc_ldap->smbldap_state->ldap_struct, result); + + dn = smbldap_talloc_dn(ctx, idmap_alloc_ldap->smbldap_state->ldap_struct, entry); + if ( ! dn) { + goto done; + } + + if ( ! (id_str = smbldap_talloc_single_attribute(idmap_alloc_ldap->smbldap_state->ldap_struct, + entry, type, ctx))) { + DEBUG(0,("%s attribute not found\n", type)); + goto done; + } + if ( ! id_str) { + DEBUG(0,("Out of memory\n")); + ret = NT_STATUS_NO_MEMORY; + goto done; + } + + xid->id = strtoul(id_str, NULL, 10); + + /* make sure we still have room to grow */ + + switch (xid->type) { + case ID_TYPE_UID: + if (xid->id > idmap_alloc_ldap->high_uid) { + DEBUG(0,("Cannot allocate uid above %lu!\n", + (unsigned long)idmap_alloc_ldap->high_uid)); + goto done; + } + break; + + case ID_TYPE_GID: + if (xid->id > idmap_alloc_ldap->high_gid) { + DEBUG(0,("Cannot allocate gid above %lu!\n", + (unsigned long)idmap_alloc_ldap->high_uid)); + goto done; + } + break; + + default: + /* impossible */ + goto done; + } + + new_id_str = talloc_asprintf(ctx, "%lu", (unsigned long)xid->id + 1); + if ( ! new_id_str) { + DEBUG(0,("Out of memory\n")); + ret = NT_STATUS_NO_MEMORY; + goto done; + } + + 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,("smbldap_set_mod() failed.\n")); + goto done; + } + + DEBUG(10, ("Try to atomically increment the id (%s -> %s)\n", id_str, new_id_str)); + + rc = smbldap_modify(idmap_alloc_ldap->smbldap_state, dn, mods); + + ldap_mods_free(mods, True); + + if (rc != LDAP_SUCCESS) { + DEBUG(1,("Failed to allocate new %s. smbldap_modify() failed.\n", type)); + goto done; + } + + ret = NT_STATUS_OK; + +done: + talloc_free(ctx); + return ret; +} + +/********************************** + Get current highest id. +**********************************/ + +static NTSTATUS idmap_ldap_get_hwm(struct unixid *xid) +{ + TALLOC_CTX *memctx; + NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + int rc = LDAP_SERVER_DOWN; + int count = 0; + LDAPMessage *result = NULL; + LDAPMessage *entry = NULL; + char *id_str; + char *filter = NULL; + const char **attr_list; + const char *type; + + if ( ! idmap_alloc_ldap) { + return NT_STATUS_UNSUCCESSFUL; + } + + memctx = talloc_new(idmap_alloc_ldap); + if ( ! memctx) { + DEBUG(0, ("Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + /* get type */ + switch (xid->type) { + + case ID_TYPE_UID: + type = get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER); + break; + + case ID_TYPE_GID: + type = get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER); + break; + + default: + DEBUG(2, ("Invalid ID type (0x%x)\n", xid->type)); + return NT_STATUS_INVALID_PARAMETER; + } + + filter = talloc_asprintf(memctx, "(objectClass=%s)", LDAP_OBJ_IDPOOL); + CHECK_ALLOC_DONE(filter); + + attr_list = get_attr_list(memctx, idpool_attr_list); + CHECK_ALLOC_DONE(attr_list); + + rc = smbldap_search(idmap_alloc_ldap->smbldap_state, + idmap_alloc_ldap->suffix, + LDAP_SCOPE_SUBTREE, filter, + attr_list, 0, &result); + + if (rc != LDAP_SUCCESS) { + DEBUG(0,("%s object not found\n", LDAP_OBJ_IDPOOL)); + goto done; + } + + talloc_autofree_ldapmsg(memctx, result); + + count = ldap_count_entries(idmap_alloc_ldap->smbldap_state->ldap_struct, result); + if (count != 1) { + DEBUG(0,("Single %s object not found\n", LDAP_OBJ_IDPOOL)); + goto done; + } + + entry = ldap_first_entry(idmap_alloc_ldap->smbldap_state->ldap_struct, result); + + id_str = smbldap_talloc_single_attribute(idmap_alloc_ldap->smbldap_state->ldap_struct, + entry, type, memctx); + if ( ! id_str) { + DEBUG(0,("%s attribute not found\n", type)); + goto done; + } + if ( ! id_str) { + DEBUG(0,("Out of memory\n")); + ret = NT_STATUS_NO_MEMORY; + goto done; + } + + xid->id = strtoul(id_str, NULL, 10); + + ret = NT_STATUS_OK; +done: + talloc_free(memctx); + return ret; +} +/********************************** + Set highest id. +**********************************/ + +static NTSTATUS idmap_ldap_set_hwm(struct unixid *xid) +{ + TALLOC_CTX *ctx; + NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + int rc = LDAP_SERVER_DOWN; + int count = 0; + LDAPMessage *result = NULL; + LDAPMessage *entry = NULL; + LDAPMod **mods = NULL; + char *new_id_str; + char *filter = NULL; + const char *dn = NULL; + const char **attr_list; + const char *type; + + if ( ! idmap_alloc_ldap) { + return NT_STATUS_UNSUCCESSFUL; + } + + ctx = talloc_new(idmap_alloc_ldap); + if ( ! ctx) { + DEBUG(0, ("Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + /* get type */ + switch (xid->type) { + + case ID_TYPE_UID: + type = get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER); + break; + + case ID_TYPE_GID: + type = get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER); + break; + + default: + DEBUG(2, ("Invalid ID type (0x%x)\n", xid->type)); + return NT_STATUS_INVALID_PARAMETER; + } + + filter = talloc_asprintf(ctx, "(objectClass=%s)", LDAP_OBJ_IDPOOL); + CHECK_ALLOC_DONE(filter); + + attr_list = get_attr_list(ctx, idpool_attr_list); + CHECK_ALLOC_DONE(attr_list); + + rc = smbldap_search(idmap_alloc_ldap->smbldap_state, + idmap_alloc_ldap->suffix, + LDAP_SCOPE_SUBTREE, filter, + attr_list, 0, &result); + + if (rc != LDAP_SUCCESS) { + DEBUG(0,("%s object not found\n", LDAP_OBJ_IDPOOL)); + goto done; + } + + talloc_autofree_ldapmsg(ctx, result); + + count = ldap_count_entries(idmap_alloc_ldap->smbldap_state->ldap_struct, result); + if (count != 1) { + DEBUG(0,("Single %s object not found\n", LDAP_OBJ_IDPOOL)); + goto done; + } + + entry = ldap_first_entry(idmap_alloc_ldap->smbldap_state->ldap_struct, result); + + dn = smbldap_talloc_dn(ctx, idmap_alloc_ldap->smbldap_state->ldap_struct, entry); + if ( ! dn) { + goto done; + } + + new_id_str = talloc_asprintf(ctx, "%lu", (unsigned long)xid->id); + if ( ! new_id_str) { + DEBUG(0,("Out of memory\n")); + ret = NT_STATUS_NO_MEMORY; + goto done; + } + + smbldap_set_mod(&mods, LDAP_MOD_REPLACE, type, new_id_str); + + if (mods == NULL) { + DEBUG(0,("smbldap_set_mod() failed.\n")); + goto done; + } + + rc = smbldap_modify(idmap_alloc_ldap->smbldap_state, dn, mods); + + ldap_mods_free(mods, True); + + if (rc != LDAP_SUCCESS) { + DEBUG(1,("Failed to allocate new %s. smbldap_modify() failed.\n", type)); + goto done; + } + + ret = NT_STATUS_OK; + +done: + talloc_free(ctx); + return ret; +} + +/********************************** + Close idmap ldap alloc +**********************************/ + +static NTSTATUS idmap_ldap_alloc_close(void) +{ + if (idmap_alloc_ldap) { + smbldap_free_struct(&idmap_alloc_ldap->smbldap_state); + DEBUG(5,("The connection to the LDAP server was closed\n")); + /* maybe free the results here --metze */ + TALLOC_FREE(idmap_alloc_ldap); + } + return NT_STATUS_OK; +} + + +/********************************************************************** + IDMAP MAPPING LDAP BACKEND +**********************************************************************/ + +struct idmap_ldap_context { + struct smbldap_state *smbldap_state; + char *url; + char *suffix; + char *user_dn; + uint32_t filter_low_id, filter_high_id; /* Filter range */ + BOOL anon; +}; + +static int idmap_ldap_close_destructor(struct idmap_ldap_context *ctx) +{ + smbldap_free_struct(&ctx->smbldap_state); + DEBUG(5,("The connection to the LDAP server was closed\n")); + /* maybe free the results here --metze */ + + return 0; +} + +/******************************** + Initialise idmap database. +********************************/ + +static NTSTATUS idmap_ldap_db_init(struct idmap_domain *dom, const char *params) +{ + NTSTATUS ret; + struct idmap_ldap_context *ctx; + char *config_option; + const char *secret; + const char *range; + const char *tmp; + + ctx = talloc_zero(dom, struct idmap_ldap_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 done; + } + + /* 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; + } + } + + if (params && *params) { + /* assume location is the only parameter */ + ctx->url = talloc_strdup(ctx, params); + } else { + tmp = lp_parm_const_string(-1, config_option, "ldap_url", NULL); + + if ( ! tmp) { + DEBUG(1, ("ERROR: missing idmap ldap url\n")); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + ctx->url = talloc_strdup(ctx, tmp); + } + CHECK_ALLOC_DONE(ctx->url); + + tmp = lp_ldap_idmap_suffix(); + if ( ! tmp || ! *tmp) { + tmp = lp_parm_const_string(-1, config_option, "ldap_base_dn", NULL); + } + if ( ! tmp) { + tmp = lp_ldap_suffix(); + if (tmp) { + DEBUG(1, ("WARNING: Trying to use the global ldap suffix(%s)\n", tmp)); + DEBUGADD(1, ("as suffix. This may not be what you want!\n")); + } + } + if ( ! tmp) { + DEBUG(1, ("ERROR: missing idmap ldap suffix\n")); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + ctx->suffix = talloc_strdup(ctx, tmp); + CHECK_ALLOC_DONE(ctx->suffix); + + ctx->anon = lp_parm_bool(-1, config_option, "ldap_anon", False); + + ret = smbldap_init(ctx, ctx->url, &ctx->smbldap_state); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(1, ("ERROR: smbldap_init (%s) failed!\n", ctx->url)); + goto done; + } + + if ( ! ctx->anon) { + tmp = lp_parm_const_string(-1, config_option, "ldap_user_dn", NULL); + + if ( ! tmp) { + tmp = lp_ldap_admin_dn(); + } + if (! tmp || ! *tmp) { + DEBUG(1, ("ERROR: missing idmap ldap user dn\n")); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + ctx->user_dn = talloc_strdup(ctx, tmp); + CHECK_ALLOC_DONE(ctx->user_dn); + + /* fetch credentials */ + secret = idmap_fecth_secret("ldap", false, dom->name, ctx->user_dn); + if (!secret) { + DEBUG(1, ("ERROR: unable to fetch auth credentials\n")); + ret = NT_STATUS_ACCESS_DENIED; + goto done; + } + /* now set credentials */ + smbldap_set_creds(ctx->smbldap_state, false, ctx->user_dn, secret); + } else { + smbldap_set_creds(ctx->smbldap_state, true, NULL, NULL); + } + + /* set the destructor on the context, so that resource are properly + * freed if the contexts is released */ + talloc_set_destructor(ctx, idmap_ldap_close_destructor); + + dom->private_data = ctx; + + talloc_free(config_option); + return NT_STATUS_OK; + +/*failed */ +done: + talloc_free(ctx); + return ret; +} + +/* max number of ids requested per batch query */ +#define IDMAP_LDAP_MAX_IDS 30 + +/********************************** + lookup a set of unix ids. +**********************************/ + +/* this function searches up to IDMAP_LDAP_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_LDAP_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_ldap_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids) +{ + NTSTATUS ret; + TALLOC_CTX *memctx; + struct idmap_ldap_context *ctx; + LDAPMessage *result = NULL; + const char *uidNumber; + const char *gidNumber; + const char **attr_list; + char *filter = NULL; + BOOL multi = False; + int idx = 0; + int bidx = 0; + int count; + int rc; + int i; + + ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context); + + memctx = talloc_new(ctx); + if ( ! memctx) { + DEBUG(0, ("Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + uidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER); + gidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER); + + attr_list = get_attr_list(ctx, sidmap_attr_list); + + if ( ! ids[1]) { + /* if we are requested just one mapping use the simple filter */ + + filter = talloc_asprintf(memctx, "(&(objectClass=%s)(%s=%lu))", + LDAP_OBJ_IDMAP_ENTRY, + (ids[0]->xid.type==ID_TYPE_UID)?uidNumber:gidNumber, + (unsigned long)ids[0]->xid.id); + CHECK_ALLOC_DONE(filter); + DEBUG(10, ("Filter: [%s]\n", filter)); + } else { + /* multiple mappings */ + multi = True; + } + +again: + if (multi) { + + talloc_free(filter); + filter = talloc_asprintf(memctx, "(&(objectClass=%s)(|", LDAP_OBJ_IDMAP_ENTRY); + CHECK_ALLOC_DONE(filter); + + bidx = idx; + for (i = 0; (i < IDMAP_LDAP_MAX_IDS) && ids[idx]; i++, idx++) { + filter = talloc_asprintf_append(filter, "(%s=%lu)", + (ids[idx]->xid.type==ID_TYPE_UID)?uidNumber:gidNumber, + (unsigned long)ids[idx]->xid.id); + 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 = smbldap_search(ctx->smbldap_state, ctx->suffix, LDAP_SCOPE_SUBTREE, + filter, attr_list, 0, &result); + + if (rc != LDAP_SUCCESS) { + DEBUG(3,("Failure looking up ids (%s)\n", ldap_err2string(rc))); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + count = ldap_count_entries(ctx->smbldap_state->ldap_struct, result); + + if (count == 0) { + DEBUG(10, ("NO SIDs found\n")); + } + + for (i = 0; i < count; i++) { + LDAPMessage *entry = NULL; + char *sidstr = NULL; + char *tmp = NULL; + enum id_type type; + struct id_map *map; + uint32_t id; + + if (i == 0) { /* first entry */ + entry = ldap_first_entry(ctx->smbldap_state->ldap_struct, result); + } else { /* following ones */ + entry = ldap_next_entry(ctx->smbldap_state->ldap_struct, entry); + } + if ( ! entry) { + DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n")); + continue; + } + + /* first check if the SID is present */ + sidstr = smbldap_talloc_single_attribute( + ctx->smbldap_state->ldap_struct, + entry, LDAP_ATTRIBUTE_SID, memctx); + if ( ! sidstr) { /* no sid, skip entry */ + DEBUG(2, ("WARNING SID not found on entry\n")); + continue; + } + + /* now try to see if it is a uid, if not try with a gid + * (gid is more common, but in case both uidNumber and + * gidNumber are returned the SID is mapped to the uid not the gid) */ + type = ID_TYPE_UID; + tmp = smbldap_talloc_single_attribute( + ctx->smbldap_state->ldap_struct, + entry, uidNumber, memctx); + if ( ! tmp) { + type = ID_TYPE_GID; + tmp = smbldap_talloc_single_attribute( + ctx->smbldap_state->ldap_struct, + entry, gidNumber, memctx); + } + if ( ! tmp) { /* wow very strange entry, how did it match ? */ + DEBUG(5, ("Unprobable match on (%s), no uidNumber, nor gidNumber returned\n", sidstr)); + TALLOC_FREE(sidstr); + continue; + } + + id = strtoul(tmp, NULL, 10); + 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)); + TALLOC_FREE(sidstr); + TALLOC_FREE(tmp); + continue; + } + TALLOC_FREE(tmp); + + map = find_map_by_id(&ids[bidx], type, id); + if (!map) { + DEBUG(2, ("WARNING: couldn't match sid (%s) with requested ids\n", sidstr)); + TALLOC_FREE(sidstr); + continue; + } + + if ( ! string_to_sid(map->sid, sidstr)) { + DEBUG(2, ("ERROR: Invalid SID on entry\n")); + TALLOC_FREE(sidstr); + continue; + } + TALLOC_FREE(sidstr); + + /* mapped */ + map->mapped = True; + + DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_static(map->sid), (unsigned long)map->xid.id, map->xid.type)); + } + + /* free the ldap results */ + if (result) { + ldap_msgfree(result); + result = NULL; + } + + if (multi && ids[idx]) { /* still some values to map */ + goto again; + } + + ret = NT_STATUS_OK; + +done: + talloc_free(memctx); + return ret; +} + +/********************************** + lookup a set of sids. +**********************************/ + +/* this function searches up to IDMAP_LDAP_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_LDAP_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_ldap_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids) +{ + NTSTATUS ret; + TALLOC_CTX *memctx; + struct idmap_ldap_context *ctx; + LDAPMessage *result = NULL; + const char *uidNumber; + const char *gidNumber; + const char **attr_list; + char *filter = NULL; + BOOL multi = False; + int idx = 0; + int bidx = 0; + int count; + int rc; + int i; + + ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context); + + memctx = talloc_new(ctx); + if ( ! memctx) { + DEBUG(0, ("Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + uidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER); + gidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER); + + attr_list = get_attr_list(ctx, sidmap_attr_list); + + if ( ! ids[1]) { + /* if we are requested just one mapping use the simple filter */ + + filter = talloc_asprintf(memctx, "(&(objectClass=%s)(%s=%s))", + LDAP_OBJ_IDMAP_ENTRY, + LDAP_ATTRIBUTE_SID, + sid_string_static(ids[0]->sid)); + CHECK_ALLOC_DONE(filter); + DEBUG(10, ("Filter: [%s]\n", filter)); + } else { + /* multiple mappings */ + multi = True; + } + +again: + if (multi) { + + TALLOC_FREE(filter); + filter = talloc_asprintf(memctx, "(&(objectClass=%s)(|", LDAP_OBJ_IDMAP_ENTRY); + CHECK_ALLOC_DONE(filter); + + bidx = idx; + for (i = 0; (i < IDMAP_LDAP_MAX_IDS) && ids[idx]; i++, idx++) { + filter = talloc_asprintf_append(filter, "(%s=%s)", + LDAP_ATTRIBUTE_SID, + sid_string_static(ids[idx]->sid)); + CHECK_ALLOC_DONE(filter); + } + filter = talloc_asprintf_append(filter, "))"); + CHECK_ALLOC_DONE(filter); + DEBUG(10, ("Filter: [%s]", filter)); + } else { + bidx = 0; + idx = 1; + } + + rc = smbldap_search(ctx->smbldap_state, ctx->suffix, LDAP_SCOPE_SUBTREE, + filter, attr_list, 0, &result); + + if (rc != LDAP_SUCCESS) { + DEBUG(3,("Failure looking up sids (%s)\n", ldap_err2string(rc))); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + count = ldap_count_entries(ctx->smbldap_state->ldap_struct, result); + + if (count == 0) { + DEBUG(10, ("NO SIDs found\n")); + } + + for (i = 0; i < count; i++) { + LDAPMessage *entry = NULL; + char *sidstr = NULL; + char *tmp = NULL; + enum id_type type; + struct id_map *map; + DOM_SID sid; + uint32_t id; + + if (i == 0) { /* first entry */ + entry = ldap_first_entry(ctx->smbldap_state->ldap_struct, result); + } else { /* following ones */ + entry = ldap_next_entry(ctx->smbldap_state->ldap_struct, entry); + } + + /* first check if the SID is present */ + sidstr = smbldap_talloc_single_attribute( + ctx->smbldap_state->ldap_struct, + entry, LDAP_ATTRIBUTE_SID, memctx); + if ( ! sidstr) { /* no sid ??, skip entry */ + DEBUG(2, ("WARNING SID not found on entry\n")); + continue; + } + + if ( ! string_to_sid(&sid, sidstr)) { + DEBUG(2, ("ERROR: Invalid SID on entry\n")); + TALLOC_FREE(sidstr); + continue; + } + + map = find_map_by_sid(&ids[bidx], &sid); + if (!map) { + DEBUG(2, ("WARNING: couldn't find entry sid (%s) in ids", sidstr)); + TALLOC_FREE(sidstr); + continue; + } + + TALLOC_FREE(sidstr); + + /* now try to see if it is a uid, if not try with a gid + * (gid is more common, but in case both uidNumber and + * gidNumber are returned the SID is mapped to the uid not the gid) */ + type = ID_TYPE_UID; + tmp = smbldap_talloc_single_attribute( + ctx->smbldap_state->ldap_struct, + entry, uidNumber, memctx); + if ( ! tmp) { + type = ID_TYPE_GID; + tmp = smbldap_talloc_single_attribute( + ctx->smbldap_state->ldap_struct, + entry, gidNumber, memctx); + } + if ( ! tmp) { /* no ids ?? */ + DEBUG(5, ("no uidNumber, nor gidNumber attributes found\n")); + continue; + } + + id = strtoul(tmp, NULL, 10); + 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)); + TALLOC_FREE(tmp); + continue; + } + TALLOC_FREE(tmp); + + /* 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)); + } + + /* free the ldap results */ + if (result) { + ldap_msgfree(result); + result = NULL; + } + + if (multi && ids[idx]) { /* still some values to map */ + goto again; + } + + ret = NT_STATUS_OK; + +done: + talloc_free(memctx); + return ret; +} + +/********************************** + set a mapping. +**********************************/ + +/* TODO: change this: This function cannot be called to modify a mapping, only set a new one */ + +static NTSTATUS idmap_ldap_set_mapping(struct idmap_domain *dom, const struct id_map *map) +{ + NTSTATUS ret; + TALLOC_CTX *memctx; + struct idmap_ldap_context *ctx; + LDAPMessage *entry = NULL; + LDAPMod **mods = NULL; + const char *type; + char *id_str; + char *sid; + char *dn; + int rc = -1; + + ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context); + + switch(map->xid.type) { + case ID_TYPE_UID: + type = get_attr_key2string(sidmap_attr_list, LDAP_ATTR_UIDNUMBER); + break; + + case ID_TYPE_GID: + type = get_attr_key2string(sidmap_attr_list, LDAP_ATTR_GIDNUMBER); + break; + + default: + return NT_STATUS_INVALID_PARAMETER; + } + + memctx = talloc_new(ctx); + if ( ! memctx) { + DEBUG(0, ("Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + id_str = talloc_asprintf(memctx, "%lu", (unsigned long)map->xid.id); + CHECK_ALLOC_DONE(id_str); + + sid = talloc_strdup(memctx, sid_string_static(map->sid)); + CHECK_ALLOC_DONE(sid); + + dn = talloc_asprintf(memctx, "%s=%s,%s", + get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID), + sid, + ctx->suffix); + CHECK_ALLOC_DONE(dn); + + smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_IDMAP_ENTRY); + + smbldap_make_mod(ctx->smbldap_state->ldap_struct, entry, &mods, type, id_str); + + smbldap_make_mod(ctx->smbldap_state->ldap_struct, entry, &mods, + get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID), sid); + + if ( ! mods) { + DEBUG(2, ("ERROR: No mods?\n")); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + /* TODO: remove conflicting mappings! */ + + smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_SID_ENTRY); + + DEBUG(10, ("Set DN %s (%s -> %s)\n", dn, sid, id_str)); + + rc = smbldap_add(ctx->smbldap_state, dn, mods); + ldap_mods_free(mods, True); + + if (rc != LDAP_SUCCESS) { + char *ld_error = NULL; + ldap_get_option(ctx->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error); + DEBUG(0,("ldap_set_mapping_internals: Failed to add %s to %lu mapping [%s]\n", + sid, (unsigned long)map->xid.id, type)); + DEBUG(0, ("ldap_set_mapping_internals: Error was: %s (%s)\n", + ld_error ? ld_error : "(NULL)", ldap_err2string (rc))); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + DEBUG(10,("ldap_set_mapping: Successfully created mapping from %s to %lu [%s]\n", + sid, (unsigned long)map->xid.id, type)); + + ret = NT_STATUS_OK; + +done: + talloc_free(memctx); + return ret; +} + +/********************************** + remove a mapping. +**********************************/ + +static NTSTATUS idmap_ldap_remove_mapping(struct idmap_domain *dom, const struct id_map *map) +{ + return NT_STATUS_UNSUCCESSFUL; +} + +/********************************** + Close the idmap ldap instance +**********************************/ + +static NTSTATUS idmap_ldap_close(struct idmap_domain *dom) +{ + struct idmap_ldap_context *ctx; + + if (dom->private_data) { + ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context); + + talloc_free(ctx); + dom->private_data = NULL; + } + + return NT_STATUS_OK; +} + +static struct idmap_methods idmap_ldap_methods = { + + .init = idmap_ldap_db_init, + .unixids_to_sids = idmap_ldap_unixids_to_sids, + .sids_to_unixids = idmap_ldap_sids_to_unixids, + .set_mapping = idmap_ldap_set_mapping, + .remove_mapping = idmap_ldap_remove_mapping, + /* .dump_data = TODO */ + .close_fn = idmap_ldap_close +}; + +static struct idmap_alloc_methods idmap_ldap_alloc_methods = { + + .init = idmap_ldap_alloc_init, + .allocate_id = idmap_ldap_allocate_id, + .get_id_hwm = idmap_ldap_get_hwm, + .set_id_hwm = idmap_ldap_set_hwm, + .close_fn = idmap_ldap_alloc_close, + /* .dump_data = TODO */ +}; + +NTSTATUS idmap_alloc_ldap_init(void) +{ + return smb_register_idmap_alloc(SMB_IDMAP_INTERFACE_VERSION, "ldap", &idmap_ldap_alloc_methods); +} + +NTSTATUS idmap_ldap_init(void) +{ + NTSTATUS ret; + + /* FIXME: bad hack to actually register also the alloc_ldap module without changining configure.in */ + ret = idmap_alloc_ldap_init(); + if (! NT_STATUS_IS_OK(ret)) { + return ret; + } + return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ldap", &idmap_ldap_methods); +} + diff --git a/source3/nsswitch/idmap_nss.c b/source3/nsswitch/idmap_nss.c new file mode 100644 index 0000000000..2748141d3b --- /dev/null +++ b/source3/nsswitch/idmap_nss.c @@ -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); +} diff --git a/source3/nsswitch/idmap_passdb.c b/source3/nsswitch/idmap_passdb.c new file mode 100644 index 0000000000..fdb14d6979 --- /dev/null +++ b/source3/nsswitch/idmap_passdb.c @@ -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); +} diff --git a/source3/nsswitch/idmap_rid.c b/source3/nsswitch/idmap_rid.c new file mode 100644 index 0000000000..55b04df9aa --- /dev/null +++ b/source3/nsswitch/idmap_rid.c @@ -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); +} + diff --git a/source3/nsswitch/idmap_tdb.c b/source3/nsswitch/idmap_tdb.c new file mode 100644 index 0000000000..4d70986b84 --- /dev/null +++ b/source3/nsswitch/idmap_tdb.c @@ -0,0 +1,1213 @@ +/* + Unix SMB/CIFS implementation. + + idmap TDB backend + + Copyright (C) Tim Potter 2000 + Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003 + Copyright (C) Jeremy Allison 2006 + Copyright (C) Simo Sorce 2003-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 + +/* High water mark keys */ +#define HWM_GROUP "GROUP HWM" +#define HWM_USER "USER HWM" + +static struct idmap_tdb_state { + + /* User and group id pool */ + uid_t low_uid, high_uid; /* Range of uids to allocate */ + gid_t low_gid, high_gid; /* Range of gids to allocate */ + +} idmap_tdb_state; + +/***************************************************************************** + 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; +} + +/***************************************************************************** + Convert the idmap database from an older version. +*****************************************************************************/ + +static BOOL idmap_tdb_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, ("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 = idmap_tdb_state.low_uid; + } + + if (tdb_store_int32(idmap_tdb, HWM_USER, wm) == -1) { + DEBUG(0, ("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 = idmap_tdb_state.low_gid; + } + + if (tdb_store_int32(idmap_tdb, HWM_GROUP, wm) == -1) { + DEBUG(0, ("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, ("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 idmap_tdb_upgrade(TALLOC_CTX *ctx, const char *tdbfile) +{ + char *backup_name; + + DEBUG(0, ("Upgrading winbindd_idmap.tdb from an old version\n")); + + backup_name = talloc_asprintf(ctx, "%s.bak", tdbfile); + if ( ! backup_name) { + DEBUG(0, ("Out of memory!\n")); + return False; + } + + if (backup_tdb(tdbfile, backup_name, 0) != 0) { + DEBUG(0, ("Could not backup idmap database\n")); + talloc_free(backup_name); + return False; + } + + talloc_free(backup_name); + return idmap_tdb_convert(tdbfile); +} + +/* WARNING: We can't open a tdb twice inthe same process, for that reason + * I'm going to use a hack with open ref counts to open the winbindd_idmap.tdb + * only once. We will later decide whether to split the db in multiple files + * or come up with a better solution to share them. */ + +static TDB_CONTEXT *idmap_tdb_common_ctx; +static int idmap_tdb_open_ref_count = 0; + +static NTSTATUS idmap_tdb_open_db(TALLOC_CTX *memctx, TDB_CONTEXT **tdbctx) +{ + NTSTATUS ret; + TALLOC_CTX *ctx; + SMB_STRUCT_STAT stbuf; + char *tdbfile = NULL; + int32 version; + BOOL tdb_is_new = False; + + if (idmap_tdb_open_ref_count) { /* the tdb has already been opened */ + idmap_tdb_open_ref_count++; + *tdbctx = idmap_tdb_common_ctx; + return NT_STATUS_OK; + } + + /* use our own context here */ + ctx = talloc_new(memctx); + if (!ctx) { + DEBUG(0, ("Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + /* use the old database if present */ + tdbfile = talloc_strdup(ctx, lock_path("winbindd_idmap.tdb")); + if (!tdbfile) { + DEBUG(0, ("Out of memory!\n")); + ret = NT_STATUS_NO_MEMORY; + goto done; + } + + if (!file_exist(tdbfile, &stbuf)) { + tdb_is_new = True; + } + + DEBUG(10,("Opening tdbfile %s\n", tdbfile )); + + /* Open idmap repository */ + if (!(idmap_tdb_common_ctx = tdb_open_log(tdbfile, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0644))) { + DEBUG(0, ("Unable to open idmap database\n")); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + 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_common_ctx, "IDMAP_VERSION", IDMAP_VERSION); + } + + /* check against earlier versions */ + version = tdb_fetch_int32(idmap_tdb_common_ctx, "IDMAP_VERSION"); + if (version != IDMAP_VERSION) { + + /* backup_tdb expects the tdb not to be open */ + tdb_close(idmap_tdb_common_ctx); + + if ( ! idmap_tdb_upgrade(ctx, tdbfile)) { + + DEBUG(0, ("Unable to open idmap database, it's in an old formati, and upgrade failed!\n")); + ret = NT_STATUS_INTERNAL_DB_ERROR; + goto done; + } + + /* Re-Open idmap repository */ + if (!(idmap_tdb_common_ctx = tdb_open_log(tdbfile, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0644))) { + DEBUG(0, ("Unable to open idmap database\n")); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + } + + *tdbctx = idmap_tdb_common_ctx; + idmap_tdb_open_ref_count++; + ret = NT_STATUS_OK; + +done: + talloc_free(ctx); + return ret; +} + + /* NEVER use tdb_close() except for the conversion routines that are guaranteed + * to run only when the database is opened the first time, always use this function. */ + +BOOL idmap_tdb_tdb_close(TDB_CONTEXT *tdbctx) +{ + if (tdbctx != idmap_tdb_common_ctx) { + DEBUG(0, ("ERROR: Invalid tdb context!")); + return False; + } + + idmap_tdb_open_ref_count--; + if (idmap_tdb_open_ref_count) { + return True; + } + + return tdb_close(idmap_tdb_common_ctx); +} + +/********************************************************************** + IDMAP ALLOC TDB BACKEND +**********************************************************************/ + +static TDB_CONTEXT *idmap_alloc_tdb; + +/********************************** + Initialise idmap alloc database. +**********************************/ + +static NTSTATUS idmap_tdb_alloc_init( const char *params ) +{ + NTSTATUS ret; + TALLOC_CTX *ctx; + const char *range; + uint32_t low_id = 0; + uint32_t high_id = 0; + + /* use our own context here */ + ctx = talloc_new(NULL); + if (!ctx) { + DEBUG(0, ("Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + ret = idmap_tdb_open_db(ctx, &idmap_alloc_tdb); + if ( ! NT_STATUS_IS_OK(ret)) { + talloc_free(ctx); + return ret; + } + + talloc_free(ctx); + + /* load ranges */ + idmap_tdb_state.low_uid = 0; + idmap_tdb_state.high_uid = 0; + idmap_tdb_state.low_gid = 0; + idmap_tdb_state.high_gid = 0; + + range = lp_parm_const_string(-1, "idmap alloc config", "range", NULL); + if (range && range[0]) { + if (sscanf(range, "%u - %u", &low_id, &high_id) == 2) { + if (low_id < high_id) { + idmap_tdb_state.low_gid = idmap_tdb_state.low_uid = low_id; + idmap_tdb_state.high_gid = idmap_tdb_state.high_uid = high_id; + } else { + DEBUG(1, ("ERROR: invalid idmap alloc range [%s]", range)); + } + } else { + DEBUG(1, ("ERROR: invalid syntax for idmap alloc config:range [%s]", range)); + } + } + + /* Create high water marks for group and user id */ + if (lp_idmap_uid(&low_id, &high_id)) { + idmap_tdb_state.low_uid = low_id; + idmap_tdb_state.high_uid = high_id; + } + + if (lp_idmap_gid(&low_id, &high_id)) { + idmap_tdb_state.low_gid = low_id; + idmap_tdb_state.high_gid = high_id; + } + + if (idmap_tdb_state.high_uid <= idmap_tdb_state.low_uid) { + DEBUG(1, ("idmap uid range missing or invalid\n")); + DEBUGADD(1, ("idmap will be unable to map foreign SIDs\n")); + return NT_STATUS_UNSUCCESSFUL; + } else { + if (((low_id = tdb_fetch_int32(idmap_alloc_tdb, HWM_USER)) == -1) || + (low_id < idmap_tdb_state.low_uid)) { + if (tdb_store_int32(idmap_alloc_tdb, HWM_USER, idmap_tdb_state.low_uid) == -1) { + DEBUG(0, ("Unable to initialise user hwm in idmap database\n")); + return NT_STATUS_INTERNAL_DB_ERROR; + } + } + } + + if (idmap_tdb_state.high_gid <= idmap_tdb_state.low_gid) { + DEBUG(1, ("idmap gid range missing or invalid\n")); + DEBUGADD(1, ("idmap will be unable to map foreign SIDs\n")); + return NT_STATUS_UNSUCCESSFUL; + } else { + if (((low_id = tdb_fetch_int32(idmap_alloc_tdb, HWM_GROUP)) == -1) || + (low_id < idmap_tdb_state.low_gid)) { + if (tdb_store_int32(idmap_alloc_tdb, HWM_GROUP, idmap_tdb_state.low_gid) == -1) { + DEBUG(0, ("Unable to initialise group hwm in idmap database\n")); + return NT_STATUS_INTERNAL_DB_ERROR; + } + } + } + + return NT_STATUS_OK; +} + +/********************************** + Allocate a new id. +**********************************/ + +static NTSTATUS idmap_tdb_allocate_id(struct unixid *xid) +{ + BOOL ret; + const char *hwmkey; + const char *hwmtype; + uint32_t high_hwm; + uint32_t hwm; + + /* Get current high water mark */ + switch (xid->type) { + + case ID_TYPE_UID: + hwmkey = HWM_USER; + hwmtype = "UID"; + high_hwm = idmap_tdb_state.high_uid; + break; + + case ID_TYPE_GID: + hwmkey = HWM_GROUP; + hwmtype = "GID"; + high_hwm = idmap_tdb_state.high_gid; + break; + + default: + DEBUG(2, ("Invalid ID type (0x%x)\n", xid->type)); + return NT_STATUS_INVALID_PARAMETER; + } + + if ((hwm = tdb_fetch_int32(idmap_alloc_tdb, hwmkey)) == -1) { + return NT_STATUS_INTERNAL_DB_ERROR; + } + + /* check it is in the range */ + if (hwm > high_hwm) { + DEBUG(1, ("Fatal Error: %s range full!! (max: %lu)\n", + hwmtype, (unsigned long)high_hwm)); + return NT_STATUS_UNSUCCESSFUL; + } + + /* fetch a new id and increment it */ + ret = tdb_change_uint32_atomic(idmap_alloc_tdb, hwmkey, &hwm, 1); + if (!ret) { + DEBUG(1, ("Fatal error while fetching a new %s value\n!", hwmtype)); + return NT_STATUS_UNSUCCESSFUL; + } + + /* recheck it is in the range */ + if (hwm > high_hwm) { + DEBUG(1, ("Fatal Error: %s range full!! (max: %lu)\n", + hwmtype, (unsigned long)high_hwm)); + return NT_STATUS_UNSUCCESSFUL; + } + + xid->id = hwm; + DEBUG(10,("New %s = %d\n", hwmtype, hwm)); + + return NT_STATUS_OK; +} + +/********************************** + Get current highest id. +**********************************/ + +static NTSTATUS idmap_tdb_get_hwm(struct unixid *xid) +{ + const char *hwmkey; + const char *hwmtype; + uint32_t hwm; + uint32_t high_hwm; + + /* Get current high water mark */ + switch (xid->type) { + + case ID_TYPE_UID: + hwmkey = HWM_USER; + hwmtype = "UID"; + high_hwm = idmap_tdb_state.high_uid; + break; + + case ID_TYPE_GID: + hwmkey = HWM_GROUP; + hwmtype = "GID"; + high_hwm = idmap_tdb_state.high_gid; + break; + + default: + return NT_STATUS_INVALID_PARAMETER; + } + + if ((hwm = tdb_fetch_int32(idmap_alloc_tdb, hwmkey)) == -1) { + return NT_STATUS_INTERNAL_DB_ERROR; + } + + xid->id = hwm; + + /* Warn if it is out of range */ + if (hwm >= high_hwm) { + DEBUG(0, ("Warning: %s range full!! (max: %lu)\n", + hwmtype, (unsigned long)high_hwm)); + } + + return NT_STATUS_OK; +} + +/********************************** + Set high id. +**********************************/ + +static NTSTATUS idmap_tdb_set_hwm(struct unixid *xid) +{ + const char *hwmkey; + const char *hwmtype; + uint32_t hwm; + uint32_t high_hwm; + + /* Get current high water mark */ + switch (xid->type) { + + case ID_TYPE_UID: + hwmkey = HWM_USER; + hwmtype = "UID"; + high_hwm = idmap_tdb_state.high_uid; + break; + + case ID_TYPE_GID: + hwmkey = HWM_GROUP; + hwmtype = "GID"; + high_hwm = idmap_tdb_state.high_gid; + break; + + default: + return NT_STATUS_INVALID_PARAMETER; + } + + hwm = xid->id; + + if ((hwm = tdb_store_int32(idmap_alloc_tdb, hwmkey, hwm)) == -1) { + return NT_STATUS_INTERNAL_DB_ERROR; + } + + /* Warn if it is out of range */ + if (hwm >= high_hwm) { + DEBUG(0, ("Warning: %s range full!! (max: %lu)\n", + hwmtype, (unsigned long)high_hwm)); + } + + return NT_STATUS_OK; +} + +/********************************** + Close the alloc tdb +**********************************/ + +static NTSTATUS idmap_tdb_alloc_close(void) +{ + if (idmap_alloc_tdb) { + if (idmap_tdb_tdb_close(idmap_alloc_tdb) == 0) { + return NT_STATUS_OK; + } else { + return NT_STATUS_UNSUCCESSFUL; + } + } + return NT_STATUS_OK; +} + +/********************************************************************** + IDMAP MAPPING TDB BACKEND +**********************************************************************/ + +struct idmap_tdb_context { + TDB_CONTEXT *tdb; + uint32_t filter_low_id; + uint32_t filter_high_id; +}; + +/***************************** + Initialise idmap database. +*****************************/ + +static NTSTATUS idmap_tdb_db_init(struct idmap_domain *dom, const char *compat_params) +{ + NTSTATUS ret; + struct idmap_tdb_context *ctx; + char *config_option = NULL; + const char *range; + + ctx = talloc(dom, struct idmap_tdb_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; + } + + ret = idmap_tdb_open_db(ctx, &ctx->tdb); + if ( ! NT_STATUS_IS_OK(ret)) { + goto failed; + } + + range = lp_parm_const_string(-1, config_option, "range", NULL); + if (( ! range) || + (sscanf(range, "%u - %u", &ctx->filter_low_id, &ctx->filter_high_id) != 2) || + (ctx->filter_low_id > ctx->filter_high_id)) { + ctx->filter_low_id = 0; + ctx->filter_high_id = 0; + } + + dom->private_data = ctx; + + talloc_free(config_option); + return NT_STATUS_OK; + +failed: + talloc_free(ctx); + return ret; +} + +/********************************** + Single id to sid lookup function. +**********************************/ + +static NTSTATUS idmap_tdb_id_to_sid(struct idmap_tdb_context *ctx, struct id_map *map) +{ + NTSTATUS ret; + TDB_DATA key, data; + + if (!ctx || !map) { + return NT_STATUS_INVALID_PARAMETER; + } + + /* apply filters before checking */ + if ((ctx->filter_low_id && (map->xid.id < ctx->filter_low_id)) || + (ctx->filter_high_id && (map->xid.id > ctx->filter_high_id))) { + DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n", + map->xid.id, ctx->filter_low_id, ctx->filter_high_id)); + return NT_STATUS_NONE_MAPPED; + } + + switch (map->xid.type) { + + case ID_TYPE_UID: + key.dptr = talloc_asprintf(ctx, "UID %lu", (unsigned long)map->xid.id); + break; + + case ID_TYPE_GID: + key.dptr = talloc_asprintf(ctx, "GID %lu", (unsigned long)map->xid.id); + break; + + default: + DEBUG(2, ("INVALID unix ID type: 0x02%x\n", map->xid.type)); + return NT_STATUS_INVALID_PARAMETER; + } + + /* final SAFE_FREE safe */ + data.dptr = NULL; + + if (key.dptr == NULL) { + DEBUG(0, ("Out of memory!\n")); + ret = NT_STATUS_NO_MEMORY; + goto done; + } + + key.dsize = strlen(key.dptr) + 1; + + DEBUG(10,("Fetching record %s\n", key.dptr)); + + /* Check if the mapping exists */ + data = tdb_fetch(ctx->tdb, key); + + if (!data.dptr) { + DEBUG(10,("Record %s not found\n", key.dptr)); + ret = NT_STATUS_NONE_MAPPED; + goto done; + } + + if (!string_to_sid(map->sid, data.dptr)) { + DEBUG(10,("INVALID SID (%s) in record %s\n", + data.dptr, key.dptr)); + ret = NT_STATUS_INTERNAL_DB_ERROR; + goto done; + } + + DEBUG(10,("Found record %s -> %s\n", key.dptr, data.dptr)); + ret = NT_STATUS_OK; + +done: + SAFE_FREE(data.dptr); + talloc_free(key.dptr); + return ret; +} + +/********************************** + Single sid to id lookup function. +**********************************/ + +static NTSTATUS idmap_tdb_sid_to_id(struct idmap_tdb_context *ctx, struct id_map *map) +{ + NTSTATUS ret; + TDB_DATA key, data; + unsigned long rec_id = 0; + + if ((key.dptr = talloc_asprintf(ctx, "%s", sid_string_static(map->sid))) == NULL) { + DEBUG(0, ("Out of memory!\n")); + ret = NT_STATUS_NO_MEMORY; + goto done; + } + + key.dsize = strlen(key.dptr) + 1; + + DEBUG(10,("Fetching record %s\n", key.dptr)); + + /* Check if sid is present in database */ + data = tdb_fetch(ctx->tdb, key); + if (!data.dptr) { + DEBUG(10,("Record %s not found\n", key.dptr)); + ret = NT_STATUS_NONE_MAPPED; + goto done; + } + + /* What type of record is this ? */ + if (sscanf(data.dptr, "UID %lu", &rec_id) == 1) { /* Try a UID record. */ + map->xid.id = rec_id; + map->xid.type = ID_TYPE_UID; + DEBUG(10,("Found 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. */ + map->xid.id = rec_id; + map->xid.type = ID_TYPE_GID; + DEBUG(10,("Found gid record %s -> %s \n", key.dptr, data.dptr )); + ret = NT_STATUS_OK; + + } else { /* Unknown record type ! */ + DEBUG(2, ("Found INVALID record %s -> %s\n", key.dptr, data.dptr)); + ret = NT_STATUS_INTERNAL_DB_ERROR; + } + + SAFE_FREE(data.dptr); + + /* apply filters before returning result */ + if ((ctx->filter_low_id && (map->xid.id < ctx->filter_low_id)) || + (ctx->filter_high_id && (map->xid.id > ctx->filter_high_id))) { + DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n", + map->xid.id, ctx->filter_low_id, ctx->filter_high_id)); + ret = NT_STATUS_NONE_MAPPED; + } + +done: + talloc_free(key.dptr); + return ret; +} + +/********************************** + lookup a set of unix ids. +**********************************/ + +static NTSTATUS idmap_tdb_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids) +{ + struct idmap_tdb_context *ctx; + NTSTATUS ret; + int i; + + ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context); + + for (i = 0; ids[i]; i++) { + ret = idmap_tdb_id_to_sid(ctx, ids[i]); + if ( ! NT_STATUS_IS_OK(ret)) { + + /* if it is just a failed mapping continue */ + if (NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED)) { + + /* make sure it is marked as unmapped */ + ids[i]->mapped = False; + continue; + } + + /* some fatal error occurred, return immediately */ + goto done; + } + + /* all ok, id is mapped */ + ids[i]->mapped = True; + } + + ret = NT_STATUS_OK; + +done: + return ret; +} + +/********************************** + lookup a set of sids. +**********************************/ + +static NTSTATUS idmap_tdb_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids) +{ + struct idmap_tdb_context *ctx; + NTSTATUS ret; + int i; + + ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context); + + for (i = 0; ids[i]; i++) { + ret = idmap_tdb_sid_to_id(ctx, ids[i]); + if ( ! NT_STATUS_IS_OK(ret)) { + + /* if it is just a failed mapping continue */ + if (NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED)) { + + /* make sure it is marked as unmapped */ + ids[i]->mapped = False; + continue; + } + + /* some fatal error occurred, return immediately */ + goto done; + } + + /* all ok, id is mapped */ + ids[i]->mapped = True; + } + + ret = NT_STATUS_OK; + +done: + return ret; +} + +/********************************** + set a mapping. +**********************************/ + +static NTSTATUS idmap_tdb_set_mapping(struct idmap_domain *dom, const struct id_map *map) +{ + struct idmap_tdb_context *ctx; + NTSTATUS ret; + TDB_DATA ksid, kid, data; + + if (!map || !map->sid) { + return NT_STATUS_INVALID_PARAMETER; + } + + ksid.dptr = kid.dptr = data.dptr = NULL; + + /* TODO: should we filter a set_mapping using low/high filters ? */ + + ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context); + + switch (map->xid.type) { + + case ID_TYPE_UID: + kid.dptr = talloc_asprintf(ctx, "UID %lu", (unsigned long)map->xid.id); + break; + + case ID_TYPE_GID: + kid.dptr = talloc_asprintf(ctx, "GID %lu", (unsigned long)map->xid.id); + break; + + default: + DEBUG(2, ("INVALID unix ID type: 0x02%x\n", map->xid.type)); + return NT_STATUS_INVALID_PARAMETER; + } + + if (kid.dptr == NULL) { + DEBUG(0, ("ERROR: Out of memory!\n")); + ret = NT_STATUS_NO_MEMORY; + goto done; + } + kid.dsize = strlen(kid.dptr) + 1; + + if ((ksid.dptr = talloc_asprintf(ctx, "%s", sid_string_static(map->sid))) == NULL) { + DEBUG(0, ("Out of memory!\n")); + ret = NT_STATUS_NO_MEMORY; + goto done; + } + ksid.dsize = strlen(ksid.dptr) + 1; + + DEBUG(10, ("Storing %s <-> %s map\n", ksid.dptr, kid.dptr)); + + /* *DELETE* previous mappings if any. + * This is done both SID and [U|G]ID passed in */ + + /* Lock the record for this SID. */ + if (tdb_chainlock(ctx->tdb, ksid) != 0) { + DEBUG(10,("Failed to lock record %s. Error %s\n", + ksid.dptr, tdb_errorstr(ctx->tdb) )); + return NT_STATUS_UNSUCCESSFUL; + } + + data = tdb_fetch(ctx->tdb, ksid); + if (data.dptr) { + DEBUG(10, ("Deleting existing mapping %s <-> %s\n", data.dptr, ksid.dptr )); + tdb_delete(ctx->tdb, data); + tdb_delete(ctx->tdb, ksid); + SAFE_FREE(data.dptr); + } + + data = tdb_fetch(ctx->tdb, kid); + if (data.dptr) { + DEBUG(10,("Deleting existing mapping %s <-> %s\n", data.dptr, kid.dptr )); + tdb_delete(ctx->tdb, data); + tdb_delete(ctx->tdb, kid); + SAFE_FREE(data.dptr); + } + + if (tdb_store(ctx->tdb, ksid, kid, TDB_INSERT) == -1) { + DEBUG(0, ("Error storing SID -> ID: %s\n", tdb_errorstr(ctx->tdb))); + tdb_chainunlock(ctx->tdb, ksid); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + if (tdb_store(ctx->tdb, kid, ksid, TDB_INSERT) == -1) { + DEBUG(0, ("Error stroing ID -> SID: %s\n", tdb_errorstr(ctx->tdb))); + /* try to remove the previous stored SID -> ID map */ + tdb_delete(ctx->tdb, ksid); + tdb_chainunlock(ctx->tdb, ksid); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + tdb_chainunlock(ctx->tdb, ksid); + DEBUG(10,("Stored %s <-> %s\n", ksid.dptr, kid.dptr)); + ret = NT_STATUS_OK; + +done: + talloc_free(ksid.dptr); + talloc_free(kid.dptr); + SAFE_FREE(data.dptr); + return ret; +} + +/********************************** + remove a mapping. +**********************************/ + +static NTSTATUS idmap_tdb_remove_mapping(struct idmap_domain *dom, const struct id_map *map) +{ + struct idmap_tdb_context *ctx; + NTSTATUS ret; + TDB_DATA ksid, kid, data; + + if (!map || !map->sid) { + return NT_STATUS_INVALID_PARAMETER; + } + + ksid.dptr = kid.dptr = data.dptr = NULL; + + /* TODO: should we filter a remove_mapping using low/high filters ? */ + + ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context); + + switch (map->xid.type) { + + case ID_TYPE_UID: + kid.dptr = talloc_asprintf(ctx, "UID %lu", (unsigned long)map->xid.id); + break; + + case ID_TYPE_GID: + kid.dptr = talloc_asprintf(ctx, "GID %lu", (unsigned long)map->xid.id); + break; + + default: + DEBUG(2, ("INVALID unix ID type: 0x02%x\n", map->xid.type)); + return NT_STATUS_INVALID_PARAMETER; + } + + if (kid.dptr == NULL) { + DEBUG(0, ("ERROR: Out of memory!\n")); + ret = NT_STATUS_NO_MEMORY; + goto done; + } + kid.dsize = strlen(kid.dptr) + 1; + + if ((ksid.dptr = talloc_asprintf(ctx, "%s", sid_string_static(map->sid))) == NULL) { + DEBUG(0, ("Out of memory!\n")); + ret = NT_STATUS_NO_MEMORY; + goto done; + } + ksid.dsize = strlen(ksid.dptr) + 1; + + DEBUG(10, ("Checking %s <-> %s map\n", ksid.dptr, kid.dptr)); + + /* Lock the record for this SID. */ + if (tdb_chainlock(ctx->tdb, ksid) != 0) { + DEBUG(10,("Failed to lock record %s. Error %s\n", + ksid.dptr, tdb_errorstr(ctx->tdb) )); + return NT_STATUS_UNSUCCESSFUL; + } + + /* Check if sid is present in database */ + data = tdb_fetch(ctx->tdb, ksid); + if (!data.dptr) { + DEBUG(10,("Record %s not found\n", ksid.dptr)); + tdb_chainunlock(ctx->tdb, ksid); + ret = NT_STATUS_NONE_MAPPED; + goto done; + } + + /* Check if sid is mapped to the specified ID */ + if ((data.dsize != kid.dsize) || + (memcmp(data.dptr, kid.dptr, data.dsize) != 0)) { + DEBUG(10,("Specified SID does not map to specified ID\n")); + DEBUGADD(10,("Actual mapping is %s -> %s\n", ksid.dptr, data.dptr)); + tdb_chainunlock(ctx->tdb, ksid); + ret = NT_STATUS_NONE_MAPPED; + goto done; + } + + DEBUG(10, ("Removing %s <-> %s map\n", ksid.dptr, kid.dptr)); + + /* Delete previous mappings. */ + + data = tdb_fetch(ctx->tdb, ksid); + if (data.dptr) { + DEBUG(10, ("Deleting existing mapping %s -> %s\n", ksid.dptr, kid.dptr )); + tdb_delete(ctx->tdb, ksid); + SAFE_FREE(data.dptr); + } + + data = tdb_fetch(ctx->tdb, kid); + if (data.dptr) { + DEBUG(10,("Deleting existing mapping %s -> %s\n", kid.dptr, ksid.dptr )); + tdb_delete(ctx->tdb, kid); + SAFE_FREE(data.dptr); + } + + tdb_chainunlock(ctx->tdb, ksid); + ret = NT_STATUS_OK; + +done: + talloc_free(ksid.dptr); + talloc_free(kid.dptr); + SAFE_FREE(data.dptr); + return ret; +} + +/********************************** + Close the idmap tdb instance +**********************************/ + +static NTSTATUS idmap_tdb_close(struct idmap_domain *dom) +{ + struct idmap_tdb_context *ctx; + + if (dom->private_data) { + ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context); + + if (idmap_tdb_tdb_close(ctx->tdb) == 0) { + return NT_STATUS_OK; + } else { + return NT_STATUS_UNSUCCESSFUL; + } + } + return NT_STATUS_OK; +} + +struct dump_data { + TALLOC_CTX *memctx; + struct id_map **maps; + int *num_maps; + NTSTATUS ret; +}; + +static int idmap_tdb_dump_one_entry(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA value, void *pdata) +{ + struct dump_data *data = talloc_get_type(pdata, struct dump_data); + struct id_map *maps; + int num_maps = *data->num_maps; + + /* ignore any record but the ones with a SID as key */ + if (strncmp(key.dptr, "S-", 2) == 0) { + + maps = talloc_realloc(NULL, *data->maps, struct id_map, num_maps+1); + if ( ! maps) { + DEBUG(0, ("Out of memory!\n")); + data->ret = NT_STATUS_NO_MEMORY; + return -1; + } + *data->maps = maps; + maps[num_maps].sid = talloc(maps, DOM_SID); + if ( ! maps[num_maps].sid) { + DEBUG(0, ("Out of memory!\n")); + data->ret = NT_STATUS_NO_MEMORY; + return -1; + } + + if (!string_to_sid(maps[num_maps].sid, key.dptr)) { + DEBUG(10,("INVALID record %s\n", key.dptr)); + /* continue even with errors */ + return 0; + } + + /* Try a UID record. */ + if (sscanf(value.dptr, "UID %u", &(maps[num_maps].xid.id)) == 1) { + maps[num_maps].xid.type = ID_TYPE_UID; + maps[num_maps].mapped = True; + *data->num_maps = num_maps + 1; + + /* Try a GID record. */ + } else + if (sscanf(value.dptr, "GID %u", &(maps[num_maps].xid.id)) == 1) { + maps[num_maps].xid.type = ID_TYPE_GID; + maps[num_maps].mapped = True; + *data->num_maps = num_maps + 1; + + /* Unknown record type ! */ + } else { + DEBUG(2, ("Found INVALID record %s -> %s\n", key.dptr, value.dptr)); + /* do not increment num_maps */ + } + } + + return 0; +} + +/********************************** + Dump all mappings out +**********************************/ + +static NTSTATUS idmap_tdb_dump_data(struct idmap_domain *dom, struct id_map **maps, int *num_maps) +{ + struct idmap_tdb_context *ctx; + struct dump_data *data; + NTSTATUS ret = NT_STATUS_OK; + + ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context); + + data = talloc_zero(ctx, struct dump_data); + if ( ! data) { + DEBUG(0, ("Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + data->maps = maps; + data->num_maps = num_maps; + data->ret = NT_STATUS_OK; + + tdb_traverse(ctx->tdb, idmap_tdb_dump_one_entry, data); + + if ( ! NT_STATUS_IS_OK(data->ret)) { + ret = data->ret; + } + + talloc_free(data); + return ret; +} + +static struct idmap_methods db_methods = { + + .init = idmap_tdb_db_init, + .unixids_to_sids = idmap_tdb_unixids_to_sids, + .sids_to_unixids = idmap_tdb_sids_to_unixids, + .set_mapping = idmap_tdb_set_mapping, + .remove_mapping = idmap_tdb_remove_mapping, + .dump_data = idmap_tdb_dump_data, + .close_fn = idmap_tdb_close +}; + +static struct idmap_alloc_methods db_alloc_methods = { + + .init = idmap_tdb_alloc_init, + .allocate_id = idmap_tdb_allocate_id, + .get_id_hwm = idmap_tdb_get_hwm, + .set_id_hwm = idmap_tdb_set_hwm, + .close_fn = idmap_tdb_alloc_close +}; + +NTSTATUS idmap_alloc_tdb_init(void) +{ + return smb_register_idmap_alloc(SMB_IDMAP_INTERFACE_VERSION, "tdb", &db_alloc_methods); +} + +NTSTATUS idmap_tdb_init(void) +{ + NTSTATUS ret; + + /* FIXME: bad hack to actually register also the alloc_tdb module without changining configure.in */ + ret = idmap_alloc_tdb_init(); + if (! NT_STATUS_IS_OK(ret)) { + return ret; + } + return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "tdb", &db_methods); +} diff --git a/source3/nsswitch/idmap_util.c b/source3/nsswitch/idmap_util.c new file mode 100644 index 0000000000..8199ebbbd8 --- /dev/null +++ b/source3/nsswitch/idmap_util.c @@ -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] = ↦ + 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] = ↦ + 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] = ↦ + 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] = ↦ + 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; +} diff --git a/source3/sam/nss_info.c b/source3/nsswitch/nss_info.c index 6d01916754..6d01916754 100644 --- a/source3/sam/nss_info.c +++ b/source3/nsswitch/nss_info.c diff --git a/source3/nsswitch/wb_client.c b/source3/nsswitch/wb_client.c index 77e2645b74..87eab6438c 100644 --- a/source3/nsswitch/wb_client.c +++ b/source3/nsswitch/wb_client.c @@ -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. */ diff --git a/source3/nsswitch/winbindd.c b/source3/nsswitch/winbindd.c index 047b6c3b85..70875e08cb 100644 --- a/source3/nsswitch/winbindd.c +++ b/source3/nsswitch/winbindd.c @@ -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 diff --git a/source3/nsswitch/winbindd.h b/source3/nsswitch/winbindd.h index 4063e6b66b..2d46be0908 100644 --- a/source3/nsswitch/winbindd.h +++ b/source3/nsswitch/winbindd.h @@ -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; diff --git a/source3/nsswitch/winbindd_async.c b/source3/nsswitch/winbindd_async.c index 607a9947ea..4debe74155 100644 --- a/source3/nsswitch/winbindd_async.c +++ b/source3/nsswitch/winbindd_async.c @@ -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); - - do_async(mem_ctx, idmap_child(), &request, idmap_set_mapping_recv, + 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, 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 (*cont)(void *priv, BOOL succ) = (void (*)(void *, BOOL))c; + + 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_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_set_hwm(struct winbindd_domain *domain, + struct winbindd_cli_state *state) +{ + struct unixid xid; + NTSTATUS result; + + DEBUG(3, ("[%5lu]: dual_set_hwm\n", (unsigned long)state->pid)); + + 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; + } + return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR; +} + +static void winbindd_sids2xids_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 *, int) = + (void (*)(void *, BOOL, void *, int))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 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_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_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_sid2uid(struct winbindd_domain *domain, +enum winbindd_result winbindd_dual_sids2xids(struct winbindd_domain *domain, struct winbindd_cli_state *state) { - DOM_SID sid; + DOM_SID *sids; + struct unixid *xids; + struct id_map **ids; NTSTATUS result; + int num, i; - DEBUG(3, ("[%5lu]: sid to uid %s\n", (unsigned long)state->pid, - state->request.data.dual_sid2id.sid)); + DEBUG(3, ("[%5lu]: sids to unix ids\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)); + 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]; + } - /* Find uid for this sid and return it, possibly ask the slow remote - * idmap */ + result = idmap_sids_to_unixids(ids); - result = idmap_sid_to_uid(&sid, &(state->response.data.uid), - state->request.data.dual_sid2id.alloc ? - 0 : IDMAP_FLAG_QUERY_ONLY); + if (NT_STATUS_IS_OK(result)) { - return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR; + 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 idmap_sid2uid_recv(TALLOC_CTX *mem_ctx, BOOL success, +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,12 +502,31 @@ 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, +static void winbindd_sid2gid_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, gid_t gid) = + (void (*)(void *, BOOL, gid_t))c; + + if (!success) { + DEBUG(5, ("Could not trigger sid2gid\n")); + cont(private_data, False, 0); + return; + } + + if (response->result != WINBINDD_OK) { + DEBUG(5, ("sid2gid returned an error\n")); + cont(private_data, False, 0); + return; + } -void idmap_sid2gid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid, BOOL alloc, + 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) { @@ -373,8 +538,7 @@ void idmap_sid2gid_async(TALLOC_CTX *mem_ctx, const DOM_SID *sid, BOOL alloc, 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, + do_async(mem_ctx, idmap_child(), &request, winbindd_sid2gid_recv, (void *)cont, private_data); } @@ -393,47 +557,15 @@ enum winbindd_result winbindd_dual_sid2gid(struct winbindd_domain *domain, 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 */ + /* Find gid for this sid and return it, possibly ask the slow remote idmap */ - if ( !NT_STATUS_IS_OK(result) ) { - if ( sid_to_gid( &sid, &(state->response.data.gid) ) ) { - result = NT_STATUS_OK; - } - } + 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 idmap_sid2gid_recv(TALLOC_CTX *mem_ctx, BOOL success, - struct winbindd_response *response, - void *c, void *private_data) -{ - void (*cont)(void *priv, BOOL succ, gid_t gid) = - (void (*)(void *, BOOL, gid_t))c; - - if (!success) { - DEBUG(5, ("Could not trigger sid2gid\n")); - cont(private_data, False, 0); - return; - } - - if (response->result != WINBINDD_OK) { - DEBUG(5, ("sid2gid returned an error\n")); - cont(private_data, False, 0); - return; - } - - cont(private_data, True, response->data.gid); -} - 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; +} + diff --git a/source3/nsswitch/winbindd_dual.c b/source3/nsswitch/winbindd_dual.c index 1a1afcb404..71ab7a1ae2 100644 --- a/source3/nsswitch/winbindd_dual.c +++ b/source3/nsswitch/winbindd_dual.c @@ -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" }, diff --git a/source3/nsswitch/winbindd_group.c b/source3/nsswitch/winbindd_group.c index aac8a9aac3..18a7be29de 100644 --- a/source3/nsswitch/winbindd_group.c +++ b/source3/nsswitch/winbindd_group.c @@ -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; diff --git a/source3/nsswitch/winbindd_nss.h b/source3/nsswitch/winbindd_nss.h index 27138749f0..25279c5650 100644 --- a/source3/nsswitch/winbindd_nss.h +++ b/source3/nsswitch/winbindd_nss.h @@ -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; diff --git a/source3/nsswitch/winbindd_sid.c b/source3/nsswitch/winbindd_sid.c index b572771a25..13b2cd0555 100644 --- a/source3/nsswitch/winbindd_sid.c +++ b/source3/nsswitch/winbindd_sid.c @@ -167,12 +167,25 @@ 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); +static void sid2uid_recv(void *private_data, BOOL success, uid_t uid) +{ + struct winbindd_cli_state *state = + talloc_get_type_abort(private_data, struct winbindd_cli_state); + + if (!success) { + DEBUG(5, ("Could not convert sid %s\n", + state->request.data.sid)); + request_error(state); + return; + } + + state->response.data.uid = uid; + request_ok(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'; @@ -180,12 +193,6 @@ void winbindd_sid_to_uid(struct winbindd_cli_state *state) 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)); @@ -193,20 +200,14 @@ void winbindd_sid_to_uid(struct winbindd_cli_state *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; - } - + /* always use the async interface (may block) */ winbindd_sid2uid_async(state->mem_ctx, &sid, sid2uid_recv, state); } -static void sid2uid_recv(void *private_data, BOOL success, uid_t uid) +/* 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 = talloc_get_type_abort(private_data, struct winbindd_cli_state); @@ -218,19 +219,13 @@ static void sid2uid_recv(void *private_data, BOOL success, uid_t uid) return; } - state->response.data.uid = uid; + state->response.data.gid = gid; 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) { DOM_SID sid; - NTSTATUS result; /* Ensure null termination */ state->request.data.sid[sizeof(state->request.data.sid)-1]='\0'; @@ -238,12 +233,6 @@ void winbindd_sid_to_gid(struct winbindd_cli_state *state) DEBUG(3, ("[%5lu]: sid to gid %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,231 +240,145 @@ 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; - } - + /* always use the async interface (may block) */ winbindd_sid2gid_async(state->mem_ctx, &sid, sid2gid_recv, state); } -static void sid2gid_recv(void *private_data, BOOL success, gid_t gid) +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 sid %s\n", - state->request.data.sid)); + DEBUG(5, ("Could not convert sids to xids\n")); request_error(state); return; } - state->response.data.gid = gid; + state->response.extra_data.data = data; + state->response.length = sizeof(state->response) + len; 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_sids_to_unixids(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)); + DEBUG(3, ("[%5lu]: sids to xids\n", (unsigned long)state->pid)); - if (idmap_proxyonly()) { - DEBUG(8, ("IDMAP proxy only\n")); - request_error(state); - return; - } - - status = idmap_uid_to_sid(&sid, state->request.data.uid, - 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_USER; - request_ok(state); - return; - } - - winbindd_uid2sid_async(state->mem_ctx, state->request.data.uid, uid2sid_recv, state); + winbindd_sids2xids_async(state->mem_ctx, + state->request.extra_data.data, + state->request.extra_len, + sids2xids_recv, state); } -static void uid2sid_recv(void *private_data, BOOL success, const char *sid) +static void set_mapping_recv(void *private_data, BOOL success) { struct winbindd_cli_state *state = - (struct winbindd_cli_state *)private_data; - struct uid2sid_state *uid2sid_state; + talloc_get_type_abort(private_data, struct winbindd_cli_state); - if (success) { - DEBUG(10,("uid2sid: uid %lu has sid %s\n", - (unsigned long)(state->request.data.uid), sid)); - fstrcpy(state->response.data.sid.sid, sid); - state->response.data.sid.type = SID_NAME_USER; - request_ok(state); + if (!success) { + DEBUG(5, ("Could not set sid mapping\n")); + request_error(state); return; } - /* preexisitng mapping not found go on */ + request_ok(state); +} - if (is_in_uid_range(state->request.data.uid)) { - /* This is winbind's, so we should better have succeeded - * above. */ - request_error(state); - return; - } +void winbindd_set_mapping(struct winbindd_cli_state *state) +{ + struct id_map map; + DOM_SID sid; - /* The only chance that this is correct is that winbind trusted - * domains only = yes, and the user exists in nss and the domain. */ + DEBUG(3, ("[%5lu]: set id map\n", (unsigned long)state->pid)); - if (!lp_winbind_trusted_domains_only()) { + if ( ! state->privileged) { + DEBUG(0, ("Only root is allowed to set mappings!\n")); request_error(state); return; } - uid2sid_state = TALLOC_ZERO_P(state->mem_ctx, struct uid2sid_state); - if (uid2sid_state == NULL) { - DEBUG(0, ("talloc failed\n")); + 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; } - uid2sid_state->cli_state = state; - uid2sid_state->uid = state->request.data.uid; + map.sid = &sid; + map.xid.id = state->request.data.dual_idmapset.id; + map.xid.type = state->request.data.dual_idmapset.type; - winbindd_uid2name_async(state->mem_ctx, state->request.data.uid, - uid2sid_uid2name_recv, uid2sid_state); + winbindd_set_mapping_async(state->mem_ctx, &map, + set_mapping_recv, state); } -static void uid2sid_uid2name_recv(void *private_data, BOOL success, - const char *username) +static void set_hwm_recv(void *private_data, BOOL success) { - struct uid2sid_state *state = - talloc_get_type_abort(private_data, struct uid2sid_state); - - DEBUG(10, ("uid2sid: uid %lu has name %s\n", - (unsigned long)state->uid, username)); - - fstrcpy(state->name, username); + struct winbindd_cli_state *state = + talloc_get_type_abort(private_data, struct winbindd_cli_state); if (!success) { - request_error(state->cli_state); + DEBUG(5, ("Could not set sid mapping\n")); + request_error(state); return; } - winbindd_lookupname_async(state->cli_state->mem_ctx, - find_our_domain()->name, username, - uid2sid_lookupname_recv, state); + request_ok(state); } -static void uid2sid_lookupname_recv(void *private_data, BOOL success, - const DOM_SID *sid, enum lsa_SidType type) +void winbindd_set_hwm(struct winbindd_cli_state *state) { - struct uid2sid_state *state = - talloc_get_type_abort(private_data, struct uid2sid_state); - unid_t id; + struct unixid xid; + + DEBUG(3, ("[%5lu]: set hwm\n", (unsigned long)state->pid)); - if ((!success) || (type != SID_NAME_USER)) { - request_error(state->cli_state); + if ( ! state->privileged) { + DEBUG(0, ("Only root is allowed to set mappings!\n")); + request_error(state); return; } - state->sid = *sid; - state->type = type; + xid.id = state->request.data.dual_idmapset.id; + xid.type = state->request.data.dual_idmapset.type; - id.uid = state->uid; - idmap_set_mapping_async(state->cli_state->mem_ctx, sid, id, ID_USERID, - uid2sid_idmap_set_mapping_recv, state ); + winbindd_set_hwm_async(state->mem_ctx, &xid, set_hwm_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); -} - -/* 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); +/* Convert a uid to a sid */ -void winbindd_gid_to_sid(struct winbindd_cli_state *state) +static void uid2sid_recv(void *private_data, BOOL success, const char *sid) { - DOM_SID sid; - NTSTATUS status; - - DEBUG(3, ("[%5lu]: gid to sid %lu\n", (unsigned long)state->pid, - (unsigned long)state->request.data.gid)); + struct winbindd_cli_state *state = + (struct winbindd_cli_state *)private_data; - if (idmap_proxyonly()) { - DEBUG(8, ("IDMAP proxy only\n")); - request_error(state); + if (success) { + DEBUG(10,("uid2sid: uid %lu has sid %s\n", + (unsigned long)(state->request.data.uid), sid)); + fstrcpy(state->response.data.sid.sid, sid); + state->response.data.sid.type = SID_NAME_USER; + request_ok(state); return; } - status = idmap_gid_to_sid(&sid, state->request.data.gid, - IDMAP_FLAG_QUERY_ONLY|IDMAP_FLAG_CACHE_ONLY); + request_error(state); + return; +} - 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; - } +void winbindd_uid_to_sid(struct winbindd_cli_state *state) +{ + DEBUG(3, ("[%5lu]: uid to sid %lu\n", (unsigned long)state->pid, + (unsigned long)state->request.data.uid)); - winbindd_gid2sid_async(state->mem_ctx, state->request.data.gid, gid2sid_recv, 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 */ + 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) -{ - struct gid2sid_state *state = - talloc_get_type_abort(private_data, struct gid2sid_state); - - 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); + request_error(state); + return; } -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) +void winbindd_gid_to_sid(struct winbindd_cli_state *state) { - struct gid2sid_state *state = - (struct gid2sid_state *)private_data; - - /* don't fail if we can't store it */ + DEBUG(3, ("[%5lu]: gid to sid %lu\n", (unsigned long)state->pid, + (unsigned long)state->request.data.gid)); - 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); +} + diff --git a/source3/nsswitch/winbindd_user.c b/source3/nsswitch/winbindd_user.c index 8b19859940..f82b03df07 100644 --- a/source3/nsswitch/winbindd_user.c +++ b/source3/nsswitch/winbindd_user.c @@ -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); } diff --git a/source3/nsswitch/winbindd_util.c b/source3/nsswitch/winbindd_util.c index c9f3a39641..c0a19cd36f 100644 --- a/source3/nsswitch/winbindd_util.c +++ b/source3/nsswitch/winbindd_util.c @@ -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; } + + *type = SID_NAME_UNKNOWN; + *name = talloc_strdup(mem_ctx, name_deadbeef); - return rv; + 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, diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 60d686f245..10efa461b1 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -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) diff --git a/source3/passdb/lookup_sid.c b/source3/passdb/lookup_sid.c index 758fe968fc..d1d0f425ad 100644 --- a/source3/passdb/lookup_sid.c +++ b/source3/passdb/lookup_sid.c @@ -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); diff --git a/source3/passdb/pdb_interface.c b/source3/passdb/pdb_interface.c index b84b0bfaff..478d1ac036 100644 --- a/source3/passdb/pdb_interface.c +++ b/source3/passdb/pdb_interface.c @@ -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; diff --git a/source3/passdb/secrets.c b/source3/passdb/secrets.c index a1be400c46..d169ffa329 100644 --- a/source3/passdb/secrets.c +++ b/source3/passdb/secrets.c @@ -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; +} + diff --git a/source3/sam/idmap.c b/source3/sam/idmap.c deleted file mode 100644 index e8ebd9272c..0000000000 --- a/source3/sam/idmap.c +++ /dev/null @@ -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(); - } -} diff --git a/source3/sam/idmap_ad.c b/source3/sam/idmap_ad.c deleted file mode 100644 index bb48c41131..0000000000 --- a/source3/sam/idmap_ad.c +++ /dev/null @@ -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); -} - diff --git a/source3/sam/idmap_ldap.c b/source3/sam/idmap_ldap.c deleted file mode 100644 index 3fec3a142b..0000000000 --- a/source3/sam/idmap_ldap.c +++ /dev/null @@ -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); -} diff --git a/source3/sam/idmap_rid.c b/source3/sam/idmap_rid.c deleted file mode 100644 index 84b32e3d3f..0000000000 --- a/source3/sam/idmap_rid.c +++ /dev/null @@ -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); -} - diff --git a/source3/sam/idmap_smbldap.c b/source3/sam/idmap_smbldap.c deleted file mode 100644 index 9850921fa3..0000000000 --- a/source3/sam/idmap_smbldap.c +++ /dev/null @@ -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); -} diff --git a/source3/sam/idmap_tdb.c b/source3/sam/idmap_tdb.c deleted file mode 100644 index 02a3178d61..0000000000 --- a/source3/sam/idmap_tdb.c +++ /dev/null @@ -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); -} diff --git a/source3/sam/idmap_util.c b/source3/sam/idmap_util.c deleted file mode 100644 index 8320b294f8..0000000000 --- a/source3/sam/idmap_util.c +++ /dev/null @@ -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; -} diff --git a/source3/utils/net.c b/source3/utils/net.c index 7b97476a25..068af2626f 100644 --- a/source3/utils/net.c +++ b/source3/utils/net.c @@ -867,7 +867,7 @@ static struct functable net_func[] = { {"SETDOMAINSID", net_setdomainsid}, {"GETDOMAINSID", net_getdomainsid}, {"MAXRID", net_maxrid}, - {"IDMAP", net_idmap}, + {"IDMAP", net_idmap}, {"STATUS", net_status}, {"USERSHARE", net_usershare}, {"USERSIDLIST", net_usersidlist}, diff --git a/source3/utils/net_idmap.c b/source3/utils/net_idmap.c index 87da952247..dd16c4b02d 100644 --- a/source3/utils/net_idmap.c +++ b/source3/utils/net_idmap.c @@ -20,166 +20,59 @@ #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; - - 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]); - return -1; - } - - tdb_traverse(idmap_tdb, net_idmap_dump_one_entry, NULL); - - tdb_close(idmap_tdb); - - return 0; -} - -/*********************************************************** - 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; + TALLOC_CTX *ctx; + char *filename; - 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 (argc != 1) { + return net_help_idmap(argc, argv); } - if (idptr == NULL) { - d_fprintf(stderr, "Illegal idmap entry: [%s]->[%s]\n", - key.dptr, data.dptr); - hwms->ok = False; + if (! winbind_ping()) { + d_fprintf(stderr, "To use net idmap Winbindd must be running.\n"); return -1; } - if (isgid) { - if (hwms->group_hwm <= (gid_t)id) { - hwms->group_hwm = (gid_t)(id+1); + ctx = talloc_new(NULL); + ALLOC_CHECK(ctx); + + filename = talloc_strdup(ctx, argv[0]); + ALLOC_CHECK(filename); + + /* filename must be absolute */ + if (*filename != '/') { + char path[4096]; + + filename = getcwd(path, 4095); + if ( ! filename) { + d_fprintf(stderr, "Failed to obtain full output file path"); + talloc_free(ctx); + return -1; } - } else { - if (hwms->user_hwm <= (uid_t)id) { - hwms->user_hwm = (uid_t)(id+1); - } - } - - 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; + filename = talloc_asprintf(ctx, "%s/%s", path, argv[0]); + ALLOC_CHECK(filename); } - 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; + if ( ! winbind_idmap_dump_maps(ctx, filename)) { + d_fprintf(stderr, "Failed to obtain idmap data from winbindd\n"); + talloc_free(ctx); + return -1; } - result = NT_STATUS_OK; - done: - tdb_close(idmap_tdb); - return result; + talloc_free(ctx); + return 0; } /*********************************************************** @@ -188,20 +81,31 @@ static NTSTATUS net_idmap_fixup_hwm(void) 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; + ctx = talloc_new(NULL); + ALLOC_CHECK(ctx); + + if (argc == 1) { + input = fopen(argv[0], "r"); + } else { + input = stdin; + } + + while (!feof(input)) { + char line[128], sid_string[128]; int len; - unid_t id; - enum idmap_type type; - unsigned long idval; DOM_SID sid; + struct id_map map; + unsigned long idval; - if (fgets(line, sizeof(line)-1, stdin) == NULL) + 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); + d_printf("Not Implemented yet\n"); + return -1; +} - idmap_tdb = tdb_open_log(argv[0], 0, TDB_DEFAULT, O_RDWR, 0); +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 (idmap_tdb == NULL) { - d_fprintf(stderr, "Could not open idmap: %s\n", argv[0]); - return -1; + 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); + + 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); } - key.dptr = sid; - key.dsize = strlen(key.dptr)+1; + secret = argv[1]; - data = tdb_fetch(idmap_tdb, key); + ctx = talloc_new(NULL); + ALLOC_CHECK(ctx); - if (data.dptr == NULL) { - d_fprintf(stderr, "Could not find sid %s\n", argv[1]); - return -1; + 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 (tdb_delete(idmap_tdb, key) != 0) { - d_fprintf(stderr, "Could not delete key %s\n", argv[1]); + if ( ( ! backend) || ( ! strequal(backend, "ldap"))) { + d_fprintf(stderr, "The only currently supported backend is LDAP\n"); + talloc_free(ctx); return -1; } - if (tdb_delete(idmap_tdb, data) != 0) { - d_fprintf(stderr, "Could not delete key %s\n", data.dptr); + 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} }; |