/*
- * $Id$
+ * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
*
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+/*
* PAM authenticator module for Squid.
+ *
* Copyright (C) 1999,2002,2003 Henrik Nordstrom <hno@squid-cache.org>
*
* This program is free software; you can redistribute it and/or modify
*
* Version 2.0, 2002-01-07
* One shot mode, command line options
- * man page
+ * man page
*
* Version 1.3, 1999-12-10
- * Bugfix release 1.3 to work around Solaris 2.6
+ * 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 basic_pam_auth basic_pam_auth.cc -lpam -ldl
+ * Initial version
*/
-#include "config.h"
-
+#include "squid.h"
+#include "helpers/defines.h"
#include "rfc1738.h"
#include "util.h"
-#if HAVE_STDIO_H
-#include <stdio.h>
-#endif
-#if HAVE_ASSERT_H
-#include <assert.h>
-#endif
-#if HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#if HAVE_STRING_H
-#include <string.h>
-#endif
-#if HAVE_SIGNAL_H
-#include <signal.h>
-#endif
-#if HAVE_TIME_H
-#include <time.h>
-#endif
+#include <cassert>
+#include <csignal>
+#include <cstring>
+#include <ctime>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <security/pam_appl.h>
#endif
-#define BUFSIZE 8192
-
-
/* The default PAM service name */
-#ifndef DEFAULT_SQUID_PAM_SERVICE
+#if !defined(DEFAULT_SQUID_PAM_SERVICE)
#define DEFAULT_SQUID_PAM_SERVICE "squid"
#endif
/* The default TTL */
-#ifndef DEFAULT_SQUID_PAM_TTL
+#if !defined(DEFAULT_SQUID_PAM_TTL)
#define DEFAULT_SQUID_PAM_TTL 0
#endif
#if _SQUID_SOLARIS_
-static char *password = NULL; /* Workaround for Solaris 2.6 brokenness */
+static char *password = NULL; /* Workaround for Solaris 2.6 brokenness */
#endif
+extern "C" int password_conversation(int num_msg, PAM_CONV_FUNC_CONST_PARM struct pam_message **msg,
+ struct pam_response **resp, void *appdata_ptr);
+
/**
* 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)
+int
+password_conversation(int num_msg, PAM_CONV_FUNC_CONST_PARM 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);
+ debug("ERROR: Unexpected PAM converstaion '%d/%s'\n", msg[0]->msg_style, msg[0]->msg);
return PAM_CONV_ERR;
}
+#if _SQUID_SOLARIS_
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;
}
+#endif
if (!appdata_ptr) {
- fprintf(stderr, "ERROR: No password available to password_converstation!\n");
+ debug("ERROR: No password available to password_converstation!\n");
return PAM_CONV_ERR;
}
- *resp = calloc(num_msg, sizeof(struct pam_response));
+ *resp = static_cast<struct pam_response *>(calloc(num_msg, sizeof(struct pam_response)));
if (!*resp) {
- fprintf(stderr, "ERROR: Out of memory!\n");
+ debug("ERROR: Out of memory!\n");
return PAM_CONV_ERR;
}
- (*resp)[0].resp = strdup((char *) appdata_ptr);
+ (*resp)[0].resp = xstrdup((char *) appdata_ptr);
(*resp)[0].resp_retcode = 0;
return ((*resp)[0].resp ? PAM_SUCCESS : PAM_CONV_ERR);
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");
+ fprintf(stderr, " -r Detect and remove Negotiate/NTLM realm from username\n");
}
int
pam_handle_t *pamh = NULL;
int retval = PAM_SUCCESS;
char *user;
- /* char *password; */
- char buf[BUFSIZE];
+ char *password_buf;
+ char buf[HELPER_INPUT_BUFFER];
time_t pamh_created = 0;
int ttl = DEFAULT_SQUID_PAM_TTL;
const char *service = DEFAULT_SQUID_PAM_SERVICE;
int no_acct_mgmt = 0;
+ int no_realm = 0;
/* make standard output line buffered */
setvbuf(stdout, NULL, _IOLBF, 0);
while (1) {
- int ch = getopt(argc, argv, "1n:t:o");
+ int ch = getopt(argc, argv, "1n:t:or");
switch (ch) {
case -1:
goto start;
case 'o':
no_acct_mgmt = 1;
break;
+ case 'r':
+ no_realm = 1;
+ break;
default:
- fprintf(stderr, "Unknown getopt value '%c'\n", ch);
+ fprintf(stderr, "FATAL: Unknown getopt value '%c'\n", ch);
usage(argv[0]);
exit(1);
}
}
start:
if (optind < argc) {
- fprintf(stderr, "Unknown option '%s'\n", argv[optind]);
+ fprintf(stderr, "FATAL: Unknown option '%s'\n", argv[optind]);
usage(argv[0]);
exit(1);
}
- while (fgets(buf, BUFSIZE, stdin)) {
+ while (fgets(buf, HELPER_INPUT_BUFFER, stdin)) {
user = buf;
- password = strchr(buf, '\n');
- if (!password) {
- fprintf(stderr, "authenticator: Unexpected input '%s'\n", buf);
+ password_buf = strchr(buf, '\n');
+ if (!password_buf) {
+ debug("ERROR: %s: Unexpected input '%s'\n", argv[0], buf);
goto error;
}
- *password = '\0';
- password = strchr(buf, ' ');
- if (!password) {
- fprintf(stderr, "authenticator: Unexpected input '%s'\n", buf);
+ *password_buf = '\0';
+ password_buf = strchr(buf, ' ');
+ if (!password_buf) {
+ debug("ERROR: %s: Unexpected input '%s'\n", argv[0], buf);
goto error;
}
- *password++ = '\0';
+ *password_buf = '\0';
+ ++password_buf;
rfc1738_unescape(user);
- rfc1738_unescape(password);
- conv.appdata_ptr = (char *) password; /* from buf above. not allocated */
+ rfc1738_unescape(password_buf);
+ conv.appdata_ptr = (char *) password_buf; /* from buf above. not allocated */
+
+ if (no_realm) {
+ /* Remove DOMAIN\.. and ...@domain from the user name in case the user
+ * thought this was an NTLM or Negotiate authentication popup box
+ */
+ char * user_ptr = strchr(user, '@');
+ if (user_ptr) *user_ptr = 0;
+ else {
+ user_ptr = strchr(user, '\\');
+ if (user_ptr) user = user_ptr + 1;
+ }
+ }
+#if _SQUID_SOLARIS_
+ /* Workaround for Solaris 2.6 where the PAM library is broken
+ * and does not pass appdata_ptr to the conversation routine
+ */
+ password = password_buf;
+#endif
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");
+ debug("ERROR: failed to create PAM authenticator\n");
goto error;
}
} else if (!pamh || (time(NULL) - pamh_created) >= ttl || pamh_created > time(NULL)) {
if (pamh) {
retval = pam_end(pamh, retval);
if (retval != PAM_SUCCESS) {
- fprintf(stderr, "WARNING: failed to release PAM authenticator\n");
+ debug("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");
+ debug("ERROR: failed to create PAM authenticator\n");
goto error;
}
pamh_created = time(NULL);
/* Authentication */
retval = PAM_SUCCESS;
if (ttl != 0) {
- if (retval == PAM_SUCCESS)
- retval = pam_set_item(pamh, PAM_USER, user);
+ retval = pam_set_item(pamh, PAM_USER, user);
if (retval == PAM_SUCCESS)
retval = pam_set_item(pamh, PAM_CONV, &conv);
}
if (retval == PAM_SUCCESS && !no_acct_mgmt)
retval = pam_acct_mgmt(pamh, 0);
if (retval == PAM_SUCCESS) {
- fprintf(stdout, "OK\n");
+ SEND_OK("");
} else {
error:
- fprintf(stdout, "ERR\n");
+ SEND_ERR("");
}
/* cleanup */
retval = PAM_SUCCESS;
#if defined(PAM_AUTHTOK)
- if (ttl != 0) {
- if (retval == PAM_SUCCESS)
- retval = pam_set_item(pamh, PAM_AUTHTOK, NULL);
+ if (ttl != 0 && pamh) {
+ retval = pam_set_item(pamh, PAM_AUTHTOK, NULL);
}
#endif
- if (ttl == 0 || retval != PAM_SUCCESS) {
+ if (pamh && (ttl == 0 || retval != PAM_SUCCESS)) {
retval = pam_end(pamh, retval);
if (retval != PAM_SUCCESS) {
- fprintf(stderr, "WARNING: failed to release PAM authenticator\n");
+ debug("WARNING: failed to release PAM authenticator\n");
}
pamh = NULL;
}
retval = pam_end(pamh, retval);
if (retval != PAM_SUCCESS) {
pamh = NULL;
- fprintf(stderr, "ERROR: failed to release PAM authenticator\n");
+ debug("ERROR: failed to release PAM authenticator\n");
}
}
return 0;
}
+