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