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