2 * Copyright (C) 1996-2014 The Squid Software Foundation and contributors
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.
10 * PAM authenticator module for Squid.
12 * Copyright (C) 1999,2002,2003 Henrik Nordstrom <hno@squid-cache.org>
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.
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.
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.
28 * Install instructions:
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.
36 * Example PAM configuration for standard UNIX passwd authentication:
38 * squid auth required /lib/security/pam_unix.so.1
39 * squid account required /lib/security/pam_unix.so.1
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
47 * Version 2.3, 2009-11-06
48 * Converted to C++. Brought into line with Squid-3 code styles.
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.
56 * Version 2.1, 2002-08-12
57 * Squid-2.5 support (URL encoded login, password strings)
59 * Version 2.0, 2002-01-07
60 * One shot mode, command line options
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
68 * Version 1.2, internal release
70 * Version 1.1, 1999-05-11
74 #include "helpers/defines.h"
85 #if HAVE_SECURITY_PAM_APPL_H
86 #include <security/pam_appl.h>
89 /* The default PAM service name */
90 #if !defined(DEFAULT_SQUID_PAM_SERVICE)
91 #define DEFAULT_SQUID_PAM_SERVICE "squid"
95 #if !defined(DEFAULT_SQUID_PAM_TTL)
96 #define DEFAULT_SQUID_PAM_TTL 0
100 static char *password
= NULL
; /* Workaround for Solaris 2.6 brokenness */
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
);
107 * A simple "conversation" function returning the supplied password.
108 * Has a bit to much error control, but this is my first PAM application
109 * so I'd rather check everything than make any mistakes. The function
110 * expects a single converstation message of type PAM_PROMPT_ECHO_OFF.
113 password_conversation(int num_msg
, PAM_CONV_FUNC_CONST_PARM
struct pam_message
**msg
, struct pam_response
**resp
, void *appdata_ptr
)
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
);
121 /* Workaround for Solaris 2.6 where the PAM library is broken
122 * and does not pass appdata_ptr to the conversation routine
124 appdata_ptr
= password
;
128 debug("ERROR: No password available to password_converstation!\n");
131 *resp
= static_cast<struct pam_response
*>(calloc(num_msg
, sizeof(struct pam_response
)));
133 debug("ERROR: Out of memory!\n");
136 (*resp
)[0].resp
= xstrdup((char *) appdata_ptr
);
137 (*resp
)[0].resp_retcode
= 0;
139 return ((*resp
)[0].resp
? PAM_SUCCESS
: PAM_CONV_ERR
);
142 static struct pam_conv conv
= {
143 &password_conversation
,
147 static void usage(char *program
)
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");
161 main(int argc
, char *argv
[])
163 pam_handle_t
*pamh
= NULL
;
164 int retval
= PAM_SUCCESS
;
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;
174 /* make standard output line buffered */
175 setvbuf(stdout
, NULL
, _IOLBF
, 0);
178 int ch
= getopt(argc
, argv
, "1n:t:or");
198 fprintf(stderr
, "FATAL: Unknown getopt value '%c'\n", ch
);
205 fprintf(stderr
, "FATAL: Unknown option '%s'\n", argv
[optind
]);
210 while (fgets(buf
, HELPER_INPUT_BUFFER
, stdin
)) {
212 password_buf
= strchr(buf
, '\n');
214 debug("ERROR: %s: Unexpected input '%s'\n", argv
[0], buf
);
217 *password_buf
= '\0';
218 password_buf
= strchr(buf
, ' ');
220 debug("ERROR: %s: Unexpected input '%s'\n", argv
[0], buf
);
223 *password_buf
= '\0';
225 rfc1738_unescape(user
);
226 rfc1738_unescape(password_buf
);
227 conv
.appdata_ptr
= (char *) password_buf
; /* from buf above. not allocated */
230 /* Remove DOMAIN\.. and ...@domain from the user name in case the user
231 * thought this was an NTLM or Negotiate authentication popup box
233 char * user_ptr
= strchr(user
, '@');
234 if (user_ptr
) *user_ptr
= 0;
236 user_ptr
= strchr(user
, '\\');
237 if (user_ptr
) user
= user_ptr
+ 1;
242 /* Workaround for Solaris 2.6 where the PAM library is broken
243 * and does not pass appdata_ptr to the conversation routine
245 password
= password_buf
;
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");
254 } else if (!pamh
|| (time(NULL
) - pamh_created
) >= ttl
|| pamh_created
> time(NULL
)) {
255 /* Close previous PAM connection */
257 retval
= pam_end(pamh
, retval
);
258 if (retval
!= PAM_SUCCESS
) {
259 debug("WARNING: failed to release PAM authenticator\n");
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");
269 pamh_created
= time(NULL
);
272 retval
= PAM_SUCCESS
;
274 retval
= pam_set_item(pamh
, PAM_USER
, user
);
275 if (retval
== PAM_SUCCESS
)
276 retval
= pam_set_item(pamh
, PAM_CONV
, &conv
);
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
) {
289 retval
= PAM_SUCCESS
;
290 #if defined(PAM_AUTHTOK)
291 if (ttl
!= 0 && pamh
) {
292 retval
= pam_set_item(pamh
, PAM_AUTHTOK
, NULL
);
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");
305 retval
= pam_end(pamh
, retval
);
306 if (retval
!= PAM_SUCCESS
) {
308 debug("ERROR: failed to release PAM authenticator\n");