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