summaryrefslogtreecommitdiffstats
path: root/ldap/clients/dsgw/dsgwutil.c
diff options
context:
space:
mode:
Diffstat (limited to 'ldap/clients/dsgw/dsgwutil.c')
-rw-r--r--ldap/clients/dsgw/dsgwutil.c1318
1 files changed, 1318 insertions, 0 deletions
diff --git a/ldap/clients/dsgw/dsgwutil.c b/ldap/clients/dsgw/dsgwutil.c
new file mode 100644
index 00000000..99e7f2aa
--- /dev/null
+++ b/ldap/clients/dsgw/dsgwutil.c
@@ -0,0 +1,1318 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * dsgwutil.c -- misc. utility functions -- HTTP gateway
+ *
+ * Copyright (c) 1996 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#include <limits.h> /* PATH_MAX */
+#include "dsgw.h"
+#include "dbtdsgw.h"
+#ifdef NS_DS
+#include "../lib/libsi18n/gsslapd.h"
+#else /* Admin Server */
+#include "../lib/libsi18n/gsadmserv.h"
+#endif
+
+#ifdef DSGW_DEBUG
+#include <time.h>
+#include <stdarg.h>
+#endif /* DSGW_DEBUG */
+
+static char **vpmap = NULL;
+
+extern char *Versionstr; /* from Versiongw.c */
+
+char *progname; /* set by dsgw_init() */
+dsgwconfig *gc; /* set by dsgw_init() */
+int http_hdr_sent = 0; /* non-zero if header has been sent */
+char **header_lines = NULL; /* null-terminated array of hdr lines */
+char *dsgw_html_body_colors = ""; /* reset by dsgw_init() */
+
+/*Global context variable, telling the CGI's where to look for the config file*/
+char *context = NULL; /* Gotten from the QUERY_STRING */
+char *langwich = NULL; /* The language that libsi18n
+ picks from acceptlang*/
+char *countri = NULL; /* The country that libsi18n
+ picks from acceptlang*/
+
+
+static void figure_out_langwich(void);
+
+/*
+ * dsgw_init -- initialize a dsgw CGI program:
+ * set "progname" global based on "progpath" (normally argv[0])
+ * check that REQUEST_METHOD is in "methods_handled" mask
+ * if request method is "POST", read HTML form variables from stdin
+ * handles the context variable if the CGI was called with a post.
+ * The context variable tells dsgw_read_config what config file
+ * to read.
+ *
+ * If an fatal error occurs, -1 is returned.
+ * If all goes well, returns either DSGW_METHOD_GET or DSGW_METHOD_POST
+ */
+int
+dsgw_init( int argc, char **argv, int methods_handled )
+{
+ char *m, *s;
+ int method;
+ int c, err;
+
+ (void)ADM_Init();
+
+ /* initialize the string database */
+ XP_InitStringDatabase(
+#ifdef NS_DS
+ SERVER_ROOT_PATH "/bin/slapd/property" /* Directory Server Gateway */
+#else
+ SERVER_ROOT_PATH "/admin" /* Admin Server */
+#endif
+ , DATABASE_NAME);
+ /* set default default languages for string database */
+ SetLanguage(CLIENT_LANGUAGE, "");
+ SetLanguage(ADMIN_LANGUAGE, "");
+ SetLanguage(DEFAULT_LANGUAGE, "");
+
+ if (( progname = strchr( argv[0], '/' )) == NULL ) {
+ progname = dsgw_ch_strdup( argv[0] );
+#ifdef _WIN32
+ if (( s = strrchr( progname, '.' )) != NULL
+ && strcasecmp( s, ".EXE" ) == 0 ) {
+ *s = '\0';
+ }
+#endif /* _WIN32 */
+ } else {
+ ++progname;
+ }
+
+ while (( c = getopt( argc, argv, "v" )) != EOF ) {
+ if ( c == 'v' ) {
+ printf( "%s\n", Versionstr );
+ }
+ exit( 0 );
+ }
+
+#ifdef DSGW_DEBUG
+ dsgw_log( "%s started\n", Versionstr );
+#endif
+ err = method = 0;
+
+ /*Have to get the context before we read the config file.*/
+ if (( m = getenv( "REQUEST_METHOD" )) != NULL ) {
+ if ( strcasecmp( m, "GET" ) == 0 || strcasecmp( m, "HEAD" ) == 0 ) {
+ method = DSGW_METHOD_GET;
+ } else if ( strcasecmp( m, "POST" ) == 0 ) {
+ method = DSGW_METHOD_POST;
+ if (( err = dsgw_post_begin( stdin )) == 0 ) {
+ context = dsgw_get_cgi_var( "context", DSGW_CGIVAR_OPTIONAL );
+ }
+ }
+ }
+
+ if ( method == 0 || ( methods_handled & method ) == 0 ) {
+ dsgw_error( DSGW_ERR_BADMETHOD, NULL, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+
+ /*If no context was given, try default.conf.*/
+ if (context == NULL) {
+ context = dsgw_ch_strdup("default");
+ }
+
+ /* If this is a LIte installation: dsgw is not enabled */
+/* this assumes the current dir is <server root>/dsgw/bin; under http servers
+other than admin server, we have to rely on relative paths to find the
+key file */
+
+ if ( is_directory_lite (SERVER_ROOT_PATH)) {
+ dsgw_error( DSGW_ERR_BADCONFIG, XP_GetClientStr(DBT_NotWillingToExecute_),
+ DSGW_ERROPT_EXIT, 0, NULL );
+ }
+ gc = dsgw_read_config();
+
+ gc->gc_charset = dsgw_emit_converts_to (gc->gc_charset);
+ {
+ /* eliminate elements of gc_changeHTML that don't apply to gc_charset: */
+ auto dsgwsubst **s = &(gc->gc_changeHTML);
+ auto char *charset = gc->gc_charset;
+ if ( charset == NULL ) charset = ""; /* Latin-1, implicitly */
+ while ( *s ) {
+ auto char **c = (*s)->dsgwsubst_charsets;
+ if ( c && *c ) {
+ for ( ; *c; ++c ) {
+ if ( strcasecmp( *c, charset ) == 0 ) {
+ break;
+ }
+ }
+ if ( *c == NULL ) {
+ *s = (*s)->dsgwsubst_next; /* eliminate **s */
+ /* This is quick and dirty: we just created garbage. */
+ continue;
+ }
+ }
+ s = &((*s)->dsgwsubst_next);
+ }
+ }
+
+ /* set languages for string database */
+ SetLanguage(CLIENT_LANGUAGE,gc->gc_ClientLanguage);
+ SetLanguage(ADMIN_LANGUAGE,gc->gc_AdminLanguage);
+ SetLanguage(DEFAULT_LANGUAGE,gc->gc_DefaultLanguage);
+
+ /* Figure out the language that libsi18n is using */
+ figure_out_langwich();
+
+ /* Get the port and servername */
+ if (method == DSGW_METHOD_POST) {
+ if (( s = dsgw_get_cgi_var( "ldapport", DSGW_CGIVAR_OPTIONAL )) != NULL ) {
+ gc->gc_ldapport = atoi( s );
+ free( s );
+ }
+ if (( s = dsgw_get_cgi_var( "ldapserver", DSGW_CGIVAR_OPTIONAL )) != NULL ) {
+ gc->gc_ldapserver = s;
+ }
+
+ }
+
+ if (( s = getenv( "HTTPS" )) == NULL || strcasecmp( s, "on" ) == 0 ||
+ ( s = getenv( "HTTPS_KEYSIZE" )) == NULL ) {
+ gc->gc_httpskeysize = 0;
+ } else {
+ gc->gc_httpskeysize = atoi( s );
+ }
+
+ /* set default color scheme */
+ if ( method == DSGW_METHOD_POST && ( s = dsgw_get_cgi_var( "colors",
+ DSGW_CGIVAR_OPTIONAL )) != NULL ) {
+ dsgw_html_body_colors = s;
+ } else if ( gc->gc_admserv ) { /* use same color scheme as libadmin */
+ dsgw_html_body_colors = "BGCOLOR=\"#C0C0C0\" LINK=\"#0000EE\" "
+ "VLINK=\"#551A8B\" ALINK=\"#FF0000\"";
+ } else {
+ dsgw_html_body_colors = "BGCOLOR=\"white\"";
+ }
+
+ return( method );
+}
+
+
+/*
+ * function called back by dsgw_parse_line() to evaluate IF directives.
+ * return non-zero for true, zero for false.
+ */
+int
+dsgw_simple_cond_is_true( int argc, char **argv, void *arg /* UNUSED */ )
+{
+ if ( strcasecmp( argv[0], DSGW_COND_ADMSERV ) == 0 ) {
+ return( gc->gc_admserv );
+ }
+
+ if ( strcasecmp( argv[0], DSGW_COND_LOCALDB ) == 0 ) {
+ return( gc->gc_localdbconf != NULL );
+ }
+
+ if ( strcasecmp( argv[0], DSGW_COND_POSTEDFORMVALUE ) == 0 ) {
+ /*
+ * format of IF statment is:
+ * <-- IF "PostedFormValue" "VARNAME" "VALUE" -->
+ * where VARNAME is the name of a POSTed CGI variable to look for and
+ * VALUE is an optional value to test it against. If VALUE is omitted,
+ * the test is just for the presence of a variable named VARNAME.
+ */
+ char *postedvalue;
+
+ if ( argc < 2 || ( postedvalue = dsgw_get_cgi_var( argv[1],
+ DSGW_CGIVAR_OPTIONAL )) == NULL ) {
+ return( 0 ); /* VARNAME is missing or not posted */
+ } else if ( argc < 3 ) {
+ return( 1 ); /* VALUE is missing, so return true */
+ } else {
+ return( strcasecmp( postedvalue, argv[ 2 ] ) == 0 );
+ }
+ }
+
+ return( 0 );
+}
+
+
+/*
+ * return a pointer to a malloc'd string containing the path to
+ * config. file "filename", based on the DSGW_CONFIGDIR define.
+ * If "filename" contains "..", or "//" this is treated as a fatal
+ * error. If "prefix" is not NULL, it is pre-pended to "filename"
+ */
+char *
+dsgw_file2path( char *prefix, char *filename )
+{
+ char *path, *pattern;
+ int len;
+
+ if ( strstr( filename, "//" ) != NULL ||
+ strstr( filename, ".." ) != NULL ) {
+ dsgw_error( DSGW_ERR_BADFILEPATH, filename, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+
+ if ( prefix == NULL ) {
+ prefix = "";
+ }
+
+ /* allocate buffers with enough extra room to fit "$$LANGDIR/" */
+ len = strlen( prefix ) + strlen( filename ) + 11;
+ if ( NULL != gc->gc_ClientLanguage ) {
+ len += strlen( gc->gc_ClientLanguage );
+ }
+ path = dsgw_ch_malloc( len );
+ pattern = dsgw_ch_malloc( len );
+
+ /* call GetFileForLanguage() to do its I18n magic */
+ sprintf( pattern, "%s$$LANGDIR/%s", prefix, filename );
+ if ( GetFileForLanguage( pattern, gc->gc_ClientLanguage, path ) < 0 ) {
+ sprintf( path, "%s%s", prefix, filename ); /* fallback */
+ }
+ free( pattern );
+
+ return( path );
+}
+
+
+
+/*
+ * return a pointer to a malloc'd string containing the path to
+ * config. file "filename", based on the DSGW_HTMLDIR define.
+ * If "filename" contains "..", or "//" this is treated as a fatal
+ * error. If "prefix" is not NULL, it is pre-pended to "filename"
+ */
+char *
+dsgw_file2htmlpath( char *prefix, char *filename )
+{
+ char *path, *pattern;
+ int len;
+
+ if ( strstr( filename, "//" ) != NULL ||
+ strstr( filename, ".." ) != NULL ) {
+ dsgw_error( DSGW_ERR_BADFILEPATH, filename, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+
+ if ( prefix == NULL ) {
+ prefix = "";
+ }
+
+ /* allocate buffers with enough extra room to fit "$$LANGDIR/" */
+ /*len = strlen( DSGW_HTMLDIR ) + strlen( prefix ) + strlen( filename ) + 11;*/
+ len = strlen( gc->gc_docdir ) + strlen( prefix ) + strlen( filename ) + 11;
+ if ( NULL != gc->gc_ClientLanguage ) {
+ len += strlen( gc->gc_ClientLanguage );
+ }
+
+ path = dsgw_ch_malloc( len );
+ pattern = dsgw_ch_malloc( len );
+
+ /* call GetFileForLanguage() to do its I18n magic */
+ sprintf( pattern, "%s%s$$LANGDIR/%s", gc->gc_docdir, prefix, filename );
+ if ( GetFileForLanguage( pattern, gc->gc_ClientLanguage, path ) < 0 ) {
+ /* use fallback */
+ sprintf( path, "%s/%s%s", gc->gc_docdir, prefix, filename );
+ }
+ free( pattern );
+
+ return( path );
+}
+
+
+/*
+ * malloc that checks for NULL return value and exits upon failure
+ */
+void *
+dsgw_ch_malloc( size_t n )
+{
+ void *p;
+
+ if (( p = malloc( n )) == NULL ) {
+ dsgw_error( DSGW_ERR_NOMEMORY, NULL, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+
+ return( p );
+}
+
+void *
+dsgw_ch_calloc( size_t nelem, size_t elsize )
+{
+ register void *p = calloc( nelem, elsize );
+ if ( p == NULL ) {
+ dsgw_error( DSGW_ERR_NOMEMORY, NULL, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+ return( p );
+}
+
+/*
+ * realloc that checks for NULL return value and exits upon failure
+ * we also handle p == NULL by doing a malloc
+ */
+void *
+dsgw_ch_realloc( void *p, size_t n )
+{
+ if ( p == NULL ) {
+ p = malloc( n );
+ } else {
+ p = realloc( p, n );
+ }
+
+ if ( p == NULL ) {
+ dsgw_error( DSGW_ERR_NOMEMORY, NULL, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+
+ return( p );
+}
+
+
+/*
+ * strdup that checks for NULL return value and exits upon failure
+ */
+char *
+dsgw_ch_strdup( const char *s )
+{
+ int len;
+ char *p;
+
+ len = strlen( s ) + 1;
+ p = dsgw_ch_malloc( len );
+ memcpy( p, s, len );
+ return( p );
+}
+
+
+
+/*
+ * Escape any single- or double-quotes with a '\'. Used when generating
+ * JavaScript code. Returns a malloc'd string which the caller is
+ * responsible for freeing.
+ */
+char *
+dsgw_escape_quotes( char *in )
+{
+ char *out;
+ char *p, *t;
+ int nq = 0;
+
+
+ if ( in == NULL ) {
+ return NULL;
+ }
+ /* count number of quotes */
+ for ( p = in; *p != '\0'; p++ ) {
+ if ( *p == '\'' || *p == '"' ) {
+ nq++;
+ }
+ }
+ out = dsgw_ch_malloc(( p - in ) + nq + 1 );
+ for ( p = in, t = out; *p != '\0'; p++ ) {
+ if ( *p == '\'' || *p == '"' ) {
+ *t++ = '\\';
+ }
+ *t++ = *p;
+ }
+ *t = '\0';
+ return out;
+}
+
+char *
+dsgw_get_translation( char *in )
+{
+ dsgwsubst *p;
+
+#ifdef DSGW_DEBUG
+ dsgw_log( "L10n map table:\n" );
+ for ( p = gc->gc_l10nsets; p ; p = p->dsgwsubst_next ) {
+ dsgw_log( "%s -> %s\n", p->dsgwsubst_from, p->dsgwsubst_to );
+ }
+#endif
+
+ for ( p = gc->gc_l10nsets; p ; p = p->dsgwsubst_next ) {
+ if ( !strcasecmp( in, p->dsgwsubst_from ))
+ return p->dsgwsubst_to;
+ }
+ return in;
+}
+
+static void
+dsgw_puts (const char* s)
+{
+ dsgw_fputn (stdout, s, strlen(s));
+}
+
+#define CONTENT_TYPE "Content-type"
+#define TYPE_HTML "text/html"
+#define VARY "Vary"
+#define VARYLIST "Accept-Language,Accept-Charset,User-Agent"
+
+static const char* ct_prefix = CONTENT_TYPE ": " TYPE_HTML;
+static const char* cs_prefix = ";charset=";
+static const char* vr_prefix = VARY ": ";
+
+/*
+ * Send the headers we've accumulated.
+ */
+void
+dsgw_send_header()
+{
+ int i;
+
+ if ( http_hdr_sent ) {
+ return;
+ }
+ if ( header_lines == NULL ) {
+ dsgw_puts (ct_prefix);
+ if ( gc != NULL && gc->gc_charset != NULL && *gc->gc_charset != '\0' ) {
+ dsgw_puts (cs_prefix); dsgw_puts (gc->gc_charset );
+ }
+ dsgw_puts ("\n");
+ /* send Vary tag if HTTP/1.1 or greater */
+ if ( NULL != gc && gc->gc_httpversion >= 1.1 ) {
+ dsgw_puts (vr_prefix); dsgw_puts (VARYLIST); dsgw_puts ("\n");
+ }
+ } else for ( i = 0; header_lines[ i ] != NULL; i++ ) {
+ dsgw_puts (header_lines[ i ]);
+ dsgw_puts ("\n");
+ }
+ dsgw_puts ("\n");
+ http_hdr_sent = 1;
+}
+
+
+/*
+ * Add a line to the array of header lines.
+ */
+void
+dsgw_add_header( char *line )
+{
+ int i;
+
+ if ( header_lines == NULL ) {
+ header_lines = ( char ** ) dsgw_ch_malloc( 3 * sizeof( char * ));
+ if ( gc != NULL && gc->gc_charset != NULL && *gc->gc_charset != '\0' ) {
+ header_lines[ 0 ] = dsgw_ch_malloc( strlen( ct_prefix ) +
+ strlen( cs_prefix ) + strlen( gc->gc_charset ) + 1 );
+ sprintf( header_lines[ 0 ], "%s%s%s", ct_prefix, cs_prefix,
+ gc->gc_charset );
+ } else {
+ header_lines[ 0 ] = dsgw_ch_strdup( ct_prefix );
+ }
+ /* send Vary tag if HTTP/1.1 or greater */
+ if ( gc->gc_httpversion >= 1.1 ) {
+ header_lines[ 1 ] =
+ dsgw_ch_malloc( strlen( vr_prefix ) + sizeof( VARYLIST ) );
+ /* (char *) */ /* string literal */
+ sprintf( header_lines[ 1 ], "%s%s", vr_prefix, VARYLIST );
+ header_lines[ 2 ] = NULL;
+ } else {
+ header_lines[ 1 ] = NULL;
+ }
+ }
+ for ( i = 0; header_lines[ i ] != NULL; i++ );
+ header_lines = (char **) dsgw_ch_realloc( header_lines,
+ ( i + 2 ) * sizeof( char * ));
+ header_lines[ i ] = dsgw_ch_strdup( line );
+ header_lines[ i + 1 ] = NULL;
+}
+
+
+/*
+ * Check the environment for an authentication cookie. Returns the
+ * entire auth cookie if present, or returns NULL if no such cookie
+ * exists. The returned string must be freed by the caller.
+ */
+char *
+dsgw_get_auth_cookie()
+{
+ char *p, *e, *ckhdr;
+
+ ckhdr = getenv( "HTTP_COOKIE" );
+
+ if ( ckhdr == NULL ) {
+ return NULL;
+ } else {
+ ckhdr = strdup( ckhdr );
+ }
+
+ if (( p = strstr( ckhdr, DSGW_AUTHCKNAME )) == NULL ) {
+ free( ckhdr );
+ return NULL;
+ }
+
+ if (( e = strchr( p, ';' )) != NULL ) {
+ *e = '\0';
+ }
+
+ p = strdup( p );
+ free( ckhdr );
+ return p;
+}
+
+
+
+/*
+ * Break a cookie into its random string and DN parts. The DN is returned
+ * unescaped. The caller is responsible for freeing the returned DN
+ * and random string. Returns 0 on success, -1 on error. If the
+ * cookie has the value "[unauthenticated]", then 0 is returned and
+ * dn is set to NULL;
+ */
+int
+dsgw_parse_cookie( char *cookie, char **rndstr, char **dn )
+{
+ char *p, *r;
+ int rlen;
+
+ if ( cookie == NULL ) {
+ *rndstr = *dn = NULL;
+ return -1;
+ }
+
+ /* Make sure cookie starts with "nsdsgwauth" */
+ if ( strncmp( cookie, DSGW_AUTHCKNAME, strlen( DSGW_AUTHCKNAME ))) {
+ /* Cookie didn't start with "nsdsgwauth" */
+ *rndstr = *dn = NULL;
+ return -1;
+ }
+
+ r = cookie + strlen( DSGW_AUTHCKNAME );
+ if ( *r == '=' ) {
+ r++;
+ }
+
+ /* Is cookie value "[unauthenticated]" ? */
+ if ( !strncmp( r, DSGW_UNAUTHSTR, strlen( DSGW_UNAUTHSTR ))) {
+ *rndstr = strdup( DSGW_UNAUTHSTR );
+ *dn = NULL;
+ return 0;
+ }
+
+ /* find start of DN */
+ if (( p = strrchr( cookie, ':' )) == NULL ) {
+ *rndstr = *dn = NULL;
+ return -1;
+ }
+
+ rlen = p - r + 1;
+ *(rndstr) = dsgw_ch_malloc( rlen );
+ *(rndstr)[ 0 ] = '\0';
+ strncat( *rndstr, r, rlen-1 );
+ (*rndstr)[ rlen - 1 ] = '\0';
+
+ p++;
+ *dn = strdup( p );
+ dsgw_form_unescape( *dn );
+
+ return 0;
+}
+
+/*
+ * Generate a "go home" button with a link to the main entry point for
+ * the gateway. The caller is responsible for any surrounding
+ * HTML, e.g. <FORM> and <TABLE> tags.
+ */
+void
+dsgw_emit_homebutton()
+{
+ dsgw_emitf( "<INPUT TYPE=\"button\" VALUE=\"%s\" "
+ "onClick=\"top.location.href='%s'\">", XP_GetClientStr(DBT_returnToMain_), gc->gc_urlpfxmain /*DSGW_URLPREFIX_MAIN*/ );
+}
+
+
+/*
+ * Generate a help button with a link to the tutor program for
+ * the given help topic. The caller is responsible for any surrounding
+ * HTML, e.g. <FORM> and <TABLE> tags.
+ */
+void
+dsgw_emit_helpbutton( char *topic )
+{
+ if ( topic == NULL ) {
+ return;
+ }
+
+ if ( gc->gc_admserv ) {
+ char *jscript;
+
+ if (( jscript = helpJavaScriptForTopic( topic )) == NULL ) {
+ return;
+ }
+
+ dsgw_emitf( "<INPUT TYPE=\"button\" VALUE=\"%s\" onClick=\"%s\">",
+#define LABEL_HELP "ヘルプ"
+/*LABEL_HELP*/ XP_GetClientStr(DBT_help_), jscript );
+ } else {
+ char *tutorvp;
+
+ tutorvp = dsgw_getvp( DSGW_CGINUM_TUTOR );
+
+ /*
+ * the following is based on code that was found in
+ * ldapserver/lib/libadmin/template.c inside the
+ * helpJavaScriptForTopic() function. We need our own copy because
+ * we use a different tutor CGI. Sigh.
+ */
+ dsgw_emitf( "<INPUT TYPE=\"button\" VALUE=\"%s\" onClick=\""
+ "if ( top.helpwin ) {"
+ " top.helpwin.focus();"
+ " top.helpwin.infotopic.location='%s?!%s&context=%s';"
+ "} else {"
+ " window.open('%s?%s&context=%s', 'infowin_dsgw', "
+ " 'resizable=1,width=400,height=500');"
+ "}\">\n",
+ XP_GetClientStr(DBT_help_1),tutorvp, topic, context,
+ tutorvp, topic, context );
+ }
+}
+
+
+/*
+ * Return malloc'd URL prefix that consists of:
+ * prefix + '/' + HOST:PORT + '/' (not anymore - RJP)
+ * prefix + ? + context=CONTEXT&hp=HOST:PORT&dn=
+ */
+char *
+dsgw_build_urlprefix()
+{
+ char *prefix = dsgw_getvp( DSGW_CGINUM_DOSEARCH );
+ char *p, *urlprefix;
+
+ p = ( gc->gc_ldapserver == NULL ? "" : gc->gc_ldapserver );
+ urlprefix = dsgw_ch_malloc( 16 /* room for "?:port#&dn=" + zero-term. */
+ + strlen( prefix ) + strlen( p ) +strlen(context) + 9);
+ sprintf( urlprefix, "%s?context=%s&hp=%s", prefix, context, p );
+ if ( gc->gc_ldapport != 0 && gc->gc_ldapport != LDAP_PORT ) {
+ sprintf( urlprefix + strlen( urlprefix ), ":%d", gc->gc_ldapport );
+ }
+ strcat( urlprefix,"&dn=" );
+ return( urlprefix );
+}
+
+
+void
+dsgw_addtemplate( dsgwtmpl **tlpp, char *template, int count, char **ocvals )
+{
+ int i;
+ dsgwtmpl *prevtp, *tp;
+
+ tp = (dsgwtmpl *)dsgw_ch_malloc( sizeof( dsgwtmpl ));
+ memset( tp, 0, sizeof( dsgwtmpl ));
+ tp->dstmpl_name = dsgw_ch_strdup( template );
+
+ /* each argument is one objectClass */
+ tp->dstmpl_ocvals = dsgw_ch_malloc(( count + 1 ) * sizeof( char * ));
+ for ( i = 0; i < count; ++i ) {
+ tp->dstmpl_ocvals[ i ] = dsgw_ch_strdup( ocvals[ i ] );
+ }
+ tp->dstmpl_ocvals[ count ] = NULL;
+
+ if ( *tlpp == NULL ) {
+ *tlpp = tp;
+ } else {
+ for ( prevtp = *tlpp; prevtp->dstmpl_next != NULL;
+ prevtp = prevtp->dstmpl_next ) {
+ ;
+ }
+ prevtp->dstmpl_next = tp;
+ }
+}
+
+
+dsgwtmpl *
+dsgw_oc2template( char **ocvals )
+{
+ int i, j, needcnt, matchcnt;
+ dsgwtmpl *tp;
+
+ for ( tp = gc->gc_templates; tp != NULL; tp = tp->dstmpl_next ) {
+ needcnt = matchcnt = 0;
+ for ( i = 0; tp->dstmpl_ocvals[ i ] != NULL; ++i ) {
+ for ( j = 0; ocvals[ j ] != NULL; ++j ) {
+ if ( strcasecmp( ocvals[ j ], tp->dstmpl_ocvals[ i ] ) == 0 ) {
+ ++matchcnt;
+ }
+ }
+ ++needcnt;
+ }
+
+ if ( matchcnt == needcnt ) {
+ return( tp );
+ }
+ }
+
+ return( NULL );
+}
+
+
+
+void
+dsgw_init_searchprefs( struct ldap_searchobj **solistp )
+{
+ char *path;
+
+ path = dsgw_file2path( gc->gc_configdir, DSGW_SEARCHPREFSFILE );
+ if ( ldap_init_searchprefs( path, solistp ) != 0 ) {
+ dsgw_error( DSGW_ERR_BADCONFIG, path, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+ free( path );
+}
+
+
+void
+dsgw_remove_leading_and_trailing_spaces( char **sp )
+{
+ auto char *s, *p;
+
+ if ( sp == NULL || *sp == NULL ) {
+ return;
+ }
+
+ s = *sp;
+
+ /* skip past any leading spaces */
+ while ( ldap_utf8isspace( s )) {
+ LDAP_UTF8INC (s);
+ }
+
+ /* truncate to remove any trailing spaces */
+ if ( *s != '\0' ) {
+ p = s + strlen( s );
+ LDAP_UTF8DEC (p);
+ while (ldap_utf8isspace( p )) {
+ LDAP_UTF8DEC (p);
+ }
+ *LDAP_UTF8INC(p) = '\0';
+ }
+ *sp = s;
+}
+
+
+/*
+ * Return the virtual path prefix for the CGI program specified by
+ * cginum.
+ */
+char *
+dsgw_getvp( int cginum )
+{
+ char *cginame;
+ char *surl;
+ /*char *extpath;*/
+ int i;
+
+ if ( cginum < 1 || cginum > DSGW_MODE_NUMMODES ) {
+ return "";
+ }
+ if ( vpmap == NULL ) {
+ /* note: slot zero of vpmap isn't used */
+ vpmap = dsgw_ch_malloc(( DSGW_MODE_NUMMODES + 1 ) * sizeof( char * ));
+ for ( i = 0; i <= DSGW_MODE_NUMMODES; i++ ) {
+ vpmap[ i ] = NULL;
+ }
+ }
+
+ if ( vpmap[ cginum ] == NULL ) {
+ switch ( cginum ) {
+ case DSGW_CGINUM_DOSEARCH:
+ cginame = DSGW_CGINAME_DOSEARCH;
+ break;
+ case DSGW_CGINUM_BROWSE:
+ cginame = DSGW_CGINAME_BROWSE;
+ break;
+ case DSGW_CGINUM_SEARCH:
+ cginame = DSGW_CGINAME_SEARCH;
+ break;
+ case DSGW_CGINUM_CSEARCH:
+ cginame = DSGW_CGINAME_CSEARCH;
+ break;
+ case DSGW_CGINUM_AUTH:
+ cginame = DSGW_CGINAME_AUTH;
+ break;
+ case DSGW_CGINUM_EDIT:
+ cginame = DSGW_CGINAME_EDIT;
+ break;
+ case DSGW_CGINUM_DOMODIFY:
+ cginame = DSGW_CGINAME_DOMODIFY;
+ break;
+ case DSGW_CGINUM_DNEDIT:
+ cginame = DSGW_CGINAME_DNEDIT;
+ break;
+ case DSGW_CGINUM_TUTOR:
+ cginame = DSGW_CGINAME_TUTOR;
+ break;
+ case DSGW_CGINUM_LANG:
+ cginame = DSGW_CGINAME_LANG;
+ break;
+ default:
+ return "";
+ }
+
+ if (( surl = getenv( "SERVER_URL" )) == NULL ) {
+ surl = "";
+ }
+
+ /*if ( gc->gc_admserv ) {
+ *
+ * include "/admin-serv/" or "/user-environment/" if appropriate
+ *
+ * if ( gc->gc_enduser ) {
+ * extpath = DSGW_USER_ADM_BINDIR;
+ * } else {
+ * extpath = DSGW_ADMSERV_BINDIR;
+ * }
+ * } else {
+ * extpath = "";
+ * }
+ */
+ vpmap[ cginum ] = dsgw_ch_malloc( strlen( gc->gc_urlpfxcgi ) + strlen( surl )
+ /*+ strlen( extpath ) */
+ + strlen( cginame ) + 2 );
+
+ sprintf( vpmap[ cginum ], "%s%s%s", surl,
+ /*extpath, */
+ gc->gc_urlpfxcgi, cginame );
+
+ /*sprintf( vpmap[ cginum ], "%s%s%s", extpath, gc->gc_urlpfxcgi, cginame );*/
+ }
+ return( vpmap[ cginum ]);
+}
+
+
+#ifdef DSGW_DEBUG
+#include <stdio.h> /* FILE */
+
+/* Returns a directory path used for tmp log files. */
+char *
+dsgw_get_tmp_log_dir()
+{
+ static char tmp_log[MAXPATHLEN];
+ char *install_dir = NULL;
+
+#if defined( XP_WIN32 )
+ int ilen;
+ char *pch;
+ char tmp_dir[_MAX_PATH];
+#endif
+ install_dir = getenv("NETSITE_ROOT");
+ if (install_dir != NULL) {
+ sprintf(tmp_log, "%s/tmp/dsgw", install_dir);
+#if defined( XP_WIN32 )
+ for(ilen=0; ilen < strlen(tmp_log); ilen++)
+ {
+ if(tmp_log[ilen]=='/')
+ tmp_log[ilen]='\\';
+ }
+#endif /* XP_WIN32 */
+ } else {
+#if defined( XP_WIN32 )
+ ilen = strlen(tmp_dir);
+ GetTempPath( ilen+1, tmp_dir );
+ /* Remove trailing slash. */
+ pch = tmp_dir[ilen-1];
+ if( pch == '\\' || pch == '/' )
+ tmp_dir[ilen-1] = '\0';
+ sprintf(tmp_log, "%s\\DSGW", tmp_dir);
+#else
+ sprintf(tmp_log, "/tmp/dsgw");
+#endif
+ }
+ return tmp_log;
+}
+
+static FILE* log_out_fp = NULL;
+
+void
+dsgw_log_out (const char* s, size_t n)
+{
+ if ( log_out_fp == NULL ) {
+ char fname[ 256 ];
+ char* format =
+#if defined( XP_WIN32 )
+ "%s\\log%.50s.out";
+#else
+ "%s/%.50s.out";
+#endif
+ PR_snprintf( fname, 256, format, dsgw_get_tmp_log_dir(), progname );
+ log_out_fp = fopen( fname, "w" );
+ }
+ if (log_out_fp != NULL) {
+ fwrite (s, sizeof(char), n, log_out_fp);
+ fflush (log_out_fp);
+ }
+}
+
+
+/*
+ * logging function -- called like printf(); syslog-like output is written
+ * to a file called /tmp/progname where progname is derived from argv[0]
+ */
+static FILE* logfp = NULL;
+void
+dsgw_log( char *fmt, ... )
+{
+ time_t t;
+ char timebuf[ 20 ];
+ va_list ap;
+
+ t = time( NULL );
+
+ if ( logfp == NULL ) {
+ char fname[ 256 ];
+ char* format =
+#if defined( XP_WIN32 )
+ "%s\\log%.50s";
+#else
+ "%s/%.50s";
+#endif
+ PR_snprintf( fname, 256, format, dsgw_get_tmp_log_dir(), progname );
+ if (( logfp = fopen( fname, "a+" )) == NULL ) {
+ return;
+ }
+ }
+
+ memcpy( timebuf, ctime( &t ), 19 );
+ timebuf[ 19 ] = '\0';
+ fprintf( logfp, "%s %s: ", timebuf, progname );
+
+ va_start( ap, fmt );
+ (void)vfprintf( logfp, fmt, ap );
+ va_end( ap );
+ fflush( logfp );
+}
+
+
+/*
+ * log the contents of a NULL-terminated array of character strings
+ */
+void
+dsgw_logstringarray( char *arrayname, char **strs )
+{
+ int i;
+
+ if ( strs == NULL || strs[ 0 ] == NULL ) {
+ dsgw_log( "Array %s: empty\n", arrayname );
+ } else {
+ dsgw_log( "Array %s:\n", arrayname );
+
+ for ( i = 0; strs[ i ] != NULL; ++i ) {
+ dsgw_log( "\t%2d: \"%s\"\n", i, strs[ i ] );
+ }
+ }
+}
+#endif /* DSGW_DEBUG */
+
+void
+dsgw_head_begin()
+{
+ dsgw_emits ("<HEAD>");
+ if ( gc != NULL && gc->gc_charset != NULL && *gc->gc_charset != '\0' ) {
+ dsgw_emitf ("<META HTTP-EQUIV=\"%s\" CONTENT=\"%s%s%s\">",
+ CONTENT_TYPE, TYPE_HTML, cs_prefix, gc->gc_charset);
+ }
+}
+
+void
+dsgw_quote_emptyFrame()
+{
+ dsgw_quotation_begin( QUOTATION_JAVASCRIPT_MULTILINE );
+ dsgw_emits( "<HTML>" );
+ dsgw_emitf( "<BODY %s></BODY></HTML>", dsgw_html_body_colors );
+ dsgw_quotation_end();
+}
+
+/* This function contains code to alert the user that their password has
+ already expired. It gives them an opportunity to change it. */
+void
+dsgw_password_expired_alert( char *dn )
+{
+ char *ufn, *encodeddn = dsgw_strdup_escaped( dn );
+
+ dsgw_send_header();
+ dsgw_emits( "<HTML>" );
+ dsgw_head_begin();
+
+ dsgw_emits( "\n"
+ "<TITLE>Password Expired</TITLE>\n"
+ "<SCRIPT LANGUAGE=\"JavaScript\">\n"
+ "<!-- Hide from non-JavaScript browsers\n" );
+
+ if ( encodeddn != NULL && strlen( encodeddn ) > 0 ) {
+ dsgw_emitf( "var editdesturl = '%s?passwd&dn=%s&context=%s';\n",
+ dsgw_getvp( DSGW_CGINUM_EDIT ), encodeddn, context );
+ } else {
+ dsgw_emitf( "var editdesturl=null;\n" );
+ }
+
+ dsgw_emits( "function EditPassword()\n"
+ "{\n"
+ " if ( editdesturl != null ) {\n"
+ " top.location.href = editdesturl;\n"
+ " } else {\n"
+ " top.close();\n"
+ " }\n"
+ "}\n"
+ "var contButtons = ");
+
+ dsgw_quotation_begin (QUOTATION_JAVASCRIPT_MULTILINE);
+ dsgw_form_begin ("bForm", NULL);
+ dsgw_emits(
+ "\n<TABLE BORDER=2 WIDTH=100%>\n"
+ "<TD ALIGN=CENTER WIDTH=50%>\n"
+ "<INPUT TYPE=BUTTON NAME=\"contButton\""
+ "VALUE=\"");
+ dsgw_emits( XP_GetClientStr( DBT_EditPassword_ ));
+ dsgw_emits(
+ "\" onClick=\"EditPassword();\">\n"
+ "<TD ALIGN=CENTER WIDTH=50%%>" );
+ dsgw_emit_helpbutton( "AUTHSUCCESS" );
+ dsgw_emits(
+ "\n</TABLE></FORM>");
+ dsgw_quotation_end(); dsgw_emits(";\n");
+
+ dsgw_emits(
+ "var noContButtons = ");
+ dsgw_quotation_begin (QUOTATION_JAVASCRIPT_MULTILINE);
+ dsgw_emits( XP_GetClientStr( DBT_ToContinue_ ));
+ dsgw_form_begin( "bForm", NULL );
+ dsgw_emits(
+ "\n<TABLE BORDER=2 WIDTH=100%>"
+ "\n<TD ALIGN=CENTER WIDTH=50%>" );
+ dsgw_emit_homebutton();
+ dsgw_emits( "\n<TD ALIGN=CENTER WIDTH=50%%>" );
+ dsgw_emit_helpbutton( "AUTHPROBLEM" );
+ dsgw_emits(
+ "\n</TABLE></FORM>\n");
+ dsgw_quotation_end(); dsgw_emits(";\n");
+
+#ifdef NOTFORNOW
+ /* ldap_dn2ufn currently gobbles up 'dc' so don't use it for */
+ /* now */
+ ufn = ldap_dn2ufn( dn );
+#endif
+
+ dsgw_emitf(
+ "// End hiding -->\n"
+ "</SCRIPT>\n"
+ "</HEAD>\n<BODY %s>\n"
+ "<CENTER>\n",
+ dsgw_html_body_colors );
+ dsgw_emitf( XP_GetClientStr( DBT_PasswordExpiredFor_ ), dn );
+ dsgw_emits( "</CENTER>\n" );
+ dsgw_emits( XP_GetClientStr( DBT_YourPasswordHasExpired_ ));
+ dsgw_emits( XP_GetClientStr( DBT_YouMustChangeYourPasswd_ ));
+ dsgw_emits( "<P>\n"
+ "<TR>\n"
+ "<SCRIPT LANGUAGE=\"JavaScript\">\n"
+ "<!-- Hide from non-JavaScript browsers\n"
+ "if ( editdesturl != null ) {\n"
+ " document.write( contButtons );\n"
+ "} else {\n"
+ " document.write( noContButtons );\n"
+ "}\n"
+ "// End hiding -->\n"
+ "</SCRIPT>\n"
+ "</BODY>\n</HTML>\n" );
+}
+
+/* Pulled from ldapserver/ldap/servers/slapd/time.c */
+
+time_t
+dsgw_current_time()
+{
+ return( time( (time_t *)0 ));
+}
+
+#define mktime_r(from) mktime (from)
+
+time_t
+dsgw_time_plus_sec (time_t l, long r)
+ /* return the point in time 'r' seconds after 'l'. */
+{
+ /* On many (but not all) platforms this is simply l + r;
+ perhaps it would be better to implement it that way. */
+ struct tm t;
+ if (r == 0) return l; /* performance optimization */
+#ifdef _WIN32
+ {
+ struct tm *pt = localtime( &l );
+ memcpy(&t, pt, sizeof(struct tm) );
+ }
+#else
+ localtime_r (&l, &t);
+#endif
+ /* Conceptually, we want to do: t.tm_sec += r;
+ but to avoid overflowing fields: */
+ r += t.tm_sec; t.tm_sec = r % 60; r /= 60;
+ r += t.tm_min; t.tm_min = r % 60; r /= 60;
+ r += t.tm_hour; t.tm_hour = r % 24; r /= 24;
+ t.tm_mday += r; /* may be > 31; mktime_r() must handle this */
+
+ /* These constants are chosen to work when the maximum
+ field values are 127 (the worst case) or more.
+ Perhaps this is excessively conservative. */
+ return mktime_r (&t);
+}
+
+/*
+ * Function: figure_out_langwich
+ *
+ * Returns: nothing
+ *
+ * Description: figures out the language/locale that libsi18n will
+ * use. This is so that non libsi18n functions can display
+ * stuff in the same language.
+ *
+ * Author: RJP
+ *
+ */
+static void
+figure_out_langwich(void)
+{
+ char *path = NULL;
+ char *iter = NULL;
+ char *p = NULL;
+ char *before = NULL;
+
+ /* Get a path to the html directory */
+ path = dsgw_file2path( gc->gc_configdir, "dsgwfilter.conf");
+
+ before = path;
+
+ /* Find the lang subdirectory part */
+ for ( p = ldap_utf8strtok_r( path, DSGW_PATHSEP_STR, &iter );
+ p != NULL && *p != '\0' && strcmp(p, "dsgwfilter.conf") != 0;
+ p = ldap_utf8strtok_r( NULL, DSGW_PATHSEP_STR, &iter )){
+ before = p;
+ }
+
+ /* If there is one, copy it. */
+ if (before != NULL && *before != '\0') {
+ langwich = dsgw_ch_strdup(before);
+ }
+
+ iter = NULL;
+
+ /* split off any country specification */
+ ldap_utf8strtok_r( langwich, "-", &iter );
+ countri = iter;
+
+ free (path);
+
+}
+
+/*
+ * Accept-Language = "Accept-Language" ":"
+ * 1#( language-range [ ";" "q" "=" qvalue ] )
+ * language-range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )
+ *
+ * NLS_AccLangList() assumes that "Accept-Language:" has already
+ * been stripped off. It takes as input
+ *
+ * 1#( ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" ) [ ";" "q" "=" qvalue ] )
+ *
+ * and returns a list of languages, ordered by qvalues, in
+ * the array NLS_ACCEPT_LANGUAGE_LIST.
+ *
+ * If there are to many languages (>NLS_MAX_ACCEPT_LANGUAGE) the excess
+ * is ignored. If the language-range is too long (>NLS_MAX_ACCEPT_LENGTH),
+ * the language-range is ignored. In these cases, NLS_AccLangList()
+ * will quietly return, perhaps with numLang = 0. numLang is
+ * returned by the function.
+ */
+
+
+size_t
+AcceptLangList(const char* AcceptLanguage,
+ ACCEPT_LANGUAGE_LIST AcceptLanguageList)
+{
+ char* input;
+ char* cPtr;
+ char* cPtr1;
+ char* cPtr2;
+ int i;
+ int j;
+ int countLang = 0;
+
+ input = dsgw_ch_strdup(AcceptLanguage);
+ if (input == (char*)NULL){
+ return 0;
+ }
+
+ cPtr1 = input-1;
+ cPtr2 = input;
+
+ /* put in standard form */
+ while (*(++cPtr1)) {
+ if (isalpha(*cPtr1)) *cPtr2++ = tolower(*cPtr1); /* force lower case */
+ else if (isspace(*cPtr1)); /* ignore any space */
+ else if (*cPtr1=='-') *cPtr2++ = '_'; /* "-" -> "_" */
+ else if (*cPtr1=='*'); /* ignore "*" */
+ else *cPtr2++ = *cPtr1; /* else unchanged */
+ }
+ *cPtr2 = '\0';
+
+ countLang = 0;
+
+ if (strchr(input,';')) {
+ /* deal with the quality values */
+
+ float qvalue[MAX_ACCEPT_LANGUAGE];
+ float qSwap;
+ float bias = 0.0f;
+ char* ptrLanguage[MAX_ACCEPT_LANGUAGE];
+ char* ptrSwap;
+
+ cPtr = strtok(input,",");
+ while (cPtr) {
+ qvalue[countLang] = 1.0f;
+ if (cPtr1 = strchr(cPtr,';')) {
+ sscanf(cPtr1,";q=%f",&qvalue[countLang]);
+ *cPtr1 = '\0';
+ }
+ if (strlen(cPtr)<MAX_ACCEPT_LENGTH) { /* ignore if too long */
+ qvalue[countLang] -= (bias += 0.0001f); /* to insure original order */
+ ptrLanguage[countLang++] = cPtr;
+ if (countLang>=MAX_ACCEPT_LANGUAGE) break; /* quit if too many */
+ }
+ cPtr = strtok(NULL,",");
+ }
+
+ /* sort according to decending qvalue */
+ /* not a very good algorithm, but count is not likely large */
+ for ( i=0 ; i<countLang-1 ; i++ ) {
+ for ( j=i+1 ; j<countLang ; j++ ) {
+ if (qvalue[i]<qvalue[j]) {
+ qSwap = qvalue[i];
+ qvalue[i] = qvalue[j];
+ qvalue[j] = qSwap;
+ ptrSwap = ptrLanguage[i];
+ ptrLanguage[i] = ptrLanguage[j];
+ ptrLanguage[j] = ptrSwap;
+ }
+ }
+ }
+ for ( i=0 ; i<countLang ; i++ ) {
+ strcpy(AcceptLanguageList[i],ptrLanguage[i]);
+ }
+
+ } else {
+ /* simple case: no quality values */
+
+ cPtr = strtok(input,",");
+ while (cPtr) {
+ if (strlen(cPtr)<MAX_ACCEPT_LENGTH) { /* ignore if too long */
+ strcpy(AcceptLanguageList[countLang++],cPtr);
+ if (countLang>=MAX_ACCEPT_LANGUAGE) break; /* quit if too many */
+ }
+ cPtr = strtok(NULL,",");
+ }
+ }
+
+ free(input);
+
+ return countLang;
+}