mirror of
https://github.com/samba-team/samba.git
synced 2025-01-11 05:18:09 +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 294b653f2e
)
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…
Reference in New Issue
Block a user