/* * $Id: pam_auth-2.0.c,v 1.2 2002/01/07 03:30:19 hno Exp $ * * PAM authenticator module for Squid. * Copyright (C) 1999,2002 Henrik Nordstrom * * 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. * * Install instructions: * * This program authenticates users against a PAM configured authentication * service "squid". This allows you to authenticate Squid users to any * authentication source for which you have a PAM module. Commonly available * PAM modules includes "UNIX", RADIUS, Kerberos and SMB, but a lot of other * PAM modules are available from various sources. * * Example PAM configuration for standard UNIX passwd authentication: * /etc/pam.conf: * squid auth required /lib/security/pam_unix.so.1 * squid account required /lib/security/pam_unix.so.1 * * Note that some PAM modules (for example shadow password authentication) * requires the program to be installed suid root to gain access to the * user password database * * Change Log: * * Version 2.0, 2002-01-07 * One shot mode, command line options * man page * * Version 1.3, 1999-12-10 * Bugfix release 1.3 to work around Solaris 2.6 * brokenness (not sending arguments to conversation * functions) * * Version 1.2, internal release * * Version 1.1, 1999-05-11 * Initial version * * Compile this program with: gcc -o pam_auth pam_auth.c -lpam -ldl */ #include #include #include #include #include #include #include #include #define BUFSIZE 8192 /* The default PAM service name */ #ifndef DEFAULT_SQUID_PAM_SERVICE #define DEFAULT_SQUID_PAM_SERVICE "squid" #endif /* The default TTL */ #ifndef DEFAULT_SQUID_PAM_TTL #define DEFAULT_SQUID_PAM_TTL 60 #endif static char *password = NULL; /* Workaround for Solaris 2.6 brokenness */ /* * A simple "conversation" function returning the supplied password. * Has a bit to much error control, but this is my first PAM application * so I'd rather check everything than make any mistakes. The function * expects a single converstation message of type PAM_PROMPT_ECHO_OFF. */ static int password_conversation(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) { if (num_msg != 1 || msg[0]->msg_style != PAM_PROMPT_ECHO_OFF) { fprintf(stderr, "ERROR: Unexpected PAM converstaion '%d/%s'\n", msg[0]->msg_style, msg[0]->msg); return PAM_CONV_ERR; } if (!appdata_ptr) { /* Workaround for Solaris 2.6 where the PAM library is broken * and does not pass appdata_ptr to the conversation routine */ appdata_ptr = password; } if (!appdata_ptr) { fprintf(stderr, "ERROR: No password available to password_converstation!\n"); return PAM_CONV_ERR; } *resp = calloc(num_msg, sizeof(struct pam_response)); if (!*resp) { fprintf(stderr, "ERROR: Out of memory!\n"); return PAM_CONV_ERR; } (*resp)[0].resp = strdup((char *) appdata_ptr); (*resp)[0].resp_retcode = 0; return ((*resp)[0].resp ? PAM_SUCCESS : PAM_CONV_ERR); } static struct pam_conv conv = { &password_conversation, NULL }; static void usage(char *program) { fprintf(stderr, "Usage: %s [options..]\n", program); fprintf(stderr, " -n service_name\n"); fprintf(stderr, " The PAM service name (default \"%s\")\n", DEFAULT_SQUID_PAM_SERVICE); fprintf(stderr, " -t ttl PAM connection ttl in seconds (default %d)\n", DEFAULT_SQUID_PAM_TTL); fprintf(stderr, " during this time the same connection will be reused\n"); fprintf(stderr, " to authenticate all users\n"); fprintf(stderr, " -o Do not perform account mgmt (account expiration etc)\n"); fprintf(stderr, " -1 Only one user authentication per PAM connection\n"); } int main(int argc, char *argv[]) { pam_handle_t *pamh = NULL; int retval = PAM_SUCCESS; char *user; /* char *password; */ char buf[BUFSIZE]; time_t pamh_created = 0; int ttl = DEFAULT_SQUID_PAM_TTL; char *service = DEFAULT_SQUID_PAM_SERVICE; int no_acct_mgmt = 0; /* make standard output line buffered */ setvbuf(stdout, NULL, _IOLBF, 0); while (1) { int ch = getopt(argc, argv, "1n:t:o"); switch (ch) { case -1: goto start; case 'n': service = optarg; break; case 't': ttl = atoi(optarg); break; case '1': ttl = 0; break; case 'o': no_acct_mgmt = 1; break; default: fprintf(stderr, "Unknown getopt value '%c'\n", ch); usage(argv[0]); exit(1); } } start: if (optind < argc) { fprintf(stderr, "Unknown option '%s'\n", argv[optind]); usage(argv[0]); exit(1); } while (fgets(buf, BUFSIZE, stdin)) { user = buf; password = strchr(buf, '\n'); if (!password) { fprintf(stderr, "authenticator: Unexpected input '%s'\n", buf); goto error; } *password = '\0'; password = strchr(buf, ' '); if (!password) { fprintf(stderr, "authenticator: Unexpected input '%s'\n", buf); goto error; } *password++ = '\0'; conv.appdata_ptr = (char *) password; /* from buf above. not allocated */ if (ttl == 0) { /* Create PAM connection */ retval = pam_start(service, user, &conv, &pamh); if (retval != PAM_SUCCESS) { fprintf(stderr, "ERROR: failed to create PAM authenticator\n"); goto error; } } else if (!pamh || (time(NULL) - pamh_created) >= ttl || pamh_created > time(NULL)) { /* Close previous PAM connection */ if (pamh) { retval = pam_end(pamh, retval); if (retval != PAM_SUCCESS) { fprintf(stderr, "WARNING: failed to release PAM authenticator\n"); } pamh = NULL; } /* Initialize persistent PAM connection */ retval = pam_start(service, "squid@", &conv, &pamh); if (retval != PAM_SUCCESS) { fprintf(stderr, "ERROR: failed to create PAM authenticator\n"); goto error; } pamh_created = time(NULL); } retval = PAM_SUCCESS; if (ttl != 0) { if (retval == PAM_SUCCESS) retval = pam_set_item(pamh, PAM_USER, user); if (retval == PAM_SUCCESS) retval = pam_set_item(pamh, PAM_CONV, &conv); } if (retval == PAM_SUCCESS) retval = pam_authenticate(pamh, 0); if (retval == PAM_SUCCESS && !no_acct_mgmt) retval = pam_acct_mgmt(pamh, 0); if (retval == PAM_SUCCESS) { fprintf(stdout, "OK\n"); } else { error: fprintf(stdout, "ERR\n"); } if (ttl == 0) { retval = pam_end(pamh, retval); if (retval != PAM_SUCCESS) { fprintf(stderr, "WARNING: failed to release PAM authenticator\n"); } pamh = NULL; } } if (pamh) { retval = pam_end(pamh, retval); if (retval != PAM_SUCCESS) { pamh = NULL; fprintf(stderr, "ERROR: failed to release PAM authenticator\n"); } } return 0; }