--- /dev/null
+.TH squid_session 8 "19 March 2006" "Version 1.0"
+.
+.SH NAME
+squid_session - Squid session tracking external acl group helper
+.
+.SH SYNOPSIS
+squid_session [-t idle_timeout] [-b dbpath] [-a]
+.
+.SH DESCRIPTION
+This helper maintains a concept of sessions by monitoring requests
+and timing out sessions if no requests have been seen for the idle timeout
+timer.
+.P
+Intended use is for displaying "terms of use" pages, ad popups etc.
+.
+.TP
+.BI "-t " "idletimeout " "(default 3600)"
+Specifies the session idle timeout timer.
+.
+.TP
+.BI "-b " "dbpath"
+Path to persistent database. If not specified the session details
+will be kept in memory only and all sessions will reset each time
+Squid restarts it's helpers (Squid restart or rotation of logs).
+.
+.TP
+.B "-a"
+Active mode. In this mode sessions are started by evaluating an
+acl with the argument LOGIN, or terminated by the argument LOGOUT.
+.P
+Without this flag the helper automatically starts the session after
+the first request.
+.
+.SH AUTHOR
+This helper and documentation was written by
+.I Henrik Nordstrom <henrik@henriknordstrom.net>
+.
+.SH QUESTIONS
+Any questions on usage can be sent to
+.IR "Squid Users <squid-users@squid-cache.org>" .
+.
+.SH REPORTING BUGS
+Report bugs or bug-fixes to
+.I Squid Bugs <squid-bugs@squid-cache.org>
+or ideas for new improvements to
+.I Squid Developers <squid-dev@squid-cache.org>
+.
+.SH "SEE ALSO"
+.BR squid ( 8 )
--- /dev/null
+/*
+ * squid_session: Squid external acl helper for tracking sessions
+ *
+ * Copyright (C) 2006 Henrik Nordstrom <henrik@henriknordstrom.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+
+#include <db_185.h>
+
+static int session_ttl = 3600;
+char *db_path = NULL;
+const char *program_name;
+
+DB *db = NULL;
+
+static void init_db(void)
+{
+ db = dbopen(db_path, O_CREAT | O_RDWR, 0666, DB_BTREE, NULL);
+ if (!db) {
+ fprintf(stderr, "%s: Failed to open session db '%s'\n", program_name, db_path);
+ exit(1);
+ }
+}
+
+static void shutdown_db(void)
+{
+ db->close(db);
+}
+
+int session_is_active = 0;
+
+static int session_active(const char *details)
+{
+ DBT key, data;
+ key.data = (void *)details;
+ key.size = strlen(details);
+ if (db->get(db, &key, &data, 0) == 0) {
+ time_t timestamp;
+ if (data.size != sizeof(timestamp)) {
+ fprintf(stderr, "%s: CORRUPTED DATABASE (%s)\n", program_name, details);
+ db->del(db, &key, 0);
+ return 0;
+ }
+ memcpy(×tamp, data.data, sizeof(timestamp));
+ if (timestamp + session_ttl >= time(NULL))
+ return 1;
+ }
+ return 0;
+}
+
+static void session_login(const char *details)
+{
+ DBT key, data;
+ time_t now = time(NULL);
+ key.data = (void *)details;
+ key.size = strlen(details);
+ data.data = &now;
+ data.size = sizeof(now);
+ db->put(db, &key, &data, 0);
+}
+
+static void session_logout(const char *details)
+{
+ DBT key;
+ key.data = (void *)details;
+ key.size = strlen(details);
+ db->del(db, &key, 0);
+}
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: %s [-t session_timeout] [-b dbpath] [-a]\n", program_name);
+ fprintf(stderr, " -t sessiontimeout Idle timeout after which sessions will be forgotten\n");
+ fprintf(stderr, " -b dbpath Path where persistent session database will be kept\n");
+ fprintf(stderr, " -a Active mode requiring LOGIN argument to start a session\n");
+}
+int main(int argc, char **argv)
+{
+ char request[256];
+ int opt;
+ int default_action = 1;
+
+ program_name = argv[0];
+
+ while ((opt = getopt(argc, argv, "t:b:a?")) != -1) {
+ switch(opt) {
+ case 't':
+ session_ttl = strtol(optarg, NULL, 0);
+ break;
+ case 'b':
+ db_path = optarg;
+ break;
+ case 'a':
+ default_action = 0;
+ break;
+ case '?':
+ usage();
+ exit(0);
+ break;
+ }
+ }
+
+ setbuf(stdout, NULL);
+
+ init_db();
+
+ while (fgets(request, sizeof(request), stdin)) {
+ const char *index, *detail;
+ char *lastdetail;
+ int action = 0;
+ index = strtok(request, " \n");
+ detail = strtok(NULL, "\n");
+ lastdetail = strrchr(detail, ' ');
+ if (lastdetail) {
+ if (strcmp(lastdetail, " LOGIN") == 0) {
+ *lastdetail++ = '\0';
+ action = 1;
+ } else if (strcmp(lastdetail, " LOGOUT") == 0) {
+ action = -1;
+ *lastdetail++ = '\0';
+ }
+ }
+ if (action == -1) {
+ session_logout(detail);
+ printf("%s OK message=\"Bye\"\n", index);
+ } else if (action == 1) {
+ session_login(detail);
+ printf("%s OK message=\"Welcome\"\n", index);
+ } else if (session_active(detail)) {
+ session_login(detail);
+ printf("%s OK\n", index);
+ } else if (default_action == 1) {
+ session_login(detail);
+ printf("%s ERR message=\"Welcome\"\n", index);
+ } else {
+ printf("%s ERR message=\"No session available\"\n", index);
+ }
+ }
+ shutdown_db();
+ return 0;
+}