]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/curl/lib/http_digest.c
Various Mac OS X tweaks to get this to build. Probably breaking things.
[icculus/iodoom3.git] / neo / curl / lib / http_digest.c
1 /***************************************************************************
2  *                                  _   _ ____  _     
3  *  Project                     ___| | | |  _ \| |    
4  *                             / __| | | | |_) | |    
5  *                            | (__| |_| |  _ <| |___ 
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at http://curl.haxx.se/docs/copyright.html.
13  * 
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  * $Id: http_digest.c,v 1.8 2004/03/08 12:37:11 bagder Exp $
22  ***************************************************************************/
23 #include "setup.h"
24
25 #ifndef CURL_DISABLE_HTTP
26 /* -- WIN32 approved -- */
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdarg.h>
30 #include <stdlib.h>
31 #include <ctype.h>
32
33 #include "urldata.h"
34 #include "sendf.h"
35 #include "strequal.h"
36
37 #include "md5.h"
38 #include "http_digest.h"
39
40 #define _MPRINTF_REPLACE /* use our functions only */
41 #include <curl/mprintf.h>
42
43 /* The last #include file should be: */
44 #ifdef CURLDEBUG
45 #include "memdebug.h"
46 #endif
47
48 /* Test example header:
49
50 WWW-Authenticate: Digest realm="testrealm", nonce="1053604598"
51
52 */
53
54 CURLdigest Curl_input_digest(struct connectdata *conn,
55                              char *header) /* rest of the www-authenticate:
56                                               header */
57 {
58   bool more = TRUE;
59   struct SessionHandle *data=conn->data;
60
61   /* skip initial whitespaces */
62   while(*header && isspace((int)*header))
63     header++;
64
65   if(checkprefix("Digest", header)) {
66     header += strlen("Digest");
67
68     /* clear off any former leftovers and init to defaults */
69     Curl_digest_cleanup(data);
70
71     while(more) {
72       char value[32];
73       char content[128];
74       size_t totlen=0;
75
76       while(*header && isspace((int)*header))
77         header++;
78     
79       /* how big can these strings be? */
80       if(2 == sscanf(header, "%31[^=]=\"%127[^\"]\"",
81                      value, content)) {
82         if(strequal(value, "nonce")) {
83           data->state.digest.nonce = strdup(content);
84         }
85         else if(strequal(value, "cnonce")) {
86           data->state.digest.cnonce = strdup(content);
87         }
88         else if(strequal(value, "realm")) {
89           data->state.digest.realm = strdup(content);
90         }
91         else if(strequal(value, "algorithm")) {
92           if(strequal(content, "MD5-sess"))
93             data->state.digest.algo = CURLDIGESTALGO_MD5SESS;
94           /* else, remain using the default md5 */
95         }
96         else {
97           /* unknown specifier, ignore it! */
98         }
99         totlen = strlen(value)+strlen(content)+3;
100       }
101       else 
102         break; /* we're done here */
103         
104       header += totlen;
105       if(',' == *header)
106         /* allow the list to be comma-separated */
107         header++; 
108     }
109
110     if(!data->state.digest.nonce)
111       return CURLDIGEST_BAD;
112   }
113   else 
114     /* else not a digest, get out */
115     return CURLDIGEST_NONE;
116
117   return CURLDIGEST_FINE;
118 }
119
120 /* convert md5 chunk to RFC2617 (section 3.1.3) -suitable ascii string*/
121 static void md5_to_ascii(unsigned char *source, /* 16 bytes */
122                          unsigned char *dest) /* 33 bytes */
123 {
124   int i;
125   for(i=0; i<16; i++)
126     sprintf((char *)&dest[i*2], "%02x", source[i]);
127 }
128
129 CURLcode Curl_output_digest(struct connectdata *conn,
130                             unsigned char *request,
131                             unsigned char *uripath)
132 {
133   /* We have a Digest setup for this, use it!  Now, to get all the details for
134      this sorted out, I must urge you dear friend to read up on the RFC2617
135      section 3.2.2, */
136   unsigned char md5buf[16]; /* 16 bytes/128 bits */
137   unsigned char ha1[33]; /* 32 digits and 1 zero byte */
138   unsigned char ha2[33];
139   unsigned char request_digest[33];
140   unsigned char *md5this;
141
142   struct SessionHandle *data = conn->data;
143
144   /*
145     if the algorithm is "MD5" or unspecified (which then defaults to MD5):
146     
147     A1 = unq(username-value) ":" unq(realm-value) ":" passwd
148
149     if the algorithm is "MD5-sess" then:
150
151     A1 = H( unq(username-value) ":" unq(realm-value) ":" passwd )
152          ":" unq(nonce-value) ":" unq(cnonce-value)
153   */
154   if(data->state.digest.algo == CURLDIGESTALGO_MD5SESS) {
155     md5this = (unsigned char *)
156       aprintf("%s:%s:%s:%s:%s",
157               conn->user,
158               data->state.digest.realm,
159               conn->passwd,
160               data->state.digest.nonce,
161               data->state.digest.cnonce);
162   }
163   else {
164     md5this = (unsigned char *)
165       aprintf("%s:%s:%s",
166               conn->user,
167               data->state.digest.realm,
168               conn->passwd);
169   }
170   Curl_md5it(md5buf, md5this);
171   free(md5this); /* free this again */
172   md5_to_ascii(md5buf, ha1);
173
174   /*
175     A2 = Method ":" digest-uri-value
176     
177     (The "Method" value is the HTTP request method as specified in section
178     5.1.1 of RFC 2616)
179   */
180
181   md5this = (unsigned char *)aprintf("%s:%s", request, uripath);
182   Curl_md5it(md5buf, md5this);
183   free(md5this); /* free this again */
184   md5_to_ascii(md5buf, ha2);
185   
186   md5this = (unsigned char *)aprintf("%s:%s:%s", ha1, data->state.digest.nonce,
187                                      ha2);
188   Curl_md5it(md5buf, md5this);
189   free(md5this); /* free this again */
190   md5_to_ascii(md5buf, request_digest);
191
192   /* for test case 64 (snooped from a Mozilla 1.3a request)
193
194     Authorization: Digest username="testuser", realm="testrealm", \
195     nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca"
196   */
197
198   conn->allocptr.userpwd =
199     aprintf( "Authorization: Digest "
200              "username=\"%s\", "
201              "realm=\"%s\", "
202              "nonce=\"%s\", "
203              "uri=\"%s\", "
204              "response=\"%s\"\r\n",
205              conn->user,
206              data->state.digest.realm,
207              data->state.digest.nonce,
208              uripath, /* this is the PATH part of the URL */ 
209              request_digest );
210
211   return CURLE_OK;
212 }
213
214 void Curl_digest_cleanup(struct SessionHandle *data)
215 {
216   if(data->state.digest.nonce)
217     free(data->state.digest.nonce);
218   data->state.digest.nonce = NULL;
219
220   if(data->state.digest.cnonce)
221     free(data->state.digest.cnonce);
222   data->state.digest.cnonce = NULL;
223
224   if(data->state.digest.realm)
225     free(data->state.digest.realm);
226   data->state.digest.realm = NULL;
227
228   data->state.digest.algo = CURLDIGESTALGO_MD5; /* default algorithm */
229 }
230
231 #endif