HTAABrow.c 36.6 KB
Newer Older
1
/*
2
 * $LynxId: HTAABrow.c,v 1.42 2016/11/24 23:57:57 tom Exp $
3 4
 *
 * MODULE							HTAABrow.c
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
 *		BROWSER SIDE ACCESS AUTHORIZATION MODULE
 *
 *	Contains the code for keeping track on server hostnames,
 *	port numbers, scheme names, usernames, passwords
 *	(and servers' public keys).
 *
 * IMPORTANT:
 *	Routines in this module use dynamic allocation, but free
 *	automatically all the memory reserved by them.
 *
 *	Therefore the caller never has to (and never should)
 *	free() any object returned by these functions.
 *
 *	Therefore also all the strings returned by this package
 *	are only valid until the next call to the same function
 *	is made.  This approach is selected, because of the nature
 *	of access authorization: no string returned by the package
 *	needs to be valid longer than until the next call.
 *
 *	This also makes it easy to plug the AA package in:
 *	you don't have to ponder whether to free() something
 *	here or is it done somewhere else (because it is always
 *	done somewhere else).
 *
 *	The strings that the package needs to store are copied
 *	so the original strings given as parameters to AA
 *	functions may be freed or modified with no side effects.
 *
 *	The AA package does not free() anything else than what
 *	it has itself allocated.
 *
 * AUTHORS:
 *	AL	Ari Luotonen	luotonen@dxcern.cern.ch
 *
 * HISTORY:
 *	Oct 17	AL	Made corrections suggested by marca:
 *			Added  if (!realm->username) return NULL;
 *			Changed some ""s to NULLs.
 *			Now doing calloc() to init uuencode source;
 *			otherwise HTUU_encode() reads uninitialized memory
 *			every now and then (not a real bug but not pretty).
 *			Corrected the formula for uuencode destination size.
 *
 * 28 Apr 1997	AJL	Do Proxy Authorisation.
 *
 * BUGS:
 *
 *
 */
54 55 56

#include <HTUtils.h>
#include <HTString.h>
57 58 59 60 61
#include <HTParse.h>		/* URL parsing function         */
#include <HTList.h>		/* HTList object                */
#include <HTAlert.h>		/* HTConfirm(), HTPrompt()      */
#include <HTAAUtil.h>		/* AA common to both sides      */
#include <HTAssoc.h>		/* Assoc list                   */
62
#include <HTAccess.h>		/* Are we using an HTTP gateway? */
63 64
#include <HTAABrow.h>		/* Implemented here             */
#include <HTUU.h>		/* Uuencoding and uudecoding    */
65 66 67 68

#include <LYLeaks.h>

/*
69 70 71 72
 *  Local datatype definitions
 *
 *  HTAAServer contains all the information about one server.
 */
73 74
typedef struct {

75 76 77 78 79 80 81 82 83 84
    char *hostname;		/* Host's name                  */
    int portnumber;		/* Port number                  */
    BOOL IsProxy;		/* Is it a proxy?               */
    HTList *setups;		/* List of protection setups 
				   on this server; i.e., valid
				   authentication schemes and
				   templates when to use them.
				   This is actually a list of
				   HTAASetup objects.           */
    HTList *realms;		/* Information about passwords  */
85 86 87
} HTAAServer;

/*
88 89 90
 *  HTAASetup contains information about one server's one
 *  protected tree of documents.
 */
91
typedef struct {
92 93 94 95 96
    HTAAServer *server;		/* Which server serves this tree             */
    char *ctemplate;		/* Template for this tree                    */
    HTList *valid_schemes;	/* Valid authentic.schemes                   */
    HTAssocList **scheme_specifics;	/* Scheme specific params                  */
    BOOL retry;			/* Failed last time -- reprompt (or whatever) */
97 98 99
} HTAASetup;

/*
100 101 102
 *  Information about usernames and passwords in
 *  Basic and Pubkey authentication schemes;
 */
103
typedef struct {
104 105 106
    char *realmname;		/* Password domain name         */
    char *username;		/* Username in that domain      */
    char *password;		/* Corresponding password       */
107 108 109
} HTAARealm;

/*
110 111 112 113 114 115
 *  To free off all globals. - FM
 */
static void free_HTAAGlobals(void);
static BOOL free_HTAAGlobalsSet = FALSE;
static char *HTAA_composeAuthResult = NULL;
static char *compose_auth_stringResult = NULL;	/* Uuencoded presentation */
116 117

/*
118 119 120 121 122
 *  Module-wide global variables
 */
static HTList *server_table = NULL;	/* Browser's info about servers      */
static char *secret_key = NULL;	/* Browser's latest secret key       */
static HTAASetup *current_setup = NULL;		/* The server setup we are currently */
123

124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
					/* talking to                        */
static char *current_hostname = NULL;	/* The server's name and portnumber  */
static int current_portnumber = 80;	/* where we are currently trying to  */

					/* connect.                          */
static char *current_docname = NULL;	/* The document's name we are        */

					/* trying to access.                 */
static char *HTAAForwardAuth = NULL;	/* Authorization: line to forward    */

					/* (used by gateway httpds)          */
static HTAASetup *proxy_setup = NULL;	/* Same as above, but for Proxy -AJL */
static char *proxy_hostname = NULL;
static char *proxy_docname = NULL;
static int proxy_portnumber = 80;
139 140 141

/*** HTAAForwardAuth for enabling gateway-httpds to forward Authorization ***/

142 143
void HTAAForwardAuth_set(const char *scheme_name,
			 const char *scheme_specifics)
144
{
145 146 147
    size_t len = (20
		  + (scheme_name ? strlen(scheme_name) : 0)
		  + (scheme_specifics ? strlen(scheme_specifics) : 0));
148 149 150

    FREE(HTAAForwardAuth);
    if ((HTAAForwardAuth = typecallocn(char, len)) == 0)
151
	  outofmem(__FILE__, "HTAAForwardAuth_set");
152 153 154 155 156 157 158 159 160 161 162

    strcpy(HTAAForwardAuth, "Authorization: ");
    if (scheme_name) {
	strcat(HTAAForwardAuth, scheme_name);
	strcat(HTAAForwardAuth, " ");
	if (scheme_specifics) {
	    strcat(HTAAForwardAuth, scheme_specifics);
	}
    }
}

