summaryrefslogtreecommitdiff
path: root/source/nmbd/nmbd.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/nmbd/nmbd.c')
-rw-r--r--source/nmbd/nmbd.c575
1 files changed, 575 insertions, 0 deletions
diff --git a/source/nmbd/nmbd.c b/source/nmbd/nmbd.c
new file mode 100644
index 00000000000..10b356d9b50
--- /dev/null
+++ b/source/nmbd/nmbd.c
@@ -0,0 +1,575 @@
+/*
+ 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"
+
+extern int DEBUGLEVEL;
+
+extern pstring debugf;
+pstring servicesf = CONFIGFILE;
+
+extern pstring scope;
+
+int ClientNMB = -1;
+int ClientDGRAM = -1;
+
+extern pstring myhostname;
+static pstring host_file;
+extern pstring myname;
+
+/* are we running as a daemon ? */
+static BOOL is_daemon = False;
+
+/* machine comment for host announcements */
+pstring ServerComment="";
+
+/* what server type are we currently */
+
+time_t StartupTime =0;
+
+extern struct in_addr ipzero;
+
+
+ /****************************************************************************
+ catch a sigterm
+ ****************************************************************************/
+static int sig_term()
+{
+ BlockSignals(True);
+
+ DEBUG(0,("Got SIGTERM: going down...\n"));
+
+ /* write out wins.dat file if samba is a WINS server */
+ dump_names();
+
+ /* remove all samba names, with wins server if necessary. */
+ remove_my_names();
+
+ /* announce all server entries as 0 time-to-live, 0 type */
+ /* XXXX don't care if we never receive a response back... yet */
+ remove_my_servers();
+
+ /* XXXX other things: if we are a master browser, force an election? */
+
+ exit(0);
+}
+
+
+/****************************************************************************
+catch a sighup
+****************************************************************************/
+static int sig_hup(void)
+{
+ BlockSignals(True);
+
+ DEBUG(0,("Got SIGHUP (reload not implemented)\n"));
+ dump_names();
+ reload_services(True);
+
+ BlockSignals(False);
+#ifndef DONT_REINSTALL_SIG
+ signal(SIGHUP,SIGNAL_CAST sig_hup);
+#endif
+ return(0);
+}
+
+/****************************************************************************
+catch a sigpipe
+****************************************************************************/
+static int sig_pipe(void)
+{
+ BlockSignals(True);
+
+ DEBUG(0,("Got SIGPIPE\n"));
+ if (!is_daemon)
+ exit(1);
+ BlockSignals(False);
+ return(0);
+}
+
+#if DUMP_CORE
+/*******************************************************************
+prepare to dump a core file - carefully!
+********************************************************************/
+static BOOL dump_core(void)
+{
+ char *p;
+ pstring dname;
+ strcpy(dname,debugf);
+ if ((p=strrchr(dname,'/'))) *p=0;
+ strcat(dname,"/corefiles");
+ mkdir(dname,0700);
+ sys_chown(dname,getuid(),getgid());
+ chmod(dname,0700);
+ if (chdir(dname)) return(False);
+ umask(~(0700));
+
+#ifndef NO_GETRLIMIT
+#ifdef RLIMIT_CORE
+ {
+ struct rlimit rlp;
+ getrlimit(RLIMIT_CORE, &rlp);
+ rlp.rlim_cur = MAX(4*1024*1024,rlp.rlim_cur);
+ setrlimit(RLIMIT_CORE, &rlp);
+ getrlimit(RLIMIT_CORE, &rlp);
+ DEBUG(3,("Core limits now %d %d\n",rlp.rlim_cur,rlp.rlim_max));
+ }
+#endif
+#endif
+
+
+ DEBUG(0,("Dumping core in %s\n",dname));
+ return(True);
+}
+#endif
+
+
+/****************************************************************************
+possibly continue after a fault
+****************************************************************************/
+static void fault_continue(void)
+{
+#if DUMP_CORE
+ dump_core();
+#endif
+}
+
+/*******************************************************************
+ expire old names from the namelist and server list
+ ******************************************************************/
+static void expire_names_and_servers(void)
+{
+ static time_t lastrun = 0;
+ time_t t = time(NULL);
+
+ if (!lastrun) lastrun = t;
+ if (t < lastrun + 5) return;
+ lastrun = t;
+
+ expire_names(t);
+ expire_servers(t);
+}
+
+/*****************************************************************************
+ reload the services file
+ **************************************************************************/
+BOOL reload_services(BOOL test)
+{
+ BOOL ret;
+ extern fstring remote_machine;
+
+ strcpy(remote_machine,"nmbd");
+
+ if (lp_loaded())
+ {
+ pstring fname;
+ strcpy(fname,lp_configfile());
+ if (file_exist(fname,NULL) && !strcsequal(fname,servicesf))
+ {
+ strcpy(servicesf,fname);
+ test = False;
+ }
+ }
+
+ if (test && !lp_file_list_changed())
+ return(True);
+
+ ret = lp_load(servicesf,True);
+
+ /* perhaps the config filename is now set */
+ if (!test) {
+ DEBUG(3,("services not loaded\n"));
+ reload_services(True);
+ }
+
+ load_interfaces();
+ add_subnet_interfaces();
+
+ return(ret);
+}
+
+
+
+/****************************************************************************
+load a netbios hosts file
+****************************************************************************/
+static void load_hosts_file(char *fname)
+{
+ FILE *f = fopen(fname,"r");
+ pstring line;
+ if (!f) {
+ DEBUG(2,("Can't open lmhosts file %s\n",fname));
+ return;
+ }
+
+ while (!feof(f))
+ {
+ if (!fgets_slash(line,sizeof(pstring),f)) continue;
+
+ if (*line == '#') continue;
+
+ {
+ BOOL group=False;
+
+ pstring ip,name,mask,flags,extra;
+
+ char *ptr;
+ int count = 0;
+ struct in_addr ipaddr;
+ struct in_addr ipmask;
+ enum name_source source = LMHOSTS;
+
+ strcpy(ip,"");
+ strcpy(name,"");
+ strcpy(mask,"");
+ strcpy(flags,"");
+ strcpy(extra,"");
+
+ ptr = line;
+
+ if (next_token(&ptr,ip ,NULL)) ++count;
+ if (next_token(&ptr,name ,NULL)) ++count;
+ if (next_token(&ptr,mask ,NULL)) ++count;
+ if (next_token(&ptr,flags,NULL)) ++count;
+ if (next_token(&ptr,extra,NULL)) ++count;
+
+ if (count <= 0) continue;
+
+ if (count > 0 && count < 2) {
+ DEBUG(0,("Ill formed hosts line [%s]\n",line));
+ continue;
+ }
+
+ /* work out if we need to shuffle the tokens along due to the
+ optional subnet mask argument */
+
+ if (strchr(mask, 'G') || strchr(mask, 'S') || strchr(mask, 'M')) {
+ strcpy(flags, mask );
+ /* default action for no subnet mask */
+ strcpy(mask, "");
+ }
+
+ DEBUG(4, ("lmhost entry: %s %s %s %s\n", ip, name, mask, flags));
+
+ if (strchr(flags,'G') || strchr(flags,'S'))
+ group = True;
+
+ if (strchr(flags,'M') && !group) {
+ source = SELF;
+ strcpy(myname,name);
+ }
+
+ ipaddr = *interpret_addr2(ip);
+ if (*mask)
+ ipmask = *interpret_addr2(mask);
+ else
+ ipmask = *iface_nmask(ipaddr);
+
+ if (group) {
+ add_subnet_entry(ipaddr, ipmask, name, True, True);
+ } else {
+ struct subnet_record *d = find_subnet(ipaddr);
+ if (d)
+ {
+ add_netbios_entry(d,name,0x20,NB_ACTIVE,0,source,ipaddr,True,True);
+ }
+ }
+ }
+ }
+
+ fclose(f);
+}
+
+
+/****************************************************************************
+ The main select loop.
+ ***************************************************************************/
+static void process(void)
+{
+ BOOL run_election;
+
+ while (True)
+ {
+ time_t t = time(NULL);
+ run_election = check_elections();
+ listen_for_packets(run_election);
+
+ run_packet_queue();
+ run_elections();
+
+ announce_host();
+
+#if 1
+ /* XXXX what was this stuff supposed to do? It sent
+ ANN_GetBackupListReq packets which I think should only be
+ sent when trying to find out who to browse with */
+
+ announce_backup();
+#endif
+
+ announce_master();
+
+ query_refresh_names();
+
+ expire_names_and_servers();
+ expire_netbios_response_entries();
+ refresh_my_names(t);
+
+ write_browse_list();
+ do_browser_lists();
+ check_master_browser();
+ }
+}
+
+
+/****************************************************************************
+ open the socket communication
+****************************************************************************/
+static BOOL open_sockets(BOOL isdaemon, int port)
+{
+ struct hostent *hp;
+
+ /* get host info */
+ if ((hp = Get_Hostbyname(myhostname)) == 0) {
+ DEBUG(0,( "Get_Hostbyname: Unknown host. %s\n",myhostname));
+ return False;
+ }
+
+ if (isdaemon)
+ ClientNMB = open_socket_in(SOCK_DGRAM, port,0);
+ else
+ ClientNMB = 0;
+
+ ClientDGRAM = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3);
+
+ if (ClientNMB == -1)
+ return(False);
+
+ signal(SIGPIPE, SIGNAL_CAST sig_pipe);
+
+ set_socket_options(ClientNMB,"SO_BROADCAST");
+ set_socket_options(ClientDGRAM,"SO_BROADCAST");
+
+ DEBUG(3,("Sockets opened.\n"));
+ return True;
+}
+
+
+/****************************************************************************
+ initialise connect, service and file structs
+****************************************************************************/
+static BOOL init_structs()
+{
+ if (!get_myname(myhostname,NULL))
+ return(False);
+
+ if (! *myname) {
+ char *p;
+ strcpy(myname,myhostname);
+ p = strchr(myname,'.');
+ if (p) *p = 0;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+usage on the program
+****************************************************************************/
+static void usage(char *pname)
+{
+ DEBUG(0,("Incorrect program usage - is the command line correct?\n"));
+
+ printf("Usage: %s [-n name] [-B bcast address] [-D] [-p port] [-d debuglevel] [-l log basename]\n",pname);
+ printf("Version %s\n",VERSION);
+ printf("\t-D become a daemon\n");
+ printf("\t-p port listen on the specified port\n");
+ printf("\t-d debuglevel set the debuglevel\n");
+ printf("\t-l log basename. Basename for log/debug files\n");
+ printf("\t-n netbiosname. the netbios name to advertise for this host\n");
+ printf("\t-B broadcast address the address to use for broadcasts\n");
+ printf("\t-N netmask the netmask to use for subnet determination\n");
+ printf("\t-H hosts file load a netbios hosts file\n");
+ printf("\t-G group name add a group name to be part of\n");
+ printf("\t-I ip-address override the IP address\n");
+ printf("\t-C comment sets the machine comment that appears in browse lists\n");
+ printf("\n");
+}
+
+
+/****************************************************************************
+ main program
+ **************************************************************************/
+ int main(int argc,char *argv[])
+{
+ int port = NMB_PORT;
+ int opt;
+ extern FILE *dbf;
+ extern char *optarg;
+ fstring group;
+
+ *group = 0;
+ *host_file = 0;
+
+ 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);
+ signal(SIGTERM,SIGNAL_CAST sig_term);
+
+ 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':
+ strcpy(group,optarg);
+ break;
+ case 'H':
+ strcpy(host_file,optarg);
+ break;
+ case 'I':
+ iface_set_default(optarg,NULL,NULL);
+ break;
+ case 'B':
+ iface_set_default(NULL,optarg,NULL);
+ break;
+ case 'N':
+ iface_set_default(NULL,NULL,optarg);
+ 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 (*group)
+ add_my_subnets(group);
+
+ if (!is_daemon && !is_a_socket(0)) {
+ DEBUG(0,("standard input is not a socket, assuming -D option\n"));
+ is_daemon = True;
+ }
+
+ if (is_daemon) {
+ DEBUG(2,("%s becoming a daemon\n",timestring()));
+ become_daemon();
+ }
+
+ DEBUG(3,("Opening sockets %d\n", port));
+
+ if (!open_sockets(is_daemon,port)) return 1;
+
+ if (*host_file) {
+ load_hosts_file(host_file);
+ DEBUG(3,("Loaded hosts file\n"));
+ }
+
+
+
+ if (!*ServerComment)
+ strcpy(ServerComment,"Samba %v");
+ string_sub(ServerComment,"%v",VERSION);
+ string_sub(ServerComment,"%h",myhostname);
+
+ add_my_names();
+ add_my_subnets(lp_workgroup());
+
+ DEBUG(3,("Checked names\n"));
+
+ load_netbios_names();
+
+ DEBUG(3,("Loaded names\n"));
+
+ write_browse_list();
+
+ DEBUG(3,("Dumped names\n"));
+
+ process();
+ close_sockets();
+
+ if (dbf)
+ fclose(dbf);
+ return(0);
+}