]> git.ipfire.org Git - thirdparty/squid.git/blame - helpers/ntlm_auth/smb_lm/ntlm_smb_lm_auth.cc
Added comment on log_file_daemon error reporting
[thirdparty/squid.git] / helpers / ntlm_auth / smb_lm / ntlm_smb_lm_auth.cc
CommitLineData
ca02e0ec 1/*
bde978a6 2 * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
ca02e0ec
AJ
3 *
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
94439e4e 9/*
10 * (C) 2000 Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it>
11 * Distributed freely under the terms of the GNU General Public License,
12 * version 2. See the file COPYING for licensing details
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
26ac0430 18
94439e4e 19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
94439e4e 22 */
ca02e0ec 23
f7f3304a 24#include "squid.h"
25f98340 25#include "base64.h"
59a09b98 26#include "compat/debug.h"
aadbbd7d 27#include "helpers/defines.h"
7c16470c
AJ
28#include "ntlmauth/ntlmauth.h"
29#include "ntlmauth/support_bits.cci"
30#include "rfcnb/rfcnb.h"
31#include "smblib/smblib.h"
dc47f531 32
074d6a40
AJ
33#include <cassert>
34#include <cctype>
35#include <cerrno>
36#include <csignal>
37#include <cstdlib>
38#include <cstring>
39#include <ctime>
1dcf61eb
AJ
40#if HAVE_UNISTD_H
41#include <unistd.h>
42#endif
94439e4e 43#if HAVE_GETOPT_H
44#include <getopt.h>
45#endif
32d002cb 46#if HAVE_UNISTD_H
45b635fa 47#include <unistd.h>
48#endif
1dcf61eb 49
1dcf61eb
AJ
50/************* CONFIGURATION ***************/
51
52#define DEAD_DC_RETRY_INTERVAL 30
53
54/************* END CONFIGURATION ***************/
55
56/* A couple of harmless helper macros */
57#define SEND(X) debug("sending '%s' to squid\n",X); printf(X "\n");
58#ifdef __GNUC__
59#define SEND2(X,Y...) debug("sending '" X "' to squid\n",Y); printf(X "\n",Y);
60#define SEND3(X,Y...) debug("sending '" X "' to squid\n",Y); printf(X "\n",Y);
61#else
62/* no gcc, no debugging. varargs macros are a gcc extension */
63#define SEND2 printf
64#define SEND3 printf
65#endif
66
67const char *make_challenge(char *domain, char *controller);
68char *ntlm_check_auth(ntlm_authenticate * auth, int auth_length);
69void dc_disconnect(void);
70int connectedp(void);
71int is_dc_ok(char *domain, char *domain_controller);
72
73typedef struct _dc dc;
74struct _dc {
75 char *domain;
76 char *controller;
f53969cc 77 time_t dead; /* 0 if it's alive, otherwise time of death */
1dcf61eb
AJ
78 dc *next;
79};
94439e4e 80
a19a836d 81/* local functions */
a19a836d
AJ
82void usage(void);
83void process_options(int argc, char *argv[]);
84const char * obtain_challenge(void);
85void manage_request(void);
86
1dcf61eb
AJ
87#define ENCODED_PASS_LEN 24
88#define MAX_USERNAME_LEN 255
89#define MAX_DOMAIN_LEN 255
90#define MAX_PASSWD_LEN 31
91
92static unsigned char challenge[NTLM_NONCE_LEN];
93static unsigned char lmencoded_empty_pass[ENCODED_PASS_LEN],
f53969cc 94 ntencoded_empty_pass[ENCODED_PASS_LEN];
1dcf61eb
AJ
95SMB_Handle_Type handle = NULL;
96int ntlm_errno;
f53969cc 97static char credentials[MAX_USERNAME_LEN+MAX_DOMAIN_LEN+2]; /* we can afford to waste */
1dcf61eb
AJ
98static char my_domain[100], my_domain_controller[100];
99static char errstr[1001];
32d002cb 100#if DEBUG
1dcf61eb 101char error_messages_buffer[NTLM_BLOB_BUFFER_SIZE];
2d70df72 102#endif
5d146f7d 103char load_balance = 0, protocol_pedantic = 0;
94439e4e 104dc *controllers = NULL;
105int numcontrollers = 0;
106dc *current_dc;
2d70df72 107char smb_error_buffer[1000];
108
1dcf61eb
AJ
109/* Disconnects from the DC. A reconnection will be done upon the next request
110 */
111void
112dc_disconnect()
9bea1d5b 113{
1dcf61eb
AJ
114 if (handle != NULL)
115 SMB_Discon(handle, 0);
116 handle = NULL;
94439e4e 117}
118
1dcf61eb
AJ
119int
120connectedp()
94439e4e 121{
1dcf61eb
AJ
122 return (handle != NULL);
123}
124
125/* Tries to connect to a DC. Returns 0 on failure, 1 on OK */
126int
127is_dc_ok(char *domain, char *domain_controller)
128{
129 SMB_Handle_Type h = SMB_Connect_Server(NULL, domain_controller, domain);
130 if (h == NULL)
131 return 0;
132 SMB_Discon(h, 0);
133 return 1;
134}
135
136/* returns 0 on success, > 0 on failure */
137static int
138init_challenge(char *domain, char *domain_controller)
139{
140 int smberr;
141
142 if (handle != NULL) {
143 return 0;
94439e4e 144 }
1dcf61eb
AJ
145 debug("Connecting to server %s domain %s\n", domain_controller, domain);
146 handle = SMB_Connect_Server(NULL, domain_controller, domain);
147 smberr = SMB_Get_Last_Error();
148 SMB_Get_Error_Msg(smberr, errstr, 1000);
149
f53969cc 150 if (handle == NULL) { /* couldn't connect */
1dcf61eb
AJ
151 debug("Couldn't connect to SMB Server. Error:%s\n", errstr);
152 return 1;
153 }
f53969cc 154 if (SMB_Negotiate(handle, SMB_Prots) < 0) { /* An error */
1dcf61eb
AJ
155 debug("Error negotiating protocol with SMB Server\n");
156 SMB_Discon(handle, 0);
157 handle = NULL;
158 return 2;
159 }
f53969cc 160 if (handle->Security == 0) { /* share-level security, unuseable */
1dcf61eb
AJ
161 debug("SMB Server uses share-level security .. we need user security.\n");
162 SMB_Discon(handle, 0);
163 handle = NULL;
164 return 3;
165 }
166 memcpy(challenge, handle->Encrypt_Key, NTLM_NONCE_LEN);
167 SMBencrypt((unsigned char *)"",challenge,lmencoded_empty_pass);
168 SMBNTencrypt((unsigned char *)"",challenge,ntencoded_empty_pass);
169 return 0;
94439e4e 170}
171
1dcf61eb
AJ
172const char *
173make_challenge(char *domain, char *domain_controller)
94439e4e 174{
1dcf61eb
AJ
175 /* trying to circumvent some strange problem wih pointers in SMBLib */
176 /* Ugly as hell, but the lib is going to be dropped... */
34107f7c
AJ
177 strncpy(my_domain, domain, sizeof(my_domain)-1);
178 my_domain[sizeof(my_domain)-1] = '\0';
179 strncpy(my_domain_controller, domain_controller, sizeof(my_domain_controller)-1);
180 my_domain_controller[sizeof(my_domain_controller)-1] = '\0';
181
1dcf61eb
AJ
182 if (init_challenge(my_domain, my_domain_controller) > 0) {
183 return NULL;
184 }
aadbbd7d 185
1dcf61eb 186 ntlm_challenge chal;
09aabd84
FC
187 uint32_t flags = NTLM_REQUEST_NON_NT_SESSION_KEY |
188 NTLM_CHALLENGE_TARGET_IS_DOMAIN |
189 NTLM_NEGOTIATE_ALWAYS_SIGN |
190 NTLM_NEGOTIATE_USE_NTLM |
191 NTLM_NEGOTIATE_USE_LM |
192 NTLM_NEGOTIATE_ASCII;
1dcf61eb 193 ntlm_make_challenge(&chal, my_domain, my_domain_controller, (char *)challenge, NTLM_NONCE_LEN, flags);
aadbbd7d
AJ
194
195 size_t len = sizeof(chal) - sizeof(chal.payload) + le16toh(chal.target.maxlen);
196 // for lack of a good NTLM token size limit, allow up to what the helper input can be
197 // validations later will expect to be limited to that size.
198 static uint8_t b64buf[HELPER_INPUT_BUFFER-10]; /* 10 for other line fields, delimiters and terminator */
199 if (base64_encode_len(len) < sizeof(b64buf)-1) {
54835620 200 debug("base64 encoding of the token challenge will exceed %" PRIuSIZE " bytes", sizeof(b64buf));
aadbbd7d
AJ
201 return NULL;
202 }
203
204 struct base64_encode_ctx ctx;
205 base64_encode_init(&ctx);
206 size_t blen = base64_encode_update(&ctx, b64buf, len, reinterpret_cast<const uint8_t *>(&chal));
207 blen += base64_encode_final(&ctx, b64buf+blen);
208 b64buf[blen] = '\0';
209 return reinterpret_cast<const char*>(b64buf);
1dcf61eb
AJ
210}
211
212/* returns NULL on failure, or a pointer to
213 * the user's credentials (domain\\username)
214 * upon success. WARNING. It's pointing to static storage.
215 * In case of problem sets as side-effect ntlm_errno to one of the
216 * codes defined in ntlm.h
217 */
218char *
219ntlm_check_auth(ntlm_authenticate * auth, int auth_length)
220{
221 int rv;
222 char pass[MAX_PASSWD_LEN+1];
223 char *domain = credentials;
224 char *user;
225 lstring tmp;
226
f53969cc 227 if (handle == NULL) { /*if null we aren't connected, but it shouldn't happen */
1dcf61eb
AJ
228 debug("Weird, we've been disconnected\n");
229 ntlm_errno = NTLM_ERR_NOT_CONNECTED;
230 return NULL;
231 }
232
233 /* debug("fetching domain\n"); */
234 tmp = ntlm_fetch_string(&(auth->hdr), auth_length, &auth->domain, auth->flags);
235 if (tmp.str == NULL || tmp.l == 0) {
236 debug("No domain supplied. Returning no-auth\n");
237 ntlm_errno = NTLM_ERR_LOGON;
238 return NULL;
239 }
240 if (tmp.l > MAX_DOMAIN_LEN) {
241 debug("Domain string exceeds %d bytes, rejecting\n", MAX_DOMAIN_LEN);
242 ntlm_errno = NTLM_ERR_LOGON;
243 return NULL;
244 }
245 memcpy(domain, tmp.str, tmp.l);
246 user = domain + tmp.l;
f207fe64
FC
247 *user = '\0';
248 ++user;
1dcf61eb
AJ
249
250 /* debug("fetching user name\n"); */
251 tmp = ntlm_fetch_string(&(auth->hdr), auth_length, &auth->user, auth->flags);
252 if (tmp.str == NULL || tmp.l == 0) {
253 debug("No username supplied. Returning no-auth\n");
254 ntlm_errno = NTLM_ERR_LOGON;
255 return NULL;
256 }
257 if (tmp.l > MAX_USERNAME_LEN) {
258 debug("Username string exceeds %d bytes, rejecting\n", MAX_USERNAME_LEN);
259 ntlm_errno = NTLM_ERR_LOGON;
260 return NULL;
261 }
262 memcpy(user, tmp.str, tmp.l);
263 *(user + tmp.l) = '\0';
264
1dcf61eb
AJ
265 /* Authenticating against the NT response doesn't seem to work... */
266 tmp = ntlm_fetch_string(&(auth->hdr), auth_length, &auth->lmresponse, auth->flags);
267 if (tmp.str == NULL || tmp.l == 0) {
268 fprintf(stderr, "No auth at all. Returning no-auth\n");
269 ntlm_errno = NTLM_ERR_LOGON;
270 return NULL;
94439e4e 271 }
1dcf61eb
AJ
272 if (tmp.l > MAX_PASSWD_LEN) {
273 debug("Password string exceeds %d bytes, rejecting\n", MAX_PASSWD_LEN);
274 ntlm_errno = NTLM_ERR_LOGON;
275 return NULL;
276 }
277
278 memcpy(pass, tmp.str, tmp.l);
279 pass[min(MAX_PASSWD_LEN,tmp.l)] = '\0';
280
281#if 1
282 debug("Empty LM pass detection: user: '%s', ours:'%s', his: '%s' (length: %d)\n",
283 user,lmencoded_empty_pass,tmp.str,tmp.l);
284 if (memcmp(tmp.str,lmencoded_empty_pass,ENCODED_PASS_LEN)==0) {
285 fprintf(stderr,"Empty LM password supplied for user %s\\%s. "
286 "No-auth\n",domain,user);
287 ntlm_errno=NTLM_ERR_LOGON;
288 return NULL;
289 }
290
291 tmp = ntlm_fetch_string(&(auth->hdr), auth_length, &auth->ntresponse, auth->flags);
292 if (tmp.str != NULL && tmp.l != 0) {
293 debug("Empty NT pass detection: user: '%s', ours:'%s', his: '%s' (length: %d)\n",
294 user,ntencoded_empty_pass,tmp.str,tmp.l);
295 if (memcmp(tmp.str,lmencoded_empty_pass,ENCODED_PASS_LEN)==0) {
296 fprintf(stderr,"ERROR: Empty NT password supplied for user %s\\%s. No-auth\n", domain, user);
297 ntlm_errno = NTLM_ERR_LOGON;
298 return NULL;
299 }
300 }
301#endif
302
303 /* TODO: check against empty password!!!!! */
304
1dcf61eb
AJ
305 debug("checking domain: '%s', user: '%s', pass='%s'\n", domain, user, pass);
306
307 rv = SMB_Logon_Server(handle, user, pass, domain, 1);
308 debug("Login attempt had result %d\n", rv);
309
f53969cc 310 if (rv != NTLM_ERR_NONE) { /* failed */
1dcf61eb
AJ
311 ntlm_errno = rv;
312 return NULL;
313 }
f53969cc 314 *(user - 1) = '\\'; /* hack. Performing, but ugly. */
1dcf61eb
AJ
315
316 debug("credentials: %s\n", credentials);
317 return credentials;
94439e4e 318}
319
daacd51f
AJ
320extern "C" void timeout_during_auth(int signum);
321
1dcf61eb 322static char got_timeout = 0;
daacd51f
AJ
323/** signal handler to be invoked when the authentication operation
324 * times out */
325void
ced8def3 326timeout_during_auth(int)
1dcf61eb
AJ
327{
328 dc_disconnect();
329}
2d70df72 330
94439e4e 331/*
332 * options:
333 * -b try load-balancing the domain-controllers
334 * -f fail-over to another DC if DC connection fails.
5d146f7d 335 * DEPRECATED and VERBOSELY IGNORED. This is on by default now.
2d70df72 336 * -l last-ditch-mode
94439e4e 337 * domain\controller ...
338 */
a88de9ce 339char *my_program_name = NULL;
340
341void
342usage()
343{
344 fprintf(stderr,
26ac0430
AJ
345 "%s usage:\n%s [-b] [-f] [-d] [-l] domain\\controller [domain\\controller ...]\n"
346 "-b enables load-balancing among controllers\n"
347 "-f enables failover among controllers (DEPRECATED and always active)\n"
26ac0430
AJ
348 "-d enables debugging statements if DEBUG was defined at build-time.\n\n"
349 "You MUST specify at least one Domain Controller.\n"
350 "You can use either \\ or / as separator between the domain name \n"
351 "and the controller name\n",
352 my_program_name, my_program_name);
a88de9ce 353}
354
59a09b98 355/* int debug_enabled=0; defined in libcompat */
a88de9ce 356
94439e4e 357void
358process_options(int argc, char *argv[])
359{
360 int opt, j, had_error = 0;
361 dc *new_dc = NULL, *last_dc = NULL;
3c641669 362 while (-1 != (opt = getopt(argc, argv, "bfld"))) {
26ac0430
AJ
363 switch (opt) {
364 case 'b':
365 load_balance = 1;
366 break;
367 case 'f':
368 fprintf(stderr,
369 "WARNING. The -f flag is DEPRECATED and always active.\n");
370 break;
26ac0430
AJ
371 case 'd':
372 debug_enabled=1;
373 break;
374 default:
375 fprintf(stderr, "unknown option: -%c. Exiting\n", opt);
376 usage();
377 had_error = 1;
378 }
94439e4e 379 }
380 if (had_error)
26ac0430 381 exit(1);
94439e4e 382 /* Okay, now begin filling controllers up */
383 /* we can avoid memcpy-ing, and just reuse argv[] */
755494da 384 for (j = optind; j < argc; ++j) {
26ac0430
AJ
385 char *d, *c;
386 /* d will not be freed in case of non-error. Since we don't reconfigure,
387 * it's going to live as long as the process anyways */
1dcf61eb 388 d = (char*)malloc(strlen(argv[j]) + 1);
26ac0430 389 strcpy(d, argv[j]);
75aa769b 390 debug("Adding domain-controller %s\n", d);
26ac0430
AJ
391 if (NULL == (c = strchr(d, '\\')) && NULL == (c = strchr(d, '/'))) {
392 fprintf(stderr, "Couldn't grok domain-controller %s\n", d);
393 free(d);
394 continue;
395 }
396 /* more than one delimiter is not allowed */
397 if (NULL != strchr(c + 1, '\\') || NULL != strchr(c + 1, '/')) {
398 fprintf(stderr, "Broken domain-controller %s\n", d);
399 free(d);
400 continue;
401 }
f207fe64
FC
402 *c= '\0';
403 ++c;
26ac0430
AJ
404 new_dc = (dc *) malloc(sizeof(dc));
405 if (!new_dc) {
406 fprintf(stderr, "Malloc error while parsing DC options\n");
407 free(d);
408 continue;
409 }
410 /* capitalize */
411 uc(c);
412 uc(d);
755494da 413 ++numcontrollers;
26ac0430
AJ
414 new_dc->domain = d;
415 new_dc->controller = c;
416 new_dc->dead = 0;
f53969cc 417 if (controllers == NULL) { /* first controller */
26ac0430
AJ
418 controllers = new_dc;
419 last_dc = new_dc;
420 } else {
f53969cc 421 last_dc->next = new_dc; /* can't be null */
26ac0430
AJ
422 last_dc = new_dc;
423 }
94439e4e 424 }
425 if (numcontrollers == 0) {
26ac0430
AJ
426 fprintf(stderr, "You must specify at least one domain-controller!\n");
427 usage();
428 exit(1);
94439e4e 429 }
f53969cc 430 last_dc->next = controllers; /* close the queue, now it's circular */
94439e4e 431}
432
a19a836d
AJ
433/**
434 * tries connecting to the domain controllers in the "controllers" ring,
94439e4e 435 * with failover if the adequate option is specified.
436 */
437const char *
438obtain_challenge()
439{
440 int j = 0;
60d096f4 441 const char *ch = NULL;
755494da 442 for (j = 0; j < numcontrollers; ++j) {
75aa769b 443 debug("obtain_challenge: selecting %s\\%s (attempt #%d)\n",
632d8053 444 current_dc->domain, current_dc->controller, j + 1);
26ac0430
AJ
445 if (current_dc->dead != 0) {
446 if (time(NULL) - current_dc->dead >= DEAD_DC_RETRY_INTERVAL) {
447 /* mark helper as retry-worthy if it's so. */
75aa769b 448 debug("Reviving DC\n");
26ac0430 449 current_dc->dead = 0;
f53969cc 450 } else { /* skip it */
75aa769b 451 debug("Skipping it\n");
26ac0430
AJ
452 continue;
453 }
454 }
455 /* else branch. Here we KNOW that the DC is fine */
75aa769b 456 debug("attempting challenge retrieval\n");
26ac0430 457 ch = make_challenge(current_dc->domain, current_dc->controller);
75aa769b 458 debug("make_challenge retuned %p\n", ch);
26ac0430 459 if (ch) {
75aa769b 460 debug("Got it\n");
f53969cc 461 return ch; /* All went OK, returning */
26ac0430
AJ
462 }
463 /* Huston, we've got a problem. Take this DC out of the loop */
75aa769b 464 debug("Marking DC as DEAD\n");
26ac0430
AJ
465 current_dc->dead = time(NULL);
466 /* Try with the next */
75aa769b 467 debug("moving on to next controller\n");
26ac0430 468 current_dc = current_dc->next;
94439e4e 469 }
5d146f7d 470 /* all DCs failed. */
94439e4e 471 return NULL;
472}
473
474void
475manage_request()
476{
477 ntlmhdr *fast_header;
1dcf61eb 478 char buf[NTLM_BLOB_BUFFER_SIZE];
8bdd0cec 479 char decoded[NTLM_BLOB_BUFFER_SIZE];
94439e4e 480 const char *ch;
8bdd0cec 481 char *ch2, *cred = NULL;
94439e4e 482
1dcf61eb 483 if (fgets(buf, NTLM_BLOB_BUFFER_SIZE, stdin) == NULL) {
26ac0430
AJ
484 fprintf(stderr, "fgets() failed! dying..... errno=%d (%s)\n", errno,
485 strerror(errno));
f53969cc 486 exit(1); /* BIIG buffer */
6437ac71 487 }
75aa769b 488 debug("managing request\n");
f53969cc 489 ch2 = (char*)memchr(buf, '\n', NTLM_BLOB_BUFFER_SIZE); /* safer against overrun than strchr */
94439e4e 490 if (ch2) {
f53969cc 491 *ch2 = '\0'; /* terminate the string at newline. */
26ac0430 492 ch = ch2;
94439e4e 493 }
75aa769b 494 debug("ntlm authenticator. Got '%s' from Squid\n", buf);
94439e4e 495
f53969cc 496 if (memcmp(buf, "KK ", 3) == 0) { /* authenticate-request */
26ac0430 497 /* figure out what we got */
aadbbd7d
AJ
498 struct base64_decode_ctx ctx;
499 base64_decode_init(&ctx);
500 size_t dstLen = 0;
501 int decodedLen = 0;
502 if (!base64_decode_update(&ctx, &dstLen, reinterpret_cast<uint8_t*>(decoded), strlen(buf)-3, reinterpret_cast<const uint8_t*>(buf+3)) ||
503 !base64_decode_final(&ctx)) {
504 SEND("NA Packet format error, couldn't base64-decode");
505 return;
506 }
507 decodedLen = dstLen;
26ac0430 508
f53969cc 509 if ((size_t)decodedLen < sizeof(ntlmhdr)) { /* decoding failure, return error */
aadbbd7d 510 SEND("NA Packet format error, truncated packet header.");
26ac0430
AJ
511 return;
512 }
513 /* fast-track-decode request type. */
1dcf61eb 514 fast_header = (ntlmhdr *) decoded;
26ac0430
AJ
515
516 /* sanity-check: it IS a NTLMSSP packet, isn't it? */
1dcf61eb 517 if (ntlm_validate_packet(fast_header, NTLM_ANY) < 0) {
26ac0430
AJ
518 SEND("NA Broken authentication packet");
519 return;
520 }
521 switch (le32toh(fast_header->type)) {
522 case NTLM_NEGOTIATE:
523 SEND("NA Invalid negotiation request received");
524 return;
f53969cc 525 /* notreached */
26ac0430 526 case NTLM_CHALLENGE:
83ae34bc 527 SEND("NA Got a challenge. We refuse to have our authority disputed");
26ac0430 528 return;
f53969cc 529 /* notreached */
26ac0430
AJ
530 case NTLM_AUTHENTICATE:
531 /* check against the DC */
26ac0430
AJ
532 signal(SIGALRM, timeout_during_auth);
533 alarm(30);
8bdd0cec 534 cred = ntlm_check_auth((ntlm_authenticate *) decoded, decodedLen);
26ac0430
AJ
535 alarm(0);
536 signal(SIGALRM, SIG_DFL);
537 if (got_timeout != 0) {
538 fprintf(stderr, "ntlm-auth[%ld]: Timeout during authentication.\n", (long)getpid());
539 SEND("BH Timeout during authentication");
540 got_timeout = 0;
541 return;
542 }
543 if (cred == NULL) {
544 int smblib_err, smb_errorclass, smb_errorcode, nb_error;
f53969cc 545 if (ntlm_errno == NTLM_ERR_LOGON) { /* hackish */
26ac0430
AJ
546 SEND("NA Logon Failure");
547 return;
548 }
549 /* there was an error. We have two errno's to look at.
550 * libntlmssp's erno is insufficient, we'll have to look at
551 * the actual SMB library error codes, to acually figure
552 * out what's happening. The thing has braindamaged interfacess..*/
553 smblib_err = SMB_Get_Last_Error();
554 smb_errorclass = SMBlib_Error_Class(SMB_Get_Last_SMB_Err());
555 smb_errorcode = SMBlib_Error_Code(SMB_Get_Last_SMB_Err());
556 nb_error = RFCNB_Get_Last_Error();
75aa769b
AJ
557 debug("No creds. SMBlib error %d, SMB error class %d, SMB error code %d, NB error %d\n",
558 smblib_err, smb_errorclass, smb_errorcode, nb_error);
26ac0430
AJ
559 /* Should I use smblib_err? Actually it seems I can do as well
560 * without it.. */
f53969cc 561 if (nb_error != 0) { /* netbios-level error */
e490d2a3 562 SEND("BH NetBios error!");
26ac0430
AJ
563 fprintf(stderr, "NetBios error code %d (%s)\n", nb_error,
564 RFCNB_Error_Strings[abs(nb_error)]);
565 return;
566 }
567 switch (smb_errorclass) {
568 case SMBC_SUCCESS:
75aa769b 569 debug("Huh? Got a SMB success code but could check auth..");
26ac0430 570 SEND("NA Authentication failed");
26ac0430
AJ
571 return;
572 case SMBC_ERRDOS:
573 /*this is the most important one for errors */
75aa769b 574 debug("DOS error\n");
26ac0430 575 switch (smb_errorcode) {
f53969cc
SM
576 /* two categories matter to us: those which could be
577 * server errors, and those which are auth errors */
578 case SMBD_noaccess: /* 5 */
26ac0430
AJ
579 SEND("NA Access denied");
580 return;
581 case SMBD_badformat:
582 SEND("NA bad format in authentication packet");
583 return;
584 case SMBD_badaccess:
585 SEND("NA Bad access request");
586 return;
587 case SMBD_baddata:
588 SEND("NA Bad Data");
589 return;
590 default:
e490d2a3 591 SEND("BH DOS Error");
26ac0430
AJ
592 return;
593 }
f53969cc 594 case SMBC_ERRSRV: /* server errors */
75aa769b 595 debug("Server error");
26ac0430 596 switch (smb_errorcode) {
f53969cc 597 /* mostly same as above */
26ac0430
AJ
598 case SMBV_badpw:
599 SEND("NA Bad password");
600 return;
601 case SMBV_access:
602 SEND("NA Server access error");
603 return;
604 default:
e490d2a3 605 SEND("BH Server Error");
26ac0430
AJ
606 return;
607 }
f53969cc 608 case SMBC_ERRHRD: /* hardware errors don't really matter */
e490d2a3 609 SEND("BH Domain Controller Hardware error");
26ac0430
AJ
610 return;
611 case SMBC_ERRCMD:
e490d2a3 612 SEND("BH Domain Controller Command Error");
26ac0430
AJ
613 return;
614 }
83ae34bc
AJ
615 SEND("BH unknown internal error.");
616 return;
26ac0430 617 }
83ae34bc 618
f53969cc 619 lc(cred); /* let's lowercase them for our convenience */
26ac0430
AJ
620 SEND2("AF %s", cred);
621 return;
622 default:
623 SEND("BH unknown authentication packet type");
624 return;
625 }
7c572fcd 626 /* notreached */
26ac0430 627 return;
94439e4e 628 }
f53969cc 629 if (memcmp(buf, "YR", 2) == 0) { /* refresh-request */
26ac0430
AJ
630 dc_disconnect();
631 ch = obtain_challenge();
632 /* Robert says we can afford to wait forever. I'll trust him on this
633 * one */
634 while (ch == NULL) {
635 sleep(30);
636 ch = obtain_challenge();
637 }
638 SEND2("TT %s", ch);
639 return;
94439e4e 640 }
641 SEND("BH Helper detected protocol error");
642 return;
26ac0430 643 /********* END ********/
94439e4e 644
94439e4e 645}
646
647int
648main(int argc, char *argv[])
649{
a20277e1 650 debug("%s " VERSION " " SQUID_BUILD_INFO " starting up...\n", argv[0]);
94439e4e 651
a88de9ce 652 my_program_name = argv[0];
94439e4e 653 process_options(argc, argv);
654
75aa769b 655 debug("options processed OK\n");
94439e4e 656
657 /* initialize FDescs */
658 setbuf(stdout, NULL);
659 setbuf(stderr, NULL);
660
661 /* select the first domain controller we're going to use */
662 current_dc = controllers;
663 if (load_balance != 0 && numcontrollers > 1) {
26ac0430
AJ
664 int n;
665 pid_t pid = getpid();
666 n = pid % numcontrollers;
75aa769b 667 debug("load balancing. Selected controller #%d\n", n);
26ac0430
AJ
668 while (n > 0) {
669 current_dc = current_dc->next;
755494da 670 --n;
26ac0430 671 }
94439e4e 672 }
673 while (1) {
26ac0430 674 manage_request();
94439e4e 675 }
7c572fcd 676 /* notreached */
94439e4e 677 return 0;
678}
f53969cc 679