diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:20:00 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:20:00 +0000 |
commit | 8daa83a594a2e98f39d764422bfbdbc62c9efd44 (patch) | |
tree | 4099e8021376c7d8c05bdf8503093d80e9c7bad0 /source4/dsdb/samdb/samdb.c | |
parent | Initial commit. (diff) | |
download | samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.tar.xz samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.zip |
Adding upstream version 2:4.20.0+dfsg.upstream/2%4.20.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'source4/dsdb/samdb/samdb.c')
-rw-r--r-- | source4/dsdb/samdb/samdb.c | 344 |
1 files changed, 344 insertions, 0 deletions
diff --git a/source4/dsdb/samdb/samdb.c b/source4/dsdb/samdb/samdb.c new file mode 100644 index 0000000..42375a8 --- /dev/null +++ b/source4/dsdb/samdb/samdb.c @@ -0,0 +1,344 @@ +/* + Unix SMB/CIFS implementation. + + interface functions for the sam database + + Copyright (C) Andrew Tridgell 2004 + Copyright (C) Volker Lendecke 2004 + Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "librpc/gen_ndr/ndr_netlogon.h" +#include "librpc/gen_ndr/ndr_security.h" +#include "lib/events/events.h" +#include "lib/ldb-samba/ldb_wrap.h" +#include <ldb.h> +#include <ldb_errors.h> +#include "libcli/security/security.h" +#include "libcli/security/claims-conversions.h" +#include "libcli/auth/libcli_auth.h" +#include "libcli/ldap/ldap_ndr.h" +#include "system/time.h" +#include "system/filesys.h" +#include "ldb_wrap.h" +#include "../lib/util/util_ldb.h" +#include "dsdb/samdb/samdb.h" +#include "../libds/common/flags.h" +#include "param/param.h" +#include "lib/events/events.h" +#include "auth/credentials/credentials.h" +#include "param/secrets.h" +#include "auth/auth.h" +#include "lib/tsocket/tsocket.h" +#include "lib/param/loadparm.h" + +/* + connect to the SAM database specified by URL + return an opaque context pointer on success, or NULL on failure + */ +int samdb_connect_url(TALLOC_CTX *mem_ctx, + struct tevent_context *ev_ctx, + struct loadparm_context *lp_ctx, + struct auth_session_info *session_info, + unsigned int flags, + const char *url, + const struct tsocket_address *remote_address, + struct ldb_context **ldb_ret, + char **errstring) +{ + struct ldb_context *ldb = NULL; + int ret; + *ldb_ret = NULL; + *errstring = NULL; + + /* We create sam.ldb in provision, and never anywhere else */ + flags |= LDB_FLG_DONT_CREATE_DB; + + if (remote_address == NULL) { + ldb = ldb_wrap_find(url, ev_ctx, lp_ctx, + session_info, NULL, flags); + if (ldb != NULL) { + *ldb_ret = talloc_reference(mem_ctx, ldb); + if (*ldb_ret == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + return LDB_SUCCESS; + } + } + + ldb = samba_ldb_init(mem_ctx, ev_ctx, lp_ctx, session_info, NULL); + + if (ldb == NULL) { + *errstring = talloc_asprintf(mem_ctx, + "Failed to set up Samba ldb " + "wrappers with samba_ldb_init() " + "to connect to %s", + url); + return LDB_ERR_OPERATIONS_ERROR; + } + + dsdb_set_global_schema(ldb); + + ret = samba_ldb_connect(ldb, lp_ctx, url, flags); + if (ret != LDB_SUCCESS) { + *errstring = talloc_asprintf(mem_ctx, + "Failed to connect to %s: %s", + url, + ldb_errstring(ldb)); + talloc_free(ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* + * If a remote_address was specified, then set it on the DB + * and do not add to the wrap list (as we need to keep the LDB + * pointer unique for the address). + * + * We use this for audit logging and for the "netlogon" attribute + */ + if (remote_address != NULL) { + ldb_set_opaque(ldb, "remoteAddress", + discard_const(remote_address)); + *ldb_ret = ldb; + return LDB_SUCCESS; + } + + if (!ldb_wrap_add(url, ev_ctx, lp_ctx, session_info, NULL, flags, ldb)) { + *errstring = talloc_asprintf(mem_ctx, + "Failed to add cached DB reference" + " to %s", + url); + talloc_free(ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + + *ldb_ret = ldb; + return LDB_SUCCESS; +} + + +/* + connect to the SAM database + return an opaque context pointer on success, or NULL on failure + */ +struct ldb_context *samdb_connect(TALLOC_CTX *mem_ctx, + struct tevent_context *ev_ctx, + struct loadparm_context *lp_ctx, + struct auth_session_info *session_info, + const struct tsocket_address *remote_address, + unsigned int flags) +{ + char *errstring; + struct ldb_context *ldb; + int ret = samdb_connect_url(mem_ctx, + ev_ctx, + lp_ctx, + session_info, + flags, + "sam.ldb", + remote_address, + &ldb, + &errstring); + if (ret == LDB_SUCCESS) { + return ldb; + } + return NULL; +} + +/**************************************************************************** + Create the SID list for this user. +****************************************************************************/ +NTSTATUS security_token_create(TALLOC_CTX *mem_ctx, + struct loadparm_context *lp_ctx, + uint32_t num_sids, + const struct auth_SidAttr *sids, + uint32_t num_device_sids, + const struct auth_SidAttr *device_sids, + struct auth_claims auth_claims, + uint32_t session_info_flags, + struct security_token **token) +{ + struct security_token *ptoken; + uint32_t i; + NTSTATUS status; + enum claims_evaluation_control evaluate_claims; + bool sids_are_valid = false; + bool device_sids_are_valid = false; + bool authentication_was_compounded = session_info_flags & AUTH_SESSION_INFO_FORCE_COMPOUNDED_AUTHENTICATION; + + /* + * Some special-case callers can't supply the lp_ctx, but do + * not interact with claims or conditional ACEs + */ + if (lp_ctx == NULL) { + evaluate_claims = CLAIMS_EVALUATION_INVALID_STATE; + } else { + enum acl_claims_evaluation claims_evaultion_setting + = lpcfg_acl_claims_evaluation(lp_ctx); + + /* + * We are well inside the AD DC, so we do not need to check + * the server role etc + */ + switch (claims_evaultion_setting) { + case ACL_CLAIMS_EVALUATION_AD_DC_ONLY: + evaluate_claims = CLAIMS_EVALUATION_ALWAYS; + break; + default: + evaluate_claims = CLAIMS_EVALUATION_NEVER; + } + } + + ptoken = security_token_initialise(mem_ctx, evaluate_claims); + NT_STATUS_HAVE_NO_MEMORY(ptoken); + + if (num_sids > UINT32_MAX - 6) { + talloc_free(ptoken); + return NT_STATUS_INVALID_PARAMETER; + } + ptoken->sids = talloc_array(ptoken, struct dom_sid, num_sids + 6 /* over-allocate */); + if (ptoken->sids == NULL) { + talloc_free(ptoken); + return NT_STATUS_NO_MEMORY; + } + + ptoken->num_sids = 0; + + for (i = 0; i < num_sids; i++) { + uint32_t check_sid_idx; + for (check_sid_idx = 0; + check_sid_idx < ptoken->num_sids; + check_sid_idx++) { + if (dom_sid_equal(&ptoken->sids[check_sid_idx], &sids[i].sid)) { + break; + } + } + + if (check_sid_idx == ptoken->num_sids) { + const struct dom_sid *sid = &sids[i].sid; + + sids_are_valid = sids_are_valid || dom_sid_equal( + sid, &global_sid_Claims_Valid); + authentication_was_compounded = authentication_was_compounded || dom_sid_equal( + sid, &global_sid_Compounded_Authentication); + + ptoken->sids = talloc_realloc(ptoken, ptoken->sids, struct dom_sid, ptoken->num_sids + 1); + if (ptoken->sids == NULL) { + talloc_free(ptoken); + return NT_STATUS_NO_MEMORY; + } + + ptoken->sids[ptoken->num_sids] = *sid; + ptoken->num_sids++; + } + } + + if (authentication_was_compounded && num_device_sids) { + ptoken->device_sids = talloc_array(ptoken, struct dom_sid, num_device_sids); + if (ptoken->device_sids == NULL) { + talloc_free(ptoken); + return NT_STATUS_NO_MEMORY; + } + for (i = 0; i < num_device_sids; i++) { + uint32_t check_sid_idx; + for (check_sid_idx = 0; + check_sid_idx < ptoken->num_device_sids; + check_sid_idx++) { + if (dom_sid_equal(&ptoken->device_sids[check_sid_idx], &device_sids[i].sid)) { + break; + } + } + + if (check_sid_idx == ptoken->num_device_sids) { + const struct dom_sid *device_sid = &device_sids[i].sid; + + device_sids_are_valid = device_sids_are_valid || dom_sid_equal( + device_sid, &global_sid_Claims_Valid); + + ptoken->device_sids = talloc_realloc(ptoken, + ptoken->device_sids, + struct dom_sid, + ptoken->num_device_sids + 1); + if (ptoken->device_sids == NULL) { + talloc_free(ptoken); + return NT_STATUS_NO_MEMORY; + } + + ptoken->device_sids[ptoken->num_device_sids] = *device_sid; + ptoken->num_device_sids++; + } + } + } + + /* The caller may have requested simple privileges, for example if there isn't a local DB */ + if (session_info_flags & AUTH_SESSION_INFO_SIMPLE_PRIVILEGES) { + /* Shortcuts to prevent recursion and avoid lookups */ + if (ptoken->sids == NULL) { + ptoken->privilege_mask = 0; + } else if (security_token_is_system(ptoken)) { + ptoken->privilege_mask = ~0; + } else if (security_token_is_anonymous(ptoken)) { + ptoken->privilege_mask = 0; + } else if (security_token_has_builtin_administrators(ptoken)) { + ptoken->privilege_mask = ~0; + } else { + /* All other 'users' get a empty priv set so far */ + ptoken->privilege_mask = 0; + } + } else { + /* setup the privilege mask for this token */ + status = samdb_privilege_setup(lp_ctx, ptoken); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(ptoken); + DEBUG(1,("Unable to access privileges database\n")); + return status; + } + } + + /* + * TODO: we might want to regard ‘session_info_flags’ for the device + * SIDs as well as for the client SIDs. + */ + + if (sids_are_valid) { + status = claims_data_security_claims(ptoken, + auth_claims.user_claims, + &ptoken->user_claims, + &ptoken->num_user_claims); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(ptoken); + return status; + } + } + + if (device_sids_are_valid && authentication_was_compounded) { + status = claims_data_security_claims(ptoken, + auth_claims.device_claims, + &ptoken->device_claims, + &ptoken->num_device_claims); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(ptoken); + return status; + } + } + + security_token_debug(0, 10, ptoken); + + *token = ptoken; + + return NT_STATUS_OK; +} |