From a0ba234cf9b40adf6b5390e4e67730163a42883f Mon Sep 17 00:00:00 2001 From: Luke Leighton Date: Mon, 6 Dec 1999 00:44:32 +0000 Subject: the first independent msrpc daemon - lsarpcd. one horrible cut / paste job from smbd, plus a code split of shared components between the two. the job is not _yet_ complete, as i need to be able to do a become_user() call for security reasons. i picked lsarpcd first because you don't _need_ security on it (microsoft botched so badly on this one, it's not real. at least they fixed this in nt5 with restrictanonymous=0x2). fixing this involves sending the current smb and unix credentials down the unix pipe so that the daemon it eventually goes to can pick them up at the other end. i can't believe this all worked!!! (This used to be commit 2245b0c6d13c7c5886e81f9137b05df883598c26) --- source3/Makefile.in | 48 ++- source3/include/ntdomain.h | 2 + source3/include/proto.h | 60 +++- source3/lib/msrpc-agent.c | 7 +- source3/lib/msrpc-client.c | 56 +++- source3/lib/passcheck.c | 289 +++++++++++++++++ source3/lib/username.c | 29 ++ source3/lib/util_sock.c | 6 +- source3/lib/vuser.c | 169 ++++++++++ source3/lsarpcd/lsarpcd.c | 653 ++++++++++++++++++++++++++++++++++++++ source3/lsarpcd/lsarpcd_process.c | 401 +++++++++++++++++++++++ source3/rpc_parse/parse_prs.c | 10 + source3/rpc_server/srv_pipe.c | 120 ++++++- source3/rpc_server/srv_pipe_hnd.c | 25 ++ source3/smbd/challenge.c | 61 ++++ source3/smbd/password.c | 501 ----------------------------- source3/smbd/reply.c | 5 +- source3/smbd/server.c | 12 + 18 files changed, 1904 insertions(+), 550 deletions(-) create mode 100644 source3/lib/passcheck.c create mode 100644 source3/lib/vuser.c create mode 100644 source3/lsarpcd/lsarpcd.c create mode 100644 source3/lsarpcd/lsarpcd_process.c create mode 100644 source3/smbd/challenge.c diff --git a/source3/Makefile.in b/source3/Makefile.in index 6dac160ffe..2ded87c858 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -37,6 +37,7 @@ INSTALLPERMS = 0755 # These can be overridden by command line switches (see smbd(8)) # or in smb.conf (see smb.conf(5)) SMBLOGFILE = $(VARDIR)/log.smb +LSARPCLOGFILE = $(VARDIR)/log.lsarpc NMBLOGFILE = $(VARDIR)/log.nmb CONFIGFILE = $(LIBDIR)/smb.conf LMHOSTSFILE = $(LIBDIR)/lmhosts @@ -77,14 +78,21 @@ PASSWD_FLAGS = \ -DSMB_PASSGRP_FILE=\"$(SMB_PASSGRP_FILE)\" \ -DSMB_GROUP_FILE=\"$(SMB_GROUP_FILE)\" \ -DSMB_ALIAS_FILE=\"$(SMB_ALIAS_FILE)\" -FLAGS1 = $(CFLAGS) -Iinclude -I$(srcdir)/include -I$(srcdir)/ubiqx -I$(srcdir)/smbwrapper $(CPPFLAGS) -DSMBLOGFILE=\"$(SMBLOGFILE)\" -DNMBLOGFILE=\"$(NMBLOGFILE)\" +FLAGS1 = $(CFLAGS) \ + -Iinclude -I$(srcdir)/include \ + -I$(srcdir)/ubiqx \ + -I$(srcdir)/smbwrapper \ + $(CPPFLAGS) \ + -DLSARPCLOGFILE=\"$(LSARPCLOGFILE)\" \ + -DSMBLOGFILE=\"$(SMBLOGFILE)\" \ + -DNMBLOGFILE=\"$(NMBLOGFILE)\" FLAGS2 = -DCONFIGFILE=\"$(CONFIGFILE)\" -DLMHOSTSFILE=\"$(LMHOSTSFILE)\" FLAGS3 = -DSWATDIR=\"$(SWATDIR)\" -DSBINDIR=\"$(SBINDIR)\" -DLOCKDIR=\"$(LOCKDIR)\" -DSMBRUN=\"$(SMBRUN)\" -DCODEPAGEDIR=\"$(CODEPAGEDIR)\" FLAGS4 = -DDRIVERFILE=\"$(DRIVERFILE)\" -DBINDIR=\"$(BINDIR)\" -DFORMSFILE=\"$(FORMSFILE)\" -DNTDRIVERSDIR=\"$(NTDRIVERSDIR)\" FLAGS5 = $(FLAGS1) $(FLAGS2) $(FLAGS3) $(FLAGS4) -DHAVE_INCLUDES_H FLAGS = $(FLAGS5) $(PASSWD_FLAGS) -SPROGS = bin/smbd bin/nmbd bin/swat +SPROGS = bin/smbd bin/lsarpcd bin/nmbd bin/swat PROGS1 = bin/smbclient bin/testparm bin/testprns bin/smbrun bin/smbstatus PROGS2 = bin/rpcclient bin/smbpasswd bin/make_smbcodepage bin/debug2html PROGS3 = @WRAP@ @WRAP32@ @@ -107,6 +115,7 @@ LIB_OBJ = lib/charcnv.o lib/charset.o lib/debug.o lib/fault.o \ lib/membuffer.o lib/netmask.o lib/pidfile.o lib/replace.o \ lib/signal.o lib/slprintf.o lib/system.o lib/doscalls.o lib/time.o \ lib/ufc.o lib/util.o lib/genrand.o lib/username.o \ + lib/vuser.o \ lib/access.o lib/smbrun.o \ lib/bitmap.o lib/crc32.o lib/util_sid.o lib/snprintf.o \ lib/util_str.o lib/util_unistr.o \ @@ -114,7 +123,8 @@ LIB_OBJ = lib/charcnv.o lib/charset.o lib/debug.o lib/fault.o \ lib/util_sock.o lib/unix_sec_ctxt.o \ lib/util_array.o \ lib/vagent.o \ - lib/util_hnd.o + lib/util_hnd.o \ + lib/passcheck.o UBIQX_OBJ = ubiqx/ubi_BinTree.o ubiqx/ubi_Cache.o ubiqx/ubi_SplayTree.o \ ubiqx/ubi_dLinkList.o ubiqx/ubi_sLinkList.o @@ -126,20 +136,24 @@ LIBSMB_OBJ = libsmb/clientgen.o libsmb/namequery.o libsmb/nmblib.o \ libsmb/smberr.o libsmb/credentials.o libsmb/pwd_cache.o \ libsmb/passchange.o -RPC_SERVER_OBJ = \ +RPC_SRVUTIL_OBJ = \ + rpc_server/srv_pipe_hnd.o \ + rpc_server/srv_lookup.o \ + rpc_server/srv_pipe.o + +RPC_SERVER_OBJ1 = \ rpc_server/srv_lsa.o \ rpc_server/srv_netlog.o \ - rpc_server/srv_pipe_hnd.o \ rpc_server/srv_reg.o \ rpc_server/srv_samr.o \ rpc_server/srv_srvsvc.o \ rpc_server/srv_svcctl.o \ - rpc_server/srv_pipe.o \ - rpc_server/srv_lookup.o \ rpc_server/srv_wkssvc.o \ rpc_server/srv_brs.o \ rpc_server/srv_spoolss.o +RPC_SERVER_OBJ = $(RPC_SERVER_OBJ1) $(RPC_SRVUTIL_OBJ) + RPC_PARSE_OBJ1 = rpc_parse/parse_lsa.o \ rpc_parse/parse_net.o \ rpc_parse/parse_reg.o \ @@ -204,16 +218,28 @@ SMBD_OBJ1 = smbd/server.o smbd/files.o smbd/chgpasswd.o smbd/connection.o \ smbd/$(QUOTAOBJS) smbd/reply.o smbd/ssl.o smbd/trans2.o smbd/uid.o \ smbd/dosmode.o smbd/filename.o smbd/open.o smbd/close.o smbd/blocking.o \ smbd/process.o smbd/oplock.o smbd/service.o smbd/error.o smbd/vfs.o \ - smbd/vfs-wrap.o printing/nt_printing.o smbd/dfs.o + smbd/vfs-wrap.o printing/nt_printing.o smbd/dfs.o \ + smbd/challenge.o PRINTING_OBJ = printing/pcap.o printing/print_svid.o printing/printing.o +LSARPCD_OBJ1 = lsarpcd/lsarpcd.o \ + lsarpcd/lsarpcd_process.o \ + rpc_server/srv_lsa.o \ + smbd/uid.o + SMBD_OBJ = $(SMBD_OBJ1) $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) \ $(RPC_SERVER_OBJ) $(RPC_CLIENT_OBJ) $(RPC_PARSE_OBJ) \ $(LOCKING_OBJ) $(SAMPASSDB_OBJ) $(PASSDB_OBJ) $(GROUPDB_OBJ) \ $(LIBSTATUS_OBJ) $(PRINTING_OBJ) $(PROFILE_OBJ) $(LIB_OBJ) +LSARPCD_OBJ = $(LSARPCD_OBJ1) $(PARAM_OBJ) $(LIBSMB_OBJ) \ + $(UBIQX_OBJ) \ + $(RPC_SRVUTIL_OBJ) $(RPC_CLIENT_OBJ) $(RPC_PARSE_OBJ) \ + $(LOCKING_OBJ) $(SAMPASSDB_OBJ) $(PASSDB_OBJ) $(GROUPDB_OBJ) \ + $(LIBSTATUS_OBJ) $(PRINTING_OBJ) $(PROFILE_OBJ) $(LIB_OBJ) + NMBD_OBJ1 = nmbd/asyncdns.o nmbd/nmbd.o nmbd/nmbd_become_dmb.o \ nmbd/nmbd_become_lmb.o nmbd/nmbd_browserdb.o \ nmbd/nmbd_browsesync.o nmbd/nmbd_elections.o \ @@ -331,7 +357,7 @@ RPCTORTURE_OBJ = utils/rpctorture.o \ $(RPC_CLIENT_OBJ) $(RPC_PARSE_OBJ) \ $(PASSDB_OBJ) -PROTO_OBJ = $(SMBD_OBJ) $(NMBD_OBJ) $(SWAT_OBJ) $(CLIENT_OBJ) \ +PROTO_OBJ = $(LSARPCD_OBJ) $(SMBD_OBJ) $(NMBD_OBJ) $(SWAT_OBJ) $(CLIENT_OBJ) \ $(RPCCLIENT_OBJ) $(SMBWRAPPER_OBJ) PICOBJS = $(SMBWRAPPER_OBJ:.o=.po) @@ -421,6 +447,10 @@ bin/smbd: $(SMBD_OBJ) bin/.dummy @echo Linking $@ @$(CC) $(FLAGS) -o $@ $(SMBD_OBJ) $(LDFLAGS) $(LIBS) +bin/lsarpcd: $(LSARPCD_OBJ) bin/.dummy + @echo Linking $@ + @$(CC) $(FLAGS) -o $@ $(LSARPCD_OBJ) $(LDFLAGS) $(LIBS) + bin/nmbd: $(NMBD_OBJ) bin/.dummy @echo Linking $@ @$(CC) $(FLAGS) -o $@ $(NMBD_OBJ) $(LDFLAGS) $(LIBS) diff --git a/source3/include/ntdomain.h b/source3/include/ntdomain.h index 9dd6c2d3a7..95ba141b10 100644 --- a/source3/include/ntdomain.h +++ b/source3/include/ntdomain.h @@ -74,6 +74,8 @@ typedef struct pipes_struct fstring name; fstring pipe_srv_name; + struct msrpc_state *m; + prs_struct rhdr; /* output header */ prs_struct rfault; /* fault */ prs_struct rdata; /* output data */ diff --git a/source3/include/proto.h b/source3/include/proto.h index ed1f1aef58..b94e13aa0e 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -287,6 +287,8 @@ void start_msrpc_agent(char *pipe_name); /*The following definitions come from lib/msrpc-client.c */ BOOL msrpc_receive(struct msrpc_state *msrpc); +BOOL msrpc_send_prs(struct msrpc_state *msrpc, prs_struct *ps); +BOOL msrpc_receive_prs(struct msrpc_state *msrpc, prs_struct *ps); BOOL msrpc_send(struct msrpc_state *msrpc, BOOL show); BOOL msrpc_connect(struct msrpc_state *msrpc, const char *pipe_name); void msrpc_init_creds(struct msrpc_state *msrpc, const struct user_credentials *usr); @@ -317,6 +319,18 @@ void msrpc_net_use_enum(uint32 *num_cons, struct use_info ***use); int get_netmask(struct in_addr *ipaddr, struct in_addr *nmask); +/*The following definitions come from lib/passcheck.c */ + +BOOL smb_password_ok(struct smb_passwd *smb_pass, uchar challenge[8], + const char *user, const char *domain, + uchar *lm_pass, size_t lm_pwd_len, + uchar *nt_pass, size_t nt_pwd_len, + uchar sess_key[16]); +BOOL pass_check_smb(struct smb_passwd *smb_pass, char *domain, uchar *chal, + uchar *lm_pwd, size_t lm_pwd_len, + uchar *nt_pwd, size_t nt_pwd_len, + struct passwd *pwd, uchar user_sess_key[16]); + /*The following definitions come from lib/pidfile.c */ pid_t pidfile_pid(char *name); @@ -429,6 +443,7 @@ char *uidtoname(uid_t uid); char *get_home_dir(char *user); BOOL map_username(char *user); const struct passwd *Get_Pwnam(char *user,BOOL allow_change); +BOOL user_ok(char *user,int snum); BOOL user_in_list(char *user,char *list); /*The following definitions come from lib/util.c */ @@ -716,6 +731,13 @@ void init_sock_redir(struct vagent_ops*va); void free_sock_redir(struct vagent_ops*va); void start_agent(struct vagent_ops *va); +/*The following definitions come from lib/vuser.c */ + +user_struct *get_valid_user_struct(uint16 vuid); +void invalidate_vuid(uint16 vuid); +char *validated_username(uint16 vuid); +uint16 register_vuid(uid_t uid,gid_t gid, char *unix_name, char *requested_name, BOOL guest, uchar user_sess_key[16]); + /*The following definitions come from libsmb/clientgen.c */ void copy_user_creds(struct user_credentials *to, @@ -1016,6 +1038,17 @@ struct shmem_ops *smb_shm_open(int ronly); struct shmem_ops *sysv_shm_open(int ronly); +/*The following definitions come from lsarpcd/lsarpcd.c */ + +BOOL reload_services(BOOL test); +void exit_server(char *reason); + +/*The following definitions come from lsarpcd/lsarpcd_process.c */ + +BOOL receive_next_smb(char *inbuf, int bufsize, int timeout); +void process_smb(char *inbuf, char *outbuf); +void lsarpcd_process(void); + /*The following definitions come from mem_man/mem_man.c */ void *smb_mem_malloc(size_t size,char *file,int line); @@ -2697,6 +2730,7 @@ BOOL net_io_r_sam_sync(char *desc, uint8 sess_key[16], /*The following definitions come from rpc_parse/parse_prs.c */ void prs_debug(prs_struct *ps, int depth, char *desc, char *fn_name); +void prs_debug_out(prs_struct *ps, int level); void prs_init(prs_struct *ps, uint32 size, uint8 align, uint32 margin, BOOL io); @@ -3622,6 +3656,10 @@ BOOL api_netlog_rpc(pipes_struct *p, prs_struct *data); BOOL create_rpc_reply(pipes_struct *p, uint32 data_start, uint32 data_end); +void close_msrpc_command_processor(void); +void add_msrpc_command_processor(char* pipe_name, + char* process_name, + BOOL (*fn) (pipes_struct *, prs_struct *)); BOOL rpc_command(pipes_struct *p, prs_struct *pd); BOOL api_rpcTNP(pipes_struct *p, char *rpc_name, struct api_struct *api_rpc_cmds, prs_struct *data); @@ -3977,6 +4015,12 @@ void remove_pending_lock_requests_by_fid(files_struct *fsp); void remove_pending_lock_requests_by_mid(int mid); void process_blocking_lock_queue(time_t t); +/*The following definitions come from smbd/challenge.c */ + +void generate_next_challenge(char *challenge); +BOOL set_challenge(unsigned char *challenge); +BOOL last_challenge(unsigned char *challenge); + /*The following definitions come from smbd/chgpasswd.c */ BOOL chgpasswd(char *name,char *oldpass,char *newpass, BOOL as_root); @@ -4181,25 +4225,9 @@ void check_kernel_oplocks(void); /*The following definitions come from smbd/password.c */ -void generate_next_challenge(char *challenge); -BOOL set_challenge(unsigned char *challenge); -user_struct *get_valid_user_struct(uint16 vuid); -void invalidate_vuid(uint16 vuid); -char *validated_username(uint16 vuid); -uint16 register_vuid(uid_t uid,gid_t gid, char *unix_name, char *requested_name, BOOL guest, uchar user_sess_key[16]); void add_session_user(char *user); -BOOL smb_password_ok(struct smb_passwd *smb_pass, uchar chal[8], - const char *user, const char *domain, - uchar *lm_pass, size_t lm_pwd_len, - uchar *nt_pass, size_t nt_pwd_len, - uchar sess_key[16]); -BOOL pass_check_smb(struct smb_passwd *smb_pass, char *domain, uchar *chal, - uchar *lm_pwd, size_t lm_pwd_len, - uchar *nt_pwd, size_t nt_pwd_len, - struct passwd *pwd, uchar user_sess_key[16]); BOOL password_ok(char *user, char *password, int pwlen, struct passwd *pwd, uchar user_sess_key[16]); -BOOL user_ok(char *user,int snum); BOOL authorise_login(int snum,char *user,char *password, int pwlen, BOOL *guest,BOOL *force,uint16 vuid); BOOL check_hosts_equiv(char *user); diff --git a/source3/lib/msrpc-agent.c b/source3/lib/msrpc-agent.c index 4612aae14f..0bb9429ecb 100644 --- a/source3/lib/msrpc-agent.c +++ b/source3/lib/msrpc-agent.c @@ -254,8 +254,9 @@ void start_msrpc_agent(char *pipe_name) 0 }; - CatchChild(); - - start_agent(&va); + if (fork() == 0) + { + start_agent(&va); + } } diff --git a/source3/lib/msrpc-client.c b/source3/lib/msrpc-client.c index eacc25341e..fb82c54700 100644 --- a/source3/lib/msrpc-client.c +++ b/source3/lib/msrpc-client.c @@ -34,6 +34,54 @@ BOOL msrpc_receive(struct msrpc_state *msrpc) return receive_smb(msrpc->fd,msrpc->inbuf,0); } +/**************************************************************************** + send an smb to a fd and re-establish if necessary +****************************************************************************/ +BOOL msrpc_send_prs(struct msrpc_state *msrpc, prs_struct *ps) +{ + size_t len = mem_buf_len(ps->data); + + _smb_setlen(msrpc->outbuf, len); + mem_buf_copy(&msrpc->outbuf[4], ps->data, 0, len); + + if (msrpc_send(msrpc, True)) + { + prs_mem_free(ps); + return True; + } + return False; +} + +/**************************************************************************** + receive msrpc packet +****************************************************************************/ +BOOL msrpc_receive_prs(struct msrpc_state *msrpc, prs_struct *ps) +{ + int len; + char *data; + + if (!msrpc_receive(msrpc)) + { + return False; + } + + len = smb_len(msrpc->inbuf); + + dump_data(10, msrpc->inbuf, len+4); + + prs_init(ps, len, 4, 0, False); + ps->offset = len; + data = mem_data(&ps->data, 0); + if (data == NULL || len <= 0) + { + return False; + } + + memcpy(data, smb_base(msrpc->inbuf), len); + + return True; +} + /**************************************************************************** send an smb to a fd and re-establish if necessary ****************************************************************************/ @@ -62,8 +110,6 @@ BOOL msrpc_send(struct msrpc_state *msrpc, BOOL show) return True; } - - /**************************************************************************** open the msrpcent sockets ****************************************************************************/ @@ -115,7 +161,7 @@ void msrpc_sockopt(struct msrpc_state *msrpc, char *options) } -static int msrpc_init_redirect(struct msrpc_state *msrpc, +static BOOL msrpc_init_redirect(struct msrpc_state *msrpc, const char* pipe_name, const struct user_credentials *usr) { @@ -135,7 +181,7 @@ static int msrpc_init_redirect(struct msrpc_state *msrpc, if (sock < 0) { - return sock; + return False; } ZERO_STRUCT(data); @@ -196,7 +242,7 @@ static int msrpc_init_redirect(struct msrpc_state *msrpc, msrpc->fd = sock; msrpc->usr.reuse = False; - return sock; + return True; } BOOL msrpc_connect_auth(struct msrpc_state *msrpc, diff --git a/source3/lib/passcheck.c b/source3/lib/passcheck.c new file mode 100644 index 0000000000..195a404ff3 --- /dev/null +++ b/source3/lib/passcheck.c @@ -0,0 +1,289 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Password and authentication handling + Copyright (C) Andrew Tridgell 1992-1998 + + 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" + +extern int DEBUGLEVEL; +extern int Protocol; + +extern pstring scope; +extern pstring global_myname; +extern fstring global_myworkgroup; + + + +/**************************************************************************** +core of smb password checking routine. +****************************************************************************/ +static BOOL smb_pwd_check_ntlmv1(char *password, unsigned char *part_passwd, + unsigned char *c8, + uchar sess_key[16]) +{ + /* Finish the encryption of part_passwd. */ + unsigned char p24[24]; + + if (part_passwd == NULL) + DEBUG(10,("No password set - allowing access\n")); + /* No password set - always true ! */ + if (part_passwd == NULL) + return True; + + SMBOWFencrypt(part_passwd, c8, p24); + if (sess_key != NULL) + { + SMBsesskeygen_ntv1(part_passwd, NULL, sess_key); + } + +#if DEBUG_PASSWORD + DEBUG(100,("Part password (P16) was |")); + dump_data(100, part_passwd, 16); + DEBUG(100,("Password from client was |")); + dump_data(100, password, 24); + DEBUG(100,("Given challenge was |")); + dump_data(100, c8, 8); + DEBUG(100,("Value from encryption was |")); + dump_data(100, p24, 24); +#endif + return (memcmp(p24, password, 24) == 0); +} + +/**************************************************************************** +core of smb password checking routine. +****************************************************************************/ +static BOOL smb_pwd_check_ntlmv2(char *password, size_t pwd_len, + unsigned char *part_passwd, + unsigned char const *c8, + const char *user, const char *domain, + char *sess_key) +{ + /* Finish the encryption of part_passwd. */ + unsigned char kr[16]; + unsigned char resp[16]; + + if (part_passwd == NULL) + { + DEBUG(10,("No password set - allowing access\n")); + } + /* No password set - always true ! */ + if (part_passwd == NULL) + { + return True; + } + + ntv2_owf_gen(part_passwd, user, domain, kr); + SMBOWFencrypt_ntv2(kr, c8, 8, password+16, pwd_len-16, resp); + if (sess_key != NULL) + { + SMBsesskeygen_ntv2(kr, resp, sess_key); + } + +#if DEBUG_PASSWORD + DEBUG(100,("Part password (P16) was |")); + dump_data(100, part_passwd, 16); + DEBUG(100,("Password from client was |")); + dump_data(100, password, pwd_len); + DEBUG(100,("Given challenge was |")); + dump_data(100, c8, 8); + DEBUG(100,("Value from encryption was |")); + dump_data(100, resp, 16); +#endif + + return (memcmp(resp, password, 16) == 0); +} + +/**************************************************************************** + Do a specific test for an smb password being correct, given a smb_password and + the lanman and NT responses. +****************************************************************************/ +BOOL smb_password_ok(struct smb_passwd *smb_pass, uchar challenge[8], + const char *user, const char *domain, + uchar *lm_pass, size_t lm_pwd_len, + uchar *nt_pass, size_t nt_pwd_len, + uchar sess_key[16]) +{ + if (smb_pass == NULL) + { + return False; + } + + DEBUG(4,("Checking SMB password for user %s\n", + smb_pass->unix_name)); + + if (smb_pass->acct_ctrl & ACB_DISABLED) + { + DEBUG(3,("account for user %s was disabled.\n", + smb_pass->unix_name)); + return False; + } + + if (challenge == NULL) + { + DEBUG(1,("no challenge available - password failed\n")); + return False; + } + + if ((Protocol >= PROTOCOL_NT1) && (smb_pass->smb_nt_passwd != NULL)) + { + /* We have the NT MD4 hash challenge available - see if we can + use it (ie. does it exist in the smbpasswd file). + */ + if (lp_server_ntlmv2() != False && nt_pwd_len > 24) + { + DEBUG(4,("smb_password_ok: Check NTLMv2 password\n")); + if (smb_pwd_check_ntlmv2(nt_pass, nt_pwd_len, + (uchar *)smb_pass->smb_nt_passwd, + challenge, user, domain, + sess_key)) + { + return True; + } + } + if (lp_server_ntlmv2() != True && nt_pwd_len == 24) + { + DEBUG(4,("smb_password_ok: Check NT MD4 password\n")); + if (smb_pwd_check_ntlmv1((char *)nt_pass, + (uchar *)smb_pass->smb_nt_passwd, + challenge, + sess_key)) + { + DEBUG(4,("NT MD4 password check succeeded\n")); + return True; + } + } + DEBUG(4,("NT MD4 password check failed\n")); + } + + if (lp_server_ntlmv2() == True) + { + DEBUG(4,("Not checking LM MD4 password\n")); + return False; + } + + /* Try against the lanman password. smb_pass->smb_passwd == NULL means + no password, allow access. */ + + DEBUG(4,("Checking LM MD4 password\n")); + + if ((smb_pass->smb_passwd == NULL) && + (smb_pass->acct_ctrl & ACB_PWNOTREQ)) + { + DEBUG(4,("no password required for user %s\n", + smb_pass->unix_name)); + return True; + } + + if ((smb_pass->smb_passwd != NULL) && + smb_pwd_check_ntlmv1((char *)lm_pass, + (uchar *)smb_pass->smb_passwd, + challenge, NULL)) + { + DEBUG(4,("LM MD4 password check succeeded\n")); + return(True); + } + + DEBUG(4,("LM MD4 password check failed\n")); + + return False; +} + + +/**************************************************************************** +check if a username/password is OK assuming the password is a 24 byte +SMB hash +return True if the password is correct, False otherwise +****************************************************************************/ +BOOL pass_check_smb(struct smb_passwd *smb_pass, char *domain, uchar *chal, + uchar *lm_pwd, size_t lm_pwd_len, + uchar *nt_pwd, size_t nt_pwd_len, + struct passwd *pwd, uchar user_sess_key[16]) +{ + const struct passwd *pass; + struct passwd pw; + char *user = NULL; + + if (smb_pass == NULL) + { + DEBUG(3,("Couldn't find user %s in smb_passwd file.\n", user)); + return False; + } + + user = smb_pass->unix_name; + + if (lm_pwd == NULL || nt_pwd == NULL) + { + return False; + } + + if (pwd != NULL && user == NULL) + { + pass = (struct passwd *) pwd; + user = pass->pw_name; + } + else + { + pass = Get_Pwnam(user,True); + if (pass == NULL) + { + DEBUG(3,("Couldn't find user %s\n",user)); + return False; + } + memcpy(&pw, pass, sizeof(struct passwd)); + pass = &pw; + } + + /* Quit if the account was disabled. */ + if (smb_pass->acct_ctrl & ACB_DISABLED) { + DEBUG(3,("account for user %s was disabled.\n", user)); + return False; + } + + /* Ensure the uid's match */ + if (smb_pass->unix_uid != pass->pw_uid) + { + DEBUG(3,("Error : UNIX (%d) and SMB (%d) uids in password files do not match !\n", pass->pw_uid, smb_pass->unix_uid)); + return False; + } + + if (lm_pwd[0] == '\0' && IS_BITS_SET_ALL(smb_pass->acct_ctrl, ACB_PWNOTREQ) && lp_null_passwords()) + { + DEBUG(3,("account for user %s has no password and null passwords are allowed.\n", smb_pass->unix_name)); + return(True); + } + + if (smb_password_ok(smb_pass, chal, user, domain, + lm_pwd, lm_pwd_len, + nt_pwd, nt_pwd_len, + user_sess_key)) + { + if (user_sess_key != NULL) + { +#ifdef DEBUG_PASSWORD + DEBUG(100,("user session key: ")); + dump_data(100, user_sess_key, 16); +#endif + } + return(True); + } + + DEBUG(3,("Error pass_check_smb failed\n")); + return False; +} + diff --git a/source3/lib/username.c b/source3/lib/username.c index 87fe39466f..9f51d06642 100644 --- a/source3/lib/username.c +++ b/source3/lib/username.c @@ -565,6 +565,35 @@ static BOOL user_in_group_list(char *user,char *gname) return False; } +/**************************************************************************** +check if a username is valid +****************************************************************************/ +BOOL user_ok(char *user,int snum) +{ + pstring valid, invalid; + BOOL ret; + + StrnCpy(valid, lp_valid_users(snum), sizeof(pstring)); + StrnCpy(invalid, lp_invalid_users(snum), sizeof(pstring)); + + string_sub(valid,"%S",lp_servicename(snum)); + string_sub(invalid,"%S",lp_servicename(snum)); + + ret = !user_in_list(user,invalid); + + if (ret && valid && *valid) { + ret = user_in_list(user,valid); + } + + if (ret && lp_onlyuser(snum)) { + char *user_list = lp_username(snum); + string_sub(user_list,"%S",lp_servicename(snum)); + ret = user_in_list(user,user_list); + } + + return(ret); +} + /**************************************************************************** check if a user is in a user list - can check combinations of UNIX and netgroup lists. diff --git a/source3/lib/util_sock.c b/source3/lib/util_sock.c index 71e51d2771..d9b0f97259 100644 --- a/source3/lib/util_sock.c +++ b/source3/lib/util_sock.c @@ -901,6 +901,9 @@ int create_pipe_socket(char *dir, int dir_perms, int s; struct sockaddr_un sa; + DEBUG(10,("create_pipe_socket: %s %d %s %d\n", + dir, dir_perms, path, path_perms)); + mkdir(dir, dir_perms); if (chmod(dir, dir_perms) < 0) @@ -912,7 +915,6 @@ int create_pipe_socket(char *dir, int dir_perms, if (!remove(path)) { DEBUG(0, ("remove on %s failed\n", path)); - return -1; } /* start listening on unix socket */ @@ -954,5 +956,7 @@ int create_pipe_socket(char *dir, int dir_perms, return -1; } + DEBUG(5,("unix socket opened: %s\n", path)); + return s; } diff --git a/source3/lib/vuser.c b/source3/lib/vuser.c new file mode 100644 index 0000000000..dfad258152 --- /dev/null +++ b/source3/lib/vuser.c @@ -0,0 +1,169 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Password and authentication handling + Copyright (C) Andrew Tridgell 1992-1998 + + 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" + +extern int DEBUGLEVEL; + +/* this holds info on user ids that are already validated for this VC */ +static user_struct *validated_users = NULL; +static int num_validated_users = 0; + +/**************************************************************************** +check if a uid has been validated, and return an pointer to the user_struct +if it has. NULL if not. vuid is biased by an offset. This allows us to +tell random client vuid's (normally zero) from valid vuids. +****************************************************************************/ +user_struct *get_valid_user_struct(uint16 vuid) +{ + if (vuid == UID_FIELD_INVALID) + return NULL; + vuid -= VUID_OFFSET; + if ((vuid >= (uint16)num_validated_users) || + (validated_users[vuid].uid == (uid_t)-1) || (validated_users[vuid].gid == (gid_t)-1)) + return NULL; + return &validated_users[vuid]; +} + +/**************************************************************************** +invalidate a uid +****************************************************************************/ +void invalidate_vuid(uint16 vuid) +{ + user_struct *vuser = get_valid_user_struct(vuid); + + if (vuser == NULL) return; + + vuser->uid = (uid_t)-1; + vuser->gid = (gid_t)-1; + + vuser->n_sids = 0; + + /* same number of igroups as groups */ + vuser->n_groups = 0; + + if (vuser->groups) + free((char *)vuser->groups); + + if (vuser->sids) + free((char *)vuser->sids); + + vuser->sids = NULL; + vuser->groups = NULL; +} + + +/**************************************************************************** +return a validated username +****************************************************************************/ +char *validated_username(uint16 vuid) +{ + user_struct *vuser = get_valid_user_struct(vuid); + if (vuser == NULL) + return 0; + return(vuser->name); +} + + + +/**************************************************************************** +register a uid/name pair as being valid and that a valid password +has been given. vuid is biased by an offset. This allows us to +tell random client vuid's (normally zero) from valid vuids. +****************************************************************************/ +uint16 register_vuid(uid_t uid,gid_t gid, char *unix_name, char *requested_name, BOOL guest, uchar user_sess_key[16]) +{ + user_struct *vuser; + struct passwd *pwfile; /* for getting real name from passwd file */ + + /* Ensure no vuid gets registered in share level security. */ + if(lp_security() == SEC_SHARE) + return UID_FIELD_INVALID; + +#if 0 + /* + * After observing MS-Exchange services writing to a Samba share + * I belive this code is incorrect. Each service does its own + * sessionsetup_and_X for the same user, and as each service shuts + * down, it does a user_logoff_and_X. As we are consolidating multiple + * sessionsetup_and_X's onto the same vuid here, when the first service + * shuts down, it invalidates all the open files for the other services. + * Hence I am removing this code and forcing each sessionsetup_and_X + * to get a new vuid. + * Jeremy Allison. (jallison@whistle.com). + */ + + int i; + for(i = 0; i < num_validated_users; i++) { + vuser = &validated_users[i]; + if ( vuser->uid == uid ) + return (uint16)(i + VUID_OFFSET); /* User already validated */ + } +#endif + + validated_users = (user_struct *)Realloc(validated_users, + sizeof(user_struct)* + (num_validated_users+1)); + + if (!validated_users) + { + DEBUG(0,("Failed to realloc users struct!\n")); + num_validated_users = 0; + return UID_FIELD_INVALID; + } + + vuser = &validated_users[num_validated_users]; + num_validated_users++; + + vuser->uid = uid; + vuser->gid = gid; + vuser->guest = guest; + fstrcpy(vuser->name,unix_name); + fstrcpy(vuser->requested_name,requested_name); + memcpy(vuser->dc.user_sess_key, user_sess_key, sizeof(vuser->dc.user_sess_key)); + + vuser->n_sids = 0; + vuser->sids = NULL; + + vuser->n_groups = 0; + vuser->groups = NULL; + + /* Find all the groups this uid is in and store them. + Used by become_user() */ + get_unixgroups(unix_name,uid,gid, + &vuser->n_groups, + &vuser->groups); + + DEBUG(3,("uid %d registered to name %s\n",(int)uid,unix_name)); + + DEBUG(3, ("Clearing default real name\n")); + fstrcpy(vuser->real_name, "\0"); + if (lp_unix_realname()) { + if ((pwfile=hashed_getpwnam(vuser->name))!= NULL) + { + DEBUG(3, ("User name: %s\tReal name: %s\n",vuser->name,pwfile->pw_gecos)); + fstrcpy(vuser->real_name, pwfile->pw_gecos); + } + } + + return (uint16)((num_validated_users - 1) + VUID_OFFSET); +} + diff --git a/source3/lsarpcd/lsarpcd.c b/source3/lsarpcd/lsarpcd.c new file mode 100644 index 0000000000..3c883029f0 --- /dev/null +++ b/source3/lsarpcd/lsarpcd.c @@ -0,0 +1,653 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Main SMB server routines + Copyright (C) Andrew Tridgell 1992-1998 + + 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 "trans2.h" + +pstring servicesf = CONFIGFILE; +extern pstring debugf; +extern pstring global_myname; + +int am_parent = 1; + +/* the last message the was processed */ +int last_message = -1; + +/* a useful macro to debug the last message processed */ +#define LAST_MESSAGE() smb_fn_name(last_message) + +extern pstring scope; +extern int DEBUGLEVEL; + +extern fstring remote_machine; +extern pstring myhostname; + + +/**************************************************************************** + when exiting, take the whole family +****************************************************************************/ +static void *dflt_sig(void) +{ + exit_server("caught signal"); + return NULL; +} + +/**************************************************************************** + Send a SIGTERM to our process group. +*****************************************************************************/ +static void killkids(void) +{ + if(am_parent) kill(0,SIGTERM); +} + + +/**************************************************************************** + open and listen to a socket +****************************************************************************/ +static int open_server_socket(void) +{ + int s; + fstring dir; + fstring path; + + slprintf(dir, sizeof(dir)-1, "/tmp/.msrpc"); + slprintf(path, sizeof(path)-1, "%s/lsarpc", dir); + + s = create_pipe_socket(dir, 0777, path, 0777); + + if (s == -1) + return -1; + /* ready to listen */ + if (listen(s, 5) == -1) { + DEBUG(0,("listen: %s\n", strerror(errno))); + close(s); + return -1; + } + return s; +} + +/**************************************************************************** + open the socket communication +****************************************************************************/ +static BOOL open_sockets(BOOL is_daemon) +{ + extern int Client; + int num_interfaces = iface_count(); + int fd_listenset; + fd_set listen_set; + int s; + + memset(&fd_listenset, 0, sizeof(fd_listenset)); + +#ifdef HAVE_ATEXIT + { + static int atexit_set; + if(atexit_set == 0) { + atexit_set=1; + atexit(killkids); + } + } +#endif + + /* Stop zombies */ + CatchChild(); + + + FD_ZERO(&listen_set); + + /* Just bind to 0.0.0.0 - accept connections + from anywhere. */ + num_interfaces = 1; + + /* open an incoming socket */ + s = open_server_socket(); + if (s == -1) + return(False); + fd_listenset = s; + FD_SET(s,&listen_set); + + /* now accept incoming connections - forking a new process + for each incoming connection */ + DEBUG(2,("waiting for a connection\n")); + while (1) + { + struct sockaddr_un addr; + int in_addrlen = sizeof(addr); + fd_set lfds; + int num; + + memcpy((char *)&lfds, (char *)&listen_set, + sizeof(listen_set)); + + num = sys_select(256,&lfds,NULL, NULL); + + if (num == -1 && errno == EINTR) + continue; + + /* Find the sockets that are read-ready - + accept on these. */ + + s = -1; + if(FD_ISSET(fd_listenset,&lfds)) + { + s = fd_listenset; + } + + /* Clear this so we don't look at it again. */ + FD_CLR(s,&lfds); + + Client = accept(s,(struct sockaddr*)&addr,&in_addrlen); + + if (Client == -1 && errno == EINTR) + continue; + + if (Client == -1) + { + DEBUG(0,("open_sockets: accept: %s\n", + strerror(errno))); + continue; + } + + if (Client != -1 && fork()==0) + { + /* Child code ... */ + + /* close the listening socket(s) */ + close(fd_listenset); + + /* close our standard file + descriptors */ + close_low_fds(); + am_parent = 0; + + /* Reset global variables in util.c so + that client substitutions will be + done correctly in the process. */ + reset_globals_after_fork(); + + /* + * Ensure this child has kernel oplock + * capabilities, but not it's children. + */ + set_process_capability(KERNEL_OPLOCK_CAPABILITY, True); + set_inherited_process_capability(KERNEL_OPLOCK_CAPABILITY, False); + + return True; + } + /* The parent doesn't need this socket */ + close(Client); + + /* Force parent to check log size after + * spawning child. Fix from + * klausr@ITAP.Physik.Uni-Stuttgart.De. The + * parent lsarpcd will log to logserver.smb. It + * writes only two messages for each child + * started/finished. But each child writes, + * say, 50 messages also in logserver.smb, + * begining with the debug_count of the + * parent, before the child opens its own log + * file logserver.client. In a worst case + * scenario the size of logserver.smb would be + * checked after about 50*50=2500 messages + * (ca. 100kb). + * */ + force_check_log_size(); + + } /* end while 1 */ + +/* NOTREACHED return True; */ +} + +/**************************************************************************** + reload the services file + **************************************************************************/ +BOOL reload_services(BOOL test) +{ + BOOL ret; + + if (lp_loaded()) { + pstring fname; + pstrcpy(fname,lp_configfile()); + if (file_exist(fname,NULL) && !strcsequal(fname,servicesf)) { + pstrcpy(servicesf,fname); + test = False; + } + } + + reopen_logs(); + + if (test && !lp_file_list_changed()) + return(True); + + lp_killunused(NULL); + + ret = lp_load(servicesf,False,False,True); + + load_printers(); + + /* perhaps the config filename is now set */ + if (!test) + reload_services(True); + + reopen_logs(); + + load_interfaces(); + + return(ret); +} + + + +/**************************************************************************** +this prevents zombie child processes +****************************************************************************/ +BOOL reload_after_sighup = False; + +static void sig_hup(int sig) +{ + BlockSignals(True,SIGHUP); + DEBUG(0,("Got SIGHUP\n")); + + /* + * Fix from here. + * We used to reload in the signal handler - this + * is a *BIG* no-no. + */ + + reload_after_sighup = True; + BlockSignals(False,SIGHUP); +} + + + +#if DUMP_CORE +/******************************************************************* +prepare to dump a core file - carefully! +********************************************************************/ +static BOOL dump_core(void) +{ + char *p; + pstring dname; + pstrcpy(dname,debugf); + if ((p=strrchr(dname,'/'))) *p=0; + pstrcat(dname,"/corefiles"); + mkdir(dname,0700); + sys_chown(dname,getuid(),getgid()); + chmod(dname,0700); + if (chdir(dname)) return(False); + umask(~(0700)); + +#ifdef HAVE_GETRLIMIT +#ifdef RLIMIT_CORE + { + struct rlimit rlp; + getrlimit(RLIMIT_CORE, &rlp); + rlp.rlim_cur = MAX(4*1024*1024,rlp.rlim_cur); + setrlimit(RLIMIT_CORE, &rlp); + getrlimit(RLIMIT_CORE, &rlp); + DEBUG(3,("Core limits now %d %d\n", + (int)rlp.rlim_cur,(int)rlp.rlim_max)); + } +#endif +#endif + + + DEBUG(0,("Dumping core in %s\n",dname)); + abort(); + return(True); +} +#endif + + +/**************************************************************************** +exit the server +****************************************************************************/ +void exit_server(char *reason) +{ + static int firsttime=1; + extern char *last_inbuf; + + + if (!firsttime) exit(0); + firsttime = 0; + + unbecome_user(); + DEBUG(2,("Closing connections\n")); + +#ifdef WITH_DFS + if (dcelogin_atmost_once) { + dfs_unlogin(); + } +#endif + + if (!reason) { + int oldlevel = DEBUGLEVEL; + DEBUGLEVEL = 10; + if (last_inbuf) + show_msg(last_inbuf); + DEBUGLEVEL = oldlevel; + DEBUG(0,("===============================================================\n")); +#if DUMP_CORE + if (dump_core()) return; +#endif + } + + locking_end(); + + DEBUG(3,("Server exit (%s)\n", (reason ? reason : ""))); +#ifdef MEM_MAN + { + extern FILE *dbf; + smb_mem_write_verbose(dbf); + dbgflush(); + } +#endif + exit(0); +} + + + +/**************************************************************************** + initialise connect, service and file structs +****************************************************************************/ +static void init_structs(void) +{ +#if 0 + conn_init(); +#endif + init_rpc_pipe_hnd(); /* for RPC pipes */ + if (!init_policy_hnd(MAX_SERVER_POLICY_HANDLES)) + { + exit_server("could not allocate policy handles\n"); + } +} + +/**************************************************************************** +usage on the program +****************************************************************************/ +static void usage(char *pname) +{ + DEBUG(0,("Incorrect program usage - are you sure the command line is correct?\n")); + + printf("Usage: %s [-D] [-p port] [-d debuglevel] ", pname); + printf("[-l log basename] [-s services file]\n" ); + printf("Version %s\n",VERSION); + printf("\t-D become a daemon\n"); + printf("\t-p port listen on the specified port\n"); + printf("\t-d debuglevel set the debuglevel\n"); + printf("\t-l log basename. Basename for log/debug files\n"); + printf("\t-s services file. Filename of services file\n"); + printf("\t-P passive only\n"); + printf("\t-a append to log file (default)\n"); + printf("\t-o overwrite log file, don't append\n"); + printf("\t-i scope NetBIOS scope to use (default none)\n"); + printf("\n"); +} + + +/**************************************************************************** + main program +****************************************************************************/ + int main(int argc,char *argv[]) +{ + extern BOOL append_log; + /* shall I run as a daemon */ + BOOL is_daemon = False; + int opt; + extern char *optarg; + +#ifdef HAVE_SET_AUTH_PARAMETERS + set_auth_parameters(argc,argv); +#endif + +#ifdef HAVE_SETLUID + /* needed for SecureWare on SCO */ + setluid(0); +#endif + + append_log = True; + + TimeInit(); + + pstrcpy(debugf,LSARPCLOGFILE); + + pstrcpy(remote_machine, "lsarpcd"); + + setup_logging(argv[0],False); + + charset_initialise(); + + /* make absolutely sure we run as root - to handle cases where people + are crazy enough to have it setuid */ +#ifdef HAVE_SETRESUID + setresuid(0,0,0); +#else + setuid(0); + seteuid(0); + setuid(0); + seteuid(0); +#endif + + fault_setup((void (*)(void *))exit_server); + CatchSignal(SIGTERM , SIGNAL_CAST dflt_sig); + + /* we are never interested in SIGPIPE */ + BlockSignals(True,SIGPIPE); + + /* we want total control over the permissions on created files, + so set our umask to 0 */ + umask(0); + + init_uid(); + + /* this is for people who can't start the program correctly */ + while (argc > 1 && (*argv[1] != '-')) { + argv++; + argc--; + } + + while ( EOF != (opt = getopt(argc, argv, "i:l:s:d:Dh?Paof:")) ) + switch (opt) { + case 'i': + pstrcpy(scope,optarg); + break; + + case 'P': + { + extern BOOL passive; + passive = True; + } + break; + + case 's': + pstrcpy(servicesf,optarg); + break; + + case 'l': + pstrcpy(debugf,optarg); + break; + + case 'a': + append_log = True; + break; + + case 'o': + append_log = False; + break; + + case 'D': + is_daemon = True; + break; + + case 'd': + if (*optarg == 'A') + DEBUGLEVEL = 10000; + else + DEBUGLEVEL = atoi(optarg); + break; + + case 'h': + case '?': + usage(argv[0]); + exit(0); + break; + + default: + usage(argv[0]); + exit(1); + } + + reopen_logs(); + + DEBUG(1,( "lsarpcd version %s started.\n", VERSION)); + DEBUGADD(1,( "Copyright Andrew Tridgell 1992-1999\n")); + + DEBUG(2,("uid=%d gid=%d euid=%d egid=%d\n", + (int)getuid(),(int)getgid(),(int)geteuid(),(int)getegid())); + + if (sizeof(uint16) < 2 || sizeof(uint32) < 4) { + DEBUG(0,("ERROR: Samba is not configured correctly for the word size on your machine\n")); + exit(1); + } + + get_myname(myhostname,NULL); + + if (!reload_services(False)) + return(-1); + + init_structs(); + +#ifdef WITH_PROFILE + if (!profile_setup(False)) { + DEBUG(0,("ERROR: failed to setup profiling\n")); + return -1; + } +#endif + + /* + * Set the machine NETBIOS name if not already + * set from the config file. + */ + if (!*global_myname) + { + fstrcpy(global_myname, dns_to_netbios_name(myhostname)); + } + strupper(global_myname); + + add_msrpc_command_processor( "lsarpc", argv[0], api_ntlsa_rpc ); + + codepage_initialise(lp_client_code_page()); + + if (!pwdb_initialise(True)) + { + exit(1); + } + + if(!initialise_sam_password_db()) + { + exit(1); + } + + if(!initialise_passgrp_db()) + { + exit(1); + } + + if(!initialise_group_db()) + { + exit(1); + } + + if(!initialise_alias_db()) + { + exit(1); + } + + if(!initialise_builtin_db()) + { + exit(1); + } + + if (!get_member_domain_sid()) + { + DEBUG(0,("ERROR: Samba cannot obtain PDC SID from PDC(s) %s.\n", + lp_passwordserver())); + exit(1); + } + + CatchSignal(SIGHUP,SIGNAL_CAST sig_hup); + + /* Setup the signals that allow the debug log level + to by dynamically changed. */ + + /* If we are using the malloc debug code we can't use + SIGUSR1 and SIGUSR2 to do debug level changes. */ + +#ifndef MEM_MAN +#if defined(SIGUSR1) + CatchSignal( SIGUSR1, SIGNAL_CAST sig_usr1 ); +#endif /* SIGUSR1 */ + +#if defined(SIGUSR2) + CatchSignal( SIGUSR2, SIGNAL_CAST sig_usr2 ); +#endif /* SIGUSR2 */ +#endif /* MEM_MAN */ + + DEBUG(3,( "loaded services\n")); + + if (!is_daemon && !is_a_socket(0)) { + DEBUG(0,("standard input is not a socket, assuming -D option\n")); + is_daemon = True; + } + + if (is_daemon) { + DEBUG( 3, ( "Becoming a daemon.\n" ) ); + become_daemon(); + } + + if (!directory_exist(lp_lockdir(), NULL)) { + mkdir(lp_lockdir(), 0755); + } + + if (is_daemon) { + pidfile_create("lsarpcd"); + } + + if (!open_sockets(is_daemon)) + exit(1); + + if (!locking_init(0)) + exit(1); + + /* possibly reload the services file. */ + reload_services(True); + + if (*lp_rootdir()) { + if (sys_chroot(lp_rootdir()) == 0) + DEBUG(2,("Changed root to %s\n", lp_rootdir())); + } + + lsarpcd_process(); + close_sockets(); + + exit_server("normal exit"); + return(0); +} diff --git a/source3/lsarpcd/lsarpcd_process.c b/source3/lsarpcd/lsarpcd_process.c new file mode 100644 index 0000000000..f54c41bcb4 --- /dev/null +++ b/source3/lsarpcd/lsarpcd_process.c @@ -0,0 +1,401 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + process incoming packets - main loop + Copyright (C) Andrew Tridgell 1992-1998 + + 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" + +extern int DEBUGLEVEL; + +time_t smb_last_time=(time_t)0; +static struct pipes_struct static_pipe; + +char *InBuffer = NULL; +char *OutBuffer = NULL; +char *last_inbuf = NULL; + +/* + * Size of data we can send to client. Set + * by the client for all protocols above CORE. + * Set by us for CORE protocol. + */ +int max_send = BUFFER_SIZE; +/* + * Size of the data we can receive. Set by us. + * Can be modified by the max xmit parameter. + */ +int max_recv = BUFFER_SIZE; + +extern int last_message; +extern pstring sesssetup_user; +extern char *last_inbuf; +extern char *InBuffer; +extern char *OutBuffer; +extern int smb_read_error; +extern BOOL reload_after_sighup; +extern int max_send; + + +/**************************************************************************** + Do a select on an two fd's - with timeout. + + If a local udp message has been pushed onto the + queue (this can only happen during oplock break + processing) return this first. + + If a pending smb message has been pushed onto the + queue (this can only happen during oplock break + processing) return this next. + + If the first smbfd is ready then read an smb from it. + if the second (loopback UDP) fd is ready then read a message + from it and setup the buffer header to identify the length + and from address. + Returns False on timeout or error. + Else returns True. + +The timeout is in milli seconds +****************************************************************************/ + +static BOOL receive_message_or_smb(char *buffer, int buffer_len, + int timeout, BOOL *got_smb) +{ + extern int Client; + fd_set fds; + int selrtn; + struct timeval to; + int maxfd; + + smb_read_error = 0; + + *got_smb = False; + + /* + * Check to see if we already have a message on the smb queue. + * If so - copy and return it. + */ + + /* + * Setup the select read fd set. + */ + + FD_ZERO(&fds); + FD_SET(Client,&fds); + maxfd = 0; + + to.tv_sec = timeout / 1000; + to.tv_usec = (timeout % 1000) * 1000; + + selrtn = sys_select(MAX(maxfd,Client)+1,&fds,NULL, timeout>0?&to:NULL); + + /* Check if error */ + if(selrtn == -1) { + /* something is wrong. Maybe the socket is dead? */ + smb_read_error = READ_ERROR; + return False; + } + + /* Did we timeout ? */ + if (selrtn == 0) { + smb_read_error = READ_TIMEOUT; + return False; + } + + if (FD_ISSET(Client,&fds)) + { + *got_smb = True; + return receive_smb(Client, buffer, 0); + } + return False; +} + +/**************************************************************************** +Get the next SMB packet, doing the local message processing automatically. +****************************************************************************/ + +BOOL receive_next_smb(char *inbuf, int bufsize, int timeout) +{ + BOOL got_smb = False; + BOOL ret; + + do + { + ret = receive_message_or_smb(inbuf,bufsize,timeout,&got_smb); + + if(ret && !got_smb) + { + continue; + } + + if(ret && (CVAL(inbuf,0) == 0x85)) + { + /* Keepalive packet. */ + got_smb = False; + } + + } + while(ret && !got_smb); + + return ret; +} + + +/* +These flags determine some of the permissions required to do an operation + +Note that I don't set NEED_WRITE on some write operations because they +are used by some brain-dead clients when printing, and I don't want to +force write permissions on print services. +*/ +#define AS_USER (1<<0) +#define NEED_WRITE (1<<1) +#define TIME_INIT (1<<2) +#define CAN_IPC (1<<3) +#define AS_GUEST (1<<5) +#define QUEUE_IN_OPLOCK (1<<6) + +/* + define a list of possible SMB messages and their corresponding + functions. Any message that has a NULL function is unimplemented - + please feel free to contribute implementations! +*/ + +/**************************************************************************** +do a switch on the message type, and return the response size +****************************************************************************/ +static int do_message(char *inbuf,char *outbuf,int size,int bufsize) +{ + static int pid= -1; + + pipes_struct *p = &static_pipe; + prs_struct pd; + int outsize = -1; + + /* make a static data parsing structure from the api_fd_reply data */ + prs_init(&pd, 0, 4, 0, True); + mem_create(pd.data, smb_base(inbuf), 0, smb_len(inbuf), 0, False); + + if (pid == -1) + pid = getpid(); + + /* dce/rpc command */ + if (rpc_command(p, &pd)) + { + char *copy_into = smb_base(outbuf); + outsize = mem_buf_len(p->rhdr.data); + if (!mem_buf_copy(copy_into, p->rhdr.data, 0, outsize)) + { + return -1; + } + } + mem_free_data(pd.data); + + mem_free_data(p->rhdr .data); + mem_free_data(p->rfault .data); + mem_free_data(p->rdata .data); + mem_free_data(p->rdata_i.data); + mem_free_data(p->rauth .data); + mem_free_data(p->rverf .data); + mem_free_data(p->rntlm .data); + + return outsize; +} + + +/**************************************************************************** + construct a reply to the incoming packet +****************************************************************************/ +static int construct_reply(char *inbuf,char *outbuf,int size,int bufsize) +{ + int outsize = 0; + smb_last_time = time(NULL); + + outsize = do_message(inbuf,outbuf,size,bufsize) + 4; + + if(outsize > 4) + _smb_setlen(outbuf,outsize - 4); + return(outsize); +} + + +/**************************************************************************** + process an smb from the client - split out from the process() code so + it can be used by the oplock break code. +****************************************************************************/ +void process_smb(char *inbuf, char *outbuf) +{ + extern int Client; + static int trans_num; + int32 len = smb_len(inbuf); + int nread = len + 4; + + if (trans_num == 0) { + /* on the first packet, check the global hosts allow/ hosts + deny parameters before doing any parsing of the packet + passed to us by the client. This prevents attacks on our + parsing code from hosts not in the hosts allow list */ + if (!check_access(Client, lp_hostsallow(-1), lp_hostsdeny(-1))) { + /* send a negative session response "not listining on calling + name" */ + DEBUG( 1, ( "Connection denied from %s\n", + client_addr(Client) ) ); + exit_server("connection denied"); + } + } + + DEBUG( 6, ( "got message of len 0x%x\n", len ) ); + DEBUG( 3, ( "Transaction %d of length %d\n", trans_num, nread ) ); + + dump_data(10, inbuf, len); + +#ifdef WITH_VTP + if(trans_num == 1 && VT_Check(inbuf)) + { + VT_Process(); + return; + } +#endif + + nread = construct_reply(inbuf,outbuf,nread,max_send); + + if(nread > 0) + { + dump_data(10, outbuf, nread); + + if (nread != smb_len(outbuf) + 4) + { + DEBUG(0,("ERROR: Invalid message response size! %d %d\n", + nread, smb_len(outbuf))); + } + else + send_smb(Client,outbuf); + } + trans_num++; +} + + + +/**************************************************************************** + process commands from the client +****************************************************************************/ +void lsarpcd_process(void) +{ + ZERO_STRUCT(static_pipe); + + fstrcpy(static_pipe.name, "lsarpc"); + + InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); + OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); + if ((InBuffer == NULL) || (OutBuffer == NULL)) + return; + + InBuffer += SMB_ALIGNMENT; + OutBuffer += SMB_ALIGNMENT; + + + max_recv = MIN(lp_maxxmit(),BUFFER_SIZE); + + /* re-initialise the timezone */ + TimeInit(); + + while (True) + { + int deadtime = lp_deadtime()*60; + int counter; + int service_load_counter = 0; + BOOL got_smb = False; + + if (deadtime <= 0) + deadtime = DEFAULT_SMBD_TIMEOUT; + +#if USE_READ_PREDICTION + if (lp_readprediction()) + do_read_prediction(); +#endif + + errno = 0; + + for (counter=SMBD_SELECT_LOOP; + !receive_message_or_smb(InBuffer,BUFFER_SIZE, + SMBD_SELECT_LOOP*1000,&got_smb); + counter += SMBD_SELECT_LOOP) + { + time_t t; + + if (counter > 365 * 3600) /* big number of seconds. */ + { + counter = 0; + service_load_counter = 0; + } + + if (smb_read_error == READ_EOF) + { + DEBUG(3,("end of file from client\n")); + return; + } + + if (smb_read_error == READ_ERROR) + { + DEBUG(3,("receive_smb error (%s) exiting\n", + strerror(errno))); + return; + } + + t = time(NULL); + + /* become root again if waiting */ + unbecome_user(); + + /* check for smb.conf reload */ + if (counter >= service_load_counter + SMBD_RELOAD_CHECK) + { + service_load_counter = counter; + + /* reload services, if files have changed. */ + reload_services(True); + } + + /* + * If reload_after_sighup == True then we got a SIGHUP + * and are being asked to reload. Fix from + */ + + if (reload_after_sighup) + { + DEBUG(0,("Reloading services after SIGHUP\n")); + reload_services(False); + reload_after_sighup = False; + /* + * Use this as an excuse to print some stats. + */ + } + + /* automatic timeout if all connections are closed */ + if (counter >= IDLE_CLOSED_TIMEOUT) + { + DEBUG( 2, ( "Closing idle connection\n" ) ); + return; + } + + } + + if(got_smb) + process_smb(InBuffer, OutBuffer); + } +} diff --git a/source3/rpc_parse/parse_prs.c b/source3/rpc_parse/parse_prs.c index bf4efbe527..f53b2da955 100644 --- a/source3/rpc_parse/parse_prs.c +++ b/source3/rpc_parse/parse_prs.c @@ -36,6 +36,16 @@ void prs_debug(prs_struct *ps, int depth, char *desc, char *fn_name) DEBUG(5+depth, ("%s%06x %s %s\n", tab_depth(depth), ps->offset, fn_name, desc)); } +/******************************************************************* + debug a parse structure + ********************************************************************/ +void prs_debug_out(prs_struct *ps, int level) +{ + DEBUG(level,("ps: io %s align %d offset %d err %d data %p len %d\n", + BOOLSTR(ps->io), ps->align, ps->offset, ps->error, ps->data, + ps->data != NULL ? mem_buf_len(ps->data) : 0)); +} + /******************************************************************* initialise a parse structure ********************************************************************/ diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c index c4664f7d7b..04fa0955ea 100644 --- a/source3/rpc_server/srv_pipe.c +++ b/source3/rpc_server/srv_pipe.c @@ -396,7 +396,69 @@ struct api_cmd BOOL (*fn) (pipes_struct *, prs_struct *); }; -static struct api_cmd api_fd_commands[] = +static struct api_cmd **api_fd_commands = NULL; +uint32 num_cmds = 0; + +static void api_cmd_free(struct api_cmd *item) +{ + if (item != NULL) + { + if (item->pipe_clnt_name != NULL) + { + free(item->pipe_clnt_name); + } + if (item->pipe_srv_name != NULL) + { + free(item->pipe_srv_name); + } + free(item); + } +} + +static struct api_cmd *api_cmd_dup(const struct api_cmd *from) +{ + struct api_cmd *copy = NULL; + if (from == NULL) + { + return NULL; + } + copy = (struct api_cmd *) malloc(sizeof(struct api_cmd)); + if (copy != NULL) + { + ZERO_STRUCTP(copy); + if (from->pipe_clnt_name != NULL) + { + copy->pipe_clnt_name = strdup(from->pipe_clnt_name ); + } + if (from->pipe_srv_name != NULL) + { + copy->pipe_srv_name = strdup(from->pipe_srv_name); + } + if (from->fn != NULL) + { + copy->fn = from->fn; + } + } + return copy; +} + +static void free_api_cmd_array(uint32 num_entries, struct api_cmd **entries) +{ + void(*fn)(void*) = (void(*)(void*))&api_cmd_free; + free_void_array(num_entries, (void**)entries, *fn); +} + +static struct api_cmd* add_api_cmd_to_array(uint32 *len, + struct api_cmd ***array, + const struct api_cmd *name) +{ + void*(*fn)(const void*) = (void*(*)(const void*))&api_cmd_dup; + return (struct api_cmd*)add_copy_to_array(len, + (void***)array, (const void*)name, *fn, False); + +} + +#if 0 { { "lsarpc", "lsass", api_ntlsa_rpc }, { "samr", "lsass", api_samr_rpc }, @@ -409,6 +471,20 @@ static struct api_cmd api_fd_commands[] = { "spoolss", "spoolss", api_spoolss_rpc }, { NULL, NULL, NULL } }; +#endif + +void close_msrpc_command_processor(void) +{ + free_api_cmd_array(num_cmds, api_fd_commands); +} + +void add_msrpc_command_processor(char* pipe_name, + char* process_name, + BOOL (*fn) (pipes_struct *, prs_struct *)) +{ + struct api_cmd cmd = { pipe_name, process_name, fn }; + add_api_cmd_to_array(&num_cmds, &api_fd_commands, &cmd); +} static BOOL api_pipe_bind_auth_resp(pipes_struct *p, prs_struct *pd) { @@ -479,20 +555,20 @@ static BOOL api_pipe_bind_and_alt_req(pipes_struct *p, prs_struct *pd, enum RPC_ DEBUG(5,("api_pipe_bind_req: decode request. %d\n", __LINE__)); - for (i = 0; api_fd_commands[i].pipe_clnt_name; i++) + for (i = 0; i < num_cmds; i++) { - if (strequal(api_fd_commands[i].pipe_clnt_name, p->name) && - api_fd_commands[i].fn != NULL) + if (strequal(api_fd_commands[i]->pipe_clnt_name, p->name) && + api_fd_commands[i]->fn != NULL) { DEBUG(3,("api_pipe_bind_req: \\PIPE\\%s -> \\PIPE\\%s\n", - api_fd_commands[i].pipe_clnt_name, - api_fd_commands[i].pipe_srv_name)); - fstrcpy(p->pipe_srv_name, api_fd_commands[i].pipe_srv_name); + api_fd_commands[i]->pipe_clnt_name, + api_fd_commands[i]->pipe_srv_name)); + fstrcpy(p->pipe_srv_name, api_fd_commands[i]->pipe_srv_name); break; } } - if (api_fd_commands[i].fn == NULL) return False; + if (api_fd_commands[i]->fn == NULL) return False; /* decode the bind request */ smb_io_rpc_hdr_rb("", &p->hdr_rb, pd, 0); @@ -727,13 +803,13 @@ static BOOL api_pipe_request(pipes_struct *p, prs_struct *pd) #endif } - for (i = 0; api_fd_commands[i].pipe_clnt_name; i++) + for (i = 0; i < num_cmds; i++) { - if (strequal(api_fd_commands[i].pipe_clnt_name, p->name) && - api_fd_commands[i].fn != NULL) + if (strequal(api_fd_commands[i]->pipe_clnt_name, p->name) && + api_fd_commands[i]->fn != NULL) { - DEBUG(3,("Doing \\PIPE\\%s\n", api_fd_commands[i].pipe_clnt_name)); - return api_fd_commands[i].fn(p, pd); + DEBUG(3,("Doing \\PIPE\\%s\n", api_fd_commands[i]->pipe_clnt_name)); + return api_fd_commands[i]->fn(p, pd); } } return False; @@ -744,6 +820,24 @@ BOOL rpc_command(pipes_struct *p, prs_struct *pd) BOOL reply = False; DEBUG(10,("rpc_command\n")); + if (p->m != NULL) + { + DEBUG(10,("msrpc redirect\n")); + if (!msrpc_send_prs(p->m, pd)) + { + DEBUG(2,("msrpc redirect send failed\n")); + return False; + } + if (!msrpc_receive_prs(p->m, &p->rhdr)) + { + DEBUG(2,("msrpc redirect receive failed\n")); + return False; + } + prs_link(NULL, &p->rhdr, NULL); + prs_debug_out(&p->rhdr, 10); + return True; + } + if (pd->data == NULL) return False; /* process the rpc header */ diff --git a/source3/rpc_server/srv_pipe_hnd.c b/source3/rpc_server/srv_pipe_hnd.c index bd712a1702..a7e451e6da 100644 --- a/source3/rpc_server/srv_pipe_hnd.c +++ b/source3/rpc_server/srv_pipe_hnd.c @@ -83,6 +83,7 @@ pipes_struct *open_rpc_pipe_p(char *pipe_name, int i; pipes_struct *p; static int next_pipe; + struct msrpc_state *m = NULL; DEBUG(4,("Open pipe requested %s (pipes_open=%d)\n", pipe_name, pipes_open)); @@ -108,6 +109,16 @@ pipes_struct *open_rpc_pipe_p(char *pipe_name, DEBUG(5,("open pipes: name %s pnum=%x\n", p->name, p->pnum)); } + if (strequal(pipe_name, "lsarpc")) + { + m = msrpc_use_add(pipe_name, NULL, False); + if (m == NULL) + { + DEBUG(5,("open pipes: msrpc redirect failed\n")); + return NULL; + } + } + p = (pipes_struct *)malloc(sizeof(*p)); if (!p) return NULL; @@ -120,6 +131,7 @@ pipes_struct *open_rpc_pipe_p(char *pipe_name, pipes_open++; p->pnum = i; + p->m = m; p->open = True; p->device_state = 0; @@ -359,6 +371,19 @@ BOOL close_rpc_pipe_hnd(pipes_struct *p, connection_struct *conn) DLIST_REMOVE(Pipes, p); + if (p->m != NULL) + { + DEBUG(4,("closed msrpc redirect: ")); + if (msrpc_use_del(p->m->pipe_name, &p->m->usr, False, NULL)) + { + DEBUG(4,("OK\n")); + } + else + { + DEBUG(4,("FAILED\n")); + } + } + ZERO_STRUCTP(p); free(p); diff --git a/source3/smbd/challenge.c b/source3/smbd/challenge.c new file mode 100644 index 0000000000..cbb34e6395 --- /dev/null +++ b/source3/smbd/challenge.c @@ -0,0 +1,61 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Password and authentication handling + Copyright (C) Andrew Tridgell 1992-1998 + + 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" + +extern int DEBUGLEVEL; + +/* Data to do lanman1/2 password challenge. */ +static unsigned char saved_challenge[8]; +static BOOL challenge_sent=False; + +/******************************************************************* +Get the next challenge value - no repeats. +********************************************************************/ +void generate_next_challenge(char *challenge) +{ + unsigned char buf[8]; + generate_random_buffer(buf,8,False); + memcpy(saved_challenge, buf, 8); + memcpy(challenge,buf,8); + challenge_sent = True; +} + +/******************************************************************* +set the last challenge sent, usually from a password server +********************************************************************/ +BOOL set_challenge(unsigned char *challenge) +{ + memcpy(saved_challenge,challenge,8); + challenge_sent = True; + return(True); +} + +/******************************************************************* +get the last challenge sent +********************************************************************/ +BOOL last_challenge(unsigned char *challenge) +{ + if (!challenge_sent) return False; + memcpy(challenge,saved_challenge,8); + return(True); +} + diff --git a/source3/smbd/password.c b/source3/smbd/password.c index c14b50d3a6..240ec30c3f 100644 --- a/source3/smbd/password.c +++ b/source3/smbd/password.c @@ -31,209 +31,6 @@ extern pstring scope; extern pstring global_myname; extern fstring global_myworkgroup; -/* Data to do lanman1/2 password challenge. */ -static unsigned char saved_challenge[8]; -static BOOL challenge_sent=False; - -/******************************************************************* -Get the next challenge value - no repeats. -********************************************************************/ -void generate_next_challenge(char *challenge) -{ -#if 0 - /* - * Leave this ifdef'd out while we test - * the new crypto random number generator. - * JRA. - */ - unsigned char buf[16]; - static int counter = 0; - struct timeval tval; - int v1,v2; - - /* get a sort-of random number */ - GetTimeOfDay(&tval); - v1 = (counter++) + getpid() + tval.tv_sec; - v2 = (counter++) * getpid() + tval.tv_usec; - SIVAL(challenge,0,v1); - SIVAL(challenge,4,v2); - - /* mash it up with md4 */ - mdfour(buf, (unsigned char *)challenge, 8); -#else - unsigned char buf[8]; - - generate_random_buffer(buf,8,False); -#endif - memcpy(saved_challenge, buf, 8); - memcpy(challenge,buf,8); - challenge_sent = True; -} - -/******************************************************************* -set the last challenge sent, usually from a password server -********************************************************************/ -BOOL set_challenge(unsigned char *challenge) -{ - memcpy(saved_challenge,challenge,8); - challenge_sent = True; - return(True); -} - -/******************************************************************* -get the last challenge sent -********************************************************************/ -static BOOL last_challenge(unsigned char *challenge) -{ - if (!challenge_sent) return False; - memcpy(challenge,saved_challenge,8); - return(True); -} - -/* this holds info on user ids that are already validated for this VC */ -static user_struct *validated_users = NULL; -static int num_validated_users = 0; - -/**************************************************************************** -check if a uid has been validated, and return an pointer to the user_struct -if it has. NULL if not. vuid is biased by an offset. This allows us to -tell random client vuid's (normally zero) from valid vuids. -****************************************************************************/ -user_struct *get_valid_user_struct(uint16 vuid) -{ - if (vuid == UID_FIELD_INVALID) - return NULL; - vuid -= VUID_OFFSET; - if ((vuid >= (uint16)num_validated_users) || - (validated_users[vuid].uid == (uid_t)-1) || (validated_users[vuid].gid == (gid_t)-1)) - return NULL; - return &validated_users[vuid]; -} - -/**************************************************************************** -invalidate a uid -****************************************************************************/ -void invalidate_vuid(uint16 vuid) -{ - user_struct *vuser = get_valid_user_struct(vuid); - - if (vuser == NULL) return; - - vuser->uid = (uid_t)-1; - vuser->gid = (gid_t)-1; - - vuser->n_sids = 0; - - /* same number of igroups as groups */ - vuser->n_groups = 0; - - if (vuser->groups) - free((char *)vuser->groups); - - if (vuser->sids) - free((char *)vuser->sids); - - vuser->sids = NULL; - vuser->groups = NULL; -} - - -/**************************************************************************** -return a validated username -****************************************************************************/ -char *validated_username(uint16 vuid) -{ - user_struct *vuser = get_valid_user_struct(vuid); - if (vuser == NULL) - return 0; - return(vuser->name); -} - - - -/**************************************************************************** -register a uid/name pair as being valid and that a valid password -has been given. vuid is biased by an offset. This allows us to -tell random client vuid's (normally zero) from valid vuids. -****************************************************************************/ -uint16 register_vuid(uid_t uid,gid_t gid, char *unix_name, char *requested_name, BOOL guest, uchar user_sess_key[16]) -{ - user_struct *vuser; - struct passwd *pwfile; /* for getting real name from passwd file */ - - /* Ensure no vuid gets registered in share level security. */ - if(lp_security() == SEC_SHARE) - return UID_FIELD_INVALID; - -#if 0 - /* - * After observing MS-Exchange services writing to a Samba share - * I belive this code is incorrect. Each service does its own - * sessionsetup_and_X for the same user, and as each service shuts - * down, it does a user_logoff_and_X. As we are consolidating multiple - * sessionsetup_and_X's onto the same vuid here, when the first service - * shuts down, it invalidates all the open files for the other services. - * Hence I am removing this code and forcing each sessionsetup_and_X - * to get a new vuid. - * Jeremy Allison. (jallison@whistle.com). - */ - - int i; - for(i = 0; i < num_validated_users; i++) { - vuser = &validated_users[i]; - if ( vuser->uid == uid ) - return (uint16)(i + VUID_OFFSET); /* User already validated */ - } -#endif - - validated_users = (user_struct *)Realloc(validated_users, - sizeof(user_struct)* - (num_validated_users+1)); - - if (!validated_users) - { - DEBUG(0,("Failed to realloc users struct!\n")); - num_validated_users = 0; - return UID_FIELD_INVALID; - } - - vuser = &validated_users[num_validated_users]; - num_validated_users++; - - vuser->uid = uid; - vuser->gid = gid; - vuser->guest = guest; - fstrcpy(vuser->name,unix_name); - fstrcpy(vuser->requested_name,requested_name); - memcpy(vuser->dc.user_sess_key, user_sess_key, sizeof(vuser->dc.user_sess_key)); - - vuser->n_sids = 0; - vuser->sids = NULL; - - vuser->n_groups = 0; - vuser->groups = NULL; - - /* Find all the groups this uid is in and store them. - Used by become_user() */ - get_unixgroups(unix_name,uid,gid, - &vuser->n_groups, - &vuser->groups); - - DEBUG(3,("uid %d registered to name %s\n",(int)uid,unix_name)); - - DEBUG(3, ("Clearing default real name\n")); - fstrcpy(vuser->real_name, "\0"); - if (lp_unix_realname()) { - if ((pwfile=hashed_getpwnam(vuser->name))!= NULL) - { - DEBUG(3, ("User name: %s\tReal name: %s\n",vuser->name,pwfile->pw_gecos)); - fstrcpy(vuser->real_name, pwfile->pw_gecos); - } - } - - return (uint16)((num_validated_users - 1) + VUID_OFFSET); -} - /**************************************************************************** add a name to the session users list @@ -290,275 +87,6 @@ static BOOL update_smbpassword_file(char *user, char *password) -/**************************************************************************** -core of smb password checking routine. -****************************************************************************/ -static BOOL smb_pwd_check_ntlmv1(char *password, unsigned char *part_passwd, - unsigned char *c8, - uchar sess_key[16]) -{ - /* Finish the encryption of part_passwd. */ - unsigned char p24[24]; - - if (part_passwd == NULL) - DEBUG(10,("No password set - allowing access\n")); - /* No password set - always true ! */ - if (part_passwd == NULL) - return True; - - SMBOWFencrypt(part_passwd, c8, p24); - if (sess_key != NULL) - { - SMBsesskeygen_ntv1(part_passwd, NULL, sess_key); - } - -#if DEBUG_PASSWORD - DEBUG(100,("Part password (P16) was |")); - dump_data(100, part_passwd, 16); - DEBUG(100,("Password from client was |")); - dump_data(100, password, 24); - DEBUG(100,("Given challenge was |")); - dump_data(100, c8, 8); - DEBUG(100,("Value from encryption was |")); - dump_data(100, p24, 24); -#endif - return (memcmp(p24, password, 24) == 0); -} - -/**************************************************************************** -core of smb password checking routine. -****************************************************************************/ -static BOOL smb_pwd_check_ntlmv2(char *password, size_t pwd_len, - unsigned char *part_passwd, - unsigned char const *c8, - const char *user, const char *domain, - char *sess_key) -{ - /* Finish the encryption of part_passwd. */ - unsigned char kr[16]; - unsigned char resp[16]; - - if (part_passwd == NULL) - { - DEBUG(10,("No password set - allowing access\n")); - } - /* No password set - always true ! */ - if (part_passwd == NULL) - { - return True; - } - - ntv2_owf_gen(part_passwd, user, domain, kr); - SMBOWFencrypt_ntv2(kr, c8, 8, password+16, pwd_len-16, resp); - if (sess_key != NULL) - { - SMBsesskeygen_ntv2(kr, resp, sess_key); - } - -#if DEBUG_PASSWORD - DEBUG(100,("Part password (P16) was |")); - dump_data(100, part_passwd, 16); - DEBUG(100,("Password from client was |")); - dump_data(100, password, pwd_len); - DEBUG(100,("Given challenge was |")); - dump_data(100, c8, 8); - DEBUG(100,("Value from encryption was |")); - dump_data(100, resp, 16); -#endif - - return (memcmp(resp, password, 16) == 0); -} - -/**************************************************************************** - Do a specific test for an smb password being correct, given a smb_password and - the lanman and NT responses. -****************************************************************************/ -BOOL smb_password_ok(struct smb_passwd *smb_pass, uchar chal[8], - const char *user, const char *domain, - uchar *lm_pass, size_t lm_pwd_len, - uchar *nt_pass, size_t nt_pwd_len, - uchar sess_key[16]) -{ - uchar challenge[8]; - - if (smb_pass == NULL) - { - return False; - } - - DEBUG(4,("Checking SMB password for user %s\n", - smb_pass->unix_name)); - - if (smb_pass->acct_ctrl & ACB_DISABLED) - { - DEBUG(3,("account for user %s was disabled.\n", - smb_pass->unix_name)); - return False; - } - - if (chal == NULL) - { - DEBUG(5,("use last SMBnegprot challenge\n")); - if (!last_challenge(challenge)) - { - DEBUG(1,("no challenge done - password failed\n")); - return False; - } - } - else - { - DEBUG(5,("challenge received\n")); - memcpy(challenge, chal, 8); - } - - if ((Protocol >= PROTOCOL_NT1) && (smb_pass->smb_nt_passwd != NULL)) - { - /* We have the NT MD4 hash challenge available - see if we can - use it (ie. does it exist in the smbpasswd file). - */ - if (lp_server_ntlmv2() != False && nt_pwd_len > 24) - { - DEBUG(4,("smb_password_ok: Check NTLMv2 password\n")); - if (smb_pwd_check_ntlmv2(nt_pass, nt_pwd_len, - (uchar *)smb_pass->smb_nt_passwd, - challenge, user, domain, - sess_key)) - { - return True; - } - } - if (lp_server_ntlmv2() != True && nt_pwd_len == 24) - { - DEBUG(4,("smb_password_ok: Check NT MD4 password\n")); - if (smb_pwd_check_ntlmv1((char *)nt_pass, - (uchar *)smb_pass->smb_nt_passwd, - challenge, - sess_key)) - { - DEBUG(4,("NT MD4 password check succeeded\n")); - return True; - } - } - DEBUG(4,("NT MD4 password check failed\n")); - } - - if (lp_server_ntlmv2() == True) - { - DEBUG(4,("Not checking LM MD4 password\n")); - return False; - } - - /* Try against the lanman password. smb_pass->smb_passwd == NULL means - no password, allow access. */ - - DEBUG(4,("Checking LM MD4 password\n")); - - if ((smb_pass->smb_passwd == NULL) && - (smb_pass->acct_ctrl & ACB_PWNOTREQ)) - { - DEBUG(4,("no password required for user %s\n", - smb_pass->unix_name)); - return True; - } - - if ((smb_pass->smb_passwd != NULL) && - smb_pwd_check_ntlmv1((char *)lm_pass, - (uchar *)smb_pass->smb_passwd, - challenge, NULL)) - { - DEBUG(4,("LM MD4 password check succeeded\n")); - return(True); - } - - DEBUG(4,("LM MD4 password check failed\n")); - - return False; -} - - -/**************************************************************************** -check if a username/password is OK assuming the password is a 24 byte -SMB hash -return True if the password is correct, False otherwise -****************************************************************************/ - -BOOL pass_check_smb(struct smb_passwd *smb_pass, char *domain, uchar *chal, - uchar *lm_pwd, size_t lm_pwd_len, - uchar *nt_pwd, size_t nt_pwd_len, - struct passwd *pwd, uchar user_sess_key[16]) -{ - const struct passwd *pass; - struct passwd pw; - char *user = NULL; - - if (smb_pass == NULL) - { - DEBUG(3,("Couldn't find user %s in smb_passwd file.\n", user)); - return False; - } - - user = smb_pass->unix_name; - - if (lm_pwd == NULL || nt_pwd == NULL) - { - return False; - } - - if (pwd != NULL && user == NULL) - { - pass = (struct passwd *) pwd; - user = pass->pw_name; - } - else - { - pass = Get_Pwnam(user,True); - if (pass == NULL) - { - DEBUG(3,("Couldn't find user %s\n",user)); - return False; - } - memcpy(&pw, pass, sizeof(struct passwd)); - pass = &pw; - } - - /* Quit if the account was disabled. */ - if (smb_pass->acct_ctrl & ACB_DISABLED) { - DEBUG(3,("account for user %s was disabled.\n", user)); - return False; - } - - /* Ensure the uid's match */ - if (smb_pass->unix_uid != pass->pw_uid) - { - DEBUG(3,("Error : UNIX (%d) and SMB (%d) uids in password files do not match !\n", pass->pw_uid, smb_pass->unix_uid)); - return False; - } - - if (lm_pwd[0] == '\0' && IS_BITS_SET_ALL(smb_pass->acct_ctrl, ACB_PWNOTREQ) && lp_null_passwords()) - { - DEBUG(3,("account for user %s has no password and null passwords are allowed.\n", smb_pass->unix_name)); - return(True); - } - - if (smb_password_ok(smb_pass, chal, user, domain, - lm_pwd, lm_pwd_len, - nt_pwd, nt_pwd_len, - user_sess_key)) - { - if (user_sess_key != NULL) - { -#ifdef DEBUG_PASSWORD - DEBUG(100,("user session key: ")); - dump_data(100, user_sess_key, 16); -#endif - } - return(True); - } - - DEBUG(3,("Error pass_check_smb failed\n")); - return False; -} - /**************************************************************************** check if a username/password pair is OK either via the system password database or the encrypted SMB password database @@ -589,35 +117,6 @@ BOOL password_ok(char *user, char *password, int pwlen, struct passwd *pwd, update_smbpassword_file : NULL); } -/**************************************************************************** -check if a username is valid -****************************************************************************/ -BOOL user_ok(char *user,int snum) -{ - pstring valid, invalid; - BOOL ret; - - StrnCpy(valid, lp_valid_users(snum), sizeof(pstring)); - StrnCpy(invalid, lp_invalid_users(snum), sizeof(pstring)); - - string_sub(valid,"%S",lp_servicename(snum)); - string_sub(invalid,"%S",lp_servicename(snum)); - - ret = !user_in_list(user,invalid); - - if (ret && valid && *valid) { - ret = user_in_list(user,valid); - } - - if (ret && lp_onlyuser(snum)) { - char *user_list = lp_username(snum); - string_sub(user_list,"%S",lp_servicename(snum)); - ret = user_in_list(user,user_list); - } - - return(ret); -} - diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index a0ad2ca20d..81f2a9beb9 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -415,6 +415,7 @@ static int session_trust_account(connection_struct *conn, char *inbuf, char *out char *smb_nt_passwd, int smb_nt_passlen) { struct smb_passwd *smb_trust_acct = NULL; /* check if trust account exists */ + uchar last_chal[8]; if (lp_security() == SEC_USER) { smb_trust_acct = getsmbpwnam(user); @@ -441,8 +442,8 @@ static int session_trust_account(connection_struct *conn, char *inbuf, char *out SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES); return(ERROR(0, 0xc0000000|NT_STATUS_LOGON_FAILURE)); } - - if (!smb_password_ok(smb_trust_acct, NULL, NULL, NULL, + if (!last_challenge(last_chal) || + !smb_password_ok(smb_trust_acct, last_chal, NULL, NULL, (unsigned char *)smb_passwd, smb_passlen, (unsigned char *)smb_nt_passwd, smb_nt_passlen, NULL)) { diff --git a/source3/smbd/server.c b/source3/smbd/server.c index 5512e6e56b..7fde1fc6f6 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -678,6 +678,18 @@ static void usage(char *pname) } #endif /* WITH_SSL */ +#if 0 + start_msrpc_agent("lsarpc"); +#endif + add_msrpc_command_processor( "samr", "lsass", api_samr_rpc ); + add_msrpc_command_processor( "srvsvc", "ntsvcs", api_srvsvc_rpc ); + add_msrpc_command_processor( "wkssvc", "ntsvcs", api_wkssvc_rpc ); + add_msrpc_command_processor( "browser", "ntsvcs", api_brs_rpc ); + add_msrpc_command_processor( "svcctl", "ntsvcs", api_svcctl_rpc ); + add_msrpc_command_processor( "NETLOGON", "lsass", api_netlog_rpc ); + add_msrpc_command_processor( "winreg", "winreg", api_reg_rpc ); + add_msrpc_command_processor( "spoolss", "spoolss", api_spoolss_rpc ); + codepage_initialise(lp_client_code_page()); if (!pwdb_initialise(True)) -- cgit