1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-27 03:21:53 +03:00

Winbind updates!

This updates the 'winbind' authentication module and winbind's 'PAM' (actually
netlogon) code to allow smbd to cache connections to the DC.

This is particulary relevent when we need mutex locks already - there is no
parallelism to be gained anyway.

The winbind code authenticates the user, and if successful, passes back the
'info3' struct describing the user.  smbd then interprets that in exactly the
same way as an 'ntdomain' logon.

Also, add parinoia to winbind about null termination.

Andrew Bartlett
(This used to be commit 167f122b67)
This commit is contained in:
Andrew Bartlett 2002-07-31 12:05:30 +00:00
parent 2307a6f504
commit 2d67a683b7
9 changed files with 201 additions and 51 deletions

View File

@ -32,6 +32,30 @@ NSS_STATUS winbindd_request(int req_type,
struct winbindd_request *request,
struct winbindd_response *response);
NTSTATUS get_info3_from_ndr(TALLOC_CTX *mem_ctx, struct winbindd_response *response, NET_USER_INFO_3 *info3)
{
uint8 *info3_ndr;
size_t len = response->length - sizeof(response);
prs_struct ps;
if (len > 0) {
info3_ndr = response->extra_data;
if (!prs_init(&ps, len, mem_ctx, UNMARSHALL)) {
return NT_STATUS_NO_MEMORY;
}
prs_append_data(&ps, info3_ndr, len);
ps.data_offset = 0;
if (!net_io_user_info3("", info3, &ps, 1, 3)) {
DEBUG(2, ("get_info3_from_ndr: could not parse info3 struct!\n"));
return NT_STATUS_UNSUCCESSFUL;
}
prs_mem_free(&ps);
return NT_STATUS_OK;
} else {
DEBUG(2, ("get_info3_from_ndr: No info3 struct found!\n"));
return NT_STATUS_UNSUCCESSFUL;
}
}
/* Authenticate a user with a challenge/response */
@ -44,11 +68,11 @@ static NTSTATUS check_winbind_security(const struct auth_context *auth_context,
struct winbindd_request request;
struct winbindd_response response;
NSS_STATUS result;
struct passwd *pw;
NTSTATUS nt_status;
NET_USER_INFO_3 info3;
if (!user_info) {
return NT_STATUS_UNSUCCESSFUL;
return NT_STATUS_INVALID_PARAMETER;
}
if (!auth_context) {
@ -62,11 +86,14 @@ static NTSTATUS check_winbind_security(const struct auth_context *auth_context,
ZERO_STRUCT(request);
ZERO_STRUCT(response);
snprintf(request.data.auth_crap.user, sizeof(request.data.auth_crap.user),
"%s\\%s", user_info->domain.str, user_info->smb_name.str);
request.data.auth_crap.flags = WINBIND_PAM_INFO3_NDR;
fstrcpy(request.data.auth_crap.user, user_info->smb_name.str);
fstrcpy(request.data.auth_crap.domain, user_info->domain.str);
push_utf8_fstring(request.data.auth_crap.user,
user_info->smb_name.str);
push_utf8_fstring(request.data.auth_crap.domain,
user_info->domain.str);
push_utf8_fstring(request.data.auth_crap.workstation,
user_info->wksta_name.str);
memcpy(request.data.auth_crap.chal, auth_context->challenge.data, sizeof(request.data.auth_crap.chal));
@ -76,27 +103,28 @@ static NTSTATUS check_winbind_security(const struct auth_context *auth_context,
sizeof(request.data.auth_crap.nt_resp));
memcpy(request.data.auth_crap.lm_resp, user_info->lm_resp.data,
sizeof(request.data.auth_crap.lm_resp_len));
memcpy(request.data.auth_crap.nt_resp, user_info->nt_resp.data,
request.data.auth_crap.lm_resp_len);
memcpy(request.data.auth_crap.nt_resp, user_info->nt_resp.data,
request.data.auth_crap.nt_resp_len);
result = winbindd_request(WINBINDD_PAM_AUTH_CRAP, &request, &response);
if (result == NSS_STATUS_SUCCESS) {
pw = Get_Pwnam(user_info->internal_username.str);
if (pw) {
if (make_server_info_pw(server_info, pw)) {
nt_status = NT_STATUS_OK;
} else {
nt_status = NT_STATUS_NO_MEMORY;
nt_status = NT_STATUS(response.data.auth.nt_status);
if (result == NSS_STATUS_SUCCESS && response.extra_data) {
if (NT_STATUS_IS_OK(nt_status)) {
if (NT_STATUS_IS_OK(nt_status = get_info3_from_ndr(mem_ctx, &response, &info3))) {
nt_status =
make_server_info_info3(mem_ctx,
user_info->internal_username.str,
user_info->smb_name.str,
user_info->domain.str,
server_info,
&info3);
}
} else {
nt_status = NT_STATUS_NO_SUCH_USER;
}
} else {
nt_status = NT_STATUS_LOGON_FAILURE;
} else if (NT_STATUS_IS_OK(nt_status)) {
nt_status = NT_STATUS_UNSUCCESSFUL;
}
return nt_status;

View File

@ -375,6 +375,9 @@ void winbind_process_packet(struct winbindd_cli_state *state)
{
/* Process request */
/* Ensure null termination of entire request */
state->request.domain[sizeof(state->request.domain)-1]='\0';
state->pid = state->request.pid;
process_request(state);

View File

@ -196,6 +196,9 @@ enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state)
gid_t gid;
int gr_mem_len;
/* Ensure null termination */
state->request.data.groupname[sizeof(state->request.data.groupname)-1]='\0';
DEBUG(3, ("[%5d]: getgrnam %s\n", state->pid,
state->request.data.groupname));
@ -783,6 +786,9 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state)
int i;
TALLOC_CTX *mem_ctx;
/* Ensure null termination */
state->request.data.username[sizeof(state->request.data.username)-1]='\0';
DEBUG(3, ("[%5d]: getgroups %s\n", state->pid,
state->request.data.username));

View File

@ -36,7 +36,7 @@
/* Update this when you change the interface. */
#define WINBIND_INTERFACE_VERSION 4
#define WINBIND_INTERFACE_VERSION 5
/* Socket commands */
@ -107,6 +107,12 @@ enum winbindd_cmd {
WINBINDD_NUM_CMDS
};
#define WINBIND_PAM_INFO3_NDR 0x0001
#define WINBIND_PAM_INFO3_TEXT 0x0002
#define WINBIND_PAM_NTKEY 0x0004
#define WINBIND_PAM_LMKEY 0x0008
#define WINBIND_PAM_CONTACT_TRUSTDOM 0x0010
/* Winbind request structure */
struct winbindd_request {
@ -132,6 +138,8 @@ struct winbindd_request {
uint16 lm_resp_len;
fstring nt_resp;
uint16 nt_resp_len;
fstring workstation;
uint32 flags;
} auth_crap;
struct {
fstring user;
@ -216,6 +224,8 @@ struct winbindd_response {
fstring nt_status_string;
fstring error_string;
int pam_error;
char nt_session_key[16];
char first_8_lm_hash[8];
} auth;
} data;

View File

@ -23,17 +23,41 @@
*/
#include "winbindd.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_WINBIND
static NTSTATUS append_info3_as_ndr(TALLOC_CTX *mem_ctx,
struct winbindd_cli_state *state,
NET_USER_INFO_3 *info3)
{
prs_struct ps;
uint32 size;
if (!prs_init(&ps, 256 /* Random, non-zero number */, mem_ctx, MARSHALL)) {
return NT_STATUS_NO_MEMORY;
}
if (!net_io_user_info3("", info3, &ps, 1, 3)) {
prs_mem_free(&ps);
return NT_STATUS_UNSUCCESSFUL;
}
size = prs_data_size(&ps);
state->response.extra_data = memdup(prs_data_p(&ps), size);
if (!state->response.extra_data) {
prs_mem_free(&ps);
return NT_STATUS_NO_MEMORY;
}
state->response.length += size;
prs_mem_free(&ps);
return NT_STATUS_OK;
}
/* Return a password structure from a username. */
enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
{
NTSTATUS result;
fstring name_domain, name_user;
int passlen;
unsigned char trust_passwd[16];
time_t last_change_time;
uint32 smb_uid_low;
@ -46,6 +70,12 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
extern pstring global_myname;
/* Ensure null termination */
state->request.data.auth.user[sizeof(state->request.data.auth.user)-1]='\0';
/* Ensure null termination */
state->request.data.auth.pass[sizeof(state->request.data.auth.pass)-1]='\0';
DEBUG(3, ("[%5d]: pam auth %s\n", state->pid,
state->request.data.auth.user));
@ -64,8 +94,6 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
goto done;
}
passlen = strlen(state->request.data.auth.pass);
{
unsigned char local_lm_response[24];
unsigned char local_nt_response[24];
@ -140,34 +168,67 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
NET_USER_INFO_3 info3;
struct cli_state *cli = NULL;
TALLOC_CTX *mem_ctx = NULL;
const char *domain = NULL;
char *user = NULL;
char *domain = NULL;
char *contact_domain;
char *workstation;
DATA_BLOB lm_resp, nt_resp;
extern pstring global_myname;
DEBUG(3, ("[%5d]: pam auth crap domain: %s user: %s\n", state->pid,
state->request.data.auth_crap.domain, state->request.data.auth_crap.user));
/* Ensure null termination */
state->request.data.auth_crap.user[sizeof(state->request.data.auth_crap.user)-1]='\0';
if (!(mem_ctx = talloc_init_named("winbind pam auth crap for %s", state->request.data.auth.user))) {
/* Ensure null termination */
state->request.data.auth_crap.domain[sizeof(state->request.data.auth_crap.domain)-1]='\0';
if (!(mem_ctx = talloc_init_named("winbind pam auth crap for (utf8) %s", state->request.data.auth.user))) {
DEBUG(0, ("winbindd_pam_auth_crap: could not talloc_init()!\n"));
result = NT_STATUS_NO_MEMORY;
goto done;
}
if (pull_utf8_talloc(mem_ctx, &user, state->request.data.auth_crap.user) < 0) {
DEBUG(0, ("winbindd_pam_auth_crap: pull_utf8_talloc failed!\n"));
}
if (*state->request.data.auth_crap.domain) {
domain = talloc_strdup(mem_ctx, state->request.data.auth_crap.domain);
if (pull_utf8_talloc(mem_ctx, &domain, state->request.data.auth_crap.domain) < 0) {
DEBUG(0, ("winbindd_pam_auth_crap: pull_utf8_talloc failed!\n"));
}
} else if (lp_winbind_use_default_domain()) {
domain = talloc_strdup(mem_ctx, lp_workgroup());
domain = lp_workgroup();
} else {
DEBUG(5,("no domain specified with username (%s) - failing auth\n", state->request.data.auth.user));
DEBUG(5,("no domain specified with username (%s) - failing auth\n",
user));
result = NT_STATUS_INVALID_PARAMETER;
goto done;
}
if (!domain) {
DEBUG(0,("winbindd_pam_auth_crap: talloc_strdup failed!\n"));
result = NT_STATUS_NO_MEMORY;
DEBUG(3, ("[%5d]: pam auth crap domain: %s user: %s\n", state->pid,
domain, user));
if (lp_allow_trusted_domains() && (state->request.data.auth_crap.flags & WINBIND_PAM_CONTACT_TRUSTDOM)) {
contact_domain = domain;
} else {
contact_domain = lp_workgroup();
}
if (*state->request.data.auth_crap.workstation) {
if (pull_utf8_talloc(mem_ctx, &workstation, state->request.data.auth_crap.workstation) < 0) {
DEBUG(0, ("winbindd_pam_auth_crap: pull_utf8_talloc failed!\n"));
}
} else {
workstation = global_myname;
}
if (state->request.data.auth_crap.lm_resp_len > sizeof(state->request.data.auth_crap.lm_resp)
|| state->request.data.auth_crap.nt_resp_len > sizeof(state->request.data.auth_crap.nt_resp)) {
DEBUG(0, ("winbindd_pam_auth_crap: invalid password length %u/%u\n",
state->request.data.auth_crap.lm_resp_len,
state->request.data.auth_crap.nt_resp_len));
result = NT_STATUS_INVALID_PARAMETER;
goto done;
}
@ -175,13 +236,15 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
nt_resp = data_blob_talloc(mem_ctx, state->request.data.auth_crap.nt_resp, state->request.data.auth_crap.nt_resp_len);
/*
* Get the machine account password for our primary domain
* Get the machine account password for the domain to contact.
* This is either our own domain for a workstation, or possibly
* any domain for a PDC with trusted domains.
*/
if (!secrets_fetch_trust_account_password(
lp_workgroup(), trust_passwd, &last_change_time)) {
if (!secrets_fetch_trust_account_password (
contact_domain, trust_passwd, &last_change_time)) {
DEBUG(0, ("winbindd_pam_auth: could not fetch trust account "
"password for domain %s\n", lp_workgroup()));
"password for domain %s\n", contact_domain));
result = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
goto done;
}
@ -189,7 +252,7 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
ZERO_STRUCT(info3);
/* Don't shut this down - it belongs to the connection cache code */
result = cm_get_netlogon_cli(lp_workgroup(), trust_passwd, &cli);
result = cm_get_netlogon_cli(contact_domain, trust_passwd, &cli);
if (!NT_STATUS_IS_OK(result)) {
DEBUG(3, ("could not open handle to NETLOGON pipe (error: %s)\n", nt_errstr(result)));
@ -197,27 +260,43 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
}
result = cli_netlogon_sam_network_logon(cli, mem_ctx,
state->request.data.auth_crap.user, domain,
global_myname, state->request.data.auth_crap.chal,
user, domain,
workstation, state->request.data.auth_crap.chal,
lm_resp, nt_resp,
&info3);
if (NT_STATUS_IS_OK(result)) {
uni_group_cache_store_netlogon(mem_ctx, &info3);
if (state->request.data.auth_crap.flags & WINBIND_PAM_INFO3_NDR) {
result = append_info3_as_ndr(mem_ctx, state, &info3);
}
#if 0
/* we don't currently do this stuff right */
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:
state->response.data.auth.nt_status = NT_STATUS_V(result);
fstrcpy(state->response.data.auth.nt_status_string, nt_errstr(result));
fstrcpy(state->response.data.auth.error_string, nt_errstr(result));
push_utf8_fstring(state->response.data.auth.nt_status_string, nt_errstr(result));
push_utf8_fstring(state->response.data.auth.error_string, nt_errstr(result));
state->response.data.auth.pam_error = nt_status_to_pam(result);
DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("NTLM CRAP authenticaion for user [%s]\\[%s] returned %s (PAM: %d)\n",
state->request.data.auth_crap.domain,
state->request.data.auth_crap.user,
state->response.data.auth.nt_status_string,
state->response.data.auth.pam_error));
DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
("NTLM CRAP authenticaion for user [%s]\\[%s] returned %s (PAM: %d)\n",
domain,
user,
state->response.data.auth.nt_status_string,
state->response.data.auth.pam_error));
if (mem_ctx)
talloc_destroy(mem_ctx);

View File

@ -36,6 +36,9 @@ enum winbindd_result winbindd_lookupsid(struct winbindd_cli_state *state)
fstring name;
fstring dom_name;
/* Ensure null termination */
state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
DEBUG(3, ("[%5d]: lookupsid %s\n", state->pid,
state->request.data.sid));
@ -79,6 +82,12 @@ enum winbindd_result winbindd_lookupname(struct winbindd_cli_state *state)
DOM_SID sid;
struct winbindd_domain *domain;
/* Ensure null termination */
state->request.data.sid[sizeof(state->request.data.name.dom_name)-1]='\0';
/* Ensure null termination */
state->request.data.sid[sizeof(state->request.data.name.name)-1]='\0';
DEBUG(3, ("[%5d]: lookupname %s%s%s\n", state->pid,
state->request.data.name.dom_name,
lp_winbind_separator(),
@ -112,6 +121,9 @@ enum winbindd_result winbindd_sid_to_uid(struct winbindd_cli_state *state)
{
DOM_SID sid;
/* Ensure null termination */
state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
DEBUG(3, ("[%5d]: sid to uid %s\n", state->pid,
state->request.data.sid));
@ -139,6 +151,9 @@ enum winbindd_result winbindd_sid_to_gid(struct winbindd_cli_state *state)
{
DOM_SID sid;
/* Ensure null termination */
state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
DEBUG(3, ("[%5d]: sid to gid %s\n", state->pid,
state->request.data.sid));

View File

@ -103,6 +103,9 @@ enum winbindd_result winbindd_getpwnam(struct winbindd_cli_state *state)
struct winbindd_domain *domain;
TALLOC_CTX *mem_ctx;
/* Ensure null termination */
state->request.data.username[sizeof(state->request.data.username)-1]='\0';
DEBUG(3, ("[%5d]: getpwnam %s\n", state->pid,
state->request.data.username));

View File

@ -122,6 +122,9 @@ enum winbindd_result winbindd_wins_byip(struct winbindd_cli_state *state)
int i, count, maxlen, size;
struct node_status *status;
/* Ensure null termination */
state->request.data.winsreq[sizeof(state->request.data.winsreq)-1]='\0';
DEBUG(3, ("[%5d]: wins_byip %s\n", state->pid,
state->request.data.winsreq));
@ -166,6 +169,9 @@ enum winbindd_result winbindd_wins_byname(struct winbindd_cli_state *state)
fstring response;
char * addr;
/* Ensure null termination */
state->request.data.winsreq[sizeof(state->request.data.winsreq)-1]='\0';
DEBUG(3, ("[%5d]: wins_byname %s\n", state->pid,
state->request.data.winsreq));

View File

@ -1335,7 +1335,7 @@ void init_net_user_info3(TALLOC_CTX *ctx, NET_USER_INFO_3 *usr,
********************************************************************/
BOOL net_io_user_info3(const char *desc, NET_USER_INFO_3 *usr, prs_struct *ps,
int depth, uint16 validation_level)
int depth, uint16 validation_level)
{
int i;