summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README17
-rw-r--r--docs/INSTALL.txt318
-rw-r--r--docs/MIRRORS31
-rw-r--r--docs/OS2.txt57
-rw-r--r--docs/README.OS281
-rw-r--r--docs/Warp.txt99
-rw-r--r--docs/announce6
-rw-r--r--docs/manpages/nmbd.84
-rw-r--r--docs/manpages/samba.74
-rw-r--r--docs/manpages/smb.conf.557
-rw-r--r--docs/manpages/smbclient.129
-rw-r--r--docs/samba.faq606
-rw-r--r--docs/samba.lsm4
-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/Support.txt41
-rw-r--r--docs/textdocs/UNIX-SMB.txt3
-rw-r--r--docs/textdocs/security_level.txt78
-rw-r--r--examples/misc/extra_smbstatus33
-rw-r--r--examples/misc/wall.perl76
-rw-r--r--examples/thoralf/smb.conf152
-rw-r--r--source/.cvsignore10
-rw-r--r--source/change-log3
-rw-r--r--source/client/client.c814
-rw-r--r--source/client/clientutil.c1029
-rw-r--r--source/client/clitar.c10
-rw-r--r--source/include/charset.h4
-rw-r--r--source/include/includes.h56
-rw-r--r--source/include/local.h11
-rw-r--r--source/include/nameserv.h177
-rw-r--r--source/include/proto.h512
-rw-r--r--source/include/smb.h302
-rw-r--r--source/include/version.h2
-rw-r--r--source/lib/charcnv.c9
-rw-r--r--source/lib/getsmbpass.c13
-rw-r--r--source/lib/kanji.c5
-rw-r--r--source/lib/md4.c2
-rw-r--r--source/lib/system.c2
-rw-r--r--source/lib/time.c495
-rw-r--r--source/lib/ufc.c2
-rw-r--r--source/lib/util.c638
-rw-r--r--source/libsmb/namequery.c292
-rw-r--r--source/libsmb/nmblib.c443
-rw-r--r--source/libsmb/smbencrypt.c17
-rw-r--r--source/loadparm.h165
-rw-r--r--source/localnet.h6
-rw-r--r--source/nameannounce.c445
-rw-r--r--source/namedb.c709
-rw-r--r--source/nameelect.c369
-rw-r--r--source/nameresp.c628
-rw-r--r--source/nameserv.c2757
-rw-r--r--source/namework.c1017
-rw-r--r--source/nmbd/nmbd.c610
-rw-r--r--source/nmbsync.c390
-rw-r--r--source/param/loadparm.c24
-rw-r--r--source/param/params.c136
-rw-r--r--source/params.h40
-rw-r--r--source/passdb/smbpass.c7
-rw-r--r--source/pcap.h35
-rw-r--r--source/printing/printing.c81
-rw-r--r--source/reply.h60
-rwxr-xr-xsource/script/installscripts.sh26
-rw-r--r--source/script/mkproto.awk39
-rw-r--r--source/smbd/dir.c33
-rw-r--r--source/smbd/ipc.c228
-rw-r--r--source/smbd/mangle.c4
-rw-r--r--source/smbd/password.c32
-rw-r--r--source/smbd/quotas.c363
-rw-r--r--source/smbd/reply.c14
-rw-r--r--source/smbd/server.c644
-rw-r--r--source/smbd/smbrun.c73
-rw-r--r--source/smbd/trans2.c32
-rw-r--r--source/smbd/uid.c360
-rw-r--r--source/smbd/vt_mode.c26
-rw-r--r--source/smbpass.h50
-rw-r--r--source/utils/nmblookup.c4
-rw-r--r--source/utils/smbpasswd.c25
-rw-r--r--source/utils/status.c17
-rw-r--r--source/utils/testparm.c4
-rw-r--r--source/utils/testprns.c2
81 files changed, 11163 insertions, 4861 deletions
diff --git a/README b/README
index b7ef5d55957..84bc00b2ef1 100644
--- a/README
+++ b/README
@@ -35,7 +35,8 @@ 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.
+"diff -u" format, see docs/BUGS.txt for more details) and am always glad to
+receive feedback or suggestions.
You could also send hardware/software/money/jewelry or pizza
vouchers directly to me. The pizza vouchers would be especially
@@ -49,7 +50,7 @@ we get. If noone tells us they like it then we'll probably move onto
something else.
Andrew Tridgell
-Email: samba-bugs@anu.edu.au
+Email: samba-bugs@samba.anu.edu.au
3 Ballow Crescent
Macgregor, A.C.T.
@@ -70,18 +71,18 @@ 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
+versions. 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.
@@ -102,7 +103,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..b91367cd59a
--- /dev/null
+++ b/docs/INSTALL.txt
@@ -0,0 +1,318 @@
+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 give the nmbd a -B parameter to
+specify the broadcast address of your interface. 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 4, 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.
diff --git a/docs/MIRRORS b/docs/MIRRORS
new file mode 100644
index 00000000000..2feb9ba90e8
--- /dev/null
+++ b/docs/MIRRORS
@@ -0,0 +1,31 @@
+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://ftp.warwick.ac.uk/pub/linux/sunsite.unc-mirror/system/Network/samba/
+ftp://sunsite.unc.edu/pub/Linux/system/Network/samba/
+ftp://ftp.choc.apana.org.au/pub/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.apana.org.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..78775aa5ca3 100644
--- a/docs/announce
+++ b/docs/announce
@@ -93,8 +93,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 +123,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
diff --git a/docs/manpages/nmbd.8 b/docs/manpages/nmbd.8
index e42f194cdee..72e45b9d54b 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
diff --git a/docs/manpages/samba.7 b/docs/manpages/samba.7
index 0c81f736b6e..bea20555e73 100644
--- a/docs/manpages/samba.7
+++ b/docs/manpages/samba.7
@@ -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,7 +54,7 @@ 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
diff --git a/docs/manpages/smb.conf.5 b/docs/manpages/smb.conf.5
index 933d71ff0c3..7149be6a473 100644
--- a/docs/manpages/smb.conf.5
+++ b/docs/manpages/smb.conf.5
@@ -459,6 +459,8 @@ comment
default case
+delete readonly
+
deny hosts
directory
@@ -831,6 +833,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'.
@@ -1187,9 +1202,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 +1250,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
@@ -1881,8 +1896,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.
@@ -2524,6 +2540,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/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/Support.txt b/docs/textdocs/Support.txt
index d71bdaf7b3e..c9ec69918e5 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,18 @@ 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
+------------------------------------------------------------------------------
+
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..b565ea79668
--- /dev/null
+++ b/docs/textdocs/security_level.txt
@@ -0,0 +1,78 @@
+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. A "real" SMB server like NT actually
+associates 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 is 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.
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/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/source/.cvsignore b/source/.cvsignore
new file mode 100644
index 00000000000..4e181a40a7f
--- /dev/null
+++ b/source/.cvsignore
@@ -0,0 +1,10 @@
+makefile
+nmbd
+nmblookup
+smbclient
+smbd
+smbpasswd
+smbrun
+smbstatus
+testparm
+testprns
diff --git a/source/change-log b/source/change-log
index e120ac6f02a..ee49663ed6e 100644
--- a/source/change-log
+++ b/source/change-log
@@ -1793,6 +1793,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.
==========
diff --git a/source/client/client.c b/source/client/client.c
index 504cb5a0bb4..5e464ea1115 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,13 @@ 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;
+struct in_addr ipzero;
char cryptkey[8];
BOOL doencrypt=False;
@@ -71,16 +72,29 @@ extern int DEBUGLEVEL;
BOOL translation = False;
+
+static BOOL send_trans_request(char *outbuf,int trans,
+ char *name,int fid,int flags,
+ char *data,char *param,uint16 *setup,
+ int ldata,int lparam,int lsetup,
+ int mdata,int mparam,int msetup);
+static BOOL receive_trans_response(char *inbuf,int trans,
+ int *data_len,int *param_len,
+ char **data,char **param);
+static int interpret_long_filename(int level,char *p,file_info *finfo);
+static void dir_action(char *inbuf,char *outbuf,int attribute,file_info *finfo,BOOL recurse_dir,void (*fn)(),BOOL longdir);
+static int interpret_short_filename(char *p,file_info *finfo);
+static BOOL call_api(int prcnt,int drcnt,
+ int mprcnt,int mdrcnt,
+ int *rprcnt,int *rdrcnt,
+ char *param,char *data,
+ char **rparam,char **rdata);
+
+
/* clitar bits insert */
-extern void cmd_tar();
-extern void cmd_block();
-extern void cmd_tarmode();
-extern void cmd_setmode();
extern int blocksize;
extern BOOL tar_inc;
extern BOOL tar_reset;
-extern int process_tar();
-extern int tar_parseargs();
/* clitar bits end */
@@ -150,20 +164,6 @@ setup_term_code (char *code)
#define CNV_INPUT(s) unix2dos_format(s,True)
#endif
-static void send_logout(void );
-BOOL reopen_connection(char *inbuf,char *outbuf);
-static int do_long_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir);
-static int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir);
-static BOOL call_api(int prcnt,int drcnt,int mprcnt,int mdrcnt,
- int *rprcnt,int *rdrcnt,char *param,char *data,
- char **rparam,char **rdata);
-static BOOL send_trans_request(char *outbuf,int trans,
- char *name,int fid,int flags,
- char *data,char *param,uint16 *setup,
- int ldata,int lparam,int lsetup,
- int mdata,int mparam,int msetup);
-
-
/****************************************************************************
setup basics in a outgoing packet
****************************************************************************/
@@ -482,9 +482,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,False);
+
+ if (CVAL(inbuf,smb_rcls) != 0)
+ DEBUG(0,("Error closing search: %s\n",smb_errstr(inbuf)));
+ }
+#endif
+
+ if (!fn)
+ for (p=dirlist,i=0;i<num_received;i++)
+ {
+ p += interpret_short_filename(p,&finfo);
+ display_finfo(&finfo);
+ }
+
+ for (p=dirlist,i=0;i<num_received;i++)
+ {
+ p += interpret_short_filename(p,&finfo);
+ dir_action(inbuf,outbuf,attribute,&finfo,recurse_dir,fn,False);
+ }
+
+ if (dirlist) free(dirlist);
+ return(num_received);
+}
+
+
+
/****************************************************************************
do a directory listing, calling fn on each file found
****************************************************************************/
@@ -684,148 +997,11 @@ static void dir_action(char *inbuf,char *outbuf,int attribute,file_info *finfo,B
/****************************************************************************
- do a directory listing, calling fn on each file found
- ****************************************************************************/
-static int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir)
-{
- char *p;
- int received = 0;
- BOOL first = True;
- char status[21];
- int num_asked = (max_xmit - 100)/DIR_STRUCT_SIZE;
- int num_received = 0;
- int i;
- char *dirlist = NULL;
- pstring mask;
- file_info finfo;
-
- finfo = def_finfo;
-
- bzero(status,21);
-
- strcpy(mask,Mask);
-
- while (1)
- {
- bzero(outbuf,smb_size);
- if (first)
- set_message(outbuf,2,5 + strlen(mask),True);
- else
- set_message(outbuf,2,5 + 21,True);
-
-#if FFIRST
- if (Protocol >= PROTOCOL_LANMAN1)
- CVAL(outbuf,smb_com) = SMBffirst;
- else
-#endif
- CVAL(outbuf,smb_com) = SMBsearch;
-
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- SSVAL(outbuf,smb_vwv0,num_asked);
- SSVAL(outbuf,smb_vwv1,attribute);
-
- p = smb_buf(outbuf);
- *p++ = 4;
-
- if (first)
- strcpy(p,mask);
- else
- strcpy(p,"");
- p += strlen(p) + 1;
-
- *p++ = 5;
- if (first)
- SSVAL(p,0,0);
- else
- {
- SSVAL(p,0,21);
- p += 2;
- memcpy(p,status,21);
- }
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- received = SVAL(inbuf,smb_vwv0);
-
- DEBUG(5,("dir received %d\n",received));
-
- DEBUG(6,("errstr=%s\n",smb_errstr(inbuf)));
-
- if (received <= 0) break;
-
- first = False;
-
- dirlist = Realloc(dirlist,(num_received + received)*DIR_STRUCT_SIZE);
-
- if (!dirlist)
- return 0;
-
- p = smb_buf(inbuf) + 3;
-
- memcpy(dirlist+num_received*DIR_STRUCT_SIZE,
- p,received*DIR_STRUCT_SIZE);
-
- memcpy(status,p + ((received-1)*DIR_STRUCT_SIZE),21);
-
- num_received += received;
-
- if (CVAL(inbuf,smb_rcls) != 0) break;
- }
-
-#if FFIRST
- if (!first && Protocol >= PROTOCOL_LANMAN1)
- {
- bzero(outbuf,smb_size);
- CVAL(outbuf,smb_com) = SMBfclose;
-
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- p = smb_buf(outbuf);
- *p++ = 4;
-
- strcpy(p,"");
- p += strlen(p) + 1;
-
- *p++ = 5;
- SSVAL(p,0,21);
- p += 2;
- memcpy(p,status,21);
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT,False);
-
- if (CVAL(inbuf,smb_rcls) != 0)
- DEBUG(0,("Error closing search: %s\n",smb_errstr(inbuf)));
- }
-#endif
-
- if (!fn)
- for (p=dirlist,i=0;i<num_received;i++)
- {
- p += interpret_short_filename(p,&finfo);
- display_finfo(&finfo);
- }
-
- for (p=dirlist,i=0;i<num_received;i++)
- {
- p += interpret_short_filename(p,&finfo);
- dir_action(inbuf,outbuf,attribute,&finfo,recurse_dir,fn,False);
- }
-
- if (dirlist) free(dirlist);
- return(num_received);
-}
-
-/****************************************************************************
receive a SMB trans or trans2 response allocating the necessary memory
****************************************************************************/
static BOOL receive_trans_response(char *inbuf,int trans,
int *data_len,int *param_len,
- char **data,char **param)
+ char **data,char **param)
{
int total_data=0;
int total_param=0;
@@ -893,178 +1069,6 @@ static BOOL receive_trans_response(char *inbuf,int trans,
return(True);
}
-/****************************************************************************
- do a directory listing, calling fn on each file found. Use the TRANSACT2
- call for long filenames
- ****************************************************************************/
-static int do_long_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir)
-{
- int max_matches = 512;
- int info_level = Protocol<PROTOCOL_NT1?1:260; /* NT uses 260, OS/2 uses 2. Both accept 1. */
- char *p;
- pstring mask;
- file_info finfo;
- int i;
- char *dirlist = NULL;
- int dirlist_len = 0;
- int total_received = 0;
- BOOL First = True;
- char *resp_data=NULL;
- char *resp_param=NULL;
- int resp_data_len = 0;
- int resp_param_len=0;
-
- int ff_resume_key = 0;
- int ff_searchcount=0;
- int ff_eos=0;
- int ff_lastname=0;
- int ff_dir_handle=0;
- int loop_count = 0;
-
- uint16 setup;
- pstring param;
-
- strcpy(mask,Mask);
-
- while (ff_eos == 0)
- {
- loop_count++;
- if (loop_count > 200)
- {
- DEBUG(0,("ERROR: Looping in FIND_NEXT??\n"));
- break;
- }
-
- if (First)
- {
- setup = TRANSACT2_FINDFIRST;
- SSVAL(param,0,attribute); /* attribute */
- SSVAL(param,2,max_matches); /* max count */
- SSVAL(param,4,8+4+2); /* resume required + close on end + continue */
- SSVAL(param,6,info_level);
- SIVAL(param,8,0);
- strcpy(param+12,mask);
- }
- else
- {
- setup = TRANSACT2_FINDNEXT;
- SSVAL(param,0,ff_dir_handle);
- SSVAL(param,2,max_matches); /* max count */
- SSVAL(param,4,info_level);
- SIVAL(param,6,ff_resume_key); /* ff_resume_key */
- SSVAL(param,10,8+4+2); /* resume required + close on end + continue */
- strcpy(param+12,mask);
-
- DEBUG(5,("hand=0x%X resume=%d ff_lastname=%d mask=%s\n",
- ff_dir_handle,ff_resume_key,ff_lastname,mask));
- }
- /* ??? original code added 1 pad byte after param */
-
- send_trans_request(outbuf,SMBtrans2,NULL,FID_UNUSED,0,
- NULL,param,&setup,
- 0,12+strlen(mask)+1,1,
- BUFFER_SIZE,10,0);
-
- if (!receive_trans_response(inbuf,SMBtrans2,
- &resp_data_len,&resp_param_len,
- &resp_data,&resp_param))
- {
- DEBUG(3,("FIND%s gave %s\n",First?"FIRST":"NEXT",smb_errstr(inbuf)));
- break;
- }
-
- /* parse out some important return info */
- p = resp_param;
- if (First)
- {
- ff_dir_handle = SVAL(p,0);
- ff_searchcount = SVAL(p,2);
- ff_eos = SVAL(p,4);
- ff_lastname = SVAL(p,8);
- }
- else
- {
- ff_searchcount = SVAL(p,0);
- ff_eos = SVAL(p,2);
- ff_lastname = SVAL(p,6);
- }
-
- if (ff_searchcount == 0)
- break;
-
- /* point to the data bytes */
- p = resp_data;
-
- /* we might need the lastname for continuations */
- if (ff_lastname > 0)
- {
- switch(info_level)
- {
- case 260:
- ff_resume_key =0;
- StrnCpy(mask,p+ff_lastname,resp_data_len-ff_lastname);
- /* strcpy(mask,p+ff_lastname+94); */
- break;
- case 1:
- strcpy(mask,p + ff_lastname + 1);
- ff_resume_key = 0;
- break;
- }
- }
- else
- strcpy(mask,"");
-
- /* and add them to the dirlist pool */
- dirlist = Realloc(dirlist,dirlist_len + resp_data_len);
-
- if (!dirlist)
- {
- DEBUG(0,("Failed to expand dirlist\n"));
- break;
- }
-
- /* put in a length for the last entry, to ensure we can chain entries
- into the next packet */
- {
- char *p2;
- for (p2=p,i=0;i<(ff_searchcount-1);i++)
- p2 += interpret_long_filename(info_level,p2,NULL);
- SSVAL(p2,0,resp_data_len - PTR_DIFF(p2,p));
- }
-
- /* grab the data for later use */
- memcpy(dirlist+dirlist_len,p,resp_data_len);
- dirlist_len += resp_data_len;
-
- total_received += ff_searchcount;
-
- if (resp_data) free(resp_data); resp_data = NULL;
- if (resp_param) free(resp_param); resp_param = NULL;
-
- DEBUG(3,("received %d entries (eos=%d resume=%d)\n",
- ff_searchcount,ff_eos,ff_resume_key));
-
- First = False;
- }
-
- if (!fn)
- for (p=dirlist,i=0;i<total_received;i++)
- {
- p += interpret_long_filename(info_level,p,&finfo);
- display_finfo(&finfo);
- }
-
- for (p=dirlist,i=0;i<total_received;i++)
- {
- p += interpret_long_filename(info_level,p,&finfo);
- dir_action(inbuf,outbuf,attribute,&finfo,recurse_dir,fn,True);
- }
-
- /* free up the dirlist buffer */
- if (dirlist) free(dirlist);
- return(total_received);
-}
-
/****************************************************************************
get a directory listing
@@ -2131,13 +2135,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;
}
@@ -2670,7 +2673,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;
@@ -3032,7 +3035,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 +3185,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 +3245,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_vwv1);
+ }
+ else {
+ max_xmit = MIN(max_xmit,BUFFER_SIZE-4);
+ if (max_xmit <= 0)
+ max_xmit = BUFFER_SIZE - 4;
- cnum = SVAL(inbuf,smb_tid);
+ cnum = SVAL(inbuf,smb_tid);
+ }
DEBUG(3,("Connected with cnum=%d max_xmit=%d\n",cnum,max_xmit));
@@ -3572,6 +3599,7 @@ static BOOL list_servers()
pstring param;
int uLevel = 1;
int count = 0;
+ BOOL ok = False;
/* now send a SMBtrans command with api ServerEnum? */
p = param;
@@ -3618,7 +3646,8 @@ static BOOL list_servers()
printf("\t%-16.16s %s\n",
sname,
comment_offset?rdata+comment_offset-converter:"");
-
+
+ ok=True;
p2 += 26;
}
}
@@ -3656,6 +3685,7 @@ static BOOL list_servers()
sname,
comment_offset?rdata+comment_offset-converter:"");
+ ok=True;
p2 += 26;
}
}
@@ -3664,7 +3694,7 @@ static BOOL list_servers()
if (rparam) free(rparam);
if (rdata) free(rdata);
- return(count>0);
+ return(ok);
}
@@ -3975,10 +4005,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 +4024,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 +4121,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 +4144,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 +4158,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;
@@ -4112,6 +4181,8 @@ int main(int argc,char *argv[])
TimeInit();
charset_initialise();
+ ipzero = *interpret_addr2("0.0.0.0");
+
pid = getpid();
uid = getuid();
gid = getgid();
@@ -4172,10 +4243,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,"B:O:M:i:Nn:d:Pp:l:hI:EB:U:L:t:m:W:T:D:c:")) != EOF)
switch (opt)
{
case 'm':
@@ -4258,19 +4328,23 @@ 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 '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);
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..2de09c66c11 100644
--- a/source/client/clitar.c
+++ b/source/client/clitar.c
@@ -23,12 +23,6 @@
#include "includes.h"
#include "clitar.h"
-extern void setup_pkt(char *outbuf);
-extern BOOL reopen_connection(char *inbuf,char *outbuf);
-extern void do_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir);
-
-int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind);
-
extern BOOL recurse;
#define SEPARATORS " \t\n\r"
@@ -591,7 +585,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);
@@ -1655,7 +1649,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/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..5b29b275475 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,9 @@ Here come some platform specific sections
#define USE_SETSID
#define HAVE_BZERO
#define HAVE_MEMMOVE
+#if _LINUX_C_LIB_VERSION_MAJOR >= 5
+#define USE_SETFS
+#endif
#ifdef SHADOW_PWD
#ifndef crypt
#define crypt pw_encrypt
@@ -481,7 +463,6 @@ char *mktemp(char *); /* No standard include */
#include <netinet/ip.h>
#define SIGNAL_CAST (void (*)())
#define USE_DIRECT
-#define REPLACE_INNETGR
#endif
@@ -500,6 +481,8 @@ char *mktemp(char *); /* No standard include */
#define USE_WAITPID
#define SIGNAL_CAST (void (*)())
#define DEFAULT_PRINTING PRINT_AIX
+/* we undef this because sys/param.h is broken in aix. uggh. */
+#undef MAXHOSTNAMELEN
#endif
@@ -548,6 +531,32 @@ char *mktemp(char *); /* No standard include */
#define USE_DIRECT
#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>
@@ -734,7 +743,6 @@ char *strdup (char *);
#endif /* DNIX */
#ifdef CONVEX
-#define SIGNAL_CAST (void (*)(int))
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <dirent.h>
@@ -977,6 +985,8 @@ extern char *sys_errlist[];
#include "version.h"
#include "smb.h"
+#include "nameserv.h"
+#include "proto.h"
#include "byteorder.h"
#ifdef SMB_PASSWD
#include "smbpass.h"
diff --git a/source/include/local.h b/source/include/local.h
index 2775453e150..2cfacd66b39 100644
--- a/source/include/local.h
+++ b/source/include/local.h
@@ -83,12 +83,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 +130,7 @@
#define IDLE_CLOSED_TIMEOUT (60)
#define DPTR_IDLE_TIMEOUT (120)
#define SMBD_SELECT_LOOP (10)
-#define NMBD_SELECT_LOOP (10)
+#define NMBD_SELECT_LOOP (2)
#define BROWSE_INTERVAL (60)
#define REGISTRATION_INTERVAL (10*60)
#define NMBD_INETD_TIMEOUT (120)
@@ -163,5 +157,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..32ee625fa4f 100644
--- a/source/include/nameserv.h
+++ b/source/include/nameserv.h
@@ -20,16 +20,57 @@
*/
-#define MAX_DGRAM_SIZE 576
+/* NTAS uses 2, NT uses 1, WfWg uses 0 */
+#define MAINTAIN_LIST 2
+#define ELECTION_VERSION 1
+
+#define MAX_DGRAM_SIZE (80*18+64)
#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
+#define NMB_REL 0x06
+
+#define NB_GROUP 0x80
+#define NB_PERM 0x02
+#define NB_ACTIVE 0x04
+#define NB_CONFL 0x08
+#define NB_DEREG 0x10
+#define NB_BFLAG 0x00
+#define NB_PFLAG 0x20
+#define NB_MFLAG 0x40
+#define NB__FLAG 0x60
+#define NB_FLGMSK 0x60
+
+#define REFRESH_TIME (15*60)
-enum name_source {LMHOSTS, REGISTER, SELF, DNS, DNSFAIL};
+#define NAME_PERMANENT(p) ((p) & NB_PERM)
+#define NAME_ACTIVE(p) ((p) & NB_ACTIVE)
+#define NAME_CONFLICT(p) ((p) & NB_CONFL)
+#define NAME_DEREG(p) ((p) & NB_DEREG)
+#define NAME_GROUP(p) ((p) & NB_GROUP)
+
+#define NAME_BFLAG(p) (((p) & NB_FLGMSK) == NB_BFLAG)
+#define NAME_PFLAG(p) (((p) & NB_FLGMSK) == NB_PFLAG)
+#define NAME_MFLAG(p) (((p) & NB_FLGMSK) == NB_MFLAG)
+#define NAME__FLAG(p) (((p) & NB_FLGMSK) == NB__FLAG)
+
+enum name_source {STATUS_QUERY, LMHOSTS, REGISTER, SELF, DNS, DNSFAIL};
enum node_type {B_NODE=0, P_NODE=1, M_NODE=2, NBDD_NODE=3};
enum packet_type {NMB_PACKET, DGRAM_PACKET};
+enum cmd_type
+{
+ NAME_STATUS_MASTER_CHECK,
+ NAME_STATUS_CHECK,
+ MASTER_SERVER_CHECK,
+ SERVER_CHECK,
+ FIND_MASTER,
+ CHECK_MASTER,
+ NAME_REGISTER,
+ NAME_RELEASE,
+ NAME_CONFIRM_QUERY
+};
/* a netbios name structure */
struct nmb_name {
@@ -46,32 +87,73 @@ struct name_record
struct nmb_name name;
time_t death_time;
struct in_addr ip;
- BOOL unique;
+ int nb_flags;
enum name_source source;
};
-/* this is used by the list of domains */
-struct domain_record
+/* browse and backup server cache for synchronising browse list */
+struct browse_cache_record
{
- struct domain_record *next;
- struct domain_record *prev;
- fstring name;
- time_t lastannounce_time;
- int announce_interval;
- struct in_addr bcast_ip;
+ struct browse_cache_record *next;
+ struct browse_cache_record *prev;
+
+ pstring name;
+ int type;
+ pstring group;
+ struct in_addr ip;
+ time_t sync_time;
+ BOOL synced;
};
-/* this is used to hold the list of servers in my domain */
+/* this is used to hold the list of servers in my domain, and is */
+/* contained within lists of domains */
struct server_record
{
struct server_record *next;
struct server_record *prev;
- fstring name;
- fstring comment;
- uint32 servertype;
+
+ struct server_info_struct serv;
time_t death_time;
};
+/* a workgroup structure. it contains a list of servers */
+struct work_record
+{
+ struct work_record *next;
+ struct work_record *prev;
+
+ struct server_record *serverlist;
+
+ /* work group info */
+ fstring work_group;
+ int token; /* used when communicating with backup browsers */
+ int ServerType;
+
+ /* announce info */
+ time_t lastannounce_time;
+ int announce_interval;
+ BOOL needannounce;
+
+ /* election info */
+ BOOL RunningElection;
+ BOOL needelection;
+ int ElectionCount;
+ uint32 ElectionCriterion;
+};
+
+/* a domain structure. it contains a list of workgroups */
+struct domain_record
+{
+ struct domain_record *next;
+ struct domain_record *prev;
+
+ struct work_record *workgrouplist;
+
+ struct in_addr bcast_ip;
+ struct in_addr mask_ip;
+ struct in_addr myip;
+};
+
/* a resource record */
struct res_rec {
struct nmb_name rr_name;
@@ -115,6 +197,25 @@ struct nmb_packet
};
+/* initiated name queries recorded in this list to track any responses... */
+struct name_response_record
+{
+ struct name_response_record *next;
+ struct name_response_record *prev;
+
+ uint16 response_id;
+ enum cmd_type cmd_type;
+
+ int fd;
+ struct nmb_name name;
+ BOOL bcast;
+ BOOL recurse;
+ struct in_addr to_ip;
+
+ time_t start_time;
+ int num_msgs;
+};
+
/* a datagram - this normally contains SMB data in the data[] array */
struct dgram_packet {
struct {
@@ -154,31 +255,19 @@ 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;
-};
+#define AM_MASTER(work) (work->ServerType & SV_TYPE_MASTER_BROWSER)
+#define AM_BACKUP(work) (work->ServerType & SV_TYPE_BACKUP_BROWSER)
+#define AM_DOMCTL(work) (work->ServerType & SV_TYPE_DOMAIN_CTRL)
+
+#define 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
-/* 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..a3f522b2740
--- /dev/null
+++ b/source/include/proto.h
@@ -0,0 +1,512 @@
+BOOL check_access(int snum);
+BOOL allow_access(char *deny_list,char *allow_list,struct from_host *client);
+BOOL fromhost(int sock,struct from_host *f);
+char *unix2dos_format(char *str,BOOL overwrite);
+char *dos2unix_format(char *str, BOOL overwrite);
+int interpret_character_set(char *str, int def);
+void charset_initialise(void);
+void add_char_string(char *s);
+BOOL chat_with_program(char *passwordprogram,char *name,char *chatsequence);
+BOOL chgpasswd(char *name,char *oldpass,char *newpass);
+BOOL chgpasswd(char *name,char *oldpass,char *newpass);
+void setup_pkt(char *outbuf);
+void do_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir);
+void cmd_help(void);
+BOOL reopen_connection(char *inbuf,char *outbuf);
+char *smb_errstr(char *inbuf);
+void cli_setup_pkt(char *outbuf);
+BOOL cli_receive_trans_response(char *inbuf,int trans,int *data_len,
+ int *param_len, char **data,char **param);
+BOOL cli_send_session_request(char *inbuf, char *outbuf);
+BOOL cli_send_login(char *inbuf, char *outbuf, BOOL start_session, BOOL use_setup);
+void cli_send_logout(void);
+BOOL cli_call_api(int prcnt,int drcnt,int mprcnt,int mdrcnt,int *rprcnt,
+ int *rdrcnt, char *param,char *data, char **rparam,char **rdata);
+BOOL cli_send_trans_request(char *outbuf, int trans, char *name, int fid, int flags,
+ char *data,char *param,uint16 *setup, int ldata,int lparam,
+ int lsetup,int mdata,int mparam,int msetup);
+BOOL cli_open_sockets(int port);
+BOOL cli_reopen_connection(char *inbuf,char *outbuf);
+char *smb_errstr(char *inbuf);
+int strslashcmp(const char *s1, const char *s2);
+void cmd_block(void);
+void cmd_tarmode(void);
+void cmd_setmode(void);
+void cmd_tar(char *inbuf, char *outbuf);
+int process_tar(char *inbuf, char *outbuf);
+int clipfind(char **aret, int ret, char *tok);
+int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind);
+void init_dptrs(void);
+char *dptr_path(int key);
+char *dptr_wcard(int key);
+BOOL dptr_set_wcard(int key, char *wcard);
+BOOL dptr_set_attr(int key, uint16 attr);
+uint16 dptr_attr(int key);
+void dptr_close(int key);
+void dptr_closecnum(int cnum);
+void dptr_idlecnum(int cnum);
+void dptr_closepath(char *path,int pid);
+int dptr_create(int cnum,char *path, BOOL expect_close,int pid);
+BOOL dptr_fill(char *buf1,unsigned int key);
+BOOL dptr_zero(char *buf);
+void *dptr_fetch(char *buf,int *num);
+void *dptr_fetch_lanman2(char *params,int dptr_num);
+BOOL 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);
+void fault_setup(void (*fn)());
+char *getsmbpass(char *prompt) ;
+int reply_trans(char *inbuf,char *outbuf);
+int interpret_coding_system(char *str, int def);
+char *lp_string(char *s);
+BOOL lp_add_home(char *pszHomename, int iDefaultService, char *pszHomedir);
+int lp_add_service(char *pszService, int iDefaultService);
+BOOL lp_add_printer(char *pszPrintername, int iDefaultService);
+BOOL lp_file_list_changed(void);
+BOOL lp_snum_ok(int iService);
+BOOL lp_loaded(void);
+void lp_killunused(BOOL (*snumused)(int ));
+BOOL lp_load(char *pszFname,BOOL global_only);
+int lp_numservices(void);
+void lp_dump(void);
+int lp_servicenumber(char *pszServiceName);
+char *my_workgroup(void);
+char *volume_label(int snum);
+BOOL is_locked(int fnum,int cnum,uint32 count,uint32 offset);
+BOOL do_lock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode);
+BOOL do_unlock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode);
+int get_share_mode_by_fnum(int cnum,int fnum,int *pid);
+int get_share_mode_byname(int cnum,char *fname,int *pid);
+int get_share_mode(int cnum,struct stat *sbuf,int *pid);
+void del_share_mode(int fnum);
+BOOL set_share_mode(int fnum,int mode);
+void clean_share_files(void);
+int str_checksum(char *s);
+BOOL is_8_3(char *fname);
+void create_mangled_stack(int size);
+BOOL check_mangled_stack(char *s);
+BOOL is_mangled(char *s);
+void mangle_name_83(char *s);
+BOOL name_map_mangle(char *OutName,BOOL need83,int snum);
+int reply_sends(char *inbuf,char *outbuf);
+int reply_sendstrt(char *inbuf,char *outbuf);
+int reply_sendtxt(char *inbuf,char *outbuf);
+int reply_sendend(char *inbuf,char *outbuf);
+void announce_request(struct work_record *work, struct in_addr ip);
+void do_announce_request(char *info, char *to_name, int announce_type,
+ int from,
+ int to, struct in_addr dest_ip);
+void announce_backup(void);
+void announce_host(void);
+void announce_master(void);
+struct work_record *remove_workgroup(struct domain_record *d,
+ struct work_record *work);
+void expire_browse_cache(time_t t);
+struct work_record *find_workgroupstruct(struct domain_record *d, fstring name, BOOL add);
+struct domain_record *find_domain(struct in_addr source_ip);
+struct domain_record *add_domain_entry(struct in_addr source_ip,
+ struct in_addr source_mask,
+ char *name, BOOL add);
+struct browse_cache_record *add_browser_entry(char *name, int type, char *wg,
+ time_t ttl, struct in_addr ip);
+struct server_record *add_server_entry(struct domain_record *d,
+ struct work_record *work,
+ char *name,int servertype,
+ int ttl,char *comment,
+ BOOL replace);
+void write_browse_list(void);
+void expire_servers(time_t t);
+void check_master_browser(void);
+void browser_gone(char *work_name, struct in_addr ip);
+void send_election(struct domain_record *d, char *group,uint32 criterion,
+ int timeup,char *name);
+void become_nonmaster(struct domain_record *d, struct work_record *work);
+void run_elections(void);
+void process_election(struct packet_struct *p,char *buf);
+BOOL check_elections(void);
+BOOL name_status(int fd,char *name,int name_type,BOOL recurse,
+ struct in_addr to_ip,char *master,char *rname,
+ void (*fn)());
+BOOL name_query(int fd,char *name,int name_type,
+ BOOL bcast,BOOL recurse,
+ struct in_addr to_ip, struct in_addr *ip,void (*fn)());
+void expire_netbios_response_entries(time_t t);
+void reply_netbios_packet(struct packet_struct *p1,int trn_id,int rcode,int opcode,
+ struct nmb_name *rr_name,int rr_type,int rr_class,int ttl,
+ char *data,int len);
+uint16 initiate_netbios_packet(int fd,int quest_type,char *name,int name_type,
+ int nb_flags,BOOL bcast,BOOL recurse,struct in_addr to_ip);
+void queue_netbios_pkt_wins(int fd,int quest_type,enum cmd_type cmd,
+ char *name,int name_type,int nb_flags,
+ BOOL bcast,BOOL recurse,struct in_addr to_ip);
+void queue_netbios_packet(int fd,int quest_type,enum cmd_type cmd,char *name,
+ int name_type,int nb_flags,BOOL bcast,BOOL recurse,
+ struct in_addr to_ip);
+struct name_response_record *find_name_query(uint16 id);
+void queue_packet(struct packet_struct *packet);
+void run_packet_queue();
+void listen_for_packets(BOOL run_election);
+BOOL interpret_node_status(char *p, struct nmb_name *name,int t,
+ char *serv_name, struct in_addr ip);
+BOOL send_mailslot_reply(char *mailslot,int fd,char *buf,int len,char *srcname,
+ char *dstname,int src_type,int dest_type,
+ struct in_addr dest_ip,struct in_addr src_ip);
+void remove_name(struct name_record *n);
+void dump_names(void);
+void remove_netbios_name(char *name,int type, enum name_source source,
+ struct in_addr ip);
+struct name_record *add_netbios_entry(char *name, int type, int nb_flags, int ttl,
+ enum name_source source, struct in_addr ip);
+void remove_name_entry(char *name,int type);
+void add_name_entry(char *name,int type,int nb_flags);
+void add_my_names(void);
+void refresh_my_names(time_t t);
+void expire_names(time_t t);
+void response_name_release(struct packet_struct *p);
+void reply_name_release(struct packet_struct *p);
+void response_name_reg(struct packet_struct *p);
+void reply_name_reg(struct packet_struct *p);
+void reply_name_status(struct packet_struct *p);
+struct name_record *search_for_name(struct nmb_name *question,
+ struct in_addr ip, int Time, int search);
+void process_nmb(struct packet_struct *p);
+void reset_server(char *name, int state, struct in_addr ip);
+void tell_become_backup(void);
+void do_browser_lists(void);
+void sync_server(enum cmd_type cmd, char *serv_name, char *work_name,
+ int name_type,
+ struct in_addr ip);
+void update_from_reg(char *name, int type, struct in_addr ip);
+void add_my_domains(void);
+BOOL same_context(struct dgram_packet *dgram);
+BOOL listening_name(struct work_record *work, struct nmb_name *n);
+void process_logon_packet(struct packet_struct *p,char *buf,int len);
+BOOL listening_type(struct packet_struct *p, int command);
+void process_browse_packet(struct packet_struct *p,char *buf,int len);
+void process_dgram(struct packet_struct *p);
+BOOL reload_services(BOOL test);
+void debug_nmb_packet(struct packet_struct *p);
+char *namestr(struct nmb_name *n);
+void free_nmb_packet(struct nmb_packet *nmb);
+void free_packet(struct packet_struct *packet);
+struct packet_struct *read_packet(int fd,enum packet_type packet_type);
+void make_nmb_name(struct nmb_name *n,char *name,int type,char *this_scope);
+BOOL send_packet(struct packet_struct *p);
+struct packet_struct *receive_packet(int fd,enum packet_type type,int t);
+int main(int argc,char *argv[]);
+char *getsmbpass(char *pass);
+void sync_browse_lists(struct work_record *work, char *name, int nm_type,
+ struct in_addr ip);
+BOOL pm_process(char *pszFileName,BOOL (*sfunc)(char *),BOOL (*pfunc)(char *,char *));
+void generate_next_challenge(char *challenge);
+BOOL set_challenge(char *challenge);
+BOOL last_challenge(char *challenge);
+int valid_uid(int uid);
+user_struct *get_valid_user_struct(int uid);
+void invalidate_uid(int uid);
+char *validated_username(int vuid);
+void register_uid(int uid,int gid, char *name,BOOL guest);
+void add_session_user(char *user);
+void dfs_unlogin(void);
+BOOL password_check(char *password);
+BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned char *c8);
+BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd, BOOL is_nt_password);
+BOOL user_ok(char *user,int snum);
+BOOL authorise_login(int snum,char *user,char *password, int pwlen,
+ BOOL *guest,BOOL *force,int vuid);
+BOOL check_hosts_equiv(char *user);
+BOOL server_cryptkey(char *buf);
+BOOL server_validate(char *buf);
+BOOL pcap_printername_ok(char *pszPrintername, char *pszPrintcapname);
+void pcap_printer_fn(void (*fn)());
+void lpq_reset(int snum);
+void print_file(int fnum);
+int get_printqueue(int snum,int cnum,print_queue_struct **queue,
+ print_status_struct *status);
+void del_printqueue(int cnum,int snum,int jobid);
+void status_printjob(int cnum,int snum,int jobid,int status);
+int reply_special(char *inbuf,char *outbuf);
+int reply_tcon(char *inbuf,char *outbuf);
+int reply_tcon_and_X(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_unknown(char *inbuf,char *outbuf);
+int reply_ioctl(char *inbuf,char *outbuf);
+int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_chkpth(char *inbuf,char *outbuf);
+int reply_getatr(char *inbuf,char *outbuf);
+int reply_setatr(char *inbuf,char *outbuf);
+int reply_dskattr(char *inbuf,char *outbuf);
+int reply_search(char *inbuf,char *outbuf);
+int reply_fclose(char *inbuf,char *outbuf);
+int reply_open(char *inbuf,char *outbuf);
+int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_ulogoffX(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_mknew(char *inbuf,char *outbuf);
+int reply_ctemp(char *inbuf,char *outbuf);
+int reply_unlink(char *inbuf,char *outbuf);
+int reply_readbraw(char *inbuf, char *outbuf);
+int reply_lockread(char *inbuf,char *outbuf);
+int reply_read(char *inbuf,char *outbuf);
+int reply_read_and_X(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_writebraw(char *inbuf,char *outbuf);
+int reply_writeunlock(char *inbuf,char *outbuf);
+int reply_write(char *inbuf,char *outbuf,int dum1,int dum2);
+int reply_write_and_X(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_lseek(char *inbuf,char *outbuf);
+int reply_flush(char *inbuf,char *outbuf);
+int reply_exit(char *inbuf,char *outbuf);
+int reply_close(char *inbuf,char *outbuf);
+int reply_writeclose(char *inbuf,char *outbuf);
+int reply_lock(char *inbuf,char *outbuf);
+int reply_unlock(char *inbuf,char *outbuf);
+int reply_tdis(char *inbuf,char *outbuf);
+int reply_echo(char *inbuf,char *outbuf);
+int reply_printopen(char *inbuf,char *outbuf);
+int reply_printclose(char *inbuf,char *outbuf);
+int reply_printqueue(char *inbuf,char *outbuf);
+int reply_printwrite(char *inbuf,char *outbuf);
+int reply_mkdir(char *inbuf,char *outbuf);
+int reply_rmdir(char *inbuf,char *outbuf);
+int reply_mv(char *inbuf,char *outbuf);
+int reply_copy(char *inbuf,char *outbuf);
+int reply_setdir(char *inbuf,char *outbuf);
+int reply_lockingX(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_readbmpx(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_writebmpx(char *inbuf,char *outbuf);
+int reply_writebs(char *inbuf,char *outbuf);
+int reply_setattrE(char *inbuf,char *outbuf);
+int reply_getattrE(char *inbuf,char *outbuf);
+mode_t unix_mode(int cnum,int dosmode);
+int dos_mode(int cnum,char *path,struct stat *sbuf);
+int dos_chmod(int cnum,char *fname,int dosmode,struct stat *st);
+BOOL unix_convert(char *name,int cnum);
+int disk_free(char *path,int *bsize,int *dfree,int *dsize);
+int sys_disk_free(char *path,int *bsize,int *dfree,int *dsize);
+BOOL check_name(char *name,int cnum);
+void open_file(int fnum,int cnum,char *fname1,int flags,int mode);
+void sync_file(int fnum);
+void close_file(int fnum);
+BOOL check_file_sharing(int cnum,char *fname);
+void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
+ int mode,int *Access,int *action);
+int seek_file(int fnum,int pos);
+int read_file(int fnum,char *data,int pos,int mincnt,int maxcnt,int timeout,BOOL exact);
+int write_file(int fnum,char *data,int n);
+BOOL become_service(int cnum,BOOL do_chdir);
+int find_service(char *service);
+int cached_error_packet(char *inbuf,char *outbuf,int fnum,int line);
+int unix_error_packet(char *inbuf,char *outbuf,int def_class,uint32 def_code,int line);
+int error_packet(char *inbuf,char *outbuf,int error_class,uint32 error_code,int line);
+BOOL snum_used(int snum);
+BOOL reload_services(BOOL test);
+int setup_groups(char *user, int uid, int gid, int *p_ngroups,
+ int **p_igroups, gid_t **p_groups);
+int make_connection(char *service,char *user,char *password, int pwlen, char *dev,int vuid);
+int find_free_file(void );
+int reply_corep(char *outbuf);
+int reply_coreplus(char *outbuf);
+int reply_lanman1(char *outbuf);
+int reply_lanman2(char *outbuf);
+int reply_nt1(char *outbuf);
+void parse_connect(char *buf,char *service,char *user,char *password,int *pwlen,char *dev);
+void close_cnum(int cnum, int uid);
+BOOL yield_connection(int cnum,char *name,int max_connections);
+BOOL claim_connection(int cnum,char *name,int max_connections,BOOL Clear);
+void exit_server(char *reason);
+void standard_sub(int cnum,char *s);
+char *smb_fn_name(int type);
+int chain_reply(int type,char *inbuf,char *inbuf2,char *outbuf,char *outbuf2,int size,int bufsize);
+int construct_reply(char *inbuf,char *outbuf,int size,int bufsize);
+void str_to_key(uchar *str,uchar *key);
+void D1(uchar *k, uchar *d, uchar *out);
+void E1(uchar *k, uchar *d, uchar *out);
+void E_P16(uchar *p14,uchar *p16);
+void E_P24(uchar *p21, uchar *c8, uchar *p24);
+void SMBencrypt(uchar *passwd, uchar *c8, uchar *p24);
+void E_md4hash(uchar *passwd, uchar *p16);
+void SMBNTencrypt(uchar *passwd, uchar *c8, uchar *p24);
+void Ucrit_addUsername(pstring username);
+unsigned int Ucrit_checkUsername(pstring username);
+void Ucrit_addPid(int pid);
+unsigned int Ucrit_checkPid(int pid);
+int sys_select(fd_set *fds,struct timeval *tval);
+int sys_select(fd_set *fds,struct timeval *tval);
+int sys_unlink(char *fname);
+int sys_open(char *fname,int flags,int mode);
+DIR *sys_opendir(char *dname);
+int sys_stat(char *fname,struct stat *sbuf);
+int sys_lstat(char *fname,struct stat *sbuf);
+int sys_mkdir(char *dname,int mode);
+int sys_rmdir(char *dname);
+int sys_chdir(char *dname);
+int sys_utime(char *fname,struct utimbuf *times);
+int sys_rename(char *from, char *to);
+int sys_chown(char *fname,int uid,int gid);
+int sys_chroot(char *dname);
+int main(int argc, char *argv[]);
+void GetTimeOfDay(struct timeval *tval);
+void TimeInit(void);
+int TimeDiff(time_t t);
+struct tm *LocalTime(time_t *t);
+time_t interpret_long_date(char *p);
+void put_long_date(char *p,time_t t);
+void put_dos_date(char *buf,int offset,time_t unixdate);
+void put_dos_date2(char *buf,int offset,time_t unixdate);
+void put_dos_date3(char *buf,int offset,time_t unixdate);
+time_t make_unix_date(void *date_ptr);
+time_t make_unix_date2(void *date_ptr);
+time_t make_unix_date3(void *date_ptr);
+BOOL set_filetime(char *fname,time_t mtime);
+char *timestring(void );
+int reply_findclose(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_findnclose(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_transs2(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_trans2(char *inbuf,char *outbuf,int length,int bufsize);
+char *ufc_crypt(char *key,char *salt);
+void init_uid(void);
+BOOL become_guest(void);
+BOOL become_user(int cnum, int uid);
+BOOL unbecome_user(void );
+int smbrun(char *cmd,char *outfile);
+char *get_home_dir(char *user);
+void map_username(char *user);
+struct passwd *Get_Pwnam(char *user,BOOL allow_change);
+BOOL user_in_list(char *user,char *list);
+void setup_logging(char *pname,BOOL interactive);
+void reopen_logs(void);
+BOOL fcntl_lock(int fd,int op,uint32 offset,uint32 count,int type);
+int file_lock(char *name,int timeout);
+void file_unlock(int fd);
+BOOL is_a_socket(int fd);
+BOOL next_token(char **ptr,char *buff,char *sep);
+char **toktocliplist(int *ctok, char *sep);
+void *MemMove(void *dest,void *src,int size);
+void array_promote(char *array,int elsize,int element);
+void set_socket_options(int fd, char *options);
+void close_sockets(void );
+BOOL in_group(gid_t group, int current_gid, int ngroups, int *groups);
+char *StrCpy(char *dest,char *src);
+char *StrnCpy(char *dest,const char *src,int n);
+void putip(void *dest,void *src);
+int name_mangle(char *In,char *Out,char name_type);
+BOOL file_exist(char *fname,struct stat *sbuf);
+time_t file_modtime(char *fname);
+BOOL directory_exist(char *dname,struct stat *st);
+uint32 file_size(char *file_name);
+char *attrib_string(int mode);
+int StrCaseCmp(char *s, char *t);
+int StrnCaseCmp(char *s, char *t, int n);
+BOOL strequal(char *s1,char *s2);
+BOOL strnequal(char *s1,char *s2,int n);
+BOOL strcsequal(char *s1,char *s2);
+void strlower(char *s);
+void strupper(char *s);
+void strnorm(char *s);
+BOOL strisnormal(char *s);
+void string_replace(char *s,char oldc,char newc);
+void unix_format(char *fname);
+void dos_format(char *fname);
+void show_msg(char *buf);
+int smb_len(char *buf);
+void _smb_setlen(char *buf,int len);
+void smb_setlen(char *buf,int len);
+int set_message(char *buf,int num_words,int num_bytes,BOOL zero);
+int smb_numwords(char *buf);
+int smb_buflen(char *buf);
+int smb_buf_ofs(char *buf);
+char *smb_buf(char *buf);
+int smb_offset(char *p,char *buf);
+char *skip_string(char *buf,int n);
+BOOL trim_string(char *s,char *front,char *back);
+void dos_clean_name(char *s);
+void unix_clean_name(char *s);
+int ChDir(char *path);
+char *GetWd(char *str);
+BOOL reduce_name(char *s,char *dir,BOOL widelinks);
+void expand_mask(char *Mask,BOOL doext);
+BOOL strhasupper(char *s);
+BOOL strhaslower(char *s);
+int count_chars(char *s,char c);
+void make_dir_struct(char *buf,char *mask,char *fname,unsigned int size,int mode,time_t date);
+void close_low_fds(void);
+int write_socket(int fd,char *buf,int len);
+int read_udp_socket(int fd,char *buf,int len);
+int set_blocking(int fd, BOOL set);
+int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out,BOOL exact);
+int read_max_udp(int fd,char *buffer,int bufsize,int maxtime);
+int TvalDiff(struct timeval *tvalold,struct timeval *tvalnew);
+BOOL send_keepalive(int client);
+int read_data(int fd,char *buffer,int N);
+int write_data(int fd,char *buffer,int N);
+int read_predict(int fd,int offset,char *buf,char **ptr,int num);
+void do_read_prediction();
+void invalidate_read_prediction(int fd);
+int transfer_file(int infd,int outfd,int n,char *header,int headlen,int align);
+int read_smb_length(int fd,char *inbuf,int timeout);
+BOOL receive_smb(int fd,char *buffer,int timeout);
+BOOL send_smb(int fd,char *buffer);
+char *name_ptr(char *buf,int ofs);
+int name_extract(char *buf,int ofs,char *name);
+int name_len(char *s);
+BOOL send_one_packet(char *buf,int len,struct in_addr ip,int port,int type);
+void msleep(int t);
+BOOL in_list(char *s,char *list,BOOL casesensitive);
+BOOL string_init(char **dest,char *src);
+void string_free(char **s);
+BOOL string_set(char **dest,char *src);
+BOOL string_sub(char *s,char *pattern,char *insert);
+BOOL do_match(char *str, char *regexp, int case_sig);
+BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2);
+void become_daemon(void);
+void get_broadcast(struct in_addr *if_ipaddr,
+ struct in_addr *if_bcast,
+ struct in_addr *if_nmask);
+BOOL yesno(char *p);
+char *fgets_slash(char *s2,int maxlen,FILE *f);
+int set_filelen(int fd, long len);
+int byte_checksum(char *buf,int len);
+char *dirname_dos(char *path,char *buf);
+void *Realloc(void *p,int size);
+void Abort(void );
+BOOL get_myname(char *myname,struct in_addr *ip);
+BOOL ip_equal(struct in_addr ip1,struct in_addr ip2);
+int open_socket_in(int type, int port, int dlevel);
+int open_socket_out(int type, struct in_addr *addr, int port );
+int interpret_protocol(char *str,int def);
+int interpret_security(char *str,int def);
+unsigned long interpret_addr(char *str);
+struct in_addr *interpret_addr2(char *str);
+BOOL zero_ip(struct in_addr ip);
+void standard_sub_basic(char *s);
+BOOL same_net(struct in_addr ip1,struct in_addr ip2,struct in_addr mask);
+int PutUniCode(char *dst,char *src);
+struct hostent *Get_Hostbyname(char *name);
+BOOL process_exists(int pid);
+char *uidtoname(int uid);
+char *gidtoname(int gid);
+void BlockSignals(BOOL block);
+void ajt_panic(void);
+char *readdirname(void *p);
+void *malloc_wrapped(int size,char *file,int line);
+void *realloc_wrapped(void *ptr,int size,char *file,int line);
+void free_wrapped(void *ptr,char *file,int line);
+char *Strstr(char *s, char *p);
+time_t Mktime(struct tm *t);
+int InNetGr(char *group,char *host,char *user,char *dom);
+void *memcpy_wrapped(void *d,void *s,int l,char *fname,int line);
+int VT_Check(char *buffer);
+int VT_Start_utmp(void);
+int VT_Stop_utmp(void);
+void VT_AtExit(void);
+void VT_SigCLD(int sig);
+void VT_SigEXIT(int sig);
+int VT_Start(void);
+int VT_Output(char *Buffer);
+int VT_Input(char *Buffer,int Size);
+void VT_Process(void);
diff --git a/source/include/smb.h b/source/include/smb.h
index b7faffa9e92..0be860d6a36 100644
--- a/source/include/smb.h
+++ b/source/include/smb.h
@@ -40,6 +40,10 @@
# define EXTERN extern
#endif
+#define NMB_PORT 137
+#define DGRAM_PORT 138
+#define SMB_PORT 139
+
#define False (0)
#define True (1)
#define BOOLSTR(b) ((b) ? "Yes" : "No")
@@ -72,6 +76,19 @@ typedef unsigned short uint16;
typedef unsigned int uint32;
#endif
+#ifndef uchar
+#define uchar unsigned char
+#endif
+#ifndef int16
+#define int16 short
+#endif
+#ifndef uint16
+#define uint16 unsigned short
+#endif
+#ifndef uint32
+#define uint32 unsigned int
+#endif
+
#define SIZEOFWORD 2
#ifndef DEF_CREATE_MASK
@@ -216,6 +233,15 @@ typedef char pstring[1024];
typedef char fstring[128];
typedef fstring string;
+
+struct current_user {
+ int cnum, id;
+ int uid, gid;
+ int ngroups;
+ gid_t *groups;
+ int *igroups;
+};
+
typedef struct
{
int size;
@@ -332,6 +358,16 @@ typedef struct
int status;
} print_status_struct;
+/* used for server information: client, nameserv and ipc */
+struct server_info_struct
+{
+ fstring name;
+ uint32 type;
+ fstring comment;
+ fstring domain; /* used ONLY in ipc.c NOT namework.c */
+ BOOL server_added; /* used ONLY in ipc.c NOT namework.c */
+};
+
/* this is used for smbstatus */
struct connect_record
@@ -582,282 +618,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 +749,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..5244a1d9198 100644
--- a/source/include/version.h
+++ b/source/include/version.h
@@ -1 +1 @@
-#define VERSION "1.9.16alpha1"
+#define VERSION "1.9.16alpha6"
diff --git a/source/lib/charcnv.c b/source/lib/charcnv.c
index 049390f2a43..d9ee551d6a8 100644
--- a/source/lib/charcnv.c
+++ b/source/lib/charcnv.c
@@ -71,8 +71,7 @@ static void initiso() {
/*
* Convert unix to dos
*/
-char *
-unix2dos_format(char *str,BOOL overwrite)
+char *unix2dos_format(char *str,BOOL overwrite)
{
char *p;
char *dp;
@@ -91,8 +90,7 @@ unix2dos_format(char *str,BOOL overwrite)
/*
* Convert dos to unix
*/
-char *
-dos2unix_format (char *str, BOOL overwrite)
+char *dos2unix_format(char *str, BOOL overwrite)
{
char *p;
char *dp;
@@ -112,8 +110,7 @@ dos2unix_format (char *str, BOOL overwrite)
/*
* Interpret character set.
*/
-int
-interpret_character_set (char *str, int def)
+int interpret_character_set(char *str, int def)
{
if (strequal (str, "iso8859-1")) {
diff --git a/source/lib/getsmbpass.c b/source/lib/getsmbpass.c
index 07a7dbfd9b5..7ee8c187885 100644
--- a/source/lib/getsmbpass.c
+++ b/source/lib/getsmbpass.c
@@ -40,12 +40,12 @@ static struct termio t;
#define TCSANOW 0
#endif
-int tcgetattr(int fd, struct termio *t)
+ int tcgetattr(int fd, struct termio *t)
{
return ioctl(fd, TCGETA, t);
}
-int tcsetattr(int fd, int flags, const struct termio *t)
+ int tcsetattr(int fd, int flags, const struct termio *t)
{
if(flags & TCSAFLUSH)
ioctl(fd, TCFLSH, TCIOFLUSH);
@@ -71,12 +71,12 @@ static struct sgttyb t;
#define TCSANOW 0
#endif
-int tcgetattr(int fd, struct sgttyb *t)
+ int tcgetattr(int fd, struct sgttyb *t)
{
return ioctl(fd, TIOCGETP, (char *)t);
}
-int tcsetattr(int fd, int flags, const struct sgttyb *t)
+ int tcsetattr(int fd, int flags, const struct sgttyb *t)
{
return ioctl(fd, TIOCSETP, (char *)t);
}
@@ -92,8 +92,7 @@ static struct termios t;
#endif /* BSD_TERMIO */
#endif /* SYSV_TERMIO */
-char *
-getsmbpass(char *prompt)
+char *getsmbpass(char *prompt)
{
FILE *in, *out;
int echo_off;
@@ -162,5 +161,5 @@ getsmbpass(char *prompt)
#else
-void getsmbpasswd_dummy() {;}
+ void getsmbpasswd_dummy() {;}
#endif
diff --git a/source/lib/kanji.c b/source/lib/kanji.c
index 0af476eb157..a77bdea73f0 100644
--- a/source/lib/kanji.c
+++ b/source/lib/kanji.c
@@ -796,8 +796,7 @@ setup_string_function (int codes)
/*
* Interpret coding system.
*/
-int
-interpret_coding_system (char *str, int def)
+int interpret_coding_system(char *str, int def)
{
int codes = def;
@@ -890,6 +889,6 @@ interpret_coding_system (char *str, int def)
return setup_string_function (codes);
}
#else
-int kanji_dummy_procedure(void)
+ int kanji_dummy_procedure(void)
{return 0;}
#endif /* KANJI */
diff --git a/source/lib/md4.c b/source/lib/md4.c
index 485e231a784..bdff075c7e7 100644
--- a/source/lib/md4.c
+++ b/source/lib/md4.c
@@ -295,5 +295,5 @@
** End of md4.c
*/
#else
-void md4_dummy() {;}
+ void md4_dummy() {;}
#endif
diff --git a/source/lib/system.c b/source/lib/system.c
index 938746e9c9d..ac64b37a6fe 100644
--- a/source/lib/system.c
+++ b/source/lib/system.c
@@ -79,7 +79,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++;
}
diff --git a/source/lib/time.c b/source/lib/time.c
new file mode 100644
index 00000000000..0b6e6df9b07
--- /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;
+
+ /* 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;
+ }
+
+ high = low + MAX_DST_WIDTH/2;
+ if (high < t)
+ high = TIME_T_MAX;
+
+ 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..ae48a8776d4 100644
--- a/source/lib/ufc.c
+++ b/source/lib/ufc.c
@@ -777,6 +777,6 @@ ufc_long *_ufc_doit(l1, l2, r1, r2, itr)
#else
-int ufc_dummy_procedure(void)
+ int ufc_dummy_procedure(void)
{return 0;}
#endif
diff --git a/source/lib/util.c b/source/lib/util.c
index 7bd6298c4ca..8c088f306e9 100644
--- a/source/lib/util.c
+++ b/source/lib/util.c
@@ -30,8 +30,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,""};
@@ -151,58 +149,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 +241,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,11 +259,19 @@ va_dcl
if (!lp_syslog_only())
#endif
{
+#ifdef __STDC__
+ va_start(ap, format_str);
+#else
+ va_start(ap);
+ format_str = va_arg(ap,char *);
+#endif
vfprintf(dbf,format_str,ap);
+ va_end(ap);
fflush(dbf);
}
-
- va_end(ap);
+
+ check_log_size();
+
return(0);
}
@@ -390,141 +405,6 @@ void file_unlock(int fd)
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;
-#else
- timediff = mktime(&tm_utc) - mktime(&tm_local);
-#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;
- }
-
- 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;
- }
-
-/*
- 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));
-}
-
-
/****************************************************************************
determine if a file descriptor is in fact a socket
****************************************************************************/
@@ -805,32 +685,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 +887,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 +1820,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);
@@ -2666,12 +2366,11 @@ 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);
- }
+ 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);
@@ -3462,7 +3161,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 +3211,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 +3229,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);
@@ -3572,7 +3259,7 @@ void Abort(void )
/****************************************************************************
a replacement strlen() that returns int for solaris
****************************************************************************/
-int Strlen(char *s)
+ int Strlen(char *s)
{
int ret=0;
if (!s) return(0);
@@ -3582,62 +3269,11 @@ int Strlen(char *s)
#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)
+ int ftruncate(int f,long l)
{
struct flock fl;
@@ -3714,11 +3350,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 +3381,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);
@@ -3893,76 +3525,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 +3569,21 @@ void standard_sub_basic(char *s)
/*******************************************************************
+are two IPs on the same subnet?
+********************************************************************/
+BOOL same_net(struct in_addr ip1,struct in_addr ip2,struct in_addr mask)
+{
+ unsigned long net1,net2,nmask;
+
+ nmask = ntohl(mask.s_addr);
+ net1 = ntohl(ip1.s_addr);
+ net2 = ntohl(ip2.s_addr);
+
+ return((net1 & nmask) == (net2 & nmask));
+}
+
+
+/*******************************************************************
write a string in unicoode format
********************************************************************/
int PutUniCode(char *dst,char *src)
@@ -4022,34 +3599,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
@@ -4182,8 +3731,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
@@ -4263,7 +3811,7 @@ long nap(long milliseconds) {
/****************************************************************************
some systems don't have an initgroups call
****************************************************************************/
-int initgroups(char *name,gid_t id)
+ int initgroups(char *name,gid_t id)
{
#ifdef NO_SETGROUPS
/* yikes! no SETGROUPS or INITGROUPS? how can this work? */
@@ -4447,8 +3995,7 @@ time_t Mktime(struct tm *t)
#ifdef REPLACE_RENAME
/* Rename a file. (from libiberty in GNU binutils) */
-int
-rename (zfrom, zto)
+ int rename (zfrom, zto)
const char *zfrom;
const char *zto;
{
@@ -4469,8 +4016,7 @@ rename (zfrom, zto)
/*
* Search for a match in a netgroup. This replaces it on broken systems.
*/
-int InNetGr(group, host, user, dom)
- char *group, *host, *user, *dom;
+int InNetGr(char *group,char *host,char *user,char *dom)
{
char *hst, *usr, *dm;
diff --git a/source/libsmb/namequery.c b/source/libsmb/namequery.c
new file mode 100644
index 00000000000..d1b1ae7d3e5
--- /dev/null
+++ b/source/libsmb/namequery.c
@@ -0,0 +1,292 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ name query routines
+ Copyright (C) Andrew Tridgell 1994-1995
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+
+extern pstring scope;
+extern int DEBUGLEVEL;
+
+
+/****************************************************************************
+interpret a node status response
+****************************************************************************/
+static void _interpret_node_status(char *p, char *master,char *rname)
+{
+ int level = (master||rname)?4:0;
+ int numnames = CVAL(p,0);
+ DEBUG(level,("received %d names\n",numnames));
+
+ if (rname) *rname = 0;
+ if (master) *master = 0;
+
+ p += 1;
+ while (numnames--)
+ {
+ char qname[17];
+ int type;
+ fstring flags;
+ int i;
+ *flags = 0;
+ StrnCpy(qname,p,15);
+ type = CVAL(p,15);
+ p += 16;
+
+ strcat(flags, (p[0] & 0x80) ? "<GROUP> " : " ");
+ if ((p[0] & 0x60) == 0x00) strcat(flags,"B ");
+ if ((p[0] & 0x60) == 0x20) strcat(flags,"P ");
+ if ((p[0] & 0x60) == 0x40) strcat(flags,"M ");
+ if ((p[0] & 0x60) == 0x60) strcat(flags,"_ ");
+ if (p[0] & 0x10) strcat(flags,"<DEREGISTERING> ");
+ if (p[0] & 0x08) strcat(flags,"<CONFLICT> ");
+ if (p[0] & 0x04) strcat(flags,"<ACTIVE> ");
+ if (p[0] & 0x02) strcat(flags,"<PERMANENT> ");
+
+ if (master && !*master && type == 0x1d) {
+ StrnCpy(master,qname,15);
+ trim_string(master,NULL," ");
+ }
+
+ if (rname && !*rname && type == 0x20 && !(p[0]&0x80)) {
+ StrnCpy(rname,qname,15);
+ trim_string(rname,NULL," ");
+ }
+
+ for (i = strlen( qname) ; --i >= 0 ; ) {
+ if (!isprint(qname[i])) qname[i] = '.';
+ }
+ DEBUG(level,("\t%-15s <%02x> - %s\n",qname,type,flags));
+ p+=2;
+ }
+ DEBUG(level,("num_good_sends=%d num_good_receives=%d\n",
+ IVAL(p,20),IVAL(p,24)));
+}
+
+
+/****************************************************************************
+ do a netbios name status query on a host
+
+ the "master" parameter is a hack used for finding workgroups.
+ **************************************************************************/
+BOOL name_status(int fd,char *name,int name_type,BOOL recurse,
+ struct in_addr to_ip,char *master,char *rname,
+ void (*fn)())
+{
+ BOOL found=False;
+ int retries = 2;
+ int retry_time = 5000;
+ struct timeval tval;
+ struct packet_struct p;
+ struct packet_struct *p2;
+ struct nmb_packet *nmb = &p.packet.nmb;
+ static int name_trn_id = 0;
+
+ bzero((char *)&p,sizeof(p));
+
+ if (!name_trn_id) name_trn_id = (time(NULL)%(unsigned)0x7FFF) +
+ (getpid()%(unsigned)100);
+ name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
+
+ nmb->header.name_trn_id = name_trn_id;
+ nmb->header.opcode = 0;
+ nmb->header.response = False;
+ nmb->header.nm_flags.bcast = False;
+ nmb->header.nm_flags.recursion_available = 0;
+ nmb->header.nm_flags.recursion_desired = 1;
+ nmb->header.nm_flags.trunc = False;
+ nmb->header.nm_flags.authoritative = False;
+ nmb->header.rcode = 0;
+ nmb->header.qdcount = 1;
+ nmb->header.ancount = 0;
+ nmb->header.nscount = 0;
+ nmb->header.arcount = 0;
+
+ make_nmb_name(&nmb->question.question_name,name,name_type,scope);
+
+ nmb->question.question_type = 0x21;
+ nmb->question.question_class = 0x1;
+
+ p.ip = to_ip;
+ p.port = NMB_PORT;
+ p.fd = fd;
+ p.timestamp = time(NULL);
+ p.packet_type = NMB_PACKET;
+
+ GetTimeOfDay(&tval);
+
+ if (!send_packet(&p))
+ return(False);
+
+ retries--;
+
+ while (1)
+ {
+ struct timeval tval2;
+ GetTimeOfDay(&tval2);
+ if (TvalDiff(&tval,&tval2) > retry_time) {
+ if (!retries) break;
+ if (!found && !send_packet(&p))
+ return False;
+ GetTimeOfDay(&tval);
+ retries--;
+ }
+
+ if ((p2=receive_packet(fd,NMB_PACKET,90)))
+ {
+ struct nmb_packet *nmb2 = &p2->packet.nmb;
+ if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
+ !nmb2->header.response) {
+ /* its not for us - maybe deal with it later */
+ if (fn)
+ fn(p2);
+ else
+ free_packet(p2);
+ continue;
+ }
+
+ if (nmb2->header.opcode != 0 ||
+ nmb2->header.nm_flags.bcast ||
+ nmb2->header.rcode ||
+ !nmb2->header.ancount ||
+ nmb2->answers->rr_type != 0x21) {
+ /* XXXX what do we do with this? could be a redirect, but
+ we'll discard it for the moment */
+ free_packet(p2);
+ continue;
+ }
+
+ _interpret_node_status(&nmb2->answers->rdata[0], master,rname);
+ free_packet(p2);
+ return(True);
+ }
+ }
+
+
+ DEBUG(0,("No status response (this is not unusual)\n"));
+
+ return(False);
+}
+
+
+/****************************************************************************
+ do a netbios name query to find someones IP
+ ****************************************************************************/
+BOOL name_query(int fd,char *name,int name_type,
+ BOOL bcast,BOOL recurse,
+ struct in_addr to_ip, struct in_addr *ip,void (*fn)())
+{
+ BOOL found=False;
+ int retries = 3;
+ int retry_time = bcast?250:2000;
+ struct timeval tval;
+ struct packet_struct p;
+ struct packet_struct *p2;
+ struct nmb_packet *nmb = &p.packet.nmb;
+ static int name_trn_id = 0;
+
+ bzero((char *)&p,sizeof(p));
+
+ if (!name_trn_id) name_trn_id = (time(NULL)%(unsigned)0x7FFF) +
+ (getpid()%(unsigned)100);
+ name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
+
+ nmb->header.name_trn_id = name_trn_id;
+ nmb->header.opcode = 0;
+ nmb->header.response = False;
+ nmb->header.nm_flags.bcast = bcast;
+ nmb->header.nm_flags.recursion_available = 0;
+ nmb->header.nm_flags.recursion_desired = 1;
+ nmb->header.nm_flags.trunc = False;
+ nmb->header.nm_flags.authoritative = False;
+ nmb->header.rcode = 0;
+ nmb->header.qdcount = 1;
+ nmb->header.ancount = 0;
+ nmb->header.nscount = 0;
+ nmb->header.arcount = 0;
+
+ make_nmb_name(&nmb->question.question_name,name,name_type,scope);
+
+ nmb->question.question_type = 0x20;
+ nmb->question.question_class = 0x1;
+
+ p.ip = to_ip;
+ p.port = NMB_PORT;
+ p.fd = fd;
+ p.timestamp = time(NULL);
+ p.packet_type = NMB_PACKET;
+
+ GetTimeOfDay(&tval);
+
+ if (!send_packet(&p))
+ return(False);
+
+ retries--;
+
+ while (1)
+ {
+ struct timeval tval2;
+ GetTimeOfDay(&tval2);
+ if (TvalDiff(&tval,&tval2) > retry_time) {
+ if (!retries) break;
+ if (!found && !send_packet(&p))
+ return False;
+ GetTimeOfDay(&tval);
+ retries--;
+ }
+
+ if ((p2=receive_packet(fd,NMB_PACKET,90)))
+ {
+ struct nmb_packet *nmb2 = &p2->packet.nmb;
+ if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
+ !nmb2->header.response) {
+ /* its not for us - maybe deal with it later
+ (put it on the queue?) */
+ if (fn)
+ fn(p2);
+ else
+ free_packet(p2);
+ continue;
+ }
+
+ if (nmb2->header.opcode != 0 ||
+ nmb2->header.nm_flags.bcast ||
+ nmb2->header.rcode ||
+ !nmb2->header.ancount) {
+ /* XXXX what do we do with this? could be a redirect, but
+ we'll discard it for the moment */
+ free_packet(p2);
+ continue;
+ }
+
+ if (ip) {
+ putip((char *)ip,&nmb2->answers->rdata[2]);
+ DEBUG(fn?3:2,("Got a positive name query response from %s",
+ inet_ntoa(p2->ip)));
+ DEBUG(fn?3:2,(" (%s)\n",inet_ntoa(*ip)));
+ }
+ found=True; retries=0;
+ free_packet(p2);
+ if (fn) break;
+ }
+ }
+
+ return(found);
+}
diff --git a/source/libsmb/nmblib.c b/source/libsmb/nmblib.c
index 67432271737..d82d89f6534 100644
--- a/source/libsmb/nmblib.c
+++ b/source/libsmb/nmblib.c
@@ -21,15 +21,104 @@
*/
#include "includes.h"
-#include "nameserv.h"
+#include "localnet.h"
+#include "loadparm.h"
+extern struct in_addr myip;
extern int DEBUGLEVEL;
-int num_good_sends=0;
-int num_good_receives=0;
-static uint16 name_trn_id = 0;
-BOOL CanRecurse = True;
+int num_good_sends = 0;
+int num_good_receives = 0;
extern pstring scope;
+extern pstring myname;
+extern struct in_addr ipzero;
+
+
+/****************************************************************************
+ print out a res_rec structure
+ ****************************************************************************/
+static void debug_nmb_res_rec(struct res_rec *res, char *hdr)
+{
+ int i, j;
+
+ DEBUG(4,(" %s: nmb_name=%s rr_type=%d rr_class=%d ttl=%d\n",
+ hdr,
+ namestr(&res->rr_name),
+ res->rr_type,
+ res->rr_class,
+ res->ttl));
+
+ if (res->rdlength == 0 || res->rdata == NULL) return;
+
+ for (i = 0; i < res->rdlength; i+= 16)
+ {
+ DEBUG(4, (" %s %3x char ", hdr, i));
+
+ for (j = 0; j < 16; j++)
+ {
+ unsigned char x = res->rdata[i+j];
+ if (x < 32 || x > 127) x = '.';
+
+ if (i+j >= res->rdlength) break;
+ DEBUG(4, ("%c", x));
+ }
+
+ DEBUG(4, (" hex ", i));
+
+ for (j = 0; j < 16; j++)
+ {
+ if (i+j >= res->rdlength) break;
+ DEBUG(4, ("%02X", (unsigned char)res->rdata[i+j]));
+ }
+
+ DEBUG(4, ("\n"));
+ }
+}
+
+/****************************************************************************
+ process a nmb packet
+ ****************************************************************************/
+void debug_nmb_packet(struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+
+ DEBUG(4,("nmb packet from %s header: id=%d opcode=%d response=%s\n",
+ inet_ntoa(p->ip),
+ nmb->header.name_trn_id,nmb->header.opcode,BOOLSTR(nmb->header.response)));
+ DEBUG(4,(" header: flags: bcast=%s rec_avail=%s rec_des=%s trunc=%s auth=%s\n",
+ BOOLSTR(nmb->header.nm_flags.bcast),
+ BOOLSTR(nmb->header.nm_flags.recursion_available),
+ BOOLSTR(nmb->header.nm_flags.recursion_desired),
+ BOOLSTR(nmb->header.nm_flags.trunc),
+ BOOLSTR(nmb->header.nm_flags.authoritative)));
+ DEBUG(4,(" header: rcode=%d qdcount=%d ancount=%d nscount=%d arcount=%d\n",
+ nmb->header.rcode,
+ nmb->header.qdcount,
+ nmb->header.ancount,
+ nmb->header.nscount,
+ nmb->header.arcount));
+
+ if (nmb->header.qdcount)
+ {
+ DEBUG(4,(" question: q_name=%s q_type=%d q_class=%d\n",
+ namestr(&nmb->question.question_name),
+ nmb->question.question_type,
+ nmb->question.question_class));
+ }
+
+ if (nmb->answers && nmb->header.ancount)
+ {
+ debug_nmb_res_rec(nmb->answers,"answers");
+ }
+ if (nmb->nsrecs && nmb->header.nscount)
+ {
+ debug_nmb_res_rec(nmb->nsrecs,"nsrecs");
+ }
+ if (nmb->additional && nmb->header.arcount)
+ {
+ debug_nmb_res_rec(nmb->additional,"additional");
+ }
+}
/*******************************************************************
handle "compressed" name pointers
@@ -38,7 +127,7 @@ static BOOL handle_name_ptrs(unsigned char *ubuf,int *offset,int length,
BOOL *got_pointer,int *ret)
{
int loop_count=0;
-
+
while ((ubuf[*offset] & 0xC0) == 0xC0) {
if (!*got_pointer) (*ret) += 2;
(*got_pointer)=True;
@@ -54,8 +143,7 @@ static BOOL handle_name_ptrs(unsigned char *ubuf,int *offset,int length,
parse a nmb name from "compressed" format to something readable
return the space taken by the name, or 0 if the name is invalid
******************************************************************/
-static int parse_nmb_name(char *inbuf,int offset,int length,
- struct nmb_name *name)
+static int parse_nmb_name(char *inbuf,int offset,int length, struct nmb_name *name)
{
int m,n=0;
unsigned char *ubuf = (unsigned char *)inbuf;
@@ -186,11 +274,10 @@ char *namestr(struct nmb_name *n)
}
/*******************************************************************
- allocate are parse some resource records
+ allocate and parse some resource records
******************************************************************/
static BOOL parse_alloc_res_rec(char *inbuf,int *offset,int length,
- struct res_rec **recs,
- int count)
+ struct res_rec **recs, int count)
{
int i;
*recs = (struct res_rec *)malloc(sizeof(**recs)*count);
@@ -382,7 +469,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 +500,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 +521,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,
@@ -528,6 +615,7 @@ static int build_nmb(char *buf,struct packet_struct *p)
if (nmb->header.nm_flags.recursion_available) ubuf[offset+3] |= 0x80;
if (nmb->header.nm_flags.bcast) ubuf[offset+3] |= 0x10;
ubuf[offset+3] |= (nmb->header.rcode & 0xF);
+
RSSVAL(ubuf,offset+4,nmb->header.qdcount);
RSSVAL(ubuf,offset+6,nmb->header.ancount);
RSSVAL(ubuf,offset+8,nmb->header.nscount);
@@ -607,330 +695,3 @@ struct packet_struct *receive_packet(int fd,enum packet_type type,int t)
}
-/****************************************************************************
-interpret a node status response
-****************************************************************************/
-static void interpret_node_status(char *p, char *master,char *rname)
-{
- int level = (master||rname)?4:0;
- int numnames = CVAL(p,0);
- DEBUG(level,("received %d names\n",numnames));
-
- if (rname) *rname = 0;
- if (master) *master = 0;
-
- p += 1;
- while (numnames--)
- {
- char qname[17];
- int type;
- fstring flags;
- *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..be22fc50fc6 100644
--- a/source/libsmb/smbencrypt.c
+++ b/source/libsmb/smbencrypt.c
@@ -28,19 +28,6 @@
extern int DEBUGLEVEL;
-#ifndef uchar
-#define uchar unsigned char
-#endif
-#ifndef int16
-#define int16 unsigned short
-#endif
-#ifndef uint16
-#define uint16 unsigned short
-#endif
-#ifndef uint32
-#define uint32 unsigned int
-#endif
-
#include "byteorder.h"
void str_to_key(uchar *str,uchar *key)
@@ -166,7 +153,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 +185,5 @@ void SMBNTencrypt(uchar *passwd, uchar *c8, uchar *p24)
}
#else
-void smbencrypt_dummy(void){}
+ void smbencrypt_dummy(void){}
#endif
diff --git a/source/loadparm.h b/source/loadparm.h
new file mode 100644
index 00000000000..92c8274767d
--- /dev/null
+++ b/source/loadparm.h
@@ -0,0 +1,165 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Parameter loading functions
+ Copyright (C) Karl Auer 1993, 1994
+
+ Extensively modified by Andrew Tridgell
+
+ 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.
+*/
+
+/*
+ *
+ * Prototypes etc for loadparm.c.
+ *
+ */
+#ifndef _LOADPARM_H
+#define _LOADPARM_H
+
+#include "smb.h"
+
+extern BOOL lp_file_list_changed(void);
+extern void lp_killunused(BOOL (*snumused)(int ));
+extern BOOL lp_loaded(void);
+extern BOOL lp_snum_ok(int iService);
+extern BOOL lp_manglednames(int iService);
+extern char *lp_passwordserver(void);
+extern char *lp_passwd_program(void);
+extern char *lp_passwd_chat(void);
+extern char *lp_guestaccount(int iService);
+extern char *lp_printcapname(void);
+extern char *lp_lockdir(void);
+extern char *lp_logfile(void);
+extern char *lp_smbrun(void);
+extern char *lp_configfile(void);
+extern char *lp_smb_passwd_file(void);
+extern char *lp_rootdir(void);
+extern char *lp_defaultservice(void);
+extern char *lp_serverstring(void);
+extern char *lp_dfree_command(void);
+extern char *lp_msg_command(void);
+extern char *lp_workgroup(void);
+extern char *lp_domain_controller(void);
+extern char *lp_username_map(void);
+extern char *lp_hosts_equiv(void);
+extern char *lp_logon_script(void);
+extern char *lp_wins_server(void);
+extern char *lp_magicscript(int iService);
+extern char *lp_magicoutput(int iService);
+extern char *lp_mangled_map(int iService);
+char *volume_label(int snum);
+extern int lp_os_level(void);
+extern int lp_max_ttl(void);
+extern int lp_max_log_size(void);
+extern int lp_maxxmit(void);
+extern int lp_maxmux(void);
+extern int lp_mangledstack(void);
+extern BOOL lp_wins_support(void);
+extern BOOL lp_wins_proxy(void);
+extern BOOL lp_preferred_master(void);
+extern BOOL lp_domain_master(void);
+extern BOOL lp_domain_logons(void);
+extern BOOL lp_getwdcache(void);
+extern BOOL lp_use_rhosts(void);
+extern BOOL lp_readprediction(void);
+extern BOOL lp_readbmpx(void);
+extern BOOL lp_readraw(void);
+extern BOOL lp_writeraw(void);
+extern BOOL lp_null_passwords(void);
+extern BOOL lp_strip_dot(void);
+extern BOOL lp_encrypted_passwords(void);
+extern BOOL lp_syslog_only(void);
+extern BOOL lp_browse_list(void);
+extern int lp_numservices(void);
+extern int lp_keepalive(void);
+extern int lp_passwordlevel(void);
+extern int lp_security(void);
+extern int lp_printing(void);
+extern int lp_maxdisksize(void);
+extern int lp_lpqcachetime(void);
+extern int lp_syslog(void);
+extern int lp_deadtime(void);
+extern int lp_debuglevel(void);
+extern int lp_maxprotocol(void);
+extern int lp_maxpacket(void);
+extern char *lp_comment(int iService);
+extern char *lp_preexec(int iService);
+extern char *lp_postexec(int iService);
+extern char *lp_rootpreexec(int iService);
+extern char *lp_rootpostexec(int iService);
+extern char *lp_servicename(int iService);
+extern char *lp_pathname(int iService);
+extern char *lp_username(int iService);
+extern char *lp_invalid_users(int iService);
+extern char *lp_valid_users(int iService);
+extern char *lp_admin_users(int iService);
+extern char *lp_printcommand(int iService);
+extern char *lp_lpqcommand(int iService);
+extern char *lp_lprmcommand(int iService);
+extern char *lp_lppausecommand(int iService);
+extern char *lp_lpresumecommand(int iService);
+extern char *lp_printername(int iService);
+extern char *lp_hostsallow(int iService);
+extern char *lp_hostsdeny(int iService);
+extern char *lp_dontdescend(int iService);
+extern char *lp_force_user(int iService);
+extern char *lp_force_group(int iService);
+extern char *lp_readlist(int iService);
+extern char *lp_writelist(int iService);
+extern BOOL lp_alternate_permissions(int iService);
+extern BOOL lp_revalidate(int iService);
+extern BOOL lp_status(int iService);
+extern BOOL lp_hide_dot_files(int iService);
+extern BOOL lp_browseable(int iService);
+extern BOOL lp_widelinks(int iService);
+extern BOOL lp_syncalways(int iService);
+extern BOOL lp_readonly(int iService);
+extern BOOL lp_no_set_dir(int iService);
+extern BOOL lp_guest_ok(int iService);
+extern BOOL lp_guest_only(int iService);
+extern BOOL lp_print_ok(int iService);
+extern BOOL lp_postscript(int iService);
+extern BOOL lp_map_hidden(int iService);
+extern BOOL lp_map_archive(int iService);
+extern BOOL lp_locking(int iService);
+extern BOOL lp_strict_locking(int iService);
+extern BOOL lp_share_modes(int iService);
+extern BOOL lp_onlyuser(int iService);
+extern BOOL lp_map_system(int iService);
+extern BOOL lp_casesensitive(int iService);
+extern BOOL lp_casemangle(int iService);
+extern BOOL lp_preservecase(int iService);
+extern BOOL lp_shortpreservecase(int iService);
+extern BOOL lp_load(char *pszFname,BOOL global_only);
+extern void lp_dump(void);
+extern int lp_servicenumber(char *pszServiceName);
+extern BOOL lp_add_home(char *pszHomename,
+ int iDefaultService, char *pszHomedir);
+extern int lp_add_service(char *service, int iDefaultService);
+extern BOOL lp_add_printer(char *pszPrintername, int iDefaultService);
+extern BOOL lp_readonly(int iService);
+extern int lp_create_mode(int iService);
+extern int lp_minprintspace(int iService);
+extern int lp_defaultcase(int iService);
+extern char lp_magicchar(int iService);
+extern int lp_max_connections(int iService);
+extern BOOL lp_add_home(char *pservice,int ifrom,char *phome);
+extern char *lp_string(char *s);
+extern BOOL lp_delete_readonly(int iService);
+char *my_workgroup(void);
+
+#endif
+
diff --git a/source/localnet.h b/source/localnet.h
new file mode 100644
index 00000000000..7f335e790e4
--- /dev/null
+++ b/source/localnet.h
@@ -0,0 +1,6 @@
+extern struct in_addr myip;
+extern struct in_addr bcast_ip;
+extern struct in_addr Netmask;
+
+extern int ClientNMB;
+extern int ClientDGRAM;
diff --git a/source/nameannounce.c b/source/nameannounce.c
new file mode 100644
index 00000000000..6b086c97746
--- /dev/null
+++ b/source/nameannounce.c
@@ -0,0 +1,445 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1995
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+*/
+
+#include "includes.h"
+#include "loadparm.h"
+
+#define TEST_CODE
+
+extern int DEBUGLEVEL;
+extern BOOL CanRecurse;
+
+extern struct in_addr myip;
+extern struct in_addr bcast_ip;
+extern struct in_addr Netmask;
+extern struct in_addr ipzero;
+
+extern pstring myname;
+
+extern int ClientDGRAM;
+extern int ClientNMB;
+
+/* this is our domain/workgroup/server database */
+extern struct domain_record *domainlist;
+
+/* machine comment for host announcements */
+extern pstring ServerComment;
+
+extern int updatecount;
+extern int workgroup_count;
+
+/* what server type are we currently */
+
+#define MSBROWSE "\001\002__MSBROWSE__\002"
+#define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE"
+
+/****************************************************************************
+ send a announce request to the local net
+ **************************************************************************/
+void announce_request(struct work_record *work, struct in_addr ip)
+{
+ pstring outbuf;
+ char *p;
+
+ if (!work) return;
+
+ work->needannounce = True;
+
+ DEBUG(2,("sending announce request to %s for workgroup %s\n",
+ inet_ntoa(ip),work->work_group));
+
+ bzero(outbuf,sizeof(outbuf));
+ p = outbuf;
+ CVAL(p,0) = ANN_AnnouncementRequest;
+ p++;
+
+ CVAL(p,0) = work->token; /* flags?? XXXX probably a token*/
+ p++;
+ StrnCpy(p,myname,16);
+ strupper(p);
+ p = skip_string(p,1);
+
+ send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
+ myname,work->work_group,0x20,0x0,ip,myip);
+}
+
+
+/****************************************************************************
+ request an announcement
+ **************************************************************************/
+void do_announce_request(char *info, char *to_name, int announce_type,
+ int from,
+ int to, struct in_addr dest_ip)
+{
+ pstring outbuf;
+ char *p;
+
+ bzero(outbuf,sizeof(outbuf));
+ p = outbuf;
+ CVAL(p,0) = announce_type;
+ p++;
+
+ DEBUG(2,("sending announce type %d: info %s to %s - server %s(%x)\n",
+ announce_type, info, inet_ntoa(dest_ip),to_name,to));
+
+ StrnCpy(p,info,16);
+ strupper(p);
+ p = skip_string(p,1);
+
+ send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
+ myname,to_name,from,to,dest_ip,myip);
+}
+
+/****************************************************************************
+ construct a host announcement unicast
+ **************************************************************************/
+void announce_backup(void)
+{
+ static time_t lastrun = 0;
+ time_t t = time(NULL);
+ pstring outbuf;
+ char *p;
+ struct domain_record *d1;
+ int tok;
+
+ if (!lastrun) lastrun = t;
+ if (t < lastrun + 1*60) return;
+ lastrun = t;
+
+ for (tok = 0; tok <= workgroup_count; tok++)
+ {
+ for (d1 = domainlist; d1; d1 = d1->next)
+ {
+ struct work_record *work;
+ struct domain_record *d;
+
+ /* search for unique workgroup: only the name matters */
+ for (work = d1->workgrouplist;
+ work && (tok != work->token);
+ work = work->next);
+
+ if (!work) continue;
+
+ /* found one: announce it across all domains */
+ for (d = domainlist; d; d = d->next)
+ {
+ int type=0;
+
+ if (AM_DOMCTL(work)) {
+ type = 0x1b;
+ } else if (AM_MASTER(work)) {
+ type = 0x1d;
+ } else {
+ continue;
+ }
+
+ 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;
+ p++;
+
+ CVAL(p,0) = 1; /* count? */
+ SIVAL(p,1,work->token); /* workgroup unique key index */
+ p += 5;
+ p++;
+
+ send_mailslot_reply(BROWSE_MAILSLOT,
+ ClientDGRAM,outbuf,
+ PTR_DIFF(p,outbuf),
+ myname, work->work_group,
+ 0x0,type,d->bcast_ip,myip);
+ }
+ }
+ }
+}
+
+
+/****************************************************************************
+ construct a host announcement unicast
+ **************************************************************************/
+void announce_host(void)
+{
+ time_t t = time(NULL);
+ pstring outbuf;
+ char *p;
+ char *namep;
+ char *stypep;
+ char *commentp;
+ pstring comment;
+ char *my_name;
+ struct domain_record *d;
+
+ StrnCpy(comment, *ServerComment ? ServerComment : "NoComment", 43);
+
+ my_name = *myname ? myname : "NoName";
+
+ for (d = domainlist; d; d = d->next)
+ {
+ struct work_record *work;
+
+ if (!ip_equal(bcast_ip,d->bcast_ip))
+ continue;
+
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ uint32 stype = work->ServerType;
+ struct server_record *s;
+ BOOL announce = False;
+
+ if (work->needannounce) {
+ /* drop back to a max 3 minute announce - this is to prevent a
+ single lost packet from stuffing things up for too long */
+ work->announce_interval = MIN(work->announce_interval,3*60);
+ work->lastannounce_time = t - (work->announce_interval+1);
+ }
+
+ /* announce every minute at first then progress to every 12 mins */
+ if (work->lastannounce_time &&
+ (t - work->lastannounce_time) < work->announce_interval)
+ continue;
+
+ if (work->announce_interval < 12*60)
+ work->announce_interval += 60;
+
+ work->lastannounce_time = t;
+
+ if (!ip_equal(bcast_ip,d->bcast_ip)) {
+ stype &= ~(SV_TYPE_POTENTIAL_BROWSER | SV_TYPE_MASTER_BROWSER |
+ SV_TYPE_DOMAIN_MASTER | SV_TYPE_BACKUP_BROWSER |
+ SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_MEMBER);
+ }
+
+ for (s = work->serverlist; s; s = s->next) {
+ if (strequal(myname, s->serv.name)) {
+ announce = True;
+ break;
+ }
+ }
+
+ if (announce)
+ {
+ bzero(outbuf,sizeof(outbuf));
+ p = outbuf+1;
+
+ CVAL(p,0) = updatecount;
+ /* ms - despite the spec */
+ SIVAL(p,1,work->announce_interval*1000);
+ namep = p+5;
+ StrnCpy(namep,my_name,16);
+ strupper(namep);
+ CVAL(p,21) = 2; /* major version */
+ CVAL(p,22) = 2; /* minor version */
+ stypep = p+23;
+ SIVAL(p,23,stype);
+ SSVAL(p,27,0xaa55); /* browse signature */
+ SSVAL(p,29,1); /* browse version */
+ commentp = p+31;
+ strcpy(commentp,comment);
+ p = p+31;
+ p = skip_string(p,1);
+
+ if (ip_equal(bcast_ip,d->bcast_ip))
+ {
+ if (AM_MASTER(work))
+ {
+ SIVAL(stypep,0,work->ServerType);
+
+ DEBUG(2,("sending local master announce to %s for %s\n",
+ inet_ntoa(d->bcast_ip),work->work_group));
+
+ CVAL(outbuf,0) = ANN_LocalMasterAnnouncement;
+
+ send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
+ PTR_DIFF(p,outbuf),
+ my_name,work->work_group,0,
+ 0x1e,d->bcast_ip,myip);
+
+ DEBUG(2,("sending domain announce to %s for %s\n",
+ inet_ntoa(d->bcast_ip),work->work_group));
+
+ CVAL(outbuf,0) = ANN_DomainAnnouncement;
+
+ StrnCpy(namep,work->work_group,15);
+ strupper(namep);
+ StrnCpy(commentp,myname,15);
+ strupper(commentp);
+
+ SIVAL(stypep,0,(unsigned)0x80000000);
+ p = commentp + strlen(commentp) + 1;
+
+ send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
+ PTR_DIFF(p,outbuf),
+ my_name,MSBROWSE,0,0x01,d->bcast_ip,myip);
+ }
+ else
+ {
+ DEBUG(2,("sending host announce to %s for %s\n",
+ inet_ntoa(d->bcast_ip),work->work_group));
+
+ CVAL(outbuf,0) = ANN_HostAnnouncement;
+
+ send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
+ PTR_DIFF(p,outbuf),
+ my_name,work->work_group,0,0x1d,
+ d->bcast_ip,myip);
+ }
+ }
+ }
+
+ if (work->needannounce)
+ {
+ work->needannounce = False;
+ break;
+ /* sorry: can't do too many announces. do some more later */
+ }
+ }
+ }
+}
+
+
+/****************************************************************************
+ announce myself as a master to all other primary domain conrollers.
+
+ BIG NOTE: this code will remain untested until some kind soul that has access
+ to a couple of windows NT advanced servers runs this version of nmbd for at
+ least 15 minutes.
+
+ this actually gets done in search_and_sync_workgroups() via the
+ MASTER_SERVER_CHECK command, if there is a response from the
+ name query initiated here. see response_name_query()
+ **************************************************************************/
+void announce_master(void)
+{
+ struct domain_record *d;
+ static time_t last=0;
+ time_t t = time(NULL);
+ BOOL am_master = False; /* are we a master of some sort? :-) */
+
+#ifdef TEST_CODE
+ if (last && (t-last < 2*60)) return;
+#else
+ if (last && (t-last < 15*60)) return;
+#endif
+
+ last = t;
+
+ for (d = domainlist; d; d = d->next)
+ {
+ struct work_record *work;
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ if (AM_MASTER(work))
+ {
+ am_master = True;
+ }
+ }
+ }
+
+ if (!am_master) return; /* only proceed if we are a master browser */
+
+ for (d = domainlist; d; d = d->next)
+ {
+ struct work_record *work;
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ struct server_record *s;
+ for (s = work->serverlist; s; s = s->next)
+ {
+ if (strequal(s->serv.name, myname)) continue;
+
+ /* all PDCs (which should also be master browsers) */
+ if (s->serv.type & SV_TYPE_DOMAIN_CTRL)
+ {
+ /* check the existence of a pdc for this workgroup, and if
+ one exists at the specified ip, sync with it and announce
+ ourselves as a master browser to it */
+
+ if (!*lp_domain_controller() ||
+ !strequal(lp_domain_controller(), s->serv.name))
+ {
+ if (!lp_wins_support() && *lp_wins_server())
+ {
+ struct in_addr ip;
+ ip = ipzero;
+
+ queue_netbios_pkt_wins(ClientNMB,NMB_QUERY,
+ MASTER_SERVER_CHECK,
+ work->work_group,0x1b,0,
+ False, False, ip);
+ }
+ else
+ {
+ struct domain_record *d2;
+ for (d2 = domainlist; d2; d2 = d2->next)
+ {
+ queue_netbios_packet(ClientNMB,NMB_QUERY,
+ MASTER_SERVER_CHECK,
+ work->work_group,0x1b,0,
+ True, False, d2->bcast_ip);
+ }
+ }
+ }
+ }
+ }
+
+ /* now do primary domain controller - the one that's not
+ necessarily in our browse lists, although it ought to be
+ this pdc is the one that we get TOLD about through smb.conf.
+ basically, if it's on a subnet that we know about, it may end
+ up in our browse lists (which is why it's explicitly excluded
+ in the code above) */
+
+ if (*lp_domain_controller())
+ {
+ struct in_addr ip;
+ BOOL bcast = False;
+
+ ip = *interpret_addr2(lp_domain_controller());
+
+ if (zero_ip(ip))
+ {
+ ip = bcast_ip;
+ bcast = True;
+ }
+
+ DEBUG(2, ("Searching for PDC %s at %s\n",
+ lp_domain_controller(), inet_ntoa(ip)));
+
+ /* check the existence of a pdc for this workgroup, and if
+ one exists at the specified ip, sync with it and announce
+ ourselves as a master browser to it */
+ queue_netbios_pkt_wins(ClientNMB, NMB_QUERY,MASTER_SERVER_CHECK,
+ work->work_group,0x1b, 0,
+ bcast, False, ip);
+ }
+ }
+ }
+}
diff --git a/source/namedb.c b/source/namedb.c
new file mode 100644
index 00000000000..fc14c4d5c60
--- /dev/null
+++ b/source/namedb.c
@@ -0,0 +1,709 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1995
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+*/
+
+#include "includes.h"
+#include "smb.h"
+#include "loadparm.h"
+#include "localnet.h"
+
+extern int DEBUGLEVEL;
+
+extern time_t StartupTime;
+extern pstring myname;
+extern pstring scope;
+extern struct in_addr bcast_ip;
+
+/* this is our browse master/backup cache database */
+struct browse_cache_record *browserlist = NULL;
+
+/* this is our domain/workgroup/server database */
+struct domain_record *domainlist = NULL;
+
+static BOOL updatedlists = True;
+int updatecount=0;
+
+int workgroup_count = 0; /* unique index key: one for each workgroup */
+
+/* what server type are we currently */
+
+#define DFLT_SERVER_TYPE (SV_TYPE_WORKSTATION | SV_TYPE_SERVER | \
+ SV_TYPE_TIME_SOURCE | SV_TYPE_SERVER_UNIX | \
+ SV_TYPE_PRINTQ_SERVER | SV_TYPE_POTENTIAL_BROWSER)
+
+/* here are my election parameters */
+#define MSBROWSE "\001\002__MSBROWSE__\002"
+
+
+/****************************************************************************
+ add a workgroup into the domain list
+ **************************************************************************/
+static void add_workgroup(struct work_record *work, struct domain_record *d)
+{
+ struct work_record *w2;
+
+ if (!work || !d) return;
+
+ if (!d->workgrouplist)
+ {
+ d->workgrouplist = work;
+ work->prev = NULL;
+ work->next = NULL;
+ return;
+ }
+
+ for (w2 = d->workgrouplist; w2->next; w2 = w2->next);
+
+ w2->next = work;
+ work->next = NULL;
+ work->prev = w2;
+}
+
+
+/****************************************************************************
+ create a blank workgroup
+ **************************************************************************/
+static struct work_record *make_workgroup(char *name)
+{
+ struct work_record *work;
+ struct domain_record *d;
+ int t = -1;
+
+ if (!name || !name[0]) return NULL;
+
+ work = (struct work_record *)malloc(sizeof(*work));
+ if (!work) return(NULL);
+
+ StrnCpy(work->work_group,name,sizeof(work->work_group)-1);
+ work->serverlist = NULL;
+
+ work->ServerType = DFLT_SERVER_TYPE;
+ work->RunningElection = False;
+ work->ElectionCount = 0;
+ work->needelection = False;
+ work->needannounce = True;
+
+ /* make sure all token representations of workgroups are unique */
+
+ for (d = domainlist; d && t == -1; d = d->next)
+ {
+ struct work_record *w;
+ for (w = d->workgrouplist; w && t == -1; w = w->next)
+ {
+ if (strequal(w->work_group, work->work_group)) t = w->token;
+ }
+ }
+
+ if (t == -1)
+ {
+ work->token = ++workgroup_count;
+ }
+ else
+ {
+ work->token = t;
+ }
+
+
+ /* WfWg uses 01040b01 */
+ /* Win95 uses 01041501 */
+ /* NTAS uses ???????? */
+ work->ElectionCriterion = (MAINTAIN_LIST<<1)|(ELECTION_VERSION<<8);
+ work->ElectionCriterion |= (lp_os_level() << 24);
+ if (lp_domain_master()) {
+ work->ElectionCriterion |= 0x80;
+ }
+
+ return work;
+}
+
+
+/*******************************************************************
+ expire old servers in the serverlist
+ time of -1 indicates everybody dies
+ ******************************************************************/
+static void remove_old_servers(struct work_record *work, time_t t)
+{
+ struct server_record *s;
+ struct server_record *nexts;
+
+ /* expire old entries in the serverlist */
+ for (s = work->serverlist; s; s = nexts)
+ {
+ if (t == -1 || (s->death_time && s->death_time < t))
+ {
+ DEBUG(3,("Removing dead server %s\n",s->serv.name));
+ updatedlists = True;
+ nexts = s->next;
+
+ if (s->prev) s->prev->next = s->next;
+ if (s->next) s->next->prev = s->prev;
+
+ if (work->serverlist == s)
+ work->serverlist = s->next;
+
+ free(s);
+ }
+ else
+ {
+ nexts = s->next;
+ }
+ }
+}
+
+
+/*******************************************************************
+ remove workgroups
+ ******************************************************************/
+struct work_record *remove_workgroup(struct domain_record *d,
+ struct work_record *work)
+{
+ struct work_record *ret_work = NULL;
+
+ if (!d || !work) return NULL;
+
+ DEBUG(3,("Removing old workgroup %s\n", work->work_group));
+
+ remove_old_servers(work, -1);
+
+ ret_work = work->next;
+
+ if (work->prev) work->prev->next = work->next;
+ if (work->next) work->next->prev = work->prev;
+
+ if (d->workgrouplist == work) d->workgrouplist = work->next;
+
+ free(work);
+
+ return ret_work;
+}
+
+
+/****************************************************************************
+ add a domain into the list
+ **************************************************************************/
+static void add_domain(struct domain_record *d)
+{
+ struct domain_record *d2;
+
+ if (!domainlist)
+ {
+ domainlist = d;
+ d->prev = NULL;
+ d->next = NULL;
+ return;
+ }
+
+ for (d2 = domainlist; d2->next; d2 = d2->next);
+
+ d2->next = d;
+ d->next = NULL;
+ d->prev = d2;
+}
+
+/***************************************************************************
+ add a browser into the list
+ **************************************************************************/
+static void add_browse_cache(struct browse_cache_record *b)
+{
+ struct browse_cache_record *b2;
+
+ if (!browserlist)
+ {
+ browserlist = b;
+ b->prev = NULL;
+ b->next = NULL;
+ return;
+ }
+
+ for (b2 = browserlist; b2->next; b2 = b2->next) ;
+
+ b2->next = b;
+ b->next = NULL;
+ b->prev = b2;
+}
+
+
+/***************************************************************************
+ add a server into the list
+ **************************************************************************/
+static void add_server(struct work_record *work,struct server_record *s)
+{
+ struct server_record *s2;
+
+ if (!work->serverlist) {
+ work->serverlist = s;
+ s->prev = NULL;
+ s->next = NULL;
+ return;
+ }
+
+ for (s2 = work->serverlist; s2->next; s2 = s2->next) ;
+
+ s2->next = s;
+ s->next = NULL;
+ s->prev = s2;
+}
+
+
+/*******************************************************************
+ remove old browse entries
+ ******************************************************************/
+void expire_browse_cache(time_t t)
+{
+ struct browse_cache_record *b;
+ struct browse_cache_record *nextb;
+
+ /* expire old entries in the serverlist */
+ for (b = browserlist; b; b = nextb)
+ {
+ if (b->synced && b->sync_time < t)
+ {
+ DEBUG(3,("Removing dead cached browser %s\n",b->name));
+ nextb = b->next;
+
+ if (b->prev) b->prev->next = b->next;
+ if (b->next) b->next->prev = b->prev;
+
+ if (browserlist == b) browserlist = b->next;
+
+ free(b);
+ }
+ else
+ {
+ nextb = b->next;
+ }
+ }
+}
+
+
+/****************************************************************************
+ find a workgroup in the workgrouplist
+ only create it if the domain allows it, or the parameter 'add' insists
+ that it get created/added anyway. this allows us to force entries in
+ lmhosts file to be added.
+ **************************************************************************/
+struct work_record *find_workgroupstruct(struct domain_record *d, fstring name, BOOL add)
+{
+ struct work_record *ret, *work;
+
+ if (!d) return NULL;
+
+ DEBUG(4, ("workgroup search for %s: ", name));
+
+ if (strequal(name, "*"))
+ {
+ DEBUG(2,("add any workgroups: initiating browser search on %s\n",
+ inet_ntoa(d->bcast_ip)));
+ queue_netbios_pkt_wins(ClientNMB,NMB_QUERY, FIND_MASTER,
+ MSBROWSE,0x1,0,
+ True,False, d->bcast_ip);
+ return NULL;
+ }
+
+ for (ret = d->workgrouplist; ret; ret = ret->next)
+ {
+ if (!strcmp(ret->work_group,name))
+ {
+ DEBUG(4, ("found\n"));
+ return(ret);
+ }
+ }
+
+ DEBUG(4, ("not found: creating\n"));
+
+ if ((work = make_workgroup(name)))
+ {
+ if (lp_preferred_master() &&
+ strequal(lp_workgroup(), name) &&
+ ip_equal(d->bcast_ip, bcast_ip))
+ {
+ DEBUG(3, ("preferred master startup for %s\n", work->work_group));
+ work->needelection = True;
+ work->ElectionCriterion |= (1<<3);
+ }
+ if (!ip_equal(bcast_ip, d->bcast_ip))
+ {
+ work->needelection = False;
+ }
+ add_workgroup(work, d);
+ return(work);
+ }
+ return NULL;
+}
+
+/****************************************************************************
+ find a domain in the domainlist
+ **************************************************************************/
+struct domain_record *find_domain(struct in_addr source_ip)
+{
+ struct domain_record *d;
+
+ /* search through domain list for broadcast/netmask that matches
+ the source ip address */
+
+ for (d = domainlist; d; d = d->next)
+ {
+ if (same_net(source_ip, d->bcast_ip, d->mask_ip))
+ {
+ return(d);
+ }
+ }
+
+ return (NULL);
+}
+
+
+/****************************************************************************
+ dump a copy of the workgroup/domain database
+ **************************************************************************/
+static void dump_workgroups(void)
+{
+ struct domain_record *d;
+
+ for (d = domainlist; d; d = d->next)
+ {
+ if (d->workgrouplist)
+ {
+ struct work_record *work;
+
+ DEBUG(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));
+ }
+ }
+ }
+ }
+ }
+}
+
+/****************************************************************************
+ create a domain entry
+ ****************************************************************************/
+static struct domain_record *make_domain(struct in_addr ip, struct in_addr mask)
+{
+ struct domain_record *d;
+ d = (struct domain_record *)malloc(sizeof(*d));
+
+ if (!d) return(NULL);
+
+ bzero((char *)d,sizeof(*d));
+
+ DEBUG(4, ("making domain %s ", inet_ntoa(ip)));
+ DEBUG(4, ("%s\n", inet_ntoa(mask)));
+
+ d->bcast_ip = ip;
+ d->mask_ip = mask;
+ d->workgrouplist = NULL;
+
+ add_domain(d);
+
+ return d;
+}
+
+/****************************************************************************
+ add a domain entry. creates a workgroup, if necessary, and adds the domain
+ to the named a workgroup.
+ ****************************************************************************/
+struct domain_record *add_domain_entry(struct in_addr source_ip,
+ struct in_addr source_mask,
+ char *name, BOOL add)
+{
+ struct domain_record *d;
+ struct in_addr ip;
+
+ ip = *interpret_addr2("255.255.255.255");
+
+ if (zero_ip(source_ip)) source_ip = bcast_ip;
+
+ /* add the domain into our domain database */
+ if ((d = find_domain(source_ip)) ||
+ (d = make_domain(source_ip, source_mask)))
+ {
+ struct work_record *w = find_workgroupstruct(d, name, add);
+
+ /* add WORKGROUP(1e) and WORKGROUP(00) entries into name database
+ or register with WINS server, if it's our workgroup */
+ if (strequal(lp_workgroup(), name))
+ {
+ extern pstring ServerComment;
+ add_name_entry(name,0x1e,NB_ACTIVE|NB_GROUP);
+ add_name_entry(name,0x0 ,NB_ACTIVE|NB_GROUP);
+ add_server_entry(d,w,myname,w->ServerType,0,ServerComment,True);
+ }
+
+ DEBUG(3,("Added domain name entry %s at %s\n", name,inet_ntoa(ip)));
+ return d;
+ }
+ return NULL;
+}
+
+/****************************************************************************
+ add a browser entry
+ ****************************************************************************/
+struct browse_cache_record *add_browser_entry(char *name, int type, char *wg,
+ time_t ttl, struct in_addr ip)
+{
+ BOOL newentry=False;
+
+ struct browse_cache_record *b;
+
+ /* search for the entry: if it's already in the cache, update that entry */
+ for (b = browserlist; b; b = b->next)
+ {
+ if (ip_equal(ip,b->ip) && strequal(b->group, wg)) break;
+ }
+
+ if (b && b->synced)
+ {
+ /* entries get left in the cache for a while. this stops sync'ing too
+ often if the network is large */
+ DEBUG(4, ("browser %s %s %s already sync'd at time %d\n",
+ b->name, b->group, inet_ntoa(b->ip), b->sync_time));
+ return NULL;
+ }
+
+ if (!b)
+ {
+ newentry = True;
+ b = (struct browse_cache_record *)malloc(sizeof(*b));
+
+ if (!b) return(NULL);
+
+ bzero((char *)b,sizeof(*b));
+ }
+
+ /* update the entry */
+ ttl = time(NULL)+ttl;
+
+ StrnCpy(b->name ,name,sizeof(b->name )-1);
+ StrnCpy(b->group,wg ,sizeof(b->group)-1);
+ strupper(b->name);
+ strupper(b->group);
+
+ b->ip = ip;
+ b->type = type;
+
+ if (newentry || ttl < b->sync_time) b->sync_time = ttl;
+
+ if (newentry)
+ {
+ b->synced = False;
+ add_browse_cache(b);
+
+ DEBUG(3,("Added cache entry %s %s(%2x) %s ttl %d\n",
+ wg, name, type, inet_ntoa(ip),ttl));
+ }
+ else
+ {
+ DEBUG(3,("Updated cache entry %s %s(%2x) %s ttl %d\n",
+ wg, name, type, inet_ntoa(ip),ttl));
+ }
+
+ return(b);
+}
+
+
+/****************************************************************************
+ add a server entry
+ ****************************************************************************/
+struct server_record *add_server_entry(struct domain_record *d,
+ struct work_record *work,
+ char *name,int servertype,
+ int ttl,char *comment,
+ BOOL replace)
+{
+ BOOL newentry=False;
+ struct server_record *s;
+
+ if (name[0] == '*')
+ {
+ return (NULL);
+ }
+
+ for (s = work->serverlist; s; s = s->next)
+ {
+ if (strequal(name,s->serv.name)) break;
+ }
+
+ if (s && !replace)
+ {
+ DEBUG(4,("Not replacing %s\n",name));
+ return(s);
+ }
+
+ updatedlists=True;
+
+ if (!s)
+ {
+ newentry = True;
+ s = (struct server_record *)malloc(sizeof(*s));
+
+ if (!s) return(NULL);
+
+ bzero((char *)s,sizeof(*s));
+ }
+
+ if (ip_equal(bcast_ip, d->bcast_ip) &&
+ strequal(lp_workgroup(),work->work_group))
+ {
+ servertype |= SV_TYPE_LOCAL_LIST_ONLY;
+ }
+ else
+ {
+ servertype &= ~SV_TYPE_LOCAL_LIST_ONLY;
+ }
+
+ /* update the entry */
+ StrnCpy(s->serv.name,name,sizeof(s->serv.name)-1);
+ StrnCpy(s->serv.comment,comment,sizeof(s->serv.comment)-1);
+ strupper(s->serv.name);
+ s->serv.type = servertype;
+ s->death_time = ttl?time(NULL)+ttl*3:0;
+
+ /* for a domain entry, the comment field refers to the server name */
+
+ if (s->serv.type & SV_TYPE_DOMAIN_ENUM) strupper(s->serv.comment);
+
+ if (newentry)
+ {
+ add_server(work, s);
+
+ DEBUG(3,("Added "));
+ }
+ else
+ {
+ DEBUG(3,("Updated "));
+ }
+
+ DEBUG(3,("server entry %s of type %x (%s) to %s %s\n",
+ name,servertype,comment,
+ work->work_group,inet_ntoa(d->bcast_ip)));
+
+ return(s);
+}
+
+
+/*******************************************************************
+ write out browse.dat
+ ******************************************************************/
+void write_browse_list(void)
+{
+ struct domain_record *d;
+
+ pstring fname,fnamenew;
+ FILE *f;
+
+ if (!updatedlists) return;
+
+ dump_names();
+ dump_workgroups();
+
+ updatedlists = False;
+ updatecount++;
+
+ strcpy(fname,lp_lockdir());
+ trim_string(fname,NULL,"/");
+ strcat(fname,"/");
+ strcat(fname,SERVER_LIST);
+ strcpy(fnamenew,fname);
+ strcat(fnamenew,".");
+
+ f = fopen(fnamenew,"w");
+
+ if (!f)
+ {
+ DEBUG(4,("Can't open %s - %s\n",fnamenew,strerror(errno)));
+ return;
+ }
+
+ for (d = domainlist; d ; d = d->next)
+ {
+ struct work_record *work;
+ for (work = d->workgrouplist; work ; work = work->next)
+ {
+ struct server_record *s;
+ for (s = work->serverlist; s ; s = s->next)
+ {
+ fstring tmp;
+
+ /* don't list domains I don't have a master for */
+ if ((s->serv.type & SV_TYPE_DOMAIN_ENUM) &&
+ !s->serv.comment[0])
+ {
+ continue;
+ }
+
+ /* output server details, plus what workgroup/domain
+ they're in. without the domain information, the
+ combined list of all servers in all workgroups gets
+ sent to anyone asking about any workgroup! */
+
+ sprintf(tmp, "\"%s\"", s->serv.name);
+ fprintf(f, "%-25s ", tmp);
+ fprintf(f, "%08x ", s->serv.type);
+ sprintf(tmp, "\"%s\" ", s->serv.comment);
+ fprintf(f, "%-30s", tmp);
+ fprintf(f, "\"%s\"\n", work->work_group);
+ }
+ }
+ }
+
+ fclose(f);
+ unlink(fname);
+ chmod(fnamenew,0644);
+ rename(fnamenew,fname);
+ DEBUG(3,("Wrote browse list %s\n",fname));
+}
+
+
+/*******************************************************************
+ expire old servers in the serverlist
+ ******************************************************************/
+void expire_servers(time_t t)
+{
+ struct domain_record *d;
+
+ for (d = domainlist ; d ; d = d->next)
+ {
+ struct work_record *work;
+
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ remove_old_servers(work, t);
+ }
+ }
+}
+
diff --git a/source/nameelect.c b/source/nameelect.c
new file mode 100644
index 00000000000..8ceae473a78
--- /dev/null
+++ b/source/nameelect.c
@@ -0,0 +1,369 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1995
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+*/
+
+#include "includes.h"
+#include "loadparm.h"
+#include "localnet.h"
+
+extern int DEBUGLEVEL;
+extern pstring scope;
+
+extern pstring myname;
+
+/* machine comment for host announcements */
+extern pstring ServerComment;
+
+/* here are my election parameters */
+
+extern time_t StartupTime;
+
+#define AM_MASTER(work) (work->ServerType & SV_TYPE_MASTER_BROWSER)
+
+#define MSBROWSE "\001\002__MSBROWSE__\002"
+#define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE"
+
+extern struct domain_record *domainlist;
+
+
+/*******************************************************************
+ occasionally check to see if the master browser is around
+ ******************************************************************/
+void check_master_browser(void)
+{
+ static time_t lastrun=0;
+ time_t t = time(NULL);
+ struct domain_record *d;
+
+ if (!lastrun) lastrun = t;
+ if (t < lastrun + 2*60) return;
+ lastrun = t;
+
+ dump_workgroups();
+
+ for (d = domainlist; d; d = d->next)
+ {
+ struct work_record *work;
+
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ /* if we are not the browse master of a workgroup, and we can't
+ find a browser on the subnet, do something about it. */
+
+ if (!AM_MASTER(work))
+ {
+ queue_netbios_packet(ClientNMB,NMB_QUERY,CHECK_MASTER,
+ work->work_group,0x1d,0,
+ True,False,d->bcast_ip);
+ }
+ }
+ }
+}
+
+
+/*******************************************************************
+ what to do if a master browser DOESN't exist
+ ******************************************************************/
+void browser_gone(char *work_name, struct in_addr ip)
+{
+ struct domain_record *d = find_domain(ip);
+ struct work_record *work = find_workgroupstruct(d, work_name, False);
+
+ if (!work || !d) return;
+
+ DEBUG(2,("Forcing election on %s\n",work->work_group));
+
+ if (strequal(work->work_group, lp_workgroup()) &&
+ ip_equal(bcast_ip, d->bcast_ip))
+ {
+ /* we can attempt to become master browser */
+ work->needelection = True;
+ }
+ else
+ {
+ DEBUG(2,("no master browser for persistent entry %s %s\n",
+ work->work_group, inet_ntoa(d->bcast_ip)));
+
+ /* XXXX oh dear. we are going to have problems here. the
+ entry is a persistent one, there isn't anyone responsible
+ for this workgroup up and running, yet we can't find it
+ and we are going to continually have name_queries until
+ a master browser is found for this workgroup on the
+ remote subnet.
+ */
+ }
+}
+/****************************************************************************
+ send an election packet
+ **************************************************************************/
+void send_election(struct domain_record *d, char *group,uint32 criterion,
+ int timeup,char *name)
+{
+ pstring outbuf;
+ char *p;
+
+ if (!d) return;
+
+ DEBUG(2,("Sending election to %s for workgroup %s\n",
+ inet_ntoa(d->bcast_ip),group));
+
+ bzero(outbuf,sizeof(outbuf));
+ p = outbuf;
+ CVAL(p,0) = 8; /* election */
+ p++;
+
+ CVAL(p,0) = (criterion == 0 && timeup == 0) ? 0 : ELECTION_VERSION;
+ SIVAL(p,1,criterion);
+ SIVAL(p,5,timeup*1000); /* ms - despite the spec */
+ p += 13;
+ strcpy(p,name);
+ strupper(p);
+ p = skip_string(p,1);
+
+ send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
+ name,group,0,0x1e,d->bcast_ip,myip);
+}
+
+
+/*******************************************************************
+ become the master browser
+ ******************************************************************/
+static void become_master(struct domain_record *d, struct work_record *work)
+{
+ uint32 domain_type = SV_TYPE_DOMAIN_ENUM | SV_TYPE_SERVER_UNIX | 0x00400000;
+
+ if (!work) return;
+
+ DEBUG(2,("Becoming master for %s\n",work->work_group));
+
+ work->ServerType |= SV_TYPE_MASTER_BROWSER;
+ work->ServerType &= ~SV_TYPE_POTENTIAL_BROWSER;
+ work->ElectionCriterion |= 0x5;
+
+ /* add browse, master and general names to database or register with WINS */
+ add_name_entry(MSBROWSE ,0x01,NB_ACTIVE|NB_GROUP);
+ add_name_entry(work->work_group,0x1d,NB_ACTIVE );
+
+ if (lp_domain_master())
+ {
+ DEBUG(4,("Domain master: adding names...\n"));
+
+ /* add domain master and domain member names or register with WINS */
+ add_name_entry(work->work_group,0x1b,NB_ACTIVE );
+ add_name_entry(work->work_group,0x1c,NB_ACTIVE|NB_GROUP);
+
+ work->ServerType |= SV_TYPE_DOMAIN_MASTER;
+
+ if (lp_domain_logons())
+ {
+ work->ServerType |= SV_TYPE_DOMAIN_CTRL;
+ work->ServerType |= SV_TYPE_DOMAIN_MEMBER;
+ }
+ }
+
+ /* update our server status */
+ add_server_entry(d,work,work->work_group,domain_type,0,myname,True);
+ add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True);
+
+ if (ip_equal(bcast_ip, d->bcast_ip))
+ {
+ /* ask all servers on our local net to announce to us */
+ announce_request(work, d->bcast_ip);
+ }
+}
+
+
+/*******************************************************************
+ unbecome the master browser
+ ******************************************************************/
+void become_nonmaster(struct domain_record *d, struct work_record *work)
+{
+ DEBUG(2,("Becoming non-master for %s\n",work->work_group));
+
+ work->ServerType &= ~SV_TYPE_MASTER_BROWSER;
+ work->ServerType &= ~SV_TYPE_DOMAIN_MASTER;
+ work->ServerType |= SV_TYPE_POTENTIAL_BROWSER;
+
+ work->ElectionCriterion &= ~0x4;
+
+ remove_name_entry(work->work_group,0x1b);
+ remove_name_entry(work->work_group,0x1c);
+ remove_name_entry(work->work_group,0x1d);
+ remove_name_entry(MSBROWSE ,0x01);
+}
+
+
+/*******************************************************************
+ run the election
+ ******************************************************************/
+void run_elections(void)
+{
+ time_t t = time(NULL);
+ static time_t lastime = 0;
+
+ struct domain_record *d;
+
+ /* send election packets once a second */
+ if (lastime && t-lastime <= 0) return;
+
+ lastime = t;
+
+ for (d = domainlist; d; d = d->next)
+ {
+ struct work_record *work;
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ if (work->RunningElection)
+ {
+ send_election(d,work->work_group, work->ElectionCriterion,
+ t-StartupTime,myname);
+
+ if (work->ElectionCount++ >= 4)
+ {
+ /* I won! now what :-) */
+ DEBUG(2,(">>> Won election on %s <<<\n",work->work_group));
+
+ work->RunningElection = False;
+ become_master(d, work);
+ }
+ }
+ }
+ }
+}
+
+
+/*******************************************************************
+ work out if I win an election
+ ******************************************************************/
+static BOOL win_election(struct work_record *work,int version,uint32 criterion,
+ int timeup,char *name)
+{
+ time_t t = time(NULL);
+ uint32 mycriterion;
+ if (version > ELECTION_VERSION) return(False);
+ if (version < ELECTION_VERSION) return(True);
+
+ mycriterion = work->ElectionCriterion;
+
+ if (criterion > mycriterion) return(False);
+ if (criterion < mycriterion) return(True);
+
+ if (timeup > (t - StartupTime)) return(False);
+ if (timeup < (t - StartupTime)) return(True);
+
+ if (strcasecmp(myname,name) > 0) return(False);
+
+ return(True);
+}
+
+
+/*******************************************************************
+ process a election packet
+
+ An election dynamically decides who will be the master.
+ ******************************************************************/
+void process_election(struct packet_struct *p,char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ struct in_addr ip = dgram->header.source_ip;
+ struct domain_record *d = find_domain(ip);
+ int version = CVAL(buf,0);
+ uint32 criterion = IVAL(buf,1);
+ int timeup = IVAL(buf,5)/1000;
+ char *name = buf+13;
+ struct work_record *work;
+
+ if (!d) return;
+
+ name[15] = 0;
+
+ DEBUG(3,("Election request from %s vers=%d criterion=%08x timeup=%d\n",
+ name,version,criterion,timeup));
+
+ if (same_context(dgram)) return;
+
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ if (listening_name(work, &dgram->dest_name) &&
+ strequal(work->work_group, lp_workgroup()) &&
+ ip_equal(d->bcast_ip, bcast_ip))
+ {
+ if (win_election(work, version,criterion,timeup,name))
+ {
+ if (!work->RunningElection)
+ {
+ work->needelection = True;
+ work->ElectionCount=0;
+ }
+ }
+ else
+ {
+ work->needelection = False;
+
+ if (work->RunningElection)
+ {
+ work->RunningElection = False;
+ DEBUG(3,(">>> Lost election on %s <<<\n",work->work_group));
+
+ /* if we are the master then remove our masterly names */
+ if (AM_MASTER(work))
+ {
+ become_nonmaster(d, work);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+/****************************************************************************
+ checks whether a browser election is to be run on any workgroup
+ ***************************************************************************/
+BOOL check_elections(void)
+{
+ struct domain_record *d;
+ BOOL run_any_election = False;
+
+ for (d = domainlist; d; d = d->next)
+ {
+ struct work_record *work;
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ run_any_election |= work->RunningElection;
+
+ if (work->needelection && !work->RunningElection)
+ {
+ DEBUG(3,(">>> Starting election on %s <<<\n",work->work_group));
+ work->ElectionCount = 0;
+ work->RunningElection = True;
+ work->needelection = False;
+ }
+ }
+ }
+ return run_any_election;
+}
+
diff --git a/source/nameresp.c b/source/nameresp.c
new file mode 100644
index 00000000000..435864a7843
--- /dev/null
+++ b/source/nameresp.c
@@ -0,0 +1,628 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios library routines
+ Copyright (C) Andrew Tridgell 1994-1995
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+#include "localnet.h"
+#include "loadparm.h"
+
+/* this is our initiated name query response database */
+struct name_response_record *nameresponselist = NULL;
+
+extern struct in_addr myip;
+extern int DEBUGLEVEL;
+
+static uint16 name_trn_id=0;
+BOOL CanRecurse = True;
+extern pstring scope;
+extern pstring myname;
+extern struct in_addr ipzero;
+
+
+/***************************************************************************
+ add an initated name query into the list
+ **************************************************************************/
+extern void add_response_record(struct name_response_record *n)
+{
+ struct name_response_record *n2;
+
+ if (!nameresponselist)
+ {
+ nameresponselist = n;
+ n->prev = NULL;
+ n->next = NULL;
+ return;
+ }
+
+ for (n2 = nameresponselist; n2->next; n2 = n2->next) ;
+
+ n2->next = n;
+ n->next = NULL;
+ n->prev = n2;
+}
+
+
+/*******************************************************************
+ remove old name response entries
+ ******************************************************************/
+void expire_netbios_response_entries(time_t t)
+{
+ struct name_response_record *n;
+ struct name_response_record *nextn;
+
+ for (n = nameresponselist; n; n = nextn)
+ {
+ if (n->start_time < t)
+ {
+ DEBUG(3,("Removing dead name query for %s %s (num_msgs=%d)\n",
+ inet_ntoa(n->to_ip), namestr(&n->name), n->num_msgs));
+
+ if (n->cmd_type == CHECK_MASTER && n->num_msgs == 0)
+ {
+ if (n->num_msgs > 1)
+ {
+ /* more than one master browser detected on a subnet.
+ there is a configuration problem. force an election */
+ struct domain_record *d;
+ if ((d = find_domain(n->to_ip)))
+ {
+ send_election(d,n->name.name,0,0,myname);
+ }
+ }
+
+ /* if no response received, the master browser must have gone */
+ browser_gone(n->name.name, n->to_ip);
+ }
+
+ nextn = n->next;
+
+ if (n->prev) n->prev->next = n->next;
+ if (n->next) n->next->prev = n->prev;
+
+ if (nameresponselist == n) nameresponselist = n->next;
+
+ free(n);
+ }
+ else
+ {
+ nextn = n->next;
+ }
+ }
+}
+
+
+/****************************************************************************
+ reply to a netbios name packet
+ ****************************************************************************/
+void reply_netbios_packet(struct packet_struct *p1,int trn_id,int rcode,int opcode,
+ struct nmb_name *rr_name,int rr_type,int rr_class,int ttl,
+ char *data,int len)
+{
+ struct packet_struct p;
+ struct nmb_packet *nmb = &p.packet.nmb;
+ struct res_rec answers;
+ char *packet_type = "unknown";
+
+ p = *p1;
+
+ if (rr_type == NMB_STATUS) packet_type = "nmb_status";
+ if (rr_type == NMB_QUERY ) packet_type = "nmb_query";
+ if (rr_type == NMB_REG ) packet_type = "nmb_reg";
+ if (rr_type == NMB_REL ) packet_type = "nmb_rel";
+
+ DEBUG(4,("replying netbios packet: %s %s\n",
+ packet_type, namestr(rr_name), inet_ntoa(p.ip)));
+
+ nmb->header.name_trn_id = trn_id;
+ nmb->header.opcode = opcode;
+ nmb->header.response = True;
+ nmb->header.nm_flags.bcast = False;
+ nmb->header.nm_flags.recursion_available = True;
+ nmb->header.nm_flags.recursion_desired = True;
+ nmb->header.nm_flags.trunc = False;
+ nmb->header.nm_flags.authoritative = True;
+
+ nmb->header.qdcount = 0;
+ nmb->header.ancount = 1;
+ nmb->header.nscount = 0;
+ nmb->header.arcount = 0;
+ nmb->header.rcode = 0;
+
+ bzero((char*)&nmb->question,sizeof(nmb->question));
+
+ nmb->answers = &answers;
+ bzero((char*)nmb->answers,sizeof(*nmb->answers));
+
+ nmb->answers->rr_name = *rr_name;
+ nmb->answers->rr_type = rr_type;
+ nmb->answers->rr_class = rr_class;
+ nmb->answers->ttl = ttl;
+
+ if (data && len)
+ {
+ nmb->answers->rdlength = len;
+ memcpy(nmb->answers->rdata, data, len);
+ }
+
+ p.packet_type = NMB_PACKET;
+
+ debug_nmb_packet(&p);
+
+ send_packet(&p);
+}
+
+
+/****************************************************************************
+ initiate a netbios packet
+ ****************************************************************************/
+uint16 initiate_netbios_packet(int fd,int quest_type,char *name,int name_type,
+ int nb_flags,BOOL bcast,BOOL recurse,
+ struct in_addr to_ip)
+{
+ struct packet_struct p;
+ struct nmb_packet *nmb = &p.packet.nmb;
+ struct res_rec additional_rec;
+ char *packet_type = "unknown";
+ int opcode = -1;
+
+ if (quest_type == NMB_STATUS) { packet_type = "nmb_status"; opcode = 0; }
+ if (quest_type == NMB_QUERY ) { packet_type = "nmb_query"; opcode = 0; }
+ if (quest_type == NMB_REG ) { packet_type = "nmb_reg"; opcode = 5; }
+ if (quest_type == NMB_REL ) { packet_type = "nmb_rel"; opcode = 6; }
+
+ DEBUG(4,("initiating netbios packet: %s %s(%x) (bcast=%s) %s\n",
+ packet_type, name, name_type, BOOLSTR(bcast), inet_ntoa(to_ip)));
+
+ if (opcode == -1) return False;
+
+ bzero((char *)&p,sizeof(p));
+
+ if (!name_trn_id) name_trn_id = (time(NULL)%(unsigned)0x7FFF) +
+ (getpid()%(unsigned)100);
+ name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
+
+ nmb->header.name_trn_id = name_trn_id;
+ nmb->header.opcode = opcode;
+ nmb->header.response = False;
+ nmb->header.nm_flags.bcast = bcast;
+ nmb->header.nm_flags.recursion_available = CanRecurse;
+ nmb->header.nm_flags.recursion_desired = recurse;
+ nmb->header.nm_flags.trunc = False;
+ nmb->header.nm_flags.authoritative = False;
+ nmb->header.rcode = 0;
+ nmb->header.qdcount = 1;
+ nmb->header.ancount = 0;
+ nmb->header.nscount = 0;
+ nmb->header.arcount = (quest_type==NMB_REG || quest_type==NMB_REL) ? 1 : 0;
+
+ make_nmb_name(&nmb->question.question_name,name,name_type,scope);
+
+ nmb->question.question_type = quest_type;
+ nmb->question.question_class = 0x1;
+
+ if (quest_type == NMB_REG || quest_type == NMB_REL)
+ {
+ nmb->additional = &additional_rec;
+ bzero((char *)nmb->additional,sizeof(*nmb->additional));
+
+ nmb->additional->rr_name = nmb->question.question_name;
+ nmb->additional->rr_type = nmb->question.question_type;
+ nmb->additional->rr_class = nmb->question.question_class;
+
+ nmb->additional->ttl = quest_type == NMB_REG ? lp_max_ttl() : 0;
+ nmb->additional->rdlength = 6;
+ nmb->additional->rdata[0] = nb_flags;
+ putip(&nmb->additional->rdata[2],(char *)&myip);
+ }
+
+ p.ip = to_ip;
+ p.port = NMB_PORT;
+ p.fd = fd;
+ p.timestamp = time(NULL);
+ p.packet_type = NMB_PACKET;
+
+ if (!send_packet(&p))
+ return(0);
+
+ return(name_trn_id);
+}
+
+
+/****************************************************************************
+ wrapper function to override a broadcast message and send it to the WINS
+ name server instead, if it exists. if wins is false, and there has been no
+ WINS server specified, the packet will NOT be sent.
+ ****************************************************************************/
+void queue_netbios_pkt_wins(int fd,int quest_type,enum cmd_type cmd,
+ char *name,int name_type,int nb_flags,
+ BOOL bcast,BOOL recurse,struct in_addr to_ip)
+{
+ if ((!lp_wins_support()) && (*lp_wins_server()))
+ {
+ /* samba is not a WINS server, and we are using a WINS server */
+ struct in_addr wins_ip;
+ wins_ip = *interpret_addr2(lp_wins_server());
+
+ if (!zero_ip(wins_ip))
+ {
+ bcast = False;
+ to_ip = wins_ip;
+ }
+ else
+ {
+ /* oops. smb.conf's wins server parameter MUST be a host_name
+ or an ip_address. */
+ DEBUG(0,("invalid smb.conf parameter 'wins server'\n"));
+ }
+ }
+
+ if (zero_ip(to_ip)) return;
+
+ queue_netbios_packet(fd, quest_type, cmd,
+ name, name_type, nb_flags,
+ bcast, recurse, to_ip);
+}
+
+/****************************************************************************
+ create a name query response record
+ **************************************************************************/
+static struct name_response_record *make_name_query_record(
+ enum cmd_type cmd,int id,int fd,
+ char *name,int type,
+ BOOL bcast,BOOL recurse,
+ struct in_addr ip)
+{
+ struct name_response_record *n;
+
+ if (!name || !name[0]) return NULL;
+
+ if (!(n = (struct name_response_record *)malloc(sizeof(*n))))
+ return(NULL);
+
+ n->response_id = id;
+ n->cmd_type = cmd;
+ n->fd = fd;
+ make_nmb_name(&n->name, name, type, scope);
+ n->bcast = bcast;
+ n->recurse = recurse;
+ n->to_ip = ip;
+ n->start_time = time(NULL);
+ n->num_msgs = 0;
+
+ return n;
+}
+
+
+/****************************************************************************
+ initiate a netbios name query to find someone's or someones' IP
+ this is intended to be used (not exclusively) for broadcasting to
+ master browsers (WORKGROUP(1d or 1b) or __MSBROWSE__(1)) to get
+ complete lists across a wide area network
+ ****************************************************************************/
+void queue_netbios_packet(int fd,int quest_type,enum cmd_type cmd,char *name,
+ int name_type,int nb_flags,BOOL bcast,BOOL recurse,
+ struct in_addr to_ip)
+{
+ uint16 id = initiate_netbios_packet(fd, quest_type, name, name_type,
+ nb_flags, bcast, recurse, to_ip);
+ struct name_response_record *n;
+
+ if (id == 0) return;
+
+ if ((n =
+ make_name_query_record(cmd,id,fd,name,name_type,bcast,recurse,to_ip)))
+ {
+ add_response_record(n);
+ }
+}
+
+
+/****************************************************************************
+ find a response in the name query response list
+ **************************************************************************/
+struct name_response_record *find_name_query(uint16 id)
+{
+ struct name_response_record *n;
+
+ for (n = nameresponselist; n; n = n->next)
+ {
+ if (n->response_id == id) {
+ return n;
+ }
+ }
+
+ return NULL;
+}
+
+
+/*******************************************************************
+ the global packet linked-list. incoming entries are added to the
+ end of this list. it is supposed to remain fairly short so we
+ won't bother with an end pointer.
+ ******************************************************************/
+static struct packet_struct *packet_queue = NULL;
+
+/*******************************************************************
+ queue a packet into the packet queue
+ ******************************************************************/
+void queue_packet(struct packet_struct *packet)
+{
+ struct packet_struct *p;
+
+ if (!packet_queue) {
+ packet->prev = NULL;
+ packet->next = NULL;
+ packet_queue = packet;
+ return;
+ }
+
+ /* find the bottom */
+ for (p=packet_queue;p->next;p=p->next) ;
+
+ p->next = packet;
+ packet->next = NULL;
+ packet->prev = p;
+}
+
+/*******************************************************************
+ run elements off the packet queue till its empty
+ ******************************************************************/
+void run_packet_queue()
+{
+ struct packet_struct *p;
+
+ while ((p=packet_queue))
+ {
+ switch (p->packet_type)
+ {
+ case NMB_PACKET:
+ process_nmb(p);
+ break;
+
+ case DGRAM_PACKET:
+ process_dgram(p);
+ break;
+ }
+
+ packet_queue = packet_queue->next;
+ if (packet_queue) packet_queue->prev = NULL;
+ free_packet(p);
+ }
+}
+
+/****************************************************************************
+ listens for NMB or DGRAM packets, and queues them
+ ***************************************************************************/
+void listen_for_packets(BOOL run_election)
+{
+ fd_set fds;
+ int selrtn;
+ struct timeval timeout;
+
+ FD_ZERO(&fds);
+ FD_SET(ClientNMB,&fds);
+ FD_SET(ClientDGRAM,&fds);
+
+ /* during elections we need to send election packets at one
+ second intervals */
+
+ timeout.tv_sec = run_election ? 1 : NMBD_SELECT_LOOP;
+ timeout.tv_usec = 0;
+
+ selrtn = sys_select(&fds,&timeout);
+
+ if (FD_ISSET(ClientNMB,&fds))
+ {
+ struct packet_struct *packet = read_packet(ClientNMB, NMB_PACKET);
+ if (packet) {
+#if 1
+ if (ip_equal(packet->ip,myip) &&
+ (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 (ip_equal(packet->ip,myip) &&
+ (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);
+ }
+ }
+ }
+}
+
+
+
+/****************************************************************************
+interpret a node status response. this is pretty hacked: we need two bits of
+info. a) the name of the workgroup b) the name of the server. it will also
+add all the names it finds into the namelist.
+****************************************************************************/
+BOOL interpret_node_status(char *p, struct nmb_name *name,int t,
+ char *serv_name, struct in_addr ip)
+{
+ int level = t==0x20 ? 4 : 0;
+ int numnames = CVAL(p,0);
+ BOOL found = False;
+
+ DEBUG(level,("received %d names\n",numnames));
+
+ p += 1;
+
+ if (serv_name) *serv_name = 0;
+
+ while (numnames--)
+ {
+ char qname[17];
+ int type;
+ fstring flags;
+ int nb_flags;
+
+ BOOL group = False;
+ BOOL add = False;
+
+ *flags = 0;
+
+ StrnCpy(qname,p,15);
+ type = CVAL(p,15);
+ nb_flags = p[16];
+
+ p += 18;
+
+ if (NAME_GROUP (nb_flags)) { strcat(flags,"<GROUP> "); group=True;}
+ if (NAME_BFLAG (nb_flags)) { strcat(flags,"B "); }
+ if (NAME_PFLAG (nb_flags)) { strcat(flags,"P "); }
+ if (NAME_MFLAG (nb_flags)) { strcat(flags,"M "); }
+ if (NAME__FLAG (nb_flags)) { strcat(flags,"_ "); }
+ if (NAME_DEREG (nb_flags)) { strcat(flags,"<DEREGISTERING> "); }
+ if (NAME_CONFLICT (nb_flags)) { strcat(flags,"<CONFLICT> "); add=True;}
+ if (NAME_ACTIVE (nb_flags)) { strcat(flags,"<ACTIVE> "); add=True; }
+ if (NAME_PERMANENT(nb_flags)) { strcat(flags,"<PERMANENT> "); add=True;}
+
+ /* might as well update our namelist while we're at it */
+ if (add)
+ {
+ struct in_addr nameip;
+ enum name_source src;
+
+ if (ip_equal(ip, myip))
+ {
+ nameip = ipzero;
+ src = SELF;
+ }
+ else
+ {
+ nameip = ip;
+ src = STATUS_QUERY;
+ }
+ add_netbios_entry(qname,type,nb_flags,2*60*60,src,nameip);
+ }
+
+ /* we want the server name */
+ if (serv_name && !*serv_name && !group && t == 0)
+ {
+ StrnCpy(serv_name,qname,15);
+ serv_name[15] = 0;
+ }
+
+ /* looking for a name and type? */
+ if (name && !found && (t == type))
+ {
+ /* take a guess at some of the name types we're going to ask for.
+ evaluate whether they are group names or no... */
+ if (((t == 0x1b || t == 0x1d ) && !group) ||
+ ((t == 0x20 || t == 0x1c || t == 0x1e) && group))
+ {
+ found = True;
+ make_nmb_name(name,qname,type,scope);
+ }
+ }
+
+ DEBUG(level,("\t%s(0x%x)\t%s\n",qname,type,flags));
+ }
+ DEBUG(level,("num_good_sends=%d num_good_receives=%d\n",
+ IVAL(p,20),IVAL(p,24)));
+ return found;
+}
+
+
+/****************************************************************************
+ construct and send a netbios DGRAM
+
+ Note that this currently sends all answers to port 138. thats the
+ wrong things to do! I should send to the requestors port. XXX
+ **************************************************************************/
+BOOL send_mailslot_reply(char *mailslot,int fd,char *buf,int len,char *srcname,
+ char *dstname,int src_type,int dest_type,
+ struct in_addr dest_ip,struct in_addr src_ip)
+{
+ struct packet_struct p;
+ struct dgram_packet *dgram = &p.packet.dgram;
+ char *ptr,*p2;
+ char tmp[4];
+
+ bzero((char *)&p,sizeof(p));
+
+ dgram->header.msg_type = 0x11; /* DIRECT GROUP DATAGRAM */
+ dgram->header.flags.node_type = M_NODE;
+ dgram->header.flags.first = True;
+ dgram->header.flags.more = False;
+ dgram->header.dgm_id = name_trn_id++;
+ dgram->header.source_ip = src_ip;
+ dgram->header.source_port = DGRAM_PORT;
+ dgram->header.dgm_length = 0; /* let build_dgram() handle this */
+ dgram->header.packet_offset = 0;
+
+ make_nmb_name(&dgram->source_name,srcname,src_type,scope);
+ make_nmb_name(&dgram->dest_name,dstname,dest_type,scope);
+
+ ptr = &dgram->data[0];
+
+ /* now setup the smb part */
+ ptr -= 4; /* XXX ugliness because of handling of tcp SMB length */
+ memcpy(tmp,ptr,4);
+ set_message(ptr,17,17 + len,True);
+ memcpy(ptr,tmp,4);
+
+ CVAL(ptr,smb_com) = SMBtrans;
+ SSVAL(ptr,smb_vwv1,len);
+ SSVAL(ptr,smb_vwv11,len);
+ SSVAL(ptr,smb_vwv12,70 + strlen(mailslot));
+ SSVAL(ptr,smb_vwv13,3);
+ SSVAL(ptr,smb_vwv14,1);
+ SSVAL(ptr,smb_vwv15,1);
+ SSVAL(ptr,smb_vwv16,2);
+ p2 = smb_buf(ptr);
+ strcpy(p2,mailslot);
+ p2 = skip_string(p2,1);
+
+ memcpy(p2,buf,len);
+ p2 += len;
+
+ dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length */
+
+ p.ip = dest_ip;
+ p.port = DGRAM_PORT;
+ p.fd = ClientDGRAM;
+ p.timestamp = time(NULL);
+ p.packet_type = DGRAM_PACKET;
+
+ return(send_packet(&p));
+}
+
+
diff --git a/source/nameserv.c b/source/nameserv.c
index 802b98ec0a0..b6bc8a4f060 100644
--- a/source/nameserv.c
+++ b/source/nameserv.c
@@ -18,202 +18,32 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
*/
#include "includes.h"
#include "loadparm.h"
-#include "nameserv.h"
+#include "localnet.h"
-static void queue_packet(struct packet_struct *packet);
-void process(void);
-static void dump_names(void);
-static void announce_request(char *group);
-void sync_browse_lists(char *name,int name_type,char *myname,
- char *domain,struct in_addr ip);
+enum name_search { FIND_SELF, FIND_GLOBAL };
extern int DEBUGLEVEL;
-extern pstring debugf;
-pstring servicesf = CONFIGFILE;
-
extern pstring scope;
-
extern BOOL CanRecurse;
+extern pstring myname;
+extern struct in_addr ipzero;
-extern struct in_addr myip;
-extern struct in_addr bcast_ip;
-extern struct in_addr Netmask;
-extern pstring myhostname;
-static pstring host_file;
-static pstring myname="";
-
-static int ClientNMB= -1;
-static int ClientDGRAM= -1;
-
-static BOOL needannounce=True;
-
-/* this is our name database */
-static struct name_record *namelist = NULL;
-
-/* list of servers to be returned by NetServerEnum */
-static struct server_record *serverlist = NULL;
-
-/* this is the domain list. For the moment we will assume that our
- primary domain is the first one listed in this list */
-static struct domain_record *domainlist = NULL;
-
-/* are we running as a daemon ? */
-static BOOL is_daemon = False;
-
-/* machine comment for host announcements */
-static pstring ServerComment="";
-
-static BOOL got_bcast = False;
-static BOOL got_myip = False;
-static BOOL got_nmask = False;
-
-static BOOL updatedlists = False;
-static int updatecount=0;
-
-/* what server type are we currently */
-static int ServerType =
-SV_TYPE_WORKSTATION | SV_TYPE_SERVER | SV_TYPE_TIME_SOURCE |
-SV_TYPE_SERVER_UNIX |
-SV_TYPE_PRINTQ_SERVER | SV_TYPE_POTENTIAL_BROWSER;
-
-/* here are my election parameters */
-
-/* NTAS uses 2, NT uses 1, WfWg uses 0 */
-#define MAINTAIN_LIST 1
-#define ELECTION_VERSION 1
-
-static BOOL RunningElection = False;
-static BOOL needelection = False;
-static int ElectionCount = 0;
-static int StartupTime =0;
-
-
-/* WfWg uses 01040b01 */
-/* Win95 uses 01041501 */
-/* NTAS uses ?? */
-static uint32 ElectionCriterion = (MAINTAIN_LIST<<1)|(ELECTION_VERSION<<8);
-
-/* we currently support being the master for just one group. Being the
- master for more than one group might be tricky as NetServerEnum is
- often asked for a list without naming the group */
-static fstring PrimaryGroup="";
-
-#define AM_MASTER (PrimaryGroup[0] && (ServerType & SV_TYPE_MASTER_BROWSER))
-
-#define MSBROWSE "\001\002__MSBROWSE__\002"
+/* netbios names database */
+struct name_record *namelist;
#define GET_TTL(ttl) ((ttl)?MIN(ttl,lp_max_ttl()):lp_max_ttl())
-#define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE"
-
-/****************************************************************************
-catch a sighup
-****************************************************************************/
-static int sig_hup()
-{
- BlockSignals(True);
-
- DEBUG(0,("Got SIGHUP (reload not implemented)\n"));
- dump_names();
- reload_services(True);
-
- BlockSignals(False);
-#ifndef DONT_REINSTALL_SIG
- signal(SIGHUP,SIGNAL_CAST sig_hup);
-#endif
- return(0);
-}
-
-/****************************************************************************
-catch a sigpipe
-****************************************************************************/
-static int sig_pipe()
-{
- BlockSignals(True);
-
- DEBUG(0,("Got SIGPIPE\n"));
- if (!is_daemon)
- exit(1);
- BlockSignals(False);
- return(0);
-}
-
-#if DUMP_CORE
-/*******************************************************************
-prepare to dump a core file - carefully!
-********************************************************************/
-static BOOL dump_core(void)
-{
- char *p;
- pstring dname;
- strcpy(dname,debugf);
- if ((p=strrchr(dname,'/'))) *p=0;
- strcat(dname,"/corefiles");
- mkdir(dname,0700);
- sys_chown(dname,getuid(),getgid());
- chmod(dname,0700);
- if (chdir(dname)) return(False);
- umask(~(0700));
-
-#ifndef NO_GETRLIMIT
-#ifdef RLIMIT_CORE
- {
- struct rlimit rlp;
- getrlimit(RLIMIT_CORE, &rlp);
- rlp.rlim_cur = MAX(4*1024*1024,rlp.rlim_cur);
- setrlimit(RLIMIT_CORE, &rlp);
- getrlimit(RLIMIT_CORE, &rlp);
- DEBUG(3,("Core limits now %d %d\n",rlp.rlim_cur,rlp.rlim_max));
- }
-#endif
-#endif
-
-
- DEBUG(0,("Dumping core in %s\n",dname));
- return(True);
-}
-#endif
-
-
-/****************************************************************************
-possibly continue after a fault
-****************************************************************************/
-static void fault_continue(void)
-{
- static int errcount=1;
-
- errcount--;
-
- if (is_daemon && errcount)
- process();
-
-#if DUMP_CORE
- if (dump_core()) return;
-#endif
-
- return;
-}
-
-
-/*******************************************************************
- wrapper to get the DC
- ******************************************************************/
-static char *domain_controller(void)
-{
- char *dc = lp_domain_controller();
- /* so many people mistake this for a bool that we need to handle it. sigh. */
- if (!*dc || strequal(dc,"yes") || strequal(dc,"true"))
- strcpy(dc,myname);
- return(dc);
-}
-
-
/****************************************************************************
true if two netbios names are equal
@@ -232,7 +62,8 @@ static void add_name(struct name_record *n)
{
struct name_record *n2;
- if (!namelist) {
+ if (!namelist)
+ {
namelist = n;
n->prev = NULL;
n->next = NULL;
@@ -247,57 +78,17 @@ static void add_name(struct name_record *n)
}
/****************************************************************************
- add a domain into the list
- **************************************************************************/
-static void add_domain(struct domain_record *d)
-{
- struct domain_record *d2;
-
- if (!domainlist) {
- domainlist = d;
- d->prev = NULL;
- d->next = NULL;
- return;
- }
-
- for (d2 = domainlist; d2->next; d2 = d2->next) ;
-
- d2->next = d;
- d->next = NULL;
- d->prev = d2;
-}
-
-
-/****************************************************************************
- add a server into the list
- **************************************************************************/
-static void add_server(struct server_record *s)
-{
- struct server_record *s2;
-
- if (!serverlist) {
- serverlist = s;
- s->prev = NULL;
- s->next = NULL;
- return;
- }
-
- for (s2 = serverlist; s2->next; s2 = s2->next) ;
-
- s2->next = s;
- s->next = NULL;
- s->prev = s2;
-}
-
-/****************************************************************************
remove a name from the namelist. The pointer must be an element just
retrieved
**************************************************************************/
-static void remove_name(struct name_record *n)
+void remove_name(struct name_record *n)
{
struct name_record *nlist = namelist;
+
while (nlist && nlist != n) nlist = nlist->next;
- if (nlist) {
+
+ if (nlist)
+ {
if (nlist->next) nlist->next->prev = nlist->prev;
if (nlist->prev) nlist->prev->next = nlist->next;
free(nlist);
@@ -305,48 +96,80 @@ static void remove_name(struct name_record *n)
}
/****************************************************************************
- find a name in the namelist
+ find a name in the domain database namelist
+ search can be:
+ FIND_SELF - look for names the samba server has added for itself
+ FIND_GLOBAL - the name can be anyone. first look on the client's
+ subnet, then the server's subnet, then all subnets.
**************************************************************************/
-static struct name_record *find_name(struct nmb_name *n)
+static struct name_record *find_name_search(struct nmb_name *name, enum name_search search,
+ struct in_addr ip)
{
- struct name_record *ret;
- for (ret = namelist; ret; ret = ret->next)
- if (name_equal(&ret->name,n)) return(ret);
+ struct name_record *ret;
+
+ /* any number of winpopup names can be added. must search by ip as well */
+ if (name->name_type != 0x3) ip = ipzero;
+
+ for (ret = namelist; ret; ret = ret->next)
+ {
+ if (name_equal(&ret->name,name))
+ {
+ /* self search: self names only */
+ if (search == FIND_SELF && ret->source != SELF) continue;
+
+ if (zero_ip(ip) || ip_equal(ip, ret->ip))
+ {
+ return ret;
+ }
+ }
+ }
- return(NULL);
+ return NULL;
}
+
/****************************************************************************
dump a copy of the name table
**************************************************************************/
-static void dump_names(void)
+void dump_names(void)
{
- time_t t = time(NULL);
- struct name_record *n;
- struct domain_record *d;
+ struct name_record *n;
+ time_t t = time(NULL);
- DEBUG(3,("Dump of local name table:\n"));
+ 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)));
- }
+ for (n = namelist; n; n = n->next)
+ {
+ DEBUG(3,("%s %s TTL=%d NBFLAGS=%2x\n",
+ namestr(&n->name),
+ inet_ntoa(n->ip),
+ n->death_time?n->death_time-t:0,
+ n->nb_flags));
+ }
+}
- DEBUG(3,("\nDump of domain list:\n"));
- for (d = domainlist; d; d = d->next)
- DEBUG(3,("%s %s\n",d->name,inet_ntoa(d->bcast_ip)));
+
+/****************************************************************************
+ remove an entry from the name list
+ ****************************************************************************/
+void remove_netbios_name(char *name,int type, enum name_source source,
+ struct in_addr ip)
+{
+ struct nmb_name nn;
+ struct name_record *n;
+
+ make_nmb_name(&nn, name, type, scope);
+ n = find_name_search(&nn, FIND_GLOBAL, ip);
+
+ if (n && n->source == source) remove_name(n);
}
/****************************************************************************
- add a host entry to the name list
+ add an entry to the name list
****************************************************************************/
-static struct name_record *add_host_entry(char *name,int type,BOOL unique,int ttl,
- enum name_source source,
- struct in_addr ip)
+struct name_record *add_netbios_entry(char *name, int type, int nb_flags, int ttl,
+ enum name_source source, struct in_addr ip)
{
struct name_record *n;
struct name_record *n2=NULL;
@@ -357,1364 +180,431 @@ static struct name_record *add_host_entry(char *name,int type,BOOL unique,int tt
bzero((char *)n,sizeof(*n));
make_nmb_name(&n->name,name,type,scope);
- if ((n2=find_name(&n->name))) {
+
+ if ((n2 = find_name_search(&n->name, FIND_GLOBAL, ip)))
+ {
free(n);
n = n2;
}
if (ttl) n->death_time = time(NULL)+ttl*3;
n->ip = ip;
- n->unique = unique;
+ n->nb_flags = nb_flags;
n->source = source;
if (!n2) add_name(n);
- DEBUG(3,("Added host entry %s at %s ttl=%d unique=%s\n",
- namestr(&n->name),inet_ntoa(ip),ttl,BOOLSTR(unique)));
+ DEBUG(3,("Added netbios name %s at %s ttl=%d nb_flags=%2x\n",
+ namestr(&n->name),inet_ntoa(ip),ttl,nb_flags));
return(n);
}
/****************************************************************************
- add a domain entry
+ remove an entry from the name list
****************************************************************************/
-static struct domain_record *add_domain_entry(char *name,struct in_addr ip)
+void remove_name_entry(char *name,int type)
{
- struct domain_record *d;
-
- d = (struct domain_record *)malloc(sizeof(*d));
-
- if (!d) return(NULL);
-
- bzero((char *)d,sizeof(*d));
-
- if (zero_ip(ip)) ip = bcast_ip;
-
- StrnCpy(d->name,name,sizeof(d->name)-1);
- d->bcast_ip = ip;
-
- if (!PrimaryGroup[0] && ip_equal(bcast_ip,ip) && name[0] != '*') {
- strcpy(PrimaryGroup,name);
- strupper(PrimaryGroup);
- DEBUG(3,("Setting primary group to %s (%s)\n",PrimaryGroup,inet_ntoa(ip)));
- }
-
- add_domain(d);
-
- ip = *interpret_addr2("255.255.255.255");
- if (name[0] != '*') add_host_entry(name,0x1e,False,0,SELF,ip);
-
- DEBUG(3,("Added domain entry %s at %s\n",
- name,inet_ntoa(ip)));
-
- return(d);
+ if (lp_wins_support())
+ {
+ /* we are a WINS server. */
+ remove_netbios_name(name,type,SELF,myip);
+ }
+ else
+ {
+ struct in_addr ip;
+ ip = ipzero;
+
+ queue_netbios_pkt_wins(ClientNMB,NMB_REL,NAME_RELEASE,
+ name, type, 0,
+ False, True, ip);
+ }
}
+
/****************************************************************************
- add a server entry
+ add an entry to the name list
****************************************************************************/
-struct server_record *add_server_entry(char *name,int servertype,
- int ttl,char *comment,BOOL replace)
+void add_name_entry(char *name,int type,int nb_flags)
{
- BOOL newentry=False;
- struct server_record *s;
-
- for (s = serverlist; s; s = s->next)
- if (strequal(name,s->name)) break;
-
- if (s && !replace) {
- DEBUG(4,("Not replacing %s\n",name));
- return(s);
- }
-
- updatedlists=True;
-
- if (!s) {
- newentry = True;
- s = (struct server_record *)malloc(sizeof(*s));
-
- if (!s) return(NULL);
-
- bzero((char *)s,sizeof(*s));
- }
-
- /* update the entry */
- StrnCpy(s->name,name,sizeof(s->name)-1);
- StrnCpy(s->comment,comment,sizeof(s->comment)-1);
- s->servertype = servertype;
- s->death_time = ttl?time(NULL)+ttl*3:0;
- strupper(s->name);
- if (s->servertype & SV_TYPE_DOMAIN_ENUM) strupper(s->comment);
-
- if (!newentry) return(s);
-
- add_server(s);
-
- if (newentry) {
- DEBUG(3,("Added server entry %s of type %x (%s)\n",
- name,servertype,comment));
- } else {
- DEBUG(3,("Updated server entry %s of type %x (%s)\n",
- name,servertype,comment));
- }
+ /* always add our own entries */
+ add_netbios_entry(name,type,nb_flags,0,SELF,myip);
- return(s);
+ if (!lp_wins_support())
+ {
+ struct in_addr ip;
+ ip = ipzero;
+
+ queue_netbios_pkt_wins(ClientNMB,NMB_REG,NAME_REGISTER,
+ name, type, nb_flags,
+ False, True, ip);
+ }
}
/****************************************************************************
add the magic samba names, useful for finding samba servers
**************************************************************************/
-static void add_my_names(void)
+void add_my_names(void)
{
struct in_addr ip;
- ip = *interpret_addr2("0.0.0.0");
-
- add_host_entry(myname,0x20,True,0,SELF,ip);
- add_host_entry(myname,0x0,True,0,SELF,ip);
- add_host_entry(myname,0x1f,True,0,SELF,ip); /* used for chat?? */
- add_host_entry(myname,0x3,True,0,SELF,ip); /* used for winpopup */
-
- if (!domainlist)
- add_domain_entry(lp_workgroup(),bcast_ip);
- add_server_entry(myname,
- ServerType,
- 0,ServerComment,True);
-
- add_host_entry("__SAMBA__",0x20,True,0,SELF,ip);
- add_host_entry("__SAMBA__",0x0,True,0,SELF,ip);
-
- if (lp_preferred_master()) {
- DEBUG(3,("Preferred master startup\n"));
- needelection = True;
- ElectionCriterion |= (1<<3);
- }
-
- ElectionCriterion |= (lp_os_level() << 24);
-}
-
-
-/*******************************************************************
- write out browse.dat
- ******************************************************************/
-static void write_browse_list(void)
-{
- struct server_record *s;
- pstring fname,fnamenew;
- FILE *f;
+ ip = ipzero;
- updatecount++;
-
- strcpy(fname,lp_lockdir());
- trim_string(fname,NULL,"/");
- strcat(fname,"/");
- strcat(fname,SERVER_LIST);
- strcpy(fnamenew,fname);
- strcat(fnamenew,".");
+ add_name_entry(myname,0x20,NB_ACTIVE);
+ add_name_entry(myname,0x03,NB_ACTIVE);
+ add_name_entry(myname,0x00,NB_ACTIVE);
+ add_name_entry(myname,0x1f,NB_ACTIVE);
- f = fopen(fnamenew,"w");
+ add_netbios_entry("*",0x0,NB_ACTIVE,0,SELF,ip);
+ add_netbios_entry("__SAMBA__",0x20,NB_ACTIVE,0,SELF,ip);
+ add_netbios_entry("__SAMBA__",0x00,NB_ACTIVE,0,SELF,ip);
- if (!f) {
- DEBUG(4,("Can't open %s - %s\n",fnamenew,strerror(errno)));
- return;
+ if (lp_wins_support()) {
+ add_netbios_entry(inet_ntoa(myip),0x01,NB_ACTIVE,0,SELF,ip); /* nt as? */
}
-
- 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
+ refresh my own names
******************************************************************/
-static void expire_names(void)
+void refresh_my_names(time_t t)
{
- static time_t lastrun=0;
- time_t t = time(NULL);
- struct name_record *n;
- struct name_record *next;
- struct server_record *s;
- struct server_record *nexts;
-
- if (!lastrun) lastrun = t;
- if (t < lastrun + 5) return;
- lastrun = t;
+ static time_t lasttime = 0;
- /* 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;
- }
- }
+ if (t - lasttime < REFRESH_TIME)
+ return;
+ lasttime = t;
- /* 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;
- }
- }
+ add_my_names();
}
-
/*******************************************************************
- delete old names from the namelist
+ expires old names in the namelist
******************************************************************/
-static void housekeeping(void)
+void expire_names(time_t t)
{
- time_t t = time(NULL);
-
- expire_names();
-
- /* write out the browse.dat database for smbd to get */
- if (updatedlists) {
- write_browse_list();
- updatedlists = False;
- }
-
- {
- /* occasionally check to see if the master browser is around */
- static time_t lastrun=0;
- if (!lastrun) lastrun = t;
- if (t < lastrun + 5*60) return;
- lastrun = t;
-
- if (!AM_MASTER && PrimaryGroup[0] &&
- !name_query(ClientNMB,PrimaryGroup,0x1d,True,False,
- bcast_ip,NULL,queue_packet)) {
- DEBUG(2,("Forcing election on %s\n",PrimaryGroup));
- needelection = True;
- }
- }
-}
-
-
-/****************************************************************************
- reload the services file
- **************************************************************************/
-BOOL reload_services(BOOL test)
-{
- BOOL ret;
- extern fstring remote_machine;
-
- strcpy(remote_machine,"nmbd");
-
- if (lp_loaded())
+ struct name_record *n;
+ struct name_record *next;
+
+ /* expire old names */
+ for (n = namelist; n; n = next)
{
- pstring fname;
- strcpy(fname,lp_configfile());
- if (file_exist(fname,NULL) && !strcsequal(fname,servicesf))
+ if (n->death_time && n->death_time < t)
{
- strcpy(servicesf,fname);
- test = False;
+ 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;
}
}
-
- 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)
+response for a reg release received
+**************************************************************************/
+void response_name_release(struct packet_struct *p)
{
- FILE *f = fopen(fname,"r");
- pstring line;
- if (!f) {
- DEBUG(2,("Can't open lmhosts file %s\n",fname));
- return;
- }
-
- while (!feof(f))
+ 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)
{
- if (!fgets_slash(line,sizeof(pstring),f)) continue;
+ struct in_addr found_ip;
+ putip((char*)&found_ip,&nmb->answers->rdata[2]);
- 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;
-
- 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);
+ if (ip_equal(found_ip, myip))
+ {
+ remove_netbios_name(name,type,SELF,found_ip);
}
- }
}
-
- fclose(f);
-}
-
-/*******************************************************************
- check if 2 IPs are on the same net
- we will assume the local netmask, although this could be wrong XXXX
- ******************************************************************/
-static BOOL same_net(struct in_addr ip1,struct in_addr ip2)
-{
- unsigned long net1,net2,nmask;
-
- nmask = ntohl(Netmask.s_addr);
- net1 = ntohl(ip1.s_addr);
- net2 = ntohl(ip2.s_addr);
-
- return((net1 & nmask) == (net2 & nmask));
-}
-
-/****************************************************************************
- send an election packet
- **************************************************************************/
-static void send_election(char *group,uint32 criterion,int timeup,char *name)
-{
- pstring outbuf;
- char *p;
-
- DEBUG(2,("Sending election to %s for workgroup %s\n",
- inet_ntoa(bcast_ip),group));
-
- bzero(outbuf,sizeof(outbuf));
- p = outbuf;
- CVAL(p,0) = 8; /* election */
- p++;
-
- CVAL(p,0) = ELECTION_VERSION;
- SIVAL(p,1,criterion);
- SIVAL(p,5,timeup*1000); /* ms - despite the spec */
- p += 13;
- strcpy(p,name);
- strupper(p);
- p = skip_string(p,1);
-
- send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
- name,group,0,0x1e,bcast_ip,myip);
-}
-
-
-/****************************************************************************
- send a backup list response
- **************************************************************************/
-static void send_backup_list(char *name,int token,struct nmb_name *to,
- struct in_addr ip)
-{
- pstring outbuf;
- char *p;
-
- DEBUG(2,("Sending backup list to %s for workgroup %s\n",
- inet_ntoa(ip),PrimaryGroup));
-
- bzero(outbuf,sizeof(outbuf));
- p = outbuf;
- CVAL(p,0) = 10; /* backup list response */
- p++;
-
- CVAL(p,0) = 1; /* count */
- SIVAL(p,1,token);
- p += 5;
- strcpy(p,name);
- strupper(p);
- p = skip_string(p,1) + 1;
-
- send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
- myname,to->name,0,to->name_type,ip,myip);
-}
-
-
-/*******************************************************************
- become the master browser
- ******************************************************************/
-static void become_master(void)
-{
- uint32 domain_type = SV_TYPE_DOMAIN_ENUM | SV_TYPE_SERVER_UNIX;
- DEBUG(2,("Becoming master for %s\n",PrimaryGroup));
-
- ServerType |= SV_TYPE_MASTER_BROWSER;
- ServerType |= SV_TYPE_BACKUP_BROWSER;
- ElectionCriterion |= 0x5;
-
- add_host_entry(PrimaryGroup,0x1d,True,0,SELF,myip);
- add_host_entry(PrimaryGroup,0x0,False,0,SELF,myip);
- add_host_entry(MSBROWSE,1,False,0,SELF,myip);
-
- if (lp_domain_master()) {
- add_host_entry(myname,0x1b,True,0,SELF,myip);
- add_host_entry(PrimaryGroup,0x1b,True,0,SELF,myip);
- add_host_entry(PrimaryGroup,0x1c,False,0,SELF,myip);
- ServerType |= SV_TYPE_DOMAIN_MASTER;
- if (lp_domain_logons()) {
- ServerType |= SV_TYPE_DOMAIN_CTRL;
- ServerType |= SV_TYPE_DOMAIN_MEMBER;
- domain_type |= SV_TYPE_DOMAIN_CTRL;
+ else
+ {
+ DEBUG(1,("name registration for %s rejected!\n",
+ namestr(&nmb->question.question_name)));
}
- }
-
- 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);
- }
-
- 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);
- }
}
/****************************************************************************
- 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)
+reply to a name release
+****************************************************************************/
+void reply_name_release(struct packet_struct *p)
{
- 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;
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct in_addr ip;
+ int rcode=0;
+ int opcode = nmb->header.opcode;
+ int nb_flags = nmb->additional->rdata[0];
+ BOOL bcast = nmb->header.nm_flags.bcast;
+ struct name_record *n;
+ char rdata[6];
- 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;
+ putip((char *)&ip,&nmb->additional->rdata[2]);
- 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,("Name release on name %s rcode=%d\n",
+ namestr(&nmb->question.question_name),rcode));
- 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);
+ n = find_name_search(&nmb->question.question_name, FIND_GLOBAL, ip);
- mycriterion = ElectionCriterion;
-
- if (criterion > mycriterion) return(False);
- if (criterion < mycriterion) return(True);
-
- if (timeup > (t - StartupTime)) return(False);
- if (timeup < (t - StartupTime)) return(True);
-
- if (strcasecmp(myname,name) > 0) return(False);
+ /* XXXX under what conditions should we reject the removal?? */
+ if (n && n->nb_flags == nb_flags && ip_equal(n->ip,ip))
+ {
+ /* success = True;
+ rcode = 6; */
+
+ remove_name(n);
+ n = NULL;
+ }
- 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;
+ if (bcast) return;
- 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();
- }
+ /*if (success)*/
+ {
+ rdata[0] = nb_flags;
+ rdata[1] = 0;
+ putip(&rdata[2],(char *)&ip);
}
-}
-
-
-/*******************************************************************
- process a announcement request
-
- clients send these when they want everyone to send an announcement
- immediately. This can cause quite a storm of packets!
- ******************************************************************/
-static void process_announce_request(struct packet_struct *p,char *buf)
-{
- struct dgram_packet *dgram = &p->packet.dgram;
- int flags = CVAL(buf,0);
- char *name = buf+1;
-
- name[15] = 0;
-
- DEBUG(3,("Announce request from %s flags=0x%X\n",name,flags));
-
- if (strequal(dgram->source_name.name,myname)) return;
-
- needannounce = True;
-}
-
-
-/****************************************************************************
-process a browse frame
-****************************************************************************/
-static void process_browse_packet(struct packet_struct *p,char *buf,int len)
-{
- int command = CVAL(buf,0);
- switch (command)
- {
- case 1: /* host announce */
- case 12: /* domain announce */
- case 15: /* local master announce */
- process_announce(p,command,buf+1);
- break;
-
- case 2: /* announce request */
- process_announce_request(p,buf+1);
- break;
-
- case 8: /* election */
- process_election(p,buf+1);
- break;
-
- case 9: /* get backup list */
- process_backup_list(p,buf+1);
- break;
-
- case 13: /* master announcement */
- process_master_announce(p,buf+1);
- break;
- }
+
+ /* Send a NAME RELEASE RESPONSE */
+ reply_netbios_packet(p,nmb->header.name_trn_id,rcode,opcode,
+ &nmb->question.question_name,
+ nmb->question.question_type,
+ nmb->question.question_class,
+ 0,
+ rdata, 6 /*success ? 6 : 0*/);
+ /* XXXX reject packet never tested: cannot tell what to do */
}
/****************************************************************************
- process a domain logon packet
- **************************************************************************/
-static void process_logon_packet(struct packet_struct *p,char *buf,int len)
+response for a reg request received
+**************************************************************************/
+void response_name_reg(struct packet_struct *p)
{
- 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:
+ 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 registration received!\n"));
+
+ if (nmb->header.rcode == 0 && nmb->answers->rdata)
{
- 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));
+ int nb_flags = nmb->answers->rdata[0];
+ struct in_addr found_ip;
+ int ttl = nmb->answers->ttl;
+ enum name_source source = REGISTER;
+
+ putip((char*)&found_ip,&nmb->answers->rdata[2]);
+
+ if (ip_equal(found_ip, myip)) source = SELF;
+
+ add_netbios_entry(name,type,nb_flags,ttl,source,found_ip);
}
- break;
- case 7:
+ else
{
- 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);
- }
+ DEBUG(1,("name registration for %s rejected!\n",
+ namestr(&nmb->question.question_name)));
}
-
- 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]);
-
- {
- struct name_record *n = find_name(&nmb->question.question_name);
- if (n && n->unique && n->source == REGISTER &&
- ip_equal(ip,n->ip)) {
- remove_name(n); n = NULL;
- }
-
- /* XXXX under what conditions should we reject the removal?? */
- }
-
- DEBUG(3,("Name release on name %s rcode=%d\n",
- namestr(&nmb->question.question_name),rcode));
-
- if (bcast) return;
-
- /* Send a NAME RELEASE RESPONSE */
- p2 = *p;
- nmb2 = &p2.packet.nmb;
-
- nmb2->header.response = True;
- nmb2->header.nm_flags.bcast = False;
- nmb2->header.nm_flags.recursion_available = CanRecurse;
- nmb2->header.nm_flags.trunc = False;
- nmb2->header.nm_flags.authoritative = True;
- nmb2->header.qdcount = 0;
- nmb2->header.ancount = 1;
- nmb2->header.nscount = 0;
- nmb2->header.arcount = 0;
- nmb2->header.rcode = rcode;
-
- nmb2->answers = &answer_rec;
- bzero((char *)nmb2->answers,sizeof(*nmb2->answers));
-
- nmb2->answers->rr_name = nmb->question.question_name;
- nmb2->answers->rr_type = nmb->question.question_type;
- nmb2->answers->rr_class = nmb->question.question_class;
- nmb2->answers->ttl = 0;
- nmb2->answers->rdlength = 6;
- nmb2->answers->rdata[0] = nb_flags;
- putip(&nmb2->answers->rdata[2],(char *)&ip);
-
- send_packet(&p2);
-}
-
-/****************************************************************************
- reply to a reg request
- **************************************************************************/
-static void reply_name_reg(struct packet_struct *p)
+reply to a reg request
+**************************************************************************/
+void reply_name_reg(struct packet_struct *p)
{
struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
char *qname = nmb->question.question_name.name;
- BOOL wildcard = (qname[0] == '*');
+ int name_type = nmb->question.question_name.name_type;
+
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;
+ BOOL group = (nb_flags&0x80);
int rcode = 0;
-
- if (wildcard) return;
-
- putip((char *)&ip,&nmb->additional->rdata[2]);
-
- if (group) {
- /* apparently we should return 255.255.255.255 for group queries (email from MS) */
- ip = *interpret_addr2("255.255.255.255");
- }
-
- {
- struct name_record *n = find_name(&nmb->question.question_name);
-
- if (n) {
- if (!group && !ip_equal(ip,n->ip)) {
- /* check if the previous owner still wants it,
- if so reject the registration, otherwise change the owner
- and refresh */
- if (n->source != REGISTER || confirm_name(n)) {
- rcode = 6;
- } else {
- n->ip = ip;
- n->death_time = ttl?p->timestamp+ttl*3:0;
- DEBUG(3,("%s changed owner to %s\n",
- namestr(&n->name),inet_ntoa(n->ip)));
+ int opcode = nmb->header.opcode;
+ struct name_record *n = NULL;
+ int success = True;
+ char rdata[6];
+ struct in_addr ip, from_ip;
+
+ putip((char *)&from_ip,&nmb->additional->rdata[2]);
+ ip = from_ip;
+
+ DEBUG(3,("Name registration for name %s at %s rcode=%d\n",
+ namestr(question),inet_ntoa(ip),rcode));
+
+ if (group)
+ {
+ /* apparently we should return 255.255.255.255 for group queries
+ (email from MS) */
+ ip = *interpret_addr2("255.255.255.255");
+ }
+
+ /* see if the name already exists */
+ n = find_name_search(question, FIND_GLOBAL, from_ip);
+
+ if (n)
+ {
+ if (!group && !ip_equal(ip,n->ip) && question->name_type != 0x3)
+ {
+ if (n->source == SELF)
+ {
+ rcode = 6;
+ success = False;
+ }
+ else
+ {
+ n->ip = ip;
+ n->death_time = ttl?p->timestamp+ttl*3:0;
+ DEBUG(3,("%s changed owner to %s\n",
+ namestr(&n->name),inet_ntoa(n->ip)));
+ }
+ }
+ else
+ {
+ /* refresh the name */
+ if (n->source != SELF)
+ {
+ n->death_time = ttl?p->timestamp + ttl*3:0;
+ }
}
- } else {
- /* 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);
}
- }
-
+ else
+ {
+ /* add the name to our subnet/name database */
+ n = add_netbios_entry(qname,name_type,nb_flags,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);
+ update_from_reg(nmb->question.question_name.name,
+ nmb->question.question_name.name_type, from_ip);
+
+ /* XXXX don't know how to reject a name register: stick info in anyway
+ and guess that it doesn't matter if info is there! */
+ /*if (success)*/
+ {
+ rdata[0] = nb_flags;
+ rdata[1] = 0;
+ putip(&rdata[2],(char *)&ip);
+ }
+
+ /* Send a NAME REGISTRATION RESPONSE */
+ reply_netbios_packet(p,nmb->header.name_trn_id,rcode,opcode,
+ &nmb->question.question_name,
+ nmb->question.question_type,
+ nmb->question.question_class,
+ ttl,
+ rdata, 6 /*success ? 6 : 0*/);
}
/****************************************************************************
reply to a name status query
****************************************************************************/
-static void reply_name_status(struct packet_struct *p)
+void reply_name_status(struct packet_struct *p)
{
struct nmb_packet *nmb = &p->packet.nmb;
- char *qname = nmb->question.question_name.name;
+ char *qname = nmb->question.question_name.name;
+ int ques_type = nmb->question.question_name.name_type;
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));
+ char rdata[MAX_DGRAM_SIZE];
+ char *countptr, *buf;
+ int count, names_added;
+ struct name_record *n;
-
- 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 */
-
+ DEBUG(3,("Name status for name %s %s\n",
+ namestr(&nmb->question.question_name), inet_ntoa(p->ip)));
+
+ /* find a name: if it's a wildcard, search the entire database.
+ if not, search for source SELF names only */
+ n = find_name_search(&nmb->question.question_name,
+ wildcard ? FIND_GLOBAL : FIND_SELF, p->ip);
+
+ if (!wildcard && (!n || n->source != SELF)) return;
+
+ for (count=0, n = namelist ; n; n = n->next)
+ {
+ int name_type = n->name.name_type;
+
+ if (n->source != SELF) continue;
+
+ if (name_type >= 0x1b && name_type <= 0x20 &&
+ ques_type >= 0x1b && ques_type <= 0x20)
+ {
+ if (!strequal(qname, n->name.name)) continue;
+ }
+
+ count++;
+ }
- buf = &nmb2->answers->rdata[0];
- SCVAL(buf,0,count);
+ /* XXXX hack, we should calculate exactly how many will fit */
+ count = MIN(count,(sizeof(rdata) - 64) / 18);
+
+ countptr = buf = rdata;
buf += 1;
-
- for (n = namelist ; n; n = n->next)
+
+ names_added = 0;
+
+ for (n = namelist ; n && count >= 0; n = n->next)
{
+ int name_type = n->name.name_type;
+
if (n->source != SELF) continue;
-
+
+ /* start with first bit of putting info in buffer: the name */
+
bzero(buf,18);
- strcpy(buf,n->name.name);
+ StrnCpy(buf,n->name.name,15);
strupper(buf);
- buf[15] = n->name.name_type;
- buf += 16;
- buf[0] = 0x4; /* active */
- if (!n->unique) buf[0] |= 0x80; /* group */
- buf += 2;
+
+ /* now check if we want to exclude other workgroup names
+ from the response. if we don't exclude them, windows clients
+ get confused and will respond with an error for NET VIEW */
+
+ if (name_type >= 0x1b && name_type <= 0x20 &&
+ ques_type >= 0x1b && ques_type <= 0x20)
+ {
+ if (!strequal(qname, n->name.name)) continue;
+ }
+
+ /* carry on putting name info in buffer */
+
+ buf[15] = name_type;
+ buf[16] = n->nb_flags;
+
+ buf += 18;
+
count--;
+ names_added++;
}
-
+
+ if (count < 0)
+ {
+ DEBUG(3, (("too many names: missing a few!\n")));
+ }
+
+ SCVAL(countptr,0,names_added);
+
/* XXXXXXX we should fill in more fields of the statistics structure */
bzero(buf,64);
{
@@ -1722,597 +612,434 @@ static void reply_name_status(struct packet_struct *p)
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);
+
+ /* Send a POSITIVE NAME STATUS RESPONSE */
+ reply_netbios_packet(p,nmb->header.name_trn_id,0,0,
+ &nmb->question.question_name,
+ nmb->question.question_type,
+ nmb->question.question_class,
+ 0,
+ rdata,PTR_DIFF(buf,rdata));
}
-
-/****************************************************************************
+/***************************************************************************
reply to a name query
****************************************************************************/
-static void reply_name_query(struct packet_struct *p)
+struct name_record *search_for_name(struct nmb_name *question,
+ struct in_addr ip, int Time, int search)
{
- struct nmb_packet *nmb = &p->packet.nmb;
- 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;
+ 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(question,search,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 (name_type != 0x20 && name_type != 0) {
- DEBUG(3,("not found\n"));
- return;
- }
-
+ if (!dns_type)
+ {
+ DEBUG(3,("types 0x20 0x1b 0x0 only: name not found\n"));
+ return NULL;
+ }
+
/* look it up with DNS */
a = interpret_addr(qname);
-
- putip((char *)&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;
- }
-
+
+ putip((char *)&dns_ip,(char *)&a);
+
+ if (!a)
+ {
+ /* no luck with DNS. We could possibly recurse here XXXX */
+ /* if this isn't a bcast then we should send a negative reply XXXX */
+ DEBUG(3,("no recursion\n"));
+ add_netbios_entry(qname,name_type,NB_ACTIVE,60*60,DNSFAIL,dns_ip);
+ return NULL;
+ }
+
/* add it to our cache of names. give it 2 hours in the cache */
- n = add_host_entry(qname,name_type,True,2*60*60,DNS,ip);
-
+ n = add_netbios_entry(qname,name_type,NB_ACTIVE,2*60*60,DNS,dns_ip);
+
/* failed to add it? yikes! */
- if (!n) return;
- }
-
- /* don't respond to bcast queries for group names unless we own them */
- if (bcast && !n->unique && !n->source == SELF) {
- DEBUG(3,("no bcast replies\n"));
- return;
+ if (!n) return NULL;
}
-
- /* 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;
+
+ /* is our entry already dead? */
+ if (n->death_time)
+ {
+ if (n->death_time < Time) return False;
}
-
- retip = n->ip;
- unique = n->unique;
-
- /* it may have been an earlier failure */
- if (n->source == DNSFAIL) {
+
+ /* it may have been an earlier failure */
+ if (n->source == DNSFAIL)
+ {
DEBUG(3,("DNSFAIL\n"));
- return;
+ return NULL;
}
- }
-
- /* 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);
+ DEBUG(3,("OK %s\n",inet_ntoa(n->ip)));
+
+ return n;
}
+/***************************************************************************
+reply to a name query.
-/* 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;
+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.
-/*******************************************************************
- 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) ;
+ - NEVER send a negative response to a broadcast query. no-one else will!
- p->next = packet;
- packet->next = NULL;
- packet->prev = p;
-}
+with directed name queries:
-/****************************************************************************
- process a nmb packet
- ****************************************************************************/
-static void process_nmb(struct packet_struct *p)
+ - if you are the WINS server, you are expected to
+****************************************************************************/
+extern void reply_name_query(struct packet_struct *p)
{
struct nmb_packet *nmb = &p->packet.nmb;
-
- /* if this is a response then ignore it */
- if (nmb->header.response) return;
-
- switch (nmb->header.opcode)
+ struct nmb_name *question = &nmb->question.question_name;
+ int name_type = question->name_type;
+ BOOL dns_type = name_type == 0x20 || name_type == 0;
+ BOOL bcast = nmb->header.nm_flags.bcast;
+ int ttl=0;
+ int rcode = 0;
+ int nb_flags = 0;
+ struct in_addr retip;
+ char rdata[6];
+
+ struct in_addr gp_ip = *interpret_addr2("255.255.255.255");
+ BOOL success = True;
+
+ struct name_record *n;
+ enum name_search search = dns_type || name_type == 0x1b ?
+ FIND_GLOBAL : FIND_SELF;
+
+ DEBUG(3,("Name query "));
+
+ if ((n = search_for_name(question,p->ip,p->timestamp, search)))
{
- 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)
+ /* 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)
{
- switch (nmb->question.question_type)
- {
- case 0x20:
- reply_name_query(p);
- break;
-
- case 0x21:
- reply_name_status(p);
- break;
- }
- return;
+ if (!lp_wins_proxy() || same_net(p->ip,n->ip,Netmask)) {
+ /* never reply with a negative response to broadcast queries */
+ return;
+ }
}
- break;
-
- case 6:
- if (nmb->header.qdcount>0 &&
- nmb->header.arcount>0) {
- reply_name_release(p);
- return;
- }
- break;
+
+ /* we will reply */
+ ttl = n->death_time - p->timestamp;
+ retip = n->ip;
+ nb_flags = n->nb_flags;
}
-
-}
-
-
-
-/*******************************************************************
- run elements off the packet queue till its empty
- ******************************************************************/
-static void run_packet_queue(void)
-{
- struct packet_struct *p;
-
- while ((p=packet_queue)) {
- switch (p->packet_type)
- {
- case NMB_PACKET:
- process_nmb(p);
- break;
-
- case DGRAM_PACKET:
- process_dgram(p);
- break;
- }
-
- packet_queue = packet_queue->next;
- if (packet_queue) packet_queue->prev = NULL;
- free_packet(p);
- }
-}
-
-
-/****************************************************************************
- The main select loop, listen for packets and respond
- ***************************************************************************/
-void process(void)
-{
-
- while (True)
+ else
{
- fd_set fds;
- int selrtn;
- struct timeval timeout;
-
- if (needelection && PrimaryGroup[0] && !RunningElection) {
- DEBUG(3,(">>> Starting election on %s <<<\n",PrimaryGroup));
- ElectionCount = 0;
- RunningElection = True;
- needelection = False;
- }
-
- FD_ZERO(&fds);
- FD_SET(ClientNMB,&fds);
- FD_SET(ClientDGRAM,&fds);
- /* during elections we need to send election packets at one
- second intervals */
- timeout.tv_sec = RunningElection?1:NMBD_SELECT_LOOP;
- timeout.tv_usec = 0;
-
- selrtn = sys_select(&fds,&timeout);
-
- if (FD_ISSET(ClientNMB,&fds)) {
- struct packet_struct *packet = read_packet(ClientNMB,NMB_PACKET);
- if (packet) queue_packet(packet);
- }
-
- if (FD_ISSET(ClientDGRAM,&fds)) {
- struct packet_struct *packet = read_packet(ClientDGRAM,DGRAM_PACKET);
- if (packet) queue_packet(packet);
- }
-
- if (RunningElection)
- run_election();
-
- run_packet_queue();
-
- do_announcements();
-
- housekeeping();
+ if (bcast) return; /* never reply negative response to bcasts */
+ success = False;
}
-}
+
+ /* if asking for a group name (type 0x1e) return 255.255.255.255 */
+ if (ip_equal(retip, gp_ip) && name_type == 0x1e) retip = gp_ip;
+ /* if 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;
-/****************************************************************************
- open the socket communication
-****************************************************************************/
-static BOOL open_sockets(BOOL isdaemon,int port)
-{
- struct hostent *hp;
-
- /* get host info */
- if ((hp = Get_Hostbyname(myhostname)) == 0)
+ if (success)
{
- DEBUG(0,( "Get_Hostbyname: Unknown host. %s\n",myhostname));
- return False;
- }
-
- if (isdaemon)
- ClientNMB = open_socket_in(SOCK_DGRAM, port,0);
+ rcode = 0;
+ DEBUG(3,("OK %s\n",inet_ntoa(retip)));
+ }
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;
+ {
+ 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,0,
+ &nmb->question.question_name,
+ nmb->question.question_type,
+ nmb->question.question_class,
+ ttl,
+ rdata, success ? 6 : 0);
}
-/*******************************************************************
- check that a IP, bcast and netmask and consistent. Must be a 1s
- broadcast
- ******************************************************************/
-static BOOL ip_consistent(struct in_addr ip,struct in_addr bcast,
- struct in_addr nmask)
-{
- unsigned long a_ip,a_bcast,a_nmask;
-
- a_ip = ntohl(ip.s_addr);
- a_bcast = ntohl(bcast.s_addr);
- a_nmask = ntohl(nmask.s_addr);
-
- /* check the netmask is sane */
- if (((a_nmask>>24)&0xFF) != 0xFF) {
- DEBUG(0,("Insane netmask %s\n",inet_ntoa(nmask)));
- return(False);
- }
-
- /* check the IP and bcast are on the same net */
- if ((a_ip&a_nmask) != (a_bcast&a_nmask)) {
- DEBUG(0,("IP and broadcast are on different nets!\n"));
- return(False);
- }
-
- /* check the IP and bcast are on the same net */
- if ((a_bcast|a_nmask) != 0xFFFFFFFF) {
- DEBUG(0,("Not a ones based broadcast %s\n",inet_ntoa(bcast)));
- return(False);
- }
-
- return(True);
-}
-
/****************************************************************************
- initialise connect, service and file structs
+response from a name query
****************************************************************************/
-static BOOL init_structs(void )
+static void response_netbios_packet(struct packet_struct *p)
{
- if (!get_myname(myhostname,got_myip?NULL:&myip))
- return(False);
-
- /* Read the broadcast address from the interface */
- {
- struct in_addr ip0,ip1,ip2;
-
- ip0 = myip;
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
+ char *qname = question->name;
+ BOOL bcast = nmb->header.nm_flags.bcast;
+ struct name_response_record *n;
- if (!(got_bcast && got_nmask))
- {
- get_broadcast(&ip0,&ip1,&ip2);
-
- if (!got_myip)
- myip = ip0;
-
- if (!got_bcast)
- bcast_ip = ip1;
-
- if (!got_nmask)
- Netmask = ip2;
- }
-
- DEBUG(1,("Using IP %s ",inet_ntoa(myip)));
- DEBUG(1,("broadcast %s ",inet_ntoa(bcast_ip)));
- DEBUG(1,("netmask %s\n",inet_ntoa(Netmask)));
-
- if (!ip_consistent(myip,bcast_ip,Netmask)) {
- DEBUG(0,("WARNING: The IP address, broadcast and Netmask are not consistent\n"));
- DEBUG(0,("You are likely to experience problems with this setup!\n"));
+ if (nmb->answers == NULL)
+ {
+ DEBUG(3,("NMB packet response from %s (bcast=%s) - UNKNOWN\n",
+ inet_ntoa(p->ip),
+ BOOLSTR(bcast)));
+ return;
}
+
+ if (nmb->answers->rr_type == NMB_STATUS) {
+ DEBUG(3,("Name status "));
}
- if (! *myname) {
- char *p;
- strcpy(myname,myhostname);
- p = strchr(myname,'.');
- if (p) *p = 0;
+ if (nmb->answers->rr_type == NMB_QUERY) {
+ DEBUG(3,("Name query "));
}
- {
- extern fstring local_machine;
- strcpy(local_machine,myname);
- strupper(local_machine);
+ if (nmb->answers->rr_type == NMB_REG) {
+ DEBUG(3,("Name registration "));
}
- return True;
-}
-
-/****************************************************************************
-usage on the program
-****************************************************************************/
-static void usage(char *pname)
-{
- DEBUG(0,("Incorrect program usage - is the command line correct?\n"));
-
- printf("Usage: %s [-n name] [-B bcast address] [-D] [-p port] [-d debuglevel] [-l log basename]\n",pname);
- printf("Version %s\n",VERSION);
- printf("\t-D become a daemon\n");
- printf("\t-p port listen on the specified port\n");
- printf("\t-d debuglevel set the debuglevel\n");
- printf("\t-l log basename. Basename for log/debug files\n");
- printf("\t-n netbiosname. the netbios name to advertise for this host\n");
- printf("\t-B broadcast address the address to use for broadcasts\n");
- printf("\t-N netmask the netmask to use for subnet determination\n");
- printf("\t-H hosts file load a netbios hosts file\n");
- printf("\t-I ip-address override the IP address\n");
- printf("\t-G group name add a group name to be part of\n");
- printf("\t-C comment sets the machine comment that appears in browse lists\n");
- printf("\n");
-}
-
-
-/****************************************************************************
- 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);
+ if (nmb->answers->rr_type == NMB_REL) {
+ DEBUG(3,("Name release "));
+ }
- charset_initialise();
+ DEBUG(3,("response for %s from %s (bcast=%s)\n",
+ namestr(&nmb->answers->rr_name),
+ inet_ntoa(p->ip),
+ BOOLSTR(bcast)));
+
+ if (!(n = find_name_query(nmb->header.name_trn_id))) {
+ DEBUG(3,("unknown response (received too late or from nmblookup?)\n"));
+ return;
+ }
-#ifdef LMHOSTSFILE
- strcpy(host_file,LMHOSTSFILE);
-#endif
+ n->num_msgs++; /* count number of responses received */
- /* this is for people who can't start the program correctly */
- while (argc > 1 && (*argv[1] != '-'))
+ switch (n->cmd_type)
{
- argv++;
- argc--;
+ case MASTER_SERVER_CHECK : DEBUG(4,("MASTER_SVR_CHECK\n")); break;
+ case SERVER_CHECK : DEBUG(4,("SERVER_CHECK\n")); break;
+ case FIND_MASTER : DEBUG(4,("FIND_MASTER\n")); break;
+ case NAME_STATUS_MASTER_CHECK: DEBUG(4,("NAME_STAT_MST_CHK\n")); break;
+ case NAME_STATUS_CHECK : DEBUG(4,("NAME_STATUS_CHECK\n")); break;
+ case CHECK_MASTER : DEBUG(4,("CHECK_MASTER\n")); break;
+ case NAME_CONFIRM_QUERY : DEBUG(4,("NAME_CONFIRM_QUERY\n")); break;
+ default: break;
}
-
- 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)
+ switch (n->cmd_type)
+ {
+ case MASTER_SERVER_CHECK:
+ case SERVER_CHECK:
+ case FIND_MASTER:
{
- 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;
+ if (nmb->answers->rr_type == NMB_QUERY)
+ {
+ enum cmd_type cmd = (n->cmd_type == MASTER_SERVER_CHECK) ?
+ NAME_STATUS_MASTER_CHECK :
+ NAME_STATUS_CHECK;
+ if (n->num_msgs > 1 && !strequal(qname,n->name.name))
+ {
+ /* one subnet, one master browser per workgroup */
+ /* XXXX force an election? */
+ DEBUG(1,("more than one master browser replied!\n"));
+ }
+
+ /* initiate a name status check on the server that replied */
+ queue_netbios_packet(ClientNMB,NMB_STATUS, cmd,
+ nmb->answers->rr_name.name,
+ nmb->answers->rr_name.name_type,0,
+ False,False,n->to_ip);
+ }
+ else
+ {
+ DEBUG(1,("Name query reply has wrong answer rr_type\n"));
+ }
break;
- case 'd':
- DEBUGLEVEL = atoi(optarg);
+ }
+
+ case NAME_STATUS_MASTER_CHECK:
+ case NAME_STATUS_CHECK:
+ {
+ if (nmb->answers->rr_type == NMB_STATUS)
+ {
+ /* NMB_STATUS arrives: contains the workgroup name
+ and server name we require */
+ struct nmb_name name;
+ fstring serv_name;
+
+ if (interpret_node_status(nmb->answers->rdata,
+ &name,0x1d,serv_name,n->to_ip))
+ {
+ if (*serv_name)
+ {
+ sync_server(n->cmd_type,serv_name,
+ name.name,name.name_type,
+ n->to_ip);
+ }
+ }
+ else
+ {
+ DEBUG(1,("No 0x1d name type in interpret_node_status()\n"));
+ }
+ }
+ else
+ {
+ DEBUG(1,("Name status reply has wrong answer rr_type\n"));
+ }
break;
- case 'p':
- port = atoi(optarg);
+ }
+
+ case CHECK_MASTER:
+ {
+ /* no action required here. it's when NO responses are received
+ that we need to do something (see expire_name_query_entries) */
+
+ DEBUG(4, ("Master browser exists for %s at %s\n",
+ namestr(&n->name),
+ inet_ntoa(n->to_ip)));
+ if (n->num_msgs > 1)
+ {
+ DEBUG(1,("more than one master browser!\n"));
+ }
+ if (nmb->answers->rr_type != NMB_QUERY)
+ {
+ DEBUG(1,("Name query reply has wrong answer rr_type\n"));
+ }
break;
- case 'h':
- usage(argv[0]);
- exit(0);
+ }
+ case NAME_CONFIRM_QUERY:
+ {
+ DEBUG(4, ("Name query at WINS server: %s at %s - ",
+ namestr(&n->name),
+ inet_ntoa(n->to_ip)));
+ if (nmb->header.rcode == 0 && nmb->answers->rdata)
+ {
+ int nb_flags = nmb->answers->rdata[0];
+ struct in_addr found_ip;
+ putip((char*)&found_ip,&nmb->answers->rdata[2]);
+
+ DEBUG(4, (" OK: %s\n", inet_ntoa(found_ip)));
+ add_netbios_entry(nmb->answers->rr_name.name,
+ nmb->answers->rr_name.name_type,
+ nb_flags,GET_TTL(0),STATUS_QUERY,found_ip);
+ }
+ else
+ {
+ DEBUG(4, (" NEGATIVE RESPONSE\n"));
+ }
+
break;
- default:
- if (!is_a_socket(0))
- usage(argv[0]);
+ }
+ default:
+ {
+ DEBUG(0,("unknown command received in response_netbios_packet\n"));
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();
- }
+/****************************************************************************
+ process a nmb packet
+ ****************************************************************************/
+void process_nmb(struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
- DEBUG(3,("Opening sockets\n"));
+ debug_nmb_packet(p);
- if (open_sockets(is_daemon,port))
- {
- process();
- close_sockets();
- }
+ switch (nmb->header.opcode)
+ {
+ case 5:
+ case 8:
+ case 9:
+ {
+ if (nmb->header.qdcount==0 || nmb->header.arcount==0) break;
+ if (nmb->header.response)
+ response_name_reg(p);
+ else
+ reply_name_reg(p);
+ break;
+ }
+
+ case 0:
+ {
+ if (nmb->header.response)
+ {
+ switch (nmb->question.question_type)
+ {
+ case 0x0:
+ {
+ response_netbios_packet(p);
+ break;
+ }
+ }
+ return;
+ }
+ else if (nmb->header.qdcount>0)
+ {
+ switch (nmb->question.question_type)
+ {
+ case NMB_QUERY:
+ {
+ reply_name_query(p);
+ break;
+ }
+ case NMB_STATUS:
+ {
+ reply_name_status(p);
+ break;
+ }
+ }
+ return;
+ }
+ break;
+ }
+
+ case 6:
+ {
+ if (nmb->header.qdcount==0 || nmb->header.arcount==0)
+ {
+ DEBUG(2,("netbios release packet rejected\n"));
+ break;
+ }
+
+ if (nmb->header.response)
+ response_name_release(p);
+ else
+ reply_name_release(p);
+ break;
+ }
+ }
- if (dbf)
- fclose(dbf);
- return(0);
}
+
diff --git a/source/namework.c b/source/namework.c
new file mode 100644
index 00000000000..9697be23ef6
--- /dev/null
+++ b/source/namework.c
@@ -0,0 +1,1017 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1995
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+*/
+
+#include "includes.h"
+#include "loadparm.h"
+#include "localnet.h"
+
+#define TEST_CODE /* want to debug unknown browse packets */
+
+extern int DEBUGLEVEL;
+extern pstring scope;
+extern BOOL CanRecurse;
+
+extern struct in_addr myip;
+extern struct in_addr bcast_ip;
+extern struct in_addr Netmask;
+
+extern pstring myname;
+
+extern int ClientNMB;
+extern int ClientDGRAM;
+
+extern int workgroup_count; /* total number of workgroups we know about */
+
+/* this is our browse cache database */
+extern struct browse_cache_record *browserlist;
+
+/* this is our domain/workgroup/server database */
+extern struct domain_record *domainlist;
+
+/* machine comment for host announcements */
+extern pstring ServerComment;
+
+extern int updatecount;
+
+/* what server type are we currently */
+#define DFLT_SERVER_TYPE (SV_TYPE_WORKSTATION | SV_TYPE_SERVER | \
+ SV_TYPE_TIME_SOURCE | SV_TYPE_SERVER_UNIX |\
+ SV_TYPE_PRINTQ_SERVER | SV_TYPE_POTENTIAL_BROWSER)
+
+/* backup request types: which servers are to be included */
+#define MASTER_TYPE (SV_TYPE_MASTER_BROWSER)
+#define DOMCTL_TYPE (SV_TYPE_DOMAIN_CTRL )
+
+extern time_t StartupTime;
+
+#define AM_MASTER(work) (work->ServerType & SV_TYPE_MASTER_BROWSER)
+#define AM_BACKUP(work) (work->ServerType & SV_TYPE_BACKUP_BROWSER)
+
+#define MSBROWSE "\001\002__MSBROWSE__\002"
+#define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE"
+
+#define GET_TTL(ttl) ((ttl)?MIN(ttl,lp_max_ttl()):lp_max_ttl())
+
+
+/****************************************************************************
+tell a server to become a backup browser
+state - 0x01 become backup instead of master
+ - 0x02 remove all entries in browse list and become non-master
+ - 0x04 stop master browser service altogether. NT ignores this
+**************************************************************************/
+void reset_server(char *name, int state, struct in_addr ip)
+{
+ char outbuf[20];
+ char *p;
+
+ bzero(outbuf,sizeof(outbuf));
+ p = outbuf;
+
+ CVAL(p,0) = 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,myip);
+}
+
+
+/****************************************************************************
+tell a server to become a backup browser
+**************************************************************************/
+void tell_become_backup(void)
+{
+ struct domain_record *d;
+ for (d = domainlist; d; d = d->next)
+ {
+ struct work_record *work;
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ struct server_record *s;
+ int num_servers = 0;
+ int num_backups = 0;
+
+ for (s = work->serverlist; s; s = s->next)
+ {
+ if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue;
+
+ num_servers++;
+
+ if (strequal(myname, s->serv.name)) continue;
+
+ if (s->serv.type & SV_TYPE_BACKUP_BROWSER) {
+ num_backups++;
+ continue;
+ }
+
+ if (s->serv.type & SV_TYPE_MASTER_BROWSER) continue;
+
+ if (!(s->serv.type & SV_TYPE_POTENTIAL_BROWSER)) continue;
+
+ DEBUG(3,("num servers: %d num backups: %d\n",
+ num_servers, num_backups));
+
+ /* make first server a backup server. thereafter make every
+ tenth server a backup server */
+ if (num_backups != 0 && (num_servers+9) / num_backups > 10)
+ {
+ continue;
+ }
+
+ DEBUG(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);
+ }
+ }
+ }
+}
+
+/****************************************************************************
+find a server responsible for a workgroup, and sync browse lists
+**************************************************************************/
+static BOOL sync_browse_entry(struct browse_cache_record *b)
+{
+ struct domain_record *d;
+ struct work_record *work;
+ /*
+ if (!strequal(serv_name, b->name))
+ {
+ DEBUG(0, ("browser's netbios name (%s) does not match %s (%s)",
+ b->name, inet_ntoa(b->ip), serv_name));
+ }
+ */
+ if (!(d = find_domain(b->ip))) return False;
+ if (!(work = find_workgroupstruct(d, b->group, False))) return False;
+
+ if (AM_MASTER(work)) {
+ /* only try to sync browse lists if we are the master, otherwise
+ the net could get a little bit too busy */
+ sync_browse_lists(work,b->name,0x20,b->ip);
+ }
+ b->synced = True;
+
+ return True;
+}
+
+
+/****************************************************************************
+search through browser list for an entry to sync with
+**************************************************************************/
+void do_browser_lists(void)
+{
+ struct browse_cache_record *b;
+ static time_t last = 0;
+ time_t t = time(NULL);
+
+ if (t-last < 4) return; /* don't do too many of these at once! */
+
+ last = t;
+
+ /* pick any entry in the list, preferably one whose time is up */
+ for (b = browserlist; b && b->next; b = b->next)
+ {
+ if (b->sync_time < t && b->synced == False) break;
+ }
+
+ if (!b || b->synced || sync_browse_entry(b))
+ {
+ /* leave entries (even ones already sync'd) for up to a minute.
+ this stops them getting re-sync'd too often */
+ expire_browse_cache(t - 60);
+ }
+}
+
+
+/****************************************************************************
+find a server responsible for a workgroup, and sync browse lists
+control ends up back here via response_name_query.
+**************************************************************************/
+void sync_server(enum cmd_type cmd, char *serv_name, char *work_name,
+ int name_type,
+ struct in_addr ip)
+{
+ add_browser_entry(serv_name, name_type, work_name, 0, ip);
+
+ if (cmd == MASTER_SERVER_CHECK)
+ {
+ /* announce ourselves as a master browser to serv_name */
+ do_announce_request(myname, serv_name, ANN_MasterAnnouncement,
+ 0x20, 0, ip);
+ }
+}
+
+
+/****************************************************************************
+update workgroup database from a name registration
+**************************************************************************/
+void update_from_reg(char *name, int type, struct in_addr ip)
+{
+ /* default server type: minimum guess at requirement XXXX */
+
+ DEBUG(3,("update from registration: host %s ip %s type %0x\n",
+ name, inet_ntoa(ip), type));
+
+ /* workgroup types, but not a chat type */
+ if (type >= 0x1b && type <= 0x1e)
+ {
+ struct work_record *work;
+ struct domain_record *d;
+
+ if (!(d = find_domain(ip))) return;
+ if (!(work = find_workgroupstruct(d, name, False))) return;
+
+ /* request the server to announce if on our subnet */
+ if (ip_equal(bcast_ip, d->bcast_ip)) announce_request(work, ip);
+
+ /* domain master type or master browser type */
+ if (type == 0x1b || type == 0x1d)
+ {
+ struct hostent *hp = gethostbyaddr((char*)&ip, sizeof(ip), AF_INET);
+ if (hp) {
+ /* gethostbyaddr name may not match netbios name but who cares */
+ add_browser_entry(hp->h_name, type, work->work_group, 120, ip);
+ }
+ }
+ }
+}
+
+
+/****************************************************************************
+ add the default workgroup into my domain
+ **************************************************************************/
+void add_my_domains(void)
+{
+ /* add or find domain on our local subnet, in the default workgroup */
+
+ if (*lp_workgroup() != '*')
+ {
+ add_domain_entry(bcast_ip,Netmask,lp_workgroup(), True);
+ }
+}
+
+
+/****************************************************************************
+ send a backup list response.
+ **************************************************************************/
+static void send_backup_list(char *work_name, struct nmb_name *src_name,
+ int info_count, int token, int info,
+ int name_type, struct in_addr ip)
+{
+ struct domain_record *d;
+ char outbuf[1024];
+ char *p, *countptr, *nameptr;
+ int count = 0;
+ int i, j;
+ char *theirname = src_name->name;
+
+ DEBUG(3,("sending backup list of %s to %s: %s(%x) %s(%x)\n",
+ work_name, inet_ntoa(ip),
+ myname,0x20,theirname,0x0));
+
+ if (name_type == 0x1d)
+ {
+ DEBUG(4,("master browsers: "));
+ }
+ else if (name_type == 0x1b)
+ {
+ DEBUG(4,("domain controllers: "));
+ }
+ else
+ {
+ DEBUG(0,("backup request for unknown type %0x\n", name_type));
+ return;
+ }
+
+ bzero(outbuf,sizeof(outbuf));
+ p = outbuf;
+
+ CVAL(p,0) = 10; /* backup list response */
+ p++;
+
+ countptr = p; /* count pointer */
+
+ SSVAL(p,1,token); /* sender's workgroup index representation */
+ SSVAL(p,3,info); /* XXXX clueless: info, usually zero */
+ p += 5;
+
+ nameptr = p;
+
+ for (d = domainlist; d; d = d->next)
+ {
+ struct work_record *work;
+
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ struct server_record *s;
+
+ if (!strequal(work->work_group, work_name)) continue;
+
+ for (s = work->serverlist; s; s = s->next)
+ {
+ BOOL found = False;
+ char *n;
+
+ if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue;
+
+ for (n = nameptr; n < p; n = skip_string(n, 1))
+ {
+ if (strequal(n, s->serv.name)) found = True;
+ }
+
+ if (found) continue; /* exclude names already added */
+
+ /* workgroup request: include all backup browsers in the list */
+ /* domain request: include all domain members in the list */
+
+ if ((name_type == 0x1d && (s->serv.type & MASTER_TYPE)) ||
+ (name_type == 0x1b && (s->serv.type & DOMCTL_TYPE)))
+ {
+ DEBUG(4, ("%s ", s->serv.name));
+
+ count++;
+ strcpy(p,s->serv.name);
+ strupper(p);
+ p = skip_string(p,1);
+ }
+ }
+ }
+ }
+
+ if (count == 0)
+ {
+ DEBUG(4, ("none\n"));
+ return;
+ }
+ else
+ {
+ DEBUG(4, (" - count %d\n", count));
+ }
+
+ CVAL(countptr,0) = count; /* total number of backup browsers found */
+
+ {
+ int len = PTR_DIFF(p, outbuf);
+
+ for (i = 0; i < len; i+= 16)
+ {
+ DEBUG(4, ("%3x char ", i));
+
+ for (j = 0; j < 16; j++)
+ {
+ unsigned char x = outbuf[i+j];
+ if (x < 32 || x > 127) x = '.';
+
+ if (i+j >= len) break;
+ DEBUG(4, ("%c", x));
+ }
+
+ DEBUG(4, (" hex ", i));
+
+ for (j = 0; j < 16; j++)
+ {
+ if (i+j >= len) break;
+ DEBUG(4, (" %02x", outbuf[i+j]));
+ }
+
+ DEBUG(4, ("\n"));
+ }
+
+ }
+ send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
+ myname,theirname,0x20,0,ip,myip);
+}
+
+
+/*******************************************************************
+ same context: scope. should check name_type as well, and makes sure
+ we don't process messages from ourselves
+ ******************************************************************/
+BOOL same_context(struct dgram_packet *dgram)
+{
+ if (!strequal(dgram->dest_name .scope,scope )) return(True);
+ if ( strequal(dgram->source_name.name ,myname)) return(True);
+
+ return(False);
+}
+
+
+/*******************************************************************
+ am I listening on a name. XXXX check the type of name as well.
+ ******************************************************************/
+BOOL listening_name(struct work_record *work, struct nmb_name *n)
+{
+ if (strequal(n->name,myname) ||
+ strequal(n->name,work->work_group) ||
+ strequal(n->name,MSBROWSE))
+ {
+ return(True);
+ }
+
+ return(False);
+}
+
+
+/*******************************************************************
+ process a domain announcement frame
+
+ Announce frames come in 3 types. Servers send host announcements
+ (command=1) to let the master browswer know they are
+ available. Master browsers send local master announcements
+ (command=15) to let other masters and backups that they are the
+ master. They also send domain announcements (command=12) to register
+ the domain
+
+ The comment field of domain announcements contains the master
+ browser name. The servertype is used by NetServerEnum to select
+ resources. We just have to pass it to smbd (via browser.dat) and let
+ the client choose using bit masks.
+ ******************************************************************/
+static void process_announce(struct packet_struct *p,int command,char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ struct in_addr ip = dgram->header.source_ip;
+ struct domain_record *d = find_domain(ip);
+
+ int update_count = CVAL(buf,0);
+ int ttl = IVAL(buf,1)/1000;
+ char *name = buf+5;
+ int osmajor=CVAL(buf,21);
+ int osminor=CVAL(buf,22);
+ uint32 servertype = IVAL(buf,23);
+ char *comment = buf+31;
+ struct work_record *work;
+ char *work_name;
+ char *serv_name = dgram->source_name.name;
+
+ comment[43] = 0;
+
+ DEBUG(4,("Announce(%d) %s(%x)",command,name,name[15]));
+ DEBUG(4,("%s count=%d ttl=%d OS=(%d,%d) type=%08x comment=%s\n",
+ namestr(&dgram->dest_name),update_count,ttl,osmajor,osminor,
+ servertype,comment));
+
+ name[15] = 0;
+
+ if (dgram->dest_name.name_type == 0 && command == 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 (same_context(dgram)) return;
+
+ if (command == ANN_DomainAnnouncement) {
+ work_name = name;
+ } else {
+ work_name = dgram->dest_name.name;
+ }
+
+ if (!(work = find_workgroupstruct(d, work_name, False))) return;
+
+ DEBUG(4, ("workgroup %s on %s\n", work->work_group, serv_name));
+
+ ttl = GET_TTL(ttl);
+
+ /* add them to our browse list */
+ add_server_entry(d,work,name,servertype,ttl,comment,True);
+
+#if 0
+ /* the tell become backup code is broken, no great harm is done by
+ disabling it */
+ tell_become_backup();
+#endif
+
+ /* get their browse list from them and add it to ours. */
+ add_browser_entry(serv_name,dgram->dest_name.name_type,
+ work->work_group,30,ip);
+}
+
+/*******************************************************************
+ process a master announcement frame
+ ******************************************************************/
+static void process_master_announce(struct packet_struct *p,char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ struct in_addr ip = dgram->header.source_ip;
+ struct domain_record *d = find_domain(ip);
+ struct domain_record *mydomain = find_domain(bcast_ip);
+ char *name = buf;
+ struct work_record *work;
+ name[15] = 0;
+
+ DEBUG(3,("Master Announce from %s (%s)\n",name,inet_ntoa(ip)));
+
+ if (same_context(dgram)) return;
+
+ if (!d || !mydomain) return;
+
+ if (!lp_domain_master()) return;
+
+ for (work = mydomain->workgrouplist; work; work = work->next)
+ {
+ if (AM_MASTER(work))
+ {
+ /* merge browse lists with them */
+ add_browser_entry(name,0x1b, work->work_group,30,ip);
+ }
+ }
+}
+
+/*******************************************************************
+ process a receive backup list request
+
+ we receive a list of servers, and we attempt to locate them all on
+ our local subnet, and sync browse lists with them on the workgroup
+ they are said to be in.
+ ******************************************************************/
+static void process_rcv_backup_list(struct packet_struct *p,char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ struct in_addr ip = dgram->header.source_ip;
+ int count = CVAL(buf,0);
+ int Index = IVAL(buf,1); /* caller's index representing workgroup */
+ char *buf1;
+
+ DEBUG(3,("Receive Backup ack for %s from %s total=%d index=%d\n",
+ namestr(&dgram->dest_name), inet_ntoa(ip),
+ count, Index));
+
+ if (same_context(dgram)) return;
+
+ if (count <= 0) return;
+
+ /* go through the list of servers attempting to sync browse lists */
+ for (buf1 = buf+5; *buf1 && count; buf1 = skip_string(buf1, 1), --count)
+ {
+ struct in_addr back_ip;
+ struct domain_record *d;
+
+ DEBUG(4,("Searching for backup browser %s at %s...\n",
+ buf1, inet_ntoa(ip)));
+
+ /* XXXX assume name is a DNS name NOT a netbios name. a more complete
+ approach is to use reply_name_query functionality to find the name */
+ back_ip = *interpret_addr2(buf1);
+
+ if (zero_ip(back_ip))
+ {
+ DEBUG(4,("Failed to find backup browser server using DNS\n"));
+ continue;
+ }
+
+ DEBUG(4,("Found browser server at %s\n", inet_ntoa(back_ip)));
+
+ if ((d = find_domain(back_ip)))
+ {
+ struct domain_record *d1;
+ for (d1 = domainlist; d1; d1 = d1->next)
+ {
+ struct work_record *work;
+ for (work = d1->workgrouplist; work; work = work->next)
+ {
+ if (work->token == Index)
+ {
+ queue_netbios_packet(ClientNMB,NMB_QUERY,SERVER_CHECK,
+ work->work_group,0x1d,0,
+ False,False,back_ip);
+ return;
+ }
+ }
+ }
+ }
+ }
+}
+
+/*******************************************************************
+ process a send backup list request
+
+ A client send a backup list request to ask for a list of servers on
+ the net that maintain server lists for a domain. A server is then
+ chosen from this list to send NetServerEnum commands to to list
+ available servers.
+
+ Currently samba only sends back one name in the backup list, its
+ own. For larger nets we'll have to add backups and send "become
+ backup" requests occasionally.
+ ******************************************************************/
+static void process_send_backup_list(struct packet_struct *p,char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ struct in_addr ip = dgram->header.source_ip;
+ struct domain_record *d; /* = find_domain(ip); */
+ struct work_record *work;
+
+ int count = CVAL(buf,0);
+ int token = SVAL(buf,1); /* sender's key index for the workgroup? */
+ int info = SVAL(buf,3); /* XXXX don't know: some sort of info */
+ int name_type = dgram->dest_name.name_type;
+
+ if (same_context(dgram)) return;
+
+ if (count <= 0) 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 = domainlist; 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 count=%d\n",
+ namestr(&dgram->dest_name),inet_ntoa(ip),count));
+
+ send_backup_list(work->work_group,&dgram->source_name,
+ count,token,info,name_type,ip);
+ return;
+ }
+ }
+ }
+}
+
+
+/*******************************************************************
+ process a reset browser state
+
+ diagnostic packet:
+ 0x1 - stop being a master browser
+ 0x2 - discard browse lists, stop being a master browser, try again.
+ 0x4 - stop being a master browser forever. no way. ain't gonna.
+
+ ******************************************************************/
+static void process_reset_browser(struct packet_struct *p,char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ int state = CVAL(buf,0);
+
+ DEBUG(1,("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 domain_record *d;
+ for (d = domainlist; d; d = d->next)
+ {
+ struct work_record *work;
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ if (AM_MASTER(work))
+ {
+ become_nonmaster(d,work);
+ }
+ }
+ }
+ }
+
+ /* totally delete all servers and start afresh */
+ if (state & 0x2)
+ {
+ struct domain_record *d;
+ for (d = domainlist; d; d = d->next)
+ {
+ struct work_record *work;
+ for (work=d->workgrouplist;work;work=remove_workgroup(d,work));
+ }
+ add_my_domains();
+ }
+
+ /* stop browsing altogether. i don't think this is a good idea! */
+ if (state & 0x4)
+ {
+ DEBUG(1,("ignoring request to stop being a browser. sorry!\n"));
+ }
+}
+
+
+/*******************************************************************
+ process a announcement request
+
+ clients send these when they want everyone to send an announcement
+ immediately. This can cause quite a storm of packets!
+ ******************************************************************/
+static void process_announce_request(struct packet_struct *p,char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ struct work_record *work;
+ struct in_addr ip = dgram->header.source_ip;
+ struct domain_record *d = find_domain(ip);
+ int token = CVAL(buf,0);
+ char *name = buf+1;
+
+ name[15] = 0;
+
+ DEBUG(3,("Announce request from %s to %s token=0x%X\n",
+ name,namestr(&dgram->dest_name), token));
+
+ if (strequal(dgram->source_name.name,myname)) return;
+
+ if (!d) return;
+
+ if (!ip_equal(bcast_ip, d->bcast_ip)) return;
+
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ if (strequal(dgram->dest_name.name,work->work_group))
+ {
+ work->needannounce = True;
+ }
+ }
+}
+
+
+/****************************************************************************
+ process a domain logon packet
+ **************************************************************************/
+void process_logon_packet(struct packet_struct *p,char *buf,int len)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ struct in_addr ip = dgram->header.source_ip;
+ struct domain_record *d = find_domain(ip);
+ char *logname,*q;
+ char *reply_name;
+ BOOL add_slashes = False;
+ pstring outbuf;
+ int code,reply_code;
+ struct work_record *work;
+
+ if (!d) return;
+
+ if (!(work = find_workgroupstruct(d,dgram->dest_name.name, False)))
+ return;
+
+ if (!lp_domain_logons()) {
+ DEBUG(3,("No domain logons\n"));
+ return;
+ }
+ if (!listening_name(work, &dgram->dest_name))
+ {
+ DEBUG(4,("Not listening to that domain\n"));
+ return;
+ }
+
+ code = SVAL(buf,0);
+ switch (code) {
+ case 0:
+ {
+ char *machine = buf+2;
+ char *user = skip_string(machine,1);
+ logname = skip_string(user,1);
+ reply_code = 6;
+ reply_name = myname;
+ add_slashes = True;
+ DEBUG(3,("Domain login request from %s(%s) user=%s\n",
+ machine,inet_ntoa(p->ip),user));
+ }
+ break;
+ case 7:
+ {
+ char *machine = buf+2;
+ logname = skip_string(machine,1);
+ reply_code = 7;
+ reply_name = lp_domain_controller();
+ if (!*reply_name) {
+ DEBUG(3,("No domain controller configured\n"));
+ return;
+ }
+ DEBUG(3,("GETDC request from %s(%s)\n",
+ machine,inet_ntoa(p->ip)));
+ }
+ break;
+ default:
+ DEBUG(3,("Unknown domain request %d\n",code));
+ return;
+ }
+
+ bzero(outbuf,sizeof(outbuf));
+ q = outbuf;
+ SSVAL(q,0,reply_code);
+ q += 2;
+ if (add_slashes) {
+ strcpy(q,"\\\\");
+ q += 2;
+ }
+ StrnCpy(q,reply_name,16);
+ strupper(q);
+ q = skip_string(q,1);
+ SSVAL(q,0,0xFFFF);
+ q += 2;
+
+ send_mailslot_reply(logname,ClientDGRAM,outbuf,PTR_DIFF(q,outbuf),
+ myname,&dgram->source_name.name[0],0x20,0,p->ip,myip);
+ }
+
+
+/****************************************************************************
+depending on what announce has been made, we are only going to
+accept certain types of name announce. XXXX untested code
+
+check listening name type
+****************************************************************************/
+BOOL listening_type(struct packet_struct *p, int command)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ int type = dgram->dest_name.name_type;
+
+ switch (command)
+ {
+ case 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:
+ {
+ 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:
+ {
+ process_send_backup_list(p,buf+1);
+ break;
+ }
+
+ case ANN_GetBackupListResp:
+ {
+ 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)));
+ }
+ }
+}
+
+
+/****************************************************************************
+process udp 138 datagrams
+****************************************************************************/
+void process_dgram(struct packet_struct *p)
+{
+ char *buf;
+ char *buf2;
+ int len;
+ struct dgram_packet *dgram = &p->packet.dgram;
+
+ if (dgram->header.msg_type != 0x10 &&
+ dgram->header.msg_type != 0x11 &&
+ dgram->header.msg_type != 0x12) {
+ /* don't process error packets etc yet */
+ return;
+ }
+
+ buf = &dgram->data[0];
+ buf -= 4; /* XXXX for the pseudo tcp length -
+ someday I need to get rid of this */
+
+ if (CVAL(buf,smb_com) != SMBtrans) return;
+
+ len = SVAL(buf,smb_vwv11);
+ buf2 = smb_base(buf) + SVAL(buf,smb_vwv12);
+
+ DEBUG(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;
+
+ if (strequal(smb_buf(buf),"\\MAILSLOT\\BROWSE"))
+ {
+ process_browse_packet(p,buf2,len);
+ } else if (strequal(smb_buf(buf),"\\MAILSLOT\\NET\\NETLOGON")) {
+ process_logon_packet(p,buf2,len);
+ }
+}
+
diff --git a/source/nmbd/nmbd.c b/source/nmbd/nmbd.c
new file mode 100644
index 00000000000..a977667c2e2
--- /dev/null
+++ b/source/nmbd/nmbd.c
@@ -0,0 +1,610 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1995
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+*/
+
+#include "includes.h"
+#include "loadparm.h"
+#include "localnet.h"
+
+extern int DEBUGLEVEL;
+
+extern pstring debugf;
+pstring servicesf = CONFIGFILE;
+
+extern pstring scope;
+
+int ClientNMB = -1;
+int ClientDGRAM = -1;
+
+extern pstring myhostname;
+static pstring host_file;
+extern pstring myname;
+
+/* are we running as a daemon ? */
+static BOOL is_daemon = False;
+
+/* machine comment for host announcements */
+pstring ServerComment="";
+
+static BOOL got_bcast = False;
+static BOOL got_myip = False;
+static BOOL got_nmask = False;
+
+/* what server type are we currently */
+
+time_t StartupTime =0;
+
+struct in_addr ipzero;
+
+
+/****************************************************************************
+catch a sighup
+****************************************************************************/
+static int sig_hup(void)
+{
+ BlockSignals(True);
+
+ DEBUG(0,("Got SIGHUP (reload not implemented)\n"));
+ dump_names();
+ reload_services(True);
+
+ BlockSignals(False);
+#ifndef DONT_REINSTALL_SIG
+ signal(SIGHUP,SIGNAL_CAST sig_hup);
+#endif
+ return(0);
+}
+
+/****************************************************************************
+catch a sigpipe
+****************************************************************************/
+static int sig_pipe(void)
+{
+ BlockSignals(True);
+
+ DEBUG(0,("Got SIGPIPE\n"));
+ if (!is_daemon)
+ exit(1);
+ BlockSignals(False);
+ return(0);
+}
+
+#if DUMP_CORE
+/*******************************************************************
+prepare to dump a core file - carefully!
+********************************************************************/
+static BOOL dump_core(void)
+{
+ char *p;
+ pstring dname;
+ strcpy(dname,debugf);
+ if ((p=strrchr(dname,'/'))) *p=0;
+ strcat(dname,"/corefiles");
+ mkdir(dname,0700);
+ sys_chown(dname,getuid(),getgid());
+ chmod(dname,0700);
+ if (chdir(dname)) return(False);
+ umask(~(0700));
+
+#ifndef NO_GETRLIMIT
+#ifdef RLIMIT_CORE
+ {
+ struct rlimit rlp;
+ getrlimit(RLIMIT_CORE, &rlp);
+ rlp.rlim_cur = MAX(4*1024*1024,rlp.rlim_cur);
+ setrlimit(RLIMIT_CORE, &rlp);
+ getrlimit(RLIMIT_CORE, &rlp);
+ DEBUG(3,("Core limits now %d %d\n",rlp.rlim_cur,rlp.rlim_max));
+ }
+#endif
+#endif
+
+
+ DEBUG(0,("Dumping core in %s\n",dname));
+ return(True);
+}
+#endif
+
+
+/****************************************************************************
+possibly continue after a fault
+****************************************************************************/
+static void fault_continue(void)
+{
+#if DUMP_CORE
+ dump_core();
+#endif
+}
+
+/*******************************************************************
+ expire old names from the namelist and server list
+ ******************************************************************/
+static void expire_names_and_servers(void)
+{
+ static time_t lastrun = 0;
+ time_t t = time(NULL);
+
+ if (!lastrun) lastrun = t;
+ if (t < lastrun + 5) return;
+ lastrun = t;
+
+ expire_names(t);
+ expire_servers(t);
+}
+
+/*****************************************************************************
+ reload the services file
+ **************************************************************************/
+BOOL reload_services(BOOL test)
+{
+ BOOL ret;
+ extern fstring remote_machine;
+
+ strcpy(remote_machine,"nmbd");
+
+ if (lp_loaded())
+ {
+ pstring fname;
+ strcpy(fname,lp_configfile());
+ if (file_exist(fname,NULL) && !strcsequal(fname,servicesf))
+ {
+ strcpy(servicesf,fname);
+ test = False;
+ }
+ }
+
+ if (test && !lp_file_list_changed())
+ return(True);
+
+ ret = lp_load(servicesf,True);
+
+ /* perhaps the config filename is now set */
+ if (!test) {
+ DEBUG(3,("services not loaded\n"));
+ reload_services(True);
+ }
+
+ return(ret);
+}
+
+
+
+/****************************************************************************
+load a netbios hosts file
+****************************************************************************/
+static void load_hosts_file(char *fname)
+{
+ FILE *f = fopen(fname,"r");
+ pstring line;
+ if (!f) {
+ DEBUG(2,("Can't open lmhosts file %s\n",fname));
+ return;
+ }
+
+ while (!feof(f))
+ {
+ if (!fgets_slash(line,sizeof(pstring),f)) continue;
+
+ if (*line == '#') continue;
+
+ {
+ BOOL group=False;
+
+ pstring ip,name,mask,flags,extra;
+
+ char *ptr;
+ int count = 0;
+ struct in_addr ipaddr;
+ struct in_addr ipmask;
+ enum name_source source = LMHOSTS;
+
+ strcpy(ip,"");
+ strcpy(name,"");
+ strcpy(mask,"");
+ strcpy(flags,"");
+ strcpy(extra,"");
+
+ ptr = line;
+
+ if (next_token(&ptr,ip ,NULL)) ++count;
+ if (next_token(&ptr,name ,NULL)) ++count;
+ if (next_token(&ptr,mask ,NULL)) ++count;
+ if (next_token(&ptr,flags,NULL)) ++count;
+ if (next_token(&ptr,extra,NULL)) ++count;
+
+ if (count <= 0) continue;
+
+ if (count > 0 && count < 2) {
+ DEBUG(0,("Ill formed hosts line [%s]\n",line));
+ continue;
+ }
+
+ /* work out if we need to shuffle the tokens along due to the
+ optional subnet mask argument */
+
+ if (strchr(mask, 'G') || strchr(mask, 'S') || strchr(mask, 'M')) {
+ strcpy(flags, mask );
+ /* default action for no subnet mask */
+ strcpy(mask, inet_ntoa(Netmask));
+ }
+
+ DEBUG(4, ("lmhost entry: %s %s %s %s\n", ip, name, mask, flags));
+
+ if (strchr(flags,'G') || strchr(flags,'S'))
+ group = True;
+
+ if (strchr(flags,'M') && !group) {
+ source = SELF;
+ strcpy(myname,name);
+ }
+
+ ipaddr = *interpret_addr2(ip);
+ ipmask = *interpret_addr2(mask);
+
+ if (group) {
+ add_domain_entry(ipaddr, ipmask, name, True);
+ } else {
+ add_netbios_entry(name,0x20,NB_ACTIVE,0,source,ipaddr);
+ }
+ }
+ }
+
+ fclose(f);
+}
+
+
+/****************************************************************************
+ The main select loop.
+ ***************************************************************************/
+static void process(void)
+{
+ BOOL run_election;
+
+ while (True)
+ {
+ time_t t = time(NULL);
+ run_election = check_elections();
+ listen_for_packets(run_election);
+
+ run_packet_queue();
+ run_elections();
+
+ announce_host();
+
+#if 0
+ /* 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();
+
+ expire_names_and_servers();
+ expire_netbios_response_entries(t-10);
+ 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;
+}
+
+
+/*******************************************************************
+ check that a IP, bcast and netmask and consistent. Must be a 1s
+ broadcast
+ ******************************************************************/
+static BOOL ip_consistent(struct in_addr ip,struct in_addr bcast, struct in_addr nmask)
+{
+ unsigned long a_ip,a_bcast,a_nmask;
+
+ a_ip = ntohl(ip.s_addr);
+ a_bcast = ntohl(bcast.s_addr);
+ a_nmask = ntohl(nmask.s_addr);
+
+ /* check the netmask is sane */
+ if (((a_nmask>>24)&0xFF) != 0xFF) {
+ DEBUG(0,("Insane netmask %s\n",inet_ntoa(nmask)));
+ return(False);
+ }
+
+ /* check the IP and bcast are on the same net */
+ if ((a_ip&a_nmask) != (a_bcast&a_nmask)) {
+ DEBUG(0,("IP and broadcast are on different nets!\n"));
+ return(False);
+ }
+
+ /* check the IP and bcast are on the same net */
+ if ((a_bcast|a_nmask) != 0xFFFFFFFF) {
+ DEBUG(0,("Not a ones based broadcast %s\n",inet_ntoa(bcast)));
+ return(False);
+ }
+
+ return(True);
+}
+
+
+/****************************************************************************
+ initialise connect, service and file structs
+****************************************************************************/
+static BOOL init_structs()
+{
+ if (!get_myname(myhostname,got_myip?NULL:&myip))
+ return(False);
+
+ /* Read the broadcast address from the interface */
+ {
+ struct in_addr ip0,ip1,ip2;
+
+ ip0 = myip;
+
+ if (!(got_bcast && got_nmask))
+ {
+ get_broadcast(&ip0,&ip1,&ip2);
+
+ if (!got_myip)
+ myip = ip0;
+
+ if (!got_bcast)
+ bcast_ip = ip1;
+
+ if (!got_nmask)
+ Netmask = ip2;
+ }
+
+ DEBUG(1,("Using IP %s ",inet_ntoa(myip)));
+ DEBUG(1,("broadcast %s ",inet_ntoa(bcast_ip)));
+ DEBUG(1,("netmask %s\n",inet_ntoa(Netmask)));
+
+ if (!ip_consistent(myip,bcast_ip,Netmask)) {
+ DEBUG(0,("WARNING: The IP address, broadcast and Netmask are not consistent\n"));
+ DEBUG(0,("You are likely to experience problems with this setup!\n"));
+ }
+ }
+
+ if (! *myname) {
+ char *p;
+ strcpy(myname,myhostname);
+ p = strchr(myname,'.');
+ if (p) *p = 0;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+usage on the program
+****************************************************************************/
+static void usage(char *pname)
+{
+ DEBUG(0,("Incorrect program usage - is the command line correct?\n"));
+
+ printf("Usage: %s [-n name] [-B bcast address] [-D] [-p port] [-d debuglevel] [-l log basename]\n",pname);
+ printf("Version %s\n",VERSION);
+ printf("\t-D become a daemon\n");
+ printf("\t-p port listen on the specified port\n");
+ printf("\t-d debuglevel set the debuglevel\n");
+ printf("\t-l log basename. Basename for log/debug files\n");
+ printf("\t-n netbiosname. the netbios name to advertise for this host\n");
+ printf("\t-B broadcast address the address to use for broadcasts\n");
+ printf("\t-N netmask the netmask to use for subnet determination\n");
+ printf("\t-H hosts file load a netbios hosts file\n");
+ printf("\t-G group name add a group name to be part of\n");
+ printf("\t-I ip-address override the IP address\n");
+ printf("\t-C comment sets the machine comment that appears in browse lists\n");
+ printf("\n");
+}
+
+
+/****************************************************************************
+ main program
+ **************************************************************************/
+ int main(int argc,char *argv[])
+{
+ int port = NMB_PORT;
+ int opt;
+ extern FILE *dbf;
+ extern char *optarg;
+
+ *host_file = 0;
+
+ StartupTime = time(NULL);
+
+ TimeInit();
+
+ strcpy(debugf,NMBLOGFILE);
+
+ setup_logging(argv[0],False);
+
+ charset_initialise();
+
+ ipzero = *interpret_addr2("0.0.0.0");
+
+#ifdef LMHOSTSFILE
+ strcpy(host_file,LMHOSTSFILE);
+#endif
+
+ /* this is for people who can't start the program correctly */
+ while (argc > 1 && (*argv[1] != '-')) {
+ argv++;
+ argc--;
+ }
+
+ fault_setup(fault_continue);
+
+ signal(SIGHUP,SIGNAL_CAST sig_hup);
+
+ bcast_ip = ipzero;
+ myip = ipzero;
+
+ while ((opt = getopt (argc, argv, "s:T:I:C:bAi:B:N:Rn:l:d:Dp:hSH:G:")) != EOF)
+ {
+ switch (opt)
+ {
+ case 's':
+ strcpy(servicesf,optarg);
+ break;
+ case 'C':
+ strcpy(ServerComment,optarg);
+ break;
+ case 'G':
+ if (got_bcast && got_nmask) {
+ add_domain_entry(bcast_ip,Netmask,optarg, True);
+ } else {
+ DEBUG(0, ("Warning: option -G %s added before broadcast and netmask.\n",
+ optarg));
+ DEBUG(0, ("Assuming default values: bcast %s netmask %s\n",
+ inet_ntoa(bcast_ip), inet_ntoa(Netmask))); /* (i hope) */
+ }
+ break;
+ case 'H':
+ strcpy(host_file,optarg);
+ break;
+ case 'I':
+ myip = *interpret_addr2(optarg);
+ got_myip = True;
+ break;
+ case 'B':
+ bcast_ip = *interpret_addr2(optarg);
+ got_bcast = True;
+ break;
+ case 'N':
+ Netmask = *interpret_addr2(optarg);
+ got_nmask = True;
+ break;
+ case 'n':
+ strcpy(myname,optarg);
+ break;
+ case 'l':
+ sprintf(debugf,"%s.nmb",optarg);
+ break;
+ case 'i':
+ strcpy(scope,optarg);
+ strupper(scope);
+ break;
+ case 'D':
+ is_daemon = True;
+ break;
+ case 'd':
+ DEBUGLEVEL = atoi(optarg);
+ break;
+ case 'p':
+ port = atoi(optarg);
+ break;
+ case 'h':
+ usage(argv[0]);
+ exit(0);
+ break;
+ default:
+ if (!is_a_socket(0)) {
+ usage(argv[0]);
+ }
+ break;
+ }
+ }
+
+ DEBUG(1,("%s netbios nameserver version %s started\n",timestring(),VERSION));
+ DEBUG(1,("Copyright Andrew Tridgell 1994\n"));
+
+ init_structs();
+
+ if (!reload_services(False))
+ return(-1);
+
+ if (!is_daemon && !is_a_socket(0)) {
+ DEBUG(0,("standard input is not a socket, assuming -D option\n"));
+ is_daemon = True;
+ }
+
+ if (is_daemon) {
+ DEBUG(2,("%s becoming a daemon\n",timestring()));
+ become_daemon();
+ }
+
+ DEBUG(3,("Opening sockets %d\n", port));
+
+ if (!open_sockets(is_daemon,port)) return 1;
+
+ if (*host_file) {
+ load_hosts_file(host_file);
+ DEBUG(3,("Loaded hosts file\n"));
+ }
+
+ if (!*ServerComment)
+ strcpy(ServerComment,"Samba %v");
+ string_sub(ServerComment,"%v",VERSION);
+ string_sub(ServerComment,"%h",myhostname);
+
+ add_my_names();
+ add_my_domains();
+
+ DEBUG(3,("Checked names\n"));
+
+ write_browse_list();
+
+ DEBUG(3,("Dumped names\n"));
+
+ process();
+ close_sockets();
+
+ if (dbf)
+ fclose(dbf);
+ return(0);
+}
diff --git a/source/nmbsync.c b/source/nmbsync.c
index 5a77d6cc486..7e8cdd67e15 100644
--- a/source/nmbsync.c
+++ b/source/nmbsync.c
@@ -22,282 +22,162 @@
#include "includes.h"
#include "loadparm.h"
-#include "nameserv.h"
+#include "localnet.h"
-extern int DEBUGLEVEL;
-struct server_record *add_server_entry(char *name,int servertype,
- int ttl,char *comment,BOOL replace);
+extern int DEBUGLEVEL;
+extern pstring myname;
+extern struct in_addr bcast_ip;
+extern struct in_addr Netmask;
+
+extern int name_type;
+extern int max_protocol;
+extern struct in_addr dest_ip;
+extern int pid;
+extern int gid;
+extern int uid;
+extern int mid;
+extern BOOL got_pass;
+extern BOOL have_ip;
+extern pstring workgroup;
+extern pstring service;
+extern pstring desthost;
+extern BOOL connect_as_ipc;
/****************************************************************************
-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 domain_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, False)))
+ {
+ if (ip_equal(bcast_ip, d->bcast_ip))
+ {
+ announce_request(w, d->bcast_ip);
+ }
+ }
+ }
+
+ add_server_entry(d,w,sname,stype,lp_max_ttl(),cmnt,False);
+ }
+ }
}
+
+ if (rparam) free(rparam);
+ if (rdata) free(rdata);
+
+ return(True);
+}
- SIVAL(typep,0,0xFFFFFFFF); /* server list */
-
- if (call_remote_api(fd,cnum,uid,timeout,inbuf,outbuf,
- PTR_DIFF(p,param),0,
- 8,0xFFFF - 500,
- NULL,NULL,
- param,NULL,
- &rparam,&rdata) && SVAL(rparam,0)==0)
- {
- int converter=SVAL(rparam,2);
- int count=SVAL(rparam,4);
- int i;
-
- p = rdata;
- for (i=0;i<count;i++) {
- char *sname = p;
- uint32 type = IVAL(p,18);
- int comment_offset = IVAL(p,22) & 0xFFFF;
- char *comment = comment_offset?(rdata+comment_offset-converter):"";
- add_server_entry(sname,type,lp_max_ttl(),comment,False);
- p += 26;
- }
- }
- }
+/*******************************************************************
+ synchronise browse lists with another browse server.
- /* 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);
+ 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 work_record *work, char *name, int nm_type,
+ struct in_addr ip)
+{
+ struct domain_record *d;
+ pid = getpid();
+ uid = getuid();
+ gid = getgid();
+ mid = pid + 100;
+ name_type = nm_type;
+
+ got_pass = True;
+
+ DEBUG(4,("sync browse lists with %s for %s %s\n",
+ work->work_group, name, inet_ntoa(ip)));
- close(fd);
- if (inbuf) free(inbuf);
+ strcpy(workgroup,work->work_group);
+ strcpy(desthost,name);
+ dest_ip = ip;
+
+ if (zero_ip(dest_ip)) return;
+ have_ip = True;
+
+ if (!(d = find_domain(ip))) return;
+
+ connect_as_ipc = True;
+
+ /* connect as server and get domains, then servers */
+
+ sprintf(service,"\\\\%s\\IPC$", name);
+ strupper(service);
+
+ if (cli_open_sockets(SMB_PORT))
+ {
+ if (cli_send_login(NULL,NULL,True,True))
+ {
+ add_info(d, work, SV_TYPE_DOMAIN_ENUM);
+ add_info(d, work, SV_TYPE_ALL&~SV_TYPE_DOMAIN_ENUM);
+ }
+
+ close_sockets();
+ }
}
diff --git a/source/param/loadparm.c b/source/param/loadparm.c
index c61ab26781f..bbeb4801d52 100644
--- a/source/param/loadparm.c
+++ b/source/param/loadparm.c
@@ -58,7 +58,6 @@ 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"
@@ -132,6 +131,8 @@ typedef struct
char *szUsernameMap;
char *szCharacterSet;
char *szLogonScript;
+ char *szSmbrun;
+ char *szWINSserver;
int max_log_size;
int mangled_stack;
int max_xmit;
@@ -147,6 +148,8 @@ typedef struct
int syslog;
int os_level;
int max_ttl;
+ BOOL bWINSsupport;
+ BOOL bWINSproxy;
BOOL bPreferredMaster;
BOOL bDomainMaster;
BOOL bDomainLogons;
@@ -236,6 +239,7 @@ typedef struct
BOOL bSyncAlways;
char magic_char;
BOOL *copymap;
+ BOOL bDeleteReadonly;
char dummy[3]; /* for alignment */
} service;
@@ -307,6 +311,7 @@ static service sDefault =
False, /* bSyncAlways */
'~', /* magic char */
NULL, /* copymap */
+ False, /* bDeleteReadonly */
"" /* dummy */
};
@@ -365,7 +370,7 @@ struct parm_struct
{"strip dot", P_BOOL, P_GLOBAL, &Globals.bStripDot, 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},
@@ -408,6 +413,9 @@ struct parm_struct
#endif /* KANJI */
{"os level", P_INTEGER, P_GLOBAL, &Globals.os_level, NULL},
{"max ttl", P_INTEGER, P_GLOBAL, &Globals.max_ttl, NULL},
+ {"wins support", P_BOOL, P_GLOBAL, &Globals.bWINSsupport, NULL},
+ {"wins 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},
@@ -493,6 +501,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 +547,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 +578,8 @@ static void init_globals(void)
Globals.bDomainMaster = False;
Globals.bDomainLogons = False;
Globals.bBrowseList = True;
+ Globals.bWINSsupport = True;
+ Globals.bWINSproxy = False;
#ifdef KANJI
coding_system = interpret_coding_system (KANJI, SJIS_CODE);
@@ -595,6 +607,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 +683,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 +703,10 @@ 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_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)
@@ -778,6 +795,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 +1309,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..d5d841dceb8 100644
--- a/source/param/params.c
+++ b/source/param/params.c
@@ -63,23 +63,74 @@ the other = 3
static char *pszParmFile = NULL;
extern int DEBUGLEVEL;
-/* local prototypes */
-static BOOL enumerate_parameters(FILE *infile, PM_PARMFUNC pfunc);
-static BOOL enumerate_sections(FILE *infile,
- PM_SECFUNC sfunc, PM_PARMFUNC pfunc);
-/* prototypes for local toolbox functions */
-static void trimleft(char *psz);
-static void trimright(char *psz);
-static void collapse_spaces(char *psz);
-static int firstnonwhite(char *psz);
+/**************************************************************************
+Strip all leading whitespace from a string.
+**************************************************************************/
+static void trimleft(char *psz)
+{
+ char *pszDest;
+
+ pszDest = psz;
+ if (psz != NULL)
+ {
+ while (*psz != '\0' && isspace(*psz))
+ psz++;
+ while (*psz != '\0')
+ *pszDest++ = *psz++;
+ *pszDest = '\0';
+ }
+}
+
+/**************************************************************************
+Strip all trailing whitespace from a string.
+**************************************************************************/
+static void trimright(char *psz)
+{
+ char *pszTemp;
+
+ if (psz != NULL && psz[0] != '\0')
+ {
+ pszTemp = psz + strlen(psz) - 1;
+ while (isspace(*pszTemp))
+ *pszTemp-- = '\0';
+ }
+}
+
+/***********************************************************************
+Collapse each whitespace area in a string to a single space.
+***********************************************************************/
+static void collapse_spaces(char *psz)
+{
+ while (*psz)
+ if (isspace(*psz))
+ {
+ *psz++ = ' ';
+ trimleft(psz);
+ }
+ else
+ psz++;
+}
+
+/**************************************************************************
+Return the value of the first non-white character in the specified string.
+The terminating NUL counts as non-white for the purposes of this function.
+Note - no check for a NULL string! What would we return?
+**************************************************************************/
+static int firstnonwhite(char *psz)
+{
+ while (isspace(*psz) && (*psz != '\0'))
+ psz++;
+ return (*psz);
+}
+
/**************************************************************************
Identifies all parameters in the current section, calls the parameter
function for each. Ignores comment lines, stops and backs up in file when
a section is encountered. Returns True on success, False on error.
**************************************************************************/
-static BOOL enumerate_parameters(FILE *fileIn, PM_PARMFUNC pfunc)
+static BOOL enumerate_parameters(FILE *fileIn, BOOL (*pfunc)(char *,char *))
{
pstring szBuf;
char *pszTemp;
@@ -186,8 +237,8 @@ Returns True on success, False on failure. Note that the section and
parameter names will have all internal whitespace areas collapsed to a
single space for processing.
**************************************************************************/
-static BOOL enumerate_sections(FILE *fileIn,
- PM_SECFUNC sfunc, PM_PARMFUNC pfunc)
+static BOOL enumerate_sections(FILE *fileIn,
+ BOOL (*sfunc)(char *),BOOL (*pfunc)(char *,char *))
{
pstring szBuf;
BOOL bRetval;
@@ -246,7 +297,7 @@ Process the passed parameter file.
Returns True if successful, else False.
**************************************************************************/
-BOOL pm_process(char *pszFileName, PM_SECFUNC sfunc, PM_PARMFUNC pfunc)
+BOOL pm_process(char *pszFileName,BOOL (*sfunc)(char *),BOOL (*pfunc)(char *,char *))
{
FILE *fileIn;
BOOL bRetval;
@@ -274,62 +325,3 @@ BOOL pm_process(char *pszFileName, PM_SECFUNC sfunc, PM_PARMFUNC pfunc)
}
-/**************************************************************************
-Strip all leading whitespace from a string.
-**************************************************************************/
-static void trimleft(char *psz)
-{
- char *pszDest;
-
- pszDest = psz;
- if (psz != NULL)
- {
- while (*psz != '\0' && isspace(*psz))
- psz++;
- while (*psz != '\0')
- *pszDest++ = *psz++;
- *pszDest = '\0';
- }
-}
-
-/**************************************************************************
-Strip all trailing whitespace from a string.
-**************************************************************************/
-static void trimright(char *psz)
-{
- char *pszTemp;
-
- if (psz != NULL && psz[0] != '\0')
- {
- pszTemp = psz + strlen(psz) - 1;
- while (isspace(*pszTemp))
- *pszTemp-- = '\0';
- }
-}
-
-/***********************************************************************
-Collapse each whitespace area in a string to a single space.
-***********************************************************************/
-static void collapse_spaces(char *psz)
-{
- while (*psz)
- if (isspace(*psz))
- {
- *psz++ = ' ';
- trimleft(psz);
- }
- else
- psz++;
-}
-
-/**************************************************************************
-Return the value of the first non-white character in the specified string.
-The terminating NUL counts as non-white for the purposes of this function.
-Note - no check for a NULL string! What would we return?
-**************************************************************************/
-static int firstnonwhite(char *psz)
-{
- while (isspace(*psz) && (*psz != '\0'))
- psz++;
- return (*psz);
-}
diff --git a/source/params.h b/source/params.h
new file mode 100644
index 00000000000..b3ccdf74d97
--- /dev/null
+++ b/source/params.h
@@ -0,0 +1,40 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Parameter loading utilities
+ Copyright (C) Karl Auer 1993, 1994
+
+ 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.
+*/
+
+/**************************************************************************
+PARAMS.H
+
+Copyright (C) 1990, 1991, 1992 Karl Auer
+
+Prototypes and definitions for PARAMS.C.
+**************************************************************************/
+#ifndef _PARAMS_H
+#define _PARAMS_H
+
+#include <stdio.h>
+#include "smb.h"
+
+#define PM_NOFILE 1
+#define PM_NOFILENAME 2
+#define PM_FILEERROR 3
+
+#endif
+
diff --git a/source/passdb/smbpass.c b/source/passdb/smbpass.c
index 2dec15ffb43..35816c5c520 100644
--- a/source/passdb/smbpass.c
+++ b/source/passdb/smbpass.c
@@ -262,7 +262,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 +280,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 +297,7 @@ get_smbpwnam(char *name)
return NULL;
}
#else
-void
-smbpass_dummy(void)
+ void smbpass_dummy(void)
{
} /* To avoid compiler complaints */
#endif
diff --git a/source/pcap.h b/source/pcap.h
new file mode 100644
index 00000000000..89ab359af65
--- /dev/null
+++ b/source/pcap.h
@@ -0,0 +1,35 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ printcap parsing
+ Copyright (C) Karl Auer 1993, 1994
+
+ 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.
+*/
+
+/*
+ *
+ * Prototypes etc for pcap.c.
+ *
+ */
+#ifndef _PCAP_H
+#define _PCAP_H
+
+#include "smb.h"
+
+extern BOOL pcap_printername_ok(char *pszPrintername, char *pszPrintcapname);
+extern void pcap_printer_fn(void (*fn)());
+
+#endif
diff --git a/source/printing/printing.c b/source/printing/printing.c
index 1dd8921800a..2aa27926d9b 100644
--- a/source/printing/printing.c
+++ b/source/printing/printing.c
@@ -149,7 +149,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 +181,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 +598,78 @@ 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>
+****************************************************************************/
+static BOOL parse_lpq_plp(char *line,print_queue_struct *buf,BOOL first)
+{
+ string tok[5];
+ 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<8 && next_token(&line,tok[count],NULL); count++) ;
+
+ /* we must get 5 tokens */
+ if (count < 8)
+ return(False);
+
+ /* the 4rd must be integer */
+ if (!isdigit(*tok[3])) return(False);
+
+ /* if the fname contains a space then use STDIN */
+ if (strchr(tok[3],' '))
+ strcpy(tok[3],"STDIN");
+
+ /* only take the last part of the filename */
+ {
+ string tmp;
+ char *p = strrchr(tok[5],'/');
+ if (p)
+ {
+ strcpy(tmp,p+1);
+ strcpy(tok[5],tmp);
+ }
+ }
+
+
+ buf->job = atoi(tok[3]);
+
+ /* calcul de la taille du fichier */
+ if (!isdigit(*tok[7])) { buf->size = atoi(tok[7]) * 1.0 ; }
+ else {
+ string tmp;
+ strcpy(tmp,tok[7]);
+ if (strchr(tok[7],'K')) {
+ strncpy(tok[7],tmp,strlen(tmp)-1);
+ buf->size = atoi(tok[7]);
+ buf->size = buf->size * 1024;
+ }
+ if (strchr(tok[7],'M')) {
+ strncpy(tok[7],tmp,strlen(tmp)-1);
+ buf->size = atoi(tok[7]);
+ buf->size = buf->size * 1024.0 * 1000.0;
+ }
+ if (strchr(tok[7],'G')) {
+ strncpy(tok[7],tmp,strlen(tmp)-1);
+ buf->size = atoi(tok[7]);
+ buf->size = buf->size * 1024.0 * 1000000.0;
+ }
+
+ }
+ 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[5],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 +698,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;
diff --git a/source/reply.h b/source/reply.h
new file mode 100644
index 00000000000..f88229436f7
--- /dev/null
+++ b/source/reply.h
@@ -0,0 +1,60 @@
+int reply_special(char *inbuf,char *outbuf);
+int reply_corep(char *outbuf);
+int reply_coreplus(char *outbuf);
+int reply_nt1(char *outbuf);
+int reply_lanman1(char *outbuf);
+int reply_lanman2(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_setattrE(char *inbuf,char *outbuf);
+int reply_getattrE(char *inbuf,char *outbuf);
+int reply_writebs(char *inbuf,char *outbuf);
+int reply_sends(char *inbuf,char *outbuf);
+int reply_sendstrt(char *inbuf,char *outbuf);
+int reply_sendend(char *inbuf,char *outbuf);
+int reply_sendtxt(char *inbuf,char *outbuf);
+int reply_transs2(char *inbuf,char *outbuf,int length,int bufsize);
diff --git a/source/script/installscripts.sh b/source/script/installscripts.sh
new file mode 100755
index 00000000000..a3defa16e1a
--- /dev/null
+++ b/source/script/installscripts.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+# this script courtesy of James_K._Foote.PARC@xerox.com
+INSTALLPERMS=$1
+BINDIR=$2
+SRCDIR=$3
+
+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
+ exit 1
+ fi
+ fi
+done
+
+cp $SRCDIR/smbtar $BINDIR
+cp $SRCDIR/addtosmbpass $BINDIR
+echo Setting permissions on scripts
+chmod $INSTALLPERMS $BINDIR/smbtar
+chmod $INSTALLPERMS $BINDIR/addtosmbpass
+
+echo Scripts installed
+exit 0
diff --git a/source/script/mkproto.awk b/source/script/mkproto.awk
new file mode 100644
index 00000000000..d7b042652d1
--- /dev/null
+++ b/source/script/mkproto.awk
@@ -0,0 +1,39 @@
+# generate prototypes for Samba C code
+# tridge, June 1996
+
+BEGIN {
+ inheader=0;
+}
+
+{
+ if (inheader) {
+ if (match($0,"[)][ \t]*$")) {
+ inheader = 0;
+ printf "%s;\n",$0;
+ } else {
+ printf "%s\n",$0;
+ }
+ next;
+ }
+}
+
+/^static|^extern/ || !/^[a-zA-Z]/ || /[;]/ {
+ next;
+}
+
+!/^unsigned|^mode_t|^DIR|^user|^int|^char|^uint|^struct|^BOOL|^void|^time/ {
+ next;
+}
+
+
+/[(].*[)][ \t]*$/ {
+ printf "%s;\n",$0;
+ next;
+}
+
+/[(]/ {
+ inheader=1;
+ printf "%s\n",$0;
+ next;
+}
+
diff --git a/source/smbd/dir.c b/source/smbd/dir.c
index ac6f918b9da..32f2eb5e7de 100644
--- a/source/smbd/dir.c
+++ b/source/smbd/dir.c
@@ -186,6 +186,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 +412,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 +484,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..25979d72f5b 100644
--- a/source/smbd/ipc.c
+++ b/source/smbd/ipc.c
@@ -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 */
@@ -751,44 +751,64 @@ struct srv_info_struct
filter out unwanted server info
******************************************************************/
static BOOL filter_server_info(struct srv_info_struct *server,
- char *domain)
+ BOOL domains,
+ char *domain, uint32 request)
{
- 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)
-{
- 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 +827,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,32 +852,52 @@ 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);
}
@@ -957,8 +1002,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 +1017,46 @@ 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)
- {
- counted++;
- fixed_len += f_len;
- string_len += s_len;
- }
+ {
+ for (i=0;i<total;i++)
+ {
+ struct srv_info_struct *s = &servers[i];
+ if (filter_server_info(s,domains,domain,local_request|domain_request))
+ {
+ 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);
@@ -1021,10 +1069,15 @@ static BOOL api_RNetServerEnum(int cnum, int uid, char *param, char *data,
{
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))
+ {
+ 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--;
}
}
}
@@ -1289,7 +1342,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;
@@ -1551,8 +1604,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 +1710,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;
diff --git a/source/smbd/mangle.c b/source/smbd/mangle.c
index 8f1490c528d..a43e7f62451 100644
--- a/source/smbd/mangle.c
+++ b/source/smbd/mangle.c
@@ -90,8 +90,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 +120,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
diff --git a/source/smbd/password.c b/source/smbd/password.c
index 87c1fef94c5..31d91912714 100644
--- a/source/smbd/password.c
+++ b/source/smbd/password.c
@@ -52,7 +52,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 +287,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 +302,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 +682,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 +696,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 +1154,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 +1242,7 @@ BOOL check_hosts_equiv(char *user)
}
-static int password_client = -1;
+int password_client = -1;
static fstring pserver;
/****************************************************************************
@@ -1258,7 +1258,7 @@ BOOL server_cryptkey(char *buf)
fstring desthost;
struct in_addr dest_ip;
extern struct in_addr myip;
- int port = 139;
+ int port = SMB_PORT;
BOOL ret;
if (password_client >= 0)
@@ -1406,7 +1406,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/quotas.c b/source/smbd/quotas.c
new file mode 100644
index 00000000000..d5be15264e7
--- /dev/null
+++ b/source/smbd/quotas.c
@@ -0,0 +1,363 @@
+#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"
+
+
+#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"
+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);
+}
+
+#elif defined(CRAY)
+
+#include <sys/quota.h>
+#include <mntent.h>
+
+/****************************************************************************
+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) ;
+
+}
+
+
+#elif defined(SUNOS5)
+
+#include <devnm.h>
+#include <fcntl.h>
+#include <sys/fs/ufs_quota.h>
+
+/****************************************************************************
+try to get the disk space from disk quotas (solaris 2 version)
+****************************************************************************/
+/* Quota code by Peter Urbanec (amiga@cse.unsw.edu.au) */
+static BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
+{
+ uid_t user_id, euser_id;
+ int r;
+ struct dqblk D;
+ struct quotctl command;
+ int file;
+ int ret;
+
+ if((file=open(path, O_RDONLY))<0) return(False);
+
+ euser_id = geteuid();
+ user_id = getuid();
+
+ command.op = Q_GETQUOTA;
+ command.uid = euser_id;
+ command.addr = (caddr_t) &D;
+
+ setuid(0); /* Solaris seems to want to give info only to super-user */
+ seteuid(0);
+
+ ret = ioctl(file, Q_QUOTACTL, &command);
+
+ setuid(user_id); /* Restore the original UID status */
+ seteuid(euser_id);
+
+ if (ret < 0) {
+ close(file);
+ DEBUG(2,("disk_quotas ioctl (Solaris) failed\n"));
+ return(False);
+ }
+ close(file);
+
+
+ /* 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 :-)
+ */
+
+ *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
+****************************************************************************/
+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);
+}
+
+#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..4472e120aaa 100644
--- a/source/smbd/reply.c
+++ b/source/smbd/reply.c
@@ -334,11 +334,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 +1181,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);
@@ -1924,11 +1928,11 @@ int reply_close(char *inbuf,char *outbuf)
mtime = make_unix_date3(inbuf+smb_vwv1);
- close_file(fnum);
-
/* try and set the date */
set_filetime(Files[fnum].name,mtime);
+ close_file(fnum);
+
/* We have a cached error */
if(eclass || err)
return(ERROR(eclass,err));
@@ -1972,10 +1976,10 @@ int reply_writeclose(char *inbuf,char *outbuf)
nwritten = write_file(fnum,data,numtowrite);
- close_file(fnum);
-
set_filetime(Files[fnum].name,mtime);
+ close_file(fnum);
+
DEBUG(3,("%s writeclose fnum=%d cnum=%d num=%d wrote=%d (numopen=%d)\n",
timestring(),fnum,cnum,numtowrite,nwritten,
Connections[cnum].num_files_open));
diff --git a/source/smbd/server.c b/source/smbd/server.c
index 5d8facef33f..206d89423fb 100644
--- a/source/smbd/server.c
+++ b/source/smbd/server.c
@@ -26,7 +26,6 @@
#include "reply.h"
pstring servicesf = CONFIGFILE;
-pstring OriginalDir ="/";
extern pstring debugf;
extern pstring sesssetup_user;
@@ -34,16 +33,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;
@@ -93,11 +84,6 @@ 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 +134,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,7 +232,7 @@ 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));
}
@@ -326,7 +301,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 +385,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 +501,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 +961,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 */
@@ -1609,14 +1333,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 +1393,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 +1698,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();
@@ -2633,7 +2112,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 +2174,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 +2346,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 +2381,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 +3367,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 +3391,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;
@@ -3960,8 +3441,8 @@ void process(void )
extern int keepalive;
/* check for socket failure */
- if (errno == EBADF) {
- DEBUG(3,("%s Bad file descriptor - exiting\n",timestring()));
+ if (errno) {
+ DEBUG(3,("receive_smb error (%s) exiting\n",strerror(errno)));
return;
}
@@ -3989,10 +3470,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;
}
@@ -4090,7 +3576,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 +3596,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 +3638,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 +3700,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 +3746,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..dcd5379bc1d 100644
--- a/source/smbd/smbrun.c
+++ b/source/smbd/smbrun.c
@@ -44,53 +44,54 @@ static void close_fds(void)
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..60e9ae2b294 100644
--- a/source/smbd/trans2.c
+++ b/source/smbd/trans2.c
@@ -264,7 +264,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
int mode=0;
uint32 size=0,len;
uint32 mdate=0, adate=0, cdate=0;
- char *name_ptr;
+ char *nameptr;
BOOL isrootdir = (strequal(Connections[cnum].dirpath,"./") ||
strequal(Connections[cnum].dirpath,".") ||
strequal(Connections[cnum].dirpath,"/"));
@@ -325,11 +325,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 +349,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
#endif
p = pdata;
- name_ptr = p;
+ nameptr = p;
name_map_mangle(fname,False,SNUM(cnum));
@@ -368,7 +368,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
SSVAL(p,l1_attrFile,mode);
SCVAL(p,l1_cchName,strlen(fname));
strcpy(p + l1_achName, fname);
- name_ptr = p + l1_achName;
+ nameptr = p + l1_achName;
p += l1_achName + strlen(fname) + 1;
break;
@@ -387,7 +387,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
SIVAL(p,l2_cbList,0); /* No extended attributes */
SCVAL(p,l2_cchName,strlen(fname));
strcpy(p + l2_achName, fname);
- name_ptr = p + l2_achName;
+ nameptr = p + l2_achName;
p += l2_achName + strlen(fname) + 1;
break;
@@ -402,7 +402,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
SIVAL(p,26,4);
CVAL(p,30) = strlen(fname);
strcpy(p+31, fname);
- name_ptr = p+31;
+ nameptr = p+31;
p += 31 + strlen(fname) + 1;
break;
@@ -420,7 +420,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
SSVAL(p,24,mode);
CVAL(p,32) = strlen(fname);
strcpy(p + 33, fname);
- name_ptr = p+33;
+ nameptr = p+33;
p += 33 + strlen(fname) + 1;
break;
@@ -452,7 +452,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
strupper(p+2);
SSVAL(p,0,strlen(p+2));
p += 2 + 24;
- /* name_ptr = p; */
+ /* nameptr = p; */
strcpy(p,fname); p += strlen(p);
p = pdata + len;
break;
@@ -517,7 +517,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
}
/* Setup the last_filename pointer, as an offset from base_data */
- *last_name_off = PTR_DIFF(name_ptr,base_data);
+ *last_name_off = PTR_DIFF(nameptr,base_data);
/* Advance the data pointer to the next slot */
*ppdata = p;
return(found);
@@ -1004,7 +1004,7 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
if (tran_call == TRANSACT2_QFILEINFO) {
- int16 fnum = SVAL(params,0);
+ int16 fnum = SVALS(params,0);
info_level = SVAL(params,2);
CHECK_FNUM(fnum,cnum);
@@ -1198,7 +1198,7 @@ static int call_trans2setfilepathinfo(char *inbuf, char *outbuf, int length,
return(ERROR(ERRSRV,ERRaccess));
if (tran_call == TRANSACT2_SETFILEINFO) {
- int16 fnum = SVAL(params,0);
+ int16 fnum = SVALS(params,0);
info_level = SVAL(params,2);
CHECK_FNUM(fnum,cnum);
@@ -1444,7 +1444,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);
diff --git a/source/smbd/uid.c b/source/smbd/uid.c
new file mode 100644
index 00000000000..625303350a6
--- /dev/null
+++ b/source/smbd/uid.c
@@ -0,0 +1,360 @@
+/*
+ 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"
+#include "loadparm.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/smbpass.h b/source/smbpass.h
new file mode 100644
index 00000000000..6ddca0b92dd
--- /dev/null
+++ b/source/smbpass.h
@@ -0,0 +1,50 @@
+#ifndef _SMBPASS_H_
+#define _SMBPASS_H_
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB parameters and setup
+ Copyright (C) Jeremy Allison 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.
+*/
+
+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 */
+};
+
+/* Return a smb_passwd struct given a user name, 0 if fails. */
+struct smb_passwd *get_smbpwnam(char *user);
+
+#ifndef uchar
+#define uchar unsigned char
+#endif
+
+/* SMB Encryption functions. */
+void str_to_key(unsigned char *str,unsigned char *key);
+void E_P16(uchar *p14,uchar *p16);
+void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24);
+void E_md4hash(uchar *passwd,uchar *p16);
+void SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
+void SMB_nt_encrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
+
+/* Password file lock/unlock routines */
+int pw_file_lock(char *name, int type, int secs);
+int pw_file_unlock(int fd);
+#endif
diff --git a/source/utils/nmblookup.c b/source/utils/nmblookup.c
index aa431733322..6289ef74b1e 100644
--- a/source/utils/nmblookup.c
+++ b/source/utils/nmblookup.c
@@ -25,7 +25,6 @@
#endif
#include "includes.h"
-#include "nameserv.h"
extern int DEBUGLEVEL;
@@ -35,6 +34,7 @@ extern struct in_addr bcast_ip;
extern pstring myhostname;
static BOOL got_bcast = False;
+struct in_addr ipzero;
int ServerFD= -1;
@@ -124,6 +124,8 @@ int main(int argc,char *argv[])
TimeInit();
+ ipzero = *interpret_addr2("0.0.0.0");
+
setup_logging(argv[0],True);
charset_initialise();
diff --git a/source/utils/smbpasswd.c b/source/utils/smbpasswd.c
index 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..65e9d975f14 100644
--- a/source/utils/status.c
+++ b/source/utils/status.c
@@ -33,6 +33,7 @@
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 */
@@ -43,7 +44,7 @@ unsigned int Ucrit_checkUsername(pstring username); /* added by OH */
void Ucrit_addPid(int pid); /* added by OH */
unsigned int Ucrit_checkPid(int pid); /* added by OH */
-int main(int argc, char *argv[])
+ int main(int argc, char *argv[])
{
FILE *f;
pstring fname;
@@ -57,6 +58,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 +71,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 +91,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 +115,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 +147,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 +218,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..c6fa674b2d3 100644
--- a/source/utils/testparm.c
+++ b/source/utils/testparm.c
@@ -41,11 +41,13 @@
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..1474f0ecc60 100644
--- a/source/utils/testprns.c
+++ b/source/utils/testprns.c
@@ -43,6 +43,8 @@ int main(int argc, char *argv[])
{
char *pszTemp;
+ TimeInit();
+
setup_logging(argv[0],True);
charset_initialise();