summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README88
-rw-r--r--docs/INSTALL.txt328
-rw-r--r--docs/MIRRORS32
-rw-r--r--docs/OS2.txt57
-rw-r--r--docs/README.OS281
-rw-r--r--docs/Warp.txt99
-rw-r--r--docs/announce30
-rw-r--r--docs/manpages/nmbd.88
-rw-r--r--docs/manpages/samba.710
-rw-r--r--docs/manpages/smb.conf.5154
-rw-r--r--docs/manpages/smbclient.129
-rw-r--r--docs/samba.faq606
-rw-r--r--docs/samba.lsm4
-rw-r--r--docs/textdocs/BROWSING.txt20
-rw-r--r--docs/textdocs/BUGS.txt15
-rw-r--r--docs/textdocs/DIAGNOSIS.txt8
-rw-r--r--docs/textdocs/HINTS.txt2
-rw-r--r--docs/textdocs/README.jis31
-rw-r--r--docs/textdocs/Support.txt59
-rw-r--r--docs/textdocs/UNIX-SMB.txt3
-rw-r--r--docs/textdocs/security_level.txt79
-rw-r--r--examples/misc/extra_smbstatus33
-rw-r--r--examples/misc/wall.perl76
-rw-r--r--examples/printer-accounting/README63
-rw-r--r--examples/printer-accounting/acct-all9
-rw-r--r--examples/printer-accounting/acct-sum29
-rw-r--r--examples/printer-accounting/hp5-redir43
-rw-r--r--examples/printer-accounting/lp-acct38
-rw-r--r--examples/printer-accounting/printcap22
-rw-r--r--examples/simple/smb.conf6
-rw-r--r--examples/thoralf/smb.conf152
-rw-r--r--examples/validchars/msdos70.out257
-rw-r--r--examples/validchars/nwdos70.out257
-rw-r--r--examples/validchars/readme101
-rw-r--r--examples/validchars/validchr.c123
-rw-r--r--examples/validchars/validchr.combin0 -> 9792 bytes
-rw-r--r--source/.cvsignore11
-rw-r--r--source/change-log12
-rw-r--r--source/client/client.c1056
-rw-r--r--source/client/clientutil.c1029
-rw-r--r--source/client/clitar.c17
-rw-r--r--source/include/byteorder.h64
-rw-r--r--source/include/charset.h4
-rw-r--r--source/include/includes.h73
-rw-r--r--source/include/local.h22
-rw-r--r--source/include/nameserv.h287
-rw-r--r--source/include/proto.h894
-rw-r--r--source/include/smb.h332
-rw-r--r--source/include/version.h2
-rw-r--r--source/internals.doc212
-rw-r--r--source/lib/access.c6
-rw-r--r--source/lib/charcnv.c9
-rw-r--r--source/lib/getsmbpass.c13
-rw-r--r--source/lib/interface.c457
-rw-r--r--source/lib/kanji.c5
-rw-r--r--source/lib/md4.c2
-rw-r--r--source/lib/replace.c322
-rw-r--r--source/lib/system.c15
-rw-r--r--source/lib/time.c495
-rw-r--r--source/lib/ufc.c4
-rw-r--r--source/lib/username.c1
-rw-r--r--source/lib/util.c1608
-rw-r--r--source/libsmb/namequery.c296
-rw-r--r--source/libsmb/nmblib.c443
-rw-r--r--source/libsmb/smbencrypt.c18
-rw-r--r--source/locking/locking.c134
-rw-r--r--source/nameannounce.c580
-rw-r--r--source/nameannounce.doc265
-rw-r--r--source/namebrowse.c219
-rw-r--r--source/namebrowse.doc149
-rw-r--r--source/namedbname.c562
-rw-r--r--source/namedbname.doc182
-rw-r--r--source/namedbresp.c160
-rw-r--r--source/namedbresp.doc100
-rw-r--r--source/namedbserver.c221
-rw-r--r--source/namedbsubnet.c327
-rw-r--r--source/namedbwork.c250
-rw-r--r--source/nameelect.c634
-rw-r--r--source/nameelect.doc256
-rw-r--r--source/namelogon.c145
-rw-r--r--source/namelogon.doc36
-rw-r--r--source/namepacket.c581
-rw-r--r--source/namepacket.doc133
-rw-r--r--source/namequery.doc83
-rw-r--r--source/nameresp.c302
-rw-r--r--source/nameresp.doc178
-rw-r--r--source/nameserv.c2412
-rw-r--r--source/nameserv.doc159
-rw-r--r--source/nameservreply.c569
-rw-r--r--source/nameservreply.doc213
-rw-r--r--source/nameservresp.c822
-rw-r--r--source/nameservresp.doc191
-rw-r--r--source/namework.c799
-rw-r--r--source/namework.doc363
-rw-r--r--source/nmbd/nmbd.c579
-rw-r--r--source/nmbsync.c386
-rw-r--r--source/param/loadparm.c143
-rw-r--r--source/param/params.c139
-rw-r--r--source/passdb/smbpass.c17
-rw-r--r--source/printing/pcap.c2
-rw-r--r--source/printing/printing.c88
-rwxr-xr-xsource/script/installbin.sh4
-rwxr-xr-xsource/script/installman.sh37
-rwxr-xr-xsource/script/installscripts.sh43
-rw-r--r--source/script/mkproto.awk82
-rw-r--r--source/script/smbtar1
-rwxr-xr-xsource/script/uninstallbin.sh43
-rwxr-xr-xsource/script/uninstallman.sh31
-rwxr-xr-xsource/script/uninstallscripts.sh37
-rw-r--r--source/smbd/chgpasswd.c3
-rw-r--r--source/smbd/dir.c34
-rw-r--r--source/smbd/ipc.c300
-rw-r--r--source/smbd/mangle.c59
-rw-r--r--source/smbd/message.c1
-rw-r--r--source/smbd/password.c42
-rw-r--r--source/smbd/predict.c145
-rw-r--r--source/smbd/quotas.c441
-rw-r--r--source/smbd/reply.c32
-rw-r--r--source/smbd/server.c695
-rw-r--r--source/smbd/smbrun.c75
-rw-r--r--source/smbd/trans2.c39
-rw-r--r--source/smbd/uid.c359
-rw-r--r--source/smbd/vt_mode.c26
-rw-r--r--source/utils/nmblookup.c53
-rw-r--r--source/utils/smbpasswd.c25
-rw-r--r--source/utils/status.c22
-rw-r--r--source/utils/testparm.c6
-rw-r--r--source/utils/testprns.c3
128 files changed, 19361 insertions, 6317 deletions
diff --git a/README b/README
index b7ef5d55957..1426c67bf1b 100644
--- a/README
+++ b/README
@@ -1,4 +1,6 @@
-This is version 1.9 of Samba, the free SMB client and server for unix.
+This is version 1.9 of Samba, the free SMB client and server for unix
+and other operating systems. Samba is maintained by the Samba Team,
+who support the original author and principal maintainer, Andrew Tridgell.
>>>> Please read THE WHOLE of this file as it gives important information
>>>> about the configuration and use of Samba.
@@ -7,54 +9,90 @@ This software is freely distributable under the GNU public license, a
copy of which you should have received with this software (in a file
called COPYING).
+WHAT IS SMB?
+============
+
+This is a big question.
+
+The very short answer is that it is the protocol by which a lot of
+PC-related machines share files and printers and other informatiuon
+such as lists of available files and printers. Operating systems that
+support this natively include Windows NT, OS/2, and Linux and add on
+packages that achieve the same thing are available for DOS, Windows,
+VMS, Unix of all kinds, MVS, and more. There is no reason why Apple
+Macs and indeed any Web browser should not be able to speak this
+protocol, and current development (in which the Samba team is heavily
+involved) is aimed at exactly that. Alternatives to SMB include
+Netware, NFS, Appletalk, Banyan Vines, Decnet etc; many of these have
+advantages but none are both public specifications and widely
+implemented in desktop machines by default.
+
+The Common Internet Filesystem is what the new SMB initiative is
+called. For details watch http://samba.anu.edu.au/cifs.
+
WHAT CAN SAMBA DO?
==================
-Here is a very short list of what samba includes, and what it does
+Here is a very short list of what samba includes, and what it does.
-- a SMB server, to provide LanManager style file and print services to PCs
+- a SMB server, to provide Windows NT and LAN Manager-style file and print
+ services to SMB clients such as Windows 95, Warp Server, smbfs and others.
-- a Netbios (rfc1001/1002) nameserver
+- a Netbios (rfc1001/1002) nameserver, which among other things gives
+ browsing support. Samba can be the master browser on your LAN if you wish.
- a ftp-like SMB client so you can access PC resources (disks and
-printers) from unix
+printers) from unix, Netware and other operating systems
- a tar extension to the client for backing up PCs
+For a much better overview have a look at the web site at
+http://samba.canberra.edu.au/pub/samba, and browse the user survey.
+
Related packages include:
-- ksmbfs, a linux-only filesystem allowing you to mount remote SMB
-filesystems from PCs on your linux box
+- smbfs, a linux-only filesystem allowing you to mount remote SMB
+filesystems from PCs on your linux box. This is included as standard with
+Linux 2.0 and later.
- tcpdump-smb, a extension to tcpdump to allow you to investigate SMB
-networking problems over netbeui and tcp/ip
+networking problems over netbeui and tcp/ip.
+- smblib, a library of smb functions which are designed to make it
+easy to smb-ise any particular application. See
+ftp://samba.anu.edu.au/pub/samba/smblib.
CONTRIBUTIONS
=============
If you want to contribute to the development of the software then
-please join the mailing list. I accept patches (preferably in
-"diff -u" format) and am always glad to receive feedback or suggestions.
+please join the mailing list. The Samba team accepts patches
+(preferably in "diff -u" format, see docs/BUGS.txt for more details)
+and are always glad to receive feedback or suggestions to the address
+samba-bugs@samba.anu.edu.au.
You could also send hardware/software/money/jewelry or pizza
-vouchers directly to me. The pizza vouchers would be especially
-welcome :-)
+vouchers directly to Andrew. The pizza vouchers would be especially
+welcome, in fact there is a special field in the survey for people who
+have paid up their pizza :-)
If you like a particular feature then look through the change-log and
see who added it, then send them an email.
Remember that free software of this kind lives or dies by the response
we get. If noone tells us they like it then we'll probably move onto
-something else.
+something else. However, as you can see from the user survey quite a lot of
+people do seem to like it at the moment :-)
Andrew Tridgell
-Email: samba-bugs@anu.edu.au
+Email: samba-bugs@samba.anu.edu.au
3 Ballow Crescent
Macgregor, A.C.T.
2615 Australia
+Samba Team
+Email: samba-team@samba.anu.edu.au
MORE INFO
=========
@@ -64,26 +102,26 @@ DOCUMENTATION
There is quite a bit of documentation included with the package,
including man pages, and lots of .txt files with hints and useful
-info.
+info. This is also available from the web page.
FTP SITE
--------
The main anonymous ftp distribution site for this software is
-nimbus.anu.edu.au in the directory pub/tridge/samba/.
+samba.anu.edu.au in the directory pub/samba/.
MAILING LIST
------------
There is a mailing list for discussion of Samba. To subscribe send
-mail to listproc@anu.edu.au with a body of "subscribe samba Your Name"
+mail to listproc@samba.anu.edu.au with a body of "subscribe samba Your Name"
To send mail to everyone on the list mail to samba@listproc.anu.edu.au
-There is also an announcement mailing list where I announce new
-versions. To subscribe send mail to listproc@anu.edu.au with a body
-of "subscribe samba-announce Your Name". All announcements also go to
-the samba list.
+There is also an announcement mailing list where new versions are
+announced. To subscribe send mail to listproc@samba.anu.edu.au with a
+body of "subscribe samba-announce Your Name". All announcements also
+go to the samba list.
NEWS GROUP
@@ -94,7 +132,7 @@ comp.protocols.smb as it often contains lots of useful info and is
frequented by lots of Samba users. The newsgroup was initially setup
by people on the Samba mailing list. It is not, however, exclusive to
Samba, it is a forum for discussing the SMB protocol (which Samba
-implements).
+implements). The samba list is gatewayed to this newsgroup.
WEB SITE
@@ -102,7 +140,11 @@ WEB SITE
A Samba WWW site has been setup with lots of useful info. Connect to:
-http://lake.canberra.edu.au/pub/samba/
+http://samba.canberra.edu.au/pub/samba/
+
+As well as general information and documentation, this also has searchable
+archives of the mailing list and a user survey that shows who else is using
+this package. Have you registered with the survey yet? :-)
It is maintained by Paul Blackman (thanks Paul!). You can contact him
at ictinus@lake.canberra.edu.au.
diff --git a/docs/INSTALL.txt b/docs/INSTALL.txt
new file mode 100644
index 00000000000..00b791e07aa
--- /dev/null
+++ b/docs/INSTALL.txt
@@ -0,0 +1,328 @@
+HOW TO INSTALL AND TEST SAMBA
+=============================
+
+
+STEP 0. Read the man pages. They contain lots of useful info that will
+help to get you started. If you don't know how to read man pages then
+try something like:
+
+ nroff -man smbd.8 | more
+
+STEP 1. Building the binaries
+
+To do this, first edit the file source/Makefile. You will find that
+the Makefile has an entry for most unixes and you need to uncomment
+the one that matches your operating system.
+
+You should also edit the section at the top of the Makefile which
+determines where things will be installed. You need to get this right
+before compilation as Samba needs to find some things at runtime
+(smbrun in particular). There are also settings for where you want
+your log files etc. Make sure you get these right, and that the
+directories exist.
+
+Then type "make". This will create the binaries.
+
+Once it's successfully compiled you can use "make install" to install
+the binaries and manual pages. You can separately install the binaries
+and/or man pages using "make installbin" and "make installman".
+
+Note that if you are upgrading for a previous version of Samba you
+might like to know that the old versions of the binaries will be
+renamed with a ".old" extension. You can go back to the previous
+version with "make revert" if you find this version a disaster!
+
+STEP 2. The all important step
+
+At this stage you must fetch yourself a coffee or other drink you find
+stimulating. Getting the rest of the install right can sometimes be
+tricky, so you will probably need it.
+
+If you have installed samba before then you can skip this step.
+
+STEP 3. Create the smb configuration file.
+
+There are sample configuration files in the examples subdirectory in
+the distribution. I suggest you read them carefully so you can see how
+the options go together in practice. See the man page for all the
+options.
+
+The simplest useful configuration file would be something like this:
+
+[homes]
+ workgroup = MYGROUP
+ guest ok = no
+ read only = no
+
+which would allow connections by anyone with an account on the server,
+using either their login name or "homes" as the service name. (Note
+that I also set the workgroup that Samba is part of. See BROWSING.txt
+for defails)
+
+Note that "make install" will not install a smb.conf file. You need to
+create it yourself. You will also need to create the path you specify
+in the Makefile for the logs etc, such as /usr/local/samba.
+
+Make sure you put the smb.conf file in the same place you specified in
+the Makefile.
+
+STEP 4. Test your config file with testparm
+
+It's important that you test the validity of your smb.conf file using
+the testparm program. If testparm runs OK then it will list the loaded
+services. If not it will give an error message.
+
+Make sure it runs OK and that the services look resonable before
+proceeding.
+
+STEP 5. Starting the smbd and nmbd.
+
+You must choose to start smbd and nmbd either as daemons or from
+inetd. Don't try to do both! Either you can put them in inetd.conf
+and have them started on demand by inetd, or you can start them as
+daemons either from the command line or in /etc/rc.local. See the man
+pages for details on the command line options.
+
+The main advantage of starting smbd and nmbd as a daemon is that they
+will respond slightly more quickly to an initial connection
+request. This is, however, unlilkely to be a problem.
+
+Step 5a. Starting from inetd.conf
+
+NOTE; The following will be different if you use NIS or NIS+ to
+distributed services maps.
+
+Look at your /etc/services. What is defined at port 139/tcp. If
+nothing is defined then add a line like this:
+
+netbios-ssn 139/tcp
+
+similarly for 137/udp you should have an entry like:
+
+netbios-ns 137/udp
+
+Next edit your /etc/inetd.conf and add two lines something like this:
+
+netbios-ssn stream tcp nowait root /usr/local/samba/bin/smbd smbd
+netbios-ns dgram udp wait root /usr/local/samba/bin/nmbd nmbd
+
+The exact syntax of /etc/inetd.conf varies between unixes. Look at the
+other entries in inetd.conf for a guide.
+
+NOTE: Some unixes already have entries like netbios_ns (note the
+underscore) in /etc/services. You must either edit /etc/services or
+/etc/inetd.conf to make them consistant.
+
+NOTE: On many systems you may need to use the "interfaces" option in
+smb.conf to specify the IP address and netmask of your interfaces. Run
+ifconfig as root if you don't know what the broadcast is for your
+net. nmbd tries to determine it at run time, but fails on some
+unixes. See the section on "testing nmbd" for a method of finding if
+you need to do this.
+
+!!!WARNING!!! Many unixes only accept around 5 parameters on the
+command line in inetd. This means you shouldn't use spaces between the
+options and arguments, or you should use a script, and start the
+script from inetd.
+
+Restart inetd, perhaps just send it a HUP. If you have installed an
+earlier version of nmbd then you may need to kill nmbd as well.
+
+Step 5b. Alternative: starting it as a daemon
+
+To start the server as a daemon you should create a script something
+like this one, perhaps calling it "startsmb"
+
+#!/bin/sh
+/usr/local/samba/bin/smbd -D
+/usr/local/samba/bin/nmbd -D
+
+then make it executable with "chmod +x startsmb"
+
+You can then run startsmb by hand or execute it from /etc/rc.local
+
+To kill it send a kill signal to the processes nmbd and smbd.
+
+
+
+STEP 7. Try listing the shares available on your server
+
+smbclient -L yourhostname
+
+Your should get back a list of shares available on your server. If you
+don't then something is incorrectly setup. Note that this method can
+also be used to see what shares are available on other LanManager
+clients (such as WfWg).
+
+If you choose user level security then you may find that Samba requests
+a password before it will list the shares. See the smbclient docs for
+details. (you can force it to list the shares without a password by
+adding the option -U% to the command line. This will not work with
+non-Samba servers)
+
+STEP 8. try connecting with the unix client. eg:
+
+smbclient '\\yourhostname\aservice'
+
+Typically the "yourhostname" would be the name of the host where you
+installed smbd. The "aservice" is any service you have defined in the
+smb.conf file. Try your user name if you just have a [homes] section
+in smb.conf.
+
+For example if your unix host is bambi and your login name is fred you
+would type:
+
+smbclient '\\bambi\fred'
+
+NOTE: The number of slashes to use depends on the type of shell you
+use. You may need '\\\\bambi\\fred' with some shells.
+
+STEP 9. Try connecting from a dos/WfWg/Win95/NT/os-2 client. Try
+mounting disks. eg:
+
+net use d: \\servername\service
+
+Try printing. eg:
+
+net use lpt1: \\servername\spoolservice
+print filename
+
+Celebrate, or send me a bug report!
+
+WHAT IF IT DOESN'T WORK?
+========================
+
+If nothing works and you start to think "who wrote this pile of trash"
+then I suggest you do step 2 again (and again) till you calm down.
+
+Then you might read the file DIAGNOSIS.txt and the FAQ. If you are
+still stuck then try the mailing list or newsgroup (look in the README
+for details). Samba has been successfully installed at thousands of
+sites worldwide, so maybe someone else has hit your problem and has
+overcome it. You could also use the WWW site to scan back issues of
+the samba-digest.
+
+When you fix the problem PLEASE send me some updates to the
+documentation (or source code) so that the next person will find it
+easier.
+
+DIAGNOSING PROBLEMS
+===================
+
+If you have instalation problems then go to DIAGNOSIS.txt to try to
+find the problem.
+
+SCOPE IDs
+=========
+
+By default Samba uses a blank scope ID. This means all your windows
+boxes must also have a blank scope ID. If you really want to use a
+non-blank scope ID then you will need to use the -i <scope> option to
+nmbd, smbd, and smbclient. All your PCs will need to have the same
+setting for this to work. I do not recommend scope IDs.
+
+
+CHOOSING THE PROTOCOL LEVEL
+===========================
+
+The SMB protocol has many dialects. Currently Samba supports 5, called
+CORE, COREPLUS, LANMAN1, LANMAN2 and NT1.
+
+You can choose what protocols to support in the smb.conf file. The
+default is NT1 and that is the best for the vast majority of sites.
+
+In older versions of Samba you may have found it necessary to use
+COREPLUS. The limitations that led to this have mostly been fixed. It
+is now less likely that you will want to use less than LANMAN1. The
+only remaining advantage of COREPLUS is that for some obscure reason
+WfWg preserves the case of passwords in this protocol, whereas under
+LANMAN1, LANMAN2 or NT1 it uppercases all passwords before sending them,
+forcing you to use the "password level=" option in some cases.
+
+The main advantage of LANMAN2 and NT1 is support for long filenames with some
+clients (eg: smbclient, Windows NT or Win95).
+
+See the smb.conf manual page for more details.
+
+Note: To support print queue reporting you may find that you have to
+use TCP/IP as the default protocol under WfWg. For some reason if you
+leave Netbeui as the default it may break the print queue reporting on
+some systems. It is presumably a WfWg bug.
+
+
+PRINTING FROM UNIX TO A CLIENT PC
+=================================
+
+To use a printer that is available via a smb-based server from a unix
+host you will need to compile the smbclient program. You then need to
+install the script "smbprint". Read the instruction in smbprint for
+more details.
+
+There is also a SYSV style script that does much the same thing called
+smbprint.sysv. It contains instructions.
+
+
+LOCKING
+=======
+
+One area which sometimes causes trouble is locking.
+
+There are two types of locking which need to be performed by a SMB
+server. The first is "record locking" which allows a client to lock a
+range of bytes in a open file. The second is the "deny modes" that are
+specified when a file is open.
+
+Samba supports "record locking" using the fcntl() unix system
+call. This is often implemented using rpc calls to a rpc.lockd process
+running on the system that owns the filesystem. Unfortunately many
+rpc.lockd implementations are very buggy, particularly when made to
+talk to versions from other vendors. It is not uncommon for the
+rpc.lockd to crash.
+
+There is also a problem translating the 32 bit lock requests generated
+by PC clients to 31 bit requests supported by most
+unixes. Unfortunately many PC applications (typically OLE2
+applications) use byte ranges with the top bit set as semaphore
+sets. Samba attempts translation to support these types of
+applications, and the translation has proved to be quite successful.
+
+Strictly a SMB server should check for locks before every read and
+write call on a file. Unfortunately with the way fcntl() works this
+can be slow and may overstress the rpc.lockd. It is also almost always
+unnecessary as clients are supposed to independently make locking
+calls before reads and writes anyway if locking is important to
+them. By default Samba only makes locking calls when explicitly asked
+to by a client, but if you set "strict locking = yes" then it will
+make lock checking calls on every read and write.
+
+You can also disable by range locking completely using "locking =
+no". This is useful for those shares that don't support locking or
+don't need it (such as cdroms). In this case Samba fakes the return
+codes of locking calls to tell clients that everything is OK.
+
+The second class of locking is the "deny modes". These are set by an
+application when it opens a file to determine what types of access
+should be allowed simultaneously with it's open. A client may ask for
+DENY_NONE, DENY_READ, DENY_WRITE or DENY_ALL. There are also special
+compatability modes called DENY_FCB and DENY_DOS.
+
+You can disable share modes using "share modes = no". This may be
+useful on a heavily loaded server as the share modes code is very
+slow.
+
+
+MAPPING USERNAMES
+=================
+
+If you have different usernames on the PCs and the unix server then
+take a look at the "username map" option. See the smb.conf man page
+for details.
+
+
+OTHER CHARACTER SETS
+====================
+
+If you have problems using filenames with accented characters in them
+(like the German, French or Scandinavian character sets) then I
+recommmend you look at the "valid chars" option in smb.conf and also
+take a look at the validchars package in the examples directory.
diff --git a/docs/MIRRORS b/docs/MIRRORS
new file mode 100644
index 00000000000..11efbf51d57
--- /dev/null
+++ b/docs/MIRRORS
@@ -0,0 +1,32 @@
+The main Samba site is samba.anu.edu.au in pub/samba/. Contact
+samba-bugs@samba.anu.edu.au for help with this site.
+
+Mirror sites include:
+
+ftp://nimbus.anu.edu.au/pub/tridge/samba
+ftp://sunsite.auc.dk/pub/unix/networking/samba/
+ftp://src.doc.ic.ac.uk/packages/samba/
+ftp://choc.satech.net.au/pub/samba/
+ftp://ftp.warwick.ac.uk/pub/linux/sunsite.unc-mirror/system/Network/samba/
+ftp://sunsite.unc.edu/pub/Linux/system/Network/samba/
+ftp://ftp.uni-trier.de/pub/unix/network/samba/
+ftp://ftp.spectrum.titan.com/pub/samba/
+ftp://ftp.demon.co.uk/pub/unix/unix/samba/
+ftp://sunsite.mff.cuni.cz/Net/Protocols/Samba/
+
+There are several others. Give archie a try.
+
+SCO binaries available from:
+ftp://ftp.markv.com/pub/samba (built by lance@fox.com)
+
+AIX and DEC OSF/1 binaries are available from:
+ftp://151.99.220.5/pub/samba (built by davide.migliavacca@inferentia.inet.it)
+
+QNX binaries and source code:
+ftp://quics.qnx.com/usr/free/staging/samba
+
+Http sites include:
+
+http://samba.canberra.edu.au/pub/samba
+http://www.choc.satech.net.au/pub/samba/
+
diff --git a/docs/OS2.txt b/docs/OS2.txt
new file mode 100644
index 00000000000..7d678a4bfb5
--- /dev/null
+++ b/docs/OS2.txt
@@ -0,0 +1,57 @@
+This describes how to use smbclient to connect to an OS/2 server.
+Knowing this allows you to use a OS/2 printer from unix.
+
+Author: riiber@oslonett.no
+
+
+How to login to an OS/2 server
+-------------------------------
+
+Sample setup for OS/2 server running LanMan 2.2:
+
+ OS/2 Server Name : \\OBV11
+ OS/2 User Account : ARNE
+ OS/2 Password : xxx
+ OS/2 shared service 1 : LASER02
+ OS/2 Shared service 2 : PCPROGS
+ Samba NetBIOS name : KLATREMUS
+
+First, the two servers were started with the commands
+smbd and nmbd -n KLATREMUS.
+
+Command to connect to a the shared printer LASER02 on the OS/2 server:
+n
+ smbclient '\\OBV11\LASER02' xxx -n ARNE -U ARNE -P
+
+and to connect to the shared drive 'PCPROGS':
+
+ smbclient '\\OBV11\PCPROGS' xxx -n ARNE -U ARNE
+
+
+If login to the OS/2 server fails:
+----------------------------------
+
+The remarkable OS/2 server requires NetBIOS name to be equal to User name.
+This was the only combination of (NetBIOS name, User name) that allowed login.
+
+Password xxx must be in upper case, case in user name is unimportant.
+
+The OS/2 server responds with "Bad password - name/password pair"
+if the password is illegal (in lowercase, for example).
+
+If correct user name and password, but invalid NetBIOS name is given,
+it responds with "... SMBtcon failed. ERRDOS - 65".
+
+The OS/2 server can disable login from a list of workstations (PCs)
+corresponding to the NetBIOS name (-n option). I set it up to
+allow login from any workstation.
+
+
+
+(I experimented quite a lot with the -U and -n options, printed and browsed
+the MS SMB protocol docs and the RFC's, then read some comp.protocols.smb,
+got some tips, tried some "stupid" command line options,
+and at last I got it working!)
+
+-Arne-
+
diff --git a/docs/README.OS2 b/docs/README.OS2
new file mode 100644
index 00000000000..a464dd9946c
--- /dev/null
+++ b/docs/README.OS2
@@ -0,0 +1,81 @@
+Samba 1.9.15p8 for OS/2 : REQUIRES emx 0.9b.
+
+
+Please read the file README, which contains general information about
+the configuration and use of Samba.
+
+
+Notes specific to OS/2 port:
+============================
+
+Filenames have been shortened to 8.3 in case anyone is using FAT.
+Files affected are:
+smb.conf -> smb.cfg smbclient -> smbclnt.exe
+smbstatus -> smbstat.exe nmblookup -> nmblook.exe
+
+As I only use HPFS, I can't guarantee this will work on FAT systems,
+although I have tried to stick to 8.3 filenames. I have noticed some
+temporary files being created with long filenames by smbd when I tried
+printing (which does not work yet anyway). nmbd will not be able to
+create browse lists on FAT systems, as it uses temporary files with
+long file names.
+
+smb.cfg should be in the directory smbd is started from. The path to
+smb.cfg is a compile time option, so if you are compiling from source
+you can set this to an absolute path to remove this restriction.
+
+User home directories not supported. This doesn't make much sense on
+OS/2. I haven't actually disabled anything, so if you try setting
+this up, behaivour is undefined.
+
+Password support is incomplete (I have found a crypt() routine, but
+lack of passwd file support in the EMX libraries make support difficult
+without major changes).
+
+Printing does not appear to be working. OS/2's lpq gives output in a
+different format than the versions of lpq already supported by samba.
+This will be easy to accomodate, but there is not much point until I can
+get lpr working properly.
+
+
+
+Source is available from the Samba WWW site :
+
+http://samba.canberra.edu.au/pub/samba/
+
+EMX 0.9b is available from hobbes.nmsu.edu, ftp.cdrom.com, ftp.leo.org and
+other OS/2 FTP sites. emxrt.zip contains the required libraries.
+
+Bugs:
+=====
+
+Known problems:
+===============
+
+Printing does not work. I have tried using REXX scripts with path info
+built in, and watched the processes startup properly but nothing comes
+out of the printer (remote via lpr in this case).
+If you can get it going, please let me know how you did it.
+
+The output from OS/2's lpq.exe is not understood by smbd, so all querys
+about the print queue say it is empty. Printing doesn't work anyway,
+so I have not attempted to fix this yet.
+
+Temporary files are created with long filenames (when printing, and updating
+browse list)
+
+Bug reports for the OS/2 port should be sent to Jason Rumney <jasonr@pec.co.nz>.
+
+Change log:
+===========
+
+Changes from release 1 to release 2.
+
+nmblookup (nmblook.exe) is included, and works.
+
+An attempt at password support was made using the gnuufc crypt routines,
+but then I found that a lot of functions in the EMX libraries to do with
+passwd files don't actually do anything.
+
+Browse lists should now work if you use HPFS and set your lock directory
+to an absolute pathname.
diff --git a/docs/Warp.txt b/docs/Warp.txt
new file mode 100644
index 00000000000..9b8e6782ba5
--- /dev/null
+++ b/docs/Warp.txt
@@ -0,0 +1,99 @@
+Here is some advice from maxfield@ctelcom.uucp.netcom.com (Wade Maxfie
+to use Samba with OS/2 Warp.
+
+Note that you may also find ftp://ftp.cdrom.com/pub/os2/new/os2net.faq
+useful.
+
+
+
+ Can I use Samba with Warp?
+
+ Yes. The MSClient software at ftp.microsoft.com in the Bussys
+(lanman os2 directory) will work, sort of. It is version 2.2c.
+
+ First, uncloack os2ver. (attrib -h -r -s c:\os2ver). It is a
+text file. change netwksta.xxx to 20=netwksta.sys. Also add
+20=setup.exe. Another change will be needed, a .vdd file. I remember
+it came up during the installation as being a wrong version. I wrote
+the name down, changed os2ver to include it, and restarted the
+installation.
+
+ Here is a copy of my os2ver
+
+setup.exe
+netbios.os2
+nwifs.ifs
+netwksta.sys
+nwreq.sys
+netbios.sys
+ipx.sys
+netvdd.sys
+
+Re-cloak os2ver. (attrib +h +r +s c:\os2ver)
+
+Run the installation from an OS/2 Box. Note that your mouse wont work,
+use the TAB key to move around, enter to select hilighted items.
+
+Here is a copy of my Config.sys file regarding the Laman entries.
+Note even though the version is 2.2c, it reports 2.2a in the text.
+
+REM ==== LANMAN 2.2a == DO NOT MODIFY BETWEEN THESE LINES == LANMAN 2.
+DEVICE=C:\LANMAN\DRIVERS\PROTMAN\PROTMAN.OS2 /i:C:\LANMAN
+DEVICE=C:\LANMAN\DRIVERS\ETHERNET\Ns2000\Ns2000.OS2
+RUN=C:\LANMAN\DRIVERS\PROTOCOL\tcpip\starttcp.exe
+RUN=C:\LANMAN\DRIVERS\PROTOCOL\tcpip\startnb.exe
+DEVICE=C:\LANMAN\DRIVERS\PROTOCOL\tcpip\tcpdrv.os2
+DEVICE=C:\LANMAN\DRIVERS\PROTOCOL\tcpip\nbdrv.os2
+DEVICE=C:\LANMAN\DRIVERS\PROTOCOL\tcpip\nmdrv.os2
+DEVICE=C:\LANMAN\arpa\sockdrv.os2
+DEVICE=C:\LANMAN\DRIVERS\PROTOCOL\NETBEUI\NETBEUI.OS2
+DEVICE=C:\LANMAN\NETPROG\RDRHELP.SYS
+IFS=C:\LANMAN\NETPROG\NETWKSTA.SYS /i:C:\LANMAN
+DEVICE=C:\LANMAN\NETPROG\NETVDD.SYS
+REM ==== LANMAN 2.2a == DO NOT MODIFY BETWEEN THESE LINES == LANMAN 2.
+
+
+ If you have an NE2000 card, don't reboot, or you'll be sorry.
+enable the automatic backup mechanism for recovering old config.sys and
+other files in OS/2. It paid for itself during this installation nightm
+before I knew better!)
+
+ Next, (or perhaps before this), if you have an NE2000 adaptor,
+get the ns2000 files from hobbes.nmsu.edu (in ns2000.zip). I manually
+patched protocol.ini to refer to that adaptor, and copied it into my
+c:\lanman directory. Note that I also modified the driver to be loaded
+in the config.sys to the ns2000.os2. It might install as an "other"
+adaptor.
+
+ A command file "startup.cmd" is placed in c:\. This file is
+automatically run when OS/2 Warp starts.
+Here is a copy of my startup file. Note that Warp sometimes fails to
+login properly to the server. I solve this by checking for the
+existance of a file, and rerunning the loing if that file fails to
+exist.
+
+@REM ==== LANMAN 2.2a == DO NOT MODIFY BETWEEN THESE LINES == LANMAN
+NET START WORKSTATION
+:relogin
+NET LOGON maxfield mypassword /y
+rem net use f: \\packard90\d$
+rem net use g: \\linuxone\cdromsdir
+rem net use h: \\linuxone\public
+:doOver
+if not exist f:\wildcat\wildcat.exe goto relogin
+@REM ==== LANMAN 2.2a == DO NOT MODIFY BETWEEN THESE LINES == LANMAN
+exit
+
+ Finally, the system expects to be on a domain with a domain
+server. BTW, TCP/IP and NetBeui allow simultaneous communication with
+Os/2 lanserver 4.0, and Samba. (Note: Lanserver 4.0 won't yet to
+TCP/IP. (Well,it might, but it crashes before I get to that point, so I
+havent' been able to enable it))
+
+I have not yet tried with only a SAMBA server on the domain.
+
+ I would be glad to try to answer any questions at above e-mail
+address, if I can.
+
+wade
+
diff --git a/docs/announce b/docs/announce
index f761320f43e..5740f37dc61 100644
--- a/docs/announce
+++ b/docs/announce
@@ -4,19 +4,21 @@
What is Samba?
--------------
-Samba is a Unix based SMB file server. This allows a Unix host to
-act as a file and print server for SMB clients. This includes
+Samba is a SMB file server that runs on Unix and other operating systems.
+It allows these operating systems (currently Unix, Netware, OS/2 and
+AmigaDOS) to act as a file and print server for SMB clients. There are many
Lan-Manager compatible clients such as LanManager for DOS, Windows for
Workgroups, Windows NT, Windows 95, OS/2, Pathworks and many more.
-The package also includes a Unix SMB client and a netbios nameserver.
+The package also includes a SMB client for accessing other SMB servers
+and a netbios nameserver for browsing support.
What can it do for me?
----------------------
If you have any PCs running SMB clients, such as a PC running Windows
-for Workgroups, then you can mount file space or printers from a unix
-host, so that directories, files and printers on the unix host are
+for Workgroups, then you can mount file space or printers on a Samba
+host, so that directories, files and printers on the host are
available on the PC.
The client part of the package will also allow you to attach to other
@@ -31,7 +33,7 @@ What are it's features?
Samba supports many features that are not supported in other SMB
implementations (all of which are commercial). Some of it's features
-include host as well as username/password security, a unix client,
+include host as well as username/password security, a client,
automatic home directory exporting, automatic printer exporting, dead
connection timeouts, umask support, guest connections, name mangling
and hidden and system attribute mapping. Look at the man pages
@@ -66,7 +68,7 @@ Samba software is free software. It is available under the
GNU Public licence in source code form at no cost. Please read the
file COPYING that comes with the package for more information.
-What flavours of unix does it support?
+What operating systems does it support?
---------------------------------------
The code has been written to be as portable as possible. It has been
@@ -79,7 +81,9 @@ Sequent, HP-UX, SGI, FreeBSD, NeXT, ISC, A/UX, SCO, Intergraph,
Domain/OS and DGUX.
Some of these have received more testing than others. If it doesn't
-work with your unix then it should be easy to fix.
+work with your unix then it should be easy to fix. It has also been ported
+to Netware, OS/2 and the Amiga. A VMS port is underway. See the web site
+for more details.
Who wrote it?
-------------
@@ -93,8 +97,8 @@ on who did what bits.
Where can I get it?
-------------------
-The package is available via anonymous ftp from nimbus.anu.edu.au in
-the directory pub/tridge/samba/.
+The package is available via anonymous ftp from samba.anu.edu.au in
+the directory pub/samba/.
What about SMBServer?
---------------------
@@ -123,7 +127,7 @@ There is also often quite a bit of discussion about Samba on the
newsgroup comp.protocols.smb.
A WWW site with lots of Samba info can be found at
-http://lake.canberra.edu.au/pub/samba/
+http://samba.canberra.edu.au/pub/samba/
-Andrew Tridgell (Contact: samba-bugs@anu.edu.au)
-January 1995
+The Samba Team (Contact: samba-bugs@anu.edu.au)
+June 1996
diff --git a/docs/manpages/nmbd.8 b/docs/manpages/nmbd.8
index e42f194cdee..d3f397563df 100644
--- a/docs/manpages/nmbd.8
+++ b/docs/manpages/nmbd.8
@@ -56,10 +56,6 @@ is by default the name of the host it is running on, but this can be overriden
with the
.B -n
option (see "OPTIONS" below). Using the
-.B -S
-option (see "OPTIONS" below), it can also be instructed to respond with IP
-information about other hosts, provided they are locatable via the
-gethostbyname() call, or they are in a netbios hosts file.
Nmbd can also be used as a WINS (Windows Internet Name Server)
server. It will do this automatically by default. What this basically
@@ -154,7 +150,7 @@ option has been selected).
A S or G means that the specified address is a broadcast address of a
network that you want people to be able to browse you from. Nmbd will
search for a master browser in that domain and will send host
-announcements to that machine, informing it that the specifed somain
+announcements to that machine, informing it that the specified domain
is available.
A M means that this name is the default netbios name for this
@@ -267,7 +263,6 @@ log.nmb.out (containing outbound transaction data)
The log files generated are never removed by the server.
.RE
-.RE
.B -n
.I netbios name
@@ -327,7 +322,6 @@ If running the server via the meta-daemon inetd, this file must contain a
mapping of service name (eg., netbios-ns) to service port (eg., 137) and
protocol type (eg., udp). See the section "INSTALLATION" below.
.RE
-.RE
.SH ENVIRONMENT VARIABLES
Not applicable.
diff --git a/docs/manpages/samba.7 b/docs/manpages/samba.7
index 0c81f736b6e..ac106e00224 100644
--- a/docs/manpages/samba.7
+++ b/docs/manpages/samba.7
@@ -18,7 +18,7 @@ you read the documentation that comes with Samba and the manual pages
of those components that you use. If the manual pages aren't clear
enough then please send me a patch!
-The smbd(8) daemon provides the file and print services to SMB clents,
+The smbd(8) daemon provides the file and print services to SMB clients,
such as Windows for Workgroups, Windows NT or LanManager. The
configuration file for this daemon is described in smb.conf(5).
@@ -45,7 +45,7 @@ encouraged to distribute copies of the Samba suite, but please keep it
intact.
The latest version of the Samba suite can be obtained via anonymous
-ftp from nimbus.anu.edu.au in the directory pub/tridge/samba/. It is
+ftp from samba.anu.edu.au in the directory pub/samba/. It is
also available on several mirror sites worldwide.
You may also find useful information about Samba on the newsgroup
@@ -54,14 +54,14 @@ the mailing list are given in the README file that comes with Samba.
If you have access to a WWW viewer (such as Netscape or Mosaic) then
you will also find lots of useful information, including back issues
-of the Samba mailing list, at http://lake.canberra.edu.au/pub/samba/
+of the Samba mailing list, at http://samba.canberra.edu.au/pub/samba/
.SH AUTHOR
The main author of the Samba suite is Andrew Tridgell. He may be
contacted via e-mail at samba-bugs@anu.edu.au.
-There have also been an enourmous number of contributors to Samba from
+There have also been an enormous number of contributors to Samba from
all over the world. A partial list of these contributors is included
in the CREDITS section below. The list is, however, badly out of
date. More up to date info may be obtained from the change-log that
@@ -74,7 +74,7 @@ join the Samba mailing list.
If you have patches to submit or bugs to report then you may mail them
directly to samba-bugs@anu.edu.au. Note, however, that due to the
-enourmous popularity of this package I may take some time to repond to
+enormous popularity of this package I may take some time to repond to
mail. I prefer patches in "diff -u" format.
.SH CREDITS
diff --git a/docs/manpages/smb.conf.5 b/docs/manpages/smb.conf.5
index 933d71ff0c3..7f67ae4e123 100644
--- a/docs/manpages/smb.conf.5
+++ b/docs/manpages/smb.conf.5
@@ -35,7 +35,7 @@ within a parameter value is retained verbatim.
Any line beginning with a semicolon is ignored, as are lines containing
only whitespace.
-Any line ending in a \\ is "continued" on the next line in the
+Any line ending in a \e is "continued" on the next line in the
customary unix fashion.
The values following the equals sign in parameters are all either a string
@@ -212,6 +212,7 @@ could be used simply to limit access to a subset of your local printers.
An alias, by the way, is defined as any component of the first entry of a
printcap record. Records are separated by newlines, components (if there are
more than one) are separated by vertical bar symbols ("|").
+.RE
.SH PARAMETERS
Parameters define the specific attributes of services.
@@ -221,7 +222,7 @@ permissible only in normal sections. For the purposes of the following
descriptions the [homes] and [printers] sections will be considered normal.
The letter 'G' in parentheses indicates that a parameter is specific to the
[global] section. The letter 'S' indicates that a parameter can be
-specified in a secvice specific section. Note that all S parameters
+specified in a service specific section. Note that all S parameters
can also be specified in the [global] section - in which case they
will define the default behaviour for all services.
@@ -237,7 +238,7 @@ interpreted as "path = /tmp/john" if the user connected with the
username john.
These substitutions are mostly noted in the descriptions below, but
-there are some general substitions which apply whenever they might be
+there are some general substitutions which apply whenever they might be
relevant. These are:
%S = the name of the current service, if any
@@ -459,6 +460,8 @@ comment
default case
+delete readonly
+
deny hosts
directory
@@ -657,7 +660,7 @@ See testparm(1) for a way of testing your host access to see if it
does what you expect.
.B Default:
- none (ie., all hosts permitted access)
+ none (i.e., all hosts permitted access)
.B Example:
allow hosts = 150.203.5. myhost.mynet.edu.au
@@ -831,6 +834,19 @@ things.
path = /%S
+.SS delete readonly (S)
+This parameter allows readonly files to be deleted. This is not normal DOS
+semantics, but is allowed by Unix.
+
+This option may be useful for running applications such as rcs, where unix
+file ownership prevents changing file permissions, and dos semantics prevent
+deletion of a read only file.
+
+.B Default:
+ delete readonly = No
+
+.B Example:
+ delete readonly = Yes
.SS deny hosts (S)
A synonym for this parameter is 'hosts deny'.
@@ -839,7 +855,7 @@ access to services unless the specific services have their own lists to
override this one. Where the lists conflict, the 'allow' list takes precedence.
.B Default:
- none (ie., no hosts specifically excluded)
+ none (i.e., no hosts specifically excluded)
.B Example:
deny hosts = 150.203.4. badhost.mynet.edu.au
@@ -895,11 +911,11 @@ Linux) that are either not of interest to clients or are infinitely deep
of directories that the server should always show as empty.
Note that Samba can be very fussy about the exact format of the "dont
-descend" entries. For example you ma need "./proc" instead of just
+descend" entries. For example you may need "./proc" instead of just
"/proc". Experimentation is the best policy :-)
.B Default:
- none (ie., all directories are OK to descend)
+ none (i.e., all directories are OK to descend)
.B Example:
dont descend = /proc,/dev
@@ -907,7 +923,7 @@ descend" entries. For example you ma need "./proc" instead of just
.SS encrypt passwords (G)
This boolean controls whether encrypted passwords will be negotiated
-with the cient. Note that this option has no effect if you haven't
+with the client. Note that this option has no effect if you haven't
compiled in the necessary des libraries and encryption code. It
defaults to no.
@@ -1007,7 +1023,7 @@ See
.B deny hosts.
.SS group (S)
-This is an alias for "force group" and is only kept for compatability
+This is an alias for "force group" and is only kept for compatibility
with old versions of Samba. It may be removed in future versions.
.SS hosts equiv (G)
@@ -1033,6 +1049,31 @@ or perhaps on a home network where you trust your wife and kids :-)
.B Example
hosts equiv = /etc/hosts.equiv
+.SS interfaces (G)
+
+This option allows you to setup multiple network interfaces, so that
+Samba can properly handle browsing on all interfaces.
+
+The option takes a list of ip/netmask pairs. The netmask may either be
+a bitmask, or a bitlength.
+
+For example, the following line:
+
+interfaces = 192.168.2.10/24 192.168.3.10/24
+
+would configure two network interfaces with IP addresses 192.168.2.10
+and 192.168.3.10. The netmasks of both interfaces would be set to
+255.255.255.0.
+
+You could produce an equivalent result by using:
+
+interfaces = 192.168.2.10/255.255.255.0 192.168.3.10/255.255.255.0
+
+if you prefer that format.
+
+If this option is not set then Samba will attempt to find a primary
+interface, but won't attempt to configure more than one interface.
+
.SS invalid users (S)
This is a list of users that should not be allowed to login to this
service. This is really a "paranoid" check to absolutely ensure an
@@ -1187,9 +1228,9 @@ order to obtain "lpq"-style printer status information.
This command should be a program or script which takes a printer name
as its only parameter and outputs printer status information.
-Currently four styles of printer status information are supported;
-BSD, SYSV, AIX and HPUX. This covers most unix systems. You control
-which type is expected using the "printing =" option.
+Currently six styles of printer status information are supported; BSD,
+SYSV, AIX, HPUX, QNX and PLP. This covers most unix systems. You
+control which type is expected using the "printing =" option.
Some clients (notably Windows for Workgroups) may not correctly send the
connection number for the printer they are requesting status information
@@ -1235,8 +1276,8 @@ order to delete a print job.
This command should be a program or script which takes a printer name
and job number, and deletes the print job.
-Currently four styles of printer control are supported; BSD, SYSV, AIX
-and HPUX. This covers most unix systems. You control which type is
+Currently six styles of printer control are supported; BSD, SYSV, AIX
+HPUX, QNX and PLP. This covers most unix systems. You control which type is
expected using the "printing =" option.
If a %p is given then the printername is put in it's place. A %j is
@@ -1379,6 +1420,28 @@ software. Use this option to set it to whatever you prefer.
.B Example:
mangling char = ^
+.SS max disk size (G)
+This option allows you to put an upper limit on the apparent size of
+disks. If you set this option to 100 then all shares will appear to be
+not larger than 100 MB in size.
+
+Note that this option does not limit the amount of data you can put on
+the disk. In the above case you could still store much more than 100
+MB on the disk, but if a client ever asks for the amount of free disk
+space or the total disk size then the result will be bounded by the
+amount specified in "max disk size".
+
+This option is primarily useful to work around bugs in some pieces of
+software that can't handle very large disks, particularly disks over
+1GB in size.
+
+A "max disk size" of 0 means no limit.
+
+.B Default:
+ max disk size = 0
+
+.B Example:
+ max disk size = 1000
.SS max log size (G)
This option (an integer in kilobytes) specifies the max size the log
@@ -1881,8 +1944,9 @@ This parameters controls how printer status information is interpreted
on your system, and also affects the default values for the "print
command", "lpq command" and "lprm command".
-Currently three printing styles are supported. They are "printing =
-bsd", "printing = sysv", "printing = hpux" and "printing = aix".
+Currently six printing styles are supported. They are "printing =
+bsd", "printing = sysv", "printing = hpux", "printing = aix",
+"printing = qnx" and "printing = plp".
To see what the defaults are for the other print commands when using
these three options use the "testparm" program.
@@ -1900,9 +1964,13 @@ minimal file that looks like a printcap and set "printcap name =" in
A minimal printcap file would look something like this:
print1|My Printer 1
+.br
print2|My Printer 2
+.br
print3|My Printer 3
+.br
print4|My Printer 4
+.br
print5|My Printer 5
where the | separates aliases of a printer. The fact that the second
@@ -1931,9 +1999,26 @@ for any printable service that does not have its own printer name specified.
.B Example:
printer name = laserwriter
+
+.SS printer driver (S)
+This option allows you to control the string that clients receive when
+they ask the server for the printer driver associated with a
+printer. If you are using Windows95 or WindowsNT then you can use this
+to automate the setup of printers on your system.
+
+You need to set this parameter to the exact string (case sensitive)
+that describes the appropriate printer driver for your system.
+If you don't know the exact string to use then you should first try
+with no "printer driver" option set and the client will give you a
+list of printer drivers. The appropriate strings are shown in a
+scrollbox after you have chosen the printer manufacturer.
+.B Example:
+ printer driver = HP LaserJet 4L
+
.SS printer name (S)
See
.B printer.
+
.SS protocol (G)
The value of the parameter (a string) is the highest protocol level that will
be supported by the server.
@@ -1941,6 +2026,9 @@ be supported by the server.
Possible values are CORE, COREPLUS, LANMAN1, LANMAN2 and NT1. The relative
merits of each are discussed in the README file.
+Normally this option should not be set as the automatic negotiation
+phase in the SMB protocol takes care of choosing the appropriate protocol.
+
.B Default:
protocol = NT1
@@ -2486,6 +2574,13 @@ the uppercase and lowercase mappings appropriately.
The above example allows filenames to have the swedish characters in
them.
+NOTE: It is actually quite difficult to correctly produce a "valid
+chars" line for a particular system. To automate the process
+tino@augsburg.net has written a package called "validchars" which will
+automatically produce a complete "valid chars" line for a given client
+system. Look in the examples subdirectory for this package.
+
+
.SS valid users (S)
This is a list of users that should be allowed to login to this
service. A name starting with @ is interpreted as a unix group.
@@ -2524,6 +2619,33 @@ only to areas that are outside the directory tree being exported.
.B Example:
wide links = no
+.SS wins proxy (G)
+
+This is a boolean that controls if nmbd will respond to broadcast name
+queries on behalf of other hosts. You may need to set this to no for
+some older clients.
+
+.B Default:
+ wins proxy = no
+.SS wins support (G)
+
+This boolean controls if Samba will act as a WINS server. You should
+normally set this to true unless you already have another WINS server
+on the network.
+
+.B Default:
+ wins support = yes
+.SS wins server (G)
+
+This specifies the DNS name of the WINS server that Samba should
+register with. If you have a WINS server on your network then you
+should set this to the WINS servers name.
+
+This option only takes effect if Samba is not acting as a WINS server
+itself.
+
+.B Default:
+ wins server =
.SS workgroup (G)
This controls what workgroup your server will appear to be in when
diff --git a/docs/manpages/smbclient.1 b/docs/manpages/smbclient.1
index 5590e01296e..e0af67ca1a4 100644
--- a/docs/manpages/smbclient.1
+++ b/docs/manpages/smbclient.1
@@ -36,13 +36,21 @@ smbclient \- ftp-like Lan Manager client program
.B -n
.I netbios name
] [
+.B -W
+.I workgroup
+] [
.B -O
.I socket options
] [
.B -p
.I port number
+] [
+.B -c
+.I command string
+] [
.B -T
.I tar options
+] [
.B -D
.I initial directory
]
@@ -323,6 +331,14 @@ uppercase) as its netbios name. This parameter allows you to override
the host name and use whatever netbios name you wish.
.RE
+.B -W
+.I workgroup
+
+.RS 3
+Override what workgroup is used for the connection. This may be needed
+to connect to some servers.
+.RE
+
.B -p
.I port number
.RS 3
@@ -429,6 +445,19 @@ with the tar (\-T) option.
.RE
+.B -c
+.I command string
+
+.RS 3
+
+command string is a semicolon separated list of commands to be
+executed instead of prompting from stdin. -N is implied by -c.
+
+This is particularly useful in scripts and for printing stdin to
+the server, e.g. -c 'print -'.
+
+.RE
+
.SH OPERATIONS
Once the client is running, the user is presented with a prompt, "smb: \\>".
The backslash ("\\") indicates the current working directory on the server,
diff --git a/docs/samba.faq b/docs/samba.faq
new file mode 100644
index 00000000000..86dd48877f8
--- /dev/null
+++ b/docs/samba.faq
@@ -0,0 +1,606 @@
+
+ Frequently Asked Questions
+
+ about the
+
+ SAMBA Suite
+
+ (FAQ version 1.9.15a, Samba version 1.09.15)
+
+-------------------------------------------------------------------------------
+
+This FAQ was originally prepared by Karl Auer (Karl.Auer@anu.edu.au) and is
+currently maintained by Paul Blackman (ictinus@lake.canberra.edu.au).
+
+As Karl originally said, 'this FAQ was prepared with lots of help from numerous
+net.helpers', and that's the way I'd like to keep it. So if you find anything
+that you think should be in here don't hesitate to contact me.
+
+Thanks to Karl for the work he's done, and continuing thanks to Andrew Tridgell
+for developing Samba.
+
+Note: This FAQ is (and probably always will be) under construction. Some
+sections exist only as optimistic entries in the Contents page.
+
+-------------------------------------------------------------------------------
+
+Contents
+
+ * SECTION ONE: General information
+ All about Samba - what it is, how to get it, related sources of
+ information.
+ * SECTION TWO: Compiling and installing Samba on a Unix host
+ Common problems that arise when building and installing Samba under
+ Unix.
+ * SECTION THREE: Common client problems
+ Common problems that arise when trying to communicate from a client
+ computer to a Samba server. All problems which have symptoms you see
+ at the client end will be in this section.
+ * SECTION FOUR: Specific client problems
+ This section covers problems that are specific to certain clients,
+ such as Windows for Workgroups or Windows NT. Please check Section
+ Three first!
+ * SECTION FIVE: Specific client application problems
+ This section covers problems that are specific to certain products,
+ such as Windows for Workgroups or Windows NT. Please check Sections
+ Three and Four first!
+ * SECTION SIX: Miscellaneous
+ All the questions that aren't classifiable into any other section.
+
+
+===============================================================================
+SECTION ONE: General information
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* 1: What is Samba?
+
+Samba is a suite of programs which work together to allow clients to access
+to a server's filespace and printers via the SMB (Session Message Block)
+protocol. Initially written for Unix, Samba now also runs on Netware, OS/2 and
+AmigaDOS.
+
+In practice, this means that you can redirect disks and printers to Unix disks
+and printers from Lan Manager clients, Windows for Workgroups 3.11 clients,
+Windows NT clients, Linux clients and OS/2 clients. There is also a generic
+Unix client program supplied as part of the suite which allows Unix users to
+use an ftp-like interface to access filespace and printers on any other SMB
+servers. This gives the capability for these operating systems to behave much
+like a LAN Server or Windows NT Server machine, only with added functionality
+and flexibility designed to make life easier for administrators.
+
+The components of the suite are (in summary):
+
+ * smbd, the SMB server. This handles actual connections from clients,
+ doing all the file, permission and username work
+ * nmbd, the Netbios name server, which helps clients locate servers,
+ doing the browsing work and managing domains as this capability is
+ being built into Samba
+ * smbclient, the Unix-hosted client program
+ * smbrun, a little 'glue' program to help the server run external
+ programs
+ * testprns, a program to test server access to printers
+ * testparms, a program to test the Samba configuration file for
+ correctness
+ * smb.conf, the Samba configuration file
+ * smbprint, a sample script to allow a Unix host to use smbclient to
+ print to an SMB server
+ * documentation! DON'T neglect to read it - you will save a great deal
+ of time!
+
+The suite is supplied with full source (of course!) and is GPLed.
+
+The primary creator of the Samba suite is Andrew Tridgell. Later versions
+incorporate much effort by many net.helpers. The man pages and this FAQ were
+originally written by Karl Auer.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* 2: What is the current version of Samba?
+
+At time of writing, the current version was 1.9.15. If you want to be sure
+check the bottom of the change-log file.
+(ftp://samba.anu.edu.au/pub/samba/alpha/change-log)
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* 3: Where can I get it?
+
+The Samba suite is available via anonymous ftp from samba.anu.edu.au. The
+latest and greatest versions of the suite are in the directory:
+
+/pub/samba/
+
+Development (read "alpha") versions, which are NOT necessarily stable and which
+do NOT necessarily have accurate documentation, are available in the directory:
+
+/pub/samba/alpha
+
+Note that binaries are NOT included in any of the above. Samba is distributed
+ONLY in source form, though binaries may be available from other sites. Recent
+versions of some Linux distributions, for example, do contain Samba binaries
+for that platform.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* 4: What platforms are supported?
+
+Many different platforms have run Samba successfully. The platforms most widely
+used and thus best tested are Linux and SunOS.
+
+At time of writing, the Makefile claimed support for:
+
+ * SunOS
+ * Linux with shadow passwords
+ * Linux without shadow passwords
+ * SOLARIS
+ * SOLARIS 2.2 and above (aka SunOS 5)
+ * SVR4
+ * ULTRIX
+ * OSF1 (alpha only)
+ * OSF1 with NIS and Fast Crypt (alpha only)
+ * OSF1 V2.0 Enhanced Security (alpha only)
+ * AIX
+ * BSDI
+ * NetBSD
+ * NetBSD 1.0
+ * SEQUENT
+ * HP-UX
+ * SGI
+ * SGI IRIX 4.x.x
+ * SGI IRIX 5.x.x
+ * FreeBSD
+ * NeXT 3.2 and above
+ * NeXT OS 2.x
+ * NeXT OS 3.0
+ * ISC SVR3V4 (POSIX mode)
+ * ISC SVR3V4 (iBCS2 mode)
+ * A/UX 3.0
+ * SCO with shadow passwords.
+ * SCO with shadow passwords, without YP.
+ * SCO with TCB passwords
+ * SCO 3.2v2 (ODT 1.1) with TCP passwords
+ * intergraph
+ * DGUX
+ * Apollo Domain/OS sr10.3 (BSD4.3)
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* 5: How can I find out more about Samba?
+
+There are two mailing lists devoted to discussion of Samba-related matters.
+There is also the newsgroup, comp.protocols.smb, which has a great deal of
+discussion on Samba. There is also a WWW site 'SAMBA Web Pages' at
+http://samba.canberra.edu.au/pub/samba/samba.html, under which there is a
+comprehensive survey of Samba users. Another useful resource is the hypertext
+archive of the Samba mailing list.
+
+Send email to listproc@anu.edu.au. Make sure the subject line is blank, and
+include the following two lines in the body of the message:
+
+ subscribe samba Firstname Lastname
+ subscribe samba-announce Firstname Lastname
+
+Obviously you should substitute YOUR first name for "Firstname" and YOUR last
+name for "Lastname"! Try not to send any signature stuff, it sometimes confuses
+the list processor.
+
+The samba list is a digest list - every eight hours or so it regurgitates a
+single message containing all the messages that have been received by the list
+since the last time and sends a copy of this message to all subscribers.
+
+If you stop being interested in Samba, please send another email to
+listproc@anu.edu.au. Make sure the subject line is blank, and include the
+following two lines in the body of the message:
+
+ unsubscribe samba
+ unsubscribe samba-announce
+
+The From: line in your message MUST be the same address you used when you
+subscribed.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* 6: Something's gone wrong - what should I do?
+
+[#] *** IMPORTANT! *** [#]
+DO NOT post messages on mailing lists or in newsgroups until you have carried
+out the first three steps given here!
+
+Firstly, see if there are any likely looking entries in this FAQ! If you have
+just installed Samba, have you run through the checklist in DIAGNOSIS.txt? It
+can save you a lot of time and effort.
+
+Secondly, read the man pages for smbd, nmbd and smb.conf, looking for topics
+that relate to what you are trying to do.
+
+Thirdly, if there is no obvious solution to hand, try to get a look at the log
+files for smbd and/or nmbd for the period during which you were having
+problems. You may need to reconfigure the servers to provide more extensive
+debugging information - usually level 2 or level 3 provide ample debugging
+info. Inspect these logs closely, looking particularly for the string "Error:".
+
+Fourthly, if you still haven't got anywhere, ask the mailing list or newsgroup.
+In general nobody minds answering questions provided you have followed the
+preceding steps. It might be a good idea to scan the archives of the mailing
+list, which are available through the Samba web site described in the previous
+section.
+
+If you successfully solve a problem, please mail the FAQ maintainer a succinct
+description of the symptom, the problem and the solution, so I can incorporate
+it in the next version.
+
+If you make changes to the source code, _please_ submit these patches so that
+everyone else gets the benefit of your work. This is one of the most important
+aspects to the maintainence of Samba. Send all patches to
+samba-bugs@samba.anu.edu.au, not Andrew Tridgell or any other individual.
+
+===============================================================================
+SECTION TWO: Compiling and installing Samba on a Unix host
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+===============================================================================
+SECTION THREE: Common client problems
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* 1: I can't see the Samba server in any browse lists!
+
+*** Until the FAQ can be updated, please check the file:
+*** ftp://samba.anu.edu.au/pub/samba/BROWSING.txt
+*** for more information on browsing.
+
+If your GUI client does not permit you to select non-browsable servers, you may
+need to do so on the command line. For example, under Lan Manager you might
+connect to the above service as disk drive M: thusly:
+
+ net use M: \\mary\fred
+
+The details of how to do this and the specific syntax varies from client to
+client - check your client's documentation.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* 2: Some files that I KNOW are on the server doesn't show up when I view the
+ directories from my client!
+
+If you check what files are not showing up, you will note that they are files
+which contain upper case letters or which are otherwise not DOS-compatible (ie,
+they are not legal DOS filenames for some reason).
+
+The Samba server can be configured either to ignore such files completely, or
+to present them to the client in "mangled" form. If you are not seeing the
+files at all, the Samba server has most likely been configured to ignore them.
+Consult the man page smb.conf(5) for details of how to change this - the
+parameter you need to set is "mangled names = yes".
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* 3: Some files on the server show up with really wierd filenames when I view
+the directories from my client!
+
+If you check what files are showing up wierd, you will note that they are files
+which contain upper case letters or which are otherwise not DOS-compatible (ie,
+they are not legal DOS filenames for some reason).
+
+The Samba server can be configured either to ignore such files completely, or
+to present them to the client in "mangled" form. If you are seeing strange file
+names, they are most likely "mangled". If you would prefer to have such files
+ignored rather than presented in "mangled" form, consult the man page
+smb.conf(5) for details of how to change the server configuration - the
+parameter you need to set is "mangled names = no".
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* 4: My client reports "cannot locate specified computer" or similar.
+
+This indicates one of three things: You supplied an incorrect server name, the
+underlying TCP/IP layer is not working correctly, or the name you specified
+cannot be resolved.
+
+After carefully checking that the name you typed is the name you should have
+typed, try doing things like pinging a host or telnetting to somewhere on your
+network to see if TCP/IP is functioning OK. If it is, the problem is most
+likely name resolution.
+
+If your client has a facility to do so, hardcode a mapping between the hosts IP
+and the name you want to use. For example, with Man Manager or Windows for
+Workgroups you would put a suitable entry in the file LMHOSTS. If this works,
+the problem is in the communication between your client and the netbios name
+server. If it does not work, then there is something fundamental wrong with
+your naming and the solution is beyond the scope of this document.
+
+If you do not have any server on your subnet supplying netbios name resolution,
+hardcoded mappings are your only option. If you DO have a netbios name server
+running (such as the Samba suite's nmbd program), the problem probably lies in
+the way it is set up. Refer to Section Two of this FAQ for more ideas.
+
+By the way, remember to REMOVE the hardcoded mapping before further tests :-)
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* 5: My client reports "cannot locate specified share name" or similar.
+
+This message indicates that your client CAN locate the specified server, which
+is a good start, but that it cannot find a service of the name you gave.
+
+The first step is to check the exact name of the service you are trying to
+connect to (consult your system administrator). Assuming it exists and you
+specified it correctly (read your client's doco on how to specify a service
+name correctly), read on:
+
+ * Many clients cannot accept or use service names longer than eight
+ characters.
+ * Many clients cannot accept or use service names containing spaces.
+ * Some servers (not Samba though) are case sensitive with service names.
+ * Some clients force service names into upper case.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* 6: My client reports "cannot find domain controller", "cannot log on to the
+network" or similar.
+
+Nothing is wrong - Samba does not implement the primary domain name controller
+stuff for several reasons, including the fact that the whole concept of a
+primary domain controller and "logging in to a network" doesn't fit well with
+clients possibly running on multiuser machines (such as users of smbclient
+under Unix). Having said that, several developers are working hard on
+building it in to the next major version of Samba. If you can contribute,
+send a message to samba-bugs!
+
+Seeing this message should not affect your ability to mount redirected disks
+and printers, which is really what all this is about.
+
+For many clients (including Windows for Workgroups and Lan Manager), setting
+the domain to STANDALONE at least gets rid of the message.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* 7: Printing doesn't work :-(
+
+Make sure that the specified print command for the service you are connecting
+to is correct and that it has a fully-qualified path (eg., use "/usr/bin/lpr"
+rather than just "lpr").
+
+Make sure that the spool directory specified for the service is writable by the
+user connected to the service. In particular the user "nobody" often has
+problems with printing, even if it worked with an earlier version of Samba. Try
+creating another guest user other than "nobody".
+
+Make sure that the user specified in the service is permitted to use the
+printer.
+
+Check the debug log produced by smbd. Search for the printer name and see if
+the log turns up any clues. Note that error messages to do with a service ipc$
+are meaningless - they relate to the way the client attempts to retrieve status
+information when using the LANMAN1 protocol.
+
+If using WfWg then you need to set the default protocol to TCP/IP, not Netbeui.
+This is a WfWg bug.
+
+If using the Lanman1 protocol (the default) then try switching to coreplus.
+Also not that print status error messages don't mean printing won't work. The
+print status is received by a different mechanism.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* 8: My programs install on the server OK, but refuse to work properly.
+
+There are numerous possible reasons for this, but one MAJOR possibility is that
+your software uses locking. Make sure you are using Samba 1.6.11 or later. It
+may also be possible to work around the problem by setting "locking=no" in the
+Samba configuration file for the service the software is installed on. This
+should be regarded as a strictly temporary solution.
+
+In earlier Samba versions there were some difficulties with the very latest
+Microsoft products, particularly Excel 5 and Word for Windows 6. These should
+have all been solved. If not then please let Andrew Tridgell know.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* 9: My "server string" doesn't seem to be recognized, my client reports the
+ default setting, eg. "Samba 1.9.15p4", instead of what I have changed it
+ to in the smb.conf file.
+
+You need to use the -C option in nmbd. The "server string" affects
+what smbd puts out and -C affects what nmbd puts out. In a future
+version these will probably be combined and -C will be removed, but
+for now use -C
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* 10: When I attempt to get a listing of available resources from the Samba
+ server, my client reports
+ "This server is not configured to list shared resources".
+
+Your guest account is probably invalid for some reason. Samba uses
+the guest account for browsing in smbd. Check that your guest account is
+valid.
+
+See also 'guest account' in smb.conf man page.
+
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* 11: You get the message "you appear to have a trapdoor uid system"
+ in your logs
+
+This can have several causes. It might be because you are using a uid
+or gid of 65535 or -1. This is a VERY bad idea, and is a big security
+hole. Check carefully in your /etc/passwd file and make sure that no
+user has uid 65535 or -1. Especially check the "nobody" user, as many
+broken systems are shipped with nobody setup with a uid of 65535.
+
+It might also mean that your OS has a trapdoor uid/gid system :-)
+
+This means that once a process changes effective uid from root to
+another user it can't go back to root. Unfortunately Samba relies on
+being able to change effective uid from root to non-root and back
+again to implement its security policy. If your OS has a trapdoor uid
+system this won't work, and several things in Samba may break. Less
+things will break if you use user or server level security instead of
+the default share level security, but you may still strike
+problems.
+
+The problems don't give rise to any security holes, so don't panic,
+but it does mean some of Samba's capabilities will be unavailable.
+In particular you will not be able to connect to the Samba server as
+two different uids at once. This may happen if you try to print as a
+"guest" while accessing a share as a normal user. It may also affect
+your ability to list the available shares as this is normally done as
+the guest user.
+
+Complain to your OS vendor and ask them to fix their system.
+
+===============================================================================
+SECTION FOUR: Specific client problems
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* 1: Are any MacIntosh clients for Samba.
+
+In Rob Newberry's words (rob@eats.com, Sun, 4 Dec 1994):
+
+The answer is "No." Samba speaks SMB, the protocol used for Microsoft networks.
+The Macintosh has ALWAYS spoken Appletalk. Even with Microsoft "services for
+Macintosh", it has been a matter of making the server speak Appletalk. It is
+the same for Novell Netware and the Macintosh, although I believe Novell has
+(VERY LATE) released an extension for the Mac to let it speak IPX.
+
+In future Apple System Software, you may see support for other protocols, such
+as SMB -- Applet is working on a new networking architecture that will make it
+easier to support additional protocols. But it's not here yet.
+
+Now, the nice part is that if you want your Unix machine to speak Appletalk,
+there are several options. "Netatalk" and "CAP" are free, and available on the
+net. There are also several commercial options, such as "PacerShare" and
+"Helios" (I think). In any case, you'll have to look around for a server, not
+anything for the Mac.
+
+Depending on you OS, some of these may not help you. I am currently
+coordinating the effort to get CAP working with Native Ethertalk under Linux,
+but we're not done yet.
+
+Rob
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* 2: I am getting a "Session request failed (131,130)" error when I try to
+ connect to my Win95 PC with smbclient. I am able to connect from the PC
+ to the Samba server without problems. What gives?
+
+The following answer is provided by John E. Miller:
+
+I'll assume that you're able to ping back and forth between the machines by
+IP address and name, and that you're using some security model where you're
+confident that you've got user IDs and passwords right. The logging options
+(-d3 or greater) can help a lot with that. DNS and WINS configuration can
+also impact connectivity as well.
+
+Now, on to 'scope id's. Somewhere in your Win95 TCP/IP network configuration
+(I'm too much of an NT bigot to know where it's located in the Win95 setup,
+but I'll have to learn someday since I teach for a Microsoft Solution Provider
+Authorized Tech Education Center - what an acronym...) [Note: It's under
+Control Panel | Network | TCP/IP | WINS Configuration] there's a little text
+entry field called something like 'Scope ID'.
+
+This field essentially creates 'invisible' sub-workgroups on the same wire.
+Boxes can only see other boxes whose Scope IDs are set to the exact same
+value - it's sometimes used by OEMs to configure their boxes to browse only
+other boxes from the same vendor and, in most environments, this field should
+be left blank. If you, in fact, have something in this box that EXACT value
+(case-sensitive!) needs to be provided to smbclient and nmbd as the -i
+(lowercase) parameter. So, if your Scope ID is configured as the string
+'SomeStr' in Win95 then you'd have to use smbclient -iSomeStr <otherparms>
+in connecting to it.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* 3: How do I synchronize my PC's clock with my Samba server?
+
+To syncronize your PC's clock with your Samba server:
+
+* Copy timesync.pif to your windows directory
+ * timesync.pif can be found at:
+ http://samba.canberra.edu.au/pub/samba/binaries/miscellaneous/timesync.pif
+* Add timesync.pif to your 'Start Up' group/folder
+* Open the properties dialog box for the program/icon
+ * Make sure the 'Run Minimized' option is set in program 'Properties'
+ * Change the command line section that reads \\sambahost to reflect the name
+ of your server.
+* Close the properties dialog box by choosing 'OK'
+
+Each time you start your computer (or login for Win95) your PC will
+synchronize it's clock with your Samba server.
+
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* 4: Problems with WinDD, NTrigue, WinCenterPro etc
+
+All of the above programs are applications that sit on an NT box and
+allow multiple users to access the NT GUI applications from remote
+workstations (often over X).
+
+What has this got to do with Samba? The problem comes when these users
+use filemanager to mount shares from a Samba server. The most common
+symptom is that the first user to connect get correct file permissions
+and has a nice day, but subsequent connections get logged in as the
+same user as the first person to login. They find that they cannot
+access files in their own home directory, but that they can access
+files in the first users home directory (maybe not such a nice day
+after all?)
+
+Why does this happen? The above products all share a common heritage
+(and code base I believe). They all open just a single TCP based SMB
+connection to the Samba server, and requests from all users are piped
+over this connection. This is unfortunate, but not fatal.
+
+It means that if you run your Samba server in share level security
+(the default) then things will definately break as described above. The
+share level SMB security model has no provision for multiple user IDs
+on the one SMB connection. See security_level.txt in the docs for more
+info on share/user/server level security.
+
+If you run in user or server level security then you have a chance,
+but only if you have a recent version of Samba (at least 1.9.15p6). In
+older versions bugs in Samba meant you still would have had problems.
+
+If you have a trapdoor uid system in your OS then it will never work
+properly. Samba needs to be able to switch uids on the connection and
+it can't if your OS has a trapdoor uid system. You'll know this
+because Samba will note it in your logs.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* 5: Problem with printers under NT
+
+This info from Stefan Hergeth may be useful:
+
+ A network-printer (with ethernetcard) is connected to the NT-Clients via
+ our UNIX-Fileserver (SAMBA-Server), like the configuration told by
+ Matthew Harrell <harrell@leech.nrl.navy.mil> (see WinNT.txt)
+
+ 1.) If a user has choosen this printer as the default printer in his
+ NT-Session and this printer is not connected to the network
+ (e.g. switched off) than this user has a problem with the SAMBA-
+ connection of his filesystems. It's very slow.
+
+ 2.) If the printer is connected to the network everything works fine.
+
+ 3.) When the smbd ist started with debug level 3, you can see that the
+ NT spooling system try to connect to the printer many times. If the
+ printer ist not connected to the network this request fails and the
+ NT spooler is wasting a lot of time to connect to the printer service.
+ This seems to be the reason for the slow network connection.
+
+ 4.) Maybe it's possible to change this behaviour by setting different printer
+ properties in the Print-Manager-Menu of NT, but i didn't try it
+ yet.
+
+ I hope this information will help in some way.
+
+ Stefan Hergeth <hergeth@f7axp1.informatik.fh-muenchen.de>
+
+
+===============================================================================
+SECTION FIVE: Specific client application problems
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* 1: MS Office Setup reports "Cannot change properties of the file named:
+ X:\MSOFFICE\SETUP.INI"
+
+When installing MS Office on a Samba drive for which you have admin user
+permissions, ie. admin users = <username>, you will find the setup program
+unable to complete the installation.
+
+To get around this problem, do the installation without admin user permissions
+The problem is that MS Office Setup checks that a file is rdonly by trying to
+open it for writing.
+
+Admin users can always open a file for writing, as they run as root.
+You just have to install as a non-admin user and then use "chown -R" to fix
+the owner.
+
+===============================================================================
+SECTION SIX: Miscellaneous
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Maintained By Paul Blackman, Email:ictinus@lake.canberra.edu.au
diff --git a/docs/samba.lsm b/docs/samba.lsm
index 503ba1ec94b..eacfda5ba0a 100644
--- a/docs/samba.lsm
+++ b/docs/samba.lsm
@@ -10,8 +10,8 @@ Author = Andrew Tridgell
AuthorEmail = samba-bugs@anu.edu.au
Maintainer = Andrew Tridgell
MaintEmail = samba-bugs@anu.edu.au
-Site1 = nimbus.anu.edu.au
-Path1 = pub/tridge/samba/
+Site1 = samba.anu.edu.au
+Path1 = pub/samba/
File1 = samba-latest.tar.gz
FileSize1 = 200K
Required1 = Ansi-C compiler and a TCP/IP network.
diff --git a/docs/textdocs/BROWSING.txt b/docs/textdocs/BROWSING.txt
index 8a09d2274fb..05d2f96544a 100644
--- a/docs/textdocs/BROWSING.txt
+++ b/docs/textdocs/BROWSING.txt
@@ -5,9 +5,9 @@ Samba now fully supports browsing. The browsing is supported by nmbd
and is also controlled by options in the smb.conf file (see
smb.conf(5)).
-Samba can act as a browse master for a workgroup, but currently cannot
-act as a domain controller. The ability to be a domain controller will
-be added in a later version.
+Samba can act as a browse master for a workgroup and the ability for
+samba to support domain logons and scripts is now available with features
+still being added. See DOMAIN.txt for more information .
To get browsing to work you need to run nmbd as usual, but will need
to use the "workgroup" option in smb.conf to control what workgroup
@@ -30,7 +30,7 @@ A simple lmhosts file might be:
#
# first put ourselves in workgroup MYGROUP using
# our own net address
-0.0.0.0 MYGROUP G
+0.0.0.0 MYGROUP 255.255.255.0 G
Note in the above that I overrode what workgroup Samba is in using the
G flag. Also note that the 0.0.0.0 address is used, which will be
@@ -48,7 +48,7 @@ the network which has a broadcast of 192.0.3.255 then this entry would
do the trick:
# put ourselves in the STAFF workgroup on the other subnet
-192.0.3.255 STAFF G
+192.0.3.255 STAFF 255.255.255.0 G
Notice the G at the end! It is very important you include this as this
entry without the G could cause a broadcast storm!
@@ -69,7 +69,7 @@ have a valid guest account.
Also, a lot of people are getting bitten by the problem of too many
parameters on the command line of nmbd in inetd.conf. This trick is to
not use spaces between the option and the parameter (eg: -d2 instead
-of -d 2), and to not use the -B and -N options. New versions of nmbd
+Of -d 2), and to not use the -B and -N options. New versions of nmbd
are now far more likely to correctly find your broadcast and network
addess, so in most cases these aren't needed.
@@ -142,4 +142,12 @@ the -B option. This only works if your network setup listens on both
0s and 1s based broadcasts. The -B option can only control what
address it sends to, not what it listens on.
+MULTIPLE INTERFACES
+===================
+
+Samba now supports machines with multiple network interfaces. If you
+have multiple interfaces then you will need to use the "interfaces"
+option in smb.conf to configure them. See smb.conf(5) for details.
+
+
diff --git a/docs/textdocs/BUGS.txt b/docs/textdocs/BUGS.txt
index e0fd6951477..8cccfcf449e 100644
--- a/docs/textdocs/BUGS.txt
+++ b/docs/textdocs/BUGS.txt
@@ -2,10 +2,6 @@ This file describes how to report Samba bugs.
>> The email address for bug reports is samba-bugs@anu.edu.au <<
-(NOTE: This mail may not be in place yet. If you have troubles with it
-then use samba-bugs@arvidsjaur.anu.edu.au)
-
-
Please take the time to read this file before you submit a bug
report. Also, please see if it has changed between releases, as I
may be changing the bug reporting mechanism sometime soon.
@@ -17,15 +13,14 @@ of an answer and a fix if you send me a "developer friendly" bug
report that lets me fix it fast.
Do not assume that if you post the bug to the comp.protocols.smb
-newsgroup that I will read it. I do read all postings to the samba
-mailing list (see the README). If you suspect that your problem is not
-a bug but a configuration problem then it is better to send it to the
-Samba mailing list, as there are (at last count) 1900 other users on
+newsgroup or the mailing list that I will read it. If you suspect that your
+problem is not a bug but a configuration problem then it is better to send
+it to the Samba mailing list, as there are (at last count) 1900 other users on
that list that may be able to help you.
You may also like to look though the recent mailing list archives,
which are conveniently accessible on the Samba web pages
-at http://lake.canberra.edu.au/pub/samba/
+at http://samba.canberra.edu.au/pub/samba/
GENERAL INFO
@@ -36,6 +31,8 @@ errors. Look in your log files for obvious messages that tell you that
you've misconfigured something and run testparm to test your config
file for correct syntax.
+Have you run through DIAGNOSIS.txt? This is very important.
+
If you include part of a log file with your bug report then be sure to
annotate it with exactly what you were doing on the client at the
time, and exactly what the results were.
diff --git a/docs/textdocs/DIAGNOSIS.txt b/docs/textdocs/DIAGNOSIS.txt
index 6681bdc4bcb..ad3eb449314 100644
--- a/docs/textdocs/DIAGNOSIS.txt
+++ b/docs/textdocs/DIAGNOSIS.txt
@@ -86,7 +86,13 @@ If you get a "session request failed" then the server refused the
connection. If it says "your server software is being unfriendly" then
its probably because you have invalid command line parameters to smbd,
or a similar fatal problem with the initial startup of smbd. Also
-check your config file for syntax errors with "testparm".
+check your config file for syntax errors with "testparm".
+
+Another common cause of these two errors is having something already running
+on port 139, such as Samba (ie smbd is running from inetd already) or something
+like Digital's Pathworks. Check your inetd.conf file before trying to start
+smbd as a daemon, it can avoid a lot of frustration!
+
TEST 4:
-------
diff --git a/docs/textdocs/HINTS.txt b/docs/textdocs/HINTS.txt
index 953650bdd3e..eedd0bf36e1 100644
--- a/docs/textdocs/HINTS.txt
+++ b/docs/textdocs/HINTS.txt
@@ -40,7 +40,7 @@ Jim barry has written an excellent drag-and-drop cr/lf converter for
windows. Just drag your file onto the icon and it converts the file.
Get it from
-ftp://nimbus.anu.edu.au/pub/tridge/samba/contributed/fixcrlf.zip
+ftp://samba.anu.edu.au/pub/samba/contributed/fixcrlf.zip
----------------------
HINT: Use the "username map" option
diff --git a/docs/textdocs/README.jis b/docs/textdocs/README.jis
index 2ac6716a6f6..50ff0cced74 100644
--- a/docs/textdocs/README.jis
+++ b/docs/textdocs/README.jis
@@ -14,6 +14,10 @@
$B$rL\E*$H$7$F$$$^$9!#$=$N$?$a!"F|K\8lBP1~$O!"I,MW:G>.8B$7$+9T$J$C$F$*$j$^$;$s!#(B
+ $BF|K\8lBP1~$7$?(B samba $B$rMxMQ$9$k$?$a$K$O!"%3%s%Q%$%k$9$k;~$K!"I,$:!"(BKANJI $B$NDj5A$rDI(B
+ $B2C$7$F$/$@$5$$!#$3$N%*%W%7%g%s$r;XDj$7$F$$$J$$>l9g$O!"F|K\8l$N%U%!%$%kL>$r@5$7$/07(B
+ $B$&$3$H$O$G$-$^$;$s!#!J%3%s%Q%$%k$K$D$$$F$O!"2<5-(B 3. $B$r;2>H$7$F2<$5$$!K(B
+
2. $BMxMQJ}K!(B
(1) $BDI2C$7$?%Q%i%a!<%?(B
@@ -34,6 +38,12 @@
$B$N(B16$B?J?t$rB3$1$k7A<0$K$J$j$^$9!#(B
$B$3$3$G!"(B':' $B$rB>$NJ8;z$KJQ99$7$?$$>l9g$O!"(Bhex $B$N8e$m$K$=$NJ8;z$r;XDj$7$^$9!#(B
$BNc$($P!"(B@$B$rJQ$o$j$K;H$$$?$$>l9g$O!"(B'hex@'$B$N$h$&$K;XDj$7$^$9!#(B
+ cap: 7 bits $B$N(B ASCII $B%3!<%I0J30$N%3!<%I$r0J2<$N7A<0$GI=$9J}<0$H$$$&E@$G$O(B
+ hex$B$HF1MM$G$9$,!"(BCAP (The Columbia AppleTalk Package)$B$H8_49@-$r;}$DJQ49(B
+ $BJ}<0$H$J$C$F$$$^$9!#(Bhex$B$H$N0c$$$O(B0x80$B0J>e$N%3!<%I$N$_(B':80'$B$N$h$&$KJQ49(B
+ $B$5$l!"$=$NB>$O(BASCII$B%3!<%I$G8=$5$l$^$9!#(B
+ $BNc$($P!"(B'$B%*%U%#%9(B'$B$H$$$&L>A0$O!"(B':83I:83t:83B:83X'$B$H$J$j$^$9!#(B
+
JIS $B%3!<%I$K$D$$$F$O!"0J2<$NI=$r;2>H$7$F2<$5$$!#(B
$B(#(!(!(!(((!(!(!(!(((!(!(!(!(((!(!(!(!(((!(!(!(!(((!(!(!(!(((!(!(!(!(!(!(!(!(!($(B
$B(";XDj(B $B("4A;z3+;O("4A;z=*N;("%+%J3+;O("%+%J=*N;("1Q?t3+;O("Hw9M(B $B("(B
@@ -90,6 +100,8 @@
$B%$%kL>$O!"(BEUC $B%3!<%I$K$J$j$^$9!#$3$3$G;XDj$7$?%3!<%I7O$O!"%5!<%P5Z$S%/%i%$%"%s%H(B
$B%W%m%0%i%`$N%G%U%)%k%H$KCM$J$j$^$9!#(B
+ $B>0!"%*%W%7%g%sCf$N(B \ $B$d(B " $B$bK:$l$:$K;XDj$7$F2<$5$$!#(B
+
3. $B@)8B;v9`(B
(1) $B4A;z%3!<%I(B
@@ -104,21 +116,34 @@
$B$A$c$s$H$7$?%9%Z%C%/$,$h$/$o$+$i$J$+$C$?$N$G$9$,!"0l1~!"(BDOS/V $B$NF0:n$HF1$8F0:n$r9T$J(B
$B$&$h$&$K$J$C$F$$$^$9!#(B
+(4) $B%m%s%0%U%!%$%kL>$K$D$$$F(B
+ Windows NT/95 $B$G$O!"%m%s%0%U%!%$%kL>$,07$($^$9!#%m%s%0%U%!%$%kL>$r(B 8.3 $B%U%)!<%^%C%H(B
+ $B$G07$&$?$a$K!"(Bmangling $B$7$F$$$^$9$,!"$3$NJ}K!$O!"(BNT $B$d(B 95 $B$,9T$J$C$F$$$k(B mangling $B$H(B
+ $B$O0[$J$j$^$9$N$GCm0U$7$F2<$5$$!#(B
+
4. $B>c32Ey$N%l%]!<%H$K$D$$$F(B
$BF|K\8l$N%U%!%$%kL>$K4X$7$F!"J8;z2=$1Ey$N>c32$,$"$l$P!";d$K%l%]!<%H$7$FD:$1$l$P9,$$$G(B
$B$9!#$?$@$7!"%*%j%8%J%k$+$i$NLdBjE@$d<ALd$K$D$$$F$O!"%*%j%8%J%k$N:n<T$XD>@\Ld$$9g$o$;$k(B
$B$+!"$b$7$/$O%a!<%j%s%0%j%9%H$J$I$X%l%]!<%H$9$k$h$&$K$7$F2<$5$$!#(B
+$B%l%]!<%H$5$l$k>l9g!"MxMQ$5$l$F$$$k4D6-(B(UNIX $B5Z$S(B PC $BB&$N(BOS$B$J$I(B)$B$H$G$-$^$7$?$i@_Dj%U%!(B
+$B%$%k$d%m%0$J$I$rE:IU$7$FD:$1$k$H9,$$$G$9!#(B
+
5. $B$=$NB>(B
- hex $B7A<0$NJQ49J}K!$O!"(B
+ $B%3!<%IJQ49$O0J2<$NJ}!9$,:n$i$l$?%W%m%0%i%`$rMxMQ$7$F$$$^$9!#(B
- $BBgLZ!wBgDM!&C^GH(B <ohki@gssm.otsuka.tsukuba.ac.jp>$B;a(B
+ hex $B7A<0(B $BBgLZ!wBgDM!&C^GH(B <ohki@gssm.otsuka.tsukuba.ac.jp>$B;a(B
+ cap $B7A<0(B $BI%ED(B $BF;O:(B (michiro@po.iijnet.or.jp)(michiro@dms.toppan.co.jp)$B;a(B
- $B$,:n$i$l$?%3!<%I$rMxMQ$7$F$$$^$9!#(B
+ $B$=$NB>!"$?$/$5$s$NJ}!9$+$i$$$m$$$m$H8f65<($$$?$@$-$"$j$,$H$&$4$6$$$^$7$?!#:#8e$H$b$h(B
+$B$m$7$/$*4j$$CW$7$^$9!#(B
1994$BG/(B10$B7n(B28$BF|(B $BBh#1HG(B
1995$BG/(B 8$B7n(B16$BF|(B $BBh#2HG(B
+1995$BG/(B11$B7n(B24$BF|(B $BBh#3HG(B
+1996$BG/(B 5$B7n(B13$BF|(B $BBh#4HG(B
+
$BF#ED(B $B?r(B fujita@ainix.isac.co.jp
diff --git a/docs/textdocs/Support.txt b/docs/textdocs/Support.txt
index d71bdaf7b3e..1c951be0eee 100644
--- a/docs/textdocs/Support.txt
+++ b/docs/textdocs/Support.txt
@@ -41,11 +41,13 @@ of the SAMBA Web Pages.
------------------------------------------------------------------------------
READING - ENGLAND
-Philip Hands | E-Mail: info@hands.com
-Philip Hands Computing Ltd. | Tel: +44 1734 476287 Fax: 1734 474655
-Unit 1, Cherry Close, Caversham, Reading RG4 8UP UK
+Philip Hands | E-Mail: info@hands.com Tel:+44 118 9545656
+Philip Hands Computing Ltd. | Mobile: +44 802 242989 Fax:+44 118 9474655
+Unit 1, Cherry Close, Caversham, Reading RG4 8UP ENGLAND
-Samba experience: SVR4,SVR3.2 & Linux <--> WfWg, W3.1, OS2 and MS-LanMan
+Samba experience:
+ Server platforms: Linux,SVR4,SVR3.2 & Sequent ptx
+ Clients: WfWg, W3.1, OS2 and MS-LanMan
------------------------------------------------------------------------------
------------------------------------------------------------------------------
@@ -243,15 +245,15 @@ LE12 8DX
TELEPHONE 01509-620922
FAX 01509-620933
-CONTACT DAVID ROBINSON
+Contact David Robinson
-WE ARE UNIX ORIENTATED BUT ALSO SPECIALISE IN PC TO UNIX COMMUNICATIONS, WE
-KNOW AND UNDERSTAND PC-NFS, (HENCE OUR INTEREST IN SAMBA).
-WE SUPPORT SUNOS, SOLARIS 1.X AND 2.X, HP-UX 9.0 AND 10.0, OSF (or DEC UNIX,
-whichever you prefer), WinNT, WfWG and Win95.
+We are unix orientated but also specialise in pc to unix communications, we
+know and understand pc-nfs, (hence our interest in samba).
+we support sunos, solaris 1.x and 2.x, hp-ux 9.0 and 10.0, osf (or dec unix,
+whichever you prefer), winnt, wfwg and win95.
-WE ARE ALREADY TALKING TO A COUPLE OF VERY LARGE SAMBA USERS HERE IN THE UK.
-WE WOULD LIKE TO SUPPORT THEM (AND MANY MORE), WOULD YOU PLEASE CONTACT ME ON:
+We are already talking to a couple of very large samba users here in the uk.
+we would like to support them (and many more), would you please contact me on:
david@tectonic.demon.co.uk
----------------------------------------------------------
@@ -357,6 +359,8 @@ rowl@earthlink.net
Michael St. Laurent
Hartwell Corporation
------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
WASHINGTON DC METRO - USA
Asset Software, Inc. has been running Samba since the 1.6 release on various
@@ -374,3 +378,36 @@ David J. Fenwick Asset Software, Inc.
President djf@assetsw.com
------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+WELLINGTON - NEW ZEALAND
+
+David Gempton
+Computer Consultant
+UNIX & PC Networking specialist
+TTC Technology Training Consulting
+PO Box 5444
+Lambton Quay Wellington
+New Zealand
+Phone (025) 518-574
+Email: ttcdg@cyberspace.co.nz
+------------------------------------------------------------------------------
+
+
+
+------------------------------------------------------------------------------
+PRAHA (PRAGUE) - CZECH
+
+AGC Praha,
+David Doubrava
+Sokolovska 141
+PRAHA 8
+180 00
+
+Tel: +42 (2) 6600 2202 Fax: +42 (2) 683 02 55
+Email: ddoubrava@agc.cz WWW: http://corwin.agc.cz/
+
+I have Samba experience with Windows NT,
+Windows 95, and Windows for Workgroups clients with Linux and HP-UX
+servers.
+------------------------------------------------------------------------------
diff --git a/docs/textdocs/UNIX-SMB.txt b/docs/textdocs/UNIX-SMB.txt
index b2c064215cf..92167a9e843 100644
--- a/docs/textdocs/UNIX-SMB.txt
+++ b/docs/textdocs/UNIX-SMB.txt
@@ -155,6 +155,9 @@ within the one process. On some unixes (such as SCO) this is not
possible. This means that on those unixes the client is restricted to
a single uid.
+Note that you can also get the "trapdoor uid" message for other
+reasons. Please see the FAQ for details.
+
Port numbers
============
diff --git a/docs/textdocs/security_level.txt b/docs/textdocs/security_level.txt
new file mode 100644
index 00000000000..34d7ce70932
--- /dev/null
+++ b/docs/textdocs/security_level.txt
@@ -0,0 +1,79 @@
+Description of SMB security levels.
+----------------------------------
+
+
+A SMB server tells the client at startup what "security level" it is
+running. There are two options "share level" and "user level". Which
+of these two the client receives affects the way the client then tries
+to authenticate itself. It does not directly affect (to any great
+extent) the way the Samba server does security. I know this is
+strange, but it fits in with the client/server approach of SMB. In SMB
+everything is initiated and controlled by the client, and the server
+can only tell the client what is available and whether an action is
+allowed.
+
+I'll describe user level security first, as its simpler. In user level
+security the client will send a "session setup" command directly after
+the protocol negotiation. This contains a username and password. The
+server can either accept or reject that username/password
+combination. Note that at this stage the server has no idea what
+share the client will eventually try to connect to, so it can't base
+the "accept/reject" on anything other than:
+
+- the username/password
+- the machine that the client is coming from
+
+If the server accepts the username/password then the client expects to
+be able to mount any share (using a "tree connection") without
+specifying a password. It expects that all access rights will be as
+the username/password specified in the "session setup".
+
+It is also possible for a client to send multiple "session setup"
+requests. When the server responds it gives the client a "uid" to use
+as an authentication tag for that username/password. The client can
+maintain multiple authentication contexts in this way (WinDD is an
+example of an application that does this)
+
+
+Ok, now for share level security. In share level security (the default
+with samba) the client authenticates itself separately for each
+share. It will send a password along with each "tree connection"
+(share mount). It does not explicitly send a username with this
+operation. The client is expecting a password to be associated with
+each share, independent of the user. This means that samba has to work
+out what username the client probably wants to use. It is never
+explicitly sent the username. Some commercial SMB servers such as NT actually
+associate passwords directly with shares in share level security, but
+samba always uses the unix authentication scheme where it is a
+username/password that is authenticated, not a "share/password".
+
+Many clients send a "session setup" even if the server is in share
+level security. They normally send a valid username but no
+password. Samba records this username in a list of "possible
+usernames". When the client then does a "tree connection" it also adds
+to this list the name of the share they try to connect to (useful for
+home directories) and any users listed in the "user =" smb.conf
+line. The password is then checked in turn against these "possible
+usernames". If a match is found then the client is authenticated as
+that user.
+
+Finally "server level" security. In server level security the samba
+server reports to the client that it is in user level security. The
+client then does a "session setup" as described earlier. The samba
+server takes the username/password that the client sends and attempts
+to login to the "password server" by sending exactly the same
+username/password that it got from the client. If that server is in
+user level security and accepts the password then samba accepts the
+clients connection. This allows the samba server to use another SMB
+server as the "password server".
+
+You should also note that at the very start of all this, where the
+server tells the client what security level it is in, it also tells
+the client if it supports encryption. If it does then it supplies the
+client with a random "cryptkey". The client will then send all
+passwords in encrypted form. You have to compile samba with encryption
+enabled to support this feature, and you have to maintain a separate
+smbpasswd file with SMB style encrypted passwords. It is
+cryptographically impossible to translate from unix style encryption
+to SMB style encryption, although there are some fairly simple management
+schemes by which the two could be kept in sync.
diff --git a/examples/misc/extra_smbstatus b/examples/misc/extra_smbstatus
index b018f3dcce9..363e7f67af5 100644
--- a/examples/misc/extra_smbstatus
+++ b/examples/misc/extra_smbstatus
@@ -10,28 +10,31 @@ added things at source level, script was quick&easy.
if ($1 == "-p") then
smbstatus -p |sort -u
else if ($1 == "-c") then
- echo There are `smbstatus -p |sort -u |grep -n -v z |grep -c :` unique
-smbd processes running.
+ echo There are `smbstatus -p |sort -u |grep -n -v z |grep -c :` unique smbd processes running.
else if ($1 == "-l") then
- echo `date '+ %d/%m/%y %H:%M:%S'` `smbstatus -p |sort -u |grep -n -v z
-|grep -c :` >>$2
+ echo `date '+ %d/%m/%y %H:%M:%S'` `smbstatus -p |sort -u |grep -n -v z |grep -c :` >>$2
+else if ($1 == "-cs") then
+ echo There are `smbstatus |awk '$1==share {n++;} END {print n}' share=$2` concurrent connections to share: $2
+else if ($1 == "-csl") then
+ echo `date '+ %d/%m/%y %H:%M:%S'` `smbstatus |awk '$1==share {n++;} END {print n}' share=$2` >>$3
else
- smbstatus |sort +3 -4 -u
+ echo "'smbstat -c' ==> Count unique smbd processes."
+ echo "'smbstat -p' ==> List unique smbd processes."
+ echo "'smbstat -l logfile' ==> Append a log entry for the number of"
+ echo " concurrent and unique processes to logfile."
+ echo "'smbstat -cs sharename'"
+ echo " ==> Count processes connected to sharename (assumed unique)"
+ echo "'smbstat -csl sharename logfile'"
+ echo " ==> Append a log entry for the number of concurrent"
+ echo " processes connected to sharename (assumed unique)"
endif
******
-The '-p' option was just to show unique PIDs.
+Run this script from cron eg.
-The more important ones are the '-c' and '-l' options '-c' just counts
-the number of unique smbd's, While '-l' logs this count with date and
-time to a log file specified on the command line. I'm using '-l' at
-the moment with cron to give me an idea of usage/max connections etc.
-I was also thinking of doing a log for individual/specified services.
+0,5,10,15,20,25,30,35,40,50,55 * * * * /usr/local/samba/bin/smbstat -l /usr/local/samba/var/smbdcount.log
-The default (last) option was to show unique PIDs with user names.
-Unfortunately this still lists all file locks etc. This would be
-better with a 'no locked files' option from smbstatus (or is there one
-that I didn't see)
+and you get a good idea of usage over time.
Cheers,
~^ MIME OK ^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~
diff --git a/examples/misc/wall.perl b/examples/misc/wall.perl
index fc3dc2e2c05..9303658ce14 100644
--- a/examples/misc/wall.perl
+++ b/examples/misc/wall.perl
@@ -6,40 +6,64 @@
#@(#) ...using "smbclient -M" message to winpopup service.
#@(#) Default usage is to message every connected PC.
#@(#) Alternate usage is to message every pc on the argument list.
-#@(#) Hacked up by Keith Farrar <farrar@parc.xerox.com>
+#@(#) Hacked up by Keith Farrar <farrar@parc.xerox.com>
#
+# Cleanup and corrections by
+# Michal Jaegermann <michal@ellpspace.math.ualberta.ca>
+# Message to send can be now also fed (quietly) from stdin; a pipe will do.
#=============================================================================
-$smbstatus = "/usr/local/bin/smbstatus";
-$smbclient = "/usr/local/bin/smbclient";
-print STDOUT "\nEnter message for Samba clients of this host\n";
-print STDOUT "(terminated with single '.' or end of file):\n";
+$smbstatus = "/usr/local/bin/smbstatus";
+$smbshout = "/usr/local/bin/smbclient -M";
-while ( <STDIN> ) {
- /^\.$/ && last;
- push(@message, $_);
+if (@ARGV) {
+ @clients = @ARGV;
+ undef @ARGV;
}
+else { # no clients specified explicitly
+ open(PCLIST, "$smbstatus |") || die "$smbstatus failed!.\n$!\n";
+ while(<PCLIST>) {
+ last if /^Locked files:/;
+ split(' ', $_, 6);
+ # do not accept this line if less then six fields
+ next unless $_[5];
+ # if you have A LOT of clients you may speed things up by
+ # checking pid - no need to look further if this pid was already
+ # seen; left as an exercise :-)
+ $client = $_[4];
+ next unless $client =~ /^\w+\./; # expect 'dot' in a client name
+ next if grep($_ eq $client, @clients); # we want this name once
+ push(@clients, $client);
+ }
+ close(PCLIST);
+}
+
+if (-t) {
+ print <<'EOT';
-if ( $ARGV[0] ne "" ) {
- $debug && print STDOUT "Was given args: \n\t @ARGV\n";
- foreach $client ( @ARGV ) {
- $pcclient{$client} = $client;
- }
-} else {
- open( PCLIST, "$smbstatus | /bin/awk '/^[a-z]/ {print $5}' | /bin/sort | /bin/uniq|");
- while ( <PCLIST> ) {
- /^[a-z]+[a-z0-9A-Z-_]+.+/ || next;
- ($share, $user, $group, $pid, $client, @junk) = split;
- $pcclient{$client} = $client;
- }
- close(PCLIST);
+Enter message for Samba clients of this host
+(terminated with single '.' or end of file):
+EOT
+
+ while (<>) {
+ last if /^\.$/;
+ push(@message, $_);
+ }
+}
+else { # keep quiet and read message from stdin
+ @message = <>;
}
-foreach $pc ( keys(%pcclient) ) {
- print STDOUT "Sending message ";
- $debug && print STDOUT " <@message> \n";
- print STDOUT "To <$pc>\n";
- open(SENDMSG,"|$smbclient -M $pc") || next;
+foreach(@clients) {
+## print "To $_:\n";
+ if (open(SENDMSG,"|$smbshout $_")) {
print SENDMSG @message;
close(SENDMSG);
+ }
+ else {
+ warn "Cannot notify $_ with $smbshout:\n$!\n";
+ }
}
+
+exit 0;
+
diff --git a/examples/printer-accounting/README b/examples/printer-accounting/README
new file mode 100644
index 00000000000..b7ab42acb96
--- /dev/null
+++ b/examples/printer-accounting/README
@@ -0,0 +1,63 @@
+These are just a few examples of what you can do for printer accounting;
+they are really just hacks to show a manager how may pages were being
+printed out on his new hp5n :)
+
+acct-all will run acct-sum and read the log files to generate some
+stats.
+
+Here is a sample output of the raw stats :
+
+1996-06-10.15:02:15 pkelly master.fcp.oypi.com 538 0
+1996-06-10.15:06:40 pkelly master.fcp.oypi.com 537 0
+1996-06-10.15:32:12 ted master.fcp.oypi.com 547 0
+1996-06-11.09:06:15 violet master.fcp.oypi.com 2667 0
+1996-06-11.09:48:02 violet master.fcp.oypi.com 66304 5
+1996-06-11.09:50:04 violet master.fcp.oypi.com 116975 9
+1996-06-11.09:57:20 violet master.fcp.oypi.com 3013 1
+1996-06-11.10:13:17 pkelly master.fcp.oypi.com 3407 1
+1996-06-11.12:37:06 craig master.fcp.oypi.com 13639 2
+1996-06-11.12:42:23 pkelly master.fcp.oypi.com 13639 2
+1996-06-11.12:45:11 marlene master.fcp.oypi.com 515 0
+1996-06-11.14:17:10 lucie master.fcp.oypi.com 1405 1
+1996-06-11.14:36:03 laura master.fcp.oypi.com 45486 5
+1996-06-11.15:08:21 violet master.fcp.oypi.com 1923 1
+1996-06-11.15:09:42 laura master.fcp.oypi.com 4821 1
+1996-06-11.15:12:28 laura master.fcp.oypi.com 46277 5
+1996-06-11.15:19:38 violet master.fcp.oypi.com 3503 1
+1996-06-11.15:21:49 lucie master.fcp.oypi.com 493 0
+1996-06-11.15:43:36 al master.fcp.oypi.com 3067 1
+
+And the output after the acct-sum is done on a full set of files
+in /var/log/lp/*
+
+master[1072] /var/log/lp$ /etc/conf/acct-all
+
+Sun Jul 21 23:03:16 EDT 1996
+
+Pages are approximate ...
+
+User Jobs Pages Size
+al 1 1 2 KB
+craig 1 2 13 KB
+jack 68 235 1995 KB
+laura 88 328 3050 KB
+lucie 221 379 3529 KB
+marlene 12 151 1539 KB
+melanie 83 365 3691 KB
+michelle 68 219 1987 KB
+mike 2 10 81 KB
+neil 111 225 2753 KB
+operator 44 137 1132 KB
+pkelly 368 984 11154 KB
+root 8 0 29 KB
+ted 158 257 2337 KB
+tony 244 368 2455 KB
+violet 419 1002 10072 KB
+
+
+Printer Jobs Pages
+hp2p 3 4
+hp5 915 2135
+lp 978 2524
+
+<pkelly@ets.net>
diff --git a/examples/printer-accounting/acct-all b/examples/printer-accounting/acct-all
new file mode 100644
index 00000000000..dc8f175b3cb
--- /dev/null
+++ b/examples/printer-accounting/acct-all
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+echo ""
+date
+echo ""
+echo "Pages are approximate ..."
+echo ""
+/etc/conf/acct-sum /var/log/lp/*
+echo ""
diff --git a/examples/printer-accounting/acct-sum b/examples/printer-accounting/acct-sum
new file mode 100644
index 00000000000..ffbfc8d8801
--- /dev/null
+++ b/examples/printer-accounting/acct-sum
@@ -0,0 +1,29 @@
+#!/usr/bin/perl
+
+while (<>) {
+ ($date, $user, $machine, $size, $pages) = split(' ');
+
+ $Printer{$ARGV}++;
+ $PrinterPages{$ARGV} += $pages;
+
+ $Jobs{$user}++;
+ $Size{$user}+= $size;
+ $Pages{$user}+= $pages;
+}
+
+printf "%-15s %5s %8s %8s\n", qw(User Jobs Pages Size);
+foreach $user (sort keys %Jobs) {
+ printf "%-15s %5d %8d %8d \KB\n",
+ $user, $Jobs{$user}, $Pages{$user}, $Size{$user}/1024;
+}
+
+
+print "\n\n";
+printf "%-15s %5s %8s %8s\n", qw(Printer Jobs Pages);
+foreach $prn (sort keys %Printer) {
+ ($name = $prn) =~ s=.*/==;
+ printf "%-15s %5d %8d\n",
+ $name, $Printer{$prn}, $PrinterPages{$prn};
+}
+
+
diff --git a/examples/printer-accounting/hp5-redir b/examples/printer-accounting/hp5-redir
new file mode 100644
index 00000000000..98c2b72edd2
--- /dev/null
+++ b/examples/printer-accounting/hp5-redir
@@ -0,0 +1,43 @@
+#!/usr/bin/perl
+#
+# $Source: /data/src/mirror/cvs/samba/examples/printer-accounting/hp5-redir,v $
+# $Id: hp5-redir,v 1.1 1996/07/23 03:30:56 samba-bugs Exp $
+#
+# 0 == stdin == docuement
+# 1 == stdout == printer
+# 2 == stderr == logging
+#
+# With redirection to another valid /etc/printcap entry
+#
+
+umask(002);
+
+# -w132 -l66 -i0 -n pkelly -h master.fcp.oypi.com /var/log/lp-acct
+require "getopts.pl";
+&Getopts("w:l:i:n:h:");
+
+chomp($date = `date '+%Y-%m-%d.%T'`);
+
+($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
+ $atime,$mtime,$ctime,$blksize,$blocks)
+ = stat(STDIN);
+
+# send to the real printer now.
+open(P, "|lpr -Pmgmt0") || die "Can't print to hp5-real ($!)\n";
+$cnt = 0;
+while (sysread(STDIN, $buf, 10240)) {
+ print P $buf;
+ # this is ugly, but it gives the approx in pages. We
+ # don't print graphics, so ... There must be a better way :)
+ $cnt += ($buf =~ /^L/g);
+}
+close(P);
+
+$acct = shift;
+if (open(ACCT, ">>$acct")) {
+ print ACCT "$date $opt_n $opt_h $size $cnt\n";
+ close(ACCT);
+} else {
+ warn "Err: Can't account for it ($!)\n";
+ warn "Log: $date $opt_n $opt_h $size $cnt\n";
+}
diff --git a/examples/printer-accounting/lp-acct b/examples/printer-accounting/lp-acct
new file mode 100644
index 00000000000..3fe45f877fd
--- /dev/null
+++ b/examples/printer-accounting/lp-acct
@@ -0,0 +1,38 @@
+#!/usr/bin/perl
+#
+# $Source: /data/src/mirror/cvs/samba/examples/printer-accounting/lp-acct,v $
+# $Id: lp-acct,v 1.1 1996/07/23 03:30:56 samba-bugs Exp $
+#
+# 0 == stdin == docuement
+# 1 == stdout == printer
+# 2 == stderr == logging
+#
+# Regular, with no redirection
+#
+
+umask(002);
+
+# -w132 -l66 -i0 -n pkelly -h master.fcp.oypi.com /var/log/lp-acct
+require "getopts.pl";
+&Getopts("w:l:i:n:h:");
+
+chomp($date = `date '+%Y-%m-%d.%T'`);
+
+($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
+ $atime,$mtime,$ctime,$blksize,$blocks)
+ = stat(STDIN);
+
+$cnt = 0;
+while (sysread(STDIN, $buf, 10240)) {
+ print $buf;
+ $cnt += ($buf =~ /^L/g);
+}
+
+$acct = shift;
+if (open(ACCT, ">>$acct")) {
+ print ACCT "$date $opt_n $opt_h $size $cnt\n";
+ close(ACCT);
+} else {
+ warn "Err: Can't account for it ($!)\n";
+ warn "Log: $date $opt_n $opt_h $size $cnt\n";
+}
diff --git a/examples/printer-accounting/printcap b/examples/printer-accounting/printcap
new file mode 100644
index 00000000000..976005a097c
--- /dev/null
+++ b/examples/printer-accounting/printcap
@@ -0,0 +1,22 @@
+# HP5N - Accounting entry
+#
+# This file calls the filter, hp5-redir to do the numbers and then
+# is redirected to the real entry, mgmt0, which is a remote HP5N
+# on the LAN with it's own IP number.
+#
+hp5:lp=/dev/lp1:\
+ :sd=/usr/spool/lpd/hp5-acct:\
+ :lf=/var/log/lp-err:\
+ :af=/var/log/lp/hp5:\
+ :if=/usr/local/bin/lp/hp5-redir:\
+ :sh:sf:\
+ :mx#0:
+
+# HP5N - Real printer location
+mgmt0:\
+ :rm=hp5.fcp.oypi.com:\
+ :rp=hp5.fcp.oypi.com:\
+ :sd=/usr/spool/lpd/mgmt0:\
+ :sh:sf:\
+ :mx#0:
+
diff --git a/examples/simple/smb.conf b/examples/simple/smb.conf
index cdf65b337f7..786bf49057c 100644
--- a/examples/simple/smb.conf
+++ b/examples/simple/smb.conf
@@ -80,11 +80,13 @@
writable = no
create mode = 0700
-; you might also want this one
+; you might also want this one, notice that it is read only so as not to give
+; people without an account write access.
+;
; [tmp]
; comment = Temporary file space
; path = /tmp
-; read only = no
+; read only = yes
; public = yes
;
diff --git a/examples/thoralf/smb.conf b/examples/thoralf/smb.conf
new file mode 100644
index 00000000000..f9f147474a8
--- /dev/null
+++ b/examples/thoralf/smb.conf
@@ -0,0 +1,152 @@
+; Configuration file for smbd (Samba 1.9.15p8)
+; created by Thoralf Freitag. Send comments to:
+; <Thoralf.Freitag@remserv.rz.fhtw-berlin.de> or
+; <Thoralf.Freitag@t-online.de>
+; last edit 24.04.1995 01:11
+;
+;
+
+[global]
+
+ protocol = NT1
+ ;long filenames for win95
+ mangle case = yes
+ ;lower and upper letters
+ mangled names = yes
+ default case = lower
+ case sensitive = no
+ preserve case = yes
+ short preserve case = yes
+
+ printing = bsd
+ printcap name = /etc/printcap
+ lpq cache time = 0
+ workgroup = WORKGROUP
+ admin users = su
+ ;su is allowed to do all !!!
+ guest account = ftp
+ ;guest is same as user ftp
+ default service = reference
+ ;is possibly helpful to browsing under win 95
+ os level = 2
+ log file = /var/adm/log.smb
+ max log size = 10
+ debug level = 1
+ share modes = yes
+ lock directory = /var/adm
+
+[JP_360_raw]
+ comment = Networkprinter queue for Olivetti JP 360 (untreated RAW format)
+ browseable = yes
+ available = yes
+ public = no
+ force user = root
+ writable = no
+ printable = yes
+ printer name = samba
+ ;samba is an alias name for an raw_printer in your /etc/printcap
+ path = /samba/tmp
+ create mode = 0700
+
+[JP_360_mono]
+ comment = Networkprinter queue for Olivetti JP 360 Mono (with apsfilter)
+ browseable = yes
+ available = yes
+ public = no
+ force user = root
+ writable = no
+ printable = yes
+ printer name = lp
+ ;lp means the standard printer in your /etc/printcap
+ path = /samba/tmp
+ create mode = 0700
+
+[JP_360_color]
+ comment = Networkprinter queue for Olivetti JP 360 Color (with apsfilter)
+ browseable = yes
+ available = yes
+ public = no
+ force user = root
+ writable = no
+ printable = yes
+ printer name = lp4
+ ;my printer need this to print with his color cartridge
+ ;--> the lpd is drive to the printer as an color printer
+ path = /samba/tmp
+ create mode = 0700
+
+[tmp]
+ comment = the garbage dump
+ browseable = yes
+ available = yes
+ public = yes
+ read only = no
+ printable = no
+ path = /samba/tmp
+ create mask = 0777
+
+[transfer]
+ comment = the market place
+ browseable = yes
+ available = yes
+ public = yes
+ read only = no
+ printable = no
+ path = /samba/transfer
+ create mask = 0777
+
+[homes]
+ comment = home directories
+ browseable = no
+ ;ONLY the home-dirs are visible, not the service itself
+ available = yes
+ guest ok = no
+ read only = no
+ printable = no
+ create mode = 0700
+
+[install]
+ comment = all of the many install files
+ browsable = yes
+ available = yes
+ public = no
+ username = @root, @users
+ writable = yes
+ read list = @users
+ printable = no
+ path = /samba/install
+ create mode = 0755
+
+[doc-help]
+ comment = documentations, helpfiles, FAQ's
+ browsable = yes
+ available = yes
+ public = no
+ username = @root, @users
+ writable = yes
+ read list = @users
+ printable = no
+ path = /samba/doc
+ create mode = 0755
+
+[cd_rom_2]
+ comment = the CD in the CD-ROM drive on PANDORA
+ browsable = yes
+ available = yes
+ public = yes
+ writable = no
+ printable = no
+ path = /cdrom
+
+[reference]
+ ;the default, if invalid accesses
+ comment = PANDORA: Samba LAN manager
+ browsable = yes
+ ;only as an hint
+ available = no
+ ;however no access possible
+ public = yes
+ writable = no
+ printable = no
+ path = /samba/tmp
+
diff --git a/examples/validchars/msdos70.out b/examples/validchars/msdos70.out
new file mode 100644
index 00000000000..a722b83604f
--- /dev/null
+++ b/examples/validchars/msdos70.out
@@ -0,0 +1,257 @@
+255: ok
+254: ok
+253: ok
+252: ok
+251: ok
+250: ok
+249: ok
+248: ok
+247: ok
+246: ok
+245: ok
+244: ok
+243: ok
+242: ok
+241: ok
+240: ok
+239: ok
+238: ok
+237: ok
+236: 237
+235: ok
+234: ok
+233: ok
+232: ok
+231: 232
+230: ok
+229: ok
+228: 229
+227: ok
+226: ok
+225: ok
+224: ok
+223: ok
+222: ok
+221: ok
+220: ok
+219: ok
+218: ok
+217: ok
+216: ok
+215: ok
+214: ok
+213: 73
+212: ok
+211: ok
+210: ok
+209: ok
+208: 209
+207: ok
+206: ok
+205: ok
+204: ok
+203: ok
+202: ok
+201: ok
+200: ok
+199: ok
+198: 199
+197: ok
+196: ok
+195: ok
+194: ok
+193: ok
+192: ok
+191: ok
+190: ok
+189: ok
+188: ok
+187: ok
+186: ok
+185: ok
+184: ok
+183: ok
+182: ok
+181: ok
+180: ok
+179: ok
+178: ok
+177: ok
+176: ok
+175: ok
+174: ok
+173: ok
+172: ok
+171: ok
+170: ok
+169: ok
+168: ok
+167: ok
+166: ok
+165: ok
+164: 165
+163: 233
+162: 224
+161: 214
+160: 181
+159: ok
+158: ok
+157: ok
+156: ok
+155: 157
+154: ok
+153: ok
+152: length 0
+151: 235
+150: 234
+149: 227
+148: 153
+147: 226
+146: ok
+145: 146
+144: ok
+143: ok
+142: ok
+141: 222
+140: 215
+139: 216
+138: 212
+137: 211
+136: 210
+135: 128
+134: 143
+133: 183
+132: 142
+131: 182
+130: 144
+129: 154
+128: ok
+127: ok
+126: ok
+125: ok
+124: open unlink 0
+123: ok
+122: 90
+121: 89
+120: 88
+119: 87
+118: 86
+117: 85
+116: 84
+115: 83
+114: 82
+113: 81
+112: 80
+111: 79
+110: 78
+109: 77
+108: 76
+107: 75
+106: 74
+105: 73
+104: 72
+103: 71
+102: 70
+101: 69
+100: 68
+99: 67
+98: 66
+97: 65
+96: ok
+95: ok
+94: ok
+93: open unlink 0
+92: open unlink 0
+91: open unlink 0
+90: ok
+89: ok
+88: ok
+87: ok
+86: ok
+85: ok
+84: ok
+83: ok
+82: ok
+81: ok
+80: ok
+79: ok
+78: ok
+77: ok
+76: ok
+75: ok
+74: ok
+73: ok
+72: ok
+71: ok
+70: ok
+69: ok
+68: ok
+67: ok
+66: ok
+65: ok
+64: ok
+63: open unlink 0
+62: open unlink 0
+61: open unlink 0
+60: open unlink 0
+59: open unlink 0
+58: open unlink 0
+57: ok
+56: ok
+55: ok
+54: ok
+53: ok
+52: ok
+51: ok
+50: ok
+49: ok
+48: ok
+47: open unlink 0
+46: open unlink 0
+45: ok
+44: open unlink 0
+43: open unlink 0
+42: open unlink 0
+41: ok
+40: ok
+39: ok
+38: ok
+37: ok
+36: ok
+35: ok
+34: open unlink 0
+33: ok
+32: open unlink 0
+31: open unlink 0
+30: open unlink 0
+29: open unlink 0
+28: open unlink 0
+27: open unlink 0
+26: open unlink 0
+25: open unlink 0
+24: open unlink 0
+23: open unlink 0
+22: open unlink 0
+21: open unlink 0
+20: open unlink 0
+19: open unlink 0
+18: open unlink 0
+17: open unlink 0
+16: open unlink 0
+15: open unlink 0
+14: open unlink 0
+13: open unlink 0
+12: open unlink 0
+11: open unlink 0
+10: open unlink 0
+9: open unlink 0
+8: open unlink 0
+7: open unlink 0
+6: open unlink 0
+5: open unlink 0
+4: open unlink 0
+3: open unlink 0
+2: open unlink 0
+1: open unlink 0
+
+ valid chars = 73:213 213:73 73:73 33 35 36 37 38 39 40 41 45 48 49 50 51 52 53 54 55 56 57 64 97:65 98:66 99:67 100:68 101:69 102:70 103:71 104:72 105:73 106:74 107:75 108:76 109:77 110:78 111:79 112:80 113:81 114:82 115:83 116:84 117:85 118:86 119:87 120:88 121:89 122:90 94 95 96 123 125 126 127 135:128 132:142 134:143 130:144 145:146 148:153 129:154 156 155:157 158 159 164:165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 160:181 131:182 133:183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198:199 200 201 202 203 204 205 206 207 208:209 136:210 137:211 138:212 161:214 140:215 139:216 217 218 219 220 221 141:222 223 162:224 225 147:226 149:227 228:229 230 231:232 163:233 150:234 151:235 236:237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
diff --git a/examples/validchars/nwdos70.out b/examples/validchars/nwdos70.out
new file mode 100644
index 00000000000..b0dbf628531
--- /dev/null
+++ b/examples/validchars/nwdos70.out
@@ -0,0 +1,257 @@
+255: ok
+254: ok
+253: ok
+252: ok
+251: ok
+250: ok
+249: ok
+248: ok
+247: ok
+246: ok
+245: ok
+244: ok
+243: ok
+242: ok
+241: ok
+240: ok
+239: ok
+238: ok
+237: ok
+236: ok
+235: ok
+234: ok
+233: ok
+232: ok
+231: ok
+230: ok
+229: ok
+228: ok
+227: ok
+226: ok
+225: ok
+224: ok
+223: ok
+222: ok
+221: ok
+220: ok
+219: ok
+218: ok
+217: ok
+216: ok
+215: ok
+214: ok
+213: ok
+212: ok
+211: ok
+210: ok
+209: ok
+208: ok
+207: ok
+206: ok
+205: ok
+204: ok
+203: ok
+202: ok
+201: ok
+200: ok
+199: ok
+198: ok
+197: ok
+196: ok
+195: ok
+194: ok
+193: ok
+192: ok
+191: ok
+190: ok
+189: ok
+188: ok
+187: ok
+186: ok
+185: ok
+184: ok
+183: ok
+182: ok
+181: ok
+180: ok
+179: ok
+178: ok
+177: ok
+176: ok
+175: ok
+174: ok
+173: ok
+172: ok
+171: ok
+170: ok
+169: ok
+168: ok
+167: ok
+166: ok
+165: ok
+164: 165
+163: 85
+162: 79
+161: 73
+160: 65
+159: ok
+158: ok
+157: ok
+156: ok
+155: ok
+154: ok
+153: ok
+152: 89
+151: 85
+150: 85
+149: 79
+148: 153
+147: 79
+146: ok
+145: 146
+144: ok
+143: ok
+142: ok
+141: 73
+140: 73
+139: 73
+138: 69
+137: 69
+136: 69
+135: 128
+134: 143
+133: 65
+132: 142
+131: 65
+130: 69
+129: 154
+128: ok
+127: ok
+126: ok
+125: ok
+124: open unlink 0
+123: ok
+122: 90
+121: 89
+120: 88
+119: 87
+118: 86
+117: 85
+116: 84
+115: 83
+114: 82
+113: 81
+112: 80
+111: 79
+110: 78
+109: 77
+108: 76
+107: 75
+106: 74
+105: 73
+104: 72
+103: 71
+102: 70
+101: 69
+100: 68
+99: 67
+98: 66
+97: 65
+96: ok
+95: ok
+94: ok
+93: open unlink 0
+92: open unlink 0
+91: open unlink 0
+90: ok
+89: ok
+88: ok
+87: ok
+86: ok
+85: ok
+84: ok
+83: ok
+82: ok
+81: ok
+80: ok
+79: ok
+78: ok
+77: ok
+76: ok
+75: ok
+74: ok
+73: ok
+72: ok
+71: ok
+70: ok
+69: ok
+68: ok
+67: ok
+66: ok
+65: ok
+64: ok
+63: open unlink 0
+62: open unlink 0
+61: open unlink 0
+60: open unlink 0
+59: open unlink 0
+58: open unlink 0
+57: ok
+56: ok
+55: ok
+54: ok
+53: ok
+52: ok
+51: ok
+50: ok
+49: ok
+48: ok
+47: open unlink 0
+46: open unlink 0
+45: ok
+44: open unlink 0
+43: open unlink 0
+42: open unlink 0
+41: ok
+40: ok
+39: ok
+38: ok
+37: ok
+36: ok
+35: ok
+34: open unlink 0
+33: ok
+32: length 0
+31: open unlink 0
+30: open unlink 0
+29: open unlink 0
+28: open unlink 0
+27: open unlink 0
+26: open unlink 0
+25: open unlink 0
+24: open unlink 0
+23: open unlink 0
+22: open unlink 0
+21: open unlink 0
+20: open unlink 0
+19: open unlink 0
+18: open unlink 0
+17: open unlink 0
+16: open unlink 0
+15: open unlink 0
+14: open unlink 0
+13: open unlink 0
+12: open unlink 0
+11: open unlink 0
+10: open unlink 0
+9: open unlink 0
+8: open unlink 0
+7: open unlink 0
+6: open unlink 0
+5: open unlink 0
+4: open unlink 0
+3: open unlink 0
+2: open unlink 0
+1: open unlink 0
+
+ valid chars = 69:130 130:69 69:69 65:131 131:65 65:65 65:133 133:65 65:65 69:136 136:69 69:69 69:137 137:69 69:69 69:138 138:69 69:69 73:139 139:73 73:73 73:140 140:73 73:73 73:141 141:73 73:73 79:147 147:79 79:79 79:149 149:79 79:79 85:150 150:85 85:85 85:151 151:85 85:85 89:152 152:89 89:89 65:160 160:65 65:65 73:161 161:73 73:73 79:162 162:79 79:79 85:163 163:85 85:85 33 35 36 37 38 39 40 41 45 48 49 50 51 52 53 54 55 56 57 64 97:65 98:66 99:67 100:68 101:69 102:70 103:71 104:72 105:73 106:74 107:75 108:76 109:77 110:78 111:79 112:80 113:81 114:82 115:83 116:84 117:85 118:86 119:87 120:88 121:89 122:90 94 95 96 123 125 126 127 135:128 132:142 134:143 144 145:146 148:153 129:154 155 156 157 158 159 164:165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
diff --git a/examples/validchars/readme b/examples/validchars/readme
new file mode 100644
index 00000000000..6487fbd766a
--- /dev/null
+++ b/examples/validchars/readme
@@ -0,0 +1,101 @@
+Note: All files in this directory are DOS formatted (CRLF line terminator).
+
+!!! VIRUS WARNING !!! I do not know if VALIDCHR.COM is virus free !!!
+I think that my system is virus free here because I do not run any games
+or other copied software. I only run Shareware/Freeware etc. from CD-ROMs
+or from registered disks, however I do not use viral scanners because
+I have not registered any (I consider `having no sex' is better than
+`testing for AIDS on a regular basis', if you know what I mean).
+
+This is VALIDCHR, a little DOS program I wrote to create
+an apropriate `valid chars =' config parameter.
+It is freeware and is thought to be distributed freely with Samba.
+
+WARNING:
+ Your SMB driver may use another character map as the one VALIDCHR
+ sees. The only way you can tell this is that some file names fail.
+ Under Win95 everything is fine, though.
+
+Usage:
+ c:
+ mkdir junk_dir
+ cd junk_dir
+ a:validchr > a:output.log
+ cd ..
+ rmdir junk_dir
+
+Siedeffects:
+ Files named *.TST may be deleted.
+
+Verification:
+ For diagnostic purpose you can run VALIDCHR on a Samba mounted drive.
+ Then you can use unix diff to compare the output of the network and
+ the hard drive. These two outputs usually differ! However there
+ should be few differences. I get following on Win95 (c: visa e:)
+ 104c104
+ < 152: length 0
+ ---
+ > 152: 95
+ (diff line for `valid chars =' deleted because it's uninteresting)
+ You can see, `y diaresis' can be mapped on the network drive while
+ it cannot be mapped on the hard drive. Everything else is identical.
+ However this gives a hint that one can improve the mapping.
+
+Bugs:
+ Yes, probably some.
+
+
+VALIDCHR must be run on the system which character mapping should be probed.
+It must be run on the hard drive for this. VALIDCHR ALTERS THE CURRENT
+DIRECTORY AND REMOVES SOME FILES, SO ALWAYS RUN IT IN A junk DIRECTORY !!!
+You should redirect the output of VALIDCHR. At the end of the output is a
+line like
+ valid chars = x:y y:x x:x ... a:b c ...
+which is suitable for your smb.conf file. (you should remove the DOS CR
+character, because DOS uses CRLF while Unix uses LF only.)
+
+Note that some mappings at the beginning of the `valid chars =' line like
+A:B B:A B:B
+might look a little bit strange to you, however sometimes character A
+has to be mapped to character B independently of a default mapping
+to uppercase or lowercase while character B must not be touched. I found
+this out the hard way ... Consider it a crude workaround, because Samba
+lacks the possibility to map characters in one direction only!
+
+VALIDCHR usually issues one warning for character 32.
+You may ignore these and any other warnings.
+
+VALIDCHR does not test for character NUL (this is the directory end marker).
+
+validchr.c is the source code to validchr.com
+ You may do anything with the source code (copy, change, sell, burn)
+validchr.com is a Borland C compiled binary.
+ Beware, it may contain a virus (if my system contains one).
+nwdos70.out is the output of an VALIDCHR-run under Novell DOS 7.0
+ while no codepage (no display.sys) was active.
+msdos70.out is the output of an VALIDCHR-run under MS-DOS 7.0 (Win95 DOS)
+ while codepage 850 was active.
+
+I have no other MS-DOS systems at home currently.
+(I have access to MS-DOS 3.0, 3.2, 3.3, 5.0 and 6.22, however I have no time
+ to run VALIDCHR there)
+
+Some words to the output
+(for people not fammiliar with programming language C):
+
+probed_char: [text] mapped_char
+
+probed_char is the character probed to be written to disk
+text may be empty or contain:
+ open File could not be opened.
+ close File could not be closed (should not happen)
+ length File name was shortened (usually occurs on SPC)
+ unlink File cannot be unlinked (usually when open fails)
+mapped_char is the character which is used by MS-DOS in the directory
+ This is usually the uppercase character.
+ The mapped character is 0 if something failed (you may say
+ that the character is not supported)
+
+The last line in the output is documented in the smb.conf manual page ;)
+
+tino@augsburg.net
diff --git a/examples/validchars/validchr.c b/examples/validchars/validchr.c
new file mode 100644
index 00000000000..415546cb841
--- /dev/null
+++ b/examples/validchars/validchr.c
@@ -0,0 +1,123 @@
+/* by tino@augsburg.net
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <dirent.h>
+
+unsigned char
+test(void)
+{
+ DIR *dir;
+ struct dirent *dp;
+ unsigned char c;
+
+ if ((dir=opendir("."))==0)
+ {
+ perror("open .");
+ return 0;
+ }
+ c = 0;
+ while ((dp=readdir(dir))!=0)
+ {
+ size_t len;
+
+ len = strlen(dp->d_name);
+ if (len<4)
+ continue;
+ if (strcmp(dp->d_name+len-4, ".TST"))
+ continue;
+ if (len!=5)
+ {
+ fprintf(stderr, "warning: %s\n", dp->d_name);
+ printf(" length");
+ continue;
+ }
+ if (c)
+ printf(" double%d\n", c);
+ c = dp->d_name[0];
+ }
+ if (closedir(dir))
+ perror("close .");
+ return c;
+}
+
+int
+main(void)
+{
+ char name[256];
+ unsigned char map[256], upper[256], lower[256];
+ int i, j, c;
+ FILE *fd;
+
+ if (test())
+ {
+ printf("There are *.TST files, please remove\n");
+ return 0;
+ }
+ for (i=0; ++i<256; )
+ {
+ lower[i] = i;
+ upper[i] = 0;
+ }
+ for (i=256; --i; )
+ {
+ map[i] = i;
+ strcpy(name, "..TST");
+ name[0] = i;
+ printf("%d:", i);
+ if ((fd=fopen(name, "w"))==0)
+ printf(" open");
+ else
+ fclose(fd);
+ c = test();
+ if (unlink(name))
+ printf(" unlink");
+ if (c==i)
+ printf(" ok");
+ else
+ printf(" %d", c);
+ printf("\n");
+ if (c!=i)
+ {
+ upper[c]++;
+ lower[c] = i;
+ }
+ map[i] = c;
+ }
+
+ /* Uppercase characters are detected above on:
+ * The character is mapped to itself and there is a
+ * character which maps to it.
+ * Lowercase characters are the lowest character pointing to another one.
+ * Else it is a one way character.
+ *
+ * For this reason we have to process the list
+ * 1) for 'one way' characters
+ * 'one way' is something which is no upper and no lower character.
+ * This is an awful, crude and ugly hack due to missing Samba support.
+ * 2) for true uppercase/lowercase characters
+ * 3) for standalone characters
+ * Note that there might be characters which do not fall into 1 to 3.
+ */
+ printf("\n valid chars =");
+ for (i=0; ++i<256; )
+ if (map[i] && map[i]!=i && lower[map[i]]!=i)
+ {
+ if (!upper[i])
+ printf(" %d:%d %d:%d %d:%d", /*1*/
+ map[i], i, i, map[i], map[i], map[i]);
+ else
+ fprintf(stderr, "ignoring map %d->%d because of %d->%d\n",
+ lower[i], i, i, map[i]);
+ }
+ for (i=0; ++i<256; )
+ if (map[i] && map[i]==i)
+ if (upper[i])
+ printf(" %d:%d", lower[i], i); /*2*/
+ else
+ printf(" %d", i); /*3*/
+ printf("\n");
+ return 0;
+}
diff --git a/examples/validchars/validchr.com b/examples/validchars/validchr.com
new file mode 100644
index 00000000000..ce159568369
--- /dev/null
+++ b/examples/validchars/validchr.com
Binary files differ
diff --git a/source/.cvsignore b/source/.cvsignore
new file mode 100644
index 00000000000..d675e728fec
--- /dev/null
+++ b/source/.cvsignore
@@ -0,0 +1,11 @@
+makefile
+makefile.sunos5
+nmbd
+nmblookup
+smbclient
+smbd
+smbpasswd
+smbrun
+smbstatus
+testparm
+testprns
diff --git a/source/change-log b/source/change-log
index e120ac6f02a..42a27fe6f68 100644
--- a/source/change-log
+++ b/source/change-log
@@ -1,10 +1,13 @@
-Change Log for Samba
+SUPERCEDED Change Log for Samba
+^^^^^^^^^^
Unless otherwise attributed, all changes were made by
-Andrew.Tridgell@anu.edu.au
+Andrew.Tridgell@anu.edu.au. All bugs to samba-bugs@samba.anu.edu.au.
NOTE: THIS LOG IS IN CHRONOLOGICAL ORDER
+NOTE: From now on the cvs.log file will be used to give a complete log of
+changes to samba. This change-log is now obsolete.
1.5.00 announced to mailing list
@@ -1793,6 +1796,9 @@ NOTE: THIS LOG IS IN CHRONOLOGICAL ORDER
- Linux quota patch from xeno@mix.hsv.no
- try to work around NT passlen2 problem in session setup
- released alpha1
+
+NOTE: From now on the cvs.log file will be used to give a complete log of
+changes to samba. This change-log is now obsolete.
==========
@@ -1869,4 +1875,4 @@ lpd stuff:
Tony Aiuto (tony@ics.com)
make max disk size local
- \ No newline at end of file
+
diff --git a/source/client/client.c b/source/client/client.c
index 504cb5a0bb4..a6bb50cb3d8 100644
--- a/source/client/client.c
+++ b/source/client/client.c
@@ -24,7 +24,6 @@
#endif
#include "includes.h"
-#include "nameserv.h"
#ifndef REGISTER
#define REGISTER 0
@@ -38,11 +37,11 @@ pstring myname = "";
pstring password = "";
pstring username="";
pstring workgroup=WORKGROUP;
+char *cmdstr="";
BOOL got_pass = False;
BOOL connect_as_printer = False;
BOOL connect_as_ipc = False;
-extern struct in_addr bcast_ip;
-static BOOL got_bcast=False;
+extern struct in_addr ipzero;
char cryptkey[8];
BOOL doencrypt=False;
@@ -64,23 +63,34 @@ int max_protocol = PROTOCOL_NT1;
time_t newer_than = 0;
int archive_level = 0;
-extern struct in_addr myip;
-
extern pstring debugf;
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 */
@@ -150,20 +160,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
****************************************************************************/
@@ -482,9 +478,322 @@ static void display_finfo(file_info *finfo)
CNV_LANG(finfo->name),
attrib_string(finfo->mode),
finfo->size,
- asctime(LocalTime(&t,GMT_TO_LOCAL))));
+ 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);
+
+ 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
****************************************************************************/
@@ -518,6 +827,34 @@ static BOOL do_this_one(file_info *finfo)
return(True);
}
+
+/*****************************************************************************
+ Convert a character pointer in a call_api() response to a form we can use.
+ This function contains code to prevent core dumps if the server returns
+ invalid data.
+*****************************************************************************/
+static char *fix_char_ptr(unsigned int datap, unsigned int converter, char *rdata, int rdrcnt)
+{
+if( datap == 0 ) /* turn NULL pointers */
+ { /* into zero length strings */
+ return "";
+ }
+else
+ {
+ unsigned int offset = datap - converter;
+
+ if( offset < 0 || offset >= rdrcnt )
+ {
+ DEBUG(1,("bad char ptr: datap=%u, converter=%u, rdata=%u, rdrcnt=%d>", datap, converter, (unsigned)rdata, rdrcnt));
+ return "<ERROR>";
+ }
+ else
+ {
+ return &rdata[offset];
+ }
+ }
+}
+
/****************************************************************************
interpret a short filename structure
The length of the structure is returned
@@ -684,148 +1021,11 @@ static void dir_action(char *inbuf,char *outbuf,int attribute,file_info *finfo,B
/****************************************************************************
- do a directory listing, calling fn on each file found
- ****************************************************************************/
-static int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir)
-{
- char *p;
- int received = 0;
- BOOL first = True;
- char status[21];
- int num_asked = (max_xmit - 100)/DIR_STRUCT_SIZE;
- int num_received = 0;
- int i;
- char *dirlist = NULL;
- pstring mask;
- file_info finfo;
-
- finfo = def_finfo;
-
- bzero(status,21);
-
- strcpy(mask,Mask);
-
- while (1)
- {
- bzero(outbuf,smb_size);
- if (first)
- set_message(outbuf,2,5 + strlen(mask),True);
- else
- set_message(outbuf,2,5 + 21,True);
-
-#if FFIRST
- if (Protocol >= PROTOCOL_LANMAN1)
- CVAL(outbuf,smb_com) = SMBffirst;
- else
-#endif
- CVAL(outbuf,smb_com) = SMBsearch;
-
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- SSVAL(outbuf,smb_vwv0,num_asked);
- SSVAL(outbuf,smb_vwv1,attribute);
-
- p = smb_buf(outbuf);
- *p++ = 4;
-
- if (first)
- strcpy(p,mask);
- else
- strcpy(p,"");
- p += strlen(p) + 1;
-
- *p++ = 5;
- if (first)
- SSVAL(p,0,0);
- else
- {
- SSVAL(p,0,21);
- p += 2;
- memcpy(p,status,21);
- }
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- received = SVAL(inbuf,smb_vwv0);
-
- DEBUG(5,("dir received %d\n",received));
-
- DEBUG(6,("errstr=%s\n",smb_errstr(inbuf)));
-
- if (received <= 0) break;
-
- first = False;
-
- dirlist = Realloc(dirlist,(num_received + received)*DIR_STRUCT_SIZE);
-
- if (!dirlist)
- return 0;
-
- p = smb_buf(inbuf) + 3;
-
- memcpy(dirlist+num_received*DIR_STRUCT_SIZE,
- p,received*DIR_STRUCT_SIZE);
-
- memcpy(status,p + ((received-1)*DIR_STRUCT_SIZE),21);
-
- num_received += received;
-
- if (CVAL(inbuf,smb_rcls) != 0) break;
- }
-
-#if FFIRST
- if (!first && Protocol >= PROTOCOL_LANMAN1)
- {
- bzero(outbuf,smb_size);
- CVAL(outbuf,smb_com) = SMBfclose;
-
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- p = smb_buf(outbuf);
- *p++ = 4;
-
- strcpy(p,"");
- p += strlen(p) + 1;
-
- *p++ = 5;
- SSVAL(p,0,21);
- p += 2;
- memcpy(p,status,21);
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT,False);
-
- if (CVAL(inbuf,smb_rcls) != 0)
- DEBUG(0,("Error closing search: %s\n",smb_errstr(inbuf)));
- }
-#endif
-
- if (!fn)
- for (p=dirlist,i=0;i<num_received;i++)
- {
- p += interpret_short_filename(p,&finfo);
- display_finfo(&finfo);
- }
-
- for (p=dirlist,i=0;i<num_received;i++)
- {
- p += interpret_short_filename(p,&finfo);
- dir_action(inbuf,outbuf,attribute,&finfo,recurse_dir,fn,False);
- }
-
- if (dirlist) free(dirlist);
- return(num_received);
-}
-
-/****************************************************************************
receive a SMB trans or trans2 response allocating the necessary memory
****************************************************************************/
static BOOL receive_trans_response(char *inbuf,int trans,
int *data_len,int *param_len,
- char **data,char **param)
+ char **data,char **param)
{
int total_data=0;
int total_param=0;
@@ -893,178 +1093,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
@@ -2131,13 +2159,12 @@ static void cmd_mput(void)
strcpy(rname,cur_dir);
strcat(rname,lname);
- if (!do_mkdir(rname))
- {
- strcat(lname,"/");
- if (!seek_list(f,lname))
- break;
- goto again1;
- }
+ if (!chkpath(rname,False) && !do_mkdir(rname)) {
+ strcat(lname,"/");
+ if (!seek_list(f,lname))
+ break;
+ goto again1;
+ }
continue;
}
@@ -2178,7 +2205,7 @@ static void do_cancel(int job)
bzero(param,sizeof(param));
p = param;
- SSVAL(p,0,81); /* api number */
+ SSVAL(p,0,81); /* DosPrintJobDel() */
p += 2;
strcpy(p,"W");
p = skip_string(p,1);
@@ -2425,7 +2452,7 @@ static void cmd_print(char *inbuf,char *outbuf )
}
/****************************************************************************
-print a file
+show a print queue
****************************************************************************/
static void cmd_queue(char *inbuf,char *outbuf )
{
@@ -2487,6 +2514,109 @@ static void cmd_queue(char *inbuf,char *outbuf )
/****************************************************************************
+show information about a print queue
+****************************************************************************/
+static void cmd_qinfo(char *inbuf,char *outbuf )
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt, rprcnt;
+ pstring param;
+ int result_code;
+
+ bzero(param,sizeof(param));
+
+ p = param;
+ SSVAL(p,0,70); /* API function number 70 (DosPrintQGetInfo) */
+ p += 2;
+ strcpy(p,"zWrLh"); /* parameter description? */
+ p = skip_string(p,1);
+ strcpy(p,"zWWWWzzzzWWzzl"); /* returned data format */
+ p = skip_string(p,1);
+ strcpy(p,strrchr(service,'\\')+1); /* name of queue */
+ p = skip_string(p,1);
+ SSVAL(p,0,3); /* API function level 3, just queue info, no job info */
+ SSVAL(p,2,1000); /* size of bytes of returned data buffer */
+ p += 4;
+ strcpy(p,""); /* subformat */
+ p = skip_string(p,1);
+
+ DEBUG(1,("Calling DosPrintQueueGetInfo()...\n"));
+ if( call_api(PTR_DIFF(p,param), 0,
+ 10, 4096,
+ &rprcnt, &rdrcnt,
+ param, NULL,
+ &rparam, &rdata) )
+ {
+ int converter;
+ result_code = SVAL(rparam,0);
+ converter = SVAL(rparam,2); /* conversion factor */
+
+ DEBUG(2,("returned %d bytes of parameters, %d bytes of data, %d records\n", rprcnt, rdrcnt, SVAL(rparam,4) ));
+
+ if (result_code == 0) /* if no error, */
+ {
+ p = rdata; /* received data */
+
+ printf("Name: \"%s\"\n", fix_char_ptr(SVAL(p,0), converter, rdata, rdrcnt) );
+ printf("Priority: %u\n", SVAL(p,4) );
+ printf("Start time: %u\n", SVAL(p,6) );
+ printf("Until time: %u\n", SVAL(p,8) );
+ printf("Seperator file: \"%s\"\n", fix_char_ptr(SVAL(p,12), converter, rdata, rdrcnt) );
+ printf("Print processor: \"%s\"\n", fix_char_ptr(SVAL(p,16), converter, rdata, rdrcnt) );
+ printf("Parameters: \"%s\"\n", fix_char_ptr(SVAL(p,20), converter, rdata, rdrcnt) );
+ printf("Comment: \"%s\"\n", fix_char_ptr(SVAL(p,24), converter, rdata, rdrcnt) );
+ printf("Status: %u\n", SVAL(p,28) );
+ printf("Jobs: %u\n", SVAL(p,30) );
+ printf("Printers: \"%s\"\n", fix_char_ptr(SVAL(p,32), converter, rdata, rdrcnt) );
+ printf("Drivername: \"%s\"\n", fix_char_ptr(SVAL(p,36), converter, rdata, rdrcnt) );
+
+ /* Dump the driver data */
+ {
+ int count, x, y, c;
+ char *ddptr;
+
+ ddptr = rdata + SVAL(p,40) - converter;
+ if( SVAL(p,40) == 0 ) {count = 0;} else {count = IVAL(ddptr,0);}
+ printf("Driverdata: size=%d, version=%u\n", count, IVAL(ddptr,4) );
+
+ for(x=8; x < count; x+=16)
+ {
+ for(y=0; y < 16; y++)
+ {
+ if( (x+y) < count )
+ printf("%2.2X ", CVAL(ddptr,(x+y)) );
+ else
+ fputs(" ", stdout);
+ }
+ for(y=0; y < 16 && (x+y) < count; y++)
+ {
+ c = CVAL(ddptr,(x+y));
+ if(isprint(c))
+ fputc(c, stdout);
+ else
+ fputc('.', stdout);
+ }
+ fputc('\n', stdout);
+ }
+ }
+
+ }
+ }
+ else /* call_api() failed */
+ {
+ printf("Failed, error = %d\n", result_code);
+ }
+
+ /* If any parameters or data were returned, free the storage. */
+ if(rparam) free(rparam);
+ if(rdata) free(rdata);
+
+ return;
+}
+
+/****************************************************************************
delete some files
****************************************************************************/
static void do_del(file_info *finfo)
@@ -2670,7 +2800,7 @@ static void cmd_newer(void)
{
newer_than = sbuf.st_mtime;
DEBUG(1,("Getting files newer than %s",
- asctime(LocalTime(&newer_than,GMT_TO_LOCAL))));
+ asctime(LocalTime(&newer_than))));
}
else
newer_than = 0;
@@ -2875,6 +3005,21 @@ static BOOL send_session_request(char *inbuf,char *outbuf)
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
@@ -2888,22 +3033,6 @@ static BOOL send_login(char *inbuf,char *outbuf,BOOL start_session,BOOL use_setu
int sec_mode=0;
int crypt_len;
int max_vcs=0;
- 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}
- };
char *pass = NULL;
pstring dev;
char *p;
@@ -3032,7 +3161,7 @@ static BOOL send_login(char *inbuf,char *outbuf,BOOL start_session,BOOL use_setu
static BOOL done_time = False;
if (!done_time) {
DEBUG(1,("Server time is %sTimezone is UTC%+02.1f\n",
- asctime(LocalTime(&servertime,GMT_TO_LOCAL)),
+ asctime(LocalTime(&servertime)),
-(double)(serverzone/3600.0)));
done_time = True;
}
@@ -3182,19 +3311,36 @@ static BOOL send_login(char *inbuf,char *outbuf,BOOL start_session,BOOL use_setu
strcpy(pword, ""); passlen=1;
}
- set_message(outbuf,4,2 + strlen(service) + passlen + strlen(dev),True);
- CVAL(outbuf,smb_com) = SMBtconX;
- setup_pkt(outbuf);
-
- SSVAL(outbuf,smb_vwv0,0xFF);
- SSVAL(outbuf,smb_vwv3,passlen);
+ if (Protocol <= PROTOCOL_CORE) {
+ set_message(outbuf,0,6 + strlen(service) + passlen + strlen(dev),True);
+ CVAL(outbuf,smb_com) = SMBtcon;
+ setup_pkt(outbuf);
- p = smb_buf(outbuf);
- memcpy(p,pword,passlen);
- p += passlen;
- strcpy(p,service);
- p = skip_string(p,1);
- strcpy(p,dev);
+ p = smb_buf(outbuf);
+ *p++ = 0x04;
+ strcpy(p, service);
+ p = skip_string(p,1);
+ *p++ = 0x04;
+ memcpy(p,pword,passlen);
+ p += passlen;
+ *p++ = 0x04;
+ strcpy(p, dev);
+ }
+ else {
+ set_message(outbuf,4,2 + strlen(service) + passlen + strlen(dev),True);
+ CVAL(outbuf,smb_com) = SMBtconX;
+ 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);
@@ -3225,11 +3371,18 @@ static BOOL send_login(char *inbuf,char *outbuf,BOOL start_session,BOOL use_setu
}
- max_xmit = MIN(max_xmit,BUFFER_SIZE-4);
- if (max_xmit <= 0)
- max_xmit = BUFFER_SIZE - 4;
+ if (Protocol <= PROTOCOL_CORE) {
+ max_xmit = SVAL(inbuf,smb_vwv0);
- cnum = SVAL(inbuf,smb_tid);
+ cnum = SVAL(inbuf,smb_vwv1);
+ }
+ else {
+ 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));
@@ -3522,7 +3675,7 @@ static void server_info()
bzero(param,sizeof(param));
p = param;
- SSVAL(p,0,63); /* api number */
+ SSVAL(p,0,63); /* NetServerGetInfo()? */
p += 2;
strcpy(p,"WrLh");
p = skip_string(p,1);
@@ -3563,34 +3716,49 @@ static void server_info()
/****************************************************************************
try and browse available connections on a host
****************************************************************************/
-static BOOL list_servers()
+static BOOL list_servers(char *wk_grp)
{
char *rparam = NULL;
char *rdata = NULL;
int rdrcnt,rprcnt;
- char *p;
+ char *p,*svtype_p;
pstring param;
int uLevel = 1;
int count = 0;
+ BOOL ok = False;
+ BOOL generic_request = False;
+
+
+ if (strequal(wk_grp,"WORKGROUP")) {
+ /* we won't specify a workgroup */
+ generic_request = True;
+ }
/* now send a SMBtrans command with api ServerEnum? */
p = param;
SSVAL(p,0,0x68); /* api number */
p += 2;
- strcpy(p,"WrLehDO");
+
+ strcpy(p,generic_request?"WrLehDO":"WrLehDz");
p = skip_string(p,1);
strcpy(p,"B16BBDz");
-#if 0
- strcpy(p,getenv("XX_STR2"));
-#endif
p = skip_string(p,1);
SSVAL(p,0,uLevel);
SSVAL(p,2,0x2000); /* buf length */
p += 4;
- SIVAL(p,0,SV_TYPE_ALL);
+ svtype_p = p;
+ p += 4;
+
+ if (!generic_request) {
+ strcpy(p, wk_grp);
+ p = skip_string(p,1);
+ }
+
+ /* first ask for a list of servers in this workgroup */
+ SIVAL(svtype_p,0,SV_TYPE_ALL);
if (call_api(PTR_DIFF(p+4,param),0,
8,10000,
@@ -3618,7 +3786,8 @@ static BOOL list_servers()
printf("\t%-16.16s %s\n",
sname,
comment_offset?rdata+comment_offset-converter:"");
-
+
+ ok=True;
p2 += 26;
}
}
@@ -3627,7 +3796,8 @@ static BOOL list_servers()
if (rparam) {free(rparam); rparam = NULL;}
if (rdata) {free(rdata); rdata = NULL;}
- SIVAL(p,0,SV_TYPE_DOMAIN_ENUM);
+ /* now ask for a list of workgroups */
+ SIVAL(svtype_p,0,SV_TYPE_DOMAIN_ENUM);
if (call_api(PTR_DIFF(p+4,param),0,
8,10000,
@@ -3656,6 +3826,7 @@ static BOOL list_servers()
sname,
comment_offset?rdata+comment_offset-converter:"");
+ ok=True;
p2 += 26;
}
}
@@ -3664,14 +3835,10 @@ static BOOL list_servers()
if (rparam) free(rparam);
if (rdata) free(rdata);
- return(count>0);
+ return(ok);
}
-
-
-void cmd_help();
-
/* This defines the commands supported by this client */
struct
{
@@ -3705,6 +3872,7 @@ struct
{"print",cmd_print,"<file name> print a file"},
{"printmode",cmd_printmode,"<graphics or text> set the print mode"},
{"queue",cmd_queue,"show the print queue"},
+ {"qinfo",cmd_qinfo,"show print queue information"},
{"cancel",cmd_cancel,"<jobid> cancel a print queue entry"},
{"stat",cmd_stat,"<file> get info on a file (experimental!)"},
{"quit",send_logout,"logoff the server"},
@@ -3815,14 +3983,14 @@ static BOOL open_sockets(int port )
strcpy(desthost,host);
}
- DEBUG(3,("Opening sockets\n"));
-
if (*myname == 0)
{
get_myname(myname,NULL);
strupper(myname);
}
+ DEBUG(3,("Opening sockets\n"));
+
if (!have_ip)
{
struct hostent *hp;
@@ -3834,17 +4002,12 @@ static BOOL open_sockets(int port )
#ifdef USENMB
/* Try and resolve the name with the netbios server */
int bcast;
- pstring hs;
- struct in_addr ip1, ip2;
-
- if ((bcast = open_socket_in(SOCK_DGRAM, 0, 3)) != -1) {
- set_socket_options (bcast, "SO_BROADCAST");
- if (!got_bcast && get_myname(hs, &ip1)) {
- get_broadcast(&ip1, &bcast_ip, &ip2);
- }
+ if ((bcast = open_socket_in(SOCK_DGRAM, 0, 3)) != -1) {
+ set_socket_options(bcast, "SO_BROADCAST");
- if (name_query(bcast, host, 0x20, True, True, bcast_ip, &dest_ip,0)){
+ if (name_query(bcast, host, 0x20, True, True, *iface_bcast(dest_ip),
+ &dest_ip,0)) {
failed = False;
}
close (bcast);
@@ -3975,10 +4138,11 @@ 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;
+ char *cmd;
char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
@@ -3993,7 +4157,44 @@ BOOL process(char *base_directory)
if (*base_directory) do_cd(base_directory);
- while (!feof(stdin))
+ cmd = cmdstr;
+ if (cmd[0] != '\0') while (cmd[0] != '\0')
+ {
+ char *p;
+ fstring tok;
+ int i;
+
+ if ((p = strchr(cmd, ';')) == 0)
+ {
+ strncpy(line, cmd, 999);
+ line[1000] = '\0';
+ cmd += strlen(cmd);
+ }
+ else
+ {
+ if (p - cmd > 999) p = cmd + 999;
+ strncpy(line, cmd, p - cmd);
+ line[p - cmd] = '\0';
+ cmd = p + 1;
+ }
+
+ /* input language code to internal one */
+ CNV_INPUT (line);
+
+ /* and get the first part of the command */
+ {
+ char *ptr = line;
+ if (!next_token(&ptr,tok,NULL)) continue;
+ }
+
+ if ((i = process_tok(tok)) >= 0)
+ commands[i].fn(InBuffer,OutBuffer);
+ else if (i == -2)
+ DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
+ else
+ DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
+ }
+ else while (!feof(stdin))
{
fstring tok;
int i;
@@ -4053,7 +4254,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));
@@ -4076,6 +4277,7 @@ void usage(char *pname)
DEBUG(0,("\t-E write messages to stderr instead of stdout\n"));
DEBUG(0,("\t-U username set the network username\n"));
DEBUG(0,("\t-W workgroup set the workgroup name\n"));
+ DEBUG(0,("\t-c command string execute semicolon separated commands\n"));
#ifdef KANJI
DEBUG(0,("\t-t terminal code terminal i/o code {sjis|euc|jis7|jis8|junet|hex}\n"));
#endif /* KANJI */
@@ -4089,11 +4291,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;
@@ -4101,6 +4303,7 @@ int main(int argc,char *argv[])
pstring query_host;
BOOL message = False;
extern char tar_type;
+ static pstring servicesf = CONFIGFILE;
*query_host = 0;
*base_directory = 0;
@@ -4172,10 +4375,9 @@ int main(int argc,char *argv[])
#ifdef KANJI
setup_term_code (KANJI);
- while ((opt = getopt (argc, argv, "B:O:M:i:Nn:d:Pp:l:hI:EB:U:L:t:m:W:T:D:")) != EOF)
-#else
- while ((opt = getopt (argc, argv, "B:O:M:i:Nn:d:Pp:l:hI:EB:U:L:m:W:T:D:")) != EOF)
-#endif /* KANJI */
+#endif
+ while ((opt =
+ getopt(argc, argv,"s:B:O:M:i:Nn:d:Pp:l:hI:EB:U:L:t:m:W:T:D:c:")) != EOF)
switch (opt)
{
case 'm':
@@ -4191,8 +4393,7 @@ int main(int argc,char *argv[])
message = True;
break;
case 'B':
- bcast_ip = *interpret_addr2(optarg);
- got_bcast = True;
+ iface_set_default(NULL,optarg,NULL);
break;
case 'D':
strcpy(base_directory,optarg);
@@ -4258,19 +4459,26 @@ int main(int argc,char *argv[])
case 'p':
port = atoi(optarg);
break;
+ case 'c':
+ cmdstr = optarg;
+ got_pass = True;
+ break;
case 'h':
usage(pname);
exit(0);
break;
-#ifdef KANJI
+ case 's':
+ strcpy(servicesf, optarg);
+ break;
case 't':
+#ifdef KANJI
if (!setup_term_code (optarg)) {
DEBUG(0, ("%s: unknown terminal code name\n", optarg));
usage (pname);
exit (1);
}
+#endif
break;
-#endif /* KANJI */
default:
usage(pname);
exit(1);
@@ -4285,7 +4493,13 @@ int main(int argc,char *argv[])
DEBUG(3,("%s client started (version %s)\n",timestring(),VERSION));
- get_myname(*myname?NULL:myname,&myip);
+ if (!lp_load(servicesf,True)) {
+ fprintf(stderr, "Can't load %s - run testparm to debug it\n", servicesf);
+ return (-1);
+ }
+
+ load_interfaces();
+ get_myname(*myname?NULL:myname,NULL);
strupper(myname);
if (tar_type) {
@@ -4333,9 +4547,9 @@ int main(int argc,char *argv[])
sleep(1);
browse_host(True);
}
- if (!list_servers()) {
+ if (!list_servers(workgroup)) {
sleep(1);
- list_servers();
+ list_servers(workgroup);
}
send_logout();
diff --git a/source/client/clientutil.c b/source/client/clientutil.c
new file mode 100644
index 00000000000..41c482196ad
--- /dev/null
+++ b/source/client/clientutil.c
@@ -0,0 +1,1029 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB client
+ Copyright (C) Andrew Tridgell 1994-1995
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifdef SYSLOG
+#undef SYSLOG
+#endif
+
+#include "includes.h"
+
+#ifndef REGISTER
+#define REGISTER 0
+#endif
+
+pstring service="";
+pstring desthost="";
+pstring myname = "";
+pstring password = "";
+pstring username="";
+pstring workgroup=WORKGROUP;
+BOOL got_pass = False;
+BOOL connect_as_printer = False;
+BOOL connect_as_ipc = False;
+
+char cryptkey[8];
+BOOL doencrypt=False;
+
+extern pstring user_socket_options;
+
+/* 30 second timeout on most commands */
+#define CLIENT_TIMEOUT (30*1000)
+#define SHORT_TIMEOUT (5*1000)
+
+int name_type = 0x20;
+
+int max_protocol = PROTOCOL_NT1;
+
+BOOL readbraw_supported = False;
+BOOL writebraw_supported = False;
+
+extern int DEBUGLEVEL;
+
+int cnum = 0;
+int pid = 0;
+int gid = 0;
+int uid = 0;
+int mid = 0;
+
+int max_xmit = BUFFER_SIZE;
+
+BOOL have_ip = False;
+
+struct in_addr dest_ip;
+
+extern int Protocol;
+
+extern int Client;
+
+
+/****************************************************************************
+setup basics in a outgoing packet
+****************************************************************************/
+void cli_setup_pkt(char *outbuf)
+{
+ SSVAL(outbuf,smb_pid,pid);
+ SSVAL(outbuf,smb_uid,uid);
+ SSVAL(outbuf,smb_mid,mid);
+ if (Protocol > PROTOCOL_CORE)
+ {
+ SCVAL(outbuf,smb_flg,0x8);
+ SSVAL(outbuf,smb_flg2,0x1);
+ }
+}
+
+/****************************************************************************
+ receive a SMB trans or trans2 response allocating the necessary memory
+ ****************************************************************************/
+BOOL cli_receive_trans_response(char *inbuf,int trans,int *data_len,
+ int *param_len, char **data,char **param)
+{
+ int total_data=0;
+ int total_param=0;
+ int this_data,this_param;
+
+ *data_len = *param_len = 0;
+
+ receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ show_msg(inbuf);
+
+ /* sanity check */
+ if (CVAL(inbuf,smb_com) != trans)
+ {
+ DEBUG(0,("Expected %s response, got command 0x%02x\n",
+ trans==SMBtrans?"SMBtrans":"SMBtrans2", CVAL(inbuf,smb_com)));
+ return(False);
+ }
+ if (CVAL(inbuf,smb_rcls) != 0)
+ return(False);
+
+ /* parse out the lengths */
+ total_data = SVAL(inbuf,smb_tdrcnt);
+ total_param = SVAL(inbuf,smb_tprcnt);
+
+ /* allocate it */
+ *data = Realloc(*data,total_data);
+ *param = Realloc(*param,total_param);
+
+ while (1)
+ {
+ this_data = SVAL(inbuf,smb_drcnt);
+ this_param = SVAL(inbuf,smb_prcnt);
+ if (this_data)
+ memcpy(*data + SVAL(inbuf,smb_drdisp),
+ smb_base(inbuf) + SVAL(inbuf,smb_droff),
+ this_data);
+ if (this_param)
+ memcpy(*param + SVAL(inbuf,smb_prdisp),
+ smb_base(inbuf) + SVAL(inbuf,smb_proff),
+ this_param);
+ *data_len += this_data;
+ *param_len += this_param;
+
+ /* parse out the total lengths again - they can shrink! */
+ total_data = SVAL(inbuf,smb_tdrcnt);
+ total_param = SVAL(inbuf,smb_tprcnt);
+
+ if (total_data <= *data_len && total_param <= *param_len)
+ break;
+
+ receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ show_msg(inbuf);
+
+ /* sanity check */
+ if (CVAL(inbuf,smb_com) != trans)
+ {
+ DEBUG(0,("Expected %s response, got command 0x%02x\n",
+ trans==SMBtrans?"SMBtrans":"SMBtrans2", CVAL(inbuf,smb_com)));
+ return(False);
+ }
+ if (CVAL(inbuf,smb_rcls) != 0)
+ return(False);
+ }
+
+ return(True);
+}
+
+/****************************************************************************
+send a session request
+****************************************************************************/
+BOOL cli_send_session_request(char *inbuf, char *outbuf)
+{
+ fstring dest;
+ char *p;
+ int len = 4;
+ /* send a session request (RFC 8002) */
+
+ strcpy(dest,desthost);
+ p = strchr(dest,'.');
+ if (p) *p = 0;
+
+ /* put in the destination name */
+ p = outbuf+len;
+ name_mangle(dest,p,name_type);
+ len += name_len(p);
+
+ /* and my name */
+ p = outbuf+len;
+ name_mangle(myname,p,0);
+ len += name_len(p);
+
+ /* setup the packet length */
+ _smb_setlen(outbuf,len);
+ CVAL(outbuf,0) = 0x81;
+
+ send_smb(Client,outbuf);
+ DEBUG(5,("Sent session request\n"));
+
+ receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+
+ if (CVAL(inbuf,0) == 0x84) /* C. Hoch 9/14/95 Start */
+ {
+ /* For information, here is the response structure.
+ * We do the byte-twiddling to for portability.
+ struct RetargetResponse{
+ unsigned char type;
+ unsigned char flags;
+ int16 length;
+ int32 ip_addr;
+ int16 port;
+ };
+ */
+ extern int Client;
+ int port = (CVAL(inbuf,8)<<8)+CVAL(inbuf,9);
+ /* SESSION RETARGET */
+ putip((char *)&dest_ip,inbuf+4);
+
+ close_sockets();
+ Client = open_socket_out(SOCK_STREAM, &dest_ip, port);
+ if (Client == -1)
+ return False;
+
+ DEBUG(5,("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(5,("max mux %d\n",SVAL(inbuf,smb_vwv3)));
+ max_vcs = SVAL(inbuf,smb_vwv4);
+ DEBUG(5,("max vcs %d\n",max_vcs));
+ DEBUG(5,("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(5,("max mux %d\n",SVAL(inbuf,smb_vwv1+1)));
+ max_vcs = SVAL(inbuf,smb_vwv2+1);
+ DEBUG(5,("max vcs %d\n",max_vcs));
+ DEBUG(5,("max raw %d\n",IVAL(inbuf,smb_vwv5+1)));
+ DEBUG(5,("capabilities 0x%x\n",IVAL(inbuf,smb_vwv9+1)));
+ }
+
+ DEBUG(5,("Sec mode %d\n",SVAL(inbuf,smb_vwv1)));
+ DEBUG(5,("max xmt %d\n",max_xmit));
+ DEBUG(5,("Got %d byte crypt key\n",crypt_len));
+ DEBUG(5,("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(5,("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(5,("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(5,("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(5,("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(5,("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(5,("Connected\n"));
+
+ set_socket_options(Client,user_socket_options);
+
+ return True;
+}
+
+/****************************************************************************
+close and open the connection again
+****************************************************************************/
+BOOL cli_reopen_connection(char *inbuf,char *outbuf)
+{
+ static int open_count=0;
+
+ open_count++;
+
+ if (open_count>5) return(False);
+
+ DEBUG(1,("Trying to re-open connection\n"));
+
+ set_message(outbuf,0,0,True);
+ SCVAL(outbuf,smb_com,SMBtdis);
+ SSVAL(outbuf,smb_tid,cnum);
+ cli_setup_pkt(outbuf);
+
+ send_smb(Client,outbuf);
+ receive_smb(Client,inbuf,SHORT_TIMEOUT);
+
+ close_sockets();
+ if (!cli_open_sockets(0)) return(False);
+
+ return(cli_send_login(inbuf,outbuf,True,True));
+}
+
+/* error code stuff - put together by Merik Karman
+ merik@blackadder.dsh.oz.au */
+
+typedef struct
+{
+ char *name;
+ int code;
+ char *message;
+} err_code_struct;
+
+/* Dos Error Messages */
+err_code_struct dos_msgs[] = {
+ {"ERRbadfunc",1,"Invalid function."},
+ {"ERRbadfile",2,"File not found."},
+ {"ERRbadpath",3,"Directory invalid."},
+ {"ERRnofids",4,"No file descriptors available"},
+ {"ERRnoaccess",5,"Access denied."},
+ {"ERRbadfid",6,"Invalid file handle."},
+ {"ERRbadmcb",7,"Memory control blocks destroyed."},
+ {"ERRnomem",8,"Insufficient server memory to perform the requested function."},
+ {"ERRbadmem",9,"Invalid memory block address."},
+ {"ERRbadenv",10,"Invalid environment."},
+ {"ERRbadformat",11,"Invalid format."},
+ {"ERRbadaccess",12,"Invalid open mode."},
+ {"ERRbaddata",13,"Invalid data."},
+ {"ERR",14,"reserved."},
+ {"ERRbaddrive",15,"Invalid drive specified."},
+ {"ERRremcd",16,"A Delete Directory request attempted to remove the server's current directory."},
+ {"ERRdiffdevice",17,"Not same device."},
+ {"ERRnofiles",18,"A File Search command can find no more files matching the specified criteria."},
+ {"ERRbadshare",32,"The sharing mode specified for an Open conflicts with existing FIDs on the file."},
+ {"ERRlock",33,"A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."},
+ {"ERRfilexists",80,"The file named in a Create Directory, Make New File or Link request already exists."},
+ {"ERRbadpipe",230,"Pipe invalid."},
+ {"ERRpipebusy",231,"All instances of the requested pipe are busy."},
+ {"ERRpipeclosing",232,"Pipe close in progress."},
+ {"ERRnotconnected",233,"No process on other end of pipe."},
+ {"ERRmoredata",234,"There is more data to be returned."},
+ {NULL,-1,NULL}};
+
+/* Server Error Messages */
+err_code_struct server_msgs[] = {
+ {"ERRerror",1,"Non-specific error code."},
+ {"ERRbadpw",2,"Bad password - name/password pair in a Tree Connect or Session Setup are invalid."},
+ {"ERRbadtype",3,"reserved."},
+ {"ERRaccess",4,"The requester does not have the necessary access rights within the specified context for the requested function. The context is defined by the TID or the UID."},
+ {"ERRinvnid",5,"The tree ID (TID) specified in a command was invalid."},
+ {"ERRinvnetname",6,"Invalid network name in tree connect."},
+ {"ERRinvdevice",7,"Invalid device - printer request made to non-printer connection or non-printer request made to printer connection."},
+ {"ERRqfull",49,"Print queue full (files) -- returned by open print file."},
+ {"ERRqtoobig",50,"Print queue full -- no space."},
+ {"ERRqeof",51,"EOF on print queue dump."},
+ {"ERRinvpfid",52,"Invalid print file FID."},
+ {"ERRsmbcmd",64,"The server did not recognize the command received."},
+ {"ERRsrverror",65,"The server encountered an internal error, e.g., system file unavailable."},
+ {"ERRfilespecs",67,"The file handle (FID) and pathname parameters contained an invalid combination of values."},
+ {"ERRreserved",68,"reserved."},
+ {"ERRbadpermits",69,"The access permissions specified for a file or directory are not a valid combination. The server cannot set the requested attribute."},
+ {"ERRreserved",70,"reserved."},
+ {"ERRsetattrmode",71,"The attribute mode in the Set File Attribute request is invalid."},
+ {"ERRpaused",81,"Server is paused."},
+ {"ERRmsgoff",82,"Not receiving messages."},
+ {"ERRnoroom",83,"No room to buffer message."},
+ {"ERRrmuns",87,"Too many remote user names."},
+ {"ERRtimeout",88,"Operation timed out."},
+ {"ERRnoresource",89,"No resources currently available for request."},
+ {"ERRtoomanyuids",90,"Too many UIDs active on this session."},
+ {"ERRbaduid",91,"The UID is not known as a valid ID on this session."},
+ {"ERRusempx",250,"Temp unable to support Raw, use MPX mode."},
+ {"ERRusestd",251,"Temp unable to support Raw, use standard read/write."},
+ {"ERRcontmpx",252,"Continue in MPX mode."},
+ {"ERRreserved",253,"reserved."},
+ {"ERRreserved",254,"reserved."},
+ {"ERRnosupport",0xFFFF,"Function not supported."},
+ {NULL,-1,NULL}};
+
+/* Hard Error Messages */
+err_code_struct hard_msgs[] = {
+ {"ERRnowrite",19,"Attempt to write on write-protected diskette."},
+ {"ERRbadunit",20,"Unknown unit."},
+ {"ERRnotready",21,"Drive not ready."},
+ {"ERRbadcmd",22,"Unknown command."},
+ {"ERRdata",23,"Data error (CRC)."},
+ {"ERRbadreq",24,"Bad request structure length."},
+ {"ERRseek",25 ,"Seek error."},
+ {"ERRbadmedia",26,"Unknown media type."},
+ {"ERRbadsector",27,"Sector not found."},
+ {"ERRnopaper",28,"Printer out of paper."},
+ {"ERRwrite",29,"Write fault."},
+ {"ERRread",30,"Read fault."},
+ {"ERRgeneral",31,"General failure."},
+ {"ERRbadshare",32,"A open conflicts with an existing open."},
+ {"ERRlock",33,"A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."},
+ {"ERRwrongdisk",34,"The wrong disk was found in a drive."},
+ {"ERRFCBUnavail",35,"No FCBs are available to process request."},
+ {"ERRsharebufexc",36,"A sharing buffer has been exceeded."},
+ {NULL,-1,NULL}};
+
+
+struct
+{
+ int code;
+ char *class;
+ err_code_struct *err_msgs;
+} err_classes[] = {
+ {0,"SUCCESS",NULL},
+ {0x01,"ERRDOS",dos_msgs},
+ {0x02,"ERRSRV",server_msgs},
+ {0x03,"ERRHRD",hard_msgs},
+ {0x04,"ERRXOS",NULL},
+ {0xE1,"ERRRMX1",NULL},
+ {0xE2,"ERRRMX2",NULL},
+ {0xE3,"ERRRMX3",NULL},
+ {0xFF,"ERRCMD",NULL},
+ {-1,NULL,NULL}};
+
+
+/****************************************************************************
+return a SMB error string from a SMB buffer
+****************************************************************************/
+char *smb_errstr(char *inbuf)
+{
+ static pstring ret;
+ int class = CVAL(inbuf,smb_rcls);
+ int num = SVAL(inbuf,smb_err);
+ int i,j;
+
+ for (i=0;err_classes[i].class;i++)
+ if (err_classes[i].code == class)
+ {
+ if (err_classes[i].err_msgs)
+ {
+ err_code_struct *err = err_classes[i].err_msgs;
+ for (j=0;err[j].name;j++)
+ if (num == err[j].code)
+ {
+ if (DEBUGLEVEL > 0)
+ sprintf(ret,"%s - %s (%s)",err_classes[i].class,
+ err[j].name,err[j].message);
+ else
+ sprintf(ret,"%s - %s",err_classes[i].class,err[j].name);
+ return ret;
+ }
+ }
+
+ sprintf(ret,"%s - %d",err_classes[i].class,num);
+ return ret;
+ }
+
+ sprintf(ret,"ERROR: Unknown error (%d,%d)",class,num);
+ return(ret);
+}
diff --git a/source/client/clitar.c b/source/client/clitar.c
index 1433ec59412..a4c1f00adf3 100644
--- a/source/client/clitar.c
+++ b/source/client/clitar.c
@@ -23,12 +23,6 @@
#include "includes.h"
#include "clitar.h"
-extern void setup_pkt(char *outbuf);
-extern BOOL reopen_connection(char *inbuf,char *outbuf);
-extern void do_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir);
-
-int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind);
-
extern BOOL recurse;
#define SEPARATORS " \t\n\r"
@@ -81,10 +75,7 @@ static void dozerobuf();
static void dotareof();
static void initarbuf();
static int do_setrattr();
-void cmd_tar();
-int process_tar();
-char **toktocliplist();
-int clipfind();
+
/* restore functions */
static long readtarheader();
static long unoct();
@@ -591,7 +582,7 @@ static BOOL smbshut(file_info finfo, int fnum, char *inbuf, char *outbuf)
put_dos_date3(outbuf,smb_vwv1,finfo.mtime);
DEBUG(3,("Setting date to %s (0x%X)",
- asctime(LocalTime(&finfo.mtime,GMT_TO_LOCAL)),
+ asctime(LocalTime(&finfo.mtime)),
finfo.mtime));
send_smb(Client,outbuf);
@@ -1492,7 +1483,7 @@ void cmd_setmode(void)
return;
}
-DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
+ DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
(void) do_setrattr(fname, attra[ATTRSET], ATTRSET);
(void) do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
}
@@ -1655,7 +1646,7 @@ int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
if (sys_stat(argv[Optind], &stbuf) == 0) {
newer_than = stbuf.st_mtime;
DEBUG(1,("Getting files newer than %s",
- asctime(LocalTime(&newer_than,GMT_TO_LOCAL))));
+ asctime(LocalTime(&newer_than))));
Optind++;
} else {
DEBUG(0,("Error setting newer-than time\n"));
diff --git a/source/include/byteorder.h b/source/include/byteorder.h
index 899cd6c4991..51f368e61b5 100644
--- a/source/include/byteorder.h
+++ b/source/include/byteorder.h
@@ -22,6 +22,70 @@
/*
This file implements macros for machine independent short and
int manipulation
+
+Here is a description of this file that I emailed to the samba list once:
+
+> I am confused about the way that byteorder.h works in Samba. I have
+> looked at it, and I would have thought that you might make a distinction
+> between LE and BE machines, but you only seem to distinguish between 386
+> and all other architectures.
+>
+> Can you give me a clue?
+
+sure.
+
+The distinction between 386 and other architectures is only there as
+an optimisation. You can take it out completely and it will make no
+difference. The routines (macros) in byteorder.h are totally byteorder
+independent. The 386 optimsation just takes advantage of the fact that
+the x86 processors don't care about alignment, so we don't have to
+align ints on int boundaries etc. If there are other processors out
+there that aren't alignment sensitive then you could also define
+CAREFUL_ALIGNMENT=0 on those processors as well.
+
+Ok, now to the macros themselves. I'll take a simple example, say we
+want to extract a 2 byte integer from a SMB packet and put it into a
+type called uint16 that is in the local machines byte order, and you
+want to do it with only the assumption that uint16 is _at_least_ 16
+bits long (this last condition is very important for architectures
+that don't have any int types that are 2 bytes long)
+
+You do this:
+
+#define CVAL(buf,pos) (((unsigned char *)(buf))[pos])
+#define PVAL(buf,pos) ((unsigned)CVAL(buf,pos))
+#define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
+
+then to extract a uint16 value at offset 25 in a buffer you do this:
+
+char *buffer = foo_bar();
+uint16 xx = SVAL(buffer,25);
+
+We are using the byteoder independence of the ANSI C bitshifts to do
+the work. A good optimising compiler should turn this into efficient
+code, especially if it happens to have the right byteorder :-)
+
+I know these macros can be made a bit tidier by removing some of the
+casts, but you need to look at byteorder.h as a whole to see the
+reasoning behind them. byteorder.h defines the following macros:
+
+SVAL(buf,pos) - extract a 2 byte SMB value
+IVAL(buf,pos) - extract a 4 byte SMB value
+SVALS(buf,pos) signed version of SVAL()
+IVALS(buf,pos) signed version of IVAL()
+
+SSVAL(buf,pos,val) - put a 2 byte SMB value into a buffer
+SIVAL(buf,pos,val) - put a 4 byte SMB value into a buffer
+SSVALS(buf,pos,val) - signed version of SSVAL()
+SIVALS(buf,pos,val) - signed version of SIVAL()
+
+RSVAL(buf,pos) - like SVAL() but for NMB byte ordering
+RIVAL(buf,pos) - like IVAL() but for NMB byte ordering
+RSSVAL(buf,pos,val) - like SSVAL() but for NMB ordering
+RSIVAL(buf,pos,val) - like SIVAL() but for NMB ordering
+
+it also defines lots of intermediate macros, just ignore those :-)
+
*/
#undef CAREFUL_ALIGNMENT
diff --git a/source/include/charset.h b/source/include/charset.h
index 7091732223a..14b6ec2020f 100644
--- a/source/include/charset.h
+++ b/source/include/charset.h
@@ -57,5 +57,9 @@ extern void charset_initialise(void);
#define islower(c) (((char)(c)) != toupper(c))
#define isdoschar(c) (dos_char_map[(char)(c)] != 0)
#define isspace(c) ((c)==' ' || (c) == '\t')
+
+/* this is used to determine if a character is safe to use in
+ something that may be put on a command line */
+#define issafe(c) (isalnum(c) || strchr("-._",c))
#endif
diff --git a/source/include/includes.h b/source/include/includes.h
index cc2bbbfad7c..bcf79ac79a3 100644
--- a/source/include/includes.h
+++ b/source/include/includes.h
@@ -198,27 +198,6 @@
#include <shadow.h>
#endif
-/* this might be different on different systems */
-#ifdef QUOTAS
-#ifdef LINUX
-#ifdef __KERNEL__
-#undef __KERNEL__
-#include <sys/quota.h>
-#define __KERNEL__
-#else
-#include <sys/quota.h>
-#endif
-#include <mntent.h>
-#else
-#include <sys/quota.h>
-#ifndef CRAY
-#include <devnm.h>
-#else
-#include <mntent.h>
-#endif
-#endif
-#endif
-
#ifdef SYSLOG
#include <syslog.h>
#endif
@@ -244,6 +223,10 @@ Here come some platform specific sections
#define USE_SETSID
#define HAVE_BZERO
#define HAVE_MEMMOVE
+#define USE_SIGBLOCK
+#if _LINUX_C_LIB_VERSION_MAJOR >= 5
+#define USE_SETFS
+#endif
#ifdef SHADOW_PWD
#ifndef crypt
#define crypt pw_encrypt
@@ -273,6 +256,7 @@ typedef unsigned short mode_t;
#endif
#define REPLACE_GETPASS
#define BSD_TERMIO
+#define USE_SIGBLOCK
#endif
@@ -306,6 +290,7 @@ extern int innetgr (const char *, const char *, const char *, const char *);
#define USE_GETCWD
#define USE_SETSID
#define REPLACE_GETPASS
+#define USE_SIGBLOCK
#endif
@@ -481,7 +466,6 @@ char *mktemp(char *); /* No standard include */
#include <netinet/ip.h>
#define SIGNAL_CAST (void (*)())
#define USE_DIRECT
-#define REPLACE_INNETGR
#endif
@@ -498,8 +482,11 @@ char *mktemp(char *); /* No standard include */
#include <netinet/tcp.h>
#define SYSV
#define USE_WAITPID
+#define USE_SIGBLOCK
#define SIGNAL_CAST (void (*)())
#define DEFAULT_PRINTING PRINT_AIX
+/* we undef this because sys/param.h is broken in aix. uggh. */
+#undef MAXHOSTNAMELEN
#endif
@@ -546,8 +533,39 @@ char *mktemp(char *); /* No standard include */
#define NO_EID
#define STATFS4
#define USE_DIRECT
+#ifdef PTX4
+#undef USE_DIRECT
+#endif
#endif
+
+
+#ifdef SEQUENT_PTX4
+#include <string.h>
+#include <sys/dir.h>
+#include <dirent.h>
+#include <sys/statfs.h>
+#include <sys/statvfs.h>
+#include <sys/vfs.h>
+#include <fcntl.h>
+#include <sys/sockio.h>
+#include <netinet/tcp.h>
+#include <stropts.h>
+#include <termios.h>
+#define SYSV
+#define USE_WAITPID
+#define SIGNAL_CAST (void (*)(int))
+#define USE_STATVFS
+#define USE_GETCWD
+#ifndef seteuid
+#define seteuid(uid) setreuid(-1,uid)
+#endif
+#ifndef setegid
+#define setegid(gid) setregid(-1,gid)
+#endif
+#endif
+
+
#ifdef NEXT2
#include <sys/types.h>
#include <strings.h>
@@ -575,6 +593,7 @@ char *mktemp(char *); /* No standard include */
#define mode_t int
#define GID_TYPE int
#define gid_t int
+#define pid_t int
#define SIGNAL_CAST (void (*)(int))
#define WAIT3_CAST1 (union wait *)
#define HAVE_GMTOFF
@@ -734,7 +753,6 @@ char *strdup (char *);
#endif /* DNIX */
#ifdef CONVEX
-#define SIGNAL_CAST (void (*)(int))
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <dirent.h>
@@ -891,10 +909,6 @@ extern char *getsmbpass(char *);
#define FD_SETSIZE 255
#endif
-#ifndef MAXINT
-#define MAXINT ((((unsigned)1)<<(sizeof(int)*8-1))-1)
-#endif
-
#ifndef __STDC__
#define const
#endif
@@ -977,10 +991,9 @@ 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"
-#endif
#include "kanji.h"
#include "charset.h"
diff --git a/source/include/local.h b/source/include/local.h
index 2775453e150..5a577909e14 100644
--- a/source/include/local.h
+++ b/source/include/local.h
@@ -53,17 +53,6 @@
/* this is where browse lists are kept in the lock dir */
#define SERVER_LIST "browse.dat"
-/* the print command on the server, %s is replaced with the filename */
-/* note that the -r removes the file after printing - you'll run out */
-/* of disk pretty quickly if you don't. This command is only used as */
-/* the default - it can be overridden in the configuration file. */
-#define PRINT_COMMAND "lpr -r %s"
-
-/* the lpq command on the server. the printername is passed as an argument */
-#ifndef LPQ_COMMAND
-#define LPQ_COMMAND "lpq -P"
-#endif
-
/* shall guest entries in printer queues get changed to user entries,
so they can be deleted using the windows print manager? */
#define LPQ_GUEST_TO_USER
@@ -83,12 +72,6 @@
manager window? */
#define FSTYPE_STRING "Samba"
-/* we have two time standards - local and GMT. This will try to sort them out.
- */
-
-#define LOCAL_TO_GMT 1
-#define GMT_TO_LOCAL (-1)
-
/* do you want smbd to send a 1 byte packet to nmbd to trigger it to start
when smbd starts? */
#ifndef PRIME_NMBD
@@ -136,7 +119,7 @@
#define IDLE_CLOSED_TIMEOUT (60)
#define DPTR_IDLE_TIMEOUT (120)
#define SMBD_SELECT_LOOP (10)
-#define NMBD_SELECT_LOOP (10)
+#define NMBD_SELECT_LOOP (2)
#define BROWSE_INTERVAL (60)
#define REGISTRATION_INTERVAL (10*60)
#define NMBD_INETD_TIMEOUT (120)
@@ -163,5 +146,8 @@
/* shall we support browse requests via a FIFO to nmbd? */
#define ENABLE_FIFO 1
+/* keep the password server open, this uses up a aocket, but is needed
+ by many apps */
+#define KEEP_PASSWORD_SERVER_OPEN 1
#endif
diff --git a/source/include/nameserv.h b/source/include/nameserv.h
index 168dd4ba866..582378e1839 100644
--- a/source/include/nameserv.h
+++ b/source/include/nameserv.h
@@ -20,16 +20,99 @@
*/
-#define MAX_DGRAM_SIZE 576
+#define GET_TTL(ttl) ((ttl)?MIN(ttl,lp_max_ttl()):lp_max_ttl())
+
+/* NTAS uses 2, NT uses 1, WfWg uses 0 */
+#define MAINTAIN_LIST 2
+#define ELECTION_VERSION 1
+
+#define MAX_DGRAM_SIZE (576) /* tcp/ip datagram limit is 576 bytes */
#define MIN_DGRAM_SIZE 12
-#define NMB_PORT 137
-#define DGRAM_PORT 138
-#define SMB_PORT 139
+#define NMB_QUERY 0x20
+#define NMB_STATUS 0x21
+
+#define NMB_REG 0x05 /* see rfc1002.txt 4.2.2,3,5,6,7,8 */
+#define NMB_REG_REFRESH 0x09 /* see rfc1002.txt 4.2.4 */
+#define NMB_REL 0x06 /* see rfc1002.txt 4.2.9,10,11 */
+#define NMB_WAIT_ACK 0x07 /* see rfc1002.txt 4.2.16 */
+/* XXXX what about all the other types?? 0x1, 0x2, 0x3, 0x4, 0x8? */
+
+#define FIND_SELF 0x01
+#define FIND_WINS 0x02
+#define FIND_LOCAL 0x04
+
+/* NetBIOS flags */
+#define NB_GROUP 0x80
+#define NB_PERM 0x02
+#define NB_ACTIVE 0x04
+#define NB_CONFL 0x08
+#define NB_DEREG 0x10
+#define NB_BFLAG 0x00 /* broadcast node type */
+#define NB_PFLAG 0x20 /* point-to-point node type */
+#define NB_MFLAG 0x40 /* mixed bcast & p-p node type */
+#define NB_HFLAG 0x60 /* microsoft 'hybrid' node type */
+#define NB_FLGMSK 0x60
+
+#define REFRESH_TIME (15*60)
+#define NAME_POLL_REFRESH_TIME (5*60)
+#define NAME_POLL_INTERVAL 15
+
+/* NetBIOS flag identifier */
+#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_HFLAG(p) (((p) & NB_FLGMSK) == NB_HFLAG)
+
+/* server type identifiers */
+#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)
-enum name_source {LMHOSTS, REGISTER, SELF, DNS, DNSFAIL};
+/* microsoft browser NetBIOS name */
+#define MSBROWSE "\001\002__MSBROWSE__\002"
+
+/* mail slots */
+#define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE"
+#define NET_LOGON_MAILSLOT "\\MAILSLOT\\NET\\NETLOGON"
+
+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 master_state
+{
+ MST_NONE,
+ MST_WON,
+ MST_MSB,
+ MST_BROWSER,
+ MST_DOMAIN_NONE,
+ MST_DOMAIN_MEM,
+ MST_DOMAIN_TST,
+ MST_DOMAIN
+};
+
+enum state_type
+{
+ NAME_STATUS_DOM_SRV_CHK,
+ NAME_STATUS_SRV_CHK,
+ NAME_REGISTER_CHALLENGE,
+ NAME_REGISTER,
+ NAME_RELEASE,
+ NAME_QUERY_CONFIRM,
+ NAME_QUERY_ANNOUNCE_HOST,
+ NAME_QUERY_SYNC_LOCAL,
+ NAME_QUERY_SYNC_REMOTE,
+ NAME_QUERY_DOM_SRV_CHK,
+ NAME_QUERY_SRV_CHK,
+ NAME_QUERY_FIND_MST,
+ NAME_QUERY_MST_CHK
+};
/* a netbios name structure */
struct nmb_name {
@@ -43,35 +126,142 @@ struct name_record
{
struct name_record *next;
struct name_record *prev;
- struct nmb_name name;
- time_t death_time;
- struct in_addr ip;
- BOOL unique;
- enum name_source source;
+
+ struct nmb_name name; /* the netbios name */
+ struct in_addr ip; /* ip address of host that owns this name */
+ int nb_flags; /* netbios flags */
+
+ enum name_source source; /* where the name came from */
+
+ time_t death_time; /* time record must be removed (do not remove if 0) */
+ time_t refresh_time; /* time record should be refreshed */
};
-/* 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;
+ BOOL local;
};
-/* 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;
+
+ /* stage of development from non-master to master browser / domain master */
+ enum master_state state;
+
+ /* 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;
+};
+
+/* initiated name queries recorded in this list to track any responses... */
+/* sadly, we need to group everything together. i suppose that if this
+ gets unwieldy, then a union ought to be considered. oh for c++... */
+struct response_record
+{
+ struct response_record *next;
+ struct response_record *prev;
+
+ uint16 response_id;
+ enum state_type state;
+
+ int fd;
+ int quest_type;
+ struct nmb_name name;
+ int nb_flags;
+ time_t ttl;
+
+ int server_type;
+ fstring my_name;
+ fstring my_comment;
+
+ BOOL bcast;
+ BOOL recurse;
+ struct in_addr send_ip;
+ struct in_addr reply_to_ip;
+
+ int num_msgs;
+
+ time_t repeat_time;
+ time_t repeat_interval;
+ int repeat_count;
+};
+
+/* a subnet structure. it contains a list of workgroups and netbios names*/
+
+/* note that a subnet of 255.255.255.255 contains all the WINS netbios names.
+ all communication from such nodes are on a non-broadcast basis: they
+ are point-to-point (P nodes) or mixed point-to-point and broadcast
+ (M nodes). M nodes use point-to-point as a preference, and will use
+ broadcasting for certain activities, or will resort to broadcasting as a
+ last resort, if the WINS server fails (users of wfwg will notice that their
+ machine often freezes for 30 seconds at a time intermittently, if the WINS
+ server is down).
+
+ B nodes will have their own, totally separate subnet record, with their
+ own netbios name set. these do NOT interact with other subnet records'
+ netbios names, INCLUDING the WINS one (with an ip "address", so called,
+ of 255.255.255.255)
+
+ there is a separate response list for each subnet record. in the case of
+ the 255.255.255.255 subnet record (WINS), the WINS server will be able to
+ use this to poll (infrequently!) each of its entries, to ensure that the
+ names are still in use.
+ XXXX this polling is a planned feature for a really over-cautious WINS server
+*/
+
+struct subnet_record
+{
+ struct subnet_record *next;
+ struct subnet_record *prev;
+
+ struct work_record *workgrouplist; /* list of workgroups */
+ struct name_record *namelist; /* list of netbios names */
+ struct response_record *responselist; /* list of responses expected */
+
+ 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;
@@ -154,31 +344,32 @@ 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;
-};
+/* ids for netbios packet types */
+#define ANN_HostAnnouncement 1
+#define ANN_AnnouncementRequest 2
+#define ANN_Election 8
+#define ANN_GetBackupListReq 9
+#define ANN_GetBackupListResp 10
+#define ANN_BecomeBackup 11
+#define ANN_DomainAnnouncement 12
+#define ANN_MasterAnnouncement 13
+#define ANN_ResetBrowserState 14
+#define ANN_LocalMasterAnnouncement 15
+
+
+/* broadcast packet announcement intervals, in minutes */
+
+/* search for master browsers of workgroups samba knows about,
+ except default */
+#define CHECK_TIME_MST_BROWSE 5
+
+/* request backup browser announcements from other servers */
+#define CHECK_TIME_ANNOUNCE_BACKUP 15
+
+/* request host announcements from other servers: min and max of interval */
+#define CHECK_TIME_MIN_HOST_ANNCE 3
+#define CHECK_TIME_MAX_HOST_ANNCE 12
+/* announce as master to WINS server and any Primary Domain Controllers */
+#define CHECK_TIME_MST_ANNOUNCE 15
-/* prototypes */
-void free_nmb_packet(struct nmb_packet *nmb);
-void free_packet(struct packet_struct *packet);
-struct packet_struct *read_packet(int fd,enum packet_type packet_type);
-BOOL send_packet(struct packet_struct *p);
-struct packet_struct *receive_packet(int fd,enum packet_type type,int timeout);
-void make_nmb_name(struct nmb_name *n,char *name,int type,char *this_scope);
-BOOL name_query(int fd,char *name,int name_type,
- BOOL bcast,BOOL recurse,
- struct in_addr to_ip, struct in_addr *ip,void (*fn)());
-BOOL name_status(int fd,char *name,int name_type,BOOL recurse,
- struct in_addr to_ip,char *master,char *rname,
- void (*fn)());
-BOOL send_mailslot_reply(char *mailslot,int fd,char *buf,int len,
- char *srcname,char *dstname,
- int src_type,int dest_type,
- struct in_addr dest_ip,
- struct in_addr src_ip);
-char *namestr(struct nmb_name *n);
diff --git a/source/include/proto.h b/source/include/proto.h
new file mode 100644
index 00000000000..4d1c4bf6f97
--- /dev/null
+++ b/source/include/proto.h
@@ -0,0 +1,894 @@
+/* This file is automatically generated with "make proto". DO NOT EDIT */
+
+
+/*The following definitions come from access.c */
+
+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);
+
+/*The following definitions come from charcnv.c */
+
+char *unix2dos_format(char *str,BOOL overwrite);
+char *dos2unix_format(char *str, BOOL overwrite);
+int interpret_character_set(char *str, int def);
+
+/*The following definitions come from charset.c */
+
+void charset_initialise(void);
+void add_char_string(char *s);
+
+/*The following definitions come from chgpasswd.c */
+
+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);
+
+/*The following definitions come from client.c */
+
+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);
+
+/*The following definitions come from clientutil.c */
+
+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);
+
+/*The following definitions come from clitar.c */
+
+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);
+
+/*The following definitions come from dir.c */
+
+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 dir_check_ftype(int cnum,int mode,struct stat *st,int dirtype);
+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);
+
+/*The following definitions come from fault.c */
+
+void fault_setup(void (*fn)());
+
+/*The following definitions come from getsmbpass.c */
+
+char *getsmbpass(char *prompt) ;
+
+/*The following definitions come from interface.c */
+
+void load_interfaces(void);
+void iface_set_default(char *ip,char *bcast,char *nmask);
+BOOL ismyip(struct in_addr ip);
+BOOL ismybcast(struct in_addr bcast);
+int iface_count(void);
+struct in_addr *iface_n_ip(int n);
+struct in_addr *iface_bcast(struct in_addr ip);
+struct in_addr *iface_nmask(struct in_addr ip);
+struct in_addr *iface_ip(struct in_addr ip);
+
+/*The following definitions come from ipc.c */
+
+int reply_trans(char *inbuf,char *outbuf);
+
+/*The following definitions come from kanji.c */
+
+int interpret_coding_system(char *str, int def);
+
+/*The following definitions come from loadparm.c */
+
+char *lp_string(char *s);
+char *lp_logfile(void);
+char *lp_smbrun(void);
+char *lp_configfile(void);
+char *lp_smb_passwd_file(void);
+char *lp_serverstring(void);
+char *lp_printcapname(void);
+char *lp_lockdir(void);
+char *lp_rootdir(void);
+char *lp_defaultservice(void);
+char *lp_msg_command(void);
+char *lp_dfree_command(void);
+char *lp_hosts_equiv(void);
+char *lp_auto_services(void);
+char *lp_passwd_program(void);
+char *lp_passwd_chat(void);
+char *lp_passwordserver(void);
+char *lp_workgroup(void);
+char *lp_domain_controller(void);
+char *lp_username_map(void);
+char *lp_character_set(void);
+char *lp_logon_script(void);
+char *lp_wins_server(void);
+char *lp_interfaces(void);
+BOOL lp_wins_support(void);
+BOOL lp_wins_proxy(void);
+BOOL lp_domain_master(void);
+BOOL lp_domain_logons(void);
+BOOL lp_preferred_master(void);
+BOOL lp_load_printers(void);
+BOOL lp_use_rhosts(void);
+BOOL lp_getwdcache(void);
+BOOL lp_readprediction(void);
+BOOL lp_readbmpx(void);
+BOOL lp_readraw(void);
+BOOL lp_writeraw(void);
+BOOL lp_null_passwords(void);
+BOOL lp_strip_dot(void);
+BOOL lp_encrypted_passwords(void);
+BOOL lp_syslog_only(void);
+BOOL lp_browse_list(void);
+int lp_os_level(void);
+int lp_max_ttl(void);
+int lp_max_log_size(void);
+int lp_mangledstack(void);
+int lp_maxxmit(void);
+int lp_maxmux(void);
+int lp_maxpacket(void);
+int lp_keepalive(void);
+int lp_passwordlevel(void);
+int lp_readsize(void);
+int lp_deadtime(void);
+int lp_maxprotocol(void);
+int lp_security(void);
+int lp_printing(void);
+int lp_maxdisksize(void);
+int lp_lpqcachetime(void);
+int lp_syslog(void);
+char *lp_preexec(int );
+char *lp_postexec(int );
+char *lp_rootpreexec(int );
+char *lp_rootpostexec(int );
+char *lp_servicename(int );
+char *lp_pathname(int );
+char *lp_dontdescend(int );
+char *lp_username(int );
+char *lp_guestaccount(int );
+char *lp_invalid_users(int );
+char *lp_valid_users(int );
+char *lp_admin_users(int );
+char *lp_printcommand(int );
+char *lp_lpqcommand(int );
+char *lp_lprmcommand(int );
+char *lp_lppausecommand(int );
+char *lp_lpresumecommand(int );
+char *lp_printername(int );
+char *lp_printerdriver(int );
+char *lp_hostsallow(int );
+char *lp_hostsdeny(int );
+char *lp_magicscript(int );
+char *lp_magicoutput(int );
+char *lp_comment(int );
+char *lp_force_user(int );
+char *lp_force_group(int );
+char *lp_readlist(int );
+char *lp_writelist(int );
+char *lp_volume(int );
+char *lp_mangled_map(int );
+BOOL lp_alternate_permissions(int );
+BOOL lp_revalidate(int );
+BOOL lp_casesensitive(int );
+BOOL lp_preservecase(int );
+BOOL lp_shortpreservecase(int );
+BOOL lp_casemangle(int );
+BOOL lp_status(int );
+BOOL lp_hide_dot_files(int );
+BOOL lp_browseable(int );
+BOOL lp_readonly(int );
+BOOL lp_no_set_dir(int );
+BOOL lp_guest_ok(int );
+BOOL lp_guest_only(int );
+BOOL lp_print_ok(int );
+BOOL lp_postscript(int );
+BOOL lp_map_hidden(int );
+BOOL lp_map_archive(int );
+BOOL lp_locking(int );
+BOOL lp_strict_locking(int );
+BOOL lp_share_modes(int );
+BOOL lp_onlyuser(int );
+BOOL lp_manglednames(int );
+BOOL lp_widelinks(int );
+BOOL lp_syncalways(int );
+BOOL lp_map_system(int );
+BOOL lp_delete_readonly(int );
+int lp_create_mode(int );
+int lp_max_connections(int );
+int lp_defaultcase(int );
+int lp_minprintspace(int );
+char lp_magicchar(int );
+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);
+
+/*The following definitions come from locking.c */
+
+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_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);
+
+/*The following definitions come from mangle.c */
+
+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);
+
+/*The following definitions come from md4.c */
+
+
+/*The following definitions come from message.c */
+
+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);
+
+/*The following definitions come from nameannounce.c */
+
+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 sync_server(enum state_type state, char *serv_name, char *work_name,
+ int name_type,
+ struct in_addr ip);
+void announce_backup(void);
+void do_announce_host(int command,
+ char *from_name, int from_type, struct in_addr from_ip,
+ char *to_name , int to_type , struct in_addr to_ip,
+ time_t announce_interval,
+ char *server_name, int server_type, char *server_comment);
+void remove_my_servers(void);
+void announce_server(struct subnet_record *d, struct work_record *work,
+ char *name, char *comment, time_t ttl, int server_type);
+void announce_host(void);
+void announce_master(void);
+
+/*The following definitions come from namebrowse.c */
+
+void expire_browse_cache(time_t t);
+struct browse_cache_record *add_browser_entry(char *name, int type, char *wg,
+ time_t ttl, struct in_addr ip, BOOL local);
+void do_browser_lists(void);
+
+/*The following definitions come from namedbname.c */
+
+void set_samba_nb_type(void);
+BOOL name_equal(struct nmb_name *n1,struct nmb_name *n2);
+BOOL ms_browser_name(char *name, int type);
+void remove_name(struct subnet_record *d, struct name_record *n);
+struct name_record *find_name(struct name_record *n,
+ struct nmb_name *name,
+ int search);
+struct name_record *find_name_search(struct subnet_record **d,
+ struct nmb_name *name,
+ int search, struct in_addr ip);
+void dump_names(void);
+void load_netbios_names(void);
+void remove_netbios_name(struct subnet_record *d,
+ char *name,int type, enum name_source source,
+ struct in_addr ip);
+struct name_record *add_netbios_entry(struct subnet_record *d,
+ char *name, int type, int nb_flags,
+ int ttl, enum name_source source, struct in_addr ip,
+ BOOL new_only,BOOL wins);
+void expire_names(time_t t);
+struct name_record *search_for_name(struct subnet_record **d,
+ struct nmb_name *question,
+ struct in_addr ip, int Time, int search);
+
+/*The following definitions come from namedbresp.c */
+
+void add_response_record(struct subnet_record *d,
+ struct response_record *n);
+void remove_response_record(struct subnet_record *d,
+ struct response_record *n);
+struct response_record *make_response_queue_record(enum state_type state,
+ int id,uint16 fd,
+ int quest_type, char *name,int type, int nb_flags, time_t ttl,
+ int server_type, char *my_name, char *my_comment,
+ BOOL bcast,BOOL recurse,
+ struct in_addr send_ip, struct in_addr reply_to_ip);
+struct response_record *find_response_record(struct subnet_record **d,
+ uint16 id);
+
+/*The following definitions come from namedbserver.c */
+
+void remove_old_servers(struct work_record *work, time_t t,
+ BOOL remove_all);
+struct server_record *find_server(struct work_record *work, char *name);
+struct server_record *add_server_entry(struct subnet_record *d,
+ struct work_record *work,
+ char *name,int servertype,
+ int ttl,char *comment,
+ BOOL replace);
+void expire_servers(time_t t);
+
+/*The following definitions come from namedbsubnet.c */
+
+struct subnet_record *find_subnet(struct in_addr bcast_ip);
+struct subnet_record *find_req_subnet(struct in_addr ip, BOOL bcast);
+void add_subnet_interfaces(void);
+void add_my_subnets(char *group);
+struct subnet_record *add_subnet_entry(struct in_addr bcast_ip,
+ struct in_addr mask_ip,
+ char *name, BOOL add, BOOL lmhosts);
+void write_browse_list(void);
+
+/*The following definitions come from namedbwork.c */
+
+struct work_record *remove_workgroup(struct subnet_record *d,
+ struct work_record *work,
+ BOOL remove_all_servers);
+struct work_record *find_workgroupstruct(struct subnet_record *d,
+ fstring name, BOOL add);
+void dump_workgroups(void);
+
+/*The following definitions come from nameelect.c */
+
+void check_master_browser(void);
+void browser_gone(char *work_name, struct in_addr ip);
+void send_election(struct subnet_record *d, char *group,uint32 criterion,
+ int timeup,char *name);
+void name_unregister_work(struct subnet_record *d, char *name, int name_type);
+void name_register_work(struct subnet_record *d, char *name, int name_type,
+ int nb_flags, time_t ttl, struct in_addr ip, BOOL bcast);
+void become_master(struct subnet_record *d, struct work_record *work);
+void become_nonmaster(struct subnet_record *d, struct work_record *work,
+ int remove_type);
+void run_elections(void);
+void process_election(struct packet_struct *p,char *buf);
+BOOL check_elections(void);
+
+/*The following definitions come from namelogon.c */
+
+void process_logon_packet(struct packet_struct *p,char *buf,int len);
+
+/*The following definitions come from namepacket.c */
+
+void debug_browse_data(char *outbuf, int len);
+void initiate_netbios_packet(uint16 *id,
+ int fd,int quest_type,char *name,int name_type,
+ int nb_flags,BOOL bcast,BOOL recurse,
+ struct in_addr to_ip);
+void reply_netbios_packet(struct packet_struct *p1,int trn_id,
+ int rcode, int rcv_code, int opcode, BOOL recurse,
+ struct nmb_name *rr_name,int rr_type,int rr_class,int ttl,
+ char *data,int len);
+void queue_packet(struct packet_struct *packet);
+void run_packet_queue();
+void listen_for_packets(BOOL run_election);
+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);
+
+/*The following definitions come from namequery.c */
+
+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)());
+
+/*The following definitions come from nameresp.c */
+
+void expire_netbios_response_entries();
+struct response_record *queue_netbios_pkt_wins(struct subnet_record *d,
+ int fd,int quest_type,enum state_type state,
+ char *name,int name_type,int nb_flags, time_t ttl,
+ int server_type, char *my_name, char *my_comment,
+ BOOL bcast,BOOL recurse,
+ struct in_addr send_ip, struct in_addr reply_to_ip);
+struct response_record *queue_netbios_packet(struct subnet_record *d,
+ int fd,int quest_type,enum state_type state,char *name,
+ int name_type,int nb_flags, time_t ttl,
+ int server_type, char *my_name, char *my_comment,
+ BOOL bcast,BOOL recurse,
+ struct in_addr send_ip, struct in_addr reply_to_ip);
+
+/*The following definitions come from nameserv.c */
+
+void remove_name_entry(struct subnet_record *d, char *name,int type);
+void add_my_name_entry(struct subnet_record *d,char *name,int type,int nb_flags);
+void add_my_names(void);
+void remove_my_names();
+void refresh_my_names(time_t t);
+void query_refresh_names(void);
+
+/*The following definitions come from nameservreply.c */
+
+void add_name_respond(struct subnet_record *d, int fd, struct in_addr from_ip,
+ uint16 response_id,
+ struct nmb_name *name,
+ int nb_flags, int ttl, struct in_addr register_ip,
+ BOOL new_owner, struct in_addr reply_to_ip);
+void send_name_response(int fd, struct in_addr from_ip,
+ int name_trn_id, int opcode, BOOL success, BOOL recurse,
+ struct nmb_name *reply_name, int nb_flags, int ttl,
+ struct in_addr ip);
+void reply_name_release(struct packet_struct *p);
+void reply_name_reg(struct packet_struct *p);
+void reply_name_status(struct packet_struct *p);
+void reply_name_query(struct packet_struct *p);
+
+/*The following definitions come from nameservresp.c */
+
+void debug_state_type(int state);
+void response_netbios_packet(struct packet_struct *p);
+
+/*The following definitions come from namework.c */
+
+void reset_server(char *name, int state, struct in_addr ip);
+void tell_become_backup(void);
+BOOL same_context(struct dgram_packet *dgram);
+BOOL listening_name(struct work_record *work, struct nmb_name *n);
+BOOL listening_type(struct packet_struct *p, int command);
+void process_browse_packet(struct packet_struct *p,char *buf,int len);
+
+/*The following definitions come from nmbd.c */
+
+BOOL reload_services(BOOL test);
+
+/*The following definitions come from nmblib.c */
+
+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);
+
+/*The following definitions come from nmblookup.c */
+
+int main(int argc,char *argv[]);
+
+/*The following definitions come from nmbsync.c */
+
+char *getsmbpass(char *pass);
+void sync_browse_lists(struct subnet_record *d, struct work_record *work,
+ char *name, int nm_type, struct in_addr ip, BOOL local);
+
+/*The following definitions come from params.c */
+
+BOOL pm_process(char *pszFileName,BOOL (*sfunc)(char *),BOOL (*pfunc)(char *,char *));
+
+/*The following definitions come from password.c */
+
+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);
+
+/*The following definitions come from pcap.c */
+
+BOOL pcap_printername_ok(char *pszPrintername, char *pszPrintcapname);
+void pcap_printer_fn(void (*fn)());
+
+/*The following definitions come from predict.c */
+
+int read_predict(int fd,int offset,char *buf,char **ptr,int num);
+void do_read_prediction();
+void invalidate_read_prediction(int fd);
+
+/*The following definitions come from printing.c */
+
+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);
+
+/*The following definitions come from quotas.c */
+
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize);
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize);
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize);
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize);
+
+/*The following definitions come from replace.c */
+
+char *Strstr(char *s, char *p);
+time_t Mktime(struct tm *t);
+int InNetGr(char *group,char *host,char *user,char *dom);
+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);
+void *memcpy_wrapped(void *d,void *s,int l,char *fname,int line);
+
+/*The following definitions come from reply.c */
+
+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);
+
+/*The following definitions come from server.c */
+
+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 n);
+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);
+
+/*The following definitions come from smbencrypt.c */
+
+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);
+
+/*The following definitions come from smbpass.c */
+
+int pw_file_lock(char *name, int type, int secs);
+int pw_file_unlock(int fd);
+struct smb_passwd *get_smbpwnam(char *name);
+
+/*The following definitions come from smbpasswd.c */
+
+
+/*The following definitions come from smbrun.c */
+
+
+/*The following definitions come from status.c */
+
+void Ucrit_addUsername(pstring username);
+unsigned int Ucrit_checkUsername(pstring username);
+void Ucrit_addPid(int pid);
+unsigned int Ucrit_checkPid(int pid);
+
+/*The following definitions come from system.c */
+
+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_chmod(char *fname,int mode);
+int sys_chown(char *fname,int uid,int gid);
+int sys_chroot(char *dname);
+
+/*The following definitions come from testparm.c */
+
+
+/*The following definitions come from testprns.c */
+
+int main(int argc, char *argv[]);
+
+/*The following definitions come from time.c */
+
+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 );
+
+/*The following definitions come from trans2.c */
+
+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);
+
+/*The following definitions come from ufc.c */
+
+char *ufc_crypt(char *key,char *salt);
+
+/*The following definitions come from uid.c */
+
+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);
+
+/*The following definitions come from username.c */
+
+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);
+
+/*The following definitions come from util.c */
+
+void setup_logging(char *pname,BOOL interactive);
+void reopen_logs(void);
+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 read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out);
+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 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);
+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);
+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);
+
+/*The following definitions come from vt_mode.c */
+
+int VT_Check(char *buffer);
+int VT_Start_utmp(void);
+int VT_Stop_utmp(void);
+void VT_AtExit(void);
+void VT_SigCLD(int sig);
+void VT_SigEXIT(int sig);
+int VT_Start(void);
+int VT_Output(char *Buffer);
+int VT_Input(char *Buffer,int Size);
+void VT_Process(void);
diff --git a/source/include/smb.h b/source/include/smb.h
index b7faffa9e92..317f31b19ed 100644
--- a/source/include/smb.h
+++ b/source/include/smb.h
@@ -40,6 +40,10 @@
# define EXTERN extern
#endif
+#define NMB_PORT 137
+#define DGRAM_PORT 138
+#define SMB_PORT 139
+
#define False (0)
#define True (1)
#define BOOLSTR(b) ((b) ? "Yes" : "No")
@@ -72,6 +76,19 @@ typedef unsigned short uint16;
typedef unsigned int uint32;
#endif
+#ifndef uchar
+#define uchar unsigned char
+#endif
+#ifndef int16
+#define int16 short
+#endif
+#ifndef uint16
+#define uint16 unsigned short
+#endif
+#ifndef uint32
+#define uint32 unsigned int
+#endif
+
#define SIZEOFWORD 2
#ifndef DEF_CREATE_MASK
@@ -82,16 +99,24 @@ typedef unsigned int uint32;
#define DEFAULT_PIPE_TIMEOUT 10000000 /* Ten seconds */
#endif
+/* how long to wait for secondary SMB packets (seconds) */
+#define SMB_SECONDARY_WAIT 30
+
/* debugging code */
#ifndef SYSLOG
#define DEBUG(level,body) ((DEBUGLEVEL>=(level))?(Debug1 body):0)
#else
EXTERN int syslog_level;
-#define DEBUG(level,body) ((DEBUGLEVEL>=(level))? \
- (syslog_level = (level), Debug1 body):0)
+#define DEBUG(level,body) ((DEBUGLEVEL>=(level))? (syslog_level = (level), Debug1 body):0)
#endif
+/* this defines the error codes that receive_smb can put in smb_read_error */
+#define READ_TIMEOUT 1
+#define READ_EOF 2
+#define READ_ERROR 3
+
+
#define DIR_STRUCT_SIZE 43
/* these define all the command types recognised by the server - there
@@ -216,6 +241,24 @@ typedef char pstring[1024];
typedef char fstring[128];
typedef fstring string;
+
+struct smb_passwd {
+ int smb_userid;
+ char *smb_name;
+ unsigned char *smb_passwd; /* Null if no password */
+ unsigned char *smb_nt_passwd; /* Null if no password */
+ /* Other fields / flags may be added later */
+};
+
+
+struct current_user {
+ int cnum, id;
+ int uid, gid;
+ int ngroups;
+ gid_t *groups;
+ int *igroups;
+};
+
typedef struct
{
int size;
@@ -332,6 +375,25 @@ 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 */
+};
+
+
+/* used for network interfaces */
+struct interface
+{
+ struct interface *next;
+ struct in_addr ip;
+ struct in_addr bcast;
+ struct in_addr nmask;
+};
/* this is used for smbstatus */
struct connect_record
@@ -582,282 +644,29 @@ struct from_host {
struct sockaddr_in *sin; /* their side of the link */
};
-/* and a few prototypes */
-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);
-int DSTDiff(time_t t);
-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);
-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);
-BOOL sane_unix_date(time_t unixdate);
-time_t start_of_month(void);
-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
@@ -966,7 +775,8 @@ enum protocol_types {PROTOCOL_NONE,PROTOCOL_CORE,PROTOCOL_COREPLUS,PROTOCOL_LANM
enum security_types {SEC_SHARE,SEC_USER,SEC_SERVER};
/* printing types */
-enum printing_types {PRINT_BSD,PRINT_SYSV,PRINT_AIX,PRINT_HPUX,PRINT_QNX};
+enum printing_types {PRINT_BSD,PRINT_SYSV,PRINT_AIX,PRINT_HPUX,
+ PRINT_QNX,PRINT_PLP};
/* case handling */
diff --git a/source/include/version.h b/source/include/version.h
index 9ad8b7d44b5..891d626693c 100644
--- a/source/include/version.h
+++ b/source/include/version.h
@@ -1 +1 @@
-#define VERSION "1.9.16alpha1"
+#define VERSION "1.9.16alpha17"
diff --git a/source/internals.doc b/source/internals.doc
new file mode 100644
index 00000000000..971f2567388
--- /dev/null
+++ b/source/internals.doc
@@ -0,0 +1,212 @@
+internals.txt, 8 May 1996
+Written by David Chappell <David.Chappell@mail.trincoll.edu>.
+
+This document describes some of the internal functions which must be
+understood by anyone wishing to add features to Samba.
+
+
+
+
+
+=============================================================================
+This section describes the macros defined in byteorder.h. These macros
+are used extensively in the Samba code.
+
+-----------------------------------------------------------------------------
+CVAL(buf,pos)
+
+returns the byte at offset pos within buffer buf as an unsigned character.
+
+-----------------------------------------------------------------------------
+PVAL(buf,pos)
+
+returns the value of CVAL(buf,pos) cast to type unsigned integer.
+
+-----------------------------------------------------------------------------
+SCVAL(buf,pos,val)
+
+sets the byte at offset pos within buffer buf to value val.
+
+-----------------------------------------------------------------------------
+SVAL(buf,pos)
+
+returns the value of the unsigned short (16 bit) little-endian integer at
+offset pos within buffer buf. An integer of this type is sometimes
+refered to as "USHORT".
+
+-----------------------------------------------------------------------------
+IVAL(buf,pos)
+
+returns the value of the unsigned 32 bit little-endian integer at offset
+pos within buffer buf.
+
+-----------------------------------------------------------------------------
+SVALS(buf,pos)
+
+returns the value of the signed short (16 bit) little-endian integer at
+offset pos within buffer buf.
+
+-----------------------------------------------------------------------------
+IVALS(buf,pos)
+
+returns the value of the signed 32 bit little-endian integer at offset pos
+within buffer buf.
+
+-----------------------------------------------------------------------------
+SSVAL(buf,pos,val)
+
+sets the unsigned short (16 bit) little-endian integer at offset pos within
+buffer buf to value val.
+
+-----------------------------------------------------------------------------
+SIVAL(buf,pos,val)
+
+sets the unsigned 32 bit little-endian integer at offset pos within buffer
+buf to the value val.
+
+-----------------------------------------------------------------------------
+SSVALS(buf,pos,val)
+
+sets the short (16 bit) signed little-endian integer at offset pos within
+buffer buf to the value val.
+
+-----------------------------------------------------------------------------
+SIVALS(buf,pos,val)
+
+sets the signed 32 bit little-endian integer at offset pos withing buffer
+buf to the value val.
+
+-----------------------------------------------------------------------------
+RSVAL(buf,pos)
+
+returns the value of the unsigned short (16 bit) big-endian integer at
+offset pos within buffer buf.
+
+-----------------------------------------------------------------------------
+RIVAL(buf,pos)
+
+returns the value of the unsigned 32 bit big-endian integer at offset
+pos within buffer buf.
+
+-----------------------------------------------------------------------------
+RSSVAL(buf,pos,val)
+
+sets the value of the unsigned short (16 bit) big-endian integer at
+offset pos within buffer buf to value val.
+refered to as "USHORT".
+
+-----------------------------------------------------------------------------
+RSIVAL(buf,pos,val)
+
+sets the value of the unsigned 32 bit big-endian integer at offset
+pos within buffer buf to value val.
+
+
+
+
+
+=============================================================================
+This section describes the functions need to make a LAN Manager RPC call.
+This information had been obtained by examining the Samba code and the LAN
+Manager 2.0 API documentation. It should not be considered entirely
+reliable.
+
+-----------------------------------------------------------------------------
+call_api(int prcnt, int drcnt, int mprcnt, int mdrcnt,
+ char *param, char *data, char **rparam, char **rdata);
+
+This function is defined in client.c. It uses an SMB transaction to call a
+remote api.
+
+The parameters are as follows:
+
+prcnt: the number of bytes of parameters begin sent.
+drcnt: the number of bytes of data begin sent.
+mprcnt: the maximum number of bytes of parameters which should be returned
+mdrcnt: the maximum number of bytes of data which should be returned
+param: a pointer to the parameters to be sent.
+data: a pointer to the data to be sent.
+rparam: a pointer to a pointer which will be set to point to the returned
+ paramters. The caller of call_api() must deallocate this memory.
+rdata: a pointer to a pointer which will be set to point to the returned
+ data. The caller of call_api() must deallocate this memory.
+
+-----------------------------------------------------------------------------
+These are the parameters which you ought to send, in the order of their
+appearance in the parameter block:
+
+* An unsigned 16 bit integer API number. You should set this value with
+SSVAL(). I do not know where these numbers are described.
+
+* An ASCIIZ string describing the parameters to the API function as defined
+in the LAN Manager documentation. The first parameter, which is the server
+name, is ommited. This string is based uppon the API function as described
+in the manual, not the data which is actually passed.
+
+* An ASCIIZ string describing the data structure which ought to be returned.
+
+* Any parameters which appear in the function call, as defined in the LAN
+Manager API documentation, after the "Server" and up to and including the
+"uLevel" parameters.
+
+* An unsigned 16 bit integer which gives the size in bytes of the buffer we
+will use to receive the returned array of data structures. Presumably this
+should be the same as mdrcnt. This value should be set with SSVAL().
+
+* An ASCIIZ string describing substructures which should be returned. If no
+substructures apply, this string is of zero length.
+
+-----------------------------------------------------------------------------
+The code in client.c always calls call_api() with no data. It is unclear
+when a non-zero length data buffer would be sent.
+
+-----------------------------------------------------------------------------
+The returned parameters (pointed to by rparam), in their order of appearance
+are:
+
+* An unsigned 16 bit integer which contains the API function's return code.
+This value should be read with SVAL().
+
+* An adjustment which tells the amount by which pointers in the returned
+data should be adjusted. This value should be read with SVAL(). Basically,
+the address of the start of the returned data buffer should have the returned
+pointer value added to it and then have this value subtracted from it in
+order to obtain the currect offset into the returned data buffer.
+
+* A count of the number of elements in the array of structures returned.
+It is also possible that this may sometimes be the number of bytes returned.
+
+-----------------------------------------------------------------------------
+When call_api() returns, rparam points to the returned parameters. The
+first if these is the result code. It will be zero if the API call
+suceeded. This value by be read with "SVAL(rparam,0)".
+
+The second parameter may be read as "SVAL(rparam,2)". It is a 16 bit offset
+which indicates what the base address of the returned data buffer was when
+it was built on the server. It should be used to correct pointer before
+use.
+
+The returned data buffer contains the array of returned data structures.
+Note that all pointers must be adjusted before use. The function
+fix_char_ptr() in client.c can be used for this purpose.
+
+The third parameter (which may be read as "SVAL(rparam,4)") has something to
+do with indicating the amount of data returned or possibly the amount of
+data which can be returned if enough buffer space is allowed.
+
+-----------------------------------------------------------------------------
+Certain data structures are described by means of ASCIIz strings containing
+code characters. These are the code characters:
+
+W a type byte little-endian unsigned integer
+N a count of substructures which follow
+D a four byte little-endian unsigned integer
+B a byte (with optional count expressed as trailing ASCII digits)
+z a four byte offset to a NULL terminated string
+l a four byte offset to non-string user data
+b an offset to data (with count expressed as trailing ASCII digits)
+r pointer to returned data buffer???
+L length in bytes of returned data buffer???
+h number of bytes of information available???
+
+----------------------------------------------------------------------------
diff --git a/source/lib/access.c b/source/lib/access.c
index 14a84b2fb44..4d5954096fc 100644
--- a/source/lib/access.c
+++ b/source/lib/access.c
@@ -5,11 +5,10 @@ by Wietse Venema, Eindhoven University of Technology, The Netherlands.
The code is used here with permission.
The code has been considerably changed from the original. Bug reports
-should be sent to Andrew.Tridgell@anu.edu.au
+should be sent to samba-bugs@samba.anu.edu.au
*/
#include "includes.h"
-#include "loadparm.h"
#define ALLOW_PURE_ADDRESSES
@@ -37,14 +36,11 @@ static char sep[] = ", \t";
#define FAIL (-1)
/* Forward declarations. */
-BOOL allow_access(char *deny_list,char *allow_list,struct from_host *client);
static int list_match(char *list,char *item, int (*match_fn)());
static int client_match(char *tok,char *item);
static int string_match(char *tok,char *s);
static int masked_match(char *tok, char *slash, char *s);
static int matchname(char *remotehost,struct in_addr addr);
-BOOL fromhost(int sock,struct from_host *f);
-
/* Size of logical line buffer. */
#define BUFLEN 2048
diff --git a/source/lib/charcnv.c b/source/lib/charcnv.c
index 049390f2a43..d9ee551d6a8 100644
--- a/source/lib/charcnv.c
+++ b/source/lib/charcnv.c
@@ -71,8 +71,7 @@ static void initiso() {
/*
* Convert unix to dos
*/
-char *
-unix2dos_format(char *str,BOOL overwrite)
+char *unix2dos_format(char *str,BOOL overwrite)
{
char *p;
char *dp;
@@ -91,8 +90,7 @@ unix2dos_format(char *str,BOOL overwrite)
/*
* Convert dos to unix
*/
-char *
-dos2unix_format (char *str, BOOL overwrite)
+char *dos2unix_format(char *str, BOOL overwrite)
{
char *p;
char *dp;
@@ -112,8 +110,7 @@ dos2unix_format (char *str, BOOL overwrite)
/*
* Interpret character set.
*/
-int
-interpret_character_set (char *str, int def)
+int interpret_character_set(char *str, int def)
{
if (strequal (str, "iso8859-1")) {
diff --git a/source/lib/getsmbpass.c b/source/lib/getsmbpass.c
index 07a7dbfd9b5..7ee8c187885 100644
--- a/source/lib/getsmbpass.c
+++ b/source/lib/getsmbpass.c
@@ -40,12 +40,12 @@ static struct termio t;
#define TCSANOW 0
#endif
-int tcgetattr(int fd, struct termio *t)
+ int tcgetattr(int fd, struct termio *t)
{
return ioctl(fd, TCGETA, t);
}
-int tcsetattr(int fd, int flags, const struct termio *t)
+ int tcsetattr(int fd, int flags, const struct termio *t)
{
if(flags & TCSAFLUSH)
ioctl(fd, TCFLSH, TCIOFLUSH);
@@ -71,12 +71,12 @@ static struct sgttyb t;
#define TCSANOW 0
#endif
-int tcgetattr(int fd, struct sgttyb *t)
+ int tcgetattr(int fd, struct sgttyb *t)
{
return ioctl(fd, TIOCGETP, (char *)t);
}
-int tcsetattr(int fd, int flags, const struct sgttyb *t)
+ int tcsetattr(int fd, int flags, const struct sgttyb *t)
{
return ioctl(fd, TIOCSETP, (char *)t);
}
@@ -92,8 +92,7 @@ static struct termios t;
#endif /* BSD_TERMIO */
#endif /* SYSV_TERMIO */
-char *
-getsmbpass(char *prompt)
+char *getsmbpass(char *prompt)
{
FILE *in, *out;
int echo_off;
@@ -162,5 +161,5 @@ getsmbpass(char *prompt)
#else
-void getsmbpasswd_dummy() {;}
+ void getsmbpasswd_dummy() {;}
#endif
diff --git a/source/lib/interface.c b/source/lib/interface.c
new file mode 100644
index 00000000000..061ac08c7b4
--- /dev/null
+++ b/source/lib/interface.c
@@ -0,0 +1,457 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ multiple interface handling
+ Copyright (C) Andrew Tridgell 1992-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 int DEBUGLEVEL;
+
+struct in_addr ipzero;
+struct in_addr ipgrp;
+static struct in_addr default_ip;
+static struct in_addr default_bcast;
+static struct in_addr default_nmask;
+static BOOL got_ip=False;
+static BOOL got_bcast=False;
+static BOOL got_nmask=False;
+
+struct interface *local_interfaces = NULL;
+
+struct interface *last_iface;
+
+/****************************************************************************
+calculate the default netmask for an address
+****************************************************************************/
+static void default_netmask(struct in_addr *inm, struct in_addr *iad)
+{
+ unsigned long ad = ntohl(iad->s_addr);
+ unsigned long nm;
+ /*
+ ** Guess a netmask based on the class of the IP address given.
+ */
+ if ( (ad & 0x80000000) == 0 ) {
+ /* class A address */
+ nm = 0xFF000000;
+ } else if ( (ad & 0xC0000000) == 0x80000000 ) {
+ /* class B address */
+ nm = 0xFFFF0000;
+ } else if ( (ad & 0xE0000000) == 0xC0000000 ) {
+ /* class C address */
+ nm = 0xFFFFFF00;
+ } else {
+ /* class D or E; netmask doesn't make much sense - guess 4 bits */
+ nm = 0xFFFFFFF0;
+ }
+ inm->s_addr = htonl(nm);
+}
+
+
+/****************************************************************************
+ get the broadcast address for our address
+(troyer@saifr00.ateng.az.honeywell.com)
+****************************************************************************/
+static void get_broadcast(struct in_addr *if_ipaddr,
+ struct in_addr *if_bcast,
+ struct in_addr *if_nmask)
+{
+ BOOL found = False;
+#ifndef NO_GET_BROADCAST
+ int sock = -1; /* AF_INET raw socket desc */
+ char buff[1024];
+ struct ifreq *ifr=NULL;
+ int i;
+
+#if defined(EVEREST)
+ int n_interfaces;
+ struct ifconf ifc;
+ struct ifreq *ifreqs;
+#elif defined(USE_IFREQ)
+ struct ifreq ifreq;
+ struct strioctl strioctl;
+ struct ifconf *ifc;
+#else
+ struct ifconf ifc;
+#endif
+#endif
+
+ /* get a default netmask and broadcast */
+ default_netmask(if_nmask, if_ipaddr);
+
+#ifndef NO_GET_BROADCAST
+ /* Create a socket to the INET kernel. */
+#if USE_SOCKRAW
+ if ((sock = socket(AF_INET, SOCK_RAW, PF_INET )) < 0)
+#else
+ if ((sock = socket(AF_INET, SOCK_DGRAM, 0 )) < 0)
+#endif
+ {
+ DEBUG(0,( "Unable to open socket to get broadcast address\n"));
+ return;
+ }
+
+ /* Get a list of the configured interfaces */
+#ifdef EVEREST
+ /* This is part of SCO Openserver 5: The ioctls are no longer part
+ if the lower level STREAMS interface glue. They are now real
+ ioctl calls */
+
+ if (ioctl(sock, SIOCGIFANUM, &n_interfaces) < 0) {
+ DEBUG(0,( "SIOCGIFANUM: %s\n", strerror(errno)));
+ } else {
+ DEBUG(0,( "number of interfaces returned is: %d\n", n_interfaces));
+
+ ifc.ifc_len = sizeof(struct ifreq) * n_interfaces;
+ ifc.ifc_buf = (caddr_t) alloca(ifc.ifc_len);
+
+ if (ioctl(sock, SIOCGIFCONF, &ifc) < 0)
+ DEBUG(0, ( "SIOCGIFCONF: %s\n", strerror(errno)));
+ else {
+ ifr = ifc.ifc_req;
+
+ for (i = 0; i < n_interfaces; ++i) {
+ if (if_ipaddr->s_addr ==
+ ((struct sockaddr_in *) &ifr[i].ifr_addr)->sin_addr.s_addr) {
+ found = True;
+ break;
+ }
+ }
+ }
+ }
+#elif defined(USE_IFREQ)
+ ifc = (struct ifconf *)buff;
+ ifc->ifc_len = BUFSIZ - sizeof(struct ifconf);
+ strioctl.ic_cmd = SIOCGIFCONF;
+ strioctl.ic_dp = (char *)ifc;
+ strioctl.ic_len = sizeof(buff);
+ if (ioctl(sock, I_STR, &strioctl) < 0) {
+ DEBUG(0,( "I_STR/SIOCGIFCONF: %s\n", strerror(errno)));
+ } else {
+ ifr = (struct ifreq *)ifc->ifc_req;
+
+ /* Loop through interfaces, looking for given IP address */
+ for (i = ifc->ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) {
+ if (if_ipaddr->s_addr ==
+ (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) {
+ found = True;
+ break;
+ }
+ }
+ }
+#elif defined(__FreeBSD__) || defined(NETBSD)
+ ifc.ifc_len = sizeof(buff);
+ ifc.ifc_buf = buff;
+ if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
+ DEBUG(0,("SIOCGIFCONF: %s\n", strerror(errno)));
+ } else {
+ ifr = ifc.ifc_req;
+ /* Loop through interfaces, looking for given IP address */
+ i = ifc.ifc_len;
+ while (i > 0) {
+ if (if_ipaddr->s_addr ==
+ (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) {
+ found = True;
+ break;
+ }
+ i -= ifr->ifr_addr.sa_len + IFNAMSIZ;
+ ifr = (struct ifreq*) ((char*) ifr + ifr->ifr_addr.sa_len + IFNAMSIZ);
+ }
+ }
+#else
+ ifc.ifc_len = sizeof(buff);
+ ifc.ifc_buf = buff;
+ if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
+ DEBUG(0,("SIOCGIFCONF: %s\n", strerror(errno)));
+ } else {
+ ifr = ifc.ifc_req;
+
+ /* Loop through interfaces, looking for given IP address */
+ for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) {
+#ifdef BSDI
+ if (ioctl(sock, SIOCGIFADDR, ifr) < 0) break;
+#endif
+ if (if_ipaddr->s_addr ==
+ (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) {
+ found = True;
+ break;
+ }
+ }
+ }
+#endif
+
+ if (!found) {
+ DEBUG(0,("No interface found for address %s\n", inet_ntoa(*if_ipaddr)));
+ } else {
+ /* Get the netmask address from the kernel */
+#ifdef USE_IFREQ
+ ifreq = *ifr;
+
+ strioctl.ic_cmd = SIOCGIFNETMASK;
+ strioctl.ic_dp = (char *)&ifreq;
+ strioctl.ic_len = sizeof(struct ifreq);
+ if (ioctl(sock, I_STR, &strioctl) < 0)
+ DEBUG(0,("Failed I_STR/SIOCGIFNETMASK: %s\n", strerror(errno)));
+ else
+ *if_nmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
+#else
+ if (ioctl(sock, SIOCGIFNETMASK, ifr) < 0)
+ DEBUG(0,("SIOCGIFNETMASK failed\n"));
+ else
+ *if_nmask = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
+#endif
+
+ DEBUG(4,("Netmask for %s = %s\n", ifr->ifr_name,
+ inet_ntoa(*if_nmask)));
+ }
+
+ /* Close up shop */
+ (void) close(sock);
+
+#endif
+
+ /* sanity check on the netmask */
+ {
+ unsigned long nm = ntohl(if_nmask->s_addr);
+ if ((nm >> 24) != 0xFF) {
+ DEBUG(0,("Impossible netmask %s - using defaults\n",inet_ntoa(*if_nmask)));
+ default_netmask(if_nmask, if_ipaddr);
+ }
+ }
+
+ /* derive the broadcast assuming a 1's broadcast, as this is what
+ all MS operating systems do, we have to comply even if the unix
+ box is setup differently */
+ {
+ unsigned long ad = ntohl(if_ipaddr->s_addr);
+ unsigned long nm = ntohl(if_nmask->s_addr);
+ unsigned long bc = (ad & nm) | (0xffffffff & ~nm);
+ if_bcast->s_addr = htonl(bc);
+ }
+
+ DEBUG(4,("Derived broadcast address %s\n", inet_ntoa(*if_bcast)));
+} /* get_broadcast */
+
+
+
+/****************************************************************************
+load a list of network interfaces
+****************************************************************************/
+static void interpret_interfaces(char *s, struct interface **interfaces,
+ char *description)
+{
+ char *ptr = s;
+ fstring token;
+ struct interface *iface;
+ struct in_addr ip;
+
+ ipzero = *interpret_addr2("0.0.0.0");
+ ipgrp = *interpret_addr2("255.255.255.255");
+
+ while (next_token(&ptr,token,NULL)) {
+ /* parse it into an IP address/netmasklength pair */
+ char *p = strchr(token,'/');
+ if (p) *p = 0;
+
+ ip = *interpret_addr2(token);
+
+ /* maybe we already have it listed */
+ {
+ struct interface *i;
+ for (i=(*interfaces);i;i=i->next)
+ if (ip_equal(ip,i->ip)) break;
+ if (i) continue;
+ }
+
+ iface = (struct interface *)malloc(sizeof(*iface));
+ if (!iface) return;
+
+ iface->ip = ip;
+
+ if (p) {
+ if (strlen(p+1)>2)
+ iface->nmask = *interpret_addr2(p+1);
+ else
+ iface->nmask.s_addr = htonl(~((1<<(32-atoi(p+1)))-1));
+ } else {
+ default_netmask(&iface->nmask,&iface->ip);
+ }
+ iface->bcast.s_addr = iface->ip.s_addr | ~iface->nmask.s_addr;
+ iface->next = NULL;
+
+ if (!(*interfaces)) {
+ (*interfaces) = iface;
+ } else {
+ last_iface->next = iface;
+ }
+ last_iface = iface;
+ DEBUG(1,("Added %s ip=%s ",description,inet_ntoa(iface->ip)));
+ DEBUG(1,("bcast=%s ",inet_ntoa(iface->bcast)));
+ DEBUG(1,("nmask=%s\n",inet_ntoa(iface->nmask)));
+ }
+
+ if (*interfaces) return;
+
+ /* setup a default interface */
+ iface = (struct interface *)malloc(sizeof(*iface));
+ if (!iface) return;
+
+ iface->next = NULL;
+
+ if (got_ip) {
+ iface->ip = default_ip;
+ } else {
+ get_myname(NULL,&iface->ip);
+ }
+
+ if (got_bcast) {
+ iface->bcast = default_bcast;
+ } else {
+ get_broadcast(&iface->ip,&iface->bcast,&iface->nmask);
+ }
+
+ if (got_nmask) {
+ iface->nmask = default_nmask;
+ iface->bcast.s_addr = iface->ip.s_addr | ~iface->nmask.s_addr;
+ }
+
+ if (iface->bcast.s_addr != (iface->ip.s_addr | ~iface->nmask.s_addr)) {
+ DEBUG(2,("Warning: inconsistant interface %s\n",inet_ntoa(iface->ip)));
+ }
+
+ iface->next = NULL;
+ (*interfaces) = last_iface = iface;
+
+ DEBUG(1,("Added interface ip=%s ",inet_ntoa(iface->ip)));
+ DEBUG(1,("bcast=%s ",inet_ntoa(iface->bcast)));
+ DEBUG(1,("nmask=%s\n",inet_ntoa(iface->nmask)));
+}
+
+
+/****************************************************************************
+load the remote and local interfaces
+****************************************************************************/
+void load_interfaces(void)
+{
+ /* add the machine's interfaces to local interface structure*/
+ interpret_interfaces(lp_interfaces(), &local_interfaces,"interface");
+}
+
+
+/****************************************************************************
+ override the defaults
+ **************************************************************************/
+void iface_set_default(char *ip,char *bcast,char *nmask)
+{
+ if (ip) {
+ got_ip = True;
+ default_ip = *interpret_addr2(ip);
+ }
+
+ if (bcast) {
+ got_bcast = True;
+ default_bcast = *interpret_addr2(bcast);
+ }
+
+ if (nmask) {
+ got_nmask = True;
+ default_nmask = *interpret_addr2(nmask);
+ }
+}
+
+
+/****************************************************************************
+ check if an IP is one of mine
+ **************************************************************************/
+BOOL ismyip(struct in_addr ip)
+{
+ struct interface *i;
+ for (i=local_interfaces;i;i=i->next)
+ if (ip_equal(i->ip,ip)) return True;
+ return False;
+}
+
+/****************************************************************************
+ check if a bcast is one of mine
+ **************************************************************************/
+BOOL ismybcast(struct in_addr bcast)
+{
+ struct interface *i;
+ for (i=local_interfaces;i;i=i->next)
+ if (ip_equal(i->bcast,bcast)) return True;
+ return False;
+}
+
+/****************************************************************************
+ how many interfaces do we have
+ **************************************************************************/
+int iface_count(void)
+{
+ int ret = 0;
+ struct interface *i;
+
+ for (i=local_interfaces;i;i=i->next)
+ ret++;
+ return ret;
+}
+
+/****************************************************************************
+ return IP of the Nth interface
+ **************************************************************************/
+struct in_addr *iface_n_ip(int n)
+{
+ struct interface *i;
+
+ for (i=local_interfaces;i && n;i=i->next)
+ n--;
+
+ if (i) return &i->ip;
+ return NULL;
+}
+
+static struct interface *iface_find(struct in_addr ip)
+{
+ struct interface *i;
+ if (zero_ip(ip)) return local_interfaces;
+
+ for (i=local_interfaces;i;i=i->next)
+ if (same_net(i->ip,ip,i->nmask)) return i;
+
+ return local_interfaces;
+}
+
+/* these 3 functions return the ip/bcast/nmask for the interface
+ most appropriate for the given ip address */
+
+struct in_addr *iface_bcast(struct in_addr ip)
+{
+ return(&iface_find(ip)->bcast);
+}
+
+struct in_addr *iface_nmask(struct in_addr ip)
+{
+ return(&iface_find(ip)->nmask);
+}
+
+struct in_addr *iface_ip(struct in_addr ip)
+{
+ return(&iface_find(ip)->ip);
+}
+
+
+
diff --git a/source/lib/kanji.c b/source/lib/kanji.c
index 0af476eb157..a77bdea73f0 100644
--- a/source/lib/kanji.c
+++ b/source/lib/kanji.c
@@ -796,8 +796,7 @@ setup_string_function (int codes)
/*
* Interpret coding system.
*/
-int
-interpret_coding_system (char *str, int def)
+int interpret_coding_system(char *str, int def)
{
int codes = def;
@@ -890,6 +889,6 @@ interpret_coding_system (char *str, int def)
return setup_string_function (codes);
}
#else
-int kanji_dummy_procedure(void)
+ int kanji_dummy_procedure(void)
{return 0;}
#endif /* KANJI */
diff --git a/source/lib/md4.c b/source/lib/md4.c
index 485e231a784..bdff075c7e7 100644
--- a/source/lib/md4.c
+++ b/source/lib/md4.c
@@ -295,5 +295,5 @@
** End of md4.c
*/
#else
-void md4_dummy() {;}
+ void md4_dummy() {;}
#endif
diff --git a/source/lib/replace.c b/source/lib/replace.c
new file mode 100644
index 00000000000..14e3c184b7d
--- /dev/null
+++ b/source/lib/replace.c
@@ -0,0 +1,322 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ replacement routines for broken systems
+ Copyright (C) Andrew Tridgell 1992-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"
+
+ void replace_dummy(void)
+{}
+
+#ifdef REPLACE_STRLEN
+/****************************************************************************
+a replacement strlen() that returns int for solaris
+****************************************************************************/
+ int Strlen(char *s)
+{
+ int ret=0;
+ if (!s) return(0);
+ while (*s++) ret++;
+ return(ret);
+}
+#endif
+
+#ifdef NO_FTRUNCATE
+ /*******************************************************************
+ftruncate for operating systems that don't have it
+********************************************************************/
+ int ftruncate(int f,long l)
+{
+ struct flock fl;
+
+ fl.l_whence = 0;
+ fl.l_len = 0;
+ fl.l_start = l;
+ fl.l_type = F_WRLCK;
+ return fcntl(f, F_FREESP, &fl);
+}
+#endif
+
+
+#ifdef REPLACE_STRSTR
+/****************************************************************************
+Mips version of strstr doesn't seem to work correctly.
+There is a #define in includes.h to redirect calls to this function.
+****************************************************************************/
+char *Strstr(char *s, char *p)
+{
+ int len = strlen(p);
+
+ while ( *s != '\0' ) {
+ if ( strncmp(s, p, len) == 0 )
+ return s;
+ s++;
+ }
+
+ return NULL;
+}
+#endif /* REPLACE_STRSTR */
+
+
+#ifdef REPLACE_MKTIME
+/*******************************************************************
+a mktime() replacement for those who don't have it - contributed by
+C.A. Lademann <cal@zls.com>
+********************************************************************/
+#define MINUTE 60
+#define HOUR 60*MINUTE
+#define DAY 24*HOUR
+#define YEAR 365*DAY
+time_t Mktime(struct tm *t)
+{
+ struct tm *u;
+ time_t epoch = 0;
+ int mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+ y, m, i;
+
+ if(t->tm_year < 70)
+ return((time_t)-1);
+
+ epoch = (t->tm_year - 70) * YEAR +
+ (t->tm_year / 4 - 70 / 4 - t->tm_year / 100) * DAY;
+
+ y = t->tm_year;
+ m = 0;
+
+ for(i = 0; i < t->tm_mon; i++) {
+ epoch += mon [m] * DAY;
+ if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
+ epoch += DAY;
+
+ if(++m > 11) {
+ m = 0;
+ y++;
+ }
+ }
+
+ epoch += (t->tm_mday - 1) * DAY;
+ epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec;
+
+ if((u = localtime(&epoch)) != NULL) {
+ t->tm_sec = u->tm_sec;
+ t->tm_min = u->tm_min;
+ t->tm_hour = u->tm_hour;
+ t->tm_mday = u->tm_mday;
+ t->tm_mon = u->tm_mon;
+ t->tm_year = u->tm_year;
+ t->tm_wday = u->tm_wday;
+ t->tm_yday = u->tm_yday;
+ t->tm_isdst = u->tm_isdst;
+#ifndef NO_TM_NAME
+ memcpy(t->tm_name, u->tm_name, LTZNMAX);
+#endif
+ }
+
+ return(epoch);
+}
+#endif /* REPLACE_MKTIME */
+
+
+
+#ifdef REPLACE_RENAME
+/* Rename a file. (from libiberty in GNU binutils) */
+ int rename (zfrom, zto)
+ const char *zfrom;
+ const char *zto;
+{
+ if (link (zfrom, zto) < 0)
+ {
+ if (errno != EEXIST)
+ return -1;
+ if (unlink (zto) < 0
+ || link (zfrom, zto) < 0)
+ return -1;
+ }
+ return unlink (zfrom);
+}
+#endif
+
+
+#ifdef REPLACE_INNETGR
+/*
+ * Search for a match in a netgroup. This replaces it on broken systems.
+ */
+int InNetGr(char *group,char *host,char *user,char *dom)
+{
+ char *hst, *usr, *dm;
+
+ setnetgrent(group);
+ while (getnetgrent(&hst, &usr, &dm))
+ if (((host == 0) || (hst == 0) || !strcmp(host, hst)) &&
+ ((user == 0) || (usr == 0) || !strcmp(user, usr)) &&
+ ((dom == 0) || (dm == 0) || !strcmp(dom, dm))) {
+ endnetgrent();
+ return (1);
+ }
+ endnetgrent();
+ return (0);
+}
+#endif
+
+
+
+#ifdef NO_INITGROUPS
+#include <sys/types.h>
+#include <limits.h>
+#include <grp.h>
+
+#ifndef NULL
+#define NULL (void *)0
+#endif
+
+/****************************************************************************
+ some systems don't have an initgroups call
+****************************************************************************/
+ int initgroups(char *name,gid_t id)
+{
+#ifdef NO_SETGROUPS
+ /* yikes! no SETGROUPS or INITGROUPS? how can this work? */
+ return(0);
+#else
+ gid_t grouplst[NGROUPS_MAX];
+ int i,j;
+ struct group *g;
+ char *gr;
+
+ grouplst[0] = id;
+ i = 1;
+ while (i < NGROUPS_MAX &&
+ ((g = (struct group *)getgrent()) != (struct group *)NULL))
+ {
+ if (g->gr_gid == id)
+ continue;
+ j = 0;
+ gr = g->gr_mem[0];
+ while (gr && (*gr != (char)NULL)) {
+ if (strcmp(name,gr) == 0) {
+ grouplst[i] = g->gr_gid;
+ i++;
+ gr = (char *)NULL;
+ break;
+ }
+ gr = g->gr_mem[++j];
+ }
+ }
+ endgrent();
+ return(setgroups(i,grouplst));
+#endif
+}
+#endif
+
+
+#if (defined(SecureWare) && defined(SCO))
+/* This is needed due to needing the nap() function but we don't want
+ to include the Xenix libraries since that will break other things...
+ BTW: system call # 0x0c28 is the same as calling nap() */
+long nap(long milliseconds) {
+ return syscall(0x0c28, milliseconds);
+}
+#endif
+
+
+
+#if WRAP_MALLOC
+
+/* undo the wrapping temporarily */
+#undef malloc
+#undef realloc
+#undef free
+
+/****************************************************************************
+wrapper for malloc() to catch memory errors
+****************************************************************************/
+void *malloc_wrapped(int size,char *file,int line)
+{
+#ifdef xx_old_malloc
+ void *res = xx_old_malloc(size);
+#else
+ void *res = malloc(size);
+#endif
+ DEBUG(3,("Malloc called from %s(%d) with size=%d gave ptr=0x%X\n",
+ file,line,
+ size,(unsigned int)res));
+ return(res);
+}
+
+/****************************************************************************
+wrapper for realloc() to catch memory errors
+****************************************************************************/
+void *realloc_wrapped(void *ptr,int size,char *file,int line)
+{
+#ifdef xx_old_realloc
+ void *res = xx_old_realloc(ptr,size);
+#else
+ void *res = realloc(ptr,size);
+#endif
+ DEBUG(3,("Realloc\n"));
+ DEBUG(3,("free called from %s(%d) with ptr=0x%X\n",
+ file,line,
+ (unsigned int)ptr));
+ DEBUG(3,("Malloc called from %s(%d) with size=%d gave ptr=0x%X\n",
+ file,line,
+ size,(unsigned int)res));
+ return(res);
+}
+
+/****************************************************************************
+wrapper for free() to catch memory errors
+****************************************************************************/
+void free_wrapped(void *ptr,char *file,int line)
+{
+#ifdef xx_old_free
+ xx_old_free(ptr);
+#else
+ free(ptr);
+#endif
+ DEBUG(3,("free called from %s(%d) with ptr=0x%X\n",
+ file,line,(unsigned int)ptr));
+ return;
+}
+
+/* and re-do the define for spots lower in this file */
+#define malloc(size) malloc_wrapped(size,__FILE__,__LINE__)
+#define realloc(ptr,size) realloc_wrapped(ptr,size,__FILE__,__LINE__)
+#define free(ptr) free_wrapped(ptr,__FILE__,__LINE__)
+
+#endif
+
+
+#if WRAP_MEMCPY
+#undef memcpy
+/*******************************************************************
+a wrapper around memcpy for diagnostic purposes
+********************************************************************/
+void *memcpy_wrapped(void *d,void *s,int l,char *fname,int line)
+{
+ if (l>64 && (((int)d)%4) != (((int)s)%4))
+ DEBUG(4,("Misaligned memcpy(0x%X,0x%X,%d) at %s(%d)\n",d,s,l,fname,line));
+#ifdef xx_old_memcpy
+ return(xx_old_memcpy(d,s,l));
+#else
+ return(memcpy(d,s,l));
+#endif
+}
+#define memcpy(d,s,l) memcpy_wrapped(d,s,l,__FILE__,__LINE__)
+#endif
+
diff --git a/source/lib/system.c b/source/lib/system.c
index 938746e9c9d..1410b776ab1 100644
--- a/source/lib/system.c
+++ b/source/lib/system.c
@@ -25,13 +25,17 @@ extern int DEBUGLEVEL;
/*
The idea is that this file will eventually have wrappers around all
- important system calls in samba. The aim is twofold:
+ important system calls in samba. The aims are:
- to enable easier porting by putting OS dependent stuff in here
- to allow for hooks into other "pseudo-filesystems"
- to allow easier integration of things like the japanese extensions
+
+ - to support the philosophy of Samba to expose the features of
+ the OS within the SMB model. In general whatever file/printer/variable
+ expansions/etc make sense to the OS should be acceptable to Samba.
*/
@@ -79,7 +83,7 @@ int sys_select(fd_set *fds,struct timeval *tval)
return(found);
}
- if (tval && tval.tv_sec < counter) return(0);
+ if (tval && tval->tv_sec < counter) return(0);
sleep(1);
counter++;
}
@@ -196,6 +200,13 @@ int sys_rename(char *from, char *to)
#endif /* KANJI */
}
+/*******************************************************************
+for chmod
+********************************************************************/
+int sys_chmod(char *fname,int mode)
+{
+ return(chmod(dos_to_unix(fname,False),mode));
+}
/*******************************************************************
chown isn't used much but OS/2 doesn't have it
diff --git a/source/lib/time.c b/source/lib/time.c
new file mode 100644
index 00000000000..efcda804c49
--- /dev/null
+++ b/source/lib/time.c
@@ -0,0 +1,495 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ time handling functions
+ Copyright (C) Andrew Tridgell 1992-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"
+
+/*
+ This stuff was largely rewritten by Paul Eggert <eggert@twinsun.com>
+ in May 1996
+ */
+
+
+int serverzone=0;
+int extra_time_offset = 0;
+
+extern int DEBUGLEVEL;
+
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+
+#ifndef TIME_T_MIN
+#define TIME_T_MIN (0 < (time_t) -1 ? (time_t) 0 \
+ : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1))
+#endif
+#ifndef TIME_T_MAX
+#define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN)
+#endif
+
+
+
+/*******************************************************************
+a gettimeofday wrapper
+********************************************************************/
+void GetTimeOfDay(struct timeval *tval)
+{
+#ifdef GETTIMEOFDAY1
+ gettimeofday(tval);
+#else
+ gettimeofday(tval,NULL);
+#endif
+}
+
+#define TM_YEAR_BASE 1900
+
+/*******************************************************************
+yield the difference between *A and *B, in seconds, ignoring leap seconds
+********************************************************************/
+static int tm_diff(struct tm *a, struct tm *b)
+{
+ int ay = a->tm_year + (TM_YEAR_BASE - 1);
+ int by = b->tm_year + (TM_YEAR_BASE - 1);
+ int intervening_leap_days =
+ (ay/4 - by/4) - (ay/100 - by/100) + (ay/400 - by/400);
+ int years = ay - by;
+ int days = 365*years + intervening_leap_days + (a->tm_yday - b->tm_yday);
+ int hours = 24*days + (a->tm_hour - b->tm_hour);
+ int minutes = 60*hours + (a->tm_min - b->tm_min);
+ int seconds = 60*minutes + (a->tm_sec - b->tm_sec);
+ return seconds;
+}
+
+/*******************************************************************
+ return the UTC offset in seconds west of UTC
+ ******************************************************************/
+static int TimeZone(time_t t)
+{
+ struct tm tm_utc = *(gmtime(&t));
+ return tm_diff(&tm_utc,localtime(&t));
+}
+
+
+/*******************************************************************
+init the time differences
+********************************************************************/
+void TimeInit(void)
+{
+ serverzone = TimeZone(time(NULL));
+ DEBUG(4,("Serverzone is %d\n",serverzone));
+}
+
+
+/*******************************************************************
+return the same value as TimeZone, but it should be more efficient.
+
+We keep a table of DST offsets to prevent calling localtime() on each
+call of this function. This saves a LOT of time on many unixes.
+
+Updated by Paul Eggert <eggert@twinsun.com>
+********************************************************************/
+static int TimeZoneFaster(time_t t)
+{
+ static struct dst_table {time_t start,end; int zone;} *dst_table = NULL;
+ static int table_size = 0;
+ int i;
+ int zone = 0;
+
+ if (t == 0) t = time(NULL);
+
+ /* Tunis has a 8 day DST region, we need to be careful ... */
+#define MAX_DST_WIDTH (365*24*60*60)
+#define MAX_DST_SKIP (7*24*60*60)
+
+ for (i=0;i<table_size;i++)
+ if (t >= dst_table[i].start && t <= dst_table[i].end) break;
+
+ if (i<table_size) {
+ zone = dst_table[i].zone;
+ } else {
+ time_t low,high;
+
+ zone = TimeZone(t);
+ dst_table = (struct dst_table *)Realloc(dst_table,
+ sizeof(dst_table[0])*(i+1));
+ if (!dst_table) {
+ table_size = 0;
+ } else {
+ table_size++;
+
+ dst_table[i].zone = zone;
+ dst_table[i].start = dst_table[i].end = t;
+
+ /* no entry will cover more than 6 months */
+ low = t - MAX_DST_WIDTH/2;
+ if (t < low)
+ low = TIME_T_MIN;
+
+ high = t + MAX_DST_WIDTH/2;
+ if (high < t)
+ high = TIME_T_MAX;
+
+ /* widen the new entry using two bisection searches */
+ while (low+60*60 < dst_table[i].start) {
+ if (dst_table[i].start - low > MAX_DST_SKIP*2)
+ t = dst_table[i].start - MAX_DST_SKIP;
+ else
+ t = low + (dst_table[i].start-low)/2;
+ if (TimeZone(t) == zone)
+ dst_table[i].start = t;
+ else
+ low = t;
+ }
+
+ while (high-60*60 > dst_table[i].end) {
+ if (high - dst_table[i].end > MAX_DST_SKIP*2)
+ t = dst_table[i].end + MAX_DST_SKIP;
+ else
+ t = high - (high-dst_table[i].end)/2;
+ if (TimeZone(t) == zone)
+ dst_table[i].end = t;
+ else
+ high = t;
+ }
+#if 0
+ DEBUG(1,("Added DST entry from %s ",
+ asctime(localtime(&dst_table[i].start))));
+ DEBUG(1,("to %s (%d)\n",asctime(localtime(&dst_table[i].end)),
+ dst_table[i].zone));
+#endif
+ }
+ }
+ return zone;
+}
+
+/****************************************************************************
+ return the UTC offset in seconds west of UTC, adjusted for extra time offset
+ **************************************************************************/
+int TimeDiff(time_t t)
+{
+ return TimeZoneFaster(t) + 60*extra_time_offset;
+}
+
+
+/****************************************************************************
+ return the UTC offset in seconds west of UTC, adjusted for extra time
+ offset, for a local time value. If ut = lt + LocTimeDiff(lt), then
+ lt = ut - TimeDiff(ut), but the converse does not necessarily hold near
+ daylight savings transitions because some local times are ambiguous.
+ LocTimeDiff(t) equals TimeDiff(t) except near daylight savings transitions.
+ +**************************************************************************/
+static int LocTimeDiff(time_t lte)
+{
+ time_t lt = lte - 60*extra_time_offset;
+ int d = TimeZoneFaster(lt);
+ time_t t = lt + d;
+
+ /* if overflow occurred, ignore all the adjustments so far */
+ if (((lte < lt) ^ (extra_time_offset < 0)) | ((t < lt) ^ (d < 0)))
+ t = lte;
+
+ /* now t should be close enough to the true UTC to yield the right answer */
+ return TimeDiff(t);
+}
+
+
+/****************************************************************************
+try to optimise the localtime call, it can be quite expenive on some machines
+****************************************************************************/
+struct tm *LocalTime(time_t *t)
+{
+ time_t t2 = *t;
+
+ t2 -= TimeDiff(t2);
+
+ return(gmtime(&t2));
+}
+
+
+#define TIME_FIXUP_CONSTANT (369.0*365.25*24*60*60-(3.0*24*60*60+6.0*60*60))
+
+/****************************************************************************
+interpret an 8 byte "filetime" structure to a time_t
+It's originally in "100ns units since jan 1st 1601"
+
+It appears to be kludge-GMT (at least for file listings). This means
+its the GMT you get by taking a localtime and adding the
+serverzone. This is NOT the same as GMT in some cases. This routine
+converts this to real GMT.
+****************************************************************************/
+time_t interpret_long_date(char *p)
+{
+ double d;
+ time_t ret;
+ uint32 tlow,thigh;
+ tlow = IVAL(p,0);
+ thigh = IVAL(p,4);
+
+ if (thigh == 0) return(0);
+
+ d = ((double)thigh)*4.0*(double)(1<<30);
+ d += (tlow&0xFFF00000);
+ d *= 1.0e-7;
+
+ /* now adjust by 369 years to make the secs since 1970 */
+ d -= TIME_FIXUP_CONSTANT;
+
+ if (!(TIME_T_MIN <= d && d <= TIME_T_MAX))
+ return(0);
+
+ ret = (time_t)(d+0.5);
+
+ /* this takes us from kludge-GMT to real GMT */
+ ret -= serverzone;
+ ret += LocTimeDiff(ret);
+
+ return(ret);
+}
+
+
+/****************************************************************************
+put a 8 byte filetime from a time_t
+This takes real GMT as input and converts to kludge-GMT
+****************************************************************************/
+void put_long_date(char *p,time_t t)
+{
+ uint32 tlow,thigh;
+ double d;
+
+ if (t==0) {
+ SIVAL(p,0,0); SIVAL(p,4,0);
+ return;
+ }
+
+ /* this converts GMT to kludge-GMT */
+ t -= TimeDiff(t) - serverzone;
+
+ d = (double) (t);
+
+ d += TIME_FIXUP_CONSTANT;
+
+ d *= 1.0e7;
+
+ thigh = (uint32)(d * (1.0/(4.0*(double)(1<<30))));
+ tlow = (uint32)(d - ((double)thigh)*4.0*(double)(1<<30));
+
+ SIVAL(p,0,tlow);
+ SIVAL(p,4,thigh);
+}
+
+
+/****************************************************************************
+check if it's a null mtime
+****************************************************************************/
+static BOOL null_mtime(time_t mtime)
+{
+ if (mtime == 0 || mtime == 0xFFFFFFFF || mtime == (time_t)-1)
+ return(True);
+ return(False);
+}
+
+/*******************************************************************
+ create a 16 bit dos packed date
+********************************************************************/
+static uint16 make_dos_date1(time_t unixdate,struct tm *t)
+{
+ uint16 ret=0;
+ ret = (((unsigned)(t->tm_mon+1)) >> 3) | ((t->tm_year-80) << 1);
+ ret = ((ret&0xFF)<<8) | (t->tm_mday | (((t->tm_mon+1) & 0x7) << 5));
+ return(ret);
+}
+
+/*******************************************************************
+ create a 16 bit dos packed time
+********************************************************************/
+static uint16 make_dos_time1(time_t unixdate,struct tm *t)
+{
+ uint16 ret=0;
+ ret = ((((unsigned)t->tm_min >> 3)&0x7) | (((unsigned)t->tm_hour) << 3));
+ ret = ((ret&0xFF)<<8) | ((t->tm_sec/2) | ((t->tm_min & 0x7) << 5));
+ return(ret);
+}
+
+/*******************************************************************
+ create a 32 bit dos packed date/time from some parameters
+ This takes a GMT time and returns a packed localtime structure
+********************************************************************/
+static uint32 make_dos_date(time_t unixdate)
+{
+ struct tm *t;
+ uint32 ret=0;
+
+ t = LocalTime(&unixdate);
+
+ ret = make_dos_date1(unixdate,t);
+ ret = ((ret&0xFFFF)<<16) | make_dos_time1(unixdate,t);
+
+ return(ret);
+}
+
+/*******************************************************************
+put a dos date into a buffer (time/date format)
+This takes GMT time and puts local time in the buffer
+********************************************************************/
+void put_dos_date(char *buf,int offset,time_t unixdate)
+{
+ uint32 x = make_dos_date(unixdate);
+ SIVAL(buf,offset,x);
+}
+
+/*******************************************************************
+put a dos date into a buffer (date/time format)
+This takes GMT time and puts local time in the buffer
+********************************************************************/
+void put_dos_date2(char *buf,int offset,time_t unixdate)
+{
+ uint32 x = make_dos_date(unixdate);
+ x = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
+ SIVAL(buf,offset,x);
+}
+
+/*******************************************************************
+put a dos 32 bit "unix like" date into a buffer. This routine takes
+GMT and converts it to LOCAL time before putting it (most SMBs assume
+localtime for this sort of date)
+********************************************************************/
+void put_dos_date3(char *buf,int offset,time_t unixdate)
+{
+ if (!null_mtime(unixdate))
+ unixdate -= TimeDiff(unixdate);
+ SIVAL(buf,offset,unixdate);
+}
+
+/*******************************************************************
+ interpret a 32 bit dos packed date/time to some parameters
+********************************************************************/
+static void interpret_dos_date(uint32 date,int *year,int *month,int *day,int *hour,int *minute,int *second)
+{
+ uint32 p0,p1,p2,p3;
+
+ p0=date&0xFF; p1=((date&0xFF00)>>8)&0xFF;
+ p2=((date&0xFF0000)>>16)&0xFF; p3=((date&0xFF000000)>>24)&0xFF;
+
+ *second = 2*(p0 & 0x1F);
+ *minute = ((p0>>5)&0xFF) + ((p1&0x7)<<3);
+ *hour = (p1>>3)&0xFF;
+ *day = (p2&0x1F);
+ *month = ((p2>>5)&0xFF) + ((p3&0x1)<<3) - 1;
+ *year = ((p3>>1)&0xFF) + 80;
+}
+
+/*******************************************************************
+ create a unix date (int GMT) from a dos date (which is actually in
+ localtime)
+********************************************************************/
+time_t make_unix_date(void *date_ptr)
+{
+ uint32 dos_date=0;
+ struct tm t;
+ time_t ret;
+
+ dos_date = IVAL(date_ptr,0);
+
+ if (dos_date == 0) return(0);
+
+ interpret_dos_date(dos_date,&t.tm_year,&t.tm_mon,
+ &t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec);
+ t.tm_isdst = -1;
+
+ /* mktime() also does the local to GMT time conversion for us */
+ ret = mktime(&t);
+
+ return(ret);
+}
+
+/*******************************************************************
+like make_unix_date() but the words are reversed
+********************************************************************/
+time_t make_unix_date2(void *date_ptr)
+{
+ uint32 x,x2;
+
+ x = IVAL(date_ptr,0);
+ x2 = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
+ SIVAL(&x,0,x2);
+
+ return(make_unix_date((void *)&x));
+}
+
+/*******************************************************************
+ create a unix GMT date from a dos date in 32 bit "unix like" format
+ these generally arrive as localtimes, with corresponding DST
+ ******************************************************************/
+time_t make_unix_date3(void *date_ptr)
+{
+ time_t t = IVAL(date_ptr,0);
+ if (!null_mtime(t))
+ t += LocTimeDiff(t);
+ return(t);
+}
+
+/****************************************************************************
+set the time on a file
+****************************************************************************/
+BOOL set_filetime(char *fname,time_t mtime)
+{
+ struct utimbuf times;
+
+ if (null_mtime(mtime)) return(True);
+
+ times.modtime = times.actime = mtime;
+
+ if (sys_utime(fname,&times)) {
+ DEBUG(4,("set_filetime(%s) failed: %s\n",fname,strerror(errno)));
+ }
+
+ return(True);
+}
+
+
+/****************************************************************************
+ return the date and time as a string
+****************************************************************************/
+char *timestring(void )
+{
+ static char TimeBuf[100];
+ time_t t = time(NULL);
+ struct tm *tm = LocalTime(&t);
+
+#ifdef NO_STRFTIME
+ strcpy(TimeBuf, asctime(tm));
+#elif defined(CLIX) || defined(CONVEX)
+ strftime(TimeBuf,100,"%m/%d/%y %I:%M:%S %p",tm);
+#elif defined(AMPM)
+ strftime(TimeBuf,100,"%D %r",tm);
+#elif defined(TZ_TIME)
+ {
+ int zone = TimeDiff(t);
+ int absZoneMinutes = (zone<0 ? -zone : zone) / 60;
+ size_t len = strftime(TimeBuf,sizeof(TimeBuf)-6,"%D %T",tm);
+ sprintf(TimeBuf+len," %c%02d%02d",
+ zone<0?'+':'-',absZoneMinutes/60,absZoneMinutes%60);
+ }
+#else
+ strftime(TimeBuf,100,"%D %T",tm);
+#endif
+ return(TimeBuf);
+}
+
diff --git a/source/lib/ufc.c b/source/lib/ufc.c
index 8417285821a..fc35fce80a4 100644
--- a/source/lib/ufc.c
+++ b/source/lib/ufc.c
@@ -656,8 +656,6 @@ static char *output_conversion(v1, v2, salt)
return outbuf;
}
-ufc_long *_ufc_doit();
-
/*
* UNIX crypt function
*/
@@ -777,6 +775,6 @@ ufc_long *_ufc_doit(l1, l2, r1, r2, itr)
#else
-int ufc_dummy_procedure(void)
+ int ufc_dummy_procedure(void)
{return 0;}
#endif
diff --git a/source/lib/username.c b/source/lib/username.c
index 3d214fbbdab..0b82d79747b 100644
--- a/source/lib/username.c
+++ b/source/lib/username.c
@@ -20,7 +20,6 @@
*/
#include "includes.h"
-#include "loadparm.h"
extern int DEBUGLEVEL;
diff --git a/source/lib/util.c b/source/lib/util.c
index 7bd6298c4ca..657e9cb1a0d 100644
--- a/source/lib/util.c
+++ b/source/lib/util.c
@@ -20,7 +20,6 @@
*/
#include "includes.h"
-#include "loadparm.h"
pstring scope = "";
@@ -30,8 +29,6 @@ BOOL passive = False;
int Protocol = PROTOCOL_COREPLUS;
-int serverzone=0;
-
/* a default finfo structure to ensure all fields are sensible */
file_info def_finfo = {-1,0,0,0,0,0,0,""};
@@ -51,11 +48,6 @@ struct in_addr lastip;
/* the last port received from */
int lastport=0;
-/* my IP, the broadcast IP and the Netmask */
-struct in_addr myip;
-struct in_addr bcast_ip;
-struct in_addr Netmask;
-
int trans_num = 0;
/*
@@ -63,10 +55,6 @@ int trans_num = 0;
*/
int case_default = CASE_LOWER;
-
-/* size of reads during a direct file to file transfer */
-int ReadSize = 16*1024;
-
pstring debugf = "/tmp/log.samba";
int syslog_level;
@@ -87,6 +75,8 @@ pstring user_socket_options="";
pstring sesssetup_user="";
+int smb_read_error = 0;
+
static char *filename_dos(char *path,char *buf);
static BOOL stdout_logging = False;
@@ -151,58 +141,60 @@ void reopen_logs(void)
/*******************************************************************
+check if the log has grown too big
+********************************************************************/
+static void check_log_size(void)
+{
+ static int debug_count=0;
+ int maxlog;
+ struct stat st;
+
+ if (debug_count++ < 100) return;
+
+ maxlog = lp_max_log_size() * 1024;
+ if (!dbf || maxlog <= 0) return;
+
+ if (fstat(fileno(dbf),&st) == 0 && st.st_size > maxlog) {
+ fclose(dbf); dbf = NULL;
+ reopen_logs();
+ if (dbf && file_size(debugf) > maxlog) {
+ pstring name;
+ fclose(dbf); dbf = NULL;
+ sprintf(name,"%s.old",debugf);
+ sys_rename(debugf,name);
+ reopen_logs();
+ }
+ }
+ debug_count=0;
+}
+
+
+/*******************************************************************
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;
#endif
va_list ap;
+ if (stdout_logging) {
#ifdef __STDC__
- va_start(ap, format_str);
+ va_start(ap, format_str);
#else
- va_start(ap);
- format_str = va_arg(ap,char *);
+ va_start(ap);
+ format_str = va_arg(ap,char *);
#endif
-
- if (stdout_logging) {
vfprintf(dbf,format_str,ap);
va_end(ap);
return(0);
}
-
- {
- static int debug_count=0;
-
- debug_count++;
- if (debug_count == 100) {
- int maxlog = lp_max_log_size() * 1024;
- if (dbf && maxlog > 0)
- {
- struct stat st;
-
- if (fstat(fileno(dbf),&st) == 0 && st.st_size > maxlog) {
- fclose(dbf); dbf = NULL;
- reopen_logs();
- if (dbf && file_size(debugf) > maxlog) {
- pstring name;
- fclose(dbf); dbf = NULL;
- sprintf(name,"%s.old",debugf);
- sys_rename(debugf,name);
- reopen_logs();
- }
- }
- }
- debug_count=0;
- }
- }
#ifdef SYSLOG
if (!lp_syslog_only())
@@ -241,7 +233,14 @@ va_dcl
else
priority = priority_map[syslog_level];
+#ifdef __STDC__
+ va_start(ap, format_str);
+#else
+ va_start(ap);
+ format_str = va_arg(ap,char *);
+#endif
vsprintf(msgbuf, format_str, ap);
+ va_end(ap);
msgbuf[255] = '\0';
syslog(priority, "%s", msgbuf);
@@ -252,279 +251,22 @@ va_dcl
if (!lp_syslog_only())
#endif
{
- vfprintf(dbf,format_str,ap);
- fflush(dbf);
- }
-
- va_end(ap);
- return(0);
-}
-
-/****************************************************************************
-routine to do file locking
-****************************************************************************/
-BOOL fcntl_lock(int fd,int op,uint32 offset,uint32 count,int type)
-{
-#if HAVE_FCNTL_LOCK
- struct flock lock;
- int ret;
-
-#if 1
- uint32 mask = 0xC0000000;
-
- /* make sure the count is reasonable, we might kill the lockd otherwise */
- count &= ~mask;
-
- /* the offset is often strange - remove 2 of its bits if either of
- the top two bits are set. Shift the top ones by two bits. This
- still allows OLE2 apps to operate, but should stop lockd from
- dieing */
- if ((offset & mask) != 0)
- offset = (offset & ~mask) | ((offset & mask) >> 2);
-#else
- unsigned long mask = ((unsigned)1<<31);
-
- /* interpret negative counts as large numbers */
- if (count < 0)
- count &= ~mask;
-
- /* no negative offsets */
- offset &= ~mask;
-
- /* count + offset must be in range */
- while ((offset < 0 || (offset + count < 0)) && mask)
- {
- offset &= ~mask;
- mask = mask >> 1;
- }
-#endif
-
-
- DEBUG(5,("fcntl_lock %d %d %d %d %d\n",fd,op,(int)offset,(int)count,type));
-
- lock.l_type = type;
- lock.l_whence = SEEK_SET;
- lock.l_start = (int)offset;
- lock.l_len = (int)count;
- lock.l_pid = 0;
-
- errno = 0;
-
- ret = fcntl(fd,op,&lock);
-
- if (errno != 0)
- DEBUG(3,("fcntl lock gave errno %d (%s)\n",errno,strerror(errno)));
-
- /* a lock query */
- if (op == F_GETLK)
- {
- if ((ret != -1) &&
- (lock.l_type != F_UNLCK) &&
- (lock.l_pid != 0) &&
- (lock.l_pid != getpid()))
- {
- DEBUG(3,("fd %d is locked by pid %d\n",fd,lock.l_pid));
- return(True);
- }
-
- /* it must be not locked or locked by me */
- return(False);
- }
-
- /* a lock set or unset */
- if (ret == -1)
- {
- DEBUG(3,("lock failed at offset %d count %d op %d type %d (%s)\n",
- offset,count,op,type,strerror(errno)));
-
- /* perhaps it doesn't support this sort of locking?? */
- if (errno == EINVAL)
- {
- DEBUG(3,("locking not supported? returning True\n"));
- return(True);
- }
-
- return(False);
- }
-
- /* everything went OK */
- DEBUG(5,("Lock call successful\n"));
-
- return(True);
-#else
- return(False);
-#endif
-}
-
-/*******************************************************************
-lock a file - returning a open file descriptor or -1 on failure
-The timeout is in seconds. 0 means no timeout
-********************************************************************/
-int file_lock(char *name,int timeout)
-{
- int fd = open(name,O_RDWR|O_CREAT,0666);
- time_t t=0;
- if (fd < 0) return(-1);
-
-#if HAVE_FCNTL_LOCK
- if (timeout) t = time(NULL);
- while (!timeout || (time(NULL)-t < timeout)) {
- if (fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)) return(fd);
- msleep(LOCK_RETRY_TIMEOUT);
- }
- return(-1);
-#else
- return(fd);
-#endif
-}
-
-/*******************************************************************
-unlock a file locked by file_lock
-********************************************************************/
-void file_unlock(int fd)
-{
- if (fd<0) return;
-#if HAVE_FCNTL_LOCK
- fcntl_lock(fd,F_SETLK,0,1,F_UNLCK);
-#endif
- close(fd);
-}
-
-/*******************************************************************
-a gettimeofday wrapper
-********************************************************************/
-void GetTimeOfDay(struct timeval *tval)
-{
-#ifdef GETTIMEOFDAY1
- gettimeofday(tval);
-#else
- gettimeofday(tval,NULL);
-#endif
-}
-
-int extra_time_offset = 0;
-
-static int timediff = 0;
-
-/*******************************************************************
-init the time differences
-********************************************************************/
-void TimeInit(void)
-{
- struct tm tm_utc,tm_local;
- time_t t;
-
- t = time(NULL);
-
- tm_utc = *(gmtime(&t));
- tm_local = *(localtime(&t));
-
-#ifdef HAVE_GMTOFF
- timediff = -tm_local.tm_gmtoff;
+#ifdef __STDC__
+ va_start(ap, format_str);
#else
- timediff = mktime(&tm_utc) - mktime(&tm_local);
+ va_start(ap);
+ format_str = va_arg(ap,char *);
#endif
-
- if (serverzone == 0) {
- serverzone = timediff - DSTDiff(t);
- DEBUG(4,("Serverzone is %d\n",serverzone));
- }
-}
-
-
-/*******************************************************************
-return the DST offset for a particular time
-We keep a table of DST offsets to prevent calling localtime() on each
-call of this function. This saves a LOT of time on many unixes.
-********************************************************************/
-int DSTDiff(time_t t)
-{
- static struct dst_table {time_t start,end; BOOL is_dst;} *dst_table = NULL;
- static int table_size = 0;
- int i;
- BOOL is_dst = False;
-
- if (t == 0) t = time(NULL);
-
-#ifndef NO_ISDST
- for (i=0;i<table_size;i++)
- if (t >= dst_table[i].start && t <= dst_table[i].end) break;
-
- if (i<table_size) {
- is_dst = dst_table[i].is_dst;
- } else {
- time_t low,high;
-
- dst_table = (struct dst_table *)Realloc(dst_table,
- sizeof(dst_table[0])*(i+1));
- if (!dst_table) {
- table_size = 0;
- return(0);
- }
-
- table_size++;
-
- dst_table[i].is_dst = is_dst = (localtime(&t)->tm_isdst?True:False);;
- dst_table[i].start = dst_table[i].end = t;
-
- /* no entry will cover more than 6 months */
- low = t - 3*30*24*60*60;
- high = t + 3*30*24*60*60;
-
- /* widen the new entry using two bisection searches */
- while (low+60*60 < dst_table[i].start) {
- t = low + (dst_table[i].start-low)/2;
- if ((localtime(&t)->tm_isdst?True:False) == is_dst)
- dst_table[i].start = t;
- else
- low = t;
+ vfprintf(dbf,format_str,ap);
+ va_end(ap);
+ fflush(dbf);
}
- while (high-60*60 > dst_table[i].end) {
- t = high + (high-dst_table[i].end)/2;
- if ((localtime(&t)->tm_isdst?True:False) == is_dst)
- dst_table[i].end = t;
- else
- high = t;
- }
+ check_log_size();
-/*
- DEBUG(1,("Added DST entry from %s ",
- asctime(localtime(&dst_table[i].start))));
- DEBUG(1,("to %s (%d)\n",asctime(localtime(&dst_table[i].end)),
- dst_table[i].is_dst));
-*/
- }
-#endif
-
- return((is_dst?60*60:0) - (extra_time_offset*60));
-}
-
-/****************************************************************************
-return the difference between local and GMT time
-****************************************************************************/
-int TimeDiff(time_t t)
-{
- static BOOL initialised = False;
- if (!initialised) {initialised=True; TimeInit();}
- return(timediff - DSTDiff(t));
-}
-
-/****************************************************************************
-try to optimise the localtime call, it can be quite expenive on some machines
-timemul is normally LOCAL_TO_GMT, GMT_TO_LOCAL or 0
-****************************************************************************/
-struct tm *LocalTime(time_t *t,int timemul)
-{
- time_t t2 = *t;
-
- if (timemul)
- t2 += timemul * TimeDiff(t2);
-
- return(gmtime(&t2));
+ return(0);
}
-
/****************************************************************************
determine if a file descriptor is in fact a socket
****************************************************************************/
@@ -805,32 +547,6 @@ void close_sockets(void )
}
/****************************************************************************
- return the date and time as a string
-****************************************************************************/
-char *timestring(void )
-{
- static char TimeBuf[100];
- time_t t;
- t = time(NULL);
-#ifdef NO_STRFTIME
- strcpy(TimeBuf, asctime(LocalTime(&t,GMT_TO_LOCAL)));
-#elif defined(CLIX) || defined(CONVEX)
- strftime(TimeBuf,100,"%m/%d/%y %I:%M:%S %p",LocalTime(&t,GMT_TO_LOCAL));
-#elif defined(AMPM)
- strftime(TimeBuf,100,"%D %r",LocalTime(&t,GMT_TO_LOCAL));
-#elif defined(TZ_TIME)
- {
- strftime(TimeBuf,100,"%D:%T",LocalTime(&t,0));
- sprintf(TimeBuf+strlen(TimeBuf)," %+03d%02d",
- -TimeDiff(t)/(60*60),-(TimeDiff(t)/60)%60);
- }
-#else
- strftime(TimeBuf,100,"%D %T",LocalTime(&t,GMT_TO_LOCAL));
-#endif
- return(TimeBuf);
-}
-
-/****************************************************************************
determine whether we are in the specified group
****************************************************************************/
BOOL in_group(gid_t group, int current_gid, int ngroups, int *groups)
@@ -1033,159 +749,6 @@ uint32 file_size(char *file_name)
return(buf.st_size);
}
-/****************************************************************************
-check if it's a null mtime
-****************************************************************************/
-static BOOL null_mtime(time_t mtime)
-{
- if (mtime == 0 || mtime == 0xFFFFFFFF)
- return(True);
- return(False);
-}
-
-/*******************************************************************
- create a 16 bit dos packed date
-********************************************************************/
-static uint16 make_dos_date1(time_t unixdate,struct tm *t)
-{
- uint16 ret=0;
- ret = (((unsigned)(t->tm_mon+1)) >> 3) | ((t->tm_year-80) << 1);
- ret = ((ret&0xFF)<<8) | (t->tm_mday | (((t->tm_mon+1) & 0x7) << 5));
- return(ret);
-}
-
-/*******************************************************************
- create a 16 bit dos packed time
-********************************************************************/
-static uint16 make_dos_time1(time_t unixdate,struct tm *t)
-{
- uint16 ret=0;
- ret = ((((unsigned)t->tm_min >> 3)&0x7) | (((unsigned)t->tm_hour) << 3));
- ret = ((ret&0xFF)<<8) | ((t->tm_sec/2) | ((t->tm_min & 0x7) << 5));
- return(ret);
-}
-
-/*******************************************************************
- create a 32 bit dos packed date/time from some parameters
- This takes a GMT time and returns a packed localtime structure
-********************************************************************/
-static uint32 make_dos_date(time_t unixdate)
-{
- struct tm *t;
- uint32 ret=0;
-
- t = LocalTime(&unixdate,GMT_TO_LOCAL);
-
- ret = make_dos_date1(unixdate,t);
- ret = ((ret&0xFFFF)<<16) | make_dos_time1(unixdate,t);
-
- return(ret);
-}
-
-/*******************************************************************
-put a dos date into a buffer (time/date format)
-This takes GMT time and puts local time in the buffer
-********************************************************************/
-void put_dos_date(char *buf,int offset,time_t unixdate)
-{
- uint32 x = make_dos_date(unixdate);
- SIVAL(buf,offset,x);
-}
-
-/*******************************************************************
-put a dos date into a buffer (date/time format)
-This takes GMT time and puts local time in the buffer
-********************************************************************/
-void put_dos_date2(char *buf,int offset,time_t unixdate)
-{
- uint32 x = make_dos_date(unixdate);
- x = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
- SIVAL(buf,offset,x);
-}
-
-/*******************************************************************
-put a dos 32 bit "unix like" date into a buffer. This routine takes
-GMT and converts it to LOCAL time before putting it (most SMBs assume
-localtime for this sort of date)
-********************************************************************/
-void put_dos_date3(char *buf,int offset,time_t unixdate)
-{
- if (!null_mtime(unixdate))
- unixdate += GMT_TO_LOCAL*TimeDiff(unixdate);
- SIVAL(buf,offset,unixdate);
-}
-
-/*******************************************************************
- interpret a 32 bit dos packed date/time to some parameters
-********************************************************************/
-static void interpret_dos_date(uint32 date,int *year,int *month,int *day,int *hour,int *minute,int *second)
-{
- uint32 p0,p1,p2,p3;
-
- p0=date&0xFF; p1=((date&0xFF00)>>8)&0xFF;
- p2=((date&0xFF0000)>>16)&0xFF; p3=((date&0xFF000000)>>24)&0xFF;
-
- *second = 2*(p0 & 0x1F);
- *minute = ((p0>>5)&0xFF) + ((p1&0x7)<<3);
- *hour = (p1>>3)&0xFF;
- *day = (p2&0x1F);
- *month = ((p2>>5)&0xFF) + ((p3&0x1)<<3) - 1;
- *year = ((p3>>1)&0xFF) + 80;
-}
-
-/*******************************************************************
- create a unix date (int GMT) from a dos date (which is actually in
- localtime)
-********************************************************************/
-time_t make_unix_date(void *date_ptr)
-{
- uint32 dos_date=0;
- struct tm t;
- time_t ret;
-
- dos_date = IVAL(date_ptr,0);
-
- if (dos_date == 0) return(0);
-
- interpret_dos_date(dos_date,&t.tm_year,&t.tm_mon,
- &t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec);
- t.tm_wday = 1;
- t.tm_yday = 1;
- t.tm_isdst = -1;
-
- /* mktime() also does the local to GMT time conversion for us. XXXXX
- Do all unixes do this the same?? */
- ret = mktime(&t);
-
- return(ret);
-}
-
-/*******************************************************************
-like make_unix_date() but the words are reversed
-********************************************************************/
-time_t make_unix_date2(void *date_ptr)
-{
- uint32 x,x2;
-
- x = IVAL(date_ptr,0);
- x2 = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
- SIVAL(&x,0,x2);
-
- return(make_unix_date((void *)&x));
-}
-
-/*******************************************************************
- create a unix GMT date from a dos date in 32 bit "unix like" format
-these generally arrive as localtimes, with corresponding DST
-********************************************************************/
-time_t make_unix_date3(void *date_ptr)
-{
- time_t t = IVAL(date_ptr,0);
- if (!null_mtime(t))
- t += LOCAL_TO_GMT*TimeDiff(t);
- return(t);
-}
-
/*******************************************************************
return a string representing an attribute for a file
********************************************************************/
@@ -2119,11 +1682,10 @@ int read_udp_socket(int fd,char *buf,int len)
bzero((char *)&sock,socklen);
bzero((char *)&lastip,sizeof(lastip));
ret = recvfrom(fd,buf,len,0,&sock,&socklen);
- if (ret <= 0)
- {
- DEBUG(2,("read socket failed. ERRNO=%d\n",errno));
- return(0);
- }
+ if (ret <= 0) {
+ DEBUG(2,("read socket failed. ERRNO=%d\n",errno));
+ return(0);
+ }
lastip = *(struct in_addr *) &sock.sa_data[2];
lastport = ntohs(((struct sockaddr_in *)&sock)->sin_port);
@@ -2132,102 +1694,43 @@ int read_udp_socket(int fd,char *buf,int len)
}
/****************************************************************************
-Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
-else
-if SYSV use O_NDELAY
-if BSD use FNDELAY
-****************************************************************************/
-int set_blocking(int fd, BOOL set)
-{
-int val;
-#ifdef O_NONBLOCK
-#define FLAG_TO_SET O_NONBLOCK
-#else
-#ifdef SYSV
-#define FLAG_TO_SET O_NDELAY
-#else /* BSD */
-#define FLAG_TO_SET FNDELAY
-#endif
-#endif
-
- if((val = fcntl(fd, F_GETFL, 0))==-1)
- return -1;
- if(set) /* Turn blocking on - ie. clear nonblock flag */
- val &= ~FLAG_TO_SET;
- else
- val |= FLAG_TO_SET;
- return fcntl( fd, F_SETFL, val);
-#undef FLAG_TO_SET
-}
-
-
-/****************************************************************************
-Calculate the difference in timeout values. Return 1 if val1 > val2,
-0 if val1 == val2, -1 if val1 < val2. Stores result in retval. retval
-may be == val1 or val2
-****************************************************************************/
-static int tval_sub( struct timeval *retval, struct timeval *val1, struct timeval *val2)
-{
- int usecdiff = val1->tv_usec - val2->tv_usec;
- int secdiff = val1->tv_sec - val2->tv_sec;
- if(usecdiff < 0) {
- usecdiff = 1000000 + usecdiff;
- secdiff--;
- }
- retval->tv_sec = secdiff;
- retval->tv_usec = usecdiff;
- if(secdiff < 0)
- return -1;
- if(secdiff > 0)
- return 1;
- return (usecdiff < 0 ) ? -1 : ((usecdiff > 0 ) ? 1 : 0);
-}
-
-/****************************************************************************
read data from a device with a timout in msec.
mincount = if timeout, minimum to read before returning
maxcount = number to be read.
****************************************************************************/
-int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out,BOOL exact)
+int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out)
{
fd_set fds;
int selrtn;
int readret;
int nread = 0;
- struct timeval timeout, tval1, tval2, tvaldiff;
- int error_limit = 5;
+ struct timeval timeout;
/* just checking .... */
if (maxcnt <= 0) return(0);
- if(time_out == -2)
- time_out = DEFAULT_PIPE_TIMEOUT;
+ smb_read_error = 0;
/* Blocking read */
- if(time_out < 0) {
+ if (time_out <= 0) {
if (mincnt == 0) mincnt = maxcnt;
- while (nread < mincnt)
- {
- readret = read(fd, buf + nread, maxcnt - nread);
- if (readret <= 0) return(nread);
- nread += readret;
+ while (nread < mincnt) {
+ readret = read(fd, buf + nread, maxcnt - nread);
+ if (readret == 0) {
+ smb_read_error = READ_EOF;
+ return -1;
+ }
+
+ if (readret == -1) {
+ smb_read_error = READ_ERROR;
+ return -1;
}
+ nread += readret;
+ }
return(nread);
}
- /* Non blocking read */
- if(time_out == 0) {
- set_blocking(fd, False);
- nread = read_data(fd, buf, mincnt);
- if (nread < maxcnt)
- nread += read(fd,buf+nread,maxcnt-nread);
- if(nread == -1 && errno == EWOULDBLOCK)
- nread = 0;
- set_blocking(fd,True);
- return nread;
- }
-
/* Most difficult - timeout read */
/* If this is ever called on a disk file and
mincnt is greater then the filesize then
@@ -2238,71 +1741,40 @@ int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out,BOOL
timeout.tv_sec = time_out / 1000;
timeout.tv_usec = 1000 * (time_out % 1000);
- /* As most UNIXes don't modify the value of timeout
- when they return from select we need to get the timeofday (in usec)
- now, and also after the select returns so we know
- how much time has elapsed */
-
- if (exact)
- GetTimeOfDay( &tval1);
- nread = 0; /* Number of bytes we have read */
-
- for(;;)
+ for (nread=0; nread<mincnt; )
{
FD_ZERO(&fds);
FD_SET(fd,&fds);
selrtn = sys_select(&fds,&timeout);
-
+
/* Check if error */
if(selrtn == -1) {
- errno = EBADF;
+ /* something is wrong. Maybe the socket is dead? */
+ smb_read_error = READ_ERROR;
return -1;
}
/* Did we timeout ? */
if (selrtn == 0) {
- if (nread < mincnt) return -1;
- break; /* Yes */
+ smb_read_error = READ_TIMEOUT;
+ return -1;
}
readret = read(fd, buf+nread, maxcnt-nread);
- if (readret == 0 && nread < mincnt) {
- /* error_limit should not really be needed, but some systems
- do strange things ... I don't want to just continue
- indefinately in case we get an infinite loop */
- if (error_limit--) continue;
- return(-1);
+ if (readret == 0) {
+ /* we got EOF on the file descriptor */
+ smb_read_error = READ_EOF;
+ return -1;
}
- if (readret < 0) {
- /* force a particular error number for
- portability */
- DEBUG(5,("read gave error %s\n",strerror(errno)));
- errno = EBADF;
+ if (readret == -1) {
+ /* the descriptor is probably dead */
+ smb_read_error = READ_ERROR;
return -1;
}
nread += readret;
-
- /* If we have read more than mincnt then return */
- if (nread >= mincnt)
- break;
-
- /* We need to do another select - but first reduce the
- time_out by the amount of time already elapsed - if
- this is less than zero then return */
- if (exact) {
- GetTimeOfDay(&tval2);
- (void)tval_sub( &tvaldiff, &tval2, &tval1);
-
- if (tval_sub(&timeout, &timeout, &tvaldiff) <= 0)
- break; /* We timed out */
- }
-
- /* Save the time of day as we need to do the select
- again (saves a system call) */
- tval1 = tval2;
}
/* Return the number we got */
@@ -2369,16 +1841,19 @@ int read_data(int fd,char *buffer,int N)
int ret;
int total=0;
+ smb_read_error = 0;
+
while (total < N)
{
ret = read(fd,buffer + total,N - total);
-
- /* this is for portability */
- if (ret < 0)
- errno = EBADF;
-
- if (ret <= 0)
- return total;
+ if (ret == 0) {
+ smb_read_error = READ_EOF;
+ return 0;
+ }
+ if (ret == -1) {
+ smb_read_error = READ_ERROR;
+ return -1;
+ }
total += ret;
}
return total;
@@ -2397,8 +1872,8 @@ int write_data(int fd,char *buffer,int N)
{
ret = write(fd,buffer + total,N - total);
- if (ret <= 0)
- return total;
+ if (ret == -1) return -1;
+ if (ret == 0) return total;
total += ret;
}
@@ -2406,142 +1881,28 @@ int write_data(int fd,char *buffer,int N)
}
-/* variables used by the read prediction module */
-int rp_fd = -1;
-int rp_offset = 0;
-int rp_length = 0;
-int rp_alloced = 0;
-int rp_predict_fd = -1;
-int rp_predict_offset = 0;
-int rp_predict_length = 0;
-int rp_timeout = 5;
-time_t rp_time = 0;
-char *rp_buffer = NULL;
-BOOL predict_skip=False;
-time_t smb_last_time=(time_t)0;
-
-/****************************************************************************
-handle read prediction on a file
-****************************************************************************/
-int read_predict(int fd,int offset,char *buf,char **ptr,int num)
-{
- int ret = 0;
- int possible = rp_length - (offset - rp_offset);
-
- possible = MIN(possible,num);
-
- /* give data if possible */
- if (fd == rp_fd &&
- offset >= rp_offset &&
- possible>0 &&
- smb_last_time-rp_time < rp_timeout)
- {
- ret = possible;
- if (buf)
- memcpy(buf,rp_buffer + (offset-rp_offset),possible);
- else
- *ptr = rp_buffer + (offset-rp_offset);
- DEBUG(5,("read-prediction gave %d bytes of %d\n",ret,num));
- }
-
- if (ret == num) {
- predict_skip = True;
- } else {
- predict_skip = False;
-
- /* prepare the next prediction */
- rp_predict_fd = fd;
- rp_predict_offset = offset + num;
- rp_predict_length = num;
- }
-
- if (ret < 0) ret = 0;
-
- return(ret);
-}
-
-/****************************************************************************
-pre-read some data
-****************************************************************************/
-void do_read_prediction()
-{
- if (predict_skip) return;
-
- if (rp_predict_fd == -1)
- return;
-
- rp_fd = rp_predict_fd;
- rp_offset = rp_predict_offset;
- rp_length = 0;
-
- rp_predict_fd = -1;
-
- rp_predict_length = MIN(rp_predict_length,2*ReadSize);
- rp_predict_length = MAX(rp_predict_length,1024);
- rp_offset = (rp_offset/1024)*1024;
- rp_predict_length = (rp_predict_length/1024)*1024;
-
- if (rp_predict_length > rp_alloced)
- {
- rp_buffer = Realloc(rp_buffer,rp_predict_length);
- rp_alloced = rp_predict_length;
- if (!rp_buffer)
- {
- DEBUG(0,("can't allocate read-prediction buffer\n"));
- rp_predict_fd = -1;
- rp_fd = -1;
- rp_alloced = 0;
- return;
- }
- }
-
- if (lseek(rp_fd,rp_offset,SEEK_SET) != rp_offset) {
- rp_fd = -1;
- rp_predict_fd = -1;
- return;
- }
-
- rp_length = read(rp_fd,rp_buffer,rp_predict_length);
- rp_time = time(NULL);
- if (rp_length < 0)
- rp_length = 0;
-}
-
-/****************************************************************************
-invalidate read-prediction on a fd
-****************************************************************************/
-void invalidate_read_prediction(int fd)
-{
- if (rp_fd == fd)
- rp_fd = -1;
- if (rp_predict_fd == fd)
- rp_predict_fd = -1;
-}
-
-
/****************************************************************************
transfer some data between two fd's
****************************************************************************/
int transfer_file(int infd,int outfd,int n,char *header,int headlen,int align)
{
static char *buf=NULL;
+ static int size=0;
char *buf1,*abuf;
- static int size = 0;
int total = 0;
DEBUG(4,("transfer_file %d (head=%d) called\n",n,headlen));
- if ((size < ReadSize) && buf) {
- free(buf);
- buf = NULL;
+ if (size == 0) {
+ size = lp_readsize();
+ size = MAX(size,1024);
}
- size = MAX(ReadSize,1024);
-
while (!buf && size>0) {
buf = (char *)Realloc(buf,size+8);
if (!buf) size /= 2;
}
+
if (!buf) {
DEBUG(0,("Can't allocate transfer buffer!\n"));
exit(1);
@@ -2616,30 +1977,19 @@ int read_smb_length(int fd,char *inbuf,int timeout)
while (!ok)
{
if (timeout > 0)
- ok = (read_with_timeout(fd,buffer,4,4,timeout,False) == 4);
- else
+ ok = (read_with_timeout(fd,buffer,4,4,timeout) == 4);
+ else
ok = (read_data(fd,buffer,4) == 4);
if (!ok)
- {
- if (timeout>0)
- {
- DEBUG(10,("select timeout (%d)\n", timeout));
- return(-1);
- }
- else
- {
- DEBUG(6,("couldn't read from client\n"));
- exit(1);
- }
- }
+ return(-1);
len = smb_len(buffer);
msg_type = CVAL(buffer,0);
if (msg_type == 0x85)
{
- DEBUG(5,( "Got keepalive packet\n"));
+ DEBUG(5,("Got keepalive packet\n"));
ok = False;
}
}
@@ -2657,8 +2007,9 @@ The timeout is in milli seconds
****************************************************************************/
BOOL receive_smb(int fd,char *buffer,int timeout)
{
- int len;
- BOOL ok;
+ int len,ret;
+
+ smb_read_error = 0;
bzero(buffer,smb_size + 100);
@@ -2666,20 +2017,17 @@ BOOL receive_smb(int fd,char *buffer,int timeout)
if (len == -1)
return(False);
- if (len > BUFFER_SIZE)
- {
- DEBUG(0,("Invalid packet length! (%d bytes)\n",len));
- if (len > BUFFER_SIZE + (SAFETY_MARGIN/2))
- exit(1);
- }
-
- ok = (read_data(fd,buffer+4,len) == len);
-
- if (!ok)
- {
- close_sockets();
+ if (len > BUFFER_SIZE) {
+ DEBUG(0,("Invalid packet length! (%d bytes).\n",len));
+ if (len > BUFFER_SIZE + (SAFETY_MARGIN/2))
exit(1);
- }
+ }
+
+ ret = read_data(fd,buffer+4,len);
+ if (ret != len) {
+ smb_read_error = READ_ERROR;
+ return False;
+ }
return(True);
}
@@ -3102,216 +2450,6 @@ void become_daemon(void)
#endif
}
-/****************************************************************************
-calculate the default netmask for an address
-****************************************************************************/
-static void default_netmask(struct in_addr *inm, struct in_addr *iad)
-{
- unsigned long ad = ntohl(iad->s_addr);
- unsigned long nm;
- /*
- ** Guess a netmask based on the class of the IP address given.
- */
- if ( (ad & 0x80000000) == 0 ) {
- /* class A address */
- nm = 0xFF000000;
- } else if ( (ad & 0xC0000000) == 0x80000000 ) {
- /* class B address */
- nm = 0xFFFF0000;
- } else if ( (ad & 0xE0000000) == 0xC0000000 ) {
- /* class C address */
- nm = 0xFFFFFF00;
- } else {
- /* class D or E; netmask doesn't make much sense - guess 4 bits */
- nm = 0xFFFFFFF0;
- }
- inm->s_addr = htonl(nm);
-}
-
-/****************************************************************************
- get the broadcast address for our address
-(troyer@saifr00.ateng.az.honeywell.com)
-****************************************************************************/
-void get_broadcast(struct in_addr *if_ipaddr,
- struct in_addr *if_bcast,
- struct in_addr *if_nmask)
-{
- BOOL found = False;
-#ifndef NO_GET_BROADCAST
- int sock = -1; /* AF_INET raw socket desc */
- char buff[1024];
- struct ifreq *ifr=NULL;
- int i;
-
-#if defined(EVEREST)
- int n_interfaces;
- struct ifconf ifc;
- struct ifreq *ifreqs;
-#elif defined(USE_IFREQ)
- struct ifreq ifreq;
- struct strioctl strioctl;
- struct ifconf *ifc;
-#else
- struct ifconf ifc;
-#endif
-#endif
-
- /* get a default netmask and broadcast */
- default_netmask(if_nmask, if_ipaddr);
-
-#ifndef NO_GET_BROADCAST
- /* Create a socket to the INET kernel. */
-#if USE_SOCKRAW
- if ((sock = socket(AF_INET, SOCK_RAW, PF_INET )) < 0)
-#else
- if ((sock = socket(AF_INET, SOCK_DGRAM, 0 )) < 0)
-#endif
- {
- DEBUG(0,( "Unable to open socket to get broadcast address\n"));
- return;
- }
-
- /* Get a list of the configured interfaces */
-#ifdef EVEREST
- /* This is part of SCO Openserver 5: The ioctls are no longer part
- if the lower level STREAMS interface glue. They are now real
- ioctl calls */
-
- if (ioctl(sock, SIOCGIFANUM, &n_interfaces) < 0) {
- DEBUG(0,( "SIOCGIFANUM: %s\n", strerror(errno)));
- } else {
- DEBUG(0,( "number of interfaces returned is: %d\n", n_interfaces));
-
- ifc.ifc_len = sizeof(struct ifreq) * n_interfaces;
- ifc.ifc_buf = (caddr_t) alloca(ifc.ifc_len);
-
- if (ioctl(sock, SIOCGIFCONF, &ifc) < 0)
- DEBUG(0, ( "SIOCGIFCONF: %s\n", strerror(errno)));
- else {
- ifr = ifc.ifc_req;
-
- for (i = 0; i < n_interfaces; ++i) {
- if (if_ipaddr->s_addr ==
- ((struct sockaddr_in *) &ifr[i].ifr_addr)->sin_addr.s_addr) {
- found = True;
- break;
- }
- }
- }
- }
-#elif defined(USE_IFREQ)
- ifc = (struct ifconf *)buff;
- ifc->ifc_len = BUFSIZ - sizeof(struct ifconf);
- strioctl.ic_cmd = SIOCGIFCONF;
- strioctl.ic_dp = (char *)ifc;
- strioctl.ic_len = sizeof(buff);
- if (ioctl(sock, I_STR, &strioctl) < 0) {
- DEBUG(0,( "I_STR/SIOCGIFCONF: %s\n", strerror(errno)));
- } else {
- ifr = (struct ifreq *)ifc->ifc_req;
-
- /* Loop through interfaces, looking for given IP address */
- for (i = ifc->ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) {
- if (if_ipaddr->s_addr ==
- (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) {
- found = True;
- break;
- }
- }
- }
-#elif defined(__FreeBSD__) || defined(NETBSD)
- ifc.ifc_len = sizeof(buff);
- ifc.ifc_buf = buff;
- if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
- DEBUG(0,("SIOCGIFCONF: %s\n", strerror(errno)));
- } else {
- ifr = ifc.ifc_req;
- /* Loop through interfaces, looking for given IP address */
- i = ifc.ifc_len;
- while (i > 0) {
- if (if_ipaddr->s_addr ==
- (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) {
- found = True;
- break;
- }
- i -= ifr->ifr_addr.sa_len + IFNAMSIZ;
- ifr = (struct ifreq*) ((char*) ifr + ifr->ifr_addr.sa_len + IFNAMSIZ);
- }
- }
-#else
- ifc.ifc_len = sizeof(buff);
- ifc.ifc_buf = buff;
- if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
- DEBUG(0,("SIOCGIFCONF: %s\n", strerror(errno)));
- } else {
- ifr = ifc.ifc_req;
-
- /* Loop through interfaces, looking for given IP address */
- for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) {
-#ifdef BSDI
- if (ioctl(sock, SIOCGIFADDR, ifr) < 0) break;
-#endif
- if (if_ipaddr->s_addr ==
- (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) {
- found = True;
- break;
- }
- }
- }
-#endif
-
- if (!found) {
- DEBUG(0,("No interface found for address %s\n", inet_ntoa(*if_ipaddr)));
- } else {
- /* Get the netmask address from the kernel */
-#ifdef USE_IFREQ
- ifreq = *ifr;
-
- strioctl.ic_cmd = SIOCGIFNETMASK;
- strioctl.ic_dp = (char *)&ifreq;
- strioctl.ic_len = sizeof(struct ifreq);
- if (ioctl(sock, I_STR, &strioctl) < 0)
- DEBUG(0,("Failed I_STR/SIOCGIFNETMASK: %s\n", strerror(errno)));
- else
- *if_nmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
-#else
- if (ioctl(sock, SIOCGIFNETMASK, ifr) < 0)
- DEBUG(0,("SIOCGIFNETMASK failed\n"));
- else
- *if_nmask = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
-#endif
-
- DEBUG(2,("Netmask for %s = %s\n", ifr->ifr_name,
- inet_ntoa(*if_nmask)));
- }
-
- /* Close up shop */
- (void) close(sock);
-
-#endif
-
- /* sanity check on the netmask */
- {
- unsigned long nm = ntohl(if_nmask->s_addr);
- if ((nm >> 24) != 0xFF) {
- DEBUG(0,("Impossible netmask %s - using defaults\n",inet_ntoa(*if_nmask)));
- default_netmask(if_nmask, if_ipaddr);
- }
- }
-
- /* derive the broadcast assuming a 1's broadcast, as this is what
- all MS operating systems do, we have to comply even if the unix
- box is setup differently */
- {
- unsigned long ad = ntohl(if_ipaddr->s_addr);
- unsigned long nm = ntohl(if_nmask->s_addr);
- unsigned long bc = (ad & nm) | (0xffffffff & ~nm);
- if_bcast->s_addr = htonl(bc);
- }
-
- DEBUG(2,("Derived broadcast address %s\n", inet_ntoa(*if_bcast)));
-} /* get_broadcast */
-
/****************************************************************************
put up a yes/no prompt
@@ -3462,7 +2600,7 @@ int byte_checksum(char *buf,int len)
/****************************************************************************
this is a version of setbuffer() for those machines that only have setvbuf
****************************************************************************/
-void setbuffer(FILE *f,char *buf,int bufsize)
+ void setbuffer(FILE *f,char *buf,int bufsize)
{
setvbuf(f,buf,_IOFBF,bufsize);
}
@@ -3512,6 +2650,13 @@ expand a pointer to be a particular size
void *Realloc(void *p,int size)
{
void *ret=NULL;
+
+ if (size == 0) {
+ if (p) free(p);
+ DEBUG(5,("Realloc asked for 0 bytes\n"));
+ return NULL;
+ }
+
if (!p)
ret = (void *)malloc(size);
else
@@ -3523,30 +2668,11 @@ void *Realloc(void *p,int size)
return(ret);
}
-/****************************************************************************
-set the time on a file
-****************************************************************************/
-BOOL set_filetime(char *fname,time_t mtime)
-{
- struct utimbuf times;
-
- if (null_mtime(mtime)) return(True);
-
- times.modtime = times.actime = mtime;
-
- if (sys_utime(fname,&times)) {
- DEBUG(4,("set_filetime(%s) failed: %s\n",fname,strerror(errno)));
- }
-
- return(True);
-}
-
-
#ifdef NOSTRDUP
/****************************************************************************
duplicate a string
****************************************************************************/
-char *strdup(char *s)
+ char *strdup(char *s)
{
char *ret = NULL;
if (!s) return(NULL);
@@ -3567,90 +2693,6 @@ void Abort(void )
exit(2);
}
-
-#ifdef REPLACE_STRLEN
-/****************************************************************************
-a replacement strlen() that returns int for solaris
-****************************************************************************/
-int Strlen(char *s)
-{
- int ret=0;
- if (!s) return(0);
- while (*s++) ret++;
- return(ret);
-}
-#endif
-
-
-/****************************************************************************
-return a time at the start of the current month
-****************************************************************************/
-time_t start_of_month(void)
-{
- time_t t = time(NULL);
- struct tm *t2;
-
- t2 = gmtime(&t);
-
- t2->tm_mday = 1;
- t2->tm_hour = 0;
- t2->tm_min = 0;
- t2->tm_sec = 0;
-
- return(mktime(t2));
-}
-
-
-/*******************************************************************
- check for a sane unix date
-********************************************************************/
-BOOL sane_unix_date(time_t unixdate)
-{
- struct tm t,today;
- time_t t_today = time(NULL);
-
- t = *(LocalTime(&unixdate,LOCAL_TO_GMT));
- today = *(LocalTime(&t_today,LOCAL_TO_GMT));
-
- if (t.tm_year < 80)
- return(False);
-
- if (t.tm_year > today.tm_year)
- return(False);
-
- if (t.tm_year == today.tm_year &&
- t.tm_mon > today.tm_mon)
- return(False);
-
-
- if (t.tm_year == today.tm_year &&
- t.tm_mon == today.tm_mon &&
- t.tm_mday > (today.tm_mday+1))
- return(False);
-
- return(True);
-}
-
-
-
-#ifdef NO_FTRUNCATE
- /*******************************************************************
-ftruncate for operating systems that don't have it
-********************************************************************/
-int ftruncate(int f,long l)
-{
- struct flock fl;
-
- fl.l_whence = 0;
- fl.l_len = 0;
- fl.l_start = l;
- fl.l_type = F_WRLCK;
- return fcntl(f, F_FREESP, &fl);
-}
-#endif
-
-
-
/****************************************************************************
get my own name and IP
****************************************************************************/
@@ -3714,11 +2756,7 @@ int open_socket_in(int type, int port, int dlevel)
int res;
/* get my host name */
-#ifdef MAXHOSTNAMELEN
if (gethostname(host_name, MAXHOSTNAMELEN) == -1)
-#else
- if (gethostname(host_name, sizeof(host_name)) == -1)
-#endif
{ DEBUG(0,("gethostname failed\n")); return -1; }
/* get host info */
@@ -3749,7 +2787,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);
@@ -3879,7 +2917,7 @@ struct in_addr *interpret_addr2(char *str)
{
static struct in_addr ret;
unsigned long a = interpret_addr(str);
- putip((char *)&ret,(char *)&a);
+ ret.s_addr = a;
return(&ret);
}
@@ -3893,76 +2931,6 @@ BOOL zero_ip(struct in_addr ip)
return(a == 0);
}
-#define TIME_FIXUP_CONSTANT (369.0*365.25*24*60*60-(3.0*24*60*60+6.0*60*60))
-
-/****************************************************************************
-interpret an 8 byte "filetime" structure to a time_t
-It's originally in "100ns units since jan 1st 1601"
-
-It appears to be kludge-GMT (at least for file listings). This means
-its the GMT you get by taking a localtime and adding the
-serverzone. This is NOT the same as GMT in some cases. This routine
-converts this to real GMT.
-****************************************************************************/
-time_t interpret_long_date(char *p)
-{
- double d;
- time_t ret;
- uint32 tlow,thigh;
- tlow = IVAL(p,0);
- thigh = IVAL(p,4);
-
- if (thigh == 0) return(0);
-
- d = ((double)thigh)*4.0*(double)(1<<30);
- d += (tlow&0xFFF00000);
- d *= 1.0e-7;
-
- /* now adjust by 369 years to make the secs since 1970 */
- d -= TIME_FIXUP_CONSTANT;
-
- if (d>=MAXINT)
- return(0);
-
- ret = (time_t)(d+0.5);
-
- /* this takes us from kludge-GMT to real GMT */
- ret += TimeDiff(ret) - serverzone;
-
- return(ret);
-}
-
-
-/****************************************************************************
-put a 8 byte filetime from a time_t
-This takes real GMT as input and converts to kludge-GMT
-****************************************************************************/
-void put_long_date(char *p,time_t t)
-{
- uint32 tlow,thigh;
- double d;
-
- if (t==0) {
- SIVAL(p,0,0); SIVAL(p,4,0);
- return;
- }
-
- /* this converts GMT to kludge-GMT */
- t -= TimeDiff(t) - serverzone;
-
- d = (double) (t);
-
- d += TIME_FIXUP_CONSTANT;
-
- d *= 1.0e7;
-
- thigh = (uint32)(d * (1.0/(4.0*(double)(1<<30))));
- tlow = (uint32)(d - ((double)thigh)*4.0*(double)(1<<30));
-
- SIVAL(p,0,tlow);
- SIVAL(p,4,thigh);
-}
-
/*******************************************************************
sub strings with useful parameters
********************************************************************/
@@ -4007,6 +2975,21 @@ void standard_sub_basic(char *s)
/*******************************************************************
+are two IPs on the same subnet?
+********************************************************************/
+BOOL same_net(struct in_addr ip1,struct in_addr ip2,struct in_addr mask)
+{
+ unsigned long net1,net2,nmask;
+
+ nmask = ntohl(mask.s_addr);
+ net1 = ntohl(ip1.s_addr);
+ net2 = ntohl(ip2.s_addr);
+
+ return((net1 & nmask) == (net2 & nmask));
+}
+
+
+/*******************************************************************
write a string in unicoode format
********************************************************************/
int PutUniCode(char *dst,char *src)
@@ -4022,34 +3005,6 @@ int PutUniCode(char *dst,char *src)
return(ret);
}
-
-pstring smbrun_path = SMBRUN;
-
-/****************************************************************************
-run a command via system() using smbrun
-****************************************************************************/
-int smbrun(char *cmd,char *outfile)
-{
- int ret;
- pstring syscmd;
-
- if (!file_exist(smbrun_path,NULL))
- {
- DEBUG(0,("SMBRUN ERROR: Can't find %s. Installation problem?\n",smbrun_path));
- return(1);
- }
-
- sprintf(syscmd,"%s \"(%s 2>&1) > %s\"",
- smbrun_path,cmd,
- outfile?outfile:"/dev/null");
-
- DEBUG(5,("smbrun - running %s ",syscmd));
- ret = system(syscmd);
- DEBUG(5,("gave %d\n",ret));
- return(ret);
-}
-
-
/****************************************************************************
a wrapper for gethostbyname() that tries with all lower and all upper case
if the initial name fails
@@ -4172,7 +3127,7 @@ void BlockSignals(BOOL block)
if (block)
sigblock(block_mask);
else
- sigunblock(block_mask);
+ sigsetmask(0);
#endif
}
@@ -4182,8 +3137,7 @@ my own panic function - not suitable for general use
********************************************************************/
void ajt_panic(void)
{
- pstring cmd = "/usr/bin/X11/xedit -display :0 /tmp/ERROR_FAULT &";
- smbrun(cmd,NULL);
+ system("/usr/bin/X11/xedit -display :0 /tmp/ERROR_FAULT");
}
#endif
@@ -4242,269 +3196,3 @@ char *readdirname(void *p)
-#if (defined(SecureWare) && defined(SCO))
-/* This is needed due to needing the nap() function but we don't want
- to include the Xenix libraries since that will break other things...
- BTW: system call # 0x0c28 is the same as calling nap() */
-long nap(long milliseconds) {
- return syscall(0x0c28, milliseconds);
-}
-#endif
-
-#ifdef NO_INITGROUPS
-#include <sys/types.h>
-#include <limits.h>
-#include <grp.h>
-
-#ifndef NULL
-#define NULL (void *)0
-#endif
-
-/****************************************************************************
- some systems don't have an initgroups call
-****************************************************************************/
-int initgroups(char *name,gid_t id)
-{
-#ifdef NO_SETGROUPS
- /* yikes! no SETGROUPS or INITGROUPS? how can this work? */
- return(0);
-#else
- gid_t grouplst[NGROUPS_MAX];
- int i,j;
- struct group *g;
- char *gr;
-
- grouplst[0] = id;
- i = 1;
- while (i < NGROUPS_MAX &&
- ((g = (struct group *)getgrent()) != (struct group *)NULL))
- {
- if (g->gr_gid == id)
- continue;
- j = 0;
- gr = g->gr_mem[0];
- while (gr && (*gr != (char)NULL)) {
- if (strcmp(name,gr) == 0) {
- grouplst[i] = g->gr_gid;
- i++;
- gr = (char *)NULL;
- break;
- }
- gr = g->gr_mem[++j];
- }
- }
- endgrent();
- return(setgroups(i,grouplst));
-#endif
-}
-#endif
-
-
-#if WRAP_MALLOC
-
-/* undo the wrapping temporarily */
-#undef malloc
-#undef realloc
-#undef free
-
-/****************************************************************************
-wrapper for malloc() to catch memory errors
-****************************************************************************/
-void *malloc_wrapped(int size,char *file,int line)
-{
-#ifdef xx_old_malloc
- void *res = xx_old_malloc(size);
-#else
- void *res = malloc(size);
-#endif
- DEBUG(3,("Malloc called from %s(%d) with size=%d gave ptr=0x%X\n",
- file,line,
- size,(unsigned int)res));
- return(res);
-}
-
-/****************************************************************************
-wrapper for realloc() to catch memory errors
-****************************************************************************/
-void *realloc_wrapped(void *ptr,int size,char *file,int line)
-{
-#ifdef xx_old_realloc
- void *res = xx_old_realloc(ptr,size);
-#else
- void *res = realloc(ptr,size);
-#endif
- DEBUG(3,("Realloc\n"));
- DEBUG(3,("free called from %s(%d) with ptr=0x%X\n",
- file,line,
- (unsigned int)ptr));
- DEBUG(3,("Malloc called from %s(%d) with size=%d gave ptr=0x%X\n",
- file,line,
- size,(unsigned int)res));
- return(res);
-}
-
-/****************************************************************************
-wrapper for free() to catch memory errors
-****************************************************************************/
-void free_wrapped(void *ptr,char *file,int line)
-{
-#ifdef xx_old_free
- xx_old_free(ptr);
-#else
- free(ptr);
-#endif
- DEBUG(3,("free called from %s(%d) with ptr=0x%X\n",
- file,line,(unsigned int)ptr));
- return;
-}
-
-/* and re-do the define for spots lower in this file */
-#define malloc(size) malloc_wrapped(size,__FILE__,__LINE__)
-#define realloc(ptr,size) realloc_wrapped(ptr,size,__FILE__,__LINE__)
-#define free(ptr) free_wrapped(ptr,__FILE__,__LINE__)
-
-#endif
-
-#ifdef REPLACE_STRSTR
-/****************************************************************************
-Mips version of strstr doesn't seem to work correctly.
-There is a #define in includes.h to redirect calls to this function.
-****************************************************************************/
-char *Strstr(char *s, char *p)
-{
- int len = strlen(p);
-
- while ( *s != '\0' ) {
- if ( strncmp(s, p, len) == 0 )
- return s;
- s++;
- }
-
- return NULL;
-}
-#endif /* REPLACE_STRSTR */
-
-
-#ifdef REPLACE_MKTIME
-/*******************************************************************
-a mktime() replacement for those who don't have it - contributed by
-C.A. Lademann <cal@zls.com>
-********************************************************************/
-#define MINUTE 60
-#define HOUR 60*MINUTE
-#define DAY 24*HOUR
-#define YEAR 365*DAY
-time_t Mktime(struct tm *t)
-{
- struct tm *u;
- time_t epoch = 0;
- int mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
- y, m, i;
-
- if(t->tm_year < 70)
- return((time_t)-1);
-
- epoch = (t->tm_year - 70) * YEAR +
- (t->tm_year / 4 - 70 / 4 - t->tm_year / 100) * DAY;
-
- y = t->tm_year;
- m = 0;
-
- for(i = 0; i < t->tm_mon; i++) {
- epoch += mon [m] * DAY;
- if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
- epoch += DAY;
-
- if(++m > 11) {
- m = 0;
- y++;
- }
- }
-
- epoch += (t->tm_mday - 1) * DAY;
- epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec;
-
- if((u = localtime(&epoch)) != NULL) {
- t->tm_sec = u->tm_sec;
- t->tm_min = u->tm_min;
- t->tm_hour = u->tm_hour;
- t->tm_mday = u->tm_mday;
- t->tm_mon = u->tm_mon;
- t->tm_year = u->tm_year;
- t->tm_wday = u->tm_wday;
- t->tm_yday = u->tm_yday;
- t->tm_isdst = u->tm_isdst;
-#ifndef NO_TM_NAME
- memcpy(t->tm_name, u->tm_name, LTZNMAX);
-#endif
- }
-
- return(epoch);
-}
-#endif /* REPLACE_MKTIME */
-
-
-
-#ifdef REPLACE_RENAME
-/* Rename a file. (from libiberty in GNU binutils) */
-int
-rename (zfrom, zto)
- const char *zfrom;
- const char *zto;
-{
- if (link (zfrom, zto) < 0)
- {
- if (errno != EEXIST)
- return -1;
- if (unlink (zto) < 0
- || link (zfrom, zto) < 0)
- return -1;
- }
- return unlink (zfrom);
-}
-#endif
-
-
-#ifdef REPLACE_INNETGR
-/*
- * Search for a match in a netgroup. This replaces it on broken systems.
- */
-int InNetGr(group, host, user, dom)
- char *group, *host, *user, *dom;
-{
- char *hst, *usr, *dm;
-
- setnetgrent(group);
- while (getnetgrent(&hst, &usr, &dm))
- if (((host == 0) || (hst == 0) || !strcmp(host, hst)) &&
- ((user == 0) || (usr == 0) || !strcmp(user, usr)) &&
- ((dom == 0) || (dm == 0) || !strcmp(dom, dm))) {
- endnetgrent();
- return (1);
- }
- endnetgrent();
- return (0);
-}
-#endif
-
-
-#if WRAP_MEMCPY
-#undef memcpy
-/*******************************************************************
-a wrapper around memcpy for diagnostic purposes
-********************************************************************/
-void *memcpy_wrapped(void *d,void *s,int l,char *fname,int line)
-{
- if (l>64 && (((int)d)%4) != (((int)s)%4))
- DEBUG(4,("Misaligned memcpy(0x%X,0x%X,%d) at %s(%d)\n",d,s,l,fname,line));
-#ifdef xx_old_memcpy
- return(xx_old_memcpy(d,s,l));
-#else
- return(memcpy(d,s,l));
-#endif
-}
-#define memcpy(d,s,l) memcpy_wrapped(d,s,l,__FILE__,__LINE__)
-#endif
-
-
-
diff --git a/source/libsmb/namequery.c b/source/libsmb/namequery.c
new file mode 100644
index 00000000000..f1847e38baa
--- /dev/null
+++ b/source/libsmb/namequery.c
@@ -0,0 +1,296 @@
+/*
+ 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,"H ");
+ 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 = False;
+ nmb->header.nm_flags.recursion_desired = False;
+ 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;
+ debug_nmb_packet(p2);
+
+ 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 = False;
+ nmb->header.nm_flags.recursion_desired = True;
+ 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;
+ debug_nmb_packet(p2);
+
+ if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
+ !nmb2->header.response) {
+ /* its not for us - maybe deal with it later
+ (put it on the queue?) */
+ if (fn)
+ fn(p2);
+ else
+ free_packet(p2);
+ continue;
+ }
+
+ if (nmb2->header.opcode != 0 ||
+ nmb2->header.nm_flags.bcast ||
+ nmb2->header.rcode ||
+ !nmb2->header.ancount) {
+ /* XXXX what do we do with this? could be a redirect, but
+ we'll discard it for the moment */
+ free_packet(p2);
+ continue;
+ }
+
+ if (ip) {
+ putip((char *)ip,&nmb2->answers->rdata[2]);
+ DEBUG(fn?3:2,("Got a positive name query response from %s",
+ inet_ntoa(p2->ip)));
+ DEBUG(fn?3:2,(" (%s)\n",inet_ntoa(*ip)));
+ }
+ found=True; retries=0;
+ free_packet(p2);
+ if (fn) break;
+ }
+ }
+
+ return(found);
+}
diff --git a/source/libsmb/nmblib.c b/source/libsmb/nmblib.c
index 67432271737..4113b34cab4 100644
--- a/source/libsmb/nmblib.c
+++ b/source/libsmb/nmblib.c
@@ -21,15 +21,101 @@
*/
#include "includes.h"
-#include "nameserv.h"
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 +124,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 +140,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 +271,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,7 +466,7 @@ 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);
@@ -413,7 +497,7 @@ struct packet_struct *read_packet(int fd,enum packet_type packet_type)
num_good_receives++;
- DEBUG(4,("%s received a packet of len %d from (%s) port %d\n",
+ DEBUG(5,("%s received a packet of len %d from (%s) port %d\n",
timestring(),length,inet_ntoa(packet->ip),packet->port));
return(packet);
@@ -434,7 +518,7 @@ static BOOL send_udp(int fd,char *buf,int len,struct in_addr ip,int port)
sock_out.sin_port = htons( port );
sock_out.sin_family = AF_INET;
- DEBUG(4,("%s sending a packet of len %d to (%s) on port %d\n",
+ DEBUG(5,("%s sending a packet of len %d to (%s) on port %d\n",
timestring(),len,inet_ntoa(ip),port));
ret = (sendto(fd,buf,len,0,(struct sockaddr *)&sock_out,
@@ -525,9 +609,11 @@ static int build_nmb(char *buf,struct packet_struct *p)
if (nmb->header.nm_flags.authoritative) ubuf[offset+2] |= 0x4;
if (nmb->header.nm_flags.trunc) ubuf[offset+2] |= 0x2;
if (nmb->header.nm_flags.recursion_desired) ubuf[offset+2] |= 0x1;
- if (nmb->header.nm_flags.recursion_available) ubuf[offset+3] |= 0x80;
+ if (nmb->header.nm_flags.recursion_available &&
+ nmb->header.response) 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,330 +693,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;
- *flags = 0;
- StrnCpy(qname,p,15);
- type = CVAL(p,15);
- p += 16;
-
- if (p[0] & 0x80) strcat(flags,"<GROUP> ");
- if ((p[0] & 0x60) == 0) strcat(flags,"B ");
- if ((p[0] & 0x60) == 1) strcat(flags,"P ");
- if ((p[0] & 0x60) == 2) strcat(flags,"M ");
- if ((p[0] & 0x60) == 3) 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," ");
- }
-
- DEBUG(level,("\t%s (type=0x%x)\t%s\n",qname,type,flags));
- p+=2;
- }
- DEBUG(level,("num_good_sends=%d num_good_receives=%d\n",
- IVAL(p,20),IVAL(p,24)));
-}
-
-
-/****************************************************************************
- do a netbios name status query on a host
-
- the "master" parameter is a hack used for finding workgroups.
- **************************************************************************/
-BOOL name_status(int fd,char *name,int name_type,BOOL recurse,
- struct in_addr to_ip,char *master,char *rname,
- void (*fn)())
-{
- BOOL found=False;
- int retries = 2;
- int retry_time = 5000;
- struct timeval tval;
- struct packet_struct p;
- struct packet_struct *p2;
- struct nmb_packet *nmb = &p.packet.nmb;
-
- bzero((char *)&p,sizeof(p));
-
- if (!name_trn_id) name_trn_id = (time(NULL)%(unsigned)0x7FFF) +
- (getpid()%(unsigned)100);
- name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
-
- nmb->header.name_trn_id = name_trn_id;
- nmb->header.opcode = 0;
- nmb->header.response = False;
- nmb->header.nm_flags.bcast = False;
- nmb->header.nm_flags.recursion_available = CanRecurse;
- nmb->header.nm_flags.recursion_desired = recurse;
- nmb->header.nm_flags.trunc = False;
- nmb->header.nm_flags.authoritative = False;
- nmb->header.rcode = 0;
- nmb->header.qdcount = 1;
- nmb->header.ancount = 0;
- nmb->header.nscount = 0;
- nmb->header.arcount = 0;
-
- make_nmb_name(&nmb->question.question_name,name,name_type,scope);
-
- nmb->question.question_type = 0x21;
- nmb->question.question_class = 0x1;
-
- p.ip = to_ip;
- p.port = NMB_PORT;
- p.fd = fd;
- p.timestamp = time(NULL);
- p.packet_type = NMB_PACKET;
-
- GetTimeOfDay(&tval);
-
- if (!send_packet(&p))
- return(False);
-
- retries--;
-
- while (1)
- {
- struct timeval tval2;
- GetTimeOfDay(&tval2);
- if (TvalDiff(&tval,&tval2) > retry_time) {
- if (!retries) break;
- if (!found && !send_packet(&p))
- return False;
- GetTimeOfDay(&tval);
- retries--;
- }
-
- if ((p2=receive_packet(fd,NMB_PACKET,90)))
- {
- struct nmb_packet *nmb2 = &p2->packet.nmb;
- if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
- !nmb2->header.response) {
- /* its not for us - maybe deal with it later */
- if (fn)
- fn(p2);
- else
- free_packet(p2);
- continue;
- }
-
- if (nmb2->header.opcode != 0 ||
- nmb2->header.nm_flags.bcast ||
- nmb2->header.rcode ||
- !nmb2->header.ancount ||
- nmb2->answers->rr_type != 0x21) {
- /* XXXX what do we do with this? could be a redirect, but
- we'll discard it for the moment */
- free_packet(p2);
- continue;
- }
-
- interpret_node_status(&nmb2->answers->rdata[0], master,rname);
- free_packet(p2);
- return(True);
- }
- }
-
-
- DEBUG(0,("No status response (this is not unusual)\n"));
-
- return(False);
-}
-
-
-/****************************************************************************
- do a netbios name query to find someones IP
- ****************************************************************************/
-BOOL name_query(int fd,char *name,int name_type,
- BOOL bcast,BOOL recurse,
- struct in_addr to_ip, struct in_addr *ip,void (*fn)())
-{
- BOOL found=False;
- int retries = 3;
- int retry_time = bcast?250:2000;
- struct timeval tval;
- struct packet_struct p;
- struct packet_struct *p2;
- struct nmb_packet *nmb = &p.packet.nmb;
-
- bzero((char *)&p,sizeof(p));
-
- if (!name_trn_id) name_trn_id = (time(NULL)%(unsigned)0x7FFF) +
- (getpid()%(unsigned)100);
- name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
-
- nmb->header.name_trn_id = name_trn_id;
- nmb->header.opcode = 0;
- nmb->header.response = False;
- nmb->header.nm_flags.bcast = bcast;
- nmb->header.nm_flags.recursion_available = CanRecurse;
- nmb->header.nm_flags.recursion_desired = recurse;
- nmb->header.nm_flags.trunc = False;
- nmb->header.nm_flags.authoritative = False;
- nmb->header.rcode = 0;
- nmb->header.qdcount = 1;
- nmb->header.ancount = 0;
- nmb->header.nscount = 0;
- nmb->header.arcount = 0;
-
- make_nmb_name(&nmb->question.question_name,name,name_type,scope);
-
- nmb->question.question_type = 0x20;
- nmb->question.question_class = 0x1;
-
- p.ip = to_ip;
- p.port = NMB_PORT;
- p.fd = fd;
- p.timestamp = time(NULL);
- p.packet_type = NMB_PACKET;
-
- GetTimeOfDay(&tval);
-
- if (!send_packet(&p))
- return(False);
-
- retries--;
-
- while (1)
- {
- struct timeval tval2;
- GetTimeOfDay(&tval2);
- if (TvalDiff(&tval,&tval2) > retry_time) {
- if (!retries) break;
- if (!found && !send_packet(&p))
- return False;
- GetTimeOfDay(&tval);
- retries--;
- }
-
- if ((p2=receive_packet(fd,NMB_PACKET,90)))
- {
- struct nmb_packet *nmb2 = &p2->packet.nmb;
- if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
- !nmb2->header.response) {
- /* its not for us - maybe deal with it later
- (put it on the queue?) */
- if (fn)
- fn(p2);
- else
- free_packet(p2);
- continue;
- }
-
- if (nmb2->header.opcode != 0 ||
- nmb2->header.nm_flags.bcast ||
- nmb2->header.rcode ||
- !nmb2->header.ancount) {
- /* XXXX what do we do with this? could be a redirect, but
- we'll discard it for the moment */
- free_packet(p2);
- continue;
- }
-
- if (ip) {
- putip((char *)ip,&nmb2->answers->rdata[2]);
- DEBUG(fn?3:2,("Got a positive name query response from %s",
- inet_ntoa(p2->ip)));
- DEBUG(fn?3:2,(" (%s)\n",inet_ntoa(*ip)));
- }
- found=True; retries=0;
- free_packet(p2);
- if (fn) break;
- }
- }
-
- return(found);
-}
-
-
-/****************************************************************************
- construct and send a netbios DGRAM
-
- Note that this currently sends all answers to port 138. thats the
- wrong things to do! I should send to the requestors port. XXX
- **************************************************************************/
-BOOL send_mailslot_reply(char *mailslot,int fd,char *buf,int len,
- char *srcname,char *dstname,
- int src_type,int dest_type,
- struct in_addr dest_ip,
- struct in_addr src_ip)
-{
- struct packet_struct p;
- struct dgram_packet *dgram = &p.packet.dgram;
- char *ptr,*p2;
- char tmp[4];
-
- bzero((char *)&p,sizeof(p));
-
- dgram->header.msg_type = 0x11; /* DIRECT GROUP DATAGRAM */
- dgram->header.flags.node_type = M_NODE;
- dgram->header.flags.first = True;
- dgram->header.flags.more = False;
- dgram->header.dgm_id = name_trn_id++;
- dgram->header.source_ip = src_ip;
- dgram->header.source_port = DGRAM_PORT;
- dgram->header.dgm_length = 0; /* let build_dgram() handle this */
- dgram->header.packet_offset = 0;
-
- make_nmb_name(&dgram->source_name,srcname,src_type,scope);
- make_nmb_name(&dgram->dest_name,dstname,dest_type,scope);
-
- ptr = &dgram->data[0];
-
- /* now setup the smb part */
- ptr -= 4; /* XXX ugliness because of handling of tcp SMB length */
- memcpy(tmp,ptr,4);
- set_message(ptr,17,17 + len,True);
- memcpy(ptr,tmp,4);
-
- CVAL(ptr,smb_com) = SMBtrans;
- SSVAL(ptr,smb_vwv1,len);
- SSVAL(ptr,smb_vwv11,len);
- SSVAL(ptr,smb_vwv12,70 + strlen(mailslot));
- SSVAL(ptr,smb_vwv13,3);
- SSVAL(ptr,smb_vwv14,1);
- SSVAL(ptr,smb_vwv15,1);
- SSVAL(ptr,smb_vwv16,2);
- p2 = smb_buf(ptr);
- strcpy(p2,mailslot);
- p2 = skip_string(p2,1);
-
- memcpy(p2,buf,len);
- p2 += len;
-
- dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length */
-
- p.ip = dest_ip;
- p.port = DGRAM_PORT;
- p.fd = fd;
- p.timestamp = time(NULL);
- p.packet_type = DGRAM_PACKET;
-
- return(send_packet(&p));
-}
-
-
diff --git a/source/libsmb/smbencrypt.c b/source/libsmb/smbencrypt.c
index a0683b5d282..c666e79547d 100644
--- a/source/libsmb/smbencrypt.c
+++ b/source/libsmb/smbencrypt.c
@@ -22,25 +22,11 @@
*/
#include "includes.h"
-#include "loadparm.h"
#include "des.h"
#include "md4.h"
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)
@@ -166,7 +152,7 @@ void E_md4hash(uchar *passwd, uchar *p16)
MDstruct MD;
/* Password cannot be longer than 128 characters */
- len = strlen(passwd);
+ len = strlen((char *)passwd);
if(len > 128)
len = 128;
/* Password must be converted to NT unicode */
@@ -198,5 +184,5 @@ void SMBNTencrypt(uchar *passwd, uchar *c8, uchar *p24)
}
#else
-void smbencrypt_dummy(void){}
+ void smbencrypt_dummy(void){}
#endif
diff --git a/source/locking/locking.c b/source/locking/locking.c
index 6ff3ab5d125..78661d69706 100644
--- a/source/locking/locking.c
+++ b/source/locking/locking.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Locking functions
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1996
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
@@ -20,7 +20,6 @@
*/
#include "includes.h"
-#include "loadparm.h"
extern int DEBUGLEVEL;
extern connection_struct Connections[];
extern files_struct Files[];
@@ -29,6 +28,137 @@ pstring share_del_pending="";
/****************************************************************************
+routine to do file locking
+****************************************************************************/
+BOOL fcntl_lock(int fd,int op,uint32 offset,uint32 count,int type)
+{
+#if HAVE_FCNTL_LOCK
+ struct flock lock;
+ int ret;
+
+#if 1
+ uint32 mask = 0xC0000000;
+
+ /* make sure the count is reasonable, we might kill the lockd otherwise */
+ count &= ~mask;
+
+ /* the offset is often strange - remove 2 of its bits if either of
+ the top two bits are set. Shift the top ones by two bits. This
+ still allows OLE2 apps to operate, but should stop lockd from
+ dieing */
+ if ((offset & mask) != 0)
+ offset = (offset & ~mask) | ((offset & mask) >> 2);
+#else
+ unsigned long mask = ((unsigned)1<<31);
+
+ /* interpret negative counts as large numbers */
+ if (count < 0)
+ count &= ~mask;
+
+ /* no negative offsets */
+ offset &= ~mask;
+
+ /* count + offset must be in range */
+ while ((offset < 0 || (offset + count < 0)) && mask)
+ {
+ offset &= ~mask;
+ mask = mask >> 1;
+ }
+#endif
+
+
+ DEBUG(5,("fcntl_lock %d %d %d %d %d\n",fd,op,(int)offset,(int)count,type));
+
+ lock.l_type = type;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = (int)offset;
+ lock.l_len = (int)count;
+ lock.l_pid = 0;
+
+ errno = 0;
+
+ ret = fcntl(fd,op,&lock);
+
+ if (errno != 0)
+ DEBUG(3,("fcntl lock gave errno %d (%s)\n",errno,strerror(errno)));
+
+ /* a lock query */
+ if (op == F_GETLK)
+ {
+ if ((ret != -1) &&
+ (lock.l_type != F_UNLCK) &&
+ (lock.l_pid != 0) &&
+ (lock.l_pid != getpid()))
+ {
+ DEBUG(3,("fd %d is locked by pid %d\n",fd,lock.l_pid));
+ return(True);
+ }
+
+ /* it must be not locked or locked by me */
+ return(False);
+ }
+
+ /* a lock set or unset */
+ if (ret == -1)
+ {
+ DEBUG(3,("lock failed at offset %d count %d op %d type %d (%s)\n",
+ offset,count,op,type,strerror(errno)));
+
+ /* perhaps it doesn't support this sort of locking?? */
+ if (errno == EINVAL)
+ {
+ DEBUG(3,("locking not supported? returning True\n"));
+ return(True);
+ }
+
+ return(False);
+ }
+
+ /* everything went OK */
+ DEBUG(5,("Lock call successful\n"));
+
+ return(True);
+#else
+ return(False);
+#endif
+}
+
+/*******************************************************************
+lock a file - returning a open file descriptor or -1 on failure
+The timeout is in seconds. 0 means no timeout
+********************************************************************/
+int file_lock(char *name,int timeout)
+{
+ int fd = open(name,O_RDWR|O_CREAT,0666);
+ time_t t=0;
+ if (fd < 0) return(-1);
+
+#if HAVE_FCNTL_LOCK
+ if (timeout) t = time(NULL);
+ while (!timeout || (time(NULL)-t < timeout)) {
+ if (fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)) return(fd);
+ msleep(LOCK_RETRY_TIMEOUT);
+ }
+ return(-1);
+#else
+ return(fd);
+#endif
+}
+
+/*******************************************************************
+unlock a file locked by file_lock
+********************************************************************/
+void file_unlock(int fd)
+{
+ if (fd<0) return;
+#if HAVE_FCNTL_LOCK
+ fcntl_lock(fd,F_SETLK,0,1,F_UNLCK);
+#endif
+ close(fd);
+}
+
+
+/****************************************************************************
utility function called to see if a file region is locked
****************************************************************************/
BOOL is_locked(int fnum,int cnum,uint32 count,uint32 offset)
diff --git a/source/nameannounce.c b/source/nameannounce.c
new file mode 100644
index 00000000000..4c1ef78f9ed
--- /dev/null
+++ b/source/nameannounce.c
@@ -0,0 +1,580 @@
+/*
+ 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"
+
+#define TEST_CODE
+
+extern int DEBUGLEVEL;
+extern BOOL CanRecurse;
+
+extern struct in_addr ipzero;
+
+extern pstring myname;
+
+extern int ClientDGRAM;
+extern int ClientNMB;
+
+/* this is our domain/workgroup/server database */
+extern struct subnet_record *subnetlist;
+
+/* machine comment for host announcements */
+extern pstring ServerComment;
+
+extern int updatecount;
+extern int workgroup_count;
+
+extern struct in_addr ipgrp;
+
+/****************************************************************************
+ 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) = ANN_AnnouncementRequest;
+ p++;
+
+ CVAL(p,0) = work->token; /* (local) unique workgroup token id */
+ p++;
+ StrnCpy(p,myname,16);
+ strupper(p);
+ p = skip_string(p,1);
+
+ /* XXXX note: if we sent the announcement request to 0x1d instead
+ of 0x1e, then we could get the master browser to announce to
+ us instead of the members of the workgroup. wha-hey! */
+
+ send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
+ myname,work->work_group,0x20,0x1e,ip,*iface_ip(ip));
+}
+
+
+/****************************************************************************
+ 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;
+ 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,*iface_ip(dest_ip));
+}
+
+
+/****************************************************************************
+ find a server responsible for a workgroup, and sync browse lists
+ control ends up back here via response_name_query.
+ **************************************************************************/
+void sync_server(enum state_type state, char *serv_name, char *work_name,
+ int name_type,
+ struct in_addr ip)
+{
+ /* with a domain master we can get the whole list (not local only list) */
+ BOOL local_only = (state != NAME_STATUS_DOM_SRV_CHK);
+
+ add_browser_entry(serv_name, name_type, work_name, 0, ip, local_only);
+
+ if (state == NAME_STATUS_DOM_SRV_CHK)
+ {
+ /* announce ourselves as a master browser to serv_name */
+ do_announce_request(myname, serv_name, ANN_MasterAnnouncement,
+ 0x20, 0, ip);
+ }
+}
+
+
+/****************************************************************************
+ construct a host announcement unicast
+
+ this function should not be used heavily, and only when we are _not_
+ a master browser and _not_ a primary domain controller.
+
+ **************************************************************************/
+void announce_backup(void)
+{
+ static time_t lastrun = 0;
+ time_t t = time(NULL);
+ pstring outbuf;
+ char *p;
+ struct subnet_record *d1;
+ int tok;
+ static uint32 id_count = 0;
+
+ if (!lastrun) lastrun = t;
+#if 1
+ if (t < lastrun + 1 * 60)
+#else
+ if (t < lastrun + CHECK_TIME_ANNOUNCE_BACKUP * 60)
+#endif
+ return;
+ lastrun = t;
+
+ DEBUG(4,("checking backups...\n"));
+
+ for (tok = 0; tok <= workgroup_count; tok++)
+ {
+ for (d1 = subnetlist; d1; d1 = d1->next)
+ {
+ struct work_record *work;
+ struct subnet_record *d;
+
+ /* search for unique workgroup: only the name matters */
+ for (work = d1->workgrouplist;
+ work && (tok != work->token);
+ work = work->next);
+
+ if (!work) continue;
+
+ if (AM_MASTER(work) && AM_DOMCTL(work)) continue;
+
+ /* found one: announce it across all domains */
+ for (d = subnetlist; 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) = ANN_GetBackupListReq;
+ CVAL(p,1) = work->token; /* workgroup unique key index */
+ SIVAL(p,2,++id_count); /* unique count. not that we use it! */
+
+ p += 6;
+
+ debug_browse_data(outbuf, PTR_DIFF(p,outbuf));
+
+ if (!AM_DOMCTL(work))
+ {
+ /* only ask for a list of backup domain controllers
+ if we are not a domain controller ourselves */
+
+ send_mailslot_reply(BROWSE_MAILSLOT,
+ ClientDGRAM,outbuf,
+ PTR_DIFF(p,outbuf),
+ myname, work->work_group,
+ 0x0,0x1b,d->bcast_ip,
+ *iface_ip(d->bcast_ip));
+ }
+
+ debug_browse_data(outbuf, PTR_DIFF(p,outbuf));
+
+ if (!AM_MASTER(work))
+ {
+ /* only ask for a list of master browsers if we
+ are not a master browser ourselves */
+
+ send_mailslot_reply(BROWSE_MAILSLOT,
+ ClientDGRAM,outbuf,
+ PTR_DIFF(p,outbuf),
+ myname, work->work_group,
+ 0x0,0x1d,d->bcast_ip,
+ *iface_ip(d->bcast_ip));
+ }
+ }
+ }
+ }
+}
+
+
+/****************************************************************************
+ send a host announcement packet
+ **************************************************************************/
+void do_announce_host(int command,
+ char *from_name, int from_type, struct in_addr from_ip,
+ char *to_name , int to_type , struct in_addr to_ip,
+ time_t announce_interval,
+ char *server_name, int server_type, char *server_comment)
+{
+ pstring outbuf;
+ char *p;
+
+ bzero(outbuf,sizeof(outbuf));
+ p = outbuf+1;
+
+ /* command type */
+ CVAL(outbuf,0) = command;
+
+ /* announcement parameters */
+ CVAL(p,0) = updatecount;
+ SIVAL(p,1,announce_interval*1000); /* ms - despite the spec */
+
+ StrnCpy(p+5,server_name,16);
+ strupper(p+5);
+
+ CVAL(p,21) = 0x02; /* major version */
+ CVAL(p,22) = 0x02; /* minor version */
+
+ SIVAL(p,23,server_type);
+ SSVAL(p,27,0x010f); /* browse version: got from NT/AS 4.00 */
+ SSVAL(p,29,0xaa55); /* browse signature */
+
+ strcpy(p+31,server_comment);
+ p += 31;
+ p = skip_string(p,1);
+
+ debug_browse_data(outbuf, PTR_DIFF(p,outbuf));
+
+ /* send the announcement */
+ send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
+ PTR_DIFF(p,outbuf),
+ from_name, to_name,
+ from_type, to_type,
+ to_ip, from_ip);
+}
+
+
+/****************************************************************************
+ remove all samba's server entries
+ ****************************************************************************/
+void remove_my_servers(void)
+{
+ struct subnet_record *d;
+ for (d = subnetlist; 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(myname,s->serv.name)) continue;
+ announce_server(d, work, s->serv.name, s->serv.comment, 0, 0);
+ }
+ }
+ }
+}
+
+
+/****************************************************************************
+ announce a server entry
+ ****************************************************************************/
+void announce_server(struct subnet_record *d, struct work_record *work,
+ char *name, char *comment, time_t ttl, int server_type)
+{
+ uint32 domain_type = SV_TYPE_DOMAIN_ENUM|SV_TYPE_SERVER_UNIX;
+ BOOL wins_iface = ip_equal(d->bcast_ip, ipgrp);
+
+ if (wins_iface && server_type != 0)
+ {
+ /* wins pseudo-ip interface */
+ if (!AM_MASTER(work))
+ {
+ /* non-master announce by unicast to the domain master */
+ if (!lp_wins_support() && *lp_wins_server())
+ {
+ /* look up the domain master with the WINS server */
+ queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY,
+ NAME_QUERY_ANNOUNCE_HOST,
+ work->work_group,0x1b,0,ttl*1000,
+ server_type,name,comment,
+ False, False, ipzero, d->bcast_ip);
+ }
+ else
+ {
+ /* we are the WINS server, but not the domain master. */
+ /* XXXX we need to look up the domain master in our
+ WINS database list, and do_announce_host(). maybe
+ we could do a name query on the unsuspecting domain
+ master just to make sure it's awake. */
+ }
+ }
+
+ if (AM_DOMCTL(work))
+ {
+ /* XXXX announce to backup domain masters? */
+ }
+
+ /* XXXX any other kinds of announcements we need to consider here?
+ e.g local master browsers... no. local master browsers do
+ local master announcements to their domain master. they even
+ use WINS lookup of the domain master if another wins server
+ is being used!
+ */
+ }
+ else
+ {
+ if (AM_MASTER(work))
+ {
+ DEBUG(3,("sending local master announce to %s for %s(1e)\n",
+ inet_ntoa(d->bcast_ip),work->work_group));
+
+ do_announce_host(ANN_LocalMasterAnnouncement,
+ name , 0x00, d->myip,
+ work->work_group, 0x1e, d->bcast_ip,
+ ttl*1000,
+ name, server_type, comment);
+
+ DEBUG(3,("sending domain announce to %s for %s\n",
+ inet_ntoa(d->bcast_ip),work->work_group));
+
+ /* XXXX should we do a domain-announce-kill? */
+ if (server_type != 0)
+ {
+ if (AM_DOMCTL(work))
+ {
+ domain_type |= SV_TYPE_DOMAIN_CTRL;
+ }
+ do_announce_host(ANN_DomainAnnouncement,
+ name , 0x00, d->myip,
+ MSBROWSE, 0x01, d->bcast_ip,
+ ttl*1000,
+ work->work_group, server_type ? domain_type : 0,
+ name);
+ }
+ }
+ else
+ {
+ DEBUG(3,("sending host announce to %s for %s(1d)\n",
+ inet_ntoa(d->bcast_ip),work->work_group));
+
+ do_announce_host(ANN_HostAnnouncement,
+ name , 0x00, d->myip,
+ work->work_group, 0x1d, d->bcast_ip,
+ ttl*1000,
+ name, server_type, comment);
+ }
+ }
+}
+
+/****************************************************************************
+ construct a host announcement unicast
+ **************************************************************************/
+void announce_host(void)
+{
+ time_t t = time(NULL);
+ struct subnet_record *d;
+ pstring comment;
+ char *my_name;
+
+ StrnCpy(comment, *ServerComment ? ServerComment : "NoComment", 43);
+
+ my_name = *myname ? myname : "NoName";
+
+ for (d = subnetlist; d; d = d->next)
+ {
+ struct work_record *work;
+
+ if (ip_equal(d->bcast_ip, ipgrp)) continue;
+
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ uint32 stype = work->ServerType;
+ struct server_record *s;
+ BOOL announce = False;
+
+ /* must work on the code that does announcements at up to
+ 30 seconds later if a master browser sends us a request
+ announce.
+ */
+
+ 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,
+ CHECK_TIME_MIN_HOST_ANNCE*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 < CHECK_TIME_MAX_HOST_ANNCE * 60)
+ work->announce_interval += 60;
+
+ work->lastannounce_time = t;
+
+ /*
+ if (!d->my_interface) {
+ 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)
+ {
+ announce_server(d,work,my_name,comment,work->announce_interval,stype);
+ }
+
+ 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.
+
+ this actually gets done in search_and_sync_workgroups() via the
+ NAME_QUERY_DOM_SRV_CHK command, if there is a response from the
+ name query initiated here. see response_name_query()
+ **************************************************************************/
+void announce_master(void)
+{
+ struct subnet_record *d;
+ static time_t last=0;
+ time_t t = time(NULL);
+ BOOL am_master = False; /* are we a master of some sort? :-) */
+
+ if (!last) last = t;
+ if (t-last < CHECK_TIME_MST_ANNOUNCE * 60)
+ return;
+
+ last = t;
+
+ for (d = subnetlist; 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 = subnetlist; 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 DOMs (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())
+ {
+ queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY,
+ NAME_QUERY_DOM_SRV_CHK,
+ work->work_group,0x1b,0,0,0,NULL,NULL,
+ False, False, ipzero, ipzero);
+ }
+ else
+ {
+ struct subnet_record *d2;
+ for (d2 = subnetlist; d2; d2 = d2->next)
+ {
+ queue_netbios_packet(d,ClientNMB,NMB_QUERY,
+ NAME_QUERY_DOM_SRV_CHK,
+ work->work_group,0x1b,0,0,0,NULL,NULL,
+ True, False, d2->bcast_ip, 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 = d->bcast_ip;
+ bcast = True;
+ }
+
+ DEBUG(2, ("Searching for DOM %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(d,ClientNMB,NMB_QUERY,NAME_QUERY_DOM_SRV_CHK,
+ work->work_group,0x1b,0,0,0,NULL,NULL,
+ bcast, False, ip, ip);
+ }
+ }
+ }
+}
diff --git a/source/nameannounce.doc b/source/nameannounce.doc
new file mode 100644
index 00000000000..a1e33cb8008
--- /dev/null
+++ b/source/nameannounce.doc
@@ -0,0 +1,265 @@
+/*
+ Unix SMB/Netbios documentation.
+ Version 0.2
+ Copyright (C) Luke Leighton Andrew Tridgell 1996
+
+ 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.
+
+ Document name: nameannounce.doc
+
+ Revision History:
+
+ 0.0 - 02jul96 : lkcl@pires.co.uk
+ created
+
+ 0.1 - 22jul96 : Andrew.Tridgell@anu.edu.au
+ tridge's comments on first revision
+
+ 0.2 - 05aug96 : lkcl@pires.co.uk
+ actioned tridge comments about pdc -> domain master
+ documented NAME_QUERY_ANNOUNCE_HOST
+
+*/
+
+
+this module deals with announcements: the sending of announcement requests
+and the sending of announcements either to refresh other servers' records
+or as a response to announcement requests.
+
+
+/*************************************************************************
+ announce_master()
+ *************************************************************************/
+
+this function is responsible for announcing samba as a master browser
+to all known domain masters.
+
+this announcement is sent out at CHECK_TIME_MST_ANNOUNCE minute
+intervals, only if samba is a master browser on one or more of
+its local interfaces.
+
+if no domain controller has been specified (lp_domain_controller())
+samba goes through its list of servers looking for domain master
+browsers. when it finds one (other than itself) it will either
+initiate a NAME_QUERY_PDC_SRV_CHK by broadcast or with a WINS
+server. this will result in a NAME_STATUS_PDC_SRV_CHK, which
+will result in a sync browse list and an announcement
+ANN_MasterAnnounce being sent (see sync_server()).
+
+if a domain controller has been specified, samba will search for
+a domain master browser for its workgroup (either by directed
+packet or by broadcast if it cannot resolve the domain controller
+name using DNS), which results in the same action as listed above.
+
+------------
+NOTE FROM TRIDGE:
+
+PDC in the above should really be DMB (domain master browser). They
+might be separate entities.
+
+I also propose a simpler scheme :-)
+
+If a DMB is not configured with lp_domain_controller() (perhaps
+renamed to lp_domain_master()?) then just don't do master
+announcements. Remember that most peoples networks are very simple and
+don't need DMB capabilities. Those that do need them will have more
+complex network topologies and they really need to choose themselves
+which box will act as the "hub" for netbios name resolution. Doing it
+via name queries will just lead to lag and propogation delays, because
+if two parts of the net choose different DMBs then the data will be
+very slow to propoogate.
+
+If a DMB is configured then just sent the master announcemnt to that
+box! Thats all that needs to be done. Just send a udp 138 packet and
+forget it. If the recipient is indeed a DMB (as it should be if the
+config file is correct) then it should initiate a browse list sync
+with us at some later time, but that is take care of by smbd and nmbd
+doesn't even need to know it happened.
+
+Additionally, if a DMB is configured we need to sync our workgroup
+list and server list with them occasionally. Note that this is only
+time a non-DMB should do a browse sync, and it should only do it with
+a DMB. Essentially WAN based netbios is just a simple star. There is a
+DMB in the centre, and the individual master browsers for each subnet
+talk to it, but never talk to each other. If they start talking to
+each other then the network load will go as the square of the number
+of machines, which will result in meltdown :-)
+-------------
+
+
+/*************************************************************************
+ announce_host()
+ *************************************************************************/
+
+this complex-looking function is responsible for announcing samba's
+existence to other servers by broadcast. the actual announcement
+is carried out by announce_server().
+
+the time period between samba's announcement will stretch from one
+minute to twelve minutes by one minute. if samba has received an
+announce request from a master browser, then it should answer at
+any random interval between zero and thirty seconds after the
+request is received. this is to ensure that the master browser
+does not get overloaded with responses!
+
+
+/*************************************************************************
+ announce_server()
+ *************************************************************************/
+
+this function is responsible for sending announcement packets.
+these packets are received by other servers, which will then
+update their records accordingly: what services we have, our
+name, our comment field and our time to live (to name a few).
+
+if samba is a non-master then we need to see if there is a
+domain master (on a remote subnet) that we need to announce to
+it.
+
+if samba is not the WINS server (and it is using another
+WINS server) then we need to do a name query to the WINS
+server to ask it what the domain controller is. this is done
+using a samba 'state' NAME_QUERY_ANNOUNCE_HOST, which passes
+sufficient information on to be able to carry out the
+host announcement using a unicasted do_announce_host() if and
+when a reply comes back. if there is no reply to the name query,
+this is not necessarily an error - there may genuinely be no
+domain master currently up and running for samba's workgroup.
+
+if samba is a WINS server, then samba will need to look up the
+domain controller for its workgroup in its WINS records. an
+over-cautious samba could carry out a name query on that
+domain controller to make sure that it is alive and that samba's
+WINS records are up-to-date. in any event, it will send a unicast
+do_announce_host() to inform the domain master browser, if one
+exists, of samba's server status.
+
+if we are a master browser, then using do_announce_host() we
+must send a broadcast announcement on the local interface
+notifying members of that workgroup that we are their master
+browser, and another announcement indicating to all backup
+browsers and master browsers that we are a master browser.
+
+(note: if another master browser receives this broadcasted
+announcement and thinks that it is also the master browser
+for this workgroup, it stops being a master browser and forces
+an election).
+
+if we are not a master browser, then we send a broacast
+announcement notifying the master browser that we are a member
+of its workgroup, on the local interface.
+
+
+/*************************************************************************
+ remove_my_servers()
+ *************************************************************************/
+
+this function is responsible for informing other servers that
+samba is about to go down. it announces, on all subnets, that
+samba's time to live is zero and that it has no services.
+
+
+/*************************************************************************
+ do_announce_host()
+ *************************************************************************/
+
+this function is responsible for sending out an announcement
+MAILSLOT browse packet. it contains information such as the
+time to live, name of the server, services that the server
+offers etc.
+
+the format of this MAILSLOT browse packet is described in
+draft-heizer-cifs-v1-spec-00.txt 3.9.50.4.1 page 165-6.
+
+
+/*************************************************************************
+ announce_backup()
+ *************************************************************************/
+
+this function is responsible for getting master browsers and domain
+controllers to send us lists of backup servers. this is done by
+sending an ANN_GetBackupListReq browse mailslot.
+
+the local master browser, or domain master browser, should respond
+with an ANN_GetBackupListResp browse mailslot containing the list
+of backup servers.
+
+--------------
+NOTE FROM TRIDGE: I don't see why nmbd should ever send one of
+these. The only reason I can see for any part of Samba sending one of
+these is if we implement it in smbclient.
+
+This packet is used to request a list of backup master browsers from
+the master browser. It is used by clients (not servers!) to spread the
+browse load over more than one server. The only server that needs to
+know what the list of backups is is the master browser, and as it is
+also responsible for generating this list it will never ask anyone
+else for it.
+--------------
+
+
+/*************************************************************************
+ sync_server()
+ *************************************************************************/
+
+this function is responsible for initiating a sync browse list
+sequence and, if necessary, carrying out an ANN_MasterAnnouncement
+to the domain master browser (that we are also sync'ing browse lists
+with).
+
+see nameservresp.c:response_name_status_check().
+
+
+/*************************************************************************
+ announce_request()
+ *************************************************************************/
+
+this function is responsible for sending an announcement request to
+another server. this server should respond with an announcement.
+
+if the announce request is sent to WORKGROUP(0x1e) then members of
+the workgroup will respond (with ANN_HostAnnounce packets)
+
+if the announce request is sent to WORKGROUP(0x1d) then the master
+browser of the workgroup should respond (ANN_LocalMasterAnnounce).
+this is untested.
+
+if the announce request is sent to ^1^2__MSBROWSE__^2(0x1) then
+(and this is pure speculation), all backup browsers and master
+browsers should respond with ANN_DomainAnnounce packets.
+this is untested.
+
+-----------
+NOTE FROM TRIDGE:
+
+I had great trouble getting machines to actually respond to this
+packet. Either we have the format wrong or MS chose not to implement
+it.
+
+Not implementing it doesn't break anything, it just means a new master
+browser won't get a complete server list as quickly.
+
+Also note that this packet should be used as little as possible as it
+could easily cause meltdown if too many servers used it. Imagine a
+dozen samba servers on a net all sending this packet! You will get 244
+responses all within 30 seconds. now imagine 50 samba servers ....
+
+So I think we should restrict ourselves to sending this packet only if
+we are already the master browser for a workgroup. We could send a
+single "announce request" when we become the master, just to prime our
+server lists. From then on the normal announce cycles should take care
+of keeping it uptodate.
+-----------
+
diff --git a/source/namebrowse.c b/source/namebrowse.c
new file mode 100644
index 00000000000..b426bc7a150
--- /dev/null
+++ b/source/namebrowse.c
@@ -0,0 +1,219 @@
+/*
+ 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"
+
+extern int ClientNMB;
+
+extern int DEBUGLEVEL;
+
+/* this is our browse master/backup cache database */
+static struct browse_cache_record *browserlist = NULL;
+
+
+/***************************************************************************
+ 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;
+}
+
+
+/*******************************************************************
+ 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;
+ }
+ }
+}
+
+
+/****************************************************************************
+ 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 local)
+{
+ 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;
+ b->local = local; /* local server list sync or complete sync required */
+
+ 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);
+}
+
+
+/****************************************************************************
+find a server responsible for a workgroup, and sync browse lists
+**************************************************************************/
+static void start_sync_browse_entry(struct browse_cache_record *b)
+{
+ struct subnet_record *d;
+ struct work_record *work;
+
+ if (!(d = find_subnet(b->ip))) return;
+
+ if (!(work = find_workgroupstruct(d, b->group, False))) return;
+
+ /* only sync if we are the master */
+ if (AM_MASTER(work)) {
+
+ /* first check whether the group we intend to sync with exists. if it
+ doesn't, the server must have died. o dear. */
+
+ /* see response_netbios_packet() or expire_netbios_response_entries() */
+ queue_netbios_packet(d,ClientNMB,NMB_QUERY,
+ b->local?NAME_QUERY_SYNC_LOCAL:NAME_QUERY_SYNC_REMOTE,
+ b->group,0x20,0,0,0,NULL,NULL,
+ False,False,b->ip,b->ip);
+ }
+
+ b->synced = 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 < 20) return; /* don't do too many of these at once! */
+ /* XXXX equally this period should not be too long
+ the server may die in the intervening gap */
+
+ 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 with the selected entry then remove some dead entries */
+ start_sync_browse_entry(b);
+ expire_browse_cache(t - 60);
+ }
+
+}
+
diff --git a/source/namebrowse.doc b/source/namebrowse.doc
new file mode 100644
index 00000000000..82713d85708
--- /dev/null
+++ b/source/namebrowse.doc
@@ -0,0 +1,149 @@
+/*
+ Unix SMB/Netbios documentation.
+ Version 0.1
+ Copyright (C) Luke Leighton Andrew Tridgell 1996
+
+ 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.
+
+ Document name: namebrowse.doc
+
+ Revision History:
+
+ 0.0 - 02jul96 : lkcl@pires.co.uk
+ created
+
+ 0.1 - 22jul96 Andrew.Tridgell@anu.edu.au
+ tridge's comments on first revision
+*/
+
+this module deals with queueing servers that samba must sync browse
+lists with. it will always issue a name query immediately before
+actually carrying out the NetServerEnum call, to ensure that time
+is not wasted by a remote server's failure.
+
+this module was created to minimise the amount of NetServerEnum calls
+that samba may be asked to perform, by maintaining the name of a server
+for up to a minute after the NetServerEnum call was issued, and
+disallowing further NetServerEnum calls to this remote server until
+the entry is removed.
+
+samba can ask for a NetServerEnum call to be issued to grab a remote
+server's list of servers and workgroups either in its capacity as
+a domain master browser, as a local master browser.
+
+samba does not deal with becoming a backup master browser properly
+at present.
+
+-------------
+NOTE FROM TRIDGE:
+
+Yes, samba can send these either in its capacity as a DMB or as a
+MB. There are only two situations:
+
+- If samba is a DMB then it should sync with the "local only" bit set
+with any master browser that has sent it a "master announce".
+
+- if samba is not a DMB then it can only sync with the DMB, and should
+not set the "local only" bit.
+
+Note that samba should never sync with other non-DMB servers when it
+is not a DMB.
+
+Try to do a sync under any other circumstances is dangerous without a
+multi-threaded nmbd. I have a print server at home that knows some SMB
+and NBT, but if you try to sync browse lists with it then it clogs up,
+and also clogs up nmbd while it times out the connection. If we
+follow the above two rules then we can't get into this sort of
+trouble as:
+
+- if we are a DMB and a master browser sends us a "master announce"
+then it is expecting to receive a NetServerEnum SMB connection soon,
+and must be capabable of handling it.
+
+- if we are not a DMB then we will only sync with the DMB, which must
+be capable of doing this stuff or things are really in a mess :-)
+--------------
+
+
+/*************************************************************************
+ do_browser_lists()
+ *************************************************************************/
+
+this function is responsible for finding an appropriate entry in the
+sync browser cache, initiating a name query (which results in a
+NetServerEnum call if there is a positive response), and then
+removing all entries that have been actioned and have been around
+for over a minute.
+
+
+/*************************************************************************
+ start_sync_browse_entry()
+ *************************************************************************/
+
+this function is responsible for initiating a name query. if a
+positive response is received, then this will result in a
+NetServerEnum api call.
+
+samba will only initiate this process if it is a master browser
+for this workgroup.
+
+-----------
+NOTE FROM TRIDGE:
+
+I'd actually prefer to skip the name query completely if we can
+resolve the DMBs name via gethostbyname(). For the name query to work
+we either have to have WINS working, or we need to know the broadcast
+address of the network that the DMB is on. This makes us too dependent
+on too many thing being right.
+
+If the gethostbyname() fails then sure, go for a normal name query,
+but if it works then we have saved ourselves a lot of trouble and
+gained a lot of robustness.
+
+This is best handled by a generic "resolve netbios name" routine that
+tries DNS first then resorts to WINS or bcast if that fails. It also
+needs to cache the results.
+-------------
+
+
+/*************************************************************************
+ add_browser_entry()
+ *************************************************************************/
+
+this function is responsible for adding a browser into the list of
+servers to sync browse lists with. if the server entry has already
+been added and syncing browse lists has already been initiated, it
+will not be added again.
+
+
+/*************************************************************************
+ expire_browse_cache()
+ *************************************************************************/
+
+this function is responsible for removing entries that have had the
+sync browse list initiated (whether that succeeded or not is beyond
+this function's scope) and have been in the cache for a while.
+
+
+/*************************************************************************
+ add_browse_entry()
+ *************************************************************************/
+
+this function is responsible for adding a new entry into the list
+of servers to sync browse lists with at some point in the near future.
+
+
+
+
diff --git a/source/namedbname.c b/source/namedbname.c
new file mode 100644
index 00000000000..177c36fc07e
--- /dev/null
+++ b/source/namedbname.c
@@ -0,0 +1,562 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1996
+
+ 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.
+
+ Module name: namedbname.c
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+ 04 jul 96: lkcl@pires.co.uk
+ created module namedbname containing name database functions
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+extern pstring scope;
+extern struct in_addr ipzero;
+extern struct in_addr ipgrp;
+
+extern struct subnet_record *subnetlist;
+
+#define WINS_LIST "wins.dat"
+
+uint16 nb_type = 0; /* samba's NetBIOS name type */
+
+
+/****************************************************************************
+ samba's NetBIOS name type
+
+ XXXX maybe functionality could be set: B, M, P or H name registration
+ and resolution could be set through nb_type. just a thought.
+ ****************************************************************************/
+void set_samba_nb_type(void)
+{
+ if (lp_wins_support() || (*lp_wins_server()))
+ {
+ nb_type = NB_MFLAG; /* samba is a 'hybrid' node type */
+ }
+ else
+ {
+ nb_type = NB_BFLAG; /* samba is broadcast-only node type */
+ }
+}
+
+
+/****************************************************************************
+ true if two netbios names are equal
+****************************************************************************/
+BOOL name_equal(struct nmb_name *n1,struct nmb_name *n2)
+{
+ return n1->name_type == n2->name_type &&
+ strequal(n1->name ,n2->name ) &&
+ strequal(n1->scope,n2->scope);
+}
+
+
+/****************************************************************************
+ true if the netbios name is ^1^2__MSBROWSE__^2^1
+
+ note: this name is registered if as a master browser or backup browser
+ you are responsible for a workgroup (when you announce a domain by
+ broadcasting on your local subnet, you announce it as coming from this
+ name: see announce_host()).
+
+ **************************************************************************/
+BOOL ms_browser_name(char *name, int type)
+{
+ return strequal(name,MSBROWSE) && type == 0x01;
+}
+
+
+/****************************************************************************
+ add a netbios name into the namelist
+ **************************************************************************/
+static void add_name(struct subnet_record *d, struct name_record *n)
+{
+ struct name_record *n2;
+
+ if (!d) return;
+
+ if (!d->namelist)
+ {
+ d->namelist = n;
+ n->prev = NULL;
+ n->next = NULL;
+ return;
+ }
+
+ for (n2 = d->namelist; n2->next; n2 = n2->next) ;
+
+ n2->next = n;
+ n->next = NULL;
+ n->prev = n2;
+}
+
+
+/****************************************************************************
+ remove a name from the namelist. The pointer must be an element just
+ retrieved
+ **************************************************************************/
+void remove_name(struct subnet_record *d, struct name_record *n)
+{
+ struct name_record *nlist;
+ if (!d) return;
+
+ nlist = d->namelist;
+
+ while (nlist && nlist != n) nlist = nlist->next;
+
+ if (nlist)
+ {
+ if (nlist->next) nlist->next->prev = nlist->prev;
+ if (nlist->prev) nlist->prev->next = nlist->next;
+ free(nlist);
+ }
+}
+
+
+/****************************************************************************
+ find a name in a namelist.
+ **************************************************************************/
+struct name_record *find_name(struct name_record *n,
+ struct nmb_name *name,
+ int search)
+{
+ struct name_record *ret;
+
+ for (ret = n; ret; ret = ret->next)
+ {
+ if (name_equal(&ret->name,name))
+ {
+ /* self search: self names only */
+ if ((search&FIND_SELF) == FIND_SELF && ret->source != SELF)
+ continue;
+
+ return ret;
+ }
+ }
+ return NULL;
+}
+
+
+/****************************************************************************
+ find a name in the domain database namelist
+ search can be any of:
+ FIND_SELF - look exclusively for names the samba server has added for itself
+ FIND_LOCAL - look for names in the local subnet record.
+ FIND_WINS - look for names in the WINS record
+ **************************************************************************/
+struct name_record *find_name_search(struct subnet_record **d,
+ struct nmb_name *name,
+ int search, struct in_addr ip)
+{
+ if (d == NULL) return NULL; /* bad error! */
+
+ if ((search & FIND_LOCAL) == FIND_LOCAL)
+ {
+ if (*d != NULL)
+ {
+ struct name_record *n = find_name((*d)->namelist, name, search);
+ DEBUG(4,("find_name on local: %s %s search %x\n",
+ namestr(name),inet_ntoa(ip), search));
+ if (n) return n;
+ }
+ }
+
+ if ((search & FIND_WINS) != FIND_WINS) return NULL;
+
+ /* find WINS subnet record. */
+ *d = find_subnet(ipgrp);
+
+ if (*d == NULL) return NULL;
+
+ DEBUG(4,("find_name on WINS: %s %s search %x\n",
+ namestr(name),inet_ntoa(ip), search));
+ return find_name((*d)->namelist, name, search);
+}
+
+
+/****************************************************************************
+ dump a copy of the name table
+ **************************************************************************/
+void dump_names(void)
+{
+ struct name_record *n;
+ struct subnet_record *d;
+ fstring fname, fnamenew;
+ time_t t = time(NULL);
+
+ FILE *f;
+
+ strcpy(fname,lp_lockdir());
+ trim_string(fname,NULL,"/");
+ strcat(fname,"/");
+ strcat(fname,WINS_LIST);
+ strcpy(fnamenew,fname);
+ strcat(fnamenew,".");
+
+ f = fopen(fnamenew,"w");
+
+ if (!f)
+ {
+ DEBUG(4,("Can't open %s - %s\n",fnamenew,strerror(errno)));
+ }
+
+ DEBUG(3,("Dump of local name table:\n"));
+
+ for (d = subnetlist; d; d = d->next)
+ for (n = d->namelist; n; n = n->next)
+ {
+ if (f && ip_equal(d->bcast_ip, ipgrp) && n->source == REGISTER)
+ {
+ fstring data;
+
+ /* XXXX i have little imagination as to how to output nb_flags as
+ anything other than as a hexadecimal number :-) */
+
+ sprintf(data, "%s#%02x %s %2x %ld",
+ n->name.name,n->name.name_type, /* XXXX ignore scope for now */
+ inet_ntoa(n->ip),
+ n->nb_flags,
+ n->death_time);
+ fprintf(f, "%s\n", data);
+ }
+
+ DEBUG(3,("%15s ", inet_ntoa(d->bcast_ip)));
+ DEBUG(3,("%15s ", inet_ntoa(d->mask_ip)));
+ DEBUG(3,("%-19s %15s NB=%2x TTL=%ld \n",
+ namestr(&n->name),
+ inet_ntoa(n->ip),
+ n->nb_flags,
+ n->death_time?n->death_time-t:0));
+ }
+
+ fclose(f);
+ unlink(fname);
+ chmod(fnamenew,0644);
+ rename(fnamenew,fname);
+
+ DEBUG(3,("Wrote wins database %s\n",fname));
+}
+
+
+/****************************************************************************
+load a netbios name database file
+****************************************************************************/
+void load_netbios_names(void)
+{
+ struct subnet_record *d = find_subnet(ipgrp);
+ fstring fname;
+
+ FILE *f;
+ pstring line;
+
+ if (!d) return;
+
+ strcpy(fname,lp_lockdir());
+ trim_string(fname,NULL,"/");
+ strcat(fname,"/");
+ strcat(fname,WINS_LIST);
+
+ f = fopen(fname,"r");
+
+ if (!f) {
+ DEBUG(2,("Can't open wins database file %s\n",fname));
+ return;
+ }
+
+ while (!feof(f))
+ {
+ pstring name_str, ip_str, ttd_str, nb_flags_str;
+
+ pstring name;
+ int type = 0;
+ int nb_flags;
+ time_t ttd;
+ struct in_addr ipaddr;
+
+ enum name_source source;
+
+ char *ptr;
+ int count = 0;
+
+ char *p;
+
+ if (!fgets_slash(line,sizeof(pstring),f)) continue;
+
+ if (*line == '#') continue;
+
+ ptr = line;
+
+ if (next_token(&ptr,name_str ,NULL)) ++count;
+ if (next_token(&ptr,ip_str ,NULL)) ++count;
+ if (next_token(&ptr,ttd_str ,NULL)) ++count;
+ if (next_token(&ptr,nb_flags_str,NULL)) ++count;
+
+ if (count <= 0) continue;
+
+ if (count != 4) {
+ DEBUG(0,("Ill formed wins line"));
+ DEBUG(0,("[%s]: name#type ip nb_flags abs_time\n",line));
+ continue;
+ }
+
+ /* netbios name. # divides the name from the type (hex): netbios#xx */
+ strcpy(name,name_str);
+
+ p = strchr(name,'#');
+
+ if (p) {
+ *p = 0;
+ sscanf(p+1,"%x",&type);
+ }
+
+ /* decode the netbios flags (hex) and the time-to-die (seconds) */
+ sscanf(nb_flags_str,"%x",&nb_flags);
+ sscanf(ttd_str,"%ld",&ttd);
+
+ ipaddr = *interpret_addr2(ip_str);
+
+ if (ip_equal(ipaddr,ipzero)) {
+ source = SELF;
+ }
+ else
+ {
+ source = REGISTER;
+ }
+
+ DEBUG(4, ("add WINS line: %s#%02x %s %ld %2x\n",
+ name,type, inet_ntoa(ipaddr), ttd, nb_flags));
+
+ /* add all entries that have 60 seconds or more to live */
+ if (ttd - 60 < time(NULL) || ttd == 0)
+ {
+ time_t t = (ttd?ttd-time(NULL):0) / 3;
+
+ /* add netbios entry read from the wins.dat file. IF it's ok */
+ add_netbios_entry(d,name,type,nb_flags,t,source,ipaddr,True,True);
+ }
+ }
+
+ fclose(f);
+}
+
+
+/****************************************************************************
+ remove an entry from the name list
+ ****************************************************************************/
+void remove_netbios_name(struct subnet_record *d,
+ char *name,int type, enum name_source source,
+ struct in_addr ip)
+{
+ struct nmb_name nn;
+ struct name_record *n;
+
+ make_nmb_name(&nn, name, type, scope);
+ n = find_name_search(&d, &nn, FIND_LOCAL, ip);
+
+ if (n && n->source == source) remove_name(d,n);
+}
+
+
+/****************************************************************************
+ add an entry to the name list.
+
+ this is a multi-purpose function.
+
+ it adds samba's own names in to its records on each interface, keeping a
+ record of whether it is a master browser, domain master, or WINS server.
+
+ it also keeps a record of WINS entries.
+
+ ****************************************************************************/
+struct name_record *add_netbios_entry(struct subnet_record *d,
+ char *name, int type, int nb_flags,
+ int ttl, enum name_source source, struct in_addr ip,
+ BOOL new_only,BOOL wins)
+{
+ struct name_record *n;
+ struct name_record *n2=NULL;
+ int search = 0;
+ BOOL self = source == SELF;
+
+ /* add the name to the WINS list if the name comes from a directed query */
+ search |= wins ? FIND_WINS : FIND_LOCAL;
+ /* search for SELF names only */
+ search |= self ? FIND_SELF : 0;
+
+ if (!self)
+ {
+ if (!wins && type != 0x1b)
+ {
+ /* the only broadcast (non-WINS) names we are adding are ours
+ (SELF) and Domain Master type names */
+ return NULL;
+ }
+ }
+
+ n = (struct name_record *)malloc(sizeof(*n));
+ if (!n) return(NULL);
+
+ bzero((char *)n,sizeof(*n));
+
+ make_nmb_name(&n->name,name,type,scope);
+
+ if ((n2 = find_name_search(&d, &n->name, search, new_only?ipzero:ip)))
+ {
+ free(n);
+ if (new_only || (n2->source==SELF && source!=SELF)) return n2;
+ n = n2;
+ }
+
+ if (ttl)
+ n->death_time = time(NULL)+ttl*3;
+ n->refresh_time = time(NULL)+GET_TTL(ttl);
+
+ n->ip = ip;
+ n->nb_flags = nb_flags;
+ n->source = source;
+
+ if (!n2) add_name(d,n);
+
+ 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);
+}
+
+
+/*******************************************************************
+ expires old names in the namelist
+ ******************************************************************/
+void expire_names(time_t t)
+{
+ struct name_record *n;
+ struct name_record *next;
+ struct subnet_record *d;
+
+ /* expire old names */
+ for (d = subnetlist; d; d = d->next)
+ {
+ for (n = d->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 (d->namelist == n) d->namelist = n->next;
+
+ free(n);
+ }
+ else
+ {
+ next = n->next;
+ }
+ }
+ }
+}
+
+
+/***************************************************************************
+ reply to a name query
+ ****************************************************************************/
+struct name_record *search_for_name(struct subnet_record **d,
+ struct nmb_name *question,
+ struct in_addr ip, int Time, int search)
+{
+ int name_type = question->name_type;
+ char *qname = question->name;
+ BOOL dns_type = name_type == 0x20 || name_type == 0;
+
+ struct name_record *n;
+
+ DEBUG(3,("Search for %s from %s - ", namestr(question), inet_ntoa(ip)));
+
+ /* first look up name in cache */
+ n = find_name_search(d,question,search,ip);
+
+ if (*d == NULL) return NULL;
+
+ DEBUG(4,("subnet %s ", inet_ntoa((*d)->bcast_ip)));
+
+ /* 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 && name_type != 0x1b)
+ {
+ 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 */
+ DEBUG(3,("no recursion.\n"));
+ /* add the fail to our WINS cache of names. give it 1 hour in the cache */
+ add_netbios_entry(*d,qname,name_type,NB_ACTIVE,60*60,DNSFAIL,dns_ip,
+ True, True);
+ return NULL;
+ }
+
+ /* add it to our WINS cache of names. give it 2 hours in the cache */
+ n = add_netbios_entry(*d,qname,name_type,NB_ACTIVE,2*60*60,DNS,dns_ip,
+ True,True);
+
+ /* failed to add it? yikes! */
+ if (!n) return NULL;
+ }
+
+ /* 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;
+ }
+
+ DEBUG(3,("OK %s\n",inet_ntoa(n->ip)));
+
+ return n;
+}
+
+
diff --git a/source/namedbname.doc b/source/namedbname.doc
new file mode 100644
index 00000000000..34a791dbb89
--- /dev/null
+++ b/source/namedbname.doc
@@ -0,0 +1,182 @@
+/*
+ Unix SMB/Netbios documentation.
+ Version 0.0
+ Copyright (C) Luke Leighton Andrew Tridgell 1996
+
+ 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.
+
+ Document name: namedbname.doc
+
+ Revision History:
+
+ 0.0 - 02jul96 : lkcl@pires.co.uk
+ created
+*/
+
+this module deals with the NetBIOS name database for samba. it deals
+directly with adding, removing, finding, loading and saving of names.
+
+/*************************************************************************
+ search_for_name()
+ *************************************************************************/
+
+this function is responsible for finding a name in the appropriate part
+of samba's NetBIOS name database. if the name cannot be found, then it
+should look the name up using DNS. later modifications will be to
+forward the request on to another WINS server, should samba not be able
+to find out about the requested name (this will be implemented through
+issuing a new type of samba 'state').
+
+the name is first searched for in the NetBIOS cache. if it cannot be
+found, then it if the name looks like it's a server-type name (0x20
+0x0 or 0x1b) then DNS is used to look for the name.
+
+if DNS fails, then a record of this failure is kept. if it succeeds, then
+a new NetBIOS entry is added.
+
+the successfully found name is returned. on failure, NULL is returned.
+
+
+/*************************************************************************
+ expire_names()
+ *************************************************************************/
+
+this function is responsible for removing old NetBIOS names from its
+database. no further action is required.
+
+for over-zealous WINS systems, the use of query_refresh_names() is
+recommended. this function initiates polling of hosts that have
+registered with samba in its capacity as a WINS server. an alternative
+means to achieve the same end as query_refresh_names() is to
+reduce the time to live when the name is registered with samba,
+except that in this instance the responsibility for refreshing the
+name is with the owner of the name, not the server with which the name
+is registered.
+
+
+/*************************************************************************
+ add_netbios_entry()
+ *************************************************************************/
+
+this function is responsible for adding or updating a NetBIOS name
+in the database. into the local interface records, the only names
+that will be added are those of domain master browsers and
+samba's own names. into the WINS records, all names are added.
+
+the name to be added / updated will be looked up in the records.
+if it is found, then we will not overwrite the entry if the flag
+'newonly' is True, or if the name is being added as a non-SELF
+(non-samba) name and the records indicate that samba owns the
+name.
+
+otherwise, the name is added or updated with the new details.
+
+
+/*************************************************************************
+ remove_netbios_entry()
+ *************************************************************************/
+
+this function is responsible for removing a NetBIOS entry from
+the database. the name is searched for in the records using
+find_name_search(). if the ip is zero, then the ip is ignored.
+
+the name is removed if the expected source (e.g SELF, REGISTER)
+matches that in the database.
+
+
+/*************************************************************************
+ load_netbios_names()
+ *************************************************************************/
+
+this function is responsible for loading any NetBIOS names that samba,
+in its WINS capacity, has written out to disk. all the relevant details
+are recorded in this file, including the time-to-live. should the
+time left to live be small, the name is not added back in to samba's
+WINS database.
+
+
+/*************************************************************************
+ dump_names()
+ *************************************************************************/
+
+this function is responsible for outputting NetBIOS names in two formats.
+firstly, as debugging information, and secondly, all names that have been
+registered with samba in its capacity as a WINS server are written to
+disk.
+
+writing all WINS names allows two things. firstly, if samba's NetBIOS
+daemon dies or is terminated, on restarting the daemon most if not all
+of the registered WINS names will be preserved (which is a good reason
+why query_netbios_names() should be used).
+
+
+/*************************************************************************
+ find_name_search()
+ *************************************************************************/
+
+this function is a wrapper around find_name(). find_name_search() can
+be told whether to search for the name in a local subnet structure or
+in the WINS database. on top of this, it can be told to search only
+for samba's SELF names.
+
+if it finds the name in the WINS database, it will set the subnet_record
+and also return the name it finds.
+
+
+/*************************************************************************
+ find_name()
+ *************************************************************************/
+
+this function is a low-level search function that searches a single
+interface's NetBIOS records for a name. if the ip to be found is
+zero then the ip address is ignored. this is to enable a name to
+be found without knowing its ip address, and also to find the exact
+name if a large number of group names are added with different ip
+addresses.
+
+
+/*************************************************************************
+ remove_name()
+ *************************************************************************/
+
+this function is responsible for removing a specific NetBIOS entry
+from a subnet list's records. only if the pointer to the entry is
+in the list will the name be removed.
+
+
+/*************************************************************************
+ add_name()
+ *************************************************************************/
+
+this function is responsible for adding a NetBIOS entry into a
+subnet list's records.
+
+
+/*************************************************************************
+ ms_browser_name()
+ *************************************************************************/
+
+this function returns True if the NetBIOS name passed to it is
+^1^2__MSBROWSE__^2^1
+
+
+/*************************************************************************
+ name_equal()
+ *************************************************************************/
+
+this function returns True if the two NetBIOS names passed to it
+match in name, type and scope: the NetBIOS names are equal.
+
+
diff --git a/source/namedbresp.c b/source/namedbresp.c
new file mode 100644
index 00000000000..d89bfe8ae84
--- /dev/null
+++ b/source/namedbresp.c
@@ -0,0 +1,160 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios library routines
+ Copyright (C) Andrew Tridgell 1994-1996
+
+ 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.
+
+ Module name: namedbresp.c
+
+*/
+
+#include "includes.h"
+
+extern int ClientNMB;
+extern int ClientDGRAM;
+
+extern struct subnet_record *subnetlist;
+
+extern int DEBUGLEVEL;
+
+extern pstring scope;
+extern pstring myname;
+extern struct in_addr ipzero;
+extern struct in_addr ipgrp;
+
+int num_response_packets = 0;
+
+/***************************************************************************
+ add an expected response record into the list
+ **************************************************************************/
+void add_response_record(struct subnet_record *d,
+ struct response_record *n)
+{
+ struct response_record *n2;
+
+ if (!d) return;
+
+ num_response_packets++; /* count of total number of packets still around */
+
+ DEBUG(4,("adding response record id:%d num_records:%d\n",
+ n->response_id, num_response_packets));
+
+ if (!d->responselist)
+ {
+ d->responselist = n;
+ n->prev = NULL;
+ n->next = NULL;
+ return;
+ }
+
+ for (n2 = d->responselist; n2->next; n2 = n2->next) ;
+
+ n2->next = n;
+ n->next = NULL;
+ n->prev = n2;
+}
+
+
+/***************************************************************************
+ remove an expected response record from the list
+ **************************************************************************/
+void remove_response_record(struct subnet_record *d,
+ struct response_record *n)
+{
+ if (!d) return;
+
+ if (n->prev) n->prev->next = n->next;
+ if (n->next) n->next->prev = n->prev;
+
+ if (d->responselist == n) d->responselist = n->next;
+
+ free(n);
+
+ num_response_packets--; /* count of total number of packets still around */
+}
+
+
+/****************************************************************************
+ create a name query response record
+ **************************************************************************/
+struct response_record *make_response_queue_record(enum state_type state,
+ int id,uint16 fd,
+ int quest_type, char *name,int type, int nb_flags, time_t ttl,
+ int server_type, char *my_name, char *my_comment,
+ BOOL bcast,BOOL recurse,
+ struct in_addr send_ip, struct in_addr reply_to_ip)
+{
+ struct response_record *n;
+
+ if (!name || !name[0]) return NULL;
+
+ if (!(n = (struct response_record *)malloc(sizeof(*n))))
+ return(NULL);
+
+ n->response_id = id;
+ n->state = state;
+ n->fd = fd;
+ n->quest_type = quest_type;
+ make_nmb_name(&n->name, name, type, scope);
+ n->nb_flags = nb_flags;
+ n->ttl = ttl;
+ n->server_type = server_type;
+ n->bcast = bcast;
+ n->recurse = recurse;
+ n->send_ip = send_ip;
+ n->reply_to_ip = reply_to_ip;
+ StrnCpy(my_name , n->my_name , sizeof(n->my_name )-1);
+ StrnCpy(my_comment, n->my_comment, sizeof(n->my_comment)-1);
+
+ n->repeat_interval = 1; /* XXXX should be in ms */
+ n->repeat_count = 3; /* 3 retries */
+ n->repeat_time = time(NULL) + n->repeat_interval; /* initial retry time */
+
+ n->num_msgs = 0;
+
+ return n;
+}
+
+
+/****************************************************************************
+ find a response in a subnet's name query response list.
+ **************************************************************************/
+struct response_record *find_response_record(struct subnet_record **d,
+ uint16 id)
+{
+ struct response_record *n;
+
+ if (!d) return NULL;
+
+ for ((*d) = subnetlist; (*d); (*d) = (*d)->next)
+ {
+ for (n = (*d)->responselist; n; n = n->next)
+ {
+ if (n->response_id == id) {
+ DEBUG(4, ("found response record on %s: %d\n",
+ inet_ntoa((*d)->bcast_ip), id));
+ return n;
+ }
+ }
+ }
+
+ *d = NULL;
+
+ return NULL;
+}
+
+
diff --git a/source/namedbresp.doc b/source/namedbresp.doc
new file mode 100644
index 00000000000..a54c0702758
--- /dev/null
+++ b/source/namedbresp.doc
@@ -0,0 +1,100 @@
+/*
+ Unix SMB/Netbios documentation.
+ Version 0.1
+ Copyright (C) Luke Leighton Andrew Tridgell 1996
+
+ 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.
+
+ Document name: namedbresp.doc
+
+ Revision History:
+
+ 0.0 - 02jul96 : lkcl@pires.co.uk
+ created
+
+ 0.1 - 22jul96 Andrew.Tridgell@anu.edu.au
+ tridge's comments on first revision
+*/
+
+module namedbresp deals with the maintenance of the list of expected
+responses - creating, finding and removal.
+
+module nameresp deals with the initial transmission, re-transmission
+and time-out of netbios response records.
+
+
+/*************************************************************************
+ find_response_record()
+ *************************************************************************/
+
+this function is responsible for matching the unique response transaction
+id with an expected response record. as a side-effect of this search,
+it will find the subnet (or the WINS pseudo-subnet) that samba expected
+the response to come from.
+
+
+/*************************************************************************
+ make_response_queue_record()
+ *************************************************************************/
+
+this function is responsible for creating a response record, which will
+be queued awaiting a response.
+
+the number of retries is set to 3, and the retry period set to 1 second.
+if no response is received, then the packet is re-transmitted, which is
+why so much information is stored in the response record.
+
+the number of expected responses queued is kept, so listen_for_packets()
+knows it must time-out after 1 second if one or more responses are
+expected.
+
+
+/*************************************************************************
+ remove_response_record()
+ *************************************************************************/
+
+this function is responsible for removing a response record from the
+expected response queue. the number of expected responses is decreased.
+
+
+/*************************************************************************
+ add_response_record()
+ *************************************************************************/
+
+this function is responsible for adding the response record created by
+make_response_queue_record() into the appropriate response record queue.
+
+
+-----------------
+NOTE FROM TRIDGE:
+
+namedbresp.c is interesting because it implements a novel way of
+getting most of the advantages of a multi-threaded nmbd daemon without
+the portability problems.
+
+The NBT specs (rfc1001/1002) talk about the 16 bit IDs in the packets
+as being used to ensure that packets are unique, and to stop packets
+from being confused. It suggests incrementing the ID by 1 each time.
+
+Instead Luke uses these IDs to identify individual threads of control
+in nmbd. So when nmbd sends out a NBT packet as part of some complex
+processing, it adds to a linked list the information required to
+continue the processing when the reply comes in (or it times
+out). When a reply arrives this list can be searched to find the
+matching query and the next step in the processing can be carried out.
+
+This is really good stuff, and allows for much more complex behaviour
+than was possible with the old nmbd.
+----------------
diff --git a/source/namedbserver.c b/source/namedbserver.c
new file mode 100644
index 00000000000..afb1dc14315
--- /dev/null
+++ b/source/namedbserver.c
@@ -0,0 +1,221 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1996
+
+ 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
+
+ 04 jul 96: lkcl@pires.co.uk
+ created module namedbserver containing server database functions
+
+*/
+
+#include "includes.h"
+#include "smb.h"
+
+extern int ClientNMB;
+extern int ClientDGRAM;
+
+extern int DEBUGLEVEL;
+
+extern pstring myname;
+
+/* this is our domain/workgroup/server database */
+extern struct subnet_record *subnetlist;
+
+extern BOOL updatedlists;
+
+
+/*******************************************************************
+ expire old servers in the serverlist
+ time of -1 indicates everybody dies except those with time of 0
+ remove_all_servers indicates everybody dies.
+ ******************************************************************/
+void remove_old_servers(struct work_record *work, time_t t,
+ BOOL remove_all)
+{
+ struct server_record *s;
+ struct server_record *nexts;
+
+ /* expire old entries in the serverlist */
+ for (s = work->serverlist; s; s = nexts)
+ {
+ if (remove_all || (s->death_time && (t == -1 || 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;
+ }
+ }
+}
+
+
+/***************************************************************************
+ 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;
+}
+
+
+/****************************************************************************
+ find a server in a server list.
+ **************************************************************************/
+struct server_record *find_server(struct work_record *work, char *name)
+{
+ struct server_record *ret;
+
+ if (!work) return NULL;
+
+ for (ret = work->serverlist; ret; ret = ret->next)
+ {
+ if (strequal(ret->serv.name,name))
+ {
+ return ret;
+ }
+ }
+ return NULL;
+}
+
+
+/****************************************************************************
+ add a server entry
+ ****************************************************************************/
+struct server_record *add_server_entry(struct subnet_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);
+ }
+
+ s = find_server(work, name);
+
+ if (s && !replace)
+ {
+ DEBUG(4,("Not replacing %s\n",name));
+ return(s);
+ }
+
+ if (!s || s->serv.type != servertype || !strequal(s->serv.comment, comment))
+ updatedlists=True;
+
+ if (!s)
+ {
+ newentry = True;
+ s = (struct server_record *)malloc(sizeof(*s));
+
+ if (!s) return(NULL);
+
+ bzero((char *)s,sizeof(*s));
+ }
+
+
+ if (strequal(lp_workgroup(),work->work_group))
+ {
+ if (servertype)
+ 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 = servertype ? (ttl?time(NULL)+ttl*3:0) : (time(NULL)-1);
+
+ /* 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);
+}
+
+
+/*******************************************************************
+ expire old servers in the serverlist
+ ******************************************************************/
+void expire_servers(time_t t)
+{
+ struct subnet_record *d;
+
+ for (d = subnetlist ; d ; d = d->next)
+ {
+ struct work_record *work;
+
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ remove_old_servers(work, t, False);
+ }
+ }
+}
+
diff --git a/source/namedbsubnet.c b/source/namedbsubnet.c
new file mode 100644
index 00000000000..5c683e5e49b
--- /dev/null
+++ b/source/namedbsubnet.c
@@ -0,0 +1,327 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1996
+
+ 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
+
+ 04 jul 96: lkcl@pires.co.uk
+ created module namedbsubnet containing subnet database functions
+
+*/
+
+#include "includes.h"
+#include "smb.h"
+
+extern int ClientNMB;
+extern int ClientDGRAM;
+
+extern int DEBUGLEVEL;
+
+extern struct in_addr ipgrp;
+extern struct in_addr ipzero;
+
+extern pstring myname;
+
+BOOL updatedlists = True;
+int updatecount = 0;
+
+/* local interfaces structure */
+extern struct interface *local_interfaces;
+
+/* this is our domain/workgroup/server database */
+struct subnet_record *subnetlist = NULL;
+
+extern uint16 nb_type; /* samba's NetBIOS name type */
+
+/****************************************************************************
+ add a domain into the list
+ **************************************************************************/
+static void add_subnet(struct subnet_record *d)
+{
+ struct subnet_record *d2;
+
+ if (!subnetlist)
+ {
+ subnetlist = d;
+ d->prev = NULL;
+ d->next = NULL;
+ return;
+ }
+
+ for (d2 = subnetlist; d2->next; d2 = d2->next);
+
+ d2->next = d;
+ d->next = NULL;
+ d->prev = d2;
+}
+
+
+/****************************************************************************
+ find a subnet in the subnetlist
+ **************************************************************************/
+struct subnet_record *find_subnet(struct in_addr bcast_ip)
+{
+ struct subnet_record *d;
+ struct in_addr wins_ip = ipgrp;
+
+ /* search through subnet list for broadcast/netmask that matches
+ the source ip address. a subnet 255.255.255.255 represents the
+ WINS list. */
+
+ for (d = subnetlist; d; d = d->next)
+ {
+ if (ip_equal(bcast_ip, wins_ip))
+ {
+ if (ip_equal(bcast_ip, d->bcast_ip))
+ {
+ return d;
+ }
+ }
+ else if (same_net(bcast_ip, d->bcast_ip, d->mask_ip))
+ {
+ return(d);
+ }
+ }
+
+ return (NULL);
+}
+
+
+/****************************************************************************
+ finds the appropriate subnet structure. directed packets (non-bcast) are
+ assumed to come from a point-to-point (P or M node), and so the subnet we
+ return in this instance is the WINS 'pseudo-subnet' with ip 255.255.255.255
+ ****************************************************************************/
+struct subnet_record *find_req_subnet(struct in_addr ip, BOOL bcast)
+{
+ if (bcast)
+ {
+ /* identify the subnet the broadcast request came from */
+ return find_subnet(*iface_bcast(ip));
+ }
+ /* find the subnet under the pseudo-ip of 255.255.255.255 */
+ return find_subnet(ipgrp);
+}
+
+
+/****************************************************************************
+ create a domain entry
+ ****************************************************************************/
+static struct subnet_record *make_subnet(struct in_addr bcast_ip, struct in_addr mask_ip)
+{
+ struct subnet_record *d;
+ d = (struct subnet_record *)malloc(sizeof(*d));
+
+ if (!d) return(NULL);
+
+ bzero((char *)d,sizeof(*d));
+
+ DEBUG(4, ("making subnet %s ", inet_ntoa(bcast_ip)));
+ DEBUG(4, ("%s\n", inet_ntoa(mask_ip)));
+
+ d->bcast_ip = bcast_ip;
+ d->mask_ip = mask_ip;
+ d->workgrouplist = NULL;
+
+ add_subnet(d);
+
+ return d;
+}
+
+
+/****************************************************************************
+ add the remote interfaces from lp_interfaces()
+ to the netbios subnet database.
+ ****************************************************************************/
+void add_subnet_interfaces(void)
+{
+ struct interface *i;
+
+ /* loop on all local interfaces */
+ for (i = local_interfaces; i; i = i->next)
+ {
+ /* add the interface into our subnet database */
+ if (!find_subnet(i->bcast))
+ {
+ make_subnet(i->bcast,i->nmask);
+ }
+ }
+
+ /* add the pseudo-ip interface for WINS: 255.255.255.255 */
+ if (lp_wins_support() || (*lp_wins_server()))
+ {
+ struct in_addr wins_bcast = ipgrp;
+ struct in_addr wins_nmask = ipzero;
+ make_subnet(wins_bcast, wins_nmask);
+ }
+}
+
+
+
+/****************************************************************************
+ add the default workgroup into my domain
+ **************************************************************************/
+void add_my_subnets(char *group)
+{
+ struct interface *i;
+
+ /* add or find domain on our local subnet, in the default workgroup */
+
+ if (*group == '*') return;
+
+ /* the coding choice is up to you, andrew: i can see why you don't want
+ global access to the local_interfaces structure: so it can't get
+ messed up! */
+ for (i = local_interfaces; i; i = i->next)
+ {
+ add_subnet_entry(i->bcast,i->nmask,group, True, False);
+ }
+}
+
+
+/****************************************************************************
+ add a domain entry. creates a workgroup, if necessary, and adds the domain
+ to the named a workgroup.
+ ****************************************************************************/
+struct subnet_record *add_subnet_entry(struct in_addr bcast_ip,
+ struct in_addr mask_ip,
+ char *name, BOOL add, BOOL lmhosts)
+{
+ struct subnet_record *d;
+
+ /* XXXX andrew: struct in_addr ip appears not to be referenced at all except
+ in the DEBUG comment. i assume that the DEBUG comment below actually
+ intends to refer to bcast_ip? i don't know.
+
+ struct in_addr ip = ipgrp;
+
+ */
+
+ if (zero_ip(bcast_ip))
+ bcast_ip = *iface_bcast(bcast_ip);
+
+ /* add the domain into our domain database */
+ if ((d = find_subnet(bcast_ip)) ||
+ (d = make_subnet(bcast_ip, mask_ip)))
+ {
+ struct work_record *w = find_workgroupstruct(d, name, add);
+ extern pstring ServerComment;
+
+ if (!w) return NULL;
+
+ /* 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_my_name_entry(d,name,0x1e,nb_type|NB_ACTIVE|NB_GROUP);
+ add_my_name_entry(d,name,0x0 ,nb_type|NB_ACTIVE|NB_GROUP);
+ }
+ /* add samba server name to workgroup list. don't add
+ lmhosts server entries to local interfaces */
+ if (strequal(lp_workgroup(), name))
+ {
+ add_server_entry(d,w,myname,w->ServerType,0,ServerComment,True);
+ DEBUG(3,("Added server name entry %s at %s\n",
+ name,inet_ntoa(bcast_ip)));
+ }
+
+ return d;
+ }
+ return NULL;
+}
+
+
+/*******************************************************************
+ write out browse.dat
+ ******************************************************************/
+void write_browse_list(void)
+{
+ struct subnet_record *d;
+ pstring fname,fnamenew;
+ FILE *f;
+
+ static time_t lasttime = 0;
+ time_t t = time(NULL);
+
+ if (!lasttime) lasttime = t;
+ if (!updatedlists || t - lasttime < 5) return;
+
+ lasttime = t;
+ updatedlists = False;
+ updatecount++;
+
+ dump_names();
+ dump_workgroups();
+
+ 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 = subnetlist; 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));
+}
+
diff --git a/source/namedbwork.c b/source/namedbwork.c
new file mode 100644
index 00000000000..200132304b0
--- /dev/null
+++ b/source/namedbwork.c
@@ -0,0 +1,250 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1996
+
+ 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
+
+ 04 jul 96: lkcl@pires.co.uk
+ created module namedbwork containing workgroup database functions
+
+*/
+
+#include "includes.h"
+#include "smb.h"
+
+extern int ClientNMB;
+
+extern int DEBUGLEVEL;
+
+/* this is our domain/workgroup/server database */
+extern struct subnet_record *subnetlist;
+
+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)
+
+
+/****************************************************************************
+ add a workgroup into the domain list
+ **************************************************************************/
+static void add_workgroup(struct work_record *work, struct subnet_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 subnet_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;
+ work->state = MST_NONE;
+
+ /* make sure all token representations of workgroups are unique */
+
+ for (d = subnetlist; 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;
+}
+
+
+/*******************************************************************
+ remove workgroups
+ ******************************************************************/
+struct work_record *remove_workgroup(struct subnet_record *d,
+ struct work_record *work,
+ BOOL remove_all_servers)
+{
+ struct work_record *ret_work = NULL;
+
+ if (!d || !work) return NULL;
+
+ DEBUG(3,("Removing old workgroup %s\n", work->work_group));
+
+ ret_work = work->next;
+
+ remove_old_servers(work, -1, remove_all_servers);
+
+ if (!work->serverlist)
+ {
+ 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;
+}
+
+
+/****************************************************************************
+ 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 subnet_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(d,ClientNMB,NMB_QUERY, NAME_QUERY_FIND_MST,
+ MSBROWSE,0x1,0,0,0,NULL,NULL,
+ True,False, d->bcast_ip, 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);
+ }
+ }
+
+ if (!add) {
+ DEBUG(4, ("not found\n"));
+ return NULL;
+ }
+
+ DEBUG(4,("not found: creating\n"));
+
+ if ((work = make_workgroup(name)))
+ {
+ if (lp_preferred_master() &&
+ strequal(lp_workgroup(), name))
+ {
+ DEBUG(3, ("preferred master startup for %s\n", work->work_group));
+ work->needelection = True;
+ work->ElectionCriterion |= (1<<3);
+ }
+ add_workgroup(work, d);
+ return(work);
+ }
+ return NULL;
+}
+
+
+/****************************************************************************
+ dump a copy of the workgroup/domain database
+ **************************************************************************/
+void dump_workgroups(void)
+{
+ struct subnet_record *d;
+
+ for (d = subnetlist; d; d = d->next)
+ {
+ if (d->workgrouplist)
+ {
+ struct work_record *work;
+
+ DEBUG(4,("dump domain bcast=%15s: ", inet_ntoa(d->bcast_ip)));
+ DEBUG(4,(" netmask=%15s:\n", inet_ntoa(d->mask_ip)));
+
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ DEBUG(4,("\t%s(%d)\n", work->work_group, work->token));
+ if (work->serverlist)
+ {
+ struct server_record *s;
+ for (s = work->serverlist; s; s = s->next)
+ {
+ DEBUG(4,("\t\t%s %8x (%s)\n",
+ s->serv.name, s->serv.type, s->serv.comment));
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/source/nameelect.c b/source/nameelect.c
new file mode 100644
index 00000000000..38b4d5d80e7
--- /dev/null
+++ b/source/nameelect.c
@@ -0,0 +1,634 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1996
+
+ 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.
+
+ Module name: nameelect.c
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+ 04 jul 96: lkcl@pires.co.uk
+ added system to become a master browser by stages.
+
+
+*/
+
+#include "includes.h"
+
+extern int ClientNMB;
+extern int ClientDGRAM;
+
+extern int DEBUGLEVEL;
+extern pstring scope;
+
+extern pstring myname;
+extern struct in_addr ipzero;
+extern struct in_addr ipgrp;
+
+/* machine comment for host announcements */
+extern pstring ServerComment;
+
+/* here are my election parameters */
+
+extern time_t StartupTime;
+
+extern struct subnet_record *subnetlist;
+
+extern uint16 nb_type; /* samba's NetBIOS name type */
+
+/*******************************************************************
+ 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 subnet_record *d;
+
+ if (!lastrun) lastrun = t;
+ if (t < lastrun + CHECK_TIME_MST_BROWSE * 60)
+ return;
+ lastrun = t;
+
+ dump_workgroups();
+
+ for (d = subnetlist; 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(d,ClientNMB,NMB_QUERY,NAME_QUERY_MST_CHK,
+ work->work_group,0x1d,0,0,0,NULL,NULL,
+ True,False,d->bcast_ip,d->bcast_ip);
+ }
+ }
+ }
+}
+
+
+/*******************************************************************
+ what to do if a master browser DOESN't exist
+ ******************************************************************/
+void browser_gone(char *work_name, struct in_addr ip)
+{
+ struct subnet_record *d = find_subnet(ip);
+ struct work_record *work = find_workgroupstruct(d, work_name, False);
+
+ /* i don't know about this workgroup, therefore i don't care */
+ if (!work || !d) return;
+
+ if (strequal(work->work_group, lp_workgroup()))
+ {
+
+ DEBUG(2,("Forcing election on %s %s\n",
+ work->work_group,inet_ntoa(d->bcast_ip)));
+
+ /* we can attempt to become master browser */
+ work->needelection = True;
+ }
+ else
+ {
+ /* local interfaces: force an election */
+ send_election(d, work->work_group, 0, 0, myname);
+
+ /* only removes workgroup completely on a local interface
+ persistent lmhosts entries on a local interface _will_ be removed).
+ */
+ remove_workgroup(d, work,True);
+ }
+}
+
+
+/****************************************************************************
+ send an election packet
+ **************************************************************************/
+void send_election(struct subnet_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) = ANN_Election; /* 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,*iface_ip(d->bcast_ip));
+}
+
+
+/****************************************************************************
+ un-register a SELF name that got rejected.
+
+ if this name happens to be rejected when samba is in the process
+ of becoming a master browser (registering __MSBROWSE__, WORKGROUP(1d)
+ or WORKGROUP(1b)) then we must stop being a master browser. sad.
+
+ **************************************************************************/
+void name_unregister_work(struct subnet_record *d, char *name, int name_type)
+{
+ struct work_record *work;
+
+ remove_netbios_name(d,name,name_type,SELF,ipzero);
+
+ if (!(work = find_workgroupstruct(d, name, False))) return;
+
+ if (ms_browser_name(name, name_type) ||
+ (AM_MASTER(work) && strequal(name, lp_workgroup()) == 0 &&
+ (name_type == 0x1d || name_type == 0x1b)))
+ {
+ int remove_type = 0;
+
+ if (ms_browser_name(name, name_type))
+ remove_type = SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER;
+ if (name_type == 0x1d)
+ remove_type = SV_TYPE_MASTER_BROWSER;
+ if (name_type == 0x1b)
+ remove_type = SV_TYPE_DOMAIN_MASTER;
+
+ become_nonmaster(d, work, remove_type);
+ }
+}
+
+
+/****************************************************************************
+ registers a name.
+
+ if the name being added is a SELF name, we must additionally check
+ whether to proceed to the next stage in samba becoming a master browser.
+
+ **************************************************************************/
+void name_register_work(struct subnet_record *d, char *name, int name_type,
+ int nb_flags, time_t ttl, struct in_addr ip, BOOL bcast)
+{
+ enum name_source source = (ismyip(ip) || ip_equal(ip, ipzero)) ?
+ SELF : REGISTER;
+
+ if (source == SELF)
+ {
+ struct work_record *work = find_workgroupstruct(d, lp_workgroup(), False);
+
+ add_netbios_entry(d,name,name_type,nb_flags,ttl,source,ip,True,!bcast);
+
+ if (work)
+ {
+ if (work->state != MST_NONE)
+ {
+ /* samba is in the process of working towards master browser-ness.
+ initiate the next stage.
+ */
+ become_master(d, work);
+ return;
+ }
+ }
+ }
+}
+
+
+/*******************************************************************
+ become the master browser.
+
+ this is done in stages. note that this could take a while,
+ particularly on a broadcast subnet, as we have to wait for
+ the implicit registration of each name to be accepted.
+
+ as each name is successfully registered, become_master() is
+ called again, in order to initiate the next stage. see
+ dead_netbios_entry() - deals with implicit name registration
+ and response_name_reg() - deals with explicit registration
+ with a WINS server.
+
+ stage 1: was MST_NONE - go to MST_NONE and register ^1^2__MSBROWSE__^2^1.
+ stage 2: was MST_WON - go to MST_MSB and register WORKGROUP(0x1d)
+ stage 3: was MST_MSB - go to MST_BROWSER and register WORKGROUP(0x1b)
+ stage 4: was MST_BROWSER - go to MST_DOMAIN (do not pass GO, do not...)
+
+ XXXX note: this code still does not cope with the distinction
+ between different types of nodes, particularly between M and P
+ nodes. that comes later.
+
+ ******************************************************************/
+void become_master(struct subnet_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 %s (currently at stage %d)\n",
+ work->work_group,inet_ntoa(d->bcast_ip),work->state));
+
+ switch (work->state)
+ {
+ case MST_NONE: /* while we were nothing but a server... */
+ {
+ DEBUG(3,("go to first stage: register ^1^2__MSBROWSE__^2^1\n"));
+ work->state = MST_WON; /* ... an election win was successful */
+
+ work->ElectionCriterion |= 0x5;
+
+ /* update our server status */
+ work->ServerType &= ~SV_TYPE_POTENTIAL_BROWSER;
+ add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True);
+
+ /* add special browser name */
+ add_my_name_entry(d,MSBROWSE ,0x01,nb_type|NB_ACTIVE|NB_GROUP);
+
+ /* DON'T do anything else after calling add_my_name_entry() */
+ return;
+ }
+ case MST_WON: /* while nothing had happened except we won an election... */
+ {
+ DEBUG(3,("go to second stage: register as master browser\n"));
+ work->state = MST_MSB; /* ... registering MSBROWSE was successful */
+
+ /* add server entry on successful registration of MSBROWSE */
+ add_server_entry(d,work,work->work_group,domain_type,0,myname,True);
+
+ /* add master name */
+ add_my_name_entry(d,work->work_group,0x1d,nb_type|NB_ACTIVE);
+
+ /* DON'T do anything else after calling add_my_name_entry() */
+ return;
+ }
+ case MST_MSB: /* while we were still only registered MSBROWSE state... */
+ {
+ DEBUG(3,("2nd stage complete: registered as master browser\n"));
+ work->state = MST_BROWSER; /* ... registering WORKGROUP(1d) succeeded */
+
+ /* update our server status */
+ work->ServerType |= SV_TYPE_MASTER_BROWSER;
+ add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True);
+
+ if (work->serverlist == NULL) /* no servers! */
+ {
+ /* ask all servers on our local net to announce to us */
+ announce_request(work, d->bcast_ip);
+ }
+ break;
+ }
+
+ case MST_BROWSER:
+ {
+ /* don't have to do anything: just report success */
+ DEBUG(3,("3rd stage: become master browser!\n"));
+
+ break;
+ }
+
+ case MST_DOMAIN_NONE:
+ {
+ if (lp_domain_master())
+ {
+ work->state = MST_DOMAIN_MEM; /* ... become domain member */
+ DEBUG(3,("domain first stage: register as domain member\n"));
+
+ /* add domain member name */
+ add_my_name_entry(d,work->work_group,0x1e,nb_type|NB_ACTIVE|NB_GROUP);
+
+ /* DON'T do anything else after calling add_my_name_entry() */
+ return;
+ }
+ else
+ {
+ DEBUG(4,("samba not configured as a domain master.\n"));
+ }
+
+ break;
+ }
+
+ case MST_DOMAIN_MEM:
+ {
+ if (lp_domain_master())
+ {
+ work->state = MST_DOMAIN_TST; /* ... possibly become domain master */
+ DEBUG(3,("domain second stage: register as domain master\n"));
+
+ if (lp_domain_logons())
+ {
+ work->ServerType |= SV_TYPE_DOMAIN_MEMBER;
+ add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True);
+ }
+
+ /* add domain master name */
+ add_my_name_entry(d,work->work_group,0x1b,nb_type|NB_ACTIVE );
+
+ /* DON'T do anything else after calling add_my_name_entry() */
+ return;
+ }
+ else
+ {
+ DEBUG(4,("samba not configured as a domain master.\n"));
+ }
+
+ break;
+ }
+
+ case MST_DOMAIN_TST: /* while we were still a master browser... */
+ {
+ /* update our server status */
+ if (lp_domain_master())
+ {
+ struct subnet_record *d1;
+ uint32 update_type = 0;
+
+ DEBUG(3,("domain third stage: samba is now a domain master.\n"));
+ work->state = MST_DOMAIN; /* ... registering WORKGROUP(1b) succeeded */
+
+ update_type |= SV_TYPE_DOMAIN_MASTER;
+
+ if (lp_domain_logons())
+ {
+ update_type |= SV_TYPE_DOMAIN_CTRL|SV_TYPE_SERVER_UNIX;
+ }
+
+ work->ServerType |= update_type;
+ add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True);
+
+ for (d1 = subnetlist; d1; d1 = d1->next)
+ {
+ struct work_record *w;
+ if (ip_equal(d1->bcast_ip, d->bcast_ip)) continue;
+
+ for (w = d1->workgrouplist; w; w = w->next)
+ {
+ struct server_record *s = find_server(w, myname);
+ if (strequal(w->work_group, work->work_group))
+ {
+ w->ServerType |= update_type;
+ }
+ if (s)
+ {
+ s->serv.type |= update_type;
+ DEBUG(4,("found server %s on %s: update to %8x\n",
+ s->serv.name, inet_ntoa(d1->bcast_ip),
+ s->serv.type));
+ }
+ }
+ }
+ }
+
+ break;
+ }
+
+ case MST_DOMAIN:
+ {
+ /* don't have to do anything: just report success */
+ DEBUG(3,("fifth stage: there isn't one yet!\n"));
+ break;
+ }
+ }
+}
+
+
+/*******************************************************************
+ unbecome the master browser. initates removal of necessary netbios
+ names, and tells the world that we are no longer a master browser.
+ ******************************************************************/
+void become_nonmaster(struct subnet_record *d, struct work_record *work,
+ int remove_type)
+{
+ int new_server_type = work->ServerType;
+
+ DEBUG(2,("Becoming non-master for %s\n",work->work_group));
+
+ /* can only remove master or domain types with this function */
+ remove_type &= ~(SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER);
+
+ /* unbecome a master browser; unbecome a domain master, too :-( */
+ if (remove_type & SV_TYPE_MASTER_BROWSER)
+ remove_type |= SV_TYPE_DOMAIN_MASTER;
+
+ new_server_type &= ~remove_type;
+
+ if (!(new_server_type & (SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER)))
+ {
+ /* no longer a master browser of any sort */
+
+ work->ServerType |= SV_TYPE_POTENTIAL_BROWSER;
+ work->ElectionCriterion &= ~0x4;
+ work->state = MST_NONE;
+
+ /* announce ourselves as no longer active as a master browser. */
+ announce_server(d, work, work->work_group, myname, 0, 0);
+ remove_name_entry(d,MSBROWSE ,0x01);
+ }
+
+ work->ServerType = new_server_type;
+
+ if (!(work->ServerType & SV_TYPE_DOMAIN_MASTER))
+ {
+ if (work->state == MST_DOMAIN)
+ work->state = MST_BROWSER;
+ remove_name_entry(d,work->work_group,0x1b);
+
+ }
+
+ if (!(work->ServerType & SV_TYPE_DOMAIN_MASTER))
+ {
+ if (work->state >= MST_BROWSER)
+ work->state = MST_NONE;
+ remove_name_entry(d,work->work_group,0x1d);
+ }
+}
+
+
+/*******************************************************************
+ run the election
+ ******************************************************************/
+void run_elections(void)
+{
+ time_t t = time(NULL);
+ static time_t lastime = 0;
+
+ struct subnet_record *d;
+
+ /* send election packets once a second */
+ if (lastime && t-lastime <= 0) return;
+
+ lastime = t;
+
+ for (d = subnetlist; 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 %s <<<\n",
+ work->work_group,inet_ntoa(d->bcast_ip)));
+
+ work->RunningElection = False;
+ work->state = MST_NONE;
+
+ 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 subnet_record *d = find_subnet(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()))
+ {
+ if (win_election(work, version,criterion,timeup,name))
+ {
+ if (!work->RunningElection)
+ {
+ work->needelection = True;
+ work->ElectionCount=0;
+ work->state = MST_NONE;
+ }
+ }
+ else
+ {
+ work->needelection = False;
+
+ if (work->RunningElection)
+ {
+ work->RunningElection = False;
+ DEBUG(3,(">>> Lost election on %s %s <<<\n",
+ work->work_group,inet_ntoa(d->bcast_ip)));
+
+ /* if we are the master then remove our masterly names */
+ if (AM_MASTER(work))
+ {
+ become_nonmaster(d, work,
+ SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+/****************************************************************************
+ checks whether a browser election is to be run on any workgroup
+
+ this function really ought to return the time between election
+ packets (which depends on whether samba intends to be a domain
+ master or a master browser) in milliseconds.
+
+ ***************************************************************************/
+BOOL check_elections(void)
+{
+ struct subnet_record *d;
+ BOOL run_any_election = False;
+
+ for (d = subnetlist; 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 %s <<<\n",
+ work->work_group,inet_ntoa(d->bcast_ip)));
+ work->ElectionCount = 0;
+ work->RunningElection = True;
+ work->needelection = False;
+ }
+ }
+ }
+ return run_any_election;
+}
+
diff --git a/source/nameelect.doc b/source/nameelect.doc
new file mode 100644
index 00000000000..df025e2069a
--- /dev/null
+++ b/source/nameelect.doc
@@ -0,0 +1,256 @@
+/*
+ Unix SMB/Netbios documentation.
+ Version 0.1
+ Copyright (C) Luke Leighton Andrew Tridgell 1996
+
+ 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.
+
+ Document name: nameelect.doc
+
+ Revision History:
+
+ 0.0 - 02jul96 : lkcl@pires.co.uk
+ created
+
+ 0.1 - 22jul96 Andrew.Tridgell@anu.edu.au
+ tridge's comments on first revision
+*/
+
+the module nameelect.c deals with initiating, winning, losing
+browsing elections, and checking if browsers are still around,
+and the consequences of getting involved in all this.
+
+an election packet can be received at any time, which will initiate
+an election. samba can also detect that there is no longer a
+master browser and will initiate an election.
+
+there is one way to become a master browser, but there are two
+ways to un-become a master browser. if you lose an election, you
+must stop being a master browser. if you fail to register your
+unique special browser names (either on your local subnet or with
+the WINS server) then you must stop being a master browser.
+
+this is a double fail-safe mechanism to ensure that there is only
+one master browser per workgroup per subnet (and one domain master
+browser - per domain (workgroup) per wide area network).
+
+(a wide area network is created when one or more servers on a
+broadcast-isolated subnet point to the same WINS server).
+
+--------
+NOTE FROM TRIDGE:
+
+I'd say "domain master browser" not "WINS server" here. WINS doesn't
+have much to do with browsing, it is the WAN varient of name
+resolution. The name resolution and browsing functions of a netbios
+network are almost entirely separate. Both grew out of systems that
+could only be used on local networks.
+
+To adapt them to WANs, WINS was added for name resolution, and "domain
+master browsers" were added for browse lists. It would be perfectly
+possible to have a WINS server that doesn't even listen to UDP port
+138.
+--------
+
+/*************************************************************************
+ check_elections()
+ *************************************************************************/
+
+this function returns True if samba is in the process of running an
+election on any of its interfaces. a better version of this function
+should return the time-out period in between election packets, in
+milliseconds.
+
+
+/*************************************************************************
+ process_election()
+ *************************************************************************/
+
+this function is responsible for dealing with the receipt of an election
+browse MAILSLOT packet.
+
+if samba is running an election, it checks the criteria in the packet
+received using win_election() to see if it has lost the election or if
+it should join in the election.
+
+if it loses the election, then it becomes a non-master.
+
+
+/*************************************************************************
+ win_election()
+ *************************************************************************/
+
+this function returns True if samba has won an election. the criteria
+in order of precedence are:
+
+the election version; the election criteria; the time since samba was
+started; and as a last resort, a name comparison is used.
+
+
+/*************************************************************************
+ run_elections()
+ *************************************************************************/
+
+this function is responsible for sending out election packets if
+samba is running in an election. once the fourth packet is sent
+out, it is assumed that we have won, and samba initiates becoming
+a master browser.
+
+(it looks like samba sends out an extra packet just to be sure...)
+
+
+/*************************************************************************
+ become_nonmaster()
+ *************************************************************************/
+
+this function is responsible for down-grading samba's status from
+either domain master to master browser or nothing, or master browser
+to nothing, depending on its current status.
+
+samba can become a non-master in three ways: by losing an election -
+see process_election(); by having one of its special browser names
+de-registered - see name_unregister_work(); by receiving and
+processing a browser reset packet - see process_reset_browser().
+
+when samba stops being a domain master, it must release its unique
+0x1b name. when samba stops being a master browser, it must release
+its unique 0x1d name.
+
+becoming non-master is done on a per-subnet basis.
+
+
+/*************************************************************************
+ become_master()
+ *************************************************************************/
+
+this function is responsible for slowly turning samba into a
+local master browser or a domain master browser.
+
+
+this is done in stages. note that this could take a while,
+particularly on a broadcast subnet, as we have to wait for
+the implicit registration of each name to be accepted.
+
+as each name is successfully registered, become_master() is
+called again via name_register_work(), in order to initiate
+the next stage (see dead_netbios_entry() - deals with implicit
+name registration and response_name_reg() - deals with explicit
+registration with a WINS server).
+
+stage 1: was MST_NONE - go to MST_NONE and register ^1^2__MSBROWSE__^2^1.
+stage 2: was MST_WON - go to MST_MSB and register WORKGROUP(0x1d)
+stage 3: was MST_MSB - go to MST_BROWSER and register WORKGROUP(0x1b)
+stage 4: was MST_BROWSER - go to MST_DOMAIN (do not pass GO, do not...)
+
+note that this code still does not cope with the distinction
+between different types of nodes, particularly between M and P
+nodes (see rfc1001.txt). that will be developed later.
+
+
+/*************************************************************************
+ name_register_work()
+ *************************************************************************/
+
+this function is called when a NetBIOS name is successfully
+registered. it will add the registered name into samba's NetBIOS
+records.
+
+it has the additional responsibility that when samba is becoming
+a master browser, it must initiate the next stage in the progress
+towards becoming a master browser.
+
+implicit name registration is done through dead_netbios_entry()
+by time-out. explicit name registration is done through
+response_name_reg() with a WINS server.
+
+
+/*************************************************************************
+ name_unregister_work()
+ *************************************************************************/
+
+this function is called when there is an objection to a NetBIOS
+name being registered. this will always be done through a negative
+response to a name registration, whether it be by a host that
+already owns the unique name being registered on a subnet, or
+by a WINS server.
+
+the name being objected to must be removed from samba's records.
+
+it has the additional responsibility of checking whether samba is
+currently a master browser or not, and if so it should initiate
+becoming a non-master.
+
+
+
+/*************************************************************************
+ send_election()
+ *************************************************************************/
+
+this function is responsible for sending a browse mailslot
+datagram election packet (of type ANN_Election). it constructs
+the packet with all the relevant info needed to participate:
+election version; election criteria; time since startup and
+our name.
+
+this function can be used to ensure that initiate but lose an
+election by specifying a criteria and time up of zero. this
+is necessary if we are a master browser and we are about to
+go down (politely!) - see nmbd.c:sig_term().
+
+
+/*************************************************************************
+ browser_gone()
+ *************************************************************************/
+
+this function is responsible for dealing with the instance when
+the master browser we thought was present on a subnet is no longer
+responding.
+
+if it is samba's workgroup, and it's a local interface, samba
+detects that it can participate in an election on that interface
+and potentially become a master browser or domain master.
+
+if it's a local subnet and not one of samba's workgroups, then
+samba will force an election (which it is not obliged to do).
+remove_workgroup() will be expected to remove all references
+to this workgroup and the servers in it from the database.
+
+if it's a remote subnet and not one of samba's workgroups then
+no election is forced, and remove_workgroup() will be expected
+to remove all server entries from this workgroup _except_ those
+added from the lmhosts file. if there are entries added from
+the lmhosts file, then the workgroup entry will remain,
+otherwise it too will be removed.
+
+
+/*************************************************************************
+ check_master_browser()
+ *************************************************************************/
+
+this function is responsible for periodically checking whether
+master browsers that samba expects to be alive are alive. this
+is done every CHECK_TIME_MST_BROWSE minutes.
+
+for every workgroup record for which samba is not a master browser,
+on both local and remote interfaces, samba will initiate a
+broadcast query for a master browser on that subnet.
+
+(browser_gone() will be called to deal with the case where no
+response is received to the NAME_QUERY_MST_CHK initiated here.
+no action is required when a response _is_ received, however:
+see nameservresp.c:response_process() and dead_netbios_entry()
+for details)
+
+
diff --git a/source/namelogon.c b/source/namelogon.c
new file mode 100644
index 00000000000..24bb9842474
--- /dev/null
+++ b/source/namelogon.c
@@ -0,0 +1,145 @@
+/*
+ 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 ClientDGRAM;
+
+#define TEST_CODE /* want to debug unknown browse packets */
+
+extern int DEBUGLEVEL;
+
+extern pstring myname;
+
+
+/****************************************************************************
+ process a domain logon packet
+
+ 08aug96 lkcl@pires.co.uk
+ reply_code == 0xC courtesy of jim@oxfordcc.co.uk forwarded by
+ lewis2@server.uwindsor.ca
+ **************************************************************************/
+void process_logon_packet(struct packet_struct *p,char *buf,int len)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ struct in_addr ip = dgram->header.source_ip;
+ struct subnet_record *d = find_subnet(ip);
+ char *logname,*q;
+ char *reply_name;
+ BOOL add_slashes = False;
+ pstring outbuf;
+ int code,reply_code;
+ struct work_record *work;
+
+ if (!d) return;
+
+ if (!(work = find_workgroupstruct(d,dgram->dest_name.name, False)))
+ return;
+
+ if (!lp_domain_logons()) {
+ DEBUG(3,("No domain logons\n"));
+ return;
+ }
+ if (!listening_name(work, &dgram->dest_name))
+ {
+ DEBUG(4,("Not listening to that domain\n"));
+ return;
+ }
+
+ code = SVAL(buf,0);
+ switch (code) {
+ case 0:
+ {
+ char *machine = buf+2;
+ char *user = skip_string(machine,1);
+ logname = skip_string(user,1);
+ reply_code = 6;
+ reply_name = myname;
+ add_slashes = True;
+ DEBUG(3,("Domain login request from %s(%s) user=%s\n",
+ machine,inet_ntoa(p->ip),user));
+ }
+ break;
+ case 7:
+ {
+ char *machine = buf+2;
+ logname = skip_string(machine,1);
+ reply_code = 7;
+ reply_name = lp_domain_controller();
+ if (!*reply_name) {
+ reply_name = myname;
+ reply_code = 0xC;
+ }
+ DEBUG(3,("GETDC request from %s(%s), reporting %s 0x%2x\n",
+ machine,inet_ntoa(p->ip), reply_name, reply_code));
+ }
+ break;
+ default:
+ DEBUG(3,("Unknown domain request %d\n",code));
+ return;
+ }
+
+ bzero(outbuf,sizeof(outbuf));
+ q = outbuf;
+ SSVAL(q,0,reply_code);
+ q += 2;
+ if (add_slashes) {
+ strcpy(q,"\\\\");
+ q += 2;
+ }
+ StrnCpy(q,reply_name,16);
+ strupper(q);
+ q = skip_string(q,1);
+
+ if (reply_code == 0xC)
+ {
+ if ( PTR_DIFF (q,outbuf) & 1 )
+ {
+ q++;
+ }
+
+ StrnCpy(q,reply_name,16);
+ strupper(q);
+ q = skip_string(q,1);
+
+ StrnCpy(q,lp_workgroup(),16);
+ strupper(q);
+ q = skip_string(q,1);
+
+ SIVAL(q,0,1);
+ q += 4;
+ SSVAL(q,0,0xFFFF);
+ q += 2;
+ }
+
+ SSVAL(q,0,0xFFFF);
+ q += 2;
+
+ send_mailslot_reply(logname,ClientDGRAM,outbuf,PTR_DIFF(q,outbuf),
+ myname,&dgram->source_name.name[0],0x20,0,p->ip,
+ *iface_ip(p->ip));
+}
diff --git a/source/namelogon.doc b/source/namelogon.doc
new file mode 100644
index 00000000000..c4a97d0cf16
--- /dev/null
+++ b/source/namelogon.doc
@@ -0,0 +1,36 @@
+/*
+ Unix SMB/Netbios documentation.
+ Version 0.0
+ Copyright (C) Luke Leighton Andrew Tridgell 1996
+
+ 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.
+
+ Document name: namelogon.doc
+
+ Revision History:
+
+ 0.0 - 02jul96 : lkcl@pires.co.uk
+ created
+*/
+
+this module deals with the first stage of domain logons. there is much
+more work to be done on this: it's all totally undocumented.
+
+
+/*************************************************************************
+ process_logon_packet()
+ *************************************************************************/
+
+a function that processes logon packets (the most helpful comment yet :-).
diff --git a/source/namepacket.c b/source/namepacket.c
new file mode 100644
index 00000000000..a752ef5dfae
--- /dev/null
+++ b/source/namepacket.c
@@ -0,0 +1,581 @@
+/*
+ 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 ClientNMB;
+extern int ClientDGRAM;
+
+extern int DEBUGLEVEL;
+
+extern int num_response_packets;
+
+BOOL CanRecurse = True;
+extern pstring scope;
+extern struct in_addr ipgrp;
+
+static uint16 name_trn_id=0;
+
+
+/***************************************************************************
+ updates the unique transaction identifier
+ **************************************************************************/
+void debug_browse_data(char *outbuf, int len)
+{
+ int i,j;
+ for (i = 0; i < len; i+= 16)
+ {
+ DEBUG(4, ("%3x char ", i));
+
+ for (j = 0; j < 16; j++)
+ {
+ unsigned char x = outbuf[i+j];
+ if (x < 32 || x > 127) x = '.';
+
+ if (i+j >= len) break;
+ DEBUG(4, ("%c", x));
+ }
+
+ DEBUG(4, (" hex ", i));
+
+ for (j = 0; j < 16; j++)
+ {
+ if (i+j >= len) break;
+ DEBUG(4, (" %02x", outbuf[i+j]));
+ }
+
+ DEBUG(4, ("\n"));
+ }
+
+}
+
+
+/***************************************************************************
+ updates the unique transaction identifier
+ **************************************************************************/
+static void update_name_trn_id(void)
+{
+ if (!name_trn_id)
+ {
+ name_trn_id = (time(NULL)%(unsigned)0x7FFF) + (getpid()%(unsigned)100);
+ }
+ name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
+}
+
+
+/****************************************************************************
+ initiate a netbios packet
+ ****************************************************************************/
+void initiate_netbios_packet(uint16 *id,
+ 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 (!id) return;
+
+ 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;
+
+ bzero((char *)&p,sizeof(p));
+
+ if (*id == 0xffff) {
+ update_name_trn_id();
+ *id = name_trn_id; /* allow resending with same id */
+ }
+
+ nmb->header.name_trn_id = *id;
+ nmb->header.opcode = opcode;
+ nmb->header.response = False;
+
+ nmb->header.nm_flags.bcast = bcast;
+ nmb->header.nm_flags.recursion_available = False;
+ 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 *)iface_ip(to_ip));
+ }
+
+ p.ip = to_ip;
+ p.port = NMB_PORT;
+ p.fd = fd;
+ p.timestamp = time(NULL);
+ p.packet_type = NMB_PACKET;
+
+ if (!send_packet(&p)) *id = 0xffff;
+
+ return;
+}
+
+
+/****************************************************************************
+ reply to a netbios name packet
+ ****************************************************************************/
+void reply_netbios_packet(struct packet_struct *p1,int trn_id,
+ int rcode, int rcv_code, int opcode, BOOL recurse,
+ 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";
+ BOOL recursion_desired = False;
+
+ p = *p1;
+
+ switch (rcv_code)
+ {
+ case NMB_STATUS:
+ {
+ packet_type = "nmb_status";
+ recursion_desired = True;
+ break;
+ }
+ case NMB_QUERY:
+ {
+ packet_type = "nmb_query";
+ recursion_desired = True;
+ break;
+ }
+ case NMB_REG:
+ {
+ packet_type = "nmb_reg";
+ recursion_desired = True;
+ break;
+ }
+ case NMB_REL:
+ {
+ packet_type = "nmb_rel";
+ recursion_desired = False;
+ break;
+ }
+ case NMB_WAIT_ACK:
+ {
+ packet_type = "nmb_wack";
+ recursion_desired = False;
+ break;
+ }
+ default:
+ {
+ DEBUG(1,("replying netbios packet: %s %s\n",
+ packet_type, namestr(rr_name), inet_ntoa(p.ip)));
+
+ return;
+ }
+ }
+
+ 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 = recurse;
+ nmb->header.nm_flags.recursion_desired = recursion_desired;
+ 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);
+}
+
+
+/*******************************************************************
+ 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;
+}
+
+
+/****************************************************************************
+ 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(4,("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;
+
+ /* datagram packet received for the browser mailslot */
+ if (strequal(smb_buf(buf),BROWSE_MAILSLOT)) {
+ process_browse_packet(p,buf2,len);
+ return;
+ }
+
+ /* datagram packet received for the domain log on mailslot */
+ if (strequal(smb_buf(buf),NET_LOGON_MAILSLOT)) {
+ process_logon_packet(p,buf2,len);
+ return;
+ }
+}
+
+/****************************************************************************
+ process a nmb packet
+ ****************************************************************************/
+static void process_nmb(struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+
+ debug_nmb_packet(p);
+
+ switch (nmb->header.opcode)
+ {
+ case 8: /* what is this?? */
+ case NMB_REG:
+ case NMB_REG_REFRESH:
+ {
+ if (nmb->header.qdcount==0 || nmb->header.arcount==0) break;
+ if (nmb->header.response)
+ response_netbios_packet(p); /* response to registration dealt with here */
+ 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 NMB_REL:
+ {
+ if (nmb->header.qdcount==0 || nmb->header.arcount==0)
+ {
+ DEBUG(2,("netbios release packet rejected\n"));
+ break;
+ }
+
+ if (nmb->header.response)
+ response_netbios_packet(p); /* response to reply dealt with in here */
+ else
+ reply_name_release(p);
+ break;
+ }
+ }
+}
+
+
+/*******************************************************************
+ 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 and when expecting a netbios response packet we need
+ to send election packets at one second intervals.
+ XXXX actually, it needs to be the interval (in ms) between time now and the
+ time we are expecting the next netbios packet */
+
+ timeout.tv_sec = (run_election||num_response_packets) ? 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) {
+#if 1
+ if (ismyip(packet->ip) &&
+ (packet->port == NMB_PORT || packet->port == DGRAM_PORT)) {
+ DEBUG(5,("discarding own packet from %s:%d\n",
+ inet_ntoa(packet->ip),packet->port));
+ free_packet(packet);
+ } else
+#endif
+ {
+ queue_packet(packet);
+ }
+ }
+ }
+
+ if (FD_ISSET(ClientDGRAM,&fds))
+ {
+ struct packet_struct *packet = read_packet(ClientDGRAM, DGRAM_PACKET);
+ if (packet) {
+#if 1
+ if (ismyip(packet->ip) &&
+ (packet->port == NMB_PORT || packet->port == DGRAM_PORT)) {
+ DEBUG(5,("discarding own packet from %s:%d\n",
+ inet_ntoa(packet->ip),packet->port));
+ free_packet(packet);
+ } else
+#endif
+ {
+ queue_packet(packet);
+ }
+ }
+ }
+}
+
+
+
+/****************************************************************************
+ 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;
+ struct in_addr wins_ip = ipgrp;
+ char *ptr,*p2;
+ char tmp[4];
+
+ /* ha ha. no. do NOT send packets to 255.255.255.255: it's a pseudo address */
+ if (ip_equal(wins_ip, dest_ip)) return False;
+
+ bzero((char *)&p,sizeof(p));
+
+ update_name_trn_id();
+
+ 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 = ClientDGRAM;
+ p.timestamp = time(NULL);
+ p.packet_type = DGRAM_PACKET;
+
+ DEBUG(4,("send mailslot %s from %s %s", mailslot,
+ inet_ntoa(src_ip),namestr(&dgram->source_name)));
+ DEBUG(4,("to %s %s\n", inet_ntoa(dest_ip),namestr(&dgram->dest_name)));
+
+ return(send_packet(&p));
+}
diff --git a/source/namepacket.doc b/source/namepacket.doc
new file mode 100644
index 00000000000..159a50738c5
--- /dev/null
+++ b/source/namepacket.doc
@@ -0,0 +1,133 @@
+/*
+ Unix SMB/Netbios documentation.
+ Version 0.0
+ Copyright (C) Luke Leighton Andrew Tridgell 1996
+
+ 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.
+
+ Document name: namepacket.doc
+
+ Revision History:
+
+ 0.0 - 02jul96 : lkcl@pires.co.uk
+ created
+*/
+
+this module deals with packets: sending, receiving, queueing
+and some basic interpretation (e.g it excludes datagram
+error packets at the moment).
+
+the packet queueing mechanism was originally introduced when
+samba dealt with responses by sending a packet, receiving
+packets and queueing all packets that didn't match up with
+the response expected. this is fine in a single-thread
+environment, but samba now deals with response packets by
+queueing the responses. to some extent, therefore, this
+queue_packet mechanism is redundant.
+
+
+/*************************************************************************
+ send_mailslot_reply()
+ *************************************************************************/
+
+this function is responsible for sending a MAILSLOT packet.
+
+it will _not_ send packets to the pseudo WINS subnet's address of
+255.255.255.255: this would be disastrous.
+
+each packet sent out has a unique transaction identifier. this is done
+so that responses can be matched later with the original purpose for
+the packet being sent out in the first place.
+
+
+/*************************************************************************
+ listen_for_packets()
+ *************************************************************************/
+
+this function is responsible for reading NMB and DGRAM packets, and then
+queueing them. it will normally time-out for NMBD_SELECT_LOOP seconds, but
+if there is an election currently running or we are expecting a response
+then this time is reduced to 1 second.
+
+note: the time-out period needs refining to the millisecond level.
+
+
+/*************************************************************************
+ queue_packet()
+ *************************************************************************/
+
+this function is responsible for queueing any NMB and DGRAM packets passed
+to it. these packets will be removed from the queue in run_packet_queue().
+
+
+/*************************************************************************
+ run_packet_queue()
+ *************************************************************************/
+
+this function is responsible for taking a packet off the queue,
+identifying whether it is an NMB or a DGRAM packet, processing
+it accordingly and deleting it. this process continues until
+there are no more packets on the queue.
+
+
+/*************************************************************************
+ process_nmb()
+ *************************************************************************/
+
+this function receives a packet identified as a netbios packet.
+it further identifies whether it is a response or a query packet.
+by identifying the type of packet (name registration, query etc)
+process_nmb() will call the appropriate function to deal with the
+type of packet received.
+
+
+/*************************************************************************
+ process_dgram()
+ *************************************************************************/
+
+this function is responsible for identifying whether the datagram
+packet received is a browser packet or a domain logon packet. it
+also does some filtering of certain types of packets (e.g it
+filters out error packets).
+
+
+/*************************************************************************
+ reply_netbios_packet()
+ *************************************************************************/
+
+this function is responsible for sending a reply to another NetBIOS
+packet from another host. it can be used to send a reply to a name
+registration, name release, name query or name status request.
+
+the reply can be either a positive or a negative one.
+
+
+/*************************************************************************
+ initiate_netbios_packet()
+ *************************************************************************/
+
+this function is responsible for construction a netbios packet and sending
+it. if the packet has not had a unique transaction id allocated to it,
+then initiate_netbios_packet() will give it one.
+
+
+/*************************************************************************
+ update_name_trn_id()
+ *************************************************************************/
+
+this function is responsible for allocating unique transaction identifiers
+for each new packet sent on the network.
+
+
diff --git a/source/namequery.doc b/source/namequery.doc
new file mode 100644
index 00000000000..4337cfb7e2a
--- /dev/null
+++ b/source/namequery.doc
@@ -0,0 +1,83 @@
+/*
+ Unix SMB/Netbios documentation.
+ Version 0.0
+ Copyright (C) Luke Leighton Andrew Tridgell 1996
+
+ 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.
+
+ Document name: namequery.doc
+
+ Revision History:
+
+ 0.0 - 02jul96 : lkcl@pires.co.uk
+ created
+*/
+
+this module contains non-threaded versions of name status and name
+query functions. if a multi-threaded nmbd was to be written, these
+functions would be the starting point.
+
+at the moment, the expected response queueing system is used to
+replace these functions without needing to multi-thread nmbd.
+
+these functions are used in smbclient and nmblookup at present to
+avoid having the vast quantities of complex and unused code needed
+to support even a simple name query (or providing stubs for the
+unused side of these functions).
+
+there is a down-side to these functions, which is all microsoft's
+fault. microsoft machines always always reply to queries on the
+priveleged ports, rather than following the usual tcp/ip mechanism
+of replying on the client's port (the exception to this i am led
+to believe is windows nt 3.50).
+
+as a result of this, in order to receive a response to a name
+query from a microsoft machine, we must be able to listen on
+the priveleged netbios name server ports. this is simply not
+possible with some versions of unix, unless you have root access.
+
+it is also not possible if you run smbclient or nmblookup on an
+interface that already has been claimed by the netbios name server
+daemon nmbd.
+
+all in all, i wish that microsoft would fix this.
+
+a solution does exist: nmbd _does_ actually reply on the client's
+port, so if smbclient and nmblookup were to use nmbd as a proxy
+forwarder of queries (or to use samba's WINS capabilities) then
+a query could be made without needing access to the priveleged
+ports. in order to do this properly, samba must implement secured
+netbios name server functionality (see rfc1001.txt 15.1.6).
+(lkcl 01aug96: samba now supports secured name registration)
+
+/*************************************************************************
+ name_query()
+ *************************************************************************/
+
+
+
+/*************************************************************************
+ name_status()
+ *************************************************************************/
+
+
+
+/*************************************************************************
+ _interpret_node_status()
+ *************************************************************************/
+
+
+this is a older version of interpret_node_status().
+
diff --git a/source/nameresp.c b/source/nameresp.c
new file mode 100644
index 00000000000..7fcb41e79f0
--- /dev/null
+++ b/source/nameresp.c
@@ -0,0 +1,302 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios library routines
+ Copyright (C) Andrew Tridgell 1994-1996
+
+ 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.
+
+ Module name: nameresp.c
+
+*/
+
+#include "includes.h"
+
+extern int ClientNMB;
+extern int ClientDGRAM;
+
+extern struct subnet_record *subnetlist;
+
+extern int DEBUGLEVEL;
+
+extern pstring scope;
+extern struct in_addr ipzero;
+extern struct in_addr ipgrp;
+
+
+/***************************************************************************
+ deals with an entry before it dies
+ **************************************************************************/
+static void dead_netbios_entry(struct subnet_record *d,
+ struct response_record *n)
+{
+ DEBUG(3,("Removing dead netbios entry for %s %s (num_msgs=%d)\n",
+ inet_ntoa(n->send_ip), namestr(&n->name), n->num_msgs));
+
+ debug_state_type(n->state);
+
+ switch (n->state)
+ {
+ case NAME_QUERY_CONFIRM:
+ {
+ if (!lp_wins_support()) return; /* only if we're a WINS server */
+
+ if (n->num_msgs == 0)
+ {
+ /* oops. name query had no response. check that the name is
+ unique and then remove it from our WINS database */
+
+ /* IMPORTANT: see query_refresh_names() */
+
+ if ((!NAME_GROUP(n->nb_flags)))
+ {
+ struct subnet_record *d1 = find_subnet(ipgrp);
+ if (d1)
+ {
+ /* remove the name that had been registered with us,
+ and we're now getting no response when challenging.
+ see rfc1001.txt 15.5.2
+ */
+ remove_netbios_name(d1, n->name.name, n->name.name_type,
+ REGISTER, n->send_ip);
+ }
+ }
+ }
+ break;
+ }
+
+ case NAME_QUERY_MST_CHK:
+ {
+ /* if no response received, the master browser must have gone
+ down on that subnet, without telling anyone. */
+
+ /* IMPORTANT: see response_netbios_packet() */
+
+ if (n->num_msgs == 0)
+ browser_gone(n->name.name, n->send_ip);
+ break;
+ }
+
+ case NAME_RELEASE:
+ {
+ /* if no response received, it must be OK for us to release the
+ name. nobody objected (including a potentially dead or deaf
+ WINS server) */
+
+ /* IMPORTANT: see response_name_release() */
+
+ if (ismyip(n->send_ip))
+ {
+ name_unregister_work(d,n->name.name,n->name.name_type);
+ }
+ if (!n->bcast)
+ {
+ DEBUG(0,("WINS server did not respond to name release!\n"));
+ /* XXXX whoops. we have problems. must deal with this */
+ }
+ break;
+ }
+
+ case NAME_REGISTER_CHALLENGE:
+ {
+ /* name challenge: no reply. we can reply to the person that
+ wanted the unique name and tell them that they can have it
+ */
+
+ add_name_respond(d,n->fd,d->myip, n->response_id ,&n->name,
+ n->nb_flags, GET_TTL(0),
+ n->reply_to_ip, False, n->reply_to_ip);
+
+ if (!n->bcast)
+ {
+ DEBUG(1,("WINS server did not respond to name registration!\n"));
+ /* XXXX whoops. we have problems. must deal with this */
+ }
+ break;
+ }
+
+ case NAME_REGISTER:
+ {
+ /* if no response received, and we are using a broadcast registration
+ method, it must be OK for us to register the name: nobody objected
+ on that subnet. if we are using a WINS server, then the WINS
+ server must be dead or deaf.
+ */
+ if (n->bcast)
+ {
+ /* broadcast method: implicit acceptance of the name registration
+ by not receiving any objections. */
+
+ /* IMPORTANT: see response_name_reg() */
+
+ name_register_work(d,n->name.name,n->name.name_type,
+ n->nb_flags, n->ttl, n->reply_to_ip, n->bcast);
+ }
+ else
+ {
+ /* received no response. rfc1001.txt states that after retrying,
+ we should assume the WINS server is dead, and fall back to
+ broadcasting (see bits about M nodes: can't find any right
+ now) */
+
+ DEBUG(1,("WINS server did not respond to name registration!\n"));
+ /* XXXX whoops. we have problems. must deal with this */
+ }
+ break;
+ }
+
+ default:
+ {
+ /* nothing to do but delete the dead expected-response structure */
+ /* this is normal. */
+ break;
+ }
+ }
+}
+
+
+/*******************************************************************
+ remove old name response entries
+
+ XXXX retry code needs to be added, including a retry wait period and a count
+ see name_query() and name_status() for suggested implementation.
+
+ ******************************************************************/
+void expire_netbios_response_entries()
+{
+ struct subnet_record *d;
+
+ for (d = subnetlist; d; d = d->next)
+ {
+ struct response_record *n, *nextn;
+
+ for (n = d->responselist; n; n = nextn)
+ {
+ nextn = n->next;
+
+ if (n->repeat_time <= time(NULL))
+ {
+ if (n->repeat_count > 0)
+ {
+ /* resend the entry */
+ initiate_netbios_packet(&n->response_id, n->fd, n->quest_type,
+ n->name.name, n->name.name_type,
+ n->nb_flags, n->bcast, n->recurse, n->send_ip);
+
+ n->repeat_time += n->repeat_interval; /* XXXX ms needed */
+ n->repeat_count--;
+
+ }
+ else
+ {
+ DEBUG(4,("timeout response %d for %s %s\n",
+ n->response_id, namestr(&n->name),
+ inet_ntoa(n->send_ip)));
+
+ dead_netbios_entry (d,n); /* process the non-response */
+ remove_response_record(d,n); /* remove the non-response */
+
+ continue;
+ }
+ }
+ }
+ }
+}
+
+
+/****************************************************************************
+ 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.
+ ****************************************************************************/
+struct response_record *queue_netbios_pkt_wins(struct subnet_record *d,
+ int fd,int quest_type,enum state_type state,
+ char *name,int name_type,int nb_flags, time_t ttl,
+ int server_type, char *my_name, char *my_comment,
+ BOOL bcast,BOOL recurse,
+ struct in_addr send_ip, struct in_addr reply_to_ip)
+{
+ /* XXXX note: please see rfc1001.txt section 10 for details on this
+ function: it is currently inappropriate to use this - it will do
+ for now - once there is a clarification of B, M and P nodes and
+ which one samba is supposed to be
+ */
+
+ 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;
+ send_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(send_ip)) return NULL;
+
+ return queue_netbios_packet(d,fd, quest_type, state,
+ name, name_type, nb_flags, ttl,
+ server_type,my_name,my_comment,
+ bcast, recurse, send_ip, reply_to_ip);
+}
+
+
+/****************************************************************************
+ 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
+ ****************************************************************************/
+struct response_record *queue_netbios_packet(struct subnet_record *d,
+ int fd,int quest_type,enum state_type state,char *name,
+ int name_type,int nb_flags, time_t ttl,
+ int server_type, char *my_name, char *my_comment,
+ BOOL bcast,BOOL recurse,
+ struct in_addr send_ip, struct in_addr reply_to_ip)
+{
+ struct in_addr wins_ip = ipgrp;
+ struct response_record *n;
+ uint16 id = 0xffff;
+
+ /* ha ha. no. do NOT broadcast to 255.255.255.255: it's a pseudo address */
+ if (ip_equal(wins_ip, send_ip)) return NULL;
+
+ initiate_netbios_packet(&id, fd, quest_type, name, name_type,
+ nb_flags, bcast, recurse, send_ip);
+
+ if (id == 0xffff) {
+ DEBUG(4,("did not initiate netbios packet: %s\n", inet_ntoa(send_ip)));
+ return NULL;
+ }
+
+ if ((n = make_response_queue_record(state,id,fd,
+ quest_type,name,name_type,nb_flags,ttl,
+ server_type,my_name, my_comment,
+ bcast,recurse,send_ip,reply_to_ip)))
+ {
+ add_response_record(d,n);
+ return n;
+ }
+ return NULL;
+}
diff --git a/source/nameresp.doc b/source/nameresp.doc
new file mode 100644
index 00000000000..cfe63500c88
--- /dev/null
+++ b/source/nameresp.doc
@@ -0,0 +1,178 @@
+/*
+ Unix SMB/Netbios documentation.
+ Version 0.0
+ Copyright (C) Luke Leighton Andrew Tridgell 1996
+
+ 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.
+
+ Document name: nameresp.doc
+
+ Revision History:
+
+ 0.0 - 02jul96 : lkcl@pires.co.uk
+ created
+*/
+
+the netbios expected response code is a key part of samba's NetBIOS
+handling capabilities. it allows samba to carry on dealing with
+other things while expecting a response from one or more hosts.
+
+this allows samba to simultaneously deal with registering its names
+with another WINS server, register its names on its local subnets,
+query any hosts that have registered with samba in its capacity as
+a WINS server, and at a later date it will be also be able handle
+END-NODE CHALLENGES (see rfc1001.txt 15.2.2.2 and 15.2.2.3 - secured
+NBNS functionality).
+
+all at once!
+
+when a netbios packet is sent out by samba and it expects a response,
+a record of all the relevant information is kept (most importantly,
+the unique transaction id associated which will come back to us in
+a response packet is recorded, and also recorded is the reason that
+the original packet was sent out by samba in the first place!).
+
+if a response is received, then the unique transaction identifier
+returned in the response packet is searched for in the expected
+response records. the record indicates why the initial request was
+made (and therefore the type of response can be verified) and
+appropriate action can be taken.
+
+when no responses, after a number of retries, are not received, then
+samba may take appropriate action. this is a crucial part of samba's
+operation: for a key number of NetBIOS operations, no response is an
+implicit positive response.
+
+module nameresp deals with the initial transmission, re-transmission
+and time-out of netbios response records.
+
+module namedbresp deals with the maintenance of the list of expected
+responses - creation, finding and removal.
+
+
+/*************************************************************************
+ queue_netbios_packet()
+ *************************************************************************/
+
+this function is responsible for sending out a netbios packet, and then
+making a record of the information that was sent out. a response will
+be expected later (or not, as the case may be).
+
+if a response is received, response_netbios_packet() will deal with it.
+otherwise, it will be dealt with in expire_netbios_response_entries().
+
+
+/*************************************************************************
+ queue_netbios_pkt_wins()
+ *************************************************************************/
+
+this function is a wrapper around queue_netbios_packet(). there is
+some confusion about B, M and P nodes (see rfc1001.txt section 10) -
+confusion introduced by luke :-) - which needs sorting out.
+
+for example, rfc1001.txt 15.2.3 - an M node must attempt to register a
+name first as a B node, then attempt to register as an M node. negative
+responses on either of these attempts is a failure to register the
+name.
+
+this is NOT the case with a P node.
+
+
+/*************************************************************************
+ expire_netbios_response_entries()
+ *************************************************************************/
+
+this function is responsible for dealing with queued response records
+that have not received a response packet matching their unique
+transaction id.
+
+if the retry count for any record is non-zero, and its time-out period
+has expired, the retry count is reduced, the time-out period is stepped
+forward and the packet is re-transmitted (from the information stored
+in the queued response record) with the same unique transaction id of
+the initial attempt at soliciting a response.
+
+if the retry count is zero, then the packet is assumed to have expired.
+dead_netbios_entry() is called to deal with the possibility of an error
+or a problem (or in certain instances, no answer is an implicit
+positive response!).
+
+the expected response record is then deleted, and the number of expected
+responses reduced. when this count gets to zero, listen_for_packets()
+will no longer time-out for 1 second on account of expecting response
+packets.
+
+
+/*************************************************************************
+ dead_netbios_entry()
+ *************************************************************************/
+
+this function is responsible for dealing with the case when a NetBIOS
+response to a packet sent out by samba was not received. for certain
+transactions, this may be normal. for others, under certain conditions
+it may constitute either an error or a problem with or failure of one
+or more hosts.
+
+- NAME_QUERY_CONFIRM
+
+when a samba 'state' of type NAME_QUERY_CONFIRM is sent, a response
+may or may not be forthcoming. if no response is received to a unique
+name, then the record is removed from samba's WINS database. non-unique
+names are simply expected to die off on a time-to-live basis (see
+rfc1001.txt 15.1.3.4)
+
+query_refresh_names() issues this samba 'state'
+response_name_query_sync() deals with responses to NAME_QUERY_CONFIRM.
+
+- NAME_QUERY_MST_CHK
+
+when a samba 'state' of type NAME_QUERY_MST_CHK is sent, and a response
+is not received, this implies that a master browser will have failed.
+remedial action may need to be taken, for example if samba is a member
+of that workgroup and it is also a potential master browser it could
+force an election.
+
+check_master_browser() issues this samba 'state'.
+response_process() does nothing if a response is received. this is normal.
+
+- NAME_RELEASE
+
+when a samba 'state' of type NAME_RELEASE is sent, and a response is
+not received, it is assumed to be acceptable to release the name. if the
+original response was sent to another WINS server, then that WINS server
+may be inaccessible or may have failed. if so, then at a later date
+samba should take this into account (see rfc1001.txt 10.3).
+
+remove_name_entry() issues this samba 'state'
+response_name_rel() deals with responses to NAME_RELEASE.
+
+- NAME_REGISTER
+
+when a samba 'state' of type NAME_REGISTER is sent, and a response is
+not received, if the registration was done by broadcast, it is assumed
+that there are no objections to the registration of this name, and samba
+adds the name to the appropriate subnet record name database. if the
+registration was point-to-point (i.e with another WINS server) then that
+WINS server may be inaccessible or may have failed. if so, then at a later
+date samba should take this into account (see rfc1001.txt 10.3).
+
+add_my_name_entry() issues this samba 'state'
+response_name_reg() deals with responses to NAME_REGISTER.
+
+no action is taken for any other kinds of samba 'states' if a response
+is not received. this is not to say that action may not be appropriate,
+just that it's not been looked at yet :-)
+
+
diff --git a/source/nameserv.c b/source/nameserv.c
index 802b98ec0a0..289f6702b3b 100644
--- a/source/nameserv.c
+++ b/source/nameserv.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
NBT netbios routines and daemon - version 2
- Copyright (C) Andrew Tridgell 1994-1995
+ Copyright (C) Andrew Tridgell 1994-1996
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
@@ -18,2301 +18,313 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ Module name: nameserv.c
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+ 04 jul 96: lkcl@pires.co.uk
+ module nameserv contains name server management functions
*/
#include "includes.h"
-#include "loadparm.h"
-#include "nameserv.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);
+extern int ClientNMB;
extern int DEBUGLEVEL;
-extern pstring debugf;
-pstring servicesf = CONFIGFILE;
-
extern pstring scope;
+extern pstring myname;
+extern pstring ServerComment;
+extern struct in_addr ipzero;
+extern struct in_addr ipgrp;
-extern BOOL CanRecurse;
-
-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"
+extern struct subnet_record *subnetlist;
-#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);
-}
+extern uint16 nb_type; /* samba's NetBIOS type */
/****************************************************************************
-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;
+ remove an entry from the name list
- errcount--;
+ note: the name will _always_ be removed: it's just a matter of when.
+ XXXX at present, the name is removed _even_ if a WINS server says keep it.
- 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
-****************************************************************************/
-static BOOL name_equal(struct nmb_name *n1,struct nmb_name *n2)
-{
- if (n1->name_type != n2->name_type) return(False);
-
- return(strequal(n1->name,n2->name) && strequal(n1->scope,n2->scope));
-}
-
-/****************************************************************************
- add a netbios name into the namelist
- **************************************************************************/
-static void add_name(struct name_record *n)
-{
- struct name_record *n2;
-
- if (!namelist) {
- namelist = n;
- n->prev = NULL;
- n->next = NULL;
- return;
- }
-
- for (n2 = namelist; n2->next; n2 = n2->next) ;
-
- n2->next = n;
- n->next = NULL;
- 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)
-{
- struct name_record *nlist = namelist;
- while (nlist && nlist != n) nlist = nlist->next;
- if (nlist) {
- if (nlist->next) nlist->next->prev = nlist->prev;
- if (nlist->prev) nlist->prev->next = nlist->next;
- free(nlist);
- }
-}
-
-/****************************************************************************
- find a name in the namelist
- **************************************************************************/
-static struct name_record *find_name(struct nmb_name *n)
-{
- struct name_record *ret;
- for (ret = namelist; ret; ret = ret->next)
- if (name_equal(&ret->name,n)) return(ret);
-
- return(NULL);
-}
-
-/****************************************************************************
- dump a copy of the name table
- **************************************************************************/
-static void dump_names(void)
-{
- time_t t = time(NULL);
- struct name_record *n;
- struct domain_record *d;
-
- DEBUG(3,("Dump of local name table:\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)));
- }
-
- 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)));
-}
-
-
-/****************************************************************************
- add a host 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 *n;
- struct name_record *n2=NULL;
-
- n = (struct name_record *)malloc(sizeof(*n));
- if (!n) return(NULL);
-
- bzero((char *)n,sizeof(*n));
-
- make_nmb_name(&n->name,name,type,scope);
- if ((n2=find_name(&n->name))) {
- free(n);
- n = n2;
- }
-
- if (ttl) n->death_time = time(NULL)+ttl*3;
- n->ip = ip;
- n->unique = unique;
- 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)));
-
- return(n);
-}
-
-
-/****************************************************************************
- add a domain entry
- ****************************************************************************/
-static struct domain_record *add_domain_entry(char *name,struct in_addr ip)
-{
- 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)));
-
- return(d);
-}
-
-/****************************************************************************
- add a server entry
****************************************************************************/
-struct server_record *add_server_entry(char *name,int servertype,
- int ttl,char *comment,BOOL replace)
-{
- 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));
- }
-
- return(s);
-}
-
-
-/****************************************************************************
- add the magic samba names, useful for finding samba servers
- **************************************************************************/
-static void add_my_names(void)
-{
- struct in_addr ip;
-
- ip = *interpret_addr2("0.0.0.0");
-
- add_host_entry(myname,0x20,True,0,SELF,ip);
- add_host_entry(myname,0x0,True,0,SELF,ip);
- add_host_entry(myname,0x1f,True,0,SELF,ip); /* used for chat?? */
- add_host_entry(myname,0x3,True,0,SELF,ip); /* used for winpopup */
-
- if (!domainlist)
- add_domain_entry(lp_workgroup(),bcast_ip);
- add_server_entry(myname,
- ServerType,
- 0,ServerComment,True);
-
- add_host_entry("__SAMBA__",0x20,True,0,SELF,ip);
- add_host_entry("__SAMBA__",0x0,True,0,SELF,ip);
-
- if (lp_preferred_master()) {
- DEBUG(3,("Preferred master startup\n"));
- needelection = True;
- ElectionCriterion |= (1<<3);
- }
-
- ElectionCriterion |= (lp_os_level() << 24);
-}
-
-
-/*******************************************************************
- 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;
-
- 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));
-}
-
-/*******************************************************************
- expire old names in the namelist and serverlist
- ******************************************************************/
-static void expire_names(void)
-{
- 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;
- }
- }
-
- /* 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;
- }
- }
-}
-
-
-/*******************************************************************
- delete old names from the namelist
- ******************************************************************/
-static void housekeeping(void)
+void remove_name_entry(struct subnet_record *d, char *name,int type)
{
- time_t t = time(NULL);
+ /* XXXX BUG: if samba is offering WINS support, it should still broadcast
+ a de-registration packet to the local subnet before removing the
+ name from its local-subnet name database. */
- expire_names();
-
- /* write out the browse.dat database for smbd to get */
- if (updatedlists) {
- write_browse_list();
- updatedlists = False;
- }
+ struct name_record n;
+ struct name_record *n2=NULL;
+
+ make_nmb_name(&n.name,name,type,scope);
+ if ((n2 = find_name_search(&d, &n.name, FIND_SELF, ipzero)))
{
- /* 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;
+ /* check name isn't already being de-registered */
+ if (NAME_DEREG(n2->nb_flags))
+ return;
- 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;
- }
+ /* mark the name as in the process of deletion. */
+ n2->nb_flags &= NB_DEREG;
}
-}
-
-
-/****************************************************************************
- reload the services file
- **************************************************************************/
-BOOL reload_services(BOOL test)
-{
- BOOL ret;
- extern fstring remote_machine;
- strcpy(remote_machine,"nmbd");
-
- if (lp_loaded())
+ if (ip_equal(d->bcast_ip, ipgrp))
+ {
+ if (lp_wins_support())
{
- pstring fname;
- strcpy(fname,lp_configfile());
- if (file_exist(fname,NULL) && !strcsequal(fname,servicesf))
- {
- strcpy(servicesf,fname);
- test = False;
- }
+ /* we are a WINS server. */
+ /* XXXX assume that if we are a WINS server that we are therefore
+ not pointing to another WINS server as well. this may later NOT
+ actually be true
+ */
+ remove_netbios_name(d,name,type,SELF,ipzero);
}
-
- if (test && !lp_file_list_changed())
- return(True);
-
- ret = lp_load(servicesf,True);
-
- /* perhaps the config filename is now set */
- if (!test)
- reload_services(True);
-
- return(ret);
-}
-
-
-
-/****************************************************************************
-load a netbios hosts file
-****************************************************************************/
-static void load_hosts_file(char *fname)
-{
- FILE *f = fopen(fname,"r");
- pstring line;
- if (!f) {
- DEBUG(2,("Can't open lmhosts file %s\n",fname));
- return;
- }
-
- while (!feof(f))
+ else
{
- if (!fgets_slash(line,sizeof(pstring),f)) continue;
-
- if (*line == '#') continue;
-
- {
- BOOL group=False;
- string ip,name,flags,extra;
- char *ptr;
- int count = 0;
- struct in_addr ipaddr;
- enum name_source source = LMHOSTS;
-
- *ip = *name = *flags = *extra = 0;
-
- ptr = line;
-
- if (next_token(&ptr,ip,NULL)) ++count;
- if (next_token(&ptr,name,NULL)) ++count;
- if (next_token(&ptr,flags,NULL)) ++count;
- if (next_token(&ptr,extra,NULL)) ++count;
-
- if (count <= 0) continue;
-
- if (count > 0 && count < 2)
- {
- DEBUG(0,("Ill formed hosts line [%s]\n",line));
- continue;
- }
-
- if (strchr(flags,'G') || strchr(flags,'S'))
- group = True;
+ /* not a WINS server: cannot just remove our own names: we have to
+ release them on the network first. ask permission from the WINS
+ server, or if no reply is received, then we can remove the name */
- if (strchr(flags,'M') && !group) {
- source = SELF;
- strcpy(myname,name);
- }
-
- ipaddr = *interpret_addr2(ip);
-
- if (group) {
- add_domain_entry(name,ipaddr);
- } else {
- add_host_entry(name,0x20,True,0,source,ipaddr);
- }
- }
+ queue_netbios_pkt_wins(d,ClientNMB,NMB_REL,NAME_RELEASE,
+ name, type, 0, 0,0,NULL,NULL,
+ False, True, ipzero, ipzero);
}
-
- fclose(f);
-}
-
-/*******************************************************************
- check if 2 IPs are on the same net
- we will assume the local netmask, although this could be wrong XXXX
- ******************************************************************/
-static BOOL same_net(struct in_addr ip1,struct in_addr ip2)
-{
- unsigned long net1,net2,nmask;
-
- nmask = ntohl(Netmask.s_addr);
- net1 = ntohl(ip1.s_addr);
- net2 = ntohl(ip2.s_addr);
-
- return((net1 & nmask) == (net2 & nmask));
-}
-
-/****************************************************************************
- send an election packet
- **************************************************************************/
-static void send_election(char *group,uint32 criterion,int timeup,char *name)
-{
- pstring outbuf;
- char *p;
-
- DEBUG(2,("Sending election to %s for workgroup %s\n",
- inet_ntoa(bcast_ip),group));
-
- bzero(outbuf,sizeof(outbuf));
- p = outbuf;
- CVAL(p,0) = 8; /* election */
- p++;
-
- CVAL(p,0) = ELECTION_VERSION;
- SIVAL(p,1,criterion);
- SIVAL(p,5,timeup*1000); /* ms - despite the spec */
- p += 13;
- strcpy(p,name);
- strupper(p);
- p = skip_string(p,1);
-
- send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
- name,group,0,0x1e,bcast_ip,myip);
-}
-
-
-/****************************************************************************
- send a backup list response
- **************************************************************************/
-static void send_backup_list(char *name,int token,struct nmb_name *to,
- struct in_addr ip)
-{
- pstring outbuf;
- char *p;
-
- DEBUG(2,("Sending backup list to %s for workgroup %s\n",
- inet_ntoa(ip),PrimaryGroup));
-
- bzero(outbuf,sizeof(outbuf));
- p = outbuf;
- CVAL(p,0) = 10; /* backup list response */
- p++;
-
- CVAL(p,0) = 1; /* count */
- SIVAL(p,1,token);
- p += 5;
- strcpy(p,name);
- strupper(p);
- p = skip_string(p,1) + 1;
-
- send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
- myname,to->name,0,to->name_type,ip,myip);
-}
-
-
-/*******************************************************************
- become the master browser
- ******************************************************************/
-static void become_master(void)
-{
- uint32 domain_type = SV_TYPE_DOMAIN_ENUM | SV_TYPE_SERVER_UNIX;
- DEBUG(2,("Becoming master for %s\n",PrimaryGroup));
-
- ServerType |= SV_TYPE_MASTER_BROWSER;
- ServerType |= SV_TYPE_BACKUP_BROWSER;
- ElectionCriterion |= 0x5;
-
- add_host_entry(PrimaryGroup,0x1d,True,0,SELF,myip);
- add_host_entry(PrimaryGroup,0x0,False,0,SELF,myip);
- add_host_entry(MSBROWSE,1,False,0,SELF,myip);
-
- if (lp_domain_master()) {
- add_host_entry(myname,0x1b,True,0,SELF,myip);
- add_host_entry(PrimaryGroup,0x1b,True,0,SELF,myip);
- add_host_entry(PrimaryGroup,0x1c,False,0,SELF,myip);
- ServerType |= SV_TYPE_DOMAIN_MASTER;
- if (lp_domain_logons()) {
- ServerType |= SV_TYPE_DOMAIN_CTRL;
- ServerType |= SV_TYPE_DOMAIN_MEMBER;
- domain_type |= SV_TYPE_DOMAIN_CTRL;
- }
- }
-
- add_server_entry(PrimaryGroup,domain_type,0,myname,True);
- add_server_entry(myname,ServerType,0,ServerComment,True);
-
- announce_request(PrimaryGroup);
-
- needannounce = True;
-}
-
-
-/*******************************************************************
- unbecome the master browser
- ******************************************************************/
-static void become_nonmaster(void)
-{
- struct name_record *n;
- struct nmb_name nn;
-
- DEBUG(2,("Becoming non-master for %s\n",PrimaryGroup));
-
- ServerType &= ~SV_TYPE_MASTER_BROWSER;
- ServerType &= ~SV_TYPE_DOMAIN_CTRL;
- ServerType &= ~SV_TYPE_DOMAIN_MASTER;
-
- ElectionCriterion &= ~0x4;
-
- make_nmb_name(&nn,PrimaryGroup,0x1d,scope);
- n = find_name(&nn);
- if (n && n->source == SELF) remove_name(n);
-
- make_nmb_name(&nn,PrimaryGroup,0x1b,scope);
- n = find_name(&nn);
- if (n && n->source == SELF) remove_name(n);
-
- make_nmb_name(&nn,MSBROWSE,1,scope);
- n = find_name(&nn);
- if (n && n->source == SELF) remove_name(n);
-}
-
-
-/*******************************************************************
- run the election
- ******************************************************************/
-static void run_election(void)
-{
- time_t t = time(NULL);
- static time_t lastime = 0;
-
- if (!PrimaryGroup[0] || !RunningElection) return;
-
- /* send election packets once a second */
- if (lastime &&
- t-lastime <= 0) return;
-
- lastime = t;
-
- send_election(PrimaryGroup,ElectionCriterion,t-StartupTime,myname);
-
- if (ElectionCount++ < 4) return;
-
- /* I won! now what :-) */
- RunningElection = False;
- DEBUG(2,(">>> Won election on %s <<<\n",PrimaryGroup));
- become_master();
-}
-
-
-/****************************************************************************
- construct a host announcement unicast
- **************************************************************************/
-static void announce_host(struct domain_record *d,char *my_name,char *comment)
-{
- 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);
- }
-
- /* announce every minute at first then progress to every 12 mins */
- if (d->lastannounce_time &&
- (t - d->lastannounce_time) < d->announce_interval)
- return;
-
- if (d->announce_interval < 12*60) d->announce_interval += 60;
- d->lastannounce_time = t;
-
- DEBUG(2,("Sending announcement to %s for workgroup %s\n",
- inet_ntoa(d->bcast_ip),d->name));
-
- 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);
}
+ else
+ {
+ /* local interface: cannot just remove our own names: we have to
+ release them on the network first. once no reply is received,
+ then we can remove the name. */
- 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);
+ queue_netbios_packet(d,ClientNMB,NMB_REL,NAME_RELEASE,
+ name, type, 0, 0,0,NULL,NULL,
+ True, True, d->bcast_ip, d->bcast_ip);
}
}
/****************************************************************************
- send a announce request to the local net
- **************************************************************************/
-static void announce_request(char *group)
-{
- pstring outbuf;
- char *p;
-
- DEBUG(2,("Sending announce request to %s for workgroup %s\n",
- inet_ntoa(bcast_ip),group));
-
- bzero(outbuf,sizeof(outbuf));
- p = outbuf;
- CVAL(p,0) = 2; /* announce request */
- p++;
-
- CVAL(p,0) = 0; /* flags?? */
- p++;
- StrnCpy(p,myname,16);
- strupper(p);
- p = skip_string(p,1);
-
- send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
- myname,group,0,0,bcast_ip,myip);
-}
-
-/****************************************************************************
- announce myself as a master to the PDC
- **************************************************************************/
-static void announce_master(char *group)
-{
- static time_t last=0;
- time_t t = time(NULL);
- pstring outbuf;
- char *p;
- struct in_addr ip,pdc_ip;
- fstring pdcname;
- *pdcname = 0;
-
- if (strequal(domain_controller(),myname)) return;
-
- if (!AM_MASTER || (last && (t-last < 10*60))) return;
- last = t;
-
- ip = *interpret_addr2(domain_controller());
-
- if (zero_ip(ip)) ip = bcast_ip;
-
- if (!name_query(ClientNMB,PrimaryGroup,
- 0x1b,False,False,ip,&pdc_ip,queue_packet)) {
- DEBUG(2,("Failed to find PDC at %s\n",domain_controller()));
- return;
- }
-
- name_status(ClientNMB,PrimaryGroup,0x1b,False,
- pdc_ip,NULL,pdcname,queue_packet);
-
- if (!pdcname[0]) {
- DEBUG(3,("Can't find netbios name of PDC at %s\n",inet_ntoa(pdc_ip)));
- } else {
- sync_browse_lists(pdcname,0x20,myname,PrimaryGroup,pdc_ip);
- }
-
-
- DEBUG(2,("Sending master announce to %s for workgroup %s\n",
- inet_ntoa(pdc_ip),group));
-
- bzero(outbuf,sizeof(outbuf));
- p = outbuf;
- CVAL(p,0) = 13; /* announce request */
- p++;
-
- StrnCpy(p,myname,16);
- strupper(p);
- p = skip_string(p,1);
-
- send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
- myname,PrimaryGroup,0x1b,0,pdc_ip,myip);
-}
-
-
-/*******************************************************************
- am I listening on a name. Should check name_type as well
-
- This is primarily used to prevent us gathering server lists from
- other workgroups we aren't a part of
- ******************************************************************/
-static BOOL listening(struct nmb_name *n)
-{
- if (!strequal(n->scope,scope)) return(False);
-
- if (strequal(n->name,myname) ||
- strequal(n->name,PrimaryGroup) ||
- strequal(n->name,MSBROWSE))
- return(True);
-
- return(False);
-}
-
-
-/*******************************************************************
- process a domain announcement frame
-
- Announce frames come in 3 types. Servers send host announcements
- (command=1) to let the master browswer know they are
- available. Master browsers send local master announcements
- (command=15) to let other masters and backups that they are the
- master. They also send domain announcements (command=12) to register
- the domain
-
- The comment field of domain announcements contains the master
- browser name. The servertype is used by NetServerEnum to select
- resources. We just have to pass it to smbd (via browser.dat) and let
- the client choose using bit masks.
- ******************************************************************/
-static void process_announce(struct packet_struct *p,int command,char *buf)
-{
- struct dgram_packet *dgram = &p->packet.dgram;
- int update_count = CVAL(buf,0);
- int ttl = IVAL(buf,1)/1000;
- char *name = buf+5;
- int osmajor=CVAL(buf,21);
- int osminor=CVAL(buf,22);
- uint32 servertype = IVAL(buf,23);
- char *comment = buf+31;
-
- name[15] = 0;
- comment[43] = 0;
-
- DEBUG(3,("Announce(%d) %s count=%d ttl=%d OS=(%d,%d) type=%08x comment=%s\n",
- command,name,update_count,ttl,osmajor,osminor,
- servertype,comment));
-
- if (strequal(dgram->source_name.name,myname)) return;
-
- if (!listening(&dgram->dest_name)) return;
-
- ttl = GET_TTL(ttl);
-
- /* add them to our browse list */
- add_server_entry(name,servertype,ttl,comment,True);
-
-}
-
-/*******************************************************************
- process a master announcement frame
- ******************************************************************/
-static void process_master_announce(struct packet_struct *p,char *buf)
-{
- struct dgram_packet *dgram = &p->packet.dgram;
- char *name = buf;
-
- name[15] = 0;
+ add an entry to the name list
- 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);
+ big note: our name will _always_ be added (if there are no objections).
+ it's just a matter of when this will be done (e.g after a time-out).
- 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)
+ ****************************************************************************/
+void add_my_name_entry(struct subnet_record *d,char *name,int type,int nb_flags)
{
- struct dgram_packet *dgram = &p->packet.dgram;
- int flags = CVAL(buf,0);
- char *name = buf+1;
-
- name[15] = 0;
+ BOOL re_reg = False;
+ struct nmb_name n;
- DEBUG(3,("Announce request from %s flags=0x%X\n",name,flags));
+ if (!d) return;
- if (strequal(dgram->source_name.name,myname)) return;
+ /* not that it particularly matters, but if the SELF name already exists,
+ it must be re-registered, rather than just registered */
- needannounce = True;
-}
+ make_nmb_name(&n, name, type, scope);
+ if (find_name(d->namelist, &n, SELF))
+ re_reg = True;
+ /* XXXX BUG: if samba is offering WINS support, it should still add the
+ name entry to a local-subnet name database. see rfc1001.txt 15.1.1 p28
+ regarding the point about M-nodes. */
-/****************************************************************************
-process a browse frame
-****************************************************************************/
-static void process_browse_packet(struct packet_struct *p,char *buf,int len)
-{
- int command = CVAL(buf,0);
- switch (command)
+ if (ip_equal(d->bcast_ip, ipgrp))
+ {
+ if (lp_wins_support())
{
- 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;
+ /* we are a WINS server. */
+ /* XXXX assume that if we are a WINS server that we are therefore
+ not pointing to another WINS server as well. this may later NOT
+ actually be true
+ */
+
+ DEBUG(4,("samba as WINS server adding: "));
+ /* this will call add_netbios_entry() */
+ name_register_work(d, name, type, nb_flags,0, ipzero, False);
}
-}
-
-
-/****************************************************************************
- 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:
+ else
{
- 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));
+ /* a time-to-live allows us to refresh this name with the WINS server. */
+ queue_netbios_pkt_wins(d,ClientNMB,
+ re_reg ? NMB_REG_REFRESH : NMB_REG, NAME_REGISTER,
+ name, type, nb_flags, GET_TTL(0),0,NULL,NULL,
+ False, True, ipzero, ipzero);
}
- 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
-****************************************************************************/
-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]);
-
+ else
{
- 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?? */
+ /* broadcast the packet, but it comes from ipzero */
+ queue_netbios_packet(d,ClientNMB,
+ re_reg ? NMB_REG_REFRESH : NMB_REG, NAME_REGISTER,
+ name, type, nb_flags, GET_TTL(0),0,NULL,NULL,
+ True, True, d->bcast_ip, ipzero);
}
-
- 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
+ add the magic samba names, useful for finding samba servers
**************************************************************************/
-static void reply_name_reg(struct packet_struct *p)
+void add_my_names(void)
{
- 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;
+ BOOL wins = lp_wins_support();
+ struct subnet_record *d;
- if (wildcard) return;
+ struct in_addr ip = ipzero;
- putip((char *)&ip,&nmb->additional->rdata[2]);
+ /* each subnet entry, including WINS pseudo-subnet, has SELF names */
- if (group) {
- /* apparently we should return 255.255.255.255 for group queries (email from MS) */
- ip = *interpret_addr2("255.255.255.255");
- }
+ /* XXXX if there was a transport layer added to samba (ipx/spx etc) then
+ there would be yet _another_ for-loop, this time on the transport type
+ */
+ for (d = subnetlist; d; d = d->next)
{
- 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)));
+ BOOL wins_iface = ip_equal(d->bcast_ip, ipgrp);
+
+ add_my_name_entry(d, myname,0x20,nb_type|NB_ACTIVE);
+ add_my_name_entry(d, myname,0x03,nb_type|NB_ACTIVE);
+ add_my_name_entry(d, myname,0x00,nb_type|NB_ACTIVE);
+ add_my_name_entry(d, myname,0x1f,nb_type|NB_ACTIVE);
+
+ /* these names are added permanently (ttl of zero) and will NOT be
+ refreshed with the WINS server */
+ add_netbios_entry(d,"*",0x0,nb_type|NB_ACTIVE,0,SELF,ip,False,wins);
+ add_netbios_entry(d,"__SAMBA__",0x20,nb_type|NB_ACTIVE,0,SELF,ip,False,wins);
+ add_netbios_entry(d,"__SAMBA__",0x00,nb_type|NB_ACTIVE,0,SELF,ip,False,wins);
+
+ if (lp_domain_logons()) {
+ /* 0x1c is used to find logon servers for a domain */
+ add_my_name_entry(d, my_workgroup(),0x1c,nb_type|NB_ACTIVE|NB_GROUP);
}
- } 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 */
-
-
- buf = &nmb2->answers->rdata[0];
- SCVAL(buf,0,count);
- buf += 1;
-
- for (n = namelist ; n; n = n->next)
+ if (lp_domain_master() && (d = find_subnet(ipgrp)))
+ {
+ struct work_record *work = find_workgroupstruct(d, lp_workgroup(), True);
+ if (work && work->state == MST_NONE)
{
- 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--;
+ work->state = MST_DOMAIN_NONE;
+ become_master(d, work);
}
-
- /* XXXXXXX we should fill in more fields of the statistics structure */
- bzero(buf,64);
- {
- extern int num_good_sends,num_good_receives;
- SIVAL(buf,20,num_good_sends);
- SIVAL(buf,24,num_good_receives);
}
- SIVAL(buf,46,0xFFB8E5); /* undocumented - used by NT */
-
- buf += 64;
-
- nmb2->answers->rdlength = PTR_DIFF(buf,&nmb2->answers->rdata[0]);
-
- send_packet(&p2);
}
-
/****************************************************************************
-reply to 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;
- }
-
- /* don't respond to bcast queries for addresses on the same net as the
- machine doing the querying unless its our IP */
- if (bcast &&
- n->source != SELF &&
- same_net(n->ip,p->ip)) {
- DEBUG(3,("same net\n"));
- return;
- }
-
- /* is our entry already dead? */
- if (n->death_time) {
- if (n->death_time < p->timestamp) return;
- ttl = n->death_time - p->timestamp;
- }
-
- retip = n->ip;
- unique = n->unique;
-
- /* it may have been an earlier failure */
- if (n->source == DNSFAIL) {
- DEBUG(3,("DNSFAIL\n"));
- return;
- }
- }
-
- /* if the IP is 0 then substitute my IP - we should see which one is on the
- right interface for the caller to do this right XXX */
- if (zero_ip(retip)) retip = myip;
-
- DEBUG(3,("OK %s rcode=%d\n",inet_ntoa(retip),rcode));
-
- /* a lot of fields get copied from the query. This gives us the IP
- and port the reply will be sent to etc */
- p2 = *p;
- nmb2 = &p2.packet.nmb;
-
- nmb2->header.response = True;
- nmb2->header.nm_flags.bcast = False;
- nmb2->header.nm_flags.recursion_available = CanRecurse;
- nmb2->header.nm_flags.trunc = False;
- nmb2->header.nm_flags.authoritative = True; /* WfWg ignores
- non-authoritative answers */
- nmb2->header.qdcount = 0;
- nmb2->header.ancount = 1;
- nmb2->header.nscount = 0;
- nmb2->header.arcount = 0;
- nmb2->header.rcode = rcode;
-
- nmb2->answers = &answer_rec;
- bzero((char *)nmb2->answers,sizeof(*nmb2->answers));
-
- nmb2->answers->rr_name = nmb->question.question_name;
- nmb2->answers->rr_type = nmb->question.question_type;
- nmb2->answers->rr_class = nmb->question.question_class;
- nmb2->answers->ttl = ttl;
- nmb2->answers->rdlength = 6;
- nmb2->answers->rdata[0] = unique?0:0x80;
- nmb2->answers->rdata[1] = 0;
- putip(&nmb2->answers->rdata[2],(char *)&retip);
-
- send_packet(&p2);
-}
-
-
-
-/* the global packet linked-list. incoming entries are added to the
- end of this list. it is supposed to remain fairly short so we
- won't bother with an end pointer. */
-static struct packet_struct *packet_queue = NULL;
-
-
-/*******************************************************************
- queue a packet into the packet queue
- ******************************************************************/
-static void queue_packet(struct packet_struct *packet)
-{
- struct packet_struct *p;
- if (!packet_queue) {
- packet->prev = NULL;
- packet->next = NULL;
- packet_queue = packet;
- return;
- }
-
- /* find the bottom */
- for (p=packet_queue;p->next;p=p->next) ;
-
- p->next = packet;
- packet->next = NULL;
- packet->prev = p;
-}
-
-/****************************************************************************
- process a nmb packet
- ****************************************************************************/
-static void process_nmb(struct packet_struct *p)
+ remove all the samba names... from a WINS server if necessary.
+ **************************************************************************/
+void remove_my_names()
{
- struct nmb_packet *nmb = &p->packet.nmb;
+ struct subnet_record *d;
- /* 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)
+ for (d = subnetlist; d; d = d->next)
{
- switch (nmb->question.question_type)
- {
- case 0x20:
- reply_name_query(p);
- break;
-
- case 0x21:
- reply_name_status(p);
- break;
- }
- return;
+ struct name_record *n, *next;
+
+ for (n = d->namelist; n; n = next)
+ {
+ next = n->next;
+ if (n->source == SELF)
+ {
+ /* get all SELF names removed from the WINS server's database */
+ /* XXXX note: problem occurs if this removes the wrong one! */
+
+ remove_name_entry(d,n->name.name, n->name.name_type);
+ }
+ }
}
- 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
+ refresh my own names
******************************************************************/
-static void run_packet_queue(void)
+void refresh_my_names(time_t t)
{
- 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);
- }
-}
+ struct subnet_record *d;
-
-/****************************************************************************
- The main select loop, listen for packets and respond
- ***************************************************************************/
-void process(void)
-{
-
- while (True)
+ for (d = subnetlist; d; d = d->next)
+ {
+ struct name_record *n;
+
+ for (n = d->namelist; n; n = n->next)
{
- 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);
+ /* each SELF name has an individual time to be refreshed */
+ if (n->source == SELF && n->refresh_time < time(NULL) &&
+ n->death_time != 0)
+ {
+ add_my_name_entry(d,n->name.name,n->name.name_type,n->nb_flags);
}
-
- if (RunningElection)
- run_election();
-
- run_packet_queue();
-
- do_announcements();
-
- housekeeping();
}
-}
-
-
-/****************************************************************************
- 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, ("Socket opened.\n"));
- return True;
+ }
}
/*******************************************************************
- check that a IP, bcast and netmask and consistent. Must be a 1s
- broadcast
- ******************************************************************/
-static BOOL ip_consistent(struct in_addr ip,struct in_addr bcast,
- struct in_addr nmask)
-{
- 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);
+ queries names occasionally. an over-cautious, non-trusting WINS server!
- /* 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);
-}
+ this function has been added because nmbd could be restarted. it
+ is generally a good idea to check all the names that have been
+ reloaded from file.
-/****************************************************************************
- initialise connect, service and file structs
-****************************************************************************/
-static BOOL init_structs(void )
+ XXXX which names to poll and which not can be refined at a later date.
+ ******************************************************************/
+void query_refresh_names(void)
{
- if (!get_myname(myhostname,got_myip?NULL:&myip))
- return(False);
+ struct name_record *n;
+ struct subnet_record *d = find_subnet(ipgrp);
- /* Read the broadcast address from the interface */
- {
- struct in_addr ip0,ip1,ip2;
-
- ip0 = myip;
+ static time_t lasttime = 0;
+ time_t t = time(NULL);
- if (!(got_bcast && got_nmask))
- {
- get_broadcast(&ip0,&ip1,&ip2);
+ int count = 0;
+ int name_refresh_time = NAME_POLL_REFRESH_TIME;
+ int max_count = name_refresh_time * 2 / NAME_POLL_INTERVAL;
+ if (max_count > 10) max_count = 10;
- if (!got_myip)
- myip = ip0;
-
- if (!got_bcast)
- bcast_ip = ip1;
-
- if (!got_nmask)
- Netmask = ip2;
- }
+ name_refresh_time = NAME_POLL_INTERVAL * max_count / 2;
- 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 (!lp_poll_wins()) return; polling of registered names allowed */
- if (!ip_consistent(myip,bcast_ip,Netmask)) {
- DEBUG(0,("WARNING: The IP address, broadcast and Netmask are not consistent\n"));
- DEBUG(0,("You are likely to experience problems with this setup!\n"));
- }
- }
+ if (!d) return;
- if (! *myname) {
- char *p;
- strcpy(myname,myhostname);
- p = strchr(myname,'.');
- if (p) *p = 0;
- }
+ if (!lasttime) lasttime = t;
+ if (t - lasttime < NAME_POLL_INTERVAL) return;
- {
- extern fstring local_machine;
- strcpy(local_machine,myname);
- strupper(local_machine);
- }
-
- return True;
-}
-
-/****************************************************************************
-usage on the program
-****************************************************************************/
-static void usage(char *pname)
-{
- DEBUG(0,("Incorrect program usage - is the command line correct?\n"));
+ lasttime = time(NULL);
- 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");
+ for (n = d->namelist; n; n = n->next)
+ {
+ /* only do unique, registered names */
+
+ if (n->source != REGISTER) continue;
+ if (!NAME_GROUP(n->nb_flags)) continue;
+
+ if (n->refresh_time < t)
+ {
+ DEBUG(3,("Polling name %s\n", namestr(&n->name)));
+
+ queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_CONFIRM,
+ n->name.name, n->name.name_type,
+ 0,0,0,NULL,NULL,
+ False,False,n->ip,n->ip);
+ count++;
+ }
+
+ if (count >= max_count)
+ {
+ /* don't do too many of these at once, but do enough to
+ cover everyone in the list */
+ return;
+ }
+
+ /* this name will be checked on again, if it's not removed */
+ n->refresh_time += name_refresh_time;
+ }
}
-
-/****************************************************************************
- 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/nameserv.doc b/source/nameserv.doc
new file mode 100644
index 00000000000..af4934ade21
--- /dev/null
+++ b/source/nameserv.doc
@@ -0,0 +1,159 @@
+/*
+ Unix SMB/Netbios documentation.
+ Version 0.0
+ Copyright (C) Luke Leighton Andrew Tridgell 1996
+
+ 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.
+
+ Document name: nameserv.doc
+
+ Revision History:
+
+ 0.0 - 02jul96 : lkcl@pires.co.uk
+ created
+*/
+
+this module deals with general maintenance of NetBIOS names.
+
+/*************************************************************************
+ query_refresh_names()
+ *************************************************************************/
+
+this function is responsible for polling all names registered in the
+WINS database. it is planned to enable this function should samba
+detect an inconsistency on the network, which could occur if the
+samba NetBIOS daemon dies and is restarted.
+
+polling is done very infrequently, but all names will be covered
+within a period NAME_POLL_REFRESH_TIME. a group of at most ten names
+will be queried at once, at intervals of NAME_POLL_INTERVAL seconds.
+if the total number of names queried in this way will take too long,
+then the time that an individual name will next be polled is
+increased accordingly.
+
+name query polling is functionality over-and-above the normal
+requirement (see rfc1001.txt 15.1.7 point 7). it is normally the
+responsibility of the owner of a name to re-register the name at
+regular intervals.
+
+
+/*************************************************************************
+ refresh_my_names()
+ *************************************************************************/
+
+this function is responsible for refreshing samba's names that have
+been registered with other servers on a local subnet, or with another
+WINS server if samba is using one.
+
+samba's names' refresh_time will be updated through the use of the function
+add_my_name_entry().
+
+
+/*************************************************************************
+ remove_my_names()
+ *************************************************************************/
+
+this function is responsible for removing all samba's SELF names. it
+is used when samba receives a SIG_TERM. samba at present does not wait
+for the WINS server to reply to the name releases sent out.
+
+
+/*************************************************************************
+ add_my_names()
+ *************************************************************************/
+
+this function is responsible for adding and registering if necessary all
+samba's SELF names, on each of its local subnets and with another WINS
+server if samba is using one.
+
+/*************************************************************************
+ add_my_name_entry()
+ *************************************************************************/
+
+this function is responsible for registering or re-registering one of
+samba's names, either on the local subnet or with another WINS server
+if samba is using one.
+
+if the name is already in samba's database, then it is re-registered,
+otherwise it is simply registered.
+
+if the name is being registered in a WINS capacity (the subnet to which
+the name should be added is the WINS pseudo-subnet) then we add the entry
+immediately if samba is a WINS server. it uses name_register_work()
+because if the name is being added as part of becoming a master browser,
+we want to carry on that process. if the name is registered with another
+WINS server, we must wait for an answer from that WINS server. either
+name_register_work() or name_unregister_work() will be called as a result.
+
+if the name is being registered on a local subnet, then it is
+broadcast. an explicit rejection from another host will result
+in name_unregister_work() being called. no response will, after
+retrying, result in name_register_work() being called.
+
+what ever method is used, the name will either be registered
+or rejected, and what ever process was taking place (becoming
+a master browser for example) will carry on.
+
+expire_netbios_response_entries() is responsible for taking further
+action if no response to the registration is received.
+
+note that there may be a large number of function calls on the
+stack if become_master() is called and samba is configured as
+a WINS server. the loop will be:
+
+become_master(), add_my_name_entry(), name_register_work() and
+back to become_master() with the new value of the workgroup
+'state'.
+
+
+/*************************************************************************
+ remove_name_entry()
+ *************************************************************************/
+
+this function is responsible for removing a NetBIOS name. if the name
+being removed is registered on a local subnet, a name release should be
+broadcast on the local subnet.
+
+if the name is being released in a WINS capacity (the subnet to
+which the name should be added is the WINS pseudo-subnet) then we
+remove the entry immediately if samba is a WINS server. it uses
+name_unregister_work() because if the name is being added as part of
+becoming a master browser, we want to terminate that process. if the
+name is released from another WINS server, we must wait for an
+answer from that WINS server. name_unregister_work() will
+definitely be called as a result, because at present we ignore
+negative responses for a name release from a WINS server.
+
+if the name is being releasedd on a local subnet, then it is
+broadcast. name_unregister_work() will definitely be called
+because we ignore negative name releases at present.
+
+what ever method is used, the name will be released. (NOT TRUE!
+see response_name_release())
+
+expire_netbios_response_entries() is responsible for taking further action
+if no response to the name release is received.
+
+
+/*************************************************************************
+ load_netbios_names()
+ *************************************************************************/
+
+this function is responsible for loading any NetBIOS names that samba,
+in its WINS capacity, has written out to disk. all the relevant details
+are recorded in this file, including the time-to-live. should the
+time left to live be small, the name is not added back in to samba's
+WINS database.
+
diff --git a/source/nameservreply.c b/source/nameservreply.c
new file mode 100644
index 00000000000..5b45e88c5e7
--- /dev/null
+++ b/source/nameservreply.c
@@ -0,0 +1,569 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1996
+
+ 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.
+
+ Module name: nameservreply.c
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+ 04 jul 96: lkcl@pires.co.uk
+ created module nameservreply containing NetBIOS reply functions
+
+*/
+
+#include "includes.h"
+
+extern int ClientNMB;
+
+extern int DEBUGLEVEL;
+
+extern struct in_addr ipgrp;
+
+
+/****************************************************************************
+ add a netbios entry. respond to the (possibly new) owner.
+ **************************************************************************/
+void add_name_respond(struct subnet_record *d, int fd, struct in_addr from_ip,
+ uint16 response_id,
+ struct nmb_name *name,
+ int nb_flags, int ttl, struct in_addr register_ip,
+ BOOL new_owner, struct in_addr reply_to_ip)
+{
+ /* register the old or the new owners' ip */
+ add_netbios_entry(d,name->name,name->name_type,
+ nb_flags,ttl,REGISTER,register_ip,False,True);
+
+ /* reply yes or no to the host that requested the name */
+ send_name_response(fd,from_ip, response_id, NMB_REG,
+ new_owner, True,
+ name, nb_flags, ttl, reply_to_ip);
+}
+
+/****************************************************************************
+send a registration / release response: pos/neg
+**************************************************************************/
+void send_name_response(int fd, struct in_addr from_ip,
+ int name_trn_id, int opcode, BOOL success, BOOL recurse,
+ struct nmb_name *reply_name, int nb_flags, int ttl,
+ struct in_addr ip)
+{
+ char rdata[6];
+ struct packet_struct p;
+
+ int rcode = 0;
+
+ if (success == False)
+ {
+ /* NEGATIVE RESPONSE */
+ rcode = 6;
+ }
+ else if (opcode == NMB_REG && recurse == False)
+ {
+ /* END-NODE CHALLENGE REGISTRATION RESPONSE */
+ rcode = 0;
+ }
+
+ rdata[0] = nb_flags;
+ rdata[1] = 0;
+ putip(&rdata[2],(char *)&ip);
+
+ p.ip = from_ip;
+ p.port = NMB_PORT;
+ p.fd = fd;
+ p.timestamp = time(NULL);
+ p.packet_type = NMB_PACKET;
+
+ reply_netbios_packet(&p,name_trn_id,
+ rcode,opcode,opcode,recurse,
+ reply_name, 0x20, 0x1,
+ ttl,
+ rdata, 6);
+}
+
+
+/****************************************************************************
+reply to a name release
+****************************************************************************/
+void reply_name_release(struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct in_addr ip;
+ int nb_flags = nmb->additional->rdata[0];
+ BOOL bcast = nmb->header.nm_flags.bcast;
+ struct name_record *n;
+ struct subnet_record *d = NULL;
+ int search = 0;
+ BOOL success = False;
+
+ putip((char *)&ip,&nmb->additional->rdata[2]);
+
+ DEBUG(3,("Name release on name %s\n",
+ namestr(&nmb->question.question_name)));
+
+ if (!(d = find_req_subnet(p->ip, bcast)))
+ {
+ DEBUG(3,("response packet: bcast %s not known\n",
+ inet_ntoa(p->ip)));
+ return;
+ }
+
+ if (bcast)
+ search &= FIND_LOCAL;
+ else
+ search &= FIND_WINS;
+
+ n = find_name_search(&d, &nmb->question.question_name,
+ search, ip);
+
+ /* XXXX under what conditions should we reject the removal?? */
+ if (n && n->nb_flags == nb_flags)
+ {
+ success = True;
+
+ remove_name(d,n);
+ n = NULL;
+ }
+
+ if (bcast) return;
+
+ /* Send a NAME RELEASE RESPONSE (pos/neg) see rfc1002.txt 4.2.10-11 */
+ send_name_response(p->fd,p->ip, nmb->header.name_trn_id, NMB_REL,
+ success, False,
+ &nmb->question.question_name, nb_flags, 0, ip);
+}
+
+
+/****************************************************************************
+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;
+
+ struct nmb_name *reply_name = question;
+
+ char *qname = question->name;
+ int qname_type = question->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 = NAME_GROUP(nb_flags);
+
+ struct subnet_record *d = NULL;
+ struct name_record *n = NULL;
+
+ BOOL success = True;
+ BOOL secured_redirect = False;
+
+ struct in_addr ip, from_ip;
+ int search = 0;
+
+ putip((char *)&from_ip,&nmb->additional->rdata[2]);
+ ip = from_ip;
+
+ DEBUG(3,("Name registration for name %s at %s\n",
+ namestr(question),inet_ntoa(ip)));
+
+ if (group)
+ {
+ /* apparently we should return 255.255.255.255 for group queries
+ (email from MS) */
+ ip = ipgrp;
+ }
+
+ if (!(d = find_req_subnet(p->ip, bcast)))
+ {
+ DEBUG(3,("response packet: bcast %s not known\n",
+ inet_ntoa(p->ip)));
+ return;
+ }
+
+ if (bcast)
+ search &= FIND_LOCAL;
+ else
+ search &= FIND_WINS;
+
+ /* see if the name already exists */
+ n = find_name_search(&d, question, search, from_ip);
+
+ if (n)
+ {
+ if (!group) /* unique names */
+ {
+ if (n->source == SELF || NAME_GROUP(n->nb_flags))
+ {
+ /* no-one can register one of samba's names, nor can they
+ register a name that's a group name as a unique name */
+
+ success = False;
+ }
+ else if(!ip_equal(ip, n->ip))
+ {
+ /* XXXX rfc1001.txt says:
+ * if we are doing secured WINS, we must send a Wait-Acknowledge
+ * packet (WACK) to the person who wants the name, then do a
+ * name query on the person who currently owns the unique name.
+ * if the current owner still says they own it, the person who wants
+ * the name can't have it. if they do not, or are not alive, they can.
+ */
+
+ secured_redirect = True;
+
+ reply_name = &n->name;
+ }
+ else
+ {
+ n->ip = ip;
+ n->death_time = ttl?p->timestamp+ttl*3:0;
+ DEBUG(3,("%s owner: %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;
+ }
+ }
+
+ /* XXXX bug reported by terryt@ren.pc.athabascau.ca */
+ /* names that people have checked for and not found get DNSFAILed.
+ we need to update the name record if someone then registers */
+
+ if (n->source == DNSFAIL)
+ n->source = REGISTER;
+
+ }
+ else
+ {
+ /* add the name to our name/subnet, or WINS, database */
+ n = add_netbios_entry(d,qname,qname_type,nb_flags,ttl,REGISTER,ip,
+ True,!bcast);
+ }
+
+ /* if samba owns a unique name on a subnet, then it must respond and
+ disallow the attempted registration. if the registration is
+ successful by broadcast, only then is there no need to respond
+ (implicit registration: see rfc1001.txt 15.2.1).
+ */
+
+ if (bcast && success) return;
+
+ if (secured_redirect)
+ {
+ char rdata[2];
+
+ /* XXXX luke is confused. RSVAL or SSVAL? assume NMB byte ordering */
+ RSSVAL(rdata,0,(nmb->header.opcode&0xf) + ((nb_flags&0xff) << 4));
+
+ /* XXXX mistake in rfc1002.txt? 4.2.16: NULL is 0xa see 4.2.1.3
+ type = 0x0a; see rfc1002.txt 4.2.1.3
+ class = 0x01; see rfc1002.txt 4.2.16
+ */
+
+ /* send WAIT ACKNOWLEDGEMENT see rfc1002.txt 4.2.16 */
+ reply_netbios_packet(p,nmb->header.name_trn_id,
+ 0,NMB_WAIT_ACK,NMB_WAIT_ACK,False,
+ reply_name, 0x0a, 0x01,
+ 15*1000, /* 15 seconds long enough to wait? */
+ rdata, 2);
+
+ /* initiate some enquiries to the current owner. */
+ queue_netbios_packet(d,ClientNMB,NMB_QUERY,
+ NAME_REGISTER_CHALLENGE,
+ reply_name->name,reply_name->name_type,
+ nb_flags,0,0,NULL,NULL,
+ False, False, n->ip, p->ip);
+ }
+ else
+ {
+ /* Send a NAME REGISTRATION RESPONSE (pos/neg) see rfc1002.txt 4.2.13-14
+ or an END-NODE CHALLENGE REGISTRATION RESPONSE see rfc1002.txt 4.2.7
+ */
+
+ send_name_response(p->fd,p->ip, nmb->header.name_trn_id, NMB_REG,
+ success, True,
+ reply_name, nb_flags, ttl, ip);
+ }
+}
+
+
+/****************************************************************************
+ reply to a name status query
+
+ combine the list of the local interface on which the query was made with
+ the names registered via wins.
+ ****************************************************************************/
+void reply_name_status(struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ char *qname = nmb->question.question_name.name;
+ int ques_type = nmb->question.question_name.name_type;
+ char rdata[MAX_DGRAM_SIZE];
+ char *countptr, *buf, *bufend;
+ int names_added;
+ struct name_record *n;
+ struct subnet_record *d = NULL;
+ int search = FIND_SELF | FIND_WINS;
+
+ BOOL bcast = nmb->header.nm_flags.bcast;
+
+ if (!(d = find_req_subnet(p->ip, bcast)))
+ {
+ DEBUG(3,("Name status req: bcast %s not known\n",
+ inet_ntoa(p->ip)));
+ return;
+ }
+
+ DEBUG(3,("Name status for name %s %s\n",
+ namestr(&nmb->question.question_name), inet_ntoa(p->ip)));
+
+ if (bcast)
+ search |= FIND_LOCAL;
+
+ n = find_name_search(&d, &nmb->question.question_name,
+ search, p->ip);
+
+ if (!n) return;
+
+ /* XXXX hack, we should calculate exactly how many will fit */
+ bufend = &rdata[MAX_DGRAM_SIZE] - 18;
+ countptr = buf = rdata;
+ buf += 1;
+
+ names_added = 0;
+
+ n = d->namelist;
+
+ while (buf < bufend)
+ {
+ if (n->source == SELF)
+ {
+ int name_type = n->name.name_type;
+
+ /* check if we want to exclude other workgroup names
+ from the response. if we don't exclude them, windows clients
+ get confused and will respond with an error for NET VIEW */
+
+ if (name_type < 0x1b || name_type > 0x20 ||
+ ques_type < 0x1b || ques_type > 0x20 ||
+ strequal(qname, n->name.name))
+ {
+ /* start with first bit of putting info in buffer: the name */
+ bzero(buf,18);
+ sprintf(buf,"%-15.15s",n->name.name);
+ strupper(buf);
+
+ /* put name type and netbios flags in buffer */
+ buf[15] = name_type;
+ buf[16] = n->nb_flags;
+
+ buf += 18;
+
+ names_added++;
+ }
+ }
+
+ n = n->next;
+
+ if (!n)
+ {
+ /* end of this name list: add wins names too? */
+ struct subnet_record *w_d;
+
+ if (!(w_d = find_subnet(ipgrp))) break;
+
+ if (w_d != d)
+ {
+ d = w_d;
+ n = d->namelist; /* start on the wins name list */
+ }
+ }
+ if (!n) break;
+ }
+
+ SCVAL(countptr,0,names_added);
+
+ /* 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);
+ }
+
+ buf += 46;
+
+ /* Send a POSITIVE NAME STATUS RESPONSE */
+ reply_netbios_packet(p,nmb->header.name_trn_id,
+ 0,NMB_STATUS,0,True,
+ &nmb->question.question_name,
+ nmb->question.question_type,
+ nmb->question.question_class,
+ 0,
+ rdata,PTR_DIFF(buf,rdata));
+}
+
+
+/***************************************************************************
+reply to a name query.
+
+with broadcast name queries:
+
+ - 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.
+
+ - NEVER send a negative response to a broadcast query. no-one else will!
+
+with directed name queries:
+
+ - if you are the WINS server, you are expected to respond with either
+ a negative response, a positive response, or a wait-for-acknowledgement
+ packet, and then later on a pos/neg response.
+
+****************************************************************************/
+void reply_name_query(struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
+ int name_type = question->name_type;
+ 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 subnet_record *d = NULL;
+ BOOL success = True;
+ struct name_record *n;
+
+ /* directed queries are for WINS server: broadcasts are local SELF queries.
+ the exception is Domain Master names. */
+
+ int search = bcast ? FIND_LOCAL | FIND_SELF : FIND_WINS;
+
+ if (name_type == 0x1b || name_type == 0x0 || name_type == 0x20)
+ {
+ search |= FIND_WINS;
+ }
+
+ if (search | FIND_LOCAL)
+ {
+ if (!(d = find_req_subnet(p->ip, bcast)))
+ {
+ DEBUG(3,("name query: bcast %s not known\n",
+ inet_ntoa(p->ip)));
+ success = False;
+ }
+ }
+ else
+ {
+ if (!(d = find_subnet(ipgrp)))
+ {
+ DEBUG(3,("name query: wins search %s not known\n",
+ inet_ntoa(p->ip)));
+ success = False;
+ }
+ }
+
+ DEBUG(3,("Name query "));
+
+ if (search == 0)
+ {
+ /* eh? no criterion for searching database. help! */
+ success = False;
+ }
+
+ if (success && (n = search_for_name(&d,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) {
+ if (!lp_wins_proxy() || same_net(p->ip,n->ip,*iface_nmask(p->ip))) {
+ /* never reply with a negative response to broadcast queries */
+ return;
+ }
+ }
+
+ /* name is directed query, or it's self, or it's a Domain Master type
+ name, or we're replying on behalf of a caller because they are on a
+ different subnet and cannot hear the broadcast. XXXX lp_wins_proxy
+ should be switched off in environments where broadcasts are forwarded
+ */
+
+ /* XXXX note: for proxy servers, we should forward the query on to
+ another WINS server if the name is not in our database, or we are
+ not a WINS server ourselves
+ */
+ ttl = n->death_time ? n->death_time - p->timestamp : GET_TTL(0);
+ retip = n->ip;
+ nb_flags = n->nb_flags;
+ }
+ else
+ {
+ if (bcast) return; /* never reply negative response to bcasts */
+ success = False;
+ }
+
+ /* if the IP is 0 then substitute my IP */
+ if (zero_ip(retip)) retip = *iface_ip(p->ip);
+
+ if (success)
+ {
+ rcode = 0;
+ DEBUG(3,("OK %s\n",inet_ntoa(retip)));
+ }
+ else
+ {
+ rcode = 3;
+ DEBUG(3,("UNKNOWN\n"));
+ }
+
+ if (success)
+ {
+ rdata[0] = nb_flags;
+ rdata[1] = 0;
+ putip(&rdata[2],(char *)&retip);
+ }
+
+ reply_netbios_packet(p,nmb->header.name_trn_id,
+ rcode,NMB_QUERY,0,True,
+ &nmb->question.question_name,
+ nmb->question.question_type,
+ nmb->question.question_class,
+ ttl,
+ rdata, success ? 6 : 0);
+}
+
+
diff --git a/source/nameservreply.doc b/source/nameservreply.doc
new file mode 100644
index 00000000000..a5acf8a9c26
--- /dev/null
+++ b/source/nameservreply.doc
@@ -0,0 +1,213 @@
+/*
+ Unix SMB/Netbios documentation.
+ Version 0.0
+ Copyright (C) Luke Leighton Andrew Tridgell 1996
+
+ 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.
+
+ Document name: nameservreply.doc
+
+ Revision History:
+
+ 0.0 - 02jul96 : lkcl@pires.co.uk
+ created
+*/
+
+/*************************************************************************
+ reply_name_query()
+ *************************************************************************/
+
+this function is responsible for replying to a NetBIOS name query.
+
+there are two kinds of name queries: directed, and broadcast. directed
+queries are usually sent to samba in its WINS capacity. such hosts are
+termed 'point-to-point' hosts. broadcast queries are usually sent from
+'broadcast' or 'mixed' hosts.
+
+broadcasting is used by either older NetBIOS hosts, new NetBIOS hosts that
+have not had WINS capabilities added and new NetBIOS hosts that think the
+WINS server has died.
+
+the samba NetBIOS name database is divided into sections, on a
+per-subnet basis. there is also a WINS NetBIOS name database, and for
+convenience this is added as a pseudo-subnet with the ip address of
+255.255.255.255.
+
+the local subnet NetBIOS name databases only contain samba's names.
+the reason for this is that if a broadcast query is received, a NetBIOS
+hosts is only expected to respond if that query is for one of its own
+names (the exception to this is if a host is configured as a 'proxy'
+server, in which case, samba should redirect the query to another WINS
+server).
+
+the WINS pseudo-subnet NetBIOS database contains all NetBIOS names
+that are not 'special browser' type names (regarding this i am a
+_bit_ confused :-). names of type 0x01, 0x1d and 0x1e i consider to
+be 'special browser' names. at the moment. maybe.
+
+the type of search to be initiated is determined. if the NetBIOS name
+type is a non-special-browser name, then the WINS database is included
+in the search.
+
+if the name is not a special browser name, then we need to find the
+right subnet that the query came from. this is done using
+find_req_subnet(). this also has the benefit of stopping any queries
+from subnets that samba does not know about.
+
+if the query is a broadcast query, then the database of the local subnet
+is included in the search.
+
+the name is then searched for in the appropriate NetBIOS data structures.
+if it is found, then we need to check whether it is appropriate for us
+to reply to such a query.
+
+we will only reply if the query is a directed query, the name belongs to
+samba on that subnet, or the name is a domain master browser type,
+or we're doing replies on behalf of hosts on subnets not known to the
+host issuing the query. in the latter instance, it would be appropriate
+if samba is using a WINS server for it to forward the name query on to
+this WINS server.
+
+reply_name_query() then takes note of all the information that is
+needed to construct a reply to the caller. a negative reply (if the
+name is unknown to samba) or a positive reply (the name is known to
+samba) is then issued.
+
+
+/*************************************************************************
+ reply_name_status()
+ *************************************************************************/
+
+this function is responsible for constructing a reply to a NetBIOS
+name status query. this response contains all samba's NetBIOS names
+on the subnet that the query came in from.
+
+a reply will only be made if the NetBIOS name being queried exists.
+
+see rfc1001.txt and rfc1002.txt for details of the name status reply.
+
+
+/*************************************************************************
+ reply_name_reg()
+ *************************************************************************/
+
+this function is responsible for updating the NetBIOS name database
+from registration packets sent out by hosts wishing to register a
+name, and for informing them, if necessary, if this is acceptable
+or not.
+
+name registration can be done by broadcast or by point-to-point,
+i.e the registration is sent directly to samba in its capacity as
+a WINS server.
+
+if the name registration is done by broadcast (see rfc1001.txt 15.2.1),
+then samba's involvement in replying is limited to whether that name
+is owned by samba or not, on the relevant subnet.
+
+if the name registration is done point-to-point (see rfc1001.txt 15.2.2)
+then samba will first need to check its WINS name database records and
+proceed accordingly.
+
+samba looks for the appropriate subnet record that the registration
+should be added to / checked against, using find_req_subnet().
+
+next, the name is searched for in the local database or the WINS
+database as appropriate.
+
+if the name is not found, then it is added to the NetBIOS name database,
+using add_netbios_entry(), which may choose not to add the name (not
+that this affects the registration of the name on the network in any way).
+it will only add names to the WINS database, and even then it will only
+add non-special-browser type names.
+
+if the name is found, then samba must decide whether to accept the name
+or not. a group name is always added. for unique names, further checks
+need to be carried out.
+
+firstly, if the name in the database is one of samba's names, or if the
+name in the database is a group name, then it cannot be added as a unique
+name belonging to someone else. it is therefore rejected.
+
+secondly, if the ip address of the name being registered does not match
+against the ip in the database, then the unique name may belong to
+someone else. a check needs to be carried out with the owner in case
+they still wish to keep this name. a detailed discussion of what action
+to take is in rfc1001.txt 15.2.2.2 and 15.2.2.3.
+
+samba currently implements non-secured WINS, whereupon the responsibility
+for checking the name is passed on to the host doing the registration.
+rfc1001.txt refers to this as an END-NODE CHALLENGE REGISTRATION RESPONSE.
+(samba itself cannot yet cope with receiving such responses if it
+registers its names with another WINS server).
+
+having decided what kind of response to send (if any - acceptance of
+name registrations by broadcast is implicit), samba will send either a
+positive or negative NAME REGISTRATION RESPONSE, or an END-NODE CHALLENGE
+REGISTRATION RESPONSE to the host that initially sent the registration.
+
+whew.
+
+
+/*************************************************************************
+ reply_name_release()
+ *************************************************************************/
+
+this function is responsible for removing a NetBIOS name from the
+database when a server sends a release packet.
+
+samba looks for the appropriate subnet record that the release should
+be removed from, using find_req_subnet(). next, the name is searched
+for in the local database or the WINS database as appropriate.
+
+if the name is found, it is removed from the database and a
+positive reply is sent confirming this. if the name is not
+found, a negative reply is sent.
+
+a reply is _not_ sent if the release was done by broadcast: the
+release is implicit, and we should be grateful that they bothered
+to tell us. if the release was done by directed packet, then
+we deal with it as a WINS server and must reply (pos / neg).
+
+at present, the criteria for removing a name have yet to be
+developed / experimented with. at present, the only flags that
+are checked are the NetBIOS flags.
+
+
+/*************************************************************************
+ send_name_response()
+ *************************************************************************/
+
+this function is a wrap around reply_netbios_packet(). it sends
+a response to a name registration or release packet, minimising
+the function parameters needed to do this.
+
+if the function is called with the parameter 'success' set to
+True, then a positive response (to the registration or release)
+is made (see rfc1002.txt 4.2.5 and 4.2.10). if this parameter
+is False, then a negative response is issued (see rfc1002.txt
+4.2.6 and 4.2.11)
+
+if the function is called with a registration code, and the
+parameter 'recurse' is False, then an End-Node Challenge
+Registration response is issued (see rfc1002.txt 4.2.7)
+
+note: this function could also easily be used for name conflict
+demand (see rfc1002.txt 4.2.8).
+
+note: End-Node Challenge Registration response is only sent in
+non-secured NetBIOS Name Server implementations. samba now
+implements secured NetBIOS Name Server functionality (see
+rfc1001.txt 15.1.6).
+
diff --git a/source/nameservresp.c b/source/nameservresp.c
new file mode 100644
index 00000000000..a4cda7cdfb5
--- /dev/null
+++ b/source/nameservresp.c
@@ -0,0 +1,822 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1996
+
+ 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:
+
+ Module name: nameservresp.c
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+ 05 jul 96: lkcl@pires.co.uk
+ created module nameservresp containing NetBIOS response functions
+
+*/
+
+#include "includes.h"
+
+extern int ClientNMB;
+
+extern int DEBUGLEVEL;
+
+extern pstring scope;
+extern struct in_addr ipzero;
+
+#define GET_TTL(ttl) ((ttl)?MIN(ttl,lp_max_ttl()):lp_max_ttl())
+
+
+/****************************************************************************
+ response for a reg release received. samba has asked a WINS server if it
+ could release a name.
+ **************************************************************************/
+static void response_name_release(struct subnet_record *d,
+ struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ char *name = nmb->question.question_name.name;
+ int type = nmb->question.question_name.name_type;
+
+ DEBUG(4,("response name release received\n"));
+
+ if (nmb->header.rcode == 0 && nmb->answers->rdata)
+ {
+ /* IMPORTANT: see expire_netbios_response_entries() */
+
+ struct in_addr found_ip;
+ putip((char*)&found_ip,&nmb->answers->rdata[2]);
+
+ /* NOTE: we only release our own names at present */
+ if (ismyip(found_ip))
+ {
+ name_unregister_work(d,name,type);
+ }
+ else
+ {
+ DEBUG(2,("name release for different ip! %s %s\n",
+ inet_ntoa(found_ip),
+ namestr(&nmb->question.question_name)));
+ }
+ }
+ else
+ {
+ DEBUG(2,("name release for %s rejected!\n",
+ namestr(&nmb->question.question_name)));
+
+ /* XXXX PANIC! what to do if it's one of samba's own names? */
+
+ /* XXXX do we honestly care if our name release was rejected?
+ only if samba is issuing the release on behalf of some out-of-sync
+ server. if it's one of samba's SELF names, we don't care. */
+ }
+}
+
+
+/****************************************************************************
+response for a reg request received
+**************************************************************************/
+static void response_name_reg(struct subnet_record *d, struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ char *name = nmb->question.question_name.name;
+ int type = nmb->question.question_name.name_type;
+ BOOL bcast = nmb->header.nm_flags.bcast;
+
+ DEBUG(4,("response name registration received!\n"));
+
+ if (nmb->header.rcode == 0 && nmb->answers->rdata)
+ {
+ /* IMPORTANT: see expire_netbios_response_entries() */
+
+ int nb_flags = nmb->answers->rdata[0];
+ int ttl = nmb->answers->ttl;
+ struct in_addr found_ip;
+
+ putip((char*)&found_ip,&nmb->answers->rdata[2]);
+
+ name_register_work(d,name,type,nb_flags,ttl,found_ip,bcast);
+ }
+ else
+ {
+ DEBUG(1,("name registration for %s rejected!\n",
+ namestr(&nmb->question.question_name)));
+
+ /* oh dear. we have problems. possibly unbecome a master browser. */
+ name_unregister_work(d,name,type);
+ }
+}
+
+
+/****************************************************************************
+ response from a name query announce host
+ NAME_QUERY_ANNOUNCE_HOST is dealt with here
+ ****************************************************************************/
+static void response_announce_host(struct nmb_name *ans_name,
+ struct nmb_packet *nmb,
+ struct response_record *n, struct subnet_record *d)
+{
+ DEBUG(4, ("Name query at %s ip %s - ",
+ namestr(&n->name), inet_ntoa(n->send_ip)));
+
+ if (!name_equal(&n->name, ans_name))
+ {
+ /* someone gave us the wrong name as a reply. oops. */
+ /* XXXX should say to them 'oi! release that name!' */
+
+ DEBUG(4,("unexpected name received: %s\n", namestr(ans_name)));
+ return;
+ }
+
+ if (nmb->header.rcode == 0 && nmb->answers->rdata)
+ {
+ /* we had sent out a name query to the current owner
+ of a name because someone else wanted it. now they
+ have responded saying that they still want the name,
+ so the other host can't have it.
+ */
+
+ /* first check all the details are correct */
+
+ int nb_flags = nmb->answers->rdata[0];
+ struct in_addr found_ip;
+
+ putip((char*)&found_ip,&nmb->answers->rdata[2]);
+
+ if (nb_flags != n->nb_flags)
+ {
+ /* someone gave us the wrong nb_flags as a reply. oops. */
+ /* XXXX should say to them 'oi! release that name!' */
+
+ DEBUG(4,("expected nb_flags: %d\n", n->nb_flags));
+ DEBUG(4,("unexpected nb_flags: %d\n", nb_flags));
+ return;
+ }
+
+ /* do an announce host */
+ do_announce_host(ANN_HostAnnouncement,
+ n->my_name , 0x00, d->myip,
+ n->name.name, 0x1d, found_ip,
+ n->ttl,
+ n->my_name, n->server_type, n->my_comment);
+ }
+ else
+ {
+ /* XXXX negative name query response. no master exists. oops */
+ }
+}
+
+
+/****************************************************************************
+ response from a name query server check. states of type NAME_QUERY_DOM_SRV_CHK,
+ NAME_QUERY_SRV_CHK, and NAME_QUERY_FIND_MST dealt with here.
+ ****************************************************************************/
+static void response_server_check(struct nmb_name *ans_name,
+ struct response_record *n, struct subnet_record *d)
+{
+ /* issue another state: this time to do a name status check */
+
+ enum state_type cmd = (n->state == NAME_QUERY_DOM_SRV_CHK) ?
+ NAME_STATUS_DOM_SRV_CHK : NAME_STATUS_SRV_CHK;
+
+ /* initiate a name status check on the server that replied */
+ queue_netbios_packet(d,ClientNMB,NMB_STATUS, cmd,
+ ans_name->name, ans_name->name_type,
+ 0,0,0,NULL,NULL,
+ False,False,n->send_ip,n->reply_to_ip);
+}
+
+
+/****************************************************************************
+ 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.
+****************************************************************************/
+static BOOL interpret_node_status(struct subnet_record *d,
+ char *p, struct nmb_name *name,int t,
+ char *serv_name, struct in_addr ip, BOOL bcast)
+{
+ 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];
+ trim_string(qname,NULL," ");
+
+ 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_HFLAG (nb_flags)) { strcat(flags,"H "); }
+ 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 (ismyip(ip)) {
+ nameip = ipzero;
+ src = SELF;
+ } else {
+ nameip = ip;
+ src = STATUS_QUERY;
+ }
+ add_netbios_entry(d,qname,type,nb_flags,2*60*60,src,nameip,True,bcast);
+ }
+
+ /* 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;
+}
+
+
+/****************************************************************************
+ response from a name status check. states of type NAME_STATUS_DOM_SRV_CHK
+ and NAME_STATUS_SRV_CHK dealt with here.
+ ****************************************************************************/
+static void response_name_status_check(struct in_addr ip,
+ struct nmb_packet *nmb, BOOL bcast,
+ struct response_record *n, struct subnet_record *d)
+{
+ /* NMB_STATUS arrives: contains workgroup name and server name required.
+ amongst other things. */
+
+ struct nmb_name name;
+ fstring serv_name;
+
+ if (interpret_node_status(d,nmb->answers->rdata,
+ &name,name.name_type,serv_name,ip,bcast))
+ {
+ if (*serv_name)
+ {
+ sync_server(n->state,serv_name,
+ name.name,name.name_type, n->send_ip);
+ }
+ }
+ else
+ {
+ DEBUG(1,("No 0x1d name type in interpret_node_status()\n"));
+ }
+}
+
+
+/****************************************************************************
+ response from a name query for secured WINS registration. a state of
+ NAME_REGISTER_CHALLENGE is dealt with here.
+ ****************************************************************************/
+static void response_name_query_register(struct nmb_packet *nmb,
+ struct nmb_name *ans_name,
+ struct response_record *n, struct subnet_record *d)
+{
+ struct in_addr register_ip;
+ BOOL new_owner;
+
+ DEBUG(4, ("Name query at %s ip %s - ",
+ namestr(&n->name), inet_ntoa(n->send_ip)));
+
+ if (!name_equal(&n->name, ans_name))
+ {
+ /* someone gave us the wrong name as a reply. oops. */
+ /* XXXX should say to them 'oi! release that name!' */
+
+ DEBUG(4,("unexpected name received: %s\n", namestr(ans_name)));
+ return;
+ }
+
+ if (nmb->header.rcode == 0 && nmb->answers->rdata)
+ {
+ /* we had sent out a name query to the current owner
+ of a name because someone else wanted it. now they
+ have responded saying that they still want the name,
+ so the other host can't have it.
+ */
+
+ /* first check all the details are correct */
+
+ int nb_flags = nmb->answers->rdata[0];
+ struct in_addr found_ip;
+
+ putip((char*)&found_ip,&nmb->answers->rdata[2]);
+
+ if (nb_flags != n->nb_flags)
+ {
+ /* someone gave us the wrong nb_flags as a reply. oops. */
+ /* XXXX should say to them 'oi! release that name!' */
+
+ DEBUG(4,("expected nb_flags: %d\n", n->nb_flags));
+ DEBUG(4,("unexpected nb_flags: %d\n", nb_flags));
+ return;
+ }
+
+ if (!ip_equal(n->send_ip, found_ip))
+ {
+ /* someone gave us the wrong ip as a reply. oops. */
+ /* XXXX should say to them 'oi! release that name!' */
+
+ DEBUG(4,("expected ip: %s\n", inet_ntoa(n->send_ip)));
+ DEBUG(4,("unexpected ip: %s\n", inet_ntoa(found_ip)));
+ return;
+ }
+
+ DEBUG(4, (" OK: %s\n", inet_ntoa(found_ip)));
+
+ /* fine: now tell the other host they can't have the name */
+ register_ip = n->send_ip;
+ new_owner = False;
+ }
+ else
+ {
+ DEBUG(4, (" NEGATIVE RESPONSE!\n"));
+
+ /* the owner didn't want the name: the other host can have it */
+ register_ip = n->reply_to_ip;
+ new_owner = True;
+ }
+
+ /* register the old or the new owners' ip */
+ add_name_respond(d, n->fd, d->myip, n->response_id,&n->name,n->nb_flags,
+ GET_TTL(0), register_ip,
+ new_owner, n->reply_to_ip);
+}
+
+
+/****************************************************************************
+ response from a name query to sync browse lists or to update our netbios
+ entry. states of type NAME_QUERY_SYNC and NAME_QUERY_CONFIRM
+ ****************************************************************************/
+static void response_name_query_sync(struct nmb_packet *nmb,
+ struct nmb_name *ans_name, BOOL bcast,
+ struct response_record *n, struct subnet_record *d)
+{
+ DEBUG(4, ("Name query at %s ip %s - ",
+ namestr(&n->name), inet_ntoa(n->send_ip)));
+
+ if (!name_equal(&n->name, ans_name))
+ {
+ /* someone gave us the wrong name as a reply. oops. */
+ DEBUG(4,("unexpected name received: %s\n", namestr(ans_name)));
+ return;
+ }
+
+ 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]);
+
+ if (!ip_equal(n->send_ip, found_ip))
+ {
+ /* someone gave us the wrong ip as a reply. oops. */
+ DEBUG(4,("expected ip: %s\n", inet_ntoa(n->send_ip)));
+ DEBUG(4,("unexpected ip: %s\n", inet_ntoa(found_ip)));
+ return;
+ }
+
+ DEBUG(4, (" OK: %s\n", inet_ntoa(found_ip)));
+
+ if (n->state == NAME_QUERY_SYNC_LOCAL ||
+ n->state == NAME_QUERY_SYNC_REMOTE)
+ {
+ struct work_record *work = NULL;
+ if ((work = find_workgroupstruct(d, ans_name->name, False)))
+ {
+ BOOL local_list_only = n->state == NAME_QUERY_SYNC_LOCAL;
+
+ /* the server is there: sync quick before it (possibly) dies! */
+ sync_browse_lists(d, work, ans_name->name, ans_name->name_type,
+ found_ip, local_list_only);
+ }
+ }
+ else
+ {
+ /* update our netbios name list (re-register it if necessary) */
+ add_netbios_entry(d, ans_name->name, ans_name->name_type,
+ nb_flags,GET_TTL(0),REGISTER,
+ found_ip,False,!bcast);
+ }
+ }
+ else
+ {
+ DEBUG(4, (" NEGATIVE RESPONSE!\n"));
+
+ if (n->state == NAME_QUERY_CONFIRM)
+ {
+ /* XXXX remove_netbios_entry()? */
+ /* lots of things we ought to do, here. if we get here,
+ then we're in a mess: our name database doesn't match
+ reality. sort it out
+ */
+ remove_netbios_name(d,n->name.name, n->name.name_type,
+ REGISTER,n->send_ip);
+ }
+ }
+}
+
+
+/****************************************************************************
+ report the response record type
+ ****************************************************************************/
+static void debug_rr_type(int rr_type)
+{
+ switch (rr_type)
+ {
+ case NMB_STATUS: DEBUG(3,("Name status ")); break;
+ case NMB_QUERY : DEBUG(3,("Name query ")); break;
+ case NMB_REG : DEBUG(3,("Name registration ")); break;
+ case NMB_REL : DEBUG(3,("Name release ")); break;
+ default : DEBUG(1,("wrong response packet type received")); break;
+ }
+}
+
+/****************************************************************************
+ report the response record nmbd state
+ ****************************************************************************/
+void debug_state_type(int state)
+{
+ /* report the state type to help debugging */
+ switch (state)
+ {
+ case NAME_QUERY_DOM_SRV_CHK : DEBUG(4,("MASTER_SVR_CHECK\n")); break;
+ case NAME_QUERY_SRV_CHK : DEBUG(4,("NAME_QUERY_SRV_CHK\n")); break;
+ case NAME_QUERY_FIND_MST : DEBUG(4,("NAME_QUERY_FIND_MST\n")); break;
+ case NAME_QUERY_MST_CHK : DEBUG(4,("NAME_QUERY_MST_CHK\n")); break;
+ case NAME_QUERY_CONFIRM : DEBUG(4,("NAME_QUERY_CONFIRM\n")); break;
+ case NAME_QUERY_SYNC_LOCAL : DEBUG(4,("NAME_QUERY_SYNC_LOCAL\n")); break;
+ case NAME_QUERY_SYNC_REMOTE : DEBUG(4,("NAME_QUERY_SYNC_REMOTE\n")); break;
+ case NAME_QUERY_ANNOUNCE_HOST: DEBUG(4,("NAME_QUERY_ANNCE_HOST\n"));break;
+
+ case NAME_REGISTER : DEBUG(4,("NAME_REGISTER\n")); break;
+ case NAME_REGISTER_CHALLENGE : DEBUG(4,("NAME_REGISTER_CHALLENGE\n"));break;
+
+ case NAME_RELEASE : DEBUG(4,("NAME_RELEASE\n")); break;
+
+ case NAME_STATUS_DOM_SRV_CHK : DEBUG(4,("NAME_STAT_MST_CHK\n")); break;
+ case NAME_STATUS_SRV_CHK : DEBUG(4,("NAME_STATUS_SRV_CHK\n")); break;
+
+ default: break;
+ }
+}
+
+/****************************************************************************
+ report any problems with the fact that a response has been received.
+
+ (responses for certain types of operations are only expected from one host)
+ ****************************************************************************/
+static BOOL response_problem_check(struct response_record *n,
+ struct nmb_packet *nmb, char *qname)
+{
+ switch (nmb->answers->rr_type)
+ {
+ case NMB_REL:
+ {
+ if (n->num_msgs > 1)
+ {
+ DEBUG(1,("more than one release name response received!\n"));
+ return True;
+ }
+ break;
+ }
+
+ case NMB_REG:
+ {
+ if (n->num_msgs > 1)
+ {
+ DEBUG(1,("more than one register name response received!\n"));
+ return True;
+ }
+ break;
+ }
+
+ case NMB_QUERY:
+ {
+ if (n->num_msgs > 1)
+ {
+ if (nmb->header.rcode == 0 && nmb->answers->rdata)
+ {
+ int nb_flags = nmb->answers->rdata[0];
+
+ if ((!NAME_GROUP(nb_flags)))
+ {
+ /* oh dear. more than one person responded to a unique name.
+ there is either a network problem, a configuration problem
+ or a server is mis-behaving */
+
+ /* XXXX mark the name as in conflict, and then let the
+ person who just responded know that they must also mark it
+ as in conflict, and therefore must NOT use it.
+ see rfc1001.txt 15.1.3.5 */
+
+ /* this may cause problems for some early versions of nmbd */
+
+ switch (n->state)
+ {
+ case NAME_QUERY_FIND_MST:
+ {
+ /* query for ^1^2__MSBROWSE__^2^1 expect lots of responses */
+ return False;
+ }
+ case NAME_QUERY_ANNOUNCE_HOST:
+ case NAME_QUERY_DOM_SRV_CHK:
+ case NAME_QUERY_SRV_CHK:
+ case NAME_QUERY_MST_CHK:
+ {
+ if (!strequal(qname,n->name.name))
+ {
+ /* one subnet, one master browser per workgroup */
+ /* XXXX force an election? */
+
+ DEBUG(3,("more than one master browser replied!\n"));
+ return True;
+ }
+ break;
+ }
+ default: break;
+ }
+ DEBUG(3,("Unique Name conflict detected!\n"));
+ return True;
+ }
+ }
+ else
+ {
+ /* we have received a negative reply, having already received
+ at least one response (pos/neg). something's really wrong! */
+
+ DEBUG(3,("wierd name query problem detected!\n"));
+ return True;
+ }
+ }
+ }
+ }
+ return False;
+}
+
+/****************************************************************************
+ check that the response received is compatible with the response record
+ ****************************************************************************/
+static BOOL response_compatible(struct response_record *n,
+ struct nmb_packet *nmb)
+{
+ switch (n->state)
+ {
+ case NAME_RELEASE:
+ {
+ if (nmb->answers->rr_type != NMB_REL)
+ {
+ DEBUG(1,("Name release reply has wrong answer rr_type\n"));
+ return False;
+ }
+ break;
+ }
+
+ case NAME_REGISTER:
+ {
+ if (nmb->answers->rr_type != NMB_REG)
+ {
+ DEBUG(1,("Name register reply has wrong answer rr_type\n"));
+ return False;
+ }
+ break;
+ }
+
+ case NAME_REGISTER_CHALLENGE: /* this is a query: we then do a register */
+ case NAME_QUERY_CONFIRM:
+ case NAME_QUERY_ANNOUNCE_HOST:
+ case NAME_QUERY_SYNC_LOCAL:
+ case NAME_QUERY_SYNC_REMOTE:
+ case NAME_QUERY_DOM_SRV_CHK:
+ case NAME_QUERY_SRV_CHK:
+ case NAME_QUERY_FIND_MST:
+ case NAME_QUERY_MST_CHK:
+ {
+ if (nmb->answers->rr_type != NMB_QUERY)
+ {
+ DEBUG(1,("Name query reply has wrong answer rr_type\n"));
+ return False;
+ }
+ break;
+ }
+
+ case NAME_STATUS_DOM_SRV_CHK:
+ case NAME_STATUS_SRV_CHK:
+ {
+ if (nmb->answers->rr_type != NMB_STATUS)
+ {
+ DEBUG(1,("Name status reply has wrong answer rr_type\n"));
+ return False;
+ }
+ break;
+ }
+
+ default:
+ {
+ DEBUG(1,("unknown state type received in response_netbios_packet\n"));
+ return False;
+ }
+ }
+ return True;
+}
+
+
+/****************************************************************************
+ process the response packet received
+ ****************************************************************************/
+static void response_process(struct subnet_record *d, struct packet_struct *p,
+ struct response_record *n, struct nmb_packet *nmb,
+ BOOL bcast, struct nmb_name *ans_name)
+{
+ switch (n->state)
+ {
+ case NAME_RELEASE:
+ {
+ response_name_release(d, p);
+ break;
+ }
+
+ case NAME_REGISTER:
+ {
+ response_name_reg(d, p);
+ break;
+ }
+
+ case NAME_REGISTER_CHALLENGE:
+ {
+ response_name_query_register(nmb, ans_name, n, d);
+ break;
+ }
+
+ case NAME_QUERY_DOM_SRV_CHK:
+ case NAME_QUERY_SRV_CHK:
+ case NAME_QUERY_FIND_MST:
+ {
+ response_server_check(ans_name, n, d);
+ break;
+ }
+
+ case NAME_STATUS_DOM_SRV_CHK:
+ case NAME_STATUS_SRV_CHK:
+ {
+ response_name_status_check(p->ip, nmb, bcast, n, d);
+ break;
+ }
+
+ case NAME_QUERY_ANNOUNCE_HOST:
+ {
+ response_announce_host(ans_name, nmb, n, d);
+ break;
+ }
+
+ case NAME_QUERY_CONFIRM:
+ case NAME_QUERY_SYNC_LOCAL:
+ case NAME_QUERY_SYNC_REMOTE:
+ {
+ response_name_query_sync(nmb, ans_name, bcast, n, d);
+ break;
+ }
+ case NAME_QUERY_MST_CHK:
+ {
+ /* 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 (just checking!)\n",
+ namestr(&n->name), inet_ntoa(n->send_ip)));
+ break;
+ }
+
+ default:
+ {
+ DEBUG(1,("unknown state type received in response_netbios_packet\n"));
+ break;
+ }
+ }
+}
+
+
+/****************************************************************************
+ response from a netbios packet.
+ ****************************************************************************/
+void response_netbios_packet(struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
+ struct nmb_name *ans_name = NULL;
+ char *qname = question->name;
+ BOOL bcast = nmb->header.nm_flags.bcast;
+ struct response_record *n;
+ struct subnet_record *d = NULL;
+
+ if (!(n = find_response_record(&d,nmb->header.name_trn_id))) {
+ DEBUG(2,("unknown netbios response (received late or from nmblookup?)\n"));
+ return;
+ }
+
+ if (!d)
+ {
+ DEBUG(2,("response packet: subnet %s not known\n", inet_ntoa(p->ip)));
+ return;
+ }
+
+ /* args wrong way round: spotted by ccm@shentel.net */
+ if (!same_net(d->bcast_ip, p->ip, d->mask_ip)) /* copes with WINS 'subnet' */
+ {
+ DEBUG(2,("response from %s. ", inet_ntoa(p->ip)));
+ DEBUG(2,("expected on subnet %s. hmm.\n", inet_ntoa(d->bcast_ip)));
+ return;
+ }
+
+ if (nmb->answers == NULL)
+ {
+ /* hm. the packet received was a response, but with no answer. wierd! */
+ DEBUG(2,("NMB packet response from %s (bcast=%s) - UNKNOWN\n",
+ inet_ntoa(p->ip), BOOLSTR(bcast)));
+ return;
+ }
+
+ ans_name = &nmb->answers->rr_name;
+ DEBUG(3,("response for %s from %s (bcast=%s)\n",
+ namestr(ans_name), inet_ntoa(p->ip), BOOLSTR(bcast)));
+
+ debug_rr_type(nmb->answers->rr_type);
+
+ n->num_msgs++; /* count number of responses received */
+ n->repeat_count = 0; /* don't resend: see expire_netbios_packets() */
+
+ debug_state_type(n->state);
+
+ /* problem checking: multiple responses etc */
+ if (response_problem_check(n, nmb, qname))
+ return;
+
+ /* now check whether the 'state' has received the correct type of response */
+ if (!response_compatible(n, nmb))
+ return;
+
+ /* now deal with the current state */
+ response_process(d, p, n, nmb, bcast, ans_name);
+}
+
+
diff --git a/source/nameservresp.doc b/source/nameservresp.doc
new file mode 100644
index 00000000000..635db45084f
--- /dev/null
+++ b/source/nameservresp.doc
@@ -0,0 +1,191 @@
+/*
+ Unix SMB/Netbios documentation.
+ Version 0.0
+ Copyright (C) Luke Leighton Andrew Tridgell 1996
+
+ 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.
+
+ Document name: nameservresp.doc
+
+ Revision History:
+
+ 0.0 - 02jul96 : lkcl@pires.co.uk
+ created
+*/
+
+this module deals with the receipt of response packets. the
+response packets are expected to be received, and there is a
+record of this kept (see also: modules nameresp and namedbresp)
+
+point of interest to design purists: every function in this
+module is static except response_netbios_packet().
+
+/*************************************************************************
+ response_netbios_packet()
+ *************************************************************************/
+
+this function receives netbios response packets. the samba server
+(or a rogue tcp/ip system, or nmblookup) will have sent out a packet
+requesting a response. a client (or a rogue tcp/ip system) responds
+to that request.
+
+this function checks the validity of the packet it receives.
+the expected response records are searched for the transaction id,
+to see if it's a response expected by the samba server. if it isn't
+it's reported as such, and ignored.
+
+if the response is found, then the subnet it was expected from will
+also have been found. the subnet it actually came in on can be
+checked against the subnet it was expected from and reported,
+otherwise this function just carries on.
+
+the number of responses received is increased, and the number of
+retries left to be sent is set to zero.
+
+after debug information is reported, and validation of the netbios
+packet (e.g only one response from one machine is expected for some
+functions) has occurred, the packet is processed. when the initial
+request was sent out, the expected response record was flagged with,
+for lack of a better word, a samba 'state' type. whenever a
+response is received, the appropriate function is called to carry on
+where the program control flow was interrupted while awaiting exactly
+such a response.
+
+please note that _not_ receiving a response is dealt with in another
+area of code - expire_netbios_response_entries().
+
+
+/*************************************************************************
+ response_name_query_sync()
+ *************************************************************************/
+
+this function receives responses to samba 'states' NAME_QUERY_SYNC and
+NAME_QUERY_CONFIRM.
+
+NAME_QUERY_SYNC: name query a server before synchronising browse lists.
+NAME_QUERY_CONFIRM: name query a server to check that it's alive.
+
+a NAME_QUERY_SYNC will be carried out in order to check that a server
+is alive before syncing browse lists. we don't want to delay the SMB
+NetServerEnum api just because the server has gone down: we have too
+much else to do.
+
+a NAME_QUERY_CONFIRM is just a name query to see whether the server is
+alive. these queries are sent out by samba's WINS server side, to verify
+its netbios name database of all machines that have registered with it.
+
+we don't normally expect a negative response from such a query, although
+we may do so if the query was sent to another WINS server. the registered
+entry should be removed if we receive a negative response.
+
+
+/*************************************************************************
+ response_name_status_check()
+ *************************************************************************/
+
+this function receives responses to samba 'states' NAME_STATUS_SRV_CHK
+and NAME_STATUS_DOM_SRV_CHK
+
+NAME_STATUS_DOM_SRV_CHK: name status a domain master browser
+ confirm its domain and then initiate syncing
+ its browse list.
+
+NAME_STATUS_SRV_CHK: same as NAME_STATUS_DOM_SRV_CHK except the
+ name status is issued to a master browser.
+
+if we don't know what workgroup a server is responsible for, but we
+know that there is a master browser at a certain ip, we can issue a
+name status check. from the response received, there will be
+a master browser netbios entry. this will allow us to synchronise
+browse lists with that machine and then add the information to the
+correct part of samba's workgroup - server database.
+
+
+/*************************************************************************
+ response_server_check()
+ *************************************************************************/
+
+this function receives responses to samba 'states' NAME_QUERY_DOM_SRV_CHK,
+NAME_QUERY_SRV_CHK and NAME_QUERY_FIND_MST.
+
+NAME_QUERY_FIND_MST: issued as a broadcast when we wish to find out all
+ master browsers (i.e all servers that have registered
+ the NetBIOS name ^1^2__MSBROWSE__^2(0x1), and then
+ issue a NAME_STATUS_MASTER_CHECK on any servers that
+ respond, which will initiate a sync browse lists.
+
+NAME_QUERY_DOM_SRV_CHK: same as a NAME_QUERY_FIND_MST except this is sent
+ to a domain master browser.
+
+NAME_QUERY_SRV_CHK: same as a NAME_QUERY_DOM_SRV_CHK except this is sent to
+ a master browser.
+
+the purpose of each of these states is to do a broadcast name query, or
+a name query directed at a WINS server, then to all hosts that respond,
+we issue a name status check, which will confirm for us the workgroup
+or domain name, and then initiate issuing a sync browse list call with
+that server.
+
+a NAME_QUERY_SRV_CHK is sent when samba receives a list of backup
+browsers. it checks to see if that server is alive (by doing a
+name query on a server) and then syncs browse lists with it.
+
+
+/*************************************************************************
+ response_name_reg()
+ *************************************************************************/
+
+this function is responsible for dealing with samba's registration
+attempts, by broadcast to a local subnet, or point-to-point with
+another WINS server.
+
+please note that it cannot cope with END-NODE CHALLENGE REGISTRATION
+RESPONSEs at present.
+
+when a response is received, samba determines if the response is a
+positive or a negative one. if it is a positive response, the name
+is added to samba's database.
+
+when a negative response is received, samba will remove the name
+from its database. if, however, the name is a browser type (0x1b is
+a domain master browser type name; or 0x1d, which is a local master
+browser type name) then it must also stop being a domain master
+browser or master browser respectively, depending on what kind
+of name was rejected.
+
+(when no response is received, then expire_netbios_response_entries()
+is expected to deal with this. the only case that is dealt with here
+at present is when the registration was done by broadcast. if there
+is no challenge to the broadcast registration, it is implicitly
+assumed that claiming the name is acceptable).
+
+
+/*************************************************************************
+ response_name_release()
+ *************************************************************************/
+
+this function is responsible for removing samba's NetBIOS name when
+samba contacts another WINS server with which it had registered the
+name.
+
+only positive name releases are expected and dealt with. exactly what
+to do if a negative name release (i.e someone says 'oi! you have to
+keep that name!') is received is uncertain.
+
+(when no response is received, then expire_netbios_response_entries()
+is expected to deal with this. if there is no challenge to the release
+of the name, the name is then removed from that subnet's NetBIOS
+name database).
+
diff --git a/source/namework.c b/source/namework.c
new file mode 100644
index 00000000000..74c567fa748
--- /dev/null
+++ b/source/namework.c
@@ -0,0 +1,799 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1996
+
+ 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 ClientNMB;
+extern int ClientDGRAM;
+
+#define TEST_CODE /* want to debug unknown browse packets */
+
+extern int DEBUGLEVEL;
+extern pstring scope;
+extern BOOL CanRecurse;
+
+extern pstring myname;
+
+extern int ClientNMB;
+extern int ClientDGRAM;
+
+extern struct in_addr ipzero;
+
+extern int workgroup_count; /* total number of workgroups we know about */
+
+/* this is our domain/workgroup/server database */
+extern struct subnet_record *subnetlist;
+
+/* 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;
+
+extern BOOL updatedlists;
+
+/****************************************************************************
+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) = ANN_ResetBrowserState;
+ CVAL(p,2) = state;
+ p += 2;
+
+ DEBUG(2,("sending reset to %s %s of state %d\n",
+ name,inet_ntoa(ip),state));
+
+ send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
+ myname,name,0x20,0x1d,ip,*iface_ip(ip));
+}
+
+
+/****************************************************************************
+tell a server to become a backup browser
+**************************************************************************/
+void tell_become_backup(void)
+{
+ /* XXXX note: this function is currently unsuitable for use, as it
+ does not properly check that a server is in a fit state to become
+ a backup browser before asking it to be one.
+ */
+
+ struct subnet_record *d;
+ for (d = subnetlist; 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(2,("sending become backup to %s %s for %s\n",
+ s->serv.name, inet_ntoa(d->bcast_ip),
+ work->work_group));
+
+ /* type 11 request from MYNAME(20) to WG(1e) for SERVER */
+ do_announce_request(s->serv.name, work->work_group,
+ ANN_BecomeBackup, 0x20, 0x1e, d->bcast_ip);
+ }
+ }
+ }
+}
+
+
+/*******************************************************************
+ same context: scope. should check name_type as well, and makes sure
+ we don't process messages from ourselves
+ ******************************************************************/
+BOOL same_context(struct dgram_packet *dgram)
+{
+ if (!strequal(dgram->dest_name .scope,scope )) return(True);
+ if ( strequal(dgram->source_name.name ,myname)) return(True);
+
+ return(False);
+}
+
+
+/*******************************************************************
+ am I listening on a name. XXXX check the type of name as well.
+ ******************************************************************/
+BOOL listening_name(struct work_record *work, struct nmb_name *n)
+{
+ if (strequal(n->name,myname) ||
+ strequal(n->name,work->work_group) ||
+ strequal(n->name,MSBROWSE))
+ {
+ return(True);
+ }
+
+ return(False);
+}
+
+
+/*******************************************************************
+ process a domain announcement frame
+
+ Announce frames come in 3 types. Servers send host announcements
+ (command=1) to let the master browswer know they are
+ available. Master browsers send local master announcements
+ (command=15) to let other masters and backups that they are the
+ master. They also send domain announcements (command=12) to register
+ the domain
+
+ The comment field of domain announcements contains the master
+ browser name. The servertype is used by NetServerEnum to select
+ resources. We just have to pass it to smbd (via browser.dat) and let
+ the client choose using bit masks.
+ ******************************************************************/
+static void process_announce(struct packet_struct *p,uint16 command,char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ struct in_addr ip = dgram->header.source_ip;
+ struct subnet_record *d = find_subnet(ip);
+ int update_count = CVAL(buf,0);
+
+ int ttl = IVAL(buf,1)/1000;
+ char *name = buf+5;
+ int osmajor=CVAL(buf,21);
+ int osminor=CVAL(buf,22);
+ uint32 servertype = IVAL(buf,23);
+ uint32 browse_type= CVAL(buf,27);
+ uint32 browse_sig = CVAL(buf,29);
+ char *comment = buf+31;
+
+ struct work_record *work;
+ char *work_name;
+ char *serv_name = dgram->source_name.name;
+ BOOL add = False;
+
+ comment[43] = 0;
+
+ DEBUG(4,("Announce(%d) %s(%x)",command,name,name[15]));
+ DEBUG(4,("%s count=%d ttl=%d OS=(%d,%d) type=%08x sig=%4x %4x comment=%s\n",
+ namestr(&dgram->dest_name),update_count,ttl,osmajor,osminor,
+ servertype,browse_type,browse_sig,comment));
+
+ name[15] = 0;
+
+ if (dgram->dest_name.name_type == 0 && command == ANN_HostAnnouncement)
+ {
+ DEBUG(2,("Announce to nametype(0) not supported yet\n"));
+ return;
+ }
+
+ if (command == ANN_DomainAnnouncement &&
+ ((!strequal(dgram->dest_name.name, MSBROWSE)) ||
+ dgram->dest_name.name_type != 0x1))
+ {
+ DEBUG(0,("Announce(%d) from %s should be __MSBROWSE__(1) not %s\n",
+ command, inet_ntoa(ip), namestr(&dgram->dest_name)));
+ return;
+ }
+
+ if (!strequal(dgram->dest_name.scope,scope )) return;
+
+ if (command == ANN_DomainAnnouncement) {
+ /* XXXX if we are a master browser for the workgroup work_name,
+ then there is a local subnet configuration problem. only
+ we should be sending out such domain announcements, because
+ as the master browser, that is our job.
+
+ stop being a master browser, and force an election. this will
+ sort out the network problem. hopefully.
+ */
+
+ work_name = name;
+ add = True;
+ } else {
+ work_name = dgram->dest_name.name;
+ }
+
+ /* we need some way of finding out about new workgroups
+ that appear to be sending packets to us. The name_type checks make
+ sure we don't add host names as workgroups */
+ if (command == ANN_HostAnnouncement &&
+ (dgram->dest_name.name_type == 0x1d ||
+ dgram->dest_name.name_type == 0x1e))
+ add = True;
+
+ if (!(work = find_workgroupstruct(d, work_name,add)))
+ return;
+
+ DEBUG(4, ("workgroup %s on %s\n", work->work_group, serv_name));
+
+ ttl = GET_TTL(ttl);
+
+ /* add them to our browse list, and update the browse.dat file */
+ add_server_entry(d,work,name,servertype,ttl,comment,True);
+ updatedlists = True;
+
+#if 0
+ /* the tell become backup code is broken, no great harm is done by
+ disabling it */
+ tell_become_backup();
+#endif
+
+ /* get the local_only browse list from the local master and add it to ours. */
+ if (command == ANN_LocalMasterAnnouncement)
+ {
+ add_browser_entry(serv_name,dgram->dest_name.name_type,
+ work->work_group,30,ip,True);
+ }
+}
+
+/*******************************************************************
+ process a master announcement frame
+ ******************************************************************/
+static void process_master_announce(struct packet_struct *p,char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ struct in_addr ip = dgram->header.source_ip;
+ struct subnet_record *d = find_subnet(ip);
+ struct subnet_record *mydomain = find_subnet(*iface_bcast(ip));
+ char *name = buf;
+ struct work_record *work;
+ name[15] = 0;
+
+ DEBUG(3,("Master Announce from %s (%s)\n",name,inet_ntoa(ip)));
+
+ if (same_context(dgram)) return;
+
+ if (!d || !mydomain) return;
+
+ if (!lp_domain_master()) return;
+
+ for (work = mydomain->workgrouplist; work; work = work->next)
+ {
+ if (AM_MASTER(work))
+ {
+ /* merge browse lists with them */
+ add_browser_entry(name,0x1b, work->work_group,30,ip,True);
+ }
+ }
+}
+
+/*******************************************************************
+ process a receive backup list request
+
+ we receive a list of servers, and we attempt to locate them all on
+ our local subnet, and sync browse lists with them on the workgroup
+ they are said to be in.
+
+ XXXX NOTE: this function is in overdrive. it should not really do
+ half of what it actually does (it should pick _one_ name from the
+ list received and sync with it at regular intervals, rather than
+ sync with them all only once!)
+
+ ******************************************************************/
+static void process_rcv_backup_list(struct packet_struct *p,char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ struct in_addr ip = dgram->header.source_ip;
+ int count = CVAL(buf,0);
+ uint32 info = IVAL(buf,1); /* XXXX caller's incremental info */
+ char *buf1;
+
+ DEBUG(3,("Receive Backup ack for %s from %s total=%d info=%d\n",
+ namestr(&dgram->dest_name), inet_ntoa(ip),
+ count, info));
+
+ if (same_context(dgram)) return;
+
+ if (count <= 0) return;
+
+ /* go through the list of servers attempting to sync browse lists */
+ for (buf1 = buf+5; *buf1 && count; buf1 = skip_string(buf1, 1), --count)
+ {
+ struct in_addr back_ip;
+ struct subnet_record *d;
+
+ DEBUG(4,("Searching for backup browser %s at %s...\n",
+ buf1, inet_ntoa(ip)));
+
+ /* XXXX assume name is a DNS name NOT a netbios name. a more complete
+ approach is to use reply_name_query functionality to find the name */
+
+ back_ip = *interpret_addr2(buf1);
+
+ if (zero_ip(back_ip))
+ {
+ DEBUG(4,("Failed to find backup browser server using DNS\n"));
+ continue;
+ }
+
+ DEBUG(4,("Found browser server at %s\n", inet_ntoa(back_ip)));
+ DEBUG(4,("END THIS LOOP: CODE NEEDS UPDATING\n"));
+
+ /* XXXX function needs work */
+ continue;
+
+ if ((d = find_subnet(back_ip)))
+ {
+ struct subnet_record *d1;
+ for (d1 = subnetlist; d1; d1 = d1->next)
+ {
+ struct work_record *work;
+ for (work = d1->workgrouplist; work; work = work->next)
+ {
+ if (work->token == 0 /* token */)
+ {
+ queue_netbios_packet(d1,ClientNMB,NMB_QUERY,NAME_QUERY_SRV_CHK,
+ work->work_group,0x1d,
+ 0,0,0,NULL,NULL,
+ False,False,back_ip,back_ip);
+ return;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+/****************************************************************************
+ send a backup list response.
+ **************************************************************************/
+static void send_backup_list(char *work_name, struct nmb_name *src_name,
+ int token, uint32 info,
+ int name_type, struct in_addr ip)
+{
+ char outbuf[1024];
+ char *p, *countptr, *nameptr;
+ int count = 0;
+ char *theirname = src_name->name;
+
+ DEBUG(3,("sending backup list of %s to %s: %s(%x) %s(%x)\n",
+ work_name, inet_ntoa(ip),
+ myname,0x0,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) = ANN_GetBackupListResp; /* backup list response */
+
+ p++;
+ countptr = p;
+
+ SIVAL(p,1,info); /* the sender's unique info */
+
+ p += 5;
+
+ nameptr = p;
+
+#if 0
+
+ for (d = subnetlist; d; d = d->next)
+ {
+ struct work_record *work;
+
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ struct server_record *s;
+
+ if (!strequal(work->work_group, work_name)) continue;
+
+ for (s = work->serverlist; s; s = s->next)
+ {
+ BOOL found = False;
+ char *n;
+
+ if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue;
+
+ for (n = nameptr; n < p; n = skip_string(n, 1))
+ {
+ if (strequal(n, s->serv.name)) found = True;
+ }
+
+ if (found) continue; /* exclude names already added */
+
+ /* workgroup request: include all backup browsers in the list */
+ /* domain request: include all domain members in the list */
+
+ if ((name_type == 0x1d && (s->serv.type & MASTER_TYPE)) ||
+ (name_type == 0x1b && (s->serv.type & DOMCTL_TYPE)))
+ {
+ DEBUG(4, ("%s ", s->serv.name));
+
+ count++;
+ strcpy(p,s->serv.name);
+ strupper(p);
+ p = skip_string(p,1);
+ }
+ }
+ }
+ }
+
+#endif
+
+ count++;
+ strcpy(p,myname);
+ strupper(p);
+ p = skip_string(p,1);
+
+ if (count == 0)
+ {
+ DEBUG(4, ("none\n"));
+ }
+ else
+ {
+ DEBUG(4, (" - count %d\n", count));
+ }
+
+ CVAL(countptr, 0) = count;
+
+ {
+ int len = PTR_DIFF(p, outbuf);
+ debug_browse_data(outbuf, len);
+ }
+ send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
+ myname,theirname,0x0,0x0,ip,*iface_ip(ip));
+}
+
+
+/*******************************************************************
+ process a send backup list request
+
+ A client sends a backup list request to ask for a list of servers on
+ the net that maintain server lists for a domain. A server is then
+ chosen from this list to send NetServerEnum commands to to list
+ available servers.
+
+ Currently samba only sends back one name in the backup list, its
+ own. For larger nets we'll have to add backups and send "become
+ backup" requests occasionally.
+ ******************************************************************/
+static void process_send_backup_list(struct packet_struct *p,char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ struct in_addr ip = dgram->header.source_ip;
+ struct subnet_record *d;
+ struct work_record *work;
+
+ int token = CVAL(buf,0); /* sender's key index for the workgroup */
+ uint32 info = IVAL(buf,1); /* XXXX don't know: some sort of info */
+ int name_type = dgram->dest_name.name_type;
+
+ if (same_context(dgram)) return;
+
+ if (name_type != 0x1b && name_type != 0x1d) {
+ DEBUG(0,("backup request to wrong type %d from %s\n",
+ name_type,inet_ntoa(ip)));
+ return;
+ }
+
+ for (d = subnetlist; d; d = d->next)
+ {
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ if (strequal(work->work_group, dgram->dest_name.name))
+ {
+ DEBUG(2,("sending backup list to %s %s id=%x\n",
+ namestr(&dgram->dest_name),inet_ntoa(ip),info));
+
+ send_backup_list(work->work_group,&dgram->source_name,
+ token,info,name_type,ip);
+ return;
+ }
+ }
+ }
+}
+
+
+/*******************************************************************
+ process a reset browser state
+
+ diagnostic packet:
+ 0x1 - stop being a master browser and become a backup browser.
+ 0x2 - discard browse lists, stop being a master browser, try again.
+ 0x4 - stop being a master browser forever. no way. ain't gonna.
+
+ ******************************************************************/
+static void process_reset_browser(struct packet_struct *p,char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ int state = CVAL(buf,0);
+
+ DEBUG(1,("received diagnostic browser reset request to %s state=0x%X\n",
+ namestr(&dgram->dest_name), state));
+
+ /* stop being a master but still deal with being a backup browser */
+ if (state & 0x1)
+ {
+ struct subnet_record *d;
+ for (d = subnetlist; d; d = d->next)
+ {
+ struct work_record *work;
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ if (AM_MASTER(work))
+ {
+ become_nonmaster(d,work,SV_TYPE_DOMAIN_MASTER|SV_TYPE_MASTER_BROWSER);
+ }
+ }
+ }
+ }
+
+ /* XXXX documentation inconsistency: the above description does not
+ exactly tally with what is implemented for state & 0x2
+ */
+
+ /* totally delete all servers and start afresh */
+ if (state & 0x2)
+ {
+ struct subnet_record *d;
+ for (d = subnetlist; d; d = d->next)
+ {
+ struct work_record *work;
+ for (work=d->workgrouplist;work;work=remove_workgroup(d,work,True));
+ }
+ add_my_subnets(lp_workgroup());
+ }
+
+ /* stop browsing altogether. i don't think this is a good idea! */
+ if (state & 0x4)
+ {
+ DEBUG(1,("ignoring request to stop being a browser. sorry!\n"));
+ }
+}
+
+/*******************************************************************
+ process a announcement request
+
+ clients send these when they want everyone to send an announcement
+ immediately. This can cause quite a storm of packets!
+ ******************************************************************/
+static void process_announce_request(struct packet_struct *p,char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ struct work_record *work;
+ struct in_addr ip = dgram->header.source_ip;
+ struct subnet_record *d = find_subnet(ip);
+ int token = CVAL(buf,0);
+ char *name = buf+1;
+
+ name[15] = 0;
+
+ DEBUG(3,("Announce request from %s to %s token=0x%X\n",
+ name,namestr(&dgram->dest_name), token));
+
+ if (strequal(dgram->source_name.name,myname)) return;
+
+ /* XXXX BUG or FEATURE?: need to ensure that we are a member of
+ this workgroup before announcing, particularly as we only
+ respond on local interfaces anyway.
+
+ if (strequal(dgram->dest_name, lp_workgroup()) return; ???
+ */
+
+ if (!d) return;
+
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ /* XXXX BUG: the destination name type should also be checked,
+ not just the name. e.g if the name is WORKGROUP(0x1d) then
+ we should only respond if we own that name */
+
+ if (strequal(dgram->dest_name.name,work->work_group))
+ {
+ work->needannounce = True;
+ }
+ }
+}
+
+
+/****************************************************************************
+depending on what announce has been made, we are only going to
+accept certain types of name announce. XXXX untested code
+
+check listening name type
+****************************************************************************/
+BOOL listening_type(struct packet_struct *p, int command)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ int type = dgram->dest_name.name_type;
+
+ switch (command)
+ {
+ case ANN_HostAnnouncement:
+ {
+ if (type != 0x0 || type != 0x20) return (False);
+ break;
+ }
+
+ case ANN_AnnouncementRequest:
+ {
+ return (True);
+ break;
+ }
+
+ case ANN_Election:
+ {
+ return (True);
+ break;
+ }
+
+ case ANN_GetBackupListReq:
+ {
+ return (True);
+ break;
+ }
+
+ case ANN_GetBackupListResp:
+ {
+ return (True);
+ break;
+ }
+
+ case ANN_DomainAnnouncement:
+ {
+ if (type != 0x1b || type != 0x1c) return (False);
+ break;
+ }
+
+ case ANN_MasterAnnouncement:
+ {
+ if (type != 0x1d) return (False);
+ break;
+ }
+
+ case ANN_LocalMasterAnnouncement:
+ {
+ if (type != 0x1c || type != 0x1d) return (False);
+ break;
+ }
+ }
+ return (True); /* we're not dealing with unknown packet types */
+}
+
+
+/****************************************************************************
+process a browse frame
+****************************************************************************/
+void process_browse_packet(struct packet_struct *p,char *buf,int len)
+{
+ int command = CVAL(buf,0);
+ switch (command)
+ {
+ case ANN_HostAnnouncement:
+ case ANN_DomainAnnouncement:
+ case ANN_LocalMasterAnnouncement:
+ {
+ debug_browse_data(buf, len);
+ process_announce(p,command,buf+1);
+ break;
+ }
+
+ case ANN_AnnouncementRequest:
+ {
+ process_announce_request(p,buf+1);
+ break;
+ }
+
+ case ANN_Election:
+ {
+ process_election(p,buf+1);
+ break;
+ }
+
+ case ANN_GetBackupListReq:
+ {
+ debug_browse_data(buf, len);
+ process_send_backup_list(p,buf+1);
+ break;
+ }
+
+ case ANN_GetBackupListResp:
+ {
+ debug_browse_data(buf, len);
+ process_rcv_backup_list(p, buf+1);
+ break;
+ }
+
+ case ANN_ResetBrowserState:
+ {
+ process_reset_browser(p, buf+1);
+ break;
+ }
+
+ case ANN_MasterAnnouncement:
+ {
+ process_master_announce(p,buf+1);
+ break;
+ }
+
+ default:
+ {
+ struct dgram_packet *dgram = &p->packet.dgram;
+ DEBUG(4,("ignoring browse packet %d from %s %s to %s\n",
+ command, namestr(&dgram->source_name),
+ inet_ntoa(p->ip), namestr(&dgram->dest_name)));
+ }
+ }
+}
+
+
diff --git a/source/namework.doc b/source/namework.doc
new file mode 100644
index 00000000000..958a86c8668
--- /dev/null
+++ b/source/namework.doc
@@ -0,0 +1,363 @@
+/*
+ Unix SMB/Netbios documentation.
+ Version 0.1
+ Copyright (C) Luke Leighton Andrew Tridgell 1996
+
+ 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.
+
+ Document name: namework.doc
+
+ Revision History:
+
+ 0.0 - 02jul96 : lkcl@pires.co.uk
+ created
+
+ 0.1 - 22jul96 Andrew.Tridgell@anu.edu.au
+ tridge's comments on first revision
+*/
+
+the module namework.c deals with NetBIOS datagram packets, primarily.
+it deals with nmbd's workgroup browser side and the domain log in
+side. none of the functionality here has specification documents available.
+empirical observation of packet traces has been the order of the day,
+along with some guess-work.
+
+beware!
+
+the receipt of datagram packets for workgroup browsing are dealt with here.
+some of the functions listed here will call others outside of this
+module, or will activate functionality dealt with by other modules
+(namedb, nameannounce, nameelect, namelogon, and namebrowse).
+
+
+/*************************************************************************
+ process_browse_packet()
+ *************************************************************************/
+
+this function is responsible for further identifying which type of
+browser datagram packet has been received, and dealing with it
+accordingly. if the packet is not dealt with, then an error is
+logged along with the type of packet that has been received.
+
+if listening_type() was in use, then it would be used here.
+
+the types of packets received and dealt with are:
+
+- ANN_HostAnnouncement
+- ANN_DomainAnnouncement
+- ANN_LocalMasterAnnouncement
+
+these are all identical in format and can all be processed by
+process_announce(). an announcement is received from a host
+(either a master browser telling us about itself, a server
+telling us about itself or a master browser telling us about
+a domain / workgroup)
+
+- ANN_AnnouncementRequest
+
+these are sent by master browsers or by servers. it is a
+request to announce ourselves as appropriate by sending
+either a ANN_HostAnnouncement datagram or both an
+ANN_DomainAnnouncement and an ANN_LocalMasterAnnouncement
+if we are a master browser (but not both).
+
+- ANN_Election
+
+this is an election datagram. if samba has been configured
+as a domain master then it will also send out election
+datagrams.
+
+- ANN_GetBackupListReq
+
+this is a request from another server for us to send a
+backup list of all servers that we know about. we respond
+by sending a datagram ANN_GetBackupListResp. the protocol
+here is a little dicey.
+
+- ANN_GetBackupListResp
+
+this is a response from another server that we have sent an
+ANN_GetBackupListReq to. the protocol is a little dicey.
+
+- ANN_BecomeBackup
+
+this is a message sent by a master browser to a
+potential master browser, indicating that it should become
+a backup master browser for the workgroup it is a member
+of. samba does not respond at present to such datagrams,
+and it also sends out such datagrams for the wrong reasons
+(this code has now been disabled until this is fixed).
+
+- ANN_ResetBrowserState
+
+this datagram is sent for trouble-shooting purposes.
+it asks a browser to clear out its server lists, or to
+stop becoming a master browser altogether. NT/AS and
+samba do not implement this latter option.
+
+- ANN_MasterAnnouncement
+
+this datagram is sent by a master browser to a domain master
+browser. it is a way to ensure that master browsers are kept in sync
+with a domain master browser across a wide area network. on
+receipt of an ANN_MasterAnnouncement we should sync browse lists with
+the sender.
+
+(i never got the hang of this one when i was experimenting.
+i forget exactly what it's for, and i never fully worked
+out how to coax a server to send it. :-)
+
+NOTE FROM TRIDGE: The reason you didn't work out how to coax a server
+into sending it is that you can't (or shouldn't try!). Basically these
+"master announce" datagrams are the way that separate netbios subnets
+are linked together to form a complete browse net. The way it works is
+that the local master decides it is going to inform the domain master
+of its presence, then sends this master announce to the domain
+master. The domain master then syncs with the local master using a
+"local only" sync. The whole transaction is initiated by the local
+master, not the domain master, so the domain master should not do any
+of this if it does not first receive a "master announcement". The
+local domain masters need to be configured to know the IP address of
+the domain master.
+
+
+/*************************************************************************
+ listening_type()
+ *************************************************************************/
+
+
+a datagram packet is sent from one NetBIOS name of a specific type
+to another NetBIOS name of a specific type. certain types of
+datagrams are only expected from certain types of NetBIOS names.
+
+this function is intended to catch errors in the type of datagrams
+received from different NetBIOS names. it is currently incomplete
+due to lack of information on the types of names and the datagrams
+they send.
+
+
+/*************************************************************************
+ process_announce_request()
+ *************************************************************************/
+
+this function is responsible for dealing with announcement requests.
+if the type of name that the request is sent to matches our current
+status, then we should respond. otherwise, the datagram should be
+ignored.
+
+samba only responds on its local subnets.
+
+at present, just the name is checked to see if the packet is for us.
+what should be done is that if we own the name (e.g WORGROUP(0x1d)
+or WORKGROUP(0x1b) then we should respond, otherwise, ignore the
+datagram.
+
+if the name is for us, and we are a member of that workgroup, then
+samba should respond.
+
+note that samba does not respond immediately. this is to ensure that
+if the master browser for the workgroup that samba is a member of
+sends out a broadcast request announcement, that that master browser
+is not swamped with replies. it is therefore up to samba to reply
+at some random interval. hence, a flag is set indicating the need
+to announce later.
+
+
+/*************************************************************************
+ process_reset_browser()
+ *************************************************************************/
+
+this function is responsible for dealing with reset state datagrams.
+there are three kinds of diagnostic reset requests:
+
+- stop being a master browser
+- discard browse lists, stop being a master browser, and run for re-election
+- stop being a master browser forever.
+
+samba and windows nt do not implement the latter option.
+
+there appears to be a discrepancy between this description and the
+code actually implemented.
+
+
+/*************************************************************************
+ process_send_backup_list()
+ *************************************************************************/
+
+this function is part of samba's domain master browser functionality.
+
+it is responsible for giving master browsers a list of other browsers
+that maintain backup lists of servers for that master browser's workgroup.
+
+it is also responsible for giving master browsers a list of domain master
+browsers for that local master browser's domain.
+
+a correct way to think of this function is that it is a 'request to
+send out a backup list for the requested workgroup or domain'.
+
+i have some suspicions and intuitions about this function and how it
+is to actually be used. there is no documentation on this, so it is a
+matter of experimenting until it's right.
+
+
+/*************************************************************************
+ send_backup_list()
+ *************************************************************************/
+
+this function is responsible for compiling a list of either master
+browsers and backup master browsers or domain master browsers and
+backup domain master browsers. samba constructs this list from its
+workgroup / server database.
+
+the list is then sent to the host that requested it by sending an
+ANN_GetBackupListResp datagram to this host.
+
+
+NOTE FROM TRIDGE: The "backup list" stuff is only relevant to
+local subnets. It has nothing to do with PDCs or domain masters. Its
+function is twofold:
+
+1) spread the browsing load over multiple servers so one server
+doesn't get overloaded with browse requests
+2) make sure the database doesn't get lost completely if the master
+goes down
+
+To accomplish this a few things are supposed to be done:
+
+- the master browser maintains a list of "backup browsers".
+
+- backup browsers are are machines that are just like ordinary servers
+but also maintain a browse list and respond to "NetServerEnum"
+requests
+
+- when a server initially announces itself to the master it may set
+its "maintain browse list" flag to auto.
+
+- when a master browser sees a server announcement with "auto" set it
+may send a "become backup" to that server telling it to become a
+backup.
+
+- the master has a simple algorithm to determine how many backups it wants
+given the number of hosts on the net
+
+- when a client wishes to get a browse list it asks the master for a
+backup list. The master sends it the current list of backup browsers,
+including itself. The client caches this list. The client then sends
+the NetServerEnum to a random member of this list easch time it wants
+to browse. This spreads the load.
+
+
+
+/*************************************************************************
+ process_rcv_backup_list()
+ *************************************************************************/
+
+this function is implemented with a slightly over-kill algorithm.
+the correct functionality is to pick any three names at random from
+the list that is received from this datagram, and then at intervals
+contact _one_ of them for a list of browser, in order to update
+samba's browse list.
+
+samba contacts every single one of the backup browsers listed, through
+the use of a NAME_QUERY_SRV_CHK 'state'.
+
+
+/*************************************************************************
+ process_master_announce()
+ *************************************************************************/
+
+this function is responsible for synchronising browse lists with a
+master browser that contacts samba in its capacity as a domain master
+browser.
+
+the function add_browser_entry() is used to add the server that
+contacts us to our list of browser to sync browse lists with at
+some point in the near future.
+
+
+/*************************************************************************
+ process_announce()
+ *************************************************************************/
+
+this function is responsible for dealing with the three types of
+announcement type datagrams that samba recognises. some appropriate
+type-checking is done on the name that the datagram is sent to.
+
+samba does not at present deal with LanManager announcements.
+
+these announcements are for updating the browse entry records.
+each browse entry has a time-to-live associated with it. each server
+must refresh its entry with all other servers by broadcasting
+Announcements. if it does not do so, then other servers will not
+know about that machine, and the records on each server of that
+other machine will die.
+
+if an ANN_DomainAnnouncement is received, then this will be from
+a master browser. only one machine on any given broadcast area (e.g
+a subnet) should be broadcasting such announcements. the information
+it contains tells other servers that there is a master browser for
+this workgroup. if another server thinks that it is also a master
+browser for the same workgroup, then it should stop being a master
+browser and force an election.
+
+if an ANN_LocalMasterAnnouncement is received, then a master browser
+is telling us that it exists. i am uncertain that anything else
+actually needs to be done with this, other than to shout 'hooray' and
+'thank you for informing me of this fact'.
+
+
+/*************************************************************************
+ listening_name()
+ *************************************************************************/
+
+this function is an over-simplified way of identifying whether we
+should be responding to a datagram that has been received.
+
+
+/*************************************************************************
+ same_context()
+ *************************************************************************/
+
+this function helps us to identify whether we should be responding to
+a datagram that has been received.
+
+
+/*************************************************************************
+ tell_become_backup()
+ *************************************************************************/
+
+this function is part of samba's domain master browser capabilities.
+it is responsible for finding appropriate servers to tell to become a
+backup master browser for the domain that samba controls.
+
+other servers that contact samba asking for a list of backup browsers
+will then be given that server's name, and that server can expect to
+receive NetServerEnum requests for lists of servers and workgroups.
+
+this function must be updated before it is in a fit state to be used.
+it must properly check whether a server is prepared to become a backup
+browser before actually asking it to be one.
+
+
+/*************************************************************************
+ reset_server()
+ *************************************************************************/
+
+this function is responsible for issuing an ANN_ResetBrowserState to
+the specified server, asking it to reset its browser information.
+
+see process_reset_browser() for details on this function.
+
+
diff --git a/source/nmbd/nmbd.c b/source/nmbd/nmbd.c
new file mode 100644
index 00000000000..5c3be920f5f
--- /dev/null
+++ b/source/nmbd/nmbd.c
@@ -0,0 +1,579 @@
+/*
+ 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);
+
+ set_samba_nb_type();
+
+ 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,0x00,NB_ACTIVE,0,source,ipaddr,True,True);
+ 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);
+
+ set_samba_nb_type();
+
+ 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);
+}
diff --git a/source/nmbsync.c b/source/nmbsync.c
index 5a77d6cc486..2efb364bcae 100644
--- a/source/nmbsync.c
+++ b/source/nmbsync.c
@@ -21,283 +21,161 @@
*/
#include "includes.h"
-#include "loadparm.h"
-#include "nameserv.h"
-extern int DEBUGLEVEL;
+extern int ClientNMB;
+extern int ClientDGRAM;
-struct server_record *add_server_entry(char *name,int servertype,
- int ttl,char *comment,BOOL replace);
+extern int DEBUGLEVEL;
+extern pstring myname;
+
+extern int name_type;
+extern int max_protocol;
+extern struct in_addr dest_ip;
+extern int pid;
+extern int gid;
+extern int uid;
+extern int mid;
+extern BOOL got_pass;
+extern BOOL have_ip;
+extern pstring workgroup;
+extern pstring service;
+extern pstring desthost;
+extern BOOL connect_as_ipc;
/****************************************************************************
-call a remote api
+fudge for getpass function
****************************************************************************/
-static BOOL call_remote_api(int fd,int cnum,int uid,int timeout,
- char *inbuf,char *outbuf,
- int prcnt,int drcnt,
- int mprcnt,int mdrcnt,
- int *rprcnt,int *rdrcnt,
- char *param,char *data,
- char **rparam,char **rdata)
+char *getsmbpass(char *pass)
{
- char *p1,*p2;
-
- /* send a SMBtrans command */
- bzero(outbuf,smb_size);
- set_message(outbuf,14,0,True);
- CVAL(outbuf,smb_com) = SMBtrans;
- SSVAL(outbuf,smb_tid,cnum);
- SSVAL(outbuf,smb_uid,uid);
-
- p1 = smb_buf(outbuf);
- strcpy(p1,"\\PIPE\\LANMAN");
- p1 = skip_string(p1,1);
- p2 = p1 + prcnt;
-
- if (prcnt > 0)
- memcpy(p1,param,prcnt);
- if (drcnt > 0)
- memcpy(p2,data,drcnt);
-
- SSVAL(outbuf,smb_vwv0,prcnt); /* param count */
- SSVAL(outbuf,smb_vwv1,drcnt); /* data count */
- SSVAL(outbuf,smb_vwv2,mprcnt); /* mprcnt */
- SSVAL(outbuf,smb_vwv3,mdrcnt); /* mdrcnt */
- SSVAL(outbuf,smb_vwv4,0); /* msrcnt */
- SSVAL(outbuf,smb_vwv5,0); /* flags */
- SSVAL(outbuf,smb_vwv9,prcnt); /* pscnt */
- SSVAL(outbuf,smb_vwv10,smb_offset(p1,outbuf)); /* psoff */
- SSVAL(outbuf,smb_vwv11,drcnt); /* dscnt */
- SSVAL(outbuf,smb_vwv12,smb_offset(p2,outbuf)); /* dsoff */
- CVAL(outbuf,smb_vwv13) = 0; /* suwcnt */
-
- set_message(outbuf,14,PTR_DIFF(p2+drcnt,smb_buf(outbuf)),False);
-
- send_smb(fd,outbuf);
-
- if (receive_smb(fd,inbuf,timeout) &&
- CVAL(inbuf,smb_rcls) == 0)
- {
- if (rparam)
- *rparam = inbuf+4 + SVAL(inbuf,smb_vwv4);
- if (rdata)
- *rdata = inbuf+4 + SVAL(inbuf,smb_vwv7);
- if (rprcnt)
- *rprcnt = SVAL(inbuf,smb_vwv3);
- if (rdrcnt)
- *rdrcnt = SVAL(inbuf,smb_vwv6);
- return(True);
- }
-
- return(False);
+ return "dummy"; /* return anything: it should be ignored anyway */
}
-
-/*******************************************************************
- synchronise browse lists with another browse server
- ******************************************************************/
-void sync_browse_lists(char *name,int name_type,char *myname,
- char *domain,struct in_addr ip)
+/****************************************************************************
+adds information retrieved from a NetServerEnum call
+****************************************************************************/
+static BOOL add_info(struct subnet_record *d, struct work_record *work, int servertype)
{
- char *protocol = "LM1.2X002";
- char *service = "IPC$";
- char *dev = "IPC";
- int timeout=2000;
- char *inbuf=NULL;
- pstring outbuf;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rdrcnt,rprcnt;
char *p;
- int len;
- uint32 sesskey;
- int cnum,uid;
- BOOL ret;
-
- int fd = open_socket_out(SOCK_STREAM, &ip, SMB_PORT);
- if (fd < 0) {
- DEBUG(3,("Failed to connect to %s at %s\n",name,inet_ntoa(ip)));
- return;
- }
-
- if (!(inbuf = (char *)malloc(0xFFFF+1024))) return;
-
- /* put in the destination name */
- len = 4;
- p = outbuf+len;
- name_mangle(name,p,name_type);
- len += name_len(p);
-
- /* and my name */
- p = outbuf+len;
- name_mangle(myname,p,0x20);
- len += name_len(p);
-
- _smb_setlen(outbuf,len);
- CVAL(outbuf,0) = 0x81;
-
- send_smb(fd,outbuf);
- receive_smb(fd,inbuf,5000);
+ pstring param;
+ int uLevel = 1;
+ int count = -1;
- bzero(outbuf,smb_size);
-
- /* setup the protocol string */
- set_message(outbuf,0,strlen(protocol)+2,True);
- p = smb_buf(outbuf);
- *p++ = 2;
- strcpy(p,protocol);
-
- CVAL(outbuf,smb_com) = SMBnegprot;
- CVAL(outbuf,smb_flg) = 0x8;
- SSVAL(outbuf,smb_flg2,0x1);
-
- send_smb(fd,outbuf);
- bzero(inbuf,smb_size);
- ret = receive_smb(fd,inbuf,timeout);
+ /* now send a SMBtrans command with api ServerEnum? */
+ p = param;
+ SSVAL(p,0,0x68); /* api number */
+ p += 2;
+ strcpy(p,"WrLehDz");
+ p = skip_string(p,1);
+
+ strcpy(p,"B16BBDz");
- if (!ret || CVAL(inbuf,smb_rcls) || SVAL(inbuf,smb_vwv0)) {
- DEBUG(3,("%s rejected the protocol\n",name));
- close(fd);
- if (inbuf) free(inbuf);
- return;
- }
-
- sesskey = IVAL(inbuf,smb_vwv6);
-
- bzero(outbuf,smb_size);
- set_message(outbuf,10,2,True);
- CVAL(outbuf,smb_com) = SMBsesssetupX;
-
- CVAL(outbuf,smb_vwv0) = 0xFF;
- SSVAL(outbuf,smb_vwv2,0xFFFF);
- SSVAL(outbuf,smb_vwv3,2);
- SSVAL(outbuf,smb_vwv4,1);
- SIVAL(outbuf,smb_vwv5,sesskey);
- SSVAL(outbuf,smb_vwv7,1);
-
- send_smb(fd,outbuf);
- bzero(inbuf,smb_size);
- ret = receive_smb(fd,inbuf,timeout);
- if (!ret || CVAL(inbuf,smb_rcls)) {
- DEBUG(3,("%s rejected session setup\n",name));
- close(fd);
- if (inbuf) free(inbuf);
- return;
- }
-
- uid = SVAL(inbuf,smb_uid);
-
- bzero(outbuf,smb_size);
- set_message(outbuf,4,2 + (2 + strlen(name) + 1 + strlen(service)) +
- 1 + strlen(dev),True);
- CVAL(outbuf,smb_com) = SMBtconX;
- SSVAL(outbuf,smb_uid,uid);
-
- SSVAL(outbuf,smb_vwv0,0xFF);
- SSVAL(outbuf,smb_vwv3,1);
-
- p = smb_buf(outbuf) + 1;
- strcpy(p, "\\\\");
- strcat(p, name);
- strcat(p, "\\");
- strcat(p,service);
p = skip_string(p,1);
- strcpy(p,dev);
-
- send_smb(fd,outbuf);
- bzero(inbuf,smb_size);
- ret = receive_smb(fd,inbuf,timeout);
- if (!ret || CVAL(inbuf,smb_rcls)) {
- DEBUG(3,("%s rejected IPC connect (%d,%d)\n",name,
- CVAL(inbuf,smb_rcls),SVAL(inbuf,smb_err)));
- close(fd);
- if (inbuf) free(inbuf);
- return;
- }
-
- cnum = SVAL(inbuf,smb_tid);
+ SSVAL(p,0,uLevel);
+ SSVAL(p,2,0x2000); /* buf length */
+ p += 4;
+ SIVAL(p,0,servertype);
+ p += 4;
- /* now I need to send a NetServerEnum */
- {
- fstring param;
- uint32 *typep;
- char *rparam,*rdata;
-
- p = param;
- SSVAL(p,0,0x68); /* api number */
- p += 2;
- strcpy(p,"WrLehDz");
- p = skip_string(p,1);
-
- strcpy(p,"B16BBDz");
-
- p = skip_string(p,1);
- SSVAL(p,0,1); /* level 1 */
- SSVAL(p,2,0xFFFF - 500); /* buf length */
- p += 4;
- typep = (uint32 *)p;
- p += 4;
- strcpy(p,domain);
- strupper(p);
- p = skip_string(p,1);
-
- SIVAL(typep,0,0x80000000); /* domain list */
-
- if (call_remote_api(fd,cnum,uid,timeout,inbuf,outbuf,
- PTR_DIFF(p,param),0,
- 8,0xFFFF - 500,
- NULL,NULL,
- param,NULL,
- &rparam,&rdata) && SVAL(rparam,0)==0)
+ strcpy(p, work->work_group);
+ p = skip_string(p,1);
+
+ if (cli_call_api(PTR_DIFF(p,param),0, 8,10000,
+ &rprcnt,&rdrcnt, param,NULL,
+ &rparam,&rdata))
{
+ int res = SVAL(rparam,0);
int converter=SVAL(rparam,2);
- int count=SVAL(rparam,4);
int i;
- char *p2 = rdata;
- for (i=0;i<count;i++) {
- char *sname = p2;
- uint32 type = IVAL(p2,18);
- int comment_offset = IVAL(p2,22) & 0xFFFF;
- char *comment = comment_offset?(rdata+comment_offset-converter):"";
-
- add_server_entry(sname,type,lp_max_ttl(),comment,False);
- p2 += 26;
- }
+
+ if (res == 0)
+ {
+ count=SVAL(rparam,4);
+ p = rdata;
+
+ for (i = 0;i < count;i++, p += 26)
+ {
+ char *sname = p;
+ uint32 stype = IVAL(p,18);
+ int comment_offset = IVAL(p,22) & 0xFFFF;
+ char *cmnt = comment_offset?(rdata+comment_offset-converter):"";
+
+ struct work_record *w = work;
+
+ DEBUG(4, ("\t%-16.16s %08x %s\n", sname, stype, cmnt));
+
+ if (stype & SV_TYPE_DOMAIN_ENUM)
+ {
+ /* creates workgroup on remote subnet */
+ if ((w = find_workgroupstruct(d,sname,True)))
+ {
+ announce_request(w, d->bcast_ip);
+ }
+ }
+
+ if (w)
+ add_server_entry(d,w,sname,stype,lp_max_ttl(),cmnt,False);
+ }
+ }
}
+
+ if (rparam) free(rparam);
+ if (rdata) free(rdata);
+
+ return(True);
+}
- SIVAL(typep,0,0xFFFFFFFF); /* server list */
- if (call_remote_api(fd,cnum,uid,timeout,inbuf,outbuf,
- PTR_DIFF(p,param),0,
- 8,0xFFFF - 500,
- NULL,NULL,
- param,NULL,
- &rparam,&rdata) && SVAL(rparam,0)==0)
- {
- int converter=SVAL(rparam,2);
- int count=SVAL(rparam,4);
- int i;
+/*******************************************************************
+ synchronise browse lists with another browse server.
- p = rdata;
- for (i=0;i<count;i++) {
- char *sname = p;
- uint32 type = IVAL(p,18);
- int comment_offset = IVAL(p,22) & 0xFFFF;
- char *comment = comment_offset?(rdata+comment_offset-converter):"";
+ log in on the remote server's SMB port to their IPC$ service,
+ do a NetServerEnum and update our server and workgroup databases.
+ ******************************************************************/
+void sync_browse_lists(struct subnet_record *d, struct work_record *work,
+ char *name, int nm_type, struct in_addr ip, BOOL local)
+{
+ uint32 local_type = local ? SV_TYPE_LOCAL_LIST_ONLY : 0;
- add_server_entry(sname,type,lp_max_ttl(),comment,False);
- p += 26;
- }
- }
- }
+ if (!d || !work || !AM_MASTER(work)) return;
- /* close up */
- bzero(outbuf,smb_size);
- set_message(outbuf,0,0,True);
- CVAL(outbuf,smb_com) = SMBtdis;
- SSVAL(outbuf,smb_uid,uid);
- SSVAL(outbuf,smb_tid,cnum);
- send_smb(fd,outbuf);
- receive_smb(fd,inbuf,1000);
+ pid = getpid();
+ uid = getuid();
+ gid = getgid();
+ mid = pid + 100;
+ name_type = nm_type;
+
+ got_pass = True;
- close(fd);
- if (inbuf) free(inbuf);
+ DEBUG(4,("sync browse lists with %s for %s %s\n",
+ work->work_group, name, inet_ntoa(ip)));
+
+ strcpy(workgroup,work->work_group);
+ strcpy(desthost,name);
+ dest_ip = ip;
+
+ if (zero_ip(dest_ip)) return;
+ have_ip = True;
+
+ connect_as_ipc = True;
+
+ /* connect as server and get domains, then servers */
+
+ sprintf(service,"\\\\%s\\IPC$", name);
+ strupper(service);
+
+ if (cli_open_sockets(SMB_PORT))
+ {
+ if (cli_send_login(NULL,NULL,True,True))
+ {
+ add_info(d, work, local_type|SV_TYPE_DOMAIN_ENUM);
+ add_info(d, work, local_type|(SV_TYPE_ALL&
+ ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY)));
+ }
+
+ close_sockets();
+ }
}
diff --git a/source/param/loadparm.c b/source/param/loadparm.c
index c61ab26781f..7877f2eb99c 100644
--- a/source/param/loadparm.c
+++ b/source/param/loadparm.c
@@ -49,16 +49,10 @@
#include "includes.h"
-#include "params.h"
-#include "loadparm.h"
-#include "pcap.h"
-
BOOL bLoaded = False;
extern int DEBUGLEVEL;
-extern int ReadSize;
extern pstring user_socket_options;
-extern pstring smbrun_path;
#ifndef GLOBAL_NAME
#define GLOBAL_NAME "global"
@@ -110,57 +104,63 @@ extern int coding_system;
*/
typedef struct
{
- char *szPrintcapname;
- char *szLockDir;
- char *szRootdir;
- char *szDefaultService;
- char *szDfree;
- char *szMsgCommand;
- char *szHostsEquiv;
- char *szServerString;
- char *szAutoServices;
- char *szPasswdProgram;
- char *szPasswdChat;
- char *szLogFile;
- char *szConfigFile;
- char *szSMBPasswdFile;
- char *szPasswordServer;
- char *szSocketOptions;
- char *szValidChars;
- char *szWorkGroup;
- char *szDomainController;
- char *szUsernameMap;
- char *szCharacterSet;
- char *szLogonScript;
- int max_log_size;
- int mangled_stack;
- int max_xmit;
- int max_mux;
- int max_packet;
- int pwordlevel;
- int deadtime;
- int maxprotocol;
- int security;
- int printing;
- int maxdisksize;
- int lpqcachetime;
- int syslog;
- int os_level;
- int max_ttl;
- BOOL bPreferredMaster;
- BOOL bDomainMaster;
- BOOL bDomainLogons;
- BOOL bEncryptPasswords;
- BOOL bStripDot;
- BOOL bNullPasswords;
- BOOL bLoadPrinters;
- BOOL bUseRhosts;
- BOOL bReadRaw;
- BOOL bWriteRaw;
- BOOL bReadPrediction;
- BOOL bReadbmpx;
- BOOL bSyslogOnly;
- BOOL bBrowseList;
+ char *szPrintcapname;
+ char *szLockDir;
+ char *szRootdir;
+ char *szDefaultService;
+ char *szDfree;
+ char *szMsgCommand;
+ char *szHostsEquiv;
+ char *szServerString;
+ char *szAutoServices;
+ char *szPasswdProgram;
+ char *szPasswdChat;
+ char *szLogFile;
+ char *szConfigFile;
+ char *szSMBPasswdFile;
+ char *szPasswordServer;
+ char *szSocketOptions;
+ char *szValidChars;
+ char *szWorkGroup;
+ char *szDomainController;
+ char *szUsernameMap;
+ char *szCharacterSet;
+ char *szLogonScript;
+ char *szSmbrun;
+ char *szWINSserver;
+ char *szInterfaces;
+ int max_log_size;
+ int mangled_stack;
+ int max_xmit;
+ int max_mux;
+ int max_packet;
+ int pwordlevel;
+ int deadtime;
+ int maxprotocol;
+ int security;
+ int printing;
+ int maxdisksize;
+ int lpqcachetime;
+ int syslog;
+ int os_level;
+ int max_ttl;
+ int ReadSize;
+ BOOL bWINSsupport;
+ BOOL bWINSproxy;
+ BOOL bPreferredMaster;
+ BOOL bDomainMaster;
+ BOOL bDomainLogons;
+ BOOL bEncryptPasswords;
+ BOOL bStripDot;
+ BOOL bNullPasswords;
+ BOOL bLoadPrinters;
+ BOOL bUseRhosts;
+ BOOL bReadRaw;
+ BOOL bWriteRaw;
+ BOOL bReadPrediction;
+ BOOL bReadbmpx;
+ BOOL bSyslogOnly;
+ BOOL bBrowseList;
} global;
static global Globals;
@@ -192,6 +192,7 @@ typedef struct
char *szLppausecommand;
char *szLpresumecommand;
char *szPrintername;
+ char *szPrinterDriver;
char *szDontdescend;
char *szHostsallow;
char *szHostsdeny;
@@ -236,6 +237,7 @@ typedef struct
BOOL bSyncAlways;
char magic_char;
BOOL *copymap;
+ BOOL bDeleteReadonly;
char dummy[3]; /* for alignment */
} service;
@@ -263,6 +265,7 @@ static service sDefault =
NULL, /* szLppausecommand */
NULL, /* szLpresumecommand */
NULL, /* szPrintername */
+ NULL, /* szPrinterDriver */
NULL, /* szDontdescend */
NULL, /* szHostsallow */
NULL, /* szHostsdeny */
@@ -307,6 +310,7 @@ static service sDefault =
False, /* bSyncAlways */
'~', /* magic char */
NULL, /* copymap */
+ False, /* bDeleteReadonly */
"" /* dummy */
};
@@ -363,9 +367,10 @@ struct parm_struct
{"load printers", P_BOOL, P_GLOBAL, &Globals.bLoadPrinters, NULL},
{"null passwords", P_BOOL, P_GLOBAL, &Globals.bNullPasswords, NULL},
{"strip dot", P_BOOL, P_GLOBAL, &Globals.bStripDot, NULL},
+ {"interfaces", P_STRING, P_GLOBAL, &Globals.szInterfaces, NULL},
{"password server", P_STRING, P_GLOBAL, &Globals.szPasswordServer, NULL},
{"socket options", P_GSTRING, P_GLOBAL, user_socket_options, NULL},
- {"smbrun", P_GSTRING, P_GLOBAL, smbrun_path, NULL},
+ {"smbrun", P_STRING, P_GLOBAL, &Globals.szSmbrun, NULL},
{"log file", P_STRING, P_GLOBAL, &Globals.szLogFile, NULL},
{"config file", P_STRING, P_GLOBAL, &Globals.szConfigFile, NULL},
{"smb passwd file", P_STRING, P_GLOBAL, &Globals.szSMBPasswdFile, NULL},
@@ -402,12 +407,15 @@ struct parm_struct
{"keepalive", P_INTEGER, P_GLOBAL, &keepalive, NULL},
{"deadtime", P_INTEGER, P_GLOBAL, &Globals.deadtime, NULL},
{"time offset", P_INTEGER, P_GLOBAL, &extra_time_offset, NULL},
- {"read size", P_INTEGER, P_GLOBAL, &ReadSize, NULL},
+ {"read size", P_INTEGER, P_GLOBAL, &Globals.ReadSize, NULL},
#ifdef KANJI
{"coding system", P_INTEGER, P_GLOBAL, &coding_system, handle_coding_system},
#endif /* KANJI */
{"os level", P_INTEGER, P_GLOBAL, &Globals.os_level, NULL},
{"max ttl", P_INTEGER, P_GLOBAL, &Globals.max_ttl, NULL},
+ {"wins support", P_BOOL, P_GLOBAL, &Globals.bWINSsupport, NULL},
+ {"wins proxy", P_BOOL, P_GLOBAL, &Globals.bWINSproxy, NULL},
+ {"wins server", P_STRING, P_GLOBAL, &Globals.szWINSserver, NULL},
{"preferred master", P_BOOL, P_GLOBAL, &Globals.bPreferredMaster, NULL},
{"prefered master", P_BOOL, P_GLOBAL, &Globals.bPreferredMaster, NULL},
{"domain master", P_BOOL, P_GLOBAL, &Globals.bDomainMaster, NULL},
@@ -485,6 +493,7 @@ struct parm_struct
{"lpresume command", P_STRING, P_LOCAL, &sDefault.szLpresumecommand,NULL},
{"printer", P_STRING, P_LOCAL, &sDefault.szPrintername, NULL},
{"printer name", P_STRING, P_LOCAL, &sDefault.szPrintername, NULL},
+ {"printer driver", P_STRING, P_LOCAL, &sDefault.szPrinterDriver, NULL},
{"hosts allow", P_STRING, P_LOCAL, &sDefault.szHostsallow, NULL},
{"allow hosts", P_STRING, P_LOCAL, &sDefault.szHostsallow, NULL},
{"hosts deny", P_STRING, P_LOCAL, &sDefault.szHostsdeny, NULL},
@@ -493,6 +502,7 @@ struct parm_struct
{"magic script", P_STRING, P_LOCAL, &sDefault.szMagicScript, NULL},
{"magic output", P_STRING, P_LOCAL, &sDefault.szMagicOutput, NULL},
{"mangled map", P_STRING, P_LOCAL, &sDefault.szMangledMap, NULL},
+ {"delete readonly", P_BOOL, P_LOCAL, &sDefault.bDeleteReadonly, NULL},
{NULL, P_BOOL, P_NONE, NULL, NULL}
};
@@ -538,6 +548,7 @@ static void init_globals(void)
string_set(&Globals.szPrintcapname, PRINTCAP_NAME);
string_set(&Globals.szLockDir, LOCKDIR);
string_set(&Globals.szRootdir, "/");
+ string_set(&Globals.szSmbrun, SMBRUN);
sprintf(s,"Samba %s",VERSION);
string_set(&Globals.szServerString,s);
Globals.bLoadPrinters = True;
@@ -568,6 +579,9 @@ static void init_globals(void)
Globals.bDomainMaster = False;
Globals.bDomainLogons = False;
Globals.bBrowseList = True;
+ Globals.bWINSsupport = True;
+ Globals.bWINSproxy = False;
+ Globals.ReadSize = 16*1024;
#ifdef KANJI
coding_system = interpret_coding_system (KANJI, SJIS_CODE);
@@ -595,6 +609,7 @@ static void init_locals(void)
{
case PRINT_BSD:
case PRINT_AIX:
+ case PRINT_PLP:
string_initial(&sDefault.szLpqcommand,"lpq -P%p");
string_initial(&sDefault.szLprmcommand,"lprm -P%p %j");
string_initial(&sDefault.szPrintcommand,"lpr -r -P%p %s");
@@ -670,6 +685,7 @@ char *lp_string(char *s)
int fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
FN_GLOBAL_STRING(lp_logfile,&Globals.szLogFile)
+FN_GLOBAL_STRING(lp_smbrun,&Globals.szSmbrun)
FN_GLOBAL_STRING(lp_configfile,&Globals.szConfigFile)
FN_GLOBAL_STRING(lp_smb_passwd_file,&Globals.szSMBPasswdFile)
FN_GLOBAL_STRING(lp_serverstring,&Globals.szServerString)
@@ -689,7 +705,11 @@ FN_GLOBAL_STRING(lp_domain_controller,&Globals.szDomainController)
FN_GLOBAL_STRING(lp_username_map,&Globals.szUsernameMap)
FN_GLOBAL_STRING(lp_character_set,&Globals.szCharacterSet)
FN_GLOBAL_STRING(lp_logon_script,&Globals.szLogonScript)
+FN_GLOBAL_STRING(lp_wins_server,&Globals.szWINSserver)
+FN_GLOBAL_STRING(lp_interfaces,&Globals.szInterfaces)
+FN_GLOBAL_BOOL(lp_wins_support,&Globals.bWINSsupport)
+FN_GLOBAL_BOOL(lp_wins_proxy,&Globals.bWINSproxy)
FN_GLOBAL_BOOL(lp_domain_master,&Globals.bDomainMaster)
FN_GLOBAL_BOOL(lp_domain_logons,&Globals.bDomainLogons)
FN_GLOBAL_BOOL(lp_preferred_master,&Globals.bPreferredMaster)
@@ -715,6 +735,7 @@ FN_GLOBAL_INTEGER(lp_maxmux,&Globals.max_mux)
FN_GLOBAL_INTEGER(lp_maxpacket,&Globals.max_packet)
FN_GLOBAL_INTEGER(lp_keepalive,&keepalive)
FN_GLOBAL_INTEGER(lp_passwordlevel,&Globals.pwordlevel)
+FN_GLOBAL_INTEGER(lp_readsize,&Globals.ReadSize)
FN_GLOBAL_INTEGER(lp_deadtime,&Globals.deadtime)
FN_GLOBAL_INTEGER(lp_maxprotocol,&Globals.maxprotocol)
FN_GLOBAL_INTEGER(lp_security,&Globals.security)
@@ -741,6 +762,7 @@ FN_LOCAL_STRING(lp_lprmcommand,szLprmcommand)
FN_LOCAL_STRING(lp_lppausecommand,szLppausecommand)
FN_LOCAL_STRING(lp_lpresumecommand,szLpresumecommand)
FN_LOCAL_STRING(lp_printername,szPrintername)
+FN_LOCAL_STRING(lp_printerdriver,szPrinterDriver)
FN_LOCAL_STRING(lp_hostsallow,szHostsallow)
FN_LOCAL_STRING(lp_hostsdeny,szHostsdeny)
FN_LOCAL_STRING(lp_magicscript,szMagicScript)
@@ -778,6 +800,7 @@ FN_LOCAL_BOOL(lp_manglednames,bMangledNames)
FN_LOCAL_BOOL(lp_widelinks,bWidelinks)
FN_LOCAL_BOOL(lp_syncalways,bSyncAlways)
FN_LOCAL_BOOL(lp_map_system,bMap_system)
+FN_LOCAL_BOOL(lp_delete_readonly,bDeleteReadonly)
FN_LOCAL_INTEGER(lp_create_mode,iCreate_mode)
FN_LOCAL_INTEGER(lp_max_connections,iMaxConnections)
@@ -1291,6 +1314,8 @@ static BOOL handle_printing(char *pszParmValue,int *val)
*val = PRINT_BSD;
else if (strequal(pszParmValue,"qnx"))
*val = PRINT_QNX;
+ else if (strequal(pszParmValue,"plp"))
+ *val = PRINT_PLP;
return(True);
}
diff --git a/source/param/params.c b/source/param/params.c
index b9d61382a18..8030e4ab583 100644
--- a/source/param/params.c
+++ b/source/param/params.c
@@ -57,29 +57,79 @@ the other = 3
#include "includes.h"
#include "smb.h"
-#include "params.h"
/* local variable pointing to passed filename */
static char *pszParmFile = NULL;
extern int DEBUGLEVEL;
-/* local prototypes */
-static BOOL enumerate_parameters(FILE *infile, PM_PARMFUNC pfunc);
-static BOOL enumerate_sections(FILE *infile,
- PM_SECFUNC sfunc, PM_PARMFUNC pfunc);
-/* prototypes for local toolbox functions */
-static void trimleft(char *psz);
-static void trimright(char *psz);
-static void collapse_spaces(char *psz);
-static int firstnonwhite(char *psz);
+/**************************************************************************
+Strip all leading whitespace from a string.
+**************************************************************************/
+static void trimleft(char *psz)
+{
+ char *pszDest;
+
+ pszDest = psz;
+ if (psz != NULL)
+ {
+ while (*psz != '\0' && isspace(*psz))
+ psz++;
+ while (*psz != '\0')
+ *pszDest++ = *psz++;
+ *pszDest = '\0';
+ }
+}
+
+/**************************************************************************
+Strip all trailing whitespace from a string.
+**************************************************************************/
+static void trimright(char *psz)
+{
+ char *pszTemp;
+
+ if (psz != NULL && psz[0] != '\0')
+ {
+ pszTemp = psz + strlen(psz) - 1;
+ while (isspace(*pszTemp))
+ *pszTemp-- = '\0';
+ }
+}
+
+/***********************************************************************
+Collapse each whitespace area in a string to a single space.
+***********************************************************************/
+static void collapse_spaces(char *psz)
+{
+ while (*psz)
+ if (isspace(*psz))
+ {
+ *psz++ = ' ';
+ trimleft(psz);
+ }
+ else
+ psz++;
+}
+
+/**************************************************************************
+Return the value of the first non-white character in the specified string.
+The terminating NUL counts as non-white for the purposes of this function.
+Note - no check for a NULL string! What would we return?
+**************************************************************************/
+static int firstnonwhite(char *psz)
+{
+ while (isspace(*psz) && (*psz != '\0'))
+ psz++;
+ return (*psz);
+}
+
/**************************************************************************
Identifies all parameters in the current section, calls the parameter
function for each. Ignores comment lines, stops and backs up in file when
a section is encountered. Returns True on success, False on error.
**************************************************************************/
-static BOOL enumerate_parameters(FILE *fileIn, PM_PARMFUNC pfunc)
+static BOOL enumerate_parameters(FILE *fileIn, BOOL (*pfunc)(char *,char *))
{
pstring szBuf;
char *pszTemp;
@@ -186,8 +236,8 @@ Returns True on success, False on failure. Note that the section and
parameter names will have all internal whitespace areas collapsed to a
single space for processing.
**************************************************************************/
-static BOOL enumerate_sections(FILE *fileIn,
- PM_SECFUNC sfunc, PM_PARMFUNC pfunc)
+static BOOL enumerate_sections(FILE *fileIn,
+ BOOL (*sfunc)(char *),BOOL (*pfunc)(char *,char *))
{
pstring szBuf;
BOOL bRetval;
@@ -246,7 +296,7 @@ Process the passed parameter file.
Returns True if successful, else False.
**************************************************************************/
-BOOL pm_process(char *pszFileName, PM_SECFUNC sfunc, PM_PARMFUNC pfunc)
+BOOL pm_process(char *pszFileName,BOOL (*sfunc)(char *),BOOL (*pfunc)(char *,char *))
{
FILE *fileIn;
BOOL bRetval;
@@ -263,7 +313,7 @@ BOOL pm_process(char *pszFileName, PM_SECFUNC sfunc, PM_PARMFUNC pfunc)
DEBUG(0,( "Unable to open configuration file \"%s\"!\n", pszParmFile));
else
{
- DEBUG(2,( "Processing configuration file \"%s\"\n", pszParmFile));
+ DEBUG(3,("Processing configuration file \"%s\"\n", pszParmFile));
bRetval = enumerate_sections(fileIn, sfunc, pfunc);
fclose(fileIn);
}
@@ -274,62 +324,3 @@ BOOL pm_process(char *pszFileName, PM_SECFUNC sfunc, PM_PARMFUNC pfunc)
}
-/**************************************************************************
-Strip all leading whitespace from a string.
-**************************************************************************/
-static void trimleft(char *psz)
-{
- char *pszDest;
-
- pszDest = psz;
- if (psz != NULL)
- {
- while (*psz != '\0' && isspace(*psz))
- psz++;
- while (*psz != '\0')
- *pszDest++ = *psz++;
- *pszDest = '\0';
- }
-}
-
-/**************************************************************************
-Strip all trailing whitespace from a string.
-**************************************************************************/
-static void trimright(char *psz)
-{
- char *pszTemp;
-
- if (psz != NULL && psz[0] != '\0')
- {
- pszTemp = psz + strlen(psz) - 1;
- while (isspace(*pszTemp))
- *pszTemp-- = '\0';
- }
-}
-
-/***********************************************************************
-Collapse each whitespace area in a string to a single space.
-***********************************************************************/
-static void collapse_spaces(char *psz)
-{
- while (*psz)
- if (isspace(*psz))
- {
- *psz++ = ' ';
- trimleft(psz);
- }
- else
- psz++;
-}
-
-/**************************************************************************
-Return the value of the first non-white character in the specified string.
-The terminating NUL counts as non-white for the purposes of this function.
-Note - no check for a NULL string! What would we return?
-**************************************************************************/
-static int firstnonwhite(char *psz)
-{
- while (isspace(*psz) && (*psz != '\0'))
- psz++;
- return (*psz);
-}
diff --git a/source/passdb/smbpass.c b/source/passdb/smbpass.c
index 2dec15ffb43..cd4a7ccf664 100644
--- a/source/passdb/smbpass.c
+++ b/source/passdb/smbpass.c
@@ -19,7 +19,6 @@
*/
#include "includes.h"
-#include "loadparm.h"
extern int DEBUGLEVEL;
@@ -59,8 +58,7 @@ do_pw_lock(int fd, int waitsecs, int type)
return ret;
}
-int
-pw_file_lock(char *name, int type, int secs)
+int pw_file_lock(char *name, int type, int secs)
{
int fd = open(name, O_RDWR | O_CREAT, 0666);
if (fd < 0)
@@ -72,8 +70,7 @@ pw_file_lock(char *name, int type, int secs)
return fd;
}
-int
-pw_file_unlock(int fd)
+int pw_file_unlock(int fd)
{
do_pw_lock(fd, 5, F_UNLCK);
return close(fd);
@@ -110,8 +107,7 @@ static int gethexpwd(char *p, char *pwd)
/*
* Routine to search the smbpasswd file for an entry matching the username.
*/
-struct smb_passwd *
-get_smbpwnam(char *name)
+struct smb_passwd *get_smbpwnam(char *name)
{
/* Static buffers we will return. */
static struct smb_passwd pw_buf;
@@ -262,7 +258,7 @@ get_smbpwnam(char *name)
if (!strncasecmp((char *) p, "NO PASSWORD", 11)) {
pw_buf.smb_passwd = NULL;
} else {
- if(!gethexpwd(p,smbpwd)) {
+ if(!gethexpwd((char *)p,(char *)smbpwd)) {
DEBUG(0, ("Malformed Lanman password entry (non hex chars)\n"));
fclose(fp);
pw_file_unlock(lockfd);
@@ -280,7 +276,7 @@ get_smbpwnam(char *name)
the lanman password. */
if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) {
if (*p != '*' && *p != 'X') {
- if(gethexpwd(p,smbntpwd))
+ if(gethexpwd((char *)p,(char *)smbntpwd))
pw_buf.smb_nt_passwd = smbntpwd;
}
}
@@ -297,8 +293,7 @@ get_smbpwnam(char *name)
return NULL;
}
#else
-void
-smbpass_dummy(void)
+ void smbpass_dummy(void)
{
} /* To avoid compiler complaints */
#endif
diff --git a/source/printing/pcap.c b/source/printing/pcap.c
index 8973b1627fb..13b850b3f5b 100644
--- a/source/printing/pcap.c
+++ b/source/printing/pcap.c
@@ -54,8 +54,6 @@
#include "includes.h"
#include "smb.h"
-#include "loadparm.h"
-#include "pcap.h"
extern int DEBUGLEVEL;
diff --git a/source/printing/printing.c b/source/printing/printing.c
index 1dd8921800a..00df859e0ab 100644
--- a/source/printing/printing.c
+++ b/source/printing/printing.c
@@ -20,7 +20,6 @@
*/
#include "includes.h"
-#include "loadparm.h"
extern int DEBUGLEVEL;
extern connection_struct Connections[];
extern files_struct Files[];
@@ -74,7 +73,7 @@ static char *build_print_command(int cnum, char *command, char *syscmd, char *fi
}
if (strstr(syscmd,"%s")) {
- int iOffset = strstr(syscmd, "%s") - syscmd;
+ int iOffset = PTR_DIFF(strstr(syscmd, "%s"),syscmd);
/* construct the full path for the filename, shouldn't be necessary unless
the subshell causes a "cd" to be executed.
@@ -149,7 +148,7 @@ process time fields
********************************************************************/
static time_t EntryTime(string tok[], int ptr, int count, int minimum)
{
- time_t jobtime;
+ time_t jobtime,jobtime1;
jobtime = time(NULL); /* default case: take current time */
if (count >= minimum) {
@@ -181,7 +180,9 @@ static time_t EntryTime(string tok[], int ptr, int count, int minimum)
t->tm_hour = hour;
t->tm_min = min;
t->tm_sec = sec;
- jobtime = mktime(t);
+ jobtime1 = mktime(t);
+ if (jobtime1 != (time_t)-1)
+ jobtime = jobtime1;
}
}
return jobtime;
@@ -596,6 +597,76 @@ static BOOL parse_lpq_qnx(char *line,print_queue_struct *buf,BOOL first)
}
+/****************************************************************************
+ parse a lpq line for the plp printing system
+ Bertrand Wallrich <Bertrand.Wallrich@loria.fr>
+
+redone by tridge. Here is a sample queue:
+
+Local Printer 'lp2' (fjall):
+ Printing (started at Jun 15 13:33:58, attempt 1).
+ Rank Owner Pr Opt Job Host Files Size Date
+ active tridge X - 6 fjall /etc/hosts 739 Jun 15 13:33
+ 3rd tridge X - 7 fjall /etc/hosts 739 Jun 15 13:33
+
+****************************************************************************/
+static BOOL parse_lpq_plp(char *line,print_queue_struct *buf,BOOL first)
+{
+ string tok[11];
+ int count=0;
+
+ /* handle the case of "(standard input)" as a filename */
+ string_sub(line,"stdin","STDIN");
+ string_sub(line,"(","\"");
+ string_sub(line,")","\"");
+
+ for (count=0; count<11 && next_token(&line,tok[count],NULL); count++) ;
+
+ /* we must get 11 tokens */
+ if (count < 11)
+ return(False);
+
+ /* the first must be "active" or begin with an integer */
+ if (strcmp(tok[0],"active") && !isdigit(tok[0][0]))
+ return(False);
+
+ /* the 5th and 8th must be integer */
+ if (!isdigit(*tok[4]) || !isdigit(*tok[7]))
+ return(False);
+
+ /* if the fname contains a space then use STDIN */
+ if (strchr(tok[6],' '))
+ strcpy(tok[6],"STDIN");
+
+ /* only take the last part of the filename */
+ {
+ string tmp;
+ char *p = strrchr(tok[6],'/');
+ if (p)
+ {
+ strcpy(tmp,p+1);
+ strcpy(tok[6],tmp);
+ }
+ }
+
+
+ buf->job = atoi(tok[4]);
+
+ buf->size = atoi(tok[7]);
+ if (strchr(tok[7],'K'))
+ buf->size *= 1024;
+ if (strchr(tok[7],'M'))
+ buf->size *= 1024*1024;
+
+ buf->status = strequal(tok[0],"active")?LPQ_PRINTING:LPQ_QUEUED;
+ buf->priority = 0;
+ buf->time = time(NULL);
+ StrnCpy(buf->user,tok[1],sizeof(buf->user)-1);
+ StrnCpy(buf->file,tok[6],sizeof(buf->file)-1);
+ return(True);
+}
+
+
char *stat0_strings[] = { "enabled", "online", "idle", "no entries", "free", "ready", NULL };
char *stat1_strings[] = { "offline", "disabled", "down", "off", "waiting", "no daemon", NULL };
@@ -624,6 +695,9 @@ static BOOL parse_lpq_entry(int snum,char *line,
case PRINT_QNX:
ret = parse_lpq_qnx(line,buf,first);
break;
+ case PRINT_PLP:
+ ret = parse_lpq_plp(line,buf,first);
+ break;
default:
ret = parse_lpq_bsd(line,buf,first);
break;
@@ -639,6 +713,12 @@ static BOOL parse_lpq_entry(int snum,char *line,
}
#endif
+ /* We don't want the newline in the status message. */
+ {
+ char *p = strchr(line,'\n');
+ if (p) *p = 0;
+ }
+
if (status && !ret)
{
/* a few simple checks to see if the line might be a
diff --git a/source/script/installbin.sh b/source/script/installbin.sh
index 633e6cb5bb2..b976a3e5ea8 100755
--- a/source/script/installbin.sh
+++ b/source/script/installbin.sh
@@ -34,7 +34,9 @@ done
cat << EOF
======================================================================
The binaries are installed. You may restore the old binaries (if there
-were any) using the command "make revert"
+were any) using the command "make revert". You may uninstall the binaries
+using the command "make uninstallbin" or "make uninstall" to uninstall
+binaries, man pages and shell scripts.
======================================================================
EOF
diff --git a/source/script/installman.sh b/source/script/installman.sh
index a79d157c5f5..3c8fc718654 100755
--- a/source/script/installman.sh
+++ b/source/script/installman.sh
@@ -1,4 +1,6 @@
#!/bin/sh
+#5 July 96 Dan.Shearer@unisa.edu.au removed hardcoded values
+
MANDIR=$1
SRCDIR=$2
@@ -8,28 +10,29 @@ for d in $MANDIR $MANDIR/man1 $MANDIR/man5 $MANDIR/man7 $MANDIR/man8; do
if [ ! -d $d ]; then
mkdir $d
if [ ! -d $d ]; then
- echo Failed to make directory $d
+ echo Failed to make directory $d, does $USER have privileges?
exit 1
fi
fi
done
-cp $SRCDIR../docs/*.1 $MANDIR/man1
-cp $SRCDIR../docs/*.5 $MANDIR/man5
-cp $SRCDIR../docs/*.8 $MANDIR/man8
-cp $SRCDIR../docs/*.7 $MANDIR/man7
-echo Setting permissions on man pages
-chmod 0644 $MANDIR/man1/smbstatus.1
-chmod 0644 $MANDIR/man1/smbclient.1
-chmod 0644 $MANDIR/man1/smbrun.1
-chmod 0644 $MANDIR/man1/testparm.1
-chmod 0644 $MANDIR/man1/testprns.1
-chmod 0644 $MANDIR/man1/smbtar.1
-chmod 0644 $MANDIR/man5/smb.conf.5
-chmod 0644 $MANDIR/man7/samba.7
-chmod 0644 $MANDIR/man8/smbd.8
-chmod 0644 $MANDIR/man8/nmbd.8
+for sect in 1 5 7 8 ; do
+ for m in $MANDIR/man$sect ; do
+ for s in $SRCDIR../docs/*$sect; do
+ FNAME=$m/`basename $s`
+ cp $s $m || echo Cannot create $FNAME... does $USER have privileges?
+ chmod 0644 $FNAME
+ done
+ done
+done
+
+cat << EOF
+======================================================================
+The man pages have been installed. You may uninstall them using the command
+the command "make uninstallman" or make "uninstall" to uninstall binaries,
+man pages and shell scripts.
+======================================================================
+EOF
-echo Man pages installed
exit 0
diff --git a/source/script/installscripts.sh b/source/script/installscripts.sh
new file mode 100755
index 00000000000..ab9035ff812
--- /dev/null
+++ b/source/script/installscripts.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+# this script courtesy of James_K._Foote.PARC@xerox.com
+# 5 July 96 Dan.Shearer@UniSA.Edu.Au Don't hardcode script names, get from Make
+
+INSTALLPERMS=$1
+BINDIR=$2
+
+shift
+shift
+
+echo Installing scripts in $BINDIR
+
+for d in [ $BINDIR ]; do
+ if [ ! -d $d ]; then
+ mkdir $d
+ if [ ! -d $d ]; then
+ echo Failed to make directory $d
+ echo Have you run installbin first?
+ exit 1
+ fi
+ fi
+done
+
+for p in $*; do
+ echo Installing $BINDIR/$p
+ cp $p $BINDIR/$p
+ if [ ! -f $BINDIR/$p ]; then
+ echo Cannot copy $p... does $USER have privileges?
+ fi
+ echo Setting permissions on $BINDIR/$p
+ chmod $INSTALLPERMS $BINDIR/$p
+done
+
+cat << EOF
+======================================================================
+The scripts have been installed. You may uninstall them using
+the command "make uninstallscripts" or "make install" to install binaries,
+man pages and shell scripts. You may recover the previous version (if any
+by "make revert".
+======================================================================
+EOF
+
+exit 0
diff --git a/source/script/mkproto.awk b/source/script/mkproto.awk
new file mode 100644
index 00000000000..200d5bd050b
--- /dev/null
+++ b/source/script/mkproto.awk
@@ -0,0 +1,82 @@
+BEGIN {
+ inheader=0;
+ current_file="";
+ print "/* This file is automatically generated with \"make proto\". DO NOT EDIT */"
+ print ""
+}
+
+{
+ if (FILENAME!=current_file) {
+ print ""
+ print "/*The following definitions come from ",FILENAME," */"
+ print ""
+ current_file=FILENAME
+ }
+ if (inheader) {
+ if (match($0,"[)][ \t]*$")) {
+ inheader = 0;
+ printf "%s;\n",$0;
+ } else {
+ printf "%s\n",$0;
+ }
+ next;
+ }
+}
+
+# we handle the loadparm.c fns separately
+
+/^FN_LOCAL_BOOL/ {
+ split($0,a,"[,()]")
+ printf "BOOL %s(int );\n", a[2]
+}
+
+/^FN_LOCAL_STRING/ {
+ split($0,a,"[,()]")
+ printf "char *%s(int );\n", a[2]
+}
+
+/^FN_LOCAL_INT/ {
+ split($0,a,"[,()]")
+ printf "int %s(int );\n", a[2]
+}
+
+/^FN_LOCAL_CHAR/ {
+ split($0,a,"[,()]")
+ printf "char %s(int );\n", a[2]
+}
+
+/^FN_GLOBAL_BOOL/ {
+ split($0,a,"[,()]")
+ printf "BOOL %s(void);\n", a[2]
+}
+
+/^FN_GLOBAL_STRING/ {
+ split($0,a,"[,()]")
+ printf "char *%s(void);\n", a[2]
+}
+
+/^FN_GLOBAL_INT/ {
+ split($0,a,"[,()]")
+ printf "int %s(void);\n", a[2]
+}
+
+/^static|^extern/ || !/^[a-zA-Z]/ || /[;]/ {
+ next;
+}
+
+!/^unsigned|^mode_t|^DIR|^user|^int|^char|^uint|^struct|^BOOL|^void|^time/ {
+ next;
+}
+
+
+/[(].*[)][ \t]*$/ {
+ printf "%s;\n",$0;
+ next;
+}
+
+/[(]/ {
+ inheader=1;
+ printf "%s\n",$0;
+ next;
+}
+
diff --git a/source/script/smbtar b/source/script/smbtar
index fc032ed41cd..156375ce9c8 100644
--- a/source/script/smbtar
+++ b/source/script/smbtar
@@ -138,4 +138,3 @@ eval $SMBCLIENT "'\\\\$server\\$service'" "'$password'" -U "'$username'" \
-E -N $log -D "'$cdcmd'" \
-T${tarcmd}${tarargs} $blocksize $newer $tapefile $* $verbose
-
diff --git a/source/script/uninstallbin.sh b/source/script/uninstallbin.sh
new file mode 100755
index 00000000000..fab36804a29
--- /dev/null
+++ b/source/script/uninstallbin.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+#4 July 96 Dan.Shearer@UniSA.edu.au
+
+INSTALLPERMS=$1
+BASEDIR=$2
+BINDIR=$3
+LIBDIR=$4
+VARDIR=$5
+shift
+shift
+shift
+shift
+shift
+
+if [ ! -d $BINDIR ]; then
+ echo Directory $BINDIR does not exist!
+ echo Do a "make installbin" or "make install" first.
+ exit 1
+fi
+
+for p in $*; do
+ if [ ! -f $BINDIR/$p ]; then
+ echo $BINDIR/$p does not exist!
+ else
+ echo Removing $BINDIR/$p
+ rm -f $BINDIR/$p
+ if [ -f $BINDIR/$p ]; then
+ echo Cannot remove $BINDIR/$p... does $USER have privileges?
+ fi
+ fi
+done
+
+
+cat << EOF
+======================================================================
+The binaries have been uninstalled. You may restore the binaries using
+the command "make installbin" or "make install" to install binaries,
+man pages and shell scripts. You can restore a previous version of the
+binaries (if there were any) using "make revert".
+======================================================================
+EOF
+
+exit 0
diff --git a/source/script/uninstallman.sh b/source/script/uninstallman.sh
new file mode 100755
index 00000000000..b4d4bfc1f92
--- /dev/null
+++ b/source/script/uninstallman.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+#4 July 96 Dan.Shearer@UniSA.edu.au
+
+MANDIR=$1
+SRCDIR=$2
+
+echo Uninstalling man pages from $MANDIR
+
+for sect in 1 5 7 8 ; do
+ for m in $MANDIR/man$sect ; do
+ for s in $SRCDIR../docs/*$sect; do
+ FNAME=$m/`basename $s`
+ if test -f $FNAME; then
+ echo Deleting $FNAME
+ rm -f $FNAME
+ test -f $FNAME && echo Cannot remove $FNAME... does $USER have privileges?
+ else
+ echo $FNAME does not exist! Check defines in the Makefile
+ fi
+ done
+ done
+done
+
+cat << EOF
+======================================================================
+The man pages have been uninstalled. You may install them again using
+the command "make installman" or make "install" to install binaries,
+man pages and shell scripts.
+======================================================================
+EOF
+exit 0
diff --git a/source/script/uninstallscripts.sh b/source/script/uninstallscripts.sh
new file mode 100755
index 00000000000..ae907546f2e
--- /dev/null
+++ b/source/script/uninstallscripts.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+# 5 July 96 Dan.Shearer@UniSA.Edu.Au - almost identical to uninstallbin.sh
+
+INSTALLPERMS=$1
+BINDIR=$2
+
+shift
+shift
+
+if [ ! -d $BINDIR ]; then
+ echo Directory $BINDIR does not exist!
+ echo Do a "make installscripts" or "make install" first.
+ exit 1
+fi
+
+for p in $*; do
+ if [ ! -f $BINDIR/$p ]; then
+ echo $BINDIR/$p does not exist!
+ else
+ echo Removing $BINDIR/$p
+ rm -f $BINDIR/$p
+ if [ -f $BINDIR/$p ]; then
+ echo Cannot remove $BINDIR/$p... does $USER have privileges?
+ fi
+ fi
+done
+
+cat << EOF
+======================================================================
+The scripts have been uninstalled. You may reinstall them using
+the command "make installscripts" or "make install" to install binaries,
+man pages and shell scripts. You may recover a previous version (if any
+with "make revert".
+======================================================================
+EOF
+
+exit 0
diff --git a/source/smbd/chgpasswd.c b/source/smbd/chgpasswd.c
index dc0514c1ed7..54b49edf13b 100644
--- a/source/smbd/chgpasswd.c
+++ b/source/smbd/chgpasswd.c
@@ -27,7 +27,6 @@
*/
#include "includes.h"
-#include "loadparm.h"
extern int DEBUGLEVEL;
@@ -179,7 +178,7 @@ static int expect(int master,char *expected,char *buf)
}
/* allow 4 seconds for some output to appear */
- m = read_with_timeout(master, buf+n, 1, BUFSIZE-1-n, 4000, True);
+ m = read_with_timeout(master, buf+n, 1, BUFSIZE-1-n, 4000);
if (m < 0)
return False;
diff --git a/source/smbd/dir.c b/source/smbd/dir.c
index ac6f918b9da..55a59834685 100644
--- a/source/smbd/dir.c
+++ b/source/smbd/dir.c
@@ -20,7 +20,6 @@
*/
#include "includes.h"
-#include "loadparm.h"
extern int DEBUGLEVEL;
extern connection_struct Connections[];
@@ -186,6 +185,19 @@ close a dptr
****************************************************************************/
void dptr_close(int key)
{
+ /* OS/2 seems to use -1 to indicate "close all directories" */
+ if (key == -1) {
+ int i;
+ for (i=0;i<NUMDIRPTRS;i++)
+ dptr_close(i);
+ return;
+ }
+
+ if (key < 0 || key >= NUMDIRPTRS) {
+ DEBUG(3,("Invalid key %d given to dptr_close\n",key));
+ return;
+ }
+
if (dirptrs[key].valid) {
DEBUG(4,("closing dptr key %d\n",key));
if (dirptrs[key].ptr) {
@@ -399,6 +411,16 @@ void *dptr_fetch_lanman2(char *params,int dptr_num)
}
/****************************************************************************
+check a filetype for being valid
+****************************************************************************/
+BOOL dir_check_ftype(int cnum,int mode,struct stat *st,int dirtype)
+{
+ if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
+ return False;
+ return True;
+}
+
+/****************************************************************************
get a directory entry
****************************************************************************/
BOOL get_dir_entry(int cnum,char *mask,int dirtype,char *fname,int *size,int *mode,time_t *date,BOOL check_descend)
@@ -461,11 +483,11 @@ BOOL get_dir_entry(int cnum,char *mask,int dirtype,char *fname,int *size,int *mo
*mode = dos_mode(cnum,pathreal,&sbuf);
- if (((*mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
- {
- DEBUG(5,("[%s] attribs didn't match %x\n",filename,dirtype));
- continue;
- }
+ if (!dir_check_ftype(cnum,*mode,&sbuf,dirtype)) {
+ DEBUG(5,("[%s] attribs didn't match %x\n",filename,dirtype));
+ continue;
+ }
+
*size = sbuf.st_size;
*date = sbuf.st_mtime;
diff --git a/source/smbd/ipc.c b/source/smbd/ipc.c
index 8852e57e8b6..0a54936cd02 100644
--- a/source/smbd/ipc.c
+++ b/source/smbd/ipc.c
@@ -24,8 +24,6 @@
*/
#include "includes.h"
-#include "loadparm.h"
-#include "pcap.h"
#ifdef CHECK_TYPES
#undef CHECK_TYPES
@@ -61,6 +59,9 @@ extern fstring local_machine;
#define SNLEN 15 /* service name length */
#define QNLEN 12 /* queue name maximum length */
+#define MAJOR_VERSION 2
+#define MINOR_VERSION 0
+
extern int Client;
static int CopyExpanded(int cnum, int snum, char** dst, char* src, int* n)
@@ -189,12 +190,6 @@ static void send_trans_reply(char *outbuf,char *data,char *param,uint16 *setup,
}
}
-
-
-/****************************************************************************
- get a print queue
- ****************************************************************************/
-
struct pack_desc {
char* format; /* formatstring for structure */
char* subformat; /* subformat for structure */
@@ -418,6 +413,11 @@ static void PACKS(struct pack_desc* desc,char *t,char *v)
PACK(desc,t,v);
}
+
+/****************************************************************************
+ get a print queue
+ ****************************************************************************/
+
static void PackDriverData(struct pack_desc* desc)
{
char drivdata[4+4+32];
@@ -467,7 +467,7 @@ static void fill_printjob_info(int cnum, int snum, int uLevel,
time_t t = queue->time;
/* the client expects localtime */
- t += GMT_TO_LOCAL*TimeDiff(t);
+ t -= TimeDiff(t);
PACKI(desc,"W",((snum%0xFF)<<8) | (queue->job%0xFF)); /* uJobId */
if (uLevel == 1) {
@@ -479,7 +479,7 @@ static void fill_printjob_info(int cnum, int snum, int uLevel,
PACKI(desc,"W",n+1); /* uPosition */
PACKI(desc,"W",queue->status); /* fsStatus */
PACKS(desc,"z",""); /* pszStatus */
- PACKI(desc,"D",queue->time); /* ulSubmitted */
+ PACKI(desc,"D",t); /* ulSubmitted */
PACKI(desc,"D",queue->size); /* ulSize */
PACKS(desc,"z",queue->file); /* pszComment */
}
@@ -488,7 +488,7 @@ static void fill_printjob_info(int cnum, int snum, int uLevel,
PACKS(desc,"z",queue->user); /* pszUserName */
PACKI(desc,"W",n+1); /* uPosition */
PACKI(desc,"W",queue->status); /* fsStatus */
- PACKI(desc,"D",queue->time); /* ulSubmitted */
+ PACKI(desc,"D",t); /* ulSubmitted */
PACKI(desc,"D",queue->size); /* ulSize */
PACKS(desc,"z","Samba"); /* pszComment */
PACKS(desc,"z",queue->file); /* pszDocument */
@@ -545,7 +545,7 @@ static void fill_printq_info(int cnum, int snum, int uLevel,
PACKI(desc,"W",0); /* uUntiltime */
PACKI(desc,"W",5); /* pad1 */
PACKS(desc,"z",""); /* pszSepFile */
- PACKS(desc,"z","lpd"); /* pszPrProc */
+ PACKS(desc,"z","WinPrint"); /* pszPrProc */
PACKS(desc,"z",""); /* pszParms */
if (!status || !status->message[0]) {
PACKS(desc,"z",Expand(cnum,snum,lp_comment(snum))); /* pszComment */
@@ -556,7 +556,7 @@ static void fill_printq_info(int cnum, int snum, int uLevel,
}
PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
- PACKS(desc,"z","NULL"); /* pszDriverName */
+ PACKS(desc,"z",lp_printerdriver(snum)); /* pszDriverName */
PackDriverData(desc); /* pDriverData */
}
if (uLevel == 2 || uLevel == 4) {
@@ -593,6 +593,7 @@ static BOOL api_DosPrintQGetInfo(int cnum,int uid, char *param,char *data,
cbBuf = SVAL(p,2);
str3 = p + 4;
+ /* remove any trailing username */
if ((p = strchr(QueueName,'%'))) *p = 0;
DEBUG(3,("PrintQueue uLevel=%d name=%s\n",uLevel,QueueName));
@@ -751,44 +752,65 @@ struct srv_info_struct
filter out unwanted server info
******************************************************************/
static BOOL filter_server_info(struct srv_info_struct *server,
- char *domain)
-{
- if (*domain)
- return(strequal(domain, server->domain));
-
- return (True); /* be indiscriminate: get all servers! */
-}
-
-/*******************************************************************
- find server in the files saved by nmbd. Return True if we find it.
- ******************************************************************/
-static BOOL find_server(struct srv_info_struct *servers, int num_servers,
- char *domain, char *name)
+ BOOL domains,
+ char *domain, uint32 request)
{
- int count;
-
- if (!servers || num_servers == 0) return (False);
-
- for (count = 0; count < num_servers; count++) {
- struct srv_info_struct *s;
-
- s = &servers[count];
-
- if (strequal(name, s->name)) {
- StrnCpy(domain, s->domain, sizeof(pstring)-1);
- return (True);
+ if (*domain == 0)
+ {
+ if (strequal(lp_workgroup(), server->domain)) {
+ return True;
+ }
+ else if (domains)
+ {
+ DEBUG(4,("primary domain:reject %8x %s %s\n",request,server->name,server->domain));
+ return False;
+ }
+ else if ((request & SV_TYPE_DOMAIN_ENUM) &&
+ (server->type & SV_TYPE_DOMAIN_ENUM))
+ {
+ DEBUG(4,("rej:DOM %8x: %s %s\n",server->type,server->name,server->domain));
+ return False;
+ }
+
+ return True;
+ }
+ else
+ {
+ if (strequal(domain, server->domain))
+ {
+ /*
+ if (request == SV_TYPE_LOCAL_LIST_ONLY &&
+ !(server->type & SV_TYPE_LOCAL_LIST_ONLY))
+ {
+ DEBUG(4,("rej:LOC %8x: ok %s %s\n",request,server->name,server->domain));
+ return False;
+ }
+ */
+ if ((request == (SV_TYPE_LOCAL_LIST_ONLY|SV_TYPE_DOMAIN_ENUM)) &&
+ !(server->type&SV_TYPE_DOMAIN_ENUM))
+ {
+ DEBUG(4,("rej:LOCDOM %8x: ok %s %s\n",request,server->name,server->domain));
+ return False;
+ }
+
+ return True;
+ }
+ else if (!domains)
+ {
+ DEBUG(4,("domain:%s %s %s\n",domain,server->name,server->domain));
+ return False;
+ }
+ return True;
}
- }
- return (False);
}
-
/*******************************************************************
get server info lists from the files saved by nmbd. Return the
number of entries
******************************************************************/
static int get_server_info(uint32 servertype,
- struct srv_info_struct **servers)
+ struct srv_info_struct **servers, BOOL domains,
+ char *domain)
{
FILE *f;
pstring fname;
@@ -807,18 +829,23 @@ static int get_server_info(uint32 servertype,
DEBUG(4,("Can't open %s - %s\n",fname,strerror(errno)));
return(0);
}
+
+ /* request for everything is code for request all servers */
if (servertype == SV_TYPE_ALL) servertype &= ~SV_TYPE_DOMAIN_ENUM;
+ DEBUG(4,("Servertype search: %8x domains:%s\n",servertype,BOOLSTR(domains)));
+
while (!feof(f))
{
fstring stype;
struct srv_info_struct *s;
char *ptr = line;
+ BOOL ok = True;
*ptr = 0;
fgets(line,sizeof(line)-1,f);
if (!*line) continue;
-
+
if (count == alloced) {
alloced += 10;
(*servers) = (struct srv_info_struct *)
@@ -827,36 +854,63 @@ static int get_server_info(uint32 servertype,
bzero((char *)((*servers)+count),sizeof(**servers)*(alloced-count));
}
s = &(*servers)[count];
-
- s->server_added = True;
-
+
if (!next_token(&ptr,s->name , NULL)) continue;
if (!next_token(&ptr,stype , NULL)) continue;
if (!next_token(&ptr,s->comment, NULL)) continue;
if (!next_token(&ptr,s->domain , NULL)) {
- /* this allows us to cop with an old nmbd */
+ /* this allows us to cope with an old nmbd */
strcpy(s->domain,my_workgroup());
}
-
- if (sscanf(stype,"%X",&s->type) != 1) continue;
-
+
+ if (sscanf(stype,"%X",&s->type) != 1) {
+ DEBUG(4,("r:host file "));
+ ok = False;
+ }
+
/* doesn't match up: don't want it */
- if (!(servertype & s->type)) continue;
-
- /* server entry is a domain, we haven't asked for domains: don't want it */
- if ((s->type&SV_TYPE_DOMAIN_ENUM) && !(servertype&SV_TYPE_DOMAIN_ENUM))
- continue;
-
- DEBUG(4,("Server %20s %8x %25s %15s\n",
- s->name, stype, s->comment, s->domain));
-
- count++;
+ if (!(servertype & s->type)) {
+ DEBUG(4,("r:serv type "));
+ ok = False;
+ }
+
+ if ((servertype == ~SV_TYPE_DOMAIN_ENUM) &&
+ (s->type & SV_TYPE_DOMAIN_ENUM))
+ {
+ DEBUG(4,("s:all x dom "));
+ ok = False;
+ }
+
+ if (domains && !(domain && *domain && strequal(domain, s->domain)))
+ {
+ if (!(s->type & SV_TYPE_DOMAIN_ENUM))
+ {
+ DEBUG(4,("r:dom enum "));
+ ok = False;
+ }
+ }
+
+ if (ok)
+ {
+ DEBUG(4,("**SV** %20s %8x %25s %15s\n",
+ s->name, s->type, s->comment, s->domain));
+
+ s->type |= SV_TYPE_LOCAL_LIST_ONLY;
+ s->server_added = True;
+ count++;
+ }
+ else
+ {
+ DEBUG(4,("%20s %8x %25s %15s\n",
+ s->name, s->type, s->comment, s->domain));
+ }
}
-
+
fclose(f);
return(count);
}
+
/*******************************************************************
fill in a server info structure
******************************************************************/
@@ -936,6 +990,11 @@ static int fill_srv_info(struct srv_info_struct *service,
}
+static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
+{
+ return(strcmp(s1->name,s2->name));
+}
+
/****************************************************************************
view list of servers available (or possibly domains). The info is
extracted from lists saved by nmbd on the local host
@@ -957,8 +1016,14 @@ static BOOL api_RNetServerEnum(int cnum, int uid, char *param, char *data,
int counted=0,total=0;
int i;
fstring domain;
- BOOL domain_request = (servertype & SV_TYPE_DOMAIN_ENUM) &&
- !(servertype == SV_TYPE_ALL);
+ BOOL domains;
+ BOOL domain_request;
+ BOOL local_request = servertype & SV_TYPE_LOCAL_LIST_ONLY;
+
+ /*if (servertype == SV_TYPE_ALL) servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);*/
+ if (servertype == SV_TYPE_ALL) servertype &= ~SV_TYPE_DOMAIN_ENUM;
+
+ domain_request = servertype & SV_TYPE_DOMAIN_ENUM;
domain[0] = 0;
p += 8;
@@ -966,49 +1031,53 @@ static BOOL api_RNetServerEnum(int cnum, int uid, char *param, char *data,
if (!prefix_ok(str1,"WrLehD")) return False;
if (!check_server_info(uLevel,str2)) return False;
- DEBUG(4, ("server request level: %s\n", str2));
+ DEBUG(4, ("server request level: %s %8x ", str2, servertype));
+ DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request)));
+ DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request)));
if (strcmp(str1, "WrLehDO") == 0)
{
- /* asking for servers. we will have to work out which workgroup was
- requested, as we maintain lists for multiple workgroups */
+ domains = False;
}
else if (strcmp(str1, "WrLehDz") == 0)
{
- /* asking for a specific workgroup */
+ domains = True;
StrnCpy(domain, p, sizeof(fstring)-1);
}
if (lp_browse_list())
{
- total = get_server_info(servertype,&servers);
- }
-
- if (!domain[0] && !domain_request) {
- extern fstring remote_machine;
- /* must be a server request with an assumed domain. find a domain */
-
- if (find_server(servers, total, domain, remote_machine)) {
- DEBUG(4, ("No domain specified: using %s for %s\n",
- domain, remote_machine));
- } else {
- /* default to soemthing sensible */
- strcpy(domain,my_workgroup());
- }
+ total = get_server_info(servertype,&servers,domains,domain);
}
data_len = fixed_len = string_len = 0;
- for (i=0;i<total;i++)
- if (filter_server_info(&servers[i],domain)) {
- data_len += fill_srv_info(&servers[i],uLevel,0,&f_len,0,&s_len,0);
- if (data_len <= buf_len)
+ qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
+
+ {
+ char *lastname=NULL;
+
+ for (i=0;i<total;i++)
+ {
+ struct srv_info_struct *s = &servers[i];
+ if (filter_server_info(s,domains,domain,
+ local_request|domain_request))
{
- counted++;
- fixed_len += f_len;
- string_len += s_len;
+ if (lastname && strequal(lastname,s->name)) continue;
+ lastname = s->name;
+ data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
+ DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
+ s->name, s->type, s->comment, s->domain));
+
+ if (data_len <= buf_len)
+ {
+ counted++;
+ fixed_len += f_len;
+ string_len += s_len;
+ }
}
}
+ }
*rdata_len = fixed_len + string_len;
*rdata = REALLOC(*rdata,*rdata_len);
@@ -1020,13 +1089,21 @@ static BOOL api_RNetServerEnum(int cnum, int uid, char *param, char *data,
s_len = string_len;
{
+ char *lastname=NULL;
int count2 = counted;
- for (i = 0; i < total && count2;i++) {
- if (filter_server_info(&servers[i],domain)) {
- fill_srv_info(&servers[i],uLevel,&p,&f_len,&p2,&s_len,*rdata);
- count2--;
+ for (i = 0; i < total && count2;i++)
+ {
+ struct srv_info_struct *s = &servers[i];
+ if (filter_server_info(s,domains,domain,local_request|domain_request))
+ {
+ if (lastname && strequal(lastname,s->name)) continue;
+ lastname = s->name;
+ fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
+ DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
+ s->name, s->type, s->comment, s->domain));
+ count2--;
+ }
}
- }
}
*rparam_len = 8;
@@ -1289,7 +1366,7 @@ static BOOL api_NetRemoteTOD(int cnum,int uid, char *param,char *data,
/* the client expects to get localtime, not GMT, in this bit
(I think, this needs testing) */
- t = LocalTime(&unixdate,GMT_TO_LOCAL);
+ t = LocalTime(&unixdate);
SIVAL(p,4,0); /* msecs ? */
CVAL(p,8) = t->tm_hour;
@@ -1332,14 +1409,16 @@ static BOOL api_SetUserPassword(int cnum,int uid, char *param,char *data,
*rdata_len = 0;
- SSVAL(*rparam,0,NERR_Success);
+ SSVAL(*rparam,0,NERR_badpass);
SSVAL(*rparam,2,0); /* converter word */
DEBUG(3,("Set password for <%s>\n",user));
- if (!password_ok(user,pass1,strlen(pass1),NULL,False) ||
- !chgpasswd(user,pass1,pass2))
- SSVAL(*rparam,0,NERR_badpass);
+ if (password_ok(user,pass1,strlen(pass1),NULL,False) &&
+ chgpasswd(user,pass1,pass2))
+ {
+ SSVAL(*rparam,0,NERR_Success);
+ }
bzero(pass1,sizeof(fstring));
bzero(pass2,sizeof(fstring));
@@ -1551,8 +1630,7 @@ static BOOL api_PrintJobInfo(int cnum,int uid,char *param,char *data,
int l = 0;
while (l<64 && *s)
{
- if (isalnum(*s) || strchr("-._",*s))
- name[l++] = *s;
+ if (issafe(*s)) name[l++] = *s;
s++;
}
name[l] = 0;
@@ -1658,7 +1736,7 @@ static BOOL api_RNetServerGetInfo(int cnum,int uid, char *param,char *data,
strcpy(comment,lp_serverstring());
- if ((count=get_server_info(SV_TYPE_ALL,&servers))>0) {
+ if ((count=get_server_info(SV_TYPE_ALL,&servers,False,NULL))>0) {
for (i=0;i<count;i++)
if (strequal(servers[i].name,local_machine)) {
servertype = servers[i].type;
@@ -1667,9 +1745,10 @@ static BOOL api_RNetServerGetInfo(int cnum,int uid, char *param,char *data,
}
if (servers) free(servers);
- SCVAL(p,0,2); /* version_major */
- SCVAL(p,1,0); /* version_minor */
+ SCVAL(p,0,MAJOR_VERSION);
+ SCVAL(p,1,MINOR_VERSION);
SIVAL(p,2,servertype);
+
if (mdrcnt == struct_len) {
SIVAL(p,6,0);
} else {
@@ -1744,8 +1823,8 @@ static BOOL api_NetWkstaGetInfo(int cnum,int uid, char *param,char *data,
p2 = skip_string(p2,1);
p += 4;
- SCVAL(p,0,2); /* major version?? */
- SCVAL(p,1,1); /* minor version?? */
+ SCVAL(p,0,MAJOR_VERSION);
+ SCVAL(p,1,MINOR_VERSION);
p += 2;
SIVAL(p,0,PTR_DIFF(p2,*rdata));
@@ -2717,12 +2796,9 @@ int reply_trans(char *inbuf,char *outbuf)
while (pscnt < tpscnt || dscnt < tdscnt)
{
int pcnt,poff,dcnt,doff,pdisp,ddisp;
-
- receive_smb(Client,inbuf, 0);
- show_msg(inbuf);
-
- /* Ensure this is still a trans packet (sanity check) */
- if(CVAL(inbuf, smb_com) != SMBtrans)
+
+ if (!receive_smb(Client,inbuf, SMB_SECONDARY_WAIT*1000) ||
+ CVAL(inbuf, smb_com) != SMBtrans)
{
DEBUG(2,("Invalid secondary trans2 packet\n"));
if (params) free(params);
@@ -2730,6 +2806,8 @@ int reply_trans(char *inbuf,char *outbuf)
if (setup) free(setup);
return(ERROR(ERRSRV,ERRerror));
}
+
+ show_msg(inbuf);
tpscnt = SVAL(inbuf,smb_vwv0);
tdscnt = SVAL(inbuf,smb_vwv1);
diff --git a/source/smbd/mangle.c b/source/smbd/mangle.c
index 8f1490c528d..177a34c9751 100644
--- a/source/smbd/mangle.c
+++ b/source/smbd/mangle.c
@@ -20,7 +20,6 @@
*/
#include "includes.h"
-#include "loadparm.h"
extern int DEBUGLEVEL;
extern int case_default;
@@ -90,8 +89,6 @@ BOOL is_8_3(char *fname)
if (slash_pos) fname = slash_pos+1;
len = strlen(fname);
- dot_pos = strchr(fname,'.');
-
DEBUG(5,("checking %s for 8.3\n",fname));
if (case_mangle)
@@ -122,6 +119,8 @@ BOOL is_8_3(char *fname)
/* %%% A nice improvment to name mangling would be to translate
filename to ANSI charset on the smb server host */
+ dot_pos = strchr(fname,'.');
+
{
char *p = fname;
#ifdef KANJI
@@ -510,9 +509,36 @@ void mangle_name_83(char *s)
*p++ = 0;
while (*p && extlen < 3)
{
+#ifdef KANJI
+ if (is_shift_jis (*p))
+ {
+ if (extlen < 2)
+ {
+ extension[extlen++] = p[0];
+ extension[extlen++] = p[1];
+ }
+ else
+ {
+ extension[extlen++] = base36 (((unsigned char) *p) % 36);
+ }
+ p += 2;
+ }
+ else if (is_kana (*p))
+ {
+ extension[extlen++] = p[0];
+ p++;
+ }
+ else
+ {
+ if (isdoschar (*p) && *p != '.')
+ extension[extlen++] = p[0];
+ p++;
+ }
+#else
if (isdoschar(*p) && *p != '.')
extension[extlen++] = *p;
p++;
+#endif /* KANJI */
}
extension[extlen] = 0;
}
@@ -522,9 +548,36 @@ void mangle_name_83(char *s)
while (*p && baselen < 5)
{
+#ifdef KANJI
+ if (is_shift_jis (*p))
+ {
+ if (baselen < 4)
+ {
+ base[baselen++] = p[0];
+ base[baselen++] = p[1];
+ }
+ else
+ {
+ base[baselen++] = base36 (((unsigned char) *p) % 36);
+ }
+ p += 2;
+ }
+ else if (is_kana (*p))
+ {
+ base[baselen++] = p[0];
+ p++;
+ }
+ else
+ {
+ if (isdoschar (*p) && *p != '.')
+ base[baselen++] = p[0];
+ p++;
+ }
+#else
if (isdoschar(*p) && *p != '.')
base[baselen++] = *p;
p++;
+#endif /* KANJI */
}
base[baselen] = 0;
diff --git a/source/smbd/message.c b/source/smbd/message.c
index 6a96b4c7a9c..b26a6605ed5 100644
--- a/source/smbd/message.c
+++ b/source/smbd/message.c
@@ -25,7 +25,6 @@
#include "includes.h"
-#include "loadparm.h"
/* look in server.c for some explanation of these variables */
extern int DEBUGLEVEL;
diff --git a/source/smbd/password.c b/source/smbd/password.c
index 87c1fef94c5..a5f597682f6 100644
--- a/source/smbd/password.c
+++ b/source/smbd/password.c
@@ -20,7 +20,6 @@
*/
#include "includes.h"
-#include "loadparm.h"
extern int DEBUGLEVEL;
extern int Protocol;
@@ -43,7 +42,6 @@ Get the next challenge value - no repeats.
********************************************************************/
void generate_next_challenge(char *challenge)
{
- extern void E1(char *,char *,char *);
static int counter = 0;
struct timeval tval;
int v1,v2;
@@ -52,7 +50,7 @@ void generate_next_challenge(char *challenge)
v2 = (counter++) * getpid() + tval.tv_usec;
SIVAL(challenge,0,v1);
SIVAL(challenge,4,v2);
- E1(challenge,"SAMBA",saved_challenge);
+ E1(challenge,"SAMBA",(char *)saved_challenge);
memcpy(challenge,saved_challenge,8);
challenge_sent = True;
}
@@ -287,15 +285,13 @@ static void update_protected_database( char *user, BOOL result)
#ifdef OSF1_ENH_SEC
struct pr_passwd *mypasswd;
time_t starttime;
- long tz;
mypasswd = getprpwnam (user);
starttime = time (NULL);
- tz = mktime ( localtime ( &starttime ) );
if (result)
{
- mypasswd->ufld.fd_slogin = tz;
+ mypasswd->ufld.fd_slogin = starttime;
mypasswd->ufld.fd_nlogins = 0;
putprpwnam(user,mypasswd);
@@ -304,7 +300,7 @@ static void update_protected_database( char *user, BOOL result)
}
else
{
- mypasswd->ufld.fd_ulogin = tz;
+ mypasswd->ufld.fd_ulogin = starttime;
mypasswd->ufld.fd_nlogins = mypasswd->ufld.fd_nlogins + 1;
if ( mypasswd->ufld.fd_max_tries != 0 && mypasswd->ufld.fd_nlogins > mypasswd->ufld.fd_max_tries )
{
@@ -684,7 +680,9 @@ BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd, BOOL
if(smb_pass->smb_nt_passwd != NULL)
{
DEBUG(4,("Checking NT MD4 password\n"));
- if(smb_password_check(password, smb_pass->smb_nt_passwd, challenge))
+ if(smb_password_check(password,
+ smb_pass->smb_nt_passwd,
+ (char *)challenge))
{
update_protected_database(user,True);
return(True);
@@ -696,11 +694,12 @@ BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd, BOOL
/* Try against the lanman password */
- if(smb_password_check(password, smb_pass->smb_passwd, challenge))
- {
- update_protected_database(user,True);
- return(True);
- }
+ if (smb_password_check(password,
+ smb_pass->smb_passwd,
+ (char *)challenge)) {
+ update_protected_database(user,True);
+ return(True);
+ }
DEBUG(3,("Error smb_password_check failed\n"));
}
@@ -1153,13 +1152,12 @@ static BOOL check_user_equiv(char *user, char *remote, char *equiv_file)
BOOL host_ok = False;
#ifdef NETGROUP
- /* THIS IS UNTESTED!! */
if (is_group)
{
static char *mydomain = NULL;
if (!mydomain)
yp_get_default_domain(&mydomain);
- if (mydomain && innetgr(remote,file_host,user,mydomain))
+ if (mydomain && innetgr(file_host,remote,user,mydomain))
host_ok = True;
}
#else
@@ -1242,7 +1240,7 @@ BOOL check_hosts_equiv(char *user)
}
-static int password_client = -1;
+int password_client = -1;
static fstring pserver;
/****************************************************************************
@@ -1257,8 +1255,7 @@ BOOL server_cryptkey(char *buf)
int len;
fstring desthost;
struct in_addr dest_ip;
- extern struct in_addr myip;
- int port = 139;
+ int port = SMB_PORT;
BOOL ret;
if (password_client >= 0)
@@ -1285,7 +1282,7 @@ BOOL server_cryptkey(char *buf)
continue;
}
- if (memcmp(&dest_ip,&myip,sizeof(dest_ip)) == 0) {
+ if (ismyip(dest_ip)) {
DEBUG(1,("Password server loop - disabling password server %s\n",p));
continue;
}
@@ -1321,9 +1318,10 @@ BOOL server_cryptkey(char *buf)
CVAL(outbuf,0) = 0x81;
send_smb(password_client,outbuf);
- receive_smb(password_client,inbuf,5000);
+
- if (CVAL(inbuf,0) != 0x82) {
+ if (!receive_smb(password_client,inbuf,5000) ||
+ CVAL(inbuf,0) != 0x82) {
DEBUG(1,("%s rejected the session\n",pserver));
close(password_client); password_client = -1;
return(False);
@@ -1406,7 +1404,7 @@ BOOL server_validate(char *buf)
DEBUG(3,("password server %s accepted the password\n",pserver));
-#ifndef KEEP_PASSWORD_SERVER_OPEN
+#if !KEEP_PASSWORD_SERVER_OPEN
close(password_client); password_client= -1;
#endif
diff --git a/source/smbd/predict.c b/source/smbd/predict.c
new file mode 100644
index 00000000000..7f1692931c9
--- /dev/null
+++ b/source/smbd/predict.c
@@ -0,0 +1,145 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ file read prediction routines
+ Copyright (C) Andrew Tridgell 1992-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 int DEBUGLEVEL;
+
+
+/* variables used by the read prediction module */
+static int rp_fd = -1;
+static int rp_offset = 0;
+static int rp_length = 0;
+static int rp_alloced = 0;
+static int rp_predict_fd = -1;
+static int rp_predict_offset = 0;
+static int rp_predict_length = 0;
+static int rp_timeout = 5;
+static time_t rp_time = 0;
+static char *rp_buffer = NULL;
+static BOOL predict_skip=False;
+time_t smb_last_time=(time_t)0;
+
+/****************************************************************************
+handle read prediction on a file
+****************************************************************************/
+int read_predict(int fd,int offset,char *buf,char **ptr,int num)
+{
+ int ret = 0;
+ int possible = rp_length - (offset - rp_offset);
+
+ possible = MIN(possible,num);
+
+ /* give data if possible */
+ if (fd == rp_fd &&
+ offset >= rp_offset &&
+ possible>0 &&
+ smb_last_time-rp_time < rp_timeout)
+ {
+ ret = possible;
+ if (buf)
+ memcpy(buf,rp_buffer + (offset-rp_offset),possible);
+ else
+ *ptr = rp_buffer + (offset-rp_offset);
+ DEBUG(5,("read-prediction gave %d bytes of %d\n",ret,num));
+ }
+
+ if (ret == num) {
+ predict_skip = True;
+ } else {
+ predict_skip = False;
+
+ /* prepare the next prediction */
+ rp_predict_fd = fd;
+ rp_predict_offset = offset + num;
+ rp_predict_length = num;
+ }
+
+ if (ret < 0) ret = 0;
+
+ return(ret);
+}
+
+/****************************************************************************
+pre-read some data
+****************************************************************************/
+void do_read_prediction()
+{
+ static int readsize = 0;
+
+ if (predict_skip) return;
+
+ if (rp_predict_fd == -1)
+ return;
+
+ rp_fd = rp_predict_fd;
+ rp_offset = rp_predict_offset;
+ rp_length = 0;
+
+ rp_predict_fd = -1;
+
+ if (readsize == 0) {
+ readsize = lp_readsize();
+ readsize = MAX(readsize,1024);
+ }
+
+ rp_predict_length = MIN(rp_predict_length,2*readsize);
+ rp_predict_length = MAX(rp_predict_length,1024);
+ rp_offset = (rp_offset/1024)*1024;
+ rp_predict_length = (rp_predict_length/1024)*1024;
+
+ if (rp_predict_length > rp_alloced)
+ {
+ rp_buffer = Realloc(rp_buffer,rp_predict_length);
+ rp_alloced = rp_predict_length;
+ if (!rp_buffer)
+ {
+ DEBUG(0,("can't allocate read-prediction buffer\n"));
+ rp_predict_fd = -1;
+ rp_fd = -1;
+ rp_alloced = 0;
+ return;
+ }
+ }
+
+ if (lseek(rp_fd,rp_offset,SEEK_SET) != rp_offset) {
+ rp_fd = -1;
+ rp_predict_fd = -1;
+ return;
+ }
+
+ rp_length = read(rp_fd,rp_buffer,rp_predict_length);
+ rp_time = time(NULL);
+ if (rp_length < 0)
+ rp_length = 0;
+}
+
+/****************************************************************************
+invalidate read-prediction on a fd
+****************************************************************************/
+void invalidate_read_prediction(int fd)
+{
+ if (rp_fd == fd)
+ rp_fd = -1;
+ if (rp_predict_fd == fd)
+ rp_predict_fd = -1;
+}
+
diff --git a/source/smbd/quotas.c b/source/smbd/quotas.c
new file mode 100644
index 00000000000..6ba20faa6cd
--- /dev/null
+++ b/source/smbd/quotas.c
@@ -0,0 +1,441 @@
+#ifdef QUOTAS
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ support for quotas
+ Copyright (C) Andrew Tridgell 1992-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.
+*/
+
+
+/*
+ * This is one of the most system dependent parts of Samba, and its
+ * done a litle differently. Each system has its own way of doing
+ * things :-(
+ */
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+#ifdef LINUX
+
+#ifdef __KERNEL__
+# undef __KERNEL__
+# include <sys/quota.h>
+# define __KERNEL__
+#else
+# include <sys/quota.h>
+#endif
+
+#include <mntent.h>
+
+/****************************************************************************
+try to get the disk space from disk quotas (LINUX version)
+****************************************************************************/
+/*
+If you didn't make the symlink to the quota package, too bad :(
+*/
+#include "quota/quotactl.c"
+#include "quota/hasquota.c"
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
+{
+ uid_t euser_id;
+ struct dqblk D;
+ struct stat S;
+ dev_t devno ;
+ struct mntent *mnt;
+ FILE *fp;
+ int found ;
+ int qcmd, fd ;
+ char *qfpathname;
+
+ /* find the block device file */
+
+ if ( stat(path, &S) == -1 )
+ return(False) ;
+
+ devno = S.st_dev ;
+
+ fp = setmntent(MOUNTED,"r");
+ found = False ;
+
+ while ((mnt = getmntent(fp)) != (struct mntent *) 0) {
+ if ( stat(mnt->mnt_dir,&S) == -1 )
+ continue ;
+ if (S.st_dev == devno) {
+ found = True ;
+ break ;
+ }
+ }
+ endmntent(fp) ;
+
+ if ( ! found )
+ return(False) ;
+
+ qcmd = QCMD(Q_GETQUOTA, USRQUOTA);
+
+ if (hasmntopt(mnt, MNTOPT_NOAUTO) || hasmntopt(mnt, MNTOPT_NOQUOTA))
+ return(False) ;
+
+ if (!hasquota(mnt, USRQUOTA, &qfpathname))
+ return(False) ;
+
+ euser_id = geteuid();
+ seteuid(0);
+
+ if (quotactl(qcmd, mnt->mnt_fsname, euser_id, (caddr_t)&D) != 0) {
+ if ((fd = open(qfpathname, O_RDONLY)) < 0) {
+ seteuid(euser_id);
+ return(False);
+ }
+ lseek(fd, (long) dqoff(euser_id), L_SET);
+ switch (read(fd, &D, sizeof(struct dqblk))) {
+ case 0:/* EOF */
+ memset((caddr_t)&D, 0, sizeof(struct dqblk));
+ break;
+ case sizeof(struct dqblk): /* OK */
+ break;
+ default: /* ERROR */
+ close(fd);
+ seteuid(euser_id);
+ return(False);
+ }
+ }
+ seteuid(euser_id);
+ *bsize=1024;
+
+ if (D.dqb_bsoftlimit==0)
+ return(False);
+ if ((D.dqb_curblocks>D.dqb_bsoftlimit)||(D.dqb_curinodes>D.dqb_isoftlimit))
+ {
+ *dfree = 0;
+ *dsize = D.dqb_curblocks;
+ }
+ else {
+ *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
+ *dsize = D.dqb_bsoftlimit;
+ }
+ return (True);
+}
+
+#elif defined(CRAY)
+
+#include <sys/quota.h>
+#include <mntent.h>
+
+/****************************************************************************
+try to get the disk space from disk quotas (CRAY VERSION)
+****************************************************************************/
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
+{
+ struct mntent *mnt;
+ FILE *fd;
+ struct stat sbuf;
+ dev_t devno ;
+ static dev_t devno_cached = 0 ;
+ static char name[MNTMAXSTR] ;
+ struct q_request request ;
+ struct qf_header header ;
+ static int quota_default = 0 ;
+ int found ;
+
+ if ( stat(path,&sbuf) == -1 )
+ return(False) ;
+
+ devno = sbuf.st_dev ;
+
+ if ( devno != devno_cached ) {
+
+ devno_cached = devno ;
+
+ if ((fd = setmntent(KMTAB)) == NULL)
+ return(False) ;
+
+ found = False ;
+
+ while ((mnt = getmntent(fd)) != NULL) {
+
+ if ( stat(mnt->mnt_dir,&sbuf) == -1 )
+ continue ;
+
+ if (sbuf.st_dev == devno) {
+
+ found = True ;
+ break ;
+
+ }
+
+ }
+
+ strcpy(name,mnt->mnt_dir) ;
+ endmntent(fd) ;
+
+ if ( ! found )
+ return(False) ;
+ }
+
+ request.qf_magic = QF_MAGIC ;
+ request.qf_entry.id = geteuid() ;
+
+ if (quotactl(name, Q_GETQUOTA, &request) == -1)
+ return(False) ;
+
+ if ( ! request.user )
+ return(False) ;
+
+ if ( request.qf_entry.user_q.f_quota == QFV_DEFAULT ) {
+
+ if ( ! quota_default ) {
+
+ if ( quotactl(name, Q_GETHEADER, &header) == -1 )
+ return(False) ;
+ else
+ quota_default = header.user_h.def_fq ;
+ }
+
+ *dfree = quota_default ;
+
+ }else if ( request.qf_entry.user_q.f_quota == QFV_PREVENT ) {
+
+ *dfree = 0 ;
+
+ }else{
+
+ *dfree = request.qf_entry.user_q.f_quota ;
+
+ }
+
+ *dsize = request.qf_entry.user_q.f_use ;
+
+ if ( *dfree )
+ *dfree -= *dsize ;
+
+ if ( *dfree < 0 )
+ *dfree = 0 ;
+
+ *bsize = 4096 ; /* Cray blocksize */
+
+ return(True) ;
+
+}
+
+
+#elif defined(SUNOS5) || defined(SUNOS4)
+
+#include <fcntl.h>
+#if defined(SUNOS5)
+#include <sys/fs/ufs_quota.h>
+#include <sys/mnttab.h>
+#else /* defined(SUNOS4) */
+#include <ufs/quota.h>
+#include <mntent.h>
+#endif
+
+/****************************************************************************
+try to get the disk space from disk quotas (solaris 2 version)
+****************************************************************************/
+/* Quota code by Peter Urbanec (amiga@cse.unsw.edu.au) */
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
+{
+ uid_t user_id, euser_id;
+ int ret;
+ struct dqblk D;
+#if defined(SUNOS5)
+ struct quotctl command;
+ int file;
+ struct mnttab mnt;
+ static char name[MNT_LINE_MAX] ;
+#else
+ struct mntent *mnt;
+ static char name[MNTMAXSTR] ;
+#endif
+ FILE *fd;
+ struct stat sbuf;
+ dev_t devno ;
+ static dev_t devno_cached = 0 ;
+ int found ;
+
+ if ( stat(path,&sbuf) == -1 )
+ return(False) ;
+
+ devno = sbuf.st_dev ;
+ DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%o\n", path,devno));
+ if ( devno != devno_cached ) {
+ devno_cached = devno ;
+#if defined(SUNOS5)
+ if ((fd = fopen(MNTTAB, "r")) == NULL)
+ return(False) ;
+
+ found = False ;
+ while (getmntent(fd, &mnt) == 0) {
+ if ( stat(mnt.mnt_mountp,&sbuf) == -1 )
+ continue ;
+ DEBUG(5,("disk_quotas: testing \"%s\" devno=%o\n",
+ mnt.mnt_mountp,sbuf.st_dev));
+ if (sbuf.st_dev == devno) {
+ found = True ;
+ break ;
+ }
+ }
+
+ strcpy(name,mnt.mnt_mountp) ;
+ strcat(name,"/quotas") ;
+ fclose(fd) ;
+#else
+ if ((fd = setmntent(MOUNTED, "r")) == NULL)
+ return(False) ;
+
+ found = False ;
+ while ((mnt = getmntent(fd)) != NULL) {
+ if ( stat(mnt->mnt_dir,&sbuf) == -1 )
+ continue ;
+ DEBUG(5,("disk_quotas: testing \"%s\" devno=%o\n",
+ mnt->mnt_dir,sbuf.st_dev));
+ if (sbuf.st_dev == devno) {
+ found = True ;
+ break ;
+ }
+ }
+
+ strcpy(name,mnt->mnt_fsname) ;
+ endmntent(fd) ;
+#endif
+
+ if ( ! found )
+ return(False) ;
+ }
+
+ euser_id = geteuid();
+ user_id = getuid();
+
+ setuid(0); /* Solaris seems to want to give info only to super-user */
+ seteuid(0);
+
+#if defined(SUNOS5)
+ DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
+ if((file=open(name, O_RDONLY))<0) {
+ setuid(user_id); /* Restore the original UID status */
+ seteuid(euser_id);
+ return(False);
+ }
+ command.op = Q_GETQUOTA;
+ command.uid = euser_id;
+ command.addr = (caddr_t) &D;
+ ret = ioctl(file, Q_QUOTACTL, &command);
+ close(file);
+#else
+ DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
+ ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
+#endif
+
+ setuid(user_id); /* Restore the original UID status */
+ seteuid(euser_id);
+
+ if (ret < 0) {
+ DEBUG(2,("disk_quotas ioctl (Solaris) failed\n"));
+ return(False);
+ }
+
+
+ /* Use softlimit to determine disk space. A user exceeding the quota is told
+ * that there's no space left. Writes might actually work for a bit if the
+ * hardlimit is set higher than softlimit. Effectively the disk becomes
+ * made of rubber latex and begins to expand to accommodate the user :-)
+ */
+
+ if (D.dqb_bsoftlimit==0)
+ return(False);
+ *bsize = 512;
+ *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
+ *dsize = D.dqb_bsoftlimit;
+ if(*dfree < 0)
+ {
+ *dfree = 0;
+ *dsize = D.dqb_curblocks;
+ }
+
+DEBUG(5,("disk_quotas for path \"%s\" returning bsize %d, dfree %d, dsize %d\n",
+ path,*bsize,*dfree,*dsize));
+
+ return(True);
+}
+
+#else
+
+#include <sys/quota.h>
+#include <devnm.h>
+
+/****************************************************************************
+try to get the disk space from disk quotas - default version
+****************************************************************************/
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
+{
+ uid_t user_id, euser_id;
+ int r;
+ char dev_disk[256];
+ struct dqblk D;
+ struct stat S;
+ /* find the block device file */
+ if ((stat(path, &S)<0) ||
+ (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0)) return (False);
+
+ euser_id = geteuid();
+
+#ifdef USE_SETRES
+ /* for HPUX, real uid must be same as euid to execute quotactl for euid */
+ user_id = getuid();
+ setresuid(euser_id,-1,-1);
+#endif
+ r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
+ #ifdef USE_SETRES
+ if (setresuid(user_id,-1,-1))
+ DEBUG(5,("Unable to reset uid to %d\n", user_id));
+ #endif
+ /* Use softlimit to determine disk space, except when it has been exceeded */
+ *bsize = 1024;
+ if (r)
+ {
+ if (errno == EDQUOT)
+ {
+ *dfree =0;
+ *dsize =D.dqb_curblocks;
+ return (True);
+ }
+ else return(False);
+ }
+ if (D.dqb_bsoftlimit==0)
+ return(False);
+ /* Use softlimit to determine disk space, except when it has been exceeded */
+ if ((D.dqb_curblocks>D.dqb_bsoftlimit)||(D.dqb_curfiles>D.dqb_fsoftlimit))
+ {
+ *dfree = 0;
+ *dsize = D.dqb_curblocks;
+ }
+ else {
+ *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
+ *dsize = D.dqb_bsoftlimit;
+ }
+ return (True);
+}
+
+#endif
+
+#else
+/* this keeps fussy compilers happy */
+ void quotas_dummy(void) {}
+#endif /* QUOTAS */
+
diff --git a/source/smbd/reply.c b/source/smbd/reply.c
index b7b51775bb8..d463b305c9c 100644
--- a/source/smbd/reply.c
+++ b/source/smbd/reply.c
@@ -25,7 +25,6 @@
#include "includes.h"
-#include "loadparm.h"
#include "trans2.h"
/* look in server.c for some explanation of these variables */
@@ -334,11 +333,13 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
StrnCpy(smb_apasswd,p + passlen1,smb_apasslen);
}
}
+#if NT_WORKAROUND
if (passlen2 == 1) {
/* apparently NT sometimes sets passlen2 to 1 when it means 0. This
tries to work around that problem */
passlen2 = 0;
}
+#endif
p += passlen1 + passlen2;
strcpy(user,p); p = skip_string(p,1);
DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s]\n",
@@ -1179,7 +1180,9 @@ static BOOL can_delete(char *fname,int cnum,int dirtype)
if (sys_lstat(fname,&sbuf) != 0) return(False);
fmode = dos_mode(cnum,fname,&sbuf);
if (fmode & aDIR) return(False);
- if (fmode & aRONLY) return(False);
+ if (!lp_delete_readonly(SNUM(cnum))) {
+ if (fmode & aRONLY) return(False);
+ }
if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM))
return(False);
if (!check_file_sharing(cnum,fname)) return(False);
@@ -1360,7 +1363,7 @@ int reply_readbraw(char *inbuf, char *outbuf)
fname,startpos,nread,ret));
#else
- ret = read_file(fnum,header+4,startpos,nread,nread,-1,False);
+ ret = read_file(fnum,header+4,startpos,nread);
if (ret < mincount) ret = 0;
_smb_setlen(header,ret);
@@ -1402,7 +1405,7 @@ int reply_lockread(char *inbuf,char *outbuf)
if(!do_lock( fnum, cnum, numtoread, startpos, &eclass, &ecode))
return (ERROR(eclass,ecode));
- nread = read_file(fnum,data,startpos,numtoread,numtoread,-1,False);
+ nread = read_file(fnum,data,startpos,numtoread);
if (nread < 0)
return(UNIXERROR(ERRDOS,ERRnoaccess));
@@ -1447,7 +1450,7 @@ int reply_read(char *inbuf,char *outbuf)
return(ERROR(ERRDOS,ERRlock));
if (numtoread > 0)
- nread = read_file(fnum,data,startpos,numtoread,numtoread,-1,False);
+ nread = read_file(fnum,data,startpos,numtoread);
if (nread < 0)
return(UNIXERROR(ERRDOS,ERRnoaccess));
@@ -1492,7 +1495,7 @@ int reply_read_and_X(char *inbuf,char *outbuf,int length,int bufsize)
if (is_locked(fnum,cnum,smb_maxcnt,smb_offs))
return(ERROR(ERRDOS,ERRlock));
- nread = read_file(fnum,data,smb_offs,smb_maxcnt,smb_maxcnt,-1,False);
+ nread = read_file(fnum,data,smb_offs,smb_maxcnt);
ok = True;
if (nread < 0)
@@ -1587,7 +1590,7 @@ int reply_writebraw(char *inbuf,char *outbuf)
send_smb(Client,outbuf);
/* Now read the raw data into the buffer and write it */
- if(read_smb_length(Client,inbuf,0) == -1) {
+ if (read_smb_length(Client,inbuf,SMB_SECONDARY_WAIT) == -1) {
exit_server("secondary writebraw failed");
}
@@ -1924,11 +1927,11 @@ int reply_close(char *inbuf,char *outbuf)
mtime = make_unix_date3(inbuf+smb_vwv1);
- close_file(fnum);
-
/* try and set the date */
set_filetime(Files[fnum].name,mtime);
+ close_file(fnum);
+
/* We have a cached error */
if(eclass || err)
return(ERROR(eclass,err));
@@ -1972,10 +1975,10 @@ int reply_writeclose(char *inbuf,char *outbuf)
nwritten = write_file(fnum,data,numtowrite);
- close_file(fnum);
-
set_filetime(Files[fnum].name,mtime);
+ close_file(fnum);
+
DEBUG(3,("%s writeclose fnum=%d cnum=%d num=%d wrote=%d (numopen=%d)\n",
timestring(),fnum,cnum,numtowrite,nwritten,
Connections[cnum].num_files_open));
@@ -2059,6 +2062,11 @@ int reply_tdis(char *inbuf,char *outbuf)
cnum = SVAL(inbuf,smb_tid);
uid = SVAL(inbuf,smb_uid);
+ if (!OPEN_CNUM(cnum)) {
+ DEBUG(4,("Invalid cnum in tdis (%d)\n",cnum));
+ return(ERROR(ERRSRV,ERRinvnid));
+ }
+
Connections[cnum].used = False;
close_cnum(cnum,uid);
@@ -2926,7 +2934,7 @@ int reply_readbmpx(char *inbuf,char *outbuf,int length,int bufsize)
{
int N = MIN(max_per_packet,tcount-total_read);
- nread = read_file(fnum,data,startpos,N,N,-1,False);
+ nread = read_file(fnum,data,startpos,N);
if (nread <= 0) nread = 0;
diff --git a/source/smbd/server.c b/source/smbd/server.c
index 5d8facef33f..334edf77d0e 100644
--- a/source/smbd/server.c
+++ b/source/smbd/server.c
@@ -20,13 +20,9 @@
*/
#include "includes.h"
-#include "loadparm.h"
-#include "pcap.h"
#include "trans2.h"
-#include "reply.h"
pstring servicesf = CONFIGFILE;
-pstring OriginalDir ="/";
extern pstring debugf;
extern pstring sesssetup_user;
@@ -34,16 +30,8 @@ char *InBuffer = NULL;
char *OutBuffer = NULL;
char *last_inbuf = NULL;
-int initial_uid = 0;
-int initial_gid = 0;
-
BOOL share_mode_pending = False;
-/* have I done a become_user? */
-static struct {
- int cnum, uid;
-} last_user;
-
/* the last message the was processed */
int last_message = -1;
@@ -60,6 +48,8 @@ extern BOOL short_case_preserve;
extern BOOL case_mangle;
extern time_t smb_last_time;
+extern int smb_read_error;
+
extern pstring user_socket_options;
connection_struct Connections[MAX_CONNECTIONS];
@@ -88,16 +78,9 @@ int unix_ERR_code=0;
extern int extra_time_offset;
extern pstring myhostname;
-extern struct in_addr myip;
-
static int find_free_connection(int hash);
-#ifdef SMB_PASSWD
-extern void generate_next_challenge(char *challenge);
-extern void set_challenge(char *challenge);
-#endif
-
/* for readability... */
#define IS_DOS_READONLY(test_mode) (((test_mode) & aRONLY) != 0)
#define IS_DOS_DIR(test_mode) (((test_mode) & aDIR) != 0)
@@ -148,31 +131,20 @@ mode_t unix_mode(int cnum,int dosmode)
int dos_mode(int cnum,char *path,struct stat *sbuf)
{
int result = 0;
+ extern struct current_user current_user;
-#if OLD_DOS_MODE
- if (!CAN_WRITE(cnum) || !((sbuf->st_mode & S_IWOTH) ||
- Connections[cnum].admin_user ||
- ((sbuf->st_mode & S_IWUSR) &&
- Connections[cnum].uid==sbuf->st_uid) ||
- ((sbuf->st_mode & S_IWGRP) &&
- in_group(sbuf->st_gid,Connections[cnum].gid,
- Connections[cnum].ngroups,
- Connections[cnum].igroups))))
- result |= aRONLY;
-#else
if (CAN_WRITE(cnum) && !lp_alternate_permissions(SNUM(cnum))) {
if (!((sbuf->st_mode & S_IWOTH) ||
Connections[cnum].admin_user ||
- ((sbuf->st_mode & S_IWUSR) && Connections[cnum].uid==sbuf->st_uid) ||
+ ((sbuf->st_mode & S_IWUSR) && current_user.uid==sbuf->st_uid) ||
((sbuf->st_mode & S_IWGRP) &&
- in_group(sbuf->st_gid,Connections[cnum].gid,
- Connections[cnum].ngroups,Connections[cnum].igroups))))
+ in_group(sbuf->st_gid,current_user.gid,
+ current_user.ngroups,current_user.igroups))))
result |= aRONLY;
} else {
if ((sbuf->st_mode & S_IWUSR) == 0)
result |= aRONLY;
}
-#endif
if ((sbuf->st_mode & S_IXUSR) != 0)
result |= aARCH;
@@ -257,8 +229,8 @@ int dos_chmod(int cnum,char *fname,int dosmode,struct stat *st)
unixmode &= ~(S_IWUSR|S_IWGRP|S_IWOTH);
unixmode |= tmp;
}
-
- return(chmod(fname,unixmode));
+
+ return(sys_chmod(fname,unixmode));
}
@@ -326,7 +298,7 @@ static BOOL scan_directory(char *path, char *name,int snum,BOOL docache)
void *cur_dir;
char *dname;
BOOL mangled;
- fstring name2;
+ pstring name2;
mangled = is_mangled(name);
@@ -410,8 +382,12 @@ BOOL unix_convert(char *name,int cnum)
{
if ((! *name) || strchr(name,'/') || !is_8_3(name))
{
+ char *s;
fstring name2;
sprintf(name2,"%.6s.XXXXXX",remote_machine);
+ /* sanitise the name */
+ for (s=name2 ; *s ; s++)
+ if (!issafe(*s)) *s = '_';
strcpy(name,(char *)mktemp(name2));
}
return(True);
@@ -522,251 +498,6 @@ BOOL unix_convert(char *name,int cnum)
}
-
-
-#ifdef QUOTAS
-#ifdef LINUX
-/****************************************************************************
-try to get the disk space from disk quotas (LINUX version)
-****************************************************************************/
-/*
-If you didn't make the symlink to the quota package, too bad :(
-*/
-#include "quota/quotactl.c"
-#include "quota/hasquota.c"
-static BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
-{
- uid_t euser_id;
- struct dqblk D;
- struct stat S;
- dev_t devno ;
- struct mntent *mnt;
- FILE *fp;
- int found ;
- int qcmd, fd ;
- char *qfpathname;
-
- /* find the block device file */
-
- if ( stat(path, &S) == -1 )
- return(False) ;
-
- devno = S.st_dev ;
-
- fp = setmntent(MOUNTED,"r");
- found = False ;
-
- while ((mnt = getmntent(fp)) != (struct mntent *) 0) {
- if ( stat(mnt->mnt_dir,&S) == -1 )
- continue ;
- if (S.st_dev == devno) {
- found = True ;
- break ;
- }
- }
- endmntent(fp) ;
-
- if ( ! found )
- return(False) ;
-
- qcmd = QCMD(Q_GETQUOTA, USRQUOTA);
-
- if (hasmntopt(mnt, MNTOPT_NOAUTO) || hasmntopt(mnt, MNTOPT_NOQUOTA))
- return(False) ;
-
- if (!hasquota(mnt, USRQUOTA, &qfpathname))
- return(False) ;
-
- euser_id = geteuid();
- seteuid(0);
-
- if (quotactl(qcmd, mnt->mnt_fsname, euser_id, (caddr_t)&D) != 0) {
- if ((fd = open(qfpathname, O_RDONLY)) < 0) {
- seteuid(euser_id);
- return(False);
- }
- lseek(fd, (long) dqoff(euser_id), L_SET);
- switch (read(fd, &D, sizeof(struct dqblk))) {
- case 0:/* EOF */
- memset((caddr_t)&D, 0, sizeof(struct dqblk));
- break;
- case sizeof(struct dqblk): /* OK */
- break;
- default: /* ERROR */
- close(fd);
- seteuid(euser_id);
- return(False);
- }
- }
- seteuid(euser_id);
- *bsize=1024;
-
- if (D.dqb_bsoftlimit==0)
- return(False);
- if ((D.dqb_curblocks>D.dqb_bsoftlimit)||(D.dqb_curinodes>D.dqb_isoftlimit))
- {
- *dfree = 0;
- *dsize = D.dqb_curblocks;
- }
- else {
- *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
- *dsize = D.dqb_bsoftlimit;
- }
- return (True);
-}
-#else
-#ifndef CRAY
-/****************************************************************************
-try to get the disk space from disk quotas
-****************************************************************************/
-static BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
-{
- uid_t user_id, euser_id;
- int r;
- char dev_disk[256];
- struct dqblk D;
- struct stat S;
- /* find the block device file */
- if ((stat(path, &S)<0) ||
- (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0)) return (False);
-
- euser_id = geteuid();
-
-#ifdef USE_SETRES
- /* for HPUX, real uid must be same as euid to execute quotactl for euid */
- user_id = getuid();
- setresuid(euser_id,-1,-1);
-#endif
- r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
- #ifdef USE_SETRES
- if (setresuid(user_id,-1,-1))
- DEBUG(5,("Unable to reset uid to %d\n", user_id));
- #endif
- /* Use softlimit to determine disk space, except when it has been exceeded */
- *bsize = 1024;
- if (r)
- {
- if (errno == EDQUOT)
- {
- *dfree =0;
- *dsize =D.dqb_curblocks;
- return (True);
- }
- else return(False);
- }
- /* Use softlimit to determine disk space, except when it has been exceeded */
- if ((D.dqb_curblocks>D.dqb_bsoftlimit)||(D.dqb_curfiles>D.dqb_fsoftlimit))
- {
- *dfree = 0;
- *dsize = D.dqb_curblocks;
- }
- else {
- *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
- *dsize = D.dqb_bsoftlimit;
- }
- return (True);
-}
-#else
-/****************************************************************************
-try to get the disk space from disk quotas (CRAY VERSION)
-****************************************************************************/
-static BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
-{
- struct mntent *mnt;
- FILE *fd;
- struct stat sbuf;
- dev_t devno ;
- static dev_t devno_cached = 0 ;
- static char name[MNTMAXSTR] ;
- struct q_request request ;
- struct qf_header header ;
- static int quota_default = 0 ;
- int found ;
-
- if ( stat(path,&sbuf) == -1 )
- return(False) ;
-
- devno = sbuf.st_dev ;
-
- if ( devno != devno_cached ) {
-
- devno_cached = devno ;
-
- if ((fd = setmntent(KMTAB)) == NULL)
- return(False) ;
-
- found = False ;
-
- while ((mnt = getmntent(fd)) != NULL) {
-
- if ( stat(mnt->mnt_dir,&sbuf) == -1 )
- continue ;
-
- if (sbuf.st_dev == devno) {
-
- found = True ;
- break ;
-
- }
-
- }
-
- strcpy(name,mnt->mnt_dir) ;
- endmntent(fd) ;
-
- if ( ! found )
- return(False) ;
- }
-
- request.qf_magic = QF_MAGIC ;
- request.qf_entry.id = geteuid() ;
-
- if (quotactl(name, Q_GETQUOTA, &request) == -1)
- return(False) ;
-
- if ( ! request.user )
- return(False) ;
-
- if ( request.qf_entry.user_q.f_quota == QFV_DEFAULT ) {
-
- if ( ! quota_default ) {
-
- if ( quotactl(name, Q_GETHEADER, &header) == -1 )
- return(False) ;
- else
- quota_default = header.user_h.def_fq ;
- }
-
- *dfree = quota_default ;
-
- }else if ( request.qf_entry.user_q.f_quota == QFV_PREVENT ) {
-
- *dfree = 0 ;
-
- }else{
-
- *dfree = request.qf_entry.user_q.f_quota ;
-
- }
-
- *dsize = request.qf_entry.user_q.f_use ;
-
- if ( *dfree )
- *dfree -= *dsize ;
-
- if ( *dfree < 0 )
- *dfree = 0 ;
-
- *bsize = 4096 ; /* Cray blocksize */
-
- return(True) ;
-
-}
-#endif /* CRAY */
-#endif /* LINUX */
-#endif /* QUOTAS */
-
-
/****************************************************************************
normalise for DOS usage
****************************************************************************/
@@ -1227,16 +958,6 @@ void close_file(int fnum)
if (lp_share_modes(SNUM(cnum)))
del_share_mode(fnum);
- if (Files[fnum].modified) {
- struct stat st;
- if (fstat(Files[fnum].fd,&st) == 0) {
- int dosmode = dos_mode(cnum,Files[fnum].name,&st);
- if (!IS_DOS_ARCHIVE(dosmode)) {
- dos_chmod(cnum,Files[fnum].name,dosmode | aARCH,&st);
- }
- }
- }
-
close(Files[fnum].fd);
/* NT uses smbclose to start a print - weird */
@@ -1544,41 +1265,35 @@ int seek_file(int fnum,int pos)
/****************************************************************************
read from a file
****************************************************************************/
-int read_file(int fnum,char *data,int pos,int mincnt,int maxcnt,int timeout,BOOL exact)
+int read_file(int fnum,char *data,int pos,int n)
{
- int ret=0;
+ int ret=0,readret;
if (!Files[fnum].can_write)
{
- ret = read_predict(Files[fnum].fd,
- pos,
- data,
- NULL,
- maxcnt);
+ ret = read_predict(Files[fnum].fd,pos,data,NULL,n);
data += ret;
- maxcnt -= ret;
- mincnt = MAX(mincnt-ret,0);
+ n -= ret;
pos += ret;
}
#if USE_MMAP
if (Files[fnum].mmap_ptr)
{
- int num = MIN(maxcnt,Files[fnum].mmap_size-pos);
+ int num = MIN(n,Files[fnum].mmap_size-pos);
if (num > 0)
{
memcpy(data,Files[fnum].mmap_ptr+pos,num);
data += num;
pos += num;
- maxcnt -= num;
- mincnt = MAX(mincnt-num,0);
+ n -= num;
ret += num;
}
}
#endif
- if (maxcnt <= 0)
+ if (n <= 0)
return(ret);
if (seek_file(fnum,pos) != pos)
@@ -1587,13 +1302,10 @@ int read_file(int fnum,char *data,int pos,int mincnt,int maxcnt,int timeout,BOOL
return(ret);
}
- if (maxcnt > 0)
- ret += read_with_timeout(Files[fnum].fd,
- data,
- mincnt,
- maxcnt,
- timeout,
- exact);
+ if (n > 0) {
+ readret = read(Files[fnum].fd,data,n);
+ if (readret > 0) ret += readret;
+ }
return(ret);
}
@@ -1609,14 +1321,21 @@ int write_file(int fnum,char *data,int n)
return(0);
}
- Files[fnum].modified = True;
+ if (!Files[fnum].modified) {
+ struct stat st;
+ Files[fnum].modified = True;
+ if (fstat(Files[fnum].fd,&st) == 0) {
+ int dosmode = dos_mode(Files[fnum].cnum,Files[fnum].name,&st);
+ if (MAP_ARCHIVE(Files[fnum].cnum) && !IS_DOS_ARCHIVE(dosmode)) {
+ dos_chmod(Files[fnum].cnum,Files[fnum].name,dosmode | aARCH,&st);
+ }
+ }
+ }
return(write_data(Files[fnum].fd,data,n));
}
-static int old_umask = 022;
-
/****************************************************************************
load parameters specific to a connection/service
****************************************************************************/
@@ -1662,261 +1381,6 @@ BOOL become_service(int cnum,BOOL do_chdir)
/****************************************************************************
- become the specified uid
-****************************************************************************/
-static BOOL become_uid(int uid)
-{
- if (initial_uid != 0)
- return(True);
-
-#ifdef AIX
- {
- /* AIX 3 stuff - inspired by a code fragment in wu-ftpd */
- priv_t priv;
-
- priv.pv_priv[0] = 0;
- priv.pv_priv[1] = 0;
- if (setpriv(PRIV_SET|PRIV_INHERITED|PRIV_EFFECTIVE|PRIV_BEQUEATH,
- &priv, sizeof(priv_t)) < 0 ||
- setuidx(ID_REAL|ID_EFFECTIVE, (uid_t)uid) < 0 ||
- seteuid((uid_t)uid) < 0)
- DEBUG(1,("Can't set uid (AIX3)"));
- }
-#endif
-
-#ifdef USE_SETRES
- if (setresuid(-1,uid,-1) != 0)
-#else
- if ((seteuid(uid) != 0) &&
- (setuid(uid) != 0))
-#endif
- {
- DEBUG(0,("Couldn't set uid %d currently set to (%d,%d)\n",
- uid,getuid(), geteuid()));
- if (uid > 32000)
- DEBUG(0,("Looks like your OS doesn't like high uid values - try using a different account\n"));
- return(False);
- }
-
- if (((uid == -1) || (uid == 65535)) && geteuid() != uid)
- {
- DEBUG(0,("Invalid uid -1. perhaps you have a account with uid 65535?\n"));
- return(False);
- }
-
- return(True);
-}
-
-
-/****************************************************************************
- become the specified gid
-****************************************************************************/
-static BOOL become_gid(int gid)
-{
- if (initial_uid != 0)
- return(True);
-
-#ifdef USE_SETRES
- if (setresgid(-1,gid,-1) != 0)
-#else
- if (setgid(gid) != 0)
-#endif
- {
- DEBUG(0,("Couldn't set gid %d currently set to (%d,%d)\n",
- gid,getgid(),getegid()));
- if (gid > 32000)
- DEBUG(0,("Looks like your OS doesn't like high gid values - try using a different account\n"));
- return(False);
- }
-
- return(True);
-}
-
-
-/****************************************************************************
- become the specified uid and gid
-****************************************************************************/
-static BOOL become_id(int uid,int gid)
-{
- return(become_gid(gid) && become_uid(uid));
-}
-
-/****************************************************************************
-become the guest user
-****************************************************************************/
-static BOOL become_guest(void)
-{
- BOOL ret;
- static struct passwd *pass=NULL;
-
- if (initial_uid != 0)
- return(True);
-
- if (!pass)
- pass = Get_Pwnam(lp_guestaccount(-1),True);
- if (!pass) return(False);
-
- ret = become_id(pass->pw_uid,pass->pw_gid);
-
- if (!ret)
- DEBUG(1,("Failed to become guest. Invalid guest account?\n"));
-
- last_user.cnum = -2;
-
- return(ret);
-}
-
-/*******************************************************************
-check if a username is OK
-********************************************************************/
-static BOOL check_user_ok(int cnum,user_struct *vuser,int snum)
-{
- int i;
- for (i=0;i<Connections[cnum].uid_cache.entries;i++)
- if (Connections[cnum].uid_cache.list[i] == vuser->uid) return(True);
-
- if (!user_ok(vuser->name,snum)) return(False);
-
- i = Connections[cnum].uid_cache.entries % UID_CACHE_SIZE;
- Connections[cnum].uid_cache.list[i] = vuser->uid;
-
- if (Connections[cnum].uid_cache.entries < UID_CACHE_SIZE)
- Connections[cnum].uid_cache.entries++;
-
- return(True);
-}
-
-
-/****************************************************************************
- become the user of a connection number
-****************************************************************************/
-BOOL become_user(int cnum, int uid)
-{
- int new_umask;
- user_struct *vuser;
- int snum,gid;
- int ngroups;
- gid_t *groups;
-
- if (last_user.cnum == cnum && last_user.uid == uid) {
- DEBUG(4,("Skipping become_user - already user\n"));
- return(True);
- }
-
- unbecome_user();
-
- if (!OPEN_CNUM(cnum)) {
- DEBUG(2,("Connection %d not open\n",cnum));
- return(False);
- }
-
- snum = Connections[cnum].service;
-
- if (Connections[cnum].force_user ||
- lp_security() == SEC_SHARE ||
- !(vuser = get_valid_user_struct(uid)) ||
- !check_user_ok(cnum,vuser,snum)) {
- uid = Connections[cnum].uid;
- gid = Connections[cnum].gid;
- groups = Connections[cnum].groups;
- ngroups = Connections[cnum].ngroups;
- } else {
- if (!vuser) {
- DEBUG(2,("Invalid vuid used %d\n",uid));
- return(False);
- }
- uid = vuser->uid;
- if(!*lp_force_group(snum))
- gid = vuser->gid;
- else
- gid = Connections[cnum].gid;
- groups = vuser->user_groups;
- ngroups = vuser->user_ngroups;
- }
-
- if (initial_uid == 0)
- {
- if (!become_gid(gid)) return(False);
-
-#ifndef NO_SETGROUPS
- if (!IS_IPC(cnum)) {
- /* groups stuff added by ih/wreu */
- if (ngroups > 0)
- if (setgroups(ngroups,groups)<0)
- DEBUG(0,("setgroups call failed!\n"));
- }
-#endif
-
- if (!Connections[cnum].admin_user && !become_uid(uid))
- return(False);
- }
-
- new_umask = 0777 & ~CREATE_MODE(cnum);
- old_umask = umask(new_umask);
-
- last_user.cnum = cnum;
- last_user.uid = uid;
-
- DEBUG(5,("become_user uid=(%d,%d) gid=(%d,%d) new_umask=0%o\n",
- getuid(),geteuid(),getgid(),getegid(),new_umask));
-
- return(True);
-}
-
-/****************************************************************************
- unbecome the user of a connection number
-****************************************************************************/
-BOOL unbecome_user(void )
-{
- if (last_user.cnum == -1)
- return(False);
-
- ChDir(OriginalDir);
-
- umask(old_umask);
-
- if (initial_uid == 0)
- {
-#ifdef USE_SETRES
- setresuid(-1,getuid(),-1);
- setresgid(-1,getgid(),-1);
-#else
- if (seteuid(initial_uid) != 0)
- setuid(initial_uid);
- setgid(initial_gid);
-#endif
- }
-#ifdef NO_EID
- if (initial_uid == 0)
- DEBUG(2,("Running with no EID\n"));
- initial_uid = getuid();
- initial_gid = getgid();
-#else
- if (geteuid() != initial_uid)
- {
- DEBUG(0,("Warning: You appear to have a trapdoor uid system\n"));
- initial_uid = geteuid();
- }
- if (getegid() != initial_gid)
- {
- DEBUG(0,("Warning: You appear to have a trapdoor gid system\n"));
- initial_gid = getegid();
- }
-#endif
-
- if (ChDir(OriginalDir) != 0)
- DEBUG(0,("%s chdir(%s) failed in unbecome_user\n",
- timestring(),OriginalDir));
-
- DEBUG(5,("unbecome_user now uid=(%d,%d) gid=(%d,%d)\n",
- getuid(),geteuid(),getgid(),getegid()));
-
- last_user.cnum = -1;
-
- return(True);
-}
-
-/****************************************************************************
find a service entry
****************************************************************************/
int find_service(char *service)
@@ -2222,6 +1686,9 @@ static BOOL open_sockets(BOOL is_daemon,int port)
signal(SIGPIPE, SIGNAL_CAST sig_pipe);
signal(SIGCLD, SIGNAL_CAST SIG_DFL);
#endif
+ /* close the listening socket */
+ close(s);
+
/* close our standard file descriptors */
close_low_fds();
@@ -2299,6 +1766,8 @@ BOOL reload_services(BOOL test)
reopen_logs();
+ load_interfaces();
+
{
extern int Client;
if (Client != -1) {
@@ -2633,7 +2102,8 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
if (ChDir(pcon->connectpath) != 0)
{
- DEBUG(0,("Can't change directory to %s\n",pcon->connectpath));
+ DEBUG(0,("Can't change directory to %s (%s)\n",
+ pcon->connectpath,strerror(errno)));
pcon->open = False;
unbecome_user();
if (!IS_IPC(cnum)) {
@@ -2694,6 +2164,8 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
int find_free_file(void )
{
int i;
+ /* we start at 1 here for an obscure reason I can't now remember,
+ but I think is important :-) */
for (i=1;i<MAX_OPEN_FILES;i++)
if (!Files[i].open)
return(i);
@@ -2864,6 +2336,7 @@ int reply_nt1(char *outbuf)
int capabilities=0x300; /* has dual names + lock_and_read */
int secword=0;
BOOL doencrypt = SMBENCRYPT();
+ time_t t = time(NULL);
if (lp_security()>=SEC_USER) secword |= 1;
if (doencrypt) secword |= 2;
@@ -2898,8 +2371,8 @@ int reply_nt1(char *outbuf)
SIVAL(outbuf,smb_vwv3+1,0xFFFF); /* max buffer */
SIVAL(outbuf,smb_vwv5+1,0xFFFF); /* raw size */
SIVAL(outbuf,smb_vwv9+1,capabilities); /* capabilities */
- put_long_date(outbuf+smb_vwv11+1,time(NULL));
- SSVALS(outbuf,smb_vwv15+1,TimeDiff(time(NULL))/60);
+ put_long_date(outbuf+smb_vwv11+1,t);
+ SSVALS(outbuf,smb_vwv15+1,TimeDiff(t)/60);
return (smb_len(outbuf)+4);
}
@@ -3884,7 +3357,7 @@ int construct_reply(char *inbuf,char *outbuf,int size,int bufsize)
/****************************************************************************
process commands from the client
****************************************************************************/
-void process(void )
+static void process(void)
{
static int trans_num = 0;
int nread;
@@ -3908,12 +3381,10 @@ void process(void )
ip = *interpret_addr2("localhost");
if (zero_ip(ip)) ip = *interpret_addr2("127.0.0.1");
*OutBuffer = 0;
- send_one_packet(OutBuffer,1,ip,137,SOCK_DGRAM);
+ send_one_packet(OutBuffer,1,ip,NMB_PORT,SOCK_DGRAM);
}
#endif
- last_user.cnum = -1;
-
while (True)
{
int32 len;
@@ -3959,9 +3430,14 @@ void process(void )
BOOL allidle = True;
extern int keepalive;
- /* check for socket failure */
- if (errno == EBADF) {
- DEBUG(3,("%s Bad file descriptor - exiting\n",timestring()));
+ if (smb_read_error == READ_EOF) {
+ DEBUG(3,("end of file from client\n"));
+ return;
+ }
+
+ if (smb_read_error == READ_ERROR) {
+ DEBUG(3,("receive_smb error (%s) exiting\n",
+ strerror(errno)));
return;
}
@@ -3989,10 +3465,15 @@ void process(void )
}
if (keepalive && (counter-last_keepalive)>keepalive) {
+ extern int password_client;
if (!send_keepalive(Client)) {
DEBUG(2,("%s Keepalive failed - exiting\n",timestring()));
return;
- }
+ }
+ /* also send a keepalive to the password server if its still
+ connected */
+ if (password_client != -1)
+ send_keepalive(password_client);
last_keepalive = counter;
}
@@ -4064,7 +3545,7 @@ void process(void )
static void init_structs(void )
{
int i;
- get_myname(myhostname,&myip);
+ get_myname(myhostname,NULL);
for (i=0;i<MAX_CONNECTIONS;i++)
{
@@ -4090,7 +3571,7 @@ static void init_structs(void )
/****************************************************************************
usage on the program
****************************************************************************/
-void usage(char *pname)
+static void usage(char *pname)
{
DEBUG(0,("Incorrect program usage - are you sure the command line is correct?\n"));
@@ -4110,12 +3591,12 @@ void usage(char *pname)
/****************************************************************************
main program
****************************************************************************/
-int main(int argc,char *argv[])
+ int main(int argc,char *argv[])
{
extern BOOL append_log;
/* shall I run as a daemon */
BOOL is_daemon = False;
- int port = 139;
+ int port = SMB_PORT;
int opt;
extern char *optarg;
@@ -4152,22 +3633,7 @@ int main(int argc,char *argv[])
umask(0777 & ~DEF_CREATE_MASK);
- initial_uid = geteuid();
- initial_gid = getegid();
-
- if (initial_gid != 0 && initial_uid == 0)
- {
-#ifdef HPUX
- setresgid(0,0,0);
-#else
- setgid(0);
- setegid(0);
-#endif
- }
-
- initial_uid = geteuid();
- initial_gid = getegid();
-
+ init_uid();
/* this is for people who can't start the program correctly */
while (argc > 1 && (*argv[1] != '-'))
@@ -4229,8 +3695,6 @@ int main(int argc,char *argv[])
DEBUG(2,("%s smbd version %s started\n",timestring(),VERSION));
DEBUG(2,("Copyright Andrew Tridgell 1992-1995\n"));
- GetWd(OriginalDir);
-
#ifndef NO_GETRLIMIT
#ifdef RLIMIT_NOFILE
{
@@ -4277,22 +3741,23 @@ int main(int argc,char *argv[])
become_daemon();
}
- if (open_sockets(is_daemon,port))
- {
- /* possibly reload the services file. */
- reload_services(True);
+ if (!open_sockets(is_daemon,port))
+ exit(1);
- maxxmit = MIN(lp_maxxmit(),BUFFER_SIZE);
+ /* possibly reload the services file. */
+ reload_services(True);
- if (*lp_rootdir())
- {
- if (sys_chroot(lp_rootdir()) == 0)
- DEBUG(2,("%s changed root to %s\n",timestring(),lp_rootdir()));
- }
+ maxxmit = MIN(lp_maxxmit(),BUFFER_SIZE);
- process();
- close_sockets();
+ if (*lp_rootdir())
+ {
+ if (sys_chroot(lp_rootdir()) == 0)
+ DEBUG(2,("%s changed root to %s\n",timestring(),lp_rootdir()));
}
+
+ process();
+ close_sockets();
+
exit_server("normal exit");
return(0);
}
diff --git a/source/smbd/smbrun.c b/source/smbd/smbrun.c
index df12ae1f85c..d547c796e07 100644
--- a/source/smbd/smbrun.c
+++ b/source/smbd/smbrun.c
@@ -41,56 +41,57 @@ static void close_fds(void)
/*
-This is a wrapper around the system call to allow commands to run correctly
+This is a wrapper around the system() call to allow commands to run correctly
as non root from a program which is switching between root and non-root
-It takes one argument as argv[1] and runs it after becoming a non-root
-user
-*/
-int main(int argc,char *argv[])
+It takes 3 arguments as uid,gid,command and runs command after
+becoming a non-root user */
+ int main(int argc,char *argv[])
{
+ int uid,gid;
+
close_fds();
- if (getuid() != geteuid())
- {
- int uid,gid;
-
- if (getuid() == 0)
- uid = geteuid();
- else
- uid = getuid();
-
- if (getgid() == 0)
- gid = getegid();
- else
- gid = getgid();
-
+ if (argc != 4) exit(2);
+
+ uid = atoi(argv[1]);
+ gid = atoi(argv[2]);
+
+ /* first become root - we may need to do this in order to lose
+ our privilages! */
#ifdef USE_SETRES
- setresgid(0,0,0);
- setresuid(0,0,0);
- setresgid(gid,gid,gid);
- setresuid(uid,uid,uid);
+ setresgid(0,0,0);
+ setresuid(0,0,0);
#else
- setuid(0);
- seteuid(0);
- setgid(gid);
- setegid(gid);
- setuid(uid);
- seteuid(uid);
+ setuid(0);
+ seteuid(0);
#endif
- if (getuid() != uid)
- return(3);
- }
+#ifdef USE_SETFS
+ setfsuid(uid);
+ setfsgid(gid);
+#endif
+
+#ifdef USE_SETRES
+ setresgid(gid,gid,gid);
+ setresuid(uid,uid,uid);
+#else
+ setgid(gid);
+ setegid(gid);
+ setuid(uid);
+ seteuid(uid);
+#endif
- if (geteuid() != getuid())
- return(1);
- if (argc < 2)
- return(2);
+ /* paranoia :-) */
+ if (getuid() != uid)
+ return(3);
+
+ if (geteuid() != getuid())
+ return(4);
/* this is to make sure that the system() call doesn't run forever */
alarm(30);
- return(system(argv[1]));
+ return(system(argv[3]));
}
diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c
index 9d02123cf87..321dabc72cf 100644
--- a/source/smbd/trans2.c
+++ b/source/smbd/trans2.c
@@ -22,7 +22,6 @@
*/
#include "includes.h"
-#include "loadparm.h"
#include "trans2.h"
extern int DEBUGLEVEL;
@@ -264,7 +263,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
int mode=0;
uint32 size=0,len;
uint32 mdate=0, adate=0, cdate=0;
- char *name_ptr;
+ char *nameptr;
BOOL isrootdir = (strequal(Connections[cnum].dirpath,"./") ||
strequal(Connections[cnum].dirpath,".") ||
strequal(Connections[cnum].dirpath,"/"));
@@ -325,11 +324,11 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
mode = dos_mode(cnum,pathreal,&sbuf);
- if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
- {
- DEBUG(5,("[%s] attribs didn't match %x\n",fname,dirtype));
- continue;
- }
+ if (!dir_check_ftype(cnum,mode,&sbuf,dirtype)) {
+ DEBUG(5,("[%s] attribs didn't match %x\n",fname,dirtype));
+ continue;
+ }
+
size = sbuf.st_size;
mdate = sbuf.st_mtime;
adate = sbuf.st_atime;
@@ -349,7 +348,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
#endif
p = pdata;
- name_ptr = p;
+ nameptr = p;
name_map_mangle(fname,False,SNUM(cnum));
@@ -368,7 +367,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
SSVAL(p,l1_attrFile,mode);
SCVAL(p,l1_cchName,strlen(fname));
strcpy(p + l1_achName, fname);
- name_ptr = p + l1_achName;
+ nameptr = p + l1_achName;
p += l1_achName + strlen(fname) + 1;
break;
@@ -387,7 +386,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
SIVAL(p,l2_cbList,0); /* No extended attributes */
SCVAL(p,l2_cchName,strlen(fname));
strcpy(p + l2_achName, fname);
- name_ptr = p + l2_achName;
+ nameptr = p + l2_achName;
p += l2_achName + strlen(fname) + 1;
break;
@@ -402,7 +401,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
SIVAL(p,26,4);
CVAL(p,30) = strlen(fname);
strcpy(p+31, fname);
- name_ptr = p+31;
+ nameptr = p+31;
p += 31 + strlen(fname) + 1;
break;
@@ -420,7 +419,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
SSVAL(p,24,mode);
CVAL(p,32) = strlen(fname);
strcpy(p + 33, fname);
- name_ptr = p+33;
+ nameptr = p+33;
p += 33 + strlen(fname) + 1;
break;
@@ -452,7 +451,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
strupper(p+2);
SSVAL(p,0,strlen(p+2));
p += 2 + 24;
- /* name_ptr = p; */
+ /* nameptr = p; */
strcpy(p,fname); p += strlen(p);
p = pdata + len;
break;
@@ -517,7 +516,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
}
/* Setup the last_filename pointer, as an offset from base_data */
- *last_name_off = PTR_DIFF(name_ptr,base_data);
+ *last_name_off = PTR_DIFF(nameptr,base_data);
/* Advance the data pointer to the next slot */
*ppdata = p;
return(found);
@@ -1004,7 +1003,7 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
if (tran_call == TRANSACT2_QFILEINFO) {
- int16 fnum = SVAL(params,0);
+ int16 fnum = SVALS(params,0);
info_level = SVAL(params,2);
CHECK_FNUM(fnum,cnum);
@@ -1198,7 +1197,7 @@ static int call_trans2setfilepathinfo(char *inbuf, char *outbuf, int length,
return(ERROR(ERRSRV,ERRaccess));
if (tran_call == TRANSACT2_SETFILEINFO) {
- int16 fnum = SVAL(params,0);
+ int16 fnum = SVALS(params,0);
info_level = SVAL(params,2);
CHECK_FNUM(fnum,cnum);
@@ -1444,7 +1443,7 @@ int reply_findclose(char *inbuf,char *outbuf,int length,int bufsize)
{
int cnum;
int outsize = 0;
- uint16 dptr_num=SVAL(inbuf,smb_vwv0);
+ int16 dptr_num=SVALS(inbuf,smb_vwv0);
cnum = SVAL(inbuf,smb_tid);
@@ -1555,10 +1554,8 @@ int reply_trans2(char *inbuf,char *outbuf,int length,int bufsize)
while( num_data_sofar < total_data || num_params_sofar < total_params)
{
- receive_smb(Client,inbuf, 0);
-
- /* Ensure this is still a trans2 packet (sanity check) */
- if(CVAL(inbuf, smb_com) != SMBtranss2)
+ if(!receive_smb(Client,inbuf, SMB_SECONDARY_WAIT*1000) ||
+ CVAL(inbuf, smb_com) != SMBtranss2)
{
outsize = set_message(outbuf,0,0,True);
DEBUG(2,("Invalid secondary trans2 packet\n"));
diff --git a/source/smbd/uid.c b/source/smbd/uid.c
new file mode 100644
index 00000000000..555cd457e77
--- /dev/null
+++ b/source/smbd/uid.c
@@ -0,0 +1,359 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ uid/user handling
+ Copyright (C) Andrew Tridgell 1992-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 int DEBUGLEVEL;
+
+extern connection_struct Connections[];
+
+static int initial_uid;
+static int initial_gid;
+static int old_umask = 022;
+
+static pstring OriginalDir;
+
+/* what user is current? */
+struct current_user current_user;
+
+/****************************************************************************
+initialise the uid routines
+****************************************************************************/
+void init_uid(void)
+{
+ initial_uid = current_user.uid = geteuid();
+ initial_gid = current_user.gid = getegid();
+
+ if (initial_gid != 0 && initial_uid == 0)
+ {
+#ifdef HPUX
+ setresgid(0,0,0);
+#else
+ setgid(0);
+ setegid(0);
+#endif
+ }
+
+ initial_uid = geteuid();
+ initial_gid = getegid();
+
+ current_user.cnum = -1;
+
+ GetWd(OriginalDir);
+}
+
+
+/****************************************************************************
+ become the specified uid
+****************************************************************************/
+static BOOL become_uid(int uid)
+{
+ if (initial_uid != 0)
+ return(True);
+
+#ifdef AIX
+ {
+ /* AIX 3 stuff - inspired by a code fragment in wu-ftpd */
+ priv_t priv;
+
+ priv.pv_priv[0] = 0;
+ priv.pv_priv[1] = 0;
+ if (setpriv(PRIV_SET|PRIV_INHERITED|PRIV_EFFECTIVE|PRIV_BEQUEATH,
+ &priv, sizeof(priv_t)) < 0 ||
+ setuidx(ID_REAL|ID_EFFECTIVE, (uid_t)uid) < 0 ||
+ seteuid((uid_t)uid) < 0)
+ DEBUG(1,("Can't set uid (AIX3)"));
+ }
+#endif
+
+#ifdef USE_SETRES
+ if (setresuid(-1,uid,-1) != 0)
+#elif defined(USE_SETFS)
+ if (setfsuid(uid) != 0)
+#else
+ if ((seteuid(uid) != 0) &&
+ (setuid(uid) != 0))
+#endif
+ {
+ DEBUG(0,("Couldn't set uid %d currently set to (%d,%d)\n",
+ uid,getuid(), geteuid()));
+ if (uid > 32000)
+ DEBUG(0,("Looks like your OS doesn't like high uid values - try using a different account\n"));
+ return(False);
+ }
+
+ if (((uid == -1) || (uid == 65535)) && geteuid() != uid) {
+ DEBUG(0,("Invalid uid -1. perhaps you have a account with uid 65535?\n"));
+ return(False);
+ }
+
+ current_user.uid = uid;
+
+ return(True);
+}
+
+
+/****************************************************************************
+ become the specified gid
+****************************************************************************/
+static BOOL become_gid(int gid)
+{
+ if (initial_uid != 0)
+ return(True);
+
+#ifdef USE_SETRES
+ if (setresgid(-1,gid,-1) != 0)
+#elif defined(USE_SETFS)
+ if (setfsgid(gid) != 0)
+#else
+ if (setgid(gid) != 0)
+#endif
+ {
+ DEBUG(0,("Couldn't set gid %d currently set to (%d,%d)\n",
+ gid,getgid(),getegid()));
+ if (gid > 32000)
+ DEBUG(0,("Looks like your OS doesn't like high gid values - try using a different account\n"));
+ return(False);
+ }
+
+ current_user.gid = gid;
+
+ return(True);
+}
+
+
+/****************************************************************************
+ become the specified uid and gid
+****************************************************************************/
+static BOOL become_id(int uid,int gid)
+{
+ return(become_gid(gid) && become_uid(uid));
+}
+
+/****************************************************************************
+become the guest user
+****************************************************************************/
+BOOL become_guest(void)
+{
+ BOOL ret;
+ static struct passwd *pass=NULL;
+
+ if (initial_uid != 0)
+ return(True);
+
+ if (!pass)
+ pass = Get_Pwnam(lp_guestaccount(-1),True);
+ if (!pass) return(False);
+
+ ret = become_id(pass->pw_uid,pass->pw_gid);
+
+ if (!ret)
+ DEBUG(1,("Failed to become guest. Invalid guest account?\n"));
+
+ current_user.cnum = -2;
+
+ return(ret);
+}
+
+/*******************************************************************
+check if a username is OK
+********************************************************************/
+static BOOL check_user_ok(int cnum,user_struct *vuser,int snum)
+{
+ int i;
+ for (i=0;i<Connections[cnum].uid_cache.entries;i++)
+ if (Connections[cnum].uid_cache.list[i] == vuser->uid) return(True);
+
+ if (!user_ok(vuser->name,snum)) return(False);
+
+ i = Connections[cnum].uid_cache.entries % UID_CACHE_SIZE;
+ Connections[cnum].uid_cache.list[i] = vuser->uid;
+
+ if (Connections[cnum].uid_cache.entries < UID_CACHE_SIZE)
+ Connections[cnum].uid_cache.entries++;
+
+ return(True);
+}
+
+
+/****************************************************************************
+ become the user of a connection number
+****************************************************************************/
+BOOL become_user(int cnum, int uid)
+{
+ int new_umask;
+ user_struct *vuser;
+ int snum,gid;
+ int id = uid;
+
+ if (current_user.cnum == cnum && current_user.id == id) {
+ DEBUG(4,("Skipping become_user - already user\n"));
+ return(True);
+ }
+
+ unbecome_user();
+
+ if (!OPEN_CNUM(cnum)) {
+ DEBUG(2,("Connection %d not open\n",cnum));
+ return(False);
+ }
+
+ snum = Connections[cnum].service;
+
+ if (Connections[cnum].force_user ||
+ lp_security() == SEC_SHARE ||
+ !(vuser = get_valid_user_struct(uid)) ||
+ !check_user_ok(cnum,vuser,snum)) {
+ uid = Connections[cnum].uid;
+ gid = Connections[cnum].gid;
+ current_user.groups = Connections[cnum].groups;
+ current_user.igroups = Connections[cnum].igroups;
+ current_user.ngroups = Connections[cnum].ngroups;
+ } else {
+ if (!vuser) {
+ DEBUG(2,("Invalid vuid used %d\n",uid));
+ return(False);
+ }
+ uid = vuser->uid;
+ if(!*lp_force_group(snum))
+ gid = vuser->gid;
+ else
+ gid = Connections[cnum].gid;
+ current_user.groups = vuser->user_groups;
+ current_user.igroups = vuser->user_igroups;
+ current_user.ngroups = vuser->user_ngroups;
+ }
+
+ if (initial_uid == 0)
+ {
+ if (!become_gid(gid)) return(False);
+
+#ifndef NO_SETGROUPS
+ if (!IS_IPC(cnum)) {
+ /* groups stuff added by ih/wreu */
+ if (current_user.ngroups > 0)
+ if (setgroups(current_user.ngroups,current_user.groups)<0)
+ DEBUG(0,("setgroups call failed!\n"));
+ }
+#endif
+
+ if (!Connections[cnum].admin_user && !become_uid(uid))
+ return(False);
+ }
+
+ new_umask = 0777 & ~CREATE_MODE(cnum);
+ old_umask = umask(new_umask);
+
+ current_user.cnum = cnum;
+ current_user.id = id;
+
+ DEBUG(5,("become_user uid=(%d,%d) gid=(%d,%d) new_umask=0%o\n",
+ getuid(),geteuid(),getgid(),getegid(),new_umask));
+
+ return(True);
+}
+
+/****************************************************************************
+ unbecome the user of a connection number
+****************************************************************************/
+BOOL unbecome_user(void )
+{
+ if (current_user.cnum == -1)
+ return(False);
+
+ ChDir(OriginalDir);
+
+ umask(old_umask);
+
+ if (initial_uid == 0)
+ {
+#ifdef USE_SETRES
+ setresuid(-1,getuid(),-1);
+ setresgid(-1,getgid(),-1);
+#elif defined(USE_SETFS)
+ setfsuid(initial_uid);
+ setfsgid(initial_gid);
+#else
+ if (seteuid(initial_uid) != 0)
+ setuid(initial_uid);
+ setgid(initial_gid);
+#endif
+ }
+#ifdef NO_EID
+ if (initial_uid == 0)
+ DEBUG(2,("Running with no EID\n"));
+ initial_uid = getuid();
+ initial_gid = getgid();
+#else
+ if (geteuid() != initial_uid)
+ {
+ DEBUG(0,("Warning: You appear to have a trapdoor uid system\n"));
+ initial_uid = geteuid();
+ }
+ if (getegid() != initial_gid)
+ {
+ DEBUG(0,("Warning: You appear to have a trapdoor gid system\n"));
+ initial_gid = getegid();
+ }
+#endif
+
+ current_user.uid = initial_uid;
+ current_user.gid = initial_gid;
+
+ if (ChDir(OriginalDir) != 0)
+ DEBUG(0,("%s chdir(%s) failed in unbecome_user\n",
+ timestring(),OriginalDir));
+
+ DEBUG(5,("unbecome_user now uid=(%d,%d) gid=(%d,%d)\n",
+ getuid(),geteuid(),getgid(),getegid()));
+
+ current_user.cnum = -1;
+
+ return(True);
+}
+
+
+/****************************************************************************
+run a command via system() using smbrun, being careful about uid/gid handling
+****************************************************************************/
+int smbrun(char *cmd,char *outfile)
+{
+ int ret;
+ pstring syscmd;
+ char *path = lp_smbrun();
+
+ if (!file_exist(path,NULL))
+ {
+ DEBUG(0,("SMBRUN ERROR: Can't find %s. Installation problem?\n",path));
+ return(1);
+ }
+
+ sprintf(syscmd,"%s %d %d \"(%s 2>&1) > %s\"",
+ path,current_user.uid,current_user.gid,cmd,
+ outfile?outfile:"/dev/null");
+
+ DEBUG(5,("smbrun - running %s ",syscmd));
+ ret = system(syscmd);
+ DEBUG(5,("gave %d\n",ret));
+ return(ret);
+}
+
+
diff --git a/source/smbd/vt_mode.c b/source/smbd/vt_mode.c
index 83b62a38ac2..0a4d50c217f 100644
--- a/source/smbd/vt_mode.c
+++ b/source/smbd/vt_mode.c
@@ -60,8 +60,7 @@ int ms_type = MS_NONE,
/*
VT_Check: test incoming packet for "vtp" or "iVT1\0"
*/
-int VT_Check(buffer)
-char *buffer;
+int VT_Check(char *buffer)
{
DEBUG(3,("Checking packet: <%10s...>\n", buffer+4));
if((strncmp(buffer+4, "vtp", 3) == 0 && smb_len(buffer) == 3) || (strncmp(buffer+4, "iVT1\0", 5) == 0 && smb_len(buffer) == 5))
@@ -74,7 +73,7 @@ char *buffer;
/*
VT_Start_utmp: prepare /etc/utmp for /bin/login
*/
-VT_Start_utmp()
+int VT_Start_utmp(void)
{
struct utmp u, *v;
char *tt;
@@ -111,7 +110,7 @@ VT_Start_utmp()
/*
VT_Stop_utmp: prepare /etc/utmp for other processes
*/
-VT_Stop_utmp()
+int VT_Stop_utmp(void)
{
struct utmp u, *v;
@@ -138,7 +137,7 @@ VT_Stop_utmp()
/*
VT_AtExit: Things to do when the program exits
*/
-void VT_AtExit()
+void VT_AtExit(void)
{
if(VT_ChildPID > 0) {
kill(VT_ChildPID, SIGHUP);
@@ -152,8 +151,7 @@ void VT_AtExit()
/*
VT_SigCLD: signalhandler for SIGCLD: set flag if child-process died
*/
-void VT_SigCLD(sig)
-int sig;
+void VT_SigCLD(int sig)
{
if(wait(NULL) == VT_ChildPID)
VT_ChildDied = True;
@@ -165,8 +163,7 @@ int sig;
/*
VT_SigEXIT: signalhandler for signals that cause the process to exit
*/
-void VT_SigEXIT(sig)
-int sig;
+void VT_SigEXIT(int sig)
{
VT_AtExit();
@@ -177,7 +174,7 @@ int sig;
/*
VT_Start: initialize vt-specific data, alloc pty, spawn shell and send ACK
*/
-int VT_Start()
+int VT_Start(void)
{
char OutBuf [64], *X, *Y;
@@ -330,8 +327,7 @@ int VT_Start()
/*
VT_Output: transport data from socket to pty
*/
-int VT_Output(Buffer)
-char *Buffer;
+int VT_Output(char *Buffer)
{
int i, len, nb;
@@ -350,9 +346,7 @@ char *Buffer;
/*
VT_Input: transport data from pty to socket
*/
-int VT_Input(Buffer, Size)
-char *Buffer;
-int Size;
+int VT_Input(char *Buffer,int Size)
{
int len;
@@ -372,7 +366,7 @@ int Size;
/*
VT_Process: main loop while in vt-mode
*/
-void VT_Process()
+void VT_Process(void)
{
static int trans_num = 0;
extern int Client;
diff --git a/source/utils/nmblookup.c b/source/utils/nmblookup.c
index aa431733322..292b526df93 100644
--- a/source/utils/nmblookup.c
+++ b/source/utils/nmblookup.c
@@ -25,16 +25,13 @@
#endif
#include "includes.h"
-#include "nameserv.h"
extern int DEBUGLEVEL;
extern pstring scope;
-extern struct in_addr bcast_ip;
extern pstring myhostname;
-
-static BOOL got_bcast = False;
+extern struct in_addr ipzero;
int ServerFD= -1;
@@ -69,24 +66,9 @@ static BOOL open_sockets(void)
****************************************************************************/
static BOOL init_structs(void )
{
- struct in_addr myip;
-
- if (!get_myname(myhostname,&myip))
+ if (!get_myname(myhostname,NULL))
return(False);
- /* Read the broadcast address from the interface */
- {
- struct in_addr ip0,ip2;
-
- ip0 = myip;
-
- if (!got_bcast) {
- get_broadcast(&ip0,&bcast_ip,&ip2);
-
- DEBUG(2,("Using broadcast %s\n",inet_ntoa(bcast_ip)));
- }
- }
-
return True;
}
@@ -111,7 +93,7 @@ static void usage(void)
int main(int argc,char *argv[])
{
int opt;
- unsigned int lookup_type = 0x20;
+ unsigned int lookup_type = 0x0;
pstring lookup;
extern int optind;
extern char *optarg;
@@ -132,11 +114,7 @@ int main(int argc,char *argv[])
switch (opt)
{
case 'B':
- {
- unsigned long a = interpret_addr(optarg);
- putip((char *)&bcast_ip,(char *)&a);
- got_bcast = True;
- }
+ iface_set_default(NULL,optarg,NULL);
break;
case 'i':
strcpy(scope,optarg);
@@ -165,14 +143,15 @@ int main(int argc,char *argv[])
exit(1);
}
+ load_interfaces();
init_structs();
if (!open_sockets()) return(1);
- DEBUG(1,("Sending queries to %s\n",inet_ntoa(bcast_ip)));
+ DEBUG(1,("Sending queries to %s\n",inet_ntoa(*iface_bcast(ipzero))));
for (i=optind;i<argc;i++)
- {
+ {
BOOL bcast = True;
int retries = 2;
char *p;
@@ -185,7 +164,7 @@ int main(int argc,char *argv[])
strcpy(lookup,"\01\02__MSBROWSE__\02");
lookup_type = 1;
} else {
- lookup_type = 0x1d;
+ lookup_type = 0x1b;
}
}
@@ -198,20 +177,18 @@ int main(int argc,char *argv[])
retries = 1;
}
- if (name_query(ServerFD,lookup,lookup_type,bcast,True,
- bcast_ip,&ip,NULL))
+ if (name_query(ServerFD,lookup,lookup_type,bcast,True,
+ *iface_bcast(ipzero),&ip,NULL))
{
printf("%s %s\n",inet_ntoa(ip),lookup);
- if (find_status)
- {
+ }
+ if (find_status)
+ {
printf("Looking up status of %s\n",inet_ntoa(ip));
name_status(ServerFD,lookup,lookup_type,True,ip,NULL,NULL,NULL);
printf("\n");
- }
- } else {
- printf("couldn't find name %s\n",lookup);
- }
- }
+ }
+ }
return(0);
}
diff --git a/source/utils/smbpasswd.c b/source/utils/smbpasswd.c
index 167eb2ed5f3..c79aa15c807 100644
--- a/source/utils/smbpasswd.c
+++ b/source/utils/smbpasswd.c
@@ -152,8 +152,8 @@ _my_get_smbpwnam(FILE * fp, char *name, BOOL * valid_old_pwd,
/* NT Entry was valid - even if 'X' or '*', can be overwritten */
*got_valid_nt_entry = True;
if (*p != '*' && *p != 'X') {
- if(gethexpwd(p,smbntpwd))
- pw_buf.smb_nt_passwd = smbntpwd;
+ if (gethexpwd((char *)p,(char *)smbntpwd))
+ pw_buf.smb_nt_passwd = smbntpwd;
}
}
pw_buf.smb_name = user_name;
@@ -167,12 +167,12 @@ _my_get_smbpwnam(FILE * fp, char *name, BOOL * valid_old_pwd,
if (p[32] != ':')
return (False);
- if (!strncasecmp(p, "NO PASSWORD", 11)) {
- pw_buf.smb_passwd = NULL; /* No password */
+ if (!strncasecmp((char *)p, "NO PASSWORD", 11)) {
+ pw_buf.smb_passwd = NULL; /* No password */
} else {
- if(!gethexpwd(p,smbpwd))
- return False;
- pw_buf.smb_passwd = smbpwd;
+ if(!gethexpwd((char *)p,(char *)smbpwd))
+ return False;
+ pw_buf.smb_passwd = smbpwd;
}
pw_buf.smb_name = user_name;
@@ -189,8 +189,8 @@ _my_get_smbpwnam(FILE * fp, char *name, BOOL * valid_old_pwd,
/* NT Entry was valid - even if 'X' or '*', can be overwritten */
*got_valid_nt_entry = True;
if (*p != '*' && *p != 'X') {
- if(gethexpwd(p,smbntpwd))
- pw_buf.smb_nt_passwd = smbntpwd;
+ if (gethexpwd((char *)p,(char *)smbntpwd))
+ pw_buf.smb_nt_passwd = smbntpwd;
}
}
return &pw_buf;
@@ -201,14 +201,13 @@ _my_get_smbpwnam(FILE * fp, char *name, BOOL * valid_old_pwd,
/*
* Print command usage on stderr and die.
*/
-void
-usage(char *name)
+static void usage(char *name)
{
fprintf(stderr, "Usage is : %s [username]\n", name);
exit(1);
}
-int main(int argc, char **argv)
+ int main(int argc, char **argv)
{
int real_uid;
struct passwd *pwd;
@@ -232,6 +231,8 @@ int main(int argc, char **argv)
char *pfile = SMB_PASSWD_FILE;
char readbuf[16 * 1024];
+ TimeInit();
+
setup_logging(argv[0],True);
charset_initialise();
diff --git a/source/utils/status.c b/source/utils/status.c
index ed0ae532114..3d520564895 100644
--- a/source/utils/status.c
+++ b/source/utils/status.c
@@ -28,22 +28,18 @@
#endif
#include "includes.h"
-#include "loadparm.h"
struct connect_record crec;
extern int DEBUGLEVEL;
extern FILE *dbf;
+extern pstring myhostname;
static pstring Ucrit_username = ""; /* added by OH */
int Ucrit_pid[100]; /* Ugly !!! */ /* added by OH */
int Ucrit_MaxPid=0; /* added by OH */
unsigned int Ucrit_IsActive = 0; /* added by OH */
-void Ucrit_addUsername(pstring username); /* added by OH */
-unsigned int Ucrit_checkUsername(pstring username); /* added by OH */
-void Ucrit_addPid(int pid); /* added by OH */
-unsigned int Ucrit_checkPid(int pid); /* added by OH */
-int main(int argc, char *argv[])
+ int main(int argc, char *argv[])
{
FILE *f;
pstring fname;
@@ -57,6 +53,7 @@ int main(int argc, char *argv[])
BOOL processes_only=False;
int last_pid=0;
+ TimeInit();
setup_logging(argv[0],True);
charset_initialise();
@@ -69,7 +66,7 @@ int main(int argc, char *argv[])
return(1);
}
- while ((c = getopt(argc, argv, "pdsu:")) != EOF) {
+ while ((c = getopt(argc, argv, "pds:u:")) != EOF) {
switch (c) {
case 'd':
verbose = 1;
@@ -89,13 +86,13 @@ int main(int argc, char *argv[])
}
}
-
-
if (!lp_load(servicesf,False)) {
fprintf(stderr, "Can't load %s - run testparm to debug it\n", servicesf);
return (-1);
}
+ get_myname(myhostname, NULL);
+
if (verbose) {
printf("using configfile = %s\n", servicesf);
printf("lockdir = %s\n", *lp_lockdir() ? lp_lockdir() : "NULL");
@@ -113,6 +110,9 @@ int main(int argc, char *argv[])
printf("You need to have status=yes in your smb config file\n");
return(0);
}
+ else if (verbose) {
+ printf("Opened status file %s\n", fname);
+ }
uid = getuid();
@@ -142,7 +142,7 @@ int main(int argc, char *argv[])
printf("%-10.10s %-8s %-8s %5d %-8s (%s) %s",
crec.name,uidtoname(crec.uid),gidtoname(crec.gid),crec.pid,
crec.machine,crec.addr,
- asctime(LocalTime(&crec.start,GMT_TO_LOCAL)));
+ asctime(LocalTime(&crec.start)));
}
}
fclose(f);
@@ -213,7 +213,7 @@ int main(int argc, char *argv[])
case 1: printf("WRONLY "); break;
case 2: printf("RDWR "); break;
}
- printf(" %s %s",fname,asctime(LocalTime(&t,GMT_TO_LOCAL)));
+ printf(" %s %s",fname,asctime(LocalTime(&t)));
}
closedir(dir);
diff --git a/source/utils/testparm.c b/source/utils/testparm.c
index e1f070a4b83..1d6cc2b0003 100644
--- a/source/utils/testparm.c
+++ b/source/utils/testparm.c
@@ -34,18 +34,18 @@
#include "includes.h"
#include "smb.h"
-#include "params.h"
-#include "loadparm.h"
/* these live in util.c */
extern FILE *dbf;
extern int DEBUGLEVEL;
-int main(int argc, char *argv[])
+ int main(int argc, char *argv[])
{
pstring configfile;
int s;
+ TimeInit();
+
setup_logging(argv[0],True);
charset_initialise();
diff --git a/source/utils/testprns.c b/source/utils/testprns.c
index 89c615898d7..b41b4a4c422 100644
--- a/source/utils/testprns.c
+++ b/source/utils/testprns.c
@@ -33,7 +33,6 @@
#include "includes.h"
#include "smb.h"
-#include "pcap.h"
/* these live in util.c */
extern FILE *dbf;
@@ -43,6 +42,8 @@ int main(int argc, char *argv[])
{
char *pszTemp;
+ TimeInit();
+
setup_logging(argv[0],True);
charset_initialise();