]> git.ipfire.org Git - thirdparty/cups.git/blob - cgi-bin/var.c
Finish up cups-driverd and fix some bugs.
[thirdparty/cups.git] / cgi-bin / var.c
1 /*
2 * "$Id$"
3 *
4 * CGI form variable and array functions.
5 *
6 * Copyright 1997-2005 by Easy Software Products.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the Free
10 * Software Foundation; either version 2 of the License, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 *
22 * Contents:
23 *
24 * cgiInitialize() - Initialize the CGI variable "database"...
25 * cgiIsPOST() - Determine whether this page was POSTed.
26 * cgiCheckVariables() - Check for the presence of "required" variables.
27 * cgiGetArray() - Get an element from a form array...
28 * cgiGetSize() - Get the size of a form array value.
29 * cgiGetVariable() - Get a CGI variable from the database...
30 * cgiSetArray() - Set array element N to the specified string.
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_get() - Initialize form variables using the GET method.
36 * cgi_initialize_post() - Initialize variables using the POST method.
37 * cgi_initialize_string() - Initialize form variables from a string.
38 * cgi_sort_variables() - Sort all form variables for faster lookup.
39 */
40
41 /*#define DEBUG*/
42 #include "cgi.h"
43 #include <cups/cups.h>
44 #include <errno.h>
45 #include <syslog.h>
46
47
48 /*
49 * Data structure to hold all the CGI form variables and arrays...
50 */
51
52 typedef struct
53 {
54 const char *name; /* Name of variable */
55 int nvalues, /* Number of values */
56 avalues; /* Number of values allocated */
57 const char **values; /* Value(s) of variable */
58 } var_t;
59
60
61 /*
62 * Local globals...
63 */
64
65 static int form_count = 0, /* Form variable count */
66 form_alloc = 0; /* Number of variables allocated */
67 static var_t *form_vars = NULL; /* Form variables */
68
69
70 /*
71 * Local functions...
72 */
73
74 static void cgi_add_variable(const char *name, int element,
75 const char *value);
76 static int cgi_compare_variables(const var_t *v1, const var_t *v2);
77 static var_t *cgi_find_variable(const char *name);
78 static int cgi_initialize_get(void);
79 static int cgi_initialize_post(void);
80 static int cgi_initialize_string(const char *data);
81 static const char *cgi_passwd(const char *prompt);
82 static void cgi_sort_variables(void);
83
84
85 /*
86 * 'cgiInitialize()' - Initialize the CGI variable "database"...
87 */
88
89 int /* O - Non-zero if there was form data */
90 cgiInitialize(void)
91 {
92 const char *method; /* Form posting method */
93
94
95 /*
96 * Setup a password callback for authentication...
97 */
98
99 cupsSetPasswordCB(cgi_passwd);
100
101 #ifdef DEBUG
102 /*
103 * Disable output buffering to find bugs...
104 */
105
106 setbuf(stdout, NULL);
107 puts("Content-type: text/plain\n");
108 #endif /* DEBUG */
109
110 /*
111 * Get the request method (GET or POST)...
112 */
113
114 method = getenv("REQUEST_METHOD");
115
116 if (!method)
117 return (0);
118
119 /*
120 * Grab form data from the corresponding location...
121 */
122
123 if (!strcasecmp(method, "GET"))
124 return (cgi_initialize_get());
125 else if (!strcasecmp(method, "POST"))
126 return (cgi_initialize_post());
127 else
128 return (0);
129 }
130
131
132 /*
133 * 'cgiCheckVariables()' - Check for the presence of "required" variables.
134 *
135 * Names may be separated by spaces and/or commas.
136 */
137
138 int /* O - 1 if all variables present, 0 otherwise */
139 cgiCheckVariables(const char *names) /* I - Variables to look for */
140 {
141 char name[255], /* Current variable name */
142 *s; /* Pointer in string */
143 const char *val; /* Value of variable */
144 int element; /* Array element number */
145
146
147 if (names == NULL)
148 return (1);
149
150 while (*names != '\0')
151 {
152 while (*names == ' ' || *names == ',')
153 names ++;
154
155 for (s = name; *names != '\0' && *names != ' ' && *names != ','; s ++, names ++)
156 *s = *names;
157
158 *s = 0;
159 if (name[0] == '\0')
160 break;
161
162 if ((s = strrchr(name, '-')) != NULL)
163 {
164 *s = '\0';
165 element = atoi(s + 1) - 1;
166 val = cgiGetArray(name, element);
167 }
168 else
169 val = cgiGetVariable(name);
170
171 if (val == NULL)
172 return (0);
173
174 if (*val == '\0')
175 return (0); /* Can't be blank, either! */
176 }
177
178 return (1);
179 }
180
181
182 /*
183 * 'cgiIsPOST()' - Determine whether this page was POSTed.
184 */
185
186 int /* O - 1 if POST, 0 if GET */
187 cgiIsPOST(void)
188 {
189 const char *method; /* REQUEST_METHOD environment variable */
190
191
192 if ((method = getenv("REQUEST_METHOD")) == NULL)
193 return (0);
194 else
195 return (!strcmp(method, "POST"));
196 }
197
198
199 /*
200 * 'cgiGetArray()' - Get an element from a form array...
201 */
202
203 const char * /* O - Element value or NULL */
204 cgiGetArray(const char *name, /* I - Name of array variable */
205 int element) /* I - Element number (0 to N) */
206 {
207 var_t *var; /* Pointer to variable */
208
209
210 if ((var = cgi_find_variable(name)) == NULL)
211 return (NULL);
212
213 if (var->nvalues == 1)
214 return (var->values[0]);
215
216 if (element < 0 || element >= var->nvalues)
217 return (NULL);
218
219 return (var->values[element]);
220 }
221
222
223 /*
224 * 'cgiGetSize()' - Get the size of a form array value.
225 */
226
227 int /* O - Number of elements */
228 cgiGetSize(const char *name) /* I - Name of variable */
229 {
230 var_t *var; /* Pointer to variable */
231
232
233 if ((var = cgi_find_variable(name)) == NULL)
234 return (0);
235
236 return (var->nvalues);
237 }
238
239
240 /*
241 * 'cgiGetVariable()' - Get a CGI variable from the database...
242 *
243 * Returns NULL if the variable doesn't exist... If the variable is an
244 * array of values, returns the last element...
245 */
246
247 const char * /* O - Value of variable */
248 cgiGetVariable(const char *name)/* I - Name of variable */
249 {
250 const var_t *var; /* Returned variable */
251
252
253 var = cgi_find_variable(name);
254
255 #ifdef DEBUG
256 if (var == NULL)
257 printf("cgiGetVariable(\"%s\") is returning NULL...\n", name);
258 else
259 printf("cgiGetVariable(\"%s\") is returning \"%s\"...\n", name,
260 var->values[var->nvalues - 1]);
261 #endif /* DEBUG */
262
263 return ((var == NULL) ? NULL : var->values[var->nvalues - 1]);
264 }
265
266
267 /*
268 * 'cgiSetArray()' - Set array element N to the specified string.
269 *
270 * If the variable array is smaller than (element + 1), the intervening
271 * elements are set to NULL.
272 */
273
274 void
275 cgiSetArray(const char *name, /* I - Name of variable */
276 int element, /* I - Element number (0 to N) */
277 const char *value) /* I - Value of variable */
278 {
279 int i; /* Looping var */
280 var_t *var; /* Returned variable */
281
282
283 if (name == NULL || value == NULL || element < 0 || element > 100000)
284 return;
285
286 if ((var = cgi_find_variable(name)) == NULL)
287 {
288 cgi_add_variable(name, element, value);
289 cgi_sort_variables();
290 }
291 else
292 {
293 if (element >= var->avalues)
294 {
295 var->avalues = element + 16;
296 var->values = (const char **)realloc((void *)(var->values),
297 sizeof(char *) * var->avalues);
298 }
299
300 if (element >= var->nvalues)
301 {
302 for (i = var->nvalues; i < element; i ++)
303 var->values[i] = NULL;
304
305 var->nvalues = element + 1;
306 }
307 else if (var->values[element])
308 free((char *)var->values[element]);
309
310 var->values[element] = strdup(value);
311 }
312 }
313
314
315 /*
316 * 'cgiSetSize()' - Set the array size.
317 */
318
319 void
320 cgiSetSize(const char *name, /* I - Name of variable */
321 int size) /* I - Number of elements (0 to N) */
322 {
323 int i; /* Looping var */
324 var_t *var; /* Returned variable */
325
326
327 if (name == NULL || size < 0 || size > 100000)
328 return;
329
330 if ((var = cgi_find_variable(name)) == NULL)
331 return;
332
333 if (size >= var->avalues)
334 {
335 var->avalues = size + 16;
336 var->values = (const char **)realloc((void *)(var->values),
337 sizeof(char *) * var->avalues);
338 }
339
340 if (size > var->nvalues)
341 {
342 for (i = var->nvalues; i < size; i ++)
343 var->values[i] = NULL;
344 }
345 else if (size < var->nvalues)
346 {
347 for (i = size; i < var->nvalues; i ++)
348 if (var->values[i])
349 free((void *)(var->values[i]));
350 }
351
352 var->nvalues = size;
353 }
354
355
356 /*
357 * 'cgiSetVariable()' - Set a CGI variable in the database...
358 *
359 * If the variable is an array, this truncates the array to a single element.
360 */
361
362 void
363 cgiSetVariable(const char *name, /* I - Name of variable */
364 const char *value) /* I - Value of variable */
365 {
366 int i; /* Looping var */
367 var_t *var; /* Returned variable */
368
369
370 if (name == NULL || value == NULL)
371 return;
372
373 if ((var = cgi_find_variable(name)) == NULL)
374 {
375 cgi_add_variable(name, 0, value);
376 cgi_sort_variables();
377 }
378 else
379 {
380 for (i = 0; i < var->nvalues; i ++)
381 if (var->values[i])
382 free((char *)var->values[i]);
383
384 var->values[0] = strdup(value);
385 var->nvalues = 1;
386 }
387 }
388
389
390 /*
391 * 'cgi_add_variable()' - Add a form variable.
392 */
393
394 static void
395 cgi_add_variable(const char *name, /* I - Variable name */
396 int element, /* I - Array element number */
397 const char *value) /* I - Variable value */
398 {
399 var_t *var; /* New variable */
400
401
402 if (name == NULL || value == NULL || element < 0 || element > 100000)
403 return;
404
405 #ifdef DEBUG
406 printf("Adding variable \'%s\' with value \'%s\'...\n", name, value);
407 #endif /* DEBUG */
408
409 if (form_count >= form_alloc)
410 {
411 if (form_alloc == 0)
412 form_vars = malloc(sizeof(var_t) * 16);
413 else
414 form_vars = realloc(form_vars, (form_alloc + 16) * sizeof(var_t));
415
416 form_alloc += 16;
417 }
418
419 var = form_vars + form_count;
420 var->name = strdup(name);
421 var->nvalues = element + 1;
422 var->avalues = element + 1;
423 var->values = calloc(element + 1, sizeof(char *));
424 var->values[element] = strdup(value);
425
426 form_count ++;
427 }
428
429
430 /*
431 * 'cgi_compare_variables()' - Compare two variables.
432 */
433
434 static int /* O - Result of comparison */
435 cgi_compare_variables(const var_t *v1, /* I - First variable */
436 const var_t *v2) /* I - Second variable */
437 {
438 return (strcasecmp(v1->name, v2->name));
439 }
440
441
442 /*
443 * 'cgi_find_variable()' - Find a variable...
444 */
445
446 static var_t * /* O - Variable pointer or NULL */
447 cgi_find_variable(const char *name) /* I - Name of variable */
448 {
449 var_t key; /* Search key */
450
451
452 if (form_count < 1 || name == NULL)
453 return (NULL);
454
455 key.name = name;
456
457 return ((var_t *)bsearch(&key, form_vars, form_count, sizeof(var_t),
458 (int (*)(const void *, const void *))cgi_compare_variables));
459 }
460
461
462 /*
463 * 'cgi_initialize_get()' - Initialize form variables using the GET method.
464 */
465
466 static int /* O - 1 if form data read */
467 cgi_initialize_get(void)
468 {
469 char *data; /* Pointer to form data string */
470
471
472 #ifdef DEBUG
473 puts("Initializing variables using GET method...");
474 #endif /* DEBUG */
475
476 /*
477 * Check to see if there is anything for us to read...
478 */
479
480 data = getenv("QUERY_STRING");
481 if (data == NULL || strlen(data) == 0)
482 return (0);
483
484 /*
485 * Parse it out and return...
486 */
487
488 return (cgi_initialize_string(data));
489 }
490
491
492 /*
493 * 'cgi_initialize_post()' - Initialize variables using the POST method.
494 */
495
496 static int /* O - 1 if form data was read */
497 cgi_initialize_post(void)
498 {
499 char *content_length, /* Length of input data (string) */
500 *data; /* Pointer to form data string */
501 int length, /* Length of input data */
502 nbytes, /* Number of bytes read this read() */
503 tbytes, /* Total number of bytes read */
504 status; /* Return status */
505
506
507 #ifdef DEBUG
508 puts("Initializing variables using POST method...");
509 #endif /* DEBUG */
510
511 /*
512 * Check to see if there is anything for us to read...
513 */
514
515 content_length = getenv("CONTENT_LENGTH");
516 if (content_length == NULL || atoi(content_length) <= 0)
517 return (0);
518
519 /*
520 * Get the length of the input stream and allocate a buffer for it...
521 */
522
523 length = atoi(content_length);
524 data = malloc(length + 1);
525
526 if (data == NULL)
527 return (0);
528
529 /*
530 * Read the data into the buffer...
531 */
532
533 for (tbytes = 0; tbytes < length; tbytes += nbytes)
534 if ((nbytes = read(0, data + tbytes, length - tbytes)) < 0)
535 if (errno != EAGAIN)
536 {
537 free(data);
538 return (0);
539 }
540
541 data[length] = '\0';
542
543 /*
544 * Parse it out...
545 */
546
547 status = cgi_initialize_string(data);
548
549 /*
550 * Free the data and return...
551 */
552
553 free(data);
554
555 return (status);
556 }
557
558
559 /*
560 * 'cgi_initialize_string()' - Initialize form variables from a string.
561 */
562
563 static int
564 cgi_initialize_string(const char *data) /* I - Form data string */
565 {
566 int done; /* True if we're done reading a form variable */
567 char *s, /* Pointer to current form string */
568 ch, /* Temporary character */
569 name[255], /* Name of form variable */
570 value[65536]; /* Variable value... */
571
572
573 /*
574 * Check input...
575 */
576
577 if (data == NULL)
578 return (0);
579
580 /*
581 * Loop until we've read all the form data...
582 */
583
584 while (*data != '\0')
585 {
586 /*
587 * Get the variable name...
588 */
589
590 for (s = name; *data != '\0'; data ++)
591 if (*data == '=')
592 break;
593 else if (*data >= ' ' && s < (name + sizeof(name) - 1))
594 *s++ = *data;
595
596 *s = '\0';
597 if (*data == '=')
598 data ++;
599 else
600 return (0);
601
602 /*
603 * Read the variable value...
604 */
605
606 for (s = value, done = 0; !done && *data != '\0'; data ++)
607 switch (*data)
608 {
609 case '&' : /* End of data... */
610 done = 1;
611 break;
612
613 case '+' : /* Escaped space character */
614 if (s < (value + sizeof(value) - 1))
615 *s++ = ' ';
616 break;
617
618 case '%' : /* Escaped control character */
619 /*
620 * Read the hex code...
621 */
622
623 if (s < (value + sizeof(value) - 1))
624 {
625 data ++;
626 ch = *data - '0';
627 if (ch > 9)
628 ch -= 7;
629 *s = ch << 4;
630
631 data ++;
632 ch = *data - '0';
633 if (ch > 9)
634 ch -= 7;
635 *s++ |= ch;
636 }
637 else
638 data += 2;
639 break;
640
641 default : /* Other characters come straight through */
642 if (*data >= ' ' && s < (value + sizeof(value) - 1))
643 *s++ = *data;
644 break;
645 }
646
647 *s = '\0'; /* nul terminate the string */
648
649 /*
650 * Remove trailing whitespace...
651 */
652
653 if (s > value)
654 s --;
655
656 while (s >= value && *s == ' ')
657 *s-- = '\0';
658
659 /*
660 * Add the string to the variable "database"...
661 */
662
663 if ((s = strrchr(name, '-')) != NULL && isdigit(s[1] & 255))
664 {
665 *s++ = '\0';
666 if (value[0])
667 cgiSetArray(name, atoi(s) - 1, value);
668 }
669 else if (cgiGetVariable(name) != NULL)
670 cgiSetArray(name, cgiGetSize(name), value);
671 else
672 cgiSetVariable(name, value);
673 }
674
675 return (1);
676 }
677
678
679 /*
680 * 'cgi_passwd()' - Catch authentication requests and notify the server.
681 *
682 * This function sends a Status header and exits, forcing authentication
683 * for this request.
684 */
685
686 static const char * /* O - NULL (no return) */
687 cgi_passwd(const char *prompt) /* I - Prompt (not used) */
688 {
689 (void)prompt;
690
691 /*
692 * Send a 401 (unauthorized) status to the server, so it can notify
693 * the client that authentication is required.
694 */
695
696 puts("Status: 401\n");
697 exit(0);
698
699 /*
700 * This code is never executed, but is present to satisfy the compiler.
701 */
702
703 return (NULL);
704 }
705
706
707 /*
708 * 'cgi_sort_variables()' - Sort all form variables for faster lookup.
709 */
710
711 static void
712 cgi_sort_variables(void)
713 {
714 #ifdef DEBUG
715 int i;
716
717
718 puts("Sorting variables...");
719 #endif /* DEBUG */
720
721 if (form_count < 2)
722 return;
723
724 qsort(form_vars, form_count, sizeof(var_t),
725 (int (*)(const void *, const void *))cgi_compare_variables);
726
727 #ifdef DEBUG
728 puts("Sorted variable list is:");
729 for (i = 0; i < form_count; i ++)
730 printf("%d: %s (%d) = \"%s\" ...\n", i, form_vars[i].name,
731 form_vars[i].nvalues, form_vars[i].values[0]);
732 #endif /* DEBUG */
733 }
734
735
736 /*
737 * End of "$Id$".
738 */