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