From 0891bb6a910841455162876be09a92107cd9df00 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 21 Oct 1997 09:34:33 +0000 Subject: rewrote the password server code using the new clientgen.c client interface The new code uses a source netbios name equal to the Samba servers name, not the client name. It also uses NetWkstaUserLogon to do a full network logon. This means it will honour the servers logon restrictions (such as login times etc). (This used to be commit 11de90f972f6d83974425e80014f54e15d495413) --- source3/smbd/password.c | 275 +++++++++++++++++++----------------------------- source3/smbd/reply.c | 11 +- source3/smbd/server.c | 158 +++++++++++++--------------- 3 files changed, 191 insertions(+), 253 deletions(-) (limited to 'source3/smbd') diff --git a/source3/smbd/password.c b/source3/smbd/password.c index 311ef47679..24ee52ed69 100644 --- a/source3/smbd/password.c +++ b/source3/smbd/password.c @@ -1475,206 +1475,143 @@ BOOL check_hosts_equiv(char *user) } -int password_client = -1; -static fstring pserver; -static char *secserver_inbuf = NULL; +static struct cli_state cli; /**************************************************************************** -attempted support for server level security +return the client state structure ****************************************************************************/ -BOOL server_cryptkey(char *buf) +struct cli_state *server_client(void) { - pstring outbuf; - fstring pass_protocol; - extern fstring remote_machine; - char *p; - int len; - fstring desthost; - struct in_addr dest_ip; - int port = SMB_PORT; - BOOL ret; - - if(secserver_inbuf == NULL) { - secserver_inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); - if(secserver_inbuf == NULL) { - DEBUG(0,("server_cryptkey: malloc fail for input buffer.\n")); - return False; - } - } - - if (password_client >= 0) - close(password_client); - password_client = -1; - - if (Protocol < PROTOCOL_NT1) { - strcpy(pass_protocol,"LM1.2X002"); - } else { - strcpy(pass_protocol,"NT LM 0.12"); - } - - bzero(secserver_inbuf,BUFFER_SIZE + SAFETY_MARGIN); - bzero(outbuf,sizeof(outbuf)); - - for (p=strtok(lp_passwordserver(),LIST_SEP); p ; p = strtok(NULL,LIST_SEP)) { - strcpy(desthost,p); - standard_sub_basic(desthost); - strupper(desthost); - - dest_ip = *interpret_addr2(desthost); - if (zero_ip(dest_ip)) { - DEBUG(1,("Can't resolve address for %s\n",p)); - continue; - } - - if (ismyip(dest_ip)) { - DEBUG(1,("Password server loop - disabling password server %s\n",p)); - continue; - } - - password_client = open_socket_out(SOCK_STREAM, &dest_ip, port, SHORT_CONNECT_TIMEOUT); - if (password_client >= 0) { - DEBUG(3,("connected to password server %s\n",p)); - StrnCpy(pserver,p,sizeof(pserver)-1); - break; - } - } - - if (password_client < 0) { - DEBUG(1,("password server not available\n")); - return(False); - } - - - /* send a session request (RFC 8002) */ - - /* put in the destination name */ - len = 4; - p = outbuf+len; - name_mangle(desthost,p,' '); - len += name_len(p); - p = outbuf+len; - - /* and my name */ - /* Fix from Frank Varnavas . - We cannot use the same name as the client to - the NT password server, as NT will drop client - connections if the same client name connects - twice. Instead, synthesize a name from our pid. - and the remote machine name. - */ - { - char buf2[32]; /* create name as PIDname */ - sprintf(buf2,"%d", getpid()); - strncpy(&buf2[strlen(buf2)], remote_machine, 31 - strlen(buf2)); - buf2[31] = '\0'; - DEBUG(1,("negprot w/password server as %s\n",buf2)); - name_mangle(buf2,p,' '); - len += name_len(p); - } - - _smb_setlen(outbuf,len); - CVAL(outbuf,0) = 0x81; - - send_smb(password_client,outbuf); - - - if (!receive_smb(password_client,secserver_inbuf,5000) || - CVAL(secserver_inbuf,0) != 0x82) { - DEBUG(1,("%s rejected the session\n",pserver)); - close(password_client); password_client = -1; - return(False); - } + return &cli; +} - DEBUG(3,("got session\n")); +/**************************************************************************** +support for server level security +****************************************************************************/ +struct cli_state *server_cryptkey(void) +{ + fstring desthost; + struct in_addr dest_ip; + extern fstring local_machine; + char *p; + + if (!cli_initialise(&cli)) + return NULL; + + for (p=strtok(lp_passwordserver(),LIST_SEP); p ; p = strtok(NULL,LIST_SEP)) { + fstrcpy(desthost,p); + standard_sub_basic(desthost); + strupper(desthost); + + dest_ip = *interpret_addr2(desthost); + if (zero_ip(dest_ip)) { + DEBUG(1,("Can't resolve address for %s\n",p)); + continue; + } - bzero(outbuf,smb_size); + if (ismyip(dest_ip)) { + DEBUG(1,("Password server loop - disabling password server %s\n",p)); + continue; + } - /* setup the protocol string */ - set_message(outbuf,0,strlen(pass_protocol)+2,True); - p = smb_buf(outbuf); - *p++ = 2; - strcpy(p,pass_protocol); + if (cli_connect(&cli, desthost, &dest_ip)) { + DEBUG(3,("connected to password server %s\n",p)); + break; + } + } - CVAL(outbuf,smb_com) = SMBnegprot; - CVAL(outbuf,smb_flg) = 0x8; - SSVAL(outbuf,smb_flg2,0x1); + if (!p) { + DEBUG(1,("password server not available\n")); + cli_shutdown(&cli); + return NULL; + } - send_smb(password_client,outbuf); - ret = receive_smb(password_client,secserver_inbuf,5000); + if (!cli_session_request(&cli, desthost, 0x20, local_machine)) { + DEBUG(1,("%s rejected the session\n",desthost)); + cli_shutdown(&cli); + return NULL; + } - if (!ret || CVAL(secserver_inbuf,smb_rcls) || SVAL(secserver_inbuf,smb_vwv0)) { - DEBUG(1,("%s rejected the protocol\n",pserver)); - close(password_client); password_client= -1; - return(False); - } + DEBUG(3,("got session\n")); - if (!(CVAL(secserver_inbuf,smb_vwv1) & 1)) { - DEBUG(1,("%s isn't in user level security mode\n",pserver)); - close(password_client); password_client= -1; - return(False); - } + if (!cli_negprot(&cli)) { + DEBUG(1,("%s rejected the negprot\n",desthost)); + cli_shutdown(&cli); + return NULL; + } - memcpy(buf,secserver_inbuf,smb_len(secserver_inbuf)+4); + if (cli.protocol < PROTOCOL_LANMAN2 || + !(cli.sec_mode & 1)) { + DEBUG(1,("%s isn't in user level security mode\n",desthost)); + cli_shutdown(&cli); + return NULL; + } - DEBUG(3,("password server OK\n")); + DEBUG(3,("password server OK\n")); - return(True); + return &cli; } /**************************************************************************** -support for server level security +validate a password with the password server ****************************************************************************/ -BOOL server_validate(char *buf) +BOOL server_validate(char *user, char *domain, + char *pass, int passlen, + char *ntpass, int ntpasslen) { - pstring outbuf; - BOOL ret; + extern fstring local_machine; + fstring share; - if(secserver_inbuf == NULL) { - secserver_inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); - if(secserver_inbuf == NULL) { - DEBUG(0,("server_validate: malloc fail for input buffer.\n")); - return False; - } - } + if (!cli.initialised) { + DEBUG(1,("password server %s is not connected\n", cli.desthost)); + return(False); + } - if (password_client < 0) { - DEBUG(1,("%s not connected\n",pserver)); - return(False); - } + if (!cli_session_setup(&cli, user, pass, passlen, ntpass, ntpasslen, domain)) { + DEBUG(1,("password server %s rejected the password\n", cli.desthost)); + return False; + } - bzero(secserver_inbuf,BUFFER_SIZE + SAFETY_MARGIN); - memcpy(outbuf,buf,sizeof(outbuf)); + /* if logged in as guest then reject */ + if ((SVAL(cli.inbuf,smb_vwv2) & 1) != 0) { + DEBUG(1,("password server %s gave us guest only\n", cli.desthost)); + return(False); + } - /* send a session setup command */ - CVAL(outbuf,smb_flg) = 0x8; - SSVAL(outbuf,smb_flg2,0x1); - CVAL(outbuf,smb_vwv0) = 0xFF; - set_message(outbuf,smb_numwords(outbuf),smb_buflen(outbuf),False); + sprintf(share,"\\\\%s\\IPC$", cli.desthost); - SCVAL(secserver_inbuf,smb_rcls,1); + if (!cli_send_tconX(&cli, share, "IPC", "", 1)) { + DEBUG(1,("password server %s refused IPC$ connect\n", cli.desthost)); + return False; + } - send_smb(password_client,outbuf); - ret = receive_smb(password_client,secserver_inbuf,5000); - if (!ret || CVAL(secserver_inbuf,smb_rcls) != 0) { - DEBUG(1,("password server %s rejected the password\n",pserver)); - return(False); - } + if (!cli_NetWkstaUserLogon(&cli,user,local_machine)) { + DEBUG(1,("password server %s failed NetWkstaUserLogon\n", cli.desthost)); + cli_tdis(&cli); + return False; + } - /* if logged in as guest then reject */ - if ((SVAL(secserver_inbuf,smb_vwv2) & 1) != 0) { - DEBUG(1,("password server %s gave us guest only\n",pserver)); - return(False); - } + if (cli.privilages == 0) { + DEBUG(1,("password server %s gave guest privilages\n", cli.desthost)); + cli_tdis(&cli); + return False; + } + + if (!strequal(cli.eff_name, user)) { + DEBUG(1,("password server %s gave different username %s\n", + cli.desthost, + cli.eff_name)); + cli_tdis(&cli); + return False; + } - DEBUG(3,("password server %s accepted the password\n",pserver)); + DEBUG(3,("password server %s accepted the password\n", cli.desthost)); -#if !KEEP_PASSWORD_SERVER_OPEN - close(password_client); password_client= -1; -#endif + cli_tdis(&cli); - return(True); + return(True); } diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 424c7d8183..3643b6eed0 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -379,8 +379,10 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize) BOOL computer_id=False; static BOOL done_sesssetup = False; BOOL doencrypt = SMBENCRYPT(); + char *domain = ""; *smb_apasswd = 0; + *smb_ntpasswd = 0; smb_bufsize = SVAL(inbuf,smb_vwv2); smb_mpxmax = SVAL(inbuf,smb_vwv3); @@ -469,8 +471,10 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize) p += passlen1 + passlen2; fstrcpy(user,p); p = skip_string(p,1); + domain = p; + DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s]\n", - p,skip_string(p,1),skip_string(p,2))); + domain,skip_string(p,1),skip_string(p,2))); } @@ -533,7 +537,10 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize) if(!guest && strequal(user,lp_guestaccount(-1)) && (*smb_apasswd == 0)) guest = True; - if (!guest && !(lp_security() == SEC_SERVER && server_validate(inbuf)) && + if (!guest && !(lp_security() == SEC_SERVER && + server_validate(user, domain, + smb_apasswd, smb_apasslen, + smb_ntpasswd, smb_ntpasslen)) && !check_hosts_equiv(user)) { diff --git a/source3/smbd/server.c b/source3/smbd/server.c index 7639c5940b..f6a43a536d 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -2320,22 +2320,21 @@ static int sig_cld() **************************************************************************/ static int sig_pipe() { - extern int password_client; - BlockSignals(True,SIGPIPE); + struct cli_state *cli; + BlockSignals(True,SIGPIPE); - if (password_client != -1) { - DEBUG(3,("lost connection to password server\n")); - close(password_client); - password_client = -1; + if ((cli = server_client()) && cli->initialised) { + DEBUG(3,("lost connection to password server\n")); + cli_shutdown(cli); #ifndef DONT_REINSTALL_SIG - signal(SIGPIPE, SIGNAL_CAST sig_pipe); + signal(SIGPIPE, SIGNAL_CAST sig_pipe); #endif - BlockSignals(False,SIGPIPE); - return 0; - } + BlockSignals(False,SIGPIPE); + return 0; + } - exit_server("Got sigpipe\n"); - return(0); + exit_server("Got sigpipe\n"); + return(0); } /**************************************************************************** @@ -3564,11 +3563,6 @@ int reply_lanman1(char *outbuf) Protocol = PROTOCOL_LANMAN1; - if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) { - DEBUG(3,("using password server validation\n")); - if (doencrypt) set_challenge(smb_buf(outbuf)); - } - CVAL(outbuf,smb_flg) = 0x81; /* Reply, SMBlockread, SMBwritelock supported */ SSVAL(outbuf,smb_mid,mid); /* Restore possibly corrupted mid */ SSVAL(outbuf,smb_vwv2,max_recv); @@ -3594,32 +3588,42 @@ int reply_lanman2(char *outbuf) int secword=0; BOOL doencrypt = SMBENCRYPT(); time_t t = time(NULL); - /* We need to save and restore this as it can be destroyed - if we call another server if security=server - Thanks to Paul Nelson @ Thursby for pointing this out. - */ - uint16 mid = SVAL(outbuf, smb_mid); + struct cli_state *cli = NULL; + char cryptkey[8]; + char crypt_len = 0; + + if (lp_security() == SEC_SERVER) { + cli = server_cryptkey(); + } + + if (cli) { + DEBUG(3,("using password server validation\n")); + doencrypt = ((cli->sec_mode & 2) != 0); + } if (lp_security()>=SEC_USER) secword |= 1; if (doencrypt) secword |= 2; - set_message(outbuf,13,doencrypt?8:0,True); + if (doencrypt) { + crypt_len = 8; + if (!cli) { + generate_next_challenge(cryptkey); + } else { + memcpy(cryptkey, cli->cryptkey, 8); + set_challenge(cli->cryptkey); + } + } + + set_message(outbuf,13,crypt_len,True); SSVAL(outbuf,smb_vwv1,secword); - /* Create a token value and add it to the outgoing packet. */ if (doencrypt) - generate_next_challenge(smb_buf(outbuf)); + memcpy(smb_buf(outbuf), cryptkey, 8); SIVAL(outbuf,smb_vwv6,getpid()); Protocol = PROTOCOL_LANMAN2; - if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) { - DEBUG(3,("using password server validation\n")); - if (doencrypt) set_challenge(smb_buf(outbuf)); - } - CVAL(outbuf,smb_flg) = 0x81; /* Reply, SMBlockread, SMBwritelock supported */ - SSVAL(outbuf,smb_mid,mid); /* Restore possibly corrupted mid */ SSVAL(outbuf,smb_vwv2,max_recv); SSVAL(outbuf,smb_vwv3,lp_maxmux()); SSVAL(outbuf,smb_vwv4,1); @@ -3641,67 +3645,58 @@ int reply_nt1(char *outbuf) /* other valid capabilities which we may support at some time... CAP_LARGE_FILES|CAP_NT_SMBS|CAP_RPC_REMOTE_APIS; - CAP_LARGE_FILES|CAP_LARGE_READX| - CAP_STATUS32|CAP_LEVEL_II_OPLOCKS; + CAP_LARGE_READX|CAP_STATUS32|CAP_LEVEL_II_OPLOCKS; */ int secword=0; BOOL doencrypt = SMBENCRYPT(); time_t t = time(NULL); int data_len; - int encrypt_len; - char challenge_len = 8; - /* We need to save and restore this as it can be destroyed - if we call another server if security=server - Thanks to Paul Nelson @ Thursby for pointing this out. - */ - uint16 mid = SVAL(outbuf, smb_mid); + struct cli_state *cli = NULL; + char cryptkey[8]; + char crypt_len = 0; - if (lp_readraw() && lp_writeraw()) - { - capabilities |= CAP_RAW_MODE; + if (lp_security() == SEC_SERVER) { + cli = server_cryptkey(); } - if (lp_security()>=SEC_USER) secword |= 1; + if (cli) { + DEBUG(3,("using password server validation\n")); + doencrypt = ((cli->sec_mode & 2) != 0); + } + + if (doencrypt) { + crypt_len = 8; + if (!cli) { + generate_next_challenge(cryptkey); + } else { + memcpy(cryptkey, cli->cryptkey, 8); + set_challenge(cli->cryptkey); + } + } + + if (lp_readraw() && lp_writeraw()) { + capabilities |= CAP_RAW_MODE; + } + + if (lp_security() >= SEC_USER) secword |= 1; if (doencrypt) secword |= 2; /* decide where (if) to put the encryption challenge, and follow it with the OEM'd domain name */ - encrypt_len = doencrypt?challenge_len:0; -#if UNICODE - data_len = encrypt_len + 2*(strlen(myworkgroup)+1); -#else - data_len = encrypt_len + strlen(myworkgroup) + 1; -#endif + data_len = crypt_len + strlen(myworkgroup) + 1; set_message(outbuf,17,data_len,True); - -#if UNICODE - /* put the OEM'd domain name */ - PutUniCode(smb_buf(outbuf)+encrypt_len,myworkgroup); -#else - strcpy(smb_buf(outbuf)+encrypt_len, myworkgroup); -#endif + strcpy(smb_buf(outbuf)+crypt_len, myworkgroup); CVAL(outbuf,smb_vwv1) = secword; - /* Create a token value and add it to the outgoing packet. */ - if (doencrypt) - { - generate_next_challenge(smb_buf(outbuf)); - - /* Tell the nt machine how long the challenge is. */ - SSVALS(outbuf,smb_vwv16+1,challenge_len); - } + SSVALS(outbuf,smb_vwv16+1,crypt_len); + if (doencrypt) + memcpy(smb_buf(outbuf), cryptkey, 8); Protocol = PROTOCOL_NT1; - if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) { - DEBUG(3,("using password server validation\n")); - if (doencrypt) set_challenge(smb_buf(outbuf)); - } - - SSVAL(outbuf,smb_mid,mid); /* Restore possibly corrupted mid */ SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */ SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */ SIVAL(outbuf,smb_vwv3+1,0xffff); /* max buffer. LOTS! */ @@ -4766,17 +4761,16 @@ static void process(void) if (keepalive && (counter-last_keepalive)>keepalive) { - extern int password_client; - if (!send_keepalive(Client)) - { - DEBUG(2,("%s Keepalive failed - exiting\n",timestring())); - return; - } - /* also send a keepalive to the password server if its still - connected */ - if (password_client != -1) - send_keepalive(password_client); - last_keepalive = counter; + struct cli_state *cli = server_client(); + if (!send_keepalive(Client)) { + DEBUG(2,("%s Keepalive failed - exiting\n",timestring())); + return; + } + /* also send a keepalive to the password server if its still + connected */ + if (cli && cli->initialised) + send_keepalive(cli->fd); + last_keepalive = counter; } /* check for connection timeouts */ -- cgit