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