a huge pile of changes :-)
authorAndrew Tridgell <tridge@samba.org>
Tue, 4 Jun 1996 06:42:03 +0000 (06:42 +0000)
committerAndrew Tridgell <tridge@samba.org>
Tue, 4 Jun 1996 06:42:03 +0000 (06:42 +0000)
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

44 files changed:
source/client/client.c
source/client/clientutil.c [new file with mode: 0644]
source/client/clitar.c
source/include/includes.h
source/include/local.h
source/include/nameserv.h
source/include/proto.h [new file with mode: 0644]
source/include/smb.h
source/lib/charcnv.c
source/lib/getsmbpass.c
source/lib/kanji.c
source/lib/md4.c
source/lib/ufc.c
source/lib/util.c
source/libsmb/namequery.c [new file with mode: 0644]
source/libsmb/nmblib.c
source/libsmb/smbencrypt.c
source/loadparm.h
source/localnet.h [new file with mode: 0644]
source/nameannounce.c [new file with mode: 0644]
source/namedb.c [new file with mode: 0644]
source/nameelect.c [new file with mode: 0644]
source/nameresp.c [new file with mode: 0644]
source/nameserv.c
source/namework.c [new file with mode: 0644]
source/nmbd/nmbd.c [new file with mode: 0644]
source/nmbsync.c
source/param/loadparm.c
source/param/params.c
source/params.h
source/passdb/smbpass.c
source/script/mkproto.awk [new file with mode: 0644]
source/smbd/password.c
source/smbd/reply.c
source/smbd/server.c
source/smbd/smbrun.c
source/smbd/trans2.c
source/smbd/uid.c
source/smbd/vt_mode.c
source/sockspy.c [deleted file]
source/utils/nmblookup.c
source/utils/smbpasswd.c
source/utils/status.c
source/utils/testparm.c

index a40d377955c17991fe9a9f15952809902e8bf5bf..3cefbc2284c8a55098186a1c897fc94346db5c50 100644 (file)
@@ -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
   ****************************************************************************/
@@ -631,202 +943,65 @@ static int interpret_long_filename(int level,char *p,file_info *finfo)
          p += 2; /* short name len? */
          p += 24; /* short name? */      
          StrnCpy(finfo->name,p,namelen);
