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