1/* 2 ldb database library 3 4 Copyright (C) Andrew Tridgell 2004 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/* 25 * Name: ldb 26 * 27 * Component: ldbsearch 28 * 29 * Description: utility for ldb search - modelled on ldapsearch 30 * 31 * Author: Andrew Tridgell 32 */ 33 34#include "ldb_includes.h" 35#include "ldb.h" 36#include "tools/cmdline.h" 37 38static void usage(void) 39{ 40 printf("Usage: ldbsearch <options> <expression> <attrs...>\n"); 41 ldb_cmdline_help("ldbsearch", stdout); 42 exit(1); 43} 44 45static int do_compare_msg(struct ldb_message **el1, 46 struct ldb_message **el2, 47 void *opaque) 48{ 49 return ldb_dn_compare((*el1)->dn, (*el2)->dn); 50} 51 52struct search_context { 53 struct ldb_context *ldb; 54 struct ldb_control **req_ctrls; 55 56 int sort; 57 int num_stored; 58 struct ldb_message **store; 59 int refs_stored; 60 char **refs_store; 61 62 int entries; 63 int refs; 64 65 int pending; 66 int status; 67}; 68 69static int store_message(struct ldb_message *msg, struct search_context *sctx) { 70 71 sctx->store = talloc_realloc(sctx, sctx->store, struct ldb_message *, sctx->num_stored + 2); 72 if (!sctx->store) { 73 fprintf(stderr, "talloc_realloc failed while storing messages\n"); 74 return -1; 75 } 76 77 sctx->store[sctx->num_stored] = talloc_move(sctx->store, &msg); 78 sctx->num_stored++; 79 sctx->store[sctx->num_stored] = NULL; 80 81 return 0; 82} 83 84static int store_referral(char *referral, struct search_context *sctx) { 85 86 sctx->refs_store = talloc_realloc(sctx, sctx->refs_store, char *, sctx->refs_stored + 2); 87 if (!sctx->refs_store) { 88 fprintf(stderr, "talloc_realloc failed while storing referrals\n"); 89 return -1; 90 } 91 92 sctx->refs_store[sctx->refs_stored] = talloc_move(sctx->refs_store, &referral); 93 sctx->refs_stored++; 94 sctx->refs_store[sctx->refs_stored] = NULL; 95 96 return 0; 97} 98 99static int display_message(struct ldb_message *msg, struct search_context *sctx) { 100 struct ldb_ldif ldif; 101 102 sctx->entries++; 103 printf("# record %d\n", sctx->entries); 104 105 ldif.changetype = LDB_CHANGETYPE_NONE; 106 ldif.msg = msg; 107 108 if (sctx->sort) { 109 /* 110 * Ensure attributes are always returned in the same 111 * order. For testing, this makes comparison of old 112 * vs. new much easier. 113 */ 114 ldb_msg_sort_elements(ldif.msg); 115 } 116 117 ldb_ldif_write_file(sctx->ldb, stdout, &ldif); 118 119 return 0; 120} 121 122static int display_referral(char *referral, struct search_context *sctx) 123{ 124 125 sctx->refs++; 126 printf("# Referral\nref: %s\n\n", referral); 127 128 return 0; 129} 130 131static int search_callback(struct ldb_request *req, struct ldb_reply *ares) 132{ 133 struct search_context *sctx; 134 int ret; 135 136 sctx = talloc_get_type(req->context, struct search_context); 137 138 if (!ares) { 139 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR); 140 } 141 if (ares->error != LDB_SUCCESS) { 142 return ldb_request_done(req, ares->error); 143 } 144 145 switch (ares->type) { 146 case LDB_REPLY_ENTRY: 147 if (sctx->sort) { 148 ret = store_message(ares->message, sctx); 149 } else { 150 ret = display_message(ares->message, sctx); 151 } 152 break; 153 154 case LDB_REPLY_REFERRAL: 155 if (sctx->sort) { 156 ret = store_referral(ares->referral, sctx); 157 } else { 158 ret = display_referral(ares->referral, sctx); 159 } 160 if (ret) { 161 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR); 162 } 163 break; 164 165 case LDB_REPLY_DONE: 166 if (ares->controls) { 167 if (handle_controls_reply(ares->controls, sctx->req_ctrls) == 1) 168 sctx->pending = 1; 169 } 170 talloc_free(ares); 171 return ldb_request_done(req, LDB_SUCCESS); 172 } 173 174 talloc_free(ares); 175 if (ret) { 176 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR); 177 } 178 179 return LDB_SUCCESS; 180} 181 182static int do_search(struct ldb_context *ldb, 183 struct ldb_dn *basedn, 184 struct ldb_cmdline *options, 185 const char *expression, 186 const char * const *attrs) 187{ 188 struct ldb_request *req; 189 struct search_context *sctx; 190 int ret; 191 192 req = NULL; 193 194 sctx = talloc(ldb, struct search_context); 195 if (!sctx) return -1; 196 197 sctx->ldb = ldb; 198 sctx->sort = options->sorted; 199 sctx->num_stored = 0; 200 sctx->refs_stored = 0; 201 sctx->store = NULL; 202 sctx->req_ctrls = ldb_parse_control_strings(ldb, sctx, (const char **)options->controls); 203 if (options->controls != NULL && sctx->req_ctrls== NULL) { 204 printf("parsing controls failed: %s\n", ldb_errstring(ldb)); 205 return -1; 206 } 207 sctx->entries = 0; 208 sctx->refs = 0; 209 210 if (basedn == NULL) { 211 basedn = ldb_get_default_basedn(ldb); 212 } 213 214again: 215 /* free any previous requests */ 216 if (req) talloc_free(req); 217 218 ret = ldb_build_search_req(&req, ldb, ldb, 219 basedn, options->scope, 220 expression, attrs, 221 sctx->req_ctrls, 222 sctx, search_callback, 223 NULL); 224 if (ret != LDB_SUCCESS) { 225 talloc_free(sctx); 226 printf("allocating request failed: %s\n", ldb_errstring(ldb)); 227 return -1; 228 } 229 230 sctx->pending = 0; 231 232 ret = ldb_request(ldb, req); 233 if (ret != LDB_SUCCESS) { 234 printf("search failed - %s\n", ldb_errstring(ldb)); 235 return -1; 236 } 237 238 ret = ldb_wait(req->handle, LDB_WAIT_ALL); 239 if (ret != LDB_SUCCESS) { 240 printf("search error - %s\n", ldb_errstring(ldb)); 241 return -1; 242 } 243 244 if (sctx->pending) 245 goto again; 246 247 if (sctx->sort && (sctx->num_stored != 0 || sctx->refs != 0)) { 248 int i; 249 250 if (sctx->num_stored) { 251 ldb_qsort(sctx->store, sctx->num_stored, sizeof(struct ldb_message *), 252 ldb, (ldb_qsort_cmp_fn_t)do_compare_msg); 253 } 254 for (i = 0; i < sctx->num_stored; i++) { 255 display_message(sctx->store[i], sctx); 256 } 257 258 for (i = 0; i < sctx->refs_stored; i++) { 259 display_referral(sctx->refs_store[i], sctx); 260 } 261 } 262 263 printf("# returned %d records\n# %d entries\n# %d referrals\n", 264 sctx->entries + sctx->refs, sctx->entries, sctx->refs); 265 266 talloc_free(sctx); 267 talloc_free(req); 268 269 return 0; 270} 271 272int main(int argc, const char **argv) 273{ 274 struct ldb_context *ldb; 275 struct ldb_dn *basedn = NULL; 276 const char * const * attrs = NULL; 277 struct ldb_cmdline *options; 278 int ret = -1; 279 const char *expression = "(|(objectClass=*)(distinguishedName=*))"; 280 281 ldb = ldb_init(NULL, NULL); 282 if (ldb == NULL) { 283 return -1; 284 } 285 286 options = ldb_cmdline_process(ldb, argc, argv, usage); 287 288 /* the check for '=' is for compatibility with ldapsearch */ 289 if (!options->interactive && 290 options->argc > 0 && 291 strchr(options->argv[0], '=')) { 292 expression = options->argv[0]; 293 options->argv++; 294 options->argc--; 295 } 296 297 if (options->argc > 0) { 298 attrs = (const char * const *)(options->argv); 299 } 300 301 if (options->basedn != NULL) { 302 basedn = ldb_dn_new(ldb, ldb, options->basedn); 303 if ( ! ldb_dn_validate(basedn)) { 304 fprintf(stderr, "Invalid Base DN format\n"); 305 exit(1); 306 } 307 } 308 309 if (options->interactive) { 310 char line[1024]; 311 while (fgets(line, sizeof(line), stdin)) { 312 if (do_search(ldb, basedn, options, line, attrs) == -1) { 313 ret = -1; 314 } 315 } 316 } else { 317 ret = do_search(ldb, basedn, options, expression, attrs); 318 } 319 320 talloc_free(ldb); 321 return ret; 322} 323