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