/* squark-auth-ip.c - Squid User Authentication and Rating Kit * An external acl helper for Squid which collects authentication * information about an IP-address from local shared memory database. * * Copyright (C) 2010 Timo Teräs * All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. See http://www.gnu.org/ for details. */ #include #include #include #include "config.h" #include "blob.h" #include "authdb.h" #include "filterdb.h" #define DO_LOGIN -1 #define DO_OVERRIDE -2 #define DO_PRINT -3 #define DO_LOGOUT -4 #define DO_REFRESH -5 static int running = 1; static struct sqdb db; static struct authdb adb; static struct authdb_config adbc; static blob_t space = BLOB_STR_INIT(" "); static blob_t lf = BLOB_STR_INIT("\n"); static time_t now; static void handle_line(blob_t line) { char reply[128]; blob_t b, id, ipaddr; struct authdb_entry entry; sockaddr_any addr; void *token; int auth_ok = 0; id = blob_pull_cspn(&line, space); blob_pull_spn(&line, space); ipaddr = blob_pull_cspn(&line, space); if (addr_parse(ipaddr, &addr)) { token = authdb_get(&adb, &addr, &entry, 1); if (authdb_check_login(token, &entry, BLOB_NULL, now, &adbc)) auth_ok = 1; } b = BLOB_BUF(reply); blob_push(&b, id); if (auth_ok) { blob_push(&b, BLOB_STR(" OK user=")); blob_push(&b, BLOB_STRLEN(entry.p.login_name)); blob_push(&b, BLOB_PTR_LEN("\n", 1)); } else { blob_push(&b, BLOB_STR(" ERR\n")); } b = blob_pushed(BLOB_BUF(reply), b); write(STDOUT_FILENO, b.ptr, b.len); } static void read_input(void) { static char buffer[256]; static blob_t left; blob_t b, line; int r; if (blob_is_null(left)) left = BLOB_BUF(buffer); r = read(STDIN_FILENO, left.ptr, left.len); if (r < 0) return; if (r == 0) { running = 0; return; } left.ptr += r; left.len -= r; now = time(NULL); adbc_refresh(&adbc, now); b = blob_pushed(BLOB_BUF(buffer), left); do { line = blob_pull_cspn(&b, lf); if (!blob_pull_matching(&b, lf)) return; handle_line(line); if (b.len) { memcpy(buffer, b.ptr, b.len); b.ptr = buffer; } left = BLOB_PTR_LEN(buffer + b.len, sizeof(buffer) - b.len); } while (b.len); } #define DUMPPAR(b, name, fn) \ do { \ blob_push(b, BLOB_STR("squark_" name "='")); \ fn; \ blob_push(b, BLOB_STR("'; ")); \ } while (0) int main(int argc, char **argv) { int opt, rc = 1; sockaddr_any ipaddr = { .any.sa_family = AF_UNSPEC }; blob_t ip = BLOB_NULL, username = BLOB_NULL; while ((opt = getopt(argc, argv, "Vi:u:olpLr")) != -1) { switch (opt) { case 'V': fprintf(stderr, "squark-auth-ip %s\n", squark_version); return 0; case 'i': ip = BLOB_STRLEN(optarg); if (!addr_parse(ip, &ipaddr)) { fprintf(stderr, "'%s' does not look like IP-address\n", optarg); return 1; } break; case 'u': username = BLOB_STRLEN(optarg); break; case 'o': running = DO_OVERRIDE; break; case 'l': running = DO_LOGIN; break; case 'p': running = DO_PRINT; break; case 'L': running = DO_LOGOUT; break; case 'r': running = DO_REFRESH; break; } } now = time(NULL); if (sqdb_open(&db, squark_dbname) < 0) { fprintf(stderr, "%s: failed to open squarkdb\n", squark_dbname); goto err_sqdb; } if (authdb_open(&adb, &adbc, &db) < 0) { fprintf(stderr, "Failed to initialize authdb\n"); goto err_adb; } rc = 0; if (running < 0) { struct authdb_entry entry; void *token; if (ipaddr.any.sa_family == AF_UNSPEC) { fprintf(stderr, "IP-address not specified\n"); return 2; } token = authdb_get(&adb, &ipaddr, &entry, 1); if (token == NULL) { fprintf(stderr, "Failed to get authdb record\n"); return 3; } switch (running) { case DO_LOGIN: if (blob_is_null(username)) { fprintf(stderr, "Username not specified\n"); return 2; } authdb_clear_entry(&entry); memcpy(entry.p.login_name, username.ptr, username.len); authdb_commit_login(token, &entry, now, &adbc); break; case DO_REFRESH: if (!authdb_check_login(token, &entry, username, now, &adbc)) rc = 3; break; case DO_OVERRIDE: if (authdb_check_login(token, &entry, username, now, &adbc)) authdb_commit_override(token, &entry, now); break; case DO_PRINT: { char buf[512]; blob_t b = BLOB_BUF(buf); DUMPPAR(&b, "ip_address", addr_push_hostaddr(&b, &ipaddr)); DUMPPAR(&b, "username", blob_push(&b, BLOB_BUF(entry.p.login_name))); DUMPPAR(&b, "mac_address", blob_push_hexdump(&b, BLOB_BUF(entry.p.mac_address))); DUMPPAR(&b, "login_time", blob_push_ctime(&b, entry.p.login_time)); DUMPPAR(&b, "activity_time", blob_push_ctime(&b, entry.last_activity_time)); DUMPPAR(&b, "override_time", blob_push_ctime(&b, entry.override_time)); DUMPPAR(&b, "block_categories", blob_push_hexdump(&b, BLOB_BUF(&entry.p.block_categories))); DUMPPAR(&b, "hard_block_categories", blob_push_hexdump(&b, BLOB_BUF(&entry.p.hard_block_categories))); blob_push(&b, BLOB_STR("\n")); b = blob_pushed(BLOB_BUF(buf), b); fwrite(b.ptr, b.len, 1, stdout); break; } case DO_LOGOUT: if (authdb_check_login(token, &entry, username, now, &adbc)) authdb_commit_logout(token); break; } } else { while (running) read_input(); } authdb_close(&adb); err_adb: sqdb_close(&db); err_sqdb: return rc; }