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