-         return(ret);
-       }
-      return(SVAL(p,0));
-    }
-
-  DEBUG(1,("Unknown long filename format %d\n",level));
-  return(SVAL(p,0));
-}
-
-
-
-
-/****************************************************************************
-  act on the files in a dir listing
-  ****************************************************************************/
-static void dir_action(char *inbuf,char *outbuf,int attribute,file_info *finfo,BOOL recurse_dir,void (*fn)(),BOOL longdir)
-{
-
-  if (!((finfo->mode & aDIR) == 0 && *fileselection && 
-       !mask_match(finfo->name,fileselection,False,False)) &&
-      !(recurse_dir && (strequal(finfo->name,".") || 
-                       strequal(finfo->name,".."))))
-    {
-      if (recurse_dir && (finfo->mode & aDIR))
-       {
-         pstring mask2;
-         pstring sav_dir;
-         strcpy(sav_dir,cur_dir);
-         strcat(cur_dir,finfo->name);
-         strcat(cur_dir,"\\");
-         strcpy(mask2,cur_dir);
-
-         if (!fn)
-           DEBUG(0,("\n%s\n",CNV_LANG(cur_dir)));
-
-         strcat(mask2,"*");
-
-         if (longdir)
-           do_long_dir(inbuf,outbuf,mask2,attribute,fn,True);      
-         else
-           do_dir(inbuf,outbuf,mask2,attribute,fn,True);
-
-         strcpy(cur_dir,sav_dir);
-       }
-      else
-       {
-         if (fn && do_this_one(finfo))
-           fn(finfo);
-       }
-    }
-}
-
-
-/****************************************************************************
-  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;
+         return(ret);
+       }
+      return(SVAL(p,0));
+    }
 
-      p = smb_buf(inbuf) + 3;
+  DEBUG(1,("Unknown long filename format %d\n",level));
+  return(SVAL(p,0));
+}
 
-      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;
-    }
+/****************************************************************************
+  act on the files in a dir listing
+  ****************************************************************************/
+static void dir_action(char *inbuf,char *outbuf,int attribute,file_info *finfo,BOOL recurse_dir,void (*fn)(),BOOL longdir)
+{
 
-#if FFIRST
-  if (!first && Protocol >= PROTOCOL_LANMAN1)
+  if (!((finfo->mode & aDIR) == 0 && *fileselection && 
+       !mask_match(finfo->name,fileselection,False,False)) &&
+      !(recurse_dir && (strequal(finfo->name,".") || 
+                       strequal(finfo->name,".."))))
     {
-      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);
+      if (recurse_dir && (finfo->mode & aDIR))
+       {
+         pstring mask2;
+         pstring sav_dir;
+         strcpy(sav_dir,cur_dir);
+         strcat(cur_dir,finfo->name);
+         strcat(cur_dir,"\\");
+         strcpy(mask2,cur_dir);
 
-      send_smb(Client,outbuf);
-      receive_smb(Client,inbuf,CLIENT_TIMEOUT,False);
+         if (!fn)
+           DEBUG(0,("\n%s\n",CNV_LANG(cur_dir)));
 
-      if (CVAL(inbuf,smb_rcls) != 0) 
-       DEBUG(0,("Error closing search: %s\n",smb_errstr(inbuf)));      
-    }
-#endif
+         strcat(mask2,"*");
 
-  if (!fn)
-    for (p=dirlist,i=0;i<num_received;i++)
-      {
-       p += interpret_short_filename(p,&finfo);
-       display_finfo(&finfo);
-      }
+         if (longdir)
+           do_long_dir(inbuf,outbuf,mask2,attribute,fn,True);      
+         else
+           do_dir(inbuf,outbuf,mask2,attribute,fn,True);
 
-  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);
+         strcpy(cur_dir,sav_dir);
+       }
+      else
+       {
+         if (fn && do_this_one(finfo))
+           fn(finfo);
+       }
     }
-
-  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 (file)
index 0000000..e2427a4
--- /dev/null
@@ -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);
+}
index 0701aac1cf4d1d21de7ff80882192b8e0526774d..2de09c66c114983287752f59821c4f2f8013b204 100644 (file)
 #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"
index 8b2821948c3cdcb3f580c1b95a030cfa9ca0ecc2..ad65bcc6075b4746fa78cef8dd9a5caa61357d78 100644 (file)
@@ -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"
index 9572243e730d42bdcd3e1ce969964a83c7a33eff..2cfacd66b39dd61a9c2e571a38e697eff11c56c0 100644 (file)
 #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)
index 168dd4ba866ad181e0e4fdc5a138e6768f4d734f..81079fabe01c7d6700762c24edaf777f3e3ae55f 100644 (file)
    
 */
 
-#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 (file)
index 0000000..face79d
--- /dev/null
@@ -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);
index 3e38f4c37e421c2bd6a96da65c3960c4eb7b1d3a..0be860d6a363f7c7f30c55ad6828695959aca014 100644 (file)
 #      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
index 049390f2a431dc60a2ea71c49beea8ca4e772663..d9ee551d6a815aecd808fc61dfeeca5f07837559 100644 (file)
@@ -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")) {
index 07a7dbfd9b5a91645aa01fa8d50eed663349b9c8..7ee8c18788543dbf3b15ee594175badb665090c6 100644 (file)
@@ -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
index 0af476eb157d3811aa77649f0d027318a1e60d18..a77bdea73f0d71211161f54e4ce2b137212e9be2 100644 (file)
@@ -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 */
index 485e231a784485781112e67be6b27a19ebee32d4..bdff075c7e7b2834b50f2ec52fefcbaf7dd90b4d 100644 (file)
  ** End of md4.c
  */
 #else
-void md4_dummy() {;}
+ void md4_dummy() {;}
 #endif
index 8417285821a2429dba62a782e7a2efe69ee4f448..ae48a8776d405c642c9b31127a15e87c0b862f48 100644 (file)
@@ -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
index d2f03835326d696d3f9992df759b0fb1b73127f5..57f2e9240cf8e1b60c38a6d683deb1105dc3ded9 100644 (file)
@@ -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); 
@@ -3569,6 +3569,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
 ********************************************************************/
