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¶m=value
3233*5e7646d2SAndroid Build Coastguard Worker * ?param=value¶m=value
3234*5e7646d2SAndroid Build Coastguard Worker * /name?argument+argument+argument
3235*5e7646d2SAndroid Build Coastguard Worker * /name?param=value¶m=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