163
void HTAAForwardAuth_reset(void)
164 165 166 167 168 169
{
    FREE(HTAAForwardAuth);
}

/**************************** HTAAServer ***********************************/

170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
static void HTAASetup_delete(HTAASetup * killme);	/* Forward */

/* static						HTAAServer_new()
 *		ALLOCATE A NEW NODE TO HOLD SERVER INFO
 *		AND ADD IT TO THE LIST OF SERVERS
 * ON ENTRY:
 *	hostname	is the name of the host that the server
 *			is running in.
 *	portnumber	is the portnumber which the server listens.
 *	IsProxy		should be TRUE if this is a proxy.
 *
 * ON EXIT:
 *	returns		the newly-allocated node with all the strings
 *			duplicated.
 *			Strings will be automatically freed by
 *			the function HTAAServer_delete(), which also
 *			frees the node itself.
 */
static HTAAServer *HTAAServer_new(const char *hostname,
				  int portnumber,
190
				  int IsProxy)
191 192 193 194
{
    HTAAServer *server;

    if ((server = typecalloc(HTAAServer)) == 0)
195
	  outofmem(__FILE__, "HTAAServer_new");
196

197 198
    server->hostname = NULL;
    server->portnumber = (portnumber > 0 ? portnumber : 80);
199
    server->IsProxy = (BOOLEAN) IsProxy;
200 201
    server->setups = HTList_new();
    server->realms = HTList_new();
202 203 204 205 206 207 208

    if (hostname)
	StrAllocCopy(server->hostname, hostname);

    if (!server_table)
	server_table = HTList_new();

209
    HTList_addObject(server_table, (void *) server);
210 211 212 213

    return server;
}

214 215 216 217 218 219 220 221 222 223 224 225
/* static						HTAAServer_delete()
 *
 *	DELETE THE ENTRY FOR THE SERVER FROM THE HOST TABLE,
 *	AND FREE THE MEMORY USED BY IT.
 *
 * ON ENTRY:
 *	killme		points to the HTAAServer to be freed.
 *
 * ON EXIT:
 *	returns		nothing.
 */
static void HTAAServer_delete(HTAAServer *killme)
226 227 228 229 230 231 232 233 234 235
{
    int n, i;
    HTAASetup *setup;
    HTAARealm *realm;
    HTList *cur;

    if (killme) {
	if (killme->setups != NULL) {
	    n = HTList_count(killme->setups);
	    for (i = (n - 1); i >= 0; i--) {
236 237
		if ((setup = (HTAASetup *) HTList_objectAt(killme->setups,
							   i)) != NULL) {
238 239 240 241 242 243 244 245 246
		    HTAASetup_delete(setup);
		    setup = NULL;
		}
	    }
	    HTList_delete(killme->setups);
	    killme->setups = NULL;
	}

	cur = killme->realms;
247
	while (NULL != (realm = (HTAARealm *) HTList_nextObject(cur))) {
248 249 250 251 252 253 254 255 256 257
	    FREE(realm->realmname);
	    FREE(realm->username);
	    FREE(realm->password);
	    FREE(realm);
	}
	HTList_delete(killme->realms);
	killme->realms = NULL;

	FREE(killme->hostname);

258
	HTList_removeObject(server_table, (void *) killme);
259 260 261 262
	FREE(killme);
    }
}

263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
/* static						HTAAServer_lookup()
 *		LOOK UP SERVER BY HOSTNAME AND PORTNUMBER
 * ON ENTRY:
 *	hostname	obvious.
 *	portnumber	if non-positive defaults to 80.
 *	IsProxy		should be TRUE if this is a proxy.
 *
 *	Looks up the server in the module-global server_table.
 *
 * ON EXIT:
 *	returns		pointer to a HTAAServer structure
 *			representing the looked-up server.
 *			NULL, if not found.
 */
static HTAAServer *HTAAServer_lookup(const char *hostname,
				     int portnumber,
279
				     int IsProxy)
280 281 282 283 284 285 286 287
{
    if (hostname) {
	HTList *cur = server_table;
	HTAAServer *server;

	if (portnumber <= 0)
	    portnumber = 80;

288 289 290
	while (NULL != (server = (HTAAServer *) HTList_nextObject(cur))) {
	    if (server->portnumber == portnumber &&
		0 == strcmp(server->hostname, hostname) &&
291 292 293 294
		server->IsProxy == IsProxy)
		return server;
	}
    }
295
    return NULL;		/* NULL parameter, or not found */
296 297 298 299
}

/*************************** HTAASetup *******************************/

300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
/* static						HTAASetup_lookup()
 *	FIGURE OUT WHICH AUTHENTICATION SETUP THE SERVER
 *	IS USING FOR A GIVEN FILE ON A GIVEN HOST AND PORT
 *
 * ON ENTRY:
 *	hostname	is the name of the server host machine.
 *	portnumber	is the port that the server is running in.
 *	docname		is the (URL-)pathname of the document we
 *			are trying to access.
 *	IsProxy		should be TRUE if this is a proxy.
 *
 *	This function goes through the information known about
 *	all the setups of the server, and finds out if the given
 *	filename resides in one of the protected directories.
 *
 * ON EXIT:
 *	returns		NULL if no match.
 *			Otherwise, a HTAASetup structure representing
 *			the protected server setup on the corresponding
 *			document tree.
 *
 */
