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