summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/auth/auth_domain.c7
-rw-r--r--source3/auth/auth_util.c3
-rw-r--r--source3/include/rpc_netlogon.h2
-rw-r--r--source3/lib/util_str.c24
-rw-r--r--source3/libsmb/ntlmssp.c50
-rw-r--r--source3/nsswitch/wb_common.c73
-rw-r--r--source3/nsswitch/winbindd.c30
-rw-r--r--source3/nsswitch/winbindd.h2
-rw-r--r--source3/nsswitch/winbindd_misc.c17
-rw-r--r--source3/nsswitch/winbindd_nss.h5
-rw-r--r--source3/nsswitch/winbindd_pam.c13
-rw-r--r--source3/nsswitch/winbindd_util.c24
-rw-r--r--source3/rpc_client/cli_netlogon.c13
-rw-r--r--source3/utils/ntlm_auth.c164
14 files changed, 283 insertions, 144 deletions
diff --git a/source3/auth/auth_domain.c b/source3/auth/auth_domain.c
index 0d90a184a4..534af2257d 100644
--- a/source3/auth/auth_domain.c
+++ b/source3/auth/auth_domain.c
@@ -350,13 +350,6 @@ static NTSTATUS domain_client_validate(TALLOC_CTX *mem_ctx,
} else {
nt_status = make_server_info_info3(mem_ctx, user_info->internal_username.str,
user_info->smb_name.str, domain, server_info, &info3);
-#if 0
- /* The stuff doesn't work right yet */
- SMB_ASSERT(sizeof((*server_info)->session_key) == sizeof(info3.user_sess_key));
- memcpy((*server_info)->session_key, info3.user_sess_key, sizeof((*server_info)->session_key)/* 16 */);
- SamOEMhash((*server_info)->session_key, trust_passwd, sizeof((*server_info)->session_key));
-#endif
-
uni_group_cache_store_netlogon(mem_ctx, &info3);
}
diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c
index 7d85153bd0..d0f1fc1e34 100644
--- a/source3/auth/auth_util.c
+++ b/source3/auth/auth_util.c
@@ -1083,6 +1083,9 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx,
SAFE_FREE(all_group_SIDs);
+ memcpy((*server_info)->session_key, info3->user_sess_key, sizeof((*server_info)->session_key)/* 16 */);
+ memcpy((*server_info)->first_8_lm_hash, info3->padding, 8);
+
return NT_STATUS_OK;
}
diff --git a/source3/include/rpc_netlogon.h b/source3/include/rpc_netlogon.h
index fb849f8238..74e3a50ee4 100644
--- a/source3/include/rpc_netlogon.h
+++ b/source3/include/rpc_netlogon.h
@@ -156,7 +156,7 @@ typedef struct net_user_info_3
uint32 buffer_groups; /* undocumented buffer pointer to groups. */
uint32 user_flgs; /* user flags */
- uint8 user_sess_key[16]; /* unused user session key */
+ uint8 user_sess_key[16]; /* user session key */
UNIHDR hdr_logon_srv; /* logon server unicode string header */
UNIHDR hdr_logon_dom; /* logon domain unicode string header */
diff --git a/source3/lib/util_str.c b/source3/lib/util_str.c
index d1e57ed5cf..4d955c59a7 100644
--- a/source3/lib/util_str.c
+++ b/source3/lib/util_str.c
@@ -603,8 +603,12 @@ char *StrnCpy_fn(const char *fn, int line,char *dest,const char *src,size_t n)
*dest = 0;
return(dest);
}
- while (n-- && (*d++ = *src++))
- ;
+
+ while (n-- && (*d = *src)) {
+ d++;
+ src++;
+ }
+
*d = 0;
return(dest);
}
@@ -682,6 +686,22 @@ size_t strhex_to_str(char *p, size_t len, const char *strhex)
}
/**
+ * Routine to print a buffer as HEX digits, into an allocated string.
+ */
+
+void hex_encode(const unsigned char *buff_in, size_t len, char **out_hex_buffer)
+{
+ int i;
+ char *hex_buffer;
+
+ *out_hex_buffer = smb_xmalloc((len*2)+1);
+ hex_buffer = *out_hex_buffer;
+
+ for (i = 0; i < len; i++)
+ slprintf(&hex_buffer[i*2], 3, "%02X", buff_in[i]);
+}
+
+/**
Check if a string is part of a list.
**/
diff --git a/source3/libsmb/ntlmssp.c b/source3/libsmb/ntlmssp.c
index 5722b8efcd..0cd1ac33ec 100644
--- a/source3/libsmb/ntlmssp.c
+++ b/source3/libsmb/ntlmssp.c
@@ -121,7 +121,8 @@ static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state,
{
DATA_BLOB struct_blob;
fstring dnsname, dnsdomname;
- uint32 ntlmssp_command, neg_flags, chal_flags;
+ uint32 neg_flags = 0;
+ uint32 ntlmssp_command, chal_flags;
char *cliname=NULL, *domname=NULL;
const uint8 *cryptkey;
const char *target_name;
@@ -131,20 +132,24 @@ static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state,
file_save("ntlmssp_negotiate.dat", request.data, request.length);
#endif
- if (!msrpc_parse(&request, "CddAA",
- "NTLMSSP",
- &ntlmssp_command,
- &neg_flags,
- &cliname,
- &domname)) {
- return NT_STATUS_INVALID_PARAMETER;
+ if (request.length) {
+ if (!msrpc_parse(&request, "CddAA",
+ "NTLMSSP",
+ &ntlmssp_command,
+ &neg_flags,
+ &cliname,
+ &domname)) {
+ DEBUG(1, ("ntlmssp_server_negotiate: failed to parse NTLMSSP:\n"));
+ dump_data(2, request.data, request.length);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ SAFE_FREE(cliname);
+ SAFE_FREE(domname);
+
+ debug_ntlmssp_flags(neg_flags);
}
-
- SAFE_FREE(cliname);
- SAFE_FREE(domname);
-
- debug_ntlmssp_flags(neg_flags);
-
+
cryptkey = ntlmssp_state->get_challenge(ntlmssp_state);
data_blob_free(&ntlmssp_state->chal);
@@ -268,6 +273,8 @@ static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state,
&ntlmssp_state->workstation,
&sess_key,
&neg_flags)) {
+ DEBUG(1, ("ntlmssp_server_auth: failed to parse NTLMSSP:\n"));
+ dump_data(2, request.data, request.length);
return NT_STATUS_INVALID_PARAMETER;
}
@@ -357,13 +364,19 @@ NTSTATUS ntlmssp_server_update(NTLMSSP_STATE *ntlmssp_state,
uint32 ntlmssp_command;
*reply = data_blob(NULL, 0);
- if (!msrpc_parse(&request, "Cd",
- "NTLMSSP",
- &ntlmssp_command)) {
- return NT_STATUS_INVALID_PARAMETER;
+ if (request.length) {
+ if (!msrpc_parse(&request, "Cd",
+ "NTLMSSP",
+ &ntlmssp_command)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ } else {
+ /* 'datagram' mode - no neg packet */
+ ntlmssp_command = NTLMSSP_NEGOTIATE;
}
if (ntlmssp_command != ntlmssp_state->expected_state) {
+ DEBUG(1, ("got NTLMSSP command %u, expected %u\n", ntlmssp_command, ntlmssp_state->expected_state));
return NT_STATUS_INVALID_PARAMETER;
}
@@ -372,6 +385,7 @@ NTSTATUS ntlmssp_server_update(NTLMSSP_STATE *ntlmssp_state,
} else if (ntlmssp_command == NTLMSSP_AUTH) {
return ntlmssp_server_auth(ntlmssp_state, request, reply);
} else {
+ DEBUG(1, ("unknown NTLMSSP command %u\n", ntlmssp_command, ntlmssp_state->expected_state));
return NT_STATUS_INVALID_PARAMETER;
}
}
diff --git a/source3/nsswitch/wb_common.c b/source3/nsswitch/wb_common.c
index 89c751a4ef..ac1ccb217e 100644
--- a/source3/nsswitch/wb_common.c
+++ b/source3/nsswitch/wb_common.c
@@ -131,27 +131,16 @@ static int make_safe_fd(int fd)
/* Connect to winbindd socket */
-int winbind_open_pipe_sock(void)
+static int winbind_named_pipe_sock(const char *dir)
{
-#ifdef HAVE_UNIXSOCKET
struct sockaddr_un sunaddr;
- static pid_t our_pid;
struct stat st;
pstring path;
int fd;
- if (our_pid != getpid()) {
- close_sock();
- our_pid = getpid();
- }
-
- if (winbindd_fd != -1) {
- return winbindd_fd;
- }
-
/* Check permissions on unix socket directory */
- if (lstat(WINBINDD_SOCKET_DIR, &st) == -1) {
+ if (lstat(dir, &st) == -1) {
return -1;
}
@@ -162,13 +151,13 @@ int winbind_open_pipe_sock(void)
/* Connect to socket */
- strncpy(path, WINBINDD_SOCKET_DIR, sizeof(path) - 1);
+ strncpy(path, dir, sizeof(path) - 1);
path[sizeof(path) - 1] = '\0';
- strncat(path, "/", sizeof(path) - 1);
+ strncat(path, "/", sizeof(path) - 1 - strlen(path));
path[sizeof(path) - 1] = '\0';
- strncat(path, WINBINDD_SOCKET_NAME, sizeof(path) - 1);
+ strncat(path, WINBINDD_SOCKET_NAME, sizeof(path) - 1 - strlen(path));
path[sizeof(path) - 1] = '\0';
ZERO_STRUCT(sunaddr);
@@ -196,16 +185,60 @@ int winbind_open_pipe_sock(void)
return -1;
}
- if ((winbindd_fd = make_safe_fd( fd)) == -1) {
- return winbindd_fd;
+ if ((fd = make_safe_fd( fd)) == -1) {
+ return fd;
}
- if (connect(winbindd_fd, (struct sockaddr *)&sunaddr,
+ if (connect(fd, (struct sockaddr *)&sunaddr,
sizeof(sunaddr)) == -1) {
- close_sock();
+ close(fd);
return -1;
}
+ return fd;
+}
+
+/* Connect to winbindd socket */
+
+int winbind_open_pipe_sock(void)
+{
+#ifdef HAVE_UNIXSOCKET
+ static pid_t our_pid;
+ struct winbindd_request request;
+ struct winbindd_response response;
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ if (our_pid != getpid()) {
+ close_sock();
+ our_pid = getpid();
+ }
+
+ if (winbindd_fd != -1) {
+ return winbindd_fd;
+ }
+
+ if ((winbindd_fd = winbind_named_pipe_sock(WINBINDD_SOCKET_DIR)) == -1) {
+ return -1;
+ }
+
+ /* version-check the socket */
+
+ if ((winbindd_request(WINBINDD_INTERFACE_VERSION, &request, &response) != NSS_STATUS_SUCCESS) || (response.data.interface_version != WINBIND_INTERFACE_VERSION)) {
+ close_sock();
+ return -1;
+ }
+
+ /* try and get priv pipe */
+
+ if (winbindd_request(WINBINDD_PRIV_PIPE_DIR, &request, &response) == NSS_STATUS_SUCCESS) {
+ int fd;
+ if ((fd = winbind_named_pipe_sock(response.extra_data)) != -1) {
+ close(winbindd_fd);
+ winbindd_fd = fd;
+ }
+ }
+
return winbindd_fd;
#else
return -1;
diff --git a/source3/nsswitch/winbindd.c b/source3/nsswitch/winbindd.c
index 35fef6e361..3b91f2d6af 100644
--- a/source3/nsswitch/winbindd.c
+++ b/source3/nsswitch/winbindd.c
@@ -265,6 +265,7 @@ static struct dispatch_table dispatch_table[] = {
{ WINBINDD_INTERFACE_VERSION, winbindd_interface_version, "INTERFACE_VERSION" },
{ WINBINDD_DOMAIN_NAME, winbindd_domain_name, "DOMAIN_NAME" },
{ WINBINDD_NETBIOS_NAME, winbindd_netbios_name, "NETBIOS_NAME" },
+ { WINBINDD_PRIV_PIPE_DIR, winbindd_priv_pipe_dir, "WINBINDD_PRIV_PIPE_DIR" },
/* WINS functions */
@@ -311,7 +312,7 @@ static void process_request(struct winbindd_cli_state *state)
/* Process a new connection by adding it to the client connection list */
-static void new_connection(int listen_sock)
+static void new_connection(int listen_sock, BOOL privilaged)
{
struct sockaddr_un sunaddr;
struct winbindd_cli_state *state;
@@ -342,6 +343,8 @@ static void new_connection(int listen_sock)
state->last_access = time(NULL);
+ state->privilaged = privilaged;
+
/* Add to connection list */
winbindd_add_client(state);
@@ -553,7 +556,7 @@ static void process_loop(void)
while (1) {
struct winbindd_cli_state *state;
fd_set r_fds, w_fds;
- int maxfd, listen_sock, selret;
+ int maxfd, listen_sock, listen_priv_sock, selret;
struct timeval timeout;
/* Handle messages */
@@ -572,17 +575,19 @@ static void process_loop(void)
/* Initialise fd lists for select() */
listen_sock = open_winbindd_socket();
+ listen_priv_sock = open_winbindd_priv_socket();
- if (listen_sock == -1) {
+ if (listen_sock == -1 || listen_priv_sock == -1) {
perror("open_winbind_socket");
exit(1);
}
- maxfd = listen_sock;
+ maxfd = MAX(listen_sock, listen_priv_sock);
FD_ZERO(&r_fds);
FD_ZERO(&w_fds);
FD_SET(listen_sock, &r_fds);
+ FD_SET(listen_priv_sock, &r_fds);
timeout.tv_sec = WINBINDD_ESTABLISH_LOOP;
timeout.tv_usec = 0;
@@ -659,7 +664,22 @@ static void process_loop(void)
break;
}
}
- new_connection(listen_sock);
+ /* new, non-privilaged connection */
+ new_connection(listen_sock, False);
+ }
+
+ if (FD_ISSET(listen_priv_sock, &r_fds)) {
+ while (winbindd_num_clients() > WINBINDD_MAX_SIMULTANEOUS_CLIENTS - 1) {
+ DEBUG(5,("winbindd: Exceeding %d client connections, removing idle connection.\n",
+ WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
+ if (!remove_idle_client()) {
+ DEBUG(0,("winbindd: Exceeding %d client connections, no idle connection found\n",
+ WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
+ break;
+ }
+ }
+ /* new, privilaged connection */
+ new_connection(listen_priv_sock, True);
}
/* Process activity on client connections */
diff --git a/source3/nsswitch/winbindd.h b/source3/nsswitch/winbindd.h
index cc7cdc5297..f6b0e73543 100644
--- a/source3/nsswitch/winbindd.h
+++ b/source3/nsswitch/winbindd.h
@@ -42,6 +42,8 @@ struct winbindd_cli_state {
BOOL finished; /* Can delete from list */
BOOL write_extra_data; /* Write extra_data field */
time_t last_access; /* Time of last access (read or write) */
+ BOOL privilaged; /* Is the client 'privilaged' */
+
struct winbindd_request request; /* Request from client */
struct winbindd_response response; /* Respose to client */
struct getent_state *getpwent_state; /* State for getpwent() */
diff --git a/source3/nsswitch/winbindd_misc.c b/source3/nsswitch/winbindd_misc.c
index 0b283812b2..3b44d029c0 100644
--- a/source3/nsswitch/winbindd_misc.c
+++ b/source3/nsswitch/winbindd_misc.c
@@ -233,3 +233,20 @@ enum winbindd_result winbindd_netbios_name(struct winbindd_cli_state *state)
return WINBINDD_OK;
}
+
+/* What's my name again? */
+
+enum winbindd_result winbindd_priv_pipe_dir(struct winbindd_cli_state *state)
+{
+
+ DEBUG(3, ("[%5d]: request location of privilaged pipe\n", state->pid));
+
+ state->response.extra_data = strdup(get_winbind_priv_pipe_dir());
+ if (!state->response.extra_data)
+ return WINBINDD_ERROR;
+
+ /* must add one to length to copy the 0 for string termination */
+ state->response.length += strlen((char *)state->response.extra_data) + 1;
+
+ return WINBINDD_OK;
+}
diff --git a/source3/nsswitch/winbindd_nss.h b/source3/nsswitch/winbindd_nss.h
index 2c87a77100..88f4a11f87 100644
--- a/source3/nsswitch/winbindd_nss.h
+++ b/source3/nsswitch/winbindd_nss.h
@@ -30,7 +30,7 @@
#define WINBINDD_SOCKET_NAME "pipe" /* Name of PF_UNIX socket */
#define WINBINDD_SOCKET_DIR "/tmp/.winbindd" /* Name of PF_UNIX dir */
-
+#define WINBINDD_PRIV_SOCKET_SUBDIR "winbindd_privilaged" /* name of subdirectory of lp_lockdir() to hold the 'privilaged' pipe */
#define WINBINDD_DOMAIN_ENV "WINBINDD_DOMAIN" /* Environment variables */
#define WINBINDD_DONT_ENV "_NO_WINBINDD"
@@ -105,6 +105,9 @@ enum winbindd_cmd {
WINBINDD_NETBIOS_NAME, /* The netbios name of the server */
/* Placeholder for end of cmd list */
+ /* find the location of our privilaged pipe */
+ WINBINDD_PRIV_PIPE_DIR,
+
WINBINDD_NUM_CMDS
};
diff --git a/source3/nsswitch/winbindd_pam.c b/source3/nsswitch/winbindd_pam.c
index e24afbabd6..d408a8b3ae 100644
--- a/source3/nsswitch/winbindd_pam.c
+++ b/source3/nsswitch/winbindd_pam.c
@@ -174,6 +174,12 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
DATA_BLOB lm_resp, nt_resp;
+ if (!state->privilaged) {
+ DEBUG(2, ("winbindd_pam_auth_crap: non-privilaged access denied!\n"));
+ result = NT_STATUS_ACCESS_DENIED;
+ goto done;
+ }
+
/* Ensure null termination */
state->request.data.auth_crap.user[sizeof(state->request.data.auth_crap.user)-1]='\0';
@@ -272,19 +278,12 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
result = append_info3_as_ndr(mem_ctx, state, &info3);
}
-#if 0
- /* we don't currently do this stuff right */
- /* Doing an assert in a daemon is going to be a pretty bad
- idea. - tpot */
if (state->request.data.auth_crap.flags & WINBIND_PAM_NTKEY) {
- SMB_ASSERT(sizeof(state->response.data.auth.nt_session_key) == sizeof(info3.user_sess_key));
memcpy(state->response.data.auth.nt_session_key, info3.user_sess_key, sizeof(state->response.data.auth.nt_session_key) /* 16 */);
}
if (state->request.data.auth_crap.flags & WINBIND_PAM_LMKEY) {
- SMB_ASSERT(sizeof(state->response.data.auth.nt_session_key) <= sizeof(info3.user_sess_key));
memcpy(state->response.data.auth.first_8_lm_hash, info3.padding, sizeof(state->response.data.auth.nt_session_key) /* 16 */);
}
-#endif
}
done:
diff --git a/source3/nsswitch/winbindd_util.c b/source3/nsswitch/winbindd_util.c
index 99b94eac47..262d862b8a 100644
--- a/source3/nsswitch/winbindd_util.c
+++ b/source3/nsswitch/winbindd_util.c
@@ -444,9 +444,15 @@ void fill_domain_username(fstring name, const char *domain, const char *user)
* Winbindd socket accessor functions
*/
+char *get_winbind_priv_pipe_dir(void)
+{
+ return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
+}
+
/* Open the winbindd socket */
static int _winbindd_socket = -1;
+static int _winbindd_priv_socket = -1;
int open_winbindd_socket(void)
{
@@ -460,6 +466,18 @@ int open_winbindd_socket(void)
return _winbindd_socket;
}
+int open_winbindd_priv_socket(void)
+{
+ if (_winbindd_priv_socket == -1) {
+ _winbindd_priv_socket = create_pipe_sock(
+ get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
+ DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
+ _winbindd_priv_socket));
+ }
+
+ return _winbindd_priv_socket;
+}
+
/* Close the winbindd socket */
void close_winbindd_socket(void)
@@ -470,6 +488,12 @@ void close_winbindd_socket(void)
close(_winbindd_socket);
_winbindd_socket = -1;
}
+ if (_winbindd_priv_socket != -1) {
+ DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
+ _winbindd_priv_socket));
+ close(_winbindd_priv_socket);
+ _winbindd_priv_socket = -1;
+ }
}
/*
diff --git a/source3/rpc_client/cli_netlogon.c b/source3/rpc_client/cli_netlogon.c
index cbb09803af..f83571af03 100644
--- a/source3/rpc_client/cli_netlogon.c
+++ b/source3/rpc_client/cli_netlogon.c
@@ -597,7 +597,7 @@ NTSTATUS cli_netlogon_sam_logon(struct cli_state *cli, TALLOC_CTX *mem_ctx,
NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli, TALLOC_CTX *mem_ctx,
const char *username, const char *domain, const char *workstation,
- const uint8 chal[8],
+ const uint8 chal[8],
DATA_BLOB lm_response, DATA_BLOB nt_response,
NET_USER_INFO_3 *info3)
@@ -610,6 +610,8 @@ NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli, TALLOC_CTX *mem_c
NET_ID_INFO_CTR ctr;
int validation_level = 3;
char *workstation_name_slash;
+ uint8 netlogon_sess_key[16];
+ static uint8 zeros[16];
ZERO_STRUCT(q);
ZERO_STRUCT(r);
@@ -662,6 +664,15 @@ NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli, TALLOC_CTX *mem_c
goto done;
}
+ ZERO_STRUCT(netlogon_sess_key);
+ memcpy(netlogon_sess_key, cli->sess_key, 8);
+
+ if (memcmp(zeros, info3->user_sess_key, 16) != 0)
+ SamOEMhash(info3->user_sess_key, netlogon_sess_key, 16);
+
+ if (memcmp(zeros, info3->padding, 16) != 0)
+ SamOEMhash(info3->padding, netlogon_sess_key, 16);
+
/* Return results */
result = r.status;
diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c
index b76308c55f..ac456769f2 100644
--- a/source3/utils/ntlm_auth.c
+++ b/source3/utils/ntlm_auth.c
@@ -51,6 +51,8 @@ static unsigned char *lm_response;
static size_t lm_response_len;
static unsigned char *nt_response;
static size_t nt_response_len;
+static int request_lm_key;
+static int request_nt_key;
static char *password;
@@ -197,7 +199,7 @@ static NTSTATUS winbind_pw_check(struct ntlmssp_state *ntlmssp_state)
memcpy(request.data.auth_crap.lm_resp, ntlmssp_state->lm_resp.data,
MIN(ntlmssp_state->lm_resp.length, sizeof(request.data.auth_crap.lm_resp)));
- memcpy(request.data.auth_crap.nt_resp, ntlmssp_state->lm_resp.data,
+ memcpy(request.data.auth_crap.nt_resp, ntlmssp_state->nt_resp.data,
MIN(ntlmssp_state->nt_resp.length, sizeof(request.data.auth_crap.nt_resp)));
request.data.auth_crap.lm_resp_len = ntlmssp_state->lm_resp.length;
@@ -217,10 +219,28 @@ static NTSTATUS winbind_pw_check(struct ntlmssp_state *ntlmssp_state)
static void manage_squid_ntlmssp_request(enum squid_mode squid_mode,
char *buf, int length)
{
- static NTLMSSP_STATE *ntlmssp_state;
+ static NTLMSSP_STATE *ntlmssp_state = NULL;
DATA_BLOB request, reply;
NTSTATUS nt_status;
+ if (strlen(buf) < 2) {
+ DEBUG(1, ("NTLMSSP query [%s] invalid", buf));
+ x_fprintf(x_stdout, "BH\n");
+ return;
+ }
+
+ if (strlen(buf) > 3) {
+ request = base64_decode_data_blob(buf + 3);
+ } else if (strcmp(buf, "YR") == 0) {
+ request = data_blob(NULL, 0);
+ if (ntlmssp_state)
+ ntlmssp_server_end(&ntlmssp_state);
+ } else {
+ DEBUG(1, ("NTLMSSP query [%s] invalid", buf));
+ x_fprintf(x_stdout, "BH\n");
+ return;
+ }
+
if (!ntlmssp_state) {
ntlmssp_server_start(&ntlmssp_state);
ntlmssp_state->check_password = winbind_pw_check;
@@ -228,15 +248,8 @@ static void manage_squid_ntlmssp_request(enum squid_mode squid_mode,
ntlmssp_state->get_global_myname = get_winbind_netbios_name;
}
- if (strlen(buf) < 3) {
- x_fprintf(x_stdout, "BH\n");
- return;
- }
-
- request = base64_decode_data_blob(buf + 3);
-
- DEBUG(0, ("got NTLMSSP packet:\n"));
- dump_data(0, request.data, request.length);
+ DEBUG(10, ("got NTLMSSP packet:\n"));
+ dump_data(10, request.data, request.length);
nt_status = ntlmssp_server_update(ntlmssp_state, request, &reply);
@@ -245,10 +258,13 @@ static void manage_squid_ntlmssp_request(enum squid_mode squid_mode,
x_fprintf(x_stdout, "TT %s\n", reply_base64);
SAFE_FREE(reply_base64);
data_blob_free(&reply);
+ DEBUG(10, ("NTLMSSP challenge\n"));
} else if (!NT_STATUS_IS_OK(nt_status)) {
x_fprintf(x_stdout, "NA %s\n", nt_errstr(nt_status));
+ DEBUG(10, ("NTLMSSP %s\n", nt_errstr(nt_status)));
} else {
x_fprintf(x_stdout, "AF %s\\%s\n", ntlmssp_state->domain, ntlmssp_state->user);
+ DEBUG(10, ("NTLMSSP OK!\n"));
}
data_blob_free(&request);
@@ -287,10 +303,11 @@ static void manage_squid_request(enum squid_mode squid_mode)
int length;
char *c;
static BOOL err;
-
- if (x_fgets(buf, sizeof(buf)-1, x_stdin) == NULL) {
- DEBUG(1, ("fgets() failed! dying..... errno=%d (%s)\n", errno,
- strerror(errno)));
+
+ /* this is not a typo - x_fgets doesn't work too well under squid */
+ if (fgets(buf, sizeof(buf)-1, stdin) == NULL) {
+ DEBUG(1, ("fgets() failed! dying..... errno=%d (%s)\n", ferror(stdin),
+ strerror(ferror(stdin))));
exit(1); /* BIIG buffer */
}
@@ -341,12 +358,22 @@ static BOOL check_auth_crap(void)
{
struct winbindd_request request;
struct winbindd_response response;
+ char *lm_key;
+ char *nt_key;
+ static uint8 zeros[16];
+
NSS_STATUS result;
/* Send off request */
ZERO_STRUCT(request);
ZERO_STRUCT(response);
+ if (request_lm_key)
+ request.data.auth_crap.flags |= WINBIND_PAM_LMKEY;
+
+ if (request_nt_key)
+ request.data.auth_crap.flags |= WINBIND_PAM_NTKEY;
+
fstrcpy(request.data.auth_crap.user, username);
fstrcpy(request.data.auth_crap.domain, domain);
@@ -373,6 +400,27 @@ static BOOL check_auth_crap(void)
response.data.auth.nt_status_string,
response.data.auth.nt_status);
+ if (response.data.auth.nt_status == 0) {
+ if (request_lm_key
+ && (memcmp(zeros, response.data.auth.first_8_lm_hash,
+ sizeof(response.data.auth.first_8_lm_hash)) != 0)) {
+ hex_encode(response.data.auth.first_8_lm_hash,
+ sizeof(response.data.auth.first_8_lm_hash),
+ &lm_key);
+ d_printf("LM_KEY: %s\n", lm_key);
+ SAFE_FREE(lm_key);
+ }
+ if (request_nt_key
+ && (memcmp(zeros, response.data.auth.nt_session_key,
+ sizeof(response.data.auth.nt_session_key)) != 0)) {
+ hex_encode(response.data.auth.nt_session_key,
+ sizeof(response.data.auth.nt_session_key),
+ &nt_key);
+ d_printf("NT_KEY: %s\n", nt_key);
+ SAFE_FREE(nt_key);
+ }
+ }
+
return result == NSS_STATUS_SUCCESS;
}
@@ -386,68 +434,11 @@ enum {
OPT_RESPONSE,
OPT_LM,
OPT_NT,
- OPT_PASSWORD
+ OPT_PASSWORD,
+ OPT_LM_KEY,
+ OPT_NT_KEY
};
-/*************************************************************
- Routine to set hex password characters into an allocated array.
-**************************************************************/
-
-static void hex_encode(const unsigned char *buff_in, size_t len, char **out_hex_buffer)
-{
- int i;
- char *hex_buffer;
-
- *out_hex_buffer = smb_xmalloc((len*2)+1);
- hex_buffer = *out_hex_buffer;
-
- for (i = 0; i < len; i++)
- slprintf(&hex_buffer[i*2], 3, "%02X", buff_in[i]);
-}
-
-/*************************************************************
- Routine to get the 32 hex characters and turn them
- into a 16 byte array.
-**************************************************************/
-
-static BOOL hex_decode(const char *hex_buf_in, unsigned char **out_buffer, size_t *size)
-{
- int i;
- size_t hex_buf_in_len = strlen(hex_buf_in);
- unsigned char partial_byte_hex;
- unsigned char partial_byte;
- const char *hexchars = "0123456789ABCDEF";
- char *p;
- BOOL high = True;
-
- if (!hex_buf_in)
- return (False);
-
- *size = (hex_buf_in_len + 1) / 2;
-
- *out_buffer = smb_xmalloc(*size);
-
- for (i = 0; i < hex_buf_in_len; i++) {
- partial_byte_hex = toupper(hex_buf_in[i]);
-
- p = strchr(hexchars, partial_byte_hex);
-
- if (!p)
- return (False);
-
- partial_byte = PTR_DIFF(p, hexchars);
-
- if (high) {
- (*out_buffer)[i / 2] = (partial_byte << 4);
- } else {
- (*out_buffer)[i / 2] |= partial_byte;
- }
- high = !high;
- }
- return (True);
-}
-
-
int main(int argc, const char **argv)
{
int opt;
@@ -464,6 +455,8 @@ int main(int argc, const char **argv)
{ "lm-response", 0, POPT_ARG_STRING, &hex_lm_response, OPT_LM, "LM Response to the challenge (HEX encoded)"},
{ "nt-response", 0, POPT_ARG_STRING, &hex_nt_response, OPT_NT, "NT or NTLMv2 Response to the challenge (HEX encoded)"},
{ "password", 0, POPT_ARG_STRING, &password, OPT_PASSWORD, "User's plaintext password"},
+ { "request-lm-key", 0, POPT_ARG_NONE, &request_lm_key, OPT_LM_KEY, "Retreive LM session key"},
+ { "request-nt-key", 0, POPT_ARG_NONE, &request_nt_key, OPT_NT_KEY, "Retreive NT session key"},
{ NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_debug },
{ NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_configfile },
{ NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_version},
@@ -491,20 +484,27 @@ int main(int argc, const char **argv)
while((opt = poptGetNextOpt(pc)) != -1) {
switch (opt) {
case OPT_CHALLENGE:
- if (!hex_decode(hex_challenge, &challenge, &challenge_len)) {
- fprintf(stderr, "hex decode of %s failed!\n", hex_challenge);
+ challenge_len = strlen(hex_challenge);
+ challenge = smb_xmalloc((challenge_len+1)/2);
+ if ((challenge_len = strhex_to_str(challenge, challenge_len, hex_challenge)) != 8) {
+ fprintf(stderr, "hex decode of %s failed (only got %u bytes)!\n",
+ hex_challenge, challenge_len);
exit(1);
}
break;
case OPT_LM:
- if (!hex_decode(hex_lm_response, &lm_response, &lm_response_len)) {
- fprintf(stderr, "hex decode of %s failed!\n", lm_response);
+ lm_response_len = strlen(hex_lm_response);
+ lm_response = smb_xmalloc((lm_response_len+1)/2);
+ if ((lm_response_len = strhex_to_str(lm_response, lm_response_len, hex_lm_response)) != 24) {
+ fprintf(stderr, "hex decode of %s failed!\n", hex_lm_response);
exit(1);
}
break;
- case OPT_NT:
- if (!hex_decode(hex_lm_response, &lm_response, &lm_response_len)) {
- fprintf(stderr, "hex decode of %s failed!\n", lm_response);
+ case OPT_NT:
+ nt_response_len = strlen(hex_nt_response);
+ nt_response = smb_xmalloc((nt_response_len+1)/2);
+ if ((nt_response_len = strhex_to_str(nt_response, nt_response_len, hex_nt_response)) < 24) {
+ fprintf(stderr, "hex decode of %s failed!\n", hex_nt_response);
exit(1);
}
break;