Revert manifest to default one
[external/cups.git] / scheduler / client.c
1 /*
2  * "$Id: client.c 10338 2012-03-07 06:05:39Z mike $"
3  *
4  *   Client routines for the CUPS scheduler.
5  *
6  *   Copyright 2007-2011 by Apple Inc.
7  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
8  *
9  *   This file contains Kerberos support code, copyright 2006 by
10  *   Jelmer Vernooij.
11  *
12  *   These coded instructions, statements, and computer programs are the
13  *   property of Apple Inc. and are protected by Federal copyright
14  *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
15  *   which should have been included with this file.  If this file is
16  *   file is missing or damaged, see the license at "http://www.cups.org/".
17  *
18  * Contents:
19  *
20  *   cupsdAcceptClient()     - Accept a new client.
21  *   cupsdCloseAllClients()  - Close all remote clients immediately.
22  *   cupsdCloseClient()      - Close a remote client.
23  *   cupsdFlushHeader()      - Flush the header fields to the client.
24  *   cupsdReadClient()       - Read data from a client.
25  *   cupsdSendCommand()      - Send output from a command via HTTP.
26  *   cupsdSendError()        - Send an error message via HTTP.
27  *   cupsdSendHeader()       - Send an HTTP request.
28  *   cupsdUpdateCGI()        - Read status messages from CGI scripts and
29  *                             programs.
30  *   cupsdWriteClient()      - Write data to a client as needed.
31  *   check_if_modified()     - Decode an "If-Modified-Since" line.
32  *   compare_clients()       - Compare two client connections.
33  *   copy_cdsa_certificate() - Copy a SSL/TLS certificate from the System
34  *                             keychain.
35  *   data_ready()            - Check whether data is available from a client.
36  *   encrypt_client()        - Enable encryption for the client...
37  *   get_file()              - Get a filename and state info.
38  *   install_conf_file()     - Install a configuration file.
39  *   is_cgi()                - Is the resource a CGI script/program?
40  *   is_path_absolute()      - Is a path absolute and free of relative elements
41  *                             (i.e. "..").
42  *   make_certificate()      - Make a self-signed SSL/TLS certificate.
43  *   pipe_command()          - Pipe the output of a command to the remote
44  *                             client.
45  *   valid_host()            - Is the Host: field valid?
46  *   write_file()            - Send a file via HTTP.
47  *   write_pipe()            - Flag that data is available on the CGI pipe.
48  */
49
50 /*
51  * Include necessary headers...
52  */
53
54 #include "cupsd.h"
55
56 #ifdef HAVE_TCPD_H
57 #  include <tcpd.h>
58 #endif /* HAVE_TCPD_H */
59
60
61 /*
62  * Local functions...
63  */
64
65 static int              check_if_modified(cupsd_client_t *con,
66                                           struct stat *filestats);
67 static int              compare_clients(cupsd_client_t *a, cupsd_client_t *b,
68                                         void *data);
69 #ifdef HAVE_CDSASSL
70 static CFArrayRef       copy_cdsa_certificate(cupsd_client_t *con);
71 #endif /* HAVE_CDSASSL */
72 static int              data_ready(cupsd_client_t *con);
73 #ifdef HAVE_SSL
74 static int              encrypt_client(cupsd_client_t *con);
75 #endif /* HAVE_SSL */
76 static char             *get_file(cupsd_client_t *con, struct stat *filestats,
77                                   char *filename, int len);
78 static http_status_t    install_conf_file(cupsd_client_t *con);
79 static int              is_cgi(cupsd_client_t *con, const char *filename,
80                                struct stat *filestats, mime_type_t *type);
81 static int              is_path_absolute(const char *path);
82 #ifdef HAVE_SSL
83 static int              make_certificate(cupsd_client_t *con);
84 #endif /* HAVE_SSL */
85 static int              pipe_command(cupsd_client_t *con, int infile, int *outfile,
86                                      char *command, char *options, int root);
87 static int              valid_host(cupsd_client_t *con);
88 static int              write_file(cupsd_client_t *con, http_status_t code,
89                                    char *filename, char *type,
90                                    struct stat *filestats);
91 static void             write_pipe(cupsd_client_t *con);
92
93
94 /*
95  * 'cupsdAcceptClient()' - Accept a new client.
96  */
97
98 void
99 cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */
100 {
101   int                   count;          /* Count of connections on a host */
102   int                   val;            /* Parameter value */
103   cupsd_client_t        *con,           /* New client pointer */
104                         *tempcon;       /* Temporary client pointer */
105   http_addrlist_t       *addrlist,      /* List of adddresses for host */
106                         *addr;          /* Current address */
107   socklen_t             addrlen;        /* Length of address */
108   char                  *hostname;      /* Hostname for address */
109   http_addr_t           temp;           /* Temporary address variable */
110   static time_t         last_dos = 0;   /* Time of last DoS attack */
111 #ifdef HAVE_TCPD_H
112   struct request_info   wrap_req;       /* TCP wrappers request information */
113 #endif /* HAVE_TCPD_H */
114
115
116   cupsdLogMessage(CUPSD_LOG_DEBUG2,
117                   "cupsdAcceptClient(lis=%p(%d)) Clients=%d",
118                   lis, lis->fd, cupsArrayCount(Clients));
119
120  /*
121   * Make sure we don't have a full set of clients already...
122   */
123
124   if (cupsArrayCount(Clients) == MaxClients)
125     return;
126
127  /*
128   * Get a pointer to the next available client...
129   */
130
131   if (!Clients)
132     Clients = cupsArrayNew(NULL, NULL);
133
134   if (!Clients)
135   {
136     cupsdLogMessage(CUPSD_LOG_ERROR,
137                     "Unable to allocate memory for clients array!");
138     cupsdPauseListening();
139     return;
140   }
141
142   if (!ActiveClients)
143     ActiveClients = cupsArrayNew((cups_array_func_t)compare_clients, NULL);
144
145   if (!ActiveClients)
146   {
147     cupsdLogMessage(CUPSD_LOG_ERROR,
148                     "Unable to allocate memory for active clients array!");
149     cupsdPauseListening();
150     return;
151   }
152
153   if ((con = calloc(1, sizeof(cupsd_client_t))) == NULL)
154   {
155     cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to allocate memory for client!");
156     cupsdPauseListening();
157     return;
158   }
159
160   con->http.activity   = time(NULL);
161   con->file            = -1;
162   con->http.hostaddr   = &(con->clientaddr);
163   con->http.wait_value = 10000;
164
165  /*
166   * Accept the client and get the remote address...
167   */
168
169   addrlen = sizeof(http_addr_t);
170
171   if ((con->http.fd = accept(lis->fd, (struct sockaddr *)con->http.hostaddr,
172                              &addrlen)) < 0)
173   {
174     if (errno == ENFILE || errno == EMFILE)
175       cupsdPauseListening();
176
177     cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to accept client connection - %s.",
178                     strerror(errno));
179     free(con);
180
181     return;
182   }
183
184  /*
185   * Save the connected port number...
186   */
187
188   _httpAddrSetPort(con->http.hostaddr, _httpAddrPort(&(lis->address)));
189
190 #ifdef AF_INET6
191  /*
192   * Convert IPv4 over IPv6 addresses (::ffff:n.n.n.n) to IPv4 forms we
193   * can more easily use...
194   */
195
196   if (lis->address.addr.sa_family == AF_INET6 &&
197       con->http.hostaddr->ipv6.sin6_addr.s6_addr32[0] == 0 &&
198       con->http.hostaddr->ipv6.sin6_addr.s6_addr32[1] == 0 &&
199       ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[2]) == 0xffff)
200     con->http.hostaddr->ipv6.sin6_addr.s6_addr32[2] = 0;
201 #endif /* AF_INET6 */
202
203  /*
204   * Check the number of clients on the same address...
205   */
206
207   for (count = 0, tempcon = (cupsd_client_t *)cupsArrayFirst(Clients);
208        tempcon;
209        tempcon = (cupsd_client_t *)cupsArrayNext(Clients))
210     if (httpAddrEqual(tempcon->http.hostaddr, con->http.hostaddr))
211     {
212       count ++;
213       if (count >= MaxClientsPerHost)
214         break;
215     }
216
217   if (count >= MaxClientsPerHost)
218   {
219     if ((time(NULL) - last_dos) >= 60)
220     {
221       last_dos = time(NULL);
222       cupsdLogMessage(CUPSD_LOG_WARN,
223                       "Possible DoS attack - more than %d clients connecting "
224                       "from %s!",
225                       MaxClientsPerHost,
226                       httpAddrString(con->http.hostaddr, con->http.hostname,
227                                      sizeof(con->http.hostname)));
228     }
229
230 #ifdef WIN32
231     closesocket(con->http.fd);
232 #else
233     close(con->http.fd);
234 #endif /* WIN32 */
235
236     free(con);
237     return;
238   }
239
240  /*
241   * Get the hostname or format the IP address as needed...
242   */
243
244   if (httpAddrLocalhost(con->http.hostaddr))
245   {
246    /*
247     * Map accesses from the loopback interface to "localhost"...
248     */
249
250     strlcpy(con->http.hostname, "localhost", sizeof(con->http.hostname));
251     hostname = con->http.hostname;
252   }
253   else
254   {
255    /*
256     * Map accesses from the same host to the server name.
257     */
258
259     if (HostNameLookups)
260       hostname = httpAddrLookup(con->http.hostaddr, con->http.hostname,
261                                 sizeof(con->http.hostname));
262     else
263     {
264       hostname = NULL;
265       httpAddrString(con->http.hostaddr, con->http.hostname,
266                      sizeof(con->http.hostname));
267     }
268   }
269
270   if (hostname == NULL && HostNameLookups == 2)
271   {
272    /*
273     * Can't have an unresolved IP address with double-lookups enabled...
274     */
275
276 #ifdef WIN32
277     closesocket(con->http.fd);
278 #else
279     close(con->http.fd);
280 #endif /* WIN32 */
281
282     cupsdLogMessage(CUPSD_LOG_WARN,
283                     "Name lookup failed - connection from %s closed!",
284                     con->http.hostname);
285
286     free(con);
287     return;
288   }
289
290   if (HostNameLookups == 2)
291   {
292    /*
293     * Do double lookups as needed...
294     */
295
296     if ((addrlist = httpAddrGetList(con->http.hostname, AF_UNSPEC, NULL))
297             != NULL)
298     {
299      /*
300       * See if the hostname maps to the same IP address...
301       */
302
303       for (addr = addrlist; addr; addr = addr->next)
304         if (httpAddrEqual(con->http.hostaddr, &(addr->addr)))
305           break;
306     }
307     else
308       addr = NULL;
309
310     httpAddrFreeList(addrlist);
311
312     if (!addr)
313     {
314      /*
315       * Can't have a hostname that doesn't resolve to the same IP address
316       * with double-lookups enabled...
317       */
318
319 #ifdef WIN32
320       closesocket(con->http.fd);
321 #else
322       close(con->http.fd);
323 #endif /* WIN32 */
324
325       cupsdLogMessage(CUPSD_LOG_WARN,
326                       "IP lookup failed - connection from %s closed!",
327                       con->http.hostname);
328       free(con);
329       return;
330     }
331   }
332
333 #ifdef HAVE_TCPD_H
334  /*
335   * See if the connection is denied by TCP wrappers...
336   */
337
338   request_init(&wrap_req, RQ_DAEMON, "cupsd", RQ_FILE, con->http.fd, NULL);
339   fromhost(&wrap_req);
340
341   if (!hosts_access(&wrap_req))
342   {
343 #ifdef WIN32
344     closesocket(con->http.fd);
345 #else
346     close(con->http.fd);
347 #endif /* WIN32 */
348
349     cupsdLogMessage(CUPSD_LOG_WARN,
350                     "Connection from %s refused by /etc/hosts.allow and "
351                     "/etc/hosts.deny rules.", con->http.hostname);
352     free(con);
353     return;
354   }
355 #endif /* HAVE_TCPD_H */
356
357 #ifdef AF_LOCAL
358   if (con->http.hostaddr->addr.sa_family == AF_LOCAL)
359     cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAcceptClient: %d from %s (Domain)",
360                     con->http.fd, con->http.hostname);
361   else
362 #endif /* AF_LOCAL */
363   cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAcceptClient: %d from %s:%d (IPv%d)",
364                   con->http.fd, con->http.hostname,
365                   _httpAddrPort(con->http.hostaddr),
366                   _httpAddrFamily(con->http.hostaddr) == AF_INET ? 4 : 6);
367
368  /*
369   * Get the local address the client connected to...
370   */
371
372   addrlen = sizeof(temp);
373   if (getsockname(con->http.fd, (struct sockaddr *)&temp, &addrlen))
374   {
375     cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to get local address - %s",
376                     strerror(errno));
377
378     strcpy(con->servername, "localhost");
379     con->serverport = LocalPort;
380   }
381 #ifdef AF_LOCAL
382   else if (_httpAddrFamily(&temp) == AF_LOCAL)
383   {
384     strcpy(con->servername, "localhost");
385     con->serverport = LocalPort;
386   }
387 #endif /* AF_LOCAL */
388   else
389   {
390     if (httpAddrLocalhost(&temp))
391       strlcpy(con->servername, "localhost", sizeof(con->servername));
392     else if (HostNameLookups)
393       httpAddrLookup(&temp, con->servername, sizeof(con->servername));
394     else
395       httpAddrString(&temp, con->servername, sizeof(con->servername));
396
397     con->serverport = _httpAddrPort(&(lis->address));
398   }
399
400   cupsArrayAdd(Clients, con);
401
402  /*
403   * Using TCP_NODELAY improves responsiveness, especially on systems with a slow
404   * loopback interface.  Since we write large buffers when sending print files
405   * and requests there shouldn't be any performance penalty for this...
406   */
407
408   val = 1;
409   setsockopt(con->http.fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
410
411  /*
412   * Close this file on all execs...
413   */
414
415   fcntl(con->http.fd, F_SETFD, fcntl(con->http.fd, F_GETFD) | FD_CLOEXEC);
416
417  /*
418   * Add the socket to the server select.
419   */
420
421   cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient, NULL, con);
422
423  /*
424   * Temporarily suspend accept()'s until we lose a client...
425   */
426
427   if (cupsArrayCount(Clients) == MaxClients)
428     cupsdPauseListening();
429
430 #ifdef HAVE_SSL
431  /*
432   * See if we are connecting on a secure port...
433   */
434
435   if (lis->encryption == HTTP_ENCRYPT_ALWAYS)
436   {
437    /*
438     * https connection; go secure...
439     */
440
441     con->http.encryption = HTTP_ENCRYPT_ALWAYS;
442
443     if (!encrypt_client(con))
444       cupsdCloseClient(con);
445   }
446   else
447     con->auto_ssl = 1;
448 #endif /* HAVE_SSL */
449 }
450
451
452 /*
453  * 'cupsdCloseAllClients()' - Close all remote clients immediately.
454  */
455
456 void
457 cupsdCloseAllClients(void)
458 {
459   cupsd_client_t        *con;           /* Current client */
460
461
462   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCloseAllClients() Clients=%d",
463                   cupsArrayCount(Clients));
464
465   for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
466        con;
467        con = (cupsd_client_t *)cupsArrayNext(Clients))
468     if (cupsdCloseClient(con))
469       cupsdCloseClient(con);
470 }
471
472
473 /*
474  * 'cupsdCloseClient()' - Close a remote client.
475  */
476
477 int                                     /* O - 1 if partial close, 0 if fully closed */
478 cupsdCloseClient(cupsd_client_t *con)   /* I - Client to close */
479 {
480   int           partial;                /* Do partial close for SSL? */
481 #ifdef HAVE_LIBSSL
482   SSL_CTX       *context;               /* Context for encryption */
483   unsigned long error;                  /* Error code */
484 #elif defined(HAVE_GNUTLS)
485   int           error;                  /* Error code */
486   gnutls_certificate_server_credentials *credentials;
487                                         /* TLS credentials */
488 #  elif defined(HAVE_CDSASSL)
489 #endif /* HAVE_LIBSSL */
490
491
492   cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdCloseClient: %d", con->http.fd);
493
494  /*
495   * Flush pending writes before closing...
496   */
497
498   httpFlushWrite(HTTP(con));
499
500   partial = 0;
501
502 #ifdef HAVE_SSL
503  /*
504   * Shutdown encryption as needed...
505   */
506
507   if (con->http.tls)
508   {
509     partial = 1;
510
511 #  ifdef HAVE_LIBSSL
512     context = SSL_get_SSL_CTX(con->http.tls);
513
514     switch (SSL_shutdown(con->http.tls))
515     {
516       case 1 :
517           cupsdLogMessage(CUPSD_LOG_DEBUG,
518                           "SSL shutdown successful!");
519           break;
520       case -1 :
521           cupsdLogMessage(CUPSD_LOG_ERROR,
522                           "Fatal error during SSL shutdown!");
523       default :
524           while ((error = ERR_get_error()) != 0)
525             cupsdLogMessage(CUPSD_LOG_ERROR, "SSL shutdown failed: %s",
526                             ERR_error_string(error, NULL));
527           break;
528     }
529
530     SSL_CTX_free(context);
531     SSL_free(con->http.tls);
532
533 #  elif defined(HAVE_GNUTLS)
534     credentials = (gnutls_certificate_server_credentials *)(con->http.tls_credentials);
535
536     error = gnutls_bye(con->http.tls, GNUTLS_SHUT_WR);
537     switch (error)
538     {
539       case GNUTLS_E_SUCCESS:
540         cupsdLogMessage(CUPSD_LOG_DEBUG,
541                         "SSL shutdown successful!");
542         break;
543       default:
544         cupsdLogMessage(CUPSD_LOG_ERROR,
545                         "SSL shutdown failed: %s", gnutls_strerror(error));
546         break;
547     }
548
549     gnutls_deinit(con->http.tls);
550     gnutls_certificate_free_credentials(*credentials);
551     free(credentials);
552
553 #  elif defined(HAVE_CDSASSL)
554     while (SSLClose(con->http.tls) == errSSLWouldBlock)
555       usleep(1000);
556
557     SSLDisposeContext(con->http.tls);
558
559     if (con->http.tls_credentials)
560       CFRelease(con->http.tls_credentials);
561
562 #  endif /* HAVE_LIBSSL */
563
564     con->http.tls = NULL;
565   }
566 #endif /* HAVE_SSL */
567
568   if (con->pipe_pid != 0)
569   {
570    /*
571     * Stop any CGI process...
572     */
573
574     cupsdEndProcess(con->pipe_pid, 1);
575     con->pipe_pid = 0;
576   }
577
578   if (con->file >= 0)
579   {
580     cupsdRemoveSelect(con->file);
581
582     close(con->file);
583     con->file = -1;
584   }
585
586  /*
587   * Close the socket and clear the file from the input set for select()...
588   */
589
590   if (con->http.fd >= 0)
591   {
592     cupsArrayRemove(ActiveClients, con);
593     cupsdSetBusyState();
594
595     if (partial)
596     {
597      /*
598       * Only do a partial close so that the encrypted client gets everything.
599       */
600
601       shutdown(con->http.fd, 0);
602       cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient, NULL, con);
603     }
604     else
605     {
606      /*
607       * Shut the socket down fully...
608       */
609
610       cupsdRemoveSelect(con->http.fd);
611       close(con->http.fd);
612       con->http.fd = -1;
613     }
614   }
615
616   if (!partial)
617   {
618    /*
619     * Free memory...
620     */
621
622     if (con->http.input_set)
623       free(con->http.input_set);
624
625     httpClearCookie(HTTP(con));
626     httpClearFields(HTTP(con));
627
628     cupsdClearString(&con->filename);
629     cupsdClearString(&con->command);
630     cupsdClearString(&con->options);
631     cupsdClearString(&con->query_string);
632
633     if (con->request)
634     {
635       ippDelete(con->request);
636       con->request = NULL;
637     }
638
639     if (con->response)
640     {
641       ippDelete(con->response);
642       con->response = NULL;
643     }
644
645     if (con->language)
646     {
647       cupsLangFree(con->language);
648       con->language = NULL;
649     }
650
651 #ifdef HAVE_AUTHORIZATION_H
652     if (con->authref)
653     {
654       AuthorizationFree(con->authref, kAuthorizationFlagDefaults);
655       con->authref = NULL;
656     }
657 #endif /* HAVE_AUTHORIZATION_H */
658
659    /*
660     * Re-enable new client connections if we are going back under the
661     * limit...
662     */
663
664     if (cupsArrayCount(Clients) == MaxClients)
665       cupsdResumeListening();
666
667    /*
668     * Compact the list of clients as necessary...
669     */
670
671     cupsArrayRemove(Clients, con);
672
673     free(con);
674   }
675
676   return (partial);
677 }
678
679
680 /*
681  * 'cupsdFlushHeader()' - Flush the header fields to the client.
682  */
683
684 int                                     /* I - Bytes written or -1 on error */
685 cupsdFlushHeader(cupsd_client_t *con)   /* I - Client to flush to */
686 {
687   int bytes = httpFlushWrite(HTTP(con));
688
689   con->http.data_encoding = HTTP_ENCODE_LENGTH;
690
691   return (bytes);
692 }
693
694
695 /*
696  * 'cupsdReadClient()' - Read data from a client.
697  */
698
699 void
700 cupsdReadClient(cupsd_client_t *con)    /* I - Client to read from */
701 {
702   char                  line[32768],    /* Line from client... */
703                         operation[64],  /* Operation code from socket */
704                         version[64],    /* HTTP version number string */
705                         locale[64],     /* Locale */
706                         *ptr;           /* Pointer into strings */
707   int                   major, minor;   /* HTTP version numbers */
708   http_status_t         status;         /* Transfer status */
709   ipp_state_t           ipp_state;      /* State of IPP transfer */
710   int                   bytes;          /* Number of bytes to POST */
711   char                  *filename;      /* Name of file for GET/HEAD */
712   char                  buf[1024];      /* Buffer for real filename */
713   struct stat           filestats;      /* File information */
714   mime_type_t           *type;          /* MIME type of file */
715   cupsd_printer_t       *p;             /* Printer */
716   static unsigned       request_id = 0; /* Request ID for temp files */
717
718
719   status = HTTP_CONTINUE;
720
721   cupsdLogMessage(CUPSD_LOG_DEBUG2,
722                   "cupsdReadClient(con=%p(%d)) "
723                   "con->http.error=%d "
724                   "con->http.used=%d, "
725                   "con->http.state=%d "
726                   "con->data_encoding=HTTP_ENCODE_%s, "
727                   "con->data_remaining=" CUPS_LLFMT ", "
728                   "con->file=%d",
729                   con, con->http.fd, con->http.error, con->http.used,
730                   con->http.state,
731                   con->http.data_encoding == HTTP_ENCODE_CHUNKED ?
732                       "CHUNKED" : "LENGTH",
733                   CUPS_LLCAST con->http.data_remaining, con->file);
734
735 #ifdef HAVE_SSL
736   if (con->auto_ssl)
737   {
738    /*
739     * Automatically check for a SSL/TLS handshake...
740     */
741
742     con->auto_ssl = 0;
743
744     if (recv(con->http.fd, buf, 1, MSG_PEEK) == 1 &&
745         (!buf[0] || !strchr("DGHOPT", buf[0])))
746     {
747      /*
748       * Encrypt this connection...
749       */
750
751       cupsdLogMessage(CUPSD_LOG_DEBUG2,
752                       "cupsdReadClient: Saw first byte %02X, auto-negotiating "
753                       "SSL/TLS session...", buf[0] & 255);
754
755       if (!encrypt_client(con))
756         cupsdCloseClient(con);
757
758       return;
759     }
760   }
761 #endif /* HAVE_SSL */
762
763   switch (con->http.state)
764   {
765     case HTTP_WAITING :
766        /*
767         * See if we've received a request line...
768         */
769
770         if (httpGets(line, sizeof(line) - 1, HTTP(con)) == NULL)
771         {
772           if (con->http.error && con->http.error != EPIPE)
773             cupsdLogMessage(CUPSD_LOG_DEBUG,
774                             "cupsdReadClient: %d WAITING Closing for error %d "
775                             "(%s)", con->http.fd, con->http.error,
776                             strerror(con->http.error));
777           else
778             cupsdLogMessage(CUPSD_LOG_DEBUG,
779                             "cupsdReadClient: %d WAITING Closing on EOF",
780                             con->http.fd);
781
782           cupsdCloseClient(con);
783           return;
784         }
785
786        /*
787         * Ignore blank request lines...
788         */
789
790         if (line[0] == '\0')
791           break;
792
793        /*
794         * Clear other state variables...
795         */
796
797         httpClearFields(HTTP(con));
798
799         con->http.activity        = time(NULL);
800         con->http.version         = HTTP_1_0;
801         con->http.keep_alive      = HTTP_KEEPALIVE_OFF;
802         con->http.data_encoding   = HTTP_ENCODE_LENGTH;
803         con->http.data_remaining  = 0;
804         con->http._data_remaining = 0;
805         con->operation            = HTTP_WAITING;
806         con->bytes                = 0;
807         con->file                 = -1;
808         con->file_ready           = 0;
809         con->pipe_pid             = 0;
810         con->username[0]          = '\0';
811         con->password[0]          = '\0';
812         con->uri[0]               = '\0';
813
814         cupsdClearString(&con->command);
815         cupsdClearString(&con->options);
816         cupsdClearString(&con->query_string);
817
818         if (con->request)
819         {
820           ippDelete(con->request);
821           con->request = NULL;
822         }
823
824         if (con->response)
825         {
826           ippDelete(con->response);
827           con->response = NULL;
828         }
829
830         if (con->language)
831         {
832           cupsLangFree(con->language);
833           con->language = NULL;
834         }
835
836 #ifdef HAVE_GSSAPI
837         con->have_gss = 0;
838         con->gss_uid  = 0;
839 #endif /* HAVE_GSSAPI */
840
841        /*
842         * Grab the request line...
843         */
844
845         switch (sscanf(line, "%63s%1023s%63s", operation, con->uri, version))
846         {
847           case 1 :
848               if (line[0])
849               {
850                 cupsdLogMessage(CUPSD_LOG_ERROR,
851                                 "Bad request line \"%s\" from %s!",
852                                 _httpEncodeURI(buf, line, sizeof(buf)),
853                                 con->http.hostname);
854                 cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE);
855                 cupsdCloseClient(con);
856               }
857               return;
858           case 2 :
859               con->http.version = HTTP_0_9;
860               break;
861           case 3 :
862               if (sscanf(version, "HTTP/%d.%d", &major, &minor) != 2)
863               {
864                 cupsdLogMessage(CUPSD_LOG_ERROR,
865                                 "Bad request line \"%s\" from %s!",
866                                 _httpEncodeURI(buf, line, sizeof(buf)),
867                                 con->http.hostname);
868                 cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE);
869                 cupsdCloseClient(con);
870                 return;
871               }
872
873               if (major < 2)
874               {
875                 con->http.version = (http_version_t)(major * 100 + minor);
876                 if (con->http.version == HTTP_1_1 && KeepAlive)
877                   con->http.keep_alive = HTTP_KEEPALIVE_ON;
878                 else
879                   con->http.keep_alive = HTTP_KEEPALIVE_OFF;
880               }
881               else
882               {
883                 cupsdLogMessage(CUPSD_LOG_ERROR,
884                                 "Unsupported request line \"%s\" from %s!",
885                                 _httpEncodeURI(buf, line, sizeof(buf)),
886                                 con->http.hostname);
887                 cupsdSendError(con, HTTP_NOT_SUPPORTED, CUPSD_AUTH_NONE);
888                 cupsdCloseClient(con);
889                 return;
890               }
891               break;
892         }
893
894        /*
895         * Handle full URLs in the request line...
896         */
897
898         if (strcmp(con->uri, "*"))
899         {
900           char  scheme[HTTP_MAX_URI],   /* Method/scheme */
901                 userpass[HTTP_MAX_URI], /* Username:password */
902                 hostname[HTTP_MAX_URI], /* Hostname */
903                 resource[HTTP_MAX_URI]; /* Resource path */
904           int   port;                   /* Port number */
905
906
907          /*
908           * Separate the URI into its components...
909           */
910
911           httpSeparateURI(HTTP_URI_CODING_MOST, con->uri,
912                           scheme, sizeof(scheme),
913                           userpass, sizeof(userpass),
914                           hostname, sizeof(hostname), &port,
915                           resource, sizeof(resource));
916
917          /*
918           * Only allow URIs with the servername, localhost, or an IP
919           * address...
920           */
921
922           if (strcmp(scheme, "file") &&
923               _cups_strcasecmp(hostname, ServerName) &&
924               _cups_strcasecmp(hostname, "localhost") &&
925               !isdigit(hostname[0]) && hostname[0] != '[')
926           {
927            /*
928             * Nope, we don't do proxies...
929             */
930
931             cupsdLogMessage(CUPSD_LOG_ERROR, "Bad URI \"%s\" in request!",
932                             con->uri);
933             cupsdSendError(con, HTTP_METHOD_NOT_ALLOWED, CUPSD_AUTH_NONE);
934             cupsdCloseClient(con);
935             return;
936           }
937
938          /*
939           * Copy the resource portion back into the URI; both resource and
940           * con->uri are HTTP_MAX_URI bytes in size...
941           */
942
943           strcpy(con->uri, resource);
944         }
945
946        /*
947         * Process the request...
948         */
949
950         if (!strcmp(operation, "GET"))
951           con->http.state = HTTP_GET;
952         else if (!strcmp(operation, "PUT"))
953           con->http.state = HTTP_PUT;
954         else if (!strcmp(operation, "POST"))
955           con->http.state = HTTP_POST;
956         else if (!strcmp(operation, "DELETE"))
957           con->http.state = HTTP_DELETE;
958         else if (!strcmp(operation, "TRACE"))
959           con->http.state = HTTP_TRACE;
960         else if (!strcmp(operation, "OPTIONS"))
961           con->http.state = HTTP_OPTIONS;
962         else if (!strcmp(operation, "HEAD"))
963           con->http.state = HTTP_HEAD;
964         else
965         {
966           cupsdLogMessage(CUPSD_LOG_ERROR, "Bad operation \"%s\"!", operation);
967           cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE);
968           cupsdCloseClient(con);
969           return;
970         }
971
972         gettimeofday(&(con->start), NULL);
973         con->operation = con->http.state;
974
975         cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdReadClient: %d %s %s HTTP/%d.%d",
976                         con->http.fd, operation, con->uri,
977                         con->http.version / 100, con->http.version % 100);
978
979         con->http.status = HTTP_OK;
980
981         if (!cupsArrayFind(ActiveClients, con))
982         {
983           cupsArrayAdd(ActiveClients, con);
984           cupsdSetBusyState();
985         }
986
987     case HTTP_OPTIONS :
988     case HTTP_DELETE :
989     case HTTP_GET :
990     case HTTP_HEAD :
991     case HTTP_POST :
992     case HTTP_PUT :
993     case HTTP_TRACE :
994        /*
995         * Parse incoming parameters until the status changes...
996         */
997
998         while ((status = httpUpdate(HTTP(con))) == HTTP_CONTINUE)
999           if (!data_ready(con))
1000             break;
1001
1002         if (status != HTTP_OK && status != HTTP_CONTINUE)
1003         {
1004           if (con->http.error && con->http.error != EPIPE)
1005             cupsdLogMessage(CUPSD_LOG_DEBUG,
1006                             "cupsdReadClient: %d FIELDS Closing for error %d "
1007                             "(%s)", con->http.fd, con->http.error,
1008                             strerror(con->http.error));
1009           else
1010             cupsdLogMessage(CUPSD_LOG_DEBUG,
1011                             "cupsdReadClient: %d FIELDS Closing on EOF",
1012                             con->http.fd);
1013
1014           cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE);
1015           cupsdCloseClient(con);
1016           return;
1017         }
1018         break;
1019
1020     default :
1021         if (!data_ready(con) && recv(con->http.fd, buf, 1, MSG_PEEK) < 1)
1022         {
1023          /*
1024           * Connection closed...
1025           */
1026
1027           cupsdLogMessage(CUPSD_LOG_DEBUG,
1028                           "cupsdReadClient: %d Closing on EOF", con->http.fd);
1029           cupsdCloseClient(con);
1030           return;
1031         }
1032         break; /* Anti-compiler-warning-code */
1033   }
1034
1035  /*
1036   * Handle new transfers...
1037   */
1038
1039   if (status == HTTP_OK)
1040   {
1041     if (con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE][0])
1042     {
1043      /*
1044       * Figure out the locale from the Accept-Language and Content-Type
1045       * fields...
1046       */
1047
1048       if ((ptr = strchr(con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE],
1049                         ',')) != NULL)
1050         *ptr = '\0';
1051
1052       if ((ptr = strchr(con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE],
1053                         ';')) != NULL)
1054         *ptr = '\0';
1055
1056       if ((ptr = strstr(con->http.fields[HTTP_FIELD_CONTENT_TYPE],
1057                         "charset=")) != NULL)
1058       {
1059        /*
1060         * Combine language and charset, and trim any extra params in the
1061         * content-type.
1062         */
1063
1064         snprintf(locale, sizeof(locale), "%s.%s",
1065                  con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE], ptr + 8);
1066
1067         if ((ptr = strchr(locale, ',')) != NULL)
1068           *ptr = '\0';
1069       }
1070       else
1071         snprintf(locale, sizeof(locale), "%s.UTF-8",
1072                  con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE]);
1073
1074       con->language = cupsLangGet(locale);
1075     }
1076     else
1077       con->language = cupsLangGet(DefaultLocale);
1078
1079     cupsdAuthorize(con);
1080
1081     if (!_cups_strncasecmp(con->http.fields[HTTP_FIELD_CONNECTION], "Keep-Alive",
1082                      10) && KeepAlive)
1083       con->http.keep_alive = HTTP_KEEPALIVE_ON;
1084     else if (!_cups_strncasecmp(con->http.fields[HTTP_FIELD_CONNECTION], "close", 5))
1085       con->http.keep_alive = HTTP_KEEPALIVE_OFF;
1086
1087     if (!con->http.fields[HTTP_FIELD_HOST][0] &&
1088         con->http.version >= HTTP_1_1)
1089     {
1090      /*
1091       * HTTP/1.1 and higher require the "Host:" field...
1092       */
1093
1094       if (!cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE))
1095       {
1096         cupsdLogMessage(CUPSD_LOG_ERROR, "Missing Host: field in request!");
1097         cupsdCloseClient(con);
1098         return;
1099       }
1100     }
1101     else if (!valid_host(con))
1102     {
1103      /*
1104       * Access to localhost must use "localhost" or the corresponding IPv4
1105       * or IPv6 values in the Host: field.
1106       */
1107
1108       cupsdLogMessage(CUPSD_LOG_ERROR,
1109                       "Request from \"%s\" using invalid Host: field \"%s\"",
1110                       con->http.hostname, con->http.fields[HTTP_FIELD_HOST]);
1111
1112       if (!cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE))
1113       {
1114         cupsdCloseClient(con);
1115         return;
1116       }
1117     }
1118     else if (con->operation == HTTP_OPTIONS)
1119     {
1120      /*
1121       * Do OPTIONS command...
1122       */
1123
1124       if (con->best && con->best->type != CUPSD_AUTH_NONE)
1125       {
1126         if (!cupsdSendHeader(con, HTTP_UNAUTHORIZED, NULL, CUPSD_AUTH_NONE))
1127         {
1128           cupsdCloseClient(con);
1129           return;
1130         }
1131       }
1132
1133       if (!_cups_strcasecmp(con->http.fields[HTTP_FIELD_CONNECTION], "Upgrade") &&
1134           con->http.tls == NULL)
1135       {
1136 #ifdef HAVE_SSL
1137        /*
1138         * Do encryption stuff...
1139         */
1140
1141         if (!cupsdSendHeader(con, HTTP_SWITCHING_PROTOCOLS, NULL, CUPSD_AUTH_NONE))
1142         {
1143           cupsdCloseClient(con);
1144           return;
1145         }
1146
1147         httpPrintf(HTTP(con), "Connection: Upgrade\r\n");
1148         httpPrintf(HTTP(con), "Upgrade: TLS/1.0,HTTP/1.1\r\n");
1149         httpPrintf(HTTP(con), "Content-Length: 0\r\n");
1150         httpPrintf(HTTP(con), "\r\n");
1151
1152         if (cupsdFlushHeader(con) < 0)
1153         {
1154           cupsdCloseClient(con);
1155           return;
1156         }
1157
1158         if (!encrypt_client(con))
1159         {
1160           cupsdCloseClient(con);
1161           return;
1162         }
1163 #else
1164         if (!cupsdSendError(con, HTTP_NOT_IMPLEMENTED, CUPSD_AUTH_NONE))
1165         {
1166           cupsdCloseClient(con);
1167           return;
1168         }
1169 #endif /* HAVE_SSL */
1170       }
1171
1172       if (!cupsdSendHeader(con, HTTP_OK, NULL, CUPSD_AUTH_NONE))
1173       {
1174         cupsdCloseClient(con);
1175         return;
1176       }
1177
1178       httpPrintf(HTTP(con), "Allow: GET, HEAD, OPTIONS, POST, PUT\r\n");
1179       httpPrintf(HTTP(con), "Content-Length: 0\r\n");
1180       httpPrintf(HTTP(con), "\r\n");
1181
1182       if (cupsdFlushHeader(con) < 0)
1183       {
1184         cupsdCloseClient(con);
1185         return;
1186       }
1187     }
1188     else if (!is_path_absolute(con->uri))
1189     {
1190      /*
1191       * Protect against malicious users!
1192       */
1193
1194       cupsdLogMessage(CUPSD_LOG_ERROR,
1195                       "Request for non-absolute resource \"%s\"!", con->uri);
1196
1197       if (!cupsdSendError(con, HTTP_FORBIDDEN, CUPSD_AUTH_NONE))
1198       {
1199         cupsdCloseClient(con);
1200         return;
1201       }
1202     }
1203     else
1204     {
1205       if (!_cups_strcasecmp(con->http.fields[HTTP_FIELD_CONNECTION], "Upgrade") &&
1206           con->http.tls == NULL)
1207       {
1208 #ifdef HAVE_SSL
1209        /*
1210         * Do encryption stuff...
1211         */
1212
1213         if (!cupsdSendHeader(con, HTTP_SWITCHING_PROTOCOLS, NULL, CUPSD_AUTH_NONE))
1214         {
1215           cupsdCloseClient(con);
1216           return;
1217         }
1218
1219         httpPrintf(HTTP(con), "Connection: Upgrade\r\n");
1220         httpPrintf(HTTP(con), "Upgrade: TLS/1.0,HTTP/1.1\r\n");
1221         httpPrintf(HTTP(con), "Content-Length: 0\r\n");
1222         httpPrintf(HTTP(con), "\r\n");
1223
1224         if (cupsdFlushHeader(con) < 0)
1225         {
1226           cupsdCloseClient(con);
1227           return;
1228         }
1229
1230         if (!encrypt_client(con))
1231         {
1232           cupsdCloseClient(con);
1233           return;
1234         }
1235 #else
1236         if (!cupsdSendError(con, HTTP_NOT_IMPLEMENTED, CUPSD_AUTH_NONE))
1237         {
1238           cupsdCloseClient(con);
1239           return;
1240         }
1241 #endif /* HAVE_SSL */
1242       }
1243
1244       if ((status = cupsdIsAuthorized(con, NULL)) != HTTP_OK)
1245       {
1246         cupsdSendError(con, status, CUPSD_AUTH_NONE);
1247         cupsdCloseClient(con);
1248         return;
1249       }
1250
1251       if (con->http.expect &&
1252           (con->operation == HTTP_POST || con->operation == HTTP_PUT))
1253       {
1254         if (con->http.expect == HTTP_CONTINUE)
1255         {
1256          /*
1257           * Send 100-continue header...
1258           */
1259
1260           if (!cupsdSendHeader(con, HTTP_CONTINUE, NULL, CUPSD_AUTH_NONE))
1261           {
1262             cupsdCloseClient(con);
1263             return;
1264           }
1265         }
1266         else
1267         {
1268          /*
1269           * Send 417-expectation-failed header...
1270           */
1271
1272           if (!cupsdSendHeader(con, HTTP_EXPECTATION_FAILED, NULL,
1273                                CUPSD_AUTH_NONE))
1274           {
1275             cupsdCloseClient(con);
1276             return;
1277           }
1278
1279           httpPrintf(HTTP(con), "Content-Length: 0\r\n");
1280           httpPrintf(HTTP(con), "\r\n");
1281
1282           if (cupsdFlushHeader(con) < 0)
1283           {
1284             cupsdCloseClient(con);
1285             return;
1286           }
1287         }
1288       }
1289
1290       switch (con->http.state)
1291       {
1292         case HTTP_GET_SEND :
1293             if (!strncmp(con->uri, "/printers/", 10) &&
1294                 !strcmp(con->uri + strlen(con->uri) - 4, ".ppd"))
1295             {
1296              /*
1297               * Send PPD file - get the real printer name since printer
1298               * names are not case sensitive but filenames can be...
1299               */
1300
1301               con->uri[strlen(con->uri) - 4] = '\0';    /* Drop ".ppd" */
1302
1303               if ((p = cupsdFindPrinter(con->uri + 10)) != NULL)
1304                 snprintf(con->uri, sizeof(con->uri), "/ppd/%s.ppd", p->name);
1305               else
1306               {
1307                 if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE))
1308                 {
1309                   cupsdCloseClient(con);
1310                   return;
1311                 }
1312
1313                 break;
1314               }
1315             }
1316             else if ((!strncmp(con->uri, "/printers/", 10) ||
1317                       !strncmp(con->uri, "/classes/", 9)) &&
1318                      !strcmp(con->uri + strlen(con->uri) - 4, ".png"))
1319             {
1320              /*
1321               * Send icon file - get the real queue name since queue names are
1322               * not case sensitive but filenames can be...
1323               */
1324
1325               con->uri[strlen(con->uri) - 4] = '\0';    /* Drop ".png" */
1326
1327               if (!strncmp(con->uri, "/printers/", 10))
1328                 p = cupsdFindPrinter(con->uri + 10);
1329               else
1330                 p = cupsdFindClass(con->uri + 9);
1331
1332               if (p)
1333                 snprintf(con->uri, sizeof(con->uri), "/icons/%s.png", p->name);
1334               else
1335               {
1336                 if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE))
1337                 {
1338                   cupsdCloseClient(con);
1339                   return;
1340                 }
1341
1342                 break;
1343               }
1344             }
1345             else if (!WebInterface)
1346             {
1347              /*
1348               * Web interface is disabled. Show an appropriate message...
1349               */
1350
1351               if (!cupsdSendError(con, HTTP_WEBIF_DISABLED, CUPSD_AUTH_NONE))
1352               {
1353                 cupsdCloseClient(con);
1354                 return;
1355               }
1356
1357               break;
1358             }
1359
1360             if ((!strncmp(con->uri, "/admin", 6) &&
1361                   strncmp(con->uri, "/admin/conf/", 12) &&
1362                   strncmp(con->uri, "/admin/log/", 11)) ||
1363                  !strncmp(con->uri, "/printers", 9) ||
1364                  !strncmp(con->uri, "/classes", 8) ||
1365                  !strncmp(con->uri, "/help", 5) ||
1366                  !strncmp(con->uri, "/jobs", 5))
1367             {
1368              /*
1369               * Send CGI output...
1370               */
1371
1372               if (!strncmp(con->uri, "/admin", 6))
1373               {
1374                 cupsdSetStringf(&con->command, "%s/cgi-bin/admin.cgi",
1375                                 ServerBin);
1376
1377                 cupsdSetString(&con->options, strchr(con->uri + 6, '?'));
1378               }
1379               else if (!strncmp(con->uri, "/printers", 9))
1380               {
1381                 cupsdSetStringf(&con->command, "%s/cgi-bin/printers.cgi",
1382                                 ServerBin);
1383
1384                 if (con->uri[9] && con->uri[10])
1385                   cupsdSetString(&con->options, con->uri + 9);
1386                 else
1387                   cupsdSetString(&con->options, NULL);
1388               }
1389               else if (!strncmp(con->uri, "/classes", 8))
1390               {
1391                 cupsdSetStringf(&con->command, "%s/cgi-bin/classes.cgi",
1392                                 ServerBin);
1393
1394                 if (con->uri[8] && con->uri[9])
1395                   cupsdSetString(&con->options, con->uri + 8);
1396                 else
1397                   cupsdSetString(&con->options, NULL);
1398               }
1399               else if (!strncmp(con->uri, "/jobs", 5))
1400               {
1401                 cupsdSetStringf(&con->command, "%s/cgi-bin/jobs.cgi",
1402                                 ServerBin);
1403
1404                 if (con->uri[5] && con->uri[6])
1405                   cupsdSetString(&con->options, con->uri + 5);
1406                 else
1407                   cupsdSetString(&con->options, NULL);
1408               }
1409               else
1410               {
1411                 cupsdSetStringf(&con->command, "%s/cgi-bin/help.cgi",
1412                                 ServerBin);
1413
1414                 if (con->uri[5] && con->uri[6])
1415                   cupsdSetString(&con->options, con->uri + 5);
1416                 else
1417                   cupsdSetString(&con->options, NULL);
1418               }
1419
1420               if (!cupsdSendCommand(con, con->command, con->options, 0))
1421               {
1422                 if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE))
1423                 {
1424                   cupsdCloseClient(con);
1425                   return;
1426                 }
1427               }
1428               else
1429                 cupsdLogRequest(con, HTTP_OK);
1430
1431               if (con->http.version <= HTTP_1_0)
1432                 con->http.keep_alive = HTTP_KEEPALIVE_OFF;
1433             }
1434             else if ((!strncmp(con->uri, "/admin/conf/", 12) &&
1435                       (strchr(con->uri + 12, '/') ||
1436                        strlen(con->uri) == 12)) ||
1437                      (!strncmp(con->uri, "/admin/log/", 11) &&
1438                       (strchr(con->uri + 11, '/') ||
1439                        strlen(con->uri) == 11)))
1440             {
1441              /*
1442               * GET can only be done to configuration files directly under
1443               * /admin/conf...
1444               */
1445
1446               cupsdLogMessage(CUPSD_LOG_ERROR,
1447                               "Request for subdirectory \"%s\"!", con->uri);
1448
1449               if (!cupsdSendError(con, HTTP_FORBIDDEN, CUPSD_AUTH_NONE))
1450               {
1451                 cupsdCloseClient(con);
1452                 return;
1453               }
1454
1455               break;
1456             }
1457             else
1458             {
1459              /*
1460               * Serve a file...
1461               */
1462
1463               if ((filename = get_file(con, &filestats, buf,
1464                                        sizeof(buf))) == NULL)
1465               {
1466                 if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE))
1467                 {
1468                   cupsdCloseClient(con);
1469                   return;
1470                 }
1471
1472                 break;
1473               }
1474
1475               type = mimeFileType(MimeDatabase, filename, NULL, NULL);
1476
1477               if (is_cgi(con, filename, &filestats, type))
1478               {
1479                /*
1480                 * Note: con->command and con->options were set by
1481                 * is_cgi()...
1482                 */
1483
1484                 if (!cupsdSendCommand(con, con->command, con->options, 0))
1485                 {
1486                   if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE))
1487                   {
1488                     cupsdCloseClient(con);
1489                     return;
1490                   }
1491                 }
1492                 else
1493                   cupsdLogRequest(con, HTTP_OK);
1494
1495                 if (con->http.version <= HTTP_1_0)
1496                   con->http.keep_alive = HTTP_KEEPALIVE_OFF;
1497                 break;
1498               }
1499
1500               if (!check_if_modified(con, &filestats))
1501               {
1502                 if (!cupsdSendError(con, HTTP_NOT_MODIFIED, CUPSD_AUTH_NONE))
1503                 {
1504                   cupsdCloseClient(con);
1505                   return;
1506                 }
1507               }
1508               else
1509               {
1510                 if (type == NULL)
1511                   strcpy(line, "text/plain");
1512                 else
1513                   snprintf(line, sizeof(line), "%s/%s", type->super, type->type);
1514
1515                 if (!write_file(con, HTTP_OK, filename, line, &filestats))
1516                 {
1517                   cupsdCloseClient(con);
1518                   return;
1519                 }
1520               }
1521             }
1522             break;
1523
1524         case HTTP_POST_RECV :
1525            /*
1526             * See if the POST request includes a Content-Length field, and if
1527             * so check the length against any limits that are set...
1528             */
1529
1530             if (con->http.fields[HTTP_FIELD_CONTENT_LENGTH][0] &&
1531                 MaxRequestSize > 0 &&
1532                 con->http.data_remaining > MaxRequestSize)
1533             {
1534              /*
1535               * Request too large...
1536               */
1537
1538               if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
1539               {
1540                 cupsdCloseClient(con);
1541                 return;
1542               }
1543
1544               break;
1545             }
1546             else if (con->http.data_remaining < 0 ||
1547                      (!con->http.fields[HTTP_FIELD_CONTENT_LENGTH][0] &&
1548                       con->http.data_encoding == HTTP_ENCODE_LENGTH))
1549             {
1550              /*
1551               * Negative content lengths are invalid!
1552               */
1553
1554               if (!cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE))
1555               {
1556                 cupsdCloseClient(con);
1557                 return;
1558               }
1559
1560               break;
1561             }
1562
1563            /*
1564             * See what kind of POST request this is; for IPP requests the
1565             * content-type field will be "application/ipp"...
1566             */
1567
1568             if (!strcmp(con->http.fields[HTTP_FIELD_CONTENT_TYPE],
1569                         "application/ipp"))
1570               con->request = ippNew();
1571             else if (!WebInterface)
1572             {
1573              /*
1574               * Web interface is disabled. Show an appropriate message...
1575               */
1576
1577               if (!cupsdSendError(con, HTTP_WEBIF_DISABLED, CUPSD_AUTH_NONE))
1578               {
1579                 cupsdCloseClient(con);
1580                 return;
1581               }
1582
1583               break;
1584             }
1585             else if ((!strncmp(con->uri, "/admin", 6) &&
1586                       strncmp(con->uri, "/admin/conf/", 12) &&
1587                       strncmp(con->uri, "/admin/log/", 11)) ||
1588                      !strncmp(con->uri, "/printers", 9) ||
1589                      !strncmp(con->uri, "/classes", 8) ||
1590                      !strncmp(con->uri, "/help", 5) ||
1591                      !strncmp(con->uri, "/jobs", 5))
1592             {
1593              /*
1594               * CGI request...
1595               */
1596
1597               if (!strncmp(con->uri, "/admin", 6))
1598               {
1599                 cupsdSetStringf(&con->command, "%s/cgi-bin/admin.cgi",
1600                                 ServerBin);
1601
1602                 cupsdSetString(&con->options, strchr(con->uri + 6, '?'));
1603               }
1604               else if (!strncmp(con->uri, "/printers", 9))
1605               {
1606                 cupsdSetStringf(&con->command, "%s/cgi-bin/printers.cgi",
1607                                 ServerBin);
1608
1609                 if (con->uri[9] && con->uri[10])
1610                   cupsdSetString(&con->options, con->uri + 9);
1611                 else
1612                   cupsdSetString(&con->options, NULL);
1613               }
1614               else if (!strncmp(con->uri, "/classes", 8))
1615               {
1616                 cupsdSetStringf(&con->command, "%s/cgi-bin/classes.cgi",
1617                                 ServerBin);
1618
1619                 if (con->uri[8] && con->uri[9])
1620                   cupsdSetString(&con->options, con->uri + 8);
1621                 else
1622                   cupsdSetString(&con->options, NULL);
1623               }
1624               else if (!strncmp(con->uri, "/jobs", 5))
1625               {
1626                 cupsdSetStringf(&con->command, "%s/cgi-bin/jobs.cgi",
1627                                 ServerBin);
1628
1629                 if (con->uri[5] && con->uri[6])
1630                   cupsdSetString(&con->options, con->uri + 5);
1631                 else
1632                   cupsdSetString(&con->options, NULL);
1633               }
1634               else
1635               {
1636                 cupsdSetStringf(&con->command, "%s/cgi-bin/help.cgi",
1637                                 ServerBin);
1638
1639                 if (con->uri[5] && con->uri[6])
1640                   cupsdSetString(&con->options, con->uri + 5);
1641                 else
1642                   cupsdSetString(&con->options, NULL);
1643               }
1644
1645               if (con->http.version <= HTTP_1_0)
1646                 con->http.keep_alive = HTTP_KEEPALIVE_OFF;
1647             }
1648             else
1649             {
1650              /*
1651               * POST to a file...
1652               */
1653
1654               if ((filename = get_file(con, &filestats, buf,
1655                                        sizeof(buf))) == NULL)
1656               {
1657                 if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE))
1658                 {
1659                   cupsdCloseClient(con);
1660                   return;
1661                 }
1662
1663                 break;
1664               }
1665
1666               type = mimeFileType(MimeDatabase, filename, NULL, NULL);
1667
1668               if (!is_cgi(con, filename, &filestats, type))
1669               {
1670                /*
1671                 * Only POST to CGI's...
1672                 */
1673
1674                 if (!cupsdSendError(con, HTTP_UNAUTHORIZED, CUPSD_AUTH_NONE))
1675                 {
1676                   cupsdCloseClient(con);
1677                   return;
1678                 }
1679               }
1680             }
1681             break;
1682
1683         case HTTP_PUT_RECV :
1684            /*
1685             * Validate the resource name...
1686             */
1687
1688             if (strncmp(con->uri, "/admin/conf/", 12) ||
1689                 strchr(con->uri + 12, '/') ||
1690                 strlen(con->uri) == 12)
1691             {
1692              /*
1693               * PUT can only be done to configuration files under
1694               * /admin/conf...
1695               */
1696
1697               cupsdLogMessage(CUPSD_LOG_ERROR,
1698                               "Request for subdirectory \"%s\"!", con->uri);
1699
1700               if (!cupsdSendError(con, HTTP_FORBIDDEN, CUPSD_AUTH_NONE))
1701               {
1702                 cupsdCloseClient(con);
1703                 return;
1704               }
1705
1706               break;
1707             }
1708
1709            /*
1710             * See if the PUT request includes a Content-Length field, and if
1711             * so check the length against any limits that are set...
1712             */
1713
1714             if (con->http.fields[HTTP_FIELD_CONTENT_LENGTH][0] &&
1715                 MaxRequestSize > 0 &&
1716                 con->http.data_remaining > MaxRequestSize)
1717             {
1718              /*
1719               * Request too large...
1720               */
1721
1722               if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
1723               {
1724                 cupsdCloseClient(con);
1725                 return;
1726               }
1727
1728               break;
1729             }
1730             else if (con->http.data_remaining < 0)
1731             {
1732              /*
1733               * Negative content lengths are invalid!
1734               */
1735
1736               if (!cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE))
1737               {
1738                 cupsdCloseClient(con);
1739                 return;
1740               }
1741
1742               break;
1743             }
1744
1745            /*
1746             * Open a temporary file to hold the request...
1747             */
1748
1749             cupsdSetStringf(&con->filename, "%s/%08x", RequestRoot,
1750                             request_id ++);
1751             con->file = open(con->filename, O_WRONLY | O_CREAT | O_TRUNC, 0640);
1752
1753             if (con->file < 0)
1754             {
1755               cupsdLogMessage(CUPSD_LOG_ERROR,
1756                               "Unable to create request file %s: %s",
1757                               con->filename, strerror(errno));
1758
1759               if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
1760               {
1761                 cupsdCloseClient(con);
1762                 return;
1763               }
1764             }
1765
1766             fchmod(con->file, 0640);
1767             fchown(con->file, RunUser, Group);
1768             fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
1769             break;
1770
1771         case HTTP_DELETE :
1772         case HTTP_TRACE :
1773             cupsdSendError(con, HTTP_NOT_IMPLEMENTED, CUPSD_AUTH_NONE);
1774             cupsdCloseClient(con);
1775             return;
1776
1777         case HTTP_HEAD :
1778             if (!strncmp(con->uri, "/printers/", 10) &&
1779                 !strcmp(con->uri + strlen(con->uri) - 4, ".ppd"))
1780             {
1781              /*
1782               * Send PPD file - get the real printer name since printer
1783               * names are not case sensitive but filenames can be...
1784               */
1785
1786               con->uri[strlen(con->uri) - 4] = '\0';    /* Drop ".ppd" */
1787
1788               if ((p = cupsdFindPrinter(con->uri + 10)) != NULL)
1789                 snprintf(con->uri, sizeof(con->uri), "/ppd/%s.ppd", p->name);
1790               else
1791               {
1792                 if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE))
1793                 {
1794                   cupsdCloseClient(con);
1795                   return;
1796                 }
1797
1798                 break;
1799               }
1800             }
1801             else if (!strncmp(con->uri, "/printers/", 10) &&
1802                      !strcmp(con->uri + strlen(con->uri) - 4, ".png"))
1803             {
1804              /*
1805               * Send PNG file - get the real printer name since printer
1806               * names are not case sensitive but filenames can be...
1807               */
1808
1809               con->uri[strlen(con->uri) - 4] = '\0';    /* Drop ".ppd" */
1810
1811               if ((p = cupsdFindPrinter(con->uri + 10)) != NULL)
1812                 snprintf(con->uri, sizeof(con->uri), "/icons/%s.png", p->name);
1813               else
1814               {
1815                 if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE))
1816                 {
1817                   cupsdCloseClient(con);
1818                   return;
1819                 }
1820
1821                 break;
1822               }
1823             }
1824             else if (!WebInterface)
1825             {
1826               if (!cupsdSendHeader(con, HTTP_OK, line, CUPSD_AUTH_NONE))
1827               {
1828                 cupsdCloseClient(con);
1829                 return;
1830               }
1831
1832               if (httpPrintf(HTTP(con), "\r\n") < 0)
1833               {
1834                 cupsdCloseClient(con);
1835                 return;
1836               }
1837
1838               if (cupsdFlushHeader(con) < 0)
1839               {
1840                 cupsdCloseClient(con);
1841                 return;
1842               }
1843
1844               con->http.state = HTTP_WAITING;
1845               break;
1846             }
1847
1848             if ((!strncmp(con->uri, "/admin", 6) &&
1849                  strncmp(con->uri, "/admin/conf/", 12) &&
1850                  strncmp(con->uri, "/admin/log/", 11)) ||
1851                 !strncmp(con->uri, "/printers", 9) ||
1852                 !strncmp(con->uri, "/classes", 8) ||
1853                 !strncmp(con->uri, "/help", 5) ||
1854                 !strncmp(con->uri, "/jobs", 5))
1855             {
1856              /*
1857               * CGI output...
1858               */
1859
1860               if (!cupsdSendHeader(con, HTTP_OK, "text/html", CUPSD_AUTH_NONE))
1861               {
1862                 cupsdCloseClient(con);
1863                 return;
1864               }
1865
1866               if (httpPrintf(HTTP(con), "\r\n") < 0)
1867               {
1868                 cupsdCloseClient(con);
1869                 return;
1870               }
1871
1872               if (cupsdFlushHeader(con) < 0)
1873               {
1874                 cupsdCloseClient(con);
1875                 return;
1876               }
1877
1878               cupsdLogRequest(con, HTTP_OK);
1879             }
1880             else if ((!strncmp(con->uri, "/admin/conf/", 12) &&
1881                       (strchr(con->uri + 12, '/') ||
1882                        strlen(con->uri) == 12)) ||
1883                      (!strncmp(con->uri, "/admin/log/", 11) &&
1884                       (strchr(con->uri + 11, '/') ||
1885                        strlen(con->uri) == 11)))
1886             {
1887              /*
1888               * HEAD can only be done to configuration files under
1889               * /admin/conf...
1890               */
1891
1892               cupsdLogMessage(CUPSD_LOG_ERROR,
1893                               "Request for subdirectory \"%s\"!", con->uri);
1894
1895               if (!cupsdSendError(con, HTTP_FORBIDDEN, CUPSD_AUTH_NONE))
1896               {
1897                 cupsdCloseClient(con);
1898                 return;
1899               }
1900
1901               break;
1902             }
1903             else if ((filename = get_file(con, &filestats, buf,
1904                                           sizeof(buf))) == NULL)
1905             {
1906               if (!cupsdSendHeader(con, HTTP_NOT_FOUND, "text/html",
1907                                    CUPSD_AUTH_NONE))
1908               {
1909                 cupsdCloseClient(con);
1910                 return;
1911               }
1912
1913               cupsdLogRequest(con, HTTP_NOT_FOUND);
1914             }
1915             else if (!check_if_modified(con, &filestats))
1916             {
1917               if (!cupsdSendError(con, HTTP_NOT_MODIFIED, CUPSD_AUTH_NONE))
1918               {
1919                 cupsdCloseClient(con);
1920                 return;
1921               }
1922
1923               cupsdLogRequest(con, HTTP_NOT_MODIFIED);
1924             }
1925             else
1926             {
1927              /*
1928               * Serve a file...
1929               */
1930
1931               type = mimeFileType(MimeDatabase, filename, NULL, NULL);
1932               if (type == NULL)
1933                 strcpy(line, "text/plain");
1934               else
1935                 snprintf(line, sizeof(line), "%s/%s", type->super, type->type);
1936
1937               if (!cupsdSendHeader(con, HTTP_OK, line, CUPSD_AUTH_NONE))
1938               {
1939                 cupsdCloseClient(con);
1940                 return;
1941               }
1942
1943               if (httpPrintf(HTTP(con), "Last-Modified: %s\r\n",
1944                              httpGetDateString(filestats.st_mtime)) < 0)
1945               {
1946                 cupsdCloseClient(con);
1947                 return;
1948               }
1949
1950               if (httpPrintf(HTTP(con), "Content-Length: %lu\r\n",
1951                              (unsigned long)filestats.st_size) < 0)
1952               {
1953                 cupsdCloseClient(con);
1954                 return;
1955               }
1956
1957               cupsdLogRequest(con, HTTP_OK);
1958             }
1959
1960             if (httpPrintf(HTTP(con), "\r\n") < 0)
1961             {
1962               cupsdCloseClient(con);
1963               return;
1964             }
1965
1966             if (cupsdFlushHeader(con) < 0)
1967             {
1968               cupsdCloseClient(con);
1969               return;
1970             }
1971
1972             con->http.state = HTTP_WAITING;
1973             break;
1974
1975         default :
1976             break; /* Anti-compiler-warning-code */
1977       }
1978     }
1979   }
1980
1981  /*
1982   * Handle any incoming data...
1983   */
1984
1985   switch (con->http.state)
1986   {
1987     case HTTP_PUT_RECV :
1988         do
1989         {
1990           if ((bytes = httpRead2(HTTP(con), line, sizeof(line))) < 0)
1991           {
1992             if (con->http.error && con->http.error != EPIPE)
1993               cupsdLogMessage(CUPSD_LOG_DEBUG,
1994                               "cupsdReadClient: %d PUT_RECV Closing for error "
1995                               "%d (%s)", con->http.fd, con->http.error,
1996                               strerror(con->http.error));
1997             else
1998               cupsdLogMessage(CUPSD_LOG_DEBUG,
1999                               "cupsdReadClient: %d PUT_RECV Closing on EOF",
2000                               con->http.fd);
2001
2002             cupsdCloseClient(con);
2003             return;
2004           }
2005           else if (bytes > 0)
2006           {
2007             con->bytes += bytes;
2008
2009             if (write(con->file, line, bytes) < bytes)
2010             {
2011               cupsdLogMessage(CUPSD_LOG_ERROR,
2012                               "cupsdReadClient: Unable to write %d bytes to %s: %s",
2013                               bytes, con->filename, strerror(errno));
2014
2015               close(con->file);
2016               con->file = -1;
2017               unlink(con->filename);
2018               cupsdClearString(&con->filename);
2019
2020               if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
2021               {
2022                 cupsdCloseClient(con);
2023                 return;
2024               }
2025             }
2026           }
2027         }
2028         while (con->http.state == HTTP_PUT_RECV && data_ready(con));
2029
2030         if (con->http.state == HTTP_WAITING)
2031         {
2032          /*
2033           * End of file, see how big it is...
2034           */
2035
2036           fstat(con->file, &filestats);
2037
2038           close(con->file);
2039           con->file = -1;
2040
2041           if (filestats.st_size > MaxRequestSize &&
2042               MaxRequestSize > 0)
2043           {
2044            /*
2045             * Request is too big; remove it and send an error...
2046             */
2047
2048             unlink(con->filename);
2049             cupsdClearString(&con->filename);
2050
2051             if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
2052             {
2053               cupsdCloseClient(con);
2054               return;
2055             }
2056           }
2057
2058          /*
2059           * Install the configuration file...
2060           */
2061
2062           status = install_conf_file(con);
2063
2064          /*
2065           * Return the status to the client...
2066           */
2067
2068           if (!cupsdSendError(con, status, CUPSD_AUTH_NONE))
2069           {
2070             cupsdCloseClient(con);
2071             return;
2072           }
2073         }
2074         break;
2075
2076     case HTTP_POST_RECV :
2077         do
2078         {
2079           if (con->request && con->file < 0)
2080           {
2081            /*
2082             * Grab any request data from the connection...
2083             */
2084
2085             if ((ipp_state = ippRead(&(con->http), con->request)) == IPP_ERROR)
2086             {
2087               cupsdLogMessage(CUPSD_LOG_ERROR,
2088                               "cupsdReadClient: %d IPP Read Error!",
2089                               con->http.fd);
2090
2091               cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE);
2092               cupsdCloseClient(con);
2093               return;
2094             }
2095             else if (ipp_state != IPP_DATA)
2096             {
2097               if (con->http.state == HTTP_POST_SEND)
2098               {
2099                 cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE);
2100                 cupsdCloseClient(con);
2101                 return;
2102               }
2103
2104               break;
2105             }
2106             else
2107             {
2108               cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdReadClient: %d %d.%d %s %d",
2109                               con->http.fd, con->request->request.op.version[0],
2110                               con->request->request.op.version[1],
2111                               ippOpString(con->request->request.op.operation_id),
2112                               con->request->request.op.request_id);
2113               con->bytes += ippLength(con->request);
2114             }
2115           }
2116
2117           if (con->file < 0 && con->http.state != HTTP_POST_SEND)
2118           {
2119            /*
2120             * Create a file as needed for the request data...
2121             */
2122
2123             cupsdSetStringf(&con->filename, "%s/%08x", RequestRoot,
2124                             request_id ++);
2125             con->file = open(con->filename, O_WRONLY | O_CREAT | O_TRUNC, 0640);
2126
2127             if (con->file < 0)
2128             {
2129               cupsdLogMessage(CUPSD_LOG_ERROR,
2130                               "Unable to create request file %s: %s",
2131                               con->filename, strerror(errno));
2132
2133               if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
2134               {
2135                 cupsdCloseClient(con);
2136                 return;
2137               }
2138             }
2139
2140             fchmod(con->file, 0640);
2141             fchown(con->file, RunUser, Group);
2142             fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
2143           }
2144
2145           if (con->http.state != HTTP_POST_SEND)
2146           {
2147             if ((bytes = httpRead2(HTTP(con), line, sizeof(line))) < 0)
2148             {
2149               if (con->http.error && con->http.error != EPIPE)
2150                 cupsdLogMessage(CUPSD_LOG_DEBUG,
2151                                 "cupsdReadClient: %d POST_SEND Closing for "
2152                                 "error %d (%s)", con->http.fd, con->http.error,
2153                                 strerror(con->http.error));
2154               else
2155                 cupsdLogMessage(CUPSD_LOG_DEBUG,
2156                                 "cupsdReadClient: %d POST_SEND Closing on EOF",
2157                                 con->http.fd);
2158
2159               cupsdCloseClient(con);
2160               return;
2161             }
2162             else if (bytes > 0)
2163             {
2164               con->bytes += bytes;
2165
2166               if (write(con->file, line, bytes) < bytes)
2167               {
2168                 cupsdLogMessage(CUPSD_LOG_ERROR,
2169                                 "cupsdReadClient: Unable to write %d bytes to "
2170                                 "%s: %s", bytes, con->filename,
2171                                 strerror(errno));
2172
2173                 close(con->file);
2174                 con->file = -1;
2175                 unlink(con->filename);
2176                 cupsdClearString(&con->filename);
2177
2178                 if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE,
2179                                     CUPSD_AUTH_NONE))
2180                 {
2181                   cupsdCloseClient(con);
2182                   return;
2183                 }
2184               }
2185             }
2186             else if (con->http.state == HTTP_POST_RECV)
2187               return;
2188             else if (con->http.state != HTTP_POST_SEND)
2189             {
2190               cupsdLogMessage(CUPSD_LOG_DEBUG,
2191                               "cupsdReadClient: %d Closing on unknown HTTP "
2192                               "state %d", con->http.fd, con->http.state);
2193               cupsdCloseClient(con);
2194               return;
2195             }
2196           }
2197         }
2198         while (con->http.state == HTTP_POST_RECV && data_ready(con));
2199
2200         if (con->http.state == HTTP_POST_SEND)
2201         {
2202           if (con->file >= 0)
2203           {
2204             fstat(con->file, &filestats);
2205
2206             close(con->file);
2207             con->file = -1;
2208
2209             if (filestats.st_size > MaxRequestSize &&
2210                 MaxRequestSize > 0)
2211             {
2212              /*
2213               * Request is too big; remove it and send an error...
2214               */
2215
2216               unlink(con->filename);
2217               cupsdClearString(&con->filename);
2218
2219               if (con->request)
2220               {
2221                /*
2222                 * Delete any IPP request data...
2223                 */
2224
2225                 ippDelete(con->request);
2226                 con->request = NULL;
2227               }
2228
2229               if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
2230               {
2231                 cupsdCloseClient(con);
2232                 return;
2233               }
2234             }
2235             else if (filestats.st_size == 0)
2236             {
2237              /*
2238               * Don't allow empty file...
2239               */
2240
2241               unlink(con->filename);
2242               cupsdClearString(&con->filename);
2243             }
2244
2245             if (con->command)
2246             {
2247               if (!cupsdSendCommand(con, con->command, con->options, 0))
2248               {
2249                 if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE))
2250                 {
2251                   cupsdCloseClient(con);
2252                   return;
2253                 }
2254               }
2255               else
2256                 cupsdLogRequest(con, HTTP_OK);
2257             }
2258           }
2259
2260           if (con->request)
2261           {
2262             cupsdProcessIPPRequest(con);
2263
2264             if (con->filename)
2265             {
2266               unlink(con->filename);
2267               cupsdClearString(&con->filename);
2268             }
2269
2270             return;
2271           }
2272         }
2273         break;
2274
2275     default :
2276         break; /* Anti-compiler-warning-code */
2277   }
2278
2279   if (con->http.state == HTTP_WAITING)
2280   {
2281     if (!con->http.keep_alive)
2282     {
2283       cupsdLogMessage(CUPSD_LOG_DEBUG,
2284                       "cupsdReadClient: %d Closing because Keep-Alive disabled",
2285                       con->http.fd);
2286       cupsdCloseClient(con);
2287     }
2288     else
2289     {
2290       cupsArrayRemove(ActiveClients, con);
2291       cupsdSetBusyState();
2292     }
2293   }
2294 }
2295
2296
2297 /*
2298  * 'cupsdSendCommand()' - Send output from a command via HTTP.
2299  */
2300
2301 int                                     /* O - 1 on success, 0 on failure */
2302 cupsdSendCommand(
2303     cupsd_client_t *con,                /* I - Client connection */
2304     char           *command,            /* I - Command to run */
2305     char           *options,            /* I - Command-line options */
2306     int            root)                /* I - Run as root? */
2307 {
2308   int   fd;                             /* Standard input file descriptor */
2309
2310
2311   if (con->filename)
2312   {
2313     fd = open(con->filename, O_RDONLY);
2314
2315     if (fd < 0)
2316     {
2317       cupsdLogMessage(CUPSD_LOG_ERROR,
2318                       "cupsdSendCommand: %d Unable to open \"%s\" for reading: %s",
2319                       con->http.fd, con->filename ? con->filename : "/dev/null",
2320                       strerror(errno));
2321       return (0);
2322     }
2323
2324     fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
2325   }
2326   else
2327     fd = -1;
2328
2329   con->pipe_pid = pipe_command(con, fd, &(con->file), command, options, root);
2330
2331   if (fd >= 0)
2332     close(fd);
2333
2334   cupsdLogMessage(CUPSD_LOG_INFO, "Started \"%s\" (pid=%d)", command,
2335                   con->pipe_pid);
2336
2337   cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdSendCommand: %d file=%d",
2338                   con->http.fd, con->file);
2339
2340   if (con->pipe_pid == 0)
2341     return (0);
2342
2343   fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
2344
2345   cupsdAddSelect(con->file, (cupsd_selfunc_t)write_pipe, NULL, con);
2346
2347   con->sent_header = 0;
2348   con->file_ready  = 0;
2349   con->got_fields  = 0;
2350   con->header_used = 0;
2351
2352   return (1);
2353 }
2354
2355
2356 /*
2357  * 'cupsdSendError()' - Send an error message via HTTP.
2358  */
2359
2360 int                                     /* O - 1 if successful, 0 otherwise */
2361 cupsdSendError(cupsd_client_t *con,     /* I - Connection */
2362                http_status_t  code,     /* I - Error code */
2363                int            auth_type)/* I - Authentication type */
2364 {
2365   cupsdLogMessage(CUPSD_LOG_DEBUG2,
2366                   "cupsdSendError(con=%p(%d), code=%d, auth_type=%d", con,
2367                   con->http.fd, code, auth_type);
2368
2369 #ifdef HAVE_SSL
2370  /*
2371   * Force client to upgrade for authentication if that is how the
2372   * server is configured...
2373   */
2374
2375   if (code == HTTP_UNAUTHORIZED &&
2376       DefaultEncryption == HTTP_ENCRYPT_REQUIRED &&
2377       _cups_strcasecmp(con->http.hostname, "localhost") &&
2378       !con->http.tls)
2379   {
2380     code = HTTP_UPGRADE_REQUIRED;
2381   }
2382 #endif /* HAVE_SSL */
2383
2384  /*
2385   * Put the request in the access_log file...
2386   */
2387
2388   cupsdLogRequest(con, code);
2389
2390  /*
2391   * To work around bugs in some proxies, don't use Keep-Alive for some
2392   * error messages...
2393   *
2394   * Kerberos authentication doesn't work without Keep-Alive, so
2395   * never disable it in that case.
2396   */
2397
2398   if (code >= HTTP_BAD_REQUEST && con->http.auth_type != CUPSD_AUTH_NEGOTIATE)
2399     con->http.keep_alive = HTTP_KEEPALIVE_OFF;
2400
2401  /*
2402   * Send an error message back to the client.  If the error code is a
2403   * 400 or 500 series, make sure the message contains some text, too!
2404   */
2405
2406   if (!cupsdSendHeader(con, code, NULL, auth_type))
2407     return (0);
2408
2409 #ifdef HAVE_SSL
2410   if (code == HTTP_UPGRADE_REQUIRED)
2411     if (httpPrintf(HTTP(con), "Connection: Upgrade\r\n") < 0)
2412       return (0);
2413
2414   if (httpPrintf(HTTP(con), "Upgrade: TLS/1.0,HTTP/1.1\r\n") < 0)
2415     return (0);
2416 #endif /* HAVE_SSL */
2417
2418   if (con->http.version >= HTTP_1_1 &&
2419       con->http.keep_alive == HTTP_KEEPALIVE_OFF)
2420   {
2421     if (httpPrintf(HTTP(con), "Connection: close\r\n") < 0)
2422       return (0);
2423   }
2424
2425   if (code >= HTTP_BAD_REQUEST)
2426   {
2427    /*
2428     * Send a human-readable error message.
2429     */
2430
2431     char        message[4096],          /* Message for user */
2432                 urltext[1024],          /* URL redirection text */
2433                 redirect[1024];         /* Redirection link */
2434     const char  *text;                  /* Status-specific text */
2435
2436
2437     redirect[0] = '\0';
2438
2439     if (code == HTTP_UNAUTHORIZED)
2440       text = _cupsLangString(con->language,
2441                              _("Enter your username and password or the "
2442                                "root username and password to access this "
2443                                "page. If you are using Kerberos authentication, "
2444                                "make sure you have a valid Kerberos ticket."));
2445     else if (code == HTTP_UPGRADE_REQUIRED)
2446     {
2447       text = urltext;
2448
2449       snprintf(urltext, sizeof(urltext),
2450                _cupsLangString(con->language,
2451                                _("You must access this page using the URL "
2452                                  "<A HREF=\"https://%s:%d%s\">"
2453                                  "https://%s:%d%s</A>.")),
2454                con->servername, con->serverport, con->uri,
2455                con->servername, con->serverport, con->uri);
2456
2457       snprintf(redirect, sizeof(redirect),
2458                "<META HTTP-EQUIV=\"Refresh\" "
2459                "CONTENT=\"3;URL=https://%s:%d%s\">\n",
2460                con->servername, con->serverport, con->uri);
2461     }
2462     else if (code == HTTP_WEBIF_DISABLED)
2463       text = _cupsLangString(con->language,
2464                              _("The web interface is currently disabled. Run "
2465                                "\"cupsctl WebInterface=yes\" to enable it."));
2466     else
2467       text = "";
2468
2469     snprintf(message, sizeof(message),
2470              "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" "
2471              "\"http://www.w3.org/TR/html4/loose.dtd\">\n"
2472              "<HTML>\n"
2473              "<HEAD>\n"
2474              "\t<META HTTP-EQUIV=\"Content-Type\" "
2475              "CONTENT=\"text/html; charset=utf-8\">\n"
2476              "\t<TITLE>%s - " CUPS_SVERSION "</TITLE>\n"
2477              "\t<LINK REL=\"STYLESHEET\" TYPE=\"text/css\" "
2478              "HREF=\"/cups.css\">\n"
2479              "%s"
2480              "</HEAD>\n"
2481              "<BODY>\n"
2482              "<H1>%s</H1>\n"
2483              "<P>%s</P>\n"
2484              "</BODY>\n"
2485              "</HTML>\n",
2486              httpStatus(code), redirect, httpStatus(code), text);
2487
2488     if (httpPrintf(HTTP(con), "Content-Type: text/html; charset=utf-8\r\n") < 0)
2489       return (0);
2490     if (httpPrintf(HTTP(con), "Content-Length: %d\r\n",
2491                    (int)strlen(message)) < 0)
2492       return (0);
2493     if (httpPrintf(HTTP(con), "\r\n") < 0)
2494       return (0);
2495     if (httpPrintf(HTTP(con), "%s", message) < 0)
2496       return (0);
2497   }
2498   else if (httpPrintf(HTTP(con), "\r\n") < 0)
2499     return (0);
2500
2501   if (cupsdFlushHeader(con) < 0)
2502     return (0);
2503
2504   con->http.state = HTTP_WAITING;
2505
2506   return (1);
2507 }
2508
2509
2510 /*
2511  * 'cupsdSendHeader()' - Send an HTTP request.
2512  */
2513
2514 int                                     /* O - 1 on success, 0 on failure */
2515 cupsdSendHeader(
2516     cupsd_client_t *con,                /* I - Client to send to */
2517     http_status_t  code,                /* I - HTTP status code */
2518     char           *type,               /* I - MIME type of document */
2519     int            auth_type)           /* I - Type of authentication */
2520 {
2521   char          auth_str[1024];         /* Authorization string */
2522 #if 0 /* def HAVE_GSSAPI */
2523   static char   *gss_buf = NULL;        /* Kerberos auth data buffer */
2524   static int    gss_bufsize = 0;        /* Size of Kerberos auth data buffer */
2525 #endif /* HAVE_GSSAPI */
2526
2527
2528  /*
2529   * Send the HTTP status header...
2530   */
2531
2532   if (code == HTTP_CONTINUE)
2533   {
2534    /*
2535     * 100-continue doesn't send any headers...
2536     */
2537
2538     return (httpPrintf(HTTP(con), "HTTP/%d.%d 100 Continue\r\n\r\n",
2539                        con->http.version / 100, con->http.version % 100) > 0);
2540   }
2541   else if (code == HTTP_WEBIF_DISABLED)
2542   {
2543    /*
2544     * Treat our special "web interface is disabled" status as "200 OK" for web
2545     * browsers.
2546     */
2547
2548     code = HTTP_OK;
2549   }
2550
2551   httpFlushWrite(HTTP(con));
2552
2553   con->http.data_encoding = HTTP_ENCODE_FIELDS;
2554
2555   if (httpPrintf(HTTP(con), "HTTP/%d.%d %d %s\r\n", con->http.version / 100,
2556                  con->http.version % 100, code, httpStatus(code)) < 0)
2557     return (0);
2558   if (httpPrintf(HTTP(con), "Date: %s\r\n", httpGetDateString(time(NULL))) < 0)
2559     return (0);
2560   if (ServerHeader)
2561     if (httpPrintf(HTTP(con), "Server: %s\r\n", ServerHeader) < 0)
2562       return (0);
2563   if (con->http.keep_alive && con->http.version >= HTTP_1_0)
2564   {
2565     if (httpPrintf(HTTP(con), "Connection: Keep-Alive\r\n") < 0)
2566       return (0);
2567     if (httpPrintf(HTTP(con), "Keep-Alive: timeout=%d\r\n",
2568                    KeepAliveTimeout) < 0)
2569       return (0);
2570   }
2571   if (code == HTTP_METHOD_NOT_ALLOWED)
2572     if (httpPrintf(HTTP(con), "Allow: GET, HEAD, OPTIONS, POST, PUT\r\n") < 0)
2573       return (0);
2574
2575   if (code == HTTP_UNAUTHORIZED)
2576   {
2577     if (auth_type == CUPSD_AUTH_NONE)
2578     {
2579       if (!con->best || con->best->type <= CUPSD_AUTH_NONE)
2580         auth_type = DefaultAuthType;
2581       else
2582         auth_type = con->best->type;
2583     }
2584
2585     auth_str[0] = '\0';
2586
2587     if (auth_type == CUPSD_AUTH_BASIC || auth_type == CUPSD_AUTH_BASICDIGEST)
2588       strlcpy(auth_str, "Basic realm=\"CUPS\"", sizeof(auth_str));
2589     else if (auth_type == CUPSD_AUTH_DIGEST)
2590       snprintf(auth_str, sizeof(auth_str), "Digest realm=\"CUPS\", nonce=\"%s\"",
2591                con->http.hostname);
2592 #ifdef HAVE_GSSAPI
2593     else if (auth_type == CUPSD_AUTH_NEGOTIATE)
2594     {
2595 #  ifdef AF_LOCAL
2596       if (_httpAddrFamily(con->http.hostaddr) == AF_LOCAL)
2597         strlcpy(auth_str, "Basic realm=\"CUPS\"", sizeof(auth_str));
2598       else
2599 #  endif /* AF_LOCAL */
2600       strlcpy(auth_str, "Negotiate", sizeof(auth_str));
2601     }
2602 #endif /* HAVE_GSSAPI */
2603
2604     if (con->best && auth_type != CUPSD_AUTH_NEGOTIATE &&
2605         !_cups_strcasecmp(con->http.hostname, "localhost"))
2606     {
2607      /*
2608       * Add a "trc" (try root certification) parameter for local non-Kerberos
2609       * requests when the request requires system group membership - then the
2610       * client knows the root certificate can/should be used.
2611       *
2612       * Also, for Mac OS X we also look for @AUTHKEY and add an "authkey"
2613       * parameter as needed...
2614       */
2615
2616       char      *name,                  /* Current user name */
2617                 *auth_key;              /* Auth key buffer */
2618       size_t    auth_size;              /* Size of remaining buffer */
2619
2620       auth_key  = auth_str + strlen(auth_str);
2621       auth_size = sizeof(auth_str) - (auth_key - auth_str);
2622
2623       for (name = (char *)cupsArrayFirst(con->best->names);
2624            name;
2625            name = (char *)cupsArrayNext(con->best->names))
2626       {
2627 #ifdef HAVE_AUTHORIZATION_H
2628         if (!_cups_strncasecmp(name, "@AUTHKEY(", 9))
2629         {
2630           snprintf(auth_key, auth_size, ", authkey=\"%s\"", name + 9);
2631           /* end parenthesis is stripped in conf.c */
2632           break;
2633         }
2634         else
2635 #endif /* HAVE_AUTHORIZATION_H */
2636         if (!_cups_strcasecmp(name, "@SYSTEM"))
2637         {
2638 #ifdef HAVE_AUTHORIZATION_H
2639           if (SystemGroupAuthKey)
2640             snprintf(auth_key, auth_size,
2641                      ", authkey=\"%s\"",
2642                      SystemGroupAuthKey);
2643           else
2644 #else
2645           strlcpy(auth_key, ", trc=\"y\"", auth_size);
2646 #endif /* HAVE_AUTHORIZATION_H */
2647           break;
2648         }
2649       }
2650     }
2651
2652     if (auth_str[0])
2653     {
2654       cupsdLogMessage(CUPSD_LOG_DEBUG,
2655                       "cupsdSendHeader: %d WWW-Authenticate: %s", con->http.fd,
2656                       auth_str);
2657
2658       if (httpPrintf(HTTP(con), "WWW-Authenticate: %s\r\n", auth_str) < 0)
2659         return (0);
2660     }
2661   }
2662
2663   if (con->language && strcmp(con->language->language, "C"))
2664   {
2665     if (httpPrintf(HTTP(con), "Content-Language: %s\r\n",
2666                    con->language->language) < 0)
2667       return (0);
2668   }
2669
2670   if (type)
2671   {
2672     if (!strcmp(type, "text/html"))
2673     {
2674       if (httpPrintf(HTTP(con),
2675                      "Content-Type: text/html; charset=utf-8\r\n") < 0)
2676         return (0);
2677     }
2678     else if (httpPrintf(HTTP(con), "Content-Type: %s\r\n", type) < 0)
2679       return (0);
2680   }
2681
2682   return (1);
2683 }
2684
2685
2686 /*
2687  * 'cupsdUpdateCGI()' - Read status messages from CGI scripts and programs.
2688  */
2689
2690 void
2691 cupsdUpdateCGI(void)
2692 {
2693   char          *ptr,                   /* Pointer to end of line in buffer */
2694                 message[1024];          /* Pointer to message text */
2695   int           loglevel;               /* Log level for message */
2696
2697
2698   while ((ptr = cupsdStatBufUpdate(CGIStatusBuffer, &loglevel,
2699                                    message, sizeof(message))) != NULL)
2700   {
2701     if (loglevel == CUPSD_LOG_INFO)
2702       cupsdLogMessage(CUPSD_LOG_INFO, "%s", message);
2703
2704     if (!strchr(CGIStatusBuffer->buffer, '\n'))
2705       break;
2706   }
2707
2708   if (ptr == NULL && !CGIStatusBuffer->bufused)
2709   {
2710    /*
2711     * Fatal error on pipe - should never happen!
2712     */
2713
2714     cupsdLogMessage(CUPSD_LOG_CRIT,
2715                     "cupsdUpdateCGI: error reading from CGI error pipe - %s",
2716                     strerror(errno));
2717   }
2718 }
2719
2720
2721 /*
2722  * 'cupsdWriteClient()' - Write data to a client as needed.
2723  */
2724
2725 void
2726 cupsdWriteClient(cupsd_client_t *con)   /* I - Client connection */
2727 {
2728   int           bytes,                  /* Number of bytes written */
2729                 field_col;              /* Current column */
2730   char          *bufptr,                /* Pointer into buffer */
2731                 *bufend;                /* Pointer to end of buffer */
2732   ipp_state_t   ipp_state;              /* IPP state value */
2733
2734
2735   cupsdLogMessage(CUPSD_LOG_DEBUG2,
2736                   "cupsdWriteClient(con=%p(%d)) response=%p(%d), file=%d "
2737                   "pipe_pid=%d state=%d",
2738                   con, con->http.fd, con->response,
2739                   con->response ? con->response->state : -1,
2740                   con->file, con->pipe_pid, con->http.state);
2741
2742   if (con->http.state != HTTP_GET_SEND &&
2743       con->http.state != HTTP_POST_SEND)
2744   {
2745    /*
2746     * If we get called in the wrong state, then something went wrong with the
2747     * connection and we need to shut it down...
2748     */
2749
2750     cupsdLogMessage(CUPSD_LOG_DEBUG,
2751                     "cupsdWriteClient: %d Closing on unknown HTTP state %d",
2752                     con->http.fd, con->http.state);
2753     cupsdCloseClient(con);
2754     return;
2755   }
2756
2757   if (con->pipe_pid)
2758   {
2759    /*
2760     * Make sure we select on the CGI output...
2761     */
2762
2763     cupsdAddSelect(con->file, (cupsd_selfunc_t)write_pipe, NULL, con);
2764
2765     if (!con->file_ready)
2766     {
2767      /*
2768       * Try again later when there is CGI output available...
2769       */
2770
2771       cupsdRemoveSelect(con->http.fd);
2772       return;
2773     }
2774
2775     con->file_ready = 0;
2776   }
2777
2778   if (con->response && con->response->state != IPP_DATA)
2779   {
2780     ipp_state = ippWrite(HTTP(con), con->response);
2781     bytes     = ipp_state != IPP_ERROR &&
2782                 (con->file >= 0 || ipp_state != IPP_DATA);
2783   }
2784   else if ((bytes = read(con->file, con->header + con->header_used,
2785                          sizeof(con->header) - con->header_used)) > 0)
2786   {
2787     con->header_used += bytes;
2788
2789     if (con->pipe_pid && !con->got_fields)
2790     {
2791      /*
2792       * Inspect the data for Content-Type and other fields.
2793       */
2794
2795       for (bufptr = con->header, bufend = con->header + con->header_used,
2796                field_col = 0;
2797            !con->got_fields && bufptr < bufend;
2798            bufptr ++)
2799       {
2800         if (*bufptr == '\n')
2801         {
2802          /*
2803           * Send line to client...
2804           */
2805
2806           if (bufptr > con->header && bufptr[-1] == '\r')
2807             bufptr[-1] = '\0';
2808           *bufptr++ = '\0';
2809
2810           cupsdLogMessage(CUPSD_LOG_DEBUG, "Script header: %s", con->header);
2811
2812           if (!con->sent_header)
2813           {
2814            /*
2815             * Handle redirection and CGI status codes...
2816             */
2817
2818             if (!_cups_strncasecmp(con->header, "Location:", 9))
2819             {
2820               if (!cupsdSendHeader(con, HTTP_SEE_OTHER, NULL, CUPSD_AUTH_NONE))
2821               {
2822                 cupsdCloseClient(con);
2823                 return;
2824               }
2825
2826               con->sent_header = 2;
2827
2828               if (httpPrintf(HTTP(con), "Content-Length: 0\r\n") < 0)
2829                 return;
2830             }
2831             else if (!_cups_strncasecmp(con->header, "Status:", 7))
2832             {
2833               cupsdSendError(con, (http_status_t)atoi(con->header + 7),
2834                              CUPSD_AUTH_NONE);
2835               con->sent_header = 2;
2836             }
2837             else
2838             {
2839               if (!cupsdSendHeader(con, HTTP_OK, NULL, CUPSD_AUTH_NONE))
2840               {
2841                 cupsdCloseClient(con);
2842                 return;
2843               }
2844
2845               con->sent_header = 1;
2846
2847               if (con->http.version == HTTP_1_1)
2848               {
2849                 if (httpPrintf(HTTP(con), "Transfer-Encoding: chunked\r\n") < 0)
2850                   return;
2851               }
2852             }
2853           }
2854
2855           if (_cups_strncasecmp(con->header, "Status:", 7))
2856             httpPrintf(HTTP(con), "%s\r\n", con->header);
2857
2858          /*
2859           * Update buffer...
2860           */
2861
2862           con->header_used -= bufptr - con->header;
2863
2864           if (con->header_used > 0)
2865             memmove(con->header, bufptr, con->header_used);
2866
2867           bufptr = con->header - 1;
2868
2869          /*
2870           * See if the line was empty...
2871           */
2872
2873           if (field_col == 0)
2874           {
2875             con->got_fields = 1;
2876
2877             if (cupsdFlushHeader(con) < 0)
2878             {
2879               cupsdCloseClient(con);
2880               return;
2881             }
2882
2883             if (con->http.version == HTTP_1_1)
2884               con->http.data_encoding = HTTP_ENCODE_CHUNKED;
2885           }
2886           else
2887             field_col = 0;
2888         }
2889         else if (*bufptr != '\r')
2890           field_col ++;
2891       }
2892
2893       if (!con->got_fields)
2894       {
2895         con->http.activity = time(NULL);
2896         return;
2897       }
2898     }
2899
2900     if (con->header_used > 0)
2901     {
2902       if (httpWrite2(HTTP(con), con->header, con->header_used) < 0)
2903       {
2904         cupsdLogMessage(CUPSD_LOG_DEBUG,
2905                         "cupsdWriteClient: %d Closing for error %d (%s)",
2906                         con->http.fd, con->http.error,
2907                         strerror(con->http.error));
2908         cupsdCloseClient(con);
2909         return;
2910       }
2911
2912       if (con->http.data_encoding == HTTP_ENCODE_CHUNKED)
2913         httpFlushWrite(HTTP(con));
2914
2915       con->bytes += con->header_used;
2916
2917       if (con->http.state == HTTP_WAITING)
2918         bytes = 0;
2919       else
2920         bytes = con->header_used;
2921
2922       con->header_used = 0;
2923     }
2924   }
2925
2926   if (bytes <= 0 ||
2927       (con->http.state != HTTP_GET_SEND && con->http.state != HTTP_POST_SEND))
2928   {
2929     if (!con->sent_header && con->pipe_pid)
2930       cupsdSendError(con, HTTP_SERVER_ERROR, CUPSD_AUTH_NONE);
2931     else
2932     {
2933       cupsdLogRequest(con, HTTP_OK);
2934
2935       httpFlushWrite(HTTP(con));
2936
2937       if (con->http.data_encoding == HTTP_ENCODE_CHUNKED && con->sent_header == 1)
2938       {
2939         if (httpWrite2(HTTP(con), "", 0) < 0)
2940         {
2941           cupsdLogMessage(CUPSD_LOG_DEBUG,
2942                           "cupsdWriteClient: %d Closing for error %d (%s)",
2943                           con->http.fd, con->http.error,
2944                           strerror(con->http.error));
2945           cupsdCloseClient(con);
2946           return;
2947         }
2948       }
2949     }
2950
2951     con->http.state = HTTP_WAITING;
2952
2953     cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient, NULL, con);
2954
2955     if (con->file >= 0)
2956     {
2957       cupsdRemoveSelect(con->file);
2958
2959       if (con->pipe_pid)
2960         cupsdEndProcess(con->pipe_pid, 0);
2961
2962       close(con->file);
2963       con->file     = -1;
2964       con->pipe_pid = 0;
2965     }
2966
2967     if (con->filename)
2968     {
2969       unlink(con->filename);
2970       cupsdClearString(&con->filename);
2971     }
2972
2973     if (con->request)
2974     {
2975       ippDelete(con->request);
2976       con->request = NULL;
2977     }
2978
2979     if (con->response)
2980     {
2981       ippDelete(con->response);
2982       con->response = NULL;
2983     }
2984
2985     cupsdClearString(&con->command);
2986     cupsdClearString(&con->options);
2987     cupsdClearString(&con->query_string);
2988
2989     if (!con->http.keep_alive)
2990     {
2991       cupsdLogMessage(CUPSD_LOG_DEBUG,
2992                       "cupsdWriteClient: %d Closing because Keep-Alive disabled",
2993                       con->http.fd);
2994       cupsdCloseClient(con);
2995       return;
2996     }
2997     else
2998     {
2999       cupsArrayRemove(ActiveClients, con);
3000       cupsdSetBusyState();
3001     }
3002   }
3003
3004   con->http.activity = time(NULL);
3005 }
3006
3007
3008 /*
3009  * 'check_if_modified()' - Decode an "If-Modified-Since" line.
3010  */
3011
3012 static int                              /* O - 1 if modified since */
3013 check_if_modified(
3014     cupsd_client_t *con,                /* I - Client connection */
3015     struct stat    *filestats)          /* I - File information */
3016 {
3017   char          *ptr;                   /* Pointer into field */
3018   time_t        date;                   /* Time/date value */
3019   off_t         size;                   /* Size/length value */
3020
3021
3022   size = 0;
3023   date = 0;
3024   ptr  = con->http.fields[HTTP_FIELD_IF_MODIFIED_SINCE];
3025
3026   if (*ptr == '\0')
3027     return (1);
3028
3029   cupsdLogMessage(CUPSD_LOG_DEBUG2,
3030                   "check_if_modified(con=%p(%d), "
3031                   "filestats=%p(" CUPS_LLFMT ", %d)) If-Modified-Since=\"%s\"",
3032                   con, con->http.fd, filestats, CUPS_LLCAST filestats->st_size,
3033                   (int)filestats->st_mtime, ptr);
3034
3035   while (*ptr != '\0')
3036   {
3037     while (isspace(*ptr) || *ptr == ';')
3038       ptr ++;
3039
3040     if (_cups_strncasecmp(ptr, "length=", 7) == 0)
3041     {
3042       ptr += 7;
3043       size = strtoll(ptr, NULL, 10);
3044
3045       while (isdigit(*ptr))
3046         ptr ++;
3047     }
3048     else if (isalpha(*ptr))
3049     {
3050       date = httpGetDateTime(ptr);
3051       while (*ptr != '\0' && *ptr != ';')
3052         ptr ++;
3053     }
3054     else
3055       ptr ++;
3056   }
3057
3058   return ((size != filestats->st_size && size != 0) ||
3059           (date < filestats->st_mtime && date != 0) ||
3060           (size == 0 && date == 0));
3061 }
3062
3063
3064 /*
3065  * 'compare_clients()' - Compare two client connections.
3066  */
3067
3068 static int                              /* O - Result of comparison */
3069 compare_clients(cupsd_client_t *a,      /* I - First client */
3070                 cupsd_client_t *b,      /* I - Second client */
3071                 void           *data)   /* I - User data (not used) */
3072 {
3073   (void)data;
3074
3075   if (a == b)
3076     return (0);
3077   else if (a < b)
3078     return (-1);
3079   else
3080     return (1);
3081 }
3082
3083
3084 #ifdef HAVE_CDSASSL
3085 /*
3086  * 'copy_cdsa_certificate()' - Copy a SSL/TLS certificate from the System
3087  *                             keychain.
3088  */
3089
3090 static CFArrayRef                               /* O - Array of certificates */
3091 copy_cdsa_certificate(
3092     cupsd_client_t *con)                        /* I - Client connection */
3093 {
3094   OSStatus              err;            /* Error info */
3095   SecKeychainRef        keychain = NULL;/* Keychain reference */
3096   SecIdentitySearchRef  search = NULL;  /* Search reference */
3097   SecIdentityRef        identity = NULL;/* Identity */
3098   CFArrayRef            certificates = NULL;
3099                                         /* Certificate array */
3100 #  if HAVE_SECPOLICYCREATESSL
3101   SecPolicyRef          policy = NULL;  /* Policy ref */
3102   CFStringRef           servername = NULL;
3103                                         /* Server name */
3104   CFMutableDictionaryRef query = NULL;  /* Query qualifiers */
3105   char                  localname[1024];/* Local hostname */
3106 #  elif defined(HAVE_SECIDENTITYSEARCHCREATEWITHPOLICY)
3107   SecPolicyRef          policy = NULL;  /* Policy ref */
3108   SecPolicySearchRef    policy_search = NULL;
3109                                         /* Policy search ref */
3110   CSSM_DATA             options;        /* Policy options */
3111   CSSM_APPLE_TP_SSL_OPTIONS
3112                         ssl_options;    /* SSL Option for hostname */
3113   char                  localname[1024];/* Local hostname */
3114 #  endif /* HAVE_SECPOLICYCREATESSL */
3115
3116
3117   cupsdLogMessage(CUPSD_LOG_DEBUG,
3118                   "copy_cdsa_certificate: Looking for certs for \"%s\"...",
3119                   con->servername);
3120
3121   if ((err = SecKeychainOpen(ServerCertificate, &keychain)))
3122   {
3123     cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot open keychain \"%s\" - %s (%d)",
3124                     ServerCertificate, cssmErrorString(err), (int)err);
3125     goto cleanup;
3126   }
3127
3128 #  if HAVE_SECPOLICYCREATESSL
3129   servername = CFStringCreateWithCString(kCFAllocatorDefault, con->servername,
3130                                          kCFStringEncodingUTF8);
3131
3132   policy = SecPolicyCreateSSL(1, servername);
3133
3134   if (servername)
3135     CFRelease(servername);
3136
3137   if (!policy)
3138   {
3139     cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create ssl policy reference");
3140     goto cleanup;
3141   }
3142
3143   if (!(query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
3144                                           &kCFTypeDictionaryKeyCallBacks,
3145                                           &kCFTypeDictionaryValueCallBacks)))
3146   {
3147     cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create query dictionary");
3148     goto cleanup;
3149   }
3150
3151   CFDictionaryAddValue(query, kSecClass, kSecClassIdentity);
3152   CFDictionaryAddValue(query, kSecMatchPolicy, policy);
3153   CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue);
3154   CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitOne);
3155
3156   err = SecItemCopyMatching(query, (CFTypeRef *)&identity);
3157
3158   if (err && DNSSDHostName)
3159   {
3160    /*
3161     * Search for the connection server name failed; try the DNS-SD .local
3162     * hostname instead...
3163     */
3164
3165     snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName);
3166
3167     cupsdLogMessage(CUPSD_LOG_DEBUG,
3168                     "copy_cdsa_certificate: Looking for certs for \"%s\"...",
3169                     localname);
3170
3171     servername = CFStringCreateWithCString(kCFAllocatorDefault, localname,
3172                                            kCFStringEncodingUTF8);
3173
3174     CFRelease(policy);
3175
3176     policy = SecPolicyCreateSSL(1, servername);
3177
3178     if (servername)
3179       CFRelease(servername);
3180
3181     if (!policy)
3182     {
3183       cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create ssl policy reference");
3184       goto cleanup;
3185     }
3186
3187     CFDictionarySetValue(query, kSecMatchPolicy, policy);
3188
3189     err = SecItemCopyMatching(query, (CFTypeRef *)&identity);
3190   }
3191
3192   if (err)
3193   {
3194     cupsdLogMessage(CUPSD_LOG_DEBUG,
3195                     "Cannot find signing key in keychain \"%s\": %s (%d)",
3196                     ServerCertificate, cssmErrorString(err), (int)err);
3197     goto cleanup;
3198   }
3199
3200 #  elif defined(HAVE_SECIDENTITYSEARCHCREATEWITHPOLICY)
3201  /*
3202   * Use a policy to search for valid certificates whose common name matches the
3203   * servername...
3204   */
3205
3206   if (SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_TP_SSL,
3207                             NULL, &policy_search))
3208   {
3209     cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create a policy search reference");
3210     goto cleanup;
3211   }
3212
3213   if (SecPolicySearchCopyNext(policy_search, &policy))
3214   {
3215     cupsdLogMessage(CUPSD_LOG_ERROR,
3216                     "Cannot find a policy to use for searching");
3217     goto cleanup;
3218   }
3219
3220   memset(&ssl_options, 0, sizeof(ssl_options));
3221   ssl_options.Version = CSSM_APPLE_TP_SSL_OPTS_VERSION;
3222   ssl_options.ServerName = con->servername;
3223   ssl_options.ServerNameLen = strlen(con->servername);
3224
3225   options.Data = (uint8 *)&ssl_options;
3226   options.Length = sizeof(ssl_options);
3227
3228   if (SecPolicySetValue(policy, &options))
3229   {
3230     cupsdLogMessage(CUPSD_LOG_ERROR,
3231                     "Cannot set policy value to use for searching");
3232     goto cleanup;
3233   }
3234
3235   if ((err = SecIdentitySearchCreateWithPolicy(policy, NULL, CSSM_KEYUSE_SIGN,
3236                                                keychain, FALSE, &search)))
3237   {
3238     cupsdLogMessage(CUPSD_LOG_ERROR,
3239                     "Cannot create identity search reference: %s (%d)",
3240                     cssmErrorString(err), (int)err);
3241     goto cleanup;
3242   }
3243
3244   err = SecIdentitySearchCopyNext(search, &identity);
3245
3246   if (err && DNSSDHostName)
3247   {
3248    /*
3249     * Search for the connection server name failed; try the DNS-SD .local
3250     * hostname instead...
3251     */
3252
3253     snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName);
3254
3255     ssl_options.ServerName    = localname;
3256     ssl_options.ServerNameLen = strlen(localname);
3257
3258     cupsdLogMessage(CUPSD_LOG_DEBUG,
3259                     "copy_cdsa_certificate: Looking for certs for \"%s\"...",
3260                     localname);
3261
3262     if (SecPolicySetValue(policy, &options))
3263     {
3264       cupsdLogMessage(CUPSD_LOG_ERROR,
3265                       "Cannot set policy value to use for searching");
3266       goto cleanup;
3267     }
3268
3269     CFRelease(search);
3270     search = NULL;
3271     if ((err = SecIdentitySearchCreateWithPolicy(policy, NULL, CSSM_KEYUSE_SIGN,
3272                                                keychain, FALSE, &search)))
3273     {
3274       cupsdLogMessage(CUPSD_LOG_ERROR,
3275                       "Cannot create identity search reference: %s (%d)",
3276                       cssmErrorString(err), (int)err);
3277       goto cleanup;
3278     }
3279
3280     err = SecIdentitySearchCopyNext(search, &identity);
3281
3282   }
3283
3284   if (err)
3285   {
3286     cupsdLogMessage(CUPSD_LOG_DEBUG,
3287                     "Cannot find signing key in keychain \"%s\": %s (%d)",
3288                     ServerCertificate, cssmErrorString(err), (int)err);
3289     goto cleanup;
3290   }
3291
3292 #  else
3293  /*
3294   * Assume there is exactly one SecIdentity in the keychain...
3295   */
3296
3297   if ((err = SecIdentitySearchCreate(keychain, CSSM_KEYUSE_SIGN, &search)))
3298   {
3299     cupsdLogMessage(CUPSD_LOG_DEBUG,
3300                     "Cannot create identity search reference (%d)", (int)err);
3301     goto cleanup;
3302   }
3303
3304   if ((err = SecIdentitySearchCopyNext(search, &identity)))
3305   {
3306     cupsdLogMessage(CUPSD_LOG_DEBUG,
3307                     "Cannot find signing key in keychain \"%s\": %s (%d)",
3308                     ServerCertificate, cssmErrorString(err), (int)err);
3309     goto cleanup;
3310   }
3311 #  endif /* HAVE_SECPOLICYCREATESSL */
3312
3313   if (CFGetTypeID(identity) != SecIdentityGetTypeID())
3314   {
3315     cupsdLogMessage(CUPSD_LOG_ERROR, "SecIdentity CFTypeID failure!");
3316     goto cleanup;
3317   }
3318
3319   if ((certificates = CFArrayCreate(NULL, (const void **)&identity,
3320                                   1, &kCFTypeArrayCallBacks)) == NULL)
3321   {
3322     cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create certificate array");
3323     goto cleanup;
3324   }
3325
3326   cleanup :
3327
3328   if (keychain)
3329     CFRelease(keychain);
3330   if (search)
3331     CFRelease(search);
3332   if (identity)
3333     CFRelease(identity);
3334
3335 #  if HAVE_SECPOLICYCREATESSL
3336   if (policy)
3337     CFRelease(policy);
3338   if (query)
3339     CFRelease(query);
3340 #  elif defined(HAVE_SECIDENTITYSEARCHCREATEWITHPOLICY)
3341   if (policy)
3342     CFRelease(policy);
3343   if (policy_search)
3344     CFRelease(policy_search);
3345 #  endif /* HAVE_SECPOLICYCREATESSL */
3346
3347   return (certificates);
3348 }
3349 #endif /* HAVE_CDSASSL */
3350
3351
3352 /*
3353  * 'data_ready()' - Check whether data is available from a client.
3354  */
3355
3356 static int                              /* O - 1 if data is ready, 0 otherwise */
3357 data_ready(cupsd_client_t *con)         /* I - Client */
3358 {
3359   if (con->http.used > 0)
3360     return (1);
3361 #ifdef HAVE_SSL
3362   else if (con->http.tls)
3363   {
3364 #  ifdef HAVE_LIBSSL
3365     if (SSL_pending((SSL *)(con->http.tls)))
3366       return (1);
3367 #  elif defined(HAVE_GNUTLS)
3368     if (gnutls_record_check_pending(con->http.tls))
3369       return (1);
3370 #  elif defined(HAVE_CDSASSL)
3371     size_t bytes;                       /* Bytes that are available */
3372
3373     if (!SSLGetBufferedReadSize(con->http.tls, &bytes) && bytes > 0)
3374       return (1);
3375 #  endif /* HAVE_LIBSSL */
3376   }
3377 #endif /* HAVE_SSL */
3378
3379   return (0);
3380 }
3381
3382
3383 #ifdef HAVE_SSL
3384 /*
3385  * 'encrypt_client()' - Enable encryption for the client...
3386  */
3387
3388 static int                              /* O - 1 on success, 0 on error */
3389 encrypt_client(cupsd_client_t *con)     /* I - Client to encrypt */
3390 {
3391 #  ifdef HAVE_LIBSSL
3392   SSL_CTX       *context;               /* Context for encryption */
3393   BIO           *bio;                   /* BIO data */
3394   unsigned long error;                  /* Error code */
3395
3396
3397   cupsdLogMessage(CUPSD_LOG_DEBUG2, "encrypt_client(con=%p(%d))", con,
3398                   con->http.fd);
3399
3400  /*
3401   * Verify that we have a certificate...
3402   */
3403
3404   if (access(ServerKey, 0) || access(ServerCertificate, 0))
3405   {
3406    /*
3407     * Nope, make a self-signed certificate...
3408     */
3409
3410     if (!make_certificate(con))
3411       return (0);
3412   }
3413
3414  /*
3415   * Create the SSL context and accept the connection...
3416   */
3417
3418   context = SSL_CTX_new(SSLv23_server_method());
3419
3420   SSL_CTX_set_options(context, SSL_OP_NO_SSLv2); /* Only use SSLv3 or TLS */
3421   if (SSLOptions & CUPSD_SSL_NOEMPTY)
3422     SSL_CTX_set_options(context, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
3423   SSL_CTX_use_PrivateKey_file(context, ServerKey, SSL_FILETYPE_PEM);
3424   SSL_CTX_use_certificate_chain_file(context, ServerCertificate);
3425
3426   bio = BIO_new(_httpBIOMethods());
3427   BIO_ctrl(bio, BIO_C_SET_FILE_PTR, 0, (char *)HTTP(con));
3428
3429   con->http.tls = SSL_new(context);
3430   SSL_set_bio(con->http.tls, bio, bio);
3431
3432   if (SSL_accept(con->http.tls) != 1)
3433   {
3434     cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to encrypt connection from %s.",
3435                     con->http.hostname);
3436
3437     while ((error = ERR_get_error()) != 0)
3438       cupsdLogMessage(CUPSD_LOG_ERROR, "%s", ERR_error_string(error, NULL));
3439
3440     SSL_CTX_free(context);
3441     SSL_free(con->http.tls);
3442     con->http.tls = NULL;
3443     return (0);
3444   }
3445
3446   cupsdLogMessage(CUPSD_LOG_DEBUG, "Connection from %s now encrypted.",
3447                   con->http.hostname);
3448
3449   return (1);
3450
3451 #  elif defined(HAVE_GNUTLS)
3452   int           status;                 /* Error code */
3453   gnutls_certificate_server_credentials *credentials;
3454                                         /* TLS credentials */
3455
3456
3457   cupsdLogMessage(CUPSD_LOG_DEBUG2, "encrypt_client(con=%p(%d))", con,
3458                   con->http.fd);
3459
3460  /*
3461   * Verify that we have a certificate...
3462   */
3463
3464   if (access(ServerKey, 0) || access(ServerCertificate, 0))
3465   {
3466    /*
3467     * Nope, make a self-signed certificate...
3468     */
3469
3470     if (!make_certificate(con))
3471       return (0);
3472   }
3473
3474  /*
3475   * Create the SSL object and perform the SSL handshake...
3476   */
3477
3478   credentials = (gnutls_certificate_server_credentials *)
3479                     malloc(sizeof(gnutls_certificate_server_credentials));
3480   if (credentials == NULL)
3481   {
3482     cupsdLogMessage(CUPSD_LOG_ERROR,
3483                     "Unable to encrypt connection from %s - %s",
3484                     con->http.hostname, strerror(errno));
3485
3486     return (0);
3487   }
3488
3489   gnutls_certificate_allocate_credentials(credentials);
3490   gnutls_certificate_set_x509_key_file(*credentials, ServerCertificate,
3491                                        ServerKey, GNUTLS_X509_FMT_PEM);
3492
3493   gnutls_init(&con->http.tls, GNUTLS_SERVER);
3494   gnutls_set_default_priority(con->http.tls);
3495
3496   gnutls_credentials_set(con->http.tls, GNUTLS_CRD_CERTIFICATE, *credentials);
3497   gnutls_transport_set_ptr(con->http.tls, (gnutls_transport_ptr)HTTP(con));
3498   gnutls_transport_set_pull_function(con->http.tls, _httpReadGNUTLS);
3499   gnutls_transport_set_push_function(con->http.tls, _httpWriteGNUTLS);
3500
3501   while ((status = gnutls_handshake(con->http.tls)) != GNUTLS_E_SUCCESS)
3502   {
3503     if (gnutls_error_is_fatal(status))
3504     {
3505       cupsdLogMessage(CUPSD_LOG_ERROR,
3506                       "Unable to encrypt connection from %s - %s",
3507                       con->http.hostname, gnutls_strerror(status));
3508
3509       gnutls_deinit(con->http.tls);
3510       gnutls_certificate_free_credentials(*credentials);
3511       con->http.tls = NULL;
3512       free(credentials);
3513       return (0);
3514     }
3515   }
3516
3517   cupsdLogMessage(CUPSD_LOG_DEBUG, "Connection from %s now encrypted.",
3518                   con->http.hostname);
3519
3520   con->http.tls_credentials = credentials;
3521   return (1);
3522
3523 #  elif defined(HAVE_CDSASSL)
3524   OSStatus      error = 0;              /* Error code */
3525   CFArrayRef    peerCerts;              /* Peer certificates */
3526
3527
3528   cupsdLogMessage(CUPSD_LOG_DEBUG2, "encrypt_client(con=%p(%d))", con,
3529                   con->http.fd);
3530
3531   con->http.tls_credentials = copy_cdsa_certificate(con);
3532
3533   if (!con->http.tls_credentials)
3534   {
3535    /*
3536     * No keychain (yet), make a self-signed certificate...
3537     */
3538
3539     if (make_certificate(con))
3540       con->http.tls_credentials = copy_cdsa_certificate(con);
3541   }
3542
3543   if (!con->http.tls_credentials)
3544   {
3545     cupsdLogMessage(CUPSD_LOG_ERROR,
3546                     "Could not find signing key in keychain \"%s\"",
3547                     ServerCertificate);
3548     error = errSSLBadCert; /* errSSLBadConfiguration is a better choice, but not available on 10.2.x */
3549   }
3550
3551   if (!error)
3552     error = SSLNewContext(true, &con->http.tls);
3553
3554   if (!error)
3555     error = SSLSetIOFuncs(con->http.tls, _httpReadCDSA, _httpWriteCDSA);
3556
3557   if (!error)
3558     error = SSLSetConnection(con->http.tls, HTTP(con));
3559
3560   if (!error)
3561     error = SSLSetAllowsExpiredCerts(con->http.tls, true);
3562
3563   if (!error)
3564     error = SSLSetAllowsAnyRoot(con->http.tls, true);
3565
3566   if (!error)
3567     error = SSLSetCertificate(con->http.tls, con->http.tls_credentials);
3568
3569   if (!error)
3570   {
3571    /*
3572     * Perform SSL/TLS handshake
3573     */
3574
3575     while ((error = SSLHandshake(con->http.tls)) == errSSLWouldBlock)
3576       usleep(1000);
3577   }
3578
3579   if (error)
3580   {
3581     cupsdLogMessage(CUPSD_LOG_ERROR,
3582                     "Unable to encrypt connection from %s - %s (%d)",
3583                     con->http.hostname, cssmErrorString(error), (int)error);
3584
3585     con->http.error  = error;
3586     con->http.status = HTTP_ERROR;
3587
3588     if (con->http.tls)
3589     {
3590       SSLDisposeContext(con->http.tls);
3591       con->http.tls = NULL;
3592     }
3593
3594     if (con->http.tls_credentials)
3595     {
3596       CFRelease(con->http.tls_credentials);
3597       con->http.tls_credentials = NULL;
3598     }
3599
3600     return (0);
3601   }
3602
3603   cupsdLogMessage(CUPSD_LOG_DEBUG, "Connection from %s now encrypted.",
3604                   con->http.hostname);
3605
3606   if (!SSLCopyPeerCertificates(con->http.tls, &peerCerts) && peerCerts)
3607   {
3608     cupsdLogMessage(CUPSD_LOG_DEBUG, "Received %d peer certificates!",
3609                     (int)CFArrayGetCount(peerCerts));
3610     CFRelease(peerCerts);
3611   }
3612   else
3613     cupsdLogMessage(CUPSD_LOG_DEBUG, "Received NO peer certificates!");
3614
3615   return (1);
3616
3617 #  endif /* HAVE_LIBSSL */
3618 }
3619 #endif /* HAVE_SSL */
3620
3621
3622 /*
3623  * 'get_file()' - Get a filename and state info.
3624  */
3625
3626 static char *                           /* O  - Real filename */
3627 get_file(cupsd_client_t *con,           /* I  - Client connection */
3628          struct stat    *filestats,     /* O  - File information */
3629          char           *filename,      /* IO - Filename buffer */
3630          int            len)            /* I  - Buffer length */
3631 {
3632   int           status;                 /* Status of filesystem calls */
3633   char          *ptr;                   /* Pointer info filename */
3634   int           plen;                   /* Remaining length after pointer */
3635   char          language[7];            /* Language subdirectory, if any */
3636
3637
3638  /*
3639   * Figure out the real filename...
3640   */
3641
3642   language[0] = '\0';
3643
3644   if (!strncmp(con->uri, "/ppd/", 5) && !strchr(con->uri + 5, '/'))
3645     snprintf(filename, len, "%s%s", ServerRoot, con->uri);
3646   else if (!strncmp(con->uri, "/icons/", 7) && !strchr(con->uri + 7, '/'))
3647   {
3648     snprintf(filename, len, "%s/%s", CacheDir, con->uri + 7);
3649     if (access(filename, F_OK) < 0)
3650       snprintf(filename, len, "%s/images/generic.png", DocumentRoot);
3651   }
3652   else if (!strncmp(con->uri, "/rss/", 5) && !strchr(con->uri + 5, '/'))
3653     snprintf(filename, len, "%s/rss/%s", CacheDir, con->uri + 5);
3654   else if (!strncmp(con->uri, "/admin/conf/", 12))
3655     snprintf(filename, len, "%s%s", ServerRoot, con->uri + 11);
3656   else if (!strncmp(con->uri, "/admin/log/", 11))
3657   {
3658     if (!strncmp(con->uri + 11, "access_log", 10) && AccessLog[0] == '/')
3659       strlcpy(filename, AccessLog, len);
3660     else if (!strncmp(con->uri + 11, "error_log", 9) && ErrorLog[0] == '/')
3661       strlcpy(filename, ErrorLog, len);
3662     else if (!strncmp(con->uri + 11, "page_log", 8) && PageLog[0] == '/')
3663       strlcpy(filename, PageLog, len);
3664     else
3665       return (NULL);
3666   }
3667   else if (con->language)
3668   {
3669     snprintf(language, sizeof(language), "/%s", con->language->language);
3670     snprintf(filename, len, "%s%s%s", DocumentRoot, language, con->uri);
3671   }
3672   else
3673     snprintf(filename, len, "%s%s", DocumentRoot, con->uri);
3674
3675   if ((ptr = strchr(filename, '?')) != NULL)
3676     *ptr = '\0';
3677
3678  /*
3679   * Grab the status for this language; if there isn't a language-specific file
3680   * then fallback to the default one...
3681   */
3682
3683   if ((status = stat(filename, filestats)) != 0 && language[0] &&
3684       strncmp(con->uri, "/icons/", 7) &&
3685       strncmp(con->uri, "/ppd/", 5) &&
3686       strncmp(con->uri, "/rss/", 5) &&
3687       strncmp(con->uri, "/admin/conf/", 12) &&
3688       strncmp(con->uri, "/admin/log/", 11))
3689   {
3690    /*
3691     * Drop the country code...
3692     */
3693
3694     language[3] = '\0';
3695     snprintf(filename, len, "%s%s%s", DocumentRoot, language, con->uri);
3696
3697     if ((ptr = strchr(filename, '?')) != NULL)
3698       *ptr = '\0';
3699
3700     if ((status = stat(filename, filestats)) != 0)
3701     {
3702      /*
3703       * Drop the language prefix and try the root directory...
3704       */
3705
3706       language[0] = '\0';
3707       snprintf(filename, len, "%s%s", DocumentRoot, con->uri);
3708
3709       if ((ptr = strchr(filename, '?')) != NULL)
3710         *ptr = '\0';
3711
3712       status = stat(filename, filestats);
3713     }
3714   }
3715
3716  /*
3717   * If we're found a directory, get the index.html file instead...
3718   */
3719
3720   if (!status && S_ISDIR(filestats->st_mode))
3721   {
3722    /*
3723     * Make sure the URI ends with a slash...
3724     */
3725
3726     if (con->uri[strlen(con->uri) - 1] != '/')
3727       strlcat(con->uri, "/", sizeof(con->uri));
3728
3729    /*
3730     * Find the directory index file, trying every language...
3731     */
3732
3733     do
3734     {
3735       if (status && language[0])
3736       {
3737        /*
3738         * Try a different language subset...
3739         */
3740
3741         if (language[3])
3742           language[0] = '\0';           /* Strip country code */
3743         else
3744           language[0] = '\0';           /* Strip language */
3745       }
3746
3747      /*
3748       * Look for the index file...
3749       */
3750
3751       snprintf(filename, len, "%s%s%s", DocumentRoot, language, con->uri);
3752
3753       if ((ptr = strchr(filename, '?')) != NULL)
3754         *ptr = '\0';
3755
3756       ptr  = filename + strlen(filename);
3757       plen = len - (ptr - filename);
3758
3759       strlcpy(ptr, "index.html", plen);
3760       status = stat(filename, filestats);
3761
3762 #ifdef HAVE_JAVA
3763       if (status)
3764       {
3765         strlcpy(ptr, "index.class", plen);
3766         status = stat(filename, filestats);
3767       }
3768 #endif /* HAVE_JAVA */
3769
3770 #ifdef HAVE_PERL
3771       if (status)
3772       {
3773         strlcpy(ptr, "index.pl", plen);
3774         status = stat(filename, filestats);
3775       }
3776 #endif /* HAVE_PERL */
3777
3778 #ifdef HAVE_PHP
3779       if (status)
3780       {
3781         strlcpy(ptr, "index.php", plen);
3782         status = stat(filename, filestats);
3783       }
3784 #endif /* HAVE_PHP */
3785
3786 #ifdef HAVE_PYTHON
3787       if (status)
3788       {
3789         strlcpy(ptr, "index.pyc", plen);
3790         status = stat(filename, filestats);
3791       }
3792
3793       if (status)
3794       {
3795         strlcpy(ptr, "index.py", plen);
3796         status = stat(filename, filestats);
3797       }
3798 #endif /* HAVE_PYTHON */
3799
3800     }
3801     while (status && language[0]);
3802   }
3803
3804   cupsdLogMessage(CUPSD_LOG_DEBUG2,
3805                   "get_file(con=%p(%d), filestats=%p, filename=%p, len=%d) = "
3806                   "%s", con, con->http.fd, filestats, filename, len,
3807                   status ? "(null)" : filename);
3808
3809   if (status)
3810     return (NULL);
3811   else
3812     return (filename);
3813 }
3814
3815
3816 /*
3817  * 'install_conf_file()' - Install a configuration file.
3818  */
3819
3820 static http_status_t                    /* O - Status */
3821 install_conf_file(cupsd_client_t *con)  /* I - Connection */
3822 {
3823   char          filename[1024];         /* Configuration filename */
3824   mode_t        mode;                   /* Permissions */
3825   cups_file_t   *in,                    /* Input file */
3826                 *out;                   /* Output file */
3827   char          buffer[16384];          /* Copy buffer */
3828   ssize_t       bytes;                  /* Number of bytes */
3829
3830
3831  /*
3832   * Open the request file...
3833   */
3834
3835   if ((in = cupsFileOpen(con->filename, "rb")) == NULL)
3836   {
3837     cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open request file \"%s\": %s",
3838                     con->filename, strerror(errno));
3839     return (HTTP_SERVER_ERROR);
3840   }
3841
3842  /*
3843   * Open the new config file...
3844   */
3845
3846   snprintf(filename, sizeof(filename), "%s%s", ServerRoot, con->uri + 11);
3847   if (!strcmp(con->uri, "/admin/conf/printers.conf"))
3848     mode = ConfigFilePerm & 0600;
3849   else
3850     mode = ConfigFilePerm;
3851
3852   if ((out = cupsdCreateConfFile(filename, mode)) == NULL)
3853   {
3854     cupsFileClose(in);
3855     return (HTTP_SERVER_ERROR);
3856   }
3857
3858   cupsdLogMessage(CUPSD_LOG_INFO, "Installing config file \"%s\"...", filename);
3859
3860  /*
3861   * Copy from the request to the new config file...
3862   */
3863
3864   while ((bytes = cupsFileRead(in, buffer, sizeof(buffer))) > 0)
3865     if (cupsFileWrite(out, buffer, bytes) < bytes)
3866     {
3867       cupsdLogMessage(CUPSD_LOG_ERROR,
3868                       "Unable to copy to config file \"%s\": %s",
3869                       filename, strerror(errno));
3870
3871       cupsFileClose(in);
3872       cupsFileClose(out);
3873
3874       snprintf(filename, sizeof(filename), "%s%s.N", ServerRoot, con->uri + 11);
3875       cupsdRemoveFile(filename);
3876
3877       return (HTTP_SERVER_ERROR);
3878     }
3879
3880  /*
3881   * Close the files...
3882   */
3883
3884   cupsFileClose(in);
3885
3886   if (cupsdCloseCreatedConfFile(out, filename))
3887     return (HTTP_SERVER_ERROR);
3888
3889  /*
3890   * Remove the request file...
3891   */
3892
3893   cupsdRemoveFile(con->filename);
3894   cupsdClearString(&con->filename);
3895
3896  /*
3897   * If the cupsd.conf file was updated, set the NeedReload flag...
3898   */
3899
3900   if (!strcmp(con->uri, "/admin/conf/cupsd.conf"))
3901     NeedReload = RELOAD_CUPSD;
3902   else
3903     NeedReload = RELOAD_ALL;
3904
3905   ReloadTime = time(NULL);
3906
3907  /*
3908   * Return that the file was created successfully...
3909   */
3910
3911   return (HTTP_CREATED);
3912 }
3913
3914
3915 /*
3916  * 'is_cgi()' - Is the resource a CGI script/program?
3917  */
3918
3919 static int                              /* O - 1 = CGI, 0 = file */
3920 is_cgi(cupsd_client_t *con,             /* I - Client connection */
3921        const char     *filename,        /* I - Real filename */
3922        struct stat    *filestats,       /* I - File information */
3923        mime_type_t    *type)            /* I - MIME type */
3924 {
3925   const char    *options;               /* Options on URL */
3926
3927
3928  /*
3929   * Get the options, if any...
3930   */
3931
3932   if ((options = strchr(con->uri, '?')) != NULL)
3933   {
3934     options ++;
3935     cupsdSetStringf(&(con->query_string), "QUERY_STRING=%s", options);
3936   }
3937
3938  /*
3939   * Check for known types...
3940   */
3941
3942   if (!type || _cups_strcasecmp(type->super, "application"))
3943   {
3944     cupsdLogMessage(CUPSD_LOG_DEBUG2,
3945                     "is_cgi(con=%p(%d), filename=\"%s\", filestats=%p, "
3946                     "type=%s/%s) = 0", con, con->http.fd, filename, filestats,
3947                     type ? type->super : "unknown",
3948                     type ? type->type : "unknown");
3949     return (0);
3950   }
3951
3952   if (!_cups_strcasecmp(type->type, "x-httpd-cgi") &&
3953       (filestats->st_mode & 0111))
3954   {
3955    /*
3956     * "application/x-httpd-cgi" is a CGI script.
3957     */
3958
3959     cupsdSetString(&con->command, filename);
3960
3961     if (options)
3962       cupsdSetStringf(&con->options, " %s", options);
3963
3964     cupsdLogMessage(CUPSD_LOG_DEBUG2,
3965                     "is_cgi(con=%p(%d), filename=\"%s\", filestats=%p, "
3966                     "type=%s/%s) = 1", con, con->http.fd, filename, filestats,
3967                     type->super, type->type);
3968     return (1);
3969   }
3970 #ifdef HAVE_JAVA
3971   else if (!_cups_strcasecmp(type->type, "x-httpd-java"))
3972   {
3973    /*
3974     * "application/x-httpd-java" is a Java servlet.
3975     */
3976
3977     cupsdSetString(&con->command, CUPS_JAVA);
3978
3979     if (options)
3980       cupsdSetStringf(&con->options, " %s %s", filename, options);
3981     else
3982       cupsdSetStringf(&con->options, " %s", filename);
3983
3984     cupsdLogMessage(CUPSD_LOG_DEBUG2,
3985                     "is_cgi(con=%p(%d), filename=\"%s\", filestats=%p, "
3986                     "type=%s/%s) = 1", con, con->http.fd, filename, filestats,
3987                     type->super, type->type);
3988     return (1);
3989   }
3990 #endif /* HAVE_JAVA */
3991 #ifdef HAVE_PERL
3992   else if (!_cups_strcasecmp(type->type, "x-httpd-perl"))
3993   {
3994    /*
3995     * "application/x-httpd-perl" is a Perl page.
3996     */
3997
3998     cupsdSetString(&con->command, CUPS_PERL);
3999
4000     if (options)
4001       cupsdSetStringf(&con->options, " %s %s", filename, options);
4002     else
4003       cupsdSetStringf(&con->options, " %s", filename);
4004
4005     cupsdLogMessage(CUPSD_LOG_DEBUG2,
4006                     "is_cgi(con=%p(%d), filename=\"%s\", filestats=%p, "
4007                     "type=%s/%s) = 1", con, con->http.fd, filename, filestats,
4008                     type->super, type->type);
4009     return (1);
4010   }
4011 #endif /* HAVE_PERL */
4012 #ifdef HAVE_PHP
4013   else if (!_cups_strcasecmp(type->type, "x-httpd-php"))
4014   {
4015    /*
4016     * "application/x-httpd-php" is a PHP page.
4017     */
4018
4019     cupsdSetString(&con->command, CUPS_PHP);
4020
4021     if (options)
4022       cupsdSetStringf(&con->options, " %s %s", filename, options);
4023     else
4024       cupsdSetStringf(&con->options, " %s", filename);
4025
4026     cupsdLogMessage(CUPSD_LOG_DEBUG2,
4027                     "is_cgi(con=%p(%d), filename=\"%s\", filestats=%p, "
4028                     "type=%s/%s) = 1", con, con->http.fd, filename, filestats,
4029                     type->super, type->type);
4030     return (1);
4031   }
4032 #endif /* HAVE_PHP */
4033 #ifdef HAVE_PYTHON
4034   else if (!_cups_strcasecmp(type->type, "x-httpd-python"))
4035   {
4036    /*
4037     * "application/x-httpd-python" is a Python page.
4038     */
4039
4040     cupsdSetString(&con->command, CUPS_PYTHON);
4041
4042     if (options)
4043       cupsdSetStringf(&con->options, " %s %s", filename, options);
4044     else
4045       cupsdSetStringf(&con->options, " %s", filename);
4046
4047     cupsdLogMessage(CUPSD_LOG_DEBUG2,
4048                     "is_cgi(con=%p(%d), filename=\"%s\", filestats=%p, "
4049                     "type=%s/%s) = 1", con, con->http.fd, filename, filestats,
4050                     type->super, type->type);
4051     return (1);
4052   }
4053 #endif /* HAVE_PYTHON */
4054
4055   cupsdLogMessage(CUPSD_LOG_DEBUG2,
4056                   "is_cgi(con=%p(%d), filename=\"%s\", filestats=%p, "
4057                   "type=%s/%s) = 0", con, con->http.fd, filename, filestats,
4058                   type->super, type->type);
4059   return (0);
4060 }
4061
4062
4063 /*
4064  * 'is_path_absolute()' - Is a path absolute and free of relative elements (i.e. "..").
4065  */
4066
4067 static int                              /* O - 0 if relative, 1 if absolute */
4068 is_path_absolute(const char *path)      /* I - Input path */
4069 {
4070  /*
4071   * Check for a leading slash...
4072   */
4073
4074   if (path[0] != '/')
4075     return (0);
4076
4077  /*
4078   * Check for "/.." in the path...
4079   */
4080
4081   while ((path = strstr(path, "/..")) != NULL)
4082   {
4083     if (!path[3] || path[3] == '/')
4084       return (0);
4085
4086     path ++;
4087   }
4088
4089  /*
4090   * If we haven't found any relative paths, return 1 indicating an
4091   * absolute path...
4092   */
4093
4094   return (1);
4095 }
4096
4097
4098 #ifdef HAVE_SSL
4099 /*
4100  * 'make_certificate()' - Make a self-signed SSL/TLS certificate.
4101  */
4102
4103 static int                              /* O - 1 on success, 0 on failure */
4104 make_certificate(cupsd_client_t *con)   /* I - Client connection */
4105 {
4106 #if defined(HAVE_LIBSSL) && defined(HAVE_WAITPID)
4107   int           pid,                    /* Process ID of command */
4108                 status;                 /* Status of command */
4109   char          command[1024],          /* Command */
4110                 *argv[12],              /* Command-line arguments */
4111                 *envp[MAX_ENV + 1],     /* Environment variables */
4112                 infofile[1024],         /* Type-in information for cert */
4113                 seedfile[1024];         /* Random number seed file */
4114   int           envc,                   /* Number of environment variables */
4115                 bytes;                  /* Bytes written */
4116   cups_file_t   *fp;                    /* Seed/info file */
4117   int           infofd;                 /* Info file descriptor */
4118
4119
4120  /*
4121   * Run the "openssl" command to seed the random number generator and
4122   * generate a self-signed certificate that is good for 10 years:
4123   *
4124   *     openssl rand -rand seedfile 1
4125   *
4126   *     openssl req -new -x509 -keyout ServerKey \
4127   *             -out ServerCertificate -days 3650 -nodes
4128   *
4129   * The seeding step is crucial in ensuring that the openssl command
4130   * does not block on systems without sufficient entropy...
4131   */
4132
4133   if (!cupsFileFind("openssl", getenv("PATH"), 1, command, sizeof(command)))
4134   {
4135     cupsdLogMessage(CUPSD_LOG_ERROR,
4136                     "No SSL certificate and openssl command not found!");
4137     return (0);
4138   }
4139
4140   if (access("/dev/urandom", 0))
4141   {
4142    /*
4143     * If the system doesn't provide /dev/urandom, then any random source
4144     * will probably be blocking-style, so generate some random data to
4145     * use as a seed for the certificate.  Note that we have already
4146     * seeded the random number generator in cupsdInitCerts()...
4147     */
4148
4149     cupsdLogMessage(CUPSD_LOG_INFO,
4150                     "Seeding the random number generator...");
4151
4152    /*
4153     * Write the seed file...
4154     */
4155
4156     if ((fp = cupsTempFile2(seedfile, sizeof(seedfile))) == NULL)
4157     {
4158       cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create seed file %s - %s",
4159                       seedfile, strerror(errno));
4160       return (0);
4161     }
4162
4163     for (bytes = 0; bytes < 262144; bytes ++)
4164       cupsFilePutChar(fp, random());
4165
4166     cupsFileClose(fp);
4167
4168    /*
4169     * Run the openssl command to seed its random number generator...
4170     */
4171
4172     argv[0] = "openssl";
4173     argv[1] = "rand";
4174     argv[2] = "-rand";
4175     argv[3] = seedfile;
4176     argv[4] = "1";
4177     argv[5] = NULL;
4178
4179     envc = cupsdLoadEnv(envp, MAX_ENV);
4180     envp[envc] = NULL;
4181
4182     if (!cupsdStartProcess(command, argv, envp, -1, -1, -1, -1, -1, 1, NULL,
4183                            NULL, &pid))
4184     {
4185       unlink(seedfile);
4186       return (0);
4187     }
4188
4189     while (waitpid(pid, &status, 0) < 0)
4190       if (errno != EINTR)
4191       {
4192         status = 1;
4193         break;
4194       }
4195
4196     cupsdFinishProcess(pid, command, sizeof(command), NULL);
4197
4198    /*
4199     * Remove the seed file, as it is no longer needed...
4200     */
4201
4202     unlink(seedfile);
4203
4204     if (status)
4205     {
4206       if (WIFEXITED(status))
4207         cupsdLogMessage(CUPSD_LOG_ERROR,
4208                         "Unable to seed random number generator - "
4209                         "the openssl command stopped with status %d!",
4210                         WEXITSTATUS(status));
4211       else
4212         cupsdLogMessage(CUPSD_LOG_ERROR,
4213                         "Unable to seed random number generator - "
4214                         "the openssl command crashed on signal %d!",
4215                         WTERMSIG(status));
4216
4217       return (0);
4218     }
4219   }
4220
4221  /*
4222   * Create a file with the certificate information fields...
4223   *
4224   * Note: This assumes that the default questions are asked by the openssl
4225   * command...
4226   */
4227
4228   if ((fp = cupsTempFile2(infofile, sizeof(infofile))) == NULL)
4229   {
4230     cupsdLogMessage(CUPSD_LOG_ERROR,
4231                     "Unable to create certificate information file %s - %s",
4232                     infofile, strerror(errno));
4233     return (0);
4234   }
4235
4236   cupsFilePrintf(fp, ".\n.\n.\n%s\n.\n%s\n%s\n",
4237                  ServerName, ServerName, ServerAdmin);
4238   cupsFileClose(fp);
4239
4240   cupsdLogMessage(CUPSD_LOG_INFO,
4241                   "Generating SSL server key and certificate...");
4242
4243   argv[0]  = "openssl";
4244   argv[1]  = "req";
4245   argv[2]  = "-new";
4246   argv[3]  = "-x509";
4247   argv[4]  = "-keyout";
4248   argv[5]  = ServerKey;
4249   argv[6]  = "-out";
4250   argv[7]  = ServerCertificate;
4251   argv[8]  = "-days";
4252   argv[9]  = "3650";
4253   argv[10] = "-nodes";
4254   argv[11] = NULL;
4255
4256   cupsdLoadEnv(envp, MAX_ENV);
4257
4258   infofd = open(infofile, O_RDONLY);
4259
4260   if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, NULL,
4261                          NULL, &pid))
4262   {
4263     close(infofd);
4264     unlink(infofile);
4265     return (0);
4266   }
4267
4268   close(infofd);
4269   unlink(infofile);
4270
4271   while (waitpid(pid, &status, 0) < 0)
4272     if (errno != EINTR)
4273     {
4274       status = 1;
4275       break;
4276     }
4277
4278   cupsdFinishProcess(pid, command, sizeof(command), NULL);
4279
4280   if (status)
4281   {
4282     if (WIFEXITED(status))
4283       cupsdLogMessage(CUPSD_LOG_ERROR,
4284                       "Unable to create SSL server key and certificate - "
4285                       "the openssl command stopped with status %d!",
4286                       WEXITSTATUS(status));
4287     else
4288       cupsdLogMessage(CUPSD_LOG_ERROR,
4289                       "Unable to create SSL server key and certificate - "
4290                       "the openssl command crashed on signal %d!",
4291                       WTERMSIG(status));
4292   }
4293   else
4294   {
4295     cupsdLogMessage(CUPSD_LOG_INFO, "Created SSL server key file \"%s\"...",
4296                     ServerKey);
4297     cupsdLogMessage(CUPSD_LOG_INFO,
4298                     "Created SSL server certificate file \"%s\"...",
4299                     ServerCertificate);
4300   }
4301
4302   return (!status);
4303
4304 #elif defined(HAVE_GNUTLS)
4305   gnutls_x509_crt       crt;            /* Self-signed certificate */
4306   gnutls_x509_privkey   key;            /* Encryption key */
4307   cups_lang_t           *language;      /* Default language info */
4308   cups_file_t           *fp;            /* Key/cert file */
4309   unsigned char         buffer[8192];   /* Buffer for x509 data */
4310   size_t                bytes;          /* Number of bytes of data */
4311   unsigned char         serial[4];      /* Serial number buffer */
4312   time_t                curtime;        /* Current time */
4313   int                   result;         /* Result of GNU TLS calls */
4314
4315
4316  /*
4317   * Create the encryption key...
4318   */
4319
4320   cupsdLogMessage(CUPSD_LOG_INFO, "Generating SSL server key...");
4321
4322   gnutls_x509_privkey_init(&key);
4323   gnutls_x509_privkey_generate(key, GNUTLS_PK_RSA, 2048, 0);
4324
4325  /*
4326   * Save it...
4327   */
4328
4329   bytes = sizeof(buffer);
4330
4331   if ((result = gnutls_x509_privkey_export(key, GNUTLS_X509_FMT_PEM,
4332                                            buffer, &bytes)) < 0)
4333   {
4334     cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to export SSL server key - %s",
4335                     gnutls_strerror(result));
4336     gnutls_x509_privkey_deinit(key);
4337     return (0);
4338   }
4339   else if ((fp = cupsFileOpen(ServerKey, "w")) != NULL)
4340   {
4341     cupsFileWrite(fp, (char *)buffer, bytes);
4342     cupsFileClose(fp);
4343
4344     cupsdLogMessage(CUPSD_LOG_INFO, "Created SSL server key file \"%s\"...",
4345                     ServerKey);
4346   }
4347   else
4348   {
4349     cupsdLogMessage(CUPSD_LOG_ERROR,
4350                     "Unable to create SSL server key file \"%s\" - %s",
4351                     ServerKey, strerror(errno));
4352     gnutls_x509_privkey_deinit(key);
4353     return (0);
4354   }
4355
4356  /*
4357   * Create the self-signed certificate...
4358   */
4359
4360   cupsdLogMessage(CUPSD_LOG_INFO, "Generating self-signed SSL certificate...");
4361
4362   language  = cupsLangDefault();
4363   curtime   = time(NULL);
4364   serial[0] = curtime >> 24;
4365   serial[1] = curtime >> 16;
4366   serial[2] = curtime >> 8;
4367   serial[3] = curtime;
4368
4369   gnutls_x509_crt_init(&crt);
4370   if (strlen(language->language) == 5)
4371     gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0,
4372                                   language->language + 3, 2);
4373   else
4374     gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0,
4375                                   "US", 2);
4376   gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COMMON_NAME, 0,
4377                                 ServerName, strlen(ServerName));
4378   gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATION_NAME, 0,
4379                                 ServerName, strlen(ServerName));
4380   gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME,
4381                                 0, "Unknown", 7);
4382   gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0,
4383                                 "Unknown", 7);
4384   gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_LOCALITY_NAME, 0,
4385                                 "Unknown", 7);
4386   gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_PKCS9_EMAIL, 0,
4387                                 ServerAdmin, strlen(ServerAdmin));
4388   gnutls_x509_crt_set_key(crt, key);
4389   gnutls_x509_crt_set_serial(crt, serial, sizeof(serial));
4390   gnutls_x509_crt_set_activation_time(crt, curtime);
4391   gnutls_x509_crt_set_expiration_time(crt, curtime + 10 * 365 * 86400);
4392   gnutls_x509_crt_set_ca_status(crt, 0);
4393   gnutls_x509_crt_set_subject_alternative_name(crt, GNUTLS_SAN_DNSNAME,
4394                                                ServerName);
4395   gnutls_x509_crt_set_key_purpose_oid(crt, GNUTLS_KP_TLS_WWW_SERVER, 0);
4396   gnutls_x509_crt_set_key_usage(crt, GNUTLS_KEY_KEY_ENCIPHERMENT);
4397   gnutls_x509_crt_set_version(crt, 3);
4398
4399   bytes = sizeof(buffer);
4400   if (gnutls_x509_crt_get_key_id(crt, 0, buffer, &bytes) >= 0)
4401     gnutls_x509_crt_set_subject_key_id(crt, buffer, bytes);
4402
4403   gnutls_x509_crt_sign(crt, crt, key);
4404
4405  /*
4406   * Save it...
4407   */
4408
4409   bytes = sizeof(buffer);
4410   if ((result = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM,
4411                                        buffer, &bytes)) < 0)
4412     cupsdLogMessage(CUPSD_LOG_ERROR,
4413                     "Unable to export SSL server certificate - %s",
4414                     gnutls_strerror(result));
4415   else if ((fp = cupsFileOpen(ServerCertificate, "w")) != NULL)
4416   {
4417     cupsFileWrite(fp, (char *)buffer, bytes);
4418     cupsFileClose(fp);
4419
4420     cupsdLogMessage(CUPSD_LOG_INFO,
4421                     "Created SSL server certificate file \"%s\"...",
4422                     ServerCertificate);
4423   }
4424   else
4425     cupsdLogMessage(CUPSD_LOG_ERROR,
4426                     "Unable to create SSL server certificate file \"%s\" - %s",
4427                     ServerCertificate, strerror(errno));
4428
4429  /*
4430   * Cleanup...
4431   */
4432
4433   gnutls_x509_crt_deinit(crt);
4434   gnutls_x509_privkey_deinit(key);
4435
4436   return (1);
4437
4438 #elif defined(HAVE_CDSASSL) && defined(HAVE_WAITPID)
4439   int           pid,                    /* Process ID of command */
4440                 status;                 /* Status of command */
4441   char          command[1024],          /* Command */
4442                 *argv[4],               /* Command-line arguments */
4443                 *envp[MAX_ENV + 1],     /* Environment variables */
4444                 keychain[1024],         /* Keychain argument */
4445                 infofile[1024],         /* Type-in information for cert */
4446                 localname[1024],        /* Local hostname */
4447                 *servername;            /* Name of server in cert */
4448   cups_file_t   *fp;                    /* Seed/info file */
4449   int           infofd;                 /* Info file descriptor */
4450
4451
4452   if (con->servername && isdigit(con->servername[0] & 255) && DNSSDHostName)
4453   {
4454     snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName);
4455     servername = localname;
4456   }
4457   else
4458     servername = con->servername;
4459
4460  /*
4461   * Run the "certtool" command to generate a self-signed certificate...
4462   */
4463
4464   if (!cupsFileFind("certtool", getenv("PATH"), 1, command, sizeof(command)))
4465   {
4466     cupsdLogMessage(CUPSD_LOG_ERROR,
4467                     "No SSL certificate and certtool command not found!");
4468     return (0);
4469   }
4470
4471  /*
4472   * Create a file with the certificate information fields...
4473   *
4474   * Note: This assumes that the default questions are asked by the certtool
4475   * command...
4476   */
4477
4478   if ((fp = cupsTempFile2(infofile, sizeof(infofile))) == NULL)
4479   {
4480     cupsdLogMessage(CUPSD_LOG_ERROR,
4481                     "Unable to create certificate information file %s - %s",
4482                     infofile, strerror(errno));
4483     return (0);
4484   }
4485
4486   cupsFilePrintf(fp,
4487                  "%s\n"                 /* Enter key and certificate label */
4488                  "r\n"                  /* Generate RSA key pair */
4489                  "2048\n"               /* Key size in bits */
4490                  "y\n"                  /* OK (y = yes) */
4491                  "b\n"                  /* Usage (b=signing/encryption) */
4492                  "s\n"                  /* Sign with SHA1 */
4493                  "y\n"                  /* OK (y = yes) */
4494                  "%s\n"                 /* Common name */
4495                  "\n"                   /* Country (default) */
4496                  "\n"                   /* Organization (default) */
4497                  "\n"                   /* Organizational unit (default) */
4498                  "\n"                   /* State/Province (default) */
4499                  "%s\n"                 /* Email address */
4500                  "y\n",                 /* OK (y = yes) */
4501                  servername, servername, ServerAdmin);
4502   cupsFileClose(fp);
4503
4504   cupsdLogMessage(CUPSD_LOG_INFO,
4505                   "Generating SSL server key and certificate...");
4506
4507   snprintf(keychain, sizeof(keychain), "k=%s", ServerCertificate);
4508
4509   argv[0] = "certtool";
4510   argv[1] = "c";
4511   argv[2] = keychain;
4512   argv[3] = NULL;
4513
4514   cupsdLoadEnv(envp, MAX_ENV);
4515
4516   infofd = open(infofile, O_RDONLY);
4517
4518   if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, NULL,
4519                          NULL, &pid))
4520   {
4521     close(infofd);
4522     unlink(infofile);
4523     return (0);
4524   }
4525
4526   close(infofd);
4527   unlink(infofile);
4528
4529   while (waitpid(pid, &status, 0) < 0)
4530     if (errno != EINTR)
4531     {
4532       status = 1;
4533       break;
4534     }
4535
4536   cupsdFinishProcess(pid, command, sizeof(command), NULL);
4537
4538   if (status)
4539   {
4540     if (WIFEXITED(status))
4541       cupsdLogMessage(CUPSD_LOG_ERROR,
4542                       "Unable to create SSL server key and certificate - "
4543                       "the certtool command stopped with status %d!",
4544                       WEXITSTATUS(status));
4545     else
4546       cupsdLogMessage(CUPSD_LOG_ERROR,
4547                       "Unable to create SSL server key and certificate - "
4548                       "the certtool command crashed on signal %d!",
4549                       WTERMSIG(status));
4550   }
4551   else
4552   {
4553     cupsdLogMessage(CUPSD_LOG_INFO,
4554                     "Created SSL server certificate file \"%s\"...",
4555                     ServerCertificate);
4556   }
4557
4558   return (!status);
4559
4560 #else
4561   return (0);
4562 #endif /* HAVE_LIBSSL && HAVE_WAITPID */
4563 }
4564 #endif /* HAVE_SSL */
4565
4566
4567 /*
4568  * 'pipe_command()' - Pipe the output of a command to the remote client.
4569  */
4570
4571 static int                              /* O - Process ID */
4572 pipe_command(cupsd_client_t *con,       /* I - Client connection */
4573              int            infile,     /* I - Standard input for command */
4574              int            *outfile,   /* O - Standard output for command */
4575              char           *command,   /* I - Command to run */
4576              char           *options,   /* I - Options for command */
4577              int            root)       /* I - Run as root? */
4578 {
4579   int           i;                      /* Looping var */
4580   int           pid;                    /* Process ID */
4581   char          *commptr,               /* Command string pointer */
4582                 commch;                 /* Command string character */
4583   char          *uriptr;                /* URI string pointer */
4584   int           fds[2];                 /* Pipe FDs */
4585   int           argc;                   /* Number of arguments */
4586   int           envc;                   /* Number of environment variables */
4587   char          argbuf[10240],          /* Argument buffer */
4588                 *argv[100],             /* Argument strings */
4589                 *envp[MAX_ENV + 20];    /* Environment variables */
4590   char          auth_type[256],         /* AUTH_TYPE environment variable */
4591                 content_length[1024],   /* CONTENT_LENGTH environment variable */
4592                 content_type[1024],     /* CONTENT_TYPE environment variable */
4593                 http_cookie[32768],     /* HTTP_COOKIE environment variable */
4594                 http_referer[1024],     /* HTTP_REFERER environment variable */
4595                 http_user_agent[1024],  /* HTTP_USER_AGENT environment variable */
4596                 lang[1024],             /* LANG environment variable */
4597                 path_info[1024],        /* PATH_INFO environment variable */
4598                 remote_addr[1024],      /* REMOTE_ADDR environment variable */
4599                 remote_host[1024],      /* REMOTE_HOST environment variable */
4600                 remote_user[1024],      /* REMOTE_USER environment variable */
4601                 script_filename[1024],  /* SCRIPT_FILENAME environment variable */
4602                 script_name[1024],      /* SCRIPT_NAME environment variable */
4603                 server_name[1024],      /* SERVER_NAME environment variable */
4604                 server_port[1024];      /* SERVER_PORT environment variable */
4605   ipp_attribute_t *attr;                /* attributes-natural-language attribute */
4606   void          *ccache = NULL;         /* Kerberos credentials */
4607
4608
4609  /*
4610   * Parse a copy of the options string, which is of the form:
4611   *
4612   *     argument+argument+argument
4613   *     ?argument+argument+argument
4614   *     param=value&param=value
4615   *     ?param=value&param=value
4616   *     /name?argument+argument+argument
4617   *     /name?param=value&param=value
4618   *
4619   * If the string contains an "=" character after the initial name,
4620   * then we treat it as a HTTP GET form request and make a copy of
4621   * the remaining string for the environment variable.
4622   *
4623   * The string is always parsed out as command-line arguments, to
4624   * be consistent with Apache...
4625   */
4626
4627   cupsdLogMessage(CUPSD_LOG_DEBUG2,
4628                   "pipe_command(con=%p(%d), infile=%d, outfile=%p, "
4629                   "command=\"%s\", options=\"%s\", root=%d)",
4630                   con, con->http.fd, infile, outfile, command,
4631                   options ? options : "(null)", root);
4632
4633   argv[0] = command;
4634
4635   if (options)
4636   {
4637     commptr = options;
4638     if (*commptr == ' ')
4639       commptr ++;
4640     strlcpy(argbuf, commptr, sizeof(argbuf));
4641   }
4642   else
4643     argbuf[0] = '\0';
4644
4645   if (argbuf[0] == '/')
4646   {
4647    /*
4648     * Found some trailing path information, set PATH_INFO...
4649     */
4650
4651     if ((commptr = strchr(argbuf, '?')) == NULL)
4652       commptr = argbuf + strlen(argbuf);
4653
4654     commch   = *commptr;
4655     *commptr = '\0';
4656     snprintf(path_info, sizeof(path_info), "PATH_INFO=%s", argbuf);
4657     *commptr = commch;
4658   }
4659   else
4660   {
4661     commptr      = argbuf;
4662     path_info[0] = '\0';
4663
4664     if (*commptr == ' ')
4665       commptr ++;
4666   }
4667
4668   if (*commptr == '?' && con->operation == HTTP_GET && !con->query_string)
4669   {
4670     commptr ++;
4671     cupsdSetStringf(&(con->query_string), "QUERY_STRING=%s", commptr);
4672   }
4673
4674   argc = 1;
4675
4676   if (*commptr)
4677   {
4678     argv[argc ++] = commptr;
4679
4680     for (; *commptr && argc < 99; commptr ++)
4681     {
4682      /*
4683       * Break arguments whenever we see a + or space...
4684       */
4685
4686       if (*commptr == ' ' || *commptr == '+')
4687       {
4688         while (*commptr == ' ' || *commptr == '+')
4689           *commptr++ = '\0';
4690
4691        /*
4692         * If we don't have a blank string, save it as another argument...
4693         */
4694
4695         if (*commptr)
4696         {
4697           argv[argc] = commptr;
4698           argc ++;
4699         }
4700         else
4701           break;
4702       }
4703       else if (*commptr == '%' && isxdigit(commptr[1] & 255) &&
4704                isxdigit(commptr[2] & 255))
4705       {
4706        /*
4707         * Convert the %xx notation to the individual character.
4708         */
4709
4710         if (commptr[1] >= '0' && commptr[1] <= '9')
4711           *commptr = (commptr[1] - '0') << 4;
4712         else
4713           *commptr = (tolower(commptr[1]) - 'a' + 10) << 4;
4714
4715         if (commptr[2] >= '0' && commptr[2] <= '9')
4716           *commptr |= commptr[2] - '0';
4717         else
4718           *commptr |= tolower(commptr[2]) - 'a' + 10;
4719
4720         _cups_strcpy(commptr + 1, commptr + 3);
4721
4722        /*
4723         * Check for a %00 and break if that is the case...
4724         */
4725
4726         if (!*commptr)
4727           break;
4728       }
4729     }
4730   }
4731
4732   argv[argc] = NULL;
4733
4734  /*
4735   * Setup the environment variables as needed...
4736   */
4737
4738   if (con->username[0])
4739   {
4740     snprintf(auth_type, sizeof(auth_type), "AUTH_TYPE=%s",
4741              httpGetField(HTTP(con), HTTP_FIELD_AUTHORIZATION));
4742
4743     if ((uriptr = strchr(auth_type + 10, ' ')) != NULL)
4744       *uriptr = '\0';
4745   }
4746   else
4747     auth_type[0] = '\0';
4748
4749   if (con->request &&
4750       (attr = ippFindAttribute(con->request, "attributes-natural-language",
4751                                IPP_TAG_LANGUAGE)) != NULL)
4752   {
4753     switch (strlen(attr->values[0].string.text))
4754     {
4755       default :
4756          /*
4757           * This is an unknown or badly formatted language code; use
4758           * the POSIX locale...
4759           */
4760
4761           strcpy(lang, "LANG=C");
4762           break;
4763
4764       case 2 :
4765          /*
4766           * Just the language code (ll)...
4767           */
4768
4769           snprintf(lang, sizeof(lang), "LANG=%s.UTF8",
4770                    attr->values[0].string.text);
4771           break;
4772
4773       case 5 :
4774          /*
4775           * Language and country code (ll-cc)...
4776           */
4777
4778           snprintf(lang, sizeof(lang), "LANG=%c%c_%c%c.UTF8",
4779                    attr->values[0].string.text[0],
4780                    attr->values[0].string.text[1],
4781                    toupper(attr->values[0].string.text[3] & 255),
4782                    toupper(attr->values[0].string.text[4] & 255));
4783           break;
4784     }
4785   }
4786   else if (con->language)
4787     snprintf(lang, sizeof(lang), "LANG=%s.UTF8", con->language->language);
4788   else
4789     strcpy(lang, "LANG=C");
4790
4791   strcpy(remote_addr, "REMOTE_ADDR=");
4792   httpAddrString(con->http.hostaddr, remote_addr + 12,
4793                  sizeof(remote_addr) - 12);
4794
4795   snprintf(remote_host, sizeof(remote_host), "REMOTE_HOST=%s",
4796            con->http.hostname);
4797
4798   snprintf(script_name, sizeof(script_name), "SCRIPT_NAME=%s", con->uri);
4799   if ((uriptr = strchr(script_name, '?')) != NULL)
4800     *uriptr = '\0';
4801
4802   snprintf(script_filename, sizeof(script_filename), "SCRIPT_FILENAME=%s%s",
4803            DocumentRoot, script_name + 12);
4804
4805   sprintf(server_port, "SERVER_PORT=%d", con->serverport);
4806
4807   if (con->http.fields[HTTP_FIELD_HOST][0])
4808   {
4809     char *nameptr;                      /* Pointer to ":port" */
4810
4811     snprintf(server_name, sizeof(server_name), "SERVER_NAME=%s",
4812              con->http.fields[HTTP_FIELD_HOST]);
4813     if ((nameptr = strrchr(server_name, ':')) != NULL && !strchr(nameptr, ']'))
4814       *nameptr = '\0';                  /* Strip trailing ":port" */
4815   }
4816   else
4817     snprintf(server_name, sizeof(server_name), "SERVER_NAME=%s",
4818              con->servername);
4819
4820   envc = cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
4821
4822   if (auth_type[0])
4823     envp[envc ++] = auth_type;
4824
4825   envp[envc ++] = lang;
4826   envp[envc ++] = "REDIRECT_STATUS=1";
4827   envp[envc ++] = "GATEWAY_INTERFACE=CGI/1.1";
4828   envp[envc ++] = server_name;
4829   envp[envc ++] = server_port;
4830   envp[envc ++] = remote_addr;
4831   envp[envc ++] = remote_host;
4832   envp[envc ++] = script_name;
4833   envp[envc ++] = script_filename;
4834
4835   if (path_info[0])
4836     envp[envc ++] = path_info;
4837
4838   if (con->username[0])
4839   {
4840     snprintf(remote_user, sizeof(remote_user), "REMOTE_USER=%s", con->username);
4841
4842     envp[envc ++] = remote_user;
4843   }
4844
4845   if (con->http.version == HTTP_1_1)
4846     envp[envc ++] = "SERVER_PROTOCOL=HTTP/1.1";
4847   else if (con->http.version == HTTP_1_0)
4848     envp[envc ++] = "SERVER_PROTOCOL=HTTP/1.0";
4849   else
4850     envp[envc ++] = "SERVER_PROTOCOL=HTTP/0.9";
4851
4852   if (con->http.cookie)
4853   {
4854     snprintf(http_cookie, sizeof(http_cookie), "HTTP_COOKIE=%s",
4855              con->http.cookie);
4856     envp[envc ++] = http_cookie;
4857   }
4858
4859   if (con->http.fields[HTTP_FIELD_USER_AGENT][0])
4860   {
4861     snprintf(http_user_agent, sizeof(http_user_agent), "HTTP_USER_AGENT=%s",
4862              con->http.fields[HTTP_FIELD_USER_AGENT]);
4863     envp[envc ++] = http_user_agent;
4864   }
4865
4866   if (con->http.fields[HTTP_FIELD_REFERER][0])
4867   {
4868     snprintf(http_referer, sizeof(http_referer), "HTTP_REFERER=%s",
4869              con->http.fields[HTTP_FIELD_REFERER]);
4870     envp[envc ++] = http_referer;
4871   }
4872
4873   if (con->operation == HTTP_GET)
4874   {
4875     envp[envc ++] = "REQUEST_METHOD=GET";
4876
4877     if (con->query_string)
4878     {
4879      /*
4880       * Add GET form variables after ?...
4881       */
4882
4883       envp[envc ++] = con->query_string;
4884     }
4885     else
4886       envp[envc ++] = "QUERY_STRING=";
4887   }
4888   else
4889   {
4890     sprintf(content_length, "CONTENT_LENGTH=" CUPS_LLFMT,
4891             CUPS_LLCAST con->bytes);
4892     snprintf(content_type, sizeof(content_type), "CONTENT_TYPE=%s",
4893              con->http.fields[HTTP_FIELD_CONTENT_TYPE]);
4894
4895     envp[envc ++] = "REQUEST_METHOD=POST";
4896     envp[envc ++] = content_length;
4897     envp[envc ++] = content_type;
4898   }
4899
4900  /*
4901   * Tell the CGI if we are using encryption...
4902   */
4903
4904   if (con->http.tls)
4905     envp[envc ++] = "HTTPS=ON";
4906
4907  /*
4908   * Terminate the environment array...
4909   */
4910
4911   envp[envc] = NULL;
4912
4913   if (LogLevel >= CUPSD_LOG_DEBUG)
4914   {
4915     for (i = 0; i < argc; i ++)
4916       cupsdLogMessage(CUPSD_LOG_DEBUG,
4917                       "[CGI] argv[%d] = \"%s\"", i, argv[i]);
4918     for (i = 0; i < envc; i ++)
4919       cupsdLogMessage(CUPSD_LOG_DEBUG,
4920                       "[CGI] envp[%d] = \"%s\"", i, envp[i]);
4921   }
4922
4923  /*
4924   * Create a pipe for the output...
4925   */
4926
4927   if (cupsdOpenPipe(fds))
4928   {
4929     cupsdLogMessage(CUPSD_LOG_ERROR, "[CGI] Unable to create pipe for %s - %s",
4930                     argv[0], strerror(errno));
4931     return (0);
4932   }
4933
4934  /*
4935   * Then execute the command...
4936   */
4937
4938   if (cupsdStartProcess(command, argv, envp, infile, fds[1], CGIPipes[1],
4939                         -1, -1, root, DefaultProfile, NULL, &pid) < 0)
4940   {
4941    /*
4942     * Error - can't fork!
4943     */
4944
4945     cupsdLogMessage(CUPSD_LOG_ERROR, "[CGI] Unable to start %s - %s", argv[0],
4946                     strerror(errno));
4947
4948     cupsdClosePipe(fds);
4949     pid = 0;
4950   }
4951   else
4952   {
4953    /*
4954     * Fork successful - return the PID...
4955     */
4956
4957     if (con->username[0])
4958       cupsdAddCert(pid, con->username, ccache);
4959
4960     cupsdLogMessage(CUPSD_LOG_DEBUG, "[CGI] Started %s (PID %d)", command, pid);
4961
4962     *outfile = fds[0];
4963     close(fds[1]);
4964   }
4965
4966   return (pid);
4967 }
4968
4969
4970 /*
4971  * 'valid_host()' - Is the Host: field valid?
4972  */
4973
4974 static int                              /* O - 1 if valid, 0 if not */
4975 valid_host(cupsd_client_t *con)         /* I - Client connection */
4976 {
4977   cupsd_alias_t *a;                     /* Current alias */
4978   cupsd_netif_t *netif;                 /* Current network interface */
4979   const char    *host,                  /* Host field */
4980                 *end;                   /* End character */
4981
4982
4983   host = con->http.fields[HTTP_FIELD_HOST];
4984
4985   if (httpAddrLocalhost(con->http.hostaddr))
4986   {
4987    /*
4988     * Only allow "localhost" or the equivalent IPv4 or IPv6 numerical
4989     * addresses when accessing CUPS via the loopback interface...
4990     */
4991
4992     return (!_cups_strcasecmp(host, "localhost") ||
4993             !_cups_strncasecmp(host, "localhost:", 10) ||
4994             !_cups_strcasecmp(host, "localhost.") ||
4995             !_cups_strncasecmp(host, "localhost.:", 11) ||
4996 #ifdef __linux
4997             !_cups_strcasecmp(host, "localhost.localdomain") ||
4998             !_cups_strncasecmp(host, "localhost.localdomain:", 22) ||
4999 #endif /* __linux */
5000             !strcmp(host, "127.0.0.1") ||
5001             !strncmp(host, "127.0.0.1:", 10) ||
5002             !strcmp(host, "[::1]") ||
5003             !strncmp(host, "[::1]:", 6));
5004   }
5005
5006 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
5007  /*
5008   * Check if the hostname is something.local (Bonjour); if so, allow it.
5009   */
5010
5011   if ((end = strrchr(host, '.')) != NULL &&
5012       (!_cups_strcasecmp(end, ".local") || !_cups_strncasecmp(end, ".local:", 7) ||
5013        !_cups_strcasecmp(end, ".local.") || !_cups_strncasecmp(end, ".local.:", 8)))
5014     return (1);
5015 #endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
5016
5017  /*
5018   * Check if the hostname is an IP address...
5019   */
5020
5021   if (isdigit(*host & 255) || *host == '[')
5022   {
5023    /*
5024     * Possible IPv4/IPv6 address...
5025     */
5026
5027     char        temp[1024],             /* Temporary string */
5028                 *ptr;                   /* Pointer into temporary string */
5029     http_addrlist_t *addrlist;          /* List of addresses */
5030
5031
5032     strlcpy(temp, host, sizeof(temp));
5033     if ((ptr = strrchr(temp, ':')) != NULL && !strchr(ptr, ']'))
5034       *ptr = '\0';                      /* Strip :port from host value */
5035
5036     if ((addrlist = httpAddrGetList(temp, AF_UNSPEC, NULL)) != NULL)
5037     {
5038      /*
5039       * Good IPv4/IPv6 address...
5040       */
5041
5042       httpAddrFreeList(addrlist);
5043       return (1);
5044     }
5045   }
5046
5047  /*
5048   * Check for (alias) name matches...
5049   */
5050
5051   for (a = (cupsd_alias_t *)cupsArrayFirst(ServerAlias);
5052        a;
5053        a = (cupsd_alias_t *)cupsArrayNext(ServerAlias))
5054   {
5055    /*
5056     * "ServerAlias *" allows all host values through...
5057     */
5058
5059     if (!strcmp(a->name, "*"))
5060       return (1);
5061
5062     if (!_cups_strncasecmp(host, a->name, a->namelen))
5063     {
5064      /*
5065       * Prefix matches; check the character at the end - it must be ":", ".",
5066       * ".:", or nul...
5067       */
5068
5069       end = host + a->namelen;
5070
5071       if (!*end || *end == ':' || (*end == '.' && (!end[1] || end[1] == ':')))
5072         return (1);
5073     }
5074   }
5075
5076 #ifdef HAVE_DNSSD
5077   for (a = (cupsd_alias_t *)cupsArrayFirst(DNSSDAlias);
5078        a;
5079        a = (cupsd_alias_t *)cupsArrayNext(DNSSDAlias))
5080   {
5081    /*
5082     * "ServerAlias *" allows all host values through...
5083     */
5084
5085     if (!strcmp(a->name, "*"))
5086       return (1);
5087
5088     if (!_cups_strncasecmp(host, a->name, a->namelen))
5089     {
5090      /*
5091       * Prefix matches; check the character at the end - it must be ":", ".",
5092       * ".:", or nul...
5093       */
5094
5095       end = host + a->namelen;
5096
5097       if (!*end || *end == ':' || (*end == '.' && (!end[1] || end[1] == ':')))
5098         return (1);
5099     }
5100   }
5101 #endif /* HAVE_DNSSD */
5102
5103  /*
5104   * Check for interface hostname matches...
5105   */
5106
5107   for (netif = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
5108        netif;
5109        netif = (cupsd_netif_t *)cupsArrayNext(NetIFList))
5110   {
5111     if (!_cups_strncasecmp(host, netif->hostname, netif->hostlen))
5112     {
5113      /*
5114       * Prefix matches; check the character at the end - it must be ":", ".",
5115       * ".:", or nul...
5116       */
5117
5118       end = host + netif->hostlen;
5119
5120       if (!*end || *end == ':' || (*end == '.' && (!end[1] || end[1] == ':')))
5121         return (1);
5122     }
5123   }
5124
5125   return (0);
5126 }
5127
5128
5129 /*
5130  * 'write_file()' - Send a file via HTTP.
5131  */
5132
5133 static int                              /* O - 0 on failure, 1 on success */
5134 write_file(cupsd_client_t *con,         /* I - Client connection */
5135            http_status_t  code,         /* I - HTTP status */
5136            char           *filename,    /* I - Filename */
5137            char           *type,        /* I - File type */
5138            struct stat    *filestats)   /* O - File information */
5139 {
5140   con->file = open(filename, O_RDONLY);
5141
5142   cupsdLogMessage(CUPSD_LOG_DEBUG2,
5143                   "write_file(con=%p(%d), code=%d, filename=\"%s\" (%d), "
5144                   "type=\"%s\", filestats=%p)", con, con->http.fd,
5145                   code, filename, con->file, type ? type : "(null)", filestats);
5146
5147   if (con->file < 0)
5148     return (0);
5149
5150   fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
5151
5152   con->pipe_pid = 0;
5153
5154   if (!cupsdSendHeader(con, code, type, CUPSD_AUTH_NONE))
5155     return (0);
5156
5157   if (httpPrintf(HTTP(con), "Last-Modified: %s\r\n",
5158                  httpGetDateString(filestats->st_mtime)) < 0)
5159     return (0);
5160   if (httpPrintf(HTTP(con), "Content-Length: " CUPS_LLFMT "\r\n",
5161                  CUPS_LLCAST filestats->st_size) < 0)
5162     return (0);
5163   if (httpPrintf(HTTP(con), "\r\n") < 0)
5164     return (0);
5165
5166   if (cupsdFlushHeader(con) < 0)
5167     return (0);
5168
5169   con->http.data_encoding  = HTTP_ENCODE_LENGTH;
5170   con->http.data_remaining = filestats->st_size;
5171
5172   if (con->http.data_remaining <= INT_MAX)
5173     con->http._data_remaining = con->http.data_remaining;
5174   else
5175     con->http._data_remaining = INT_MAX;
5176
5177   cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient,
5178                  (cupsd_selfunc_t)cupsdWriteClient, con);
5179
5180   return (1);
5181 }
5182
5183
5184 /*
5185  * 'write_pipe()' - Flag that data is available on the CGI pipe.
5186  */
5187
5188 static void
5189 write_pipe(cupsd_client_t *con)         /* I - Client connection */
5190 {
5191   cupsdLogMessage(CUPSD_LOG_DEBUG2,
5192                   "write_pipe(con=%p(%d)) CGI output on fd %d",
5193                   con, con->http.fd, con->file);
5194
5195   con->file_ready = 1;
5196
5197   cupsdRemoveSelect(con->file);
5198   cupsdAddSelect(con->http.fd, NULL, (cupsd_selfunc_t)cupsdWriteClient, con);
5199 }
5200
5201
5202 /*
5203  * End of "$Id: client.c 10338 2012-03-07 06:05:39Z mike $".
5204  */