]> 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.56 2003/03/30 21:49:15 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_SEND)
1876 {
1877 CloseClient(con);
1878 return (0);
1879 }
1880 }
1881
1882 if (con->http.state == HTTP_POST_SEND)
1883 {
1884 if (con->file)
1885 {
1886 fstat(con->file, &filestats);
1887
1888 LogMessage(L_DEBUG2, "ReadClient() %d Closing data file %d, size = %d.",
1889 con->http.fd, con->file, (int)filestats.st_size);
1890
1891 close(con->file);
1892 con->file = 0;
1893
1894 if (filestats.st_size > MaxRequestSize &&
1895 MaxRequestSize > 0)
1896 {
1897 /*
1898 * Request is too big; remove it and send an error...
1899 */
1900
1901 LogMessage(L_DEBUG2, "ReadClient() %d Removing temp file %s",
1902 con->http.fd, con->filename);
1903 unlink(con->filename);
1904 ClearString(&con->filename);
1905
1906 if (con->request)
1907 {
1908 /*
1909 * Delete any IPP request data...
1910 */
1911
1912 ippDelete(con->request);
1913 con->request = NULL;
1914 }
1915
1916 if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
1917 {
1918 CloseClient(con);
1919 return (0);
1920 }
1921 }
1922
1923 if (con->command)
1924 {
1925 if (!SendCommand(con, con->command, con->options))
1926 {
1927 if (!SendError(con, HTTP_NOT_FOUND))
1928 {
1929 CloseClient(con);
1930 return (0);
1931 }
1932 }
1933 else
1934 LogRequest(con, HTTP_OK);
1935 }
1936 }
1937
1938 if (con->request)
1939 return (ProcessIPPRequest(con));
1940 }
1941 break;
1942
1943 default :
1944 break; /* Anti-compiler-warning-code */
1945 }
1946
1947 if (!con->http.keep_alive && con->http.state == HTTP_WAITING)
1948 {
1949 CloseClient(con);
1950 return (0);
1951 }
1952 else
1953 return (1);
1954 }
1955
1956
1957 /*
1958 * 'SendCommand()' - Send output from a command via HTTP.
1959 */
1960
1961 int
1962 SendCommand(client_t *con,
1963 char *command,
1964 char *options)
1965 {
1966 int fd;
1967
1968
1969 if (con->filename)
1970 fd = open(con->filename, O_RDONLY);
1971 else
1972 fd = open("/dev/null", O_RDONLY);
1973
1974 con->pipe_pid = pipe_command(con, fd, &(con->file), command, options);
1975
1976 close(fd);
1977
1978 LogMessage(L_INFO, "Started \"%s\" (pid=%d)", command, con->pipe_pid);
1979
1980 LogMessage(L_DEBUG, "SendCommand() %d file=%d", con->http.fd, con->file);
1981
1982 if (con->pipe_pid == 0)
1983 return (0);
1984
1985 fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
1986
1987 LogMessage(L_DEBUG2, "SendCommand: Adding fd %d to InputSet...", con->file);
1988 LogMessage(L_DEBUG2, "SendCommand: Adding fd %d to OutputSet...",
1989 con->http.fd);
1990
1991 FD_SET(con->file, InputSet);
1992 FD_SET(con->http.fd, OutputSet);
1993
1994 if (!SendHeader(con, HTTP_OK, NULL))
1995 return (0);
1996
1997 if (con->http.version == HTTP_1_1)
1998 {
1999 con->http.data_encoding = HTTP_ENCODE_CHUNKED;
2000
2001 if (httpPrintf(HTTP(con), "Transfer-Encoding: chunked\r\n") < 0)
2002 return (0);
2003 }
2004
2005 con->got_fields = 0;
2006 con->field_col = 0;
2007
2008 return (1);
2009 }
2010
2011
2012 /*
2013 * 'SendError()' - Send an error message via HTTP.
2014 */
2015
2016 int /* O - 1 if successful, 0 otherwise */
2017 SendError(client_t *con, /* I - Connection */
2018 http_status_t code) /* I - Error code */
2019 {
2020 char message[1024]; /* Message for user */
2021
2022
2023 /*
2024 * Put the request in the access_log file...
2025 */
2026
2027 if (con->operation > HTTP_WAITING)
2028 LogRequest(con, code);
2029
2030 LogMessage(L_DEBUG, "SendError() %d code=%d", con->http.fd, code);
2031
2032 /*
2033 * To work around bugs in some proxies, don't use Keep-Alive for some
2034 * error messages...
2035 */
2036
2037 if (code >= HTTP_BAD_REQUEST)
2038 con->http.keep_alive = HTTP_KEEPALIVE_OFF;
2039
2040 /*
2041 * Send an error message back to the client. If the error code is a
2042 * 400 or 500 series, make sure the message contains some text, too!
2043 */
2044
2045 if (!SendHeader(con, code, NULL))
2046 return (0);
2047
2048 #ifdef HAVE_SSL
2049 if (code == HTTP_UPGRADE_REQUIRED)
2050 if (httpPrintf(HTTP(con), "Connection: Upgrade\r\n") < 0)
2051 return (0);
2052
2053 if (httpPrintf(HTTP(con), "Upgrade: TLS/1.0,HTTP/1.1\r\n") < 0)
2054 return (0);
2055 #endif /* HAVE_SSL */
2056
2057 if ((con->http.version >= HTTP_1_1 && !con->http.keep_alive) ||
2058 (code >= HTTP_BAD_REQUEST && code != HTTP_UPGRADE_REQUIRED))
2059 {
2060 if (httpPrintf(HTTP(con), "Connection: close\r\n") < 0)
2061 return (0);
2062 }
2063
2064 if (code >= HTTP_BAD_REQUEST)
2065 {
2066 /*
2067 * Send a human-readable error message.
2068 */
2069
2070 snprintf(message, sizeof(message),
2071 "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>"
2072 "<BODY><H1>%s</H1>%s</BODY></HTML>\n",
2073 code, httpStatus(code), httpStatus(code),
2074 con->language ? con->language->messages[code] :
2075 httpStatus(code));
2076
2077 if (httpPrintf(HTTP(con), "Content-Type: text/html\r\n") < 0)
2078 return (0);
2079 if (httpPrintf(HTTP(con), "Content-Length: %d\r\n",
2080 (int)strlen(message)) < 0)
2081 return (0);
2082 if (httpPrintf(HTTP(con), "\r\n") < 0)
2083 return (0);
2084 if (httpPrintf(HTTP(con), "%s", message) < 0)
2085 return (0);
2086 }
2087 else if (httpPrintf(HTTP(con), "\r\n") < 0)
2088 return (0);
2089
2090 con->http.state = HTTP_WAITING;
2091
2092 return (1);
2093 }
2094
2095
2096 /*
2097 * 'SendFile()' - Send a file via HTTP.
2098 */
2099
2100 int
2101 SendFile(client_t *con,
2102 http_status_t code,
2103 char *filename,
2104 char *type,
2105 struct stat *filestats)
2106 {
2107 con->file = open(filename, O_RDONLY);
2108
2109 LogMessage(L_DEBUG, "SendFile() %d file=%d", con->http.fd, con->file);
2110
2111 if (con->file < 0)
2112 return (0);
2113
2114 fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
2115
2116 con->pipe_pid = 0;
2117
2118 if (!SendHeader(con, code, type))
2119 return (0);
2120
2121 if (httpPrintf(HTTP(con), "Last-Modified: %s\r\n", httpGetDateString(filestats->st_mtime)) < 0)
2122 return (0);
2123 if (httpPrintf(HTTP(con), "Content-Length: %lu\r\n",
2124 (unsigned long)filestats->st_size) < 0)
2125 return (0);
2126 if (httpPrintf(HTTP(con), "\r\n") < 0)
2127 return (0);
2128
2129 LogMessage(L_DEBUG2, "SendFile: Adding fd %d to OutputSet...", con->http.fd);
2130
2131 FD_SET(con->http.fd, OutputSet);
2132
2133 return (1);
2134 }
2135
2136
2137 /*
2138 * 'SendHeader()' - Send an HTTP request.
2139 */
2140
2141 int /* O - 1 on success, 0 on failure */
2142 SendHeader(client_t *con, /* I - Client to send to */
2143 http_status_t code, /* I - HTTP status code */
2144 char *type) /* I - MIME type of document */
2145 {
2146 location_t *loc; /* Authentication location */
2147
2148
2149 if (httpPrintf(HTTP(con), "HTTP/%d.%d %d %s\r\n", con->http.version / 100,
2150 con->http.version % 100, code, httpStatus(code)) < 0)
2151 return (0);
2152 if (httpPrintf(HTTP(con), "Date: %s\r\n", httpGetDateString(time(NULL))) < 0)
2153 return (0);
2154 if (httpPrintf(HTTP(con), "Server: CUPS/1.1\r\n") < 0)
2155 return (0);
2156 if (con->http.keep_alive && con->http.version >= HTTP_1_0)
2157 {
2158 if (httpPrintf(HTTP(con), "Connection: Keep-Alive\r\n") < 0)
2159 return (0);
2160 if (httpPrintf(HTTP(con), "Keep-Alive: timeout=%d\r\n", KeepAliveTimeout) < 0)
2161 return (0);
2162 }
2163 if (code == HTTP_METHOD_NOT_ALLOWED)
2164 if (httpPrintf(HTTP(con), "Allow: GET, HEAD, OPTIONS, POST\r\n") < 0)
2165 return (0);
2166
2167 if (code == HTTP_UNAUTHORIZED)
2168 {
2169 /*
2170 * This already succeeded in IsAuthorized...
2171 */
2172
2173 loc = FindBest(con->uri, con->http.state);
2174
2175 if (loc->type != AUTH_DIGEST)
2176 {
2177 if (httpPrintf(HTTP(con), "WWW-Authenticate: Basic realm=\"CUPS\"\r\n") < 0)
2178 return (0);
2179 }
2180 else
2181 {
2182 if (httpPrintf(HTTP(con), "WWW-Authenticate: Digest realm=\"CUPS\" "
2183 "nonce=\"%s\"\r\n", con->http.hostname) < 0)
2184 return (0);
2185 }
2186 }
2187 if (con->language != NULL)
2188 {
2189 if (httpPrintf(HTTP(con), "Content-Language: %s\r\n",
2190 con->language->language) < 0)
2191 return (0);
2192
2193 if (type != NULL)
2194 if (httpPrintf(HTTP(con), "Content-Type: %s; charset=%s\r\n", type,
2195 cupsLangEncoding(con->language)) < 0)
2196 return (0);
2197 }
2198 else if (type != NULL)
2199 if (httpPrintf(HTTP(con), "Content-Type: %s\r\n", type) < 0)
2200 return (0);
2201
2202 return (1);
2203 }
2204
2205
2206 /*
2207 * 'ShutdownClient()' - Shutdown the receiving end of a connection.
2208 */
2209
2210 void
2211 ShutdownClient(client_t *con) /* I - Client connection */
2212 {
2213 /*
2214 * Shutdown the receiving end of the socket, since the client
2215 * still needs to read the error message...
2216 */
2217
2218 shutdown(con->http.fd, 0);
2219 con->http.used = 0;
2220
2221 /*
2222 * Update the activity time so that we timeout after 30 seconds rather
2223 * then the current Timeout setting (300 by default). This prevents
2224 * some DoS situations...
2225 */
2226
2227 con->http.activity = time(NULL) - Timeout + 30;
2228
2229 LogMessage(L_DEBUG2, "ShutdownClient: Removing fd %d from InputSet...",
2230 con->http.fd);
2231
2232 FD_CLR(con->http.fd, InputSet);
2233 }
2234
2235
2236 /*
2237 * 'UpdateCGI()' - Read status messages from CGI scripts and programs.
2238 */
2239
2240 void
2241 UpdateCGI(void)
2242 {
2243 int bytes; /* Number of bytes read */
2244 char *lineptr, /* Pointer to end of line in buffer */
2245 *message; /* Pointer to message text */
2246 int loglevel; /* Log level for message */
2247 static int bufused = 0; /* Number of bytes used in buffer */
2248 static char buffer[1024]; /* Status buffer */
2249
2250
2251 if ((bytes = read(CGIPipes[0], buffer + bufused,
2252 sizeof(buffer) - bufused - 1)) > 0)
2253 {
2254 bufused += bytes;
2255 buffer[bufused] = '\0';
2256 lineptr = strchr(buffer, '\n');
2257 }
2258 else if (bytes < 0 && errno == EINTR)
2259 return;
2260 else
2261 {
2262 lineptr = buffer + bufused;
2263 lineptr[1] = 0;
2264 }
2265
2266 if (bytes == 0 && bufused == 0)
2267 lineptr = NULL;
2268
2269 while (lineptr != NULL)
2270 {
2271 /*
2272 * Terminate each line and process it...
2273 */
2274
2275 *lineptr++ = '\0';
2276
2277 /*
2278 * Figure out the logging level...
2279 */
2280
2281 if (strncmp(buffer, "EMERG:", 6) == 0)
2282 {
2283 loglevel = L_EMERG;
2284 message = buffer + 6;
2285 }
2286 else if (strncmp(buffer, "ALERT:", 6) == 0)
2287 {
2288 loglevel = L_ALERT;
2289 message = buffer + 6;
2290 }
2291 else if (strncmp(buffer, "CRIT:", 5) == 0)
2292 {
2293 loglevel = L_CRIT;
2294 message = buffer + 5;
2295 }
2296 else if (strncmp(buffer, "ERROR:", 6) == 0)
2297 {
2298 loglevel = L_ERROR;
2299 message = buffer + 6;
2300 }
2301 else if (strncmp(buffer, "WARNING:", 8) == 0)
2302 {
2303 loglevel = L_WARN;
2304 message = buffer + 8;
2305 }
2306 else if (strncmp(buffer, "NOTICE:", 6) == 0)
2307 {
2308 loglevel = L_NOTICE;
2309 message = buffer + 6;
2310 }
2311 else if (strncmp(buffer, "INFO:", 5) == 0)
2312 {
2313 loglevel = L_INFO;
2314 message = buffer + 5;
2315 }
2316 else if (strncmp(buffer, "DEBUG:", 6) == 0)
2317 {
2318 loglevel = L_DEBUG;
2319 message = buffer + 6;
2320 }
2321 else if (strncmp(buffer, "DEBUG2:", 7) == 0)
2322 {
2323 loglevel = L_DEBUG2;
2324 message = buffer + 7;
2325 }
2326 else if (strncmp(buffer, "PAGE:", 5) == 0)
2327 {
2328 loglevel = L_PAGE;
2329 message = buffer + 5;
2330 }
2331 else
2332 {
2333 loglevel = L_DEBUG;
2334 message = buffer;
2335 }
2336
2337 /*
2338 * Skip leading whitespace in the message...
2339 */
2340
2341 while (isspace(*message))
2342 message ++;
2343
2344 LogMessage(loglevel, "[CGI] %s", message);
2345
2346 /*
2347 * Copy over the buffer data we've used up...
2348 */
2349
2350 strcpy(buffer, lineptr);
2351 bufused -= lineptr - buffer;
2352
2353 if (bufused < 0)
2354 bufused = 0;
2355
2356 lineptr = strchr(buffer, '\n');
2357 }
2358
2359 if (bytes <= 0)
2360 {
2361 /*
2362 * Fatal error on pipe - should never happen!
2363 */
2364
2365 LogMessage(L_ERROR, "UpdateCGI: error reading from CGI error pipe - %s",
2366 strerror(errno));
2367 }
2368 }
2369
2370
2371 /*
2372 * 'WriteClient()' - Write data to a client as needed.
2373 */
2374
2375 int /* O - 1 if success, 0 if fail */
2376 WriteClient(client_t *con) /* I - Client connection */
2377 {
2378 int bytes; /* Number of bytes written */
2379 char buf[HTTP_MAX_BUFFER + 1];/* Data buffer */
2380 char *bufptr; /* Pointer into buffer */
2381 ipp_state_t ipp_state; /* IPP state value */
2382
2383
2384 if (con->http.state != HTTP_GET_SEND &&
2385 con->http.state != HTTP_POST_SEND)
2386 return (1);
2387
2388 if (con->response != NULL)
2389 {
2390 ipp_state = ippWrite(&(con->http), con->response);
2391 bytes = ipp_state != IPP_ERROR && ipp_state != IPP_DATA;
2392 }
2393 else if ((bytes = read(con->file, buf, HTTP_MAX_BUFFER)) > 0)
2394 {
2395 if (con->pipe_pid && !con->got_fields)
2396 {
2397 /*
2398 * Inspect the data for Content-Type and other fields.
2399 */
2400
2401 buf[bytes] = '\0';
2402
2403 for (bufptr = buf; !con->got_fields && *bufptr; bufptr ++)
2404 if (*bufptr == '\n')
2405 {
2406 /*
2407 * Send line to client...
2408 */
2409
2410 if (bufptr > buf && bufptr[-1] == '\r')
2411 bufptr[-1] = '\0';
2412 *bufptr++ = '\0';
2413
2414 httpPrintf(HTTP(con), "%s\r\n", buf);
2415 LogMessage(L_DEBUG2, "WriteClient() %d %s", con->http.fd, buf);
2416
2417 /*
2418 * Update buffer...
2419 */
2420
2421 bytes -= (bufptr - buf);
2422 memcpy(buf, bufptr, bytes + 1);
2423 bufptr = buf - 1;
2424
2425 /*
2426 * See if the line was empty...
2427 */
2428
2429 if (con->field_col == 0)
2430 con->got_fields = 1;
2431 else
2432 con->field_col = 0;
2433 }
2434 else if (*bufptr != '\r')
2435 con->field_col ++;
2436
2437 if (bytes > 0 && !con->got_fields)
2438 {
2439 /*
2440 * Remaining text needs to go out...
2441 */
2442
2443 httpPrintf(HTTP(con), "%s", buf);
2444
2445 con->http.activity = time(NULL);
2446 return (1);
2447 }
2448 else if (bytes == 0)
2449 {
2450 con->http.activity = time(NULL);
2451 return (1);
2452 }
2453 }
2454
2455 if (httpWrite(HTTP(con), buf, bytes) < 0)
2456 {
2457 CloseClient(con);
2458 return (0);
2459 }
2460
2461 con->bytes += bytes;
2462 }
2463
2464 if (bytes <= 0)
2465 {
2466 LogRequest(con, HTTP_OK);
2467
2468 if (con->http.data_encoding == HTTP_ENCODE_CHUNKED)
2469 {
2470 if (httpPrintf(HTTP(con), "0\r\n\r\n") < 0)
2471 {
2472 CloseClient(con);
2473 return (0);
2474 }
2475 }
2476
2477 con->http.state = HTTP_WAITING;
2478
2479 LogMessage(L_DEBUG2, "WriteClient() Removing fd %d from OutputSet...",
2480 con->http.fd);
2481
2482 FD_CLR(con->http.fd, OutputSet);
2483
2484 if (con->file)
2485 {
2486 LogMessage(L_DEBUG2, "WriteClient() Removing fd %d from InputSet...",
2487 con->file);
2488 FD_CLR(con->file, InputSet);
2489
2490 if (con->pipe_pid)
2491 kill(con->pipe_pid, SIGTERM);
2492
2493 LogMessage(L_DEBUG2, "WriteClient() %d Closing data file %d.",
2494 con->http.fd, con->file);
2495
2496 close(con->file);
2497 con->file = 0;
2498 con->pipe_pid = 0;
2499 }
2500
2501 if (con->filename)
2502 {
2503 LogMessage(L_DEBUG2, "WriteClient() %d Removing temp file %s",
2504 con->http.fd, con->filename);
2505 unlink(con->filename);
2506 ClearString(&con->filename);
2507 }
2508
2509 if (con->request != NULL)
2510 {
2511 ippDelete(con->request);
2512 con->request = NULL;
2513 }
2514
2515 if (con->response != NULL)
2516 {
2517 ippDelete(con->response);
2518 con->response = NULL;
2519 }
2520
2521 ClearString(&con->command);
2522 ClearString(&con->options);
2523
2524 if (!con->http.keep_alive)
2525 {
2526 CloseClient(con);
2527 return (0);
2528 }
2529 }
2530
2531 if (bytes >= 1024)
2532 LogMessage(L_DEBUG2, "WriteClient() %d %d bytes", con->http.fd, bytes);
2533
2534 con->http.activity = time(NULL);
2535
2536 return (1);
2537 }
2538
2539
2540 /*
2541 * 'check_if_modified()' - Decode an "If-Modified-Since" line.
2542 */
2543
2544 static int /* O - 1 if modified since */
2545 check_if_modified(client_t *con, /* I - Client connection */
2546 struct stat *filestats) /* I - File information */
2547 {
2548 char *ptr; /* Pointer into field */
2549 time_t date; /* Time/date value */
2550 int size; /* Size/length value */
2551
2552
2553 size = 0;
2554 date = 0;
2555 ptr = con->http.fields[HTTP_FIELD_IF_MODIFIED_SINCE];
2556
2557 if (*ptr == '\0')
2558 return (1);
2559
2560 LogMessage(L_DEBUG2, "check_if_modified() %d If-Modified-Since=\"%s\"",
2561 con->http.fd, ptr);
2562
2563 while (*ptr != '\0')
2564 {
2565 while (isspace(*ptr) || *ptr == ';')
2566 ptr ++;
2567
2568 if (strncasecmp(ptr, "length=", 7) == 0)
2569 {
2570 ptr += 7;
2571 size = atoi(ptr);
2572
2573 while (isdigit(*ptr))
2574 ptr ++;
2575 }
2576 else if (isalpha(*ptr))
2577 {
2578 date = httpGetDateTime(ptr);
2579 while (*ptr != '\0' && *ptr != ';')
2580 ptr ++;
2581 }
2582 }
2583
2584 LogMessage(L_DEBUG2, "check_if_modified() %d sizes=%d,%d dates=%d,%d",
2585 con->http.fd, size, (int)filestats->st_size, (int)date,
2586 (int)filestats->st_mtime);
2587
2588 return ((size != filestats->st_size && size != 0) ||
2589 (date < filestats->st_mtime && date != 0) ||
2590 (size == 0 && date == 0));
2591 }
2592
2593
2594 /*
2595 * 'decode_auth()' - Decode an authorization string.
2596 */
2597
2598 static void
2599 decode_auth(client_t *con) /* I - Client to decode to */
2600 {
2601 char *s, /* Authorization string */
2602 value[1024]; /* Value string */
2603 const char *username; /* Certificate username */
2604
2605
2606 /*
2607 * Decode the string...
2608 */
2609
2610 s = con->http.fields[HTTP_FIELD_AUTHORIZATION];
2611
2612 LogMessage(L_DEBUG2, "decode_auth(%p): Authorization string = \"%s\"",
2613 con, s);
2614
2615 if (strncmp(s, "Basic", 5) == 0)
2616 {
2617 s += 5;
2618 while (isspace(*s))
2619 s ++;
2620
2621 httpDecode64(value, s);
2622
2623 /*
2624 * Pull the username and password out...
2625 */
2626
2627 if ((s = strchr(value, ':')) == NULL)
2628 {
2629 LogMessage(L_DEBUG, "decode_auth() %d no colon in auth string \"%s\"",
2630 con->http.fd, value);
2631 return;
2632 }
2633
2634 *s++ = '\0';
2635
2636 strlcpy(con->username, value, sizeof(con->username));
2637 strlcpy(con->password, s, sizeof(con->password));
2638 }
2639 else if (strncmp(s, "Local", 5) == 0)
2640 {
2641 s += 5;
2642 while (isspace(*s))
2643 s ++;
2644
2645 if ((username = FindCert(s)) != NULL)
2646 strlcpy(con->username, username, sizeof(con->username));
2647 }
2648 else if (strncmp(s, "Digest", 5) == 0)
2649 {
2650 /*
2651 * Get the username and password from the Digest attributes...
2652 */
2653
2654 if (httpGetSubField(&(con->http), HTTP_FIELD_WWW_AUTHENTICATE, "username",
2655 value))
2656 strlcpy(con->username, value, sizeof(con->username));
2657
2658 if (httpGetSubField(&(con->http), HTTP_FIELD_WWW_AUTHENTICATE, "response",
2659 value))
2660 strlcpy(con->password, value, sizeof(con->password) - 1);
2661 }
2662
2663 LogMessage(L_DEBUG2, "decode_auth() %d username=\"%s\"",
2664 con->http.fd, con->username);
2665 }
2666
2667
2668 /*
2669 * 'get_file()' - Get a filename and state info.
2670 */
2671
2672 static char * /* O - Real filename */
2673 get_file(client_t *con, /* I - Client connection */
2674 struct stat *filestats,/* O - File information */
2675 char *filename, /* IO - Filename buffer */
2676 int len) /* I - Buffer length */
2677 {
2678 int status; /* Status of filesystem calls */
2679 char *params; /* Pointer to parameters in URI */
2680
2681
2682 /*
2683 * Need to add DocumentRoot global...
2684 */
2685
2686 if (strncmp(con->uri, "/ppd/", 5) == 0)
2687 snprintf(filename, len, "%s%s", ServerRoot, con->uri);
2688 else if (strncmp(con->uri, "/admin/conf/", 12) == 0)
2689 snprintf(filename, len, "%s%s", ServerRoot, con->uri + 11);
2690 else if (con->language != NULL)
2691 snprintf(filename, len, "%s/%s%s", DocumentRoot, con->language->language,
2692 con->uri);
2693 else
2694 snprintf(filename, len, "%s%s", DocumentRoot, con->uri);
2695
2696 if ((params = strchr(filename, '?')) != NULL)
2697 *params = '\0';
2698
2699 /*
2700 * Grab the status for this language; if there isn't a language-specific file
2701 * then fallback to the default one...
2702 */
2703
2704 if ((status = stat(filename, filestats)) != 0 && con->language != NULL)
2705 {
2706 /*
2707 * Drop the language prefix and try the current directory...
2708 */
2709
2710 if (strncmp(con->uri, "/ppd/", 5) != 0 &&
2711 strncmp(con->uri, "/admin/conf/", 12) != 0)
2712 {
2713 snprintf(filename, len, "%s%s", DocumentRoot, con->uri);
2714
2715 status = stat(filename, filestats);
2716 }
2717 }
2718
2719 /*
2720 * If we're found a directory, get the index.html file instead...
2721 */
2722
2723 if (!status && S_ISDIR(filestats->st_mode))
2724 {
2725 if (filename[strlen(filename) - 1] == '/')
2726 strlcat(filename, "index.html", len);
2727 else
2728 strlcat(filename, "/index.html", len);
2729
2730 status = stat(filename, filestats);
2731 }
2732
2733 LogMessage(L_DEBUG2, "get_file() %d filename=%s size=%d",
2734 con->http.fd, filename, status ? -1 : (int)filestats->st_size);
2735
2736 if (status)
2737 return (NULL);
2738 else
2739 return (filename);
2740 }
2741
2742
2743 /*
2744 * 'install_conf_file()' - Install a configuration file.
2745 */
2746
2747 static http_status_t /* O - Status */
2748 install_conf_file(client_t *con) /* I - Connection */
2749 {
2750 cups_file_t *in, /* Input file */
2751 *out; /* Output file */
2752 char buffer[1024]; /* Copy buffer */
2753 int bytes; /* Number of bytes */
2754 char conffile[1024], /* Configuration filename */
2755 newfile[1024], /* New config filename */
2756 oldfile[1024]; /* Old config filename */
2757 struct stat confinfo; /* Config file info */
2758
2759
2760 /*
2761 * First construct the filenames...
2762 */
2763
2764 snprintf(conffile, sizeof(conffile), "%s%s", ServerRoot, con->uri + 11);
2765 snprintf(newfile, sizeof(newfile), "%s%s.N", ServerRoot, con->uri + 11);
2766 snprintf(oldfile, sizeof(oldfile), "%s%s.O", ServerRoot, con->uri + 11);
2767
2768 LogMessage(L_INFO, "Installing config file \"%s\"...", conffile);
2769
2770 /*
2771 * Get the owner, group, and permissions of the configuration file.
2772 * If it doesn't exist, assign it to the User and Group in the
2773 * cupsd.conf file with mode 0640 permissions.
2774 */
2775
2776 if (stat(conffile, &confinfo))
2777 {
2778 confinfo.st_uid = User;
2779 confinfo.st_gid = Group;
2780 confinfo.st_mode = ConfigFilePerm;
2781 }
2782
2783 /*
2784 * Open the request file and new config file...
2785 */
2786
2787 if ((in = cupsFileOpen(con->filename, "rb")) == NULL)
2788 {
2789 LogMessage(L_ERROR, "Unable to open request file \"%s\" - %s",
2790 con->filename, strerror(errno));
2791 return (HTTP_SERVER_ERROR);
2792 }
2793
2794 if ((out = cupsFileOpen(newfile, "wb")) == NULL)
2795 {
2796 cupsFileClose(in);
2797 LogMessage(L_ERROR, "Unable to open config file \"%s\" - %s",
2798 newfile, strerror(errno));
2799 return (HTTP_SERVER_ERROR);
2800 }
2801
2802 fchmod(cupsFileNumber(out), confinfo.st_mode);
2803 fchown(cupsFileNumber(out), confinfo.st_uid, confinfo.st_gid);
2804
2805 /*
2806 * Copy from the request to the new config file...
2807 */
2808
2809 while ((bytes = cupsFileRead(in, buffer, sizeof(buffer))) > 0)
2810 if (cupsFileWrite(out, buffer, bytes) < bytes)
2811 {
2812 LogMessage(L_ERROR, "Unable to copy to config file \"%s\" - %s",
2813 newfile, strerror(errno));
2814
2815 cupsFileClose(in);
2816 cupsFileClose(out);
2817 unlink(newfile);
2818
2819 return (HTTP_SERVER_ERROR);
2820 }
2821
2822 /*
2823 * Close the files...
2824 */
2825
2826 cupsFileClose(in);
2827 if (cupsFileClose(out))
2828 {
2829 LogMessage(L_ERROR, "Error file closing config file \"%s\" - %s",
2830 newfile, strerror(errno));
2831
2832 unlink(newfile);
2833
2834 return (HTTP_SERVER_ERROR);
2835 }
2836
2837 /*
2838 * Remove the request file...
2839 */
2840
2841 unlink(con->filename);
2842 ClearString(&con->filename);
2843
2844 /*
2845 * Unlink the old backup, rename the current config file to the backup
2846 * filename, and rename the new config file to the config file name...
2847 */
2848
2849 if (unlink(oldfile))
2850 if (errno != ENOENT)
2851 {
2852 LogMessage(L_ERROR, "Unable to remove backup config file \"%s\" - %s",
2853 oldfile, strerror(errno));
2854
2855 unlink(newfile);
2856
2857 return (HTTP_SERVER_ERROR);
2858 }
2859
2860 if (rename(conffile, oldfile))
2861 if (errno != ENOENT)
2862 {
2863 LogMessage(L_ERROR, "Unable to rename old config file \"%s\" - %s",
2864 conffile, strerror(errno));
2865
2866 unlink(newfile);
2867
2868 return (HTTP_SERVER_ERROR);
2869 }
2870
2871 if (rename(newfile, conffile))
2872 {
2873 LogMessage(L_ERROR, "Unable to rename new config file \"%s\" - %s",
2874 newfile, strerror(errno));
2875
2876 rename(oldfile, conffile);
2877 unlink(newfile);
2878
2879 return (HTTP_SERVER_ERROR);
2880 }
2881
2882 /*
2883 * If the cupsd.conf file was updated, set the NeedReload flag...
2884 */
2885
2886 if (strcmp(con->uri, "/admin/conf/cupsd.conf") == 0)
2887 NeedReload = TRUE;
2888
2889 /*
2890 * Return that the file was created successfully...
2891 */
2892
2893 return (HTTP_CREATED);
2894 }
2895
2896
2897 /*
2898 * 'pipe_command()' - Pipe the output of a command to the remote client.
2899 */
2900
2901 static int /* O - Process ID */
2902 pipe_command(client_t *con, /* I - Client connection */
2903 int infile, /* I - Standard input for command */
2904 int *outfile, /* O - Standard output for command */
2905 char *command, /* I - Command to run */
2906 char *options) /* I - Options for command */
2907 {
2908 int i; /* Looping var */
2909 int pid; /* Process ID */
2910 char *commptr; /* Command string pointer */
2911 char *uriptr; /* URI string pointer */
2912 int fd; /* Looping var */
2913 int fds[2]; /* Pipe FDs */
2914 int argc; /* Number of arguments */
2915 int envc; /* Number of environment variables */
2916 char argbuf[10240], /* Argument buffer */
2917 *argv[100], /* Argument strings */
2918 *envp[100]; /* Environment variables */
2919 char content_length[1024], /* CONTENT_LENGTH environment variable */
2920 content_type[1024], /* CONTENT_TYPE environment variable */
2921 cups_datadir[1024], /* CUPS_DATADIR environment variable */
2922 cups_serverroot[1024], /* CUPS_SERVERROOT environment variable */
2923 http_cookie[1024], /* HTTP_COOKIE environment variable */
2924 http_user_agent[1024], /* HTTP_USER_AGENT environment variable */
2925 ipp_port[1024], /* IPP_PORT environment variable */
2926 lang[1024], /* LANG environment variable */
2927 ld_library_path[1024], /* LD_LIBRARY_PATH environment variable */
2928 nlspath[1024], /* NLSPATH environment variable */
2929 query_string[10240], /* QUERY_STRING env variable */
2930 remote_addr[1024], /* REMOTE_ADDR environment variable */
2931 remote_host[1024], /* REMOTE_HOST environment variable */
2932 remote_user[1024], /* REMOTE_USER environment variable */
2933 script_name[1024], /* SCRIPT_NAME environment variable */
2934 server_name[1024], /* SERVER_NAME environment variable */
2935 server_port[1024], /* SERVER_PORT environment variable */
2936 tmpdir[1024]; /* TMPDIR environment variable */
2937 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
2938 struct sigaction action; /* POSIX signal handler */
2939 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
2940
2941
2942 /*
2943 * Copy the command string...
2944 */
2945
2946 strlcpy(argbuf, options, sizeof(argbuf));
2947
2948 /*
2949 * Parse the string; arguments can be separated by + and are terminated
2950 * by ?...
2951 */
2952
2953 argv[0] = argbuf;
2954
2955 for (commptr = argbuf, argc = 1; *commptr != '\0' && argc < 99; commptr ++)
2956 if (*commptr == ' ' || *commptr == '+')
2957 {
2958 *commptr++ = '\0';
2959
2960 while (*commptr == ' ')
2961 commptr ++;
2962
2963 if (*commptr != '\0')
2964 {
2965 argv[argc] = commptr;
2966 argc ++;
2967 }
2968
2969 commptr --;
2970 }
2971 else if (*commptr == '%')
2972 {
2973 if (commptr[1] >= '0' && commptr[1] <= '9')
2974 *commptr = (commptr[1] - '0') << 4;
2975 else
2976 *commptr = (tolower(commptr[1]) - 'a' + 10) << 4;
2977
2978 if (commptr[2] >= '0' && commptr[2] <= '9')
2979 *commptr |= commptr[2] - '0';
2980 else
2981 *commptr |= tolower(commptr[2]) - 'a' + 10;
2982
2983 strcpy(commptr + 1, commptr + 3);
2984 }
2985 else if (*commptr == '?')
2986 break;
2987
2988 argv[argc] = NULL;
2989
2990 if (argv[0][0] == '\0')
2991 argv[0] = strrchr(command, '/') + 1;
2992
2993 /*
2994 * Setup the environment variables as needed...
2995 */
2996
2997 snprintf(lang, sizeof(lang), "LANG=%s",
2998 con->language ? con->language->language : "C");
2999 #ifdef AF_INET6
3000 if (con->http.hostaddr.addr.sa_family == AF_INET6)
3001 {
3002 sprintf(ipp_port, "IPP_PORT=%d", ntohs(con->http.hostaddr.ipv6.sin6_port));
3003 sprintf(server_port, "SERVER_PORT=%d",
3004 ntohs(con->http.hostaddr.ipv6.sin6_port));
3005 }
3006 else
3007 #endif /* AF_INET6 */
3008 {
3009 sprintf(ipp_port, "IPP_PORT=%d", ntohs(con->http.hostaddr.ipv4.sin_port));
3010 sprintf(server_port, "SERVER_PORT=%d",
3011 ntohs(con->http.hostaddr.ipv4.sin_port));
3012 }
3013
3014 if (strcmp(con->http.hostname, "localhost") == 0)
3015 strlcpy(server_name, "SERVER_NAME=localhost", sizeof(server_name));
3016 else
3017 snprintf(server_name, sizeof(server_name), "SERVER_NAME=%s", ServerName);
3018 snprintf(remote_host, sizeof(remote_host), "REMOTE_HOST=%s", con->http.hostname);
3019 strcpy(remote_addr, "REMOTE_ADDR=");
3020 httpAddrString(&(con->http.hostaddr), remote_addr + 12,
3021 sizeof(remote_addr) - 12);
3022 snprintf(remote_user, sizeof(remote_user), "REMOTE_USER=%s", con->username);
3023 snprintf(tmpdir, sizeof(tmpdir), "TMPDIR=%s", TempDir);
3024 snprintf(cups_datadir, sizeof(cups_datadir), "CUPS_DATADIR=%s", DataDir);
3025 snprintf(cups_serverroot, sizeof(cups_serverroot), "CUPS_SERVERROOT=%s", ServerRoot);
3026
3027 envc = 0;
3028
3029 envp[envc ++] = "PATH=/bin:/usr/bin";
3030 envp[envc ++] = "SERVER_SOFTWARE=CUPS/1.1";
3031 envp[envc ++] = "GATEWAY_INTERFACE=CGI/1.1";
3032 if (con->http.version == HTTP_1_1)
3033 envp[envc ++] = "SERVER_PROTOCOL=HTTP/1.1";
3034 else if (con->http.version == HTTP_1_0)
3035 envp[envc ++] = "SERVER_PROTOCOL=HTTP/1.0";
3036 else
3037 envp[envc ++] = "SERVER_PROTOCOL=HTTP/0.9";
3038 envp[envc ++] = "REDIRECT_STATUS=1";
3039 envp[envc ++] = ipp_port;
3040 envp[envc ++] = server_name;
3041 envp[envc ++] = server_port;
3042 envp[envc ++] = remote_addr;
3043 envp[envc ++] = remote_host;
3044 envp[envc ++] = remote_user;
3045 envp[envc ++] = lang;
3046 envp[envc ++] = TZ;
3047 envp[envc ++] = tmpdir;
3048 envp[envc ++] = cups_datadir;
3049 envp[envc ++] = cups_serverroot;
3050
3051 if (getenv("LD_LIBRARY_PATH") != NULL)
3052 {
3053 snprintf(ld_library_path, sizeof(ld_library_path), "LD_LIBRARY_PATH=%s",
3054 getenv("LD_LIBRARY_PATH"));
3055 envp[envc ++] = ld_library_path;
3056 }
3057 else if (getenv("DYLD_LIBRARY_PATH") != NULL)
3058 {
3059 snprintf(ld_library_path, sizeof(ld_library_path), "DYLD_LIBRARY_PATH=%s",
3060 getenv("DYLD_LIBRARY_PATH"));
3061 envp[envc ++] = ld_library_path;
3062 }
3063 else if (getenv("SHLIB_PATH") != NULL)
3064 {
3065 snprintf(ld_library_path, sizeof(ld_library_path), "SHLIB_PATH=%s",
3066 getenv("SHLIB_PATH"));
3067 envp[envc ++] = ld_library_path;
3068 }
3069
3070 if (getenv("NLSPATH") != NULL)
3071 {
3072 snprintf(nlspath, sizeof(nlspath), "NLSPATH=%s", getenv("NLSPATH"));
3073 envp[envc ++] = nlspath;
3074 }
3075
3076 if (con->http.cookie)
3077 {
3078 snprintf(http_cookie, sizeof(http_cookie), "HTTP_COOKIE=%s",
3079 con->http.cookie);
3080 envp[envc ++] = http_cookie;
3081 }
3082
3083 if (con->http.fields[HTTP_FIELD_USER_AGENT][0])
3084 {
3085 snprintf(http_user_agent, sizeof(http_user_agent), "HTTP_USER_AGENT=%s",
3086 con->http.fields[HTTP_FIELD_USER_AGENT]);
3087 envp[envc ++] = http_user_agent;
3088 }
3089
3090 snprintf(script_name, sizeof(script_name), "SCRIPT_NAME=%s", con->uri);
3091 if ((uriptr = strchr(script_name, '?')) != NULL)
3092 *uriptr = '\0';
3093 envp[envc ++] = script_name;
3094
3095 if (con->operation == HTTP_GET)
3096 {
3097 for (i = 0; i < argc; i ++)
3098 LogMessage(L_DEBUG2, "argv[%d] = \"%s\"", i, argv[i]);
3099 envp[envc ++] = "REQUEST_METHOD=GET";
3100
3101 if (*commptr)
3102 {
3103 /*
3104 * Add GET form variables after ?...
3105 */
3106
3107 *commptr++ = '\0';
3108
3109 snprintf(query_string, sizeof(query_string), "QUERY_STRING=%s", commptr);
3110 envp[envc ++] = query_string;
3111 }
3112 }
3113 else
3114 {
3115 sprintf(content_length, "CONTENT_LENGTH=%d", con->bytes);
3116 snprintf(content_type, sizeof(content_type), "CONTENT_TYPE=%s",
3117 con->http.fields[HTTP_FIELD_CONTENT_TYPE]);
3118
3119 envp[envc ++] = "REQUEST_METHOD=POST";
3120 envp[envc ++] = content_length;
3121 envp[envc ++] = content_type;
3122 }
3123
3124 /*
3125 * Tell the CGI if we are using encryption...
3126 */
3127
3128 if (con->http.encryption == HTTP_ENCRYPT_ALWAYS)
3129 {
3130 envp[envc ++] = "HTTPS=ON";
3131 envp[envc ++] = "CUPS_ENCRYPTION=Always";
3132 }
3133
3134 envp[envc] = NULL;
3135
3136 if (LogLevel == L_DEBUG2)
3137 {
3138 for (i = 0; i < argc; i ++)
3139 LogMessage(L_DEBUG2, "argv[%d] = \"%s\"", i, argv[i]);
3140 for (i = 0; i < envc; i ++)
3141 LogMessage(L_DEBUG2, "envp[%d] = \"%s\"", i, envp[i]);
3142 }
3143
3144 /*
3145 * Create a pipe for the output...
3146 */
3147
3148 if (pipe(fds))
3149 {
3150 LogMessage(L_ERROR, "Unable to create pipes for CGI %s - %s",
3151 argv[0], strerror(errno));
3152 return (0);
3153 }
3154
3155 /*
3156 * Block signals before forking...
3157 */
3158
3159 HoldSignals();
3160
3161 /*
3162 * Then execute the command...
3163 */
3164
3165 if ((pid = fork()) == 0)
3166 {
3167 /*
3168 * Child comes here... Close stdin if necessary and dup the pipe to stdout.
3169 */
3170
3171 if (getuid() == 0)
3172 {
3173 /*
3174 * Running as root, so change to a non-priviledged user...
3175 */
3176
3177 if (setgid(Group))
3178 exit(errno);
3179
3180 if (setuid(User))
3181 exit(errno);
3182 }
3183
3184 /*
3185 * Reset group membership to just the main one we belong to.
3186 */
3187
3188 setgroups(0, NULL);
3189
3190 /*
3191 * Update stdin/stdout/stderr...
3192 */
3193
3194 if (infile)
3195 {
3196 close(0);
3197 if (dup(infile) < 0)
3198 exit(errno);
3199 }
3200
3201 close(1);
3202 if (dup(fds[1]) < 0)
3203 exit(errno);
3204
3205 close(2);
3206 dup(CGIPipes[1]);
3207
3208 /*
3209 * Close extra file descriptors...
3210 */
3211
3212 for (fd = 3; fd < MaxFDs; fd ++)
3213 close(fd);
3214
3215 /*
3216 * Change umask to restrict permissions on created files...
3217 */
3218
3219 umask(077);
3220
3221 /*
3222 * Unblock signals before doing the exec...
3223 */
3224
3225 #ifdef HAVE_SIGSET
3226 sigset(SIGTERM, SIG_DFL);
3227 sigset(SIGCHLD, SIG_DFL);
3228 #elif defined(HAVE_SIGACTION)
3229 memset(&action, 0, sizeof(action));
3230
3231 sigemptyset(&action.sa_mask);
3232 action.sa_handler = SIG_DFL;
3233
3234 sigaction(SIGTERM, &action, NULL);
3235 sigaction(SIGCHLD, &action, NULL);
3236 #else
3237 signal(SIGTERM, SIG_DFL);
3238 signal(SIGCHLD, SIG_DFL);
3239 #endif /* HAVE_SIGSET */
3240
3241 ReleaseSignals();
3242
3243 /*
3244 * Execute the pipe program; if an error occurs, exit with status 1...
3245 */
3246
3247 execve(command, argv, envp);
3248 exit(errno);
3249 return (0);
3250 }
3251 else if (pid < 0)
3252 {
3253 /*
3254 * Error - can't fork!
3255 */
3256
3257 LogMessage(L_ERROR, "Unable to fork for CGI %s - %s", argv[0],
3258 strerror(errno));
3259
3260 close(fds[0]);
3261 close(fds[1]);
3262 pid = 0;
3263 }
3264 else
3265 {
3266 /*
3267 * Fork successful - return the PID...
3268 */
3269
3270 AddCert(pid, con->username);
3271
3272 LogMessage(L_DEBUG, "CGI %s started - PID = %d", command, pid);
3273
3274 *outfile = fds[0];
3275 close(fds[1]);
3276 }
3277
3278 ReleaseSignals();
3279
3280 return (pid);
3281 }
3282
3283
3284 #if defined(HAVE_CDSASSL)
3285 /*
3286 * 'CDSAReadFunc()' - Read function for CDSA decryption code.
3287 */
3288
3289 static OSStatus /* O - -1 on error, 0 on success */
3290 CDSAReadFunc(SSLConnectionRef connection, /* I - SSL/TLS connection */
3291 void *data, /* I - Data buffer */
3292 size_t *dataLength) /* IO - Number of bytes */
3293 {
3294 ssize_t bytes; /* Number of bytes read */
3295
3296
3297 bytes = recv((int)connection, data, *dataLength, 0);
3298 if (bytes >= 0)
3299 {
3300 *dataLength = bytes;
3301 return (0);
3302 }
3303 else
3304 return (-1);
3305 }
3306
3307
3308 /*
3309 * 'CDSAWriteFunc()' - Write function for CDSA encryption code.
3310 */
3311
3312 static OSStatus /* O - -1 on error, 0 on success */
3313 CDSAWriteFunc(SSLConnectionRef connection, /* I - SSL/TLS connection */
3314 const void *data, /* I - Data buffer */
3315 size_t *dataLength) /* IO - Number of bytes */
3316 {
3317 ssize_t bytes;
3318
3319
3320 bytes = write((int)connection, data, *dataLength);
3321 if (bytes >= 0)
3322 {
3323 *dataLength = bytes;
3324 return (0);
3325 }
3326 else
3327 return (-1);
3328 }
3329 #endif /* HAVE_CDSASSL */
3330
3331
3332 /*
3333 * End of "$Id: client.c,v 1.91.2.56 2003/03/30 21:49:15 mike Exp $".
3334 */