1
0
mirror of https://github.com/samba-team/samba.git synced 2025-08-09 17:49:29 +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 commit is contained in:
Luke Leighton
-
parent f33e4ca930
commit 294b653f2e
9 changed files with 487 additions and 6 deletions

View File

@ -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)

View File

@ -126,6 +126,7 @@ struct cli_state
size_t nt_cli_chal_len;
BOOL use_ntlmv2;
BOOL redirect;
uint32 sesskey;
int serverzone;

View File

@ -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,

View File

@ -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))

View File

@ -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
****************************************************************************/

View File

@ -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)
{

View File

@ -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))
{

View File

@ -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
source/utils/smb-agent.c Normal file
View 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;
}