/*
- * "$Id: var.c 7460 2008-04-16 02:19:54Z mike $"
+ * CGI form variable and array functions for CUPS.
*
- * CGI form variable and array functions.
+ * Copyright © 2007-2019 by Apple Inc.
+ * Copyright © 1997-2005 by Easy Software Products.
*
- * Copyright 2007-2009 by Apple Inc.
- * Copyright 1997-2005 by Easy Software Products.
- *
- * These coded instructions, statements, and computer programs are the
- * property of Apple Inc. and are protected by Federal copyright
- * law. Distribution and use rights are outlined in the file "LICENSE.txt"
- * which should have been included with this file. If this file is
- * file is missing or damaged, see the license at "http://www.cups.org/".
- *
- * Contents:
- *
- * cgiCheckVariables() - Check for the presence of "required" variables.
- * cgiGetArray() - Get an element from a form array...
- * cgiGetFile() - Get the file (if any) that was submitted in the form.
- * cgiGetSize() - Get the size of a form array value.
- * cgiGetVariable() - Get a CGI variable from the database...
- * cgiInitialize() - Initialize the CGI variable "database"...
- * cgiIsPOST() - Determine whether this page was POSTed.
- * cgiSetArray() - Set array element N to the specified string.
- * cgiSetSize() - Set the array size.
- * cgiSetVariable() - Set a CGI variable in the database...
- * cgi_add_variable() - Add a form variable.
- * cgi_compare_variables() - Compare two variables.
- * cgi_find_variable() - Find a variable...
- * cgi_initialize_get() - Initialize form variables using the GET method.
- * cgi_initialize_multipart() - Initialize variables and file using the POST method.
- * cgi_initialize_post() - Initialize variables using the POST method.
- * cgi_initialize_string() - Initialize form variables from a string.
- * cgi_passwd() - Catch authentication requests and notify the server.
- * cgi_sort_variables() - Sort all form variables for faster lookup.
- * cgi_unlink_file() - Remove the uploaded form.
+ * Licensed under Apache License v2.0. See the file "LICENSE" for more
+ * information.
+ */
+
+/*
+ * Include necessary headers...
*/
/*#define DEBUG*/
#include "cgi-private.h"
-#include <errno.h>
+#include <cups/http.h>
+
+
+/*
+ * Session ID name
+ */
+
+#define CUPS_SID "org.cups.sid"
/*
typedef struct /**** Form variable structure ****/
{
- const char *name; /* Name of variable */
+ char *name; /* Name of variable */
int nvalues, /* Number of values */
avalues; /* Number of values allocated */
- const char **values; /* Value(s) of variable */
+ char **values; /* Value(s) of variable */
} _cgi_var_t;
* Local globals...
*/
+static int num_cookies = 0;/* Number of cookies */
+static cups_option_t *cookies = NULL;/* Cookies */
static int form_count = 0, /* Form variable count */
form_alloc = 0; /* Number of variables allocated */
static _cgi_var_t *form_vars = NULL;
static int cgi_compare_variables(const _cgi_var_t *v1,
const _cgi_var_t *v2);
static _cgi_var_t *cgi_find_variable(const char *name);
+static void cgi_initialize_cookies(void);
static int cgi_initialize_get(void);
static int cgi_initialize_multipart(const char *boundary);
static int cgi_initialize_post(void);
static int cgi_initialize_string(const char *data);
static const char *cgi_passwd(const char *prompt);
+static const char *cgi_set_sid(void);
static void cgi_sort_variables(void);
static void cgi_unlink_file(void);
return (0);
if (*val == '\0')
+ {
+ free((void *)val);
return (0); /* Can't be blank, either! */
+ }
+
+ free((void *)val);
}
return (1);
/*
- * 'cgiGetArray()' - Get an element from a form array...
+ * 'cgiClearVariables()' - Clear all form variables.
*/
-const char * /* O - Element value or NULL */
+void
+cgiClearVariables(void)
+{
+ int i, j; /* Looping vars */
+ _cgi_var_t *v; /* Current variable */
+
+
+ fputs("DEBUG: cgiClearVariables called.\n", stderr);
+
+ for (v = form_vars, i = form_count; i > 0; v ++, i --)
+ {
+ free(v->name);
+ for (j = 0; j < v->nvalues; j ++)
+ if (v->values[j])
+ free(v->values[j]);
+ }
+
+ form_count = 0;
+
+ cgi_unlink_file();
+}
+
+
+/*
+ * 'cgiGetArray()' - Get an element from a form array.
+ */
+
+char * /* O - Element value or NULL */
cgiGetArray(const char *name, /* I - Name of array variable */
int element) /* I - Element number (0 to N) */
{
if (element < 0 || element >= var->nvalues)
return (NULL);
- return (var->values[element]);
+ if (var->values[element] == NULL)
+ return (NULL);
+
+ return (strdup(var->values[element]));
+}
+
+
+/*
+ * 'cgiGetCookie()' - Get a cookie value.
+ */
+
+const char * /* O - Value or NULL */
+cgiGetCookie(const char *name) /* I - Name of cookie */
+{
+ return (cupsGetOption(name, num_cookies, cookies));
}
/*
- * 'cgiGetVariable()' - Get a CGI variable from the database...
+ * 'cgiGetVariable()' - Get a CGI variable from the database.
*
* Returns NULL if the variable doesn't exist. If the variable is an
- * array of values, returns the last element...
+ * array of values, returns the last element.
*/
-const char * /* O - Value of variable */
+char * /* O - Value of variable */
cgiGetVariable(const char *name) /* I - Name of variable */
{
const _cgi_var_t *var; /* Returned variable */
var = cgi_find_variable(name);
-#ifdef DEBUG
- if (var == NULL)
- DEBUG_printf(("cgiGetVariable(\"%s\") is returning NULL...\n", name));
- else
- DEBUG_printf(("cgiGetVariable(\"%s\") is returning \"%s\"...\n", name,
- var->values[var->nvalues - 1]));
-#endif /* DEBUG */
-
- return ((var == NULL) ? NULL : var->values[var->nvalues - 1]);
+ return ((var == NULL) ? NULL : strdup(var->values[var->nvalues - 1]));
}
/*
- * 'cgiInitialize()' - Initialize the CGI variable "database"...
+ * 'cgiInitialize()' - Initialize the CGI variable "database".
*/
int /* O - Non-zero if there was form data */
cgiInitialize(void)
{
- const char *method; /* Form posting method */
- const char *content_type; /* Content-Type of post data */
+ const char *method, /* Form posting method */
+ *content_type, /* Content-Type of post data */
+ *cups_sid_cookie, /* SID cookie */
+ *cups_sid_form; /* SID form variable */
/*
setbuf(stdout, NULL);
#endif /* DEBUG */
+ /*
+ * Get cookies...
+ */
+
+ cgi_initialize_cookies();
+
+ if ((cups_sid_cookie = cgiGetCookie(CUPS_SID)) == NULL)
+ {
+ fputs("DEBUG: " CUPS_SID " cookie not found, initializing!\n", stderr);
+ cups_sid_cookie = cgi_set_sid();
+ }
+
+ fprintf(stderr, "DEBUG: " CUPS_SID " cookie is \"%s\"\n", cups_sid_cookie);
+
/*
* Get the request method (GET or POST)...
*/
* Grab form data from the corresponding location...
*/
- if (!strcasecmp(method, "GET"))
+ if (!_cups_strcasecmp(method, "GET"))
return (cgi_initialize_get());
- else if (!strcasecmp(method, "POST") && content_type)
+ else if (!_cups_strcasecmp(method, "POST") && content_type)
{
const char *boundary = strstr(content_type, "boundary=");
boundary += 9;
if (content_type && !strncmp(content_type, "multipart/form-data; ", 21))
- return (cgi_initialize_multipart(boundary));
+ {
+ if (!cgi_initialize_multipart(boundary))
+ return (0);
+ }
+ else if (!cgi_initialize_post())
+ return (0);
+
+ if ((cups_sid_form = cgiGetVariable(CUPS_SID)) == NULL ||
+ strcmp(cups_sid_cookie, cups_sid_form))
+ {
+ if (cups_sid_form)
+ fprintf(stderr, "DEBUG: " CUPS_SID " form variable is \"%s\"\n",
+ cups_sid_form);
+ else
+ fputs("DEBUG: " CUPS_SID " form variable is not present.\n", stderr);
+
+ free((void *)cups_sid_form);
+
+ cgiClearVariables();
+
+ return (0);
+ }
else
- return (cgi_initialize_post());
+ {
+ free((void *)cups_sid_form);
+
+ return (1);
+ }
}
else
return (0);
if (name == NULL || value == NULL || element < 0 || element > 100000)
return;
+ fprintf(stderr, "DEBUG: cgiSetArray: %s[%d]=\"%s\"\n", name, element, value);
+
if ((var = cgi_find_variable(name)) == NULL)
{
cgi_add_variable(name, element, value);
{
if (element >= var->avalues)
{
- const char **temp; /* Temporary pointer */
+ char **temp; /* Temporary pointer */
- temp = (const char **)realloc((void *)(var->values),
- sizeof(char *) * (element + 16));
+ temp = (char **)realloc((void *)(var->values), sizeof(char *) * (size_t)(element + 16));
if (!temp)
return;
}
+/*
+ * 'cgiSetCookie()' - Set a cookie value.
+ */
+
+void
+cgiSetCookie(const char *name, /* I - Name */
+ const char *value, /* I - Value */
+ const char *path, /* I - Path (typically "/") */
+ const char *domain, /* I - Domain name */
+ time_t expires, /* I - Expiration date (0 for session) */
+ int secure) /* I - Require SSL */
+{
+ num_cookies = cupsAddOption(name, value, num_cookies, &cookies);
+
+ printf("Set-Cookie: %s=%s;", name, value);
+ if (path)
+ printf(" path=%s;", path);
+ if (domain)
+ printf(" domain=%s;", domain);
+ if (expires)
+ {
+ char date[256]; /* Date string */
+
+ printf(" expires=%s;", httpGetDateString2(expires, date, sizeof(date)));
+ }
+ if (secure)
+ puts(" httponly; secure;");
+ else
+ puts(" httponly;");
+}
+
+
/*
* 'cgiSetSize()' - Set the array size.
*/
if (size >= var->avalues)
{
- const char **temp; /* Temporary pointer */
+ char **temp; /* Temporary pointer */
- temp = (const char **)realloc((void *)(var->values),
- sizeof(char *) * (size + 16));
+ temp = (char **)realloc((void *)(var->values), sizeof(char *) * (size_t)(size + 16));
if (!temp)
return;
/*
- * 'cgiSetVariable()' - Set a CGI variable in the database...
+ * 'cgiSetVariable()' - Set a CGI variable in the database.
*
* If the variable is an array, this truncates the array to a single element.
*/
if (name == NULL || value == NULL)
return;
+ fprintf(stderr, "cgiSetVariable: %s=\"%s\"\n", name, value);
+
if ((var = cgi_find_variable(name)) == NULL)
{
cgi_add_variable(name, 0, value);
if (name == NULL || value == NULL || element < 0 || element > 100000)
return;
- DEBUG_printf(("cgi_add_variable: Adding variable \'%s\' with value "
- "\'%s\'...\n", name, value));
-
if (form_count >= form_alloc)
{
_cgi_var_t *temp_vars; /* Temporary form pointer */
if (form_alloc == 0)
temp_vars = malloc(sizeof(_cgi_var_t) * 16);
else
- temp_vars = realloc(form_vars, (form_alloc + 16) * sizeof(_cgi_var_t));
+ temp_vars = realloc(form_vars, (size_t)(form_alloc + 16) * sizeof(_cgi_var_t));
if (!temp_vars)
return;
var = form_vars + form_count;
- if ((var->values = calloc(element + 1, sizeof(char *))) == NULL)
+ if ((var->values = calloc((size_t)element + 1, sizeof(char *))) == NULL)
return;
var->name = strdup(name);
const _cgi_var_t *v1, /* I - First variable */
const _cgi_var_t *v2) /* I - Second variable */
{
- return (strcasecmp(v1->name, v2->name));
+ return (_cups_strcasecmp(v1->name, v2->name));
}
/*
- * 'cgi_find_variable()' - Find a variable...
+ * 'cgi_find_variable()' - Find a variable.
*/
static _cgi_var_t * /* O - Variable pointer or NULL */
if (form_count < 1 || name == NULL)
return (NULL);
- key.name = name;
+ key.name = (char *)name;
- return ((_cgi_var_t *)bsearch(&key, form_vars, form_count, sizeof(_cgi_var_t),
+ return ((_cgi_var_t *)bsearch(&key, form_vars, (size_t)form_count, sizeof(_cgi_var_t),
(int (*)(const void *, const void *))cgi_compare_variables));
}
+/*
+ * 'cgi_initialize_cookies()' - Initialize cookies.
+ */
+
+static void
+cgi_initialize_cookies(void)
+{
+ const char *cookie; /* HTTP_COOKIE environment variable */
+ char name[128], /* Name string */
+ value[512], /* Value string */
+ *ptr; /* Pointer into name/value */
+
+
+ if ((cookie = getenv("HTTP_COOKIE")) == NULL)
+ return;
+
+ while (*cookie)
+ {
+ int skip = 0; /* Skip this cookie? */
+
+ /*
+ * Skip leading whitespace...
+ */
+
+ while (isspace(*cookie & 255))
+ cookie ++;
+ if (!*cookie)
+ break;
+
+ /*
+ * Copy the name...
+ */
+
+ for (ptr = name; *cookie && *cookie != '=';)
+ if (ptr < (name + sizeof(name) - 1))
+ {
+ *ptr++ = *cookie++;
+ }
+ else
+ {
+ skip = 1;
+ cookie ++;
+ }
+
+ if (*cookie != '=')
+ break;
+
+ *ptr = '\0';
+ cookie ++;
+
+ /*
+ * Then the value...
+ */
+
+ if (*cookie == '\"')
+ {
+ for (cookie ++, ptr = value; *cookie && *cookie != '\"';)
+ if (ptr < (value + sizeof(value) - 1))
+ {
+ *ptr++ = *cookie++;
+ }
+ else
+ {
+ skip = 1;
+ cookie ++;
+ }
+
+ if (*cookie == '\"')
+ cookie ++;
+ else
+ skip = 1;
+ }
+ else
+ {
+ for (ptr = value; *cookie && *cookie != ';';)
+ if (ptr < (value + sizeof(value) - 1))
+ {
+ *ptr++ = *cookie++;
+ }
+ else
+ {
+ skip = 1;
+ cookie ++;
+ }
+ }
+
+ if (*cookie == ';')
+ cookie ++;
+ else if (*cookie)
+ skip = 1;
+
+ *ptr = '\0';
+
+ /*
+ * Then add the cookie to an array as long as the name doesn't start with
+ * "$"...
+ */
+
+ if (name[0] != '$' && !skip)
+ num_cookies = cupsAddOption(name, value, num_cookies, &cookies);
+ }
+}
+
+
/*
* 'cgi_initialize_get()' - Initialize form variables using the GET method.
*/
char *data; /* Pointer to form data string */
- DEBUG_puts("cgi_initialize_get: Initializing variables using GET method...");
-
/*
* Check to see if there is anything for us to read...
*/
/*
- * 'cgi_initialize_multipart()' - Initialize variables and file using the POST method.
+ * 'cgi_initialize_multipart()' - Initialize variables and file using the POST
+ * method.
*
* TODO: Update to support files > 2GB.
*/
*ptr, /* Pointer into name/filename */
*end; /* End of buffer */
int ch, /* Character from file */
- fd, /* Temporary file descriptor */
- blen; /* Length of boundary string */
+ fd; /* Temporary file descriptor */
+ size_t blen; /* Length of boundary string */
- DEBUG_printf(("cgi_initialize_multipart(boundary=\"%s\")\n", boundary));
-
/*
* Read multipart form data until we run out...
*/
/*
* Copy file data to the temp file...
*/
-
+
ptr = line;
while ((ch = getchar()) != EOF)
{
- *ptr++ = ch;
+ *ptr++ = (char)ch;
- if ((ptr - line) >= blen && !memcmp(ptr - blen, bstring, blen))
+ if ((size_t)(ptr - line) >= blen && !memcmp(ptr - blen, bstring, blen))
{
ptr -= blen;
break;
}
- if ((ptr - line - blen) >= 8192)
+ if ((ptr - line - (int)blen) >= 8192)
{
/*
* Write out the first 8k of the buffer...
*/
write(fd, line, 8192);
- memmove(line, line + 8192, ptr - line - 8192);
+ memmove(line, line + 8192, (size_t)(ptr - line - 8192));
ptr -= 8192;
}
}
*/
if (ptr > line)
- write(fd, line, ptr - line);
+ write(fd, line, (size_t)(ptr - line));
close(fd);
}
while ((ch = getchar()) != EOF)
{
if (ptr < end)
- *ptr++ = ch;
+ *ptr++ = (char)ch;
- if ((ptr - line) >= blen && !memcmp(ptr - blen, bstring, blen))
+ if ((size_t)(ptr - line) >= blen && !memcmp(ptr - blen, bstring, blen))
{
ptr -= blen;
break;
if (line[0])
cgiSetArray(name, atoi(ptr) - 1, line);
}
- else if (cgiGetVariable(name))
+ else if ((ptr = cgiGetVariable(name)) != NULL)
{
/*
* Add another element in the array...
*/
+ free(ptr);
cgiSetArray(name, cgiGetSize(name), line);
}
else
filename[0] = '\0';
mimetype[0] = '\0';
}
- else if (!strncasecmp(line, "Content-Disposition:", 20))
+ else if (!_cups_strncasecmp(line, "Content-Disposition:", 20))
{
if ((ptr = strstr(line + 20, " name=\"")) != NULL)
{
*ptr = '\0';
}
}
- else if (!strncasecmp(line, "Content-Type:", 13))
+ else if (!_cups_strncasecmp(line, "Content-Type:", 13))
{
for (ptr = line + 13; isspace(*ptr & 255); ptr ++);
static int /* O - 1 if form data was read */
cgi_initialize_post(void)
{
- char *content_length, /* Length of input data (string) */
- *data; /* Pointer to form data string */
- int length, /* Length of input data */
- nbytes, /* Number of bytes read this read() */
- tbytes, /* Total number of bytes read */
- status; /* Return status */
-
+ char *content_length, /* Length of input data (string) */
+ *data; /* Pointer to form data string */
+ size_t length, /* Length of input data */
+ tbytes; /* Total number of bytes read */
+ ssize_t nbytes; /* Number of bytes read this read() */
+ int status; /* Return status */
- DEBUG_puts("cgi_initialize_post: Initializing variables using POST method...");
/*
* Check to see if there is anything for us to read...
* Get the length of the input stream and allocate a buffer for it...
*/
- length = atoi(content_length);
+ length = (size_t)strtol(content_length, NULL, 10);
data = malloc(length + 1);
if (data == NULL)
* Read the data into the buffer...
*/
- for (tbytes = 0; tbytes < length; tbytes += nbytes)
- if ((nbytes = read(0, data + tbytes, length - tbytes)) < 0)
+ for (tbytes = 0; tbytes < length; tbytes += (size_t)nbytes)
+ if ((nbytes = read(0, data + tbytes, (size_t)(length - tbytes))) < 0)
{
if (errno != EAGAIN)
{
char *s, /* Pointer to current form string */
ch, /* Temporary character */
name[255], /* Name of form variable */
- value[65536]; /* Variable value... */
+ value[65536], /* Variable value */
+ *temp; /* Temporary pointer */
/*
* Read the hex code...
*/
+ if (!isxdigit(data[1] & 255) || !isxdigit(data[2] & 255))
+ return (0);
+
if (s < (value + sizeof(value) - 1))
{
data ++;
ch = *data - '0';
if (ch > 9)
ch -= 7;
- *s = ch << 4;
+ *s = (char)(ch << 4);
data ++;
ch = *data - '0';
if (value[0])
cgiSetArray(name, atoi(s) - 1, value);
}
- else if (cgiGetVariable(name) != NULL)
+ else if ((temp = cgiGetVariable(name)) != NULL)
+ {
+ free(temp);
cgiSetArray(name, cgiGetSize(name), value);
+ }
else
cgiSetVariable(name, value);
}
/*
- * 'cgi_sort_variables()' - Sort all form variables for faster lookup.
+ * 'cgi_set_sid()' - Set the CUPS session ID.
*/
-static void
-cgi_sort_variables(void)
+static const char * /* O - New session ID */
+cgi_set_sid(void)
{
-#ifdef DEBUG
- int i;
+ char buffer[512], /* SID data */
+ sid[33]; /* SID string */
+ unsigned char sum[16]; /* MD5 sum */
+ const char *remote_addr, /* REMOTE_ADDR */
+ *server_name, /* SERVER_NAME */
+ *server_port; /* SERVER_PORT */
+ struct timeval curtime; /* Current time */
+
+
+ if ((remote_addr = getenv("REMOTE_ADDR")) == NULL)
+ remote_addr = "REMOTE_ADDR";
+ if ((server_name = getenv("SERVER_NAME")) == NULL)
+ server_name = "SERVER_NAME";
+ if ((server_port = getenv("SERVER_PORT")) == NULL)
+ server_port = "SERVER_PORT";
+
+ gettimeofday(&curtime, NULL);
+ CUPS_SRAND(curtime.tv_sec + curtime.tv_usec);
+ snprintf(buffer, sizeof(buffer), "%s:%s:%s:%02X%02X%02X%02X%02X%02X%02X%02X",
+ remote_addr, server_name, server_port,
+ (unsigned)CUPS_RAND() & 255, (unsigned)CUPS_RAND() & 255,
+ (unsigned)CUPS_RAND() & 255, (unsigned)CUPS_RAND() & 255,
+ (unsigned)CUPS_RAND() & 255, (unsigned)CUPS_RAND() & 255,
+ (unsigned)CUPS_RAND() & 255, (unsigned)CUPS_RAND() & 255);
+ cupsHashData("md5", (unsigned char *)buffer, strlen(buffer), sum, sizeof(sum));
+
+ cgiSetCookie(CUPS_SID, cupsHashString(sum, sizeof(sum), sid, sizeof(sid)), "/", NULL, 0, 0);
+
+ return (cupsGetOption(CUPS_SID, num_cookies, cookies));
+}
- DEBUG_puts("cgi_sort_variables: Sorting variables...");
-#endif /* DEBUG */
+/*
+ * 'cgi_sort_variables()' - Sort all form variables for faster lookup.
+ */
+static void
+cgi_sort_variables(void)
+{
if (form_count < 2)
return;
- qsort(form_vars, form_count, sizeof(_cgi_var_t),
+ qsort(form_vars, (size_t)form_count, sizeof(_cgi_var_t),
(int (*)(const void *, const void *))cgi_compare_variables);
-
-#ifdef DEBUG
- DEBUG_puts("cgi_sort_variables: Sorted variable list is:");
- for (i = 0; i < form_count; i ++)
- DEBUG_printf(("cgi_sort_variables: %d: %s (%d) = \"%s\" ...\n", i,
- form_vars[i].name, form_vars[i].nvalues,
- form_vars[i].values[0]));
-#endif /* DEBUG */
}
form_file = NULL;
}
}
-
-
-/*
- * End of "$Id: var.c 7460 2008-04-16 02:19:54Z mike $".
- */