xref: /aosp_15_r20/external/libcups/scheduler/client.c (revision 5e7646d21f1134fb0638875d812ef646c12ab91e)
1*5e7646d2SAndroid Build Coastguard Worker /*
2*5e7646d2SAndroid Build Coastguard Worker  * Client routines for the CUPS scheduler.
3*5e7646d2SAndroid Build Coastguard Worker  *
4*5e7646d2SAndroid Build Coastguard Worker  * Copyright © 2021 by OpenPrinting.
5*5e7646d2SAndroid Build Coastguard Worker  * Copyright © 2007-2021 by Apple Inc.
6*5e7646d2SAndroid Build Coastguard Worker  * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
7*5e7646d2SAndroid Build Coastguard Worker  *
8*5e7646d2SAndroid Build Coastguard Worker  * This file contains Kerberos support code, copyright 2006 by
9*5e7646d2SAndroid Build Coastguard Worker  * Jelmer Vernooij.
10*5e7646d2SAndroid Build Coastguard Worker  *
11*5e7646d2SAndroid Build Coastguard Worker  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
12*5e7646d2SAndroid Build Coastguard Worker  * information.
13*5e7646d2SAndroid Build Coastguard Worker  */
14*5e7646d2SAndroid Build Coastguard Worker 
15*5e7646d2SAndroid Build Coastguard Worker /*
16*5e7646d2SAndroid Build Coastguard Worker  * Include necessary headers...
17*5e7646d2SAndroid Build Coastguard Worker  */
18*5e7646d2SAndroid Build Coastguard Worker 
19*5e7646d2SAndroid Build Coastguard Worker #define _CUPS_NO_DEPRECATED
20*5e7646d2SAndroid Build Coastguard Worker #define _HTTP_NO_PRIVATE
21*5e7646d2SAndroid Build Coastguard Worker #include "cupsd.h"
22*5e7646d2SAndroid Build Coastguard Worker 
23*5e7646d2SAndroid Build Coastguard Worker #ifdef __APPLE__
24*5e7646d2SAndroid Build Coastguard Worker #  include <libproc.h>
25*5e7646d2SAndroid Build Coastguard Worker #endif /* __APPLE__ */
26*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_TCPD_H
27*5e7646d2SAndroid Build Coastguard Worker #  include <tcpd.h>
28*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_TCPD_H */
29*5e7646d2SAndroid Build Coastguard Worker 
30*5e7646d2SAndroid Build Coastguard Worker 
31*5e7646d2SAndroid Build Coastguard Worker /*
32*5e7646d2SAndroid Build Coastguard Worker  * Local functions...
33*5e7646d2SAndroid Build Coastguard Worker  */
34*5e7646d2SAndroid Build Coastguard Worker 
35*5e7646d2SAndroid Build Coastguard Worker static int		check_if_modified(cupsd_client_t *con,
36*5e7646d2SAndroid Build Coastguard Worker 			                  struct stat *filestats);
37*5e7646d2SAndroid Build Coastguard Worker static int		compare_clients(cupsd_client_t *a, cupsd_client_t *b,
38*5e7646d2SAndroid Build Coastguard Worker 			                void *data);
39*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_SSL
40*5e7646d2SAndroid Build Coastguard Worker static int		cupsd_start_tls(cupsd_client_t *con, http_encryption_t e);
41*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_SSL */
42*5e7646d2SAndroid Build Coastguard Worker static char		*get_file(cupsd_client_t *con, struct stat *filestats,
43*5e7646d2SAndroid Build Coastguard Worker 			          char *filename, size_t len);
44*5e7646d2SAndroid Build Coastguard Worker static http_status_t	install_cupsd_conf(cupsd_client_t *con);
45*5e7646d2SAndroid Build Coastguard Worker static int		is_cgi(cupsd_client_t *con, const char *filename,
46*5e7646d2SAndroid Build Coastguard Worker 		               struct stat *filestats, mime_type_t *type);
47*5e7646d2SAndroid Build Coastguard Worker static int		is_path_absolute(const char *path);
48*5e7646d2SAndroid Build Coastguard Worker static int		pipe_command(cupsd_client_t *con, int infile, int *outfile,
49*5e7646d2SAndroid Build Coastguard Worker 			             char *command, char *options, int root);
50*5e7646d2SAndroid Build Coastguard Worker static int		valid_host(cupsd_client_t *con);
51*5e7646d2SAndroid Build Coastguard Worker static int		write_file(cupsd_client_t *con, http_status_t code,
52*5e7646d2SAndroid Build Coastguard Worker 		        	   char *filename, char *type,
53*5e7646d2SAndroid Build Coastguard Worker 				   struct stat *filestats);
54*5e7646d2SAndroid Build Coastguard Worker static void		write_pipe(cupsd_client_t *con);
55*5e7646d2SAndroid Build Coastguard Worker 
56*5e7646d2SAndroid Build Coastguard Worker 
57*5e7646d2SAndroid Build Coastguard Worker /*
58*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdAcceptClient()' - Accept a new client.
59*5e7646d2SAndroid Build Coastguard Worker  */
60*5e7646d2SAndroid Build Coastguard Worker 
61*5e7646d2SAndroid Build Coastguard Worker void
cupsdAcceptClient(cupsd_listener_t * lis)62*5e7646d2SAndroid Build Coastguard Worker cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */
63*5e7646d2SAndroid Build Coastguard Worker {
64*5e7646d2SAndroid Build Coastguard Worker   const char		*hostname;	/* Hostname of client */
65*5e7646d2SAndroid Build Coastguard Worker   char			name[256];	/* Hostname of client */
66*5e7646d2SAndroid Build Coastguard Worker   int			count;		/* Count of connections on a host */
67*5e7646d2SAndroid Build Coastguard Worker   cupsd_client_t	*con,		/* New client pointer */
68*5e7646d2SAndroid Build Coastguard Worker 			*tempcon;	/* Temporary client pointer */
69*5e7646d2SAndroid Build Coastguard Worker   socklen_t		addrlen;	/* Length of address */
70*5e7646d2SAndroid Build Coastguard Worker   http_addr_t		temp;		/* Temporary address variable */
71*5e7646d2SAndroid Build Coastguard Worker   static time_t		last_dos = 0;	/* Time of last DoS attack */
72*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_TCPD_H
73*5e7646d2SAndroid Build Coastguard Worker   struct request_info	wrap_req;	/* TCP wrappers request information */
74*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_TCPD_H */
75*5e7646d2SAndroid Build Coastguard Worker 
76*5e7646d2SAndroid Build Coastguard Worker 
77*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAcceptClient(lis=%p(%d)) Clients=%d", lis, lis->fd, cupsArrayCount(Clients));
78*5e7646d2SAndroid Build Coastguard Worker 
79*5e7646d2SAndroid Build Coastguard Worker  /*
80*5e7646d2SAndroid Build Coastguard Worker   * Make sure we don't have a full set of clients already...
81*5e7646d2SAndroid Build Coastguard Worker   */
82*5e7646d2SAndroid Build Coastguard Worker 
83*5e7646d2SAndroid Build Coastguard Worker   if (cupsArrayCount(Clients) == MaxClients)
84*5e7646d2SAndroid Build Coastguard Worker     return;
85*5e7646d2SAndroid Build Coastguard Worker 
86*5e7646d2SAndroid Build Coastguard Worker   cupsdSetBusyState(1);
87*5e7646d2SAndroid Build Coastguard Worker 
88*5e7646d2SAndroid Build Coastguard Worker  /*
89*5e7646d2SAndroid Build Coastguard Worker   * Get a pointer to the next available client...
90*5e7646d2SAndroid Build Coastguard Worker   */
91*5e7646d2SAndroid Build Coastguard Worker 
92*5e7646d2SAndroid Build Coastguard Worker   if (!Clients)
93*5e7646d2SAndroid Build Coastguard Worker     Clients = cupsArrayNew(NULL, NULL);
94*5e7646d2SAndroid Build Coastguard Worker 
95*5e7646d2SAndroid Build Coastguard Worker   if (!Clients)
96*5e7646d2SAndroid Build Coastguard Worker   {
97*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_ERROR,
98*5e7646d2SAndroid Build Coastguard Worker                     "Unable to allocate memory for clients array!");
99*5e7646d2SAndroid Build Coastguard Worker     cupsdPauseListening();
100*5e7646d2SAndroid Build Coastguard Worker     return;
101*5e7646d2SAndroid Build Coastguard Worker   }
102*5e7646d2SAndroid Build Coastguard Worker 
103*5e7646d2SAndroid Build Coastguard Worker   if (!ActiveClients)
104*5e7646d2SAndroid Build Coastguard Worker     ActiveClients = cupsArrayNew((cups_array_func_t)compare_clients, NULL);
105*5e7646d2SAndroid Build Coastguard Worker 
106*5e7646d2SAndroid Build Coastguard Worker   if (!ActiveClients)
107*5e7646d2SAndroid Build Coastguard Worker   {
108*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_ERROR,
109*5e7646d2SAndroid Build Coastguard Worker                     "Unable to allocate memory for active clients array!");
110*5e7646d2SAndroid Build Coastguard Worker     cupsdPauseListening();
111*5e7646d2SAndroid Build Coastguard Worker     return;
112*5e7646d2SAndroid Build Coastguard Worker   }
113*5e7646d2SAndroid Build Coastguard Worker 
114*5e7646d2SAndroid Build Coastguard Worker   if ((con = calloc(1, sizeof(cupsd_client_t))) == NULL)
115*5e7646d2SAndroid Build Coastguard Worker   {
116*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to allocate memory for client!");
117*5e7646d2SAndroid Build Coastguard Worker     cupsdPauseListening();
118*5e7646d2SAndroid Build Coastguard Worker     return;
119*5e7646d2SAndroid Build Coastguard Worker   }
120*5e7646d2SAndroid Build Coastguard Worker 
121*5e7646d2SAndroid Build Coastguard Worker  /*
122*5e7646d2SAndroid Build Coastguard Worker   * Accept the client and get the remote address...
123*5e7646d2SAndroid Build Coastguard Worker   */
124*5e7646d2SAndroid Build Coastguard Worker 
125*5e7646d2SAndroid Build Coastguard Worker   con->number = ++ LastClientNumber;
126*5e7646d2SAndroid Build Coastguard Worker   con->file   = -1;
127*5e7646d2SAndroid Build Coastguard Worker 
128*5e7646d2SAndroid Build Coastguard Worker   if ((con->http = httpAcceptConnection(lis->fd, 0)) == NULL)
129*5e7646d2SAndroid Build Coastguard Worker   {
130*5e7646d2SAndroid Build Coastguard Worker     if (errno == ENFILE || errno == EMFILE)
131*5e7646d2SAndroid Build Coastguard Worker       cupsdPauseListening();
132*5e7646d2SAndroid Build Coastguard Worker 
133*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to accept client connection - %s.",
134*5e7646d2SAndroid Build Coastguard Worker                     strerror(errno));
135*5e7646d2SAndroid Build Coastguard Worker     free(con);
136*5e7646d2SAndroid Build Coastguard Worker 
137*5e7646d2SAndroid Build Coastguard Worker     return;
138*5e7646d2SAndroid Build Coastguard Worker   }
139*5e7646d2SAndroid Build Coastguard Worker 
140*5e7646d2SAndroid Build Coastguard Worker  /*
141*5e7646d2SAndroid Build Coastguard Worker   * Save the connected address and port number...
142*5e7646d2SAndroid Build Coastguard Worker   */
143*5e7646d2SAndroid Build Coastguard Worker 
144*5e7646d2SAndroid Build Coastguard Worker   addrlen = sizeof(con->clientaddr);
145*5e7646d2SAndroid Build Coastguard Worker 
146*5e7646d2SAndroid Build Coastguard Worker   if (getsockname(httpGetFd(con->http), (struct sockaddr *)&con->clientaddr, &addrlen) || addrlen == 0)
147*5e7646d2SAndroid Build Coastguard Worker     con->clientaddr = lis->address;
148*5e7646d2SAndroid Build Coastguard Worker 
149*5e7646d2SAndroid Build Coastguard Worker   cupsdLogClient(con, CUPSD_LOG_DEBUG, "Server address is \"%s\".", httpAddrString(&con->clientaddr, name, sizeof(name)));
150*5e7646d2SAndroid Build Coastguard Worker 
151*5e7646d2SAndroid Build Coastguard Worker  /*
152*5e7646d2SAndroid Build Coastguard Worker   * Check the number of clients on the same address...
153*5e7646d2SAndroid Build Coastguard Worker   */
154*5e7646d2SAndroid Build Coastguard Worker 
155*5e7646d2SAndroid Build Coastguard Worker   for (count = 0, tempcon = (cupsd_client_t *)cupsArrayFirst(Clients);
156*5e7646d2SAndroid Build Coastguard Worker        tempcon;
157*5e7646d2SAndroid Build Coastguard Worker        tempcon = (cupsd_client_t *)cupsArrayNext(Clients))
158*5e7646d2SAndroid Build Coastguard Worker     if (httpAddrEqual(httpGetAddress(tempcon->http), httpGetAddress(con->http)))
159*5e7646d2SAndroid Build Coastguard Worker     {
160*5e7646d2SAndroid Build Coastguard Worker       count ++;
161*5e7646d2SAndroid Build Coastguard Worker       if (count >= MaxClientsPerHost)
162*5e7646d2SAndroid Build Coastguard Worker 	break;
163*5e7646d2SAndroid Build Coastguard Worker     }
164*5e7646d2SAndroid Build Coastguard Worker 
165*5e7646d2SAndroid Build Coastguard Worker   if (count >= MaxClientsPerHost)
166*5e7646d2SAndroid Build Coastguard Worker   {
167*5e7646d2SAndroid Build Coastguard Worker     if ((time(NULL) - last_dos) >= 60)
168*5e7646d2SAndroid Build Coastguard Worker     {
169*5e7646d2SAndroid Build Coastguard Worker       last_dos = time(NULL);
170*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_WARN,
171*5e7646d2SAndroid Build Coastguard Worker                       "Possible DoS attack - more than %d clients connecting "
172*5e7646d2SAndroid Build Coastguard Worker 		      "from %s.",
173*5e7646d2SAndroid Build Coastguard Worker 	              MaxClientsPerHost,
174*5e7646d2SAndroid Build Coastguard Worker 		      httpGetHostname(con->http, name, sizeof(name)));
175*5e7646d2SAndroid Build Coastguard Worker     }
176*5e7646d2SAndroid Build Coastguard Worker 
177*5e7646d2SAndroid Build Coastguard Worker     httpClose(con->http);
178*5e7646d2SAndroid Build Coastguard Worker     free(con);
179*5e7646d2SAndroid Build Coastguard Worker     return;
180*5e7646d2SAndroid Build Coastguard Worker   }
181*5e7646d2SAndroid Build Coastguard Worker 
182*5e7646d2SAndroid Build Coastguard Worker  /*
183*5e7646d2SAndroid Build Coastguard Worker   * Get the hostname or format the IP address as needed...
184*5e7646d2SAndroid Build Coastguard Worker   */
185*5e7646d2SAndroid Build Coastguard Worker 
186*5e7646d2SAndroid Build Coastguard Worker   if (HostNameLookups)
187*5e7646d2SAndroid Build Coastguard Worker     hostname = httpResolveHostname(con->http, NULL, 0);
188*5e7646d2SAndroid Build Coastguard Worker   else
189*5e7646d2SAndroid Build Coastguard Worker     hostname = httpGetHostname(con->http, NULL, 0);
190*5e7646d2SAndroid Build Coastguard Worker 
191*5e7646d2SAndroid Build Coastguard Worker   if (hostname == NULL && HostNameLookups == 2)
192*5e7646d2SAndroid Build Coastguard Worker   {
193*5e7646d2SAndroid Build Coastguard Worker    /*
194*5e7646d2SAndroid Build Coastguard Worker     * Can't have an unresolved IP address with double-lookups enabled...
195*5e7646d2SAndroid Build Coastguard Worker     */
196*5e7646d2SAndroid Build Coastguard Worker 
197*5e7646d2SAndroid Build Coastguard Worker     httpClose(con->http);
198*5e7646d2SAndroid Build Coastguard Worker 
199*5e7646d2SAndroid Build Coastguard Worker     cupsdLogClient(con, CUPSD_LOG_WARN,
200*5e7646d2SAndroid Build Coastguard Worker                     "Name lookup failed - connection from %s closed!",
201*5e7646d2SAndroid Build Coastguard Worker                     httpGetHostname(con->http, NULL, 0));
202*5e7646d2SAndroid Build Coastguard Worker 
203*5e7646d2SAndroid Build Coastguard Worker     free(con);
204*5e7646d2SAndroid Build Coastguard Worker     return;
205*5e7646d2SAndroid Build Coastguard Worker   }
206*5e7646d2SAndroid Build Coastguard Worker 
207*5e7646d2SAndroid Build Coastguard Worker   if (HostNameLookups == 2)
208*5e7646d2SAndroid Build Coastguard Worker   {
209*5e7646d2SAndroid Build Coastguard Worker    /*
210*5e7646d2SAndroid Build Coastguard Worker     * Do double lookups as needed...
211*5e7646d2SAndroid Build Coastguard Worker     */
212*5e7646d2SAndroid Build Coastguard Worker 
213*5e7646d2SAndroid Build Coastguard Worker     http_addrlist_t	*addrlist,	/* List of addresses */
214*5e7646d2SAndroid Build Coastguard Worker 			*addr;		/* Current address */
215*5e7646d2SAndroid Build Coastguard Worker 
216*5e7646d2SAndroid Build Coastguard Worker     if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, NULL)) != NULL)
217*5e7646d2SAndroid Build Coastguard Worker     {
218*5e7646d2SAndroid Build Coastguard Worker      /*
219*5e7646d2SAndroid Build Coastguard Worker       * See if the hostname maps to the same IP address...
220*5e7646d2SAndroid Build Coastguard Worker       */
221*5e7646d2SAndroid Build Coastguard Worker 
222*5e7646d2SAndroid Build Coastguard Worker       for (addr = addrlist; addr; addr = addr->next)
223*5e7646d2SAndroid Build Coastguard Worker         if (httpAddrEqual(httpGetAddress(con->http), &(addr->addr)))
224*5e7646d2SAndroid Build Coastguard Worker           break;
225*5e7646d2SAndroid Build Coastguard Worker     }
226*5e7646d2SAndroid Build Coastguard Worker     else
227*5e7646d2SAndroid Build Coastguard Worker       addr = NULL;
228*5e7646d2SAndroid Build Coastguard Worker 
229*5e7646d2SAndroid Build Coastguard Worker     httpAddrFreeList(addrlist);
230*5e7646d2SAndroid Build Coastguard Worker 
231*5e7646d2SAndroid Build Coastguard Worker     if (!addr)
232*5e7646d2SAndroid Build Coastguard Worker     {
233*5e7646d2SAndroid Build Coastguard Worker      /*
234*5e7646d2SAndroid Build Coastguard Worker       * Can't have a hostname that doesn't resolve to the same IP address
235*5e7646d2SAndroid Build Coastguard Worker       * with double-lookups enabled...
236*5e7646d2SAndroid Build Coastguard Worker       */
237*5e7646d2SAndroid Build Coastguard Worker 
238*5e7646d2SAndroid Build Coastguard Worker       httpClose(con->http);
239*5e7646d2SAndroid Build Coastguard Worker 
240*5e7646d2SAndroid Build Coastguard Worker       cupsdLogClient(con, CUPSD_LOG_WARN,
241*5e7646d2SAndroid Build Coastguard Worker                       "IP lookup failed - connection from %s closed!",
242*5e7646d2SAndroid Build Coastguard Worker                       httpGetHostname(con->http, NULL, 0));
243*5e7646d2SAndroid Build Coastguard Worker       free(con);
244*5e7646d2SAndroid Build Coastguard Worker       return;
245*5e7646d2SAndroid Build Coastguard Worker     }
246*5e7646d2SAndroid Build Coastguard Worker   }
247*5e7646d2SAndroid Build Coastguard Worker 
248*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_TCPD_H
249*5e7646d2SAndroid Build Coastguard Worker  /*
250*5e7646d2SAndroid Build Coastguard Worker   * See if the connection is denied by TCP wrappers...
251*5e7646d2SAndroid Build Coastguard Worker   */
252*5e7646d2SAndroid Build Coastguard Worker 
253*5e7646d2SAndroid Build Coastguard Worker   request_init(&wrap_req, RQ_DAEMON, "cupsd", RQ_FILE, httpGetFd(con->http),
254*5e7646d2SAndroid Build Coastguard Worker                NULL);
255*5e7646d2SAndroid Build Coastguard Worker   fromhost(&wrap_req);
256*5e7646d2SAndroid Build Coastguard Worker 
257*5e7646d2SAndroid Build Coastguard Worker   if (!hosts_access(&wrap_req))
258*5e7646d2SAndroid Build Coastguard Worker   {
259*5e7646d2SAndroid Build Coastguard Worker     httpClose(con->http);
260*5e7646d2SAndroid Build Coastguard Worker 
261*5e7646d2SAndroid Build Coastguard Worker     cupsdLogClient(con, CUPSD_LOG_WARN,
262*5e7646d2SAndroid Build Coastguard Worker                     "Connection from %s refused by /etc/hosts.allow and "
263*5e7646d2SAndroid Build Coastguard Worker 		    "/etc/hosts.deny rules.", httpGetHostname(con->http, NULL, 0));
264*5e7646d2SAndroid Build Coastguard Worker     free(con);
265*5e7646d2SAndroid Build Coastguard Worker     return;
266*5e7646d2SAndroid Build Coastguard Worker   }
267*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_TCPD_H */
268*5e7646d2SAndroid Build Coastguard Worker 
269*5e7646d2SAndroid Build Coastguard Worker #ifdef AF_LOCAL
270*5e7646d2SAndroid Build Coastguard Worker   if (httpAddrFamily(httpGetAddress(con->http)) == AF_LOCAL)
271*5e7646d2SAndroid Build Coastguard Worker   {
272*5e7646d2SAndroid Build Coastguard Worker #  ifdef __APPLE__
273*5e7646d2SAndroid Build Coastguard Worker     socklen_t	peersize;		/* Size of peer credentials */
274*5e7646d2SAndroid Build Coastguard Worker     pid_t	peerpid;		/* Peer process ID */
275*5e7646d2SAndroid Build Coastguard Worker     char	peername[256];		/* Name of process */
276*5e7646d2SAndroid Build Coastguard Worker 
277*5e7646d2SAndroid Build Coastguard Worker     peersize = sizeof(peerpid);
278*5e7646d2SAndroid Build Coastguard Worker     if (!getsockopt(httpGetFd(con->http), SOL_LOCAL, LOCAL_PEERPID, &peerpid,
279*5e7646d2SAndroid Build Coastguard Worker                     &peersize))
280*5e7646d2SAndroid Build Coastguard Worker     {
281*5e7646d2SAndroid Build Coastguard Worker       if (!proc_name((int)peerpid, peername, sizeof(peername)))
282*5e7646d2SAndroid Build Coastguard Worker 	cupsdLogClient(con, CUPSD_LOG_DEBUG,
283*5e7646d2SAndroid Build Coastguard Worker 	               "Accepted from %s (Domain ???[%d])",
284*5e7646d2SAndroid Build Coastguard Worker                        httpGetHostname(con->http, NULL, 0), (int)peerpid);
285*5e7646d2SAndroid Build Coastguard Worker       else
286*5e7646d2SAndroid Build Coastguard Worker 	cupsdLogClient(con, CUPSD_LOG_DEBUG,
287*5e7646d2SAndroid Build Coastguard Worker                        "Accepted from %s (Domain %s[%d])",
288*5e7646d2SAndroid Build Coastguard Worker                        httpGetHostname(con->http, NULL, 0), peername, (int)peerpid);
289*5e7646d2SAndroid Build Coastguard Worker     }
290*5e7646d2SAndroid Build Coastguard Worker     else
291*5e7646d2SAndroid Build Coastguard Worker #  endif /* __APPLE__ */
292*5e7646d2SAndroid Build Coastguard Worker 
293*5e7646d2SAndroid Build Coastguard Worker     cupsdLogClient(con, CUPSD_LOG_DEBUG, "Accepted from %s (Domain)",
294*5e7646d2SAndroid Build Coastguard Worker                    httpGetHostname(con->http, NULL, 0));
295*5e7646d2SAndroid Build Coastguard Worker   }
296*5e7646d2SAndroid Build Coastguard Worker   else
297*5e7646d2SAndroid Build Coastguard Worker #endif /* AF_LOCAL */
298*5e7646d2SAndroid Build Coastguard Worker   cupsdLogClient(con, CUPSD_LOG_DEBUG, "Accepted from %s:%d (IPv%d)",
299*5e7646d2SAndroid Build Coastguard Worker                  httpGetHostname(con->http, NULL, 0),
300*5e7646d2SAndroid Build Coastguard Worker 		 httpAddrPort(httpGetAddress(con->http)),
301*5e7646d2SAndroid Build Coastguard Worker 		 httpAddrFamily(httpGetAddress(con->http)) == AF_INET ? 4 : 6);
302*5e7646d2SAndroid Build Coastguard Worker 
303*5e7646d2SAndroid Build Coastguard Worker  /*
304*5e7646d2SAndroid Build Coastguard Worker   * Get the local address the client connected to...
305*5e7646d2SAndroid Build Coastguard Worker   */
306*5e7646d2SAndroid Build Coastguard Worker 
307*5e7646d2SAndroid Build Coastguard Worker   addrlen = sizeof(temp);
308*5e7646d2SAndroid Build Coastguard Worker   if (getsockname(httpGetFd(con->http), (struct sockaddr *)&temp, &addrlen))
309*5e7646d2SAndroid Build Coastguard Worker   {
310*5e7646d2SAndroid Build Coastguard Worker     cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to get local address - %s",
311*5e7646d2SAndroid Build Coastguard Worker                    strerror(errno));
312*5e7646d2SAndroid Build Coastguard Worker 
313*5e7646d2SAndroid Build Coastguard Worker     strlcpy(con->servername, "localhost", sizeof(con->servername));
314*5e7646d2SAndroid Build Coastguard Worker     con->serverport = LocalPort;
315*5e7646d2SAndroid Build Coastguard Worker   }
316*5e7646d2SAndroid Build Coastguard Worker #ifdef AF_LOCAL
317*5e7646d2SAndroid Build Coastguard Worker   else if (httpAddrFamily(&temp) == AF_LOCAL)
318*5e7646d2SAndroid Build Coastguard Worker   {
319*5e7646d2SAndroid Build Coastguard Worker     strlcpy(con->servername, "localhost", sizeof(con->servername));
320*5e7646d2SAndroid Build Coastguard Worker     con->serverport = LocalPort;
321*5e7646d2SAndroid Build Coastguard Worker   }
322*5e7646d2SAndroid Build Coastguard Worker #endif /* AF_LOCAL */
323*5e7646d2SAndroid Build Coastguard Worker   else
324*5e7646d2SAndroid Build Coastguard Worker   {
325*5e7646d2SAndroid Build Coastguard Worker     if (httpAddrLocalhost(&temp))
326*5e7646d2SAndroid Build Coastguard Worker       strlcpy(con->servername, "localhost", sizeof(con->servername));
327*5e7646d2SAndroid Build Coastguard Worker     else if (HostNameLookups)
328*5e7646d2SAndroid Build Coastguard Worker       httpAddrLookup(&temp, con->servername, sizeof(con->servername));
329*5e7646d2SAndroid Build Coastguard Worker     else
330*5e7646d2SAndroid Build Coastguard Worker       httpAddrString(&temp, con->servername, sizeof(con->servername));
331*5e7646d2SAndroid Build Coastguard Worker 
332*5e7646d2SAndroid Build Coastguard Worker     con->serverport = httpAddrPort(&(lis->address));
333*5e7646d2SAndroid Build Coastguard Worker   }
334*5e7646d2SAndroid Build Coastguard Worker 
335*5e7646d2SAndroid Build Coastguard Worker  /*
336*5e7646d2SAndroid Build Coastguard Worker   * Add the connection to the array of active clients...
337*5e7646d2SAndroid Build Coastguard Worker   */
338*5e7646d2SAndroid Build Coastguard Worker 
339*5e7646d2SAndroid Build Coastguard Worker   cupsArrayAdd(Clients, con);
340*5e7646d2SAndroid Build Coastguard Worker 
341*5e7646d2SAndroid Build Coastguard Worker  /*
342*5e7646d2SAndroid Build Coastguard Worker   * Add the socket to the server select.
343*5e7646d2SAndroid Build Coastguard Worker   */
344*5e7646d2SAndroid Build Coastguard Worker 
345*5e7646d2SAndroid Build Coastguard Worker   cupsdAddSelect(httpGetFd(con->http), (cupsd_selfunc_t)cupsdReadClient, NULL,
346*5e7646d2SAndroid Build Coastguard Worker                  con);
347*5e7646d2SAndroid Build Coastguard Worker 
348*5e7646d2SAndroid Build Coastguard Worker   cupsdLogClient(con, CUPSD_LOG_DEBUG, "Waiting for request.");
349*5e7646d2SAndroid Build Coastguard Worker 
350*5e7646d2SAndroid Build Coastguard Worker  /*
351*5e7646d2SAndroid Build Coastguard Worker   * Temporarily suspend accept()'s until we lose a client...
352*5e7646d2SAndroid Build Coastguard Worker   */
353*5e7646d2SAndroid Build Coastguard Worker 
354*5e7646d2SAndroid Build Coastguard Worker   if (cupsArrayCount(Clients) == MaxClients)
355*5e7646d2SAndroid Build Coastguard Worker     cupsdPauseListening();
356*5e7646d2SAndroid Build Coastguard Worker 
357*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_SSL
358*5e7646d2SAndroid Build Coastguard Worker  /*
359*5e7646d2SAndroid Build Coastguard Worker   * See if we are connecting on a secure port...
360*5e7646d2SAndroid Build Coastguard Worker   */
361*5e7646d2SAndroid Build Coastguard Worker 
362*5e7646d2SAndroid Build Coastguard Worker   if (lis->encryption == HTTP_ENCRYPTION_ALWAYS)
363*5e7646d2SAndroid Build Coastguard Worker   {
364*5e7646d2SAndroid Build Coastguard Worker    /*
365*5e7646d2SAndroid Build Coastguard Worker     * https connection; go secure...
366*5e7646d2SAndroid Build Coastguard Worker     */
367*5e7646d2SAndroid Build Coastguard Worker 
368*5e7646d2SAndroid Build Coastguard Worker     if (cupsd_start_tls(con, HTTP_ENCRYPTION_ALWAYS))
369*5e7646d2SAndroid Build Coastguard Worker       cupsdCloseClient(con);
370*5e7646d2SAndroid Build Coastguard Worker   }
371*5e7646d2SAndroid Build Coastguard Worker   else
372*5e7646d2SAndroid Build Coastguard Worker     con->auto_ssl = 1;
373*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_SSL */
374*5e7646d2SAndroid Build Coastguard Worker }
375*5e7646d2SAndroid Build Coastguard Worker 
376*5e7646d2SAndroid Build Coastguard Worker 
377*5e7646d2SAndroid Build Coastguard Worker /*
378*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdCloseAllClients()' - Close all remote clients immediately.
379*5e7646d2SAndroid Build Coastguard Worker  */
380*5e7646d2SAndroid Build Coastguard Worker 
381*5e7646d2SAndroid Build Coastguard Worker void
cupsdCloseAllClients(void)382*5e7646d2SAndroid Build Coastguard Worker cupsdCloseAllClients(void)
383*5e7646d2SAndroid Build Coastguard Worker {
384*5e7646d2SAndroid Build Coastguard Worker   cupsd_client_t	*con;		/* Current client */
385*5e7646d2SAndroid Build Coastguard Worker 
386*5e7646d2SAndroid Build Coastguard Worker 
387*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCloseAllClients() Clients=%d", cupsArrayCount(Clients));
388*5e7646d2SAndroid Build Coastguard Worker 
389*5e7646d2SAndroid Build Coastguard Worker   for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
390*5e7646d2SAndroid Build Coastguard Worker        con;
391*5e7646d2SAndroid Build Coastguard Worker        con = (cupsd_client_t *)cupsArrayNext(Clients))
392*5e7646d2SAndroid Build Coastguard Worker     if (cupsdCloseClient(con))
393*5e7646d2SAndroid Build Coastguard Worker       cupsdCloseClient(con);
394*5e7646d2SAndroid Build Coastguard Worker }
395*5e7646d2SAndroid Build Coastguard Worker 
396*5e7646d2SAndroid Build Coastguard Worker 
397*5e7646d2SAndroid Build Coastguard Worker /*
398*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdCloseClient()' - Close a remote client.
399*5e7646d2SAndroid Build Coastguard Worker  */
400*5e7646d2SAndroid Build Coastguard Worker 
401*5e7646d2SAndroid Build Coastguard Worker int					/* O - 1 if partial close, 0 if fully closed */
cupsdCloseClient(cupsd_client_t * con)402*5e7646d2SAndroid Build Coastguard Worker cupsdCloseClient(cupsd_client_t *con)	/* I - Client to close */
403*5e7646d2SAndroid Build Coastguard Worker {
404*5e7646d2SAndroid Build Coastguard Worker   int		partial;		/* Do partial close for SSL? */
405*5e7646d2SAndroid Build Coastguard Worker 
406*5e7646d2SAndroid Build Coastguard Worker 
407*5e7646d2SAndroid Build Coastguard Worker   cupsdLogClient(con, CUPSD_LOG_DEBUG, "Closing connection.");
408*5e7646d2SAndroid Build Coastguard Worker 
409*5e7646d2SAndroid Build Coastguard Worker  /*
410*5e7646d2SAndroid Build Coastguard Worker   * Flush pending writes before closing...
411*5e7646d2SAndroid Build Coastguard Worker   */
412*5e7646d2SAndroid Build Coastguard Worker 
413*5e7646d2SAndroid Build Coastguard Worker   httpFlushWrite(con->http);
414*5e7646d2SAndroid Build Coastguard Worker 
415*5e7646d2SAndroid Build Coastguard Worker   partial = 0;
416*5e7646d2SAndroid Build Coastguard Worker 
417*5e7646d2SAndroid Build Coastguard Worker   if (con->pipe_pid != 0)
418*5e7646d2SAndroid Build Coastguard Worker   {
419*5e7646d2SAndroid Build Coastguard Worker    /*
420*5e7646d2SAndroid Build Coastguard Worker     * Stop any CGI process...
421*5e7646d2SAndroid Build Coastguard Worker     */
422*5e7646d2SAndroid Build Coastguard Worker 
423*5e7646d2SAndroid Build Coastguard Worker     cupsdEndProcess(con->pipe_pid, 1);
424*5e7646d2SAndroid Build Coastguard Worker     con->pipe_pid = 0;
425*5e7646d2SAndroid Build Coastguard Worker   }
426*5e7646d2SAndroid Build Coastguard Worker 
427*5e7646d2SAndroid Build Coastguard Worker   if (con->file >= 0)
428*5e7646d2SAndroid Build Coastguard Worker   {
429*5e7646d2SAndroid Build Coastguard Worker     cupsdRemoveSelect(con->file);
430*5e7646d2SAndroid Build Coastguard Worker 
431*5e7646d2SAndroid Build Coastguard Worker     close(con->file);
432*5e7646d2SAndroid Build Coastguard Worker     con->file = -1;
433*5e7646d2SAndroid Build Coastguard Worker   }
434*5e7646d2SAndroid Build Coastguard Worker 
435*5e7646d2SAndroid Build Coastguard Worker  /*
436*5e7646d2SAndroid Build Coastguard Worker   * Close the socket and clear the file from the input set for select()...
437*5e7646d2SAndroid Build Coastguard Worker   */
438*5e7646d2SAndroid Build Coastguard Worker 
439*5e7646d2SAndroid Build Coastguard Worker   if (httpGetFd(con->http) >= 0)
440*5e7646d2SAndroid Build Coastguard Worker   {
441*5e7646d2SAndroid Build Coastguard Worker     cupsArrayRemove(ActiveClients, con);
442*5e7646d2SAndroid Build Coastguard Worker     cupsdSetBusyState(0);
443*5e7646d2SAndroid Build Coastguard Worker 
444*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_SSL
445*5e7646d2SAndroid Build Coastguard Worker    /*
446*5e7646d2SAndroid Build Coastguard Worker     * Shutdown encryption as needed...
447*5e7646d2SAndroid Build Coastguard Worker     */
448*5e7646d2SAndroid Build Coastguard Worker 
449*5e7646d2SAndroid Build Coastguard Worker     if (httpIsEncrypted(con->http))
450*5e7646d2SAndroid Build Coastguard Worker       partial = 1;
451*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_SSL */
452*5e7646d2SAndroid Build Coastguard Worker 
453*5e7646d2SAndroid Build Coastguard Worker     if (partial)
454*5e7646d2SAndroid Build Coastguard Worker     {
455*5e7646d2SAndroid Build Coastguard Worker      /*
456*5e7646d2SAndroid Build Coastguard Worker       * Only do a partial close so that the encrypted client gets everything.
457*5e7646d2SAndroid Build Coastguard Worker       */
458*5e7646d2SAndroid Build Coastguard Worker 
459*5e7646d2SAndroid Build Coastguard Worker       httpShutdown(con->http);
460*5e7646d2SAndroid Build Coastguard Worker       cupsdAddSelect(httpGetFd(con->http), (cupsd_selfunc_t)cupsdReadClient,
461*5e7646d2SAndroid Build Coastguard Worker                      NULL, con);
462*5e7646d2SAndroid Build Coastguard Worker 
463*5e7646d2SAndroid Build Coastguard Worker       cupsdLogClient(con, CUPSD_LOG_DEBUG, "Waiting for socket close.");
464*5e7646d2SAndroid Build Coastguard Worker     }
465*5e7646d2SAndroid Build Coastguard Worker     else
466*5e7646d2SAndroid Build Coastguard Worker     {
467*5e7646d2SAndroid Build Coastguard Worker      /*
468*5e7646d2SAndroid Build Coastguard Worker       * Shut the socket down fully...
469*5e7646d2SAndroid Build Coastguard Worker       */
470*5e7646d2SAndroid Build Coastguard Worker 
471*5e7646d2SAndroid Build Coastguard Worker       cupsdRemoveSelect(httpGetFd(con->http));
472*5e7646d2SAndroid Build Coastguard Worker       httpClose(con->http);
473*5e7646d2SAndroid Build Coastguard Worker       con->http = NULL;
474*5e7646d2SAndroid Build Coastguard Worker     }
475*5e7646d2SAndroid Build Coastguard Worker   }
476*5e7646d2SAndroid Build Coastguard Worker 
477*5e7646d2SAndroid Build Coastguard Worker   if (!partial)
478*5e7646d2SAndroid Build Coastguard Worker   {
479*5e7646d2SAndroid Build Coastguard Worker    /*
480*5e7646d2SAndroid Build Coastguard Worker     * Free memory...
481*5e7646d2SAndroid Build Coastguard Worker     */
482*5e7646d2SAndroid Build Coastguard Worker 
483*5e7646d2SAndroid Build Coastguard Worker     cupsdRemoveSelect(httpGetFd(con->http));
484*5e7646d2SAndroid Build Coastguard Worker 
485*5e7646d2SAndroid Build Coastguard Worker     httpClose(con->http);
486*5e7646d2SAndroid Build Coastguard Worker 
487*5e7646d2SAndroid Build Coastguard Worker     if (con->filename)
488*5e7646d2SAndroid Build Coastguard Worker     {
489*5e7646d2SAndroid Build Coastguard Worker       unlink(con->filename);
490*5e7646d2SAndroid Build Coastguard Worker       cupsdClearString(&con->filename);
491*5e7646d2SAndroid Build Coastguard Worker     }
492*5e7646d2SAndroid Build Coastguard Worker 
493*5e7646d2SAndroid Build Coastguard Worker     cupsdClearString(&con->command);
494*5e7646d2SAndroid Build Coastguard Worker     cupsdClearString(&con->options);
495*5e7646d2SAndroid Build Coastguard Worker     cupsdClearString(&con->query_string);
496*5e7646d2SAndroid Build Coastguard Worker 
497*5e7646d2SAndroid Build Coastguard Worker     if (con->request)
498*5e7646d2SAndroid Build Coastguard Worker     {
499*5e7646d2SAndroid Build Coastguard Worker       ippDelete(con->request);
500*5e7646d2SAndroid Build Coastguard Worker       con->request = NULL;
501*5e7646d2SAndroid Build Coastguard Worker     }
502*5e7646d2SAndroid Build Coastguard Worker 
503*5e7646d2SAndroid Build Coastguard Worker     if (con->response)
504*5e7646d2SAndroid Build Coastguard Worker     {
505*5e7646d2SAndroid Build Coastguard Worker       ippDelete(con->response);
506*5e7646d2SAndroid Build Coastguard Worker       con->response = NULL;
507*5e7646d2SAndroid Build Coastguard Worker     }
508*5e7646d2SAndroid Build Coastguard Worker 
509*5e7646d2SAndroid Build Coastguard Worker     if (con->language)
510*5e7646d2SAndroid Build Coastguard Worker     {
511*5e7646d2SAndroid Build Coastguard Worker       cupsLangFree(con->language);
512*5e7646d2SAndroid Build Coastguard Worker       con->language = NULL;
513*5e7646d2SAndroid Build Coastguard Worker     }
514*5e7646d2SAndroid Build Coastguard Worker 
515*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_AUTHORIZATION_H
516*5e7646d2SAndroid Build Coastguard Worker     if (con->authref)
517*5e7646d2SAndroid Build Coastguard Worker     {
518*5e7646d2SAndroid Build Coastguard Worker       AuthorizationFree(con->authref, kAuthorizationFlagDefaults);
519*5e7646d2SAndroid Build Coastguard Worker       con->authref = NULL;
520*5e7646d2SAndroid Build Coastguard Worker     }
521*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_AUTHORIZATION_H */
522*5e7646d2SAndroid Build Coastguard Worker 
523*5e7646d2SAndroid Build Coastguard Worker    /*
524*5e7646d2SAndroid Build Coastguard Worker     * Re-enable new client connections if we are going back under the
525*5e7646d2SAndroid Build Coastguard Worker     * limit...
526*5e7646d2SAndroid Build Coastguard Worker     */
527*5e7646d2SAndroid Build Coastguard Worker 
528*5e7646d2SAndroid Build Coastguard Worker     if (cupsArrayCount(Clients) == MaxClients)
529*5e7646d2SAndroid Build Coastguard Worker       cupsdResumeListening();
530*5e7646d2SAndroid Build Coastguard Worker 
531*5e7646d2SAndroid Build Coastguard Worker    /*
532*5e7646d2SAndroid Build Coastguard Worker     * Compact the list of clients as necessary...
533*5e7646d2SAndroid Build Coastguard Worker     */
534*5e7646d2SAndroid Build Coastguard Worker 
535*5e7646d2SAndroid Build Coastguard Worker     cupsArrayRemove(Clients, con);
536*5e7646d2SAndroid Build Coastguard Worker 
537*5e7646d2SAndroid Build Coastguard Worker     free(con);
538*5e7646d2SAndroid Build Coastguard Worker   }
539*5e7646d2SAndroid Build Coastguard Worker 
540*5e7646d2SAndroid Build Coastguard Worker   return (partial);
541*5e7646d2SAndroid Build Coastguard Worker }
542*5e7646d2SAndroid Build Coastguard Worker 
543*5e7646d2SAndroid Build Coastguard Worker 
544*5e7646d2SAndroid Build Coastguard Worker /*
545*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdReadClient()' - Read data from a client.
546*5e7646d2SAndroid Build Coastguard Worker  */
547*5e7646d2SAndroid Build Coastguard Worker 
548*5e7646d2SAndroid Build Coastguard Worker void
cupsdReadClient(cupsd_client_t * con)549*5e7646d2SAndroid Build Coastguard Worker cupsdReadClient(cupsd_client_t *con)	/* I - Client to read from */
550*5e7646d2SAndroid Build Coastguard Worker {
551*5e7646d2SAndroid Build Coastguard Worker   char			line[32768],	/* Line from client... */
552*5e7646d2SAndroid Build Coastguard Worker 			locale[64],	/* Locale */
553*5e7646d2SAndroid Build Coastguard Worker 			*ptr;		/* Pointer into strings */
554*5e7646d2SAndroid Build Coastguard Worker   http_status_t		status;		/* Transfer status */
555*5e7646d2SAndroid Build Coastguard Worker   ipp_state_t		ipp_state;	/* State of IPP transfer */
556*5e7646d2SAndroid Build Coastguard Worker   int			bytes;		/* Number of bytes to POST */
557*5e7646d2SAndroid Build Coastguard Worker   char			*filename;	/* Name of file for GET/HEAD */
558*5e7646d2SAndroid Build Coastguard Worker   char			buf[1024];	/* Buffer for real filename */
559*5e7646d2SAndroid Build Coastguard Worker   struct stat		filestats;	/* File information */
560*5e7646d2SAndroid Build Coastguard Worker   mime_type_t		*type;		/* MIME type of file */
561*5e7646d2SAndroid Build Coastguard Worker   static unsigned	request_id = 0;	/* Request ID for temp files */
562*5e7646d2SAndroid Build Coastguard Worker 
563*5e7646d2SAndroid Build Coastguard Worker 
564*5e7646d2SAndroid Build Coastguard Worker   status = HTTP_STATUS_CONTINUE;
565*5e7646d2SAndroid Build Coastguard Worker 
566*5e7646d2SAndroid Build Coastguard Worker   cupsdLogClient(con, CUPSD_LOG_DEBUG2, "cupsdReadClient: error=%d, used=%d, state=%s, data_encoding=HTTP_ENCODING_%s, data_remaining=" CUPS_LLFMT ", request=%p(%s), file=%d", httpError(con->http), (int)httpGetReady(con->http), httpStateString(httpGetState(con->http)), httpIsChunked(con->http) ? "CHUNKED" : "LENGTH", CUPS_LLCAST httpGetRemaining(con->http), con->request, con->request ? ippStateString(ippGetState(con->request)) : "", con->file);
567*5e7646d2SAndroid Build Coastguard Worker 
568*5e7646d2SAndroid Build Coastguard Worker   if (httpError(con->http) == EPIPE && !httpGetReady(con->http) && recv(httpGetFd(con->http), buf, 1, MSG_PEEK) < 1)
569*5e7646d2SAndroid Build Coastguard Worker   {
570*5e7646d2SAndroid Build Coastguard Worker    /*
571*5e7646d2SAndroid Build Coastguard Worker     * Connection closed...
572*5e7646d2SAndroid Build Coastguard Worker     */
573*5e7646d2SAndroid Build Coastguard Worker 
574*5e7646d2SAndroid Build Coastguard Worker     cupsdLogClient(con, CUPSD_LOG_DEBUG, "Closing on EOF.");
575*5e7646d2SAndroid Build Coastguard Worker     cupsdCloseClient(con);
576*5e7646d2SAndroid Build Coastguard Worker     return;
577*5e7646d2SAndroid Build Coastguard Worker   }
578*5e7646d2SAndroid Build Coastguard Worker 
579*5e7646d2SAndroid Build Coastguard Worker   if (httpGetState(con->http) == HTTP_STATE_GET_SEND ||
580*5e7646d2SAndroid Build Coastguard Worker       httpGetState(con->http) == HTTP_STATE_POST_SEND ||
581*5e7646d2SAndroid Build Coastguard Worker       httpGetState(con->http) == HTTP_STATE_STATUS)
582*5e7646d2SAndroid Build Coastguard Worker   {
583*5e7646d2SAndroid Build Coastguard Worker    /*
584*5e7646d2SAndroid Build Coastguard Worker     * If we get called in the wrong state, then something went wrong with the
585*5e7646d2SAndroid Build Coastguard Worker     * connection and we need to shut it down...
586*5e7646d2SAndroid Build Coastguard Worker     */
587*5e7646d2SAndroid Build Coastguard Worker 
588*5e7646d2SAndroid Build Coastguard Worker     cupsdLogClient(con, CUPSD_LOG_DEBUG, "Closing on unexpected HTTP read state %s.", httpStateString(httpGetState(con->http)));
589*5e7646d2SAndroid Build Coastguard Worker     cupsdCloseClient(con);
590*5e7646d2SAndroid Build Coastguard Worker     return;
591*5e7646d2SAndroid Build Coastguard Worker   }
592*5e7646d2SAndroid Build Coastguard Worker 
593*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_SSL
594*5e7646d2SAndroid Build Coastguard Worker   if (con->auto_ssl)
595*5e7646d2SAndroid Build Coastguard Worker   {
596*5e7646d2SAndroid Build Coastguard Worker    /*
597*5e7646d2SAndroid Build Coastguard Worker     * Automatically check for a SSL/TLS handshake...
598*5e7646d2SAndroid Build Coastguard Worker     */
599*5e7646d2SAndroid Build Coastguard Worker 
600*5e7646d2SAndroid Build Coastguard Worker     con->auto_ssl = 0;
601*5e7646d2SAndroid Build Coastguard Worker 
602*5e7646d2SAndroid Build Coastguard Worker     if (recv(httpGetFd(con->http), buf, 1, MSG_PEEK) == 1 &&
603*5e7646d2SAndroid Build Coastguard Worker         (!buf[0] || !strchr("DGHOPT", buf[0])))
604*5e7646d2SAndroid Build Coastguard Worker     {
605*5e7646d2SAndroid Build Coastguard Worker      /*
606*5e7646d2SAndroid Build Coastguard Worker       * Encrypt this connection...
607*5e7646d2SAndroid Build Coastguard Worker       */
608*5e7646d2SAndroid Build Coastguard Worker 
609*5e7646d2SAndroid Build Coastguard Worker       cupsdLogClient(con, CUPSD_LOG_DEBUG2, "Saw first byte %02X, auto-negotiating SSL/TLS session.", buf[0] & 255);
610*5e7646d2SAndroid Build Coastguard Worker 
611*5e7646d2SAndroid Build Coastguard Worker       if (cupsd_start_tls(con, HTTP_ENCRYPTION_ALWAYS))
612*5e7646d2SAndroid Build Coastguard Worker         cupsdCloseClient(con);
613*5e7646d2SAndroid Build Coastguard Worker 
614*5e7646d2SAndroid Build Coastguard Worker       return;
615*5e7646d2SAndroid Build Coastguard Worker     }
616*5e7646d2SAndroid Build Coastguard Worker   }
617*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_SSL */
618*5e7646d2SAndroid Build Coastguard Worker 
619*5e7646d2SAndroid Build Coastguard Worker   switch (httpGetState(con->http))
620*5e7646d2SAndroid Build Coastguard Worker   {
621*5e7646d2SAndroid Build Coastguard Worker     case HTTP_STATE_WAITING :
622*5e7646d2SAndroid Build Coastguard Worker        /*
623*5e7646d2SAndroid Build Coastguard Worker         * See if we've received a request line...
624*5e7646d2SAndroid Build Coastguard Worker 	*/
625*5e7646d2SAndroid Build Coastguard Worker 
626*5e7646d2SAndroid Build Coastguard Worker         con->operation = httpReadRequest(con->http, con->uri, sizeof(con->uri));
627*5e7646d2SAndroid Build Coastguard Worker         if (con->operation == HTTP_STATE_ERROR ||
628*5e7646d2SAndroid Build Coastguard Worker 	    con->operation == HTTP_STATE_UNKNOWN_METHOD ||
629*5e7646d2SAndroid Build Coastguard Worker 	    con->operation == HTTP_STATE_UNKNOWN_VERSION)
630*5e7646d2SAndroid Build Coastguard Worker 	{
631*5e7646d2SAndroid Build Coastguard Worker 	  if (httpError(con->http))
632*5e7646d2SAndroid Build Coastguard Worker 	    cupsdLogClient(con, CUPSD_LOG_DEBUG,
633*5e7646d2SAndroid Build Coastguard Worker 			   "HTTP_STATE_WAITING Closing for error %d (%s)",
634*5e7646d2SAndroid Build Coastguard Worker 			   httpError(con->http), strerror(httpError(con->http)));
635*5e7646d2SAndroid Build Coastguard Worker 	  else
636*5e7646d2SAndroid Build Coastguard Worker 	    cupsdLogClient(con, CUPSD_LOG_DEBUG,
637*5e7646d2SAndroid Build Coastguard Worker 	                   "HTTP_STATE_WAITING Closing on error: %s",
638*5e7646d2SAndroid Build Coastguard Worker 			   cupsLastErrorString());
639*5e7646d2SAndroid Build Coastguard Worker 
640*5e7646d2SAndroid Build Coastguard Worker 	  cupsdCloseClient(con);
641*5e7646d2SAndroid Build Coastguard Worker 	  return;
642*5e7646d2SAndroid Build Coastguard Worker 	}
643*5e7646d2SAndroid Build Coastguard Worker 
644*5e7646d2SAndroid Build Coastguard Worker        /*
645*5e7646d2SAndroid Build Coastguard Worker         * Ignore blank request lines...
646*5e7646d2SAndroid Build Coastguard Worker 	*/
647*5e7646d2SAndroid Build Coastguard Worker 
648*5e7646d2SAndroid Build Coastguard Worker         if (con->operation == HTTP_STATE_WAITING)
649*5e7646d2SAndroid Build Coastguard Worker 	  break;
650*5e7646d2SAndroid Build Coastguard Worker 
651*5e7646d2SAndroid Build Coastguard Worker        /*
652*5e7646d2SAndroid Build Coastguard Worker         * Clear other state variables...
653*5e7646d2SAndroid Build Coastguard Worker 	*/
654*5e7646d2SAndroid Build Coastguard Worker 
655*5e7646d2SAndroid Build Coastguard Worker 	con->bytes       = 0;
656*5e7646d2SAndroid Build Coastguard Worker 	con->file        = -1;
657*5e7646d2SAndroid Build Coastguard Worker 	con->file_ready  = 0;
658*5e7646d2SAndroid Build Coastguard Worker 	con->pipe_pid    = 0;
659*5e7646d2SAndroid Build Coastguard Worker 	con->username[0] = '\0';
660*5e7646d2SAndroid Build Coastguard Worker 	con->password[0] = '\0';
661*5e7646d2SAndroid Build Coastguard Worker 
662*5e7646d2SAndroid Build Coastguard Worker 	cupsdClearString(&con->command);
663*5e7646d2SAndroid Build Coastguard Worker 	cupsdClearString(&con->options);
664*5e7646d2SAndroid Build Coastguard Worker 	cupsdClearString(&con->query_string);
665*5e7646d2SAndroid Build Coastguard Worker 
666*5e7646d2SAndroid Build Coastguard Worker 	if (con->request)
667*5e7646d2SAndroid Build Coastguard Worker 	{
668*5e7646d2SAndroid Build Coastguard Worker 	  ippDelete(con->request);
669*5e7646d2SAndroid Build Coastguard Worker 	  con->request = NULL;
670*5e7646d2SAndroid Build Coastguard Worker 	}
671*5e7646d2SAndroid Build Coastguard Worker 
672*5e7646d2SAndroid Build Coastguard Worker 	if (con->response)
673*5e7646d2SAndroid Build Coastguard Worker 	{
674*5e7646d2SAndroid Build Coastguard Worker 	  ippDelete(con->response);
675*5e7646d2SAndroid Build Coastguard Worker 	  con->response = NULL;
676*5e7646d2SAndroid Build Coastguard Worker 	}
677*5e7646d2SAndroid Build Coastguard Worker 
678*5e7646d2SAndroid Build Coastguard Worker 	if (con->language)
679*5e7646d2SAndroid Build Coastguard Worker 	{
680*5e7646d2SAndroid Build Coastguard Worker 	  cupsLangFree(con->language);
681*5e7646d2SAndroid Build Coastguard Worker 	  con->language = NULL;
682*5e7646d2SAndroid Build Coastguard Worker 	}
683*5e7646d2SAndroid Build Coastguard Worker 
684*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_GSSAPI
685*5e7646d2SAndroid Build Coastguard Worker         con->have_gss = 0;
686*5e7646d2SAndroid Build Coastguard Worker 	con->gss_uid  = 0;
687*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_GSSAPI */
688*5e7646d2SAndroid Build Coastguard Worker 
689*5e7646d2SAndroid Build Coastguard Worker        /*
690*5e7646d2SAndroid Build Coastguard Worker         * Handle full URLs in the request line...
691*5e7646d2SAndroid Build Coastguard Worker 	*/
692*5e7646d2SAndroid Build Coastguard Worker 
693*5e7646d2SAndroid Build Coastguard Worker         if (strcmp(con->uri, "*"))
694*5e7646d2SAndroid Build Coastguard Worker 	{
695*5e7646d2SAndroid Build Coastguard Worker 	  char	scheme[HTTP_MAX_URI],	/* Method/scheme */
696*5e7646d2SAndroid Build Coastguard Worker 		userpass[HTTP_MAX_URI],	/* Username:password */
697*5e7646d2SAndroid Build Coastguard Worker 		hostname[HTTP_MAX_URI],	/* Hostname */
698*5e7646d2SAndroid Build Coastguard Worker 		resource[HTTP_MAX_URI];	/* Resource path */
699*5e7646d2SAndroid Build Coastguard Worker           int	port;			/* Port number */
700*5e7646d2SAndroid Build Coastguard Worker 
701*5e7646d2SAndroid Build Coastguard Worker          /*
702*5e7646d2SAndroid Build Coastguard Worker 	  * Separate the URI into its components...
703*5e7646d2SAndroid Build Coastguard Worker 	  */
704*5e7646d2SAndroid Build Coastguard Worker 
705*5e7646d2SAndroid Build Coastguard Worker           if (httpSeparateURI(HTTP_URI_CODING_MOST, con->uri,
706*5e7646d2SAndroid Build Coastguard Worker 	                      scheme, sizeof(scheme),
707*5e7646d2SAndroid Build Coastguard Worker 	                      userpass, sizeof(userpass),
708*5e7646d2SAndroid Build Coastguard Worker 			      hostname, sizeof(hostname), &port,
709*5e7646d2SAndroid Build Coastguard Worker 			      resource, sizeof(resource)) < HTTP_URI_STATUS_OK)
710*5e7646d2SAndroid Build Coastguard Worker           {
711*5e7646d2SAndroid Build Coastguard Worker 	    cupsdLogClient(con, CUPSD_LOG_ERROR, "Bad URI \"%s\" in request.",
712*5e7646d2SAndroid Build Coastguard Worker                            con->uri);
713*5e7646d2SAndroid Build Coastguard Worker 	    cupsdSendError(con, HTTP_STATUS_METHOD_NOT_ALLOWED, CUPSD_AUTH_NONE);
714*5e7646d2SAndroid Build Coastguard Worker 	    cupsdCloseClient(con);
715*5e7646d2SAndroid Build Coastguard Worker 	    return;
716*5e7646d2SAndroid Build Coastguard Worker 	  }
717*5e7646d2SAndroid Build Coastguard Worker 
718*5e7646d2SAndroid Build Coastguard Worker 	 /*
719*5e7646d2SAndroid Build Coastguard Worker 	  * Only allow URIs with the servername, localhost, or an IP
720*5e7646d2SAndroid Build Coastguard Worker 	  * address...
721*5e7646d2SAndroid Build Coastguard Worker 	  */
722*5e7646d2SAndroid Build Coastguard Worker 
723*5e7646d2SAndroid Build Coastguard Worker 	  if (strcmp(scheme, "file") &&
724*5e7646d2SAndroid Build Coastguard Worker 	      _cups_strcasecmp(hostname, ServerName) &&
725*5e7646d2SAndroid Build Coastguard Worker 	      _cups_strcasecmp(hostname, "localhost") &&
726*5e7646d2SAndroid Build Coastguard Worker 	      !cupsArrayFind(ServerAlias, hostname) &&
727*5e7646d2SAndroid Build Coastguard Worker 	      !isdigit(hostname[0]) && hostname[0] != '[')
728*5e7646d2SAndroid Build Coastguard Worker 	  {
729*5e7646d2SAndroid Build Coastguard Worker 	   /*
730*5e7646d2SAndroid Build Coastguard Worker 	    * Nope, we don't do proxies...
731*5e7646d2SAndroid Build Coastguard Worker 	    */
732*5e7646d2SAndroid Build Coastguard Worker 
733*5e7646d2SAndroid Build Coastguard Worker 	    cupsdLogClient(con, CUPSD_LOG_ERROR, "Bad URI \"%s\" in request.",
734*5e7646d2SAndroid Build Coastguard Worker                            con->uri);
735*5e7646d2SAndroid Build Coastguard Worker 	    cupsdSendError(con, HTTP_STATUS_METHOD_NOT_ALLOWED, CUPSD_AUTH_NONE);
736*5e7646d2SAndroid Build Coastguard Worker 	    cupsdCloseClient(con);
737*5e7646d2SAndroid Build Coastguard Worker 	    return;
738*5e7646d2SAndroid Build Coastguard Worker 	  }
739*5e7646d2SAndroid Build Coastguard Worker 
740*5e7646d2SAndroid Build Coastguard Worker          /*
741*5e7646d2SAndroid Build Coastguard Worker 	  * Copy the resource portion back into the URI; both resource and
742*5e7646d2SAndroid Build Coastguard Worker 	  * con->uri are HTTP_MAX_URI bytes in size...
743*5e7646d2SAndroid Build Coastguard Worker 	  */
744*5e7646d2SAndroid Build Coastguard Worker 
745*5e7646d2SAndroid Build Coastguard Worker           strlcpy(con->uri, resource, sizeof(con->uri));
746*5e7646d2SAndroid Build Coastguard Worker 	}
747*5e7646d2SAndroid Build Coastguard Worker 
748*5e7646d2SAndroid Build Coastguard Worker        /*
749*5e7646d2SAndroid Build Coastguard Worker         * Process the request...
750*5e7646d2SAndroid Build Coastguard Worker 	*/
751*5e7646d2SAndroid Build Coastguard Worker 
752*5e7646d2SAndroid Build Coastguard Worker         gettimeofday(&(con->start), NULL);
753*5e7646d2SAndroid Build Coastguard Worker 
754*5e7646d2SAndroid Build Coastguard Worker         cupsdLogClient(con, CUPSD_LOG_DEBUG, "%s %s HTTP/%d.%d",
755*5e7646d2SAndroid Build Coastguard Worker 	               httpStateString(con->operation) + 11, con->uri,
756*5e7646d2SAndroid Build Coastguard Worker 		       httpGetVersion(con->http) / 100,
757*5e7646d2SAndroid Build Coastguard Worker                        httpGetVersion(con->http) % 100);
758*5e7646d2SAndroid Build Coastguard Worker 
759*5e7646d2SAndroid Build Coastguard Worker         if (!cupsArrayFind(ActiveClients, con))
760*5e7646d2SAndroid Build Coastguard Worker 	{
761*5e7646d2SAndroid Build Coastguard Worker 	  cupsArrayAdd(ActiveClients, con);
762*5e7646d2SAndroid Build Coastguard Worker           cupsdSetBusyState(0);
763*5e7646d2SAndroid Build Coastguard Worker         }
764*5e7646d2SAndroid Build Coastguard Worker 
765*5e7646d2SAndroid Build Coastguard Worker     case HTTP_STATE_OPTIONS :
766*5e7646d2SAndroid Build Coastguard Worker     case HTTP_STATE_DELETE :
767*5e7646d2SAndroid Build Coastguard Worker     case HTTP_STATE_GET :
768*5e7646d2SAndroid Build Coastguard Worker     case HTTP_STATE_HEAD :
769*5e7646d2SAndroid Build Coastguard Worker     case HTTP_STATE_POST :
770*5e7646d2SAndroid Build Coastguard Worker     case HTTP_STATE_PUT :
771*5e7646d2SAndroid Build Coastguard Worker     case HTTP_STATE_TRACE :
772*5e7646d2SAndroid Build Coastguard Worker        /*
773*5e7646d2SAndroid Build Coastguard Worker         * Parse incoming parameters until the status changes...
774*5e7646d2SAndroid Build Coastguard Worker 	*/
775*5e7646d2SAndroid Build Coastguard Worker 
776*5e7646d2SAndroid Build Coastguard Worker         while ((status = httpUpdate(con->http)) == HTTP_STATUS_CONTINUE)
777*5e7646d2SAndroid Build Coastguard Worker 	  if (!httpGetReady(con->http))
778*5e7646d2SAndroid Build Coastguard Worker 	    break;
779*5e7646d2SAndroid Build Coastguard Worker 
780*5e7646d2SAndroid Build Coastguard Worker 	if (status != HTTP_STATUS_OK && status != HTTP_STATUS_CONTINUE)
781*5e7646d2SAndroid Build Coastguard Worker 	{
782*5e7646d2SAndroid Build Coastguard Worker 	  if (httpError(con->http) && httpError(con->http) != EPIPE)
783*5e7646d2SAndroid Build Coastguard Worker 	    cupsdLogClient(con, CUPSD_LOG_DEBUG,
784*5e7646d2SAndroid Build Coastguard Worker                            "Closing for error %d (%s) while reading headers.",
785*5e7646d2SAndroid Build Coastguard Worker                            httpError(con->http), strerror(httpError(con->http)));
786*5e7646d2SAndroid Build Coastguard Worker 	  else
787*5e7646d2SAndroid Build Coastguard Worker 	    cupsdLogClient(con, CUPSD_LOG_DEBUG,
788*5e7646d2SAndroid Build Coastguard Worker 	                   "Closing on EOF while reading headers.");
789*5e7646d2SAndroid Build Coastguard Worker 
790*5e7646d2SAndroid Build Coastguard Worker 	  cupsdSendError(con, HTTP_STATUS_BAD_REQUEST, CUPSD_AUTH_NONE);
791*5e7646d2SAndroid Build Coastguard Worker 	  cupsdCloseClient(con);
792*5e7646d2SAndroid Build Coastguard Worker 	  return;
793*5e7646d2SAndroid Build Coastguard Worker 	}
794*5e7646d2SAndroid Build Coastguard Worker 	break;
795*5e7646d2SAndroid Build Coastguard Worker 
796*5e7646d2SAndroid Build Coastguard Worker     default :
797*5e7646d2SAndroid Build Coastguard Worker         if (!httpGetReady(con->http) && recv(httpGetFd(con->http), buf, 1, MSG_PEEK) < 1)
798*5e7646d2SAndroid Build Coastguard Worker 	{
799*5e7646d2SAndroid Build Coastguard Worker 	 /*
800*5e7646d2SAndroid Build Coastguard Worker 	  * Connection closed...
801*5e7646d2SAndroid Build Coastguard Worker 	  */
802*5e7646d2SAndroid Build Coastguard Worker 
803*5e7646d2SAndroid Build Coastguard Worker 	  cupsdLogClient(con, CUPSD_LOG_DEBUG, "Closing on EOF.");
804*5e7646d2SAndroid Build Coastguard Worker           cupsdCloseClient(con);
805*5e7646d2SAndroid Build Coastguard Worker 	  return;
806*5e7646d2SAndroid Build Coastguard Worker 	}
807*5e7646d2SAndroid Build Coastguard Worker         break; /* Anti-compiler-warning-code */
808*5e7646d2SAndroid Build Coastguard Worker   }
809*5e7646d2SAndroid Build Coastguard Worker 
810*5e7646d2SAndroid Build Coastguard Worker  /*
811*5e7646d2SAndroid Build Coastguard Worker   * Handle new transfers...
812*5e7646d2SAndroid Build Coastguard Worker   */
813*5e7646d2SAndroid Build Coastguard Worker 
814*5e7646d2SAndroid Build Coastguard Worker   cupsdLogClient(con, CUPSD_LOG_DEBUG, "Read: status=%d, state=%d", status, httpGetState(con->http));
815*5e7646d2SAndroid Build Coastguard Worker 
816*5e7646d2SAndroid Build Coastguard Worker   if (status == HTTP_STATUS_OK)
817*5e7646d2SAndroid Build Coastguard Worker   {
818*5e7646d2SAndroid Build Coastguard Worker    /*
819*5e7646d2SAndroid Build Coastguard Worker     * Record whether the client is a web browser.  "Mozilla" was the original
820*5e7646d2SAndroid Build Coastguard Worker     * and it seems that every web browser in existence now uses that as the
821*5e7646d2SAndroid Build Coastguard Worker     * prefix with additional information identifying *which* browser.
822*5e7646d2SAndroid Build Coastguard Worker     *
823*5e7646d2SAndroid Build Coastguard Worker     * Chrome (at least) has problems with multiple WWW-Authenticate values in
824*5e7646d2SAndroid Build Coastguard Worker     * a single header, so we only report Basic or Negotiate to web browsers and
825*5e7646d2SAndroid Build Coastguard Worker     * leave the multiple choices to the native CUPS client...
826*5e7646d2SAndroid Build Coastguard Worker     */
827*5e7646d2SAndroid Build Coastguard Worker 
828*5e7646d2SAndroid Build Coastguard Worker     con->is_browser = !strncmp(httpGetField(con->http, HTTP_FIELD_USER_AGENT), "Mozilla/", 8);
829*5e7646d2SAndroid Build Coastguard Worker 
830*5e7646d2SAndroid Build Coastguard Worker     if (httpGetField(con->http, HTTP_FIELD_ACCEPT_LANGUAGE)[0])
831*5e7646d2SAndroid Build Coastguard Worker     {
832*5e7646d2SAndroid Build Coastguard Worker      /*
833*5e7646d2SAndroid Build Coastguard Worker       * Figure out the locale from the Accept-Language and Content-Type
834*5e7646d2SAndroid Build Coastguard Worker       * fields...
835*5e7646d2SAndroid Build Coastguard Worker       */
836*5e7646d2SAndroid Build Coastguard Worker 
837*5e7646d2SAndroid Build Coastguard Worker       if ((ptr = strchr(httpGetField(con->http, HTTP_FIELD_ACCEPT_LANGUAGE),
838*5e7646d2SAndroid Build Coastguard Worker                         ',')) != NULL)
839*5e7646d2SAndroid Build Coastguard Worker         *ptr = '\0';
840*5e7646d2SAndroid Build Coastguard Worker 
841*5e7646d2SAndroid Build Coastguard Worker       if ((ptr = strchr(httpGetField(con->http, HTTP_FIELD_ACCEPT_LANGUAGE),
842*5e7646d2SAndroid Build Coastguard Worker                         ';')) != NULL)
843*5e7646d2SAndroid Build Coastguard Worker         *ptr = '\0';
844*5e7646d2SAndroid Build Coastguard Worker 
845*5e7646d2SAndroid Build Coastguard Worker       if ((ptr = strstr(httpGetField(con->http, HTTP_FIELD_CONTENT_TYPE),
846*5e7646d2SAndroid Build Coastguard Worker                         "charset=")) != NULL)
847*5e7646d2SAndroid Build Coastguard Worker       {
848*5e7646d2SAndroid Build Coastguard Worker        /*
849*5e7646d2SAndroid Build Coastguard Worker         * Combine language and charset, and trim any extra params in the
850*5e7646d2SAndroid Build Coastguard Worker 	* content-type.
851*5e7646d2SAndroid Build Coastguard Worker 	*/
852*5e7646d2SAndroid Build Coastguard Worker 
853*5e7646d2SAndroid Build Coastguard Worker         snprintf(locale, sizeof(locale), "%s.%s",
854*5e7646d2SAndroid Build Coastguard Worker 	         httpGetField(con->http, HTTP_FIELD_ACCEPT_LANGUAGE), ptr + 8);
855*5e7646d2SAndroid Build Coastguard Worker 
856*5e7646d2SAndroid Build Coastguard Worker 	if ((ptr = strchr(locale, ',')) != NULL)
857*5e7646d2SAndroid Build Coastguard Worker 	  *ptr = '\0';
858*5e7646d2SAndroid Build Coastguard Worker       }
859*5e7646d2SAndroid Build Coastguard Worker       else
860*5e7646d2SAndroid Build Coastguard Worker         snprintf(locale, sizeof(locale), "%s.UTF-8",
861*5e7646d2SAndroid Build Coastguard Worker 	         httpGetField(con->http, HTTP_FIELD_ACCEPT_LANGUAGE));
862*5e7646d2SAndroid Build Coastguard Worker 
863*5e7646d2SAndroid Build Coastguard Worker       con->language = cupsLangGet(locale);
864*5e7646d2SAndroid Build Coastguard Worker     }
865*5e7646d2SAndroid Build Coastguard Worker     else
866*5e7646d2SAndroid Build Coastguard Worker       con->language = cupsLangGet(DefaultLocale);
867*5e7646d2SAndroid Build Coastguard Worker 
868*5e7646d2SAndroid Build Coastguard Worker     cupsdAuthorize(con);
869*5e7646d2SAndroid Build Coastguard Worker 
870*5e7646d2SAndroid Build Coastguard Worker     if (!_cups_strncasecmp(httpGetField(con->http, HTTP_FIELD_CONNECTION),
871*5e7646d2SAndroid Build Coastguard Worker                            "Keep-Alive", 10) && KeepAlive)
872*5e7646d2SAndroid Build Coastguard Worker       httpSetKeepAlive(con->http, HTTP_KEEPALIVE_ON);
873*5e7646d2SAndroid Build Coastguard Worker     else if (!_cups_strncasecmp(httpGetField(con->http, HTTP_FIELD_CONNECTION),
874*5e7646d2SAndroid Build Coastguard Worker                                 "close", 5))
875*5e7646d2SAndroid Build Coastguard Worker       httpSetKeepAlive(con->http, HTTP_KEEPALIVE_OFF);
876*5e7646d2SAndroid Build Coastguard Worker 
877*5e7646d2SAndroid Build Coastguard Worker     if (!httpGetField(con->http, HTTP_FIELD_HOST)[0] &&
878*5e7646d2SAndroid Build Coastguard Worker         httpGetVersion(con->http) >= HTTP_VERSION_1_1)
879*5e7646d2SAndroid Build Coastguard Worker     {
880*5e7646d2SAndroid Build Coastguard Worker      /*
881*5e7646d2SAndroid Build Coastguard Worker       * HTTP/1.1 and higher require the "Host:" field...
882*5e7646d2SAndroid Build Coastguard Worker       */
883*5e7646d2SAndroid Build Coastguard Worker 
884*5e7646d2SAndroid Build Coastguard Worker       if (!cupsdSendError(con, HTTP_STATUS_BAD_REQUEST, CUPSD_AUTH_NONE))
885*5e7646d2SAndroid Build Coastguard Worker       {
886*5e7646d2SAndroid Build Coastguard Worker         cupsdLogClient(con, CUPSD_LOG_ERROR, "Missing Host: field in request.");
887*5e7646d2SAndroid Build Coastguard Worker 	cupsdCloseClient(con);
888*5e7646d2SAndroid Build Coastguard Worker 	return;
889*5e7646d2SAndroid Build Coastguard Worker       }
890*5e7646d2SAndroid Build Coastguard Worker     }
891*5e7646d2SAndroid Build Coastguard Worker     else if (!valid_host(con))
892*5e7646d2SAndroid Build Coastguard Worker     {
893*5e7646d2SAndroid Build Coastguard Worker      /*
894*5e7646d2SAndroid Build Coastguard Worker       * Access to localhost must use "localhost" or the corresponding IPv4
895*5e7646d2SAndroid Build Coastguard Worker       * or IPv6 values in the Host: field.
896*5e7646d2SAndroid Build Coastguard Worker       */
897*5e7646d2SAndroid Build Coastguard Worker 
898*5e7646d2SAndroid Build Coastguard Worker       cupsdLogClient(con, CUPSD_LOG_ERROR,
899*5e7646d2SAndroid Build Coastguard Worker                      "Request from \"%s\" using invalid Host: field \"%s\".",
900*5e7646d2SAndroid Build Coastguard Worker                      httpGetHostname(con->http, NULL, 0), httpGetField(con->http, HTTP_FIELD_HOST));
901*5e7646d2SAndroid Build Coastguard Worker 
902*5e7646d2SAndroid Build Coastguard Worker       if (!cupsdSendError(con, HTTP_STATUS_BAD_REQUEST, CUPSD_AUTH_NONE))
903*5e7646d2SAndroid Build Coastguard Worker       {
904*5e7646d2SAndroid Build Coastguard Worker 	cupsdCloseClient(con);
905*5e7646d2SAndroid Build Coastguard Worker 	return;
906*5e7646d2SAndroid Build Coastguard Worker       }
907*5e7646d2SAndroid Build Coastguard Worker     }
908*5e7646d2SAndroid Build Coastguard Worker     else if (con->operation == HTTP_STATE_OPTIONS)
909*5e7646d2SAndroid Build Coastguard Worker     {
910*5e7646d2SAndroid Build Coastguard Worker      /*
911*5e7646d2SAndroid Build Coastguard Worker       * Do OPTIONS command...
912*5e7646d2SAndroid Build Coastguard Worker       */
913*5e7646d2SAndroid Build Coastguard Worker 
914*5e7646d2SAndroid Build Coastguard Worker       if (con->best && con->best->type != CUPSD_AUTH_NONE)
915*5e7646d2SAndroid Build Coastguard Worker       {
916*5e7646d2SAndroid Build Coastguard Worker         httpClearFields(con->http);
917*5e7646d2SAndroid Build Coastguard Worker 
918*5e7646d2SAndroid Build Coastguard Worker 	if (!cupsdSendHeader(con, HTTP_STATUS_UNAUTHORIZED, NULL, CUPSD_AUTH_NONE))
919*5e7646d2SAndroid Build Coastguard Worker 	{
920*5e7646d2SAndroid Build Coastguard Worker 	  cupsdCloseClient(con);
921*5e7646d2SAndroid Build Coastguard Worker 	  return;
922*5e7646d2SAndroid Build Coastguard Worker 	}
923*5e7646d2SAndroid Build Coastguard Worker       }
924*5e7646d2SAndroid Build Coastguard Worker 
925*5e7646d2SAndroid Build Coastguard Worker       if (!_cups_strcasecmp(httpGetField(con->http, HTTP_FIELD_CONNECTION), "Upgrade") && strstr(httpGetField(con->http, HTTP_FIELD_UPGRADE), "TLS/") != NULL && !httpIsEncrypted(con->http))
926*5e7646d2SAndroid Build Coastguard Worker       {
927*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_SSL
928*5e7646d2SAndroid Build Coastguard Worker        /*
929*5e7646d2SAndroid Build Coastguard Worker         * Do encryption stuff...
930*5e7646d2SAndroid Build Coastguard Worker 	*/
931*5e7646d2SAndroid Build Coastguard Worker 
932*5e7646d2SAndroid Build Coastguard Worker         httpClearFields(con->http);
933*5e7646d2SAndroid Build Coastguard Worker 
934*5e7646d2SAndroid Build Coastguard Worker 	if (!cupsdSendHeader(con, HTTP_STATUS_SWITCHING_PROTOCOLS, NULL, CUPSD_AUTH_NONE))
935*5e7646d2SAndroid Build Coastguard Worker 	{
936*5e7646d2SAndroid Build Coastguard Worker 	  cupsdCloseClient(con);
937*5e7646d2SAndroid Build Coastguard Worker 	  return;
938*5e7646d2SAndroid Build Coastguard Worker 	}
939*5e7646d2SAndroid Build Coastguard Worker 
940*5e7646d2SAndroid Build Coastguard Worker         if (cupsd_start_tls(con, HTTP_ENCRYPTION_REQUIRED))
941*5e7646d2SAndroid Build Coastguard Worker         {
942*5e7646d2SAndroid Build Coastguard Worker 	  cupsdCloseClient(con);
943*5e7646d2SAndroid Build Coastguard Worker 	  return;
944*5e7646d2SAndroid Build Coastguard Worker 	}
945*5e7646d2SAndroid Build Coastguard Worker #else
946*5e7646d2SAndroid Build Coastguard Worker 	if (!cupsdSendError(con, HTTP_STATUS_NOT_IMPLEMENTED, CUPSD_AUTH_NONE))
947*5e7646d2SAndroid Build Coastguard Worker 	{
948*5e7646d2SAndroid Build Coastguard Worker 	  cupsdCloseClient(con);
949*5e7646d2SAndroid Build Coastguard Worker 	  return;
950*5e7646d2SAndroid Build Coastguard Worker 	}
951*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_SSL */
952*5e7646d2SAndroid Build Coastguard Worker       }
953*5e7646d2SAndroid Build Coastguard Worker 
954*5e7646d2SAndroid Build Coastguard Worker       httpClearFields(con->http);
955*5e7646d2SAndroid Build Coastguard Worker       httpSetField(con->http, HTTP_FIELD_CONTENT_LENGTH, "0");
956*5e7646d2SAndroid Build Coastguard Worker 
957*5e7646d2SAndroid Build Coastguard Worker       if (!cupsdSendHeader(con, HTTP_STATUS_OK, NULL, CUPSD_AUTH_NONE))
958*5e7646d2SAndroid Build Coastguard Worker       {
959*5e7646d2SAndroid Build Coastguard Worker 	cupsdCloseClient(con);
960*5e7646d2SAndroid Build Coastguard Worker 	return;
961*5e7646d2SAndroid Build Coastguard Worker       }
962*5e7646d2SAndroid Build Coastguard Worker     }
963*5e7646d2SAndroid Build Coastguard Worker     else if (!is_path_absolute(con->uri))
964*5e7646d2SAndroid Build Coastguard Worker     {
965*5e7646d2SAndroid Build Coastguard Worker      /*
966*5e7646d2SAndroid Build Coastguard Worker       * Protect against malicious users!
967*5e7646d2SAndroid Build Coastguard Worker       */
968*5e7646d2SAndroid Build Coastguard Worker 
969*5e7646d2SAndroid Build Coastguard Worker       cupsdLogClient(con, CUPSD_LOG_ERROR,
970*5e7646d2SAndroid Build Coastguard Worker                      "Request for non-absolute resource \"%s\".", con->uri);
971*5e7646d2SAndroid Build Coastguard Worker 
972*5e7646d2SAndroid Build Coastguard Worker       if (!cupsdSendError(con, HTTP_STATUS_FORBIDDEN, CUPSD_AUTH_NONE))
973*5e7646d2SAndroid Build Coastguard Worker       {
974*5e7646d2SAndroid Build Coastguard Worker 	cupsdCloseClient(con);
975*5e7646d2SAndroid Build Coastguard Worker 	return;
976*5e7646d2SAndroid Build Coastguard Worker       }
977*5e7646d2SAndroid Build Coastguard Worker     }
978*5e7646d2SAndroid Build Coastguard Worker     else
979*5e7646d2SAndroid Build Coastguard Worker     {
980*5e7646d2SAndroid Build Coastguard Worker       if (!_cups_strcasecmp(httpGetField(con->http, HTTP_FIELD_CONNECTION),
981*5e7646d2SAndroid Build Coastguard Worker                             "Upgrade") && !httpIsEncrypted(con->http))
982*5e7646d2SAndroid Build Coastguard Worker       {
983*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_SSL
984*5e7646d2SAndroid Build Coastguard Worker        /*
985*5e7646d2SAndroid Build Coastguard Worker         * Do encryption stuff...
986*5e7646d2SAndroid Build Coastguard Worker 	*/
987*5e7646d2SAndroid Build Coastguard Worker 
988*5e7646d2SAndroid Build Coastguard Worker         httpClearFields(con->http);
989*5e7646d2SAndroid Build Coastguard Worker 
990*5e7646d2SAndroid Build Coastguard Worker 	if (!cupsdSendHeader(con, HTTP_STATUS_SWITCHING_PROTOCOLS, NULL,
991*5e7646d2SAndroid Build Coastguard Worker 	                     CUPSD_AUTH_NONE))
992*5e7646d2SAndroid Build Coastguard Worker 	{
993*5e7646d2SAndroid Build Coastguard Worker 	  cupsdCloseClient(con);
994*5e7646d2SAndroid Build Coastguard Worker 	  return;
995*5e7646d2SAndroid Build Coastguard Worker 	}
996*5e7646d2SAndroid Build Coastguard Worker 
997*5e7646d2SAndroid Build Coastguard Worker         if (cupsd_start_tls(con, HTTP_ENCRYPTION_REQUIRED))
998*5e7646d2SAndroid Build Coastguard Worker         {
999*5e7646d2SAndroid Build Coastguard Worker 	  cupsdCloseClient(con);
1000*5e7646d2SAndroid Build Coastguard Worker 	  return;
1001*5e7646d2SAndroid Build Coastguard Worker 	}
1002*5e7646d2SAndroid Build Coastguard Worker #else
1003*5e7646d2SAndroid Build Coastguard Worker 	if (!cupsdSendError(con, HTTP_STATUS_NOT_IMPLEMENTED, CUPSD_AUTH_NONE))
1004*5e7646d2SAndroid Build Coastguard Worker 	{
1005*5e7646d2SAndroid Build Coastguard Worker 	  cupsdCloseClient(con);
1006*5e7646d2SAndroid Build Coastguard Worker 	  return;
1007*5e7646d2SAndroid Build Coastguard Worker 	}
1008*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_SSL */
1009*5e7646d2SAndroid Build Coastguard Worker       }
1010*5e7646d2SAndroid Build Coastguard Worker 
1011*5e7646d2SAndroid Build Coastguard Worker       if ((status = cupsdIsAuthorized(con, NULL)) != HTTP_STATUS_OK)
1012*5e7646d2SAndroid Build Coastguard Worker       {
1013*5e7646d2SAndroid Build Coastguard Worker 	cupsdSendError(con, status, CUPSD_AUTH_NONE);
1014*5e7646d2SAndroid Build Coastguard Worker 	cupsdCloseClient(con);
1015*5e7646d2SAndroid Build Coastguard Worker 	return;
1016*5e7646d2SAndroid Build Coastguard Worker       }
1017*5e7646d2SAndroid Build Coastguard Worker 
1018*5e7646d2SAndroid Build Coastguard Worker       if (httpGetExpect(con->http) &&
1019*5e7646d2SAndroid Build Coastguard Worker           (con->operation == HTTP_STATE_POST || con->operation == HTTP_STATE_PUT))
1020*5e7646d2SAndroid Build Coastguard Worker       {
1021*5e7646d2SAndroid Build Coastguard Worker         if (httpGetExpect(con->http) == HTTP_STATUS_CONTINUE)
1022*5e7646d2SAndroid Build Coastguard Worker 	{
1023*5e7646d2SAndroid Build Coastguard Worker 	 /*
1024*5e7646d2SAndroid Build Coastguard Worker 	  * Send 100-continue header...
1025*5e7646d2SAndroid Build Coastguard Worker 	  */
1026*5e7646d2SAndroid Build Coastguard Worker 
1027*5e7646d2SAndroid Build Coastguard Worker           if (httpWriteResponse(con->http, HTTP_STATUS_CONTINUE))
1028*5e7646d2SAndroid Build Coastguard Worker 	  {
1029*5e7646d2SAndroid Build Coastguard Worker 	    cupsdCloseClient(con);
1030*5e7646d2SAndroid Build Coastguard Worker 	    return;
1031*5e7646d2SAndroid Build Coastguard Worker 	  }
1032*5e7646d2SAndroid Build Coastguard Worker 	}
1033*5e7646d2SAndroid Build Coastguard Worker 	else
1034*5e7646d2SAndroid Build Coastguard Worker 	{
1035*5e7646d2SAndroid Build Coastguard Worker 	 /*
1036*5e7646d2SAndroid Build Coastguard Worker 	  * Send 417-expectation-failed header...
1037*5e7646d2SAndroid Build Coastguard Worker 	  */
1038*5e7646d2SAndroid Build Coastguard Worker 
1039*5e7646d2SAndroid Build Coastguard Worker           httpClearFields(con->http);
1040*5e7646d2SAndroid Build Coastguard Worker 	  httpSetField(con->http, HTTP_FIELD_CONTENT_LENGTH, "0");
1041*5e7646d2SAndroid Build Coastguard Worker 
1042*5e7646d2SAndroid Build Coastguard Worker 	  cupsdSendError(con, HTTP_STATUS_EXPECTATION_FAILED, CUPSD_AUTH_NONE);
1043*5e7646d2SAndroid Build Coastguard Worker           cupsdCloseClient(con);
1044*5e7646d2SAndroid Build Coastguard Worker           return;
1045*5e7646d2SAndroid Build Coastguard Worker 	}
1046*5e7646d2SAndroid Build Coastguard Worker       }
1047*5e7646d2SAndroid Build Coastguard Worker 
1048*5e7646d2SAndroid Build Coastguard Worker       switch (httpGetState(con->http))
1049*5e7646d2SAndroid Build Coastguard Worker       {
1050*5e7646d2SAndroid Build Coastguard Worker 	case HTTP_STATE_GET_SEND :
1051*5e7646d2SAndroid Build Coastguard Worker             cupsdLogClient(con, CUPSD_LOG_DEBUG, "Processing GET %s", con->uri);
1052*5e7646d2SAndroid Build Coastguard Worker 
1053*5e7646d2SAndroid Build Coastguard Worker             if ((filename = get_file(con, &filestats, buf, sizeof(buf))) != NULL)
1054*5e7646d2SAndroid Build Coastguard Worker             {
1055*5e7646d2SAndroid Build Coastguard Worker 	      type = mimeFileType(MimeDatabase, filename, NULL, NULL);
1056*5e7646d2SAndroid Build Coastguard Worker 
1057*5e7646d2SAndroid Build Coastguard Worker               cupsdLogClient(con, CUPSD_LOG_DEBUG, "filename=\"%s\", type=%s/%s", filename, type ? type->super : "", type ? type->type : "");
1058*5e7646d2SAndroid Build Coastguard Worker 
1059*5e7646d2SAndroid Build Coastguard Worker               if (is_cgi(con, filename, &filestats, type))
1060*5e7646d2SAndroid Build Coastguard Worker 	      {
1061*5e7646d2SAndroid Build Coastguard Worker 	       /*
1062*5e7646d2SAndroid Build Coastguard Worker 	        * Note: con->command and con->options were set by is_cgi()...
1063*5e7646d2SAndroid Build Coastguard Worker 		*/
1064*5e7646d2SAndroid Build Coastguard Worker 
1065*5e7646d2SAndroid Build Coastguard Worker         	if (!cupsdSendCommand(con, con->command, con->options, 0))
1066*5e7646d2SAndroid Build Coastguard Worker 		{
1067*5e7646d2SAndroid Build Coastguard Worker 		  if (!cupsdSendError(con, HTTP_STATUS_NOT_FOUND, CUPSD_AUTH_NONE))
1068*5e7646d2SAndroid Build Coastguard Worker 		  {
1069*5e7646d2SAndroid Build Coastguard Worker 		    cupsdCloseClient(con);
1070*5e7646d2SAndroid Build Coastguard Worker 		    return;
1071*5e7646d2SAndroid Build Coastguard Worker 		  }
1072*5e7646d2SAndroid Build Coastguard Worker         	}
1073*5e7646d2SAndroid Build Coastguard Worker 		else
1074*5e7646d2SAndroid Build Coastguard Worker         	  cupsdLogRequest(con, HTTP_STATUS_OK);
1075*5e7646d2SAndroid Build Coastguard Worker 
1076*5e7646d2SAndroid Build Coastguard Worker 		if (httpGetVersion(con->http) <= HTTP_VERSION_1_0)
1077*5e7646d2SAndroid Build Coastguard Worker 		  httpSetKeepAlive(con->http, HTTP_KEEPALIVE_OFF);
1078*5e7646d2SAndroid Build Coastguard Worker 	        break;
1079*5e7646d2SAndroid Build Coastguard Worker 	      }
1080*5e7646d2SAndroid Build Coastguard Worker 
1081*5e7646d2SAndroid Build Coastguard Worker 	      if (!check_if_modified(con, &filestats))
1082*5e7646d2SAndroid Build Coastguard Worker               {
1083*5e7646d2SAndroid Build Coastguard Worker         	if (!cupsdSendError(con, HTTP_STATUS_NOT_MODIFIED, CUPSD_AUTH_NONE))
1084*5e7646d2SAndroid Build Coastguard Worker 		{
1085*5e7646d2SAndroid Build Coastguard Worker 		  cupsdCloseClient(con);
1086*5e7646d2SAndroid Build Coastguard Worker 		  return;
1087*5e7646d2SAndroid Build Coastguard Worker 		}
1088*5e7646d2SAndroid Build Coastguard Worker 	      }
1089*5e7646d2SAndroid Build Coastguard Worker 	      else
1090*5e7646d2SAndroid Build Coastguard Worker               {
1091*5e7646d2SAndroid Build Coastguard Worker 		if (type == NULL)
1092*5e7646d2SAndroid Build Coastguard Worker 	          strlcpy(line, "text/plain", sizeof(line));
1093*5e7646d2SAndroid Build Coastguard Worker 		else
1094*5e7646d2SAndroid Build Coastguard Worker 	          snprintf(line, sizeof(line), "%s/%s", type->super, type->type);
1095*5e7646d2SAndroid Build Coastguard Worker 
1096*5e7646d2SAndroid Build Coastguard Worker         	if (!write_file(con, HTTP_STATUS_OK, filename, line, &filestats))
1097*5e7646d2SAndroid Build Coastguard Worker 		{
1098*5e7646d2SAndroid Build Coastguard Worker 		  cupsdCloseClient(con);
1099*5e7646d2SAndroid Build Coastguard Worker 		  return;
1100*5e7646d2SAndroid Build Coastguard Worker 		}
1101*5e7646d2SAndroid Build Coastguard Worker 	      }
1102*5e7646d2SAndroid Build Coastguard Worker             }
1103*5e7646d2SAndroid Build Coastguard Worker             else if (!buf[0] && (!strncmp(con->uri, "/admin", 6) || !strncmp(con->uri, "/classes", 8) || !strncmp(con->uri, "/help", 5) || !strncmp(con->uri, "/jobs", 5) || !strncmp(con->uri, "/printers", 9)))
1104*5e7646d2SAndroid Build Coastguard Worker 	    {
1105*5e7646d2SAndroid Build Coastguard Worker 	      if (!WebInterface)
1106*5e7646d2SAndroid Build Coastguard Worker 	      {
1107*5e7646d2SAndroid Build Coastguard Worker 	       /*
1108*5e7646d2SAndroid Build Coastguard Worker 		* Web interface is disabled. Show an appropriate message...
1109*5e7646d2SAndroid Build Coastguard Worker 		*/
1110*5e7646d2SAndroid Build Coastguard Worker 
1111*5e7646d2SAndroid Build Coastguard Worker 		if (!cupsdSendError(con, HTTP_STATUS_CUPS_WEBIF_DISABLED, CUPSD_AUTH_NONE))
1112*5e7646d2SAndroid Build Coastguard Worker 		{
1113*5e7646d2SAndroid Build Coastguard Worker 		  cupsdCloseClient(con);
1114*5e7646d2SAndroid Build Coastguard Worker 		  return;
1115*5e7646d2SAndroid Build Coastguard Worker 		}
1116*5e7646d2SAndroid Build Coastguard Worker 
1117*5e7646d2SAndroid Build Coastguard Worker 		break;
1118*5e7646d2SAndroid Build Coastguard Worker 	      }
1119*5e7646d2SAndroid Build Coastguard Worker 
1120*5e7646d2SAndroid Build Coastguard Worker 	     /*
1121*5e7646d2SAndroid Build Coastguard Worker 	      * Send CGI output...
1122*5e7646d2SAndroid Build Coastguard Worker 	      */
1123*5e7646d2SAndroid Build Coastguard Worker 
1124*5e7646d2SAndroid Build Coastguard Worker               if (!strncmp(con->uri, "/admin", 6))
1125*5e7646d2SAndroid Build Coastguard Worker 	      {
1126*5e7646d2SAndroid Build Coastguard Worker 		cupsdSetStringf(&con->command, "%s/cgi-bin/admin.cgi", ServerBin);
1127*5e7646d2SAndroid Build Coastguard Worker 		cupsdSetString(&con->options, strchr(con->uri + 6, '?'));
1128*5e7646d2SAndroid Build Coastguard Worker 	      }
1129*5e7646d2SAndroid Build Coastguard Worker 	      else if (!strncmp(con->uri, "/classes", 8))
1130*5e7646d2SAndroid Build Coastguard Worker 	      {
1131*5e7646d2SAndroid Build Coastguard Worker 		cupsdSetStringf(&con->command, "%s/cgi-bin/classes.cgi", ServerBin);
1132*5e7646d2SAndroid Build Coastguard Worker                 if (con->uri[8] && con->uri[9])
1133*5e7646d2SAndroid Build Coastguard Worker 		  cupsdSetString(&con->options, con->uri + 8);
1134*5e7646d2SAndroid Build Coastguard Worker 		else
1135*5e7646d2SAndroid Build Coastguard Worker 		  cupsdSetString(&con->options, NULL);
1136*5e7646d2SAndroid Build Coastguard Worker 	      }
1137*5e7646d2SAndroid Build Coastguard Worker 	      else if (!strncmp(con->uri, "/jobs", 5))
1138*5e7646d2SAndroid Build Coastguard Worker 	      {
1139*5e7646d2SAndroid Build Coastguard Worker 		cupsdSetStringf(&con->command, "%s/cgi-bin/jobs.cgi", ServerBin);
1140*5e7646d2SAndroid Build Coastguard Worker                 if (con->uri[5] && con->uri[6])
1141*5e7646d2SAndroid Build Coastguard Worker 		  cupsdSetString(&con->options, con->uri + 5);
1142*5e7646d2SAndroid Build Coastguard Worker 		else
1143*5e7646d2SAndroid Build Coastguard Worker 		  cupsdSetString(&con->options, NULL);
1144*5e7646d2SAndroid Build Coastguard Worker 	      }
1145*5e7646d2SAndroid Build Coastguard Worker               else if (!strncmp(con->uri, "/printers", 9))
1146*5e7646d2SAndroid Build Coastguard Worker 	      {
1147*5e7646d2SAndroid Build Coastguard Worker 		cupsdSetStringf(&con->command, "%s/cgi-bin/printers.cgi", ServerBin);
1148*5e7646d2SAndroid Build Coastguard Worker                 if (con->uri[9] && con->uri[10])
1149*5e7646d2SAndroid Build Coastguard Worker 		  cupsdSetString(&con->options, con->uri + 9);
1150*5e7646d2SAndroid Build Coastguard Worker 		else
1151*5e7646d2SAndroid Build Coastguard Worker 		  cupsdSetString(&con->options, NULL);
1152*5e7646d2SAndroid Build Coastguard Worker 	      }
1153*5e7646d2SAndroid Build Coastguard Worker 	      else
1154*5e7646d2SAndroid Build Coastguard Worker 	      {
1155*5e7646d2SAndroid Build Coastguard Worker 		cupsdSetStringf(&con->command, "%s/cgi-bin/help.cgi", ServerBin);
1156*5e7646d2SAndroid Build Coastguard Worker                 if (con->uri[5] && con->uri[6])
1157*5e7646d2SAndroid Build Coastguard Worker 		  cupsdSetString(&con->options, con->uri + 5);
1158*5e7646d2SAndroid Build Coastguard Worker 		else
1159*5e7646d2SAndroid Build Coastguard Worker 		  cupsdSetString(&con->options, NULL);
1160*5e7646d2SAndroid Build Coastguard Worker 	      }
1161*5e7646d2SAndroid Build Coastguard Worker 
1162*5e7646d2SAndroid Build Coastguard Worker               if (!cupsdSendCommand(con, con->command, con->options, 0))
1163*5e7646d2SAndroid Build Coastguard Worker 	      {
1164*5e7646d2SAndroid Build Coastguard Worker 		if (!cupsdSendError(con, HTTP_STATUS_NOT_FOUND, CUPSD_AUTH_NONE))
1165*5e7646d2SAndroid Build Coastguard Worker 		{
1166*5e7646d2SAndroid Build Coastguard Worker 		  cupsdCloseClient(con);
1167*5e7646d2SAndroid Build Coastguard Worker 		  return;
1168*5e7646d2SAndroid Build Coastguard Worker 		}
1169*5e7646d2SAndroid Build Coastguard Worker               }
1170*5e7646d2SAndroid Build Coastguard Worker 	      else
1171*5e7646d2SAndroid Build Coastguard Worker         	cupsdLogRequest(con, HTTP_STATUS_OK);
1172*5e7646d2SAndroid Build Coastguard Worker 
1173*5e7646d2SAndroid Build Coastguard Worker 	      if (httpGetVersion(con->http) <= HTTP_VERSION_1_0)
1174*5e7646d2SAndroid Build Coastguard Worker 		httpSetKeepAlive(con->http, HTTP_KEEPALIVE_OFF);
1175*5e7646d2SAndroid Build Coastguard Worker 	    }
1176*5e7646d2SAndroid Build Coastguard Worker 	    else
1177*5e7646d2SAndroid Build Coastguard Worker 	    {
1178*5e7646d2SAndroid Build Coastguard Worker 	      if (!cupsdSendError(con, HTTP_STATUS_NOT_FOUND, CUPSD_AUTH_NONE))
1179*5e7646d2SAndroid Build Coastguard Worker 	      {
1180*5e7646d2SAndroid Build Coastguard Worker 		cupsdCloseClient(con);
1181*5e7646d2SAndroid Build Coastguard Worker 		return;
1182*5e7646d2SAndroid Build Coastguard Worker 	      }
1183*5e7646d2SAndroid Build Coastguard Worker 	    }
1184*5e7646d2SAndroid Build Coastguard Worker             break;
1185*5e7646d2SAndroid Build Coastguard Worker 
1186*5e7646d2SAndroid Build Coastguard Worker 	case HTTP_STATE_POST_RECV :
1187*5e7646d2SAndroid Build Coastguard Worker            /*
1188*5e7646d2SAndroid Build Coastguard Worker 	    * See if the POST request includes a Content-Length field, and if
1189*5e7646d2SAndroid Build Coastguard Worker 	    * so check the length against any limits that are set...
1190*5e7646d2SAndroid Build Coastguard Worker 	    */
1191*5e7646d2SAndroid Build Coastguard Worker 
1192*5e7646d2SAndroid Build Coastguard Worker             if (httpGetField(con->http, HTTP_FIELD_CONTENT_LENGTH)[0] && MaxRequestSize > 0 && httpGetLength2(con->http) > MaxRequestSize)
1193*5e7646d2SAndroid Build Coastguard Worker 	    {
1194*5e7646d2SAndroid Build Coastguard Worker 	     /*
1195*5e7646d2SAndroid Build Coastguard Worker 	      * Request too large...
1196*5e7646d2SAndroid Build Coastguard Worker 	      */
1197*5e7646d2SAndroid Build Coastguard Worker 
1198*5e7646d2SAndroid Build Coastguard Worker               if (!cupsdSendError(con, HTTP_STATUS_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
1199*5e7646d2SAndroid Build Coastguard Worker 	      {
1200*5e7646d2SAndroid Build Coastguard Worker 		cupsdCloseClient(con);
1201*5e7646d2SAndroid Build Coastguard Worker 		return;
1202*5e7646d2SAndroid Build Coastguard Worker 	      }
1203*5e7646d2SAndroid Build Coastguard Worker 
1204*5e7646d2SAndroid Build Coastguard Worker 	      break;
1205*5e7646d2SAndroid Build Coastguard Worker             }
1206*5e7646d2SAndroid Build Coastguard Worker 	    else if (httpGetLength2(con->http) < 0)
1207*5e7646d2SAndroid Build Coastguard Worker 	    {
1208*5e7646d2SAndroid Build Coastguard Worker 	     /*
1209*5e7646d2SAndroid Build Coastguard Worker 	      * Negative content lengths are invalid!
1210*5e7646d2SAndroid Build Coastguard Worker 	      */
1211*5e7646d2SAndroid Build Coastguard Worker 
1212*5e7646d2SAndroid Build Coastguard Worker               if (!cupsdSendError(con, HTTP_STATUS_BAD_REQUEST, CUPSD_AUTH_NONE))
1213*5e7646d2SAndroid Build Coastguard Worker 	      {
1214*5e7646d2SAndroid Build Coastguard Worker 		cupsdCloseClient(con);
1215*5e7646d2SAndroid Build Coastguard Worker 		return;
1216*5e7646d2SAndroid Build Coastguard Worker 	      }
1217*5e7646d2SAndroid Build Coastguard Worker 
1218*5e7646d2SAndroid Build Coastguard Worker 	      break;
1219*5e7646d2SAndroid Build Coastguard Worker 	    }
1220*5e7646d2SAndroid Build Coastguard Worker 
1221*5e7646d2SAndroid Build Coastguard Worker            /*
1222*5e7646d2SAndroid Build Coastguard Worker 	    * See what kind of POST request this is; for IPP requests the
1223*5e7646d2SAndroid Build Coastguard Worker 	    * content-type field will be "application/ipp"...
1224*5e7646d2SAndroid Build Coastguard Worker 	    */
1225*5e7646d2SAndroid Build Coastguard Worker 
1226*5e7646d2SAndroid Build Coastguard Worker 	    if (!strcmp(httpGetField(con->http, HTTP_FIELD_CONTENT_TYPE), "application/ipp"))
1227*5e7646d2SAndroid Build Coastguard Worker 	    {
1228*5e7646d2SAndroid Build Coastguard Worker               con->request = ippNew();
1229*5e7646d2SAndroid Build Coastguard Worker               break;
1230*5e7646d2SAndroid Build Coastguard Worker             }
1231*5e7646d2SAndroid Build Coastguard Worker             else if (!WebInterface)
1232*5e7646d2SAndroid Build Coastguard Worker 	    {
1233*5e7646d2SAndroid Build Coastguard Worker 	     /*
1234*5e7646d2SAndroid Build Coastguard Worker 	      * Web interface is disabled. Show an appropriate message...
1235*5e7646d2SAndroid Build Coastguard Worker 	      */
1236*5e7646d2SAndroid Build Coastguard Worker 
1237*5e7646d2SAndroid Build Coastguard Worker 	      if (!cupsdSendError(con, HTTP_STATUS_CUPS_WEBIF_DISABLED, CUPSD_AUTH_NONE))
1238*5e7646d2SAndroid Build Coastguard Worker 	      {
1239*5e7646d2SAndroid Build Coastguard Worker 		cupsdCloseClient(con);
1240*5e7646d2SAndroid Build Coastguard Worker 		return;
1241*5e7646d2SAndroid Build Coastguard Worker 	      }
1242*5e7646d2SAndroid Build Coastguard Worker 
1243*5e7646d2SAndroid Build Coastguard Worker 	      break;
1244*5e7646d2SAndroid Build Coastguard Worker 	    }
1245*5e7646d2SAndroid Build Coastguard Worker 
1246*5e7646d2SAndroid Build Coastguard Worker 	    if ((filename = get_file(con, &filestats, buf, sizeof(buf))) != NULL)
1247*5e7646d2SAndroid Build Coastguard Worker             {
1248*5e7646d2SAndroid Build Coastguard Worker 	     /*
1249*5e7646d2SAndroid Build Coastguard Worker 	      * POST to a file...
1250*5e7646d2SAndroid Build Coastguard Worker 	      */
1251*5e7646d2SAndroid Build Coastguard Worker 
1252*5e7646d2SAndroid Build Coastguard Worker 	      type = mimeFileType(MimeDatabase, filename, NULL, NULL);
1253*5e7646d2SAndroid Build Coastguard Worker 
1254*5e7646d2SAndroid Build Coastguard Worker               if (!is_cgi(con, filename, &filestats, type))
1255*5e7646d2SAndroid Build Coastguard Worker 	      {
1256*5e7646d2SAndroid Build Coastguard Worker 	       /*
1257*5e7646d2SAndroid Build Coastguard Worker 	        * Only POST to CGI's...
1258*5e7646d2SAndroid Build Coastguard Worker 		*/
1259*5e7646d2SAndroid Build Coastguard Worker 
1260*5e7646d2SAndroid Build Coastguard Worker 		if (!cupsdSendError(con, HTTP_STATUS_UNAUTHORIZED, CUPSD_AUTH_NONE))
1261*5e7646d2SAndroid Build Coastguard Worker 		{
1262*5e7646d2SAndroid Build Coastguard Worker 		  cupsdCloseClient(con);
1263*5e7646d2SAndroid Build Coastguard Worker 		  return;
1264*5e7646d2SAndroid Build Coastguard Worker 		}
1265*5e7646d2SAndroid Build Coastguard Worker 	      }
1266*5e7646d2SAndroid Build Coastguard Worker             }
1267*5e7646d2SAndroid Build Coastguard Worker 	    else if (!strncmp(con->uri, "/admin", 6) || !strncmp(con->uri, "/printers", 9) ||  !strncmp(con->uri, "/classes", 8) || !strncmp(con->uri, "/help", 5) || !strncmp(con->uri, "/jobs", 5))
1268*5e7646d2SAndroid Build Coastguard Worker 	    {
1269*5e7646d2SAndroid Build Coastguard Worker 	     /*
1270*5e7646d2SAndroid Build Coastguard Worker 	      * CGI request...
1271*5e7646d2SAndroid Build Coastguard Worker 	      */
1272*5e7646d2SAndroid Build Coastguard Worker 
1273*5e7646d2SAndroid Build Coastguard Worker               if (!strncmp(con->uri, "/admin", 6))
1274*5e7646d2SAndroid Build Coastguard Worker 	      {
1275*5e7646d2SAndroid Build Coastguard Worker 		cupsdSetStringf(&con->command, "%s/cgi-bin/admin.cgi", ServerBin);
1276*5e7646d2SAndroid Build Coastguard Worker 		cupsdSetString(&con->options, strchr(con->uri + 6, '?'));
1277*5e7646d2SAndroid Build Coastguard Worker 	      }
1278*5e7646d2SAndroid Build Coastguard Worker               else if (!strncmp(con->uri, "/printers", 9))
1279*5e7646d2SAndroid Build Coastguard Worker 	      {
1280*5e7646d2SAndroid Build Coastguard Worker 		cupsdSetStringf(&con->command, "%s/cgi-bin/printers.cgi", ServerBin);
1281*5e7646d2SAndroid Build Coastguard Worker                 if (con->uri[9] && con->uri[10])
1282*5e7646d2SAndroid Build Coastguard Worker 		  cupsdSetString(&con->options, con->uri + 9);
1283*5e7646d2SAndroid Build Coastguard Worker 		else
1284*5e7646d2SAndroid Build Coastguard Worker 		  cupsdSetString(&con->options, NULL);
1285*5e7646d2SAndroid Build Coastguard Worker 	      }
1286*5e7646d2SAndroid Build Coastguard Worker 	      else if (!strncmp(con->uri, "/classes", 8))
1287*5e7646d2SAndroid Build Coastguard Worker 	      {
1288*5e7646d2SAndroid Build Coastguard Worker 		cupsdSetStringf(&con->command, "%s/cgi-bin/classes.cgi", ServerBin);
1289*5e7646d2SAndroid Build Coastguard Worker                 if (con->uri[8] && con->uri[9])
1290*5e7646d2SAndroid Build Coastguard Worker 		  cupsdSetString(&con->options, con->uri + 8);
1291*5e7646d2SAndroid Build Coastguard Worker 		else
1292*5e7646d2SAndroid Build Coastguard Worker 		  cupsdSetString(&con->options, NULL);
1293*5e7646d2SAndroid Build Coastguard Worker 	      }
1294*5e7646d2SAndroid Build Coastguard Worker 	      else if (!strncmp(con->uri, "/jobs", 5))
1295*5e7646d2SAndroid Build Coastguard Worker 	      {
1296*5e7646d2SAndroid Build Coastguard Worker 		cupsdSetStringf(&con->command, "%s/cgi-bin/jobs.cgi", ServerBin);
1297*5e7646d2SAndroid Build Coastguard Worker                 if (con->uri[5] && con->uri[6])
1298*5e7646d2SAndroid Build Coastguard Worker 		  cupsdSetString(&con->options, con->uri + 5);
1299*5e7646d2SAndroid Build Coastguard Worker 		else
1300*5e7646d2SAndroid Build Coastguard Worker 		  cupsdSetString(&con->options, NULL);
1301*5e7646d2SAndroid Build Coastguard Worker 	      }
1302*5e7646d2SAndroid Build Coastguard Worker 	      else
1303*5e7646d2SAndroid Build Coastguard Worker 	      {
1304*5e7646d2SAndroid Build Coastguard Worker 		cupsdSetStringf(&con->command, "%s/cgi-bin/help.cgi", ServerBin);
1305*5e7646d2SAndroid Build Coastguard Worker                 if (con->uri[5] && con->uri[6])
1306*5e7646d2SAndroid Build Coastguard Worker 		  cupsdSetString(&con->options, con->uri + 5);
1307*5e7646d2SAndroid Build Coastguard Worker 		else
1308*5e7646d2SAndroid Build Coastguard Worker 		  cupsdSetString(&con->options, NULL);
1309*5e7646d2SAndroid Build Coastguard Worker 	      }
1310*5e7646d2SAndroid Build Coastguard Worker 
1311*5e7646d2SAndroid Build Coastguard Worker 	      if (httpGetVersion(con->http) <= HTTP_VERSION_1_0)
1312*5e7646d2SAndroid Build Coastguard Worker 		httpSetKeepAlive(con->http, HTTP_KEEPALIVE_OFF);
1313*5e7646d2SAndroid Build Coastguard Worker 	    }
1314*5e7646d2SAndroid Build Coastguard Worker 	    else
1315*5e7646d2SAndroid Build Coastguard Worker 	    {
1316*5e7646d2SAndroid Build Coastguard Worker 	      if (!cupsdSendError(con, HTTP_STATUS_NOT_FOUND, CUPSD_AUTH_NONE))
1317*5e7646d2SAndroid Build Coastguard Worker 	      {
1318*5e7646d2SAndroid Build Coastguard Worker 		cupsdCloseClient(con);
1319*5e7646d2SAndroid Build Coastguard Worker 		return;
1320*5e7646d2SAndroid Build Coastguard Worker 	      }
1321*5e7646d2SAndroid Build Coastguard Worker 	    }
1322*5e7646d2SAndroid Build Coastguard Worker 	    break;
1323*5e7646d2SAndroid Build Coastguard Worker 
1324*5e7646d2SAndroid Build Coastguard Worker 	case HTTP_STATE_PUT_RECV :
1325*5e7646d2SAndroid Build Coastguard Worker 	   /*
1326*5e7646d2SAndroid Build Coastguard Worker 	    * Validate the resource name...
1327*5e7646d2SAndroid Build Coastguard Worker 	    */
1328*5e7646d2SAndroid Build Coastguard Worker 
1329*5e7646d2SAndroid Build Coastguard Worker             if (strcmp(con->uri, "/admin/conf/cupsd.conf"))
1330*5e7646d2SAndroid Build Coastguard Worker 	    {
1331*5e7646d2SAndroid Build Coastguard Worker 	     /*
1332*5e7646d2SAndroid Build Coastguard Worker 	      * PUT can only be done to the cupsd.conf file...
1333*5e7646d2SAndroid Build Coastguard Worker 	      */
1334*5e7646d2SAndroid Build Coastguard Worker 
1335*5e7646d2SAndroid Build Coastguard Worker 	      cupsdLogClient(con, CUPSD_LOG_ERROR, "Disallowed PUT request for \"%s\".", con->uri);
1336*5e7646d2SAndroid Build Coastguard Worker 
1337*5e7646d2SAndroid Build Coastguard Worker 	      if (!cupsdSendError(con, HTTP_STATUS_FORBIDDEN, CUPSD_AUTH_NONE))
1338*5e7646d2SAndroid Build Coastguard Worker 	      {
1339*5e7646d2SAndroid Build Coastguard Worker 		cupsdCloseClient(con);
1340*5e7646d2SAndroid Build Coastguard Worker 		return;
1341*5e7646d2SAndroid Build Coastguard Worker 	      }
1342*5e7646d2SAndroid Build Coastguard Worker 
1343*5e7646d2SAndroid Build Coastguard Worker 	      break;
1344*5e7646d2SAndroid Build Coastguard Worker 	    }
1345*5e7646d2SAndroid Build Coastguard Worker 
1346*5e7646d2SAndroid Build Coastguard Worker            /*
1347*5e7646d2SAndroid Build Coastguard Worker 	    * See if the PUT request includes a Content-Length field, and if
1348*5e7646d2SAndroid Build Coastguard Worker 	    * so check the length against any limits that are set...
1349*5e7646d2SAndroid Build Coastguard Worker 	    */
1350*5e7646d2SAndroid Build Coastguard Worker 
1351*5e7646d2SAndroid Build Coastguard Worker             if (httpGetField(con->http, HTTP_FIELD_CONTENT_LENGTH)[0] && MaxRequestSize > 0 && httpGetLength2(con->http) > MaxRequestSize)
1352*5e7646d2SAndroid Build Coastguard Worker 	    {
1353*5e7646d2SAndroid Build Coastguard Worker 	     /*
1354*5e7646d2SAndroid Build Coastguard Worker 	      * Request too large...
1355*5e7646d2SAndroid Build Coastguard Worker 	      */
1356*5e7646d2SAndroid Build Coastguard Worker 
1357*5e7646d2SAndroid Build Coastguard Worker               if (!cupsdSendError(con, HTTP_STATUS_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
1358*5e7646d2SAndroid Build Coastguard Worker 	      {
1359*5e7646d2SAndroid Build Coastguard Worker 		cupsdCloseClient(con);
1360*5e7646d2SAndroid Build Coastguard Worker 		return;
1361*5e7646d2SAndroid Build Coastguard Worker 	      }
1362*5e7646d2SAndroid Build Coastguard Worker 
1363*5e7646d2SAndroid Build Coastguard Worker 	      break;
1364*5e7646d2SAndroid Build Coastguard Worker             }
1365*5e7646d2SAndroid Build Coastguard Worker 	    else if (httpGetLength2(con->http) < 0)
1366*5e7646d2SAndroid Build Coastguard Worker 	    {
1367*5e7646d2SAndroid Build Coastguard Worker 	     /*
1368*5e7646d2SAndroid Build Coastguard Worker 	      * Negative content lengths are invalid!
1369*5e7646d2SAndroid Build Coastguard Worker 	      */
1370*5e7646d2SAndroid Build Coastguard Worker 
1371*5e7646d2SAndroid Build Coastguard Worker               if (!cupsdSendError(con, HTTP_STATUS_BAD_REQUEST, CUPSD_AUTH_NONE))
1372*5e7646d2SAndroid Build Coastguard Worker 	      {
1373*5e7646d2SAndroid Build Coastguard Worker 		cupsdCloseClient(con);
1374*5e7646d2SAndroid Build Coastguard Worker 		return;
1375*5e7646d2SAndroid Build Coastguard Worker 	      }
1376*5e7646d2SAndroid Build Coastguard Worker 
1377*5e7646d2SAndroid Build Coastguard Worker 	      break;
1378*5e7646d2SAndroid Build Coastguard Worker 	    }
1379*5e7646d2SAndroid Build Coastguard Worker 
1380*5e7646d2SAndroid Build Coastguard Worker            /*
1381*5e7646d2SAndroid Build Coastguard Worker 	    * Open a temporary file to hold the request...
1382*5e7646d2SAndroid Build Coastguard Worker 	    */
1383*5e7646d2SAndroid Build Coastguard Worker 
1384*5e7646d2SAndroid Build Coastguard Worker             cupsdSetStringf(&con->filename, "%s/%08x", RequestRoot, request_id ++);
1385*5e7646d2SAndroid Build Coastguard Worker 	    con->file = open(con->filename, O_WRONLY | O_CREAT | O_TRUNC, 0640);
1386*5e7646d2SAndroid Build Coastguard Worker 
1387*5e7646d2SAndroid Build Coastguard Worker 	    if (con->file < 0)
1388*5e7646d2SAndroid Build Coastguard Worker 	    {
1389*5e7646d2SAndroid Build Coastguard Worker 	      cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to create request file \"%s\": %s", con->filename, strerror(errno));
1390*5e7646d2SAndroid Build Coastguard Worker 
1391*5e7646d2SAndroid Build Coastguard Worker 	      if (!cupsdSendError(con, HTTP_STATUS_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
1392*5e7646d2SAndroid Build Coastguard Worker 	      {
1393*5e7646d2SAndroid Build Coastguard Worker 		cupsdCloseClient(con);
1394*5e7646d2SAndroid Build Coastguard Worker 		return;
1395*5e7646d2SAndroid Build Coastguard Worker 	      }
1396*5e7646d2SAndroid Build Coastguard Worker 	    }
1397*5e7646d2SAndroid Build Coastguard Worker 
1398*5e7646d2SAndroid Build Coastguard Worker 	    fchmod(con->file, 0640);
1399*5e7646d2SAndroid Build Coastguard Worker 	    fchown(con->file, RunUser, Group);
1400*5e7646d2SAndroid Build Coastguard Worker 	    fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
1401*5e7646d2SAndroid Build Coastguard Worker 	    break;
1402*5e7646d2SAndroid Build Coastguard Worker 
1403*5e7646d2SAndroid Build Coastguard Worker 	case HTTP_STATE_DELETE :
1404*5e7646d2SAndroid Build Coastguard Worker 	case HTTP_STATE_TRACE :
1405*5e7646d2SAndroid Build Coastguard Worker             cupsdSendError(con, HTTP_STATUS_NOT_IMPLEMENTED, CUPSD_AUTH_NONE);
1406*5e7646d2SAndroid Build Coastguard Worker 	    cupsdCloseClient(con);
1407*5e7646d2SAndroid Build Coastguard Worker 	    return;
1408*5e7646d2SAndroid Build Coastguard Worker 
1409*5e7646d2SAndroid Build Coastguard Worker 	case HTTP_STATE_HEAD :
1410*5e7646d2SAndroid Build Coastguard Worker             if ((filename = get_file(con, &filestats, buf, sizeof(buf))) != NULL)
1411*5e7646d2SAndroid Build Coastguard Worker             {
1412*5e7646d2SAndroid Build Coastguard Worker 	      if (!check_if_modified(con, &filestats))
1413*5e7646d2SAndroid Build Coastguard Worker 	      {
1414*5e7646d2SAndroid Build Coastguard Worker 		if (!cupsdSendError(con, HTTP_STATUS_NOT_MODIFIED, CUPSD_AUTH_NONE))
1415*5e7646d2SAndroid Build Coastguard Worker 		{
1416*5e7646d2SAndroid Build Coastguard Worker 		  cupsdCloseClient(con);
1417*5e7646d2SAndroid Build Coastguard Worker 		  return;
1418*5e7646d2SAndroid Build Coastguard Worker 		}
1419*5e7646d2SAndroid Build Coastguard Worker 
1420*5e7646d2SAndroid Build Coastguard Worker 		cupsdLogRequest(con, HTTP_STATUS_NOT_MODIFIED);
1421*5e7646d2SAndroid Build Coastguard Worker 	      }
1422*5e7646d2SAndroid Build Coastguard Worker 	      else
1423*5e7646d2SAndroid Build Coastguard Worker 	      {
1424*5e7646d2SAndroid Build Coastguard Worker 	       /*
1425*5e7646d2SAndroid Build Coastguard Worker 		* Serve a file...
1426*5e7646d2SAndroid Build Coastguard Worker 		*/
1427*5e7646d2SAndroid Build Coastguard Worker 
1428*5e7646d2SAndroid Build Coastguard Worker 		type = mimeFileType(MimeDatabase, filename, NULL, NULL);
1429*5e7646d2SAndroid Build Coastguard Worker 		if (type == NULL)
1430*5e7646d2SAndroid Build Coastguard Worker 		  strlcpy(line, "text/plain", sizeof(line));
1431*5e7646d2SAndroid Build Coastguard Worker 		else
1432*5e7646d2SAndroid Build Coastguard Worker 		  snprintf(line, sizeof(line), "%s/%s", type->super, type->type);
1433*5e7646d2SAndroid Build Coastguard Worker 
1434*5e7646d2SAndroid Build Coastguard Worker 		httpClearFields(con->http);
1435*5e7646d2SAndroid Build Coastguard Worker 
1436*5e7646d2SAndroid Build Coastguard Worker 		httpSetField(con->http, HTTP_FIELD_LAST_MODIFIED, httpGetDateString(filestats.st_mtime));
1437*5e7646d2SAndroid Build Coastguard Worker 		httpSetLength(con->http, (size_t)filestats.st_size);
1438*5e7646d2SAndroid Build Coastguard Worker 
1439*5e7646d2SAndroid Build Coastguard Worker 		if (!cupsdSendHeader(con, HTTP_STATUS_OK, line, CUPSD_AUTH_NONE))
1440*5e7646d2SAndroid Build Coastguard Worker 		{
1441*5e7646d2SAndroid Build Coastguard Worker 		  cupsdCloseClient(con);
1442*5e7646d2SAndroid Build Coastguard Worker 		  return;
1443*5e7646d2SAndroid Build Coastguard Worker 		}
1444*5e7646d2SAndroid Build Coastguard Worker 
1445*5e7646d2SAndroid Build Coastguard Worker 		cupsdLogRequest(con, HTTP_STATUS_OK);
1446*5e7646d2SAndroid Build Coastguard Worker 	      }
1447*5e7646d2SAndroid Build Coastguard Worker             }
1448*5e7646d2SAndroid Build Coastguard Worker 	    else if (!WebInterface)
1449*5e7646d2SAndroid Build Coastguard Worker 	    {
1450*5e7646d2SAndroid Build Coastguard Worker               httpClearFields(con->http);
1451*5e7646d2SAndroid Build Coastguard Worker 
1452*5e7646d2SAndroid Build Coastguard Worker               if (!cupsdSendHeader(con, HTTP_STATUS_OK, NULL, CUPSD_AUTH_NONE))
1453*5e7646d2SAndroid Build Coastguard Worker 	      {
1454*5e7646d2SAndroid Build Coastguard Worker 		cupsdCloseClient(con);
1455*5e7646d2SAndroid Build Coastguard Worker 		return;
1456*5e7646d2SAndroid Build Coastguard Worker 	      }
1457*5e7646d2SAndroid Build Coastguard Worker 
1458*5e7646d2SAndroid Build Coastguard Worker               cupsdLogRequest(con, HTTP_STATUS_OK);
1459*5e7646d2SAndroid Build Coastguard Worker 	      break;
1460*5e7646d2SAndroid Build Coastguard Worker 	    }
1461*5e7646d2SAndroid Build Coastguard Worker 
1462*5e7646d2SAndroid Build Coastguard Worker 	    if (!buf[0] && (!strncmp(con->uri, "/admin", 6) || !strncmp(con->uri, "/classes", 8) || !strncmp(con->uri, "/help", 5) || !strncmp(con->uri, "/jobs", 5) || !strncmp(con->uri, "/printers", 9)))
1463*5e7646d2SAndroid Build Coastguard Worker 	    {
1464*5e7646d2SAndroid Build Coastguard Worker 	     /*
1465*5e7646d2SAndroid Build Coastguard Worker 	      * CGI output...
1466*5e7646d2SAndroid Build Coastguard Worker 	      */
1467*5e7646d2SAndroid Build Coastguard Worker 
1468*5e7646d2SAndroid Build Coastguard Worker               httpClearFields(con->http);
1469*5e7646d2SAndroid Build Coastguard Worker 
1470*5e7646d2SAndroid Build Coastguard Worker               if (!cupsdSendHeader(con, HTTP_STATUS_OK, "text/html", CUPSD_AUTH_NONE))
1471*5e7646d2SAndroid Build Coastguard Worker 	      {
1472*5e7646d2SAndroid Build Coastguard Worker 		cupsdCloseClient(con);
1473*5e7646d2SAndroid Build Coastguard Worker 		return;
1474*5e7646d2SAndroid Build Coastguard Worker 	      }
1475*5e7646d2SAndroid Build Coastguard Worker 
1476*5e7646d2SAndroid Build Coastguard Worker               cupsdLogRequest(con, HTTP_STATUS_OK);
1477*5e7646d2SAndroid Build Coastguard Worker 	    }
1478*5e7646d2SAndroid Build Coastguard Worker 	    else
1479*5e7646d2SAndroid Build Coastguard Worker 	    {
1480*5e7646d2SAndroid Build Coastguard Worker               httpClearFields(con->http);
1481*5e7646d2SAndroid Build Coastguard Worker 
1482*5e7646d2SAndroid Build Coastguard Worker 	      if (!cupsdSendHeader(con, HTTP_STATUS_NOT_FOUND, "text/html", CUPSD_AUTH_NONE))
1483*5e7646d2SAndroid Build Coastguard Worker 	      {
1484*5e7646d2SAndroid Build Coastguard Worker 		cupsdCloseClient(con);
1485*5e7646d2SAndroid Build Coastguard Worker 		return;
1486*5e7646d2SAndroid Build Coastguard Worker 	      }
1487*5e7646d2SAndroid Build Coastguard Worker 
1488*5e7646d2SAndroid Build Coastguard Worker               cupsdLogRequest(con, HTTP_STATUS_NOT_FOUND);
1489*5e7646d2SAndroid Build Coastguard Worker 	    }
1490*5e7646d2SAndroid Build Coastguard Worker             break;
1491*5e7646d2SAndroid Build Coastguard Worker 
1492*5e7646d2SAndroid Build Coastguard Worker 	default :
1493*5e7646d2SAndroid Build Coastguard Worker             break; /* Anti-compiler-warning-code */
1494*5e7646d2SAndroid Build Coastguard Worker       }
1495*5e7646d2SAndroid Build Coastguard Worker     }
1496*5e7646d2SAndroid Build Coastguard Worker   }
1497*5e7646d2SAndroid Build Coastguard Worker 
1498*5e7646d2SAndroid Build Coastguard Worker  /*
1499*5e7646d2SAndroid Build Coastguard Worker   * Handle any incoming data...
1500*5e7646d2SAndroid Build Coastguard Worker   */
1501*5e7646d2SAndroid Build Coastguard Worker 
1502*5e7646d2SAndroid Build Coastguard Worker   switch (httpGetState(con->http))
1503*5e7646d2SAndroid Build Coastguard Worker   {
1504*5e7646d2SAndroid Build Coastguard Worker     case HTTP_STATE_PUT_RECV :
1505*5e7646d2SAndroid Build Coastguard Worker         do
1506*5e7646d2SAndroid Build Coastguard Worker 	{
1507*5e7646d2SAndroid Build Coastguard Worker           if ((bytes = httpRead2(con->http, line, sizeof(line))) < 0)
1508*5e7646d2SAndroid Build Coastguard Worker 	  {
1509*5e7646d2SAndroid Build Coastguard Worker 	    if (httpError(con->http) && httpError(con->http) != EPIPE)
1510*5e7646d2SAndroid Build Coastguard Worker 	      cupsdLogClient(con, CUPSD_LOG_DEBUG,
1511*5e7646d2SAndroid Build Coastguard Worker                              "HTTP_STATE_PUT_RECV Closing for error %d (%s)",
1512*5e7646d2SAndroid Build Coastguard Worker                              httpError(con->http), strerror(httpError(con->http)));
1513*5e7646d2SAndroid Build Coastguard Worker 	    else
1514*5e7646d2SAndroid Build Coastguard Worker 	      cupsdLogClient(con, CUPSD_LOG_DEBUG,
1515*5e7646d2SAndroid Build Coastguard Worker 			     "HTTP_STATE_PUT_RECV Closing on EOF.");
1516*5e7646d2SAndroid Build Coastguard Worker 
1517*5e7646d2SAndroid Build Coastguard Worker 	    cupsdCloseClient(con);
1518*5e7646d2SAndroid Build Coastguard Worker 	    return;
1519*5e7646d2SAndroid Build Coastguard Worker 	  }
1520*5e7646d2SAndroid Build Coastguard Worker 	  else if (bytes > 0)
1521*5e7646d2SAndroid Build Coastguard Worker 	  {
1522*5e7646d2SAndroid Build Coastguard Worker 	    con->bytes += bytes;
1523*5e7646d2SAndroid Build Coastguard Worker 
1524*5e7646d2SAndroid Build Coastguard Worker             if (MaxRequestSize > 0 && con->bytes > MaxRequestSize)
1525*5e7646d2SAndroid Build Coastguard Worker             {
1526*5e7646d2SAndroid Build Coastguard Worker 	      close(con->file);
1527*5e7646d2SAndroid Build Coastguard Worker 	      con->file = -1;
1528*5e7646d2SAndroid Build Coastguard Worker 	      unlink(con->filename);
1529*5e7646d2SAndroid Build Coastguard Worker 	      cupsdClearString(&con->filename);
1530*5e7646d2SAndroid Build Coastguard Worker 
1531*5e7646d2SAndroid Build Coastguard Worker               if (!cupsdSendError(con, HTTP_STATUS_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
1532*5e7646d2SAndroid Build Coastguard Worker 	      {
1533*5e7646d2SAndroid Build Coastguard Worker 		cupsdCloseClient(con);
1534*5e7646d2SAndroid Build Coastguard Worker 		return;
1535*5e7646d2SAndroid Build Coastguard Worker 	      }
1536*5e7646d2SAndroid Build Coastguard Worker             }
1537*5e7646d2SAndroid Build Coastguard Worker 
1538*5e7646d2SAndroid Build Coastguard Worker             if (write(con->file, line, (size_t)bytes) < bytes)
1539*5e7646d2SAndroid Build Coastguard Worker 	    {
1540*5e7646d2SAndroid Build Coastguard Worker               cupsdLogClient(con, CUPSD_LOG_ERROR,
1541*5e7646d2SAndroid Build Coastguard Worker 	                     "Unable to write %d bytes to \"%s\": %s", bytes,
1542*5e7646d2SAndroid Build Coastguard Worker                              con->filename, strerror(errno));
1543*5e7646d2SAndroid Build Coastguard Worker 
1544*5e7646d2SAndroid Build Coastguard Worker 	      close(con->file);
1545*5e7646d2SAndroid Build Coastguard Worker 	      con->file = -1;
1546*5e7646d2SAndroid Build Coastguard Worker 	      unlink(con->filename);
1547*5e7646d2SAndroid Build Coastguard Worker 	      cupsdClearString(&con->filename);
1548*5e7646d2SAndroid Build Coastguard Worker 
1549*5e7646d2SAndroid Build Coastguard Worker               if (!cupsdSendError(con, HTTP_STATUS_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
1550*5e7646d2SAndroid Build Coastguard Worker 	      {
1551*5e7646d2SAndroid Build Coastguard Worker 		cupsdCloseClient(con);
1552*5e7646d2SAndroid Build Coastguard Worker 		return;
1553*5e7646d2SAndroid Build Coastguard Worker 	      }
1554*5e7646d2SAndroid Build Coastguard Worker 	    }
1555*5e7646d2SAndroid Build Coastguard Worker 	  }
1556*5e7646d2SAndroid Build Coastguard Worker           else if (httpGetState(con->http) == HTTP_STATE_PUT_RECV)
1557*5e7646d2SAndroid Build Coastguard Worker           {
1558*5e7646d2SAndroid Build Coastguard Worker             cupsdCloseClient(con);
1559*5e7646d2SAndroid Build Coastguard Worker             return;
1560*5e7646d2SAndroid Build Coastguard Worker           }
1561*5e7646d2SAndroid Build Coastguard Worker         }
1562*5e7646d2SAndroid Build Coastguard Worker 	while (httpGetState(con->http) == HTTP_STATE_PUT_RECV && httpGetReady(con->http));
1563*5e7646d2SAndroid Build Coastguard Worker 
1564*5e7646d2SAndroid Build Coastguard Worker         if (httpGetState(con->http) == HTTP_STATE_STATUS)
1565*5e7646d2SAndroid Build Coastguard Worker 	{
1566*5e7646d2SAndroid Build Coastguard Worker 	 /*
1567*5e7646d2SAndroid Build Coastguard Worker 	  * End of file, see how big it is...
1568*5e7646d2SAndroid Build Coastguard Worker 	  */
1569*5e7646d2SAndroid Build Coastguard Worker 
1570*5e7646d2SAndroid Build Coastguard Worker 	  fstat(con->file, &filestats);
1571*5e7646d2SAndroid Build Coastguard Worker 
1572*5e7646d2SAndroid Build Coastguard Worker 	  close(con->file);
1573*5e7646d2SAndroid Build Coastguard Worker 	  con->file = -1;
1574*5e7646d2SAndroid Build Coastguard Worker 
1575*5e7646d2SAndroid Build Coastguard Worker           if (filestats.st_size > MaxRequestSize &&
1576*5e7646d2SAndroid Build Coastguard Worker 	      MaxRequestSize > 0)
1577*5e7646d2SAndroid Build Coastguard Worker 	  {
1578*5e7646d2SAndroid Build Coastguard Worker 	   /*
1579*5e7646d2SAndroid Build Coastguard Worker 	    * Request is too big; remove it and send an error...
1580*5e7646d2SAndroid Build Coastguard Worker 	    */
1581*5e7646d2SAndroid Build Coastguard Worker 
1582*5e7646d2SAndroid Build Coastguard Worker 	    unlink(con->filename);
1583*5e7646d2SAndroid Build Coastguard Worker 	    cupsdClearString(&con->filename);
1584*5e7646d2SAndroid Build Coastguard Worker 
1585*5e7646d2SAndroid Build Coastguard Worker             if (!cupsdSendError(con, HTTP_STATUS_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
1586*5e7646d2SAndroid Build Coastguard Worker 	    {
1587*5e7646d2SAndroid Build Coastguard Worker 	      cupsdCloseClient(con);
1588*5e7646d2SAndroid Build Coastguard Worker 	      return;
1589*5e7646d2SAndroid Build Coastguard Worker 	    }
1590*5e7646d2SAndroid Build Coastguard Worker 	  }
1591*5e7646d2SAndroid Build Coastguard Worker 
1592*5e7646d2SAndroid Build Coastguard Worker          /*
1593*5e7646d2SAndroid Build Coastguard Worker 	  * Install the configuration file...
1594*5e7646d2SAndroid Build Coastguard Worker 	  */
1595*5e7646d2SAndroid Build Coastguard Worker 
1596*5e7646d2SAndroid Build Coastguard Worker           status = install_cupsd_conf(con);
1597*5e7646d2SAndroid Build Coastguard Worker 
1598*5e7646d2SAndroid Build Coastguard Worker          /*
1599*5e7646d2SAndroid Build Coastguard Worker 	  * Return the status to the client...
1600*5e7646d2SAndroid Build Coastguard Worker 	  */
1601*5e7646d2SAndroid Build Coastguard Worker 
1602*5e7646d2SAndroid Build Coastguard Worker           if (!cupsdSendError(con, status, CUPSD_AUTH_NONE))
1603*5e7646d2SAndroid Build Coastguard Worker 	  {
1604*5e7646d2SAndroid Build Coastguard Worker 	    cupsdCloseClient(con);
1605*5e7646d2SAndroid Build Coastguard Worker 	    return;
1606*5e7646d2SAndroid Build Coastguard Worker 	  }
1607*5e7646d2SAndroid Build Coastguard Worker 	}
1608*5e7646d2SAndroid Build Coastguard Worker         break;
1609*5e7646d2SAndroid Build Coastguard Worker 
1610*5e7646d2SAndroid Build Coastguard Worker     case HTTP_STATE_POST_RECV :
1611*5e7646d2SAndroid Build Coastguard Worker         do
1612*5e7646d2SAndroid Build Coastguard Worker 	{
1613*5e7646d2SAndroid Build Coastguard Worker           if (con->request && con->file < 0)
1614*5e7646d2SAndroid Build Coastguard Worker 	  {
1615*5e7646d2SAndroid Build Coastguard Worker 	   /*
1616*5e7646d2SAndroid Build Coastguard Worker 	    * Grab any request data from the connection...
1617*5e7646d2SAndroid Build Coastguard Worker 	    */
1618*5e7646d2SAndroid Build Coastguard Worker 
1619*5e7646d2SAndroid Build Coastguard Worker 	    if (!httpWait(con->http, 0))
1620*5e7646d2SAndroid Build Coastguard Worker 	      return;
1621*5e7646d2SAndroid Build Coastguard Worker 
1622*5e7646d2SAndroid Build Coastguard Worker 	    if ((ipp_state = ippRead(con->http, con->request)) == IPP_STATE_ERROR)
1623*5e7646d2SAndroid Build Coastguard Worker 	    {
1624*5e7646d2SAndroid Build Coastguard Worker               cupsdLogClient(con, CUPSD_LOG_ERROR, "IPP read error: %s",
1625*5e7646d2SAndroid Build Coastguard Worker                              cupsLastErrorString());
1626*5e7646d2SAndroid Build Coastguard Worker 
1627*5e7646d2SAndroid Build Coastguard Worker 	      cupsdSendError(con, HTTP_STATUS_BAD_REQUEST, CUPSD_AUTH_NONE);
1628*5e7646d2SAndroid Build Coastguard Worker 	      cupsdCloseClient(con);
1629*5e7646d2SAndroid Build Coastguard Worker 	      return;
1630*5e7646d2SAndroid Build Coastguard Worker 	    }
1631*5e7646d2SAndroid Build Coastguard Worker 	    else if (ipp_state != IPP_STATE_DATA)
1632*5e7646d2SAndroid Build Coastguard Worker 	    {
1633*5e7646d2SAndroid Build Coastguard Worker               if (httpGetState(con->http) == HTTP_STATE_POST_SEND)
1634*5e7646d2SAndroid Build Coastguard Worker 	      {
1635*5e7646d2SAndroid Build Coastguard Worker 		cupsdSendError(con, HTTP_STATUS_BAD_REQUEST, CUPSD_AUTH_NONE);
1636*5e7646d2SAndroid Build Coastguard Worker 		cupsdCloseClient(con);
1637*5e7646d2SAndroid Build Coastguard Worker 		return;
1638*5e7646d2SAndroid Build Coastguard Worker 	      }
1639*5e7646d2SAndroid Build Coastguard Worker 
1640*5e7646d2SAndroid Build Coastguard Worker 	      if (httpGetReady(con->http))
1641*5e7646d2SAndroid Build Coastguard Worker 	        continue;
1642*5e7646d2SAndroid Build Coastguard Worker 	      break;
1643*5e7646d2SAndroid Build Coastguard Worker             }
1644*5e7646d2SAndroid Build Coastguard Worker 	    else
1645*5e7646d2SAndroid Build Coastguard Worker 	    {
1646*5e7646d2SAndroid Build Coastguard Worker 	      cupsdLogClient(con, CUPSD_LOG_DEBUG, "%d.%d %s %d",
1647*5e7646d2SAndroid Build Coastguard Worker 			      con->request->request.op.version[0],
1648*5e7646d2SAndroid Build Coastguard Worker 			      con->request->request.op.version[1],
1649*5e7646d2SAndroid Build Coastguard Worker 			      ippOpString(con->request->request.op.operation_id),
1650*5e7646d2SAndroid Build Coastguard Worker 			      con->request->request.op.request_id);
1651*5e7646d2SAndroid Build Coastguard Worker 	      con->bytes += (off_t)ippLength(con->request);
1652*5e7646d2SAndroid Build Coastguard Worker 	    }
1653*5e7646d2SAndroid Build Coastguard Worker 	  }
1654*5e7646d2SAndroid Build Coastguard Worker 
1655*5e7646d2SAndroid Build Coastguard Worker           if (con->file < 0 && httpGetState(con->http) != HTTP_STATE_POST_SEND)
1656*5e7646d2SAndroid Build Coastguard Worker 	  {
1657*5e7646d2SAndroid Build Coastguard Worker            /*
1658*5e7646d2SAndroid Build Coastguard Worker 	    * Create a file as needed for the request data...
1659*5e7646d2SAndroid Build Coastguard Worker 	    */
1660*5e7646d2SAndroid Build Coastguard Worker 
1661*5e7646d2SAndroid Build Coastguard Worker             cupsdSetStringf(&con->filename, "%s/%08x", RequestRoot,
1662*5e7646d2SAndroid Build Coastguard Worker 	                    request_id ++);
1663*5e7646d2SAndroid Build Coastguard Worker 	    con->file = open(con->filename, O_WRONLY | O_CREAT | O_TRUNC, 0640);
1664*5e7646d2SAndroid Build Coastguard Worker 
1665*5e7646d2SAndroid Build Coastguard Worker 	    if (con->file < 0)
1666*5e7646d2SAndroid Build Coastguard Worker 	    {
1667*5e7646d2SAndroid Build Coastguard Worker 	      cupsdLogClient(con, CUPSD_LOG_ERROR,
1668*5e7646d2SAndroid Build Coastguard Worker 	                     "Unable to create request file \"%s\": %s",
1669*5e7646d2SAndroid Build Coastguard Worker                              con->filename, strerror(errno));
1670*5e7646d2SAndroid Build Coastguard Worker 
1671*5e7646d2SAndroid Build Coastguard Worker 	      if (!cupsdSendError(con, HTTP_STATUS_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
1672*5e7646d2SAndroid Build Coastguard Worker 	      {
1673*5e7646d2SAndroid Build Coastguard Worker 		cupsdCloseClient(con);
1674*5e7646d2SAndroid Build Coastguard Worker 		return;
1675*5e7646d2SAndroid Build Coastguard Worker 	      }
1676*5e7646d2SAndroid Build Coastguard Worker 	    }
1677*5e7646d2SAndroid Build Coastguard Worker 
1678*5e7646d2SAndroid Build Coastguard Worker 	    fchmod(con->file, 0640);
1679*5e7646d2SAndroid Build Coastguard Worker 	    fchown(con->file, RunUser, Group);
1680*5e7646d2SAndroid Build Coastguard Worker             fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
1681*5e7646d2SAndroid Build Coastguard Worker 	  }
1682*5e7646d2SAndroid Build Coastguard Worker 
1683*5e7646d2SAndroid Build Coastguard Worker 	  if (httpGetState(con->http) != HTTP_STATE_POST_SEND)
1684*5e7646d2SAndroid Build Coastguard Worker 	  {
1685*5e7646d2SAndroid Build Coastguard Worker 	    if (!httpWait(con->http, 0))
1686*5e7646d2SAndroid Build Coastguard Worker 	      return;
1687*5e7646d2SAndroid Build Coastguard Worker             else if ((bytes = httpRead2(con->http, line, sizeof(line))) < 0)
1688*5e7646d2SAndroid Build Coastguard Worker 	    {
1689*5e7646d2SAndroid Build Coastguard Worker 	      if (httpError(con->http) && httpError(con->http) != EPIPE)
1690*5e7646d2SAndroid Build Coastguard Worker 		cupsdLogClient(con, CUPSD_LOG_DEBUG,
1691*5e7646d2SAndroid Build Coastguard Worker 			       "HTTP_STATE_POST_SEND Closing for error %d (%s)",
1692*5e7646d2SAndroid Build Coastguard Worker                                httpError(con->http), strerror(httpError(con->http)));
1693*5e7646d2SAndroid Build Coastguard Worker 	      else
1694*5e7646d2SAndroid Build Coastguard Worker 		cupsdLogClient(con, CUPSD_LOG_DEBUG,
1695*5e7646d2SAndroid Build Coastguard Worker 			       "HTTP_STATE_POST_SEND Closing on EOF.");
1696*5e7646d2SAndroid Build Coastguard Worker 
1697*5e7646d2SAndroid Build Coastguard Worker 	      cupsdCloseClient(con);
1698*5e7646d2SAndroid Build Coastguard Worker 	      return;
1699*5e7646d2SAndroid Build Coastguard Worker 	    }
1700*5e7646d2SAndroid Build Coastguard Worker 	    else if (bytes > 0)
1701*5e7646d2SAndroid Build Coastguard Worker 	    {
1702*5e7646d2SAndroid Build Coastguard Worker 	      con->bytes += bytes;
1703*5e7646d2SAndroid Build Coastguard Worker 
1704*5e7646d2SAndroid Build Coastguard Worker               if (MaxRequestSize > 0 && con->bytes > MaxRequestSize)
1705*5e7646d2SAndroid Build Coastguard Worker               {
1706*5e7646d2SAndroid Build Coastguard Worker                 close(con->file);
1707*5e7646d2SAndroid Build Coastguard Worker                 con->file = -1;
1708*5e7646d2SAndroid Build Coastguard Worker                 unlink(con->filename);
1709*5e7646d2SAndroid Build Coastguard Worker                 cupsdClearString(&con->filename);
1710*5e7646d2SAndroid Build Coastguard Worker 
1711*5e7646d2SAndroid Build Coastguard Worker                 if (!cupsdSendError(con, HTTP_STATUS_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
1712*5e7646d2SAndroid Build Coastguard Worker                 {
1713*5e7646d2SAndroid Build Coastguard Worker                   cupsdCloseClient(con);
1714*5e7646d2SAndroid Build Coastguard Worker                   return;
1715*5e7646d2SAndroid Build Coastguard Worker                 }
1716*5e7646d2SAndroid Build Coastguard Worker               }
1717*5e7646d2SAndroid Build Coastguard Worker 
1718*5e7646d2SAndroid Build Coastguard Worker               if (write(con->file, line, (size_t)bytes) < bytes)
1719*5e7646d2SAndroid Build Coastguard Worker 	      {
1720*5e7646d2SAndroid Build Coastguard Worker         	cupsdLogClient(con, CUPSD_LOG_ERROR,
1721*5e7646d2SAndroid Build Coastguard Worker 	                       "Unable to write %d bytes to \"%s\": %s",
1722*5e7646d2SAndroid Build Coastguard Worker                                bytes, con->filename, strerror(errno));
1723*5e7646d2SAndroid Build Coastguard Worker 
1724*5e7646d2SAndroid Build Coastguard Worker 		close(con->file);
1725*5e7646d2SAndroid Build Coastguard Worker 		con->file = -1;
1726*5e7646d2SAndroid Build Coastguard Worker 		unlink(con->filename);
1727*5e7646d2SAndroid Build Coastguard Worker 		cupsdClearString(&con->filename);
1728*5e7646d2SAndroid Build Coastguard Worker 
1729*5e7646d2SAndroid Build Coastguard Worker         	if (!cupsdSendError(con, HTTP_STATUS_REQUEST_TOO_LARGE,
1730*5e7646d2SAndroid Build Coastguard Worker 		                    CUPSD_AUTH_NONE))
1731*5e7646d2SAndroid Build Coastguard Worker 		{
1732*5e7646d2SAndroid Build Coastguard Worker 		  cupsdCloseClient(con);
1733*5e7646d2SAndroid Build Coastguard Worker 		  return;
1734*5e7646d2SAndroid Build Coastguard Worker 		}
1735*5e7646d2SAndroid Build Coastguard Worker 	      }
1736*5e7646d2SAndroid Build Coastguard Worker 	    }
1737*5e7646d2SAndroid Build Coastguard Worker 	    else if (httpGetState(con->http) == HTTP_STATE_POST_RECV)
1738*5e7646d2SAndroid Build Coastguard Worker               return;
1739*5e7646d2SAndroid Build Coastguard Worker 	    else if (httpGetState(con->http) != HTTP_STATE_POST_SEND)
1740*5e7646d2SAndroid Build Coastguard Worker 	    {
1741*5e7646d2SAndroid Build Coastguard Worker 	      cupsdLogClient(con, CUPSD_LOG_DEBUG,
1742*5e7646d2SAndroid Build Coastguard Worker 	                     "Closing on unexpected state %s.",
1743*5e7646d2SAndroid Build Coastguard Worker 			     httpStateString(httpGetState(con->http)));
1744*5e7646d2SAndroid Build Coastguard Worker 	      cupsdCloseClient(con);
1745*5e7646d2SAndroid Build Coastguard Worker 	      return;
1746*5e7646d2SAndroid Build Coastguard Worker 	    }
1747*5e7646d2SAndroid Build Coastguard Worker 	  }
1748*5e7646d2SAndroid Build Coastguard Worker         }
1749*5e7646d2SAndroid Build Coastguard Worker 	while (httpGetState(con->http) == HTTP_STATE_POST_RECV && httpGetReady(con->http));
1750*5e7646d2SAndroid Build Coastguard Worker 
1751*5e7646d2SAndroid Build Coastguard Worker 	if (httpGetState(con->http) == HTTP_STATE_POST_SEND)
1752*5e7646d2SAndroid Build Coastguard Worker 	{
1753*5e7646d2SAndroid Build Coastguard Worker 	  if (con->file >= 0)
1754*5e7646d2SAndroid Build Coastguard Worker 	  {
1755*5e7646d2SAndroid Build Coastguard Worker 	    fstat(con->file, &filestats);
1756*5e7646d2SAndroid Build Coastguard Worker 
1757*5e7646d2SAndroid Build Coastguard Worker 	    close(con->file);
1758*5e7646d2SAndroid Build Coastguard Worker 	    con->file = -1;
1759*5e7646d2SAndroid Build Coastguard Worker 
1760*5e7646d2SAndroid Build Coastguard Worker             if (filestats.st_size > MaxRequestSize &&
1761*5e7646d2SAndroid Build Coastguard Worker 	        MaxRequestSize > 0)
1762*5e7646d2SAndroid Build Coastguard Worker 	    {
1763*5e7646d2SAndroid Build Coastguard Worker 	     /*
1764*5e7646d2SAndroid Build Coastguard Worker 	      * Request is too big; remove it and send an error...
1765*5e7646d2SAndroid Build Coastguard Worker 	      */
1766*5e7646d2SAndroid Build Coastguard Worker 
1767*5e7646d2SAndroid Build Coastguard Worker 	      unlink(con->filename);
1768*5e7646d2SAndroid Build Coastguard Worker 	      cupsdClearString(&con->filename);
1769*5e7646d2SAndroid Build Coastguard Worker 
1770*5e7646d2SAndroid Build Coastguard Worker 	      if (con->request)
1771*5e7646d2SAndroid Build Coastguard Worker 	      {
1772*5e7646d2SAndroid Build Coastguard Worker 	       /*
1773*5e7646d2SAndroid Build Coastguard Worker 	        * Delete any IPP request data...
1774*5e7646d2SAndroid Build Coastguard Worker 		*/
1775*5e7646d2SAndroid Build Coastguard Worker 
1776*5e7646d2SAndroid Build Coastguard Worker 	        ippDelete(con->request);
1777*5e7646d2SAndroid Build Coastguard Worker 		con->request = NULL;
1778*5e7646d2SAndroid Build Coastguard Worker               }
1779*5e7646d2SAndroid Build Coastguard Worker 
1780*5e7646d2SAndroid Build Coastguard Worker               if (!cupsdSendError(con, HTTP_STATUS_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
1781*5e7646d2SAndroid Build Coastguard Worker 	      {
1782*5e7646d2SAndroid Build Coastguard Worker 		cupsdCloseClient(con);
1783*5e7646d2SAndroid Build Coastguard Worker 		return;
1784*5e7646d2SAndroid Build Coastguard Worker 	      }
1785*5e7646d2SAndroid Build Coastguard Worker 	    }
1786*5e7646d2SAndroid Build Coastguard Worker 	    else if (filestats.st_size == 0)
1787*5e7646d2SAndroid Build Coastguard Worker 	    {
1788*5e7646d2SAndroid Build Coastguard Worker 	     /*
1789*5e7646d2SAndroid Build Coastguard Worker 	      * Don't allow empty file...
1790*5e7646d2SAndroid Build Coastguard Worker 	      */
1791*5e7646d2SAndroid Build Coastguard Worker 
1792*5e7646d2SAndroid Build Coastguard Worker 	      unlink(con->filename);
1793*5e7646d2SAndroid Build Coastguard Worker 	      cupsdClearString(&con->filename);
1794*5e7646d2SAndroid Build Coastguard Worker 	    }
1795*5e7646d2SAndroid Build Coastguard Worker 
1796*5e7646d2SAndroid Build Coastguard Worker 	    if (con->command)
1797*5e7646d2SAndroid Build Coastguard Worker 	    {
1798*5e7646d2SAndroid Build Coastguard Worker 	      if (!cupsdSendCommand(con, con->command, con->options, 0))
1799*5e7646d2SAndroid Build Coastguard Worker 	      {
1800*5e7646d2SAndroid Build Coastguard Worker 		if (!cupsdSendError(con, HTTP_STATUS_NOT_FOUND, CUPSD_AUTH_NONE))
1801*5e7646d2SAndroid Build Coastguard Worker 		{
1802*5e7646d2SAndroid Build Coastguard Worker 		  cupsdCloseClient(con);
1803*5e7646d2SAndroid Build Coastguard Worker 		  return;
1804*5e7646d2SAndroid Build Coastguard Worker 		}
1805*5e7646d2SAndroid Build Coastguard Worker               }
1806*5e7646d2SAndroid Build Coastguard Worker 	      else
1807*5e7646d2SAndroid Build Coastguard Worker         	cupsdLogRequest(con, HTTP_STATUS_OK);
1808*5e7646d2SAndroid Build Coastguard Worker             }
1809*5e7646d2SAndroid Build Coastguard Worker 	  }
1810*5e7646d2SAndroid Build Coastguard Worker 
1811*5e7646d2SAndroid Build Coastguard Worker           if (con->request)
1812*5e7646d2SAndroid Build Coastguard Worker 	  {
1813*5e7646d2SAndroid Build Coastguard Worker 	    cupsdProcessIPPRequest(con);
1814*5e7646d2SAndroid Build Coastguard Worker 
1815*5e7646d2SAndroid Build Coastguard Worker 	    if (con->filename)
1816*5e7646d2SAndroid Build Coastguard Worker 	    {
1817*5e7646d2SAndroid Build Coastguard Worker 	      unlink(con->filename);
1818*5e7646d2SAndroid Build Coastguard Worker 	      cupsdClearString(&con->filename);
1819*5e7646d2SAndroid Build Coastguard Worker 	    }
1820*5e7646d2SAndroid Build Coastguard Worker 
1821*5e7646d2SAndroid Build Coastguard Worker 	    return;
1822*5e7646d2SAndroid Build Coastguard Worker 	  }
1823*5e7646d2SAndroid Build Coastguard Worker 	}
1824*5e7646d2SAndroid Build Coastguard Worker         break;
1825*5e7646d2SAndroid Build Coastguard Worker 
1826*5e7646d2SAndroid Build Coastguard Worker     default :
1827*5e7646d2SAndroid Build Coastguard Worker         break; /* Anti-compiler-warning-code */
1828*5e7646d2SAndroid Build Coastguard Worker   }
1829*5e7646d2SAndroid Build Coastguard Worker 
1830*5e7646d2SAndroid Build Coastguard Worker   if (httpGetState(con->http) == HTTP_STATE_WAITING)
1831*5e7646d2SAndroid Build Coastguard Worker   {
1832*5e7646d2SAndroid Build Coastguard Worker     if (!httpGetKeepAlive(con->http))
1833*5e7646d2SAndroid Build Coastguard Worker     {
1834*5e7646d2SAndroid Build Coastguard Worker       cupsdLogClient(con, CUPSD_LOG_DEBUG,
1835*5e7646d2SAndroid Build Coastguard Worker                      "Closing because Keep-Alive is disabled.");
1836*5e7646d2SAndroid Build Coastguard Worker       cupsdCloseClient(con);
1837*5e7646d2SAndroid Build Coastguard Worker     }
1838*5e7646d2SAndroid Build Coastguard Worker     else
1839*5e7646d2SAndroid Build Coastguard Worker     {
1840*5e7646d2SAndroid Build Coastguard Worker       cupsArrayRemove(ActiveClients, con);
1841*5e7646d2SAndroid Build Coastguard Worker       cupsdSetBusyState(0);
1842*5e7646d2SAndroid Build Coastguard Worker     }
1843*5e7646d2SAndroid Build Coastguard Worker   }
1844*5e7646d2SAndroid Build Coastguard Worker }
1845*5e7646d2SAndroid Build Coastguard Worker 
1846*5e7646d2SAndroid Build Coastguard Worker 
1847*5e7646d2SAndroid Build Coastguard Worker /*
1848*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdSendCommand()' - Send output from a command via HTTP.
1849*5e7646d2SAndroid Build Coastguard Worker  */
1850*5e7646d2SAndroid Build Coastguard Worker 
1851*5e7646d2SAndroid Build Coastguard Worker int					/* O - 1 on success, 0 on failure */
cupsdSendCommand(cupsd_client_t * con,char * command,char * options,int root)1852*5e7646d2SAndroid Build Coastguard Worker cupsdSendCommand(
1853*5e7646d2SAndroid Build Coastguard Worker     cupsd_client_t *con,		/* I - Client connection */
1854*5e7646d2SAndroid Build Coastguard Worker     char           *command,		/* I - Command to run */
1855*5e7646d2SAndroid Build Coastguard Worker     char           *options,		/* I - Command-line options */
1856*5e7646d2SAndroid Build Coastguard Worker     int            root)		/* I - Run as root? */
1857*5e7646d2SAndroid Build Coastguard Worker {
1858*5e7646d2SAndroid Build Coastguard Worker   int	fd;				/* Standard input file descriptor */
1859*5e7646d2SAndroid Build Coastguard Worker 
1860*5e7646d2SAndroid Build Coastguard Worker 
1861*5e7646d2SAndroid Build Coastguard Worker   if (con->filename)
1862*5e7646d2SAndroid Build Coastguard Worker   {
1863*5e7646d2SAndroid Build Coastguard Worker     fd = open(con->filename, O_RDONLY);
1864*5e7646d2SAndroid Build Coastguard Worker 
1865*5e7646d2SAndroid Build Coastguard Worker     if (fd < 0)
1866*5e7646d2SAndroid Build Coastguard Worker     {
1867*5e7646d2SAndroid Build Coastguard Worker       cupsdLogClient(con, CUPSD_LOG_ERROR,
1868*5e7646d2SAndroid Build Coastguard Worker                      "Unable to open \"%s\" for reading: %s",
1869*5e7646d2SAndroid Build Coastguard Worker                      con->filename ? con->filename : "/dev/null",
1870*5e7646d2SAndroid Build Coastguard Worker 	             strerror(errno));
1871*5e7646d2SAndroid Build Coastguard Worker       return (0);
1872*5e7646d2SAndroid Build Coastguard Worker     }
1873*5e7646d2SAndroid Build Coastguard Worker 
1874*5e7646d2SAndroid Build Coastguard Worker     fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
1875*5e7646d2SAndroid Build Coastguard Worker   }
1876*5e7646d2SAndroid Build Coastguard Worker   else
1877*5e7646d2SAndroid Build Coastguard Worker     fd = -1;
1878*5e7646d2SAndroid Build Coastguard Worker 
1879*5e7646d2SAndroid Build Coastguard Worker   con->pipe_pid    = pipe_command(con, fd, &(con->file), command, options, root);
1880*5e7646d2SAndroid Build Coastguard Worker   con->pipe_status = HTTP_STATUS_OK;
1881*5e7646d2SAndroid Build Coastguard Worker 
1882*5e7646d2SAndroid Build Coastguard Worker   httpClearFields(con->http);
1883*5e7646d2SAndroid Build Coastguard Worker 
1884*5e7646d2SAndroid Build Coastguard Worker   if (fd >= 0)
1885*5e7646d2SAndroid Build Coastguard Worker     close(fd);
1886*5e7646d2SAndroid Build Coastguard Worker 
1887*5e7646d2SAndroid Build Coastguard Worker   cupsdLogClient(con, CUPSD_LOG_INFO, "Started \"%s\" (pid=%d, file=%d)",
1888*5e7646d2SAndroid Build Coastguard Worker                  command, con->pipe_pid, con->file);
1889*5e7646d2SAndroid Build Coastguard Worker 
1890*5e7646d2SAndroid Build Coastguard Worker   if (con->pipe_pid == 0)
1891*5e7646d2SAndroid Build Coastguard Worker     return (0);
1892*5e7646d2SAndroid Build Coastguard Worker 
1893*5e7646d2SAndroid Build Coastguard Worker   fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
1894*5e7646d2SAndroid Build Coastguard Worker 
1895*5e7646d2SAndroid Build Coastguard Worker   cupsdAddSelect(con->file, (cupsd_selfunc_t)write_pipe, NULL, con);
1896*5e7646d2SAndroid Build Coastguard Worker 
1897*5e7646d2SAndroid Build Coastguard Worker   cupsdLogClient(con, CUPSD_LOG_DEBUG, "Waiting for CGI data.");
1898*5e7646d2SAndroid Build Coastguard Worker 
1899*5e7646d2SAndroid Build Coastguard Worker   con->sent_header = 0;
1900*5e7646d2SAndroid Build Coastguard Worker   con->file_ready  = 0;
1901*5e7646d2SAndroid Build Coastguard Worker   con->got_fields  = 0;
1902*5e7646d2SAndroid Build Coastguard Worker   con->header_used = 0;
1903*5e7646d2SAndroid Build Coastguard Worker 
1904*5e7646d2SAndroid Build Coastguard Worker   return (1);
1905*5e7646d2SAndroid Build Coastguard Worker }
1906*5e7646d2SAndroid Build Coastguard Worker 
1907*5e7646d2SAndroid Build Coastguard Worker 
1908*5e7646d2SAndroid Build Coastguard Worker /*
1909*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdSendError()' - Send an error message via HTTP.
1910*5e7646d2SAndroid Build Coastguard Worker  */
1911*5e7646d2SAndroid Build Coastguard Worker 
1912*5e7646d2SAndroid Build Coastguard Worker int					/* O - 1 if successful, 0 otherwise */
cupsdSendError(cupsd_client_t * con,http_status_t code,int auth_type)1913*5e7646d2SAndroid Build Coastguard Worker cupsdSendError(cupsd_client_t *con,	/* I - Connection */
1914*5e7646d2SAndroid Build Coastguard Worker                http_status_t  code,	/* I - Error code */
1915*5e7646d2SAndroid Build Coastguard Worker 	       int            auth_type)/* I - Authentication type */
1916*5e7646d2SAndroid Build Coastguard Worker {
1917*5e7646d2SAndroid Build Coastguard Worker   char	location[HTTP_MAX_VALUE];	/* Location field */
1918*5e7646d2SAndroid Build Coastguard Worker 
1919*5e7646d2SAndroid Build Coastguard Worker 
1920*5e7646d2SAndroid Build Coastguard Worker   cupsdLogClient(con, CUPSD_LOG_DEBUG2, "cupsdSendError code=%d, auth_type=%d", code, auth_type);
1921*5e7646d2SAndroid Build Coastguard Worker 
1922*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_SSL
1923*5e7646d2SAndroid Build Coastguard Worker  /*
1924*5e7646d2SAndroid Build Coastguard Worker   * Force client to upgrade for authentication if that is how the
1925*5e7646d2SAndroid Build Coastguard Worker   * server is configured...
1926*5e7646d2SAndroid Build Coastguard Worker   */
1927*5e7646d2SAndroid Build Coastguard Worker 
1928*5e7646d2SAndroid Build Coastguard Worker   if (code == HTTP_STATUS_UNAUTHORIZED &&
1929*5e7646d2SAndroid Build Coastguard Worker       DefaultEncryption == HTTP_ENCRYPTION_REQUIRED &&
1930*5e7646d2SAndroid Build Coastguard Worker       _cups_strcasecmp(httpGetHostname(con->http, NULL, 0), "localhost") &&
1931*5e7646d2SAndroid Build Coastguard Worker       !httpIsEncrypted(con->http))
1932*5e7646d2SAndroid Build Coastguard Worker   {
1933*5e7646d2SAndroid Build Coastguard Worker     code = HTTP_STATUS_UPGRADE_REQUIRED;
1934*5e7646d2SAndroid Build Coastguard Worker   }
1935*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_SSL */
1936*5e7646d2SAndroid Build Coastguard Worker 
1937*5e7646d2SAndroid Build Coastguard Worker  /*
1938*5e7646d2SAndroid Build Coastguard Worker   * Put the request in the access_log file...
1939*5e7646d2SAndroid Build Coastguard Worker   */
1940*5e7646d2SAndroid Build Coastguard Worker 
1941*5e7646d2SAndroid Build Coastguard Worker   cupsdLogRequest(con, code);
1942*5e7646d2SAndroid Build Coastguard Worker 
1943*5e7646d2SAndroid Build Coastguard Worker  /*
1944*5e7646d2SAndroid Build Coastguard Worker   * To work around bugs in some proxies, don't use Keep-Alive for some
1945*5e7646d2SAndroid Build Coastguard Worker   * error messages...
1946*5e7646d2SAndroid Build Coastguard Worker   *
1947*5e7646d2SAndroid Build Coastguard Worker   * Kerberos authentication doesn't work without Keep-Alive, so
1948*5e7646d2SAndroid Build Coastguard Worker   * never disable it in that case.
1949*5e7646d2SAndroid Build Coastguard Worker   */
1950*5e7646d2SAndroid Build Coastguard Worker 
1951*5e7646d2SAndroid Build Coastguard Worker   strlcpy(location, httpGetField(con->http, HTTP_FIELD_LOCATION), sizeof(location));
1952*5e7646d2SAndroid Build Coastguard Worker 
1953*5e7646d2SAndroid Build Coastguard Worker   httpClearFields(con->http);
1954*5e7646d2SAndroid Build Coastguard Worker   httpClearCookie(con->http);
1955*5e7646d2SAndroid Build Coastguard Worker 
1956*5e7646d2SAndroid Build Coastguard Worker   httpSetField(con->http, HTTP_FIELD_LOCATION, location);
1957*5e7646d2SAndroid Build Coastguard Worker 
1958*5e7646d2SAndroid Build Coastguard Worker   if (code >= HTTP_STATUS_BAD_REQUEST && con->type != CUPSD_AUTH_NEGOTIATE)
1959*5e7646d2SAndroid Build Coastguard Worker     httpSetKeepAlive(con->http, HTTP_KEEPALIVE_OFF);
1960*5e7646d2SAndroid Build Coastguard Worker 
1961*5e7646d2SAndroid Build Coastguard Worker   if (httpGetVersion(con->http) >= HTTP_VERSION_1_1 &&
1962*5e7646d2SAndroid Build Coastguard Worker       httpGetKeepAlive(con->http) == HTTP_KEEPALIVE_OFF)
1963*5e7646d2SAndroid Build Coastguard Worker     httpSetField(con->http, HTTP_FIELD_CONNECTION, "close");
1964*5e7646d2SAndroid Build Coastguard Worker 
1965*5e7646d2SAndroid Build Coastguard Worker   if (code >= HTTP_STATUS_BAD_REQUEST)
1966*5e7646d2SAndroid Build Coastguard Worker   {
1967*5e7646d2SAndroid Build Coastguard Worker    /*
1968*5e7646d2SAndroid Build Coastguard Worker     * Send a human-readable error message.
1969*5e7646d2SAndroid Build Coastguard Worker     */
1970*5e7646d2SAndroid Build Coastguard Worker 
1971*5e7646d2SAndroid Build Coastguard Worker     char	message[4096],		/* Message for user */
1972*5e7646d2SAndroid Build Coastguard Worker 		urltext[1024],		/* URL redirection text */
1973*5e7646d2SAndroid Build Coastguard Worker 		redirect[1024];		/* Redirection link */
1974*5e7646d2SAndroid Build Coastguard Worker     const char	*text;			/* Status-specific text */
1975*5e7646d2SAndroid Build Coastguard Worker 
1976*5e7646d2SAndroid Build Coastguard Worker 
1977*5e7646d2SAndroid Build Coastguard Worker     redirect[0] = '\0';
1978*5e7646d2SAndroid Build Coastguard Worker 
1979*5e7646d2SAndroid Build Coastguard Worker     if (code == HTTP_STATUS_UNAUTHORIZED)
1980*5e7646d2SAndroid Build Coastguard Worker     {
1981*5e7646d2SAndroid Build Coastguard Worker       text = _cupsLangString(con->language,
1982*5e7646d2SAndroid Build Coastguard Worker                              _("Enter your username and password or the "
1983*5e7646d2SAndroid Build Coastguard Worker 			       "root username and password to access this "
1984*5e7646d2SAndroid Build Coastguard Worker 			       "page. If you are using Kerberos authentication, "
1985*5e7646d2SAndroid Build Coastguard Worker 			       "make sure you have a valid Kerberos ticket."));
1986*5e7646d2SAndroid Build Coastguard Worker     }
1987*5e7646d2SAndroid Build Coastguard Worker     else if (code == HTTP_STATUS_FORBIDDEN)
1988*5e7646d2SAndroid Build Coastguard Worker     {
1989*5e7646d2SAndroid Build Coastguard Worker       if (con->username[0])
1990*5e7646d2SAndroid Build Coastguard Worker         text = _cupsLangString(con->language, _("Your account does not have the necessary privileges."));
1991*5e7646d2SAndroid Build Coastguard Worker       else
1992*5e7646d2SAndroid Build Coastguard Worker         text = _cupsLangString(con->language, _("You cannot access this page."));
1993*5e7646d2SAndroid Build Coastguard Worker     }
1994*5e7646d2SAndroid Build Coastguard Worker     else if (code == HTTP_STATUS_UPGRADE_REQUIRED)
1995*5e7646d2SAndroid Build Coastguard Worker     {
1996*5e7646d2SAndroid Build Coastguard Worker       text = urltext;
1997*5e7646d2SAndroid Build Coastguard Worker 
1998*5e7646d2SAndroid Build Coastguard Worker       snprintf(urltext, sizeof(urltext), _cupsLangString(con->language, _("You must access this page using the URL https://%s:%d%s.")), con->servername, con->serverport, con->uri);
1999*5e7646d2SAndroid Build Coastguard Worker 
2000*5e7646d2SAndroid Build Coastguard Worker       snprintf(redirect, sizeof(redirect), "<META HTTP-EQUIV=\"Refresh\" CONTENT=\"3;URL=https://%s:%d%s\">\n", con->servername, con->serverport, con->uri);
2001*5e7646d2SAndroid Build Coastguard Worker     }
2002*5e7646d2SAndroid Build Coastguard Worker     else if (code == HTTP_STATUS_CUPS_WEBIF_DISABLED)
2003*5e7646d2SAndroid Build Coastguard Worker       text = _cupsLangString(con->language,
2004*5e7646d2SAndroid Build Coastguard Worker                              _("The web interface is currently disabled. Run "
2005*5e7646d2SAndroid Build Coastguard Worker 			       "\"cupsctl WebInterface=yes\" to enable it."));
2006*5e7646d2SAndroid Build Coastguard Worker     else
2007*5e7646d2SAndroid Build Coastguard Worker       text = "";
2008*5e7646d2SAndroid Build Coastguard Worker 
2009*5e7646d2SAndroid Build Coastguard Worker     snprintf(message, sizeof(message),
2010*5e7646d2SAndroid Build Coastguard Worker              "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" "
2011*5e7646d2SAndroid Build Coastguard Worker 	     "\"http://www.w3.org/TR/html4/loose.dtd\">\n"
2012*5e7646d2SAndroid Build Coastguard Worker 	     "<HTML>\n"
2013*5e7646d2SAndroid Build Coastguard Worker 	     "<HEAD>\n"
2014*5e7646d2SAndroid Build Coastguard Worker              "\t<META HTTP-EQUIV=\"Content-Type\" "
2015*5e7646d2SAndroid Build Coastguard Worker 	     "CONTENT=\"text/html; charset=utf-8\">\n"
2016*5e7646d2SAndroid Build Coastguard Worker 	     "\t<TITLE>%s - " CUPS_SVERSION "</TITLE>\n"
2017*5e7646d2SAndroid Build Coastguard Worker 	     "\t<LINK REL=\"STYLESHEET\" TYPE=\"text/css\" "
2018*5e7646d2SAndroid Build Coastguard Worker 	     "HREF=\"/cups.css\">\n"
2019*5e7646d2SAndroid Build Coastguard Worker 	     "%s"
2020*5e7646d2SAndroid Build Coastguard Worker 	     "</HEAD>\n"
2021*5e7646d2SAndroid Build Coastguard Worker              "<BODY>\n"
2022*5e7646d2SAndroid Build Coastguard Worker 	     "<H1>%s</H1>\n"
2023*5e7646d2SAndroid Build Coastguard Worker 	     "<P>%s</P>\n"
2024*5e7646d2SAndroid Build Coastguard Worker 	     "</BODY>\n"
2025*5e7646d2SAndroid Build Coastguard Worker 	     "</HTML>\n",
2026*5e7646d2SAndroid Build Coastguard Worker 	     _httpStatus(con->language, code), redirect,
2027*5e7646d2SAndroid Build Coastguard Worker 	     _httpStatus(con->language, code), text);
2028*5e7646d2SAndroid Build Coastguard Worker 
2029*5e7646d2SAndroid Build Coastguard Worker    /*
2030*5e7646d2SAndroid Build Coastguard Worker     * Send an error message back to the client.  If the error code is a
2031*5e7646d2SAndroid Build Coastguard Worker     * 400 or 500 series, make sure the message contains some text, too!
2032*5e7646d2SAndroid Build Coastguard Worker     */
2033*5e7646d2SAndroid Build Coastguard Worker 
2034*5e7646d2SAndroid Build Coastguard Worker     size_t length = strlen(message);	/* Length of message */
2035*5e7646d2SAndroid Build Coastguard Worker 
2036*5e7646d2SAndroid Build Coastguard Worker     httpSetLength(con->http, length);
2037*5e7646d2SAndroid Build Coastguard Worker 
2038*5e7646d2SAndroid Build Coastguard Worker     if (!cupsdSendHeader(con, code, "text/html", auth_type))
2039*5e7646d2SAndroid Build Coastguard Worker       return (0);
2040*5e7646d2SAndroid Build Coastguard Worker 
2041*5e7646d2SAndroid Build Coastguard Worker     if (httpWrite2(con->http, message, length) < 0)
2042*5e7646d2SAndroid Build Coastguard Worker       return (0);
2043*5e7646d2SAndroid Build Coastguard Worker 
2044*5e7646d2SAndroid Build Coastguard Worker     if (httpFlushWrite(con->http) < 0)
2045*5e7646d2SAndroid Build Coastguard Worker       return (0);
2046*5e7646d2SAndroid Build Coastguard Worker   }
2047*5e7646d2SAndroid Build Coastguard Worker   else
2048*5e7646d2SAndroid Build Coastguard Worker   {
2049*5e7646d2SAndroid Build Coastguard Worker     httpSetField(con->http, HTTP_FIELD_CONTENT_LENGTH, "0");
2050*5e7646d2SAndroid Build Coastguard Worker 
2051*5e7646d2SAndroid Build Coastguard Worker     if (!cupsdSendHeader(con, code, NULL, auth_type))
2052*5e7646d2SAndroid Build Coastguard Worker       return (0);
2053*5e7646d2SAndroid Build Coastguard Worker   }
2054*5e7646d2SAndroid Build Coastguard Worker 
2055*5e7646d2SAndroid Build Coastguard Worker   return (1);
2056*5e7646d2SAndroid Build Coastguard Worker }
2057*5e7646d2SAndroid Build Coastguard Worker 
2058*5e7646d2SAndroid Build Coastguard Worker 
2059*5e7646d2SAndroid Build Coastguard Worker /*
2060*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdSendHeader()' - Send an HTTP request.
2061*5e7646d2SAndroid Build Coastguard Worker  */
2062*5e7646d2SAndroid Build Coastguard Worker 
2063*5e7646d2SAndroid Build Coastguard Worker int					/* O - 1 on success, 0 on failure */
cupsdSendHeader(cupsd_client_t * con,http_status_t code,char * type,int auth_type)2064*5e7646d2SAndroid Build Coastguard Worker cupsdSendHeader(
2065*5e7646d2SAndroid Build Coastguard Worker     cupsd_client_t *con,		/* I - Client to send to */
2066*5e7646d2SAndroid Build Coastguard Worker     http_status_t  code,		/* I - HTTP status code */
2067*5e7646d2SAndroid Build Coastguard Worker     char           *type,		/* I - MIME type of document */
2068*5e7646d2SAndroid Build Coastguard Worker     int            auth_type)		/* I - Type of authentication */
2069*5e7646d2SAndroid Build Coastguard Worker {
2070*5e7646d2SAndroid Build Coastguard Worker   char		auth_str[1024];		/* Authorization string */
2071*5e7646d2SAndroid Build Coastguard Worker 
2072*5e7646d2SAndroid Build Coastguard Worker 
2073*5e7646d2SAndroid Build Coastguard Worker   cupsdLogClient(con, CUPSD_LOG_DEBUG, "cupsdSendHeader: code=%d, type=\"%s\", auth_type=%d", code, type, auth_type);
2074*5e7646d2SAndroid Build Coastguard Worker 
2075*5e7646d2SAndroid Build Coastguard Worker  /*
2076*5e7646d2SAndroid Build Coastguard Worker   * Send the HTTP status header...
2077*5e7646d2SAndroid Build Coastguard Worker   */
2078*5e7646d2SAndroid Build Coastguard Worker 
2079*5e7646d2SAndroid Build Coastguard Worker   if (code == HTTP_STATUS_CUPS_WEBIF_DISABLED)
2080*5e7646d2SAndroid Build Coastguard Worker   {
2081*5e7646d2SAndroid Build Coastguard Worker    /*
2082*5e7646d2SAndroid Build Coastguard Worker     * Treat our special "web interface is disabled" status as "200 OK" for web
2083*5e7646d2SAndroid Build Coastguard Worker     * browsers.
2084*5e7646d2SAndroid Build Coastguard Worker     */
2085*5e7646d2SAndroid Build Coastguard Worker 
2086*5e7646d2SAndroid Build Coastguard Worker     code = HTTP_STATUS_OK;
2087*5e7646d2SAndroid Build Coastguard Worker   }
2088*5e7646d2SAndroid Build Coastguard Worker 
2089*5e7646d2SAndroid Build Coastguard Worker   if (ServerHeader)
2090*5e7646d2SAndroid Build Coastguard Worker     httpSetField(con->http, HTTP_FIELD_SERVER, ServerHeader);
2091*5e7646d2SAndroid Build Coastguard Worker 
2092*5e7646d2SAndroid Build Coastguard Worker   if (code == HTTP_STATUS_METHOD_NOT_ALLOWED)
2093*5e7646d2SAndroid Build Coastguard Worker     httpSetField(con->http, HTTP_FIELD_ALLOW, "GET, HEAD, OPTIONS, POST, PUT");
2094*5e7646d2SAndroid Build Coastguard Worker 
2095*5e7646d2SAndroid Build Coastguard Worker   if (code == HTTP_STATUS_UNAUTHORIZED)
2096*5e7646d2SAndroid Build Coastguard Worker   {
2097*5e7646d2SAndroid Build Coastguard Worker     if (auth_type == CUPSD_AUTH_NONE)
2098*5e7646d2SAndroid Build Coastguard Worker     {
2099*5e7646d2SAndroid Build Coastguard Worker       if (!con->best || con->best->type <= CUPSD_AUTH_NONE)
2100*5e7646d2SAndroid Build Coastguard Worker 	auth_type = cupsdDefaultAuthType();
2101*5e7646d2SAndroid Build Coastguard Worker       else
2102*5e7646d2SAndroid Build Coastguard Worker 	auth_type = con->best->type;
2103*5e7646d2SAndroid Build Coastguard Worker     }
2104*5e7646d2SAndroid Build Coastguard Worker 
2105*5e7646d2SAndroid Build Coastguard Worker     auth_str[0] = '\0';
2106*5e7646d2SAndroid Build Coastguard Worker 
2107*5e7646d2SAndroid Build Coastguard Worker     if (auth_type == CUPSD_AUTH_BASIC)
2108*5e7646d2SAndroid Build Coastguard Worker     {
2109*5e7646d2SAndroid Build Coastguard Worker       strlcpy(auth_str, "Basic realm=\"CUPS\"", sizeof(auth_str));
2110*5e7646d2SAndroid Build Coastguard Worker     }
2111*5e7646d2SAndroid Build Coastguard Worker     else if (auth_type == CUPSD_AUTH_NEGOTIATE)
2112*5e7646d2SAndroid Build Coastguard Worker     {
2113*5e7646d2SAndroid Build Coastguard Worker       strlcpy(auth_str, "Negotiate", sizeof(auth_str));
2114*5e7646d2SAndroid Build Coastguard Worker     }
2115*5e7646d2SAndroid Build Coastguard Worker 
2116*5e7646d2SAndroid Build Coastguard Worker     if (con->best && !con->is_browser && !_cups_strcasecmp(httpGetHostname(con->http, NULL, 0), "localhost"))
2117*5e7646d2SAndroid Build Coastguard Worker     {
2118*5e7646d2SAndroid Build Coastguard Worker      /*
2119*5e7646d2SAndroid Build Coastguard Worker       * Add a "trc" (try root certification) parameter for local
2120*5e7646d2SAndroid Build Coastguard Worker       * requests when the request requires system group membership - then the
2121*5e7646d2SAndroid Build Coastguard Worker       * client knows the root certificate can/should be used.
2122*5e7646d2SAndroid Build Coastguard Worker       *
2123*5e7646d2SAndroid Build Coastguard Worker       * Also, for macOS we also look for @AUTHKEY and add an "AuthRef key=foo"
2124*5e7646d2SAndroid Build Coastguard Worker       * method as needed...
2125*5e7646d2SAndroid Build Coastguard Worker       */
2126*5e7646d2SAndroid Build Coastguard Worker 
2127*5e7646d2SAndroid Build Coastguard Worker       char	*name,			/* Current user name */
2128*5e7646d2SAndroid Build Coastguard Worker 		*auth_key;		/* Auth key buffer */
2129*5e7646d2SAndroid Build Coastguard Worker       size_t	auth_size;		/* Size of remaining buffer */
2130*5e7646d2SAndroid Build Coastguard Worker       int	need_local = 1;		/* Do we need to list "Local" method? */
2131*5e7646d2SAndroid Build Coastguard Worker 
2132*5e7646d2SAndroid Build Coastguard Worker       auth_key  = auth_str + strlen(auth_str);
2133*5e7646d2SAndroid Build Coastguard Worker       auth_size = sizeof(auth_str) - (size_t)(auth_key - auth_str);
2134*5e7646d2SAndroid Build Coastguard Worker 
2135*5e7646d2SAndroid Build Coastguard Worker #if defined(SO_PEERCRED) && defined(AF_LOCAL)
2136*5e7646d2SAndroid Build Coastguard Worker       if (httpAddrFamily(httpGetAddress(con->http)) == AF_LOCAL)
2137*5e7646d2SAndroid Build Coastguard Worker       {
2138*5e7646d2SAndroid Build Coastguard Worker         strlcpy(auth_key, ", PeerCred", auth_size);
2139*5e7646d2SAndroid Build Coastguard Worker         auth_key += 10;
2140*5e7646d2SAndroid Build Coastguard Worker         auth_size -= 10;
2141*5e7646d2SAndroid Build Coastguard Worker       }
2142*5e7646d2SAndroid Build Coastguard Worker #endif /* SO_PEERCRED && AF_LOCAL */
2143*5e7646d2SAndroid Build Coastguard Worker 
2144*5e7646d2SAndroid Build Coastguard Worker       for (name = (char *)cupsArrayFirst(con->best->names);
2145*5e7646d2SAndroid Build Coastguard Worker            name;
2146*5e7646d2SAndroid Build Coastguard Worker 	   name = (char *)cupsArrayNext(con->best->names))
2147*5e7646d2SAndroid Build Coastguard Worker       {
2148*5e7646d2SAndroid Build Coastguard Worker         cupsdLogClient(con, CUPSD_LOG_DEBUG2, "cupsdSendHeader: require \"%s\"", name);
2149*5e7646d2SAndroid Build Coastguard Worker 
2150*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_AUTHORIZATION_H
2151*5e7646d2SAndroid Build Coastguard Worker 	if (!_cups_strncasecmp(name, "@AUTHKEY(", 9))
2152*5e7646d2SAndroid Build Coastguard Worker 	{
2153*5e7646d2SAndroid Build Coastguard Worker 	  snprintf(auth_key, auth_size, ", AuthRef key=\"%s\", Local trc=\"y\"", name + 9);
2154*5e7646d2SAndroid Build Coastguard Worker 	  need_local = 0;
2155*5e7646d2SAndroid Build Coastguard Worker 	  /* end parenthesis is stripped in conf.c */
2156*5e7646d2SAndroid Build Coastguard Worker 	  break;
2157*5e7646d2SAndroid Build Coastguard Worker         }
2158*5e7646d2SAndroid Build Coastguard Worker 	else
2159*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_AUTHORIZATION_H */
2160*5e7646d2SAndroid Build Coastguard Worker 	if (!_cups_strcasecmp(name, "@SYSTEM"))
2161*5e7646d2SAndroid Build Coastguard Worker 	{
2162*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_AUTHORIZATION_H
2163*5e7646d2SAndroid Build Coastguard Worker 	  if (SystemGroupAuthKey)
2164*5e7646d2SAndroid Build Coastguard Worker 	    snprintf(auth_key, auth_size, ", AuthRef key=\"%s\", Local trc=\"y\"", SystemGroupAuthKey);
2165*5e7646d2SAndroid Build Coastguard Worker           else
2166*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_AUTHORIZATION_H */
2167*5e7646d2SAndroid Build Coastguard Worker 	  strlcpy(auth_key, ", Local trc=\"y\"", auth_size);
2168*5e7646d2SAndroid Build Coastguard Worker 	  need_local = 0;
2169*5e7646d2SAndroid Build Coastguard Worker 	  break;
2170*5e7646d2SAndroid Build Coastguard Worker 	}
2171*5e7646d2SAndroid Build Coastguard Worker       }
2172*5e7646d2SAndroid Build Coastguard Worker 
2173*5e7646d2SAndroid Build Coastguard Worker       if (need_local)
2174*5e7646d2SAndroid Build Coastguard Worker 	strlcat(auth_key, ", Local", auth_size);
2175*5e7646d2SAndroid Build Coastguard Worker     }
2176*5e7646d2SAndroid Build Coastguard Worker 
2177*5e7646d2SAndroid Build Coastguard Worker     if (auth_str[0])
2178*5e7646d2SAndroid Build Coastguard Worker     {
2179*5e7646d2SAndroid Build Coastguard Worker       cupsdLogClient(con, CUPSD_LOG_DEBUG, "WWW-Authenticate: %s", auth_str);
2180*5e7646d2SAndroid Build Coastguard Worker 
2181*5e7646d2SAndroid Build Coastguard Worker       httpSetField(con->http, HTTP_FIELD_WWW_AUTHENTICATE, auth_str);
2182*5e7646d2SAndroid Build Coastguard Worker     }
2183*5e7646d2SAndroid Build Coastguard Worker   }
2184*5e7646d2SAndroid Build Coastguard Worker 
2185*5e7646d2SAndroid Build Coastguard Worker   if (con->language && strcmp(con->language->language, "C"))
2186*5e7646d2SAndroid Build Coastguard Worker     httpSetField(con->http, HTTP_FIELD_CONTENT_LANGUAGE, con->language->language);
2187*5e7646d2SAndroid Build Coastguard Worker 
2188*5e7646d2SAndroid Build Coastguard Worker   if (type)
2189*5e7646d2SAndroid Build Coastguard Worker   {
2190*5e7646d2SAndroid Build Coastguard Worker     if (!strcmp(type, "text/html"))
2191*5e7646d2SAndroid Build Coastguard Worker       httpSetField(con->http, HTTP_FIELD_CONTENT_TYPE, "text/html; charset=utf-8");
2192*5e7646d2SAndroid Build Coastguard Worker     else
2193*5e7646d2SAndroid Build Coastguard Worker       httpSetField(con->http, HTTP_FIELD_CONTENT_TYPE, type);
2194*5e7646d2SAndroid Build Coastguard Worker   }
2195*5e7646d2SAndroid Build Coastguard Worker 
2196*5e7646d2SAndroid Build Coastguard Worker   return (!httpWriteResponse(con->http, code));
2197*5e7646d2SAndroid Build Coastguard Worker }
2198*5e7646d2SAndroid Build Coastguard Worker 
2199*5e7646d2SAndroid Build Coastguard Worker 
2200*5e7646d2SAndroid Build Coastguard Worker /*
2201*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdUpdateCGI()' - Read status messages from CGI scripts and programs.
2202*5e7646d2SAndroid Build Coastguard Worker  */
2203*5e7646d2SAndroid Build Coastguard Worker 
2204*5e7646d2SAndroid Build Coastguard Worker void
cupsdUpdateCGI(void)2205*5e7646d2SAndroid Build Coastguard Worker cupsdUpdateCGI(void)
2206*5e7646d2SAndroid Build Coastguard Worker {
2207*5e7646d2SAndroid Build Coastguard Worker   char		*ptr,			/* Pointer to end of line in buffer */
2208*5e7646d2SAndroid Build Coastguard Worker 		message[1024];		/* Pointer to message text */
2209*5e7646d2SAndroid Build Coastguard Worker   int		loglevel;		/* Log level for message */
2210*5e7646d2SAndroid Build Coastguard Worker 
2211*5e7646d2SAndroid Build Coastguard Worker 
2212*5e7646d2SAndroid Build Coastguard Worker   while ((ptr = cupsdStatBufUpdate(CGIStatusBuffer, &loglevel,
2213*5e7646d2SAndroid Build Coastguard Worker                                    message, sizeof(message))) != NULL)
2214*5e7646d2SAndroid Build Coastguard Worker   {
2215*5e7646d2SAndroid Build Coastguard Worker     if (loglevel == CUPSD_LOG_INFO)
2216*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_INFO, "%s", message);
2217*5e7646d2SAndroid Build Coastguard Worker 
2218*5e7646d2SAndroid Build Coastguard Worker     if (!strchr(CGIStatusBuffer->buffer, '\n'))
2219*5e7646d2SAndroid Build Coastguard Worker       break;
2220*5e7646d2SAndroid Build Coastguard Worker   }
2221*5e7646d2SAndroid Build Coastguard Worker 
2222*5e7646d2SAndroid Build Coastguard Worker   if (ptr == NULL && !CGIStatusBuffer->bufused)
2223*5e7646d2SAndroid Build Coastguard Worker   {
2224*5e7646d2SAndroid Build Coastguard Worker    /*
2225*5e7646d2SAndroid Build Coastguard Worker     * Fatal error on pipe - should never happen!
2226*5e7646d2SAndroid Build Coastguard Worker     */
2227*5e7646d2SAndroid Build Coastguard Worker 
2228*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_CRIT,
2229*5e7646d2SAndroid Build Coastguard Worker                     "cupsdUpdateCGI: error reading from CGI error pipe - %s",
2230*5e7646d2SAndroid Build Coastguard Worker                     strerror(errno));
2231*5e7646d2SAndroid Build Coastguard Worker   }
2232*5e7646d2SAndroid Build Coastguard Worker }
2233*5e7646d2SAndroid Build Coastguard Worker 
2234*5e7646d2SAndroid Build Coastguard Worker 
2235*5e7646d2SAndroid Build Coastguard Worker /*
2236*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdWriteClient()' - Write data to a client as needed.
2237*5e7646d2SAndroid Build Coastguard Worker  */
2238*5e7646d2SAndroid Build Coastguard Worker 
2239*5e7646d2SAndroid Build Coastguard Worker void
cupsdWriteClient(cupsd_client_t * con)2240*5e7646d2SAndroid Build Coastguard Worker cupsdWriteClient(cupsd_client_t *con)	/* I - Client connection */
2241*5e7646d2SAndroid Build Coastguard Worker {
2242*5e7646d2SAndroid Build Coastguard Worker   int		bytes,			/* Number of bytes written */
2243*5e7646d2SAndroid Build Coastguard Worker 		field_col;		/* Current column */
2244*5e7646d2SAndroid Build Coastguard Worker   char		*bufptr,		/* Pointer into buffer */
2245*5e7646d2SAndroid Build Coastguard Worker 		*bufend;		/* Pointer to end of buffer */
2246*5e7646d2SAndroid Build Coastguard Worker   ipp_state_t	ipp_state;		/* IPP state value */
2247*5e7646d2SAndroid Build Coastguard Worker 
2248*5e7646d2SAndroid Build Coastguard Worker 
2249*5e7646d2SAndroid Build Coastguard Worker   cupsdLogClient(con, CUPSD_LOG_DEBUG, "con->http=%p", con->http);
2250*5e7646d2SAndroid Build Coastguard Worker   cupsdLogClient(con, CUPSD_LOG_DEBUG,
2251*5e7646d2SAndroid Build Coastguard Worker 		 "cupsdWriteClient "
2252*5e7646d2SAndroid Build Coastguard Worker 		 "error=%d, "
2253*5e7646d2SAndroid Build Coastguard Worker 		 "used=%d, "
2254*5e7646d2SAndroid Build Coastguard Worker 		 "state=%s, "
2255*5e7646d2SAndroid Build Coastguard Worker 		 "data_encoding=HTTP_ENCODING_%s, "
2256*5e7646d2SAndroid Build Coastguard Worker 		 "data_remaining=" CUPS_LLFMT ", "
2257*5e7646d2SAndroid Build Coastguard Worker 		 "response=%p(%s), "
2258*5e7646d2SAndroid Build Coastguard Worker 		 "pipe_pid=%d, "
2259*5e7646d2SAndroid Build Coastguard Worker 		 "file=%d",
2260*5e7646d2SAndroid Build Coastguard Worker 		 httpError(con->http), (int)httpGetReady(con->http),
2261*5e7646d2SAndroid Build Coastguard Worker 		 httpStateString(httpGetState(con->http)),
2262*5e7646d2SAndroid Build Coastguard Worker 		 httpIsChunked(con->http) ? "CHUNKED" : "LENGTH",
2263*5e7646d2SAndroid Build Coastguard Worker 		 CUPS_LLCAST httpGetLength2(con->http),
2264*5e7646d2SAndroid Build Coastguard Worker 		 con->response,
2265*5e7646d2SAndroid Build Coastguard Worker 		 con->response ? ippStateString(ippGetState(con->request)) : "",
2266*5e7646d2SAndroid Build Coastguard Worker 		 con->pipe_pid, con->file);
2267*5e7646d2SAndroid Build Coastguard Worker 
2268*5e7646d2SAndroid Build Coastguard Worker   if (httpGetState(con->http) != HTTP_STATE_GET_SEND &&
2269*5e7646d2SAndroid Build Coastguard Worker       httpGetState(con->http) != HTTP_STATE_POST_SEND)
2270*5e7646d2SAndroid Build Coastguard Worker   {
2271*5e7646d2SAndroid Build Coastguard Worker    /*
2272*5e7646d2SAndroid Build Coastguard Worker     * If we get called in the wrong state, then something went wrong with the
2273*5e7646d2SAndroid Build Coastguard Worker     * connection and we need to shut it down...
2274*5e7646d2SAndroid Build Coastguard Worker     */
2275*5e7646d2SAndroid Build Coastguard Worker 
2276*5e7646d2SAndroid Build Coastguard Worker     cupsdLogClient(con, CUPSD_LOG_DEBUG, "Closing on unexpected HTTP write state %s.",
2277*5e7646d2SAndroid Build Coastguard Worker 		   httpStateString(httpGetState(con->http)));
2278*5e7646d2SAndroid Build Coastguard Worker     cupsdCloseClient(con);
2279*5e7646d2SAndroid Build Coastguard Worker     return;
2280*5e7646d2SAndroid Build Coastguard Worker   }
2281*5e7646d2SAndroid Build Coastguard Worker 
2282*5e7646d2SAndroid Build Coastguard Worker   if (con->pipe_pid)
2283*5e7646d2SAndroid Build Coastguard Worker   {
2284*5e7646d2SAndroid Build Coastguard Worker    /*
2285*5e7646d2SAndroid Build Coastguard Worker     * Make sure we select on the CGI output...
2286*5e7646d2SAndroid Build Coastguard Worker     */
2287*5e7646d2SAndroid Build Coastguard Worker 
2288*5e7646d2SAndroid Build Coastguard Worker     cupsdAddSelect(con->file, (cupsd_selfunc_t)write_pipe, NULL, con);
2289*5e7646d2SAndroid Build Coastguard Worker 
2290*5e7646d2SAndroid Build Coastguard Worker     cupsdLogClient(con, CUPSD_LOG_DEBUG, "Waiting for CGI data.");
2291*5e7646d2SAndroid Build Coastguard Worker 
2292*5e7646d2SAndroid Build Coastguard Worker     if (!con->file_ready)
2293*5e7646d2SAndroid Build Coastguard Worker     {
2294*5e7646d2SAndroid Build Coastguard Worker      /*
2295*5e7646d2SAndroid Build Coastguard Worker       * Try again later when there is CGI output available...
2296*5e7646d2SAndroid Build Coastguard Worker       */
2297*5e7646d2SAndroid Build Coastguard Worker 
2298*5e7646d2SAndroid Build Coastguard Worker       cupsdRemoveSelect(httpGetFd(con->http));
2299*5e7646d2SAndroid Build Coastguard Worker       return;
2300*5e7646d2SAndroid Build Coastguard Worker     }
2301*5e7646d2SAndroid Build Coastguard Worker 
2302*5e7646d2SAndroid Build Coastguard Worker     con->file_ready = 0;
2303*5e7646d2SAndroid Build Coastguard Worker   }
2304*5e7646d2SAndroid Build Coastguard Worker 
2305*5e7646d2SAndroid Build Coastguard Worker   bytes = (ssize_t)(sizeof(con->header) - (size_t)con->header_used);
2306*5e7646d2SAndroid Build Coastguard Worker 
2307*5e7646d2SAndroid Build Coastguard Worker   if (!con->pipe_pid && bytes > (ssize_t)httpGetRemaining(con->http))
2308*5e7646d2SAndroid Build Coastguard Worker   {
2309*5e7646d2SAndroid Build Coastguard Worker    /*
2310*5e7646d2SAndroid Build Coastguard Worker     * Limit GET bytes to original size of file (STR #3265)...
2311*5e7646d2SAndroid Build Coastguard Worker     */
2312*5e7646d2SAndroid Build Coastguard Worker 
2313*5e7646d2SAndroid Build Coastguard Worker     bytes = (ssize_t)httpGetRemaining(con->http);
2314*5e7646d2SAndroid Build Coastguard Worker   }
2315*5e7646d2SAndroid Build Coastguard Worker 
2316*5e7646d2SAndroid Build Coastguard Worker   if (con->response && con->response->state != IPP_STATE_DATA)
2317*5e7646d2SAndroid Build Coastguard Worker   {
2318*5e7646d2SAndroid Build Coastguard Worker     size_t wused = httpGetPending(con->http);	/* Previous write buffer use */
2319*5e7646d2SAndroid Build Coastguard Worker 
2320*5e7646d2SAndroid Build Coastguard Worker     do
2321*5e7646d2SAndroid Build Coastguard Worker     {
2322*5e7646d2SAndroid Build Coastguard Worker      /*
2323*5e7646d2SAndroid Build Coastguard Worker       * Write a single attribute or the IPP message header...
2324*5e7646d2SAndroid Build Coastguard Worker       */
2325*5e7646d2SAndroid Build Coastguard Worker 
2326*5e7646d2SAndroid Build Coastguard Worker       ipp_state = ippWrite(con->http, con->response);
2327*5e7646d2SAndroid Build Coastguard Worker 
2328*5e7646d2SAndroid Build Coastguard Worker      /*
2329*5e7646d2SAndroid Build Coastguard Worker       * If the write buffer has been flushed, stop buffering up attributes...
2330*5e7646d2SAndroid Build Coastguard Worker       */
2331*5e7646d2SAndroid Build Coastguard Worker 
2332*5e7646d2SAndroid Build Coastguard Worker       if (httpGetPending(con->http) <= wused)
2333*5e7646d2SAndroid Build Coastguard Worker         break;
2334*5e7646d2SAndroid Build Coastguard Worker     }
2335*5e7646d2SAndroid Build Coastguard Worker     while (ipp_state != IPP_STATE_DATA && ipp_state != IPP_STATE_ERROR);
2336*5e7646d2SAndroid Build Coastguard Worker 
2337*5e7646d2SAndroid Build Coastguard Worker     cupsdLogClient(con, CUPSD_LOG_DEBUG,
2338*5e7646d2SAndroid Build Coastguard Worker                    "Writing IPP response, ipp_state=%s, old "
2339*5e7646d2SAndroid Build Coastguard Worker                    "wused=" CUPS_LLFMT ", new wused=" CUPS_LLFMT,
2340*5e7646d2SAndroid Build Coastguard Worker                    ippStateString(ipp_state),
2341*5e7646d2SAndroid Build Coastguard Worker 		   CUPS_LLCAST wused, CUPS_LLCAST httpGetPending(con->http));
2342*5e7646d2SAndroid Build Coastguard Worker 
2343*5e7646d2SAndroid Build Coastguard Worker     if (httpGetPending(con->http) > 0)
2344*5e7646d2SAndroid Build Coastguard Worker       httpFlushWrite(con->http);
2345*5e7646d2SAndroid Build Coastguard Worker 
2346*5e7646d2SAndroid Build Coastguard Worker     bytes = ipp_state != IPP_STATE_ERROR &&
2347*5e7646d2SAndroid Build Coastguard Worker 	    (con->file >= 0 || ipp_state != IPP_STATE_DATA);
2348*5e7646d2SAndroid Build Coastguard Worker 
2349*5e7646d2SAndroid Build Coastguard Worker     cupsdLogClient(con, CUPSD_LOG_DEBUG,
2350*5e7646d2SAndroid Build Coastguard Worker                    "bytes=%d, http_state=%d, data_remaining=" CUPS_LLFMT,
2351*5e7646d2SAndroid Build Coastguard Worker                    (int)bytes, httpGetState(con->http),
2352*5e7646d2SAndroid Build Coastguard Worker                    CUPS_LLCAST httpGetLength2(con->http));
2353*5e7646d2SAndroid Build Coastguard Worker   }
2354*5e7646d2SAndroid Build Coastguard Worker   else if ((bytes = read(con->file, con->header + con->header_used, (size_t)bytes)) > 0)
2355*5e7646d2SAndroid Build Coastguard Worker   {
2356*5e7646d2SAndroid Build Coastguard Worker     con->header_used += bytes;
2357*5e7646d2SAndroid Build Coastguard Worker 
2358*5e7646d2SAndroid Build Coastguard Worker     if (con->pipe_pid && !con->got_fields)
2359*5e7646d2SAndroid Build Coastguard Worker     {
2360*5e7646d2SAndroid Build Coastguard Worker      /*
2361*5e7646d2SAndroid Build Coastguard Worker       * Inspect the data for Content-Type and other fields.
2362*5e7646d2SAndroid Build Coastguard Worker       */
2363*5e7646d2SAndroid Build Coastguard Worker 
2364*5e7646d2SAndroid Build Coastguard Worker       for (bufptr = con->header, bufend = con->header + con->header_used,
2365*5e7646d2SAndroid Build Coastguard Worker                field_col = 0;
2366*5e7646d2SAndroid Build Coastguard Worker            !con->got_fields && bufptr < bufend;
2367*5e7646d2SAndroid Build Coastguard Worker 	   bufptr ++)
2368*5e7646d2SAndroid Build Coastguard Worker       {
2369*5e7646d2SAndroid Build Coastguard Worker         if (*bufptr == '\n')
2370*5e7646d2SAndroid Build Coastguard Worker 	{
2371*5e7646d2SAndroid Build Coastguard Worker 	 /*
2372*5e7646d2SAndroid Build Coastguard Worker 	  * Send line to client...
2373*5e7646d2SAndroid Build Coastguard Worker 	  */
2374*5e7646d2SAndroid Build Coastguard Worker 
2375*5e7646d2SAndroid Build Coastguard Worker 	  if (bufptr > con->header && bufptr[-1] == '\r')
2376*5e7646d2SAndroid Build Coastguard Worker 	    bufptr[-1] = '\0';
2377*5e7646d2SAndroid Build Coastguard Worker 	  *bufptr++ = '\0';
2378*5e7646d2SAndroid Build Coastguard Worker 
2379*5e7646d2SAndroid Build Coastguard Worker           cupsdLogClient(con, CUPSD_LOG_DEBUG, "Script header: %s", con->header);
2380*5e7646d2SAndroid Build Coastguard Worker 
2381*5e7646d2SAndroid Build Coastguard Worker           if (!con->sent_header)
2382*5e7646d2SAndroid Build Coastguard Worker 	  {
2383*5e7646d2SAndroid Build Coastguard Worker 	   /*
2384*5e7646d2SAndroid Build Coastguard Worker 	    * Handle redirection and CGI status codes...
2385*5e7646d2SAndroid Build Coastguard Worker 	    */
2386*5e7646d2SAndroid Build Coastguard Worker 
2387*5e7646d2SAndroid Build Coastguard Worker 	    http_field_t field;		/* HTTP field */
2388*5e7646d2SAndroid Build Coastguard Worker 	    char	*value = strchr(con->header, ':');
2389*5e7646d2SAndroid Build Coastguard Worker 					/* Value of field */
2390*5e7646d2SAndroid Build Coastguard Worker 
2391*5e7646d2SAndroid Build Coastguard Worker 	    if (value)
2392*5e7646d2SAndroid Build Coastguard Worker 	    {
2393*5e7646d2SAndroid Build Coastguard Worker 	      *value++ = '\0';
2394*5e7646d2SAndroid Build Coastguard Worker 	      while (isspace(*value & 255))
2395*5e7646d2SAndroid Build Coastguard Worker 		value ++;
2396*5e7646d2SAndroid Build Coastguard Worker 	    }
2397*5e7646d2SAndroid Build Coastguard Worker 
2398*5e7646d2SAndroid Build Coastguard Worker 	    field = httpFieldValue(con->header);
2399*5e7646d2SAndroid Build Coastguard Worker 
2400*5e7646d2SAndroid Build Coastguard Worker 	    if (field != HTTP_FIELD_UNKNOWN && value)
2401*5e7646d2SAndroid Build Coastguard Worker 	    {
2402*5e7646d2SAndroid Build Coastguard Worker 	      httpSetField(con->http, field, value);
2403*5e7646d2SAndroid Build Coastguard Worker 
2404*5e7646d2SAndroid Build Coastguard Worker 	      if (field == HTTP_FIELD_LOCATION)
2405*5e7646d2SAndroid Build Coastguard Worker 	      {
2406*5e7646d2SAndroid Build Coastguard Worker 		con->pipe_status = HTTP_STATUS_SEE_OTHER;
2407*5e7646d2SAndroid Build Coastguard Worker 		con->sent_header = 2;
2408*5e7646d2SAndroid Build Coastguard Worker 	      }
2409*5e7646d2SAndroid Build Coastguard Worker 	      else
2410*5e7646d2SAndroid Build Coastguard Worker 	        con->sent_header = 1;
2411*5e7646d2SAndroid Build Coastguard Worker 	    }
2412*5e7646d2SAndroid Build Coastguard Worker 	    else if (!_cups_strcasecmp(con->header, "Status") && value)
2413*5e7646d2SAndroid Build Coastguard Worker 	    {
2414*5e7646d2SAndroid Build Coastguard Worker   	      con->pipe_status = (http_status_t)atoi(value);
2415*5e7646d2SAndroid Build Coastguard Worker 	      con->sent_header = 2;
2416*5e7646d2SAndroid Build Coastguard Worker 	    }
2417*5e7646d2SAndroid Build Coastguard Worker 	    else if (!_cups_strcasecmp(con->header, "Set-Cookie") && value)
2418*5e7646d2SAndroid Build Coastguard Worker 	    {
2419*5e7646d2SAndroid Build Coastguard Worker 	      httpSetCookie(con->http, value);
2420*5e7646d2SAndroid Build Coastguard Worker 	      con->sent_header = 1;
2421*5e7646d2SAndroid Build Coastguard Worker 	    }
2422*5e7646d2SAndroid Build Coastguard Worker 	  }
2423*5e7646d2SAndroid Build Coastguard Worker 
2424*5e7646d2SAndroid Build Coastguard Worker          /*
2425*5e7646d2SAndroid Build Coastguard Worker 	  * Update buffer...
2426*5e7646d2SAndroid Build Coastguard Worker 	  */
2427*5e7646d2SAndroid Build Coastguard Worker 
2428*5e7646d2SAndroid Build Coastguard Worker 	  con->header_used -= bufptr - con->header;
2429*5e7646d2SAndroid Build Coastguard Worker 
2430*5e7646d2SAndroid Build Coastguard Worker 	  if (con->header_used > 0)
2431*5e7646d2SAndroid Build Coastguard Worker 	    memmove(con->header, bufptr, (size_t)con->header_used);
2432*5e7646d2SAndroid Build Coastguard Worker 
2433*5e7646d2SAndroid Build Coastguard Worker 	  bufptr = con->header - 1;
2434*5e7646d2SAndroid Build Coastguard Worker 
2435*5e7646d2SAndroid Build Coastguard Worker          /*
2436*5e7646d2SAndroid Build Coastguard Worker 	  * See if the line was empty...
2437*5e7646d2SAndroid Build Coastguard Worker 	  */
2438*5e7646d2SAndroid Build Coastguard Worker 
2439*5e7646d2SAndroid Build Coastguard Worker 	  if (field_col == 0)
2440*5e7646d2SAndroid Build Coastguard Worker 	  {
2441*5e7646d2SAndroid Build Coastguard Worker 	    con->got_fields = 1;
2442*5e7646d2SAndroid Build Coastguard Worker 
2443*5e7646d2SAndroid Build Coastguard Worker 	    if (httpGetVersion(con->http) == HTTP_VERSION_1_1 &&
2444*5e7646d2SAndroid Build Coastguard Worker 		!httpGetField(con->http, HTTP_FIELD_CONTENT_LENGTH)[0])
2445*5e7646d2SAndroid Build Coastguard Worker 	      httpSetLength(con->http, 0);
2446*5e7646d2SAndroid Build Coastguard Worker 
2447*5e7646d2SAndroid Build Coastguard Worker             cupsdLogClient(con, CUPSD_LOG_DEBUG, "Sending status %d for CGI.", con->pipe_status);
2448*5e7646d2SAndroid Build Coastguard Worker 
2449*5e7646d2SAndroid Build Coastguard Worker             if (con->pipe_status == HTTP_STATUS_OK)
2450*5e7646d2SAndroid Build Coastguard Worker 	    {
2451*5e7646d2SAndroid Build Coastguard Worker 	      if (!cupsdSendHeader(con, con->pipe_status, NULL, CUPSD_AUTH_NONE))
2452*5e7646d2SAndroid Build Coastguard Worker 	      {
2453*5e7646d2SAndroid Build Coastguard Worker 		cupsdCloseClient(con);
2454*5e7646d2SAndroid Build Coastguard Worker 		return;
2455*5e7646d2SAndroid Build Coastguard Worker 	      }
2456*5e7646d2SAndroid Build Coastguard Worker 	    }
2457*5e7646d2SAndroid Build Coastguard Worker 	    else
2458*5e7646d2SAndroid Build Coastguard Worker 	    {
2459*5e7646d2SAndroid Build Coastguard Worker 	      if (!cupsdSendError(con, con->pipe_status, CUPSD_AUTH_NONE))
2460*5e7646d2SAndroid Build Coastguard Worker 	      {
2461*5e7646d2SAndroid Build Coastguard Worker 		cupsdCloseClient(con);
2462*5e7646d2SAndroid Build Coastguard Worker 		return;
2463*5e7646d2SAndroid Build Coastguard Worker 	      }
2464*5e7646d2SAndroid Build Coastguard Worker 	    }
2465*5e7646d2SAndroid Build Coastguard Worker           }
2466*5e7646d2SAndroid Build Coastguard Worker 	  else
2467*5e7646d2SAndroid Build Coastguard Worker 	    field_col = 0;
2468*5e7646d2SAndroid Build Coastguard Worker 	}
2469*5e7646d2SAndroid Build Coastguard Worker 	else if (*bufptr != '\r')
2470*5e7646d2SAndroid Build Coastguard Worker 	  field_col ++;
2471*5e7646d2SAndroid Build Coastguard Worker       }
2472*5e7646d2SAndroid Build Coastguard Worker 
2473*5e7646d2SAndroid Build Coastguard Worker       if (!con->got_fields)
2474*5e7646d2SAndroid Build Coastguard Worker         return;
2475*5e7646d2SAndroid Build Coastguard Worker     }
2476*5e7646d2SAndroid Build Coastguard Worker 
2477*5e7646d2SAndroid Build Coastguard Worker     if (con->header_used > 0)
2478*5e7646d2SAndroid Build Coastguard Worker     {
2479*5e7646d2SAndroid Build Coastguard Worker       if (httpWrite2(con->http, con->header, (size_t)con->header_used) < 0)
2480*5e7646d2SAndroid Build Coastguard Worker       {
2481*5e7646d2SAndroid Build Coastguard Worker 	cupsdLogClient(con, CUPSD_LOG_DEBUG, "Closing for error %d (%s)",
2482*5e7646d2SAndroid Build Coastguard Worker 		       httpError(con->http), strerror(httpError(con->http)));
2483*5e7646d2SAndroid Build Coastguard Worker 	cupsdCloseClient(con);
2484*5e7646d2SAndroid Build Coastguard Worker 	return;
2485*5e7646d2SAndroid Build Coastguard Worker       }
2486*5e7646d2SAndroid Build Coastguard Worker 
2487*5e7646d2SAndroid Build Coastguard Worker       if (httpIsChunked(con->http))
2488*5e7646d2SAndroid Build Coastguard Worker         httpFlushWrite(con->http);
2489*5e7646d2SAndroid Build Coastguard Worker 
2490*5e7646d2SAndroid Build Coastguard Worker       con->bytes += con->header_used;
2491*5e7646d2SAndroid Build Coastguard Worker 
2492*5e7646d2SAndroid Build Coastguard Worker       if (httpGetState(con->http) == HTTP_STATE_WAITING)
2493*5e7646d2SAndroid Build Coastguard Worker 	bytes = 0;
2494*5e7646d2SAndroid Build Coastguard Worker       else
2495*5e7646d2SAndroid Build Coastguard Worker         bytes = con->header_used;
2496*5e7646d2SAndroid Build Coastguard Worker 
2497*5e7646d2SAndroid Build Coastguard Worker       con->header_used = 0;
2498*5e7646d2SAndroid Build Coastguard Worker     }
2499*5e7646d2SAndroid Build Coastguard Worker   }
2500*5e7646d2SAndroid Build Coastguard Worker 
2501*5e7646d2SAndroid Build Coastguard Worker   if (bytes <= 0 ||
2502*5e7646d2SAndroid Build Coastguard Worker       (httpGetState(con->http) != HTTP_STATE_GET_SEND &&
2503*5e7646d2SAndroid Build Coastguard Worker        httpGetState(con->http) != HTTP_STATE_POST_SEND))
2504*5e7646d2SAndroid Build Coastguard Worker   {
2505*5e7646d2SAndroid Build Coastguard Worker     if (!con->sent_header && con->pipe_pid)
2506*5e7646d2SAndroid Build Coastguard Worker       cupsdSendError(con, HTTP_STATUS_SERVER_ERROR, CUPSD_AUTH_NONE);
2507*5e7646d2SAndroid Build Coastguard Worker     else
2508*5e7646d2SAndroid Build Coastguard Worker     {
2509*5e7646d2SAndroid Build Coastguard Worker       cupsdLogRequest(con, HTTP_STATUS_OK);
2510*5e7646d2SAndroid Build Coastguard Worker 
2511*5e7646d2SAndroid Build Coastguard Worker       if (httpIsChunked(con->http) && (!con->pipe_pid || con->sent_header > 0))
2512*5e7646d2SAndroid Build Coastguard Worker       {
2513*5e7646d2SAndroid Build Coastguard Worker         cupsdLogClient(con, CUPSD_LOG_DEBUG, "Sending 0-length chunk.");
2514*5e7646d2SAndroid Build Coastguard Worker 
2515*5e7646d2SAndroid Build Coastguard Worker 	if (httpWrite2(con->http, "", 0) < 0)
2516*5e7646d2SAndroid Build Coastguard Worker 	{
2517*5e7646d2SAndroid Build Coastguard Worker 	  cupsdLogClient(con, CUPSD_LOG_DEBUG, "Closing for error %d (%s)",
2518*5e7646d2SAndroid Build Coastguard Worker 			 httpError(con->http), strerror(httpError(con->http)));
2519*5e7646d2SAndroid Build Coastguard Worker 	  cupsdCloseClient(con);
2520*5e7646d2SAndroid Build Coastguard Worker 	  return;
2521*5e7646d2SAndroid Build Coastguard Worker 	}
2522*5e7646d2SAndroid Build Coastguard Worker       }
2523*5e7646d2SAndroid Build Coastguard Worker 
2524*5e7646d2SAndroid Build Coastguard Worker       cupsdLogClient(con, CUPSD_LOG_DEBUG, "Flushing write buffer.");
2525*5e7646d2SAndroid Build Coastguard Worker       httpFlushWrite(con->http);
2526*5e7646d2SAndroid Build Coastguard Worker       cupsdLogClient(con, CUPSD_LOG_DEBUG, "New state is %s", httpStateString(httpGetState(con->http)));
2527*5e7646d2SAndroid Build Coastguard Worker     }
2528*5e7646d2SAndroid Build Coastguard Worker 
2529*5e7646d2SAndroid Build Coastguard Worker     cupsdAddSelect(httpGetFd(con->http), (cupsd_selfunc_t)cupsdReadClient, NULL, con);
2530*5e7646d2SAndroid Build Coastguard Worker 
2531*5e7646d2SAndroid Build Coastguard Worker     cupsdLogClient(con, CUPSD_LOG_DEBUG, "Waiting for request.");
2532*5e7646d2SAndroid Build Coastguard Worker 
2533*5e7646d2SAndroid Build Coastguard Worker     if (con->file >= 0)
2534*5e7646d2SAndroid Build Coastguard Worker     {
2535*5e7646d2SAndroid Build Coastguard Worker       cupsdRemoveSelect(con->file);
2536*5e7646d2SAndroid Build Coastguard Worker 
2537*5e7646d2SAndroid Build Coastguard Worker       if (con->pipe_pid)
2538*5e7646d2SAndroid Build Coastguard Worker 	cupsdEndProcess(con->pipe_pid, 0);
2539*5e7646d2SAndroid Build Coastguard Worker 
2540*5e7646d2SAndroid Build Coastguard Worker       close(con->file);
2541*5e7646d2SAndroid Build Coastguard Worker       con->file     = -1;
2542*5e7646d2SAndroid Build Coastguard Worker       con->pipe_pid = 0;
2543*5e7646d2SAndroid Build Coastguard Worker     }
2544*5e7646d2SAndroid Build Coastguard Worker 
2545*5e7646d2SAndroid Build Coastguard Worker     if (con->filename)
2546*5e7646d2SAndroid Build Coastguard Worker     {
2547*5e7646d2SAndroid Build Coastguard Worker       unlink(con->filename);
2548*5e7646d2SAndroid Build Coastguard Worker       cupsdClearString(&con->filename);
2549*5e7646d2SAndroid Build Coastguard Worker     }
2550*5e7646d2SAndroid Build Coastguard Worker 
2551*5e7646d2SAndroid Build Coastguard Worker     if (con->request)
2552*5e7646d2SAndroid Build Coastguard Worker     {
2553*5e7646d2SAndroid Build Coastguard Worker       ippDelete(con->request);
2554*5e7646d2SAndroid Build Coastguard Worker       con->request = NULL;
2555*5e7646d2SAndroid Build Coastguard Worker     }
2556*5e7646d2SAndroid Build Coastguard Worker 
2557*5e7646d2SAndroid Build Coastguard Worker     if (con->response)
2558*5e7646d2SAndroid Build Coastguard Worker     {
2559*5e7646d2SAndroid Build Coastguard Worker       ippDelete(con->response);
2560*5e7646d2SAndroid Build Coastguard Worker       con->response = NULL;
2561*5e7646d2SAndroid Build Coastguard Worker     }
2562*5e7646d2SAndroid Build Coastguard Worker 
2563*5e7646d2SAndroid Build Coastguard Worker     cupsdClearString(&con->command);
2564*5e7646d2SAndroid Build Coastguard Worker     cupsdClearString(&con->options);
2565*5e7646d2SAndroid Build Coastguard Worker     cupsdClearString(&con->query_string);
2566*5e7646d2SAndroid Build Coastguard Worker 
2567*5e7646d2SAndroid Build Coastguard Worker     if (!httpGetKeepAlive(con->http))
2568*5e7646d2SAndroid Build Coastguard Worker     {
2569*5e7646d2SAndroid Build Coastguard Worker       cupsdLogClient(con, CUPSD_LOG_DEBUG,
2570*5e7646d2SAndroid Build Coastguard Worker 		     "Closing because Keep-Alive is disabled.");
2571*5e7646d2SAndroid Build Coastguard Worker       cupsdCloseClient(con);
2572*5e7646d2SAndroid Build Coastguard Worker       return;
2573*5e7646d2SAndroid Build Coastguard Worker     }
2574*5e7646d2SAndroid Build Coastguard Worker     else
2575*5e7646d2SAndroid Build Coastguard Worker     {
2576*5e7646d2SAndroid Build Coastguard Worker       cupsArrayRemove(ActiveClients, con);
2577*5e7646d2SAndroid Build Coastguard Worker       cupsdSetBusyState(0);
2578*5e7646d2SAndroid Build Coastguard Worker     }
2579*5e7646d2SAndroid Build Coastguard Worker   }
2580*5e7646d2SAndroid Build Coastguard Worker }
2581*5e7646d2SAndroid Build Coastguard Worker 
2582*5e7646d2SAndroid Build Coastguard Worker 
2583*5e7646d2SAndroid Build Coastguard Worker /*
2584*5e7646d2SAndroid Build Coastguard Worker  * 'check_if_modified()' - Decode an "If-Modified-Since" line.
2585*5e7646d2SAndroid Build Coastguard Worker  */
2586*5e7646d2SAndroid Build Coastguard Worker 
2587*5e7646d2SAndroid Build Coastguard Worker static int				/* O - 1 if modified since */
check_if_modified(cupsd_client_t * con,struct stat * filestats)2588*5e7646d2SAndroid Build Coastguard Worker check_if_modified(
2589*5e7646d2SAndroid Build Coastguard Worker     cupsd_client_t *con,		/* I - Client connection */
2590*5e7646d2SAndroid Build Coastguard Worker     struct stat    *filestats)		/* I - File information */
2591*5e7646d2SAndroid Build Coastguard Worker {
2592*5e7646d2SAndroid Build Coastguard Worker   const char	*ptr;			/* Pointer into field */
2593*5e7646d2SAndroid Build Coastguard Worker   time_t	date;			/* Time/date value */
2594*5e7646d2SAndroid Build Coastguard Worker   off_t		size;			/* Size/length value */
2595*5e7646d2SAndroid Build Coastguard Worker 
2596*5e7646d2SAndroid Build Coastguard Worker 
2597*5e7646d2SAndroid Build Coastguard Worker   size = 0;
2598*5e7646d2SAndroid Build Coastguard Worker   date = 0;
2599*5e7646d2SAndroid Build Coastguard Worker   ptr  = httpGetField(con->http, HTTP_FIELD_IF_MODIFIED_SINCE);
2600*5e7646d2SAndroid Build Coastguard Worker 
2601*5e7646d2SAndroid Build Coastguard Worker   if (*ptr == '\0')
2602*5e7646d2SAndroid Build Coastguard Worker     return (1);
2603*5e7646d2SAndroid Build Coastguard Worker 
2604*5e7646d2SAndroid Build Coastguard Worker   cupsdLogClient(con, CUPSD_LOG_DEBUG2, "check_if_modified: filestats=%p(" CUPS_LLFMT ", %d)) If-Modified-Since=\"%s\"", filestats, CUPS_LLCAST filestats->st_size, (int)filestats->st_mtime, ptr);
2605*5e7646d2SAndroid Build Coastguard Worker 
2606*5e7646d2SAndroid Build Coastguard Worker   while (*ptr != '\0')
2607*5e7646d2SAndroid Build Coastguard Worker   {
2608*5e7646d2SAndroid Build Coastguard Worker     while (isspace(*ptr) || *ptr == ';')
2609*5e7646d2SAndroid Build Coastguard Worker       ptr ++;
2610*5e7646d2SAndroid Build Coastguard Worker 
2611*5e7646d2SAndroid Build Coastguard Worker     if (_cups_strncasecmp(ptr, "length=", 7) == 0)
2612*5e7646d2SAndroid Build Coastguard Worker     {
2613*5e7646d2SAndroid Build Coastguard Worker       ptr += 7;
2614*5e7646d2SAndroid Build Coastguard Worker       size = strtoll(ptr, NULL, 10);
2615*5e7646d2SAndroid Build Coastguard Worker 
2616*5e7646d2SAndroid Build Coastguard Worker       while (isdigit(*ptr))
2617*5e7646d2SAndroid Build Coastguard Worker         ptr ++;
2618*5e7646d2SAndroid Build Coastguard Worker     }
2619*5e7646d2SAndroid Build Coastguard Worker     else if (isalpha(*ptr))
2620*5e7646d2SAndroid Build Coastguard Worker     {
2621*5e7646d2SAndroid Build Coastguard Worker       date = httpGetDateTime(ptr);
2622*5e7646d2SAndroid Build Coastguard Worker       while (*ptr != '\0' && *ptr != ';')
2623*5e7646d2SAndroid Build Coastguard Worker         ptr ++;
2624*5e7646d2SAndroid Build Coastguard Worker     }
2625*5e7646d2SAndroid Build Coastguard Worker     else
2626*5e7646d2SAndroid Build Coastguard Worker       ptr ++;
2627*5e7646d2SAndroid Build Coastguard Worker   }
2628*5e7646d2SAndroid Build Coastguard Worker 
2629*5e7646d2SAndroid Build Coastguard Worker   return ((size != filestats->st_size && size != 0) ||
2630*5e7646d2SAndroid Build Coastguard Worker           (date < filestats->st_mtime && date != 0) ||
2631*5e7646d2SAndroid Build Coastguard Worker 	  (size == 0 && date == 0));
2632*5e7646d2SAndroid Build Coastguard Worker }
2633*5e7646d2SAndroid Build Coastguard Worker 
2634*5e7646d2SAndroid Build Coastguard Worker 
2635*5e7646d2SAndroid Build Coastguard Worker /*
2636*5e7646d2SAndroid Build Coastguard Worker  * 'compare_clients()' - Compare two client connections.
2637*5e7646d2SAndroid Build Coastguard Worker  */
2638*5e7646d2SAndroid Build Coastguard Worker 
2639*5e7646d2SAndroid Build Coastguard Worker static int				/* O - Result of comparison */
compare_clients(cupsd_client_t * a,cupsd_client_t * b,void * data)2640*5e7646d2SAndroid Build Coastguard Worker compare_clients(cupsd_client_t *a,	/* I - First client */
2641*5e7646d2SAndroid Build Coastguard Worker                 cupsd_client_t *b,	/* I - Second client */
2642*5e7646d2SAndroid Build Coastguard Worker                 void           *data)	/* I - User data (not used) */
2643*5e7646d2SAndroid Build Coastguard Worker {
2644*5e7646d2SAndroid Build Coastguard Worker   (void)data;
2645*5e7646d2SAndroid Build Coastguard Worker 
2646*5e7646d2SAndroid Build Coastguard Worker   if (a == b)
2647*5e7646d2SAndroid Build Coastguard Worker     return (0);
2648*5e7646d2SAndroid Build Coastguard Worker   else if (a < b)
2649*5e7646d2SAndroid Build Coastguard Worker     return (-1);
2650*5e7646d2SAndroid Build Coastguard Worker   else
2651*5e7646d2SAndroid Build Coastguard Worker     return (1);
2652*5e7646d2SAndroid Build Coastguard Worker }
2653*5e7646d2SAndroid Build Coastguard Worker 
2654*5e7646d2SAndroid Build Coastguard Worker 
2655*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_SSL
2656*5e7646d2SAndroid Build Coastguard Worker /*
2657*5e7646d2SAndroid Build Coastguard Worker  * 'cupsd_start_tls()' - Start encryption on a connection.
2658*5e7646d2SAndroid Build Coastguard Worker  */
2659*5e7646d2SAndroid Build Coastguard Worker 
2660*5e7646d2SAndroid Build Coastguard Worker static int				/* O - 0 on success, -1 on error */
cupsd_start_tls(cupsd_client_t * con,http_encryption_t e)2661*5e7646d2SAndroid Build Coastguard Worker cupsd_start_tls(cupsd_client_t    *con,	/* I - Client connection */
2662*5e7646d2SAndroid Build Coastguard Worker                 http_encryption_t e)	/* I - Encryption mode */
2663*5e7646d2SAndroid Build Coastguard Worker {
2664*5e7646d2SAndroid Build Coastguard Worker   if (httpEncryption(con->http, e))
2665*5e7646d2SAndroid Build Coastguard Worker   {
2666*5e7646d2SAndroid Build Coastguard Worker     cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to encrypt connection: %s",
2667*5e7646d2SAndroid Build Coastguard Worker                    cupsLastErrorString());
2668*5e7646d2SAndroid Build Coastguard Worker     return (-1);
2669*5e7646d2SAndroid Build Coastguard Worker   }
2670*5e7646d2SAndroid Build Coastguard Worker 
2671*5e7646d2SAndroid Build Coastguard Worker   cupsdLogClient(con, CUPSD_LOG_DEBUG, "Connection now encrypted.");
2672*5e7646d2SAndroid Build Coastguard Worker   return (0);
2673*5e7646d2SAndroid Build Coastguard Worker }
2674*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_SSL */
2675*5e7646d2SAndroid Build Coastguard Worker 
2676*5e7646d2SAndroid Build Coastguard Worker 
2677*5e7646d2SAndroid Build Coastguard Worker /*
2678*5e7646d2SAndroid Build Coastguard Worker  * 'get_file()' - Get a filename and state info.
2679*5e7646d2SAndroid Build Coastguard Worker  */
2680*5e7646d2SAndroid Build Coastguard Worker 
2681*5e7646d2SAndroid Build Coastguard Worker static char *				/* O  - Real filename */
get_file(cupsd_client_t * con,struct stat * filestats,char * filename,size_t len)2682*5e7646d2SAndroid Build Coastguard Worker get_file(cupsd_client_t *con,		/* I  - Client connection */
2683*5e7646d2SAndroid Build Coastguard Worker          struct stat    *filestats,	/* O  - File information */
2684*5e7646d2SAndroid Build Coastguard Worker          char           *filename,	/* IO - Filename buffer */
2685*5e7646d2SAndroid Build Coastguard Worker          size_t         len)		/* I  - Buffer length */
2686*5e7646d2SAndroid Build Coastguard Worker {
2687*5e7646d2SAndroid Build Coastguard Worker   int		status;			/* Status of filesystem calls */
2688*5e7646d2SAndroid Build Coastguard Worker   char		*ptr;			/* Pointer info filename */
2689*5e7646d2SAndroid Build Coastguard Worker   size_t	plen;			/* Remaining length after pointer */
2690*5e7646d2SAndroid Build Coastguard Worker   char		language[7],		/* Language subdirectory, if any */
2691*5e7646d2SAndroid Build Coastguard Worker 		dest[1024];		/* Destination name */
2692*5e7646d2SAndroid Build Coastguard Worker   int		perm_check = 1;		/* Do permissions check? */
2693*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t *p;			/* Printer */
2694*5e7646d2SAndroid Build Coastguard Worker 
2695*5e7646d2SAndroid Build Coastguard Worker 
2696*5e7646d2SAndroid Build Coastguard Worker  /*
2697*5e7646d2SAndroid Build Coastguard Worker   * Figure out the real filename...
2698*5e7646d2SAndroid Build Coastguard Worker   */
2699*5e7646d2SAndroid Build Coastguard Worker 
2700*5e7646d2SAndroid Build Coastguard Worker   filename[0] = '\0';
2701*5e7646d2SAndroid Build Coastguard Worker   language[0] = '\0';
2702*5e7646d2SAndroid Build Coastguard Worker 
2703*5e7646d2SAndroid Build Coastguard Worker   if (!strncmp(con->uri, "/help", 5) && (con->uri[5] == '/' || !con->uri[5]))
2704*5e7646d2SAndroid Build Coastguard Worker   {
2705*5e7646d2SAndroid Build Coastguard Worker    /*
2706*5e7646d2SAndroid Build Coastguard Worker     * All help files are served by the help.cgi program...
2707*5e7646d2SAndroid Build Coastguard Worker     */
2708*5e7646d2SAndroid Build Coastguard Worker 
2709*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
2710*5e7646d2SAndroid Build Coastguard Worker   }
2711*5e7646d2SAndroid Build Coastguard Worker   else if ((!strncmp(con->uri, "/ppd/", 5) || !strncmp(con->uri, "/printers/", 10) || !strncmp(con->uri, "/classes/", 9)) && !strcmp(con->uri + strlen(con->uri) - 4, ".ppd"))
2712*5e7646d2SAndroid Build Coastguard Worker   {
2713*5e7646d2SAndroid Build Coastguard Worker     strlcpy(dest, strchr(con->uri + 1, '/') + 1, sizeof(dest));
2714*5e7646d2SAndroid Build Coastguard Worker     dest[strlen(dest) - 4] = '\0'; /* Strip .ppd */
2715*5e7646d2SAndroid Build Coastguard Worker 
2716*5e7646d2SAndroid Build Coastguard Worker     if ((p = cupsdFindDest(dest)) == NULL)
2717*5e7646d2SAndroid Build Coastguard Worker     {
2718*5e7646d2SAndroid Build Coastguard Worker       strlcpy(filename, "/", len);
2719*5e7646d2SAndroid Build Coastguard Worker       cupsdLogClient(con, CUPSD_LOG_INFO, "No destination \"%s\" found.", dest);
2720*5e7646d2SAndroid Build Coastguard Worker       return (NULL);
2721*5e7646d2SAndroid Build Coastguard Worker     }
2722*5e7646d2SAndroid Build Coastguard Worker 
2723*5e7646d2SAndroid Build Coastguard Worker     if (p->type & CUPS_PRINTER_CLASS)
2724*5e7646d2SAndroid Build Coastguard Worker     {
2725*5e7646d2SAndroid Build Coastguard Worker       int i;				/* Looping var */
2726*5e7646d2SAndroid Build Coastguard Worker 
2727*5e7646d2SAndroid Build Coastguard Worker       for (i = 0; i < p->num_printers; i ++)
2728*5e7646d2SAndroid Build Coastguard Worker       {
2729*5e7646d2SAndroid Build Coastguard Worker 	if (!(p->printers[i]->type & CUPS_PRINTER_CLASS))
2730*5e7646d2SAndroid Build Coastguard Worker 	{
2731*5e7646d2SAndroid Build Coastguard Worker 	  snprintf(filename, len, "%s/ppd/%s.ppd", ServerRoot, p->printers[i]->name);
2732*5e7646d2SAndroid Build Coastguard Worker 	  if (!access(filename, 0))
2733*5e7646d2SAndroid Build Coastguard Worker 	  {
2734*5e7646d2SAndroid Build Coastguard Worker 	    p = p->printers[i];
2735*5e7646d2SAndroid Build Coastguard Worker 	    break;
2736*5e7646d2SAndroid Build Coastguard Worker 	  }
2737*5e7646d2SAndroid Build Coastguard Worker 	}
2738*5e7646d2SAndroid Build Coastguard Worker       }
2739*5e7646d2SAndroid Build Coastguard Worker 
2740*5e7646d2SAndroid Build Coastguard Worker       if (i >= p->num_printers)
2741*5e7646d2SAndroid Build Coastguard Worker 	p = NULL;
2742*5e7646d2SAndroid Build Coastguard Worker     }
2743*5e7646d2SAndroid Build Coastguard Worker     else
2744*5e7646d2SAndroid Build Coastguard Worker       snprintf(filename, len, "%s/ppd/%s.ppd", ServerRoot, p->name);
2745*5e7646d2SAndroid Build Coastguard Worker 
2746*5e7646d2SAndroid Build Coastguard Worker     perm_check = 0;
2747*5e7646d2SAndroid Build Coastguard Worker   }
2748*5e7646d2SAndroid Build Coastguard Worker   else if ((!strncmp(con->uri, "/icons/", 7) || !strncmp(con->uri, "/printers/", 10) || !strncmp(con->uri, "/classes/", 9)) && !strcmp(con->uri + strlen(con->uri) - 4, ".png"))
2749*5e7646d2SAndroid Build Coastguard Worker   {
2750*5e7646d2SAndroid Build Coastguard Worker     strlcpy(dest, strchr(con->uri + 1, '/') + 1, sizeof(dest));
2751*5e7646d2SAndroid Build Coastguard Worker     dest[strlen(dest) - 4] = '\0'; /* Strip .png */
2752*5e7646d2SAndroid Build Coastguard Worker 
2753*5e7646d2SAndroid Build Coastguard Worker     if ((p = cupsdFindDest(dest)) == NULL)
2754*5e7646d2SAndroid Build Coastguard Worker     {
2755*5e7646d2SAndroid Build Coastguard Worker       strlcpy(filename, "/", len);
2756*5e7646d2SAndroid Build Coastguard Worker       cupsdLogClient(con, CUPSD_LOG_INFO, "No destination \"%s\" found.", dest);
2757*5e7646d2SAndroid Build Coastguard Worker       return (NULL);
2758*5e7646d2SAndroid Build Coastguard Worker     }
2759*5e7646d2SAndroid Build Coastguard Worker 
2760*5e7646d2SAndroid Build Coastguard Worker     if (p->type & CUPS_PRINTER_CLASS)
2761*5e7646d2SAndroid Build Coastguard Worker     {
2762*5e7646d2SAndroid Build Coastguard Worker       int i;				/* Looping var */
2763*5e7646d2SAndroid Build Coastguard Worker 
2764*5e7646d2SAndroid Build Coastguard Worker       for (i = 0; i < p->num_printers; i ++)
2765*5e7646d2SAndroid Build Coastguard Worker       {
2766*5e7646d2SAndroid Build Coastguard Worker 	if (!(p->printers[i]->type & CUPS_PRINTER_CLASS))
2767*5e7646d2SAndroid Build Coastguard Worker 	{
2768*5e7646d2SAndroid Build Coastguard Worker 	  snprintf(filename, len, "%s/images/%s.png", CacheDir, p->printers[i]->name);
2769*5e7646d2SAndroid Build Coastguard Worker 	  if (!access(filename, 0))
2770*5e7646d2SAndroid Build Coastguard Worker 	  {
2771*5e7646d2SAndroid Build Coastguard Worker 	    p = p->printers[i];
2772*5e7646d2SAndroid Build Coastguard Worker 	    break;
2773*5e7646d2SAndroid Build Coastguard Worker 	  }
2774*5e7646d2SAndroid Build Coastguard Worker 	}
2775*5e7646d2SAndroid Build Coastguard Worker       }
2776*5e7646d2SAndroid Build Coastguard Worker 
2777*5e7646d2SAndroid Build Coastguard Worker       if (i >= p->num_printers)
2778*5e7646d2SAndroid Build Coastguard Worker 	p = NULL;
2779*5e7646d2SAndroid Build Coastguard Worker     }
2780*5e7646d2SAndroid Build Coastguard Worker     else
2781*5e7646d2SAndroid Build Coastguard Worker       snprintf(filename, len, "%s/images/%s.png", CacheDir, p->name);
2782*5e7646d2SAndroid Build Coastguard Worker 
2783*5e7646d2SAndroid Build Coastguard Worker     if (access(filename, F_OK) < 0)
2784*5e7646d2SAndroid Build Coastguard Worker       snprintf(filename, len, "%s/images/generic.png", DocumentRoot);
2785*5e7646d2SAndroid Build Coastguard Worker 
2786*5e7646d2SAndroid Build Coastguard Worker     perm_check = 0;
2787*5e7646d2SAndroid Build Coastguard Worker   }
2788*5e7646d2SAndroid Build Coastguard Worker   else if (!strcmp(con->uri, "/admin/conf/cupsd.conf"))
2789*5e7646d2SAndroid Build Coastguard Worker   {
2790*5e7646d2SAndroid Build Coastguard Worker     strlcpy(filename, ConfigurationFile, len);
2791*5e7646d2SAndroid Build Coastguard Worker 
2792*5e7646d2SAndroid Build Coastguard Worker     perm_check = 0;
2793*5e7646d2SAndroid Build Coastguard Worker   }
2794*5e7646d2SAndroid Build Coastguard Worker   else if (!strncmp(con->uri, "/admin/log/", 11))
2795*5e7646d2SAndroid Build Coastguard Worker   {
2796*5e7646d2SAndroid Build Coastguard Worker     if (!strncmp(con->uri + 11, "access_log", 10) && AccessLog[0] == '/')
2797*5e7646d2SAndroid Build Coastguard Worker       strlcpy(filename, AccessLog, len);
2798*5e7646d2SAndroid Build Coastguard Worker     else if (!strncmp(con->uri + 11, "error_log", 9) && ErrorLog[0] == '/')
2799*5e7646d2SAndroid Build Coastguard Worker       strlcpy(filename, ErrorLog, len);
2800*5e7646d2SAndroid Build Coastguard Worker     else if (!strncmp(con->uri + 11, "page_log", 8) && PageLog[0] == '/')
2801*5e7646d2SAndroid Build Coastguard Worker       strlcpy(filename, PageLog, len);
2802*5e7646d2SAndroid Build Coastguard Worker     else
2803*5e7646d2SAndroid Build Coastguard Worker       return (NULL);
2804*5e7646d2SAndroid Build Coastguard Worker 
2805*5e7646d2SAndroid Build Coastguard Worker     perm_check = 0;
2806*5e7646d2SAndroid Build Coastguard Worker   }
2807*5e7646d2SAndroid Build Coastguard Worker   else if (!strncmp(con->uri, "/admin", 6) || !strncmp(con->uri, "/classes", 8) || !strncmp(con->uri, "/jobs", 5) || !strncmp(con->uri, "/printers", 9))
2808*5e7646d2SAndroid Build Coastguard Worker   {
2809*5e7646d2SAndroid Build Coastguard Worker    /*
2810*5e7646d2SAndroid Build Coastguard Worker     * Admin/class/job/printer pages are served by CGI...
2811*5e7646d2SAndroid Build Coastguard Worker     */
2812*5e7646d2SAndroid Build Coastguard Worker 
2813*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
2814*5e7646d2SAndroid Build Coastguard Worker   }
2815*5e7646d2SAndroid Build Coastguard Worker   else if (!strncmp(con->uri, "/rss/", 5) && !strchr(con->uri + 5, '/'))
2816*5e7646d2SAndroid Build Coastguard Worker     snprintf(filename, len, "%s/rss/%s", CacheDir, con->uri + 5);
2817*5e7646d2SAndroid Build Coastguard Worker   else if (!strncmp(con->uri, "/strings/", 9) && !strcmp(con->uri + strlen(con->uri) - 8, ".strings"))
2818*5e7646d2SAndroid Build Coastguard Worker   {
2819*5e7646d2SAndroid Build Coastguard Worker     strlcpy(dest, con->uri + 9, sizeof(dest));
2820*5e7646d2SAndroid Build Coastguard Worker     dest[strlen(dest) - 8] = '\0';
2821*5e7646d2SAndroid Build Coastguard Worker 
2822*5e7646d2SAndroid Build Coastguard Worker     if ((p = cupsdFindDest(dest)) == NULL)
2823*5e7646d2SAndroid Build Coastguard Worker     {
2824*5e7646d2SAndroid Build Coastguard Worker       strlcpy(filename, "/", len);
2825*5e7646d2SAndroid Build Coastguard Worker       cupsdLogClient(con, CUPSD_LOG_INFO, "No destination \"%s\" found.", dest);
2826*5e7646d2SAndroid Build Coastguard Worker       return (NULL);
2827*5e7646d2SAndroid Build Coastguard Worker     }
2828*5e7646d2SAndroid Build Coastguard Worker 
2829*5e7646d2SAndroid Build Coastguard Worker     if (!p->strings)
2830*5e7646d2SAndroid Build Coastguard Worker     {
2831*5e7646d2SAndroid Build Coastguard Worker       strlcpy(filename, "/", len);
2832*5e7646d2SAndroid Build Coastguard Worker       cupsdLogClient(con, CUPSD_LOG_INFO, "No strings files for \"%s\".", dest);
2833*5e7646d2SAndroid Build Coastguard Worker       return (NULL);
2834*5e7646d2SAndroid Build Coastguard Worker     }
2835*5e7646d2SAndroid Build Coastguard Worker 
2836*5e7646d2SAndroid Build Coastguard Worker     strlcpy(filename, p->strings, len);
2837*5e7646d2SAndroid Build Coastguard Worker 
2838*5e7646d2SAndroid Build Coastguard Worker     perm_check = 0;
2839*5e7646d2SAndroid Build Coastguard Worker   }
2840*5e7646d2SAndroid Build Coastguard Worker   else if (con->language)
2841*5e7646d2SAndroid Build Coastguard Worker   {
2842*5e7646d2SAndroid Build Coastguard Worker     snprintf(language, sizeof(language), "/%s", con->language->language);
2843*5e7646d2SAndroid Build Coastguard Worker     snprintf(filename, len, "%s%s%s", DocumentRoot, language, con->uri);
2844*5e7646d2SAndroid Build Coastguard Worker   }
2845*5e7646d2SAndroid Build Coastguard Worker   else
2846*5e7646d2SAndroid Build Coastguard Worker     snprintf(filename, len, "%s%s", DocumentRoot, con->uri);
2847*5e7646d2SAndroid Build Coastguard Worker 
2848*5e7646d2SAndroid Build Coastguard Worker   if ((ptr = strchr(filename, '?')) != NULL)
2849*5e7646d2SAndroid Build Coastguard Worker     *ptr = '\0';
2850*5e7646d2SAndroid Build Coastguard Worker 
2851*5e7646d2SAndroid Build Coastguard Worker  /*
2852*5e7646d2SAndroid Build Coastguard Worker   * Grab the status for this language; if there isn't a language-specific file
2853*5e7646d2SAndroid Build Coastguard Worker   * then fallback to the default one...
2854*5e7646d2SAndroid Build Coastguard Worker   */
2855*5e7646d2SAndroid Build Coastguard Worker 
2856*5e7646d2SAndroid Build Coastguard Worker   if ((status = lstat(filename, filestats)) != 0 && language[0] &&
2857*5e7646d2SAndroid Build Coastguard Worker       strncmp(con->uri, "/icons/", 7) &&
2858*5e7646d2SAndroid Build Coastguard Worker       strncmp(con->uri, "/ppd/", 5) &&
2859*5e7646d2SAndroid Build Coastguard Worker       strncmp(con->uri, "/rss/", 5) &&
2860*5e7646d2SAndroid Build Coastguard Worker       strncmp(con->uri, "/strings/", 9) &&
2861*5e7646d2SAndroid Build Coastguard Worker       strncmp(con->uri, "/admin/conf/", 12) &&
2862*5e7646d2SAndroid Build Coastguard Worker       strncmp(con->uri, "/admin/log/", 11))
2863*5e7646d2SAndroid Build Coastguard Worker   {
2864*5e7646d2SAndroid Build Coastguard Worker    /*
2865*5e7646d2SAndroid Build Coastguard Worker     * Drop the country code...
2866*5e7646d2SAndroid Build Coastguard Worker     */
2867*5e7646d2SAndroid Build Coastguard Worker 
2868*5e7646d2SAndroid Build Coastguard Worker     language[3] = '\0';
2869*5e7646d2SAndroid Build Coastguard Worker     snprintf(filename, len, "%s%s%s", DocumentRoot, language, con->uri);
2870*5e7646d2SAndroid Build Coastguard Worker 
2871*5e7646d2SAndroid Build Coastguard Worker     if ((ptr = strchr(filename, '?')) != NULL)
2872*5e7646d2SAndroid Build Coastguard Worker       *ptr = '\0';
2873*5e7646d2SAndroid Build Coastguard Worker 
2874*5e7646d2SAndroid Build Coastguard Worker     if ((status = lstat(filename, filestats)) != 0)
2875*5e7646d2SAndroid Build Coastguard Worker     {
2876*5e7646d2SAndroid Build Coastguard Worker      /*
2877*5e7646d2SAndroid Build Coastguard Worker       * Drop the language prefix and try the root directory...
2878*5e7646d2SAndroid Build Coastguard Worker       */
2879*5e7646d2SAndroid Build Coastguard Worker 
2880*5e7646d2SAndroid Build Coastguard Worker       language[0] = '\0';
2881*5e7646d2SAndroid Build Coastguard Worker       snprintf(filename, len, "%s%s", DocumentRoot, con->uri);
2882*5e7646d2SAndroid Build Coastguard Worker 
2883*5e7646d2SAndroid Build Coastguard Worker       if ((ptr = strchr(filename, '?')) != NULL)
2884*5e7646d2SAndroid Build Coastguard Worker 	*ptr = '\0';
2885*5e7646d2SAndroid Build Coastguard Worker 
2886*5e7646d2SAndroid Build Coastguard Worker       status = lstat(filename, filestats);
2887*5e7646d2SAndroid Build Coastguard Worker     }
2888*5e7646d2SAndroid Build Coastguard Worker   }
2889*5e7646d2SAndroid Build Coastguard Worker 
2890*5e7646d2SAndroid Build Coastguard Worker  /*
2891*5e7646d2SAndroid Build Coastguard Worker   * If we've found a symlink, 404 the sucker to avoid disclosing information.
2892*5e7646d2SAndroid Build Coastguard Worker   */
2893*5e7646d2SAndroid Build Coastguard Worker 
2894*5e7646d2SAndroid Build Coastguard Worker   if (!status && S_ISLNK(filestats->st_mode))
2895*5e7646d2SAndroid Build Coastguard Worker   {
2896*5e7646d2SAndroid Build Coastguard Worker     cupsdLogClient(con, CUPSD_LOG_INFO, "Symlinks such as \"%s\" are not allowed.", filename);
2897*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
2898*5e7646d2SAndroid Build Coastguard Worker   }
2899*5e7646d2SAndroid Build Coastguard Worker 
2900*5e7646d2SAndroid Build Coastguard Worker  /*
2901*5e7646d2SAndroid Build Coastguard Worker   * Similarly, if the file/directory does not have world read permissions, do
2902*5e7646d2SAndroid Build Coastguard Worker   * not allow access...
2903*5e7646d2SAndroid Build Coastguard Worker   */
2904*5e7646d2SAndroid Build Coastguard Worker 
2905*5e7646d2SAndroid Build Coastguard Worker   if (!status && perm_check && !(filestats->st_mode & S_IROTH))
2906*5e7646d2SAndroid Build Coastguard Worker   {
2907*5e7646d2SAndroid Build Coastguard Worker     cupsdLogClient(con, CUPSD_LOG_INFO, "Files/directories such as \"%s\" must be world-readable.", filename);
2908*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
2909*5e7646d2SAndroid Build Coastguard Worker   }
2910*5e7646d2SAndroid Build Coastguard Worker 
2911*5e7646d2SAndroid Build Coastguard Worker  /*
2912*5e7646d2SAndroid Build Coastguard Worker   * If we've found a directory, get the index.html file instead...
2913*5e7646d2SAndroid Build Coastguard Worker   */
2914*5e7646d2SAndroid Build Coastguard Worker 
2915*5e7646d2SAndroid Build Coastguard Worker   if (!status && S_ISDIR(filestats->st_mode))
2916*5e7646d2SAndroid Build Coastguard Worker   {
2917*5e7646d2SAndroid Build Coastguard Worker    /*
2918*5e7646d2SAndroid Build Coastguard Worker     * Make sure the URI ends with a slash...
2919*5e7646d2SAndroid Build Coastguard Worker     */
2920*5e7646d2SAndroid Build Coastguard Worker 
2921*5e7646d2SAndroid Build Coastguard Worker     if (con->uri[strlen(con->uri) - 1] != '/')
2922*5e7646d2SAndroid Build Coastguard Worker       strlcat(con->uri, "/", sizeof(con->uri));
2923*5e7646d2SAndroid Build Coastguard Worker 
2924*5e7646d2SAndroid Build Coastguard Worker    /*
2925*5e7646d2SAndroid Build Coastguard Worker     * Find the directory index file, trying every language...
2926*5e7646d2SAndroid Build Coastguard Worker     */
2927*5e7646d2SAndroid Build Coastguard Worker 
2928*5e7646d2SAndroid Build Coastguard Worker     do
2929*5e7646d2SAndroid Build Coastguard Worker     {
2930*5e7646d2SAndroid Build Coastguard Worker       if (status && language[0])
2931*5e7646d2SAndroid Build Coastguard Worker       {
2932*5e7646d2SAndroid Build Coastguard Worker        /*
2933*5e7646d2SAndroid Build Coastguard Worker         * Try a different language subset...
2934*5e7646d2SAndroid Build Coastguard Worker 	*/
2935*5e7646d2SAndroid Build Coastguard Worker 
2936*5e7646d2SAndroid Build Coastguard Worker 	if (language[3])
2937*5e7646d2SAndroid Build Coastguard Worker 	  language[3] = '\0';		/* Strip country code */
2938*5e7646d2SAndroid Build Coastguard Worker 	else
2939*5e7646d2SAndroid Build Coastguard Worker 	  language[0] = '\0';		/* Strip language */
2940*5e7646d2SAndroid Build Coastguard Worker       }
2941*5e7646d2SAndroid Build Coastguard Worker 
2942*5e7646d2SAndroid Build Coastguard Worker      /*
2943*5e7646d2SAndroid Build Coastguard Worker       * Look for the index file...
2944*5e7646d2SAndroid Build Coastguard Worker       */
2945*5e7646d2SAndroid Build Coastguard Worker 
2946*5e7646d2SAndroid Build Coastguard Worker       snprintf(filename, len, "%s%s%s", DocumentRoot, language, con->uri);
2947*5e7646d2SAndroid Build Coastguard Worker 
2948*5e7646d2SAndroid Build Coastguard Worker       if ((ptr = strchr(filename, '?')) != NULL)
2949*5e7646d2SAndroid Build Coastguard Worker 	*ptr = '\0';
2950*5e7646d2SAndroid Build Coastguard Worker 
2951*5e7646d2SAndroid Build Coastguard Worker       ptr  = filename + strlen(filename);
2952*5e7646d2SAndroid Build Coastguard Worker       plen = len - (size_t)(ptr - filename);
2953*5e7646d2SAndroid Build Coastguard Worker 
2954*5e7646d2SAndroid Build Coastguard Worker       strlcpy(ptr, "index.html", plen);
2955*5e7646d2SAndroid Build Coastguard Worker       status = lstat(filename, filestats);
2956*5e7646d2SAndroid Build Coastguard Worker     }
2957*5e7646d2SAndroid Build Coastguard Worker     while (status && language[0]);
2958*5e7646d2SAndroid Build Coastguard Worker 
2959*5e7646d2SAndroid Build Coastguard Worker    /*
2960*5e7646d2SAndroid Build Coastguard Worker     * If we've found a symlink, 404 the sucker to avoid disclosing information.
2961*5e7646d2SAndroid Build Coastguard Worker     */
2962*5e7646d2SAndroid Build Coastguard Worker 
2963*5e7646d2SAndroid Build Coastguard Worker     if (!status && S_ISLNK(filestats->st_mode))
2964*5e7646d2SAndroid Build Coastguard Worker     {
2965*5e7646d2SAndroid Build Coastguard Worker       cupsdLogClient(con, CUPSD_LOG_INFO, "Symlinks such as \"%s\" are not allowed.", filename);
2966*5e7646d2SAndroid Build Coastguard Worker       return (NULL);
2967*5e7646d2SAndroid Build Coastguard Worker     }
2968*5e7646d2SAndroid Build Coastguard Worker 
2969*5e7646d2SAndroid Build Coastguard Worker    /*
2970*5e7646d2SAndroid Build Coastguard Worker     * Similarly, if the file/directory does not have world read permissions, do
2971*5e7646d2SAndroid Build Coastguard Worker     * not allow access...
2972*5e7646d2SAndroid Build Coastguard Worker     */
2973*5e7646d2SAndroid Build Coastguard Worker 
2974*5e7646d2SAndroid Build Coastguard Worker     if (!status && perm_check && !(filestats->st_mode & S_IROTH))
2975*5e7646d2SAndroid Build Coastguard Worker     {
2976*5e7646d2SAndroid Build Coastguard Worker       cupsdLogClient(con, CUPSD_LOG_INFO, "Files/directories such as \"%s\" must be world-readable.", filename);
2977*5e7646d2SAndroid Build Coastguard Worker       return (NULL);
2978*5e7646d2SAndroid Build Coastguard Worker     }
2979*5e7646d2SAndroid Build Coastguard Worker   }
2980*5e7646d2SAndroid Build Coastguard Worker 
2981*5e7646d2SAndroid Build Coastguard Worker   cupsdLogClient(con, CUPSD_LOG_DEBUG2, "get_file: filestats=%p, filename=%p, len=" CUPS_LLFMT ", returning \"%s\".", filestats, filename, CUPS_LLCAST len, status ? "(null)" : filename);
2982*5e7646d2SAndroid Build Coastguard Worker 
2983*5e7646d2SAndroid Build Coastguard Worker   if (status)
2984*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
2985*5e7646d2SAndroid Build Coastguard Worker   else
2986*5e7646d2SAndroid Build Coastguard Worker     return (filename);
2987*5e7646d2SAndroid Build Coastguard Worker }
2988*5e7646d2SAndroid Build Coastguard Worker 
2989*5e7646d2SAndroid Build Coastguard Worker 
2990*5e7646d2SAndroid Build Coastguard Worker /*
2991*5e7646d2SAndroid Build Coastguard Worker  * 'install_cupsd_conf()' - Install a configuration file.
2992*5e7646d2SAndroid Build Coastguard Worker  */
2993*5e7646d2SAndroid Build Coastguard Worker 
2994*5e7646d2SAndroid Build Coastguard Worker static http_status_t			/* O - Status */
install_cupsd_conf(cupsd_client_t * con)2995*5e7646d2SAndroid Build Coastguard Worker install_cupsd_conf(cupsd_client_t *con)	/* I - Connection */
2996*5e7646d2SAndroid Build Coastguard Worker {
2997*5e7646d2SAndroid Build Coastguard Worker   char		filename[1024];		/* Configuration filename */
2998*5e7646d2SAndroid Build Coastguard Worker   cups_file_t	*in,			/* Input file */
2999*5e7646d2SAndroid Build Coastguard Worker 		*out;			/* Output file */
3000*5e7646d2SAndroid Build Coastguard Worker   char		buffer[16384];		/* Copy buffer */
3001*5e7646d2SAndroid Build Coastguard Worker   ssize_t	bytes;			/* Number of bytes */
3002*5e7646d2SAndroid Build Coastguard Worker 
3003*5e7646d2SAndroid Build Coastguard Worker 
3004*5e7646d2SAndroid Build Coastguard Worker  /*
3005*5e7646d2SAndroid Build Coastguard Worker   * Open the request file...
3006*5e7646d2SAndroid Build Coastguard Worker   */
3007*5e7646d2SAndroid Build Coastguard Worker 
3008*5e7646d2SAndroid Build Coastguard Worker   if ((in = cupsFileOpen(con->filename, "rb")) == NULL)
3009*5e7646d2SAndroid Build Coastguard Worker   {
3010*5e7646d2SAndroid Build Coastguard Worker     cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to open request file \"%s\": %s",
3011*5e7646d2SAndroid Build Coastguard Worker                     con->filename, strerror(errno));
3012*5e7646d2SAndroid Build Coastguard Worker     goto server_error;
3013*5e7646d2SAndroid Build Coastguard Worker   }
3014*5e7646d2SAndroid Build Coastguard Worker 
3015*5e7646d2SAndroid Build Coastguard Worker  /*
3016*5e7646d2SAndroid Build Coastguard Worker   * Open the new config file...
3017*5e7646d2SAndroid Build Coastguard Worker   */
3018*5e7646d2SAndroid Build Coastguard Worker 
3019*5e7646d2SAndroid Build Coastguard Worker   if ((out = cupsdCreateConfFile(ConfigurationFile, ConfigFilePerm)) == NULL)
3020*5e7646d2SAndroid Build Coastguard Worker   {
3021*5e7646d2SAndroid Build Coastguard Worker     cupsFileClose(in);
3022*5e7646d2SAndroid Build Coastguard Worker     goto server_error;
3023*5e7646d2SAndroid Build Coastguard Worker   }
3024*5e7646d2SAndroid Build Coastguard Worker 
3025*5e7646d2SAndroid Build Coastguard Worker   cupsdLogClient(con, CUPSD_LOG_INFO, "Installing config file \"%s\"...",
3026*5e7646d2SAndroid Build Coastguard Worker                   ConfigurationFile);
3027*5e7646d2SAndroid Build Coastguard Worker 
3028*5e7646d2SAndroid Build Coastguard Worker  /*
3029*5e7646d2SAndroid Build Coastguard Worker   * Copy from the request to the new config file...
3030*5e7646d2SAndroid Build Coastguard Worker   */
3031*5e7646d2SAndroid Build Coastguard Worker 
3032*5e7646d2SAndroid Build Coastguard Worker   while ((bytes = cupsFileRead(in, buffer, sizeof(buffer))) > 0)
3033*5e7646d2SAndroid Build Coastguard Worker     if (cupsFileWrite(out, buffer, (size_t)bytes) < bytes)
3034*5e7646d2SAndroid Build Coastguard Worker     {
3035*5e7646d2SAndroid Build Coastguard Worker       cupsdLogClient(con, CUPSD_LOG_ERROR,
3036*5e7646d2SAndroid Build Coastguard Worker                       "Unable to copy to config file \"%s\": %s",
3037*5e7646d2SAndroid Build Coastguard Worker         	      ConfigurationFile, strerror(errno));
3038*5e7646d2SAndroid Build Coastguard Worker 
3039*5e7646d2SAndroid Build Coastguard Worker       cupsFileClose(in);
3040*5e7646d2SAndroid Build Coastguard Worker       cupsFileClose(out);
3041*5e7646d2SAndroid Build Coastguard Worker 
3042*5e7646d2SAndroid Build Coastguard Worker       snprintf(filename, sizeof(filename), "%s.N", ConfigurationFile);
3043*5e7646d2SAndroid Build Coastguard Worker       cupsdUnlinkOrRemoveFile(filename);
3044*5e7646d2SAndroid Build Coastguard Worker 
3045*5e7646d2SAndroid Build Coastguard Worker       goto server_error;
3046*5e7646d2SAndroid Build Coastguard Worker     }
3047*5e7646d2SAndroid Build Coastguard Worker 
3048*5e7646d2SAndroid Build Coastguard Worker  /*
3049*5e7646d2SAndroid Build Coastguard Worker   * Close the files...
3050*5e7646d2SAndroid Build Coastguard Worker   */
3051*5e7646d2SAndroid Build Coastguard Worker 
3052*5e7646d2SAndroid Build Coastguard Worker   cupsFileClose(in);
3053*5e7646d2SAndroid Build Coastguard Worker 
3054*5e7646d2SAndroid Build Coastguard Worker   if (cupsdCloseCreatedConfFile(out, ConfigurationFile))
3055*5e7646d2SAndroid Build Coastguard Worker     goto server_error;
3056*5e7646d2SAndroid Build Coastguard Worker 
3057*5e7646d2SAndroid Build Coastguard Worker  /*
3058*5e7646d2SAndroid Build Coastguard Worker   * Remove the request file...
3059*5e7646d2SAndroid Build Coastguard Worker   */
3060*5e7646d2SAndroid Build Coastguard Worker 
3061*5e7646d2SAndroid Build Coastguard Worker   cupsdUnlinkOrRemoveFile(con->filename);
3062*5e7646d2SAndroid Build Coastguard Worker   cupsdClearString(&con->filename);
3063*5e7646d2SAndroid Build Coastguard Worker 
3064*5e7646d2SAndroid Build Coastguard Worker  /*
3065*5e7646d2SAndroid Build Coastguard Worker   * Set the NeedReload flag...
3066*5e7646d2SAndroid Build Coastguard Worker   */
3067*5e7646d2SAndroid Build Coastguard Worker 
3068*5e7646d2SAndroid Build Coastguard Worker   NeedReload = RELOAD_CUPSD;
3069*5e7646d2SAndroid Build Coastguard Worker   ReloadTime = time(NULL);
3070*5e7646d2SAndroid Build Coastguard Worker 
3071*5e7646d2SAndroid Build Coastguard Worker  /*
3072*5e7646d2SAndroid Build Coastguard Worker   * Return that the file was created successfully...
3073*5e7646d2SAndroid Build Coastguard Worker   */
3074*5e7646d2SAndroid Build Coastguard Worker 
3075*5e7646d2SAndroid Build Coastguard Worker   return (HTTP_STATUS_CREATED);
3076*5e7646d2SAndroid Build Coastguard Worker 
3077*5e7646d2SAndroid Build Coastguard Worker  /*
3078*5e7646d2SAndroid Build Coastguard Worker   * Common exit for errors...
3079*5e7646d2SAndroid Build Coastguard Worker   */
3080*5e7646d2SAndroid Build Coastguard Worker 
3081*5e7646d2SAndroid Build Coastguard Worker   server_error:
3082*5e7646d2SAndroid Build Coastguard Worker 
3083*5e7646d2SAndroid Build Coastguard Worker   cupsdUnlinkOrRemoveFile(con->filename);
3084*5e7646d2SAndroid Build Coastguard Worker   cupsdClearString(&con->filename);
3085*5e7646d2SAndroid Build Coastguard Worker 
3086*5e7646d2SAndroid Build Coastguard Worker   return (HTTP_STATUS_SERVER_ERROR);
3087*5e7646d2SAndroid Build Coastguard Worker }
3088*5e7646d2SAndroid Build Coastguard Worker 
3089*5e7646d2SAndroid Build Coastguard Worker 
3090*5e7646d2SAndroid Build Coastguard Worker /*
3091*5e7646d2SAndroid Build Coastguard Worker  * 'is_cgi()' - Is the resource a CGI script/program?
3092*5e7646d2SAndroid Build Coastguard Worker  */
3093*5e7646d2SAndroid Build Coastguard Worker 
3094*5e7646d2SAndroid Build Coastguard Worker static int				/* O - 1 = CGI, 0 = file */
is_cgi(cupsd_client_t * con,const char * filename,struct stat * filestats,mime_type_t * type)3095*5e7646d2SAndroid Build Coastguard Worker is_cgi(cupsd_client_t *con,		/* I - Client connection */
3096*5e7646d2SAndroid Build Coastguard Worker        const char     *filename,	/* I - Real filename */
3097*5e7646d2SAndroid Build Coastguard Worker        struct stat    *filestats,	/* I - File information */
3098*5e7646d2SAndroid Build Coastguard Worker        mime_type_t    *type)		/* I - MIME type */
3099*5e7646d2SAndroid Build Coastguard Worker {
3100*5e7646d2SAndroid Build Coastguard Worker   const char	*options;		/* Options on URL */
3101*5e7646d2SAndroid Build Coastguard Worker 
3102*5e7646d2SAndroid Build Coastguard Worker 
3103*5e7646d2SAndroid Build Coastguard Worker  /*
3104*5e7646d2SAndroid Build Coastguard Worker   * Get the options, if any...
3105*5e7646d2SAndroid Build Coastguard Worker   */
3106*5e7646d2SAndroid Build Coastguard Worker 
3107*5e7646d2SAndroid Build Coastguard Worker   if ((options = strchr(con->uri, '?')) != NULL)
3108*5e7646d2SAndroid Build Coastguard Worker   {
3109*5e7646d2SAndroid Build Coastguard Worker     options ++;
3110*5e7646d2SAndroid Build Coastguard Worker     cupsdSetStringf(&(con->query_string), "QUERY_STRING=%s", options);
3111*5e7646d2SAndroid Build Coastguard Worker   }
3112*5e7646d2SAndroid Build Coastguard Worker 
3113*5e7646d2SAndroid Build Coastguard Worker  /*
3114*5e7646d2SAndroid Build Coastguard Worker   * Check for known types...
3115*5e7646d2SAndroid Build Coastguard Worker   */
3116*5e7646d2SAndroid Build Coastguard Worker 
3117*5e7646d2SAndroid Build Coastguard Worker   if (!type || _cups_strcasecmp(type->super, "application"))
3118*5e7646d2SAndroid Build Coastguard Worker   {
3119*5e7646d2SAndroid Build Coastguard Worker     cupsdLogClient(con, CUPSD_LOG_DEBUG2, "is_cgi: filename=\"%s\", filestats=%p, type=%s/%s, returning 0.", filename, filestats, type ? type->super : "unknown", type ? type->type : "unknown");
3120*5e7646d2SAndroid Build Coastguard Worker     return (0);
3121*5e7646d2SAndroid Build Coastguard Worker   }
3122*5e7646d2SAndroid Build Coastguard Worker 
3123*5e7646d2SAndroid Build Coastguard Worker   if (!_cups_strcasecmp(type->type, "x-httpd-cgi") && (filestats->st_mode & 0111) && (getuid() || !(filestats->st_mode & 022)))
3124*5e7646d2SAndroid Build Coastguard Worker   {
3125*5e7646d2SAndroid Build Coastguard Worker    /*
3126*5e7646d2SAndroid Build Coastguard Worker     * "application/x-httpd-cgi" is a CGI script.
3127*5e7646d2SAndroid Build Coastguard Worker     */
3128*5e7646d2SAndroid Build Coastguard Worker 
3129*5e7646d2SAndroid Build Coastguard Worker     cupsdSetString(&con->command, filename);
3130*5e7646d2SAndroid Build Coastguard Worker 
3131*5e7646d2SAndroid Build Coastguard Worker     if (options)
3132*5e7646d2SAndroid Build Coastguard Worker       cupsdSetStringf(&con->options, " %s", options);
3133*5e7646d2SAndroid Build Coastguard Worker 
3134*5e7646d2SAndroid Build Coastguard Worker     cupsdLogClient(con, CUPSD_LOG_DEBUG2, "is_cgi: filename=\"%s\", filestats=%p, type=%s/%s, returning 1.", filename, filestats, type->super, type->type);
3135*5e7646d2SAndroid Build Coastguard Worker     return (1);
3136*5e7646d2SAndroid Build Coastguard Worker   }
3137*5e7646d2SAndroid Build Coastguard Worker 
3138*5e7646d2SAndroid Build Coastguard Worker   cupsdLogClient(con, CUPSD_LOG_DEBUG2, "is_cgi: filename=\"%s\", filestats=%p, type=%s/%s, returning 0.", filename, filestats, type->super, type->type);
3139*5e7646d2SAndroid Build Coastguard Worker   return (0);
3140*5e7646d2SAndroid Build Coastguard Worker }
3141*5e7646d2SAndroid Build Coastguard Worker 
3142*5e7646d2SAndroid Build Coastguard Worker 
3143*5e7646d2SAndroid Build Coastguard Worker /*
3144*5e7646d2SAndroid Build Coastguard Worker  * 'is_path_absolute()' - Is a path absolute and free of relative elements (i.e. "..").
3145*5e7646d2SAndroid Build Coastguard Worker  */
3146*5e7646d2SAndroid Build Coastguard Worker 
3147*5e7646d2SAndroid Build Coastguard Worker static int				/* O - 0 if relative, 1 if absolute */
is_path_absolute(const char * path)3148*5e7646d2SAndroid Build Coastguard Worker is_path_absolute(const char *path)	/* I - Input path */
3149*5e7646d2SAndroid Build Coastguard Worker {
3150*5e7646d2SAndroid Build Coastguard Worker  /*
3151*5e7646d2SAndroid Build Coastguard Worker   * Check for a leading slash...
3152*5e7646d2SAndroid Build Coastguard Worker   */
3153*5e7646d2SAndroid Build Coastguard Worker 
3154*5e7646d2SAndroid Build Coastguard Worker   if (path[0] != '/')
3155*5e7646d2SAndroid Build Coastguard Worker     return (0);
3156*5e7646d2SAndroid Build Coastguard Worker 
3157*5e7646d2SAndroid Build Coastguard Worker  /*
3158*5e7646d2SAndroid Build Coastguard Worker   * Check for "<" or quotes in the path and reject since this is probably
3159*5e7646d2SAndroid Build Coastguard Worker   * someone trying to inject HTML...
3160*5e7646d2SAndroid Build Coastguard Worker   */
3161*5e7646d2SAndroid Build Coastguard Worker 
3162*5e7646d2SAndroid Build Coastguard Worker   if (strchr(path, '<') != NULL || strchr(path, '\"') != NULL || strchr(path, '\'') != NULL)
3163*5e7646d2SAndroid Build Coastguard Worker     return (0);
3164*5e7646d2SAndroid Build Coastguard Worker 
3165*5e7646d2SAndroid Build Coastguard Worker  /*
3166*5e7646d2SAndroid Build Coastguard Worker   * Check for "/.." in the path...
3167*5e7646d2SAndroid Build Coastguard Worker   */
3168*5e7646d2SAndroid Build Coastguard Worker 
3169*5e7646d2SAndroid Build Coastguard Worker   while ((path = strstr(path, "/..")) != NULL)
3170*5e7646d2SAndroid Build Coastguard Worker   {
3171*5e7646d2SAndroid Build Coastguard Worker     if (!path[3] || path[3] == '/')
3172*5e7646d2SAndroid Build Coastguard Worker       return (0);
3173*5e7646d2SAndroid Build Coastguard Worker 
3174*5e7646d2SAndroid Build Coastguard Worker     path ++;
3175*5e7646d2SAndroid Build Coastguard Worker   }
3176*5e7646d2SAndroid Build Coastguard Worker 
3177*5e7646d2SAndroid Build Coastguard Worker  /*
3178*5e7646d2SAndroid Build Coastguard Worker   * If we haven't found any relative paths, return 1 indicating an
3179*5e7646d2SAndroid Build Coastguard Worker   * absolute path...
3180*5e7646d2SAndroid Build Coastguard Worker   */
3181*5e7646d2SAndroid Build Coastguard Worker 
3182*5e7646d2SAndroid Build Coastguard Worker   return (1);
3183*5e7646d2SAndroid Build Coastguard Worker }
3184*5e7646d2SAndroid Build Coastguard Worker 
3185*5e7646d2SAndroid Build Coastguard Worker 
3186*5e7646d2SAndroid Build Coastguard Worker /*
3187*5e7646d2SAndroid Build Coastguard Worker  * 'pipe_command()' - Pipe the output of a command to the remote client.
3188*5e7646d2SAndroid Build Coastguard Worker  */
3189*5e7646d2SAndroid Build Coastguard Worker 
3190*5e7646d2SAndroid Build Coastguard Worker static int				/* O - Process ID */
pipe_command(cupsd_client_t * con,int infile,int * outfile,char * command,char * options,int root)3191*5e7646d2SAndroid Build Coastguard Worker pipe_command(cupsd_client_t *con,	/* I - Client connection */
3192*5e7646d2SAndroid Build Coastguard Worker              int            infile,	/* I - Standard input for command */
3193*5e7646d2SAndroid Build Coastguard Worker              int            *outfile,	/* O - Standard output for command */
3194*5e7646d2SAndroid Build Coastguard Worker 	     char           *command,	/* I - Command to run */
3195*5e7646d2SAndroid Build Coastguard Worker 	     char           *options,	/* I - Options for command */
3196*5e7646d2SAndroid Build Coastguard Worker 	     int            root)	/* I - Run as root? */
3197*5e7646d2SAndroid Build Coastguard Worker {
3198*5e7646d2SAndroid Build Coastguard Worker   int		i;			/* Looping var */
3199*5e7646d2SAndroid Build Coastguard Worker   int		pid;			/* Process ID */
3200*5e7646d2SAndroid Build Coastguard Worker   char		*commptr,		/* Command string pointer */
3201*5e7646d2SAndroid Build Coastguard Worker 		commch;			/* Command string character */
3202*5e7646d2SAndroid Build Coastguard Worker   char		*uriptr;		/* URI string pointer */
3203*5e7646d2SAndroid Build Coastguard Worker   int		fds[2];			/* Pipe FDs */
3204*5e7646d2SAndroid Build Coastguard Worker   int		argc;			/* Number of arguments */
3205*5e7646d2SAndroid Build Coastguard Worker   int		envc;			/* Number of environment variables */
3206*5e7646d2SAndroid Build Coastguard Worker   char		argbuf[10240],		/* Argument buffer */
3207*5e7646d2SAndroid Build Coastguard Worker 		*argv[100],		/* Argument strings */
3208*5e7646d2SAndroid Build Coastguard Worker 		*envp[MAX_ENV + 20];	/* Environment variables */
3209*5e7646d2SAndroid Build Coastguard Worker   char		auth_type[256],		/* AUTH_TYPE environment variable */
3210*5e7646d2SAndroid Build Coastguard Worker 		content_length[1024],	/* CONTENT_LENGTH environment variable */
3211*5e7646d2SAndroid Build Coastguard Worker 		content_type[1024],	/* CONTENT_TYPE environment variable */
3212*5e7646d2SAndroid Build Coastguard Worker 		http_cookie[32768],	/* HTTP_COOKIE environment variable */
3213*5e7646d2SAndroid Build Coastguard Worker 		http_referer[1024],	/* HTTP_REFERER environment variable */
3214*5e7646d2SAndroid Build Coastguard Worker 		http_user_agent[1024],	/* HTTP_USER_AGENT environment variable */
3215*5e7646d2SAndroid Build Coastguard Worker 		lang[1024],		/* LANG environment variable */
3216*5e7646d2SAndroid Build Coastguard Worker 		path_info[1024],	/* PATH_INFO environment variable */
3217*5e7646d2SAndroid Build Coastguard Worker 		remote_addr[1024],	/* REMOTE_ADDR environment variable */
3218*5e7646d2SAndroid Build Coastguard Worker 		remote_host[1024],	/* REMOTE_HOST environment variable */
3219*5e7646d2SAndroid Build Coastguard Worker 		remote_user[1024],	/* REMOTE_USER environment variable */
3220*5e7646d2SAndroid Build Coastguard Worker 		script_filename[1024],	/* SCRIPT_FILENAME environment variable */
3221*5e7646d2SAndroid Build Coastguard Worker 		script_name[1024],	/* SCRIPT_NAME environment variable */
3222*5e7646d2SAndroid Build Coastguard Worker 		server_name[1024],	/* SERVER_NAME environment variable */
3223*5e7646d2SAndroid Build Coastguard Worker 		server_port[1024];	/* SERVER_PORT environment variable */
3224*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t *attr;		/* attributes-natural-language attribute */
3225*5e7646d2SAndroid Build Coastguard Worker 
3226*5e7646d2SAndroid Build Coastguard Worker 
3227*5e7646d2SAndroid Build Coastguard Worker  /*
3228*5e7646d2SAndroid Build Coastguard Worker   * Parse a copy of the options string, which is of the form:
3229*5e7646d2SAndroid Build Coastguard Worker   *
3230*5e7646d2SAndroid Build Coastguard Worker   *     argument+argument+argument
3231*5e7646d2SAndroid Build Coastguard Worker   *     ?argument+argument+argument
3232*5e7646d2SAndroid Build Coastguard Worker   *     param=value&param=value
3233*5e7646d2SAndroid Build Coastguard Worker   *     ?param=value&param=value
3234*5e7646d2SAndroid Build Coastguard Worker   *     /name?argument+argument+argument
3235*5e7646d2SAndroid Build Coastguard Worker   *     /name?param=value&param=value
3236*5e7646d2SAndroid Build Coastguard Worker   *
3237*5e7646d2SAndroid Build Coastguard Worker   * If the string contains an "=" character after the initial name,
3238*5e7646d2SAndroid Build Coastguard Worker   * then we treat it as a HTTP GET form request and make a copy of
3239*5e7646d2SAndroid Build Coastguard Worker   * the remaining string for the environment variable.
3240*5e7646d2SAndroid Build Coastguard Worker   *
3241*5e7646d2SAndroid Build Coastguard Worker   * The string is always parsed out as command-line arguments, to
3242*5e7646d2SAndroid Build Coastguard Worker   * be consistent with Apache...
3243*5e7646d2SAndroid Build Coastguard Worker   */
3244*5e7646d2SAndroid Build Coastguard Worker 
3245*5e7646d2SAndroid Build Coastguard Worker   cupsdLogClient(con, CUPSD_LOG_DEBUG2, "pipe_command: infile=%d, outfile=%p, command=\"%s\", options=\"%s\", root=%d", infile, outfile, command, options ? options : "(null)", root);
3246*5e7646d2SAndroid Build Coastguard Worker 
3247*5e7646d2SAndroid Build Coastguard Worker   argv[0] = command;
3248*5e7646d2SAndroid Build Coastguard Worker 
3249*5e7646d2SAndroid Build Coastguard Worker   if (options)
3250*5e7646d2SAndroid Build Coastguard Worker     strlcpy(argbuf, options, sizeof(argbuf));
3251*5e7646d2SAndroid Build Coastguard Worker   else
3252*5e7646d2SAndroid Build Coastguard Worker     argbuf[0] = '\0';
3253*5e7646d2SAndroid Build Coastguard Worker 
3254*5e7646d2SAndroid Build Coastguard Worker   if (argbuf[0] == '/')
3255*5e7646d2SAndroid Build Coastguard Worker   {
3256*5e7646d2SAndroid Build Coastguard Worker    /*
3257*5e7646d2SAndroid Build Coastguard Worker     * Found some trailing path information, set PATH_INFO...
3258*5e7646d2SAndroid Build Coastguard Worker     */
3259*5e7646d2SAndroid Build Coastguard Worker 
3260*5e7646d2SAndroid Build Coastguard Worker     if ((commptr = strchr(argbuf, '?')) == NULL)
3261*5e7646d2SAndroid Build Coastguard Worker       commptr = argbuf + strlen(argbuf);
3262*5e7646d2SAndroid Build Coastguard Worker 
3263*5e7646d2SAndroid Build Coastguard Worker     commch   = *commptr;
3264*5e7646d2SAndroid Build Coastguard Worker     *commptr = '\0';
3265*5e7646d2SAndroid Build Coastguard Worker     snprintf(path_info, sizeof(path_info), "PATH_INFO=%s", argbuf);
3266*5e7646d2SAndroid Build Coastguard Worker     *commptr = commch;
3267*5e7646d2SAndroid Build Coastguard Worker   }
3268*5e7646d2SAndroid Build Coastguard Worker   else
3269*5e7646d2SAndroid Build Coastguard Worker   {
3270*5e7646d2SAndroid Build Coastguard Worker     commptr      = argbuf;
3271*5e7646d2SAndroid Build Coastguard Worker     path_info[0] = '\0';
3272*5e7646d2SAndroid Build Coastguard Worker 
3273*5e7646d2SAndroid Build Coastguard Worker     if (*commptr == ' ')
3274*5e7646d2SAndroid Build Coastguard Worker       commptr ++;
3275*5e7646d2SAndroid Build Coastguard Worker   }
3276*5e7646d2SAndroid Build Coastguard Worker 
3277*5e7646d2SAndroid Build Coastguard Worker   if (*commptr == '?' && con->operation == HTTP_STATE_GET && !con->query_string)
3278*5e7646d2SAndroid Build Coastguard Worker   {
3279*5e7646d2SAndroid Build Coastguard Worker     commptr ++;
3280*5e7646d2SAndroid Build Coastguard Worker     cupsdSetStringf(&(con->query_string), "QUERY_STRING=%s", commptr);
3281*5e7646d2SAndroid Build Coastguard Worker   }
3282*5e7646d2SAndroid Build Coastguard Worker 
3283*5e7646d2SAndroid Build Coastguard Worker   argc = 1;
3284*5e7646d2SAndroid Build Coastguard Worker 
3285*5e7646d2SAndroid Build Coastguard Worker   if (*commptr)
3286*5e7646d2SAndroid Build Coastguard Worker   {
3287*5e7646d2SAndroid Build Coastguard Worker     argv[argc ++] = commptr;
3288*5e7646d2SAndroid Build Coastguard Worker 
3289*5e7646d2SAndroid Build Coastguard Worker     for (; *commptr && argc < 99; commptr ++)
3290*5e7646d2SAndroid Build Coastguard Worker     {
3291*5e7646d2SAndroid Build Coastguard Worker      /*
3292*5e7646d2SAndroid Build Coastguard Worker       * Break arguments whenever we see a + or space...
3293*5e7646d2SAndroid Build Coastguard Worker       */
3294*5e7646d2SAndroid Build Coastguard Worker 
3295*5e7646d2SAndroid Build Coastguard Worker       if (*commptr == ' ' || *commptr == '+')
3296*5e7646d2SAndroid Build Coastguard Worker       {
3297*5e7646d2SAndroid Build Coastguard Worker 	while (*commptr == ' ' || *commptr == '+')
3298*5e7646d2SAndroid Build Coastguard Worker 	  *commptr++ = '\0';
3299*5e7646d2SAndroid Build Coastguard Worker 
3300*5e7646d2SAndroid Build Coastguard Worker        /*
3301*5e7646d2SAndroid Build Coastguard Worker 	* If we don't have a blank string, save it as another argument...
3302*5e7646d2SAndroid Build Coastguard Worker 	*/
3303*5e7646d2SAndroid Build Coastguard Worker 
3304*5e7646d2SAndroid Build Coastguard Worker 	if (*commptr)
3305*5e7646d2SAndroid Build Coastguard Worker 	{
3306*5e7646d2SAndroid Build Coastguard Worker 	  argv[argc] = commptr;
3307*5e7646d2SAndroid Build Coastguard Worker 	  argc ++;
3308*5e7646d2SAndroid Build Coastguard Worker 	}
3309*5e7646d2SAndroid Build Coastguard Worker 	else
3310*5e7646d2SAndroid Build Coastguard Worker 	  break;
3311*5e7646d2SAndroid Build Coastguard Worker       }
3312*5e7646d2SAndroid Build Coastguard Worker       else if (*commptr == '%' && isxdigit(commptr[1] & 255) &&
3313*5e7646d2SAndroid Build Coastguard Worker                isxdigit(commptr[2] & 255))
3314*5e7646d2SAndroid Build Coastguard Worker       {
3315*5e7646d2SAndroid Build Coastguard Worker        /*
3316*5e7646d2SAndroid Build Coastguard Worker 	* Convert the %xx notation to the individual character.
3317*5e7646d2SAndroid Build Coastguard Worker 	*/
3318*5e7646d2SAndroid Build Coastguard Worker 
3319*5e7646d2SAndroid Build Coastguard Worker 	if (commptr[1] >= '0' && commptr[1] <= '9')
3320*5e7646d2SAndroid Build Coastguard Worker           *commptr = (char)((commptr[1] - '0') << 4);
3321*5e7646d2SAndroid Build Coastguard Worker 	else
3322*5e7646d2SAndroid Build Coastguard Worker           *commptr = (char)((tolower(commptr[1]) - 'a' + 10) << 4);
3323*5e7646d2SAndroid Build Coastguard Worker 
3324*5e7646d2SAndroid Build Coastguard Worker 	if (commptr[2] >= '0' && commptr[2] <= '9')
3325*5e7646d2SAndroid Build Coastguard Worker           *commptr |= commptr[2] - '0';
3326*5e7646d2SAndroid Build Coastguard Worker 	else
3327*5e7646d2SAndroid Build Coastguard Worker           *commptr |= tolower(commptr[2]) - 'a' + 10;
3328*5e7646d2SAndroid Build Coastguard Worker 
3329*5e7646d2SAndroid Build Coastguard Worker 	_cups_strcpy(commptr + 1, commptr + 3);
3330*5e7646d2SAndroid Build Coastguard Worker 
3331*5e7646d2SAndroid Build Coastguard Worker        /*
3332*5e7646d2SAndroid Build Coastguard Worker 	* Check for a %00 and break if that is the case...
3333*5e7646d2SAndroid Build Coastguard Worker 	*/
3334*5e7646d2SAndroid Build Coastguard Worker 
3335*5e7646d2SAndroid Build Coastguard Worker 	if (!*commptr)
3336*5e7646d2SAndroid Build Coastguard Worker           break;
3337*5e7646d2SAndroid Build Coastguard Worker       }
3338*5e7646d2SAndroid Build Coastguard Worker     }
3339*5e7646d2SAndroid Build Coastguard Worker   }
3340*5e7646d2SAndroid Build Coastguard Worker 
3341*5e7646d2SAndroid Build Coastguard Worker   argv[argc] = NULL;
3342*5e7646d2SAndroid Build Coastguard Worker 
3343*5e7646d2SAndroid Build Coastguard Worker  /*
3344*5e7646d2SAndroid Build Coastguard Worker   * Setup the environment variables as needed...
3345*5e7646d2SAndroid Build Coastguard Worker   */
3346*5e7646d2SAndroid Build Coastguard Worker 
3347*5e7646d2SAndroid Build Coastguard Worker   if (con->username[0])
3348*5e7646d2SAndroid Build Coastguard Worker   {
3349*5e7646d2SAndroid Build Coastguard Worker     snprintf(auth_type, sizeof(auth_type), "AUTH_TYPE=%s",
3350*5e7646d2SAndroid Build Coastguard Worker              httpGetField(con->http, HTTP_FIELD_AUTHORIZATION));
3351*5e7646d2SAndroid Build Coastguard Worker 
3352*5e7646d2SAndroid Build Coastguard Worker     if ((uriptr = strchr(auth_type + 10, ' ')) != NULL)
3353*5e7646d2SAndroid Build Coastguard Worker       *uriptr = '\0';
3354*5e7646d2SAndroid Build Coastguard Worker   }
3355*5e7646d2SAndroid Build Coastguard Worker   else
3356*5e7646d2SAndroid Build Coastguard Worker     auth_type[0] = '\0';
3357*5e7646d2SAndroid Build Coastguard Worker 
3358*5e7646d2SAndroid Build Coastguard Worker   if (con->request && (attr = ippFindAttribute(con->request, "attributes-natural-language", IPP_TAG_LANGUAGE)) != NULL)
3359*5e7646d2SAndroid Build Coastguard Worker   {
3360*5e7646d2SAndroid Build Coastguard Worker     cups_lang_t *language = cupsLangGet(ippGetString(attr, 0, NULL));
3361*5e7646d2SAndroid Build Coastguard Worker 
3362*5e7646d2SAndroid Build Coastguard Worker     snprintf(lang, sizeof(lang), "LANG=%s.UTF8", language->language);
3363*5e7646d2SAndroid Build Coastguard Worker     cupsLangFree(language);
3364*5e7646d2SAndroid Build Coastguard Worker   }
3365*5e7646d2SAndroid Build Coastguard Worker   else if (con->language)
3366*5e7646d2SAndroid Build Coastguard Worker     snprintf(lang, sizeof(lang), "LANG=%s.UTF8", con->language->language);
3367*5e7646d2SAndroid Build Coastguard Worker   else
3368*5e7646d2SAndroid Build Coastguard Worker     strlcpy(lang, "LANG=C", sizeof(lang));
3369*5e7646d2SAndroid Build Coastguard Worker 
3370*5e7646d2SAndroid Build Coastguard Worker   strlcpy(remote_addr, "REMOTE_ADDR=", sizeof(remote_addr));
3371*5e7646d2SAndroid Build Coastguard Worker   httpAddrString(httpGetAddress(con->http), remote_addr + 12,
3372*5e7646d2SAndroid Build Coastguard Worker                  sizeof(remote_addr) - 12);
3373*5e7646d2SAndroid Build Coastguard Worker 
3374*5e7646d2SAndroid Build Coastguard Worker   snprintf(remote_host, sizeof(remote_host), "REMOTE_HOST=%s",
3375*5e7646d2SAndroid Build Coastguard Worker            httpGetHostname(con->http, NULL, 0));
3376*5e7646d2SAndroid Build Coastguard Worker 
3377*5e7646d2SAndroid Build Coastguard Worker   snprintf(script_name, sizeof(script_name), "SCRIPT_NAME=%s", con->uri);
3378*5e7646d2SAndroid Build Coastguard Worker   if ((uriptr = strchr(script_name, '?')) != NULL)
3379*5e7646d2SAndroid Build Coastguard Worker     *uriptr = '\0';
3380*5e7646d2SAndroid Build Coastguard Worker 
3381*5e7646d2SAndroid Build Coastguard Worker   snprintf(script_filename, sizeof(script_filename), "SCRIPT_FILENAME=%s%s",
3382*5e7646d2SAndroid Build Coastguard Worker            DocumentRoot, script_name + 12);
3383*5e7646d2SAndroid Build Coastguard Worker 
3384*5e7646d2SAndroid Build Coastguard Worker   snprintf(server_port, sizeof(server_port), "SERVER_PORT=%d", con->serverport);
3385*5e7646d2SAndroid Build Coastguard Worker 
3386*5e7646d2SAndroid Build Coastguard Worker   if (httpGetField(con->http, HTTP_FIELD_HOST)[0])
3387*5e7646d2SAndroid Build Coastguard Worker   {
3388*5e7646d2SAndroid Build Coastguard Worker     char *nameptr;			/* Pointer to ":port" */
3389*5e7646d2SAndroid Build Coastguard Worker 
3390*5e7646d2SAndroid Build Coastguard Worker     snprintf(server_name, sizeof(server_name), "SERVER_NAME=%s",
3391*5e7646d2SAndroid Build Coastguard Worker 	     httpGetField(con->http, HTTP_FIELD_HOST));
3392*5e7646d2SAndroid Build Coastguard Worker     if ((nameptr = strrchr(server_name, ':')) != NULL && !strchr(nameptr, ']'))
3393*5e7646d2SAndroid Build Coastguard Worker       *nameptr = '\0';			/* Strip trailing ":port" */
3394*5e7646d2SAndroid Build Coastguard Worker   }
3395*5e7646d2SAndroid Build Coastguard Worker   else
3396*5e7646d2SAndroid Build Coastguard Worker     snprintf(server_name, sizeof(server_name), "SERVER_NAME=%s",
3397*5e7646d2SAndroid Build Coastguard Worker 	     con->servername);
3398*5e7646d2SAndroid Build Coastguard Worker 
3399*5e7646d2SAndroid Build Coastguard Worker   envc = cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
3400*5e7646d2SAndroid Build Coastguard Worker 
3401*5e7646d2SAndroid Build Coastguard Worker   if (auth_type[0])
3402*5e7646d2SAndroid Build Coastguard Worker     envp[envc ++] = auth_type;
3403*5e7646d2SAndroid Build Coastguard Worker 
3404*5e7646d2SAndroid Build Coastguard Worker   envp[envc ++] = lang;
3405*5e7646d2SAndroid Build Coastguard Worker   envp[envc ++] = "REDIRECT_STATUS=1";
3406*5e7646d2SAndroid Build Coastguard Worker   envp[envc ++] = "GATEWAY_INTERFACE=CGI/1.1";
3407*5e7646d2SAndroid Build Coastguard Worker   envp[envc ++] = server_name;
3408*5e7646d2SAndroid Build Coastguard Worker   envp[envc ++] = server_port;
3409*5e7646d2SAndroid Build Coastguard Worker   envp[envc ++] = remote_addr;
3410*5e7646d2SAndroid Build Coastguard Worker   envp[envc ++] = remote_host;
3411*5e7646d2SAndroid Build Coastguard Worker   envp[envc ++] = script_name;
3412*5e7646d2SAndroid Build Coastguard Worker   envp[envc ++] = script_filename;
3413*5e7646d2SAndroid Build Coastguard Worker 
3414*5e7646d2SAndroid Build Coastguard Worker   if (path_info[0])
3415*5e7646d2SAndroid Build Coastguard Worker     envp[envc ++] = path_info;
3416*5e7646d2SAndroid Build Coastguard Worker 
3417*5e7646d2SAndroid Build Coastguard Worker   if (con->username[0])
3418*5e7646d2SAndroid Build Coastguard Worker   {
3419*5e7646d2SAndroid Build Coastguard Worker     snprintf(remote_user, sizeof(remote_user), "REMOTE_USER=%s", con->username);
3420*5e7646d2SAndroid Build Coastguard Worker 
3421*5e7646d2SAndroid Build Coastguard Worker     envp[envc ++] = remote_user;
3422*5e7646d2SAndroid Build Coastguard Worker   }
3423*5e7646d2SAndroid Build Coastguard Worker 
3424*5e7646d2SAndroid Build Coastguard Worker   if (httpGetVersion(con->http) == HTTP_VERSION_1_1)
3425*5e7646d2SAndroid Build Coastguard Worker     envp[envc ++] = "SERVER_PROTOCOL=HTTP/1.1";
3426*5e7646d2SAndroid Build Coastguard Worker   else if (httpGetVersion(con->http) == HTTP_VERSION_1_0)
3427*5e7646d2SAndroid Build Coastguard Worker     envp[envc ++] = "SERVER_PROTOCOL=HTTP/1.0";
3428*5e7646d2SAndroid Build Coastguard Worker   else
3429*5e7646d2SAndroid Build Coastguard Worker     envp[envc ++] = "SERVER_PROTOCOL=HTTP/0.9";
3430*5e7646d2SAndroid Build Coastguard Worker 
3431*5e7646d2SAndroid Build Coastguard Worker   if (httpGetCookie(con->http))
3432*5e7646d2SAndroid Build Coastguard Worker   {
3433*5e7646d2SAndroid Build Coastguard Worker     snprintf(http_cookie, sizeof(http_cookie), "HTTP_COOKIE=%s",
3434*5e7646d2SAndroid Build Coastguard Worker              httpGetCookie(con->http));
3435*5e7646d2SAndroid Build Coastguard Worker     envp[envc ++] = http_cookie;
3436*5e7646d2SAndroid Build Coastguard Worker   }
3437*5e7646d2SAndroid Build Coastguard Worker 
3438*5e7646d2SAndroid Build Coastguard Worker   if (httpGetField(con->http, HTTP_FIELD_USER_AGENT)[0])
3439*5e7646d2SAndroid Build Coastguard Worker   {
3440*5e7646d2SAndroid Build Coastguard Worker     snprintf(http_user_agent, sizeof(http_user_agent), "HTTP_USER_AGENT=%s",
3441*5e7646d2SAndroid Build Coastguard Worker              httpGetField(con->http, HTTP_FIELD_USER_AGENT));
3442*5e7646d2SAndroid Build Coastguard Worker     envp[envc ++] = http_user_agent;
3443*5e7646d2SAndroid Build Coastguard Worker   }
3444*5e7646d2SAndroid Build Coastguard Worker 
3445*5e7646d2SAndroid Build Coastguard Worker   if (httpGetField(con->http, HTTP_FIELD_REFERER)[0])
3446*5e7646d2SAndroid Build Coastguard Worker   {
3447*5e7646d2SAndroid Build Coastguard Worker     snprintf(http_referer, sizeof(http_referer), "HTTP_REFERER=%s",
3448*5e7646d2SAndroid Build Coastguard Worker              httpGetField(con->http, HTTP_FIELD_REFERER));
3449*5e7646d2SAndroid Build Coastguard Worker     envp[envc ++] = http_referer;
3450*5e7646d2SAndroid Build Coastguard Worker   }
3451*5e7646d2SAndroid Build Coastguard Worker 
3452*5e7646d2SAndroid Build Coastguard Worker   if (con->operation == HTTP_STATE_GET)
3453*5e7646d2SAndroid Build Coastguard Worker   {
3454*5e7646d2SAndroid Build Coastguard Worker     envp[envc ++] = "REQUEST_METHOD=GET";
3455*5e7646d2SAndroid Build Coastguard Worker 
3456*5e7646d2SAndroid Build Coastguard Worker     if (con->query_string)
3457*5e7646d2SAndroid Build Coastguard Worker     {
3458*5e7646d2SAndroid Build Coastguard Worker      /*
3459*5e7646d2SAndroid Build Coastguard Worker       * Add GET form variables after ?...
3460*5e7646d2SAndroid Build Coastguard Worker       */
3461*5e7646d2SAndroid Build Coastguard Worker 
3462*5e7646d2SAndroid Build Coastguard Worker       envp[envc ++] = con->query_string;
3463*5e7646d2SAndroid Build Coastguard Worker     }
3464*5e7646d2SAndroid Build Coastguard Worker     else
3465*5e7646d2SAndroid Build Coastguard Worker       envp[envc ++] = "QUERY_STRING=";
3466*5e7646d2SAndroid Build Coastguard Worker   }
3467*5e7646d2SAndroid Build Coastguard Worker   else
3468*5e7646d2SAndroid Build Coastguard Worker   {
3469*5e7646d2SAndroid Build Coastguard Worker     snprintf(content_length, sizeof(content_length), "CONTENT_LENGTH=" CUPS_LLFMT, CUPS_LLCAST con->bytes);
3470*5e7646d2SAndroid Build Coastguard Worker     snprintf(content_type, sizeof(content_type), "CONTENT_TYPE=%s",
3471*5e7646d2SAndroid Build Coastguard Worker              httpGetField(con->http, HTTP_FIELD_CONTENT_TYPE));
3472*5e7646d2SAndroid Build Coastguard Worker 
3473*5e7646d2SAndroid Build Coastguard Worker     envp[envc ++] = "REQUEST_METHOD=POST";
3474*5e7646d2SAndroid Build Coastguard Worker     envp[envc ++] = content_length;
3475*5e7646d2SAndroid Build Coastguard Worker     envp[envc ++] = content_type;
3476*5e7646d2SAndroid Build Coastguard Worker   }
3477*5e7646d2SAndroid Build Coastguard Worker 
3478*5e7646d2SAndroid Build Coastguard Worker  /*
3479*5e7646d2SAndroid Build Coastguard Worker   * Tell the CGI if we are using encryption...
3480*5e7646d2SAndroid Build Coastguard Worker   */
3481*5e7646d2SAndroid Build Coastguard Worker 
3482*5e7646d2SAndroid Build Coastguard Worker   if (httpIsEncrypted(con->http))
3483*5e7646d2SAndroid Build Coastguard Worker     envp[envc ++] = "HTTPS=ON";
3484*5e7646d2SAndroid Build Coastguard Worker 
3485*5e7646d2SAndroid Build Coastguard Worker  /*
3486*5e7646d2SAndroid Build Coastguard Worker   * Terminate the environment array...
3487*5e7646d2SAndroid Build Coastguard Worker   */
3488*5e7646d2SAndroid Build Coastguard Worker 
3489*5e7646d2SAndroid Build Coastguard Worker   envp[envc] = NULL;
3490*5e7646d2SAndroid Build Coastguard Worker 
3491*5e7646d2SAndroid Build Coastguard Worker   if (LogLevel >= CUPSD_LOG_DEBUG)
3492*5e7646d2SAndroid Build Coastguard Worker   {
3493*5e7646d2SAndroid Build Coastguard Worker     for (i = 0; i < argc; i ++)
3494*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_DEBUG,
3495*5e7646d2SAndroid Build Coastguard Worker                       "[CGI] argv[%d] = \"%s\"", i, argv[i]);
3496*5e7646d2SAndroid Build Coastguard Worker     for (i = 0; i < envc; i ++)
3497*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_DEBUG,
3498*5e7646d2SAndroid Build Coastguard Worker                       "[CGI] envp[%d] = \"%s\"", i, envp[i]);
3499*5e7646d2SAndroid Build Coastguard Worker   }
3500*5e7646d2SAndroid Build Coastguard Worker 
3501*5e7646d2SAndroid Build Coastguard Worker  /*
3502*5e7646d2SAndroid Build Coastguard Worker   * Create a pipe for the output...
3503*5e7646d2SAndroid Build Coastguard Worker   */
3504*5e7646d2SAndroid Build Coastguard Worker 
3505*5e7646d2SAndroid Build Coastguard Worker   if (cupsdOpenPipe(fds))
3506*5e7646d2SAndroid Build Coastguard Worker   {
3507*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_ERROR, "[CGI] Unable to create pipe for %s - %s",
3508*5e7646d2SAndroid Build Coastguard Worker                     argv[0], strerror(errno));
3509*5e7646d2SAndroid Build Coastguard Worker     return (0);
3510*5e7646d2SAndroid Build Coastguard Worker   }
3511*5e7646d2SAndroid Build Coastguard Worker 
3512*5e7646d2SAndroid Build Coastguard Worker  /*
3513*5e7646d2SAndroid Build Coastguard Worker   * Then execute the command...
3514*5e7646d2SAndroid Build Coastguard Worker   */
3515*5e7646d2SAndroid Build Coastguard Worker 
3516*5e7646d2SAndroid Build Coastguard Worker   if (cupsdStartProcess(command, argv, envp, infile, fds[1], CGIPipes[1],
3517*5e7646d2SAndroid Build Coastguard Worker 			-1, -1, root, DefaultProfile, NULL, &pid) < 0)
3518*5e7646d2SAndroid Build Coastguard Worker   {
3519*5e7646d2SAndroid Build Coastguard Worker    /*
3520*5e7646d2SAndroid Build Coastguard Worker     * Error - can't fork!
3521*5e7646d2SAndroid Build Coastguard Worker     */
3522*5e7646d2SAndroid Build Coastguard Worker 
3523*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_ERROR, "[CGI] Unable to start %s - %s", argv[0],
3524*5e7646d2SAndroid Build Coastguard Worker                     strerror(errno));
3525*5e7646d2SAndroid Build Coastguard Worker 
3526*5e7646d2SAndroid Build Coastguard Worker     cupsdClosePipe(fds);
3527*5e7646d2SAndroid Build Coastguard Worker     pid = 0;
3528*5e7646d2SAndroid Build Coastguard Worker   }
3529*5e7646d2SAndroid Build Coastguard Worker   else
3530*5e7646d2SAndroid Build Coastguard Worker   {
3531*5e7646d2SAndroid Build Coastguard Worker    /*
3532*5e7646d2SAndroid Build Coastguard Worker     * Fork successful - return the PID...
3533*5e7646d2SAndroid Build Coastguard Worker     */
3534*5e7646d2SAndroid Build Coastguard Worker 
3535*5e7646d2SAndroid Build Coastguard Worker     if (con->username[0])
3536*5e7646d2SAndroid Build Coastguard Worker       cupsdAddCert(pid, con->username, con->type);
3537*5e7646d2SAndroid Build Coastguard Worker 
3538*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_DEBUG, "[CGI] Started %s (PID %d)", command, pid);
3539*5e7646d2SAndroid Build Coastguard Worker 
3540*5e7646d2SAndroid Build Coastguard Worker     *outfile = fds[0];
3541*5e7646d2SAndroid Build Coastguard Worker     close(fds[1]);
3542*5e7646d2SAndroid Build Coastguard Worker   }
3543*5e7646d2SAndroid Build Coastguard Worker 
3544*5e7646d2SAndroid Build Coastguard Worker   return (pid);
3545*5e7646d2SAndroid Build Coastguard Worker }
3546*5e7646d2SAndroid Build Coastguard Worker 
3547*5e7646d2SAndroid Build Coastguard Worker 
3548*5e7646d2SAndroid Build Coastguard Worker /*
3549*5e7646d2SAndroid Build Coastguard Worker  * 'valid_host()' - Is the Host: field valid?
3550*5e7646d2SAndroid Build Coastguard Worker  */
3551*5e7646d2SAndroid Build Coastguard Worker 
3552*5e7646d2SAndroid Build Coastguard Worker static int				/* O - 1 if valid, 0 if not */
valid_host(cupsd_client_t * con)3553*5e7646d2SAndroid Build Coastguard Worker valid_host(cupsd_client_t *con)		/* I - Client connection */
3554*5e7646d2SAndroid Build Coastguard Worker {
3555*5e7646d2SAndroid Build Coastguard Worker   cupsd_alias_t	*a;			/* Current alias */
3556*5e7646d2SAndroid Build Coastguard Worker   cupsd_netif_t	*netif;			/* Current network interface */
3557*5e7646d2SAndroid Build Coastguard Worker   const char	*end;			/* End character */
3558*5e7646d2SAndroid Build Coastguard Worker   char		*ptr;			/* Pointer into host value */
3559*5e7646d2SAndroid Build Coastguard Worker 
3560*5e7646d2SAndroid Build Coastguard Worker 
3561*5e7646d2SAndroid Build Coastguard Worker  /*
3562*5e7646d2SAndroid Build Coastguard Worker   * Copy the Host: header for later use...
3563*5e7646d2SAndroid Build Coastguard Worker   */
3564*5e7646d2SAndroid Build Coastguard Worker 
3565*5e7646d2SAndroid Build Coastguard Worker   strlcpy(con->clientname, httpGetField(con->http, HTTP_FIELD_HOST),
3566*5e7646d2SAndroid Build Coastguard Worker           sizeof(con->clientname));
3567*5e7646d2SAndroid Build Coastguard Worker   if ((ptr = strrchr(con->clientname, ':')) != NULL && !strchr(ptr, ']'))
3568*5e7646d2SAndroid Build Coastguard Worker   {
3569*5e7646d2SAndroid Build Coastguard Worker     *ptr++ = '\0';
3570*5e7646d2SAndroid Build Coastguard Worker     con->clientport = atoi(ptr);
3571*5e7646d2SAndroid Build Coastguard Worker   }
3572*5e7646d2SAndroid Build Coastguard Worker   else
3573*5e7646d2SAndroid Build Coastguard Worker     con->clientport = con->serverport;
3574*5e7646d2SAndroid Build Coastguard Worker 
3575*5e7646d2SAndroid Build Coastguard Worker  /*
3576*5e7646d2SAndroid Build Coastguard Worker   * Then validate...
3577*5e7646d2SAndroid Build Coastguard Worker   */
3578*5e7646d2SAndroid Build Coastguard Worker 
3579*5e7646d2SAndroid Build Coastguard Worker   if (httpAddrLocalhost(httpGetAddress(con->http)))
3580*5e7646d2SAndroid Build Coastguard Worker   {
3581*5e7646d2SAndroid Build Coastguard Worker    /*
3582*5e7646d2SAndroid Build Coastguard Worker     * Only allow "localhost" or the equivalent IPv4 or IPv6 numerical
3583*5e7646d2SAndroid Build Coastguard Worker     * addresses when accessing CUPS via the loopback interface...
3584*5e7646d2SAndroid Build Coastguard Worker     */
3585*5e7646d2SAndroid Build Coastguard Worker 
3586*5e7646d2SAndroid Build Coastguard Worker     return (!_cups_strcasecmp(con->clientname, "localhost") ||
3587*5e7646d2SAndroid Build Coastguard Worker 	    !_cups_strcasecmp(con->clientname, "localhost.") ||
3588*5e7646d2SAndroid Build Coastguard Worker             !strcmp(con->clientname, "127.0.0.1") ||
3589*5e7646d2SAndroid Build Coastguard Worker 	    !strcmp(con->clientname, "[::1]"));
3590*5e7646d2SAndroid Build Coastguard Worker   }
3591*5e7646d2SAndroid Build Coastguard Worker 
3592*5e7646d2SAndroid Build Coastguard Worker #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
3593*5e7646d2SAndroid Build Coastguard Worker  /*
3594*5e7646d2SAndroid Build Coastguard Worker   * Check if the hostname is something.local (Bonjour); if so, allow it.
3595*5e7646d2SAndroid Build Coastguard Worker   */
3596*5e7646d2SAndroid Build Coastguard Worker 
3597*5e7646d2SAndroid Build Coastguard Worker   if ((end = strrchr(con->clientname, '.')) != NULL && end > con->clientname &&
3598*5e7646d2SAndroid Build Coastguard Worker       !end[1])
3599*5e7646d2SAndroid Build Coastguard Worker   {
3600*5e7646d2SAndroid Build Coastguard Worker    /*
3601*5e7646d2SAndroid Build Coastguard Worker     * "." on end, work back to second-to-last "."...
3602*5e7646d2SAndroid Build Coastguard Worker     */
3603*5e7646d2SAndroid Build Coastguard Worker 
3604*5e7646d2SAndroid Build Coastguard Worker     for (end --; end > con->clientname && *end != '.'; end --);
3605*5e7646d2SAndroid Build Coastguard Worker   }
3606*5e7646d2SAndroid Build Coastguard Worker 
3607*5e7646d2SAndroid Build Coastguard Worker   if (end && (!_cups_strcasecmp(end, ".local") ||
3608*5e7646d2SAndroid Build Coastguard Worker 	      !_cups_strcasecmp(end, ".local.")))
3609*5e7646d2SAndroid Build Coastguard Worker     return (1);
3610*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_DNSSD || HAVE_AVAHI */
3611*5e7646d2SAndroid Build Coastguard Worker 
3612*5e7646d2SAndroid Build Coastguard Worker  /*
3613*5e7646d2SAndroid Build Coastguard Worker   * Check if the hostname is an IP address...
3614*5e7646d2SAndroid Build Coastguard Worker   */
3615*5e7646d2SAndroid Build Coastguard Worker 
3616*5e7646d2SAndroid Build Coastguard Worker   if (isdigit(con->clientname[0] & 255) || con->clientname[0] == '[')
3617*5e7646d2SAndroid Build Coastguard Worker   {
3618*5e7646d2SAndroid Build Coastguard Worker    /*
3619*5e7646d2SAndroid Build Coastguard Worker     * Possible IPv4/IPv6 address...
3620*5e7646d2SAndroid Build Coastguard Worker     */
3621*5e7646d2SAndroid Build Coastguard Worker 
3622*5e7646d2SAndroid Build Coastguard Worker     http_addrlist_t *addrlist;		/* List of addresses */
3623*5e7646d2SAndroid Build Coastguard Worker 
3624*5e7646d2SAndroid Build Coastguard Worker 
3625*5e7646d2SAndroid Build Coastguard Worker     if ((addrlist = httpAddrGetList(con->clientname, AF_UNSPEC, NULL)) != NULL)
3626*5e7646d2SAndroid Build Coastguard Worker     {
3627*5e7646d2SAndroid Build Coastguard Worker      /*
3628*5e7646d2SAndroid Build Coastguard Worker       * Good IPv4/IPv6 address...
3629*5e7646d2SAndroid Build Coastguard Worker       */
3630*5e7646d2SAndroid Build Coastguard Worker 
3631*5e7646d2SAndroid Build Coastguard Worker       httpAddrFreeList(addrlist);
3632*5e7646d2SAndroid Build Coastguard Worker       return (1);
3633*5e7646d2SAndroid Build Coastguard Worker     }
3634*5e7646d2SAndroid Build Coastguard Worker   }
3635*5e7646d2SAndroid Build Coastguard Worker 
3636*5e7646d2SAndroid Build Coastguard Worker  /*
3637*5e7646d2SAndroid Build Coastguard Worker   * Check for (alias) name matches...
3638*5e7646d2SAndroid Build Coastguard Worker   */
3639*5e7646d2SAndroid Build Coastguard Worker 
3640*5e7646d2SAndroid Build Coastguard Worker   for (a = (cupsd_alias_t *)cupsArrayFirst(ServerAlias);
3641*5e7646d2SAndroid Build Coastguard Worker        a;
3642*5e7646d2SAndroid Build Coastguard Worker        a = (cupsd_alias_t *)cupsArrayNext(ServerAlias))
3643*5e7646d2SAndroid Build Coastguard Worker   {
3644*5e7646d2SAndroid Build Coastguard Worker    /*
3645*5e7646d2SAndroid Build Coastguard Worker     * "ServerAlias *" allows all host values through...
3646*5e7646d2SAndroid Build Coastguard Worker     */
3647*5e7646d2SAndroid Build Coastguard Worker 
3648*5e7646d2SAndroid Build Coastguard Worker     if (!strcmp(a->name, "*"))
3649*5e7646d2SAndroid Build Coastguard Worker       return (1);
3650*5e7646d2SAndroid Build Coastguard Worker 
3651*5e7646d2SAndroid Build Coastguard Worker     if (!_cups_strncasecmp(con->clientname, a->name, a->namelen))
3652*5e7646d2SAndroid Build Coastguard Worker     {
3653*5e7646d2SAndroid Build Coastguard Worker      /*
3654*5e7646d2SAndroid Build Coastguard Worker       * Prefix matches; check the character at the end - it must be "." or nul.
3655*5e7646d2SAndroid Build Coastguard Worker       */
3656*5e7646d2SAndroid Build Coastguard Worker 
3657*5e7646d2SAndroid Build Coastguard Worker       end = con->clientname + a->namelen;
3658*5e7646d2SAndroid Build Coastguard Worker 
3659*5e7646d2SAndroid Build Coastguard Worker       if (!*end || (*end == '.' && !end[1]))
3660*5e7646d2SAndroid Build Coastguard Worker         return (1);
3661*5e7646d2SAndroid Build Coastguard Worker     }
3662*5e7646d2SAndroid Build Coastguard Worker   }
3663*5e7646d2SAndroid Build Coastguard Worker 
3664*5e7646d2SAndroid Build Coastguard Worker #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
3665*5e7646d2SAndroid Build Coastguard Worker   for (a = (cupsd_alias_t *)cupsArrayFirst(DNSSDAlias);
3666*5e7646d2SAndroid Build Coastguard Worker        a;
3667*5e7646d2SAndroid Build Coastguard Worker        a = (cupsd_alias_t *)cupsArrayNext(DNSSDAlias))
3668*5e7646d2SAndroid Build Coastguard Worker   {
3669*5e7646d2SAndroid Build Coastguard Worker    /*
3670*5e7646d2SAndroid Build Coastguard Worker     * "ServerAlias *" allows all host values through...
3671*5e7646d2SAndroid Build Coastguard Worker     */
3672*5e7646d2SAndroid Build Coastguard Worker 
3673*5e7646d2SAndroid Build Coastguard Worker     if (!strcmp(a->name, "*"))
3674*5e7646d2SAndroid Build Coastguard Worker       return (1);
3675*5e7646d2SAndroid Build Coastguard Worker 
3676*5e7646d2SAndroid Build Coastguard Worker     if (!_cups_strncasecmp(con->clientname, a->name, a->namelen))
3677*5e7646d2SAndroid Build Coastguard Worker     {
3678*5e7646d2SAndroid Build Coastguard Worker      /*
3679*5e7646d2SAndroid Build Coastguard Worker       * Prefix matches; check the character at the end - it must be "." or nul.
3680*5e7646d2SAndroid Build Coastguard Worker       */
3681*5e7646d2SAndroid Build Coastguard Worker 
3682*5e7646d2SAndroid Build Coastguard Worker       end = con->clientname + a->namelen;
3683*5e7646d2SAndroid Build Coastguard Worker 
3684*5e7646d2SAndroid Build Coastguard Worker       if (!*end || (*end == '.' && !end[1]))
3685*5e7646d2SAndroid Build Coastguard Worker         return (1);
3686*5e7646d2SAndroid Build Coastguard Worker     }
3687*5e7646d2SAndroid Build Coastguard Worker   }
3688*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_DNSSD || HAVE_AVAHI */
3689*5e7646d2SAndroid Build Coastguard Worker 
3690*5e7646d2SAndroid Build Coastguard Worker  /*
3691*5e7646d2SAndroid Build Coastguard Worker   * Check for interface hostname matches...
3692*5e7646d2SAndroid Build Coastguard Worker   */
3693*5e7646d2SAndroid Build Coastguard Worker 
3694*5e7646d2SAndroid Build Coastguard Worker   for (netif = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
3695*5e7646d2SAndroid Build Coastguard Worker        netif;
3696*5e7646d2SAndroid Build Coastguard Worker        netif = (cupsd_netif_t *)cupsArrayNext(NetIFList))
3697*5e7646d2SAndroid Build Coastguard Worker   {
3698*5e7646d2SAndroid Build Coastguard Worker     if (!_cups_strncasecmp(con->clientname, netif->hostname, netif->hostlen))
3699*5e7646d2SAndroid Build Coastguard Worker     {
3700*5e7646d2SAndroid Build Coastguard Worker      /*
3701*5e7646d2SAndroid Build Coastguard Worker       * Prefix matches; check the character at the end - it must be "." or nul.
3702*5e7646d2SAndroid Build Coastguard Worker       */
3703*5e7646d2SAndroid Build Coastguard Worker 
3704*5e7646d2SAndroid Build Coastguard Worker       end = con->clientname + netif->hostlen;
3705*5e7646d2SAndroid Build Coastguard Worker 
3706*5e7646d2SAndroid Build Coastguard Worker       if (!*end || (*end == '.' && !end[1]))
3707*5e7646d2SAndroid Build Coastguard Worker         return (1);
3708*5e7646d2SAndroid Build Coastguard Worker     }
3709*5e7646d2SAndroid Build Coastguard Worker   }
3710*5e7646d2SAndroid Build Coastguard Worker 
3711*5e7646d2SAndroid Build Coastguard Worker   return (0);
3712*5e7646d2SAndroid Build Coastguard Worker }
3713*5e7646d2SAndroid Build Coastguard Worker 
3714*5e7646d2SAndroid Build Coastguard Worker 
3715*5e7646d2SAndroid Build Coastguard Worker /*
3716*5e7646d2SAndroid Build Coastguard Worker  * 'write_file()' - Send a file via HTTP.
3717*5e7646d2SAndroid Build Coastguard Worker  */
3718*5e7646d2SAndroid Build Coastguard Worker 
3719*5e7646d2SAndroid Build Coastguard Worker static int				/* O - 0 on failure, 1 on success */
write_file(cupsd_client_t * con,http_status_t code,char * filename,char * type,struct stat * filestats)3720*5e7646d2SAndroid Build Coastguard Worker write_file(cupsd_client_t *con,		/* I - Client connection */
3721*5e7646d2SAndroid Build Coastguard Worker            http_status_t  code,		/* I - HTTP status */
3722*5e7646d2SAndroid Build Coastguard Worker 	   char           *filename,	/* I - Filename */
3723*5e7646d2SAndroid Build Coastguard Worker 	   char           *type,	/* I - File type */
3724*5e7646d2SAndroid Build Coastguard Worker 	   struct stat    *filestats)	/* O - File information */
3725*5e7646d2SAndroid Build Coastguard Worker {
3726*5e7646d2SAndroid Build Coastguard Worker   con->file = open(filename, O_RDONLY);
3727*5e7646d2SAndroid Build Coastguard Worker 
3728*5e7646d2SAndroid Build Coastguard Worker   cupsdLogClient(con, CUPSD_LOG_DEBUG2, "write_file: code=%d, filename=\"%s\" (%d), type=\"%s\", filestats=%p.", code, filename, con->file, type ? type : "(null)", filestats);
3729*5e7646d2SAndroid Build Coastguard Worker 
3730*5e7646d2SAndroid Build Coastguard Worker   if (con->file < 0)
3731*5e7646d2SAndroid Build Coastguard Worker     return (0);
3732*5e7646d2SAndroid Build Coastguard Worker 
3733*5e7646d2SAndroid Build Coastguard Worker   fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
3734*5e7646d2SAndroid Build Coastguard Worker 
3735*5e7646d2SAndroid Build Coastguard Worker   con->pipe_pid    = 0;
3736*5e7646d2SAndroid Build Coastguard Worker   con->sent_header = 1;
3737*5e7646d2SAndroid Build Coastguard Worker 
3738*5e7646d2SAndroid Build Coastguard Worker   httpClearFields(con->http);
3739*5e7646d2SAndroid Build Coastguard Worker 
3740*5e7646d2SAndroid Build Coastguard Worker   httpSetLength(con->http, (size_t)filestats->st_size);
3741*5e7646d2SAndroid Build Coastguard Worker 
3742*5e7646d2SAndroid Build Coastguard Worker   httpSetField(con->http, HTTP_FIELD_LAST_MODIFIED,
3743*5e7646d2SAndroid Build Coastguard Worker 	       httpGetDateString(filestats->st_mtime));
3744*5e7646d2SAndroid Build Coastguard Worker 
3745*5e7646d2SAndroid Build Coastguard Worker   if (!cupsdSendHeader(con, code, type, CUPSD_AUTH_NONE))
3746*5e7646d2SAndroid Build Coastguard Worker     return (0);
3747*5e7646d2SAndroid Build Coastguard Worker 
3748*5e7646d2SAndroid Build Coastguard Worker   cupsdAddSelect(httpGetFd(con->http), NULL, (cupsd_selfunc_t)cupsdWriteClient, con);
3749*5e7646d2SAndroid Build Coastguard Worker 
3750*5e7646d2SAndroid Build Coastguard Worker   cupsdLogClient(con, CUPSD_LOG_DEBUG, "Sending file.");
3751*5e7646d2SAndroid Build Coastguard Worker 
3752*5e7646d2SAndroid Build Coastguard Worker   return (1);
3753*5e7646d2SAndroid Build Coastguard Worker }
3754*5e7646d2SAndroid Build Coastguard Worker 
3755*5e7646d2SAndroid Build Coastguard Worker 
3756*5e7646d2SAndroid Build Coastguard Worker /*
3757*5e7646d2SAndroid Build Coastguard Worker  * 'write_pipe()' - Flag that data is available on the CGI pipe.
3758*5e7646d2SAndroid Build Coastguard Worker  */
3759*5e7646d2SAndroid Build Coastguard Worker 
3760*5e7646d2SAndroid Build Coastguard Worker static void
write_pipe(cupsd_client_t * con)3761*5e7646d2SAndroid Build Coastguard Worker write_pipe(cupsd_client_t *con)		/* I - Client connection */
3762*5e7646d2SAndroid Build Coastguard Worker {
3763*5e7646d2SAndroid Build Coastguard Worker   cupsdLogClient(con, CUPSD_LOG_DEBUG2, "write_pipe: CGI output on fd %d.", con->file);
3764*5e7646d2SAndroid Build Coastguard Worker 
3765*5e7646d2SAndroid Build Coastguard Worker   con->file_ready = 1;
3766*5e7646d2SAndroid Build Coastguard Worker 
3767*5e7646d2SAndroid Build Coastguard Worker   cupsdRemoveSelect(con->file);
3768*5e7646d2SAndroid Build Coastguard Worker   cupsdAddSelect(httpGetFd(con->http), NULL, (cupsd_selfunc_t)cupsdWriteClient, con);
3769*5e7646d2SAndroid Build Coastguard Worker 
3770*5e7646d2SAndroid Build Coastguard Worker   cupsdLogClient(con, CUPSD_LOG_DEBUG, "CGI data ready to be sent.");
3771*5e7646d2SAndroid Build Coastguard Worker }
3772