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