From 8584c6bd6621eefb49aff69581caf28e38b4ceda Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 22 Apr 1998 00:56:38 +0000 Subject: genrand.c: Improved generation of random values, more secure. loadparm.c: Started add of 'security=domain' code. password.c: Fix for security=server NT bugs. reply.c: Started add of 'security=domain' code. server.c: Started add of 'security=domain' code. smb.h: Started add of 'security=domain' code. Jeremy. (This used to be commit e6bda112ebe0d41f54c4249b5c2e1f24011347e1) --- source3/include/smb.h | 4 ++++ source3/lib/genrand.c | 41 ++++++++++++++++++++++++++++++++--------- source3/param/loadparm.c | 6 ++++++ source3/smbd/password.c | 39 ++++++++++++++++++++++++++++++++++++--- source3/smbd/reply.c | 12 +++++++++++- source3/smbd/server.c | 4 ++++ 6 files changed, 93 insertions(+), 13 deletions(-) (limited to 'source3') diff --git a/source3/include/smb.h b/source3/include/smb.h index 46e282b2ba..4438024dbd 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -1061,7 +1061,11 @@ char *Strstr(char *s, char *p); enum protocol_types {PROTOCOL_NONE,PROTOCOL_CORE,PROTOCOL_COREPLUS,PROTOCOL_LANMAN1,PROTOCOL_LANMAN2,PROTOCOL_NT1}; /* security levels */ +#ifdef DOMAIN_CLIENT +enum security_types {SEC_SHARE,SEC_USER,SEC_SERVER,SEC_DOMAIN}; +#else /* DOMAIN_CLIENT */ enum security_types {SEC_SHARE,SEC_USER,SEC_SERVER}; +#endif /* DOMAIN_CLIENT */ /* printing types */ enum printing_types {PRINT_BSD,PRINT_SYSV,PRINT_AIX,PRINT_HPUX, diff --git a/source3/lib/genrand.c b/source3/lib/genrand.c index 8d7084d9f6..e20f054504 100644 --- a/source3/lib/genrand.c +++ b/source3/lib/genrand.c @@ -26,7 +26,6 @@ extern int DEBUGLEVEL; static uint32 counter = 0; - /**************************************************************** get a 16 byte hash from the contents of a file Note that the hash is not initialised. @@ -102,18 +101,19 @@ static void do_dirrand(char *name, unsigned char *buf, int buf_len) Try and get a good random number seed. Try a number of different factors. Firstly, try /dev/random and try and read from this. If this fails iterate through /tmp and - XOR all the file timestamps. If this fails then just use - a combination of pid and time of day (yes I know this + /dev and XOR all the file timestamps. Next add in + a hash of the contents of /etc/shadow and the smb passwd + file and a combination of pid and time of day (yes I know this sucks :-). Finally md4 the result. The result goes in a 16 byte buffer passed from the caller **************************************************************/ -static void do_reseed(unsigned char *md4_outbuf) +static uint32 do_reseed(unsigned char *md4_outbuf) { unsigned char md4_inbuf[40]; BOOL got_random = False; - uint32 v1, v2; + uint32 v1, v2, ret; int fd; struct timeval tval; pid_t mypid; @@ -135,7 +135,7 @@ static void do_reseed(unsigned char *md4_outbuf) if(!got_random) { /* - * /dev/random failed - try /tmp/ for timestamps. + * /dev/random failed - try /tmp and /dev for timestamps. */ do_dirrand("/tmp", md4_inbuf, sizeof(md4_inbuf)); do_dirrand("/dev", md4_inbuf, sizeof(md4_inbuf)); @@ -148,7 +148,7 @@ static void do_reseed(unsigned char *md4_outbuf) /* add in the root encrypted password. On any system where security is taken seriously this will be secret */ pw = getpwnam("root"); - if (pw) { + if (pw && pw->pw_passwd) { int i; unsigned char md4_tmp[16]; mdfour(md4_tmp, pw->pw_passwd, strlen(pw->pw_passwd)); @@ -168,6 +168,16 @@ static void do_reseed(unsigned char *md4_outbuf) SIVAL(md4_inbuf, 36, v2 ^ IVAL(md4_inbuf, 36)); mdfour(md4_outbuf, md4_inbuf, sizeof(md4_inbuf)); + + /* + * Return a 32 bit int created from XORing the + * 16 bit return buffer. + */ + + ret = IVAL(md4_outbuf, 0); + ret ^= IVAL(md4_outbuf, 4); + ret ^= IVAL(md4_outbuf, 8); + return (ret ^ IVAL(md4_outbuf, 12)); } /******************************************************************* @@ -177,25 +187,38 @@ static void do_reseed(unsigned char *md4_outbuf) void generate_random_buffer( unsigned char *out, int len, BOOL re_seed) { static BOOL done_reseed = False; + static unsigned char md4_buf[16]; unsigned char tmp_buf[16]; - unsigned char md4_buf[16]; unsigned char *p; if(!done_reseed || re_seed) { - do_reseed(md4_buf); + srandom(do_reseed(md4_buf)); done_reseed = True; } /* * Generate random numbers in chunks of 64 bytes, * then md4 them & copy to the output buffer. + * Added XOR with output from random, seeded + * by the original md4_buf. This is to stop the + * output from this function being the previous + * md4_buf md4'ed. The output from this function + * is often output onto the wire, and so it should + * not be possible to guess the next output from + * this function based on the previous output. + * XORing in the output from random(), seeded by + * the original md4 hash should stop this. JRA. */ p = out; while(len > 0) { + int i; int copy_len = len > 16 ? 16 : len; mdfour(tmp_buf, md4_buf, sizeof(md4_buf)); memcpy(md4_buf, tmp_buf, sizeof(md4_buf)); + /* XOR in output from random(). */ + for(i = 0; i < 4; i++) + SIVAL(tmp_buf, i*4, (IVAL(tmp_buf, i*4) ^ (uint32)random())); memcpy(p, tmp_buf, copy_len); p += copy_len; len -= copy_len; diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index ce9b816e81..661ca901fa 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -402,8 +402,14 @@ static struct enum_list enum_protocol[] = {{PROTOCOL_NT1, "NT1"}, {PROTOCOL_LANM {PROTOCOL_COREPLUS, "COREPLUS"}, {PROTOCOL_COREPLUS, "CORE+"}, {-1, NULL}}; +#ifdef DOMAIN_CLIENT +static struct enum_list enum_security[] = {{SEC_SHARE, "SHARE"}, {SEC_USER, "USER"}, + {SEC_SERVER, "SERVER"}, {SEC_DOMAIN, "DOMAIN"}, + {-1, NULL}}; +#else /* DOMAIN_CLIENT */ static struct enum_list enum_security[] = {{SEC_SHARE, "SHARE"}, {SEC_USER, "USER"}, {SEC_SERVER, "SERVER"}, {-1, NULL}}; +#endif /* DOMAIN_CLIENT */ static struct enum_list enum_printing[] = {{PRINT_SYSV, "sysv"}, {PRINT_AIX, "aix"}, {PRINT_HPUX, "hpux"}, {PRINT_BSD, "bsd"}, diff --git a/source3/smbd/password.c b/source3/smbd/password.c index b69b58f54e..c347f2de0d 100644 --- a/source3/smbd/password.c +++ b/source3/smbd/password.c @@ -1755,12 +1755,48 @@ BOOL server_validate(char *user, char *domain, char *ntpass, int ntpasslen) { extern fstring local_machine; + static unsigned char badpass[24]; if (!cli.initialised) { DEBUG(1,("password server %s is not connected\n", cli.desthost)); return(False); } + if(badpass[0] == 0) { + memset(badpass, 0x1f, sizeof(badpass)); + } + + if((passlen == sizeof(badpass)) && !memcmp(badpass, pass, passlen)) { + /* Very unlikely, our random bad password is the same as the users + password. */ + memset(badpass, badpass[0]+1, sizeof(badpass)); + } + + /* + * Attempt a session setup with a totally incorrect password. + * If this succeeds with the guest bit *NOT* set then the password + * server is broken and is not correctly setting the guest bit. We + * need to detect this as some versions of NT4.x are broken. JRA. + */ + + if (cli_session_setup(&cli, user, badpass, sizeof(badpass), badpass, sizeof(badpass), + domain)) { + if ((SVAL(cli.inbuf,smb_vwv2) & 1) == 0) { + DEBUG(0,("server_validate: password server %s allows users as non-guest \ +with a bad password.\n", cli.desthost)); + DEBUG(0,("server_validate: This is broken (and insecure) behaviour. Please do not \ +use this machine as the password server.\n")); + cli_ulogoff(&cli); + return False; + } + cli_ulogoff(&cli); + } + + /* + * Now we know the password server will correctly set the guest bit, or is + * not guest enabled, we can try with the real password. + */ + if (!cli_session_setup(&cli, user, pass, passlen, ntpass, ntpasslen, domain)) { DEBUG(1,("password server %s rejected the password\n", cli.desthost)); return False; @@ -1773,7 +1809,6 @@ BOOL server_validate(char *user, char *domain, return(False); } - if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) { DEBUG(1,("password server %s refused IPC$ connect\n", cli.desthost)); cli_ulogoff(&cli); @@ -1825,5 +1860,3 @@ BOOL server_validate(char *user, char *domain, return(True); } - - diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 2c4800b1c2..2f3b3660fc 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -515,7 +515,11 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize) passlen1 = MIN(passlen1, MAX_PASS_LEN); passlen2 = MIN(passlen2, MAX_PASS_LEN); - if(doencrypt || (lp_security() == SEC_SERVER)) { +#ifdef DOMAIN_CLIENT + if(doencrypt || ((lp_security() == SEC_SERVER) || (lp_security() == SEC_DOMAIN))) { +#else /* DOMAIN_CLIENT */ + if(doencrypt || lp_security() == SEC_SERVER) { +#endif /* DOMAIN_CLIENT */ /* Save the lanman2 password and the NT md4 password. */ smb_apasslen = passlen1; memcpy(smb_apasswd,p,smb_apasslen); @@ -603,6 +607,12 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize) server_validate(user, domain, smb_apasswd, smb_apasslen, smb_ntpasswd, smb_ntpasslen)) && +#ifdef DOMAIN_CLIENT + !(lp_security() == SEC_DOMAIN && + domain_client_validate(user, domain, + smb_apasswd, smb_apasslen, + smb_ntpasswd, smb_ntpasslen)) && +#endif /* DOMAIN_CLIENT */ !check_hosts_equiv(user)) { diff --git a/source3/smbd/server.c b/source3/smbd/server.c index 4a3edeb871..81fe5c9306 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -4133,7 +4133,11 @@ static int reply_negprot(char *inbuf,char *outbuf, int dum_size, int dum_buffsiz /* a special case to stop password server loops */ if (Index == 1 && strequal(remote_machine,myhostname) && +#ifdef DOMAIN_CLIENT + (lp_security()==SEC_SERVER || lp_security()==SEC_DOMAIN)) +#else /* DOMAIN_CLIENT */ lp_security()==SEC_SERVER) +#endif /* DOMAIN_CLIENT */ exit_server("Password server loop!"); /* Check for protocols, most desirable first */ -- cgit