--- /dev/null
+
+/*
+ * usersfile.c
+ * (C) 2000 Antonino Iannella, Stellar-X Pty Ltd
+ * Released under GPL, see COPYING-2.0 for details.
+ *
+ * These routines are to allow users attempting to use the proxy which
+ * have been explicitly allowed by the system administrator.
+ * The code originated from denyusers.c.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <time.h>
+#include <ctype.h>
+#include <sys/param.h>
+#include <fcntl.h>
+
+#include "usersfile.h"
+
+#define NAMELEN 50 /* Maximum username length */
+
+static int
+name_cmp(const void *a, const void *b)
+{
+ const char *A = a;
+ const char *B = b;
+ return strcasecmp(A, B);
+}
+
+static void
+free_names(usersfile * uf)
+{
+ int i;
+ for (i = 0; i < uf->Inuse; i++) {
+ if (uf->names[i])
+ free(uf->names[i]);
+ uf->names[i] = NULL;
+ }
+ uf->Inuse = 0;
+}
+
+/*
+ * Reads a file of usernames and stuffs them into an array
+ * of strings.
+ * Returns 0 if the user list was successfully loaded,
+ * and 1 in case of error.
+ */
+
+int
+Read_usersfile(const char *path, usersfile * uf)
+{
+ FILE *fp;
+ struct stat FileBuf;
+ char buf[1024];
+
+ free_names(uf);
+
+ if (NULL == path) {
+ path = uf->path;
+ } else {
+ if (uf->path)
+ free(uf->path);
+ uf->path = strdup(path);
+ }
+
+ /* Open the users file. Report any errors. */
+ fp = fopen(path, "r");
+ if (NULL == fp) {
+ uf->LMT = 0;
+ if (errno == ENOENT)
+ return 0;
+ syslog(LOG_ERR, "%s: %s", path, strerror(errno));
+ return 1;
+ }
+ /* Stat the file. If it does not exist, save the size as zero.
+ * Clear the allowed user string. Return. */
+ if (fstat(fileno(fp), &FileBuf) < 0) {
+ syslog(LOG_ERR, "%s: %s", path, strerror(errno));
+ return 1;
+ }
+ /* If it exists, save the modification time and size */
+ uf->LMT = FileBuf.st_mtime;
+
+ /* Handle the special case of a zero length file */
+ if (FileBuf.st_size == 0)
+ return 0;
+
+ /*
+ * Read the file into memory
+ * XXX assumes one username per input line
+ */
+ while (fgets(buf, 1024, fp) != NULL) {
+ /* ensure no names longer than our limit */
+ buf[NAMELEN] = '\0';
+ /* skip bad input lines */
+ if (NULL == strtok(buf, "\r\n"))
+ continue;
+ /* grow the list if necessary */
+ if (0 == uf->Alloc) {
+ uf->Alloc = 256;
+ uf->names = calloc(uf->Alloc, sizeof(*uf->names));
+ } else if (uf->Inuse == uf->Alloc) {
+ uf->Alloc = uf->Alloc << 1;
+ uf->names = realloc(uf->names, uf->Alloc);
+ /* zero out the newly allocated memory */
+ memset(uf->names[uf->Alloc >> 1],
+ '\0',
+ (uf->Alloc >> 1) * sizeof(*uf->names));
+ }
+ uf->names[uf->Inuse] = strdup(buf);
+ uf->Inuse++;
+ }
+ fclose(fp);
+ fp = NULL;
+
+ /* sort the names for searching */
+ qsort(uf->names, uf->Inuse, sizeof(*uf->names), name_cmp);
+
+ return 0;
+}
+
+/*
+ * Check to see if the username provided by Squid appears in the
+ * user list. Returns 0 if the user was not found, and 1 if they were.
+ */
+
+int
+Check_userlist(usersfile * uf, char *User)
+{
+ void *p;
+
+ /* Empty users are always in the list */
+ if (User[0] == '\0')
+ return 1;
+
+ /* If allowed user list is empty, allow all users.
+ * If no users are supposed to be using the proxy, stop squid instead. */
+ if (0 == uf->Inuse)
+ return 1;
+
+ /* Check if username string is found in the allowed user list.
+ * If so, allow. If not, deny. Reconstruct the username
+ * to have whitespace, to avoid finding wrong string subsets. */
+
+ p = bsearch(User,
+ uf->names,
+ uf->Inuse,
+ sizeof(*uf->names),
+ name_cmp);
+ if (NULL == p) {
+ syslog(LOG_DEBUG, "User %s not found", User);
+ return 0;
+ }
+ syslog(LOG_DEBUG, "User %s found", User);
+ return 1;
+}
+
+/*
+ * Checks if there has been a change in a users file.
+ * If the modification time has changed, then reload the user list.
+ */
+void
+Check_forfilechange(usersfile * uf)
+{
+ struct stat ChkBuf; /* Stat data buffer */
+
+ /* Stat the allowed users file. If it cannot be accessed, return. */
+
+ if (stat(uf->path, &ChkBuf) < 0) {
+ if (errno == ENOENT) {
+ uf->LMT = 0;
+ free_names(uf);
+ } else { /* Report error when accessing file */
+ syslog(LOG_ERR, "%s: %s", uf->path, strerror(errno));
+ }
+ return;
+ }
+ /* return if no change */
+ if (ChkBuf.st_mtime == uf->LMT)
+ return;
+
+ /*
+ * The file changed, so re-read it.
+ */
+ syslog(LOG_INFO, "Check_forchange: Reloading user list.");
+ Read_usersfile(NULL, uf);
+}