@@ -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 (file)
index 0000000..d1b1ae7
--- /dev/null
@@ -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);
+}
index 1f78996156037aa014d2141083af0523a4b1fb1c..d8d6eb0ee4098999f8785995cf7eafb9ebfd117c 100644 (file)
 */
 
 #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));
-}
-
-
index 0221520ce650648046d1e7f608e1f75259cb0605..be22fc50fc6a82065a6fd19f3e0da32d8767c783 100644 (file)
 
 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
index 879ff25e67572795d6efff7c59f171ce8dbfa8e2..5600d66922fcd99101d4e4885f2c07def3d97666 100644 (file)
@@ -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 (file)
index 0000000..7f335e7
--- /dev/null
@@ -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 (file)
index 0000000..f0de4d0
--- /dev/null
@@ -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 (file)
index 0000000..9151789
--- /dev/null
@@ -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 (file)
index 0000000..30c3c37
--- /dev/null
@@ -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 (file)
index 0000000..a4a55c9
--- /dev/null
@@ -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));
+}
+
+
index b64a93457264dbcada47f6e469ac84ce559b87ee..4cd9b099f0011b84f61cf8bfa4cfa6bdcbc613a8 100644 (file)
    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;
@@ -246,58 +77,18 @@ static void add_name(struct name_record *n)
   n->prev = n2;
 }
 
-/****************************************************************************
-  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;
+
+       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);
+       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"));
+
+       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));
+       }
+}
+
 
-  DEBUG(3,("Dump of local name table:\n"));
+/****************************************************************************
+  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;
 
-  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)));
-    }
+       make_nmb_name(&nn, name, type, scope);
+       n = find_name_search(&nn, FIND_GLOBAL, ip);
 
-  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)));
+       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);
-  }
+       struct in_addr ip;
 
-  ElectionCriterion |= (lp_os_level() << 24);
-}
-
-
-/*******************************************************************
-  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;
+
+                       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;
+               }
+       }
 }
 
 
-/*******************************************************************
-  delete old names from the namelist
-  ******************************************************************/
-static void housekeeping(void)
+/****************************************************************************
+response for a reg release received
+**************************************************************************/
+void response_name_release(struct packet_struct *p)
 {
-  time_t t = time(NULL);
+       struct nmb_packet *nmb = &p->packet.nmb;
+       char *name = nmb->question.question_name.name;
+       int   type = nmb->question.question_name.name_type;
 
-  expire_names();
+       DEBUG(4,("response name release received\n"));
 
-  /* write out the browse.dat database for smbd to get */
-  if (updatedlists) {
-    write_browse_list();
-    updatedlists = False;
-  }
+       if (nmb->header.rcode == 0 && nmb->answers->rdata)
+       {
+               struct in_addr found_ip;
+               putip((char*)&found_ip,&nmb->answers->rdata[2]);
 
-  {
-    /* 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;
-    }
-  }
+               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)));
+       }
 }
 
 
 /****************************************************************************
-  reload the services file
-  **************************************************************************/
-BOOL reload_services(BOOL test)
+reply to a name release
+****************************************************************************/
+void reply_name_release(struct packet_struct *p)
 {
-  BOOL ret;
-  extern fstring remote_machine;
+       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));
 
-  strcpy(remote_machine,"nmbd");
+       n = find_name_search(&nmb->question.question_name, FIND_GLOBAL, ip);
 
-  if (lp_loaded())
-    {
-      pstring fname;
-      strcpy(fname,lp_configfile());
-      if (file_exist(fname,NULL) && !strcsequal(fname,servicesf))
+       /* XXXX under what conditions should we reject the removal?? */
+       if (n && n->nb_flags == nb_flags && ip_equal(n->ip,ip))
        {
-         strcpy(servicesf,fname);
-         test = False;
-       }
-    }
+               /* success = True;
+               rcode = 6; */
 
-  if (test && !lp_file_list_changed())
-    return(True);
+               remove_name(n);
+               n = NULL;
+       }
 
-  ret = lp_load(servicesf,True);
+       if (bcast) return;
 
-  /* perhaps the config filename is now set */
-  if (!test)
-    reload_services(True);
+       /*if (success)*/
+       {
+               rdata[0] = nb_flags;
+               rdata[1] = 0;
+               putip(&rdata[2],(char *)&ip);
+       }
 
-  return(ret);
+       /* 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 */
 }
 
 
