]> git.ipfire.org Git - thirdparty/squid.git/blame - helpers/basic_auth/PAM/basic_pam_auth.cc
Forcing some configure options now fails the build if they can't be supported.
[thirdparty/squid.git] / helpers / basic_auth / PAM / basic_pam_auth.cc
CommitLineData
94439e4e 1/*
262a0e14 2 * $Id$
94439e4e 3 *
4 * PAM authenticator module for Squid.
2900aadb 5 * Copyright (C) 1999,2002,2003 Henrik Nordstrom <hno@squid-cache.org>
94439e4e 6 *
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.
11 *
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.
16 *
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.
20 *
21 * Install instructions:
22 *
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.
28 *
29 * Example PAM configuration for standard UNIX passwd authentication:
30 * /etc/pam.conf:
31 * squid auth required /lib/security/pam_unix.so.1
32 * squid account required /lib/security/pam_unix.so.1
33 *
34 * Note that some PAM modules (for example shadow password authentication)
fab7a87e 35 * requires the program to be installed suid root to gain access to the
36 * user password database
94439e4e 37 *
fab7a87e 38 * Change Log:
94439e4e 39 *
5a48ed18
AJ
40 * Version 2.3, 2009-11-06
41 * Converted to C++. Brought into line with Squid-3 code styles.
42 *
2900aadb 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.
48 *
49 * Version 2.1, 2002-08-12
50 * Squid-2.5 support (URL encoded login, password strings)
51 *
fab7a87e 52 * Version 2.0, 2002-01-07
53 * One shot mode, command line options
54 * man page
43f7ea67 55 *
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
59 * functions)
60 *
fab7a87e 61 * Version 1.2, internal release
43f7ea67 62 *
63 * Version 1.1, 1999-05-11
64 * Initial version
fab7a87e 65 *
5a48ed18 66 * Compile this program with: gcc -o basic_pam_auth basic_pam_auth.cc -lpam -ldl
94439e4e 67 */
dc47f531 68#define SQUID_NO_ALLOC_PROTECT 1
5a48ed18 69#include "config.h"
94439e4e 70
1fa9b1a7 71#include "rfc1738.h"
7483aded 72#include "util.h"
73
5a48ed18 74#if HAVE_STDIO_H
94439e4e 75#include <stdio.h>
5a48ed18
AJ
76#endif
77#if HAVE_ASSERT_H
94439e4e 78#include <assert.h>
5a48ed18 79#endif
5a48ed18 80#if HAVE_STRING_H
94439e4e 81#include <string.h>
5a48ed18
AJ
82#endif
83#if HAVE_SIGNAL_H
94439e4e 84#include <signal.h>
5a48ed18
AJ
85#endif
86#if HAVE_TIME_H
94439e4e 87#include <time.h>
5a48ed18
AJ
88#endif
89#if HAVE_UNISTD_H
fab7a87e 90#include <unistd.h>
5a48ed18
AJ
91#endif
92#if HAVE_SECURITY_PAM_APPL_H
94439e4e 93#include <security/pam_appl.h>
5a48ed18 94#endif
94439e4e 95
96#define BUFSIZE 8192
97
98
99/* The default PAM service name */
fab7a87e 100#ifndef DEFAULT_SQUID_PAM_SERVICE
101#define DEFAULT_SQUID_PAM_SERVICE "squid"
94439e4e 102#endif
103
fab7a87e 104/* The default TTL */
105#ifndef DEFAULT_SQUID_PAM_TTL
2900aadb 106#define DEFAULT_SQUID_PAM_TTL 0
fab7a87e 107#endif
94439e4e 108
5a48ed18 109#if _SQUID_SOLARIS_
94439e4e 110static char *password = NULL; /* Workaround for Solaris 2.6 brokenness */
5a48ed18 111#endif
94439e4e 112
5a48ed18 113/**
94439e4e 114 * A simple "conversation" function returning the supplied password.
115 * Has a bit to much error control, but this is my first PAM application
116 * so I'd rather check everything than make any mistakes. The function
117 * expects a single converstation message of type PAM_PROMPT_ECHO_OFF.
118 */
119static int
120password_conversation(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr)
121{
122 if (num_msg != 1 || msg[0]->msg_style != PAM_PROMPT_ECHO_OFF) {
26ac0430
AJ
123 fprintf(stderr, "ERROR: Unexpected PAM converstaion '%d/%s'\n", msg[0]->msg_style, msg[0]->msg);
124 return PAM_CONV_ERR;
94439e4e 125 }
519267d1 126#if _SQUID_SOLARIS_
94439e4e 127 if (!appdata_ptr) {
26ac0430
AJ
128 /* Workaround for Solaris 2.6 where the PAM library is broken
129 * and does not pass appdata_ptr to the conversation routine
130 */
131 appdata_ptr = password;
94439e4e 132 }
519267d1 133#endif
94439e4e 134 if (!appdata_ptr) {
26ac0430
AJ
135 fprintf(stderr, "ERROR: No password available to password_converstation!\n");
136 return PAM_CONV_ERR;
94439e4e 137 }
519267d1 138 *resp = static_cast<struct pam_response *>(calloc(num_msg, sizeof(struct pam_response)));
94439e4e 139 if (!*resp) {
26ac0430
AJ
140 fprintf(stderr, "ERROR: Out of memory!\n");
141 return PAM_CONV_ERR;
94439e4e 142 }
bb85e424 143 (*resp)[0].resp = xstrdup((char *) appdata_ptr);
94439e4e 144 (*resp)[0].resp_retcode = 0;
145
146 return ((*resp)[0].resp ? PAM_SUCCESS : PAM_CONV_ERR);
147}
148
26ac0430 149static struct pam_conv conv = {
94439e4e 150 &password_conversation,
151 NULL
152};
153
fab7a87e 154static void usage(char *program)
94439e4e 155{
fab7a87e 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");
94439e4e 164}
165
166int
167main(int argc, char *argv[])
168{
169 pam_handle_t *pamh = NULL;
fab7a87e 170 int retval = PAM_SUCCESS;
94439e4e 171 char *user;
519267d1 172 char *password_buf;
94439e4e 173 char buf[BUFSIZE];
174 time_t pamh_created = 0;
fab7a87e 175 int ttl = DEFAULT_SQUID_PAM_TTL;
e9505fad 176 const char *service = DEFAULT_SQUID_PAM_SERVICE;
fab7a87e 177 int no_acct_mgmt = 0;
94439e4e 178
179 /* make standard output line buffered */
180 setvbuf(stdout, NULL, _IOLBF, 0);
181
fab7a87e 182 while (1) {
26ac0430
AJ
183 int ch = getopt(argc, argv, "1n:t:o");
184 switch (ch) {
185 case -1:
186 goto start;
187 case 'n':
188 service = optarg;
189 break;
190 case 't':
191 ttl = atoi(optarg);
192 break;
193 case '1':
194 ttl = 0;
195 break;
196 case 'o':
197 no_acct_mgmt = 1;
198 break;
199 default:
200 fprintf(stderr, "Unknown getopt value '%c'\n", ch);
201 usage(argv[0]);
202 exit(1);
203 }
fab7a87e 204 }
205start:
206 if (optind < argc) {
26ac0430
AJ
207 fprintf(stderr, "Unknown option '%s'\n", argv[optind]);
208 usage(argv[0]);
209 exit(1);
fab7a87e 210 }
211
212 while (fgets(buf, BUFSIZE, stdin)) {
26ac0430 213 user = buf;
519267d1
AJ
214 password_buf = strchr(buf, '\n');
215 if (!password_buf) {
26ac0430
AJ
216 fprintf(stderr, "authenticator: Unexpected input '%s'\n", buf);
217 goto error;
218 }
519267d1
AJ
219 *password_buf = '\0';
220 password_buf = strchr(buf, ' ');
221 if (!password_buf) {
26ac0430
AJ
222 fprintf(stderr, "authenticator: Unexpected input '%s'\n", buf);
223 goto error;
224 }
519267d1 225 *password_buf++ = '\0';
26ac0430 226 rfc1738_unescape(user);
519267d1
AJ
227 rfc1738_unescape(password_buf);
228 conv.appdata_ptr = (char *) password_buf; /* from buf above. not allocated */
fab7a87e 229
519267d1 230#if _SQUID_SOLARIS_
22beb156
A
231 /* Workaround for Solaris 2.6 where the PAM library is broken
232 * and does not pass appdata_ptr to the conversation routine
233 */
234 password = password_buf;
519267d1 235#endif
26ac0430
AJ
236 if (ttl == 0) {
237 /* Create PAM connection */
238 retval = pam_start(service, user, &conv, &pamh);
239 if (retval != PAM_SUCCESS) {
240 fprintf(stderr, "ERROR: failed to create PAM authenticator\n");
241 goto error;
242 }
243 } else if (!pamh || (time(NULL) - pamh_created) >= ttl || pamh_created > time(NULL)) {
244 /* Close previous PAM connection */
245 if (pamh) {
246 retval = pam_end(pamh, retval);
247 if (retval != PAM_SUCCESS) {
248 fprintf(stderr, "WARNING: failed to release PAM authenticator\n");
249 }
250 pamh = NULL;
251 }
252 /* Initialize persistent PAM connection */
253 retval = pam_start(service, "squid@", &conv, &pamh);
254 if (retval != PAM_SUCCESS) {
255 fprintf(stderr, "ERROR: failed to create PAM authenticator\n");
256 goto error;
257 }
258 pamh_created = time(NULL);
259 }
260 /* Authentication */
261 retval = PAM_SUCCESS;
262 if (ttl != 0) {
263 if (retval == PAM_SUCCESS)
264 retval = pam_set_item(pamh, PAM_USER, user);
265 if (retval == PAM_SUCCESS)
266 retval = pam_set_item(pamh, PAM_CONV, &conv);
267 }
268 if (retval == PAM_SUCCESS)
269 retval = pam_authenticate(pamh, 0);
270 if (retval == PAM_SUCCESS && !no_acct_mgmt)
271 retval = pam_acct_mgmt(pamh, 0);
272 if (retval == PAM_SUCCESS) {
273 fprintf(stdout, "OK\n");
274 } else {
fab7a87e 275error:
26ac0430
AJ
276 fprintf(stdout, "ERR\n");
277 }
278 /* cleanup */
279 retval = PAM_SUCCESS;
5a48ed18 280#if defined(PAM_AUTHTOK)
26ac0430
AJ
281 if (ttl != 0) {
282 if (retval == PAM_SUCCESS)
283 retval = pam_set_item(pamh, PAM_AUTHTOK, NULL);
284 }
4ebcec86 285#endif
26ac0430
AJ
286 if (ttl == 0 || retval != PAM_SUCCESS) {
287 retval = pam_end(pamh, retval);
288 if (retval != PAM_SUCCESS) {
289 fprintf(stderr, "WARNING: failed to release PAM authenticator\n");
290 }
291 pamh = NULL;
292 }
94439e4e 293 }
294
295 if (pamh) {
26ac0430
AJ
296 retval = pam_end(pamh, retval);
297 if (retval != PAM_SUCCESS) {
298 pamh = NULL;
299 fprintf(stderr, "ERROR: failed to release PAM authenticator\n");
300 }
94439e4e 301 }
fab7a87e 302 return 0;
94439e4e 303}