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