mirror of
https://github.com/samba-team/samba.git
synced 2025-01-25 06:04:04 +03:00
cool! a unix socket smb redirector. code based on smbfilter and
ideas from ssh-agent. the intent is to be able to share smb sessions using cli_net_use_add() across multiple processes, where one process knows the target server name, user name and domain, but not the smb password. (This used to be commit 294b653f2e9cdc1864ec638ae8b4300df25723cf)
This commit is contained in:
parent
69683dc27a
commit
7d01f964ff
@ -302,7 +302,8 @@ NMBLOOKUP_OBJ = utils/nmblookup.o $(PARAM_OBJ) $(UBIQX_OBJ) \
|
||||
|
||||
DEBUG2HTML_OBJ = utils/debug2html.o $(PARAM_OBJ) $(LIB_OBJ)
|
||||
|
||||
SMB_AGENT_OBJ = smb-agent.o $(PARAM_OBJ) $(LIB_OBJ)
|
||||
SMB_AGENT_OBJ = utils/smb-agent.o $(LIBSMB_OBJ) $(PARAM_OBJ) $(LIB_OBJ) \
|
||||
$(RPC_PARSE_OBJ2) rpc_client/cli_use.o
|
||||
|
||||
SMB_CLIENT_OBJ = smb-client.o $(PARAM_OBJ) $(LIB_OBJ)
|
||||
|
||||
@ -481,6 +482,14 @@ bin/rpctorture: $(RPCTORTURE_OBJ) bin/.dummy
|
||||
@echo Linking $@
|
||||
@$(CC) $(FLAGS) -o $@ $(RPCTORTURE_OBJ) $(LDFLAGS) $(LIBS)
|
||||
|
||||
bin/smb-client: $(SMB_CLIENT_OBJ) bin/.dummy
|
||||
@echo Linking $@
|
||||
@$(CC) $(FLAGS) -o $@ $(SMB_CLIENT_OBJ) $(LDFLAGS) $(LIBS)
|
||||
|
||||
bin/smb-agent: $(SMB_AGENT_OBJ) bin/.dummy
|
||||
@echo Linking $@
|
||||
@$(CC) $(FLAGS) -o $@ $(SMB_AGENT_OBJ) $(LDFLAGS) $(LIBS)
|
||||
|
||||
bin/smbfilter: $(SMBFILTER_OBJ) bin/.dummy
|
||||
@echo Linking $@
|
||||
@$(CC) $(FLAGS) -o $@ $(SMBFILTER_OBJ) $(LDFLAGS) $(LIBS)
|
||||
|
@ -126,6 +126,7 @@ struct cli_state
|
||||
size_t nt_cli_chal_len;
|
||||
|
||||
BOOL use_ntlmv2;
|
||||
BOOL redirect;
|
||||
|
||||
uint32 sesskey;
|
||||
int serverzone;
|
||||
|
@ -676,7 +676,8 @@ void unistr2_free(UNISTR2 *name);
|
||||
|
||||
/*The following definitions come from libsmb/clientgen.c */
|
||||
|
||||
void copy_user_creds(struct user_credentials *to, const struct user_credentials *from);
|
||||
void copy_user_creds(struct user_credentials *to,
|
||||
const struct user_credentials *from);
|
||||
int cli_set_port(struct cli_state *cli, int port);
|
||||
char *cli_errstr(struct cli_state *cli);
|
||||
void cli_safe_smb_errstr(struct cli_state *cli, char *msg, size_t len);
|
||||
@ -852,6 +853,7 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name,
|
||||
/*The following definitions come from libsmb/pwd_cache.c */
|
||||
|
||||
void pwd_init(struct pwd_info *pwd);
|
||||
BOOL pwd_is_nullpwd(const struct pwd_info *pwd);
|
||||
void pwd_obfuscate_key(struct pwd_info *pwd, uint32 int_key, char *str_key);
|
||||
BOOL pwd_compare(struct pwd_info *pwd1, struct pwd_info *pwd2);
|
||||
void pwd_read(struct pwd_info *pwd, char *passwd_report, BOOL do_encrypt);
|
||||
@ -2184,7 +2186,8 @@ BOOL svc_change_svc_cfg( POLICY_HND *hnd,
|
||||
void init_cli_use(void);
|
||||
void free_cli_use(void);
|
||||
struct cli_state *cli_net_use_add(const char* srv_name,
|
||||
const struct user_credentials *usr_creds);
|
||||
const struct user_credentials *usr_creds,
|
||||
BOOL redir);
|
||||
BOOL cli_net_use_del(const char* srv_name,
|
||||
const struct user_credentials *usr_creds,
|
||||
BOOL force_close,
|
||||
|
@ -2930,6 +2930,104 @@ BOOL cli_reestablish_connection(struct cli_state *cli)
|
||||
return False;
|
||||
}
|
||||
|
||||
static int cli_init_redirect(struct cli_state *cli,
|
||||
const char* srv_name, struct in_addr *destip,
|
||||
const struct user_credentials *usr)
|
||||
{
|
||||
int sock;
|
||||
struct sockaddr_un sa;
|
||||
fstring ip_name;
|
||||
struct cli_state cli_redir;
|
||||
|
||||
pstring data;
|
||||
uint32 len;
|
||||
char *p;
|
||||
char *in = cli->inbuf;
|
||||
char *out = cli->outbuf;
|
||||
|
||||
if (strequal(srv_name, "*SMBSERVER"))
|
||||
{
|
||||
fstrcpy(ip_name, "\\\\");
|
||||
inet_aton(&ip_name[2], destip);
|
||||
srv_name = ip_name;
|
||||
}
|
||||
|
||||
sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
|
||||
if (sock < 0)
|
||||
{
|
||||
DEBUG(0, ("unix socket open failed\n"));
|
||||
return sock;
|
||||
}
|
||||
|
||||
ZERO_STRUCT(sa);
|
||||
sa.sun_family = AF_UNIX;
|
||||
safe_strcpy(sa.sun_path, "/tmp/smb-agent/smb.sock",
|
||||
sizeof(sa.sun_path)-1);
|
||||
|
||||
DEBUG(10, ("socket open succeeded. file name: %s\n", sa.sun_path));
|
||||
|
||||
if (connect(sock, (struct sockaddr*) &sa, sizeof(sa)) < 0)
|
||||
{
|
||||
DEBUG(0,("socket connect to %s failed\n", sa.sun_path));
|
||||
close(sock);
|
||||
return False;
|
||||
}
|
||||
|
||||
DEBUG(10,("connect succeeded\n"));
|
||||
|
||||
ZERO_STRUCT(data);
|
||||
|
||||
p = &data[4];
|
||||
safe_strcpy(p, srv_name, 16);
|
||||
p = skip_string(p, 1);
|
||||
safe_strcpy(p, usr != NULL ? usr->user_name : "", 16);
|
||||
p = skip_string(p, 1);
|
||||
safe_strcpy(p, usr != NULL ? usr->domain : "", 16);
|
||||
p = skip_string(p, 1);
|
||||
|
||||
if (usr != NULL && !pwd_is_nullpwd(&usr->pwd))
|
||||
{
|
||||
uchar lm16[16];
|
||||
uchar nt16[16];
|
||||
|
||||
pwd_get_lm_nt_16(&usr->pwd, lm16, nt16);
|
||||
memcpy(p, lm16, 16);
|
||||
p += 16;
|
||||
memcpy(p, nt16, 16);
|
||||
p += 16;
|
||||
}
|
||||
|
||||
len = PTR_DIFF(p, data);
|
||||
SIVAL(data, 0, len);
|
||||
|
||||
printf("data len: %d\n", len);
|
||||
out_data(stdout, data, len, 80);
|
||||
|
||||
if (write(sock, data, len) <= 0)
|
||||
{
|
||||
DEBUG(0,("write failed\n"));
|
||||
close(sock);
|
||||
return False;
|
||||
}
|
||||
|
||||
len = read(sock, &cli_redir, sizeof(cli_redir));
|
||||
|
||||
if (len != sizeof(cli_redir))
|
||||
{
|
||||
DEBUG(0,("read failed\n"));
|
||||
close(sock);
|
||||
return False;
|
||||
}
|
||||
|
||||
memcpy(cli, &cli_redir, sizeof(cli_redir));
|
||||
cli->inbuf = in;
|
||||
cli->outbuf = out;
|
||||
cli->fd = sock;
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
establishes a connection right up to doing tconX, reading in a password.
|
||||
****************************************************************************/
|
||||
@ -2957,6 +3055,19 @@ BOOL cli_establish_connection(struct cli_state *cli,
|
||||
return False;
|
||||
}
|
||||
|
||||
if (cli->fd == -1 && cli->redirect)
|
||||
{
|
||||
if (cli_init_redirect(cli, dest_host, dest_ip, &cli->usr))
|
||||
{
|
||||
DEBUG(10,("cli_establish_connection: redirected OK\n"));
|
||||
return True;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG(10,("redirect FAILED\n"));
|
||||
return False;
|
||||
}
|
||||
}
|
||||
if (cli->fd == -1)
|
||||
{
|
||||
if (!cli_connect(cli, dest_host, dest_ip))
|
||||
|
@ -42,6 +42,14 @@ void pwd_init(struct pwd_info *pwd)
|
||||
pwd->crypted = False;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
returns NULL password flag
|
||||
****************************************************************************/
|
||||
BOOL pwd_is_nullpwd(const struct pwd_info *pwd)
|
||||
{
|
||||
return pwd->null_pwd;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
de-obfuscates a password
|
||||
****************************************************************************/
|
||||
|
@ -96,7 +96,7 @@ static struct cli_connection *cli_con_get(const char* srv_name,
|
||||
con->pipe_name = strdup(pipe_name);
|
||||
}
|
||||
|
||||
con->cli = cli_net_use_add(srv_name, usr_creds);
|
||||
con->cli = cli_net_use_add(srv_name, usr_creds, True);
|
||||
|
||||
if (con->cli == NULL)
|
||||
{
|
||||
|
@ -204,7 +204,8 @@ static struct cli_use *cli_use_get(const char* srv_name,
|
||||
init client state
|
||||
****************************************************************************/
|
||||
struct cli_state *cli_net_use_add(const char* srv_name,
|
||||
const struct user_credentials *usr_creds)
|
||||
const struct user_credentials *usr_creds,
|
||||
BOOL redir)
|
||||
{
|
||||
struct nmb_name calling;
|
||||
struct nmb_name called;
|
||||
@ -225,6 +226,7 @@ struct cli_state *cli_net_use_add(const char* srv_name,
|
||||
*/
|
||||
|
||||
cli = cli_use_get(srv_name, usr_creds);
|
||||
cli->cli->redirect = redir;
|
||||
|
||||
if (resolve_srv_name(srv_name, dest_host, &ip))
|
||||
{
|
||||
|
@ -1493,7 +1493,7 @@ static void cmd_net(struct client_info *info, int argc, char *argv[])
|
||||
srv_name, u.user_name, u.domain);
|
||||
report(out_hnd, "Connection:\t");
|
||||
|
||||
if (cli_net_use_add(srv_name, &u) != NULL)
|
||||
if (cli_net_use_add(srv_name, &u, True) != NULL)
|
||||
{
|
||||
report(out_hnd, "OK\n");
|
||||
}
|
||||
|
347
source3/utils/smb-agent.c
Normal file
347
source3/utils/smb-agent.c
Normal file
@ -0,0 +1,347 @@
|
||||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
Version 2
|
||||
SMB agent/socket plugin
|
||||
Copyright (C) Andrew Tridgell 1999
|
||||
|
||||
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"
|
||||
#include "smb.h"
|
||||
|
||||
#define SECURITY_MASK 0
|
||||
#define SECURITY_SET 0
|
||||
|
||||
/* this forces non-unicode */
|
||||
#define CAPABILITY_MASK CAP_UNICODE
|
||||
#define CAPABILITY_SET 0
|
||||
|
||||
/* and non-unicode for the client too */
|
||||
#define CLI_CAPABILITY_MASK CAP_UNICODE
|
||||
#define CLI_CAPABILITY_SET 0
|
||||
|
||||
static char *netbiosname;
|
||||
static char packet[BUFFER_SIZE];
|
||||
|
||||
extern int DEBUGLEVEL;
|
||||
|
||||
static void agent_reply(char *buf)
|
||||
{
|
||||
int msg_type = CVAL(buf,0);
|
||||
int type = CVAL(buf,smb_com);
|
||||
unsigned x;
|
||||
|
||||
if (msg_type) return;
|
||||
|
||||
switch (type) {
|
||||
|
||||
case SMBnegprot:
|
||||
/* force the security bits */
|
||||
x = CVAL(buf, smb_vwv1);
|
||||
x = (x | SECURITY_SET) & ~SECURITY_MASK;
|
||||
SCVAL(buf, smb_vwv1, x);
|
||||
|
||||
/* force the capabilities */
|
||||
x = IVAL(buf,smb_vwv9+1);
|
||||
x = (x | CAPABILITY_SET) & ~CAPABILITY_MASK;
|
||||
SIVAL(buf, smb_vwv9+1, x);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void agent_request(char *buf)
|
||||
{
|
||||
int msg_type = CVAL(buf,0);
|
||||
int type = CVAL(buf,smb_com);
|
||||
pstring name1,name2;
|
||||
unsigned x;
|
||||
|
||||
if (msg_type) {
|
||||
/* it's a netbios special */
|
||||
switch (msg_type) {
|
||||
case 0x81:
|
||||
/* session request */
|
||||
name_extract(buf,4,name1);
|
||||
name_extract(buf,4 + name_len(buf + 4),name2);
|
||||
DEBUG(0,("sesion_request: %s -> %s\n",
|
||||
name1, name2));
|
||||
if (netbiosname) {
|
||||
/* replace the destination netbios name */
|
||||
name_mangle(netbiosname, buf+4, 0x20);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* it's an ordinary SMB request */
|
||||
switch (type) {
|
||||
case SMBsesssetupX:
|
||||
/* force the client capabilities */
|
||||
x = IVAL(buf,smb_vwv11);
|
||||
x = (x | CLI_CAPABILITY_SET) & ~CLI_CAPABILITY_MASK;
|
||||
SIVAL(buf, smb_vwv11, x);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void agent_child(int c)
|
||||
{
|
||||
struct cli_state *s = NULL;
|
||||
|
||||
DEBUG(10,("agent_child: %d\n", c));
|
||||
|
||||
while (c != -1)
|
||||
{
|
||||
fd_set fds;
|
||||
int num;
|
||||
int maxfd = 0;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
if (s != NULL)
|
||||
{
|
||||
FD_SET(s->fd, &fds);
|
||||
maxfd = MAX(s->fd, maxfd);
|
||||
}
|
||||
|
||||
if (c != -1)
|
||||
{
|
||||
FD_SET(c, &fds);
|
||||
maxfd = MAX(c, maxfd);
|
||||
}
|
||||
|
||||
num = sys_select(maxfd+1,&fds,NULL, NULL);
|
||||
if (num <= 0) continue;
|
||||
|
||||
if (c != -1 && FD_ISSET(c, &fds))
|
||||
{
|
||||
if (s == NULL)
|
||||
{
|
||||
pstring buf;
|
||||
uchar ntpw[16];
|
||||
uchar lmpw[16];
|
||||
fstring srv_name;
|
||||
struct user_credentials usr;
|
||||
char *p = buf;
|
||||
int rl;
|
||||
uint32 len;
|
||||
|
||||
DEBUG(10,("first request\n"));
|
||||
|
||||
rl = read(c, &buf, sizeof(len));
|
||||
|
||||
if (rl != sizeof(len))
|
||||
{
|
||||
DEBUG(0,("Unable to read length\n"));
|
||||
dump_data(0, buf, sizeof(len));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
len = IVAL(buf, 0);
|
||||
|
||||
if (len > sizeof(buf))
|
||||
{
|
||||
DEBUG(0,("length %d too long\n", len));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
rl = read(c, buf, len);
|
||||
|
||||
if (rl < 0)
|
||||
{
|
||||
DEBUG(0,("Unable to read from connection\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_PASSWORD
|
||||
dump_data(100, buf, rl);
|
||||
#endif
|
||||
fstrcpy(srv_name, p);
|
||||
p = skip_string(p, 1);
|
||||
fstrcpy(usr.user_name, p);
|
||||
p = skip_string(p, 1);
|
||||
fstrcpy(usr.domain, p);
|
||||
p = skip_string(p, 1);
|
||||
|
||||
if (PTR_DIFF(p, buf) < rl)
|
||||
{
|
||||
memcpy(ntpw, p, 16);
|
||||
p += 16;
|
||||
memcpy(lmpw, p, 16);
|
||||
p += 16;
|
||||
pwd_set_lm_nt_16(&usr.pwd, lmpw, ntpw);
|
||||
}
|
||||
else
|
||||
{
|
||||
pwd_set_nullpwd(&usr.pwd);
|
||||
}
|
||||
|
||||
if (PTR_DIFF(p, buf) != rl)
|
||||
{
|
||||
DEBUG(0,("Buffer size %d %d!\n",
|
||||
PTR_DIFF(p, buf), rl));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
s = cli_net_use_add(srv_name, &usr, False);
|
||||
|
||||
if (s == NULL)
|
||||
{
|
||||
DEBUG(0,("Unable to connect to %s\n", srv_name));
|
||||
exit(1);
|
||||
}
|
||||
if (write(c, s, sizeof(*s)) < 0)
|
||||
{
|
||||
DEBUG(0,("Could not write ack\n"));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!receive_smb(c, packet, 0))
|
||||
{
|
||||
DEBUG(0,("client closed connection\n"));
|
||||
exit(0);
|
||||
}
|
||||
if (!send_smb(s->fd, packet))
|
||||
{
|
||||
DEBUG(0,("server is dead\n"));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (s != NULL && FD_ISSET(s->fd, &fds))
|
||||
{
|
||||
if (!receive_smb(s->fd, packet, 0))
|
||||
{
|
||||
DEBUG(0,("server closed connection\n"));
|
||||
exit(0);
|
||||
}
|
||||
#if 0
|
||||
agent_reply(packet);
|
||||
#endif
|
||||
if (!send_smb(c, packet))
|
||||
{
|
||||
DEBUG(0,("client is dead\n"));
|
||||
cli_shutdown(s);
|
||||
free(s);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
DEBUG(0,("Connection closed\n"));
|
||||
if (s != NULL)
|
||||
{
|
||||
cli_shutdown(s);
|
||||
free(s);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
static void start_agent(void)
|
||||
{
|
||||
int s, c;
|
||||
struct sockaddr_un sa;
|
||||
|
||||
CatchChild();
|
||||
|
||||
/* start listening on unix socket */
|
||||
|
||||
mkdir("/tmp/smb-agent", 700);
|
||||
s = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
|
||||
if (s < 0)
|
||||
{
|
||||
fprintf(stderr, "socket open failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ZERO_STRUCT(sa);
|
||||
sa.sun_family = AF_UNIX;
|
||||
safe_strcpy(sa.sun_path, "/tmp/smb-agent/smb.sock",
|
||||
sizeof(sa.sun_path)-1);
|
||||
|
||||
if (bind(s, (struct sockaddr*) &sa, sizeof(sa)) < 0)
|
||||
{
|
||||
fprintf(stderr, "socket bind to %s failed\n", sa.sun_path);
|
||||
close(s);
|
||||
remove("/tmp/smb-agent/smb.sock");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (s == -1) {
|
||||
DEBUG(0,("bind failed\n"));
|
||||
remove("/tmp/smb-agent/smb.sock");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (listen(s, 5) == -1)
|
||||
{
|
||||
DEBUG(0,("listen failed\n"));
|
||||
remove("/tmp/smb-agent/smb.sock");
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
fd_set fds;
|
||||
int num;
|
||||
struct sockaddr_un addr;
|
||||
int in_addrlen = sizeof(addr);
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(s, &fds);
|
||||
|
||||
num = sys_select(s+1,&fds,NULL, NULL);
|
||||
if (num > 0)
|
||||
{
|
||||
c = accept(s, (struct sockaddr*)&addr, &in_addrlen);
|
||||
if (c != -1) {
|
||||
if (fork() == 0)
|
||||
{
|
||||
close(s);
|
||||
agent_child(c);
|
||||
exit(0);
|
||||
} else {
|
||||
close(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
pstring configfile;
|
||||
|
||||
TimeInit();
|
||||
|
||||
setup_logging(argv[0],True);
|
||||
|
||||
charset_initialise();
|
||||
|
||||
pstrcpy(configfile,CONFIGFILE);
|
||||
|
||||
if (!lp_load(configfile,True,False,False)) {
|
||||
DEBUG(0,("Unable to load config file\n"));
|
||||
}
|
||||
|
||||
start_agent();
|
||||
return 0;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user