This patch adds support for LDAP URLs to the CERN WWW common code library version 2.17. You will also need a LDAP 3.1 distribution that has the ldap-html.patch patches applies. The WWW library version 2.17 is available here: http://www.w3.org/pub/src/WWWLibrary.tar.Z Apply these patches from the top of the distribution using this command: patch -p -s < libwww-2.17-patch Note that the patches have only been tested with a sun4 build; for other platforms, you will probably need to make some changes. Please report any problems to ldap-support@umich.edu. -Mark Smith *** All/sun4/Makefile.include- Thu Sep 29 09:30:31 1994 --- All/sun4/Makefile.include Tue Mar 21 16:45:05 1995 *************** *** 41,43 **** --- 41,53 ---- # WAISCFLAGS = -DDIRECT_WAIS # HTWAIS = $(WTMP)/Library/$(WWW_MACH)/HTWAIS.o + # + # WHEN COMPILING WITH DIRECT LDAP SUPPORT: + # + # Uncomment these four lines (and edit them, if necessary). + # + LDAPLIBDIR = /usr/local/lib + LDAPLIB = $(LDAPLIBDIR)/libldap.a $(LDAPLIBDIR)/liblber.a + LDAPINC = -I/usr/local/include + LDAPCFLAGS = -DDIRECT_LDAP -DLIBWWW_217 + HTLDAP = $(WTMP)/Library/$(WWW_MACH)/HTLDAP.o diff -cr WWW-2.17/Library/Implementation/CommonMakefile WWW+ldap/Library/Implementation/CommonMakefile *** Library/Implementation/CommonMakefile- Mon Sep 26 10:24:16 1994 --- Library/Implementation/CommonMakefile Tue Mar 21 16:28:35 1995 *************** *** 58,64 **** # This is now done by cat in WWW/All/Implementation/Makefile # include $(ABS)$(CMN)Version.make ! CFLAGS2 = $(CFLAGS) $(WAISCFLAGS) -I$(CMN) $(SOCKS_FLAGS) CERNLIBBIN = $(WWW)/bin --- 58,64 ---- # This is now done by cat in WWW/All/Implementation/Makefile # include $(ABS)$(CMN)Version.make ! CFLAGS2 = $(CFLAGS) $(WAISCFLAGS) $(LDAPCFLAGS) -I$(CMN) $(SOCKS_FLAGS) CERNLIBBIN = $(WWW)/bin *************** *** 71,77 **** $(LOB)/HTList.o $(LOB)/HTString.o $(LOB)/HTAlert.o \ $(LOB)/HTRules.o $(LOB)/HTFormat.o $(LOB)/HTInit.o $(LOB)/HTMIME.o \ $(LOB)/HTHistory.o $(LOB)/HTNews.o $(LOB)/HTGopher.o \ ! $(LOB)/HTTelnet.o $(LOB)/HTWSRC.o $(HTWAIS) \ $(LOB)/HTAAUtil.o $(LOB)/HTAABrow.o $(LOB)/HTAssoc.o \ $(LOB)/HTUU.o $(LOB)/HTMulti.o $(LOB)/HTTeXGen.o \ $(LOB)/HTDirBrw.o $(LOB)/HTDescript.o $(LOB)/HTGuess.o \ --- 71,77 ---- $(LOB)/HTList.o $(LOB)/HTString.o $(LOB)/HTAlert.o \ $(LOB)/HTRules.o $(LOB)/HTFormat.o $(LOB)/HTInit.o $(LOB)/HTMIME.o \ $(LOB)/HTHistory.o $(LOB)/HTNews.o $(LOB)/HTGopher.o \ ! $(LOB)/HTTelnet.o $(LOB)/HTWSRC.o $(HTWAIS) $(HTLDAP) \ $(LOB)/HTAAUtil.o $(LOB)/HTAABrow.o $(LOB)/HTAssoc.o \ $(LOB)/HTUU.o $(LOB)/HTMulti.o $(LOB)/HTTeXGen.o \ $(LOB)/HTDirBrw.o $(LOB)/HTDescript.o $(LOB)/HTGuess.o \ *************** *** 87,93 **** $(CMN)HTList.c $(CMN)HTString.c $(CMN)HTAlert.c $(CMN)HTRules.c \ $(CMN)HTFormat.c $(CMN)HTInit.c $(CMN)HTMIME.c $(CMN)HTHistory.c \ $(CMN)HTNews.c $(CMN)HTGopher.c $(CMN)HTTelnet.c \ ! $(CMN)HTWAIS.c $(CMN)HTWSRC.c \ $(CMN)HTAAUtil.c $(CMN)HTAABrow.c $(CMN)HTAssoc.c \ $(CMN)HTUU.c $(CMN)HTTeXGen.c \ $(CMN)HTDirBrw.c $(CMN)HTDescript.c $(CMN)HTGuess.c \ --- 87,93 ---- $(CMN)HTList.c $(CMN)HTString.c $(CMN)HTAlert.c $(CMN)HTRules.c \ $(CMN)HTFormat.c $(CMN)HTInit.c $(CMN)HTMIME.c $(CMN)HTHistory.c \ $(CMN)HTNews.c $(CMN)HTGopher.c $(CMN)HTTelnet.c \ ! $(CMN)HTWAIS.c $(CMD)HTLDAP.c $(CMN)HTWSRC.c \ $(CMN)HTAAUtil.c $(CMN)HTAABrow.c $(CMN)HTAssoc.c \ $(CMN)HTUU.c $(CMN)HTTeXGen.c \ $(CMN)HTDirBrw.c $(CMN)HTDescript.c $(CMN)HTGuess.c \ *************** *** 107,113 **** $(CMN)HTGopher.h \ $(CMN)HTUtils.h $(CMN)tcp.h $(CMN)HText.h \ $(CMN)HTTelnet.h \ ! $(CMN)HTWAIS.h $(CMN)HTWSRC.h \ $(CMN)HTAAUtil.h $(CMN)HTAABrow.h $(CMN)HTAssoc.h \ $(CMN)HTUU.h $(CMN)HTTeXGen.h \ $(CMN)HTDirBrw.h $(CMN)HTDescript.h $(CMN)HTGuess.h \ --- 107,113 ---- $(CMN)HTGopher.h \ $(CMN)HTUtils.h $(CMN)tcp.h $(CMN)HText.h \ $(CMN)HTTelnet.h \ ! $(CMN)HTWAIS.h $(CMN)HTLDAP.h $(CMN)HTWSRC.h \ $(CMN)HTAAUtil.h $(CMN)HTAABrow.h $(CMN)HTAssoc.h \ $(CMN)HTUU.h $(CMN)HTTeXGen.h \ $(CMN)HTDirBrw.h $(CMN)HTDescript.h $(CMN)HTGuess.h \ *************** *** 299,304 **** --- 299,307 ---- $(LOB)/HTWAIS.o : $(OE) $(CMN)HTWAIS.c $(CMN)HTUtils.h $(CMN)HTList.h $(CC) -c -o $@ $(CFLAGS2) $(WAISINC) $(CMN)HTWAIS.c + + $(LOB)/HTLDAP.o : $(OE) $(CMN)HTLDAP.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(LDAPINC) $(CMN)HTLDAP.c $(LOB)/HTWSRC.o : $(OE) $(CMN)HTWSRC.c $(CMN)HTUtils.h $(CMN)HTList.h $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTWSRC.c *** Library/Implementation/HTAccess.c- Thu Sep 29 07:53:28 1994 --- Library/Implementation/HTAccess.c Tue Mar 21 16:11:12 1995 *************** *** 236,241 **** --- 236,244 ---- #ifdef DIRECT_WAIS GLOBALREF HTProtocol HTWAIS; #endif + #ifdef DIRECT_LDAP + GLOBALREF HTProtocol HTLDAP; + #endif HTRegisterProtocol(&HTFTP); HTRegisterProtocol(&HTNews); #ifdef NEW_CODE *************** *** 245,250 **** --- 248,256 ---- #ifdef DIRECT_WAIS HTRegisterProtocol(&HTWAIS); + #endif + #ifdef DIRECT_LDAP + HTRegisterProtocol(&HTLDAP); #endif #endif /* DECNET */ *** Library/Implementation/HTError.c- Sun Sep 25 09:53:22 1994 --- Library/Implementation/HTError.c Tue Mar 21 16:39:08 1995 *************** *** 63,68 **** --- 63,69 ---- "wais.multi" }, { 0, "WAIS-server doesn't return any data", "wais.multi" }, { 0, "Can't connect to WAIS-server", "wais.multi" }, + { 0, "Unable to search the LDAP directory", "ldap.multi" }, { 0, "System call `%s' failed: ", "system.multi" } }; *** Library/Implementation/HTError.h- Sun Sep 25 10:15:37 1994 --- Library/Implementation/HTError.h Tue Mar 21 16:39:39 1995 *************** *** 62,67 **** --- 62,68 ---- HTERR_WAIS_OVERFLOW, HTERR_WAIS_MODULE, HTERR_WAIS_NO_CONNECT, + HTERR_LDAP_SEARCH_FAILED, HTERR_SYSTEM, HTERR_ELEMENTS /* This MUST be the last element */ } HTErrorElement; *** Library/Implementation/HTLDAP.c- Tue Mar 21 16:48:57 1995 --- Library/Implementation/HTLDAP.c Tue Mar 21 16:44:28 1995 *************** *** 0 **** --- 1,882 ---- + #ifdef DIRECT_LDAP + /* HTLDAP.c + ** LDAP ACCESS + ** + ** (c) COPYRIGHT University of Michigan 1995. + ** Based on HTNews.c which is (c) COPYRIGHT CERN 1995. + ** Please first read the full copyright statement in the file COPYRIGH. + ** + ** History: + ** 9 Jan 95 Written mcs@umich.edu + */ + /* Implements: + */ + + #define APPEND /* Use append methods */ + + #include + #include "HTUtils.h" /* Coding convention macros */ + #include "tcp.h" + + #include "HTML.h" + #include "HTParse.h" + #include "HTFormat.h" + #include "HTAlert.h" + #ifndef OLD_LIBWWW + #include "HTError.h" + #endif + + #include + #include + #include + + #include "HTLDAP.h" + + #define LDAP_SEARCH_OK( e ) ( (e) == LDAP_SIZELIMIT_EXCEEDED || \ + (e) == LDAP_TIMELIMIT_EXCEEDED || \ + (e) == LDAP_SUCCESS ) + + #ifdef WINSOCK + #define LDAP_MEMFREE( p ) ldap_memfree( p ) + #else /* WINSOCK */ + #define LDAP_MEMFREE( p ) free( p ) + #endif /* WINSOCK */ + + struct _HTStream { + CONST HTStreamClass * isa; + /* ... */ + }; + + #define LDAP_PROGRESS(foo) HTProgress(foo) + + #ifndef HT_ERROR + #define HT_ERROR -1 + #endif /* !HT_ERROR */ + + #ifdef OLD_LIBWWW + + #define PROT_TRACE TRACE + + typedef struct { + HTParentAnchor *anchor; + HTStream *output_stream; + HTAtom *output_format; + } HTRequest; + + #endif + + + #ifdef FORCE_TRACE + #if defined( PROT_TRACE ) + #undef PROT_TRACE + #endif /* PROT_TRACE */ + #define PROT_TRACE 1 + #endif /* FORCE_TRACE */ + + + /* Module-wide variables + */ + PRIVATE char * HTLDAPHost; /* set by application */ + PRIVATE char * HTLDAPTmplFile; /* set by application */ + PRIVATE char * HTLDAPFriendlyFile; /* set by application */ + PRIVATE struct ldap_disptmpl * HTLDAPTmplList; /* set by application */ + PRIVATE struct ldap_disptmpl * ldaptmpllist; /* loaded template list */ + PRIVATE FriendlyMap *ldapfriendlymap; /* loaded friendly map */ + + PRIVATE int diagnostic; /* level: 0=none 2=source */ + PRIVATE char *tmpbuf; /* allocated in initialize() */ + + + /* Hypertext object building machinery */ + #define PUTC(c) (*target->isa->put_character)(target, c) + #define PUTS(s) (*target->isa->put_string)(target, s) + #define START(e) (*target->isa->start_element)(target, e, 0, 0) + #define END(e) (*target->isa->end_element)(target, e) + #ifdef OLD_LIBWWW + #define FREE_TARGET (*target->isa->free)(target) + #else /* OLD_LIBWWW */ + #define FREE_TARGET (*target->isa->_free)(target) + #endif /* OLD_LIBWWW */ + + + + /* + ** There are two configurable items used by the HTLDAP module: + ** + ** 1. The default LDAP server hostname + ** defaulted from compile-time DEFAULT_LDAP_HOST macro + ** set by calling HTSetLDAPHost() + ** + ** 2. The LDAP display template configuration + ** defaulted from the compile-time LDAP_TEMPLATE_FILE macro + ** set by calling either: + ** HTSetLDAPTmplFile() + ** or HTSetLDAPTmplList() + */ + + /* retrieve the default LDAP server hostname + ** ---------------------------------------- + */ + PUBLIC CONST char * HTGetLDAPHost NOARGS + { + return( HTLDAPHost ); + } + + + /* set the default LDAP server hostname + ** ------------------------------------ + */ + PUBLIC void HTSetLDAPHost ARGS1(CONST char *, value) + { + if ( HTLDAPHost != NULL ) { + free( HTLDAPHost ); + } + StrAllocCopy( HTLDAPHost, value ); + } + + + /* get the name of the LDAP display template configuration file + ** ------------------------------------------------------------ + */ + PUBLIC CONST char*HTGetLDAPTmplFile NOARGS + { + return( HTLDAPTmplFile ); + } + + + /* set the name of the LDAP display template configuration file + ** ------------------------------------------------------------ + */ + PUBLIC void HTSetLDAPTmplFile ARGS1(CONST char *, filename ) + { + if ( HTLDAPTmplFile != NULL ) { + free( HTLDAPTmplFile ); + } + StrAllocCopy( HTLDAPTmplFile, filename ); + if ( HTLDAPTmplList == NULL && ldaptmpllist != NULL ) { + ldap_free_templates( ldaptmpllist ); + } + HTLDAPTmplList = ldaptmpllist = NULL; + } + + + /* set the LDAP display template list + ** ---------------------------------- + */ + PUBLIC void HTSetLDAPTmplList ARGS1(struct ldap_disptmpl *, tmpllist) + { + if ( HTLDAPTmplFile != NULL ) { + free( HTLDAPTmplFile ); + HTLDAPTmplFile = NULL; + } + if ( HTLDAPTmplList == NULL && ldaptmpllist != NULL ) { + ldap_free_templates( ldaptmpllist ); + ldaptmpllist = NULL; + } + HTLDAPTmplList = tmpllist; + } + + + /* get the name of the LDAP "friendly names" configuration file + ** ------------------------------------------------------------ + */ + PUBLIC CONST char*HTGetLDAPFriendlyFile NOARGS + { + return( HTLDAPFriendlyFile ); + } + + + /* set the name of the LDAP "friendly names" configuration file + ** ------------------------------------------------------------ + */ + PUBLIC void HTSetLDAPFriendlyFile ARGS1(CONST char *, filename ) + { + if ( HTLDAPFriendlyFile != NULL ) { + free( HTLDAPFriendlyFile ); + } + StrAllocCopy( HTLDAPFriendlyFile, filename ); + if ( ldapfriendlymap != NULL ) { + ldap_free_friendlymap( &ldapfriendlymap ); + } + } + + + /* Initialization for this module + ** ------------------------------ + */ + PRIVATE BOOL initialized = NO; + + PRIVATE BOOL initialize NOARGS + { + if (!HTLDAPHost) HTSetLDAPHost( DEFAULT_LDAP_HOST ); + if (!HTLDAPTmplFile) HTSetLDAPTmplFile( LDAP_TEMPLATE_FILE ); + if (!HTLDAPFriendlyFile) HTSetLDAPFriendlyFile( LDAP_FRIENDLY_FILE ); + if (( tmpbuf = (char *)malloc( 1024 )) == NULL ) { + return( NO ); + } + + return( YES ); + } + + + PRIVATE void write_dn_anchor ARGS4( + HTStream *, target, + char *, label, + char *, hostport, + char *, dn) + { + char *s; + + #ifdef OLD_LIBWWW + if (( s = HTEscape( dn )) == NULL ) { + #else + if (( s = HTEscape( dn, URL_XPALPHAS )) == NULL ) { + #endif + PUTS( "Error: HTEscape failed.\n" ); + } else { + sprintf( tmpbuf, "%s\n", LDAP_URL_PREFIX, + hostport, s, label ); + free( s ); + if ( PROT_TRACE ) { + fprintf( stderr, "write_dn_anchor: %s", tmpbuf ); + } + PUTS( tmpbuf ); + } + } + + + /* add a new error to error list in request + ** ---------------------------------------- + */ + PRIVATE int report_ldap_error ARGS2( + HTRequest *, request, + LDAP *, ldp) + { + int err; + char errs[ 128 ]; + #ifdef OLD_LIBWWW + HTStream *target; + + target = request->output_stream; + #endif /* OLD_LIBWWW */ + + + err = ( ldp == NULL ) ? LDAP_SERVER_DOWN : ldp->ld_errno; + + #ifdef OLD_LIBWWW + sprintf( errs, "Unable to access LDAP directory (%s)", + ldap_err2string( err )); + LDAP_PROGRESS( errs ); + #else /* OLD_LIBWWW */ + sprintf( errs, "(%s)", ldap_err2string( err )); + HTErrorAdd( request, ERR_FATAL, NO, HTERR_LDAP_SEARCH_FAILED, errs, + 0, NULL ); + #endif /* OLD_LIBWWW */ + + return( err ); + } + + + /* add an LDAP DN as the title of target + ** ------------------------------------- + */ + PRIVATE void start_dn_titled_html ARGS3( + HTStream *, target, + char *, dn, + int, inbody) + { + char *ufn, *s; + + if ( dn == NULL || *dn == '\0' ) { + s = "The World"; + ufn = NULL; + } else { + if (( ufn = ldap_dn2ufn( dn )) != NULL ) { + s = ufn; + } else { + s = dn; + } + } + + PUTS( "\n\n" ); + PUTS( s ); + PUTS( "\n\n\n" ); + + if ( inbody ) { + PUTS( "

