r12829: fix ldb headers, to not include '<...>' files in .c files
[kamenim/samba.git] / source4 / lib / ldb / tools / ldbsearch.c
index 478601ec7eb1196c1079c4318557792c574dd88d..4ce974c6fa4acf382f2b6d3c8caa2692bf9cd2ce 100644 (file)
@@ -33,6 +33,8 @@
  */
 
 #include "includes.h"
+#include "ldb/include/includes.h"
+#include "ldb/tools/cmdline.h"
 
 static void usage(void)
 {
@@ -42,40 +44,174 @@ static void usage(void)
        printf("  -s base|sub|one  choose search scope\n");
        printf("  -b basedn        choose baseDN\n");
        printf("  -i               read search expressions from stdin\n");
+        printf("  -S               sort returned attributes\n");
+       printf("  -o options       pass options like modules to activate\n");
+       printf("              e.g: -o modules:timestamps\n");
        exit(1);
 }
 
+static int do_compare_msg(struct ldb_message **el1,
+                         struct ldb_message **el2,
+                         void *opaque)
+{
+       struct ldb_context *ldb = talloc_get_type(opaque, struct ldb_context);
+       return ldb_dn_compare(ldb, (*el1)->dn, (*el2)->dn);
+}
+
+static struct ldb_control **parse_controls(void *mem_ctx, char **control_strings)
+{
+       int i;
+       struct ldb_control **ctrl;
+
+       if (control_strings == NULL || control_strings[0] == NULL)
+               return NULL;
+
+       for (i = 0; control_strings[i]; i++);
+
+       ctrl = talloc_array(mem_ctx, struct ldb_control *, i + 1);
+
+       for (i = 0; control_strings[i]; i++) {
+               if (strncmp(control_strings[i], "extended_dn:", 12) == 0) {
+                       struct ldb_extended_dn_control *control;
+                       const char *p;
+                       int crit, type, ret;
+
+                       p = &(control_strings[i][12]);
+                       ret = sscanf(p, "%d:%d", &crit, &type);
+                       if ((ret != 2) || (crit < 0) || (crit > 1) || (type < 0) || (type > 1)) {
+                               fprintf(stderr, "invalid extended_dn control syntax\n");
+                               return NULL;
+                       }
+
+                       ctrl[i] = talloc(ctrl, struct ldb_control);
+                       ctrl[i]->oid = LDB_CONTROL_EXTENDED_DN_OID;
+                       ctrl[i]->critical = crit;
+                       control = talloc(ctrl[i], struct ldb_extended_dn_control);
+                       control->type = type;
+                       ctrl[i]->data = control;
+
+                       continue;
+               }
+
+               if (strncmp(control_strings[i], "paged_results:", 14) == 0) {
+                       struct ldb_paged_control *control;
+                       const char *p;
+                       int crit, size, ret;
+                      
+                       p = &(control_strings[i][14]);
+                       ret = sscanf(p, "%d:%d", &crit, &size);
+
+                       if ((ret != 2) || (crit < 0) || (crit > 1) || (size < 0)) {
+                               fprintf(stderr, "invalid paged_results control syntax\n");
+                               return NULL;
+                       }
+
+                       ctrl[i] = talloc(ctrl, struct ldb_control);
+                       ctrl[i]->oid = LDB_CONTROL_PAGED_RESULTS_OID;
+                       ctrl[i]->critical = crit;
+                       control = talloc(ctrl[i], struct ldb_paged_control);
+                       control->size = size;
+                       control->cookie = NULL;
+                       control->cookie_len = 0;
+                       ctrl[i]->data = control;
+
+                       continue;
+               }
+
+               if (strncmp(control_strings[i], "server_sort:", 12) == 0) {
+                       struct ldb_server_sort_control **control;
+                       const char *p;
+                       char attr[256];
+                       char rule[128];
+                       int crit, rev, ret;
+
+                       p = &(control_strings[i][12]);
+                       ret = sscanf(p, "%d:%d:%255[^:]:%127[^:]", &crit, &rev, attr, rule);
+                       if ((ret < 3) || (crit < 0) || (crit > 1) || (rev < 0 ) || (rev > 1) ||attr[0] == '\0') {
+                               fprintf(stderr, "invalid server_sort control syntax\n");
+                               return NULL;
+                       }
+                       ctrl[i] = talloc(ctrl, struct ldb_control);
+                       ctrl[i]->oid = LDB_CONTROL_SERVER_SORT_OID;
+                       ctrl[i]->critical = crit;
+                       control = talloc_array(ctrl[i], struct ldb_server_sort_control *, 2);
+                       control[0] = talloc(control, struct ldb_server_sort_control);
+                       control[0]->attributeName = talloc_strdup(control, attr);
+                       control[0]->orderingRule = talloc_strdup(control, rule);
+                       control[0]->reverse = rev;
+                       control[1] = NULL;
+                       ctrl[i]->data = control;
+
+                       continue;
+               }
+
+               /* no controls matched, throw an error */
+               fprintf(stderr, "Invalid control name\n");
+               return NULL;
+       }
+
+       ctrl[i + 1] = NULL;
+
+       return ctrl;
+}
+
 static int do_search(struct ldb_context *ldb,
-                    const char *basedn,
-                    int scope,
+                    const struct ldb_dn *basedn,
+                    struct ldb_cmdline *options,
                     const char *expression,
                     const char * const *attrs)
 {
        int ret, i;
-       struct ldb_message **msgs;
+       struct ldb_request req;
+       struct ldb_result *result = NULL;
 
-       ret = ldb_search(ldb, basedn, scope, expression, attrs, &msgs);
-       if (ret == -1) {
+       req.operation = LDB_REQ_SEARCH;
+       req.op.search.base = basedn;
+       req.op.search.scope = options->scope;
+       req.op.search.tree = ldb_parse_tree(ldb, expression);
+       req.op.search.attrs = attrs;
+       req.op.search.res = NULL;
+       req.controls = parse_controls(ldb, options->controls);
+       if (options->controls != NULL && req.controls == NULL) return -1;
+       req.creds = NULL;
+
+       ret = ldb_request(ldb, &req);
+       if (ret != LDB_SUCCESS) {
                printf("search failed - %s\n", ldb_errstring(ldb));
                return -1;
        }
 
+       result = req.op.search.res;
        printf("# returned %d records\n", ret);
 
-       for (i=0;i<ret;i++) {
+       if (options->sorted) {
+               ldb_qsort(result->msgs, ret, sizeof(struct ldb_message *),
+                         ldb, (ldb_qsort_cmp_fn_t)do_compare_msg);
+       }
+
+       for (i = 0; i < result->count; i++) {
                struct ldb_ldif ldif;
                printf("# record %d\n", i+1);
 
                ldif.changetype = LDB_CHANGETYPE_NONE;
-               ldif.msg = *msgs[i];
+               ldif.msg = result->msgs[i];
 
-               ldif_write_file(ldb, stdout, &ldif);
+                if (options->sorted) {
+                        /*
+                         * Ensure attributes are always returned in the same
+                         * order.  For testing, this makes comparison of old
+                         * vs. new much easier.
+                         */
+                        ldb_msg_sort_elements(ldif.msg);
+                }
+                
+               ldb_ldif_write_file(ldb, stdout, &ldif);
        }
 
-       if (ret > 0) {
-               ret = ldb_search_free(ldb, msgs);
+       if (result) {
+               ret = talloc_free(result);
                if (ret == -1) {
-                       fprintf(stderr, "search_free failed\n");
+                       fprintf(stderr, "talloc_free failed\n");
                        exit(1);
                }
        }
@@ -83,85 +219,51 @@ static int do_search(struct ldb_context *ldb,
        return 0;
 }
 
- int main(int argc, char * const argv[])
+ int main(int argc, const char **argv)
 {
        struct ldb_context *ldb;
+       struct ldb_dn *basedn = NULL;
        const char * const * attrs = NULL;
-       const char *ldb_url;
-       const char *basedn = NULL;
-       int opt;
-       enum ldb_scope scope = LDB_SCOPE_SUBTREE;
-       int interactive = 0, ret=0;
-
-       ldb_url = getenv("LDB_URL");
-
-       while ((opt = getopt(argc, argv, "b:H:s:hi")) != EOF) {
-               switch (opt) {
-               case 'b':
-                       basedn = optarg;
-                       break;
-
-               case 'H':
-                       ldb_url = optarg;
-                       break;
-
-               case 's':
-                       if (strcmp(optarg, "base") == 0) {
-                               scope = LDB_SCOPE_BASE;
-                       } else if (strcmp(optarg, "sub") == 0) {
-                               scope = LDB_SCOPE_SUBTREE;
-                       } else if (strcmp(optarg, "one") == 0) {
-                               scope = LDB_SCOPE_ONELEVEL;
-                       }
-                       break;
-
-               case 'i':
-                       interactive = 1;
-                       break;
-
-               case 'h':
-               default:
-                       usage();
-                       break;
-               }
-       }
+       struct ldb_cmdline *options;
+       int ret = -1;
+       const char *expression = "(objectclass=*)";
 
-       if (!ldb_url) {
-               fprintf(stderr, "You must specify a ldb URL\n\n");
-               usage();
-       }
+       ldb = ldb_init(NULL);
 
-       argc -= optind;
-       argv += optind;
+       options = ldb_cmdline_process(ldb, argc, argv, usage);
 
-       if (argc < 1 && !interactive) {
-               usage();
-               exit(1);
+       /* the check for '=' is for compatibility with ldapsearch */
+       if (!options->interactive &&
+           options->argc > 0 && 
+           strchr(options->argv[0], '=')) {
+               expression = options->argv[0];
+               options->argv++;
+               options->argc--;
        }
 
-       if (argc > 1) {
-               attrs = (const char * const *)(argv+1);
+       if (options->argc > 0) {
+               attrs = (const char * const *)(options->argv);
        }
 
-       ldb = ldb_connect(ldb_url, 0, NULL);
-       if (!ldb) {
-               perror("ldb_connect");
-               exit(1);
+       if (options->basedn != NULL) {
+               basedn = ldb_dn_explode(ldb, options->basedn);
+               if (basedn == NULL) {
+                       fprintf(stderr, "Invalid Base DN format\n");
+                       exit(1);
+               }
        }
 
-       ldb_set_debug_stderr(ldb);
-
-       if (interactive) {
+       if (options->interactive) {
                char line[1024];
                while (fgets(line, sizeof(line), stdin)) {
-                       if (do_search(ldb, basedn, scope, line, attrs) == -1) {
+                       if (do_search(ldb, basedn, options, line, attrs) == -1) {
                                ret = -1;
                        }
                }
        } else {
-               ret = do_search(ldb, basedn, scope, argv[0], attrs);
+               ret = do_search(ldb, basedn, options, expression, attrs);
        }
 
-       ldb_close(ldb);
+       talloc_free(ldb);
        return ret;
 }