/* -*- 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);
}
syntax highlighted by Code2HTML, v. 0.9.1