]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - helpers/basic_auth/PAM/basic_pam_auth.cc
SourceFormat Enforcement
[thirdparty/squid.git] / helpers / basic_auth / PAM / basic_pam_auth.cc
index 0802a1fd0279d454fe0970b04945e72d673a0a3f..9638a0299f31377a6c3decea8df30ac6e4a76371 100644 (file)
@@ -1,7 +1,14 @@
 /*
- * $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);
@@ -161,6 +154,7 @@ static void usage(char *program)
     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
@@ -169,18 +163,19 @@ main(int argc, char *argv[])
     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;
@@ -196,42 +191,64 @@ main(int argc, char *argv[])
         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)) {
@@ -239,14 +256,14 @@ start:
             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);
@@ -254,8 +271,7 @@ start:
         /* 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);
         }
@@ -264,23 +280,22 @@ start:
         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;
         }
@@ -290,8 +305,9 @@ error:
         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;
 }
+