static HTAASetup *HTAASetup_lookup(const char *hostname,
				   int portnumber,
				   const char *docname,
325
				   int IsProxy)
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
{
    HTAAServer *server;
    HTAASetup *setup;

    if (portnumber <= 0)
	portnumber = 80;

    if (hostname && docname && *hostname && *docname &&
	NULL != (server = HTAAServer_lookup(hostname,
					    portnumber,
					    IsProxy))) {

	HTList *cur = server->setups;

	CTRACE((tfp, "%s %s (%s:%d:%s)\n",
341 342 343
		"HTAASetup_lookup: resolving setup for",
		(IsProxy ? "proxy" : "server"),
		hostname, portnumber, docname));
344

345 346
	while (NULL != (setup = (HTAASetup *) HTList_nextObject(cur))) {
	    if (HTAA_templateMatch(setup->ctemplate, docname)) {
347
		CTRACE((tfp, "%s `%s' %s `%s'\n",
348 349
			"HTAASetup_lookup:", docname,
			"matched template", setup->ctemplate));
350 351 352
		return setup;
	    } else {
		CTRACE((tfp, "%s `%s' %s `%s'\n",
353 354
			"HTAASetup_lookup:", docname,
			"did NOT match template", setup->ctemplate));
355
	    }
356 357 358
	}			/* while setups remain */
    }
    /* if valid parameters and server found */
359
    CTRACE((tfp, "%s `%s' %s\n",
360 361 362
	    "HTAASetup_lookup: No template matched",
	    NONNULL(docname),
	    "(so probably not protected)"));
363

364
    return NULL;		/* NULL in parameters, or not found */
365 366
}

367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
/* static						HTAASetup_new()
 *			CREATE A NEW SETUP NODE
 * ON ENTRY:
 *	server		is a pointer to a HTAAServer structure
 *			to which this setup belongs.
 *	ctemplate	documents matching this template
 *			are protected according to this setup.
 *	valid_schemes	a list containing all valid authentication
 *			schemes for this setup.
 *			If NULL, all schemes are disallowed.
 *	scheme_specifics is an array of assoc lists, which
 *			contain scheme specific parameters given
 *			by server in Authenticate: fields.
 *			If NULL, all scheme specifics are
 *			set to NULL.
 * ON EXIT:
 *	returns		a new HTAASetup node, and also adds it as
 *			part of the HTAAServer given as parameter.
 */
static HTAASetup *HTAASetup_new(HTAAServer *server, char *ctemplate,
				HTList *valid_schemes,
				HTAssocList **scheme_specifics)
389 390 391
{
    HTAASetup *setup;

392
    if (!server || isEmpty(ctemplate))
393 394 395 396 397 398 399
	return NULL;

    if ((setup = typecalloc(HTAASetup)) == 0)
	outofmem(__FILE__, "HTAASetup_new");

    setup->retry = NO;
    setup->server = server;
400 401 402
    setup->ctemplate = NULL;
    if (ctemplate)
	StrAllocCopy(setup->ctemplate, ctemplate);
403 404 405
    setup->valid_schemes = valid_schemes;
    setup->scheme_specifics = scheme_specifics;

406
    HTList_addObject(server->setups, (void *) setup);
407 408 409 410

    return setup;
}

411 412 413 414 415 416 417 418 419
/* static						HTAASetup_delete()
 *			FREE A HTAASetup STRUCTURE
 * ON ENTRY:
 *	killme		is a pointer to the structure to free().
 *
 * ON EXIT:
 *	returns		nothing.
 */
static void HTAASetup_delete(HTAASetup * killme)
420 421 422 423
{
    int scheme;

    if (killme) {
424
	FREE(killme->ctemplate);
425 426 427 428 429 430 431 432 433 434 435 436
	if (killme->valid_schemes) {
	    HTList_delete(killme->valid_schemes);
	    killme->valid_schemes = NULL;
	}
	for (scheme = 0; scheme < HTAA_MAX_SCHEMES; scheme++)
	    if (killme->scheme_specifics[scheme])
		HTAssocList_delete(killme->scheme_specifics[scheme]);
	FREE(killme->scheme_specifics);
	FREE(killme);
    }
}

437 438 439 440 441 442 443 444 445 446 447 448 449 450
/* static					HTAASetup_updateSpecifics()
 *		COPY SCHEME SPECIFIC PARAMETERS
 *		TO HTAASetup STRUCTURE
 * ON ENTRY:
 *	setup		destination setup structure.
 *	specifics	string array containing scheme
 *			specific parameters for each scheme.
 *			If NULL, all the scheme specific
 *			parameters are set to NULL.
 *
 * ON EXIT:
 *	returns		nothing.
 */
static void HTAASetup_updateSpecifics(HTAASetup * setup, HTAssocList **specifics)
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
{
    int scheme;

    if (setup) {
	if (setup->scheme_specifics) {
	    for (scheme = 0; scheme < HTAA_MAX_SCHEMES; scheme++) {
		if (setup->scheme_specifics[scheme])
		    HTAssocList_delete(setup->scheme_specifics[scheme]);
	    }
	    FREE(setup->scheme_specifics);
	}
	setup->scheme_specifics = specifics;
    }
}

/*************************** HTAARealm **********************************/

468 469 470 471 472 473 474 475 476 477 478
/* static						HTAARealm_lookup()
 *		LOOKUP HTAARealm STRUCTURE BY REALM NAME
 * ON ENTRY:
 *	realm_table	a list of realm objects.
 *	realmname	is the name of realm to look for.
 *
 * ON EXIT:
 *	returns		the realm.  NULL, if not found.
 */
static HTAARealm *HTAARealm_lookup(HTList *realm_table,
				   const char *realmname)
479 480 481 482 483
{
    if (realm_table && realmname) {
	HTList *cur = realm_table;
	HTAARealm *realm;

484 485
	while (NULL != (realm = (HTAARealm *) HTList_nextObject(cur))) {
	    if (0 == strcmp(realm->realmname, realmname))
486 487 488
		return realm;
	}
    }
489
    return NULL;		/* No table, NULL param, or not found */
490 491
}

492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
/* static						HTAARealm_new()
 *		CREATE A NODE CONTAINING USERNAME AND
 *		PASSWORD USED FOR THE GIVEN REALM.
 *		IF REALM ALREADY EXISTS, CHANGE
 *		USERNAME/PASSWORD.
 * ON ENTRY:
 *	realm_table	a list of realms to where to add
 *			the new one, too.
 *	realmname	is the name of the password domain.
 *	username	and
 *	password	are what you can expect them to be.
 *
 * ON EXIT:
 *	returns		the created realm.
 */
static HTAARealm *HTAARealm_new(HTList *realm_table,
				const char *realmname,
				const char *username,
				const char *password)
