mirror of
https://git.openldap.org/openldap/openldap.git
synced 2024-12-15 03:01:09 +08:00
b5494457d8
This could cause problems on odd systems. The generic headers should be extended as needed to include necessary system headers or, if necessary, make explicit declarations. Extended ac/string.h header to look for string.h/strings.h if STDC_HEADERS is not defined. Also provide basic declarations for str*() functions. This could cause problems on odd systems. Extended ac/unistd.h header to define basic declaration for misc functions that might be missing from headers. This includes externs for getenv(), getopt(), mktemp(), tempname(). Protect fax500.h from multiple inclusion. Moved includes of system/generic headers back to source files. Made mail500 helper functions static. Fixed includes of ctype.h, signal.h, etc. to use generics. lutil/tempname.c: was including stdlib.h twice, one should stdio.h. Wrapped <sys/resource.h> with HAVE_SYS_RESOURCE_H. lber/io.c/ber_get_next(): Changed noctets back to signed. Used with BerRead which expects signed int as second arg and returns signed int.
502 lines
13 KiB
C
502 lines
13 KiB
C
/*
|
|
* Copyright (c) 1991, 1992, 1993
|
|
* Regents of the University of Michigan. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms are permitted
|
|
* provided that this notice is preserved and that due credit is given
|
|
* to the University of Michigan at Ann Arbor. The name of the University
|
|
* may not be used to endorse or promote products derived from this
|
|
* software without specific prior written permission. This software
|
|
* is provided ``as is'' without express or implied warranty.
|
|
*/
|
|
|
|
#include "portable.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <ac/ctype.h>
|
|
#include <ac/string.h>
|
|
#include <ac/time.h>
|
|
|
|
#include <lber.h>
|
|
#include <ldap.h>
|
|
|
|
#include "ud.h"
|
|
|
|
static int num_picked = 0; /* used when user picks entry at More prompt */
|
|
|
|
|
|
int
|
|
vrfy( char *dn )
|
|
{
|
|
LDAPMessage *results;
|
|
static char *attrs[2] = { "objectClass", NULL };
|
|
int ld_errno = 0;
|
|
|
|
#ifdef DEBUG
|
|
if (debug & D_TRACE)
|
|
printf("->vrfy(%s)\n", dn);
|
|
#endif
|
|
/* verify that this DN exists in the directory */
|
|
(void) ldap_search_s(ld, dn, LDAP_SCOPE_BASE, "objectClass=*", attrs, TRUE, &results);
|
|
(void) ldap_msgfree(results);
|
|
|
|
ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
|
|
|
|
if ((ld_errno == LDAP_NO_SUCH_OBJECT) || (ld_errno == LDAP_INVALID_DN_SYNTAX))
|
|
return(0);
|
|
else if (ld_errno == LDAP_SUCCESS)
|
|
return(1);
|
|
else {
|
|
ldap_perror(ld, "ldap_search");
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
|
|
static LDAPMessage *
|
|
disambiguate( LDAPMessage *result, int matches, char **read_attrs, char *who )
|
|
{
|
|
int choice; /* entry that user chooses */
|
|
int i;
|
|
char *namelist[MAX_NUM_NAMES]; /* names found */
|
|
char response[SMALL_BUF_SIZE]; /* results from user */
|
|
char *name = NULL; /* DN to lookup */
|
|
LDAPMessage *mp;
|
|
int ld_errno = 0;
|
|
|
|
#ifdef DEBUG
|
|
if (debug & D_TRACE)
|
|
printf("->disambiguate(%x, %d, %x, %s)\n", result, matches,
|
|
read_attrs, who);
|
|
#endif
|
|
|
|
ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
|
|
|
|
/*
|
|
* If we are here, it means that we got back multiple answers.
|
|
*/
|
|
if ((ld_errno == LDAP_TIMELIMIT_EXCEEDED)
|
|
|| (ld_errno == LDAP_SIZELIMIT_EXCEEDED)) {
|
|
if (verbose) {
|
|
printf(" Your query was too general and a limit was exceeded. The results listed\n");
|
|
printf(" are not complete. You may want to try again with a more refined query.\n\n");
|
|
}
|
|
else
|
|
printf(" Time or size limit exceeded. Partial results follow.\n\n");
|
|
}
|
|
printf(" %1d names matched \"%s\".\n", matches, who);
|
|
for (;;) {
|
|
printf(" Do you wish to see a list of names? ");
|
|
fflush(stdout);
|
|
(void) memset(response, 0, sizeof(response));
|
|
fetch_buffer(response, sizeof(response), stdin);
|
|
switch (response[0]) {
|
|
case 'n' :
|
|
case 'N' :
|
|
case '\0' :
|
|
case '\n' :
|
|
return(NULL);
|
|
/* NOTREACHED */
|
|
case 'y' :
|
|
case 'Y' :
|
|
print_list(result, namelist, &matches);
|
|
if (num_picked == 0)
|
|
choice = pick_one(matches);
|
|
else
|
|
choice = num_picked;
|
|
num_picked = 0;
|
|
if (choice >= 0)
|
|
name = strdup(namelist[choice]);
|
|
/*
|
|
* Now free up all of the pointers allocated in
|
|
* namelist. The print_list() routine that filled
|
|
* in this collection of strings starts at 1, not 0.
|
|
*/
|
|
for (i = 1; namelist[i] != NULL; i++)
|
|
Free(namelist[i]);
|
|
if (choice < 0) {
|
|
if (name != NULL)
|
|
Free(name);
|
|
return(NULL);
|
|
}
|
|
#ifdef DEBUG
|
|
if (debug & D_FIND) {
|
|
printf(" Calling ldap_search_s()\n");
|
|
printf(" ld = 0x%x\n", ld);
|
|
printf(" search base = %s\n", name);
|
|
printf(" scope = LDAP_SCOPE_BASE\n");
|
|
printf(" filter = objectClass=*\n");
|
|
for (i = 0; read_attrs[i] != NULL; i++)
|
|
printf(" read_attrs[%d] = %s\n", i, read_attrs[i]);
|
|
printf(" read_attrs[%d] = NULL\n", i);
|
|
printf(" attrsonly = FALSE\n");
|
|
printf(" &mp = 0x%x\n", &mp);
|
|
}
|
|
#endif
|
|
if (ldap_search_s(ld, name, LDAP_SCOPE_BASE, "objectClass=*", read_attrs, FALSE, &mp) != LDAP_SUCCESS) {
|
|
ldap_perror(ld, "ldap_search_s");
|
|
Free(name);
|
|
ldap_msgfree(mp);
|
|
return(NULL);
|
|
}
|
|
Free(name);
|
|
return(mp);
|
|
/* NOTREACHED */
|
|
default :
|
|
printf(" Please enter 'y', 'n', or RETURN.\n");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
LDAPMessage *
|
|
find( char *who, int quiet )
|
|
{
|
|
register int i, j, k; /* general ints */
|
|
int matches; /* from ldap_count_entries() */
|
|
int admonished = FALSE;
|
|
static int attrs_set = 0;
|
|
static char *read_attrs[MAX_ATTRS]; /* attrs to use in a read op */
|
|
static char *search_attrs[MAX_ATTRS]; /* attrs to use in a srch op */
|
|
static int rc; /* return from ldap_search */
|
|
LDAPMessage *ldtmp, *res; /* results returned from search */
|
|
char name[MED_BUF_SIZE];
|
|
char response[SMALL_BUF_SIZE];
|
|
char *cp, *dn, **rdns;
|
|
LDAPFiltInfo *fi;
|
|
|
|
#ifdef DEBUG
|
|
if (debug & D_TRACE)
|
|
fprintf(stderr, "->find(%s)\n", who);
|
|
#endif
|
|
/* did not specify a 'who' */
|
|
if (who == NULL) {
|
|
printf(" Locate whose entry? ");
|
|
fflush(stdout);
|
|
fetch_buffer(name, sizeof(name), stdin);
|
|
if (name[0] != '\0')
|
|
who = name;
|
|
else
|
|
return(NULL);
|
|
}
|
|
if (attrs_set == 0) {
|
|
j = k = 0;
|
|
attrs_set = 1;
|
|
for (i = 0; attrlist[i].quipu_name != NULL; i++) {
|
|
if (attrlist[i].flags & ATTR_FLAG_READ)
|
|
read_attrs[j++] = attrlist[i].quipu_name;
|
|
if (attrlist[i].flags & ATTR_FLAG_SEARCH)
|
|
search_attrs[k++] = attrlist[i].quipu_name;
|
|
}
|
|
read_attrs[j] = NULL;
|
|
search_attrs[k] = NULL;
|
|
}
|
|
|
|
/*
|
|
* If the user-supplied name has any commas in it, we
|
|
* assume that it is a UFN, and do everything right
|
|
* here. If we don't find it, treat it as NOT a UFN.
|
|
*/
|
|
if (strchr(who, ',') != NULL) {
|
|
int savederef, deref;
|
|
#ifdef DEBUG
|
|
if (debug & D_FIND)
|
|
printf("\"%s\" appears to be a UFN\n", who);
|
|
#endif
|
|
ldap_get_option(ld, LDAP_OPT_DEREF, &savederef);
|
|
deref = LDAP_DEREF_FINDING;
|
|
ldap_set_option(ld, LDAP_OPT_DEREF, &deref);
|
|
|
|
if ((rc = ldap_ufn_search_s(ld, who, search_attrs, FALSE, &res)) !=
|
|
LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED &&
|
|
rc != LDAP_TIMELIMIT_EXCEEDED) {
|
|
ldap_perror(ld, "ldap_ufn_search_s");
|
|
ldap_set_option(ld, LDAP_OPT_DEREF, &savederef);
|
|
return(NULL);
|
|
}
|
|
if ((matches = ldap_count_entries(ld, res)) < 0) {
|
|
ldap_perror(ld, "ldap_count_entries");
|
|
ldap_set_option(ld, LDAP_OPT_DEREF, &savederef);
|
|
return(NULL);
|
|
} else if (matches == 1) {
|
|
dn = ldap_get_dn(ld, ldap_first_entry(ld, res));
|
|
rc = ldap_search_s(ld, dn, LDAP_SCOPE_BASE, "objectClass=*", read_attrs, FALSE, &res);
|
|
Free(dn);
|
|
if (rc != LDAP_SUCCESS) {
|
|
int ld_errno = 0;
|
|
ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
|
|
if (ld_errno == LDAP_UNAVAILABLE)
|
|
printf(" Could not contact the LDAP server to find \"%s\".\n", who);
|
|
else
|
|
ldap_perror(ld, "ldap_search_s");
|
|
return(NULL);
|
|
}
|
|
ldap_set_option(ld, LDAP_OPT_DEREF, &savederef);
|
|
return(res);
|
|
} else if (matches > 1 ) {
|
|
return disambiguate( res, matches, read_attrs, who );
|
|
}
|
|
ldap_set_option(ld, LDAP_OPT_DEREF, &savederef);
|
|
}
|
|
|
|
/*
|
|
* Old users of the MTS *USERDIRECTORY will likely wrap the name
|
|
* in quotes. Not only is this unnecessary, but it also won't work.
|
|
*/
|
|
for (cp = strchr(who, '"'); cp != NULL; cp = strchr(cp, '"')) {
|
|
if (!admonished) {
|
|
printf(" You do not need to enclose names in quotes.\n");
|
|
admonished = TRUE;
|
|
}
|
|
*cp++ = ' ';
|
|
if (*cp == '\0')
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* It wasn't a UFN, so look it up in the usual method.
|
|
*/
|
|
for (fi = ldap_getfirstfilter(lfdp, "ud", who); fi != NULL;
|
|
fi = ldap_getnextfilter(lfdp)) {
|
|
#ifdef DEBUG
|
|
if (debug & D_FIND)
|
|
printf("Searching, filter = %s\n", fi->lfi_filter);
|
|
#endif
|
|
|
|
if ((rc = ldap_search_s(ld, search_base, fi->lfi_scope,
|
|
fi->lfi_filter, search_attrs, FALSE, &res)) != LDAP_SUCCESS &&
|
|
rc != LDAP_SIZELIMIT_EXCEEDED && rc != LDAP_TIMELIMIT_EXCEEDED) {
|
|
ldap_perror(ld, "ldap_search_s");
|
|
ldap_msgfree(res);
|
|
return(NULL);
|
|
}
|
|
if ((matches = ldap_count_entries(ld, res)) < 0) {
|
|
ldap_perror(ld, "ldap_count_entries");
|
|
ldap_msgfree(res);
|
|
return(NULL);
|
|
}
|
|
else if (matches == 1) {
|
|
dn = ldap_get_dn(ld, ldap_first_entry(ld, res));
|
|
ldap_msgfree(res);
|
|
if (!quiet)
|
|
printf(" Found one %s match for \"%s\"\n",
|
|
fi->lfi_desc, who);
|
|
if (!fi->lfi_isexact) {
|
|
rdns = ldap_explode_dn(dn, TRUE);
|
|
printf(" Do you mean %s? ", *rdns);
|
|
(void) ldap_value_free(rdns);
|
|
fflush(stdout);
|
|
fetch_buffer(response, sizeof(response), stdin);
|
|
if ((response[0] == 'n') || (response[0] == 'N'))
|
|
{
|
|
Free(dn);
|
|
return(NULL);
|
|
}
|
|
}
|
|
#ifdef DEBUG
|
|
if (debug & D_FIND) {
|
|
printf(" Calling ldap_search_s()\n");
|
|
printf(" ld = 0x%x\n", ld);
|
|
printf(" dn = %s\n", dn);
|
|
printf(" scope = LDAP_SCOPE_BASE\n");
|
|
printf(" filter = %s\n", "objectClass=*");
|
|
for (i = 0; read_attrs[i] != NULL; i++)
|
|
printf(" read_attrs[%d] = %s\n", i, read_attrs[i]);
|
|
printf(" read_attrs[%d] = NULL\n", i);
|
|
printf(" attrsonly = FALSE\n");
|
|
printf(" &results = 0x%x\n", &res);
|
|
}
|
|
#endif
|
|
if (ldap_search_s(ld, dn, LDAP_SCOPE_BASE, "objectClass=*", read_attrs, FALSE, &res) != LDAP_SUCCESS) {
|
|
ldap_perror(ld, "ldap_search_s");
|
|
ldap_msgfree(res);
|
|
res = NULL;
|
|
}
|
|
Free(dn);
|
|
return(res);
|
|
}
|
|
else if (matches > 0) {
|
|
ldtmp = disambiguate(res, matches, read_attrs, who);
|
|
ldap_msgfree(res);
|
|
return(ldtmp);
|
|
}
|
|
/* if we're here, there were zero matches */
|
|
ldap_msgfree(res);
|
|
}
|
|
return(NULL);
|
|
}
|
|
|
|
int
|
|
pick_one( int i )
|
|
{
|
|
int n;
|
|
char user_pick[SMALL_BUF_SIZE];
|
|
|
|
#ifdef DEBUG
|
|
if (debug & D_TRACE)
|
|
printf("->pick_one(%d)\n", i);
|
|
#endif
|
|
|
|
/* make the user pick an entry */
|
|
for (;;) {
|
|
printf(" Enter the number of the name you want or Q to quit: ");
|
|
fflush(stdout);
|
|
fetch_buffer(user_pick, sizeof(user_pick), stdin);
|
|
if (user_pick[0] == 'q' || user_pick[0] == 'Q')
|
|
return(-1);
|
|
n = atoi(user_pick);
|
|
if ((n > 0) && (n <= i))
|
|
return(n);
|
|
printf(" Invalid response\n");
|
|
}
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
void
|
|
print_list( LDAPMessage *list, char **names, int *matches )
|
|
{
|
|
char **rdns, **cpp;
|
|
char resp[SMALL_BUF_SIZE];
|
|
register LDAPMessage *ep;
|
|
register int i = 1;
|
|
register int rest = 4; /* 4, not 1 */
|
|
|
|
#ifdef DEBUG
|
|
if (debug & D_TRACE)
|
|
printf("->print_list(%x, %x, %x)\n", list, names, matches);
|
|
#endif
|
|
/* print a list of names from which the user will select */
|
|
for (ep = ldap_first_entry(ld, list); ep != NULL; ep = ldap_next_entry(ld, ep)) {
|
|
|
|
names[i] = ldap_get_dn(ld, ep);
|
|
rdns = ldap_explode_dn(names[i], TRUE);
|
|
cpp = ldap_get_values(ld, ep, "title");
|
|
if (cpp == NULL)
|
|
printf(" %3d. %s\n", i, *rdns);
|
|
else
|
|
printf(" %3d. %s, %s\n", i, *rdns, *cpp);
|
|
ldap_value_free(rdns);
|
|
ldap_value_free(cpp);
|
|
i++;
|
|
if ((rest++ > (lpp - 1)) && (i < *matches)) {
|
|
again:
|
|
printf(" More? ");
|
|
fflush(stdout);
|
|
fetch_buffer(resp, sizeof(resp), stdin);
|
|
if ((resp[0] == 'n') || (resp[0] == 'N'))
|
|
break;
|
|
else if ((num_picked = atoi(resp)) != 0) {
|
|
if (num_picked < i)
|
|
break;
|
|
else
|
|
goto again;
|
|
}
|
|
rest = 1;
|
|
}
|
|
}
|
|
*matches = i - 1;
|
|
names[i] = NULL;
|
|
return;
|
|
}
|
|
|
|
int
|
|
find_all_subscribers( char **sub, char *group )
|
|
{
|
|
int count;
|
|
LDAPMessage *result;
|
|
static char *attributes[] = { "cn", NULL };
|
|
char filter[MED_BUF_SIZE];
|
|
register LDAPMessage *ep;
|
|
register int i = 0;
|
|
|
|
#ifdef DEBUG
|
|
if (debug & D_TRACE)
|
|
printf("->find_all_subscribers(%x, %s)\n", sub, group);
|
|
#endif
|
|
|
|
sprintf(filter, "%s=%s", "memberOfGroup", group);
|
|
if (ldap_search_s(ld, search_base, LDAP_SCOPE_SUBTREE, filter, attributes, FALSE, &result) != LDAP_SUCCESS) {
|
|
int ld_errno = 0;
|
|
ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
|
|
if (ld_errno == LDAP_NO_SUCH_ATTRIBUTE)
|
|
return(0);
|
|
ldap_perror(ld, "ldap_search_s");
|
|
return(0);
|
|
}
|
|
count = ldap_count_entries(ld, result);
|
|
if (count < 1) {
|
|
ldap_msgfree(result);
|
|
return(0);
|
|
}
|
|
if ( count > MAX_VALUES ) {
|
|
printf( " Only retrieving the first %d subscribers....\n",
|
|
MAX_VALUES );
|
|
}
|
|
|
|
for (ep = ldap_first_entry(ld, result); i < MAX_VALUES && ep != NULL; ep = ldap_next_entry(ld, ep)) {
|
|
sub[i++] = ldap_get_dn(ld, ep);
|
|
#ifdef DEBUG
|
|
if (debug & D_PARSE)
|
|
printf("sub[%d] = %s\n", i - 1, sub[i - 1]);
|
|
#endif
|
|
}
|
|
sub[i] = NULL;
|
|
ldap_msgfree(result);
|
|
return(count);
|
|
}
|
|
|
|
char *
|
|
fetch_boolean_value( char *who, struct attribute attr )
|
|
{
|
|
LDAPMessage *result; /* from the search below */
|
|
register LDAPMessage *ep; /* entry pointer */
|
|
register char **vp; /* for parsing the result */
|
|
static char *attributes[] = { NULL, NULL };
|
|
|
|
#ifdef DEBUG
|
|
if (debug & D_TRACE)
|
|
printf("->fetch_boolean_value(%s, %s)\n", who, attr.quipu_name);
|
|
#endif
|
|
attributes[0] = attr.quipu_name;
|
|
if (ldap_search_s(ld, who, LDAP_SCOPE_BASE, "objectClass=*", attributes, FALSE, &result) != LDAP_SUCCESS) {
|
|
int ld_errno = 0;
|
|
ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
|
|
if (ld_errno == LDAP_NO_SUCH_ATTRIBUTE)
|
|
return("FALSE");
|
|
ldap_perror(ld, "ldap_search_s");
|
|
ldap_msgfree(result);
|
|
return(NULL);
|
|
}
|
|
|
|
/*
|
|
* We did a read on one name and only asked for one attribute.
|
|
* There's no reason to loop through any of these structures.
|
|
*
|
|
* If ldap_first_attribute() returns NULL, then this entry did
|
|
* not have this particular attribute.
|
|
*/
|
|
ep = ldap_first_entry(ld, result);
|
|
if ((vp = (char **) ldap_get_values(ld, ep, attr.quipu_name)) == NULL) {
|
|
ldap_msgfree(result);
|
|
return("FALSE");
|
|
}
|
|
else {
|
|
ldap_msgfree(result);
|
|
if (!strcasecmp(*vp, "TRUE")) {
|
|
ldap_value_free(vp);
|
|
return("TRUE");
|
|
}
|
|
else if (!strcasecmp(*vp, "FALSE")) {
|
|
ldap_value_free(vp);
|
|
return("FALSE");
|
|
}
|
|
else {
|
|
fprintf(stderr, " Got garbage -> [%s]\n", *vp);
|
|
ldap_value_free(vp);
|
|
return(NULL);
|
|
}
|
|
}
|
|
}
|