]> code.citadel.org Git - citadel.git/blob - rss2ctdl/net-support.c
907f25077eb9fbaad706ce95dce5e52ac7ef03a5
[citadel.git] / rss2ctdl / net-support.c
1 /*
2  * $Id$
3  * 
4  * Copyright 2003-2004 Oliver Feiler <kiza@kcore.de>
5  *
6  * net-support.c
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  */
22
23 #include <string.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26
27 #include "config.h"
28 #include "conversions.h"
29
30 #include "digcalc.h"
31
32 char * ConstructBasicAuth (char * username, char * password) {
33         int len;
34         char * authinfo;
35         char * authstring;
36         char * tmpstr;
37
38         /* Create base64 authinfo.
39
40         RFC 2617. Basic HTTP authentication.
41         Authorization: Basic username:password[base64 encoded] */
42
43         /* Construct the cleartext authstring. */
44         len = strlen(username) + 1 + strlen(password) + 1;
45         authstring = malloc (len);
46         snprintf (authstring, len, "%s:%s", username, password);
47
48         tmpstr = base64encode (authstring, len-1);
49
50         /* "Authorization: Basic " + base64str + \r\n\0 */
51         len = 21 + strlen(tmpstr) + 3;
52         authinfo = malloc (len);
53         snprintf (authinfo, len, "Authorization: Basic %s\r\n", tmpstr);
54         
55         free (tmpstr);
56         free (authstring);
57         
58         return authinfo;
59 }
60
61 char * GetRandomBytes (void) {
62         char * randomness = NULL;
63         char raw[8];
64         int i;
65         FILE * devrandom;
66         
67         devrandom = fopen ("/dev/random", "r");
68         if (devrandom == NULL) {
69                 /* Use rand() if we don't have access to /dev/random. */
70                 for (i = 0; i <= 7; i++) {
71                         raw[i] = 1+(float)rand() / (float)RAND_MAX * 255;
72                 }
73         } else {
74                 fread (raw, 8, 1, devrandom);
75                 fclose (devrandom);
76         }
77         
78         randomness = malloc (17);
79         snprintf (randomness, 17, "%hhx%hhx%hhx%hhx%hhx%hhx%hhx%hhx",
80                 raw[0], raw[1], raw[2], raw[3], raw[4], raw[5], raw[6], raw[7]);
81         
82         return randomness;
83 }
84
85 char * ConstructDigestAuth (char * username, char * password, char * url, char * authdata) {
86         char * authinfo;                        /* Authorization header as sent to the server. */
87         char * token;
88         int len;
89         char * realm = NULL;            /* Variables for the overcomplicated and annoying HTTP digest algo. */
90         char * qop = NULL;
91         char * nonce = NULL;
92         char * opaque = NULL;
93         char * cnonce;
94         char szNonceCount[9] = "00000001";      /* Can be always 1 if we never use the same cnonce twice. */
95         HASHHEX HA1;
96         HASHHEX HA2 = "";
97         HASHHEX Response;
98         
99         cnonce = GetRandomBytes();
100         
101         while (1) {
102                 token = strsep (&authdata, ", ");
103                 
104                 if (token == NULL)
105                         break;
106                 
107                 if (strncasecmp (token, "realm", 5) == 0) {
108                         len = strlen(token)-8;
109                         memmove (token, token+7, len);
110                         token[len] = '\0';
111                         realm = strdup (token);
112                 } else if (strncasecmp (token, "qop", 3) == 0) {
113                         len = strlen(token)-6;
114                         memmove (token, token+5, len);
115                         token[len] = '\0';
116                         qop = strdup (token);
117                 } else if (strncasecmp (token, "nonce", 5) == 0) {
118                         len = strlen(token)-8;
119                         memmove (token, token+7, len);
120                         token[len] = '\0';
121                         nonce = strdup (token);
122                 } else if (strncasecmp (token, "opaque", 6) == 0) {
123                         len = strlen(token)-9;
124                         memmove (token, token+8, len);
125                         token[len] = '\0';
126                         opaque = strdup (token);
127                 }
128         }
129         
130         DigestCalcHA1 ("md5", username, realm, password, nonce, cnonce, HA1);
131         DigestCalcResponse(HA1, nonce, szNonceCount, cnonce, "auth", "GET", url, HA2, Response);
132
133         /* Determine length of Authorize header.
134          *
135          * Authorization: Digest username="(username)", realm="(realm)",
136          * nonce="(nonce)", uri="(url)", algorithm=MD5, response="(Response)",
137          * qop=(auth), nc=(szNonceCount), cnonce="deadbeef"
138          */
139         if (opaque == NULL)
140                 len = 32 + strlen(username) + 10 + strlen(realm) + 10 + strlen(nonce) + 8 + strlen(url) + 28 + strlen(Response) + 16 + strlen(szNonceCount) + 10 + strlen(cnonce) + 4 ;
141         else
142                 len = 32 + strlen(username) + 10 + strlen(realm) + 10 + strlen(nonce) + 8 + strlen(url) + 28 + strlen(Response) + 16 + strlen(szNonceCount) + 10 + strlen(cnonce) + 10 + strlen(opaque) + 4;
143
144         authinfo = malloc (len);
145         
146         if (opaque == NULL) {
147                 snprintf (authinfo, len, "Authorization: Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", algorithm=MD5, response=\"%s\", qop=auth, nc=%s, cnonce=\"%s\"\r\n",
148                         username, realm, nonce, url, Response, szNonceCount, cnonce);
149         } else {
150                 snprintf (authinfo, len, "Authorization: Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", algorithm=MD5, response=\"%s\", qop=auth, nc=%s, cnonce=\"%s\", opaque=\"%s\"\r\n",
151                         username, realm, nonce, url, Response, szNonceCount, cnonce, opaque);
152         }
153         
154         free (realm);
155         free (qop);
156         free (nonce);
157         free (cnonce);
158         free (opaque);
159         
160         return authinfo;
161 }
162
163
164 /*
165 Authorization: Digest username="(username)", realm="(realm)",
166 nonce="(nonce)", uri="(url)", algorithm=MD5, response="(Response)",
167 qop=(auth), nc=(szNonceCount), cnonce="deadbeef"
168 */
169 int NetSupportAuth (struct feed * cur_ptr, char * authdata, char * url, char * netbuf) {
170         char * header;
171         char * tmpstr;
172         char * freeme;
173         char * username = NULL;
174         char * password = NULL;
175         char * authtype = NULL;
176         
177         /* Reset cur_ptr->authinfo. */
178         free (cur_ptr->authinfo);
179         cur_ptr->authinfo = NULL;
180         
181         /* Catch invalid authdata. */
182         if (authdata == NULL) {
183                 return 1;
184         } else if (strchr (authdata, ':') == NULL){
185                 /* No authinfo found in URL. This should not happen. */
186                 return 1;
187         }
188         
189         tmpstr = strdup (authdata);
190         freeme = tmpstr;
191         
192         strsep (&tmpstr, ":");
193         username = strdup (freeme);
194         password = strdup (tmpstr);
195         
196         /* Free allocated string in tmpstr. */
197         free (freeme);
198         
199         /* Extract requested auth type from webserver reply. */
200         header = strdup (netbuf);
201         freeme = header;
202         strsep (&header, " ");
203         authtype = header;
204         
205         /* Catch invalid server replies. authtype should contain at least _something_. */
206         if (authtype == NULL) {
207                 free (freeme);
208                 free (username);
209                 free (password);
210                 return -1;
211         }
212         
213         strsep (&header, " ");
214         /* header now contains:
215            Basic auth:  realm
216            Digest auth: realm + a lot of other stuff somehow needed by digest auth. */
217         
218         /* Determine auth type the server requests. */
219         if (strncasecmp (authtype, "Basic", 5) == 0) {
220                 /* Basic auth. */
221                 cur_ptr->authinfo = ConstructBasicAuth (username, password);
222         } else if (strncasecmp (authtype, "Digest", 6) == 0) {
223                 /* Digest auth. */
224                 cur_ptr->authinfo = ConstructDigestAuth (username, password, url, header);
225         } else {
226                 /* Unkown auth type. */
227                 free (freeme);
228                 free (username);
229                 free (password);
230                 return -1;
231         }
232         
233         free (username);
234         free (password);
235         free (freeme);
236
237         if (cur_ptr->authinfo == NULL) {
238                 return 2;
239         }
240         
241         return 0;
242 }
243
244 /* HTTP header may only contain ASCII characters.
245  *
246  * Ensure that we don't hit the terminating \0 in a string
247  * with the for loop.
248  * The function also ensures that there is no NULL byte in the string.
249  * If given binary data return at once if we read beyond
250  * the boundary of sizeof(header).
251  */
252 int checkValidHTTPHeader (const unsigned char * header, int size) {
253         int i, len;
254         
255         len = strlen(header);
256         if (len > size)
257                 return -1;
258         
259         for (i = 0; i < len; i++) {
260                 if (((header[i] < 32) || (header[i] > 127)) &&
261                         (header[i] != '\r') && (header[i] != '\n'))
262                         return -1;
263         }
264         return 0;
265 }
266
267 int checkValidHTTPURL (const unsigned char * url) {
268         int i, len;
269         
270         if (strncasecmp(url, "http://", 7) != 0)
271                 return -1;
272         
273         len = strlen(url);
274                 
275         for (i = 0; i < len; i++) {
276                 if ((url[i] < 32) || (url[i] > 126))
277                         return -1;
278         }
279         
280         return 0;
281 }
282