Annotation of libwww/Library/src/HTAABrow.c, revision 2.41
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.41 ! frystyk 6: ** @(#) $Id: HTAABrow.c,v 2.40 1996/08/08 02:16:36 frystyk Exp $
2.1 luotonen 7: **
2.32 frystyk 8: ** Contains code for parsing challenges and creating credentials for
2.36 frystyk 9: ** basic authentication schemes. See also the HTAAUtil module
2.32 frystyk 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.36 frystyk 34: #define BASIC_AUTH "basic"
35:
2.32 frystyk 36: typedef struct _HTBasic { /* Basic challenge and credentials */
37: char * uid;
38: char * pw;
2.38 frystyk 39: BOOL retry; /* Should we ask the user again? */
2.40 frystyk 40: BOOL proxy; /* Proxy authentication */
2.32 frystyk 41: } HTBasic;
42:
2.36 frystyk 43: /* ------------------------------------------------------------------------- */
44:
45: PRIVATE HTBasic * HTBasic_new()
46: {
47: HTBasic * me = NULL;
48: if ((me = (HTBasic *) HT_CALLOC(1, sizeof(HTBasic))) == NULL)
49: HT_OUTOFMEM("HTBasic_new");
2.38 frystyk 50: me->retry = YES; /* Ask the first time through */
2.36 frystyk 51: return me;
52: }
2.7 luotonen 53:
2.36 frystyk 54: /* HTBasic_delete
55: ** --------------
56: ** Deletes a "basic" information object
57: */
58: PUBLIC int HTBasic_delete (void * context)
59: {
60: HTBasic * basic = (HTBasic *) context;
61: if (basic) {
62: HT_FREE(basic->uid);
63: HT_FREE(basic->pw);
64: HT_FREE(basic);
65: return YES;
66: }
67: return NO;
68: }
2.1 luotonen 69:
2.32 frystyk 70: /*
71: ** Create a protection template for the files
72: ** in the same directory as the given file
73: ** Returns a template matching docname, and other files in that directory.
74: **
75: ** E.g. /foo/bar/x.html => /foo/bar/ *
76: ** ^
77: ** Space only to prevent it from
78: ** being a comment marker here,
79: ** there really isn't any space.
2.1 luotonen 80: */
2.33 frystyk 81: PRIVATE char * make_template (const char * docname)
2.1 luotonen 82: {
2.39 frystyk 83: char * tmplate = NULL;
2.32 frystyk 84: if (docname) {
2.39 frystyk 85: char * host = HTParse(docname, "", PARSE_ACCESS|PARSE_HOST|PARSE_PUNCTUATION);
86: char * path = HTParse(docname, "", PARSE_PATH|PARSE_PUNCTUATION);
87: char * slash = strrchr(path, '/');
88: if (slash) {
89: if (*(slash+1)) {
90: strcpy(slash, "*");
91: StrAllocCat(host, path);
92: } else
93: StrAllocCat(host, "*");
94: }
95: HT_FREE(path);
96: tmplate = host;
97: } else
98: StrAllocCopy(tmplate, "*");
2.32 frystyk 99: if (AUTH_TRACE)
100: HTTrace("Template.... Made template `%s' for file `%s'\n",
2.39 frystyk 101: tmplate, docname ? docname : "<null>");
2.32 frystyk 102: return tmplate;
2.1 luotonen 103: }
104:
2.32 frystyk 105: /*
106: ** Make basic authentication scheme credentials and register this
107: ** information in the request object as credentials. They will then
108: ** be included in the request header. An example is
109: **
110: ** "Basic AkRDIhEF8sdEgs72F73bfaS=="
111: **
2.40 frystyk 112: ** The function can both create normal and proxy credentials
2.36 frystyk 113: ** Returns HT_OK or HT_ERROR
2.32 frystyk 114: */
2.36 frystyk 115: PRIVATE BOOL basic_credentials (HTRequest * request, HTBasic * basic)
2.32 frystyk 116: {
117: if (request && basic) {
118: char * cleartext = NULL;
119: char * cipher = NULL;
120: int cl_len = strlen(basic->uid ? basic->uid : "") +
2.38 frystyk 121: strlen(basic->pw ? basic->pw : "") + 2;
2.37 frystyk 122: int ci_len = 4 * (((cl_len+2)/3) + 1);
123: if ((cleartext = (char *) HT_CALLOC(1, cl_len)) == NULL)
2.32 frystyk 124: HT_OUTOFMEM("basic_credentials");
125: *cleartext = '\0';
126: if (basic->uid) strcpy(cleartext, basic->uid);
127: strcat(cleartext, ":");
128: if (basic->pw) strcat(cleartext, basic->pw);
2.37 frystyk 129: if ((cipher = (char *) HT_CALLOC(1, ci_len + 3)) == NULL)
2.32 frystyk 130: HT_OUTOFMEM("basic_credentials");
2.37 frystyk 131: HTUU_encode((unsigned char *) cleartext, strlen(cleartext), cipher);
2.1 luotonen 132:
2.32 frystyk 133: /* Create the credentials and assign them to the request object */
134: {
2.37 frystyk 135: int cr_len = strlen("basic") + ci_len + 3;
2.32 frystyk 136: char * cookie = (char *) HT_MALLOC(cr_len+1);
137: if (!cookie) HT_OUTOFMEM("basic_credentials");
138: strcpy(cookie, "Basic ");
139: strcat(cookie, cipher);
2.37 frystyk 140: if (AUTH_TRACE) HTTrace("Basic Cookie `%s\'\n", cookie);
2.40 frystyk 141:
142: /* Check whether it is proxy or normal credentials */
143: if (basic->proxy)
144: HTRequest_addCredentials(request, "Proxy-Authorization", cookie);
145: else
146: HTRequest_addCredentials(request, "Authorization", cookie);
147:
2.32 frystyk 148: HT_FREE(cookie);
2.1 luotonen 149: }
2.32 frystyk 150: HT_FREE(cleartext);
151: HT_FREE(cipher);
2.36 frystyk 152: return HT_OK;
2.32 frystyk 153: }
2.36 frystyk 154: return HT_ERROR;
2.1 luotonen 155: }
156:
2.32 frystyk 157: /*
158: ** Prompt the user for username and password.
159: ** Returns YES if user name was typed in, else NO
2.1 luotonen 160: */
2.36 frystyk 161: PRIVATE int prompt_user (HTRequest * request, const char * realm,
162: HTBasic * basic)
2.1 luotonen 163: {
2.32 frystyk 164: HTAlertCallback * cbf = HTAlert_find(HT_A_USER_PW);
165: if (request && cbf) {
2.40 frystyk 166: HTAlertPar * reply = HTAlert_newReply();
2.41 ! frystyk 167: int msg = basic->proxy ? HT_MSG_PROXY_UID : HT_MSG_UID;
! 168: BOOL res = (*cbf)(request, HT_A_USER_PW, msg,
2.36 frystyk 169: basic->uid, (char *) realm, reply);
2.32 frystyk 170: if (res) {
2.36 frystyk 171: HT_FREE(basic->uid);
172: HT_FREE(basic->pw);
173: basic->uid = HTAlert_replyMessage(reply);
174: basic->pw = HTAlert_replySecret(reply);
2.32 frystyk 175: }
176: HTAlert_deleteReply(reply);
2.36 frystyk 177: return res ? HT_OK : HT_ERROR;
2.1 luotonen 178: }
2.36 frystyk 179: return HT_OK;
2.1 luotonen 180: }
181:
2.32 frystyk 182: /* HTBasic_generate
183: ** ----------------
184: ** This function generates "basic" credentials for the challenge found in
185: ** the authentication information base for this request. The result is
186: ** stored as an association list in the request object.
187: ** This is a callback function for the AA handler.
188: */
2.36 frystyk 189: PUBLIC int HTBasic_generate (HTRequest * request, void * context, int status)
2.32 frystyk 190: {
2.36 frystyk 191: HTBasic * basic = (HTBasic *) context;
192: if (request) {
193: const char * realm = HTRequest_realm(request);
194:
2.40 frystyk 195: /*
196: ** If we don't have a basic context then add a new one to the tree.
197: ** As we don't know whether this is for a proxy or not then try
198: ** normal and hope for the best. This should normal not happen!
199: */
2.36 frystyk 200: if (!basic) {
2.39 frystyk 201: char *url = HTAnchor_address((HTAnchor*)HTRequest_anchor(request));
2.36 frystyk 202: basic = HTBasic_new();
2.40 frystyk 203: HTAA_updateNode(NO, BASIC_AUTH, realm, url, basic);
2.39 frystyk 204: HT_FREE(url);
2.36 frystyk 205: }
206:
2.32 frystyk 207: /*
2.36 frystyk 208: ** If we have a set of credentials (or the user provides a new set)
209: ** then store it in the request object as the credentials
2.32 frystyk 210: */
2.39 frystyk 211: if ((basic->retry && prompt_user(request, realm, basic) == HT_OK) ||
212: (!basic->retry && basic->uid)) {
2.38 frystyk 213: basic->retry = NO;
2.36 frystyk 214: return basic_credentials(request, basic);
2.38 frystyk 215: } else
2.37 frystyk 216: return HT_ERROR;
2.1 luotonen 217: }
2.36 frystyk 218: return HT_OK;
2.1 luotonen 219: }
220:
2.32 frystyk 221: /* HTBasic_parse
222: ** -------------
223: ** This function parses the contents of a "basic" challenge
224: ** and stores the challenge in our authentication information datebase.
225: ** We also store the realm in the request object which will help finding
226: ** the right set of credentials to generate.
227: ** The function is a callback function for the AA handler.
228: */
2.36 frystyk 229: PUBLIC int HTBasic_parse (HTRequest * request, void * context, int status)
2.32 frystyk 230: {
2.36 frystyk 231: HTAssocList * challenge = HTRequest_challenge(request);
2.38 frystyk 232: HTBasic * basic = NULL;
2.40 frystyk 233: BOOL proxy = status==HT_NO_PROXY_ACCESS ? YES : NO;
2.36 frystyk 234: if (request && challenge) {
235: char * p = HTAssocList_findObject(challenge, BASIC_AUTH);
236: char * realm = HTNextField(&p);
237: char * rm = HTNextField(&p);
2.38 frystyk 238:
2.32 frystyk 239: /*
2.36 frystyk 240: ** If valid challenge then make a template for the resource and
241: ** store this information in our authentication URL Tree
2.32 frystyk 242: */
2.36 frystyk 243: if (realm && !strcasecomp(realm, "realm") && rm) {
244: if (AUTH_TRACE) HTTrace("Basic Parse. Realm `%s\' found\n", rm);
245: HTRequest_setRealm(request, rm);
2.40 frystyk 246:
247: /*
248: ** If we are in proxy mode then add the proxy - not the final URL
249: */
250: if (proxy) {
251: char * url = HTRequest_proxy(request);
252: basic = (HTBasic *) HTAA_updateNode(proxy, BASIC_AUTH, rm,
253: url, NULL);
254: } else {
255: char * url = HTAnchor_address((HTAnchor *)
256: HTRequest_anchor(request));
257: char * tmplate = make_template(url);
258: basic = (HTBasic *) HTAA_updateNode(proxy, BASIC_AUTH, rm,
259: tmplate, NULL);
260: HT_FREE(url);
261: HT_FREE(tmplate);
262: }
2.1 luotonen 263: }
2.38 frystyk 264:
265: /*
266: ** For some reason the authentication failed so we have to ask the user
267: ** if we should try again. It may be because the user typed the wrong
268: ** user name and password
269: */
270: if (basic) {
271: HTAlertCallback * prompt = HTAlert_find(HT_A_CONFIRM);
2.40 frystyk 272:
273: /*
274: ** Check if the reason for being here is because of lack of proxy
275: ** credentials or "normal" credentials
276: */
277: if (proxy) {
278: if (AUTH_TRACE) HTTrace("Basic Parse. Proxy authentication\n");
279: basic->proxy = YES; /* Remember this */
280: }
281:
282: /* Can we ask the user? */
2.38 frystyk 283: if (prompt) {
2.40 frystyk 284: int code = proxy ?
285: HT_MSG_RETRY_PROXY_AUTH : HT_MSG_RETRY_AUTHENTICATION;
286: if ((*prompt)(request, HT_A_CONFIRM, code,
2.38 frystyk 287: NULL, NULL, NULL) != YES)
288: return HT_ERROR;
289: basic->retry = YES;
290: }
291: }
2.36 frystyk 292: return HT_OK;
2.1 luotonen 293: }
2.36 frystyk 294: if (AUTH_TRACE) HTTrace("Auth........ No challenges found\n");
2.38 frystyk 295: return HT_ERROR;
2.7 luotonen 296: }
Webmaster