]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/client.c
Mirror 1.1.x changes.
[thirdparty/cups.git] / scheduler / client.c
1 /*
2 * "$Id: client.c,v 1.91.2.60 2003/05/09 16:10:38 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 * IsCGI() - Is the resource a CGI script/program?
31 * ReadClient() - Read data from a client.
32 * SendCommand() - Send output from a command via HTTP.
33 * SendError() - Send an error message via HTTP.
34 * SendFile() - Send a file via HTTP.
35 * SendHeader() - Send an HTTP request.
36 * ShutdownClient() - Shutdown the receiving end of a connection.
37 * UpdateCGI() - Read status messages from CGI scripts and programs.
38 * WriteClient() - Write data to a client as needed.
39 * check_if_modified() - Decode an "If-Modified-Since" line.
40 * decode_auth() - Decode an authorization string.
41 * get_file() - Get a filename and state info.
42 * install_conf_file() - Install a configuration file.
43 * pipe_command() - Pipe the output of a command to the remote client.
44 * CDSAReadFunc() - Read function for CDSA decryption code.
45 * CDSAWriteFunc() - Write function for CDSA encryption code.
46 */
47
48 /*
49 * Include necessary headers...
50 */
51
52 #include <cups/http-private.h>
53 #include "cupsd.h"
54 #include <grp.h>
55
56
57 /*
58 * Local functions...
59 */
60
61 static int check_if_modified(client_t *con,
62 struct stat *filestats);
63 static void decode_auth(client_t *con);
64 static char *get_file(client_t *con, struct stat *filestats,
65 char *filename, int len);
66 static http_status_t install_conf_file(client_t *con);
67 static int pipe_command(client_t *con, int infile, int *outfile,
68 char *command, char *options);
69
70 #ifdef HAVE_CDSASSL
71 static OSStatus CDSAReadFunc(SSLConnectionRef connection, void *data,
72 size_t *dataLength);
73 static OSStatus CDSAWriteFunc(SSLConnectionRef connection,
74 const void *data, size_t *dataLength);
75 #endif /* HAVE_CDSASSL */
76
77
78 /*
79 * 'AcceptClient()' - Accept a new client.
80 */
81
82 void
83 AcceptClient(listener_t *lis) /* I - Listener socket */
84 {
85 int i; /* Looping var */
86 int count; /* Count of connections on a host */
87 int val; /* Parameter value */
88 client_t *con; /* New client pointer */
89 const struct hostent *host; /* Host entry for address */
90 char *hostname;/* Hostname for address */
91 http_addr_t temp; /* Temporary address variable */
92 static time_t last_dos = 0;
93 /* Time of last DoS attack */
94
95
96 LogMessage(L_DEBUG2, "AcceptClient(%p) %d NumClients = %d",
97 lis, lis->fd, NumClients);
98
99 /*
100 * Make sure we don't have a full set of clients already...
101 */
102
103 if (NumClients == MaxClients)
104 return;
105
106 /*
107 * Get a pointer to the next available client...
108 */
109
110 con = Clients + NumClients;
111
112 memset(con, 0, sizeof(client_t));
113 con->http.activity = time(NULL);
114
115 /*
116 * Accept the client and get the remote address...
117 */
118
119 val = sizeof(struct sockaddr_in);
120
121 if ((con->http.fd = accept(lis->fd, (struct sockaddr *)&(con->http.hostaddr),
122 &val)) < 0)
123 {
124 LogMessage(L_ERROR, "Unable to accept client connection - %s.",
125 strerror(errno));
126 return;
127 }
128
129 #ifdef AF_INET6
130 if (lis->address.addr.sa_family == AF_INET6)
131 con->http.hostaddr.ipv6.sin6_port = lis->address.ipv6.sin6_port;
132 else
133 #endif /* AF_INET6 */
134 con->http.hostaddr.ipv4.sin_port = lis->address.ipv4.sin_port;
135
136 /*
137 * Check the number of clients on the same address...
138 */
139
140 for (i = 0, count = 0; i < NumClients; i ++)
141 if (memcmp(&(Clients[i].http.hostaddr), &(con->http.hostaddr),
142 sizeof(con->http.hostaddr)) == 0)
143 {
144 count ++;
145 if (count >= MaxClientsPerHost)
146 break;
147 }
148
149 if (count >= MaxClientsPerHost)
150 {
151 if ((time(NULL) - last_dos) >= 60)
152 {
153 last_dos = time(NULL);
154 LogMessage(L_WARN, "Possible DoS attack - more than %d clients connecting from %s!",
155 MaxClientsPerHost, Clients[i].http.hostname);
156 }
157
158 #ifdef WIN32
159 closesocket(con->http.fd);
160 #else
161 close(con->http.fd);
162 #endif /* WIN32 */
163
164 return;
165 }
166
167 /*
168 * Get the hostname or format the IP address as needed...
169 */
170
171 if (HostNameLookups)
172 hostname = httpAddrLookup(&(con->http.hostaddr), con->http.hostname,
173 sizeof(con->http.hostname));
174 else
175 {
176 hostname = NULL;
177 httpAddrString(&(con->http.hostaddr), con->http.hostname,
178 sizeof(con->http.hostname));
179 }
180
181 if (httpAddrLocalhost(&(con->http.hostaddr)))
182 {
183 /*
184 * Map accesses from the loopback interface to "localhost"...
185 */
186
187 strlcpy(con->http.hostname, "localhost", sizeof(con->http.hostname));
188 }
189 else if (httpAddrEqual(&(con->http.hostaddr), &ServerAddr))
190 {
191 /*
192 * Map accesses from the same host to the server name.
193 */
194
195 strlcpy(con->http.hostname, ServerName, sizeof(con->http.hostname));
196 }
197
198 if (hostname == NULL && HostNameLookups == 2)
199 {
200 /*
201 * Can't have an unresolved IP address with double-lookups enabled...
202 */
203
204 LogMessage(L_DEBUG2, "AcceptClient: Closing connection %d...",
205 con->http.fd);
206
207 #ifdef WIN32
208 closesocket(con->http.fd);
209 #else
210 close(con->http.fd);
211 #endif /* WIN32 */
212
213 LogMessage(L_WARN, "Name lookup failed - connection from %s closed!",
214 con->http.hostname);
215 return;
216 }
217
218 if (HostNameLookups == 2)
219 {
220 /*
221 * Do double lookups as needed...
222 */
223
224 if ((host = httpGetHostByName(con->http.hostname)) != NULL)
225 {
226 /*
227 * See if the hostname maps to the same IP address...
228 */
229
230 if (host->h_addrtype != con->http.hostaddr.addr.sa_family)
231 {
232 /*
233 * Not the right type of address...
234 */
235
236 host = NULL;
237 }
238 else
239 {
240 /*
241 * Compare all of the addresses against this one...
242 */
243
244 for (i = 0; host->h_addr_list[i]; i ++)
245 {
246 httpAddrLoad(host, 0, i, &temp);
247
248 if (httpAddrEqual(&(con->http.hostaddr), &temp))
249 break;
250 }
251
252 if (!host->h_addr_list[i])
253 host = NULL;
254 }
255 }
256
257 if (host == NULL)
258 {
259 /*
260 * Can't have a hostname that doesn't resolve to the same IP address
261 * with double-lookups enabled...
262 */
263
264 LogMessage(L_DEBUG2, "AcceptClient: Closing connection %d...",
265 con->http.fd);
266
267 #ifdef WIN32
268 closesocket(con->http.fd);
269 #else
270 close(con->http.fd);
271 #endif /* WIN32 */
272
273 LogMessage(L_WARN, "IP lookup failed - connection from %s closed!",
274 con->http.hostname);
275 return;
276 }
277 }
278
279 #ifdef AF_INET6
280 if (con->http.hostaddr.addr.sa_family == AF_INET6)
281 LogMessage(L_DEBUG, "AcceptClient: %d from %s:%d.", con->http.fd,
282 con->http.hostname, ntohs(con->http.hostaddr.ipv6.sin6_port));
283 else
284 #endif /* AF_INET6 */
285 LogMessage(L_DEBUG, "AcceptClient: %d from %s:%d.", con->http.fd,
286 con->http.hostname, ntohs(con->http.hostaddr.ipv4.sin_port));
287
288 /*
289 * Using TCP_NODELAY improves responsiveness, especially on systems
290 * with a slow loopback interface... Since we write large buffers
291 * when sending print files and requests, there shouldn't be any
292 * performance penalty for this...
293 */
294
295 val = 1;
296 setsockopt(con->http.fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
297
298 /*
299 * Close this file on all execs...
300 */
301
302 fcntl(con->http.fd, F_SETFD, fcntl(con->http.fd, F_GETFD) | FD_CLOEXEC);
303
304 /*
305 * Add the socket to the select() input mask.
306 */
307
308 LogMessage(L_DEBUG2, "AcceptClient: Adding fd %d to InputSet...",
309 con->http.fd);
310 FD_SET(con->http.fd, InputSet);
311
312 NumClients ++;
313
314 /*
315 * Temporarily suspend accept()'s until we lose a client...
316 */
317
318 if (NumClients == MaxClients)
319 PauseListening();
320
321 #ifdef HAVE_SSL
322 /*
323 * See if we are connecting on a secure port...
324 */
325
326 if (lis->encryption == HTTP_ENCRYPT_ALWAYS)
327 {
328 /*
329 * https connection; go secure...
330 */
331
332 con->http.encryption = HTTP_ENCRYPT_ALWAYS;
333
334 EncryptClient(con);
335 }
336 #endif /* HAVE_SSL */
337 }
338
339
340 /*
341 * 'CloseAllClients()' - Close all remote clients immediately.
342 */
343
344 void
345 CloseAllClients(void)
346 {
347 while (NumClients > 0)
348 CloseClient(Clients);
349 }
350
351
352 /*
353 * 'CloseClient()' - Close a remote client.
354 */
355
356 void
357 CloseClient(client_t *con) /* I - Client to close */
358 {
359 int status; /* Exit status of pipe command */
360 #if defined(HAVE_LIBSSL)
361 SSL_CTX *context; /* Context for encryption */
362 SSL *conn; /* Connection for encryption */
363 unsigned long error; /* Error code */
364 #elif defined(HAVE_GNUTLS)
365 http_tls_t *conn; /* TLS connection information */
366 int error; /* Error code */
367 gnutls_certificate_server_credentials *credentials;
368 /* TLS credentials */
369 #endif /* HAVE_GNUTLS */
370
371
372 LogMessage(L_DEBUG, "CloseClient() %d", con->http.fd);
373
374 if (con->http.input_set)
375 free(con->http.input_set);
376
377 httpClearCookie(HTTP(con));
378
379 ClearString(&con->filename);
380 ClearString(&con->command);
381 ClearString(&con->options);
382
383 #ifdef HAVE_SSL
384 /*
385 * Shutdown encryption as needed...
386 */
387
388 if (con->http.tls)
389 {
390 # ifdef HAVE_LIBSSL
391 conn = (SSL *)(con->http.tls);
392 context = SSL_get_SSL_CTX(conn);
393
394 switch (SSL_shutdown(conn))
395 {
396 case 1 :
397 LogMessage(L_INFO, "CloseClient: SSL shutdown successful!");
398 break;
399 case -1 :
400 LogMessage(L_ERROR, "CloseClient: Fatal error during SSL shutdown!");
401 default :
402 while ((error = ERR_get_error()) != 0)
403 LogMessage(L_ERROR, "CloseClient: %s", ERR_error_string(error, NULL));
404 break;
405 }
406
407 SSL_CTX_free(context);
408 SSL_free(conn);
409
410 # elif defined(HAVE_GNUTLS)
411 conn = (http_tls_t *)(con->http.tls);
412 credentials = (gnutls_certificate_server_credentials *)(conn->credentials);
413
414 error = gnutls_bye(conn->session, GNUTLS_SHUT_WR);
415 switch (error)
416 {
417 case GNUTLS_E_SUCCESS:
418 LogMessage(L_INFO, "CloseClient: SSL shutdown successful!");
419 break;
420 default:
421 LogMessage(L_ERROR, "CloseClient: %s", gnutls_strerror(error));
422 break;
423 }
424
425 gnutls_deinit(conn->session);
426 gnutls_certificate_free_credentials(*credentials);
427 free(credentials);
428 free(conn);
429
430 # elif defined(HAVE_CDSASSL)
431 status = SSLClose((SSLContextRef)con->http.tls);
432 SSLDisposeContext((SSLContextRef)con->http.tls);
433 # endif /* HAVE_LIBSSL */
434
435 con->http.tls = NULL;
436 }
437 #endif /* HAVE_SSL */
438
439 /*
440 * Close the socket and clear the file from the input set for select()...
441 */
442
443 if (con->http.fd >= 0)
444 {
445 LogMessage(L_DEBUG2, "CloseClient: Removing fd %d from InputSet and OutputSet...",
446 con->http.fd);
447 close(con->http.fd);
448 FD_CLR(con->http.fd, InputSet);
449 FD_CLR(con->http.fd, OutputSet);
450 con->http.fd = 0;
451 }
452
453 if (con->pipe_pid != 0)
454 {
455 LogMessage(L_DEBUG2, "CloseClient: Removing fd %d from InputSet...",
456 con->file);
457 FD_CLR(con->file, InputSet);
458 }
459
460 if (con->file)
461 {
462 /*
463 * Close the open data file...
464 */
465
466 if (con->pipe_pid)
467 {
468 kill(con->pipe_pid, SIGKILL);
469 waitpid(con->pipe_pid, &status, WNOHANG);
470 }
471
472 LogMessage(L_DEBUG2, "CloseClient() %d Closing data file %d.",
473 con->http.fd, con->file);
474 LogMessage(L_DEBUG2, "CloseClient() %d Removing fd %d from InputSet.",
475 con->http.fd, con->file);
476
477 FD_CLR(con->file, InputSet);
478 close(con->file);
479 con->file = 0;
480 }
481
482 if (con->request)
483 {
484 ippDelete(con->request);
485 con->request = NULL;
486 }
487
488 if (con->response)
489 {
490 ippDelete(con->response);
491 con->response = NULL;
492 }
493
494 if (con->language)
495 {
496 cupsLangFree(con->language);
497 con->language = NULL;
498 }
499
500 /*
501 * Re-enable new client connections if we are going back under the
502 * limit...
503 */
504
505 if (NumClients == MaxClients)
506 ResumeListening();
507
508 /*
509 * Compact the list of clients as necessary...
510 */
511
512 NumClients --;
513
514 if (con < (Clients + NumClients))
515 memcpy(con, con + 1, (Clients + NumClients - con) * sizeof(client_t));
516 }
517
518
519 /*
520 * 'EncryptClient()' - Enable encryption for the client...
521 */
522
523 int /* O - 1 on success, 0 on error */
524 EncryptClient(client_t *con) /* I - Client to encrypt */
525 {
526 #if defined HAVE_LIBSSL
527 SSL_CTX *context; /* Context for encryption */
528 SSL *conn; /* Connection for encryption */
529 unsigned long error; /* Error code */
530
531
532 /*
533 * Create the SSL context and accept the connection...
534 */
535
536 context = SSL_CTX_new(SSLv23_server_method());
537
538 SSL_CTX_use_PrivateKey_file(context, ServerKey, SSL_FILETYPE_PEM);
539 SSL_CTX_use_certificate_file(context, ServerCertificate, SSL_FILETYPE_PEM);
540
541 conn = SSL_new(context);
542
543 SSL_set_fd(conn, con->http.fd);
544 if (SSL_accept(conn) != 1)
545 {
546 while ((error = ERR_get_error()) != 0)
547 LogMessage(L_ERROR, "EncryptClient: %s", ERR_error_string(error, NULL));
548
549 SSL_CTX_free(context);
550 SSL_free(conn);
551 return (0);
552 }
553
554 con->http.tls = conn;
555 return (1);
556
557 #elif defined(HAVE_GNUTLS)
558 http_tls_t *conn; /* TLS session object */
559 int error; /* Error code */
560 gnutls_certificate_server_credentials *credentials;
561 /* TLS credentials */
562
563 /*
564 * Create the SSL object and perform the SSL handshake...
565 */
566
567 conn = (http_tls_t *)malloc(sizeof(gnutls_session));
568
569 if (conn == NULL)
570 return (0);
571
572 credentials = (gnutls_certificate_server_credentials *)
573 malloc(sizeof(gnutls_certificate_server_credentials));
574 if (credentials == NULL)
575 {
576 free(conn);
577 return (0);
578 }
579
580 gnutls_certificate_allocate_credentials(credentials);
581 gnutls_certificate_set_x509_key_file(*credentials, ServerCertificate,
582 ServerKey, GNUTLS_X509_FMT_PEM);
583
584 gnutls_init(&(conn->session), GNUTLS_SERVER);
585 gnutls_set_default_priority(conn->session);
586 gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE, *credentials);
587 gnutls_transport_set_ptr(conn->session, con->http.fd);
588
589 error = gnutls_handshake(conn->session);
590
591 if (error != GNUTLS_E_SUCCESS)
592 {
593 LogMessage(L_ERROR, "EncryptClient: %s", gnutls_strerror(error));
594 gnutls_deinit(conn->session);
595 gnutls_certificate_free_credentials(*credentials);
596 free(conn);
597 free(credentials);
598 return (0);
599 }
600
601 LogMessage(L_DEBUG, "EncryptClient() %d Connection now encrypted.",
602 con->http.fd);
603
604 conn->credentials = credentials;
605 con->http.tls = conn;
606 return (1);
607
608 #elif defined(HAVE_CDSASSL)
609 OSStatus error; /* Error info */
610 SSLContextRef conn; /* New connection */
611 SSLProtocol tryVersion; /* Protocol version */
612 const char *hostName; /* Local hostname */
613 int allowExpired; /* Allow expired certificates? */
614 int allowAnyRoot; /* Allow any root certificate? */
615 SSLProtocol *negVersion; /* Negotiated protocol version */
616 SSLCipherSuite *negCipher; /* Negotiated cypher */
617 CFArrayRef *peerCerts; /* Certificates */
618
619
620 conn = NULL;
621 error = SSLNewContext(true, &conn);
622 allowExpired = 1;
623 allowAnyRoot = 1;
624
625 if (!error)
626 error = SSLSetIOFuncs(conn, CDSAReadFunc, CDSAWriteFunc);
627
628 if (!error)
629 error = SSLSetProtocolVersion(conn, kSSLProtocol3);
630
631 if (!error)
632 error = SSLSetConnection(conn, (SSLConnectionRef)con->http.fd);
633
634 if (!error)
635 {
636 hostName = ServerName; /* MRS: ??? */
637 error = SSLSetPeerDomainName(conn, hostName, strlen(hostName) + 1);
638 }
639
640 /* have to do these options befor setting server certs */
641 if (!error && allowExpired)
642 error = SSLSetAllowsExpiredCerts(conn, true);
643
644 if (!error && allowAnyRoot)
645 error = SSLSetAllowsAnyRoot(conn, true);
646
647 if (!error && ServerCertificatesArray != NULL)
648 error = SSLSetCertificate(conn, ServerCertificatesArray);
649
650 /*
651 * Perform SSL/TLS handshake
652 */
653
654 do
655 {
656 error = SSLHandshake(conn);
657 }
658 while (error == errSSLWouldBlock);
659
660 if (error)
661 {
662 LogMessage(L_ERROR, "EncryptClient: %d", error);
663
664 con->http.error = error;
665 con->http.status = HTTP_ERROR;
666
667 if (conn != NULL)
668 SSLDisposeContext(conn);
669
670 return (0);
671 }
672
673 LogMessage(L_DEBUG, "EncryptClient() %d Connection now encrypted.",
674 con->http.fd);
675 con->http.tls = conn;
676 return (1);
677
678 #else
679 return (0);
680 #endif /* HAVE_GNUTLS */
681 }
682
683
684 /*
685 * 'IsCGI()' - Is the resource a CGI script/program?
686 */
687
688 int /* O - 1 = CGI, 0 = file */
689 IsCGI(client_t *con, /* I - Client connection */
690 const char *filename, /* I - Real filename */
691 struct stat *filestats, /* I - File information */
692 mime_type_t *type) /* I - MIME type */
693 {
694 const char *options; /* Options on URL */
695
696
697 LogMessage(L_DEBUG2, "IsCGI(con=%p, filename=\"%s\", filestats=%p, type=%s/%s)\n",
698 con, filename, filestats, type ? type->super : "unknown",
699 type ? type->type : "unknown");
700
701 /*
702 * Get the options, if any...
703 */
704
705 if ((options = strchr(con->uri, '?')) != NULL)
706 options ++;
707
708 /*
709 * Check for known types...
710 */
711
712 if (strcasecmp(type->super, "application"))
713 {
714 LogMessage(L_DEBUG2, "IsCGI: Returning 0...");
715 return (0);
716 }
717
718 if (!strcasecmp(type->type, "x-httpd-cgi") &&
719 (filestats->st_mode & 0111))
720 {
721 /*
722 * "application/x-httpd-cgi" is a CGI script.
723 */
724
725 SetString(&con->command, filename);
726
727 filename = strrchr(filename, '/') + 1; /* Filename always absolute */
728
729 if (options)
730 SetStringf(&con->options, "%s %s", filename, options);
731 else
732 SetStringf(&con->options, "%s", filename);
733
734 LogMessage(L_DEBUG2, "IsCGI: Returning 1 with command=\"%s\" and options=\"%s\"",
735 con->command, con->options);
736
737 return (1);
738 }
739 #ifdef HAVE_JAVA
740 else if (!strcasecmp(type->type, "x-httpd-java"))
741 {
742 /*
743 * "application/x-httpd-java" is a Java servlet.
744 */
745
746 SetString(&con->command, CUPS_JAVA);
747
748 if (options)
749 SetStringf(&con->options, "java %s %s", filename, options);
750 else
751 SetStringf(&con->options, "java %s", filename);
752
753 LogMessage(L_DEBUG2, "IsCGI: Returning 1 with command=\"%s\" and options=\"%s\"",
754 con->command, con->options);
755
756 return (1);
757 }
758 #endif /* HAVE_JAVA */
759 #ifdef HAVE_PERL
760 else if (!strcasecmp(type->type, "x-httpd-perl"))
761 {
762 /*
763 * "application/x-httpd-perl" is a Perl page.
764 */
765
766 SetString(&con->command, CUPS_PERL);
767
768 if (options)
769 SetStringf(&con->options, "perl %s %s", filename, options);
770 else
771 SetStringf(&con->options, "perl %s", filename);
772
773 LogMessage(L_DEBUG2, "IsCGI: Returning 1 with command=\"%s\" and options=\"%s\"",
774 con->command, con->options);
775
776 return (1);
777 }
778 #endif /* HAVE_PERL */
779 #ifdef HAVE_PHP
780 else if (!strcasecmp(type->type, "x-httpd-php"))
781 {
782 /*
783 * "application/x-httpd-php" is a PHP page.
784 */
785
786 SetString(&con->command, CUPS_PHP);
787
788 if (options)
789 SetStringf(&con->options, "php %s %s", filename, options);
790 else
791 SetStringf(&con->options, "php %s", filename);
792
793 LogMessage(L_DEBUG2, "IsCGI: Returning 1 with command=\"%s\" and options=\"%s\"",
794 con->command, con->options);
795
796 return (1);
797 }
798 #endif /* HAVE_PHP */
799 #ifdef HAVE_PYTHON
800 else if (!strcasecmp(type->type, "x-httpd-python"))
801 {
802 /*
803 * "application/x-httpd-python" is a Python page.
804 */
805
806 SetString(&con->command, CUPS_PYTHON);
807
808 if (options)
809 SetStringf(&con->options, "python %s %s", filename, options);
810 else
811 SetStringf(&con->options, "python %s", filename);
812
813 LogMessage(L_DEBUG2, "IsCGI: Returning 1 with command=\"%s\" and options=\"%s\"",
814 con->command, con->options);
815
816 return (1);
817 }
818 #endif /* HAVE_PYTHON */
819
820 LogMessage(L_DEBUG2, "IsCGI: Returning 0...");
821
822 return (0);
823 }
824
825
826 /*
827 * 'ReadClient()' - Read data from a client.
828 */
829
830 int /* O - 1 on success, 0 on error */
831 ReadClient(client_t *con) /* I - Client to read from */
832 {
833 char line[32768], /* Line from client... */
834 operation[64], /* Operation code from socket */
835 version[64]; /* HTTP version number string */
836 int major, minor; /* HTTP version numbers */
837 http_status_t status; /* Transfer status */
838 ipp_state_t ipp_state; /* State of IPP transfer */
839 int bytes; /* Number of bytes to POST */
840 char *filename; /* Name of file for GET/HEAD */
841 char buf[1024]; /* Buffer for real filename */
842 struct stat filestats; /* File information */
843 mime_type_t *type; /* MIME type of file */
844 printer_t *p; /* Printer */
845 location_t *best; /* Best match for authentication */
846 static unsigned request_id = 0;/* Request ID for temp files */
847
848
849 status = HTTP_CONTINUE;
850
851 LogMessage(L_DEBUG2, "ReadClient() %d, used=%d", con->http.fd,
852 con->http.used);
853
854 if (con->http.error)
855 {
856 CloseClient(con);
857 return (0);
858 }
859
860 switch (con->http.state)
861 {
862 case HTTP_WAITING :
863 /*
864 * See if we've received a request line...
865 */
866
867 if (httpGets(line, sizeof(line) - 1, HTTP(con)) == NULL)
868 {
869 CloseClient(con);
870 return (0);
871 }
872
873 /*
874 * Ignore blank request lines...
875 */
876
877 if (line[0] == '\0')
878 break;
879
880 /*
881 * Clear other state variables...
882 */
883
884 httpClearFields(HTTP(con));
885
886 con->http.activity = time(NULL);
887 con->http.version = HTTP_1_0;
888 con->http.keep_alive = HTTP_KEEPALIVE_OFF;
889 con->http.data_encoding = HTTP_ENCODE_LENGTH;
890 con->http.data_remaining = 0;
891 con->operation = HTTP_WAITING;
892 con->bytes = 0;
893 con->file = 0;
894 con->pipe_pid = 0;
895 con->username[0] = '\0';
896 con->password[0] = '\0';
897 con->uri[0] = '\0';
898
899 ClearString(&con->command);
900 ClearString(&con->options);
901
902 if (con->language != NULL)
903 {
904 cupsLangFree(con->language);
905 con->language = NULL;
906 }
907
908 /*
909 * Grab the request line...
910 */
911
912 switch (sscanf(line, "%63s%1023s%63s", operation, con->uri, version))
913 {
914 case 1 :
915 LogMessage(L_ERROR, "Bad request line \"%s\"!", line);
916 SendError(con, HTTP_BAD_REQUEST);
917 ShutdownClient(con);
918 return (1);
919 case 2 :
920 con->http.version = HTTP_0_9;
921 break;
922 case 3 :
923 if (sscanf(version, "HTTP/%d.%d", &major, &minor) != 2)
924 {
925 LogMessage(L_ERROR, "Bad request line \"%s\"!", line);
926 SendError(con, HTTP_BAD_REQUEST);
927 ShutdownClient(con);
928 return (1);
929 }
930
931 if (major < 2)
932 {
933 con->http.version = (http_version_t)(major * 100 + minor);
934 if (con->http.version == HTTP_1_1 && KeepAlive)
935 con->http.keep_alive = HTTP_KEEPALIVE_ON;
936 else
937 con->http.keep_alive = HTTP_KEEPALIVE_OFF;
938 }
939 else
940 {
941 SendError(con, HTTP_NOT_SUPPORTED);
942 ShutdownClient(con);
943 return (1);
944 }
945 break;
946 }
947
948 /*
949 * Handle full URLs in the request line...
950 */
951
952 if (con->uri[0] != '/' && strcmp(con->uri, "*"))
953 {
954 char method[HTTP_MAX_URI], /* Method/scheme */
955 userpass[HTTP_MAX_URI], /* Username:password */
956 hostname[HTTP_MAX_URI], /* Hostname */
957 resource[HTTP_MAX_URI]; /* Resource path */
958 int port; /* Port number */
959
960
961 /*
962 * Separate the URI into its components...
963 */
964
965 httpSeparate(con->uri, method, userpass, hostname, &port, resource);
966
967 /*
968 * Only allow URIs with the servername, localhost, or an IP
969 * address...
970 */
971
972 if (strcasecmp(hostname, ServerName) &&
973 strcasecmp(hostname, "localhost") &&
974 !isdigit(hostname[0]))
975 {
976 /*
977 * Nope, we don't do proxies...
978 */
979
980 LogMessage(L_ERROR, "Bad URI \"%s\" in request!", con->uri);
981 SendError(con, HTTP_METHOD_NOT_ALLOWED);
982 ShutdownClient(con);
983 return (1);
984 }
985
986 /*
987 * Copy the resource portion back into the URI; both resource and
988 * con->uri are HTTP_MAX_URI bytes in size...
989 */
990
991 strcpy(con->uri, resource);
992 }
993
994 /*
995 * Process the request...
996 */
997
998 if (strcmp(operation, "GET") == 0)
999 con->http.state = HTTP_GET;
1000 else if (strcmp(operation, "PUT") == 0)
1001 con->http.state = HTTP_PUT;
1002 else if (strcmp(operation, "POST") == 0)
1003 con->http.state = HTTP_POST;
1004 else if (strcmp(operation, "DELETE") == 0)
1005 con->http.state = HTTP_DELETE;
1006 else if (strcmp(operation, "TRACE") == 0)
1007 con->http.state = HTTP_TRACE;
1008 else if (strcmp(operation, "OPTIONS") == 0)
1009 con->http.state = HTTP_OPTIONS;
1010 else if (strcmp(operation, "HEAD") == 0)
1011 con->http.state = HTTP_HEAD;
1012 else
1013 {
1014 LogMessage(L_ERROR, "Bad operation \"%s\"!", operation);
1015 SendError(con, HTTP_BAD_REQUEST);
1016 ShutdownClient(con);
1017 return (1);
1018 }
1019
1020 con->start = time(NULL);
1021 con->operation = con->http.state;
1022
1023 LogMessage(L_DEBUG, "ReadClient() %d %s %s HTTP/%d.%d", con->http.fd,
1024 operation, con->uri,
1025 con->http.version / 100, con->http.version % 100);
1026
1027 con->http.status = HTTP_OK;
1028
1029 case HTTP_OPTIONS :
1030 case HTTP_DELETE :
1031 case HTTP_GET :
1032 case HTTP_HEAD :
1033 case HTTP_POST :
1034 case HTTP_PUT :
1035 case HTTP_TRACE :
1036 /*
1037 * Parse incoming parameters until the status changes...
1038 */
1039
1040 status = httpUpdate(HTTP(con));
1041
1042 if (status != HTTP_OK && status != HTTP_CONTINUE)
1043 {
1044 SendError(con, HTTP_BAD_REQUEST);
1045 ShutdownClient(con);
1046 return (1);
1047 }
1048 break;
1049
1050 default :
1051 break; /* Anti-compiler-warning-code */
1052 }
1053
1054 /*
1055 * Handle new transfers...
1056 */
1057
1058 if (status == HTTP_OK)
1059 {
1060 con->language = cupsLangGet(con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE]);
1061
1062 decode_auth(con);
1063
1064 if (strncmp(con->http.fields[HTTP_FIELD_CONNECTION], "Keep-Alive", 10) == 0 &&
1065 KeepAlive)
1066 con->http.keep_alive = HTTP_KEEPALIVE_ON;
1067
1068 if (con->http.fields[HTTP_FIELD_HOST][0] == '\0' &&
1069 con->http.version >= HTTP_1_1)
1070 {
1071 /*
1072 * HTTP/1.1 and higher require the "Host:" field...
1073 */
1074
1075 if (!SendError(con, HTTP_BAD_REQUEST))
1076 {
1077 CloseClient(con);
1078 return (0);
1079 }
1080 }
1081 else if (con->operation == HTTP_OPTIONS)
1082 {
1083 /*
1084 * Do OPTIONS command...
1085 */
1086
1087 if ((best = FindBest(con->uri, con->http.state)) != NULL &&
1088 best->type != AUTH_NONE)
1089 {
1090 if (!SendHeader(con, HTTP_UNAUTHORIZED, NULL))
1091 {
1092 CloseClient(con);
1093 return (0);
1094 }
1095 }
1096
1097 if (strcasecmp(con->http.fields[HTTP_FIELD_CONNECTION], "Upgrade") == 0 &&
1098 con->http.tls == NULL)
1099 {
1100 #ifdef HAVE_SSL
1101 /*
1102 * Do encryption stuff...
1103 */
1104
1105 if (!SendHeader(con, HTTP_SWITCHING_PROTOCOLS, NULL))
1106 {
1107 CloseClient(con);
1108 return (0);
1109 }
1110
1111 httpPrintf(HTTP(con), "Connection: Upgrade\r\n");
1112 httpPrintf(HTTP(con), "Upgrade: TLS/1.0,HTTP/1.1\r\n");
1113 httpPrintf(HTTP(con), "Content-Length: 0\r\n");
1114 httpPrintf(HTTP(con), "\r\n");
1115
1116 EncryptClient(con);
1117 #else
1118 if (!SendError(con, HTTP_NOT_IMPLEMENTED))
1119 {
1120 CloseClient(con);
1121 return (0);
1122 }
1123 #endif /* HAVE_SSL */
1124 }
1125
1126 if (con->http.expect)
1127 {
1128 /**** TODO: send expected header ****/
1129 }
1130
1131 if (!SendHeader(con, HTTP_OK, NULL))
1132 {
1133 CloseClient(con);
1134 return (0);
1135 }
1136
1137 httpPrintf(HTTP(con), "Allow: GET, HEAD, OPTIONS, POST, PUT\r\n");
1138 httpPrintf(HTTP(con), "Content-Length: 0\r\n");
1139 httpPrintf(HTTP(con), "\r\n");
1140 }
1141 else if (strstr(con->uri, "..") != NULL)
1142 {
1143 /*
1144 * Protect against malicious users!
1145 */
1146
1147 if (!SendError(con, HTTP_FORBIDDEN))
1148 {
1149 CloseClient(con);
1150 return (0);
1151 }
1152 }
1153 else
1154 {
1155 if (strcasecmp(con->http.fields[HTTP_FIELD_CONNECTION], "Upgrade") == 0 &&
1156 con->http.tls == NULL)
1157 {
1158 #ifdef HAVE_SSL
1159 /*
1160 * Do encryption stuff...
1161 */
1162
1163 if (!SendHeader(con, HTTP_SWITCHING_PROTOCOLS, NULL))
1164 {
1165 CloseClient(con);
1166 return (0);
1167 }
1168
1169 httpPrintf(HTTP(con), "Connection: Upgrade\r\n");
1170 httpPrintf(HTTP(con), "Upgrade: TLS/1.0,HTTP/1.1\r\n");
1171 httpPrintf(HTTP(con), "Content-Length: 0\r\n");
1172 httpPrintf(HTTP(con), "\r\n");
1173
1174 EncryptClient(con);
1175
1176 status = IsAuthorized(con);
1177 #else
1178 if (!SendError(con, HTTP_NOT_IMPLEMENTED))
1179 {
1180 CloseClient(con);
1181 return (0);
1182 }
1183 #endif /* HAVE_SSL */
1184 }
1185
1186 if (status != HTTP_OK)
1187 {
1188 LogMessage(L_DEBUG2, "ReadClient: Unauthorized request for %s...\n",
1189 con->uri);
1190 SendError(con, status);
1191 ShutdownClient(con);
1192 return (1);
1193 }
1194
1195 if (con->http.expect)
1196 {
1197 /**** TODO: send expected header ****/
1198 }
1199
1200 switch (con->http.state)
1201 {
1202 case HTTP_GET_SEND :
1203 if (strncmp(con->uri, "/printers/", 10) == 0 &&
1204 strcmp(con->uri + strlen(con->uri) - 4, ".ppd") == 0)
1205 {
1206 /*
1207 * Send PPD file - get the real printer name since printer
1208 * names are not case sensitive but filenames can be...
1209 */
1210
1211 con->uri[strlen(con->uri) - 4] = '\0'; /* Drop ".ppd" */
1212
1213 if ((p = FindPrinter(con->uri + 10)) != NULL)
1214 snprintf(con->uri, sizeof(con->uri), "/ppd/%s.ppd", p->name);
1215 else
1216 {
1217 if (!SendError(con, HTTP_NOT_FOUND))
1218 {
1219 CloseClient(con);
1220 return (0);
1221 }
1222
1223 break;
1224 }
1225 }
1226
1227 if ((strncmp(con->uri, "/admin", 6) == 0 &&
1228 strncmp(con->uri, "/admin/conf/", 12) != 0) ||
1229 strncmp(con->uri, "/printers", 9) == 0 ||
1230 strncmp(con->uri, "/classes", 8) == 0 ||
1231 strncmp(con->uri, "/jobs", 5) == 0)
1232 {
1233 /*
1234 * Send CGI output...
1235 */
1236
1237 if (strncmp(con->uri, "/admin", 6) == 0)
1238 {
1239 SetStringf(&con->command, "%s/cgi-bin/admin.cgi", ServerBin);
1240 SetString(&con->options, con->uri + 6);
1241 }
1242 else if (strncmp(con->uri, "/printers", 9) == 0)
1243 {
1244 SetStringf(&con->command, "%s/cgi-bin/printers.cgi", ServerBin);
1245 SetString(&con->options, con->uri + 9);
1246 }
1247 else if (strncmp(con->uri, "/classes", 8) == 0)
1248 {
1249 SetStringf(&con->command, "%s/cgi-bin/classes.cgi", ServerBin);
1250 SetString(&con->options, con->uri + 8);
1251 }
1252 else
1253 {
1254 SetStringf(&con->command, "%s/cgi-bin/jobs.cgi", ServerBin);
1255 SetString(&con->options, con->uri + 5);
1256 }
1257
1258 if (con->options[0] == '/')
1259 strcpy(con->options, con->options + 1);
1260
1261 if (!SendCommand(con, con->command, con->options))
1262 {
1263 if (!SendError(con, HTTP_NOT_FOUND))
1264 {
1265 CloseClient(con);
1266 return (0);
1267 }
1268 }
1269 else
1270 LogRequest(con, HTTP_OK);
1271
1272 if (con->http.version <= HTTP_1_0)
1273 con->http.keep_alive = HTTP_KEEPALIVE_OFF;
1274 }
1275 else if (strncmp(con->uri, "/admin/conf/", 12) == 0 &&
1276 (strchr(con->uri + 12, '/') != NULL ||
1277 strlen(con->uri) == 12))
1278 {
1279 /*
1280 * GET can only be done to configuration files under
1281 * /admin/conf...
1282 */
1283
1284 if (!SendError(con, HTTP_FORBIDDEN))
1285 {
1286 CloseClient(con);
1287 return (0);
1288 }
1289
1290 break;
1291 }
1292 else
1293 {
1294 /*
1295 * Serve a file...
1296 */
1297
1298 if ((filename = get_file(con, &filestats, buf,
1299 sizeof(buf))) == NULL)
1300 {
1301 if (!SendError(con, HTTP_NOT_FOUND))
1302 {
1303 CloseClient(con);
1304 return (0);
1305 }
1306
1307 break;
1308 }
1309
1310 type = mimeFileType(MimeDatabase, filename, NULL);
1311
1312 if (IsCGI(con, filename, &filestats, type))
1313 {
1314 if (!SendCommand(con, con->command, con->options))
1315 {
1316 if (!SendError(con, HTTP_NOT_FOUND))
1317 {
1318 CloseClient(con);
1319 return (0);
1320 }
1321 }
1322 else
1323 LogRequest(con, HTTP_OK);
1324
1325 if (con->http.version <= HTTP_1_0)
1326 con->http.keep_alive = HTTP_KEEPALIVE_OFF;
1327 break;
1328 }
1329
1330 if (!check_if_modified(con, &filestats))
1331 {
1332 if (!SendError(con, HTTP_NOT_MODIFIED))
1333 {
1334 CloseClient(con);
1335 return (0);
1336 }
1337 }
1338 else
1339 {
1340 if (type == NULL)
1341 strcpy(line, "text/plain");
1342 else
1343 snprintf(line, sizeof(line), "%s/%s", type->super, type->type);
1344
1345 if (!SendFile(con, HTTP_OK, filename, line, &filestats))
1346 {
1347 CloseClient(con);
1348 return (0);
1349 }
1350 }
1351 }
1352 break;
1353
1354 case HTTP_POST_RECV :
1355 /*
1356 * See if the POST request includes a Content-Length field, and if
1357 * so check the length against any limits that are set...
1358 */
1359
1360 LogMessage(L_DEBUG2, "POST %s", con->uri);
1361 LogMessage(L_DEBUG2, "CONTENT_TYPE = %s", con->http.fields[HTTP_FIELD_CONTENT_TYPE]);
1362
1363 if (con->http.fields[HTTP_FIELD_CONTENT_LENGTH][0] &&
1364 atoi(con->http.fields[HTTP_FIELD_CONTENT_LENGTH]) > MaxRequestSize &&
1365 MaxRequestSize > 0)
1366 {
1367 /*
1368 * Request too large...
1369 */
1370
1371 if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
1372 {
1373 CloseClient(con);
1374 return (0);
1375 }
1376
1377 break;
1378 }
1379 else if (atoi(con->http.fields[HTTP_FIELD_CONTENT_LENGTH]) < 0)
1380 {
1381 /*
1382 * Negative content lengths are invalid!
1383 */
1384
1385 if (!SendError(con, HTTP_BAD_REQUEST))
1386 {
1387 CloseClient(con);
1388 return (0);
1389 }
1390
1391 break;
1392 }
1393
1394 /*
1395 * See what kind of POST request this is; for IPP requests the
1396 * content-type field will be "application/ipp"...
1397 */
1398
1399 if (strcmp(con->http.fields[HTTP_FIELD_CONTENT_TYPE], "application/ipp") == 0)
1400 con->request = ippNew();
1401 else if ((strncmp(con->uri, "/admin", 6) == 0 &&
1402 strncmp(con->uri, "/admin/conf/", 12) != 0) ||
1403 strncmp(con->uri, "/printers", 9) == 0 ||
1404 strncmp(con->uri, "/classes", 8) == 0 ||
1405 strncmp(con->uri, "/jobs", 5) == 0)
1406 {
1407 /*
1408 * CGI request...
1409 */
1410
1411 if (strncmp(con->uri, "/admin", 6) == 0)
1412 {
1413 SetStringf(&con->command, "%s/cgi-bin/admin.cgi", ServerBin);
1414 SetString(&con->options, con->uri + 6);
1415 }
1416 else if (strncmp(con->uri, "/printers", 9) == 0)
1417 {
1418 SetStringf(&con->command, "%s/cgi-bin/printers.cgi", ServerBin);
1419 SetString(&con->options, con->uri + 9);
1420 }
1421 else if (strncmp(con->uri, "/classes", 8) == 0)
1422 {
1423 SetStringf(&con->command, "%s/cgi-bin/classes.cgi", ServerBin);
1424 SetString(&con->options, con->uri + 8);
1425 }
1426 else
1427 {
1428 SetStringf(&con->command, "%s/cgi-bin/jobs.cgi", ServerBin);
1429 SetString(&con->options, con->uri + 5);
1430 }
1431
1432 if (con->options[0] == '/')
1433 strcpy(con->options, con->options + 1);
1434
1435 LogMessage(L_DEBUG2, "ReadClient() %d command=\"%s\", options = \"%s\"",
1436 con->http.fd, con->command, con->options);
1437
1438 if (con->http.version <= HTTP_1_0)
1439 con->http.keep_alive = HTTP_KEEPALIVE_OFF;
1440 }
1441 else
1442 {
1443 /*
1444 * POST to a file...
1445 */
1446
1447 if ((filename = get_file(con, &filestats, buf,
1448 sizeof(buf))) == NULL)
1449 {
1450 if (!SendError(con, HTTP_NOT_FOUND))
1451 {
1452 CloseClient(con);
1453 return (0);
1454 }
1455
1456 break;
1457 }
1458
1459 type = mimeFileType(MimeDatabase, filename, NULL);
1460
1461 if (!IsCGI(con, filename, &filestats, type))
1462 {
1463 /*
1464 * Only POST to CGI's...
1465 */
1466
1467 if (!SendError(con, HTTP_UNAUTHORIZED))
1468 {
1469 CloseClient(con);
1470 return (0);
1471 }
1472 }
1473 }
1474 break;
1475
1476 case HTTP_PUT_RECV :
1477 /*
1478 * Validate the resource name...
1479 */
1480
1481 if (strncmp(con->uri, "/admin/conf/", 12) != 0 ||
1482 strchr(con->uri + 12, '/') != NULL ||
1483 strlen(con->uri) == 12)
1484 {
1485 /*
1486 * PUT can only be done to configuration files under
1487 * /admin/conf...
1488 */
1489
1490 if (!SendError(con, HTTP_FORBIDDEN))
1491 {
1492 CloseClient(con);
1493 return (0);
1494 }
1495
1496 break;
1497 }
1498
1499 /*
1500 * See if the PUT request includes a Content-Length field, and if
1501 * so check the length against any limits that are set...
1502 */
1503
1504 LogMessage(L_DEBUG2, "PUT %s", con->uri);
1505 LogMessage(L_DEBUG2, "CONTENT_TYPE = %s", con->http.fields[HTTP_FIELD_CONTENT_TYPE]);
1506
1507 if (con->http.fields[HTTP_FIELD_CONTENT_LENGTH][0] &&
1508 atoi(con->http.fields[HTTP_FIELD_CONTENT_LENGTH]) > MaxRequestSize &&
1509 MaxRequestSize > 0)
1510 {
1511 /*
1512 * Request too large...
1513 */
1514
1515 if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
1516 {
1517 CloseClient(con);
1518 return (0);
1519 }
1520
1521 break;
1522 }
1523
1524 /*
1525 * Open a temporary file to hold the request...
1526 */
1527
1528 SetStringf(&con->filename, "%s/%08x", RequestRoot, request_id ++);
1529 con->file = open(con->filename, O_WRONLY | O_CREAT | O_TRUNC, 0640);
1530 fchmod(con->file, 0640);
1531 fchown(con->file, User, Group);
1532
1533 LogMessage(L_DEBUG2, "ReadClient() %d REQUEST %s=%d", con->http.fd,
1534 con->filename, con->file);
1535
1536 if (con->file < 0)
1537 {
1538 if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
1539 {
1540 CloseClient(con);
1541 return (0);
1542 }
1543 }
1544 break;
1545
1546 case HTTP_DELETE :
1547 case HTTP_TRACE :
1548 SendError(con, HTTP_NOT_IMPLEMENTED);
1549 ShutdownClient(con);
1550 return (1);
1551
1552 case HTTP_HEAD :
1553 if (strncmp(con->uri, "/printers/", 10) == 0 &&
1554 strcmp(con->uri + strlen(con->uri) - 4, ".ppd") == 0)
1555 {
1556 /*
1557 * Send PPD file - get the real printer name since printer
1558 * names are not case sensitive but filenames can be...
1559 */
1560
1561 con->uri[strlen(con->uri) - 4] = '\0'; /* Drop ".ppd" */
1562
1563 if ((p = FindPrinter(con->uri + 10)) != NULL)
1564 snprintf(con->uri, sizeof(con->uri), "/ppd/%s.ppd", p->name);
1565 else
1566 {
1567 if (!SendError(con, HTTP_NOT_FOUND))
1568 {
1569 CloseClient(con);
1570 return (0);
1571 }
1572
1573 break;
1574 }
1575 }
1576
1577 if ((strncmp(con->uri, "/admin/", 7) == 0 &&
1578 strncmp(con->uri, "/admin/conf/", 12) != 0) ||
1579 strncmp(con->uri, "/printers/", 10) == 0 ||
1580 strncmp(con->uri, "/classes/", 9) == 0 ||
1581 strncmp(con->uri, "/jobs/", 6) == 0)
1582 {
1583 /*
1584 * CGI output...
1585 */
1586
1587 if (!SendHeader(con, HTTP_OK, "text/html"))
1588 {
1589 CloseClient(con);
1590 return (0);
1591 }
1592
1593 if (httpPrintf(HTTP(con), "\r\n") < 0)
1594 {
1595 CloseClient(con);
1596 return (0);
1597 }
1598
1599 LogRequest(con, HTTP_OK);
1600 }
1601 else if (strncmp(con->uri, "/admin/conf/", 12) == 0 &&
1602 (strchr(con->uri + 12, '/') != NULL ||
1603 strlen(con->uri) == 12))
1604 {
1605 /*
1606 * HEAD can only be done to configuration files under
1607 * /admin/conf...
1608 */
1609
1610 if (!SendError(con, HTTP_FORBIDDEN))
1611 {
1612 CloseClient(con);
1613 return (0);
1614 }
1615
1616 break;
1617 }
1618 else if ((filename = get_file(con, &filestats, buf,
1619 sizeof(buf))) == NULL)
1620 {
1621 if (!SendHeader(con, HTTP_NOT_FOUND, "text/html"))
1622 {
1623 CloseClient(con);
1624 return (0);
1625 }
1626
1627 LogRequest(con, HTTP_NOT_FOUND);
1628 }
1629 else if (!check_if_modified(con, &filestats))
1630 {
1631 if (!SendError(con, HTTP_NOT_MODIFIED))
1632 {
1633 CloseClient(con);
1634 return (0);
1635 }
1636
1637 LogRequest(con, HTTP_NOT_MODIFIED);
1638 }
1639 else
1640 {
1641 /*
1642 * Serve a file...
1643 */
1644
1645 type = mimeFileType(MimeDatabase, filename, NULL);
1646 if (type == NULL)
1647 strcpy(line, "text/plain");
1648 else
1649 snprintf(line, sizeof(line), "%s/%s", type->super, type->type);
1650
1651 if (!SendHeader(con, HTTP_OK, line))
1652 {
1653 CloseClient(con);
1654 return (0);
1655 }
1656
1657 if (httpPrintf(HTTP(con), "Last-Modified: %s\r\n",
1658 httpGetDateString(filestats.st_mtime)) < 0)
1659 {
1660 CloseClient(con);
1661 return (0);
1662 }
1663
1664 if (httpPrintf(HTTP(con), "Content-Length: %lu\r\n",
1665 (unsigned long)filestats.st_size) < 0)
1666 {
1667 CloseClient(con);
1668 return (0);
1669 }
1670
1671 LogRequest(con, HTTP_OK);
1672 }
1673
1674 if (httpPrintf(HTTP(con), "\r\n") < 0)
1675 {
1676 CloseClient(con);
1677 return (0);
1678 }
1679
1680 con->http.state = HTTP_WAITING;
1681 break;
1682
1683 default :
1684 break; /* Anti-compiler-warning-code */
1685 }
1686 }
1687 }
1688
1689 /*
1690 * Handle any incoming data...
1691 */
1692
1693 switch (con->http.state)
1694 {
1695 case HTTP_PUT_RECV :
1696 LogMessage(L_DEBUG2, "ReadClient() %d con->data_encoding = %s, con->data_remaining = %d, con->file = %d",
1697 con->http.fd,
1698 con->http.data_encoding == HTTP_ENCODE_CHUNKED ? "chunked" : "length",
1699 con->http.data_remaining, con->file);
1700
1701 if ((bytes = httpRead(HTTP(con), line, sizeof(line))) < 0)
1702 {
1703 CloseClient(con);
1704 return (0);
1705 }
1706 else if (bytes > 0)
1707 {
1708 con->bytes += bytes;
1709
1710 LogMessage(L_DEBUG2, "ReadClient() %d writing %d bytes to %d",
1711 con->http.fd, bytes, con->file);
1712
1713 if (write(con->file, line, bytes) < bytes)
1714 {
1715 LogMessage(L_ERROR, "ReadClient: Unable to write %d bytes to %s: %s",
1716 bytes, con->filename, strerror(errno));
1717
1718 LogMessage(L_DEBUG2, "ReadClient: Closing data file %d...",
1719 con->file);
1720
1721 close(con->file);
1722 con->file = 0;
1723 unlink(con->filename);
1724 ClearString(&con->filename);
1725
1726 if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
1727 {
1728 CloseClient(con);
1729 return (0);
1730 }
1731 }
1732 }
1733
1734 if (con->http.state == HTTP_WAITING)
1735 {
1736 /*
1737 * End of file, see how big it is...
1738 */
1739
1740 fstat(con->file, &filestats);
1741
1742 LogMessage(L_DEBUG2, "ReadClient() %d Closing data file %d, size = %d.",
1743 con->http.fd, con->file, (int)filestats.st_size);
1744
1745 close(con->file);
1746 con->file = 0;
1747
1748 if (filestats.st_size > MaxRequestSize &&
1749 MaxRequestSize > 0)
1750 {
1751 /*
1752 * Request is too big; remove it and send an error...
1753 */
1754
1755 LogMessage(L_DEBUG2, "ReadClient() %d Removing temp file %s",
1756 con->http.fd, con->filename);
1757 unlink(con->filename);
1758 ClearString(&con->filename);
1759
1760 if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
1761 {
1762 CloseClient(con);
1763 return (0);
1764 }
1765 }
1766
1767 /*
1768 * Install the configuration file...
1769 */
1770
1771 status = install_conf_file(con);
1772
1773 /*
1774 * Return the status to the client...
1775 */
1776
1777 if (!SendError(con, status))
1778 {
1779 CloseClient(con);
1780 return (0);
1781 }
1782 }
1783 break;
1784
1785 case HTTP_POST_RECV :
1786 LogMessage(L_DEBUG2, "ReadClient() %d con->data_encoding = %s, con->data_remaining = %d, con->file = %d",
1787 con->http.fd,
1788 con->http.data_encoding == HTTP_ENCODE_CHUNKED ? "chunked" : "length",
1789 con->http.data_remaining, con->file);
1790
1791 if (con->request != NULL)
1792 {
1793 /*
1794 * Grab any request data from the connection...
1795 */
1796
1797 if ((ipp_state = ippRead(&(con->http), con->request)) == IPP_ERROR)
1798 {
1799 LogMessage(L_ERROR, "ReadClient() %d IPP Read Error!",
1800 con->http.fd);
1801
1802 if (!SendError(con, HTTP_BAD_REQUEST))
1803 {
1804 CloseClient(con);
1805 return (0);
1806 }
1807
1808 ShutdownClient(con);
1809 return (1);
1810 }
1811 else if (ipp_state != IPP_DATA)
1812 break;
1813 else
1814 con->bytes += ippLength(con->request);
1815 }
1816
1817 if (con->file == 0 && con->http.state != HTTP_POST_SEND)
1818 {
1819 /*
1820 * Create a file as needed for the request data...
1821 */
1822
1823 SetStringf(&con->filename, "%s/%08x", RequestRoot, request_id ++);
1824 con->file = open(con->filename, O_WRONLY | O_CREAT | O_TRUNC, 0640);
1825 fchmod(con->file, 0640);
1826 fchown(con->file, User, Group);
1827
1828 LogMessage(L_DEBUG2, "ReadClient() %d REQUEST %s=%d", con->http.fd,
1829 con->filename, con->file);
1830
1831 if (con->file < 0)
1832 {
1833 if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
1834 {
1835 CloseClient(con);
1836 return (0);
1837 }
1838 }
1839 }
1840
1841 if (con->http.state != HTTP_POST_SEND)
1842 {
1843 if ((bytes = httpRead(HTTP(con), line, sizeof(line))) < 0)
1844 {
1845 CloseClient(con);
1846 return (0);
1847 }
1848 else if (bytes > 0)
1849 {
1850 con->bytes += bytes;
1851
1852 LogMessage(L_DEBUG2, "ReadClient() %d writing %d bytes to %d",
1853 con->http.fd, bytes, con->file);
1854
1855 if (write(con->file, line, bytes) < bytes)
1856 {
1857 LogMessage(L_ERROR, "ReadClient: Unable to write %d bytes to %s: %s",
1858 bytes, con->filename, strerror(errno));
1859
1860 LogMessage(L_DEBUG2, "ReadClient: Closing file %d...",
1861 con->file);
1862
1863 close(con->file);
1864 con->file = 0;
1865 unlink(con->filename);
1866 ClearString(&con->filename);
1867
1868 if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
1869 {
1870 CloseClient(con);
1871 return (0);
1872 }
1873 }
1874 }
1875 else if (con->http.state == HTTP_POST_RECV)
1876 {
1877 return (0);
1878 }
1879 else if (con->http.state != HTTP_POST_SEND)
1880 {
1881 CloseClient(con);
1882 return (0);
1883 }
1884 }
1885
1886 if (con->http.state == HTTP_POST_SEND)
1887 {
1888 if (con->file)
1889 {
1890 fstat(con->file, &filestats);
1891
1892 LogMessage(L_DEBUG2, "ReadClient() %d Closing data file %d, size = %d.",
1893 con->http.fd, con->file, (int)filestats.st_size);
1894
1895 close(con->file);
1896 con->file = 0;
1897
1898 if (filestats.st_size > MaxRequestSize &&
1899 MaxRequestSize > 0)
1900 {
1901 /*
1902 * Request is too big; remove it and send an error...
1903 */
1904
1905 LogMessage(L_DEBUG2, "ReadClient() %d Removing temp file %s",
1906 con->http.fd, con->filename);
1907 unlink(con->filename);
1908 ClearString(&con->filename);
1909
1910 if (con->request)
1911 {
1912 /*
1913 * Delete any IPP request data...
1914 */
1915
1916 ippDelete(con->request);
1917 con->request = NULL;
1918 }
1919
1920 if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
1921 {
1922 CloseClient(con);
1923 return (0);
1924 }
1925 }
1926
1927 if (con->command)
1928 {
1929 if (!SendCommand(con, con->command, con->options))
1930 {
1931 if (!SendError(con, HTTP_NOT_FOUND))
1932 {
1933 CloseClient(con);
1934 return (0);
1935 }
1936 }
1937 else
1938 LogRequest(con, HTTP_OK);
1939 }
1940 }
1941
1942 if (con->request)
1943 return (ProcessIPPRequest(con));
1944 }
1945 break;
1946
1947 default :
1948 break; /* Anti-compiler-warning-code */
1949 }
1950
1951 if (!con->http.keep_alive && con->http.state == HTTP_WAITING)
1952 {
1953 CloseClient(con);
1954 return (0);
1955 }
1956 else
1957 return (1);
1958 }
1959
1960
1961 /*
1962 * 'SendCommand()' - Send output from a command via HTTP.
1963 */
1964
1965 int
1966 SendCommand(client_t *con,
1967 char *command,
1968 char *options)
1969 {
1970 int fd;
1971
1972
1973 if (con->filename)
1974 fd = open(con->filename, O_RDONLY);
1975 else
1976 fd = open("/dev/null", O_RDONLY);
1977
1978 con->pipe_pid = pipe_command(con, fd, &(con->file), command, options);
1979
1980 close(fd);
1981
1982 LogMessage(L_INFO, "Started \"%s\" (pid=%d)", command, con->pipe_pid);
1983
1984 LogMessage(L_DEBUG, "SendCommand() %d file=%d", con->http.fd, con->file);
1985
1986 if (con->pipe_pid == 0)
1987 return (0);
1988
1989 fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
1990
1991 LogMessage(L_DEBUG2, "SendCommand: Adding fd %d to InputSet...", con->file);
1992 LogMessage(L_DEBUG2, "SendCommand: Adding fd %d to OutputSet...",
1993 con->http.fd);
1994
1995 FD_SET(con->file, InputSet);
1996 FD_SET(con->http.fd, OutputSet);
1997
1998 if (!SendHeader(con, HTTP_OK, NULL))
1999 return (0);
2000
2001 if (con->http.version == HTTP_1_1)
2002 {
2003 con->http.data_encoding = HTTP_ENCODE_CHUNKED;
2004
2005 if (httpPrintf(HTTP(con), "Transfer-Encoding: chunked\r\n") < 0)
2006 return (0);
2007 }
2008
2009 con->got_fields = 0;
2010 con->field_col = 0;
2011
2012 return (1);
2013 }
2014
2015
2016 /*
2017 * 'SendError()' - Send an error message via HTTP.
2018 */
2019
2020 int /* O - 1 if successful, 0 otherwise */
2021 SendError(client_t *con, /* I - Connection */
2022 http_status_t code) /* I - Error code */
2023 {
2024 char message[1024]; /* Message for user */
2025
2026
2027 /*
2028 * Put the request in the access_log file...
2029 */
2030
2031 if (con->operation > HTTP_WAITING)
2032 LogRequest(con, code);
2033
2034 LogMessage(L_DEBUG, "SendError() %d code=%d", con->http.fd, code);
2035
2036 /*
2037 * To work around bugs in some proxies, don't use Keep-Alive for some
2038 * error messages...
2039 */
2040
2041 if (code >= HTTP_BAD_REQUEST)
2042 con->http.keep_alive = HTTP_KEEPALIVE_OFF;
2043
2044 /*
2045 * Send an error message back to the client. If the error code is a
2046 * 400 or 500 series, make sure the message contains some text, too!
2047 */
2048
2049 if (!SendHeader(con, code, NULL))
2050 return (0);
2051
2052 #ifdef HAVE_SSL
2053 if (code == HTTP_UPGRADE_REQUIRED)
2054 if (httpPrintf(HTTP(con), "Connection: Upgrade\r\n") < 0)
2055 return (0);
2056
2057 if (httpPrintf(HTTP(con), "Upgrade: TLS/1.0,HTTP/1.1\r\n") < 0)
2058 return (0);
2059 #endif /* HAVE_SSL */
2060
2061 if ((con->http.version >= HTTP_1_1 && !con->http.keep_alive) ||
2062 (code >= HTTP_BAD_REQUEST && code != HTTP_UPGRADE_REQUIRED))
2063 {
2064 if (httpPrintf(HTTP(con), "Connection: close\r\n") < 0)
2065 return (0);
2066 }
2067
2068 if (code >= HTTP_BAD_REQUEST)
2069 {
2070 /*
2071 * Send a human-readable error message.
2072 */
2073
2074 snprintf(message, sizeof(message),
2075 "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>"
2076 "<BODY><H1>%s</H1>%s</BODY></HTML>\n",
2077 code, httpStatus(code), httpStatus(code),
2078 con->language ? con->language->messages[code] :
2079 httpStatus(code));
2080
2081 if (httpPrintf(HTTP(con), "Content-Type: text/html\r\n") < 0)
2082 return (0);
2083 if (httpPrintf(HTTP(con), "Content-Length: %d\r\n",
2084 (int)strlen(message)) < 0)
2085 return (0);
2086 if (httpPrintf(HTTP(con), "\r\n") < 0)
2087 return (0);
2088 if (httpPrintf(HTTP(con), "%s", message) < 0)
2089 return (0);
2090 }
2091 else if (httpPrintf(HTTP(con), "\r\n") < 0)
2092 return (0);
2093
2094 con->http.state = HTTP_WAITING;
2095
2096 return (1);
2097 }
2098
2099
2100 /*
2101 * 'SendFile()' - Send a file via HTTP.
2102 */
2103
2104 int
2105 SendFile(client_t *con,
2106 http_status_t code,
2107 char *filename,
2108 char *type,
2109 struct stat *filestats)
2110 {
2111 con->file = open(filename, O_RDONLY);
2112
2113 LogMessage(L_DEBUG, "SendFile() %d file=%d", con->http.fd, con->file);
2114
2115 if (con->file < 0)
2116 return (0);
2117
2118 fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
2119
2120 con->pipe_pid = 0;
2121
2122 if (!SendHeader(con, code, type))
2123 return (0);
2124
2125 if (httpPrintf(HTTP(con), "Last-Modified: %s\r\n", httpGetDateString(filestats->st_mtime)) < 0)
2126 return (0);
2127 if (httpPrintf(HTTP(con), "Content-Length: %lu\r\n",
2128 (unsigned long)filestats->st_size) < 0)
2129 return (0);
2130 if (httpPrintf(HTTP(con), "\r\n") < 0)
2131 return (0);
2132
2133 LogMessage(L_DEBUG2, "SendFile: Adding fd %d to OutputSet...", con->http.fd);
2134
2135 FD_SET(con->http.fd, OutputSet);
2136
2137 return (1);
2138 }
2139
2140
2141 /*
2142 * 'SendHeader()' - Send an HTTP request.
2143 */
2144
2145 int /* O - 1 on success, 0 on failure */
2146 SendHeader(client_t *con, /* I - Client to send to */
2147 http_status_t code, /* I - HTTP status code */
2148 char *type) /* I - MIME type of document */
2149 {
2150 location_t *loc; /* Authentication location */
2151
2152
2153 if (httpPrintf(HTTP(con), "HTTP/%d.%d %d %s\r\n", con->http.version / 100,
2154 con->http.version % 100, code, httpStatus(code)) < 0)
2155 return (0);
2156 if (httpPrintf(HTTP(con), "Date: %s\r\n", httpGetDateString(time(NULL))) < 0)
2157 return (0);
2158 if (httpPrintf(HTTP(con), "Server: CUPS/1.1\r\n") < 0)
2159 return (0);
2160 if (con->http.keep_alive && con->http.version >= HTTP_1_0)
2161 {
2162 if (httpPrintf(HTTP(con), "Connection: Keep-Alive\r\n") < 0)
2163 return (0);
2164 if (httpPrintf(HTTP(con), "Keep-Alive: timeout=%d\r\n", KeepAliveTimeout) < 0)
2165 return (0);
2166 }
2167 if (code == HTTP_METHOD_NOT_ALLOWED)
2168 if (httpPrintf(HTTP(con), "Allow: GET, HEAD, OPTIONS, POST\r\n") < 0)
2169 return (0);
2170
2171 if (code == HTTP_UNAUTHORIZED)
2172 {
2173 /*
2174 * This already succeeded in IsAuthorized...
2175 */
2176
2177 loc = FindBest(con->uri, con->http.state);
2178
2179 if (loc->type != AUTH_DIGEST)
2180 {
2181 if (httpPrintf(HTTP(con), "WWW-Authenticate: Basic realm=\"CUPS\"\r\n") < 0)
2182 return (0);
2183 }
2184 else
2185 {
2186 if (httpPrintf(HTTP(con), "WWW-Authenticate: Digest realm=\"CUPS\" "
2187 "nonce=\"%s\"\r\n", con->http.hostname) < 0)
2188 return (0);
2189 }
2190 }
2191 if (con->language != NULL)
2192 {
2193 if (httpPrintf(HTTP(con), "Content-Language: %s\r\n",
2194 con->language->language) < 0)
2195 return (0);
2196
2197 if (type != NULL)
2198 if (httpPrintf(HTTP(con), "Content-Type: %s; charset=%s\r\n", type,
2199 cupsLangEncoding(con->language)) < 0)
2200 return (0);
2201 }
2202 else if (type != NULL)
2203 if (httpPrintf(HTTP(con), "Content-Type: %s\r\n", type) < 0)
2204 return (0);
2205
2206 return (1);
2207 }
2208
2209
2210 /*
2211 * 'ShutdownClient()' - Shutdown the receiving end of a connection.
2212 */
2213
2214 void
2215 ShutdownClient(client_t *con) /* I - Client connection */
2216 {
2217 /*
2218 * Shutdown the receiving end of the socket, since the client
2219 * still needs to read the error message...
2220 */
2221
2222 shutdown(con->http.fd, 0);
2223 con->http.used = 0;
2224
2225 /*
2226 * Update the activity time so that we timeout after 30 seconds rather
2227 * then the current Timeout setting (300 by default). This prevents
2228 * some DoS situations...
2229 */
2230
2231 con->http.activity = time(NULL) - Timeout + 30;
2232
2233 LogMessage(L_DEBUG2, "ShutdownClient: Removing fd %d from InputSet...",
2234 con->http.fd);
2235
2236 FD_CLR(con->http.fd, InputSet);
2237 }
2238
2239
2240 /*
2241 * 'UpdateCGI()' - Read status messages from CGI scripts and programs.
2242 */
2243
2244 void
2245 UpdateCGI(void)
2246 {
2247 int bytes; /* Number of bytes read */
2248 char *lineptr, /* Pointer to end of line in buffer */
2249 *message; /* Pointer to message text */
2250 int loglevel; /* Log level for message */
2251 static int bufused = 0; /* Number of bytes used in buffer */
2252 static char buffer[1024]; /* Status buffer */
2253
2254
2255 if ((bytes = read(CGIPipes[0], buffer + bufused,
2256 sizeof(buffer) - bufused - 1)) > 0)
2257 {
2258 bufused += bytes;
2259 buffer[bufused] = '\0';
2260 lineptr = strchr(buffer, '\n');
2261 }
2262 else if (bytes < 0 && errno == EINTR)
2263 return;
2264 else
2265 {
2266 lineptr = buffer + bufused;
2267 lineptr[1] = 0;
2268 }
2269
2270 if (bytes == 0 && bufused == 0)
2271 lineptr = NULL;
2272
2273 while (lineptr != NULL)
2274 {
2275 /*
2276 * Terminate each line and process it...
2277 */
2278
2279 *lineptr++ = '\0';
2280
2281 /*
2282 * Figure out the logging level...
2283 */
2284
2285 if (strncmp(buffer, "EMERG:", 6) == 0)
2286 {
2287 loglevel = L_EMERG;
2288 message = buffer + 6;
2289 }
2290 else if (strncmp(buffer, "ALERT:", 6) == 0)
2291 {
2292 loglevel = L_ALERT;
2293 message = buffer + 6;
2294 }
2295 else if (strncmp(buffer, "CRIT:", 5) == 0)
2296 {
2297 loglevel = L_CRIT;
2298 message = buffer + 5;
2299 }
2300 else if (strncmp(buffer, "ERROR:", 6) == 0)
2301 {
2302 loglevel = L_ERROR;
2303 message = buffer + 6;
2304 }
2305 else if (strncmp(buffer, "WARNING:", 8) == 0)
2306 {
2307 loglevel = L_WARN;
2308 message = buffer + 8;
2309 }
2310 else if (strncmp(buffer, "NOTICE:", 6) == 0)
2311 {
2312 loglevel = L_NOTICE;
2313 message = buffer + 6;
2314 }
2315 else if (strncmp(buffer, "INFO:", 5) == 0)
2316 {
2317 loglevel = L_INFO;
2318 message = buffer + 5;
2319 }
2320 else if (strncmp(buffer, "DEBUG:", 6) == 0)
2321 {
2322 loglevel = L_DEBUG;
2323 message = buffer + 6;
2324 }
2325 else if (strncmp(buffer, "DEBUG2:", 7) == 0)
2326 {
2327 loglevel = L_DEBUG2;
2328 message = buffer + 7;
2329 }
2330 else if (strncmp(buffer, "PAGE:", 5) == 0)
2331 {
2332 loglevel = L_PAGE;
2333 message = buffer + 5;
2334 }
2335 else
2336 {
2337 loglevel = L_DEBUG;
2338 message = buffer;
2339 }
2340
2341 /*
2342 * Skip leading whitespace in the message...
2343 */
2344
2345 while (isspace(*message))
2346 message ++;
2347
2348 LogMessage(loglevel, "[CGI] %s", message);
2349
2350 /*
2351 * Copy over the buffer data we've used up...
2352 */
2353
2354 strcpy(buffer, lineptr);
2355 bufused -= lineptr - buffer;
2356
2357 if (bufused < 0)
2358 bufused = 0;
2359
2360 lineptr = strchr(buffer, '\n');
2361 }
2362
2363 if (bytes <= 0)
2364 {
2365 /*
2366 * Fatal error on pipe - should never happen!
2367 */
2368
2369 LogMessage(L_ERROR, "UpdateCGI: error reading from CGI error pipe - %s",
2370 strerror(errno));
2371 }
2372 }
2373
2374
2375 /*
2376 * 'WriteClient()' - Write data to a client as needed.
2377 */
2378
2379 int /* O - 1 if success, 0 if fail */
2380 WriteClient(client_t *con) /* I - Client connection */
2381 {
2382 int bytes; /* Number of bytes written */
2383 char buf[HTTP_MAX_BUFFER + 1];/* Data buffer */
2384 char *bufptr; /* Pointer into buffer */
2385 ipp_state_t ipp_state; /* IPP state value */
2386
2387
2388 if (con->http.state != HTTP_GET_SEND &&
2389 con->http.state != HTTP_POST_SEND)
2390 return (1);
2391
2392 if (con->response != NULL)
2393 {
2394 ipp_state = ippWrite(&(con->http), con->response);
2395 bytes = ipp_state != IPP_ERROR && ipp_state != IPP_DATA;
2396 }
2397 else if ((bytes = read(con->file, buf, HTTP_MAX_BUFFER)) > 0)
2398 {
2399 if (con->pipe_pid && !con->got_fields)
2400 {
2401 /*
2402 * Inspect the data for Content-Type and other fields.
2403 */
2404
2405 buf[bytes] = '\0';
2406
2407 for (bufptr = buf; !con->got_fields && *bufptr; bufptr ++)
2408 if (*bufptr == '\n')
2409 {
2410 /*
2411 * Send line to client...
2412 */
2413
2414 if (bufptr > buf && bufptr[-1] == '\r')
2415 bufptr[-1] = '\0';
2416 *bufptr++ = '\0';
2417
2418 httpPrintf(HTTP(con), "%s\r\n", buf);
2419 LogMessage(L_DEBUG2, "WriteClient() %d %s", con->http.fd, buf);
2420
2421 /*
2422 * Update buffer...
2423 */
2424
2425 bytes -= (bufptr - buf);
2426 memcpy(buf, bufptr, bytes + 1);
2427 bufptr = buf - 1;
2428
2429 /*
2430 * See if the line was empty...
2431 */
2432
2433 if (con->field_col == 0)
2434 con->got_fields = 1;
2435 else
2436 con->field_col = 0;
2437 }
2438 else if (*bufptr != '\r')
2439 con->field_col ++;
2440
2441 if (bytes > 0 && !con->got_fields)
2442 {
2443 /*
2444 * Remaining text needs to go out...
2445 */
2446
2447 httpPrintf(HTTP(con), "%s", buf);
2448
2449 con->http.activity = time(NULL);
2450 return (1);
2451 }
2452 else if (bytes == 0)
2453 {
2454 con->http.activity = time(NULL);
2455 return (1);
2456 }
2457 }
2458
2459 if (httpWrite(HTTP(con), buf, bytes) < 0)
2460 {
2461 CloseClient(con);
2462 return (0);
2463 }
2464
2465 con->bytes += bytes;
2466 }
2467
2468 if (bytes <= 0)
2469 {
2470 LogRequest(con, HTTP_OK);
2471
2472 if (con->http.data_encoding == HTTP_ENCODE_CHUNKED)
2473 {
2474 if (httpPrintf(HTTP(con), "0\r\n\r\n") < 0)
2475 {
2476 CloseClient(con);
2477 return (0);
2478 }
2479 }
2480
2481 con->http.state = HTTP_WAITING;
2482
2483 LogMessage(L_DEBUG2, "WriteClient() Removing fd %d from OutputSet...",
2484 con->http.fd);
2485
2486 FD_CLR(con->http.fd, OutputSet);
2487
2488 if (con->file)
2489 {
2490 LogMessage(L_DEBUG2, "WriteClient() Removing fd %d from InputSet...",
2491 con->file);
2492 FD_CLR(con->file, InputSet);
2493
2494 if (con->pipe_pid)
2495 kill(con->pipe_pid, SIGTERM);
2496
2497 LogMessage(L_DEBUG2, "WriteClient() %d Closing data file %d.",
2498 con->http.fd, con->file);
2499
2500 close(con->file);
2501 con->file = 0;
2502 con->pipe_pid = 0;
2503 }
2504
2505 if (con->filename)
2506 {
2507 LogMessage(L_DEBUG2, "WriteClient() %d Removing temp file %s",
2508 con->http.fd, con->filename);
2509 unlink(con->filename);
2510 ClearString(&con->filename);
2511 }
2512
2513 if (con->request != NULL)
2514 {
2515 ippDelete(con->request);
2516 con->request = NULL;
2517 }
2518
2519 if (con->response != NULL)
2520 {
2521 ippDelete(con->response);
2522 con->response = NULL;
2523 }
2524
2525 ClearString(&con->command);
2526 ClearString(&con->options);
2527
2528 if (!con->http.keep_alive)
2529 {
2530 CloseClient(con);
2531 return (0);
2532 }
2533 }
2534
2535 if (bytes >= 1024)
2536 LogMessage(L_DEBUG2, "WriteClient() %d %d bytes", con->http.fd, bytes);
2537
2538 con->http.activity = time(NULL);
2539
2540 return (1);
2541 }
2542
2543
2544 /*
2545 * 'check_if_modified()' - Decode an "If-Modified-Since" line.
2546 */
2547
2548 static int /* O - 1 if modified since */
2549 check_if_modified(client_t *con, /* I - Client connection */
2550 struct stat *filestats) /* I - File information */
2551 {
2552 char *ptr; /* Pointer into field */
2553 time_t date; /* Time/date value */
2554 int size; /* Size/length value */
2555
2556
2557 size = 0;
2558 date = 0;
2559 ptr = con->http.fields[HTTP_FIELD_IF_MODIFIED_SINCE];
2560
2561 if (*ptr == '\0')
2562 return (1);
2563
2564 LogMessage(L_DEBUG2, "check_if_modified() %d If-Modified-Since=\"%s\"",
2565 con->http.fd, ptr);
2566
2567 while (*ptr != '\0')
2568 {
2569 while (isspace(*ptr) || *ptr == ';')
2570 ptr ++;
2571
2572 if (strncasecmp(ptr, "length=", 7) == 0)
2573 {
2574 ptr += 7;
2575 size = atoi(ptr);
2576
2577 while (isdigit(*ptr))
2578 ptr ++;
2579 }
2580 else if (isalpha(*ptr))
2581 {
2582 date = httpGetDateTime(ptr);
2583 while (*ptr != '\0' && *ptr != ';')
2584 ptr ++;
2585 }
2586 }
2587
2588 LogMessage(L_DEBUG2, "check_if_modified() %d sizes=%d,%d dates=%d,%d",
2589 con->http.fd, size, (int)filestats->st_size, (int)date,
2590 (int)filestats->st_mtime);
2591
2592 return ((size != filestats->st_size && size != 0) ||
2593 (date < filestats->st_mtime && date != 0) ||
2594 (size == 0 && date == 0));
2595 }
2596
2597
2598 /*
2599 * 'decode_auth()' - Decode an authorization string.
2600 */
2601
2602 static void
2603 decode_auth(client_t *con) /* I - Client to decode to */
2604 {
2605 char *s, /* Authorization string */
2606 value[1024]; /* Value string */
2607 const char *username; /* Certificate username */
2608
2609
2610 /*
2611 * Decode the string...
2612 */
2613
2614 s = con->http.fields[HTTP_FIELD_AUTHORIZATION];
2615
2616 LogMessage(L_DEBUG2, "decode_auth(%p): Authorization string = \"%s\"",
2617 con, s);
2618
2619 if (strncmp(s, "Basic", 5) == 0)
2620 {
2621 s += 5;
2622 while (isspace(*s))
2623 s ++;
2624
2625 httpDecode64(value, s);
2626
2627 /*
2628 * Pull the username and password out...
2629 */
2630
2631 if ((s = strchr(value, ':')) == NULL)
2632 {
2633 LogMessage(L_DEBUG, "decode_auth() %d no colon in auth string \"%s\"",
2634 con->http.fd, value);
2635 return;
2636 }
2637
2638 *s++ = '\0';
2639
2640 strlcpy(con->username, value, sizeof(con->username));
2641 strlcpy(con->password, s, sizeof(con->password));
2642 }
2643 else if (strncmp(s, "Local", 5) == 0)
2644 {
2645 s += 5;
2646 while (isspace(*s))
2647 s ++;
2648
2649 if ((username = FindCert(s)) != NULL)
2650 strlcpy(con->username, username, sizeof(con->username));
2651 }
2652 else if (strncmp(s, "Digest", 5) == 0)
2653 {
2654 /*
2655 * Get the username and password from the Digest attributes...
2656 */
2657
2658 if (httpGetSubField(&(con->http), HTTP_FIELD_WWW_AUTHENTICATE, "username",
2659 value))
2660 strlcpy(con->username, value, sizeof(con->username));
2661
2662 if (httpGetSubField(&(con->http), HTTP_FIELD_WWW_AUTHENTICATE, "response",
2663 value))
2664 strlcpy(con->password, value, sizeof(con->password) - 1);
2665 }
2666
2667 LogMessage(L_DEBUG2, "decode_auth() %d username=\"%s\"",
2668 con->http.fd, con->username);
2669 }
2670
2671
2672 /*
2673 * 'get_file()' - Get a filename and state info.
2674 */
2675
2676 static char * /* O - Real filename */
2677 get_file(client_t *con, /* I - Client connection */
2678 struct stat *filestats,/* O - File information */
2679 char *filename, /* IO - Filename buffer */
2680 int len) /* I - Buffer length */
2681 {
2682 int status; /* Status of filesystem calls */
2683 char *params; /* Pointer to parameters in URI */
2684
2685
2686 /*
2687 * Need to add DocumentRoot global...
2688 */
2689
2690 if (strncmp(con->uri, "/ppd/", 5) == 0)
2691 snprintf(filename, len, "%s%s", ServerRoot, con->uri);
2692 else if (strncmp(con->uri, "/admin/conf/", 12) == 0)
2693 snprintf(filename, len, "%s%s", ServerRoot, con->uri + 11);
2694 else if (con->language != NULL)
2695 snprintf(filename, len, "%s/%s%s", DocumentRoot, con->language->language,
2696 con->uri);
2697 else
2698 snprintf(filename, len, "%s%s", DocumentRoot, con->uri);
2699
2700 if ((params = strchr(filename, '?')) != NULL)
2701 *params = '\0';
2702
2703 /*
2704 * Grab the status for this language; if there isn't a language-specific file
2705 * then fallback to the default one...
2706 */
2707
2708 if ((status = stat(filename, filestats)) != 0 && con->language != NULL)
2709 {
2710 /*
2711 * Drop the language prefix and try the current directory...
2712 */
2713
2714 if (strncmp(con->uri, "/ppd/", 5) != 0 &&
2715 strncmp(con->uri, "/admin/conf/", 12) != 0)
2716 {
2717 snprintf(filename, len, "%s%s", DocumentRoot, con->uri);
2718
2719 status = stat(filename, filestats);
2720 }
2721 }
2722
2723 /*
2724 * If we're found a directory, get the index.html file instead...
2725 */
2726
2727 if (!status && S_ISDIR(filestats->st_mode))
2728 {
2729 if (filename[strlen(filename) - 1] == '/')
2730 strlcat(filename, "index.html", len);
2731 else
2732 strlcat(filename, "/index.html", len);
2733
2734 status = stat(filename, filestats);
2735 }
2736
2737 LogMessage(L_DEBUG2, "get_file() %d filename=%s size=%d",
2738 con->http.fd, filename, status ? -1 : (int)filestats->st_size);
2739
2740 if (status)
2741 return (NULL);
2742 else
2743 return (filename);
2744 }
2745
2746
2747 /*
2748 * 'install_conf_file()' - Install a configuration file.
2749 */
2750
2751 static http_status_t /* O - Status */
2752 install_conf_file(client_t *con) /* I - Connection */
2753 {
2754 cups_file_t *in, /* Input file */
2755 *out; /* Output file */
2756 char buffer[1024]; /* Copy buffer */
2757 int bytes; /* Number of bytes */
2758 char conffile[1024], /* Configuration filename */
2759 newfile[1024], /* New config filename */
2760 oldfile[1024]; /* Old config filename */
2761 struct stat confinfo; /* Config file info */
2762
2763
2764 /*
2765 * First construct the filenames...
2766 */
2767
2768 snprintf(conffile, sizeof(conffile), "%s%s", ServerRoot, con->uri + 11);
2769 snprintf(newfile, sizeof(newfile), "%s%s.N", ServerRoot, con->uri + 11);
2770 snprintf(oldfile, sizeof(oldfile), "%s%s.O", ServerRoot, con->uri + 11);
2771
2772 LogMessage(L_INFO, "Installing config file \"%s\"...", conffile);
2773
2774 /*
2775 * Get the owner, group, and permissions of the configuration file.
2776 * If it doesn't exist, assign it to the User and Group in the
2777 * cupsd.conf file with mode 0640 permissions.
2778 */
2779
2780 if (stat(conffile, &confinfo))
2781 {
2782 confinfo.st_uid = User;
2783 confinfo.st_gid = Group;
2784 confinfo.st_mode = ConfigFilePerm;
2785 }
2786
2787 /*
2788 * Open the request file and new config file...
2789 */
2790
2791 if ((in = cupsFileOpen(con->filename, "rb")) == NULL)
2792 {
2793 LogMessage(L_ERROR, "Unable to open request file \"%s\" - %s",
2794 con->filename, strerror(errno));
2795 return (HTTP_SERVER_ERROR);
2796 }
2797
2798 if ((out = cupsFileOpen(newfile, "wb")) == NULL)
2799 {
2800 cupsFileClose(in);
2801 LogMessage(L_ERROR, "Unable to open config file \"%s\" - %s",
2802 newfile, strerror(errno));
2803 return (HTTP_SERVER_ERROR);
2804 }
2805
2806 fchmod(cupsFileNumber(out), confinfo.st_mode);
2807 fchown(cupsFileNumber(out), confinfo.st_uid, confinfo.st_gid);
2808
2809 /*
2810 * Copy from the request to the new config file...
2811 */
2812
2813 while ((bytes = cupsFileRead(in, buffer, sizeof(buffer))) > 0)
2814 if (cupsFileWrite(out, buffer, bytes) < bytes)
2815 {
2816 LogMessage(L_ERROR, "Unable to copy to config file \"%s\" - %s",
2817 newfile, strerror(errno));
2818
2819 cupsFileClose(in);
2820 cupsFileClose(out);
2821 unlink(newfile);
2822
2823 return (HTTP_SERVER_ERROR);
2824 }
2825
2826 /*
2827 * Close the files...
2828 */
2829
2830 cupsFileClose(in);
2831 if (cupsFileClose(out))
2832 {
2833 LogMessage(L_ERROR, "Error file closing config file \"%s\" - %s",
2834 newfile, strerror(errno));
2835
2836 unlink(newfile);
2837
2838 return (HTTP_SERVER_ERROR);
2839 }
2840
2841 /*
2842 * Remove the request file...
2843 */
2844
2845 unlink(con->filename);
2846 ClearString(&con->filename);
2847
2848 /*
2849 * Unlink the old backup, rename the current config file to the backup
2850 * filename, and rename the new config file to the config file name...
2851 */
2852
2853 if (unlink(oldfile))
2854 if (errno != ENOENT)
2855 {
2856 LogMessage(L_ERROR, "Unable to remove backup config file \"%s\" - %s",
2857 oldfile, strerror(errno));
2858
2859 unlink(newfile);
2860
2861 return (HTTP_SERVER_ERROR);
2862 }
2863
2864 if (rename(conffile, oldfile))
2865 if (errno != ENOENT)
2866 {
2867 LogMessage(L_ERROR, "Unable to rename old config file \"%s\" - %s",
2868 conffile, strerror(errno));
2869
2870 unlink(newfile);
2871
2872 return (HTTP_SERVER_ERROR);
2873 }
2874
2875 if (rename(newfile, conffile))
2876 {
2877 LogMessage(L_ERROR, "Unable to rename new config file \"%s\" - %s",
2878 newfile, strerror(errno));
2879
2880 rename(oldfile, conffile);
2881 unlink(newfile);
2882
2883 return (HTTP_SERVER_ERROR);
2884 }
2885
2886 /*
2887 * If the cupsd.conf file was updated, set the NeedReload flag...
2888 */
2889
2890 if (strcmp(con->uri, "/admin/conf/cupsd.conf") == 0)
2891 NeedReload = RELOAD_CUPSD;
2892 else
2893 NeedReload = RELOAD_ALL;
2894
2895 /*
2896 * Return that the file was created successfully...
2897 */
2898
2899 return (HTTP_CREATED);
2900 }
2901
2902
2903 /*
2904 * 'pipe_command()' - Pipe the output of a command to the remote client.
2905 */
2906
2907 static int /* O - Process ID */
2908 pipe_command(client_t *con, /* I - Client connection */
2909 int infile, /* I - Standard input for command */
2910 int *outfile, /* O - Standard output for command */
2911 char *command, /* I - Command to run */
2912 char *options) /* I - Options for command */
2913 {
2914 int i; /* Looping var */
2915 int pid; /* Process ID */
2916 char *commptr; /* Command string pointer */
2917 char *uriptr; /* URI string pointer */
2918 int fd; /* Looping var */
2919 int fds[2]; /* Pipe FDs */
2920 int argc; /* Number of arguments */
2921 int envc; /* Number of environment variables */
2922 char argbuf[10240], /* Argument buffer */
2923 *argv[100], /* Argument strings */
2924 *envp[100]; /* Environment variables */
2925 char content_length[1024], /* CONTENT_LENGTH environment variable */
2926 content_type[1024], /* CONTENT_TYPE environment variable */
2927 cups_datadir[1024], /* CUPS_DATADIR environment variable */
2928 cups_serverroot[1024], /* CUPS_SERVERROOT environment variable */
2929 http_cookie[1024], /* HTTP_COOKIE environment variable */
2930 http_user_agent[1024], /* HTTP_USER_AGENT environment variable */
2931 ipp_port[1024], /* IPP_PORT environment variable */
2932 lang[1024], /* LANG environment variable */
2933 ld_library_path[1024], /* LD_LIBRARY_PATH environment variable */
2934 ld_preload[1024], /* LD_PRELOAD environment variable */
2935 dyld_library_path[1024],/* DYLD_LIBRARY_PATH environment variable */
2936 shlib_path[1024], /* SHLIB_PATH environment variable */
2937 nlspath[1024], /* NLSPATH environment variable */
2938 query_string[10240], /* QUERY_STRING env variable */
2939 remote_addr[1024], /* REMOTE_ADDR environment variable */
2940 remote_host[1024], /* REMOTE_HOST environment variable */
2941 remote_user[1024], /* REMOTE_USER environment variable */
2942 script_name[1024], /* SCRIPT_NAME environment variable */
2943 server_name[1024], /* SERVER_NAME environment variable */
2944 server_port[1024], /* SERVER_PORT environment variable */
2945 tmpdir[1024]; /* TMPDIR environment variable */
2946 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
2947 struct sigaction action; /* POSIX signal handler */
2948 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
2949
2950
2951 /*
2952 * Copy the command string...
2953 */
2954
2955 strlcpy(argbuf, options, sizeof(argbuf));
2956
2957 /*
2958 * Parse the string; arguments can be separated by + and are terminated
2959 * by ?...
2960 */
2961
2962 argv[0] = argbuf;
2963
2964 for (commptr = argbuf, argc = 1; *commptr != '\0' && argc < 99; commptr ++)
2965 if (*commptr == ' ' || *commptr == '+')
2966 {
2967 *commptr++ = '\0';
2968
2969 while (*commptr == ' ')
2970 commptr ++;
2971
2972 if (*commptr != '\0')
2973 {
2974 argv[argc] = commptr;
2975 argc ++;
2976 }
2977
2978 commptr --;
2979 }
2980 else if (*commptr == '%')
2981 {
2982 if (commptr[1] >= '0' && commptr[1] <= '9')
2983 *commptr = (commptr[1] - '0') << 4;
2984 else
2985 *commptr = (tolower(commptr[1]) - 'a' + 10) << 4;
2986
2987 if (commptr[2] >= '0' && commptr[2] <= '9')
2988 *commptr |= commptr[2] - '0';
2989 else
2990 *commptr |= tolower(commptr[2]) - 'a' + 10;
2991
2992 strcpy(commptr + 1, commptr + 3);
2993 }
2994 else if (*commptr == '?')
2995 break;
2996
2997 argv[argc] = NULL;
2998
2999 if (argv[0][0] == '\0')
3000 argv[0] = strrchr(command, '/') + 1;
3001
3002 /*
3003 * Setup the environment variables as needed...
3004 */
3005
3006 snprintf(lang, sizeof(lang), "LANG=%s",
3007 con->language ? con->language->language : "C");
3008 #ifdef AF_INET6
3009 if (con->http.hostaddr.addr.sa_family == AF_INET6)
3010 {
3011 sprintf(ipp_port, "IPP_PORT=%d", ntohs(con->http.hostaddr.ipv6.sin6_port));
3012 sprintf(server_port, "SERVER_PORT=%d",
3013 ntohs(con->http.hostaddr.ipv6.sin6_port));
3014 }
3015 else
3016 #endif /* AF_INET6 */
3017 {
3018 sprintf(ipp_port, "IPP_PORT=%d", ntohs(con->http.hostaddr.ipv4.sin_port));
3019 sprintf(server_port, "SERVER_PORT=%d",
3020 ntohs(con->http.hostaddr.ipv4.sin_port));
3021 }
3022
3023 if (strcmp(con->http.hostname, "localhost") == 0)
3024 strlcpy(server_name, "SERVER_NAME=localhost", sizeof(server_name));
3025 else
3026 snprintf(server_name, sizeof(server_name), "SERVER_NAME=%s", ServerName);
3027 snprintf(remote_host, sizeof(remote_host), "REMOTE_HOST=%s", con->http.hostname);
3028 strcpy(remote_addr, "REMOTE_ADDR=");
3029 httpAddrString(&(con->http.hostaddr), remote_addr + 12,
3030 sizeof(remote_addr) - 12);
3031 snprintf(remote_user, sizeof(remote_user), "REMOTE_USER=%s", con->username);
3032 snprintf(tmpdir, sizeof(tmpdir), "TMPDIR=%s", TempDir);
3033 snprintf(cups_datadir, sizeof(cups_datadir), "CUPS_DATADIR=%s", DataDir);
3034 snprintf(cups_serverroot, sizeof(cups_serverroot), "CUPS_SERVERROOT=%s", ServerRoot);
3035
3036 envc = 0;
3037
3038 envp[envc ++] = "PATH=/bin:/usr/bin";
3039 envp[envc ++] = "SERVER_SOFTWARE=CUPS/1.1";
3040 envp[envc ++] = "GATEWAY_INTERFACE=CGI/1.1";
3041 if (con->http.version == HTTP_1_1)
3042 envp[envc ++] = "SERVER_PROTOCOL=HTTP/1.1";
3043 else if (con->http.version == HTTP_1_0)
3044 envp[envc ++] = "SERVER_PROTOCOL=HTTP/1.0";
3045 else
3046 envp[envc ++] = "SERVER_PROTOCOL=HTTP/0.9";
3047 envp[envc ++] = "REDIRECT_STATUS=1";
3048 envp[envc ++] = ipp_port;
3049 envp[envc ++] = server_name;
3050 envp[envc ++] = server_port;
3051 envp[envc ++] = remote_addr;
3052 envp[envc ++] = remote_host;
3053 envp[envc ++] = remote_user;
3054 envp[envc ++] = lang;
3055 envp[envc ++] = TZ;
3056 envp[envc ++] = tmpdir;
3057 envp[envc ++] = cups_datadir;
3058 envp[envc ++] = cups_serverroot;
3059
3060 if (getenv("LD_LIBRARY_PATH") != NULL)
3061 {
3062 snprintf(ld_library_path, sizeof(ld_library_path), "LD_LIBRARY_PATH=%s",
3063 getenv("LD_LIBRARY_PATH"));
3064 envp[envc ++] = ld_library_path;
3065 }
3066
3067 if (getenv("LD_PRELOAD") != NULL)
3068 {
3069 snprintf(ld_preload, sizeof(ld_preload), "LD_PRELOAD=%s",
3070 getenv("LD_PRELOAD"));
3071 envp[envc ++] = ld_preload;
3072 }
3073
3074 if (getenv("DYLD_LIBRARY_PATH") != NULL)
3075 {
3076 snprintf(dyld_library_path, sizeof(dyld_library_path), "DYLD_LIBRARY_PATH=%s",
3077 getenv("DYLD_LIBRARY_PATH"));
3078 envp[envc ++] = dyld_library_path;
3079 }
3080
3081 if (getenv("SHLIB_PATH") != NULL)
3082 {
3083 snprintf(shlib_path, sizeof(shlib_path), "SHLIB_PATH=%s",
3084 getenv("SHLIB_PATH"));
3085 envp[envc ++] = shlib_path;
3086 }
3087
3088 if (getenv("NLSPATH") != NULL)
3089 {
3090 snprintf(nlspath, sizeof(nlspath), "NLSPATH=%s", getenv("NLSPATH"));
3091 envp[envc ++] = nlspath;
3092 }
3093
3094 if (con->http.cookie)
3095 {
3096 snprintf(http_cookie, sizeof(http_cookie), "HTTP_COOKIE=%s",
3097 con->http.cookie);
3098 envp[envc ++] = http_cookie;
3099 }
3100
3101 if (con->http.fields[HTTP_FIELD_USER_AGENT][0])
3102 {
3103 snprintf(http_user_agent, sizeof(http_user_agent), "HTTP_USER_AGENT=%s",
3104 con->http.fields[HTTP_FIELD_USER_AGENT]);
3105 envp[envc ++] = http_user_agent;
3106 }
3107
3108 snprintf(script_name, sizeof(script_name), "SCRIPT_NAME=%s", con->uri);
3109 if ((uriptr = strchr(script_name, '?')) != NULL)
3110 *uriptr = '\0';
3111 envp[envc ++] = script_name;
3112
3113 if (con->operation == HTTP_GET)
3114 {
3115 for (i = 0; i < argc; i ++)
3116 LogMessage(L_DEBUG2, "argv[%d] = \"%s\"", i, argv[i]);
3117 envp[envc ++] = "REQUEST_METHOD=GET";
3118
3119 if (*commptr)
3120 {
3121 /*
3122 * Add GET form variables after ?...
3123 */
3124
3125 *commptr++ = '\0';
3126
3127 snprintf(query_string, sizeof(query_string), "QUERY_STRING=%s", commptr);
3128 envp[envc ++] = query_string;
3129 }
3130 }
3131 else
3132 {
3133 sprintf(content_length, "CONTENT_LENGTH=%d", con->bytes);
3134 snprintf(content_type, sizeof(content_type), "CONTENT_TYPE=%s",
3135 con->http.fields[HTTP_FIELD_CONTENT_TYPE]);
3136
3137 envp[envc ++] = "REQUEST_METHOD=POST";
3138 envp[envc ++] = content_length;
3139 envp[envc ++] = content_type;
3140 }
3141
3142 /*
3143 * Tell the CGI if we are using encryption...
3144 */
3145
3146 if (con->http.encryption == HTTP_ENCRYPT_ALWAYS)
3147 {
3148 envp[envc ++] = "HTTPS=ON";
3149 envp[envc ++] = "CUPS_ENCRYPTION=Always";
3150 }
3151
3152 envp[envc] = NULL;
3153
3154 if (LogLevel == L_DEBUG2)
3155 {
3156 for (i = 0; i < argc; i ++)
3157 LogMessage(L_DEBUG2, "argv[%d] = \"%s\"", i, argv[i]);
3158 for (i = 0; i < envc; i ++)
3159 LogMessage(L_DEBUG2, "envp[%d] = \"%s\"", i, envp[i]);
3160 }
3161
3162 /*
3163 * Create a pipe for the output...
3164 */
3165
3166 if (pipe(fds))
3167 {
3168 LogMessage(L_ERROR, "Unable to create pipes for CGI %s - %s",
3169 argv[0], strerror(errno));
3170 return (0);
3171 }
3172
3173 /*
3174 * Block signals before forking...
3175 */
3176
3177 HoldSignals();
3178
3179 /*
3180 * Then execute the command...
3181 */
3182
3183 if ((pid = fork()) == 0)
3184 {
3185 /*
3186 * Child comes here... Close stdin if necessary and dup the pipe to stdout.
3187 */
3188
3189 if (getuid() == 0)
3190 {
3191 /*
3192 * Running as root, so change to a non-priviledged user...
3193 */
3194
3195 if (setgid(Group))
3196 exit(errno);
3197
3198 if (setuid(User))
3199 exit(errno);
3200 }
3201
3202 /*
3203 * Reset group membership to just the main one we belong to.
3204 */
3205
3206 setgroups(0, NULL);
3207
3208 /*
3209 * Update stdin/stdout/stderr...
3210 */
3211
3212 if (infile)
3213 {
3214 close(0);
3215 if (dup(infile) < 0)
3216 exit(errno);
3217 }
3218
3219 close(1);
3220 if (dup(fds[1]) < 0)
3221 exit(errno);
3222
3223 close(2);
3224 dup(CGIPipes[1]);
3225
3226 /*
3227 * Close extra file descriptors...
3228 */
3229
3230 for (fd = 3; fd < MaxFDs; fd ++)
3231 close(fd);
3232
3233 /*
3234 * Change umask to restrict permissions on created files...
3235 */
3236
3237 umask(077);
3238
3239 /*
3240 * Unblock signals before doing the exec...
3241 */
3242
3243 #ifdef HAVE_SIGSET
3244 sigset(SIGTERM, SIG_DFL);
3245 sigset(SIGCHLD, SIG_DFL);
3246 #elif defined(HAVE_SIGACTION)
3247 memset(&action, 0, sizeof(action));
3248
3249 sigemptyset(&action.sa_mask);
3250 action.sa_handler = SIG_DFL;
3251
3252 sigaction(SIGTERM, &action, NULL);
3253 sigaction(SIGCHLD, &action, NULL);
3254 #else
3255 signal(SIGTERM, SIG_DFL);
3256 signal(SIGCHLD, SIG_DFL);
3257 #endif /* HAVE_SIGSET */
3258
3259 ReleaseSignals();
3260
3261 /*
3262 * Execute the pipe program; if an error occurs, exit with status 1...
3263 */
3264
3265 execve(command, argv, envp);
3266 exit(errno);
3267 return (0);
3268 }
3269 else if (pid < 0)
3270 {
3271 /*
3272 * Error - can't fork!
3273 */
3274
3275 LogMessage(L_ERROR, "Unable to fork for CGI %s - %s", argv[0],
3276 strerror(errno));
3277
3278 close(fds[0]);
3279 close(fds[1]);
3280 pid = 0;
3281 }
3282 else
3283 {
3284 /*
3285 * Fork successful - return the PID...
3286 */
3287
3288 AddCert(pid, con->username);
3289
3290 LogMessage(L_DEBUG, "CGI %s started - PID = %d", command, pid);
3291
3292 *outfile = fds[0];
3293 close(fds[1]);
3294 }
3295
3296 ReleaseSignals();
3297
3298 return (pid);
3299 }
3300
3301
3302 #if defined(HAVE_CDSASSL)
3303 /*
3304 * 'CDSAReadFunc()' - Read function for CDSA decryption code.
3305 */
3306
3307 static OSStatus /* O - -1 on error, 0 on success */
3308 CDSAReadFunc(SSLConnectionRef connection, /* I - SSL/TLS connection */
3309 void *data, /* I - Data buffer */
3310 size_t *dataLength) /* IO - Number of bytes */
3311 {
3312 ssize_t bytes; /* Number of bytes read */
3313
3314
3315 bytes = recv((int)connection, data, *dataLength, 0);
3316 if (bytes >= 0)
3317 {
3318 *dataLength = bytes;
3319 return (0);
3320 }
3321 else
3322 return (-1);
3323 }
3324
3325
3326 /*
3327 * 'CDSAWriteFunc()' - Write function for CDSA encryption code.
3328 */
3329
3330 static OSStatus /* O - -1 on error, 0 on success */
3331 CDSAWriteFunc(SSLConnectionRef connection, /* I - SSL/TLS connection */
3332 const void *data, /* I - Data buffer */
3333 size_t *dataLength) /* IO - Number of bytes */
3334 {
3335 ssize_t bytes;
3336
3337
3338 bytes = write((int)connection, data, *dataLength);
3339 if (bytes >= 0)
3340 {
3341 *dataLength = bytes;
3342 return (0);
3343 }
3344 else
3345 return (-1);
3346 }
3347 #endif /* HAVE_CDSASSL */
3348
3349
3350 /*
3351 * End of "$Id: client.c,v 1.91.2.60 2003/05/09 16:10:38 mike Exp $".
3352 */