Logo Search packages:      
Sourcecode: ldapvi version File versions

search.c

/* -*- 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);
}

Generated by  Doxygen 1.6.0   Back to index