summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/include/proto.h7
-rw-r--r--source/libsmb/clientgen.c28
-rw-r--r--source/param/loadparm.c6
-rw-r--r--source/rpc_client/cli_pipe.c4
-rw-r--r--source/rpc_client/ntclienttrust.c4
-rw-r--r--source/smbd/password.c13
-rw-r--r--source/smbd/reply.c90
-rw-r--r--source/smbwrapper/smbw.c2
-rw-r--r--source/utils/torture.c2
9 files changed, 127 insertions, 29 deletions
diff --git a/source/include/proto.h b/source/include/proto.h
index 4848c5e70fb..d69f715f0ec 100644
--- a/source/include/proto.h
+++ b/source/include/proto.h
@@ -458,7 +458,7 @@ BOOL cli_session_request(struct cli_state *cli,
BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip);
struct cli_state *cli_initialise(struct cli_state *cli);
void cli_shutdown(struct cli_state *cli);
-int cli_error(struct cli_state *cli, uint8 *eclass, uint32 *num);
+int cli_error(struct cli_state *cli, uint8 *eclass, uint32 *num, uint32 *nt_rpc_error);
void cli_sockopt(struct cli_state *cli, char *options);
uint16 cli_setpid(struct cli_state *cli, uint16 pid);
BOOL cli_reestablish_connection(struct cli_state *cli);
@@ -980,6 +980,8 @@ char *lp_nis_home_map_name(void);
char *lp_netbios_aliases(void);
char *lp_driverfile(void);
char *lp_panic_action(void);
+char *lp_adduser_script(void);
+char *lp_deluser_script(void);
char *lp_domain_groups(void);
char *lp_domain_admin_group(void);
char *lp_domain_guest_group(void);
@@ -2466,7 +2468,8 @@ BOOL server_validate(char *user, char *domain,
char *ntpass, int ntpasslen);
BOOL domain_client_validate( char *user, char *domain,
char *smb_apasswd, int smb_apasslen,
- char *smb_ntpasswd, int smb_ntpasslen);
+ char *smb_ntpasswd, int smb_ntpasslen,
+ BOOL *user_exists);
/*The following definitions come from smbd/pipes.c */
diff --git a/source/libsmb/clientgen.c b/source/libsmb/clientgen.c
index 550f7cc391d..c9d221bd337 100644
--- a/source/libsmb/clientgen.c
+++ b/source/libsmb/clientgen.c
@@ -108,6 +108,7 @@ char *cli_errstr(struct cli_state *cli)
static fstring error_message;
uint8 errclass;
uint32 errnum;
+ uint32 nt_rpc_error;
int i;
/*
@@ -117,7 +118,7 @@ char *cli_errstr(struct cli_state *cli)
* errors, whose error code is in cli.rap_error.
*/
- cli_error(cli, &errclass, &errnum);
+ cli_error(cli, &errclass, &errnum, &nt_rpc_error);
if (errclass != 0)
{
@@ -128,13 +129,13 @@ char *cli_errstr(struct cli_state *cli)
* Was it an NT error ?
*/
- if (cli->nt_error)
+ if (nt_rpc_error)
{
- char *nt_msg = get_nt_error_msg(cli->nt_error);
+ char *nt_msg = get_nt_error_msg(nt_rpc_error);
if (nt_msg == NULL)
{
- slprintf(error_message, sizeof(fstring) - 1, "NT code %d", cli->nt_error);
+ slprintf(error_message, sizeof(fstring) - 1, "NT code %d", nt_rpc_error);
}
else
{
@@ -338,7 +339,7 @@ static BOOL cli_receive_trans(struct cli_state *cli,int trans,
return(False);
}
- if (cli_error(cli, NULL, NULL))
+ if (cli_error(cli, NULL, NULL, NULL))
{
return(False);
}
@@ -391,7 +392,7 @@ static BOOL cli_receive_trans(struct cli_state *cli,int trans,
CVAL(cli->inbuf,smb_com)));
return(False);
}
- if (cli_error(cli, NULL, NULL))
+ if (cli_error(cli, NULL, NULL, NULL))
{
return(False);
}
@@ -1650,7 +1651,7 @@ BOOL cli_qpathinfo(struct cli_state *cli, const char *fname,
it gives ERRSRV/ERRerror temprarily */
uint8 eclass;
uint32 ecode;
- cli_error(cli, &eclass, &ecode);
+ cli_error(cli, &eclass, &ecode, NULL);
if (eclass != ERRSRV || ecode != ERRerror) break;
msleep(100);
}
@@ -2013,7 +2014,7 @@ int cli_list(struct cli_state *cli,const char *Mask,uint16 attribute,
it gives ERRSRV/ERRerror temprarily */
uint8 eclass;
uint32 ecode;
- cli_error(cli, &eclass, &ecode);
+ cli_error(cli, &eclass, &ecode, NULL);
if (eclass != ERRSRV || ecode != ERRerror) break;
msleep(100);
continue;
@@ -2427,7 +2428,7 @@ void cli_shutdown(struct cli_state *cli)
for 32 bit "warnings", a return code of 0 is expected.
****************************************************************************/
-int cli_error(struct cli_state *cli, uint8 *eclass, uint32 *num)
+int cli_error(struct cli_state *cli, uint8 *eclass, uint32 *num, uint32 *nt_rpc_error)
{
int flgs2 = SVAL(cli->inbuf,smb_flg2);
char rcls;
@@ -2435,6 +2436,7 @@ int cli_error(struct cli_state *cli, uint8 *eclass, uint32 *num)
if (eclass) *eclass = 0;
if (num ) *num = 0;
+ if (nt_rpc_error) *nt_rpc_error = cli->nt_error;
if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
/* 32 bit error codes detected */
@@ -2831,7 +2833,7 @@ BOOL cli_chkpath(struct cli_state *cli, char *path)
return False;
}
- if (cli_error(cli, NULL, NULL)) return False;
+ if (cli_error(cli, NULL, NULL, NULL)) return False;
return True;
}
@@ -2868,7 +2870,7 @@ BOOL cli_message_start(struct cli_state *cli, char *host, char *username,
return False;
}
- if (cli_error(cli, NULL, NULL)) return False;
+ if (cli_error(cli, NULL, NULL, NULL)) return False;
*grp = SVAL(cli->inbuf,smb_vwv0);
@@ -2901,7 +2903,7 @@ BOOL cli_message_text(struct cli_state *cli, char *msg, int len, int grp)
return False;
}
- if (cli_error(cli, NULL, NULL)) return False;
+ if (cli_error(cli, NULL, NULL, NULL)) return False;
return True;
}
@@ -2926,7 +2928,7 @@ BOOL cli_message_end(struct cli_state *cli, int grp)
return False;
}
- if (cli_error(cli, NULL, NULL)) return False;
+ if (cli_error(cli, NULL, NULL, NULL)) return False;
return True;
}
diff --git a/source/param/loadparm.c b/source/param/loadparm.c
index 8b351168586..6f270eb0f55 100644
--- a/source/param/loadparm.c
+++ b/source/param/loadparm.c
@@ -155,6 +155,8 @@ typedef struct
char *szLdapRoot;
char *szLdapRootPassword;
char *szPanicAction;
+ char *szAddUserScript;
+ char *szDelUserScript;
int max_log_size;
int mangled_stack;
int max_xmit;
@@ -691,6 +693,8 @@ static struct parm_struct parm_table[] =
{"machine password timeout", P_INTEGER, P_GLOBAL, &Globals.machine_password_timeout, NULL, NULL, 0},
{"Logon Options", P_SEP, P_SEPARATOR},
+ {"add user script", P_STRING, P_GLOBAL, &Globals.szAddUserScript, NULL, NULL, 0},
+ {"delete user script",P_STRING, P_GLOBAL, &Globals.szDelUserScript, NULL, NULL, 0},
{"logon script", P_STRING, P_GLOBAL, &Globals.szLogonScript, NULL, NULL, 0},
{"logon path", P_STRING, P_GLOBAL, &Globals.szLogonPath, NULL, NULL, 0},
{"logon drive", P_STRING, P_GLOBAL, &Globals.szLogonDrive, NULL, NULL, 0},
@@ -1124,6 +1128,8 @@ static FN_GLOBAL_STRING(lp_announce_version,&Globals.szAnnounceVersion)
FN_GLOBAL_STRING(lp_netbios_aliases,&Globals.szNetbiosAliases)
FN_GLOBAL_STRING(lp_driverfile,&Globals.szDriverFile)
FN_GLOBAL_STRING(lp_panic_action,&Globals.szPanicAction)
+FN_GLOBAL_STRING(lp_adduser_script,&Globals.szAddUserScript)
+FN_GLOBAL_STRING(lp_deluser_script,&Globals.szDelUserScript)
FN_GLOBAL_STRING(lp_domain_groups,&Globals.szDomainGroups)
FN_GLOBAL_STRING(lp_domain_admin_group,&Globals.szDomainAdminGroup)
diff --git a/source/rpc_client/cli_pipe.c b/source/rpc_client/cli_pipe.c
index 579eeebdac1..a9e0449c950 100644
--- a/source/rpc_client/cli_pipe.c
+++ b/source/rpc_client/cli_pipe.c
@@ -93,7 +93,7 @@ static BOOL rpc_read(struct cli_state *cli,
file_offset += num_read;
data += num_read;
- if (cli_error(cli, NULL, &err)) return False;
+ if (cli_error(cli, NULL, &err, NULL)) return False;
} while (num_read > 0 && data_to_read > 0);
/* && err == (0x80000000 | STATUS_BUFFER_OVERFLOW)); */
@@ -378,7 +378,7 @@ static BOOL rpc_api_pipe(struct cli_state *cli, uint16 cmd,
prs_mem_free(&hps);
- if (cli_error(cli, NULL, &err)) return False;
+ if (cli_error(cli, NULL, &err, NULL)) return False;
if (first)
{
diff --git a/source/rpc_client/ntclienttrust.c b/source/rpc_client/ntclienttrust.c
index 04860171817..e55d325294f 100644
--- a/source/rpc_client/ntclienttrust.c
+++ b/source/rpc_client/ntclienttrust.c
@@ -93,7 +93,7 @@ BOOL trust_account_check(struct in_addr dest_ip, char *dest_host,
if (!server_connect_init(&cli_trust, myhostname, dest_ip, dest_host))
{
- cli_error(&cli_trust, &err_cls, &err_num);
+ cli_error(&cli_trust, &err_cls, &err_num, NULL);
DEBUG(1,("server_connect_init failed (%s)\n", cli_errstr(&cli_trust)));
cli_shutdown(&cli_trust);
@@ -141,7 +141,7 @@ BOOL trust_account_check(struct in_addr dest_ip, char *dest_host,
return False;
}
- cli_error(&cli_trust, &err_cls, &err_num);
+ cli_error(&cli_trust, &err_cls, &err_num, NULL);
if (err_num == (0xC0000000 | NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT))
{
diff --git a/source/smbd/password.c b/source/smbd/password.c
index 0ff498737d2..50a0ebd79e0 100644
--- a/source/smbd/password.c
+++ b/source/smbd/password.c
@@ -1142,7 +1142,8 @@ use this machine as the password server.\n"));
BOOL domain_client_validate( char *user, char *domain,
char *smb_apasswd, int smb_apasslen,
- char *smb_ntpasswd, int smb_ntpasslen)
+ char *smb_ntpasswd, int smb_ntpasslen,
+ BOOL *user_exists)
{
unsigned char local_challenge[8];
unsigned char local_lm_response[24];
@@ -1158,6 +1159,9 @@ BOOL domain_client_validate( char *user, char *domain,
BOOL connected_ok = False;
struct nmb_name calling, called;
+ if(user_exists != NULL)
+ *user_exists = True; /* Only set false on a very specific error. */
+
/*
* 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
@@ -1346,11 +1350,18 @@ machine %s. Error was : %s.\n", remote_machine, cli_errstr(&cli)));
((smb_apasslen != 0) ? smb_apasswd : NULL),
((smb_ntpasslen != 0) ? smb_ntpasswd : NULL),
&ctr, &info3) == False) {
+ uint32 nt_rpc_err;
+
+ cli_error(&cli, NULL, NULL, &nt_rpc_err);
DEBUG(0,("domain_client_validate: unable to validate password for user %s in domain \
%s to Domain controller %s. Error was %s.\n", user, domain, remote_machine, cli_errstr(&cli)));
cli_nt_session_close(&cli);
cli_ulogoff(&cli);
cli_shutdown(&cli);
+
+ if((nt_rpc_err == NT_STATUS_NO_SUCH_USER) && (user_exists != NULL))
+ *user_exists = False;
+
return False;
}
diff --git a/source/smbd/reply.c b/source/smbd/reply.c
index 69894d4cb10..f61b89f8ddb 100644
--- a/source/smbd/reply.c
+++ b/source/smbd/reply.c
@@ -448,35 +448,111 @@ static int session_trust_account(connection_struct *conn, char *inbuf, char *out
}
/****************************************************************************
+ Create a UNIX user on demand.
+****************************************************************************/
+
+static int smb_create_user(char *unix_user)
+{
+ pstring add_script;
+ int ret;
+
+ pstrcpy(add_script, lp_adduser_script());
+ string_sub(add_script, "%u", unix_user);
+ ret = smbrun(add_script,NULL,False);
+ DEBUG(3,("smb_create_user: Running the command `%s' gave %d\n",add_script,ret));
+ return ret;
+}
+
+/****************************************************************************
+ Delete a UNIX user on demand.
+****************************************************************************/
+
+static int smb_delete_user(char *unix_user)
+{
+ pstring del_script;
+ int ret;
+
+ pstrcpy(del_script, lp_deluser_script());
+ string_sub(del_script, "%u", unix_user);
+ ret = smbrun(del_script,NULL,False);
+ DEBUG(3,("smb_delete_user: Running the command `%s' gave %d\n",del_script,ret));
+ return ret;
+}
+
+/****************************************************************************
Check for a valid username and password in security=server mode.
****************************************************************************/
-static BOOL check_server_security(char *orig_user, char *domain,
+static BOOL check_server_security(char *orig_user, char *domain, char *unix_user,
char *smb_apasswd, int smb_apasslen,
char *smb_ntpasswd, int smb_ntpasslen)
{
+ BOOL ret = False;
+
if(lp_security() != SEC_SERVER)
return False;
- return server_validate(orig_user, domain,
+ ret = server_validate(orig_user, domain,
smb_apasswd, smb_apasslen,
smb_ntpasswd, smb_ntpasslen);
+ if(ret) {
+ /*
+ * User validated ok against Domain controller.
+ * If the admin wants us to try and create a UNIX
+ * user on the fly, do so.
+ * Note that we can never delete users when in server
+ * level security as we never know if it was a failure
+ * due to a bad password, or the user really doesn't exist.
+ */
+ if(lp_adduser_script() && !Get_Pwnam(unix_user,True)) {
+ smb_create_user(unix_user);
+ }
+ }
+
+ return ret;
}
/****************************************************************************
Check for a valid username and password in security=domain mode.
****************************************************************************/
-static BOOL check_domain_security(char *orig_user, char *domain,
+static BOOL check_domain_security(char *orig_user, char *domain, char *unix_user,
char *smb_apasswd, int smb_apasslen,
char *smb_ntpasswd, int smb_ntpasslen)
{
+ BOOL ret = False;
+ BOOL user_exists = True;
+
if(lp_security() != SEC_DOMAIN)
return False;
- return domain_client_validate(orig_user, domain,
+ ret = domain_client_validate(orig_user, domain,
smb_apasswd, smb_apasslen,
- smb_ntpasswd, smb_ntpasslen);
+ smb_ntpasswd, smb_ntpasslen,
+ &user_exists);
+
+ if(ret) {
+ /*
+ * User validated ok against Domain controller.
+ * If the admin wants us to try and create a UNIX
+ * user on the fly, do so.
+ */
+ if(user_exists && lp_adduser_script() && !Get_Pwnam(unix_user,True)) {
+ smb_create_user(unix_user);
+ }
+ } else {
+ /*
+ * User failed to validate ok against Domain controller.
+ * If the failure was "user doesn't exist" and admin
+ * wants us to try and delete that UNIX user on the fly,
+ * do so.
+ */
+ if(!user_exists && lp_deluser_script() && Get_Pwnam(unix_user,True)) {
+ smb_delete_user(unix_user);
+ }
+ }
+
+ return ret;
}
/****************************************************************************
@@ -669,10 +745,10 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int
*/
if (!guest &&
- !check_server_security(orig_user, domain,
+ !check_server_security(orig_user, domain, user,
smb_apasswd, smb_apasslen,
smb_ntpasswd, smb_ntpasslen) &&
- !check_domain_security(orig_user, domain,
+ !check_domain_security(orig_user, domain, user,
smb_apasswd, smb_apasslen,
smb_ntpasswd, smb_ntpasslen) &&
!check_hosts_equiv(user)
diff --git a/source/smbwrapper/smbw.c b/source/smbwrapper/smbw.c
index faaa9f047b0..6ae6146ed22 100644
--- a/source/smbwrapper/smbw.c
+++ b/source/smbwrapper/smbw.c
@@ -378,7 +378,7 @@ int smbw_errno(struct cli_state *c)
uint32 ecode;
int ret;
- ret = cli_error(c, &eclass, &ecode);
+ ret = cli_error(c, &eclass, &ecode, NULL);
if (ret) {
DEBUG(3,("smbw_error %d %d (0x%x) -> %d\n",
diff --git a/source/utils/torture.c b/source/utils/torture.c
index 81fa33fc750..54b42819dd8 100644
--- a/source/utils/torture.c
+++ b/source/utils/torture.c
@@ -107,7 +107,7 @@ static BOOL check_error(struct cli_state *c,
uint8 class;
uint32 num;
int eno;
- eno = cli_error(c, &class, &num);
+ eno = cli_error(c, &class, &num, NULL);
if ((eclass != class || ecode != num) &&
num != (nterr&0xFFFFFF)) {
printf("unexpected error code class=%d code=%d\n",