-
 /****************************************************************************
-load a netbios hosts file
-****************************************************************************/
-static void load_hosts_file(char *fname)
+response for a reg request received
+**************************************************************************/
+void response_name_reg(struct packet_struct *p)
 {
-  FILE *f = fopen(fname,"r");
-  pstring line;
-  if (!f) {
-    DEBUG(2,("Can't open lmhosts file %s\n",fname));
-    return;
-  }
+       struct nmb_packet *nmb = &p->packet.nmb;
+       char *name = nmb->question.question_name.name;
+       int   type = nmb->question.question_name.name_type;
 
-  while (!feof(f))
-    {
-      if (!fgets_slash(line,sizeof(pstring),f)) continue;
-      
-      if (*line == '#') continue;
+       DEBUG(4,("response name registration received!\n"));
 
-      {
-       BOOL group=False;
-       string ip,name,flags,extra;
-       char *ptr;
-       int count = 0;
-       struct in_addr ipaddr;
-       enum name_source source = LMHOSTS;
+       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;
 
-       *ip = *name = *flags = *extra = 0;
+               putip((char*)&found_ip,&nmb->answers->rdata[2]);
 
-       ptr = line;
+               if (ip_equal(found_ip, myip)) source = SELF;
 
-       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;
+               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)));
+       }
+}
 
-       if (count <= 0) continue;
 
-       if (count > 0 && count < 2)
-         {
-           DEBUG(0,("Ill formed hosts line [%s]\n",line));         
-           continue;
-         }
+/****************************************************************************
+reply to a reg request
+**************************************************************************/
+void reply_name_reg(struct packet_struct *p)
+{
+       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");
+       }
 
-       if (strchr(flags,'G') || strchr(flags,'S'))
-         group = True;
+       /* see if the name already exists */
+       n = find_name_search(question, FIND_GLOBAL, from_ip);
 
-       if (strchr(flags,'M') && !group) {
-         source = SELF;
-         strcpy(myname,name);
+       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);
        }
 
-       ipaddr = *interpret_addr2(ip);
+       if (bcast) return;
+
+       update_from_reg(nmb->question.question_name.name,
+                                 nmb->question.question_name.name_type, from_ip);
 
-       if (group) {
-         add_domain_entry(name,ipaddr);
-       } else {
-         add_host_entry(name,0x20,True,0,source,ipaddr);
+       /* 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);
        }
-      }
-    }
 
-  fclose(f);
+       /* 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*/);
 }
 
-/*******************************************************************
-  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)
+reply to a name status query
+****************************************************************************/
+void reply_name_status(struct packet_struct *p)
 {
-  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);
-}
+       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;
 
-/****************************************************************************
-  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);
-}
+               if (name_type >= 0x1b && name_type <= 0x20 && 
+                   ques_type >= 0x1b && ques_type <= 0x20)
+               {
+                       if (!strequal(qname, n->name.name)) continue;
+               }
 
+               count++;
+       }
 
-/*******************************************************************
-  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;
-    }
-  }
+       /* XXXX hack, we should calculate exactly how many will fit */
+       count = MIN(count,(sizeof(rdata) - 64) / 18);
 
-  add_server_entry(PrimaryGroup,domain_type,0,myname,True);
-  add_server_entry(myname,ServerType,0,ServerComment,True);
+       countptr = buf = rdata;
+       buf += 1;
 
-  announce_request(PrimaryGroup);
+       names_added = 0;
 
