/*
 * Squid auth module for qi servers.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>
#include <syslog.h>
#include <signal.h>
#include "qick.h"

static char rcsid[] = "$Id: qiauth.c,v 2.1 2000/08/18 19:27:34 dgc Exp $";

char *A0;		/* Je m'appelle */
int die = 0;		/* Wake up... it's time to die */

/* When alarm goes off, flag for death at earliest opportunity. */
void
timeout(int sig)
{
	/*
	syslog(LOG_INFO,
		"suicide: maximum lifespan reached (%d)",
		MAX_LIFESPAN);
	*/
	die = 1;
}

/*
 * Get up
 */
main(int argc, char *argv[])
{
	char	 buf[1024];
	char	*p, *user, *server, *pass;
	FILE	*nstdout;
	int	 i, fd, nauths = 0;
	int	 tryany;
	qi_t	*qi;
	qick_t	*qh;

	/* Decide what we're going to call ourselves. */
	if ((A0 = strrchr(argv[0], '/')) == NULL)
		A0 = argv[0];
	else
		++A0;

	/* Get down with the system log facility. */
	openlog(A0, LOG_PID, LOG_AUTH);

	/* Initialize the library. */
	if ((qh = qick_init()) == NULL) {
		fprintf(stderr, "%s: cannot initialize qick library\n", A0);
		exit(2);
	}

	/* Save the original stdout -- this is where we talk to squid. */
	fd = dup(1);
	nstdout = fdopen(fd, "w");
	close(1);

	/* Line-buffer to guarantee freshness. */
	setvbuf(stdin, NULL, _IOLBF, 0);
	setvbuf(nstdout, NULL, _IOLBF, 0);

	/* Init servers. */
	for (i = 1; i < argc; ++i) {
		qi_server(qh, argv[i]);
	}
	/* Take one default, if none were listed directly. */
	if (i == 1)
		qi_server(qh, QI_SERVER);

	/*
	 * If we get too old, we will get trapped.  Then we will die after
	 * any current query.
	 */
	signal(SIGALRM, timeout);
	alarm(qh->q_lifetime);

	/* As long as we shall live, listen on stdin for squid auth reqs. */
	while (!die && !qick_suicidal(qh) && fgets(buf, 1023, stdin)) {
		buf[1024] = '\0';
		if ((p = strchr(buf, '\r')) != NULL)
			*p = '\0';
		else if ((p = strchr(buf, '\n')) != NULL)
			*p = '\0';
		else {
			/* Asshole. */
			syslog(LOG_ALERT, "%s: buffer overrun attempt\n", A0);
			continue;
		}

		/* Skip empty reqs. */
		if (*buf == '\0')
			continue;

		/* Find username. */
		user = buf;
		while (isspace(*user))
			++user;

		/* If username begins with "ph:", discard it.  *sigh*.... */
		if (!strncmp(user, "ph:", 3) || !strncmp(user, "PH:", 3)) {
			user = &user[3];
			while (isspace(*user))
				++user;
		}

		/* Find the password. */
		pass = user;
		while (*pass && !isspace(*pass))
			++pass;
		*pass = '\0';
		++pass;
		while (*pass && isspace(*pass))
			++pass;
		p = pass;
		while (*p && !isspace(*p))
			++p;
		*p = '\0';

		/*
		 * Increment authentication counter -- this also causes
		 * death when it peaks.
		 */
		++nauths;

		/*
		 * If username contains '@', consider the RHS the only
		 *   permissible server name for this query.
		 * Else, if no cmdline args, use default server only.
		 * Else, use all cmdline-listed servers.
		 */
		if ((p = strchr(user, '@')) != NULL) {
			*p = '\0';
			qi = qi_server(qh, ++p);
			tryany = 0;
		} else {
			qi = qi_first(qh);
			tryany = 1;
		}

		/* Walk the server list, querying all servers on demand. */
		while (qi != NULL) {
			qi_debug("@ query %s@%s\n", user, qi->qi_host);
			p = qi_auth_svr(qi, user, pass);
			if (p == NULL) {
				syslog(LOG_INFO,
				"authenticated \"%s\" on \"%s\"",
					S(qi->qi_alias), S(qi->qi_host));
				fprintf(nstdout, "OK\n");
				fflush(nstdout);
				break;
			} else {
				syslog(LOG_ERR,
					"failed to authenticate %s@%s: %s",
				user, qi->qi_host, p);
			}
			if (tryany)
				qi = qi_next(qh);
			else
				qi = NULL;
		}

		/* If at list's end, report failure. */
		if (qi == NULL) {
			fprintf(nstdout, "ERR\n");
			fflush(nstdout);
		}

		/* Stop after MAX_AUTHS_PP authentications. */
		if (nauths == qh->q_max_queries) {
			syslog(LOG_INFO, "suicide: maximum authentications reached (%d)", qh->q_max_queries);
			++die;		/* Flag death, don't die directly. */
		}

	}

	/* We authenticated client. */
	return(0);
}


