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
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
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.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
static struct cli_state *server_cryptkey(TALLOC_CTX *mem_ctx)
{
struct cli_state *cli = NULL;
- fstring desthost;
- struct in_addr dest_ip;
+ char *desthost = NULL;
+ struct sockaddr_storage dest_ss;
const char *p;
- char *pserver;
- BOOL connected_ok = False;
+ char *pserver = NULL;
+ bool connected_ok = False;
+ struct named_mutex *mutex = NULL;
- if (!(cli = cli_initialise(cli)))
+ if (!(cli = cli_initialise()))
return NULL;
/* security = server just can't function with spnego */
pserver = talloc_strdup(mem_ctx, lp_passwordserver());
p = pserver;
- while(next_token( &p, desthost, LIST_SEP, sizeof(desthost))) {
- standard_sub_basic(current_user_info.smb_name, desthost, sizeof(desthost));
+ while(next_token_talloc(mem_ctx, &p, &desthost, LIST_SEP)) {
+ NTSTATUS status;
+
+ desthost = talloc_sub_basic(mem_ctx,
+ current_user_info.smb_name,
+ current_user_info.domain,
+ desthost);
+ if (!desthost) {
+ return NULL;
+ }
strupper_m(desthost);
- if(!resolve_name( desthost, &dest_ip, 0x20)) {
+ if(!resolve_name( desthost, &dest_ss, 0x20)) {
DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",desthost));
continue;
}
- if (ismyip(dest_ip)) {
+ if (ismyaddr((struct sockaddr *)&dest_ss)) {
DEBUG(1,("Password server loop - disabling password server %s\n",desthost));
continue;
}
- /* we use a mutex to prevent two connections at once - when a
- Win2k PDC get two connections where one hasn't completed a
- session setup yet it will send a TCP reset to the first
+ /* we use a mutex to prevent two connections at once - when a
+ Win2k PDC get two connections where one hasn't completed a
+ session setup yet it will send a TCP reset to the first
connection (tridge) */
- if (!grab_server_mutex(desthost)) {
+ mutex = grab_named_mutex(talloc_tos(), desthost, 10);
+ if (mutex == NULL) {
+ cli_shutdown(cli);
return NULL;
}
- if (cli_connect(cli, desthost, &dest_ip)) {
+ status = cli_connect(cli, desthost, &dest_ss);
+ if (NT_STATUS_IS_OK(status)) {
DEBUG(3,("connected to password server %s\n",desthost));
connected_ok = True;
break;
}
+ DEBUG(10,("server_cryptkey: failed to connect to server %s. Error %s\n",
+ desthost, nt_errstr(status) ));
+ TALLOC_FREE(mutex);
}
if (!connected_ok) {
- release_server_mutex();
DEBUG(0,("password server not available\n"));
cli_shutdown(cli);
return NULL;
}
-
- if (!attempt_netbios_session_request(cli, global_myname(),
- desthost, &dest_ip)) {
- release_server_mutex();
+
+ if (!attempt_netbios_session_request(&cli, global_myname(),
+ desthost, &dest_ss)) {
+ TALLOC_FREE(mutex);
DEBUG(1,("password server fails session request\n"));
cli_shutdown(cli);
return NULL;
}
-
+
if (strequal(desthost,myhostname())) {
- exit_server("Password server loop!");
+ exit_server_cleanly("Password server loop!");
}
-
+
DEBUG(3,("got session\n"));
if (!cli_negprot(cli)) {
+ TALLOC_FREE(mutex);
DEBUG(1,("%s rejected the negprot\n",desthost));
- release_server_mutex();
cli_shutdown(cli);
return NULL;
}
if (cli->protocol < PROTOCOL_LANMAN2 ||
!(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL)) {
+ TALLOC_FREE(mutex);
DEBUG(1,("%s isn't in user level security mode\n",desthost));
- release_server_mutex();
cli_shutdown(cli);
return NULL;
}
- /* Get the first session setup done quickly, to avoid silly
+ /* Get the first session setup done quickly, to avoid silly
Win2k bugs. (The next connection to the server will kill
- this one...
+ this one...
*/
- if (!cli_session_setup(cli, "", "", 0, "", 0,
- "")) {
+ if (!NT_STATUS_IS_OK(cli_session_setup(cli, "", "", 0, "", 0,
+ ""))) {
+ TALLOC_FREE(mutex);
DEBUG(0,("%s rejected the initial session setup (%s)\n",
desthost, cli_errstr(cli)));
- release_server_mutex();
cli_shutdown(cli);
return NULL;
}
-
- release_server_mutex();
-
+
+ TALLOC_FREE(mutex);
+
DEBUG(3,("password server OK\n"));
-
+
return cli;
}
+struct server_security_state {
+ struct cli_state *cli;
+};
+
/****************************************************************************
- Clean up our allocated cli.
+ Send a 'keepalive' packet down the cli pipe.
****************************************************************************/
-static void free_server_private_data(void **private_data_pointer)
+static bool send_server_keepalive(const struct timeval *now,
+ void *private_data)
{
- struct cli_state **cli = (struct cli_state **)private_data_pointer;
- if (*cli && (*cli)->initialised) {
- cli_shutdown(*cli);
+ struct server_security_state *state = talloc_get_type_abort(
+ private_data, struct server_security_state);
+
+ if (!state->cli || !state->cli->initialised) {
+ return False;
+ }
+
+ if (send_keepalive(state->cli->fd)) {
+ return True;
}
+
+ DEBUG( 2, ( "send_server_keepalive: password server keepalive "
+ "failed.\n"));
+ cli_shutdown(state->cli);
+ state->cli = NULL;
+ return False;
}
-/****************************************************************************
- Send a 'keepalive' packet down the cli pipe.
-****************************************************************************/
+static int destroy_server_security(struct server_security_state *state)
+{
+ if (state->cli) {
+ cli_shutdown(state->cli);
+ }
+ return 0;
+}
-static void send_server_keepalive(void **private_data_pointer)
+static struct server_security_state *make_server_security_state(struct cli_state *cli)
{
- /* also send a keepalive to the password server if its still
- connected */
- if (private_data_pointer) {
- struct cli_state *cli = (struct cli_state *)(*private_data_pointer);
- if (cli && cli->initialised) {
- if (!send_keepalive(cli->fd)) {
- DEBUG( 2, ( "send_server_keepalive: password server keepalive failed.\n"));
- cli_shutdown(cli);
- *private_data_pointer = NULL;
- }
+ struct server_security_state *result;
+
+ if (!(result = talloc(NULL, struct server_security_state))) {
+ DEBUG(0, ("talloc failed\n"));
+ cli_shutdown(cli);
+ return NULL;
+ }
+
+ result->cli = cli;
+ talloc_set_destructor(result, destroy_server_security);
+
+ if (lp_keepalive() != 0) {
+ struct timeval interval;
+ interval.tv_sec = lp_keepalive();
+ interval.tv_usec = 0;
+
+ if (event_add_idle(smbd_event_context(), result, interval,
+ "server_security_keepalive",
+ send_server_keepalive,
+ result) == NULL) {
+ DEBUG(0, ("event_add_idle failed\n"));
+ TALLOC_FREE(result);
+ return NULL;
}
}
+
+ return result;
}
/****************************************************************************
/* However, it is still a perfectly fine connection
to pass that unencrypted password over */
- *my_private_data = (void *)cli;
- return data_blob(NULL, 0);
-
+ *my_private_data =
+ (void *)make_server_security_state(cli);
+ return data_blob_null;
} else if (cli->secblob.length < 8) {
/* We can't do much if we don't get a full challenge */
DEBUG(2,("make_auth_info_server: Didn't receive a full challenge from server\n"));
cli_shutdown(cli);
- return data_blob(NULL, 0);
+ return data_blob_null;
}
- *my_private_data = (void *)cli;
+ if (!(*my_private_data = (void *)make_server_security_state(cli))) {
+ return data_blob(NULL,0);
+ }
/* The return must be allocated on the caller's mem_ctx, as our own will be
destoyed just after the call. */
return data_blob_talloc(auth_context->mem_ctx, cli->secblob.data,8);
} else {
- return data_blob(NULL, 0);
+ return data_blob_null;
}
}
const auth_usersupplied_info *user_info,
auth_serversupplied_info **server_info)
{
+ struct server_security_state *state = talloc_get_type_abort(
+ my_private_data, struct server_security_state);
struct cli_state *cli;
- static unsigned char badpass[24];
- static fstring baduser;
- static BOOL tested_password_server = False;
- static BOOL bad_password_server = False;
+ static bool tested_password_server = False;
+ static bool bad_password_server = False;
NTSTATUS nt_status = NT_STATUS_NOT_IMPLEMENTED;
- BOOL locally_made_cli = False;
-
- /*
- * Check that the requested domain is not our own machine name.
- * If it is, we should never check the PDC here, we use our own local
- * password file.
- */
+ bool locally_made_cli = False;
- if(is_myname(user_info->domain.str)) {
- DEBUG(3,("check_smbserver_security: Requested domain was for this machine.\n"));
- return nt_status;
- }
-
- cli = my_private_data;
+ cli = state->cli;
if (cli) {
} else {
}
if (!cli || !cli->initialised) {
- DEBUG(1,("password server is not connected (cli not initilised)\n"));
+ DEBUG(1,("password server is not connected (cli not initialised)\n"));
return NT_STATUS_LOGON_FAILURE;
}
}
}
- if(badpass[0] == 0)
- memset(badpass, 0x1f, sizeof(badpass));
-
- if((user_info->nt_resp.length == sizeof(badpass)) &&
- !memcmp(badpass, user_info->nt_resp.data, sizeof(badpass))) {
- /*
- * Very unlikely, our random bad password is the same as the users
- * password.
- */
- memset(badpass, badpass[0]+1, sizeof(badpass));
- }
-
- if(baduser[0] == 0) {
- fstrcpy(baduser, INVALID_USER_PREFIX);
- fstrcat(baduser, global_myname());
- }
-
/*
* Attempt a session setup with a totally incorrect password.
* If this succeeds with the guest bit *NOT* set then the password
*/
if ((!tested_password_server) && (lp_paranoid_server_security())) {
- if (cli_session_setup(cli, baduser, (char *)badpass, sizeof(badpass),
- (char *)badpass, sizeof(badpass), user_info->domain.str)) {
+ unsigned char badpass[24];
+ char *baduser = NULL;
+
+ memset(badpass, 0x1f, sizeof(badpass));
+
+ if((user_info->nt_resp.length == sizeof(badpass)) &&
+ !memcmp(badpass, user_info->nt_resp.data, sizeof(badpass))) {
+ /*
+ * Very unlikely, our random bad password is the same as the users
+ * password.
+ */
+ memset(badpass, badpass[0]+1, sizeof(badpass));
+ }
+
+ baduser = talloc_asprintf(mem_ctx,
+ "%s%s",
+ INVALID_USER_PREFIX,
+ global_myname());
+ if (!baduser) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (NT_STATUS_IS_OK(cli_session_setup(cli, baduser,
+ (char *)badpass,
+ sizeof(badpass),
+ (char *)badpass,
+ sizeof(badpass),
+ user_info->domain))) {
/*
* We connected to the password server so we
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;
- }
+ nt_status = cli_session_setup(
+ cli, user_info->smb_name,
+ (char *)user_info->plaintext_password.data,
+ user_info->plaintext_password.length,
+ NULL, 0, user_info->domain);
+
} else {
- 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;
- }
+ nt_status = cli_session_setup(
+ cli, user_info->smb_name,
+ (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);
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(1,("password server %s rejected the password: %s\n",
+ cli->desthost, nt_errstr(nt_status)));
}
/* if logged in as guest then reject */
cli_ulogoff(cli);
if (NT_STATUS_IS_OK(nt_status)) {
- struct passwd *pass = Get_Pwnam(user_info->internal_username.str);
- if (pass) {
- nt_status = make_server_info_pw(server_info, pass);
- } else {
- auth_add_user_script(user_info->domain.str, user_info->internal_username.str);
- pass = Get_Pwnam(user_info->internal_username.str);
-
- if (pass) {
- nt_status = make_server_info_pw(server_info, pass);
+ fstring real_username;
+ struct passwd *pass;
+
+ if ( (pass = smb_getpwnam( NULL, user_info->internal_username,
+ real_username, True )) != NULL )
+ {
+ /* if a real user check pam account restrictions */
+ /* only really perfomed if "obey pam restriction" is true */
+ nt_status = smb_pam_accountcheck(pass->pw_name);
+ if ( !NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(1, ("PAM account restriction prevents user login\n"));
} else {
- nt_status = NT_STATUS_NO_SUCH_USER;
+
+ nt_status = make_server_info_pw(server_info, pass->pw_name, pass);
}
+ TALLOC_FREE(pass);
+ }
+ else
+ {
+ nt_status = NT_STATUS_NO_SUCH_USER;
}
}
(*auth_method)->name = "smbserver";
(*auth_method)->auth = check_smbserver_security;
(*auth_method)->get_chal = auth_get_challenge_server;
- (*auth_method)->send_keepalive = send_server_keepalive;
- (*auth_method)->free_private_data = free_server_private_data;
return NT_STATUS_OK;
}