/* -*- show-trailing-whitespace: t; indent-tabs: t -*- * Copyright (c) 2003,2004,2005,2006 David Lichteblau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common.h" static int get_ws_col(void) { struct winsize ws; if (ioctl(1, TIOCGWINSZ, &ws) == -1) return 80; return ws.ws_col; } static void update_progress(LDAP *ld, int n, LDAPMessage *entry) { int cols = get_ws_col(); static struct timeval tv; static int usec = 0; int i; if (gettimeofday(&tv, 0) == -1) syserr(); if (!entry) usec = 0; else if (!usec) usec = tv.tv_usec; else { if (tv.tv_usec < usec) usec -= 1000000; if (tv.tv_usec - usec < 200000) return; usec = tv.tv_usec; } putchar('\r'); for (i = 0; i < cols; i++) putchar(' '); printf((n == 1) ? "\r%7d entry read " :"\r%7d entries read", n); if (entry) { char *dn = ldap_get_dn(ld, entry); if (strlen(dn) < cols - 28) printf(" %s", dn); ldap_memfree(dn); } fflush(stdout); } void handle_result(LDAP *ld, LDAPMessage *result, int start, int n, int progress, int noninteractive) { int rc; int err; char *matcheddn; char *text; rc = ldap_parse_result(ld, result, &err, &matcheddn, &text, 0, 0, 0); if (rc) ldaperr(ld, "ldap_parse_result"); if (err) { fprintf(stderr, "Search failed: %s\n", ldap_err2string(err)); if (text && *text) fprintf(stderr, "\t%s\n", text); if ((err != LDAP_NO_SUCH_OBJECT && err != LDAP_TIMELIMIT_EXCEEDED && err != LDAP_SIZELIMIT_EXCEEDED && err != LDAP_ADMINLIMIT_EXCEEDED) || noninteractive) { exit(1); } if (n > start /* otherwise there is only point in continuing * if other searches find results, and we check * that later */ && choose("Continue anyway?", "yn", 0) != 'y') exit(0); } if (n == start && progress) { fputs("No search results", stderr); if (matcheddn && *matcheddn) fprintf(stderr, " (matched: %s)", matcheddn); fputs(".\n", stderr); } if (matcheddn) ldap_memfree(matcheddn); if (text) ldap_memfree(text); } void log_reference(LDAP *ld, LDAPMessage *reference, FILE *s) { char **refs; char **ptr; if (ldap_parse_reference(ld, reference, &refs, 0, 0)) ldaperr(ld, "ldap_parse_reference"); fputc('\n', s); for (ptr = refs; *ptr; ptr++) fprintf(s, "# reference to: %s\n", *ptr); ldap_value_free(refs); } static tentroid * entroid_set_message(LDAP *ld, tentroid *entroid, LDAPMessage *entry) { struct berval **values = ldap_get_values_len(ld, entry, "objectClass"); struct berval **ptr; if (!values || !*values) return 0; entroid_reset(entroid); for (ptr = values; *ptr; ptr++) { struct berval *value = *ptr; LDAPObjectClass *cls = entroid_request_class(entroid, value->bv_val); if (!cls) { g_string_append(entroid->comment, "# ERROR: "); g_string_append(entroid->comment, entroid->error->str); ldap_value_free_len(values); return entroid; } } ldap_value_free_len(values); if (compute_entroid(entroid) == -1) { g_string_append(entroid->comment, "# ERROR: "); g_string_append(entroid->comment, entroid->error->str); return entroid; } return entroid; } static void search_subtree(FILE *s, LDAP *ld, GArray *offsets, char *base, cmdline *cmdline, LDAPControl **ctrls, int notty, int ldif, tschema *schema) { int msgid; LDAPMessage *result, *entry; int start = offsets->len; int n = start; long offset; tentroid *entroid; tentroid *e; if (schema) entroid = entroid_new(schema); else entroid = 0; if (ldap_search_ext( ld, base, cmdline->scope, cmdline->filter, cmdline->attrs, 0, ctrls, 0, 0, 0, &msgid)) ldaperr(ld, "ldap_search"); while (n >= 0) switch (ldap_result(ld, msgid, 0, 0, &result)) { case -1: case 0: ldaperr(ld, "ldap_result"); case LDAP_RES_SEARCH_ENTRY: entry = ldap_first_entry(ld, result); offset = ftell(s); if (offset == -1 && !notty) syserr(); g_array_append_val(offsets, offset); if (entroid) e = entroid_set_message(ld, entroid, entry); else e = 0; if (ldif) print_ldif_message( s, ld, entry, notty ? -1 : n, e); else print_ldapvi_message(s, ld, entry, n, e); n++; if (!cmdline->quiet && !notty) update_progress(ld, n, entry); ldap_msgfree(entry); break; case LDAP_RES_SEARCH_REFERENCE: log_reference(ld, result, s); ldap_msgfree(result); break; case LDAP_RES_SEARCH_RESULT: if (!notty) { update_progress(ld, n, 0); putchar('\n'); } handle_result(ld, result, start, n, !cmdline->quiet, notty); n = -1; ldap_msgfree(result); break; default: abort(); } if (entroid) entroid_free(entroid); } GArray * search(FILE *s, LDAP *ld, cmdline *cmdline, LDAPControl **ctrls, int notty, int ldif) { GArray *offsets = g_array_new(0, 0, sizeof(long)); GPtrArray *basedns = cmdline->basedns; int i; tschema *schema; if (cmdline->schema_comments) { schema = schema_new(ld); if (!schema) { fputs("Error: Failed to read schema, giving up.", stderr); exit(1); } } else schema = 0; if (basedns->len == 0) search_subtree(s, ld, offsets, 0, cmdline, ctrls, notty, ldif, schema); else for (i = 0; i < basedns->len; i++) { char *base = g_ptr_array_index(basedns, i); if (!cmdline->quiet && (basedns->len > 1)) fprintf(stderr, "Searching in: %s\n", base); search_subtree(s, ld, offsets, base, cmdline, ctrls, notty, ldif, schema); } if (!offsets->len) { if (!cmdline->noninteractive) { if (cmdline->quiet) /* if not printed already... */ fputs("No search results. ", stderr); fputs("(Maybe use --add or --discover instead?)\n", stderr); } exit(0); } if (schema) schema_free(schema); return offsets; } LDAPMessage * get_entry(LDAP *ld, char *dn, LDAPMessage **result) { LDAPMessage *entry; char *attrs[3] = {"+", "*", 0}; if (ldap_search_s(ld, dn, LDAP_SCOPE_BASE, 0, attrs, 0, result)) ldaperr(ld, "ldap_search"); if ( !(entry = ldap_first_entry(ld, *result))) ldaperr(ld, "ldap_first_entry"); return entry; } void discover_naming_contexts(LDAP *ld, GPtrArray *basedns) { LDAPMessage *result, *entry; char **values; entry = get_entry(ld, "", &result); values = ldap_get_values(ld, entry, "namingContexts"); if (values) { char **ptr = values; for (ptr = values; *ptr; ptr++) g_ptr_array_add(basedns, xdup(*ptr)); ldap_value_free(values); } ldap_msgfree(result); }