-  needannounce = True;
-}
+       for (n = namelist ; n && count >= 0; n = n->next) 
+       {
+               int name_type = n->name.name_type;
 
+               if (n->source != SELF) continue;
 
-/*******************************************************************
-  unbecome the master browser
-  ******************************************************************/
-static void become_nonmaster(void)
-{
-  struct name_record *n;
-  struct nmb_name nn;
+               /* start with first bit of putting info in buffer: the name */
 
-  DEBUG(2,("Becoming non-master for %s\n",PrimaryGroup));
+               bzero(buf,18);
+               StrnCpy(buf,n->name.name,15);
+               strupper(buf);
 
-  ServerType &= ~SV_TYPE_MASTER_BROWSER;
-  ServerType &= ~SV_TYPE_DOMAIN_CTRL;
-  ServerType &= ~SV_TYPE_DOMAIN_MASTER;
+               /* 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 */
 
-  ElectionCriterion &= ~0x4;
+               if (name_type >= 0x1b && name_type <= 0x20 && 
+                       ques_type >= 0x1b && ques_type <= 0x20)
+               {
+                       if (!strequal(qname, n->name.name)) continue;
+               }
 
-  make_nmb_name(&nn,PrimaryGroup,0x1d,scope);
-  n = find_name(&nn);
-  if (n && n->source == SELF) remove_name(n);
+               /* carry on putting name info in buffer */
 
-  make_nmb_name(&nn,PrimaryGroup,0x1b,scope);
-  n = find_name(&nn);
-  if (n && n->source == SELF) remove_name(n);
+               buf[15] = name_type;
+               buf[16]  = n->nb_flags;
 
-  make_nmb_name(&nn,MSBROWSE,1,scope);
-  n = find_name(&nn);
-  if (n && n->source == SELF) remove_name(n);
-}
+               buf += 18;
 
+               count--;
+               names_added++;
+       }
 
-/*******************************************************************
-  run the election
-  ******************************************************************/
-static void run_election(void)
-{
-  time_t t = time(NULL);
-  static time_t lastime = 0;
+       if (count < 0)
+       {
+               DEBUG(3, (("too many names: missing a few!\n")));
+       }
 
-  if (!PrimaryGroup[0] || !RunningElection) return;
+       SCVAL(countptr,0,names_added);
 
-  /* send election packets once a second */
-  if (lastime &&
-      t-lastime <= 0) return;
+       /* 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);
+       }
 
-  lastime = t;
+       SIVAL(buf,46,0xFFB8E5); /* undocumented - used by NT */
 
-  send_election(PrimaryGroup,ElectionCriterion,t-StartupTime,myname);
+       buf += 64;
 
-  if (ElectionCount++ < 4) return;
-   
-  /* I won! now what :-) */
-  RunningElection = False;
-  DEBUG(2,(">>> Won election on %s <<<\n",PrimaryGroup));
-  become_master();
+       /* 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));
 }
 
 
-/****************************************************************************
-  construct a host announcement unicast
-  **************************************************************************/
-static void announce_host(struct domain_record *d,char *my_name,char *comment)
+/***************************************************************************
+reply to a name query
+****************************************************************************/
+struct name_record *search_for_name(struct nmb_name *question,
+                                   struct in_addr ip, int Time, int search)
 {
-  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);
-  }
+       int name_type = question->name_type;
+       char *qname = question->name;
+       BOOL dns_type = name_type == 0x20 || name_type == 0;
 
-  /* announce every minute at first then progress to every 12 mins */
-  if (d->lastannounce_time && 
-      (t - d->lastannounce_time) < d->announce_interval)
-    return;
+       struct name_record *n;
 
-  if (d->announce_interval < 12*60) d->announce_interval += 60;
-  d->lastannounce_time = t;
+       DEBUG(3,("Search for %s from %s - ", namestr(question), inet_ntoa(ip)));
 
-  DEBUG(2,("Sending announcement to %s for workgroup %s\n",
-          inet_ntoa(d->bcast_ip),d->name));
+       /* first look up name in cache */
+       n = find_name_search(question,search,ip);
 
-  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);
-  }
+       /* 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;
+       }
 
-  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);
-  }
-}
+       /* is our entry already dead? */
+       if (n->death_time)
+       {
+               if (n->death_time < Time) return False;
+       }
 
+       /* it may have been an earlier failure */
+       if (n->source == DNSFAIL)
+       {
+               DEBUG(3,("DNSFAIL\n"));
+               return NULL;
+       }
 
