Skip to content
Snippets Groups Projects
Commit 005ae0b4 authored by Kurt Zeilenga's avatar Kurt Zeilenga
Browse files

Move to attic

parent 211de312
No related branches found
No related tags found
No related merge requests found
Showing
with 0 additions and 2006 deletions
This is not really a bugs list (would I admit to having bugs? :-) but a
limitations list.
This implementation attempts to implement most of the proposed whois++
interface but those sections that conflict with the underlying X.500 service
are not implemented. This includes such things as the indexing service. While
it would be possible to provide this functionality it is likely that a
production X.500 Directory will have restrictions on access to the Directory
in order to prevent "trawling" of data. It is unlikely that such a site
would wish to allow an indexing server carte blanche access to it's data in
order to index it.
The current version also doesn't support multiple languages, this is not
because I don't think it's a good idea (I do), but rather due to my wish to
get this thing out of the door! As a result of this attributes are returned
using their X.500 attribute names rather than using "whois++" names. Once
the code to do multi-lingual support has been integrated these attributes
will be returned in the natural language specified by the client.
Some responses are returned as system messages, and some are returned as
normal messages (with or without a leading space). At present there is no
real consistancy, which is a result of me coding whatever I thought was best
at the time. The current draft lacks adequate direction (except for search
results) as to the format of responses but once this has been fixed I will
correct the code.
I am using a beta version of the LDAP beta code (possibly not the latest
version) to develop this code but you should be able to use any of the
University of Michigan releases, although the patches to the main Makefile
may need some tweaking.
This program has only really been tested with Ultrix although John Farrell
of the ISODE Consortium threw it at SunOS for me so it may work with other
Unix variants but there are no guarantees.
Mark Prior
26 April 93
I assume that you have already obtained the LDAP libraries and installed
them in the appropriate place. This kit should fit into the directory
structure created by LDAP. You should use the root.Makefile.diffs file to
patch the LDAP Makefile so that it knows how to build whois++. This may fail
depending on what version of LDAP you have but the rejections should be
trival to fix (hopefully UMich will release a new version RSN).
This program makes use of a number of definitions defined in the main LDAP
Makefile but it also has a number of it's own definitions that you will
have to modify (all definitions are located in the Makefile).
CONFIG_DIRECTORY At present the configuration directory only contains
the template directory. The files in this directory contain the
attribute fields to return when a template is returned. The objectClass
of an object determines the whois++ template.
HELP_DIRECTORY The server has a number of help files that it may
display when queried by a client. These files are stored under the
specific language.
LDAPHOST Which host is running a ldap server. This program
communicates to the X.500 Directory via LDAP so you must be able to
identify a host that is able to provide this communication.
FACILITY Some error diagnostics are reported via syslog, as is
normal queries if logging is enabled. This variable specifies which
facility to use. I use local3 so I can create a separate log file just
for whois++ but you may wish to log under daemon.
SYSLIBS Any additional libraries required. Ultrix requires -li
to get the Internationalisation support. I also use -lsyslog in order
to link with a 4.3BSD style syslog rather than the ancient syslog that
DEC normally ship with Ultrix.
INTERNATIONAL Define this is you have POSIX international support.
At present this is only used for displaying dates so it's not really
important but I intend to use this facility to support the language
constraint in a future release.
Available under Ultrix but not SunOS.
Once you have modified these variable you should be able to just type "make",
if you are in the whois++ directory, or "make ldap-whois++" from the main
LDAP directory. All going well there should be no problems so "make install",
or "make inst-whois++".
You should now copy the tailor file (whois++dtailor) to the ETCDIR and modify
the base statement to indicate to whois++ where in the DIT whois++ should base
its searches. You may also wish to define a user and password if you need to
authenticate the server.
Modify /etc/inetd.conf to include the new whois++ service with a line such as
whois stream tcp nowait ETCDIR/whois++d whois++d
where ETCDIR is the value of your ETCDIR variable.
You might like to add the -l flag (if you want to log queries) and -i if you
have an info attribute in the base entry (this will be displayed as a system
message).
Now send a HUP (or kill and restart) /etc/inetd.
Note that if you turn on RFC931 lookups you will need the rfc931.c
module from Wietse Venema's log_tcp package (archie should be able to find
you a copy).
Mark Prior
mrp@itd.adelaide.edu.au
#
# Configuration parameters, can be overridden in config file
#
LDAPSRC = ../..
CONFIG_DIRECTORY = $(ETCDIR)/whois++
HELP_DIRECTORY = /usr/local/isode/help/whois++
LDAPHOST = "localhost"
#
# Where to stuff the man page
MANDIR = /usr/local/isode/man
MANSEC = 8
#
# Syslog facility to log queries under, using info serverity level
#
FACILITY = LOG_LOCAL3
#
# Additional system libraries
# Under Ultrix I use the 4.3 syslog, hence the additional syslog library
#
#SYSLIBS = -li -lsyslog
#
# If you want POSIX international support (format of dates), on ultrix
#
#INTERNATIONAL = -DINTERNATIONAL
#
# If you want RFC931 logging you must have log_tcp source available
#
#RFC931DEF = -DRFC931
#RFC931SRC = /local/src/log_tcp/rfc931.c
SRCS = whois++.c command.c config.c describe.c help.c output.c template.c \
util.c version.c $(RFC931SRC)
HDRS = whois++.h
OBJS = ${SRCS:.c=.o}
HOST = `hostname`
# This returns a date such as "26 April 1993", unfortunately SunOS doesn't
# understand the %B abd %Y macros so you may need to change this.
#DATE = `date +'%d %B %Y'`
DATE = `date +'%D'` # this gives 4/26/93 format
REVISION = 2
DEFINES = -DETCDIR=\"$(ETCDIR)\" -DBUILD="\"$(USER)@$(HOST) on $(DATE)\"" \
-DCONFIG_DIRECTORY=\"$(CONFIG_DIRECTORY)\" -DMAIN \
-DHELP_DIRECTORY=\"$(HELP_DIRECTORY)\" -DREVISION="$(REVISION)" \
-DPROTOCOL="\"[FIRST DRAFT - 15 April 1993]\"" -DRELEASE=\"BETA\" \
-DFACILITY=$(FACILITY) -DDEFAULT_LDAPHOST=\"$(LDAPHOST)\" \
$(INTERNATIONAL) $(RFC931DEF)
CFLAGS = -I$(LDAPSRC)/include -I/usr/local/include $(ACFLAGS)
LIBS = -L$(LDAPSRC)/libraries/libldap -lldap -L$(LDAPSRC)/libraries/liblber \
-llber $(SYSLIBS) $(KRBLIBFLAG) $(KRBLIBS)
all: whois++d
whois++d: $(OBJS) $(LDAPSRC)/libraries/libldap/libldap.a
$(CC) $(ALDFLAGS) -o $@ $(OBJS) $(LIBS)
whois++.o: whois++.c $(HDRS)
$(CC) $(CFLAGS) $(DEFINES) -c whois++.c
install: inst-whois++
inst-whois++: $(DESTDIR)$(ETCDIR)/whois++d
-$(MKDIR) $(DESTDIR)$(CONFIG_DIRECTORY)
cp -r templates $(DESTDIR)$(CONFIG_DIRECTORY)
-$(MKDIR) $(DESTDIR)$(HELP_DIRECTORY)
cp -r helpfiles/* $(DESTDIR)$(HELP_DIRECTORY)
-$(MKDIR) $(DESTDIR)$(MANDIR)/man$(MANSEC)
sed -e 's#ETCDIR#$(ETCDIR)#' whois++d.man > $(DESTDIR)$(MANDIR)/man$(MANSEC)/whois++d.$(MANSEC)
@echo "Don't forget to modify and install the tailor file"
$(DESTDIR)$(ETCDIR)/whois++d: whois++d
install -c -m 755 whois++d $(DESTDIR)$(ETCDIR)
lint:;
lint $(SRCS)
5lint:;
/usr/5bin/lint $(SRCS)
clean:;
rm -f *.o core a.out whois++d
depend:;
../mkdep $(CFLAGS) $(SRCS)
# DO NOT DELETE THIS LINE -- mkdep uses it.
# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
This is a DUA interface, using LDAP, that conforms to the latest (not yet)
Internet Draft for the Whois++ Architecture. It does NOT support the indexing
service also proposed under Whois++.
It is a gateway to X.500 (similar to the finger and gopher gateways) which
allows the user to access the directory via a mechanism that they are
comfortable with and/or have access to. The real Directory Service (and the
only practical large scale distributed directory service) is provided by the
underlying X.500 service. This implementation is not an endorsement of Whois++
but I recognise that there are users whose only interface to a directory
service is via a whois client. It therefore attempts to service these users,
much like the other two gateways.
Comments on the Whois++ specification should be sent to the IETF Whois and
Network Information Lookup Service (WNILS) Working Group. The e-mail address
of the group is ietf-wnils@ucdavis.edu, to be added to the mailing list send
a request to ietf-wnils-request@ucdavis.edu. Comments about this program
should be directed to the discussion list ldap-whois++@itd.adelaide.edu.au,
(send a message to ldap-whois++-request@itd.adelaide.edu.au to join). I will
post bug fix announcements to this list.
Mark Prior
6 May 93
Things to do list (well the start of one anyway :-)
. Test on something other than Ultrix
. Finish the multilingual support.
. Make the parser for the query "language" more error resistant
. Do a real parser for the config file
. More help files
. Think about multi charset, although this is probably an issue for LDAP
. Kerberos authentication
This diff is collapsed.
#if !defined(lint)
static char copyright[] = "Copyright 1992 The University of Adelaide";
#endif
/*
* C O N F I G
*
* Author: Mark R. Prior
* Communications and Systems Branch
* Information Technology Division
* The University of Adelaide
* E-mail: mrp@itd.adelaide.edu.au
* Date: October 1992
* Version: 1.7
* Description:
* Process the configuration file.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of Adelaide. 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'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#include "whois++.h"
static struct {
char *str;
int cmd;
} commands[] = {
#define CMD_BASE 1
"base", CMD_BASE,
#define CMD_LDAP 2
"ldaphost", CMD_LDAP,
#define CMD_HELPDIR 3
"helpdir", CMD_HELPDIR,
#define CMD_USER 4
"user", CMD_USER,
#define CMD_PASSWORD 5
"password", CMD_PASSWORD,
#define CMD_CONFIGDIR 6
"configdir", CMD_CONFIGDIR,
#define CMD_CONTACT 7
"contact", CMD_CONTACT,
#define CMD_HOSTNAME 8
"hostname", CMD_HOSTNAME,
#define CMD_LANGUAGE 9
"language", CMD_LANGUAGE,
#define CMD_BANNER 10
"banner", CMD_BANNER,
#define CMD_TEMPLATE 11
"template", CMD_TEMPLATE,
NULL, NULL
};
static nextLine(fp)
FILE *fp;
{
/*
* We probably should check that the user hasn't put anything else
* on the line but I can't be bothered!
*/
register int c;
while ((c = getc(fp)) != EOF && c != '\n')
;
}
/*
* Get next word, skipping blanks & comments.
*/
static int getWord(buffer, size, fp)
char *buffer;
int size;
FILE *fp;
{
char *cp;
int c, string;
string = 0;
cp = buffer;
while ((c = getc(fp)) != EOF) {
if (c == '#') {
while ((c = getc(fp)) != EOF && c != '\n')
;
continue;
}
if (c == '\n') {
if (cp != buffer)
ungetc(c, fp);
break;
} else if (c == '\\') {
c = getc(fp);
if (c == EOF)
c = '\n';
} else if (c == '"') {
string = !string;
continue;
}
if (!string && isspace(c)) {
while (isspace(c = getc(fp)) && c != '\n')
;
ungetc(c, fp);
if (cp != buffer) /* Trailing whitespace */
break;
continue; /* Leading whitespace */
}
if (cp >= buffer+size-1)
break;
*cp++ = c;
}
*cp = '\0';
return (cp != buffer);
}
void readConfiguration( config )
FILE *config;
{
char buffer[BUFSIZ];
char *s;
int i;
/*
* A procedure to read in the configuration parameters.
* At the moment this is just a "quick hack" and it should be
* replaced in the next version by a proper scanner.
*/
while ( getWord( buffer, BUFSIZ, config ) != NULL ) {
for ( i = 0; commands[i].str != NULL; i++ )
if ( EQ( buffer, commands[i].str ) )
break;
if ( commands[i].str == NULL ) {
printFormatted( lineLength, TRUE, stdout,
"Unrecognised command <%s>", buffer );
exit( 1 );
}
if ( getWord( buffer, BUFSIZ, config ) == NULL ) {
printFormatted( lineLength, TRUE, stdout,
"value missing in configuration file" );
exit( 1 );
}
switch ( commands[i].cmd ) {
case CMD_BASE:
base = strdup( buffer );
break;
case CMD_LDAP:
ldaphost = strdup( buffer );
break;
case CMD_HELPDIR:
helpDir = strdup( buffer );
break;
case CMD_USER:
user = strdup( buffer );
break;
case CMD_PASSWORD:
password = strdup( buffer );
break;
case CMD_CONFIGDIR:
configDir = strdup( buffer );
break;
case CMD_CONTACT:
contact = strdup( buffer );
break;
case CMD_HOSTNAME:
hostname = strdup( buffer );
break;
case CMD_LANGUAGE:
defaultLanguage = lowerCase( strdup( buffer ) );
break;
case CMD_BANNER:
banner = strdup( buffer );
break;
case CMD_TEMPLATE:
if ( templateTranslationTable == NULL
&& ( templateTranslationTable = (table *)malloc(sizeof(table)*tableSize) ) == NULL ) {
printFormatted( lineLength, TRUE, stdout,
"Malloc failed" );
exit( 1 );
} else if ( numberOfTemplates+1 == tableSize ) {
tableSize += TABLE_INCREMENT;
if ( ( templateTranslationTable = (table *)realloc(templateTranslationTable, sizeof(table)*tableSize) ) == NULL ) {
printFormatted( lineLength, TRUE, stdout,
"Realloc failed" );
exit( 1 );
}
}
templateTranslationTable[numberOfTemplates].key =
lowerCase( strdup( buffer ) );
if ( getWord( buffer, BUFSIZ, config ) == NULL ) {
printFormatted( lineLength, TRUE, stdout,
"objectClass missing in config file" );
exit( 1 );
}
templateTranslationTable[numberOfTemplates].value =
lowerCase( strdup( buffer ) );
numberOfTemplates++;
break;
default:
printFormatted( lineLength, TRUE, stdout,
"Attribute <%s> not recognised.",
buffer );
break;
}
nextLine( config );
}
}
#if !defined(lint)
static char copyright[] = "Copyright 1992 The University of Adelaide";
#endif
/*
* D E S C R I B E
*
* Author: Mark R. Prior
* Communications and Systems Branch
* Information Technology Division
* The University of Adelaide
* E-mail: mrp@itd.adelaide.edu.au
* Date: October 1992
* Version: 1.7
* Description:
* A module implementing the describe whois++ command.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of Adelaide. 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'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#include "whois++.h"
int displayDescribe( ld, organisation )
LDAP *ld;
char *organisation;
{
int i, len1, len2;
LDAPMessage *result, *entry;
char *value, *ptr;
char **values;
static char *masterDSA[] = { "masterDSA", NULL };
static char *manager[] = { "manager", NULL };
static char *roleOccupant[] = { "roleOccupant", NULL };
static char *attributes[] = { "postalAddress", "telephoneNumber",
"facsimileTelephoneNumber", "mail", "lastModifiedBy",
#if defined(UOFA)
"preferredName",
#endif
NULL };
extern char *index();
if ( !EQ( language, "english" ) )
printFormatted( lineLength, TRUE, stdout,
"The output of the DESCRIBE command must be in english \
according to the IAFA services template." );
printFormatted( lineLength, FALSE, stdout,
"%-19s Whois++", "Service-Name:" );
if ( hostname != NULL )
printFormatted( lineLength, FALSE, stdout, "%-19s %s",
"Primary-Name:", hostname );
else
printFormatted( lineLength, FALSE, stdout,
"%-19s <unknown>", "Primary-Name:" );
printFormatted( lineLength, FALSE, stdout,
"%-19s Whois++ service using LDAP to access a Quipu based",
"Description:" );
printFormatted( lineLength, FALSE, stdout,
"%-19s X.500 Directory Service.", "" );
printFormatted( lineLength, FALSE, stdout,
"%-19s whois++ protocol on tcp port 43", "Access-Protocol:" );
printFormatted( lineLength, FALSE, stdout,
"%-19s whois, x.500, ldap", "Keywords:" );
printFormatted( lineLength, FALSE, stdout,
"%-19s 24 hours a day, 7 days a week", "Access-Times:" );
printFormatted( lineLength, FALSE, stdout,
"%-19s Open Access", "Policy:" );
printFormatted( lineLength, FALSE, stdout,
"%-19s ", "URI:" );
if ( contact == NULL ) {
/*
* The contact hasn't identified themselves in the tailor file
* so lets try to work it out by finding out who manages the
* DSA that masters the organisation's entry!
*/
if ( debug > 2 )
printFormatted( lineLength, TRUE, stdout,
"No contact info provided, searching ..." );
ldap_search_s( ld, organisation, LDAP_SCOPE_BASE,
"objectclass=*", masterDSA, 0, &result );
if ( ld->ld_errno != LDAP_SUCCESS ) {
printFormatted( lineLength, FALSE, stdout,
"%-19s <Unknown>", "Contact:" );
return TRUE;
}
if ( debug > 2 )
printFormatted( lineLength, TRUE, stdout,
"Looking for the master DSA ..." );
if ( (values = ldap_get_values( ld, result, "masterDSA" )) == NULL
|| values[0] == NULL ) {
printFormatted( lineLength, FALSE, stdout,
"%-19s <Unknown>", "Contact:" );
return TRUE;
}
if ( debug > 2 )
printFormatted( lineLength, TRUE, stdout,
"Searching for the DSA manager ..." );
ldap_search_s( ld, values[0], LDAP_SCOPE_BASE, "objectclass=*",
manager, 0, &result );
if ( ld->ld_errno != LDAP_SUCCESS ) {
printFormatted( lineLength, FALSE, stdout,
"%-19s <Unknown>", "Contact:" );
printFormatted( lineLength, TRUE, stdout,
"Search failed, %s",
ldap_err2string( ld->ld_errno ) );
return TRUE;
}
if ( (values = ldap_get_values( ld, result, "manager" )) == NULL ) {
printFormatted( lineLength, FALSE, stdout,
"%-19s <Unknown>", "Contact:" );
return TRUE;
}
if ( debug > 2 )
printFormatted( lineLength, TRUE, stdout,
"Retrieving the DSA manager's entry ..." );
/*
* we have at least one manager for this DSA but which one is
* the "correct" one to list?
*/
len1 = strlen( organisation );
for ( i = 0; values[i] != NULL; i++ )
if ( strlen( values[i] ) >= len1 ) {
len2 = strlen( values[i] );
if ( EQ( organisation, &values[i][len2-len1] ) )
contact = strdup( values[i] );
}
ldap_value_free( values );
if ( contact == NULL ) {
printFormatted( lineLength, FALSE, stdout,
"%-19s <Unknown>", "Contact:" );
if ( debug )
printFormatted( lineLength, TRUE, stdout,
"Cannot find a suitable manager" );
return TRUE;
}
ldap_search_s( ld, contact, LDAP_SCOPE_BASE, "objectclass=*",
roleOccupant, 0, &result );
if ( ld->ld_errno != LDAP_SUCCESS ) {
printFormatted( lineLength, FALSE, stdout,
"%-19s <Unknown>", "Contact:" );
printFormatted( lineLength, TRUE, stdout,
"Search failed, %s",
ldap_err2string( ld->ld_errno ) );
return TRUE;
}
if ( (values = ldap_get_values( ld, result, "roleOccupant" )) != NULL
|| values[0] == NULL ) {
free( contact );
/* Just pick one! */
contact = strdup( values[0] );
ldap_value_free( values );
}
if ( debug > 2 )
printFormatted( lineLength, TRUE, stdout,
"The contact is %s", contact );
}
ldap_search_s( ld, contact, LDAP_SCOPE_BASE, "objectclass=*",
attributes, 0, &result );
if ( ld->ld_errno != LDAP_SUCCESS ) {
printFormatted( lineLength, FALSE, stdout, "%-19s <Unknown>",
"Contact:" );
printFormatted( lineLength, TRUE, stdout,
"Read for \"%s\" returned error, %s", contact,
ldap_err2string( ld->ld_errno ) );
}
#if defined(UOFA)
if ( (values = ldap_get_values( ld, result, "preferredName" )) != NULL
&& values[0] != NULL ) {
printFormatted( lineLength, FALSE, stdout, "%-19s %s",
"Contact:", values[0] );
ldap_value_free( values );
} else {
#endif
value = strdup( ldap_dn2ufn( ldap_get_dn( ld, result ) ) );
if ( (ptr = index( value, ',' )) != NULL )
*ptr = '\0';
printFormatted( lineLength, FALSE, stdout, "%-19s %s",
"Contact:", value );
#if defined(UOFA)
}
#endif
if ( ( values = ldap_get_values( ld, result, "postalAddress" )) != NULL ) {
for ( i = 0; values[i] != NULL; i++ ) {
printFormatted( lineLength, FALSE, stdout, "%-19s %s",
"Postal-Address:",
strtok( values[i], "$" ) );
while ( ( ptr = strtok( NULL, "$" ) ) != NULL )
printFormatted( lineLength, FALSE, stdout,
"%-19s%s", "", ptr );
}
ldap_value_free( values );
}
if ( ( values = ldap_get_values( ld, result, "telephoneNumber" )) != NULL ) {
for ( i = 0; values[i] != NULL; i++ )
printFormatted( lineLength, FALSE, stdout, "%-19s %s",
"Telephone:", values[i] );
ldap_value_free( values );
}
if ( ( values = ldap_get_values( ld, result, "facsimileTelephoneNumber" )) != NULL ) {
for ( i = 0; values[i] != NULL; i++ )
printFormatted( lineLength, FALSE, stdout, "%-19s %s",
"Fax:", values[i] );
ldap_value_free( values );
}
if ( ( values = ldap_get_values( ld, result, "mail" )) != NULL ) {
for ( i = 0; values[i] != NULL; i++ )
printFormatted( lineLength, FALSE, stdout, "%-19s %s",
"Electronic-Address:", values[i] );
ldap_value_free( values );
}
if ( ( values = ldap_get_values( ld, result, "lastModifiedBy" )) != NULL ) {
for ( i = 0; values[i] != NULL; i++ )
printFormatted( lineLength, FALSE, stdout,
"%-19s \"%s\"", "Modified-By:", values[i] );
ldap_value_free( values );
}
return FALSE;
}
#if !defined(lint)
static char copyright[] = "Copyright 1992 The University of Adelaide";
#endif
/*
* H E L P
*
* Author: Mark R. Prior
* Communications and Systems Branch
* Information Technology Division
* The University of Adelaide
* E-mail: mrp@itd.adelaide.edu.au
* Date: October 1992
* Version: 1.7
* Description:
* The Help module
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of Adelaide. 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'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#include "whois++.h"
void needHelp( reason )
char *reason;
{
char filename[MAXPATHLEN];
char buffer[BUFSIZ];
int i;
DIR *dir;
struct dirent *entry;
FILE *help;
if ( reason == NULL || *reason == '\0' ) {
sprintf( filename, "%s/%s/general", helpDir, language );
if ( ( help = fopen( filename, "r" ) ) == NULL ) {
printFormatted( lineLength, TRUE, stdout,
"Sorry cannot open general information help file" );
return;
}
} else {
sprintf( filename, "%s/%s/%s", helpDir, language,
lowerCase( reason ) );
if ( ( help = fopen( filename, "r" ) ) == NULL ) {
sprintf( filename, "%s/%s/%s", helpDir, defaultLanguage,
lowerCase( reason ) );
if ( ( help = fopen( filename, "r" ) ) == NULL ) {
printFormatted( lineLength, TRUE, stdout,
"Sorry cannot open help file for topic \"%s\"",
reason );
return;
} else {
printFormatted( lineLength, TRUE, stdout,
"Sorry no help in %s, using default language (%s).",
language, defaultLanguage );
}
}
}
while ( fgets( buffer, BUFSIZ, help ) != NULL ) {
i = strlen( buffer );
while ( i-- > 0 && ( buffer[i] == '\n' || buffer[i] == '\r' ) )
buffer[i] = '\0';
printFormatted( lineLength, FALSE, stdout, "%s", buffer );
}
fclose( help );
if ( reason == NULL || *reason == '\0' ) {
sprintf( filename, "%s/%s", helpDir, language );
if ( ( dir = opendir( filename ) ) == NULL )
return;
printFormatted( lineLength, FALSE, stdout, "" );
printFormatted( lineLength, FALSE, stdout,
"Further information is available on the following topics" );
for ( entry = readdir( dir ); entry != NULL; entry = readdir( dir ) )
if ( !EQ(entry->d_name, "." ) && !EQ(entry->d_name, ".." ) )
printFormatted( lineLength, FALSE, stdout,
" %s", lowerCase( entry->d_name ) );
closedir( dir );
}
return;
}
List the commands supported by this server.
The whois++ query langauge contains a number of mandatory commands which all
servers should support but there are also a number of optional commands. In
order that a client can find out what commands are supported by a server
there is a mandatory command called "command" that should provide a list of
all commands supported by the server. If you wish to use a command that is
optional you may wish to use the "command" command to find out if the server
supports it.
This server only supports the mandatory commands.
Constraints are a mechanism for modifying the behaviour of the query and are
divided into two classes (local or global) depending on the scope of the
modification. Local contraints may appear attached to each term in a query,
whereas global contraints apply to the entire query and so are listed after
the actual query (separated from the query by a colon).
This implementation supports the following constraints -
1. Local constraints
a. match=(exact|fuzzy)
The directory is either searched for an exact match of the value
specified or soundex style matching is attempted.
If you wish to attempt substring matching you should include a "*" in
your search string.
Default=exact
2. Global constraints
a. format=(full|abridged|handle|summary)
This specifies the format of the response returned by the query.
Normally the format used is controlled by the number of matches but this
constraint may be used to override the default.
b. hold
The connection is held open for a maximum of 60 seconds for further
queries, normally the connection is closed after each query.
c. language=<string>
Return any diagnostics in the natural language specified.
Default=english
d. linelength=<value>
This constraint allows you to indicate the maximum length of lines you
can display via your client.
Default=80
e. maxhits=<value>
The intent of this constraint is to limit the number of hits returned.
Unfortunately in the context of the server communicating with an X.500
server this is generally not possible as the DSA will define the
maximum number of entries it wishes to return. It is still of some use
if you wish to constrain the value to less than the value that the
X.500 directory would normally return.
The default value is dependant on the value configured by the Directory
Administrator into the DSA.
The describe command returns information about this service, formatted
according to the IAFA Services template. This information will include a
description of the service, access policy, and a contract for the person
who manages the Directory.
You have connected to a server that implements the new WHOIS++ specification.
This service is provided via an underlying X.500 Directory Service and so
this server is really only a read-only DUA interface to the X.500 Directory.
A "technical" description of this service may be obtained by using the
"describe" command, this will also list a contact for this service.
This is an experimental implementation of a whois++ service being proposed
by the IETF's WNILS (Whois and Network Information Lookup Service) Working
Group. It uses a (Quipu 8.0 based) X.500 Directory Service as it's
information source.
The whois++ server communicates with the Directory via LDAP (Lightweight
Directory Access Protocol), using the libraries developed by the University
of Michigan. All user search queries are transformed into LDAP queries that
are passed to the X.500 Directory service for resolution.
For "normal" whois style queries we make a number of assumptions on the
attributes of interest depending on the format of the query. If you only
supply a single token it is assumed that you wish to search for a family
name or userid. Multiple tokens imply a search on a full name (commonName
in X.500-speak). We also support e-mail lookups as described in the
original whois RFC (RFC954) however wildcard style searches may be
constrained by the X.500 Directory service.
Example queries
a. ng =>
(|(sn=ng)(userid=ng)(l=ng)(ou=ng)(&(cn=ng)(!(objectClass=person))))
b. zhongyi li =>
(|(l=zhongyi li)(ou=zhongyi li)(preferredName=zhongyi li)\
(cn=*zhongyi * li))
c. mrp@ =>
(|(mail=mrp@*)(userid=mrp))
You can also use structured whois++ queries that specify the attribute to
search as well as value. Searching using uncommon attributes attributes may
be restricted by the X.500 Directory system.
The list command returns a list of the whois++ template types that may be
returned as a result of a query. You can use the show command to return
further information about these templates.
There are 4 different search styles possible when using a whois++ server.
The first of these styles is the familiar whois style query, where your
client supplies a number of tokens and these tokens are converted into a
LDAP search query for processing by the X.500 Directory system.
Example queries
a. ng =>
(|(sn=ng)(userid=ng)(l=ng)(ou=ng)(&(cn=ng)(!(objectClass=person))))
b. Snoke, Robert Lee =>
(&(sn=Snoke)(|(l=Robert Lee Snoke)(ou=Robert Lee Snoke)\
(preferredName=Robert Lee Snoke)(cn=*Robert * Lee * Snoke)))
c. mrp@ =>
(|(mail=mrp@*)(userid=mrp))
As you can see no attribute information was supplied by the client and so
the server must "guess" what information is required. X.500 uses the
attribute cn (commonName) fairly generically to name entries so this is used
in constructing queries. It is assumed that most queries will relate to a
search for a person so the query is composed in such a way to emphasise this
assumption. If only one token is supplied this is assumed to be a family
name whereas if more than one token is supplied this assumed to be the full
name, in order to distinguish the family name you may use the "," syntax as
per example (b).
E-mail lookups as described in the original whois RFC (RFC954) are also
supported however wildcard style searches may be constrained by the X.500
Directory service.
The other search styles involve the use of attributes, where the client
specifies the type of the data that it wishes to search for.
The show command returns a list of attributes that can be returned if a
record of that template type is returned as a result of a query.
The version command provides version number information and should be quoted
when reporting any problems with the server. The information returned will
include the version of the protocol as well as the program's revision number.
#if !defined(lint)
static char copyright[] = "Copyright 1992 The University of Adelaide";
#endif
/*
* O U T P U T
*
* Author: Mark R. Prior
* Communications and Systems Branch
* Information Technology Division
* The University of Adelaide
* E-mail: mrp@itd.adelaide.edu.au
* Date: October 1992
* Version: 1.7
* Description:
* The Output routines
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of Adelaide. 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'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#include <varargs.h>
#include "whois++.h"
extern char *index(), *rindex();
static displayEntry();
static printAttribute();
static char *selectObjectClass( ld, entry )
LDAP *ld;
LDAPMessage *entry;
{
static char *objectClass[] = { "objectClass", NULL };
LDAPMessage *result;
char *dn, *template;
char **val;
int i;
template = NULL;
dn = strdup( ldap_get_dn( ld, entry ) );
ldap_search_s( ld, dn, LDAP_SCOPE_BASE, "objectclass=*", objectClass,
0, &result );
if ( ld->ld_errno != LDAP_SUCCESS ) {
printFormatted( lineLength, TRUE, stdout,
"Read on object \"%s\" failed, %s",
dn, ldap_err2string( ld->ld_errno ) );
free( dn );
return;
} else
free( dn );
if ( ( val = ldap_get_values( ld, result, "objectClass" ) ) == NULL )
return;
for ( i = 0 ; val[i] != NULL ; i++ )
if ( specifyAttributes( lowerCase( val[i] ) ) != NULL ) {
template = strdup( val[i] );
break;
}
ldap_value_free( val );
return template;
}
int displayResult( ld, result, outputFormat )
LDAP *ld;
LDAPMessage *result;
int outputFormat;
{
int i, matches, number = 0;
char *dn;
LDAPMessage *e;
char *objectClass;
char **attributes, **objectClassTable;
matches = ldap_count_entries( ld, result );
if ( log )
syslog( LOG_INFO, "%d match(es) to query", matches );
if ( matches == 0 ) {
printFormatted( lineLength, TRUE, stdout, "No matches found." );
return FALSE;
}
if ( outputFormat == NULL ) {
if ( matches == 1 )
outputFormat = FULL;
else if ( matches <= ABRIDGED_LIMIT )
outputFormat = HANDLE;
else
outputFormat = SUMMARY;
}
switch (outputFormat) {
case FULL:
printFormatted( lineLength, FALSE, stdout,
"#FULL %d", matches );
for ( e = ldap_first_entry( ld, result ); e != NULL;
e = ldap_next_entry( ld, e ) ) {
objectClass = selectObjectClass( ld, e );
dn = ldap_get_dn( ld, e );
printFormatted( lineLength, FALSE, stdout,
"#%s \"%s\"",
objectClassToTemplate( objectClass ), dn );
displayEntry( ld, dn,
specifyAttributes( objectClass ) );
if ( objectClass != NULL )
free( objectClass );
}
printFormatted( lineLength, FALSE, stdout, "#END" );
break;
case ABRIDGED:
/*
* As the DN contains most of the information wanted in
* ABRIDGED format we use HANDLE format even if the client
* really specified ABRIDGED.
*/
printFormatted( lineLength, TRUE, stdout,
"Abridged format is not really supported, the handle \
supplies most of the information specified in the abridged format description \
so we use the handle format instead." );
case HANDLE:
printFormatted( lineLength, FALSE, stdout,
"#HANDLE %d", matches );
for ( e = ldap_first_entry( ld, result ); e != NULL;
e = ldap_next_entry( ld, e ) ) {
objectClass = selectObjectClass( ld, e );
printFormatted( lineLength, FALSE, stdout, " \"%s\" %s",
ldap_get_dn( ld, e ),
objectClassToTemplate( objectClass ) );
if ( objectClass != NULL )
free( objectClass );
}
printFormatted( lineLength, FALSE, stdout, "#END" );
break;
case SUMMARY:
printFormatted( lineLength, FALSE, stdout, "#SUMMARY" );
printFormatted( lineLength, FALSE, stdout, " matches: %d",
matches );
e = ldap_first_entry( ld, result );
objectClass = selectObjectClass( ld, e );
if ( ( objectClassTable = (char **)malloc(sizeof(char **)*matches) ) == NULL ) {
printFormatted( lineLength, TRUE, stdout,
"Malloc failed" );
break;
}
objectClassTable[number++] = objectClass;
printFormatted( lineLength, FALSE, stdout, " templates: %s",
objectClassToTemplate( objectClass ) );
while ( ( e = ldap_next_entry( ld, e ) ) != NULL ) {
objectClass = selectObjectClass( ld, e );
/* have we printed this before? If not do it now */
for ( i = 0; i < number; i++ )
if ( EQ( objectClass, objectClassTable[i] ) )
break;
if ( i < number ) {
if ( objectClass != NULL )
free( objectClass );
} else {
objectClassTable[number++] = objectClass;
printFormatted( lineLength, FALSE, stdout,
" %s",
objectClassToTemplate( objectClass ) );
}
}
printFormatted( lineLength, FALSE, stdout, "#END" );
for ( i = 0; i < number; i++ )
if ( objectClassTable[i] != NULL )
free( objectClassTable[i] );
free( objectClassTable );
break;
}
return TRUE;
}
static displayEntry( ld, dn, attributes )
LDAP *ld;
char *dn, *attributes[];
{
char *ufn;
int i;
char *s, *department;
LDAPMessage *result, *entry;
ldap_search_s( ld, dn, LDAP_SCOPE_BASE, "objectclass=*", attributes,
0, &result );
if ( ld->ld_errno != LDAP_SUCCESS ) {
printFormatted( lineLength, TRUE, stdout,
"Read on object \"%s\" failed, %s", dn,
ldap_err2string( ld->ld_errno ) );
return;
}
entry = ldap_first_entry( ld, result );
if ( entry == NULL ) {
/* something very weird has happened */
printFormatted( lineLength, TRUE, stdout,
"Possible conflict with ACLs for \"%s\"", dn );
return;
}
/*
* Get the UFN version of the DN and then cut it up into
* name and department.
*/
ufn = ldap_dn2ufn( dn );
if ( ( s = index( ufn, ',' ) ) != NULL ) {
*s++ = '\0';
while ( *s != '\0' && isspace( *s ) )
s++;
department = s;
while ( s != NULL && *s != '\0' && !EQ( s, organisation ) )
if ( ( s = index( s, ',' ) ) != NULL ) {
s++;
while ( *s != '\0' && isspace( *s ) )
s++;
}
if ( s != NULL )
if ( s != department ) {
while ( isspace( *--s ) )
;
*s = '\0';
} else
department = NULL;
} else
department = NULL;
/**/ /*
* Name, Organization, Department, Organization-Type, and Handle
* should be read in from language dictionary rather than hard coded.
*/
printFormatted( lineLength, FALSE, stdout, " %-19s %s", "Name", ufn );
if ( department != NULL && *department != '\0' )
printFormatted( lineLength, FALSE, stdout,
" %-19s %s", "Department", department );
printFormatted( lineLength, FALSE, stdout, " %-19s %s",
"Organization", organisation );
if ( category != NULL )
for ( i = 0; category[i] != NULL; i++ )
printFormatted( lineLength, FALSE, stdout, " %-19s %s",
"Organization-type", category[i] );
for ( i = 0; attributes != NULL && attributes[i] != NULL; i++ ) {
printAttribute( ld, attributes[i], entry );
}
printFormatted( lineLength, FALSE, stdout, " %-19s \"%s\"",
"Handle", dn );
free( ufn );
}
char *attributeLabel( attribute )
char *attribute;
{
/**/ /* need to get printable string from language dictionary */
return attribute;
}
static printAttribute( ld, attribute, entry )
LDAP *ld;
char *attribute;
LDAPMessage *entry;
{
char **val;
char *tag, *ptr;
int i;
/**/ /*
* We really should determine whether the attribute value needs line
* processing or not rather than just hard coding in a couple of cases
* but for the moment we will ignore the problem.
*/
if ( ( val = ldap_get_values( ld, entry, attribute )) == NULL )
return;
tag = attributeLabel( attribute );
for ( i = 0; val[i] != NULL; i++ )
if ( EQ( attribute, "lastModifiedTime" ) )
printFormatted( lineLength, FALSE, stdout, " %-19s %s",
tag, convertTime( val[i], locale ) );
else if ( EQ( attribute, "postalAddress" )
|| EQ( attribute, "homePostalAddress" ) ) {
printFormatted( lineLength, FALSE, stdout, " %-19s %s",
tag, strtok( val[i], "$" ) );
while ( ( ptr = strtok( NULL, "$" ) ) != NULL )
printFormatted( lineLength, FALSE, stdout,
" %-19s%s", "", ptr );
} else
printFormatted( lineLength, FALSE, stdout, " %-19s %s",
tag, val[i] );
ldap_value_free( val );
}
printFormatted( lineLength, systemMessage, output, format, va_alist )
int lineLength, systemMessage;
FILE *output;
char *format;
va_dcl
{
va_list ap;
char buffer[BUFSIZ];
char *head, *p, *q;
char *tag;
int count;
if ( systemMessage ) {
lineLength--;
tag = "% ";
} else
tag = "";
va_start( ap );
vsprintf( buffer, format, ap );
va_end( ap );
if ( strlen( buffer ) < lineLength )
fprintf( output, "%s%s\r\n", tag, buffer );
else {
head = buffer;
do {
count = strlen( tag );
for ( q = head; *q && *q != ' '; q++ )
count++;
if ( *q == NULL ) {
fprintf( output, "%s%s\r\n", tag, head );
break;
} else if ( count > lineLength ) {
*q++ = '\0';
fprintf( output, "%s%s\r\n", tag, head );
head = q;
} else {
do {
p = q++;
count++;
for (; *q && *q != ' '; q++ )
count++;
} while ( *p != '\0' && count <= lineLength );
if ( *p != '\0' )
*p++ = '\0';
fprintf( output, "%s%s\r\n", tag, head );
head = p;
}
if ( !systemMessage )
tag = "+ ";
} while ( *head != NULL );
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment