diff options
Diffstat (limited to 'source4/dsdb/samdb/samdb.c')
-rw-r--r-- | source4/dsdb/samdb/samdb.c | 296 |
1 files changed, 296 insertions, 0 deletions
diff --git a/source4/dsdb/samdb/samdb.c b/source4/dsdb/samdb/samdb.c new file mode 100644 index 0000000000..b5b7ddfdc6 --- /dev/null +++ b/source4/dsdb/samdb/samdb.c @@ -0,0 +1,296 @@ +/* + 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_misc.h" +#include "librpc/gen_ndr/ndr_security.h" +#include "lib/events/events.h" +#include "lib/ldb/include/ldb.h" +#include "lib/ldb/include/ldb_errors.h" +#include "libcli/security/security.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 "util/util_ldb.h" +#include "dsdb/samdb/samdb.h" +#include "dsdb/common/flags.h" +#include "param/param.h" +#include "lib/events/events.h" +#include "auth/credentials/credentials.h" +#include "param/secrets.h" + +char *samdb_relative_path(struct ldb_context *ldb, + TALLOC_CTX *mem_ctx, + const char *name) +{ + const char *base_url = + (const char *)ldb_get_opaque(ldb, "ldb_url"); + char *path, *p, *full_name; + if (name == NULL) { + return NULL; + } + if (name[0] == 0 || name[0] == '/' || strstr(name, ":/")) { + return talloc_strdup(mem_ctx, name); + } + path = talloc_strdup(mem_ctx, base_url); + if (path == NULL) { + return NULL; + } + if ( (p = strrchr(path, '/')) != NULL) { + p[0] = '\0'; + full_name = talloc_asprintf(mem_ctx, "%s/%s", path, name); + } else { + full_name = talloc_asprintf(mem_ctx, "./%s", name); + } + talloc_free(path); + return full_name; +} + +struct cli_credentials *samdb_credentials(TALLOC_CTX *mem_ctx, + struct event_context *event_ctx, + struct loadparm_context *lp_ctx) +{ + struct cli_credentials *cred = cli_credentials_init(mem_ctx); + if (!cred) { + return NULL; + } + cli_credentials_set_conf(cred, lp_ctx); + + /* We don't want to use krb5 to talk to our samdb - recursion + * here would be bad, and this account isn't in the KDC + * anyway */ + cli_credentials_set_kerberos_state(cred, CRED_DONT_USE_KERBEROS); + + if (!NT_STATUS_IS_OK(cli_credentials_set_secrets(cred, event_ctx, lp_ctx, NULL, NULL, + SECRETS_LDAP_FILTER))) { + /* Perfectly OK - if not against an LDAP backend */ + return NULL; + } + return cred; +} + +/* + 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 event_context *ev_ctx, + struct loadparm_context *lp_ctx, + struct auth_session_info *session_info) +{ + struct ldb_context *ldb; + ldb = ldb_wrap_connect(mem_ctx, ev_ctx, lp_ctx, + lp_sam_url(lp_ctx), session_info, + samdb_credentials(mem_ctx, ev_ctx, lp_ctx), + 0, NULL); + if (!ldb) { + return NULL; + } + dsdb_make_schema_global(ldb); + return ldb; +} + +/* + copy from a template record to a message +*/ +int samdb_copy_template(struct ldb_context *ldb, + struct ldb_message *msg, const char *name, + const char **errstring) +{ + struct ldb_result *res; + struct ldb_message *t; + int ret, i, j; + struct ldb_context *templates_ldb; + char *templates_ldb_path; + struct ldb_dn *basedn; + struct event_context *event_ctx; + struct loadparm_context *lp_ctx; + + templates_ldb = talloc_get_type(ldb_get_opaque(ldb, "templates_ldb"), struct ldb_context); + + if (!templates_ldb) { + templates_ldb_path = samdb_relative_path(ldb, + msg, + "templates.ldb"); + if (!templates_ldb_path) { + *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: Failed to contruct path for template db"); + return LDB_ERR_OPERATIONS_ERROR; + } + + event_ctx = ldb_get_event_context(ldb); + lp_ctx = (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"); + + /* FIXME: need to remove this wehn we finally pass the event + * context around in ldb */ + if (event_ctx == NULL) { + event_ctx = s4_event_context_init(templates_ldb); + } + + templates_ldb = ldb_wrap_connect(ldb, event_ctx, lp_ctx, + templates_ldb_path, NULL, + NULL, 0, NULL); + talloc_free(templates_ldb_path); + if (!templates_ldb) { + *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: Failed to connect to templates db at: %s", + templates_ldb_path); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_set_opaque(ldb, "templates_ldb", templates_ldb); + if (ret != LDB_SUCCESS) { + return ret; + } + } + *errstring = NULL; + + basedn = ldb_dn_new(templates_ldb, ldb, "cn=Templates"); + if (!ldb_dn_add_child_fmt(basedn, "CN=Template%s", name)) { + talloc_free(basedn); + *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: Failed to contruct DN for template '%s'", + name); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* pull the template record */ + ret = ldb_search(templates_ldb, basedn, LDB_SCOPE_BASE, "distinguishedName=*", NULL, &res); + talloc_free(basedn); + if (ret != LDB_SUCCESS) { + *errstring = talloc_steal(msg, ldb_errstring(templates_ldb)); + return ret; + } + if (res->count != 1) { + *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: template '%s' matched %d records, expected 1", + name, + res->count); + talloc_free(res); + return LDB_ERR_OPERATIONS_ERROR; + } + t = res->msgs[0]; + + for (i = 0; i < t->num_elements; i++) { + struct ldb_message_element *el = &t->elements[i]; + /* some elements should not be copied from the template */ + if (ldb_attr_cmp(el->name, "cn") == 0 || + ldb_attr_cmp(el->name, "name") == 0 || + ldb_attr_cmp(el->name, "objectClass") == 0 || + ldb_attr_cmp(el->name, "sAMAccountName") == 0 || + ldb_attr_cmp(el->name, "sAMAccountName") == 0 || + ldb_attr_cmp(el->name, "distinguishedName") == 0 || + ldb_attr_cmp(el->name, "objectGUID") == 0) { + continue; + } + for (j = 0; j < el->num_values; j++) { + ret = samdb_find_or_add_attribute(ldb, msg, el->name, + (char *)el->values[j].data); + if (ret) { + *errstring = talloc_asprintf(msg, "Adding attribute %s failed.", el->name); + talloc_free(res); + return ret; + } + } + } + + talloc_free(res); + + return LDB_SUCCESS; +} + + +/**************************************************************************** + Create the SID list for this user. +****************************************************************************/ +NTSTATUS security_token_create(TALLOC_CTX *mem_ctx, + struct event_context *ev_ctx, + struct loadparm_context *lp_ctx, + struct dom_sid *user_sid, + struct dom_sid *group_sid, + int n_groupSIDs, + struct dom_sid **groupSIDs, + bool is_authenticated, + struct security_token **token) +{ + struct security_token *ptoken; + int i; + NTSTATUS status; + + ptoken = security_token_initialise(mem_ctx); + NT_STATUS_HAVE_NO_MEMORY(ptoken); + + ptoken->sids = talloc_array(ptoken, struct dom_sid *, n_groupSIDs + 5); + NT_STATUS_HAVE_NO_MEMORY(ptoken->sids); + + ptoken->user_sid = talloc_reference(ptoken, user_sid); + ptoken->group_sid = talloc_reference(ptoken, group_sid); + ptoken->privilege_mask = 0; + + ptoken->sids[0] = ptoken->user_sid; + ptoken->sids[1] = ptoken->group_sid; + + /* + * Finally add the "standard" SIDs. + * The only difference between guest and "anonymous" + * is the addition of Authenticated_Users. + */ + ptoken->sids[2] = dom_sid_parse_talloc(ptoken->sids, SID_WORLD); + NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[2]); + ptoken->sids[3] = dom_sid_parse_talloc(ptoken->sids, SID_NT_NETWORK); + NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[3]); + ptoken->num_sids = 4; + + if (is_authenticated) { + ptoken->sids[4] = dom_sid_parse_talloc(ptoken->sids, SID_NT_AUTHENTICATED_USERS); + NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[4]); + ptoken->num_sids++; + } + + for (i = 0; i < n_groupSIDs; i++) { + size_t check_sid_idx; + for (check_sid_idx = 1; + check_sid_idx < ptoken->num_sids; + check_sid_idx++) { + if (dom_sid_equal(ptoken->sids[check_sid_idx], groupSIDs[i])) { + break; + } + } + + if (check_sid_idx == ptoken->num_sids) { + ptoken->sids[ptoken->num_sids++] = talloc_reference(ptoken->sids, groupSIDs[i]); + } + } + + /* setup the privilege mask for this token */ + status = samdb_privilege_setup(ev_ctx, lp_ctx, ptoken); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(ptoken); + return status; + } + + security_token_debug(10, ptoken); + + *token = ptoken; + + return NT_STATUS_OK; +} |