]> git.ipfire.org Git - thirdparty/squid.git/blob - helpers/basic_auth/PAM/pam_auth.c
Major rewrite of proxy authentication to support other schemes than
[thirdparty/squid.git] / helpers / basic_auth / PAM / pam_auth.c
1 /*
2 * $Id: pam_auth.c,v 1.1 2001/01/07 23:36:45 hno Exp $
3 *
4 * PAM authenticator module for Squid.
5 * Copyright (C) 1999 Henrik Nordstrom <hno@hem.passagen.se>
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, or PAM will not allow
36 * it to authenticate other users than it runs as (this is a security
37 * limitation of PAM to avoid automated probing of passwords).
38 *
39 * Compile this program with: gcc -o pam_auth pam_auth.c -lpam -ldl
40 *
41 */
42
43 #include <stdio.h>
44 #include <assert.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <signal.h>
48 #include <time.h>
49
50 #include <security/pam_appl.h>
51
52 #define BUFSIZE 8192
53
54
55 /* The default PAM service name */
56 #ifndef SQUID_PAM_SERVICE
57 #define SQUID_PAM_SERVICE "squid"
58 #endif
59
60 /* How often to reinitialize PAM, in seconds. Undefined = never, 0=always */
61 /* #define PAM_CONNECTION_TTL 60 */
62
63 static int reset_pam = 1; /* Set to one if it is time to reset PAM processing */
64
65 static char *password = NULL; /* Workaround for Solaris 2.6 brokenness */
66
67 /*
68 * A simple "conversation" function returning the supplied password.
69 * Has a bit to much error control, but this is my first PAM application
70 * so I'd rather check everything than make any mistakes. The function
71 * expects a single converstation message of type PAM_PROMPT_ECHO_OFF.
72 */
73 static int
74 password_conversation(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr)
75 {
76 if (num_msg != 1 || msg[0]->msg_style != PAM_PROMPT_ECHO_OFF) {
77 fprintf(stderr, "ERROR: Unexpected PAM converstaion '%d/%s'\n", msg[0]->msg_style, msg[0]->msg);
78 return PAM_CONV_ERR;
79 }
80 if (!appdata_ptr) {
81 /* Workaround for Solaris 2.6 where the PAM library is broken
82 * and does not pass appdata_ptr to the conversation routine
83 */
84 appdata_ptr = password;
85 }
86 if (!appdata_ptr) {
87 fprintf(stderr, "ERROR: No password available to password_converstation!\n");
88 return PAM_CONV_ERR;
89 }
90 *resp = calloc(num_msg, sizeof(struct pam_response));
91 if (!*resp) {
92 fprintf(stderr, "ERROR: Out of memory!\n");
93 return PAM_CONV_ERR;
94 }
95 (*resp)[0].resp = strdup((char *) appdata_ptr);
96 (*resp)[0].resp_retcode = 0;
97
98 return ((*resp)[0].resp ? PAM_SUCCESS : PAM_CONV_ERR);
99 }
100
101 static struct pam_conv conv =
102 {
103 &password_conversation,
104 NULL
105 };
106
107 void
108 signal_received(int sig)
109 {
110 reset_pam = 1;
111 signal(sig, signal_received);
112 }
113
114 int
115 main(int argc, char *argv[])
116 {
117 pam_handle_t *pamh = NULL;
118 int retval;
119 char *user;
120 /* char *password; */
121 char buf[BUFSIZE];
122 time_t pamh_created = 0;
123
124 signal(SIGHUP, signal_received);
125
126 /* make standard output line buffered */
127 setvbuf(stdout, NULL, _IOLBF, 0);
128
129 while (retval = PAM_SUCCESS, fgets(buf, BUFSIZE, stdin)) {
130 user = buf;
131 password = strchr(buf, '\n');
132 if (!password) {
133 fprintf(stderr, "authenticator: Unexpected input '%s'\n", buf);
134 fprintf(stdout, "ERR\n");
135 continue;
136 }
137 *password = '\0';
138 password = strchr(buf, ' ');
139 if (!password) {
140 fprintf(stderr, "authenticator: Unexpected input '%s'\n", buf);
141 fprintf(stdout, "ERR\n");
142 continue;
143 }
144 *password++ = '\0';
145 conv.appdata_ptr = (char *) password; /* from buf above. not allocated */
146 #ifdef PAM_CONNECTION_TTL
147 if (pamh_created + PAM_CONNECTION_TTL >= time(NULL))
148 reset_pam = 1;
149 #endif
150 if (reset_pam && pamh) {
151 /* Close previous PAM connection */
152 retval = pam_end(pamh, retval);
153 if (retval != PAM_SUCCESS) {
154 fprintf(stderr, "ERROR: failed to release PAM authenticator\n");
155 }
156 pamh = NULL;
157 }
158 if (!pamh) {
159 /* Initialize PAM connection */
160 retval = pam_start(SQUID_PAM_SERVICE, "squid@", &conv, &pamh);
161 if (retval != PAM_SUCCESS) {
162 fprintf(stderr, "ERROR: failed to create PAM authenticator\n");
163 }
164 reset_pam = 0;
165 pamh_created = time(NULL);
166 }
167 if (retval == PAM_SUCCESS)
168 retval = pam_set_item(pamh, PAM_USER, user);
169 if (retval == PAM_SUCCESS)
170 retval = pam_set_item(pamh, PAM_CONV, &conv);
171 if (retval == PAM_SUCCESS)
172 retval = pam_authenticate(pamh, 0);
173 if (retval == PAM_SUCCESS)
174 retval = pam_acct_mgmt(pamh, 0);
175 if (retval == PAM_SUCCESS) {
176 fprintf(stdout, "OK\n");
177 } else {
178 fprintf(stdout, "ERR\n");
179 }
180 }
181
182 if (pamh) {
183 retval = pam_end(pamh, retval);
184 if (retval != PAM_SUCCESS) {
185 pamh = NULL;
186 fprintf(stderr, "ERROR: failed to release PAM authenticator\n");
187 }
188 }
189 return (retval == PAM_SUCCESS ? 0 : 1); /* indicate success */
190 }