1/* 2 ldb database library - command line handling for ldb tools 3 4 Copyright (C) Andrew Tridgell 2005 5 6 ** NOTE! The following LGPL license applies to the ldb 7 ** library. This does NOT imply that all of Samba is released 8 ** under the LGPL 9 10 This library is free software; you can redistribute it and/or 11 modify it under the terms of the GNU Lesser General Public 12 License as published by the Free Software Foundation; either 13 version 3 of the License, or (at your option) any later version. 14 15 This library is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 Lesser General Public License for more details. 19 20 You should have received a copy of the GNU Lesser General Public 21 License along with this library; if not, see <http://www.gnu.org/licenses/>. 22*/ 23 24#include "ldb_includes.h" 25#include "ldb.h" 26#include "tools/cmdline.h" 27 28#if (_SAMBA_BUILD_ >= 4) 29#include "includes.h" 30#include "lib/cmdline/popt_common.h" 31#include "lib/ldb-samba/ldif_handlers.h" 32#include "auth/gensec/gensec.h" 33#include "auth/auth.h" 34#include "ldb_wrap.h" 35#include "param/param.h" 36#endif 37 38static struct ldb_cmdline options; /* needs to be static for older compilers */ 39 40static struct poptOption popt_options[] = { 41 POPT_AUTOHELP 42 { "url", 'H', POPT_ARG_STRING, &options.url, 0, "database URL", "URL" }, 43 { "basedn", 'b', POPT_ARG_STRING, &options.basedn, 0, "base DN", "DN" }, 44 { "editor", 'e', POPT_ARG_STRING, &options.editor, 0, "external editor", "PROGRAM" }, 45 { "scope", 's', POPT_ARG_STRING, NULL, 's', "search scope", "SCOPE" }, 46 { "verbose", 'v', POPT_ARG_NONE, NULL, 'v', "increase verbosity", NULL }, 47 { "trace", 0, POPT_ARG_NONE, &options.tracing, 0, "enable tracing", NULL }, 48 { "interactive", 'i', POPT_ARG_NONE, &options.interactive, 0, "input from stdin", NULL }, 49 { "recursive", 'r', POPT_ARG_NONE, &options.recursive, 0, "recursive delete", NULL }, 50 { "modules-path", 0, POPT_ARG_STRING, &options.modules_path, 0, "modules path", "PATH" }, 51 { "num-searches", 0, POPT_ARG_INT, &options.num_searches, 0, "number of test searches", NULL }, 52 { "num-records", 0, POPT_ARG_INT, &options.num_records, 0, "number of test records", NULL }, 53 { "all", 'a', POPT_ARG_NONE, &options.all_records, 0, "(|(objectClass=*)(distinguishedName=*))", NULL }, 54 { "nosync", 0, POPT_ARG_NONE, &options.nosync, 0, "non-synchronous transactions", NULL }, 55 { "sorted", 'S', POPT_ARG_NONE, &options.sorted, 0, "sort attributes", NULL }, 56 { "input", 'I', POPT_ARG_STRING, &options.input, 0, "Input File", "Input" }, 57 { "output", 'O', POPT_ARG_STRING, &options.output, 0, "Output File", "Output" }, 58 { NULL, 'o', POPT_ARG_STRING, NULL, 'o', "ldb_connect option", "OPTION" }, 59 { "controls", 0, POPT_ARG_STRING, NULL, 'c', "controls", NULL }, 60 { "show-binary", 0, POPT_ARG_NONE, &options.show_binary, 0, "display binary LDIF", NULL }, 61#if (_SAMBA_BUILD_ >= 4) 62 POPT_COMMON_SAMBA 63 POPT_COMMON_CREDENTIALS 64 POPT_COMMON_CONNECTION 65 POPT_COMMON_VERSION 66#endif 67 { NULL } 68}; 69 70void ldb_cmdline_help(const char *cmdname, FILE *f) 71{ 72 poptContext pc; 73 pc = poptGetContext(cmdname, 0, NULL, popt_options, 74 POPT_CONTEXT_KEEP_FIRST); 75 poptPrintHelp(pc, f, 0); 76} 77 78/** 79 process command line options 80*/ 81struct ldb_cmdline *ldb_cmdline_process(struct ldb_context *ldb, 82 int argc, const char **argv, 83 void (*usage)(void)) 84{ 85 struct ldb_cmdline *ret=NULL; 86 poptContext pc; 87#if (_SAMBA_BUILD_ >= 4) 88 int r; 89#endif 90 int num_options = 0; 91 int opt; 92 int flags = 0; 93 94#if (_SAMBA_BUILD_ >= 4) 95 r = ldb_register_samba_handlers(ldb); 96 if (r != 0) { 97 goto failed; 98 } 99 100#endif 101 102 ret = talloc_zero(ldb, struct ldb_cmdline); 103 if (ret == NULL) { 104 fprintf(stderr, "Out of memory!\n"); 105 goto failed; 106 } 107 108 options = *ret; 109 110 /* pull in URL */ 111 options.url = getenv("LDB_URL"); 112 113 /* and editor (used by ldbedit) */ 114 options.editor = getenv("VISUAL"); 115 if (!options.editor) { 116 options.editor = getenv("EDITOR"); 117 } 118 if (!options.editor) { 119 options.editor = "vi"; 120 } 121 122 options.scope = LDB_SCOPE_DEFAULT; 123 124 pc = poptGetContext(argv[0], argc, argv, popt_options, 125 POPT_CONTEXT_KEEP_FIRST); 126 127 while((opt = poptGetNextOpt(pc)) != -1) { 128 switch (opt) { 129 case 's': { 130 const char *arg = poptGetOptArg(pc); 131 if (strcmp(arg, "base") == 0) { 132 options.scope = LDB_SCOPE_BASE; 133 } else if (strcmp(arg, "sub") == 0) { 134 options.scope = LDB_SCOPE_SUBTREE; 135 } else if (strcmp(arg, "one") == 0) { 136 options.scope = LDB_SCOPE_ONELEVEL; 137 } else { 138 fprintf(stderr, "Invalid scope '%s'\n", arg); 139 goto failed; 140 } 141 break; 142 } 143 144 case 'v': 145 options.verbose++; 146 break; 147 148 case 'o': 149 options.options = talloc_realloc(ret, options.options, 150 const char *, num_options+3); 151 if (options.options == NULL) { 152 fprintf(stderr, "Out of memory!\n"); 153 goto failed; 154 } 155 options.options[num_options] = poptGetOptArg(pc); 156 options.options[num_options+1] = NULL; 157 num_options++; 158 break; 159 160 case 'c': { 161 const char *cs = poptGetOptArg(pc); 162 const char *p, *q; 163 int cc; 164 165 for (p = cs, cc = 1; (q = strchr(p, ',')); cc++, p = q + 1) ; 166 167 options.controls = talloc_array(ret, char *, cc + 1); 168 if (options.controls == NULL) { 169 fprintf(stderr, "Out of memory!\n"); 170 goto failed; 171 } 172 for (p = cs, cc = 0; p != NULL; cc++) { 173 const char *t; 174 175 t = strchr(p, ','); 176 if (t == NULL) { 177 options.controls[cc] = talloc_strdup(options.controls, p); 178 p = NULL; 179 } else { 180 options.controls[cc] = talloc_strndup(options.controls, p, t-p); 181 p = t + 1; 182 } 183 } 184 options.controls[cc] = NULL; 185 186 break; 187 } 188 default: 189 fprintf(stderr, "Invalid option %s: %s\n", 190 poptBadOption(pc, 0), poptStrerror(opt)); 191 if (usage) usage(); 192 goto failed; 193 } 194 } 195 196 /* setup the remaining options for the main program to use */ 197 options.argv = poptGetArgs(pc); 198 if (options.argv) { 199 options.argv++; 200 while (options.argv[options.argc]) options.argc++; 201 } 202 203 *ret = options; 204 205 /* all utils need some option */ 206 if (ret->url == NULL) { 207 fprintf(stderr, "You must supply a url with -H or with $LDB_URL\n"); 208 if (usage) usage(); 209 goto failed; 210 } 211 212 if (strcmp(ret->url, "NONE") == 0) { 213 return ret; 214 } 215 216 if (options.nosync) { 217 flags |= LDB_FLG_NOSYNC; 218 } 219 220 if (options.show_binary) { 221 flags |= LDB_FLG_SHOW_BINARY; 222 } 223 224 if (options.tracing) { 225 flags |= LDB_FLG_ENABLE_TRACING; 226 } 227 228#if (_SAMBA_BUILD_ >= 4) 229 /* Must be after we have processed command line options */ 230 gensec_init(cmdline_lp_ctx); 231 232 if (ldb_set_opaque(ldb, "sessionInfo", system_session(ldb, cmdline_lp_ctx))) { 233 goto failed; 234 } 235 if (ldb_set_opaque(ldb, "credentials", cmdline_credentials)) { 236 goto failed; 237 } 238 if (ldb_set_opaque(ldb, "loadparm", cmdline_lp_ctx)) { 239 goto failed; 240 } 241 242 ldb_set_utf8_fns(ldb, NULL, wrap_casefold); 243#endif 244 245 if (options.modules_path != NULL) { 246 ldb_set_modules_dir(ldb, options.modules_path); 247 } else if (getenv("LDB_MODULES_PATH") != NULL) { 248 ldb_set_modules_dir(ldb, getenv("LDB_MODULES_PATH")); 249 } 250 251 /* now connect to the ldb */ 252 if (ldb_connect(ldb, ret->url, flags, ret->options) != 0) { 253 fprintf(stderr, "Failed to connect to %s - %s\n", 254 ret->url, ldb_errstring(ldb)); 255 goto failed; 256 } 257 258 return ret; 259 260failed: 261 talloc_free(ret); 262 exit(1); 263 return NULL; 264} 265 266/* this function check controls reply and determines if more 267 * processing is needed setting up the request controls correctly 268 * 269 * returns: 270 * -1 error 271 * 0 all ok 272 * 1 all ok, more processing required 273 */ 274int handle_controls_reply(struct ldb_control **reply, struct ldb_control **request) 275{ 276 int i, j; 277 int ret = 0; 278 279 if (reply == NULL || request == NULL) return -1; 280 281 for (i = 0; reply[i]; i++) { 282 if (strcmp(LDB_CONTROL_VLV_RESP_OID, reply[i]->oid) == 0) { 283 struct ldb_vlv_resp_control *rep_control; 284 285 rep_control = talloc_get_type(reply[i]->data, struct ldb_vlv_resp_control); 286 287 /* check we have a matching control in the request */ 288 for (j = 0; request[j]; j++) { 289 if (strcmp(LDB_CONTROL_VLV_REQ_OID, request[j]->oid) == 0) 290 break; 291 } 292 if (! request[j]) { 293 fprintf(stderr, "Warning VLV reply received but no request have been made\n"); 294 continue; 295 } 296 297 /* check the result */ 298 if (rep_control->vlv_result != 0) { 299 fprintf(stderr, "Warning: VLV not performed with error: %d\n", rep_control->vlv_result); 300 } else { 301 fprintf(stderr, "VLV Info: target position = %d, content count = %d\n", rep_control->targetPosition, rep_control->contentCount); 302 } 303 304 continue; 305 } 306 307 if (strcmp(LDB_CONTROL_ASQ_OID, reply[i]->oid) == 0) { 308 struct ldb_asq_control *rep_control; 309 310 rep_control = talloc_get_type(reply[i]->data, struct ldb_asq_control); 311 312 /* check the result */ 313 if (rep_control->result != 0) { 314 fprintf(stderr, "Warning: ASQ not performed with error: %d\n", rep_control->result); 315 } 316 317 continue; 318 } 319 320 if (strcmp(LDB_CONTROL_PAGED_RESULTS_OID, reply[i]->oid) == 0) { 321 struct ldb_paged_control *rep_control, *req_control; 322 323 rep_control = talloc_get_type(reply[i]->data, struct ldb_paged_control); 324 if (rep_control->cookie_len == 0) /* we are done */ 325 break; 326 327 /* more processing required */ 328 /* let's fill in the request control with the new cookie */ 329 330 for (j = 0; request[j]; j++) { 331 if (strcmp(LDB_CONTROL_PAGED_RESULTS_OID, request[j]->oid) == 0) 332 break; 333 } 334 /* if there's a reply control we must find a request 335 * control matching it */ 336 if (! request[j]) return -1; 337 338 req_control = talloc_get_type(request[j]->data, struct ldb_paged_control); 339 340 if (req_control->cookie) 341 talloc_free(req_control->cookie); 342 req_control->cookie = (char *)talloc_memdup( 343 req_control, rep_control->cookie, 344 rep_control->cookie_len); 345 req_control->cookie_len = rep_control->cookie_len; 346 347 ret = 1; 348 349 continue; 350 } 351 352 if (strcmp(LDB_CONTROL_SORT_RESP_OID, reply[i]->oid) == 0) { 353 struct ldb_sort_resp_control *rep_control; 354 355 rep_control = talloc_get_type(reply[i]->data, struct ldb_sort_resp_control); 356 357 /* check we have a matching control in the request */ 358 for (j = 0; request[j]; j++) { 359 if (strcmp(LDB_CONTROL_SERVER_SORT_OID, request[j]->oid) == 0) 360 break; 361 } 362 if (! request[j]) { 363 fprintf(stderr, "Warning Server Sort reply received but no request found\n"); 364 continue; 365 } 366 367 /* check the result */ 368 if (rep_control->result != 0) { 369 fprintf(stderr, "Warning: Sorting not performed with error: %d\n", rep_control->result); 370 } 371 372 continue; 373 } 374 375 if (strcmp(LDB_CONTROL_DIRSYNC_OID, reply[i]->oid) == 0) { 376 struct ldb_dirsync_control *rep_control, *req_control; 377 char *cookie; 378 379 rep_control = talloc_get_type(reply[i]->data, struct ldb_dirsync_control); 380 if (rep_control->cookie_len == 0) /* we are done */ 381 break; 382 383 /* more processing required */ 384 /* let's fill in the request control with the new cookie */ 385 386 for (j = 0; request[j]; j++) { 387 if (strcmp(LDB_CONTROL_DIRSYNC_OID, request[j]->oid) == 0) 388 break; 389 } 390 /* if there's a reply control we must find a request 391 * control matching it */ 392 if (! request[j]) return -1; 393 394 req_control = talloc_get_type(request[j]->data, struct ldb_dirsync_control); 395 396 if (req_control->cookie) 397 talloc_free(req_control->cookie); 398 req_control->cookie = (char *)talloc_memdup( 399 req_control, rep_control->cookie, 400 rep_control->cookie_len); 401 req_control->cookie_len = rep_control->cookie_len; 402 403 cookie = ldb_base64_encode(req_control, rep_control->cookie, rep_control->cookie_len); 404 printf("# DIRSYNC cookie returned was:\n# %s\n", cookie); 405 406 continue; 407 } 408 409 /* no controls matched, throw a warning */ 410 fprintf(stderr, "Unknown reply control oid: %s\n", reply[i]->oid); 411 } 412 413 return ret; 414} 415 416