From 7d01f964ff3c1a11bd72d987312f9826fee1c124 Mon Sep 17 00:00:00 2001 From: Luke Leighton Date: Fri, 3 Dec 1999 18:16:08 +0000 Subject: 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) --- source3/Makefile.in | 11 +- source3/include/client.h | 1 + source3/include/proto.h | 7 +- source3/libsmb/clientgen.c | 111 +++++++++++++ source3/libsmb/pwd_cache.c | 8 + source3/rpc_client/cli_connect.c | 2 +- source3/rpc_client/cli_use.c | 4 +- source3/rpcclient/rpcclient.c | 2 +- source3/utils/smb-agent.c | 347 +++++++++++++++++++++++++++++++++++++++ 9 files changed, 487 insertions(+), 6 deletions(-) create mode 100644 source3/utils/smb-agent.c (limited to 'source3') 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 @@ -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 ****************************************************************************/ 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; +} -- cgit