]> git.ipfire.org Git - thirdparty/squid.git/blame - helpers/negotiate_auth/mswin_sspi/negotiate_auth.c
Windows port: addition of native authentication helpers.
[thirdparty/squid.git] / helpers / negotiate_auth / mswin_sspi / negotiate_auth.c
CommitLineData
6e785d85 1/*
2 * win32_ntlm_auth: helper for NTLM Authentication for Squid Cache
3 *
4 * (C)2005 Guido Serassio - Acme Consulting S.r.l.
5 *
6 * Authors:
7 * Guido Serassio <guido.serassio@acmeconsulting.it>
8 * Acme Consulting S.r.l., Italy <http://www.acmeconsulting.it>
9 *
10 * With contributions from others mentioned in the change history section
11 * below.
12 *
13 * Based on previous work of Francesco Chemolli and Robert Collins.
14 *
15 * Dependencies: Windows NT4 SP4 and later.
16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
30 *
31 * History:
32 *
33 * Version 1.0
34 * 29-10-2005 Guido Serassio
35 * First release.
36 *
37 *
38 */
39
40#include "util.h"
41#if HAVE_GETOPT_H
42#include <getopt.h>
43#endif
44#include "negotiate.h"
45#if HAVE_CTYPE_H
46#include <ctype.h>
47#endif
48
49#define BUFFER_SIZE 10240
50
51int debug_enabled = 0;
52int Negotiate_packet_debug_enabled = 0;
53
54static int have_serverblob;
55
56/* makes a null-terminated string upper-case. Changes CONTENTS! */
57void
58uc(char *string)
59{
60 char *p = string, c;
61 while ((c = *p)) {
62 *p = toupper(c);
63 p++;
64 }
65}
66
67/* makes a null-terminated string lower-case. Changes CONTENTS! */
68static void
69lc(char *string)
70{
71 char *p = string, c;
72 while ((c = *p)) {
73 *p = tolower(c);
74 p++;
75 }
76}
77
78void
79helperfail(const char *reason)
80{
81#if FAIL_DEBUG
82 fail_debug_enabled =1;
83#endif
84 SEND2("BH %s", reason);
85}
86
87/*
88 options:
89 -d enable debugging.
90 -v enable verbose NTLM packet debugging.
91 */
92char *my_program_name = NULL;
93
94void
95usage()
96{
97 fprintf(stderr,
98 "Usage: %s [-d] [-v] [-h]\n"
99 " -d enable debugging.\n"
100 " -v enable verbose NTLM packet debugging.\n"
101 " -h this message\n\n",
102 my_program_name);
103}
104
105
106void
107process_options(int argc, char *argv[])
108{
109 int opt, had_error = 0;
110
111 opterr =0;
112 while (-1 != (opt = getopt(argc, argv, "hdv"))) {
113 switch (opt) {
114 case 'd':
115 debug_enabled = 1;
116 break;
117 case 'v':
118 debug_enabled = 1;
119 Negotiate_packet_debug_enabled = 1;
120 break;
121 case 'h':
122 usage();
123 exit(0);
124 case '?':
125 opt = optopt;
126 /* fall thru to default */
127 default:
128 fprintf(stderr, "unknown option: -%c. Exiting\n", opt);
129 usage();
130 had_error = 1;
131 }
132 }
133 if (had_error)
134 exit(1);
135}
136
137int
138manage_request()
139{
140 char buf[BUFFER_SIZE];
141 char helper_command[3];
142 char *c, *decoded;
143 int plen, status;
144 int oversized = 0;
145 char * ErrorMessage;
146 static char cred[SSP_MAX_CRED_LEN+1];
147 BOOL Done = FALSE;
148
149try_again:
150 if (fgets(buf, BUFFER_SIZE, stdin) == NULL)
151 return 0;
152
153 c = memchr(buf, '\n', BUFFER_SIZE); /* safer against overrun than strchr */
154 if (c) {
155 if (oversized) {
156 helperfail("illegal request received");
157 fprintf(stderr, "Illegal request received: '%s'\n", buf);
158 return 1;
159 }
160 *c = '\0';
161 } else {
162 fprintf(stderr, "No newline in '%s'\n", buf);
163 oversized = 1;
164 goto try_again;
165 }
166
167 if ((strlen(buf) > 3) && Negotiate_packet_debug_enabled) {
168 decoded = base64_decode(buf + 3);
169 strncpy(helper_command, buf, 2);
170 debug("Got '%s' from Squid with data:\n", helper_command);
171 hex_dump(decoded, ((strlen(buf) - 3) * 3) / 4);
172 } else
173 debug("Got '%s' from Squid\n", buf);
174
175 if (memcmp(buf, "YR ", 3) == 0) { /* refresh-request */
176 /* figure out what we got */
177 decoded = base64_decode(buf + 3);
178 /* Note: we don't need to manage memory at this point, since
179 * base64_decode returns a pointer to static storage.
180 */
181 if (!decoded) { /* decoding failure, return error */
182 SEND("NA * Packet format error, couldn't base64-decode");
183 return 1;
184 }
185 /* Obtain server blob against SSPI */
186 plen = (strlen(buf) - 3) * 3 / 4; /* we only need it here. Optimization */
187 c = (char *) SSP_MakeNegotiateBlob(decoded, plen, &Done, &status, cred);
188
189 if (status == SSP_OK) {
190 if (Done) {
191 lc(cred); /* let's lowercase them for our convenience */
192 have_serverblob = 0;
193 Done = FALSE;
194 if (Negotiate_packet_debug_enabled) {
195 printf("AF %s %s\n",c,cred);
196 decoded = base64_decode(c);
197 debug("sending 'AF' %s to squid with data:\n", cred);
198 hex_dump(decoded, (strlen(c) * 3) / 4);
199 } else
200 SEND3("AF %s %s", c, cred);
201 } else {
202 if (Negotiate_packet_debug_enabled) {
203 printf("TT %s\n",c);
204 decoded = base64_decode(c);
205 debug("sending 'TT' to squid with data:\n");
206 hex_dump(decoded, (strlen(c) * 3) / 4);
207 } else {
208 SEND2("TT %s", c);
209 }
210 have_serverblob = 1;
211 }
212 } else
213 helperfail("can't obtain server blob");
214 return 1;
215 }
216
217 if (memcmp(buf, "KK ", 3) == 0) { /* authenticate-request */
218 if (!have_serverblob) {
219 helperfail("invalid server blob");
220 return 1;
221 }
222 /* figure out what we got */
223 decoded = base64_decode(buf + 3);
224 /* Note: we don't need to manage memory at this point, since
225 * base64_decode returns a pointer to static storage.
226 */
227 if (!decoded) { /* decoding failure, return error */
228 SEND("NA * Packet format error, couldn't base64-decode");
229 return 1;
230 }
231
232 /* check against SSPI */
233 plen = (strlen(buf) - 3) * 3 / 4; /* we only need it here. Optimization */
234 c = (char *) SSP_ValidateNegotiateCredentials(decoded, plen, &Done, &status, cred);
235
236 if (status == SSP_ERROR) {
237#if FAIL_DEBUG
238 fail_debug_enabled = 1;
239#endif
240 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
241 FORMAT_MESSAGE_IGNORE_INSERTS,
242 NULL,
243 GetLastError(),
244 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
245 (LPTSTR) &ErrorMessage,
246 0,
247 NULL);
248 if (ErrorMessage[strlen(ErrorMessage) - 1] == '\n')
249 ErrorMessage[strlen(ErrorMessage) - 1] = '\0';
250 if (ErrorMessage[strlen(ErrorMessage) - 1] == '\r')
251 ErrorMessage[strlen(ErrorMessage) - 1] = '\0';
252 SEND2("NA * %s", ErrorMessage);
253 LocalFree(ErrorMessage);
254 return 1;
255 }
256
257 if (Done) {
258 lc(cred); /* let's lowercase them for our convenience */
259 have_serverblob = 0;
260 Done = FALSE;
261 if (Negotiate_packet_debug_enabled) {
262 printf("AF %s %s\n",c,cred);
263 decoded = base64_decode(c);
264 debug("sending 'AF' %s to squid with data:\n", cred);
265 hex_dump(decoded, (strlen(c) * 3) / 4);
266 } else {
267 SEND3("AF %s %s", c, cred);
268 }
269 return 1;
270 } else {
271 if (Negotiate_packet_debug_enabled) {
272 printf("TT %s\n",c);
273 decoded = base64_decode(c);
274 debug("sending 'TT' to squid with data:\n");
275 hex_dump(decoded, (strlen(c) * 3) / 4);
276 } else
277 SEND2("TT %s", c);
278 return 1;
279 }
280
281 } else { /* not an auth-request */
282 helperfail("illegal request received");
283 fprintf(stderr, "Illegal request received: '%s'\n", buf);
284 return 1;
285 }
286 helperfail("detected protocol error");
287 return 1;
288/********* END ********/
289}
290
291int
292main(int argc, char *argv[])
293{
294 my_program_name = argv[0];
295
296 process_options(argc, argv);
297
298 debug("%s build " __DATE__ ", " __TIME__ " starting up...\n", my_program_name);
299
300 if (LoadSecurityDll(SSP_NTLM, NEGOTIATE_PACKAGE_NAME) == NULL) {
301 fprintf(stderr, "FATAL, can't initialize SSPI, exiting.\n");
302 exit(1);
303 }
304 debug("SSPI initialized OK\n");
305
306 atexit(UnloadSecurityDll);
307
308 /* initialize FDescs */
309 setbuf(stdout, NULL);
310 setbuf(stderr, NULL);
311
312 while (manage_request()) {
313 /* everything is done within manage_request */
314 }
315 exit(0);
316}