diff options
| -rw-r--r-- | source3/auth/auth_domain.c | 7 | ||||
| -rw-r--r-- | source3/auth/auth_util.c | 3 | ||||
| -rw-r--r-- | source3/include/rpc_netlogon.h | 2 | ||||
| -rw-r--r-- | source3/lib/util_str.c | 24 | ||||
| -rw-r--r-- | source3/libsmb/ntlmssp.c | 50 | ||||
| -rw-r--r-- | source3/nsswitch/wb_common.c | 73 | ||||
| -rw-r--r-- | source3/nsswitch/winbindd.c | 30 | ||||
| -rw-r--r-- | source3/nsswitch/winbindd.h | 2 | ||||
| -rw-r--r-- | source3/nsswitch/winbindd_misc.c | 17 | ||||
| -rw-r--r-- | source3/nsswitch/winbindd_nss.h | 5 | ||||
| -rw-r--r-- | source3/nsswitch/winbindd_pam.c | 13 | ||||
| -rw-r--r-- | source3/nsswitch/winbindd_util.c | 24 | ||||
| -rw-r--r-- | source3/rpc_client/cli_netlogon.c | 13 | ||||
| -rw-r--r-- | source3/utils/ntlm_auth.c | 164 | 
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;  | 
