1 /*
2  *  Copyright 2016-2018 Fiona Klute
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  */
16 
17 #include "gnutls_util.h"
18 
19 #include <apr_strings.h>
20 #include <gnutls/gnutls.h>
21 
22 
http_post_header(apr_pool_t * p,apr_uri_t * uri,const char * content_type,const char * accept,apr_size_t size)23 const char* http_post_header(apr_pool_t *p, apr_uri_t *uri,
24                              const char *content_type, const char *accept,
25                              apr_size_t size)
26 {
27     return apr_psprintf(p, "POST %s HTTP/1.0\r\n"
28                         "Host: %s\r\n"
29                         "Content-Type: %s\r\n"
30                         "Accept: %s\r\n"
31                         "Content-Length: %" APR_SIZE_T_FMT "\r\n\r\n",
32                         apr_uri_unparse(p, uri, APR_URI_UNP_OMITSITEPART),
33                         uri->hostname, content_type,
34                         accept != NULL ? accept : "*/*",
35                         size);
36 }
37 
38 
39 
sock_send_buf(apr_socket_t * sock,const char * buf,const apr_size_t size)40 apr_status_t sock_send_buf(apr_socket_t *sock, const char *buf,
41                            const apr_size_t size)
42 {
43     apr_status_t rv = APR_EINIT;
44     apr_size_t len = 0;
45     for (apr_size_t sent = 0; sent < size; sent += len)
46     {
47         len = size - sent;
48         rv = apr_socket_send(sock, buf + sent, &len);
49         /* API documentation for apr_socket_send(): "It is possible
50          * for both bytes to be sent and an error to be returned."
51          *
52          * So break if there was an error, unless bytes were also
53          * sent. In the latter case try to continue. */
54         if (rv != APR_SUCCESS && len == 0)
55             break;
56     }
57     return rv;
58 }
59 
60 
61 
read_line(apr_pool_t * p,apr_bucket_brigade * sockb,apr_bucket_brigade * lineb)62 const char* read_line(apr_pool_t *p, apr_bucket_brigade *sockb,
63                       apr_bucket_brigade *lineb)
64 {
65     apr_brigade_cleanup(lineb);
66     apr_status_t rv = apr_brigade_split_line(lineb, sockb,
67                                              APR_BLOCK_READ,
68                                              HTTP_HDR_LINE_MAX);
69     if (rv != APR_SUCCESS)
70         return NULL;
71 
72     char *line;
73     apr_size_t len;
74     rv = apr_brigade_pflatten(lineb, &line, &len, p);
75     if (rv != APR_SUCCESS)
76         return NULL;
77 
78     /* The last two characters on a correct header line are
79      * "\r\n". Switch \r to \0 to chomp off the line break. */
80     if (len >= 2 && line[len-1] == '\n' && line[len-2] == '\r')
81     {
82         line[len-2] = '\0';
83         return line;
84     }
85     else
86         return NULL;
87 }
88 
89 
90 
datum_from_file(apr_pool_t * p,const char * filename,gnutls_datum_t * datum)91 apr_status_t datum_from_file(apr_pool_t *p, const char* filename,
92                              gnutls_datum_t *datum)
93 {
94     apr_status_t rv = APR_EINIT;
95     apr_file_t *file;
96     apr_finfo_t finfo;
97     apr_size_t br = 0;
98     rv = apr_file_open(&file, filename,
99                        APR_READ | APR_BINARY, APR_OS_DEFAULT, p);
100     if (rv != APR_SUCCESS)
101         return rv;
102 
103     rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, file);
104     if (rv != APR_SUCCESS)
105         return rv;
106 
107     datum->data = apr_palloc(p, finfo.size);
108     rv = apr_file_read_full(file, datum->data, finfo.size, &br);
109     if (rv != APR_SUCCESS)
110         return rv;
111 
112     apr_file_close(file);
113 
114     /* safe integer type conversion: unsigned int and apr_size_t might
115      * have different sizes */
116 #if defined(__GNUC__) && __GNUC__ < 5 && \
117     !(defined(__clang__) && __has_builtin(__builtin_add_overflow))
118     if (__builtin_expect(br > UINT_MAX, 0))
119         return APR_EINVAL;
120     else
121         datum->size = (unsigned int) br;
122 #else
123     if (__builtin_add_overflow(br, 0, &datum->size))
124         return APR_EINVAL;
125 #endif
126 
127     return rv;
128 }
129 
130 
131 
init_gnutls_ctxt(conn_rec * c)132 mgs_handle_t *init_gnutls_ctxt(conn_rec *c)
133 {
134     mgs_handle_t *ctxt = (mgs_handle_t *)
135         ap_get_module_config(c->conn_config, &gnutls_module);
136     if (ctxt == NULL)
137     {
138         ctxt = apr_pcalloc(c->pool, sizeof (*ctxt));
139         ap_set_module_config(c->conn_config, &gnutls_module, ctxt);
140 
141         /* Get mod_gnutls server configuration */
142         mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
143             ap_get_module_config(c->base_server->module_config,
144                                  &gnutls_module);
145 
146         /* Set up connection and server references */
147         ctxt->c = c;
148         ctxt->sc = sc;
149         /* Default, unconditionally changed in proxy setup functions */
150         ctxt->is_proxy = GNUTLS_ENABLED_FALSE;
151     }
152     return ctxt;
153 }
154