diff options
author | Andrew Bartlett <abartlet@samba.org> | 2001-11-24 12:12:38 +0000 |
---|---|---|
committer | Andrew Bartlett <abartlet@samba.org> | 2001-11-24 12:12:38 +0000 |
commit | d0a2faf78d316fec200497f5f7997df4c477a1e1 (patch) | |
tree | a1d9f9f837b2c88e6154fb5ee6214cbcebc97ad4 | |
parent | af1a0238aa106a43006902e8ef593d7853913b0e (diff) | |
download | samba-d0a2faf78d316fec200497f5f7997df4c477a1e1.tar.gz samba-d0a2faf78d316fec200497f5f7997df4c477a1e1.tar.bz2 samba-d0a2faf78d316fec200497f5f7997df4c477a1e1.zip |
This is another rather major change to the samba authenticaion
subystem.
The particular aim is to modularized the interface - so that we
can have arbitrary password back-ends.
This code adds one such back-end, a 'winbind' module to authenticate
against the winbind_auth_crap functionality. While fully-functional
this code is mainly useful as a demonstration, because we don't get
back the info3 as we would for direct ntdomain authentication.
This commit introduced the new 'auth methods' parameter, in the
spirit of the 'auth order' discussed on the lists. It is renamed
because not all the methods may be consulted, even if previous
methods fail - they may not have a suitable challenge for example.
Also, we have a 'local' authentication method, for old-style
'unix if plaintext, sam if encrypted' authentication and a
'guest' module to handle guest logins in a single place.
While this current design is not ideal, I feel that it does
provide a better infrastructure than the current design, and can
be built upon.
The following parameters have changed:
- use rhosts =
This has been replaced by the 'rhosts' authentication method,
and can be specified like 'auth methods = guest rhosts'
- hosts equiv =
This needs both this parameter and an 'auth methods' entry
to be effective. (auth methods = guest hostsequiv ....)
- plaintext to smbpasswd =
This is replaced by specifying 'sam' rather than 'local'
in the auth methods.
The security = parameter is unchanged, and now provides defaults
for the 'auth methods' parameter.
The available auth methods are:
guest
rhosts
hostsequiv
sam (passdb direct hash access)
unix (PAM, crypt() etc)
local (the combination of the above, based on encryption)
smbserver (old security=server)
ntdomain (old security=domain)
winbind (use winbind to cache DC connections)
Assistance in testing, or the production of new and interesting
authentication modules is always appreciated.
Andrew Bartlett
(This used to be commit 8d31eae52a9757739711dbb82035a4dfe6b40c99)
33 files changed, 1842 insertions, 743 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in index d69941bed3..6b3b337a12 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -197,7 +197,8 @@ NOTIFY_OBJ = smbd/notify.o smbd/notify_hash.o smbd/notify_kernel.o PLAINTEXT_AUTH_OBJ = passdb/pampass.o passdb/pass_check.o AUTH_OBJ = smbd/auth.o smbd/auth_smbpasswd.o smbd/auth_server.o smbd/auth_domain.o \ - smbd/auth_rhosts.o smbd/auth_unix.o smbd/auth_util.o $(PLAINTEXT_AUTH_OBJ) \ + smbd/auth_rhosts.o smbd/auth_unix.o smbd/auth_util.o smbd/auth_winbind.o \ + smbd/auth_info.o smbd/auth_builtin.o $(PLAINTEXT_AUTH_OBJ) \ libsmb/domain_client_validate.o diff --git a/source3/auth/auth.c b/source3/auth/auth.c index 95c97182b8..c62e2ed5a0 100644 --- a/source3/auth/auth.c +++ b/source3/auth/auth.c @@ -58,27 +58,50 @@ static BOOL check_domain_match(char *user, char *domain) ****************************************************************************/ NTSTATUS check_password(const auth_usersupplied_info *user_info, + const auth_authsupplied_info *auth_info, auth_serversupplied_info **server_info) { NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE; - BOOL done_pam = False; const char *pdb_username; + auth_methods *auth_method; + + if (!user_info || !auth_info || !server_info) { + return NT_STATUS_LOGON_FAILURE; + } DEBUG(3, ("check_password: Checking password for unmapped user [%s]\\[%s]@[%s] with the new password interface\n", user_info->client_domain.str, user_info->smb_name.str, user_info->wksta_name.str)); DEBUG(3, ("check_password: mapped user is: [%s]\\[%s]@[%s]\n", user_info->domain.str, user_info->internal_username.str, user_info->wksta_name.str)); - - if (!NT_STATUS_IS_OK(nt_status)) { - nt_status = check_guest_security(user_info, server_info); + DEBUG(10, ("auth_info challange created by %s\n", auth_info->challange_set_by)); + DEBUG(10, ("challange is: \n")); + dump_data(5, (auth_info)->challange.data, (auth_info)->challange.length); + +#ifdef DEBUG_PASSWORD + DEBUG(100, ("user_info has passwords of length %d and %d\n", + user_info->lm_resp.length, user_info->nt_resp.length)); + DEBUG(100, ("lm:\n")); + dump_data(100, user_info->lm_resp.data, user_info->lm_resp.length); + DEBUG(100, ("nt:\n")); + dump_data(100, user_info->nt_resp.data, user_info->nt_resp.length); +#endif + + for (auth_method = auth_info->auth_method_list;auth_method; auth_method = auth_method->next) + { + nt_status = auth_method->auth(auth_method->private_data, user_info, auth_info, server_info); if (NT_STATUS_IS_OK(nt_status)) { - DEBUG(5, ("check_password: checking guest-account for user [%s] suceeded\n", user_info->smb_name.str)); + DEBUG(3, ("check_password: %s authentication for user [%s] suceeded\n", + auth_method->name, user_info->smb_name.str)); } else { - DEBUG(10, ("check_password: checking gusst-account for user [%s] FAILED with error %s\n", user_info->smb_name.str, get_nt_error_msg(nt_status))); - - } + DEBUG(5, ("check_password: %s authentication for user [%s] FAILED with error %s\n", + auth_method->name, user_info->smb_name.str, get_nt_error_msg(nt_status))); + } + + if (NT_STATUS_IS_OK(nt_status)) { + break; + } } /* This needs to be sorted: If it doesn't match, what should we do? */ @@ -86,83 +109,47 @@ NTSTATUS check_password(const auth_usersupplied_info *user_info, return NT_STATUS_LOGON_FAILURE; } - if (!NT_STATUS_IS_OK(nt_status)) { - nt_status = check_rhosts_security(user_info, server_info); - if (NT_STATUS_IS_OK(nt_status)) { - DEBUG(3, ("check_password: Password (rhosts) for user [%s] suceeded\n", user_info->smb_name.str)); - } else { - DEBUG(10, ("check_password: Password (rhosts) for user [%s] FAILED with error %s\n", user_info->smb_name.str, get_nt_error_msg(nt_status))); - - } - } - - if ((lp_security() == SEC_DOMAIN) && !NT_STATUS_IS_OK(nt_status)) { - nt_status = check_domain_security(user_info, server_info); - if (NT_STATUS_IS_OK(nt_status)) { - DEBUG(7, ("check_password: Password (domain) for user [%s] suceeded\n", user_info->smb_name.str)); - } else { - DEBUG(5, ("check_password: Password (domain) for user [%s] FAILED with error %s\n", user_info->smb_name.str, get_nt_error_msg(nt_status))); - - } - } - - if ((lp_security() == SEC_SERVER) && !NT_STATUS_IS_OK(nt_status)) { - nt_status = check_server_security(user_info, server_info); - if (NT_STATUS_IS_OK(nt_status)) { - DEBUG(7, ("check_password: Password (server) for user [%s] suceeded\n", user_info->smb_name.str)); - } else { - DEBUG(5, ("check_password: Password (server) for user [%s] FAILED with error %s\n", user_info->smb_name.str, get_nt_error_msg(nt_status))); - - } - } + /* This is one of the few places the *relies* (rather than just sets defaults + on the value of lp_security(). This needs to change. A new paramater + perhaps? */ if (lp_security() >= SEC_SERVER) { smb_user_control(user_info, *server_info, nt_status); } - if (!NT_STATUS_IS_OK(nt_status)) { - if (user_info->encrypted || lp_plaintext_to_smbpasswd()) { - nt_status = check_smbpasswd_security(user_info, server_info); - } else { - nt_status = check_unix_security(user_info, server_info); - done_pam = True; - } - - if (NT_STATUS_IS_OK(nt_status)) { - DEBUG(7, ("check_password: Password (unix/smbpasswd) for user [%s] suceeded\n", user_info->smb_name.str)); - } else { - DEBUG(5, ("check_password: Password (unix/smbpasswd) for user [%s] FAILED with error %s\n", user_info->smb_name.str, get_nt_error_msg(nt_status))); - - } - } - if (NT_STATUS_IS_OK(nt_status)) { pdb_username = pdb_get_username((*server_info)->sam_account); - if (!done_pam && !(*server_info)->guest) { + if (!(*server_info)->guest) { /* We might not be root if we are an RPC call */ become_root(); nt_status = smb_pam_accountcheck(pdb_username); unbecome_root(); if (NT_STATUS_IS_OK(nt_status)) { - DEBUG(5, ("check_password: PAM Account for user [%s] suceeded\n", pdb_username)); + DEBUG(5, ("check_password: PAM Account for user [%s] suceeded\n", + pdb_username)); } else { - DEBUG(3, ("check_password: PAM Account for user [%s] FAILED with error %s\n", pdb_username, get_nt_error_msg(nt_status))); + DEBUG(3, ("check_password: PAM Account for user [%s] FAILED with error %s\n", + pdb_username, get_nt_error_msg(nt_status))); } } + + if (NT_STATUS_IS_OK(nt_status)) { + DEBUG((*server_info)->guest ? 5 : 2, + ("check_password: %sauthenticaion for user [%s] -> [%s] -> [%s] suceeded\n", + (*server_info)->guest ? "guest " : "", + user_info->smb_name.str, + user_info->internal_username.str, + pdb_username)); + } } - if (NT_STATUS_IS_OK(nt_status)) { - DEBUG(3, ("check_password: %sauthenticaion for user [%s] -> [%s] -> [%s] suceeded\n", - (*server_info)->guest ? "guest " : "", - user_info->smb_name.str, - user_info->internal_username.str, - pdb_username)); - } else { - DEBUG(3, ("check_password: Authenticaion for user [%s] -> [%s] FAILED with error %s\n", user_info->smb_name.str, user_info->internal_username.str, get_nt_error_msg(nt_status))); + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(2, ("check_password: Authenticaion for user [%s] -> [%s] FAILED with error %s\n", + user_info->smb_name.str, user_info->internal_username.str, + get_nt_error_msg(nt_status))); ZERO_STRUCTP(server_info); - } - + } return nt_status; } @@ -210,16 +197,35 @@ static NTSTATUS pass_check_smb(char *smb_name, { NTSTATUS nt_status; auth_usersupplied_info *user_info = NULL; + extern auth_authsupplied_info *negprot_global_auth_info; auth_serversupplied_info *server_info = NULL; + if (encrypted) { + make_user_info_for_reply_enc(&user_info, smb_name, + domain, + lm_pwd, + nt_pwd, + plaintext_password); + nt_status = check_password(user_info, negprot_global_auth_info, &server_info); + } else { + auth_authsupplied_info *plaintext_auth_info = NULL; + DATA_BLOB chal; + if (!make_auth_info_subsystem(&plaintext_auth_info)) { + return NT_STATUS_NO_MEMORY; + } - make_user_info_for_reply(&user_info, smb_name, - domain, - lm_pwd, - nt_pwd, - plaintext_password, - encrypted); - - nt_status = check_password(user_info, &server_info); + chal = auth_get_challange(plaintext_auth_info); + + if (!make_user_info_for_reply(&user_info, + smb_name, domain, chal.data, + plaintext_password)) { + return NT_STATUS_NO_MEMORY; + } + + nt_status = check_password(user_info, plaintext_auth_info, &server_info); + + data_blob_free(&chal); + free_auth_info(&plaintext_auth_info); + } free_user_info(&user_info); free_server_info(&server_info); return nt_status; @@ -235,22 +241,23 @@ BOOL password_ok(char *smb_name, DATA_BLOB password_blob) DATA_BLOB null_password = data_blob(NULL, 0); extern BOOL global_encrypted_passwords_negotiated; - - if (global_encrypted_passwords_negotiated) { + BOOL encrypted = (global_encrypted_passwords_negotiated && password_blob.length == 24); + + if (encrypted) { /* * The password could be either NTLM or plain LM. Try NTLM first, * but fall-through as required. * NTLMv2 makes no sense here. */ - if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), null_password, password_blob, null_password, global_encrypted_passwords_negotiated))) { + if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), null_password, password_blob, null_password, encrypted))) { return True; } - if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), password_blob, null_password, null_password, global_encrypted_passwords_negotiated))) { + if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), password_blob, null_password, null_password, encrypted))) { return True; } } else { - if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), null_password, null_password, password_blob, global_encrypted_passwords_negotiated))) { + if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), null_password, null_password, password_blob, encrypted))) { return True; } } diff --git a/source3/auth/auth_builtin.c b/source3/auth/auth_builtin.c new file mode 100644 index 0000000000..6ea6d0bbe0 --- /dev/null +++ b/source3/auth/auth_builtin.c @@ -0,0 +1,87 @@ +/* + Unix SMB/Netbios implementation. + Version 3.0. + Generic authenticaion types + Copyright (C) Andrew Bartlett 2001 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +/**************************************************************************** + Check for a guest logon (username = "") and if so create the required + structure. +****************************************************************************/ + +static NTSTATUS check_guest_security(void *my_private_data, + const auth_usersupplied_info *user_info, + const auth_authsupplied_info *auth_info, + auth_serversupplied_info **server_info) +{ + NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE; + + if (!(user_info->internal_username.str + && *user_info->internal_username.str)) { + if (make_server_info_guest(server_info)) { + nt_status = NT_STATUS_OK; + } else { + nt_status = NT_STATUS_NO_SUCH_USER; + } + } + + return nt_status; +} + +BOOL auth_init_guest(auth_methods **auth_method) +{ + if (!make_auth_methods(auth_method)) { + return False; + } + + (*auth_method)->auth = check_guest_security; + return True; +} + +/**************************************************************************** + Check against either sam or unix, depending on encryption. +****************************************************************************/ + +static NTSTATUS check_local_security(void *my_private_data, + const auth_usersupplied_info *user_info, + const auth_authsupplied_info *auth_info, + auth_serversupplied_info **server_info) +{ + NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE; + + if (user_info->encrypted) { + nt_status = check_sam_security(my_private_data, user_info, auth_info, server_info); + } else { + nt_status = check_unix_security(my_private_data, user_info, auth_info, server_info); + } + + return nt_status; +} + +BOOL auth_init_local(auth_methods **auth_method) +{ + if (!make_auth_methods(auth_method)) { + return False; + } + + (*auth_method)->auth = check_local_security; + return True; +} + diff --git a/source3/auth/auth_domain.c b/source3/auth/auth_domain.c index 4ada7d4a56..ef0e5b2f10 100644 --- a/source3/auth/auth_domain.c +++ b/source3/auth/auth_domain.c @@ -28,8 +28,10 @@ BOOL global_machine_password_needs_changing = False; Check for a valid username and password in security=domain mode. ****************************************************************************/ -NTSTATUS check_domain_security(const auth_usersupplied_info *user_info, - auth_serversupplied_info **server_info) +static NTSTATUS check_ntdomain_security(void *my_private_data, + const auth_usersupplied_info *user_info, + const auth_authsupplied_info *auth_info, + auth_serversupplied_info **server_info) { NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE; char *p, *pserver; @@ -66,8 +68,18 @@ NTSTATUS check_domain_security(const auth_usersupplied_info *user_info, if (! *pserver) pserver = "*"; p = pserver; - nt_status = domain_client_validate(user_info, server_info, + nt_status = domain_client_validate(user_info, (uchar *)auth_info->challange.data,server_info, p, trust_passwd, last_change_time); return nt_status; } + +BOOL auth_init_ntdomain(auth_methods **auth_method) +{ + if (!make_auth_methods(auth_method)) { + return False; + } + + (*auth_method)->auth = check_ntdomain_security; + return True; +} diff --git a/source3/auth/auth_info.c b/source3/auth/auth_info.c new file mode 100644 index 0000000000..12b843d781 --- /dev/null +++ b/source3/auth/auth_info.c @@ -0,0 +1,279 @@ +/* + Unix SMB/Netbios implementation. + Version 3.0. + Authentication utility functions + Copyright (C) Andrew Bartlett 2001 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +const struct auth_init_function builtin_auth_init_functions[] = { + { "guest", auth_init_guest }, + { "rhosts", auth_init_rhosts }, + { "hostsequiv", auth_init_hostsequiv }, + { "sam", auth_init_sam }, + { "unix", auth_init_unix }, + { "local", auth_init_local }, + { "smbserver", auth_init_smbserver }, + { "ntdomain", auth_init_ntdomain }, + { "winbind", auth_init_winbind }, + { NULL, NULL} +}; + +/*************************************************************************** + Make a auth_info struct +***************************************************************************/ + +static BOOL make_auth_info(auth_authsupplied_info **auth_info) +{ + *auth_info = malloc(sizeof(**auth_info)); + if (!*auth_info) { + DEBUG(0,("make_auth_info: malloc failed!\n")); + return False; + } + ZERO_STRUCTP(*auth_info); + + return True; +} + +/*************************************************************************** + Make a auth_info struct with a specified list. +***************************************************************************/ + +BOOL make_auth_info_list(auth_authsupplied_info **auth_info, auth_methods *list) +{ + if (!make_auth_info(auth_info)) { + return False; + } + + (*auth_info)->auth_method_list = list; + + return True; +} + +/*************************************************************************** + Make a auth_info struct for the auth subsystem +***************************************************************************/ + +static BOOL make_auth_info_text_list(auth_authsupplied_info **auth_info, char **text_list) +{ + auth_methods *list = NULL; + auth_methods *t = NULL; + auth_methods *tmp; + int i; + + for (;*text_list; text_list++) + { + DEBUG(5,("Attempting to find an auth method to match %s\n", *text_list)); + for (i = 0; builtin_auth_init_functions[i].name; i++) + { + if (strequal(builtin_auth_init_functions[i].name, *text_list)) + { + DEBUG(5,("Found auth method %s (at pos %d)\n", *text_list, i)); + /* Malloc entry, fill it, link it */ + t = (auth_methods *)malloc(sizeof(*t)); + if (!t) { + DEBUG(0,("make_pw_chat: malloc failed!\n")); + return False; + } + + ZERO_STRUCTP(t); + + if (builtin_auth_init_functions[i].init(&t)) { + DEBUG(5,("auth method %s has a valid init\n", *text_list)); + t->name = builtin_auth_init_functions[i].name; + DLIST_ADD_END(list, t, tmp); + } else { + DEBUG(5,("auth method %s DOES NOT have a valid init\n", *text_list)); + } + break; + } + } + } + + make_auth_info_list(auth_info, list); + + return True; +} + +/*************************************************************************** + Make a auth_info struct for the auth subsystem +***************************************************************************/ + +BOOL make_auth_info_subsystem(auth_authsupplied_info **auth_info) +{ + char **auth_method_list = NULL; + + if (!make_auth_info(auth_info)) { + return False; + } + + if (lp_auth_methods() && !lp_list_copy(&auth_method_list, lp_auth_methods())) { + return False; + } + + if (auth_method_list == NULL) { + switch (lp_security()) + { + case SEC_DOMAIN: + DEBUG(5,("Making default auth method list for security=domain\n")); + auth_method_list = lp_list_make("guest ntdomain local"); + break; + case SEC_SERVER: + DEBUG(5,("Making default auth method list for security=server\n")); + auth_method_list = lp_list_make("guest smbserver local"); + break; + case SEC_USER: + DEBUG(5,("Making default auth method list for security=user\n")); + auth_method_list = lp_list_make("guest local"); + break; + case SEC_SHARE: + DEBUG(5,("Making default auth method list for security=share\n")); + auth_method_list = lp_list_make("guest local"); + break; + } + } else { + DEBUG(5,("Using specified auth order\n")); + } + + if (!make_auth_info_text_list(auth_info, auth_method_list)) { + lp_list_free(&auth_method_list); + return False; + } + + lp_list_free(&auth_method_list); + return True; +} + +/*************************************************************************** + Make a auth_info struct with a random challange +***************************************************************************/ + +BOOL make_auth_info_random(auth_authsupplied_info **auth_info) +{ + uchar chal[8]; + if (!make_auth_info_subsystem(auth_info)) { + return False; + } + + generate_random_buffer(chal, sizeof(chal), False); + (*auth_info)->challange = data_blob(chal, sizeof(chal)); + + (*auth_info)->challange_set_by = "random"; + + return True; +} + +/*************************************************************************** + Make a auth_info struct with a fixed challange +***************************************************************************/ + +BOOL make_auth_info_fixed(auth_authsupplied_info **auth_info, uchar chal[8]) +{ + if (!make_auth_info_subsystem(auth_info)) { + return False; + } + + (*auth_info)->challange = data_blob(chal, 8); + return True; +} + +/*************************************************************************** + Clear out a auth_info struct that has been allocated +***************************************************************************/ + +void free_auth_info(auth_authsupplied_info **auth_info) +{ + auth_methods *list; + if (*auth_info != NULL) { + list = (*auth_info)->auth_method_list; + while (list) { + auth_methods *old_head = list; + if (list->free_private_data) { + list->free_private_data(&(list->private_data)); + } + DLIST_REMOVE(list, list); + SAFE_FREE(old_head); + } + + data_blob_free(&(*auth_info)->challange); + ZERO_STRUCT(**auth_info); + } + SAFE_FREE(*auth_info); +} + +/**************************************************************************** + Try to get a challange out of the various authenticaion modules. + It is up to the caller to free it. +****************************************************************************/ + +DATA_BLOB auth_get_challange(auth_authsupplied_info *auth_info) +{ + DATA_BLOB challange = data_blob(NULL, 0); + char *challange_set_by = NULL; + auth_methods *auth_method; + + if (auth_info->challange.length) { + DEBUG(5, ("auth_get_challange: returning previous challange (normal)\n")); + return data_blob(auth_info->challange.data, auth_info->challange.length); + } + + for (auth_method = auth_info->auth_method_list; auth_method; auth_method = auth_method->next) + { + if (auth_method->get_chal) { + DEBUG(5, ("auth_get_challange: getting challange from module %s\n", auth_method->name)); + if (challange_set_by) { + DEBUG(1, ("auth_get_challange: CONFIGURATION ERROR: authenticaion method %s has already specified a challange. Challange by %s ignored.\n", + challange_set_by, auth_method->name)); + } else { + challange = auth_method->get_chal(&auth_method->private_data, auth_info); + if (challange.length) { + DEBUG(5, ("auth_get_challange: sucessfully got challange from module %s\n", auth_method->name)); + auth_info->challange = challange; + challange_set_by = auth_method->name; + auth_info->challange_set_method = auth_method; + } else { + DEBUG(3, ("auth_get_challange: getting challange from authenticaion method %s FAILED.\n", + auth_method->name)); + } + } + } else { + DEBUG(5, ("auth_get_challange: module %s did not want to specify a challange\n", auth_method->name)); + } + } + + if (!challange_set_by) { + uchar chal[8]; + + generate_random_buffer(chal, sizeof(chal), False); + auth_info->challange = data_blob(chal, sizeof(chal)); + + challange_set_by = "random"; + } + + DEBUG(5, ("auth_info challange created by %s\n", challange_set_by)); + DEBUG(5, ("challange is: \n")); + dump_data(5, auth_info->challange.data, (auth_info)->challange.length); + + SMB_ASSERT(auth_info->challange.length == 8); + + auth_info->challange_set_by=challange_set_by; + + return data_blob(auth_info->challange.data, auth_info->challange.length); +} + + diff --git a/source3/auth/auth_rhosts.c b/source3/auth/auth_rhosts.c index 9c07e48a9b..2605f0770a 100644 --- a/source3/auth/auth_rhosts.c +++ b/source3/auth/auth_rhosts.c @@ -135,7 +135,6 @@ check for a possible hosts equiv or rhosts entry for the user static BOOL check_hosts_equiv(struct passwd *pass) { char *fname = NULL; - pstring rhostsfile; if (!pass) return(False); @@ -148,39 +147,82 @@ static BOOL check_hosts_equiv(struct passwd *pass) return(True); } - if (lp_use_rhosts()) - { - char *home = pass->pw_dir; - if (home) { - slprintf(rhostsfile, sizeof(rhostsfile)-1, "%s/.rhosts", home); - if (check_user_equiv(pass->pw_name,client_name(),rhostsfile)) - return(True); - } - } - return(False); } + /**************************************************************************** Check for a valid .rhosts/hosts.equiv entry for this user ****************************************************************************/ -NTSTATUS check_rhosts_security(const auth_usersupplied_info *user_info, - auth_serversupplied_info **server_info) +static NTSTATUS check_hostsequiv_security(void *my_private_data, + const auth_usersupplied_info *user_info, + const auth_authsupplied_info *auth_info, + auth_serversupplied_info **server_info) { NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE; struct passwd *pass = Get_Pwnam(user_info->internal_username.str); if (pass) { - become_root(); if (check_hosts_equiv(pass)) { nt_status = NT_STATUS_OK; make_server_info_pw(server_info, pass); } - unbecome_root(); } else { nt_status = NT_STATUS_NO_SUCH_USER; } return nt_status; } + + +/**************************************************************************** + Check for a valid .rhosts/hosts.equiv entry for this user +****************************************************************************/ + +static NTSTATUS check_rhosts_security(void *my_private_data, + const auth_usersupplied_info *user_info, + const auth_authsupplied_info *auth_info, + auth_serversupplied_info **server_info) +{ + NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE; + struct passwd *pass = Get_Pwnam(user_info->internal_username.str); + pstring rhostsfile; + + if (pass) { + char *home = pass->pw_dir; + if (home) { + slprintf(rhostsfile, sizeof(rhostsfile)-1, "%s/.rhosts", home); + become_root(); + if (check_user_equiv(pass->pw_name,client_name(),rhostsfile)) { + nt_status = NT_STATUS_OK; + make_server_info_pw(server_info, pass); + } + unbecome_root(); + } + } else { + nt_status = NT_STATUS_NO_SUCH_USER; + } + + return nt_status; +} + +BOOL auth_init_hostsequiv(auth_methods **auth_method) +{ + + if (!make_auth_methods(auth_method)) { + return False; + } + (*auth_method)->auth = check_hostsequiv_security; + return True; +} + +BOOL auth_init_rhosts(auth_methods **auth_method) +{ + + if (!make_auth_methods(auth_method)) { + return False; + } + (*auth_method)->auth = check_rhosts_security; + return True; +} diff --git a/source3/auth/auth_sam.c b/source3/auth/auth_sam.c index 70632fb5df..24a4d4e4e4 100644 --- a/source3/auth/auth_sam.c +++ b/source3/auth/auth_sam.c @@ -96,7 +96,7 @@ static BOOL smb_pwd_check_ntlmv2(const DATA_BLOB ntv2_response, if (ntv2_response.length < 16) { /* We MUST have more than 16 bytes, or the stuff below will go crazy... */ - DEBUG(0, ("smb_pwd_check_ntlmv1: incorrect password length (%d)\n", + DEBUG(0, ("smb_pwd_check_ntlmv2: incorrect password length (%d)\n", ntv2_response.length)); return False; } @@ -132,15 +132,16 @@ static BOOL smb_pwd_check_ntlmv2(const DATA_BLOB ntv2_response, Do a specific test for an smb password being correct, given a smb_password and the lanman and NT responses. ****************************************************************************/ -NTSTATUS sam_password_ok(SAM_ACCOUNT *sampass, const auth_usersupplied_info *user_info, uint8 user_sess_key[16]) +static NTSTATUS sam_password_ok(SAM_ACCOUNT *sampass, + const auth_usersupplied_info *user_info, + const auth_authsupplied_info *auth_info, + uint8 user_sess_key[16]) { + uint16 acct_ctrl; const uint8 *nt_pw, *lm_pw; - uint16 acct_ctrl = pdb_get_acct_ctrl(sampass); uint32 ntlmssp_flags; - if (!user_info || !sampass) - return NT_STATUS_LOGON_FAILURE; - + acct_ctrl = pdb_get_acct_ctrl(sampass); if (acct_ctrl & ACB_PWNOTREQ) { if (lp_null_passwords()) @@ -173,8 +174,8 @@ NTSTATUS sam_password_ok(SAM_ACCOUNT *sampass, const auth_usersupplied_info *use */ DEBUG(4,("smb_password_ok: Checking NTLMv2 password\n")); if (smb_pwd_check_ntlmv2( user_info->nt_resp, - nt_pw, - user_info->sec_blob, user_info->smb_name.str, + nt_pw, auth_info->challange, + user_info->smb_name.str, user_info->client_domain.str, user_sess_key)) { @@ -190,7 +191,7 @@ NTSTATUS sam_password_ok(SAM_ACCOUNT *sampass, const auth_usersupplied_info *use */ DEBUG(4,("smb_password_ok: Checking NT MD4 password\n")); if (smb_pwd_check_ntlmv1(user_info->nt_resp, - nt_pw, user_info->sec_blob, + nt_pw, auth_info->challange, user_sess_key)) { return NT_STATUS_OK; @@ -223,7 +224,7 @@ NTSTATUS sam_password_ok(SAM_ACCOUNT *sampass, const auth_usersupplied_info *use DEBUG(4,("smb_password_ok: Checking LM password\n")); if (smb_pwd_check_ntlmv1(user_info->lm_resp, - lm_pw, user_info->sec_blob, + lm_pw, auth_info->challange, user_sess_key)) { return NT_STATUS_OK; @@ -265,6 +266,24 @@ static NTSTATUS sam_account_ok(SAM_ACCOUNT *sampass, const auth_usersupplied_inf return NT_STATUS_ACCOUNT_EXPIRED; } + if (!(pdb_get_acct_ctrl(sampass) & ACB_PWNOEXP)) { + time_t must_change_time = pdb_get_pass_must_change_time(sampass); + time_t last_set_time = pdb_get_pass_last_set_time(sampass); + + /* check for immediate expiry "must change at next logon" */ + if (must_change_time == 0 && last_set_time != 0) { + DEBUG(1,("Account for user '%s' password must change!.\n", pdb_get_username(sampass))); + return NT_STATUS_PASSWORD_MUST_CHANGE; + } + + /* check for expired password */ + if (must_change_time < time(NULL) && must_change_time != 0) { + DEBUG(1,("Account for user '%s' password expired!.\n", pdb_get_username(sampass))); + DEBUG(1,("Password expired at '%s' (%ld) unix time.\n", http_timestring(must_change_time), (long)must_change_time)); + return NT_STATUS_PASSWORD_EXPIRED; + } + } + /* Test workstation. Workstation list is comma separated. */ workstation_list = strdup(pdb_get_workstations(sampass)); @@ -293,24 +312,6 @@ static NTSTATUS sam_account_ok(SAM_ACCOUNT *sampass, const auth_usersupplied_inf SAFE_FREE(workstation_list); } - if (!(pdb_get_acct_ctrl(sampass) & ACB_PWNOEXP)) { - time_t must_change_time = pdb_get_pass_must_change_time(sampass); - time_t last_set_time = pdb_get_pass_last_set_time(sampass); - - /* check for immediate expiry "must change at next logon" */ - if (must_change_time == 0 && last_set_time != 0) { - DEBUG(1,("Account for user '%s' password must change!.\n", pdb_get_username(sampass))); - return NT_STATUS_PASSWORD_MUST_CHANGE; - } - - /* check for expired password */ - if (must_change_time < time(NULL) && must_change_time != 0) { - DEBUG(1,("Account for user '%s' password expired!.\n", pdb_get_username(sampass))); - DEBUG(1,("Password expired at '%s' (%ld) unix time.\n", http_timestring(must_change_time), (long)must_change_time)); - return NT_STATUS_PASSWORD_EXPIRED; - } - } - if (acct_ctrl & ACB_DOMTRUST) { DEBUG(2,("session_trust_account: Domain trust account %s denied by server\n", pdb_get_username(sampass))); return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT; @@ -336,7 +337,10 @@ SMB hash supplied in the user_info structure return an NT_STATUS constant. ****************************************************************************/ -NTSTATUS check_smbpasswd_security(const auth_usersupplied_info *user_info, auth_serversupplied_info **server_info) +NTSTATUS check_sam_security(void *my_private_dat, + const auth_usersupplied_info *user_info, + const auth_authsupplied_info *auth_info, + auth_serversupplied_info **server_info) { SAM_ACCOUNT *sampass=NULL; BOOL ret; @@ -344,7 +348,7 @@ NTSTATUS check_smbpasswd_security(const auth_usersupplied_info *user_info, auth_ uint8 user_sess_key[16]; const uint8* lm_hash; - if (!user_info) { + if (!user_info || !auth_info) { return NT_STATUS_LOGON_FAILURE; } @@ -365,7 +369,7 @@ NTSTATUS check_smbpasswd_security(const auth_usersupplied_info *user_info, auth_ return NT_STATUS_NO_SUCH_USER; } - nt_status = sam_password_ok(sampass, user_info, user_sess_key); + nt_status = sam_password_ok(sampass, user_info, auth_info, user_sess_key); if (!NT_STATUS_IS_OK(nt_status)) { pdb_free_sam(&sampass); @@ -394,6 +398,15 @@ NTSTATUS check_smbpasswd_security(const auth_usersupplied_info *user_info, auth_ return nt_status; } +BOOL auth_init_sam(auth_methods **auth_method) +{ + if (!make_auth_methods(auth_method)) { + return False; + } + + (*auth_method)->auth = check_sam_security; + return True; +} diff --git a/source3/auth/auth_server.c b/source3/auth/auth_server.c index ddbc284d50..067b5b2997 100644 --- a/source3/auth/auth_server.c +++ b/source3/auth/auth_server.c @@ -25,30 +25,18 @@ extern pstring global_myname; /**************************************************************************** - Return the client state structure. -****************************************************************************/ - -struct cli_state *server_client(void) -{ - static struct cli_state pw_cli; - return &pw_cli; -} - -/**************************************************************************** Support for server level security. ****************************************************************************/ -struct cli_state *server_cryptkey(void) +static struct cli_state *server_cryptkey(void) { - struct cli_state *cli; + struct cli_state *cli = NULL; fstring desthost; struct in_addr dest_ip; char *p, *pserver; BOOL connected_ok = False; - cli = server_client(); - - if (!cli_initialise(cli)) + if (!(cli = cli_initialise(cli))) return NULL; /* security = server just can't function with spnego */ @@ -88,7 +76,11 @@ struct cli_state *server_cryptkey(void) if (!attempt_netbios_session_request(cli, global_myname, desthost, &dest_ip)) return NULL; - + + if (strequal(desthost,myhostname())) { + exit_server("Password server loop!"); + } + DEBUG(3,("got session\n")); if (!cli_negprot(cli)) { @@ -109,13 +101,82 @@ struct cli_state *server_cryptkey(void) return cli; } +/**************************************************************************** + Clean up our allocated cli. +****************************************************************************/ + +static void free_server_private_data(void **private_data_pointer) +{ + struct cli_state **cli = (struct cli_state **)private_data_pointer; + if (*cli && (*cli)->initialised) { + cli_shutdown(*cli); + + SAFE_FREE(*cli); + } +} + +/**************************************************************************** + Send a 'keepalive' packet down the cli pipe. +****************************************************************************/ + +static void send_server_keepalive(void **private_data_pointer) +{ + struct cli_state **cli = (struct cli_state **)private_data_pointer; + + /* also send a keepalive to the password server if its still + connected */ + if (cli && *cli && (*cli)->initialised) { + if (!send_keepalive((*cli)->fd)) { + DEBUG( 2, ( "password server keepalive failed.\n")); + cli_shutdown(*cli); + SAFE_FREE(*cli); + } + } +} + +/**************************************************************************** + Get the challange out of a password server. +****************************************************************************/ + +static DATA_BLOB auth_get_challange_server(void **my_private_data, const struct authsupplied_info *auth_info) +{ + struct cli_state *cli = server_cryptkey(); + + if (cli) { + DEBUG(3,("using password server validation\n")); + if ((cli->sec_mode & 2) == 0) { + /* We can't work with unencrypted password servers + unless 'encrypt passwords = no' */ + DEBUG(5,("make_auth_info_server: Server is unencrypted, no challange available..\n")); + + *my_private_data = (void *)cli; + return data_blob(NULL, 0); + + } else if (cli->secblob.length < 8) { + /* We can't do much if we don't get a full challange */ + DEBUG(2,("make_auth_info_server: Didn't receive a full challange from server\n")); + cli_shutdown(cli); + return data_blob(NULL, 0); + } + + *my_private_data = (void *)cli; + + return data_blob(cli->secblob.data,8); + } else { + return data_blob(NULL, 0); + } +} + /**************************************************************************** Check for a valid username and password in security=server mode. - Validate a password with the password server. ****************************************************************************/ -NTSTATUS check_server_security(const auth_usersupplied_info *user_info, auth_serversupplied_info **server_info) +static NTSTATUS check_smbserver_security(void *my_private_data, + const auth_usersupplied_info *user_info, + const auth_authsupplied_info *auth_info, + auth_serversupplied_info **server_info) { struct cli_state *cli; static unsigned char badpass[24]; @@ -123,13 +184,32 @@ NTSTATUS check_server_security(const auth_usersupplied_info *user_info, auth_ser static BOOL tested_password_server = False; static BOOL bad_password_server = False; NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE; + BOOL locally_made_cli = False; - cli = server_client(); + cli = my_private_data; + + if (cli) { + } else { + cli = server_cryptkey(); + locally_made_cli = True; + } - if (!cli->initialised) { + if (!cli || !cli->initialised) { DEBUG(1,("password server %s is not connected\n", cli->desthost)); - return(NT_STATUS_LOGON_FAILURE); + return NT_STATUS_LOGON_FAILURE; } + + if ((cli->sec_mode & 2) == 0) { + if (user_info->encrypted) { + DEBUG(1,("password server %s is plaintext, but we are encrypted. This just can't work :-(\n", cli->desthost)); + return NT_STATUS_LOGON_FAILURE; + } + } else { + if (memcmp(cli->secblob.data, auth_info->challange.data, 8) != 0) { + DEBUG(1,("the challange that the password server (%s) supplied us is not the one we gave our client. This just can't work :-(\n", cli->desthost)); + return NT_STATUS_LOGON_FAILURE; + } + } if(badpass[0] == 0) memset(badpass, 0x1f, sizeof(badpass)); @@ -206,17 +286,32 @@ use this machine as the password server.\n")); * not guest enabled, we can try with the real password. */ - if (!cli_session_setup(cli, user_info->smb_name.str, - (char *)user_info->lm_resp.data, - user_info->lm_resp.length, - (char *)user_info->nt_resp.data, - user_info->nt_resp.length, - user_info->domain.str)) { - DEBUG(1,("password server %s rejected the password\n", cli->desthost)); - /* Make this cli_nt_error() when the conversion is in */ - nt_status = cli_nt_error(cli); + if (!user_info->encrypted) { + /* Plaintext available */ + if (!cli_session_setup(cli, user_info->smb_name.str, + (char *)user_info->plaintext_password.data, + user_info->plaintext_password.length, + NULL, 0, + user_info->domain.str)) { + DEBUG(1,("password server %s rejected the password\n", cli->desthost)); + /* Make this cli_nt_error() when the conversion is in */ + nt_status = cli_nt_error(cli); + } else { + nt_status = NT_STATUS_OK; + } } else { - nt_status = NT_STATUS_OK; + if (!cli_session_setup(cli, user_info->smb_name.str, + (char *)user_info->lm_resp.data, + user_info->lm_resp.length, + (char *)user_info->nt_resp.data, + user_info->nt_resp.length, + user_info->domain.str)) { + DEBUG(1,("password server %s rejected the password\n", cli->desthost)); + /* Make this cli_nt_error() when the conversion is in */ + nt_status = cli_nt_error(cli); + } else { + nt_status = NT_STATUS_OK; + } } /* if logged in as guest then reject */ @@ -238,5 +333,22 @@ use this machine as the password server.\n")); } } + if (locally_made_cli) { + cli_shutdown(cli); + SAFE_FREE(cli); + } + return(nt_status); } + +BOOL auth_init_smbserver(auth_methods **auth_method) +{ + if (!make_auth_methods(auth_method)) { + return False; + } + (*auth_method)->auth = check_smbserver_security; + (*auth_method)->get_chal = auth_get_challange_server; + (*auth_method)->send_keepalive = send_server_keepalive; + (*auth_method)->free_private_data = free_server_private_data; + return True; +} diff --git a/source3/auth/auth_unix.c b/source3/auth/auth_unix.c index 8c4a520350..d134ce6909 100644 --- a/source3/auth/auth_unix.c +++ b/source3/auth/auth_unix.c @@ -82,7 +82,10 @@ check if a username/password is OK assuming the password in PLAIN TEXT ****************************************************************************/ -NTSTATUS check_unix_security(const auth_usersupplied_info *user_info, auth_serversupplied_info **server_info) +NTSTATUS check_unix_security(void *my_private_data, + const auth_usersupplied_info *user_info, + const auth_authsupplied_info *auth_info, + auth_serversupplied_info **server_info) { NTSTATUS nt_status; struct passwd *pass = NULL; @@ -104,9 +107,19 @@ NTSTATUS check_unix_security(const auth_usersupplied_info *user_info, auth_serve if (pass) { make_server_info_pw(server_info, pass); } else { + /* we need to do somthing more useful here */ nt_status = NT_STATUS_NO_SUCH_USER; } } return nt_status; } + +BOOL auth_init_unix(auth_methods **auth_method) +{ + if (!make_auth_methods(auth_method)) { + return False; + } + (*auth_method)->auth = check_unix_security; + return True; +} diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c index 25e0830fc7..d1b2cc92e5 100644 --- a/source3/auth/auth_util.c +++ b/source3/auth/auth_util.c @@ -23,49 +23,9 @@ #include "includes.h" -/* Data to do lanman1/2 password challenge. */ -static unsigned char saved_challenge[8]; -static BOOL challenge_sent=False; extern fstring remote_machine; extern pstring global_myname; -/******************************************************************* - Get the next challenge value - no repeats. -********************************************************************/ - -void generate_next_challenge(char *challenge) -{ - unsigned char buf[8]; - - generate_random_buffer(buf,8,False); - memcpy(saved_challenge, buf, 8); - memcpy(challenge,buf,8); - challenge_sent = True; -} - -/******************************************************************* - Set the last challenge sent, usually from a password server. -********************************************************************/ - -BOOL set_challenge(unsigned char *challenge) -{ - memcpy(saved_challenge,challenge,8); - challenge_sent = True; - return(True); -} - -/******************************************************************* - Get the last challenge sent. -********************************************************************/ - -BOOL last_challenge(unsigned char *challenge) -{ - if (!challenge_sent) - return(False); - memcpy(challenge,saved_challenge,8); - return(True); -} - /**************************************************************************** Create a UNIX user on demand. ****************************************************************************/ @@ -166,7 +126,6 @@ static BOOL make_user_info(auth_usersupplied_info **user_info, const char *client_domain, const char *domain, const char *wksta_name, - DATA_BLOB sec_blob, DATA_BLOB lm_pwd, DATA_BLOB nt_pwd, DATA_BLOB plaintext, uint32 ntlmssp_flags, BOOL encrypted) @@ -226,7 +185,6 @@ static BOOL make_user_info(auth_usersupplied_info **user_info, DEBUG(5,("makeing blobs for %s's user_info struct\n", internal_username)); - (*user_info)->sec_blob = data_blob(sec_blob.data, sec_blob.length); (*user_info)->lm_resp = data_blob(lm_pwd.data, lm_pwd.length); (*user_info)->nt_resp = data_blob(nt_pwd.data, nt_pwd.length); (*user_info)->plaintext_password = data_blob(plaintext.data, plaintext.length); @@ -246,7 +204,7 @@ static BOOL make_user_info(auth_usersupplied_info **user_info, BOOL make_user_info_map(auth_usersupplied_info **user_info, const char *smb_name, const char *client_domain, - const char *wksta_name, DATA_BLOB sec_blob, + const char *wksta_name, DATA_BLOB lm_pwd, DATA_BLOB nt_pwd, DATA_BLOB plaintext, uint32 ntlmssp_flags, BOOL encrypted) @@ -265,7 +223,7 @@ BOOL make_user_info_map(auth_usersupplied_info **user_info, return make_user_info(user_info, smb_name, internal_username, client_domain, domain, - wksta_name, sec_blob, + wksta_name, lm_pwd, nt_pwd, plaintext, ntlmssp_flags, encrypted); @@ -280,12 +238,11 @@ BOOL make_user_info_map(auth_usersupplied_info **user_info, BOOL make_user_info_netlogon_network(auth_usersupplied_info **user_info, char *smb_name, char *client_domain, - char *wksta_name, uchar chal[8], + char *wksta_name, uchar *lm_network_pwd, int lm_pwd_len, uchar *nt_network_pwd, int nt_pwd_len) { BOOL ret; - DATA_BLOB sec_blob = data_blob(chal, sizeof(chal)); DATA_BLOB lm_blob = data_blob(lm_network_pwd, lm_pwd_len); DATA_BLOB nt_blob = data_blob(nt_network_pwd, nt_pwd_len); DATA_BLOB plaintext_blob = data_blob(NULL, 0); @@ -301,8 +258,8 @@ BOOL make_user_info_netlogon_network(auth_usersupplied_info **user_info, ret = make_user_info_map(user_info, smb_name, client_domain, - wksta_name, sec_blob, - nt_blob, lm_blob, + wksta_name, + lm_blob, nt_blob, plaintext_blob, ntlmssp_flags, True); @@ -320,6 +277,7 @@ BOOL make_user_info_netlogon_interactive(auth_usersupplied_info **user_info, char *smb_name, char *client_domain, char *wksta_name, + char chal[8], uchar lm_interactive_pwd[16], uchar nt_interactive_pwd[16], uchar *dc_sess_key) @@ -329,11 +287,8 @@ BOOL make_user_info_netlogon_interactive(auth_usersupplied_info **user_info, unsigned char local_lm_response[24]; unsigned char local_nt_response[24]; unsigned char key[16]; - uint8 chal[8]; uint32 ntlmssp_flags = 0; - generate_random_buffer(chal, 8, False); - ZERO_STRUCT(key); memcpy(key, dc_sess_key, 8); @@ -362,7 +317,6 @@ BOOL make_user_info_netlogon_interactive(auth_usersupplied_info **user_info, dump_data(100, nt_pwd, sizeof(nt_pwd)); #endif - generate_random_buffer(chal, 8, False); SMBOWFencrypt((const unsigned char *)lm_pwd, chal, local_lm_response); SMBOWFencrypt((const unsigned char *)nt_pwd, chal, local_nt_response); @@ -373,7 +327,6 @@ BOOL make_user_info_netlogon_interactive(auth_usersupplied_info **user_info, { BOOL ret; - DATA_BLOB sec_blob = data_blob(chal, sizeof(chal)); DATA_BLOB local_lm_blob = data_blob(local_lm_response, sizeof(local_lm_response)); DATA_BLOB local_nt_blob = data_blob(local_nt_response, sizeof(local_nt_response)); DATA_BLOB plaintext_blob = data_blob(NULL, 0); @@ -385,7 +338,7 @@ BOOL make_user_info_netlogon_interactive(auth_usersupplied_info **user_info, ret = make_user_info_map(user_info, smb_name, client_domain, - wksta_name, sec_blob, + wksta_name, local_lm_blob, local_nt_blob, plaintext_blob, @@ -402,13 +355,14 @@ BOOL make_user_info_netlogon_interactive(auth_usersupplied_info **user_info, ****************************************************************************/ BOOL make_user_info_winbind(auth_usersupplied_info **user_info, - char *username, - char *domain, - char *password) + const char *username, + const char *domain, + const char *password, + char chal[8] /* Give winbind back the challange we used */ + ) { unsigned char local_lm_response[24]; unsigned char local_nt_response[24]; - char chal[8]; DATA_BLOB local_lm_blob; DATA_BLOB local_nt_blob; DATA_BLOB plaintext_blob; @@ -453,16 +407,11 @@ BOOL make_user_info_winbind(auth_usersupplied_info **user_info, { BOOL ret; - DATA_BLOB sec_blob = data_blob(chal, sizeof(chal)); - - if (!sec_blob.data) { - return False; - } ret = make_user_info(user_info, username, username, domain, domain, - global_myname, sec_blob, + global_myname, local_nt_blob, local_lm_blob, plaintext_blob, @@ -483,12 +432,10 @@ BOOL make_user_info_winbind(auth_usersupplied_info **user_info, BOOL make_user_info_winbind_crap(auth_usersupplied_info **user_info, char *smb_name, char *client_domain, - uchar chal[8], uchar *lm_network_pwd, int lm_pwd_len, uchar *nt_network_pwd, int nt_pwd_len) { BOOL ret; - DATA_BLOB sec_blob = data_blob(chal, 8); DATA_BLOB lm_blob = data_blob(lm_network_pwd, lm_pwd_len); DATA_BLOB nt_blob = data_blob(nt_network_pwd, nt_pwd_len); DATA_BLOB plaintext_blob = data_blob(NULL, 0); @@ -502,7 +449,7 @@ BOOL make_user_info_winbind_crap(auth_usersupplied_info **user_info, ret = make_user_info(user_info, smb_name, smb_name, client_domain, client_domain, - global_myname, sec_blob, + global_myname, nt_blob, lm_blob, plaintext_blob, ntlmssp_flags, True); @@ -517,59 +464,30 @@ BOOL make_user_info_winbind_crap(auth_usersupplied_info **user_info, ****************************************************************************/ BOOL make_user_info_for_reply(auth_usersupplied_info **user_info, - char *smb_name, - char *client_domain, - DATA_BLOB lm_resp, DATA_BLOB nt_resp, - DATA_BLOB plaintext_password, - BOOL encrypted) + char *smb_name, + char *client_domain, + char chal[8], + DATA_BLOB plaintext_password) { - uchar chal[8]; DATA_BLOB local_lm_blob; DATA_BLOB local_nt_blob; - DATA_BLOB sec_blob; BOOL ret = False; uint32 ntlmssp_flags = 0; - if (encrypted) { - DATA_BLOB no_plaintext_blob = data_blob(NULL, 0); - if (!last_challenge(chal)) { - DEBUG(0,("Encrypted login but no challange set!\n")); - return False; - } - sec_blob = data_blob(chal, 8); - - if (lm_resp.length == 24) { - ntlmssp_flags |= NTLMSSP_NEGOTIATE_OEM; - } - if (nt_resp.length == 0) { - } else if (nt_resp.length == 24) { - ntlmssp_flags |= NTLMSSP_NEGOTIATE_NTLM; - } else { - ntlmssp_flags |= NTLMSSP_NEGOTIATE_NTLM2; - } - - return make_user_info_map(user_info, smb_name, - client_domain, - remote_machine, sec_blob, - lm_resp, - nt_resp, - no_plaintext_blob, - ntlmssp_flags, encrypted); - } - - generate_random_buffer(chal, 8, False); - - sec_blob = data_blob(chal, 8); - /* * Not encrypted - do so. */ - DEBUG(5,("pass_check_smb: User passwords not in encrypted format.\n")); + DEBUG(5,("make_user_info_for_reply: User passwords not in encrypted format.\n")); if (plaintext_password.data) { unsigned char local_lm_response[24]; + +#ifdef DEBUG_PASSWORD + DEBUG(10,("Unencrypted password (len %d):\n",plaintext_password.length)); + dump_data(100, plaintext_password.data, plaintext_password.length); +#endif SMBencrypt( (const uchar *)plaintext_password.data, chal, local_lm_response); local_lm_blob = data_blob(local_lm_response, 24); @@ -587,23 +505,54 @@ BOOL make_user_info_for_reply(auth_usersupplied_info **user_info, ret = make_user_info_map(user_info, smb_name, client_domain, remote_machine, - sec_blob, local_lm_blob, local_nt_blob, plaintext_password, - ntlmssp_flags, encrypted); + ntlmssp_flags, False); data_blob_free(&local_lm_blob); return ret; } /**************************************************************************** + Create an auth_usersupplied_data structure +****************************************************************************/ + +BOOL make_user_info_for_reply_enc(auth_usersupplied_info **user_info, + char *smb_name, + char *client_domain, + DATA_BLOB lm_resp, DATA_BLOB nt_resp, + DATA_BLOB plaintext_password) +{ + uint32 ntlmssp_flags = 0; + + DATA_BLOB no_plaintext_blob = data_blob(NULL, 0); + + if (lm_resp.length == 24) { + ntlmssp_flags |= NTLMSSP_NEGOTIATE_OEM; + } + if (nt_resp.length == 0) { + } else if (nt_resp.length == 24) { + ntlmssp_flags |= NTLMSSP_NEGOTIATE_NTLM; + } else { + ntlmssp_flags |= NTLMSSP_NEGOTIATE_NTLM2; + } + + return make_user_info_map(user_info, smb_name, + client_domain, + remote_machine, + lm_resp, + nt_resp, + no_plaintext_blob, + ntlmssp_flags, True); +} + +/**************************************************************************** Create a guest user_info blob, for anonymous authenticaion. ****************************************************************************/ BOOL make_user_info_guest(auth_usersupplied_info **user_info) { - DATA_BLOB sec_blob = data_blob(NULL, 0); DATA_BLOB lm_blob = data_blob(NULL, 0); DATA_BLOB nt_blob = data_blob(NULL, 0); DATA_BLOB plaintext_blob = data_blob(NULL, 0); @@ -612,7 +561,7 @@ BOOL make_user_info_guest(auth_usersupplied_info **user_info) return make_user_info(user_info, "","", "","", - "", sec_blob, + "", nt_blob, lm_blob, plaintext_blob, ntlmssp_flags, True); @@ -680,7 +629,6 @@ void free_user_info(auth_usersupplied_info **user_info) SAFE_FREE((*user_info)->internal_username.str); SAFE_FREE((*user_info)->client_domain.str); SAFE_FREE((*user_info)->domain.str); - data_blob_free(&(*user_info)->sec_blob); data_blob_free(&(*user_info)->lm_resp); data_blob_free(&(*user_info)->nt_resp); SAFE_FREE((*user_info)->interactive_password); @@ -725,6 +673,22 @@ BOOL make_server_info_guest(auth_serversupplied_info **server_info) return False; } +/*************************************************************************** + Make an auth_methods struct +***************************************************************************/ + +BOOL make_auth_methods(auth_methods **auth_method) +{ + *auth_method = malloc(sizeof(**auth_method)); + if (!*auth_method) { + DEBUG(0,("make_auth_method: malloc failed!\n")); + return False; + } + ZERO_STRUCTP(*auth_method); + + return True; +} + /**************************************************************************** Delete a SID token. ****************************************************************************/ @@ -764,25 +728,3 @@ NT_USER_TOKEN *dup_nt_token(NT_USER_TOKEN *ptoken) return token; } - -/**************************************************************************** - Check for a guest logon (username = "") and if so create the required - structure. -****************************************************************************/ - -NTSTATUS check_guest_security(const auth_usersupplied_info *user_info, - auth_serversupplied_info **server_info) -{ - NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE; - - if (!(user_info->internal_username.str - && *user_info->internal_username.str)) { - if (make_server_info_guest(server_info)) { - nt_status = NT_STATUS_OK; - } else { - nt_status = NT_STATUS_NO_SUCH_USER; - } - } - - return nt_status; -} diff --git a/source3/include/auth.h b/source3/include/auth.h index 04c5aa55e5..e33ccc2e24 100644 --- a/source3/include/auth.h +++ b/source3/include/auth.h @@ -53,8 +53,6 @@ typedef struct usersupplied_info uint32 ntlmssp_flags; - DATA_BLOB sec_blob; - AUTH_STR client_domain; /* domain name string */ AUTH_STR domain; /* domain name after mapping */ AUTH_STR internal_username; /* username after mapping */ @@ -69,16 +67,16 @@ typedef struct usersupplied_info #define SAM_FILL_UNIX 0x08 #define SAM_FILL_ALL (SAM_FILL_NAME | SAM_FILL_INFO3 | SAM_FILL_SAM | SAM_FILL_UNIX) -typedef struct serversupplied_info +typedef struct serversupplied_info { BOOL guest; /* This groups info is needed for when we become_user() for this uid */ int n_groups; gid_t *groups; - + /* NT group information taken from the info3 structure */ - + NT_USER_TOKEN *ptok; uchar session_key[16]; @@ -86,8 +84,52 @@ typedef struct serversupplied_info uint8 first_8_lm_hash[8]; uint32 sam_fill_level; /* How far is this structure filled? */ - + SAM_ACCOUNT *sam_account; + + void *pam_handle; + } auth_serversupplied_info; +typedef struct authsupplied_info { + DATA_BLOB challange; + + /* Who set this up in the first place? */ + char *challange_set_by; \ + + struct auth_methods *challange_set_method; + /* What order are the various methods in? Try to stop it changing under us */ + struct auth_methods *auth_method_list; +} auth_authsupplied_info; + +typedef struct auth_methods +{ + struct auth_methods *prev, *next; + char *name; /* What name got this module */ + + NTSTATUS (*auth)(void *my_private_data, + const auth_usersupplied_info *user_info, + const struct authsupplied_info *auth_info, + auth_serversupplied_info **server_info); + + DATA_BLOB (*get_chal)(void **my_private_data, const struct authsupplied_info *auth_info); + + /* Used to keep tabs on things like the cli for SMB server authentication */ + void *private_data; + + /* Function to clean up the above arbitary structure */ + void (*free_private_data)(void **private_data); + + /* Function to send a keepalive message on the above structure */ + void (*send_keepalive)(void **private_data); + +} auth_methods; + +typedef struct auth_init_function { + char *name; + /* Function to create a member of the authmethods list */ + BOOL (*init)(struct auth_methods **auth_method); +} auth_init_function; + + #endif /* _SMBAUTH_H_ */ diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index f5d6c5a7f4..4ea19db9ec 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -197,7 +197,7 @@ static BOOL cli_session_setup_plaintext(struct cli_state *cli, char *user, int passlen; char *p; - passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE); + passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE|STR_ASCII); set_message(cli->outbuf,13,0,True); CVAL(cli->outbuf,smb_com) = SMBsesssetupX; diff --git a/source3/libsmb/domain_client_validate.c b/source3/libsmb/domain_client_validate.c index 2fd17e1fa4..df263e7ae9 100644 --- a/source3/libsmb/domain_client_validate.c +++ b/source3/libsmb/domain_client_validate.c @@ -271,9 +271,10 @@ static BOOL find_connect_pdc(struct cli_state *pcli, ************************************************************************/ NTSTATUS domain_client_validate(const auth_usersupplied_info *user_info, - auth_serversupplied_info **server_info, - char *server, unsigned char *trust_passwd, - time_t last_change_time) + uchar chal[8], + auth_serversupplied_info **server_info, + char *server, unsigned char *trust_passwd, + time_t last_change_time) { fstring remote_machine; NET_ID_INFO_CTR ctr; @@ -330,7 +331,7 @@ NTSTATUS domain_client_validate(const auth_usersupplied_info *user_info, * in the info3 structure. */ - status = cli_nt_login_network(&cli, user_info, smb_uid_low, + status = cli_nt_login_network(&cli, user_info, chal, smb_uid_low, &ctr, &info3); if (!NT_STATUS_IS_OK(status)) { diff --git a/source3/nsswitch/winbindd_pam.c b/source3/nsswitch/winbindd_pam.c index 9138583096..2ea0692fe9 100644 --- a/source3/nsswitch/winbindd_pam.c +++ b/source3/nsswitch/winbindd_pam.c @@ -40,6 +40,7 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state) NET_USER_INFO_3 info3; NET_ID_INFO_CTR ctr; struct cli_state *cli; + uchar chal[8]; DEBUG(3, ("[%5d]: pam auth %s\n", state->pid, state->request.data.auth.user)); @@ -59,7 +60,8 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state) if (state->request.data.auth.pass[0]) make_user_info_winbind(&user_info, name_user, name_domain, - state->request.data.auth.pass); + state->request.data.auth.pass, + chal); else return WINBINDD_ERROR; @@ -87,7 +89,7 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state) goto done; } - result = cli_nt_login_network(cli, user_info, smb_uid_low, + result = cli_nt_login_network(cli, user_info, chal, smb_uid_low, &ctr, &info3); free_user_info(&user_info); @@ -123,7 +125,7 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state) make_user_info_winbind_crap( &user_info, name_user, - name_domain, state->request.data.auth_crap.chal, + name_domain, (uchar *)state->request.data.auth_crap.lm_resp, state->request.data.auth_crap.lm_resp_len, (uchar *)state->request.data.auth_crap.nt_resp, @@ -153,8 +155,8 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state) goto done; } - result = cli_nt_login_network(cli, user_info, smb_uid_low, - &ctr, &info3); + result = cli_nt_login_network(cli, user_info, state->request.data.auth_crap.chal, + smb_uid_low, &ctr, &info3); free_user_info(&user_info); diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 3f781be67f..ab17f90a6e 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -179,6 +179,7 @@ typedef struct int maxprotocol; int minprotocol; int security; + char **AuthMethods; BOOL paranoid_server_security; int maxdisksize; int lpqcachetime; @@ -238,7 +239,6 @@ typedef struct BOOL bNullPasswords; BOOL bObeyPamRestrictions; BOOL bLoadPrinters; - BOOL bUseRhosts; BOOL bLargeReadwrite; BOOL bReadRaw; BOOL bWriteRaw; @@ -261,7 +261,6 @@ typedef struct BOOL bRestrictAnonymous; BOOL bLanmanAuth; BOOL bNTLMAuth; - BOOL bPlaintextToSmbpasswd; BOOL bDebugHiresTimestamp; BOOL bDebugPid; BOOL bDebugUid; @@ -661,6 +660,7 @@ static struct parm_struct parm_table[] = { {"Security Options", P_SEP, P_SEPARATOR}, {"security", P_ENUM, P_GLOBAL, &Globals.security, NULL, enum_security, FLAG_BASIC}, + {"auth methods", P_LIST, P_GLOBAL, &Globals.AuthMethods, NULL, NULL, FLAG_BASIC}, {"encrypt passwords", P_BOOL, P_GLOBAL, &Globals.bEncryptPasswords, NULL, NULL, FLAG_BASIC}, {"update encrypted", P_BOOL, P_GLOBAL, &Globals.bUpdateEncrypt, NULL, NULL, FLAG_BASIC}, {"allow trusted domains", P_BOOL, P_GLOBAL, &Globals.bAllowTrustedDomains, NULL, NULL, 0}, @@ -691,8 +691,6 @@ static struct parm_struct parm_table[] = { {"restrict anonymous", P_BOOL, P_GLOBAL, &Globals.bRestrictAnonymous, NULL, NULL, 0}, {"lanman auth", P_BOOL, P_GLOBAL, &Globals.bLanmanAuth, NULL, NULL, 0}, {"ntlm auth", P_BOOL, P_GLOBAL, &Globals.bNTLMAuth, NULL, NULL, 0}, - {"plaintext to smbpasswd", P_BOOL, P_GLOBAL, &Globals.bPlaintextToSmbpasswd, NULL, NULL, 0}, - {"use rhosts", P_BOOL, P_GLOBAL, &Globals.bUseRhosts, NULL, NULL, 0}, {"username", P_STRING, P_LOCAL, &sDefault.szUsername, NULL, NULL, FLAG_GLOBAL | FLAG_SHARE}, {"user", P_STRING, P_LOCAL, &sDefault.szUsername, NULL, NULL, 0}, @@ -1191,7 +1189,7 @@ static void init_globals(void) string_set(&Globals.szPassdbModulePath, ""); string_set(&Globals.szGuestaccount, GUEST_ACCOUNT); - + /* * Allow the default PASSWD_CHAT to be overridden in local.h. */ @@ -1218,7 +1216,6 @@ static void init_globals(void) string_set(&Globals.szNameResolveOrder, "lmhosts wins host bcast"); Globals.bLoadPrinters = True; - Globals.bUseRhosts = False; Globals.max_packet = 65535; Globals.mangled_stack = 50; Globals.max_xmit = 65535; @@ -1281,7 +1278,6 @@ static void init_globals(void) Globals.bRestrictAnonymous = False; Globals.bLanmanAuth = True; /* Do use the LanMan hash if it is available */ Globals.bNTLMAuth = True; /* Do use NTLMv1 if it is available (otherwise NTLMv2) */ - Globals.bPlaintextToSmbpasswd = False; /* Check the passwords with smbpasswd, even if in plaintext */ Globals.map_to_guest = 0; /* By Default, "Never" */ Globals.min_passwd_length = MINPASSWDLENGTH; /* By Default, 5. */ Globals.oplock_break_wait_time = 0; /* By Default, 0 msecs. */ @@ -1543,7 +1539,6 @@ FN_GLOBAL_BOOL(lp_wins_proxy, &Globals.bWINSproxy) FN_GLOBAL_BOOL(lp_local_master, &Globals.bLocalMaster) FN_GLOBAL_BOOL(lp_domain_logons, &Globals.bDomainLogons) FN_GLOBAL_BOOL(lp_load_printers, &Globals.bLoadPrinters) -FN_GLOBAL_BOOL(lp_use_rhosts, &Globals.bUseRhosts) FN_GLOBAL_BOOL(lp_readprediction, &Globals.bReadPrediction) FN_GLOBAL_BOOL(lp_readbmpx, &Globals.bReadbmpx) FN_GLOBAL_BOOL(lp_readraw, &Globals.bReadRaw) @@ -1573,7 +1568,6 @@ FN_GLOBAL_BOOL(lp_allow_trusted_domains, &Globals.bAllowTrustedDomains) FN_GLOBAL_BOOL(lp_restrict_anonymous, &Globals.bRestrictAnonymous) FN_GLOBAL_BOOL(lp_lanman_auth, &Globals.bLanmanAuth) FN_GLOBAL_BOOL(lp_ntlm_auth, &Globals.bNTLMAuth) -FN_GLOBAL_BOOL(lp_plaintext_to_smbpasswd, &Globals.bPlaintextToSmbpasswd) FN_GLOBAL_BOOL(lp_host_msdfs, &Globals.bHostMSDfs) FN_GLOBAL_BOOL(lp_kernel_oplocks, &Globals.bKernelOplocks) FN_GLOBAL_BOOL(lp_enhanced_browsing, &Globals.enhanced_browsing) @@ -1594,6 +1588,7 @@ FN_GLOBAL_INTEGER(lp_deadtime, &Globals.deadtime) FN_GLOBAL_INTEGER(lp_maxprotocol, &Globals.maxprotocol) FN_GLOBAL_INTEGER(lp_minprotocol, &Globals.minprotocol) FN_GLOBAL_INTEGER(lp_security, &Globals.security) +FN_GLOBAL_LIST(lp_auth_methods, &Globals.AuthMethods) FN_GLOBAL_BOOL(lp_paranoid_server_security, &Globals.paranoid_server_security) FN_GLOBAL_INTEGER(lp_maxdisksize, &Globals.maxdisksize) FN_GLOBAL_INTEGER(lp_lpqcachetime, &Globals.lpqcachetime) diff --git a/source3/passdb/pdb_smbpasswd.c b/source3/passdb/pdb_smbpasswd.c index e190be99a5..ce79be1666 100644 --- a/source3/passdb/pdb_smbpasswd.c +++ b/source3/passdb/pdb_smbpasswd.c @@ -1408,7 +1408,7 @@ BOOL pdb_getsampwuid (SAM_ACCOUNT *sam_acct, uid_t uid) struct smb_passwd *smb_pw; void *fp = NULL; - DEBUG(10, ("pdb_getsampwuid: search by uid: %d\n", uid)); + DEBUG(10, ("pdb_getsampwuid: search by uid: %d\n", (int)uid)); /* Open the sam password file - not for update. */ fp = startsmbfilepwent(lp_smb_passwd_file(), PWF_READ, &pw_file_lock_depth); diff --git a/source3/rpc_client/cli_login.c b/source3/rpc_client/cli_login.c index eaedb1613a..e5c221690d 100644 --- a/source3/rpc_client/cli_login.c +++ b/source3/rpc_client/cli_login.c @@ -159,9 +159,10 @@ password equivalents over the network. JRA. ****************************************************************************/ NTSTATUS cli_nt_login_network(struct cli_state *cli, - const auth_usersupplied_info *user_info, - uint32 smb_userid_low, NET_ID_INFO_CTR *ctr, - NET_USER_INFO_3 *user_info3) + const auth_usersupplied_info *user_info, + uchar chal[8], + uint32 smb_userid_low, NET_ID_INFO_CTR *ctr, + NET_USER_INFO_3 *user_info3) { DEBUG(5,("cli_nt_login_network: %d\n", __LINE__)); /* indicate a "network" login */ @@ -174,7 +175,7 @@ NTSTATUS cli_nt_login_network(struct cli_state *cli, ((user_info->wksta_name.len > 0) ? user_info->wksta_name.str : cli->clnt_name_slash), - user_info->sec_blob.data, + chal, user_info->lm_resp.data, user_info->lm_resp.length, user_info->nt_resp.data, user_info->nt_resp.length); diff --git a/source3/rpc_server/srv_netlog_nt.c b/source3/rpc_server/srv_netlog_nt.c index 1aa58f5274..6f0d2384d5 100644 --- a/source3/rpc_server/srv_netlog_nt.c +++ b/source3/rpc_server/srv_netlog_nt.c @@ -566,26 +566,46 @@ NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON * switch (ctr->switch_value) { case NET_LOGON_TYPE: + { + auth_authsupplied_info *auth_info = NULL; + make_auth_info_fixed(&auth_info, ctr->auth.id2.lm_chal); /* Standard challange/response authenticaion */ make_user_info_netlogon_network(&user_info, nt_username, nt_domain, - nt_workstation, ctr->auth.id2.lm_chal, + nt_workstation, ctr->auth.id2.lm_chal_resp.buffer, ctr->auth.id2.lm_chal_resp.str_str_len, ctr->auth.id2.nt_chal_resp.buffer, ctr->auth.id2.nt_chal_resp.str_str_len); + + status = check_password(user_info, auth_info, &server_info); + free_auth_info(&auth_info); + break; + } case INTERACTIVE_LOGON_TYPE: /* 'Interactive' autheticaion, supplies the password in its MD4 form, encrypted with the session key. We will convert this to challange/responce for the auth subsystem to chew on */ { + auth_authsupplied_info *auth_info = NULL; + DATA_BLOB chal; + if (!make_auth_info_subsystem(&auth_info)) { + return NT_STATUS_NO_MEMORY; + } + + chal = auth_get_challange(auth_info); + make_user_info_netlogon_interactive(&user_info, nt_username, nt_domain, - nt_workstation, + nt_workstation, chal.data, ctr->auth.id1.lm_owf.data, ctr->auth.id1.nt_owf.data, p->dc.sess_key); + status = check_password(user_info, auth_info, &server_info); + data_blob_free(&chal); + free_auth_info(&auth_info); + break; } default: @@ -593,8 +613,6 @@ NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON * return NT_STATUS_INVALID_INFO_CLASS; } /* end switch */ - status = check_password(user_info, &server_info); - free_user_info(&user_info); DEBUG(5, ("_net_sam_logon: check_password returned status %s\n", diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c index b9c40e719b..4b3140b350 100644 --- a/source3/rpc_server/srv_pipe.c +++ b/source3/rpc_server/srv_pipe.c @@ -271,6 +271,7 @@ static BOOL api_pipe_ntlmssp_verify(pipes_struct *p, RPC_AUTH_NTLMSSP_RESP *ntlm NTSTATUS nt_status; auth_usersupplied_info *user_info = NULL; + auth_authsupplied_info *auth_info = NULL; auth_serversupplied_info *server_info = NULL; uid_t *puid; @@ -343,17 +344,20 @@ static BOOL api_pipe_ntlmssp_verify(pipes_struct *p, RPC_AUTH_NTLMSSP_RESP *ntlm return False; } + + make_auth_info_fixed(&auth_info, (uchar*)p->challenge); if (!make_user_info_netlogon_network(&user_info, - user_name, domain, wks, (uchar*)p->challenge, + user_name, domain, wks, lm_owf, lm_pw_len, nt_owf, nt_pw_len)) { DEBUG(0,("make_user_info_netlogon_network failed! Failing authenticaion.\n")); return False; } - nt_status = check_password(user_info, &server_info); + nt_status = check_password(user_info, auth_info, &server_info); + free_auth_info(&auth_info); free_user_info(&user_info); p->ntlmssp_auth_validated = NT_STATUS_IS_OK(nt_status); diff --git a/source3/smbd/auth.c b/source3/smbd/auth.c index 95c97182b8..c62e2ed5a0 100644 --- a/source3/smbd/auth.c +++ b/source3/smbd/auth.c @@ -58,27 +58,50 @@ static BOOL check_domain_match(char *user, char *domain) ****************************************************************************/ NTSTATUS check_password(const auth_usersupplied_info *user_info, + const auth_authsupplied_info *auth_info, auth_serversupplied_info **server_info) { NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE; - BOOL done_pam = False; const char *pdb_username; + auth_methods *auth_method; + + if (!user_info || !auth_info || !server_info) { + return NT_STATUS_LOGON_FAILURE; + } DEBUG(3, ("check_password: Checking password for unmapped user [%s]\\[%s]@[%s] with the new password interface\n", user_info->client_domain.str, user_info->smb_name.str, user_info->wksta_name.str)); DEBUG(3, ("check_password: mapped user is: [%s]\\[%s]@[%s]\n", user_info->domain.str, user_info->internal_username.str, user_info->wksta_name.str)); - - if (!NT_STATUS_IS_OK(nt_status)) { - nt_status = check_guest_security(user_info, server_info); + DEBUG(10, ("auth_info challange created by %s\n", auth_info->challange_set_by)); + DEBUG(10, ("challange is: \n")); + dump_data(5, (auth_info)->challange.data, (auth_info)->challange.length); + +#ifdef DEBUG_PASSWORD + DEBUG(100, ("user_info has passwords of length %d and %d\n", + user_info->lm_resp.length, user_info->nt_resp.length)); + DEBUG(100, ("lm:\n")); + dump_data(100, user_info->lm_resp.data, user_info->lm_resp.length); + DEBUG(100, ("nt:\n")); + dump_data(100, user_info->nt_resp.data, user_info->nt_resp.length); +#endif + + for (auth_method = auth_info->auth_method_list;auth_method; auth_method = auth_method->next) + { + nt_status = auth_method->auth(auth_method->private_data, user_info, auth_info, server_info); if (NT_STATUS_IS_OK(nt_status)) { - DEBUG(5, ("check_password: checking guest-account for user [%s] suceeded\n", user_info->smb_name.str)); + DEBUG(3, ("check_password: %s authentication for user [%s] suceeded\n", + auth_method->name, user_info->smb_name.str)); } else { - DEBUG(10, ("check_password: checking gusst-account for user [%s] FAILED with error %s\n", user_info->smb_name.str, get_nt_error_msg(nt_status))); - - } + DEBUG(5, ("check_password: %s authentication for user [%s] FAILED with error %s\n", + auth_method->name, user_info->smb_name.str, get_nt_error_msg(nt_status))); + } + + if (NT_STATUS_IS_OK(nt_status)) { + break; + } } /* This needs to be sorted: If it doesn't match, what should we do? */ @@ -86,83 +109,47 @@ NTSTATUS check_password(const auth_usersupplied_info *user_info, return NT_STATUS_LOGON_FAILURE; } - if (!NT_STATUS_IS_OK(nt_status)) { - nt_status = check_rhosts_security(user_info, server_info); - if (NT_STATUS_IS_OK(nt_status)) { - DEBUG(3, ("check_password: Password (rhosts) for user [%s] suceeded\n", user_info->smb_name.str)); - } else { - DEBUG(10, ("check_password: Password (rhosts) for user [%s] FAILED with error %s\n", user_info->smb_name.str, get_nt_error_msg(nt_status))); - - } - } - - if ((lp_security() == SEC_DOMAIN) && !NT_STATUS_IS_OK(nt_status)) { - nt_status = check_domain_security(user_info, server_info); - if (NT_STATUS_IS_OK(nt_status)) { - DEBUG(7, ("check_password: Password (domain) for user [%s] suceeded\n", user_info->smb_name.str)); - } else { - DEBUG(5, ("check_password: Password (domain) for user [%s] FAILED with error %s\n", user_info->smb_name.str, get_nt_error_msg(nt_status))); - - } - } - - if ((lp_security() == SEC_SERVER) && !NT_STATUS_IS_OK(nt_status)) { - nt_status = check_server_security(user_info, server_info); - if (NT_STATUS_IS_OK(nt_status)) { - DEBUG(7, ("check_password: Password (server) for user [%s] suceeded\n", user_info->smb_name.str)); - } else { - DEBUG(5, ("check_password: Password (server) for user [%s] FAILED with error %s\n", user_info->smb_name.str, get_nt_error_msg(nt_status))); - - } - } + /* This is one of the few places the *relies* (rather than just sets defaults + on the value of lp_security(). This needs to change. A new paramater + perhaps? */ if (lp_security() >= SEC_SERVER) { smb_user_control(user_info, *server_info, nt_status); } - if (!NT_STATUS_IS_OK(nt_status)) { - if (user_info->encrypted || lp_plaintext_to_smbpasswd()) { - nt_status = check_smbpasswd_security(user_info, server_info); - } else { - nt_status = check_unix_security(user_info, server_info); - done_pam = True; - } - - if (NT_STATUS_IS_OK(nt_status)) { - DEBUG(7, ("check_password: Password (unix/smbpasswd) for user [%s] suceeded\n", user_info->smb_name.str)); - } else { - DEBUG(5, ("check_password: Password (unix/smbpasswd) for user [%s] FAILED with error %s\n", user_info->smb_name.str, get_nt_error_msg(nt_status))); - - } - } - if (NT_STATUS_IS_OK(nt_status)) { pdb_username = pdb_get_username((*server_info)->sam_account); - if (!done_pam && !(*server_info)->guest) { + if (!(*server_info)->guest) { /* We might not be root if we are an RPC call */ become_root(); nt_status = smb_pam_accountcheck(pdb_username); unbecome_root(); if (NT_STATUS_IS_OK(nt_status)) { - DEBUG(5, ("check_password: PAM Account for user [%s] suceeded\n", pdb_username)); + DEBUG(5, ("check_password: PAM Account for user [%s] suceeded\n", + pdb_username)); } else { - DEBUG(3, ("check_password: PAM Account for user [%s] FAILED with error %s\n", pdb_username, get_nt_error_msg(nt_status))); + DEBUG(3, ("check_password: PAM Account for user [%s] FAILED with error %s\n", + pdb_username, get_nt_error_msg(nt_status))); } } + + if (NT_STATUS_IS_OK(nt_status)) { + DEBUG((*server_info)->guest ? 5 : 2, + ("check_password: %sauthenticaion for user [%s] -> [%s] -> [%s] suceeded\n", + (*server_info)->guest ? "guest " : "", + user_info->smb_name.str, + user_info->internal_username.str, + pdb_username)); + } } - if (NT_STATUS_IS_OK(nt_status)) { - DEBUG(3, ("check_password: %sauthenticaion for user [%s] -> [%s] -> [%s] suceeded\n", - (*server_info)->guest ? "guest " : "", - user_info->smb_name.str, - user_info->internal_username.str, - pdb_username)); - } else { - DEBUG(3, ("check_password: Authenticaion for user [%s] -> [%s] FAILED with error %s\n", user_info->smb_name.str, user_info->internal_username.str, get_nt_error_msg(nt_status))); + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(2, ("check_password: Authenticaion for user [%s] -> [%s] FAILED with error %s\n", + user_info->smb_name.str, user_info->internal_username.str, + get_nt_error_msg(nt_status))); ZERO_STRUCTP(server_info); - } - + } return nt_status; } @@ -210,16 +197,35 @@ static NTSTATUS pass_check_smb(char *smb_name, { NTSTATUS nt_status; auth_usersupplied_info *user_info = NULL; + extern auth_authsupplied_info *negprot_global_auth_info; auth_serversupplied_info *server_info = NULL; + if (encrypted) { + make_user_info_for_reply_enc(&user_info, smb_name, + domain, + lm_pwd, + nt_pwd, + plaintext_password); + nt_status = check_password(user_info, negprot_global_auth_info, &server_info); + } else { + auth_authsupplied_info *plaintext_auth_info = NULL; + DATA_BLOB chal; + if (!make_auth_info_subsystem(&plaintext_auth_info)) { + return NT_STATUS_NO_MEMORY; + } - make_user_info_for_reply(&user_info, smb_name, - domain, - lm_pwd, - nt_pwd, - plaintext_password, - encrypted); - - nt_status = check_password(user_info, &server_info); + chal = auth_get_challange(plaintext_auth_info); + + if (!make_user_info_for_reply(&user_info, + smb_name, domain, chal.data, + plaintext_password)) { + return NT_STATUS_NO_MEMORY; + } + + nt_status = check_password(user_info, plaintext_auth_info, &server_info); + + data_blob_free(&chal); + free_auth_info(&plaintext_auth_info); + } free_user_info(&user_info); free_server_info(&server_info); return nt_status; @@ -235,22 +241,23 @@ BOOL password_ok(char *smb_name, DATA_BLOB password_blob) DATA_BLOB null_password = data_blob(NULL, 0); extern BOOL global_encrypted_passwords_negotiated; - - if (global_encrypted_passwords_negotiated) { + BOOL encrypted = (global_encrypted_passwords_negotiated && password_blob.length == 24); + + if (encrypted) { /* * The password could be either NTLM or plain LM. Try NTLM first, * but fall-through as required. * NTLMv2 makes no sense here. */ - if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), null_password, password_blob, null_password, global_encrypted_passwords_negotiated))) { + if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), null_password, password_blob, null_password, encrypted))) { return True; } - if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), password_blob, null_password, null_password, global_encrypted_passwords_negotiated))) { + if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), password_blob, null_password, null_password, encrypted))) { return True; } } else { - if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), null_password, null_password, password_blob, global_encrypted_passwords_negotiated))) { + if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), null_password, null_password, password_blob, encrypted))) { return True; } } diff --git a/source3/smbd/auth_builtin.c b/source3/smbd/auth_builtin.c new file mode 100644 index 0000000000..6ea6d0bbe0 --- /dev/null +++ b/source3/smbd/auth_builtin.c @@ -0,0 +1,87 @@ +/* + Unix SMB/Netbios implementation. + Version 3.0. + Generic authenticaion types + Copyright (C) Andrew Bartlett 2001 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +/**************************************************************************** + Check for a guest logon (username = "") and if so create the required + structure. +****************************************************************************/ + +static NTSTATUS check_guest_security(void *my_private_data, + const auth_usersupplied_info *user_info, + const auth_authsupplied_info *auth_info, + auth_serversupplied_info **server_info) +{ + NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE; + + if (!(user_info->internal_username.str + && *user_info->internal_username.str)) { + if (make_server_info_guest(server_info)) { + nt_status = NT_STATUS_OK; + } else { + nt_status = NT_STATUS_NO_SUCH_USER; + } + } + + return nt_status; +} + +BOOL auth_init_guest(auth_methods **auth_method) +{ + if (!make_auth_methods(auth_method)) { + return False; + } + + (*auth_method)->auth = check_guest_security; + return True; +} + +/**************************************************************************** + Check against either sam or unix, depending on encryption. +****************************************************************************/ + +static NTSTATUS check_local_security(void *my_private_data, + const auth_usersupplied_info *user_info, + const auth_authsupplied_info *auth_info, + auth_serversupplied_info **server_info) +{ + NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE; + + if (user_info->encrypted) { + nt_status = check_sam_security(my_private_data, user_info, auth_info, server_info); + } else { + nt_status = check_unix_security(my_private_data, user_info, auth_info, server_info); + } + + return nt_status; +} + +BOOL auth_init_local(auth_methods **auth_method) +{ + if (!make_auth_methods(auth_method)) { + return False; + } + + (*auth_method)->auth = check_local_security; + return True; +} + diff --git a/source3/smbd/auth_domain.c b/source3/smbd/auth_domain.c index 4ada7d4a56..ef0e5b2f10 100644 --- a/source3/smbd/auth_domain.c +++ b/source3/smbd/auth_domain.c @@ -28,8 +28,10 @@ BOOL global_machine_password_needs_changing = False; Check for a valid username and password in security=domain mode. ****************************************************************************/ -NTSTATUS check_domain_security(const auth_usersupplied_info *user_info, - auth_serversupplied_info **server_info) +static NTSTATUS check_ntdomain_security(void *my_private_data, + const auth_usersupplied_info *user_info, + const auth_authsupplied_info *auth_info, + auth_serversupplied_info **server_info) { NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE; char *p, *pserver; @@ -66,8 +68,18 @@ NTSTATUS check_domain_security(const auth_usersupplied_info *user_info, if (! *pserver) pserver = "*"; p = pserver; - nt_status = domain_client_validate(user_info, server_info, + nt_status = domain_client_validate(user_info, (uchar *)auth_info->challange.data,server_info, p, trust_passwd, last_change_time); return nt_status; } + +BOOL auth_init_ntdomain(auth_methods **auth_method) +{ + if (!make_auth_methods(auth_method)) { + return False; + } + + (*auth_method)->auth = check_ntdomain_security; + return True; +} diff --git a/source3/smbd/auth_info.c b/source3/smbd/auth_info.c new file mode 100644 index 0000000000..12b843d781 --- /dev/null +++ b/source3/smbd/auth_info.c @@ -0,0 +1,279 @@ +/* + Unix SMB/Netbios implementation. + Version 3.0. + Authentication utility functions + Copyright (C) Andrew Bartlett 2001 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +const struct auth_init_function builtin_auth_init_functions[] = { + { "guest", auth_init_guest }, + { "rhosts", auth_init_rhosts }, + { "hostsequiv", auth_init_hostsequiv }, + { "sam", auth_init_sam }, + { "unix", auth_init_unix }, + { "local", auth_init_local }, + { "smbserver", auth_init_smbserver }, + { "ntdomain", auth_init_ntdomain }, + { "winbind", auth_init_winbind }, + { NULL, NULL} +}; + +/*************************************************************************** + Make a auth_info struct +***************************************************************************/ + +static BOOL make_auth_info(auth_authsupplied_info **auth_info) +{ + *auth_info = malloc(sizeof(**auth_info)); + if (!*auth_info) { + DEBUG(0,("make_auth_info: malloc failed!\n")); + return False; + } + ZERO_STRUCTP(*auth_info); + + return True; +} + +/*************************************************************************** + Make a auth_info struct with a specified list. +***************************************************************************/ + +BOOL make_auth_info_list(auth_authsupplied_info **auth_info, auth_methods *list) +{ + if (!make_auth_info(auth_info)) { + return False; + } + + (*auth_info)->auth_method_list = list; + + return True; +} + +/*************************************************************************** + Make a auth_info struct for the auth subsystem +***************************************************************************/ + +static BOOL make_auth_info_text_list(auth_authsupplied_info **auth_info, char **text_list) +{ + auth_methods *list = NULL; + auth_methods *t = NULL; + auth_methods *tmp; + int i; + + for (;*text_list; text_list++) + { + DEBUG(5,("Attempting to find an auth method to match %s\n", *text_list)); + for (i = 0; builtin_auth_init_functions[i].name; i++) + { + if (strequal(builtin_auth_init_functions[i].name, *text_list)) + { + DEBUG(5,("Found auth method %s (at pos %d)\n", *text_list, i)); + /* Malloc entry, fill it, link it */ + t = (auth_methods *)malloc(sizeof(*t)); + if (!t) { + DEBUG(0,("make_pw_chat: malloc failed!\n")); + return False; + } + + ZERO_STRUCTP(t); + + if (builtin_auth_init_functions[i].init(&t)) { + DEBUG(5,("auth method %s has a valid init\n", *text_list)); + t->name = builtin_auth_init_functions[i].name; + DLIST_ADD_END(list, t, tmp); + } else { + DEBUG(5,("auth method %s DOES NOT have a valid init\n", *text_list)); + } + break; + } + } + } + + make_auth_info_list(auth_info, list); + + return True; +} + +/*************************************************************************** + Make a auth_info struct for the auth subsystem +***************************************************************************/ + +BOOL make_auth_info_subsystem(auth_authsupplied_info **auth_info) +{ + char **auth_method_list = NULL; + + if (!make_auth_info(auth_info)) { + return False; + } + + if (lp_auth_methods() && !lp_list_copy(&auth_method_list, lp_auth_methods())) { + return False; + } + + if (auth_method_list == NULL) { + switch (lp_security()) + { + case SEC_DOMAIN: + DEBUG(5,("Making default auth method list for security=domain\n")); + auth_method_list = lp_list_make("guest ntdomain local"); + break; + case SEC_SERVER: + DEBUG(5,("Making default auth method list for security=server\n")); + auth_method_list = lp_list_make("guest smbserver local"); + break; + case SEC_USER: + DEBUG(5,("Making default auth method list for security=user\n")); + auth_method_list = lp_list_make("guest local"); + break; + case SEC_SHARE: + DEBUG(5,("Making default auth method list for security=share\n")); + auth_method_list = lp_list_make("guest local"); + break; + } + } else { + DEBUG(5,("Using specified auth order\n")); + } + + if (!make_auth_info_text_list(auth_info, auth_method_list)) { + lp_list_free(&auth_method_list); + return False; + } + + lp_list_free(&auth_method_list); + return True; +} + +/*************************************************************************** + Make a auth_info struct with a random challange +***************************************************************************/ + +BOOL make_auth_info_random(auth_authsupplied_info **auth_info) +{ + uchar chal[8]; + if (!make_auth_info_subsystem(auth_info)) { + return False; + } + + generate_random_buffer(chal, sizeof(chal), False); + (*auth_info)->challange = data_blob(chal, sizeof(chal)); + + (*auth_info)->challange_set_by = "random"; + + return True; +} + +/*************************************************************************** + Make a auth_info struct with a fixed challange +***************************************************************************/ + +BOOL make_auth_info_fixed(auth_authsupplied_info **auth_info, uchar chal[8]) +{ + if (!make_auth_info_subsystem(auth_info)) { + return False; + } + + (*auth_info)->challange = data_blob(chal, 8); + return True; +} + +/*************************************************************************** + Clear out a auth_info struct that has been allocated +***************************************************************************/ + +void free_auth_info(auth_authsupplied_info **auth_info) +{ + auth_methods *list; + if (*auth_info != NULL) { + list = (*auth_info)->auth_method_list; + while (list) { + auth_methods *old_head = list; + if (list->free_private_data) { + list->free_private_data(&(list->private_data)); + } + DLIST_REMOVE(list, list); + SAFE_FREE(old_head); + } + + data_blob_free(&(*auth_info)->challange); + ZERO_STRUCT(**auth_info); + } + SAFE_FREE(*auth_info); +} + +/**************************************************************************** + Try to get a challange out of the various authenticaion modules. + It is up to the caller to free it. +****************************************************************************/ + +DATA_BLOB auth_get_challange(auth_authsupplied_info *auth_info) +{ + DATA_BLOB challange = data_blob(NULL, 0); + char *challange_set_by = NULL; + auth_methods *auth_method; + + if (auth_info->challange.length) { + DEBUG(5, ("auth_get_challange: returning previous challange (normal)\n")); + return data_blob(auth_info->challange.data, auth_info->challange.length); + } + + for (auth_method = auth_info->auth_method_list; auth_method; auth_method = auth_method->next) + { + if (auth_method->get_chal) { + DEBUG(5, ("auth_get_challange: getting challange from module %s\n", auth_method->name)); + if (challange_set_by) { + DEBUG(1, ("auth_get_challange: CONFIGURATION ERROR: authenticaion method %s has already specified a challange. Challange by %s ignored.\n", + challange_set_by, auth_method->name)); + } else { + challange = auth_method->get_chal(&auth_method->private_data, auth_info); + if (challange.length) { + DEBUG(5, ("auth_get_challange: sucessfully got challange from module %s\n", auth_method->name)); + auth_info->challange = challange; + challange_set_by = auth_method->name; + auth_info->challange_set_method = auth_method; + } else { + DEBUG(3, ("auth_get_challange: getting challange from authenticaion method %s FAILED.\n", + auth_method->name)); + } + } + } else { + DEBUG(5, ("auth_get_challange: module %s did not want to specify a challange\n", auth_method->name)); + } + } + + if (!challange_set_by) { + uchar chal[8]; + + generate_random_buffer(chal, sizeof(chal), False); + auth_info->challange = data_blob(chal, sizeof(chal)); + + challange_set_by = "random"; + } + + DEBUG(5, ("auth_info challange created by %s\n", challange_set_by)); + DEBUG(5, ("challange is: \n")); + dump_data(5, auth_info->challange.data, (auth_info)->challange.length); + + SMB_ASSERT(auth_info->challange.length == 8); + + auth_info->challange_set_by=challange_set_by; + + return data_blob(auth_info->challange.data, auth_info->challange.length); +} + + diff --git a/source3/smbd/auth_rhosts.c b/source3/smbd/auth_rhosts.c index 9c07e48a9b..2605f0770a 100644 --- a/source3/smbd/auth_rhosts.c +++ b/source3/smbd/auth_rhosts.c @@ -135,7 +135,6 @@ check for a possible hosts equiv or rhosts entry for the user static BOOL check_hosts_equiv(struct passwd *pass) { char *fname = NULL; - pstring rhostsfile; if (!pass) return(False); @@ -148,39 +147,82 @@ static BOOL check_hosts_equiv(struct passwd *pass) return(True); } - if (lp_use_rhosts()) - { - char *home = pass->pw_dir; - if (home) { - slprintf(rhostsfile, sizeof(rhostsfile)-1, "%s/.rhosts", home); - if (check_user_equiv(pass->pw_name,client_name(),rhostsfile)) - return(True); - } - } - return(False); } + /**************************************************************************** Check for a valid .rhosts/hosts.equiv entry for this user ****************************************************************************/ -NTSTATUS check_rhosts_security(const auth_usersupplied_info *user_info, - auth_serversupplied_info **server_info) +static NTSTATUS check_hostsequiv_security(void *my_private_data, + const auth_usersupplied_info *user_info, + const auth_authsupplied_info *auth_info, + auth_serversupplied_info **server_info) { NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE; struct passwd *pass = Get_Pwnam(user_info->internal_username.str); if (pass) { - become_root(); if (check_hosts_equiv(pass)) { nt_status = NT_STATUS_OK; make_server_info_pw(server_info, pass); } - unbecome_root(); } else { nt_status = NT_STATUS_NO_SUCH_USER; } return nt_status; } + + +/**************************************************************************** + Check for a valid .rhosts/hosts.equiv entry for this user +****************************************************************************/ + +static NTSTATUS check_rhosts_security(void *my_private_data, + const auth_usersupplied_info *user_info, + const auth_authsupplied_info *auth_info, + auth_serversupplied_info **server_info) +{ + NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE; + struct passwd *pass = Get_Pwnam(user_info->internal_username.str); + pstring rhostsfile; + + if (pass) { + char *home = pass->pw_dir; + if (home) { + slprintf(rhostsfile, sizeof(rhostsfile)-1, "%s/.rhosts", home); + become_root(); + if (check_user_equiv(pass->pw_name,client_name(),rhostsfile)) { + nt_status = NT_STATUS_OK; + make_server_info_pw(server_info, pass); + } + unbecome_root(); + } + } else { + nt_status = NT_STATUS_NO_SUCH_USER; + } + + return nt_status; +} + +BOOL auth_init_hostsequiv(auth_methods **auth_method) +{ + + if (!make_auth_methods(auth_method)) { + return False; + } + (*auth_method)->auth = check_hostsequiv_security; + return True; +} + +BOOL auth_init_rhosts(auth_methods **auth_method) +{ + + if (!make_auth_methods(auth_method)) { + return False; + } + (*auth_method)->auth = check_rhosts_security; + return True; +} diff --git a/source3/smbd/auth_server.c b/source3/smbd/auth_server.c index ddbc284d50..067b5b2997 100644 --- a/source3/smbd/auth_server.c +++ b/source3/smbd/auth_server.c @@ -25,30 +25,18 @@ extern pstring global_myname; /**************************************************************************** - Return the client state structure. -****************************************************************************/ - -struct cli_state *server_client(void) -{ - static struct cli_state pw_cli; - return &pw_cli; -} - -/**************************************************************************** Support for server level security. ****************************************************************************/ -struct cli_state *server_cryptkey(void) +static struct cli_state *server_cryptkey(void) { - struct cli_state *cli; + struct cli_state *cli = NULL; fstring desthost; struct in_addr dest_ip; char *p, *pserver; BOOL connected_ok = False; - cli = server_client(); - - if (!cli_initialise(cli)) + if (!(cli = cli_initialise(cli))) return NULL; /* security = server just can't function with spnego */ @@ -88,7 +76,11 @@ struct cli_state *server_cryptkey(void) if (!attempt_netbios_session_request(cli, global_myname, desthost, &dest_ip)) return NULL; - + + if (strequal(desthost,myhostname())) { + exit_server("Password server loop!"); + } + DEBUG(3,("got session\n")); if (!cli_negprot(cli)) { @@ -109,13 +101,82 @@ struct cli_state *server_cryptkey(void) return cli; } +/**************************************************************************** + Clean up our allocated cli. +****************************************************************************/ + +static void free_server_private_data(void **private_data_pointer) +{ + struct cli_state **cli = (struct cli_state **)private_data_pointer; + if (*cli && (*cli)->initialised) { + cli_shutdown(*cli); + + SAFE_FREE(*cli); + } +} + +/**************************************************************************** + Send a 'keepalive' packet down the cli pipe. +****************************************************************************/ + +static void send_server_keepalive(void **private_data_pointer) +{ + struct cli_state **cli = (struct cli_state **)private_data_pointer; + + /* also send a keepalive to the password server if its still + connected */ + if (cli && *cli && (*cli)->initialised) { + if (!send_keepalive((*cli)->fd)) { + DEBUG( 2, ( "password server keepalive failed.\n")); + cli_shutdown(*cli); + SAFE_FREE(*cli); + } + } +} + +/**************************************************************************** + Get the challange out of a password server. +****************************************************************************/ + +static DATA_BLOB auth_get_challange_server(void **my_private_data, const struct authsupplied_info *auth_info) +{ + struct cli_state *cli = server_cryptkey(); + + if (cli) { + DEBUG(3,("using password server validation\n")); + if ((cli->sec_mode & 2) == 0) { + /* We can't work with unencrypted password servers + unless 'encrypt passwords = no' */ + DEBUG(5,("make_auth_info_server: Server is unencrypted, no challange available..\n")); + + *my_private_data = (void *)cli; + return data_blob(NULL, 0); + + } else if (cli->secblob.length < 8) { + /* We can't do much if we don't get a full challange */ + DEBUG(2,("make_auth_info_server: Didn't receive a full challange from server\n")); + cli_shutdown(cli); + return data_blob(NULL, 0); + } + + *my_private_data = (void *)cli; + + return data_blob(cli->secblob.data,8); + } else { + return data_blob(NULL, 0); + } +} + /**************************************************************************** Check for a valid username and password in security=server mode. - Validate a password with the password server. ****************************************************************************/ -NTSTATUS check_server_security(const auth_usersupplied_info *user_info, auth_serversupplied_info **server_info) +static NTSTATUS check_smbserver_security(void *my_private_data, + const auth_usersupplied_info *user_info, + const auth_authsupplied_info *auth_info, + auth_serversupplied_info **server_info) { struct cli_state *cli; static unsigned char badpass[24]; @@ -123,13 +184,32 @@ NTSTATUS check_server_security(const auth_usersupplied_info *user_info, auth_ser static BOOL tested_password_server = False; static BOOL bad_password_server = False; NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE; + BOOL locally_made_cli = False; - cli = server_client(); + cli = my_private_data; + + if (cli) { + } else { + cli = server_cryptkey(); + locally_made_cli = True; + } - if (!cli->initialised) { + if (!cli || !cli->initialised) { DEBUG(1,("password server %s is not connected\n", cli->desthost)); - return(NT_STATUS_LOGON_FAILURE); + return NT_STATUS_LOGON_FAILURE; } + + if ((cli->sec_mode & 2) == 0) { + if (user_info->encrypted) { + DEBUG(1,("password server %s is plaintext, but we are encrypted. This just can't work :-(\n", cli->desthost)); + return NT_STATUS_LOGON_FAILURE; + } + } else { + if (memcmp(cli->secblob.data, auth_info->challange.data, 8) != 0) { + DEBUG(1,("the challange that the password server (%s) supplied us is not the one we gave our client. This just can't work :-(\n", cli->desthost)); + return NT_STATUS_LOGON_FAILURE; + } + } if(badpass[0] == 0) memset(badpass, 0x1f, sizeof(badpass)); @@ -206,17 +286,32 @@ use this machine as the password server.\n")); * not guest enabled, we can try with the real password. */ - if (!cli_session_setup(cli, user_info->smb_name.str, - (char *)user_info->lm_resp.data, - user_info->lm_resp.length, - (char *)user_info->nt_resp.data, - user_info->nt_resp.length, - user_info->domain.str)) { - DEBUG(1,("password server %s rejected the password\n", cli->desthost)); - /* Make this cli_nt_error() when the conversion is in */ - nt_status = cli_nt_error(cli); + if (!user_info->encrypted) { + /* Plaintext available */ + if (!cli_session_setup(cli, user_info->smb_name.str, + (char *)user_info->plaintext_password.data, + user_info->plaintext_password.length, + NULL, 0, + user_info->domain.str)) { + DEBUG(1,("password server %s rejected the password\n", cli->desthost)); + /* Make this cli_nt_error() when the conversion is in */ + nt_status = cli_nt_error(cli); + } else { + nt_status = NT_STATUS_OK; + } } else { - nt_status = NT_STATUS_OK; + if (!cli_session_setup(cli, user_info->smb_name.str, + (char *)user_info->lm_resp.data, + user_info->lm_resp.length, + (char *)user_info->nt_resp.data, + user_info->nt_resp.length, + user_info->domain.str)) { + DEBUG(1,("password server %s rejected the password\n", cli->desthost)); + /* Make this cli_nt_error() when the conversion is in */ + nt_status = cli_nt_error(cli); + } else { + nt_status = NT_STATUS_OK; + } } /* if logged in as guest then reject */ @@ -238,5 +333,22 @@ use this machine as the password server.\n")); } } + if (locally_made_cli) { + cli_shutdown(cli); + SAFE_FREE(cli); + } + return(nt_status); } + +BOOL auth_init_smbserver(auth_methods **auth_method) +{ + if (!make_auth_methods(auth_method)) { + return False; + } + (*auth_method)->auth = check_smbserver_security; + (*auth_method)->get_chal = auth_get_challange_server; + (*auth_method)->send_keepalive = send_server_keepalive; + (*auth_method)->free_private_data = free_server_private_data; + return True; +} diff --git a/source3/smbd/auth_smbpasswd.c b/source3/smbd/auth_smbpasswd.c index 70632fb5df..24a4d4e4e4 100644 --- a/source3/smbd/auth_smbpasswd.c +++ b/source3/smbd/auth_smbpasswd.c @@ -96,7 +96,7 @@ static BOOL smb_pwd_check_ntlmv2(const DATA_BLOB ntv2_response, if (ntv2_response.length < 16) { /* We MUST have more than 16 bytes, or the stuff below will go crazy... */ - DEBUG(0, ("smb_pwd_check_ntlmv1: incorrect password length (%d)\n", + DEBUG(0, ("smb_pwd_check_ntlmv2: incorrect password length (%d)\n", ntv2_response.length)); return False; } @@ -132,15 +132,16 @@ static BOOL smb_pwd_check_ntlmv2(const DATA_BLOB ntv2_response, Do a specific test for an smb password being correct, given a smb_password and the lanman and NT responses. ****************************************************************************/ -NTSTATUS sam_password_ok(SAM_ACCOUNT *sampass, const auth_usersupplied_info *user_info, uint8 user_sess_key[16]) +static NTSTATUS sam_password_ok(SAM_ACCOUNT *sampass, + const auth_usersupplied_info *user_info, + const auth_authsupplied_info *auth_info, + uint8 user_sess_key[16]) { + uint16 acct_ctrl; const uint8 *nt_pw, *lm_pw; - uint16 acct_ctrl = pdb_get_acct_ctrl(sampass); uint32 ntlmssp_flags; - if (!user_info || !sampass) - return NT_STATUS_LOGON_FAILURE; - + acct_ctrl = pdb_get_acct_ctrl(sampass); if (acct_ctrl & ACB_PWNOTREQ) { if (lp_null_passwords()) @@ -173,8 +174,8 @@ NTSTATUS sam_password_ok(SAM_ACCOUNT *sampass, const auth_usersupplied_info *use */ DEBUG(4,("smb_password_ok: Checking NTLMv2 password\n")); if (smb_pwd_check_ntlmv2( user_info->nt_resp, - nt_pw, - user_info->sec_blob, user_info->smb_name.str, + nt_pw, auth_info->challange, + user_info->smb_name.str, user_info->client_domain.str, user_sess_key)) { @@ -190,7 +191,7 @@ NTSTATUS sam_password_ok(SAM_ACCOUNT *sampass, const auth_usersupplied_info *use */ DEBUG(4,("smb_password_ok: Checking NT MD4 password\n")); if (smb_pwd_check_ntlmv1(user_info->nt_resp, - nt_pw, user_info->sec_blob, + nt_pw, auth_info->challange, user_sess_key)) { return NT_STATUS_OK; @@ -223,7 +224,7 @@ NTSTATUS sam_password_ok(SAM_ACCOUNT *sampass, const auth_usersupplied_info *use DEBUG(4,("smb_password_ok: Checking LM password\n")); if (smb_pwd_check_ntlmv1(user_info->lm_resp, - lm_pw, user_info->sec_blob, + lm_pw, auth_info->challange, user_sess_key)) { return NT_STATUS_OK; @@ -265,6 +266,24 @@ static NTSTATUS sam_account_ok(SAM_ACCOUNT *sampass, const auth_usersupplied_inf return NT_STATUS_ACCOUNT_EXPIRED; } + if (!(pdb_get_acct_ctrl(sampass) & ACB_PWNOEXP)) { + time_t must_change_time = pdb_get_pass_must_change_time(sampass); + time_t last_set_time = pdb_get_pass_last_set_time(sampass); + + /* check for immediate expiry "must change at next logon" */ + if (must_change_time == 0 && last_set_time != 0) { + DEBUG(1,("Account for user '%s' password must change!.\n", pdb_get_username(sampass))); + return NT_STATUS_PASSWORD_MUST_CHANGE; + } + + /* check for expired password */ + if (must_change_time < time(NULL) && must_change_time != 0) { + DEBUG(1,("Account for user '%s' password expired!.\n", pdb_get_username(sampass))); + DEBUG(1,("Password expired at '%s' (%ld) unix time.\n", http_timestring(must_change_time), (long)must_change_time)); + return NT_STATUS_PASSWORD_EXPIRED; + } + } + /* Test workstation. Workstation list is comma separated. */ workstation_list = strdup(pdb_get_workstations(sampass)); @@ -293,24 +312,6 @@ static NTSTATUS sam_account_ok(SAM_ACCOUNT *sampass, const auth_usersupplied_inf SAFE_FREE(workstation_list); } - if (!(pdb_get_acct_ctrl(sampass) & ACB_PWNOEXP)) { - time_t must_change_time = pdb_get_pass_must_change_time(sampass); - time_t last_set_time = pdb_get_pass_last_set_time(sampass); - - /* check for immediate expiry "must change at next logon" */ - if (must_change_time == 0 && last_set_time != 0) { - DEBUG(1,("Account for user '%s' password must change!.\n", pdb_get_username(sampass))); - return NT_STATUS_PASSWORD_MUST_CHANGE; - } - - /* check for expired password */ - if (must_change_time < time(NULL) && must_change_time != 0) { - DEBUG(1,("Account for user '%s' password expired!.\n", pdb_get_username(sampass))); - DEBUG(1,("Password expired at '%s' (%ld) unix time.\n", http_timestring(must_change_time), (long)must_change_time)); - return NT_STATUS_PASSWORD_EXPIRED; - } - } - if (acct_ctrl & ACB_DOMTRUST) { DEBUG(2,("session_trust_account: Domain trust account %s denied by server\n", pdb_get_username(sampass))); return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT; @@ -336,7 +337,10 @@ SMB hash supplied in the user_info structure return an NT_STATUS constant. ****************************************************************************/ -NTSTATUS check_smbpasswd_security(const auth_usersupplied_info *user_info, auth_serversupplied_info **server_info) +NTSTATUS check_sam_security(void *my_private_dat, + const auth_usersupplied_info *user_info, + const auth_authsupplied_info *auth_info, + auth_serversupplied_info **server_info) { SAM_ACCOUNT *sampass=NULL; BOOL ret; @@ -344,7 +348,7 @@ NTSTATUS check_smbpasswd_security(const auth_usersupplied_info *user_info, auth_ uint8 user_sess_key[16]; const uint8* lm_hash; - if (!user_info) { + if (!user_info || !auth_info) { return NT_STATUS_LOGON_FAILURE; } @@ -365,7 +369,7 @@ NTSTATUS check_smbpasswd_security(const auth_usersupplied_info *user_info, auth_ return NT_STATUS_NO_SUCH_USER; } - nt_status = sam_password_ok(sampass, user_info, user_sess_key); + nt_status = sam_password_ok(sampass, user_info, auth_info, user_sess_key); if (!NT_STATUS_IS_OK(nt_status)) { pdb_free_sam(&sampass); @@ -394,6 +398,15 @@ NTSTATUS check_smbpasswd_security(const auth_usersupplied_info *user_info, auth_ return nt_status; } +BOOL auth_init_sam(auth_methods **auth_method) +{ + if (!make_auth_methods(auth_method)) { + return False; + } + + (*auth_method)->auth = check_sam_security; + return True; +} diff --git a/source3/smbd/auth_unix.c b/source3/smbd/auth_unix.c index 8c4a520350..d134ce6909 100644 --- a/source3/smbd/auth_unix.c +++ b/source3/smbd/auth_unix.c @@ -82,7 +82,10 @@ check if a username/password is OK assuming the password in PLAIN TEXT ****************************************************************************/ -NTSTATUS check_unix_security(const auth_usersupplied_info *user_info, auth_serversupplied_info **server_info) +NTSTATUS check_unix_security(void *my_private_data, + const auth_usersupplied_info *user_info, + const auth_authsupplied_info *auth_info, + auth_serversupplied_info **server_info) { NTSTATUS nt_status; struct passwd *pass = NULL; @@ -104,9 +107,19 @@ NTSTATUS check_unix_security(const auth_usersupplied_info *user_info, auth_serve if (pass) { make_server_info_pw(server_info, pass); } else { + /* we need to do somthing more useful here */ nt_status = NT_STATUS_NO_SUCH_USER; } } return nt_status; } + +BOOL auth_init_unix(auth_methods **auth_method) +{ + if (!make_auth_methods(auth_method)) { + return False; + } + (*auth_method)->auth = check_unix_security; + return True; +} diff --git a/source3/smbd/auth_util.c b/source3/smbd/auth_util.c index 25e0830fc7..d1b2cc92e5 100644 --- a/source3/smbd/auth_util.c +++ b/source3/smbd/auth_util.c @@ -23,49 +23,9 @@ #include "includes.h" -/* Data to do lanman1/2 password challenge. */ -static unsigned char saved_challenge[8]; -static BOOL challenge_sent=False; extern fstring remote_machine; extern pstring global_myname; -/******************************************************************* - Get the next challenge value - no repeats. -********************************************************************/ - -void generate_next_challenge(char *challenge) -{ - unsigned char buf[8]; - - generate_random_buffer(buf,8,False); - memcpy(saved_challenge, buf, 8); - memcpy(challenge,buf,8); - challenge_sent = True; -} - -/******************************************************************* - Set the last challenge sent, usually from a password server. -********************************************************************/ - -BOOL set_challenge(unsigned char *challenge) -{ - memcpy(saved_challenge,challenge,8); - challenge_sent = True; - return(True); -} - -/******************************************************************* - Get the last challenge sent. -********************************************************************/ - -BOOL last_challenge(unsigned char *challenge) -{ - if (!challenge_sent) - return(False); - memcpy(challenge,saved_challenge,8); - return(True); -} - /**************************************************************************** Create a UNIX user on demand. ****************************************************************************/ @@ -166,7 +126,6 @@ static BOOL make_user_info(auth_usersupplied_info **user_info, const char *client_domain, const char *domain, const char *wksta_name, - DATA_BLOB sec_blob, DATA_BLOB lm_pwd, DATA_BLOB nt_pwd, DATA_BLOB plaintext, uint32 ntlmssp_flags, BOOL encrypted) @@ -226,7 +185,6 @@ static BOOL make_user_info(auth_usersupplied_info **user_info, DEBUG(5,("makeing blobs for %s's user_info struct\n", internal_username)); - (*user_info)->sec_blob = data_blob(sec_blob.data, sec_blob.length); (*user_info)->lm_resp = data_blob(lm_pwd.data, lm_pwd.length); (*user_info)->nt_resp = data_blob(nt_pwd.data, nt_pwd.length); (*user_info)->plaintext_password = data_blob(plaintext.data, plaintext.length); @@ -246,7 +204,7 @@ static BOOL make_user_info(auth_usersupplied_info **user_info, BOOL make_user_info_map(auth_usersupplied_info **user_info, const char *smb_name, const char *client_domain, - const char *wksta_name, DATA_BLOB sec_blob, + const char *wksta_name, DATA_BLOB lm_pwd, DATA_BLOB nt_pwd, DATA_BLOB plaintext, uint32 ntlmssp_flags, BOOL encrypted) @@ -265,7 +223,7 @@ BOOL make_user_info_map(auth_usersupplied_info **user_info, return make_user_info(user_info, smb_name, internal_username, client_domain, domain, - wksta_name, sec_blob, + wksta_name, lm_pwd, nt_pwd, plaintext, ntlmssp_flags, encrypted); @@ -280,12 +238,11 @@ BOOL make_user_info_map(auth_usersupplied_info **user_info, BOOL make_user_info_netlogon_network(auth_usersupplied_info **user_info, char *smb_name, char *client_domain, - char *wksta_name, uchar chal[8], + char *wksta_name, uchar *lm_network_pwd, int lm_pwd_len, uchar *nt_network_pwd, int nt_pwd_len) { BOOL ret; - DATA_BLOB sec_blob = data_blob(chal, sizeof(chal)); DATA_BLOB lm_blob = data_blob(lm_network_pwd, lm_pwd_len); DATA_BLOB nt_blob = data_blob(nt_network_pwd, nt_pwd_len); DATA_BLOB plaintext_blob = data_blob(NULL, 0); @@ -301,8 +258,8 @@ BOOL make_user_info_netlogon_network(auth_usersupplied_info **user_info, ret = make_user_info_map(user_info, smb_name, client_domain, - wksta_name, sec_blob, - nt_blob, lm_blob, + wksta_name, + lm_blob, nt_blob, plaintext_blob, ntlmssp_flags, True); @@ -320,6 +277,7 @@ BOOL make_user_info_netlogon_interactive(auth_usersupplied_info **user_info, char *smb_name, char *client_domain, char *wksta_name, + char chal[8], uchar lm_interactive_pwd[16], uchar nt_interactive_pwd[16], uchar *dc_sess_key) @@ -329,11 +287,8 @@ BOOL make_user_info_netlogon_interactive(auth_usersupplied_info **user_info, unsigned char local_lm_response[24]; unsigned char local_nt_response[24]; unsigned char key[16]; - uint8 chal[8]; uint32 ntlmssp_flags = 0; - generate_random_buffer(chal, 8, False); - ZERO_STRUCT(key); memcpy(key, dc_sess_key, 8); @@ -362,7 +317,6 @@ BOOL make_user_info_netlogon_interactive(auth_usersupplied_info **user_info, dump_data(100, nt_pwd, sizeof(nt_pwd)); #endif - generate_random_buffer(chal, 8, False); SMBOWFencrypt((const unsigned char *)lm_pwd, chal, local_lm_response); SMBOWFencrypt((const unsigned char *)nt_pwd, chal, local_nt_response); @@ -373,7 +327,6 @@ BOOL make_user_info_netlogon_interactive(auth_usersupplied_info **user_info, { BOOL ret; - DATA_BLOB sec_blob = data_blob(chal, sizeof(chal)); DATA_BLOB local_lm_blob = data_blob(local_lm_response, sizeof(local_lm_response)); DATA_BLOB local_nt_blob = data_blob(local_nt_response, sizeof(local_nt_response)); DATA_BLOB plaintext_blob = data_blob(NULL, 0); @@ -385,7 +338,7 @@ BOOL make_user_info_netlogon_interactive(auth_usersupplied_info **user_info, ret = make_user_info_map(user_info, smb_name, client_domain, - wksta_name, sec_blob, + wksta_name, local_lm_blob, local_nt_blob, plaintext_blob, @@ -402,13 +355,14 @@ BOOL make_user_info_netlogon_interactive(auth_usersupplied_info **user_info, ****************************************************************************/ BOOL make_user_info_winbind(auth_usersupplied_info **user_info, - char *username, - char *domain, - char *password) + const char *username, + const char *domain, + const char *password, + char chal[8] /* Give winbind back the challange we used */ + ) { unsigned char local_lm_response[24]; unsigned char local_nt_response[24]; - char chal[8]; DATA_BLOB local_lm_blob; DATA_BLOB local_nt_blob; DATA_BLOB plaintext_blob; @@ -453,16 +407,11 @@ BOOL make_user_info_winbind(auth_usersupplied_info **user_info, { BOOL ret; - DATA_BLOB sec_blob = data_blob(chal, sizeof(chal)); - - if (!sec_blob.data) { - return False; - } ret = make_user_info(user_info, username, username, domain, domain, - global_myname, sec_blob, + global_myname, local_nt_blob, local_lm_blob, plaintext_blob, @@ -483,12 +432,10 @@ BOOL make_user_info_winbind(auth_usersupplied_info **user_info, BOOL make_user_info_winbind_crap(auth_usersupplied_info **user_info, char *smb_name, char *client_domain, - uchar chal[8], uchar *lm_network_pwd, int lm_pwd_len, uchar *nt_network_pwd, int nt_pwd_len) { BOOL ret; - DATA_BLOB sec_blob = data_blob(chal, 8); DATA_BLOB lm_blob = data_blob(lm_network_pwd, lm_pwd_len); DATA_BLOB nt_blob = data_blob(nt_network_pwd, nt_pwd_len); DATA_BLOB plaintext_blob = data_blob(NULL, 0); @@ -502,7 +449,7 @@ BOOL make_user_info_winbind_crap(auth_usersupplied_info **user_info, ret = make_user_info(user_info, smb_name, smb_name, client_domain, client_domain, - global_myname, sec_blob, + global_myname, nt_blob, lm_blob, plaintext_blob, ntlmssp_flags, True); @@ -517,59 +464,30 @@ BOOL make_user_info_winbind_crap(auth_usersupplied_info **user_info, ****************************************************************************/ BOOL make_user_info_for_reply(auth_usersupplied_info **user_info, - char *smb_name, - char *client_domain, - DATA_BLOB lm_resp, DATA_BLOB nt_resp, - DATA_BLOB plaintext_password, - BOOL encrypted) + char *smb_name, + char *client_domain, + char chal[8], + DATA_BLOB plaintext_password) { - uchar chal[8]; DATA_BLOB local_lm_blob; DATA_BLOB local_nt_blob; - DATA_BLOB sec_blob; BOOL ret = False; uint32 ntlmssp_flags = 0; - if (encrypted) { - DATA_BLOB no_plaintext_blob = data_blob(NULL, 0); - if (!last_challenge(chal)) { - DEBUG(0,("Encrypted login but no challange set!\n")); - return False; - } - sec_blob = data_blob(chal, 8); - - if (lm_resp.length == 24) { - ntlmssp_flags |= NTLMSSP_NEGOTIATE_OEM; - } - if (nt_resp.length == 0) { - } else if (nt_resp.length == 24) { - ntlmssp_flags |= NTLMSSP_NEGOTIATE_NTLM; - } else { - ntlmssp_flags |= NTLMSSP_NEGOTIATE_NTLM2; - } - - return make_user_info_map(user_info, smb_name, - client_domain, - remote_machine, sec_blob, - lm_resp, - nt_resp, - no_plaintext_blob, - ntlmssp_flags, encrypted); - } - - generate_random_buffer(chal, 8, False); - - sec_blob = data_blob(chal, 8); - /* * Not encrypted - do so. */ - DEBUG(5,("pass_check_smb: User passwords not in encrypted format.\n")); + DEBUG(5,("make_user_info_for_reply: User passwords not in encrypted format.\n")); if (plaintext_password.data) { unsigned char local_lm_response[24]; + +#ifdef DEBUG_PASSWORD + DEBUG(10,("Unencrypted password (len %d):\n",plaintext_password.length)); + dump_data(100, plaintext_password.data, plaintext_password.length); +#endif SMBencrypt( (const uchar *)plaintext_password.data, chal, local_lm_response); local_lm_blob = data_blob(local_lm_response, 24); @@ -587,23 +505,54 @@ BOOL make_user_info_for_reply(auth_usersupplied_info **user_info, ret = make_user_info_map(user_info, smb_name, client_domain, remote_machine, - sec_blob, local_lm_blob, local_nt_blob, plaintext_password, - ntlmssp_flags, encrypted); + ntlmssp_flags, False); data_blob_free(&local_lm_blob); return ret; } /**************************************************************************** + Create an auth_usersupplied_data structure +****************************************************************************/ + +BOOL make_user_info_for_reply_enc(auth_usersupplied_info **user_info, + char *smb_name, + char *client_domain, + DATA_BLOB lm_resp, DATA_BLOB nt_resp, + DATA_BLOB plaintext_password) +{ + uint32 ntlmssp_flags = 0; + + DATA_BLOB no_plaintext_blob = data_blob(NULL, 0); + + if (lm_resp.length == 24) { + ntlmssp_flags |= NTLMSSP_NEGOTIATE_OEM; + } + if (nt_resp.length == 0) { + } else if (nt_resp.length == 24) { + ntlmssp_flags |= NTLMSSP_NEGOTIATE_NTLM; + } else { + ntlmssp_flags |= NTLMSSP_NEGOTIATE_NTLM2; + } + + return make_user_info_map(user_info, smb_name, + client_domain, + remote_machine, + lm_resp, + nt_resp, + no_plaintext_blob, + ntlmssp_flags, True); +} + +/**************************************************************************** Create a guest user_info blob, for anonymous authenticaion. ****************************************************************************/ BOOL make_user_info_guest(auth_usersupplied_info **user_info) { - DATA_BLOB sec_blob = data_blob(NULL, 0); DATA_BLOB lm_blob = data_blob(NULL, 0); DATA_BLOB nt_blob = data_blob(NULL, 0); DATA_BLOB plaintext_blob = data_blob(NULL, 0); @@ -612,7 +561,7 @@ BOOL make_user_info_guest(auth_usersupplied_info **user_info) return make_user_info(user_info, "","", "","", - "", sec_blob, + "", nt_blob, lm_blob, plaintext_blob, ntlmssp_flags, True); @@ -680,7 +629,6 @@ void free_user_info(auth_usersupplied_info **user_info) SAFE_FREE((*user_info)->internal_username.str); SAFE_FREE((*user_info)->client_domain.str); SAFE_FREE((*user_info)->domain.str); - data_blob_free(&(*user_info)->sec_blob); data_blob_free(&(*user_info)->lm_resp); data_blob_free(&(*user_info)->nt_resp); SAFE_FREE((*user_info)->interactive_password); @@ -725,6 +673,22 @@ BOOL make_server_info_guest(auth_serversupplied_info **server_info) return False; } +/*************************************************************************** + Make an auth_methods struct +***************************************************************************/ + +BOOL make_auth_methods(auth_methods **auth_method) +{ + *auth_method = malloc(sizeof(**auth_method)); + if (!*auth_method) { + DEBUG(0,("make_auth_method: malloc failed!\n")); + return False; + } + ZERO_STRUCTP(*auth_method); + + return True; +} + /**************************************************************************** Delete a SID token. ****************************************************************************/ @@ -764,25 +728,3 @@ NT_USER_TOKEN *dup_nt_token(NT_USER_TOKEN *ptoken) return token; } - -/**************************************************************************** - Check for a guest logon (username = "") and if so create the required - structure. -****************************************************************************/ - -NTSTATUS check_guest_security(const auth_usersupplied_info *user_info, - auth_serversupplied_info **server_info) -{ - NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE; - - if (!(user_info->internal_username.str - && *user_info->internal_username.str)) { - if (make_server_info_guest(server_info)) { - nt_status = NT_STATUS_OK; - } else { - nt_status = NT_STATUS_NO_SUCH_USER; - } - } - - return nt_status; -} diff --git a/source3/smbd/negprot.c b/source3/smbd/negprot.c index 045e16a9bb..d080c23332 100644 --- a/source3/smbd/negprot.c +++ b/source3/smbd/negprot.c @@ -27,6 +27,7 @@ extern fstring global_myworkgroup; extern fstring remote_machine; BOOL global_encrypted_passwords_negotiated = False; BOOL global_spnego_negotiated = False; +auth_authsupplied_info *negprot_global_auth_info = NULL; /**************************************************************************** reply for the core protocol @@ -68,6 +69,7 @@ static int reply_lanman1(char *inbuf, char *outbuf) int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0); int secword=0; time_t t = time(NULL); + DATA_BLOB cryptkey; global_encrypted_passwords_negotiated = lp_encrypted_passwords(); @@ -77,8 +79,14 @@ static int reply_lanman1(char *inbuf, char *outbuf) set_message(outbuf,13,global_encrypted_passwords_negotiated?8:0,True); SSVAL(outbuf,smb_vwv1,secword); /* Create a token value and add it to the outgoing packet. */ - if (global_encrypted_passwords_negotiated) - generate_next_challenge(smb_buf(outbuf)); + if (global_encrypted_passwords_negotiated) { + if (!make_auth_info_subsystem(&negprot_global_auth_info)) { + smb_panic("cannot make_negprot_global_auth_info!\n"); + } + cryptkey = auth_get_challange(negprot_global_auth_info); + memcpy(smb_buf(outbuf), cryptkey.data, 8); + data_blob_free(&cryptkey); + } Protocol = PROTOCOL_LANMAN1; @@ -106,40 +114,26 @@ static int reply_lanman2(char *inbuf, char *outbuf) int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0); int secword=0; time_t t = time(NULL); - struct cli_state *cli = NULL; - char cryptkey[8]; - char crypt_len = 0; + DATA_BLOB cryptkey; global_encrypted_passwords_negotiated = lp_encrypted_passwords(); - - if (lp_security() == SEC_SERVER) { - cli = server_cryptkey(); - } - - if (cli) { - DEBUG(3,("using password server validation\n")); - global_encrypted_passwords_negotiated = ((cli->sec_mode & 2) != 0); - } - + if (lp_security()>=SEC_USER) secword |= 1; if (global_encrypted_passwords_negotiated) secword |= 2; + set_message(outbuf,13,global_encrypted_passwords_negotiated?8:0,True); + SSVAL(outbuf,smb_vwv1,secword); + SIVAL(outbuf,smb_vwv6,sys_getpid()); + if (global_encrypted_passwords_negotiated) { - crypt_len = 8; - if (!cli) { - generate_next_challenge(cryptkey); - } else { - memcpy(cryptkey, cli->secblob.data, 8); - set_challenge((unsigned char *)cryptkey); + if (!make_auth_info_subsystem(&negprot_global_auth_info)) { + smb_panic("cannot make_negprot_global_auth_info!\n"); } + cryptkey = auth_get_challange(negprot_global_auth_info); + memcpy(smb_buf(outbuf), cryptkey.data, 8); + data_blob_free(&cryptkey); } - set_message(outbuf,13,crypt_len,True); - SSVAL(outbuf,smb_vwv1,secword); - SIVAL(outbuf,smb_vwv6,sys_getpid()); - if (global_encrypted_passwords_negotiated) - memcpy(smb_buf(outbuf), cryptkey, 8); - Protocol = PROTOCOL_LANMAN2; /* Reply, SMBlockread, SMBwritelock supported. */ @@ -202,45 +196,22 @@ static int reply_nt1(char *inbuf, char *outbuf) int secword=0; time_t t = time(NULL); - struct cli_state *cli = NULL; - uint8 cryptkey[8]; + DATA_BLOB cryptkey; char *p, *q; BOOL negotiate_spnego = False; global_encrypted_passwords_negotiated = lp_encrypted_passwords(); - if (lp_security() == SEC_SERVER) { - DEBUG(5,("attempting password server validation\n")); - cli = server_cryptkey(); - } else { - DEBUG(5,("not attempting password server validation\n")); - /* do spnego in user level security if the client - supports it and we can do encrypted passwords */ - if (global_encrypted_passwords_negotiated && - (lp_security() == SEC_USER || - lp_security() == SEC_DOMAIN) && - (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) { - negotiate_spnego = True; - capabilities |= CAP_EXTENDED_SECURITY; - } - } + /* do spnego in user level security if the client + supports it and we can do encrypted passwords */ - if (cli) { - DEBUG(3,("using password server validation\n")); - global_encrypted_passwords_negotiated = ((cli->sec_mode & 2) != 0); - } else { - DEBUG(3,("not using password server validation\n")); + if (global_encrypted_passwords_negotiated && + (lp_security() != SEC_SHARE) && + (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) { + negotiate_spnego = True; + capabilities |= CAP_EXTENDED_SECURITY; } - if (global_encrypted_passwords_negotiated) { - if (!cli) { - generate_next_challenge((char *)cryptkey); - } else { - memcpy(cryptkey, cli->secblob.data, 8); - set_challenge(cryptkey); - } - } - capabilities |= CAP_NT_SMBS|CAP_RPC_REMOTE_APIS; if (lp_large_readwrite() && (SMB_OFF_T_BITS == 64)) { @@ -283,7 +254,14 @@ static int reply_nt1(char *inbuf, char *outbuf) p = q = smb_buf(outbuf); if (!negotiate_spnego) { - if (global_encrypted_passwords_negotiated) memcpy(p, cryptkey, 8); + if (global_encrypted_passwords_negotiated) { + if (!make_auth_info_subsystem(&negprot_global_auth_info)) { + smb_panic("cannot make_negprot_global_auth_info!\n"); + } + cryptkey = auth_get_challange(negprot_global_auth_info); + memcpy(p, cryptkey.data, 8); + data_blob_free(&cryptkey); + } SSVALS(outbuf,smb_vwv16+1,8); p += 8; DEBUG(3,("not using SPNEGO\n")); @@ -467,11 +445,6 @@ int reply_negprot(connection_struct *conn, /* possibly reload - change of architecture */ reload_services(True); - /* a special case to stop password server loops */ - if (Index == 1 && strequal(remote_machine,myhostname()) && - (lp_security()==SEC_SERVER || lp_security()==SEC_DOMAIN)) - exit_server("Password server loop!"); - /* Check for protocols, most desirable first */ for (protocol = 0; supported_protocols[protocol].proto_name; protocol++) { @@ -508,3 +481,4 @@ int reply_negprot(connection_struct *conn, END_PROFILE(SMBnegprot); return(outsize); } + diff --git a/source3/smbd/process.c b/source3/smbd/process.c index b020cdd5d7..d9322ae26c 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -1112,19 +1112,23 @@ static BOOL timeout_processing(int deadtime, int *select_timeout, time_t *last_t if (keepalive && (t - last_keepalive_sent_time)>keepalive) { - struct cli_state *cli = server_client(); - if (!send_keepalive(smbd_server_fd())) { - DEBUG( 2, ( "Keepalive failed - exiting.\n" ) ); - return False; - } - /* also send a keepalive to the password server if its still - connected */ - if (cli && cli->initialised) - if (!send_keepalive(cli->fd)) { - DEBUG( 2, ( "password server keepalive failed.\n")); - cli_shutdown(cli); - } - last_keepalive_sent_time = t; + extern auth_authsupplied_info *negprot_global_auth_info; + if (!send_keepalive(smbd_server_fd())) { + DEBUG( 2, ( "Keepalive failed - exiting.\n" ) ); + return False; + } + + /* send a keepalive for a password server or the like. + This is attached to the auth_info created in the + negprot */ + if (negprot_global_auth_info + && negprot_global_auth_info->challange_set_method + && negprot_global_auth_info->challange_set_method->send_keepalive) { + negprot_global_auth_info->challange_set_method->send_keepalive + (&negprot_global_auth_info->challange_set_method->private_data); + } + + last_keepalive_sent_time = t; } /* check for connection timeouts */ diff --git a/source3/smbd/server.c b/source3/smbd/server.c index b08c8e8bda..2f374e48aa 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -476,7 +476,7 @@ void exit_server(char *reason) { static int firsttime=1; extern char *last_inbuf; - + extern auth_authsupplied_info *negprot_global_auth_info; if (!firsttime) exit(0); @@ -485,6 +485,8 @@ void exit_server(char *reason) change_to_root_user(); DEBUG(2,("Closing connections\n")); + free_auth_info(&negprot_global_auth_info); + conn_close_all(); invalidate_all_vuids(); diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c index b3e9b7be8f..c9db359569 100644 --- a/source3/smbd/sesssetup.c +++ b/source3/smbd/sesssetup.c @@ -23,6 +23,7 @@ #include "includes.h" uint32 global_client_caps = 0; +static auth_authsupplied_info *ntlmssp_auth_info; /**************************************************************************** Add the standard 'Samba' signature to the end of the session setup. @@ -37,6 +38,31 @@ static void add_signature(char *outbuf) set_message_end(outbuf,p); } +/**************************************************************************** + Do a 'guest' logon, getting back the +****************************************************************************/ +static NTSTATUS check_guest_password(auth_serversupplied_info **server_info) +{ + + auth_authsupplied_info *auth_info; + auth_usersupplied_info *user_info = NULL; + + NTSTATUS nt_status; + char chal[8]; + + ZERO_STRUCT(chal); + + DEBUG(3,("Got anonymous request\n")); + + make_user_info_guest(&user_info); + make_auth_info_fixed(&auth_info, chal); + + nt_status = check_password(user_info, auth_info, server_info); + free_auth_info(&auth_info); + return nt_status; +} + + #if HAVE_KRB5 /**************************************************************************** reply to a session setup spnego negotiate packet for kerberos @@ -189,7 +215,7 @@ static int reply_spnego_negotiate(connection_struct *conn, int i; uint32 ntlmssp_command, neg_flags; DATA_BLOB sess_key, chal, spnego_chal; - uint8 cryptkey[8]; + DATA_BLOB cryptkey; BOOL got_kerberos = False; /* parse out the OIDs and the first sec blob */ @@ -238,10 +264,12 @@ static int reply_spnego_negotiate(connection_struct *conn, DEBUG(3,("Got neg_flags=%08x\n", neg_flags)); - if (!last_challenge(cryptkey)) { - return ERROR_NT(NT_STATUS_LOGON_FAILURE); + if (!make_auth_info_subsystem(&ntlmssp_auth_info)) { + return ERROR_NT(NT_STATUS_NO_MEMORY); } + cryptkey = auth_get_challange(ntlmssp_auth_info); + /* Give them the challenge. For now, ignore neg_flags and just return the flags we want. Obviously this is not correct */ @@ -255,7 +283,7 @@ static int reply_spnego_negotiate(connection_struct *conn, 0, 0x30, /* ?? */ neg_flags, - cryptkey, 8, + cryptkey.data, cryptkey.length, 0, 0, 0, 0x3000); /* ?? */ @@ -268,6 +296,7 @@ static int reply_spnego_negotiate(connection_struct *conn, reply_sesssetup_blob(conn, outbuf, spnego_chal); data_blob_free(&chal); + data_blob_free(&cryptkey); data_blob_free(&spnego_chal); /* and tell smbd that we have already replied to this packet */ @@ -286,11 +315,9 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf, char *workgroup, *user, *machine; DATA_BLOB lmhash, nthash, sess_key; DATA_BLOB plaintext_password = data_blob(NULL, 0); - DATA_BLOB sec_blob; uint32 ntlmssp_command, neg_flags; NTSTATUS nt_status; int sess_vuid; - char chal[8]; auth_usersupplied_info *user_info = NULL; auth_serversupplied_info *server_info = NULL; @@ -327,26 +354,19 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf, file_save("lmhash1.dat", lmhash.data, lmhash.length); #endif - if (!last_challenge(chal)) { - DEBUG(0,("Encrypted login but no challange set!\n")); - return ERROR_NT(NT_STATUS_LOGON_FAILURE); - } - sec_blob = data_blob(chal, 8); - if (!sec_blob.data) { - return ERROR_NT(NT_STATUS_NO_MEMORY); - } - if (!make_user_info_map(&user_info, user, workgroup, - machine, sec_blob, + machine, lmhash, nthash, plaintext_password, neg_flags, True)) { return ERROR_NT(NT_STATUS_NO_MEMORY); } - nt_status = check_password(user_info, &server_info); + nt_status = check_password(user_info, ntlmssp_auth_info, &server_info); + free_auth_info(&ntlmssp_auth_info); + free_user_info(&user_info); data_blob_free(&lmhash); @@ -383,18 +403,17 @@ static int reply_spnego_anonymous(connection_struct *conn, char *inbuf, char *ou int length, int bufsize) { int sess_vuid; - auth_usersupplied_info *user_info = NULL; auth_serversupplied_info *server_info = NULL; - NTSTATUS nt_status; - DEBUG(3,("Got anonymous request\n")); - - make_user_info_guest(&user_info); + nt_status = check_guest_password(&server_info); - nt_status = check_password(user_info, &server_info); + if (!NT_STATUS_IS_OK(nt_status)) { + return ERROR_NT(nt_status_squash(nt_status)); + } sess_vuid = register_vuid(server_info, lp_guestaccount()); + free_server_info(&server_info); if (sess_vuid == -1) { @@ -490,6 +509,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf, extern int max_send; auth_usersupplied_info *user_info = NULL; + extern auth_authsupplied_info *negprot_global_auth_info; auth_serversupplied_info *server_info = NULL; NTSTATUS nt_status; @@ -523,16 +543,12 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf, lm_resp = data_blob(smb_buf(inbuf), passlen1); } else { plaintext_password = data_blob(smb_buf(inbuf), passlen1+1); - if (!plaintext_password.data) { - DEBUG(0,("reply_sesssetup_and_X: malloc failed for plaintext_password!\n")); - return ERROR_NT(NT_STATUS_NO_MEMORY); - } else { - /* Ensure null termination */ - plaintext_password.data[passlen1] = 0; - } + /* Ensure null termination */ + plaintext_password.data[passlen1] = 0; } srvstr_pull(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), -1, STR_TERMINATE); + *domain = 0; } else { uint16 passlen1 = SVAL(inbuf,smb_vwv7); @@ -645,15 +661,41 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf, *user = 0; } - if (!make_user_info_for_reply(&user_info, - user, domain, - lm_resp, nt_resp, - plaintext_password, doencrypt)) { - return ERROR_NT(NT_STATUS_NO_MEMORY); + if (!*user) { + + nt_status = check_guest_password(&server_info); + + } else if (doencrypt) { + if (!make_user_info_for_reply_enc(&user_info, + user, domain, + lm_resp, nt_resp, + plaintext_password)) { + return ERROR_NT(NT_STATUS_NO_MEMORY); + } + + nt_status = check_password(user_info, negprot_global_auth_info, &server_info); + + } else { + auth_authsupplied_info *plaintext_auth_info = NULL; + DATA_BLOB chal; + if (!make_auth_info_subsystem(&plaintext_auth_info)) { + return ERROR_NT(NT_STATUS_NO_MEMORY); + } + + chal = auth_get_challange(plaintext_auth_info); + + if (!make_user_info_for_reply(&user_info, + user, domain, chal.data, + plaintext_password)) { + return ERROR_NT(NT_STATUS_NO_MEMORY); + } + + nt_status = check_password(user_info, plaintext_auth_info, &server_info); + + data_blob_free(&chal); + free_auth_info(&plaintext_auth_info); } - - nt_status = check_password(user_info, &server_info); - + free_user_info(&user_info); data_blob_free(&lm_resp); @@ -726,3 +768,8 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf, END_PROFILE(SMBsesssetupX); return chain_reply(inbuf,outbuf,length,bufsize); } + + + + + diff --git a/source3/utils/testparm.c b/source3/utils/testparm.c index c1b8b10a84..97dc0c014a 100644 --- a/source3/utils/testparm.c +++ b/source3/utils/testparm.c @@ -92,12 +92,6 @@ to a valid password server.\n", sec_setting ); ret = 1; } - if(lp_use_rhosts() && !lp_hostname_lookups()) { - printf("ERROR: The setting 'use rhosts = yes' requires the 'hostname lookups = yes'.\n"); - ret = 1; - } - - /* * Password chat sanity checks. */ |