4 * PAM authenticator module for Squid.
5 * Copyright (C) 1999,2002,2003 Henrik Nordstrom <hno@squid-cache.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
21 * Install instructions:
23 * This program authenticates users against a PAM configured authentication
24 * service "squid". This allows you to authenticate Squid users to any
25 * authentication source for which you have a PAM module. Commonly available
26 * PAM modules includes "UNIX", RADIUS, Kerberos and SMB, but a lot of other
27 * PAM modules are available from various sources.
29 * Example PAM configuration for standard UNIX passwd authentication:
31 * squid auth required /lib/security/pam_unix.so.1
32 * squid account required /lib/security/pam_unix.so.1
34 * Note that some PAM modules (for example shadow password authentication)
35 * requires the program to be installed suid root to gain access to the
36 * user password database
40 * Version 2.3, 2009-11-06
41 * Converted to C++. Brought into line with Squid-3 code styles.
43 * Version 2.2, 2003-11-05
44 * One shot mode is now the default mode of operation
45 * with persistent PAM connections enabled by -t option.
46 * Support for clearing the PAM_AUTHTOK attribute on
47 * persistent PAM connections.
49 * Version 2.1, 2002-08-12
50 * Squid-2.5 support (URL encoded login, password strings)
52 * Version 2.0, 2002-01-07
53 * One shot mode, command line options
56 * Version 1.3, 1999-12-10
57 * Bugfix release 1.3 to work around Solaris 2.6
58 * brokenness (not sending arguments to conversation
61 * Version 1.2, internal release
63 * Version 1.1, 1999-05-11
66 * Compile this program with: gcc -o basic_pam_auth basic_pam_auth.cc -lpam -ldl
94 #if HAVE_SECURITY_PAM_APPL_H
95 #include <security/pam_appl.h>
101 /* The default PAM service name */
102 #ifndef DEFAULT_SQUID_PAM_SERVICE
103 #define DEFAULT_SQUID_PAM_SERVICE "squid"
106 /* The default TTL */
107 #ifndef DEFAULT_SQUID_PAM_TTL
108 #define DEFAULT_SQUID_PAM_TTL 0
112 static char *password
= NULL
; /* Workaround for Solaris 2.6 brokenness */
116 * A simple "conversation" function returning the supplied password.
117 * Has a bit to much error control, but this is my first PAM application
118 * so I'd rather check everything than make any mistakes. The function
119 * expects a single converstation message of type PAM_PROMPT_ECHO_OFF.
122 password_conversation(int num_msg
, const struct pam_message
**msg
, struct pam_response
**resp
, void *appdata_ptr
)
124 if (num_msg
!= 1 || msg
[0]->msg_style
!= PAM_PROMPT_ECHO_OFF
) {
125 fprintf(stderr
, "ERROR: Unexpected PAM converstaion '%d/%s'\n", msg
[0]->msg_style
, msg
[0]->msg
);
129 /* Workaround for Solaris 2.6 where the PAM library is broken
130 * and does not pass appdata_ptr to the conversation routine
132 appdata_ptr
= password
;
135 fprintf(stderr
, "ERROR: No password available to password_converstation!\n");
138 *resp
= calloc(num_msg
, sizeof(struct pam_response
));
140 fprintf(stderr
, "ERROR: Out of memory!\n");
143 (*resp
)[0].resp
= strdup((char *) appdata_ptr
);
144 (*resp
)[0].resp_retcode
= 0;
146 return ((*resp
)[0].resp
? PAM_SUCCESS
: PAM_CONV_ERR
);
149 static struct pam_conv conv
= {
150 &password_conversation
,
154 static void usage(char *program
)
156 fprintf(stderr
, "Usage: %s [options..]\n", program
);
157 fprintf(stderr
, " -n service_name\n");
158 fprintf(stderr
, " The PAM service name (default \"%s\")\n", DEFAULT_SQUID_PAM_SERVICE
);
159 fprintf(stderr
, " -t ttl PAM connection ttl in seconds (default %d)\n", DEFAULT_SQUID_PAM_TTL
);
160 fprintf(stderr
, " during this time the same connection will be reused\n");
161 fprintf(stderr
, " to authenticate all users\n");
162 fprintf(stderr
, " -o Do not perform account mgmt (account expiration etc)\n");
163 fprintf(stderr
, " -1 Only one user authentication per PAM connection\n");
167 main(int argc
, char *argv
[])
169 pam_handle_t
*pamh
= NULL
;
170 int retval
= PAM_SUCCESS
;
172 /* char *password; */
174 time_t pamh_created
= 0;
175 int ttl
= DEFAULT_SQUID_PAM_TTL
;
176 const char *service
= DEFAULT_SQUID_PAM_SERVICE
;
177 int no_acct_mgmt
= 0;
179 /* make standard output line buffered */
180 setvbuf(stdout
, NULL
, _IOLBF
, 0);
183 int ch
= getopt(argc
, argv
, "1n:t:o");
200 fprintf(stderr
, "Unknown getopt value '%c'\n", ch
);
207 fprintf(stderr
, "Unknown option '%s'\n", argv
[optind
]);
212 while (fgets(buf
, BUFSIZE
, stdin
)) {
214 password
= strchr(buf
, '\n');
216 fprintf(stderr
, "authenticator: Unexpected input '%s'\n", buf
);
220 password
= strchr(buf
, ' ');
222 fprintf(stderr
, "authenticator: Unexpected input '%s'\n", buf
);
226 rfc1738_unescape(user
);
227 rfc1738_unescape(password
);
228 conv
.appdata_ptr
= (char *) password
; /* from buf above. not allocated */
231 /* Create PAM connection */
232 retval
= pam_start(service
, user
, &conv
, &pamh
);
233 if (retval
!= PAM_SUCCESS
) {
234 fprintf(stderr
, "ERROR: failed to create PAM authenticator\n");
237 } else if (!pamh
|| (time(NULL
) - pamh_created
) >= ttl
|| pamh_created
> time(NULL
)) {
238 /* Close previous PAM connection */
240 retval
= pam_end(pamh
, retval
);
241 if (retval
!= PAM_SUCCESS
) {
242 fprintf(stderr
, "WARNING: failed to release PAM authenticator\n");
246 /* Initialize persistent PAM connection */
247 retval
= pam_start(service
, "squid@", &conv
, &pamh
);
248 if (retval
!= PAM_SUCCESS
) {
249 fprintf(stderr
, "ERROR: failed to create PAM authenticator\n");
252 pamh_created
= time(NULL
);
255 retval
= PAM_SUCCESS
;
257 if (retval
== PAM_SUCCESS
)
258 retval
= pam_set_item(pamh
, PAM_USER
, user
);
259 if (retval
== PAM_SUCCESS
)
260 retval
= pam_set_item(pamh
, PAM_CONV
, &conv
);
262 if (retval
== PAM_SUCCESS
)
263 retval
= pam_authenticate(pamh
, 0);
264 if (retval
== PAM_SUCCESS
&& !no_acct_mgmt
)
265 retval
= pam_acct_mgmt(pamh
, 0);
266 if (retval
== PAM_SUCCESS
) {
267 fprintf(stdout
, "OK\n");
270 fprintf(stdout
, "ERR\n");
273 retval
= PAM_SUCCESS
;
274 #if defined(PAM_AUTHTOK)
276 if (retval
== PAM_SUCCESS
)
277 retval
= pam_set_item(pamh
, PAM_AUTHTOK
, NULL
);
280 if (ttl
== 0 || retval
!= PAM_SUCCESS
) {
281 retval
= pam_end(pamh
, retval
);
282 if (retval
!= PAM_SUCCESS
) {
283 fprintf(stderr
, "WARNING: failed to release PAM authenticator\n");
290 retval
= pam_end(pamh
, retval
);
291 if (retval
!= PAM_SUCCESS
) {
293 fprintf(stderr
, "ERROR: failed to release PAM authenticator\n");