4 * Copyright 2003-2004 Oliver Feiler <kiza@kcore.de>
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.
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.
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
28 #include "conversions.h"
32 char * ConstructBasicAuth (char * username, char * password) {
38 /* Create base64 authinfo.
40 RFC 2617. Basic HTTP authentication.
41 Authorization: Basic username:password[base64 encoded] */
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);
48 tmpstr = base64encode (authstring, len-1);
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);
61 char * GetRandomBytes (void) {
62 char * randomness = NULL;
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;
74 fread (raw, 8, 1, devrandom);
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]);
85 char * ConstructDigestAuth (char * username, char * password, char * url, char * authdata) {
86 char * authinfo; /* Authorization header as sent to the server. */
89 char * realm = NULL; /* Variables for the overcomplicated and annoying HTTP digest algo. */
94 char szNonceCount[9] = "00000001"; /* Can be always 1 if we never use the same cnonce twice. */
99 cnonce = GetRandomBytes();
102 token = strsep (&authdata, ", ");
107 if (strncasecmp (token, "realm", 5) == 0) {
108 len = strlen(token)-8;
109 memmove (token, token+7, len);
111 realm = strdup (token);
112 } else if (strncasecmp (token, "qop", 3) == 0) {
113 len = strlen(token)-6;
114 memmove (token, token+5, len);
116 qop = strdup (token);
117 } else if (strncasecmp (token, "nonce", 5) == 0) {
118 len = strlen(token)-8;
119 memmove (token, token+7, len);
121 nonce = strdup (token);
122 } else if (strncasecmp (token, "opaque", 6) == 0) {
123 len = strlen(token)-9;
124 memmove (token, token+8, len);
126 opaque = strdup (token);
130 DigestCalcHA1 ("md5", username, realm, password, nonce, cnonce, HA1);
131 DigestCalcResponse(HA1, nonce, szNonceCount, cnonce, "auth", "GET", url, HA2, Response);
133 /* Determine length of Authorize header.
135 * Authorization: Digest username="(username)", realm="(realm)",
136 * nonce="(nonce)", uri="(url)", algorithm=MD5, response="(Response)",
137 * qop=(auth), nc=(szNonceCount), cnonce="deadbeef"
140 len = 32 + strlen(username) + 10 + strlen(realm) + 10 + strlen(nonce) + 8 + strlen(url) + 28 + strlen(Response) + 16 + strlen(szNonceCount) + 10 + strlen(cnonce) + 4 ;
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;
144 authinfo = malloc (len);
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);
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);
165 Authorization: Digest username="(username)", realm="(realm)",
166 nonce="(nonce)", uri="(url)", algorithm=MD5, response="(Response)",
167 qop=(auth), nc=(szNonceCount), cnonce="deadbeef"
169 int NetSupportAuth (struct feed * cur_ptr, char * authdata, char * url, char * netbuf) {
173 char * username = NULL;
174 char * password = NULL;
175 char * authtype = NULL;
177 /* Reset cur_ptr->authinfo. */
178 free (cur_ptr->authinfo);
179 cur_ptr->authinfo = NULL;
181 /* Catch invalid authdata. */
182 if (authdata == NULL) {
184 } else if (strchr (authdata, ':') == NULL){
185 /* No authinfo found in URL. This should not happen. */
189 tmpstr = strdup (authdata);
192 strsep (&tmpstr, ":");
193 username = strdup (freeme);
194 password = strdup (tmpstr);
196 /* Free allocated string in tmpstr. */
199 /* Extract requested auth type from webserver reply. */
200 header = strdup (netbuf);
202 strsep (&header, " ");
205 /* Catch invalid server replies. authtype should contain at least _something_. */
206 if (authtype == NULL) {
213 strsep (&header, " ");
214 /* header now contains:
216 Digest auth: realm + a lot of other stuff somehow needed by digest auth. */
218 /* Determine auth type the server requests. */
219 if (strncasecmp (authtype, "Basic", 5) == 0) {
221 cur_ptr->authinfo = ConstructBasicAuth (username, password);
222 } else if (strncasecmp (authtype, "Digest", 6) == 0) {
224 cur_ptr->authinfo = ConstructDigestAuth (username, password, url, header);
226 /* Unkown auth type. */
237 if (cur_ptr->authinfo == NULL) {
244 /* HTTP header may only contain ASCII characters.
246 * Ensure that we don't hit the terminating \0 in a string
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).
252 int checkValidHTTPHeader (const unsigned char * header, int size) {
255 len = strlen(header);
259 for (i = 0; i < len; i++) {
260 if (((header[i] < 32) || (header[i] > 127)) &&
261 (header[i] != '\r') && (header[i] != '\n'))
267 int checkValidHTTPURL (const unsigned char * url) {
270 if (strncasecmp(url, "http://", 7) != 0)
275 for (i = 0; i < len; i++) {
276 if ((url[i] < 32) || (url[i] > 126))