summaryrefslogtreecommitdiffstats
path: root/ldap/clients/dsgw/cgiutil.c
diff options
context:
space:
mode:
Diffstat (limited to 'ldap/clients/dsgw/cgiutil.c')
-rw-r--r--ldap/clients/dsgw/cgiutil.c512
1 files changed, 512 insertions, 0 deletions
diff --git a/ldap/clients/dsgw/cgiutil.c b/ldap/clients/dsgw/cgiutil.c
new file mode 100644
index 00000000..be2ba3db
--- /dev/null
+++ b/ldap/clients/dsgw/cgiutil.c
@@ -0,0 +1,512 @@
+/**
+ * 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.
+ */
+/*
+ * cgiutil.c -- CGI-related utility functions -- HTTP gateway
+ *
+ * Note: tihs code is derived from the extras/changepw.c code that ships
+ * with the FastTrack 2.0 server
+ *
+ * Copyright (c) 1996 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#include "dsgw.h"
+#include "dbtdsgw.h"
+
+#include <prprf.h>
+#include <unicode/ucnv.h>
+#include <unicode/ustring.h>
+
+/* globals */
+static char **formvars = NULL;
+
+/* functions */
+static char **dsgw_string_to_vec(char *in);
+
+static void
+dsgw_vec_convert (char** vec)
+ /* Convert input from the charset named in it (if any) to UTF_8.
+ Either return s, or free(s) and return the converted string.
+ */
+{
+ static const char* prefix = "charset=";
+ const size_t prefix_len = strlen (prefix);
+ char** v;
+
+ if (vec) for (v = vec; *v; ++v) {
+ if (!strncmp (*v, prefix, prefix_len)) {
+ char* charset = *v + prefix_len;
+ UConverter* converter = NULL;
+ UErrorCode err = U_ZERO_ERROR;
+ if ( ! is_UTF_8 (charset) && (converter = ucnv_open(charset, &err)) &&
+ (err == U_ZERO_ERROR) ) {
+ for (v = vec; *v; ++v) {
+ char* s = strchr (*v, '=');
+ if (s != NULL) {
+ char *t = NULL;
+ const size_t nlen = (++s) - *v;
+ const size_t slen = strlen (s);
+ size_t tlen = 0;
+ size_t reallen = 0;
+ int result;
+
+ if (ucnv_getMaxCharSize(converter) == 1) {
+ tlen = slen + 2; /* best case - ascii or other 7/8 bit */
+ } else { /* assume worst case utf8 - each char is 3 bytes */
+ tlen = (slen * 3) + 2;
+ }
+ do {
+ char *tptr;
+ size_t realSlen = 0;
+ err = U_ZERO_ERROR;
+
+ if (t) {
+ t = dsgw_ch_realloc(t, nlen + tlen);
+ } else {
+ t = dsgw_ch_malloc(nlen + tlen);
+ }
+ tptr = t + nlen;
+
+ /* copy the converted characters into t after the '=', and
+ leave room for the trailing 0 */
+ result = dsgw_convert(DSGW_TO_UTF8, converter,
+ &tptr, (tlen - nlen - 1), &reallen,
+ s, slen, &realSlen, &err);
+ tlen += slen; /* if failed, make more room */
+ } while (result == 0);
+ if ((result == 1) && (err == U_ZERO_ERROR)) {
+ memcpy (t, *v, nlen);
+ t[nlen+reallen] = '\0';
+ free (*v);
+ *v = t;
+ } else {
+ free (t);
+ }
+ ucnv_reset (converter); /* back to initial shift state */
+ }
+ }
+ ucnv_close (converter);
+ }
+ if (U_FAILURE(err)) {
+ dsgw_error(DSGW_ERR_CHARSET_NOT_SUPPORTED, charset, 0, 0, 0);
+ }
+ break;
+ }
+ }
+}
+
+/* Read in the variables from stdin, unescape them, and then put them in
+ * the static vector.
+ *
+ * Return 0 if all goes well; DSGW error code otherwise
+ */
+int
+dsgw_post_begin(FILE *in)
+{
+ char *ct, *vars = NULL, *tmp = NULL;
+ int cl;
+
+ if (( ct = getenv( "CONTENT_TYPE" )) == NULL ||
+ strcasecmp( ct, "application/x-www-form-urlencoded" ) != 0 ||
+ ( tmp = getenv( "CONTENT_LENGTH" )) == NULL ) {
+ return( DSGW_ERR_BADFORMDATA );
+ }
+
+ cl = atoi(tmp);
+
+ vars = (char *)dsgw_ch_malloc(cl+1);
+
+ if ( fread(vars, 1, cl, in) != cl ) {
+ return( DSGW_ERR_BADFORMDATA );
+ }
+
+ vars[cl] = '\0';
+#ifdef DSGW_DEBUG
+ dsgw_log ("vars=\"%s\"\n", vars);
+#endif
+ formvars = dsgw_string_to_vec (vars);
+ free( vars );
+ dsgw_vec_convert (formvars);
+
+#ifdef DSGW_DEBUG
+ dsgw_logstringarray( "formvars", formvars );
+if (0) {
+ char** var = formvars;
+ if (var) {
+ printf ("Content-type: text/html;charset=UTF-8\n\n<HTML><BODY>\n");
+ for (; *var; ++var) {
+ printf ("%s<br>\n", *var);
+ }
+ printf ("</BODY></HTML>\n");
+ exit (1);
+ }
+}
+#endif
+
+ return( 0 );
+}
+
+
+/* Unescape the %xx variables as they're sent in. */
+void
+dsgw_form_unescape(char *str)
+{
+ register int x = 0, y = 0;
+ int l = strlen(str);
+ char digit;
+
+ while(x < l) {
+ if((str[x] == '%') && (x < (l - 2))) {
+ ++x;
+ digit = (str[x] >= 'A' ?
+ ((str[x] & 0xdf) - 'A')+10 : (str[x] - '0'));
+ digit *= 16;
+
+ ++x;
+ digit += (str[x] >= 'A' ?
+ ((str[x] & 0xdf) - 'A')+10 : (str[x] - '0'));
+
+ str[y] = digit;
+ }
+ else if(str[x] == '+') {
+ str[y] = ' ';
+ } else {
+ str[y] = str[x];
+ }
+ x++;
+ y++;
+ }
+ str[y] = '\0';
+}
+
+
+/* Return the value of a POSTed variable, or NULL if none was sent. */
+char *
+dsgw_get_cgi_var(char *varname, int required)
+{
+ register int x = 0;
+ int len = strlen(varname);
+ char *ans = NULL;
+
+ while(formvars != NULL && formvars[x]) {
+ /* We want to get rid of the =, so len, len+1 */
+ if((!strncmp(formvars[x], varname, len)) &&
+ (*(formvars[x]+len) == '=')) {
+ ans = dsgw_ch_strdup(formvars[x] + len + 1);
+ if(!strcmp(ans, "")) {
+ free(ans);
+ ans = NULL;
+ }
+ break;
+ } else
+ x++;
+ }
+
+ if ( required == DSGW_CGIVAR_REQUIRED && ans == NULL ) {
+ char errbuf[ 256 ];
+ PR_snprintf( errbuf, 256,
+ XP_GetClientStr(DBT_missingFormDataElement100s_), varname );
+ dsgw_error( DSGW_ERR_BADFORMDATA, errbuf, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+
+ return ans;
+}
+
+
+/*
+ * Return integer equivalent of POSTed value. If no variable POSTed,
+ * return defval.
+ */
+int
+dsgw_get_int_var( char *varname, int required, int defval )
+{
+ char *val;
+ int rc;
+
+ if (( val = dsgw_get_cgi_var( varname, required )) == NULL ) {
+ rc = defval;
+ } else {
+ rc = atoi( val );
+ free( val );
+ }
+
+ return( rc );
+}
+
+
+/*
+ * Return non-zero if POSTed variable is "true" or "yes". If !required
+ * and no variable POSTed, return defval.
+ */
+int
+dsgw_get_boolean_var( char *varname, int required, int defval )
+{
+ char *val;
+ int rc;
+
+ if (( val = dsgw_get_cgi_var( varname, required )) == NULL ) {
+ rc = defval;
+ } else {
+ rc = ( strcasecmp( val, "true" ) == 0 ||
+ strcasecmp( val, "yes" ) == 0 );
+ free( val );
+ }
+
+ return( rc );
+}
+
+
+/*
+ * If a CGI variable named "varname_escaped" was POST'd, unescape it and
+ * return its value.
+ * Otherwise if "varname" is not NULL and a CGI variable called "varname"
+ * was POST'd, return its value.
+ * Otherwise return NULL.
+ */
+char *
+dsgw_get_escaped_cgi_var( char *varname_escaped, char *varname, int required )
+{
+ char *val;
+
+ if (( val = dsgw_get_cgi_var( varname_escaped,
+ ( varname == NULL ) ? required: DSGW_CGIVAR_OPTIONAL )) != NULL ) {
+ dsgw_form_unescape( val );
+ } else if ( varname != NULL ) {
+ val = dsgw_get_cgi_var( varname, required );
+ }
+
+ return( val );
+}
+
+
+/* Convert the input from stdin to a usable variable vector. */
+static char **
+dsgw_string_to_vec(char *in)
+{
+ char **ans;
+ int vars = 0;
+ register int x = 0;
+ char *tmp;
+
+ while(in[x])
+ if(in[x++]=='=')
+ vars++;
+
+ ans = (char **) dsgw_ch_malloc((sizeof(char *)) * (vars+1));
+
+ x=0;
+ /* strtok() is not MT safe, but it is okay to call here because it is used in monothreaded env */
+ tmp = strtok(in, "&");
+ ans[x]=dsgw_ch_strdup(tmp);
+ dsgw_form_unescape(ans[x++]);
+
+ while((tmp = strtok(NULL, "&"))) {
+ if ( strchr( tmp, '=' ) == NULL ) {
+ break;
+ }
+ ans[x] = dsgw_ch_strdup(tmp);
+ dsgw_form_unescape(ans[x++]);
+ }
+ ans[x] = NULL;
+
+ return(ans);
+}
+
+
+/*
+ * Step through all the CGI POSTed variables. A malloc'd copy of the variable
+ * name is returned and *valuep is set to point to the value (not malloc'd).
+ * If there are no more variables, NULL is returned.
+ *
+ * The first time this is called, *indexp should be zero. On subsequent
+ * calls, pass the same indexp as on the first call.
+ */
+char *
+dsgw_next_cgi_var( int *indexp, char **valuep )
+{
+ char *name;
+ int namelen;
+
+ if ( formvars == NULL || formvars[ *indexp ] == NULL ) {
+ return( NULL );
+ }
+
+ if (( *valuep = strchr( formvars[ *indexp ], '=' )) == NULL ) {
+ namelen = strlen( formvars[ *indexp ] );
+ } else {
+ namelen = *valuep - formvars[ *indexp ];
+ ++(*valuep);
+ }
+ name = dsgw_ch_malloc( namelen + 1 );
+ memcpy( name, formvars[ *indexp ], namelen );
+ name[ namelen ] = '\0';
+
+ *indexp += 1;
+
+ return( name );
+}
+
+/*
+ * converts a buffer of characters to/from UTF8 from/to a native charset
+ * the given converter will handle the native charset
+ * returns 0 if not all of source was converted, 1 if all of source
+ * was converted, -1 upon error
+ * all of source will be converted if there is enough room in dest to contain
+ * the entire conversion, or if dest is null and we are malloc'ing space for dest
+ */
+int
+dsgw_convert(
+ int direction, /* false for native->utf8, true for utf8->native */
+ UConverter *nativeConv, /* convert from/to native charset */
+ char **dest, /* *dest is the destination buffer - if *dest == NULL, it will be malloced */
+ size_t destSize, /* size of dest buffer (ignored if *dest == NULL) */
+ size_t *nDest, /* number of chars written to dest */
+ const char *source, /* source buffer to convert - either in native encoding (from) or utf8 (to) */
+ size_t sourceSize, /* size of source buffer - if 0, assume source is NULL terminated */
+ size_t *nSource, /* number of chars read from source buffer */
+ UErrorCode *pErrorCode /* will be reset each time through */
+)
+{
+#define CHUNK_SIZE 1024
+ UChar pivotBuffer[CHUNK_SIZE];
+ UChar *pivot, *pivot2;
+ static UConverter *utf8Converter = NULL;
+ UConverter *inConverter, *outConverter;
+ char *myDest;
+ const char *mySource;
+ const char *destLimit;
+ const char *sourceLimit;
+ int32_t destCapacity=0;
+ int destAlloc = 0; /* set to true if we allocated *dest */
+
+ *pErrorCode = U_ZERO_ERROR;
+
+ if(sourceSize<0 || source==NULL || nDest==NULL || nSource==NULL)
+ {
+ *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+ return -1;
+ }
+
+ *nSource = 0;
+ *nDest = 0;
+
+ /* if source size is 0, assume source is null terminated and use strlen */
+ if(sourceSize==0) {
+ sourceSize = strlen(source);
+ }
+
+ /* create the converters */
+ if (!utf8Converter) {
+ utf8Converter = ucnv_open(UNICODE_ENCODING_UTF_8, pErrorCode);
+ if(U_FAILURE(*pErrorCode)) {
+ return -1;
+ }
+ }
+ /* reset utf8Converter if done or error */
+
+ if (direction) {
+ inConverter = utf8Converter; /* source is utf8 */
+ outConverter = nativeConv; /* dest is native charset */
+ } else {
+ inConverter = nativeConv; /* source is native charset */
+ outConverter = utf8Converter; /* dest is utf8 */
+ }
+
+ /* if dest is NULL, allocate space for it - may be reallocated later */
+ if (!*dest) {
+ /* good approximation of size is n chars in source * max dest char size */
+ destSize = ucnv_getMaxCharSize(outConverter) * sourceSize;
+ *dest = dsgw_ch_malloc(destSize);
+ destAlloc = 1;
+ }
+
+ /* set up the other variables */
+ mySource = source;
+ sourceLimit = source + sourceSize;
+ pivot = pivot2 = pivotBuffer;
+ myDest = *dest;
+ destLimit = *dest + destSize;
+
+ /*
+ * loops until the input buffer is completely consumed
+ * or an error is encountered;
+ * first we convert from inConverter codepage to Unicode
+ * then from Unicode to outConverter codepage
+ */
+ do {
+ pivot = pivotBuffer;
+ ucnv_toUnicode(inConverter,
+ &pivot, pivotBuffer + CHUNK_SIZE,
+ &mySource, sourceLimit,
+ NULL,
+ TRUE,
+ pErrorCode);
+
+ /* U_BUFFER_OVERFLOW_ERROR only means that the pivot buffer is full */
+ if(U_SUCCESS(*pErrorCode) || (*pErrorCode == U_BUFFER_OVERFLOW_ERROR)) {
+ pivot2 = pivotBuffer;
+
+ /* convert and write bytes from the pivot buffer to the dest -
+ if dest is allocated and we run out of space in dest, grow
+ dest and try again - otherwise, just bail out and let the
+ caller know that their dest buffer is full and they need
+ to try again */
+ do {
+ *pErrorCode = U_ZERO_ERROR;
+ ucnv_fromUnicode(outConverter,
+ &myDest, destLimit,
+ (const UChar **)&pivot2, pivot,
+ NULL,
+ (UBool)(mySource == sourceLimit),
+ pErrorCode);
+
+ /* we overflowed dest and dest is allocated, so let's increase
+ the dest size */
+ if ((*pErrorCode == U_BUFFER_OVERFLOW_ERROR) && destAlloc) {
+ /* figure out where myDest was pointing */
+ size_t myDestOffset = myDest - *dest;
+ /* probably don't need this much more room . . . */
+ destSize += CHUNK_SIZE;
+ /* realloc *dest for new size */
+ *dest = dsgw_ch_realloc(*dest, destSize);
+ /* reset myDest in new *dest */
+ myDest = *dest + myDestOffset;
+ /* set new destLimit */
+ destLimit = *dest + destSize;
+ } else {
+ break; /* skip it */
+ }
+ } while(*pErrorCode == U_BUFFER_OVERFLOW_ERROR);
+ /*
+ * If this overflows the fixed size dest, then we must stop
+ * converting and return what we already have
+ * in this case, pErrorCode will be buffer overflow error because
+ * we have overflowed the dest buffer
+ * the outer while loop will break because !U_SUCCESS
+ */
+ }
+ } while(U_SUCCESS(*pErrorCode) && source != sourceLimit);
+
+ *nSource = mySource - source; /* n chars read from source */
+ *nDest = myDest - *dest; /* n chars written to dest */
+
+ if (U_SUCCESS(*pErrorCode) && source == sourceLimit) {
+ /* reset internal converter */
+ ucnv_reset(utf8Converter);
+ return 1; /* converted entire string */
+ }
+
+ if (source != sourceLimit) {
+ /* not done with conversion yet */
+ /* no reset here - preserve state for next call */
+ return 0;
+ }
+
+ /* error */
+ ucnv_reset(utf8Converter);
+ return -1;
+}