diff options
author | Andrew Tridgell <tridge@samba.org> | 1996-06-04 06:42:03 +0000 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 1996-06-04 06:42:03 +0000 |
commit | 0d8dcfa13c527ec2c8aca39ba49c09e4e694b26c (patch) | |
tree | 5e811c2a4419ac3c544291de3fefced4bb367f6a /source | |
parent | 72543810ce3eb5ea7b141f957edf38b4c46b1ea4 (diff) | |
download | samba-0d8dcfa13c527ec2c8aca39ba49c09e4e694b26c.tar.gz |
a huge pile of changes :-)
The biggest thing is the integration of Lukes new nmbd. Its still
largely untested, so we will really need some feedback
I've also added auto prototype generation and cleaned up a lot of
minor things as a result
Diffstat (limited to 'source')
44 files changed, 7393 insertions, 3812 deletions
diff --git a/source/client/client.c b/source/client/client.c index a40d377955c..3cefbc2284c 100644 --- a/source/client/client.c +++ b/source/client/client.c @@ -24,7 +24,6 @@ #endif #include "includes.h" -#include "nameserv.h" #ifndef REGISTER #define REGISTER 0 @@ -44,6 +43,7 @@ BOOL connect_as_printer = False; BOOL connect_as_ipc = False; extern struct in_addr bcast_ip; static BOOL got_bcast=False; +struct in_addr ipzero; char cryptkey[8]; BOOL doencrypt=False; @@ -72,16 +72,29 @@ extern int DEBUGLEVEL; BOOL translation = False; + +static BOOL send_trans_request(char *outbuf,int trans, + char *name,int fid,int flags, + char *data,char *param,uint16 *setup, + int ldata,int lparam,int lsetup, + int mdata,int mparam,int msetup); +static BOOL receive_trans_response(char *inbuf,int trans, + int *data_len,int *param_len, + char **data,char **param); +static int interpret_long_filename(int level,char *p,file_info *finfo); +static void dir_action(char *inbuf,char *outbuf,int attribute,file_info *finfo,BOOL recurse_dir,void (*fn)(),BOOL longdir); +static int interpret_short_filename(char *p,file_info *finfo); +static BOOL call_api(int prcnt,int drcnt, + int mprcnt,int mdrcnt, + int *rprcnt,int *rdrcnt, + char *param,char *data, + char **rparam,char **rdata); + + /* clitar bits insert */ -extern void cmd_tar(); -extern void cmd_block(); -extern void cmd_tarmode(); -extern void cmd_setmode(); extern int blocksize; extern BOOL tar_inc; extern BOOL tar_reset; -extern int process_tar(); -extern int tar_parseargs(); /* clitar bits end */ @@ -151,20 +164,6 @@ setup_term_code (char *code) #define CNV_INPUT(s) unix2dos_format(s,True) #endif -static void send_logout(void ); -BOOL reopen_connection(char *inbuf,char *outbuf); -static int do_long_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir); -static int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir); -static BOOL call_api(int prcnt,int drcnt,int mprcnt,int mdrcnt, - int *rprcnt,int *rdrcnt,char *param,char *data, - char **rparam,char **rdata); -static BOOL send_trans_request(char *outbuf,int trans, - char *name,int fid,int flags, - char *data,char *param,uint16 *setup, - int ldata,int lparam,int lsetup, - int mdata,int mparam,int msetup); - - /**************************************************************************** setup basics in a outgoing packet ****************************************************************************/ @@ -486,6 +485,319 @@ static void display_finfo(file_info *finfo) asctime(LocalTime(&t)))); } + +/**************************************************************************** + do a directory listing, calling fn on each file found. Use the TRANSACT2 + call for long filenames + ****************************************************************************/ +static int do_long_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir) +{ + int max_matches = 512; + int info_level = Protocol<PROTOCOL_NT1?1:260; /* NT uses 260, OS/2 uses 2. Both accept 1. */ + char *p; + pstring mask; + file_info finfo; + int i; + char *dirlist = NULL; + int dirlist_len = 0; + int total_received = 0; + BOOL First = True; + char *resp_data=NULL; + char *resp_param=NULL; + int resp_data_len = 0; + int resp_param_len=0; + + int ff_resume_key = 0; + int ff_searchcount=0; + int ff_eos=0; + int ff_lastname=0; + int ff_dir_handle=0; + int loop_count = 0; + + uint16 setup; + pstring param; + + strcpy(mask,Mask); + + while (ff_eos == 0) + { + loop_count++; + if (loop_count > 200) + { + DEBUG(0,("ERROR: Looping in FIND_NEXT??\n")); + break; + } + + if (First) + { + setup = TRANSACT2_FINDFIRST; + SSVAL(param,0,attribute); /* attribute */ + SSVAL(param,2,max_matches); /* max count */ + SSVAL(param,4,8+4+2); /* resume required + close on end + continue */ + SSVAL(param,6,info_level); + SIVAL(param,8,0); + strcpy(param+12,mask); + } + else + { + setup = TRANSACT2_FINDNEXT; + SSVAL(param,0,ff_dir_handle); + SSVAL(param,2,max_matches); /* max count */ + SSVAL(param,4,info_level); + SIVAL(param,6,ff_resume_key); /* ff_resume_key */ + SSVAL(param,10,8+4+2); /* resume required + close on end + continue */ + strcpy(param+12,mask); + + DEBUG(5,("hand=0x%X resume=%d ff_lastname=%d mask=%s\n", + ff_dir_handle,ff_resume_key,ff_lastname,mask)); + } + /* ??? original code added 1 pad byte after param */ + + send_trans_request(outbuf,SMBtrans2,NULL,FID_UNUSED,0, + NULL,param,&setup, + 0,12+strlen(mask)+1,1, + BUFFER_SIZE,10,0); + + if (!receive_trans_response(inbuf,SMBtrans2, + &resp_data_len,&resp_param_len, + &resp_data,&resp_param)) + { + DEBUG(3,("FIND%s gave %s\n",First?"FIRST":"NEXT",smb_errstr(inbuf))); + break; + } + + /* parse out some important return info */ + p = resp_param; + if (First) + { + ff_dir_handle = SVAL(p,0); + ff_searchcount = SVAL(p,2); + ff_eos = SVAL(p,4); + ff_lastname = SVAL(p,8); + } + else + { + ff_searchcount = SVAL(p,0); + ff_eos = SVAL(p,2); + ff_lastname = SVAL(p,6); + } + + if (ff_searchcount == 0) + break; + + /* point to the data bytes */ + p = resp_data; + + /* we might need the lastname for continuations */ + if (ff_lastname > 0) + { + switch(info_level) + { + case 260: + ff_resume_key =0; + StrnCpy(mask,p+ff_lastname,resp_data_len-ff_lastname); + /* strcpy(mask,p+ff_lastname+94); */ + break; + case 1: + strcpy(mask,p + ff_lastname + 1); + ff_resume_key = 0; + break; + } + } + else + strcpy(mask,""); + + /* and add them to the dirlist pool */ + dirlist = Realloc(dirlist,dirlist_len + resp_data_len); + + if (!dirlist) + { + DEBUG(0,("Failed to expand dirlist\n")); + break; + } + + /* put in a length for the last entry, to ensure we can chain entries + into the next packet */ + { + char *p2; + for (p2=p,i=0;i<(ff_searchcount-1);i++) + p2 += interpret_long_filename(info_level,p2,NULL); + SSVAL(p2,0,resp_data_len - PTR_DIFF(p2,p)); + } + + /* grab the data for later use */ + memcpy(dirlist+dirlist_len,p,resp_data_len); + dirlist_len += resp_data_len; + + total_received += ff_searchcount; + + if (resp_data) free(resp_data); resp_data = NULL; + if (resp_param) free(resp_param); resp_param = NULL; + + DEBUG(3,("received %d entries (eos=%d resume=%d)\n", + ff_searchcount,ff_eos,ff_resume_key)); + + First = False; + } + + if (!fn) + for (p=dirlist,i=0;i<total_received;i++) + { + p += interpret_long_filename(info_level,p,&finfo); + display_finfo(&finfo); + } + + for (p=dirlist,i=0;i<total_received;i++) + { + p += interpret_long_filename(info_level,p,&finfo); + dir_action(inbuf,outbuf,attribute,&finfo,recurse_dir,fn,True); + } + + /* free up the dirlist buffer */ + if (dirlist) free(dirlist); + return(total_received); +} + + +/**************************************************************************** + do a directory listing, calling fn on each file found + ****************************************************************************/ +static int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir) +{ + char *p; + int received = 0; + BOOL first = True; + char status[21]; + int num_asked = (max_xmit - 100)/DIR_STRUCT_SIZE; + int num_received = 0; + int i; + char *dirlist = NULL; + pstring mask; + file_info finfo; + + finfo = def_finfo; + + bzero(status,21); + + strcpy(mask,Mask); + + while (1) + { + bzero(outbuf,smb_size); + if (first) + set_message(outbuf,2,5 + strlen(mask),True); + else + set_message(outbuf,2,5 + 21,True); + +#if FFIRST + if (Protocol >= PROTOCOL_LANMAN1) + CVAL(outbuf,smb_com) = SMBffirst; + else +#endif + CVAL(outbuf,smb_com) = SMBsearch; + + SSVAL(outbuf,smb_tid,cnum); + setup_pkt(outbuf); + + SSVAL(outbuf,smb_vwv0,num_asked); + SSVAL(outbuf,smb_vwv1,attribute); + + p = smb_buf(outbuf); + *p++ = 4; + + if (first) + strcpy(p,mask); + else + strcpy(p,""); + p += strlen(p) + 1; + + *p++ = 5; + if (first) + SSVAL(p,0,0); + else + { + SSVAL(p,0,21); + p += 2; + memcpy(p,status,21); + } + + send_smb(Client,outbuf); + receive_smb(Client,inbuf,CLIENT_TIMEOUT); + + received = SVAL(inbuf,smb_vwv0); + + DEBUG(5,("dir received %d\n",received)); + + DEBUG(6,("errstr=%s\n",smb_errstr(inbuf))); + + if (received <= 0) break; + + first = False; + + dirlist = Realloc(dirlist,(num_received + received)*DIR_STRUCT_SIZE); + + if (!dirlist) + return 0; + + p = smb_buf(inbuf) + 3; + + memcpy(dirlist+num_received*DIR_STRUCT_SIZE, + p,received*DIR_STRUCT_SIZE); + + memcpy(status,p + ((received-1)*DIR_STRUCT_SIZE),21); + + num_received += received; + + if (CVAL(inbuf,smb_rcls) != 0) break; + } + +#if FFIRST + if (!first && Protocol >= PROTOCOL_LANMAN1) + { + bzero(outbuf,smb_size); + CVAL(outbuf,smb_com) = SMBfclose; + + SSVAL(outbuf,smb_tid,cnum); + setup_pkt(outbuf); + + p = smb_buf(outbuf); + *p++ = 4; + + strcpy(p,""); + p += strlen(p) + 1; + + *p++ = 5; + SSVAL(p,0,21); + p += 2; + memcpy(p,status,21); + + send_smb(Client,outbuf); + receive_smb(Client,inbuf,CLIENT_TIMEOUT,False); + + if (CVAL(inbuf,smb_rcls) != 0) + DEBUG(0,("Error closing search: %s\n",smb_errstr(inbuf))); + } +#endif + + if (!fn) + for (p=dirlist,i=0;i<num_received;i++) + { + p += interpret_short_filename(p,&finfo); + display_finfo(&finfo); + } + + for (p=dirlist,i=0;i<num_received;i++) + { + p += interpret_short_filename(p,&finfo); + dir_action(inbuf,outbuf,attribute,&finfo,recurse_dir,fn,False); + } + + if (dirlist) free(dirlist); + return(num_received); +} + + + /**************************************************************************** do a directory listing, calling fn on each file found ****************************************************************************/ @@ -685,148 +997,11 @@ static void dir_action(char *inbuf,char *outbuf,int attribute,file_info *finfo,B /**************************************************************************** - do a directory listing, calling fn on each file found - ****************************************************************************/ -static int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir) -{ - char *p; - int received = 0; - BOOL first = True; - char status[21]; - int num_asked = (max_xmit - 100)/DIR_STRUCT_SIZE; - int num_received = 0; - int i; - char *dirlist = NULL; - pstring mask; - file_info finfo; - - finfo = def_finfo; - - bzero(status,21); - - strcpy(mask,Mask); - - while (1) - { - bzero(outbuf,smb_size); - if (first) - set_message(outbuf,2,5 + strlen(mask),True); - else - set_message(outbuf,2,5 + 21,True); - -#if FFIRST - if (Protocol >= PROTOCOL_LANMAN1) - CVAL(outbuf,smb_com) = SMBffirst; - else -#endif - CVAL(outbuf,smb_com) = SMBsearch; - - SSVAL(outbuf,smb_tid,cnum); - setup_pkt(outbuf); - - SSVAL(outbuf,smb_vwv0,num_asked); - SSVAL(outbuf,smb_vwv1,attribute); - - p = smb_buf(outbuf); - *p++ = 4; - - if (first) - strcpy(p,mask); - else - strcpy(p,""); - p += strlen(p) + 1; - - *p++ = 5; - if (first) - SSVAL(p,0,0); - else - { - SSVAL(p,0,21); - p += 2; - memcpy(p,status,21); - } - - send_smb(Client,outbuf); - receive_smb(Client,inbuf,CLIENT_TIMEOUT); - - received = SVAL(inbuf,smb_vwv0); - - DEBUG(5,("dir received %d\n",received)); - - DEBUG(6,("errstr=%s\n",smb_errstr(inbuf))); - - if (received <= 0) break; - - first = False; - - dirlist = Realloc(dirlist,(num_received + received)*DIR_STRUCT_SIZE); - - if (!dirlist) - return 0; - - p = smb_buf(inbuf) + 3; - - memcpy(dirlist+num_received*DIR_STRUCT_SIZE, - p,received*DIR_STRUCT_SIZE); - - memcpy(status,p + ((received-1)*DIR_STRUCT_SIZE),21); - - num_received += received; - - if (CVAL(inbuf,smb_rcls) != 0) break; - } - -#if FFIRST - if (!first && Protocol >= PROTOCOL_LANMAN1) - { - bzero(outbuf,smb_size); - CVAL(outbuf,smb_com) = SMBfclose; - - SSVAL(outbuf,smb_tid,cnum); - setup_pkt(outbuf); - - p = smb_buf(outbuf); - *p++ = 4; - - strcpy(p,""); - p += strlen(p) + 1; - - *p++ = 5; - SSVAL(p,0,21); - p += 2; - memcpy(p,status,21); - - send_smb(Client,outbuf); - receive_smb(Client,inbuf,CLIENT_TIMEOUT,False); - - if (CVAL(inbuf,smb_rcls) != 0) - DEBUG(0,("Error closing search: %s\n",smb_errstr(inbuf))); - } -#endif - - if (!fn) - for (p=dirlist,i=0;i<num_received;i++) - { - p += interpret_short_filename(p,&finfo); - display_finfo(&finfo); - } - - for (p=dirlist,i=0;i<num_received;i++) - { - p += interpret_short_filename(p,&finfo); - dir_action(inbuf,outbuf,attribute,&finfo,recurse_dir,fn,False); - } - - if (dirlist) free(dirlist); - return(num_received); -} - -/**************************************************************************** receive a SMB trans or trans2 response allocating the necessary memory ****************************************************************************/ static BOOL receive_trans_response(char *inbuf,int trans, int *data_len,int *param_len, - char **data,char **param) + char **data,char **param) { int total_data=0; int total_param=0; @@ -894,178 +1069,6 @@ static BOOL receive_trans_response(char *inbuf,int trans, return(True); } -/**************************************************************************** - do a directory listing, calling fn on each file found. Use the TRANSACT2 - call for long filenames - ****************************************************************************/ -static int do_long_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir) -{ - int max_matches = 512; - int info_level = Protocol<PROTOCOL_NT1?1:260; /* NT uses 260, OS/2 uses 2. Both accept 1. */ - char *p; - pstring mask; - file_info finfo; - int i; - char *dirlist = NULL; - int dirlist_len = 0; - int total_received = 0; - BOOL First = True; - char *resp_data=NULL; - char *resp_param=NULL; - int resp_data_len = 0; - int resp_param_len=0; - - int ff_resume_key = 0; - int ff_searchcount=0; - int ff_eos=0; - int ff_lastname=0; - int ff_dir_handle=0; - int loop_count = 0; - - uint16 setup; - pstring param; - - strcpy(mask,Mask); - - while (ff_eos == 0) - { - loop_count++; - if (loop_count > 200) - { - DEBUG(0,("ERROR: Looping in FIND_NEXT??\n")); - break; - } - - if (First) - { - setup = TRANSACT2_FINDFIRST; - SSVAL(param,0,attribute); /* attribute */ - SSVAL(param,2,max_matches); /* max count */ - SSVAL(param,4,8+4+2); /* resume required + close on end + continue */ - SSVAL(param,6,info_level); - SIVAL(param,8,0); - strcpy(param+12,mask); - } - else - { - setup = TRANSACT2_FINDNEXT; - SSVAL(param,0,ff_dir_handle); - SSVAL(param,2,max_matches); /* max count */ - SSVAL(param,4,info_level); - SIVAL(param,6,ff_resume_key); /* ff_resume_key */ - SSVAL(param,10,8+4+2); /* resume required + close on end + continue */ - strcpy(param+12,mask); - - DEBUG(5,("hand=0x%X resume=%d ff_lastname=%d mask=%s\n", - ff_dir_handle,ff_resume_key,ff_lastname,mask)); - } - /* ??? original code added 1 pad byte after param */ - - send_trans_request(outbuf,SMBtrans2,NULL,FID_UNUSED,0, - NULL,param,&setup, - 0,12+strlen(mask)+1,1, - BUFFER_SIZE,10,0); - - if (!receive_trans_response(inbuf,SMBtrans2, - &resp_data_len,&resp_param_len, - &resp_data,&resp_param)) - { - DEBUG(3,("FIND%s gave %s\n",First?"FIRST":"NEXT",smb_errstr(inbuf))); - break; - } - - /* parse out some important return info */ - p = resp_param; - if (First) - { - ff_dir_handle = SVAL(p,0); - ff_searchcount = SVAL(p,2); - ff_eos = SVAL(p,4); - ff_lastname = SVAL(p,8); - } - else - { - ff_searchcount = SVAL(p,0); - ff_eos = SVAL(p,2); - ff_lastname = SVAL(p,6); - } - - if (ff_searchcount == 0) - break; - - /* point to the data bytes */ - p = resp_data; - - /* we might need the lastname for continuations */ - if (ff_lastname > 0) - { - switch(info_level) - { - case 260: - ff_resume_key =0; - StrnCpy(mask,p+ff_lastname,resp_data_len-ff_lastname); - /* strcpy(mask,p+ff_lastname+94); */ - break; - case 1: - strcpy(mask,p + ff_lastname + 1); - ff_resume_key = 0; - break; - } - } - else - strcpy(mask,""); - - /* and add them to the dirlist pool */ - dirlist = Realloc(dirlist,dirlist_len + resp_data_len); - - if (!dirlist) - { - DEBUG(0,("Failed to expand dirlist\n")); - break; - } - - /* put in a length for the last entry, to ensure we can chain entries - into the next packet */ - { - char *p2; - for (p2=p,i=0;i<(ff_searchcount-1);i++) - p2 += interpret_long_filename(info_level,p2,NULL); - SSVAL(p2,0,resp_data_len - PTR_DIFF(p2,p)); - } - - /* grab the data for later use */ - memcpy(dirlist+dirlist_len,p,resp_data_len); - dirlist_len += resp_data_len; - - total_received += ff_searchcount; - - if (resp_data) free(resp_data); resp_data = NULL; - if (resp_param) free(resp_param); resp_param = NULL; - - DEBUG(3,("received %d entries (eos=%d resume=%d)\n", - ff_searchcount,ff_eos,ff_resume_key)); - - First = False; - } - - if (!fn) - for (p=dirlist,i=0;i<total_received;i++) - { - p += interpret_long_filename(info_level,p,&finfo); - display_finfo(&finfo); - } - - for (p=dirlist,i=0;i<total_received;i++) - { - p += interpret_long_filename(info_level,p,&finfo); - dir_action(inbuf,outbuf,attribute,&finfo,recurse_dir,fn,True); - } - - /* free up the dirlist buffer */ - if (dirlist) free(dirlist); - return(total_received); -} - /**************************************************************************** get a directory listing @@ -3999,7 +4002,7 @@ BOOL reopen_connection(char *inbuf,char *outbuf) /**************************************************************************** process commands from the client ****************************************************************************/ -BOOL process(char *base_directory) +static BOOL process(char *base_directory) { extern FILE *dbf; pstring line; @@ -4115,7 +4118,7 @@ BOOL process(char *base_directory) /**************************************************************************** usage on the program ****************************************************************************/ -void usage(char *pname) +static void usage(char *pname) { DEBUG(0,("Usage: %s service <password> [-p port] [-d debuglevel] [-l log] ", pname)); @@ -4152,11 +4155,11 @@ void usage(char *pname) /**************************************************************************** main program ****************************************************************************/ -int main(int argc,char *argv[]) + int main(int argc,char *argv[]) { fstring base_directory; char *pname = argv[0]; - int port = 139; + int port = SMB_PORT; int opt; extern FILE *dbf; extern char *optarg; @@ -4175,6 +4178,8 @@ int main(int argc,char *argv[]) TimeInit(); charset_initialise(); + ipzero = *interpret_addr2("0.0.0.0"); + pid = getpid(); uid = getuid(); gid = getgid(); diff --git a/source/client/clientutil.c b/source/client/clientutil.c new file mode 100644 index 00000000000..e2427a40995 --- /dev/null +++ b/source/client/clientutil.c @@ -0,0 +1,1029 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + SMB client + Copyright (C) Andrew Tridgell 1994-1995 + + 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. +*/ + +#ifdef SYSLOG +#undef SYSLOG +#endif + +#include "includes.h" + +#ifndef REGISTER +#define REGISTER 0 +#endif + +pstring service=""; +pstring desthost=""; +pstring myname = ""; +pstring password = ""; +pstring username=""; +pstring workgroup=WORKGROUP; +BOOL got_pass = False; +BOOL connect_as_printer = False; +BOOL connect_as_ipc = False; + +char cryptkey[8]; +BOOL doencrypt=False; + +extern pstring user_socket_options; + +/* 30 second timeout on most commands */ +#define CLIENT_TIMEOUT (30*1000) +#define SHORT_TIMEOUT (5*1000) + +int name_type = 0x20; + +int max_protocol = PROTOCOL_NT1; + +BOOL readbraw_supported = False; +BOOL writebraw_supported = False; + +extern int DEBUGLEVEL; + +int cnum = 0; +int pid = 0; +int gid = 0; +int uid = 0; +int mid = 0; + +int max_xmit = BUFFER_SIZE; + +BOOL have_ip = False; + +struct in_addr dest_ip; + +extern int Protocol; + +extern int Client; + + +/**************************************************************************** +setup basics in a outgoing packet +****************************************************************************/ +void cli_setup_pkt(char *outbuf) +{ + SSVAL(outbuf,smb_pid,pid); + SSVAL(outbuf,smb_uid,uid); + SSVAL(outbuf,smb_mid,mid); + if (Protocol > PROTOCOL_CORE) + { + SCVAL(outbuf,smb_flg,0x8); + SSVAL(outbuf,smb_flg2,0x1); + } +} + +/**************************************************************************** + receive a SMB trans or trans2 response allocating the necessary memory + ****************************************************************************/ +BOOL cli_receive_trans_response(char *inbuf,int trans,int *data_len, + int *param_len, char **data,char **param) +{ + int total_data=0; + int total_param=0; + int this_data,this_param; + + *data_len = *param_len = 0; + + receive_smb(Client,inbuf,CLIENT_TIMEOUT); + show_msg(inbuf); + + /* sanity check */ + if (CVAL(inbuf,smb_com) != trans) + { + DEBUG(0,("Expected %s response, got command 0x%02x\n", + trans==SMBtrans?"SMBtrans":"SMBtrans2", CVAL(inbuf,smb_com))); + return(False); + } + if (CVAL(inbuf,smb_rcls) != 0) + return(False); + + /* parse out the lengths */ + total_data = SVAL(inbuf,smb_tdrcnt); + total_param = SVAL(inbuf,smb_tprcnt); + + /* allocate it */ + *data = Realloc(*data,total_data); + *param = Realloc(*param,total_param); + + while (1) + { + this_data = SVAL(inbuf,smb_drcnt); + this_param = SVAL(inbuf,smb_prcnt); + if (this_data) + memcpy(*data + SVAL(inbuf,smb_drdisp), + smb_base(inbuf) + SVAL(inbuf,smb_droff), + this_data); + if (this_param) + memcpy(*param + SVAL(inbuf,smb_prdisp), + smb_base(inbuf) + SVAL(inbuf,smb_proff), + this_param); + *data_len += this_data; + *param_len += this_param; + + /* parse out the total lengths again - they can shrink! */ + total_data = SVAL(inbuf,smb_tdrcnt); + total_param = SVAL(inbuf,smb_tprcnt); + + if (total_data <= *data_len && total_param <= *param_len) + break; + + receive_smb(Client,inbuf,CLIENT_TIMEOUT); + show_msg(inbuf); + + /* sanity check */ + if (CVAL(inbuf,smb_com) != trans) + { + DEBUG(0,("Expected %s response, got command 0x%02x\n", + trans==SMBtrans?"SMBtrans":"SMBtrans2", CVAL(inbuf,smb_com))); + return(False); + } + if (CVAL(inbuf,smb_rcls) != 0) + return(False); + } + + return(True); +} + +/**************************************************************************** +send a session request +****************************************************************************/ +BOOL cli_send_session_request(char *inbuf, char *outbuf) +{ + fstring dest; + char *p; + int len = 4; + /* send a session request (RFC 8002) */ + + strcpy(dest,desthost); + p = strchr(dest,'.'); + if (p) *p = 0; + + /* put in the destination name */ + p = outbuf+len; + name_mangle(dest,p,name_type); + len += name_len(p); + + /* and my name */ + p = outbuf+len; + name_mangle(myname,p,0); + len += name_len(p); + + /* setup the packet length */ + _smb_setlen(outbuf,len); + CVAL(outbuf,0) = 0x81; + + send_smb(Client,outbuf); + DEBUG(5,("Sent session request\n")); + + receive_smb(Client,inbuf,CLIENT_TIMEOUT); + + if (CVAL(inbuf,0) == 0x84) /* C. Hoch 9/14/95 Start */ + { + /* For information, here is the response structure. + * We do the byte-twiddling to for portability. + struct RetargetResponse{ + unsigned char type; + unsigned char flags; + int16 length; + int32 ip_addr; + int16 port; + }; + */ + extern int Client; + int port = (CVAL(inbuf,8)<<8)+CVAL(inbuf,9); + /* SESSION RETARGET */ + putip((char *)&dest_ip,inbuf+4); + + close_sockets(); + Client = open_socket_out(SOCK_STREAM, &dest_ip, port); + if (Client == -1) + return False; + + DEBUG(3,("Retargeted\n")); + + set_socket_options(Client,user_socket_options); + + /* Try again */ + return cli_send_session_request(inbuf,outbuf); + } /* C. Hoch 9/14/95 End */ + + + if (CVAL(inbuf,0) != 0x82) + { + int ecode = CVAL(inbuf,4); + DEBUG(0,("Session request failed (%d,%d) with myname=%s destname=%s\n", + CVAL(inbuf,0),ecode,myname,desthost)); + switch (ecode) + { + case 0x80: + DEBUG(0,("Not listening on called name\n")); + DEBUG(0,("Try to connect to another name (instead of %s)\n",desthost)); + DEBUG(0,("You may find the -I option useful for this\n")); + break; + case 0x81: + DEBUG(0,("Not listening for calling name\n")); + DEBUG(0,("Try to connect as another name (instead of %s)\n",myname)); + DEBUG(0,("You may find the -n option useful for this\n")); + break; + case 0x82: + DEBUG(0,("Called name not present\n")); + DEBUG(0,("Try to connect to another name (instead of %s)\n",desthost)); + DEBUG(0,("You may find the -I option useful for this\n")); + break; + case 0x83: + DEBUG(0,("Called name present, but insufficient resources\n")); + DEBUG(0,("Perhaps you should try again later?\n")); + break; + default: + DEBUG(0,("Unspecified error 0x%X\n",ecode)); + DEBUG(0,("Your server software is being unfriendly\n")); + break; + } + return(False); + } + return(True); +} + + +static struct { + int prot; + char *name; + } +prots[] = + { + {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"}, + {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"}, + {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"}, + {PROTOCOL_LANMAN1,"LANMAN1.0"}, + {PROTOCOL_LANMAN2,"LM1.2X002"}, + {PROTOCOL_LANMAN2,"Samba"}, + {PROTOCOL_NT1,"NT LM 0.12"}, + {PROTOCOL_NT1,"NT LANMAN 1.0"}, + {-1,NULL} + }; + +/**************************************************************************** +send a login command +****************************************************************************/ +BOOL cli_send_login(char *inbuf, char *outbuf, BOOL start_session, BOOL use_setup) +{ + BOOL was_null = (!inbuf && !outbuf); + int sesskey=0; + time_t servertime = 0; + extern int serverzone; + int sec_mode=0; + int crypt_len; + int max_vcs=0; + char *pass = NULL; + pstring dev; + char *p; + int numprots; + + if (was_null) + { + inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); + outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); + } + + strcpy(dev,"A:"); + if (connect_as_printer) + strcpy(dev,"LPT1:"); + if (connect_as_ipc) + strcpy(dev,"IPC"); + + + if (start_session && !cli_send_session_request(inbuf,outbuf)) + { + if (was_null) + { + free(inbuf); + free(outbuf); + } + return(False); + } + + bzero(outbuf,smb_size); + + /* setup the protocol strings */ + { + int plength; + + for (plength=0,numprots=0; + prots[numprots].name && prots[numprots].prot<=max_protocol; + numprots++) + plength += strlen(prots[numprots].name)+2; + + set_message(outbuf,0,plength,True); + + p = smb_buf(outbuf); + for (numprots=0; + prots[numprots].name && prots[numprots].prot<=max_protocol; + numprots++) + { + *p++ = 2; + strcpy(p,prots[numprots].name); + p += strlen(p) + 1; + } + } + + CVAL(outbuf,smb_com) = SMBnegprot; + cli_setup_pkt(outbuf); + + CVAL(smb_buf(outbuf),0) = 2; + + send_smb(Client,outbuf); + receive_smb(Client,inbuf,CLIENT_TIMEOUT); + + show_msg(inbuf); + + if (CVAL(inbuf,smb_rcls) != 0 || ((int)SVAL(inbuf,smb_vwv0) >= numprots)) + { + DEBUG(0,("SMBnegprot failed. myname=%s destname=%s - %s \n", + myname,desthost,smb_errstr(inbuf))); + if (was_null) + { + free(inbuf); + free(outbuf); + } + return(False); + } + + Protocol = prots[SVAL(inbuf,smb_vwv0)].prot; + + + if (Protocol < PROTOCOL_NT1) { + sec_mode = SVAL(inbuf,smb_vwv1); + max_xmit = SVAL(inbuf,smb_vwv2); + sesskey = IVAL(inbuf,smb_vwv6); + serverzone = SVALS(inbuf,smb_vwv10)*60; + /* this time is converted to GMT by make_unix_date */ + servertime = make_unix_date(inbuf+smb_vwv8); + if (Protocol >= PROTOCOL_COREPLUS) { + readbraw_supported = ((SVAL(inbuf,smb_vwv5) & 0x1) != 0); + writebraw_supported = ((SVAL(inbuf,smb_vwv5) & 0x2) != 0); + } + crypt_len = smb_buflen(inbuf); + memcpy(cryptkey,smb_buf(inbuf),8); + DEBUG(3,("max mux %d\n",SVAL(inbuf,smb_vwv3))); + max_vcs = SVAL(inbuf,smb_vwv4); + DEBUG(3,("max vcs %d\n",max_vcs)); + DEBUG(3,("max blk %d\n",SVAL(inbuf,smb_vwv5))); + } else { + /* NT protocol */ + sec_mode = CVAL(inbuf,smb_vwv1); + max_xmit = IVAL(inbuf,smb_vwv3+1); + sesskey = IVAL(inbuf,smb_vwv7+1); + serverzone = SVALS(inbuf,smb_vwv15+1)*60; + /* this time arrives in real GMT */ + servertime = interpret_long_date(inbuf+smb_vwv11+1); + crypt_len = CVAL(inbuf,smb_vwv16+1); + memcpy(cryptkey,smb_buf(inbuf),8); + if (IVAL(inbuf,smb_vwv9+1) & 1) + readbraw_supported = writebraw_supported = True; + DEBUG(3,("max mux %d\n",SVAL(inbuf,smb_vwv1+1))); + max_vcs = SVAL(inbuf,smb_vwv2+1); + DEBUG(3,("max vcs %d\n",max_vcs)); + DEBUG(3,("max raw %d\n",IVAL(inbuf,smb_vwv5+1))); + DEBUG(3,("capabilities 0x%x\n",IVAL(inbuf,smb_vwv9+1))); + } + + DEBUG(3,("Sec mode %d\n",SVAL(inbuf,smb_vwv1))); + DEBUG(3,("max xmt %d\n",max_xmit)); + DEBUG(3,("Got %d byte crypt key\n",crypt_len)); + DEBUG(3,("Chose protocol [%s]\n",prots[SVAL(inbuf,smb_vwv0)].name)); + + doencrypt = ((sec_mode & 2) != 0); + + if (servertime) { + static BOOL done_time = False; + if (!done_time) { + DEBUG(1,("Server time is %sTimezone is UTC%+02.1f\n", + asctime(LocalTime(&servertime)), + -(double)(serverzone/3600.0))); + done_time = True; + } + } + + get_pass: + + if (got_pass) + pass = password; + else + pass = (char *)getpass("Password: "); + + if (Protocol >= PROTOCOL_LANMAN1 && use_setup) + { + fstring pword; + int passlen = strlen(pass)+1; + strcpy(pword,pass); + +#ifdef SMB_PASSWD + if (doencrypt && *pass) { + DEBUG(3,("Using encrypted passwords\n")); + passlen = 24; + SMBencrypt(pass,cryptkey,pword); + } +#else + doencrypt = False; +#endif + + /* if in share level security then don't send a password now */ + if (!(sec_mode & 1)) {strcpy(pword, "");passlen=1;} + + /* send a session setup command */ + bzero(outbuf,smb_size); + + if (Protocol < PROTOCOL_NT1) { + set_message(outbuf,10,1 + strlen(username) + passlen,True); + CVAL(outbuf,smb_com) = SMBsesssetupX; + cli_setup_pkt(outbuf); + + CVAL(outbuf,smb_vwv0) = 0xFF; + SSVAL(outbuf,smb_vwv2,max_xmit); + SSVAL(outbuf,smb_vwv3,2); + SSVAL(outbuf,smb_vwv4,max_vcs-1); + SIVAL(outbuf,smb_vwv5,sesskey); + SSVAL(outbuf,smb_vwv7,passlen); + p = smb_buf(outbuf); + memcpy(p,pword,passlen); + p += passlen; + strcpy(p,username); + } else { + if (!doencrypt) passlen--; + /* for Win95 */ + set_message(outbuf,13,0,True); + CVAL(outbuf,smb_com) = SMBsesssetupX; + cli_setup_pkt(outbuf); + + CVAL(outbuf,smb_vwv0) = 0xFF; + SSVAL(outbuf,smb_vwv2,BUFFER_SIZE); + SSVAL(outbuf,smb_vwv3,2); + SSVAL(outbuf,smb_vwv4,getpid()); + SIVAL(outbuf,smb_vwv5,sesskey); + SSVAL(outbuf,smb_vwv7,passlen); + SSVAL(outbuf,smb_vwv8,0); + p = smb_buf(outbuf); + memcpy(p,pword,passlen); p += SVAL(outbuf,smb_vwv7); + strcpy(p,username);p = skip_string(p,1); + strcpy(p,workgroup);p = skip_string(p,1); + strcpy(p,"Unix");p = skip_string(p,1); + strcpy(p,"Samba");p = skip_string(p,1); + set_message(outbuf,13,PTR_DIFF(p,smb_buf(outbuf)),False); + } + + send_smb(Client,outbuf); + receive_smb(Client,inbuf,CLIENT_TIMEOUT); + + show_msg(inbuf); + + if (CVAL(inbuf,smb_rcls) != 0) + { + if (! *pass && + ((CVAL(inbuf,smb_rcls) == ERRDOS && + SVAL(inbuf,smb_err) == ERRnoaccess) || + (CVAL(inbuf,smb_rcls) == ERRSRV && + SVAL(inbuf,smb_err) == ERRbadpw))) + { + got_pass = False; + DEBUG(3,("resending login\n")); + goto get_pass; + } + + DEBUG(0,("Session setup failed for username=%s myname=%s destname=%s %s\n", + username,myname,desthost,smb_errstr(inbuf))); + DEBUG(0,("You might find the -U or -n options useful\n")); + DEBUG(0,("Sometimes you have to use `-n USERNAME' (particularly with OS/2)\n")); + DEBUG(0,("Some servers also insist on uppercase-only passwords\n")); + if (was_null) + { + free(inbuf); + free(outbuf); + } + return(False); + } + + if (Protocol >= PROTOCOL_NT1) { + char *domain,*os,*lanman; + p = smb_buf(inbuf); + os = p; + lanman = skip_string(os,1); + domain = skip_string(lanman,1); + if (*domain || *os || *lanman) + DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",domain,os,lanman)); + } + + /* use the returned uid from now on */ + if (SVAL(inbuf,smb_uid) != uid) + DEBUG(3,("Server gave us a UID of %d. We gave %d\n", + SVAL(inbuf,smb_uid),uid)); + uid = SVAL(inbuf,smb_uid); + } + + /* now we've got a connection - send a tcon message */ + bzero(outbuf,smb_size); + + if (strncmp(service,"\\\\",2) != 0) + { + DEBUG(0,("\nWarning: Your service name doesn't start with \\\\. This is probably incorrect.\n")); + DEBUG(0,("Perhaps try replacing each \\ with \\\\ on the command line?\n\n")); + } + + + again2: + + { + int passlen = strlen(pass)+1; + fstring pword; + strcpy(pword,pass); + +#ifdef SMB_PASSWD + if (doencrypt && *pass) { + passlen=24; + SMBencrypt(pass,cryptkey,pword); + } +#endif + + /* if in user level security then don't send a password now */ + if ((sec_mode & 1)) { + strcpy(pword, ""); passlen=1; + } + + set_message(outbuf,4,2 + strlen(service) + passlen + strlen(dev),True); + CVAL(outbuf,smb_com) = SMBtconX; + cli_setup_pkt(outbuf); + + SSVAL(outbuf,smb_vwv0,0xFF); + SSVAL(outbuf,smb_vwv3,passlen); + + p = smb_buf(outbuf); + memcpy(p,pword,passlen); + p += passlen; + strcpy(p,service); + p = skip_string(p,1); + strcpy(p,dev); + } + + send_smb(Client,outbuf); + receive_smb(Client,inbuf,CLIENT_TIMEOUT); + + /* trying again with a blank password */ + if (CVAL(inbuf,smb_rcls) != 0 && + (int)strlen(pass) > 0 && + !doencrypt && + Protocol >= PROTOCOL_LANMAN1) + { + DEBUG(2,("first SMBtconX failed, trying again. %s\n",smb_errstr(inbuf))); + strcpy(pass,""); + goto again2; + } + + if (CVAL(inbuf,smb_rcls) != 0) + { + DEBUG(0,("SMBtconX failed. %s\n",smb_errstr(inbuf))); + DEBUG(0,("Perhaps you are using the wrong sharename, username or password?\n")); + DEBUG(0,("Some servers insist that these be in uppercase\n")); + if (was_null) + { + free(inbuf); + free(outbuf); + } + return(False); + } + + + max_xmit = MIN(max_xmit,BUFFER_SIZE-4); + if (max_xmit <= 0) + max_xmit = BUFFER_SIZE - 4; + + cnum = SVAL(inbuf,smb_tid); + + DEBUG(3,("Connected with cnum=%d max_xmit=%d\n",cnum,max_xmit)); + + if (was_null) + { + free(inbuf); + free(outbuf); + } + return True; +} + + +/**************************************************************************** +send a logout command +****************************************************************************/ +void cli_send_logout(void) +{ + pstring inbuf,outbuf; + + bzero(outbuf,smb_size); + set_message(outbuf,0,0,True); + CVAL(outbuf,smb_com) = SMBtdis; + SSVAL(outbuf,smb_tid,cnum); + cli_setup_pkt(outbuf); + + send_smb(Client,outbuf); + receive_smb(Client,inbuf,SHORT_TIMEOUT); + + if (CVAL(inbuf,smb_rcls) != 0) + { + DEBUG(0,("SMBtdis failed %s\n",smb_errstr(inbuf))); + } + + +#ifdef STATS + stats_report(); +#endif + exit(0); +} + + + +/**************************************************************************** +call a remote api +****************************************************************************/ +BOOL cli_call_api(int prcnt,int drcnt,int mprcnt,int mdrcnt,int *rprcnt, + int *rdrcnt, char *param,char *data, char **rparam,char **rdata) +{ + static char *inbuf=NULL; + static char *outbuf=NULL; + + if (!inbuf) inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); + if (!outbuf) outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); + + cli_send_trans_request(outbuf,SMBtrans,"\\PIPE\\LANMAN",0,0, + data,param,NULL, + drcnt,prcnt,0, + mdrcnt,mprcnt,0); + + return (cli_receive_trans_response(inbuf,SMBtrans, + rdrcnt,rprcnt, + rdata,rparam)); +} + +/**************************************************************************** + send a SMB trans or trans2 request + ****************************************************************************/ +BOOL cli_send_trans_request(char *outbuf, int trans, char *name, int fid, int flags, + char *data,char *param,uint16 *setup, int ldata,int lparam, + int lsetup,int mdata,int mparam,int msetup) +{ + int i; + int this_ldata,this_lparam; + int tot_data=0,tot_param=0; + char *outdata,*outparam; + pstring inbuf; + char *p; + + this_lparam = MIN(lparam,max_xmit - (500+lsetup*SIZEOFWORD)); /* hack */ + this_ldata = MIN(ldata,max_xmit - (500+lsetup*SIZEOFWORD+this_lparam)); + + bzero(outbuf,smb_size); + set_message(outbuf,14+lsetup,0,True); + CVAL(outbuf,smb_com) = trans; + SSVAL(outbuf,smb_tid,cnum); + cli_setup_pkt(outbuf); + + outparam = smb_buf(outbuf)+(trans==SMBtrans ? strlen(name)+1 : 3); + outdata = outparam+this_lparam; + + /* primary request */ + SSVAL(outbuf,smb_tpscnt,lparam); /* tpscnt */ + SSVAL(outbuf,smb_tdscnt,ldata); /* tdscnt */ + SSVAL(outbuf,smb_mprcnt,mparam); /* mprcnt */ + SSVAL(outbuf,smb_mdrcnt,mdata); /* mdrcnt */ + SCVAL(outbuf,smb_msrcnt,msetup); /* msrcnt */ + SSVAL(outbuf,smb_flags,flags); /* flags */ + SIVAL(outbuf,smb_timeout,0); /* timeout */ + SSVAL(outbuf,smb_pscnt,this_lparam); /* pscnt */ + SSVAL(outbuf,smb_psoff,smb_offset(outparam,outbuf)); /* psoff */ + SSVAL(outbuf,smb_dscnt,this_ldata); /* dscnt */ + SSVAL(outbuf,smb_dsoff,smb_offset(outdata,outbuf)); /* dsoff */ + SCVAL(outbuf,smb_suwcnt,lsetup); /* suwcnt */ + for (i=0;i<lsetup;i++) /* setup[] */ + SSVAL(outbuf,smb_setup+i*SIZEOFWORD,setup[i]); + p = smb_buf(outbuf); + if (trans==SMBtrans) + strcpy(p,name); /* name[] */ + else + { + *p++ = 0; /* put in a null smb_name */ + *p++ = 'D'; *p++ = ' '; /* this was added because OS/2 does it */ + } + if (this_lparam) /* param[] */ + memcpy(outparam,param,this_lparam); + if (this_ldata) /* data[] */ + memcpy(outdata,data,this_ldata); + set_message(outbuf,14+lsetup, /* wcnt, bcc */ + PTR_DIFF(outdata+this_ldata,smb_buf(outbuf)),False); + + show_msg(outbuf); + send_smb(Client,outbuf); + + if (this_ldata < ldata || this_lparam < lparam) + { + /* receive interim response */ + if (!receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0) + { + DEBUG(0,("%s request failed (%s)\n", + trans==SMBtrans?"SMBtrans":"SMBtrans2", smb_errstr(inbuf))); + return(False); + } + + tot_data = this_ldata; + tot_param = this_lparam; + + while (tot_data < ldata || tot_param < lparam) + { + this_lparam = MIN(lparam-tot_param,max_xmit - 500); /* hack */ + this_ldata = MIN(ldata-tot_data,max_xmit - (500+this_lparam)); + + set_message(outbuf,trans==SMBtrans?8:9,0,True); + CVAL(outbuf,smb_com) = trans==SMBtrans ? SMBtranss : SMBtranss2; + + outparam = smb_buf(outbuf); + outdata = outparam+this_lparam; + + /* secondary request */ + SSVAL(outbuf,smb_tpscnt,lparam); /* tpscnt */ + SSVAL(outbuf,smb_tdscnt,ldata); /* tdscnt */ + SSVAL(outbuf,smb_spscnt,this_lparam); /* pscnt */ + SSVAL(outbuf,smb_spsoff,smb_offset(outparam,outbuf)); /* psoff */ + SSVAL(outbuf,smb_spsdisp,tot_param); /* psdisp */ + SSVAL(outbuf,smb_sdscnt,this_ldata); /* dscnt */ + SSVAL(outbuf,smb_sdsoff,smb_offset(outdata,outbuf)); /* dsoff */ + SSVAL(outbuf,smb_sdsdisp,tot_data); /* dsdisp */ + if (trans==SMBtrans2) + SSVAL(outbuf,smb_sfid,fid); /* fid */ + if (this_lparam) /* param[] */ + memcpy(outparam,param,this_lparam); + if (this_ldata) /* data[] */ + memcpy(outdata,data,this_ldata); + set_message(outbuf,trans==SMBtrans?8:9, /* wcnt, bcc */ + PTR_DIFF(outdata+this_ldata,smb_buf(outbuf)),False); + + show_msg(outbuf); + send_smb(Client,outbuf); + + tot_data += this_ldata; + tot_param += this_lparam; + } + } + + return(True); +} + + +/**************************************************************************** +open the client sockets +****************************************************************************/ +BOOL cli_open_sockets(int port) +{ + static int last_port; + char *host; + pstring service2; + extern int Client; + + if (port == 0) port=last_port; + last_port=port; + + strupper(service); + + if (*desthost) + { + host = desthost; + } + else + { + strcpy(service2,service); + host = strtok(service2,"\\/"); + strcpy(desthost,host); + } + + DEBUG(3,("Opening sockets\n")); + + if (*myname == 0) + { + get_myname(myname,NULL); + strupper(myname); + } + + if (!have_ip) + { + struct hostent *hp; + + if ((hp = Get_Hostbyname(host)) == 0) + { + DEBUG(0,("Get_Hostbyname: Unknown host %s.\n",host)); + return False; + } + + putip((char *)&dest_ip,(char *)hp->h_addr); + } + + Client = open_socket_out(SOCK_STREAM, &dest_ip, port); + if (Client == -1) + return False; + + DEBUG(3,("Connected\n")); + + set_socket_options(Client,user_socket_options); + + return True; +} + +/**************************************************************************** +close and open the connection again +****************************************************************************/ +BOOL cli_reopen_connection(char *inbuf,char *outbuf) +{ + static int open_count=0; + + open_count++; + + if (open_count>5) return(False); + + DEBUG(1,("Trying to re-open connection\n")); + + set_message(outbuf,0,0,True); + SCVAL(outbuf,smb_com,SMBtdis); + SSVAL(outbuf,smb_tid,cnum); + cli_setup_pkt(outbuf); + + send_smb(Client,outbuf); + receive_smb(Client,inbuf,SHORT_TIMEOUT); + + close_sockets(); + if (!cli_open_sockets(0)) return(False); + + return(cli_send_login(inbuf,outbuf,True,True)); +} + +/* error code stuff - put together by Merik Karman + merik@blackadder.dsh.oz.au */ + +typedef struct +{ + char *name; + int code; + char *message; +} err_code_struct; + +/* Dos Error Messages */ +err_code_struct dos_msgs[] = { + {"ERRbadfunc",1,"Invalid function."}, + {"ERRbadfile",2,"File not found."}, + {"ERRbadpath",3,"Directory invalid."}, + {"ERRnofids",4,"No file descriptors available"}, + {"ERRnoaccess",5,"Access denied."}, + {"ERRbadfid",6,"Invalid file handle."}, + {"ERRbadmcb",7,"Memory control blocks destroyed."}, + {"ERRnomem",8,"Insufficient server memory to perform the requested function."}, + {"ERRbadmem",9,"Invalid memory block address."}, + {"ERRbadenv",10,"Invalid environment."}, + {"ERRbadformat",11,"Invalid format."}, + {"ERRbadaccess",12,"Invalid open mode."}, + {"ERRbaddata",13,"Invalid data."}, + {"ERR",14,"reserved."}, + {"ERRbaddrive",15,"Invalid drive specified."}, + {"ERRremcd",16,"A Delete Directory request attempted to remove the server's current directory."}, + {"ERRdiffdevice",17,"Not same device."}, + {"ERRnofiles",18,"A File Search command can find no more files matching the specified criteria."}, + {"ERRbadshare",32,"The sharing mode specified for an Open conflicts with existing FIDs on the file."}, + {"ERRlock",33,"A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."}, + {"ERRfilexists",80,"The file named in a Create Directory, Make New File or Link request already exists."}, + {"ERRbadpipe",230,"Pipe invalid."}, + {"ERRpipebusy",231,"All instances of the requested pipe are busy."}, + {"ERRpipeclosing",232,"Pipe close in progress."}, + {"ERRnotconnected",233,"No process on other end of pipe."}, + {"ERRmoredata",234,"There is more data to be returned."}, + {NULL,-1,NULL}}; + +/* Server Error Messages */ +err_code_struct server_msgs[] = { + {"ERRerror",1,"Non-specific error code."}, + {"ERRbadpw",2,"Bad password - name/password pair in a Tree Connect or Session Setup are invalid."}, + {"ERRbadtype",3,"reserved."}, + {"ERRaccess",4,"The requester does not have the necessary access rights within the specified context for the requested function. The context is defined by the TID or the UID."}, + {"ERRinvnid",5,"The tree ID (TID) specified in a command was invalid."}, + {"ERRinvnetname",6,"Invalid network name in tree connect."}, + {"ERRinvdevice",7,"Invalid device - printer request made to non-printer connection or non-printer request made to printer connection."}, + {"ERRqfull",49,"Print queue full (files) -- returned by open print file."}, + {"ERRqtoobig",50,"Print queue full -- no space."}, + {"ERRqeof",51,"EOF on print queue dump."}, + {"ERRinvpfid",52,"Invalid print file FID."}, + {"ERRsmbcmd",64,"The server did not recognize the command received."}, + {"ERRsrverror",65,"The server encountered an internal error, e.g., system file unavailable."}, + {"ERRfilespecs",67,"The file handle (FID) and pathname parameters contained an invalid combination of values."}, + {"ERRreserved",68,"reserved."}, + {"ERRbadpermits",69,"The access permissions specified for a file or directory are not a valid combination. The server cannot set the requested attribute."}, + {"ERRreserved",70,"reserved."}, + {"ERRsetattrmode",71,"The attribute mode in the Set File Attribute request is invalid."}, + {"ERRpaused",81,"Server is paused."}, + {"ERRmsgoff",82,"Not receiving messages."}, + {"ERRnoroom",83,"No room to buffer message."}, + {"ERRrmuns",87,"Too many remote user names."}, + {"ERRtimeout",88,"Operation timed out."}, + {"ERRnoresource",89,"No resources currently available for request."}, + {"ERRtoomanyuids",90,"Too many UIDs active on this session."}, + {"ERRbaduid",91,"The UID is not known as a valid ID on this session."}, + {"ERRusempx",250,"Temp unable to support Raw, use MPX mode."}, + {"ERRusestd",251,"Temp unable to support Raw, use standard read/write."}, + {"ERRcontmpx",252,"Continue in MPX mode."}, + {"ERRreserved",253,"reserved."}, + {"ERRreserved",254,"reserved."}, + {"ERRnosupport",0xFFFF,"Function not supported."}, + {NULL,-1,NULL}}; + +/* Hard Error Messages */ +err_code_struct hard_msgs[] = { + {"ERRnowrite",19,"Attempt to write on write-protected diskette."}, + {"ERRbadunit",20,"Unknown unit."}, + {"ERRnotready",21,"Drive not ready."}, + {"ERRbadcmd",22,"Unknown command."}, + {"ERRdata",23,"Data error (CRC)."}, + {"ERRbadreq",24,"Bad request structure length."}, + {"ERRseek",25 ,"Seek error."}, + {"ERRbadmedia",26,"Unknown media type."}, + {"ERRbadsector",27,"Sector not found."}, + {"ERRnopaper",28,"Printer out of paper."}, + {"ERRwrite",29,"Write fault."}, + {"ERRread",30,"Read fault."}, + {"ERRgeneral",31,"General failure."}, + {"ERRbadshare",32,"A open conflicts with an existing open."}, + {"ERRlock",33,"A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."}, + {"ERRwrongdisk",34,"The wrong disk was found in a drive."}, + {"ERRFCBUnavail",35,"No FCBs are available to process request."}, + {"ERRsharebufexc",36,"A sharing buffer has been exceeded."}, + {NULL,-1,NULL}}; + + +struct +{ + int code; + char *class; + err_code_struct *err_msgs; +} err_classes[] = { + {0,"SUCCESS",NULL}, + {0x01,"ERRDOS",dos_msgs}, + {0x02,"ERRSRV",server_msgs}, + {0x03,"ERRHRD",hard_msgs}, + {0x04,"ERRXOS",NULL}, + {0xE1,"ERRRMX1",NULL}, + {0xE2,"ERRRMX2",NULL}, + {0xE3,"ERRRMX3",NULL}, + {0xFF,"ERRCMD",NULL}, + {-1,NULL,NULL}}; + + +/**************************************************************************** +return a SMB error string from a SMB buffer +****************************************************************************/ +char *smb_errstr(char *inbuf) +{ + static pstring ret; + int class = CVAL(inbuf,smb_rcls); + int num = SVAL(inbuf,smb_err); + int i,j; + + for (i=0;err_classes[i].class;i++) + if (err_classes[i].code == class) + { + if (err_classes[i].err_msgs) + { + err_code_struct *err = err_classes[i].err_msgs; + for (j=0;err[j].name;j++) + if (num == err[j].code) + { + if (DEBUGLEVEL > 0) + sprintf(ret,"%s - %s (%s)",err_classes[i].class, + err[j].name,err[j].message); + else + sprintf(ret,"%s - %s",err_classes[i].class,err[j].name); + return ret; + } + } + + sprintf(ret,"%s - %d",err_classes[i].class,num); + return ret; + } + + sprintf(ret,"ERROR: Unknown error (%d,%d)",class,num); + return(ret); +} diff --git a/source/client/clitar.c b/source/client/clitar.c index 0701aac1cf4..2de09c66c11 100644 --- a/source/client/clitar.c +++ b/source/client/clitar.c @@ -23,12 +23,6 @@ #include "includes.h" #include "clitar.h" -extern void setup_pkt(char *outbuf); -extern BOOL reopen_connection(char *inbuf,char *outbuf); -extern void do_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir); - -int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind); - extern BOOL recurse; #define SEPARATORS " \t\n\r" diff --git a/source/include/includes.h b/source/include/includes.h index 8b2821948c3..ad65bcc6075 100644 --- a/source/include/includes.h +++ b/source/include/includes.h @@ -983,6 +983,8 @@ extern char *sys_errlist[]; #include "version.h" #include "smb.h" +#include "nameserv.h" +#include "proto.h" #include "byteorder.h" #ifdef SMB_PASSWD #include "smbpass.h" diff --git a/source/include/local.h b/source/include/local.h index 9572243e730..2cfacd66b39 100644 --- a/source/include/local.h +++ b/source/include/local.h @@ -130,7 +130,7 @@ #define IDLE_CLOSED_TIMEOUT (60) #define DPTR_IDLE_TIMEOUT (120) #define SMBD_SELECT_LOOP (10) -#define NMBD_SELECT_LOOP (10) +#define NMBD_SELECT_LOOP (2) #define BROWSE_INTERVAL (60) #define REGISTRATION_INTERVAL (10*60) #define NMBD_INETD_TIMEOUT (120) diff --git a/source/include/nameserv.h b/source/include/nameserv.h index 168dd4ba866..81079fabe01 100644 --- a/source/include/nameserv.h +++ b/source/include/nameserv.h @@ -20,16 +20,51 @@ */ -#define MAX_DGRAM_SIZE 576 +#define MAX_DGRAM_SIZE (80*18+64) #define MIN_DGRAM_SIZE 12 -#define NMB_PORT 137 -#define DGRAM_PORT 138 -#define SMB_PORT 139 - -enum name_source {LMHOSTS, REGISTER, SELF, DNS, DNSFAIL}; +#define NMB_QUERY 0x20 +#define NMB_STATUS 0x21 +#define NMB_REG 0x05 +#define NMB_REL 0x06 + +#define NB_GROUP 0x80 +#define NB_PERM 0x02 +#define NB_ACTIVE 0x04 +#define NB_CONFL 0x08 +#define NB_DEREG 0x10 +#define NB_BFLAG 0x00 +#define NB_PFLAG 0x20 +#define NB_MFLAG 0x40 +#define NB__FLAG 0x60 +#define NB_FLGMSK 0x60 + +#define NAME_PERMANENT(p) ((p) & NB_PERM) +#define NAME_ACTIVE(p) ((p) & NB_ACTIVE) +#define NAME_CONFLICT(p) ((p) & NB_CONFL) +#define NAME_DEREG(p) ((p) & NB_DEREG) +#define NAME_GROUP(p) ((p) & NB_GROUP) + +#define NAME_BFLAG(p) (((p) & NB_FLGMSK) == NB_BFLAG) +#define NAME_PFLAG(p) (((p) & NB_FLGMSK) == NB_PFLAG) +#define NAME_MFLAG(p) (((p) & NB_FLGMSK) == NB_MFLAG) +#define NAME__FLAG(p) (((p) & NB_FLGMSK) == NB__FLAG) + +enum name_source {STATUS_QUERY, LMHOSTS, REGISTER, SELF, DNS, DNSFAIL}; enum node_type {B_NODE=0, P_NODE=1, M_NODE=2, NBDD_NODE=3}; enum packet_type {NMB_PACKET, DGRAM_PACKET}; +enum cmd_type +{ + NAME_STATUS_MASTER_CHECK, + NAME_STATUS_CHECK, + MASTER_SERVER_CHECK, + SERVER_CHECK, + FIND_MASTER, + CHECK_MASTER, + NAME_REGISTER, + NAME_RELEASE, + NAME_CONFIRM_QUERY +}; /* a netbios name structure */ struct nmb_name { @@ -46,32 +81,73 @@ struct name_record struct nmb_name name; time_t death_time; struct in_addr ip; - BOOL unique; + int nb_flags; enum name_source source; }; -/* this is used by the list of domains */ -struct domain_record +/* browse and backup server cache for synchronising browse list */ +struct browse_cache_record { - struct domain_record *next; - struct domain_record *prev; - fstring name; - time_t lastannounce_time; - int announce_interval; - struct in_addr bcast_ip; + struct browse_cache_record *next; + struct browse_cache_record *prev; + + pstring name; + int type; + pstring group; + struct in_addr ip; + time_t sync_time; + BOOL synced; }; -/* this is used to hold the list of servers in my domain */ +/* this is used to hold the list of servers in my domain, and is */ +/* contained within lists of domains */ struct server_record { struct server_record *next; struct server_record *prev; - fstring name; - fstring comment; - uint32 servertype; + + struct server_info_struct serv; time_t death_time; }; +/* a workgroup structure. it contains a list of servers */ +struct work_record +{ + struct work_record *next; + struct work_record *prev; + + struct server_record *serverlist; + + /* work group info */ + fstring work_group; + int token; /* used when communicating with backup browsers */ + int ServerType; + + /* announce info */ + time_t lastannounce_time; + int announce_interval; + BOOL needannounce; + + /* election info */ + BOOL RunningElection; + BOOL needelection; + int ElectionCount; + uint32 ElectionCriterion; +}; + +/* a domain structure. it contains a list of workgroups */ +struct domain_record +{ + struct domain_record *next; + struct domain_record *prev; + + struct work_record *workgrouplist; + + struct in_addr bcast_ip; + struct in_addr mask_ip; + struct in_addr myip; +}; + /* a resource record */ struct res_rec { struct nmb_name rr_name; @@ -115,6 +191,25 @@ struct nmb_packet }; +/* initiated name queries recorded in this list to track any responses... */ +struct name_response_record +{ + struct name_response_record *next; + struct name_response_record *prev; + + uint16 response_id; + enum cmd_type cmd_type; + + int fd; + struct nmb_name name; + BOOL bcast; + BOOL recurse; + struct in_addr to_ip; + + time_t start_time; + int num_msgs; +}; + /* a datagram - this normally contains SMB data in the data[] array */ struct dgram_packet { struct { @@ -154,31 +249,3 @@ struct packet_struct }; -/* this defines a list of network interfaces */ -struct net_interface { - struct net_interface *next; - struct in_addr ip; - struct in_addr bcast; - struct in_addr netmask; -}; - - -/* prototypes */ -void free_nmb_packet(struct nmb_packet *nmb); -void free_packet(struct packet_struct *packet); -struct packet_struct *read_packet(int fd,enum packet_type packet_type); -BOOL send_packet(struct packet_struct *p); -struct packet_struct *receive_packet(int fd,enum packet_type type,int timeout); -void make_nmb_name(struct nmb_name *n,char *name,int type,char *this_scope); -BOOL name_query(int fd,char *name,int name_type, - BOOL bcast,BOOL recurse, - struct in_addr to_ip, struct in_addr *ip,void (*fn)()); -BOOL name_status(int fd,char *name,int name_type,BOOL recurse, - struct in_addr to_ip,char *master,char *rname, - void (*fn)()); -BOOL send_mailslot_reply(char *mailslot,int fd,char *buf,int len, - char *srcname,char *dstname, - int src_type,int dest_type, - struct in_addr dest_ip, - struct in_addr src_ip); -char *namestr(struct nmb_name *n); diff --git a/source/include/proto.h b/source/include/proto.h new file mode 100644 index 00000000000..face79d2558 --- /dev/null +++ b/source/include/proto.h @@ -0,0 +1,506 @@ +BOOL check_access(int snum); +BOOL allow_access(char *deny_list,char *allow_list,struct from_host *client); +BOOL fromhost(int sock,struct from_host *f); +char *unix2dos_format(char *str,BOOL overwrite); +char *dos2unix_format(char *str, BOOL overwrite); +int interpret_character_set(char *str, int def); +void charset_initialise(void); +void add_char_string(char *s); +BOOL chat_with_program(char *passwordprogram,char *name,char *chatsequence); +BOOL chgpasswd(char *name,char *oldpass,char *newpass); +BOOL chgpasswd(char *name,char *oldpass,char *newpass); +void setup_pkt(char *outbuf); +void do_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir); +void cmd_help(void); +BOOL reopen_connection(char *inbuf,char *outbuf); +char *smb_errstr(char *inbuf); +void cli_setup_pkt(char *outbuf); +BOOL cli_receive_trans_response(char *inbuf,int trans,int *data_len, + int *param_len, char **data,char **param); +BOOL cli_send_session_request(char *inbuf, char *outbuf); +BOOL cli_send_login(char *inbuf, char *outbuf, BOOL start_session, BOOL use_setup); +void cli_send_logout(void); +BOOL cli_call_api(int prcnt,int drcnt,int mprcnt,int mdrcnt,int *rprcnt, + int *rdrcnt, char *param,char *data, char **rparam,char **rdata); +BOOL cli_send_trans_request(char *outbuf, int trans, char *name, int fid, int flags, + char *data,char *param,uint16 *setup, int ldata,int lparam, + int lsetup,int mdata,int mparam,int msetup); +BOOL cli_open_sockets(int port); +BOOL cli_reopen_connection(char *inbuf,char *outbuf); +char *smb_errstr(char *inbuf); +int strslashcmp(const char *s1, const char *s2); +void cmd_block(void); +void cmd_tarmode(void); +void cmd_setmode(void); +void cmd_tar(char *inbuf, char *outbuf); +int process_tar(char *inbuf, char *outbuf); +int clipfind(char **aret, int ret, char *tok); +int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind); +void init_dptrs(void); +char *dptr_path(int key); +char *dptr_wcard(int key); +BOOL dptr_set_wcard(int key, char *wcard); +BOOL dptr_set_attr(int key, uint16 attr); +uint16 dptr_attr(int key); +void dptr_close(int key); +void dptr_closecnum(int cnum); +void dptr_idlecnum(int cnum); +void dptr_closepath(char *path,int pid); +int dptr_create(int cnum,char *path, BOOL expect_close,int pid); +BOOL dptr_fill(char *buf1,unsigned int key); +BOOL dptr_zero(char *buf); +void *dptr_fetch(char *buf,int *num); +void *dptr_fetch_lanman2(char *params,int dptr_num); +BOOL get_dir_entry(int cnum,char *mask,int dirtype,char *fname,int *size,int *mode,time_t *date,BOOL check_descend); +void *OpenDir(char *name); +void CloseDir(void *p); +char *ReadDirName(void *p); +BOOL SeekDir(void *p,int pos); +int TellDir(void *p); +void DirCacheAdd(char *path,char *name,char *dname,int snum); +char *DirCacheCheck(char *path,char *name,int snum); +void DirCacheFlush(int snum); +void fault_setup(void (*fn)()); +char *getsmbpass(char *prompt) ; +int reply_trans(char *inbuf,char *outbuf); +int interpret_coding_system(char *str, int def); +char *lp_string(char *s); +BOOL lp_add_home(char *pszHomename, int iDefaultService, char *pszHomedir); +int lp_add_service(char *pszService, int iDefaultService); +BOOL lp_add_printer(char *pszPrintername, int iDefaultService); +BOOL lp_file_list_changed(void); +BOOL lp_snum_ok(int iService); +BOOL lp_loaded(void); +void lp_killunused(BOOL (*snumused)(int )); +BOOL lp_load(char *pszFname,BOOL global_only); +int lp_numservices(void); +void lp_dump(void); +int lp_servicenumber(char *pszServiceName); +char *my_workgroup(void); +char *volume_label(int snum); +BOOL is_locked(int fnum,int cnum,uint32 count,uint32 offset); +BOOL do_lock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode); +BOOL do_unlock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode); +int get_share_mode_by_fnum(int cnum,int fnum,int *pid); +int get_share_mode_byname(int cnum,char *fname,int *pid); +int get_share_mode(int cnum,struct stat *sbuf,int *pid); +void del_share_mode(int fnum); +BOOL set_share_mode(int fnum,int mode); +void clean_share_files(void); +int str_checksum(char *s); +BOOL is_8_3(char *fname); +void create_mangled_stack(int size); +BOOL check_mangled_stack(char *s); +BOOL is_mangled(char *s); +void mangle_name_83(char *s); +BOOL name_map_mangle(char *OutName,BOOL need83,int snum); +int reply_sends(char *inbuf,char *outbuf); +int reply_sendstrt(char *inbuf,char *outbuf); +int reply_sendtxt(char *inbuf,char *outbuf); +int reply_sendend(char *inbuf,char *outbuf); +void announce_request(struct work_record *work, struct in_addr ip); +void do_announce_request(char *info, char *to_name, int announce_type, int from, + int to, struct in_addr dest_ip); +void announce_backup(void); +void announce_host(void); +void announce_master(void); +struct work_record *remove_workgroup(struct domain_record *d, struct work_record *work); +void expire_browse_cache(time_t t); +struct work_record *find_workgroupstruct(struct domain_record *d, fstring name, BOOL add); +struct domain_record *find_domain(struct in_addr source_ip); +struct domain_record *add_domain_entry(struct in_addr source_ip, struct in_addr source_mask, + char *name, BOOL add); +struct browse_cache_record *add_browser_entry(char *name, int type, char *wg, + time_t ttl, struct in_addr ip); +struct server_record *add_server_entry(struct domain_record *d, struct work_record *work, + char *name,int servertype, int ttl,char *comment, + BOOL replace); +void write_browse_list(void); +void expire_servers(time_t t); +void check_master_browser(void); +void browser_gone(char *work_name, struct in_addr ip); +void send_election(struct domain_record *d, char *group,uint32 criterion, + int timeup,char *name); +void become_nonmaster(struct domain_record *d, struct work_record *work); +void run_elections(void); +void process_election(struct packet_struct *p,char *buf); +BOOL check_elections(void); +BOOL name_status(int fd,char *name,int name_type,BOOL recurse, + struct in_addr to_ip,char *master,char *rname, + void (*fn)()); +BOOL name_query(int fd,char *name,int name_type, + BOOL bcast,BOOL recurse, + struct in_addr to_ip, struct in_addr *ip,void (*fn)()); +void expire_netbios_response_entries(time_t t); +void reply_netbios_packet(struct packet_struct *p1,int trn_id,int rcode,int opcode, + struct nmb_name *rr_name,int rr_type,int rr_class,int ttl, + char *data,int len); +uint16 initiate_netbios_packet(int fd,int quest_type,char *name,int name_type, + int nb_flags,BOOL bcast,BOOL recurse,struct in_addr to_ip); +void send_name_reg(void); +void queue_netbios_pkt_wins(int fd,int quest_type,enum cmd_type cmd, + char *name,int name_type,int nb_flags, + BOOL bcast,BOOL recurse,struct in_addr to_ip); +void queue_netbios_packet(int fd,int quest_type,enum cmd_type cmd,char *name, + int name_type,int nb_flags,BOOL bcast,BOOL recurse, + struct in_addr to_ip); +struct name_response_record *find_name_query(uint16 id); +void queue_packet(struct packet_struct *packet); +void run_packet_queue(); +void listen_for_packets(BOOL run_election); +BOOL interpret_node_status(char *p, struct nmb_name *name,int t, + char *serv_name, struct in_addr ip); +BOOL send_mailslot_reply(char *mailslot,int fd,char *buf,int len,char *srcname, + char *dstname,int src_type,int dest_type, + struct in_addr dest_ip,struct in_addr src_ip); +void remove_name(struct name_record *n); +void dump_names(void); +void remove_netbios_name(char *name,int type, enum name_source source, + struct in_addr ip); +struct name_record *add_netbios_entry(char *name, int type, int nb_flags, int ttl, + enum name_source source, struct in_addr ip); +void remove_name_entry(char *name,int type); +void add_name_entry(char *name,int type,int nb_flags); +void add_my_names(void); +void expire_names(time_t t); +void response_name_release(struct packet_struct *p); +void reply_name_release(struct packet_struct *p); +void response_name_reg(struct packet_struct *p); +void reply_name_reg(struct packet_struct *p); +void reply_name_status(struct packet_struct *p); +struct name_record *search_for_name(struct nmb_name *question, + struct in_addr ip, int Time, int search); +void process_nmb(struct packet_struct *p); +void reset_server(char *name, int state, struct in_addr ip); +void tell_become_backup(void); +void do_browser_lists(void); +void sync_server(enum cmd_type cmd, char *serv_name, char *work_name, int name_type, + struct in_addr ip); +void update_from_reg(char *name, int type, struct in_addr ip); +void add_my_domains(void); +BOOL same_context(struct dgram_packet *dgram); +BOOL listening_name(struct work_record *work, struct nmb_name *n); +void process_logon_packet(struct packet_struct *p,char *buf,int len); +BOOL listening_type(struct packet_struct *p, int command); +void process_browse_packet(struct packet_struct *p,char *buf,int len); +void process_dgram(struct packet_struct *p); +BOOL reload_services(BOOL test); +void debug_nmb_packet(struct packet_struct *p); +char *namestr(struct nmb_name *n); +void free_nmb_packet(struct nmb_packet *nmb); +void free_packet(struct packet_struct *packet); +struct packet_struct *read_packet(int fd,enum packet_type packet_type); +void make_nmb_name(struct nmb_name *n,char *name,int type,char *this_scope); +BOOL send_packet(struct packet_struct *p); +struct packet_struct *receive_packet(int fd,enum packet_type type,int t); +int main(int argc,char *argv[]); +char *getsmbpass(char *pass); +void sync_browse_lists(struct work_record *work, char *name, int nm_type, + struct in_addr ip); +BOOL pm_process(char *pszFileName,BOOL (*sfunc)(char *),BOOL (*pfunc)(char *,char *)); +void generate_next_challenge(char *challenge); +BOOL set_challenge(char *challenge); +BOOL last_challenge(char *challenge); +int valid_uid(int uid); +user_struct *get_valid_user_struct(int uid); +void invalidate_uid(int uid); +char *validated_username(int vuid); +void register_uid(int uid,int gid, char *name,BOOL guest); +void add_session_user(char *user); +void dfs_unlogin(void); +BOOL password_check(char *password); +BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned char *c8); +BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd, BOOL is_nt_password); +BOOL user_ok(char *user,int snum); +BOOL authorise_login(int snum,char *user,char *password, int pwlen, + BOOL *guest,BOOL *force,int vuid); +BOOL check_hosts_equiv(char *user); +BOOL server_cryptkey(char *buf); +BOOL server_validate(char *buf); +BOOL pcap_printername_ok(char *pszPrintername, char *pszPrintcapname); +void pcap_printer_fn(void (*fn)()); +void lpq_reset(int snum); +void print_file(int fnum); +int get_printqueue(int snum,int cnum,print_queue_struct **queue, + print_status_struct *status); +void del_printqueue(int cnum,int snum,int jobid); +void status_printjob(int cnum,int snum,int jobid,int status); +int reply_special(char *inbuf,char *outbuf); +int reply_tcon(char *inbuf,char *outbuf); +int reply_tcon_and_X(char *inbuf,char *outbuf,int length,int bufsize); +int reply_unknown(char *inbuf,char *outbuf); +int reply_ioctl(char *inbuf,char *outbuf); +int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize); +int reply_chkpth(char *inbuf,char *outbuf); +int reply_getatr(char *inbuf,char *outbuf); +int reply_setatr(char *inbuf,char *outbuf); +int reply_dskattr(char *inbuf,char *outbuf); +int reply_search(char *inbuf,char *outbuf); +int reply_fclose(char *inbuf,char *outbuf); +int reply_open(char *inbuf,char *outbuf); +int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize); +int reply_ulogoffX(char *inbuf,char *outbuf,int length,int bufsize); +int reply_mknew(char *inbuf,char *outbuf); +int reply_ctemp(char *inbuf,char *outbuf); +int reply_unlink(char *inbuf,char *outbuf); +int reply_readbraw(char *inbuf, char *outbuf); +int reply_lockread(char *inbuf,char *outbuf); +int reply_read(char *inbuf,char *outbuf); +int reply_read_and_X(char *inbuf,char *outbuf,int length,int bufsize); +int reply_writebraw(char *inbuf,char *outbuf); +int reply_writeunlock(char *inbuf,char *outbuf); +int reply_write(char *inbuf,char *outbuf,int dum1,int dum2); +int reply_write_and_X(char *inbuf,char *outbuf,int length,int bufsize); +int reply_lseek(char *inbuf,char *outbuf); +int reply_flush(char *inbuf,char *outbuf); +int reply_exit(char *inbuf,char *outbuf); +int reply_close(char *inbuf,char *outbuf); +int reply_writeclose(char *inbuf,char *outbuf); +int reply_lock(char *inbuf,char *outbuf); +int reply_unlock(char *inbuf,char *outbuf); +int reply_tdis(char *inbuf,char *outbuf); +int reply_echo(char *inbuf,char *outbuf); +int reply_printopen(char *inbuf,char *outbuf); +int reply_printclose(char *inbuf,char *outbuf); +int reply_printqueue(char *inbuf,char *outbuf); +int reply_printwrite(char *inbuf,char *outbuf); +int reply_mkdir(char *inbuf,char *outbuf); +int reply_rmdir(char *inbuf,char *outbuf); +int reply_mv(char *inbuf,char *outbuf); +int reply_copy(char *inbuf,char *outbuf); +int reply_setdir(char *inbuf,char *outbuf); +int reply_lockingX(char *inbuf,char *outbuf,int length,int bufsize); +int reply_readbmpx(char *inbuf,char *outbuf,int length,int bufsize); +int reply_writebmpx(char *inbuf,char *outbuf); +int reply_writebs(char *inbuf,char *outbuf); +int reply_setattrE(char *inbuf,char *outbuf); +int reply_getattrE(char *inbuf,char *outbuf); +mode_t unix_mode(int cnum,int dosmode); +int dos_mode(int cnum,char *path,struct stat *sbuf); +int dos_chmod(int cnum,char *fname,int dosmode,struct stat *st); +BOOL unix_convert(char *name,int cnum); +int disk_free(char *path,int *bsize,int *dfree,int *dsize); +int sys_disk_free(char *path,int *bsize,int *dfree,int *dsize); +BOOL check_name(char *name,int cnum); +void open_file(int fnum,int cnum,char *fname1,int flags,int mode); +void sync_file(int fnum); +void close_file(int fnum); +BOOL check_file_sharing(int cnum,char *fname); +void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun, + int mode,int *Access,int *action); +int seek_file(int fnum,int pos); +int read_file(int fnum,char *data,int pos,int mincnt,int maxcnt,int timeout,BOOL exact); +int write_file(int fnum,char *data,int n); +BOOL become_service(int cnum,BOOL do_chdir); +int find_service(char *service); +int cached_error_packet(char *inbuf,char *outbuf,int fnum,int line); +int unix_error_packet(char *inbuf,char *outbuf,int def_class,uint32 def_code,int line); +int error_packet(char *inbuf,char *outbuf,int error_class,uint32 error_code,int line); +BOOL snum_used(int snum); +BOOL reload_services(BOOL test); +int setup_groups(char *user, int uid, int gid, int *p_ngroups, + int **p_igroups, gid_t **p_groups); +int make_connection(char *service,char *user,char *password, int pwlen, char *dev,int vuid); +int find_free_file(void ); +int reply_corep(char *outbuf); +int reply_coreplus(char *outbuf); +int reply_lanman1(char *outbuf); +int reply_lanman2(char *outbuf); +int reply_nt1(char *outbuf); +void parse_connect(char *buf,char *service,char *user,char *password,int *pwlen,char *dev); +void close_cnum(int cnum, int uid); +BOOL yield_connection(int cnum,char *name,int max_connections); +BOOL claim_connection(int cnum,char *name,int max_connections,BOOL Clear); +void exit_server(char *reason); +void standard_sub(int cnum,char *s); +char *smb_fn_name(int type); +int chain_reply(int type,char *inbuf,char *inbuf2,char *outbuf,char *outbuf2,int size,int bufsize); +int construct_reply(char *inbuf,char *outbuf,int size,int bufsize); +void str_to_key(uchar *str,uchar *key); +void D1(uchar *k, uchar *d, uchar *out); +void E1(uchar *k, uchar *d, uchar *out); +void E_P16(uchar *p14,uchar *p16); +void E_P24(uchar *p21, uchar *c8, uchar *p24); +void SMBencrypt(uchar *passwd, uchar *c8, uchar *p24); +void E_md4hash(uchar *passwd, uchar *p16); +void SMBNTencrypt(uchar *passwd, uchar *c8, uchar *p24); +void Ucrit_addUsername(pstring username); +unsigned int Ucrit_checkUsername(pstring username); +void Ucrit_addPid(int pid); +unsigned int Ucrit_checkPid(int pid); +int sys_select(fd_set *fds,struct timeval *tval); +int sys_select(fd_set *fds,struct timeval *tval); +int sys_unlink(char *fname); +int sys_open(char *fname,int flags,int mode); +DIR *sys_opendir(char *dname); +int sys_stat(char *fname,struct stat *sbuf); +int sys_lstat(char *fname,struct stat *sbuf); +int sys_mkdir(char *dname,int mode); +int sys_rmdir(char *dname); +int sys_chdir(char *dname); +int sys_utime(char *fname,struct utimbuf *times); +int sys_rename(char *from, char *to); +int sys_chown(char *fname,int uid,int gid); +int sys_chroot(char *dname); +int main(int argc, char *argv[]); +void GetTimeOfDay(struct timeval *tval); +void TimeInit(void); +int TimeDiff(time_t t); +struct tm *LocalTime(time_t *t); +time_t interpret_long_date(char *p); +void put_long_date(char *p,time_t t); +void put_dos_date(char *buf,int offset,time_t unixdate); +void put_dos_date2(char *buf,int offset,time_t unixdate); +void put_dos_date3(char *buf,int offset,time_t unixdate); +time_t make_unix_date(void *date_ptr); +time_t make_unix_date2(void *date_ptr); +time_t make_unix_date3(void *date_ptr); +BOOL set_filetime(char *fname,time_t mtime); +char *timestring(void ); +int reply_findclose(char *inbuf,char *outbuf,int length,int bufsize); +int reply_findnclose(char *inbuf,char *outbuf,int length,int bufsize); +int reply_transs2(char *inbuf,char *outbuf,int length,int bufsize); +int reply_trans2(char *inbuf,char *outbuf,int length,int bufsize); +char *ufc_crypt(char *key,char *salt); +void init_uid(void); +BOOL become_guest(void); +BOOL become_user(int cnum, int uid); +BOOL unbecome_user(void ); +int smbrun(char *cmd,char *outfile); +char *get_home_dir(char *user); +void map_username(char *user); +struct passwd *Get_Pwnam(char *user,BOOL allow_change); +BOOL user_in_list(char *user,char *list); +void setup_logging(char *pname,BOOL interactive); +void reopen_logs(void); +BOOL fcntl_lock(int fd,int op,uint32 offset,uint32 count,int type); +int file_lock(char *name,int timeout); +void file_unlock(int fd); +BOOL is_a_socket(int fd); +BOOL next_token(char **ptr,char *buff,char *sep); +char **toktocliplist(int *ctok, char *sep); +void *MemMove(void *dest,void *src,int size); +void array_promote(char *array,int elsize,int element); +void set_socket_options(int fd, char *options); +void close_sockets(void ); +BOOL in_group(gid_t group, int current_gid, int ngroups, int *groups); +char *StrCpy(char *dest,char *src); +char *StrnCpy(char *dest,const char *src,int n); +void putip(void *dest,void *src); +int name_mangle(char *In,char *Out,char name_type); +BOOL file_exist(char *fname,struct stat *sbuf); +time_t file_modtime(char *fname); +BOOL directory_exist(char *dname,struct stat *st); +uint32 file_size(char *file_name); +char *attrib_string(int mode); +int StrCaseCmp(char *s, char *t); +int StrnCaseCmp(char *s, char *t, int n); +BOOL strequal(char *s1,char *s2); +BOOL strnequal(char *s1,char *s2,int n); +BOOL strcsequal(char *s1,char *s2); +void strlower(char *s); +void strupper(char *s); +void strnorm(char *s); +BOOL strisnormal(char *s); +void string_replace(char *s,char oldc,char newc); +void unix_format(char *fname); +void dos_format(char *fname); +void show_msg(char *buf); +int smb_len(char *buf); +void _smb_setlen(char *buf,int len); +void smb_setlen(char *buf,int len); +int set_message(char *buf,int num_words,int num_bytes,BOOL zero); +int smb_numwords(char *buf); +int smb_buflen(char *buf); +int smb_buf_ofs(char *buf); +char *smb_buf(char *buf); +int smb_offset(char *p,char *buf); +char *skip_string(char *buf,int n); +BOOL trim_string(char *s,char *front,char *back); +void dos_clean_name(char *s); +void unix_clean_name(char *s); +int ChDir(char *path); +char *GetWd(char *str); +BOOL reduce_name(char *s,char *dir,BOOL widelinks); +void expand_mask(char *Mask,BOOL doext); +BOOL strhasupper(char *s); +BOOL strhaslower(char *s); +int count_chars(char *s,char c); +void make_dir_struct(char *buf,char *mask,char *fname,unsigned int size,int mode,time_t date); +void close_low_fds(void); +int write_socket(int fd,char *buf,int len); +int read_udp_socket(int fd,char *buf,int len); +int set_blocking(int fd, BOOL set); +int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out,BOOL exact); +int read_max_udp(int fd,char *buffer,int bufsize,int maxtime); +int TvalDiff(struct timeval *tvalold,struct timeval *tvalnew); +BOOL send_keepalive(int client); +int read_data(int fd,char *buffer,int N); +int write_data(int fd,char *buffer,int N); +int read_predict(int fd,int offset,char *buf,char **ptr,int num); +void do_read_prediction(); +void invalidate_read_prediction(int fd); +int transfer_file(int infd,int outfd,int n,char *header,int headlen,int align); +int read_smb_length(int fd,char *inbuf,int timeout); +BOOL receive_smb(int fd,char *buffer,int timeout); +BOOL send_smb(int fd,char *buffer); +char *name_ptr(char *buf,int ofs); +int name_extract(char *buf,int ofs,char *name); +int name_len(char *s); +BOOL send_one_packet(char *buf,int len,struct in_addr ip,int port,int type); +void msleep(int t); +BOOL in_list(char *s,char *list,BOOL casesensitive); +BOOL string_init(char **dest,char *src); +void string_free(char **s); +BOOL string_set(char **dest,char *src); +BOOL string_sub(char *s,char *pattern,char *insert); +BOOL do_match(char *str, char *regexp, int case_sig); +BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2); +void become_daemon(void); +void get_broadcast(struct in_addr *if_ipaddr, + struct in_addr *if_bcast, + struct in_addr *if_nmask); +BOOL yesno(char *p); +char *fgets_slash(char *s2,int maxlen,FILE *f); +int set_filelen(int fd, long len); +int byte_checksum(char *buf,int len); +void setbuffer(FILE *f,char *buf,int bufsize); +char *dirname_dos(char *path,char *buf); +void *Realloc(void *p,int size); +void Abort(void ); +BOOL get_myname(char *myname,struct in_addr *ip); +BOOL ip_equal(struct in_addr ip1,struct in_addr ip2); +int open_socket_in(int type, int port, int dlevel); +int open_socket_out(int type, struct in_addr *addr, int port ); +int interpret_protocol(char *str,int def); +int interpret_security(char *str,int def); +unsigned long interpret_addr(char *str); +struct in_addr *interpret_addr2(char *str); +BOOL zero_ip(struct in_addr ip); +void standard_sub_basic(char *s); +BOOL same_net(struct in_addr ip1,struct in_addr ip2,struct in_addr mask); +int PutUniCode(char *dst,char *src); +struct hostent *Get_Hostbyname(char *name); +BOOL process_exists(int pid); +char *uidtoname(int uid); +char *gidtoname(int gid); +void BlockSignals(BOOL block); +void ajt_panic(void); +char *readdirname(void *p); +void *malloc_wrapped(int size,char *file,int line); +void *realloc_wrapped(void *ptr,int size,char *file,int line); +void free_wrapped(void *ptr,char *file,int line); +char *Strstr(char *s, char *p); +time_t Mktime(struct tm *t); +int InNetGr(char *group,char *host,char *user,char *dom); +void *memcpy_wrapped(void *d,void *s,int l,char *fname,int line); +int VT_Check(char *buffer); +int VT_Start_utmp(void); +int VT_Stop_utmp(void); +void VT_AtExit(void); +void VT_SigCLD(int sig); +void VT_SigEXIT(int sig); +int VT_Start(void); +int VT_Output(char *Buffer); +int VT_Input(char *Buffer,int Size); +void VT_Process(void); diff --git a/source/include/smb.h b/source/include/smb.h index 3e38f4c37e4..0be860d6a36 100644 --- a/source/include/smb.h +++ b/source/include/smb.h @@ -40,6 +40,10 @@ # define EXTERN extern #endif +#define NMB_PORT 137 +#define DGRAM_PORT 138 +#define SMB_PORT 139 + #define False (0) #define True (1) #define BOOLSTR(b) ((b) ? "Yes" : "No") @@ -72,6 +76,19 @@ typedef unsigned short uint16; typedef unsigned int uint32; #endif +#ifndef uchar +#define uchar unsigned char +#endif +#ifndef int16 +#define int16 short +#endif +#ifndef uint16 +#define uint16 unsigned short +#endif +#ifndef uint32 +#define uint32 unsigned int +#endif + #define SIZEOFWORD 2 #ifndef DEF_CREATE_MASK @@ -216,6 +233,15 @@ typedef char pstring[1024]; typedef char fstring[128]; typedef fstring string; + +struct current_user { + int cnum, id; + int uid, gid; + int ngroups; + gid_t *groups; + int *igroups; +}; + typedef struct { int size; @@ -332,6 +358,16 @@ typedef struct int status; } print_status_struct; +/* used for server information: client, nameserv and ipc */ +struct server_info_struct +{ + fstring name; + uint32 type; + fstring comment; + fstring domain; /* used ONLY in ipc.c NOT namework.c */ + BOOL server_added; /* used ONLY in ipc.c NOT namework.c */ +}; + /* this is used for smbstatus */ struct connect_record @@ -582,281 +618,29 @@ struct from_host { struct sockaddr_in *sin; /* their side of the link */ }; -/* and a few prototypes */ -BOOL become_guest(void); -void init_uid(void); -BOOL user_ok(char *user,int snum); -int sys_rename(char *from, char *to); -int sys_select(fd_set *fds,struct timeval *tval); -int sys_unlink(char *fname); -int sys_open(char *fname,int flags,int mode); -DIR *sys_opendir(char *dname); -int sys_stat(char *fname,struct stat *sbuf); -int sys_lstat(char *fname,struct stat *sbuf); -int sys_mkdir(char *dname,int mode); -int sys_rmdir(char *dname); -int sys_chdir(char *dname); -int sys_utime(char *fname,struct utimbuf *times); -int sys_disk_free(char *path,int *bsize,int *dfree,int *dsize); -void lpq_reset(int); -void status_printjob(int cnum,int snum,int jobid,int status); -void DirCacheAdd(char *path,char *name,char *dname,int snum); -char *DirCacheCheck(char *path,char *name,int snum); -void DirCacheFlush(int snum); -int interpret_character_set(char *str, int def); -char *dos2unix_format(char *, BOOL); -char *unix2dos_format(char *, BOOL); -BOOL fcntl_lock(int fd,int op,uint32 offset,uint32 count,int type); -void BlockSignals(BOOL block); -void msleep(int t); -int file_lock(char *name,int timeout); -void file_unlock(int fd); -int find_service(char *service); -int TvalDiff(struct timeval *tvalold,struct timeval *tvalnew); -int smb_offset(char *p,char *buf); -void sync_file(int fnum); -int PutUniCode(char *dst,char *src); -void map_username(char *user); -void close_low_fds(void); -void clean_share_files(void); -int write_socket(int fd,char *buf,int len); -char *readdirname(void *p); -int dos_chmod(int cnum,char *fname,int mode,struct stat *st); -int smb_numwords(char *buf); -int get_share_mode(int cnum,struct stat *sbuf,int *pid); -void del_share_mode(int fnum); -BOOL set_share_mode(int fnum,int mode); -void TimeInit(void); -void put_long_date(char *p,time_t t); -time_t interpret_long_date(char *p); -void dptr_idlecnum(int cnum); -void dptr_closecnum(int cnum); -void init_dptrs(void); -void fault_setup(); -void set_socket_options(int fd, char *options); -void putip(void *dest,void *src); -void standard_sub_basic(char *s); -void *OpenDir(char *name); -void CloseDir(void *p); -char *ReadDirName(void *p); -BOOL SeekDir(void *p,int pos); -int TellDir(void *p); -int write_data(int fd,char *buffer,int N); -BOOL server_cryptkey(char *buf); -BOOL server_validate(char *buf); -BOOL become_service(int cnum,BOOL do_chdir); -BOOL snum_used(int snum); -BOOL reload_services(BOOL test); -void reopen_logs(void); -int transfer_file(int infd,int outfd,int n,char *header,int headlen,int align); -int str_checksum(char *s); -time_t file_modtime(char *fname); -BOOL do_match(char *str, char *regexp, int case_sig); -BOOL is_a_socket(int fd); -void _smb_setlen(char *buf,int len); -void valid_initialise(void); -BOOL is_8_3(char *fname); -BOOL is_mangled(char *s); -void standard_sub(int cnum,char *s); -void del_printqueue(int cnum,int snum,int jobid); -BOOL strisnormal(char *s); -BOOL check_mangled_stack(char *s); -int sys_chown(char *fname,int uid,int gid); -int sys_chroot(char *dname); -BOOL next_token(char **ptr,char *buff,char *sep); -void invalidate_uid(int uid); -char *fgets_slash(char *s,int maxlen,FILE *f); -int read_udp_socket(int fd,char *buf,int len); -void exit_server(char *reason); -BOOL process_exists(int pid); -BOOL chgpasswd(char *name,char *oldpass,char *newpass); -void array_promote(char *array,int elsize,int element); -void string_replace(char *s,char oldc,char newc); -BOOL user_in_list(char *user,char *list); -BOOL string_sub(char *s,char *pattern,char *insert); -char *StrnCpy(char *dest,const char *src,int n); -char *validated_username(int vuid); -BOOL set_user_password(char *user,char *oldpass,char *newpass); -int smb_buf_ofs(char *buf); -char *skip_string(char *buf,int n); -BOOL is_locked(int fnum,int cnum,uint32 count,uint32 offset); -int read_file(int fnum,char *data,int pos,int mincnt,int maxcnt,int timeout,BOOL exact); -int write_file(int fnum,char *data,int n); -BOOL do_lock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode); -int seek_file(int fnum,int pos); -BOOL do_unlock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode); -int get_printqueue(int snum,int cnum,print_queue_struct **queue,print_status_struct *status); -void parse_connect(char *buf,char *service,char *user,char *password,int *pwlen,char *dev); -int setup_groups(char *user,int uid, int gid, int *p_ngroups, - int **p_igroups, gid_t **p_groups); -int make_connection(char *service,char *user,char *password, int pwlen, char *dev,int vuid); -char *dptr_path(int key); -char *dptr_wcard(int key); -BOOL dptr_set_wcard(int key, char *wcard); -BOOL dptr_set_attr(int key, uint16 attr); -uint16 dptr_attr(int key); -void dptr_close(int key); -void dptr_closepath(char *path,int pid); -int dptr_create(int cnum,char *path, BOOL expect_close,int pid); -BOOL dptr_fill(char *buf,unsigned int key); -BOOL dptr_zero(char *buf); -void *dptr_fetch(char *buf,int *num); -void *dptr_fetch_lanman2(char *params,int dptr_num); -BOOL get_dir_entry(int cnum,char *mask,int dirtype,char *fname,int *size,int *mode,time_t *date,BOOL check_descend); -void open_file(int fnum,int cnum,char *fname,int flags,int mode); -void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,int mode,int *Access,int *action); -void close_file(int fnum); -int reply_trans2(char *inbuf,char *outbuf,int length,int bufsize); -int reply_trans(char *inbuf,char *outbuf); -char *ufc_crypt(char *key,char *salt); -BOOL authorise_login(int snum,char *user,char *password, int pwlen, - BOOL *guest,BOOL *force,int vuid); -void add_session_user(char *user); -int valid_uid(int uid); -user_struct *get_valid_user_struct(int uid); -BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd, BOOL nt_password); -void register_uid(int uid,int gid,char *name,BOOL guest); -BOOL fromhost(int sock,struct from_host *f); -BOOL strhasupper(char *s); -BOOL strhaslower(char *s); -int disk_free(char *path,int *bsize,int *dfree,int *dsize); -char *uidtoname(int uid); -char *gidtoname(int gid); -int get_share_mode_byname(int cnum,char *fname,int *pid); -int get_share_mode_by_fnum(int cnum,int fnum,int *pid); -BOOL check_file_sharing(int cnum,char *fname); -char *StrCpy(char *dest,char *src); -int unix_error_packet(char *inbuf,char *outbuf,int def_class,uint32 def_code,int line); -time_t make_unix_date2(void *date_ptr); -int cached_error_packet(char *inbuf,char *outbuf,int fnum,int line); -mode_t unix_mode(int cnum,int dosmode); -BOOL check_name(char *name,int cnum); -int error_packet(char *inbuf,char *outbuf,int error_class,uint32 error_code,int line); -int find_free_file(void ); -BOOL unix_convert(char *name,int cnum); -void unix_convert_lanman2(char *s,char *home,BOOL case_is_sig); -void print_file(int fnum); -int read_smb_length(int fd,char *inbuf,int timeout); -int read_predict(int fd,int offset,char *buf,char **ptr,int num); -void invalidate_read_prediction(int fd); -void do_read_prediction(); -BOOL claim_connection(int cnum,char *name,int max_connections,BOOL Clear); -BOOL yield_connection(int cnum,char *name,int max_connections); -int count_chars(char *s,char c); -int smbrun(char *,char *); -BOOL name_map_mangle(char *OutName,BOOL need83,int snum); -struct hostent *Get_Hostbyname(char *name); -struct passwd *Get_Pwnam(char *user,BOOL allow_change); -void Abort(void); -void *Realloc(void *p,int size); -void smb_setlen(char *buf,int len); -int set_message(char *buf,int num_words,int num_bytes,BOOL zero); -BOOL check_access(int snum); -BOOL in_group(gid_t group, int current_gid, int ngroups, int *groups); -BOOL string_set(char **dest,char *src); -BOOL string_init(char **dest,char *src); -void string_free(char **s); -char *attrib_string(int mode); -void unix_format(char *fname); -BOOL directory_exist(char *dname,struct stat *st); -time_t make_unix_date3(void *date_ptr); -void put_dos_date3(char *buf,int offset,time_t unixdate); -void make_dir_struct(char *buf,char *mask,char *fname,unsigned int size,int mode,time_t date); -BOOL in_list(char *s,char *list,BOOL case_sensitive); -void strupper(char *s); -BOOL file_exist(char *fname,struct stat *sbuf); -int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt, long time_out, BOOL exact); -void close_sockets(void ); -BOOL send_smb(int fd,char *buffer); -BOOL send_keepalive(int client); -int read_data(int fd,char *buffer,int N); -int smb_len(char *buf); -BOOL receive_smb(int fd,char *buffer,int timeout); -void show_msg(char *buf); -BOOL big_endian(void ); -BOOL become_user(int cnum, int uid); -BOOL unbecome_user(void); -void become_daemon(void); -BOOL reduce_name(char *s,char *dir,BOOL widelinks); -void strlower(char *s); -void strnorm(char *s); -char *smb_buf(char *buf); -char *smb_trans2_param(char *buf); -char *smb_trans2_data(char *buf); -BOOL strequal(char *,char *); -BOOL strnequal(char *,char *,int n); -BOOL strcsequal(char *,char *); -BOOL mask_match( char *str, char *regexp, int case_sig, BOOL trans2); -int dos_mode(int ,char *,struct stat *); -char *timestring(); -BOOL ip_equal(struct in_addr ip1,struct in_addr ip2); -BOOL send_one_packet(char *buf,int len,struct in_addr ip,int port,int type); -char *get_home_dir(char *); -int set_filelen(int fd, long len); -void put_dos_date(char *buf,int offset,time_t unixdate); -void put_dos_date2(char *buf,int offset,time_t unixdate); -int lp_keepalive(void); -int name_len(char *s); -void dos_clean_name(char *s); -void unix_clean_name(char *s); -time_t make_unix_date(void *date_ptr); -BOOL lanman2_match( char *str, char *regexp, int case_sig, BOOL autoext); -BOOL trim_string(char *s,char *front,char *back); -int byte_checksum(char *buf,int len); -BOOL yesno(char *p); -uint32 file_size(char *file_name); -void dos_format(char *fname); -char *GetWd(char *s); -int name_mangle(char *in,char *out,char name_type); -int name_len(char *s); -void create_mangled_stack(int size); -int name_extract(char *buf,int ofs,char *name); -void get_broadcast(struct in_addr *if_ipaddr, struct in_addr *if_bcast, struct in_addr *if_nmask); -BOOL allow_access(char *deny_list,char *allow_list,struct from_host *client); #ifdef __STDC__ int Debug1(char *, ...); #else int Debug1(); #endif -BOOL check_hosts_equiv(char *user); -int chain_reply(int type,char *inbuf,char *inbuf2,char *outbuf,char *outbuf2,int size,int bufsize); -void close_cnum(int cnum,int uid); -char *smb_errstr(char *inbuf); -void GetTimeOfDay(struct timeval *tval); -struct tm *LocalTime(time_t *t); -int TimeDiff(time_t t); -BOOL set_filetime(char *fname,time_t mtime); -char *dirname_dos(char *path,char *buf); -BOOL get_myname(char *myname,struct in_addr *ip); -void expand_mask(char *Mask, BOOL); -char *smb_fn_name(int cnum); -void get_machine_info(void); -int open_socket_in(int type, int port, int dlevel); -int open_socket_out(int type,struct in_addr *addr, int port ); -struct in_addr *interpret_addr2(char *str); -BOOL zero_ip(struct in_addr ip); -int read_max_udp(int fd,char *buffer,int bufsize,int maxtime); -int interpret_protocol(char *str,int def); -int interpret_security(char *str,int def); -int ChDir(char *path); -int smb_buflen(char *buf); -unsigned long interpret_addr(char *str); -void mangle_name_83(char *s); -BOOL lp_casesignames(void); -void setup_logging(char *pname,BOOL interactive); + #ifdef DFS_AUTH void dfs_unlogin(void); extern int dcelogin_atmost_once; #endif + #if AJT void ajt_panic(void); #endif + #ifdef NOSTRDUP char *strdup(char *s); #endif + #ifdef REPLACE_STRLEN int Strlen(char *); #endif + #ifdef REPLACE_STRSTR char *Strstr(char *s, char *p); #endif diff --git a/source/lib/charcnv.c b/source/lib/charcnv.c index 049390f2a43..d9ee551d6a8 100644 --- a/source/lib/charcnv.c +++ b/source/lib/charcnv.c @@ -71,8 +71,7 @@ static void initiso() { /* * Convert unix to dos */ -char * -unix2dos_format(char *str,BOOL overwrite) +char *unix2dos_format(char *str,BOOL overwrite) { char *p; char *dp; @@ -91,8 +90,7 @@ unix2dos_format(char *str,BOOL overwrite) /* * Convert dos to unix */ -char * -dos2unix_format (char *str, BOOL overwrite) +char *dos2unix_format(char *str, BOOL overwrite) { char *p; char *dp; @@ -112,8 +110,7 @@ dos2unix_format (char *str, BOOL overwrite) /* * Interpret character set. */ -int -interpret_character_set (char *str, int def) +int interpret_character_set(char *str, int def) { if (strequal (str, "iso8859-1")) { diff --git a/source/lib/getsmbpass.c b/source/lib/getsmbpass.c index 07a7dbfd9b5..7ee8c187885 100644 --- a/source/lib/getsmbpass.c +++ b/source/lib/getsmbpass.c @@ -40,12 +40,12 @@ static struct termio t; #define TCSANOW 0 #endif -int tcgetattr(int fd, struct termio *t) + int tcgetattr(int fd, struct termio *t) { return ioctl(fd, TCGETA, t); } -int tcsetattr(int fd, int flags, const struct termio *t) + int tcsetattr(int fd, int flags, const struct termio *t) { if(flags & TCSAFLUSH) ioctl(fd, TCFLSH, TCIOFLUSH); @@ -71,12 +71,12 @@ static struct sgttyb t; #define TCSANOW 0 #endif -int tcgetattr(int fd, struct sgttyb *t) + int tcgetattr(int fd, struct sgttyb *t) { return ioctl(fd, TIOCGETP, (char *)t); } -int tcsetattr(int fd, int flags, const struct sgttyb *t) + int tcsetattr(int fd, int flags, const struct sgttyb *t) { return ioctl(fd, TIOCSETP, (char *)t); } @@ -92,8 +92,7 @@ static struct termios t; #endif /* BSD_TERMIO */ #endif /* SYSV_TERMIO */ -char * -getsmbpass(char *prompt) +char *getsmbpass(char *prompt) { FILE *in, *out; int echo_off; @@ -162,5 +161,5 @@ getsmbpass(char *prompt) #else -void getsmbpasswd_dummy() {;} + void getsmbpasswd_dummy() {;} #endif diff --git a/source/lib/kanji.c b/source/lib/kanji.c index 0af476eb157..a77bdea73f0 100644 --- a/source/lib/kanji.c +++ b/source/lib/kanji.c @@ -796,8 +796,7 @@ setup_string_function (int codes) /* * Interpret coding system. */ -int -interpret_coding_system (char *str, int def) +int interpret_coding_system(char *str, int def) { int codes = def; @@ -890,6 +889,6 @@ interpret_coding_system (char *str, int def) return setup_string_function (codes); } #else -int kanji_dummy_procedure(void) + int kanji_dummy_procedure(void) {return 0;} #endif /* KANJI */ diff --git a/source/lib/md4.c b/source/lib/md4.c index 485e231a784..bdff075c7e7 100644 --- a/source/lib/md4.c +++ b/source/lib/md4.c @@ -295,5 +295,5 @@ ** End of md4.c */ #else -void md4_dummy() {;} + void md4_dummy() {;} #endif diff --git a/source/lib/ufc.c b/source/lib/ufc.c index 8417285821a..ae48a8776d4 100644 --- a/source/lib/ufc.c +++ b/source/lib/ufc.c @@ -777,6 +777,6 @@ ufc_long *_ufc_doit(l1, l2, r1, r2, itr) #else -int ufc_dummy_procedure(void) + int ufc_dummy_procedure(void) {return 0;} #endif diff --git a/source/lib/util.c b/source/lib/util.c index d2f03835326..57f2e9240cf 100644 --- a/source/lib/util.c +++ b/source/lib/util.c @@ -182,10 +182,10 @@ write an debug message on the debugfile. This is called by the DEBUG macro ********************************************************************/ #ifdef __STDC__ -int Debug1(char *format_str, ...) + int Debug1(char *format_str, ...) { #else -int Debug1(va_alist) + int Debug1(va_alist) va_dcl { char *format_str; @@ -3234,7 +3234,7 @@ void *Realloc(void *p,int size) /**************************************************************************** duplicate a string ****************************************************************************/ -char *strdup(char *s) + char *strdup(char *s) { char *ret = NULL; if (!s) return(NULL); @@ -3260,7 +3260,7 @@ void Abort(void ) /**************************************************************************** a replacement strlen() that returns int for solaris ****************************************************************************/ -int Strlen(char *s) + int Strlen(char *s) { int ret=0; if (!s) return(0); @@ -3274,7 +3274,7 @@ int Strlen(char *s) /******************************************************************* ftruncate for operating systems that don't have it ********************************************************************/ -int ftruncate(int f,long l) + int ftruncate(int f,long l) { struct flock fl; @@ -3382,7 +3382,7 @@ int open_socket_in(int type, int port, int dlevel) if (bind(res, (struct sockaddr * ) &sock,sizeof(sock)) < 0) { if (port) { - if (port == 139 || port == 137) + if (port == SMB_PORT || port == NMB_PORT) DEBUG(dlevel,("bind failed on port %d (%s)\n", port,strerror(errno))); close(res); @@ -3570,6 +3570,21 @@ void standard_sub_basic(char *s) /******************************************************************* +are two IPs on the same subnet? +********************************************************************/ +BOOL same_net(struct in_addr ip1,struct in_addr ip2,struct in_addr mask) +{ + unsigned long net1,net2,nmask; + + nmask = ntohl(mask.s_addr); + net1 = ntohl(ip1.s_addr); + net2 = ntohl(ip2.s_addr); + + return((net1 & nmask) == (net2 & nmask)); +} + + +/******************************************************************* write a string in unicoode format ********************************************************************/ int PutUniCode(char *dst,char *src) @@ -3797,7 +3812,7 @@ long nap(long milliseconds) { /**************************************************************************** some systems don't have an initgroups call ****************************************************************************/ -int initgroups(char *name,gid_t id) + int initgroups(char *name,gid_t id) { #ifdef NO_SETGROUPS /* yikes! no SETGROUPS or INITGROUPS? how can this work? */ @@ -3981,8 +3996,7 @@ time_t Mktime(struct tm *t) #ifdef REPLACE_RENAME /* Rename a file. (from libiberty in GNU binutils) */ -int -rename (zfrom, zto) + int rename (zfrom, zto) const char *zfrom; const char *zto; { @@ -4003,8 +4017,7 @@ rename (zfrom, zto) /* * Search for a match in a netgroup. This replaces it on broken systems. */ -int InNetGr(group, host, user, dom) - char *group, *host, *user, *dom; +int InNetGr(char *group,char *host,char *user,char *dom) { char *hst, *usr, *dm; diff --git a/source/libsmb/namequery.c b/source/libsmb/namequery.c new file mode 100644 index 00000000000..d1b1ae7d3e5 --- /dev/null +++ b/source/libsmb/namequery.c @@ -0,0 +1,292 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + name query routines + Copyright (C) Andrew Tridgell 1994-1995 + + 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 pstring scope; +extern int DEBUGLEVEL; + + +/**************************************************************************** +interpret a node status response +****************************************************************************/ +static void _interpret_node_status(char *p, char *master,char *rname) +{ + int level = (master||rname)?4:0; + int numnames = CVAL(p,0); + DEBUG(level,("received %d names\n",numnames)); + + if (rname) *rname = 0; + if (master) *master = 0; + + p += 1; + while (numnames--) + { + char qname[17]; + int type; + fstring flags; + int i; + *flags = 0; + StrnCpy(qname,p,15); + type = CVAL(p,15); + p += 16; + + strcat(flags, (p[0] & 0x80) ? "<GROUP> " : " "); + if ((p[0] & 0x60) == 0x00) strcat(flags,"B "); + if ((p[0] & 0x60) == 0x20) strcat(flags,"P "); + if ((p[0] & 0x60) == 0x40) strcat(flags,"M "); + if ((p[0] & 0x60) == 0x60) strcat(flags,"_ "); + if (p[0] & 0x10) strcat(flags,"<DEREGISTERING> "); + if (p[0] & 0x08) strcat(flags,"<CONFLICT> "); + if (p[0] & 0x04) strcat(flags,"<ACTIVE> "); + if (p[0] & 0x02) strcat(flags,"<PERMANENT> "); + + if (master && !*master && type == 0x1d) { + StrnCpy(master,qname,15); + trim_string(master,NULL," "); + } + + if (rname && !*rname && type == 0x20 && !(p[0]&0x80)) { + StrnCpy(rname,qname,15); + trim_string(rname,NULL," "); + } + + for (i = strlen( qname) ; --i >= 0 ; ) { + if (!isprint(qname[i])) qname[i] = '.'; + } + DEBUG(level,("\t%-15s <%02x> - %s\n",qname,type,flags)); + p+=2; + } + DEBUG(level,("num_good_sends=%d num_good_receives=%d\n", + IVAL(p,20),IVAL(p,24))); +} + + +/**************************************************************************** + do a netbios name status query on a host + + the "master" parameter is a hack used for finding workgroups. + **************************************************************************/ +BOOL name_status(int fd,char *name,int name_type,BOOL recurse, + struct in_addr to_ip,char *master,char *rname, + void (*fn)()) +{ + BOOL found=False; + int retries = 2; + int retry_time = 5000; + struct timeval tval; + struct packet_struct p; + struct packet_struct *p2; + struct nmb_packet *nmb = &p.packet.nmb; + static int name_trn_id = 0; + + bzero((char *)&p,sizeof(p)); + + if (!name_trn_id) name_trn_id = (time(NULL)%(unsigned)0x7FFF) + + (getpid()%(unsigned)100); + name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF; + + nmb->header.name_trn_id = name_trn_id; + nmb->header.opcode = 0; + nmb->header.response = False; + nmb->header.nm_flags.bcast = False; + nmb->header.nm_flags.recursion_available = 0; + nmb->header.nm_flags.recursion_desired = 1; + nmb->header.nm_flags.trunc = False; + nmb->header.nm_flags.authoritative = False; + nmb->header.rcode = 0; + nmb->header.qdcount = 1; + nmb->header.ancount = 0; + nmb->header.nscount = 0; + nmb->header.arcount = 0; + + make_nmb_name(&nmb->question.question_name,name,name_type,scope); + + nmb->question.question_type = 0x21; + nmb->question.question_class = 0x1; + + p.ip = to_ip; + p.port = NMB_PORT; + p.fd = fd; + p.timestamp = time(NULL); + p.packet_type = NMB_PACKET; + + GetTimeOfDay(&tval); + + if (!send_packet(&p)) + return(False); + + retries--; + + while (1) + { + struct timeval tval2; + GetTimeOfDay(&tval2); + if (TvalDiff(&tval,&tval2) > retry_time) { + if (!retries) break; + if (!found && !send_packet(&p)) + return False; + GetTimeOfDay(&tval); + retries--; + } + + if ((p2=receive_packet(fd,NMB_PACKET,90))) + { + struct nmb_packet *nmb2 = &p2->packet.nmb; + if (nmb->header.name_trn_id != nmb2->header.name_trn_id || + !nmb2->header.response) { + /* its not for us - maybe deal with it later */ + if (fn) + fn(p2); + else + free_packet(p2); + continue; + } + + if (nmb2->header.opcode != 0 || + nmb2->header.nm_flags.bcast || + nmb2->header.rcode || + !nmb2->header.ancount || + nmb2->answers->rr_type != 0x21) { + /* XXXX what do we do with this? could be a redirect, but + we'll discard it for the moment */ + free_packet(p2); + continue; + } + + _interpret_node_status(&nmb2->answers->rdata[0], master,rname); + free_packet(p2); + return(True); + } + } + + + DEBUG(0,("No status response (this is not unusual)\n")); + + return(False); +} + + +/**************************************************************************** + do a netbios name query to find someones IP + ****************************************************************************/ +BOOL name_query(int fd,char *name,int name_type, + BOOL bcast,BOOL recurse, + struct in_addr to_ip, struct in_addr *ip,void (*fn)()) +{ + BOOL found=False; + int retries = 3; + int retry_time = bcast?250:2000; + struct timeval tval; + struct packet_struct p; + struct packet_struct *p2; + struct nmb_packet *nmb = &p.packet.nmb; + static int name_trn_id = 0; + + bzero((char *)&p,sizeof(p)); + + if (!name_trn_id) name_trn_id = (time(NULL)%(unsigned)0x7FFF) + + (getpid()%(unsigned)100); + name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF; + + nmb->header.name_trn_id = name_trn_id; + nmb->header.opcode = 0; + nmb->header.response = False; + nmb->header.nm_flags.bcast = bcast; + nmb->header.nm_flags.recursion_available = 0; + nmb->header.nm_flags.recursion_desired = 1; + nmb->header.nm_flags.trunc = False; + nmb->header.nm_flags.authoritative = False; + nmb->header.rcode = 0; + nmb->header.qdcount = 1; + nmb->header.ancount = 0; + nmb->header.nscount = 0; + nmb->header.arcount = 0; + + make_nmb_name(&nmb->question.question_name,name,name_type,scope); + + nmb->question.question_type = 0x20; + nmb->question.question_class = 0x1; + + p.ip = to_ip; + p.port = NMB_PORT; + p.fd = fd; + p.timestamp = time(NULL); + p.packet_type = NMB_PACKET; + + GetTimeOfDay(&tval); + + if (!send_packet(&p)) + return(False); + + retries--; + + while (1) + { + struct timeval tval2; + GetTimeOfDay(&tval2); + if (TvalDiff(&tval,&tval2) > retry_time) { + if (!retries) break; + if (!found && !send_packet(&p)) + return False; + GetTimeOfDay(&tval); + retries--; + } + + if ((p2=receive_packet(fd,NMB_PACKET,90))) + { + struct nmb_packet *nmb2 = &p2->packet.nmb; + if (nmb->header.name_trn_id != nmb2->header.name_trn_id || + !nmb2->header.response) { + /* its not for us - maybe deal with it later + (put it on the queue?) */ + if (fn) + fn(p2); + else + free_packet(p2); + continue; + } + + if (nmb2->header.opcode != 0 || + nmb2->header.nm_flags.bcast || + nmb2->header.rcode || + !nmb2->header.ancount) { + /* XXXX what do we do with this? could be a redirect, but + we'll discard it for the moment */ + free_packet(p2); + continue; + } + + if (ip) { + putip((char *)ip,&nmb2->answers->rdata[2]); + DEBUG(fn?3:2,("Got a positive name query response from %s", + inet_ntoa(p2->ip))); + DEBUG(fn?3:2,(" (%s)\n",inet_ntoa(*ip))); + } + found=True; retries=0; + free_packet(p2); + if (fn) break; + } + } + + return(found); +} diff --git a/source/libsmb/nmblib.c b/source/libsmb/nmblib.c index 1f789961560..d8d6eb0ee40 100644 --- a/source/libsmb/nmblib.c +++ b/source/libsmb/nmblib.c @@ -21,15 +21,104 @@ */ #include "includes.h" -#include "nameserv.h" +#include "localnet.h" +#include "loadparm.h" +extern struct in_addr myip; extern int DEBUGLEVEL; -int num_good_sends=0; -int num_good_receives=0; -static uint16 name_trn_id = 0; -BOOL CanRecurse = True; +int num_good_sends = 0; +int num_good_receives = 0; extern pstring scope; +extern pstring myname; +extern struct in_addr ipzero; + + +/**************************************************************************** + print out a res_rec structure + ****************************************************************************/ +static void debug_nmb_res_rec(struct res_rec *res, char *hdr) +{ + int i, j; + + DEBUG(4,(" %s: nmb_name=%s rr_type=%d rr_class=%d ttl=%d\n", + hdr, + namestr(&res->rr_name), + res->rr_type, + res->rr_class, + res->ttl)); + + if (res->rdlength == 0 || res->rdata == NULL) return; + + for (i = 0; i < res->rdlength; i+= 16) + { + DEBUG(4, (" %s %3x char ", hdr, i)); + + for (j = 0; j < 16; j++) + { + unsigned char x = res->rdata[i+j]; + if (x < 32 || x > 127) x = '.'; + + if (i+j >= res->rdlength) break; + DEBUG(4, ("%c", x)); + } + + DEBUG(4, (" hex ", i)); + + for (j = 0; j < 16; j++) + { + if (i+j >= res->rdlength) break; + DEBUG(4, ("%02X", (unsigned char)res->rdata[i+j])); + } + + DEBUG(4, ("\n")); + } +} + +/**************************************************************************** + process a nmb packet + ****************************************************************************/ +void debug_nmb_packet(struct packet_struct *p) +{ + struct nmb_packet *nmb = &p->packet.nmb; + + DEBUG(4,("nmb packet from %s header: id=%d opcode=%d response=%s\n", + inet_ntoa(p->ip), + nmb->header.name_trn_id,nmb->header.opcode,BOOLSTR(nmb->header.response))); + DEBUG(4,(" header: flags: bcast=%s rec_avail=%s rec_des=%s trunc=%s auth=%s\n", + BOOLSTR(nmb->header.nm_flags.bcast), + BOOLSTR(nmb->header.nm_flags.recursion_available), + BOOLSTR(nmb->header.nm_flags.recursion_desired), + BOOLSTR(nmb->header.nm_flags.trunc), + BOOLSTR(nmb->header.nm_flags.authoritative))); + DEBUG(4,(" header: rcode=%d qdcount=%d ancount=%d nscount=%d arcount=%d\n", + nmb->header.rcode, + nmb->header.qdcount, + nmb->header.ancount, + nmb->header.nscount, + nmb->header.arcount)); + + if (nmb->header.qdcount) + { + DEBUG(4,(" question: q_name=%s q_type=%d q_class=%d\n", + namestr(&nmb->question.question_name), + nmb->question.question_type, + nmb->question.question_class)); + } + + if (nmb->answers && nmb->header.ancount) + { + debug_nmb_res_rec(nmb->answers,"answers"); + } + if (nmb->nsrecs && nmb->header.nscount) + { + debug_nmb_res_rec(nmb->nsrecs,"nsrecs"); + } + if (nmb->additional && nmb->header.arcount) + { + debug_nmb_res_rec(nmb->additional,"additional"); + } +} /******************************************************************* handle "compressed" name pointers @@ -38,7 +127,7 @@ static BOOL handle_name_ptrs(unsigned char *ubuf,int *offset,int length, BOOL *got_pointer,int *ret) { int loop_count=0; - + while ((ubuf[*offset] & 0xC0) == 0xC0) { if (!*got_pointer) (*ret) += 2; (*got_pointer)=True; @@ -54,8 +143,7 @@ static BOOL handle_name_ptrs(unsigned char *ubuf,int *offset,int length, parse a nmb name from "compressed" format to something readable return the space taken by the name, or 0 if the name is invalid ******************************************************************/ -static int parse_nmb_name(char *inbuf,int offset,int length, - struct nmb_name *name) +static int parse_nmb_name(char *inbuf,int offset,int length, struct nmb_name *name) { int m,n=0; unsigned char *ubuf = (unsigned char *)inbuf; @@ -186,11 +274,10 @@ char *namestr(struct nmb_name *n) } /******************************************************************* - allocate are parse some resource records + allocate and parse some resource records ******************************************************************/ static BOOL parse_alloc_res_rec(char *inbuf,int *offset,int length, - struct res_rec **recs, - int count) + struct res_rec **recs, int count) { int i; *recs = (struct res_rec *)malloc(sizeof(**recs)*count); @@ -382,10 +469,10 @@ struct packet_struct *read_packet(int fd,enum packet_type packet_type) char buf[MAX_DGRAM_SIZE]; int length; BOOL ok=False; - + length = read_udp_socket(fd,buf,sizeof(buf)); if (length < MIN_DGRAM_SIZE) return(NULL); - + packet = (struct packet_struct *)malloc(sizeof(*packet)); if (!packet) return(NULL); @@ -528,6 +615,7 @@ static int build_nmb(char *buf,struct packet_struct *p) if (nmb->header.nm_flags.recursion_available) ubuf[offset+3] |= 0x80; if (nmb->header.nm_flags.bcast) ubuf[offset+3] |= 0x10; ubuf[offset+3] |= (nmb->header.rcode & 0xF); + RSSVAL(ubuf,offset+4,nmb->header.qdcount); RSSVAL(ubuf,offset+6,nmb->header.ancount); RSSVAL(ubuf,offset+8,nmb->header.nscount); @@ -607,334 +695,3 @@ struct packet_struct *receive_packet(int fd,enum packet_type type,int t) } -/**************************************************************************** -interpret a node status response -****************************************************************************/ -static void interpret_node_status(char *p, char *master,char *rname) -{ - int level = (master||rname)?4:0; - int numnames = CVAL(p,0); - DEBUG(level,("received %d names\n",numnames)); - - if (rname) *rname = 0; - if (master) *master = 0; - - p += 1; - while (numnames--) - { - char qname[17]; - int type; - fstring flags; - int i; - *flags = 0; - StrnCpy(qname,p,15); - type = CVAL(p,15); - p += 16; - - strcat(flags, (p[0] & 0x80) ? "<GROUP> " : " "); - if ((p[0] & 0x60) == 0x00) strcat(flags,"B "); - if ((p[0] & 0x60) == 0x20) strcat(flags,"P "); - if ((p[0] & 0x60) == 0x40) strcat(flags,"M "); - if ((p[0] & 0x60) == 0x60) strcat(flags,"_ "); - if (p[0] & 0x10) strcat(flags,"<DEREGISTERING> "); - if (p[0] & 0x08) strcat(flags,"<CONFLICT> "); - if (p[0] & 0x04) strcat(flags,"<ACTIVE> "); - if (p[0] & 0x02) strcat(flags,"<PERMANENT> "); - - if (master && !*master && type == 0x1d) { - StrnCpy(master,qname,15); - trim_string(master,NULL," "); - } - - if (rname && !*rname && type == 0x20 && !(p[0]&0x80)) { - StrnCpy(rname,qname,15); - trim_string(rname,NULL," "); - } - - for (i = strlen( qname) ; --i >= 0 ; ) { - if (!isprint(qname[i])) qname[i] = '.'; - } - DEBUG(level,("\t%-15s <%02x> - %s\n",qname,type,flags)); - p+=2; - } - DEBUG(level,("num_good_sends=%d num_good_receives=%d\n", - IVAL(p,20),IVAL(p,24))); -} - - -/**************************************************************************** - do a netbios name status query on a host - - the "master" parameter is a hack used for finding workgroups. - **************************************************************************/ -BOOL name_status(int fd,char *name,int name_type,BOOL recurse, - struct in_addr to_ip,char *master,char *rname, - void (*fn)()) -{ - BOOL found=False; - int retries = 2; - int retry_time = 5000; - struct timeval tval; - struct packet_struct p; - struct packet_struct *p2; - struct nmb_packet *nmb = &p.packet.nmb; - - bzero((char *)&p,sizeof(p)); - - if (!name_trn_id) name_trn_id = (time(NULL)%(unsigned)0x7FFF) + - (getpid()%(unsigned)100); - name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF; - - nmb->header.name_trn_id = name_trn_id; - nmb->header.opcode = 0; - nmb->header.response = False; - nmb->header.nm_flags.bcast = False; - nmb->header.nm_flags.recursion_available = CanRecurse; - nmb->header.nm_flags.recursion_desired = recurse; - nmb->header.nm_flags.trunc = False; - nmb->header.nm_flags.authoritative = False; - nmb->header.rcode = 0; - nmb->header.qdcount = 1; - nmb->header.ancount = 0; - nmb->header.nscount = 0; - nmb->header.arcount = 0; - - make_nmb_name(&nmb->question.question_name,name,name_type,scope); - - nmb->question.question_type = 0x21; - nmb->question.question_class = 0x1; - - p.ip = to_ip; - p.port = NMB_PORT; - p.fd = fd; - p.timestamp = time(NULL); - p.packet_type = NMB_PACKET; - - GetTimeOfDay(&tval); - - if (!send_packet(&p)) - return(False); - - retries--; - - while (1) - { - struct timeval tval2; - GetTimeOfDay(&tval2); - if (TvalDiff(&tval,&tval2) > retry_time) { - if (!retries) break; - if (!found && !send_packet(&p)) - return False; - GetTimeOfDay(&tval); - retries--; - } - - if ((p2=receive_packet(fd,NMB_PACKET,90))) - { - struct nmb_packet *nmb2 = &p2->packet.nmb; - if (nmb->header.name_trn_id != nmb2->header.name_trn_id || - !nmb2->header.response) { - /* its not for us - maybe deal with it later */ - if (fn) - fn(p2); - else - free_packet(p2); - continue; - } - - if (nmb2->header.opcode != 0 || - nmb2->header.nm_flags.bcast || - nmb2->header.rcode || - !nmb2->header.ancount || - nmb2->answers->rr_type != 0x21) { - /* XXXX what do we do with this? could be a redirect, but - we'll discard it for the moment */ - free_packet(p2); - continue; - } - - interpret_node_status(&nmb2->answers->rdata[0], master,rname); - free_packet(p2); - return(True); - } - } - - - DEBUG(0,("No status response (this is not unusual)\n")); - - return(False); -} - - -/**************************************************************************** - do a netbios name query to find someones IP - ****************************************************************************/ -BOOL name_query(int fd,char *name,int name_type, - BOOL bcast,BOOL recurse, - struct in_addr to_ip, struct in_addr *ip,void (*fn)()) -{ - BOOL found=False; - int retries = 3; - int retry_time = bcast?250:2000; - struct timeval tval; - struct packet_struct p; - struct packet_struct *p2; - struct nmb_packet *nmb = &p.packet.nmb; - - bzero((char *)&p,sizeof(p)); - - if (!name_trn_id) name_trn_id = (time(NULL)%(unsigned)0x7FFF) + - (getpid()%(unsigned)100); - name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF; - - nmb->header.name_trn_id = name_trn_id; - nmb->header.opcode = 0; - nmb->header.response = False; - nmb->header.nm_flags.bcast = bcast; - nmb->header.nm_flags.recursion_available = CanRecurse; - nmb->header.nm_flags.recursion_desired = recurse; - nmb->header.nm_flags.trunc = False; - nmb->header.nm_flags.authoritative = False; - nmb->header.rcode = 0; - nmb->header.qdcount = 1; - nmb->header.ancount = 0; - nmb->header.nscount = 0; - nmb->header.arcount = 0; - - make_nmb_name(&nmb->question.question_name,name,name_type,scope); - - nmb->question.question_type = 0x20; - nmb->question.question_class = 0x1; - - p.ip = to_ip; - p.port = NMB_PORT; - p.fd = fd; - p.timestamp = time(NULL); - p.packet_type = NMB_PACKET; - - GetTimeOfDay(&tval); - - if (!send_packet(&p)) - return(False); - - retries--; - - while (1) - { - struct timeval tval2; - GetTimeOfDay(&tval2); - if (TvalDiff(&tval,&tval2) > retry_time) { - if (!retries) break; - if (!found && !send_packet(&p)) - return False; - GetTimeOfDay(&tval); - retries--; - } - - if ((p2=receive_packet(fd,NMB_PACKET,90))) - { - struct nmb_packet *nmb2 = &p2->packet.nmb; - if (nmb->header.name_trn_id != nmb2->header.name_trn_id || - !nmb2->header.response) { - /* its not for us - maybe deal with it later - (put it on the queue?) */ - if (fn) - fn(p2); - else - free_packet(p2); - continue; - } - - if (nmb2->header.opcode != 0 || - nmb2->header.nm_flags.bcast || - nmb2->header.rcode || - !nmb2->header.ancount) { - /* XXXX what do we do with this? could be a redirect, but - we'll discard it for the moment */ - free_packet(p2); - continue; - } - - if (ip) { - putip((char *)ip,&nmb2->answers->rdata[2]); - DEBUG(fn?3:2,("Got a positive name query response from %s", - inet_ntoa(p2->ip))); - DEBUG(fn?3:2,(" (%s)\n",inet_ntoa(*ip))); - } - found=True; retries=0; - free_packet(p2); - if (fn) break; - } - } - - return(found); -} - - -/**************************************************************************** - construct and send a netbios DGRAM - - Note that this currently sends all answers to port 138. thats the - wrong things to do! I should send to the requestors port. XXX - **************************************************************************/ -BOOL send_mailslot_reply(char *mailslot,int fd,char *buf,int len, - char *srcname,char *dstname, - int src_type,int dest_type, - struct in_addr dest_ip, - struct in_addr src_ip) -{ - struct packet_struct p; - struct dgram_packet *dgram = &p.packet.dgram; - char *ptr,*p2; - char tmp[4]; - - bzero((char *)&p,sizeof(p)); - - dgram->header.msg_type = 0x11; /* DIRECT GROUP DATAGRAM */ - dgram->header.flags.node_type = M_NODE; - dgram->header.flags.first = True; - dgram->header.flags.more = False; - dgram->header.dgm_id = name_trn_id++; - dgram->header.source_ip = src_ip; - dgram->header.source_port = DGRAM_PORT; - dgram->header.dgm_length = 0; /* let build_dgram() handle this */ - dgram->header.packet_offset = 0; - - make_nmb_name(&dgram->source_name,srcname,src_type,scope); - make_nmb_name(&dgram->dest_name,dstname,dest_type,scope); - - ptr = &dgram->data[0]; - - /* now setup the smb part */ - ptr -= 4; /* XXX ugliness because of handling of tcp SMB length */ - memcpy(tmp,ptr,4); - set_message(ptr,17,17 + len,True); - memcpy(ptr,tmp,4); - - CVAL(ptr,smb_com) = SMBtrans; - SSVAL(ptr,smb_vwv1,len); - SSVAL(ptr,smb_vwv11,len); - SSVAL(ptr,smb_vwv12,70 + strlen(mailslot)); - SSVAL(ptr,smb_vwv13,3); - SSVAL(ptr,smb_vwv14,1); - SSVAL(ptr,smb_vwv15,1); - SSVAL(ptr,smb_vwv16,2); - p2 = smb_buf(ptr); - strcpy(p2,mailslot); - p2 = skip_string(p2,1); - - memcpy(p2,buf,len); - p2 += len; - - dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length */ - - p.ip = dest_ip; - p.port = DGRAM_PORT; - p.fd = fd; - p.timestamp = time(NULL); - p.packet_type = DGRAM_PACKET; - - return(send_packet(&p)); -} - - diff --git a/source/libsmb/smbencrypt.c b/source/libsmb/smbencrypt.c index 0221520ce65..be22fc50fc6 100644 --- a/source/libsmb/smbencrypt.c +++ b/source/libsmb/smbencrypt.c @@ -28,19 +28,6 @@ extern int DEBUGLEVEL; -#ifndef uchar -#define uchar unsigned char -#endif -#ifndef int16 -#define int16 unsigned short -#endif -#ifndef uint16 -#define uint16 unsigned short -#endif -#ifndef uint32 -#define uint32 unsigned int -#endif - #include "byteorder.h" void str_to_key(uchar *str,uchar *key) @@ -198,5 +185,5 @@ void SMBNTencrypt(uchar *passwd, uchar *c8, uchar *p24) } #else -void smbencrypt_dummy(void){} + void smbencrypt_dummy(void){} #endif diff --git a/source/loadparm.h b/source/loadparm.h index 879ff25e675..5600d66922f 100644 --- a/source/loadparm.h +++ b/source/loadparm.h @@ -67,6 +67,7 @@ extern int lp_max_log_size(void); extern int lp_maxxmit(void); extern int lp_maxmux(void); extern int lp_mangledstack(void); +extern BOOL lp_wins_support(void); extern BOOL lp_preferred_master(void); extern BOOL lp_domain_master(void); extern BOOL lp_domain_logons(void); diff --git a/source/localnet.h b/source/localnet.h new file mode 100644 index 00000000000..7f335e790e4 --- /dev/null +++ b/source/localnet.h @@ -0,0 +1,6 @@ +extern struct in_addr myip; +extern struct in_addr bcast_ip; +extern struct in_addr Netmask; + +extern int ClientNMB; +extern int ClientDGRAM; diff --git a/source/nameannounce.c b/source/nameannounce.c new file mode 100644 index 00000000000..f0de4d0a27f --- /dev/null +++ b/source/nameannounce.c @@ -0,0 +1,444 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + NBT netbios routines and daemon - version 2 + Copyright (C) Andrew Tridgell 1994-1995 + + 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. + + Revision History: + + 14 jan 96: lkcl@pires.co.uk + added multiple workgroup domain master support + +*/ + +#include "includes.h" +#include "loadparm.h" + +#define TEST_CODE + +extern int DEBUGLEVEL; +extern BOOL CanRecurse; + +extern struct in_addr myip; +extern struct in_addr bcast_ip; +extern struct in_addr Netmask; +extern struct in_addr ipzero; + +extern pstring myname; + +extern int ClientDGRAM; +extern int ClientNMB; + +/* this is our domain/workgroup/server database */ +extern struct domain_record *domainlist; + +/* machine comment for host announcements */ +extern pstring ServerComment; + +extern int updatecount; +extern int workgroup_count; + +/* what server type are we currently */ + +#define AM_MASTER(work) (work->ServerType & SV_TYPE_MASTER_BROWSER) +#define AM_BACKUP(work) (work->ServerType & SV_TYPE_BACKUP_BROWSER) +#define AM_DOMCTL(work) (work->ServerType & SV_TYPE_DOMAIN_CTRL) + +#define MSBROWSE "\001\002__MSBROWSE__\002" +#define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE" + +/**************************************************************************** + send a announce request to the local net + **************************************************************************/ +void announce_request(struct work_record *work, struct in_addr ip) +{ + pstring outbuf; + char *p; + + if (!work) return; + + work->needannounce = True; + + DEBUG(2,("Sending announce request to %s for workgroup %s\n", + inet_ntoa(ip),work->work_group)); + + bzero(outbuf,sizeof(outbuf)); + p = outbuf; + CVAL(p,0) = 2; /* announce request */ + p++; + + CVAL(p,0) = work->token; /* flags?? XXXX probably a token*/ + p++; + StrnCpy(p,myname,16); + strupper(p); + p = skip_string(p,1); + + send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), + myname,work->work_group,0x20,0x0,ip,myip); +} + + +/**************************************************************************** + request an announcement + **************************************************************************/ +void do_announce_request(char *info, char *to_name, int announce_type, int from, + int to, struct in_addr dest_ip) +{ + pstring outbuf; + char *p; + + bzero(outbuf,sizeof(outbuf)); + p = outbuf; + CVAL(p,0) = announce_type; /* announce request */ + p++; + + DEBUG(2,("Sending announce type %d: info %s to %s - server %s(%x)\n", + announce_type, info, inet_ntoa(dest_ip),to_name,to)); + + StrnCpy(p,info,16); + strupper(p); + p = skip_string(p,1); + + send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), + myname,to_name,from,to,dest_ip,myip); +} + +/**************************************************************************** + construct a host announcement unicast + **************************************************************************/ +void announce_backup(void) +{ + static time_t lastrun = 0; + time_t t = time(NULL); + pstring outbuf; + char *p; + struct domain_record *d1; + int tok; + + if (!lastrun) lastrun = t; + if (t < lastrun + 1*60) return; + lastrun = t; + + for (tok = 0; tok <= workgroup_count; tok++) + { + for (d1 = domainlist; d1; d1 = d1->next) + { + struct work_record *work; + struct domain_record *d; + + /* search for unique workgroup: only the name matters */ + for (work = d1->workgrouplist; + work && (tok != work->token); + work = work->next); + + if (work) + { + /* found one: announce it across all domains */ + for (d = domainlist; d; d = d->next) + { + DEBUG(2,("Sending announce backup %s workgroup %s(%d)\n", + inet_ntoa(d->bcast_ip),work->work_group, + work->token)); + + bzero(outbuf,sizeof(outbuf)); + p = outbuf; + CVAL(p,0) = 9; /* backup list response */ + p++; + + CVAL(p,0) = 1; /* count? */ + SIVAL(p,1,work->token); /* workgroup unique key index */ + p += 5; + p++; + + if (AM_DOMCTL(work)) + { + send_mailslot_reply(BROWSE_MAILSLOT, + ClientDGRAM,outbuf, + PTR_DIFF(p,outbuf), + myname, work->work_group, + 0x0,0x1b,d->bcast_ip,myip); + } + else if (AM_MASTER(work)) + { + send_mailslot_reply(BROWSE_MAILSLOT, + ClientDGRAM,outbuf, + PTR_DIFF(p,outbuf), + myname, work->work_group, + 0x0,0x1d,d->bcast_ip,myip); + } + } + } + } + } +} + + +/**************************************************************************** + construct a host announcement unicast + **************************************************************************/ +void announce_host(void) +{ + time_t t = time(NULL); + pstring outbuf; + char *p; + char *namep; + char *stypep; + char *commentp; + pstring comment; + char *my_name; + struct domain_record *d; + + StrnCpy(comment, *ServerComment ? ServerComment : "NoComment", 43); + + my_name = *myname ? myname : "NoName"; + + for (d = domainlist; d; d = d->next) + { + struct work_record *work; + + if (!ip_equal(bcast_ip,d->bcast_ip)) + { + continue; + } + + for (work = d->workgrouplist; work; work = work->next) + { + uint32 stype = work->ServerType; + struct server_record *s; + BOOL announce = False; + + if (work->needannounce) + { + /* drop back to a max 3 minute announce - this is to prevent a + single lost packet from stuffing things up for too long */ + work->announce_interval = MIN(work->announce_interval,3*60); + work->lastannounce_time = t - (work->announce_interval+1); + } + + /* announce every minute at first then progress to every 12 mins */ + if (work->lastannounce_time && + (t - work->lastannounce_time) < work->announce_interval) + { + continue; + } + + if (work->announce_interval < 12*60) work->announce_interval += 60; + + work->lastannounce_time = t; + + DEBUG(2,("Sending announcement to subnet %s for workgroup %s\n", + inet_ntoa(d->bcast_ip),work->work_group)); + + if (!ip_equal(bcast_ip,d->bcast_ip)) + { + stype &= ~(SV_TYPE_POTENTIAL_BROWSER | SV_TYPE_MASTER_BROWSER | + SV_TYPE_DOMAIN_MASTER | SV_TYPE_BACKUP_BROWSER | + SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_MEMBER); + } + + for (s = work->serverlist; s; s = s->next) + { + if (strequal(myname, s->serv.name)) { announce = True; break; } + } + + if (announce) + { + bzero(outbuf,sizeof(outbuf)); + p = outbuf+1; + + CVAL(p,0) = updatecount; + SIVAL(p,1,work->announce_interval*1000); /* ms - despite the spec */ + namep = p+5; + StrnCpy(namep,my_name,16); + strupper(namep); + CVAL(p,21) = 2; /* major version */ + CVAL(p,22) = 2; /* minor version */ + stypep = p+23; + SIVAL(p,23,stype); + SSVAL(p,27,0xaa55); /* browse signature */ + SSVAL(p,29,1); /* browse version */ + commentp = p+31; + strcpy(commentp,comment); + p = p+31; + p = skip_string(p,1); + + if (ip_equal(bcast_ip,d->bcast_ip)) + { + if (AM_MASTER(work)) + { + SIVAL(stypep,0,work->ServerType); + + CVAL(outbuf,0) = 15; /* local member announce */ + + send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf, + PTR_DIFF(p,outbuf), + my_name,work->work_group,0,0x1e,d->bcast_ip,myip); + + CVAL(outbuf,0) = 12; /* domain announce */ + + StrnCpy(namep,work->work_group,15); + strupper(namep); + StrnCpy(commentp,myname,15); + strupper(commentp); + + SIVAL(stypep,0,(unsigned)0x80000000); + p = commentp + strlen(commentp) + 1; + + send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf, + PTR_DIFF(p,outbuf), + my_name,MSBROWSE,0,0x01,d->bcast_ip,myip); + } + else + { + CVAL(outbuf,0) = 1; /* host announce */ + + send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf, + PTR_DIFF(p,outbuf), + my_name,work->work_group,0,0x1d,d->bcast_ip,myip); + } + } + } + + if (work->needannounce) + { + work->needannounce = False; + break; + /* sorry: can't do too many announces. do some more later */ + } + } + } +} + + +/**************************************************************************** + announce myself as a master to all other primary domain conrollers. + + BIG NOTE: this code will remain untested until some kind soul that has access + to a couple of windows NT advanced servers runs this version of nmbd for at + least 15 minutes. + + this actually gets done in search_and_sync_workgroups() via the + MASTER_SERVER_CHECK command, if there is a response from the + name query initiated here. see response_name_query() + **************************************************************************/ +void announce_master(void) +{ + struct domain_record *d; + static time_t last=0; + time_t t = time(NULL); + BOOL am_master = False; /* are we a master of some sort? :-) */ + +#ifdef TEST_CODE + if (last && (t-last < 2*60)) return; +#else + if (last && (t-last < 15*60)) return; +#endif + + last = t; + + for (d = domainlist; d; d = d->next) + { + struct work_record *work; + for (work = d->workgrouplist; work; work = work->next) + { + if (AM_MASTER(work)) + { + am_master = True; + } + } + } + + if (!am_master) return; /* only proceed if we are a master browser */ + + for (d = domainlist; d; d = d->next) + { + struct work_record *work; + for (work = d->workgrouplist; work; work = work->next) + { + struct server_record *s; + for (s = work->serverlist; s; s = s->next) + { + if (strequal(s->serv.name, myname)) continue; + + /* all PDCs (which should also be master browsers) */ + if (s->serv.type & SV_TYPE_DOMAIN_CTRL) + { + /* check the existence of a pdc for this workgroup, and if + one exists at the specified ip, sync with it and announce + ourselves as a master browser to it */ + + if (!*lp_domain_controller() || + !strequal(lp_domain_controller(), s->serv.name)) + { + if (!lp_wins_support() && *lp_wins_server()) + { + struct in_addr ip; + ip = ipzero; + + queue_netbios_pkt_wins(ClientNMB,NMB_QUERY, + MASTER_SERVER_CHECK, + work->work_group,0x1b,0, + False, False, ip); + } + else + { + struct domain_record *d2; + for (d2 = domainlist; d2; d2 = d2->next) + { + queue_netbios_packet(ClientNMB,NMB_QUERY, + MASTER_SERVER_CHECK, + work->work_group,0x1b,0, + True, False, d2->bcast_ip); + } + } + } + } + } + + /* now do primary domain controller - the one that's not + necessarily in our browse lists, although it ought to be + this pdc is the one that we get TOLD about through smb.conf. + basically, if it's on a subnet that we know about, it may end + up in our browse lists (which is why it's explicitly excluded + in the code above) */ + + if (*lp_domain_controller()) + { + struct in_addr ip; + BOOL bcast = False; + + ip = *interpret_addr2(lp_domain_controller()); + + if (zero_ip(ip)) + { + ip = bcast_ip; + bcast = True; + } + + DEBUG(2, ("Searching for PDC %s at %s\n", + lp_domain_controller(), inet_ntoa(ip))); + + /* check the existence of a pdc for this workgroup, and if + one exists at the specified ip, sync with it and announce + ourselves as a master browser to it */ + queue_netbios_pkt_wins(ClientNMB, NMB_QUERY,MASTER_SERVER_CHECK, + work->work_group,0x1b, 0, + bcast, False, ip); + } + } + } +} diff --git a/source/namedb.c b/source/namedb.c new file mode 100644 index 00000000000..9151789b9b0 --- /dev/null +++ b/source/namedb.c @@ -0,0 +1,709 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + NBT netbios routines and daemon - version 2 + Copyright (C) Andrew Tridgell 1994-1995 + + 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. + + Revision History: + + 14 jan 96: lkcl@pires.co.uk + added multiple workgroup domain master support + +*/ + +#include "includes.h" +#include "smb.h" +#include "loadparm.h" +#include "localnet.h" + +extern int DEBUGLEVEL; + +extern time_t StartupTime; +extern pstring myname; +extern pstring scope; +extern struct in_addr bcast_ip; + +/* this is our browse master/backup cache database */ +struct browse_cache_record *browserlist = NULL; + +/* this is our domain/workgroup/server database */ +struct domain_record *domainlist = NULL; + +static BOOL updatedlists = True; +int updatecount=0; + +int workgroup_count = 0; /* unique index key: one for each workgroup */ + +/* what server type are we currently */ + +#define DFLT_SERVER_TYPE (SV_TYPE_WORKSTATION | SV_TYPE_SERVER | \ + SV_TYPE_TIME_SOURCE | SV_TYPE_SERVER_UNIX | \ + SV_TYPE_PRINTQ_SERVER | SV_TYPE_POTENTIAL_BROWSER) + +/* here are my election parameters */ + +/* NTAS uses 2, NT uses 1, WfWg uses 0 */ +#define MAINTAIN_LIST 2 +#define ELECTION_VERSION 2 + +#define MSBROWSE "\001\002__MSBROWSE__\002" + + +/**************************************************************************** + add a workgroup into the domain list + **************************************************************************/ +static void add_workgroup(struct work_record *work, struct domain_record *d) +{ + struct work_record *w2; + + if (!work || !d) return; + + if (!d->workgrouplist) + { + d->workgrouplist = work; + work->prev = NULL; + work->next = NULL; + return; + } + + for (w2 = d->workgrouplist; w2->next; w2 = w2->next); + + w2->next = work; + work->next = NULL; + work->prev = w2; +} + + +/**************************************************************************** + create a blank workgroup + **************************************************************************/ +static struct work_record *make_workgroup(char *name) +{ + struct work_record *work; + struct domain_record *d; + int t = -1; + + if (!name || !name[0]) return NULL; + + work = (struct work_record *)malloc(sizeof(*work)); + if (!work) return(NULL); + + StrnCpy(work->work_group,name,sizeof(work->work_group)-1); + work->serverlist = NULL; + + work->ServerType = DFLT_SERVER_TYPE; + work->RunningElection = False; + work->ElectionCount = 0; + work->needelection = False; + work->needannounce = True; + + /* make sure all token representations of workgroups are unique */ + + for (d = domainlist; d && t == -1; d = d->next) + { + struct work_record *w; + for (w = d->workgrouplist; w && t == -1; w = w->next) + { + if (strequal(w->work_group, work->work_group)) t = w->token; + } + } + + if (t == -1) + { + work->token = ++workgroup_count; + } + else + { + work->token = t; + } + + + /* WfWg uses 01040b01 */ + /* Win95 uses 01041501 */ + /* NTAS uses ???????? */ + work->ElectionCriterion = (MAINTAIN_LIST<<1)|(ELECTION_VERSION<<8); + work->ElectionCriterion |= (lp_os_level() << 24); + if (lp_domain_master()) + { + work->ElectionCriterion |= 0x80; + } + + return work; +} + + +/******************************************************************* + expire old servers in the serverlist + time of -1 indicates everybody dies + ******************************************************************/ +static void remove_old_servers(struct work_record *work, time_t t) +{ + struct server_record *s; + struct server_record *nexts; + + /* expire old entries in the serverlist */ + for (s = work->serverlist; s; s = nexts) + { + if (t == -1 || (s->death_time && s->death_time < t)) + { + DEBUG(3,("Removing dead server %s\n",s->serv.name)); + updatedlists = True; + nexts = s->next; + + if (s->prev) s->prev->next = s->next; + if (s->next) s->next->prev = s->prev; + + if (work->serverlist == s) work->serverlist = s->next; + + free(s); + } + else + { + nexts = s->next; + } + } +} + + +/******************************************************************* + remove workgroups + ******************************************************************/ +struct work_record *remove_workgroup(struct domain_record *d, struct work_record *work) +{ + struct work_record *ret_work = NULL; + + if (!d || !work) return NULL; + + DEBUG(3,("Removing old workgroup %s\n", work->work_group)); + + remove_old_servers(work, -1); + + ret_work = work->next; + + if (work->prev) work->prev->next = work->next; + if (work->next) work->next->prev = work->prev; + + if (d->workgrouplist == work) d->workgrouplist = work->next; + + free(work); + + return ret_work; +} + + +/**************************************************************************** + add a domain into the list + **************************************************************************/ +static void add_domain(struct domain_record *d) +{ + struct domain_record *d2; + + if (!domainlist) + { + domainlist = d; + d->prev = NULL; + d->next = NULL; + return; + } + + for (d2 = domainlist; d2->next; d2 = d2->next); + + d2->next = d; + d->next = NULL; + d->prev = d2; +} + +/*************************************************************************** + add a browser into the list + **************************************************************************/ +static void add_browse_cache(struct browse_cache_record *b) +{ +struct browse_cache_record *b2; + + if (!browserlist) + { + browserlist = b; + b->prev = NULL; + b->next = NULL; + return; + } + + for (b2 = browserlist; b2->next; b2 = b2->next) ; + + b2->next = b; + b->next = NULL; + b->prev = b2; +} + + +/*************************************************************************** + add a server into the list + **************************************************************************/ +static void add_server(struct work_record *work,struct server_record *s) +{ + struct server_record *s2; + + if (!work->serverlist) { + work->serverlist = s; + s->prev = NULL; + s->next = NULL; + return; + } + + for (s2 = work->serverlist; s2->next; s2 = s2->next) ; + + s2->next = s; + s->next = NULL; + s->prev = s2; +} + + +/******************************************************************* + remove old browse entries + ******************************************************************/ +void expire_browse_cache(time_t t) +{ + struct browse_cache_record *b; + struct browse_cache_record *nextb; + + /* expire old entries in the serverlist */ + for (b = browserlist; b; b = nextb) + { + if (b->synced && b->sync_time < t) + { + DEBUG(3,("Removing dead cached browser %s\n",b->name)); + nextb = b->next; + + if (b->prev) b->prev->next = b->next; + if (b->next) b->next->prev = b->prev; + + if (browserlist == b) browserlist = b->next; + + free(b); + } + else + { + nextb = b->next; + } + } +} + + +/**************************************************************************** + find a workgroup in the workgrouplist + only create it if the domain allows it, or the parameter 'add' insists + that it get created/added anyway. this allows us to force entries in + lmhosts file to be added. + **************************************************************************/ +struct work_record *find_workgroupstruct(struct domain_record *d, fstring name, BOOL add) +{ + struct work_record *ret, *work; + + if (!d) return NULL; + + DEBUG(4, ("workgroup search for %s: ", name)); + + if (strequal(name, "*")) + { + DEBUG(2,("add any workgroups: initiating browser search on %s\n", + inet_ntoa(d->bcast_ip))); + queue_netbios_pkt_wins(ClientNMB,NMB_QUERY, FIND_MASTER, + MSBROWSE,0x1,0, + True,False, d->bcast_ip); + return NULL; + } + + for (ret = d->workgrouplist; ret; ret = ret->next) + { + if (!strcmp(ret->work_group,name)) + { + DEBUG(4, ("found\n")); + return(ret); + } + } + + DEBUG(4, ("not found: creating\n")); + + if ((work = make_workgroup(name))) + { + if (lp_preferred_master() && + strequal(lp_workgroup(), name) && + ip_equal(d->bcast_ip, bcast_ip)) + { + DEBUG(3, ("preferred master startup for %s\n", work->work_group)); + work->needelection = True; + work->ElectionCriterion |= (1<<3); + } + if (!ip_equal(bcast_ip, d->bcast_ip)) + { + work->needelection = False; + } + add_workgroup(work, d); + return(work); + } + return NULL; +} + +/**************************************************************************** + find a domain in the domainlist + **************************************************************************/ +struct domain_record *find_domain(struct in_addr source_ip) +{ + struct domain_record *d; + + /* search through domain list for broadcast/netmask that matches + the source ip address */ + + for (d = domainlist; d; d = d->next) + { + if (same_net(source_ip, d->bcast_ip, d->mask_ip)) + { + return(d); + } + } + + return (NULL); +} + + +/**************************************************************************** + dump a copy of the workgroup/domain database + **************************************************************************/ +static void dump_workgroups(void) +{ + struct domain_record *d; + + for (d = domainlist; d; d = d->next) + { + if (d->workgrouplist) + { + struct work_record *work; + + DEBUG(3,("dump domain %15s: ", inet_ntoa(d->bcast_ip))); + DEBUG(3,(" %15s:\n", inet_ntoa(d->bcast_ip))); + + for (work = d->workgrouplist; work; work = work->next) + { + if (work->serverlist) + { + struct server_record *s; + + DEBUG(3,("\t%s(%d)\n", work->work_group, work->token)); + for (s = work->serverlist; s; s = s->next) + { + DEBUG(3,("\t\t%s %8x (%s)\n", + s->serv.name, s->serv.type, s->serv.comment)); + } + } + } + } + } +} + +/**************************************************************************** + create a domain entry + ****************************************************************************/ +static struct domain_record *make_domain(struct in_addr ip, struct in_addr mask) +{ + struct domain_record *d; + d = (struct domain_record *)malloc(sizeof(*d)); + + if (!d) return(NULL); + + bzero((char *)d,sizeof(*d)); + + DEBUG(4, ("making domain %s ", inet_ntoa(ip))); + DEBUG(4, ("%s\n", inet_ntoa(mask))); + + d->bcast_ip = ip; + d->mask_ip = mask; + d->workgrouplist = NULL; + + add_domain(d); + + return d; +} + +/**************************************************************************** + add a domain entry. creates a workgroup, if necessary, and adds the domain + to the named a workgroup. + ****************************************************************************/ +struct domain_record *add_domain_entry(struct in_addr source_ip, struct in_addr source_mask, + char *name, BOOL add) +{ + struct domain_record *d; + struct in_addr ip; + + ip = *interpret_addr2("255.255.255.255"); + + if (zero_ip(source_ip)) source_ip = bcast_ip; + + /* add the domain into our domain database */ + if ((d = find_domain(source_ip)) || + (d = make_domain(source_ip, source_mask))) + { + find_workgroupstruct(d, name, add); + + /* add WORKGROUP(1e) and WORKGROUP(00) entries into name database + or register with WINS server, if it's our workgroup */ + if (strequal(lp_workgroup(), name)) + { + add_name_entry(name,0x1e,NB_ACTIVE|NB_GROUP); + add_name_entry(name,0x0 ,NB_ACTIVE|NB_GROUP); + } + + DEBUG(3,("Added domain name entry %s at %s\n", name,inet_ntoa(ip))); + return d; + } + return NULL; +} + +/**************************************************************************** + add a browser entry + ****************************************************************************/ +struct browse_cache_record *add_browser_entry(char *name, int type, char *wg, + time_t ttl, struct in_addr ip) +{ + BOOL newentry=False; + + struct browse_cache_record *b; + + /* search for the entry: if it's already in the cache, update that entry */ + for (b = browserlist; b; b = b->next) + { + if (ip_equal(ip,b->ip) && strequal(b->group, wg)) break; + } + + if (b && b->synced) + { + /* entries get left in the cache for a while. this stops sync'ing too + often if the network is large */ + DEBUG(4, ("browser %s %s %s already sync'd at time %d\n", + b->name, b->group, inet_ntoa(b->ip), b->sync_time)); + return NULL; + } + + if (!b) + { + newentry = True; + b = (struct browse_cache_record *)malloc(sizeof(*b)); + + if (!b) return(NULL); + + bzero((char *)b,sizeof(*b)); + } + + /* update the entry */ + ttl = time(NULL)+ttl; + + StrnCpy(b->name ,name,sizeof(b->name )-1); + StrnCpy(b->group,wg ,sizeof(b->group)-1); + strupper(b->name); + strupper(b->group); + + b->ip = ip; + b->type = type; + + if (newentry || ttl < b->sync_time) b->sync_time = ttl; + + if (newentry) + { + b->synced = False; + add_browse_cache(b); + + DEBUG(3,("Added cache entry %s %s(%2x) %s ttl %d\n", + wg, name, type, inet_ntoa(ip),ttl)); + } + else + { + DEBUG(3,("Updated cache entry %s %s(%2x) %s ttl %d\n", + wg, name, type, inet_ntoa(ip),ttl)); + } + + return(b); +} + + +/**************************************************************************** + add a server entry + ****************************************************************************/ +struct server_record *add_server_entry(struct domain_record *d, struct work_record *work, + char *name,int servertype, int ttl,char *comment, + BOOL replace) +{ + BOOL newentry=False; + struct server_record *s; + + if (name[0] == '*') + { + return (NULL); + } + + for (s = work->serverlist; s; s = s->next) + { + if (strequal(name,s->serv.name)) break; + } + + if (s && !replace) + { + DEBUG(4,("Not replacing %s\n",name)); + return(s); + } + + updatedlists=True; + + if (!s) + { + newentry = True; + s = (struct server_record *)malloc(sizeof(*s)); + + if (!s) return(NULL); + + bzero((char *)s,sizeof(*s)); + } + + if (ip_equal(bcast_ip, d->bcast_ip) && + strequal(lp_workgroup(),work->work_group)) + { + servertype |= SV_TYPE_LOCAL_LIST_ONLY; + } + else + { + servertype &= ~SV_TYPE_LOCAL_LIST_ONLY; + } + + /* update the entry */ + StrnCpy(s->serv.name,name,sizeof(s->serv.name)-1); + StrnCpy(s->serv.comment,comment,sizeof(s->serv.comment)-1); + strupper(s->serv.name); + s->serv.type = servertype; + s->death_time = ttl?time(NULL)+ttl*3:0; + + /* for a domain entry, the comment field refers to the server name */ + + if (s->serv.type & SV_TYPE_DOMAIN_ENUM) strupper(s->serv.comment); + + if (newentry) + { + add_server(work, s); + + DEBUG(3,("Added ")); + } + else + { + DEBUG(3,("Updated ")); + } + + DEBUG(3,("server entry %s of type %x (%s) to %s %s\n", + name,servertype,comment, + work->work_group,inet_ntoa(d->bcast_ip))); + + return(s); +} + + +/******************************************************************* + write out browse.dat + ******************************************************************/ +void write_browse_list(void) +{ + struct domain_record *d; + + pstring fname,fnamenew; + FILE *f; + + if (!updatedlists) return; + + dump_names(); + dump_workgroups(); + + updatedlists = False; + updatecount++; + + strcpy(fname,lp_lockdir()); + trim_string(fname,NULL,"/"); + strcat(fname,"/"); + strcat(fname,SERVER_LIST); + strcpy(fnamenew,fname); + strcat(fnamenew,"."); + + f = fopen(fnamenew,"w"); + + if (!f) + { + DEBUG(4,("Can't open %s - %s\n",fnamenew,strerror(errno))); + return; + } + + for (d = domainlist; d ; d = d->next) + { + struct work_record *work; + for (work = d->workgrouplist; work ; work = work->next) + { + struct server_record *s; + for (s = work->serverlist; s ; s = s->next) + { + fstring tmp; + + /* don't list domains I don't have a master for */ + if ((s->serv.type & SV_TYPE_DOMAIN_ENUM) && + !s->serv.comment[0]) + { + continue; + } + + /* output server details, plus what workgroup/domain + they're in. without the domain information, the + combined list of all servers in all workgroups gets + sent to anyone asking about any workgroup! */ + + sprintf(tmp, "\"%s\"", s->serv.name); + fprintf(f, "%-25s ", tmp); + fprintf(f, "%08x ", s->serv.type); + sprintf(tmp, "\"%s\"", s->serv.comment); + fprintf(f, "%-30s", tmp); + fprintf(f, "\"%s\"\n", work->work_group); + } + } + } + + fclose(f); + unlink(fname); + chmod(fnamenew,0644); + rename(fnamenew,fname); + DEBUG(3,("Wrote browse list %s\n",fname)); +} + + +/******************************************************************* + expire old servers in the serverlist + ******************************************************************/ +void expire_servers(time_t t) +{ + struct domain_record *d; + + for (d = domainlist ; d ; d = d->next) + { + struct work_record *work; + + for (work = d->workgrouplist; work; work = work->next) + { + remove_old_servers(work, t); + } + } +} + diff --git a/source/nameelect.c b/source/nameelect.c new file mode 100644 index 00000000000..30c3c3795e8 --- /dev/null +++ b/source/nameelect.c @@ -0,0 +1,371 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + NBT netbios routines and daemon - version 2 + Copyright (C) Andrew Tridgell 1994-1995 + + 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. + + Revision History: + + 14 jan 96: lkcl@pires.co.uk + added multiple workgroup domain master support + +*/ + +#include "includes.h" +#include "loadparm.h" +#include "localnet.h" + +extern int DEBUGLEVEL; +extern pstring scope; + +extern pstring myname; + +/* machine comment for host announcements */ +extern pstring ServerComment; + +/* here are my election parameters */ + +/* NTAS uses 2, NT uses 1, WfWg uses 0 */ +#define MAINTAIN_LIST 2 +#define ELECTION_VERSION 2 + +extern time_t StartupTime; + +#define AM_MASTER(work) (work->ServerType & SV_TYPE_MASTER_BROWSER) + +#define MSBROWSE "\001\002__MSBROWSE__\002" +#define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE" + +extern struct domain_record *domainlist; + + +/******************************************************************* + occasionally check to see if the master browser is around + ******************************************************************/ +void check_master_browser(void) +{ + static time_t lastrun=0; + time_t t = time(NULL); + struct domain_record *d; + + if (!lastrun) lastrun = t; + if (t < lastrun + 2*60) return; + lastrun = t; + + for (d = domainlist; d; d = d->next) + { + struct work_record *work; + + for (work = d->workgrouplist; work; work = work->next) + { + /* if we are not the browse master of a workgroup, and we can't + find a browser on the subnet, do something about it. */ + + if (!AM_MASTER(work)) + { + queue_netbios_packet(ClientNMB,NMB_QUERY,CHECK_MASTER, + work->work_group,0x1d,0, + True,False,d->bcast_ip); + } + } + } +} + + +/******************************************************************* + what to do if a master browser DOESN't exist + ******************************************************************/ +void browser_gone(char *work_name, struct in_addr ip) +{ + struct domain_record *d = find_domain(ip); + struct work_record *work = find_workgroupstruct(d, work_name, False); + + if (!work || !d) return; + + DEBUG(2,("Forcing election on %s\n",work->work_group)); + + if (strequal(work->work_group, lp_workgroup()) && + ip_equal(bcast_ip, d->bcast_ip)) + { + /* we can attempt to become master browser */ + work->needelection = True; + } + else + { + DEBUG(2,("no master browser for persistent entry %s %s\n", + work->work_group, inet_ntoa(d->bcast_ip))); + + /* XXXX oh dear. we are going to have problems here. the + entry is a persistent one, there isn't anyone responsible + for this workgroup up and running, yet we can't find it + and we are going to continually have name_queries until + a master browser is found for this workgroup on the + remote subnet. + */ + } +} +/**************************************************************************** + send an election packet + **************************************************************************/ +void send_election(struct domain_record *d, char *group,uint32 criterion, + int timeup,char *name) +{ + pstring outbuf; + char *p; + + if (!d) return; + + DEBUG(2,("Sending election to %s for workgroup %s\n", + inet_ntoa(d->bcast_ip),group)); + + bzero(outbuf,sizeof(outbuf)); + p = outbuf; + CVAL(p,0) = 8; /* election */ + p++; + + CVAL(p,0) = (criterion == 0 && timeup == 0) ? 0 : ELECTION_VERSION; + SIVAL(p,1,criterion); + SIVAL(p,5,timeup*1000); /* ms - despite the spec */ + p += 13; + strcpy(p,name); + strupper(p); + p = skip_string(p,1); + + send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), + name,group,0,0x1e,d->bcast_ip,myip); +} + + +/******************************************************************* + become the master browser + ******************************************************************/ +static void become_master(struct domain_record *d, struct work_record *work) +{ + uint32 domain_type = SV_TYPE_DOMAIN_ENUM | SV_TYPE_SERVER_UNIX | 0x00400000; + + if (!work) return; + + DEBUG(2,("Becoming master for %s\n",work->work_group)); + + work->ServerType |= SV_TYPE_MASTER_BROWSER; + work->ServerType &= ~SV_TYPE_POTENTIAL_BROWSER; + work->ElectionCriterion |= 0x5; + + /* add browse, master and general names to database or register with WINS */ + add_name_entry(MSBROWSE ,0x01,NB_ACTIVE|NB_GROUP); + add_name_entry(work->work_group,0x1d,NB_ACTIVE ); + + if (lp_domain_master()) + { + DEBUG(4,("Domain master: adding names...\n")); + + /* add domain master and domain member names or register with WINS */ + add_name_entry(work->work_group,0x1b,NB_ACTIVE ); + add_name_entry(work->work_group,0x1c,NB_ACTIVE|NB_GROUP); + + work->ServerType |= SV_TYPE_DOMAIN_MASTER; + + if (lp_domain_logons()) + { + work->ServerType |= SV_TYPE_DOMAIN_CTRL; + work->ServerType |= SV_TYPE_DOMAIN_MEMBER; + } + } + + /* update our server status */ + add_server_entry(d,work,work->work_group,domain_type,0,myname,True); + add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True); + + if (ip_equal(bcast_ip, d->bcast_ip)) + { + /* ask all servers on our local net to announce to us */ + announce_request(work, d->bcast_ip); + } +} + + +/******************************************************************* + unbecome the master browser + ******************************************************************/ +void become_nonmaster(struct domain_record *d, struct work_record *work) +{ + DEBUG(2,("Becoming non-master for %s\n",work->work_group)); + + work->ServerType &= ~SV_TYPE_MASTER_BROWSER; + work->ServerType &= ~SV_TYPE_DOMAIN_MASTER; + work->ServerType |= SV_TYPE_POTENTIAL_BROWSER; + + work->ElectionCriterion &= ~0x4; + + remove_name_entry(work->work_group,0x1b); + remove_name_entry(work->work_group,0x1c); + remove_name_entry(work->work_group,0x1d); + remove_name_entry(MSBROWSE ,0x01); +} + + +/******************************************************************* + run the election + ******************************************************************/ +void run_elections(void) +{ + time_t t = time(NULL); + static time_t lastime = 0; + + struct domain_record *d; + + /* send election packets once a second */ + if (lastime && t-lastime <= 0) return; + + lastime = t; + + for (d = domainlist; d; d = d->next) + { + struct work_record *work; + for (work = d->workgrouplist; work; work = work->next) + { + if (work->RunningElection) + { + send_election(d,work->work_group, work->ElectionCriterion, + t-StartupTime,myname); + + if (work->ElectionCount++ >= 4) + { + /* I won! now what :-) */ + DEBUG(2,(">>> Won election on %s <<<\n",work->work_group)); + + work->RunningElection = False; + become_master(d, work); + } + } + } + } +} + + +/******************************************************************* + work out if I win an election + ******************************************************************/ +static BOOL win_election(struct work_record *work,int version,uint32 criterion, + int timeup,char *name) +{ + time_t t = time(NULL); + uint32 mycriterion; + if (version > ELECTION_VERSION) return(False); + if (version < ELECTION_VERSION) return(True); + + mycriterion = work->ElectionCriterion; + + if (criterion > mycriterion) return(False); + if (criterion < mycriterion) return(True); + + if (timeup > (t - StartupTime)) return(False); + if (timeup < (t - StartupTime)) return(True); + + if (strcasecmp(myname,name) > 0) return(False); + + return(True); +} + + +/******************************************************************* + process a election packet + + An election dynamically decides who will be the master. + ******************************************************************/ +void process_election(struct packet_struct *p,char *buf) +{ + struct dgram_packet *dgram = &p->packet.dgram; + struct in_addr ip = dgram->header.source_ip; + struct domain_record *d = find_domain(ip); + int version = CVAL(buf,0); + uint32 criterion = IVAL(buf,1); + int timeup = IVAL(buf,5)/1000; + char *name = buf+13; + struct work_record *work; + + if (!d) return; + + name[15] = 0; + + DEBUG(3,("Election request from %s vers=%d criterion=%08x timeup=%d\n", + name,version,criterion,timeup)); + + if (same_context(dgram)) return; + + for (work = d->workgrouplist; work; work = work->next) + { + if (listening_name(work, &dgram->dest_name) && + strequal(work->work_group, lp_workgroup()) && + ip_equal(d->bcast_ip, bcast_ip)) + { + if (win_election(work, version,criterion,timeup,name)) + { + if (!work->RunningElection) + { + work->needelection = True; + work->ElectionCount=0; + } + } + else + { + work->needelection = False; + + if (work->RunningElection) + { + work->RunningElection = False; + DEBUG(3,(">>> Lost election on %s <<<\n",work->work_group)); + + /* if we are the master then remove our masterly names */ + if (AM_MASTER(work)) + { + become_nonmaster(d, work); + } + } + } + } + } +} + + +/**************************************************************************** + checks whether a browser election is to be run on any workgroup + ***************************************************************************/ +BOOL check_elections(void) +{ + struct domain_record *d; + BOOL run_any_election = False; + + for (d = domainlist; d; d = d->next) + { + struct work_record *work; + for (work = d->workgrouplist; work; work = work->next) + { + run_any_election |= work->RunningElection; + + if (work->needelection && !work->RunningElection) + { + DEBUG(3,(">>> Starting election on %s <<<\n",work->work_group)); + work->ElectionCount = 0; + work->RunningElection = True; + work->needelection = False; + } + } + } + return run_any_election; +} + diff --git a/source/nameresp.c b/source/nameresp.c new file mode 100644 index 00000000000..a4a55c9f1be --- /dev/null +++ b/source/nameresp.c @@ -0,0 +1,625 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + NBT netbios library routines + Copyright (C) Andrew Tridgell 1994-1995 + + 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 "localnet.h" +#include "loadparm.h" + +/* this is our initiated name query response database */ +struct name_response_record *nameresponselist = NULL; + +extern struct in_addr myip; +extern int DEBUGLEVEL; + +static uint16 name_trn_id=0; +BOOL CanRecurse = True; +extern pstring scope; +extern pstring myname; +extern struct in_addr ipzero; + + +/*************************************************************************** + add an initated name query into the list + **************************************************************************/ +extern void add_response_record(struct name_response_record *n) +{ + struct name_response_record *n2; + + if (!nameresponselist) + { + nameresponselist = n; + n->prev = NULL; + n->next = NULL; + return; + } + + for (n2 = nameresponselist; n2->next; n2 = n2->next) ; + + n2->next = n; + n->next = NULL; + n->prev = n2; +} + + +/******************************************************************* + remove old name response entries + ******************************************************************/ +void expire_netbios_response_entries(time_t t) +{ + struct name_response_record *n; + struct name_response_record *nextn; + + for (n = nameresponselist; n; n = nextn) + { + if (n->start_time < t) + { + DEBUG(3,("Removing dead name query for %s %s (num_msgs=%d)\n", + inet_ntoa(n->to_ip), namestr(&n->name), n->num_msgs)); + + if (n->cmd_type == CHECK_MASTER && n->num_msgs == 0) + { + if (n->num_msgs > 1) + { + /* more than one master browser detected on a subnet. + there is a configuration problem. force an election */ + struct domain_record *d; + if ((d = find_domain(n->to_ip))) + { + send_election(d,n->name.name,0,0,myname); + } + } + + /* if no response received, the master browser must have gone */ + browser_gone(n->name.name, n->to_ip); + } + + nextn = n->next; + + if (n->prev) n->prev->next = n->next; + if (n->next) n->next->prev = n->prev; + + if (nameresponselist == n) nameresponselist = n->next; + + free(n); + } + else + { + nextn = n->next; + } + } +} + + +/**************************************************************************** + reply to a netbios name packet + ****************************************************************************/ +void reply_netbios_packet(struct packet_struct *p1,int trn_id,int rcode,int opcode, + struct nmb_name *rr_name,int rr_type,int rr_class,int ttl, + char *data,int len) +{ + struct packet_struct p; + struct nmb_packet *nmb = &p.packet.nmb; + struct res_rec answers; + char *packet_type = "unknown"; + + p = *p1; + + if (rr_type == NMB_STATUS) packet_type = "nmb_status"; + if (rr_type == NMB_QUERY ) packet_type = "nmb_query"; + if (rr_type == NMB_REG ) packet_type = "nmb_reg"; + if (rr_type == NMB_REL ) packet_type = "nmb_rel"; + + DEBUG(4,("replying netbios packet: %s %s\n", + packet_type, namestr(rr_name), inet_ntoa(p.ip))); + + nmb->header.name_trn_id = trn_id; + nmb->header.opcode = opcode; + nmb->header.response = True; + nmb->header.nm_flags.bcast = False; + nmb->header.nm_flags.recursion_available = True; + nmb->header.nm_flags.recursion_desired = True; + nmb->header.nm_flags.trunc = False; + nmb->header.nm_flags.authoritative = True; + + nmb->header.qdcount = 0; + nmb->header.ancount = 1; + nmb->header.nscount = 0; + nmb->header.arcount = 0; + nmb->header.rcode = 0; + + bzero((char*)&nmb->question,sizeof(nmb->question)); + + nmb->answers = &answers; + bzero((char*)nmb->answers,sizeof(*nmb->answers)); + + nmb->answers->rr_name = *rr_name; + nmb->answers->rr_type = rr_type; + nmb->answers->rr_class = rr_class; + nmb->answers->ttl = ttl; + + if (data && len) + { + nmb->answers->rdlength = len; + memcpy(nmb->answers->rdata, data, len); + } + + p.packet_type = NMB_PACKET; + + debug_nmb_packet(&p); + + send_packet(&p); +} + + +/**************************************************************************** + initiate a netbios packet + ****************************************************************************/ +uint16 initiate_netbios_packet(int fd,int quest_type,char *name,int name_type, + int nb_flags,BOOL bcast,BOOL recurse,struct in_addr to_ip) +{ + struct packet_struct p; + struct nmb_packet *nmb = &p.packet.nmb; + struct res_rec additional_rec; + char *packet_type = "unknown"; + int opcode = -1; + + if (quest_type == NMB_STATUS) { packet_type = "nmb_status"; opcode = 0; } + if (quest_type == NMB_QUERY ) { packet_type = "nmb_query"; opcode = 0; } + if (quest_type == NMB_REG ) { packet_type = "nmb_reg"; opcode = 5; } + if (quest_type == NMB_REL ) { packet_type = "nmb_rel"; opcode = 6; } + + DEBUG(4,("initiating netbios packet: %s %s(%x) (bcast=%s) %s\n", + packet_type, name, name_type, BOOLSTR(bcast), inet_ntoa(to_ip))); + + if (opcode == -1) return False; + + bzero((char *)&p,sizeof(p)); + + if (!name_trn_id) name_trn_id = (time(NULL)%(unsigned)0x7FFF) + + (getpid()%(unsigned)100); + name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF; + + nmb->header.name_trn_id = name_trn_id; + nmb->header.opcode = opcode; + nmb->header.response = False; + nmb->header.nm_flags.bcast = bcast; + nmb->header.nm_flags.recursion_available = CanRecurse; + nmb->header.nm_flags.recursion_desired = recurse; + nmb->header.nm_flags.trunc = False; + nmb->header.nm_flags.authoritative = False; + nmb->header.rcode = 0; + nmb->header.qdcount = 1; + nmb->header.ancount = 0; + nmb->header.nscount = 0; + nmb->header.arcount = (quest_type==NMB_REG || quest_type==NMB_REL) ? 1 : 0; + + make_nmb_name(&nmb->question.question_name,name,name_type,scope); + + nmb->question.question_type = quest_type; + nmb->question.question_class = 0x1; + + if (quest_type == NMB_REG || quest_type == NMB_REL) + { + nmb->additional = &additional_rec; + bzero((char *)nmb->additional,sizeof(*nmb->additional)); + + nmb->additional->rr_name = nmb->question.question_name; + nmb->additional->rr_type = nmb->question.question_type; + nmb->additional->rr_class = nmb->question.question_class; + + nmb->additional->ttl = quest_type == NMB_REG ? lp_max_ttl() : 0; + nmb->additional->rdlength = 6; + nmb->additional->rdata[0] = nb_flags; + putip(&nmb->additional->rdata[2],(char *)&myip); + } + + p.ip = to_ip; + p.port = NMB_PORT; + p.fd = fd; + p.timestamp = time(NULL); + p.packet_type = NMB_PACKET; + + if (!send_packet(&p)) + return(0); + + return(name_trn_id); +} + + +void send_name_reg(void) +{ + struct packet_struct p; + struct nmb_packet *nmb = &p.packet.nmb; + int rcode = 0; + + nmb->header.opcode = 5; + nmb->header.response = True; + nmb->header.nm_flags.bcast = False; + nmb->header.nm_flags.recursion_available = CanRecurse; + nmb->header.nm_flags.recursion_desired = CanRecurse; + nmb->header.nm_flags.trunc = False; + nmb->header.nm_flags.authoritative = True; + nmb->header.qdcount = 0; + nmb->header.ancount = 1; + nmb->header.nscount = 0; + nmb->header.arcount = 0; + nmb->header.rcode = rcode; + + send_packet(&p); +} + + +/**************************************************************************** + wrapper function to override a broadcast message and send it to the WINS + name server instead, if it exists. if wins is false, and there has been no + WINS server specified, the packet will NOT be sent. + ****************************************************************************/ +void queue_netbios_pkt_wins(int fd,int quest_type,enum cmd_type cmd, + char *name,int name_type,int nb_flags, + BOOL bcast,BOOL recurse,struct in_addr to_ip) +{ + if ((!lp_wins_support()) && (*lp_wins_server())) + { + /* samba is not a WINS server, and we are using a WINS server */ + struct in_addr wins_ip; + wins_ip = *interpret_addr2(lp_wins_server()); + + if (!zero_ip(wins_ip)) + { + bcast = False; + to_ip = wins_ip; + } + else + { + /* oops. smb.conf's wins server parameter MUST be a host_name + or an ip_address. */ + DEBUG(0,("invalid smb.conf parameter 'wins server'\n")); + } + } + + if (zero_ip(to_ip)) return; + + queue_netbios_packet(fd, quest_type, cmd, + name, name_type, nb_flags, + bcast, recurse, to_ip); +} + +/**************************************************************************** + create a name query response record + **************************************************************************/ +static struct name_response_record *make_name_query_record( + enum cmd_type cmd,int id,int fd, + char *name,int type, + BOOL bcast,BOOL recurse, + struct in_addr ip) +{ + struct name_response_record *n; + + if (!name || !name[0]) return NULL; + + if (!(n = (struct name_response_record *)malloc(sizeof(*n)))) + return(NULL); + + n->response_id = id; + n->cmd_type = cmd; + n->fd = fd; + make_nmb_name(&n->name, name, type, scope); + n->bcast = bcast; + n->recurse = recurse; + n->to_ip = ip; + n->start_time = time(NULL); + n->num_msgs = 0; + + return n; +} + + +/**************************************************************************** + initiate a netbios name query to find someone's or someones' IP + this is intended to be used (not exclusively) for broadcasting to + master browsers (WORKGROUP(1d or 1b) or __MSBROWSE__(1)) to get + complete lists across a wide area network + ****************************************************************************/ +void queue_netbios_packet(int fd,int quest_type,enum cmd_type cmd,char *name, + int name_type,int nb_flags,BOOL bcast,BOOL recurse, + struct in_addr to_ip) +{ + uint16 id = initiate_netbios_packet(fd, quest_type, name, name_type, + nb_flags, bcast, recurse, to_ip); + struct name_response_record *n; + + if (id == 0) return; + + if ((n = make_name_query_record(cmd,id,fd,name,name_type,bcast,recurse,to_ip))) + { + add_response_record(n); + } +} + + +/**************************************************************************** + find a response in the name query response list + **************************************************************************/ +struct name_response_record *find_name_query(uint16 id) +{ + struct name_response_record *n; + + for (n = nameresponselist; n; n = n->next) + { + if (n->response_id == id) { + return n; + } + } + + return NULL; +} + + +/******************************************************************* + the global packet linked-list. incoming entries are added to the + end of this list. it is supposed to remain fairly short so we + won't bother with an end pointer. + ******************************************************************/ +static struct packet_struct *packet_queue = NULL; + +/******************************************************************* + queue a packet into the packet queue + ******************************************************************/ +void queue_packet(struct packet_struct *packet) +{ + struct packet_struct *p; + + if (!packet_queue) { + packet->prev = NULL; + packet->next = NULL; + packet_queue = packet; + return; + } + + /* find the bottom */ + for (p=packet_queue;p->next;p=p->next) ; + + p->next = packet; + packet->next = NULL; + packet->prev = p; +} + +/******************************************************************* + run elements off the packet queue till its empty + ******************************************************************/ +void run_packet_queue() +{ + struct packet_struct *p; + + while ((p=packet_queue)) + { + switch (p->packet_type) + { + case NMB_PACKET: + process_nmb(p); + break; + + case DGRAM_PACKET: + process_dgram(p); + break; + } + + packet_queue = packet_queue->next; + if (packet_queue) packet_queue->prev = NULL; + free_packet(p); + } +} + +/**************************************************************************** + listens for NMB or DGRAM packets, and queues them + ***************************************************************************/ +void listen_for_packets(BOOL run_election) +{ + fd_set fds; + int selrtn; + struct timeval timeout; + + FD_ZERO(&fds); + FD_SET(ClientNMB,&fds); + FD_SET(ClientDGRAM,&fds); + + /* during elections we need to send election packets at one + second intervals */ + + timeout.tv_sec = run_election ? 1 : NMBD_SELECT_LOOP; + timeout.tv_usec = 0; + + selrtn = sys_select(&fds,&timeout); + + if (FD_ISSET(ClientNMB,&fds)) + { + struct packet_struct *packet = read_packet(ClientNMB, NMB_PACKET); + if (packet) queue_packet(packet); + } + + if (FD_ISSET(ClientDGRAM,&fds)) + { + struct packet_struct *packet = read_packet(ClientDGRAM, DGRAM_PACKET); + if (packet) queue_packet(packet); + } +} + + + +/**************************************************************************** +interpret a node status response. this is pretty hacked: we need two bits of +info. a) the name of the workgroup b) the name of the server. it will also +add all the names it finds into the namelist. +****************************************************************************/ +BOOL interpret_node_status(char *p, struct nmb_name *name,int t, + char *serv_name, struct in_addr ip) +{ + int level = t==0x20 ? 4 : 0; + int numnames = CVAL(p,0); + BOOL found = False; + + DEBUG(level,("received %d names\n",numnames)); + + p += 1; + + if (serv_name) *serv_name = 0; + + while (numnames--) + { + char qname[17]; + int type; + fstring flags; + int nb_flags; + + BOOL group = False; + BOOL add = False; + + *flags = 0; + + StrnCpy(qname,p,15); + type = CVAL(p,15); + nb_flags = p[16]; + + p += 18; + + if (NAME_GROUP (nb_flags)) { strcat(flags,"<GROUP> "); group=True;} + if (NAME_BFLAG (nb_flags)) { strcat(flags,"B "); } + if (NAME_PFLAG (nb_flags)) { strcat(flags,"P "); } + if (NAME_MFLAG (nb_flags)) { strcat(flags,"M "); } + if (NAME__FLAG (nb_flags)) { strcat(flags,"_ "); } + if (NAME_DEREG (nb_flags)) { strcat(flags,"<DEREGISTERING> "); } + if (NAME_CONFLICT (nb_flags)) { strcat(flags,"<CONFLICT> "); add=True;} + if (NAME_ACTIVE (nb_flags)) { strcat(flags,"<ACTIVE> "); add=True; } + if (NAME_PERMANENT(nb_flags)) { strcat(flags,"<PERMANENT> "); add=True;} + + /* might as well update our namelist while we're at it */ + if (add) + { + struct in_addr nameip; + enum name_source src; + + if (ip_equal(ip, myip)) + { + nameip = ipzero; + src = SELF; + } + else + { + nameip = ip; + src = STATUS_QUERY; + } + add_netbios_entry(qname,type,nb_flags,2*60*60,src,nameip); + } + + /* we want the server name */ + if (serv_name && !*serv_name && !group && t == 0) + { + StrnCpy(serv_name,qname,15); + serv_name[15] = 0; + } + + /* looking for a name and type? */ + if (name && !found && (t == type)) + { + /* take a guess at some of the name types we're going to ask for. + evaluate whether they are group names or no... */ + if (((t == 0x1b || t == 0x1d ) && !group) || + ((t == 0x20 || t == 0x1c || t == 0x1e) && group)) + { + found = True; + make_nmb_name(name,qname,type,scope); + } + } + + DEBUG(level,("\t%s(0x%x)\t%s\n",qname,type,flags)); + } + DEBUG(level,("num_good_sends=%d num_good_receives=%d\n", + IVAL(p,20),IVAL(p,24))); + return found; +} + + +/**************************************************************************** + construct and send a netbios DGRAM + + Note that this currently sends all answers to port 138. thats the + wrong things to do! I should send to the requestors port. XXX + **************************************************************************/ +BOOL send_mailslot_reply(char *mailslot,int fd,char *buf,int len,char *srcname, + char *dstname,int src_type,int dest_type, + struct in_addr dest_ip,struct in_addr src_ip) +{ + struct packet_struct p; + struct dgram_packet *dgram = &p.packet.dgram; + char *ptr,*p2; + char tmp[4]; + + bzero((char *)&p,sizeof(p)); + + dgram->header.msg_type = 0x11; /* DIRECT GROUP DATAGRAM */ + dgram->header.flags.node_type = M_NODE; + dgram->header.flags.first = True; + dgram->header.flags.more = False; + dgram->header.dgm_id = name_trn_id++; + dgram->header.source_ip = src_ip; + dgram->header.source_port = DGRAM_PORT; + dgram->header.dgm_length = 0; /* let build_dgram() handle this */ + dgram->header.packet_offset = 0; + + make_nmb_name(&dgram->source_name,srcname,src_type,scope); + make_nmb_name(&dgram->dest_name,dstname,dest_type,scope); + + ptr = &dgram->data[0]; + + /* now setup the smb part */ + ptr -= 4; /* XXX ugliness because of handling of tcp SMB length */ + memcpy(tmp,ptr,4); + set_message(ptr,17,17 + len,True); + memcpy(ptr,tmp,4); + + CVAL(ptr,smb_com) = SMBtrans; + SSVAL(ptr,smb_vwv1,len); + SSVAL(ptr,smb_vwv11,len); + SSVAL(ptr,smb_vwv12,70 + strlen(mailslot)); + SSVAL(ptr,smb_vwv13,3); + SSVAL(ptr,smb_vwv14,1); + SSVAL(ptr,smb_vwv15,1); + SSVAL(ptr,smb_vwv16,2); + p2 = smb_buf(ptr); + strcpy(p2,mailslot); + p2 = skip_string(p2,1); + + memcpy(p2,buf,len); + p2 += len; + + dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length */ + + p.ip = dest_ip; + p.port = DGRAM_PORT; + p.fd = fd; + p.timestamp = time(NULL); + p.packet_type = DGRAM_PACKET; + + return(send_packet(&p)); +} + + diff --git a/source/nameserv.c b/source/nameserv.c index b64a9345726..4cd9b099f00 100644 --- a/source/nameserv.c +++ b/source/nameserv.c @@ -18,202 +18,32 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + Revision History: + + 14 jan 96: lkcl@pires.co.uk + added multiple workgroup domain master support + */ #include "includes.h" #include "loadparm.h" -#include "nameserv.h" +#include "localnet.h" -static void queue_packet(struct packet_struct *packet); -void process(void); -static void dump_names(void); -static void announce_request(char *group); -void sync_browse_lists(char *name,int name_type,char *myname, - char *domain,struct in_addr ip); +enum name_search { FIND_SELF, FIND_GLOBAL }; extern int DEBUGLEVEL; -extern pstring debugf; -pstring servicesf = CONFIGFILE; - extern pstring scope; - extern BOOL CanRecurse; +extern pstring myname; +extern struct in_addr ipzero; -extern struct in_addr myip; -extern struct in_addr bcast_ip; -extern struct in_addr Netmask; -extern pstring myhostname; -static pstring host_file; -static pstring myname=""; - -static int ClientNMB= -1; -static int ClientDGRAM= -1; - -static BOOL needannounce=True; - -/* this is our name database */ -static struct name_record *namelist = NULL; - -/* list of servers to be returned by NetServerEnum */ -static struct server_record *serverlist = NULL; - -/* this is the domain list. For the moment we will assume that our - primary domain is the first one listed in this list */ -static struct domain_record *domainlist = NULL; - -/* are we running as a daemon ? */ -static BOOL is_daemon = False; - -/* machine comment for host announcements */ -static pstring ServerComment=""; - -static BOOL got_bcast = False; -static BOOL got_myip = False; -static BOOL got_nmask = False; - -static BOOL updatedlists = False; -static int updatecount=0; - -/* what server type are we currently */ -static int ServerType = -SV_TYPE_WORKSTATION | SV_TYPE_SERVER | SV_TYPE_TIME_SOURCE | -SV_TYPE_SERVER_UNIX | -SV_TYPE_PRINTQ_SERVER | SV_TYPE_POTENTIAL_BROWSER; - -/* here are my election parameters */ - -/* NTAS uses 2, NT uses 1, WfWg uses 0 */ -#define MAINTAIN_LIST 1 -#define ELECTION_VERSION 1 - -static BOOL RunningElection = False; -static BOOL needelection = False; -static int ElectionCount = 0; -static int StartupTime =0; - - -/* WfWg uses 01040b01 */ -/* Win95 uses 01041501 */ -/* NTAS uses ?? */ -static uint32 ElectionCriterion = (MAINTAIN_LIST<<1)|(ELECTION_VERSION<<8); - -/* we currently support being the master for just one group. Being the - master for more than one group might be tricky as NetServerEnum is - often asked for a list without naming the group */ -static fstring PrimaryGroup=""; - -#define AM_MASTER (PrimaryGroup[0] && (ServerType & SV_TYPE_MASTER_BROWSER)) - -#define MSBROWSE "\001\002__MSBROWSE__\002" +/* netbios names database */ +struct name_record *namelist; #define GET_TTL(ttl) ((ttl)?MIN(ttl,lp_max_ttl()):lp_max_ttl()) -#define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE" - -/**************************************************************************** -catch a sighup -****************************************************************************/ -static int sig_hup() -{ - BlockSignals(True); - - DEBUG(0,("Got SIGHUP (reload not implemented)\n")); - dump_names(); - reload_services(True); - - BlockSignals(False); -#ifndef DONT_REINSTALL_SIG - signal(SIGHUP,SIGNAL_CAST sig_hup); -#endif - return(0); -} - -/**************************************************************************** -catch a sigpipe -****************************************************************************/ -static int sig_pipe() -{ - BlockSignals(True); - - DEBUG(0,("Got SIGPIPE\n")); - if (!is_daemon) - exit(1); - BlockSignals(False); - return(0); -} - -#if DUMP_CORE -/******************************************************************* -prepare to dump a core file - carefully! -********************************************************************/ -static BOOL dump_core(void) -{ - char *p; - pstring dname; - strcpy(dname,debugf); - if ((p=strrchr(dname,'/'))) *p=0; - strcat(dname,"/corefiles"); - mkdir(dname,0700); - sys_chown(dname,getuid(),getgid()); - chmod(dname,0700); - if (chdir(dname)) return(False); - umask(~(0700)); - -#ifndef NO_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",rlp.rlim_cur,rlp.rlim_max)); - } -#endif -#endif - - - DEBUG(0,("Dumping core in %s\n",dname)); - return(True); -} -#endif - - -/**************************************************************************** -possibly continue after a fault -****************************************************************************/ -static void fault_continue(void) -{ - static int errcount=1; - - errcount--; - - if (is_daemon && errcount) - process(); - -#if DUMP_CORE - if (dump_core()) return; -#endif - - return; -} - - -/******************************************************************* - wrapper to get the DC - ******************************************************************/ -static char *domain_controller(void) -{ - char *dc = lp_domain_controller(); - /* so many people mistake this for a bool that we need to handle it. sigh. */ - if (!*dc || strequal(dc,"yes") || strequal(dc,"true")) - strcpy(dc,myname); - return(dc); -} - - /**************************************************************************** true if two netbios names are equal @@ -232,7 +62,8 @@ static void add_name(struct name_record *n) { struct name_record *n2; - if (!namelist) { + if (!namelist) + { namelist = n; n->prev = NULL; n->next = NULL; @@ -247,57 +78,17 @@ static void add_name(struct name_record *n) } /**************************************************************************** - add a domain into the list - **************************************************************************/ -static void add_domain(struct domain_record *d) -{ - struct domain_record *d2; - - if (!domainlist) { - domainlist = d; - d->prev = NULL; - d->next = NULL; - return; - } - - for (d2 = domainlist; d2->next; d2 = d2->next) ; - - d2->next = d; - d->next = NULL; - d->prev = d2; -} - - -/**************************************************************************** - add a server into the list - **************************************************************************/ -static void add_server(struct server_record *s) -{ - struct server_record *s2; - - if (!serverlist) { - serverlist = s; - s->prev = NULL; - s->next = NULL; - return; - } - - for (s2 = serverlist; s2->next; s2 = s2->next) ; - - s2->next = s; - s->next = NULL; - s->prev = s2; -} - -/**************************************************************************** remove a name from the namelist. The pointer must be an element just retrieved **************************************************************************/ -static void remove_name(struct name_record *n) +void remove_name(struct name_record *n) { struct name_record *nlist = namelist; + while (nlist && nlist != n) nlist = nlist->next; - if (nlist) { + + if (nlist) + { if (nlist->next) nlist->next->prev = nlist->prev; if (nlist->prev) nlist->prev->next = nlist->next; free(nlist); @@ -305,48 +96,80 @@ static void remove_name(struct name_record *n) } /**************************************************************************** - find a name in the namelist + find a name in the domain database namelist + search can be: + FIND_SELF - look for names the samba server has added for itself + FIND_GLOBAL - the name can be anyone. first look on the client's + subnet, then the server's subnet, then all subnets. **************************************************************************/ -static struct name_record *find_name(struct nmb_name *n) +static struct name_record *find_name_search(struct nmb_name *name, enum name_search search, + struct in_addr ip) { - struct name_record *ret; - for (ret = namelist; ret; ret = ret->next) - if (name_equal(&ret->name,n)) return(ret); + struct name_record *ret; + + /* any number of winpopup names can be added. must search by ip as well */ + if (name->name_type != 0x3) ip = ipzero; - return(NULL); + for (ret = namelist; ret; ret = ret->next) + { + if (name_equal(&ret->name,name)) + { + /* self search: self names only */ + if (search == FIND_SELF && ret->source != SELF) continue; + + if (zero_ip(ip) || ip_equal(ip, ret->ip)) + { + return ret; + } + } + } + + return NULL; } + /**************************************************************************** dump a copy of the name table **************************************************************************/ -static void dump_names(void) +void dump_names(void) { - time_t t = time(NULL); - struct name_record *n; - struct domain_record *d; + struct name_record *n; + time_t t = time(NULL); - DEBUG(3,("Dump of local name table:\n")); + DEBUG(3,("Dump of local name table:\n")); + + for (n = namelist; n; n = n->next) + { + DEBUG(3,("%s %s TTL=%d NBFLAGS=%2x\n", + namestr(&n->name), + inet_ntoa(n->ip), + n->death_time?n->death_time-t:0, + n->nb_flags)); + } +} - for (n = namelist; n; n = n->next) { - DEBUG(3,("%s %s TTL=%d Unique=%s\n", - namestr(&n->name), - inet_ntoa(n->ip), - n->death_time?n->death_time-t:0, - BOOLSTR(n->unique))); - } - DEBUG(3,("\nDump of domain list:\n")); - for (d = domainlist; d; d = d->next) - DEBUG(3,("%s %s\n",d->name,inet_ntoa(d->bcast_ip))); +/**************************************************************************** + remove an entry from the name list + ****************************************************************************/ +void remove_netbios_name(char *name,int type, enum name_source source, + struct in_addr ip) +{ + struct nmb_name nn; + struct name_record *n; + + make_nmb_name(&nn, name, type, scope); + n = find_name_search(&nn, FIND_GLOBAL, ip); + + if (n && n->source == source) remove_name(n); } /**************************************************************************** - add a host entry to the name list + add an entry to the name list ****************************************************************************/ -static struct name_record *add_host_entry(char *name,int type,BOOL unique,int ttl, - enum name_source source, - struct in_addr ip) +struct name_record *add_netbios_entry(char *name, int type, int nb_flags, int ttl, + enum name_source source, struct in_addr ip) { struct name_record *n; struct name_record *n2=NULL; @@ -357,1967 +180,878 @@ static struct name_record *add_host_entry(char *name,int type,BOOL unique,int tt bzero((char *)n,sizeof(*n)); make_nmb_name(&n->name,name,type,scope); - if ((n2=find_name(&n->name))) { + + if ((n2 = find_name_search(&n->name, FIND_GLOBAL, ip))) + { free(n); n = n2; } if (ttl) n->death_time = time(NULL)+ttl*3; n->ip = ip; - n->unique = unique; + n->nb_flags = nb_flags; n->source = source; if (!n2) add_name(n); - DEBUG(3,("Added host entry %s at %s ttl=%d unique=%s\n", - namestr(&n->name),inet_ntoa(ip),ttl,BOOLSTR(unique))); + DEBUG(3,("Added netbios name %s at %s ttl=%d nb_flags=%2x\n", + namestr(&n->name),inet_ntoa(ip),ttl,nb_flags)); return(n); } /**************************************************************************** - add a domain entry + remove an entry from the name list ****************************************************************************/ -static struct domain_record *add_domain_entry(char *name,struct in_addr ip) +void remove_name_entry(char *name,int type) { - struct domain_record *d; - - d = (struct domain_record *)malloc(sizeof(*d)); - - if (!d) return(NULL); - - bzero((char *)d,sizeof(*d)); - - if (zero_ip(ip)) ip = bcast_ip; - - StrnCpy(d->name,name,sizeof(d->name)-1); - d->bcast_ip = ip; - - if (!PrimaryGroup[0] && ip_equal(bcast_ip,ip) && name[0] != '*') { - strcpy(PrimaryGroup,name); - strupper(PrimaryGroup); - DEBUG(3,("Setting primary group to %s (%s)\n",PrimaryGroup,inet_ntoa(ip))); - } - - add_domain(d); - - ip = *interpret_addr2("255.255.255.255"); - if (name[0] != '*') add_host_entry(name,0x1e,False,0,SELF,ip); - - DEBUG(3,("Added domain entry %s at %s\n", - name,inet_ntoa(ip))); + if (lp_wins_support()) + { + /* we are a WINS server. */ + remove_netbios_name(name,type,SELF,myip); + } + else + { + struct in_addr ip; + ip = ipzero; - return(d); + queue_netbios_pkt_wins(ClientNMB,NMB_REL,NAME_RELEASE, + name, type, 0, + False, True, ip); + } } + /**************************************************************************** - add a server entry + add an entry to the name list ****************************************************************************/ -struct server_record *add_server_entry(char *name,int servertype, - int ttl,char *comment,BOOL replace) +void add_name_entry(char *name,int type,int nb_flags) { - BOOL newentry=False; - struct server_record *s; - - for (s = serverlist; s; s = s->next) - if (strequal(name,s->name)) break; - - if (s && !replace) { - DEBUG(4,("Not replacing %s\n",name)); - return(s); - } - - updatedlists=True; - - if (!s) { - newentry = True; - s = (struct server_record *)malloc(sizeof(*s)); - - if (!s) return(NULL); - - bzero((char *)s,sizeof(*s)); - } - - /* update the entry */ - StrnCpy(s->name,name,sizeof(s->name)-1); - StrnCpy(s->comment,comment,sizeof(s->comment)-1); - s->servertype = servertype; - s->death_time = ttl?time(NULL)+ttl*3:0; - strupper(s->name); - if (s->servertype & SV_TYPE_DOMAIN_ENUM) strupper(s->comment); - - if (!newentry) return(s); - - add_server(s); - - if (newentry) { - DEBUG(3,("Added server entry %s of type %x (%s)\n", - name,servertype,comment)); - } else { - DEBUG(3,("Updated server entry %s of type %x (%s)\n", - name,servertype,comment)); - } + if (lp_wins_support()) + { + /* we are a WINS server. */ + add_netbios_entry(name,type,nb_flags,0,SELF,myip); + } + else + { + struct in_addr ip; + ip = ipzero; - return(s); + queue_netbios_pkt_wins(ClientNMB,NMB_REG,NAME_REGISTER, + name, type, nb_flags, + False, True, ip); + } } /**************************************************************************** add the magic samba names, useful for finding samba servers **************************************************************************/ -static void add_my_names(void) +void add_my_names(void) { - struct in_addr ip; - - ip = *interpret_addr2("0.0.0.0"); - - add_host_entry(myname,0x20,True,0,SELF,ip); - add_host_entry(myname,0x0,True,0,SELF,ip); - add_host_entry(myname,0x1f,True,0,SELF,ip); /* used for chat?? */ - add_host_entry(myname,0x3,True,0,SELF,ip); /* used for winpopup */ - - if (!domainlist) - add_domain_entry(lp_workgroup(),bcast_ip); - add_server_entry(myname, - ServerType, - 0,ServerComment,True); - - add_host_entry("__SAMBA__",0x20,True,0,SELF,ip); - add_host_entry("__SAMBA__",0x0,True,0,SELF,ip); - - if (lp_preferred_master()) { - DEBUG(3,("Preferred master startup\n")); - needelection = True; - ElectionCriterion |= (1<<3); - } - - ElectionCriterion |= (lp_os_level() << 24); -} + struct in_addr ip; - -/******************************************************************* - write out browse.dat - ******************************************************************/ -static void write_browse_list(void) -{ - struct server_record *s; - pstring fname,fnamenew; - FILE *f; - - updatecount++; - - strcpy(fname,lp_lockdir()); - trim_string(fname,NULL,"/"); - strcat(fname,"/"); - strcat(fname,SERVER_LIST); - strcpy(fnamenew,fname); - strcat(fnamenew,"."); - - f = fopen(fnamenew,"w"); - - if (!f) { - DEBUG(4,("Can't open %s - %s\n",fnamenew,strerror(errno))); - return; - } - - for (s=serverlist; s ; s = s->next) { - /* don't list domains I don't have a master for */ - if ((s->servertype & SV_TYPE_DOMAIN_ENUM) && !s->comment[0]) continue; + ip = ipzero; - fprintf(f,"\"%s\"\t%08x\t\"%s\"\n",s->name,s->servertype,s->comment); - } - - - fclose(f); - chmod(fnamenew,0644); - /* unlink(fname); */ - rename(fnamenew,fname); - DEBUG(3,("Wrote browse list %s\n",fname)); + add_netbios_entry(myname,0x20,NB_ACTIVE,0,SELF,ip); + add_netbios_entry(myname,0x03,NB_ACTIVE,0,SELF,ip); + add_netbios_entry(myname,0x00,NB_ACTIVE,0,SELF,ip); + add_netbios_entry(myname,0x1f,NB_ACTIVE,0,SELF,ip); + add_netbios_entry("*",0x01,NB_ACTIVE,0,SELF,ip); + add_netbios_entry("__SAMBA__",0x20,NB_ACTIVE,0,SELF,ip); + add_netbios_entry("__SAMBA__",0x00,NB_ACTIVE,0,SELF,ip); + + if (lp_wins_support()) { + add_netbios_entry(inet_ntoa(myip),0x01,NB_ACTIVE,0,SELF,ip); /* nt as? */ + } } /******************************************************************* - expire old names in the namelist and serverlist + expires old names in the namelist ******************************************************************/ -static void expire_names(void) +void expire_names(time_t t) { - static time_t lastrun=0; - time_t t = time(NULL); - struct name_record *n; - struct name_record *next; - struct server_record *s; - struct server_record *nexts; - - if (!lastrun) lastrun = t; - if (t < lastrun + 5) return; - lastrun = t; - - /* expire old names */ - for (n = namelist; n; n = next) { - if (n->death_time && n->death_time < t) { - DEBUG(3,("Removing dead name %s\n", - namestr(&n->name))); - next = n->next; - if (n->prev) n->prev->next = n->next; - if (n->next) n->next->prev = n->prev; - if (namelist == n) namelist = n->next; - free(n); - } else { - next = n->next; - } - } + struct name_record *n; + struct name_record *next; - /* expire old entries in the serverlist */ - for (s = serverlist; s; s = nexts) { - if (s->death_time && s->death_time < t) { - DEBUG(3,("Removing dead server %s\n",s->name)); - updatedlists = True; - nexts = s->next; - if (s->prev) s->prev->next = s->next; - if (s->next) s->next->prev = s->prev; - if (serverlist == s) serverlist = s->next; - free(s); - } else { - nexts = s->next; - } - } -} + /* expire old names */ + for (n = namelist; n; n = next) + { + if (n->death_time && n->death_time < t) + { + DEBUG(3,("Removing dead name %s\n", namestr(&n->name))); + next = n->next; -/******************************************************************* - delete old names from the namelist - ******************************************************************/ -static void housekeeping(void) -{ - time_t t = time(NULL); + if (n->prev) n->prev->next = n->next; + if (n->next) n->next->prev = n->prev; - expire_names(); + if (namelist == n) namelist = n->next; - /* write out the browse.dat database for smbd to get */ - if (updatedlists) { - write_browse_list(); - updatedlists = False; - } - - { - /* occasionally check to see if the master browser is around */ - static time_t lastrun=0; - if (!lastrun) lastrun = t; - if (t < lastrun + 5*60) return; - lastrun = t; - - if (!AM_MASTER && PrimaryGroup[0] && - !name_query(ClientNMB,PrimaryGroup,0x1d,True,False, - bcast_ip,NULL,queue_packet)) { - DEBUG(2,("Forcing election on %s\n",PrimaryGroup)); - needelection = True; - } - } + free(n); + } + else + { + next = n->next; + } + } } /**************************************************************************** - reload the services file - **************************************************************************/ -BOOL reload_services(BOOL test) +response for a reg release received +**************************************************************************/ +void response_name_release(struct packet_struct *p) { - BOOL ret; - extern fstring remote_machine; + struct nmb_packet *nmb = &p->packet.nmb; + char *name = nmb->question.question_name.name; + int type = nmb->question.question_name.name_type; - strcpy(remote_machine,"nmbd"); + DEBUG(4,("response name release received\n")); - if (lp_loaded()) - { - pstring fname; - strcpy(fname,lp_configfile()); - if (file_exist(fname,NULL) && !strcsequal(fname,servicesf)) + if (nmb->header.rcode == 0 && nmb->answers->rdata) { - strcpy(servicesf,fname); - test = False; - } - } - - if (test && !lp_file_list_changed()) - return(True); - - ret = lp_load(servicesf,True); + struct in_addr found_ip; + putip((char*)&found_ip,&nmb->answers->rdata[2]); - /* perhaps the config filename is now set */ - if (!test) - reload_services(True); - - return(ret); + if (ip_equal(found_ip, myip)) + { + remove_netbios_name(name,type,SELF,found_ip); + } + } + else + { + DEBUG(1,("name registration for %s rejected!\n", + namestr(&nmb->question.question_name))); + } } - /**************************************************************************** -load a netbios hosts file +reply to a name release ****************************************************************************/ -static void load_hosts_file(char *fname) +void reply_name_release(struct packet_struct *p) { - FILE *f = fopen(fname,"r"); - pstring line; - if (!f) { - DEBUG(2,("Can't open lmhosts file %s\n",fname)); - return; - } - - while (!feof(f)) - { - if (!fgets_slash(line,sizeof(pstring),f)) continue; - - if (*line == '#') continue; - - { - BOOL group=False; - string ip,name,flags,extra; - char *ptr; - int count = 0; - struct in_addr ipaddr; - enum name_source source = LMHOSTS; - - *ip = *name = *flags = *extra = 0; - - ptr = line; - - if (next_token(&ptr,ip,NULL)) ++count; - if (next_token(&ptr,name,NULL)) ++count; - if (next_token(&ptr,flags,NULL)) ++count; - if (next_token(&ptr,extra,NULL)) ++count; - - if (count <= 0) continue; + struct nmb_packet *nmb = &p->packet.nmb; + struct in_addr ip; + int rcode=0; + int opcode = nmb->header.opcode; + int nb_flags = nmb->additional->rdata[0]; + BOOL bcast = nmb->header.nm_flags.bcast; + struct name_record *n; + char rdata[6]; + + putip((char *)&ip,&nmb->additional->rdata[2]); + + DEBUG(3,("Name release on name %s rcode=%d\n", + namestr(&nmb->question.question_name),rcode)); - if (count > 0 && count < 2) - { - DEBUG(0,("Ill formed hosts line [%s]\n",line)); - continue; - } + n = find_name_search(&nmb->question.question_name, FIND_GLOBAL, ip); - if (strchr(flags,'G') || strchr(flags,'S')) - group = True; + /* XXXX under what conditions should we reject the removal?? */ + if (n && n->nb_flags == nb_flags && ip_equal(n->ip,ip)) + { + /* success = True; + rcode = 6; */ - if (strchr(flags,'M') && !group) { - source = SELF; - strcpy(myname,name); + remove_name(n); + n = NULL; } - ipaddr = *interpret_addr2(ip); + if (bcast) return; - if (group) { - add_domain_entry(name,ipaddr); - } else { - add_host_entry(name,0x20,True,0,source,ipaddr); + /*if (success)*/ + { + rdata[0] = nb_flags; + rdata[1] = 0; + putip(&rdata[2],(char *)&ip); } - } - } - - fclose(f); -} - -/******************************************************************* - check if 2 IPs are on the same net - we will assume the local netmask, although this could be wrong XXXX - ******************************************************************/ -static BOOL same_net(struct in_addr ip1,struct in_addr ip2) -{ - unsigned long net1,net2,nmask; - - nmask = ntohl(Netmask.s_addr); - net1 = ntohl(ip1.s_addr); - net2 = ntohl(ip2.s_addr); - - return((net1 & nmask) == (net2 & nmask)); -} - -/**************************************************************************** - send an election packet - **************************************************************************/ -static void send_election(char *group,uint32 criterion,int timeup,char *name) -{ - pstring outbuf; - char *p; - - DEBUG(2,("Sending election to %s for workgroup %s\n", - inet_ntoa(bcast_ip),group)); - - bzero(outbuf,sizeof(outbuf)); - p = outbuf; - CVAL(p,0) = 8; /* election */ - p++; - - CVAL(p,0) = ELECTION_VERSION; - SIVAL(p,1,criterion); - SIVAL(p,5,timeup*1000); /* ms - despite the spec */ - p += 13; - strcpy(p,name); - strupper(p); - p = skip_string(p,1); - - send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), - name,group,0,0x1e,bcast_ip,myip); -} - - -/**************************************************************************** - send a backup list response - **************************************************************************/ -static void send_backup_list(char *name,int token,struct nmb_name *to, - struct in_addr ip) -{ - pstring outbuf; - char *p; - - DEBUG(2,("Sending backup list to %s for workgroup %s\n", - inet_ntoa(ip),PrimaryGroup)); - - bzero(outbuf,sizeof(outbuf)); - p = outbuf; - CVAL(p,0) = 10; /* backup list response */ - p++; - - CVAL(p,0) = 1; /* count */ - SIVAL(p,1,token); - p += 5; - strcpy(p,name); - strupper(p); - p = skip_string(p,1) + 1; - - send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), - myname,to->name,0,to->name_type,ip,myip); -} - - -/******************************************************************* - become the master browser - ******************************************************************/ -static void become_master(void) -{ - uint32 domain_type = SV_TYPE_DOMAIN_ENUM | SV_TYPE_SERVER_UNIX; - DEBUG(2,("Becoming master for %s\n",PrimaryGroup)); - - ServerType |= SV_TYPE_MASTER_BROWSER; - ServerType |= SV_TYPE_BACKUP_BROWSER; - ElectionCriterion |= 0x5; - - add_host_entry(PrimaryGroup,0x1d,True,0,SELF,myip); - add_host_entry(PrimaryGroup,0x0,False,0,SELF,myip); - add_host_entry(MSBROWSE,1,False,0,SELF,myip); - - if (lp_domain_master()) { - add_host_entry(myname,0x1b,True,0,SELF,myip); - add_host_entry(PrimaryGroup,0x1b,True,0,SELF,myip); - add_host_entry(PrimaryGroup,0x1c,False,0,SELF,myip); - ServerType |= SV_TYPE_DOMAIN_MASTER; - if (lp_domain_logons()) { - ServerType |= SV_TYPE_DOMAIN_CTRL; - ServerType |= SV_TYPE_DOMAIN_MEMBER; - domain_type |= SV_TYPE_DOMAIN_CTRL; - } - } - - add_server_entry(PrimaryGroup,domain_type,0,myname,True); - add_server_entry(myname,ServerType,0,ServerComment,True); - announce_request(PrimaryGroup); - - needannounce = True; -} - - -/******************************************************************* - unbecome the master browser - ******************************************************************/ -static void become_nonmaster(void) -{ - struct name_record *n; - struct nmb_name nn; - - DEBUG(2,("Becoming non-master for %s\n",PrimaryGroup)); - - ServerType &= ~SV_TYPE_MASTER_BROWSER; - ServerType &= ~SV_TYPE_DOMAIN_CTRL; - ServerType &= ~SV_TYPE_DOMAIN_MASTER; - - ElectionCriterion &= ~0x4; - - make_nmb_name(&nn,PrimaryGroup,0x1d,scope); - n = find_name(&nn); - if (n && n->source == SELF) remove_name(n); - - make_nmb_name(&nn,PrimaryGroup,0x1b,scope); - n = find_name(&nn); - if (n && n->source == SELF) remove_name(n); - - make_nmb_name(&nn,MSBROWSE,1,scope); - n = find_name(&nn); - if (n && n->source == SELF) remove_name(n); -} - - -/******************************************************************* - run the election - ******************************************************************/ -static void run_election(void) -{ - time_t t = time(NULL); - static time_t lastime = 0; - - if (!PrimaryGroup[0] || !RunningElection) return; - - /* send election packets once a second */ - if (lastime && - t-lastime <= 0) return; - - lastime = t; - - send_election(PrimaryGroup,ElectionCriterion,t-StartupTime,myname); - - if (ElectionCount++ < 4) return; - - /* I won! now what :-) */ - RunningElection = False; - DEBUG(2,(">>> Won election on %s <<<\n",PrimaryGroup)); - become_master(); + /* Send a NAME RELEASE RESPONSE */ + reply_netbios_packet(p,nmb->header.name_trn_id,rcode,opcode, + &nmb->question.question_name, + nmb->question.question_type, + nmb->question.question_class, + 0, + rdata, 6 /*success ? 6 : 0*/); + /* XXXX reject packet never tested: cannot tell what to do */ } /**************************************************************************** - construct a host announcement unicast - **************************************************************************/ -static void announce_host(struct domain_record *d,char *my_name,char *comment) +response for a reg request received +**************************************************************************/ +void response_name_reg(struct packet_struct *p) { - time_t t = time(NULL); - pstring outbuf; - char *p; - char *namep; - char *stypep; - char *commentp; - uint32 stype = ServerType; - - if (needannounce) { - /* drop back to a max 3 minute announce - this is to prevent a - single lost packet from stuffing things up for too long */ - d->announce_interval = MIN(d->announce_interval,3*60); - d->lastannounce_time = t - (d->announce_interval+1); - } + struct nmb_packet *nmb = &p->packet.nmb; + char *name = nmb->question.question_name.name; + int type = nmb->question.question_name.name_type; - /* announce every minute at first then progress to every 12 mins */ - if (d->lastannounce_time && - (t - d->lastannounce_time) < d->announce_interval) - return; + DEBUG(4,("response name registration received!\n")); - if (d->announce_interval < 12*60) d->announce_interval += 60; - d->lastannounce_time = t; + if (nmb->header.rcode == 0 && nmb->answers->rdata) + { + int nb_flags = nmb->answers->rdata[0]; + struct in_addr found_ip; + int ttl = nmb->answers->ttl; + enum name_source source = REGISTER; - DEBUG(2,("Sending announcement to %s for workgroup %s\n", - inet_ntoa(d->bcast_ip),d->name)); + putip((char*)&found_ip,&nmb->answers->rdata[2]); - if (!strequal(PrimaryGroup,d->name) || - !ip_equal(bcast_ip,d->bcast_ip)) { - stype &= ~(SV_TYPE_POTENTIAL_BROWSER | SV_TYPE_MASTER_BROWSER | - SV_TYPE_DOMAIN_MASTER | SV_TYPE_BACKUP_BROWSER | - SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_MEMBER); - } + if (ip_equal(found_ip, myip)) source = SELF; - if (!*comment) comment = "NoComment"; - if (!*my_name) my_name = "NoName"; - - if (strlen(comment) > 43) comment[43] = 0; - - bzero(outbuf,sizeof(outbuf)); - CVAL(outbuf,0) = 1; /* host announce */ - p = outbuf+1; - - CVAL(p,0) = updatecount; - SIVAL(p,1,d->announce_interval*1000); /* ms - despite the spec */ - namep = p+5; - StrnCpy(p+5,my_name,16); - strupper(p+5); - CVAL(p,21) = 2; /* major version */ - CVAL(p,22) = 2; /* minor version */ - stypep = p+23; - SIVAL(p,23,stype); - SSVAL(p,27,0xaa55); /* browse signature */ - SSVAL(p,29,1); /* browse version */ - commentp = p+31; - strcpy(p+31,comment); - p += 31; - p = skip_string(p,1); - - send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), - my_name,d->name,0,0x1d,d->bcast_ip,myip); - - /* if I'm the master then I also need to do a local master and - domain announcement */ - - if (AM_MASTER && - strequal(d->name,PrimaryGroup) && - ip_equal(bcast_ip,d->bcast_ip)) { - - /* do master announcements as well */ - SIVAL(stypep,0,ServerType); - - CVAL(outbuf,0) = 15; /* local master announce */ - send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), - my_name,PrimaryGroup,0,0x1e,d->bcast_ip,myip); - - CVAL(outbuf,0) = 12; /* domain announce */ - StrnCpy(namep,PrimaryGroup,15); - strupper(namep); - StrnCpy(commentp,myname,15); - strupper(commentp); - SIVAL(stypep,0,(unsigned)0x80000000); - p = commentp + strlen(commentp) + 1; - - send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), - my_name,MSBROWSE,0,1,d->bcast_ip,myip); - } + add_netbios_entry(name,type,nb_flags,ttl,source,found_ip); + } + else + { + DEBUG(1,("name registration for %s rejected!\n", + namestr(&nmb->question.question_name))); + } } /**************************************************************************** - send a announce request to the local net - **************************************************************************/ -static void announce_request(char *group) -{ - pstring outbuf; - char *p; - - DEBUG(2,("Sending announce request to %s for workgroup %s\n", - inet_ntoa(bcast_ip),group)); - - bzero(outbuf,sizeof(outbuf)); - p = outbuf; - CVAL(p,0) = 2; /* announce request */ - p++; - - CVAL(p,0) = 0; /* flags?? */ - p++; - StrnCpy(p,myname,16); - strupper(p); - p = skip_string(p,1); - - send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), - myname,group,0,0,bcast_ip,myip); -} - -/**************************************************************************** - announce myself as a master to the PDC - **************************************************************************/ -static void announce_master(char *group) -{ - static time_t last=0; - time_t t = time(NULL); - pstring outbuf; - char *p; - struct in_addr ip,pdc_ip; - fstring pdcname; - *pdcname = 0; - - if (strequal(domain_controller(),myname)) return; - - if (!AM_MASTER || (last && (t-last < 10*60))) return; - last = t; - - ip = *interpret_addr2(domain_controller()); - - if (zero_ip(ip)) ip = bcast_ip; - - if (!name_query(ClientNMB,PrimaryGroup, - 0x1b,False,False,ip,&pdc_ip,queue_packet)) { - DEBUG(2,("Failed to find PDC at %s\n",domain_controller())); - return; - } - - name_status(ClientNMB,PrimaryGroup,0x1b,False, - pdc_ip,NULL,pdcname,queue_packet); - - if (!pdcname[0]) { - DEBUG(3,("Can't find netbios name of PDC at %s\n",inet_ntoa(pdc_ip))); - } else { - sync_browse_lists(pdcname,0x20,myname,PrimaryGroup,pdc_ip); - } - - - DEBUG(2,("Sending master announce to %s for workgroup %s\n", - inet_ntoa(pdc_ip),group)); - - bzero(outbuf,sizeof(outbuf)); - p = outbuf; - CVAL(p,0) = 13; /* announce request */ - p++; - - StrnCpy(p,myname,16); - strupper(p); - p = skip_string(p,1); - - send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), - myname,PrimaryGroup,0x1b,0,pdc_ip,myip); -} - - -/******************************************************************* - am I listening on a name. Should check name_type as well - - This is primarily used to prevent us gathering server lists from - other workgroups we aren't a part of - ******************************************************************/ -static BOOL listening(struct nmb_name *n) -{ - if (!strequal(n->scope,scope)) return(False); - - if (strequal(n->name,myname) || - strequal(n->name,PrimaryGroup) || - strequal(n->name,MSBROWSE)) - return(True); - - return(False); -} - - -/******************************************************************* - process a domain announcement frame - - Announce frames come in 3 types. Servers send host announcements - (command=1) to let the master browswer know they are - available. Master browsers send local master announcements - (command=15) to let other masters and backups that they are the - master. They also send domain announcements (command=12) to register - the domain - - The comment field of domain announcements contains the master - browser name. The servertype is used by NetServerEnum to select - resources. We just have to pass it to smbd (via browser.dat) and let - the client choose using bit masks. - ******************************************************************/ -static void process_announce(struct packet_struct *p,int command,char *buf) -{ - struct dgram_packet *dgram = &p->packet.dgram; - int update_count = CVAL(buf,0); - int ttl = IVAL(buf,1)/1000; - char *name = buf+5; - int osmajor=CVAL(buf,21); - int osminor=CVAL(buf,22); - uint32 servertype = IVAL(buf,23); - char *comment = buf+31; - - name[15] = 0; - comment[43] = 0; - - DEBUG(3,("Announce(%d) %s count=%d ttl=%d OS=(%d,%d) type=%08x comment=%s\n", - command,name,update_count,ttl,osmajor,osminor, - servertype,comment)); - - if (strequal(dgram->source_name.name,myname)) return; - - if (!listening(&dgram->dest_name)) return; - - ttl = GET_TTL(ttl); - - /* add them to our browse list */ - add_server_entry(name,servertype,ttl,comment,True); - -} - -/******************************************************************* - process a master announcement frame - ******************************************************************/ -static void process_master_announce(struct packet_struct *p,char *buf) -{ - struct dgram_packet *dgram = &p->packet.dgram; - char *name = buf; - - name[15] = 0; - - DEBUG(3,("Master Announce from %s (%s)\n",name,inet_ntoa(p->ip))); - - if (strequal(dgram->source_name.name,myname)) return; - - if (!AM_MASTER || !listening(&dgram->dest_name)) return; - - /* merge browse lists with them */ - if (lp_domain_master()) - sync_browse_lists(name,0x20,myname,PrimaryGroup,p->ip); -} - - -/******************************************************************* - process a backup list request - - A client send a backup list request to ask for a list of servers on - the net that maintain server lists for a domain. A server is then - chosen from this list to send NetServerEnum commands to to list - available servers. - - Currently samba only sends back one name in the backup list, its - wn. For larger nets we'll have to add backups and send "become - backup" requests occasionally. - ******************************************************************/ -static void process_backup_list(struct packet_struct *p,char *buf) +reply to a reg request +**************************************************************************/ +void reply_name_reg(struct packet_struct *p) { - struct dgram_packet *dgram = &p->packet.dgram; - int count = CVAL(buf,0); - int token = IVAL(buf,1); - - DEBUG(3,("Backup request to %s token=%d\n", - namestr(&dgram->dest_name), - token)); - - if (strequal(dgram->source_name.name,myname)) return; - - if (count <= 0) return; - - if (!AM_MASTER || - !strequal(PrimaryGroup,dgram->dest_name.name)) - return; - - if (!listening(&dgram->dest_name)) return; - - send_backup_list(myname,token, - &dgram->source_name, - p->ip); -} - - -/******************************************************************* - work out if I win an election - ******************************************************************/ -static BOOL win_election(int version,uint32 criterion,int timeup,char *name) -{ - time_t t = time(NULL); - uint32 mycriterion; - if (version > ELECTION_VERSION) return(False); - if (version < ELECTION_VERSION) return(True); - - mycriterion = ElectionCriterion; - - if (criterion > mycriterion) return(False); - if (criterion < mycriterion) return(True); - - if (timeup > (t - StartupTime)) return(False); - if (timeup < (t - StartupTime)) return(True); - - if (strcasecmp(myname,name) > 0) return(False); - - return(True); -} - - -/******************************************************************* - process a election packet - - An election dynamically decides who will be the master. - ******************************************************************/ -static void process_election(struct packet_struct *p,char *buf) -{ - struct dgram_packet *dgram = &p->packet.dgram; - int version = CVAL(buf,0); - uint32 criterion = IVAL(buf,1); - int timeup = IVAL(buf,5)/1000; - char *name = buf+13; - - name[15] = 0; - - DEBUG(3,("Election request from %s vers=%d criterion=%08x timeup=%d\n", - name,version,criterion,timeup)); - - if (strequal(dgram->source_name.name,myname)) return; - - if (!listening(&dgram->dest_name)) return; - - if (win_election(version,criterion,timeup,name)) { - if (!RunningElection) { - needelection = True; - ElectionCount=0; - } - } else { - needelection = False; - if (RunningElection) { - RunningElection = False; - DEBUG(3,(">>> Lost election on %s <<<\n",PrimaryGroup)); - - /* if we are the master then remove our masterly names */ - if (AM_MASTER) - become_nonmaster(); - } - } -} - + struct nmb_packet *nmb = &p->packet.nmb; + struct nmb_name *question = &nmb->question.question_name; + char *qname = nmb->question.question_name.name; + int name_type = nmb->question.question_name.name_type; + + BOOL bcast = nmb->header.nm_flags.bcast; + + int ttl = GET_TTL(nmb->additional->ttl); + int nb_flags = nmb->additional->rdata[0]; + BOOL group = (nb_flags&0x80); + int rcode = 0; + int opcode = nmb->header.opcode; + struct name_record *n = NULL; + int success = True; + char rdata[6]; + struct in_addr ip, from_ip; + + putip((char *)&from_ip,&nmb->additional->rdata[2]); + ip = from_ip; + + DEBUG(3,("Name registration for name %s at %s rcode=%d\n", + namestr(question),inet_ntoa(ip),rcode)); + + if (group) + { + /* apparently we should return 255.255.255.255 for group queries + (email from MS) */ + ip = *interpret_addr2("255.255.255.255"); + } -/******************************************************************* - process a announcement request + /* see if the name already exists */ + n = find_name_search(question, FIND_GLOBAL, from_ip); - clients send these when they want everyone to send an announcement - immediately. This can cause quite a storm of packets! - ******************************************************************/ -static void process_announce_request(struct packet_struct *p,char *buf) -{ - struct dgram_packet *dgram = &p->packet.dgram; - int flags = CVAL(buf,0); - char *name = buf+1; + if (n) + { + if (!group && !ip_equal(ip,n->ip) && question->name_type != 0x3) + { + if (n->source == SELF) + { + rcode = 6; + success = False; + } + else + { + n->ip = ip; + n->death_time = ttl?p->timestamp+ttl*3:0; + DEBUG(3,("%s changed owner to %s\n", + namestr(&n->name),inet_ntoa(n->ip))); + } + } + else + { + /* refresh the name */ + if (n->source != SELF) + { + n->death_time = ttl?p->timestamp + ttl*3:0; + } + } + } + else + { + /* add the name to our subnet/name database */ + n = add_netbios_entry(qname,name_type,nb_flags,ttl,REGISTER,ip); + } - name[15] = 0; + if (bcast) return; - DEBUG(3,("Announce request from %s flags=0x%X\n",name,flags)); + update_from_reg(nmb->question.question_name.name, + nmb->question.question_name.name_type, from_ip); - if (strequal(dgram->source_name.name,myname)) return; + /* XXXX don't know how to reject a name register: stick info in anyway + and guess that it doesn't matter if info is there! */ + /*if (success)*/ + { + rdata[0] = nb_flags; + rdata[1] = 0; + putip(&rdata[2],(char *)&ip); + } - needannounce = True; + /* Send a NAME REGISTRATION RESPONSE */ + reply_netbios_packet(p,nmb->header.name_trn_id,rcode,opcode, + &nmb->question.question_name, + nmb->question.question_type, + nmb->question.question_class, + ttl, + rdata, 6 /*success ? 6 : 0*/); } /**************************************************************************** -process a browse frame +reply to a name status query ****************************************************************************/ -static void process_browse_packet(struct packet_struct *p,char *buf,int len) +void reply_name_status(struct packet_struct *p) { - int command = CVAL(buf,0); - switch (command) - { - case 1: /* host announce */ - case 12: /* domain announce */ - case 15: /* local master announce */ - process_announce(p,command,buf+1); - break; - - case 2: /* announce request */ - process_announce_request(p,buf+1); - break; - - case 8: /* election */ - process_election(p,buf+1); - break; - - case 9: /* get backup list */ - process_backup_list(p,buf+1); - break; - - case 13: /* master announcement */ - process_master_announce(p,buf+1); - break; - } -} + struct nmb_packet *nmb = &p->packet.nmb; + char *qname = nmb->question.question_name.name; + int ques_type = nmb->question.question_name.name_type; + BOOL wildcard = (qname[0] == '*'); + char rdata[MAX_DGRAM_SIZE]; + char *countptr, *buf; + int count, names_added; + struct name_record *n; + + DEBUG(3,("Name status for name %s %s\n", + namestr(&nmb->question.question_name), inet_ntoa(p->ip))); + + /* find a name: if it's a wildcard, search the entire database. + if not, search for source SELF names only */ + n = find_name_search(&nmb->question.question_name, + wildcard ? FIND_GLOBAL : FIND_SELF, p->ip); + + if (!wildcard && (!n || n->source != SELF)) return; + + for (count=0, n = namelist ; n; n = n->next) + { + int name_type = n->name.name_type; + if (n->source != SELF) continue; -/**************************************************************************** - process a domain logon packet - **************************************************************************/ -static void process_logon_packet(struct packet_struct *p,char *buf,int len) -{ - char *logname,*q; - pstring outbuf; - struct dgram_packet *dgram = &p->packet.dgram; - int code; + if (name_type >= 0x1b && name_type <= 0x20 && + ques_type >= 0x1b && ques_type <= 0x20) + { + if (!strequal(qname, n->name.name)) continue; + } - if (!lp_domain_logons()) { - DEBUG(3,("No domain logons\n")); - return; - } - if (!listening(&dgram->dest_name)) { - DEBUG(4,("Not listening to that domain\n")); - return; - } + count++; + } - q = outbuf; - bzero(outbuf,sizeof(outbuf)); - - code = SVAL(buf,0); - switch (code) { - case 0: - { - char *machine = buf+2; - char *user = skip_string(machine,1); - logname = skip_string(user,1); - - SSVAL(q,0,6); - q += 2; - strcpy(q,"\\\\"); - q += 2; - StrnCpy(q,myname,16); - strupper(q); - q = skip_string(q,1); - SSVAL(q,0,0xFFFF); - q += 2; - - DEBUG(3,("Domain login request from %s(%s) user=%s\n", - machine,inet_ntoa(p->ip),user)); - } - break; - case 7: - { - char *machine = buf+2; - logname = skip_string(machine,1); - - SSVAL(q,0,0xc); - q += 2; - StrnCpy(q,domain_controller(),16); - strupper(q); - q = skip_string(q,1); - q += PutUniCode(q,domain_controller()); - q += PutUniCode(q,dgram->dest_name.name); - SSVAL(q,0,0xFFFF); - q += 2; - - DEBUG(3,("GETDC request from %s(%s)\n", - machine,inet_ntoa(p->ip))); - } - break; - default: - DEBUG(3,("Unknown domain request %d\n",code)); - return; - } + /* XXXX hack, we should calculate exactly how many will fit */ + count = MIN(count,(sizeof(rdata) - 64) / 18); + countptr = buf = rdata; + buf += 1; - send_mailslot_reply(logname,ClientDGRAM,outbuf,PTR_DIFF(q,outbuf), - myname,&dgram->source_name.name[0],0,0,p->ip,myip); -} + names_added = 0; -/**************************************************************************** -process udp 138 datagrams -****************************************************************************/ -static void process_dgram(struct packet_struct *p) -{ - char *buf; - char *buf2; - int len; - struct dgram_packet *dgram = &p->packet.dgram; - - if (dgram->header.msg_type != 0x10 && - dgram->header.msg_type != 0x11 && - dgram->header.msg_type != 0x12) { - /* don't process error packets etc yet */ - return; - } + for (n = namelist ; n && count >= 0; n = n->next) + { + int name_type = n->name.name_type; - buf = &dgram->data[0]; - buf -= 4; /* XXXX for the pseudo tcp length - - someday I need to get rid of this */ + if (n->source != SELF) continue; - if (CVAL(buf,smb_com) != SMBtrans) return; + /* start with first bit of putting info in buffer: the name */ - len = SVAL(buf,smb_vwv11); - buf2 = smb_base(buf) + SVAL(buf,smb_vwv12); + bzero(buf,18); + StrnCpy(buf,n->name.name,15); + strupper(buf); - DEBUG(3,("datagram from %s to %s for %s of type %d len=%d\n", - namestr(&dgram->source_name),namestr(&dgram->dest_name), - smb_buf(buf),CVAL(buf2,0),len)); + /* now check if we want to exclude other workgroup names + from the response. if we don't exclude them, windows clients + get confused and will respond with an error for NET VIEW */ - if (len <= 0) return; + if (name_type >= 0x1b && name_type <= 0x20 && + ques_type >= 0x1b && ques_type <= 0x20) + { + if (!strequal(qname, n->name.name)) continue; + } - if (strequal(smb_buf(buf),"\\MAILSLOT\\BROWSE")) { - process_browse_packet(p,buf2,len); - } else if (strequal(smb_buf(buf),"\\MAILSLOT\\NET\\NETLOGON")) { - process_logon_packet(p,buf2,len); - } + /* carry on putting name info in buffer */ -} + buf[15] = name_type; + buf[16] = n->nb_flags; -/******************************************************************* - find a workgroup using the specified broadcast - ******************************************************************/ -static BOOL find_workgroup(char *name,struct in_addr ip) -{ - fstring name1; - BOOL ret; - struct in_addr ipout; + buf += 18; - strcpy(name1,MSBROWSE); + count--; + names_added++; + } - ret = name_query(ClientNMB,name1,0x1,True,False,ip,&ipout,queue_packet); - if (!ret) return(False); + if (count < 0) + { + DEBUG(3, (("too many names: missing a few!\n"))); + } - name_status(ClientNMB,name1,0x1,False,ipout,name,NULL,queue_packet); + SCVAL(countptr,0,names_added); - if (name[0] != '*') { - DEBUG(2,("Found workgroup %s on broadcast %s\n",name,inet_ntoa(ip))); - } else { - DEBUG(3,("Failed to find workgroup %s on broadcast %s\n",name,inet_ntoa(ip))); - } - return(name[0] != '*'); -} + /* XXXXXXX we should fill in more fields of the statistics structure */ + bzero(buf,64); + { + extern int num_good_sends,num_good_receives; + SIVAL(buf,20,num_good_sends); + SIVAL(buf,24,num_good_receives); + } + SIVAL(buf,46,0xFFB8E5); /* undocumented - used by NT */ -/**************************************************************************** - a hook for announce handling - called every minute - **************************************************************************/ -static void do_announcements(void) -{ - struct domain_record *d; - - for (d = domainlist; d; d = d->next) { - /* if the ip address is 0 then set to the broadcast */ - if (zero_ip(d->bcast_ip)) d->bcast_ip = bcast_ip; - - /* if the workgroup is '*' then find a workgroup to be part of */ - if (d->name[0] == '*') { - if (!find_workgroup(d->name,d->bcast_ip)) continue; - add_host_entry(d->name,0x1e,False,0,SELF, - *interpret_addr2("255.255.255.255")); - if (!PrimaryGroup[0] && ip_equal(bcast_ip,d->bcast_ip)) { - strcpy(PrimaryGroup,d->name); - strupper(PrimaryGroup); - } - } - - announce_host(d,myname,ServerComment); - } + buf += 64; - /* if I have a domain controller then announce to it */ - if (AM_MASTER) - announce_master(PrimaryGroup); - - needannounce=False; + /* Send a POSITIVE NAME STATUS RESPONSE */ + reply_netbios_packet(p,nmb->header.name_trn_id,0,0, + &nmb->question.question_name, + nmb->question.question_type, + nmb->question.question_class, + 0, + rdata,PTR_DIFF(buf,rdata)); } -/******************************************************************* - check if someone still owns a name - ******************************************************************/ -static BOOL confirm_name(struct name_record *n) -{ - struct in_addr ipout; - BOOL ret = name_query(ClientNMB,n->name.name, - n->name.name_type,False, - False,n->ip,&ipout,queue_packet); - return(ret && ip_equal(ipout,n->ip)); -} -/**************************************************************************** -reply to a name release +/*************************************************************************** +reply to a name query ****************************************************************************/ -static void reply_name_release(struct packet_struct *p) +struct name_record *search_for_name(struct nmb_name *question, + struct in_addr ip, int Time, int search) { - struct nmb_packet *nmb = &p->packet.nmb; - struct packet_struct p2; - struct nmb_packet *nmb2; - struct res_rec answer_rec; - struct in_addr ip; - int rcode=0; - int nb_flags = nmb->additional->rdata[0]; - BOOL bcast = nmb->header.nm_flags.bcast; - - - putip((char *)&ip,&nmb->additional->rdata[2]); + int name_type = question->name_type; + char *qname = question->name; + BOOL dns_type = name_type == 0x20 || name_type == 0; - { - struct name_record *n = find_name(&nmb->question.question_name); - if (n && n->unique && n->source == REGISTER && - ip_equal(ip,n->ip)) { - remove_name(n); n = NULL; - } + struct name_record *n; - /* XXXX under what conditions should we reject the removal?? */ - } + DEBUG(3,("Search for %s from %s - ", namestr(question), inet_ntoa(ip))); - DEBUG(3,("Name release on name %s rcode=%d\n", - namestr(&nmb->question.question_name),rcode)); + /* first look up name in cache */ + n = find_name_search(question,search,ip); - if (bcast) return; - - /* Send a NAME RELEASE RESPONSE */ - p2 = *p; - nmb2 = &p2.packet.nmb; - - nmb2->header.response = True; - nmb2->header.nm_flags.bcast = False; - nmb2->header.nm_flags.recursion_available = CanRecurse; - nmb2->header.nm_flags.trunc = False; - nmb2->header.nm_flags.authoritative = True; - nmb2->header.qdcount = 0; - nmb2->header.ancount = 1; - nmb2->header.nscount = 0; - nmb2->header.arcount = 0; - nmb2->header.rcode = rcode; - - nmb2->answers = &answer_rec; - bzero((char *)nmb2->answers,sizeof(*nmb2->answers)); - - nmb2->answers->rr_name = nmb->question.question_name; - nmb2->answers->rr_type = nmb->question.question_type; - nmb2->answers->rr_class = nmb->question.question_class; - nmb2->answers->ttl = 0; - nmb2->answers->rdlength = 6; - nmb2->answers->rdata[0] = nb_flags; - putip(&nmb2->answers->rdata[2],(char *)&ip); - - send_packet(&p2); -} - -/**************************************************************************** - reply to a reg request - **************************************************************************/ -static void reply_name_reg(struct packet_struct *p) -{ - struct nmb_packet *nmb = &p->packet.nmb; - char *qname = nmb->question.question_name.name; - BOOL wildcard = (qname[0] == '*'); - BOOL bcast = nmb->header.nm_flags.bcast; - int ttl = GET_TTL(nmb->additional->ttl); - int name_type = nmb->question.question_name.name_type; - int nb_flags = nmb->additional->rdata[0]; - struct packet_struct p2; - struct nmb_packet *nmb2; - struct res_rec answer_rec; - struct in_addr ip; - BOOL group = (nb_flags&0x80)?True:False; - int rcode = 0; - - if (wildcard) return; - - putip((char *)&ip,&nmb->additional->rdata[2]); - - if (group) { - /* apparently we should return 255.255.255.255 for group queries (email from MS) */ - ip = *interpret_addr2("255.255.255.255"); - } + /* now try DNS lookup. */ + if (!n) + { + struct in_addr dns_ip; + unsigned long a; + + /* only do DNS lookups if the query is for type 0x20 or type 0x0 */ + if (!dns_type) + { + DEBUG(3,("types 0x20 0x1b 0x0 only: name not found\n")); + return NULL; + } + + /* look it up with DNS */ + a = interpret_addr(qname); + + putip((char *)&dns_ip,(char *)&a); + + if (!a) + { + /* no luck with DNS. We could possibly recurse here XXXX */ + /* if this isn't a bcast then we should send a negative reply XXXX */ + DEBUG(3,("no recursion\n")); + add_netbios_entry(qname,name_type,NB_ACTIVE,60*60,DNSFAIL,dns_ip); + return NULL; + } + + /* add it to our cache of names. give it 2 hours in the cache */ + n = add_netbios_entry(qname,name_type,NB_ACTIVE,2*60*60,DNS,dns_ip); + + /* failed to add it? yikes! */ + if (!n) return NULL; + } - { - struct name_record *n = find_name(&nmb->question.question_name); - - if (n) { - if (!group && !ip_equal(ip,n->ip)) { - /* check if the previous owner still wants it, - if so reject the registration, otherwise change the owner - and refresh */ - if (n->source != REGISTER || confirm_name(n)) { - rcode = 6; - } else { - n->ip = ip; - n->death_time = ttl?p->timestamp+ttl*3:0; - DEBUG(3,("%s changed owner to %s\n", - namestr(&n->name),inet_ntoa(n->ip))); + /* is our entry already dead? */ + if (n->death_time) + { + if (n->death_time < Time) return False; } - } else { - /* refresh the name */ - if (n->source != SELF) - n->death_time = ttl?p->timestamp + ttl*3:0; - } - } else { - /* add the name to our database */ - n = add_host_entry(qname,name_type,!group,ttl,REGISTER,ip); - } - } - if (bcast) return; - - DEBUG(3,("Name registration for name %s at %s rcode=%d\n", - namestr(&nmb->question.question_name), - inet_ntoa(ip),rcode)); - - /* Send a NAME REGISTRATION RESPONSE */ - /* a lot of fields get copied from the query. This gives us the IP - and port the reply will be sent to etc */ - p2 = *p; - nmb2 = &p2.packet.nmb; - - nmb2->header.opcode = 5; - nmb2->header.response = True; - nmb2->header.nm_flags.bcast = False; - nmb2->header.nm_flags.recursion_available = CanRecurse; - nmb2->header.nm_flags.trunc = False; - nmb2->header.nm_flags.authoritative = True; - nmb2->header.qdcount = 0; - nmb2->header.ancount = 1; - nmb2->header.nscount = 0; - nmb2->header.arcount = 0; - nmb2->header.rcode = rcode; - - nmb2->answers = &answer_rec; - bzero((char *)nmb2->answers,sizeof(*nmb2->answers)); - - nmb2->answers->rr_name = nmb->question.question_name; - nmb2->answers->rr_type = nmb->question.question_type; - nmb2->answers->rr_class = nmb->question.question_class; + /* it may have been an earlier failure */ + if (n->source == DNSFAIL) + { + DEBUG(3,("DNSFAIL\n")); + return NULL; + } - nmb2->answers->ttl = ttl; - nmb2->answers->rdlength = 6; - nmb2->answers->rdata[0] = nb_flags; - putip(&nmb2->answers->rdata[2],(char *)&ip); + DEBUG(3,("OK %s\n",inet_ntoa(n->ip))); - send_packet(&p2); + return n; } +/* XXXX i think we should only do this if we are a WINS proxy + if (!n && bcast) + { + // now try look up the name at the primary domain controller + if (*lp_domain_controller()) + { + struct in_addr dom_ip; + dom_ip = *interpret_addr2(lp_domain_controller()); + + if (!zero_ip(dom_ip)) + { + struct in_addr found_ip; + + // initiate a netbios query to the PDC + queue_netbios_packet(ClientNMB,NMB_QUERY,NAME_CONFIRM_QUERY, + question->name, question->name_type, 0, + False, True, dom_ip, id); + return; + } + } + } +*/ -/**************************************************************************** -reply to a name status query -****************************************************************************/ -static void reply_name_status(struct packet_struct *p) -{ - struct nmb_packet *nmb = &p->packet.nmb; - char *qname = nmb->question.question_name.name; - BOOL wildcard = (qname[0] == '*'); - struct packet_struct p2; - struct nmb_packet *nmb2; - struct res_rec answer_rec; - char *buf; - int count; - int rcode = 0; - struct name_record *n = find_name(&nmb->question.question_name); - - DEBUG(3,("Name status for name %s\n", - namestr(&nmb->question.question_name))); - - if (!wildcard && (!n || n->source != SELF)) - return; - - /* Send a POSITIVE NAME STATUS RESPONSE */ - /* a lot of fields get copied from the query. This gives us the IP - and port the reply will be sent to etc */ - p2 = *p; - nmb2 = &p2.packet.nmb; - - nmb2->header.response = True; - nmb2->header.nm_flags.bcast = False; - nmb2->header.nm_flags.recursion_available = CanRecurse; - nmb2->header.nm_flags.trunc = False; - nmb2->header.nm_flags.authoritative = True; /* WfWg ignores - non-authoritative answers */ - nmb2->header.qdcount = 0; - nmb2->header.ancount = 1; - nmb2->header.nscount = 0; - nmb2->header.arcount = 0; - nmb2->header.rcode = rcode; - - nmb2->answers = &answer_rec; - bzero((char *)nmb2->answers,sizeof(*nmb2->answers)); - - - nmb2->answers->rr_name = nmb->question.question_name; - nmb2->answers->rr_type = nmb->question.question_type; - nmb2->answers->rr_class = nmb->question.question_class; - nmb2->answers->ttl = 0; - - for (count=0, n = namelist ; n; n = n->next) { - if (n->source != SELF) continue; - count++; - } +/*************************************************************************** +reply to a name query. - count = MIN(count,400/18); /* XXXX hack, we should calculate exactly - how many will fit */ +with broadcast name queries: - - buf = &nmb2->answers->rdata[0]; - SCVAL(buf,0,count); - buf += 1; - - for (n = namelist ; n; n = n->next) - { - if (n->source != SELF) continue; - - bzero(buf,18); - strcpy(buf,n->name.name); - strupper(buf); - buf[15] = n->name.name_type; - buf += 16; - buf[0] = 0x4; /* active */ - if (!n->unique) buf[0] |= 0x80; /* group */ - buf += 2; - count--; - } - - /* XXXXXXX we should fill in more fields of the statistics structure */ - bzero(buf,64); - { - extern int num_good_sends,num_good_receives; - SIVAL(buf,20,num_good_sends); - SIVAL(buf,24,num_good_receives); - } - SIVAL(buf,46,0xFFB8E5); /* undocumented - used by NT */ - - buf += 64; + - only reply if the query is for one of YOUR names. all other machines on + the network will be doing the same thing (that is, only replying to a + broadcast query if they own it) + NOTE: broadcast name queries should only be sent out by a machine + if they HAVEN'T been configured to use WINS. this is generally bad news + in a wide area tcp/ip network and should be rectified by the systems + administrator. USE WINS! :-) + - the exception to this is if the query is for a Primary Domain Controller + type name (0x1b), in which case, a reply is sent. - nmb2->answers->rdlength = PTR_DIFF(buf,&nmb2->answers->rdata[0]); - - send_packet(&p2); -} + - NEVER send a negative response to a broadcast query. no-one else will! +with directed name queries: - -/**************************************************************************** -reply to a name query + - if you are the WINS server, you are expected to ****************************************************************************/ -static void reply_name_query(struct packet_struct *p) +extern void reply_name_query(struct packet_struct *p) { - struct nmb_packet *nmb = &p->packet.nmb; - char *qname = nmb->question.question_name.name; - BOOL wildcard = (qname[0] == '*'); - BOOL bcast = nmb->header.nm_flags.bcast; - struct in_addr retip; - int name_type = nmb->question.question_name.name_type; - struct packet_struct p2; - struct nmb_packet *nmb2; - struct res_rec answer_rec; - int ttl=0; - int rcode=0; - BOOL unique = True; - - DEBUG(3,("Name query for %s from %s (bcast=%s) - ", - namestr(&nmb->question.question_name), - inet_ntoa(p->ip), - BOOLSTR(bcast))); - - if (wildcard) - retip = myip; - - if (!wildcard) { - struct name_record *n = find_name(&nmb->question.question_name); - - if (!n) { - struct in_addr ip; - unsigned long a; - - /* only do DNS lookups if the query is for type 0x20 or type 0x0 */ - if (name_type != 0x20 && name_type != 0) { - DEBUG(3,("not found\n")); - return; - } - - /* look it up with DNS */ - a = interpret_addr(qname); - - putip((char *)&ip,(char *)&a); - - if (!a) { - /* no luck with DNS. We could possibly recurse here XXXX */ - /* if this isn't a bcast then we should send a negative reply XXXX */ - DEBUG(3,("no recursion\n")); - add_host_entry(qname,name_type,True,60*60,DNSFAIL,ip); - return; - } - - /* add it to our cache of names. give it 2 hours in the cache */ - n = add_host_entry(qname,name_type,True,2*60*60,DNS,ip); - - /* failed to add it? yikes! */ - if (!n) return; - } - - /* don't respond to bcast queries for group names unless we own them */ - if (bcast && !n->unique && !n->source == SELF) { - DEBUG(3,("no bcast replies\n")); - return; - } - - if (!lp_proxy_name_resolution() && n->source != SELF) { - DEBUG(3,("no proxy resolution\n")); - return; - } - - /* don't respond to bcast queries for addresses on the same net as the - machine doing the querying unless its our IP */ - if (bcast && - n->source != SELF && - same_net(n->ip,p->ip)) { - DEBUG(3,("same net\n")); - return; - } - - /* is our entry already dead? */ - if (n->death_time) { - if (n->death_time < p->timestamp) return; - ttl = n->death_time - p->timestamp; - } - - retip = n->ip; - unique = n->unique; - - /* it may have been an earlier failure */ - if (n->source == DNSFAIL) { - DEBUG(3,("DNSFAIL\n")); - return; - } - } - - /* if the IP is 0 then substitute my IP - we should see which one is on the - right interface for the caller to do this right XXX */ - if (zero_ip(retip)) retip = myip; - - DEBUG(3,("OK %s rcode=%d\n",inet_ntoa(retip),rcode)); - - /* a lot of fields get copied from the query. This gives us the IP - and port the reply will be sent to etc */ - p2 = *p; - nmb2 = &p2.packet.nmb; - - nmb2->header.response = True; - nmb2->header.nm_flags.bcast = False; - nmb2->header.nm_flags.recursion_available = CanRecurse; - nmb2->header.nm_flags.trunc = False; - nmb2->header.nm_flags.authoritative = True; /* WfWg ignores - non-authoritative answers */ - nmb2->header.qdcount = 0; - nmb2->header.ancount = 1; - nmb2->header.nscount = 0; - nmb2->header.arcount = 0; - nmb2->header.rcode = rcode; - - nmb2->answers = &answer_rec; - bzero((char *)nmb2->answers,sizeof(*nmb2->answers)); - - nmb2->answers->rr_name = nmb->question.question_name; - nmb2->answers->rr_type = nmb->question.question_type; - nmb2->answers->rr_class = nmb->question.question_class; - nmb2->answers->ttl = ttl; - nmb2->answers->rdlength = 6; - nmb2->answers->rdata[0] = unique?0:0x80; - nmb2->answers->rdata[1] = 0; - putip(&nmb2->answers->rdata[2],(char *)&retip); - - send_packet(&p2); -} - - - -/* the global packet linked-list. incoming entries are added to the - end of this list. it is supposed to remain fairly short so we - won't bother with an end pointer. */ -static struct packet_struct *packet_queue = NULL; - - -/******************************************************************* - queue a packet into the packet queue - ******************************************************************/ -static void queue_packet(struct packet_struct *packet) -{ - struct packet_struct *p; - if (!packet_queue) { - packet->prev = NULL; - packet->next = NULL; - packet_queue = packet; - return; - } - - /* find the bottom */ - for (p=packet_queue;p->next;p=p->next) ; - - p->next = packet; - packet->next = NULL; - packet->prev = p; -} - -/**************************************************************************** - process a nmb packet - ****************************************************************************/ -static void process_nmb(struct packet_struct *p) -{ - struct nmb_packet *nmb = &p->packet.nmb; - - /* if this is a response then ignore it */ - if (nmb->header.response) return; - - switch (nmb->header.opcode) - { - case 5: - case 8: - case 9: - if (nmb->header.qdcount>0 && - nmb->header.arcount>0) { - reply_name_reg(p); - return; - } - break; - - case 0: - if (nmb->header.qdcount>0) + struct nmb_packet *nmb = &p->packet.nmb; + struct nmb_name *question = &nmb->question.question_name; + int name_type = question->name_type; + BOOL dns_type = name_type == 0x20 || name_type == 0; + BOOL bcast = nmb->header.nm_flags.bcast; + int ttl=0; + int rcode = 0; + int nb_flags = 0; + struct in_addr retip; + char rdata[6]; + + struct in_addr gp_ip = *interpret_addr2("255.255.255.255"); + BOOL success = True; + + struct name_record *n; + enum name_search search = dns_type || name_type == 0x1b ? + FIND_GLOBAL : FIND_SELF; + + DEBUG(3,("Name query ")); + + if ((n = search_for_name(question,p->ip,p->timestamp, search))) { - switch (nmb->question.question_type) - { - case 0x20: - reply_name_query(p); - break; - - case 0x21: - reply_name_status(p); - break; - } - return; + /* don't respond to broadcast queries unless the query is for + a name we own or it is for a Primary Domain Controller name */ + if (bcast && n->source != SELF && name_type != 0x1b) + { + /* never reply with a negative response to broadcast queries */ + return; + } + + /* name is directed query, or it's self, or it's a PDC type name */ + ttl = n->death_time - p->timestamp; + retip = n->ip; + nb_flags = n->nb_flags; + } + else + { + if (bcast) return; /* never reply negative response to bcasts */ + success = False; } - break; - - case 6: - if (nmb->header.qdcount>0 && - nmb->header.arcount>0) { - reply_name_release(p); - return; - } - break; - } - -} - - - -/******************************************************************* - run elements off the packet queue till its empty - ******************************************************************/ -static void run_packet_queue(void) -{ - struct packet_struct *p; - - while ((p=packet_queue)) { - switch (p->packet_type) - { - case NMB_PACKET: - process_nmb(p); - break; - - case DGRAM_PACKET: - process_dgram(p); - break; - } - - packet_queue = packet_queue->next; - if (packet_queue) packet_queue->prev = NULL; - free_packet(p); - } -} - - -/**************************************************************************** - The main select loop, listen for packets and respond - ***************************************************************************/ -void process(void) -{ - - while (True) - { - fd_set fds; - int selrtn; - struct timeval timeout; - - if (needelection && PrimaryGroup[0] && !RunningElection) { - DEBUG(3,(">>> Starting election on %s <<<\n",PrimaryGroup)); - ElectionCount = 0; - RunningElection = True; - needelection = False; - } - - FD_ZERO(&fds); - FD_SET(ClientNMB,&fds); - FD_SET(ClientDGRAM,&fds); - /* during elections we need to send election packets at one - second intervals */ - timeout.tv_sec = RunningElection?1:NMBD_SELECT_LOOP; - timeout.tv_usec = 0; - - selrtn = sys_select(&fds,&timeout); - - if (FD_ISSET(ClientNMB,&fds)) { - struct packet_struct *packet = read_packet(ClientNMB,NMB_PACKET); - if (packet) queue_packet(packet); - } - if (FD_ISSET(ClientDGRAM,&fds)) { - struct packet_struct *packet = read_packet(ClientDGRAM,DGRAM_PACKET); - if (packet) queue_packet(packet); - } + /* if asking for a group name (type 0x1e) return 255.255.255.255 */ + if (ip_equal(retip, gp_ip) && name_type == 0x1e) retip = gp_ip; - if (RunningElection) - run_election(); + /* if the IP is 0 then substitute my IP - we should see which one is on the + right interface for the caller to do this right XXX */ + if (zero_ip(retip)) retip = myip; - run_packet_queue(); + if (success) + { + rcode = 0; + DEBUG(3,("OK %s\n",inet_ntoa(retip))); + } + else + { + rcode = 3; + DEBUG(3,("UNKNOWN\n")); + } - do_announcements(); + if (success) + { + rdata[0] = nb_flags; + rdata[1] = 0; + putip(&rdata[2],(char *)&retip); + } - housekeeping(); - } + reply_netbios_packet(p,nmb->header.name_trn_id,rcode,0, + &nmb->question.question_name, + nmb->question.question_type, + nmb->question.question_class, + ttl, + rdata, success ? 6 : 0); } /**************************************************************************** - open the socket communication +response from a name query ****************************************************************************/ -static BOOL open_sockets(BOOL isdaemon,int port) -{ - struct hostent *hp; - - /* get host info */ - if ((hp = Get_Hostbyname(myhostname)) == 0) - { - DEBUG(0,( "Get_Hostbyname: Unknown host. %s\n",myhostname)); - return False; - } - - if (isdaemon) - ClientNMB = open_socket_in(SOCK_DGRAM, port,0); - else - ClientNMB = 0; - - ClientDGRAM = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3); - - if (ClientNMB == -1) - return(False); - - signal(SIGPIPE, SIGNAL_CAST sig_pipe); - - set_socket_options(ClientNMB,"SO_BROADCAST"); - set_socket_options(ClientDGRAM,"SO_BROADCAST"); - - DEBUG(3, ("Socket opened.\n")); - return True; -} - - -/******************************************************************* - check that a IP, bcast and netmask and consistent. Must be a 1s - broadcast - ******************************************************************/ -static BOOL ip_consistent(struct in_addr ip,struct in_addr bcast, - struct in_addr nmask) +static void response_netbios_packet(struct packet_struct *p) { - unsigned long a_ip,a_bcast,a_nmask; + struct nmb_packet *nmb = &p->packet.nmb; + struct nmb_name *question = &nmb->question.question_name; + char *qname = question->name; + BOOL bcast = nmb->header.nm_flags.bcast; + struct name_response_record *n; - a_ip = ntohl(ip.s_addr); - a_bcast = ntohl(bcast.s_addr); - a_nmask = ntohl(nmask.s_addr); - - /* check the netmask is sane */ - if (((a_nmask>>24)&0xFF) != 0xFF) { - DEBUG(0,("Insane netmask %s\n",inet_ntoa(nmask))); - return(False); - } + if (nmb->answers == NULL) + { + DEBUG(3,("NMB packet response from %s (bcast=%s) - UNKNOWN\n", + inet_ntoa(p->ip), + BOOLSTR(bcast))); + return; + } - /* check the IP and bcast are on the same net */ - if ((a_ip&a_nmask) != (a_bcast&a_nmask)) { - DEBUG(0,("IP and broadcast are on different nets!\n")); - return(False); - } + if (nmb->answers->rr_type == NMB_STATUS) + { + DEBUG(3,("Name status ")); + } - /* check the IP and bcast are on the same net */ - if ((a_bcast|a_nmask) != 0xFFFFFFFF) { - DEBUG(0,("Not a ones based broadcast %s\n",inet_ntoa(bcast))); - return(False); - } + if (nmb->answers->rr_type == NMB_QUERY) + { + DEBUG(3,("Name query ")); + } - return(True); -} + if (nmb->answers->rr_type == NMB_REG) + { + DEBUG(3,("Name registration ")); + } -/**************************************************************************** - initialise connect, service and file structs -****************************************************************************/ -static BOOL init_structs(void ) -{ - if (!get_myname(myhostname,got_myip?NULL:&myip)) - return(False); + if (nmb->answers->rr_type == NMB_REL) + { + DEBUG(3,("Name release ")); + } - /* Read the broadcast address from the interface */ - { - struct in_addr ip0,ip1,ip2; - - ip0 = myip; - - if (!(got_bcast && got_nmask)) - { - get_broadcast(&ip0,&ip1,&ip2); - - if (!got_myip) - myip = ip0; - - if (!got_bcast) - bcast_ip = ip1; - - if (!got_nmask) - Netmask = ip2; - } - - DEBUG(1,("Using IP %s ",inet_ntoa(myip))); - DEBUG(1,("broadcast %s ",inet_ntoa(bcast_ip))); - DEBUG(1,("netmask %s\n",inet_ntoa(Netmask))); - - if (!ip_consistent(myip,bcast_ip,Netmask)) { - DEBUG(0,("WARNING: The IP address, broadcast and Netmask are not consistent\n")); - DEBUG(0,("You are likely to experience problems with this setup!\n")); - } - } + DEBUG(3,("response for %s from %s (bcast=%s)\n", + namestr(&nmb->answers->rr_name), + inet_ntoa(p->ip), + BOOLSTR(bcast))); - if (! *myname) { - char *p; - strcpy(myname,myhostname); - p = strchr(myname,'.'); - if (p) *p = 0; - } + if (!(n = find_name_query(nmb->header.name_trn_id))) + { + DEBUG(3,("unknown response (received too late or from nmblookup?)\n")); + return; + } - { - extern fstring local_machine; - strcpy(local_machine,myname); - strupper(local_machine); - } + n->num_msgs++; /* count number of responses received */ - return True; -} - -/**************************************************************************** -usage on the program -****************************************************************************/ -static void usage(char *pname) -{ - DEBUG(0,("Incorrect program usage - is the command line correct?\n")); - - printf("Usage: %s [-n name] [-B bcast address] [-D] [-p port] [-d debuglevel] [-l log basename]\n",pname); - 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-n netbiosname. the netbios name to advertise for this host\n"); - printf("\t-B broadcast address the address to use for broadcasts\n"); - printf("\t-N netmask the netmask to use for subnet determination\n"); - printf("\t-H hosts file load a netbios hosts file\n"); - printf("\t-I ip-address override the IP address\n"); - printf("\t-G group name add a group name to be part of\n"); - printf("\t-C comment sets the machine comment that appears in browse lists\n"); - printf("\n"); + switch (n->cmd_type) + { + case MASTER_SERVER_CHECK : DEBUG(4,("MASTER_SVR_CHECK\n")); break; + case SERVER_CHECK : DEBUG(4,("SERVER_CHECK\n")); break; + case FIND_MASTER : DEBUG(4,("FIND_MASTER\n")); break; + case NAME_STATUS_MASTER_CHECK: DEBUG(4,("NAME_STAT_MST_CHK\n")); break; + case NAME_STATUS_CHECK : DEBUG(4,("NAME_STATUS_CHECK\n")); break; + case CHECK_MASTER : DEBUG(4,("CHECK_MASTER\n")); break; + case NAME_CONFIRM_QUERY : DEBUG(4,("NAME_CONFIRM_QUERY\n")); break; + default: break; + } + switch (n->cmd_type) + { + case MASTER_SERVER_CHECK: + case SERVER_CHECK: + case FIND_MASTER: + { + if (nmb->answers->rr_type == NMB_QUERY) + { + enum cmd_type cmd = (n->cmd_type == MASTER_SERVER_CHECK) ? + NAME_STATUS_MASTER_CHECK : + NAME_STATUS_CHECK; + if (n->num_msgs > 1 && !strequal(qname,n->name.name)) + { + /* one subnet, one master browser per workgroup */ + /* XXXX force an election? */ + DEBUG(1,("more than one master browser replied!\n")); + } + + /* initiate a name status check on the server that replied */ + queue_netbios_packet(ClientNMB,NMB_STATUS, cmd, + nmb->answers->rr_name.name, + nmb->answers->rr_name.name_type,0, + False,False,n->to_ip); + } + else + { + DEBUG(1,("Name query reply has wrong answer rr_type\n")); + } + break; + } + + case NAME_STATUS_MASTER_CHECK: + case NAME_STATUS_CHECK: + { + if (nmb->answers->rr_type == NMB_STATUS) + { + /* NMB_STATUS arrives: contains the workgroup name + and server name we require */ + struct nmb_name name; + fstring serv_name; + + if (interpret_node_status(nmb->answers->rdata, + &name,0x1d,serv_name,n->to_ip)) + { + if (*serv_name) + { + sync_server(n->cmd_type,serv_name, + name.name,name.name_type, + n->to_ip); + } + } + else + { + DEBUG(1,("No 0x1d name type in interpret_node_status()\n")); + } + } + else + { + DEBUG(1,("Name status reply has wrong answer rr_type\n")); + } + break; + } + + case CHECK_MASTER: + { + /* no action required here. it's when NO responses are received + that we need to do something (see expire_name_query_entries) */ + + DEBUG(4, ("Master browser exists for %s at %s\n", + namestr(&n->name), + inet_ntoa(n->to_ip))); + if (n->num_msgs > 1) + { + DEBUG(1,("more than one master browser!\n")); + } + if (nmb->answers->rr_type != NMB_QUERY) + { + DEBUG(1,("Name query reply has wrong answer rr_type\n")); + } + break; + } + case NAME_CONFIRM_QUERY: + { + DEBUG(4, ("Name query at WINS server: %s at %s - ", + namestr(&n->name), + inet_ntoa(n->to_ip))); + if (nmb->header.rcode == 0 && nmb->answers->rdata) + { + int nb_flags = nmb->answers->rdata[0]; + struct in_addr found_ip; + putip((char*)&found_ip,&nmb->answers->rdata[2]); + + DEBUG(4, (" OK: %s\n", inet_ntoa(found_ip))); + add_netbios_entry(nmb->answers->rr_name.name, + nmb->answers->rr_name.name_type, + nb_flags,GET_TTL(0),STATUS_QUERY,found_ip); + } + else + { + DEBUG(4, (" NEGATIVE RESPONSE\n")); + } + + break; + } + default: + { + DEBUG(0,("unknown command received in response_netbios_packet\n")); + break; + } + } } /**************************************************************************** - main program - **************************************************************************/ -int main(int argc,char *argv[]) + process a nmb packet + ****************************************************************************/ +void process_nmb(struct packet_struct *p) { - int port = NMB_PORT; - int opt; - extern FILE *dbf; - extern char *optarg; - - *host_file = 0; - -#if 0 - sleep(10); -#endif - - StartupTime = time(NULL); - - TimeInit(); - - strcpy(debugf,NMBLOGFILE); - - setup_logging(argv[0],False); - - charset_initialise(); - -#ifdef LMHOSTSFILE - strcpy(host_file,LMHOSTSFILE); -#endif - - /* this is for people who can't start the program correctly */ - while (argc > 1 && (*argv[1] != '-')) - { - argv++; - argc--; - } - - fault_setup(fault_continue); - - signal(SIGHUP,SIGNAL_CAST sig_hup); - - bcast_ip = *interpret_addr2("0.0.0.0"); - myip = *interpret_addr2("0.0.0.0"); - - while ((opt = getopt (argc, argv, "s:T:I:C:bAi:B:N:Rn:l:d:Dp:hSH:G:")) != EOF) - switch (opt) - { - case 's': - strcpy(servicesf,optarg); - break; - case 'C': - strcpy(ServerComment,optarg); - break; - case 'G': - add_domain_entry(optarg,bcast_ip); - break; - case 'H': - strcpy(host_file,optarg); - break; - case 'I': - myip = *interpret_addr2(optarg); - got_myip = True; - break; - case 'B': - bcast_ip = *interpret_addr2(optarg); - got_bcast = True; - break; - case 'N': - Netmask = *interpret_addr2(optarg); - got_nmask = True; - break; - case 'n': - strcpy(myname,optarg); - break; - case 'l': - sprintf(debugf,"%s.nmb",optarg); - break; - case 'i': - strcpy(scope,optarg); - strupper(scope); - break; - case 'D': - is_daemon = True; - break; - case 'd': - DEBUGLEVEL = atoi(optarg); - break; - case 'p': - port = atoi(optarg); - break; - case 'h': - usage(argv[0]); - exit(0); - break; - default: - if (!is_a_socket(0)) - usage(argv[0]); - break; - } - - DEBUG(1,("%s netbios nameserver version %s started\n",timestring(),VERSION)); - DEBUG(1,("Copyright Andrew Tridgell 1994\n")); + struct nmb_packet *nmb = &p->packet.nmb; - init_structs(); + debug_nmb_packet(p); - if (!reload_services(False)) - return(-1); - - if (*host_file) - { - load_hosts_file(host_file); - DEBUG(3,("Loaded hosts file\n")); - } - - if (!*ServerComment) - strcpy(ServerComment,"Samba %v"); - string_sub(ServerComment,"%v",VERSION); - string_sub(ServerComment,"%h",myhostname); - - add_my_names(); - - DEBUG(3,("Checked names\n")); - - dump_names(); - - DEBUG(3,("Dumped names\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(2,("%s becoming a daemon\n",timestring())); - become_daemon(); - } - - - DEBUG(3,("Opening sockets\n")); - - if (open_sockets(is_daemon,port)) - { - process(); - close_sockets(); - } + switch (nmb->header.opcode) + { + case 5: + case 8: + case 9: + { + if (nmb->header.qdcount==0 || nmb->header.arcount==0) break; + if (nmb->header.response) + response_name_reg(p); + else + reply_name_reg(p); + break; + } + + case 0: + { + if (nmb->header.response) + { + switch (nmb->question.question_type) + { + case 0x0: + { + response_netbios_packet(p); + break; + } + } + return; + } + else if (nmb->header.qdcount>0) + { + switch (nmb->question.question_type) + { + case NMB_QUERY: + { + reply_name_query(p); + break; + } + case NMB_STATUS: + { + reply_name_status(p); + break; + } + } + return; + } + break; + } + + case 6: + { + if (nmb->header.qdcount==0 || nmb->header.arcount==0) + { + DEBUG(2,("netbios release packet rejected\n")); + break; + } + + if (nmb->header.response) + response_name_release(p); + else + reply_name_release(p); + break; + } + } - if (dbf) - fclose(dbf); - return(0); } + diff --git a/source/namework.c b/source/namework.c new file mode 100644 index 00000000000..e28a1cbf95d --- /dev/null +++ b/source/namework.c @@ -0,0 +1,1072 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + NBT netbios routines and daemon - version 2 + Copyright (C) Andrew Tridgell 1994-1995 + + 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. + + Revision History: + + 14 jan 96: lkcl@pires.co.uk + added multiple workgroup domain master support + +*/ + +#include "includes.h" +#include "loadparm.h" +#include "localnet.h" + +#define TEST_CODE /* want to debug unknown browse packets */ + +extern int DEBUGLEVEL; +extern pstring scope; +extern BOOL CanRecurse; + +extern struct in_addr myip; +extern struct in_addr bcast_ip; +extern struct in_addr Netmask; + +extern pstring myname; + +extern int ClientNMB; +extern int ClientDGRAM; + +extern int workgroup_count; /* total number of workgroups we know about */ + +/* this is our browse cache database */ +extern struct browse_cache_record *browserlist; + +/* this is our domain/workgroup/server database */ +extern struct domain_record *domainlist; + +/* machine comment for host announcements */ +extern pstring ServerComment; + +extern int updatecount; + +/* what server type are we currently */ +#define DFLT_SERVER_TYPE (SV_TYPE_WORKSTATION | SV_TYPE_SERVER | \ + SV_TYPE_TIME_SOURCE | SV_TYPE_SERVER_UNIX |\ + SV_TYPE_PRINTQ_SERVER | SV_TYPE_POTENTIAL_BROWSER) + +/* backup request types: which servers are to be included */ +#define MASTER_TYPE (SV_TYPE_MASTER_BROWSER) +#define DOMCTL_TYPE (SV_TYPE_DOMAIN_CTRL ) + +extern time_t StartupTime; + +#define AM_MASTER(work) (work->ServerType & SV_TYPE_MASTER_BROWSER) +#define AM_BACKUP(work) (work->ServerType & SV_TYPE_BACKUP_BROWSER) + +#define MSBROWSE "\001\002__MSBROWSE__\002" +#define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE" + +#define GET_TTL(ttl) ((ttl)?MIN(ttl,lp_max_ttl()):lp_max_ttl()) + + +/**************************************************************************** +tell a server to become a backup browser +state - 0x01 become backup instead of master + - 0x02 remove all entries in browse list and become non-master + - 0x04 stop master browser service altogether. NT ignores this +**************************************************************************/ +void reset_server(char *name, int state, struct in_addr ip) +{ + char outbuf[20]; + char *p; + + bzero(outbuf,sizeof(outbuf)); + p = outbuf; + + CVAL(p,0) = 14; /* request reset browser state */ + CVAL(p,2) = state; /* type of request */ + p += 2; + + send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), + myname,name,0x20,0x1d,ip,myip); +} + +/**************************************************************************** +tell a server to become a backup browser +**************************************************************************/ +void tell_become_backup(void) +{ + struct domain_record *d; + for (d = domainlist; d; d = d->next) + { + struct work_record *work; + for (work = d->workgrouplist; work; work = work->next) + { + struct server_record *s; + int num_servers = 0; + int num_backups = 0; + + for (s = work->serverlist; s; s = s->next) + { + if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue; + + num_servers++; + + if (strequal(myname, s->serv.name)) continue; + + if (s->serv.type & SV_TYPE_BACKUP_BROWSER) + { + num_backups++; + continue; + } + + if (s->serv.type & SV_TYPE_MASTER_BROWSER) continue; + + if (!(s->serv.type & SV_TYPE_POTENTIAL_BROWSER)) continue; + + DEBUG(3,("num servers: %d num backups: %d\n", + num_servers, num_backups)); + + /* make first server a backup server. thereafter make every + tenth server a backup server */ + if (num_backups != 0 && (num_servers+9) / num_backups > 10) + { + continue; + } + + DEBUG(3,("workgroup %s subnet %s: make backup: %s %8x \n", + work->work_group, inet_ntoa(d->bcast_ip), + s->serv.name, s->serv.type)); + + /* type 11 request from MYNAME(20) to WG(1e) for SERVER */ + do_announce_request(s->serv.name, work->work_group, + 11, 0x20, 0x1e, d->bcast_ip); + } + } + } +} + +/**************************************************************************** +find a server responsible for a workgroup, and sync browse lists +**************************************************************************/ +static BOOL sync_browse_entry(struct browse_cache_record *b) +{ + struct domain_record *d; + struct work_record *work; +/* + if (!strequal(serv_name, b->name)) + { + DEBUG(0, ("browser's netbios name (%s) does not match %s (%s)", + b->name, inet_ntoa(b->ip), serv_name)); + } +*/ + if (!(d = find_domain(b->ip))) return False; + if (!(work = find_workgroupstruct(d, b->group, False))) return False; + + sync_browse_lists(work,b->name,0x20,b->ip); + b->synced = True; + + return True; +} + + +/**************************************************************************** +search through browser list for an entry to sync with +**************************************************************************/ +void do_browser_lists(void) +{ + struct browse_cache_record *b; + static time_t last = 0; + time_t t = time(NULL); + + if (t-last < 4) return; /* don't do too many of these at once! */ + + last = t; + + /* pick any entry in the list, preferably one whose time is up */ + for (b = browserlist; b && b->next; b = b->next) + { + if (b->sync_time < t && b->synced == False) break; + } + + if (!b || b->synced || sync_browse_entry(b)) + { + /* leave entries (even ones already sync'd) for up to a minute. + this stops them getting re-sync'd too often */ + expire_browse_cache(t - 60); + } +} + + +/**************************************************************************** +find a server responsible for a workgroup, and sync browse lists +control ends up back here via response_name_query. +**************************************************************************/ +void sync_server(enum cmd_type cmd, char *serv_name, char *work_name, int name_type, + struct in_addr ip) +{ + add_browser_entry(serv_name, name_type, work_name, 0, ip); + + if (cmd == MASTER_SERVER_CHECK) + { + /* announce ourselves as a master browser to serv_name */ + do_announce_request(myname, serv_name, 13, 0x20, 0, ip); + } +} + + +/**************************************************************************** +update workgroup database from a name registration +**************************************************************************/ +void update_from_reg(char *name, int type, struct in_addr ip) +{ + /* default server type: minimum guess at requirement XXXX */ + + DEBUG(4,("update from registration: host %s ip %s type %0x\n", + name, inet_ntoa(ip), type)); + + /* workgroup types, but not a chat type */ + if (type >= 0x1b && type <= 0x1e) + { + struct work_record *work; + struct domain_record *d; + + if (!(d = find_domain(ip))) return; + if (!(work = find_workgroupstruct(d, name, False))) return; + + /* request the server to announce if on our subnet */ + if (ip_equal(bcast_ip, d->bcast_ip)) announce_request(work, ip); + + /* domain master type or master browser type */ + if (type == 0x1b || type == 0x1d) + { + struct hostent *hp = gethostbyaddr((char*)&ip, sizeof(ip), AF_INET); + if (hp) { + /* gethostbyaddr name may not match netbios name but who cares */ + add_browser_entry(hp->h_name, type, work->work_group, 120, ip); + } + } + } +} + + +/**************************************************************************** + add the default workgroup into my domain + **************************************************************************/ +void add_my_domains(void) +{ + /* add or find domain on our local subnet, in the default workgroup */ + + if (*lp_workgroup() != '*') + { + add_domain_entry(bcast_ip,Netmask,lp_workgroup(), True); + } +} + + +/**************************************************************************** + send a backup list response. + **************************************************************************/ +static void send_backup_list(char *work_name, struct nmb_name *src_name, + int info_count, int token, int info, + int name_type, struct in_addr ip) +{ + struct domain_record *d; + char outbuf[1024]; + char *p, *countptr, *nameptr; + int count = 0; + int i, j; + char *theirname = src_name->name; + + DEBUG(3,("Backup list of %s to %s: %s(%x) %s(%x)\n", + work_name, inet_ntoa(ip), + myname,0x20,theirname,0x0)); + + if (name_type == 0x1d) + { + DEBUG(4,("master browsers: ")); + } + else if (name_type == 0x1b) + { + DEBUG(4,("domain controllers: ")); + } + else + { + DEBUG(0,("backup request for unknown type %0x\n", name_type)); + return; + } + + bzero(outbuf,sizeof(outbuf)); + p = outbuf; + + CVAL(p,0) = 10; /* backup list response */ + p++; + + countptr = p; /* count pointer */ + + SSVAL(p,1,token); /* sender's workgroup index representation */ + SSVAL(p,3,info); /* XXXX clueless: info, usually zero */ + p += 5; + + nameptr = p; + + for (d = domainlist; d; d = d->next) + { + struct work_record *work; + + for (work = d->workgrouplist; work; work = work->next) + { + struct server_record *s; + + if (!strequal(work->work_group, work_name)) continue; + + for (s = work->serverlist; s; s = s->next) + { + BOOL found = False; + char *n; + + if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue; + + for (n = nameptr; n < p; n = skip_string(n, 1)) + { + if (strequal(n, s->serv.name)) found = True; + } + + if (found) continue; /* exclude names already added */ + + /* workgroup request: include all backup browsers in the list */ + /* domain request: include all domain members in the list */ + + if ((name_type == 0x1d && (s->serv.type & MASTER_TYPE)) || + (name_type == 0x1b && (s->serv.type & DOMCTL_TYPE))) + { + DEBUG(4, ("%s ", s->serv.name)); + + count++; + strcpy(p,s->serv.name); + strupper(p); + p = skip_string(p,1); + } + } + } + } + + if (count == 0) + { + DEBUG(4, ("none\n")); + return; + } + else + { + DEBUG(4, (" - count %d\n", count)); + } + + CVAL(countptr,0) = count; /* total number of backup browsers found */ + + { + int len = PTR_DIFF(p, outbuf); + + for (i = 0; i < len; i+= 16) + { + DEBUG(4, ("%3x char ", i)); + + for (j = 0; j < 16; j++) + { + unsigned char x = outbuf[i+j]; + if (x < 32 || x > 127) x = '.'; + + if (i+j >= len) break; + DEBUG(4, ("%c", x)); + } + + DEBUG(4, (" hex ", i)); + + for (j = 0; j < 16; j++) + { + if (i+j >= len) break; + DEBUG(4, (" %02x", outbuf[i+j])); + } + + DEBUG(4, ("\n")); + } + + } + send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), + myname,theirname,0x20,0,ip,myip); +} + + +/******************************************************************* + same context: scope. should check name_type as well, and makes sure + we don't process messages from ourselves + ******************************************************************/ +BOOL same_context(struct dgram_packet *dgram) +{ + if (!strequal(dgram->dest_name .scope,scope )) return(True); + if ( strequal(dgram->source_name.name ,myname)) return(True); + + return(False); +} + + +/******************************************************************* + am I listening on a name. XXXX check the type of name as well. + ******************************************************************/ +BOOL listening_name(struct work_record *work, struct nmb_name *n) +{ + if (strequal(n->name,myname) || + strequal(n->name,work->work_group) || + strequal(n->name,MSBROWSE)) + { + return(True); + } + + return(False); +} + + +/******************************************************************* + process a domain announcement frame + + Announce frames come in 3 types. Servers send host announcements + (command=1) to let the master browswer know they are + available. Master browsers send local master announcements + (command=15) to let other masters and backups that they are the + master. They also send domain announcements (command=12) to register + the domain + + The comment field of domain announcements contains the master + browser name. The servertype is used by NetServerEnum to select + resources. We just have to pass it to smbd (via browser.dat) and let + the client choose using bit masks. + ******************************************************************/ +static void process_announce(struct packet_struct *p,int command,char *buf) +{ + struct dgram_packet *dgram = &p->packet.dgram; + struct in_addr ip = dgram->header.source_ip; + struct domain_record *d = find_domain(ip); + + int update_count = CVAL(buf,0); + int ttl = IVAL(buf,1)/1000; + char *name = buf+5; + int osmajor=CVAL(buf,21); + int osminor=CVAL(buf,22); + uint32 servertype = IVAL(buf,23); + char *comment = buf+31; + struct work_record *work; + char *work_name; + char *serv_name = dgram->source_name.name; + + comment[43] = 0; + + DEBUG(3,("Announce(%d) %s(%x)",command,name,name[15])); + DEBUG(3,("%s count=%d ttl=%d OS=(%d,%d) type=%08x comment=%s\n", + namestr(&dgram->dest_name),update_count,ttl,osmajor,osminor, + servertype,comment)); + + name[15] = 0; + + if (dgram->dest_name.name_type == 0 && command == 1) + { + DEBUG(2,("Announce to nametype(0) not supported yet\n")); + return; + } + if (command == 12 && ((!strequal(dgram->dest_name.name, MSBROWSE)) || + dgram->dest_name.name_type != 0x1)) + { + DEBUG(0, ("Announce(%d) from %s should be __MSBROWSE__(1) not %s\n", + command, inet_ntoa(ip), namestr(&dgram->dest_name))); + return; + } + + if (same_context(dgram)) return; + + if (command == 12) + { + work_name = name; + } + else + { + work_name = dgram->dest_name.name; + } + + if (!(work = find_workgroupstruct(d, work_name, False))) return; + + DEBUG(4, ("workgroup %s on %s\n", work->work_group, serv_name)); + + ttl = GET_TTL(ttl); + + /* add them to our browse list */ + add_server_entry(d,work,name,servertype,ttl,comment,True); + + /* make a selection of machines become backup browsers (1 in 10) */ + tell_become_backup(); + + /* get their browse list from them and add it to ours. */ + add_browser_entry(serv_name,dgram->dest_name.name_type, + work->work_group,30,ip); +} + +/******************************************************************* + process a master announcement frame + ******************************************************************/ +static void process_master_announce(struct packet_struct *p,char *buf) +{ + struct dgram_packet *dgram = &p->packet.dgram; + struct in_addr ip = dgram->header.source_ip; + struct domain_record *d = find_domain(ip); + struct domain_record *mydomain = find_domain(bcast_ip); + char *name = buf; + struct work_record *work; + name[15] = 0; + + DEBUG(3,("Master Announce from %s (%s)\n",name,inet_ntoa(ip))); + + if (same_context(dgram)) return; + + if (!d || !mydomain) return; + + if (!lp_domain_master()) return; + + for (work = mydomain->workgrouplist; work; work = work->next) + { + if (AM_MASTER(work)) + { + /* merge browse lists with them */ + add_browser_entry(name,0x1b, work->work_group,30,ip); + } + } +} + +/******************************************************************* + process a receive backup list request + + we receive a list of servers, and we attempt to locate them all on + our local subnet, and sync browse lists with them on the workgroup + they are said to be in. + ******************************************************************/ +static void process_rcv_backup_list(struct packet_struct *p,char *buf) +{ + struct dgram_packet *dgram = &p->packet.dgram; + struct in_addr ip = dgram->header.source_ip; + int count = CVAL(buf,0); + int Index = IVAL(buf,1); /* caller's index representing workgroup */ + char *buf1; + + DEBUG(3,("Receive Backup ack for %s from %s total=%d index=%d\n", + namestr(&dgram->dest_name), inet_ntoa(ip), + count, Index)); + + if (same_context(dgram)) return; + + if (count <= 0) return; + + /* go through the list of servers attempting to sync browse lists */ + for (buf1 = buf+5; *buf1 && count; buf1 = skip_string(buf1, 1), --count) + { + struct in_addr back_ip; + struct domain_record *d; + + DEBUG(4, ("Searching for backup browser %s at %s...\n", + buf1, inet_ntoa(ip))); + + /* XXXX assume name is a DNS name NOT a netbios name. a more complete + approach is to use reply_name_query functionality to find the name */ + back_ip = *interpret_addr2(buf1); + + if (zero_ip(back_ip)) + { + DEBUG(4,("Failed to find backup browser server using DNS\n")); + continue; + } + + DEBUG(4,("Found browser server at %s\n", inet_ntoa(back_ip))); + + if ((d = find_domain(back_ip))) + { + struct domain_record *d1; + for (d1 = domainlist; d1; d1 = d1->next) + { + struct work_record *work; + for (work = d1->workgrouplist; work; work = work->next) + { + if (work->token == Index) + { + queue_netbios_packet(ClientNMB,NMB_QUERY,SERVER_CHECK, + work->work_group,0x1d,0, + False,False,back_ip); + return; + } + } + } + } + } +} + +/******************************************************************* + process a send backup list request + + A client send a backup list request to ask for a list of servers on + the net that maintain server lists for a domain. A server is then + chosen from this list to send NetServerEnum commands to to list + available servers. + + Currently samba only sends back one name in the backup list, its + own. For larger nets we'll have to add backups and send "become + backup" requests occasionally. + ******************************************************************/ +static void process_send_backup_list(struct packet_struct *p,char *buf) +{ + struct dgram_packet *dgram = &p->packet.dgram; + struct in_addr ip = dgram->header.source_ip; + struct domain_record *d; /* = find_domain(ip); */ + struct work_record *work; + + int count = CVAL(buf,0); + int token = SVAL(buf,1); /* sender's key index for the workgroup? */ + int info = SVAL(buf,3); /* XXXX don't know: some sort of info */ + int name_type = dgram->dest_name.name_type; + + DEBUG(0,("Send Backup request to %s token=%d info = %x count=%d\n", + namestr(&dgram->dest_name), token, info, count)); + + if (same_context(dgram)) return; + + if (count <= 0) return; + + if (!d) return; + + if (name_type != 0x1b && name_type != 0x1d) + { + DEBUG(0, ("backup request to wrong type %d\n", name_type)); + return; + } + + for (d = domainlist; d; d = d->next) + { + for (work = d->workgrouplist; work; work = work->next) + { + if (strequal(work->work_group, dgram->dest_name.name)) + { + DEBUG(3, ("found workgroup %s(%d)\n", + work->work_group, work->token)); + send_backup_list(work->work_group,&dgram->source_name, + count,token,info,name_type,ip); + return; + } + } + } +} + + +/******************************************************************* + process a reset browser state + + diagnostic packet: + 0x1 - stop being a master browser + 0x2 - discard browse lists, stop being a master browser, try again. + 0x4 - stop being a master browser forever. no way. ain't gonna. + + ******************************************************************/ +static void process_reset_browser(struct packet_struct *p,char *buf) +{ + struct dgram_packet *dgram = &p->packet.dgram; + int state = CVAL(buf,0); + + DEBUG(1,("Diagnostic browser reset request to %s state=0x%X\n", + namestr(&dgram->dest_name), state)); + + /* stop being a master but still deal with being a backup browser */ + if (state & 0x1) + { + struct domain_record *d; + for (d = domainlist; d; d = d->next) + { + struct work_record *work; + for (work = d->workgrouplist; work; work = work->next) + { + if (AM_MASTER(work)) + { + become_nonmaster(d,work); + } + } + } + } + + /* totally delete all servers and start afresh */ + if (state & 0x2) + { + struct domain_record *d; + for (d = domainlist; d; d = d->next) + { + struct work_record *work; + for (work=d->workgrouplist;work;work=remove_workgroup(d,work)); + } + add_my_domains(); + } + + /* stop browsing altogether. i don't think this is a good idea! */ + if (state & 0x4) + { + DEBUG(1, ("ignoring request to stop being a browser. sorry!\n")); + } +} + + +/******************************************************************* + process a announcement request + + clients send these when they want everyone to send an announcement + immediately. This can cause quite a storm of packets! + ******************************************************************/ +static void process_announce_request(struct packet_struct *p,char *buf) +{ + struct dgram_packet *dgram = &p->packet.dgram; + struct work_record *work; + struct in_addr ip = dgram->header.source_ip; + struct domain_record *d = find_domain(ip); + int token = CVAL(buf,0); + char *name = buf+1; + + name[15] = 0; + + DEBUG(3,("Announce request from %s to %s token=0x%X\n", + name,namestr(&dgram->dest_name), token)); + + if (strequal(dgram->source_name.name,myname)) return; + + if (!d) return; + + if (!ip_equal(bcast_ip, d->bcast_ip)) return; + + for (work = d->workgrouplist; work; work = work->next) + { + if (strequal(dgram->dest_name.name,work->work_group)) + { + work->needannounce = True; + } + } +} + + +/**************************************************************************** + process a domain logon packet + **************************************************************************/ +void process_logon_packet(struct packet_struct *p,char *buf,int len) +{ + struct dgram_packet *dgram = &p->packet.dgram; + struct in_addr ip = dgram->header.source_ip; + struct domain_record *d = find_domain(ip); + char *logname,*q; + char *reply_name; + BOOL add_slashes = False; + pstring outbuf; + int code,reply_code; + struct work_record *work; + + if (!d) return; + + if (!(work = find_workgroupstruct(d,dgram->dest_name.name, False))) + return; + + if (!lp_domain_logons()) { + DEBUG(3,("No domain logons\n")); + return; + } + if (!listening_name(work, &dgram->dest_name)) + { + DEBUG(4,("Not listening to that domain\n")); + return; + } + + code = SVAL(buf,0); + switch (code) { + case 0: + { + char *machine = buf+2; + char *user = skip_string(machine,1); + logname = skip_string(user,1); + reply_code = 6; + reply_name = myname; + add_slashes = True; + DEBUG(3,("Domain login request from %s(%s) user=%s\n", + machine,inet_ntoa(p->ip),user)); + } + break; + case 7: + { + char *machine = buf+2; + logname = skip_string(machine,1); + reply_code = 7; + reply_name = lp_domain_controller(); + if (!*reply_name) { + DEBUG(3,("No domain controller configured\n")); + return; + } + DEBUG(3,("GETDC request from %s(%s)\n", + machine,inet_ntoa(p->ip))); + } + break; + default: + DEBUG(3,("Unknown domain request %d\n",code)); + return; + } + + bzero(outbuf,sizeof(outbuf)); + q = outbuf; + SSVAL(q,0,reply_code); + q += 2; + if (add_slashes) { + strcpy(q,"\\\\"); + q += 2; + } + StrnCpy(q,reply_name,16); + strupper(q); + q = skip_string(q,1); + SSVAL(q,0,0xFFFF); + q += 2; + + send_mailslot_reply(logname,ClientDGRAM,outbuf,PTR_DIFF(q,outbuf), + myname,&dgram->source_name.name[0],0x20,0,p->ip,myip); + } + + +/**************************************************************************** +depending on what announce has been made, we are only going to +accept certain types of name announce. XXXX untested code + +check listening name type +****************************************************************************/ +BOOL listening_type(struct packet_struct *p, int command) +{ + struct dgram_packet *dgram = &p->packet.dgram; + int type = dgram->dest_name.name_type; + + switch (command) + { + case 1: /* host announce */ + { + if (type != 0x0 || type != 0x20) return (False); + break; + } + + case 2: /* announce request */ + { + return (True); + break; + } + + case 8: /* election */ + { + return (True); + break; + } + + case 9: /* get backup list */ + { + return (True); + break; + } + + case 10: /* receive backup list */ + { + return (True); + break; + } + + case 12: /* domain announce */ + { + if (type != 0x1b || type != 0x1c) return (False); + break; + } + + case 13: /* master announcement */ + { + if (type != 0x1d) return (False); + break; + } + + case 15: /* local master announce */ + { + if (type != 0x1c || type != 0x1d) return (False); + break; + } + } + return (True); /* we're not dealing with unknown packet types */ +} + + +/**************************************************************************** +process a browse frame +****************************************************************************/ +void process_browse_packet(struct packet_struct *p,char *buf,int len) +{ + int command = CVAL(buf,0); + switch (command) + { + case 1: /* host announce */ + case 12: /* domain announce */ + case 15: /* local master announce */ + { + process_announce(p,command,buf+1); + break; + } + + case 2: /* announce request */ + { + process_announce_request(p,buf+1); + break; + } + + case 8: /* election */ + { + process_election(p,buf+1); + break; + } + + case 9: /* get backup list */ + { + process_send_backup_list(p,buf+1); + break; + } + + case 10: /* receive backup list */ + { +#ifdef TEST_CODE + struct dgram_packet *dgram = &p->packet.dgram; + int i, j; + + DEBUG(4, ("ignoring browse packet %d from %s %s to %s\n", + command, namestr(&dgram->source_name), + inet_ntoa(p->ip), namestr(&dgram->dest_name))); + + for (i = 0; i < len; i+= 16) + { + DEBUG(4, ("%3x char ", i)); + + for (j = 0; j < 16; j++) + { + unsigned char x = buf[i+j]; + if (x < 32 || x > 127) x = '.'; + + if (i+j >= len) break; + DEBUG(4, ("%c", x)); + } + + DEBUG(4, (" hex ", i)); + + for (j = 0; j < 16; j++) + { + if (i+j >= len) break; + DEBUG(4, (" %02x", buf[i+j])); + } + + DEBUG(4, ("\n")); + } + +#endif /* TEST_CODE */ + process_rcv_backup_list(p, buf+1); + break; + } + + case 11: /* reset browser state */ + { + process_reset_browser(p, buf+1); + break; + } + + case 13: /* master announcement */ + { + process_master_announce(p,buf+1); + break; + } + +#ifdef TEST_CODE + default: + { + struct dgram_packet *dgram = &p->packet.dgram; + int i, j; + + DEBUG(4, ("ignoring browse packet %d from %s %s to %s\n", + command, namestr(&dgram->source_name), + inet_ntoa(p->ip), namestr(&dgram->dest_name))); + + for (i = 0; i < len; i+= 16) + { + DEBUG(4, ("%3x char ", i)); + + for (j = 0; j < 16; j++) + { + unsigned char x = buf[i+j]; + if (x < 32 || x > 127) x = '.'; + + if (i+j >= len) break; + DEBUG(4, ("%c", x)); + } + + DEBUG(4, (" hex ", i)); + + for (j = 0; j < 16; j++) + { + if (i+j >= len) break; + DEBUG(4, (" %02x", buf[i+j])); + } + + DEBUG(4, ("\n")); + } + + } +#endif /* TEST_CODE */ + } +} + + +/**************************************************************************** +process udp 138 datagrams +****************************************************************************/ +void process_dgram(struct packet_struct *p) +{ + char *buf; + char *buf2; + int len; + struct dgram_packet *dgram = &p->packet.dgram; + + if (dgram->header.msg_type != 0x10 && + dgram->header.msg_type != 0x11 && + dgram->header.msg_type != 0x12) { + /* don't process error packets etc yet */ + return; + } + + buf = &dgram->data[0]; + buf -= 4; /* XXXX for the pseudo tcp length - + someday I need to get rid of this */ + + if (CVAL(buf,smb_com) != SMBtrans) return; + + len = SVAL(buf,smb_vwv11); + buf2 = smb_base(buf) + SVAL(buf,smb_vwv12); + + DEBUG(3,("datagram from %s to %s for %s of type %d len=%d\n", + namestr(&dgram->source_name),namestr(&dgram->dest_name), + smb_buf(buf),CVAL(buf2,0),len)); + + + if (len <= 0) return; + + if (strequal(smb_buf(buf),"\\MAILSLOT\\BROWSE")) + { + process_browse_packet(p,buf2,len); + } else if (strequal(smb_buf(buf),"\\MAILSLOT\\NET\\NETLOGON")) { + process_logon_packet(p,buf2,len); + } +} + diff --git a/source/nmbd/nmbd.c b/source/nmbd/nmbd.c new file mode 100644 index 00000000000..222ab3f921c --- /dev/null +++ b/source/nmbd/nmbd.c @@ -0,0 +1,601 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + NBT netbios routines and daemon - version 2 + Copyright (C) Andrew Tridgell 1994-1995 + + 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. + + Revision History: + + 14 jan 96: lkcl@pires.co.uk + added multiple workgroup domain master support + +*/ + +#include "includes.h" +#include "loadparm.h" +#include "localnet.h" + +extern int DEBUGLEVEL; + +extern pstring debugf; +pstring servicesf = CONFIGFILE; + +extern pstring scope; + +int ClientNMB = -1; +int ClientDGRAM = -1; + +extern pstring myhostname; +static pstring host_file; +extern pstring myname; + +/* are we running as a daemon ? */ +static BOOL is_daemon = False; + +/* machine comment for host announcements */ +pstring ServerComment=""; + +static BOOL got_bcast = False; +static BOOL got_myip = False; +static BOOL got_nmask = False; + +/* what server type are we currently */ + +time_t StartupTime =0; + +struct in_addr ipzero; + + +/**************************************************************************** +catch a sighup +****************************************************************************/ +static int sig_hup(void) +{ + BlockSignals(True); + + DEBUG(0,("Got SIGHUP (reload not implemented)\n")); + dump_names(); + reload_services(True); + + BlockSignals(False); +#ifndef DONT_REINSTALL_SIG + signal(SIGHUP,SIGNAL_CAST sig_hup); +#endif + return(0); +} + +/**************************************************************************** +catch a sigpipe +****************************************************************************/ +static int sig_pipe(void) +{ + BlockSignals(True); + + DEBUG(0,("Got SIGPIPE\n")); + if (!is_daemon) + exit(1); + BlockSignals(False); + return(0); +} + +#if DUMP_CORE +/******************************************************************* +prepare to dump a core file - carefully! +********************************************************************/ +static BOOL dump_core(void) +{ + char *p; + pstring dname; + strcpy(dname,debugf); + if ((p=strrchr(dname,'/'))) *p=0; + strcat(dname,"/corefiles"); + mkdir(dname,0700); + sys_chown(dname,getuid(),getgid()); + chmod(dname,0700); + if (chdir(dname)) return(False); + umask(~(0700)); + +#ifndef NO_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",rlp.rlim_cur,rlp.rlim_max)); + } +#endif +#endif + + + DEBUG(0,("Dumping core in %s\n",dname)); + return(True); +} +#endif + + +/**************************************************************************** +possibly continue after a fault +****************************************************************************/ +static void fault_continue(void) +{ +#if DUMP_CORE + dump_core(); +#endif +} + +/******************************************************************* + expire old names from the namelist and server list + ******************************************************************/ +static void expire_names_and_servers(void) +{ + static time_t lastrun = 0; + time_t t = time(NULL); + + if (!lastrun) lastrun = t; + if (t < lastrun + 5) return; + lastrun = t; + + expire_names(t); + expire_servers(t); +} + +/***************************************************************************** + reload the services file + **************************************************************************/ +BOOL reload_services(BOOL test) +{ + BOOL ret; + extern fstring remote_machine; + + strcpy(remote_machine,"nmbd"); + + if (lp_loaded()) + { + pstring fname; + strcpy(fname,lp_configfile()); + if (file_exist(fname,NULL) && !strcsequal(fname,servicesf)) + { + strcpy(servicesf,fname); + test = False; + } + } + + if (test && !lp_file_list_changed()) + return(True); + + ret = lp_load(servicesf,True); + + /* perhaps the config filename is now set */ + if (!test) { + DEBUG(3,("services not loaded\n")); + reload_services(True); + } + + return(ret); +} + + + +/**************************************************************************** +load a netbios hosts file +****************************************************************************/ +static void load_hosts_file(char *fname) +{ + FILE *f = fopen(fname,"r"); + pstring line; + if (!f) { + DEBUG(2,("Can't open lmhosts file %s\n",fname)); + return; + } + + while (!feof(f)) + { + if (!fgets_slash(line,sizeof(pstring),f)) continue; + + if (*line == '#') continue; + + { + BOOL group=False; + + pstring ip,name,mask,flags,extra; + + char *ptr; + int count = 0; + struct in_addr ipaddr; + struct in_addr ipmask; + enum name_source source = LMHOSTS; + + strcpy(ip,""); + strcpy(name,""); + strcpy(mask,""); + strcpy(flags,""); + strcpy(extra,""); + + ptr = line; + + if (next_token(&ptr,ip ,NULL)) ++count; + if (next_token(&ptr,name ,NULL)) ++count; + if (next_token(&ptr,mask ,NULL)) ++count; + if (next_token(&ptr,flags,NULL)) ++count; + if (next_token(&ptr,extra,NULL)) ++count; + + if (count <= 0) continue; + + if (count > 0 && count < 2) { + DEBUG(0,("Ill formed hosts line [%s]\n",line)); + continue; + } + + /* work out if we need to shuffle the tokens along due to the + optional subnet mask argument */ + + if (strchr(mask, 'G') || strchr(mask, 'S') || strchr(mask, 'M')) { + strcpy(flags, mask ); + /* default action for no subnet mask */ + strcpy(mask, inet_ntoa(Netmask)); + } + + DEBUG(4, ("lmhost entry: %s %s %s %s\n", ip, name, mask, flags)); + + if (strchr(flags,'G') || strchr(flags,'S')) + group = True; + + if (strchr(flags,'M') && !group) { + source = SELF; + strcpy(myname,name); + } + + ipaddr = *interpret_addr2(ip); + ipmask = *interpret_addr2(mask); + + if (group) { + add_domain_entry(ipaddr, ipmask, name, True); + } else { + add_netbios_entry(name,0x20,NB_ACTIVE,0,source,ipaddr); + } + } + } + + fclose(f); +} + + +/**************************************************************************** + The main select loop. + ***************************************************************************/ +static void process(void) +{ + BOOL run_election; + + while (True) + { + run_election = check_elections(); + listen_for_packets(run_election); + + run_packet_queue(); + run_elections(); + + announce_host(); + announce_backup(); + announce_master(); + + expire_names_and_servers(); + expire_netbios_response_entries(time(NULL)-10); + + write_browse_list(); + do_browser_lists(); + check_master_browser(); + } +} + + +/**************************************************************************** + open the socket communication +****************************************************************************/ +static BOOL open_sockets(BOOL isdaemon, int port) +{ + struct hostent *hp; + + /* get host info */ + if ((hp = Get_Hostbyname(myhostname)) == 0) { + DEBUG(0,( "Get_Hostbyname: Unknown host. %s\n",myhostname)); + return False; + } + + if (isdaemon) + ClientNMB = open_socket_in(SOCK_DGRAM, port,0); + else + ClientNMB = 0; + + ClientDGRAM = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3); + + if (ClientNMB == -1) + return(False); + + signal(SIGPIPE, SIGNAL_CAST sig_pipe); + + set_socket_options(ClientNMB,"SO_BROADCAST"); + set_socket_options(ClientDGRAM,"SO_BROADCAST"); + + DEBUG(3,("Sockets opened.\n")); + return True; +} + + +/******************************************************************* + check that a IP, bcast and netmask and consistent. Must be a 1s + broadcast + ******************************************************************/ +static BOOL ip_consistent(struct in_addr ip,struct in_addr bcast, struct in_addr nmask) +{ + unsigned long a_ip,a_bcast,a_nmask; + + a_ip = ntohl(ip.s_addr); + a_bcast = ntohl(bcast.s_addr); + a_nmask = ntohl(nmask.s_addr); + + /* check the netmask is sane */ + if (((a_nmask>>24)&0xFF) != 0xFF) { + DEBUG(0,("Insane netmask %s\n",inet_ntoa(nmask))); + return(False); + } + + /* check the IP and bcast are on the same net */ + if ((a_ip&a_nmask) != (a_bcast&a_nmask)) { + DEBUG(0,("IP and broadcast are on different nets!\n")); + return(False); + } + + /* check the IP and bcast are on the same net */ + if ((a_bcast|a_nmask) != 0xFFFFFFFF) { + DEBUG(0,("Not a ones based broadcast %s\n",inet_ntoa(bcast))); + return(False); + } + + return(True); +} + + +/**************************************************************************** + initialise connect, service and file structs +****************************************************************************/ +static BOOL init_structs() +{ + if (!get_myname(myhostname,got_myip?NULL:&myip)) + return(False); + + /* Read the broadcast address from the interface */ + { + struct in_addr ip0,ip1,ip2; + + ip0 = myip; + + if (!(got_bcast && got_nmask)) + { + get_broadcast(&ip0,&ip1,&ip2); + + if (!got_myip) + myip = ip0; + + if (!got_bcast) + bcast_ip = ip1; + + if (!got_nmask) + Netmask = ip2; + } + + DEBUG(1,("Using IP %s ",inet_ntoa(myip))); + DEBUG(1,("broadcast %s ",inet_ntoa(bcast_ip))); + DEBUG(1,("netmask %s\n",inet_ntoa(Netmask))); + + if (!ip_consistent(myip,bcast_ip,Netmask)) { + DEBUG(0,("WARNING: The IP address, broadcast and Netmask are not consistent\n")); + DEBUG(0,("You are likely to experience problems with this setup!\n")); + } + } + + if (! *myname) { + char *p; + strcpy(myname,myhostname); + p = strchr(myname,'.'); + if (p) *p = 0; + } + + return True; +} + +/**************************************************************************** +usage on the program +****************************************************************************/ +static void usage(char *pname) +{ + DEBUG(0,("Incorrect program usage - is the command line correct?\n")); + + printf("Usage: %s [-n name] [-B bcast address] [-D] [-p port] [-d debuglevel] [-l log basename]\n",pname); + 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-n netbiosname. the netbios name to advertise for this host\n"); + printf("\t-B broadcast address the address to use for broadcasts\n"); + printf("\t-N netmask the netmask to use for subnet determination\n"); + printf("\t-H hosts file load a netbios hosts file\n"); + printf("\t-G group name add a group name to be part of\n"); + printf("\t-I ip-address override the IP address\n"); + printf("\t-C comment sets the machine comment that appears in browse lists\n"); + printf("\n"); +} + + +/**************************************************************************** + main program + **************************************************************************/ + int main(int argc,char *argv[]) +{ + int port = NMB_PORT; + int opt; + extern FILE *dbf; + extern char *optarg; + + *host_file = 0; + + StartupTime = time(NULL); + + TimeInit(); + + strcpy(debugf,NMBLOGFILE); + + setup_logging(argv[0],False); + + charset_initialise(); + + ipzero = *interpret_addr2("0.0.0.0"); + +#ifdef LMHOSTSFILE + strcpy(host_file,LMHOSTSFILE); +#endif + + /* this is for people who can't start the program correctly */ + while (argc > 1 && (*argv[1] != '-')) { + argv++; + argc--; + } + + fault_setup(fault_continue); + + signal(SIGHUP,SIGNAL_CAST sig_hup); + + bcast_ip = ipzero; + myip = ipzero; + + while ((opt = getopt (argc, argv, "s:T:I:C:bAi:B:N:Rn:l:d:Dp:hSH:G:")) != EOF) + { + switch (opt) + { + case 's': + strcpy(servicesf,optarg); + break; + case 'C': + strcpy(ServerComment,optarg); + break; + case 'G': + if (got_bcast && got_nmask) { + add_domain_entry(bcast_ip,Netmask,optarg, True); + } else { + DEBUG(0, ("Warning: option -G %s added before broadcast and netmask.\n", + optarg)); + DEBUG(0, ("Assuming default values: bcast %s netmask %s\n", + inet_ntoa(bcast_ip), inet_ntoa(Netmask))); /* (i hope) */ + } + break; + case 'H': + strcpy(host_file,optarg); + break; + case 'I': + myip = *interpret_addr2(optarg); + got_myip = True; + break; + case 'B': + bcast_ip = *interpret_addr2(optarg); + got_bcast = True; + break; + case 'N': + Netmask = *interpret_addr2(optarg); + got_nmask = True; + break; + case 'n': + strcpy(myname,optarg); + break; + case 'l': + sprintf(debugf,"%s.nmb",optarg); + break; + case 'i': + strcpy(scope,optarg); + strupper(scope); + break; + case 'D': + is_daemon = True; + break; + case 'd': + DEBUGLEVEL = atoi(optarg); + break; + case 'p': + port = atoi(optarg); + break; + case 'h': + usage(argv[0]); + exit(0); + break; + default: + if (!is_a_socket(0)) { + usage(argv[0]); + } + break; + } + } + + DEBUG(1,("%s netbios nameserver version %s started\n",timestring(),VERSION)); + DEBUG(1,("Copyright Andrew Tridgell 1994\n")); + + init_structs(); + + if (!reload_services(False)) + return(-1); + + 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(2,("%s becoming a daemon\n",timestring())); + become_daemon(); + } + + DEBUG(3,("Opening sockets %d\n", port)); + + if (!open_sockets(is_daemon,port)) return 1; + + if (*host_file) { + load_hosts_file(host_file); + DEBUG(3,("Loaded hosts file\n")); + } + + if (!*ServerComment) + strcpy(ServerComment,"Samba %v"); + string_sub(ServerComment,"%v",VERSION); + string_sub(ServerComment,"%h",myhostname); + + add_my_names(); + add_my_domains(); + + DEBUG(3,("Checked names\n")); + + write_browse_list(); + + DEBUG(3,("Dumped names\n")); + + process(); + close_sockets(); + + if (dbf) + fclose(dbf); + return(0); +} diff --git a/source/nmbsync.c b/source/nmbsync.c index 5a77d6cc486..5a6c07086ab 100644 --- a/source/nmbsync.c +++ b/source/nmbsync.c @@ -22,282 +22,162 @@ #include "includes.h" #include "loadparm.h" -#include "nameserv.h" +#include "localnet.h" + extern int DEBUGLEVEL; -struct server_record *add_server_entry(char *name,int servertype, - int ttl,char *comment,BOOL replace); +extern pstring myname; +extern struct in_addr bcast_ip; +extern struct in_addr Netmask; + +extern int name_type; +extern int max_protocol; +extern struct in_addr dest_ip; +extern int pid; +extern int gid; +extern int uid; +extern int mid; +extern BOOL got_pass; +extern BOOL have_ip; +extern pstring workgroup; +extern pstring service; +extern pstring desthost; +extern BOOL connect_as_ipc; +/**************************************************************************** +fudge for getpass function +****************************************************************************/ +char *getsmbpass(char *pass) +{ + return "dummy"; /* return anything: it should be ignored anyway */ +} /**************************************************************************** -call a remote api +adds information retrieved from a NetServerEnum call ****************************************************************************/ -static BOOL call_remote_api(int fd,int cnum,int uid,int timeout, - char *inbuf,char *outbuf, - int prcnt,int drcnt, - int mprcnt,int mdrcnt, - int *rprcnt,int *rdrcnt, - char *param,char *data, - char **rparam,char **rdata) +static BOOL add_info(struct domain_record *d, struct work_record *work, int servertype) { - char *p1,*p2; - - /* send a SMBtrans command */ - bzero(outbuf,smb_size); - set_message(outbuf,14,0,True); - CVAL(outbuf,smb_com) = SMBtrans; - SSVAL(outbuf,smb_tid,cnum); - SSVAL(outbuf,smb_uid,uid); - - p1 = smb_buf(outbuf); - strcpy(p1,"\\PIPE\\LANMAN"); - p1 = skip_string(p1,1); - p2 = p1 + prcnt; - - if (prcnt > 0) - memcpy(p1,param,prcnt); - if (drcnt > 0) - memcpy(p2,data,drcnt); - - SSVAL(outbuf,smb_vwv0,prcnt); /* param count */ - SSVAL(outbuf,smb_vwv1,drcnt); /* data count */ - SSVAL(outbuf,smb_vwv2,mprcnt); /* mprcnt */ - SSVAL(outbuf,smb_vwv3,mdrcnt); /* mdrcnt */ - SSVAL(outbuf,smb_vwv4,0); /* msrcnt */ - SSVAL(outbuf,smb_vwv5,0); /* flags */ - SSVAL(outbuf,smb_vwv9,prcnt); /* pscnt */ - SSVAL(outbuf,smb_vwv10,smb_offset(p1,outbuf)); /* psoff */ - SSVAL(outbuf,smb_vwv11,drcnt); /* dscnt */ - SSVAL(outbuf,smb_vwv12,smb_offset(p2,outbuf)); /* dsoff */ - CVAL(outbuf,smb_vwv13) = 0; /* suwcnt */ - - set_message(outbuf,14,PTR_DIFF(p2+drcnt,smb_buf(outbuf)),False); - - send_smb(fd,outbuf); - - if (receive_smb(fd,inbuf,timeout) && - CVAL(inbuf,smb_rcls) == 0) - { - if (rparam) - *rparam = inbuf+4 + SVAL(inbuf,smb_vwv4); - if (rdata) - *rdata = inbuf+4 + SVAL(inbuf,smb_vwv7); - if (rprcnt) - *rprcnt = SVAL(inbuf,smb_vwv3); - if (rdrcnt) - *rdrcnt = SVAL(inbuf,smb_vwv6); - return(True); - } - - return(False); + char *rparam = NULL; + char *rdata = NULL; + int rdrcnt,rprcnt; + char *p; + pstring param; + int uLevel = 1; + int count = -1; + + /* now send a SMBtrans command with api ServerEnum? */ + p = param; + SSVAL(p,0,0x68); /* api number */ + p += 2; + strcpy(p,"WrLehDz"); + p = skip_string(p,1); + + strcpy(p,"B16BBDz"); + + p = skip_string(p,1); + SSVAL(p,0,uLevel); + SSVAL(p,2,0x2000); /* buf length */ + p += 4; + SIVAL(p,0,servertype); + p += 4; + + strcpy(p, work->work_group); + p = skip_string(p,1); + + if (cli_call_api(PTR_DIFF(p,param),0, 8,10000, + &rprcnt,&rdrcnt, param,NULL, + &rparam,&rdata)) + { + int res = SVAL(rparam,0); + int converter=SVAL(rparam,2); + int i; + + if (res == 0) + { + count=SVAL(rparam,4); + p = rdata; + + for (i = 0;i < count;i++, p += 26) + { + char *sname = p; + uint32 stype = IVAL(p,18); + int comment_offset = IVAL(p,22) & 0xFFFF; + char *cmnt = comment_offset?(rdata+comment_offset-converter):""; + + struct work_record *w = work; + + DEBUG(4, ("\t%-16.16s %08x %s\n", sname, stype, cmnt)); + + if (stype & SV_TYPE_DOMAIN_ENUM) + { + /* creates workgroup on remote subnet */ + if ((w = find_workgroupstruct(d,sname, False))) + { + if (ip_equal(bcast_ip, d->bcast_ip)) + { + announce_request(w, d->bcast_ip); + } + } + } + + add_server_entry(d,w,sname,stype,lp_max_ttl(),cmnt,False); + } + } + } + + if (rparam) free(rparam); + if (rdata) free(rdata); + + return(True); } /******************************************************************* - synchronise browse lists with another browse server + synchronise browse lists with another browse server. + + log in on the remote server's SMB port to their IPC$ service, + do a NetServerEnum and update our server and workgroup databases. ******************************************************************/ -void sync_browse_lists(char *name,int name_type,char *myname, - char *domain,struct in_addr ip) +void sync_browse_lists(struct work_record *work, char *name, int nm_type, + struct in_addr ip) { - char *protocol = "LM1.2X002"; - char *service = "IPC$"; - char *dev = "IPC"; - int timeout=2000; - char *inbuf=NULL; - pstring outbuf; - char *p; - int len; - uint32 sesskey; - int cnum,uid; - BOOL ret; - - int fd = open_socket_out(SOCK_STREAM, &ip, SMB_PORT); - if (fd < 0) { - DEBUG(3,("Failed to connect to %s at %s\n",name,inet_ntoa(ip))); - return; - } - - if (!(inbuf = (char *)malloc(0xFFFF+1024))) return; - - /* put in the destination name */ - len = 4; - p = outbuf+len; - name_mangle(name,p,name_type); - len += name_len(p); - - /* and my name */ - p = outbuf+len; - name_mangle(myname,p,0x20); - len += name_len(p); - - _smb_setlen(outbuf,len); - CVAL(outbuf,0) = 0x81; - - send_smb(fd,outbuf); - receive_smb(fd,inbuf,5000); - - bzero(outbuf,smb_size); - - /* setup the protocol string */ - set_message(outbuf,0,strlen(protocol)+2,True); - p = smb_buf(outbuf); - *p++ = 2; - strcpy(p,protocol); - - CVAL(outbuf,smb_com) = SMBnegprot; - CVAL(outbuf,smb_flg) = 0x8; - SSVAL(outbuf,smb_flg2,0x1); - - send_smb(fd,outbuf); - bzero(inbuf,smb_size); - ret = receive_smb(fd,inbuf,timeout); - - if (!ret || CVAL(inbuf,smb_rcls) || SVAL(inbuf,smb_vwv0)) { - DEBUG(3,("%s rejected the protocol\n",name)); - close(fd); - if (inbuf) free(inbuf); - return; - } - - sesskey = IVAL(inbuf,smb_vwv6); - - bzero(outbuf,smb_size); - set_message(outbuf,10,2,True); - CVAL(outbuf,smb_com) = SMBsesssetupX; - - CVAL(outbuf,smb_vwv0) = 0xFF; - SSVAL(outbuf,smb_vwv2,0xFFFF); - SSVAL(outbuf,smb_vwv3,2); - SSVAL(outbuf,smb_vwv4,1); - SIVAL(outbuf,smb_vwv5,sesskey); - SSVAL(outbuf,smb_vwv7,1); - - send_smb(fd,outbuf); - bzero(inbuf,smb_size); - ret = receive_smb(fd,inbuf,timeout); - if (!ret || CVAL(inbuf,smb_rcls)) { - DEBUG(3,("%s rejected session setup\n",name)); - close(fd); - if (inbuf) free(inbuf); - return; - } - - uid = SVAL(inbuf,smb_uid); - - bzero(outbuf,smb_size); - set_message(outbuf,4,2 + (2 + strlen(name) + 1 + strlen(service)) + - 1 + strlen(dev),True); - CVAL(outbuf,smb_com) = SMBtconX; - SSVAL(outbuf,smb_uid,uid); - - SSVAL(outbuf,smb_vwv0,0xFF); - SSVAL(outbuf,smb_vwv3,1); - - p = smb_buf(outbuf) + 1; - strcpy(p, "\\\\"); - strcat(p, name); - strcat(p, "\\"); - strcat(p,service); - p = skip_string(p,1); - strcpy(p,dev); - - send_smb(fd,outbuf); - bzero(inbuf,smb_size); - ret = receive_smb(fd,inbuf,timeout); - if (!ret || CVAL(inbuf,smb_rcls)) { - DEBUG(3,("%s rejected IPC connect (%d,%d)\n",name, - CVAL(inbuf,smb_rcls),SVAL(inbuf,smb_err))); - close(fd); - if (inbuf) free(inbuf); - return; - } - - cnum = SVAL(inbuf,smb_tid); - - /* now I need to send a NetServerEnum */ - { - fstring param; - uint32 *typep; - char *rparam,*rdata; - - p = param; - SSVAL(p,0,0x68); /* api number */ - p += 2; - strcpy(p,"WrLehDz"); - p = skip_string(p,1); - - strcpy(p,"B16BBDz"); - - p = skip_string(p,1); - SSVAL(p,0,1); /* level 1 */ - SSVAL(p,2,0xFFFF - 500); /* buf length */ - p += 4; - typep = (uint32 *)p; - p += 4; - strcpy(p,domain); - strupper(p); - p = skip_string(p,1); - - SIVAL(typep,0,0x80000000); /* domain list */ - - if (call_remote_api(fd,cnum,uid,timeout,inbuf,outbuf, - PTR_DIFF(p,param),0, - 8,0xFFFF - 500, - NULL,NULL, - param,NULL, - &rparam,&rdata) && SVAL(rparam,0)==0) - { - int converter=SVAL(rparam,2); - int count=SVAL(rparam,4); - int i; - char *p2 = rdata; - for (i=0;i<count;i++) { - char *sname = p2; - uint32 type = IVAL(p2,18); - int comment_offset = IVAL(p2,22) & 0xFFFF; - char *comment = comment_offset?(rdata+comment_offset-converter):""; - - add_server_entry(sname,type,lp_max_ttl(),comment,False); - p2 += 26; - } - } - - SIVAL(typep,0,0xFFFFFFFF); /* server list */ - - if (call_remote_api(fd,cnum,uid,timeout,inbuf,outbuf, - PTR_DIFF(p,param),0, - 8,0xFFFF - 500, - NULL,NULL, - param,NULL, - &rparam,&rdata) && SVAL(rparam,0)==0) - { - int converter=SVAL(rparam,2); - int count=SVAL(rparam,4); - int i; - - p = rdata; - for (i=0;i<count;i++) { - char *sname = p; - uint32 type = IVAL(p,18); - int comment_offset = IVAL(p,22) & 0xFFFF; - char *comment = comment_offset?(rdata+comment_offset-converter):""; - - add_server_entry(sname,type,lp_max_ttl(),comment,False); - p += 26; - } - } - } - - /* close up */ - bzero(outbuf,smb_size); - set_message(outbuf,0,0,True); - CVAL(outbuf,smb_com) = SMBtdis; - SSVAL(outbuf,smb_uid,uid); - SSVAL(outbuf,smb_tid,cnum); - send_smb(fd,outbuf); - receive_smb(fd,inbuf,1000); - - close(fd); - if (inbuf) free(inbuf); + struct domain_record *d; + pid = getpid(); + uid = getuid(); + gid = getgid(); + mid = pid + 100; + name_type = nm_type; + + got_pass = True; + + DEBUG(4, ("sync browse lists with %s for %s %s\n", + work->work_group, name, inet_ntoa(ip))); + + strcpy(workgroup,work->work_group); + strcpy(desthost,name); + dest_ip = ip; + + if (zero_ip(dest_ip)) return; + have_ip = True; + + if (!(d = find_domain(ip))) return; + + connect_as_ipc = True; + + /* connect as server and get domains, then servers */ + + sprintf(service,"\\\\%s\\IPC$", name); + strupper(service); + + if (cli_open_sockets(SMB_PORT)) + { + if (cli_send_login(NULL,NULL,True,True)) + { + add_info(d, work, SV_TYPE_DOMAIN_ENUM); + add_info(d, work, SV_TYPE_ALL&~SV_TYPE_DOMAIN_ENUM); + } + + close_sockets(); + } } diff --git a/source/param/loadparm.c b/source/param/loadparm.c index 3426a4022c4..1e488ec90da 100644 --- a/source/param/loadparm.c +++ b/source/param/loadparm.c @@ -131,8 +131,8 @@ typedef struct char *szUsernameMap; char *szCharacterSet; char *szLogonScript; - char *szWINSserver; char *szSmbrun; + char *szWINSserver; int max_log_size; int mangled_stack; int max_xmit; @@ -148,6 +148,7 @@ typedef struct int syslog; int os_level; int max_ttl; + BOOL bWINSsupport; BOOL bPreferredMaster; BOOL bDomainMaster; BOOL bDomainLogons; @@ -396,7 +397,6 @@ struct parm_struct {"username map", P_STRING, P_GLOBAL, &Globals.szUsernameMap, NULL}, {"character set", P_STRING, P_GLOBAL, &Globals.szCharacterSet, handle_character_set}, {"logon script", P_STRING, P_GLOBAL, &Globals.szLogonScript, NULL}, - {"wins server", P_STRING, P_GLOBAL, &Globals.szWINSserver, NULL}, {"max log size", P_INTEGER, P_GLOBAL, &Globals.max_log_size, NULL}, {"mangled stack", P_INTEGER, P_GLOBAL, &Globals.mangled_stack, NULL}, {"max mux", P_INTEGER, P_GLOBAL, &Globals.max_mux, NULL}, @@ -413,6 +413,8 @@ struct parm_struct #endif /* KANJI */ {"os level", P_INTEGER, P_GLOBAL, &Globals.os_level, NULL}, {"max ttl", P_INTEGER, P_GLOBAL, &Globals.max_ttl, NULL}, + {"wins support", P_BOOL, P_GLOBAL, &Globals.bWINSsupport, NULL}, + {"wins server", P_STRING, P_GLOBAL, &Globals.szWINSserver, NULL}, {"preferred master", P_BOOL, P_GLOBAL, &Globals.bPreferredMaster, NULL}, {"prefered master", P_BOOL, P_GLOBAL, &Globals.bPreferredMaster, NULL}, {"domain master", P_BOOL, P_GLOBAL, &Globals.bDomainMaster, NULL}, @@ -577,6 +579,7 @@ static void init_globals(void) Globals.bDomainLogons = False; Globals.bBrowseList = True; Globals.bProxyNameResolution = True; + Globals.bWINSsupport = True; #ifdef KANJI coding_system = interpret_coding_system (KANJI, SJIS_CODE); @@ -702,6 +705,7 @@ FN_GLOBAL_STRING(lp_character_set,&Globals.szCharacterSet) FN_GLOBAL_STRING(lp_logon_script,&Globals.szLogonScript) FN_GLOBAL_STRING(lp_wins_server,&Globals.szWINSserver) +FN_GLOBAL_BOOL(lp_wins_support,&Globals.bWINSsupport) FN_GLOBAL_BOOL(lp_domain_master,&Globals.bDomainMaster) FN_GLOBAL_BOOL(lp_domain_logons,&Globals.bDomainLogons) FN_GLOBAL_BOOL(lp_preferred_master,&Globals.bPreferredMaster) diff --git a/source/param/params.c b/source/param/params.c index b9d61382a18..d5d841dceb8 100644 --- a/source/param/params.c +++ b/source/param/params.c @@ -63,23 +63,74 @@ the other = 3 static char *pszParmFile = NULL; extern int DEBUGLEVEL; -/* local prototypes */ -static BOOL enumerate_parameters(FILE *infile, PM_PARMFUNC pfunc); -static BOOL enumerate_sections(FILE *infile, - PM_SECFUNC sfunc, PM_PARMFUNC pfunc); -/* prototypes for local toolbox functions */ -static void trimleft(char *psz); -static void trimright(char *psz); -static void collapse_spaces(char *psz); -static int firstnonwhite(char *psz); +/************************************************************************** +Strip all leading whitespace from a string. +**************************************************************************/ +static void trimleft(char *psz) +{ + char *pszDest; + + pszDest = psz; + if (psz != NULL) + { + while (*psz != '\0' && isspace(*psz)) + psz++; + while (*psz != '\0') + *pszDest++ = *psz++; + *pszDest = '\0'; + } +} + +/************************************************************************** +Strip all trailing whitespace from a string. +**************************************************************************/ +static void trimright(char *psz) +{ + char *pszTemp; + + if (psz != NULL && psz[0] != '\0') + { + pszTemp = psz + strlen(psz) - 1; + while (isspace(*pszTemp)) + *pszTemp-- = '\0'; + } +} + +/*********************************************************************** +Collapse each whitespace area in a string to a single space. +***********************************************************************/ +static void collapse_spaces(char *psz) +{ + while (*psz) + if (isspace(*psz)) + { + *psz++ = ' '; + trimleft(psz); + } + else + psz++; +} + +/************************************************************************** +Return the value of the first non-white character in the specified string. +The terminating NUL counts as non-white for the purposes of this function. +Note - no check for a NULL string! What would we return? +**************************************************************************/ +static int firstnonwhite(char *psz) +{ + while (isspace(*psz) && (*psz != '\0')) + psz++; + return (*psz); +} + /************************************************************************** Identifies all parameters in the current section, calls the parameter function for each. Ignores comment lines, stops and backs up in file when a section is encountered. Returns True on success, False on error. **************************************************************************/ -static BOOL enumerate_parameters(FILE *fileIn, PM_PARMFUNC pfunc) +static BOOL enumerate_parameters(FILE *fileIn, BOOL (*pfunc)(char *,char *)) { pstring szBuf; char *pszTemp; @@ -186,8 +237,8 @@ Returns True on success, False on failure. Note that the section and parameter names will have all internal whitespace areas collapsed to a single space for processing. **************************************************************************/ -static BOOL enumerate_sections(FILE *fileIn, - PM_SECFUNC sfunc, PM_PARMFUNC pfunc) +static BOOL enumerate_sections(FILE *fileIn, + BOOL (*sfunc)(char *),BOOL (*pfunc)(char *,char *)) { pstring szBuf; BOOL bRetval; @@ -246,7 +297,7 @@ Process the passed parameter file. Returns True if successful, else False. **************************************************************************/ -BOOL pm_process(char *pszFileName, PM_SECFUNC sfunc, PM_PARMFUNC pfunc) +BOOL pm_process(char *pszFileName,BOOL (*sfunc)(char *),BOOL (*pfunc)(char *,char *)) { FILE *fileIn; BOOL bRetval; @@ -274,62 +325,3 @@ BOOL pm_process(char *pszFileName, PM_SECFUNC sfunc, PM_PARMFUNC pfunc) } -/************************************************************************** -Strip all leading whitespace from a string. -**************************************************************************/ -static void trimleft(char *psz) -{ - char *pszDest; - - pszDest = psz; - if (psz != NULL) - { - while (*psz != '\0' && isspace(*psz)) - psz++; - while (*psz != '\0') - *pszDest++ = *psz++; - *pszDest = '\0'; - } -} - -/************************************************************************** -Strip all trailing whitespace from a string. -**************************************************************************/ -static void trimright(char *psz) -{ - char *pszTemp; - - if (psz != NULL && psz[0] != '\0') - { - pszTemp = psz + strlen(psz) - 1; - while (isspace(*pszTemp)) - *pszTemp-- = '\0'; - } -} - -/*********************************************************************** -Collapse each whitespace area in a string to a single space. -***********************************************************************/ -static void collapse_spaces(char *psz) -{ - while (*psz) - if (isspace(*psz)) - { - *psz++ = ' '; - trimleft(psz); - } - else - psz++; -} - -/************************************************************************** -Return the value of the first non-white character in the specified string. -The terminating NUL counts as non-white for the purposes of this function. -Note - no check for a NULL string! What would we return? -**************************************************************************/ -static int firstnonwhite(char *psz) -{ - while (isspace(*psz) && (*psz != '\0')) - psz++; - return (*psz); -} diff --git a/source/params.h b/source/params.h index 253eaa4e7ae..b3ccdf74d97 100644 --- a/source/params.h +++ b/source/params.h @@ -32,14 +32,9 @@ Prototypes and definitions for PARAMS.C. #include <stdio.h> #include "smb.h" -typedef BOOL (* PM_PARMFUNC)(char *pszParmName, char *pszParmValue); -typedef BOOL (* PM_SECFUNC)(char *pszSectionName); - #define PM_NOFILE 1 #define PM_NOFILENAME 2 #define PM_FILEERROR 3 -extern BOOL pm_process(char *pszFileName, PM_SECFUNC sfunc, PM_PARMFUNC pfunc); - #endif diff --git a/source/passdb/smbpass.c b/source/passdb/smbpass.c index ca86d95618d..35816c5c520 100644 --- a/source/passdb/smbpass.c +++ b/source/passdb/smbpass.c @@ -297,8 +297,7 @@ get_smbpwnam(char *name) return NULL; } #else -void -smbpass_dummy(void) + void smbpass_dummy(void) { } /* To avoid compiler complaints */ #endif diff --git a/source/script/mkproto.awk b/source/script/mkproto.awk new file mode 100644 index 00000000000..4bf0d3c37df --- /dev/null +++ b/source/script/mkproto.awk @@ -0,0 +1,39 @@ +# generate prototypes for Samba C code + + +BEGIN { + inheader=0; +} + +{ + if (inheader) { + if (match($0,"[)][ \t]*$")) { + inheader = 0; + printf "%s;\n",$0; + } else { + printf "%s\n",$0; + } + next; + } +} + +/^static|^extern/ || !/^[a-zA-Z]/ || /[;]/ { + next; +} + +!/^unsigned|^mode_t|^DIR|^user|^int|^char|^uint|^struct|^BOOL|^void|^time/ { + next; +} + + +/[(].*[)][ \t]*$/ { + printf "%s;\n",$0; + next; +} + +/[(]/ { + inheader=1; + printf "%s\n",$0; + next; +} + diff --git a/source/smbd/password.c b/source/smbd/password.c index b8111fc739a..31d91912714 100644 --- a/source/smbd/password.c +++ b/source/smbd/password.c @@ -1258,7 +1258,7 @@ BOOL server_cryptkey(char *buf) fstring desthost; struct in_addr dest_ip; extern struct in_addr myip; - int port = 139; + int port = SMB_PORT; BOOL ret; if (password_client >= 0) diff --git a/source/smbd/reply.c b/source/smbd/reply.c index 68376baaf38..4472e120aaa 100644 --- a/source/smbd/reply.c +++ b/source/smbd/reply.c @@ -1928,11 +1928,11 @@ int reply_close(char *inbuf,char *outbuf) mtime = make_unix_date3(inbuf+smb_vwv1); - close_file(fnum); - /* try and set the date */ set_filetime(Files[fnum].name,mtime); + close_file(fnum); + /* We have a cached error */ if(eclass || err) return(ERROR(eclass,err)); @@ -1976,10 +1976,10 @@ int reply_writeclose(char *inbuf,char *outbuf) nwritten = write_file(fnum,data,numtowrite); - close_file(fnum); - set_filetime(Files[fnum].name,mtime); + close_file(fnum); + DEBUG(3,("%s writeclose fnum=%d cnum=%d num=%d wrote=%d (numopen=%d)\n", timestring(),fnum,cnum,numtowrite,nwritten, Connections[cnum].num_files_open)); diff --git a/source/smbd/server.c b/source/smbd/server.c index b8e3cba61c2..a8e1dad8382 100644 --- a/source/smbd/server.c +++ b/source/smbd/server.c @@ -139,31 +139,20 @@ mode_t unix_mode(int cnum,int dosmode) int dos_mode(int cnum,char *path,struct stat *sbuf) { int result = 0; + extern struct current_user current_user; -#if OLD_DOS_MODE - if (!CAN_WRITE(cnum) || !((sbuf->st_mode & S_IWOTH) || - Connections[cnum].admin_user || - ((sbuf->st_mode & S_IWUSR) && - Connections[cnum].uid==sbuf->st_uid) || - ((sbuf->st_mode & S_IWGRP) && - in_group(sbuf->st_gid,Connections[cnum].gid, - Connections[cnum].ngroups, - Connections[cnum].igroups)))) - result |= aRONLY; -#else if (CAN_WRITE(cnum) && !lp_alternate_permissions(SNUM(cnum))) { if (!((sbuf->st_mode & S_IWOTH) || Connections[cnum].admin_user || - ((sbuf->st_mode & S_IWUSR) && Connections[cnum].uid==sbuf->st_uid) || + ((sbuf->st_mode & S_IWUSR) && current_user.uid==sbuf->st_uid) || ((sbuf->st_mode & S_IWGRP) && - in_group(sbuf->st_gid,Connections[cnum].gid, - Connections[cnum].ngroups,Connections[cnum].igroups)))) + in_group(sbuf->st_gid,current_user.gid, + current_user.ngroups,current_user.igroups)))) result |= aRONLY; } else { if ((sbuf->st_mode & S_IWUSR) == 0) result |= aRONLY; } -#endif if ((sbuf->st_mode & S_IXUSR) != 0) result |= aARCH; @@ -3383,7 +3372,7 @@ int construct_reply(char *inbuf,char *outbuf,int size,int bufsize) /**************************************************************************** process commands from the client ****************************************************************************/ -void process(void ) +static void process(void) { static int trans_num = 0; int nread; @@ -3407,7 +3396,7 @@ void process(void ) ip = *interpret_addr2("localhost"); if (zero_ip(ip)) ip = *interpret_addr2("127.0.0.1"); *OutBuffer = 0; - send_one_packet(OutBuffer,1,ip,137,SOCK_DGRAM); + send_one_packet(OutBuffer,1,ip,NMB_PORT,SOCK_DGRAM); } #endif @@ -3592,7 +3581,7 @@ static void init_structs(void ) /**************************************************************************** usage on the program ****************************************************************************/ -void usage(char *pname) +static void usage(char *pname) { DEBUG(0,("Incorrect program usage - are you sure the command line is correct?\n")); @@ -3612,12 +3601,12 @@ void usage(char *pname) /**************************************************************************** main program ****************************************************************************/ -int main(int argc,char *argv[]) + int main(int argc,char *argv[]) { extern BOOL append_log; /* shall I run as a daemon */ BOOL is_daemon = False; - int port = 139; + int port = SMB_PORT; int opt; extern char *optarg; diff --git a/source/smbd/smbrun.c b/source/smbd/smbrun.c index 6c9ba52b8b6..dcd5379bc1d 100644 --- a/source/smbd/smbrun.c +++ b/source/smbd/smbrun.c @@ -46,7 +46,7 @@ as non root from a program which is switching between root and non-root It takes 3 arguments as uid,gid,command and runs command after becoming a non-root user */ -int main(int argc,char *argv[]) + int main(int argc,char *argv[]) { int uid,gid; diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c index 045d4611840..36dd5eba3e4 100644 --- a/source/smbd/trans2.c +++ b/source/smbd/trans2.c @@ -264,7 +264,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l int mode=0; uint32 size=0,len; uint32 mdate=0, adate=0, cdate=0; - char *name_ptr; + char *nameptr; BOOL isrootdir = (strequal(Connections[cnum].dirpath,"./") || strequal(Connections[cnum].dirpath,".") || strequal(Connections[cnum].dirpath,"/")); @@ -349,7 +349,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l #endif p = pdata; - name_ptr = p; + nameptr = p; name_map_mangle(fname,False,SNUM(cnum)); @@ -368,7 +368,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l SSVAL(p,l1_attrFile,mode); SCVAL(p,l1_cchName,strlen(fname)); strcpy(p + l1_achName, fname); - name_ptr = p + l1_achName; + nameptr = p + l1_achName; p += l1_achName + strlen(fname) + 1; break; @@ -387,7 +387,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l SIVAL(p,l2_cbList,0); /* No extended attributes */ SCVAL(p,l2_cchName,strlen(fname)); strcpy(p + l2_achName, fname); - name_ptr = p + l2_achName; + nameptr = p + l2_achName; p += l2_achName + strlen(fname) + 1; break; @@ -402,7 +402,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l SIVAL(p,26,4); CVAL(p,30) = strlen(fname); strcpy(p+31, fname); - name_ptr = p+31; + nameptr = p+31; p += 31 + strlen(fname) + 1; break; @@ -420,7 +420,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l SSVAL(p,24,mode); CVAL(p,32) = strlen(fname); strcpy(p + 33, fname); - name_ptr = p+33; + nameptr = p+33; p += 33 + strlen(fname) + 1; break; @@ -452,7 +452,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l strupper(p+2); SSVAL(p,0,strlen(p+2)); p += 2 + 24; - /* name_ptr = p; */ + /* nameptr = p; */ strcpy(p,fname); p += strlen(p); p = pdata + len; break; @@ -517,7 +517,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l } /* Setup the last_filename pointer, as an offset from base_data */ - *last_name_off = PTR_DIFF(name_ptr,base_data); + *last_name_off = PTR_DIFF(nameptr,base_data); /* Advance the data pointer to the next slot */ *ppdata = p; return(found); @@ -1004,7 +1004,7 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length, if (tran_call == TRANSACT2_QFILEINFO) { - int16 fnum = SVAL(params,0); + int16 fnum = SVALS(params,0); info_level = SVAL(params,2); CHECK_FNUM(fnum,cnum); @@ -1198,7 +1198,7 @@ static int call_trans2setfilepathinfo(char *inbuf, char *outbuf, int length, return(ERROR(ERRSRV,ERRaccess)); if (tran_call == TRANSACT2_SETFILEINFO) { - int16 fnum = SVAL(params,0); + int16 fnum = SVALS(params,0); info_level = SVAL(params,2); CHECK_FNUM(fnum,cnum); diff --git a/source/smbd/uid.c b/source/smbd/uid.c index f287c733c49..625303350a6 100644 --- a/source/smbd/uid.c +++ b/source/smbd/uid.c @@ -30,23 +30,18 @@ static int initial_uid; static int initial_gid; static int old_umask = 022; -int current_uid; -int current_gid; - static pstring OriginalDir; -/* have I done a become_user? */ -static struct { - int cnum, uid; -} last_user; +/* what user is current? */ +struct current_user current_user; /**************************************************************************** initialise the uid routines ****************************************************************************/ void init_uid(void) { - initial_uid = current_uid = geteuid(); - initial_gid = current_gid = getegid(); + initial_uid = current_user.uid = geteuid(); + initial_gid = current_user.gid = getegid(); if (initial_gid != 0 && initial_uid == 0) { @@ -61,7 +56,7 @@ void init_uid(void) initial_uid = geteuid(); initial_gid = getegid(); - last_user.cnum = -1; + current_user.cnum = -1; GetWd(OriginalDir); } @@ -111,7 +106,7 @@ static BOOL become_uid(int uid) return(False); } - current_uid = uid; + current_user.uid = uid; return(True); } @@ -140,7 +135,7 @@ static BOOL become_gid(int gid) return(False); } - current_gid = gid; + current_user.gid = gid; return(True); } @@ -174,7 +169,7 @@ BOOL become_guest(void) if (!ret) DEBUG(1,("Failed to become guest. Invalid guest account?\n")); - last_user.cnum = -2; + current_user.cnum = -2; return(ret); } @@ -208,10 +203,9 @@ BOOL become_user(int cnum, int uid) int new_umask; user_struct *vuser; int snum,gid; - int ngroups; - gid_t *groups; + int id = uid; - if (last_user.cnum == cnum && last_user.uid == uid) { + if (current_user.cnum == cnum && current_user.id == id) { DEBUG(4,("Skipping become_user - already user\n")); return(True); } @@ -231,8 +225,9 @@ BOOL become_user(int cnum, int uid) !check_user_ok(cnum,vuser,snum)) { uid = Connections[cnum].uid; gid = Connections[cnum].gid; - groups = Connections[cnum].groups; - ngroups = Connections[cnum].ngroups; + current_user.groups = Connections[cnum].groups; + current_user.igroups = Connections[cnum].igroups; + current_user.ngroups = Connections[cnum].ngroups; } else { if (!vuser) { DEBUG(2,("Invalid vuid used %d\n",uid)); @@ -243,8 +238,9 @@ BOOL become_user(int cnum, int uid) gid = vuser->gid; else gid = Connections[cnum].gid; - groups = vuser->user_groups; - ngroups = vuser->user_ngroups; + current_user.groups = vuser->user_groups; + current_user.igroups = vuser->user_igroups; + current_user.ngroups = vuser->user_ngroups; } if (initial_uid == 0) @@ -254,8 +250,8 @@ BOOL become_user(int cnum, int uid) #ifndef NO_SETGROUPS if (!IS_IPC(cnum)) { /* groups stuff added by ih/wreu */ - if (ngroups > 0) - if (setgroups(ngroups,groups)<0) + if (current_user.ngroups > 0) + if (setgroups(current_user.ngroups,current_user.groups)<0) DEBUG(0,("setgroups call failed!\n")); } #endif @@ -267,8 +263,8 @@ BOOL become_user(int cnum, int uid) new_umask = 0777 & ~CREATE_MODE(cnum); old_umask = umask(new_umask); - last_user.cnum = cnum; - last_user.uid = uid; + current_user.cnum = cnum; + current_user.id = id; DEBUG(5,("become_user uid=(%d,%d) gid=(%d,%d) new_umask=0%o\n", getuid(),geteuid(),getgid(),getegid(),new_umask)); @@ -281,7 +277,7 @@ BOOL become_user(int cnum, int uid) ****************************************************************************/ BOOL unbecome_user(void ) { - if (last_user.cnum == -1) + if (current_user.cnum == -1) return(False); ChDir(OriginalDir); @@ -320,8 +316,8 @@ BOOL unbecome_user(void ) } #endif - current_uid = initial_uid; - current_gid = initial_gid; + current_user.uid = initial_uid; + current_user.gid = initial_gid; if (ChDir(OriginalDir) != 0) DEBUG(0,("%s chdir(%s) failed in unbecome_user\n", @@ -330,7 +326,7 @@ BOOL unbecome_user(void ) DEBUG(5,("unbecome_user now uid=(%d,%d) gid=(%d,%d)\n", getuid(),geteuid(),getgid(),getegid())); - last_user.cnum = -1; + current_user.cnum = -1; return(True); } @@ -352,7 +348,7 @@ int smbrun(char *cmd,char *outfile) } sprintf(syscmd,"%s %d %d \"(%s 2>&1) > %s\"", - path,current_uid,current_gid,cmd, + path,current_user.uid,current_user.gid,cmd, outfile?outfile:"/dev/null"); DEBUG(5,("smbrun - running %s ",syscmd)); diff --git a/source/smbd/vt_mode.c b/source/smbd/vt_mode.c index 83b62a38ac2..0a4d50c217f 100644 --- a/source/smbd/vt_mode.c +++ b/source/smbd/vt_mode.c @@ -60,8 +60,7 @@ int ms_type = MS_NONE, /* VT_Check: test incoming packet for "vtp" or "iVT1\0" */ -int VT_Check(buffer) -char *buffer; +int VT_Check(char *buffer) { DEBUG(3,("Checking packet: <%10s...>\n", buffer+4)); if((strncmp(buffer+4, "vtp", 3) == 0 && smb_len(buffer) == 3) || (strncmp(buffer+4, "iVT1\0", 5) == 0 && smb_len(buffer) == 5)) @@ -74,7 +73,7 @@ char *buffer; /* VT_Start_utmp: prepare /etc/utmp for /bin/login */ -VT_Start_utmp() +int VT_Start_utmp(void) { struct utmp u, *v; char *tt; @@ -111,7 +110,7 @@ VT_Start_utmp() /* VT_Stop_utmp: prepare /etc/utmp for other processes */ -VT_Stop_utmp() +int VT_Stop_utmp(void) { struct utmp u, *v; @@ -138,7 +137,7 @@ VT_Stop_utmp() /* VT_AtExit: Things to do when the program exits */ -void VT_AtExit() +void VT_AtExit(void) { if(VT_ChildPID > 0) { kill(VT_ChildPID, SIGHUP); @@ -152,8 +151,7 @@ void VT_AtExit() /* VT_SigCLD: signalhandler for SIGCLD: set flag if child-process died */ -void VT_SigCLD(sig) -int sig; +void VT_SigCLD(int sig) { if(wait(NULL) == VT_ChildPID) VT_ChildDied = True; @@ -165,8 +163,7 @@ int sig; /* VT_SigEXIT: signalhandler for signals that cause the process to exit */ -void VT_SigEXIT(sig) -int sig; +void VT_SigEXIT(int sig) { VT_AtExit(); @@ -177,7 +174,7 @@ int sig; /* VT_Start: initialize vt-specific data, alloc pty, spawn shell and send ACK */ -int VT_Start() +int VT_Start(void) { char OutBuf [64], *X, *Y; @@ -330,8 +327,7 @@ int VT_Start() /* VT_Output: transport data from socket to pty */ -int VT_Output(Buffer) -char *Buffer; +int VT_Output(char *Buffer) { int i, len, nb; @@ -350,9 +346,7 @@ char *Buffer; /* VT_Input: transport data from pty to socket */ -int VT_Input(Buffer, Size) -char *Buffer; -int Size; +int VT_Input(char *Buffer,int Size) { int len; @@ -372,7 +366,7 @@ int Size; /* VT_Process: main loop while in vt-mode */ -void VT_Process() +void VT_Process(void) { static int trans_num = 0; extern int Client; diff --git a/source/sockspy.c b/source/sockspy.c deleted file mode 100644 index 806b7379157..00000000000 --- a/source/sockspy.c +++ /dev/null @@ -1,302 +0,0 @@ -/* - USAGE - sockspy desthost destservice - -You install this program in /etc/inetd.conf and /etc/services - -For example I have used these entries: - -/etc/services: -spy 8001/tcp spy port - -/etc/inetd.conf: -spy stream tcp nowait tridge /usr/local/smb/sockspy sockspy fjall netbios-ssn - -This means any connection to port 8001 will be redirected to -netbios-ssn on fjall. By playing with these parameters you can easily -spy on most of the tcp protocols. All packets traversing the link will -be captured. - -NOTE: This program is totally unsupported. I haven't used it for 2 -years, and don't intend to fix the obvious bugs/limitations. I will, -however, accept contributed patches - or even a total rewrite :-) -*/ - -#include <stdio.h> -#include <strings.h> -#include <sys/types.h> -#include <sys/dir.h> -#include <sys/socket.h> -#include <sys/ioctl.h> -#include <netinet/in.h> -#include <netdb.h> - -#include <signal.h> - -#include <errno.h> -#include <sysexits.h> - -int trans_num = 0; - -#ifndef LOGIN -#define LOGIN "/tmp/spy.in" -#endif - -#ifndef LOGOUT -#define LOGOUT "/tmp/spy.out" -#endif - -#ifndef LOGCMD -#define LOGCMD "/tmp/spy.cmd" -#endif - -FILE *cmd = NULL; -FILE *login = NULL; -FILE *logout = NULL; - -#define STREQL(a, b) (strcmp(a, b) == 0) -#define NIL (0) - -char DestHost[256]; /* Remote system to connect to */ -char DestObj[256]; /* Remote object/service to connect to */ - -/* Signal handler for SIGPIPE (write on a disconnected socket) */ -abort() -{ - if (cmd) - { - fprintf(cmd,"writing to disconnected socket!\n"); - fflush(cmd); - } - exit(1); -} - - -main(argc, argv) -int argc; /* # of command line arguments */ -char *argv[]; /* the command line arguments */ -{ - int client, /* Socket connected to client */ - server; /* Socket to use for server */ - - trans_num = 0; -#ifndef NOLOG - login = fopen(LOGIN,"w"); - logout = fopen(LOGOUT,"w"); - cmd = fopen(LOGCMD,"w"); -#endif - - if (cmd) - { - fprintf(cmd,"Started server\n"); - fflush(cmd); - } - - /* Check usage */ - if(argc != 3) - return; - - strcpy(DestHost,argv[1]); - strcpy(DestObj,argv[2]); - - /* Time to attempt the connection */ - server = inet_conn(DestHost, DestObj); - - if( server < 0 ) { - exit(EX_CANTCREAT); - } - - /* Just to make the code more readable */ - client = 0; - - /* We will abort gracefully when the client or remote system - goes away */ - signal(SIGPIPE, abort); - - /* Now just go and move raw data between client and - remote system */ - dowork(client, server); - /* ... NEVER RETURNS ... */ -} - -dowork(client, server) - int client, server; -{ - - /* select(2) masks for client and remote */ - int ClientMask, ServerMask; - - /* Combined ClientMask and ServerMask */ - int ReadMask; - - /* Initialize select(2) masks */ - ClientMask = 1<<client; - ServerMask = 1<<server; - - ReadMask = ClientMask | ServerMask; - - /* Now move raw data for the rest of our life between - client and remote */ - for( ; ; ) { - /* Local Variables */ - int SelectReadMask;/* select(2) mask modifiable by select(2) */ - int nready; /* status return from select(2) */ - - do { - /* Intialize select(2) mask everytime - as select(2) always modifies it */ - SelectReadMask = ReadMask; - - /* Wait for data to be present to be moved */ - errno = 0; - nready = select(32,&SelectReadMask,(int *)0,(int *)0,NIL); - } while( nready < 0 && errno == EINTR ); - - /* select(2) failed, shouldn't happen. Exit abnormally */ - if( nready < 0 ) - exit(EX_SOFTWARE); - - /* Favor the client (for no particular reason) - if s/he is has data */ - if( SelectReadMask & ClientMask ) - { - if (cmd) - fprintf(cmd,"client %d\n",nready); - xfer(client, server,login); - } - - /* Then check on the other guy */ - if( SelectReadMask & ServerMask ) - { - if (cmd) - fprintf(cmd,"server %d\n",nready); - xfer(server, client,logout); - } - } - - /* NEVER REACHED */ -} - -#define BUFSIZE 20000 /* Max bytes to move at a time */ - -xfer(from, to,file) - int from, to; /* Move data from "from" to "to" */ - FILE *file; -{ - static char buf[BUFSIZE]; /* Buffer data to be moved */ - int nready; /* # bytes readable */ - int got; /* # bytes actually being moved */ - int ret; - - /* Query the system how many bytes are ready to be read */ - ioctl(from, FIONREAD, &nready); - - if (cmd) - fprintf(cmd,"nready = %d\n",nready); - - /* Only try to get the smaller of nready and BUFSIZE */ - got = read(from, buf, nready < BUFSIZE ? nready : BUFSIZE); - - /* Zero bytes returned indicates end of stream, exit gracefully */ - if( got == 0 ) - { - if (cmd) - { - fprintf(cmd,"read 0 bytes exiting\n"); - fflush(cmd); - } - if (login) - fclose(login); - if (logout) - fclose(logout); - if (cmd) - fclose(cmd); - exit(EX_OK); - } - - - if (file) - { - fprintf(file,"\nTransaction %d\n",trans_num); - fwrite(buf,got,1,file); - fflush(file); - } - trans_num++; - - /* Now send it accross to the other side */ - ret = write(to, buf, got); - - if (cmd) - { - fprintf(cmd,"wrote %d\n",ret); - if (ret < 0) - fprintf(cmd,"error = %s\n",strerror(errno)); - } -} - -int -inet_conn(host, port) - char *host; - char *port; -{ - /* Local Vars */ - int sock; /* Socket to use for the connection */ - struct hostent *hostent; /* Destination host entry */ - struct servent *servent; /* Destination service entry */ - struct sockaddr_in addr; /* Formated destination for connect */ - - /* Fetch the requested host and service entries */ - hostent = gethostbyname(host); - if (isdigit(*port)) - servent = getservbyport(80, "tcp"); - else - servent = getservbyname(port, "tcp"); - - - if (cmd) - { - fprintf(cmd,"inet_conn %s %s\n",host,port); - - if (servent == NULL) - fprintf(cmd,"servent is NIL\n"); - if (hostent == NULL) - fprintf(cmd,"hostent is NIL\n"); - if (hostent->h_addrtype != AF_INET) - fprintf(cmd,"not inet type\n"); - fflush(cmd); - } - - - /* No host entry, no service entry, or host is not - Internet, error! */ - if( servent == NIL || - hostent == NIL || - hostent->h_addrtype != AF_INET ) - return -1; - - /* Get a socket from the system to use for the connection */ - if( (sock = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) - return -1; - - /* Make sure we start with a clean address structure ... */ - bzero(&addr, sizeof(addr)); - - /* ... then fill in the required fields */ - addr.sin_family = AF_INET; - addr.sin_port = servent->s_port; - bcopy(hostent->h_addr, &addr.sin_addr, hostent->h_length); - - /* Now try to connection to the destination */ - if( connect(sock, &addr, sizeof(addr)) < 0 ) { - /* No go, release the socket, and then return error! */ - close(sock); - return -1; - } - - /* Success. Return the connected socket descriptor */ - if (cmd) - fprintf(cmd,"returning %d\n",sock); - return sock; -} - - diff --git a/source/utils/nmblookup.c b/source/utils/nmblookup.c index aa431733322..6289ef74b1e 100644 --- a/source/utils/nmblookup.c +++ b/source/utils/nmblookup.c @@ -25,7 +25,6 @@ #endif #include "includes.h" -#include "nameserv.h" extern int DEBUGLEVEL; @@ -35,6 +34,7 @@ extern struct in_addr bcast_ip; extern pstring myhostname; static BOOL got_bcast = False; +struct in_addr ipzero; int ServerFD= -1; @@ -124,6 +124,8 @@ int main(int argc,char *argv[]) TimeInit(); + ipzero = *interpret_addr2("0.0.0.0"); + setup_logging(argv[0],True); charset_initialise(); diff --git a/source/utils/smbpasswd.c b/source/utils/smbpasswd.c index 1569a3cd880..c79aa15c807 100644 --- a/source/utils/smbpasswd.c +++ b/source/utils/smbpasswd.c @@ -201,14 +201,13 @@ _my_get_smbpwnam(FILE * fp, char *name, BOOL * valid_old_pwd, /* * Print command usage on stderr and die. */ -void -usage(char *name) +static void usage(char *name) { fprintf(stderr, "Usage is : %s [username]\n", name); exit(1); } -int main(int argc, char **argv) + int main(int argc, char **argv) { int real_uid; struct passwd *pwd; diff --git a/source/utils/status.c b/source/utils/status.c index 2a2a5ca4c11..65e9d975f14 100644 --- a/source/utils/status.c +++ b/source/utils/status.c @@ -44,7 +44,7 @@ unsigned int Ucrit_checkUsername(pstring username); /* added by OH */ void Ucrit_addPid(int pid); /* added by OH */ unsigned int Ucrit_checkPid(int pid); /* added by OH */ -int main(int argc, char *argv[]) + int main(int argc, char *argv[]) { FILE *f; pstring fname; diff --git a/source/utils/testparm.c b/source/utils/testparm.c index 1eaaa10b3b8..c6fa674b2d3 100644 --- a/source/utils/testparm.c +++ b/source/utils/testparm.c @@ -41,7 +41,7 @@ extern FILE *dbf; extern int DEBUGLEVEL; -int main(int argc, char *argv[]) + int main(int argc, char *argv[]) { pstring configfile; int s; |