xref: /aosp_15_r20/external/libcups/cups/getputfile.c (revision 5e7646d21f1134fb0638875d812ef646c12ab91e)
1*5e7646d2SAndroid Build Coastguard Worker /*
2*5e7646d2SAndroid Build Coastguard Worker  * Get/put file functions for CUPS.
3*5e7646d2SAndroid Build Coastguard Worker  *
4*5e7646d2SAndroid Build Coastguard Worker  * Copyright 2007-2018 by Apple Inc.
5*5e7646d2SAndroid Build Coastguard Worker  * Copyright 1997-2006 by Easy Software Products.
6*5e7646d2SAndroid Build Coastguard Worker  *
7*5e7646d2SAndroid Build Coastguard Worker  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
8*5e7646d2SAndroid Build Coastguard Worker  * information.
9*5e7646d2SAndroid Build Coastguard Worker  */
10*5e7646d2SAndroid Build Coastguard Worker 
11*5e7646d2SAndroid Build Coastguard Worker /*
12*5e7646d2SAndroid Build Coastguard Worker  * Include necessary headers...
13*5e7646d2SAndroid Build Coastguard Worker  */
14*5e7646d2SAndroid Build Coastguard Worker 
15*5e7646d2SAndroid Build Coastguard Worker #include "cups-private.h"
16*5e7646d2SAndroid Build Coastguard Worker #include "debug-internal.h"
17*5e7646d2SAndroid Build Coastguard Worker #include <fcntl.h>
18*5e7646d2SAndroid Build Coastguard Worker #include <sys/stat.h>
19*5e7646d2SAndroid Build Coastguard Worker #if defined(_WIN32) || defined(__EMX__)
20*5e7646d2SAndroid Build Coastguard Worker #  include <io.h>
21*5e7646d2SAndroid Build Coastguard Worker #else
22*5e7646d2SAndroid Build Coastguard Worker #  include <unistd.h>
23*5e7646d2SAndroid Build Coastguard Worker #endif /* _WIN32 || __EMX__ */
24*5e7646d2SAndroid Build Coastguard Worker 
25*5e7646d2SAndroid Build Coastguard Worker 
26*5e7646d2SAndroid Build Coastguard Worker /*
27*5e7646d2SAndroid Build Coastguard Worker  * 'cupsGetFd()' - Get a file from the server.
28*5e7646d2SAndroid Build Coastguard Worker  *
29*5e7646d2SAndroid Build Coastguard Worker  * This function returns @code HTTP_STATUS_OK@ when the file is successfully retrieved.
30*5e7646d2SAndroid Build Coastguard Worker  *
31*5e7646d2SAndroid Build Coastguard Worker  * @since CUPS 1.1.20/macOS 10.4@
32*5e7646d2SAndroid Build Coastguard Worker  */
33*5e7646d2SAndroid Build Coastguard Worker 
34*5e7646d2SAndroid Build Coastguard Worker http_status_t				/* O - HTTP status */
cupsGetFd(http_t * http,const char * resource,int fd)35*5e7646d2SAndroid Build Coastguard Worker cupsGetFd(http_t     *http,		/* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
36*5e7646d2SAndroid Build Coastguard Worker 	  const char *resource,		/* I - Resource name */
37*5e7646d2SAndroid Build Coastguard Worker 	  int        fd)		/* I - File descriptor */
38*5e7646d2SAndroid Build Coastguard Worker {
39*5e7646d2SAndroid Build Coastguard Worker   ssize_t	bytes;			/* Number of bytes read */
40*5e7646d2SAndroid Build Coastguard Worker   char		buffer[8192];		/* Buffer for file */
41*5e7646d2SAndroid Build Coastguard Worker   http_status_t	status;			/* HTTP status from server */
42*5e7646d2SAndroid Build Coastguard Worker   char		if_modified_since[HTTP_MAX_VALUE];
43*5e7646d2SAndroid Build Coastguard Worker 					/* If-Modified-Since header */
44*5e7646d2SAndroid Build Coastguard Worker   int		new_auth = 0;		/* Using new auth information? */
45*5e7646d2SAndroid Build Coastguard Worker   int		digest;			/* Are we using Digest authentication? */
46*5e7646d2SAndroid Build Coastguard Worker 
47*5e7646d2SAndroid Build Coastguard Worker 
48*5e7646d2SAndroid Build Coastguard Worker  /*
49*5e7646d2SAndroid Build Coastguard Worker   * Range check input...
50*5e7646d2SAndroid Build Coastguard Worker   */
51*5e7646d2SAndroid Build Coastguard Worker 
52*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("cupsGetFd(http=%p, resource=\"%s\", fd=%d)", (void *)http, resource, fd));
53*5e7646d2SAndroid Build Coastguard Worker 
54*5e7646d2SAndroid Build Coastguard Worker   if (!resource || fd < 0)
55*5e7646d2SAndroid Build Coastguard Worker   {
56*5e7646d2SAndroid Build Coastguard Worker     if (http)
57*5e7646d2SAndroid Build Coastguard Worker       http->error = EINVAL;
58*5e7646d2SAndroid Build Coastguard Worker 
59*5e7646d2SAndroid Build Coastguard Worker     return (HTTP_STATUS_ERROR);
60*5e7646d2SAndroid Build Coastguard Worker   }
61*5e7646d2SAndroid Build Coastguard Worker 
62*5e7646d2SAndroid Build Coastguard Worker   if (!http)
63*5e7646d2SAndroid Build Coastguard Worker     if ((http = _cupsConnect()) == NULL)
64*5e7646d2SAndroid Build Coastguard Worker       return (HTTP_STATUS_SERVICE_UNAVAILABLE);
65*5e7646d2SAndroid Build Coastguard Worker 
66*5e7646d2SAndroid Build Coastguard Worker  /*
67*5e7646d2SAndroid Build Coastguard Worker   * Then send GET requests to the HTTP server...
68*5e7646d2SAndroid Build Coastguard Worker   */
69*5e7646d2SAndroid Build Coastguard Worker 
70*5e7646d2SAndroid Build Coastguard Worker   strlcpy(if_modified_since, httpGetField(http, HTTP_FIELD_IF_MODIFIED_SINCE),
71*5e7646d2SAndroid Build Coastguard Worker           sizeof(if_modified_since));
72*5e7646d2SAndroid Build Coastguard Worker 
73*5e7646d2SAndroid Build Coastguard Worker   do
74*5e7646d2SAndroid Build Coastguard Worker   {
75*5e7646d2SAndroid Build Coastguard Worker     if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_CONNECTION), "close"))
76*5e7646d2SAndroid Build Coastguard Worker     {
77*5e7646d2SAndroid Build Coastguard Worker       httpClearFields(http);
78*5e7646d2SAndroid Build Coastguard Worker       if (httpReconnect2(http, 30000, NULL))
79*5e7646d2SAndroid Build Coastguard Worker       {
80*5e7646d2SAndroid Build Coastguard Worker 	status = HTTP_STATUS_ERROR;
81*5e7646d2SAndroid Build Coastguard Worker 	break;
82*5e7646d2SAndroid Build Coastguard Worker       }
83*5e7646d2SAndroid Build Coastguard Worker     }
84*5e7646d2SAndroid Build Coastguard Worker 
85*5e7646d2SAndroid Build Coastguard Worker     httpClearFields(http);
86*5e7646d2SAndroid Build Coastguard Worker     httpSetField(http, HTTP_FIELD_IF_MODIFIED_SINCE, if_modified_since);
87*5e7646d2SAndroid Build Coastguard Worker 
88*5e7646d2SAndroid Build Coastguard Worker     digest = http->authstring && !strncmp(http->authstring, "Digest ", 7);
89*5e7646d2SAndroid Build Coastguard Worker 
90*5e7646d2SAndroid Build Coastguard Worker     if (digest && !new_auth)
91*5e7646d2SAndroid Build Coastguard Worker     {
92*5e7646d2SAndroid Build Coastguard Worker      /*
93*5e7646d2SAndroid Build Coastguard Worker       * Update the Digest authentication string...
94*5e7646d2SAndroid Build Coastguard Worker       */
95*5e7646d2SAndroid Build Coastguard Worker 
96*5e7646d2SAndroid Build Coastguard Worker       _httpSetDigestAuthString(http, http->nextnonce, "GET", resource);
97*5e7646d2SAndroid Build Coastguard Worker     }
98*5e7646d2SAndroid Build Coastguard Worker 
99*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_GSSAPI
100*5e7646d2SAndroid Build Coastguard Worker     if (http->authstring && !strncmp(http->authstring, "Negotiate", 9) && !new_auth)
101*5e7646d2SAndroid Build Coastguard Worker     {
102*5e7646d2SAndroid Build Coastguard Worker      /*
103*5e7646d2SAndroid Build Coastguard Worker       * Do not use cached Kerberos credentials since they will look like a
104*5e7646d2SAndroid Build Coastguard Worker       * "replay" attack...
105*5e7646d2SAndroid Build Coastguard Worker       */
106*5e7646d2SAndroid Build Coastguard Worker 
107*5e7646d2SAndroid Build Coastguard Worker       _cupsSetNegotiateAuthString(http, "GET", resource);
108*5e7646d2SAndroid Build Coastguard Worker     }
109*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_GSSAPI */
110*5e7646d2SAndroid Build Coastguard Worker 
111*5e7646d2SAndroid Build Coastguard Worker     httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring);
112*5e7646d2SAndroid Build Coastguard Worker 
113*5e7646d2SAndroid Build Coastguard Worker     if (httpGet(http, resource))
114*5e7646d2SAndroid Build Coastguard Worker     {
115*5e7646d2SAndroid Build Coastguard Worker       if (httpReconnect2(http, 30000, NULL))
116*5e7646d2SAndroid Build Coastguard Worker       {
117*5e7646d2SAndroid Build Coastguard Worker         status = HTTP_STATUS_ERROR;
118*5e7646d2SAndroid Build Coastguard Worker 	break;
119*5e7646d2SAndroid Build Coastguard Worker       }
120*5e7646d2SAndroid Build Coastguard Worker       else
121*5e7646d2SAndroid Build Coastguard Worker       {
122*5e7646d2SAndroid Build Coastguard Worker         status = HTTP_STATUS_UNAUTHORIZED;
123*5e7646d2SAndroid Build Coastguard Worker         continue;
124*5e7646d2SAndroid Build Coastguard Worker       }
125*5e7646d2SAndroid Build Coastguard Worker     }
126*5e7646d2SAndroid Build Coastguard Worker 
127*5e7646d2SAndroid Build Coastguard Worker     new_auth = 0;
128*5e7646d2SAndroid Build Coastguard Worker 
129*5e7646d2SAndroid Build Coastguard Worker     while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE);
130*5e7646d2SAndroid Build Coastguard Worker 
131*5e7646d2SAndroid Build Coastguard Worker     if (status == HTTP_STATUS_UNAUTHORIZED)
132*5e7646d2SAndroid Build Coastguard Worker     {
133*5e7646d2SAndroid Build Coastguard Worker      /*
134*5e7646d2SAndroid Build Coastguard Worker       * Flush any error message...
135*5e7646d2SAndroid Build Coastguard Worker       */
136*5e7646d2SAndroid Build Coastguard Worker 
137*5e7646d2SAndroid Build Coastguard Worker       httpFlush(http);
138*5e7646d2SAndroid Build Coastguard Worker 
139*5e7646d2SAndroid Build Coastguard Worker      /*
140*5e7646d2SAndroid Build Coastguard Worker       * See if we can do authentication...
141*5e7646d2SAndroid Build Coastguard Worker       */
142*5e7646d2SAndroid Build Coastguard Worker 
143*5e7646d2SAndroid Build Coastguard Worker       new_auth = 1;
144*5e7646d2SAndroid Build Coastguard Worker 
145*5e7646d2SAndroid Build Coastguard Worker       if (cupsDoAuthentication(http, "GET", resource))
146*5e7646d2SAndroid Build Coastguard Worker       {
147*5e7646d2SAndroid Build Coastguard Worker         status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED;
148*5e7646d2SAndroid Build Coastguard Worker         break;
149*5e7646d2SAndroid Build Coastguard Worker       }
150*5e7646d2SAndroid Build Coastguard Worker 
151*5e7646d2SAndroid Build Coastguard Worker       if (httpReconnect2(http, 30000, NULL))
152*5e7646d2SAndroid Build Coastguard Worker       {
153*5e7646d2SAndroid Build Coastguard Worker         status = HTTP_STATUS_ERROR;
154*5e7646d2SAndroid Build Coastguard Worker         break;
155*5e7646d2SAndroid Build Coastguard Worker       }
156*5e7646d2SAndroid Build Coastguard Worker 
157*5e7646d2SAndroid Build Coastguard Worker       continue;
158*5e7646d2SAndroid Build Coastguard Worker     }
159*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_SSL
160*5e7646d2SAndroid Build Coastguard Worker     else if (status == HTTP_STATUS_UPGRADE_REQUIRED)
161*5e7646d2SAndroid Build Coastguard Worker     {
162*5e7646d2SAndroid Build Coastguard Worker       /* Flush any error message... */
163*5e7646d2SAndroid Build Coastguard Worker       httpFlush(http);
164*5e7646d2SAndroid Build Coastguard Worker 
165*5e7646d2SAndroid Build Coastguard Worker       /* Reconnect... */
166*5e7646d2SAndroid Build Coastguard Worker       if (httpReconnect2(http, 30000, NULL))
167*5e7646d2SAndroid Build Coastguard Worker       {
168*5e7646d2SAndroid Build Coastguard Worker         status = HTTP_STATUS_ERROR;
169*5e7646d2SAndroid Build Coastguard Worker         break;
170*5e7646d2SAndroid Build Coastguard Worker       }
171*5e7646d2SAndroid Build Coastguard Worker 
172*5e7646d2SAndroid Build Coastguard Worker       /* Upgrade with encryption... */
173*5e7646d2SAndroid Build Coastguard Worker       httpEncryption(http, HTTP_ENCRYPTION_REQUIRED);
174*5e7646d2SAndroid Build Coastguard Worker 
175*5e7646d2SAndroid Build Coastguard Worker       /* Try again, this time with encryption enabled... */
176*5e7646d2SAndroid Build Coastguard Worker       continue;
177*5e7646d2SAndroid Build Coastguard Worker     }
178*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_SSL */
179*5e7646d2SAndroid Build Coastguard Worker   }
180*5e7646d2SAndroid Build Coastguard Worker   while (status == HTTP_STATUS_UNAUTHORIZED || status == HTTP_STATUS_UPGRADE_REQUIRED);
181*5e7646d2SAndroid Build Coastguard Worker 
182*5e7646d2SAndroid Build Coastguard Worker  /*
183*5e7646d2SAndroid Build Coastguard Worker   * See if we actually got the file or an error...
184*5e7646d2SAndroid Build Coastguard Worker   */
185*5e7646d2SAndroid Build Coastguard Worker 
186*5e7646d2SAndroid Build Coastguard Worker   if (status == HTTP_STATUS_OK)
187*5e7646d2SAndroid Build Coastguard Worker   {
188*5e7646d2SAndroid Build Coastguard Worker    /*
189*5e7646d2SAndroid Build Coastguard Worker     * Yes, copy the file...
190*5e7646d2SAndroid Build Coastguard Worker     */
191*5e7646d2SAndroid Build Coastguard Worker 
192*5e7646d2SAndroid Build Coastguard Worker     while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0)
193*5e7646d2SAndroid Build Coastguard Worker       write(fd, buffer, (size_t)bytes);
194*5e7646d2SAndroid Build Coastguard Worker   }
195*5e7646d2SAndroid Build Coastguard Worker   else
196*5e7646d2SAndroid Build Coastguard Worker   {
197*5e7646d2SAndroid Build Coastguard Worker     _cupsSetHTTPError(status);
198*5e7646d2SAndroid Build Coastguard Worker     httpFlush(http);
199*5e7646d2SAndroid Build Coastguard Worker   }
200*5e7646d2SAndroid Build Coastguard Worker 
201*5e7646d2SAndroid Build Coastguard Worker  /*
202*5e7646d2SAndroid Build Coastguard Worker   * Return the request status...
203*5e7646d2SAndroid Build Coastguard Worker   */
204*5e7646d2SAndroid Build Coastguard Worker 
205*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("1cupsGetFd: Returning %d...", status));
206*5e7646d2SAndroid Build Coastguard Worker 
207*5e7646d2SAndroid Build Coastguard Worker   return (status);
208*5e7646d2SAndroid Build Coastguard Worker }
209*5e7646d2SAndroid Build Coastguard Worker 
210*5e7646d2SAndroid Build Coastguard Worker 
211*5e7646d2SAndroid Build Coastguard Worker /*
212*5e7646d2SAndroid Build Coastguard Worker  * 'cupsGetFile()' - Get a file from the server.
213*5e7646d2SAndroid Build Coastguard Worker  *
214*5e7646d2SAndroid Build Coastguard Worker  * This function returns @code HTTP_STATUS_OK@ when the file is successfully retrieved.
215*5e7646d2SAndroid Build Coastguard Worker  *
216*5e7646d2SAndroid Build Coastguard Worker  * @since CUPS 1.1.20/macOS 10.4@
217*5e7646d2SAndroid Build Coastguard Worker  */
218*5e7646d2SAndroid Build Coastguard Worker 
219*5e7646d2SAndroid Build Coastguard Worker http_status_t				/* O - HTTP status */
cupsGetFile(http_t * http,const char * resource,const char * filename)220*5e7646d2SAndroid Build Coastguard Worker cupsGetFile(http_t     *http,		/* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
221*5e7646d2SAndroid Build Coastguard Worker 	    const char *resource,	/* I - Resource name */
222*5e7646d2SAndroid Build Coastguard Worker 	    const char *filename)	/* I - Filename */
223*5e7646d2SAndroid Build Coastguard Worker {
224*5e7646d2SAndroid Build Coastguard Worker   int		fd;			/* File descriptor */
225*5e7646d2SAndroid Build Coastguard Worker   http_status_t	status;			/* Status */
226*5e7646d2SAndroid Build Coastguard Worker 
227*5e7646d2SAndroid Build Coastguard Worker 
228*5e7646d2SAndroid Build Coastguard Worker  /*
229*5e7646d2SAndroid Build Coastguard Worker   * Range check input...
230*5e7646d2SAndroid Build Coastguard Worker   */
231*5e7646d2SAndroid Build Coastguard Worker 
232*5e7646d2SAndroid Build Coastguard Worker   if (!http || !resource || !filename)
233*5e7646d2SAndroid Build Coastguard Worker   {
234*5e7646d2SAndroid Build Coastguard Worker     if (http)
235*5e7646d2SAndroid Build Coastguard Worker       http->error = EINVAL;
236*5e7646d2SAndroid Build Coastguard Worker 
237*5e7646d2SAndroid Build Coastguard Worker     return (HTTP_STATUS_ERROR);
238*5e7646d2SAndroid Build Coastguard Worker   }
239*5e7646d2SAndroid Build Coastguard Worker 
240*5e7646d2SAndroid Build Coastguard Worker  /*
241*5e7646d2SAndroid Build Coastguard Worker   * Create the file...
242*5e7646d2SAndroid Build Coastguard Worker   */
243*5e7646d2SAndroid Build Coastguard Worker 
244*5e7646d2SAndroid Build Coastguard Worker   if ((fd = open(filename, O_WRONLY | O_EXCL | O_TRUNC)) < 0)
245*5e7646d2SAndroid Build Coastguard Worker   {
246*5e7646d2SAndroid Build Coastguard Worker    /*
247*5e7646d2SAndroid Build Coastguard Worker     * Couldn't open the file!
248*5e7646d2SAndroid Build Coastguard Worker     */
249*5e7646d2SAndroid Build Coastguard Worker 
250*5e7646d2SAndroid Build Coastguard Worker     http->error = errno;
251*5e7646d2SAndroid Build Coastguard Worker 
252*5e7646d2SAndroid Build Coastguard Worker     return (HTTP_STATUS_ERROR);
253*5e7646d2SAndroid Build Coastguard Worker   }
254*5e7646d2SAndroid Build Coastguard Worker 
255*5e7646d2SAndroid Build Coastguard Worker  /*
256*5e7646d2SAndroid Build Coastguard Worker   * Get the file...
257*5e7646d2SAndroid Build Coastguard Worker   */
258*5e7646d2SAndroid Build Coastguard Worker 
259*5e7646d2SAndroid Build Coastguard Worker   status = cupsGetFd(http, resource, fd);
260*5e7646d2SAndroid Build Coastguard Worker 
261*5e7646d2SAndroid Build Coastguard Worker  /*
262*5e7646d2SAndroid Build Coastguard Worker   * If the file couldn't be gotten, then remove the file...
263*5e7646d2SAndroid Build Coastguard Worker   */
264*5e7646d2SAndroid Build Coastguard Worker 
265*5e7646d2SAndroid Build Coastguard Worker   close(fd);
266*5e7646d2SAndroid Build Coastguard Worker 
267*5e7646d2SAndroid Build Coastguard Worker   if (status != HTTP_STATUS_OK)
268*5e7646d2SAndroid Build Coastguard Worker     unlink(filename);
269*5e7646d2SAndroid Build Coastguard Worker 
270*5e7646d2SAndroid Build Coastguard Worker  /*
271*5e7646d2SAndroid Build Coastguard Worker   * Return the HTTP status code...
272*5e7646d2SAndroid Build Coastguard Worker   */
273*5e7646d2SAndroid Build Coastguard Worker 
274*5e7646d2SAndroid Build Coastguard Worker   return (status);
275*5e7646d2SAndroid Build Coastguard Worker }
276*5e7646d2SAndroid Build Coastguard Worker 
277*5e7646d2SAndroid Build Coastguard Worker 
278*5e7646d2SAndroid Build Coastguard Worker /*
279*5e7646d2SAndroid Build Coastguard Worker  * 'cupsPutFd()' - Put a file on the server.
280*5e7646d2SAndroid Build Coastguard Worker  *
281*5e7646d2SAndroid Build Coastguard Worker  * This function returns @code HTTP_STATUS_CREATED@ when the file is stored
282*5e7646d2SAndroid Build Coastguard Worker  * successfully.
283*5e7646d2SAndroid Build Coastguard Worker  *
284*5e7646d2SAndroid Build Coastguard Worker  * @since CUPS 1.1.20/macOS 10.4@
285*5e7646d2SAndroid Build Coastguard Worker  */
286*5e7646d2SAndroid Build Coastguard Worker 
287*5e7646d2SAndroid Build Coastguard Worker http_status_t				/* O - HTTP status */
cupsPutFd(http_t * http,const char * resource,int fd)288*5e7646d2SAndroid Build Coastguard Worker cupsPutFd(http_t     *http,		/* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
289*5e7646d2SAndroid Build Coastguard Worker           const char *resource,		/* I - Resource name */
290*5e7646d2SAndroid Build Coastguard Worker 	  int        fd)		/* I - File descriptor */
291*5e7646d2SAndroid Build Coastguard Worker {
292*5e7646d2SAndroid Build Coastguard Worker   ssize_t	bytes;			/* Number of bytes read */
293*5e7646d2SAndroid Build Coastguard Worker   int		retries;		/* Number of retries */
294*5e7646d2SAndroid Build Coastguard Worker   char		buffer[8192];		/* Buffer for file */
295*5e7646d2SAndroid Build Coastguard Worker   http_status_t	status;			/* HTTP status from server */
296*5e7646d2SAndroid Build Coastguard Worker   int		new_auth = 0;		/* Using new auth information? */
297*5e7646d2SAndroid Build Coastguard Worker   int		digest;			/* Are we using Digest authentication? */
298*5e7646d2SAndroid Build Coastguard Worker 
299*5e7646d2SAndroid Build Coastguard Worker 
300*5e7646d2SAndroid Build Coastguard Worker  /*
301*5e7646d2SAndroid Build Coastguard Worker   * Range check input...
302*5e7646d2SAndroid Build Coastguard Worker   */
303*5e7646d2SAndroid Build Coastguard Worker 
304*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("cupsPutFd(http=%p, resource=\"%s\", fd=%d)", (void *)http, resource, fd));
305*5e7646d2SAndroid Build Coastguard Worker 
306*5e7646d2SAndroid Build Coastguard Worker   if (!resource || fd < 0)
307*5e7646d2SAndroid Build Coastguard Worker   {
308*5e7646d2SAndroid Build Coastguard Worker     if (http)
309*5e7646d2SAndroid Build Coastguard Worker       http->error = EINVAL;
310*5e7646d2SAndroid Build Coastguard Worker 
311*5e7646d2SAndroid Build Coastguard Worker     return (HTTP_STATUS_ERROR);
312*5e7646d2SAndroid Build Coastguard Worker   }
313*5e7646d2SAndroid Build Coastguard Worker 
314*5e7646d2SAndroid Build Coastguard Worker   if (!http)
315*5e7646d2SAndroid Build Coastguard Worker     if ((http = _cupsConnect()) == NULL)
316*5e7646d2SAndroid Build Coastguard Worker       return (HTTP_STATUS_SERVICE_UNAVAILABLE);
317*5e7646d2SAndroid Build Coastguard Worker 
318*5e7646d2SAndroid Build Coastguard Worker  /*
319*5e7646d2SAndroid Build Coastguard Worker   * Then send PUT requests to the HTTP server...
320*5e7646d2SAndroid Build Coastguard Worker   */
321*5e7646d2SAndroid Build Coastguard Worker 
322*5e7646d2SAndroid Build Coastguard Worker   retries = 0;
323*5e7646d2SAndroid Build Coastguard Worker 
324*5e7646d2SAndroid Build Coastguard Worker   do
325*5e7646d2SAndroid Build Coastguard Worker   {
326*5e7646d2SAndroid Build Coastguard Worker     if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_CONNECTION), "close"))
327*5e7646d2SAndroid Build Coastguard Worker     {
328*5e7646d2SAndroid Build Coastguard Worker       httpClearFields(http);
329*5e7646d2SAndroid Build Coastguard Worker       if (httpReconnect2(http, 30000, NULL))
330*5e7646d2SAndroid Build Coastguard Worker       {
331*5e7646d2SAndroid Build Coastguard Worker 	status = HTTP_STATUS_ERROR;
332*5e7646d2SAndroid Build Coastguard Worker 	break;
333*5e7646d2SAndroid Build Coastguard Worker       }
334*5e7646d2SAndroid Build Coastguard Worker     }
335*5e7646d2SAndroid Build Coastguard Worker 
336*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("2cupsPutFd: starting attempt, authstring=\"%s\"...",
337*5e7646d2SAndroid Build Coastguard Worker                   http->authstring));
338*5e7646d2SAndroid Build Coastguard Worker 
339*5e7646d2SAndroid Build Coastguard Worker     httpClearFields(http);
340*5e7646d2SAndroid Build Coastguard Worker     httpSetField(http, HTTP_FIELD_TRANSFER_ENCODING, "chunked");
341*5e7646d2SAndroid Build Coastguard Worker     httpSetExpect(http, HTTP_STATUS_CONTINUE);
342*5e7646d2SAndroid Build Coastguard Worker 
343*5e7646d2SAndroid Build Coastguard Worker     digest = http->authstring && !strncmp(http->authstring, "Digest ", 7);
344*5e7646d2SAndroid Build Coastguard Worker 
345*5e7646d2SAndroid Build Coastguard Worker     if (digest && !new_auth)
346*5e7646d2SAndroid Build Coastguard Worker     {
347*5e7646d2SAndroid Build Coastguard Worker      /*
348*5e7646d2SAndroid Build Coastguard Worker       * Update the Digest authentication string...
349*5e7646d2SAndroid Build Coastguard Worker       */
350*5e7646d2SAndroid Build Coastguard Worker 
351*5e7646d2SAndroid Build Coastguard Worker       _httpSetDigestAuthString(http, http->nextnonce, "PUT", resource);
352*5e7646d2SAndroid Build Coastguard Worker     }
353*5e7646d2SAndroid Build Coastguard Worker 
354*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_GSSAPI
355*5e7646d2SAndroid Build Coastguard Worker     if (http->authstring && !strncmp(http->authstring, "Negotiate", 9) && !new_auth)
356*5e7646d2SAndroid Build Coastguard Worker     {
357*5e7646d2SAndroid Build Coastguard Worker      /*
358*5e7646d2SAndroid Build Coastguard Worker       * Do not use cached Kerberos credentials since they will look like a
359*5e7646d2SAndroid Build Coastguard Worker       * "replay" attack...
360*5e7646d2SAndroid Build Coastguard Worker       */
361*5e7646d2SAndroid Build Coastguard Worker 
362*5e7646d2SAndroid Build Coastguard Worker       _cupsSetNegotiateAuthString(http, "PUT", resource);
363*5e7646d2SAndroid Build Coastguard Worker     }
364*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_GSSAPI */
365*5e7646d2SAndroid Build Coastguard Worker 
366*5e7646d2SAndroid Build Coastguard Worker     httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring);
367*5e7646d2SAndroid Build Coastguard Worker 
368*5e7646d2SAndroid Build Coastguard Worker     if (httpPut(http, resource))
369*5e7646d2SAndroid Build Coastguard Worker     {
370*5e7646d2SAndroid Build Coastguard Worker       if (httpReconnect2(http, 30000, NULL))
371*5e7646d2SAndroid Build Coastguard Worker       {
372*5e7646d2SAndroid Build Coastguard Worker         status = HTTP_STATUS_ERROR;
373*5e7646d2SAndroid Build Coastguard Worker 	break;
374*5e7646d2SAndroid Build Coastguard Worker       }
375*5e7646d2SAndroid Build Coastguard Worker       else
376*5e7646d2SAndroid Build Coastguard Worker       {
377*5e7646d2SAndroid Build Coastguard Worker         status = HTTP_STATUS_UNAUTHORIZED;
378*5e7646d2SAndroid Build Coastguard Worker         continue;
379*5e7646d2SAndroid Build Coastguard Worker       }
380*5e7646d2SAndroid Build Coastguard Worker     }
381*5e7646d2SAndroid Build Coastguard Worker 
382*5e7646d2SAndroid Build Coastguard Worker    /*
383*5e7646d2SAndroid Build Coastguard Worker     * Wait up to 1 second for a 100-continue response...
384*5e7646d2SAndroid Build Coastguard Worker     */
385*5e7646d2SAndroid Build Coastguard Worker 
386*5e7646d2SAndroid Build Coastguard Worker     if (httpWait(http, 1000))
387*5e7646d2SAndroid Build Coastguard Worker       status = httpUpdate(http);
388*5e7646d2SAndroid Build Coastguard Worker     else
389*5e7646d2SAndroid Build Coastguard Worker       status = HTTP_STATUS_CONTINUE;
390*5e7646d2SAndroid Build Coastguard Worker 
391*5e7646d2SAndroid Build Coastguard Worker     if (status == HTTP_STATUS_CONTINUE)
392*5e7646d2SAndroid Build Coastguard Worker     {
393*5e7646d2SAndroid Build Coastguard Worker      /*
394*5e7646d2SAndroid Build Coastguard Worker       * Copy the file...
395*5e7646d2SAndroid Build Coastguard Worker       */
396*5e7646d2SAndroid Build Coastguard Worker 
397*5e7646d2SAndroid Build Coastguard Worker       lseek(fd, 0, SEEK_SET);
398*5e7646d2SAndroid Build Coastguard Worker 
399*5e7646d2SAndroid Build Coastguard Worker       while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
400*5e7646d2SAndroid Build Coastguard Worker 	if (httpCheck(http))
401*5e7646d2SAndroid Build Coastguard Worker 	{
402*5e7646d2SAndroid Build Coastguard Worker           if ((status = httpUpdate(http)) != HTTP_STATUS_CONTINUE)
403*5e7646d2SAndroid Build Coastguard Worker             break;
404*5e7646d2SAndroid Build Coastguard Worker 	}
405*5e7646d2SAndroid Build Coastguard Worker 	else
406*5e7646d2SAndroid Build Coastguard Worker           httpWrite2(http, buffer, (size_t)bytes);
407*5e7646d2SAndroid Build Coastguard Worker     }
408*5e7646d2SAndroid Build Coastguard Worker 
409*5e7646d2SAndroid Build Coastguard Worker     if (status == HTTP_STATUS_CONTINUE)
410*5e7646d2SAndroid Build Coastguard Worker     {
411*5e7646d2SAndroid Build Coastguard Worker       httpWrite2(http, buffer, 0);
412*5e7646d2SAndroid Build Coastguard Worker 
413*5e7646d2SAndroid Build Coastguard Worker       while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE);
414*5e7646d2SAndroid Build Coastguard Worker     }
415*5e7646d2SAndroid Build Coastguard Worker 
416*5e7646d2SAndroid Build Coastguard Worker     if (status == HTTP_STATUS_ERROR && !retries)
417*5e7646d2SAndroid Build Coastguard Worker     {
418*5e7646d2SAndroid Build Coastguard Worker       DEBUG_printf(("2cupsPutFd: retry on status %d", status));
419*5e7646d2SAndroid Build Coastguard Worker 
420*5e7646d2SAndroid Build Coastguard Worker       retries ++;
421*5e7646d2SAndroid Build Coastguard Worker 
422*5e7646d2SAndroid Build Coastguard Worker       /* Flush any error message... */
423*5e7646d2SAndroid Build Coastguard Worker       httpFlush(http);
424*5e7646d2SAndroid Build Coastguard Worker 
425*5e7646d2SAndroid Build Coastguard Worker       /* Reconnect... */
426*5e7646d2SAndroid Build Coastguard Worker       if (httpReconnect2(http, 30000, NULL))
427*5e7646d2SAndroid Build Coastguard Worker       {
428*5e7646d2SAndroid Build Coastguard Worker         status = HTTP_STATUS_ERROR;
429*5e7646d2SAndroid Build Coastguard Worker         break;
430*5e7646d2SAndroid Build Coastguard Worker       }
431*5e7646d2SAndroid Build Coastguard Worker 
432*5e7646d2SAndroid Build Coastguard Worker       /* Try again... */
433*5e7646d2SAndroid Build Coastguard Worker       continue;
434*5e7646d2SAndroid Build Coastguard Worker     }
435*5e7646d2SAndroid Build Coastguard Worker 
436*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("2cupsPutFd: status=%d", status));
437*5e7646d2SAndroid Build Coastguard Worker 
438*5e7646d2SAndroid Build Coastguard Worker     new_auth = 0;
439*5e7646d2SAndroid Build Coastguard Worker 
440*5e7646d2SAndroid Build Coastguard Worker     if (status == HTTP_STATUS_UNAUTHORIZED)
441*5e7646d2SAndroid Build Coastguard Worker     {
442*5e7646d2SAndroid Build Coastguard Worker      /*
443*5e7646d2SAndroid Build Coastguard Worker       * Flush any error message...
444*5e7646d2SAndroid Build Coastguard Worker       */
445*5e7646d2SAndroid Build Coastguard Worker 
446*5e7646d2SAndroid Build Coastguard Worker       httpFlush(http);
447*5e7646d2SAndroid Build Coastguard Worker 
448*5e7646d2SAndroid Build Coastguard Worker      /*
449*5e7646d2SAndroid Build Coastguard Worker       * See if we can do authentication...
450*5e7646d2SAndroid Build Coastguard Worker       */
451*5e7646d2SAndroid Build Coastguard Worker 
452*5e7646d2SAndroid Build Coastguard Worker       new_auth = 1;
453*5e7646d2SAndroid Build Coastguard Worker 
454*5e7646d2SAndroid Build Coastguard Worker       if (cupsDoAuthentication(http, "PUT", resource))
455*5e7646d2SAndroid Build Coastguard Worker       {
456*5e7646d2SAndroid Build Coastguard Worker         status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED;
457*5e7646d2SAndroid Build Coastguard Worker         break;
458*5e7646d2SAndroid Build Coastguard Worker       }
459*5e7646d2SAndroid Build Coastguard Worker 
460*5e7646d2SAndroid Build Coastguard Worker       if (httpReconnect2(http, 30000, NULL))
461*5e7646d2SAndroid Build Coastguard Worker       {
462*5e7646d2SAndroid Build Coastguard Worker         status = HTTP_STATUS_ERROR;
463*5e7646d2SAndroid Build Coastguard Worker         break;
464*5e7646d2SAndroid Build Coastguard Worker       }
465*5e7646d2SAndroid Build Coastguard Worker 
466*5e7646d2SAndroid Build Coastguard Worker       continue;
467*5e7646d2SAndroid Build Coastguard Worker     }
468*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_SSL
469*5e7646d2SAndroid Build Coastguard Worker     else if (status == HTTP_STATUS_UPGRADE_REQUIRED)
470*5e7646d2SAndroid Build Coastguard Worker     {
471*5e7646d2SAndroid Build Coastguard Worker       /* Flush any error message... */
472*5e7646d2SAndroid Build Coastguard Worker       httpFlush(http);
473*5e7646d2SAndroid Build Coastguard Worker 
474*5e7646d2SAndroid Build Coastguard Worker       /* Reconnect... */
475*5e7646d2SAndroid Build Coastguard Worker       if (httpReconnect2(http, 30000, NULL))
476*5e7646d2SAndroid Build Coastguard Worker       {
477*5e7646d2SAndroid Build Coastguard Worker         status = HTTP_STATUS_ERROR;
478*5e7646d2SAndroid Build Coastguard Worker         break;
479*5e7646d2SAndroid Build Coastguard Worker       }
480*5e7646d2SAndroid Build Coastguard Worker 
481*5e7646d2SAndroid Build Coastguard Worker       /* Upgrade with encryption... */
482*5e7646d2SAndroid Build Coastguard Worker       httpEncryption(http, HTTP_ENCRYPTION_REQUIRED);
483*5e7646d2SAndroid Build Coastguard Worker 
484*5e7646d2SAndroid Build Coastguard Worker       /* Try again, this time with encryption enabled... */
485*5e7646d2SAndroid Build Coastguard Worker       continue;
486*5e7646d2SAndroid Build Coastguard Worker     }
487*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_SSL */
488*5e7646d2SAndroid Build Coastguard Worker   }
489*5e7646d2SAndroid Build Coastguard Worker   while (status == HTTP_STATUS_UNAUTHORIZED || status == HTTP_STATUS_UPGRADE_REQUIRED ||
490*5e7646d2SAndroid Build Coastguard Worker          (status == HTTP_STATUS_ERROR && retries < 2));
491*5e7646d2SAndroid Build Coastguard Worker 
492*5e7646d2SAndroid Build Coastguard Worker  /*
493*5e7646d2SAndroid Build Coastguard Worker   * See if we actually put the file or an error...
494*5e7646d2SAndroid Build Coastguard Worker   */
495*5e7646d2SAndroid Build Coastguard Worker 
496*5e7646d2SAndroid Build Coastguard Worker   if (status != HTTP_STATUS_CREATED)
497*5e7646d2SAndroid Build Coastguard Worker   {
498*5e7646d2SAndroid Build Coastguard Worker     _cupsSetHTTPError(status);
499*5e7646d2SAndroid Build Coastguard Worker     httpFlush(http);
500*5e7646d2SAndroid Build Coastguard Worker   }
501*5e7646d2SAndroid Build Coastguard Worker 
502*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("1cupsPutFd: Returning %d...", status));
503*5e7646d2SAndroid Build Coastguard Worker 
504*5e7646d2SAndroid Build Coastguard Worker   return (status);
505*5e7646d2SAndroid Build Coastguard Worker }
506*5e7646d2SAndroid Build Coastguard Worker 
507*5e7646d2SAndroid Build Coastguard Worker 
508*5e7646d2SAndroid Build Coastguard Worker /*
509*5e7646d2SAndroid Build Coastguard Worker  * 'cupsPutFile()' - Put a file on the server.
510*5e7646d2SAndroid Build Coastguard Worker  *
511*5e7646d2SAndroid Build Coastguard Worker  * This function returns @code HTTP_CREATED@ when the file is stored
512*5e7646d2SAndroid Build Coastguard Worker  * successfully.
513*5e7646d2SAndroid Build Coastguard Worker  *
514*5e7646d2SAndroid Build Coastguard Worker  * @since CUPS 1.1.20/macOS 10.4@
515*5e7646d2SAndroid Build Coastguard Worker  */
516*5e7646d2SAndroid Build Coastguard Worker 
517*5e7646d2SAndroid Build Coastguard Worker http_status_t				/* O - HTTP status */
cupsPutFile(http_t * http,const char * resource,const char * filename)518*5e7646d2SAndroid Build Coastguard Worker cupsPutFile(http_t     *http,		/* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
519*5e7646d2SAndroid Build Coastguard Worker             const char *resource,	/* I - Resource name */
520*5e7646d2SAndroid Build Coastguard Worker 	    const char *filename)	/* I - Filename */
521*5e7646d2SAndroid Build Coastguard Worker {
522*5e7646d2SAndroid Build Coastguard Worker   int		fd;			/* File descriptor */
523*5e7646d2SAndroid Build Coastguard Worker   http_status_t	status;			/* Status */
524*5e7646d2SAndroid Build Coastguard Worker 
525*5e7646d2SAndroid Build Coastguard Worker 
526*5e7646d2SAndroid Build Coastguard Worker  /*
527*5e7646d2SAndroid Build Coastguard Worker   * Range check input...
528*5e7646d2SAndroid Build Coastguard Worker   */
529*5e7646d2SAndroid Build Coastguard Worker 
530*5e7646d2SAndroid Build Coastguard Worker   if (!http || !resource || !filename)
531*5e7646d2SAndroid Build Coastguard Worker   {
532*5e7646d2SAndroid Build Coastguard Worker     if (http)
533*5e7646d2SAndroid Build Coastguard Worker       http->error = EINVAL;
534*5e7646d2SAndroid Build Coastguard Worker 
535*5e7646d2SAndroid Build Coastguard Worker     return (HTTP_STATUS_ERROR);
536*5e7646d2SAndroid Build Coastguard Worker   }
537*5e7646d2SAndroid Build Coastguard Worker 
538*5e7646d2SAndroid Build Coastguard Worker  /*
539*5e7646d2SAndroid Build Coastguard Worker   * Open the local file...
540*5e7646d2SAndroid Build Coastguard Worker   */
541*5e7646d2SAndroid Build Coastguard Worker 
542*5e7646d2SAndroid Build Coastguard Worker   if ((fd = open(filename, O_RDONLY)) < 0)
543*5e7646d2SAndroid Build Coastguard Worker   {
544*5e7646d2SAndroid Build Coastguard Worker    /*
545*5e7646d2SAndroid Build Coastguard Worker     * Couldn't open the file!
546*5e7646d2SAndroid Build Coastguard Worker     */
547*5e7646d2SAndroid Build Coastguard Worker 
548*5e7646d2SAndroid Build Coastguard Worker     http->error = errno;
549*5e7646d2SAndroid Build Coastguard Worker 
550*5e7646d2SAndroid Build Coastguard Worker     return (HTTP_STATUS_ERROR);
551*5e7646d2SAndroid Build Coastguard Worker   }
552*5e7646d2SAndroid Build Coastguard Worker 
553*5e7646d2SAndroid Build Coastguard Worker  /*
554*5e7646d2SAndroid Build Coastguard Worker   * Put the file...
555*5e7646d2SAndroid Build Coastguard Worker   */
556*5e7646d2SAndroid Build Coastguard Worker 
557*5e7646d2SAndroid Build Coastguard Worker   status = cupsPutFd(http, resource, fd);
558*5e7646d2SAndroid Build Coastguard Worker 
559*5e7646d2SAndroid Build Coastguard Worker   close(fd);
560*5e7646d2SAndroid Build Coastguard Worker 
561*5e7646d2SAndroid Build Coastguard Worker   return (status);
562*5e7646d2SAndroid Build Coastguard Worker }
563