511 512 513 514 515 516 517
{
    HTAARealm *realm;

    realm = HTAARealm_lookup(realm_table, realmname);

    if (!realm) {
	if ((realm = typecalloc(HTAARealm)) == 0)
518 519
	      outofmem(__FILE__, "HTAARealm_new");

520 521 522 523 524
	realm->realmname = NULL;
	realm->username = NULL;
	realm->password = NULL;
	StrAllocCopy(realm->realmname, realmname);
	if (realm_table)
525
	    HTList_addObject(realm_table, (void *) realm);
526 527 528 529 530 531 532 533 534
    }
    if (username)
	StrAllocCopy(realm->username, username);
    if (password)
	StrAllocCopy(realm->password, password);

    return realm;
}

535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
BOOL HTAA_HaveUserinfo(const char *hostname)
{
    int gen_delims = 0;
    char *my_info = NULL;
    char *at_sign = HTSkipToAt(StrAllocCopy(my_info, hostname), &gen_delims);

    free(my_info);
    return (at_sign != NULL && gen_delims == 0) ? TRUE : FALSE;
}

/*
 * If there is userinfo in the hostname string, update the realm to use that
 * information.  The command-line "-auth" option will override this.
 */
static void fill_in_userinfo(HTAARealm *realm, const char *hostname)
{
    int gen_delims = 0;
    char *my_info = NULL;
    char *at_sign = HTSkipToAt(StrAllocCopy(my_info, hostname), &gen_delims);

    if (at_sign != NULL && gen_delims == 0) {
	char *colon;

	*at_sign = '\0';
	if ((colon = StrChr(my_info, ':')) != 0) {
	    *colon++ = '\0';
	}
	if (non_empty(my_info)) {
	    char *msg;
	    BOOL prior = non_empty(realm->username);

	    if (prior && strcmp(realm->username, my_info)) {
		msg = 0;
		HTSprintf0(&msg,
			   gettext("username for realm %s changed from %s to %s"),
			   realm->realmname,
			   realm->username,
			   my_info);
		HTAlert(msg);
		free(msg);
		FREE(realm->username);
		StrAllocCopy(realm->username, my_info);
	    } else if (!prior) {
		StrAllocCopy(realm->username, my_info);
	    }
	    if (non_empty(colon)) {
		prior = non_empty(realm->password);
		if (prior && strcmp(realm->password, colon)) {
		    msg = 0;
		    HTSprintf0(&msg,
			       gettext("password for realm %s user %s changed"),
			       realm->realmname,
			       realm->username);
		    HTAlert(msg);
		    free(msg);
		    FREE(realm->password);
		    StrAllocCopy(realm->password, colon);
		} else if (!prior) {
		    StrAllocCopy(realm->password, colon);
		}
	    }
	}
    }
    free(my_info);
}

601 602
/***************** Basic and Pubkey Authentication ************************/

603 604 605 606 607 608
/* static						compose_auth_string()
 *
 *		COMPOSE Basic OR Pubkey AUTHENTICATION STRING;
 *		PROMPTS FOR USERNAME AND PASSWORD IF NEEDED
 *
 * ON ENTRY:
609
 *	hostname	may include user- and password information
610 611 612 613 614 615 616 617 618 619 620 621 622 623 624
 *	scheme		is either HTAA_BASIC or HTAA_PUBKEY.
 *	setup		is the current server setup.
 *	IsProxy		should be TRUE if this is a proxy.
 *
 * ON EXIT:
 *	returns		a newly composed authorization string,
 *			(with, of course, a newly generated secret
 *			key and fresh timestamp, if Pubkey-scheme
 *			is being used).
 *			NULL, if something fails.
 * NOTE:
 *	Like throughout the entire AA package, no string or structure
 *	returned by AA package needs to (or should) be freed.
 *
 */
625 626 627 628
static char *compose_auth_string(const char *hostname,
				 HTAAScheme scheme,
				 HTAASetup * setup,
				 int IsProxy)
