]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/client.c
1da5837b208e5b8f787775aa5df596c2984513d9
[thirdparty/cups.git] / scheduler / client.c
1 /*
2 * "$Id: client.c,v 1.91.2.32 2003/01/13 18:41:42 mike Exp $"
3 *
4 * Client routines for the Common UNIX Printing System (CUPS) scheduler.
5 *
6 * Copyright 1997-2003 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
17 * 44141 Airport View Drive, Suite 204
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 *
26 * AcceptClient() - Accept a new client.
27 * CloseAllClients() - Close all remote clients immediately.
28 * CloseClient() - Close a remote client.
29 * EncryptClient() - Enable encryption for the client...
30 * ReadClient() - Read data from a client.
31 * SendCommand() - Send output from a command via HTTP.
32 * SendError() - Send an error message via HTTP.
33 * SendFile() - Send a file via HTTP.
34 * SendHeader() - Send an HTTP request.
35 * ShutdownClient() - Shutdown the receiving end of a connection.
36 * WriteClient() - Write data to a client as needed.
37 * check_if_modified() - Decode an "If-Modified-Since" line.
38 * decode_auth() - Decode an authorization string.
39 * get_file() - Get a filename and state info.
40 * install_conf_file() - Install a configuration file.
41 * pipe_command() - Pipe the output of a command to the remote client.
42 */
43
44 /*
45 * Include necessary headers...
46 */
47
48 #include "cupsd.h"
49
50 #include <grp.h>
51
52 #ifdef HAVE_LIBSSL
53 # include <openssl/err.h>
54 # include <openssl/ssl.h>
55 # include <openssl/rand.h>
56 #endif /* HAVE_LIBSSL */
57
58
59 /*
60 * Local functions...
61 */
62
63 static int check_if_modified(client_t *con,
64 struct stat *filestats);
65 static void decode_auth(client_t *con);
66 static char *get_file(client_t *con, struct stat *filestats);
67 static http_status_t install_conf_file(client_t *con);
68 static int pipe_command(client_t *con, int infile, int *outfile,
69 char *command, char *options);
70
71
72 /*
73 * 'AcceptClient()' - Accept a new client.
74 */
75
76 void
77 AcceptClient(listener_t *lis) /* I - Listener socket */
78 {
79 int i; /* Looping var */
80 int count; /* Count of connections on a host */
81 int val; /* Parameter value */
82 client_t *con; /* New client pointer */
83 const struct hostent *host; /* Host entry for address */
84 char *hostname;/* Hostname for address */
85 http_addr_t temp; /* Temporary address variable */
86 static time_t last_dos = 0;
87 /* Time of last DoS attack */
88
89
90 LogMessage(L_DEBUG2, "AcceptClient(%p) %d NumClients = %d",
91 lis, lis->fd, NumClients);
92
93 /*
94 * Make sure we don't have a full set of clients already...
95 */
96
97 if (NumClients == MaxClients)
98 return;
99
100 /*
101 * Get a pointer to the next available client...
102 */
103
104 con = Clients + NumClients;
105
106 memset(con, 0, sizeof(client_t));
107 con->http.activity = time(NULL);
108
109 /*
110 * Accept the client and get the remote address...
111 */
112
113 val = sizeof(struct sockaddr_in);
114
115 if ((con->http.fd = accept(lis->fd, (struct sockaddr *)&(con->http.hostaddr),
116 &val)) < 0)
117 {
118 LogMessage(L_ERROR, "Unable to accept client connection - %s.",
119 strerror(errno));
120 return;
121 }
122
123 #ifdef AF_INET6
124 if (lis->address.addr.sa_family == AF_INET6)
125 con->http.hostaddr.ipv6.sin6_port = lis->address.ipv6.sin6_port;
126 else
127 #endif /* AF_INET6 */
128 con->http.hostaddr.ipv4.sin_port = lis->address.ipv4.sin_port;
129
130 /*
131 * Check the number of clients on the same address...
132 */
133
134 for (i = 0, count = 0; i < NumClients; i ++)
135 if (memcmp(&(Clients[i].http.hostaddr), &(con->http.hostaddr),
136 sizeof(con->http.hostaddr)) == 0)
137 {
138 count ++;
139 if (count >= MaxClientsPerHost)
140 break;
141 }
142
143 if (count >= MaxClientsPerHost)
144 {
145 if ((time(NULL) - last_dos) >= 60)
146 {
147 last_dos = time(NULL);
148 LogMessage(L_WARN, "Possible DoS attack - more than %d clients connecting from %s!",
149 MaxClientsPerHost, Clients[i].http.hostname);
150 }
151
152 #ifdef WIN32
153 closesocket(con->http.fd);
154 #else
155 close(con->http.fd);
156 #endif /* WIN32 */
157
158 return;
159 }
160
161 /*
162 * Get the hostname or format the IP address as needed...
163 */
164
165 if (HostNameLookups)
166 hostname = httpAddrLookup(&(con->http.hostaddr), con->http.hostname,
167 sizeof(con->http.hostname));
168 else
169 {
170 hostname = NULL;
171 httpAddrString(&(con->http.hostaddr), con->http.hostname,
172 sizeof(con->http.hostname));
173 }
174
175 if (httpAddrLocalhost(&(con->http.hostaddr)))
176 {
177 /*
178 * Map accesses from the loopback interface to "localhost"...
179 */
180
181 strlcpy(con->http.hostname, "localhost", sizeof(con->http.hostname));
182 }
183 else if (httpAddrEqual(&(con->http.hostaddr), &ServerAddr))
184 {
185 /*
186 * Map accesses from the same host to the server name.
187 */
188
189 strlcpy(con->http.hostname, ServerName, sizeof(con->http.hostname));
190 }
191
192 if (hostname == NULL && HostNameLookups == 2)
193 {
194 /*
195 * Can't have an unresolved IP address with double-lookups enabled...
196 */
197
198 LogMessage(L_DEBUG2, "AcceptClient: Closing connection %d...",
199 con->http.fd);
200
201 #ifdef WIN32
202 closesocket(con->http.fd);
203 #else
204 close(con->http.fd);
205 #endif /* WIN32 */
206
207 LogMessage(L_WARN, "Name lookup failed - connection from %s closed!",
208 con->http.hostname);
209 return;
210 }
211
212 if (HostNameLookups == 2)
213 {
214 /*
215 * Do double lookups as needed...
216 */
217
218 if ((host = httpGetHostByName(con->http.hostname)) != NULL)
219 {
220 /*
221 * See if the hostname maps to the same IP address...
222 */
223
224 if (host->h_addrtype != con->http.hostaddr.addr.sa_family)
225 {
226 /*
227 * Not the right type of address...
228 */
229
230 host = NULL;
231 }
232 else
233 {
234 /*
235 * Compare all of the addresses against this one...
236 */
237
238 for (i = 0; host->h_addr_list[i]; i ++)
239 {
240 httpAddrLoad(host, 0, i, &temp);
241
242 if (httpAddrEqual(&(con->http.hostaddr), &temp))
243 break;
244 }
245
246 if (!host->h_addr_list[i])
247 host = NULL;
248 }
249 }
250
251 if (host == NULL)
252 {
253 /*
254 * Can't have a hostname that doesn't resolve to the same IP address
255 * with double-lookups enabled...
256 */
257
258 LogMessage(L_DEBUG2, "AcceptClient: Closing connection %d...",
259 con->http.fd);
260
261 #ifdef WIN32
262 closesocket(con->http.fd);
263 #else
264 close(con->http.fd);
265 #endif /* WIN32 */
266
267 LogMessage(L_WARN, "IP lookup failed - connection from %s closed!",
268 con->http.hostname);
269 return;
270 }
271 }
272
273 #ifdef AF_INET6
274 if (con->http.hostaddr.addr.sa_family == AF_INET6)
275 LogMessage(L_DEBUG, "AcceptClient: %d from %s:%d.", con->http.fd,
276 con->http.hostname, ntohs(con->http.hostaddr.ipv6.sin6_port));
277 else
278 #endif /* AF_INET6 */
279 LogMessage(L_DEBUG, "AcceptClient: %d from %s:%d.", con->http.fd,
280 con->http.hostname, ntohs(con->http.hostaddr.ipv4.sin_port));
281
282 /*
283 * Using TCP_NODELAY improves responsiveness, especially on systems
284 * with a slow loopback interface... Since we write large buffers
285 * when sending print files and requests, there shouldn't be any
286 * performance penalty for this...
287 */
288
289 val = 1;
290 setsockopt(con->http.fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
291
292 /*
293 * Add the socket to the select() input mask.
294 */
295
296 fcntl(con->http.fd, F_SETFD, fcntl(con->http.fd, F_GETFD) | FD_CLOEXEC);
297
298 LogMessage(L_DEBUG2, "AcceptClient: Adding fd %d to InputSet...",
299 con->http.fd);
300 FD_SET(con->http.fd, &InputSet);
301
302 NumClients ++;
303
304 /*
305 * Temporarily suspend accept()'s until we lose a client...
306 */
307
308 if (NumClients == MaxClients)
309 PauseListening();
310
311 #ifdef HAVE_LIBSSL
312 /*
313 * See if we are connecting on a secure port...
314 */
315
316 if (lis->encryption == HTTP_ENCRYPT_ALWAYS)
317 {
318 /*
319 * https connection; go secure...
320 */
321
322 con->http.encryption = HTTP_ENCRYPT_ALWAYS;
323
324 EncryptClient(con);
325 }
326 #endif /* HAVE_LIBSSL */
327 }
328
329
330 /*
331 * 'CloseAllClients()' - Close all remote clients immediately.
332 */
333
334 void
335 CloseAllClients(void)
336 {
337 while (NumClients > 0)
338 CloseClient(Clients);
339 }
340
341
342 /*
343 * 'CloseClient()' - Close a remote client.
344 */
345
346 void
347 CloseClient(client_t *con) /* I - Client to close */
348 {
349 int status; /* Exit status of pipe command */
350 #ifdef HAVE_LIBSSL
351 SSL_CTX *context; /* Context for encryption */
352 SSL *conn; /* Connection for encryption */
353 unsigned long error; /* Error code */
354 #endif /* HAVE_LIBSSL */
355
356
357 LogMessage(L_DEBUG, "CloseClient() %d", con->http.fd);
358
359 #ifdef HAVE_LIBSSL
360 /*
361 * Shutdown encryption as needed...
362 */
363
364 if (con->http.tls)
365 {
366 conn = (SSL *)(con->http.tls);
367 context = SSL_get_SSL_CTX(conn);
368
369 switch (SSL_shutdown(conn))
370 {
371 case 1 :
372 LogMessage(L_INFO, "CloseClient: SSL shutdown successful!");
373 break;
374 case -1 :
375 LogMessage(L_ERROR, "CloseClient: Fatal error during SSL shutdown!");
376 default :
377 while ((error = ERR_get_error()) != 0)
378 LogMessage(L_ERROR, "CloseClient: %s", ERR_error_string(error, NULL));
379 break;
380 }
381
382 SSL_CTX_free(context);
383 SSL_free(conn);
384
385 con->http.tls = NULL;
386 }
387 #endif /* HAVE_LIBSSL */
388
389 /*
390 * Close the socket and clear the file from the input set for select()...
391 */
392
393 if (con->http.fd >= 0)
394 {
395 LogMessage(L_DEBUG2, "CloseClient: Removing fd %d from InputSet and OutputSet...",
396 con->http.fd);
397 close(con->http.fd);
398 FD_CLR(con->http.fd, &InputSet);
399 FD_CLR(con->http.fd, &OutputSet);
400 con->http.fd = 0;
401 }
402
403 if (con->pipe_pid != 0)
404 {
405 LogMessage(L_DEBUG2, "CloseClient: Removing fd %d from InputSet...",
406 con->file);
407 FD_CLR(con->file, &InputSet);
408 }
409
410 if (con->file)
411 {
412 /*
413 * Close the open data file...
414 */
415
416 if (con->pipe_pid)
417 {
418 kill(con->pipe_pid, SIGKILL);
419 waitpid(con->pipe_pid, &status, WNOHANG);
420 }
421
422 LogMessage(L_DEBUG2, "CloseClient() %d Closing data file %d.",
423 con->http.fd, con->file);
424 LogMessage(L_DEBUG2, "CloseClient() %d Removing fd %d from InputSet.",
425 con->http.fd, con->file);
426
427 FD_CLR(con->file, &InputSet);
428 close(con->file);
429 con->file = 0;
430 }
431
432 if (con->request)
433 {
434 ippDelete(con->request);
435 con->request = NULL;
436 }
437
438 if (con->response)
439 {
440 ippDelete(con->response);
441 con->response = NULL;
442 }
443
444 if (con->language)
445 {
446 cupsLangFree(con->language);
447 con->language = NULL;
448 }
449
450 /*
451 * Re-enable new client connections if we are going back under the
452 * limit...
453 */
454
455 if (NumClients == MaxClients)
456 ResumeListening();
457
458 /*
459 * Compact the list of clients as necessary...
460 */
461
462 NumClients --;
463
464 if (con < (Clients + NumClients))
465 memcpy(con, con + 1, (Clients + NumClients - con) * sizeof(client_t));
466 }
467
468
469 /*
470 * 'EncryptClient()' - Enable encryption for the client...
471 */
472
473 int /* O - 1 on success, 0 on error */
474 EncryptClient(client_t *con) /* I - Client to encrypt */
475 {
476 #ifdef HAVE_LIBSSL
477 SSL_CTX *context; /* Context for encryption */
478 SSL *conn; /* Connection for encryption */
479 unsigned long error; /* Error code */
480
481
482 /*
483 * Create the SSL context and accept the connection...
484 */
485
486 context = SSL_CTX_new(SSLv23_method());
487 conn = SSL_new(context);
488
489 SSL_use_PrivateKey_file(conn, ServerKey, SSL_FILETYPE_PEM);
490 SSL_use_certificate_file(conn, ServerCertificate, SSL_FILETYPE_PEM);
491
492 SSL_set_fd(conn, con->http.fd);
493 if (SSL_accept(conn) != 1)
494 {
495 while ((error = ERR_get_error()) != 0)
496 LogMessage(L_ERROR, "EncryptClient: %s", ERR_error_string(error, NULL));
497
498 SSL_CTX_free(context);
499 SSL_free(conn);
500 return (0);
501 }
502
503 con->http.tls = conn;
504 return (1);
505 #else
506 return (0);
507 #endif /* HAVE_LIBSSL */
508 }
509
510
511 /*
512 * 'ReadClient()' - Read data from a client.
513 */
514
515 int /* O - 1 on success, 0 on error */
516 ReadClient(client_t *con) /* I - Client to read from */
517 {
518 char line[32768], /* Line from client... */
519 operation[64], /* Operation code from socket */
520 version[64]; /* HTTP version number string */
521 int major, minor; /* HTTP version numbers */
522 http_status_t status; /* Transfer status */
523 ipp_state_t ipp_state; /* State of IPP transfer */
524 int bytes; /* Number of bytes to POST */
525 char *filename; /* Name of file for GET/HEAD */
526 struct stat filestats; /* File information */
527 mime_type_t *type; /* MIME type of file */
528 printer_t *p; /* Printer */
529 location_t *best; /* Best match for authentication */
530 static unsigned request_id = 0;/* Request ID for temp files */
531
532
533 status = HTTP_CONTINUE;
534
535 LogMessage(L_DEBUG2, "ReadClient() %d, used=%d", con->http.fd,
536 con->http.used);
537
538 if (con->http.error)
539 {
540 CloseClient(con);
541 return (0);
542 }
543
544 switch (con->http.state)
545 {
546 case HTTP_WAITING :
547 /*
548 * See if we've received a request line...
549 */
550
551 if (httpGets(line, sizeof(line) - 1, HTTP(con)) == NULL)
552 {
553 CloseClient(con);
554 return (0);
555 }
556
557 /*
558 * Ignore blank request lines...
559 */
560
561 if (line[0] == '\0')
562 break;
563
564 /*
565 * Clear other state variables...
566 */
567
568 httpClearFields(HTTP(con));
569
570 con->http.activity = time(NULL);
571 con->http.version = HTTP_1_0;
572 con->http.keep_alive = HTTP_KEEPALIVE_OFF;
573 con->http.data_encoding = HTTP_ENCODE_LENGTH;
574 con->http.data_remaining = 0;
575 con->operation = HTTP_WAITING;
576 con->bytes = 0;
577 con->file = 0;
578 con->pipe_pid = 0;
579 con->command[0] = '\0';
580 con->username[0] = '\0';
581 con->password[0] = '\0';
582 con->uri[0] = '\0';
583
584 if (con->language != NULL)
585 {
586 cupsLangFree(con->language);
587 con->language = NULL;
588 }
589
590 /*
591 * Grab the request line...
592 */
593
594 switch (sscanf(line, "%63s%1023s%63s", operation, con->uri, version))
595 {
596 case 1 :
597 LogMessage(L_ERROR, "Bad request line \"%s\"!", line);
598 SendError(con, HTTP_BAD_REQUEST);
599 ShutdownClient(con);
600 return (1);
601 case 2 :
602 con->http.version = HTTP_0_9;
603 break;
604 case 3 :
605 if (sscanf(version, "HTTP/%d.%d", &major, &minor) != 2)
606 {
607 LogMessage(L_ERROR, "Bad request line \"%s\"!", line);
608 SendError(con, HTTP_BAD_REQUEST);
609 ShutdownClient(con);
610 return (1);
611 }
612
613 if (major < 2)
614 {
615 con->http.version = (http_version_t)(major * 100 + minor);
616 if (con->http.version == HTTP_1_1 && KeepAlive)
617 con->http.keep_alive = HTTP_KEEPALIVE_ON;
618 else
619 con->http.keep_alive = HTTP_KEEPALIVE_OFF;
620 }
621 else
622 {
623 SendError(con, HTTP_NOT_SUPPORTED);
624 ShutdownClient(con);
625 return (1);
626 }
627 break;
628 }
629
630 /*
631 * Process the request...
632 */
633
634 if (strcmp(operation, "GET") == 0)
635 con->http.state = HTTP_GET;
636 else if (strcmp(operation, "PUT") == 0)
637 con->http.state = HTTP_PUT;
638 else if (strcmp(operation, "POST") == 0)
639 con->http.state = HTTP_POST;
640 else if (strcmp(operation, "DELETE") == 0)
641 con->http.state = HTTP_DELETE;
642 else if (strcmp(operation, "TRACE") == 0)
643 con->http.state = HTTP_TRACE;
644 else if (strcmp(operation, "OPTIONS") == 0)
645 con->http.state = HTTP_OPTIONS;
646 else if (strcmp(operation, "HEAD") == 0)
647 con->http.state = HTTP_HEAD;
648 else
649 {
650 LogMessage(L_ERROR, "Bad operation \"%s\"!", operation);
651 SendError(con, HTTP_BAD_REQUEST);
652 ShutdownClient(con);
653 return (1);
654 }
655
656 con->start = time(NULL);
657 con->operation = con->http.state;
658
659 LogMessage(L_DEBUG, "ReadClient() %d %s %s HTTP/%d.%d", con->http.fd,
660 operation, con->uri,
661 con->http.version / 100, con->http.version % 100);
662
663 con->http.status = HTTP_OK;
664
665 case HTTP_OPTIONS :
666 case HTTP_DELETE :
667 case HTTP_GET :
668 case HTTP_HEAD :
669 case HTTP_POST :
670 case HTTP_PUT :
671 case HTTP_TRACE :
672 /*
673 * Parse incoming parameters until the status changes...
674 */
675
676 status = httpUpdate(HTTP(con));
677
678 if (status != HTTP_OK && status != HTTP_CONTINUE)
679 {
680 SendError(con, HTTP_BAD_REQUEST);
681 ShutdownClient(con);
682 return (1);
683 }
684 break;
685
686 default :
687 break; /* Anti-compiler-warning-code */
688 }
689
690 /*
691 * Handle new transfers...
692 */
693
694 if (status == HTTP_OK)
695 {
696 con->language = cupsLangGet(con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE]);
697
698 decode_auth(con);
699
700 if (strncmp(con->http.fields[HTTP_FIELD_CONNECTION], "Keep-Alive", 10) == 0 &&
701 KeepAlive)
702 con->http.keep_alive = HTTP_KEEPALIVE_ON;
703
704 if (con->http.fields[HTTP_FIELD_HOST][0] == '\0' &&
705 con->http.version >= HTTP_1_1)
706 {
707 /*
708 * HTTP/1.1 and higher require the "Host:" field...
709 */
710
711 if (!SendError(con, HTTP_BAD_REQUEST))
712 {
713 CloseClient(con);
714 return (0);
715 }
716 }
717 else if (con->operation == HTTP_OPTIONS)
718 {
719 /*
720 * Do OPTIONS command...
721 */
722
723 if ((best = FindBest(con->uri, con->http.state)) != NULL &&
724 best->type != AUTH_NONE)
725 {
726 if (!SendHeader(con, HTTP_UNAUTHORIZED, NULL))
727 {
728 CloseClient(con);
729 return (0);
730 }
731 }
732
733 if (strcasecmp(con->http.fields[HTTP_FIELD_CONNECTION], "Upgrade") == 0 &&
734 con->http.tls == NULL)
735 {
736 #ifdef HAVE_LIBSSL
737 /*
738 * Do encryption stuff...
739 */
740
741 if (!SendHeader(con, HTTP_SWITCHING_PROTOCOLS, NULL))
742 {
743 CloseClient(con);
744 return (0);
745 }
746
747 httpPrintf(HTTP(con), "Connection: Upgrade\r\n");
748 httpPrintf(HTTP(con), "Upgrade: TLS/1.0,HTTP/1.1\r\n");
749 httpPrintf(HTTP(con), "Content-Length: 0\r\n");
750 httpPrintf(HTTP(con), "\r\n");
751
752 EncryptClient(con);
753 #else
754 if (!SendError(con, HTTP_NOT_IMPLEMENTED))
755 {
756 CloseClient(con);
757 return (0);
758 }
759 #endif /* HAVE_LIBSSL */
760 }
761
762 if (!SendHeader(con, HTTP_OK, NULL))
763 {
764 CloseClient(con);
765 return (0);
766 }
767
768 httpPrintf(HTTP(con), "Allow: GET, HEAD, OPTIONS, POST, PUT\r\n");
769 httpPrintf(HTTP(con), "Content-Length: 0\r\n");
770 httpPrintf(HTTP(con), "\r\n");
771 }
772 else if (strstr(con->uri, "..") != NULL)
773 {
774 /*
775 * Protect against malicious users!
776 */
777
778 if (!SendError(con, HTTP_FORBIDDEN))
779 {
780 CloseClient(con);
781 return (0);
782 }
783 }
784 else if (con->uri[0] != '/')
785 {
786 /*
787 * Don't allow proxying (yet)...
788 */
789
790 if (!SendError(con, HTTP_METHOD_NOT_ALLOWED))
791 {
792 CloseClient(con);
793 return (0);
794 }
795 }
796 else
797 {
798 if (strcasecmp(con->http.fields[HTTP_FIELD_CONNECTION], "Upgrade") == 0 &&
799 con->http.tls == NULL)
800 {
801 #ifdef HAVE_LIBSSL
802 /*
803 * Do encryption stuff...
804 */
805
806 if (!SendHeader(con, HTTP_SWITCHING_PROTOCOLS, NULL))
807 {
808 CloseClient(con);
809 return (0);
810 }
811
812 httpPrintf(HTTP(con), "Connection: Upgrade\r\n");
813 httpPrintf(HTTP(con), "Upgrade: TLS/1.0,HTTP/1.1\r\n");
814 httpPrintf(HTTP(con), "Content-Length: 0\r\n");
815 httpPrintf(HTTP(con), "\r\n");
816
817 EncryptClient(con);
818
819 status = IsAuthorized(con);
820 #else
821 if (!SendError(con, HTTP_NOT_IMPLEMENTED))
822 {
823 CloseClient(con);
824 return (0);
825 }
826 #endif /* HAVE_LIBSSL */
827 }
828
829 if (status != HTTP_OK)
830 {
831 LogMessage(L_DEBUG2, "ReadClient: Unauthorized request for %s...\n",
832 con->uri);
833 SendError(con, status);
834 ShutdownClient(con);
835 return (1);
836 }
837
838 switch (con->http.state)
839 {
840 case HTTP_GET_SEND :
841 if (strncmp(con->uri, "/printers/", 10) == 0 &&
842 strcmp(con->uri + strlen(con->uri) - 4, ".ppd") == 0)
843 {
844 /*
845 * Send PPD file - get the real printer name since printer
846 * names are not case sensitive but filenames can be...
847 */
848
849 con->uri[strlen(con->uri) - 4] = '\0'; /* Drop ".ppd" */
850
851 if ((p = FindPrinter(con->uri + 10)) != NULL)
852 snprintf(con->uri, sizeof(con->uri), "/ppd/%s.ppd", p->name);
853 else
854 {
855 if (!SendError(con, HTTP_NOT_FOUND))
856 {
857 CloseClient(con);
858 return (0);
859 }
860
861 break;
862 }
863 }
864
865 if ((strncmp(con->uri, "/admin", 6) == 0 &&
866 strncmp(con->uri, "/admin/conf/", 12) != 0) ||
867 strncmp(con->uri, "/printers", 9) == 0 ||
868 strncmp(con->uri, "/classes", 8) == 0 ||
869 strncmp(con->uri, "/jobs", 5) == 0)
870 {
871 /*
872 * Send CGI output...
873 */
874
875 if (strncmp(con->uri, "/admin", 6) == 0)
876 {
877 snprintf(con->command, sizeof(con->command),
878 "%s/cgi-bin/admin.cgi", ServerBin);
879 con->options = con->uri + 6;
880 }
881 else if (strncmp(con->uri, "/printers", 9) == 0)
882 {
883 snprintf(con->command, sizeof(con->command),
884 "%s/cgi-bin/printers.cgi", ServerBin);
885 con->options = con->uri + 9;
886 }
887 else if (strncmp(con->uri, "/classes", 8) == 0)
888 {
889 snprintf(con->command, sizeof(con->command),
890 "%s/cgi-bin/classes.cgi", ServerBin);
891 con->options = con->uri + 8;
892 }
893 else
894 {
895 snprintf(con->command, sizeof(con->command),
896 "%s/cgi-bin/jobs.cgi", ServerBin);
897 con->options = con->uri + 5;
898 }
899
900 if (con->options[0] == '/')
901 con->options ++;
902
903 if (!SendCommand(con, con->command, con->options))
904 {
905 if (!SendError(con, HTTP_NOT_FOUND))
906 {
907 CloseClient(con);
908 return (0);
909 }
910 }
911 else
912 LogRequest(con, HTTP_OK);
913
914 if (con->http.version <= HTTP_1_0)
915 con->http.keep_alive = HTTP_KEEPALIVE_OFF;
916 }
917 else if (strncmp(con->uri, "/admin/conf/", 12) == 0 &&
918 (strchr(con->uri + 12, '/') != NULL ||
919 strlen(con->uri) == 12))
920 {
921 /*
922 * GET can only be done to configuration files under
923 * /admin/conf...
924 */
925
926 if (!SendError(con, HTTP_FORBIDDEN))
927 {
928 CloseClient(con);
929 return (0);
930 }
931
932 break;
933 }
934 else
935 {
936 /*
937 * Serve a file...
938 */
939
940 if ((filename = get_file(con, &filestats)) == NULL)
941 {
942 if (!SendError(con, HTTP_NOT_FOUND))
943 {
944 CloseClient(con);
945 return (0);
946 }
947 }
948 else if (!check_if_modified(con, &filestats))
949 {
950 if (!SendError(con, HTTP_NOT_MODIFIED))
951 {
952 CloseClient(con);
953 return (0);
954 }
955 }
956 else
957 {
958 type = mimeFileType(MimeDatabase, filename);
959 if (type == NULL)
960 strcpy(line, "text/plain");
961 else
962 snprintf(line, sizeof(line), "%s/%s", type->super, type->type);
963
964 if (!SendFile(con, HTTP_OK, filename, line, &filestats))
965 {
966 CloseClient(con);
967 return (0);
968 }
969 }
970 }
971 break;
972
973 case HTTP_POST_RECV :
974 /*
975 * See if the POST request includes a Content-Length field, and if
976 * so check the length against any limits that are set...
977 */
978
979 LogMessage(L_DEBUG2, "POST %s", con->uri);
980 LogMessage(L_DEBUG2, "CONTENT_TYPE = %s", con->http.fields[HTTP_FIELD_CONTENT_TYPE]);
981
982 if (con->http.fields[HTTP_FIELD_CONTENT_LENGTH][0] &&
983 atoi(con->http.fields[HTTP_FIELD_CONTENT_LENGTH]) > MaxRequestSize &&
984 MaxRequestSize > 0)
985 {
986 /*
987 * Request too large...
988 */
989
990 if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
991 {
992 CloseClient(con);
993 return (0);
994 }
995
996 break;
997 }
998 else if (atoi(con->http.fields[HTTP_FIELD_CONTENT_LENGTH]) < 0)
999 {
1000 /*
1001 * Negative content lengths are invalid!
1002 */
1003
1004 if (!SendError(con, HTTP_BAD_REQUEST))
1005 {
1006 CloseClient(con);
1007 return (0);
1008 }
1009
1010 break;
1011 }
1012
1013 /*
1014 * See what kind of POST request this is; for IPP requests the
1015 * content-type field will be "application/ipp"...
1016 */
1017
1018 if (strcmp(con->http.fields[HTTP_FIELD_CONTENT_TYPE], "application/ipp") == 0)
1019 con->request = ippNew();
1020 else if ((strncmp(con->uri, "/admin", 6) == 0 &&
1021 strncmp(con->uri, "/admin/conf/", 12) != 0) ||
1022 strncmp(con->uri, "/printers", 9) == 0 ||
1023 strncmp(con->uri, "/classes", 8) == 0 ||
1024 strncmp(con->uri, "/jobs", 5) == 0)
1025 {
1026 /*
1027 * CGI request...
1028 */
1029
1030 if (strncmp(con->uri, "/admin", 6) == 0)
1031 {
1032 snprintf(con->command, sizeof(con->command),
1033 "%s/cgi-bin/admin.cgi", ServerBin);
1034 con->options = con->uri + 6;
1035 }
1036 else if (strncmp(con->uri, "/printers", 9) == 0)
1037 {
1038 snprintf(con->command, sizeof(con->command),
1039 "%s/cgi-bin/printers.cgi", ServerBin);
1040 con->options = con->uri + 9;
1041 }
1042 else if (strncmp(con->uri, "/classes", 8) == 0)
1043 {
1044 snprintf(con->command, sizeof(con->command),
1045 "%s/cgi-bin/classes.cgi", ServerBin);
1046 con->options = con->uri + 8;
1047 }
1048 else
1049 {
1050 snprintf(con->command, sizeof(con->command),
1051 "%s/cgi-bin/jobs.cgi", ServerBin);
1052 con->options = con->uri + 5;
1053 }
1054
1055 if (con->options[0] == '/')
1056 con->options ++;
1057
1058 LogMessage(L_DEBUG2, "ReadClient() %d command=\"%s\", options = \"%s\"",
1059 con->http.fd, con->command, con->options);
1060
1061 if (con->http.version <= HTTP_1_0)
1062 con->http.keep_alive = HTTP_KEEPALIVE_OFF;
1063 }
1064 else if (!SendError(con, HTTP_UNAUTHORIZED))
1065 {
1066 CloseClient(con);
1067 return (0);
1068 }
1069 break;
1070
1071 case HTTP_PUT_RECV :
1072 /*
1073 * Validate the resource name...
1074 */
1075
1076 if (strncmp(con->uri, "/admin/conf/", 12) != 0 ||
1077 strchr(con->uri + 12, '/') != NULL ||
1078 strlen(con->uri) == 12)
1079 {
1080 /*
1081 * PUT can only be done to configuration files under
1082 * /admin/conf...
1083 */
1084
1085 if (!SendError(con, HTTP_FORBIDDEN))
1086 {
1087 CloseClient(con);
1088 return (0);
1089 }
1090
1091 break;
1092 }
1093
1094 /*
1095 * See if the PUT request includes a Content-Length field, and if
1096 * so check the length against any limits that are set...
1097 */
1098
1099 LogMessage(L_DEBUG2, "PUT %s", con->uri);
1100 LogMessage(L_DEBUG2, "CONTENT_TYPE = %s", con->http.fields[HTTP_FIELD_CONTENT_TYPE]);
1101
1102 if (con->http.fields[HTTP_FIELD_CONTENT_LENGTH][0] &&
1103 atoi(con->http.fields[HTTP_FIELD_CONTENT_LENGTH]) > MaxRequestSize &&
1104 MaxRequestSize > 0)
1105 {
1106 /*
1107 * Request too large...
1108 */
1109
1110 if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
1111 {
1112 CloseClient(con);
1113 return (0);
1114 }
1115
1116 break;
1117 }
1118
1119 /*
1120 * Open a temporary file to hold the request...
1121 */
1122
1123 snprintf(con->filename, sizeof(con->filename), "%s/%08x",
1124 RequestRoot, request_id ++);
1125 con->file = open(con->filename, O_WRONLY | O_CREAT | O_TRUNC, 0640);
1126 fchmod(con->file, 0640);
1127 fchown(con->file, User, Group);
1128
1129 LogMessage(L_DEBUG2, "ReadClient() %d REQUEST %s=%d", con->http.fd,
1130 con->filename, con->file);
1131
1132 if (con->file < 0)
1133 {
1134 if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
1135 {
1136 CloseClient(con);
1137 return (0);
1138 }
1139 }
1140 break;
1141
1142 case HTTP_DELETE :
1143 case HTTP_TRACE :
1144 SendError(con, HTTP_NOT_IMPLEMENTED);
1145 ShutdownClient(con);
1146 return (1);
1147
1148 case HTTP_HEAD :
1149 if (strncmp(con->uri, "/printers/", 10) == 0 &&
1150 strcmp(con->uri + strlen(con->uri) - 4, ".ppd") == 0)
1151 {
1152 /*
1153 * Send PPD file - get the real printer name since printer
1154 * names are not case sensitive but filenames can be...
1155 */
1156
1157 con->uri[strlen(con->uri) - 4] = '\0'; /* Drop ".ppd" */
1158
1159 if ((p = FindPrinter(con->uri + 10)) != NULL)
1160 snprintf(con->uri, sizeof(con->uri), "/ppd/%s.ppd", p->name);
1161 else
1162 {
1163 if (!SendError(con, HTTP_NOT_FOUND))
1164 {
1165 CloseClient(con);
1166 return (0);
1167 }
1168
1169 break;
1170 }
1171 }
1172
1173 if ((strncmp(con->uri, "/admin/", 7) == 0 &&
1174 strncmp(con->uri, "/admin/conf/", 12) != 0) ||
1175 strncmp(con->uri, "/printers/", 10) == 0 ||
1176 strncmp(con->uri, "/classes/", 9) == 0 ||
1177 strncmp(con->uri, "/jobs/", 6) == 0)
1178 {
1179 /*
1180 * CGI output...
1181 */
1182
1183 if (!SendHeader(con, HTTP_OK, "text/html"))
1184 {
1185 CloseClient(con);
1186 return (0);
1187 }
1188
1189 if (httpPrintf(HTTP(con), "\r\n") < 0)
1190 {
1191 CloseClient(con);
1192 return (0);
1193 }
1194
1195 LogRequest(con, HTTP_OK);
1196 }
1197 else if (strncmp(con->uri, "/admin/conf/", 12) == 0 &&
1198 (strchr(con->uri + 12, '/') != NULL ||
1199 strlen(con->uri) == 12))
1200 {
1201 /*
1202 * HEAD can only be done to configuration files under
1203 * /admin/conf...
1204 */
1205
1206 if (!SendError(con, HTTP_FORBIDDEN))
1207 {
1208 CloseClient(con);
1209 return (0);
1210 }
1211
1212 break;
1213 }
1214 else if ((filename = get_file(con, &filestats)) == NULL)
1215 {
1216 if (!SendHeader(con, HTTP_NOT_FOUND, "text/html"))
1217 {
1218 CloseClient(con);
1219 return (0);
1220 }
1221
1222 LogRequest(con, HTTP_NOT_FOUND);
1223 }
1224 else if (!check_if_modified(con, &filestats))
1225 {
1226 if (!SendError(con, HTTP_NOT_MODIFIED))
1227 {
1228 CloseClient(con);
1229 return (0);
1230 }
1231
1232 LogRequest(con, HTTP_NOT_MODIFIED);
1233 }
1234 else
1235 {
1236 /*
1237 * Serve a file...
1238 */
1239
1240 type = mimeFileType(MimeDatabase, filename);
1241 if (type == NULL)
1242 strcpy(line, "text/plain");
1243 else
1244 snprintf(line, sizeof(line), "%s/%s", type->super, type->type);
1245
1246 if (!SendHeader(con, HTTP_OK, line))
1247 {
1248 CloseClient(con);
1249 return (0);
1250 }
1251
1252 if (httpPrintf(HTTP(con), "Last-Modified: %s\r\n",
1253 httpGetDateString(filestats.st_mtime)) < 0)
1254 {
1255 CloseClient(con);
1256 return (0);
1257 }
1258
1259 if (httpPrintf(HTTP(con), "Content-Length: %lu\r\n",
1260 (unsigned long)filestats.st_size) < 0)
1261 {
1262 CloseClient(con);
1263 return (0);
1264 }
1265
1266 LogRequest(con, HTTP_OK);
1267 }
1268
1269 if (httpPrintf(HTTP(con), "\r\n") < 0)
1270 {
1271 CloseClient(con);
1272 return (0);
1273 }
1274
1275 con->http.state = HTTP_WAITING;
1276 break;
1277
1278 default :
1279 break; /* Anti-compiler-warning-code */
1280 }
1281 }
1282 }
1283
1284 /*
1285 * Handle any incoming data...
1286 */
1287
1288 switch (con->http.state)
1289 {
1290 case HTTP_PUT_RECV :
1291 LogMessage(L_DEBUG2, "ReadClient() %d con->data_encoding = %s, con->data_remaining = %d, con->file = %d",
1292 con->http.fd,
1293 con->http.data_encoding == HTTP_ENCODE_CHUNKED ? "chunked" : "length",
1294 con->http.data_remaining, con->file);
1295
1296 if ((bytes = httpRead(HTTP(con), line, sizeof(line))) < 0)
1297 {
1298 CloseClient(con);
1299 return (0);
1300 }
1301 else if (bytes > 0)
1302 {
1303 con->bytes += bytes;
1304
1305 LogMessage(L_DEBUG2, "ReadClient() %d writing %d bytes to %d",
1306 con->http.fd, bytes, con->file);
1307
1308 if (write(con->file, line, bytes) < bytes)
1309 {
1310 LogMessage(L_ERROR, "ReadClient: Unable to write %d bytes to %s: %s",
1311 bytes, con->filename, strerror(errno));
1312
1313 LogMessage(L_DEBUG2, "ReadClient: Closing data file %d...",
1314 con->file);
1315
1316 close(con->file);
1317 con->file = 0;
1318 unlink(con->filename);
1319 con->filename[0] = '\0';
1320
1321 if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
1322 {
1323 CloseClient(con);
1324 return (0);
1325 }
1326 }
1327 }
1328
1329 if (con->http.state == HTTP_WAITING)
1330 {
1331 /*
1332 * End of file, see how big it is...
1333 */
1334
1335 fstat(con->file, &filestats);
1336
1337 LogMessage(L_DEBUG2, "ReadClient() %d Closing data file %d, size = %d.",
1338 con->http.fd, con->file, (int)filestats.st_size);
1339
1340 close(con->file);
1341 con->file = 0;
1342
1343 if (filestats.st_size > MaxRequestSize &&
1344 MaxRequestSize > 0)
1345 {
1346 /*
1347 * Request is too big; remove it and send an error...
1348 */
1349
1350 LogMessage(L_DEBUG2, "ReadClient() %d Removing temp file %s",
1351 con->http.fd, con->filename);
1352 unlink(con->filename);
1353 con->filename[0] = '\0';
1354
1355 if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
1356 {
1357 CloseClient(con);
1358 return (0);
1359 }
1360 }
1361
1362 /*
1363 * Install the configuration file...
1364 */
1365
1366 status = install_conf_file(con);
1367
1368 /*
1369 * Return the status to the client...
1370 */
1371
1372 if (!SendError(con, status))
1373 {
1374 CloseClient(con);
1375 return (0);
1376 }
1377 }
1378 break;
1379
1380 case HTTP_POST_RECV :
1381 LogMessage(L_DEBUG2, "ReadClient() %d con->data_encoding = %s, con->data_remaining = %d, con->file = %d",
1382 con->http.fd,
1383 con->http.data_encoding == HTTP_ENCODE_CHUNKED ? "chunked" : "length",
1384 con->http.data_remaining, con->file);
1385
1386 if (con->request != NULL)
1387 {
1388 /*
1389 * Grab any request data from the connection...
1390 */
1391
1392 if ((ipp_state = ippRead(&(con->http), con->request)) == IPP_ERROR)
1393 {
1394 LogMessage(L_ERROR, "ReadClient() %d IPP Read Error!",
1395 con->http.fd);
1396 CloseClient(con);
1397 return (0);
1398 }
1399 else if (ipp_state != IPP_DATA)
1400 break;
1401 else
1402 con->bytes += ippLength(con->request);
1403 }
1404
1405 if (con->file == 0 && con->http.state != HTTP_POST_SEND)
1406 {
1407 /*
1408 * Create a file as needed for the request data...
1409 */
1410
1411 snprintf(con->filename, sizeof(con->filename), "%s/%08x",
1412 RequestRoot, request_id ++);
1413 con->file = open(con->filename, O_WRONLY | O_CREAT | O_TRUNC, 0640);
1414 fchmod(con->file, 0640);
1415 fchown(con->file, User, Group);
1416
1417 LogMessage(L_DEBUG2, "ReadClient() %d REQUEST %s=%d", con->http.fd,
1418 con->filename, con->file);
1419
1420 if (con->file < 0)
1421 {
1422 if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
1423 {
1424 CloseClient(con);
1425 return (0);
1426 }
1427 }
1428 }
1429
1430 if (con->http.state != HTTP_POST_SEND)
1431 {
1432 if ((bytes = httpRead(HTTP(con), line, sizeof(line))) < 0)
1433 {
1434 CloseClient(con);
1435 return (0);
1436 }
1437 else if (bytes > 0)
1438 {
1439 con->bytes += bytes;
1440
1441 LogMessage(L_DEBUG2, "ReadClient() %d writing %d bytes to %d",
1442 con->http.fd, bytes, con->file);
1443
1444 if (write(con->file, line, bytes) < bytes)
1445 {
1446 LogMessage(L_ERROR, "ReadClient: Unable to write %d bytes to %s: %s",
1447 bytes, con->filename, strerror(errno));
1448
1449 LogMessage(L_DEBUG2, "ReadClient: Closing file %d...",
1450 con->file);
1451
1452 close(con->file);
1453 con->file = 0;
1454 unlink(con->filename);
1455 con->filename[0] = '\0';
1456
1457 if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
1458 {
1459 CloseClient(con);
1460 return (0);
1461 }
1462 }
1463 }
1464 else if (con->http.state != HTTP_POST_SEND)
1465 {
1466 CloseClient(con);
1467 return (0);
1468 }
1469 }
1470
1471 if (con->http.state == HTTP_POST_SEND)
1472 {
1473 if (con->file)
1474 {
1475 fstat(con->file, &filestats);
1476
1477 LogMessage(L_DEBUG2, "ReadClient() %d Closing data file %d, size = %d.",
1478 con->http.fd, con->file, (int)filestats.st_size);
1479
1480 close(con->file);
1481 con->file = 0;
1482
1483 if (filestats.st_size > MaxRequestSize &&
1484 MaxRequestSize > 0)
1485 {
1486 /*
1487 * Request is too big; remove it and send an error...
1488 */
1489
1490 LogMessage(L_DEBUG2, "ReadClient() %d Removing temp file %s",
1491 con->http.fd, con->filename);
1492 unlink(con->filename);
1493 con->filename[0] = '\0';
1494
1495 if (con->request)
1496 {
1497 /*
1498 * Delete any IPP request data...
1499 */
1500
1501 ippDelete(con->request);
1502 con->request = NULL;
1503 }
1504
1505 if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
1506 {
1507 CloseClient(con);
1508 return (0);
1509 }
1510 }
1511
1512 if (con->command[0])
1513 {
1514 if (!SendCommand(con, con->command, con->options))
1515 {
1516 if (!SendError(con, HTTP_NOT_FOUND))
1517 {
1518 CloseClient(con);
1519 return (0);
1520 }
1521 }
1522 else
1523 LogRequest(con, HTTP_OK);
1524 }
1525 }
1526
1527 if (con->request)
1528 return (ProcessIPPRequest(con));
1529 }
1530 break;
1531
1532 default :
1533 break; /* Anti-compiler-warning-code */
1534 }
1535
1536 if (!con->http.keep_alive && con->http.state == HTTP_WAITING)
1537 {
1538 CloseClient(con);
1539 return (0);
1540 }
1541 else
1542 return (1);
1543 }
1544
1545
1546 /*
1547 * 'SendCommand()' - Send output from a command via HTTP.
1548 */
1549
1550 int
1551 SendCommand(client_t *con,
1552 char *command,
1553 char *options)
1554 {
1555 int fd;
1556
1557
1558 if (con->filename[0])
1559 fd = open(con->filename, O_RDONLY);
1560 else
1561 fd = open("/dev/null", O_RDONLY);
1562
1563 con->pipe_pid = pipe_command(con, fd, &(con->file), command, options);
1564
1565 close(fd);
1566
1567 LogMessage(L_INFO, "Started \"%s\" (pid=%d)", command, con->pipe_pid);
1568
1569 LogMessage(L_DEBUG, "SendCommand() %d file=%d", con->http.fd, con->file);
1570
1571 if (con->pipe_pid == 0)
1572 return (0);
1573
1574 fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
1575
1576 LogMessage(L_DEBUG2, "SendCommand: Adding fd %d to InputSet...", con->file);
1577 LogMessage(L_DEBUG2, "SendCommand: Adding fd %d to OutputSet...",
1578 con->http.fd);
1579
1580 FD_SET(con->file, &InputSet);
1581 FD_SET(con->http.fd, &OutputSet);
1582
1583 if (!SendHeader(con, HTTP_OK, NULL))
1584 return (0);
1585
1586 if (con->http.version == HTTP_1_1)
1587 {
1588 con->http.data_encoding = HTTP_ENCODE_CHUNKED;
1589
1590 if (httpPrintf(HTTP(con), "Transfer-Encoding: chunked\r\n") < 0)
1591 return (0);
1592 }
1593
1594 con->got_fields = 0;
1595 con->field_col = 0;
1596
1597 return (1);
1598 }
1599
1600
1601 /*
1602 * 'SendError()' - Send an error message via HTTP.
1603 */
1604
1605 int /* O - 1 if successful, 0 otherwise */
1606 SendError(client_t *con, /* I - Connection */
1607 http_status_t code) /* I - Error code */
1608 {
1609 char message[1024]; /* Message for user */
1610
1611
1612 /*
1613 * Put the request in the access_log file...
1614 */
1615
1616 if (con->operation > HTTP_WAITING)
1617 LogRequest(con, code);
1618
1619 LogMessage(L_DEBUG, "SendError() %d code=%d", con->http.fd, code);
1620
1621 /*
1622 * To work around bugs in some proxies, don't use Keep-Alive for some
1623 * error messages...
1624 */
1625
1626 if (code >= HTTP_BAD_REQUEST)
1627 con->http.keep_alive = HTTP_KEEPALIVE_OFF;
1628
1629 /*
1630 * Send an error message back to the client. If the error code is a
1631 * 400 or 500 series, make sure the message contains some text, too!
1632 */
1633
1634 if (!SendHeader(con, code, NULL))
1635 return (0);
1636
1637 #ifdef HAVE_LIBSSL
1638 if (code == HTTP_UPGRADE_REQUIRED)
1639 if (httpPrintf(HTTP(con), "Connection: Upgrade\r\n") < 0)
1640 return (0);
1641
1642 if (httpPrintf(HTTP(con), "Upgrade: TLS/1.0,HTTP/1.1\r\n") < 0)
1643 return (0);
1644 #endif /* HAVE_LIBSSL */
1645
1646 if ((con->http.version >= HTTP_1_1 && !con->http.keep_alive) ||
1647 (code >= HTTP_BAD_REQUEST && code != HTTP_UPGRADE_REQUIRED))
1648 {
1649 if (httpPrintf(HTTP(con), "Connection: close\r\n") < 0)
1650 return (0);
1651 }
1652
1653 if (code >= HTTP_BAD_REQUEST)
1654 {
1655 /*
1656 * Send a human-readable error message.
1657 */
1658
1659 snprintf(message, sizeof(message),
1660 "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>"
1661 "<BODY><H1>%s</H1>%s</BODY></HTML>\n",
1662 code, httpStatus(code), httpStatus(code),
1663 con->language ? con->language->messages[code] :
1664 httpStatus(code));
1665
1666 if (httpPrintf(HTTP(con), "Content-Type: text/html\r\n") < 0)
1667 return (0);
1668 if (httpPrintf(HTTP(con), "Content-Length: %d\r\n",
1669 (int)strlen(message)) < 0)
1670 return (0);
1671 if (httpPrintf(HTTP(con), "\r\n") < 0)
1672 return (0);
1673 if (httpPrintf(HTTP(con), "%s", message) < 0)
1674 return (0);
1675 }
1676 else if (httpPrintf(HTTP(con), "\r\n") < 0)
1677 return (0);
1678
1679 con->http.state = HTTP_WAITING;
1680
1681 return (1);
1682 }
1683
1684
1685 /*
1686 * 'SendFile()' - Send a file via HTTP.
1687 */
1688
1689 int
1690 SendFile(client_t *con,
1691 http_status_t code,
1692 char *filename,
1693 char *type,
1694 struct stat *filestats)
1695 {
1696 con->file = open(filename, O_RDONLY);
1697
1698 LogMessage(L_DEBUG, "SendFile() %d file=%d", con->http.fd, con->file);
1699
1700 if (con->file < 0)
1701 return (0);
1702
1703 fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
1704
1705 con->pipe_pid = 0;
1706
1707 if (!SendHeader(con, code, type))
1708 return (0);
1709
1710 if (httpPrintf(HTTP(con), "Last-Modified: %s\r\n", httpGetDateString(filestats->st_mtime)) < 0)
1711 return (0);
1712 if (httpPrintf(HTTP(con), "Content-Length: %lu\r\n",
1713 (unsigned long)filestats->st_size) < 0)
1714 return (0);
1715 if (httpPrintf(HTTP(con), "\r\n") < 0)
1716 return (0);
1717
1718 LogMessage(L_DEBUG2, "SendFile: Adding fd %d to OutputSet...", con->http.fd);
1719
1720 FD_SET(con->http.fd, &OutputSet);
1721
1722 return (1);
1723 }
1724
1725
1726 /*
1727 * 'SendHeader()' - Send an HTTP request.
1728 */
1729
1730 int /* O - 1 on success, 0 on failure */
1731 SendHeader(client_t *con, /* I - Client to send to */
1732 http_status_t code, /* I - HTTP status code */
1733 char *type) /* I - MIME type of document */
1734 {
1735 location_t *loc; /* Authentication location */
1736
1737
1738 if (httpPrintf(HTTP(con), "HTTP/%d.%d %d %s\r\n", con->http.version / 100,
1739 con->http.version % 100, code, httpStatus(code)) < 0)
1740 return (0);
1741 if (httpPrintf(HTTP(con), "Date: %s\r\n", httpGetDateString(time(NULL))) < 0)
1742 return (0);
1743 if (httpPrintf(HTTP(con), "Server: CUPS/1.1\r\n") < 0)
1744 return (0);
1745 if (con->http.keep_alive && con->http.version >= HTTP_1_0)
1746 {
1747 if (httpPrintf(HTTP(con), "Connection: Keep-Alive\r\n") < 0)
1748 return (0);
1749 if (httpPrintf(HTTP(con), "Keep-Alive: timeout=%d\r\n", KeepAliveTimeout) < 0)
1750 return (0);
1751 }
1752 if (code == HTTP_METHOD_NOT_ALLOWED)
1753 if (httpPrintf(HTTP(con), "Allow: GET, HEAD, OPTIONS, POST\r\n") < 0)
1754 return (0);
1755
1756 if (code == HTTP_UNAUTHORIZED)
1757 {
1758 /*
1759 * This already succeeded in IsAuthorized...
1760 */
1761
1762 loc = FindBest(con->uri, con->http.state);
1763
1764 if (loc->type != AUTH_DIGEST)
1765 {
1766 if (httpPrintf(HTTP(con), "WWW-Authenticate: Basic realm=\"CUPS\"\r\n") < 0)
1767 return (0);
1768 }
1769 else
1770 {
1771 if (httpPrintf(HTTP(con), "WWW-Authenticate: Digest realm=\"CUPS\" "
1772 "nonce=\"%s\"\r\n", con->http.hostname) < 0)
1773 return (0);
1774 }
1775 }
1776 if (con->language != NULL)
1777 {
1778 if (httpPrintf(HTTP(con), "Content-Language: %s\r\n",
1779 con->language->language) < 0)
1780 return (0);
1781
1782 if (type != NULL)
1783 if (httpPrintf(HTTP(con), "Content-Type: %s; charset=%s\r\n", type,
1784 cupsLangEncoding(con->language)) < 0)
1785 return (0);
1786 }
1787 else if (type != NULL)
1788 if (httpPrintf(HTTP(con), "Content-Type: %s\r\n", type) < 0)
1789 return (0);
1790
1791 return (1);
1792 }
1793
1794
1795 /*
1796 * 'ShutdownClient()' - Shutdown the receiving end of a connection.
1797 */
1798
1799 void
1800 ShutdownClient(client_t *con) /* I - Client connection */
1801 {
1802 /*
1803 * Shutdown the receiving end of the socket, since the client
1804 * still needs to read the error message...
1805 */
1806
1807 shutdown(con->http.fd, 0);
1808 con->http.used = 0;
1809
1810 LogMessage(L_DEBUG2, "ShutdownClient: Removing fd %d from InputSet...",
1811 con->http.fd);
1812
1813 FD_CLR(con->http.fd, &InputSet);
1814 }
1815
1816
1817 /*
1818 * 'WriteClient()' - Write data to a client as needed.
1819 */
1820
1821 int /* O - 1 if success, 0 if fail */
1822 WriteClient(client_t *con) /* I - Client connection */
1823 {
1824 int bytes; /* Number of bytes written */
1825 char buf[HTTP_MAX_BUFFER + 1];/* Data buffer */
1826 char *bufptr; /* Pointer into buffer */
1827 ipp_state_t ipp_state; /* IPP state value */
1828
1829
1830 if (con->http.state != HTTP_GET_SEND &&
1831 con->http.state != HTTP_POST_SEND)
1832 return (1);
1833
1834 if (con->response != NULL)
1835 {
1836 ipp_state = ippWrite(&(con->http), con->response);
1837 bytes = ipp_state != IPP_ERROR && ipp_state != IPP_DATA;
1838 }
1839 else if ((bytes = read(con->file, buf, HTTP_MAX_BUFFER)) > 0)
1840 {
1841 if (con->pipe_pid && !con->got_fields)
1842 {
1843 /*
1844 * Inspect the data for Content-Type and other fields.
1845 */
1846
1847 buf[bytes] = '\0';
1848
1849 for (bufptr = buf; !con->got_fields && *bufptr; bufptr ++)
1850 if (*bufptr == '\n')
1851 {
1852 /*
1853 * Send line to client...
1854 */
1855
1856 if (bufptr > buf && bufptr[-1] == '\r')
1857 bufptr[-1] = '\0';
1858 *bufptr++ = '\0';
1859
1860 httpPrintf(HTTP(con), "%s\r\n", buf);
1861 LogMessage(L_DEBUG2, "WriteClient() %d %s", con->http.fd, buf);
1862
1863 /*
1864 * Update buffer...
1865 */
1866
1867 bytes -= (bufptr - buf);
1868 memcpy(buf, bufptr, bytes + 1);
1869 bufptr = buf - 1;
1870
1871 /*
1872 * See if the line was empty...
1873 */
1874
1875 if (con->field_col == 0)
1876 con->got_fields = 1;
1877 else
1878 con->field_col = 0;
1879 }
1880 else if (*bufptr != '\r')
1881 con->field_col ++;
1882
1883 if (bytes > 0 && !con->got_fields)
1884 {
1885 /*
1886 * Remaining text needs to go out...
1887 */
1888
1889 httpPrintf(HTTP(con), "%s", buf);
1890
1891 con->http.activity = time(NULL);
1892 return (1);
1893 }
1894 else if (bytes == 0)
1895 {
1896 con->http.activity = time(NULL);
1897 return (1);
1898 }
1899 }
1900
1901 if (httpWrite(HTTP(con), buf, bytes) < 0)
1902 {
1903 CloseClient(con);
1904 return (0);
1905 }
1906
1907 con->bytes += bytes;
1908 }
1909
1910 if (bytes <= 0)
1911 {
1912 LogRequest(con, HTTP_OK);
1913
1914 if (con->http.data_encoding == HTTP_ENCODE_CHUNKED)
1915 {
1916 if (httpPrintf(HTTP(con), "0\r\n\r\n") < 0)
1917 {
1918 CloseClient(con);
1919 return (0);
1920 }
1921 }
1922
1923 con->http.state = HTTP_WAITING;
1924
1925 LogMessage(L_DEBUG2, "WriteClient() Removing fd %d from OutputSet...",
1926 con->http.fd);
1927
1928 FD_CLR(con->http.fd, &OutputSet);
1929
1930 if (con->file)
1931 {
1932 LogMessage(L_DEBUG2, "WriteClient() Removing fd %d from InputSet...",
1933 con->file);
1934 FD_CLR(con->file, &InputSet);
1935
1936 if (con->pipe_pid)
1937 kill(con->pipe_pid, SIGTERM);
1938
1939 LogMessage(L_DEBUG2, "WriteClient() %d Closing data file %d.",
1940 con->http.fd, con->file);
1941
1942 close(con->file);
1943 con->file = 0;
1944 con->pipe_pid = 0;
1945 }
1946
1947 if (con->filename[0])
1948 {
1949 LogMessage(L_DEBUG2, "WriteClient() %d Removing temp file %s",
1950 con->http.fd, con->filename);
1951 unlink(con->filename);
1952 con->filename[0] = '\0';
1953 }
1954
1955 if (con->request != NULL)
1956 {
1957 ippDelete(con->request);
1958 con->request = NULL;
1959 }
1960
1961 if (con->response != NULL)
1962 {
1963 ippDelete(con->response);
1964 con->response = NULL;
1965 }
1966
1967 if (!con->http.keep_alive)
1968 {
1969 CloseClient(con);
1970 return (0);
1971 }
1972 }
1973
1974 if (bytes >= 1024)
1975 LogMessage(L_DEBUG2, "WriteClient() %d %d bytes", con->http.fd, bytes);
1976
1977 con->http.activity = time(NULL);
1978
1979 return (1);
1980 }
1981
1982
1983 /*
1984 * 'check_if_modified()' - Decode an "If-Modified-Since" line.
1985 */
1986
1987 static int /* O - 1 if modified since */
1988 check_if_modified(client_t *con, /* I - Client connection */
1989 struct stat *filestats) /* I - File information */
1990 {
1991 char *ptr; /* Pointer into field */
1992 time_t date; /* Time/date value */
1993 int size; /* Size/length value */
1994
1995
1996 size = 0;
1997 date = 0;
1998 ptr = con->http.fields[HTTP_FIELD_IF_MODIFIED_SINCE];
1999
2000 if (*ptr == '\0')
2001 return (1);
2002
2003 LogMessage(L_DEBUG2, "check_if_modified() %d If-Modified-Since=\"%s\"",
2004 con->http.fd, ptr);
2005
2006 while (*ptr != '\0')
2007 {
2008 while (isspace(*ptr) || *ptr == ';')
2009 ptr ++;
2010
2011 if (strncasecmp(ptr, "length=", 7) == 0)
2012 {
2013 ptr += 7;
2014 size = atoi(ptr);
2015
2016 while (isdigit(*ptr))
2017 ptr ++;
2018 }
2019 else if (isalpha(*ptr))
2020 {
2021 date = httpGetDateTime(ptr);
2022 while (*ptr != '\0' && *ptr != ';')
2023 ptr ++;
2024 }
2025 }
2026
2027 LogMessage(L_DEBUG2, "check_if_modified() %d sizes=%d,%d dates=%d,%d",
2028 con->http.fd, size, (int)filestats->st_size, (int)date,
2029 (int)filestats->st_mtime);
2030
2031 return ((size != filestats->st_size && size != 0) ||
2032 (date < filestats->st_mtime && date != 0) ||
2033 (size == 0 && date == 0));
2034 }
2035
2036
2037 /*
2038 * 'decode_auth()' - Decode an authorization string.
2039 */
2040
2041 static void
2042 decode_auth(client_t *con) /* I - Client to decode to */
2043 {
2044 char *s, /* Authorization string */
2045 value[1024]; /* Value string */
2046 const char *username; /* Certificate username */
2047
2048
2049 /*
2050 * Decode the string...
2051 */
2052
2053 s = con->http.fields[HTTP_FIELD_AUTHORIZATION];
2054
2055 LogMessage(L_DEBUG2, "decode_auth(%p): Authorization string = \"%s\"",
2056 con, s);
2057
2058 if (strncmp(s, "Basic", 5) == 0)
2059 {
2060 s += 5;
2061 while (isspace(*s))
2062 s ++;
2063
2064 httpDecode64(value, s);
2065
2066 /*
2067 * Pull the username and password out...
2068 */
2069
2070 if ((s = strchr(value, ':')) == NULL)
2071 {
2072 LogMessage(L_DEBUG, "decode_auth() %d no colon in auth string \"%s\"",
2073 con->http.fd, value);
2074 return;
2075 }
2076
2077 *s++ = '\0';
2078
2079 strlcpy(con->username, value, sizeof(con->username));
2080 strlcpy(con->password, s, sizeof(con->password));
2081 }
2082 else if (strncmp(s, "Local", 5) == 0)
2083 {
2084 s += 5;
2085 while (isspace(*s))
2086 s ++;
2087
2088 if ((username = FindCert(s)) != NULL)
2089 strlcpy(con->username, username, sizeof(con->username));
2090 }
2091 else if (strncmp(s, "Digest", 5) == 0)
2092 {
2093 /*
2094 * Get the username and password from the Digest attributes...
2095 */
2096
2097 if (httpGetSubField(&(con->http), HTTP_FIELD_WWW_AUTHENTICATE, "username",
2098 value))
2099 strlcpy(con->username, value, sizeof(con->username));
2100
2101 if (httpGetSubField(&(con->http), HTTP_FIELD_WWW_AUTHENTICATE, "response",
2102 value))
2103 strlcpy(con->password, value, sizeof(con->password) - 1);
2104 }
2105
2106 LogMessage(L_DEBUG2, "decode_auth() %d username=\"%s\"",
2107 con->http.fd, con->username);
2108 }
2109
2110
2111 /*
2112 * 'get_file()' - Get a filename and state info.
2113 */
2114
2115 static char * /* O - Real filename */
2116 get_file(client_t *con, /* I - Client connection */
2117 struct stat *filestats)/* O - File information */
2118 {
2119 int status; /* Status of filesystem calls */
2120 char *params; /* Pointer to parameters in URI */
2121 static char filename[1024]; /* Filename buffer */
2122
2123
2124 /*
2125 * Need to add DocumentRoot global...
2126 */
2127
2128 if (strncmp(con->uri, "/ppd/", 5) == 0)
2129 snprintf(filename, sizeof(filename), "%s%s", ServerRoot, con->uri);
2130 else if (strncmp(con->uri, "/admin/conf/", 12) == 0)
2131 snprintf(filename, sizeof(filename), "%s%s", ServerRoot, con->uri + 11);
2132 else if (con->language != NULL)
2133 snprintf(filename, sizeof(filename), "%s/%s%s", DocumentRoot, con->language->language,
2134 con->uri);
2135 else
2136 snprintf(filename, sizeof(filename), "%s%s", DocumentRoot, con->uri);
2137
2138 if ((params = strchr(filename, '?')) != NULL)
2139 *params = '\0';
2140
2141 /*
2142 * Grab the status for this language; if there isn't a language-specific file
2143 * then fallback to the default one...
2144 */
2145
2146 if ((status = stat(filename, filestats)) != 0 && con->language != NULL)
2147 {
2148 /*
2149 * Drop the language prefix and try the current directory...
2150 */
2151
2152 if (strncmp(con->uri, "/ppd/", 5) != 0 &&
2153 strncmp(con->uri, "/admin/conf/", 12) != 0)
2154 {
2155 snprintf(filename, sizeof(filename), "%s%s", DocumentRoot, con->uri);
2156
2157 status = stat(filename, filestats);
2158 }
2159 }
2160
2161 /*
2162 * If we're found a directory, get the index.html file instead...
2163 */
2164
2165 if (!status && S_ISDIR(filestats->st_mode))
2166 {
2167 if (filename[strlen(filename) - 1] == '/')
2168 strlcat(filename, "index.html", sizeof(filename));
2169 else
2170 strlcat(filename, "/index.html", sizeof(filename));
2171
2172 status = stat(filename, filestats);
2173 }
2174
2175 LogMessage(L_DEBUG2, "get_file() %d filename=%s size=%d",
2176 con->http.fd, filename, status ? -1 : (int)filestats->st_size);
2177
2178 if (status)
2179 return (NULL);
2180 else
2181 return (filename);
2182 }
2183
2184
2185 /*
2186 * 'install_conf_file()' - Install a configuration file.
2187 */
2188
2189 static http_status_t /* O - Status */
2190 install_conf_file(client_t *con) /* I - Connection */
2191 {
2192 FILE *in, /* Input file */
2193 *out; /* Output file */
2194 char buffer[1024]; /* Copy buffer */
2195 int bytes; /* Number of bytes */
2196 char conffile[1024], /* Configuration filename */
2197 newfile[1024], /* New config filename */
2198 oldfile[1024]; /* Old config filename */
2199 struct stat confinfo; /* Config file info */
2200
2201
2202 /*
2203 * First construct the filenames...
2204 */
2205
2206 snprintf(conffile, sizeof(conffile), "%s%s", ServerRoot, con->uri + 11);
2207 snprintf(newfile, sizeof(newfile), "%s%s.N", ServerRoot, con->uri + 11);
2208 snprintf(oldfile, sizeof(oldfile), "%s%s.O", ServerRoot, con->uri + 11);
2209
2210 LogMessage(L_INFO, "Installing config file \"%s\"...", conffile);
2211
2212 /*
2213 * Get the owner, group, and permissions of the configuration file.
2214 * If it doesn't exist, assign it to the User and Group in the
2215 * cupsd.conf file with mode 0640 permissions.
2216 */
2217
2218 if (stat(conffile, &confinfo))
2219 {
2220 confinfo.st_uid = User;
2221 confinfo.st_gid = Group;
2222 confinfo.st_mode = 0640;
2223 }
2224
2225 /*
2226 * Open the request file and new config file...
2227 */
2228
2229 if ((in = fopen(con->filename, "rb")) == NULL)
2230 {
2231 LogMessage(L_ERROR, "Unable to open request file \"%s\" - %s",
2232 con->filename, strerror(errno));
2233 return (HTTP_SERVER_ERROR);
2234 }
2235
2236 if ((out = fopen(newfile, "wb")) == NULL)
2237 {
2238 fclose(in);
2239 LogMessage(L_ERROR, "Unable to open config file \"%s\" - %s",
2240 newfile, strerror(errno));
2241 return (HTTP_SERVER_ERROR);
2242 }
2243
2244 fchmod(fileno(out), confinfo.st_mode);
2245 fchown(fileno(out), confinfo.st_uid, confinfo.st_gid);
2246
2247 /*
2248 * Copy from the request to the new config file...
2249 */
2250
2251 while ((bytes = fread(buffer, 1, sizeof(buffer), in)) > 0)
2252 if (fwrite(buffer, 1, bytes, out) < bytes)
2253 {
2254 LogMessage(L_ERROR, "Unable to copy to config file \"%s\" - %s",
2255 newfile, strerror(errno));
2256
2257 fclose(in);
2258 fclose(out);
2259 unlink(newfile);
2260
2261 return (HTTP_SERVER_ERROR);
2262 }
2263
2264 /*
2265 * Close the files...
2266 */
2267
2268 fclose(in);
2269 if (fclose(out))
2270 {
2271 LogMessage(L_ERROR, "Error file closing config file \"%s\" - %s",
2272 newfile, strerror(errno));
2273
2274 unlink(newfile);
2275
2276 return (HTTP_SERVER_ERROR);
2277 }
2278
2279 /*
2280 * Remove the request file...
2281 */
2282
2283 unlink(con->filename);
2284 con->filename[0] = '\0';
2285
2286 /*
2287 * Unlink the old backup, rename the current config file to the backup
2288 * filename, and rename the new config file to the config file name...
2289 */
2290
2291 if (unlink(oldfile))
2292 if (errno != ENOENT)
2293 {
2294 LogMessage(L_ERROR, "Unable to remove backup config file \"%s\" - %s",
2295 oldfile, strerror(errno));
2296
2297 unlink(newfile);
2298
2299 return (HTTP_SERVER_ERROR);
2300 }
2301
2302 if (rename(conffile, oldfile))
2303 if (errno != ENOENT)
2304 {
2305 LogMessage(L_ERROR, "Unable to rename old config file \"%s\" - %s",
2306 conffile, strerror(errno));
2307
2308 unlink(newfile);
2309
2310 return (HTTP_SERVER_ERROR);
2311 }
2312
2313 if (rename(newfile, conffile))
2314 {
2315 LogMessage(L_ERROR, "Unable to rename new config file \"%s\" - %s",
2316 newfile, strerror(errno));
2317
2318 rename(oldfile, conffile);
2319 unlink(newfile);
2320
2321 return (HTTP_SERVER_ERROR);
2322 }
2323
2324 /*
2325 * If the cupsd.conf file was updated, set the NeedReload flag...
2326 */
2327
2328 if (strcmp(con->uri, "/admin/conf/cupsd.conf") == 0)
2329 NeedReload = TRUE;
2330
2331 /*
2332 * Return that the file was created successfully...
2333 */
2334
2335 return (HTTP_CREATED);
2336 }
2337
2338
2339 /*
2340 * 'pipe_command()' - Pipe the output of a command to the remote client.
2341 */
2342
2343 static int /* O - Process ID */
2344 pipe_command(client_t *con, /* I - Client connection */
2345 int infile, /* I - Standard input for command */
2346 int *outfile, /* O - Standard output for command */
2347 char *command, /* I - Command to run */
2348 char *options) /* I - Options for command */
2349 {
2350 int pid; /* Process ID */
2351 char *commptr; /* Command string pointer */
2352 int fd; /* Looping var */
2353 int fds[2]; /* Pipe FDs */
2354 int argc; /* Number of arguments */
2355 int envc; /* Number of environment variables */
2356 char argbuf[10240], /* Argument buffer */
2357 *argv[100], /* Argument strings */
2358 *envp[100]; /* Environment variables */
2359 char lang[1024], /* LANG env variable */
2360 content_length[1024], /* CONTENT_LENGTH env variable */
2361 content_type[1024], /* CONTENT_TYPE env variable */
2362 ipp_port[1024], /* Default listen port */
2363 server_port[1024], /* Default server port */
2364 server_name[1024], /* Default listen hostname */
2365 remote_host[1024], /* REMOTE_HOST env variable */
2366 remote_user[1024], /* REMOTE_USER env variable */
2367 tmpdir[1024], /* TMPDIR environment variable */
2368 ldpath[1024], /* LD_LIBRARY_PATH environment variable */
2369 nlspath[1024], /* NLSPATH environment variable */
2370 datadir[1024], /* CUPS_DATADIR environment variable */
2371 root[1024], /* CUPS_SERVERROOT environment variable */
2372 query_string[10240]; /* QUERY_STRING env variable */
2373 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
2374 sigset_t oldmask, /* POSIX signal masks */
2375 newmask;
2376 struct sigaction action; /* POSIX signal handler */
2377 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
2378
2379
2380 /*
2381 * Copy the command string...
2382 */
2383
2384 strlcpy(argbuf, options, sizeof(argbuf));
2385
2386 /*
2387 * Parse the string; arguments can be separated by + and are terminated
2388 * by ?...
2389 */
2390
2391 argv[0] = argbuf;
2392
2393 for (commptr = argbuf, argc = 1; *commptr != '\0' && argc < 99; commptr ++)
2394 if (*commptr == ' ' || *commptr == '+')
2395 {
2396 *commptr++ = '\0';
2397
2398 while (*commptr == ' ')
2399 commptr ++;
2400
2401 if (*commptr != '\0')
2402 {
2403 argv[argc] = commptr;
2404 argc ++;
2405 }
2406
2407 commptr --;
2408 }
2409 else if (*commptr == '%')
2410 {
2411 if (commptr[1] >= '0' && commptr[1] <= '9')
2412 *commptr = (commptr[1] - '0') << 4;
2413 else
2414 *commptr = (tolower(commptr[1]) - 'a' + 10) << 4;
2415
2416 if (commptr[2] >= '0' && commptr[2] <= '9')
2417 *commptr |= commptr[2] - '0';
2418 else
2419 *commptr |= tolower(commptr[2]) - 'a' + 10;
2420
2421 strcpy(commptr + 1, commptr + 3);
2422 }
2423 else if (*commptr == '?')
2424 break;
2425
2426 argv[argc] = NULL;
2427
2428 if (argv[0][0] == '\0')
2429 argv[0] = strrchr(command, '/') + 1;
2430
2431 /*
2432 * Setup the environment variables as needed...
2433 */
2434
2435 snprintf(lang, sizeof(lang), "LANG=%s",
2436 con->language ? con->language->language : "C");
2437 #ifdef AF_INET6
2438 if (con->http.hostaddr.addr.sa_family == AF_INET6)
2439 {
2440 sprintf(ipp_port, "IPP_PORT=%d", ntohs(con->http.hostaddr.ipv6.sin6_port));
2441 sprintf(server_port, "SERVER_PORT=%d",
2442 ntohs(con->http.hostaddr.ipv6.sin6_port));
2443 }
2444 else
2445 #endif /* AF_INET6 */
2446 {
2447 sprintf(ipp_port, "IPP_PORT=%d", ntohs(con->http.hostaddr.ipv4.sin_port));
2448 sprintf(server_port, "SERVER_PORT=%d",
2449 ntohs(con->http.hostaddr.ipv4.sin_port));
2450 }
2451
2452 if (strcmp(con->http.hostname, "localhost") == 0)
2453 strlcpy(server_name, "SERVER_NAME=localhost", sizeof(server_name));
2454 else
2455 snprintf(server_name, sizeof(server_name), "SERVER_NAME=%s", ServerName);
2456 snprintf(remote_host, sizeof(remote_host), "REMOTE_HOST=%s", con->http.hostname);
2457 snprintf(remote_user, sizeof(remote_user), "REMOTE_USER=%s", con->username);
2458 snprintf(tmpdir, sizeof(tmpdir), "TMPDIR=%s", TempDir);
2459 snprintf(datadir, sizeof(datadir), "CUPS_DATADIR=%s", DataDir);
2460 snprintf(root, sizeof(root), "CUPS_SERVERROOT=%s", ServerRoot);
2461
2462 if (getenv("LD_LIBRARY_PATH") != NULL)
2463 snprintf(ldpath, sizeof(ldpath), "LD_LIBRARY_PATH=%s",
2464 getenv("LD_LIBRARY_PATH"));
2465 else if (getenv("DYLD_LIBRARY_PATH") != NULL)
2466 snprintf(ldpath, sizeof(ldpath), "DYLD_LIBRARY_PATH=%s",
2467 getenv("DYLD_LIBRARY_PATH"));
2468 else if (getenv("SHLIB_PATH") != NULL)
2469 snprintf(ldpath, sizeof(ldpath), "SHLIB_PATH=%s",
2470 getenv("SHLIB_PATH"));
2471 else
2472 ldpath[0] = '\0';
2473
2474 if (getenv("NLSPATH") != NULL)
2475 snprintf(nlspath, sizeof(nlspath), "NLSPATH=%s", getenv("NLSPATH"));
2476 else
2477 nlspath[0] = '\0';
2478
2479 envp[0] = "PATH=/bin:/usr/bin";
2480 envp[1] = "SERVER_SOFTWARE=CUPS/1.2";
2481 envp[2] = "GATEWAY_INTERFACE=CGI/1.1";
2482 envp[3] = "SERVER_PROTOCOL=HTTP/1.1";
2483 envp[4] = ipp_port;
2484 envp[5] = server_name;
2485 envp[6] = server_port;
2486 envp[7] = remote_host;
2487 envp[8] = remote_user;
2488 envp[9] = lang;
2489 envp[10] = TZ;
2490 envp[11] = tmpdir;
2491 envp[12] = datadir;
2492 envp[13] = root;
2493
2494 envc = 14;
2495
2496 if (ldpath[0])
2497 envp[envc ++] = ldpath;
2498
2499 if (nlspath[0])
2500 envp[envc ++] = nlspath;
2501
2502 if (con->operation == HTTP_GET)
2503 {
2504 envp[envc ++] = "REQUEST_METHOD=GET";
2505
2506 if (*commptr)
2507 {
2508 /*
2509 * Add GET form variables after ?...
2510 */
2511
2512 *commptr++ = '\0';
2513
2514 snprintf(query_string, sizeof(query_string), "QUERY_STRING=%s", commptr);
2515 envp[envc ++] = query_string;
2516 }
2517 }
2518 else
2519 {
2520 sprintf(content_length, "CONTENT_LENGTH=%d", con->bytes);
2521 snprintf(content_type, sizeof(content_type), "CONTENT_TYPE=%s",
2522 con->http.fields[HTTP_FIELD_CONTENT_TYPE]);
2523
2524 envp[envc ++] = "REQUEST_METHOD=POST";
2525 envp[envc ++] = content_length;
2526 envp[envc ++] = content_type;
2527 }
2528
2529 /*
2530 * Tell the CGI if we are using encryption...
2531 */
2532
2533 if (con->http.encryption == HTTP_ENCRYPT_ALWAYS)
2534 {
2535 envp[envc ++] = "HTTPS=ON";
2536 envp[envc ++] = "CUPS_ENCRYPTION=Always";
2537 }
2538
2539 envp[envc] = NULL;
2540
2541 /*
2542 * Create a pipe for the output...
2543 */
2544
2545 if (pipe(fds))
2546 {
2547 LogMessage(L_ERROR, "Unable to create pipes for CGI %s - %s",
2548 argv[0], strerror(errno));
2549 return (0);
2550 }
2551
2552 /*
2553 * Block signals before forking...
2554 */
2555
2556 #ifdef HAVE_SIGSET
2557 sighold(SIGTERM);
2558 sighold(SIGCHLD);
2559 #elif defined(HAVE_SIGACTION)
2560 sigemptyset(&newmask);
2561 sigaddset(&newmask, SIGTERM);
2562 sigaddset(&newmask, SIGCHLD);
2563 sigprocmask(SIG_BLOCK, &newmask, &oldmask);
2564 #endif /* HAVE_SIGSET */
2565
2566 /*
2567 * Then execute the command...
2568 */
2569
2570 if ((pid = fork()) == 0)
2571 {
2572 /*
2573 * Child comes here... Close stdin if necessary and dup the pipe to stdout.
2574 */
2575
2576 if (getuid() == 0)
2577 {
2578 /*
2579 * Running as root, so change to a non-priviledged user...
2580 */
2581
2582 if (setgid(Group))
2583 exit(errno);
2584
2585 if (setuid(User))
2586 exit(errno);
2587 }
2588
2589 /*
2590 * Reset group membership to just the main one we belong to.
2591 */
2592
2593 setgroups(0, NULL);
2594
2595 /*
2596 * Update stdin/stdout/stderr...
2597 */
2598
2599 if (infile)
2600 {
2601 close(0);
2602 if (dup(infile) < 0)
2603 exit(errno);
2604 }
2605
2606 close(1);
2607 if (dup(fds[1]) < 0)
2608 exit(errno);
2609
2610 close(2);
2611 open("/dev/null", O_WRONLY);
2612
2613 /*
2614 * Close extra file descriptors...
2615 */
2616
2617 for (fd = 3; fd < MaxFDs; fd ++)
2618 close(fd);
2619
2620 /*
2621 * Change umask to restrict permissions on created files...
2622 */
2623
2624 umask(077);
2625
2626 /*
2627 * Unblock signals before doing the exec...
2628 */
2629
2630 #ifdef HAVE_SIGSET
2631 sigset(SIGTERM, SIG_DFL);
2632 sigset(SIGCHLD, SIG_DFL);
2633
2634 sigrelse(SIGTERM);
2635 sigrelse(SIGCHLD);
2636 #elif defined(HAVE_SIGACTION)
2637 memset(&action, 0, sizeof(action));
2638
2639 sigemptyset(&action.sa_mask);
2640 action.sa_handler = SIG_DFL;
2641
2642 sigaction(SIGTERM, &action, NULL);
2643 sigaction(SIGCHLD, &action, NULL);
2644
2645 sigprocmask(SIG_SETMASK, &oldmask, NULL);
2646 #else
2647 signal(SIGTERM, SIG_DFL);
2648 signal(SIGCHLD, SIG_DFL);
2649 #endif /* HAVE_SIGSET */
2650
2651
2652 /*
2653 * Execute the pipe program; if an error occurs, exit with status 1...
2654 */
2655
2656 execve(command, argv, envp);
2657 exit(errno);
2658 return (0);
2659 }
2660 else if (pid < 0)
2661 {
2662 /*
2663 * Error - can't fork!
2664 */
2665
2666 LogMessage(L_ERROR, "Unable to fork for CGI %s - %s", argv[0],
2667 strerror(errno));
2668
2669 close(fds[0]);
2670 close(fds[1]);
2671 pid = 0;
2672 }
2673 else
2674 {
2675 /*
2676 * Fork successful - return the PID...
2677 */
2678
2679 AddCert(pid, con->username);
2680
2681 LogMessage(L_DEBUG, "CGI %s started - PID = %d", command, pid);
2682
2683 *outfile = fds[0];
2684 close(fds[1]);
2685 }
2686
2687 #ifdef HAVE_SIGSET
2688 sigrelse(SIGTERM);
2689 sigrelse(SIGCHLD);
2690 #elif defined(HAVE_SIGACTION)
2691 sigprocmask(SIG_SETMASK, &oldmask, NULL);
2692 #endif /* HAVE_SIGSET */
2693
2694 return (pid);
2695 }
2696
2697
2698 /*
2699 * End of "$Id: client.c,v 1.91.2.32 2003/01/13 18:41:42 mike Exp $".
2700 */