]> git.ipfire.org Git - thirdparty/squid.git/blame - src/auth/basic/PAM/basic_pam_auth.cc
Source Format Enforcement (#532)
[thirdparty/squid.git] / src / auth / basic / PAM / basic_pam_auth.cc
CommitLineData
94439e4e 1/*
77b1029d 2 * Copyright (C) 1996-2020 The Squid Software Foundation and contributors
94439e4e 3 *
5b95b903
AJ
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.
94439e4e 11 *
ca02e0ec
AJ
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 *
94439e4e 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)
fab7a87e 42 * requires the program to be installed suid root to gain access to the
43 * user password database
94439e4e 44 *
fab7a87e 45 * Change Log:
94439e4e 46 *
5a48ed18
AJ
47 * Version 2.3, 2009-11-06
48 * Converted to C++. Brought into line with Squid-3 code styles.
49 *
2900aadb 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 *
fab7a87e 59 * Version 2.0, 2002-01-07
60 * One shot mode, command line options
f53969cc 61 * man page
43f7ea67 62 *
63 * Version 1.3, 1999-12-10
f53969cc 64 * Bugfix release 1.3 to work around Solaris 2.6
43f7ea67 65 * brokenness (not sending arguments to conversation
66 * functions)
67 *
fab7a87e 68 * Version 1.2, internal release
43f7ea67 69 *
70 * Version 1.1, 1999-05-11
f53969cc 71 * Initial version
94439e4e 72 */
f7f3304a 73#include "squid.h"
079b1d0f 74#include "helper/protocol_defines.h"
1fa9b1a7 75#include "rfc1738.h"
7483aded 76#include "util.h"
77
074d6a40
AJ
78#include <cassert>
79#include <csignal>
80#include <cstring>
81#include <ctime>
5a48ed18 82#if HAVE_UNISTD_H
fab7a87e 83#include <unistd.h>
5a48ed18
AJ
84#endif
85#if HAVE_SECURITY_PAM_APPL_H
94439e4e 86#include <security/pam_appl.h>
5a48ed18 87#endif
94439e4e 88
94439e4e 89/* The default PAM service name */
605f2c3e 90#if !defined(DEFAULT_SQUID_PAM_SERVICE)
fab7a87e 91#define DEFAULT_SQUID_PAM_SERVICE "squid"
94439e4e 92#endif
93
fab7a87e 94/* The default TTL */
605f2c3e 95#if !defined(DEFAULT_SQUID_PAM_TTL)
2900aadb 96#define DEFAULT_SQUID_PAM_TTL 0
fab7a87e 97#endif
94439e4e 98
5a48ed18 99#if _SQUID_SOLARIS_
f53969cc 100static char *password = NULL; /* Workaround for Solaris 2.6 brokenness */
5a48ed18 101#endif
94439e4e 102
daacd51f
AJ
103extern "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
5a48ed18 106/**
94439e4e 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.
111 */
daacd51f 112int
3c586e38 113password_conversation(int num_msg, PAM_CONV_FUNC_CONST_PARM struct pam_message **msg, struct pam_response **resp, void *appdata_ptr)
94439e4e 114{
115 if (num_msg != 1 || msg[0]->msg_style != PAM_PROMPT_ECHO_OFF) {
43fed740 116 debug("ERROR: Unexpected PAM converstaion '%d/%s'\n", msg[0]->msg_style, msg[0]->msg);
26ac0430 117 return PAM_CONV_ERR;
94439e4e 118 }
519267d1 119#if _SQUID_SOLARIS_
94439e4e 120 if (!appdata_ptr) {
26ac0430
AJ
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;
94439e4e 125 }
519267d1 126#endif
94439e4e 127 if (!appdata_ptr) {
43fed740 128 debug("ERROR: No password available to password_converstation!\n");
26ac0430 129 return PAM_CONV_ERR;
94439e4e 130 }
519267d1 131 *resp = static_cast<struct pam_response *>(calloc(num_msg, sizeof(struct pam_response)));
94439e4e 132 if (!*resp) {
43fed740 133 debug("ERROR: Out of memory!\n");
26ac0430 134 return PAM_CONV_ERR;
94439e4e 135 }
bb85e424 136 (*resp)[0].resp = xstrdup((char *) appdata_ptr);
94439e4e 137 (*resp)[0].resp_retcode = 0;
138
139 return ((*resp)[0].resp ? PAM_SUCCESS : PAM_CONV_ERR);
140}
141
26ac0430 142static struct pam_conv conv = {
94439e4e 143 &password_conversation,
144 NULL
145};
146
fab7a87e 147static void usage(char *program)
94439e4e 148{
fab7a87e 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");
8219a52e 157 fprintf(stderr, " -r Detect and remove Negotiate/NTLM realm from username\n");
94439e4e 158}
159
160int
161main(int argc, char *argv[])
162{
163 pam_handle_t *pamh = NULL;
fab7a87e 164 int retval = PAM_SUCCESS;
94439e4e 165 char *user;
519267d1 166 char *password_buf;
43fed740 167 char buf[HELPER_INPUT_BUFFER];
94439e4e 168 time_t pamh_created = 0;
fab7a87e 169 int ttl = DEFAULT_SQUID_PAM_TTL;
e9505fad 170 const char *service = DEFAULT_SQUID_PAM_SERVICE;
fab7a87e 171 int no_acct_mgmt = 0;
8219a52e 172 int no_realm = 0;
94439e4e 173
174 /* make standard output line buffered */
175 setvbuf(stdout, NULL, _IOLBF, 0);
176
fab7a87e 177 while (1) {
8219a52e 178 int ch = getopt(argc, argv, "1n:t:or");
26ac0430
AJ
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;
8219a52e
SH
194 case 'r':
195 no_realm = 1;
196 break;
26ac0430 197 default:
43fed740 198 fprintf(stderr, "FATAL: Unknown getopt value '%c'\n", ch);
26ac0430 199 usage(argv[0]);
24885773 200 exit(EXIT_FAILURE);
26ac0430 201 }
fab7a87e 202 }
203start:
204 if (optind < argc) {
43fed740 205 fprintf(stderr, "FATAL: Unknown option '%s'\n", argv[optind]);
26ac0430 206 usage(argv[0]);
24885773 207 exit(EXIT_FAILURE);
fab7a87e 208 }
209
43fed740 210 while (fgets(buf, HELPER_INPUT_BUFFER, stdin)) {
26ac0430 211 user = buf;
519267d1
AJ
212 password_buf = strchr(buf, '\n');
213 if (!password_buf) {
43fed740 214 debug("ERROR: %s: Unexpected input '%s'\n", argv[0], buf);
26ac0430
AJ
215 goto error;
216 }
519267d1
AJ
217 *password_buf = '\0';
218 password_buf = strchr(buf, ' ');
219 if (!password_buf) {
43fed740 220 debug("ERROR: %s: Unexpected input '%s'\n", argv[0], buf);
26ac0430
AJ
221 goto error;
222 }
f207fe64
FC
223 *password_buf = '\0';
224 ++password_buf;
26ac0430 225 rfc1738_unescape(user);
519267d1 226 rfc1738_unescape(password_buf);
f53969cc 227 conv.appdata_ptr = (char *) password_buf; /* from buf above. not allocated */
fab7a87e 228
8219a52e
SH
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
519267d1 241#if _SQUID_SOLARIS_
22beb156
A
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;
519267d1 246#endif
26ac0430
AJ
247 if (ttl == 0) {
248 /* Create PAM connection */
249 retval = pam_start(service, user, &conv, &pamh);
250 if (retval != PAM_SUCCESS) {
43fed740 251 debug("ERROR: failed to create PAM authenticator\n");
26ac0430
AJ
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) {
43fed740 259 debug("WARNING: failed to release PAM authenticator\n");
26ac0430
AJ
260 }
261 pamh = NULL;
262 }
263 /* Initialize persistent PAM connection */
264 retval = pam_start(service, "squid@", &conv, &pamh);
265 if (retval != PAM_SUCCESS) {
43fed740 266 debug("ERROR: failed to create PAM authenticator\n");
26ac0430
AJ
267 goto error;
268 }
269 pamh_created = time(NULL);
270 }
271 /* Authentication */
272 retval = PAM_SUCCESS;
273 if (ttl != 0) {
d02b17ee 274 retval = pam_set_item(pamh, PAM_USER, user);
26ac0430
AJ
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) {
43fed740 283 SEND_OK("");
26ac0430 284 } else {
fab7a87e 285error:
43fed740 286 SEND_ERR("");
26ac0430
AJ
287 }
288 /* cleanup */
289 retval = PAM_SUCCESS;
5a48ed18 290#if defined(PAM_AUTHTOK)
d02b17ee
AJ
291 if (ttl != 0 && pamh) {
292 retval = pam_set_item(pamh, PAM_AUTHTOK, NULL);
26ac0430 293 }
4ebcec86 294#endif
d02b17ee 295 if (pamh && (ttl == 0 || retval != PAM_SUCCESS)) {
26ac0430
AJ
296 retval = pam_end(pamh, retval);
297 if (retval != PAM_SUCCESS) {
43fed740 298 debug("WARNING: failed to release PAM authenticator\n");
26ac0430
AJ
299 }
300 pamh = NULL;
301 }
94439e4e 302 }
303
304 if (pamh) {
26ac0430
AJ
305 retval = pam_end(pamh, retval);
306 if (retval != PAM_SUCCESS) {
307 pamh = NULL;
43fed740 308 debug("ERROR: failed to release PAM authenticator\n");
26ac0430 309 }
94439e4e 310 }
24885773 311 return EXIT_SUCCESS;
94439e4e 312}
f53969cc 313