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*/ 41static void ldb_wrap_debug(void *context, enum ldb_debug_level level, 42 const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0); 43 44static 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 */ 71static 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 */ 97struct 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} 197