From: Daniel Dehennin Date: Tue, 29 Oct 2013 10:50:03 +0100 Subject: Add NTLM login on multiple and different domains MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch add the “-a” option to “ntlm_smb_lm_auth” which makes authentication valid if one of the domain controllers validate it. --- helpers/ntlm_auth/smb_lm/ntlm_smb_lm_auth.cc | 125 ++++++++++++++++++++++------ 1 file changed, 98 insertions(+), 27 deletions(-) diff --git a/helpers/ntlm_auth/smb_lm/ntlm_smb_lm_auth.cc b/helpers/ntlm_auth/smb_lm/ntlm_smb_lm_auth.cc index 7e674e0..72348cb 100644 --- a/helpers/ntlm_auth/smb_lm/ntlm_smb_lm_auth.cc +++ b/helpers/ntlm_auth/smb_lm/ntlm_smb_lm_auth.cc @@ -22,6 +22,8 @@ #include "smblib/smblib.h" //#include "util.h" +#define MAX_DOMAIN_LEN 255 + #if HAVE_STRING_H #include #endif @@ -91,7 +93,8 @@ void usage(void); void process_options(int argc, char *argv[]); const char * obtain_challenge(void); -void manage_request(void); +int manage_request(void); +int choose_dc(ntlm_authenticate * auth, int plen, int type); #define ENCODED_PASS_LEN 24 #define MAX_USERNAME_LEN 255 @@ -109,6 +112,8 @@ #if DEBUG char error_messages_buffer[NTLM_BLOB_BUFFER_SIZE]; #endif + +int any_controller = 0; /* To authenticate on any available controller, default: NO */ char load_balance = 0, protocol_pedantic = 0; dc *controllers = NULL; int numcontrollers = 0; @@ -337,6 +342,7 @@ { fprintf(stderr, "%s usage:\n%s [-b] [-f] [-d] [-l] domain\\controller [domain\\controller ...]\n" + "-a any valid authentication on one of the domain controllers is enough to authenticate\n" "-b enables load-balancing among controllers\n" "-f enables failover among controllers (DEPRECATED and always active)\n" "-d enables debugging statements if DEBUG was defined at build-time.\n\n" @@ -353,8 +359,11 @@ { int opt, j, had_error = 0; dc *new_dc = NULL, *last_dc = NULL; - while (-1 != (opt = getopt(argc, argv, "bfld"))) { + while (-1 != (opt = getopt(argc, argv, "abfld"))) { switch (opt) { + case 'a': + any_controller = 1; + break; case 'b': load_balance = 1; break; @@ -465,7 +474,57 @@ return NULL; } -void +int +choose_dc(ntlm_authenticate * auth, int plen, int type) +{ + /* This function extracts the domain from the decoded message (type 1 + * (negotiate) or type 3 (authenticate)) and modifies the global variable + * current_dc accordingly. */ + int i; + char domain[MAX_DOMAIN_LEN+2]; + lstring tmp; + + /* Extract domain from decoded message: */ + switch (type) { + case NTLM_NEGOTIATE: + tmp = ntlm_fetch_string(&(auth->hdr), plen, &auth->domain, auth->flags); + break; + case NTLM_AUTHENTICATE: + tmp = ntlm_fetch_string(&(auth->hdr), plen, &auth->domain, auth->flags); + break; + default: + fprintf(stderr, "Unknown requested type (%d) in choose_dc.\n", + type); + return 101; + } + if (tmp.str == NULL || tmp.l == 0) { + debug("No domain supplied. Returning no-auth\n"); + return NTLM_ERR_LOGON; + } + if (tmp.l > MAX_DOMAIN_LEN) { + debug("Domain string exceeds %d bytes, rejecting\n", MAX_DOMAIN_LEN); + return NTLM_ERR_LOGON; + } + if (tmp.l > MAX_DOMAIN_LEN || tmp.l <= 0) return 111; + memcpy(domain, tmp.str, tmp.l); + domain[tmp.l] = '\0'; + + /* Select a dc according to the domain fetched above: */ + for (i = 0; i < numcontrollers && + memcmp(domain, current_dc->domain, tmp.l) != 0; i++) { + current_dc = current_dc->next; + } + + /* Check the result: */ + if (memcmp(domain, current_dc->domain, tmp.l) != 0) { + fprintf(stderr, "dc for %s not found (current_dc:%s)!\n", + domain, current_dc->domain); + return 121; /* Failure. */ + } + return 0; /* Success. */ +} + +int manage_request() { ntlmhdr *fast_header; @@ -493,7 +552,7 @@ if ((size_t)decodedLen < sizeof(ntlmhdr)) { /* decoding failure, return error */ SEND("NA Packet format error, couldn't base64-decode"); - return; + return NTLM_ERR_BAD_PROTOCOL; } /* fast-track-decode request type. */ fast_header = (ntlmhdr *) decoded; @@ -501,21 +560,24 @@ /* sanity-check: it IS a NTLMSSP packet, isn't it? */ if (ntlm_validate_packet(fast_header, NTLM_ANY) < 0) { SEND("NA Broken authentication packet"); - return; + return NTLM_ERR_BAD_PROTOCOL; } switch (le32toh(fast_header->type)) { case NTLM_NEGOTIATE: SEND("NA Invalid negotiation request received"); - return; + return NTLM_ERR_BAD_PROTOCOL; /* notreached */ case NTLM_CHALLENGE: SEND("NA Got a challenge. We refuse to have our authority disputed"); - return; + return NTLM_ERR_BAD_PROTOCOL; /* notreached */ case NTLM_AUTHENTICATE: /* check against the DC */ signal(SIGALRM, timeout_during_auth); alarm(30); + if (any_controller) { + choose_dc((ntlm_authenticate *) decoded, decodedLen, NTLM_AUTHENTICATE); + } cred = ntlm_check_auth((ntlm_authenticate *) decoded, decodedLen); alarm(0); signal(SIGALRM, SIG_DFL); @@ -523,13 +585,13 @@ fprintf(stderr, "ntlm-auth[%ld]: Timeout during authentication.\n", (long)getpid()); SEND("BH Timeout during authentication"); got_timeout = 0; - return; + return NTLM_ERR_SERVER; } if (cred == NULL) { int smblib_err, smb_errorclass, smb_errorcode, nb_error; if (ntlm_errno == NTLM_ERR_LOGON) { /* hackish */ SEND("NA Logon Failure"); - return; + return NTLM_ERR_SERVER; } /* there was an error. We have two errno's to look at. * libntlmssp's erno is insufficient, we'll have to look at @@ -547,13 +609,13 @@ SEND("BH NetBios error!"); fprintf(stderr, "NetBios error code %d (%s)\n", nb_error, RFCNB_Error_Strings[abs(nb_error)]); - return; + return NTLM_ERR_SERVER; } switch (smb_errorclass) { case SMBC_SUCCESS: debug("Huh? Got a SMB success code but could check auth.."); SEND("NA Authentication failed"); - return; + return NTLM_ERR_LOGON; case SMBC_ERRDOS: /*this is the most important one for errors */ debug("DOS error\n"); @@ -562,19 +624,19 @@ * server errors, and those which are auth errors */ case SMBD_noaccess: /* 5 */ SEND("NA Access denied"); - return; + return NTLM_ERR_LOGON; case SMBD_badformat: SEND("NA bad format in authentication packet"); - return; + return NTLM_ERR_LOGON; case SMBD_badaccess: SEND("NA Bad access request"); - return; + return NTLM_ERR_LOGON; case SMBD_baddata: SEND("NA Bad Data"); - return; + return NTLM_ERR_LOGON; default: SEND("BH DOS Error"); - return; + return NTLM_ERR_LOGON; } case SMBC_ERRSRV: /* server errors */ debug("Server error"); @@ -582,36 +644,39 @@ /* mostly same as above */ case SMBV_badpw: SEND("NA Bad password"); - return; + return NTLM_ERR_LOGON; case SMBV_access: SEND("NA Server access error"); - return; + return NTLM_ERR_SERVER; default: SEND("BH Server Error"); - return; + return NTLM_ERR_SERVER; } case SMBC_ERRHRD: /* hardware errors don't really matter */ SEND("BH Domain Controller Hardware error"); - return; + return NTLM_ERR_SERVER; case SMBC_ERRCMD: SEND("BH Domain Controller Command Error"); - return; + return NTLM_ERR_SERVER; } SEND("BH unknown internal error."); - return; + return NTLM_ERR_SERVER; } lc(cred); /* let's lowercase them for our convenience */ SEND2("AF %s", cred); - return; + return NTLM_ERR_NONE; default: SEND("BH unknown authentication packet type"); - return; + return NTLM_ERR_BAD_PROTOCOL; } /* notreached */ - return; + return NTLM_ERR_PROTOCOL; /* The 'authenticate request' did not match any of the above */ } if (memcmp(buf, "YR", 2) == 0) { /* refresh-request */ + if (any_controller) { + choose_dc((ntlm_authenticate *) decoded, base64_decode(decoded, sizeof(decoded), buf+3), NTLM_NEGOTIATE); + } dc_disconnect(); ch = obtain_challenge(); /* Robert says we can afford to wait forever. I'll trust him on this @@ -621,10 +686,10 @@ ch = obtain_challenge(); } SEND2("TT %s", ch); - return; + return NTLM_ERR_NONE; } SEND("BH Helper detected protocol error"); - return; + return NTLM_ERR_PROTOCOL; /********* END ********/ } @@ -639,6 +704,11 @@ debug("options processed OK\n"); + if ( load_balance && any_controller ) { + fprintf(stderr, "Cannot both load balance AND do authentication on any controller, exiting\n"); + exit(1); + } + /* initialize FDescs */ setbuf(stdout, NULL); setbuf(stderr, NULL);