/* connect to the database */ static int lldb_connect(struct ldb_context *ldb, const char *url, unsigned int flags, const char *options[], struct ldb_module **_module) { struct ldb_module *module; struct lldb_private *lldb; int version = 3; int ret; module = ldb_module_new(ldb, ldb, "ldb_ldap backend", &lldb_ops); if (!module) return LDB_ERR_OPERATIONS_ERROR; lldb = talloc_zero(module, struct lldb_private); if (!lldb) { ldb_oom(ldb); goto failed; } ldb_module_set_private(module, lldb); ret = ldap_initialize(&lldb->ldap, url); if (ret != LDAP_SUCCESS) { ldb_debug(ldb, LDB_DEBUG_FATAL, "ldap_initialize failed for URL '%s' - %s", url, ldap_err2string(ret)); goto failed; } talloc_set_destructor(lldb, lldb_destructor); ret = ldap_set_option(lldb->ldap, LDAP_OPT_PROTOCOL_VERSION, &version); if (ret != LDAP_SUCCESS) { ldb_debug(ldb, LDB_DEBUG_FATAL, "ldap_set_option failed - %s", ldap_err2string(ret)); goto failed; } *_module = module; ret = lldb_bind(module, options); if (ret != LDB_SUCCESS) { goto failed; } return LDB_SUCCESS; failed: talloc_free(module); return LDB_ERR_OPERATIONS_ERROR; }
/* Split message elements that stay in the local partition from those * that are mapped into the remote partition. */ static int ldb_msg_partition(struct ldb_module *module, enum ldb_request_type optype, struct ldb_message *local, struct ldb_message *remote, const struct ldb_message *msg) { /* const char * const names[]; */ struct ldb_context *ldb; unsigned int i; int ret; ldb = ldb_module_get_ctx(module); for (i = 0; i < msg->num_elements; i++) { /* Skip 'IS_MAPPED' */ if (ldb_attr_cmp(msg->elements[i].name, IS_MAPPED) == 0) { ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb_map: " "Skipping attribute '%s'", msg->elements[i].name); continue; } ret = ldb_msg_el_partition(module, optype, local, remote, msg, msg->elements[i].name, &msg->elements[i]); if (ret) { return ret; } } return 0; }
static void ltdb_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) { va_list ap; const char *name = tdb_name(tdb); struct ldb_context *ldb = talloc_get_type(tdb_get_logging_private(tdb), struct ldb_context); enum ldb_debug_level ldb_level; char *message; if (ldb == NULL) return; va_start(ap, fmt); message = talloc_vasprintf(ldb, fmt, ap); va_end(ap); switch (level) { case TDB_DEBUG_FATAL: ldb_level = LDB_DEBUG_FATAL; break; case TDB_DEBUG_ERROR: ldb_level = LDB_DEBUG_ERROR; break; case TDB_DEBUG_WARNING: ldb_level = LDB_DEBUG_WARNING; break; case TDB_DEBUG_TRACE: ldb_level = LDB_DEBUG_TRACE; break; default: ldb_level = LDB_DEBUG_FATAL; } ldb_debug(ldb, ldb_level, "ltdb: tdb(%s): %s", name, message); talloc_free(message); }
/* search the domain related to the provided dn allocate a new RID for the domain return the new sid string */ static int samldb_get_new_sid(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn *obj_dn, struct dom_sid **sid) { const char * const attrs[2] = { "objectSid", NULL }; struct ldb_result *res = NULL; struct ldb_dn *dom_dn; int ret; struct dom_sid *dom_sid; /* get the domain component part of the provided dn */ dom_dn = samldb_search_domain(module, mem_ctx, obj_dn); if (dom_dn == NULL) { ldb_asprintf_errstring(module->ldb, "Invalid dn (%s) not child of a domain object!\n", ldb_dn_get_linearized(obj_dn)); return LDB_ERR_CONSTRAINT_VIOLATION; } /* find the domain sid */ ret = ldb_search(module->ldb, dom_dn, LDB_SCOPE_BASE, "objectSid=*", attrs, &res); if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(module->ldb, "samldb_get_new_sid: error retrieving domain sid from %s: %s!\n", ldb_dn_get_linearized(dom_dn), ldb_errstring(module->ldb)); talloc_free(res); return ret; } if (res->count != 1) { ldb_asprintf_errstring(module->ldb, "samldb_get_new_sid: error retrieving domain sid from %s: not found!\n", ldb_dn_get_linearized(dom_dn)); talloc_free(res); return LDB_ERR_CONSTRAINT_VIOLATION; } dom_sid = samdb_result_dom_sid(res, res->msgs[0], "objectSid"); if (dom_sid == NULL) { ldb_set_errstring(module->ldb, "samldb_get_new_sid: error parsing domain sid!\n"); talloc_free(res); return LDB_ERR_CONSTRAINT_VIOLATION; } /* allocate a new Rid for the domain */ ret = samldb_allocate_next_rid(module, mem_ctx, dom_dn, dom_sid, sid); if (ret != 0) { ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Failed to increment nextRid of %s: %s\n", ldb_dn_get_linearized(dom_dn), ldb_errstring(module->ldb)); talloc_free(res); return ret; } talloc_free(res); return ret; }
int ldb_try_load_dso(struct ldb_context *ldb, const char *name) { char *path; void *handle; int (*init_fn) (void); char *modulesdir; #ifdef HAVE_DLOPEN if (getenv("LD_LDB_MODULE_PATH") != NULL) { modulesdir = talloc_strdup(ldb, getenv("LD_LDB_MODULE_PATH")); } else { #ifdef _SAMBA_BUILD_ modulesdir = talloc_asprintf(ldb, "%s/ldb", dyn_MODULESDIR); #else modulesdir = talloc_strdup(ldb, MODULESDIR); #endif } path = talloc_asprintf(ldb, "%s/%s.%s", modulesdir, name, SHLIBEXT); talloc_free(modulesdir); ldb_debug(ldb, LDB_DEBUG_TRACE, "trying to load %s from %s\n", name, path); handle = dlopen(path, RTLD_NOW); if (handle == NULL) { ldb_debug(ldb, LDB_DEBUG_WARNING, "unable to load %s from %s: %s\n", name, path, dlerror()); return -1; } init_fn = (int (*)(void))dlsym(handle, "init_module"); if (init_fn == NULL) { ldb_debug(ldb, LDB_DEBUG_ERROR, "no symbol `init_module' found in %s: %s\n", path, dlerror()); return -1; } talloc_free(path); return init_fn(); #else ldb_debug(ldb, LDB_DEBUG_TRACE, "no dlopen() - not trying to load %s module\n", name); return -1; #endif }
static struct ldb_val lookup_homedir(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val) { struct passwd *pwd; struct ldb_val retval; pwd = getpwnam((char *)val->data); if (!pwd) { ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Unable to lookup '%s' in passwd", (char *)val->data); return *talloc_zero(ctx, struct ldb_val); }
/* TODO: free old DNs and messages? */ int ldb_next_remote_request(struct ldb_module *module, struct ldb_request *request) { const struct ldb_map_context *data = map_get_context(module); struct ldb_context *ldb; struct ldb_message *msg; ldb = ldb_module_get_ctx(module); switch (request->operation) { case LDB_SEARCH: if (request->op.search.base) { request->op.search.base = ldb_dn_rebase_remote(request, data, request->op.search.base); } else { request->op.search.base = data->remote_base_dn; /* TODO: adjust scope? */ } break; case LDB_ADD: msg = ldb_msg_copy_shallow(request, request->op.add.message); if (msg == NULL) { return LDB_ERR_OPERATIONS_ERROR; } msg->dn = ldb_dn_rebase_remote(msg, data, msg->dn); request->op.add.message = msg; break; case LDB_MODIFY: msg = ldb_msg_copy_shallow(request, request->op.mod.message); if (msg == NULL) { return LDB_ERR_OPERATIONS_ERROR; } msg->dn = ldb_dn_rebase_remote(msg, data, msg->dn); request->op.mod.message = msg; break; case LDB_DELETE: request->op.del.dn = ldb_dn_rebase_remote(request, data, request->op.del.dn); break; case LDB_RENAME: request->op.rename.olddn = ldb_dn_rebase_remote(request, data, request->op.rename.olddn); request->op.rename.newdn = ldb_dn_rebase_remote(request, data, request->op.rename.newdn); break; default: ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: " "Invalid remote request!"); return LDB_ERR_OPERATIONS_ERROR; } return ldb_next_request(module, request); }
/* allocate a new id, attempting to do it atomically return 0 on failure, the id on success */ static int samldb_set_next_rid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn, uint32_t old_id, uint32_t new_id) { struct ldb_message msg; int ret; struct ldb_val vals[2]; struct ldb_message_element els[2]; if (new_id == 0) { /* out of IDs ! */ ldb_debug(ldb, LDB_DEBUG_FATAL, "Are we out of valid IDs ?\n"); return LDB_ERR_OPERATIONS_ERROR; } /* we do a delete and add as a single operation. That prevents a race, in case we are not actually on a transaction db */ ZERO_STRUCT(msg); msg.dn = ldb_dn_copy(mem_ctx, dn); if (!msg.dn) { return LDB_ERR_OPERATIONS_ERROR; } msg.num_elements = 2; 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(mem_ctx, "nextRid"); if (!els[0].name) { return LDB_ERR_OPERATIONS_ERROR; } 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 *)talloc_asprintf(mem_ctx, "%u", old_id); if (!vals[0].data) { return LDB_ERR_OPERATIONS_ERROR; } vals[0].length = strlen((char *)vals[0].data); vals[1].data = (uint8_t *)talloc_asprintf(mem_ctx, "%u", new_id); if (!vals[1].data) { return LDB_ERR_OPERATIONS_ERROR; } vals[1].length = strlen((char *)vals[1].data); ret = ldb_modify(ldb, &msg); return ret; }
int ldb_init_module_chain(struct ldb_context *ldb, struct ldb_module *module) { while (module && module->ops->init_context == NULL) module = module->next; if (module && module->ops->init_context && module->ops->init_context(module) != LDB_SUCCESS) { ldb_debug(ldb, LDB_DEBUG_FATAL, "module initialization failed\n"); return LDB_ERR_OPERATIONS_ERROR; } return LDB_SUCCESS; }
/* log a message, and set the ldb error string to the same message */ void ldb_debug_set(struct ldb_context *ldb, enum ldb_debug_level level, const char *fmt, ...) { va_list ap; char *msg; va_start(ap, fmt); msg = talloc_vasprintf(ldb, fmt, ap); va_end(ap); if (msg != NULL) { ldb_set_errstring(ldb, msg); ldb_debug(ldb, level, "%s", msg); } talloc_free(msg); }
static int validate_update_message(struct ldb_context *ldb, struct dsdb_schema *schema, const struct ldb_message *msg) { int i; for (i=0; i < msg->num_elements; i++) { WERROR werr; werr = dsdb_attribute_validate_ldb(ldb, schema, &msg->elements[i]); if (!W_ERROR_IS_OK(werr)) { int j; ldb_debug(ldb, LDB_DEBUG_ERROR, "TODO: object[%s] add/modify attribute[%d|%s] num_values[%d] - %s\n", ldb_dn_get_linearized(msg->dn), i, msg->elements[i].name, msg->elements[i].num_values, win_errstr(werr)); for (j=0; j < msg->elements[i].num_values; j++) { ldb_debug(ldb, LDB_DEBUG_ERROR, "TODO: value[%d] len[%d]\n", j, msg->elements[i].values[j].length); dump_data(0, msg->elements[i].values[j].data, msg->elements[i].values[j].length); } return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; } } return LDB_SUCCESS; }
static int subtree_delete_init(struct ldb_module *module) { struct ldb_context *ldb; int ret; ldb = ldb_module_get_ctx(module); ret = ldb_mod_register_control(module, LDB_CONTROL_TREE_DELETE_OID); if (ret != LDB_SUCCESS) { ldb_debug(ldb, LDB_DEBUG_ERROR, "subtree_delete: Unable to register control with rootdse!\n"); return ldb_operr(ldb); } return ldb_next_init(module); }
static int wins_ldb_verify(struct ldb_module *module, struct ldb_request *req) { struct ldb_context *ldb = ldb_module_get_ctx(module); struct winsdb_handle *h = talloc_get_type(ldb_get_opaque(ldb, "winsdb_handle"), struct winsdb_handle); const struct ldb_message *msg; switch (req->operation) { case LDB_ADD: msg = req->op.add.message; break; case LDB_MODIFY: msg = req->op.mod.message; break; default: return ldb_next_request(module, req); } /* do not manipulate our control entries */ if (ldb_dn_is_special(msg->dn)) { return ldb_next_request(module, req); } if (!h) { ldb_debug_set(ldb, LDB_DEBUG_FATAL, "%s", "WINS_LDB: INTERNAL ERROR: no winsdb_handle present!"); return LDB_ERR_OTHER; } switch (h->caller) { case WINSDB_HANDLE_CALLER_NBTD: case WINSDB_HANDLE_CALLER_WREPL: /* we trust our nbt and wrepl code ... */ return ldb_next_request(module, req); case WINSDB_HANDLE_CALLER_ADMIN: ldb_debug(ldb, LDB_DEBUG_WARNING, "%s\n", "WINS_LDB: TODO verify add/modify for WINSDB_HANDLE_CALLER_ADMIN"); return ldb_next_request(module, req); } return LDB_ERR_OTHER; }
static void ltdb_log_fn(struct tdb_context *tdb, enum tdb_log_level level, const char *message, struct ldb_context *ldb) { enum ldb_debug_level ldb_level; const char *name = tdb_name(tdb); switch (level) { case TDB_LOG_WARNING: ldb_level = LDB_DEBUG_WARNING; case TDB_LOG_USE_ERROR: case TDB_LOG_ERROR: ldb_level = LDB_DEBUG_FATAL; break; default: ldb_level = LDB_DEBUG_FATAL; } ldb_debug(ldb, ldb_level, "ltdb: tdb(%s): %s", name, message); }
/* we've made a modification to a dn - possibly reindex and update sequence number */ static int ltdb_modified(struct ldb_module *module, struct ldb_dn *dn) { int ret = LDB_SUCCESS; struct ltdb_private *ltdb = talloc_get_type(ldb_module_get_private(module), struct ltdb_private); /* only allow modifies inside a transaction, otherwise the * ldb is unsafe */ if (ltdb->in_transaction == 0) { ldb_set_errstring(ldb_module_get_ctx(module), "ltdb modify without transaction"); return LDB_ERR_OPERATIONS_ERROR; } if (ldb_dn_is_special(dn) && (ldb_dn_check_special(dn, LTDB_INDEXLIST) || ldb_dn_check_special(dn, LTDB_ATTRIBUTES)) ) { if (ltdb->warn_reindex) { ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR, "Reindexing %s due to modification on %s", tdb_name(ltdb->tdb), ldb_dn_get_linearized(dn)); } ret = ltdb_reindex(module); } /* If the modify was to a normal record, or any special except @BASEINFO, update the seq number */ if (ret == LDB_SUCCESS && !(ldb_dn_is_special(dn) && ldb_dn_check_special(dn, LTDB_BASEINFO)) ) { ret = ltdb_increase_sequence_number(module); } /* If the modify was to @OPTIONS, reload the cache */ if (ret == LDB_SUCCESS && ldb_dn_is_special(dn) && (ldb_dn_check_special(dn, LTDB_OPTIONS)) ) { ret = ltdb_cache_reload(module); } return ret; }
/* Split message elements that stay in the local partition from those * that are mapped into the remote partition. */ static int ldb_msg_partition(struct ldb_module *module, struct ldb_message *local, struct ldb_message *remote, const struct ldb_message *msg) { /* const char * const names[]; */ int i, ret; for (i = 0; i < msg->num_elements; i++) { /* Skip 'IS_MAPPED' */ if (ldb_attr_cmp(msg->elements[i].name, IS_MAPPED) == 0) { ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: " "Skipping attribute '%s'\n", msg->elements[i].name); continue; } ret = ldb_msg_el_partition(module, local, remote, msg, msg->elements[i].name, &msg->elements[i]); if (ret) { return ret; } } return 0; }
/* deny instancetype modification */ static int instancetype_mod(struct ldb_module *module, struct ldb_request *req) { struct ldb_context *ldb = ldb_module_get_ctx(module); struct ldb_message_element *el; /* do not manipulate our control entries */ if (ldb_dn_is_special(req->op.mod.message->dn)) { return ldb_next_request(module, req); } ldb_debug(ldb, LDB_DEBUG_TRACE, "instancetype_mod\n"); el = ldb_msg_find_element(req->op.mod.message, "instanceType"); if (el != NULL) { /* Except to allow dbcheck to fix things, this must never be modified */ if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) { ldb_set_errstring(ldb, "instancetype: the 'instanceType' attribute can never be changed!"); return LDB_ERR_CONSTRAINT_VIOLATION; } } return ldb_next_request(module, req); }
int ldb_load_modules_list(struct ldb_context *ldb, const char **module_list, struct ldb_module *backend, struct ldb_module **out) { struct ldb_module *module; int i; module = backend; for (i = 0; module_list[i] != NULL; i++) { struct ldb_module *current; const struct ldb_module_ops *ops; ops = ldb_find_module_ops(module_list[i]); if (ops == NULL) { if (ldb_try_load_dso(ldb, module_list[i]) == 0) { ops = ldb_find_module_ops(module_list[i]); } } if (ops == NULL) { ldb_debug(ldb, LDB_DEBUG_WARNING, "WARNING: Module [%s] not found\n", module_list[i]); continue; } current = talloc_zero(ldb, struct ldb_module); if (current == NULL) { return LDB_ERR_OPERATIONS_ERROR; } talloc_set_name(current, "ldb_module: %s", module_list[i]); current->ldb = ldb; current->ops = ops; DLIST_ADD(module, current); } *out = module; return LDB_SUCCESS; }
int ldb_load_modules(struct ldb_context *ldb, const char *options[]) { const char **modules = NULL; int i; int ret; TALLOC_CTX *mem_ctx = talloc_new(ldb); if (!mem_ctx) { return LDB_ERR_OPERATIONS_ERROR; } /* find out which modules we are requested to activate */ /* check if we have a custom module list passd as ldb option */ if (options) { for (i = 0; options[i] != NULL; i++) { if (strncmp(options[i], LDB_MODULE_PREFIX, LDB_MODULE_PREFIX_LEN) == 0) { modules = ldb_modules_list_from_string(ldb, mem_ctx, &options[i][LDB_MODULE_PREFIX_LEN]); } } } /* if not overloaded by options and the backend is not ldap try to load the modules list from ldb */ if ((modules == NULL) && (strcmp("ldap", ldb->modules->ops->name) != 0)) { const char * const attrs[] = { "@LIST" , NULL}; struct ldb_result *res = NULL; struct ldb_dn *mods_dn; mods_dn = ldb_dn_new(mem_ctx, ldb, "@MODULES"); if (mods_dn == NULL) { talloc_free(mem_ctx); return -1; } ret = ldb_search(ldb, mods_dn, LDB_SCOPE_BASE, "", attrs, &res); talloc_steal(mods_dn, res); if (ret == LDB_SUCCESS && (res->count == 0 || res->msgs[0]->num_elements == 0)) { ldb_debug(ldb, LDB_DEBUG_TRACE, "no modules required by the db\n"); } else { if (ret != LDB_SUCCESS) { ldb_debug(ldb, LDB_DEBUG_FATAL, "ldb error (%s) occurred searching for modules, bailing out\n", ldb_errstring(ldb)); talloc_free(mem_ctx); return -1; } if (res->count > 1) { ldb_debug(ldb, LDB_DEBUG_FATAL, "Too many records found (%d), bailing out\n", res->count); talloc_free(mem_ctx); return -1; } modules = ldb_modules_list_from_string(ldb, mem_ctx, (const char *)res->msgs[0]->elements[0].values[0].data); } talloc_free(mods_dn); } if (modules != NULL) { ret = ldb_load_modules_list(ldb, modules, ldb->modules, &ldb->modules); talloc_free(modules); if (ret != LDB_SUCCESS) { return ret; } } else { ldb_debug(ldb, LDB_DEBUG_TRACE, "No modules specified for this database\n"); } return ldb_init_module_chain(ldb, ldb->modules); }
/* connect to the database */ static int ltdb_connect(struct ldb_context *ldb, const char *url, unsigned int flags, const char *options[], struct ldb_module **_module) { struct ldb_module *module; const char *path; int tdb_flags, open_flags; struct ltdb_private *ltdb; /* parse the url */ if (strchr(url, ':')) { if (strncmp(url, "tdb://", 6) != 0) { ldb_debug(ldb, LDB_DEBUG_ERROR, "Invalid tdb URL '%s'", url); return LDB_ERR_OPERATIONS_ERROR; } path = url+6; } else { path = url; } tdb_flags = TDB_DEFAULT | TDB_SEQNUM; /* check for the 'nosync' option */ if (flags & LDB_FLG_NOSYNC) { tdb_flags |= TDB_NOSYNC; } /* and nommap option */ if (flags & LDB_FLG_NOMMAP) { tdb_flags |= TDB_NOMMAP; } if (flags & LDB_FLG_RDONLY) { open_flags = O_RDONLY; } else { open_flags = O_CREAT | O_RDWR; } ltdb = talloc_zero(ldb, struct ltdb_private); if (!ltdb) { ldb_oom(ldb); return LDB_ERR_OPERATIONS_ERROR; } /* note that we use quite a large default hash size */ ltdb->tdb = ltdb_wrap_open(ltdb, path, 10000, tdb_flags, open_flags, ldb_get_create_perms(ldb), ldb); if (!ltdb->tdb) { ldb_asprintf_errstring(ldb, "Unable to open tdb '%s': %s", path, strerror(errno)); ldb_debug(ldb, LDB_DEBUG_ERROR, "Unable to open tdb '%s': %s", path, strerror(errno)); talloc_free(ltdb); if (errno == EACCES || errno == EPERM) { return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; } return LDB_ERR_OPERATIONS_ERROR; } if (getenv("LDB_WARN_UNINDEXED")) { ltdb->warn_unindexed = true; } if (getenv("LDB_WARN_REINDEX")) { ltdb->warn_reindex = true; } ltdb->sequence_number = 0; module = ldb_module_new(ldb, ldb, "ldb_tdb backend", <db_ops); if (!module) { ldb_oom(ldb); talloc_free(ltdb); return LDB_ERR_OPERATIONS_ERROR; } ldb_module_set_private(module, ltdb); talloc_steal(module, ltdb); if (ltdb_cache_load(module) != 0) { ldb_asprintf_errstring(ldb, "Unable to load ltdb cache records of tdb '%s'", path); talloc_free(module); return LDB_ERR_OPERATIONS_ERROR; } *_module = module; return LDB_SUCCESS; }
/* Add a message element either to a local or to a remote message, * depending on whether it goes into the local or remote partition. */ static int ldb_msg_el_partition(struct ldb_module *module, struct ldb_message *local, struct ldb_message *remote, const struct ldb_message *msg, const char *attr_name, /* const char * const names[], */ const struct ldb_message_element *old) { const struct ldb_map_context *data = map_get_context(module); const struct ldb_map_attribute *map = map_attr_find_local(data, attr_name); struct ldb_message_element *el=NULL; /* Unknown attribute: ignore */ if (map == NULL) { ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: " "Not mapping attribute '%s': no mapping found\n", old->name); goto local; } switch (map->type) { case MAP_IGNORE: goto local; case MAP_CONVERT: if (map->u.convert.convert_local == NULL) { ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: " "Not mapping attribute '%s': " "'convert_local' not set\n", map->local_name); goto local; } /* fall through */ case MAP_KEEP: case MAP_RENAME: el = ldb_msg_el_map_local(module, remote, map, old); break; case MAP_GENERATE: if (map->u.generate.generate_remote == NULL) { ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: " "Not mapping attribute '%s': " "'generate_remote' not set\n", map->local_name); goto local; } /* TODO: if this attr requires context: * make sure all context attrs are mappable (in 'names') * make sure all context attrs have already been mapped? * maybe postpone generation until they have been mapped? */ map->u.generate.generate_remote(module, map->local_name, msg, remote, local); return 0; } if (el == NULL) { return -1; } return ldb_msg_add(remote, el, old->flags); local: el = talloc(local, struct ldb_message_element); if (el == NULL) { map_oom(module); return -1; } *el = *old; /* copy the old element */ return ldb_msg_add(local, el, old->flags); }
/* Map a DN into the local partition. */ struct ldb_dn *ldb_dn_map_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_dn *dn) { const struct ldb_map_context *data = map_get_context(module); struct ldb_dn *newdn; const struct ldb_map_attribute *map; enum ldb_map_attr_type map_type; const char *name; struct ldb_val value; int i, ret; if (dn == NULL) { return NULL; } newdn = ldb_dn_copy(mem_ctx, dn); if (newdn == NULL) { map_oom(module); return NULL; } /* For each RDN, map the component name and possibly the value */ for (i = 0; i < ldb_dn_get_comp_num(newdn); i++) { map = map_attr_find_remote(data, ldb_dn_get_component_name(dn, i)); /* Unknown attribute - leave this RDN as is and hope the best... */ if (map == NULL) { map_type = MAP_KEEP; } else { map_type = map->type; } switch (map_type) { case MAP_IGNORE: case MAP_GENERATE: ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " "MAP_IGNORE/MAP_GENERATE attribute '%s' " "used in DN!\n", ldb_dn_get_component_name(dn, i)); goto failed; case MAP_CONVERT: if (map->u.convert.convert_remote == NULL) { ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " "'convert_remote' not set for attribute '%s' " "used in DN!\n", ldb_dn_get_component_name(dn, i)); goto failed; } /* fall through */ case MAP_KEEP: case MAP_RENAME: name = map_attr_map_remote(newdn, map, ldb_dn_get_component_name(dn, i)); if (name == NULL) goto failed; value = ldb_val_map_remote(module, newdn, map, ldb_dn_get_component_val(dn, i)); if (value.data == NULL) goto failed; ret = ldb_dn_set_component(newdn, i, name, value); if (ret != LDB_SUCCESS) { goto failed; } break; } } return newdn; failed: talloc_free(newdn); return NULL; }
static int samldb_add(struct ldb_module *module, struct ldb_request *req) { const struct ldb_message *msg = req->op.add.message; struct ldb_message *msg2 = NULL; struct ldb_request *down_req; int ret; ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_add_record\n"); if (ldb_dn_is_special(msg->dn)) { /* do not manipulate our control entries */ return ldb_next_request(module, req); } /* is user or computer? */ if ((samdb_find_attribute(module->ldb, msg, "objectclass", "user") != NULL) || (samdb_find_attribute(module->ldb, msg, "objectclass", "computer") != NULL)) { /* add all relevant missing objects */ ret = samldb_fill_user_or_computer_object(module, msg, &msg2); if (ret) { return ret; } } /* is group? add all relevant missing objects */ if ( ! msg2 ) { if (samdb_find_attribute(module->ldb, msg, "objectclass", "group") != NULL) { ret = samldb_fill_group_object(module, msg, &msg2); if (ret) { return ret; } } } /* perhaps a foreignSecurityPrincipal? */ if ( ! msg2 ) { if (samdb_find_attribute(module->ldb, msg, "objectclass", "foreignSecurityPrincipal") != NULL) { ret = samldb_fill_foreignSecurityPrincipal_object(module, msg, &msg2); if (ret) { return ret; } } } if (msg2 == NULL) { return ldb_next_request(module, req); } down_req = talloc(req, struct ldb_request); if (down_req == NULL) { return LDB_ERR_OPERATIONS_ERROR; } *down_req = *req; down_req->op.add.message = talloc_steal(down_req, msg2); ldb_set_timeout_from_prev_req(module->ldb, req, down_req); /* go on with the call chain */ ret = ldb_next_request(module, down_req); /* do not free down_req as the call results may be linked to it, * it will be freed when the upper level request get freed */ if (ret == LDB_SUCCESS) { req->handle = down_req->handle; } return ret; }
static int samldb_fill_foreignSecurityPrincipal_object(struct ldb_module *module, const struct ldb_message *msg, struct ldb_message **ret_msg) { struct ldb_message *msg2; const char *rdn_name; struct dom_sid *dom_sid; struct dom_sid *sid; const char *dom_attrs[] = { "name", NULL }; struct ldb_message **dom_msgs; const char *errstr; int ret; TALLOC_CTX *mem_ctx = talloc_new(msg); if (!mem_ctx) { return LDB_ERR_OPERATIONS_ERROR; } /* build the new msg */ msg2 = ldb_msg_copy(mem_ctx, msg); if (!msg2) { ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_foreignSecurityPrincpal_object: ldb_msg_copy failed!\n"); talloc_free(mem_ctx); return LDB_ERR_OPERATIONS_ERROR; } ret = samdb_copy_template(module->ldb, msg2, "(&(CN=TemplateForeignSecurityPrincipal)(objectclass=foreignSecurityPrincipalTemplate))", &errstr); if (ret != 0) { ldb_asprintf_errstring(module->ldb, "samldb_fill_foreignSecurityPrincipal_object: " "Error copying template: %s", errstr); talloc_free(mem_ctx); return ret; } rdn_name = ldb_dn_get_rdn_name(msg2->dn); if (strcasecmp(rdn_name, "cn") != 0) { ldb_asprintf_errstring(module->ldb, "Bad RDN (%s=) for ForeignSecurityPrincipal, should be CN=!", rdn_name); talloc_free(mem_ctx); return LDB_ERR_CONSTRAINT_VIOLATION; } /* Slightly different for the foreign sids. We don't want * domain SIDs ending up there, it would cause all sorts of * pain */ sid = dom_sid_parse_talloc(msg2, (const char *)ldb_dn_get_rdn_val(msg2->dn)->data); if (!sid) { ldb_set_errstring(module->ldb, "No valid found SID in ForeignSecurityPrincipal CN!"); talloc_free(mem_ctx); return LDB_ERR_CONSTRAINT_VIOLATION; } if ( ! samldb_msg_add_sid(module, msg2, "objectSid", sid)) { talloc_free(sid); return LDB_ERR_OPERATIONS_ERROR; } dom_sid = dom_sid_dup(mem_ctx, sid); if (!dom_sid) { talloc_free(mem_ctx); return LDB_ERR_OPERATIONS_ERROR; } /* get the domain component part of the provided SID */ dom_sid->num_auths--; /* find the domain DN */ ret = gendb_search(module->ldb, mem_ctx, NULL, &dom_msgs, dom_attrs, "(&(objectSid=%s)(objectclass=domain))", ldap_encode_ndr_dom_sid(mem_ctx, dom_sid)); if (ret >= 1) { /* We don't really like the idea of foreign sids that are not foreign, but it happens */ const char *name = samdb_result_string(dom_msgs[0], "name", NULL); ldb_debug(module->ldb, LDB_DEBUG_TRACE, "NOTE (strange but valid): Adding foreign SID record with SID %s, but this domian (%s) is already in the database", dom_sid_string(mem_ctx, sid), name); } else if (ret == -1) { ldb_asprintf_errstring(module->ldb, "samldb_fill_foreignSecurityPrincipal_object: error searching for a domain with this sid: %s\n", dom_sid_string(mem_ctx, dom_sid)); talloc_free(dom_msgs); return LDB_ERR_OPERATIONS_ERROR; } /* This isn't an operation on a domain we know about, so just * check for the SID, looking for duplicates via the common * code */ ret = samldb_notice_sid(module, msg2, sid); if (ret == 0) { talloc_steal(msg, msg2); *ret_msg = msg2; } return ret; }
static int samldb_fill_user_or_computer_object(struct ldb_module *module, const struct ldb_message *msg, struct ldb_message **ret_msg) { int ret; char *name; struct ldb_message *msg2; const char *rdn_name; TALLOC_CTX *mem_ctx = talloc_new(msg); const char *errstr; if (!mem_ctx) { return LDB_ERR_OPERATIONS_ERROR; } /* build the new msg */ msg2 = ldb_msg_copy(mem_ctx, msg); if (!msg2) { ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: ldb_msg_copy failed!\n"); talloc_free(mem_ctx); return LDB_ERR_OPERATIONS_ERROR; } if (samdb_find_attribute(module->ldb, msg, "objectclass", "computer") != NULL) { ret = samdb_copy_template(module->ldb, msg2, "(&(CN=TemplateComputer)(objectclass=userTemplate))", &errstr); if (ret) { ldb_asprintf_errstring(module->ldb, "samldb_fill_user_or_computer_object: " "Error copying computer template: %s", errstr); talloc_free(mem_ctx); return ret; } /* readd user and then computer objectclasses */ ret = samdb_find_or_add_value(module->ldb, msg2, "objectclass", "user"); if (ret) { talloc_free(mem_ctx); return ret; } ret = samdb_find_or_add_value(module->ldb, msg2, "objectclass", "computer"); if (ret) { talloc_free(mem_ctx); return ret; } } else { ret = samdb_copy_template(module->ldb, msg2, "(&(CN=TemplateUser)(objectclass=userTemplate))", &errstr); if (ret) { ldb_asprintf_errstring(module->ldb, "samldb_fill_user_or_computer_object: Error copying user template: %s\n", errstr); talloc_free(mem_ctx); return ret; } /* readd user objectclass */ ret = samdb_find_or_add_value(module->ldb, msg2, "objectclass", "user"); if (ret) { talloc_free(mem_ctx); return ret; } } rdn_name = ldb_dn_get_rdn_name(msg2->dn); if (strcasecmp(rdn_name, "cn") != 0) { ldb_asprintf_errstring(module->ldb, "Bad RDN (%s=) for user/computer, should be CN=!\n", rdn_name); talloc_free(mem_ctx); return LDB_ERR_CONSTRAINT_VIOLATION; } if (ldb_msg_find_element(msg2, "samAccountName") == NULL) { name = samldb_generate_samAccountName(module, mem_ctx); if (!name) { talloc_free(mem_ctx); return LDB_ERR_OPERATIONS_ERROR; } ret = samdb_find_or_add_attribute(module->ldb, msg2, "sAMAccountName", name); if (ret) { talloc_free(mem_ctx); return ret; } } /* TODO: useraccountcontrol: setting value 0 gives 0x200 for users */ /* Manage SID allocation, conflicts etc */ ret = samldb_handle_sid(module, mem_ctx, msg2); /* TODO: objectCategory, userAccountControl, badPwdCount, codePage, countryCode, badPasswordTime, lastLogoff, lastLogon, pwdLastSet, primaryGroupID, accountExpires, logonCount */ if (ret == 0) { *ret_msg = msg2; talloc_steal(msg, msg2); } talloc_free(mem_ctx); return ret; }
static int samldb_fill_group_object(struct ldb_module *module, const struct ldb_message *msg, struct ldb_message **ret_msg) { int ret; const char *name; struct ldb_message *msg2; const char *rdn_name; TALLOC_CTX *mem_ctx = talloc_new(msg); const char *errstr; if (!mem_ctx) { return LDB_ERR_OPERATIONS_ERROR; } /* build the new msg */ msg2 = ldb_msg_copy(mem_ctx, msg); if (!msg2) { ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: ldb_msg_copy failed!\n"); talloc_free(mem_ctx); return LDB_ERR_OPERATIONS_ERROR; } ret = samdb_copy_template(module->ldb, msg2, "(&(CN=TemplateGroup)(objectclass=groupTemplate))", &errstr); if (ret != 0) { talloc_free(mem_ctx); return ret; } rdn_name = ldb_dn_get_rdn_name(msg2->dn); if (strcasecmp(rdn_name, "cn") != 0) { ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: Bad RDN (%s) for group!\n", rdn_name); talloc_free(mem_ctx); return LDB_ERR_CONSTRAINT_VIOLATION; } /* Generate a random name, if no samAccountName was supplied */ if (ldb_msg_find_element(msg2, "samAccountName") == NULL) { name = samldb_generate_samAccountName(module, mem_ctx); if (!name) { talloc_free(mem_ctx); return LDB_ERR_OPERATIONS_ERROR; } ret = samdb_find_or_add_attribute(module->ldb, msg2, "sAMAccountName", name); if (ret) { talloc_free(mem_ctx); return ret; } } /* Manage SID allocation, conflicts etc */ ret = samldb_handle_sid(module, mem_ctx, msg2); if (ret == LDB_SUCCESS) { talloc_steal(msg, msg2); *ret_msg = msg2; } talloc_free(mem_ctx); return ret; }
/* extended match, handles things like bitops */ static int ldb_match_extended(struct ldb_context *ldb, const struct ldb_message *msg, const struct ldb_parse_tree *tree, enum ldb_scope scope, bool *matched) { unsigned int i; const struct { const char *oid; int (*comparator)(const char *, const struct ldb_val *, const struct ldb_val *, bool *); } rules[] = { { LDB_OID_COMPARATOR_AND, ldb_comparator_bitmask}, { LDB_OID_COMPARATOR_OR, ldb_comparator_bitmask}, { SAMBA_LDAP_MATCH_ALWAYS_FALSE, ldb_comparator_false} }; int (*comp)(const char *,const struct ldb_val *, const struct ldb_val *, bool *) = NULL; struct ldb_message_element *el; if (tree->u.extended.dnAttributes) { /* FIXME: We really need to find out what this ":dn" part in * an extended match means and how to handle it. For now print * only a warning to have s3 winbind and other tools working * against us. - Matthias */ ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb: dnAttributes extended match not supported yet"); } if (tree->u.extended.rule_id == NULL) { ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-rule extended matches not supported yet"); return LDB_ERR_INAPPROPRIATE_MATCHING; } if (tree->u.extended.attr == NULL) { ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-attribute extended matches not supported yet"); return LDB_ERR_INAPPROPRIATE_MATCHING; } for (i=0;i<ARRAY_SIZE(rules);i++) { if (strcmp(rules[i].oid, tree->u.extended.rule_id) == 0) { comp = rules[i].comparator; break; } } if (comp == NULL) { ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: unknown extended rule_id %s", tree->u.extended.rule_id); return LDB_ERR_INAPPROPRIATE_MATCHING; } /* find the message element */ el = ldb_msg_find_element(msg, tree->u.extended.attr); if (el == NULL) { *matched = false; return LDB_SUCCESS; } for (i=0;i<el->num_values;i++) { int ret = comp(tree->u.extended.rule_id, &el->values[i], &tree->u.extended.value, matched); if (ret != LDB_SUCCESS) return ret; if (*matched) return LDB_SUCCESS; } *matched = false; return LDB_SUCCESS; }
static int acl_module_init(struct ldb_module *module) { struct ldb_context *ldb; struct acl_private *data; int ret, i; TALLOC_CTX *mem_ctx = talloc_new(module); static const char *attrs[] = { "passwordAttribute", NULL }; struct ldb_result *res; struct ldb_message *msg; struct ldb_message_element *password_attributes; ldb = ldb_module_get_ctx(module); ret = ldb_mod_register_control(module, LDB_CONTROL_SD_FLAGS_OID); if (ret != LDB_SUCCESS) { ldb_debug(ldb, LDB_DEBUG_ERROR, "acl_module_init: Unable to register control with rootdse!\n"); return LDB_ERR_OPERATIONS_ERROR; } data = talloc(module, struct acl_private); if (data == NULL) { ldb_oom(ldb); return LDB_ERR_OPERATIONS_ERROR; } data->password_attrs = NULL; data->acl_perform = lp_parm_bool(ldb_get_opaque(ldb, "loadparm"), NULL, "acl", "perform", false); ldb_module_set_private(module, data); if (!mem_ctx) { ldb_oom(ldb); return LDB_ERR_OPERATIONS_ERROR; } ret = ldb_search(ldb, mem_ctx, &res, ldb_dn_new(mem_ctx, ldb, "@KLUDGEACL"), LDB_SCOPE_BASE, attrs, NULL); if (ret != LDB_SUCCESS) { goto done; } if (res->count == 0) { goto done; } if (res->count > 1) { talloc_free(mem_ctx); return LDB_ERR_CONSTRAINT_VIOLATION; } msg = res->msgs[0]; password_attributes = ldb_msg_find_element(msg, "passwordAttribute"); if (!password_attributes) { goto done; } data->password_attrs = talloc_array(data, const char *, password_attributes->num_values + 1); if (!data->password_attrs) { talloc_free(mem_ctx); ldb_oom(ldb); return LDB_ERR_OPERATIONS_ERROR; } for (i=0; i < password_attributes->num_values; i++) { data->password_attrs[i] = (const char *)password_attributes->values[i].data; talloc_steal(data->password_attrs, password_attributes->values[i].data); } data->password_attrs[i] = NULL; done: talloc_free(mem_ctx); return ldb_next_init(module); }
static int pdc_fsmo_init(struct ldb_module *module) { struct ldb_context *ldb; TALLOC_CTX *mem_ctx; struct ldb_dn *pdc_dn; struct dsdb_pdc_fsmo *pdc_fsmo; struct ldb_result *pdc_res; int ret; static const char *pdc_attrs[] = { "fSMORoleOwner", NULL }; ldb = ldb_module_get_ctx(module); mem_ctx = talloc_new(module); if (!mem_ctx) { return ldb_oom(ldb); } pdc_dn = ldb_get_default_basedn(ldb); if (!pdc_dn) { ldb_debug_set(ldb, LDB_DEBUG_FATAL, "pdc_fsmo_init: could not determine default basedn"); talloc_free(mem_ctx); return LDB_ERR_OPERATIONS_ERROR; } pdc_fsmo = talloc_zero(mem_ctx, struct dsdb_pdc_fsmo); if (!pdc_fsmo) { return ldb_oom(ldb); } ldb_module_set_private(module, pdc_fsmo); ret = dsdb_module_search_dn(module, mem_ctx, &pdc_res, pdc_dn, pdc_attrs, DSDB_FLAG_NEXT_MODULE, NULL); if (ret == LDB_ERR_NO_SUCH_OBJECT) { ldb_debug(ldb, LDB_DEBUG_TRACE, "pdc_fsmo_init: no domain object present: (skip loading of domain details)"); talloc_free(mem_ctx); return ldb_next_init(module); } else if (ret != LDB_SUCCESS) { ldb_debug_set(ldb, LDB_DEBUG_FATAL, "pdc_fsmo_init: failed to search the domain object: %d:%s: %s", ret, ldb_strerror(ret), ldb_errstring(ldb)); talloc_free(mem_ctx); return ret; } pdc_fsmo->master_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, pdc_res->msgs[0], "fSMORoleOwner"); if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc_fsmo->master_dn) == 0) { pdc_fsmo->we_are_master = true; } else { pdc_fsmo->we_are_master = false; } if (ldb_set_opaque(ldb, "dsdb_pdc_fsmo", pdc_fsmo) != LDB_SUCCESS) { return ldb_oom(ldb); } talloc_steal(module, pdc_fsmo); ldb_debug(ldb, LDB_DEBUG_TRACE, "pdc_fsmo_init: we are master: %s\n", (pdc_fsmo->we_are_master?"yes":"no")); talloc_free(mem_ctx); return ldb_next_init(module); }
/* * @brief Load the keys into the encrypted secrets module context. * * @param module the current ldb module * @param data the private data for the current module * * Currently the keys are stored in a binary file in the same directory * as the database. * * @return an LDB result code. * */ static int load_keys(struct ldb_module *module, struct es_data *data) { const char *key_dir = NULL; const char *key_path = NULL; struct ldb_context *ldb = NULL; FILE *fp = NULL; const int key_size = 16; int read; DATA_BLOB key = data_blob_null; TALLOC_CTX *frame = talloc_stackframe(); ldb = ldb_module_get_ctx(module); key_dir = get_key_directory(frame, ldb); if (key_dir == NULL) { TALLOC_FREE(frame); return LDB_ERR_OPERATIONS_ERROR; } key_path = talloc_asprintf(frame, "%s/%s", key_dir, SECRETS_KEY_FILE); if (key_path == NULL) { TALLOC_FREE(frame); return ldb_oom(ldb); } key = data_blob_talloc_zero(module, key_size); key.length = key_size; fp = fopen(key_path, "rb"); if (fp == NULL) { TALLOC_FREE(frame); data_blob_free(&key); if (errno == ENOENT) { ldb_debug(ldb, LDB_DEBUG_WARNING, "No encrypted secrets key file. " "Secret attributes will not be encrypted or " "decrypted\n"); data->encrypt_secrets = false; return LDB_SUCCESS; } else { log_error(ldb, errno, "Opening encrypted_secrets key file\n"); return LDB_ERR_OPERATIONS_ERROR; } } read = fread(key.data, 1, key.length, fp); fclose(fp); if (read == 0) { TALLOC_FREE(frame); ldb_debug(ldb, LDB_DEBUG_WARNING, "Zero length encrypted secrets key file. " "Secret attributes will not be encrypted or " "decrypted\n"); data->encrypt_secrets = false; return LDB_SUCCESS; } if (read != key.length) { TALLOC_FREE(frame); if (errno) { log_error(ldb, errno, "Reading encrypted_secrets key file\n"); } else { ldb_debug(ldb, LDB_DEBUG_ERROR, "Invalid encrypted_secrets key file, " "only %d bytes read should be %d bytes\n", read, key_size); } return LDB_ERR_OPERATIONS_ERROR; } data->keys[0] = key; data->encrypt_secrets = true; #ifdef BUILD_WITH_GNUTLS_AEAD data->encryption_algorithm = GNUTLS_CIPHER_AES_128_GCM; #endif TALLOC_FREE(frame); return LDB_SUCCESS; }