cool! a unix socket smb redirector. code based on smbfilter and
authorLuke Leighton <lkcl@samba.org>
Fri, 3 Dec 1999 18:16:08 +0000 (18:16 +0000)
committerLuke Leighton <lkcl@samba.org>
Fri, 3 Dec 1999 18:16:08 +0000 (18:16 +0000)
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)

source3/Makefile.in
source3/include/client.h
source3/include/proto.h
source3/libsmb/clientgen.c
source3/libsmb/pwd_cache.c
source3/rpc_client/cli_connect.c
source3/rpc_client/cli_use.c
source3/rpcclient/rpcclient.c
source3/utils/smb-agent.c [new file with mode: 0644]

index 42e7e07e36e046ff27eaa92394654cf22151baaa..5e9330e6ec3940e7a054f3d181f8e324b492d405 100644 (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)
index edc20bdde02e00ce48bf7a9b7782f2c59da0d34a..821a333e546eaf317b5d5ac17dc12a6f4a8272e5 100644 (file)
@@ -126,6 +126,7 @@ struct cli_state
        size_t nt_cli_chal_len;
 
        BOOL use_ntlmv2;
+       BOOL redirect;
 
        uint32 sesskey;
        int serverzone;
index 1f2e238d58bbc9035a5b9a70923cbe74f4b269dc..331725daeacd840afdfca937ca956c79ba094e09 100644 (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,
index 5f898a8b0ec44a19ac5b5dfaa81d43b0c86682b1..218ab67758f0bf8ce3a70dcbe4c877d1974fc4e4 100644 (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))
index 548777d434d75cb868ffe26182a3275f55d7e2f2..dd42114343ccc232d5f6ca791c2e9ce34b1a28ae 100644 (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
 ****************************************************************************/
index 6f63d5356fe254683f0e3b0925ec88531b5bc9a9..147be96ba4e8e38ca1ce307dc9918d9e54d76209 100644 (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)
        {
index 17458ffacdfb4f118ee9be310f0687652f9107c4..31e3b69b2efb624d3ebfda0584df0d00f931e7de 100644 (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))
        {
index 2ae55baac02a7d771f3841bd6c07518bb5abb57c..d73652b5cdb12f494b12ae52dd4be22d2f42a1b2 100644 (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");
                }
diff --git a/source3/utils/smb-agent.c b/source3/utils/smb-agent.c
new file mode 100644 (file)
index 0000000..52feda2
--- /dev/null
@@ -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;
+}