" ); + PUTS( s ); + PUTS( "

\n" ); + } + + if ( ufn != NULL ) { + LDAP_MEMFREE( ufn ); + } + } + + + /* PUTS() callable from ldap_entry2html... routines + ** ---------------------------------------------- + */ + PRIVATE int html_write_proc ARGS3( + void *, writeparm, /* actually the target */ + char *, s, + int, len ) + { + HTStream *target = (HTStream *)writeparm; + + PUTS( s ); + return( 0 ); + } + + + /* + ** try to determine if an the entry wich objectclasses "ocvals" is + ** a leaf or non-leaf entry + */ + PRIVATE int isnonleaf ARGS1( char **, ocvals ) + { + int i, quipuobject; + + if ( ocvals == NULL ) { + return( 0 ); + } + + quipuobject = 0; + + for ( i = 0; ocvals[i] != NULL; i++ ) { + if ( strcasecomp( ocvals[i], "quipuObject" ) == 0 ) + quipuobject = 1; + if ( strcasecomp( ocvals[i], "quipuNonLeafObject" ) == 0 || + strcasecomp( ocvals[i], "externalNonLeafObject" ) == 0 ) { + return( 1 ); + } + } + + /* + * not a quipu thang - no easy way to tell leaves from nonleaves + * except by trying to search or list. ldap only lets us search. + * since this is too expensive, we guess for now. + */ + return( quipuobject ? 0 : 1 ); + } + + + /* "render" a list of directory entries in HTML + ** -------------------------------------------- + */ + PRIVATE int entrylist2html ARGS6( + HTStream *, target, + LDAP *, ldp, + int, entcount, + LDAPMessage *, ldres, + char *, base, + char *, hostport) + { + char *dn, *ufn, *s, **vals; + LDAPMessage *entry; + struct ldap_disptmpl *dtp; + + start_dn_titled_html( target, base, 1 ); + sprintf( tmpbuf, "

