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