629 630 631
{
    char *cleartext = NULL;	/* Cleartext presentation */
    char *ciphertext = NULL;	/* Encrypted presentation */
632
    size_t len;
633 634 635 636 637 638 639 640
    char *msg = NULL;
    char *username = NULL;
    char *password = NULL;
    char *realmname = NULL;
    char *theHost = NULL;
    char *proxiedHost = NULL;
    char *thePort = NULL;
    HTAARealm *realm;
641 642
    const char *i_net_addr = "0.0.0.0";		/* Change... @@@@ */
    const char *timestamp = "42";	/* ... these @@@@ */
643 644 645

    FREE(compose_auth_stringResult);	/* From previous call */

646 647 648 649 650 651
    if ((scheme != HTAA_BASIC && scheme != HTAA_PUBKEY) ||
	!(setup &&
	  setup->scheme_specifics &&
	  setup->scheme_specifics[scheme] &&
	  setup->server &&
	  setup->server->realms))
652 653 654 655 656 657 658
	return NULL;

    realmname = HTAssocList_lookup(setup->scheme_specifics[scheme], "realm");
    if (!realmname)
	return NULL;

    realm = HTAARealm_lookup(setup->server->realms, realmname);
659 660
    setup->retry |= HTAA_HaveUserinfo(hostname);

661
    if (!(realm &&
662 663
	  non_empty(realm->username) &&
	  non_empty(realm->password)) || setup->retry) {
664 665
	if (!realm) {
	    CTRACE((tfp, "%s `%s' %s\n",
666 667
		    "compose_auth_string: realm:", realmname,
		    "not found -- creating"));
668 669 670
	    realm = HTAARealm_new(setup->server->realms,
				  realmname, NULL, NULL);
	}
671
	fill_in_userinfo(realm, hostname);
672
	/*
673 674 675 676 677 678
	 * The template should be either the '*' global for everything on the
	 * server (always true for proxy authorization setups), or a path for
	 * the start of a protected limb, with no host field, but we'll check
	 * for a host anyway in case a WWW-Protection-Template header set an
	 * absolute URL instead of a path.  If we do get a host from this, it
	 * will include the port.  - FM
679
	 */
680 681
	if ((!IsProxy) && using_proxy && setup->ctemplate) {
	    proxiedHost = HTParse(setup->ctemplate, "", PARSE_HOST);
682 683 684 685 686
	    if (proxiedHost && *proxiedHost != '\0') {
		theHost = proxiedHost;
	    }
	}
	/*
687 688
	 * If we didn't get a host field from the template, set up the host
	 * name and port from the setup->server elements.  - FM
689 690 691 692 693 694 695
	 */
	if (!theHost)
	    theHost = setup->server->hostname;
	if (setup->server->portnumber > 0 &&
	    setup->server->portnumber != 80) {
	    HTSprintf0(&thePort, ":%d", setup->server->portnumber);
	}
696

697
	HTSprintf0(&msg, gettext("Username for '%s' at %s '%s%s':"),
698 699 700 701
		   realm->realmname,
		   (IsProxy ? "proxy" : "server"),
		   (theHost ? theHost : "??"),
		   NonNull(thePort));
702 703
	FREE(proxiedHost);
	FREE(thePort);
704 705 706 707 708 709
	if (non_empty(realm->username)) {
	    StrAllocCopy(username, realm->username);
	}
	if (non_empty(realm->password)) {
	    StrAllocCopy(password, realm->password);
	}
710 711 712 713 714
	HTPromptUsernameAndPassword(msg, &username, &password, IsProxy);

	FREE(msg);
	FREE(realm->username);
	FREE(realm->password);
715

716 717 718 719 720
	realm->username = username;
	realm->password = password;

	if (!realm->username || !realm->password) {
	    /*
721
	     * Signals to retry.  - FM
722 723 724 725
	     */
	    return NULL;
	} else if (*realm->username == '\0') {
	    /*
726
	     * Signals to abort.  - FM
727 728 729 730 731 732
	     */
	    StrAllocCopy(compose_auth_stringResult, "");
	    return compose_auth_stringResult;
	}
    }

733 734
    len = (strlen(NonNull(realm->username)) +
	   strlen(NonNull(realm->password)) + 3);
735 736 737 738 739 740 741

    if (scheme == HTAA_PUBKEY) {
#ifdef PUBKEY
	/* Generate new secret key */
	StrAllocCopy(secret_key, HTAA_generateRandomKey());
#endif /* PUBKEY */
	/* Room for secret key, timestamp and inet address */
742
	len += strlen(NonNull(secret_key)) + 30;
743 744 745 746 747
    } else {
	FREE(secret_key);
    }

    if ((cleartext = typecallocn(char, len)) == 0)
748
	  outofmem(__FILE__, "compose_auth_string");
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769

    if (realm->username)
	strcpy(cleartext, realm->username);
    else
	*cleartext = '\0';

    strcat(cleartext, ":");

    if (realm->password)
	strcat(cleartext, realm->password);

    if (scheme == HTAA_PUBKEY) {
	strcat(cleartext, ":");
	strcat(cleartext, i_net_addr);
	strcat(cleartext, ":");
	strcat(cleartext, timestamp);
	strcat(cleartext, ":");
	if (secret_key)
	    strcat(cleartext, secret_key);

	if (!((ciphertext = typecallocn(char, 2 * len)) &&
770 771 772
	        (compose_auth_stringResult = typecallocn(char, 3 * len))))
	      outofmem(__FILE__, "compose_auth_string");

773 774
#ifdef PUBKEY
	HTPK_encrypt(cleartext, ciphertext, server->public_key);
775
	HTUU_encode((unsigned char *) ciphertext, strlen(ciphertext),
776 777 778 779
		    compose_auth_stringResult);
#endif /* PUBKEY */
	FREE(cleartext);
	FREE(ciphertext);
780
    } else {			/* scheme == HTAA_BASIC */
781
	if (!(compose_auth_stringResult =
782 783 784 785
	      typecallocn(char, (4 * ((len + 2) / 3)) + 1)))
	      outofmem(__FILE__, "compose_auth_string");

	HTUU_encode((unsigned char *) cleartext, strlen(cleartext),
786 787 788 789 790 791
		    compose_auth_stringResult);
	FREE(cleartext);
    }
    return compose_auth_stringResult;
}

792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810
/* BROWSER static					HTAA_selectScheme()
 *		SELECT THE AUTHENTICATION SCHEME TO USE
 * ON ENTRY:
 *	setup	is the server setup structure which can
 *		be used to make the decision about the
 *		used scheme.
 *
 *	When new authentication methods are added to library
 *	this function makes the decision about which one to
 *	use at a given time.  This can be done by inspecting
 *	environment variables etc.
 *
 *	Currently only searches for the first valid scheme,
 *	and if nothing found suggests Basic scheme;
 *
 * ON EXIT:
 *	returns	the authentication scheme to use.
 */
static HTAAScheme HTAA_selectScheme(HTAASetup * setup)
811
{
812
    int scheme;
813 814

    if (setup && setup->valid_schemes) {
815
	for (scheme = HTAA_BASIC; scheme < HTAA_MAX_SCHEMES; scheme++) {
816
	    void *object = (void *) (intptr_t) scheme;
817

818
	    if (-1 < HTList_indexOf(setup->valid_schemes, object))
819
		return (HTAAScheme) scheme;
820
	}
821 822 823 824 825
    }
    return HTAA_BASIC;
}

/*
826 827 828 829 830 831 832 833 834
 *  Purpose:	Free off all module globals.
 *  Arguments:	void
 *  Return Value:	void
 *  Remarks/Portability/Dependencies/Restrictions:
 *	To be used at program exit.
 *  Revision History:
 *	06-19-96	created - FM
 */
static void free_HTAAGlobals(void)
835
{
836
    HTAAServer *server;
837 838 839 840 841
    int n, i;

    if (server_table != NULL) {
	n = HTList_count(server_table);
	for (i = (n - 1); i >= 0; i--) {
842 843
	    if ((server = (HTAAServer *) HTList_objectAt(server_table,
							 i)) != NULL) {
844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862
		HTAAServer_delete(server);
		server = NULL;
	    }
	}
	HTList_delete(server_table);
	server_table = NULL;
    }

    HTAAForwardAuth_reset();
    FREE(HTAA_composeAuthResult);
    FREE(current_hostname);
    FREE(current_docname);
    FREE(proxy_hostname);
    FREE(proxy_docname);
    FREE(compose_auth_stringResult);
    FREE(secret_key);
}