-/****************************************************************************
-  send a announce request to the local net
-  **************************************************************************/
-static void announce_request(char *group)
-{
-  pstring outbuf;
-  char *p;
+       DEBUG(3,("OK %s\n",inet_ntoa(n->ip)));      
 
-  DEBUG(2,("Sending announce request to %s for workgroup %s\n",
-          inet_ntoa(bcast_ip),group));
+       return n;
+}
 
-  bzero(outbuf,sizeof(outbuf));
-  p = outbuf;
-  CVAL(p,0) = 2; /* announce request */
-  p++;
+/* 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;
+                               }
+                       }
+               }
+*/
 
-  CVAL(p,0) = 0; /* flags?? */
-  p++;
-  StrnCpy(p,myname,16);
-  strupper(p);
-  p = skip_string(p,1);
+/***************************************************************************
+reply to a name query.
 
-  send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
-                     myname,group,0,0,bcast_ip,myip);
-}
+with broadcast name queries:
 
-/****************************************************************************
-  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;
+       - 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.
 
-  if (strequal(domain_controller(),myname)) return;
+       - NEVER send a negative response to a broadcast query. no-one else will!
 
-  if (!AM_MASTER || (last && (t-last < 10*60))) return;
-  last = t;
+with directed name queries:
 
-  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)
-{
-  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();
-    }
-  }
-}
-
-
-/*******************************************************************
-  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;
-  int flags = CVAL(buf,0);
-  char *name = buf+1;
-
-  name[15] = 0;
-
-  DEBUG(3,("Announce request from %s flags=0x%X\n",name,flags));
-
-  if (strequal(dgram->source_name.name,myname)) return;
-
-  needannounce = True;
-}
-
-
-/****************************************************************************
-process a browse frame
-****************************************************************************/
-static 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_backup_list(p,buf+1);
-      break;
-
-    case 13: /* master announcement */
-      process_master_announce(p,buf+1);
-      break;
-    }
-}
-
-
-/****************************************************************************
-  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 (!lp_domain_logons()) {
-    DEBUG(3,("No domain logons\n"));
-    return;
-  }
-  if (!listening(&dgram->dest_name)) {
-    DEBUG(4,("Not listening to that domain\n"));
-    return;
-  }
-
-  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;
-  }
-
-
-  send_mailslot_reply(logname,ClientDGRAM,outbuf,PTR_DIFF(q,outbuf),
-                     myname,&dgram->source_name.name[0],0,0,p->ip,myip);  
-}
-
-/****************************************************************************
-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;
-  }
-
-  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);
-  }
-
-}
-
-/*******************************************************************
-  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;
-
-  strcpy(name1,MSBROWSE);
-
-  ret = name_query(ClientNMB,name1,0x1,True,False,ip,&ipout,queue_packet);
-  if (!ret) return(False);
-
-  name_status(ClientNMB,name1,0x1,False,ipout,name,NULL,queue_packet);
-
-  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] != '*');
-}
-
-
-/****************************************************************************
-  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);
-  }
-
-  /* if I have a domain controller then announce to it */
-  if (AM_MASTER)
-    announce_master(PrimaryGroup);
-
-  needannounce=False;
-}
-
-/*******************************************************************
-  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
+       - if you are the WINS server, you are expected to 
 ****************************************************************************/
-static void reply_name_release(struct packet_struct *p)
-{
-  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]);  
-
-  {
-    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;
-    }
-
-    /* XXXX under what conditions should we reject the removal?? */
-  }
-
-  DEBUG(3,("Name release on name %s rcode=%d\n",
-          namestr(&nmb->question.question_name),rcode));
-
-  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)
+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;
-  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");
-  }
-
-  {
-    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)));
+       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)))
+       {
+               /* 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;
        }
-      } 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;
-
-  nmb2->answers->ttl = ttl; 
-  nmb2->answers->rdlength = 6;
-  nmb2->answers->rdata[0] = nb_flags;
-  putip(&nmb2->answers->rdata[2],(char *)&ip);
-
-  send_packet(&p2);  
-}
-
-
-/****************************************************************************
-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++;
-  }
 
-  count = MIN(count,400/18); /* XXXX hack, we should calculate exactly
-                               how many will fit */
+       /* 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;
 
-  
-  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 */
+       /* 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;
 
-  buf += 64;
+       if (success)
+       {
+               rcode = 0;
+               DEBUG(3,("OK %s\n",inet_ntoa(retip)));      
+       }
+       else
+       {
+               rcode = 3;
+               DEBUG(3,("UNKNOWN\n"));      
+       }
 
-  nmb2->answers->rdlength = PTR_DIFF(buf,&nmb2->answers->rdata[0]);
+       if (success)
+       {
+               rdata[0] = nb_flags;
+               rdata[1] = 0;
+               putip(&rdata[2],(char *)&retip);
+       }
 
-  send_packet(&p2);
+       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);
 }
 
 
-
 /****************************************************************************
-reply to a name query
+response from a name query
 ****************************************************************************/
-static 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)
+static void response_netbios_packet(struct packet_struct *p)
 {
-  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;
-}
+       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;
 
