From 2ca1aeb59be0267858c9cd46a04d37d982b79990 Mon Sep 17 00:00:00 2001 From: Kai Blin Date: Sun, 17 Feb 2008 20:25:13 +0100 Subject: loadparm: Add configuration settings for idmap. Default behaviour for "idmap trusted only" is "False", meaning idmap creates ID mappings for all SIDs. If set to "True", idmap will create SID mappings for trusted users only. "idmap database" allows to set the database idmap uses, defaulting to idmap,ldb (This used to be commit ed8178b110abcde95e5b18cfb22957c53fd3febd) --- source4/param/loadparm.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/source4/param/loadparm.c b/source4/param/loadparm.c index e850d82193..bad90fc74a 100644 --- a/source4/param/loadparm.c +++ b/source4/param/loadparm.c @@ -91,6 +91,7 @@ struct loadparm_global char *szPasswdChat; char *szShareBackend; char *szSAM_URL; + char *szIDMAP_URL; char *szSECRETS_URL; char *szSPOOLSS_URL; char *szWINS_CONFIG_URL; @@ -119,6 +120,7 @@ struct loadparm_global char *szTemplateShell; char *szTemplateHomedir; int bWinbindSealedPipes; + int bIdmapTrustedOnly; char *swat_directory; int tls_enabled; char *tls_keyfile; @@ -384,6 +386,7 @@ static struct parm_struct parm_table[] = { {"obey pam restrictions", P_BOOL, P_GLOBAL, GLOBAL_VAR(bObeyPamRestrictions), NULL, NULL}, {"password server", P_LIST, P_GLOBAL, GLOBAL_VAR(szPasswordServers), NULL, NULL}, {"sam database", P_STRING, P_GLOBAL, GLOBAL_VAR(szSAM_URL), NULL, NULL}, + {"idmap database", P_STRING, P_GLOBAL, GLOBAL_VAR(szIDMAP_URL), NULL, NULL}, {"secrets database", P_STRING, P_GLOBAL, GLOBAL_VAR(szSECRETS_URL), NULL, NULL}, {"spoolss database", P_STRING, P_GLOBAL, GLOBAL_VAR(szSPOOLSS_URL), NULL, NULL}, {"wins config database", P_STRING, P_GLOBAL, GLOBAL_VAR(szWINS_CONFIG_URL), NULL, NULL}, @@ -513,6 +516,7 @@ static struct parm_struct parm_table[] = { {"winbind sealed pipes", P_BOOL, P_GLOBAL, GLOBAL_VAR(bWinbindSealedPipes), NULL, NULL }, {"template shell", P_STRING, P_GLOBAL, GLOBAL_VAR(szTemplateShell), NULL, NULL }, {"template homedir", P_STRING, P_GLOBAL, GLOBAL_VAR(szTemplateHomedir), NULL, NULL }, + {"idmap trusted only", P_BOOL, P_GLOBAL, GLOBAL_VAR(bIdmapTrustedOnly), NULL, NULL}, {NULL, P_BOOL, P_NONE, 0, NULL, NULL} }; @@ -642,6 +646,7 @@ _PUBLIC_ FN_GLOBAL_STRING(lp_tls_crlfile, tls_crlfile) _PUBLIC_ FN_GLOBAL_STRING(lp_tls_dhpfile, tls_dhpfile) _PUBLIC_ FN_GLOBAL_STRING(lp_share_backend, szShareBackend) _PUBLIC_ FN_GLOBAL_STRING(lp_sam_url, szSAM_URL) +_PUBLIC_ FN_GLOBAL_STRING(lp_idmap_url, szIDMAP_URL) _PUBLIC_ FN_GLOBAL_STRING(lp_secrets_url, szSECRETS_URL) _PUBLIC_ FN_GLOBAL_STRING(lp_spoolss_url, szSPOOLSS_URL) _PUBLIC_ FN_GLOBAL_STRING(lp_wins_config_url, szWINS_CONFIG_URL) @@ -651,6 +656,7 @@ _PUBLIC_ FN_GLOBAL_CONST_STRING(lp_winbindd_socket_directory, szWinbinddSocketDi _PUBLIC_ FN_GLOBAL_CONST_STRING(lp_template_shell, szTemplateShell) _PUBLIC_ FN_GLOBAL_CONST_STRING(lp_template_homedir, szTemplateHomedir) _PUBLIC_ FN_GLOBAL_BOOL(lp_winbind_sealed_pipes, bWinbindSealedPipes) +_PUBLIC_ FN_GLOBAL_BOOL(lp_idmap_trusted_only, bIdmapTrustedOnly) _PUBLIC_ FN_GLOBAL_STRING(lp_private_dir, szPrivateDir) _PUBLIC_ FN_GLOBAL_STRING(lp_serverstring, szServerString) _PUBLIC_ FN_GLOBAL_STRING(lp_lockdir, szLockDir) @@ -2305,6 +2311,7 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx) lp_do_global_parameter(lp_ctx, "auth methods:standalone", "anonymous sam_ignoredomain"); lp_do_global_parameter(lp_ctx, "private dir", dyn_PRIVATE_DIR); lp_do_global_parameter(lp_ctx, "sam database", "sam.ldb"); + lp_do_global_parameter(lp_ctx, "idmap database", "idmap.ldb"); lp_do_global_parameter(lp_ctx, "secrets database", "secrets.ldb"); lp_do_global_parameter(lp_ctx, "spoolss database", "spoolss.ldb"); lp_do_global_parameter(lp_ctx, "wins config database", "wins_config.ldb"); @@ -2380,6 +2387,7 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx) lp_do_global_parameter(lp_ctx, "winbindd socket directory", dyn_WINBINDD_SOCKET_DIR); lp_do_global_parameter(lp_ctx, "template shell", "/bin/false"); lp_do_global_parameter(lp_ctx, "template homedir", "/home/%WORKGROUP%/%ACCOUNTNAME%"); + lp_do_global_parameter(lp_ctx, "idmap trusted only", "False"); lp_do_global_parameter(lp_ctx, "client signing", "Yes"); lp_do_global_parameter(lp_ctx, "server signing", "auto"); -- cgit From 895874d9663ccb95883579d145018ec8a8add9c8 Mon Sep 17 00:00:00 2001 From: Kai Blin Date: Mon, 18 Feb 2008 14:33:58 +0100 Subject: idmap: Handle uid->SID mapping (This used to be commit 6ac6de8476ba036eb041e054bc37e4503dc2fde8) --- .gitignore | 1 + source4/scripting/libjs/provision.js | 4 + source4/scripting/python/samba/provision.py | 24 ++ source4/setup/idmap_init.ldif | 5 + source4/winbind/config.mk | 11 + source4/winbind/idmap.c | 415 ++++++++++++++++++++++++++++ source4/winbind/idmap.h | 33 +++ source4/winbind/wb_server.c | 6 + source4/winbind/wb_server.h | 2 + source4/winbind/wb_uid2sid.c | 15 +- 10 files changed, 511 insertions(+), 5 deletions(-) create mode 100644 source4/setup/idmap_init.ldif create mode 100644 source4/winbind/idmap.c create mode 100644 source4/winbind/idmap.h diff --git a/.gitignore b/.gitignore index 6076ddc9cd..f75f698c65 100644 --- a/.gitignore +++ b/.gitignore @@ -129,6 +129,7 @@ source/utils/net/net_proto.h source/web_server/proto.h source/winbind/wb_helper.h source/winbind/wb_proto.h +source/winbind/idmap_proto.h source/wrepl_server/wrepl_server_proto.h tags source/auth/credentials/credentials_krb5_proto.h diff --git a/source4/scripting/libjs/provision.js b/source4/scripting/libjs/provision.js index dc9eae8e72..3ba93debf9 100644 --- a/source4/scripting/libjs/provision.js +++ b/source4/scripting/libjs/provision.js @@ -389,6 +389,7 @@ function provision_default_paths(subobj) paths.smbconf = lp.filename() paths.shareconf = lp.get("private dir") + "/" + "share.ldb"; paths.samdb = lp.get("sam database"); + paths.idmapdb = lp.get("idmap database"); paths.secrets = lp.get("secrets database"); paths.templates = lp.get("private dir") + "/" + "templates.ldb"; paths.keytab = "secrets.keytab"; @@ -679,6 +680,9 @@ function provision(subobj, message, blank, paths, session_info, credentials, lda message("Setting up templates into " + paths.templates + "\n"); setup_ldb("provision_templates.ldif", info, paths.templates); + message("Setting up " + paths.idmapdb +"\n"); + setup_ldb("idmap_init.ldif", info, paths.idmapdb); + message("Setting up sam.ldb partitions\n"); /* Also wipes the database */ setup_ldb("provision_partitions.ldif", info, paths.samdb); diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 3e88b68509..e3c47ff4a2 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -59,6 +59,7 @@ class ProvisionPaths: self.hkpd = None self.hkpt = None self.samdb = None + self.idmapdb = None self.secrets = None self.keytab = None self.dns_keytab = None @@ -202,6 +203,7 @@ def provision_paths_from_lp(lp, dnsdomain): paths.shareconf = os.path.join(private_dir, "share.ldb") paths.samdb = os.path.join(private_dir, lp.get("sam database") or "samdb.ldb") + paths.idmapdb = os.path.join(private_dir, lp.get("idmap database") or "idmap.ldb") paths.secrets = os.path.join(private_dir, lp.get("secrets database") or "secrets.ldb") paths.templates = os.path.join(private_dir, "templates.ldb") paths.dns = os.path.join(private_dir, dnsdomain + ".zone") @@ -471,6 +473,24 @@ def setup_registry(path, setup_path, session_info, credentials, lp): assert os.path.exists(provision_reg) reg.diff_apply(provision_reg) +def setup_idmapdb(path, setup_path, session_info, credentials, lp): + """Setup the idmap database. + + :param path: path to the idmap database + :param setup_path: Function that returns a path to a setup file + :param session_info: Session information + :param credentials: Credentials + :param lp: Loadparm context + """ + if os.path.exists(path): + os.unlink(path) + + idmap_ldb = Ldb(path, session_info=session_info, credentials=credentials, + lp=lp) + + idmap_ldb.erase() + idmap_ldb.load_ldif_file_add(setup_path("idmap_init.ldif")) + return idmap_ldb def setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn, hostname, dnsdomain, realm, rootdn, configdn, netbiosname, @@ -844,6 +864,10 @@ def provision(lp, setup_dir, message, paths, session_info, setup_templatesdb(paths.templates, setup_path, session_info=session_info, credentials=credentials, lp=lp) + message("Setting up idmap db") + setup_idmapdb(paths.idmapdb, setup_path, session_info=session_info, + credentials=credentials, lp=lp) + samdb = setup_samdb(paths.samdb, setup_path, session_info=session_info, credentials=credentials, lp=lp, schemadn=schemadn, configdn=configdn, domaindn=domaindn, diff --git a/source4/setup/idmap_init.ldif b/source4/setup/idmap_init.ldif new file mode 100644 index 0000000000..a397cfd0d2 --- /dev/null +++ b/source4/setup/idmap_init.ldif @@ -0,0 +1,5 @@ +dn: CN=CONFIG +cn: CONFIG +lowerBound: 10000 +upperBound: 20000 + diff --git a/source4/winbind/config.mk b/source4/winbind/config.mk index da5b71f2ae..2567d617da 100644 --- a/source4/winbind/config.mk +++ b/source4/winbind/config.mk @@ -37,6 +37,7 @@ OBJ_FILES = \ wb_sam_logon.o PRIVATE_DEPENDENCIES = \ WB_HELPER \ + IDMAP \ NDR_WINBIND \ process_model \ RPC_NDR_LSA \ @@ -56,3 +57,13 @@ OBJ_FILES = \ PUBLIC_DEPENDENCIES = RPC_NDR_LSA dcerpc_samr # End SUBSYSTEM WB_HELPER ################################################ + +################################################ +# Start SUBYSTEM IDMAP +[SUBSYSTEM::IDMAP] +PRIVATE_PROTO_HEADER = idmap_proto.h +OBJ_FILES = \ + idmap.o +PUBLIC_DEPENDENCIES = SAMDB_COMMON +# End SUBSYSTEM IDMAP +################################################ diff --git a/source4/winbind/idmap.c b/source4/winbind/idmap.c new file mode 100644 index 0000000000..b14885213e --- /dev/null +++ b/source4/winbind/idmap.c @@ -0,0 +1,415 @@ +/* + Unix SMB/CIFS implementation. + + Map SIDs to uids/gids and back + + Copyright (C) Kai Blin 2008 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "auth/auth.h" +#include "librpc/gen_ndr/lsa.h" +#include "librpc/gen_ndr/samr.h" +#include "librpc/gen_ndr/ndr_security.h" +#include "lib/ldb/include/ldb.h" +#include "lib/ldb/include/ldb_errors.h" +#include "lib/ldb_wrap.h" +#include "param/param.h" +#include "winbind/idmap.h" +#include "libcli/security/proto.h" +#include "libcli/ldap/ldap_ndr.h" + +/** + * Get uid/gid bounds from idmap database + * + * \param idmap_ctx idmap context to use + * \param low lower uid/gid bound is stored here + * \param high upper uid/gid bound is stored here + * \return 0 on success, nonzero on failure + */ +static int idmap_get_bounds(struct idmap_context *idmap_ctx, uint32_t *low, + uint32_t *high) +{ + int ret = -1; + struct ldb_context *ldb = idmap_ctx->ldb_ctx; + struct ldb_dn *dn; + struct ldb_result *res = NULL; + TALLOC_CTX *tmp_ctx = talloc_new(idmap_ctx); + uint32_t lower_bound = (uint32_t) -1; + uint32_t upper_bound = (uint32_t) -1; + + dn = ldb_dn_new(tmp_ctx, ldb, "CN=CONFIG"); + if (dn == NULL) goto failed; + + ret = ldb_search(ldb, dn, LDB_SCOPE_BASE, NULL, NULL, &res); + if (ret != LDB_SUCCESS) goto failed; + + talloc_steal(tmp_ctx, res); + + if (res->count != 1) { + ret = -1; + goto failed; + } + + lower_bound = ldb_msg_find_attr_as_uint(res->msgs[0], "lowerBound", -1); + if (lower_bound != (uint32_t) -1) { + ret = LDB_SUCCESS; + } else { + ret = -1; + goto failed; + } + + upper_bound = ldb_msg_find_attr_as_uint(res->msgs[0], "upperBound", -1); + if (upper_bound != (uint32_t) -1) { + ret = LDB_SUCCESS; + } else { + ret = -1; + } + +failed: + talloc_free(tmp_ctx); + *low = lower_bound; + *high = upper_bound; + return ret; +} + +/** + * Add a dom_sid structure to a ldb_message + * \param idmap_ctx idmap context to use + * \param mem_ctx talloc context to use + * \param ldb_message ldb message to add dom_sid to + * \param attr_name name of the attribute to store the dom_sid in + * \param sid dom_sid to store + * \return 0 on success, an ldb error code on failure. + */ +static int idmap_msg_add_dom_sid(struct idmap_context *idmap_ctx, + TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name, const struct dom_sid *sid) +{ + struct ldb_val val; + enum ndr_err_code ndr_err; + + ndr_err = ndr_push_struct_blob(&val, mem_ctx, + lp_iconv_convenience(idmap_ctx->lp_ctx), + sid, + (ndr_push_flags_fn_t)ndr_push_dom_sid); + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return -1; + } + + return ldb_msg_add_value(msg, attr_name, &val, NULL); +} + +/** + * Get a dom_sid structure from a ldb message. + * + * \param mem_ctx talloc context to allocate dom_sid memory in + * \param msg ldb_message to get dom_sid from + * \param attr_name key that has the dom_sid as data + * \return dom_sid structure on success, NULL on failure + */ +static struct dom_sid *idmap_msg_get_dom_sid(TALLOC_CTX *mem_ctx, + struct ldb_message *msg, const char *attr_name) +{ + struct dom_sid *sid; + const struct ldb_val *val; + enum ndr_err_code ndr_err; + + val = ldb_msg_find_ldb_val(msg, attr_name); + if (val == NULL) { + return NULL; + } + + sid = talloc(mem_ctx, struct dom_sid); + if (sid == NULL) { + return NULL; + } + + ndr_err = ndr_pull_struct_blob(val, sid, NULL, sid, + (ndr_pull_flags_fn_t)ndr_pull_dom_sid); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + talloc_free(sid); + return NULL; + } + + return sid; +} + +/** + * Initialize idmap context + * + * talloc_free to close. + * + * \param mem_ctx talloc context to use. + * \return allocated idmap_context on success, NULL on error + */ +struct idmap_context *idmap_init(TALLOC_CTX *mem_ctx, + struct loadparm_context *lp_ctx) +{ + struct idmap_context *idmap_ctx; + + idmap_ctx = talloc(mem_ctx, struct idmap_context); + if (idmap_ctx == NULL) { + return NULL; + } + + idmap_ctx->lp_ctx = lp_ctx; + + idmap_ctx->ldb_ctx = ldb_wrap_connect(mem_ctx, lp_ctx, + lp_idmap_url(lp_ctx), + system_session(mem_ctx, lp_ctx), + NULL, 0, NULL); + if (idmap_ctx->ldb_ctx == NULL) { + return NULL; + } + + return idmap_ctx; +} + +/** + * Convert a uid to the corresponding SID + * + * \param idmap_ctx idmap context to use + * \param mem_ctx talloc context the memory for the struct dom_sid is allocated + * from. + * \param uid Unix uid to map to a SID + * \param sid Pointer that will take the struct dom_sid pointer if the mapping + * succeeds. + * \return NT_STATUS_OK on success, NT_STATUS_NONE_MAPPED if mapping not + * possible or some other NTSTATUS that is more descriptive on failure. + */ + +NTSTATUS idmap_uid_to_sid(struct idmap_context *idmap_ctx, TALLOC_CTX *mem_ctx, + const uid_t uid, struct dom_sid **sid) +{ + int ret; + NTSTATUS status = NT_STATUS_NONE_MAPPED; + struct ldb_context *ldb = idmap_ctx->ldb_ctx; + struct ldb_message *msg; + struct ldb_result *res = NULL; + int trans = -1; + uid_t low, high; + char *sid_string, *uid_string; + struct dom_sid *unix_users_sid, *new_sid; + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + + ret = ldb_search_exp_fmt(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, + NULL, "(&(objectClass=sidMap)(uidNumber=%u))", + uid); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb))); + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + if (res->count == 1) { + *sid = idmap_msg_get_dom_sid(mem_ctx, res->msgs[0], + "objectSid"); + if (*sid == NULL) { + DEBUG(1, ("Failed to get sid from db: %u\n", ret)); + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + talloc_free(tmp_ctx); + return NT_STATUS_OK; + } + + DEBUG(6, ("uid not found in idmap db, trying to allocate SID.\n")); + + trans = ldb_transaction_start(ldb); + if (trans != LDB_SUCCESS) { + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + /* Now redo the search to make sure noone added a mapping for that SID + * while we weren't looking.*/ + ret = ldb_search_exp_fmt(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, + NULL, "(&(objectClass=sidMap)(uidNumber=%u))", + uid); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb))); + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + if (res->count > 0) { + DEBUG(1, ("sidMap modified while trying to add a mapping.\n")); + status = NT_STATUS_RETRY; + goto failed; + } + + ret = idmap_get_bounds(idmap_ctx, &low, &high); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Failed to get id bounds from db: %u\n", ret)); + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + if (uid >= low && uid <= high) { + /* An existing user would have been mapped before */ + status = NT_STATUS_NO_SUCH_USER; + goto failed; + } + + /* For local users, we just create a rid = uid +1, so root doesn't end + * up with a 0 rid */ + unix_users_sid = dom_sid_parse_talloc(tmp_ctx, "S-1-22-1"); + if (unix_users_sid == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + new_sid = dom_sid_add_rid(mem_ctx, unix_users_sid, uid + 1); + if (new_sid == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + sid_string = dom_sid_string(tmp_ctx, new_sid); + if (sid_string == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + uid_string = talloc_asprintf(tmp_ctx, "%u", uid); + if (uid_string == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + msg = ldb_msg_new(tmp_ctx); + if (msg == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + msg->dn = ldb_dn_new_fmt(tmp_ctx, ldb, "CN=%s", sid_string); + if (msg->dn == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + ret = ldb_msg_add_string(msg, "uidNumber", uid_string); + if (ret != LDB_SUCCESS) { + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + ret = idmap_msg_add_dom_sid(idmap_ctx, tmp_ctx, msg, "objectSid", + new_sid); + if (ret != LDB_SUCCESS) { + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + ret = ldb_msg_add_string(msg, "objectClass", "sidMap"); + if (ret != LDB_SUCCESS) { + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + ret = ldb_msg_add_string(msg, "cn", sid_string); + if (ret != LDB_SUCCESS) { + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + ret = ldb_add(ldb, msg); + if (ret != LDB_SUCCESS) { + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + trans = ldb_transaction_commit(ldb); + if (trans != LDB_SUCCESS) { + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + *sid = new_sid; + talloc_free(tmp_ctx); + return NT_STATUS_OK; + +failed: + if (trans == LDB_SUCCESS) ldb_transaction_cancel(ldb); + talloc_free(tmp_ctx); + return status; +} + +/** + * Map a Unix gid to the corresponding SID + * + * \todo Create a SID from the S-1-22-2 range for unmapped groups + * + * \param idmap_ctx idmap context to use + * \param mem_ctx talloc context the memory for the struct dom_sid is allocated + * from. + * \param gid Unix gid to map to a SID + * \param sid Pointer that will take the struct dom_sid pointer if mapping + * succeeds. + * \return NT_STATUS_OK on success, NT_STATUS_NONE_MAPPED if mapping not + * possible or some other NTSTATUS that is more descriptive on failure. + */ +NTSTATUS idmap_gid_to_sid(struct idmap_context *idmap_ctx, TALLOC_CTX *mem_ctx, + const gid_t gid, struct dom_sid **sid) +{ + return NT_STATUS_NONE_MAPPED; +} + +/** + * Map a SID to a Unix uid. + * + * If no mapping exists, a new mapping will be created. + * + * \todo Create mappings for users not from our primary domain. + * + * \param idmap_ctx idmap context to use + * \param mem_ctx talloc context to use + * \param sid SID to map to a Unix uid + * \param uid pointer to receive the mapped uid + * \return NT_STATUS_OK on success, NT_STATUS_INVALID_SID if the sid is not from + * a trusted domain and idmap trusted only = true, NT_STATUS_NONE_MAPPED if the + * mapping failed. + */ +NTSTATUS idmap_sid_to_uid(struct idmap_context *idmap_ctx, TALLOC_CTX *mem_ctx, + const struct dom_sid *sid, uid_t *uid) +{ + return NT_STATUS_NONE_MAPPED; +} + +/** + * Map a SID to a Unix gid. + * + * If no mapping exist, a new mapping will be created. + * + * \todo Create mappings for groups not from our primary domain. + * + * \param idmap_ctx idmap context to use + * \param mem_ctx talloc context to use + * \param sid SID to map to a Unix gid + * \param gid pointer to receive the mapped gid + * \return NT_STATUS_OK on success, NT_STATUS_INVALID_SID if the sid is not from + * a trusted domain and idmap trusted only = true, NT_STATUS_NONE_MAPPED if the + * mapping failed. + */ +NTSTATUS idmap_sid_to_gid(struct idmap_context *idmap_ctx, TALLOC_CTX *mem_ctx, + const struct dom_sid *sid, gid_t *gid) +{ + return NT_STATUS_NONE_MAPPED; +} + diff --git a/source4/winbind/idmap.h b/source4/winbind/idmap.h new file mode 100644 index 0000000000..8781819be0 --- /dev/null +++ b/source4/winbind/idmap.h @@ -0,0 +1,33 @@ +/* + Unix SMB/CIFS implementation. + + Map SIDs to uids/gids and back + + Copyright (C) Kai Blin 2008 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef _IDMAP_H_ +#define _IDMAP_H_ + +struct idmap_context { + struct loadparm_context *lp_ctx; + struct ldb_context *ldb_ctx; +}; + +#include "winbind/idmap_proto.h" + +#endif + diff --git a/source4/winbind/wb_server.c b/source4/winbind/wb_server.c index 9b303f3615..99191f3c6c 100644 --- a/source4/winbind/wb_server.c +++ b/source4/winbind/wb_server.c @@ -149,6 +149,12 @@ static void winbind_task_init(struct task_server *task) return; } + service->idmap_ctx = idmap_init(service, task->lp_ctx); + if (service->idmap_ctx == NULL) { + task_server_terminate(task, "Failed to load idmap database"); + return; + } + /* setup the unprivileged samba3 socket */ listen_socket = talloc(service, struct wbsrv_listen_socket); if (!listen_socket) goto nomem; diff --git a/source4/winbind/wb_server.h b/source4/winbind/wb_server.h index f3cfc18565..ce972932f5 100644 --- a/source4/winbind/wb_server.h +++ b/source4/winbind/wb_server.h @@ -21,6 +21,7 @@ #include "nsswitch/winbind_nss_config.h" #include "nsswitch/winbind_struct_protocol.h" +#include "winbind/idmap.h" #include "libnet/libnet.h" #define WINBINDD_SAMBA3_SOCKET "pipe" @@ -33,6 +34,7 @@ struct wbsrv_service { const struct dom_sid *primary_sid; struct wbsrv_domain *domains; + struct idmap_context *idmap_ctx; }; struct wbsrv_samconn { diff --git a/source4/winbind/wb_uid2sid.c b/source4/winbind/wb_uid2sid.c index d7a909fda2..e81d2e4671 100644 --- a/source4/winbind/wb_uid2sid.c +++ b/source4/winbind/wb_uid2sid.c @@ -3,7 +3,7 @@ Command backend for wbinfo -U - Copyright (C) Kai Blin 2007 + Copyright (C) Kai Blin 2007-2008 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 @@ -25,6 +25,7 @@ #include "smbd/service_task.h" #include "winbind/wb_helper.h" #include "libcli/security/proto.h" +#include "winbind/idmap.h" struct uid2sid_state { struct composite_context *ctx; @@ -50,10 +51,14 @@ struct composite_context *wb_uid2sid_send(TALLOC_CTX *mem_ctx, result->private_data = state; state->service = service; - /* FIXME: This is a stub so far. - * We cheat by just using the uid as RID with the domain SID.*/ - state->sid = dom_sid_add_rid(result, service->primary_sid, uid); - if (composite_nomem(state->sid, state->ctx)) return result; + state->ctx->status = idmap_uid_to_sid(service->idmap_ctx, mem_ctx, uid, + &state->sid); + if (NT_STATUS_EQUAL(state->ctx->status, NT_STATUS_RETRY)) { + state->ctx->status = idmap_uid_to_sid(service->idmap_ctx, + mem_ctx, uid, + &state->sid); + } + if (!composite_is_ok(state->ctx)) return result; composite_done(state->ctx); return result; -- cgit From 9c7f714962bdfe280baed42ed6a1e35a422a0267 Mon Sep 17 00:00:00 2001 From: Kai Blin Date: Mon, 18 Feb 2008 14:30:17 +0100 Subject: idmap: Handle gid->SID mapping (This used to be commit 6f2d95030cd7b4b22d1b75d15b76881449eda697) --- source4/winbind/idmap.c | 157 ++++++++++++++++++++++++++++++++++++++++++- source4/winbind/wb_gid2sid.c | 13 ++-- 2 files changed, 163 insertions(+), 7 deletions(-) diff --git a/source4/winbind/idmap.c b/source4/winbind/idmap.c index b14885213e..af026a4d5c 100644 --- a/source4/winbind/idmap.c +++ b/source4/winbind/idmap.c @@ -354,8 +354,6 @@ failed: /** * Map a Unix gid to the corresponding SID * - * \todo Create a SID from the S-1-22-2 range for unmapped groups - * * \param idmap_ctx idmap context to use * \param mem_ctx talloc context the memory for the struct dom_sid is allocated * from. @@ -368,7 +366,160 @@ failed: NTSTATUS idmap_gid_to_sid(struct idmap_context *idmap_ctx, TALLOC_CTX *mem_ctx, const gid_t gid, struct dom_sid **sid) { - return NT_STATUS_NONE_MAPPED; + int ret; + NTSTATUS status = NT_STATUS_NONE_MAPPED; + struct ldb_context *ldb = idmap_ctx->ldb_ctx; + struct ldb_message *msg; + struct ldb_result *res = NULL; + int trans = -1; + gid_t low, high; + char *sid_string, *gid_string; + struct dom_sid *unix_groups_sid, *new_sid; + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + + ret = ldb_search_exp_fmt(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, + NULL, "(&(objectClass=sidMap)(gidNumber=%u))", gid); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb))); + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + if (res->count == 1) { + *sid = idmap_msg_get_dom_sid(mem_ctx, res->msgs[0], + "objectSid"); + if (*sid == NULL) { + DEBUG(1, ("Failed to get sid from db: %u\n", ret)); + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + /* No change, so cancel the transaction */ + ldb_transaction_cancel(ldb); + talloc_free(tmp_ctx); + return NT_STATUS_OK; + } + + DEBUG(6, ("gid not found in idmap db, trying to allocate SID.\n")); + + trans = ldb_transaction_start(ldb); + if (trans != LDB_SUCCESS) { + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + /* Now redo the search to make sure noone added a mapping for that SID + * while we weren't looking.*/ + ret = ldb_search_exp_fmt(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, + NULL, "(&(objectClass=sidMap)(gidNumber=%u))", + gid); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb))); + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + if (res->count > 0) { + DEBUG(1, ("sidMap modified while trying to add a mapping.\n")); + status = NT_STATUS_RETRY; + goto failed; + } + + ret = idmap_get_bounds(idmap_ctx, &low, &high); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Failed to get id bounds from db: %u\n", ret)); + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + if (gid >= low && gid <= high) { + /* An existing group would have been mapped before */ + status = NT_STATUS_NO_SUCH_USER; + goto failed; + } + + /* For local groups, we just create a rid = gid +1, so root doesn't end + * up with a 0 rid */ + unix_groups_sid = dom_sid_parse_talloc(tmp_ctx, "S-1-22-2"); + if (unix_groups_sid == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + new_sid = dom_sid_add_rid(mem_ctx, unix_groups_sid, gid + 1); + if (new_sid == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + sid_string = dom_sid_string(tmp_ctx, new_sid); + if (sid_string == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + gid_string = talloc_asprintf(tmp_ctx, "%u", gid); + if (gid_string == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + msg = ldb_msg_new(tmp_ctx); + if (msg == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + msg->dn = ldb_dn_new_fmt(tmp_ctx, ldb, "CN=%s", sid_string); + if (msg->dn == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + ret = ldb_msg_add_string(msg, "gidNumber", gid_string); + if (ret != LDB_SUCCESS) { + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + ret = idmap_msg_add_dom_sid(idmap_ctx, tmp_ctx, msg, "objectSid", + new_sid); + if (ret != LDB_SUCCESS) { + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + ret = ldb_msg_add_string(msg, "objectClass", "sidMap"); + if (ret != LDB_SUCCESS) { + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + ret = ldb_msg_add_string(msg, "cn", sid_string); + if (ret != LDB_SUCCESS) { + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + ret = ldb_add(ldb, msg); + if (ret != LDB_SUCCESS) { + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + trans = ldb_transaction_commit(ldb); + if (trans != LDB_SUCCESS) { + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + *sid = new_sid; + talloc_free(tmp_ctx); + return NT_STATUS_OK; + +failed: + if (trans == LDB_SUCCESS) ldb_transaction_cancel(ldb); + talloc_free(tmp_ctx); + return status; } /** diff --git a/source4/winbind/wb_gid2sid.c b/source4/winbind/wb_gid2sid.c index 5c0b87118d..f2577029aa 100644 --- a/source4/winbind/wb_gid2sid.c +++ b/source4/winbind/wb_gid2sid.c @@ -25,6 +25,7 @@ #include "smbd/service_task.h" #include "winbind/wb_helper.h" #include "libcli/security/proto.h" +#include "winbind/idmap.h" struct gid2sid_state { struct composite_context *ctx; @@ -50,10 +51,14 @@ struct composite_context *wb_gid2sid_send(TALLOC_CTX *mem_ctx, result->private_data = state; state->service = service; - /* FIXME: This is a stub so far. - * We cheat by just using the gid as RID with the domain SID.*/ - state->sid = dom_sid_add_rid(result, service->primary_sid, gid); - if (composite_nomem(state->sid, state->ctx)) return result; + state->ctx->status = idmap_gid_to_sid(service->idmap_ctx, mem_ctx, gid, + &state->sid); + if (NT_STATUS_EQUAL(state->ctx->status, NT_STATUS_RETRY)) { + state->ctx->status = idmap_gid_to_sid(service->idmap_ctx, + mem_ctx, gid, + &state->sid); + } + if (!composite_is_ok(state->ctx)) return result; composite_done(state->ctx); return result; -- cgit From 705abe2cb3bc67f4e225ed38f32f77a2b433abc8 Mon Sep 17 00:00:00 2001 From: Kai Blin Date: Mon, 18 Feb 2008 18:53:12 +0100 Subject: idmap: Handle SID->uid (This used to be commit 4037ca6b9cf14219b4a4475399a51db01c655da6) --- source4/winbind/idmap.c | 257 ++++++++++++++++++++++++++++++++++++++++++- source4/winbind/wb_sid2uid.c | 15 ++- 2 files changed, 264 insertions(+), 8 deletions(-) diff --git a/source4/winbind/idmap.c b/source4/winbind/idmap.c index af026a4d5c..53276114dd 100644 --- a/source4/winbind/idmap.c +++ b/source4/winbind/idmap.c @@ -527,7 +527,7 @@ failed: * * If no mapping exists, a new mapping will be created. * - * \todo Create mappings for users not from our primary domain. + * \todo Check if SIDs can be resolved if lp_idmap_trusted_only() == true * * \param idmap_ctx idmap context to use * \param mem_ctx talloc context to use @@ -540,7 +540,260 @@ failed: NTSTATUS idmap_sid_to_uid(struct idmap_context *idmap_ctx, TALLOC_CTX *mem_ctx, const struct dom_sid *sid, uid_t *uid) { - return NT_STATUS_NONE_MAPPED; + int ret; + NTSTATUS status = NT_STATUS_NONE_MAPPED; + struct ldb_context *ldb = idmap_ctx->ldb_ctx; + struct ldb_dn *dn; + struct ldb_message *hwm_msg, *map_msg; + struct ldb_result *res = NULL; + int trans; + uid_t low, high, hwm, new_uid; + char *sid_string, *uid_string, *hwm_string; + bool hwm_entry_exists; + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + + ret = ldb_search_exp_fmt(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, + NULL, "(&(objectClass=sidMap)(objectSid=%s))", + ldap_encode_ndr_dom_sid(tmp_ctx, sid)); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb))); + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + if (res->count == 1) { + new_uid = ldb_msg_find_attr_as_uint(res->msgs[0], "uidNumber", + -1); + if (new_uid == (uid_t) -1) { + DEBUG(1, ("Invalid uid mapping.\n")); + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + *uid = new_uid; + talloc_free(tmp_ctx); + return NT_STATUS_OK; + } + + DEBUG(6, ("No existing mapping found, attempting to create one.\n")); + + trans = ldb_transaction_start(ldb); + if (trans != LDB_SUCCESS) { + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + /* Redo the search to make sure noone changed the mapping while we + * weren't looking */ + ret = ldb_search_exp_fmt(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, + NULL, "(&(objectClass=sidMap)(objectSid=%s))", + ldap_encode_ndr_dom_sid(tmp_ctx, sid)); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb))); + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + if (res->count > 0) { + DEBUG(1, ("Database changed while trying to add a sidmap.\n")); + status = NT_STATUS_RETRY; + goto failed; + } + + /*FIXME: if lp_idmap_trusted_only() == true, check if SID can be + * resolved here. */ + + ret = idmap_get_bounds(idmap_ctx, &low, &high); + if (ret != LDB_SUCCESS) { + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + dn = ldb_dn_new(tmp_ctx, ldb, "CN=CONFIG"); + if (dn == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + ret = ldb_search(ldb, dn, LDB_SCOPE_BASE, NULL, NULL, &res); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb))); + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + talloc_steal(tmp_ctx, res); + + if (res->count != 1) { + DEBUG(1, ("No CN=CONFIG record, idmap database is broken.\n")); + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + hwm = ldb_msg_find_attr_as_uint(res->msgs[0], "uidNumber", -1); + if (hwm == (uid_t)-1) { + hwm = low; + hwm_entry_exists = false; + } else { + hwm_entry_exists = true; + } + + if (hwm > high) { + DEBUG(1, ("Out of uids to allocate.\n")); + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + hwm_msg = ldb_msg_new(tmp_ctx); + if (hwm_msg == NULL) { + DEBUG(1, ("Out of memory when creating ldb_message\n")); + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + hwm_msg->dn = dn; + + new_uid = hwm; + hwm++; + + hwm_string = talloc_asprintf(tmp_ctx, "%u", hwm); + if (hwm_string == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + sid_string = dom_sid_string(tmp_ctx, sid); + if (sid_string == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + uid_string = talloc_asprintf(tmp_ctx, "%u", new_uid); + if (uid_string == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + if (hwm_entry_exists) { + struct ldb_message_element *els; + struct ldb_val *vals; + + /* We're modifying the entry, not just adding a new one. */ + els = talloc_array(tmp_ctx, struct ldb_message_element, 2); + if (els == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + vals = talloc_array(tmp_ctx, struct ldb_val, 2); + if (els == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + hwm_msg->num_elements = 2; + hwm_msg->elements = els; + + els[0].num_values = 1; + els[0].values = &vals[0]; + els[0].flags = LDB_FLAG_MOD_DELETE; + els[0].name = talloc_strdup(tmp_ctx, "uidNumber"); + if (els[0].name == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + els[1].num_values = 1; + els[1].values = &vals[1]; + els[1].flags = LDB_FLAG_MOD_ADD; + els[1].name = els[0].name; + + vals[0].data = (uint8_t *)uid_string; + vals[0].length = strlen(uid_string); + vals[1].data = (uint8_t *)hwm_string; + vals[1].length = strlen(hwm_string); + } else { + ret = ldb_msg_add_empty(hwm_msg, "uidNumber", LDB_FLAG_MOD_ADD, + NULL); + if (ret != LDB_SUCCESS) { + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + ret = ldb_msg_add_string(hwm_msg, "uidNumber", hwm_string); + if (ret != LDB_SUCCESS) + { + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + } + + ret = ldb_modify(ldb, hwm_msg); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Updating the uid high water mark failed: %s\n", + ldb_errstring(ldb))); + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + map_msg = ldb_msg_new(tmp_ctx); + if (map_msg == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + map_msg->dn = ldb_dn_new_fmt(tmp_ctx, ldb, "CN=%s", sid_string); + if (map_msg->dn == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + ret = ldb_msg_add_string(map_msg, "uidNumber", uid_string); + if (ret != LDB_SUCCESS) { + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + ret = idmap_msg_add_dom_sid(idmap_ctx, tmp_ctx, map_msg, "objectSid", + sid); + if (ret != LDB_SUCCESS) { + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + ret = ldb_msg_add_string(map_msg, "objectClass", "sidMap"); + if (ret != LDB_SUCCESS) { + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + ret = ldb_msg_add_string(map_msg, "cn", sid_string); + if (ret != LDB_SUCCESS) { + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + ret = ldb_add(ldb, map_msg); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Adding a sidmap failed: %s\n", ldb_errstring(ldb))); + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + trans = ldb_transaction_commit(ldb); + if (trans != LDB_SUCCESS) { + DEBUG(1, ("Transaction failed: %s\n", ldb_errstring(ldb))); + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + *uid = new_uid; + talloc_free(tmp_ctx); + return NT_STATUS_OK; + +failed: + if (trans == LDB_SUCCESS) ldb_transaction_cancel(ldb); + talloc_free(tmp_ctx); + return status; } /** diff --git a/source4/winbind/wb_sid2uid.c b/source4/winbind/wb_sid2uid.c index 449596ef38..0de45fdea9 100644 --- a/source4/winbind/wb_sid2uid.c +++ b/source4/winbind/wb_sid2uid.c @@ -3,7 +3,7 @@ Map a SID to a uid - Copyright (C) Kai Blin 2007 + Copyright (C) Kai Blin 2007-2008 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 @@ -25,6 +25,7 @@ #include "smbd/service_task.h" #include "winbind/wb_helper.h" #include "libcli/security/proto.h" +#include "winbind/idmap.h" struct sid2uid_state { struct composite_context *ctx; @@ -50,11 +51,13 @@ struct composite_context *wb_sid2uid_send(TALLOC_CTX *mem_ctx, result->private_data = state; state->service = service; - /*FIXME: This is a stub so far. */ - state->ctx->status = dom_sid_split_rid(result, sid, NULL, &state->uid); - if(!composite_is_ok(state->ctx)) return result; - - DEBUG(5, ("Rid is %d\n", state->uid)); + state->ctx->status = idmap_sid_to_uid(service->idmap_ctx, state, sid, + &state->uid); + if (NT_STATUS_EQUAL(state->ctx->status, NT_STATUS_RETRY)) { + state->ctx->status = idmap_sid_to_uid(service->idmap_ctx, state, + sid, &state->uid); + } + if (!composite_is_ok(state->ctx)) return result; composite_done(state->ctx); return result; -- cgit From 99b311449f494c0318127dc9140c4a22bb932884 Mon Sep 17 00:00:00 2001 From: Kai Blin Date: Mon, 18 Feb 2008 23:47:30 +0100 Subject: idmap: Handle SID->gid (This used to be commit 78d22a28eca4dd89f629dbe75287e9ac3940606b) --- source4/winbind/idmap.c | 257 ++++++++++++++++++++++++++++++++++++++++++- source4/winbind/wb_sid2gid.c | 11 +- 2 files changed, 263 insertions(+), 5 deletions(-) diff --git a/source4/winbind/idmap.c b/source4/winbind/idmap.c index 53276114dd..3372ad51ee 100644 --- a/source4/winbind/idmap.c +++ b/source4/winbind/idmap.c @@ -801,7 +801,7 @@ failed: * * If no mapping exist, a new mapping will be created. * - * \todo Create mappings for groups not from our primary domain. + * \todo Check if SID resolve when lp_idmap_trusted_only() == true * * \param idmap_ctx idmap context to use * \param mem_ctx talloc context to use @@ -814,6 +814,259 @@ failed: NTSTATUS idmap_sid_to_gid(struct idmap_context *idmap_ctx, TALLOC_CTX *mem_ctx, const struct dom_sid *sid, gid_t *gid) { - return NT_STATUS_NONE_MAPPED; + int ret; + NTSTATUS status = NT_STATUS_NONE_MAPPED; + struct ldb_context *ldb = idmap_ctx->ldb_ctx; + struct ldb_dn *dn; + struct ldb_message *hwm_msg, *map_msg; + struct ldb_result *res = NULL; + int trans = -1; + gid_t low, high, hwm, new_gid; + char *sid_string, *gid_string, *hwm_string; + bool hwm_entry_exists; + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + + ret = ldb_search_exp_fmt(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, + NULL, "(&(objectClass=sidMap)(objectSid=%s))", + ldap_encode_ndr_dom_sid(tmp_ctx, sid)); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb))); + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + if (res->count == 1) { + new_gid = ldb_msg_find_attr_as_uint(res->msgs[0], "gidNumber", + -1); + if (new_gid == (gid_t) -1) { + DEBUG(1, ("Invalid gid mapping.\n")); + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + *gid = new_gid; + talloc_free(tmp_ctx); + return NT_STATUS_OK; + } + + DEBUG(6, ("No existing mapping found, attempting to create one.\n")); + + trans = ldb_transaction_start(ldb); + if (trans != LDB_SUCCESS) { + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + /* Redo the search to make sure noone changed the mapping while we + * weren't looking */ + ret = ldb_search_exp_fmt(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, + NULL, "(&(objectClass=sidMap)(objectSid=%s))", + ldap_encode_ndr_dom_sid(tmp_ctx, sid)); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb))); + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + if (res->count > 0) { + DEBUG(1, ("Database changed while trying to add a sidmap.\n")); + status = NT_STATUS_RETRY; + goto failed; + } + + /*FIXME: if lp_idmap_trusted_only() == true, check if SID can be + * resolved here. */ + + ret = idmap_get_bounds(idmap_ctx, &low, &high); + if (ret != LDB_SUCCESS) { + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + dn = ldb_dn_new(tmp_ctx, ldb, "CN=CONFIG"); + if (dn == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + ret = ldb_search(ldb, dn, LDB_SCOPE_BASE, NULL, NULL, &res); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb))); + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + talloc_steal(tmp_ctx, res); + + if (res->count != 1) { + DEBUG(1, ("No CN=CONFIG record, idmap database is broken.\n")); + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + hwm = ldb_msg_find_attr_as_uint(res->msgs[0], "gidNumber", -1); + if (hwm == (gid_t)-1) { + hwm = low; + hwm_entry_exists = false; + } else { + hwm_entry_exists = true; + } + + if (hwm > high) { + DEBUG(1, ("Out of gids to allocate.\n")); + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + hwm_msg = ldb_msg_new(tmp_ctx); + if (hwm_msg == NULL) { + DEBUG(1, ("Out of memory when creating ldb_message\n")); + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + hwm_msg->dn = dn; + + new_gid = hwm; + hwm++; + + hwm_string = talloc_asprintf(tmp_ctx, "%u", hwm); + if (hwm_string == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + sid_string = dom_sid_string(tmp_ctx, sid); + if (sid_string == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + gid_string = talloc_asprintf(tmp_ctx, "%u", new_gid); + if (gid_string == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + if (hwm_entry_exists) { + struct ldb_message_element *els; + struct ldb_val *vals; + + /* We're modifying the entry, not just adding a new one. */ + els = talloc_array(tmp_ctx, struct ldb_message_element, 2); + if (els == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + vals = talloc_array(tmp_ctx, struct ldb_val, 2); + if (els == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + hwm_msg->num_elements = 2; + hwm_msg->elements = els; + + els[0].num_values = 1; + els[0].values = &vals[0]; + els[0].flags = LDB_FLAG_MOD_DELETE; + els[0].name = talloc_strdup(tmp_ctx, "gidNumber"); + if (els[0].name == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + els[1].num_values = 1; + els[1].values = &vals[1]; + els[1].flags = LDB_FLAG_MOD_ADD; + els[1].name = els[0].name; + + vals[0].data = (uint8_t *)gid_string; + vals[0].length = strlen(gid_string); + vals[1].data = (uint8_t *)hwm_string; + vals[1].length = strlen(hwm_string); + } else { + ret = ldb_msg_add_empty(hwm_msg, "gidNumber", LDB_FLAG_MOD_ADD, + NULL); + if (ret != LDB_SUCCESS) { + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + ret = ldb_msg_add_string(hwm_msg, "gidNumber", hwm_string); + if (ret != LDB_SUCCESS) + { + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + } + + ret = ldb_modify(ldb, hwm_msg); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Updating the gid high water mark failed: %s\n", + ldb_errstring(ldb))); + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + map_msg = ldb_msg_new(tmp_ctx); + if (map_msg == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + map_msg->dn = ldb_dn_new_fmt(tmp_ctx, ldb, "CN=%s", sid_string); + if (map_msg->dn == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + ret = ldb_msg_add_string(map_msg, "gidNumber", gid_string); + if (ret != LDB_SUCCESS) { + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + ret = idmap_msg_add_dom_sid(idmap_ctx, tmp_ctx, map_msg, "objectSid", + sid); + if (ret != LDB_SUCCESS) { + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + ret = ldb_msg_add_string(map_msg, "objectClass", "sidMap"); + if (ret != LDB_SUCCESS) { + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + ret = ldb_msg_add_string(map_msg, "cn", sid_string); + if (ret != LDB_SUCCESS) { + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + ret = ldb_add(ldb, map_msg); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Adding a sidmap failed: %s\n", ldb_errstring(ldb))); + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + trans = ldb_transaction_commit(ldb); + if (trans != LDB_SUCCESS) { + DEBUG(1, ("Transaction failed: %s\n", ldb_errstring(ldb))); + status = NT_STATUS_NONE_MAPPED; + goto failed; + } + + *gid = new_gid; + talloc_free(tmp_ctx); + return NT_STATUS_OK; + +failed: + if (trans == LDB_SUCCESS) ldb_transaction_cancel(ldb); + talloc_free(tmp_ctx); + return status; } diff --git a/source4/winbind/wb_sid2gid.c b/source4/winbind/wb_sid2gid.c index 8cb5608b2f..12129226be 100644 --- a/source4/winbind/wb_sid2gid.c +++ b/source4/winbind/wb_sid2gid.c @@ -25,6 +25,7 @@ #include "smbd/service_task.h" #include "winbind/wb_helper.h" #include "libcli/security/proto.h" +#include "winbind/idmap.h" struct sid2gid_state { struct composite_context *ctx; @@ -50,9 +51,13 @@ struct composite_context *wb_sid2gid_send(TALLOC_CTX *mem_ctx, result->private_data = state; state->service = service; - /*FIXME: This is a stub so far. */ - state->ctx->status = dom_sid_split_rid(result, sid, NULL, &state->gid); - if(!composite_is_ok(state->ctx)) return result; + state->ctx->status = idmap_sid_to_gid(service->idmap_ctx, state, sid, + &state->gid); + if (NT_STATUS_EQUAL(state->ctx->status, NT_STATUS_RETRY)) { + state->ctx->status = idmap_sid_to_gid(service->idmap_ctx, state, + sid, &state->gid); + } + if (!composite_is_ok(state->ctx)) return result; composite_done(state->ctx); return result; -- cgit From 52623b627ddcaf50347d5cb75c2f2490e73dfe29 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 15 Feb 2008 14:56:35 +0100 Subject: samr.idl: windows uses lsa_AsciiStringLarge in QueryDisplayInfo Tested with nt4 and w2k3. metze (This used to be commit 24ec069751ef8db1211c50e7ca1e527adaa6432c) --- source4/librpc/idl/samr.idl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source4/librpc/idl/samr.idl b/source4/librpc/idl/samr.idl index 2dc33fa9b9..3a11ab752c 100644 --- a/source4/librpc/idl/samr.idl +++ b/source4/librpc/idl/samr.idl @@ -960,7 +960,7 @@ import "misc.idl", "lsa.idl", "security.idl"; typedef struct { uint32 idx; - lsa_AsciiString account_name; + lsa_AsciiStringLarge account_name; } samr_DispEntryAscii; typedef struct { -- cgit From 9f4f4968317c92efee5db5b13f31cb5811c22e9f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 19 Feb 2008 16:40:48 +0100 Subject: srvsvc.idl: don't use STR_LEN4 anymore metze (This used to be commit 8c7509bd684ccdabcdb9ad9f75f3dd693ee9c416) --- source4/librpc/idl/srvsvc.idl | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/source4/librpc/idl/srvsvc.idl b/source4/librpc/idl/srvsvc.idl index 66c52fa43f..8ef49413bc 100644 --- a/source4/librpc/idl/srvsvc.idl +++ b/source4/librpc/idl/srvsvc.idl @@ -1127,7 +1127,16 @@ import "security.idl", "svcctl.idl"; /* srvsvc_NetDisk */ /**************************/ typedef struct { - [flag(STR_LEN4)] string disk; + /* + * In theory this should be: + * [charset(UTF16),string] uint16 annotation[3] + * But midl treats this as: + * [charset(UTF16),string] uint16 annotation[] + * and pidl doesn't support this yet + */ + [value(0)] uint32 __disk_offset; + [value(strlen(disk)+1)] uint32 __disk_length; + [charset(UTF16)] uint16 disk[__disk_length]; } srvsvc_NetDiskInfo0; typedef struct { -- cgit From e36b159e8c3d8b41823c09a612938cbf1b6e544b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 21 Feb 2008 15:51:40 +0100 Subject: ldb_sqlite: fix the build metze (This used to be commit 14c8e3101cc3b0138a551afdf3a94f4bb11bb21d) --- source4/lib/ldb/config.mk | 1 - source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/source4/lib/ldb/config.mk b/source4/lib/ldb/config.mk index 6027acd0c7..d6980f341a 100644 --- a/source4/lib/ldb/config.mk +++ b/source4/lib/ldb/config.mk @@ -99,7 +99,6 @@ OBJ_FILES = modules/skel.o SUBSYSTEM = LIBLDB CFLAGS = -Ilib/ldb/include PRIVATE_DEPENDENCIES = LIBTALLOC SQLITE3 LIBTALLOC -INIT_FUNCTION = &ldb_sqlite3_module_ops OBJ_FILES = \ ldb_sqlite3/ldb_sqlite3.o # End MODULE ldb_sqlite3 diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 214e7eec5f..8742e257f3 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -1903,7 +1903,7 @@ failed: return -1; } -_PUBLIC_ const struct ldb_backend_ops ldb_sqlite3_backend_ops = { +const struct ldb_backend_ops ldb_sqlite3_backend_ops = { .name = "sqlite3", .connect_fn = lsqlite3_connect }; -- cgit From 141f4b8f838f750b979eeef11743244008bfa339 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 21 Feb 2008 15:54:31 +0100 Subject: selftest: fix --socket-wrapper-pcap metze (This used to be commit f5ff4a571cdf7d00d065f4a4996880020f1f459f) --- source4/selftest/selftest.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source4/selftest/selftest.pl b/source4/selftest/selftest.pl index aa4423c7e2..73d03f3d4c 100755 --- a/source4/selftest/selftest.pl +++ b/source4/selftest/selftest.pl @@ -204,7 +204,7 @@ sub getlog_env($); sub setup_pcap($) { - my ($state, $name) = @_; + my ($name) = @_; return unless ($opt_socket_wrapper_pcap); return unless defined($ENV{SOCKET_WRAPPER_PCAP_DIR}); -- cgit