]> git.ipfire.org Git - thirdparty/cups.git/blame - cgi-bin/var.c
Import experimental work-in-progress HTTP/2 branch
[thirdparty/cups.git] / cgi-bin / var.c
CommitLineData
ef416fc2 1/*
354aadbe 2 * "$Id: var.c 13138 2016-03-15 14:59:54Z msweet $"
ef416fc2 3 *
7e86f2f6 4 * CGI form variable and array functions for CUPS.
ef416fc2 5 *
fab4b71e 6 * Copyright 2007-2015 by Apple Inc.
7e86f2f6 7 * Copyright 1997-2005 by Easy Software Products.
ef416fc2 8 *
7e86f2f6
MS
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
14 */
15
16/*
17 * Include necessary headers...
ef416fc2 18 */
19
20/*#define DEBUG*/
21#include "cgi-private.h"
f8b3a85b 22#include <cups/http.h>
71e16022 23#include <cups/md5-private.h>
f8b3a85b
MS
24
25
26/*
27 * Session ID name
28 */
29
30#define CUPS_SID "org.cups.sid"
ef416fc2 31
32
33/*
34 * Data structure to hold all the CGI form variables and arrays...
35 */
36
37typedef struct /**** Form variable structure ****/
38{
39 const char *name; /* Name of variable */
40 int nvalues, /* Number of values */
41 avalues; /* Number of values allocated */
42 const char **values; /* Value(s) of variable */
43} _cgi_var_t;
44
45
46/*
47 * Local globals...
48 */
49
f8b3a85b
MS
50static int num_cookies = 0;/* Number of cookies */
51static cups_option_t *cookies = NULL;/* Cookies */
ef416fc2 52static int form_count = 0, /* Form variable count */
53 form_alloc = 0; /* Number of variables allocated */
54static _cgi_var_t *form_vars = NULL;
55 /* Form variables */
56static cgi_file_t *form_file = NULL;
57 /* Uploaded file */
58
59
60/*
61 * Local functions...
62 */
63
64static void cgi_add_variable(const char *name, int element,
65 const char *value);
66static int cgi_compare_variables(const _cgi_var_t *v1,
67 const _cgi_var_t *v2);
68static _cgi_var_t *cgi_find_variable(const char *name);
f8b3a85b 69static void cgi_initialize_cookies(void);
ef416fc2 70static int cgi_initialize_get(void);
71static int cgi_initialize_multipart(const char *boundary);
72static int cgi_initialize_post(void);
73static int cgi_initialize_string(const char *data);
74static const char *cgi_passwd(const char *prompt);
f8b3a85b 75static const char *cgi_set_sid(void);
ef416fc2 76static void cgi_sort_variables(void);
77static void cgi_unlink_file(void);
78
79
80/*
81 * 'cgiCheckVariables()' - Check for the presence of "required" variables.
82 *
83 * Names may be separated by spaces and/or commas.
84 */
85
86int /* O - 1 if all variables present, 0 otherwise */
87cgiCheckVariables(const char *names) /* I - Variables to look for */
88{
89 char name[255], /* Current variable name */
90 *s; /* Pointer in string */
91 const char *val; /* Value of variable */
92 int element; /* Array element number */
93
94
95 if (names == NULL)
96 return (1);
97
98 while (*names != '\0')
99 {
100 while (*names == ' ' || *names == ',')
101 names ++;
102
103 for (s = name; *names != '\0' && *names != ' ' && *names != ','; s ++, names ++)
104 *s = *names;
105
106 *s = 0;
107 if (name[0] == '\0')
108 break;
109
110 if ((s = strrchr(name, '-')) != NULL)
111 {
112 *s = '\0';
113 element = atoi(s + 1) - 1;
114 val = cgiGetArray(name, element);
115 }
116 else
117 val = cgiGetVariable(name);
118
119 if (val == NULL)
120 return (0);
121
122 if (*val == '\0')
123 return (0); /* Can't be blank, either! */
124 }
125
126 return (1);
127}
128
129
ef55b745
MS
130/*
131 * 'cgiClearVariables()' - Clear all form variables.
132 */
133
134void
135cgiClearVariables(void)
136{
137 int i, j; /* Looping vars */
138 _cgi_var_t *v; /* Current variable */
139
140
82cc1f9a
MS
141 fputs("DEBUG: cgiClearVariables called.\n", stderr);
142
ef55b745
MS
143 for (v = form_vars, i = form_count; i > 0; v ++, i --)
144 {
145 _cupsStrFree(v->name);
146 for (j = 0; j < v->nvalues; j ++)
147 if (v->values[j])
148 _cupsStrFree(v->values[j]);
149 }
150
151 form_count = 0;
152
153 cgi_unlink_file();
154}
155
156
ef416fc2 157/*
f8b3a85b 158 * 'cgiGetArray()' - Get an element from a form array.
ef416fc2 159 */
160
161const char * /* O - Element value or NULL */
162cgiGetArray(const char *name, /* I - Name of array variable */
163 int element) /* I - Element number (0 to N) */
164{
165 _cgi_var_t *var; /* Pointer to variable */
166
167
168 if ((var = cgi_find_variable(name)) == NULL)
169 return (NULL);
170
ef416fc2 171 if (element < 0 || element >= var->nvalues)
172 return (NULL);
173
ef55b745 174 return (_cupsStrRetain(var->values[element]));
ef416fc2 175}
176
177
f8b3a85b
MS
178/*
179 * 'cgiGetCookie()' - Get a cookie value.
180 */
181
182const char * /* O - Value or NULL */
183cgiGetCookie(const char *name) /* I - Name of cookie */
184{
185 return (cupsGetOption(name, num_cookies, cookies));
186}
187
188
ef416fc2 189/*
190 * 'cgiGetFile()' - Get the file (if any) that was submitted in the form.
191 */
192
193const cgi_file_t * /* O - Attached file or NULL */
194cgiGetFile(void)
195{
196 return (form_file);
197}
198
199
200/*
201 * 'cgiGetSize()' - Get the size of a form array value.
202 */
203
204int /* O - Number of elements */
205cgiGetSize(const char *name) /* I - Name of variable */
206{
207 _cgi_var_t *var; /* Pointer to variable */
208
209
210 if ((var = cgi_find_variable(name)) == NULL)
211 return (0);
212
213 return (var->nvalues);
214}
215
216
217/*
f8b3a85b 218 * 'cgiGetVariable()' - Get a CGI variable from the database.
ef416fc2 219 *
220 * Returns NULL if the variable doesn't exist. If the variable is an
f8b3a85b 221 * array of values, returns the last element.
ef416fc2 222 */
223
224const char * /* O - Value of variable */
225cgiGetVariable(const char *name) /* I - Name of variable */
226{
227 const _cgi_var_t *var; /* Returned variable */
228
229
230 var = cgi_find_variable(name);
231
232#ifdef DEBUG
233 if (var == NULL)
ae71f5de 234 DEBUG_printf(("cgiGetVariable(\"%s\") is returning NULL...\n", name));
ef416fc2 235 else
ae71f5de
MS
236 DEBUG_printf(("cgiGetVariable(\"%s\") is returning \"%s\"...\n", name,
237 var->values[var->nvalues - 1]));
ef416fc2 238#endif /* DEBUG */
239
ef55b745 240 return ((var == NULL) ? NULL : _cupsStrRetain(var->values[var->nvalues - 1]));
ef416fc2 241}
242
243
244/*
f8b3a85b 245 * 'cgiInitialize()' - Initialize the CGI variable "database".
ef416fc2 246 */
247
248int /* O - Non-zero if there was form data */
249cgiInitialize(void)
250{
f8b3a85b
MS
251 const char *method, /* Form posting method */
252 *content_type, /* Content-Type of post data */
253 *cups_sid_cookie, /* SID cookie */
254 *cups_sid_form; /* SID form variable */
ef416fc2 255
256
257 /*
258 * Setup a password callback for authentication...
259 */
260
261 cupsSetPasswordCB(cgi_passwd);
262
80ca4592 263 /*
264 * Set the locale so that times, etc. are formatted properly...
265 */
266
267 setlocale(LC_ALL, "");
268
ef416fc2 269#ifdef DEBUG
270 /*
271 * Disable output buffering to find bugs...
272 */
273
274 setbuf(stdout, NULL);
ef416fc2 275#endif /* DEBUG */
276
f8b3a85b
MS
277 /*
278 * Get cookies...
279 */
280
281 cgi_initialize_cookies();
282
283 if ((cups_sid_cookie = cgiGetCookie(CUPS_SID)) == NULL)
284 {
285 fputs("DEBUG: " CUPS_SID " cookie not found, initializing!\n", stderr);
286 cups_sid_cookie = cgi_set_sid();
287 }
288
289 fprintf(stderr, "DEBUG: " CUPS_SID " cookie is \"%s\"\n", cups_sid_cookie);
290
ef416fc2 291 /*
292 * Get the request method (GET or POST)...
293 */
294
295 method = getenv("REQUEST_METHOD");
296 content_type = getenv("CONTENT_TYPE");
297 if (!method)
298 return (0);
299
300 /*
301 * Grab form data from the corresponding location...
302 */
303
88f9aafc 304 if (!_cups_strcasecmp(method, "GET"))
ef416fc2 305 return (cgi_initialize_get());
88f9aafc 306 else if (!_cups_strcasecmp(method, "POST") && content_type)
ef416fc2 307 {
308 const char *boundary = strstr(content_type, "boundary=");
309
310 if (boundary)
311 boundary += 9;
312
313 if (content_type && !strncmp(content_type, "multipart/form-data; ", 21))
f8b3a85b
MS
314 {
315 if (!cgi_initialize_multipart(boundary))
316 return (0);
317 }
318 else if (!cgi_initialize_post())
319 return (0);
320
321 if ((cups_sid_form = cgiGetVariable(CUPS_SID)) == NULL ||
322 strcmp(cups_sid_cookie, cups_sid_form))
323 {
324 if (cups_sid_form)
325 fprintf(stderr, "DEBUG: " CUPS_SID " form variable is \"%s\"\n",
326 cups_sid_form);
327 else
328 fputs("DEBUG: " CUPS_SID " form variable is not present.\n", stderr);
329
330 cgiClearVariables();
331 return (0);
332 }
ef416fc2 333 else
f8b3a85b 334 return (1);
ef416fc2 335 }
336 else
337 return (0);
338}
339
340
341/*
342 * 'cgiIsPOST()' - Determine whether this page was POSTed.
343 */
344
345int /* O - 1 if POST, 0 if GET */
346cgiIsPOST(void)
347{
348 const char *method; /* REQUEST_METHOD environment variable */
349
350
351 if ((method = getenv("REQUEST_METHOD")) == NULL)
352 return (0);
353 else
354 return (!strcmp(method, "POST"));
355}
356
357
358/*
359 * 'cgiSetArray()' - Set array element N to the specified string.
360 *
361 * If the variable array is smaller than (element + 1), the intervening
362 * elements are set to NULL.
363 */
364
365void
366cgiSetArray(const char *name, /* I - Name of variable */
367 int element, /* I - Element number (0 to N) */
368 const char *value) /* I - Value of variable */
369{
370 int i; /* Looping var */
371 _cgi_var_t *var; /* Returned variable */
372
373
374 if (name == NULL || value == NULL || element < 0 || element > 100000)
375 return;
376
82cc1f9a
MS
377 fprintf(stderr, "DEBUG: cgiSetArray: %s[%d]=\"%s\"\n", name, element, value);
378
ef416fc2 379 if ((var = cgi_find_variable(name)) == NULL)
380 {
381 cgi_add_variable(name, element, value);
382 cgi_sort_variables();
383 }
384 else
385 {
386 if (element >= var->avalues)
387 {
91c84a35
MS
388 const char **temp; /* Temporary pointer */
389
390 temp = (const char **)realloc((void *)(var->values),
7e86f2f6 391 sizeof(char *) * (size_t)(element + 16));
91c84a35
MS
392 if (!temp)
393 return;
394
ef416fc2 395 var->avalues = element + 16;
91c84a35 396 var->values = temp;
ef416fc2 397 }
398
399 if (element >= var->nvalues)
400 {
401 for (i = var->nvalues; i < element; i ++)
402 var->values[i] = NULL;
403
404 var->nvalues = element + 1;
405 }
406 else if (var->values[element])
ef55b745 407 _cupsStrFree((char *)var->values[element]);
ef416fc2 408
ef55b745 409 var->values[element] = _cupsStrAlloc(value);
ef416fc2 410 }
411}
412
413
f8b3a85b
MS
414/*
415 * 'cgiSetCookie()' - Set a cookie value.
416 */
417
418void
419cgiSetCookie(const char *name, /* I - Name */
420 const char *value, /* I - Value */
421 const char *path, /* I - Path (typically "/") */
422 const char *domain, /* I - Domain name */
423 time_t expires, /* I - Expiration date (0 for session) */
424 int secure) /* I - Require SSL */
425{
426 num_cookies = cupsAddOption(name, value, num_cookies, &cookies);
427
428 printf("Set-Cookie: %s=%s;", name, value);
429 if (path)
85dda01c 430 printf(" path=%s;", path);
f8b3a85b 431 if (domain)
85dda01c 432 printf(" domain=%s;", domain);
f8b3a85b
MS
433 if (expires)
434 {
435 char date[256]; /* Date string */
436
85dda01c 437 printf(" expires=%s;", httpGetDateString2(expires, date, sizeof(date)));
f8b3a85b
MS
438 }
439 if (secure)
6c2b2b19 440 puts(" httponly; secure;");
f8b3a85b 441 else
6c2b2b19 442 puts(" httponly;");
f8b3a85b
MS
443}
444
445
ef416fc2 446/*
447 * 'cgiSetSize()' - Set the array size.
448 */
449
450void
451cgiSetSize(const char *name, /* I - Name of variable */
452 int size) /* I - Number of elements (0 to N) */
453{
454 int i; /* Looping var */
455 _cgi_var_t *var; /* Returned variable */
456
457
458 if (name == NULL || size < 0 || size > 100000)
459 return;
460
461 if ((var = cgi_find_variable(name)) == NULL)
462 return;
463
464 if (size >= var->avalues)
465 {
91c84a35
MS
466 const char **temp; /* Temporary pointer */
467
468 temp = (const char **)realloc((void *)(var->values),
7e86f2f6 469 sizeof(char *) * (size_t)(size + 16));
91c84a35
MS
470 if (!temp)
471 return;
472
ef416fc2 473 var->avalues = size + 16;
91c84a35 474 var->values = temp;
ef416fc2 475 }
476
477 if (size > var->nvalues)
478 {
479 for (i = var->nvalues; i < size; i ++)
480 var->values[i] = NULL;
481 }
482 else if (size < var->nvalues)
483 {
484 for (i = size; i < var->nvalues; i ++)
485 if (var->values[i])
ef55b745 486 _cupsStrFree((void *)(var->values[i]));
ef416fc2 487 }
488
489 var->nvalues = size;
490}
491
492
493/*
f8b3a85b 494 * 'cgiSetVariable()' - Set a CGI variable in the database.
ef416fc2 495 *
496 * If the variable is an array, this truncates the array to a single element.
497 */
498
499void
500cgiSetVariable(const char *name, /* I - Name of variable */
501 const char *value) /* I - Value of variable */
502{
503 int i; /* Looping var */
504 _cgi_var_t *var; /* Returned variable */
505
506
507 if (name == NULL || value == NULL)
508 return;
509
82cc1f9a
MS
510 fprintf(stderr, "cgiSetVariable: %s=\"%s\"\n", name, value);
511
ef416fc2 512 if ((var = cgi_find_variable(name)) == NULL)
513 {
514 cgi_add_variable(name, 0, value);
515 cgi_sort_variables();
516 }
517 else
518 {
519 for (i = 0; i < var->nvalues; i ++)
520 if (var->values[i])
ef55b745 521 _cupsStrFree((char *)var->values[i]);
ef416fc2 522
ef55b745 523 var->values[0] = _cupsStrAlloc(value);
ef416fc2 524 var->nvalues = 1;
525 }
526}
527
528
529/*
530 * 'cgi_add_variable()' - Add a form variable.
531 */
532
533static void
534cgi_add_variable(const char *name, /* I - Variable name */
535 int element, /* I - Array element number */
536 const char *value) /* I - Variable value */
537{
91c84a35 538 _cgi_var_t *var; /* New variable */
ef416fc2 539
540
541 if (name == NULL || value == NULL || element < 0 || element > 100000)
542 return;
543
ae71f5de
MS
544 DEBUG_printf(("cgi_add_variable: Adding variable \'%s\' with value "
545 "\'%s\'...\n", name, value));
ef416fc2 546
547 if (form_count >= form_alloc)
548 {
91c84a35
MS
549 _cgi_var_t *temp_vars; /* Temporary form pointer */
550
551
ef416fc2 552 if (form_alloc == 0)
91c84a35 553 temp_vars = malloc(sizeof(_cgi_var_t) * 16);
ef416fc2 554 else
7e86f2f6 555 temp_vars = realloc(form_vars, (size_t)(form_alloc + 16) * sizeof(_cgi_var_t));
91c84a35
MS
556
557 if (!temp_vars)
558 return;
ef416fc2 559
91c84a35 560 form_vars = temp_vars;
ef416fc2 561 form_alloc += 16;
562 }
563
91c84a35
MS
564 var = form_vars + form_count;
565
7e86f2f6 566 if ((var->values = calloc((size_t)element + 1, sizeof(char *))) == NULL)
91c84a35
MS
567 return;
568
ef55b745 569 var->name = _cupsStrAlloc(name);
ef416fc2 570 var->nvalues = element + 1;
571 var->avalues = element + 1;
ef55b745 572 var->values[element] = _cupsStrAlloc(value);
ef416fc2 573
574 form_count ++;
575}
576
577
578/*
579 * 'cgi_compare_variables()' - Compare two variables.
580 */
581
582static int /* O - Result of comparison */
583cgi_compare_variables(
584 const _cgi_var_t *v1, /* I - First variable */
585 const _cgi_var_t *v2) /* I - Second variable */
586{
88f9aafc 587 return (_cups_strcasecmp(v1->name, v2->name));
ef416fc2 588}
589
590
591/*
f8b3a85b 592 * 'cgi_find_variable()' - Find a variable.
ef416fc2 593 */
594
595static _cgi_var_t * /* O - Variable pointer or NULL */
596cgi_find_variable(const char *name) /* I - Name of variable */
597{
598 _cgi_var_t key; /* Search key */
599
600
601 if (form_count < 1 || name == NULL)
602 return (NULL);
603
604 key.name = name;
605
7e86f2f6 606 return ((_cgi_var_t *)bsearch(&key, form_vars, (size_t)form_count, sizeof(_cgi_var_t),
ef416fc2 607 (int (*)(const void *, const void *))cgi_compare_variables));
608}
609
610
f8b3a85b
MS
611/*
612 * 'cgi_initialize_cookies()' - Initialize cookies.
613 */
614
615static void
616cgi_initialize_cookies(void)
617{
618 const char *cookie; /* HTTP_COOKIE environment variable */
619 char name[128], /* Name string */
620 value[512], /* Value string */
621 *ptr; /* Pointer into name/value */
622
623
624 if ((cookie = getenv("HTTP_COOKIE")) == NULL)
625 return;
626
627 while (*cookie)
628 {
fab4b71e
MS
629 int skip = 0; /* Skip this cookie? */
630
f8b3a85b
MS
631 /*
632 * Skip leading whitespace...
633 */
634
635 while (isspace(*cookie & 255))
636 cookie ++;
637 if (!*cookie)
638 break;
639
640 /*
641 * Copy the name...
642 */
643
644 for (ptr = name; *cookie && *cookie != '=';)
645 if (ptr < (name + sizeof(name) - 1))
fab4b71e 646 {
f8b3a85b 647 *ptr++ = *cookie++;
fab4b71e 648 }
f8b3a85b 649 else
fab4b71e
MS
650 {
651 skip = 1;
652 cookie ++;
653 }
f8b3a85b
MS
654
655 if (*cookie != '=')
656 break;
657
658 *ptr = '\0';
659 cookie ++;
660
661 /*
662 * Then the value...
663 */
664
665 if (*cookie == '\"')
666 {
667 for (cookie ++, ptr = value; *cookie && *cookie != '\"';)
668 if (ptr < (value + sizeof(value) - 1))
fab4b71e 669 {
f8b3a85b 670 *ptr++ = *cookie++;
fab4b71e 671 }
f8b3a85b 672 else
fab4b71e
MS
673 {
674 skip = 1;
675 cookie ++;
676 }
f8b3a85b
MS
677
678 if (*cookie == '\"')
679 cookie ++;
fab4b71e
MS
680 else
681 skip = 1;
f8b3a85b
MS
682 }
683 else
684 {
685 for (ptr = value; *cookie && *cookie != ';';)
686 if (ptr < (value + sizeof(value) - 1))
fab4b71e 687 {
f8b3a85b 688 *ptr++ = *cookie++;
fab4b71e 689 }
f8b3a85b 690 else
fab4b71e
MS
691 {
692 skip = 1;
693 cookie ++;
694 }
f8b3a85b
MS
695 }
696
697 if (*cookie == ';')
698 cookie ++;
699 else if (*cookie)
fab4b71e 700 skip = 1;
f8b3a85b
MS
701
702 *ptr = '\0';
703
704 /*
705 * Then add the cookie to an array as long as the name doesn't start with
706 * "$"...
707 */
708
fab4b71e 709 if (name[0] != '$' && !skip)
f8b3a85b
MS
710 num_cookies = cupsAddOption(name, value, num_cookies, &cookies);
711 }
712}
713
714
ef416fc2 715/*
716 * 'cgi_initialize_get()' - Initialize form variables using the GET method.
717 */
718
719static int /* O - 1 if form data read */
720cgi_initialize_get(void)
721{
722 char *data; /* Pointer to form data string */
723
724
ae71f5de 725 DEBUG_puts("cgi_initialize_get: Initializing variables using GET method...");
ef416fc2 726
727 /*
728 * Check to see if there is anything for us to read...
729 */
730
731 data = getenv("QUERY_STRING");
732 if (data == NULL || strlen(data) == 0)
733 return (0);
734
735 /*
736 * Parse it out and return...
737 */
738
739 return (cgi_initialize_string(data));
740}
741
742
743/*
f8b3a85b
MS
744 * 'cgi_initialize_multipart()' - Initialize variables and file using the POST
745 * method.
ef416fc2 746 *
747 * TODO: Update to support files > 2GB.
748 */
749
750static int /* O - 1 if form data was read */
751cgi_initialize_multipart(
752 const char *boundary) /* I - Boundary string */
753{
754 char line[10240], /* MIME header line */
755 name[1024], /* Form variable name */
756 filename[1024], /* Form filename */
757 mimetype[1024], /* MIME media type */
758 bstring[256], /* Boundary string to look for */
759 *ptr, /* Pointer into name/filename */
760 *end; /* End of buffer */
761 int ch, /* Character from file */
7e86f2f6
MS
762 fd; /* Temporary file descriptor */
763 size_t blen; /* Length of boundary string */
ef416fc2 764
765
766 DEBUG_printf(("cgi_initialize_multipart(boundary=\"%s\")\n", boundary));
767
768 /*
769 * Read multipart form data until we run out...
770 */
771
772 name[0] = '\0';
773 filename[0] = '\0';
774 mimetype[0] = '\0';
775
776 snprintf(bstring, sizeof(bstring), "\r\n--%s", boundary);
777 blen = strlen(bstring);
778
779 while (fgets(line, sizeof(line), stdin))
780 {
781 if (!strcmp(line, "\r\n"))
782 {
783 /*
784 * End of headers, grab value...
785 */
786
787 if (filename[0])
788 {
789 /*
790 * Read an embedded file...
791 */
792
793 if (form_file)
794 {
795 /*
796 * Remove previous file...
797 */
798
799 cgi_unlink_file();
800 }
801
802 /*
803 * Allocate memory for the new file...
804 */
805
806 if ((form_file = calloc(1, sizeof(cgi_file_t))) == NULL)
807 return (0);
808
809 form_file->name = strdup(name);
810 form_file->filename = strdup(filename);
811 form_file->mimetype = strdup(mimetype);
812
813 fd = cupsTempFd(form_file->tempfile, sizeof(form_file->tempfile));
814
815 if (fd < 0)
816 return (0);
817
818 atexit(cgi_unlink_file);
819
820 /*
821 * Copy file data to the temp file...
822 */
88f9aafc 823
ef416fc2 824 ptr = line;
825
826 while ((ch = getchar()) != EOF)
827 {
7e86f2f6 828 *ptr++ = (char)ch;
ef416fc2 829
7e86f2f6 830 if ((size_t)(ptr - line) >= blen && !memcmp(ptr - blen, bstring, blen))
ef416fc2 831 {
832 ptr -= blen;
833 break;
834 }
835
7e86f2f6 836 if ((ptr - line - (int)blen) >= 8192)
ef416fc2 837 {
838 /*
839 * Write out the first 8k of the buffer...
840 */
841
842 write(fd, line, 8192);
07623986 843 memmove(line, line + 8192, (size_t)(ptr - line - 8192));
ef416fc2 844 ptr -= 8192;
845 }
846 }
847
848 /*
849 * Write the rest of the data and close the temp file...
850 */
851
852 if (ptr > line)
7e86f2f6 853 write(fd, line, (size_t)(ptr - line));
ef416fc2 854
855 close(fd);
856 }
857 else
858 {
859 /*
860 * Just get a form variable; the current code only handles
861 * form values up to 10k in size...
862 */
863
864 ptr = line;
865 end = line + sizeof(line) - 1;
866
867 while ((ch = getchar()) != EOF)
868 {
869 if (ptr < end)
7e86f2f6 870 *ptr++ = (char)ch;
ef416fc2 871
7e86f2f6 872 if ((size_t)(ptr - line) >= blen && !memcmp(ptr - blen, bstring, blen))
ef416fc2 873 {
874 ptr -= blen;
875 break;
876 }
877 }
878
879 *ptr = '\0';
880
881 /*
882 * Set the form variable...
883 */
884
885 if ((ptr = strrchr(name, '-')) != NULL && isdigit(ptr[1] & 255))
886 {
887 /*
888 * Set a specific index in the array...
889 */
890
891 *ptr++ = '\0';
892 if (line[0])
893 cgiSetArray(name, atoi(ptr) - 1, line);
894 }
895 else if (cgiGetVariable(name))
896 {
897 /*
898 * Add another element in the array...
899 */
900
901 cgiSetArray(name, cgiGetSize(name), line);
902 }
903 else
904 {
905 /*
906 * Just set the line...
907 */
908
909 cgiSetVariable(name, line);
910 }
911 }
912
913 /*
914 * Read the rest of the current line...
915 */
916
917 fgets(line, sizeof(line), stdin);
918
919 /*
920 * Clear the state vars...
921 */
922
923 name[0] = '\0';
924 filename[0] = '\0';
925 mimetype[0] = '\0';
926 }
88f9aafc 927 else if (!_cups_strncasecmp(line, "Content-Disposition:", 20))
ef416fc2 928 {
929 if ((ptr = strstr(line + 20, " name=\"")) != NULL)
930 {
931 strlcpy(name, ptr + 7, sizeof(name));
932
933 if ((ptr = strchr(name, '\"')) != NULL)
934 *ptr = '\0';
935 }
936
937 if ((ptr = strstr(line + 20, " filename=\"")) != NULL)
938 {
939 strlcpy(filename, ptr + 11, sizeof(filename));
940
941 if ((ptr = strchr(filename, '\"')) != NULL)
942 *ptr = '\0';
943 }
944 }
88f9aafc 945 else if (!_cups_strncasecmp(line, "Content-Type:", 13))
ef416fc2 946 {
947 for (ptr = line + 13; isspace(*ptr & 255); ptr ++);
948
949 strlcpy(mimetype, ptr, sizeof(mimetype));
950
951 for (ptr = mimetype + strlen(mimetype) - 1;
952 ptr > mimetype && isspace(*ptr & 255);
953 *ptr-- = '\0');
954 }
955 }
956
957 /*
958 * Return 1 for "form data found"...
959 */
960
961 return (1);
962}
963
964
965/*
966 * 'cgi_initialize_post()' - Initialize variables using the POST method.
967 */
968
969static int /* O - 1 if form data was read */
970cgi_initialize_post(void)
971{
7e86f2f6
MS
972 char *content_length, /* Length of input data (string) */
973 *data; /* Pointer to form data string */
974 size_t length, /* Length of input data */
975 tbytes; /* Total number of bytes read */
976 ssize_t nbytes; /* Number of bytes read this read() */
977 int status; /* Return status */
ef416fc2 978
979
ae71f5de 980 DEBUG_puts("cgi_initialize_post: Initializing variables using POST method...");
ef416fc2 981
982 /*
983 * Check to see if there is anything for us to read...
984 */
985
986 content_length = getenv("CONTENT_LENGTH");
987 if (content_length == NULL || atoi(content_length) <= 0)
988 return (0);
989
990 /*
991 * Get the length of the input stream and allocate a buffer for it...
992 */
993
7e86f2f6 994 length = (size_t)strtol(content_length, NULL, 10);
ef416fc2 995 data = malloc(length + 1);
996
997 if (data == NULL)
998 return (0);
999
1000 /*
1001 * Read the data into the buffer...
1002 */
1003
7e86f2f6
MS
1004 for (tbytes = 0; tbytes < length; tbytes += (size_t)nbytes)
1005 if ((nbytes = read(0, data + tbytes, (size_t)(length - tbytes))) < 0)
080811b1 1006 {
ef416fc2 1007 if (errno != EAGAIN)
1008 {
1009 free(data);
1010 return (0);
1011 }
080811b1
MS
1012 else
1013 nbytes = 0;
1014 }
f11a948a
MS
1015 else if (nbytes == 0)
1016 {
1017 /*
1018 * CUPS STR #3176: OpenBSD: Early end-of-file on POST data causes 100% CPU
1019 *
1020 * This should never happen, but does on OpenBSD. If we see early end-of-
1021 * file, treat this as an error and process no data.
1022 */
1023
1024 free(data);
1025 return (0);
1026 }
ef416fc2 1027
1028 data[length] = '\0';
1029
1030 /*
1031 * Parse it out...
1032 */
1033
1034 status = cgi_initialize_string(data);
1035
1036 /*
1037 * Free the data and return...
1038 */
1039
1040 free(data);
1041
1042 return (status);
1043}
1044
1045
1046/*
1047 * 'cgi_initialize_string()' - Initialize form variables from a string.
1048 */
1049
1050static int /* O - 1 if form data was processed */
1051cgi_initialize_string(const char *data) /* I - Form data string */
1052{
1053 int done; /* True if we're done reading a form variable */
1054 char *s, /* Pointer to current form string */
1055 ch, /* Temporary character */
1056 name[255], /* Name of form variable */
f8b3a85b 1057 value[65536]; /* Variable value */
ef416fc2 1058
1059
1060 /*
1061 * Check input...
1062 */
1063
1064 if (data == NULL)
1065 return (0);
1066
1067 /*
1068 * Loop until we've read all the form data...
1069 */
1070
1071 while (*data != '\0')
1072 {
1073 /*
1074 * Get the variable name...
1075 */
1076
1077 for (s = name; *data != '\0'; data ++)
1078 if (*data == '=')
1079 break;
1080 else if (*data >= ' ' && s < (name + sizeof(name) - 1))
1081 *s++ = *data;
1082
1083 *s = '\0';
1084 if (*data == '=')
1085 data ++;
1086 else
1087 return (0);
1088
1089 /*
1090 * Read the variable value...
1091 */
1092
1093 for (s = value, done = 0; !done && *data != '\0'; data ++)
1094 switch (*data)
1095 {
1096 case '&' : /* End of data... */
1097 done = 1;
1098 break;
1099
1100 case '+' : /* Escaped space character */
1101 if (s < (value + sizeof(value) - 1))
1102 *s++ = ' ';
1103 break;
1104
1105 case '%' : /* Escaped control character */
1106 /*
1107 * Read the hex code...
1108 */
1109
c7017ecc
MS
1110 if (!isxdigit(data[1] & 255) || !isxdigit(data[2] & 255))
1111 return (0);
1112
ef416fc2 1113 if (s < (value + sizeof(value) - 1))
1114 {
1115 data ++;
1116 ch = *data - '0';
1117 if (ch > 9)
1118 ch -= 7;
7e86f2f6 1119 *s = (char)(ch << 4);
ef416fc2 1120
1121 data ++;
1122 ch = *data - '0';
1123 if (ch > 9)
1124 ch -= 7;
1125 *s++ |= ch;
1126 }
1127 else
1128 data += 2;
1129 break;
1130
1131 default : /* Other characters come straight through */
1132 if (*data >= ' ' && s < (value + sizeof(value) - 1))
1133 *s++ = *data;
1134 break;
1135 }
1136
1137 *s = '\0'; /* nul terminate the string */
1138
1139 /*
1140 * Remove trailing whitespace...
1141 */
1142
1143 if (s > value)
1144 s --;
1145
58dc1933 1146 while (s >= value && isspace(*s & 255))
ef416fc2 1147 *s-- = '\0';
1148
1149 /*
1150 * Add the string to the variable "database"...
1151 */
1152
1153 if ((s = strrchr(name, '-')) != NULL && isdigit(s[1] & 255))
1154 {
1155 *s++ = '\0';
1156 if (value[0])
1157 cgiSetArray(name, atoi(s) - 1, value);
1158 }
1159 else if (cgiGetVariable(name) != NULL)
1160 cgiSetArray(name, cgiGetSize(name), value);
1161 else
1162 cgiSetVariable(name, value);
1163 }
1164
1165 return (1);
1166}
1167
1168
1169/*
1170 * 'cgi_passwd()' - Catch authentication requests and notify the server.
1171 *
1172 * This function sends a Status header and exits, forcing authentication
1173 * for this request.
1174 */
1175
1176static const char * /* O - NULL (no return) */
1177cgi_passwd(const char *prompt) /* I - Prompt (not used) */
1178{
1179 (void)prompt;
1180
f301802f 1181 fprintf(stderr, "DEBUG: cgi_passwd(prompt=\"%s\") called!\n",
1182 prompt ? prompt : "(null)");
ef416fc2 1183
1184 /*
1185 * Send a 401 (unauthorized) status to the server, so it can notify
1186 * the client that authentication is required.
1187 */
1188
1189 puts("Status: 401\n");
1190 exit(0);
1191
1192 /*
1193 * This code is never executed, but is present to satisfy the compiler.
1194 */
1195
1196 return (NULL);
1197}
1198
1199
f8b3a85b
MS
1200/*
1201 * 'cgi_set_sid()' - Set the CUPS session ID.
1202 */
1203
1204static const char * /* O - New session ID */
1205cgi_set_sid(void)
1206{
1207 char buffer[512], /* SID data */
1208 sid[33]; /* SID string */
1209 _cups_md5_state_t md5; /* MD5 state */
1210 unsigned char sum[16]; /* MD5 sum */
1211 const char *remote_addr, /* REMOTE_ADDR */
1212 *server_name, /* SERVER_NAME */
1213 *server_port; /* SERVER_PORT */
1214
1215
1216 if ((remote_addr = getenv("REMOTE_ADDR")) == NULL)
1217 remote_addr = "REMOTE_ADDR";
1218 if ((server_name = getenv("SERVER_NAME")) == NULL)
1219 server_name = "SERVER_NAME";
1220 if ((server_port = getenv("SERVER_PORT")) == NULL)
1221 server_port = "SERVER_PORT";
1222
1223 CUPS_SRAND(time(NULL));
1224 snprintf(buffer, sizeof(buffer), "%s:%s:%s:%02X%02X%02X%02X%02X%02X%02X%02X",
1225 remote_addr, server_name, server_port,
1226 (unsigned)CUPS_RAND() & 255, (unsigned)CUPS_RAND() & 255,
1227 (unsigned)CUPS_RAND() & 255, (unsigned)CUPS_RAND() & 255,
1228 (unsigned)CUPS_RAND() & 255, (unsigned)CUPS_RAND() & 255,
1229 (unsigned)CUPS_RAND() & 255, (unsigned)CUPS_RAND() & 255);
1230 _cupsMD5Init(&md5);
1231 _cupsMD5Append(&md5, (unsigned char *)buffer, (int)strlen(buffer));
1232 _cupsMD5Finish(&md5, sum);
88f9aafc 1233
c7017ecc 1234 cgiSetCookie(CUPS_SID, httpMD5String(sum, sid), "/", NULL, 0, 0);
f8b3a85b
MS
1235
1236 return (cupsGetOption(CUPS_SID, num_cookies, cookies));
1237}
1238
1239
ef416fc2 1240/*
1241 * 'cgi_sort_variables()' - Sort all form variables for faster lookup.
1242 */
1243
1244static void
1245cgi_sort_variables(void)
1246{
1247#ifdef DEBUG
1248 int i;
1249
1250
ae71f5de 1251 DEBUG_puts("cgi_sort_variables: Sorting variables...");
ef416fc2 1252#endif /* DEBUG */
1253
1254 if (form_count < 2)
1255 return;
1256
7e86f2f6 1257 qsort(form_vars, (size_t)form_count, sizeof(_cgi_var_t),
ef416fc2 1258 (int (*)(const void *, const void *))cgi_compare_variables);
1259
1260#ifdef DEBUG
ae71f5de 1261 DEBUG_puts("cgi_sort_variables: Sorted variable list is:");
ef416fc2 1262 for (i = 0; i < form_count; i ++)
ae71f5de
MS
1263 DEBUG_printf(("cgi_sort_variables: %d: %s (%d) = \"%s\" ...\n", i,
1264 form_vars[i].name, form_vars[i].nvalues,
1265 form_vars[i].values[0]));
ef416fc2 1266#endif /* DEBUG */
1267}
1268
1269
1270/*
1271 * 'cgi_unlink_file()' - Remove the uploaded form.
1272 */
1273
1274static void
1275cgi_unlink_file(void)
1276{
1277 if (form_file)
1278 {
1279 /*
1280 * Remove the temporary file...
1281 */
1282
1283 unlink(form_file->tempfile);
1284
1285 /*
1286 * Free memory used...
1287 */
1288
1289 free(form_file->name);
1290 free(form_file->filename);
1291 free(form_file->mimetype);
1292 free(form_file);
1293
1294 form_file = NULL;
1295 }
1296}
1297
1298
1299/*
354aadbe 1300 * End of "$Id: var.c 13138 2016-03-15 14:59:54Z msweet $".
ef416fc2 1301 */