/* BROWSER PUBLIC					HTAA_composeAuth()
863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884
 *
 *	SELECT THE AUTHENTICATION SCHEME AND
 *	COMPOSE THE ENTIRE AUTHORIZATION HEADER LINE
 *	IF WE ALREADY KNOW THAT THE HOST REQUIRES AUTHENTICATION
 *
 * ON ENTRY:
 *	hostname	is the hostname of the server.
 *	portnumber	is the portnumber in which the server runs.
 *	docname		is the pathname of the document (as in URL)
 *	IsProxy		should be TRUE if this is a proxy.
 *
 * ON EXIT:
 *	returns	NULL, if no authorization seems to be needed, or
 *		if it is the entire Authorization: line, e.g.
 *
 *		   "Authorization: Basic username:password"
 *
 *		As usual, this string is automatically freed.
 */
char *HTAA_composeAuth(const char *hostname,
		       const int portnumber,
		       const char *docname,
885
		       int IsProxy)
886 887 888 889
{
    char *auth_string;
    BOOL retry;
    HTAAScheme scheme;
890
    size_t len;
891 892

    /*
893 894
     * Setup atexit() freeing if not done already.  - FM
     */
895 896 897 898 899 900 901 902
    if (!free_HTAAGlobalsSet) {
#ifdef LY_FIND_LEAKS
	atexit(free_HTAAGlobals);
#endif
	free_HTAAGlobalsSet = TRUE;
    }

    /*
903 904 905 906 907 908 909
     * Make gateway httpds pass authorization field as it was received.  (This
     * still doesn't really work because Authenticate:  headers from remote
     * server are not forwarded to client yet so it cannot really know that it
     * should send authorization; I will not implement it yet because I feel we
     * will soon change radically the way requests are represented to allow
     * multithreading on server-side.  Life is hard.)
     */
910 911
    if (HTAAForwardAuth) {
	CTRACE((tfp, "HTAA_composeAuth: %s\n",
912
		"Forwarding received authorization"));
913 914 915 916 917 918 919 920 921
	StrAllocCopy(HTAA_composeAuthResult, HTAAForwardAuth);
	HTAAForwardAuth_reset();	/* Just a precaution */
	return HTAA_composeAuthResult;
    }

    FREE(HTAA_composeAuthResult);	/* From previous call */

    if (IsProxy) {
	/*
922 923
	 * Proxy Authorization required.  - AJL
	 */
924 925

	CTRACE((tfp, "Composing Proxy Authorization for %s:%d/%s\n",
926
		hostname, portnumber, docname));
927

928 929 930
	if (proxy_portnumber != portnumber ||
	    !proxy_hostname || !proxy_docname ||
	    !hostname || !docname ||
931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958
	    0 != strcmp(proxy_hostname, hostname) ||
	    0 != strcmp(proxy_docname, docname)) {

	    retry = NO;

	    proxy_portnumber = portnumber;

	    if (hostname)
		StrAllocCopy(proxy_hostname, hostname);
	    else
		FREE(proxy_hostname);

	    if (docname)
		StrAllocCopy(proxy_docname, docname);
	    else
		FREE(proxy_docname);
	} else {
	    retry = YES;
	}

	if (!proxy_setup || !retry)
	    proxy_setup = HTAASetup_lookup(hostname, portnumber,
					   docname, IsProxy);

	if (!proxy_setup)
	    return NULL;

	switch (scheme = HTAA_selectScheme(proxy_setup)) {
959 960
	case HTAA_BASIC:
	case HTAA_PUBKEY:
961
	    auth_string = compose_auth_string(hostname, scheme, proxy_setup, IsProxy);
962
	    break;
963
	case HTAA_KERBEROS_V4:
964
	    /* OTHER AUTHENTICATION ROUTINES ARE CALLED HERE */
965
	default:
966 967
	    {
		char *msg = NULL;
968

969
		HTSprintf0(&msg, "%s `%s'",
970 971
			   gettext("This client doesn't know how to compose proxy authorization information for scheme"),
			   HTAAScheme_name(scheme));
972 973 974 975
		HTAlert(msg);
		FREE(msg);
		auth_string = NULL;
	    }
976
	}			/* switch scheme */
977 978 979 980 981

	proxy_setup->retry = NO;

	if (!auth_string)
	    /*
982 983 984
	     * Signal a failure.  - FM
	     */
	    return NULL;	/* Added by marca. */
985 986
	if (*auth_string == '\0') {
	    /*
987 988
	     * Signal an abort.  - FM
	     */
989
	    StrAllocCopy(HTAA_composeAuthResult, "");
990
	    return (HTAA_composeAuthResult);
991
	}
992
	len = strlen(auth_string) + strlen(HTAAScheme_name(scheme)) + 26;
993
	if ((HTAA_composeAuthResult = typecallocn(char, len)) == 0)
994 995
	      outofmem(__FILE__, "HTAA_composeAuth");

996 997 998 999
	strcpy(HTAA_composeAuthResult, "Proxy-Authorization: ");

    } else {
	/*
1000 1001
	 * Normal WWW authorization.
	 */
1002
	CTRACE((tfp, "Composing Authorization for %s:%d/%s\n",
1003
		hostname, portnumber, docname));
1004 1005 1006

	if (current_portnumber != portnumber ||
	    !current_hostname || !current_docname ||
1007
	    !hostname || !docname ||
1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035
	    0 != strcmp(current_hostname, hostname) ||
	    0 != strcmp(current_docname, docname)) {

	    retry = NO;

	    current_portnumber = portnumber;

	    if (hostname)
		StrAllocCopy(current_hostname, hostname);
	    else
		FREE(current_hostname);

	    if (docname)
		StrAllocCopy(current_docname, docname);
	    else
		FREE(current_docname);
	} else {
	    retry = YES;
	}

	if (!current_setup || !retry)
	    current_setup = HTAASetup_lookup(hostname, portnumber,
					     docname, IsProxy);

	if (!current_setup)
	    return NULL;

	switch (scheme = HTAA_selectScheme(current_setup)) {
1036 1037
	case HTAA_BASIC:
	case HTAA_PUBKEY:
1038
	    auth_string = compose_auth_string(hostname, scheme, current_setup, IsProxy);
1039
	    break;
1040
	case HTAA_KERBEROS_V4:
1041
	    /* OTHER AUTHENTICATION ROUTINES ARE CALLED HERE */
1042
	default:
1043 1044
	    {
		char *msg = 0;
1045

1046
		HTSprintf0(&msg, "%s `%s'",
1047 1048
			   gettext("This client doesn't know how to compose authorization information for scheme"),
			   HTAAScheme_name(scheme));
1049 1050 1051 1052
		HTAlert(msg);
		FREE(msg);
		auth_string = NULL;
	    }
1053
	}			/* switch scheme */
1054 1055 1056 1057 1058

	current_setup->retry = NO;

	if (!auth_string)
	    /*
1059 1060 1061
	     * Signal a failure.  - FM
	     */
	    return NULL;	/* Added by marca. */
1062 1063
	if (*auth_string == '\0') {
	    /*
1064 1065
	     * Signal an abort.  - FM
	     */
1066
	    StrAllocCopy(HTAA_composeAuthResult, "");
1067
	    return (HTAA_composeAuthResult);
1068 1069
	}

1070
	len = strlen(auth_string) + strlen(HTAAScheme_name(scheme)) + 20;
1071
	if ((HTAA_composeAuthResult = typecallocn(char, len)) == 0)
1072 1073
	      outofmem(__FILE__, "HTAA_composeAuth");

1074 1075 1076 1077 1078 1079 1080 1081 1082 1083
	strcpy(HTAA_composeAuthResult, "Authorization: ");
    }

    strcat(HTAA_composeAuthResult, HTAAScheme_name(scheme));
    strcat(HTAA_composeAuthResult, " ");
    strcat(HTAA_composeAuthResult, auth_string);
    return HTAA_composeAuthResult;
}