-/****************************************************************************
-  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) 
+       if (nmb->answers == NULL)
        {
-         switch (nmb->question.question_type)
-           {
-           case 0x20:
-             reply_name_query(p);
-             break;
-
-           case 0x21:
-             reply_name_status(p);
-             break;
-           }
-         return;
+               DEBUG(3,("NMB packet response from %s (bcast=%s) - UNKNOWN\n",
+                  inet_ntoa(p->ip),
+                  BOOLSTR(bcast)));
+               return;
        }
-      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 (RunningElection) 
-       run_election();
-
-      run_packet_queue();
-
-      do_announcements();
-
-      housekeeping();
-    }
-}
 
+       if (nmb->answers->rr_type == NMB_STATUS)
+       {
+               DEBUG(3,("Name status "));
+       }
 
-/****************************************************************************
-  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 (nmb->answers->rr_type == NMB_QUERY)
+       {
+               DEBUG(3,("Name query "));
+       }
 
-  if (isdaemon)
-    ClientNMB = open_socket_in(SOCK_DGRAM, port,0);
-  else
-    ClientNMB = 0;
+       if (nmb->answers->rr_type == NMB_REG)
+       {
+               DEBUG(3,("Name registration "));
+       }
 
-  ClientDGRAM = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3);
+       if (nmb->answers->rr_type == NMB_REL)
+       {
+               DEBUG(3,("Name release "));
+       }
 
-  if (ClientNMB == -1)
-    return(False);
+       DEBUG(3,("response for %s from %s (bcast=%s)\n",
+                  namestr(&nmb->answers->rr_name),
+                  inet_ntoa(p->ip),
+                  BOOLSTR(bcast)));
 
-  signal(SIGPIPE, SIGNAL_CAST sig_pipe);
+       if (!(n = find_name_query(nmb->header.name_trn_id)))
+       {
+               DEBUG(3,("unknown response (received too late or from nmblookup?)\n"));
+               return;
+       }
 
-  set_socket_options(ClientNMB,"SO_BROADCAST");
-  set_socket_options(ClientDGRAM,"SO_BROADCAST");
+       n->num_msgs++; /* count number of responses received */
 
-  DEBUG(3, ("Socket opened.\n"));
-  return True;
+       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;
+               }
+       }
 }
 
 
-/*******************************************************************
-  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(void )
+  process a nmb packet
+  ****************************************************************************/
+void process_nmb(struct packet_struct *p)
 {
-  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"));
-    }
-  }
+       struct nmb_packet *nmb = &p->packet.nmb;
 
-  if (! *myname) {
-    char *p;
-    strcpy(myname,myhostname);
-    p = strchr(myname,'.');
-    if (p) *p = 0;
-  }
-
-  {
-    extern fstring local_machine;
-    strcpy(local_machine,myname);
-    strupper(local_machine);
-  }
+       debug_nmb_packet(p);
 
-  return True;
-}
+       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;
+               }
+       }
 
-/****************************************************************************
-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");
 }
 
-
-/****************************************************************************
-  main program
-  **************************************************************************/
-int main(int argc,char *argv[])
-{
-  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"));
-
-  init_structs();
-
-  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();
-    }
-
-  if (dbf)
-    fclose(dbf);
-  return(0);
-}
diff --git a/source/namework.c b/source/namework.c
new file mode 100644 (file)
index 0000000..e28a1cb
--- /dev/null
@@ -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));
+