basic_pam_auth.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /*
10  * PAM authenticator module for Squid.
11  *
12  * Copyright (C) 1999,2002,2003 Henrik Nordstrom <hno@squid-cache.org>
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
27  *
28  * Install instructions:
29  *
30  * This program authenticates users against a PAM configured authentication
31  * service "squid". This allows you to authenticate Squid users to any
32  * authentication source for which you have a PAM module. Commonly available
33  * PAM modules includes "UNIX", RADIUS, Kerberos and SMB, but a lot of other
34  * PAM modules are available from various sources.
35  *
36  * Example PAM configuration for standard UNIX passwd authentication:
37  * /etc/pam.conf:
38  * squid auth required /lib/security/pam_unix.so.1
39  * squid account required /lib/security/pam_unix.so.1
40  *
41  * Note that some PAM modules (for example shadow password authentication)
42  * requires the program to be installed suid root to gain access to the
43  * user password database
44  *
45  * Change Log:
46  *
47  * Version 2.3, 2009-11-06
48  * Converted to C++. Brought into line with Squid-3 code styles.
49  *
50  * Version 2.2, 2003-11-05
51  * One shot mode is now the default mode of operation
52  * with persistent PAM connections enabled by -t option.
53  * Support for clearing the PAM_AUTHTOK attribute on
54  * persistent PAM connections.
55  *
56  * Version 2.1, 2002-08-12
57  * Squid-2.5 support (URL encoded login, password strings)
58  *
59  * Version 2.0, 2002-01-07
60  * One shot mode, command line options
61  * man page
62  *
63  * Version 1.3, 1999-12-10
64  * Bugfix release 1.3 to work around Solaris 2.6
65  * brokenness (not sending arguments to conversation
66  * functions)
67  *
68  * Version 1.2, internal release
69  *
70  * Version 1.1, 1999-05-11
71  * Initial version
72  */
73 #include "squid.h"
75 #include "rfc1738.h"
76 #include "util.h"
77 
78 #include <cassert>
79 #include <csignal>
80 #include <cstring>
81 #include <ctime>
82 #if HAVE_UNISTD_H
83 #include <unistd.h>
84 #endif
85 #if HAVE_SECURITY_PAM_APPL_H
86 #include <security/pam_appl.h>
87 #endif
88 
89 /* The default PAM service name */
90 #if !defined(DEFAULT_SQUID_PAM_SERVICE)
91 #define DEFAULT_SQUID_PAM_SERVICE "squid"
92 #endif
93 
94 /* The default TTL */
95 #if !defined(DEFAULT_SQUID_PAM_TTL)
96 #define DEFAULT_SQUID_PAM_TTL 0
97 #endif
98 
99 #if _SQUID_SOLARIS_
100 static char *password = nullptr; /* Workaround for Solaris 2.6 brokenness */
101 #endif
102 
103 extern "C" int password_conversation(int num_msg, PAM_CONV_FUNC_CONST_PARM struct pam_message **msg,
104  struct pam_response **resp, void *appdata_ptr);
105 
112 int
113 password_conversation(int num_msg, PAM_CONV_FUNC_CONST_PARM struct pam_message **msg, struct pam_response **resp, void *appdata_ptr)
114 {
115  if (num_msg != 1 || msg[0]->msg_style != PAM_PROMPT_ECHO_OFF) {
116  debug("ERROR: Unexpected PAM converstaion '%d/%s'\n", msg[0]->msg_style, msg[0]->msg);
117  return PAM_CONV_ERR;
118  }
119 #if _SQUID_SOLARIS_
120  if (!appdata_ptr) {
121  /* Workaround for Solaris 2.6 where the PAM library is broken
122  * and does not pass appdata_ptr to the conversation routine
123  */
124  appdata_ptr = password;
125  }
126 #endif
127  if (!appdata_ptr) {
128  debug("ERROR: No password available to password_converstation!\n");
129  return PAM_CONV_ERR;
130  }
131  *resp = static_cast<struct pam_response *>(calloc(num_msg, sizeof(struct pam_response)));
132  if (!*resp) {
133  debug("ERROR: Out of memory!\n");
134  return PAM_CONV_ERR;
135  }
136  (*resp)[0].resp = xstrdup((char *) appdata_ptr);
137  (*resp)[0].resp_retcode = 0;
138 
139  return ((*resp)[0].resp ? PAM_SUCCESS : PAM_CONV_ERR);
140 }
141 
142 static struct pam_conv conv = {
144  NULL
145 };
146 
147 static void usage(char *program)
148 {
149  fprintf(stderr, "Usage: %s [options..]\n", program);
150  fprintf(stderr, " -n service_name\n");
151  fprintf(stderr, " The PAM service name (default \"%s\")\n", DEFAULT_SQUID_PAM_SERVICE);
152  fprintf(stderr, " -t ttl PAM connection ttl in seconds (default %d)\n", DEFAULT_SQUID_PAM_TTL);
153  fprintf(stderr, " during this time the same connection will be reused\n");
154  fprintf(stderr, " to authenticate all users\n");
155  fprintf(stderr, " -o Do not perform account mgmt (account expiration etc)\n");
156  fprintf(stderr, " -1 Only one user authentication per PAM connection\n");
157  fprintf(stderr, " -r Detect and remove Negotiate/NTLM realm from username\n");
158 }
159 
160 int
161 main(int argc, char *argv[])
162 {
163  pam_handle_t *pamh = nullptr;
164  int retval = PAM_SUCCESS;
165  char *user;
166  char *password_buf;
167  char buf[HELPER_INPUT_BUFFER];
168  time_t pamh_created = 0;
169  int ttl = DEFAULT_SQUID_PAM_TTL;
170  const char *service = DEFAULT_SQUID_PAM_SERVICE;
171  int no_acct_mgmt = 0;
172  int no_realm = 0;
173 
174  /* make standard output line buffered */
175  setvbuf(stdout, nullptr, _IOLBF, 0);
176 
177  while (1) {
178  int ch = getopt(argc, argv, "1n:t:or");
179  switch (ch) {
180  case -1:
181  goto start;
182  case 'n':
183  service = optarg;
184  break;
185  case 't':
186  ttl = atoi(optarg);
187  break;
188  case '1':
189  ttl = 0;
190  break;
191  case 'o':
192  no_acct_mgmt = 1;
193  break;
194  case 'r':
195  no_realm = 1;
196  break;
197  default:
198  fprintf(stderr, "FATAL: Unknown getopt value '%c'\n", ch);
199  usage(argv[0]);
200  exit(EXIT_FAILURE);
201  }
202  }
203 start:
204  if (optind < argc) {
205  fprintf(stderr, "FATAL: Unknown option '%s'\n", argv[optind]);
206  usage(argv[0]);
207  exit(EXIT_FAILURE);
208  }
209 
210  while (fgets(buf, HELPER_INPUT_BUFFER, stdin)) {
211  user = buf;
212  password_buf = strchr(buf, '\n');
213  if (!password_buf) {
214  debug("ERROR: %s: Unexpected input '%s'\n", argv[0], buf);
215  goto error;
216  }
217  *password_buf = '\0';
218  password_buf = strchr(buf, ' ');
219  if (!password_buf) {
220  debug("ERROR: %s: Unexpected input '%s'\n", argv[0], buf);
221  goto error;
222  }
223  *password_buf = '\0';
224  ++password_buf;
225  rfc1738_unescape(user);
226  rfc1738_unescape(password_buf);
227  conv.appdata_ptr = (char *) password_buf; /* from buf above. not allocated */
228 
229  if (no_realm) {
230  /* Remove DOMAIN\.. and ...@domain from the user name in case the user
231  * thought this was an NTLM or Negotiate authentication popup box
232  */
233  char * user_ptr = strchr(user, '@');
234  if (user_ptr) *user_ptr = 0;
235  else {
236  user_ptr = strchr(user, '\\');
237  if (user_ptr) user = user_ptr + 1;
238  }
239  }
240 
241 #if _SQUID_SOLARIS_
242  /* Workaround for Solaris 2.6 where the PAM library is broken
243  * and does not pass appdata_ptr to the conversation routine
244  */
245  password = password_buf;
246 #endif
247  if (ttl == 0) {
248  /* Create PAM connection */
249  retval = pam_start(service, user, &conv, &pamh);
250  if (retval != PAM_SUCCESS) {
251  debug("ERROR: failed to create PAM authenticator\n");
252  goto error;
253  }
254  } else if (!pamh || (time(NULL) - pamh_created) >= ttl || pamh_created > time(NULL)) {
255  /* Close previous PAM connection */
256  if (pamh) {
257  retval = pam_end(pamh, retval);
258  if (retval != PAM_SUCCESS) {
259  debug("WARNING: failed to release PAM authenticator\n");
260  }
261  pamh = nullptr;
262  }
263  /* Initialize persistent PAM connection */
264  retval = pam_start(service, "squid@", &conv, &pamh);
265  if (retval != PAM_SUCCESS) {
266  debug("ERROR: failed to create PAM authenticator\n");
267  goto error;
268  }
269  pamh_created = time(NULL);
270  }
271  /* Authentication */
272  retval = PAM_SUCCESS;
273  if (ttl != 0) {
274  retval = pam_set_item(pamh, PAM_USER, user);
275  if (retval == PAM_SUCCESS)
276  retval = pam_set_item(pamh, PAM_CONV, &conv);
277  }
278  if (retval == PAM_SUCCESS)
279  retval = pam_authenticate(pamh, 0);
280  if (retval == PAM_SUCCESS && !no_acct_mgmt)
281  retval = pam_acct_mgmt(pamh, 0);
282  if (retval == PAM_SUCCESS) {
283  SEND_OK("");
284  } else {
285 error:
286  SEND_ERR("");
287  }
288  /* cleanup */
289  retval = PAM_SUCCESS;
290 #if defined(PAM_AUTHTOK)
291  if (ttl != 0 && pamh) {
292  retval = pam_set_item(pamh, PAM_AUTHTOK, nullptr);
293  }
294 #endif
295  if (pamh && (ttl == 0 || retval != PAM_SUCCESS)) {
296  retval = pam_end(pamh, retval);
297  if (retval != PAM_SUCCESS) {
298  debug("WARNING: failed to release PAM authenticator\n");
299  }
300  pamh = nullptr;
301  }
302  }
303 
304  if (pamh) {
305  retval = pam_end(pamh, retval);
306  if (retval != PAM_SUCCESS) {
307  pamh = nullptr;
308  debug("ERROR: failed to release PAM authenticator\n");
309  }
310  }
311  return EXIT_SUCCESS;
312 }
313 
int main(int argc, char *argv[])
void debug(const char *format,...)
Definition: debug.cc:19
void error(char *format,...)
#define xstrdup
char * optarg
Definition: getopt.c:51
#define DEFAULT_SQUID_PAM_SERVICE
int getopt(int nargc, char *const *nargv, const char *ostr)
Definition: getopt.c:62
#define NULL
Definition: types.h:145
void rfc1738_unescape(char *url)
Definition: rfc1738.c:146
#define SEND_ERR(x)
int password_conversation(int num_msg, PAM_CONV_FUNC_CONST_PARM struct pam_message **msg, struct pam_response **resp, void *appdata_ptr)
#define DEFAULT_SQUID_PAM_TTL
static void usage(char *program)
#define HELPER_INPUT_BUFFER
Definition: UserRequest.cc:24
int optind
Definition: getopt.c:48
#define SEND_OK(x)
static struct pam_conv conv

 

Introduction

Documentation

Support

Miscellaneous