]> git.ipfire.org Git - thirdparty/squid.git/blame - helpers/basic_auth/PAM/pam_auth.c
UnitTests: check precompiler is sane with our wrapping style.
[thirdparty/squid.git] / helpers / basic_auth / PAM / pam_auth.c
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 *
2900aadb 40 * Version 2.2, 2003-11-05
41 * One shot mode is now the default mode of operation
42 * with persistent PAM connections enabled by -t option.
43 * Support for clearing the PAM_AUTHTOK attribute on
44 * persistent PAM connections.
45 *
46 * Version 2.1, 2002-08-12
47 * Squid-2.5 support (URL encoded login, password strings)
48 *
fab7a87e 49 * Version 2.0, 2002-01-07
50 * One shot mode, command line options
51 * man page
43f7ea67 52 *
53 * Version 1.3, 1999-12-10
54 * Bugfix release 1.3 to work around Solaris 2.6
55 * brokenness (not sending arguments to conversation
56 * functions)
57 *
fab7a87e 58 * Version 1.2, internal release
43f7ea67 59 *
60 * Version 1.1, 1999-05-11
61 * Initial version
fab7a87e 62 *
63 * Compile this program with: gcc -o pam_auth pam_auth.c -lpam -ldl
94439e4e 64 */
65
7483aded 66#include "util.h"
67
94439e4e 68#include <stdio.h>
69#include <assert.h>
70#include <stdlib.h>
71#include <string.h>
72#include <signal.h>
73#include <time.h>
fab7a87e 74#include <unistd.h>
94439e4e 75
76#include <security/pam_appl.h>
77
78#define BUFSIZE 8192
79
80
81/* The default PAM service name */
fab7a87e 82#ifndef DEFAULT_SQUID_PAM_SERVICE
83#define DEFAULT_SQUID_PAM_SERVICE "squid"
94439e4e 84#endif
85
fab7a87e 86/* The default TTL */
87#ifndef DEFAULT_SQUID_PAM_TTL
2900aadb 88#define DEFAULT_SQUID_PAM_TTL 0
fab7a87e 89#endif
94439e4e 90
91static char *password = NULL; /* Workaround for Solaris 2.6 brokenness */
92
93/*
94 * A simple "conversation" function returning the supplied password.
95 * Has a bit to much error control, but this is my first PAM application
96 * so I'd rather check everything than make any mistakes. The function
97 * expects a single converstation message of type PAM_PROMPT_ECHO_OFF.
98 */
99static int
100password_conversation(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr)
101{
102 if (num_msg != 1 || msg[0]->msg_style != PAM_PROMPT_ECHO_OFF) {
26ac0430
AJ
103 fprintf(stderr, "ERROR: Unexpected PAM converstaion '%d/%s'\n", msg[0]->msg_style, msg[0]->msg);
104 return PAM_CONV_ERR;
94439e4e 105 }
106 if (!appdata_ptr) {
26ac0430
AJ
107 /* Workaround for Solaris 2.6 where the PAM library is broken
108 * and does not pass appdata_ptr to the conversation routine
109 */
110 appdata_ptr = password;
94439e4e 111 }
112 if (!appdata_ptr) {
26ac0430
AJ
113 fprintf(stderr, "ERROR: No password available to password_converstation!\n");
114 return PAM_CONV_ERR;
94439e4e 115 }
116 *resp = calloc(num_msg, sizeof(struct pam_response));
117 if (!*resp) {
26ac0430
AJ
118 fprintf(stderr, "ERROR: Out of memory!\n");
119 return PAM_CONV_ERR;
94439e4e 120 }
121 (*resp)[0].resp = strdup((char *) appdata_ptr);
122 (*resp)[0].resp_retcode = 0;
123
124 return ((*resp)[0].resp ? PAM_SUCCESS : PAM_CONV_ERR);
125}
126
26ac0430 127static struct pam_conv conv = {
94439e4e 128 &password_conversation,
129 NULL
130};
131
fab7a87e 132static void usage(char *program)
94439e4e 133{
fab7a87e 134 fprintf(stderr, "Usage: %s [options..]\n", program);
135 fprintf(stderr, " -n service_name\n");
136 fprintf(stderr, " The PAM service name (default \"%s\")\n", DEFAULT_SQUID_PAM_SERVICE);
137 fprintf(stderr, " -t ttl PAM connection ttl in seconds (default %d)\n", DEFAULT_SQUID_PAM_TTL);
138 fprintf(stderr, " during this time the same connection will be reused\n");
139 fprintf(stderr, " to authenticate all users\n");
140 fprintf(stderr, " -o Do not perform account mgmt (account expiration etc)\n");
141 fprintf(stderr, " -1 Only one user authentication per PAM connection\n");
94439e4e 142}
143
144int
145main(int argc, char *argv[])
146{
147 pam_handle_t *pamh = NULL;
fab7a87e 148 int retval = PAM_SUCCESS;
94439e4e 149 char *user;
150 /* char *password; */
151 char buf[BUFSIZE];
152 time_t pamh_created = 0;
fab7a87e 153 int ttl = DEFAULT_SQUID_PAM_TTL;
e9505fad 154 const char *service = DEFAULT_SQUID_PAM_SERVICE;
fab7a87e 155 int no_acct_mgmt = 0;
94439e4e 156
157 /* make standard output line buffered */
158 setvbuf(stdout, NULL, _IOLBF, 0);
159
fab7a87e 160 while (1) {
26ac0430
AJ
161 int ch = getopt(argc, argv, "1n:t:o");
162 switch (ch) {
163 case -1:
164 goto start;
165 case 'n':
166 service = optarg;
167 break;
168 case 't':
169 ttl = atoi(optarg);
170 break;
171 case '1':
172 ttl = 0;
173 break;
174 case 'o':
175 no_acct_mgmt = 1;
176 break;
177 default:
178 fprintf(stderr, "Unknown getopt value '%c'\n", ch);
179 usage(argv[0]);
180 exit(1);
181 }
fab7a87e 182 }
183start:
184 if (optind < argc) {
26ac0430
AJ
185 fprintf(stderr, "Unknown option '%s'\n", argv[optind]);
186 usage(argv[0]);
187 exit(1);
fab7a87e 188 }
189
190 while (fgets(buf, BUFSIZE, stdin)) {
26ac0430
AJ
191 user = buf;
192 password = strchr(buf, '\n');
193 if (!password) {
194 fprintf(stderr, "authenticator: Unexpected input '%s'\n", buf);
195 goto error;
196 }
197 *password = '\0';
198 password = strchr(buf, ' ');
199 if (!password) {
200 fprintf(stderr, "authenticator: Unexpected input '%s'\n", buf);
201 goto error;
202 }
203 *password++ = '\0';
204 rfc1738_unescape(user);
205 rfc1738_unescape(password);
206 conv.appdata_ptr = (char *) password; /* from buf above. not allocated */
fab7a87e 207
26ac0430
AJ
208 if (ttl == 0) {
209 /* Create PAM connection */
210 retval = pam_start(service, user, &conv, &pamh);
211 if (retval != PAM_SUCCESS) {
212 fprintf(stderr, "ERROR: failed to create PAM authenticator\n");
213 goto error;
214 }
215 } else if (!pamh || (time(NULL) - pamh_created) >= ttl || pamh_created > time(NULL)) {
216 /* Close previous PAM connection */
217 if (pamh) {
218 retval = pam_end(pamh, retval);
219 if (retval != PAM_SUCCESS) {
220 fprintf(stderr, "WARNING: failed to release PAM authenticator\n");
221 }
222 pamh = NULL;
223 }
224 /* Initialize persistent PAM connection */
225 retval = pam_start(service, "squid@", &conv, &pamh);
226 if (retval != PAM_SUCCESS) {
227 fprintf(stderr, "ERROR: failed to create PAM authenticator\n");
228 goto error;
229 }
230 pamh_created = time(NULL);
231 }
232 /* Authentication */
233 retval = PAM_SUCCESS;
234 if (ttl != 0) {
235 if (retval == PAM_SUCCESS)
236 retval = pam_set_item(pamh, PAM_USER, user);
237 if (retval == PAM_SUCCESS)
238 retval = pam_set_item(pamh, PAM_CONV, &conv);
239 }
240 if (retval == PAM_SUCCESS)
241 retval = pam_authenticate(pamh, 0);
242 if (retval == PAM_SUCCESS && !no_acct_mgmt)
243 retval = pam_acct_mgmt(pamh, 0);
244 if (retval == PAM_SUCCESS) {
245 fprintf(stdout, "OK\n");
246 } else {
fab7a87e 247error:
26ac0430
AJ
248 fprintf(stdout, "ERR\n");
249 }
250 /* cleanup */
251 retval = PAM_SUCCESS;
4ebcec86 252#ifdef PAM_AUTHTOK
26ac0430
AJ
253 if (ttl != 0) {
254 if (retval == PAM_SUCCESS)
255 retval = pam_set_item(pamh, PAM_AUTHTOK, NULL);
256 }
4ebcec86 257#endif
26ac0430
AJ
258 if (ttl == 0 || retval != PAM_SUCCESS) {
259 retval = pam_end(pamh, retval);
260 if (retval != PAM_SUCCESS) {
261 fprintf(stderr, "WARNING: failed to release PAM authenticator\n");
262 }
263 pamh = NULL;
264 }
94439e4e 265 }
266
267 if (pamh) {
26ac0430
AJ
268 retval = pam_end(pamh, retval);
269 if (retval != PAM_SUCCESS) {
270 pamh = NULL;
271 fprintf(stderr, "ERROR: failed to release PAM authenticator\n");
272 }
94439e4e 273 }
fab7a87e 274 return 0;
94439e4e 275}