/* BROWSER PUBLIC				HTAA_shouldRetryWithAuth()
1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111
 *
 *		DETERMINES IF WE SHOULD RETRY THE SERVER
 *		WITH AUTHORIZATION
 *		(OR IF ALREADY RETRIED, WITH A DIFFERENT
 *		USERNAME AND/OR PASSWORD (IF MISSPELLED))
 * ON ENTRY:
 *	start_of_headers is the first block already read from socket,
 *			but status line skipped; i.e., points to the
 *			start of the header section.
 *	length		is the remaining length of the first block.
 *	soc		is the socket to read the rest of server reply.
 *	IsProxy		should be TRUE if this is a proxy.
 *
 *			This function should only be called when
 *			server has replied with a 401 (Unauthorized)
 *			status code.
 * ON EXIT:
 *	returns		YES, if connection should be retried.
 *			     The node containing all the necessary
 *			     information is
 *				* either constructed if it does not exist
 *				* or password is reset to NULL to indicate
 *				  that username and password should be
 *				  reprompted when composing Authorization:
 *				  field (in function HTAA_composeAuth()).
 *			NO, otherwise.
 */
BOOL HTAA_shouldRetryWithAuth(char *start_of_headers,
1112
			      size_t length,
1113
			      int soc,
1114
			      int IsProxy)