%d entries were found", entcount ); + PUTS( tmpbuf ); + + if ( ldp->ld_errno == LDAP_SIZELIMIT_EXCEEDED || + ldp->ld_errno == LDAP_TIMELIMIT_EXCEEDED ) { + sprintf( tmpbuf, + " (not all entries were returned because a %slimit was exceeded)", + ldp->ld_errno == LDAP_SIZELIMIT_EXCEEDED ? "size" : "time" ); + PUTS( tmpbuf ); + } + + ldap_sort_entries( ldp, &ldres, NULL, strcasecomp ); + + PUTS( "\n


\n\n" ); + + for ( entry = ldap_first_entry( ldp, ldres ); entry != NULL; + entry = ldap_next_entry( ldp, entry )) { + PUTS( "
  • \n" ); + if (( dn = ldap_get_dn( ldp, entry )) == NULL ) { + PUTS( "Error: unable to get DN\n" ); + } else { + vals = ldap_explode_dn( dn, 1 ); + s = tmpbuf + 512; /* top half of scratch buffer */ + if ( vals == NULL || vals[ 0 ] == NULL ) { + strcpy( s, dn ); + } else { + if ( vals[ 1 ] == NULL ) { /* at root level */ + strcpy( s, ldap_friendly_name( HTLDAPFriendlyFile, + vals[ 0 ], &ldapfriendlymap )); + } else { + strcpy( s, vals[ 0 ] ); + } + } + ldap_value_free( vals ); + write_dn_anchor( target, s, hostport, dn ); + if (( vals = ldap_get_values( ldp, entry, LDAP_ATTR_OBJECTCLASS )) + != NULL ) { + if (( dtp = ldap_oc2template( vals, ldaptmpllist )) != NULL ) { + sprintf( tmpbuf, " (%s)\n", dtp->dt_name ); + PUTS( tmpbuf ); + } + ldap_value_free( vals ); + } + } + } + + PUTS( "
  • \n\n\n" ); + return( 0 ); + } + + + /* do an LDAP search asynchronously + ** -------------------------------- + ** + ** returns HT_OK if search done, HT_NOT_LOADED if some error, and + ** HT_INTERRUPTED if interrupted + ** + */ + PRIVATE int ldap_search_async ARGS8( + LDAP *, ldp, + char *, base, + int, scope, + char *, filter, + char **, attrs, + int, attrsonly, + LDAPMessage **, ldresp, + int *, ldaperr ) + { + int msgid; + struct timeval tv; + + #ifndef OLD_LIBWWW + /* XXX need to use HTThread stuff, but we are synchronous for now */ + *ldaperr = ldap_search_s( ldp, base, scope, filter, attrs, attrsonly, + ldresp ); + return( HT_OK ); + #else /* OLD_LIBWWW */ + + tv.tv_sec = 0; + tv.tv_usec = 100000; + + if (( msgid = ldap_search( ldp, base, scope, filter, attrs, + attrsonly )) < 0 ) { + return( HT_NOT_LOADED ); + } + + while(( *ldaperr = ldap_result( ldp, msgid, 1, &tv, ldresp )) == 0 ) { + if ( HTCheckActiveIcon( 1 )) { /* interrupted by the user */ + ldap_abandon( ldp, msgid ); + return( HT_INTERRUPTED ); + } + } + + if ( *ldaperr != -1 ) { + *ldaperr = ldap_result2error( ldp, *ldresp, 0 ); + } + + return( HT_OK ); + #endif /* OLD_LIBWWW */ + } + + + /* perform a directory lookup using LDAP + ** ------------------------------------- + */ + PRIVATE int do_ldap_search ARGS7( + HTRequest *, request, + char *, hostport, + char *, base, + int, scope, + char *, filter, + char **, attrlist, + int, doread ) + { + int hterr, err, port, entcount, nonleaf; + char *host, *ports; + LDAP *ldp; + LDAPMessage *ldres, *entry; + struct ldap_disptmpl *tmpl; + HTStream *target; + + if ( PROT_TRACE ) { + fprintf( stderr, "do_ldap_search: hostport <%s> base <%s>\n", + hostport, base ); + fprintf( stderr, "do_ldap_search: scope %d filter <%s>\n", + scope, filter ); + fprintf( stderr, "do_ldap_search: attrs " ); + if ( attrlist == NULL ) { + fputs( "ALL", stderr ); + } else { + int i; + + for ( i = 0; attrlist[ i ] != NULL; ++i ) { + fprintf( stderr, "<%s> ", attrlist[ i ] ); + } + } + fputc( '\n', stderr ); + } + + ports = NULL; + ldres = NULL; + target = NULL; + nonleaf = 0; /* if we are doing a read, this is reset later */ + + if ( ldaptmpllist == NULL ) { /* ensure that display templates are loaded */ + ldap_init_templates( HTLDAPTmplFile, &ldaptmpllist ); + } + + port = LDAP_PORT; /* from ldap.h */ + if ( hostport == NULL || *hostport == '\0' ) { + host = HTLDAPHost; + } else { + host = hostport; + if (( ports = strchr( hostport, ':' )) != NULL ) { + port = htons( atol( ports + 1 )); + *ports = '\0'; /* null-terminate host name part */ + } + } + + LDAP_PROGRESS( "Connecting to the LDAP Server" ); + if (( ldp = ldap_open( host, port )) == NULL ) { + report_ldap_error( request, ldp ); + return( HT_ERROR ); + } + + ldp->ld_deref = LDAP_DEREF_FINDING; + + if ( ports != NULL ) { + *ports = ':'; /* restore original hostport string */ + } + + if ( ldap_simple_bind_s( ldp, NULL, NULL ) != LDAP_SUCCESS ) { + report_ldap_error( request, ldp ); + ldap_unbind( ldp ); + return( HT_ERROR ); + } + + LDAP_PROGRESS( "Searching the LDAP Directory" ); + + if (( hterr = ldap_search_async( ldp, base, scope, filter, attrlist, 0, + &ldres, &err )) != HT_OK ) { + return( hterr ); + } + + if ( !LDAP_SEARCH_OK( err )) { + report_ldap_error( request, ldp ); + ldap_unbind( ldp ); + return( HT_ERROR ); + } + + if ( ldres == NULL ) { + return( HT_ERROR ); + } + + #ifdef OLD_LIBWWW + if (( target = HTStreamStack( HTAtom_for( "text/html" ), + request->output_format, 0, request->output_stream, + request->anchor )) != NULL ) { + #else /* OLD_LIBWWW */ + #ifdef LIBWWW_217 + if (( target = HTStreamStack( HTAtom_for( "text/html" ), + request, NO )) != NULL ) { + #else /* LIBWWW_217 */ + if (( target = HTStreamStack( HTAtom_for( "text/html" ), + request->output_format, request->output_stream, + request, NO )) != NULL ) { + #endif /* LIBWWW_217 */ + #endif /* OLD_LIBWWW */ + } + + entcount = ldap_count_entries( ldp, ldres ); + + switch ( entcount ) { + case 0: + start_dn_titled_html( target, base, 1 ); + PUTS( "
    \nNo entries found\n\n\n" ); + break; + case 1: + entry = ldap_first_entry( ldp, ldres ); + + if ( doread && entry != NULL ) { + char *dn, **ocvals; + + LDAP_PROGRESS( "Reading LDAP Directory Entry" ); + + dn = ldap_get_dn( ldp, entry ); + + ocvals = ldap_get_values( ldp, entry, LDAP_ATTR_OBJECTCLASS ); + nonleaf = isnonleaf( ocvals ); + tmpl = ldap_oc2template( ocvals, ldaptmpllist ); + if ( ocvals != NULL ) { + ldap_value_free( ocvals ); + } + + if ( tmpl == NULL ) { + attrlist = NULL; + } else { + attrlist = ldap_tmplattrs( tmpl, NULL, 1, LDAP_SYN_OPT_DEFER ); + } + + ldap_msgfree( ldres ); + + ldp->ld_deref = LDAP_DEREF_ALWAYS; + hterr = ldap_search_async( ldp, dn, LDAP_SCOPE_BASE, + LDAP_READ_FILTER, attrlist, 0, &ldres, &err ); + LDAP_MEMFREE( dn ); + if ( hterr != HT_OK ) { + return( HT_ERROR ); + } + + if ( !LDAP_SEARCH_OK( err )) { + report_ldap_error( request, ldp ); + ldap_unbind( ldp ); + return( HT_ERROR ); + } + entry = ldap_first_entry( ldp, ldres ); + } else { + tmpl = NULL; + } + + if ( entry != NULL ) { + sprintf( tmpbuf, "%s//%s/", LDAP_URL_PREFIX, hostport ); + err = ldap_entry2html( ldp, NULL, entry, tmpl, NULL, NULL, + html_write_proc, target, "\n", 2, + LDAP_DISP_OPT_DOSEARCHACTIONS | + ( nonleaf ? LDAP_DISP_OPT_NONLEAF : 0 ), base, tmpbuf ); + } + break; + default: + err = entrylist2html( target, ldp, entcount, ldres, base, hostport ); + } + + ldap_msgfree( ldres ); + ldap_unbind( ldp ); + + if ( target ) { + FREE_TARGET; + } + + return ( err != 0 ) ? HT_ERROR : HT_LOADED; + } + + + /* Load by name HTLoadLDAP + ** ============ + */ + /* LDAP URLs look like: + ** + ** l d a p : / / hostport / dn [ ? attributes [ ? scope [ ? filter ] ] ] + ** + ** where: + ** attributes is a comma separated list + ** scope is one of these three strings: base one sub + ** filter is an string-represented filter as in RFC 1XXX + ** + ** e.g., ldap://ldap.itd.umich.edu/c=US?o,description?one?o=umich + */ + #ifdef OLD_LIBWWW + PUBLIC int HTLoadLDAP ARGS4( + char *, arg, + HTParentAnchor *, anAnchor, + HTFormat, format_out, + HTStream*, sink) + #else /* OLD_LIBWWW */ + PUBLIC int HTLoadLDAP ARGS1(HTRequest *, request) + #endif /* OLD_LIBWWW */ + { + int i, status, scope, customfilter, doing_read; + BOOL fatal; + char *url, *filter, *hostport, *dn, *attrs, *scopes, *s, **attrlist; + char *p1, *p2; /* free before returning if non-NULL */ + char *ocattrlist[] = { LDAP_ATTR_OBJECTCLASS, NULL }; + #ifdef OLD_LIBWWW + HTRequest requestst, *request; + + requestst.anchor = anAnchor; + requestst.output_format = format_out; + requestst.output_stream = sink; + request = &requestst; + #endif /* OLD_LIBWWW */ + + status = HT_ERROR; + fatal = NO; + + /* check argument(s) + */ + if ( !request || !request->anchor ) { + if ( PROT_TRACE ) { + fprintf( stderr, "HTLoadLDAP bad argument\n" ); + } + return( status ); + } + + + /* get URL and initialize + */ + diagnostic = ( request->output_format == WWW_SOURCE ); + url = HTAnchor_physical( request->anchor ); + + if ( PROT_TRACE ) { + fprintf(stderr, "HTLDAP... Looking for `%s'\n", url); + } + + if ( !initialized ) initialized = initialize(); + if ( !initialized ) return( status ); /* FAIL */ + + + /* Set up some defaults + */ + scope = LDAP_SCOPE_BASE; + filter = LDAP_READ_FILTER; + customfilter = 0; + + + /* Get LDAP server name and optional port number + */ + hostport = HTParse( url, "", PARSE_HOST ); + + + /* Get distinguished name + */ + p2 = HTParse( url, "", PARSE_PATH | PARSE_PUNCTUATION) ; + dn = p2 + 1; /* omit leading slash */ + + + /* Optional attribute list + */ + if (( attrs = strchr( dn, '?' )) != NULL ) { + *attrs = '\0'; /* null terminate dn */ + ++attrs; + + /* Optional search scope + */ + if (( scopes = strchr( attrs, '?' )) != NULL ) { + *scopes = '\0'; /* null terminate attribute list */ + ++scopes; + + /* Optional filter + */ + if (( s = strchr( scopes, '?' )) != NULL ) { + *s = '\0'; /* null terminate search scope string */ + if ( *++s != '\0' ) { + filter = s; + HTUnEscape( filter ); + customfilter = 1; + } + } + + /* Translate scope string to LDAP internal number + */ + if ( strcmp( scopes, "one" ) == 0 ) { + scope = LDAP_SCOPE_ONELEVEL; + } else if ( strcmp( scopes, "base" ) == 0 ) { + scope = LDAP_SCOPE_BASE; + } else if ( strcmp( scopes, "sub" ) == 0 ) { + scope = LDAP_SCOPE_SUBTREE; + } else if ( *scopes != '\0' ) { + fatal = YES; + } + } + } + + if ( attrs != NULL ) { + StrAllocCopy( attrs, attrs ); + } + + if ( attrs != NULL && *attrs != '\0' ) { + /* turn comma-separated attribute list into null-terminated array + */ + char *p; + int nattrs; + + for ( nattrs = 1, p = attrs; *p != '\0'; ++p ) { + if ( *p == LDAP_ATTR_SEPARATOR ) { + ++nattrs; + } + } + + if (( attrlist = (char **)calloc( nattrs + 1, sizeof( char * ))) + == NULL ) { + attrlist = NULL; + fatal = YES; + } else { + for ( p = attrs, --nattrs; nattrs >= 0; --nattrs ) { + attrlist[ nattrs ] = p; + if (( p = strchr( p, LDAP_ATTR_SEPARATOR )) != NULL ) { + *p++ ='\0'; + } + } + + for ( i = 0; attrlist[ i ] != NULL; ++i ) { + HTUnEscape( attrlist[ i ] ); + } + } + } else { + attrlist = ocattrlist; + } + + if ( *dn != '\0' ) { + HTUnEscape( dn ); + } else { + dn = NULL; + } + + if (PROT_TRACE) { + fprintf( stderr, "HTLDAP: fatal %d hostport <%s> dn <%s>\n", + fatal, hostport, dn ); + fprintf( stderr, "HTLDAP: scope %d filter <%s>\n", scope, filter ); + fprintf( stderr, "HTLDAP: attrs " ); + if ( attrlist == NULL ) { + fputs( "ALL", stderr ); + } else { + for ( i = 0; attrlist[ i ] != NULL; ++i ) { + fprintf( stderr, "<%s> ", attrlist[ i ] ); + } + } + fputc( '\n', stderr ); + } + + if (!fatal) { + status = do_ldap_search( request, hostport, dn, scope, filter, + attrlist, attrlist == ocattrlist ); + } + + /* clean up allocated memory + */ + if ( hostport != NULL ) { + free( hostport ); + } + if ( p1 != NULL ) { + free( p1 ); + } + if ( p2 != NULL ) { + free( p2 ); + } + if ( attrs != NULL ) { + free( attrs ); + } + if ( attrlist != NULL ) { + free( attrlist ); + } + + return ( status ); + } + + + #ifdef OLD_LIBWWW + PUBLIC HTProtocol HTLDAP = { + "ldap", HTLoadLDAP, NULL + }; + #else /* OLD_LIBWWW */ + #ifdef LIBWWW_217 + GLOBALDEF PUBLIC HTProtocol HTLDAP = { + "ldap", HTLoadLDAP, NULL, NULL + }; + #else /* LIBWWW_217 */ + GLOBALDEF PUBLIC HTProtocol HTLDAP = { + "ldap", SOC_BLOCK, HTLoadLDAP, NULL, NULL + }; + #endif /* LIBWWW_217 */ + #endif /* OLD_LIBWWW */ + + #endif /* DIRECT_LDAP */ *** Library/Implementation/HTLDAP.h- Tue Mar 21 16:49:00 1995 --- Library/Implementation/HTLDAP.h Tue Mar 21 16:12:11 1995 *************** *** 0 **** --- 1,52 ---- + /* Lightweight Directory Access Protocol (LDAP) module for the WWW library. + * + * LDAP is defined in RFC-1487. + *//* + * This module is implemented by HTLDAP.c, and it is a part of the + * Library of Common Code. + */ + #ifndef HTLDAP_H + #define HTLDAP_H + + #include "HTAccess.h" + #include "HTAnchor.h" + + #ifndef DEFAULT_LDAP_HOST + #define DEFAULT_LDAP_HOST "ldap" + #endif + + + #ifndef LDAP_TEMPLATE_FILE + #define LDAP_TEMPLATE_FILE "/usr/local/etc/ldaptemplates.conf" + #endif + + #ifndef LDAP_FRIENDLY_FILE + #define LDAP_FRIENDLY_FILE "/usr/local/etc/ldapfriendly" + #endif + + #ifdef OLD_LIBWWW + extern HTProtocol HTLDAP; + #else /* OLD_LIBWWW */ + GLOBALREF HTProtocol HTLDAP; + #endif /* OLD_LIBWWW */ + + extern void HTSetLDAPHost PARAMS((CONST char *value)); + extern CONST char *HTGetLDAPHost NOPARAMS; + + extern void HTSetLDAPTmplFile PARAMS((CONST char *filename )); + extern CONST char *HTGetLDAPTmplFile NOPARAMS; + + extern void HTSetLDAPTmplList PARAMS((struct ldap_disptmpl * tmpllist)); + + extern void HTSetLDAPFriendlyFile PARAMS((CONST char *filename )); + extern CONST char *HTGetLDAPFriendlyFile NOPARAMS; + + + #define LDAP_ATTR_SEPARATOR ',' + #define LDAP_URL_PREFIX "ldap:" + #define LDAP_READ_FILTER "objectClass=*" + #define LDAP_ATTR_OBJECTCLASS "objectClass" + + #endif /* HTLDAP_H *//* + + end of LDAP module */ *** Library/Implementation/Makefile- Thu Jun 16 19:23:59 1994 --- Library/Implementation/Makefile Tue Mar 21 16:14:20 1995 *************** *** 293,299 **** $(LOB)/HTList.o $(LOB)/HTString.o $(LOB)/HTAlert.o \ $(LOB)/HTRules.o $(LOB)/HTFormat.o $(LOB)/HTInit.o $(LOB)/HTMIME.o \ $(LOB)/HTHistory.o $(LOB)/HTNews.o $(LOB)/HTGopher.o \ ! $(LOB)/HTTelnet.o $(LOB)/HTWSRC.o $(HTWAIS) CFILES = $(CMN)HTParse.c $(CMN)HTAccess.c $(CMN)HTTP.c $(CMN)HTFile.c \ $(CMN)HTFTP.c $(CMN)HTTCP.c $(CMN)SGML.c $(CMN)HTML.c \ --- 293,299 ---- $(LOB)/HTList.o $(LOB)/HTString.o $(LOB)/HTAlert.o \ $(LOB)/HTRules.o $(LOB)/HTFormat.o $(LOB)/HTInit.o $(LOB)/HTMIME.o \ $(LOB)/HTHistory.o $(LOB)/HTNews.o $(LOB)/HTGopher.o \ ! $(LOB)/HTTelnet.o $(LOB)/HTWSRC.o $(HTWAIS) $(HTLDAP) CFILES = $(CMN)HTParse.c $(CMN)HTAccess.c $(CMN)HTTP.c $(CMN)HTFile.c \ $(CMN)HTFTP.c $(CMN)HTTCP.c $(CMN)SGML.c $(CMN)HTML.c \ *************** *** 303,309 **** $(CMN)HTList.c $(CMN)HTString.c $(CMN)HTAlert.c $(CMN)HTRules.c \ $(CMN)HTFormat.c $(CMN)HTInit.c $(CMN)HTMIME.c $(CMN)HTHistory.c \ $(CMN)HTNews.c $(CMN)HTGopher.c $(CMN)HTTelnet.c \ ! $(CMN)HTWAIS.c $(CMN)HTWSRC.c HFILES = $(CMN)HTParse.h $(CMN)HTAccess.h $(CMN)HTTP.h $(CMN)HTFile.h \ $(CMN)HTFTP.h $(CMN)HTTCP.h \ --- 303,309 ---- $(CMN)HTList.c $(CMN)HTString.c $(CMN)HTAlert.c $(CMN)HTRules.c \ $(CMN)HTFormat.c $(CMN)HTInit.c $(CMN)HTMIME.c $(CMN)HTHistory.c \ $(CMN)HTNews.c $(CMN)HTGopher.c $(CMN)HTTelnet.c \ ! $(CMN)HTWAIS.c $(CMN)HTLDAP.c $(CMN)HTWSRC.c HFILES = $(CMN)HTParse.h $(CMN)HTAccess.h $(CMN)HTTP.h $(CMN)HTFile.h \ $(CMN)HTFTP.h $(CMN)HTTCP.h \ *************** *** 319,325 **** $(CMN)HTGopher.h \ $(CMN)HTUtils.h $(CMN)tcp.h $(CMN)WWW.h $(CMN)HText.h \ $(CMN)HTTelnet.h \ ! $(CMN)HTWAIS.h $(CMN)HTWSRC.h SOURCES = $(CFILES) $(HFILES) $(CMN)Version.make $(CMN)CommonMakefile \ $(WWW)/README.txt $(WWW)/Copyright.txt $(WWW)/BUILD --- 319,325 ---- $(CMN)HTGopher.h \ $(CMN)HTUtils.h $(CMN)tcp.h $(CMN)WWW.h $(CMN)HText.h \ $(CMN)HTTelnet.h \ ! $(CMN)HTWAIS.h $(CMN)HTLDAP.h $(CMN)HTWSRC.h SOURCES = $(CFILES) $(HFILES) $(CMN)Version.make $(CMN)CommonMakefile \ $(WWW)/README.txt $(WWW)/Copyright.txt $(WWW)/BUILD *************** *** 419,424 **** --- 419,427 ---- $(LOB)/HTWAIS.o : $(OE) $(CMN)HTWAIS.c $(CMN)HTUtils.h $(CMN)HTList.h $(CC) -c -o $@ $(CFLAGS2) $(WAISINC) $(CMN)HTWAIS.c + + $(LOB)/HTLDAP.o : $(OE) $(CMN)HTLDAP.c $(CMN)HTUtils.h $(CMN)HTList.h + $(CC) -c -o $@ $(CFLAGS2) $(LDAPINC) $(CMN)HTLDAP.c $(LOB)/HTWSRC.o : $(OE) $(CMN)HTWSRC.c $(CMN)HTUtils.h $(CMN)HTList.h $(CC) -c -o $@ $(CFLAGS2) $(CMN)HTWSRC.c Common subdirectories: WWW-2.17/Library/Implementation/vms and WWW+ldap/Library/Implementation/vms