summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Leighton <lkcl@samba.org>1999-12-03 18:16:08 +0000
committerLuke Leighton <lkcl@samba.org>1999-12-03 18:16:08 +0000
commit7d01f964ff3c1a11bd72d987312f9826fee1c124 (patch)
tree74a89a0a240cd6fd8389efd569e7ba9a3415018a
parent69683dc27a8eab7a97f580050c71ab64f1d58987 (diff)
downloadsamba-7d01f964ff3c1a11bd72d987312f9826fee1c124.tar.gz
samba-7d01f964ff3c1a11bd72d987312f9826fee1c124.tar.bz2
samba-7d01f964ff3c1a11bd72d987312f9826fee1c124.zip
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)
-rw-r--r--source3/Makefile.in11
-rw-r--r--source3/include/client.h1
-rw-r--r--source3/include/proto.h7
-rw-r--r--source3/libsmb/clientgen.c111
-rw-r--r--source3/libsmb/pwd_cache.c8
-rw-r--r--source3/rpc_client/cli_connect.c2
-rw-r--r--source3/rpc_client/cli_use.c4
-rw-r--r--source3/rpcclient/rpcclient.c2
-rw-r--r--source3/utils/smb-agent.c347
9 files changed, 487 insertions, 6 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in
index 42e7e07e36..5e9330e6ec 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -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)
diff --git a/source3/include/client.h b/source3/include/client.h
index edc20bdde0..821a333e54 100644
--- a/source3/include/client.h
+++ b/source3/include/client.h
@@ -126,6 +126,7 @@ struct cli_state
size_t nt_cli_chal_len;
BOOL use_ntlmv2;
+ BOOL redirect;
uint32 sesskey;
int serverzone;
diff --git a/source3/include/proto.h b/source3/include/proto.h
index 1f2e238d58..331725daea 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -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,
diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c
index 5f898a8b0e..218ab67758 100644
--- a/source3/libsmb/clientgen.c
+++ b/source3/libsmb/clientgen.c
@@ -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))
diff --git a/source3/libsmb/pwd_cache.c b/source3/libsmb/pwd_cache.c
index 548777d434..dd42114343 100644
--- a/source3/libsmb/pwd_cache.c
+++ b/source3/libsmb/pwd_cache.c
@@ -43,6 +43,14 @@ void pwd_init(struct pwd_info *pwd)
}
/****************************************************************************
+returns NULL password flag
+****************************************************************************/
+BOOL pwd_is_nullpwd(const struct pwd_info *pwd)
+{
+ return pwd->null_pwd;
+}
+
+/****************************************************************************
de-obfuscates a password
****************************************************************************/
static void pwd_deobfuscate(const struct pwd_info *pwd)
diff --git a/source3/rpc_client/cli_connect.c b/source3/rpc_client/cli_connect.c
index 6f63d5356f..147be96ba4 100644
--- a/source3/rpc_client/cli_connect.c
+++ b/source3/rpc_client/cli_connect.c
@@ -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)
{
diff --git a/source3/rpc_client/cli_use.c b/source3/rpc_client/cli_use.c
index 17458ffacd..31e3b69b2e 100644
--- a/source3/rpc_client/cli_use.c
+++ b/source3/rpc_client/cli_use.c
@@ -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))
{
diff --git a/source3/rpcclient/rpcclient.c b/source3/rpcclient/rpcclient.c
index 2ae55baac0..d73652b5cd 100644
--- a/source3/rpcclient/rpcclient.c
+++ b/source3/rpcclient/rpcclient.c
@@ -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");
}
diff --git a/source3/utils/smb-agent.c b/source3/utils/smb-agent.c
new file mode 100644
index 0000000000..52feda2bea
--- /dev/null
+++ b/source3/utils/smb-agent.c
@@ -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;
+}