]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/client.c
More changes to support job persistance.
[thirdparty/cups.git] / scheduler / client.c
CommitLineData
a74b005d 1/*
bd84e0d1 2 * "$Id: client.c,v 1.41 1999/12/29 02:15:40 mike Exp $"
a74b005d 3 *
4 * Client routines for the Common UNIX Printing System (CUPS) scheduler.
5 *
6 * Copyright 1997-1999 by Easy Software Products, all rights reserved.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
8784b6a6 17 * 44141 Airport View Drive, Suite 204
a74b005d 18 * Hollywood, Maryland 20636-3111 USA
19 *
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
93894a43 26 * AcceptClient() - Accept a new client.
27 * CloseAllClients() - Close all remote clients immediately.
28 * CloseClient() - Close a remote client.
29 * ReadClient() - Read data from a client.
30 * SendCommand() - Send output from a command via HTTP.
31 * SendError() - Send an error message via HTTP.
32 * SendFile() - Send a file via HTTP.
33 * SendHeader() - Send an HTTP request.
93894a43 34 * WriteClient() - Write data to a client as needed.
35 * check_if_modified() - Decode an "If-Modified-Since" line.
36 * decode_basic_auth() - Decode a Basic authorization string.
37 * get_file() - Get a filename and state info.
38 * pipe_command() - Pipe the output of a command to the remote client.
a74b005d 39 */
40
41/*
42 * Include necessary headers...
43 */
44
45#include "cupsd.h"
46
47
48/*
49 * Local functions...
50 */
51
a74b005d 52static int check_if_modified(client_t *con, struct stat *filestats);
93894a43 53static void decode_basic_auth(client_t *con);
a74b005d 54static char *get_file(client_t *con, struct stat *filestats);
b14d90ba 55static int pipe_command(client_t *con, int infile, int *outfile, char *command, char *options);
a74b005d 56
57
58/*
59 * 'AcceptClient()' - Accept a new client.
60 */
61
62void
63AcceptClient(listener_t *lis) /* I - Listener socket */
64{
65 int i; /* Looping var */
66 int val; /* Parameter value */
67 client_t *con; /* New client pointer */
68 unsigned address;/* Address of client */
69 struct hostent *host; /* Host entry for address */
70
71
bfa1abf0 72 DEBUG_printf(("AcceptClient(%08x) %d NumClients = %d\n",
73 lis, lis->fd, NumClients));
74
a74b005d 75 /*
76 * Get a pointer to the next available client...
77 */
78
79 con = Clients + NumClients;
80
81 memset(con, 0, sizeof(client_t));
82 con->http.activity = time(NULL);
83
84 /*
85 * Accept the client and get the remote address...
86 */
87
88 val = sizeof(struct sockaddr_in);
89
2f6d083c 90 if ((con->http.fd = accept(lis->fd, (struct sockaddr *)&(con->http.hostaddr),
91 &val)) < 0)
a74b005d 92 {
93 LogMessage(LOG_ERROR, "accept() failed - %s.", strerror(errno));
94 return;
95 }
96
2f6d083c 97 con->http.hostaddr.sin_port = lis->address.sin_port;
98
a74b005d 99 /*
100 * Get the hostname or format the IP address as needed...
101 */
102
103 address = ntohl(con->http.hostaddr.sin_addr.s_addr);
104
105 if (HostNameLookups)
590a0a40 106#ifndef __sgi
42d48bd2 107 host = gethostbyaddr((char *)&address, sizeof(address), AF_INET);
108#else
a74b005d 109 host = gethostbyaddr(&address, sizeof(address), AF_INET);
590a0a40 110#endif /* !__sgi */
a74b005d 111 else
112 host = NULL;
113
114 if (host == NULL)
115 sprintf(con->http.hostname, "%d.%d.%d.%d", (address >> 24) & 255,
116 (address >> 16) & 255, (address >> 8) & 255, address & 255);
117 else
118 strncpy(con->http.hostname, host->h_name, sizeof(con->http.hostname) - 1);
119
53e4c17e 120 LogMessage(LOG_DEBUG, "accept() %d from %s:%d.", con->http.fd,
2f6d083c 121 con->http.hostname, ntohs(con->http.hostaddr.sin_port));
a74b005d 122
123 /*
124 * Add the socket to the select() input mask.
125 */
126
127 fcntl(con->http.fd, F_SETFD, fcntl(con->http.fd, F_GETFD) | FD_CLOEXEC);
128
bfa1abf0 129 DEBUG_printf(("AcceptClient: Adding fd %d to InputSet...\n", con->http.fd));
a74b005d 130 FD_SET(con->http.fd, &InputSet);
131
132 NumClients ++;
133
134 /*
135 * Temporarily suspend accept()'s until we lose a client...
136 */
137
997edb40 138 if (NumClients == MaxClients)
a74b005d 139 for (i = 0; i < NumListeners; i ++)
bfa1abf0 140 {
141 DEBUG_printf(("AcceptClient: Removing fd %d from InputSet...\n", Listeners[i].fd));
a74b005d 142 FD_CLR(Listeners[i].fd, &InputSet);
bfa1abf0 143 }
a74b005d 144}
145
146
147/*
148 * 'CloseAllClients()' - Close all remote clients immediately.
149 */
150
151void
152CloseAllClients(void)
153{
154 while (NumClients > 0)
155 CloseClient(Clients);
156}
157
158
159/*
160 * 'CloseClient()' - Close a remote client.
161 */
162
163void
164CloseClient(client_t *con) /* I - Client to close */
165{
166 int i; /* Looping var */
167 int status; /* Exit status of pipe command */
168
169
53e4c17e 170 LogMessage(LOG_DEBUG, "CloseClient() %d", con->http.fd);
a74b005d 171
172 /*
173 * Close the socket and clear the file from the input set for select()...
174 */
175
882031b3 176 if (con->http.fd > 0)
177 {
178 DEBUG_printf(("CloseClient: Removing fd %d from InputSet...\n", con->http.fd));
179 close(con->http.fd);
180 FD_CLR(con->http.fd, &InputSet);
181 FD_CLR(con->http.fd, &OutputSet);
182 con->http.fd = 0;
183 }
a74b005d 184
185 for (i = 0; i < NumListeners; i ++)
bfa1abf0 186 {
187 DEBUG_printf(("CloseClient: Adding fd %d to InputSet...\n", Listeners[i].fd));
a74b005d 188 FD_SET(Listeners[i].fd, &InputSet);
bfa1abf0 189 }
a74b005d 190
a74b005d 191 if (con->pipe_pid != 0)
bfa1abf0 192 {
193 DEBUG_printf(("CloseClient: Removing fd %d from InputSet...\n", con->file));
a74b005d 194 FD_CLR(con->file, &InputSet);
bfa1abf0 195 }
196
a74b005d 197 /*
198 * If we have a data file open, close it...
199 */
200
bfa1abf0 201 if (con->file)
a74b005d 202 {
203 if (con->pipe_pid)
204 {
205 kill(con->pipe_pid, SIGKILL);
206 waitpid(con->pipe_pid, &status, WNOHANG);
207 }
208
882031b3 209 FD_CLR(con->file, &InputSet);
a74b005d 210 close(con->file);
bfa1abf0 211 con->file = 0;
a74b005d 212 }
213
214 /*
215 * Compact the list of clients as necessary...
216 */
217
218 NumClients --;
219
220 if (con < (Clients + NumClients))
221 memcpy(con, con + 1, (Clients + NumClients - con) * sizeof(client_t));
222}
223
224
225/*
226 * 'ReadClient()' - Read data from a client.
227 */
228
229int /* O - 1 on success, 0 on error */
230ReadClient(client_t *con) /* I - Client to read from */
231{
232 char line[8192], /* Line from client... */
233 operation[64], /* Operation code from socket */
234 version[64]; /* HTTP version number string */
235 int major, minor; /* HTTP version numbers */
236 http_status_t status; /* Transfer status */
bd176c9c 237 ipp_state_t ipp_state; /* State of IPP transfer */
a74b005d 238 int bytes; /* Number of bytes to POST */
e31bfb6e 239 char *filename; /* Name of file for GET/HEAD */
a74b005d 240 struct stat filestats; /* File information */
e31bfb6e 241 mime_type_t *type; /* MIME type of file */
b14d90ba 242 char command[1024], /* Command to run */
243 *options; /* Options/CGI data */
2a8fc30c 244 printer_t *p; /* Printer */
a74b005d 245
bfa1abf0 246
a74b005d 247 status = HTTP_CONTINUE;
248
249 switch (con->http.state)
250 {
251 case HTTP_WAITING :
252 /*
253 * See if we've received a request line...
254 */
255
256 if (httpGets(line, sizeof(line) - 1, HTTP(con)) == NULL)
93894a43 257 {
258 CloseClient(con);
259 return (0);
260 }
a74b005d 261
262 /*
263 * Ignore blank request lines...
264 */
265
266 if (line[0] == '\0')
267 break;
268
269 /*
270 * Clear other state variables...
271 */
272
273 httpClearFields(HTTP(con));
274
275 con->http.activity = time(NULL);
276 con->http.version = HTTP_1_0;
277 con->http.keep_alive = HTTP_KEEPALIVE_OFF;
278 con->http.data_encoding = HTTP_ENCODE_LENGTH;
279 con->http.data_remaining = 0;
6a0c519d 280 con->operation = HTTP_WAITING;
281 con->bytes = 0;
a74b005d 282 con->file = 0;
283 con->pipe_pid = 0;
284 con->username[0] = '\0';
285 con->password[0] = '\0';
286 con->uri[0] = '\0';
287
288 if (con->language != NULL)
289 {
290 cupsLangFree(con->language);
291 con->language = NULL;
292 }
293
294 /*
295 * Grab the request line...
296 */
297
970017a4 298 switch (sscanf(line, "%63s%1023s%63s", operation, con->uri, version))
a74b005d 299 {
300 case 1 :
301 SendError(con, HTTP_BAD_REQUEST);
302 CloseClient(con);
303 return (0);
304 case 2 :
305 con->http.version = HTTP_0_9;
306 break;
307 case 3 :
308 if (sscanf(version, "HTTP/%d.%d", &major, &minor) != 2)
309 {
310 SendError(con, HTTP_BAD_REQUEST);
311 CloseClient(con);
312 return (0);
313 }
314
315 if (major < 2)
316 {
317 con->http.version = (http_version_t)(major * 100 + minor);
318 if (con->http.version == HTTP_1_1)
319 con->http.keep_alive = HTTP_KEEPALIVE_ON;
320 else
321 con->http.keep_alive = HTTP_KEEPALIVE_OFF;
322 }
323 else
324 {
325 SendError(con, HTTP_NOT_SUPPORTED);
326 CloseClient(con);
327 return (0);
328 }
329 break;
330 }
331
332 /*
333 * Process the request...
334 */
335
336 if (strcmp(operation, "GET") == 0)
337 con->http.state = HTTP_GET;
338 else if (strcmp(operation, "PUT") == 0)
339 con->http.state = HTTP_PUT;
340 else if (strcmp(operation, "POST") == 0)
341 con->http.state = HTTP_POST;
342 else if (strcmp(operation, "DELETE") == 0)
343 con->http.state = HTTP_DELETE;
344 else if (strcmp(operation, "TRACE") == 0)
345 con->http.state = HTTP_TRACE;
346 else if (strcmp(operation, "CLOSE") == 0)
347 con->http.state = HTTP_CLOSE;
348 else if (strcmp(operation, "OPTIONS") == 0)
349 con->http.state = HTTP_OPTIONS;
350 else if (strcmp(operation, "HEAD") == 0)
351 con->http.state = HTTP_HEAD;
352 else
353 {
354 SendError(con, HTTP_BAD_REQUEST);
355 CloseClient(con);
356 return (0);
357 }
358
6a0c519d 359 con->start = time(NULL);
360 con->operation = con->http.state;
361
53e4c17e 362 LogMessage(LOG_DEBUG, "ReadClient() %d %s %s HTTP/%d.%d", con->http.fd,
4a64fdb7 363 operation, con->uri,
364 con->http.version / 100, con->http.version % 100);
a74b005d 365
366 con->http.status = HTTP_OK;
367 break;
368
369 case HTTP_CLOSE :
370 case HTTP_DELETE :
371 case HTTP_GET :
372 case HTTP_HEAD :
373 case HTTP_POST :
374 case HTTP_PUT :
375 case HTTP_TRACE :
376 /*
377 * Parse incoming parameters until the status changes...
378 */
379
380 status = httpUpdate(HTTP(con));
381
382 if (status != HTTP_OK && status != HTTP_CONTINUE)
383 {
384 SendError(con, HTTP_BAD_REQUEST);
385 CloseClient(con);
386 return (0);
387 }
388 break;
389 }
390
391 /*
392 * Handle new transfers...
393 */
394
395 if (status == HTTP_OK)
396 {
397 con->language = cupsLangGet(con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE]);
398
399 decode_basic_auth(con);
400
401 if (con->http.fields[HTTP_FIELD_HOST][0] == '\0' &&
402 con->http.version >= HTTP_1_0)
403 {
404 if (!SendError(con, HTTP_BAD_REQUEST))
405 {
406 CloseClient(con);
407 return (0);
408 }
409 }
bd84e0d1 410 else if (strstr(con->uri, "..") != NULL)
a74b005d 411 {
412 /*
413 * Protect against malicious users!
414 */
415
416 if (!SendError(con, HTTP_FORBIDDEN))
417 {
418 CloseClient(con);
419 return (0);
420 }
421 }
422 else if (con->uri[0] != '/')
423 {
424 /*
425 * Don't allow proxying (yet)...
426 */
427
428 if (!SendError(con, HTTP_METHOD_NOT_ALLOWED))
429 {
430 CloseClient(con);
431 return (0);
432 }
433 }
434 else if ((status = IsAuthorized(con)) != HTTP_OK)
435 {
c1918ec5 436 SendError(con, status);
437 CloseClient(con);
438 return (0);
a74b005d 439 }
440 else switch (con->http.state)
441 {
442 case HTTP_GET_SEND :
997edb40 443 if (strncmp(con->uri, "/printers/", 10) == 0 &&
f3d580b9 444 strcmp(con->uri + strlen(con->uri) - 4, ".ppd") == 0)
445 {
446 /*
2a8fc30c 447 * Send PPD file - get the real printer name since printer
448 * names are not case sensitive but filename can be...
f3d580b9 449 */
450
f969a074 451 con->uri[strlen(con->uri) - 4] = '\0'; /* Drop ".ppd" */
452
2a8fc30c 453 if ((p = FindPrinter(con->uri + 10)) != NULL)
454 sprintf(con->uri, "/ppd/%s.ppd", p->name);
455 else
456 {
457 if (!SendError(con, HTTP_NOT_FOUND))
458 {
459 CloseClient(con);
460 return (0);
461 }
462
463 break;
464 }
f3d580b9 465 }
466
bd84e0d1 467 if (strncmp(con->uri, "/admin", 6) == 0 ||
468 strncmp(con->uri, "/printers", 9) == 0 ||
b14d90ba 469 strncmp(con->uri, "/classes", 8) == 0 ||
470 strncmp(con->uri, "/jobs", 5) == 0)
a74b005d 471 {
472 /*
b14d90ba 473 * Send CGI output...
a74b005d 474 */
475
bd84e0d1 476 if (strncmp(con->uri, "/admin", 6) == 0)
b14d90ba 477 {
bd84e0d1 478 snprintf(command, sizeof(command), "%s/cgi-bin/admin.cgi", ServerBin);
479 options = con->uri + 9;
480 }
481 else if (strncmp(con->uri, "/printers", 9) == 0)
482 {
483 snprintf(command, sizeof(command), "%s/cgi-bin/printers.cgi", ServerBin);
b14d90ba 484 options = con->uri + 9;
485 }
486 else if (strncmp(con->uri, "/classes", 8) == 0)
487 {
bd84e0d1 488 snprintf(command, sizeof(command), "%s/cgi-bin/classes.cgi", ServerBin);
b14d90ba 489 options = con->uri + 8;
490 }
491 else
492 {
bd84e0d1 493 snprintf(command, sizeof(command), "%s/cgi-bin/jobs.cgi", ServerBin);
b14d90ba 494 options = con->uri + 5;
495 }
496
497 if (*options == '/')
498 options ++;
499
500 if (!SendCommand(con, command, options))
a74b005d 501 {
502 if (!SendError(con, HTTP_NOT_FOUND))
503 {
504 CloseClient(con);
505 return (0);
506 }
507 }
6a0c519d 508 else
509 LogRequest(con, HTTP_OK);
a74b005d 510
b14d90ba 511 if (con->http.version <= HTTP_1_0)
a74b005d 512 con->http.keep_alive = HTTP_KEEPALIVE_OFF;
513 }
514 else
515 {
516 /*
517 * Serve a file...
518 */
519
520 if ((filename = get_file(con, &filestats)) == NULL)
521 {
522 if (!SendError(con, HTTP_NOT_FOUND))
523 {
524 CloseClient(con);
525 return (0);
526 }
527 }
528 else if (!check_if_modified(con, &filestats))
529 {
530 if (!SendError(con, HTTP_NOT_MODIFIED))
531 {
532 CloseClient(con);
533 return (0);
534 }
535 }
536 else
537 {
e31bfb6e 538 type = mimeFileType(MimeDatabase, filename);
539 if (type == NULL)
540 strcpy(line, "text/plain");
541 else
542 sprintf(line, "%s/%s", type->super, type->type);
a74b005d 543
e31bfb6e 544 if (!SendFile(con, HTTP_OK, filename, line, &filestats))
a74b005d 545 {
546 CloseClient(con);
547 return (0);
548 }
549 }
550 }
551 break;
552
553 case HTTP_POST_RECV :
8b43895a 554 /*
555 * See if the POST request includes a Content-Length field, and if
556 * so check the length against any limits that are set...
557 */
558
559 if (con->http.fields[HTTP_FIELD_CONTENT_LENGTH][0] &&
560 atoi(con->http.fields[HTTP_FIELD_CONTENT_LENGTH]) > MaxRequestSize &&
561 MaxRequestSize > 0)
562 {
563 /*
564 * Request too large...
565 */
566
567 if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
568 {
569 CloseClient(con);
570 return (0);
571 }
572
573 break;
574 }
575
b14d90ba 576 /*
577 * See what kind of POST request this is; for IPP requests the
578 * content-type field will be "application/ipp"...
579 */
580
93894a43 581 if (strcmp(con->http.fields[HTTP_FIELD_CONTENT_TYPE], "application/ipp") == 0)
b14d90ba 582 con->request = ippNew();
f3d580b9 583 else if (strcmp(con->http.fields[HTTP_FIELD_CONTENT_TYPE], "application/x-www-form-urlencoded") == 0 &&
bd84e0d1 584 (strncmp(con->uri, "/admin", 6) == 0 ||
585 strncmp(con->uri, "/printers", 9) == 0 ||
b14d90ba 586 strncmp(con->uri, "/classes", 8) == 0 ||
587 strncmp(con->uri, "/jobs", 5) == 0))
a74b005d 588 {
b14d90ba 589 /*
590 * CGI request...
591 */
592
bd84e0d1 593 if (strncmp(con->uri, "/admin", 9) == 0)
594 {
595 snprintf(command, sizeof(command), "%s/cgi-bin/admin.cgi", ServerBin);
596 options = con->uri + 9;
597 }
598 else if (strncmp(con->uri, "/printers", 9) == 0)
a74b005d 599 {
bd84e0d1 600 snprintf(command, sizeof(command), "%s/cgi-bin/printers.cgi", ServerBin);
b14d90ba 601 options = con->uri + 9;
602 }
603 else if (strncmp(con->uri, "/classes", 8) == 0)
604 {
bd84e0d1 605 snprintf(command, sizeof(command), "%s/cgi-bin/classes.cgi", ServerBin);
b14d90ba 606 options = con->uri + 8;
607 }
608 else
609 {
bd84e0d1 610 snprintf(command, sizeof(command), "%s/cgi-bin/jobs.cgi", ServerBin);
b14d90ba 611 options = con->uri + 5;
a74b005d 612 }
b14d90ba 613
614 if (*options == '/')
615 options ++;
616
617 if (!SendCommand(con, command, options))
618 {
619 if (!SendError(con, HTTP_NOT_FOUND))
620 {
621 CloseClient(con);
622 return (0);
623 }
624 }
625 else
626 LogRequest(con, HTTP_OK);
627
628 if (con->http.version <= HTTP_1_0)
629 con->http.keep_alive = HTTP_KEEPALIVE_OFF;
630 }
631 else if (!SendError(con, HTTP_UNAUTHORIZED))
632 {
633 CloseClient(con);
634 return (0);
a74b005d 635 }
636 break;
637
638 case HTTP_PUT_RECV :
639 case HTTP_DELETE :
640 case HTTP_TRACE :
641 SendError(con, HTTP_NOT_IMPLEMENTED);
642
643 case HTTP_CLOSE :
644 CloseClient(con);
645 return (0);
646
647 case HTTP_HEAD :
f3d580b9 648 if (strncmp(con->uri, "/printers", 9) == 0 &&
649 strcmp(con->uri + strlen(con->uri) - 4, ".ppd") == 0)
650 {
651 /*
652 * Send PPD file...
653 */
654
970017a4 655 snprintf(command, sizeof(command), "/ppd/%s", con->uri + 10);
f3d580b9 656 strcpy(con->uri, command);
657 }
658
bd84e0d1 659 if (strncmp(con->uri, "/admin/", 7) == 0 ||
660 strncmp(con->uri, "/printers/", 10) == 0 ||
b14d90ba 661 strncmp(con->uri, "/classes/", 9) == 0 ||
662 strncmp(con->uri, "/jobs/", 6) == 0)
a74b005d 663 {
664 /*
b14d90ba 665 * CGI output...
a74b005d 666 */
667
668 if (!SendHeader(con, HTTP_OK, "text/html"))
669 {
670 CloseClient(con);
671 return (0);
672 }
673
674 if (httpPrintf(HTTP(con), "\r\n") < 0)
675 {
676 CloseClient(con);
677 return (0);
678 }
6a0c519d 679
680 LogRequest(con, HTTP_OK);
a74b005d 681 }
682 else if ((filename = get_file(con, &filestats)) == NULL)
683 {
684 if (!SendHeader(con, HTTP_NOT_FOUND, "text/html"))
685 {
686 CloseClient(con);
687 return (0);
688 }
6a0c519d 689
690 LogRequest(con, HTTP_NOT_FOUND);
a74b005d 691 }
692 else if (!check_if_modified(con, &filestats))
693 {
694 if (!SendError(con, HTTP_NOT_MODIFIED))
695 {
696 CloseClient(con);
697 return (0);
698 }
6a0c519d 699
700 LogRequest(con, HTTP_NOT_MODIFIED);
a74b005d 701 }
702 else
703 {
704 /*
705 * Serve a file...
706 */
707
e31bfb6e 708 type = mimeFileType(MimeDatabase, filename);
709 if (type == NULL)
710 strcpy(line, "text/plain");
711 else
712 sprintf(line, "%s/%s", type->super, type->type);
a74b005d 713
e31bfb6e 714 if (!SendHeader(con, HTTP_OK, line))
a74b005d 715 {
716 CloseClient(con);
717 return (0);
718 }
719
720 if (httpPrintf(HTTP(con), "Last-Modified: %s\r\n",
721 httpGetDateString(filestats.st_mtime)) < 0)
722 {
723 CloseClient(con);
724 return (0);
725 }
726
727 if (httpPrintf(HTTP(con), "Content-Length: %d\r\n",
728 filestats.st_size) < 0)
729 {
730 CloseClient(con);
731 return (0);
732 }
6a0c519d 733
734 LogRequest(con, HTTP_OK);
a74b005d 735 }
736
97d73ddb 737 if (httpPrintf(HTTP(con), "\r\n") < 0)
a74b005d 738 {
739 CloseClient(con);
740 return (0);
741 }
742
743 con->http.state = HTTP_WAITING;
744 break;
745 }
746 }
747
748 /*
749 * Handle any incoming data...
750 */
751
752 switch (con->http.state)
753 {
754 case HTTP_PUT_RECV :
755 break;
756
757 case HTTP_POST_RECV :
bfa1abf0 758 LogMessage(LOG_DEBUG, "ReadClient() %d con->data_encoding = %s con->data_remaining = %d",
93894a43 759 con->http.fd,
a74b005d 760 con->http.data_encoding == HTTP_ENCODE_CHUNKED ? "chunked" : "length",
761 con->http.data_remaining);
bfa1abf0 762 DEBUG_printf(("ReadClient() %d con->data_encoding = %s con->data_remaining = %d\n",
763 con->http.fd,
764 con->http.data_encoding == HTTP_ENCODE_CHUNKED ? "chunked" : "length",
765 con->http.data_remaining));
a74b005d 766
b14d90ba 767 if (con->request != NULL)
768 {
769 /*
770 * Grab any request data from the connection...
771 */
772
bd176c9c 773 if ((ipp_state = ippRead(&(con->http), con->request)) == IPP_ERROR)
774 {
775 LogMessage(LOG_ERROR, "ReadClient() %d IPP Read Error!",
776 con->http.fd);
777 CloseClient(con);
778 return (0);
779 }
780 else if (ipp_state != IPP_DATA)
b14d90ba 781 break;
782
bfa1abf0 783 if (con->file == 0 && con->http.state != HTTP_POST_SEND)
b14d90ba 784 {
1d2c70a6 785 /*
786 * Create a file as needed for the request data...
787 */
788
bd84e0d1 789 snprintf(con->filename, sizeof(con->filename), "%s/XXXXXX", RequestRoot);
b14d90ba 790 con->file = mkstemp(con->filename);
3b41df31 791 fchmod(con->file, 0640);
2f511d19 792 fchown(con->file, User, Group);
b14d90ba 793
53e4c17e 794 LogMessage(LOG_DEBUG, "ReadClient() %d REQUEST %s", con->http.fd,
b14d90ba 795 con->filename);
796
797 if (con->file < 0)
798 {
799 if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
800 {
801 CloseClient(con);
802 return (0);
803 }
804 }
805 }
806 }
807
bfa1abf0 808 if (con->http.state != HTTP_POST_SEND)
a74b005d 809 {
bfa1abf0 810 if ((bytes = httpRead(HTTP(con), line, sizeof(line))) < 0)
a74b005d 811 {
bfa1abf0 812 CloseClient(con);
813 return (0);
814 }
815 else if (bytes > 0)
816 {
817 con->bytes += bytes;
a74b005d 818
997edb40 819 if (bytes >= 1024)
820 LogMessage(LOG_DEBUG, "ReadClient() %d writing %d bytes", bytes);
bfa1abf0 821
822 if (write(con->file, line, bytes) < bytes)
a74b005d 823 {
bfa1abf0 824 close(con->file);
825 con->file = 0;
826 unlink(con->filename);
827
828 if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
829 {
830 CloseClient(con);
831 return (0);
832 }
a74b005d 833 }
834 }
bd176c9c 835 else if (con->http.state != HTTP_POST_SEND)
836 {
837 CloseClient(con);
838 return (0);
839 }
a74b005d 840 }
93894a43 841
842 if (con->http.state == HTTP_POST_SEND)
843 {
bfa1abf0 844 if (con->file)
845 {
8b43895a 846 fstat(con->file, &filestats);
bfa1abf0 847 close(con->file);
848 con->file = 0;
8b43895a 849
850 if (filestats.st_size > MaxRequestSize &&
851 MaxRequestSize > 0)
852 {
853 /*
854 * Request is too big; remove it and send an error...
855 */
856
857 unlink(con->filename);
858
859 if (con->request)
860 {
861 /*
862 * Delete any IPP request data...
863 */
864
865 ippDelete(con->request);
866 con->request = NULL;
867 }
868
869 if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
870 {
871 CloseClient(con);
872 return (0);
873 }
874 }
bfa1abf0 875 }
93894a43 876
877 if (con->request)
e31bfb6e 878 ProcessIPPRequest(con);
93894a43 879 }
a74b005d 880 break;
881 }
882
883 if (!con->http.keep_alive && con->http.state == HTTP_WAITING)
884 {
885 CloseClient(con);
886 return (0);
887 }
888 else
889 return (1);
890}
891
892
a74b005d 893/*
894 * 'SendCommand()' - Send output from a command via HTTP.
895 */
896
897int
898SendCommand(client_t *con,
a74b005d 899 char *command,
b14d90ba 900 char *options)
a74b005d 901{
b14d90ba 902 con->pipe_pid = pipe_command(con, 0, &(con->file), command, options);
a74b005d 903
904 LogMessage(LOG_DEBUG, "SendCommand() %d command=\"%s\" file=%d pipe_pid=%d",
905 con->http.fd, command, con->file, con->pipe_pid);
906
907 if (con->pipe_pid == 0)
908 return (0);
909
910 fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
911
bfa1abf0 912 DEBUG_printf(("SendCommand: Adding fd %d to InputSet...\n", con->file));
a74b005d 913 FD_SET(con->file, &InputSet);
914 FD_SET(con->http.fd, &OutputSet);
915
96df88bb 916 if (!SendHeader(con, HTTP_OK, NULL))
a74b005d 917 return (0);
918
919 if (con->http.version == HTTP_1_1)
920 {
921 con->http.data_encoding = HTTP_ENCODE_CHUNKED;
922
923 if (httpPrintf(HTTP(con), "Transfer-Encoding: chunked\r\n") < 0)
924 return (0);
925 }
926
a74b005d 927 return (1);
928}
929
930
931/*
932 * 'SendError()' - Send an error message via HTTP.
933 */
934
935int /* O - 1 if successful, 0 otherwise */
936SendError(client_t *con, /* I - Connection */
937 http_status_t code) /* I - Error code */
938{
97d73ddb 939 char message[1024]; /* Message for user */
a74b005d 940
941
6a0c519d 942 /*
943 * Put the request in the access_log file...
944 */
945
993e15da 946 if (con->operation > HTTP_WAITING)
947 LogRequest(con, code);
6a0c519d 948
a74b005d 949 /*
950 * To work around bugs in some proxies, don't use Keep-Alive for some
951 * error messages...
952 */
953
954 if (code >= HTTP_BAD_REQUEST)
955 con->http.keep_alive = HTTP_KEEPALIVE_OFF;
956
957 /*
958 * Send an error message back to the client. If the error code is a
959 * 400 or 500 series, make sure the message contains some text, too!
960 */
961
962 if (!SendHeader(con, code, NULL))
963 return (0);
964
965 if (code == HTTP_UNAUTHORIZED)
966 {
967 if (httpPrintf(HTTP(con), "WWW-Authenticate: Basic realm=\"CUPS\"\r\n") < 0)
968 return (0);
969 }
970
971 if (con->http.version >= HTTP_1_1 && !con->http.keep_alive)
972 {
973 if (httpPrintf(HTTP(con), "Connection: close\r\n") < 0)
974 return (0);
975 }
976
977 if (code >= HTTP_BAD_REQUEST)
978 {
979 /*
980 * Send a human-readable error message.
981 */
982
970017a4 983 snprintf(message, sizeof(message),
984 "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>"
985 "<BODY><H1>%s</H1>%s</BODY></HTML>\n",
986 code, httpStatus(code), httpStatus(code),
987 con->language ? con->language->messages[code] :
988 httpStatus(code));
a74b005d 989
990 if (httpPrintf(HTTP(con), "Content-Type: text/html\r\n") < 0)
991 return (0);
992 if (httpPrintf(HTTP(con), "Content-Length: %d\r\n", strlen(message)) < 0)
993 return (0);
994 if (httpPrintf(HTTP(con), "\r\n") < 0)
995 return (0);
97d73ddb 996 if (httpPrintf(HTTP(con), "%s", message) < 0)
a74b005d 997 return (0);
998 }
999 else if (httpPrintf(HTTP(con), "\r\n") < 0)
1000 return (0);
1001
1002 con->http.state = HTTP_WAITING;
1003
1004 return (1);
1005}
1006
1007
1008/*
1009 * 'SendFile()' - Send a file via HTTP.
1010 */
1011
1012int
1013SendFile(client_t *con,
1014 http_status_t code,
1015 char *filename,
1016 char *type,
1017 struct stat *filestats)
1018{
1019 con->file = open(filename, O_RDONLY);
1020
1021 LogMessage(LOG_DEBUG, "SendFile() %d file=%d", con->http.fd, con->file);
1022
1023 if (con->file < 0)
1024 return (0);
1025
1026 fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
1027
1028 con->pipe_pid = 0;
1029
1030 if (!SendHeader(con, code, type))
1031 return (0);
1032
1033 if (httpPrintf(HTTP(con), "Last-Modified: %s\r\n", httpGetDateString(filestats->st_mtime)) < 0)
1034 return (0);
1035 if (httpPrintf(HTTP(con), "Content-Length: %d\r\n", filestats->st_size) < 0)
1036 return (0);
1037 if (httpPrintf(HTTP(con), "\r\n") < 0)
1038 return (0);
1039
1040 FD_SET(con->http.fd, &OutputSet);
1041
1042 return (1);
1043}
1044
1045
1046/*
93894a43 1047 * 'SendHeader()' - Send an HTTP request.
a74b005d 1048 */
1049
1050int /* O - 1 on success, 0 on failure */
1051SendHeader(client_t *con, /* I - Client to send to */
1052 http_status_t code, /* I - HTTP status code */
1053 char *type) /* I - MIME type of document */
1054{
1055 if (httpPrintf(HTTP(con), "HTTP/%d.%d %d %s\r\n", con->http.version / 100,
1056 con->http.version % 100, code, httpStatus(code)) < 0)
1057 return (0);
1058 if (httpPrintf(HTTP(con), "Date: %s\r\n", httpGetDateString(time(NULL))) < 0)
1059 return (0);
bd84e0d1 1060 if (httpPrintf(HTTP(con), "Server: CUPS/1.1\r\n") < 0)
a74b005d 1061 return (0);
1062 if (con->http.keep_alive && con->http.version >= HTTP_1_0)
1063 {
1064 if (httpPrintf(HTTP(con), "Connection: Keep-Alive\r\n") < 0)
1065 return (0);
1066 if (httpPrintf(HTTP(con), "Keep-Alive: timeout=%d\r\n", KeepAliveTimeout) < 0)
1067 return (0);
1068 }
1069 if (con->language != NULL)
1070 {
1071 if (httpPrintf(HTTP(con), "Content-Language: %s\r\n",
1072 con->language->language) < 0)
1073 return (0);
1074
1075 if (type != NULL)
1076 if (httpPrintf(HTTP(con), "Content-Type: %s; charset=%s\r\n", type,
1077 cupsLangEncoding(con->language)) < 0)
1078 return (0);
1079 }
1080 else if (type != NULL)
1081 if (httpPrintf(HTTP(con), "Content-Type: %s\r\n", type) < 0)
1082 return (0);
1083
1084 return (1);
1085}
1086
1087
a74b005d 1088/*
1089 * 'WriteClient()' - Write data to a client as needed.
1090 */
1091
ff49100f 1092int /* O - 1 if success, 0 if fail */
1093WriteClient(client_t *con) /* I - Client connection */
a74b005d 1094{
ff49100f 1095 int bytes; /* Number of bytes written */
1096 char buf[HTTP_MAX_BUFFER]; /* Data buffer */
1097 ipp_state_t ipp_state; /* IPP state value */
a74b005d 1098
1099
1100 if (con->http.state != HTTP_GET_SEND &&
1101 con->http.state != HTTP_POST_SEND)
1102 return (1);
1103
ff49100f 1104 if (con->response != NULL)
bfa1abf0 1105 {
ff49100f 1106 ipp_state = ippWrite(&(con->http), con->response);
1107 bytes = ipp_state != IPP_ERROR && ipp_state != IPP_DATA;
bfa1abf0 1108 }
b14d90ba 1109 else if ((bytes = read(con->file, buf, sizeof(buf))) > 0)
a74b005d 1110 {
1111 if (httpWrite(HTTP(con), buf, bytes) < 0)
1112 {
1113 CloseClient(con);
1114 return (0);
1115 }
6a0c519d 1116
1117 con->bytes += bytes;
a74b005d 1118 }
b14d90ba 1119
1120 if (bytes <= 0)
a74b005d 1121 {
6a0c519d 1122 LogRequest(con, HTTP_OK);
1123
a74b005d 1124 if (con->http.data_encoding == HTTP_ENCODE_CHUNKED)
1125 {
1126 if (httpPrintf(HTTP(con), "0\r\n\r\n") < 0)
1127 {
1128 CloseClient(con);
1129 return (0);
1130 }
1131 }
1132
96df88bb 1133 con->http.state = HTTP_WAITING;
1134
a74b005d 1135 FD_CLR(con->http.fd, &OutputSet);
a74b005d 1136
bfa1abf0 1137 if (con->file)
a74b005d 1138 {
bfa1abf0 1139 DEBUG_printf(("WriteClient: Removing fd %d from InputSet...\n", con->file));
1140 FD_CLR(con->file, &InputSet);
a74b005d 1141
bfa1abf0 1142 if (con->pipe_pid)
96df88bb 1143 kill(con->pipe_pid, SIGTERM);
bfa1abf0 1144
1145 close(con->file);
96df88bb 1146 con->file = 0;
1147 con->pipe_pid = 0;
bfa1abf0 1148 }
a74b005d 1149
b14d90ba 1150 if (con->request != NULL)
1151 {
1152 ippDelete(con->request);
1153 con->request = NULL;
1154 }
1155
1156 if (con->response != NULL)
1157 {
1158 ippDelete(con->response);
1159 con->response = NULL;
1160 }
96df88bb 1161
1162 if (!con->http.keep_alive)
1163 {
1164 CloseClient(con);
1165 return (0);
1166 }
a74b005d 1167 }
1168
997edb40 1169 if (bytes >= 1024)
1170 LogMessage(LOG_DEBUG, "WriteClient() %d %d bytes", con->http.fd, bytes);
a74b005d 1171
1172 con->http.activity = time(NULL);
1173
1174 return (1);
1175}
1176
1177
a74b005d 1178/*
1179 * 'check_if_modified()' - Decode an "If-Modified-Since" line.
1180 */
1181
1182static int /* O - 1 if modified since */
1183check_if_modified(client_t *con, /* I - Client connection */
1184 struct stat *filestats) /* I - File information */
1185{
1186 char *ptr; /* Pointer into field */
1187 time_t date; /* Time/date value */
1188 int size; /* Size/length value */
1189
1190
1191 size = 0;
1192 date = 0;
1193 ptr = con->http.fields[HTTP_FIELD_IF_MODIFIED_SINCE];
1194
1195 if (*ptr == '\0')
1196 return (1);
1197
4a64fdb7 1198 LogMessage(LOG_DEBUG, "check_if_modified() %d If-Modified-Since=\"%s\"",
1199 con->http.fd, ptr);
1200
a74b005d 1201 while (*ptr != '\0')
1202 {
4a64fdb7 1203 while (isspace(*ptr) || *ptr == ';')
a74b005d 1204 ptr ++;
1205
1206 if (strncasecmp(ptr, "length=", 7) == 0)
1207 {
1208 ptr += 7;
1209 size = atoi(ptr);
1210
1211 while (isdigit(*ptr))
1212 ptr ++;
1213 }
4a64fdb7 1214 else if (isalpha(*ptr))
a74b005d 1215 {
1216 date = httpGetDateTime(ptr);
4a64fdb7 1217 while (*ptr != '\0' && *ptr != ';')
a74b005d 1218 ptr ++;
1219 }
1220 }
1221
4a64fdb7 1222 LogMessage(LOG_DEBUG, "check_if_modified() %d sizes=%d,%d dates=%d,%d",
1223 con->http.fd, size, filestats->st_size, date, filestats->st_mtime);
1224
a74b005d 1225 return ((size != filestats->st_size && size != 0) ||
4a64fdb7 1226 (date < filestats->st_mtime && date != 0) ||
1227 (size == 0 && date == 0));
a74b005d 1228}
1229
1230
1231/*
93894a43 1232 * 'decode_basic_auth()' - Decode a Basic authorization string.
a74b005d 1233 */
1234
93894a43 1235static void
1236decode_basic_auth(client_t *con) /* I - Client to decode to */
a74b005d 1237{
f3d580b9 1238 char *s, /* Authorization string */
1239 value[1024]; /* Value string */
a74b005d 1240
a74b005d 1241
1242 /*
b0d58d07 1243 * Decode the string...
a74b005d 1244 */
1245
f3d580b9 1246 s = con->http.fields[HTTP_FIELD_AUTHORIZATION];
1247 if (strncmp(s, "Basic", 5) != 0)
1248 return;
1249
1250 s += 5;
1251 while (isspace(*s))
1252 s ++;
1253
1254 httpDecode64(value, s);
a74b005d 1255
b0d58d07 1256 /*
1257 * Pull the username and password out...
1258 */
1259
1260 if ((s = strchr(value, ':')) == NULL)
1261 {
1262 LogMessage(LOG_DEBUG, "decode_basic_auth() %d no colon in auth string \"%s\"",
1263 con->http.fd, value);
1264 return;
1265 }
1266
1267 *s++ = '\0';
1268
1269 strncpy(con->username, value, sizeof(con->username) - 1);
1270 con->username[sizeof(con->username) - 1] = '\0';
1271
1272 strncpy(con->password, s, sizeof(con->password) - 1);
1273 con->password[sizeof(con->password) - 1] = '\0';
41637133 1274
1275 LogMessage(LOG_DEBUG, "decode_basic_auth() %d username=\"%s\"",
1276 con->http.fd, con->username);
a74b005d 1277}
1278
1279
e31bfb6e 1280/*
1281 * 'get_file()' - Get a filename and state info.
1282 */
1283
1284static char * /* O - Real filename */
1285get_file(client_t *con, /* I - Client connection */
1286 struct stat *filestats)/* O - File information */
1287{
1288 int status; /* Status of filesystem calls */
1289 char *params; /* Pointer to parameters in URI */
1290 static char filename[1024]; /* Filename buffer */
1291
1292
1293 /*
1294 * Need to add DocumentRoot global...
1295 */
1296
f3d580b9 1297 if (strncmp(con->uri, "/ppd/", 5) == 0)
970017a4 1298 snprintf(filename, sizeof(filename), "%s%s", ServerRoot, con->uri);
f3d580b9 1299 else if (con->language != NULL)
970017a4 1300 snprintf(filename, sizeof(filename), "%s/%s%s", DocumentRoot, con->language->language,
e31bfb6e 1301 con->uri);
1302 else
970017a4 1303 snprintf(filename, sizeof(filename), "%s%s", DocumentRoot, con->uri);
e31bfb6e 1304
1305 if ((params = strchr(filename, '?')) != NULL)
1306 *params = '\0';
1307
1308 /*
1309 * Grab the status for this language; if there isn't a language-specific file
1310 * then fallback to the default one...
1311 */
1312
1313 if ((status = stat(filename, filestats)) != 0 && con->language != NULL)
1314 {
1315 /*
1316 * Drop the language prefix and try the current directory...
1317 */
1318
f3d580b9 1319 if (strncmp(con->uri, "/ppd/", 5) != 0)
1320 {
970017a4 1321 snprintf(filename, sizeof(filename), "%s%s", DocumentRoot, con->uri);
e31bfb6e 1322
f3d580b9 1323 status = stat(filename, filestats);
1324 }
e31bfb6e 1325 }
1326
1327 /*
1328 * If we're found a directory, get the index.html file instead...
1329 */
1330
1331 if (!status && S_ISDIR(filestats->st_mode))
1332 {
1333 if (filename[strlen(filename) - 1] == '/')
1334 strcat(filename, "index.html");
1335 else
1336 strcat(filename, "/index.html");
1337
1338 status = stat(filename, filestats);
1339 }
1340
997edb40 1341 LogMessage(LOG_DEBUG, "get_file() %d filename=%s size=%d",
1342 con->http.fd, filename, status ? -1 : filestats->st_size);
e31bfb6e 1343
1344 if (status)
1345 return (NULL);
1346 else
1347 return (filename);
1348}
1349
1350
a74b005d 1351/*
1352 * 'pipe_command()' - Pipe the output of a command to the remote client.
1353 */
1354
1355static int /* O - Process ID */
b14d90ba 1356pipe_command(client_t *con, /* I - Client connection */
1357 int infile, /* I - Standard input for command */
1358 int *outfile, /* O - Standard output for command */
1359 char *command, /* I - Command to run */
1360 char *options) /* I - Options for command */
a74b005d 1361{
1362 int pid; /* Process ID */
1363 char *commptr; /* Command string pointer */
1364 int fds[2]; /* Pipe FDs */
1365 int argc; /* Number of arguments */
1366 char argbuf[1024], /* Argument buffer */
b14d90ba 1367 *argv[100], /* Argument strings */
1368 *envp[100]; /* Environment variables */
96df88bb 1369 char hostname[1024]; /* Hostname string */
b14d90ba 1370 static char lang[1024]; /* LANG env variable */
1371 static char content_length[1024]; /* CONTENT_LENGTH env variable */
1372 static char content_type[1024]; /* CONTENT_TYPE env variable */
57c77867 1373 static char ipp_port[1024]; /* Default listen port */
b14d90ba 1374 static char server_port[1024]; /* Default listen port */
96df88bb 1375 static char server_name[1024]; /* Default listen hostname */
b14d90ba 1376 static char remote_host[1024]; /* REMOTE_HOST env variable */
1377 static char remote_user[1024]; /* REMOTE_HOST env variable */
7f0679f5 1378 static char tmpdir[1024]; /* TMPDIR env variable */
a74b005d 1379
05e63c18 1380
a74b005d 1381 /*
1382 * Copy the command string...
1383 */
1384
b14d90ba 1385 strncpy(argbuf, options, sizeof(argbuf) - 1);
a74b005d 1386 argbuf[sizeof(argbuf) - 1] = '\0';
1387
1388 /*
1389 * Parse the string; arguments can be separated by spaces or by ? or +...
1390 */
1391
1392 argv[0] = argbuf;
1393
bfa1abf0 1394 for (commptr = argbuf, argc = 1; *commptr != '\0' && argc < 99; commptr ++)
a74b005d 1395 if (*commptr == ' ' || *commptr == '?' || *commptr == '+')
1396 {
1397 *commptr++ = '\0';
1398
1399 while (*commptr == ' ')
1400 commptr ++;
1401
1402 if (*commptr != '\0')
1403 {
1404 argv[argc] = commptr;
1405 argc ++;
1406 }
1407
1408 commptr --;
1409 }
1410 else if (*commptr == '%')
1411 {
1412 if (commptr[1] >= '0' && commptr[1] <= '9')
1413 *commptr = (commptr[1] - '0') << 4;
1414 else
1415 *commptr = (tolower(commptr[1]) - 'a' + 10) << 4;
1416
1417 if (commptr[2] >= '0' && commptr[2] <= '9')
1418 *commptr |= commptr[2] - '0';
1419 else
1420 *commptr |= tolower(commptr[2]) - 'a' + 10;
1421
1422 strcpy(commptr + 1, commptr + 3);
1423 }
1424
1425 argv[argc] = NULL;
1426
bfa1abf0 1427 if (argv[0][0] == '\0')
1428 argv[0] = strrchr(command, '/') + 1;
b14d90ba 1429
1430 /*
1431 * Setup the environment variables as needed...
1432 */
1433
96df88bb 1434 gethostname(hostname, sizeof(hostname) - 1);
1435
b14d90ba 1436 sprintf(lang, "LANG=%s", con->language ? con->language->language : "C");
57c77867 1437 sprintf(ipp_port, "IPP_PORT=%d", ntohs(con->http.hostaddr.sin_port));
b14d90ba 1438 sprintf(server_port, "SERVER_PORT=%d", ntohs(con->http.hostaddr.sin_port));
96df88bb 1439 sprintf(server_name, "SERVER_NAME=%s", hostname);
b14d90ba 1440 sprintf(remote_host, "REMOTE_HOST=%s", con->http.hostname);
1441 sprintf(remote_user, "REMOTE_USER=%s", con->username);
7f0679f5 1442 sprintf(tmpdir, "TMPDIR=%s", TempDir);
1443
1444 envp[0] = "PATH=/bin:/usr/bin";
bd84e0d1 1445 envp[1] = "SERVER_SOFTWARE=CUPS/1.1";
7f0679f5 1446 envp[2] = "GATEWAY_INTERFACE=CGI/1.1";
1447 envp[3] = "SERVER_PROTOCOL=HTTP/1.1";
57c77867 1448 envp[4] = ipp_port;
1449 envp[5] = server_name;
1450 envp[6] = server_port;
1451 envp[7] = remote_host;
1452 envp[8] = remote_user;
1453 envp[9] = lang;
05e63c18 1454 envp[10] = TZ;
57c77867 1455 envp[11] = tmpdir;
b14d90ba 1456
1457 if (con->operation == HTTP_GET)
1458 {
57c77867 1459 envp[12] = "REQUEST_METHOD=GET";
1460 envp[13] = NULL;
b14d90ba 1461 }
1462 else
1463 {
1464 sprintf(content_length, "CONTENT_LENGTH=%d", con->http.data_remaining);
970017a4 1465 snprintf(content_type, sizeof(content_type), "CONTENT_TYPE=%s",
1466 con->http.fields[HTTP_FIELD_CONTENT_TYPE]);
b14d90ba 1467
57c77867 1468 envp[12] = "REQUEST_METHOD=POST";
1469 envp[13] = content_length;
1470 envp[14] = content_type;
1471 envp[15] = NULL;
b14d90ba 1472 }
1473
a74b005d 1474 /*
1475 * Create a pipe for the output...
1476 */
1477
1478 if (pipe(fds))
1d6c68fb 1479 {
1480 LogMessage(LOG_ERROR, "Unable to create pipes for CGI %s - %s",
1481 argv[0], strerror(errno));
a74b005d 1482 return (0);
1d6c68fb 1483 }
a74b005d 1484
1485 /*
1d6c68fb 1486 * Then execute the command...
a74b005d 1487 */
1488
1489 if ((pid = fork()) == 0)
1490 {
1491 /*
1492 * Child comes here... Close stdin if necessary and dup the pipe to stdout.
1493 */
1494
b14d90ba 1495 setgid(Group);
d8a6bdd8 1496 setuid(User);
b14d90ba 1497
a74b005d 1498 if (infile)
1499 {
1500 close(0);
1501 dup(infile);
1502 }
1503
1504 close(1);
1505 dup(fds[1]);
1506
1507 close(fds[0]);
1508 close(fds[1]);
1509
1510 /*
1511 * Execute the pipe program; if an error occurs, exit with status 1...
1512 */
1513
b14d90ba 1514 execve(command, argv, envp);
96df88bb 1515 perror("execve failed");
1516 exit(errno);
a74b005d 1517 return (0);
1518 }
1519 else if (pid < 0)
1520 {
1521 /*
1522 * Error - can't fork!
1523 */
1524
1d6c68fb 1525 LogMessage(LOG_ERROR, "Unable to fork for CGI %s - %s", argv[0],
1526 strerror(errno));
1527
a74b005d 1528 close(fds[0]);
1529 close(fds[1]);
1530 return (0);
1531 }
1532 else
1533 {
1534 /*
1535 * Fork successful - return the PID...
1536 */
1537
7e03f42a 1538 LogMessage(LOG_DEBUG, "CGI %s started - PID = %d", argv[0], pid);
1d6c68fb 1539
a74b005d 1540 *outfile = fds[0];
1541 close(fds[1]);
1542
1543 return (pid);
1544 }
1545}
1546
1547
93894a43 1548/*
bd84e0d1 1549 * End of "$Id: client.c,v 1.41 1999/12/29 02:15:40 mike Exp $".
a74b005d 1550 */