1 /*
2  * "$Id: http.c 148 2006-04-25 16:54:17Z njacobs $"
3  *
4  *   HTTP routines for the Common UNIX Printing System (CUPS).
5  *
6  *   Copyright 1997-2005 by Easy Software Products, all rights reserved.
7  *
8  *   These coded instructions, statements, and computer programs are the
9  *   property of Easy Software Products and are protected by Federal
10  *   copyright law.  Distribution and use rights are outlined in the file
11  *   "LICENSE.txt" which should have been included with this file.  If this
12  *   file is missing or damaged please contact Easy Software Products
13  *   at:
14  *
15  *       Attn: CUPS Licensing Information
16  *       Easy Software Products
17  *       44141 Airport View Drive, Suite 204
18  *       Hollywood, Maryland 20636 USA
19  *
20  *       Voice: (301) 373-9600
21  *       EMail: cups-info@cups.org
22  *         WWW: http://www.cups.org
23  *
24  *   This file is subject to the Apple OS-Developed Software exception.
25  *
26  * Contents:
27  *
28  *   httpInitialize()     - Initialize the HTTP interface library and set the
29  *                          default HTTP proxy (if any).
30  *   httpCheck()          - Check to see if there is a pending response from
31  *                          the server.
32  *   httpClearCookie()    - Clear the cookie value(s).
33  *   httpClose()          - Close an HTTP connection...
34  *   httpConnect()        - Connect to a HTTP server.
35  *   httpConnectEncrypt() - Connect to a HTTP server using encryption.
36  *   httpEncryption()     - Set the required encryption on the link.
37  *   httpReconnect()      - Reconnect to a HTTP server...
38  *   httpGetSubField()    - Get a sub-field value.
39  *   httpSetField()       - Set the value of an HTTP header.
40  *   httpDelete()         - Send a DELETE request to the server.
41  *   httpGet()            - Send a GET request to the server.
42  *   httpHead()           - Send a HEAD request to the server.
43  *   httpOptions()        - Send an OPTIONS request to the server.
44  *   httpPost()           - Send a POST request to the server.
45  *   httpPut()            - Send a PUT request to the server.
46  *   httpTrace()          - Send an TRACE request to the server.
47  *   httpFlush()          - Flush data from a HTTP connection.
48  *   httpRead()           - Read data from a HTTP connection.
49  *   httpSetCookie()      - Set the cookie value(s)...
50  *   httpWait()           - Wait for data available on a connection.
51  *   httpWrite()          - Write data to a HTTP connection.
52  *   httpGets()           - Get a line of text from a HTTP connection.
53  *   httpPrintf()         - Print a formatted string to a HTTP connection.
54  *   httpGetDateString()  - Get a formatted date/time string from a time value.
55  *   httpGetDateTime()    - Get a time value from a formatted date/time string.
56  *   httpUpdate()         - Update the current HTTP state for incoming data.
57  *   httpDecode64()       - Base64-decode a string.
58  *   httpDecode64_2()     - Base64-decode a string.
59  *   httpEncode64()       - Base64-encode a string.
60  *   httpEncode64_2()     - Base64-encode a string.
61  *   httpGetLength()      - Get the amount of data remaining from the
62  *                          content-length or transfer-encoding fields.
63  *   http_field()         - Return the field index for a field name.
64  *   http_send()          - Send a request with all fields and the trailing
65  *                          blank line.
66  *   http_wait()          - Wait for data available on a connection.
67  *   http_upgrade()       - Force upgrade to TLS encryption.
68  *   http_setup_ssl()     - Set up SSL/TLS on a connection.
69  *   http_shutdown_ssl()  - Shut down SSL/TLS on a connection.
70  *   http_read_ssl()      - Read from a SSL/TLS connection.
71  *   http_write_ssl()     - Write to a SSL/TLS connection.
72  *   CDSAReadFunc()       - Read function for CDSA decryption code.
73  *   CDSAWriteFunc()      - Write function for CDSA encryption code.
74  */
75 
76 /*
77  * Include necessary headers...
78  */
79 
80 #include "http-private.h"
81 
82 #include <stdio.h>
83 #include <stdlib.h>
84 #include <stdarg.h>
85 #include <ctype.h>
86 #include "string.h"
87 #include <fcntl.h>
88 #include <errno.h>
89 
90 #include "http.h"
91 #include "debug.h"
92 
93 #ifndef WIN32
94 #  include <signal.h>
95 #  include <sys/time.h>
96 #  include <sys/resource.h>
97 #endif /* !WIN32 */
98 
99 
100 /*
101  * Some operating systems have done away with the Fxxxx constants for
102  * the fcntl() call; this works around that "feature"...
103  */
104 
105 #ifndef FNONBLK
106 #  define FNONBLK O_NONBLOCK
107 #endif /* !FNONBLK */
108 
109 
110 /*
111  * Local functions...
112  */
113 
114 static http_field_t	http_field(const char *name);
115 static int		http_send(http_t *http, http_state_t request,
116 			          const char *uri);
117 static int		http_wait(http_t *http, int msec);
118 #ifdef HAVE_SSL
119 static int		http_upgrade(http_t *http);
120 static int		http_setup_ssl(http_t *http);
121 static void		http_shutdown_ssl(http_t *http);
122 static int		http_read_ssl(http_t *http, char *buf, int len);
123 static int		http_write_ssl(http_t *http, const char *buf, int len);
124 #  ifdef HAVE_CDSASSL
125 static OSStatus		CDSAReadFunc(SSLConnectionRef connection, void *data, size_t *dataLength);
126 static OSStatus		CDSAWriteFunc(SSLConnectionRef connection, const void *data, size_t *dataLength);
127 #  endif /* HAVE_CDSASSL */
128 #endif /* HAVE_SSL */
129 
130 
131 /*
132  * Local globals...
133  */
134 
135 static const char * const http_fields[] =
136 			{
137 			  "Accept-Language",
138 			  "Accept-Ranges",
139 			  "Authorization",
140 			  "Connection",
141 			  "Content-Encoding",
142 			  "Content-Language",
143 			  "Content-Length",
144 			  "Content-Location",
145 			  "Content-MD5",
146 			  "Content-Range",
147 			  "Content-Type",
148 			  "Content-Version",
149 			  "Date",
150 			  "Host",
151 			  "If-Modified-Since",
152 			  "If-Unmodified-since",
153 			  "Keep-Alive",
154 			  "Last-Modified",
155 			  "Link",
156 			  "Location",
157 			  "Range",
158 			  "Referer",
159 			  "Retry-After",
160 			  "Transfer-Encoding",
161 			  "Upgrade",
162 			  "User-Agent",
163 			  "WWW-Authenticate"
164 			};
165 static const char * const days[7] =
166 			{
167 			  "Sun",
168 			  "Mon",
169 			  "Tue",
170 			  "Wed",
171 			  "Thu",
172 			  "Fri",
173 			  "Sat"
174 			};
175 static const char * const months[12] =
176 			{
177 			  "Jan",
178 			  "Feb",
179 			  "Mar",
180 			  "Apr",
181 			  "May",
182 			  "Jun",
183 		          "Jul",
184 			  "Aug",
185 			  "Sep",
186 			  "Oct",
187 			  "Nov",
188 			  "Dec"
189 			};
190 
191 void
httpDumpData(FILE * fp,const char * tag,const char * buffer,int bytes)192 httpDumpData(FILE *fp, const char *tag, const char *buffer, int bytes)
193 {
194         int i, j, ch;
195 
196 	fprintf(fp, "%s %d(0x%x) bytes...\n", tag, bytes, bytes);
197         for (i = 0; i < bytes; i += 16) {
198                 fprintf(fp, "%s   ", (tag ? tag : ""));
199 
200                 for (j = 0; j < 16 && (i + j) < bytes; j ++)
201                         fprintf(fp, " %02X", buffer[i + j] & 255);
202 
203                 while (j < 16) {
204                         fprintf(fp, "   ");
205                         j++;
206                 }
207 
208                 fprintf(fp, "    ");
209                 for (j = 0; j < 16 && (i + j) < bytes; j ++) {
210                         ch = buffer[i + j] & 255;
211                         if (ch < ' ' || ch == 127)
212                                 ch = '.';
213                         putc(ch, fp);
214                 }
215                 putc('\n', fp);
216         }
217 }
218 
219 
220 /*
221  * 'httpInitialize()' - Initialize the HTTP interface library and set the
222  *                      default HTTP proxy (if any).
223  */
224 
225 void
httpInitialize(void)226 httpInitialize(void)
227 {
228 #ifdef HAVE_LIBSSL
229 #  ifndef WIN32
230   struct timeval	curtime;	/* Current time in microseconds */
231 #  endif /* !WIN32 */
232   int			i;		/* Looping var */
233   unsigned char		data[1024];	/* Seed data */
234 #endif /* HAVE_LIBSSL */
235 
236 #ifdef WIN32
237   WSADATA	winsockdata;		/* WinSock data */
238   static int	initialized = 0;	/* Has WinSock been initialized? */
239 
240 
241   if (!initialized)
242     WSAStartup(MAKEWORD(1,1), &winsockdata);
243 #elif defined(HAVE_SIGSET)
244   sigset(SIGPIPE, SIG_IGN);
245 #elif defined(HAVE_SIGACTION)
246   struct sigaction	action;		/* POSIX sigaction data */
247 
248 
249  /*
250   * Ignore SIGPIPE signals...
251   */
252 
253   memset(&action, 0, sizeof(action));
254   action.sa_handler = SIG_IGN;
255   sigaction(SIGPIPE, &action, NULL);
256 #else
257   signal(SIGPIPE, SIG_IGN);
258 #endif /* WIN32 */
259 
260 #ifdef HAVE_GNUTLS
261   gnutls_global_init();
262 #endif /* HAVE_GNUTLS */
263 
264 #ifdef HAVE_LIBSSL
265   SSL_load_error_strings();
266   SSL_library_init();
267 
268  /*
269   * Using the current time is a dubious random seed, but on some systems
270   * it is the best we can do (on others, this seed isn't even used...)
271   */
272 
273 #ifdef WIN32
274 #else
275   gettimeofday(&curtime, NULL);
276   srand(curtime.tv_sec + curtime.tv_usec);
277 #endif /* WIN32 */
278 
279   for (i = 0; i < sizeof(data); i ++)
280     data[i] = rand(); /* Yes, this is a poor source of random data... */
281 
282   RAND_seed(&data, sizeof(data));
283 #endif /* HAVE_LIBSSL */
284 }
285 
286 
287 /*
288  * 'httpCheck()' - Check to see if there is a pending response from the server.
289  */
290 
291 int				/* O - 0 = no data, 1 = data available */
httpCheck(http_t * http)292 httpCheck(http_t *http)		/* I - HTTP connection */
293 {
294   return (httpWait(http, 0));
295 }
296 
297 
298 /*
299  * 'httpClearCookie()' - Clear the cookie value(s).
300  */
301 
302 void
httpClearCookie(http_t * http)303 httpClearCookie(http_t *http)			/* I - Connection */
304 {
305   if (!http)
306     return;
307 
308   if (http->cookie)
309   {
310     free(http->cookie);
311     http->cookie = NULL;
312   }
313 }
314 
315 
316 /*
317  * 'httpClose()' - Close an HTTP connection...
318  */
319 
320 void
httpClose(http_t * http)321 httpClose(http_t *http)		/* I - Connection to close */
322 {
323   DEBUG_printf(("httpClose(http=%p)\n", http));
324 
325   if (!http)
326     return;
327 
328   if (http->input_set)
329     free(http->input_set);
330 
331   if (http->cookie)
332     free(http->cookie);
333 
334 #ifdef HAVE_SSL
335   if (http->tls)
336     http_shutdown_ssl(http);
337 #endif /* HAVE_SSL */
338 
339 #ifdef WIN32
340   closesocket(http->fd);
341 #else
342   close(http->fd);
343 #endif /* WIN32 */
344 
345   free(http);
346 }
347 
348 
349 /*
350  * 'httpConnect()' - Connect to a HTTP server.
351  */
352 
353 http_t *				/* O - New HTTP connection */
httpConnect(const char * host,int port)354 httpConnect(const char *host,		/* I - Host to connect to */
355             int        port)		/* I - Port number */
356 {
357   http_encryption_t	encrypt;	/* Type of encryption to use */
358 
359 
360  /*
361   * Set the default encryption status...
362   */
363 
364   if (port == 443)
365     encrypt = HTTP_ENCRYPT_ALWAYS;
366   else
367     encrypt = HTTP_ENCRYPT_IF_REQUESTED;
368 
369   return (httpConnectEncrypt(host, port, encrypt));
370 }
371 
372 
373 /*
374  * 'httpConnectEncrypt()' - Connect to a HTTP server using encryption.
375  */
376 
377 http_t *				/* O - New HTTP connection */
httpConnectEncrypt(const char * host,int port,http_encryption_t encrypt)378 httpConnectEncrypt(const char *host,	/* I - Host to connect to */
379                    int        port,	/* I - Port number */
380 		   http_encryption_t encrypt)
381 					/* I - Type of encryption to use */
382 {
383   int			i;		/* Looping var */
384   http_t		*http;		/* New HTTP connection */
385   struct hostent	*hostaddr;	/* Host address data */
386 
387 
388   DEBUG_printf(("httpConnectEncrypt(host=\"%s\", port=%d, encrypt=%d)\n",
389                 host ? host : "(null)", port, encrypt));
390 
391   if (!host)
392     return (NULL);
393 
394   httpInitialize();
395 
396  /*
397   * Lookup the host...
398   */
399 
400   if ((hostaddr = httpGetHostByName(host)) == NULL)
401   {
402    /*
403     * This hack to make users that don't have a localhost entry in
404     * their hosts file or DNS happy...
405     */
406 
407     if (strcasecmp(host, "localhost") != 0)
408       return (NULL);
409     else if ((hostaddr = httpGetHostByName("127.0.0.1")) == NULL)
410       return (NULL);
411   }
412 
413  /*
414   * Verify that it is an IPv4, IPv6, or domain address...
415   */
416 
417   if ((hostaddr->h_addrtype != AF_INET || hostaddr->h_length != 4)
418 #ifdef AF_INET6
419       && (hostaddr->h_addrtype != AF_INET6 || hostaddr->h_length != 16)
420 #endif /* AF_INET6 */
421 #ifdef AF_LOCAL
422       && (hostaddr->h_addrtype != AF_LOCAL)
423 #endif /* AF_LOCAL */
424       )
425     return (NULL);
426 
427  /*
428   * Allocate memory for the structure...
429   */
430 
431   http = calloc(sizeof(http_t), 1);
432   if (http == NULL)
433     return (NULL);
434 
435   http->version  = HTTP_1_1;
436   http->blocking = 1;
437   http->activity = time(NULL);
438   http->fd       = -1;
439 
440  /*
441   * Set the encryption status...
442   */
443 
444   if (port == 443)			/* Always use encryption for https */
445     http->encryption = HTTP_ENCRYPT_ALWAYS;
446   else
447     http->encryption = encrypt;
448 
449  /*
450   * Loop through the addresses we have until one of them connects...
451   */
452 
453   strlcpy(http->hostname, host, sizeof(http->hostname));
454 
455   for (i = 0; hostaddr->h_addr_list[i]; i ++)
456   {
457    /*
458     * Load the address...
459     */
460 
461     httpAddrLoad(hostaddr, port, i, &(http->hostaddr));
462 
463    /*
464     * Connect to the remote system...
465     */
466 
467     if (!httpReconnect(http))
468       return (http);
469   }
470 
471  /*
472   * Could not connect to any known address - bail out!
473   */
474 
475   free(http);
476   return (NULL);
477 }
478 
479 
480 /*
481  * 'httpEncryption()' - Set the required encryption on the link.
482  */
483 
484 int					/* O - -1 on error, 0 on success */
httpEncryption(http_t * http,http_encryption_t e)485 httpEncryption(http_t            *http,	/* I - HTTP data */
486                http_encryption_t e)	/* I - New encryption preference */
487 {
488   DEBUG_printf(("httpEncryption(http=%p, e=%d)\n", http, e));
489 
490 #ifdef HAVE_SSL
491   if (!http)
492     return (0);
493 
494   http->encryption = e;
495 
496   if ((http->encryption == HTTP_ENCRYPT_ALWAYS && !http->tls) ||
497       (http->encryption == HTTP_ENCRYPT_NEVER && http->tls))
498     return (httpReconnect(http));
499   else if (http->encryption == HTTP_ENCRYPT_REQUIRED && !http->tls)
500     return (http_upgrade(http));
501   else
502     return (0);
503 #else
504   if (e == HTTP_ENCRYPT_ALWAYS || e == HTTP_ENCRYPT_REQUIRED)
505     return (-1);
506   else
507     return (0);
508 #endif /* HAVE_SSL */
509 }
510 
511 
512 /*
513  * 'httpReconnect()' - Reconnect to a HTTP server...
514  */
515 
516 int					/* O - 0 on success, non-zero on failure */
httpReconnect(http_t * http)517 httpReconnect(http_t *http)		/* I - HTTP data */
518 {
519   int		val;			/* Socket option value */
520   int		status;			/* Connect status */
521 
522 
523   DEBUG_printf(("httpReconnect(http=%p)\n", http));
524 
525   if (!http)
526     return (-1);
527 
528 #ifdef HAVE_SSL
529   if (http->tls)
530     http_shutdown_ssl(http);
531 #endif /* HAVE_SSL */
532 
533  /*
534   * Close any previously open socket...
535   */
536 
537   if (http->fd >= 0)
538 #ifdef WIN32
539     closesocket(http->fd);
540 #else
541     close(http->fd);
542 #endif /* WIN32 */
543 
544  /*
545   * Create the socket and set options to allow reuse.
546   */
547 
548   if ((http->fd = socket(http->hostaddr.addr.sa_family, SOCK_STREAM, 0)) < 0)
549   {
550 #ifdef WIN32
551     http->error  = WSAGetLastError();
552 #else
553     http->error  = errno;
554 #endif /* WIN32 */
555     http->status = HTTP_ERROR;
556     return (-1);
557   }
558 
559 #ifdef FD_CLOEXEC
560   fcntl(http->fd, F_SETFD, FD_CLOEXEC);	/* Close this socket when starting *
561 					 * other processes...              */
562 #endif /* FD_CLOEXEC */
563 
564   val = 1;
565   setsockopt(http->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
566 
567 #ifdef SO_REUSEPORT
568   val = 1;
569   setsockopt(http->fd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val));
570 #endif /* SO_REUSEPORT */
571 
572  /*
573   * Using TCP_NODELAY improves responsiveness, especially on systems
574   * with a slow loopback interface...  Since we write large buffers
575   * when sending print files and requests, there shouldn't be any
576   * performance penalty for this...
577   */
578 
579   val = 1;
580 #ifdef WIN32
581   setsockopt(http->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
582 #else
583   setsockopt(http->fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
584 #endif /* WIN32 */
585 
586  /*
587   * Connect to the server...
588   */
589 
590 #ifdef AF_INET6
591   if (http->hostaddr.addr.sa_family == AF_INET6)
592     status = connect(http->fd, (struct sockaddr *)&(http->hostaddr),
593                      sizeof(http->hostaddr.ipv6));
594   else
595 #endif /* AF_INET6 */
596 #ifdef AF_LOCAL
597   if (http->hostaddr.addr.sa_family == AF_LOCAL)
598     status = connect(http->fd, (struct sockaddr *)&(http->hostaddr),
599                      SUN_LEN(&(http->hostaddr.un)));
600   else
601 #endif /* AF_LOCAL */
602   status = connect(http->fd, (struct sockaddr *)&(http->hostaddr),
603                    sizeof(http->hostaddr.ipv4));
604 
605   if (status < 0)
606   {
607 #ifdef WIN32
608     http->error  = WSAGetLastError();
609 #else
610     http->error  = errno;
611 #endif /* WIN32 */
612     http->status = HTTP_ERROR;
613 
614 #ifdef WIN32
615     closesocket(http->fd);
616 #else
617     close(http->fd);
618 #endif
619 
620     http->fd = -1;
621 
622     return (-1);
623   }
624 
625   http->error  = 0;
626   http->status = HTTP_CONTINUE;
627 
628 #ifdef HAVE_SSL
629   if (http->encryption == HTTP_ENCRYPT_ALWAYS)
630   {
631    /*
632     * Always do encryption via SSL.
633     */
634 
635     if (http_setup_ssl(http) != 0)
636     {
637 #ifdef WIN32
638       closesocket(http->fd);
639 #else
640       close(http->fd);
641 #endif /* WIN32 */
642 
643       return (-1);
644     }
645   }
646   else if (http->encryption == HTTP_ENCRYPT_REQUIRED)
647     return (http_upgrade(http));
648 #endif /* HAVE_SSL */
649 
650   return (0);
651 }
652 
653 
654 /*
655  * 'httpGetSubField()' - Get a sub-field value.
656  */
657 
658 char *					/* O - Value or NULL */
httpGetSubField(http_t * http,http_field_t field,const char * name,char * value)659 httpGetSubField(http_t       *http,	/* I - HTTP data */
660                 http_field_t field,	/* I - Field index */
661                 const char   *name,	/* I - Name of sub-field */
662 		char         *value)	/* O - Value string */
663 {
664   const char	*fptr;			/* Pointer into field */
665   char		temp[HTTP_MAX_VALUE],	/* Temporary buffer for name */
666 		*ptr;			/* Pointer into string buffer */
667 
668 
669   DEBUG_printf(("httpGetSubField(http=%p, field=%d, name=\"%s\", value=%p)\n",
670                 http, field, name, value));
671 
672   if (http == NULL ||
673       field < HTTP_FIELD_ACCEPT_LANGUAGE ||
674       field > HTTP_FIELD_WWW_AUTHENTICATE ||
675       name == NULL || value == NULL)
676     return (NULL);
677 
678   for (fptr = http->fields[field]; *fptr;)
679   {
680    /*
681     * Skip leading whitespace...
682     */
683 
684     while (isspace(*fptr & 255))
685       fptr ++;
686 
687     if (*fptr == ',')
688     {
689       fptr ++;
690       continue;
691     }
692 
693    /*
694     * Get the sub-field name...
695     */
696 
697     for (ptr = temp;
698          *fptr && *fptr != '=' && !isspace(*fptr & 255) && ptr < (temp + sizeof(temp) - 1);
699          *ptr++ = *fptr++);
700 
701     *ptr = '\0';
702 
703     DEBUG_printf(("httpGetSubField: name=\"%s\"\n", temp));
704 
705    /*
706     * Skip trailing chars up to the '='...
707     */
708 
709     while (isspace(*fptr & 255))
710       fptr ++;
711 
712     if (!*fptr)
713       break;
714 
715     if (*fptr != '=')
716       continue;
717 
718    /*
719     * Skip = and leading whitespace...
720     */
721 
722     fptr ++;
723 
724     while (isspace(*fptr & 255))
725       fptr ++;
726 
727     if (*fptr == '\"')
728     {
729      /*
730       * Read quoted string...
731       */
732 
733       for (ptr = value, fptr ++;
734            *fptr && *fptr != '\"' && ptr < (value + HTTP_MAX_VALUE - 1);
735 	   *ptr++ = *fptr++);
736 
737       *ptr = '\0';
738 
739       while (*fptr && *fptr != '\"')
740         fptr ++;
741 
742       if (*fptr)
743         fptr ++;
744     }
745     else
746     {
747      /*
748       * Read unquoted string...
749       */
750 
751       for (ptr = value;
752            *fptr && !isspace(*fptr & 255) && *fptr != ',' && ptr < (value + HTTP_MAX_VALUE - 1);
753 	   *ptr++ = *fptr++);
754 
755       *ptr = '\0';
756 
757       while (*fptr && !isspace(*fptr & 255) && *fptr != ',')
758         fptr ++;
759     }
760 
761     DEBUG_printf(("httpGetSubField: value=\"%s\"\n", value));
762 
763    /*
764     * See if this is the one...
765     */
766 
767     if (strcmp(name, temp) == 0)
768       return (value);
769   }
770 
771   value[0] = '\0';
772 
773   return (NULL);
774 }
775 
776 
777 /*
778  * 'httpSetField()' - Set the value of an HTTP header.
779  */
780 
781 void
httpSetField(http_t * http,http_field_t field,const char * value)782 httpSetField(http_t       *http,	/* I - HTTP data */
783              http_field_t field,	/* I - Field index */
784 	     const char   *value)	/* I - Value */
785 {
786   if (http == NULL ||
787       field < HTTP_FIELD_ACCEPT_LANGUAGE ||
788       field > HTTP_FIELD_WWW_AUTHENTICATE ||
789       value == NULL)
790     return;
791 
792   strlcpy(http->fields[field], value, HTTP_MAX_VALUE);
793 }
794 
795 
796 /*
797  * 'httpDelete()' - Send a DELETE request to the server.
798  */
799 
800 int					/* O - Status of call (0 = success) */
httpDelete(http_t * http,const char * uri)801 httpDelete(http_t     *http,		/* I - HTTP data */
802            const char *uri)		/* I - URI to delete */
803 {
804   return (http_send(http, HTTP_DELETE, uri));
805 }
806 
807 
808 /*
809  * 'httpGet()' - Send a GET request to the server.
810  */
811 
812 int					/* O - Status of call (0 = success) */
httpGet(http_t * http,const char * uri)813 httpGet(http_t     *http,		/* I - HTTP data */
814         const char *uri)		/* I - URI to get */
815 {
816   return (http_send(http, HTTP_GET, uri));
817 }
818 
819 
820 /*
821  * 'httpHead()' - Send a HEAD request to the server.
822  */
823 
824 int					/* O - Status of call (0 = success) */
httpHead(http_t * http,const char * uri)825 httpHead(http_t     *http,		/* I - HTTP data */
826          const char *uri)		/* I - URI for head */
827 {
828   return (http_send(http, HTTP_HEAD, uri));
829 }
830 
831 
832 /*
833  * 'httpOptions()' - Send an OPTIONS request to the server.
834  */
835 
836 int					/* O - Status of call (0 = success) */
httpOptions(http_t * http,const char * uri)837 httpOptions(http_t     *http,		/* I - HTTP data */
838             const char *uri)		/* I - URI for options */
839 {
840   return (http_send(http, HTTP_OPTIONS, uri));
841 }
842 
843 
844 /*
845  * 'httpPost()' - Send a POST request to the server.
846  */
847 
848 int					/* O - Status of call (0 = success) */
httpPost(http_t * http,const char * uri)849 httpPost(http_t     *http,		/* I - HTTP data */
850          const char *uri)		/* I - URI for post */
851 {
852   httpGetLength(http);
853 
854   return (http_send(http, HTTP_POST, uri));
855 }
856 
857 
858 /*
859  * 'httpPut()' - Send a PUT request to the server.
860  */
861 
862 int					/* O - Status of call (0 = success) */
httpPut(http_t * http,const char * uri)863 httpPut(http_t     *http,		/* I - HTTP data */
864         const char *uri)		/* I - URI to put */
865 {
866   httpGetLength(http);
867 
868   return (http_send(http, HTTP_PUT, uri));
869 }
870 
871 
872 /*
873  * 'httpTrace()' - Send an TRACE request to the server.
874  */
875 
876 int					/* O - Status of call (0 = success) */
httpTrace(http_t * http,const char * uri)877 httpTrace(http_t     *http,		/* I - HTTP data */
878           const char *uri)		/* I - URI for trace */
879 {
880   return (http_send(http, HTTP_TRACE, uri));
881 }
882 
883 
884 /*
885  * 'httpFlush()' - Flush data from a HTTP connection.
886  */
887 
888 void
httpFlush(http_t * http)889 httpFlush(http_t *http)			/* I - HTTP data */
890 {
891   char	buffer[8192];			/* Junk buffer */
892 
893 
894   DEBUG_printf(("httpFlush(http=%p), state=%d\n", http, http->state));
895 
896   while (httpRead(http, buffer, sizeof(buffer)) > 0);
897 }
898 
899 
900 /*
901  * 'httpRead()' - Read data from a HTTP connection.
902  */
903 
904 int					/* O - Number of bytes read */
httpRead(http_t * http,char * buffer,int length)905 httpRead(http_t *http,			/* I - HTTP data */
906          char   *buffer,		/* I - Buffer for data */
907 	 int    length)			/* I - Maximum number of bytes */
908 {
909   int		bytes;			/* Bytes read */
910   char		len[32];		/* Length string */
911 
912 
913   DEBUG_printf(("httpRead(http=%p, buffer=%p, length=%d)\n",
914                 http, buffer, length));
915 
916   if (http == NULL || buffer == NULL)
917     return (-1);
918 
919   http->activity = time(NULL);
920 
921   if (length <= 0)
922     return (0);
923 
924   if (http->data_encoding == HTTP_ENCODE_CHUNKED &&
925       http->data_remaining <= 0)
926   {
927     DEBUG_puts("httpRead: Getting chunk length...");
928 
929     if (httpGets(len, sizeof(len), http) == NULL)
930     {
931       DEBUG_puts("httpRead: Could not get length!");
932       return (0);
933     }
934 
935     http->data_remaining = strtol(len, NULL, 16);
936     if (http->data_remaining < 0)
937     {
938       DEBUG_puts("httpRead: Negative chunk length!");
939       return (0);
940     }
941   }
942 
943   DEBUG_printf(("httpRead: data_remaining=%d\n", http->data_remaining));
944 
945   if (http->data_remaining <= 0)
946   {
947    /*
948     * A zero-length chunk ends a transfer; unless we are reading POST
949     * data, go idle...
950     */
951 
952     if (http->data_encoding == HTTP_ENCODE_CHUNKED)
953       httpGets(len, sizeof(len), http);
954 
955     if (http->state == HTTP_POST_RECV)
956       http->state ++;
957     else
958       http->state = HTTP_WAITING;
959 
960    /*
961     * Prevent future reads for this request...
962     */
963 
964     http->data_encoding = HTTP_ENCODE_LENGTH;
965 
966     return (0);
967   }
968   else if (length > http->data_remaining)
969     length = http->data_remaining;
970 
971   if (http->used == 0 && length <= 256)
972   {
973    /*
974     * Buffer small reads for better performance...
975     */
976 
977     if (!http->blocking && !httpWait(http, 1000))
978       return (0);
979 
980     if (http->data_remaining > sizeof(http->buffer))
981       bytes = sizeof(http->buffer);
982     else
983       bytes = http->data_remaining;
984 
985 #ifdef HAVE_SSL
986     if (http->tls)
987       bytes = http_read_ssl(http, http->buffer, bytes);
988     else
989 #endif /* HAVE_SSL */
990     {
991       DEBUG_printf(("httpRead: reading %d bytes from socket into buffer...\n",
992                     bytes));
993 
994       bytes = recv(http->fd, http->buffer, bytes, 0);
995 
996       DEBUG_printf(("httpRead: read %d bytes from socket into buffer...\n",
997                     bytes));
998 #ifdef DEBUG_HTTP
999     httpDumpData(stdout, "httpRead:", http->buffer, bytes);
1000 #endif
1001     }
1002 
1003     if (bytes > 0)
1004       http->used = bytes;
1005     else if (bytes < 0)
1006     {
1007 #ifdef WIN32
1008       http->error = WSAGetLastError();
1009       return (-1);
1010 #else
1011       if (errno != EINTR)
1012       {
1013         http->error = errno;
1014         return (-1);
1015       }
1016 #endif /* WIN32 */
1017     }
1018     else
1019     {
1020       http->error = EPIPE;
1021       return (0);
1022     }
1023   }
1024 
1025   if (http->used > 0)
1026   {
1027     if (length > http->used)
1028       length = http->used;
1029 
1030     bytes = length;
1031 
1032     DEBUG_printf(("httpRead: grabbing %d bytes from input buffer...\n", bytes));
1033 
1034     memcpy(buffer, http->buffer, length);
1035     http->used -= length;
1036 
1037     if (http->used > 0)
1038       memmove(http->buffer, http->buffer + length, http->used);
1039   }
1040 #ifdef HAVE_SSL
1041   else if (http->tls)
1042   {
1043     if (!http->blocking && !httpWait(http, 1000))
1044       return (0);
1045 
1046     bytes = http_read_ssl(http, buffer, length);
1047   }
1048 #endif /* HAVE_SSL */
1049   else
1050   {
1051     if (!http->blocking && !httpWait(http, 1000))
1052       return (0);
1053 
1054     DEBUG_printf(("httpRead: reading %d bytes from socket...\n", length));
1055 
1056     while ((bytes = recv(http->fd, buffer, length, 0)) < 0)
1057       if (errno != EINTR)
1058         break;
1059     DEBUG_printf(("httpRead: read %d bytes from socket...\n", bytes));
1060   }
1061 #ifdef DEBUG_HTTP
1062     httpDumpData(stdout, "httpRead:", buffer, bytes);
1063 #endif
1064 
1065   if (bytes > 0)
1066     http->data_remaining -= bytes;
1067   else if (bytes < 0)
1068   {
1069 #ifdef WIN32
1070     http->error = WSAGetLastError();
1071 #else
1072     if (errno == EINTR)
1073       bytes = 0;
1074     else
1075       http->error = errno;
1076 #endif /* WIN32 */
1077   }
1078   else
1079   {
1080     http->error = EPIPE;
1081     return (0);
1082   }
1083 
1084   if (http->data_remaining == 0)
1085   {
1086     if (http->data_encoding == HTTP_ENCODE_CHUNKED)
1087       httpGets(len, sizeof(len), http);
1088 
1089     if (http->data_encoding != HTTP_ENCODE_CHUNKED)
1090     {
1091       if (http->state == HTTP_POST_RECV)
1092 	http->state ++;
1093       else
1094 	http->state = HTTP_WAITING;
1095     }
1096   }
1097 
1098   return (bytes);
1099 }
1100 
1101 
1102 /*
1103  * 'httpSetCookie()' - Set the cookie value(s)...
1104  */
1105 
1106 void
httpSetCookie(http_t * http,const char * cookie)1107 httpSetCookie(http_t     *http,		/* I - Connection */
1108               const char *cookie)	/* I - Cookie string */
1109 {
1110   if (!http)
1111     return;
1112 
1113   if (http->cookie)
1114     free(http->cookie);
1115 
1116   if (cookie)
1117     http->cookie = strdup(cookie);
1118   else
1119     http->cookie = NULL;
1120 }
1121 
1122 
1123 /*
1124  * 'httpWait()' - Wait for data available on a connection.
1125  */
1126 
1127 int					/* O - 1 if data is available, 0 otherwise */
httpWait(http_t * http,int msec)1128 httpWait(http_t *http,			/* I - HTTP data */
1129          int    msec)			/* I - Milliseconds to wait */
1130 {
1131  /*
1132   * First see if there is data in the buffer...
1133   */
1134 
1135   if (http == NULL)
1136     return (0);
1137 
1138   if (http->used)
1139     return (1);
1140 
1141  /*
1142   * If not, check the SSL/TLS buffers and do a select() on the connection...
1143   */
1144 
1145   return (http_wait(http, msec));
1146 }
1147 
1148 
1149 /*
1150  * 'httpWrite()' - Write data to a HTTP connection.
1151  */
1152 
1153 int					/* O - Number of bytes written */
httpWrite(http_t * http,const char * buffer,int length)1154 httpWrite(http_t     *http,		/* I - HTTP data */
1155           const char *buffer,		/* I - Buffer for data */
1156 	  int        length)		/* I - Number of bytes to write */
1157 {
1158   int	tbytes,				/* Total bytes sent */
1159 	bytes;				/* Bytes sent */
1160 
1161 
1162   if (http == NULL || buffer == NULL)
1163     return (-1);
1164 
1165   http->activity = time(NULL);
1166 
1167   if (http->data_encoding == HTTP_ENCODE_CHUNKED)
1168   {
1169     if (httpPrintf(http, "%x\r\n", length) < 0)
1170       return (-1);
1171 
1172     if (length == 0)
1173     {
1174      /*
1175       * A zero-length chunk ends a transfer; unless we are sending POST
1176       * or PUT data, go idle...
1177       */
1178 
1179       DEBUG_printf(("httpWrite: changing states from %d", http->state));
1180 
1181       if (http->state == HTTP_POST_RECV)
1182 	http->state ++;
1183       else if (http->state == HTTP_PUT_RECV)
1184         http->state = HTTP_STATUS;
1185       else
1186 	http->state = HTTP_WAITING;
1187       DEBUG_printf((" to %d\n", http->state));
1188 
1189       if (httpPrintf(http, "\r\n") < 0)
1190 	return (-1);
1191 
1192       return (0);
1193     }
1194   }
1195 
1196   tbytes = 0;
1197 
1198   while (length > 0)
1199   {
1200 #ifdef HAVE_SSL
1201     if (http->tls)
1202       bytes = http_write_ssl(http, buffer, length);
1203     else
1204 #endif /* HAVE_SSL */
1205     bytes = send(http->fd, buffer, length, 0);
1206 
1207 #ifdef DEBUG_HTTP
1208   if (bytes >= 0)
1209   	httpDumpData(stdout, "httpWrite:", buffer, bytes);
1210 #endif /* DEBUG */
1211 
1212 
1213     if (bytes < 0)
1214     {
1215 #ifdef WIN32
1216       if (WSAGetLastError() != http->error)
1217       {
1218         http->error = WSAGetLastError();
1219 	continue;
1220       }
1221 #else
1222       if (errno == EINTR)
1223         continue;
1224       else if (errno != http->error && errno != ECONNRESET)
1225       {
1226         http->error = errno;
1227 	continue;
1228       }
1229 #endif /* WIN32 */
1230 
1231       DEBUG_puts("httpWrite: error writing data...\n");
1232 
1233       return (-1);
1234     }
1235 
1236     buffer += bytes;
1237     tbytes += bytes;
1238     length -= bytes;
1239     if (http->data_encoding == HTTP_ENCODE_LENGTH)
1240       http->data_remaining -= bytes;
1241   }
1242 
1243   if (http->data_encoding == HTTP_ENCODE_CHUNKED)
1244     if (httpPrintf(http, "\r\n") < 0)
1245       return (-1);
1246 
1247   if (http->data_remaining == 0 && http->data_encoding == HTTP_ENCODE_LENGTH)
1248   {
1249    /*
1250     * Finished with the transfer; unless we are sending POST or PUT
1251     * data, go idle...
1252     */
1253 
1254     DEBUG_printf(("httpWrite: changing states from %d", http->state));
1255 
1256     if (http->state == HTTP_POST_RECV)
1257       http->state ++;
1258     else if (http->state == HTTP_PUT_RECV)
1259       http->state = HTTP_STATUS;
1260     else
1261       http->state = HTTP_WAITING;
1262 
1263     DEBUG_printf((" to %d\n", http->state));
1264   }
1265 
1266   return (tbytes);
1267 }
1268 
1269 
1270 /*
1271  * 'httpGets()' - Get a line of text from a HTTP connection.
1272  */
1273 
1274 char *					/* O - Line or NULL */
httpGets(char * line,int length,http_t * http)1275 httpGets(char   *line,			/* I - Line to read into */
1276          int    length,			/* I - Max length of buffer */
1277 	 http_t *http)			/* I - HTTP data */
1278 {
1279   char	*lineptr,			/* Pointer into line */
1280 	*bufptr,			/* Pointer into input buffer */
1281 	*bufend;			/* Pointer to end of buffer */
1282   int	bytes;				/* Number of bytes read */
1283 
1284 
1285   DEBUG_printf(("httpGets(line=%p, length=%d, http=%p)\n", line, length, http));
1286 
1287   if (http == NULL || line == NULL)
1288     return (NULL);
1289 
1290  /*
1291   * Pre-scan the buffer and see if there is a newline in there...
1292   */
1293 
1294 #ifdef WIN32
1295   WSASetLastError(0);
1296 #else
1297   errno = 0;
1298 #endif /* WIN32 */
1299 
1300   do
1301   {
1302     bufptr  = http->buffer;
1303     bufend  = http->buffer + http->used;
1304 
1305     while (bufptr < bufend)
1306       if (*bufptr == 0x0a)
1307 	break;
1308       else
1309 	bufptr ++;
1310 
1311     if (bufptr >= bufend && http->used < HTTP_MAX_BUFFER)
1312     {
1313      /*
1314       * No newline; see if there is more data to be read...
1315       */
1316 
1317       if (!http->blocking && !http_wait(http, 1000))
1318         return (NULL);
1319 
1320 #ifdef HAVE_SSL
1321       if (http->tls)
1322 	bytes = http_read_ssl(http, bufend, HTTP_MAX_BUFFER - http->used);
1323       else
1324 #endif /* HAVE_SSL */
1325         bytes = recv(http->fd, bufend, HTTP_MAX_BUFFER - http->used, 0);
1326 
1327       DEBUG_printf(("httpGets: read %d bytes...\n", bytes));
1328 #ifdef DEBUG_HTTP
1329       httpDumpData(stdout, "httpGets:", bufend, bytes);
1330 #endif
1331 
1332       if (bytes < 0)
1333       {
1334        /*
1335 	* Nope, can't get a line this time...
1336 	*/
1337 
1338 #ifdef WIN32
1339         if (WSAGetLastError() != http->error)
1340 	{
1341 	  http->error = WSAGetLastError();
1342 	  continue;
1343 	}
1344 
1345         DEBUG_printf(("httpGets: recv() error %d!\n", WSAGetLastError()));
1346 #else
1347         DEBUG_printf(("httpGets: recv() error %d!\n", errno));
1348 
1349         if (errno == EINTR)
1350 	  continue;
1351 	else if (errno != http->error)
1352 	{
1353 	  http->error = errno;
1354 	  continue;
1355 	}
1356 #endif /* WIN32 */
1357 
1358         return (NULL);
1359       }
1360       else if (bytes == 0)
1361       {
1362 	http->error = EPIPE;
1363 
1364         return (NULL);
1365       }
1366 
1367      /*
1368       * Yup, update the amount used and the end pointer...
1369       */
1370 
1371       http->used += bytes;
1372       bufend     += bytes;
1373       bufptr     = bufend;
1374     }
1375   }
1376   while (bufptr >= bufend && http->used < HTTP_MAX_BUFFER);
1377 
1378   http->activity = time(NULL);
1379 
1380  /*
1381   * Read a line from the buffer...
1382   */
1383 
1384   lineptr = line;
1385   bufptr  = http->buffer;
1386   bytes   = 0;
1387   length --;
1388 
1389   while (bufptr < bufend && bytes < length)
1390   {
1391     bytes ++;
1392 
1393     if (*bufptr == 0x0a)
1394     {
1395       bufptr ++;
1396       break;
1397     }
1398     else if (*bufptr == 0x0d)
1399       bufptr ++;
1400     else
1401       *lineptr++ = *bufptr++;
1402   }
1403 
1404   if (bytes > 0)
1405   {
1406     *lineptr = '\0';
1407 
1408     http->used -= bytes;
1409     if (http->used > 0)
1410       memmove(http->buffer, bufptr, http->used);
1411 
1412     DEBUG_printf(("httpGets: Returning \"%s\"\n", line));
1413     return (line);
1414   }
1415 
1416   DEBUG_puts("httpGets: No new line available!");
1417 
1418   return (NULL);
1419 }
1420 
1421 
1422 /*
1423  * 'httpPrintf()' - Print a formatted string to a HTTP connection.
1424  */
1425 
1426 int					/* O - Number of bytes written */
httpPrintf(http_t * http,const char * format,...)1427 httpPrintf(http_t     *http,		/* I - HTTP data */
1428            const char *format,		/* I - printf-style format string */
1429 	   ...)				/* I - Additional args as needed */
1430 {
1431   int		bytes,			/* Number of bytes to write */
1432 		nbytes,			/* Number of bytes written */
1433 		tbytes;			/* Number of bytes all together */
1434   char		buf[HTTP_MAX_BUFFER],	/* Buffer for formatted string */
1435 		*bufptr;		/* Pointer into buffer */
1436   va_list	ap;			/* Variable argument pointer */
1437 
1438 
1439   DEBUG_printf(("httpPrintf: httpPrintf(http=%p, format=\"%s\", ...)\n", http, format));
1440 
1441   va_start(ap, format);
1442   bytes = vsnprintf(buf, sizeof(buf), format, ap);
1443   va_end(ap);
1444 
1445   DEBUG_printf(("httpPrintf: %s", buf));
1446 
1447   for (tbytes = 0, bufptr = buf; tbytes < bytes; tbytes += nbytes, bufptr += nbytes)
1448   {
1449 #ifdef HAVE_SSL
1450     if (http->tls)
1451       nbytes = http_write_ssl(http, bufptr, bytes - tbytes);
1452     else
1453 #endif /* HAVE_SSL */
1454     nbytes = send(http->fd, bufptr, bytes - tbytes, 0);
1455 
1456 #ifdef DEBUG_HTTP
1457     if (nbytes >= 0)
1458     	httpDumpData(stdout, "httpPrintf:", bufptr, nbytes);
1459 #endif
1460 
1461     if (nbytes < 0)
1462     {
1463       nbytes = 0;
1464 
1465 #ifdef WIN32
1466       if (WSAGetLastError() != http->error)
1467       {
1468         http->error = WSAGetLastError();
1469 	continue;
1470       }
1471 #else
1472       if (errno == EINTR)
1473 	continue;
1474       else if (errno != http->error)
1475       {
1476         http->error = errno;
1477 	continue;
1478       }
1479 #endif /* WIN32 */
1480 
1481       return (-1);
1482     }
1483   }
1484 
1485   return (bytes);
1486 }
1487 
1488 
1489 /*
1490  * 'httpGetDateString()' - Get a formatted date/time string from a time value.
1491  */
1492 
1493 const char *				/* O - Date/time string */
httpGetDateString(time_t t)1494 httpGetDateString(time_t t)		/* I - UNIX time */
1495 {
1496   struct tm	*tdate;
1497   static char	datetime[256];
1498 
1499 
1500   tdate = gmtime(&t);
1501   snprintf(datetime, sizeof(datetime), "%s, %02d %s %d %02d:%02d:%02d GMT",
1502            days[tdate->tm_wday], tdate->tm_mday, months[tdate->tm_mon],
1503 	   tdate->tm_year + 1900, tdate->tm_hour, tdate->tm_min, tdate->tm_sec);
1504 
1505   return (datetime);
1506 }
1507 
1508 
1509 /*
1510  * 'httpGetDateTime()' - Get a time value from a formatted date/time string.
1511  */
1512 
1513 time_t					/* O - UNIX time */
httpGetDateTime(const char * s)1514 httpGetDateTime(const char *s)		/* I - Date/time string */
1515 {
1516   int		i;			/* Looping var */
1517   struct tm	tdate;			/* Time/date structure */
1518   char		mon[16];		/* Abbreviated month name */
1519   int		day, year;		/* Day of month and year */
1520   int		hour, min, sec;		/* Time */
1521 
1522 
1523   if (sscanf(s, "%*s%d%15s%d%d:%d:%d", &day, mon, &year, &hour, &min, &sec) < 6)
1524     return (0);
1525 
1526   for (i = 0; i < 12; i ++)
1527     if (strcasecmp(mon, months[i]) == 0)
1528       break;
1529 
1530   if (i >= 12)
1531     return (0);
1532 
1533   tdate.tm_mon   = i;
1534   tdate.tm_mday  = day;
1535   tdate.tm_year  = year - 1900;
1536   tdate.tm_hour  = hour;
1537   tdate.tm_min   = min;
1538   tdate.tm_sec   = sec;
1539   tdate.tm_isdst = 0;
1540 
1541   return (mktime(&tdate));
1542 }
1543 
1544 
1545 /*
1546  * 'httpUpdate()' - Update the current HTTP state for incoming data.
1547  */
1548 
1549 http_status_t				/* O - HTTP status */
httpUpdate(http_t * http)1550 httpUpdate(http_t *http)		/* I - HTTP data */
1551 {
1552   char		line[1024],		/* Line from connection... */
1553 		*value;			/* Pointer to value on line */
1554   http_field_t	field;			/* Field index */
1555   int		major, minor,		/* HTTP version numbers */
1556 		status;			/* Request status */
1557 
1558 
1559   DEBUG_printf(("httpUpdate(http=%p), state=%d\n", http, http->state));
1560 
1561  /*
1562   * If we haven't issued any commands, then there is nothing to "update"...
1563   */
1564 
1565   if (http->state == HTTP_WAITING)
1566     return (HTTP_CONTINUE);
1567 
1568  /*
1569   * Grab all of the lines we can from the connection...
1570   */
1571 
1572   line[0] = '\0';
1573   while (httpGets(line, sizeof(line), http) != NULL)
1574   {
1575     DEBUG_printf(("httpUpdate: Got \"%s\"\n", line));
1576 
1577     if (line[0] == '\0')
1578     {
1579      /*
1580       * Blank line means the start of the data section (if any).  Return
1581       * the result code, too...
1582       *
1583       * If we get status 100 (HTTP_CONTINUE), then we *don't* change states.
1584       * Instead, we just return HTTP_CONTINUE to the caller and keep on
1585       * tryin'...
1586       */
1587 
1588       if (http->status == HTTP_CONTINUE)
1589         return (http->status);
1590 
1591       if (http->status < HTTP_BAD_REQUEST)
1592         http->digest_tries = 0;
1593 
1594 #ifdef HAVE_SSL
1595       if (http->status == HTTP_SWITCHING_PROTOCOLS && !http->tls)
1596       {
1597 	if (http_setup_ssl(http) != 0)
1598 	{
1599 #  ifdef WIN32
1600 	  closesocket(http->fd);
1601 #  else
1602 	  close(http->fd);
1603 #  endif /* WIN32 */
1604 
1605 	  return (HTTP_ERROR);
1606 	}
1607 
1608         return (HTTP_CONTINUE);
1609       }
1610 #endif /* HAVE_SSL */
1611 
1612       httpGetLength(http);
1613 
1614       switch (http->state)
1615       {
1616         case HTTP_GET :
1617 	case HTTP_POST :
1618 	case HTTP_POST_RECV :
1619 	case HTTP_PUT :
1620 	    http->state ++;
1621 	case HTTP_POST_SEND :
1622 	    break;
1623 
1624 	default :
1625 	    http->state = HTTP_WAITING;
1626 	    break;
1627       }
1628 
1629       return (http->status);
1630     }
1631     else if (strncmp(line, "HTTP/", 5) == 0)
1632     {
1633      /*
1634       * Got the beginning of a response...
1635       */
1636 
1637       if (sscanf(line, "HTTP/%d.%d%d", &major, &minor, &status) != 3)
1638         return (HTTP_ERROR);
1639 
1640       http->version = (http_version_t)(major * 100 + minor);
1641       http->status  = (http_status_t)status;
1642     }
1643     else if ((value = strchr(line, ':')) != NULL)
1644     {
1645      /*
1646       * Got a value...
1647       */
1648 
1649       *value++ = '\0';
1650       while (isspace(*value & 255))
1651         value ++;
1652 
1653      /*
1654       * Be tolerants of servers that send unknown attribute fields...
1655       */
1656 
1657       if (!strcasecmp(line, "expect"))
1658       {
1659        /*
1660         * "Expect: 100-continue" or similar...
1661 	*/
1662 
1663         http->expect = (http_status_t)atoi(value);
1664       }
1665       else if (!strcasecmp(line, "cookie"))
1666       {
1667        /*
1668         * "Cookie: name=value[; name=value ...]" - replaces previous cookies...
1669 	*/
1670 
1671         httpSetCookie(http, value);
1672       }
1673       else if ((field = http_field(line)) == HTTP_FIELD_UNKNOWN)
1674       {
1675         DEBUG_printf(("httpUpdate: unknown field %s seen!\n", line));
1676         continue;
1677       }
1678       else
1679         httpSetField(http, field, value);
1680     }
1681     else
1682     {
1683       http->status = HTTP_ERROR;
1684       return (HTTP_ERROR);
1685     }
1686   }
1687 
1688  /*
1689   * See if there was an error...
1690   */
1691 
1692   if (http->error == EPIPE && http->status > HTTP_CONTINUE)
1693     return (http->status);
1694 
1695   if (http->error)
1696   {
1697     DEBUG_printf(("httpUpdate: socket error %d - %s\n", http->error,
1698                   strerror(http->error)));
1699     http->status = HTTP_ERROR;
1700     return (HTTP_ERROR);
1701   }
1702 
1703  /*
1704   * If we haven't already returned, then there is nothing new...
1705   */
1706 
1707   return (HTTP_CONTINUE);
1708 }
1709 
1710 
1711 /*
1712  * 'httpDecode64()' - Base64-decode a string.
1713  */
1714 
1715 char *					/* O - Decoded string */
httpDecode64(char * out,const char * in)1716 httpDecode64(char       *out,		/* I - String to write to */
1717              const char *in)		/* I - String to read from */
1718 {
1719   int	outlen;				/* Output buffer length */
1720 
1721 
1722  /*
1723   * Use the old maximum buffer size for binary compatibility...
1724   */
1725 
1726   outlen = 512;
1727 
1728   return (httpDecode64_2(out, &outlen, in));
1729 }
1730 
1731 
1732 /*
1733  * 'httpDecode64_2()' - Base64-decode a string.
1734  */
1735 
1736 char *					/* O  - Decoded string */
httpDecode64_2(char * out,int * outlen,const char * in)1737 httpDecode64_2(char       *out,		/* I  - String to write to */
1738 	       int        *outlen,	/* IO - Size of output string */
1739                const char *in)		/* I  - String to read from */
1740 {
1741   int	pos,				/* Bit position */
1742 	base64;				/* Value of this character */
1743   char	*outptr,			/* Output pointer */
1744 	*outend;			/* End of output buffer */
1745 
1746 
1747  /*
1748   * Range check input...
1749   */
1750 
1751   if (!out || !outlen || *outlen < 1 || !in || !*in)
1752     return (NULL);
1753 
1754  /*
1755   * Convert from base-64 to bytes...
1756   */
1757 
1758   for (outptr = out, outend = out + *outlen - 1, pos = 0; *in != '\0'; in ++)
1759   {
1760    /*
1761     * Decode this character into a number from 0 to 63...
1762     */
1763 
1764     if (*in >= 'A' && *in <= 'Z')
1765       base64 = *in - 'A';
1766     else if (*in >= 'a' && *in <= 'z')
1767       base64 = *in - 'a' + 26;
1768     else if (*in >= '0' && *in <= '9')
1769       base64 = *in - '0' + 52;
1770     else if (*in == '+')
1771       base64 = 62;
1772     else if (*in == '/')
1773       base64 = 63;
1774     else if (*in == '=')
1775       break;
1776     else
1777       continue;
1778 
1779    /*
1780     * Store the result in the appropriate chars...
1781     */
1782 
1783     switch (pos)
1784     {
1785       case 0 :
1786           if (outptr < outend)
1787             *outptr = base64 << 2;
1788 	  pos ++;
1789 	  break;
1790       case 1 :
1791           if (outptr < outend)
1792             *outptr++ |= (base64 >> 4) & 3;
1793           if (outptr < outend)
1794 	    *outptr = (base64 << 4) & 255;
1795 	  pos ++;
1796 	  break;
1797       case 2 :
1798           if (outptr < outend)
1799             *outptr++ |= (base64 >> 2) & 15;
1800           if (outptr < outend)
1801 	    *outptr = (base64 << 6) & 255;
1802 	  pos ++;
1803 	  break;
1804       case 3 :
1805           if (outptr < outend)
1806             *outptr++ |= base64;
1807 	  pos = 0;
1808 	  break;
1809     }
1810   }
1811 
1812   *outptr = '\0';
1813 
1814  /*
1815   * Return the decoded string and size...
1816   */
1817 
1818   *outlen = (int)(outptr - out);
1819 
1820   return (out);
1821 }
1822 
1823 
1824 /*
1825  * 'httpEncode64()' - Base64-encode a string.
1826  */
1827 
1828 char *					/* O - Encoded string */
httpEncode64(char * out,const char * in)1829 httpEncode64(char       *out,		/* I - String to write to */
1830              const char *in)		/* I - String to read from */
1831 {
1832   return (httpEncode64_2(out, 512, in, strlen(in)));
1833 }
1834 
1835 
1836 /*
1837  * 'httpEncode64_2()' - Base64-encode a string.
1838  */
1839 
1840 char *					/* O - Encoded string */
httpEncode64_2(char * out,int outlen,const char * in,int inlen)1841 httpEncode64_2(char       *out,		/* I - String to write to */
1842 	       int        outlen,	/* I - Size of output string */
1843                const char *in,		/* I - String to read from */
1844 	       int        inlen)	/* I - Size of input string */
1845 {
1846   char		*outptr,		/* Output pointer */
1847 		*outend;		/* End of output buffer */
1848   static const char base64[] =		/* Base64 characters... */
1849   		{
1850 		  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1851 		  "abcdefghijklmnopqrstuvwxyz"
1852 		  "0123456789"
1853 		  "+/"
1854   		};
1855 
1856 
1857  /*
1858   * Range check input...
1859   */
1860 
1861   if (!out || outlen < 1 || !in || inlen < 1)
1862     return (NULL);
1863 
1864  /*
1865   * Convert bytes to base-64...
1866   */
1867 
1868   for (outptr = out, outend = out + outlen - 1; inlen > 0; in ++, inlen --)
1869   {
1870    /*
1871     * Encode the up to 3 characters as 4 Base64 numbers...
1872     */
1873 
1874     if (outptr < outend)
1875       *outptr ++ = base64[(in[0] & 255) >> 2];
1876     if (outptr < outend)
1877       *outptr ++ = base64[(((in[0] & 255) << 4) | ((in[1] & 255) >> 4)) & 63];
1878 
1879     in ++;
1880     inlen --;
1881     if (inlen <= 0)
1882     {
1883       if (outptr < outend)
1884         *outptr ++ = '=';
1885       if (outptr < outend)
1886         *outptr ++ = '=';
1887       break;
1888     }
1889 
1890     if (outptr < outend)
1891       *outptr ++ = base64[(((in[0] & 255) << 2) | ((in[1] & 255) >> 6)) & 63];
1892 
1893     in ++;
1894     inlen --;
1895     if (inlen <= 0)
1896     {
1897       if (outptr < outend)
1898         *outptr ++ = '=';
1899       break;
1900     }
1901 
1902     if (outptr < outend)
1903       *outptr ++ = base64[in[0] & 63];
1904   }
1905 
1906   *outptr = '\0';
1907 
1908  /*
1909   * Return the encoded string...
1910   */
1911 
1912   return (out);
1913 }
1914 
1915 
1916 /*
1917  * 'httpGetLength()' - Get the amount of data remaining from the
1918  *                     content-length or transfer-encoding fields.
1919  */
1920 
1921 int				/* O - Content length */
httpGetLength(http_t * http)1922 httpGetLength(http_t *http)	/* I - HTTP data */
1923 {
1924   DEBUG_printf(("httpGetLength(http=%p), state=%d\n", http, http->state));
1925 
1926   if (strcasecmp(http->fields[HTTP_FIELD_TRANSFER_ENCODING], "chunked") == 0)
1927   {
1928     DEBUG_puts("httpGetLength: chunked request!");
1929 
1930     http->data_encoding  = HTTP_ENCODE_CHUNKED;
1931     http->data_remaining = 0;
1932   }
1933   else
1934   {
1935     http->data_encoding = HTTP_ENCODE_LENGTH;
1936 
1937    /*
1938     * The following is a hack for HTTP servers that don't send a
1939     * content-length or transfer-encoding field...
1940     *
1941     * If there is no content-length then the connection must close
1942     * after the transfer is complete...
1943     */
1944 
1945     if (http->fields[HTTP_FIELD_CONTENT_LENGTH][0] == '\0')
1946       http->data_remaining = 2147483647;
1947     else
1948       http->data_remaining = atoi(http->fields[HTTP_FIELD_CONTENT_LENGTH]);
1949 
1950     DEBUG_printf(("httpGetLength: content_length=%d\n", http->data_remaining));
1951   }
1952 
1953   return (http->data_remaining);
1954 }
1955 
1956 
1957 /*
1958  * 'http_field()' - Return the field index for a field name.
1959  */
1960 
1961 static http_field_t		/* O - Field index */
http_field(const char * name)1962 http_field(const char *name)	/* I - String name */
1963 {
1964   int	i;			/* Looping var */
1965 
1966 
1967   for (i = 0; i < HTTP_FIELD_MAX; i ++)
1968     if (strcasecmp(name, http_fields[i]) == 0)
1969       return ((http_field_t)i);
1970 
1971   return (HTTP_FIELD_UNKNOWN);
1972 }
1973 
1974 
1975 /*
1976  * 'http_send()' - Send a request with all fields and the trailing blank line.
1977  */
1978 
1979 static int			/* O - 0 on success, non-zero on error */
http_send(http_t * http,http_state_t request,const char * uri)1980 http_send(http_t       *http,	/* I - HTTP data */
1981           http_state_t request,	/* I - Request code */
1982 	  const char   *uri)	/* I - URI */
1983 {
1984   int		i;		/* Looping var */
1985   char		*ptr,		/* Pointer in buffer */
1986 		buf[1024];	/* Encoded URI buffer */
1987   static const char * const codes[] =
1988 		{		/* Request code strings */
1989 		  NULL,
1990 		  "OPTIONS",
1991 		  "GET",
1992 		  NULL,
1993 		  "HEAD",
1994 		  "POST",
1995 		  NULL,
1996 		  NULL,
1997 		  "PUT",
1998 		  NULL,
1999 		  "DELETE",
2000 		  "TRACE",
2001 		  "CLOSE"
2002 		};
2003   static const char hex[] = "0123456789ABCDEF";
2004 				/* Hex digits */
2005 
2006 
2007   DEBUG_printf(("http_send(http=%p, request=HTTP_%s, uri=\"%s\")\n",
2008                 http, codes[request], uri));
2009 
2010   if (http == NULL || uri == NULL)
2011     return (-1);
2012 
2013  /*
2014   * Encode the URI as needed...
2015   */
2016 
2017   for (ptr = buf; *uri != '\0' && ptr < (buf + sizeof(buf) - 1); uri ++)
2018     if (*uri <= ' ' || *uri >= 127)
2019     {
2020       if (ptr < (buf + sizeof(buf) - 1))
2021         *ptr ++ = '%';
2022       if (ptr < (buf + sizeof(buf) - 1))
2023         *ptr ++ = hex[(*uri >> 4) & 15];
2024       if (ptr < (buf + sizeof(buf) - 1))
2025         *ptr ++ = hex[*uri & 15];
2026     }
2027     else
2028       *ptr ++ = *uri;
2029 
2030   *ptr = '\0';
2031 
2032  /*
2033   * See if we had an error the last time around; if so, reconnect...
2034   */
2035 
2036   if (http->status == HTTP_ERROR || http->status >= HTTP_BAD_REQUEST)
2037     httpReconnect(http);
2038 
2039  /*
2040   * Send the request header...
2041   */
2042 
2043   http->state = request;
2044   if (request == HTTP_POST || request == HTTP_PUT)
2045     http->state ++;
2046 
2047   http->status = HTTP_CONTINUE;
2048 
2049 #ifdef HAVE_SSL
2050   if (http->encryption == HTTP_ENCRYPT_REQUIRED && !http->tls)
2051   {
2052     httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade");
2053     httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.0,SSL/2.0,SSL/3.0");
2054   }
2055 #endif /* HAVE_SSL */
2056 
2057   if (httpPrintf(http, "%s %s HTTP/1.1\r\n", codes[request], buf) < 1)
2058   {
2059     http->status = HTTP_ERROR;
2060     return (-1);
2061   }
2062 
2063   for (i = 0; i < HTTP_FIELD_MAX; i ++)
2064     if (http->fields[i][0] != '\0')
2065     {
2066       DEBUG_printf(("%s: %s\n", http_fields[i], http->fields[i]));
2067 
2068       if (httpPrintf(http, "%s: %s\r\n", http_fields[i], http->fields[i]) < 1)
2069       {
2070 	http->status = HTTP_ERROR;
2071 	return (-1);
2072       }
2073     }
2074 
2075   if (httpPrintf(http, "\r\n") < 1)
2076   {
2077     http->status = HTTP_ERROR;
2078     return (-1);
2079   }
2080 
2081   httpClearFields(http);
2082 
2083   return (0);
2084 }
2085 
2086 
2087 /*
2088  * 'http_wait()' - Wait for data available on a connection.
2089  */
2090 
2091 static int				/* O - 1 if data is available, 0 otherwise */
http_wait(http_t * http,int msec)2092 http_wait(http_t *http,			/* I - HTTP data */
2093           int    msec)			/* I - Milliseconds to wait */
2094 {
2095 #ifndef WIN32
2096   struct rlimit		limit;          /* Runtime limit */
2097 #endif /* !WIN32 */
2098   struct timeval	timeout;	/* Timeout */
2099   int			nfds;		/* Result from select() */
2100   int			set_size;	/* Size of select set */
2101 
2102 
2103   DEBUG_printf(("http_wait(http=%p, msec=%d)\n", http, msec));
2104 
2105  /*
2106   * Check the SSL/TLS buffers for data first...
2107   */
2108 
2109 #ifdef HAVE_SSL
2110   if (http->tls)
2111   {
2112 #  ifdef HAVE_LIBSSL
2113     if (SSL_pending((SSL *)(http->tls)))
2114       return (1);
2115 #  elif defined(HAVE_GNUTLS)
2116     if (gnutls_record_check_pending(((http_tls_t *)(http->tls))->session))
2117       return (1);
2118 #  elif defined(HAVE_CDSASSL)
2119     size_t bytes;			/* Bytes that are available */
2120 
2121     if (!SSLGetBufferedReadSize((SSLContextRef)http->tls, &bytes) && bytes > 0)
2122       return;
2123 #  endif /* HAVE_LIBSSL */
2124   }
2125 #endif /* HAVE_SSL */
2126 
2127  /*
2128   * Then try doing a select() to poll the socket...
2129   */
2130 
2131   if (!http->input_set)
2132   {
2133 #ifdef WIN32
2134    /*
2135     * Windows has a fixed-size select() structure, different (surprise,
2136     * surprise!) from all UNIX implementations.  Just allocate this
2137     * fixed structure...
2138     */
2139 
2140     http->input_set = calloc(1, sizeof(fd_set));
2141 #else
2142    /*
2143     * Allocate the select() input set based upon the max number of file
2144     * descriptors available for this process...
2145     */
2146 
2147     getrlimit(RLIMIT_NOFILE, &limit);
2148 
2149     set_size = (limit.rlim_cur + 31) / 8 + 4;
2150     if (set_size < sizeof(fd_set))
2151       set_size = sizeof(fd_set);
2152 
2153     http->input_set = calloc(1, set_size);
2154 #endif /* WIN32 */
2155 
2156     if (!http->input_set)
2157       return (0);
2158   }
2159 
2160   do
2161   {
2162     FD_SET(http->fd, http->input_set);
2163 
2164     if (msec >= 0)
2165     {
2166       timeout.tv_sec  = msec / 1000;
2167       timeout.tv_usec = (msec % 1000) * 1000;
2168 
2169       nfds = select(http->fd + 1, http->input_set, NULL, NULL, &timeout);
2170     }
2171     else
2172       nfds = select(http->fd + 1, http->input_set, NULL, NULL, NULL);
2173   }
2174 #ifdef WIN32
2175   while (nfds < 0 && WSAGetLastError() == WSAEINTR);
2176 #else
2177   while (nfds < 0 && errno == EINTR);
2178 #endif /* WIN32 */
2179 
2180   FD_CLR(http->fd, http->input_set);
2181 
2182   return (nfds > 0);
2183 }
2184 
2185 
2186 #ifdef HAVE_SSL
2187 /*
2188  * 'http_upgrade()' - Force upgrade to TLS encryption.
2189  */
2190 
2191 static int			/* O - Status of connection */
http_upgrade(http_t * http)2192 http_upgrade(http_t *http)	/* I - HTTP data */
2193 {
2194   int		ret;		/* Return value */
2195   http_t	myhttp;		/* Local copy of HTTP data */
2196 
2197 
2198   DEBUG_printf(("http_upgrade(%p)\n", http));
2199 
2200  /*
2201   * Copy the HTTP data to a local variable so we can do the OPTIONS
2202   * request without interfering with the existing request data...
2203   */
2204 
2205   memcpy(&myhttp, http, sizeof(myhttp));
2206 
2207  /*
2208   * Send an OPTIONS request to the server, requiring SSL or TLS
2209   * encryption on the link...
2210   */
2211 
2212   httpClearFields(&myhttp);
2213   httpSetField(&myhttp, HTTP_FIELD_CONNECTION, "upgrade");
2214   httpSetField(&myhttp, HTTP_FIELD_UPGRADE, "TLS/1.0, SSL/2.0, SSL/3.0");
2215 
2216   if ((ret = httpOptions(&myhttp, "*")) == 0)
2217   {
2218    /*
2219     * Wait for the secure connection...
2220     */
2221 
2222     while (httpUpdate(&myhttp) == HTTP_CONTINUE);
2223   }
2224 
2225   httpFlush(&myhttp);
2226 
2227  /*
2228   * Copy the HTTP data back over, if any...
2229   */
2230 
2231   http->fd         = myhttp.fd;
2232   http->error      = myhttp.error;
2233   http->activity   = myhttp.activity;
2234   http->status     = myhttp.status;
2235   http->version    = myhttp.version;
2236   http->keep_alive = myhttp.keep_alive;
2237   http->used       = myhttp.used;
2238 
2239   if (http->used)
2240     memcpy(http->buffer, myhttp.buffer, http->used);
2241 
2242   http->auth_type   = myhttp.auth_type;
2243   http->nonce_count = myhttp.nonce_count;
2244 
2245   memcpy(http->nonce, myhttp.nonce, sizeof(http->nonce));
2246 
2247   http->tls        = myhttp.tls;
2248   http->encryption = myhttp.encryption;
2249 
2250  /*
2251   * See if we actually went secure...
2252   */
2253 
2254   if (!http->tls)
2255   {
2256    /*
2257     * Server does not support HTTP upgrade...
2258     */
2259 
2260     DEBUG_puts("Server does not support HTTP upgrade!");
2261 
2262 #  ifdef WIN32
2263     closesocket(http->fd);
2264 #  else
2265     close(http->fd);
2266 #  endif
2267 
2268     http->fd = -1;
2269 
2270     return (-1);
2271   }
2272   else
2273     return (ret);
2274 }
2275 
2276 
2277 /*
2278  * 'http_setup_ssl()' - Set up SSL/TLS support on a connection.
2279  */
2280 
2281 static int				/* O - Status of connection */
http_setup_ssl(http_t * http)2282 http_setup_ssl(http_t *http)		/* I - HTTP data */
2283 {
2284 #  ifdef HAVE_LIBSSL
2285   SSL_CTX	*context;	/* Context for encryption */
2286   SSL		*conn;		/* Connection for encryption */
2287 #  elif defined(HAVE_GNUTLS)
2288   http_tls_t	*conn;		/* TLS session object */
2289   gnutls_certificate_client_credentials *credentials;
2290 				/* TLS credentials */
2291 #  elif defined(HAVE_CDSASSL)
2292   SSLContextRef	conn;		/* Context for encryption */
2293   OSStatus	error;		/* Error info */
2294 #  endif /* HAVE_LIBSSL */
2295 
2296 
2297   DEBUG_printf(("http_setup_ssl(http=%p)\n", http));
2298 
2299 #  ifdef HAVE_LIBSSL
2300   context = SSL_CTX_new(SSLv23_client_method());
2301 
2302   SSL_CTX_set_options(context, SSL_OP_NO_SSLv2); /* Only use SSLv3 or TLS */
2303 
2304   conn = SSL_new(context);
2305 
2306   SSL_set_fd(conn, http->fd);
2307   if (SSL_connect(conn) != 1)
2308   {
2309 #    ifdef DEBUG
2310     unsigned long	error;	/* Error code */
2311 
2312     while ((error = ERR_get_error()) != 0)
2313       printf("http_setup_ssl: %s\n", ERR_error_string(error, NULL));
2314 #    endif /* DEBUG */
2315 
2316     SSL_CTX_free(context);
2317     SSL_free(conn);
2318 
2319 #    ifdef WIN32
2320     http->error  = WSAGetLastError();
2321 #    else
2322     http->error  = errno;
2323 #    endif /* WIN32 */
2324     http->status = HTTP_ERROR;
2325 
2326     return (HTTP_ERROR);
2327   }
2328 
2329 #  elif defined(HAVE_GNUTLS)
2330   conn = (http_tls_t *)malloc(sizeof(http_tls_t));
2331 
2332   if (conn == NULL)
2333   {
2334     http->error  = errno;
2335     http->status = HTTP_ERROR;
2336 
2337     return (-1);
2338   }
2339 
2340   credentials = (gnutls_certificate_client_credentials *)
2341                     malloc(sizeof(gnutls_certificate_client_credentials));
2342   if (credentials == NULL)
2343   {
2344     free(conn);
2345 
2346     http->error = errno;
2347     http->status = HTTP_ERROR;
2348 
2349     return (-1);
2350   }
2351 
2352   gnutls_certificate_allocate_credentials(credentials);
2353 
2354   gnutls_init(&(conn->session), GNUTLS_CLIENT);
2355   gnutls_set_default_priority(conn->session);
2356   gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE, *credentials);
2357   gnutls_transport_set_ptr(conn->session, http->fd);
2358 
2359   if ((gnutls_handshake(conn->session)) != GNUTLS_E_SUCCESS)
2360   {
2361     http->error  = errno;
2362     http->status = HTTP_ERROR;
2363 
2364     return (-1);
2365   }
2366 
2367   conn->credentials = credentials;
2368 
2369 #  elif defined(HAVE_CDSASSL)
2370   error = SSLNewContext(false, &conn);
2371 
2372   if (!error)
2373     error = SSLSetIOFuncs(conn, CDSAReadFunc, CDSAWriteFunc);
2374 
2375   if (!error)
2376     error = SSLSetConnection(conn, (SSLConnectionRef)http->fd);
2377 
2378   if (!error)
2379     error = SSLSetAllowsExpiredCerts(conn, true);
2380 
2381   if (!error)
2382     error = SSLSetAllowsAnyRoot(conn, true);
2383 
2384   if (!error)
2385     error = SSLHandshake(conn);
2386 
2387   if (error != 0)
2388   {
2389     http->error  = error;
2390     http->status = HTTP_ERROR;
2391 
2392     SSLDisposeContext(conn);
2393 
2394     close(http->fd);
2395 
2396     return (-1);
2397   }
2398 #  endif /* HAVE_CDSASSL */
2399 
2400   http->tls = conn;
2401   return (0);
2402 }
2403 
2404 
2405 /*
2406  * 'http_shutdown_ssl()' - Shut down SSL/TLS on a connection.
2407  */
2408 
2409 static void
http_shutdown_ssl(http_t * http)2410 http_shutdown_ssl(http_t *http)	/* I - HTTP data */
2411 {
2412 #  ifdef HAVE_LIBSSL
2413   SSL_CTX	*context;	/* Context for encryption */
2414   SSL		*conn;		/* Connection for encryption */
2415 
2416 
2417   conn    = (SSL *)(http->tls);
2418   context = SSL_get_SSL_CTX(conn);
2419 
2420   SSL_shutdown(conn);
2421   SSL_CTX_free(context);
2422   SSL_free(conn);
2423 
2424 #  elif defined(HAVE_GNUTLS)
2425   http_tls_t      *conn;	/* Encryption session */
2426   gnutls_certificate_client_credentials *credentials;
2427 				/* TLS credentials */
2428 
2429 
2430   conn = (http_tls_t *)(http->tls);
2431   credentials = (gnutls_certificate_client_credentials *)(conn->credentials);
2432 
2433   gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
2434   gnutls_deinit(conn->session);
2435   gnutls_certificate_free_credentials(*credentials);
2436   free(credentials);
2437   free(conn);
2438 
2439 #  elif defined(HAVE_CDSASSL)
2440   SSLClose((SSLContextRef)http->tls);
2441   SSLDisposeContext((SSLContextRef)http->tls);
2442 #  endif /* HAVE_LIBSSL */
2443 
2444   http->tls = NULL;
2445 }
2446 
2447 
2448 /*
2449  * 'http_read_ssl()' - Read from a SSL/TLS connection.
2450  */
2451 
2452 static int				/* O - Bytes read */
http_read_ssl(http_t * http,char * buf,int len)2453 http_read_ssl(http_t *http,		/* I - HTTP data */
2454 	      char   *buf,		/* I - Buffer to store data */
2455 	      int    len)		/* I - Length of buffer */
2456 {
2457 #  if defined(HAVE_LIBSSL)
2458   return (SSL_read((SSL *)(http->tls), buf, len));
2459 
2460 #  elif defined(HAVE_GNUTLS)
2461   return (gnutls_record_recv(((http_tls_t *)(http->tls))->session, buf, len));
2462 
2463 #  elif defined(HAVE_CDSASSL)
2464   OSStatus	error;			/* Error info */
2465   size_t	processed;		/* Number of bytes processed */
2466 
2467 
2468   error = SSLRead((SSLContextRef)http->tls, buf, len, &processed);
2469 
2470   if (error == 0)
2471     return (processed);
2472   else
2473   {
2474     http->error = error;
2475 
2476     return (-1);
2477   }
2478 #  endif /* HAVE_LIBSSL */
2479 }
2480 
2481 
2482 /*
2483  * 'http_write_ssl()' - Write to a SSL/TLS connection.
2484  */
2485 
2486 static int				/* O - Bytes written */
http_write_ssl(http_t * http,const char * buf,int len)2487 http_write_ssl(http_t     *http,	/* I - HTTP data */
2488 	       const char *buf,		/* I - Buffer holding data */
2489 	       int        len)		/* I - Length of buffer */
2490 {
2491 #  if defined(HAVE_LIBSSL)
2492   return (SSL_write((SSL *)(http->tls), buf, len));
2493 
2494 #  elif defined(HAVE_GNUTLS)
2495   return (gnutls_record_send(((http_tls_t *)(http->tls))->session, buf, len));
2496 #  elif defined(HAVE_CDSASSL)
2497   OSStatus	error;			/* Error info */
2498   size_t	processed;		/* Number of bytes processed */
2499 
2500 
2501   error = SSLWrite((SSLContextRef)http->tls, buf, len, &processed);
2502 
2503   if (error == 0)
2504     return (processed);
2505   else
2506   {
2507     http->error = error;
2508     return (-1);
2509   }
2510 #  endif /* HAVE_LIBSSL */
2511 }
2512 
2513 
2514 #  if defined(HAVE_CDSASSL)
2515 /*
2516  * 'CDSAReadFunc()' - Read function for CDSA decryption code.
2517  */
2518 
2519 static OSStatus					/* O  - -1 on error, 0 on success */
CDSAReadFunc(SSLConnectionRef connection,void * data,size_t * dataLength)2520 CDSAReadFunc(SSLConnectionRef connection,	/* I  - SSL/TLS connection */
2521              void             *data,		/* I  - Data buffer */
2522 	     size_t           *dataLength)	/* IO - Number of bytes */
2523 {
2524   ssize_t	bytes;				/* Number of bytes read */
2525 
2526 #ifdef DEBUG_HTTP
2527   httpDumpData(stdout, "CDSAReadFunc:", data, *dataLength);
2528 #endif
2529   bytes = recv((int)connection, data, *dataLength, 0);
2530   if (bytes >= 0)
2531   {
2532     *dataLength = bytes;
2533     return (0);
2534   }
2535   else
2536     return (-1);
2537 }
2538 
2539 
2540 /*
2541  * 'CDSAWriteFunc()' - Write function for CDSA encryption code.
2542  */
2543 
2544 static OSStatus					/* O  - -1 on error, 0 on success */
CDSAWriteFunc(SSLConnectionRef connection,const void * data,size_t * dataLength)2545 CDSAWriteFunc(SSLConnectionRef connection,	/* I  - SSL/TLS connection */
2546               const void       *data,		/* I  - Data buffer */
2547 	      size_t           *dataLength)	/* IO - Number of bytes */
2548 {
2549   ssize_t bytes;
2550 
2551 
2552   bytes = write((int)connection, data, *dataLength);
2553   if (bytes >= 0)
2554   {
2555     *dataLength = bytes;
2556     return (0);
2557   }
2558   else
2559     return (-1);
2560 }
2561 #  endif /* HAVE_CDSASSL */
2562 #endif /* HAVE_SSL */
2563 
2564 
2565 /*
2566  * End of "$Id: http.c 148 2006-04-25 16:54:17Z njacobs $"
2567  */
2568