Annotation of libwww/Library/src/HTAABrow.c, revision 2.34
2.15 frystyk 1: /* HTAABrow.c
2.32 frystyk 2: ** BROWSER SIDE ACCESS AUTHORIZATION MODULE
2.15 frystyk 3: **
2.19 frystyk 4: ** (c) COPYRIGHT MIT 1995.
2.15 frystyk 5: ** Please first read the full copyright statement in the file COPYRIGH.
2.34 ! frystyk 6: ** @(#) $Id: Date Author State $
2.1 luotonen 7: **
2.32 frystyk 8: ** Contains code for parsing challenges and creating credentials for
9: ** basic and digest authentication schemes. See also the HTAAUtil module
10: ** for how to handle other authentication schemes. You don't have to use
11: ** this code at all.
2.1 luotonen 12: **
13: ** AUTHORS:
14: ** AL Ari Luotonen luotonen@dxcern.cern.ch
2.32 frystyk 15: ** HFN Henrik Frystyk
2.1 luotonen 16: **
17: ** HISTORY:
2.5 luotonen 18: ** Oct 17 AL Made corrections suggested by marca:
19: ** Added if (!realm->username) return NULL;
20: ** Changed some ""s to NULLs.
2.33 frystyk 21: ** Now doing HT_CALLOC() to init uuencode source;
2.5 luotonen 22: ** otherwise HTUU_encode() reads uninitialized memory
23: ** every now and then (not a real bug but not pretty).
24: ** Corrected the formula for uuencode destination size.
2.32 frystyk 25: ** Feb 96 HFN Rewritten to make it scheme independent and based on
26: ** callback functions and an info structure
2.1 luotonen 27: */
28:
2.17 frystyk 29: /* Library include files */
2.27 frystyk 30: #include "WWWLib.h"
31: #include "HTAAUtil.h"
32: #include "HTAABrow.h" /* Implemented here */
2.1 luotonen 33:
2.32 frystyk 34: typedef struct _HTBasic { /* Basic challenge and credentials */
35: char * uid;
36: char * pw;
37: } HTBasic;
38:
39: typedef struct _HTDigest { /* Digest challenge and credentials */
40: char * nounce;
41: char * opaque;
42: BOOL stale;
43: char * uid;
44: char * pw;
45: } HTDigest;
2.7 luotonen 46:
2.32 frystyk 47: /* ------------------------------------------------------------------------- */
2.1 luotonen 48:
2.32 frystyk 49: /*
50: ** Create a protection template for the files
51: ** in the same directory as the given file
52: ** Returns a template matching docname, and other files in that directory.
53: **
54: ** E.g. /foo/bar/x.html => /foo/bar/ *
55: ** ^
56: ** Space only to prevent it from
57: ** being a comment marker here,
58: ** there really isn't any space.
2.1 luotonen 59: */
2.33 frystyk 60: PRIVATE char * make_template (const char * docname)
2.1 luotonen 61: {
2.32 frystyk 62: char *tmplate = NULL;
63: char *slash = NULL;
64: if (docname) {
65: StrAllocCopy(tmplate, docname);
66: slash = strrchr(tmplate, '/');
67: if (slash) slash++;
68: else slash = tmplate;
69: *slash = '\0';
70: StrAllocCat(tmplate, "*");
71: }
72: else StrAllocCopy(tmplate, "*");
73: if (AUTH_TRACE)
74: HTTrace("Template.... Made template `%s' for file `%s'\n",
75: tmplate, docname);
76: return tmplate;
2.1 luotonen 77: }
78:
2.32 frystyk 79: /*
80: ** Make basic authentication scheme credentials and register this
81: ** information in the request object as credentials. They will then
82: ** be included in the request header. An example is
83: **
84: ** "Basic AkRDIhEF8sdEgs72F73bfaS=="
85: **
86: ** Returns YES if credentials created, else NO
87: */
88: PRIVATE HTAssocList * basic_credentials (HTRequest * request, HTBasic * basic)
89: {
90: if (request && basic) {
91: HTAssocList * credentials = HTAssocList_new();
92: char * cleartext = NULL;
93: char * cipher = NULL;
94: int cl_len = strlen(basic->uid ? basic->uid : "") +
95: strlen(basic->pw ? basic->pw : "") + 3;
96: int ci_len = (4*(cl_len+2))/3;
97: if ((cleartext = (char *) HT_CALLOC(1, cl_len+3)) == NULL)
98: HT_OUTOFMEM("basic_credentials");
99: *cleartext = '\0';
100: if (basic->uid) strcpy(cleartext, basic->uid);
101: strcat(cleartext, ":");
102: if (basic->pw) strcat(cleartext, basic->pw);
103: if ((cipher = (char *) HT_MALLOC(ci_len+1)) == NULL)
104: HT_OUTOFMEM("basic_credentials");
105: HTUU_encode((unsigned char *) cleartext, cl_len, cipher);
2.1 luotonen 106:
2.32 frystyk 107: /* Create the credentials and assign them to the request object */
108: {
109: int cr_len = strlen("basic") + ci_len + 2;
110: char * cookie = (char *) HT_MALLOC(cr_len+1);
111: if (!cookie) HT_OUTOFMEM("basic_credentials");
112: strcpy(cookie, "Basic ");
113: strcat(cookie, cipher);
114: HTAssocList_add(credentials, "Authorization", cookie);
115: HT_FREE(cookie);
2.1 luotonen 116: }
2.32 frystyk 117: HT_FREE(cleartext);
118: HT_FREE(cipher);
119: return credentials;
2.1 luotonen 120: }
2.32 frystyk 121: return NULL;
2.1 luotonen 122: }
123:
2.32 frystyk 124: /*
125: ** Make digest authentication scheme credentials and register this
126: ** information in the request object as credentials. They will then
127: ** be included in the request header.
128: ** Returns YES if credentials created, else NO
129: */
130: PRIVATE HTAssocList *digest_credentials (HTRequest * request, HTDigest *digest)
131: {
132: if (request && digest) {
133: HTAssocList * credentials = HTAssocList_new();
134: char * cleartext = NULL;
135: char * cipher = NULL;
136:
137: /* Do the generation */
138: #if 0
139: HTAssocList_add(credentials, "Authorization", cookie);
140: #endif
141: HT_FREE(cleartext);
142: HT_FREE(cipher);
143: return credentials;
144: }
145: return NULL;
2.1 luotonen 146: }
147:
2.32 frystyk 148: /*
149: ** Prompt the user for username and password.
150: ** Returns YES if user name was typed in, else NO
2.1 luotonen 151: */
2.32 frystyk 152: PRIVATE BOOL prompt_user (HTRequest * request, char * realm,
153: char ** uid, char ** pw)
2.1 luotonen 154: {
2.32 frystyk 155: HTAlertCallback * cbf = HTAlert_find(HT_A_USER_PW);
156: if (request && cbf) {
157: HTAlertPar * reply = HTAlert_newReply();
158: BOOL res = (*cbf)(request, HT_A_USER_PW,HT_MSG_NULL,*uid,realm,reply);
159: if (res) {
160: HT_FREE(*uid);
161: HT_FREE(*pw);
162: *uid = HTAlert_replyMessage(reply);
163: *pw = HTAlert_replySecret(reply);
164: }
165: HTAlert_deleteReply(reply);
166: return res ? YES : NO;
2.1 luotonen 167: }
2.32 frystyk 168: return NO;
2.1 luotonen 169: }
170:
2.32 frystyk 171: /* HTBasic_generate
172: ** ----------------
173: ** This function generates "basic" credentials for the challenge found in
174: ** the authentication information base for this request. The result is
175: ** stored as an association list in the request object.
176: ** This is a callback function for the AA handler.
177: */
2.33 frystyk 178: PUBLIC BOOL HTBasic_generate (HTRequest * request, const char * scheme,
2.32 frystyk 179: char * realm, void * challenge)
180: {
181: if (request && scheme && realm && challenge) {
182: HTBasic * basic = (HTBasic *) challenge;
183: if (AUTH_TRACE) HTTrace("Auth........ Generating basic credentials\n");
184: /*
185: ** If we have a set of credentials then store it in the request object
186: */
187: if (basic->uid || prompt_user(request, realm,&basic->uid,&basic->pw)) {
188: HTAssocList * credentials = HTRequest_credentials(request);
189: if (credentials) HTAssocList_delete(credentials);
190: if ((credentials = basic_credentials(request, basic))) {
191: HTRequest_setCredentials(request, credentials);
192: return YES;
2.2 luotonen 193: }
194: }
2.1 luotonen 195: }
2.32 frystyk 196: return NO;
2.1 luotonen 197: }
198:
2.32 frystyk 199: /* HTBasic_parse
200: ** -------------
201: ** This function parses the contents of a "basic" challenge
202: ** and stores the challenge in our authentication information datebase.
203: ** We also store the realm in the request object which will help finding
204: ** the right set of credentials to generate.
205: ** The function is a callback function for the AA handler.
206: */
2.33 frystyk 207: PUBLIC BOOL HTBasic_parse (HTRequest * request, const char * scheme)
2.32 frystyk 208: {
209: HTAssocList * challenge;
210: if (request && (challenge = HTRequest_challenge(request))) {
211: char * p = HTAssocList_lookup(challenge, "WWW-authenticate");
212: char * value = HTNextField(&p);
213: if (AUTH_TRACE)
214: HTTrace("Auth........ Parsing %s challenge\n", value?value:"NULL");
215: if (p && (value = HTNextField(&p))) {
216: /*
217: ** If valid challenge then make a template for the resource and
218: ** store this information in our authentication base
219: */
220: if (!strcasecomp(value, "realm") && (value = HTNextField(&p))) {
221: char * url = HTAnchor_physical(HTRequest_anchor(request));
222: char * tmplate = make_template(url);
223: HTBasic * me = (HTBasic *) HT_CALLOC(1, sizeof(HTBasic));
224: if (!me) HT_OUTOFMEM("HTBasic_parse");
225: HTAuthInfo_add(scheme, tmplate, value, me);
226: HTRequest_setRealm(request, value);
227: HT_FREE(tmplate);
228: return YES;
229: }
2.1 luotonen 230: }
231: }
2.32 frystyk 232: if (AUTH_TRACE) HTTrace("Auth........ None basic challenge found\n");
233: return NO;
2.1 luotonen 234: }
235:
2.32 frystyk 236: /* HTBasic_delete
237: ** --------------
238: ** Deletes a "basic" information object
239: */
2.33 frystyk 240: PUBLIC BOOL HTBasic_delete (const char * scheme, void * data)
2.32 frystyk 241: {
242: HTBasic * basic = (HTBasic *) data;
243: if (basic) {
244: HTBasic * basic = (HTBasic *) data;
245: HT_FREE(basic->uid);
246: HT_FREE(basic->pw);
247: HT_FREE(basic);
248: return YES;
2.1 luotonen 249: }
2.32 frystyk 250: return NO;
2.1 luotonen 251: }
252:
2.32 frystyk 253: /* HTDigest_generate
254: ** -----------------
255: ** This function generates "basic" credentials for the challenge found in
256: ** the authentication information base for this request. The result is
257: ** stored as an association list in the request object.
258: ** This is a callback function for the AA handler.
259: */
2.33 frystyk 260: PUBLIC BOOL HTDigest_generate (HTRequest * request, const char * scheme,
2.32 frystyk 261: char * realm, void * challenge)
262: {
263: if (request && scheme && realm && challenge) {
264: HTDigest * digest = (HTDigest *) challenge;
265: if (AUTH_TRACE)HTTrace("Auth........ Generating digest credentials\n");
266: /*
267: ** If we have a set of credentials then store it in the request object
268: */
269: #if 0
270: if (basic->uid || prompt_user(request, realm,&basic->uid,&basic->pw)) {
271: HTAssocList * credentials = HTRequest_credentials(request);
272: if (credentials) HTAssocList_delete(credentials);
273: if ((credentials = basic_credentials(request, basic))) {
274: HTRequest_setCredentials(request, credentials);
275: return YES;
276: }
2.1 luotonen 277: }
2.32 frystyk 278: #endif
2.1 luotonen 279: }
2.32 frystyk 280: return NO;
2.1 luotonen 281: }
282:
2.32 frystyk 283: /* HTDigest_parse
284: ** --------------
285: ** This function parses the contents of a "digest" challenge
286: ** and stores the challenge in our authentication information datebase.
287: ** We also store the realm in the request object which will help finding
288: ** the right set of credentials to generate.
289: ** The function is a callback function for the AA handler.
2.1 luotonen 290: */
2.33 frystyk 291: PUBLIC BOOL HTDigest_parse (HTRequest * request, const char * scheme)
2.1 luotonen 292: {
2.32 frystyk 293: if (request) {
2.1 luotonen 294:
2.32 frystyk 295: /* Do the parsing */
2.1 luotonen 296:
297: }
2.32 frystyk 298: if (AUTH_TRACE) HTTrace("Auth........ No digest challenge found\n");
2.33 frystyk 299: return NO;
2.7 luotonen 300: }
2.1 luotonen 301:
2.32 frystyk 302: /* HTDigest_delete
303: ** ---------------
304: ** Deletes a "digest" information object
2.7 luotonen 305: */
2.33 frystyk 306: PUBLIC BOOL HTDigest_delete (const char * scheme, void * data)
2.1 luotonen 307: {
2.32 frystyk 308: HTDigest * digest = (HTDigest *) data;
309: if (digest) {
310: HT_FREE(digest->nounce);
311: HT_FREE(digest->opaque);
312: HT_FREE(digest->uid);
313: HT_FREE(digest->pw);
314: HT_FREE(digest);
315: return YES;
2.7 luotonen 316: }
2.14 frystyk 317: return NO;
2.7 luotonen 318: }
2.1 luotonen 319:
320:
Webmaster