| 1 | /*
|
|---|
| 2 | Unix SMB/CIFS implementation.
|
|---|
| 3 |
|
|---|
| 4 | LDB wrap functions
|
|---|
| 5 |
|
|---|
| 6 | Copyright (C) Andrew Tridgell 2004
|
|---|
| 7 |
|
|---|
| 8 | This program is free software; you can redistribute it and/or modify
|
|---|
| 9 | it under the terms of the GNU General Public License as published by
|
|---|
| 10 | the Free Software Foundation; either version 3 of the License, or
|
|---|
| 11 | (at your option) any later version.
|
|---|
| 12 |
|
|---|
| 13 | This program is distributed in the hope that it will be useful,
|
|---|
| 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|---|
| 16 | GNU General Public License for more details.
|
|---|
| 17 |
|
|---|
| 18 | You should have received a copy of the GNU General Public License
|
|---|
| 19 | along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|---|
| 20 | */
|
|---|
| 21 |
|
|---|
| 22 | /*
|
|---|
| 23 | the stupidity of the unix fcntl locking design forces us to never
|
|---|
| 24 | allow a database file to be opened twice in the same process. These
|
|---|
| 25 | wrappers provide convenient access to a tdb or ldb, taking advantage
|
|---|
| 26 | of talloc destructors to ensure that only a single open is done
|
|---|
| 27 | */
|
|---|
| 28 |
|
|---|
| 29 | #include "includes.h"
|
|---|
| 30 | #include "lib/events/events.h"
|
|---|
| 31 | #include "lib/ldb/include/ldb.h"
|
|---|
| 32 | #include "lib/ldb/include/ldb_errors.h"
|
|---|
| 33 | #include "lib/ldb-samba/ldif_handlers.h"
|
|---|
| 34 | #include "ldb_wrap.h"
|
|---|
| 35 | #include "dsdb/samdb/samdb.h"
|
|---|
| 36 | #include "param/param.h"
|
|---|
| 37 |
|
|---|
| 38 | /*
|
|---|
| 39 | this is used to catch debug messages from ldb
|
|---|
| 40 | */
|
|---|
| 41 | static void ldb_wrap_debug(void *context, enum ldb_debug_level level,
|
|---|
| 42 | const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0);
|
|---|
| 43 |
|
|---|
| 44 | static void ldb_wrap_debug(void *context, enum ldb_debug_level level,
|
|---|
| 45 | const char *fmt, va_list ap)
|
|---|
| 46 | {
|
|---|
| 47 | int samba_level = -1;
|
|---|
| 48 | char *s = NULL;
|
|---|
| 49 | switch (level) {
|
|---|
| 50 | case LDB_DEBUG_FATAL:
|
|---|
| 51 | samba_level = 0;
|
|---|
| 52 | break;
|
|---|
| 53 | case LDB_DEBUG_ERROR:
|
|---|
| 54 | samba_level = 1;
|
|---|
| 55 | break;
|
|---|
| 56 | case LDB_DEBUG_WARNING:
|
|---|
| 57 | samba_level = 2;
|
|---|
| 58 | break;
|
|---|
| 59 | case LDB_DEBUG_TRACE:
|
|---|
| 60 | samba_level = 5;
|
|---|
| 61 | break;
|
|---|
| 62 |
|
|---|
| 63 | };
|
|---|
| 64 | vasprintf(&s, fmt, ap);
|
|---|
| 65 | if (!s) return;
|
|---|
| 66 | DEBUG(samba_level, ("ldb: %s\n", s));
|
|---|
| 67 | free(s);
|
|---|
| 68 | }
|
|---|
| 69 |
|
|---|
| 70 | /* check for memory leaks on the ldb context */
|
|---|
| 71 | static int ldb_wrap_destructor(struct ldb_context *ldb)
|
|---|
| 72 | {
|
|---|
| 73 | size_t *startup_blocks = (size_t *)ldb_get_opaque(ldb, "startup_blocks");
|
|---|
| 74 |
|
|---|
| 75 | if (startup_blocks &&
|
|---|
| 76 | talloc_total_blocks(ldb) > *startup_blocks + 400) {
|
|---|
| 77 | DEBUG(0,("WARNING: probable memory leak in ldb %s - %lu blocks (startup %lu) %lu bytes\n",
|
|---|
| 78 | (char *)ldb_get_opaque(ldb, "wrap_url"),
|
|---|
| 79 | (unsigned long)talloc_total_blocks(ldb),
|
|---|
| 80 | (unsigned long)*startup_blocks,
|
|---|
| 81 | (unsigned long)talloc_total_size(ldb)));
|
|---|
| 82 | #if 0
|
|---|
| 83 | talloc_report_full(ldb, stdout);
|
|---|
| 84 | call_backtrace();
|
|---|
| 85 | smb_panic("probable memory leak in ldb");
|
|---|
| 86 | #endif
|
|---|
| 87 | }
|
|---|
| 88 | return 0;
|
|---|
| 89 | }
|
|---|
| 90 |
|
|---|
| 91 | /*
|
|---|
| 92 | wrapped connection to a ldb database
|
|---|
| 93 | to close just talloc_free() the returned ldb_context
|
|---|
| 94 |
|
|---|
| 95 | TODO: We need an error_string parameter
|
|---|
| 96 | */
|
|---|
| 97 | struct ldb_context *ldb_wrap_connect(TALLOC_CTX *mem_ctx,
|
|---|
| 98 | struct tevent_context *ev,
|
|---|
| 99 | struct loadparm_context *lp_ctx,
|
|---|
| 100 | const char *url,
|
|---|
| 101 | struct auth_session_info *session_info,
|
|---|
| 102 | struct cli_credentials *credentials,
|
|---|
| 103 | unsigned int flags,
|
|---|
| 104 | const char *options[])
|
|---|
| 105 | {
|
|---|
| 106 | struct ldb_context *ldb;
|
|---|
| 107 | int ret;
|
|---|
| 108 | char *real_url = NULL;
|
|---|
| 109 | size_t *startup_blocks;
|
|---|
| 110 |
|
|---|
| 111 | /* we want to use the existing event context if possible. This
|
|---|
| 112 | relies on the fact that in smbd, everything is a child of
|
|---|
| 113 | the main event_context */
|
|---|
| 114 | if (ev == NULL) {
|
|---|
| 115 | return NULL;
|
|---|
| 116 | }
|
|---|
| 117 |
|
|---|
| 118 | ldb = ldb_init(mem_ctx, ev);
|
|---|
| 119 | if (ldb == NULL) {
|
|---|
| 120 | return NULL;
|
|---|
| 121 | }
|
|---|
| 122 |
|
|---|
| 123 | ldb_set_modules_dir(ldb,
|
|---|
| 124 | talloc_asprintf(ldb,
|
|---|
| 125 | "%s/ldb",
|
|---|
| 126 | lp_modulesdir(lp_ctx)));
|
|---|
| 127 |
|
|---|
| 128 | if (ldb_set_opaque(ldb, "sessionInfo", session_info)) {
|
|---|
| 129 | talloc_free(ldb);
|
|---|
| 130 | return NULL;
|
|---|
| 131 | }
|
|---|
| 132 |
|
|---|
| 133 | if (ldb_set_opaque(ldb, "credentials", credentials)) {
|
|---|
| 134 | talloc_free(ldb);
|
|---|
| 135 | return NULL;
|
|---|
| 136 | }
|
|---|
| 137 |
|
|---|
| 138 | if (ldb_set_opaque(ldb, "loadparm", lp_ctx)) {
|
|---|
| 139 | talloc_free(ldb);
|
|---|
| 140 | return NULL;
|
|---|
| 141 | }
|
|---|
| 142 |
|
|---|
| 143 | /* This must be done before we load the schema, as these
|
|---|
| 144 | * handlers for objectSid and objectGUID etc must take
|
|---|
| 145 | * precedence over the 'binary attribute' declaration in the
|
|---|
| 146 | * schema */
|
|---|
| 147 | ret = ldb_register_samba_handlers(ldb);
|
|---|
| 148 | if (ret == -1) {
|
|---|
| 149 | talloc_free(ldb);
|
|---|
| 150 | return NULL;
|
|---|
| 151 | }
|
|---|
| 152 |
|
|---|
| 153 | if (lp_ctx != NULL && strcmp(lp_sam_url(lp_ctx), url) == 0) {
|
|---|
| 154 | dsdb_set_global_schema(ldb);
|
|---|
| 155 | }
|
|---|
| 156 |
|
|---|
| 157 | ldb_set_debug(ldb, ldb_wrap_debug, NULL);
|
|---|
| 158 |
|
|---|
| 159 | ldb_set_utf8_fns(ldb, NULL, wrap_casefold);
|
|---|
| 160 |
|
|---|
| 161 | real_url = private_path(ldb, lp_ctx, url);
|
|---|
| 162 | if (real_url == NULL) {
|
|---|
| 163 | talloc_free(ldb);
|
|---|
| 164 | return NULL;
|
|---|
| 165 | }
|
|---|
| 166 |
|
|---|
| 167 | /* allow admins to force non-sync ldb for all databases */
|
|---|
| 168 | if (lp_parm_bool(lp_ctx, NULL, "ldb", "nosync", false)) {
|
|---|
| 169 | flags |= LDB_FLG_NOSYNC;
|
|---|
| 170 | }
|
|---|
| 171 |
|
|---|
| 172 | if (DEBUGLVL(10)) {
|
|---|
| 173 | flags |= LDB_FLG_ENABLE_TRACING;
|
|---|
| 174 | }
|
|---|
| 175 |
|
|---|
| 176 | /* we usually want Samba databases to be private. If we later
|
|---|
| 177 | find we need one public, we will need to add a parameter to
|
|---|
| 178 | ldb_wrap_connect() */
|
|---|
| 179 | ldb_set_create_perms(ldb, 0600);
|
|---|
| 180 |
|
|---|
| 181 | ret = ldb_connect(ldb, real_url, flags, options);
|
|---|
| 182 | if (ret != LDB_SUCCESS) {
|
|---|
| 183 | talloc_free(ldb);
|
|---|
| 184 | return NULL;
|
|---|
| 185 | }
|
|---|
| 186 |
|
|---|
| 187 | /* setup for leak detection */
|
|---|
| 188 | ldb_set_opaque(ldb, "wrap_url", real_url);
|
|---|
| 189 | startup_blocks = talloc(ldb, size_t);
|
|---|
| 190 | *startup_blocks = talloc_total_blocks(ldb);
|
|---|
| 191 | ldb_set_opaque(ldb, "startup_blocks", startup_blocks);
|
|---|
| 192 |
|
|---|
| 193 | talloc_set_destructor(ldb, ldb_wrap_destructor);
|
|---|
| 194 |
|
|---|
| 195 | return ldb;
|
|---|
| 196 | }
|
|---|