1115 1116 1117 1118 1119 1120
{
    HTAAScheme scheme;
    char *line = NULL;
    int num_schemes = 0;
    HTList *valid_schemes = HTList_new();
    HTAssocList **scheme_specifics = NULL;
1121
    char *ctemplate = NULL;
1122
    char *temp = NULL;
1123
    BOOL result = NO;
1124 1125

    /*
1126 1127
     * Setup atexit() freeing if not done already.  - FM
     */
1128 1129 1130 1131 1132 1133 1134 1135
    if (!free_HTAAGlobalsSet) {
#ifdef LY_FIND_LEAKS
	atexit(free_HTAAGlobals);
#endif
	free_HTAAGlobalsSet = TRUE;
    }

    /*
1136 1137
     * Read server reply header lines
     */
1138 1139 1140
    CTRACE((tfp, "Server reply header lines:\n"));

    HTAA_setupReader(start_of_headers, length, soc);
1141
    while (NULL != (line = HTAA_getUnfoldedLine()) && *line != '\0') {
1142 1143
	CTRACE((tfp, "%s\n", line));

1144
	if (StrChr(line, ':')) {	/* Valid header line */
1145 1146 1147 1148 1149 1150 1151

	    char *p = line;
	    char *fieldname = HTNextField(&p);
	    char *arg1 = HTNextField(&p);
	    char *args = p;

	    if ((IsProxy &&
1152
		 0 == strcasecomp(fieldname, "Proxy-Authenticate:")) ||
1153
		(!IsProxy &&
1154
		 0 == strcasecomp(fieldname, "WWW-Authenticate:"))) {
1155
		if (isEmpty(arg1) || isEmpty(args)) {
1156
		    HTSprintf0(&temp, gettext("Invalid header '%s%s%s%s%s'"), line,
1157 1158 1159 1160
			       (non_empty(arg1) ? " " : ""),
			       NonNull(arg1),
			       (non_empty(args) ? " " : ""),
			       NonNull(args));
1161 1162
		    HTAlert(temp);
		    FREE(temp);
1163 1164
		} else if (HTAA_UNKNOWN != (scheme = HTAAScheme_enum(arg1))) {
		    HTList_addObject(valid_schemes, (void *) scheme);
1165 1166
		    if (!scheme_specifics) {
			int i;
1167

1168 1169
			scheme_specifics =
			    typecallocn(HTAssocList *, HTAA_MAX_SCHEMES);
1170

1171 1172
			if (!scheme_specifics)
			    outofmem(__FILE__, "HTAA_shouldRetryWithAuth");
1173

1174
			for (i = 0; i < HTAA_MAX_SCHEMES; i++)
1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188
			    scheme_specifics[i] = NULL;
		    }
		    scheme_specifics[scheme] = HTAA_parseArgList(args);
		    num_schemes++;
		} else {
		    CTRACE((tfp, "Unknown scheme `%s' %s\n",
			    NONNULL(arg1),
			    (IsProxy ?
			     "in Proxy-Authenticate: field" :
			     "in WWW-Authenticate: field")));
		}
	    }

	    else if (!IsProxy &&
1189
		     0 == strcasecomp(fieldname, "WWW-Protection-Template:")) {
1190
		CTRACE((tfp, "Protection template set to `%s'\n", arg1));
1191
		StrAllocCopy(ctemplate, arg1);
1192 1193
	    }

1194
	} else {
1195
	    CTRACE((tfp, "Invalid header line `%s' ignored\n", line));
1196
	}
1197 1198

	FREE(line);
1199
    }				/* while header lines remain */
1200 1201 1202
    FREE(line);

    /*
1203 1204
     * So should we retry with authorization?
     */
1205 1206 1207
    if (IsProxy) {
	if (num_schemes == 0) {
	    /*
1208 1209
	     * No proxy authorization valid
	     */
1210
	    proxy_setup = NULL;
1211
	    result = NO;
1212 1213
	}
	/*
1214 1215
	 * Doing it for proxy.  -AJL
	 */
1216
	else if (proxy_setup && proxy_setup->server) {
1217
	    /*
1218 1219 1220 1221 1222 1223
	     * We have already tried with proxy authorization.  Either we don't
	     * have access or username or password was misspelled.
	     *
	     * Update scheme-specific parameters (in case they have expired by
	     * chance).
	     */
1224 1225 1226 1227
	    HTAASetup_updateSpecifics(proxy_setup, scheme_specifics);

	    if (NO == HTConfirm(AUTH_FAILED_PROMPT)) {
		proxy_setup = NULL;
1228
		result = NO;
1229 1230
	    } else {
		/*
1231 1232
		 * Re-ask username+password (if misspelled).
		 */
1233
		HTList_delete(valid_schemes);
1234
		proxy_setup->retry = YES;
1235
		result = YES;
1236 1237 1238
	    }
	} else {
	    /*
1239 1240 1241 1242
	     * proxy_setup == NULL, i.e., we have a first connection to a
	     * protected server or the server serves a wider set of documents
	     * than we expected so far.
	     */
1243 1244 1245
	    HTAAServer *server = HTAAServer_lookup(proxy_hostname,
						   proxy_portnumber,
						   IsProxy);
1246

1247 1248 1249 1250 1251
	    if (!server) {
		server = HTAAServer_new(proxy_hostname,
					proxy_portnumber,
					IsProxy);
	    }
1252 1253
	    if (!ctemplate)	/* Proxy matches everything  -AJL */
		StrAllocCopy(ctemplate, "*");
1254
	    proxy_setup = HTAASetup_new(server,
1255 1256 1257 1258
					ctemplate,
					valid_schemes,
					scheme_specifics);
	    FREE(ctemplate);
1259 1260

	    HTAlert(gettext("Proxy authorization required -- retrying"));
1261
	    result = YES;
1262 1263 1264
	}
    }
    /*
1265 1266
     * Normal WWW authorization.
     */
1267
    else if (num_schemes == 0) {
1268
	/*
1269 1270
	 * No authorization valid.
	 */
1271
	current_setup = NULL;
1272 1273
	result = NO;
    } else if (current_setup && current_setup->server) {
1274
	/*
1275 1276 1277 1278 1279 1280
	 * So we have already tried with WWW authorization.  Either we don't
	 * have access or username or password was misspelled.
	 *
	 * Update scheme-specific parameters (in case they have expired by
	 * chance).
	 */
1281 1282 1283 1284
	HTAASetup_updateSpecifics(current_setup, scheme_specifics);

	if (NO == HTConfirm(AUTH_FAILED_PROMPT)) {
	    current_setup = NULL;
1285
	    result = NO;
1286 1287
	} else {
	    /*
1288 1289
	     * Re-ask username+password (if misspelled).
	     */
1290
	    current_setup->retry = YES;
1291
	    result = YES;
1292 1293 1294
	}
    } else {
	/*
1295 1296 1297 1298
	 * current_setup == NULL, i.e., we have a first connection to a
	 * protected server or the server serves a wider set of documents than
	 * we expected so far.
	 */
1299 1300 1301
	HTAAServer *server = HTAAServer_lookup(current_hostname,
					       current_portnumber,
					       IsProxy);
1302

1303 1304 1305 1306 1307
	if (!server) {
	    server = HTAAServer_new(current_hostname,
				    current_portnumber,
				    IsProxy);
	}
1308 1309
	if (!ctemplate)
	    ctemplate = HTAA_makeProtectionTemplate(current_docname);
1310
	current_setup = HTAASetup_new(server,
1311
				      ctemplate,
1312 1313
				      valid_schemes,
				      scheme_specifics);
1314
	FREE(ctemplate);
1315 1316

	HTAlert(gettext("Access without authorization denied -- retrying"));
1317 1318 1319 1320 1321
	result = YES;
    }

    if (result == NO) {
	HTList_delete(valid_schemes);
1322
    }
1323
    return result;
1324 1325 1326
}

/*
1327 1328 1329 1330 1331 1332 1333 1334
 *  This function clears all authorization information by
 *  invoking the free_HTAAGlobals() function, which normally
 *  is invoked at exit.  It allows a browser command to do
 *  this at any time, for example, if the user is leaving
 *  the terminal for a period of time, but does not want
 *  to end the current session.  - FM
 */
void HTClearHTTPAuthInfo(void)
1335 1336
{
    /*
1337 1338 1339 1340
     * Need code to check cached documents against the protection templates,
     * and do something to ensure that any protected documents no longer can be
     * accessed without a new retrieval.  - FM
     */
1341 1342

    /*
1343 1344 1345
     * Now free all of the authorization info, and reset the
     * free_HTAAGlobalsSet flag.  - FM
     */
1346 1347 1348
    free_HTAAGlobals();
    free_HTAAGlobalsSet = FALSE;
}