summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--COPYING.LGPL481
-rw-r--r--Manifest66
-rw-r--r--README95
-rw-r--r--README.UBI15
-rw-r--r--Read-Manifest-Now0
-rw-r--r--Roadmap32
-rw-r--r--WHATSNEW.txt191
-rw-r--r--docs/NT4_PlainPassword.reg11
-rw-r--r--docs/THANKS22
-rw-r--r--docs/Win95_PlainPassword.reg4
-rw-r--r--docs/announce34
-rw-r--r--docs/faq/Samba-Server-FAQ-1.html77
-rw-r--r--docs/faq/Samba-Server-FAQ-2.html500
-rw-r--r--docs/faq/Samba-Server-FAQ.html88
-rw-r--r--docs/faq/Samba-Server-FAQ.sgml492
-rw-r--r--docs/faq/Samba-meta-FAQ-1.html160
-rw-r--r--docs/faq/Samba-meta-FAQ-2.html384
-rw-r--r--docs/faq/Samba-meta-FAQ-3.html101
-rw-r--r--docs/faq/Samba-meta-FAQ-4.html215
-rw-r--r--docs/faq/Samba-meta-FAQ-5.html30
-rw-r--r--docs/faq/Samba-meta-FAQ-6.html30
-rw-r--r--docs/faq/Samba-meta-FAQ.html102
-rw-r--r--docs/faq/Samba-meta-FAQ.sgml771
-rw-r--r--docs/faq/Samba-meta-FAQ.txt924
-rw-r--r--docs/faq/sambafaq-1.html392
-rw-r--r--docs/faq/sambafaq-2.html239
-rw-r--r--docs/faq/sambafaq-3.html322
-rw-r--r--docs/faq/sambafaq-4.html37
-rw-r--r--docs/faq/sambafaq-5.html30
-rw-r--r--docs/faq/sambafaq.html115
-rw-r--r--docs/faq/sambafaq.sgml792
-rw-r--r--docs/faq/sambafaq.txt1122
-rw-r--r--docs/history43
-rw-r--r--docs/manpages/make_smbcodepage.1131
-rw-r--r--docs/manpages/nmbd.8479
-rw-r--r--docs/manpages/samba.760
-rw-r--r--docs/manpages/smb.conf.51694
-rw-r--r--docs/manpages/smbclient.1294
-rw-r--r--docs/manpages/smbd.8149
-rw-r--r--docs/manpages/smbpasswd.8112
-rw-r--r--docs/manpages/smbrun.126
-rw-r--r--docs/manpages/smbstatus.152
-rw-r--r--docs/manpages/smbtar.1102
-rw-r--r--docs/manpages/testparm.127
-rw-r--r--docs/manpages/testprns.137
-rw-r--r--docs/samba.lsm8
-rw-r--r--docs/textdocs/Application_Serving.txt53
-rw-r--r--docs/textdocs/BROWSING.txt564
-rw-r--r--docs/textdocs/BUGS.txt49
-rw-r--r--docs/textdocs/DIAGNOSIS.txt116
-rw-r--r--docs/textdocs/DNIX.txt3
-rw-r--r--docs/textdocs/DOMAIN.txt368
-rw-r--r--docs/textdocs/DOMAIN_CONTROL.txt108
-rw-r--r--docs/textdocs/ENCRYPTION.txt110
-rw-r--r--docs/textdocs/Faxing.txt223
-rw-r--r--docs/textdocs/GOTCHAS.txt71
-rw-r--r--docs/textdocs/HINTS.txt12
-rw-r--r--docs/textdocs/INSTALL.sambatar6
-rwxr-xr-xdocs/textdocs/MIRRORS.txt84
-rw-r--r--docs/textdocs/NTDOMAIN.txt133
-rw-r--r--docs/textdocs/NetBIOS.txt155
-rw-r--r--docs/textdocs/OS2-Client-HOWTO.txt64
-rw-r--r--docs/textdocs/PRINTER_DRIVER.txt77
-rw-r--r--docs/textdocs/PROJECTS48
-rw-r--r--docs/textdocs/Passwords.txt13
-rw-r--r--docs/textdocs/Printing.txt96
-rw-r--r--docs/textdocs/README.DCEDFS9
-rw-r--r--docs/textdocs/README.jis31
-rw-r--r--docs/textdocs/README.sambatar8
-rw-r--r--docs/textdocs/SCO.txt12
-rw-r--r--docs/textdocs/SMBTAR.notes8
-rw-r--r--docs/textdocs/Speed.txt78
-rw-r--r--docs/textdocs/Support.txt1957
-rw-r--r--docs/textdocs/Tracing.txt96
-rw-r--r--docs/textdocs/UNIX-SMB.txt52
-rw-r--r--docs/textdocs/UNIX_INSTALL.txt346
-rw-r--r--docs/textdocs/Win95.txt77
-rw-r--r--docs/textdocs/WinNT.txt71
-rw-r--r--docs/textdocs/cifsntdomain.txt1416
-rw-r--r--docs/textdocs/security_level.txt99
-rw-r--r--examples/README13
-rw-r--r--examples/misc/extra_smbstatus35
-rw-r--r--examples/misc/wall.perl76
-rw-r--r--examples/printer-accounting/README63
-rw-r--r--examples/printer-accounting/acct-all9
-rw-r--r--examples/printer-accounting/acct-sum29
-rw-r--r--examples/printer-accounting/hp5-redir43
-rw-r--r--examples/printer-accounting/lp-acct38
-rw-r--r--examples/printer-accounting/printcap22
-rwxr-xr-xexamples/printing/smbprint2
-rw-r--r--examples/simple/smb.conf6
-rw-r--r--examples/smb.conf.default243
-rw-r--r--examples/svr4-startup/README24
-rwxr-xr-xexamples/svr4-startup/samba.server38
-rw-r--r--examples/thoralf/smb.conf152
-rw-r--r--examples/validchars/msdos70.out257
-rw-r--r--examples/validchars/nwdos70.out257
-rw-r--r--examples/validchars/readme101
-rw-r--r--examples/validchars/validchr.c123
-rw-r--r--examples/validchars/validchr.combin0 -> 9792 bytes
-rw-r--r--packaging/README34
-rw-r--r--packaging/SGI/README39
-rwxr-xr-xpackaging/SGI/inetd.sh29
-rw-r--r--packaging/SGI/legal_notice.html53
-rwxr-xr-xpackaging/SGI/makefile.pl24
-rwxr-xr-xpackaging/SGI/mkman22
-rwxr-xr-xpackaging/SGI/mkprintcap.sh15
-rwxr-xr-xpackaging/SGI/mkrelease.sh26
-rw-r--r--packaging/SGI/printcap5
-rwxr-xr-xpackaging/SGI/psfixes.pl28
-rw-r--r--packaging/SGI/relnotes.html233
-rw-r--r--packaging/SGI/samba.config1
-rw-r--r--packaging/SGI/samba.idb432
-rw-r--r--packaging/SGI/samba.rc42
-rw-r--r--packaging/SGI/samba.spec45
-rw-r--r--packaging/SGI/sambalp20
-rw-r--r--packaging/SGI/smb.conf86
-rw-r--r--packaging/SGI/smbpasswd1
-rw-r--r--packaging/SGI/smbprint52
-rw-r--r--packaging/Solaris/pkg-specs/Packaging.script5
-rw-r--r--packaging/Solaris/pkg-specs/mkprototype31
-rw-r--r--packaging/Solaris/pkg-specs/pkginfo12
-rw-r--r--packaging/Solaris/pkg-specs/postinstall37
-rw-r--r--packaging/Solaris/pkg-specs/postremove30
-rw-r--r--source/.cvsignore14
-rw-r--r--source/cgi.c163
-rw-r--r--source/change-log12
-rw-r--r--source/client/client.c2342
-rw-r--r--source/client/clientutil.c1099
-rw-r--r--source/client/clitar.c242
-rw-r--r--source/client/ntclient.c323
-rw-r--r--source/codepages/codepage_def.43770
-rw-r--r--source/codepages/codepage_def.85054
-rw-r--r--source/codepages/codepage_def.85263
-rw-r--r--source/codepages/codepage_def.93224
-rw-r--r--source/include/byteorder.h165
-rw-r--r--source/include/charset.h26
-rw-r--r--source/include/includes.h275
-rw-r--r--source/include/kanji.h41
-rw-r--r--source/include/local.h41
-rw-r--r--source/include/nameserv.h383
-rw-r--r--source/include/nterr.h505
-rw-r--r--source/include/proto.h1265
-rw-r--r--source/include/smb.h1611
-rw-r--r--source/include/trans2.h12
-rw-r--r--source/include/version.h2
-rw-r--r--source/internals.doc212
-rw-r--r--source/lib/access.c182
-rw-r--r--source/lib/charcnv.c114
-rw-r--r--source/lib/charset.c348
-rw-r--r--source/lib/fault.c6
-rw-r--r--source/lib/getsmbpass.c15
-rw-r--r--source/lib/interface.c477
-rw-r--r--source/lib/kanji.c109
-rw-r--r--source/lib/md4.c448
-rw-r--r--source/lib/replace.c325
-rw-r--r--source/lib/system.c222
-rw-r--r--source/lib/time.c476
-rw-r--r--source/lib/ufc.c12
-rw-r--r--source/lib/username.c94
-rw-r--r--source/lib/util.c3357
-rw-r--r--source/libsmb/clientgen.c746
-rw-r--r--source/libsmb/credentials.c224
-rw-r--r--source/libsmb/namequery.c295
-rw-r--r--source/libsmb/nmblib.c499
-rw-r--r--source/libsmb/nterr.c514
-rw-r--r--source/libsmb/smbdes.c337
-rw-r--r--source/libsmb/smbencrypt.c129
-rw-r--r--source/locking/locking.c283
-rw-r--r--source/locking/locking_shm.c714
-rw-r--r--source/locking/locking_slow.c1050
-rw-r--r--source/locking/shmem.c874
-rw-r--r--source/locking/shmem_sysv.c680
-rw-r--r--source/lsaparse.c675
-rw-r--r--source/md4.h58
-rw-r--r--source/nameannounce.c520
-rw-r--r--source/nameannounce.doc265
-rw-r--r--source/namebrowse.c246
-rw-r--r--source/namebrowse.doc149
-rw-r--r--source/nameconf.c350
-rw-r--r--source/namedbname.c518
-rw-r--r--source/namedbname.doc182
-rw-r--r--source/namedbresp.c167
-rw-r--r--source/namedbresp.doc100
-rw-r--r--source/namedbserver.c211
-rw-r--r--source/namedbsubnet.c402
-rw-r--r--source/namedbwork.c245
-rw-r--r--source/nameelect.c856
-rw-r--r--source/nameelect.doc256
-rw-r--r--source/namelogon.c233
-rw-r--r--source/namelogon.doc36
-rw-r--r--source/namepacket.c777
-rw-r--r--source/namepacket.doc133
-rw-r--r--source/namequery.doc83
-rw-r--r--source/nameresp.c318
-rw-r--r--source/nameresp.doc178
-rw-r--r--source/nameserv.c2488
-rw-r--r--source/nameserv.doc159
-rw-r--r--source/nameservreply.c685
-rw-r--r--source/nameservreply.doc213
-rw-r--r--source/nameservresp.c851
-rw-r--r--source/nameservresp.doc191
-rw-r--r--source/namework.c724
-rw-r--r--source/namework.doc363
-rw-r--r--source/nmbd/asyncdns.c257
-rw-r--r--source/nmbd/nmbd.c659
-rw-r--r--source/nmbsync.c355
-rw-r--r--source/ntclientlsa.c380
-rw-r--r--source/ntclientnet.c481
-rw-r--r--source/ntclientpipe.c257
-rw-r--r--source/param/loadparm.c876
-rw-r--r--source/param/params.c859
-rw-r--r--source/passdb/smbpass.c25
-rw-r--r--source/pipenetlog.c660
-rw-r--r--source/pipentlsa.c464
-rw-r--r--source/pipesrvsvc.c264
-rw-r--r--source/pipeutil.c235
-rw-r--r--source/printing/pcap.c8
-rw-r--r--source/printing/printing.c327
-rwxr-xr-xsource/script/installbin.sh4
-rwxr-xr-xsource/script/installcp.sh36
-rwxr-xr-xsource/script/installman.sh37
-rwxr-xr-xsource/script/installscripts.sh43
-rw-r--r--source/script/mkproto.awk82
-rw-r--r--source/script/smbtar7
-rwxr-xr-xsource/script/uninstallbin.sh43
-rwxr-xr-xsource/script/uninstallcp.sh33
-rwxr-xr-xsource/script/uninstallman.sh31
-rwxr-xr-xsource/script/uninstallscripts.sh37
-rwxr-xr-xsource/smbadduser73
-rw-r--r--source/smbd/chgpasswd.c68
-rw-r--r--source/smbd/dir.c273
-rw-r--r--source/smbd/ipc.c1292
-rw-r--r--source/smbd/mangle.c193
-rw-r--r--source/smbd/message.c51
-rw-r--r--source/smbd/password.c745
-rw-r--r--source/smbd/pipes.c366
-rw-r--r--source/smbd/predict.c162
-rw-r--r--source/smbd/quotas.c657
-rw-r--r--source/smbd/reply.c1441
-rw-r--r--source/smbd/server.c3517
-rw-r--r--source/smbd/smbrun.c77
-rw-r--r--source/smbd/trans2.c402
-rw-r--r--source/smbd/uid.c555
-rw-r--r--source/smbd/vt_mode.c38
-rw-r--r--source/smbparse.c1290
-rw-r--r--source/srvparse.c205
-rw-r--r--source/ubi_dLinkList.c147
-rw-r--r--source/ubi_dLinkList.h178
-rw-r--r--source/utils/make_printerdef.c301
-rw-r--r--source/utils/make_smbcodepage.c472
-rw-r--r--source/utils/nmblookup.c127
-rw-r--r--source/utils/smbpasswd.c271
-rw-r--r--source/utils/status.c238
-rw-r--r--source/utils/testparm.c21
-rw-r--r--source/utils/testprns.c10
-rw-r--r--source/web/cgi.c163
-rw-r--r--source/wsmbconf.c251
-rw-r--r--source/wsmbstatus.c87
259 files changed, 62174 insertions, 12597 deletions
diff --git a/COPYING.LGPL b/COPYING.LGPL
new file mode 100644
index 00000000000..8c8377da464
--- /dev/null
+++ b/COPYING.LGPL
@@ -0,0 +1,481 @@
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/Manifest b/Manifest
new file mode 100644
index 00000000000..7e8dc0106f6
--- /dev/null
+++ b/Manifest
@@ -0,0 +1,66 @@
+Copyright (C) 1997 - Samba-Team
+
+The Samba package you have just unpacked contains the following:
+
+Directory Notes:
+========= ======
+docs (Samba Documentation):
+--------------------------------------
+
+ The Samba documentation for 1.9.17 has had some of its content
+ updated and a new structure has been put in place. However, since
+ this is all rather new the documentation format of previous
+ versions will remain in place.
+
+ Note in particular two files - <your OS>_INSTALL.txt and DIAGNOSIS.txt
+ There is the potential for there to be many *INSTALL.txt files, one
+ for each OS that Samba supports. However we are moving all this into
+ the new structure. For now, most people will be using UNIX_INSTALL.txt.
+
+ You pay close attention to all the files with a
+ .txt extension. Most problems can be solved by reference to the
+ two files mentioned.
+
+ The new documentation can be accessed starting from Samba-meta-FAQ.html,
+ in the docs/faq directory. This is incomplete, but to quote from the
+ abstract, it:
+
+ "contains overview information for the Samba suite of programs,
+ a quick-start guide, and pointers to all other Samba documentation.
+ Other FAQs exist for specific client and server issues, and HOWTO
+ documents for more extended topics to do with Samba software."
+
+
+examples (Example configuration files):
+----------------------------------------------
+ Please pay close attention to the reference smb.conf file
+ smb.conf.default that has now been included as the master guide.
+
+ Do read the smb.conf manual page in considering what settings are
+ appropriate for your site.
+
+
+packaging (Only for those wishing to build binary distributions):
+-----------------------------------------------------------------------
+ Currently support is included only for RedHat Linux. We hope that
+ other Unix OS vendors will contribute their binary distribution
+ packaging control files - and we hope to make their binary packages
+ available on the master ftp site under:
+ samba.anu.edu.au/pub/samba/Binary_Packages/"OS_Vendor"
+
+
+source (The official Samba source files - expect more of these!):
+--------------------------------------------------------------------------
+ To build your own binary files you will need a suitable ansi C
+ compiler. Also, you must edit the enclosed "Makefile" as required
+ for your operating system platform. Then just run:
+ a) make
+ b) make install
+ then
+ c) set up your configuration files.
+
+ NOTE: OS Vendors who provide Samba binary packages will generally
+ integrate all Samba files into their preferred directory locations.
+ These may differ from the default location ALWAYS used by the Samba
+ sources. Please be careful when upgrading a vendor provided binary
+ distribution from files you have built yourself.
diff --git a/README b/README
index b7ef5d55957..30103241841 100644
--- a/README
+++ b/README
@@ -1,4 +1,6 @@
-This is version 1.9 of Samba, the free SMB client and server for unix.
+This is version 1.9.17 of Samba, the free SMB client and server for unix
+and other operating systems. Samba is maintained by the Samba Team,
+who support the original author, Andrew Tridgell.
>>>> Please read THE WHOLE of this file as it gives important information
>>>> about the configuration and use of Samba.
@@ -7,54 +9,88 @@ This software is freely distributable under the GNU public license, a
copy of which you should have received with this software (in a file
called COPYING).
+WHAT IS SMB?
+============
+
+This is a big question.
+
+The very short answer is that it is the protocol by which a lot of
+PC-related machines share files and printers and other informatiuon
+such as lists of available files and printers. Operating systems that
+support this natively include Windows NT, OS/2, and Linux and add on
+packages that achieve the same thing are available for DOS, Windows,
+VMS, Unix of all kinds, MVS, and more. Apple Macs and some Web Browsers
+can speak this protocol as well. Alternatives to SMB include
+Netware, NFS, Appletalk, Banyan Vines, Decnet etc; many of these have
+advantages but none are both public specifications and widely
+implemented in desktop machines by default.
+
+The Common Internet Filesystem is what the new SMB initiative is
+called. For details watch http://samba.anu.edu.au/cifs.
+
WHAT CAN SAMBA DO?
==================
-Here is a very short list of what samba includes, and what it does
+Here is a very short list of what samba includes, and what it does.
-- a SMB server, to provide LanManager style file and print services to PCs
+- a SMB server, to provide Windows NT and LAN Manager-style file and print
+ services to SMB clients such as Windows 95, Warp Server, smbfs and others.
-- a Netbios (rfc1001/1002) nameserver
+- a Netbios (rfc1001/1002) nameserver, which among other things gives
+ browsing support. Samba can be the master browser on your LAN if you wish.
- a ftp-like SMB client so you can access PC resources (disks and
-printers) from unix
+printers) from unix, Netware and other operating systems
- a tar extension to the client for backing up PCs
+For a much better overview have a look at the web site at
+http://samba.anu.edu.au/samba, and browse the user survey.
+
Related packages include:
-- ksmbfs, a linux-only filesystem allowing you to mount remote SMB
-filesystems from PCs on your linux box
+- smbfs, a linux-only filesystem allowing you to mount remote SMB
+filesystems from PCs on your linux box. This is included as standard with
+Linux 2.0 and later.
- tcpdump-smb, a extension to tcpdump to allow you to investigate SMB
-networking problems over netbeui and tcp/ip
+networking problems over netbeui and tcp/ip.
+- smblib, a library of smb functions which are designed to make it
+easy to smb-ise any particular application. See
+ftp://samba.anu.edu.au/pub/samba/smblib.
CONTRIBUTIONS
=============
If you want to contribute to the development of the software then
-please join the mailing list. I accept patches (preferably in
-"diff -u" format) and am always glad to receive feedback or suggestions.
+please join the mailing list. The Samba team accepts patches
+(preferably in "diff -u" format, see docs/BUGS.txt for more details)
+and are always glad to receive feedback or suggestions to the address
+samba-bugs@samba.anu.edu.au.
You could also send hardware/software/money/jewelry or pizza
-vouchers directly to me. The pizza vouchers would be especially
-welcome :-)
+vouchers directly to Andrew. The pizza vouchers would be especially
+welcome, in fact there is a special field in the survey for people who
+have paid up their pizza :-)
If you like a particular feature then look through the change-log and
see who added it, then send them an email.
Remember that free software of this kind lives or dies by the response
we get. If noone tells us they like it then we'll probably move onto
-something else.
+something else. However, as you can see from the user survey quite a lot of
+people do seem to like it at the moment :-)
Andrew Tridgell
-Email: samba-bugs@anu.edu.au
+Email: samba-bugs@samba.anu.edu.au
3 Ballow Crescent
Macgregor, A.C.T.
2615 Australia
+Samba Team
+Email: samba-bugs@samba.anu.edu.au
MORE INFO
=========
@@ -64,26 +100,29 @@ DOCUMENTATION
There is quite a bit of documentation included with the package,
including man pages, and lots of .txt files with hints and useful
-info.
+info. This is also available from the web page. There is a growing
+collection of information under docs/faq; by the next release expect
+this to be the default starting point.
FTP SITE
--------
-The main anonymous ftp distribution site for this software is
-nimbus.anu.edu.au in the directory pub/tridge/samba/.
+Please use a mirror site! The list of mirrors is in docs/MIRRORS.txt.
+The master ftp site is 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"
+Please do NOT send this request to the list alias instead.
To send mail to everyone on the list mail to samba@listproc.anu.edu.au
-There is also an announcement mailing list where I announce new
-versions. To subscribe send mail to listproc@anu.edu.au with a body
-of "subscribe samba-announce Your Name". All announcements also go to
-the samba list.
+There is also an announcement mailing list where new versions are
+announced. To subscribe send mail to listproc@samba.anu.edu.au with a
+body of "subscribe samba-announce Your Name". All announcements also
+go to the samba list.
NEWS GROUP
@@ -94,7 +133,7 @@ comp.protocols.smb as it often contains lots of useful info and is
frequented by lots of Samba users. The newsgroup was initially setup
by people on the Samba mailing list. It is not, however, exclusive to
Samba, it is a forum for discussing the SMB protocol (which Samba
-implements).
+implements). The samba list is gatewayed to this newsgroup.
WEB SITE
@@ -102,10 +141,12 @@ WEB SITE
A Samba WWW site has been setup with lots of useful info. Connect to:
-http://lake.canberra.edu.au/pub/samba/
-
-It is maintained by Paul Blackman (thanks Paul!). You can contact him
-at ictinus@lake.canberra.edu.au.
+http://samba.anu.edu.au/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@samba.anu.edu.au.
diff --git a/README.UBI b/README.UBI
new file mode 100644
index 00000000000..c4a69e40d3f
--- /dev/null
+++ b/README.UBI
@@ -0,0 +1,15 @@
+Thu Oct 16 11:07:18 CDT 1997
+
+Files in the source directory which begin with the prefix "ubi_" are
+licensed under the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE
+(LGPL). A copy of the LGPL should also be included in this directory
+under the name COPYING.LGPL. If this file is not present, you can
+obtain a copy of the LGPL by writing to the Free Software Foundation,
+Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+See http://www.interads.co.uk/~crh/ubiqx/ for additional available
+modules.
+
+Chris Hertel
+Samba Team
+samba-bugs@samba.anu.edu.au
diff --git a/Read-Manifest-Now b/Read-Manifest-Now
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Read-Manifest-Now
diff --git a/Roadmap b/Roadmap
new file mode 100644
index 00000000000..556e49d342f
--- /dev/null
+++ b/Roadmap
@@ -0,0 +1,32 @@
+Copyright (C) 1997 - Samba-Team
+
+The Samba-Team are committed to an agressive program to deliver quality
+controlled software to a well defined roadmap.
+
+The current Samba release 1.9.17 is called the "Browse Fix Release"
+The following development objectives are in place:
+
+Version / Codename Notes
+------------------ ----------------------------------------------------
+1.9.18 This version will feature two main areas of improvement
+"Perf-Lock Release" - introduction of OpLock support
+ - introduction of new browse list and WINS methods
+ - introduction of experimental NT Domain Authentication
+ as a compile-time option only.
+
+1.9.19 An authentication update release to offer improved
+"Auth Code Release" security and password synchronisation capabilities
+
+1.9.20 Introduction of new managment tools
+"GUI Config Release" Improved multi-language support.
+
+2.0 The next generation Directory Services update
+"DSA Release"
+
+While no release date or content promises are made we are hoping to release
+the remainder of the 1.9 series relases within short time frame.
+
+Should a budding contributor spring into gear and deliver any of the above
+ahead of the above release sequence then we reserve the option to make an
+out of sequence release (but always keeping to a logical sequence code number).
+
diff --git a/WHATSNEW.txt b/WHATSNEW.txt
new file mode 100644
index 00000000000..97aa845f913
--- /dev/null
+++ b/WHATSNEW.txt
@@ -0,0 +1,191 @@
+ WHATS NEW IN 1.9.18alpha8 Oct 29th 1997
+ =======================================
+
+This is NOT a production release of Samba code.
+For production servers please run Samba 1.9.17p4
+or later releases in the 1.9.17 series.
+
+This release contains some experimental features and
+changes and is being made available so people can
+test and provide feedback and patches for ongoing
+Samba development.
+
+Please note that only the Domain controller code
+is truly experimental. The other changes have
+been extensively tested and are of the same
+quality as normal Samba alpha releases. The
+Domain controller code is disabled in the Makefile
+by default and is being made available to Samba
+programmers in the interests of advancing a
+public implementation of this important protocol.
+
+This release contains three major changes to the
+1.9.17 series and much re-written code.
+
+
+The main changes are :
+
+1). Oplock support now operational.
+-----------------------------------
+
+Samba now supports 'exclusive' and 'batch' oplocks.
+These are an advanced networked file system feature
+that allows clients to obtain a exclusive use of a
+file. This allows a client to cache any changes it
+makes locally, and greatly improves performance.
+
+Windows NT has this feature and prior to this
+release this was one of the reasons Windows NT
+could be faster in some situations.
+
+The oplock code in Samba has been extensively
+tested and is believed to be completely stable.
+
+Please report any problems to the samba-bugs alias.
+
+
+2). Experimental Primary Domain controller code.
+------------------------------------------------
+
+Samba now contains a *VERY* experimental client and
+server implementation of part of the Windows NT
+4.x Domain Controller specification, as
+published by Paul Ashton (now a Samba Team
+member).
+
+This code is not enabled in the Makefile by default,
+and to work on this code you must read the file :
+
+ docs/NTDOMAIN.txt
+
+Please note that as this code is not complete,
+it is being made available as part of this release
+to allow interested parties to contribute and help
+the Samba Team in documenting and implementing
+this important feature.
+
+Please do not expect to be able to replace your
+NT Domain Controllers with Samba until this code
+is finished, tested and an announcement is made.
+
+At present the Domain Controller code is for
+programmers and people interested in Microsoft
+protocols only.
+
+
+3). New Internationalization support.
+-------------------------------------
+
+With this release Samba no longer needs to be
+separately compiled for Japanese (Kanji) support,
+the same binary will serve both Kanji and non-Kanji
+clients.
+
+A new method of dynamically loading client code pages
+has been added to allow the case insensitivity to
+be done dependent on the code page of the client.
+
+Note that Samba still will only handle one client
+code page at a time. This will be fixed when
+Samba is fully UNICODE enabled.
+
+Please see the new man page for make_smbcodepage
+for details on adding additional client code page
+support.
+
+
+Changed code.
+-------------
+
+Samba no longer needs the libdes library to support
+encrypted passwords. Samba now contains a restricted
+version of DES that can only be used for authentication
+purposes (to comply with the USA export encryption
+regulations and to allow USA Mirror sites to carry
+Samba source code). The 'encrypt passwords' parameter
+may now be used without recompiling.
+
+Much of the internals of Samba has been re-structured
+to support the oplock and Domain controller changes.
+
+The WINS client and WINS server capabilities in nmbd
+are also being restructured, to make it easier to
+understand and maintain.
+
+Samba supports the NT 3.51 and 4.0 Domain Authentication
+Protocol to a degree sufficient to download Profiles to an
+NT 3.51 or 4.0 Workstation ("Welcome to the SAMBA Domain").
+
+There is also code in smbclient to generate the same
+requests as an NT Workstation would when doing an NT
+Domain Logon. This has only been tested against a Samba
+"Experimental" PDC so far.
+
+Some of the new parameters for NT Domain Logons and
+Profile support are now also used by the Win95 Domain
+Logons and Profile support.
+
+The Automount code has been slightly reshuffled, such
+that the home directory (and profile location) can be
+specified by \\%N\homes and \\%N\homes\profiles
+respectively, which are the defaults for these values.
+If -DAUTOMOUNT is enabled, then %N is the server
+component of the user's NIS auto.home entry. Obviously,
+you will need to be running Samba on the user's home
+server as well as the one they just logged in on.
+
+
+New parameters in smb.conf.
+---------------------------
+
+New Global parameters.
+----------------------
+
+Documented in the smb.con man pages :
+
+"bind interfaces only"
+"username level"
+
+"domain sid"
+"domain groups"
+
+"logon drive"
+"logon home"
+
+
+Not yet documented in the smb.conf man page, please
+read docs/NTDOMAIN.txt or examine the source code for
+information on the next parameters :
+
+"domain other sids"
+"domain admin users"
+"domain guest users"
+
+
+New Share level parameters.
+---------------------------
+
+Documented in the smb.con man pages :
+
+"delete veto files"
+"oplocks"
+
+
+Reporting bugs.
+---------------
+
+If you have problems, or think you have found a
+bug please email a report to :
+
+samba-bugs@samba.anu.edu.au
+
+Please state the version number of Samba that
+you are running, and *full details* of the steps
+we need to reproduce the problem.
+
+As always, all bugs are our responsibility.
+
+Regards,
+
+ The Samba Team.
+
diff --git a/docs/NT4_PlainPassword.reg b/docs/NT4_PlainPassword.reg
new file mode 100644
index 00000000000..b30db150c24
--- /dev/null
+++ b/docs/NT4_PlainPassword.reg
@@ -0,0 +1,11 @@
+REGEDIT4
+
+;Contributor: Tim Small (tim.small@virgin.net)
+;Updated: 20 August 1997
+;Status: Current
+;
+;Subject: Registry file to enable plain text passwords in NT4-SP3 and later
+
+[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Rdr\Parameters]
+"EnablePlainTextPassword"=dword:00000001
+
diff --git a/docs/THANKS b/docs/THANKS
index 6405da3f9f4..19c11dc432f 100644
--- a/docs/THANKS
+++ b/docs/THANKS
@@ -20,9 +20,11 @@ please contact Andrew.Tridgell@anu.edu.au, or via normal mail at
Lee Fisher (leefi@microsoft.com)
Charles Fox (cfox@microsoft.com)
Dan Perry (danp@exchnge.microsoft.com)
+Paul Leach (paulle@microsoft.com)
+Isaac Heizer (isaache@microsoft.com)
These Microsoft people have been very helpful and supportive of
- the development of Samba.
+ the development of Samba over some years.
Lee very kindly supplied me with a copy of the X/Open SMB
specs. These have been invaluable in getting the details of the
@@ -43,6 +45,11 @@ Dan Perry (danp@exchnge.microsoft.com)
NT browsing spec, which will help a lot in the development of the
Samba browser code.
+ Paul was responsible for Microsoft paying my flight to Seattle for the
+ first CIFS conference (see http://samba.anu.edu.au/cifs) and has been
+ generally helpful and cooperative as the SMB community moves towards
+ an Internet-ready specification. Isaac has regularly provided help on
+ the behaviour of NT networks.
Bruce Perens (bruce@pixar.com)
@@ -93,7 +100,7 @@ Steve Kennedy (steve@gbnet.net)
John Terpstra (jht@aquasoft.com.au)
- Aquasoft are a speciaist consulting company whose Samba using
+ Aquasoft are a specialist consulting company whose Samba-using
customers span the world.
Aquasoft have been avid supporters of the Samba project. As a
@@ -117,3 +124,14 @@ Steve Withers (swithers@vnet.IBM.COM)
OS/2 Warp installed. I hope this will allow me to finally fix
up those annoying OS/2 related Samba bugs that I have been
receiving reports of.
+
+Keith Wilkins (wilki1k@nectech.co.uk)
+
+ Keith from NEC in England very generously supplied a PC to
+ Luke Leighton to help with his nmbd development work. At the
+ same time Keith offered to help me with some new hardware, and
+ he sent me a pentium motherboard with 32MB of ram
+ onboard. This was very helpful as it allowed me to upgrade
+ my aging server to be a very powerful system. Thanks!
+
+
diff --git a/docs/Win95_PlainPassword.reg b/docs/Win95_PlainPassword.reg
new file mode 100644
index 00000000000..9dd3103689c
--- /dev/null
+++ b/docs/Win95_PlainPassword.reg
@@ -0,0 +1,4 @@
+REGEDIT4
+
+[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\VxD\VNETSUP]
+"EnablePlainTextPassword"=dword:00000001
diff --git a/docs/announce b/docs/announce
index f761320f43e..a03ddcd0e6a 100644
--- a/docs/announce
+++ b/docs/announce
@@ -4,19 +4,21 @@
What is Samba?
--------------
-Samba is a Unix based SMB file server. This allows a Unix host to
-act as a file and print server for SMB clients. This includes
+Samba is a SMB file server that runs on Unix and other operating systems.
+It allows these operating systems (currently Unix, Netware, OS/2 and
+AmigaDOS) to act as a file and print server for SMB clients. There are many
Lan-Manager compatible clients such as LanManager for DOS, Windows for
Workgroups, Windows NT, Windows 95, OS/2, Pathworks and many more.
-The package also includes a Unix SMB client and a netbios nameserver.
+The package also includes a SMB client for accessing other SMB servers
+and a netbios nameserver for browsing support.
What can it do for me?
----------------------
If you have any PCs running SMB clients, such as a PC running Windows
-for Workgroups, then you can mount file space or printers from a unix
-host, so that directories, files and printers on the unix host are
+for Workgroups, then you can mount file space or printers on a Samba
+host, so that directories, files and printers on the host are
available on the PC.
The client part of the package will also allow you to attach to other
@@ -26,12 +28,12 @@ allows you to access a SMB printer (such as one attached to an OS/2 or
WfWg server) from Unix, using an entry in /etc/printcap, or by
explicitly specifying the command used to print files.
-What are it's features?
+What are its features?
------------------------
Samba supports many features that are not supported in other SMB
implementations (all of which are commercial). Some of it's features
-include host as well as username/password security, a unix client,
+include host as well as username/password security, a client,
automatic home directory exporting, automatic printer exporting, dead
connection timeouts, umask support, guest connections, name mangling
and hidden and system attribute mapping. Look at the man pages
@@ -66,7 +68,7 @@ Samba software is free software. It is available under the
GNU Public licence in source code form at no cost. Please read the
file COPYING that comes with the package for more information.
-What flavours of unix does it support?
+What operating systems does it support?
---------------------------------------
The code has been written to be as portable as possible. It has been
@@ -76,10 +78,12 @@ unixes:
Linux, SunOS, Solaris, SVR4, Ultrix, OSF1, AIX, BSDI, NetBSD,
Sequent, HP-UX, SGI, FreeBSD, NeXT, ISC, A/UX, SCO, Intergraph,
-Domain/OS and DGUX.
+Silicon Graphics Inc., Domain/OS and DGUX.
Some of these have received more testing than others. If it doesn't
-work with your unix then it should be easy to fix.
+work with your unix then it should be easy to fix. It has also been ported
+to Netware, OS/2 and the Amiga. A VMS port is available too. See the web site
+for more details.
Who wrote it?
-------------
@@ -93,8 +97,8 @@ on who did what bits.
Where can I get it?
-------------------
-The package is available via anonymous ftp from nimbus.anu.edu.au in
-the directory pub/tridge/samba/.
+The package is available via anonymous ftp from samba.anu.edu.au in
+the directory pub/samba/.
What about SMBServer?
---------------------
@@ -123,7 +127,7 @@ There is also often quite a bit of discussion about Samba on the
newsgroup comp.protocols.smb.
A WWW site with lots of Samba info can be found at
-http://lake.canberra.edu.au/pub/samba/
+http://samba.anu.edu.au/samba/
-Andrew Tridgell (Contact: samba-bugs@anu.edu.au)
-January 1995
+The Samba Team (Contact: samba-bugs@samba.anu.edu.au)
+June 1996
diff --git a/docs/faq/Samba-Server-FAQ-1.html b/docs/faq/Samba-Server-FAQ-1.html
new file mode 100644
index 00000000000..0bf7f046109
--- /dev/null
+++ b/docs/faq/Samba-Server-FAQ-1.html
@@ -0,0 +1,77 @@
+<HTML>
+<HEAD>
+<TITLE> Samba Server FAQ: What is Samba?</TITLE>
+</HEAD>
+<BODY>
+Previous
+<A HREF="Samba-Server-FAQ-2.html">Next</A>
+<A HREF="Samba-Server-FAQ.html#toc1">Table of Contents</A>
+<HR>
+<H2><A NAME="s1">1. What is Samba?</A></H2>
+
+<P>
+<A NAME="WhatIsSamba"></A>
+</P>
+<P>See the
+<A HREF="Samba-meta-FAQ.html#introduction">meta FAQ introduction</A> if you don't have any idea what Samba does.</P>
+<P>Samba has many features that are not supported in other CIFS and SMB
+implementations, all of which are commercial. It approaches some
+problems from a different angle.</P>
+<P>Some of its features include:
+<UL>
+<LI>extremely dynamic runtime configuration</LI>
+<LI>host as well as username/password security</LI>
+<LI>scriptable SMB client</LI>
+<LI>automatic home directory exporting</LI>
+<LI>automatic printer exporting</LI>
+<LI>intelligent dead connection timeouts</LI>
+<LI>guest connections</LI>
+</UL>
+</P>
+<P>Look at the
+<A HREF="samba-man-index.html">manual pages</A> included with the package for a full list of
+features. The components of the suite are (in summary):</P>
+<P>
+<DL>
+
+<DT><B>smbd</B><DD><P>the SMB server. This handles actual connections from clients,
+doing all the interfacing with the
+<A HREF="Samba-meta-FAQ.html#DomainModeSecurity">authentication database</A> for file, permission and username work.</P>
+
+<DT><B>nmbd</B><DD><P>the NetBIOS name server, which helps clients locate servers,
+maintaining the
+<A HREF="Samba-meta-FAQ.html#BrowseAndDomainDefs">authentication database</A> doing the browsing work and managing
+domains as this capability is being built into Samba.</P>
+
+<DT><B>smbclient</B><DD><P>the scriptable commandline SMB client program.
+Useful for automated work, printer filters and testing purposes. It is
+more CIFS-compliant than most commercial implementations. Note that this
+is not a filesystem. The Samba team does not supply a network filesystem
+driver, although the smbfs filesystem for Linux is derived from
+smbclient code.</P>
+
+<DT><B>smbrun</B><DD><P>a little 'glue' program to help the server run
+external programs.</P>
+
+<DT><B>testprns</B><DD><P>a program to test server access to printers</P>
+
+<DT><B>testparms</B><DD><P>a program to test the Samba configuration file
+for correctness</P>
+
+<DT><B>smb.conf</B><DD><P>the Samba configuration file</P>
+
+<DT><B>examples</B><DD><P>many examples have been put together for the different
+operating systems that Samba supports.</P>
+
+<DT><B>Documentation!</B><DD><P>DON'T neglect to read it - you will save a great
+deal of time!</P>
+
+</DL>
+</P>
+
+<HR>
+Previous
+<A HREF="Samba-Server-FAQ-2.html">Next</A>
+<A HREF="Samba-Server-FAQ.html#toc1">Table of Contents</A>
+</BODY>
+</HTML>
diff --git a/docs/faq/Samba-Server-FAQ-2.html b/docs/faq/Samba-Server-FAQ-2.html
new file mode 100644
index 00000000000..731391a9987
--- /dev/null
+++ b/docs/faq/Samba-Server-FAQ-2.html
@@ -0,0 +1,500 @@
+<HTML>
+<HEAD>
+<TITLE> Samba Server FAQ: How do I get the CIFS, SMB and NetBIOS protocols?</TITLE>
+</HEAD>
+<BODY>
+<A HREF="Samba-Server-FAQ-1.html">Previous</A>
+Next
+<A HREF="Samba-Server-FAQ.html#toc2">Table of Contents</A>
+<HR>
+<H2><A NAME="s2">2. How do I get the CIFS, SMB and NetBIOS protocols?</A></H2>
+
+<P>
+<A NAME="ServerProtocols"></A>
+</P>
+<P>See the
+<A HREF="Samba-meta-FAQ.html#CifsSmb">meta FAQ on CIFS and SMB</A> if you don't have any idea what these protocols are.</P>
+<P>CIFS and SMB are implemented by the main Samba fileserving daemon, smbd.
+<F>.....</F></P>
+<P>nmbd speaks a limited amount of CIFS (...) but is mostly concerned with
+NetBIOS. NetBIOS is <F>....</F></P>
+<P>RFC1001, RFC1002 <F>...</F></P>
+<P>So, provided you have got Samba correctly installed and running you have
+all three of these protocols. Some operating systems already come with
+stacks for all or some of these, such as SCO Unix, OS/2 and <F>...</F> In this
+case you must <F>...</F></P>
+
+<H2><A NAME="ss2.1">2.1 What server operating systems are supported?</A></H2>
+
+<P>
+<A NAME="PortInfo"></A>
+</P>
+<P>At the last count, Samba runs on about 40 operating systems! This
+section looks at general questions about running Samba on the different
+platforms. Issues specific to particular operating systems are dealt
+with in elsewhere in this document.</P>
+<P>Many of the ports have been done by people outside the Samba team keen
+to get the advantages of Samba. The Samba team is currently trying to
+bring as many of these ports as possible into the main source tree and
+integrate the documentation. Samba is an integration tool, and so it has
+been made as easy as possible to port. The platforms most widely used
+and thus best tested are Linux and SunOS.</P>
+<P>This migration has not been completed yet. This means that some
+documentation is on web sites <F>...</F></P>
+<P>There are two main families of Samba ports, Unix and other. The Unix
+ports cover anything that remotely resembles Unix and includes some
+extremely old products as well as best-sellers, tiny PCs to massive
+multiprocessor machines supporting hundreds of thousands of users. Samba
+has been run on more than 30 Unix and Unix-like operating systems.</P>
+
+<H3>Running Samba on a Unix or Unix-like system</H3>
+
+<P>
+<A NAME="OnUnix"></A>
+</P>
+<P>
+<A HREF="../UNIX-SMB.txt">../UNIX-SMB.txt</A> describes some of the issues that confront a
+SMB implementation on unix, and how Samba copes with them. They may help
+people who are looking at unix<->PC interoperability.</P>
+<P>There is great variation between Unix implementations, especially those
+not adhering to the Common Unix Specification agreed to in 1996. Things
+that can be quite tricky are <F>.....</F></P>
+<P>There are also some considerable advantages conferred on Samba running
+under Unix compared to, say, Windows NT or LAN Server. Unix has <F>...</F></P>
+<P>At time of writing, the Makefile claimed support for:
+<UL>
+<LI> A/UX 3.0</LI>
+<LI> AIX</LI>
+<LI> Altos Series 386/1000</LI>
+<LI> Amiga</LI>
+<LI> Apollo Domain/OS sr10.3</LI>
+<LI> BSDI </LI>
+<LI> B.O.S. (Bull Operating System)</LI>
+<LI> Cray, Unicos 8.0</LI>
+<LI> Convex</LI>
+<LI> DGUX. </LI>
+<LI> DNIX.</LI>
+<LI> FreeBSD</LI>
+<LI> HP-UX</LI>
+<LI> Intergraph. </LI>
+<LI> Linux with/without shadow passwords and quota</LI>
+<LI> LYNX 2.3.0</LI>
+<LI> MachTen (a unix like system for Macintoshes)</LI>
+<LI> Motorola 88xxx/9xx range of machines</LI>
+<LI> NetBSD</LI>
+<LI> NEXTSTEP Release 2.X, 3.0 and greater (including OPENSTEP for Mach).</LI>
+<LI> OS/2 using EMX 0.9b</LI>
+<LI> OSF1</LI>
+<LI> QNX 4.22</LI>
+<LI> RiscIX. </LI>
+<LI> RISCOs 5.0B</LI>
+<LI> SEQUENT. </LI>
+<LI> SCO (including: 3.2v2, European dist., OpenServer 5)</LI>
+<LI> SGI.</LI>
+<LI> SMP_DC.OSx v1.1-94c079 on Pyramid S series</LI>
+<LI> SONY NEWS, NEWS-OS (4.2.x and 6.1.x)</LI>
+<LI> SUNOS 4</LI>
+<LI> SUNOS 5.2, 5.3, and 5.4 (Solaris 2.2, 2.3, and '2.4 and later')</LI>
+<LI> Sunsoft ISC SVR3V4</LI>
+<LI> SVR4</LI>
+<LI> System V with some berkely extensions (Motorola 88k R32V3.2).</LI>
+<LI> ULTRIX.</LI>
+<LI> UNIXWARE</LI>
+<LI> UXP/DS</LI>
+</UL>
+</P>
+
+
+<H3>Running Samba on systems unlike Unix</H3>
+
+<P>
+<A NAME="OnUnlikeUnix"></A>
+</P>
+<P>More recently Samba has been ported to a number of operating systems
+which can provide a BSD Unix-like implementation of TCP/IP sockets.
+These include OS/2, Netware, VMS, StratOS, Amiga and MVS. BeOS,
+Windows NT and several others are being worked on but not yet available
+for use.</P>
+<P>Home pages for these ports are:</P>
+<P><F>... </F></P>
+
+
+<H2><A NAME="ss2.2">2.2 Exporting server resources with Samba</A></H2>
+
+<P>
+<A NAME="Exporting"></A>
+</P>
+<P>Files, printers, CD ROMs and other local devices. Network devices,
+including networked filesystems and remote printer queues. Other devices
+such as <F>....</F></P>
+<P>1.4) Configuring SHARES
+1.4.1) Homes service
+1.4.2) Public services
+1.4.3) Application serving
+1.4.4) Team sharing a Samba resource</P>
+<P>1.5) Printer configuration
+1.5.1) Berkeley LPR/LPD systems
+1.5.2) ATT SysV lp systems
+1.5.3) Using a private printcap file
+1.5.4) Use of the smbprint utility
+1.5.5) Printing from Windows to Unix
+1.5.6) Printing from Unix to Windows</P>
+
+
+<H2><A NAME="ss2.3">2.3 Name Resolution and Browsing</A></H2>
+
+<P>
+<A NAME="NameBrowsing"></A>
+</P>
+<P>See also
+<A HREF="../BROWSING.txt">../BROWSING.txt</A></P>
+<P>1.6) Name resolution issues
+1.6.1) LMHOSTS file and when to use it
+1.6.2) configuring WINS (support, server, proxy)
+1.6.3) configuring DNS proxy</P>
+<P>1.7) Problem Diagnosis
+1.8) What NOT to do!!!!</P>
+<P>3.2) Browse list managment
+3.3) Name resolution mangement</P>
+
+
+
+<H2><A NAME="ss2.4">2.4 Handling SMB Encryption</A></H2>
+
+<P>
+<A NAME="SMBEncryptionSteps"></A>
+</P>
+<P>SMB encryption is ...</P>
+<P>...in
+<A HREF="../ENCRYPTION.txt">../ENCRYPTION.txt</A> there is...</P>
+<P>Samba compiled with libdes - enabling encrypted passwords</P>
+
+
+<H3>Laws in different countries affecting Samba</H3>
+
+<P>
+<A NAME="CryptoLaws"></A>
+</P>
+
+<H3>Relationship between encryption and Domain Authentication</H3>
+
+
+
+
+<H2><A NAME="ss2.5">2.5 Files and record locking</A> 3.1.1) Old DOS clients 3.1.2) Opportunistic locking and the consequences 3.1.3) Files caching under Windows for Workgroups, Win95 and NT Some of the foregoing links into Client-FAQ</H2>
+
+
+<H2><A NAME="ss2.6">2.6 Managing Samba Log files</A></H2>
+
+<P>
+<A NAME="LogFiles"></A>
+</P>
+
+
+<H2><A NAME="ss2.7">2.7 I can't see the Samba server in any browse lists!</A></H2>
+
+<P>
+<A NAME="no_browse"></A>
+
+See
+<A HREF="ftp://samba.anu.edu.au/pub/samba/BROWSING.txt">BROWSING.txt</A>
+for more information on browsing. Browsing.txt can also be found
+in the docs directory of the Samba source.</P>
+<P>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:
+<BLOCKQUOTE><CODE>
+<PRE>
+ net use M: \\mary\fred
+</PRE>
+</CODE></BLOCKQUOTE>
+
+The details of how to do this and the specific syntax varies from
+client to client - check your client's documentation.</P>
+
+
+<H2><A NAME="ss2.8">2.8 Some files that I KNOW are on the server doesn't show up when I view the files from my client! </A></H2>
+
+<P>
+<A NAME="missing_files"></A>
+
+See the next question.</P>
+
+
+<H2><A NAME="ss2.9">2.9 Some files on the server show up with really wierd filenames when I view the files from my client! </A></H2>
+
+<P>
+<A NAME="strange_filenames"></A>
+
+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).</P>
+<P>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".</P>
+
+
+<H2><A NAME="ss2.10">2.10 My client reports "cannot locate specified computer" or similar</A></H2>
+
+<P>
+<A NAME="cant_see_server"></A>
+
+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.</P>
+<P>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.</P>
+<P>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.</P>
+<P>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.</P>
+<P>By the way, remember to REMOVE the hardcoded mapping before further
+tests :-) </P>
+
+
+<H2><A NAME="ss2.11">2.11 My client reports "cannot locate specified share name" or similar</A></H2>
+
+<P>
+<A NAME="cant_see_share"></A>
+
+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.</P>
+<P>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:</P>
+<P>
+<UL>
+<LI> Many clients cannot accept or use service names longer than eight characters.</LI>
+<LI> Many clients cannot accept or use service names containing spaces.</LI>
+<LI> Some servers (not Samba though) are case sensitive with service names.</LI>
+<LI> Some clients force service names into upper case.</LI>
+</UL>
+</P>
+
+
+<H2><A NAME="ss2.12">2.12 My client reports "cannot find domain controller", "cannot log on to the network" or similar </A></H2>
+
+<P>
+<A NAME="cant_see_net"></A>
+
+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
+<A HREF="mailto:samba-bugs@anu.edu.au">samba-bugs@anu.edu.au</A> !</P>
+<P>Seeing this message should not affect your ability to mount redirected
+disks and printers, which is really what all this is about.</P>
+<P>For many clients (including Windows for Workgroups and Lan Manager),
+setting the domain to STANDALONE at least gets rid of the message.</P>
+
+
+<H2><A NAME="ss2.13">2.13 Printing doesn't work :-(</A></H2>
+
+<P>
+<A NAME="no_printing"></A>
+ </P>
+<P>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", if you happen to be using
+Unix).</P>
+<P>Make sure that the spool directory specified for the service is
+writable by the user connected to the service. </P>
+<P>Make sure that the user specified in the service is permitted to use
+the printer.</P>
+<P>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.</P>
+<P>If using WfWg then you need to set the default protocol to TCP/IP, not
+Netbeui. This is a WfWg bug.</P>
+<P>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.</P>
+
+
+<H2><A NAME="ss2.14">2.14 My programs install on the server OK, but refuse to work properly</A></H2>
+
+<P>
+<A NAME="programs_wont_run"></A>
+
+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.</P>
+<P>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 via email at
+<A HREF="mailto:samba-bugs@anu.edu.au">samba-bugs@anu.edu.au</A>.</P>
+
+
+<H2><A NAME="ss2.15">2.15 My "server string" doesn't seem to be recognised</A></H2>
+
+<P>
+<A NAME="bad_server_string"></A>
+
+OR My client reports the default setting, eg. "Samba 1.9.15p4", instead
+of what I have changed it to in the smb.conf file.</P>
+<P>You need to use the -C option in nmbd. The "server string" affects
+what smbd puts out and -C affects what nmbd puts out.</P>
+<P>Current versions of Samba (1.9.16 +) have combined these options into
+the "server string" field of smb.conf, -C for nmbd is now obsolete.</P>
+
+
+<H2><A NAME="ss2.16">2.16 My client reports "This server is not configured to list shared resources" </A></H2>
+
+<P>
+<A NAME="cant_list_shares"></A>
+
+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.</P>
+<P>See also 'guest account' in smb.conf man page.</P>
+
+
+<H2><A NAME="ss2.17">2.17 Issues specific to Unix and Unix-like systems</A></H2>
+
+<P>
+<A NAME="UnixIssues"></A>
+</P>
+
+<H3>Printing doesn't work with my Unix Samba server</H3>
+
+<P>
+<A NAME="no_printing"></A>
+ </P>
+<P>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".</P>
+
+<H3>Log message "you appear to have a trapdoor uid system" </H3>
+
+<P>
+<A NAME="trapdoor_uid"></A>
+
+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.</P>
+<P>It might also mean that your OS has a trapdoor uid/gid system :-)</P>
+<P>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.</P>
+<P>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.</P>
+<P>Complain to your OS vendor and ask them to fix their system.</P>
+<P>Note: the reason why 65535 is a VERY bad choice of uid and gid is that
+it casts to -1 as a uid, and the setreuid() system call ignores (with
+no error) uid changes to -1. This means any daemon attempting to run
+as uid 65535 will actually run as root. This is not good!</P>
+
+
+<H2><A NAME="ss2.18">2.18 Issues specific to IBM OS/2 systems</A></H2>
+
+<P>
+<A NAME="OS2Issues"></A>
+</P>
+<P>
+<A HREF="http://carol.wins.uva.nl/~leeuw/samba/samba2.html">Samba for OS/2</A></P>
+
+
+<H2><A NAME="ss2.19">2.19 Issues specific to IBM MVS systems</A></H2>
+
+<P>
+<A NAME="MVSIssues"></A>
+</P>
+<P>
+<A HREF="ftp://ftp.mks.com/pub/samba/">Samba for OS/390 MVS</A></P>
+
+
+<H2><A NAME="ss2.20">2.20 Issues specific to Digital VMS systems</A></H2>
+
+<P>
+<A NAME="VMSIssues"></A>
+</P>
+
+
+<H2><A NAME="ss2.21">2.21 Issues specific to Amiga systems</A></H2>
+
+<P>
+<A NAME="AmigaIssues"></A>
+</P>
+<P>
+<A HREF="http://www.gbar.dtu.dk/~c948374/Amiga/Samba/">Samba for Amiga</A></P>
+<P>There is a mailing list for Samba on the Amiga.</P>
+<P>Subscribing.</P>
+<P>Send an email to rask-samba-request@kampsax.dtu.dk with the word subscribe
+in the message. The list server will use the address in the Reply-To: or
+From: header field, in that order.</P>
+<P>Unsubscribing.</P>
+<P>Send an email to rask-samba-request@kampsax.dtu.dk with the word
+unsubscribe in the message. The list server will use the address in the
+Reply-To: or From: header field, in that order. If you are unsure which
+address you are subscribed with, look at the headers. You should see a
+"From " (no colon) or Return-Path: header looking something like</P>
+<P>rask-samba-owner-myname=my.domain@kampsax.dtu.dk</P>
+<P>where myname=my.domain gives you the address myname@my.domain. This also
+means that I will always be able to find out which address is causing
+bounces, for example.
+List archive.</P>
+<P>Messages sent to the list are archived in HTML. See the mailing list home
+page at
+<A HREF="http://www.gbar.dtu.dk/~c948374/Amiga/Samba/mailinglist/">http://www.gbar.dtu.dk/~c948374/Amiga/Samba/mailinglist/</A></P>
+
+
+<H2><A NAME="ss2.22">2.22 Issues specific to Novell IntraNetware systems</A></H2>
+
+<P>
+<A NAME="NetwareIssues"></A>
+</P>
+
+
+<H2><A NAME="ss2.23">2.23 Issues specific to Stratos VOS systems</A></H2>
+
+<P>
+<A NAME="NetwareIssues"></A>
+</P>
+<P>
+<A HREF="ftp://ftp.stratus.com/pub/vos/tools/">Samba for Stratus VOS</A></P>
+
+
+<HR>
+<A HREF="Samba-Server-FAQ-1.html">Previous</A>
+Next
+<A HREF="Samba-Server-FAQ.html#toc2">Table of Contents</A>
+</BODY>
+</HTML>
diff --git a/docs/faq/Samba-Server-FAQ.html b/docs/faq/Samba-Server-FAQ.html
new file mode 100644
index 00000000000..eadc3e26ede
--- /dev/null
+++ b/docs/faq/Samba-Server-FAQ.html
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<HTML>
+<HEAD>
+<TITLE> Samba Server FAQ</TITLE>
+</HEAD>
+<BODY>
+Previous
+<A HREF="Samba-Server-FAQ-1.html">Next</A>
+Table of Contents
+<HR>
+<H1> Samba Server FAQ</H1>
+
+<H2>Dan Shearer & Paul Blackman, <CODE>ictinus@samba.anu.edu.au</CODE></H2>v 0.3, 7 Oct '97
+<P><HR><EM> This is the <EM>Server</EM> Frequently Asked Questions (FAQ)
+document for Samba, the free and very popular SMB and CIFS server
+product. A general
+<A HREF="Samba-meta-FAQ.html">meta FAQ</A>
+exists and also a companion
+<A HREF="Samba-Client-FAQ.html">Client FAQ</A>, together with more detailed HOWTO documents on
+topics to do with Samba software. This is current to Samba version
+1.9.17. Please send any corrections to the author. </EM><HR></P>
+<P>
+<H2><A NAME="toc1">1.</A> <A HREF="Samba-Server-FAQ-1.html">What is Samba?</A></H2>
+
+<P>
+<H2><A NAME="toc2">2.</A> <A HREF="Samba-Server-FAQ-2.html">How do I get the CIFS, SMB and NetBIOS protocols?</A></H2>
+<UL>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.1">2.1 What server operating systems are supported?</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.2">2.2 Exporting server resources with Samba</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.3">2.3 Name Resolution and Browsing</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.4">2.4 Handling SMB Encryption</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.5">2.5 Files and record locking</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.6">2.6 Managing Samba Log files</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.7">2.7 I can't see the Samba server in any browse lists!</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.8">2.8 Some files that I KNOW are on the server doesn't show up when I view the files from my client! </A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.9">2.9 Some files on the server show up with really wierd filenames when I view the files from my client! </A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.10">2.10 My client reports "cannot locate specified computer" or similar</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.11">2.11 My client reports "cannot locate specified share name" or similar</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.12">2.12 My client reports "cannot find domain controller", "cannot log on to the network" or similar </A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.13">2.13 Printing doesn't work :-(</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.14">2.14 My programs install on the server OK, but refuse to work properly</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.15">2.15 My "server string" doesn't seem to be recognised</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.16">2.16 My client reports "This server is not configured to list shared resources" </A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.17">2.17 Issues specific to Unix and Unix-like systems</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.18">2.18 Issues specific to IBM OS/2 systems</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.19">2.19 Issues specific to IBM MVS systems</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.20">2.20 Issues specific to Digital VMS systems</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.21">2.21 Issues specific to Amiga systems</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.22">2.22 Issues specific to Novell IntraNetware systems</A>
+<LI><A HREF="Samba-Server-FAQ-2.html#ss2.23">2.23 Issues specific to Stratos VOS systems</A>
+</UL>
+
+
+<HR>
+Previous
+<A HREF="Samba-Server-FAQ-1.html">Next</A>
+Table of Contents
+</BODY>
+</HTML>
diff --git a/docs/faq/Samba-Server-FAQ.sgml b/docs/faq/Samba-Server-FAQ.sgml
new file mode 100644
index 00000000000..020d5322811
--- /dev/null
+++ b/docs/faq/Samba-Server-FAQ.sgml
@@ -0,0 +1,492 @@
+<!doctype linuxdoc system> <!-- -*- SGML -*- -->
+<!--
+ v 0.1 23 Aug 1997 Dan Shearer
+ Original Samba-Client-FAQ.sgml from Paul's sambafaq.sgml
+ v 0.2 25 Aug 1997 Dan
+ v 0.3 7 Oct 1997 Paul, changed email address from ictinus@lake... to ictinus@samba.anu
+-->
+
+
+<article>
+
+<title> Samba Server FAQ
+
+<author>Dan Shearer & Paul Blackman, <tt>ictinus@samba.anu.edu.au</tt>
+
+<date>v 0.3, 7 Oct '97
+
+<abstract> This is the <em>Server</em> Frequently Asked Questions (FAQ)
+document for Samba, the free and very popular SMB and CIFS server
+product. A general <url url="Samba-meta-FAQ.html" name="meta FAQ">
+exists and also a companion <url url="Samba-Client-FAQ.html"
+name="Client FAQ">, together with more detailed HOWTO documents on
+topics to do with Samba software. This is current to Samba version
+1.9.17. Please send any corrections to the author.
+
+</abstract>
+
+<toc>
+
+<sect>What is Samba?<p><label id="WhatIsSamba">
+
+See the <url url="Samba-meta-FAQ.html#introduction" name="meta FAQ
+introduction"> if you don't have any idea what Samba does.
+
+Samba has many features that are not supported in other CIFS and SMB
+implementations, all of which are commercial. It approaches some
+problems from a different angle.
+
+Some of its features include:
+<itemize>
+<item>extremely dynamic runtime configuration
+<item>host as well as username/password security
+<item>scriptable SMB client
+<item>automatic home directory exporting
+<item>automatic printer exporting
+<item>intelligent dead connection timeouts
+<item>guest connections
+</itemize>
+
+Look at the <url url="samba-man-index.html" name="manual pages"> included with the package for a full list of
+features. The components of the suite are (in summary):
+
+<descrip>
+
+<tag/smbd/ the SMB server. This handles actual connections from clients,
+doing all the interfacing with the <url
+url="Samba-meta-FAQ.html#DomainModeSecurity" name="authentication
+database"> for file, permission and username work.
+
+<tag/nmbd/ the NetBIOS name server, which helps clients locate servers,
+maintaining the <url url="Samba-meta-FAQ.html#BrowseAndDomainDefs"
+name="authentication database"> doing the browsing work and managing
+domains as this capability is being built into Samba.
+
+<tag/smbclient/ the scriptable commandline SMB client program.
+Useful for automated work, printer filters and testing purposes. It is
+more CIFS-compliant than most commercial implementations. Note that this
+is not a filesystem. The Samba team does not supply a network filesystem
+driver, although the smbfs filesystem for Linux is derived from
+smbclient code.
+
+<tag/smbrun/ a little 'glue' program to help the server run
+external programs.
+
+<tag/testprns/ a program to test server access to printers
+
+<tag/testparms/ a program to test the Samba configuration file
+for correctness
+
+<tag/smb.conf/ the Samba configuration file
+
+<tag/examples/ many examples have been put together for the different
+operating systems that Samba supports.
+
+<tag/Documentation!/ DON'T neglect to read it - you will save a great
+deal of time!
+
+</descrip>
+
+<sect>How do I get the CIFS, SMB and NetBIOS protocols?<p><label id="ServerProtocols">
+
+See the <url url="Samba-meta-FAQ.html#CifsSmb" name="meta FAQ
+on CIFS and SMB"> if you don't have any idea what these protocols are.
+
+CIFS and SMB are implemented by the main Samba fileserving daemon, smbd.
+[.....]
+
+nmbd speaks a limited amount of CIFS (...) but is mostly concerned with
+NetBIOS. NetBIOS is [....]
+
+RFC1001, RFC1002 [...]
+
+So, provided you have got Samba correctly installed and running you have
+all three of these protocols. Some operating systems already come with
+stacks for all or some of these, such as SCO Unix, OS/2 and [...] In this
+case you must [...]
+
+<sect1>What server operating systems are supported?<p><label id="PortInfo">
+
+At the last count, Samba runs on about 40 operating systems! This
+section looks at general questions about running Samba on the different
+platforms. Issues specific to particular operating systems are dealt
+with in elsewhere in this document.
+
+Many of the ports have been done by people outside the Samba team keen
+to get the advantages of Samba. The Samba team is currently trying to
+bring as many of these ports as possible into the main source tree and
+integrate the documentation. Samba is an integration tool, and so it has
+been made as easy as possible to port. The platforms most widely used
+and thus best tested are Linux and SunOS.
+
+This migration has not been completed yet. This means that some
+documentation is on web sites [...]
+
+There are two main families of Samba ports, Unix and other. The Unix
+ports cover anything that remotely resembles Unix and includes some
+extremely old products as well as best-sellers, tiny PCs to massive
+multiprocessor machines supporting hundreds of thousands of users. Samba
+has been run on more than 30 Unix and Unix-like operating systems.
+
+<sect2>Running Samba on a Unix or Unix-like system<p><label id="OnUnix">
+
+<url url="../UNIX-SMB.txt"> describes some of the issues that confront a
+SMB implementation on unix, and how Samba copes with them. They may help
+people who are looking at unix<->PC interoperability.
+
+There is great variation between Unix implementations, especially those
+not adhering to the Common Unix Specification agreed to in 1996. Things
+that can be quite tricky are [.....]
+
+There are also some considerable advantages conferred on Samba running
+under Unix compared to, say, Windows NT or LAN Server. Unix has [...]
+
+At time of writing, the Makefile claimed support for:
+<itemize>
+<item> A/UX 3.0
+<item> AIX
+<item> Altos Series 386/1000
+<item> Amiga
+<item> Apollo Domain/OS sr10.3
+<item> BSDI
+<item> B.O.S. (Bull Operating System)
+<item> Cray, Unicos 8.0
+<item> Convex
+<item> DGUX.
+<item> DNIX.
+<item> FreeBSD
+<item> HP-UX
+<item> Intergraph.
+<item> Linux with/without shadow passwords and quota
+<item> LYNX 2.3.0
+<item> MachTen (a unix like system for Macintoshes)
+<item> Motorola 88xxx/9xx range of machines
+<item> NetBSD
+<item> NEXTSTEP Release 2.X, 3.0 and greater (including OPENSTEP for Mach).
+<item> OS/2 using EMX 0.9b
+<item> OSF1
+<item> QNX 4.22
+<item> RiscIX.
+<item> RISCOs 5.0B
+<item> SEQUENT.
+<item> SCO (including: 3.2v2, European dist., OpenServer 5)
+<item> SGI.
+<item> SMP_DC.OSx v1.1-94c079 on Pyramid S series
+<item> SONY NEWS, NEWS-OS (4.2.x and 6.1.x)
+<item> SUNOS 4
+<item> SUNOS 5.2, 5.3, and 5.4 (Solaris 2.2, 2.3, and '2.4 and later')
+<item> Sunsoft ISC SVR3V4
+<item> SVR4
+<item> System V with some berkely extensions (Motorola 88k R32V3.2).
+<item> ULTRIX.
+<item> UNIXWARE
+<item> UXP/DS
+</itemize>
+
+
+<sect2>Running Samba on systems unlike Unix<p><label id="OnUnlikeUnix">
+
+More recently Samba has been ported to a number of operating systems
+which can provide a BSD Unix-like implementation of TCP/IP sockets.
+These include OS/2, Netware, VMS, StratOS, Amiga and MVS. BeOS,
+Windows NT and several others are being worked on but not yet available
+for use.
+
+Home pages for these ports are:
+
+[... ]
+
+<sect1>Exporting server resources with Samba<p><label id="Exporting">
+
+Files, printers, CD ROMs and other local devices. Network devices,
+including networked filesystems and remote printer queues. Other devices
+such as [....]
+
+ 1.4) Configuring SHARES
+ 1.4.1) Homes service
+ 1.4.2) Public services
+ 1.4.3) Application serving
+ 1.4.4) Team sharing a Samba resource
+
+ 1.5) Printer configuration
+ 1.5.1) Berkeley LPR/LPD systems
+ 1.5.2) ATT SysV lp systems
+ 1.5.3) Using a private printcap file
+ 1.5.4) Use of the smbprint utility
+ 1.5.5) Printing from Windows to Unix
+ 1.5.6) Printing from Unix to Windows
+
+<sect1>Name Resolution and Browsing<p><label id="NameBrowsing">
+
+See also <url url="../BROWSING.txt">
+
+ 1.6) Name resolution issues
+ 1.6.1) LMHOSTS file and when to use it
+ 1.6.2) configuring WINS (support, server, proxy)
+ 1.6.3) configuring DNS proxy
+
+ 1.7) Problem Diagnosis
+ 1.8) What NOT to do!!!!
+
+ 3.2) Browse list managment
+ 3.3) Name resolution mangement
+
+
+<sect1>Handling SMB Encryption<p><label id="SMBEncryptionSteps">
+
+SMB encryption is ...
+
+...in <url url="../ENCRYPTION.txt"> there is...
+
+Samba compiled with libdes - enabling encrypted passwords
+
+
+<sect2>Laws in different countries affecting Samba<p><label id="CryptoLaws">
+
+<sect2>Relationship between encryption and Domain Authentication<p>
+
+<sect1> Files and record locking
+
+ 3.1.1) Old DOS clients
+ 3.1.2) Opportunistic locking and the consequences
+ 3.1.3) Files caching under Windows for Workgroups, Win95 and NT
+
+ Some of the foregoing links into Client-FAQ
+
+<sect1>Managing Samba Log files<p><label id="LogFiles">
+
+<sect1>I can't see the Samba server in any browse lists!<p><label id="no_browse">
+ See <url url="ftp://samba.anu.edu.au/pub/samba/BROWSING.txt" name="BROWSING.txt">
+ for more information on browsing. Browsing.txt can also be found
+ in the docs directory of the Samba source.
+
+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:
+<tscreen><verb>
+ net use M: \\mary\fred
+</verb></tscreen>
+The details of how to do this and the specific syntax varies from
+client to client - check your client's documentation.
+
+<sect1>Some files that I KNOW are on the server doesn't show up when I view the files from my client! <p> <label id="missing_files">
+See the next question.
+
+<sect1>Some files on the server show up with really wierd filenames when I view the files from my client! <p> <label id="strange_filenames">
+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".
+
+<sect1>My client reports "cannot locate specified computer" or similar<p><label id="cant_see_server">
+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 :-)
+
+<sect1>My client reports "cannot locate specified share name" or similar<p> <label id="cant_see_share">
+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:
+
+<itemize>
+<item> Many clients cannot accept or use service names longer than eight characters.
+<item> Many clients cannot accept or use service names containing spaces.
+<item> Some servers (not Samba though) are case sensitive with service names.
+<item> Some clients force service names into upper case.
+</itemize>
+
+<sect1>My client reports "cannot find domain controller", "cannot log on to the network" or similar <p> <label id="cant_see_net">
+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
+<htmlurl url="mailto:samba-bugs@anu.edu.au" name="samba-bugs@anu.edu.au"> !
+
+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.
+
+<sect1>Printing doesn't work :-(<p> <label id="no_printing">
+
+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", if you happen to be using
+Unix).
+
+Make sure that the spool directory specified for the service is
+writable by the user connected to the service.
+
+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.
+
+<sect1>My programs install on the server OK, but refuse to work properly<p><label id="programs_wont_run">
+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 via email at <htmlurl url="mailto:samba-bugs@anu.edu.au" name="samba-bugs@anu.edu.au">.
+
+<sect1>My "server string" doesn't seem to be recognised<p><label id="bad_server_string">
+OR 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.
+
+Current versions of Samba (1.9.16 +) have combined these options into
+the "server string" field of smb.conf, -C for nmbd is now obsolete.
+
+<sect1>My client reports "This server is not configured to list shared resources" <p> <label id="cant_list_shares">
+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.
+
+<sect1>Issues specific to Unix and Unix-like systems<p><label id="UnixIssues">
+
+<sect2>Printing doesn't work with my Unix Samba server<p> <label id="no_printing">
+
+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".
+
+<sect2>Log message "you appear to have a trapdoor uid system" <p><label id="trapdoor_uid">
+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.
+
+Note: the reason why 65535 is a VERY bad choice of uid and gid is that
+it casts to -1 as a uid, and the setreuid() system call ignores (with
+no error) uid changes to -1. This means any daemon attempting to run
+as uid 65535 will actually run as root. This is not good!
+
+<sect1>Issues specific to IBM OS/2 systems<p><label id="OS2Issues">
+
+<url url="http://carol.wins.uva.nl/~leeuw/samba/samba2.html" name="Samba for OS/2">
+
+<sect1>Issues specific to IBM MVS systems<p><label id="MVSIssues">
+
+<url url="ftp://ftp.mks.com/pub/samba/" name="Samba for OS/390 MVS">
+
+<sect1>Issues specific to Digital VMS systems<p><label id="VMSIssues">
+
+<sect1>Issues specific to Amiga systems<p><label id="AmigaIssues">
+
+<url url="http://www.gbar.dtu.dk/~c948374/Amiga/Samba/" name="Samba for Amiga">
+
+There is a mailing list for Samba on the Amiga.
+
+ Subscribing.
+
+ Send an email to rask-samba-request@kampsax.dtu.dk with the word subscribe
+in the message. The list server will use the address in the Reply-To: or
+From: header field, in that order.
+
+ Unsubscribing.
+
+ Send an email to rask-samba-request@kampsax.dtu.dk with the word
+unsubscribe in the message. The list server will use the address in the
+Reply-To: or From: header field, in that order. If you are unsure which
+address you are subscribed with, look at the headers. You should see a
+"From " (no colon) or Return-Path: header looking something like
+
+ rask-samba-owner-myname=my.domain@kampsax.dtu.dk
+
+where myname=my.domain gives you the address myname@my.domain. This also
+means that I will always be able to find out which address is causing
+bounces, for example.
+ List archive.
+
+ Messages sent to the list are archived in HTML. See the mailing list home
+page at <URL url="http://www.gbar.dtu.dk/~c948374/Amiga/Samba/mailinglist/">
+
+<sect1>Issues specific to Novell IntraNetware systems<p><label id="NetwareIssues">
+
+<sect1>Issues specific to Stratos VOS systems<p><label id="NetwareIssues">
+
+<url url="ftp://ftp.stratus.com/pub/vos/tools/" name="Samba for Stratus VOS">
+
+</article>
diff --git a/docs/faq/Samba-meta-FAQ-1.html b/docs/faq/Samba-meta-FAQ-1.html
new file mode 100644
index 00000000000..80610fb59ed
--- /dev/null
+++ b/docs/faq/Samba-meta-FAQ-1.html
@@ -0,0 +1,160 @@
+<HTML>
+<HEAD>
+<TITLE> Samba meta FAQ: Quick Reference Guides to Samba Documentation</TITLE>
+</HEAD>
+<BODY>
+Previous
+<A HREF="Samba-meta-FAQ-2.html">Next</A>
+<A HREF="Samba-meta-FAQ.html#toc1">Table of Contents</A>
+<HR>
+<H2><A NAME="s1">1. Quick Reference Guides to Samba Documentation</A></H2>
+
+<P>
+<A NAME="quickref"></A>
+</P>
+<P>We are endeavouring to provide links here to every major class of
+information about Samba or things related to Samba. We cannot list every
+document, but we are aiming for all documents to be at most two
+referrals from those listed here. This needs constant maintaining, so
+please send the author your feedback.</P>
+
+<H2><A NAME="ss1.1">1.1 Samba for the Impatient</A></H2>
+
+<P>
+<A NAME="impatient"></A>
+</P>
+<P>You know you should read the documentation but can't wait to start? What
+you need to do then is follow the instructions in the following
+documents in the order given. This should be enough to get a fairly
+simple site going quickly. If you have any problems, refer back to this
+meta-FAQ and follow the links to find more reading material.</P>
+<P>
+<DL>
+<P>
+<A NAME="ImpGet"></A>
+</P>
+<DT><B>Getting Samba:</B><DD><P>The fastest way to get Samba
+going is and install it is to have an operating system for which the
+Samba team has put together an installation package. To see if your OS
+is included have a look at the directory
+/pub/samba/Binary_Packages/"OS_Vendor" on your nearest
+<A HREF="../MIRRORS">mirror site</A>. If it is included follow the
+installation instructions in the README file there and then do some
+<A HREF="#ImpTest">basic testing</A>. If you are not so fortunate, follow the normal
+<A HREF="Samba-meta-FAQ-2.html#WhereFrom">download instructions</A> and then continue with
+<A HREF="#ImpInst">building and installing Samba</A>.</P>
+<P>
+<A NAME="ImpInst"></A>
+</P>
+<DT><B>Building and Installing Samba:</B><DD><P>At the moment
+there are two kinds of Samba server installs besides the prepackaged
+binaries mentioned in the previous step. You need to decide if you have a
+<A HREF="../UNIX_INSTALL.txt">Unix or close relative</A> or
+<A HREF="Samba-Server-FAQ.html#PortInfo">other supported operating system</A>.</P>
+<P>
+<A NAME="ImpTest"></A>
+</P>
+<DT><B>Basic Testing:</B><DD><P>Try to connect using the
+supplied smbclient command-line program. You need to know the IP
+hostname of your server. A service name must be defined in smb.conf, as
+given in the examples (under many operating systems if there is a
+<F>homes</F> service you can just use a valid username.) Then type
+<CODE>smbclient \\hostname\servicename</CODE>
+Under most Unixes you will need to put the parameters within quotation
+marks. If this works, try connecting from one of the SMB clients you
+were planning to use with Samba.</P>
+<P>
+<A NAME="ImpDebug"></A>
+</P>
+<DT><B>Debug sequence:</B><DD><P>If you think you have completed the
+previous step and things aren't working properly work through
+<A HREF="../DIAGNOSIS.txt">the diagnosis recipe.</A></P>
+<P>
+<A NAME="ImpExp"></A>
+</P>
+<DT><B>Exporting files to SMB clients:</B><DD><P>You should read the manual pages
+for smb.conf, but here is a
+<A HREF="Samba-Server-FAQ.html#Exporting">quick answer guide.</A></P>
+<P>
+<A NAME="ImpControl"></A>
+</P>
+<DT><B>Controlling user access:</B><DD><P>the quickest and dirtiest way of sharing
+resources is to use
+<A HREF="Samba-meta-FAQ-4.html#ShareModeSecurity">share level security.</A> If you want to spend more time and have a proper username
+and password database you must read the paragraph on
+<A HREF="Samba-meta-FAQ-4.html#DomainModeSecurity">domain mode security.</A> If you want
+encryption (eg you are using Windows NT clients) follow the
+<A HREF="Samba-Server-FAQ.html#SMBEncryptionSteps">SMB encryption instructions.</A></P>
+<P>
+<A NAME="ImpBrowse"></A>
+</P>
+<DT><B>Browsing:</B><DD><P>if you are happy to type in "\\samba-server\sharename"
+at the client end then do not read any further. Otherwise you need to
+understand the
+browsing terminology</A>
+and read
+<A HREF="Samba-Server-FAQ.html#NameBrowsing">Samba-Server-FAQ.html#NameBrowsing</A>. </P>
+<P>
+<A NAME="ImpPrint"></A>
+</P>
+<DT><B>Printing:</B><DD><P>See the
+<A HREF="Samba-Server-FAQ.html#Printing">printing quick answer guide.</A></P>
+
+</DL>
+</P>
+<P>If you have got everything working to this point, you can expect Samba
+to be stable and secure: these are its greatest strengths. However Samba
+has a great deal to offer and to go further you must do some more
+reading. Speed and security optimisations, printer accounting, network
+logons, roving profiles, browsing across multiple subnets and so on are
+all covered either in this document or in those it refers to.</P>
+
+
+<H2><A NAME="ss1.2">1.2 All Samba Documentation</A></H2>
+
+<P>
+<A NAME="AllDocs"></A>
+</P>
+<P>
+<UL>
+<LI> Meta-FAQ. This is the mother of all documents, and is the one you
+are reading now. The latest version is always at
+<A HREF="http://samba.anu.edu.au/[.....]">http://samba.anu.edu.au/[.....]</A> but there is probably a much
+nearer
+<A HREF="../MIRRORS">mirror site</A> which you should use
+instead.
+</LI>
+<LI>
+<A HREF="Samba-Server-FAQ.html">Samba-Server-FAQ.html</A> is the best starting point for
+information about server-side issues. Includes configuration tips and
+pointers for Samba on particular operating systems (with 40 to choose
+from...)
+</LI>
+<LI>
+<A HREF="Samba-Client-FAQ.html">Samba-Client-FAQ.html</A> is the best starting point for
+information about client-side issues, includes a list of all clients
+that are known to work with Samba.
+</LI>
+<LI>
+<A HREF="samba-man-index.html">manual pages</A> contains
+descriptions of and links to all the Samba manual pages, in Unix man and
+postscript format.
+</LI>
+<LI>
+<A HREF="samba-txt-index.html">samba-txt-index.html</A> has descriptions of and links to
+a large number of text files have been contributed to samba covering
+many topics. These are gradually being absorbed into the FAQs and HOWTOs
+but in the meantime you might find helpful answers here.
+</LI>
+<LI>
+</LI>
+</UL>
+</P>
+
+
+<HR>
+Previous
+<A HREF="Samba-meta-FAQ-2.html">Next</A>
+<A HREF="Samba-meta-FAQ.html#toc1">Table of Contents</A>
+</BODY>
+</HTML>
diff --git a/docs/faq/Samba-meta-FAQ-2.html b/docs/faq/Samba-meta-FAQ-2.html
new file mode 100644
index 00000000000..ac760380067
--- /dev/null
+++ b/docs/faq/Samba-meta-FAQ-2.html
@@ -0,0 +1,384 @@
+<HTML>
+<HEAD>
+<TITLE> Samba meta FAQ: General Information</TITLE>
+</HEAD>
+<BODY>
+<A HREF="Samba-meta-FAQ-1.html">Previous</A>
+<A HREF="Samba-meta-FAQ-3.html">Next</A>
+<A HREF="Samba-meta-FAQ.html#toc2">Table of Contents</A>
+<HR>
+<H2><A NAME="s2">2. General Information</A></H2>
+
+<P>
+<A NAME="general_info"></A>
+</P>
+<P>All about Samba - what it is, how to get it, related sources of
+information, how to understand the numbering scheme, pizza
+details.</P>
+
+<H2><A NAME="ss2.1">2.1 What is Samba?</A></H2>
+
+<P>
+<A NAME="introduction"></A>
+</P>
+<P>Samba is a suite of programs which work together to allow clients to
+access to a server's filespace and printers via the SMB (Server Message
+Block) and CIFS (Common Internet Filesystem) protocols. Initially
+written for Unix, Samba now also runs on Netware, OS/2, VMS, StratOS and
+Amigas. Ports to BeOS and other operating systems are underway. Samba
+gives the capability for these operating systems to behave much like a
+LAN Server, Windows NT Server or Pathworks machine, only with added
+functionality and flexibility designed to make life easier for
+administrators. </P>
+<P>This means that using Samba you can share a server's disks and printers
+to many sorts of network clients, including Lan Manager, Windows for
+Workgroups, Windows NT, Linux, OS/2, and AIX. There is also a generic
+client program supplied as part of the Samba suite which gives a user on
+the server an ftp-like interface to access filespace and printers on any
+other SMB/CIFS servers.</P>
+<P>SMB has been implemented over many protocols, including XNS, NBT, IPX,
+NetBEUI and TCP/IP. Samba only uses TCP/IP. This is not likely to change
+although there have been some requests for NetBEUI support.</P>
+<P>Many users report that compared to other SMB implementations Samba is
+more stable, faster, and compatible with more clients. Administrators of
+some large installations say that Samba is the only SMB server available
+which will scale to many tens of thousands of users without crashing.
+The easy way to test these claims is to download it and try it for
+yourself!</P>
+<P>The suite is supplied with full source code under the
+<A HREF="../COPYING">GNU Public License</A>. The GPL means that you can
+use Samba for whatever purpose you wish (including changing the source
+or selling it for money) but under all circumstances the source code
+must be made freely available. A copy of the GPL must always be included
+in any copy of the package.</P>
+<P>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.</P>
+
+
+<H2><A NAME="ss2.2">2.2 What is the current version of Samba?</A></H2>
+
+<P>
+<A NAME="current_version"></A>
+</P>
+<P>At time of writing, the current version was 1.9.17. If you want to be
+sure check the bottom of the change-log file.
+<A HREF="ftp://samba.anu.edu.au/pub/samba/alpha/change-log">ftp://samba.anu.edu.au/pub/samba/alpha/change-log</A></P>
+<P>For more information see
+<A HREF="#version_nums">What do the version numbers mean?</A></P>
+
+
+<H2><A NAME="ss2.3">2.3 Where can I get it? </A></H2>
+
+<P>
+<A NAME="WhereFrom"></A>
+</P>
+<P>The Samba suite is available via anonymous ftp from samba.anu.edu.au and
+many
+<A HREF="../MIRRORS">mirror</A> sites. You will get much
+faster performance if you use a mirror site. The latest and greatest
+versions of the suite are in the directory:</P>
+<P>/pub/samba/</P>
+<P>Development (read "alpha") versions, which are NOT necessarily stable
+and which do NOT necessarily have accurate documentation, are available
+in the directory:</P>
+<P>/pub/samba/alpha</P>
+<P>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. Most Linux distributions, for example, do contain Samba
+binaries for that platform. The VMS, OS/2, Netware and Amiga and other
+ports typically have binaries made available.</P>
+<P>A special case is vendor-provided binary packages. Samba binaries and
+default configuration files are put into packages for a specific
+operating system. RedHat Linux and Sun Solaris (Sparc and x86) is
+already included, and others such as OS/2 may follow. All packages are
+in the directory:</P>
+<P>/pub/samba/Binary_Packages/"OS_Vendor"</P>
+
+
+<H2><A NAME="ss2.4">2.4 What do the version numbers mean?</A></H2>
+
+<P>
+<A NAME="version_nums"></A>
+</P>
+<P>It is not recommended that you run a version of Samba with the word
+"alpha" in its name unless you know what you are doing and are willing
+to do some debugging. Many, many people just get the latest
+recommended stable release version and are happy. If you are brave, by
+all means take the plunge and help with the testing and development -
+but don't install it on your departmental server. Samba is typically
+very stable and safe, and this is mostly due to the policy of many
+public releases.</P>
+<P>How the scheme works:</P>
+<P>
+<OL>
+<LI>When major changes are made the version number is increased. For
+example, the transition from 1.9.16 to 1.9.17. However, this version
+number will not appear immediately and people should continue to use
+1.9.15 for production systems (see next point.)
+</LI>
+<LI>Just after major changes are made the software is considered
+unstable, and a series of alpha releases are distributed, for example
+1.9.16alpha1. These are for testing by those who know what they are
+doing. The "alpha" in the filename will hopefully scare off those who
+are just looking for the latest version to install.
+</LI>
+<LI>When Andrew thinks that the alphas have stabilised to the point
+where he would recommend new users install it, he renames it to the
+same version number without the alpha, for example 1.9.17.
+</LI>
+<LI>Inevitably bugs are found in the "stable" releases and minor patch
+levels are released which give us the pXX series, for example 1.9.17p2.
+</LI>
+</OL>
+</P>
+<P>So the progression goes:</P>
+<P>
+<PRE>
+ 1.9.16p10 (production)
+ 1.9.16p11 (production)
+ 1.9.17alpha1 (test sites only)
+ :
+ 1.9.17alpha20 (test sites only)
+ 1.9.17 (production)
+ 1.9.17p1 (production)
+</PRE>
+</P>
+<P>The above system means that whenever someone looks at the samba ftp
+site they will be able to grab the highest numbered release without an
+alpha in the name and be sure of getting the current recommended
+version.</P>
+
+
+<H2><A NAME="ss2.5">2.5 Where can I go for further information?</A></H2>
+
+<P>
+<A NAME="more"></A>
+</P>
+<P>There are a number of places to look for more information on Samba,
+including:</P>
+<P>
+<UL>
+<LI>Two mailing lists devoted to discussion of Samba-related matters.
+See below for subscription information.
+</LI>
+<LI>The newsgroup comp.protocols.smb, which has a great deal of
+discussion about Samba.
+</LI>
+<LI>The WWW site 'SAMBA Web Pages' at
+<A HREF="http://samba.anu.edu.au/samba/">http://samba.anu.edu.au/samba/</A> includes:
+
+<UL>
+<LI>Links to man pages and documentation, including this FAQ</LI>
+<LI>A comprehensive survey of Samba users</LI>
+<LI>A searchable hypertext archive of the Samba mailing list</LI>
+<LI>Links to Samba source code, binaries, and mirrors of both</LI>
+<LI>This FAQ and the rest in its family</LI>
+</UL>
+
+</LI>
+</UL>
+</P>
+
+
+<H2><A NAME="ss2.6">2.6 How do I subscribe to the Samba Mailing Lists?</A></H2>
+
+<P>
+<A NAME="mailinglist"></A>
+</P>
+<P>Send email to
+<A HREF="mailto:listproc@samba.anu.edu.au">listproc@samba.anu.edu.au</A>. Make sure the subject line is blank,
+and include the following two lines in the body of the message:</P>
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+subscribe samba Firstname Lastname
+subscribe samba-announce Firstname Lastname
+</PRE>
+</CODE></BLOCKQUOTE>
+</P>
+<P>Obviously you should substitute YOUR first name for "Firstname" and
+YOUR last name for "Lastname"! Try not to send any signature, it
+sometimes confuses the list processor.</P>
+<P>The samba list is a digest list - every eight hours or so it sends 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. There are thousands of people on this list.</P>
+<P>If you stop being interested in Samba, please send another email to
+<A HREF="mailto:listproc@samba.anu.edu.au">listproc@samba.anu.edu.au</A>. Make sure the subject line is blank, and
+include the following two lines in the body of the message:</P>
+<P>
+<BLOCKQUOTE><CODE>
+<PRE>
+unsubscribe samba
+unsubscribe samba-announce
+</PRE>
+</CODE></BLOCKQUOTE>
+</P>
+<P>The <B>From:</B> line in your message <EM>MUST</EM> be the same
+address you used when you subscribed.</P>
+
+
+<H2><A NAME="ss2.7">2.7 Something's gone wrong - what should I do?</A></H2>
+
+<P>
+<A NAME="wrong"></A>
+</P>
+<P><B><F>#</F> *** IMPORTANT! *** <F>#</F></B></P>
+
+<P>DO NOT post messages on mailing lists or in newsgroups until you have
+carried out the first three steps given here!</P>
+<P>
+<OL>
+<LI> See if there are any likely looking entries in this FAQ!
+If you have just installed Samba, have you run through the checklist in
+<A HREF="ftp://samba.anu.edu.au/pub/samba/DIAGNOSIS.txt">DIAGNOSIS.txt</A>? It can save you a lot of time and effort.
+DIAGNOSIS.txt can also be found in the docs directory of the Samba
+distribution.
+</LI>
+<LI> Read the man pages for smbd, nmbd and smb.conf, looking for
+topics that relate to what you are trying to do.
+</LI>
+<LI> 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:".
+</LI>
+<LI> If you need urgent help and are willing to pay for it see
+<A HREF="#PaidSupport">Paid Support</A>.
+</LI>
+</OL>
+</P>
+<P>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. When you post be sure to include a good
+description of your environment and your problem.</P>
+<P>If you successfully solve a problem, please mail the FAQ maintainer a
+succinct description of the symptom, the problem and the solution, so
+that an explanation can be incorporated into the next version.</P>
+
+
+<H2><A NAME="ss2.8">2.8 How do I submit patches or bug reports?</A></H2>
+
+
+<P>If you make changes to the source code, <EM>please</EM> 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
+<A HREF="mailto:samba-bugs@samba.anu.edu.au">samba-bugs@samba.anu.edu.au</A>. Do not send patches to Andrew Tridgell or any
+other individual, they may be lost if you do.</P>
+<P>Patch format
+------------</P>
+<P>If you are sending a patch to fix a problem then please don't just use
+standard diff format. As an example, samba-bugs received this patch from
+someone:</P>
+<P>382a
+#endif
+..
+381a
+#if !defined(NEWS61)</P>
+<P>How are we supposed to work out what this does and where it goes? These
+sort of patches only work if we both have identical files in the first
+place. The Samba sources are constantly changing at the hands of multiple
+developers, so it doesn't work.</P>
+<P>Please use either context diffs or (even better) unified diffs. You
+get these using "diff -c4" or "diff -u". If you don't have a diff that
+can generate these then please send manualy commented patches to I
+know what is being changed and where. Most patches are applied by hand so
+the info must be clear.</P>
+<P>This is a basic guideline that will assist us with assessing your problem
+more efficiently :</P>
+<P>Machine Arch:
+Machine OS:
+OS Version:
+Kernel:</P>
+<P>Compiler:
+Libc Version:</P>
+<P>Samba Version:</P>
+<P>Network Layout (description):</P>
+<P>What else is on machine (services, etc):</P>
+<P>Some extras :</P>
+<P>
+<UL>
+<LI> what you did and what happened
+</LI>
+<LI> relevant parts of a debugging output file with debuglevel higher.
+If you can't find the relevant parts, please ask before mailing
+huge files.
+</LI>
+<LI> anything else you think is useful to trace down the bug
+</LI>
+</UL>
+</P>
+
+
+<H2><A NAME="ss2.9">2.9 What if I have an URGENT message for the developers?</A></H2>
+
+
+<P>If you have spotted something very serious and believe that it is
+important to contact the developers quickly send a message to
+samba-urgent@samba.anu.edu.au. This will be processed more quickly than
+mail to samba-bugs. Please think carefully before using this address. An
+example of its use might be to report a security hole.</P>
+<P>Examples of things <EM>not</EM> to send to samba-urgent include problems
+getting Samba to work at all and bugs that cannot potentially cause damage.</P>
+
+
+<H2><A NAME="ss2.10">2.10 What if I need paid-for support?</A></H2>
+
+<P>
+<A NAME="PaidSupport"></A>
+</P>
+<P>Samba has a large network of consultants who provide Samba support on a
+commercial basis. The list is included in the package in
+<A HREF="../Support.txt">../Support.txt</A>, and the latest version will always be on the main
+samba ftp site. Any company in the world can request that the samba team
+include their details in Support.txt so we can give no guarantee of
+their services.</P>
+
+
+<H2><A NAME="ss2.11">2.11 Pizza supply details</A></H2>
+
+<P>
+<A NAME="pizza"></A>
+
+Those who have registered in the Samba survey as "Pizza Factory" will
+already know this, but the rest may need some help. Andrew doesn't ask
+for payment, but he does appreciate it when people give him
+pizza. This calls for a little organisation when the pizza donor is
+twenty thousand kilometres away, but it has been done.</P>
+<P>
+<OL>
+<LI> Ring up your local branch of an international pizza chain
+and see if they honour their vouchers internationally. Pizza Hut do,
+which is how the entire Canberra Linux Users Group got to eat pizza
+one night, courtesy of someone in the US.
+</LI>
+<LI>Ring up a local pizza shop in Canberra and quote a credit
+card number for a certain amount, and tell them that Andrew will be
+collecting it (don't forget to tell him.) One kind soul from Germany
+did this.
+</LI>
+<LI>Purchase a pizza voucher from your local pizza shop that has
+no international affiliations and send it to Andrew. It is completely
+useless but he can hang it on the wall next to the one he already has
+from Germany :-)
+</LI>
+<LI>Air freight him a pizza with your favourite regional
+flavours. It will probably get stuck in customs or torn apart by
+hungry sniffer dogs but it will have been a noble gesture.
+</LI>
+</OL>
+</P>
+
+
+<HR>
+<A HREF="Samba-meta-FAQ-1.html">Previous</A>
+<A HREF="Samba-meta-FAQ-3.html">Next</A>
+<A HREF="Samba-meta-FAQ.html#toc2">Table of Contents</A>
+</BODY>
+</HTML>
diff --git a/docs/faq/Samba-meta-FAQ-3.html b/docs/faq/Samba-meta-FAQ-3.html
new file mode 100644
index 00000000000..63adff35f92
--- /dev/null
+++ b/docs/faq/Samba-meta-FAQ-3.html
@@ -0,0 +1,101 @@
+<HTML>
+<HEAD>
+<TITLE> Samba meta FAQ: About the CIFS and SMB Protocols</TITLE>
+</HEAD>
+<BODY>
+<A HREF="Samba-meta-FAQ-2.html">Previous</A>
+<A HREF="Samba-meta-FAQ-4.html">Next</A>
+<A HREF="Samba-meta-FAQ.html#toc3">Table of Contents</A>
+<HR>
+<H2><A NAME="s3">3. About the CIFS and SMB Protocols</A></H2>
+
+<P>
+<A NAME="CifsSmb"></A>
+</P>
+
+<H2><A NAME="ss3.1">3.1 What is the Server Message Block (SMB) Protocol?</A></H2>
+
+<P>SMB is a filesharing protocol that has had several maintainers and
+contributors over the years including Xerox, 3Com and most recently
+Microsoft. Names for this protocol include LAN Manager and Microsoft
+Networking. Parts of the specification has been made public at several
+versions including in an X/Open document, as listed at
+<A HREF="ftp://ftp.microsoft.com/developr/drg/CIFS/">ftp://ftp.microsoft.com/developr/drg/CIFS/</A>. No specification
+releases were made between 1992 and 1996, and during that period
+Microsoft became the SMB implementor with the largest market share.
+Microsoft developed the specification further for its products but for
+various reasons connected with developer's workload rather than market
+strategy did not make the changes public. This culminated with the
+"Windows NT 0.12" version released with NT 3.5 in 1995 which had significant
+improvements and bugs. Because Microsoft client systems are so popular,
+it is fair to say that what Microsoft with Windows affects all suppliers
+of SMB server products.</P>
+<P>From 1994 Andrew Tridgell began doing some serious work on his
+Smbserver (now Samba) product and with some helpers started to
+implement more and more of these protocols. Samba began to take
+a significant share of the SMB server market.</P>
+
+
+<H2><A NAME="ss3.2">3.2 What is the Common Internet Filesystem (CIFS)?</A></H2>
+
+<P>The initial pressure for Microsoft to document their current SMB
+implementation came from the Samba team, who kept coming across things
+on the wire that Microsoft either didn't know about or hadn't documented
+anywhere (even in the sourcecode to Windows NT.) Then Sun Microsystems
+came out with their WebNFS initiative, designed to replace FTP for file
+transfers on the Internet. There are many drawbacks to WebNFS (including
+its scope - it aims to replace HTTP as well!) but the concept was
+attractive. FTP is not very clever, and why should it be harder to get
+files from across the world than across the room? </P>
+<P>Some hasty revisions were made and an Internet Draft for the Common
+Internet Filesystem (CIFS) was released. Note that CIFS is not an
+Internet standard and is a very long way from becoming one, BUT the
+protocol specification is in the public domain and ongoing discussions
+concerning the spec take place on a public mailing list according to the
+rules of the Internet Engineering Task Force. For more information and
+pointers see
+<A HREF="http://samba.anu.edu.au/cifs/">http://samba.anu.edu.au/cifs/</A></P>
+<P>The following is taken from
+<A HREF="http://www.microsoft.com/intdev/cifs/">http://www.microsoft.com/intdev/cifs/</A></P>
+<P>
+<PRE>
+ CIFS defines a standard remote file system access protocol for use
+ over the Internet, enabling groups of users to work together and
+ share documents across the Internet or within their corporate
+ intranets. CIFS is an open, cross-platform technology based on the
+ native file-sharing protocols built into Microsoft® Windows® and
+ other popular PC operating systems, and supported on dozens of
+ other platforms, including UNIX®. With CIFS, millions of computer
+ users can open and share remote files on the Internet without having
+ to install new software or change the way they work.&quot;
+</PRE>
+</P>
+<P>If you consider CIFS as a backwardsly-compatible refinement of SMB that
+will work reasonably efficiently over the Internet you won't be too far
+wrong.</P>
+<P>The net effect is that Microsoft is now documenting large parts of their
+Windows NT fileserver protocols. The security concepts embodied in
+Windows NT are part of the specification, which is why Samba
+documentation often talks in terms of Windows NT. However there is no
+reason why a site shouldn't conduct all its file and printer sharing
+with CIFS and yet have no Microsoft products at all.</P>
+
+
+<H2><A NAME="ss3.3">3.3 What is Browsing? </A></H2>
+
+<P>The term "Browsing" causes a lot of confusion. It is the part of the
+SMB/CIFS protocol which allows for resource discovery. For example, in
+the Windows NT Explorer it is possible to see a "Network Neighbourhood"
+of computers in the same SMB workgroup. Clicking on the name of one of
+these machines brings up a list of file and printer resources for
+connecting to. In this way you can cruise the network, seeing what
+things are available. How this scales to the Internet is a subject for
+debate. Look at the CIFS list archives to see what the experts think.</P>
+
+
+<HR>
+<A HREF="Samba-meta-FAQ-2.html">Previous</A>
+<A HREF="Samba-meta-FAQ-4.html">Next</A>
+<A HREF="Samba-meta-FAQ.html#toc3">Table of Contents</A>
+</BODY>
+</HTML>
diff --git a/docs/faq/Samba-meta-FAQ-4.html b/docs/faq/Samba-meta-FAQ-4.html
new file mode 100644
index 00000000000..73a9eea8471
--- /dev/null
+++ b/docs/faq/Samba-meta-FAQ-4.html
@@ -0,0 +1,215 @@
+<HTML>
+<HEAD>
+<TITLE> Samba meta FAQ: Designing A SMB and CIFS Network</TITLE>
+</HEAD>
+<BODY>
+<A HREF="Samba-meta-FAQ-3.html">Previous</A>
+<A HREF="Samba-meta-FAQ-5.html">Next</A>
+<A HREF="Samba-meta-FAQ.html#toc4">Table of Contents</A>
+<HR>
+<H2><A NAME="s4">4. Designing A SMB and CIFS Network</A></H2>
+
+
+<P>The big issues for installing any network of LAN or WAN file and print
+servers are </P>
+<P>
+<UL>
+<LI>How and where usernames, passwords and other security information
+is stored
+</LI>
+<LI>What method can be used for locating the resources that users have
+permission to use
+</LI>
+<LI>What protocols the clients can converse with
+</LI>
+</UL>
+ </P>
+<P>If you buy Netware, Windows NT or just about any other LAN fileserver
+product you are expected to lock yourself into the product's preferred
+answers to these questions. This tendancy is restrictive and often very
+expensive for a site where there is only one kind of client or server,
+and for sites with a mixture of operating systems it often makes it
+impossible to share resources between some sets of users.</P>
+<P>The Samba philosophy is to make things as easy as possible for
+administators, which means allowing as many combinations of clients,
+servers, operating systems and protocols as possible.</P>
+
+<H2><A NAME="ss4.1">4.1 Workgroups, Domains, Authentication and Browsing</A></H2>
+
+
+<P>From the point of view of networking implementation, Domains and
+Workgroups are <EM>exactly</EM> the same, except for the client logon
+sequence. Some kind of distributed authentication database is associated
+with a domain (there are quite a few choices) and this adds so much
+flexibility that many people think of a domain as a completely different
+entity to a workgroup. From Samba's point of view a client connecting to
+a service presents an authentication token, and it if it is valid they
+have access. Samba does not care what mechanism was used to generate
+that token in the first place.</P>
+<P>The SMB client logging on to a domain has an expectation that every other
+server in the domain should accept the same authentication information.
+However the network browsing functionality of domains and workgroups is
+identical and is explained in
+<A HREF="../BROWSING.txt">../BROWSING.txt</A>.</P>
+<P>There are some implementation differences: Windows 95 can be a member of
+both a workgroup and a domain, but Windows NT cannot. Windows 95 also
+has the concept of an "alternative workgroup". Samba can only be a
+member of a single workgroup or domain, although this is due to change
+with a future version when nmbd will be split into two daemons, one for
+WINS and the other for browsing (
+<A HREF="../NetBIOS.txt">../NetBIOS.txt</A> explains
+what WINS is.)</P>
+
+<H3>Defining the Terms</H3>
+
+<P>
+<A NAME="BrowseAndDomainDefs"></A>
+</P>
+<P>
+<DL>
+
+<DT><B>Workgroup</B><DD><P>means a collection of machines that maintain a common
+browsing database containing information about their shared resources.
+They do not necessarily have any security information in common (if they
+do, it gets called a Domain.) The browsing database is dynamic, modified
+as servers come and go on the network and as resources are added or
+deleted. The term "browsing" refers to a user accessing the database via
+whatever interface the client provides, eg the OS/2 Workplace Shell or
+Windows 95 Explorer. SMB servers agree between themselves as to which
+ones will maintain the browsing database. Workgroups can be anywhere on
+a connected TCP/IP network, including on different subnets or even on
+the Interet. This is a very tricky part of SMB to implement.</P>
+
+<DT><B>Master Browsers</B><DD><P>are machines which holds the master browsing
+database for a workgroup or domain. There are two kinds of Master Browser:</P>
+<P>
+<UL>
+<LI> Domain Master Browser, which holds the master browsing
+information for an entire domain, which may well cross multiple TCP/IP
+subnets.
+</LI>
+<LI> Local Master Browser, which holds the master browsing database
+for a particular subnet and communicates with the Domain Master Browser
+to get information on other subnets.
+</LI>
+</UL>
+</P>
+<P>Subnets are differentiated because browsing is based on broadcasts, and
+broadcasts do not pass through routers. Subnets are not routed: while it
+is possible to have more than one subnet on a single network segment
+this is regarded as very bad practice.</P>
+<P>Master Browsers (both Domain and Local) are elected dynamically
+according to an algorithm which is supposed to take into account the
+machine's ability to sustain the browsing load. Samba can be configured
+to always act as a master browser, ie it always wins elections under all
+circumstances, even against systems such as a Windows NT Primary Domain
+Controller which themselves expect to win. </P>
+<P>There are also Backup Browsers which are promoted to Master Browsers in
+the event of a Master Browser disappearing from the network.</P>
+<P>Alternative terms include confusing variations such as "Browse Master",
+and "Master Browser" which we are trying to eliminate from the Samba
+documentation. </P>
+
+<DT><B>Domain Controller</B><DD><P>is a term which comes from the Microsoft and IBM
+etc implementation of the LAN Manager protocols. It is tied to
+authentication. There are other ways of doing domain authentication, but
+the Windows NT method has a large market share. The general issues are
+discussed in
+<A HREF="../DOMAIN.txt">../DOMAIN.txt</A> and a Windows NT-specific
+discussion is in
+<A HREF="../DOMAIN_CONTROL.txt">../DOMAIN_CONTROL.txt</A>.</P>
+
+</DL>
+</P>
+
+<H3>Sharelevel (Workgroup) Security Services</H3>
+
+<P>
+<A NAME="ShareModeSecurity"></A>
+</P>
+<P>With the Samba setting "security = SHARE", all shared resources
+information about what password is associated with them but only hints
+as to what usernames might be valid (the hint can be 'all users', in
+which case any username will work. This is usually a bad idea, but
+reflects both the initial implementations of SMB in the mid-80s and
+its reincarnation with Windows for Workgroups in 1992. The idea behind
+workgroup security was that small independant groups of people could
+share information on an ad-hoc basis without there being an
+authentication infrastructure present or requiring them to do more than
+fill in a dialogue box.</P>
+
+<H3>Authentication Domain Mode Services</H3>
+
+<P>
+<A NAME="DomainModeSecurity"></A>
+</P>
+<P>With the Samba settings "security = USER" or "security = SERVER"
+accesses to all resources are checked for username/password pair matches
+in a more rigorous manner. To the client, this has the effect of
+emulating a Microsoft Domain. The client is not concerned whether or not
+Samba looks up a Windows NT SAM or does it in some other way.</P>
+
+
+<H2><A NAME="ss4.2">4.2 Authentication Schemes</A></H2>
+
+
+<P>In the simple case authentication information is stored on a single
+server and the user types a password on connecting for the first time.
+However client operating systems often require a password before they
+can be used at all, and in addition users usually want access to more
+than one server. Asking users to remember many different passwords in
+different contexts just does not work. Some kind of distributed
+authentication database is needed. It must cope with password changes
+and provide for assigning groups of users the same level of access
+permissions. This is why Samba installations often choose to implement a
+Domain model straight away.</P>
+<P>Authentication decisions are some of the biggest in designing a network.
+Are you going to use a scheme native to the client operating system,
+native to the server operating system, or newly installed on both? A
+list of options relevant to Samba (ie that make sense in the context of
+the SMB protocol) follows. Any experiences with other setups would be
+appreciated. <F>refer to server FAQ for "passwd chat" passwd program
+password server etc etc...</F></P>
+
+<H3>NIS</H3>
+
+
+<P>For Windows 95, Windows for Workgroups and most other clients Samba can
+be a domain controller and share the password database via NIS
+transparently. Windows NT is different.
+<A HREF="http://www.dcs.qmw.ac.uk/~williams">Free NIS NT client</A></P>
+
+<H3>Kerberos</H3>
+
+
+<P>Kerberos for US users only:
+<A HREF="http://www.cygnus.com/product/unifying-security.html">Kerberos overview</A>
+<A HREF="http://www.cygnus.com/product/kerbnet-download.html">Download Kerberos</A></P>
+
+<H3>FTP</H3>
+
+
+<P>Other NT w/s logon hack via NT</P>
+
+<H3>Default Server Method</H3>
+
+
+
+<H3>Client-side Database Only</H3>
+
+
+
+
+<H2><A NAME="ss4.3">4.3 Post-Authentication: Netlogon, Logon Scripts, Profiles</A></H2>
+
+
+<P>See
+<A HREF="../DOMAIN.txt">../DOMAIN.txt</A></P>
+
+
+<HR>
+<A HREF="Samba-meta-FAQ-3.html">Previous</A>
+<A HREF="Samba-meta-FAQ-5.html">Next</A>
+<A HREF="Samba-meta-FAQ.html#toc4">Table of Contents</A>
+</BODY>
+</HTML>
diff --git a/docs/faq/Samba-meta-FAQ-5.html b/docs/faq/Samba-meta-FAQ-5.html
new file mode 100644
index 00000000000..ad528b0a975
--- /dev/null
+++ b/docs/faq/Samba-meta-FAQ-5.html
@@ -0,0 +1,30 @@
+<HTML>
+<HEAD>
+<TITLE> Samba meta FAQ: Cross-Protocol File Sharing</TITLE>
+</HEAD>
+<BODY>
+<A HREF="Samba-meta-FAQ-4.html">Previous</A>
+<A HREF="Samba-meta-FAQ-6.html">Next</A>
+<A HREF="Samba-meta-FAQ.html#toc5">Table of Contents</A>
+<HR>
+<H2><A NAME="s5">5. Cross-Protocol File Sharing</A></H2>
+
+
+<P>Samba is an important tool for...</P>
+<P>It is possible to...</P>
+<P>File protocol gateways...</P>
+<P>"Setting up a Linux File Server" http://vetrec.mit.edu/people/narf/linux.html</P>
+<P>Two free implementations of Appletalk for Unix are Netatalk,
+<A HREF="http://www.umich.edu/~rsug/netatalk/">http://www.umich.edu/~rsug/netatalk/</A>, and CAP,
+<A HREF="http://www.cs.mu.oz.au/appletalk/atalk.html">http://www.cs.mu.oz.au/appletalk/atalk.html</A>. What Samba offers MS
+Windows users, these packages offer to Macs. For more info on these
+packages, Samba, and Linux (and other UNIX-based systems) see
+<A HREF="http://www.eats.com/linux_mac_win.html">http://www.eats.com/linux_mac_win.html</A> 3.5) Sniffing your nework</P>
+
+
+<HR>
+<A HREF="Samba-meta-FAQ-4.html">Previous</A>
+<A HREF="Samba-meta-FAQ-6.html">Next</A>
+<A HREF="Samba-meta-FAQ.html#toc5">Table of Contents</A>
+</BODY>
+</HTML>
diff --git a/docs/faq/Samba-meta-FAQ-6.html b/docs/faq/Samba-meta-FAQ-6.html
new file mode 100644
index 00000000000..f8cd7817d69
--- /dev/null
+++ b/docs/faq/Samba-meta-FAQ-6.html
@@ -0,0 +1,30 @@
+<HTML>
+<HEAD>
+<TITLE> Samba meta FAQ: Miscellaneous</TITLE>
+</HEAD>
+<BODY>
+<A HREF="Samba-meta-FAQ-5.html">Previous</A>
+Next
+<A HREF="Samba-meta-FAQ.html#toc6">Table of Contents</A>
+<HR>
+<H2><A NAME="s6">6. Miscellaneous</A></H2>
+
+<P>
+<A NAME="miscellaneous"></A>
+</P>
+<H2><A NAME="ss6.1">6.1 Is Samba Year 2000 compliant?</A></H2>
+
+<P>
+<A NAME="Year2000Compliant"></A>
+
+The CIFS protocol that Samba implements
+negotiates times in various formats, all of which
+are able to cope with dates beyond 2000.</P>
+
+
+<HR>
+<A HREF="Samba-meta-FAQ-5.html">Previous</A>
+Next
+<A HREF="Samba-meta-FAQ.html#toc6">Table of Contents</A>
+</BODY>
+</HTML>
diff --git a/docs/faq/Samba-meta-FAQ.html b/docs/faq/Samba-meta-FAQ.html
new file mode 100644
index 00000000000..5a70808867b
--- /dev/null
+++ b/docs/faq/Samba-meta-FAQ.html
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<HTML>
+<HEAD>
+<TITLE> Samba meta FAQ</TITLE>
+</HEAD>
+<BODY>
+Previous
+<A HREF="Samba-meta-FAQ-1.html">Next</A>
+Table of Contents
+<HR>
+<H1> Samba meta FAQ</H1>
+
+<H2>Dan Shearer & Paul Blackman, <CODE>ictinus@samba.anu.edu.au</CODE></H2>v 0.3, 7 Oct '97
+<P><HR><EM> This is the meta-Frequently Asked Questions (FAQ) document
+for Samba, the free and very popular SMB and CIFS server product. It
+contains overview information for the Samba suite of programs, a
+quick-start guide, and pointers to all other Samba documentation. Other
+FAQs exist for specific client and server issues, and HOWTO documents
+for more extended topics to do with Samba software. Current to version
+Samba 1.9.17. Please send any corrections to the author. </EM><HR></P>
+<P>
+<H2><A NAME="toc1">1.</A> <A HREF="Samba-meta-FAQ-1.html">Quick Reference Guides to Samba Documentation</A></H2>
+<UL>
+<LI><A HREF="Samba-meta-FAQ-1.html#ss1.1">1.1 Samba for the Impatient</A>
+<LI><A HREF="Samba-meta-FAQ-1.html#ss1.2">1.2 All Samba Documentation</A>
+</UL>
+
+<P>
+<H2><A NAME="toc2">2.</A> <A HREF="Samba-meta-FAQ-2.html">General Information</A></H2>
+<UL>
+<LI><A HREF="Samba-meta-FAQ-2.html#ss2.1">2.1 What is Samba?</A>
+<LI><A HREF="Samba-meta-FAQ-2.html#ss2.2">2.2 What is the current version of Samba?</A>
+<LI><A HREF="Samba-meta-FAQ-2.html#ss2.3">2.3 Where can I get it? </A>
+<LI><A HREF="Samba-meta-FAQ-2.html#ss2.4">2.4 What do the version numbers mean?</A>
+<LI><A HREF="Samba-meta-FAQ-2.html#ss2.5">2.5 Where can I go for further information?</A>
+<LI><A HREF="Samba-meta-FAQ-2.html#ss2.6">2.6 How do I subscribe to the Samba Mailing Lists?</A>
+<LI><A HREF="Samba-meta-FAQ-2.html#ss2.7">2.7 Something's gone wrong - what should I do?</A>
+<LI><A HREF="Samba-meta-FAQ-2.html#ss2.8">2.8 How do I submit patches or bug reports?</A>
+<LI><A HREF="Samba-meta-FAQ-2.html#ss2.9">2.9 What if I have an URGENT message for the developers?</A>
+<LI><A HREF="Samba-meta-FAQ-2.html#ss2.10">2.10 What if I need paid-for support?</A>
+<LI><A HREF="Samba-meta-FAQ-2.html#ss2.11">2.11 Pizza supply details</A>
+</UL>
+
+<P>
+<H2><A NAME="toc3">3.</A> <A HREF="Samba-meta-FAQ-3.html">About the CIFS and SMB Protocols</A></H2>
+<UL>
+<LI><A HREF="Samba-meta-FAQ-3.html#ss3.1">3.1 What is the Server Message Block (SMB) Protocol?</A>
+<LI><A HREF="Samba-meta-FAQ-3.html#ss3.2">3.2 What is the Common Internet Filesystem (CIFS)?</A>
+<LI><A HREF="Samba-meta-FAQ-3.html#ss3.3">3.3 What is Browsing? </A>
+</UL>
+
+<P>
+<H2><A NAME="toc4">4.</A> <A HREF="Samba-meta-FAQ-4.html">Designing A SMB and CIFS Network</A></H2>
+<UL>
+<LI><A HREF="Samba-meta-FAQ-4.html#ss4.1">4.1 Workgroups, Domains, Authentication and Browsing</A>
+<LI><A HREF="Samba-meta-FAQ-4.html#ss4.2">4.2 Authentication Schemes</A>
+<LI><A HREF="Samba-meta-FAQ-4.html#ss4.3">4.3 Post-Authentication: Netlogon, Logon Scripts, Profiles</A>
+</UL>
+
+<P>
+<H2><A NAME="toc5">5.</A> <A HREF="Samba-meta-FAQ-5.html">Cross-Protocol File Sharing</A></H2>
+
+<P>
+<H2><A NAME="toc6">6.</A> <A HREF="Samba-meta-FAQ-6.html">Miscellaneous</A></H2>
+<UL>
+<LI><A HREF="Samba-meta-FAQ-6.html#ss6.1">6.1 Is Samba Year 2000 compliant?</A>
+</UL>
+
+
+<HR>
+Previous
+<A HREF="Samba-meta-FAQ-1.html">Next</A>
+Table of Contents
+</BODY>
+</HTML>
diff --git a/docs/faq/Samba-meta-FAQ.sgml b/docs/faq/Samba-meta-FAQ.sgml
new file mode 100644
index 00000000000..75038f19f53
--- /dev/null
+++ b/docs/faq/Samba-meta-FAQ.sgml
@@ -0,0 +1,771 @@
+<!doctype linuxdoc system> <!-- -*- SGML -*- -->
+<!--
+ v 0.1 23 Aug 1997 Dan Shearer
+ Original Samba-meta-FAQ.sgml from Paul's sambafaq.sgml
+ v 0.2 25 Aug 1997 Dan
+ v 0.3 7 Oct 1997 Paul
+ Changed samba.canberra refs to samba.anu.../samba/
+-->
+
+<article>
+
+<title> Samba meta FAQ
+
+<author>Dan Shearer & Paul Blackman, <tt>ictinus@samba.anu.edu.au</tt>
+
+<date>v 0.3, 7 Oct '97
+
+<abstract> This is the meta-Frequently Asked Questions (FAQ) document
+for Samba, the free and very popular SMB and CIFS server product. It
+contains overview information for the Samba suite of programs, a
+quick-start guide, and pointers to all other Samba documentation. Other
+FAQs exist for specific client and server issues, and HOWTO documents
+for more extended topics to do with Samba software. Current to version
+Samba 1.9.17. Please send any corrections to the author.
+</abstract>
+
+<toc>
+
+<sect> Quick Reference Guides to Samba Documentation<p><label id=quickref>
+
+We are endeavouring to provide links here to every major class of
+information about Samba or things related to Samba. We cannot list every
+document, but we are aiming for all documents to be at most two
+referrals from those listed here. This needs constant maintaining, so
+please send the author your feedback.
+
+<sect1> Samba for the Impatient<p><label id="impatient">
+
+You know you should read the documentation but can't wait to start? What
+you need to do then is follow the instructions in the following
+documents in the order given. This should be enough to get a fairly
+simple site going quickly. If you have any problems, refer back to this
+meta-FAQ and follow the links to find more reading material.
+
+<descrip>
+
+<label id="ImpGet"><tag/Getting Samba:/ The fastest way to get Samba
+going is and install it is to have an operating system for which the
+Samba team has put together an installation package. To see if your OS
+is included have a look at the directory
+/pub/samba/Binary_Packages/"OS_Vendor" on your nearest <url
+url="../MIRRORS" name="mirror site">. If it is included follow the
+installation instructions in the README file there and then do some <ref id="ImpTest"
+name="basic testing">. If you are not so fortunate, follow the normal <ref
+id="WhereFrom" name="download instructions"> and then continue with <ref
+id="ImpInst" name="building and installing Samba">.
+
+<label id="ImpInst"><tag/Building and Installing Samba:/ At the moment
+there are two kinds of Samba server installs besides the prepackaged
+binaries mentioned in the previous step. You need to decide if you have a <url url="../UNIX_INSTALL.txt"
+name="Unix or close relative"> or <url
+url="Samba-Server-FAQ.html#PortInfo" name="other supported operating system">.
+
+<label id="ImpTest"><tag/Basic Testing:/ Try to connect using the
+supplied smbclient command-line program. You need to know the IP
+hostname of your server. A service name must be defined in smb.conf, as
+given in the examples (under many operating systems if there is a
+[homes] service you can just use a valid username.) Then type
+<tt>
+ smbclient \\hostname\servicename
+</tt>
+Under most Unixes you will need to put the parameters within quotation
+marks. If this works, try connecting from one of the SMB clients you
+were planning to use with Samba.
+
+<label id="ImpDebug"><tag/Debug sequence:/ If you think you have completed the
+previous step and things aren't working properly work through
+<url url="../DIAGNOSIS.txt" name="the diagnosis recipe.">
+
+<label id="ImpExp"><tag/Exporting files to SMB clients:/ You should read the manual pages
+for smb.conf, but here is a <url url="Samba-Server-FAQ.html#Exporting"
+name="quick answer guide.">
+
+<label id="ImpControl"><tag/Controlling user access:/ the quickest and dirtiest way of sharing
+resources is to use <ref id="ShareModeSecurity" name="share level
+security."> If you want to spend more time and have a proper username
+and password database you must read the paragraph on <ref
+id="DomainModeSecurity" name="domain mode security."> If you want
+encryption (eg you are using Windows NT clients) follow the <url
+url="Samba-Server-FAQ.html#SMBEncryptionSteps" name="SMB encryption
+instructions.">
+
+<label id="ImpBrowse"><tag/Browsing:/ if you are happy to type in "\\samba-server\sharename"
+at the client end then do not read any further. Otherwise you need to
+understand the <ref id="BrowsingDefinitions" name="browsing terminology">
+and read <url url="Samba-Server-FAQ.html#NameBrowsing">.
+
+<label id="ImpPrint"><tag/Printing:/ See the <url url="Samba-Server-FAQ.html#Printing"
+name="printing quick answer guide.">
+
+</descrip>
+
+If you have got everything working to this point, you can expect Samba
+to be stable and secure: these are its greatest strengths. However Samba
+has a great deal to offer and to go further you must do some more
+reading. Speed and security optimisations, printer accounting, network
+logons, roving profiles, browsing across multiple subnets and so on are
+all covered either in this document or in those it refers to.
+
+<sect1> All Samba Documentation<p><label id=AllDocs>
+
+<itemize>
+
+<item> Meta-FAQ. This is the mother of all documents, and is the one you
+are reading now. The latest version is always at <url
+url="http://samba.anu.edu.au/[.....]"> but there is probably a much
+nearer <url url="../MIRRORS" name="mirror site"> which you should use
+instead.
+
+<item> <url url="Samba-Server-FAQ.html"> is the best starting point for
+information about server-side issues. Includes configuration tips and
+pointers for Samba on particular operating systems (with 40 to choose
+from...)
+
+<item> <url url="Samba-Client-FAQ.html"> is the best starting point for
+information about client-side issues, includes a list of all clients
+that are known to work with Samba.
+
+<item> <url url="samba-man-index.html" name="manual pages"> contains
+descriptions of and links to all the Samba manual pages, in Unix man and
+postscript format.
+
+<item> <url url="samba-txt-index.html"> has descriptions of and links to
+a large number of text files have been contributed to samba covering
+many topics. These are gradually being absorbed into the FAQs and HOWTOs
+but in the meantime you might find helpful answers here.
+
+<item>
+
+</itemize>
+
+<sect> General Information<p><label id="general_info">
+
+All about Samba - what it is, how to get it, related sources of
+information, how to understand the numbering scheme, pizza
+details.
+
+<sect1> What is Samba?<p><label id="introduction">
+
+Samba is a suite of programs which work together to allow clients to
+access to a server's filespace and printers via the SMB (Server Message
+Block) and CIFS (Common Internet Filesystem) protocols. Initially
+written for Unix, Samba now also runs on Netware, OS/2, VMS, StratOS and
+Amigas. Ports to BeOS and other operating systems are underway. Samba
+gives the capability for these operating systems to behave much like a
+LAN Server, Windows NT Server or Pathworks machine, only with added
+functionality and flexibility designed to make life easier for
+administrators.
+
+This means that using Samba you can share a server's disks and printers
+to many sorts of network clients, including Lan Manager, Windows for
+Workgroups, Windows NT, Linux, OS/2, and AIX. There is also a generic
+client program supplied as part of the Samba suite which gives a user on
+the server an ftp-like interface to access filespace and printers on any
+other SMB/CIFS servers.
+
+SMB has been implemented over many protocols, including XNS, NBT, IPX,
+NetBEUI and TCP/IP. Samba only uses TCP/IP. This is not likely to change
+although there have been some requests for NetBEUI support.
+
+Many users report that compared to other SMB implementations Samba is
+more stable, faster, and compatible with more clients. Administrators of
+some large installations say that Samba is the only SMB server available
+which will scale to many tens of thousands of users without crashing.
+The easy way to test these claims is to download it and try it for
+yourself!
+
+The suite is supplied with full source code under the <url
+url="../COPYING" name="GNU Public License">. The GPL means that you can
+use Samba for whatever purpose you wish (including changing the source
+or selling it for money) but under all circumstances the source code
+must be made freely available. A copy of the GPL must always be included
+in any copy of the package.
+
+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.
+
+<sect1> What is the current version of Samba?<p><label id="current_version">
+
+At time of writing, the current version was 1.9.17. If you want to be
+sure check the bottom of the change-log file. <url url="ftp://samba.anu.edu.au/pub/samba/alpha/change-log">
+
+For more information see <ref id="version_nums" name="What do the version numbers mean?">
+
+<sect1> Where can I get it? <p><label id="WhereFrom">
+
+The Samba suite is available via anonymous ftp from samba.anu.edu.au and
+many <url url="../MIRRORS" name="mirror"> sites. You will get much
+faster performance if you use a mirror site. 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. Most Linux distributions, for example, do contain Samba
+binaries for that platform. The VMS, OS/2, Netware and Amiga and other
+ports typically have binaries made available.
+
+A special case is vendor-provided binary packages. Samba binaries and
+default configuration files are put into packages for a specific
+operating system. RedHat Linux and Sun Solaris (Sparc and x86) is
+already included, and others such as OS/2 may follow. All packages are
+in the directory:
+
+/pub/samba/Binary_Packages/"OS_Vendor"
+
+<sect1>What do the version numbers mean?<p><label id="version_nums">
+
+It is not recommended that you run a version of Samba with the word
+"alpha" in its name unless you know what you are doing and are willing
+to do some debugging. Many, many people just get the latest
+recommended stable release version and are happy. If you are brave, by
+all means take the plunge and help with the testing and development -
+but don't install it on your departmental server. Samba is typically
+very stable and safe, and this is mostly due to the policy of many
+public releases.
+
+How the scheme works:
+
+<enum>
+
+<item>When major changes are made the version number is increased. For
+example, the transition from 1.9.16 to 1.9.17. However, this version
+number will not appear immediately and people should continue to use
+1.9.15 for production systems (see next point.)
+
+<item>Just after major changes are made the software is considered
+unstable, and a series of alpha releases are distributed, for example
+1.9.16alpha1. These are for testing by those who know what they are
+doing. The "alpha" in the filename will hopefully scare off those who
+are just looking for the latest version to install.
+
+<item>When Andrew thinks that the alphas have stabilised to the point
+where he would recommend new users install it, he renames it to the
+same version number without the alpha, for example 1.9.17.
+
+<item>Inevitably bugs are found in the "stable" releases and minor patch
+levels are released which give us the pXX series, for example 1.9.17p2.
+
+</enum>
+
+So the progression goes:
+
+<verb>
+ 1.9.16p10 (production)
+ 1.9.16p11 (production)
+ 1.9.17alpha1 (test sites only)
+ :
+ 1.9.17alpha20 (test sites only)
+ 1.9.17 (production)
+ 1.9.17p1 (production)
+</verb>
+
+The above system means that whenever someone looks at the samba ftp
+site they will be able to grab the highest numbered release without an
+alpha in the name and be sure of getting the current recommended
+version.
+
+<sect1> Where can I go for further information?<p><label id="more">
+
+There are a number of places to look for more information on Samba,
+including:
+
+<itemize>
+
+<item>Two mailing lists devoted to discussion of Samba-related matters.
+See below for subscription information.
+
+<item>The newsgroup comp.protocols.smb, which has a great deal of
+discussion about Samba.
+
+<item>The WWW site 'SAMBA Web Pages' at <url
+url="http://samba.anu.edu.au/samba/"> includes:
+
+ <itemize>
+ <item>Links to man pages and documentation, including this FAQ
+ <item>A comprehensive survey of Samba users
+ <item>A searchable hypertext archive of the Samba mailing list
+ <item>Links to Samba source code, binaries, and mirrors of both
+ <item>This FAQ and the rest in its family
+ </itemize>
+
+</itemize>
+
+<sect1>How do I subscribe to the Samba Mailing Lists?<p><label id="mailinglist">
+
+Send email to <htmlurl url="mailto:listproc@samba.anu.edu.au"
+name="listproc@samba.anu.edu.au">. Make sure the subject line is blank,
+and include the following two lines in the body of the message:
+
+<tscreen><verb>
+subscribe samba Firstname Lastname
+subscribe samba-announce Firstname Lastname
+</verb></tscreen>
+
+Obviously you should substitute YOUR first name for "Firstname" and
+YOUR last name for "Lastname"! Try not to send any signature, it
+sometimes confuses the list processor.
+
+The samba list is a digest list - every eight hours or so it sends 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. There are thousands of people on this list.
+
+If you stop being interested in Samba, please send another email to
+<htmlurl url="mailto:listproc@samba.anu.edu.au" name="listproc@samba.anu.edu.au">. Make sure the subject line is blank, and
+include the following two lines in the body of the message:
+
+<tscreen><verb>
+unsubscribe samba
+unsubscribe samba-announce
+</verb></tscreen>
+
+The <bf>From:</bf> line in your message <em>MUST</em> be the same
+address you used when you subscribed.
+
+<sect1> Something's gone wrong - what should I do?<p><label id="wrong">
+
+<bf>[#] *** IMPORTANT! *** [#]</bf>
+<p>
+
+DO NOT post messages on mailing lists or in newsgroups until you have
+carried out the first three steps given here!
+
+<enum> <item> See if there are any likely looking entries in this FAQ!
+If you have just installed Samba, have you run through the checklist in
+<url url="ftp://samba.anu.edu.au/pub/samba/DIAGNOSIS.txt"
+name="DIAGNOSIS.txt">? It can save you a lot of time and effort.
+DIAGNOSIS.txt can also be found in the docs directory of the Samba
+distribution.
+
+<item> Read the man pages for smbd, nmbd and smb.conf, looking for
+topics that relate to what you are trying to do.
+
+<item> 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:".
+
+<item> If you need urgent help and are willing to pay for it see
+<ref id="PaidSupport" name="Paid Support">.
+
+</enum>
+
+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. When you post be sure to include a good
+description of your environment and your problem.
+
+If you successfully solve a problem, please mail the FAQ maintainer a
+succinct description of the symptom, the problem and the solution, so
+that an explanation can be incorporated into the next version.
+
+<sect1> How do I submit patches or bug reports?<p>
+
+If you make changes to the source code, <em>please</em> 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 <htmlurl url="mailto:samba-bugs@samba.anu.edu.au" name="samba-bugs@samba.anu.edu.au">. Do not send patches to Andrew Tridgell or any
+other individual, they may be lost if you do.
+
+Patch format
+------------
+
+If you are sending a patch to fix a problem then please don't just use
+standard diff format. As an example, samba-bugs received this patch from
+someone:
+
+382a
+#endif
+..
+381a
+#if !defined(NEWS61)
+
+How are we supposed to work out what this does and where it goes? These
+sort of patches only work if we both have identical files in the first
+place. The Samba sources are constantly changing at the hands of multiple
+developers, so it doesn't work.
+
+Please use either context diffs or (even better) unified diffs. You
+get these using "diff -c4" or "diff -u". If you don't have a diff that
+can generate these then please send manualy commented patches to I
+know what is being changed and where. Most patches are applied by hand so
+the info must be clear.
+
+This is a basic guideline that will assist us with assessing your problem
+more efficiently :
+
+Machine Arch:
+Machine OS:
+OS Version:
+Kernel:
+
+Compiler:
+Libc Version:
+
+Samba Version:
+
+Network Layout (description):
+
+What else is on machine (services, etc):
+
+Some extras :
+
+<itemize>
+
+<item> what you did and what happened
+
+<item> relevant parts of a debugging output file with debuglevel higher.
+ If you can't find the relevant parts, please ask before mailing
+ huge files.
+
+<item> anything else you think is useful to trace down the bug
+
+</itemize>
+
+<sect1> What if I have an URGENT message for the developers?<p>
+
+If you have spotted something very serious and believe that it is
+important to contact the developers quickly send a message to
+samba-urgent@samba.anu.edu.au. This will be processed more quickly than
+mail to samba-bugs. Please think carefully before using this address. An
+example of its use might be to report a security hole.
+
+Examples of things <em>not</em> to send to samba-urgent include problems
+getting Samba to work at all and bugs that cannot potentially cause damage.
+
+<sect1> What if I need paid-for support?<p><label id=PaidSupport>
+
+Samba has a large network of consultants who provide Samba support on a
+commercial basis. The list is included in the package in <url
+url="../Support.txt">, and the latest version will always be on the main
+samba ftp site. Any company in the world can request that the samba team
+include their details in Support.txt so we can give no guarantee of
+their services.
+
+<sect1> Pizza supply details<p><label id="pizza">
+Those who have registered in the Samba survey as "Pizza Factory" will
+already know this, but the rest may need some help. Andrew doesn't ask
+for payment, but he does appreciate it when people give him
+pizza. This calls for a little organisation when the pizza donor is
+twenty thousand kilometres away, but it has been done.
+
+<enum>
+<item> Ring up your local branch of an international pizza chain
+and see if they honour their vouchers internationally. Pizza Hut do,
+which is how the entire Canberra Linux Users Group got to eat pizza
+one night, courtesy of someone in the US.
+
+<item>Ring up a local pizza shop in Canberra and quote a credit
+card number for a certain amount, and tell them that Andrew will be
+collecting it (don't forget to tell him.) One kind soul from Germany
+did this.
+
+<item>Purchase a pizza voucher from your local pizza shop that has
+no international affiliations and send it to Andrew. It is completely
+useless but he can hang it on the wall next to the one he already has
+from Germany :-)
+
+<item>Air freight him a pizza with your favourite regional
+flavours. It will probably get stuck in customs or torn apart by
+hungry sniffer dogs but it will have been a noble gesture.
+
+</enum>
+
+<sect>About the CIFS and SMB Protocols<p><label id="CifsSmb">
+
+<sect1> What is the Server Message Block (SMB) Protocol?<p>
+SMB is a filesharing protocol that has had several maintainers and
+contributors over the years including Xerox, 3Com and most recently
+Microsoft. Names for this protocol include LAN Manager and Microsoft
+Networking. Parts of the specification has been made public at several
+versions including in an X/Open document, as listed at
+<url url="ftp://ftp.microsoft.com/developr/drg/CIFS/">. No specification
+releases were made between 1992 and 1996, and during that period
+Microsoft became the SMB implementor with the largest market share.
+Microsoft developed the specification further for its products but for
+various reasons connected with developer's workload rather than market
+strategy did not make the changes public. This culminated with the
+"Windows NT 0.12" version released with NT 3.5 in 1995 which had significant
+improvements and bugs. Because Microsoft client systems are so popular,
+it is fair to say that what Microsoft with Windows affects all suppliers
+of SMB server products.
+
+From 1994 Andrew Tridgell began doing some serious work on his
+Smbserver (now Samba) product and with some helpers started to
+implement more and more of these protocols. Samba began to take
+a significant share of the SMB server market.
+
+<sect1> What is the Common Internet Filesystem (CIFS)?<p>
+The initial pressure for Microsoft to document their current SMB
+implementation came from the Samba team, who kept coming across things
+on the wire that Microsoft either didn't know about or hadn't documented
+anywhere (even in the sourcecode to Windows NT.) Then Sun Microsystems
+came out with their WebNFS initiative, designed to replace FTP for file
+transfers on the Internet. There are many drawbacks to WebNFS (including
+its scope - it aims to replace HTTP as well!) but the concept was
+attractive. FTP is not very clever, and why should it be harder to get
+files from across the world than across the room?
+
+Some hasty revisions were made and an Internet Draft for the Common
+Internet Filesystem (CIFS) was released. Note that CIFS is not an
+Internet standard and is a very long way from becoming one, BUT the
+protocol specification is in the public domain and ongoing discussions
+concerning the spec take place on a public mailing list according to the
+rules of the Internet Engineering Task Force. For more information and
+pointers see <url url="http://samba.anu.edu.au/cifs/">
+
+The following is taken from <url url="http://www.microsoft.com/intdev/cifs/">
+
+<verb>
+ CIFS defines a standard remote file system access protocol for use
+ over the Internet, enabling groups of users to work together and
+ share documents across the Internet or within their corporate
+ intranets. CIFS is an open, cross-platform technology based on the
+ native file-sharing protocols built into Microsoft® Windows® and
+ other popular PC operating systems, and supported on dozens of
+ other platforms, including UNIX®. With CIFS, millions of computer
+ users can open and share remote files on the Internet without having
+ to install new software or change the way they work."
+</verb>
+
+If you consider CIFS as a backwardsly-compatible refinement of SMB that
+will work reasonably efficiently over the Internet you won't be too far
+wrong.
+
+The net effect is that Microsoft is now documenting large parts of their
+Windows NT fileserver protocols. The security concepts embodied in
+Windows NT are part of the specification, which is why Samba
+documentation often talks in terms of Windows NT. However there is no
+reason why a site shouldn't conduct all its file and printer sharing
+with CIFS and yet have no Microsoft products at all.
+
+<sect1> What is Browsing? <p>
+The term "Browsing" causes a lot of confusion. It is the part of the
+SMB/CIFS protocol which allows for resource discovery. For example, in
+the Windows NT Explorer it is possible to see a "Network Neighbourhood"
+of computers in the same SMB workgroup. Clicking on the name of one of
+these machines brings up a list of file and printer resources for
+connecting to. In this way you can cruise the network, seeing what
+things are available. How this scales to the Internet is a subject for
+debate. Look at the CIFS list archives to see what the experts think.
+
+<sect>Designing A SMB and CIFS Network<p>
+
+The big issues for installing any network of LAN or WAN file and print
+servers are
+
+<itemize>
+
+<item>How and where usernames, passwords and other security information
+is stored
+
+<item>What method can be used for locating the resources that users have
+permission to use
+
+<item>What protocols the clients can converse with
+
+</itemize>
+
+If you buy Netware, Windows NT or just about any other LAN fileserver
+product you are expected to lock yourself into the product's preferred
+answers to these questions. This tendancy is restrictive and often very
+expensive for a site where there is only one kind of client or server,
+and for sites with a mixture of operating systems it often makes it
+impossible to share resources between some sets of users.
+
+The Samba philosophy is to make things as easy as possible for
+administators, which means allowing as many combinations of clients,
+servers, operating systems and protocols as possible.
+
+<sect1>Workgroups, Domains, Authentication and Browsing<p>
+
+From the point of view of networking implementation, Domains and
+Workgroups are <em>exactly</em> the same, except for the client logon
+sequence. Some kind of distributed authentication database is associated
+with a domain (there are quite a few choices) and this adds so much
+flexibility that many people think of a domain as a completely different
+entity to a workgroup. From Samba's point of view a client connecting to
+a service presents an authentication token, and it if it is valid they
+have access. Samba does not care what mechanism was used to generate
+that token in the first place.
+
+The SMB client logging on to a domain has an expectation that every other
+server in the domain should accept the same authentication information.
+However the network browsing functionality of domains and workgroups is
+identical and is explained in <url url="../BROWSING.txt">.
+
+There are some implementation differences: Windows 95 can be a member of
+both a workgroup and a domain, but Windows NT cannot. Windows 95 also
+has the concept of an "alternative workgroup". Samba can only be a
+member of a single workgroup or domain, although this is due to change
+with a future version when nmbd will be split into two daemons, one for
+WINS and the other for browsing (<url url="../NetBIOS.txt"> explains
+what WINS is.)
+
+<sect2> Defining the Terms<p><label id="BrowseAndDomainDefs">
+
+<descrip>
+
+<tag/Workgroup/ means a collection of machines that maintain a common
+browsing database containing information about their shared resources.
+They do not necessarily have any security information in common (if they
+do, it gets called a Domain.) The browsing database is dynamic, modified
+as servers come and go on the network and as resources are added or
+deleted. The term "browsing" refers to a user accessing the database via
+whatever interface the client provides, eg the OS/2 Workplace Shell or
+Windows 95 Explorer. SMB servers agree between themselves as to which
+ones will maintain the browsing database. Workgroups can be anywhere on
+a connected TCP/IP network, including on different subnets or even on
+the Interet. This is a very tricky part of SMB to implement.
+
+<tag/Master Browsers/ are machines which holds the master browsing
+database for a workgroup or domain. There are two kinds of Master Browser:
+
+<itemize>
+
+<item> Domain Master Browser, which holds the master browsing
+information for an entire domain, which may well cross multiple TCP/IP
+subnets.
+
+<item> Local Master Browser, which holds the master browsing database
+for a particular subnet and communicates with the Domain Master Browser
+to get information on other subnets.
+
+</itemize>
+
+Subnets are differentiated because browsing is based on broadcasts, and
+broadcasts do not pass through routers. Subnets are not routed: while it
+is possible to have more than one subnet on a single network segment
+this is regarded as very bad practice.
+
+Master Browsers (both Domain and Local) are elected dynamically
+according to an algorithm which is supposed to take into account the
+machine's ability to sustain the browsing load. Samba can be configured
+to always act as a master browser, ie it always wins elections under all
+circumstances, even against systems such as a Windows NT Primary Domain
+Controller which themselves expect to win.
+
+There are also Backup Browsers which are promoted to Master Browsers in
+the event of a Master Browser disappearing from the network.
+
+Alternative terms include confusing variations such as "Browse Master",
+and "Master Browser" which we are trying to eliminate from the Samba
+documentation.
+
+<tag/Domain Controller/ is a term which comes from the Microsoft and IBM
+etc implementation of the LAN Manager protocols. It is tied to
+authentication. There are other ways of doing domain authentication, but
+the Windows NT method has a large market share. The general issues are
+discussed in <url url="../DOMAIN.txt"> and a Windows NT-specific
+discussion is in <url url="../DOMAIN_CONTROL.txt">.
+
+</descrip>
+
+<sect2>Sharelevel (Workgroup) Security Services<p><label id="ShareModeSecurity">
+
+With the Samba setting "security = SHARE", all shared resources
+information about what password is associated with them but only hints
+as to what usernames might be valid (the hint can be 'all users', in
+which case any username will work. This is usually a bad idea, but
+reflects both the initial implementations of SMB in the mid-80s and
+its reincarnation with Windows for Workgroups in 1992. The idea behind
+workgroup security was that small independant groups of people could
+share information on an ad-hoc basis without there being an
+authentication infrastructure present or requiring them to do more than
+fill in a dialogue box.
+
+<sect2>Authentication Domain Mode Services<p><label id="DomainModeSecurity">
+
+With the Samba settings "security = USER" or "security = SERVER"
+accesses to all resources are checked for username/password pair matches
+in a more rigorous manner. To the client, this has the effect of
+emulating a Microsoft Domain. The client is not concerned whether or not
+Samba looks up a Windows NT SAM or does it in some other way.
+
+<sect1>Authentication Schemes<p>
+
+In the simple case authentication information is stored on a single
+server and the user types a password on connecting for the first time.
+However client operating systems often require a password before they
+can be used at all, and in addition users usually want access to more
+than one server. Asking users to remember many different passwords in
+different contexts just does not work. Some kind of distributed
+authentication database is needed. It must cope with password changes
+and provide for assigning groups of users the same level of access
+permissions. This is why Samba installations often choose to implement a
+Domain model straight away.
+
+Authentication decisions are some of the biggest in designing a network.
+Are you going to use a scheme native to the client operating system,
+native to the server operating system, or newly installed on both? A
+list of options relevant to Samba (ie that make sense in the context of
+the SMB protocol) follows. Any experiences with other setups would be
+appreciated. [refer to server FAQ for "passwd chat" passwd program
+password server etc etc...]
+
+<sect2>NIS<p>
+
+For Windows 95, Windows for Workgroups and most other clients Samba can
+be a domain controller and share the password database via NIS
+transparently. Windows NT is different.
+<url url="http://www.dcs.qmw.ac.uk/~williams" name="Free NIS NT client">
+
+<sect2>Kerberos<p>
+
+Kerberos for US users only:
+<url url="http://www.cygnus.com/product/unifying-security.html"
+name="Kerberos overview">
+<url url="http://www.cygnus.com/product/kerbnet-download.html"
+name="Download Kerberos">
+
+<sect2>FTP<p>
+
+Other NT w/s logon hack via NT
+
+<sect2>Default Server Method<p>
+
+<sect2>Client-side Database Only<p>
+
+<sect1>Post-Authentication: Netlogon, Logon Scripts, Profiles<p>
+
+See <url url="../DOMAIN.txt">
+
+<sect>Cross-Protocol File Sharing<p>
+
+Samba is an important tool for...
+
+It is possible to...
+
+File protocol gateways...
+
+"Setting up a Linux File Server" http://vetrec.mit.edu/people/narf/linux.html
+
+Two free implementations of Appletalk for Unix are Netatalk, <url
+url="http://www.umich.edu/~rsug/netatalk/">, and CAP, <url
+url="http://www.cs.mu.oz.au/appletalk/atalk.html">. What Samba offers MS
+Windows users, these packages offer to Macs. For more info on these
+packages, Samba, and Linux (and other UNIX-based systems) see <url
+url="http://www.eats.com/linux_mac_win.html"> 3.5) Sniffing your nework
+
+
+<sect>Miscellaneous<p><label id="miscellaneous">
+<sect1>Is Samba Year 2000 compliant?<p><label id="Year2000Compliant">
+The CIFS protocol that Samba implements
+negotiates times in various formats, all of which
+are able to cope with dates beyond 2000.
+
+</article>
diff --git a/docs/faq/Samba-meta-FAQ.txt b/docs/faq/Samba-meta-FAQ.txt
new file mode 100644
index 00000000000..65d9a57ff62
--- /dev/null
+++ b/docs/faq/Samba-meta-FAQ.txt
@@ -0,0 +1,924 @@
+ Samba meta FAQ
+ Dan Shearer & Paul Blackman, ictinus@samba.anu.edu.au
+ v 0.3, 7 Oct '97
+
+ This is the meta-Frequently Asked Questions (FAQ) document for Samba,
+ the free and very popular SMB and CIFS server product. It contains
+ overview information for the Samba suite of programs, a quick-start
+ guide, and pointers to all other Samba documentation. Other FAQs exist
+ for specific client and server issues, and HOWTO documents for more
+ extended topics to do with Samba software. Current to version Samba
+ 1.9.17. Please send any corrections to the author.
+ ______________________________________________________________________
+
+ Table of Contents:
+
+ 1. Quick Reference Guides to Samba Documentation
+
+ 1.1. Samba for the Impatient
+
+ 1.2. All Samba Documentation
+
+ 2. General Information
+
+ 2.1. What is Samba?
+
+ 2.2. What is the current version of Samba?
+
+ 2.3. Where can I get it?
+
+ 2.4. What do the version numbers mean?
+
+ 2.5. Where can I go for further information?
+
+ 2.6. How do I subscribe to the Samba Mailing Lists?
+
+ 2.7. Something's gone wrong - what should I do?
+
+ 2.8. How do I submit patches or bug reports?
+
+ 2.9. What if I have an URGENT message for the developers?
+
+ 2.10. What if I need paid-for support?
+
+ 2.11. Pizza supply details
+
+ 3. About the CIFS and SMB Protocols
+
+ 3.1. What is the Server Message Block (SMB) Protocol?
+
+ 3.2. What is the Common Internet Filesystem (CIFS)?
+
+ 3.3. What is Browsing?
+
+ 4. Designing A SMB and CIFS Network
+
+ 4.1. Workgroups, Domains, Authentication and Browsing
+
+ 4.1.1. Defining the Terms
+
+ 4.1.2. Sharelevel (Workgroup) Security Services
+
+ 4.1.3. Authentication Domain Mode Services
+
+ 4.2. Authentication Schemes
+
+
+ 4.2.1. NIS
+
+ 4.2.2. Kerberos
+
+ 4.2.3. FTP
+
+ 4.2.4. Default Server Method
+
+ 4.2.5. Client-side Database Only
+
+ 4.3. Post-Authentication: Netlogon, Logon Scripts, Profiles
+
+ 5. Cross-Protocol File Sharing
+
+ 6. Miscellaneous
+
+ 6.1. Is Samba Year 2000 compliant?
+ ______________________________________________________________________
+
+ 11.. QQuuiicckk RReeffeerreennccee GGuuiiddeess ttoo SSaammbbaa DDooccuummeennttaattiioonn
+
+
+ We are endeavouring to provide links here to every major class of
+ information about Samba or things related to Samba. We cannot list
+ every document, but we are aiming for all documents to be at most two
+ referrals from those listed here. This needs constant maintaining, so
+ please send the author your feedback.
+
+
+ 11..11.. SSaammbbaa ffoorr tthhee IImmppaattiieenntt
+
+
+ You know you should read the documentation but can't wait to start?
+ What you need to do then is follow the instructions in the following
+ documents in the order given. This should be enough to get a fairly
+ simple site going quickly. If you have any problems, refer back to
+ this meta-FAQ and follow the links to find more reading material.
+
+
+
+ GGeettttiinngg SSaammbbaa::
+ The fastest way to get Samba going is and install it is to have
+ an operating system for which the Samba team has put together an
+ installation package. To see if your OS is included have a look
+ at the directory /pub/samba/Binary_Packages/"OS_Vendor" on your
+ nearest mirror site <../MIRRORS>. If it is included follow the
+ installation instructions in the README file there and then do
+ some ``basic testing''. If you are not so fortunate, follow the
+ normal ``download instructions'' and then continue with
+ ``building and installing Samba''.
+
+
+ BBuuiillddiinngg aanndd IInnssttaalllliinngg SSaammbbaa::
+ At the moment there are two kinds of Samba server installs
+ besides the prepackaged binaries mentioned in the previous step.
+ You need to decide if you have a Unix or close relative
+ <../UNIX_INSTALL.txt> or other supported operating system
+ <Samba-Server-FAQ.html#PortInfo>.
+
+
+ BBaassiicc TTeessttiinngg::
+ Try to connect using the supplied smbclient command-line
+ program. You need to know the IP hostname of your server. A
+ service name must be defined in smb.conf, as given in the
+ examples (under many operating systems if there is a homes
+ service you can just use a valid username.) Then type smbclient
+ \hostnamevicename Under most Unixes you will need to put the
+ parameters within quotation marks. If this works, try connecting
+ from one of the SMB clients you were planning to use with Samba.
+
+
+ DDeebbuugg sseeqquueennccee::
+ If you think you have completed the previous step and things
+ aren't working properly work through the diagnosis recipe.
+ <../DIAGNOSIS.txt>
+
+
+ EExxppoorrttiinngg ffiilleess ttoo SSMMBB cclliieennttss::
+ You should read the manual pages for smb.conf, but here is a
+ quick answer guide. <Samba-Server-FAQ.html#Exporting>
+
+
+ CCoonnttrroolllliinngg uusseerr aacccceessss::
+ the quickest and dirtiest way of sharing resources is to use
+ ``share level security.'' If you want to spend more time and
+ have a proper username and password database you must read the
+ paragraph on ``domain mode security.'' If you want encryption
+ (eg you are using Windows NT clients) follow the SMB encryption
+ instructions. <Samba-Server-FAQ.html#SMBEncryptionSteps>
+
+
+ BBrroowwssiinngg::
+ if you are happy to type in "\samba-serverrename" at the client
+ end then do not read any further. Otherwise you need to
+ understand the ``browsing terminology'' and read <Samba-Server-
+ FAQ.html#NameBrowsing>.
+
+
+ PPrriinnttiinngg::
+ See the printing quick answer guide. <Samba-Server-
+ FAQ.html#Printing>
+
+
+ If you have got everything working to this point, you can expect Samba
+ to be stable and secure: these are its greatest strengths. However
+ Samba has a great deal to offer and to go further you must do some
+ more reading. Speed and security optimisations, printer accounting,
+ network logons, roving profiles, browsing across multiple subnets and
+ so on are all covered either in this document or in those it refers
+ to.
+
+
+ 11..22.. AAllll SSaammbbaa DDooccuummeennttaattiioonn
+
+
+
+ +o Meta-FAQ. This is the mother of all documents, and is the one you
+ are reading now. The latest version is always at
+ <http://samba.anu.edu.au/[.....]> but there is probably a much
+ nearer mirror site <../MIRRORS> which you should use instead.
+
+ +o <Samba-Server-FAQ.html> is the best starting point for information
+ about server-side issues. Includes configuration tips and pointers
+ for Samba on particular operating systems (with 40 to choose
+ from...)
+
+ +o <Samba-Client-FAQ.html> is the best starting point for information
+ about client-side issues, includes a list of all clients that are
+ known to work with Samba.
+
+ +o manual pages <samba-man-index.html> contains descriptions of and
+ links to all the Samba manual pages, in Unix man and postscript
+ format.
+
+ +o <samba-txt-index.html> has descriptions of and links to a large
+ number of text files have been contributed to samba covering many
+ topics. These are gradually being absorbed into the FAQs and HOWTOs
+ but in the meantime you might find helpful answers here.
+
+ +o
+
+
+ 22.. GGeenneerraall IInnffoorrmmaattiioonn
+
+
+ All about Samba - what it is, how to get it, related sources of
+ information, how to understand the numbering scheme, pizza details.
+
+
+ 22..11.. WWhhaatt iiss SSaammbbaa??
+
+
+ Samba is a suite of programs which work together to allow clients to
+ access to a server's filespace and printers via the SMB (Server
+ Message Block) and CIFS (Common Internet Filesystem) protocols.
+ Initially written for Unix, Samba now also runs on Netware, OS/2, VMS,
+ StratOS and Amigas. Ports to BeOS and other operating systems are
+ underway. Samba gives the capability for these operating systems to
+ behave much like a LAN Server, Windows NT Server or Pathworks machine,
+ only with added functionality and flexibility designed to make life
+ easier for administrators.
+
+ This means that using Samba you can share a server's disks and
+ printers to many sorts of network clients, including Lan Manager,
+ Windows for Workgroups, Windows NT, Linux, OS/2, and AIX. There is
+ also a generic client program supplied as part of the Samba suite
+ which gives a user on the server an ftp-like interface to access
+ filespace and printers on any other SMB/CIFS servers.
+
+ SMB has been implemented over many protocols, including XNS, NBT, IPX,
+ NetBEUI and TCP/IP. Samba only uses TCP/IP. This is not likely to
+ change although there have been some requests for NetBEUI support.
+
+ Many users report that compared to other SMB implementations Samba is
+ more stable, faster, and compatible with more clients. Administrators
+ of some large installations say that Samba is the only SMB server
+ available which will scale to many tens of thousands of users without
+ crashing. The easy way to test these claims is to download it and try
+ it for yourself!
+
+ The suite is supplied with full source code under the GNU Public
+ License <../COPYING>. The GPL means that you can use Samba for
+ whatever purpose you wish (including changing the source or selling it
+ for money) but under all circumstances the source code must be made
+ freely available. A copy of the GPL must always be included in any
+ copy of the package.
+
+ 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.
+
+
+ 22..22.. WWhhaatt iiss tthhee ccuurrrreenntt vveerrssiioonn ooff SSaammbbaa??
+
+
+ At time of writing, the current version was 1.9.17. If you want to be
+ sure check the bottom of the change-log file.
+ <ftp://samba.anu.edu.au/pub/samba/alpha/change-log>
+ For more information see ``What do the version numbers mean?''
+
+
+ 22..33.. WWhheerree ccaann II ggeett iitt??
+
+
+ The Samba suite is available via anonymous ftp from samba.anu.edu.au
+ and many mirror <../MIRRORS> sites. You will get much faster
+ performance if you use a mirror site. 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. Most Linux distributions, for example, do contain Samba
+ binaries for that platform. The VMS, OS/2, Netware and Amiga and other
+ ports typically have binaries made available.
+
+ A special case is vendor-provided binary packages. Samba binaries and
+ default configuration files are put into packages for a specific
+ operating system. RedHat Linux and Sun Solaris (Sparc and x86) is
+ already included, and others such as OS/2 may follow. All packages are
+ in the directory:
+
+ /pub/samba/Binary_Packages/"OS_Vendor"
+
+
+ 22..44.. WWhhaatt ddoo tthhee vveerrssiioonn nnuummbbeerrss mmeeaann??
+
+
+ It is not recommended that you run a version of Samba with the word
+ "alpha" in its name unless you know what you are doing and are willing
+ to do some debugging. Many, many people just get the latest
+ recommended stable release version and are happy. If you are brave, by
+ all means take the plunge and help with the testing and development -
+ but don't install it on your departmental server. Samba is typically
+ very stable and safe, and this is mostly due to the policy of many
+ public releases.
+
+ How the scheme works:
+
+
+ 1. When major changes are made the version number is increased. For
+ example, the transition from 1.9.16 to 1.9.17. However, this
+ version number will not appear immediately and people should
+ continue to use 1.9.15 for production systems (see next point.)
+
+ 2. Just after major changes are made the software is considered
+ unstable, and a series of alpha releases are distributed, for
+ example 1.9.16alpha1. These are for testing by those who know what
+ they are doing. The "alpha" in the filename will hopefully scare
+ off those who are just looking for the latest version to install.
+
+ 3. When Andrew thinks that the alphas have stabilised to the point
+ where he would recommend new users install it, he renames it to the
+ same version number without the alpha, for example 1.9.17.
+
+ 4. Inevitably bugs are found in the "stable" releases and minor patch
+ levels are released which give us the pXX series, for example
+ 1.9.17p2.
+
+ So the progression goes:
+
+
+ 1.9.16p10 (production)
+ 1.9.16p11 (production)
+ 1.9.17alpha1 (test sites only)
+ :
+ 1.9.17alpha20 (test sites only)
+ 1.9.17 (production)
+ 1.9.17p1 (production)
+
+
+
+ The above system means that whenever someone looks at the samba ftp
+ site they will be able to grab the highest numbered release without an
+ alpha in the name and be sure of getting the current recommended
+ version.
+
+
+ 22..55.. WWhheerree ccaann II ggoo ffoorr ffuurrtthheerr iinnffoorrmmaattiioonn??
+
+
+ There are a number of places to look for more information on Samba,
+ including:
+
+
+ +o Two mailing lists devoted to discussion of Samba-related matters.
+ See below for subscription information.
+
+ +o The newsgroup comp.protocols.smb, which has a great deal of
+ discussion about Samba.
+
+ +o The WWW site 'SAMBA Web Pages' at <http://samba.anu.edu.au/samba/>
+ includes:
+
+
+ +o Links to man pages and documentation, including this FAQ
+
+ +o A comprehensive survey of Samba users
+
+ +o A searchable hypertext archive of the Samba mailing list
+
+ +o Links to Samba source code, binaries, and mirrors of both
+
+ +o This FAQ and the rest in its family
+
+
+
+ 22..66.. HHooww ddoo II ssuubbssccrriibbee ttoo tthhee SSaammbbaa MMaaiilliinngg LLiissttss??
+
+
+ Send email to listproc@samba.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, it
+ sometimes confuses the list processor.
+
+ The samba list is a digest list - every eight hours or so it sends 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. There are thousands of people on this list.
+
+ If you stop being interested in Samba, please send another email to
+ listproc@samba.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 FFrroomm:: line in your message _M_U_S_T be the same address you used when
+ you subscribed.
+
+
+ 22..77.. SSoommeetthhiinngg''ss ggoonnee wwrroonngg -- wwhhaatt sshhoouulldd II ddoo??
+
+
+ ## ****** IIMMPPOORRTTAANNTT!! ****** ##
+
+
+ DO NOT post messages on mailing lists or in newsgroups until you have
+ carried out the first three steps given here!
+
+
+ 1. 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 <ftp://samba.anu.edu.au/pub/samba/DIAGNOSIS.txt>? It
+ can save you a lot of time and effort. DIAGNOSIS.txt can also be
+ found in the docs directory of the Samba distribution.
+
+ 2. Read the man pages for smbd, nmbd and smb.conf, looking for topics
+ that relate to what you are trying to do.
+
+ 3. 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:".
+
+ 4. If you need urgent help and are willing to pay for it see ``Paid
+ Support''.
+
+ 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. When you post be sure to include a
+ good description of your environment and your problem.
+
+ If you successfully solve a problem, please mail the FAQ maintainer a
+ succinct description of the symptom, the problem and the solution, so
+ that an explanation can be incorporated into the next version.
+
+
+
+
+ 22..88.. HHooww ddoo II ssuubbmmiitt ppaattcchheess oorr bbuugg rreeppoorrttss??
+
+
+ If you make changes to the source code, _p_l_e_a_s_e 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. Do not send patches to Andrew Tridgell
+ or any other individual, they may be lost if you do.
+
+ Patch format ------------
+
+ If you are sending a patch to fix a problem then please don't just use
+ standard diff format. As an example, samba-bugs received this patch
+ from someone:
+
+ 382a #endif 381a #if !defined(NEWS61)
+
+ How are we supposed to work out what this does and where it goes?
+ These sort of patches only work if we both have identical files in the
+ first place. The Samba sources are constantly changing at the hands of
+ multiple developers, so it doesn't work.
+
+ Please use either context diffs or (even better) unified diffs. You
+ get these using "diff -c4" or "diff -u". If you don't have a diff that
+ can generate these then please send manualy commented patches to I
+ know what is being changed and where. Most patches are applied by hand
+ so the info must be clear.
+
+ This is a basic guideline that will assist us with assessing your
+ problem more efficiently :
+
+ Machine Arch: Machine OS: OS Version: Kernel:
+
+ Compiler: Libc Version:
+
+ Samba Version:
+
+ Network Layout (description):
+
+ What else is on machine (services, etc):
+
+ Some extras :
+
+
+ +o what you did and what happened
+
+ +o relevant parts of a debugging output file with debuglevel higher.
+ If you can't find the relevant parts, please ask before mailing
+ huge files.
+
+ +o anything else you think is useful to trace down the bug
+
+
+ 22..99.. WWhhaatt iiff II hhaavvee aann UURRGGEENNTT mmeessssaaggee ffoorr tthhee ddeevveellooppeerrss??
+
+
+ If you have spotted something very serious and believe that it is
+ important to contact the developers quickly send a message to samba-
+ urgent@samba.anu.edu.au. This will be processed more quickly than mail
+ to samba-bugs. Please think carefully before using this address. An
+ example of its use might be to report a security hole.
+
+ Examples of things _n_o_t to send to samba-urgent include problems
+ getting Samba to work at all and bugs that cannot potentially cause
+ damage.
+
+ 22..1100.. WWhhaatt iiff II nneeeedd ppaaiidd--ffoorr ssuuppppoorrtt??
+
+
+ Samba has a large network of consultants who provide Samba support on
+ a commercial basis. The list is included in the package in
+ <../Support.txt>, and the latest version will always be on the main
+ samba ftp site. Any company in the world can request that the samba
+ team include their details in Support.txt so we can give no guarantee
+ of their services.
+
+
+ 22..1111.. PPiizzzzaa ssuuppppllyy ddeettaaiillss
+
+
+ Those who have registered in the Samba survey as "Pizza Factory" will
+ already know this, but the rest may need some help. Andrew doesn't ask
+ for payment, but he does appreciate it when people give him pizza.
+ This calls for a little organisation when the pizza donor is twenty
+ thousand kilometres away, but it has been done.
+
+
+ 1. Ring up your local branch of an international pizza chain and see
+ if they honour their vouchers internationally. Pizza Hut do, which
+ is how the entire Canberra Linux Users Group got to eat pizza one
+ night, courtesy of someone in the US.
+
+ 2. Ring up a local pizza shop in Canberra and quote a credit card
+ number for a certain amount, and tell them that Andrew will be
+ collecting it (don't forget to tell him.) One kind soul from
+ Germany did this.
+
+ 3. Purchase a pizza voucher from your local pizza shop that has no
+ international affiliations and send it to Andrew. It is completely
+ useless but he can hang it on the wall next to the one he already
+ has from Germany :-)
+
+ 4. Air freight him a pizza with your favourite regional flavours. It
+ will probably get stuck in customs or torn apart by hungry sniffer
+ dogs but it will have been a noble gesture.
+
+
+ 33.. AAbboouutt tthhee CCIIFFSS aanndd SSMMBB PPrroottooccoollss
+
+
+
+ 33..11.. WWhhaatt iiss tthhee SSeerrvveerr MMeessssaaggee BBlloocckk ((SSMMBB)) PPrroottooccooll??
+
+ SMB is a filesharing protocol that has had several maintainers and
+ contributors over the years including Xerox, 3Com and most recently
+ Microsoft. Names for this protocol include LAN Manager and Microsoft
+ Networking. Parts of the specification has been made public at several
+ versions including in an X/Open document, as listed at
+ <ftp://ftp.microsoft.com/developr/drg/CIFS/>. No specification
+ releases were made between 1992 and 1996, and during that period
+ Microsoft became the SMB implementor with the largest market share.
+ Microsoft developed the specification further for its products but for
+ various reasons connected with developer's workload rather than market
+ strategy did not make the changes public. This culminated with the
+ "Windows NT 0.12" version released with NT 3.5 in 1995 which had
+ significant improvements and bugs. Because Microsoft client systems
+ are so popular, it is fair to say that what Microsoft with Windows
+ affects all suppliers of SMB server products.
+
+ From 1994 Andrew Tridgell began doing some serious work on his
+ Smbserver (now Samba) product and with some helpers started to
+ implement more and more of these protocols. Samba began to take a
+ significant share of the SMB server market.
+
+
+ 33..22.. WWhhaatt iiss tthhee CCoommmmoonn IInntteerrnneett FFiilleessyysstteemm ((CCIIFFSS))??
+
+ The initial pressure for Microsoft to document their current SMB
+ implementation came from the Samba team, who kept coming across things
+ on the wire that Microsoft either didn't know about or hadn't
+ documented anywhere (even in the sourcecode to Windows NT.) Then Sun
+ Microsystems came out with their WebNFS initiative, designed to
+ replace FTP for file transfers on the Internet. There are many
+ drawbacks to WebNFS (including its scope - it aims to replace HTTP as
+ well!) but the concept was attractive. FTP is not very clever, and why
+ should it be harder to get files from across the world than across the
+ room?
+
+ Some hasty revisions were made and an Internet Draft for the Common
+ Internet Filesystem (CIFS) was released. Note that CIFS is not an
+ Internet standard and is a very long way from becoming one, BUT the
+ protocol specification is in the public domain and ongoing discussions
+ concerning the spec take place on a public mailing list according to
+ the rules of the Internet Engineering Task Force. For more information
+ and pointers see <http://samba.anu.edu.au/cifs/>
+
+ The following is taken from <http://www.microsoft.com/intdev/cifs/>
+
+
+ CIFS defines a standard remote file system access protocol for use
+ over the Internet, enabling groups of users to work together and
+ share documents across the Internet or within their corporate
+ intranets. CIFS is an open, cross-platform technology based on the
+ native file-sharing protocols built into Microsoft Windows and
+ other popular PC operating systems, and supported on dozens of
+ other platforms, including UNIX. With CIFS, millions of computer
+ users can open and share remote files on the Internet without having
+ to install new software or change the way they work."
+
+
+
+ If you consider CIFS as a backwardsly-compatible refinement of SMB
+ that will work reasonably efficiently over the Internet you won't be
+ too far wrong.
+
+ The net effect is that Microsoft is now documenting large parts of
+ their Windows NT fileserver protocols. The security concepts embodied
+ in Windows NT are part of the specification, which is why Samba
+ documentation often talks in terms of Windows NT. However there is no
+ reason why a site shouldn't conduct all its file and printer sharing
+ with CIFS and yet have no Microsoft products at all.
+
+
+ 33..33.. WWhhaatt iiss BBrroowwssiinngg??
+
+ The term "Browsing" causes a lot of confusion. It is the part of the
+ SMB/CIFS protocol which allows for resource discovery. For example, in
+ the Windows NT Explorer it is possible to see a "Network
+ Neighbourhood" of computers in the same SMB workgroup. Clicking on the
+ name of one of these machines brings up a list of file and printer
+ resources for connecting to. In this way you can cruise the network,
+ seeing what things are available. How this scales to the Internet is a
+ subject for debate. Look at the CIFS list archives to see what the
+ experts think.
+
+
+
+
+ 44.. DDeessiiggnniinngg AA SSMMBB aanndd CCIIFFSS NNeettwwoorrkk
+
+
+ The big issues for installing any network of LAN or WAN file and print
+ servers are
+
+
+ +o How and where usernames, passwords and other security information
+ is stored
+
+ +o What method can be used for locating the resources that users have
+ permission to use
+
+ +o What protocols the clients can converse with
+
+
+ If you buy Netware, Windows NT or just about any other LAN fileserver
+ product you are expected to lock yourself into the product's preferred
+ answers to these questions. This tendancy is restrictive and often
+ very expensive for a site where there is only one kind of client or
+ server, and for sites with a mixture of operating systems it often
+ makes it impossible to share resources between some sets of users.
+
+ The Samba philosophy is to make things as easy as possible for
+ administators, which means allowing as many combinations of clients,
+ servers, operating systems and protocols as possible.
+
+
+ 44..11.. WWoorrkkggrroouuppss,, DDoommaaiinnss,, AAuutthheennttiiccaattiioonn aanndd BBrroowwssiinngg
+
+
+ From the point of view of networking implementation, Domains and
+ Workgroups are _e_x_a_c_t_l_y the same, except for the client logon sequence.
+ Some kind of distributed authentication database is associated with a
+ domain (there are quite a few choices) and this adds so much
+ flexibility that many people think of a domain as a completely
+ different entity to a workgroup. From Samba's point of view a client
+ connecting to a service presents an authentication token, and it if it
+ is valid they have access. Samba does not care what mechanism was used
+ to generate that token in the first place.
+
+ The SMB client logging on to a domain has an expectation that every
+ other server in the domain should accept the same authentication
+ information. However the network browsing functionality of domains
+ and workgroups is identical and is explained in <../BROWSING.txt>.
+
+ There are some implementation differences: Windows 95 can be a member
+ of both a workgroup and a domain, but Windows NT cannot. Windows 95
+ also has the concept of an "alternative workgroup". Samba can only be
+ a member of a single workgroup or domain, although this is due to
+ change with a future version when nmbd will be split into two daemons,
+ one for WINS and the other for browsing ( <../NetBIOS.txt> explains
+ what WINS is.)
+
+
+ 44..11..11.. DDeeffiinniinngg tthhee TTeerrmmss
+
+
+
+
+ WWoorrkkggrroouupp
+ means a collection of machines that maintain a common browsing
+ database containing information about their shared resources.
+ They do not necessarily have any security information in common
+ (if they do, it gets called a Domain.) The browsing database is
+ dynamic, modified as servers come and go on the network and as
+ resources are added or deleted. The term "browsing" refers to a
+ user accessing the database via whatever interface the client
+ provides, eg the OS/2 Workplace Shell or Windows 95 Explorer.
+ SMB servers agree between themselves as to which ones will
+ maintain the browsing database. Workgroups can be anywhere on a
+ connected TCP/IP network, including on different subnets or even
+ on the Interet. This is a very tricky part of SMB to implement.
+
+
+ MMaasstteerr BBrroowwsseerrss
+ are machines which holds the master browsing database for a
+ workgroup or domain. There are two kinds of Master Browser:
+
+
+ +o Domain Master Browser, which holds the master browsing
+ information for an entire domain, which may well cross multiple
+ TCP/IP subnets.
+
+ +o Local Master Browser, which holds the master browsing database
+ for a particular subnet and communicates with the Domain Master
+ Browser to get information on other subnets.
+
+ Subnets are differentiated because browsing is based on
+ broadcasts, and broadcasts do not pass through routers. Subnets
+ are not routed: while it is possible to have more than one
+ subnet on a single network segment this is regarded as very bad
+ practice.
+
+ Master Browsers (both Domain and Local) are elected dynamically
+ according to an algorithm which is supposed to take into account
+ the machine's ability to sustain the browsing load. Samba can be
+ configured to always act as a master browser, ie it always wins
+ elections under all circumstances, even against systems such as
+ a Windows NT Primary Domain Controller which themselves expect
+ to win.
+
+ There are also Backup Browsers which are promoted to Master
+ Browsers in the event of a Master Browser disappearing from the
+ network.
+
+ Alternative terms include confusing variations such as "Browse
+ Master", and "Master Browser" which we are trying to eliminate
+ from the Samba documentation.
+
+
+ DDoommaaiinn CCoonnttrroolllleerr
+ is a term which comes from the Microsoft and IBM etc
+ implementation of the LAN Manager protocols. It is tied to
+ authentication. There are other ways of doing domain
+ authentication, but the Windows NT method has a large market
+ share. The general issues are discussed in <../DOMAIN.txt> and
+ a Windows NT-specific discussion is in <../DOMAIN_CONTROL.txt>.
+
+
+
+ 44..11..22.. SShhaarreelleevveell ((WWoorrkkggrroouupp)) SSeeccuurriittyy SSeerrvviicceess
+
+
+ With the Samba setting "security = SHARE", all shared resources
+ information about what password is associated with them but only hints
+ as to what usernames might be valid (the hint can be 'all users', in
+ which case any username will work. This is usually a bad idea, but
+ reflects both the initial implementations of SMB in the mid-80s and
+ its reincarnation with Windows for Workgroups in 1992. The idea behind
+ workgroup security was that small independant groups of people could
+ share information on an ad-hoc basis without there being an
+ authentication infrastructure present or requiring them to do more
+ than fill in a dialogue box.
+
+
+ 44..11..33.. AAuutthheennttiiccaattiioonn DDoommaaiinn MMooddee SSeerrvviicceess
+
+
+ With the Samba settings "security = USER" or "security = SERVER"
+ accesses to all resources are checked for username/password pair
+ matches in a more rigorous manner. To the client, this has the effect
+ of emulating a Microsoft Domain. The client is not concerned whether
+ or not Samba looks up a Windows NT SAM or does it in some other way.
+
+
+ 44..22.. AAuutthheennttiiccaattiioonn SScchheemmeess
+
+
+ In the simple case authentication information is stored on a single
+ server and the user types a password on connecting for the first time.
+ However client operating systems often require a password before they
+ can be used at all, and in addition users usually want access to more
+ than one server. Asking users to remember many different passwords in
+ different contexts just does not work. Some kind of distributed
+ authentication database is needed. It must cope with password changes
+ and provide for assigning groups of users the same level of access
+ permissions. This is why Samba installations often choose to implement
+ a Domain model straight away.
+
+ Authentication decisions are some of the biggest in designing a
+ network. Are you going to use a scheme native to the client operating
+ system, native to the server operating system, or newly installed on
+ both? A list of options relevant to Samba (ie that make sense in the
+ context of the SMB protocol) follows. Any experiences with other
+ setups would be appreciated. refer to server FAQ for "passwd chat"
+ passwd program password server etc etc...
+
+
+ 44..22..11.. NNIISS
+
+
+ For Windows 95, Windows for Workgroups and most other clients Samba
+ can be a domain controller and share the password database via NIS
+ transparently. Windows NT is different. Free NIS NT client
+ <http://www.dcs.qmw.ac.uk/~williams>
+
+
+ 44..22..22.. KKeerrbbeerrooss
+
+
+ Kerberos for US users only: Kerberos overview
+ <http://www.cygnus.com/product/unifying-security.html> Download
+ Kerberos <http://www.cygnus.com/product/kerbnet-download.html>
+
+
+ 44..22..33.. FFTTPP
+
+
+ Other NT w/s logon hack via NT
+
+
+ 44..22..44.. DDeeffaauulltt SSeerrvveerr MMeetthhoodd
+
+
+
+
+
+ 44..22..55.. CClliieenntt--ssiiddee DDaattaabbaassee OOnnllyy
+
+
+
+ 44..33.. PPoosstt--AAuutthheennttiiccaattiioonn:: NNeettllooggoonn,, LLooggoonn SSccrriippttss,, PPrrooffiilleess
+
+
+ See <../DOMAIN.txt>
+
+
+ 55.. CCrroossss--PPrroottooccooll FFiillee SShhaarriinngg
+
+
+ Samba is an important tool for...
+
+ It is possible to...
+
+ File protocol gateways...
+
+ "Setting up a Linux File Server"
+ http://vetrec.mit.edu/people/narf/linux.html
+
+ Two free implementations of Appletalk for Unix are Netatalk,
+ <http://www.umich.edu/~rsug/netatalk/>, and CAP,
+ <http://www.cs.mu.oz.au/appletalk/atalk.html>. What Samba offers MS
+ Windows users, these packages offer to Macs. For more info on these
+ packages, Samba, and Linux (and other UNIX-based systems) see
+ <http://www.eats.com/linux_mac_win.html> 3.5) Sniffing your nework
+
+
+
+ 66.. MMiisscceellllaanneeoouuss
+
+
+ 66..11.. IIss SSaammbbaa YYeeaarr 22000000 ccoommpplliiaanntt??
+
+
+ The CIFS protocol that Samba implements negotiates times in various
+ formats, all of which are able to cope with dates beyond 2000.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/faq/sambafaq-1.html b/docs/faq/sambafaq-1.html
new file mode 100644
index 00000000000..c010e50e011
--- /dev/null
+++ b/docs/faq/sambafaq-1.html
@@ -0,0 +1,392 @@
+<HTML>
+<HEAD>
+<TITLE> Samba FAQ: General Information</TITLE>
+</HEAD>
+<BODY>
+Previous
+<A HREF="sambafaq-2.html">Next</A>
+<A HREF="sambafaq.html#toc1">Table of Contents</A>
+<HR>
+<H2><A NAME="s1">1. General Information</A></H2>
+
+<P>
+<A NAME="general_info"></A>
+</P>
+<P>All about Samba - what it is, how to get it, related sources of
+information, how to understand the version numbering scheme, pizza
+details</P>
+
+<H2><A NAME="ss1.1">1.1 What is Samba? </A></H2>
+
+<P>
+<A NAME="introduction"></A>
+
+Samba is a suite of programs which work together to allow clients to
+access to a server's filespace and printers via the SMB (Server
+Message Block) protocol. Initially written for Unix, Samba now also
+runs on Netware, OS/2 and VMS.</P>
+<P>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.</P>
+<P>The components of the suite are (in summary):</P>
+<P>
+<UL>
+<LI><B>smbd</B>, the SMB server. This handles actual connections from clients, doing all the file, permission and username work</LI>
+<LI><B>nmbd</B>, the Netbios name server, which helps clients locate servers, doing the browsing work and managing domains as this capability is being built into Samba</LI>
+<LI><B>smbclient</B>, the Unix-hosted client program</LI>
+<LI><B>smbrun</B>, a little 'glue' program to help the server run external programs</LI>
+<LI><B>testprns</B>, a program to test server access to printers</LI>
+<LI><B>testparms</B>, a program to test the Samba configuration file for correctness</LI>
+<LI><B>smb.conf</B>, the Samba configuration file</LI>
+<LI><B>smbprint</B>, a sample script to allow a Unix host to use smbclient to print to an SMB server</LI>
+<LI><B>Documentation!</B> DON'T neglect to read it - you will save a great deal of time!</LI>
+</UL>
+</P>
+<P>The suite is supplied with full source (of course!) and is GPLed.</P>
+<P>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.</P>
+
+
+<H2><A NAME="ss1.2">1.2 What is the current version of Samba? </A></H2>
+
+<P>
+<A NAME="current_version"></A>
+
+At time of writing, the current version was 1.9.17. If you want to be
+sure check the bottom of the change-log file.
+<A HREF="ftp://samba.anu.edu.au/pub/samba/alpha/change-log">ftp://samba.anu.edu.au/pub/samba/alpha/change-log</A></P>
+<P>For more information see
+<A HREF="#version_nums">What do the version numbers mean?</A></P>
+
+
+<H2><A NAME="ss1.3">1.3 Where can I get it? </A></H2>
+
+<P>
+<A NAME="where"></A>
+
+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:</P>
+<P>/pub/samba/</P>
+<P>Development (read "alpha") versions, which are NOT necessarily stable
+and which do NOT necessarily have accurate documentation, are
+available in the directory:</P>
+<P>/pub/samba/alpha</P>
+<P>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.</P>
+
+
+<H2><A NAME="ss1.4">1.4 What do the version numbers mean? </A></H2>
+
+<P>
+<A NAME="version_nums"></A>
+
+It is not recommended that you run a version of Samba with the word
+"alpha" in its name unless you know what you are doing and are willing
+to do some debugging. Many, many people just get the latest
+recommended stable release version and are happy. If you are brave, by
+all means take the plunge and help with the testing and development -
+but don't install it on your departmental server. Samba is typically
+very stable and safe, and this is mostly due to the policy of many
+public releases.</P>
+<P>How the scheme works:
+<OL>
+<LI>When major changes are made the version number is increased. For
+example, the transition from 1.9.15 to 1.9.16. However, this version
+number will not appear immediately and people should continue to use
+1.9.15 for production systems (see next point.)
+</LI>
+<LI>Just after major changes are made the software is considered
+unstable, and a series of alpha releases are distributed, for example
+1.9.16alpha1. These are for testing by those who know what they are
+doing. The "alpha" in the filename will hopefully scare off those who
+are just looking for the latest version to install.
+</LI>
+<LI>When Andrew thinks that the alphas have stabilised to the point
+where he would recommend new users install it, he renames it to the
+same version number without the alpha, for example 1.9.16.
+</LI>
+<LI>Inevitably bugs are found in the "stable" releases and minor patch
+levels are released which give us the pXX series, for example 1.9.16p2.</LI>
+</OL>
+
+So the progression goes:
+<PRE>
+ 1.9.15p7 (production)
+ 1.9.15p8 (production)
+ 1.9.16alpha1 (test sites only)
+ :
+ 1.9.16alpha20 (test sites only)
+ 1.9.16 (production)
+ 1.9.16p1 (production)
+</PRE>
+
+The above system means that whenever someone looks at the samba ftp
+site they will be able to grab the highest numbered release without an
+alpha in the name and be sure of getting the current recommended
+version.</P>
+
+
+<H2><A NAME="ss1.5">1.5 What platforms are supported? </A></H2>
+
+<P>
+<A NAME="platforms"></A>
+
+Many different platforms have run Samba successfully. The platforms
+most widely used and thus best tested are Linux and SunOS.</P>
+<P>At time of writing, the Makefile claimed support for:
+<UL>
+<LI> A/UX 3.0</LI>
+<LI> AIX</LI>
+<LI> Altos Series 386/1000</LI>
+<LI> Amiga</LI>
+<LI> Apollo Domain/OS sr10.3</LI>
+<LI> BSDI </LI>
+<LI> B.O.S. (Bull Operating System)</LI>
+<LI> Cray, Unicos 8.0</LI>
+<LI> Convex</LI>
+<LI> DGUX. </LI>
+<LI> DNIX.</LI>
+<LI> FreeBSD</LI>
+<LI> HP-UX</LI>
+<LI> Intergraph. </LI>
+<LI> Linux with/without shadow passwords and quota</LI>
+<LI> LYNX 2.3.0</LI>
+<LI> MachTen (a unix like system for Macintoshes)</LI>
+<LI> Motorola 88xxx/9xx range of machines</LI>
+<LI> NetBSD</LI>
+<LI> NEXTSTEP Release 2.X, 3.0 and greater (including OPENSTEP for Mach).</LI>
+<LI> OS/2 using EMX 0.9b</LI>
+<LI> OSF1</LI>
+<LI> QNX 4.22</LI>
+<LI> RiscIX. </LI>
+<LI> RISCOs 5.0B</LI>
+<LI> SEQUENT. </LI>
+<LI> SCO (including: 3.2v2, European dist., OpenServer 5)</LI>
+<LI> SGI.</LI>
+<LI> SMP_DC.OSx v1.1-94c079 on Pyramid S series</LI>
+<LI> SONY NEWS, NEWS-OS (4.2.x and 6.1.x)</LI>
+<LI> SUNOS 4</LI>
+<LI> SUNOS 5.2, 5.3, and 5.4 (Solaris 2.2, 2.3, and '2.4 and later')</LI>
+<LI> Sunsoft ISC SVR3V4</LI>
+<LI> SVR4</LI>
+<LI> System V with some berkely extensions (Motorola 88k R32V3.2).</LI>
+<LI> ULTRIX.</LI>
+<LI> UNIXWARE</LI>
+<LI> UXP/DS</LI>
+</UL>
+</P>
+
+
+<H2><A NAME="ss1.6">1.6 How can I find out more about Samba? </A></H2>
+
+<P>
+<A NAME="more"></A>
+
+There are a number of places to look for more information on Samba, including:
+<UL>
+<LI>Two mailing lists devoted to discussion of Samba-related matters. </LI>
+<LI>The newsgroup, comp.protocols.smb, which has a great deal of discussion on Samba. </LI>
+<LI>The WWW site 'SAMBA Web Pages' at
+<A HREF="http://samba.edu.au/samba/">http://samba.edu.au/samba/</A> includes:
+<UL>
+<LI>Links to man pages and documentation, including this FAQ</LI>
+<LI>A comprehensive survey of Samba users.</LI>
+<LI>A searchable hypertext archive of the Samba mailing list.</LI>
+<LI>Links to Samba source code, binaries, and mirrors of both.</LI>
+</UL>
+</LI>
+<LI>The long list of topic documentation. These files can be found in the 'docs' directory of the Samba source, or at
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/">ftp://samba.anu.edu.au/pub/samba/docs/</A>
+<UL>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/Application_Serving.txt">Application_Serving.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/BROWSING.txt">BROWSING.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/BUGS.txt">BUGS.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/DIAGNOSIS.txt">DIAGNOSIS.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/DNIX.txt">DNIX.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/DOMAIN.txt">DOMAIN.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/DOMAIN_CONTROL.txt">CONTROL.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/ENCRYPTION.txt">ENCRYPTION.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/Faxing.txt">Faxing.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/GOTCHAS.txt">GOTCHAS.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/HINTS.txt">HINTS.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/INSTALL.sambatar">INSTALL.sambatar</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/INSTALL.txt">INSTALL.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/MIRRORS">MIRRORS</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/NetBIOS.txt">NetBIOS.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/OS2.txt">OS2.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/PROJECTS">PROJECTS</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/Passwords.txt">Passwords.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/Printing.txt">Printing.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/README.DCEDFS">README.DCEDFS</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/README.OS2">README.OS2</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/README.jis">README.jis</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/README.sambatar">README.sambatar</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/SCO.txt">SCO.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/SMBTAR.notes">SMBTAR.notes</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/Speed.txt">Speed.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/Support.txt">Support.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/THANKS">THANKS</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/Tracing.txt">Tracing.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/UNIX-SMB.txt">SMB.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/Warp.txt">Warp.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/WinNT.txt">WinNT.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/history">history</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/security_level.txt">level.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/wfw_slip.htm">slip.htm</A></LI>
+</UL>
+</LI>
+</UL>
+</P>
+
+
+<H2><A NAME="ss1.7">1.7 How do I subscribe to the Samba Mailing Lists?</A></H2>
+
+<P>
+<A NAME="mailinglist"></A>
+
+Send email to
+<A HREF="mailto:listproc@samba.anu.edu.au">listproc@samba.anu.edu.au</A>. Make sure the subject line is
+blank, and include the following two lines in the body of the message:
+<BLOCKQUOTE><CODE>
+<PRE>
+subscribe samba Firstname Lastname
+subscribe samba-announce Firstname Lastname
+</PRE>
+</CODE></BLOCKQUOTE>
+
+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.</P>
+<P>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.</P>
+<P>If you stop being interested in Samba, please send another email to
+<A HREF="mailto:listproc@samba.anu.edu.au">listproc@samba.anu.edu.au</A>. Make sure the subject line is blank, and
+include the following two lines in the body of the message:
+<BLOCKQUOTE><CODE>
+<PRE>
+unsubscribe samba
+unsubscribe samba-announce
+</PRE>
+</CODE></BLOCKQUOTE>
+
+The <B>From:</B> line in your message <EM>MUST</EM> be the same address you used when
+you subscribed.</P>
+
+
+<H2><A NAME="ss1.8">1.8 Something's gone wrong - what should I do? </A></H2>
+
+<P>
+<A NAME="wrong"></A>
+
+<B><F>#</F> *** IMPORTANT! *** <F>#</F></B></P>
+<P>DO NOT post messages on mailing lists or in newsgroups until you have
+carried out the first three steps given here!</P>
+<P>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
+<A HREF="ftp://samba.anu.edu.au/pub/samba/DIAGNOSIS.txt">DIAGNOSIS.txt</A>? It can save you a lot of time and effort.
+DIAGNOSIS.txt can also be found in the docs directory of the Samba distribution.</P>
+<P>Secondly, read the man pages for smbd, nmbd and smb.conf, looking for
+topics that relate to what you are trying to do.</P>
+<P>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:".</P>
+<P>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.</P>
+<P>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.</P>
+<P>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
+<A HREF="mailto:samba-bugs@samba.anu.edu.au">samba-bugs@samba.anu.edu.au</A>. Do not send patches to Andrew Tridgell or any
+other individual, they may be lost if you do.</P>
+
+
+<H2><A NAME="ss1.9">1.9 Pizza supply details </A></H2>
+
+<P>
+<A NAME="pizza"></A>
+
+Those who have registered in the Samba survey as "Pizza Factory" will
+already know this, but the rest may need some help. Andrew doesn't ask
+for payment, but he does appreciate it when people give him
+pizza. This calls for a little organisation when the pizza donor is
+twenty thousand kilometres away, but it has been done.</P>
+<P>Method 1: Ring up your local branch of an international pizza chain
+and see if they honour their vouchers internationally. Pizza Hut do,
+which is how the entire Canberra Linux Users Group got to eat pizza
+one night, courtesy of someone in the US</P>
+<P>Method 2: Ring up a local pizza shop in Canberra and quote a credit
+card number for a certain amount, and tell them that Andrew will be
+collecting it (don't forget to tell him.) One kind soul from Germany
+did this.</P>
+<P>Method 3: Purchase a pizza voucher from your local pizza shop that has
+no international affiliations and send it to Andrew. It is completely
+useless but he can hang it on the wall next to the one he already has
+from Germany :-)</P>
+<P>Method 4: Air freight him a pizza with your favourite regional
+flavours. It will probably get stuck in customs or torn apart by
+hungry sniffer dogs but it will have been a noble gesture.</P>
+
+
+<HR>
+Previous
+<A HREF="sambafaq-2.html">Next</A>
+<A HREF="sambafaq.html#toc1">Table of Contents</A>
+</BODY>
+</HTML>
diff --git a/docs/faq/sambafaq-2.html b/docs/faq/sambafaq-2.html
new file mode 100644
index 00000000000..b92a1e2fcd1
--- /dev/null
+++ b/docs/faq/sambafaq-2.html
@@ -0,0 +1,239 @@
+<HTML>
+<HEAD>
+<TITLE> Samba FAQ: Compiling and installing Samba on a Unix host</TITLE>
+</HEAD>
+<BODY>
+<A HREF="sambafaq-1.html">Previous</A>
+<A HREF="sambafaq-3.html">Next</A>
+<A HREF="sambafaq.html#toc2">Table of Contents</A>
+<HR>
+<H2><A NAME="s2">2. Compiling and installing Samba on a Unix host</A></H2>
+
+<P>
+<A NAME="unix_install"></A>
+</P>
+
+<H2><A NAME="ss2.1">2.1 I can't see the Samba server in any browse lists!</A></H2>
+
+<P>
+<A NAME="no_browse"></A>
+
+See
+<A HREF="ftp://samba.anu.edu.au/pub/samba/BROWSING.txt">BROWSING.txt</A>
+for more information on browsing. Browsing.txt can also be found
+in the docs directory of the Samba source.</P>
+<P>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:
+<BLOCKQUOTE><CODE>
+<PRE>
+ net use M: \\mary\fred
+</PRE>
+</CODE></BLOCKQUOTE>
+
+The details of how to do this and the specific syntax varies from
+client to client - check your client's documentation.</P>
+
+
+<H2><A NAME="ss2.2">2.2 Some files that I KNOW are on the server doesn't show up when I view the files from my client! </A></H2>
+
+<P>
+<A NAME="missing_files"></A>
+
+See the next question.</P>
+
+<H2><A NAME="ss2.3">2.3 Some files on the server show up with really wierd filenames when I view the files from my client! </A></H2>
+
+<P>
+<A NAME="strange_filenames"></A>
+
+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).</P>
+<P>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".</P>
+
+
+<H2><A NAME="ss2.4">2.4 My client reports "cannot locate specified computer" or similar</A></H2>
+
+<P>
+<A NAME="cant_see_server"></A>
+
+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.</P>
+<P>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.</P>
+<P>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.</P>
+<P>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.</P>
+<P>By the way, remember to REMOVE the hardcoded mapping before further
+tests :-) </P>
+
+
+<H2><A NAME="ss2.5">2.5 My client reports "cannot locate specified share name" or similar</A></H2>
+
+<P>
+<A NAME="cant_see_share"></A>
+
+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.</P>
+<P>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:</P>
+<P>
+<UL>
+<LI> Many clients cannot accept or use service names longer than eight characters.</LI>
+<LI> Many clients cannot accept or use service names containing spaces.</LI>
+<LI> Some servers (not Samba though) are case sensitive with service names.</LI>
+<LI> Some clients force service names into upper case.</LI>
+</UL>
+</P>
+
+
+<H2><A NAME="ss2.6">2.6 My client reports "cannot find domain controller", "cannot log on to the network" or similar </A></H2>
+
+<P>
+<A NAME="cant_see_net"></A>
+
+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
+<A HREF="mailto:samba-bugs@samba.anu.edu.au">samba-bugs@samba.anu.edu.au</A> !</P>
+<P>Seeing this message should not affect your ability to mount redirected
+disks and printers, which is really what all this is about.</P>
+<P>For many clients (including Windows for Workgroups and Lan Manager),
+setting the domain to STANDALONE at least gets rid of the message.</P>
+
+
+<H2><A NAME="ss2.7">2.7 Printing doesn't work :-(</A></H2>
+
+<P>
+<A NAME="no_printing"></A>
+
+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").</P>
+<P>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".</P>
+<P>Make sure that the user specified in the service is permitted to use
+the printer.</P>
+<P>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.</P>
+<P>If using WfWg then you need to set the default protocol to TCP/IP, not
+Netbeui. This is a WfWg bug.</P>
+<P>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.</P>
+
+
+<H2><A NAME="ss2.8">2.8 My programs install on the server OK, but refuse to work properly</A></H2>
+
+<P>
+<A NAME="programs_wont_run"></A>
+
+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.</P>
+<P>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 via email at
+<A HREF="mailto:samba-bugs@samba.anu.edu.au">samba-bugs@samba.anu.edu.au</A>.</P>
+
+
+<H2><A NAME="ss2.9">2.9 My "server string" doesn't seem to be recognised</A></H2>
+
+<P>
+<A NAME="bad_server_string"></A>
+
+OR My client reports the default setting, eg. "Samba 1.9.15p4", instead
+of what I have changed it to in the smb.conf file.</P>
+<P>You need to use the -C option in nmbd. The "server string" affects
+what smbd puts out and -C affects what nmbd puts out.</P>
+<P>Current versions of Samba (1.9.16 +) have combined these options into
+the "server string" field of smb.conf, -C for nmbd is now obsolete.</P>
+
+
+<H2><A NAME="ss2.10">2.10 My client reports "This server is not configured to list shared resources" </A></H2>
+
+<P>
+<A NAME="cant_list_shares"></A>
+
+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.</P>
+<P>See also 'guest account' in smb.conf man page.</P>
+
+
+<H2><A NAME="ss2.11">2.11 Log message "you appear to have a trapdoor uid system" </A></H2>
+
+<P>
+<A NAME="trapdoor_uid"></A>
+
+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.</P>
+<P>It might also mean that your OS has a trapdoor uid/gid system :-)</P>
+<P>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.</P>
+<P>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.</P>
+<P>Complain to your OS vendor and ask them to fix their system.</P>
+<P>Note: the reason why 65535 is a VERY bad choice of uid and gid is that
+it casts to -1 as a uid, and the setreuid() system call ignores (with
+no error) uid changes to -1. This means any daemon attempting to run
+as uid 65535 will actually run as root. This is not good!</P>
+
+
+<HR>
+<A HREF="sambafaq-1.html">Previous</A>
+<A HREF="sambafaq-3.html">Next</A>
+<A HREF="sambafaq.html#toc2">Table of Contents</A>
+</BODY>
+</HTML>
diff --git a/docs/faq/sambafaq-3.html b/docs/faq/sambafaq-3.html
new file mode 100644
index 00000000000..1b5dcf4d9aa
--- /dev/null
+++ b/docs/faq/sambafaq-3.html
@@ -0,0 +1,322 @@
+<HTML>
+<HEAD>
+<TITLE> Samba FAQ: Common client questions</TITLE>
+</HEAD>
+<BODY>
+<A HREF="sambafaq-2.html">Previous</A>
+<A HREF="sambafaq-4.html">Next</A>
+<A HREF="sambafaq.html#toc3">Table of Contents</A>
+<HR>
+<H2><A NAME="s3">3. Common client questions</A></H2>
+
+<P>
+<A NAME="client_questions"></A>
+</P>
+
+<H2><A NAME="ss3.1">3.1 Are there any Macintosh clients for Samba?</A></H2>
+
+<P>
+<A NAME="mac_clients"></A>
+
+Yes! Thursby now have a CIFS Client / Server called DAVE - see
+<A HREF="http://www.thursby.com/">http://www.thursby.com/</A>.
+They test it against Windows 95, Windows NT and samba for compatibility issues.
+At the time of writing, DAVE was at version 1.0.1. The 1.0.0 to 1.0.1 update is available
+as a free download from the Thursby web site (the speed of finder copies has
+been greatly enhanced, and there are bug-fixes included).</P>
+<P>Alternatives - There are two free implementations of AppleTalk for
+several kinds of UNIX machnes, and several more commercial ones.
+These products allow you to run file services and print services
+natively to Macintosh users, with no additional support required on
+the Macintosh. The two free omplementations are Netatalk,
+<A HREF="http://www.umich.edu/~rsug/netatalk/">http://www.umich.edu/~rsug/netatalk/</A>, and CAP,
+<A HREF="http://www.cs.mu.oz.au/appletalk/atalk.html">http://www.cs.mu.oz.au/appletalk/atalk.html</A>. What Samba offers
+MS Windows users, these packages offer to Macs. For more info on
+these packages, Samba, and Linux (and other UNIX-based systems)
+see
+<A HREF="http://www.eats.com/linux_mac_win.html">http://www.eats.com/linux_mac_win.html</A></P>
+
+
+<H2><A NAME="ss3.2">3.2 "Session request failed (131,130)" error</A></H2>
+
+<P>
+<A NAME="sess_req_fail"></A>
+
+The following answer is provided by John E. Miller:</P>
+<P>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.</P>
+<P>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...) <F>Note: It's under Control Panel | Network | TCP/IP | WINS
+Configuration</F> there's a little text entry field called something like
+'Scope ID'.</P>
+<P>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 <F>otherparms</F> in connecting to
+it.</P>
+
+
+<H2><A NAME="ss3.3">3.3 How do I synchronise my PC's clock with my Samba server? </A></H2>
+
+<P>
+<A NAME="synchronise_clock"></A>
+
+To syncronize your PC's clock with your Samba server:
+<UL>
+<LI> Copy timesync.pif to your windows directory</LI>
+<LI> timesync.pif can be found at:
+<A HREF="http://samba.anu.edu.au/samba/binaries/miscellaneous/timesync.pif">http://samba.anu.edu.au/samba/binaries/miscellaneous/timesync.pif</A></LI>
+<LI> Add timesync.pif to your 'Start Up' group/folder</LI>
+<LI> Open the properties dialog box for the program/icon</LI>
+<LI> Make sure the 'Run Minimized' option is set in program 'Properties'</LI>
+<LI> Change the command line section that reads <F>\\sambahost</F> to reflect the name of your server.</LI>
+<LI> Close the properties dialog box by choosing 'OK'</LI>
+</UL>
+
+Each time you start your computer (or login for Win95) your PC will
+synchronize its clock with your Samba server.</P>
+<P>Alternativley, if you clients support Domain Logons, you can setup Domain Logons with Samba
+- see:
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/BROWSING.txt">BROWSING.txt</A> *** for more information.</P>
+<P>Then add
+<BLOCKQUOTE><CODE>
+<PRE>
+NET TIME \\%L /SET /YES
+</PRE>
+</CODE></BLOCKQUOTE>
+
+as one of the lines in the logon script.</P>
+
+<H2><A NAME="ss3.4">3.4 Problems with WinDD, NTrigue, WinCenterPro etc</A></H2>
+
+<P>
+<A NAME="multiple_session_clients"></A>
+</P>
+<P>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).</P>
+<P>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?)</P>
+<P>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.</P>
+<P>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
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/security_level.txt">security_level.txt</A> in
+the docs for more info on share/user/server level security.</P>
+<P>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.</P>
+<P>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.</P>
+<P>Also note that you should not use the magic "homes" share name with
+products like these, as otherwise all users will end up with the same
+home directory. Use <F>\\server\username</F> instead.</P>
+
+
+<H2><A NAME="ss3.5">3.5 Problem with printers under NT</A></H2>
+
+<P>
+<A NAME="nt_printers"></A>
+
+This info from Stefan Hergeth
+hergeth@f7axp1.informatik.fh-muenchen.de may be useful:</P>
+<P>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)
+<OL>
+<LI>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.
+</LI>
+<LI>If the printer is connected to the network everything works fine.
+</LI>
+<LI>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.
+</LI>
+<LI>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.</LI>
+</OL>
+</P>
+
+
+<H2><A NAME="ss3.6">3.6 Why are my file's timestamps off by an hour, or by a few hours?</A></H2>
+
+<P>
+<A NAME="dst_bugs"></A>
+
+This is from Paul Eggert eggert@twinsun.com.</P>
+<P>Most likely it's a problem with your time zone settings.</P>
+<P>Internally, Samba maintains time in traditional Unix format,
+namely, the number of seconds since 1970-01-01 00:00:00 Universal Time
+(or ``GMT''), not counting leap seconds.</P>
+<P>On the server side, Samba uses the Unix TZ variable to convert
+internal timestamps to and from local time. So on the server side, there are
+two things to get right.
+<OL>
+<LI>The Unix system clock must have the correct Universal time.
+Use the shell command "sh -c 'TZ=UTC0 date'" to check this.
+</LI>
+<LI>The TZ environment variable must be set on the server
+before Samba is invoked. The details of this depend on the
+server OS, but typically you must edit a file whose name is
+/etc/TIMEZONE or /etc/default/init, or run the command `zic -l'.
+</LI>
+<LI>TZ must have the correct value.
+<OL>
+<LI>If possible, use geographical time zone settings
+(e.g. TZ='America/Los_Angeles' or perhaps
+TZ=':US/Pacific'). These are supported by most
+popular Unix OSes, are easier to get right, and are
+more accurate for historical timestamps. If your
+operating system has out-of-date tables, you should be
+able to update them from the public domain time zone
+tables at
+<A HREF="ftp://elsie.nci.nih.gov/pub/">ftp://elsie.nci.nih.gov/pub/</A>.
+</LI>
+<LI>If your system does not support geographical timezone
+settings, you must use a Posix-style TZ strings, e.g.
+TZ='PST8PDT,M4.1.0/2,M10.5.0/2' for US Pacific time.
+Posix TZ strings can take the following form (with optional
+items in brackets):
+<PRE>
+ StdOffset[Dst[Offset],Date/Time,Date/Time]
+</PRE>
+
+where:
+<UL>
+<LI> `Std' is the standard time designation (e.g. `PST').
+</LI>
+<LI> `Offset' is the number of hours behind UTC (e.g. `8').
+Prepend a `-' if you are ahead of UTC, and
+append `:30' if you are at a half-hour offset.
+Omit all the remaining items if you do not use
+daylight-saving time.
+</LI>
+<LI> `Dst' is the daylight-saving time designation
+(e.g. `PDT').
+
+The optional second `Offset' is the number of
+hours that daylight-saving time is behind UTC.
+The default is 1 hour ahead of standard time.
+</LI>
+<LI> `Date/Time,Date/Time' specify when daylight-saving
+time starts and ends. The format for a date is
+`Mm.n.d', which specifies the dth day (0 is Sunday)
+of the nth week of the mth month, where week 5 means
+the last such day in the month. The format for a
+time is <F>h</F>h<F>:mm[:ss</F>], using a 24-hour clock.</LI>
+</UL>
+
+Other Posix string formats are allowed but you don't want
+to know about them.</LI>
+</OL>
+</LI>
+</OL>
+
+On the client side, you must make sure that your client's clock and
+time zone is also set appropriately. <F>[I don't know how to do this.</F>]
+Samba traditionally has had many problems dealing with time zones, due
+to the bizarre ways that Microsoft network protocols handle time
+zones. A common symptom is for file timestamps to be off by an hour.
+To work around the problem, try disconnecting from your Samba server
+and then reconnecting to it; or upgrade your Samba server to
+1.9.16alpha10 or later.</P>
+
+
+<H2><A NAME="ss3.7">3.7 How do I set the printer driver name correctly? </A></H2>
+
+<P>
+<A NAME="printer_driver_name"></A>
+
+Question:
+On NT, I opened "Printer Manager" and "Connect to Printer".
+Enter <F>"\\ptdi270\ps1"</F> in the box of printer. I got the
+following error message:
+<BLOCKQUOTE><CODE>
+<PRE>
+ You do not have sufficient access to your machine
+ to connect to the selected printer, since a driver
+ needs to be installed locally.
+</PRE>
+</CODE></BLOCKQUOTE>
+
+Answer:</P>
+<P>In the more recent versions of Samba you can now set the "printer
+driver" in smb.conf. This tells the client what driver to use. For
+example:
+<BLOCKQUOTE><CODE>
+<PRE>
+ printer driver = HP LaserJet 4L
+</PRE>
+</CODE></BLOCKQUOTE>
+
+with this, NT knows to use the right driver. You have to get this string
+exactly right.</P>
+<P>To find the exact string to use, you need to get to the dialog box in
+your client where you select which printer driver to install. The
+correct strings for all the different printers are shown in a listbox
+in that dialog box.</P>
+<P>You could also try setting the driver to NULL like this:
+<BLOCKQUOTE><CODE>
+<PRE>
+ printer driver = NULL
+</PRE>
+</CODE></BLOCKQUOTE>
+
+this is effectively what older versions of Samba did, so if that
+worked for you then give it a go. If this does work then let us know via
+<A HREF="mailto:samba-bugs@samba.anu.edu.au">samba-bugs@samba.anu.edu.au</A>,
+and we'll make it the default. Currently the default is a 0 length
+string.</P>
+
+
+<H2><A NAME="ss3.8">3.8 I've applied NT 4.0 SP3, and now I can't access Samba shares, Why?</A></H2>
+
+<P>
+<A NAME="NT_SP3_FIX"></A>
+
+As of SP3, Microsoft has decided that they will no longer default to
+passing clear text passwords over the network. To enable access to
+Samba shares from NT 4.0 SP3, you must do <B>ONE</B> of two things:
+<OL>
+<LI> Set the Samba configuration option 'security = user' and implement all of the stuff detailed in
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/ENCRYPTION.txt">ENCRYPTION.txt</A>.</LI>
+<LI> Follow Microsoft's directions for setting your NT box to allow plain text passwords. see
+<A HREF="http://www.microsoft.com/kb/articles/q166/7/30.htm">Knowledge Base Article Q166730</A></LI>
+</OL>
+</P>
+
+
+<HR>
+<A HREF="sambafaq-2.html">Previous</A>
+<A HREF="sambafaq-4.html">Next</A>
+<A HREF="sambafaq.html#toc3">Table of Contents</A>
+</BODY>
+</HTML>
diff --git a/docs/faq/sambafaq-4.html b/docs/faq/sambafaq-4.html
new file mode 100644
index 00000000000..94d5c419906
--- /dev/null
+++ b/docs/faq/sambafaq-4.html
@@ -0,0 +1,37 @@
+<HTML>
+<HEAD>
+<TITLE> Samba FAQ: Specific client application problems</TITLE>
+</HEAD>
+<BODY>
+<A HREF="sambafaq-3.html">Previous</A>
+<A HREF="sambafaq-5.html">Next</A>
+<A HREF="sambafaq.html#toc4">Table of Contents</A>
+<HR>
+<H2><A NAME="s4">4. Specific client application problems</A></H2>
+
+<P>
+<A NAME="client_problems"></A>
+</P>
+
+<H2><A NAME="ss4.1">4.1 MS Office Setup reports "Cannot change properties of '\MSOFFICE\SETUP.INI'"</A></H2>
+
+<P>
+<A NAME="cant_change_properties"></A>
+
+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.</P>
+<P>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.</P>
+<P>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.</P>
+
+
+<HR>
+<A HREF="sambafaq-3.html">Previous</A>
+<A HREF="sambafaq-5.html">Next</A>
+<A HREF="sambafaq.html#toc4">Table of Contents</A>
+</BODY>
+</HTML>
diff --git a/docs/faq/sambafaq-5.html b/docs/faq/sambafaq-5.html
new file mode 100644
index 00000000000..0a6e9d08f03
--- /dev/null
+++ b/docs/faq/sambafaq-5.html
@@ -0,0 +1,30 @@
+<HTML>
+<HEAD>
+<TITLE> Samba FAQ: Miscellaneous</TITLE>
+</HEAD>
+<BODY>
+<A HREF="sambafaq-4.html">Previous</A>
+Next
+<A HREF="sambafaq.html#toc5">Table of Contents</A>
+<HR>
+<H2><A NAME="s5">5. Miscellaneous</A></H2>
+
+<P>
+<A NAME="miscellaneous"></A>
+</P>
+<H2><A NAME="ss5.1">5.1 Is Samba Year 2000 compliant?</A></H2>
+
+<P>
+<A NAME="Year2000Compliant"></A>
+
+The CIFS protocol that Samba implements
+negotiates times in various formats, all of which
+are able to cope with dates beyond 2000.</P>
+
+
+<HR>
+<A HREF="sambafaq-4.html">Previous</A>
+Next
+<A HREF="sambafaq.html#toc5">Table of Contents</A>
+</BODY>
+</HTML>
diff --git a/docs/faq/sambafaq.html b/docs/faq/sambafaq.html
new file mode 100644
index 00000000000..9c45d524dd3
--- /dev/null
+++ b/docs/faq/sambafaq.html
@@ -0,0 +1,115 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<HTML>
+<HEAD>
+<TITLE> Samba FAQ</TITLE>
+</HEAD>
+<BODY>
+Previous
+<A HREF="sambafaq-1.html">Next</A>
+Table of Contents
+<HR>
+<H1> Samba FAQ</H1>
+
+<H2>Paul Blackman, <CODE>ictinus@samba.anu.edu.au</CODE></H2>v 0.8, June '97
+<P><HR><EM> This is the Frequently Asked Questions (FAQ) document for
+Samba, the free and very popular SMB server product. An SMB server
+allows file and printer connections from clients such as Windows,
+OS/2, Linux and others. Current to version 1.9.17. Please send any
+corrections to the author.</EM><HR></P>
+<P>
+<H2><A NAME="toc1">1.</A> <A HREF="sambafaq-1.html">General Information</A></H2>
+<UL>
+<LI><A HREF="sambafaq-1.html#ss1.1">1.1 What is Samba? </A>
+<LI><A HREF="sambafaq-1.html#ss1.2">1.2 What is the current version of Samba? </A>
+<LI><A HREF="sambafaq-1.html#ss1.3">1.3 Where can I get it? </A>
+<LI><A HREF="sambafaq-1.html#ss1.4">1.4 What do the version numbers mean? </A>
+<LI><A HREF="sambafaq-1.html#ss1.5">1.5 What platforms are supported? </A>
+<LI><A HREF="sambafaq-1.html#ss1.6">1.6 How can I find out more about Samba? </A>
+<LI><A HREF="sambafaq-1.html#ss1.7">1.7 How do I subscribe to the Samba Mailing Lists?</A>
+<LI><A HREF="sambafaq-1.html#ss1.8">1.8 Something's gone wrong - what should I do? </A>
+<LI><A HREF="sambafaq-1.html#ss1.9">1.9 Pizza supply details </A>
+</UL>
+
+<P>
+<H2><A NAME="toc2">2.</A> <A HREF="sambafaq-2.html">Compiling and installing Samba on a Unix host</A></H2>
+<UL>
+<LI><A HREF="sambafaq-2.html#ss2.1">2.1 I can't see the Samba server in any browse lists!</A>
+<LI><A HREF="sambafaq-2.html#ss2.2">2.2 Some files that I KNOW are on the server doesn't show up when I view the files from my client! </A>
+<LI><A HREF="sambafaq-2.html#ss2.3">2.3 Some files on the server show up with really wierd filenames when I view the files from my client! </A>
+<LI><A HREF="sambafaq-2.html#ss2.4">2.4 My client reports "cannot locate specified computer" or similar</A>
+<LI><A HREF="sambafaq-2.html#ss2.5">2.5 My client reports "cannot locate specified share name" or similar</A>
+<LI><A HREF="sambafaq-2.html#ss2.6">2.6 My client reports "cannot find domain controller", "cannot log on to the network" or similar </A>
+<LI><A HREF="sambafaq-2.html#ss2.7">2.7 Printing doesn't work :-(</A>
+<LI><A HREF="sambafaq-2.html#ss2.8">2.8 My programs install on the server OK, but refuse to work properly</A>
+<LI><A HREF="sambafaq-2.html#ss2.9">2.9 My "server string" doesn't seem to be recognised</A>
+<LI><A HREF="sambafaq-2.html#ss2.10">2.10 My client reports "This server is not configured to list shared resources" </A>
+<LI><A HREF="sambafaq-2.html#ss2.11">2.11 Log message "you appear to have a trapdoor uid system" </A>
+</UL>
+
+<P>
+<H2><A NAME="toc3">3.</A> <A HREF="sambafaq-3.html">Common client questions</A></H2>
+<UL>
+<LI><A HREF="sambafaq-3.html#ss3.1">3.1 Are there any Macintosh clients for Samba?</A>
+<LI><A HREF="sambafaq-3.html#ss3.2">3.2 "Session request failed (131,130)" error</A>
+<LI><A HREF="sambafaq-3.html#ss3.3">3.3 How do I synchronise my PC's clock with my Samba server? </A>
+<LI><A HREF="sambafaq-3.html#ss3.4">3.4 Problems with WinDD, NTrigue, WinCenterPro etc</A>
+<LI><A HREF="sambafaq-3.html#ss3.5">3.5 Problem with printers under NT</A>
+<LI><A HREF="sambafaq-3.html#ss3.6">3.6 Why are my file's timestamps off by an hour, or by a few hours?</A>
+<LI><A HREF="sambafaq-3.html#ss3.7">3.7 How do I set the printer driver name correctly? </A>
+<LI><A HREF="sambafaq-3.html#ss3.8">3.8 I've applied NT 4.0 SP3, and now I can't access Samba shares, Why?</A>
+</UL>
+
+<P>
+<H2><A NAME="toc4">4.</A> <A HREF="sambafaq-4.html">Specific client application problems</A></H2>
+<UL>
+<LI><A HREF="sambafaq-4.html#ss4.1">4.1 MS Office Setup reports "Cannot change properties of '\MSOFFICE\SETUP.INI'"</A>
+</UL>
+
+<P>
+<H2><A NAME="toc5">5.</A> <A HREF="sambafaq-5.html">Miscellaneous</A></H2>
+<UL>
+<LI><A HREF="sambafaq-5.html#ss5.1">5.1 Is Samba Year 2000 compliant?</A>
+</UL>
+
+
+<HR>
+Previous
+<A HREF="sambafaq-1.html">Next</A>
+Table of Contents
+</BODY>
+</HTML>
diff --git a/docs/faq/sambafaq.sgml b/docs/faq/sambafaq.sgml
new file mode 100644
index 00000000000..d306881b56b
--- /dev/null
+++ b/docs/faq/sambafaq.sgml
@@ -0,0 +1,792 @@
+<!doctype linuxdoc system> <!-- -*- SGML -*- -->
+<!--
+ v 0.5 18 Oct 1996 Dan Shearer Dan.Shearer@unisa.edu.au
+ First linuxdoc-sgml version, outline only
+ v 0.6 25 Oct 1996 Dan
+ Filled in from current text faq
+ v 0.7 1 June 1997 Paul
+ Replicated changes in txt faq to sgml faq
+ 9 June 1997 Paul
+ Lots of changes, added doco list, updated compatible systems list
+ added NT SP3 entry, added Year 2000 entry, Getting ready for 1.9.17
+ v 0.8 7th Oct 97 Paul
+ changed samba.canberra entries to samba.anu.../samba/
+-->
+
+<article>
+
+<title> Samba FAQ
+
+<author>Paul Blackman, <tt>ictinus@samba.anu.edu.au</tt>
+
+<date>v 0.8, June '97
+
+<abstract> This is the Frequently Asked Questions (FAQ) document for
+Samba, the free and very popular SMB server product. An SMB server
+allows file and printer connections from clients such as Windows,
+OS/2, Linux and others. Current to version 1.9.17. Please send any
+corrections to the author.
+</abstract>
+
+<toc>
+
+<sect> General Information<p> <label id="general_info">
+
+All about Samba - what it is, how to get it, related sources of
+information, how to understand the version numbering scheme, pizza
+details
+
+<sect1> What is Samba? <p> <label id="introduction">
+Samba is a suite of programs which work together to allow clients to
+access to a server's filespace and printers via the SMB (Server
+Message Block) protocol. Initially written for Unix, Samba now also
+runs on Netware, OS/2 and VMS.
+
+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):
+
+<itemize>
+<item><bf>smbd</bf>, the SMB server. This handles actual connections from clients, doing all the file, permission and username work
+<item><bf>nmbd</bf>, the Netbios name server, which helps clients locate servers, doing the browsing work and managing domains as this capability is being built into Samba
+<item><bf>smbclient</bf>, the Unix-hosted client program
+<item><bf>smbrun</bf>, a little 'glue' program to help the server run external programs
+<item><bf>testprns</bf>, a program to test server access to printers
+<item><bf>testparms</bf>, a program to test the Samba configuration file for correctness
+<item><bf>smb.conf</bf>, the Samba configuration file
+<item><bf>smbprint</bf>, a sample script to allow a Unix host to use smbclient to print to an SMB server
+<item><bf>Documentation!</bf> DON'T neglect to read it - you will save a great deal of time!
+</itemize>
+
+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.
+
+<sect1> What is the current version of Samba? <p><label id="current_version">
+At time of writing, the current version was 1.9.17. If you want to be
+sure check the bottom of the change-log file. <url url="ftp://samba.anu.edu.au/pub/samba/alpha/change-log">
+
+For more information see <ref id="version_nums" name="What do the
+version numbers mean?">
+
+<sect1> Where can I get it? <p> <label id="where">
+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.
+
+<sect1> What do the version numbers mean? <p> <label id="version_nums">
+It is not recommended that you run a version of Samba with the word
+"alpha" in its name unless you know what you are doing and are willing
+to do some debugging. Many, many people just get the latest
+recommended stable release version and are happy. If you are brave, by
+all means take the plunge and help with the testing and development -
+but don't install it on your departmental server. Samba is typically
+very stable and safe, and this is mostly due to the policy of many
+public releases.
+
+How the scheme works:
+<enum>
+<item>When major changes are made the version number is increased. For
+example, the transition from 1.9.15 to 1.9.16. However, this version
+number will not appear immediately and people should continue to use
+1.9.15 for production systems (see next point.)
+
+<item>Just after major changes are made the software is considered
+unstable, and a series of alpha releases are distributed, for example
+1.9.16alpha1. These are for testing by those who know what they are
+doing. The "alpha" in the filename will hopefully scare off those who
+are just looking for the latest version to install.
+
+<item>When Andrew thinks that the alphas have stabilised to the point
+where he would recommend new users install it, he renames it to the
+same version number without the alpha, for example 1.9.16.
+
+<item>Inevitably bugs are found in the "stable" releases and minor patch
+levels are released which give us the pXX series, for example 1.9.16p2.
+</enum>
+So the progression goes:
+<verb>
+ 1.9.15p7 (production)
+ 1.9.15p8 (production)
+ 1.9.16alpha1 (test sites only)
+ :
+ 1.9.16alpha20 (test sites only)
+ 1.9.16 (production)
+ 1.9.16p1 (production)
+</verb>
+The above system means that whenever someone looks at the samba ftp
+site they will be able to grab the highest numbered release without an
+alpha in the name and be sure of getting the current recommended
+version.
+
+<sect1> What platforms are supported? <p> <label id="platforms">
+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:
+<itemize>
+<item> A/UX 3.0
+<item> AIX
+<item> Altos Series 386/1000
+<item> Amiga
+<item> Apollo Domain/OS sr10.3
+<item> BSDI
+<item> B.O.S. (Bull Operating System)
+<item> Cray, Unicos 8.0
+<item> Convex
+<item> DGUX.
+<item> DNIX.
+<item> FreeBSD
+<item> HP-UX
+<item> Intergraph.
+<item> Linux with/without shadow passwords and quota
+<item> LYNX 2.3.0
+<item> MachTen (a unix like system for Macintoshes)
+<item> Motorola 88xxx/9xx range of machines
+<item> NetBSD
+<item> NEXTSTEP Release 2.X, 3.0 and greater (including OPENSTEP for Mach).
+<item> OS/2 using EMX 0.9b
+<item> OSF1
+<item> QNX 4.22
+<item> RiscIX.
+<item> RISCOs 5.0B
+<item> SEQUENT.
+<item> SCO (including: 3.2v2, European dist., OpenServer 5)
+<item> SGI.
+<item> SMP_DC.OSx v1.1-94c079 on Pyramid S series
+<item> SONY NEWS, NEWS-OS (4.2.x and 6.1.x)
+<item> SUNOS 4
+<item> SUNOS 5.2, 5.3, and 5.4 (Solaris 2.2, 2.3, and '2.4 and later')
+<item> Sunsoft ISC SVR3V4
+<item> SVR4
+<item> System V with some berkely extensions (Motorola 88k R32V3.2).
+<item> ULTRIX.
+<item> UNIXWARE
+<item> UXP/DS
+</itemize>
+
+<sect1> How can I find out more about Samba? <p> <label id="more">
+There are a number of places to look for more information on Samba, including:
+<itemize>
+<item>Two mailing lists devoted to discussion of Samba-related matters.
+<item>The newsgroup, comp.protocols.smb, which has a great deal of discussion on Samba.
+<item>The WWW site 'SAMBA Web Pages' at <url url="http://samba.edu.au/samba/"> includes:
+ <itemize>
+ <item>Links to man pages and documentation, including this FAQ
+ <item>A comprehensive survey of Samba users.
+ <item>A searchable hypertext archive of the Samba mailing list.
+ <item>Links to Samba source code, binaries, and mirrors of both.
+ </itemize>
+<item>The long list of topic documentation. These files can be found in the 'docs' directory of the Samba source, or at <url url="ftp://samba.anu.edu.au/pub/samba/docs/">
+ <itemize>
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/Application_Serving.txt" name="Application_Serving.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/BROWSING.txt" name="BROWSING.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/BUGS.txt" name="BUGS.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/DIAGNOSIS.txt" name="DIAGNOSIS.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/DNIX.txt" name="DNIX.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/DOMAIN.txt" name="DOMAIN.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/DOMAIN_CONTROL.txt" name="CONTROL.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/ENCRYPTION.txt" name="ENCRYPTION.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/Faxing.txt" name="Faxing.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/GOTCHAS.txt" name="GOTCHAS.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/HINTS.txt" name="HINTS.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/INSTALL.sambatar" name="INSTALL.sambatar">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/INSTALL.txt" name="INSTALL.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/MIRRORS" name="MIRRORS">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/NetBIOS.txt" name="NetBIOS.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/OS2.txt" name="OS2.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/PROJECTS" name="PROJECTS">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/Passwords.txt" name="Passwords.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/Printing.txt" name="Printing.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/README.DCEDFS" name="README.DCEDFS">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/README.OS2" name="README.OS2">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/README.jis" name="README.jis">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/README.sambatar" name="README.sambatar">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/SCO.txt" name="SCO.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/SMBTAR.notes" name="SMBTAR.notes">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/Speed.txt" name="Speed.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/Support.txt" name="Support.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/THANKS" name="THANKS">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/Tracing.txt" name="Tracing.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/UNIX-SMB.txt" name="SMB.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/Warp.txt" name="Warp.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/WinNT.txt" name="WinNT.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/history" name="history">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/security_level.txt" name="level.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/wfw_slip.htm" name="slip.htm">
+ </itemize>
+</itemize>
+
+<sect1>How do I subscribe to the Samba Mailing Lists?<p><label id="mailinglist">
+Send email to <htmlurl url="mailto:listproc@samba.anu.edu.au" name="listproc@samba.anu.edu.au">. Make sure the subject line is
+blank, and include the following two lines in the body of the message:
+<tscreen><verb>
+subscribe samba Firstname Lastname
+subscribe samba-announce Firstname Lastname
+</verb></tscreen>
+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
+<htmlurl url="mailto:listproc@samba.anu.edu.au" name="listproc@samba.anu.edu.au">. Make sure the subject line is blank, and
+include the following two lines in the body of the message:
+<tscreen><verb>
+unsubscribe samba
+unsubscribe samba-announce
+</verb></tscreen>
+The <bf>From:</bf> line in your message <em>MUST</em> be the same address you used when
+you subscribed.
+
+<sect1> Something's gone wrong - what should I do? <p> <label id="wrong">
+<bf>[#] *** IMPORTANT! *** [#]</bf>
+<p>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
+<url url="ftp://samba.anu.edu.au/pub/samba/DIAGNOSIS.txt" name="DIAGNOSIS.txt">? It can save you a lot of time and effort.
+DIAGNOSIS.txt can also be found in the docs directory of the Samba distribution.
+
+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 <htmlurl url="mailto:samba-bugs@samba.anu.edu.au" name="samba-bugs@samba.anu.edu.au">. Do not send patches to Andrew Tridgell or any
+other individual, they may be lost if you do.
+
+<sect1> Pizza supply details <p> <label id="pizza">
+Those who have registered in the Samba survey as "Pizza Factory" will
+already know this, but the rest may need some help. Andrew doesn't ask
+for payment, but he does appreciate it when people give him
+pizza. This calls for a little organisation when the pizza donor is
+twenty thousand kilometres away, but it has been done.
+
+Method 1: Ring up your local branch of an international pizza chain
+and see if they honour their vouchers internationally. Pizza Hut do,
+which is how the entire Canberra Linux Users Group got to eat pizza
+one night, courtesy of someone in the US
+
+Method 2: Ring up a local pizza shop in Canberra and quote a credit
+card number for a certain amount, and tell them that Andrew will be
+collecting it (don't forget to tell him.) One kind soul from Germany
+did this.
+
+Method 3: Purchase a pizza voucher from your local pizza shop that has
+no international affiliations and send it to Andrew. It is completely
+useless but he can hang it on the wall next to the one he already has
+from Germany :-)
+
+Method 4: Air freight him a pizza with your favourite regional
+flavours. It will probably get stuck in customs or torn apart by
+hungry sniffer dogs but it will have been a noble gesture.
+
+<sect>Compiling and installing Samba on a Unix host<p><label id="unix_install">
+
+<sect1>I can't see the Samba server in any browse lists!<p><label id="no_browse">
+ See <url url="ftp://samba.anu.edu.au/pub/samba/BROWSING.txt" name="BROWSING.txt">
+ for more information on browsing. Browsing.txt can also be found
+ in the docs directory of the Samba source.
+
+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:
+<tscreen><verb>
+ net use M: \\mary\fred
+</verb></tscreen>
+The details of how to do this and the specific syntax varies from
+client to client - check your client's documentation.
+
+<sect1>Some files that I KNOW are on the server doesn't show up when I view the files from my client! <p> <label id="missing_files">
+See the next question.
+<sect1>Some files on the server show up with really wierd filenames when I view the files from my client! <p> <label id="strange_filenames">
+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".
+
+<sect1>My client reports "cannot locate specified computer" or similar<p><label id="cant_see_server">
+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 :-)
+
+<sect1>My client reports "cannot locate specified share name" or similar<p> <label id="cant_see_share">
+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:
+
+<itemize>
+<item> Many clients cannot accept or use service names longer than eight characters.
+<item> Many clients cannot accept or use service names containing spaces.
+<item> Some servers (not Samba though) are case sensitive with service names.
+<item> Some clients force service names into upper case.
+</itemize>
+
+<sect1>My client reports "cannot find domain controller", "cannot log on to the network" or similar <p> <label id="cant_see_net">
+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
+<htmlurl url="mailto:samba-bugs@samba.anu.edu.au" name="samba-bugs@samba.anu.edu.au"> !
+
+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.
+
+<sect1>Printing doesn't work :-(<p> <label id="no_printing">
+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.
+
+<sect1>My programs install on the server OK, but refuse to work properly<p><label id="programs_wont_run">
+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 via email at <htmlurl url="mailto:samba-bugs@samba.anu.edu.au" name="samba-bugs@samba.anu.edu.au">.
+
+<sect1>My "server string" doesn't seem to be recognised<p><label id="bad_server_string">
+OR 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.
+
+Current versions of Samba (1.9.16 +) have combined these options into
+the "server string" field of smb.conf, -C for nmbd is now obsolete.
+
+<sect1>My client reports "This server is not configured to list shared resources" <p> <label id="cant_list_shares">
+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.
+
+<sect1>Log message "you appear to have a trapdoor uid system" <p><label id="trapdoor_uid">
+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.
+
+Note: the reason why 65535 is a VERY bad choice of uid and gid is that
+it casts to -1 as a uid, and the setreuid() system call ignores (with
+no error) uid changes to -1. This means any daemon attempting to run
+as uid 65535 will actually run as root. This is not good!
+
+<sect>Common client questions<p> <label id="client_questions">
+
+<sect1>Are there any Macintosh clients for Samba?<p> <label id="mac_clients">
+Yes! Thursby now have a CIFS Client / Server called DAVE - see <url url="http://www.thursby.com/">.
+They test it against Windows 95, Windows NT and samba for compatibility issues.
+At the time of writing, DAVE was at version 1.0.1. The 1.0.0 to 1.0.1 update is available
+as a free download from the Thursby web site (the speed of finder copies has
+been greatly enhanced, and there are bug-fixes included).
+
+Alternatives - There are two free implementations of AppleTalk for
+several kinds of UNIX machnes, and several more commercial ones.
+These products allow you to run file services and print services
+natively to Macintosh users, with no additional support required on
+the Macintosh. The two free omplementations are Netatalk,
+<url url="http://www.umich.edu/~rsug/netatalk/">, and CAP,
+<url url="http://www.cs.mu.oz.au/appletalk/atalk.html">. What Samba offers
+MS Windows users, these packages offer to Macs. For more info on
+these packages, Samba, and Linux (and other UNIX-based systems)
+see <url url="http://www.eats.com/linux_mac_win.html">
+
+<sect1>"Session request failed (131,130)" error<p> <label id="sess_req_fail">
+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.
+
+<sect1>How do I synchronise my PC's clock with my Samba server? <p><label id="synchronise_clock">
+To syncronize your PC's clock with your Samba server:
+<itemize>
+<item> Copy timesync.pif to your windows directory
+ <item> timesync.pif can be found at:
+ <url
+url="http://samba.anu.edu.au/samba/binaries/miscellaneous/timesync.pif">
+<item> Add timesync.pif to your 'Start Up' group/folder
+<item> Open the properties dialog box for the program/icon
+<item> Make sure the 'Run Minimized' option is set in program 'Properties'
+<iteM> Change the command line section that reads [\\sambahost] to reflect the name of your server.
+<item> Close the properties dialog box by choosing 'OK'
+</itemize>
+Each time you start your computer (or login for Win95) your PC will
+synchronize its clock with your Samba server.
+
+Alternativley, if you clients support Domain Logons, you can setup Domain Logons with Samba
+ - see: <url url="ftp://samba.anu.edu.au/pub/samba/docs/BROWSING.txt" name="BROWSING.txt"> *** for more information.
+<p>Then add
+<tscreen><verb>
+NET TIME \\%L /SET /YES
+</verb></tscreen>
+as one of the lines in the logon script.
+<sect1>Problems with WinDD, NTrigue, WinCenterPro etc<p>
+<label id="multiple_session_clients">
+
+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 <url url="ftp://samba.anu.edu.au/pub/samba/docs/security_level.txt" name="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.
+
+Also note that you should not use the magic "homes" share name with
+products like these, as otherwise all users will end up with the same
+home directory. Use [\\server\username] instead.
+
+<sect1>Problem with printers under NT<p> <label id="nt_printers">
+This info from Stefan Hergeth
+hergeth@f7axp1.informatik.fh-muenchen.de 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)
+<enum>
+<item>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.
+
+<item>If the printer is connected to the network everything works fine.
+
+<item>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.
+
+<item>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.
+</enum>
+
+<sect1>Why are my file's timestamps off by an hour, or by a few hours?<p><label id="dst_bugs">
+This is from Paul Eggert eggert@twinsun.com.
+
+Most likely it's a problem with your time zone settings.
+
+Internally, Samba maintains time in traditional Unix format,
+namely, the number of seconds since 1970-01-01 00:00:00 Universal Time
+(or ``GMT''), not counting leap seconds.
+
+On the server side, Samba uses the Unix TZ variable to convert
+internal timestamps to and from local time. So on the server side, there are
+two things to get right.
+<enum>
+<item>The Unix system clock must have the correct Universal time.
+ Use the shell command "sh -c 'TZ=UTC0 date'" to check this.
+
+<item>The TZ environment variable must be set on the server
+ before Samba is invoked. The details of this depend on the
+ server OS, but typically you must edit a file whose name is
+ /etc/TIMEZONE or /etc/default/init, or run the command `zic -l'.
+
+<item>TZ must have the correct value.
+<enum>
+ <item>If possible, use geographical time zone settings
+ (e.g. TZ='America/Los_Angeles' or perhaps
+ TZ=':US/Pacific'). These are supported by most
+ popular Unix OSes, are easier to get right, and are
+ more accurate for historical timestamps. If your
+ operating system has out-of-date tables, you should be
+ able to update them from the public domain time zone
+ tables at <url url="ftp://elsie.nci.nih.gov/pub/">.
+
+ <item>If your system does not support geographical timezone
+ settings, you must use a Posix-style TZ strings, e.g.
+ TZ='PST8PDT,M4.1.0/2,M10.5.0/2' for US Pacific time.
+ Posix TZ strings can take the following form (with optional
+ items in brackets):
+<verb>
+ StdOffset[Dst[Offset],Date/Time,Date/Time]
+</verb>
+ where:
+<itemize>
+<item> `Std' is the standard time designation (e.g. `PST').
+
+<item> `Offset' is the number of hours behind UTC (e.g. `8').
+ Prepend a `-' if you are ahead of UTC, and
+ append `:30' if you are at a half-hour offset.
+ Omit all the remaining items if you do not use
+ daylight-saving time.
+
+<item> `Dst' is the daylight-saving time designation
+ (e.g. `PDT').
+
+ The optional second `Offset' is the number of
+ hours that daylight-saving time is behind UTC.
+ The default is 1 hour ahead of standard time.
+
+<item> `Date/Time,Date/Time' specify when daylight-saving
+ time starts and ends. The format for a date is
+ `Mm.n.d', which specifies the dth day (0 is Sunday)
+ of the nth week of the mth month, where week 5 means
+ the last such day in the month. The format for a
+ time is [h]h[:mm[:ss]], using a 24-hour clock.
+</itemize>
+ Other Posix string formats are allowed but you don't want
+ to know about them.
+</enum>
+</enum>
+On the client side, you must make sure that your client's clock and
+time zone is also set appropriately. [[I don't know how to do this.]]
+Samba traditionally has had many problems dealing with time zones, due
+to the bizarre ways that Microsoft network protocols handle time
+zones. A common symptom is for file timestamps to be off by an hour.
+To work around the problem, try disconnecting from your Samba server
+and then reconnecting to it; or upgrade your Samba server to
+1.9.16alpha10 or later.
+
+<sect1> How do I set the printer driver name correctly? <p><label id="printer_driver_name">
+Question:
+ On NT, I opened "Printer Manager" and "Connect to Printer".
+ Enter ["\\ptdi270\ps1"] in the box of printer. I got the
+ following error message:
+<tscreen><verb>
+ You do not have sufficient access to your machine
+ to connect to the selected printer, since a driver
+ needs to be installed locally.
+</verb></tscreen>
+Answer:
+
+In the more recent versions of Samba you can now set the "printer
+driver" in smb.conf. This tells the client what driver to use. For
+example:
+<tscreen><verb>
+ printer driver = HP LaserJet 4L
+</verb></tscreen>
+with this, NT knows to use the right driver. You have to get this string
+exactly right.
+
+To find the exact string to use, you need to get to the dialog box in
+your client where you select which printer driver to install. The
+correct strings for all the different printers are shown in a listbox
+in that dialog box.
+
+You could also try setting the driver to NULL like this:
+<tscreen><verb>
+ printer driver = NULL
+</verb></tscreen>
+this is effectively what older versions of Samba did, so if that
+worked for you then give it a go. If this does work then let us know via <htmlurl url="mailto:samba-bugs@samba.anu.edu.au" name="samba-bugs@samba.anu.edu.au">,
+and we'll make it the default. Currently the default is a 0 length
+string.
+
+<sect1>I've applied NT 4.0 SP3, and now I can't access Samba shares, Why?<p><label id="NT_SP3_FIX">
+As of SP3, Microsoft has decided that they will no longer default to
+passing clear text passwords over the network. To enable access to
+Samba shares from NT 4.0 SP3, you must do <bf>ONE</bf> of two things:
+<enum>
+<item> Set the Samba configuration option 'security = user' and implement all of the stuff detailed in <url url="ftp://samba.anu.edu.au/pub/samba/docs/ENCRYPTION.txt" name="ENCRYPTION.txt">.
+<item> Follow Microsoft's directions for setting your NT box to allow plain text passwords. see <url url="http://www.microsoft.com/kb/articles/q166/7/30.htm" name="Knowledge Base Article Q166730">
+</enum>
+
+<sect>Specific client application problems<p> <label id="client_problems">
+
+<sect1>MS Office Setup reports "Cannot change properties of '\MSOFFICE\SETUP.INI'"<p> <label id="cant_change_properties">
+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.
+
+<sect>Miscellaneous<p> <label id="miscellaneous">
+<sect1>Is Samba Year 2000 compliant?<p><label id="Year2000Compliant">
+The CIFS protocol that Samba implements
+negotiates times in various formats, all of which
+are able to cope with dates beyond 2000.
+
+</article>
diff --git a/docs/faq/sambafaq.txt b/docs/faq/sambafaq.txt
new file mode 100644
index 00000000000..7108846ae67
--- /dev/null
+++ b/docs/faq/sambafaq.txt
@@ -0,0 +1,1122 @@
+ Samba FAQ
+ Paul Blackman, ictinus@samba.anu.edu.au
+ v 0.8, June '97
+
+ This is the Frequently Asked Questions (FAQ) document for Samba, the
+ free and very popular SMB server product. An SMB server allows file
+ and printer connections from clients such as Windows, OS/2, Linux and
+ others. Current to version 1.9.17. Please send any corrections to the
+ author.
+ ______________________________________________________________________
+
+ Table of Contents:
+
+ 1. General Information
+
+ 1.1. What is Samba?
+
+ 1.2. What is the current version of Samba?
+
+ 1.3. Where can I get it?
+
+ 1.4. What do the version numbers mean?
+
+ 1.5. What platforms are supported?
+
+ 1.6. How can I find out more about Samba?
+
+ 1.7. How do I subscribe to the Samba Mailing Lists?
+
+ 1.8. Something's gone wrong - what should I do?
+
+ 1.9. Pizza supply details
+
+ 2. Compiling and installing Samba on a Unix host
+
+ 2.1. I can't see the Samba server in any browse lists!
+
+ 2.2. Some files that I KNOW are on the server doesn't show up when
+ I view the files from my client!
+
+ 2.3. Some files on the server show up with really wierd filenames
+ when I view the files from my client!
+
+ 2.4. My client reports "cannot locate specified computer" or
+ similar
+
+ 2.5. My client reports "cannot locate specified share name" or
+ similar
+
+ 2.6. My client reports "cannot find domain controller", "cannot log
+ on to the network" or similar
+
+ 2.7. Printing doesn't work :-(
+
+ 2.8. My programs install on the server OK, but refuse to work
+ properly
+
+ 2.9. My "server string" doesn't seem to be recognised
+
+ 2.10. My client reports "This server is not configured to list
+ shared resources"
+
+ 2.11. Log message "you appear to have a trapdoor uid system"
+
+ 3. Common client questions
+
+ 3.1. Are there any Macintosh clients for Samba?
+
+ 3.2. "Session request failed (131,130)" error
+
+ 3.3. How do I synchronise my PC's clock with my Samba server?
+
+ 3.4. Problems with WinDD, NTrigue, WinCenterPro etc
+
+ 3.5. Problem with printers under NT
+
+ 3.6. Why are my file's timestamps off by an hour, or by a few
+ hours?
+
+ 3.7. How do I set the printer driver name correctly?
+
+ 3.8. I've applied NT 4.0 SP3, and now I can't access Samba shares,
+ Why?
+
+ 4. Specific client application problems
+
+ 4.1. MS Office Setup reports "Cannot change properties of
+ 'MSOFFICEUP.INI'"
+
+ 5. Miscellaneous
+
+ 5.1. Is Samba Year 2000 compliant?
+ ______________________________________________________________________
+
+ 11.. GGeenneerraall IInnffoorrmmaattiioonn
+
+
+
+ All about Samba - what it is, how to get it, related sources of
+ information, how to understand the version numbering scheme, pizza
+ details
+
+
+ 11..11.. WWhhaatt iiss SSaammbbaa??
+
+
+ Samba is a suite of programs which work together to allow clients to
+ access to a server's filespace and printers via the SMB (Server
+ Message Block) protocol. Initially written for Unix, Samba now also
+ runs on Netware, OS/2 and VMS.
+
+ 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):
+
+
+ +o ssmmbbdd, the SMB server. This handles actual connections from clients,
+ doing all the file, permission and username work
+
+ +o nnmmbbdd, the Netbios name server, which helps clients locate servers,
+ doing the browsing work and managing domains as this capability is
+ being built into Samba
+
+
+ +o ssmmbbcclliieenntt, the Unix-hosted client program
+
+ +o ssmmbbrruunn, a little 'glue' program to help the server run external
+ programs
+
+ +o tteessttpprrnnss, a program to test server access to printers
+
+ +o tteessttppaarrmmss, a program to test the Samba configuration file for
+ correctness
+
+ +o ssmmbb..ccoonnff, the Samba configuration file
+
+ +o ssmmbbpprriinntt, a sample script to allow a Unix host to use smbclient to
+ print to an SMB server
+
+ +o DDooccuummeennttaattiioonn!! 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.
+
+
+ 11..22.. WWhhaatt iiss tthhee ccuurrrreenntt vveerrssiioonn ooff SSaammbbaa??
+
+
+ At time of writing, the current version was 1.9.17. If you want to be
+ sure check the bottom of the change-log file.
+ <ftp://samba.anu.edu.au/pub/samba/alpha/change-log>
+
+ For more information see ``What do the version numbers mean?''
+
+
+ 11..33.. WWhheerree ccaann II ggeett iitt??
+
+
+ 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.
+
+
+ 11..44.. WWhhaatt ddoo tthhee vveerrssiioonn nnuummbbeerrss mmeeaann??
+
+
+ It is not recommended that you run a version of Samba with the word
+ "alpha" in its name unless you know what you are doing and are willing
+ to do some debugging. Many, many people just get the latest
+ recommended stable release version and are happy. If you are brave, by
+ all means take the plunge and help with the testing and development -
+ but don't install it on your departmental server. Samba is typically
+ very stable and safe, and this is mostly due to the policy of many
+ public releases.
+ How the scheme works:
+
+ 1. When major changes are made the version number is increased. For
+ example, the transition from 1.9.15 to 1.9.16. However, this
+ version number will not appear immediately and people should
+ continue to use 1.9.15 for production systems (see next point.)
+
+ 2. Just after major changes are made the software is considered
+ unstable, and a series of alpha releases are distributed, for
+ example 1.9.16alpha1. These are for testing by those who know what
+ they are doing. The "alpha" in the filename will hopefully scare
+ off those who are just looking for the latest version to install.
+
+ 3. When Andrew thinks that the alphas have stabilised to the point
+ where he would recommend new users install it, he renames it to the
+ same version number without the alpha, for example 1.9.16.
+
+ 4. Inevitably bugs are found in the "stable" releases and minor patch
+ levels are released which give us the pXX series, for example
+ 1.9.16p2.
+
+ So the progression goes:
+
+ 1.9.15p7 (production)
+ 1.9.15p8 (production)
+ 1.9.16alpha1 (test sites only)
+ :
+ 1.9.16alpha20 (test sites only)
+ 1.9.16 (production)
+ 1.9.16p1 (production)
+
+
+ The above system means that whenever someone looks at the samba ftp
+ site they will be able to grab the highest numbered release without an
+ alpha in the name and be sure of getting the current recommended ver-
+ sion.
+
+
+ 11..55.. WWhhaatt ppllaattffoorrmmss aarree ssuuppppoorrtteedd??
+
+
+ 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:
+
+ +o A/UX 3.0
+
+ +o AIX
+
+ +o Altos Series 386/1000
+
+ +o Amiga
+
+ +o Apollo Domain/OS sr10.3
+
+ +o BSDI
+
+ +o B.O.S. (Bull Operating System)
+
+ +o Cray, Unicos 8.0
+
+ +o Convex
+
+ +o DGUX.
+
+ +o DNIX.
+
+ +o FreeBSD
+
+ +o HP-UX
+
+ +o Intergraph.
+
+ +o Linux with/without shadow passwords and quota
+
+ +o LYNX 2.3.0
+
+ +o MachTen (a unix like system for Macintoshes)
+
+ +o Motorola 88xxx/9xx range of machines
+
+ +o NetBSD
+
+ +o NEXTSTEP Release 2.X, 3.0 and greater (including OPENSTEP for
+ Mach).
+
+ +o OS/2 using EMX 0.9b
+
+ +o OSF1
+
+ +o QNX 4.22
+
+ +o RiscIX.
+
+ +o RISCOs 5.0B
+
+ +o SEQUENT.
+
+ +o SCO (including: 3.2v2, European dist., OpenServer 5)
+
+ +o SGI.
+
+ +o SMP_DC.OSx v1.1-94c079 on Pyramid S series
+
+ +o SONY NEWS, NEWS-OS (4.2.x and 6.1.x)
+
+ +o SUNOS 4
+
+ +o SUNOS 5.2, 5.3, and 5.4 (Solaris 2.2, 2.3, and '2.4 and later')
+
+ +o Sunsoft ISC SVR3V4
+
+ +o SVR4
+
+ +o System V with some berkely extensions (Motorola 88k R32V3.2).
+
+ +o ULTRIX.
+
+ +o UNIXWARE
+
+ +o UXP/DS
+
+
+ 11..66.. HHooww ccaann II ffiinndd oouutt mmoorree aabboouutt SSaammbbaa??
+
+
+ There are a number of places to look for more information on Samba,
+ including:
+
+ +o Two mailing lists devoted to discussion of Samba-related matters.
+
+ +o The newsgroup, comp.protocols.smb, which has a great deal of
+ discussion on Samba.
+
+ +o The WWW site 'SAMBA Web Pages' at <http://samba.edu.au/samba/>
+ includes:
+
+ +o Links to man pages and documentation, including this FAQ
+
+ +o A comprehensive survey of Samba users.
+
+ +o A searchable hypertext archive of the Samba mailing list.
+
+ +o Links to Samba source code, binaries, and mirrors of both.
+
+ +o The long list of topic documentation. These files can be found in
+ the 'docs' directory of the Samba source, or at
+ <ftp://samba.anu.edu.au/pub/samba/docs/>
+
+ +o Application_Serving.txt
+ <ftp://samba.anu.edu.au/pub/samba/docs/Application_Serving.txt>
+
+ +o BROWSING.txt <ftp://samba.anu.edu.au/pub/samba/docs/BROWSING.txt>
+
+ +o BUGS.txt <ftp://samba.anu.edu.au/pub/samba/docs/BUGS.txt>
+
+ +o DIAGNOSIS.txt <ftp://samba.anu.edu.au/pub/samba/docs/DIAGNOSIS.txt>
+
+ +o DNIX.txt <ftp://samba.anu.edu.au/pub/samba/docs/DNIX.txt>
+
+ +o DOMAIN.txt <ftp://samba.anu.edu.au/pub/samba/docs/DOMAIN.txt>
+
+ +o CONTROL.txt
+ <ftp://samba.anu.edu.au/pub/samba/docs/DOMAIN_CONTROL.txt>
+
+ +o ENCRYPTION.txt
+ <ftp://samba.anu.edu.au/pub/samba/docs/ENCRYPTION.txt>
+
+ +o Faxing.txt <ftp://samba.anu.edu.au/pub/samba/docs/Faxing.txt>
+
+ +o GOTCHAS.txt <ftp://samba.anu.edu.au/pub/samba/docs/GOTCHAS.txt>
+
+ +o HINTS.txt <ftp://samba.anu.edu.au/pub/samba/docs/HINTS.txt>
+
+ +o INSTALL.sambatar
+ <ftp://samba.anu.edu.au/pub/samba/docs/INSTALL.sambatar>
+
+ +o INSTALL.txt <ftp://samba.anu.edu.au/pub/samba/docs/INSTALL.txt>
+
+ +o MIRRORS <ftp://samba.anu.edu.au/pub/samba/docs/MIRRORS>
+
+ +o NetBIOS.txt <ftp://samba.anu.edu.au/pub/samba/docs/NetBIOS.txt>
+
+ +o OS2.txt <ftp://samba.anu.edu.au/pub/samba/docs/OS2.txt>
+
+ +o PROJECTS <ftp://samba.anu.edu.au/pub/samba/docs/PROJECTS>
+
+ +o Passwords.txt <ftp://samba.anu.edu.au/pub/samba/docs/Passwords.txt>
+
+ +o Printing.txt <ftp://samba.anu.edu.au/pub/samba/docs/Printing.txt>
+
+ +o README.DCEDFS <ftp://samba.anu.edu.au/pub/samba/docs/README.DCEDFS>
+
+ +o README.OS2 <ftp://samba.anu.edu.au/pub/samba/docs/README.OS2>
+
+ +o README.jis <ftp://samba.anu.edu.au/pub/samba/docs/README.jis>
+
+ +o README.sambatar
+ <ftp://samba.anu.edu.au/pub/samba/docs/README.sambatar>
+
+ +o SCO.txt <ftp://samba.anu.edu.au/pub/samba/docs/SCO.txt>
+
+ +o SMBTAR.notes <ftp://samba.anu.edu.au/pub/samba/docs/SMBTAR.notes>
+
+ +o Speed.txt <ftp://samba.anu.edu.au/pub/samba/docs/Speed.txt>
+
+ +o Support.txt <ftp://samba.anu.edu.au/pub/samba/docs/Support.txt>
+
+ +o THANKS <ftp://samba.anu.edu.au/pub/samba/docs/THANKS>
+
+ +o Tracing.txt <ftp://samba.anu.edu.au/pub/samba/docs/Tracing.txt>
+
+ +o SMB.txt <ftp://samba.anu.edu.au/pub/samba/docs/UNIX-SMB.txt>
+
+ +o Warp.txt <ftp://samba.anu.edu.au/pub/samba/docs/Warp.txt>
+
+ +o WinNT.txt <ftp://samba.anu.edu.au/pub/samba/docs/WinNT.txt>
+
+ +o history <ftp://samba.anu.edu.au/pub/samba/docs/history>
+
+ +o level.txt
+ <ftp://samba.anu.edu.au/pub/samba/docs/security_level.txt>
+
+ +o slip.htm <ftp://samba.anu.edu.au/pub/samba/docs/wfw_slip.htm>
+
+
+ 11..77.. HHooww ddoo II ssuubbssccrriibbee ttoo tthhee SSaammbbaa MMaaiilliinngg LLiissttss??
+
+
+ Send email to listproc@samba.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@samba.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 FFrroomm:: line in your message _M_U_S_T be the same address you used when
+ you subscribed.
+
+
+ 11..88.. SSoommeetthhiinngg''ss ggoonnee wwrroonngg -- wwhhaatt sshhoouulldd II ddoo??
+
+
+ ## ****** IIMMPPOORRTTAANNTT!! ****** ##
+
+ 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 <ftp://samba.anu.edu.au/pub/samba/DIAGNOSIS.txt>? It can
+ save you a lot of time and effort. DIAGNOSIS.txt can also be found in
+ the docs directory of the Samba distribution.
+
+ 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. Do not send patches to Andrew
+ Tridgell or any other individual, they may be lost if you do.
+
+
+ 11..99.. PPiizzzzaa ssuuppppllyy ddeettaaiillss
+
+
+ Those who have registered in the Samba survey as "Pizza Factory" will
+ already know this, but the rest may need some help. Andrew doesn't ask
+ for payment, but he does appreciate it when people give him pizza.
+ This calls for a little organisation when the pizza donor is twenty
+ thousand kilometres away, but it has been done.
+
+ Method 1: Ring up your local branch of an international pizza chain
+ and see if they honour their vouchers internationally. Pizza Hut do,
+ which is how the entire Canberra Linux Users Group got to eat pizza
+ one night, courtesy of someone in the US
+
+ Method 2: Ring up a local pizza shop in Canberra and quote a credit
+ card number for a certain amount, and tell them that Andrew will be
+ collecting it (don't forget to tell him.) One kind soul from Germany
+ did this.
+
+ Method 3: Purchase a pizza voucher from your local pizza shop that has
+ no international affiliations and send it to Andrew. It is completely
+ useless but he can hang it on the wall next to the one he already has
+ from Germany :-)
+
+
+ Method 4: Air freight him a pizza with your favourite regional
+ flavours. It will probably get stuck in customs or torn apart by
+ hungry sniffer dogs but it will have been a noble gesture.
+
+
+ 22.. CCoommppiilliinngg aanndd iinnssttaalllliinngg SSaammbbaa oonn aa UUnniixx hhoosstt
+
+
+
+ 22..11.. II ccaann''tt sseeee tthhee SSaammbbaa sseerrvveerr iinn aannyy bbrroowwssee lliissttss!!
+
+
+ See BROWSING.txt <ftp://samba.anu.edu.au/pub/samba/BROWSING.txt> for
+ more information on browsing. Browsing.txt can also be found in the
+ docs directory of the Samba source.
+
+ 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.
+
+
+ 22..22.. SSoommee ffiilleess tthhaatt II KKNNOOWW aarree oonn tthhee sseerrvveerr ddooeessnn''tt sshhooww uupp wwhheenn II
+ vviieeww tthhee ffiilleess ffrroomm mmyy cclliieenntt!!
+
+
+ See the next question.
+
+ 22..33.. SSoommee ffiilleess oonn tthhee sseerrvveerr sshhooww uupp wwiitthh rreeaallllyy wwiieerrdd ffiilleennaammeess
+ wwhheenn II vviieeww tthhee ffiilleess ffrroomm mmyy cclliieenntt!!
+
+
+ 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".
+
+
+ 22..44.. MMyy cclliieenntt rreeppoorrttss ""ccaannnnoott llooccaattee ssppeecciiffiieedd ccoommppuutteerr"" oorr ssiimmiillaarr
+
+
+ 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 :-)
+
+
+ 22..55.. MMyy cclliieenntt rreeppoorrttss ""ccaannnnoott llooccaattee ssppeecciiffiieedd sshhaarree nnaammee"" oorr ssiimmii--
+ llaarr
+
+
+ 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:
+
+
+ +o Many clients cannot accept or use service names longer than eight
+ characters.
+
+ +o Many clients cannot accept or use service names containing spaces.
+
+ +o Some servers (not Samba though) are case sensitive with service
+ names.
+
+ +o Some clients force service names into upper case.
+
+
+ 22..66.. MMyy cclliieenntt rreeppoorrttss ""ccaannnnoott ffiinndd ddoommaaiinn ccoonnttrroolllleerr"",, ""ccaannnnoott lloogg
+ oonn ttoo tthhee nneettwwoorrkk"" oorr ssiimmiillaarr
+
+
+ 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@samba.anu.edu.au !
+
+ 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.
+
+
+
+
+
+ 22..77.. PPrriinnttiinngg ddooeessnn''tt wwoorrkk ::--((
+
+
+ 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.
+
+
+ 22..88.. MMyy pprrooggrraammss iinnssttaallll oonn tthhee sseerrvveerr OOKK,, bbuutt rreeffuussee ttoo wwoorrkk pprroopp--
+ eerrllyy
+
+
+ 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 via email at samba-bugs@samba.anu.edu.au.
+
+
+ 22..99.. MMyy ""sseerrvveerr ssttrriinngg"" ddooeessnn''tt sseeeemm ttoo bbee rreeccooggnniisseedd
+
+
+ OR 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.
+
+ Current versions of Samba (1.9.16 +) have combined these options into
+ the "server string" field of smb.conf, -C for nmbd is now obsolete.
+
+
+ 22..1100.. MMyy cclliieenntt rreeppoorrttss ""TThhiiss sseerrvveerr iiss nnoott ccoonnffiigguurreedd ttoo lliisstt sshhaarreedd
+ rreessoouurrcceess""
+
+
+ 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.
+
+
+ 22..1111.. LLoogg mmeessssaaggee ""yyoouu aappppeeaarr ttoo hhaavvee aa ttrraappddoooorr uuiidd ssyysstteemm""
+
+
+ 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.
+
+ Note: the reason why 65535 is a VERY bad choice of uid and gid is that
+ it casts to -1 as a uid, and the setreuid() system call ignores (with
+ no error) uid changes to -1. This means any daemon attempting to run
+ as uid 65535 will actually run as root. This is not good!
+
+
+ 33.. CCoommmmoonn cclliieenntt qquueessttiioonnss
+
+
+
+
+ 33..11.. AArree tthheerree aannyy MMaacciinnttoosshh cclliieennttss ffoorr SSaammbbaa??
+
+
+ Yes! Thursby now have a CIFS Client / Server called DAVE - see
+ <http://www.thursby.com/>. They test it against Windows 95, Windows
+ NT and samba for compatibility issues. At the time of writing, DAVE
+ was at version 1.0.1. The 1.0.0 to 1.0.1 update is available as a free
+ download from the Thursby web site (the speed of finder copies has
+ been greatly enhanced, and there are bug-fixes included).
+
+ Alternatives - There are two free implementations of AppleTalk for
+ several kinds of UNIX machnes, and several more commercial ones.
+ These products allow you to run file services and print services
+ natively to Macintosh users, with no additional support required on
+ the Macintosh. The two free omplementations are Netatalk,
+ <http://www.umich.edu/~rsug/netatalk/>, and CAP,
+ <http://www.cs.mu.oz.au/appletalk/atalk.html>. What Samba offers MS
+ Windows users, these packages offer to Macs. For more info on these
+ packages, Samba, and Linux (and other UNIX-based systems) see
+ <http://www.eats.com/linux_mac_win.html>
+ 33..22.. SSeessssiioonn rreeqquueesstt ffaaiilleedd ((113311,,113300))"" eerrrroorr
+
+
+ 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
+
+ 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.
+
+
+ 33..33.. HHooww ddoo II ssyynncchhrroonniissee mmyy PPCC''ss cclloocckk wwiitthh mmyy SSaammbbaa sseerrvveerr??
+
+
+ To syncronize your PC's clock with your Samba server:
+
+ +o Copy timesync.pif to your windows directory
+
+ +o timesync.pif can be found at:
+ <http://samba.anu.edu.au/samba/binaries/miscellaneous/timesync.pif>
+
+ +o Add timesync.pif to your 'Start Up' group/folder
+
+ +o Open the properties dialog box for the program/icon
+
+ +o Make sure the 'Run Minimized' option is set in program 'Properties'
+
+ +o Change the command line section that reads \sambahost to reflect
+ the name of your server.
+
+ +o Close the properties dialog box by choosing 'OK'
+
+ Each time you start your computer (or login for Win95) your PC will
+ synchronize its clock with your Samba server.
+
+ Alternativley, if you clients support Domain Logons, you can setup
+ Domain Logons with Samba - see: BROWSING.txt
+ <ftp://samba.anu.edu.au/pub/samba/docs/BROWSING.txt> *** for more
+ information.
+
+ Then add
+
+
+ NET TIME \\%L /SET /YES
+
+
+
+
+ as one of the lines in the logon script.
+
+ 33..44.. PPrroobblleemmss wwiitthh WWiinnDDDD,, NNTTrriigguuee,, WWiinnCCeenntteerrPPrroo eettcc
+
+
+ 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
+ <ftp://samba.anu.edu.au/pub/samba/docs/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.
+
+ Also note that you should not use the magic "homes" share name with
+ products like these, as otherwise all users will end up with the same
+ home directory. Use \serversername instead.
+
+
+ 33..55.. PPrroobblleemm wwiitthh pprriinntteerrss uunnddeerr NNTT
+
+
+ This info from Stefan Hergeth hergeth@f7axp1.informatik.fh-muenchen.de
+ 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.
+
+
+ 33..66.. WWhhyy aarree mmyy ffiillee''ss ttiimmeessttaammppss ooffff bbyy aann hhoouurr,, oorr bbyy aa ffeeww hhoouurrss??
+
+
+ This is from Paul Eggert eggert@twinsun.com.
+
+ Most likely it's a problem with your time zone settings.
+
+ Internally, Samba maintains time in traditional Unix format, namely,
+ the number of seconds since 1970-01-01 00:00:00 Universal Time (or
+ ``GMT''), not counting leap seconds.
+
+ On the server side, Samba uses the Unix TZ variable to convert
+ internal timestamps to and from local time. So on the server side,
+ there are two things to get right.
+
+ 1. The Unix system clock must have the correct Universal time. Use
+ the shell command "sh -c 'TZ=UTC0 date'" to check this.
+
+ 2. The TZ environment variable must be set on the server before Samba
+ is invoked. The details of this depend on the server OS, but
+ typically you must edit a file whose name is /etc/TIMEZONE or
+ /etc/default/init, or run the command `zic -l'.
+
+ 3. TZ must have the correct value.
+
+ a. If possible, use geographical time zone settings (e.g.
+ TZ='America/Los_Angeles' or perhaps TZ=':US/Pacific'). These
+ are supported by most popular Unix OSes, are easier to get
+ right, and are more accurate for historical timestamps. If your
+ operating system has out-of-date tables, you should be able to
+ update them from the public domain time zone tables at
+ <ftp://elsie.nci.nih.gov/pub/>.
+
+ b. If your system does not support geographical timezone settings,
+ you must use a Posix-style TZ strings, e.g.
+ TZ='PST8PDT,M4.1.0/2,M10.5.0/2' for US Pacific time. Posix TZ
+ strings can take the following form (with optional items in
+ brackets):
+
+ StdOffset[Dst[Offset],Date/Time,Date/Time]
+
+
+ where:
+
+ +o `Std' is the standard time designation (e.g. `PST').
+
+ +o `Offset' is the number of hours behind UTC (e.g. `8'). Prepend
+ a `-' if you are ahead of UTC, and append `:30' if you are at a
+ half-hour offset. Omit all the remaining items if you do not
+ use daylight-saving time.
+
+ +o `Dst' is the daylight-saving time designation (e.g. `PDT').
+
+ The optional second `Offset' is the number of hours that
+ daylight-saving time is behind UTC. The default is 1 hour ahead
+ of standard time.
+
+ +o `Date/Time,Date/Time' specify when daylight-saving time starts
+ and ends. The format for a date is `Mm.n.d', which specifies
+ the dth day (0 is Sunday) of the nth week of the mth month,
+ where week 5 means the last such day in the month. The format
+ for a time is hh:mm[:ss], using a 24-hour clock.
+
+ Other Posix string formats are allowed but you don't want to
+ know about them.
+
+ On the client side, you must make sure that your client's clock and
+ time zone is also set appropriately. [I don't know how to do
+ this.] Samba traditionally has had many problems dealing with time
+ zones, due to the bizarre ways that Microsoft network protocols
+ handle time zones. A common symptom is for file timestamps to be
+ off by an hour. To work around the problem, try disconnecting from
+ your Samba server and then reconnecting to it; or upgrade your
+ Samba server to 1.9.16alpha10 or later.
+
+
+ 33..77.. HHooww ddoo II sseett tthhee pprriinntteerr ddrriivveerr nnaammee ccoorrrreeccttllyy??
+
+
+ Question: On NT, I opened "Printer Manager" and "Connect to Printer".
+ Enter "\ptdi270s1"
+ in the box of printer. I got the following error message:
+
+
+ You do not have sufficient access to your machine
+ to connect to the selected printer, since a driver
+ needs to be installed locally.
+
+
+
+
+ Answer:
+
+ In the more recent versions of Samba you can now set the "printer
+ driver" in smb.conf. This tells the client what driver to use. For
+ example:
+
+
+ printer driver = HP LaserJet 4L
+
+
+
+
+ with this, NT knows to use the right driver. You have to get this
+ string exactly right.
+
+ To find the exact string to use, you need to get to the dialog box in
+ your client where you select which printer driver to install. The
+ correct strings for all the different printers are shown in a listbox
+ in that dialog box.
+
+ You could also try setting the driver to NULL like this:
+
+
+ printer driver = NULL
+
+
+
+
+ this is effectively what older versions of Samba did, so if that
+ worked for you then give it a go. If this does work then let us know
+ via samba-bugs@samba.anu.edu.au, and we'll make it the default. Cur-
+ rently the default is a 0 length string.
+
+
+ 33..88.. II''vvee aapppplliieedd NNTT 44..00 SSPP33,, aanndd nnooww II ccaann''tt aacccceessss SSaammbbaa sshhaarreess,,
+ WWhhyy??
+
+
+ As of SP3, Microsoft has decided that they will no longer default to
+ passing clear text passwords over the network. To enable access to
+ Samba shares from NT 4.0 SP3, you must do OONNEE of two things:
+
+ 1. Set the Samba configuration option 'security = user' and implement
+ all of the stuff detailed in ENCRYPTION.txt
+ <ftp://samba.anu.edu.au/pub/samba/docs/ENCRYPTION.txt>.
+
+ 2. Follow Microsoft's directions for setting your NT box to allow
+ plain text passwords. see Knowledge Base Article Q166730
+ <http://www.microsoft.com/kb/articles/q166/7/30.htm>
+
+
+ 44.. SSppeecciiffiicc cclliieenntt aapppplliiccaattiioonn pprroobblleemmss
+
+
+
+
+ 44..11.. MMSS OOffffiiccee SSeettuupp rreeppoorrttss ""CCaannnnoott cchhaannggee pprrooppeerrttiieess ooff ''MMSSOOFF--
+ FFIICCEEUUPP..IINNII''""
+
+
+ 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.
+
+
+ 55.. MMiisscceellllaanneeoouuss
+
+
+
+ 55..11.. IIss SSaammbbaa YYeeaarr 22000000 ccoommpplliiaanntt??
+
+
+ The CIFS protocol that Samba implements negotiates times in various
+ formats, all of which are able to cope with dates beyond 2000.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/history b/docs/history
index 83761e23b86..dd9e83719ff 100644
--- a/docs/history
+++ b/docs/history
@@ -1,8 +1,9 @@
-Note: This file is now quite out of date - but perhaps that's
-appropriate?
+Contributor: Andrew Tridgell and the Samba Team
+Date: June 27, 1997
+Satus: Always out of date! (Would not be the same without it!)
-
-=========
+Subject: A bit of history and a bit of fun
+============================================================================
This is a short history of this project. It's not supposed to be
comprehensive, just enough so that new users can get a feel for where
@@ -10,7 +11,7 @@ this project has come from and maybe where it's going to.
The whole thing really started in December 1991. I was (and still am)
a PhD student in the Computer Sciences Laboratory at the Australian
-Netional University, in Canberra, Australia. We had just got a
+National University, in Canberra, Australia. We had just got a
beta copy of eXcursion from Digital, and I was testing it on my PC. At
this stage I was a MS-DOS user, dabbling in windows.
@@ -111,7 +112,7 @@ code! I wrote back saying it was OK, but never heard from him again. I
don't know if it went on the cd-rom.
Anyway, the next big event was in December 1993, when Dan again sent
-me an e-mail saying my server had "raised it's ugly head" on
+me an e-mail saying my server had "raised its ugly head" on
comp.protocols.tcpip.ibmpc. I had a quick look on the group, and was
surprised to see that there were people interested in this thing.
@@ -163,3 +164,33 @@ support and the ability to do domain logons etc. Samba has also been
ported to OS/2, the amiga and NetWare. There are now 3000 people on
the samba mailing list.
---------------------
+
+
+---------------------
+It's now June 1997 and samba-1.9.17 is due out soon. My how time passes!
+Please refer to the WHATSNEW.txt for an update on new features. Just when
+you think you understand what is happening the ground rules change - this
+is a real world after all. Since the heady days of March 1996 there has
+been a concerted effort within the SMB protocol using community to document
+and standardize the protocols. The CIFS initiative has helped a long way
+towards creating a better understood and more interoperable environment.
+The Samba Team has grown in number and have been very active in the standards
+formation and documentation process.
+
+The net effect has been that we have had to do a lot of work to bring Samba
+into line with new features and capabilities in the SMB protocols.
+
+The past year has been a productive one with the following releases:
+ 1.9.16, 1.9.16p2, 1.9.16p6, 1.9.16p9, 1.9.16p10, 1.9.16p11
+
+There are some who believe that 1.9.15p8 was the best release and others
+who would not want to be without the latest. Whatever your perception we
+hope that 1.9.17 will close the gap and convince you all that the long
+wait and the rolling changes really were worth it. Here is functionality
+and a level of code maturity that ..., well - you can be the judge!
+
+Happy SMB networking!
+Samba Team
+
+ps: The bugs are ours, so please report any you find.
+---------------------
diff --git a/docs/manpages/make_smbcodepage.1 b/docs/manpages/make_smbcodepage.1
new file mode 100644
index 00000000000..dc34bd257a2
--- /dev/null
+++ b/docs/manpages/make_smbcodepage.1
@@ -0,0 +1,131 @@
+.TH MAKE_SMBCODEPAGE 1 "30 Oct 1997" "make_smbcodepage 1.9.18alpha8"
+.SH NAME
+make_smbcodepage \- create a binary codepage definition file from an ascii codepage definition source file, or reverse the process.
+.SH SYNOPSIS
+.B make_smbcodepage
+.I c|d
+.I codepage
+.I inputfile
+.I outputfile
+.SH DESCRIPTION
+This program is part of the Samba suite.
+
+.B make_smbcodepage
+compiles or de-compiles codepage files for use with the internationalization
+features of Samba 1.9.18.
+
+An ascii Samba codepage definition file is a description that tells Samba
+how to map from upper to lower case for characters greater than ascii 127
+in the specified DOS code page. Note that for certain DOS codepages
+(437 for example) mapping from lower to upper case may be asynchronous.
+For example, in code page 437 lower case a acute maps to a plain upper
+case A when going from lower to upper case, but maps from plain upper
+case A to plain lower case a when lower casing a character.
+
+A binary Samba codepage definition file is a binary representation
+of the same information, including a value that specifies what codepage
+this file is describing.
+
+As Samba does not yet use UNICODE (current for Samba version 1.9.18)
+you must specify the client code page that your DOS and Windows clients
+are using if you wish to have case insensitivity done correctly for
+your particular language. The default codepage Samba uses is 850
+(Western European). Ascii codepage definition sample files are provided
+in the Samba distribution for codepages 437 (USA), 850 (Western European)
+852 (MS-DOS Latin 2) and 932 (Kanji SJIS). Users are encouraged to
+write ascii codepage definition files for their own code pages and
+donate them to samba-bugs@samba.anu.edu.au. All codepage files in the
+Samba source directory are compiled and installed when a 'make install'
+command is issued there.
+
+An ascii codepage definition file consists of multiple lines containing
+four fields. These fields are :
+.B lower
+which is the (hex) lower case character mapped on this line.
+.B upper
+which is the (hex) upper case character that the lower case character
+will map to.
+.B map upper to lower
+which is a boolean value (put either True or False here) which tells
+Samba if it is to map the given upper case character to the given
+lower case character when lower casing a filename.
+.B map lower to upper
+which is a boolean value (put either True or False here) which tells
+Samba if it is to map the given lower case character to the given
+upper case character when upper casing a filename.
+
+.SH OPTIONS
+.I c|d
+
+.RS 3
+This tells make_smbcodepage if it is compiling (c) an ascii code page file
+to binary, or de-compiling a binary codepage file to ascii.
+.RE
+
+.I codepage
+
+.RS 3
+This is the codepage we are processing (a number, eg. 850)
+.RE
+
+.I inputfile
+
+.RS 3
+This is the input file to process.
+.RE
+
+.I outputfile
+
+.RS 3
+This is the output file to produce.
+.RE
+
+.SH FILES
+.B codepage_def.<codepage>
+.RS 3
+These are the input (ascii) codepage files provided in the Samba
+source/ directory.
+.RE
+.SH FILES
+.B codepage.<codepage>
+.RS 3
+These are the output (binary) codepage files produced and placed in the Samba
+destination lib/codepage/ directory.
+.RE
+
+.SH ENVIRONMENT VARIABLES
+Not applicable.
+.SH INSTALLATION
+The location of the server and its support files is a matter for individual
+system administrators. The following are thus suggestions only.
+
+It is recommended that the
+.B make_smbcodepage
+program be installed under the /usr/local/samba hierarchy, in a directory readable
+by all, writeable only by root. The program itself should be executable by all.
+The program should NOT be setuid or setgid!
+.SH VERSION
+This man page is (mostly) correct for version 1.9.18 of the Samba suite, plus some
+of the recent patches to it. These notes will necessarily lag behind
+development of the software, so it is possible that your version of
+the program has extensions or parameter semantics that differ from or are not
+covered by this man page. Please notify these to the address below for
+rectification.
+.SH SEE ALSO
+.BR smb.conf (5),
+.BR smbd (8)
+
+.SH BUGS
+None known.
+.SH CREDITS
+The
+.B make_smbcodepage
+program was written by Jeremy Allison (jallison@whistle.com) as part of the
+Internationalization effort of the Samba software.
+
+Please send bug reports to samba-bugs@samba.anu.edu.au.
+
+See
+.BR samba (7)
+for a full list of contributors and details on how to
+submit bug reports, comments etc.
diff --git a/docs/manpages/nmbd.8 b/docs/manpages/nmbd.8
index e42f194cdee..484d7dba67a 100644
--- a/docs/manpages/nmbd.8
+++ b/docs/manpages/nmbd.8
@@ -1,44 +1,29 @@
-.TH NMBD 8 17/1/1995 nmbd nmbd
+.TH NMBD 8 "30 Oct 1997" "nmbd 1.9.18alpha8"
.SH NAME
nmbd \- provide netbios nameserver support to clients
.SH SYNOPSIS
.B nmbd
[
-.B -B
-.I broadcast address
+.B \-D
] [
-.B -I
-.I IP address
-] [
-.B -D
-] [
-.B -C comment string
-] [
-.B -G
-.I group name
-] [
-.B -H
+.B \-H
.I netbios hosts file
] [
-.B -N
-.I netmask
-] [
-.B -d
+.B \-d
.I debuglevel
] [
-.B -l
+.B \-l
.I log basename
] [
-.B -n
+.B \-n
.I netbios name
] [
-.B -p
+.B \-p
.I port number
] [
-.B -s
-.I config file name
+.B \-s
+.I configuration file
]
-
.SH DESCRIPTION
This program is part of the Samba suite.
@@ -51,44 +36,36 @@ LanManager clients, when they start up, may wish to locate a LanManager server.
That is, they wish to know what IP number a specified host is using.
This program simply listens for such requests, and if its own name is specified
-it will respond with the IP number of the host it is running on. "Its own name"
-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
-means is that it will respond to all name requests that it receives
-that are not broadcasts, as long as it can resolve the name.
+it will respond with the IP number of the host it is running on.
+Its "own name" 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).
+
+.B nmbd
+can also be used as a WINS (Windows Internet Name Server) server.
+What this basically means is that it will respond to all name requests that
+it receives that are not broadcasts, as long as it can resolve the name.
+Resolvable names include all names in the netbios hosts file (if any, see
+.B \-H
+below), its own name, and any other names that it may have learned about
+from other browsers on the network.
+A change to previous versions is that nmbd will now no longer
+do this automatically by default.
.SH OPTIONS
-.B -B
+.B \-B
.RS 3
-On some systems, the server is unable to determine the broadcast address to
-use for name registration requests. If your system has this difficulty, this
-parameter may be used to specify an appropriate broadcast address. The
-address should be given in standard "a.b.c.d" notation.
-
-Only use this parameter if you are sure that the server cannot properly
-determine the proper broadcast address.
-
-The default broadcast address is determined by the server at run time. If it
-encounters difficulty doing so, it makes a guess based on the local IP
-number.
+This option is obsolete. Please use the "interfaces" option in smb.conf instead.
.RE
-.B -I
+
+.B \-I
.RS 3
-On some systems, the server is unable to determine the correct IP
-address to use. This allows you to override the default choice.
+This option is obsolete. Please use the "interfaces" option in smb.conf instead.
.RE
-.B -D
+.B \-D
.RS 3
If specified, this parameter causes the server to operate as a daemon. That is,
@@ -98,75 +75,60 @@ appropriate port.
By default, the server will NOT operate as a daemon.
.RE
-.B -C comment string
+.B \-C comment string
.RS 3
-This allows you to set the "comment string" that is shown next to the
-machine name in browse listings.
-
-A %v will be replaced with the Samba version number.
-
-A %h will be replaced with the hostname.
-
-It defaults to "Samba %v".
+This option is obsolete. Please use the "server string" option in smb.conf
+instead.
.RE
-.B -G
+.B \-G
.RS 3
-This option allows you to specify a netbios group (also known as
-lanmanager domain) that the server should be part of. You may include
-several of these on the command line if you like. Alternatively you
-can use the -H option to load a netbios hosts file containing domain names.
-
-At startup, unless the -R switch has been used, the server will
-attempt to register all group names in the hosts file and on the
-command line (from the -G option).
-
-The server will also respond to queries on this name.
+This option is obsolete. Please use the "workgroup" option in smb.conf instead.
.RE
-.B -H
+.B \-H
+.I netbios hosts file
.RS 3
It may be useful in some situations to be able to specify a list of
-netbios names for which the server should send a reply if
-queried. This option allows that. The syntax is similar to the
-standard /etc/hosts file format, but has some extensions.
+netbios names for which the server should send a reply if queried.
+This option allows you to specify a file containing such a list.
+The syntax of the hosts file is similar to the standard /etc/hosts file
+format, but has some extensions.
The file contains three columns. Lines beginning with a # are ignored
as comments. The first column is an IP address, or a hostname. If it
is a hostname then it is interpreted as the IP address returned by
-gethostbyname() when read. Any IP address of 0.0.0.0 will be
-interpreted as the servers own IP address.
+gethostbyname() when read. An IP address of 0.0.0.0 will be
+interpreted as the server's own IP address.
The second column is a netbios name. This is the name that the server
will respond to. It must be less than 20 characters long.
The third column is optional, and is intended for flags. Currently the
-only flags supported are G, S and M. A G indicates that the name is a
-group (also known as domain) name.
+only flag supported is M, which means that this name is the default
+netbios name for this machine. This has the same effect as specifying the
+.B \-n
+option to
+.BR nmbd .
-At startup all groups known to the server (either from this file or
-from the -G option) are registered on the network (unless the -R
-option has been selected).
+NOTE: The G and S flags are now obsolete and are replaced by the
+"interfaces" and "remote announce" options in smb.conf.
-A S or G means that the specified address is a broadcast address of a
-network that you want people to be able to browse you from. Nmbd will
-search for a master browser in that domain and will send host
-announcements to that machine, informing it that the specifed somain
-is available.
+The default hosts file name is set at compile time, typically as
+.I /etc/lmhosts,
+but this may be changed in the Samba Makefile.
-A M means that this name is the default netbios name for this
-machine. This has the same affect as specifying the -n option to nmbd.
+After startup the server waits for queries, and will answer queries for
+any name known to it. This includes all names in the netbios hosts file,
+its own name, and any other names it may have learned about from other
+browsers on the network.
-After startup the server waits for queries, and will answer queries to
-any name known to it. This includes all names in the netbios hosts
-file (if any), it's own name, and any names given with the -G option.
-
-The primary intention of the -H option is to allow a mapping from
-netbios names to internet domain names, and to allow the specification
-of groups that the server should be part of.
+The primary intention of the
+.B \-H
+option is to allow a mapping from netbios names to internet domain names.
.B Example:
@@ -177,315 +139,100 @@ of groups that the server should be part of.
# if you want to include a name with a space in it then
# use double quotes.
- # first put ourselves in the group LANGROUP
- 0.0.0.0 LANGROUP G
-
# next add a netbios alias for a faraway host
arvidsjaur.anu.edu.au ARVIDSJAUR
# finally put in an IP for a hard to find host
130.45.3.213 FREDDY
- # now we want another subnet to be able to browse
- # us in the workgroup UNIXSERV
- 192.0.2.255 UNIXSERV G
-
.RE
-
-.B -M
-.I workgroup name
+.B \-N
.RS 3
-If this parameter is given, the server will look for a master browser
-for the specified workgroup name, report success or failure, then
-exit. If successful, the IP address of the name located will be
-reported.
-
-If you use the workgroup name "-" then nmbd will search for a master
-browser for any workgroup by using the name __MSBROWSE__.
-
-This option is meant to be used interactively on the command line, not
-as a daemon or in inetd.
-
+This option is obsolete. Please use the "interfaces" option in smb.conf instead.
.RE
-.B -N
-
-.RS 3
-On some systems, the server is unable to determine the netmask. If
-your system has this difficulty, this parameter may be used to specify
-an appropriate netmask. The mask should be given in standard
-"a.b.c.d" notation.
-Only use this parameter if you are sure that the server cannot properly
-determine the proper netmask.
-
-The default netmask is determined by the server at run time. If it
-encounters difficulty doing so, it makes a guess based on the local IP
-number.
-.RE
-
-.B -d
+.B \-d
.I debuglevel
-.RS 3
-
-debuglevel is an integer from 0 to 5.
-
-The default value if this parameter is not specified is zero.
-The higher this value, the more detail will be logged to the log files about
-the activities of the server. At level 0, only critical errors and serious
-warnings will be logged. Level 1 is a reasonable level for day to day running
-- it generates a small amount of information about operations carried out.
-
-Levels above 1 will generate considerable amounts of log data, and should
-only be used when investigating a problem. Levels above 3 are designed for
-use only by developers and generate HUGE amounts of log data, most of which
-is extremely cryptic.
+.RS 3
+This option sets the debug level. See
+.BR smb.conf (5).
.RE
-.B -l
+.B \-l
.I log file
.RS 3
-If specified,
-.I logfile
-specifies a base filename into which operational data from the running server
-will be logged.
-
-The default base name is specified at compile time.
-
-The base name is used to generate actual log file names. For example, if the
-name specified was "log", the following files would be used for log data:
-
-.RS 3
-log.nmb (containing debugging information)
-
-log.nmb.in (containing inbound transaction data)
-
-log.nmb.out (containing outbound transaction data)
-.RE
+The
+.I log file
+parameter specifies a path and base filename into which operational data
+from the running
+.B nmbd
+server will be logged.
+The actual log file name is generated by appending the extension ".nmb" to
+the specified base name.
+For example, if the name specified was "log" then the file log.nmb would
+contain the debugging data.
-The log files generated are never removed by the server.
-.RE
+The default log file is specified at compile time, typically as
+.I /var/log/log.nmb.
.RE
-.B -n
+.B \-n
.I netbios name
.RS 3
-This parameter tells the server what netbios name to respond with when
-queried. The same name is also registered on startup unless the -R
-parameter was specified.
-
-The default netbios name used if this parameter is not specified is the
-name of the host on which the server is running.
-.RE
-
-.B -p
-.I port number
-.RS 3
-
-port number is a positive integer value.
-
-The default value if this parameter is not specified is 137.
-
-This number is the port number that will be used when making connections to
-the server from client software. The standard (well-known) port number for the
-server is 137, hence the default. If you wish to run the server as an ordinary
-user rather than as root, most systems will require you to use a port number
-greater than 1024 - ask your system administrator for help if you are in this
-situation.
-
-Note that the name server uses UDP, not TCP!
-
-This parameter is not normally specified except in the above situation.
-.RE
-.SH FILES
-
-.B /etc/inetd.conf
-
-.RS 3
-If the server is to be run by the inetd meta-daemon, this file must contain
-suitable startup information for the meta-daemon. See the section
-"INSTALLATION" below.
-.RE
-
-.B /etc/rc.d/rc.inet2
-
-.RS 3
-(or whatever initialisation script your system uses)
-
-If running the server as a daemon at startup, this file will need to contain
-an appropriate startup sequence for the server. See the section "Installation"
-below.
+This option allows you to override the Netbios name that Samba uses for itself.
.RE
-.B /etc/services
+.B \-a
.RS 3
-If running the server via the meta-daemon inetd, this file must contain a
-mapping of service name (eg., netbios-ns) to service port (eg., 137) and
-protocol type (eg., udp). See the section "INSTALLATION" below.
+If this parameter is specified, the log files will be appended to with each
+new connection. By default, the log files will be overwritten.
.RE
-.RE
-
-.SH ENVIRONMENT VARIABLES
-Not applicable.
-
-.SH INSTALLATION
-The location of the server and its support files is a matter for individual
-system administrators. The following are thus suggestions only.
-
-It is recommended that the server software be installed under the /usr/local
-hierarchy, in a directory readable by all, writeable only by root. The server
-program itself should be executable by all, as users may wish to run the
-server themselves (in which case it will of course run with their privileges).
-The server should NOT be setuid or setgid!
-
-The server log files should be put in a directory readable and writable only
-by root, as the log files may contain sensitive information.
-
-The remaining notes will assume the following:
+.B \-p
+.I port number
.RS 3
-nmbd (the server program) installed in /usr/local/smb
-
-log files stored in /var/adm/smblogs
-.RE
-The server may be run either as a daemon by users or at startup, or it may
-be run from a meta-daemon such as inetd upon request. If run as a daemon, the
-server will always be ready, so starting sessions will be faster. If run from
-a meta-daemon some memory will be saved and utilities such as the tcpd
-TCP-wrapper may be used for extra security.
-
-When you've decided, continue with either "Running the server as a daemon" or
-"Running the server on request".
-.SH RUNNING THE SERVER AS A DAEMON
-To run the server as a daemon from the command line, simply put the "-D" option
-on the command line. There is no need to place an ampersand at the end of the
-command line - the "-D" option causes the server to detach itself from the
-tty anyway.
-
-Any user can run the server as a daemon (execute permissions permitting, of
-course). This is useful for testing purposes.
-
-To ensure that the server is run as a daemon whenever the machine is started,
-you will need to modify the system startup files. Wherever appropriate (for
-example, in /etc/rc.d/rc.inet2), insert the following line, substituting
-values appropriate to your system:
+port number is a positive integer value.
-.RS 3
-/usr/local/smb/nmbd -D -l/var/adm/smblogs/log
+Don't use this option unless you are an expert, in which case you
+won't need help!
.RE
-(The above should appear in your initialisation script as a single line.
-Depending on your terminal characteristics, it may not appear that way in
-this man page. If the above appears as more than one line, please treat any
-newlines or indentation as a single space or TAB character.)
-
-If the options used at compile time are appropriate for your system, all
-parameters except the desired debug level and "-D" may be omitted. See the
-section on "Options" above.
-.SH RUNNING THE SERVER ON REQUEST
-If your system uses a meta-daemon such as inetd, you can arrange to have the
-SMB name server started whenever a process attempts to connect to it. This
-requires several changes to the startup files on the host machine. If you are
-experimenting as an ordinary user rather than as root, you will need the
-assistance of your system administrator to modify the system files.
-
-First, ensure that a port is configured in the file /etc/services. The
-well-known port 137 should be used if possible, though any port may be used.
-
-Ensure that a line similar to the following is in /etc/services:
+.B \-s
+.I configuration file
.RS 3
-netbios-ns 137/udp
-.RE
+The default configuration file name is set at compile time, typically as
+.I /etc/smb.conf,
+but this may be changed in the Samba Makefile.
-Note for NIS/YP users: You may need to rebuild the NIS service maps rather
-than alter your local /etc/services file.
-
-Next, put a suitable line in the file /etc/inetd.conf (in the unlikely event
-that you are using a meta-daemon other than inetd, you are on your own). Note
-that the first item in this line matches the service name in /etc/services.
-Substitute appropriate values for your system in this line (see
-.B inetd(8)):
-
-.RS 3
-netbios-ns dgram udp wait root /usr/local/smb/nmbd -l/var/adm/smblogs/log
+The file specified contains the configuration details required by the server.
+See
+.BR smb.conf (5)
+for more information.
.RE
-
-(The above should appear in /etc/inetd.conf as a single line. Depending on
-your terminal characteristics, it may not appear that way in this man page.
-If the above appears as more than one line, please treat any newlines or
-indentation as a single space or TAB character.)
-
-Note that there is no need to specify a port number here, even if you are
-using a non-standard port number.
-.SH TESTING THE INSTALLATION
-If running the server as a daemon, execute it before proceeding. If
-using a meta-daemon, either restart the system or kill and restart the
-meta-daemon. Some versions of inetd will reread their configuration tables if
-they receive a HUP signal.
-
-To test whether the name server is running, start up a client
-.I on a different machine
-and see whether the desired name is now present. Alternatively, run
-the nameserver
-.I on a different machine
-specifying "-L netbiosname", where "netbiosname" is the name you have
-configured the test server to respond with. The command should respond
-with success, and the IP number of the machine using the specified netbios
-name. You may need the -B parameter on some systems. See the README
-file for more information on testing nmbd.
-
.SH VERSION
-This man page is (mostly) correct for version 1.9.00 of the Samba suite, plus some
-of the recent patches to it. These notes will necessarily lag behind
-development of the software, so it is possible that your version of
-the server has extensions or parameter semantics that differ from or are not
-covered by this man page. Please notify these to the address below for
-rectification.
+
+This man page is (mostly) correct for version 1.9.16 of the Samba
+suite, plus some of the recent patches to it. These notes will
+necessarily lag behind development of the software, so it is possible
+that your version of the server has extensions or parameter semantics
+that differ from or are not covered by this man page. Please notify
+these to the address below for rectification.
.SH SEE ALSO
-.B inetd(8),
-.B smbd(8),
-.B smb.conf(5),
-.B smbclient(1),
-.B testparm(1),
-.B testprns(1)
-
-.SH DIAGNOSTICS
-[This section under construction]
-
-Most diagnostics issued by the server are logged in the specified log file. The
-log file name is specified at compile time, but may be overridden on the
-command line.
-
-The number and nature of diagnostics available depends on the debug level used
-by the server. If you have problems, set the debug level to 3 and peruse the
-log files.
-
-Most messages are reasonably self-explanatory. Unfortunately, at time of
-creation of this man page the source code is still too fluid to warrant
-describing each and every diagnostic. At this stage your best bet is still
-to grep the source code and inspect the conditions that gave rise to the
-diagnostics you are seeing.
-
-.SH BUGS
-None known.
+.BR inetd (8),
+.BR smbd (8),
+.BR smb.conf (5),
+.BR smbclient (1),
+.BR testparm (1),
+.BR testprns (1)
.SH CREDITS
The original Samba software and related utilities were created by
-Andrew Tridgell (samba-bugs@anu.edu.au). Andrew is also the Keeper
+Andrew Tridgell (samba-bugs@samba.anu.edu.au). Andrew is also the Keeper
of the Source for this project.
-This man page written by Karl Auer (Karl.Auer@anu.edu.au)
-
-See
-.B smb.conf(5) for a full list of contributors and details on how to
-submit bug reports, comments etc.
-
-
-
-
-
diff --git a/docs/manpages/samba.7 b/docs/manpages/samba.7
index 0c81f736b6e..d9d5fd29d47 100644
--- a/docs/manpages/samba.7
+++ b/docs/manpages/samba.7
@@ -1,15 +1,14 @@
-.TH SAMBA 7 29/3/95 Samba Samba
+.TH SAMBA 7 "30 Oct 1997" "samba 1.9.18alpha8"
.SH NAME
-Samba \- a LanManager like fileserver for Unix
+Samba \- a LanManager like fileserver for UNIX
.SH SYNOPSIS
.B Samba
.SH DESCRIPTION
The
.B Samba
software suite is a collection of programs that implements the SMB
-protocol for unix systems. This protocol is sometimes also referred to
+protocol for UNIX systems. This protocol is sometimes also referred to
as the LanManager or Netbios protocol.
-
.SH COMPONENTS
The Samba suite is made up of several components. Each component is
@@ -18,25 +17,37 @@ you read the documentation that comes with Samba and the manual pages
of those components that you use. If the manual pages aren't clear
enough then please send me a patch!
-The smbd(8) daemon provides the file and print services to SMB clents,
+The
+.BR smbd (8)
+daemon provides the file and print services to SMB clients,
such as Windows for Workgroups, Windows NT or LanManager. The
-configuration file for this daemon is described in smb.conf(5).
+configuration file for this daemon is described in
+.BR smb.conf (5).
-The nmbd(8) daemon provides Netbios nameserving and browsing
+The
+.BR nmbd (8)
+daemon provides Netbios nameserving and browsing
support. It can also be run interactively to query other name service
daemons.
-The smbclient(1) program implements a simple ftp-like client. This is
+The
+.BR smbclient (1)
+program implements a simple ftp-like client. This is
useful for accessing SMB shares on other compatible servers (such as
-WfWg), and can also be used to allow a unix box to print to a printer
+WfWg), and can also be used to allow a UNIX box to print to a printer
attached to any SMB server (such as a PC running WfWg).
-The testparm(1) utility allows you to test your smb.conf(5)
+The
+.BR testparm (1)
+utility allows you to test your
+.BR smb.conf (5)
configuration file.
-The smbstatus(1) utility allows you to tell who is currently using the
-smbd(8) server.
-
+The
+.BR smbstatus (1)
+utility allows you to tell who is currently using the
+.BR smbd (8)
+server.
.SH AVAILABILITY
The Samba software suite is licensed under the Gnu Public License. A
@@ -45,7 +56,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,29 +65,26 @@ 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.anu.edu.au/samba/
.SH AUTHOR
The main author of the Samba suite is Andrew Tridgell. He may be
-contacted via e-mail at samba-bugs@anu.edu.au.
+contacted via e-mail at samba-bugs@samba.anu.edu.au.
-There have also been an enourmous number of contributors to Samba from
+There have also been an enormous number of contributors to Samba from
all over the world. A partial list of these contributors is included
in the CREDITS section below. The list is, however, badly out of
date. More up to date info may be obtained from the change-log that
comes with the Samba source code.
-
.SH CONTRIBUTIONS
If you wish to contribute to the Samba project, then I suggest you
join the Samba mailing list.
If you have patches to submit or bugs to report then you may mail them
-directly to samba-bugs@anu.edu.au. Note, however, that due to the
-enourmous popularity of this package I may take some time to repond to
-mail. I prefer patches in "diff -u" format.
-
+directly to samba-bugs@samba.anu.edu.au. Note, however, that due to the
+enormous popularity of this package I may take some time to repond to
+mail. I prefer patches in "diff \-u" format.
.SH CREDITS
Contributors to the project are (in alphabetical order by email address):
@@ -147,6 +155,8 @@ Contributors to the project are (in alphabetical order by email address):
(kuku@acds.physik.rwth-aachen.de)
???
(lance@fox.com)
+ Leighton, Luke
+ (lkcl@pires.co.uk)
Lendecke, Volker
(lendecke@namu01.gwdg.de)
???
@@ -175,8 +185,10 @@ Contributors to the project are (in alphabetical order by email address):
(joergs@toppoint.de)
S{rkel{, Vesa
(vesku@rankki.kcl.fi)
+ Terpstra, John
+ (jht@aquasoft.com.au)
Tridgell, Andrew
- (samba-bugs@anu.edu.au)
+ (samba-bugs@samba.anu.edu.au)
Troyer, Dean
(troyer@saifr00.ateng.az.honeywell.com)
Wakelin, Ross
diff --git a/docs/manpages/smb.conf.5 b/docs/manpages/smb.conf.5
index 933d71ff0c3..3278ce559bf 100644
--- a/docs/manpages/smb.conf.5
+++ b/docs/manpages/smb.conf.5
@@ -1,4 +1,4 @@
-.TH SMB.CONF 5 11/10/94 smb.conf smb.conf
+.TH SMB.CONF 5 "30 Oct 1997" "smb.conf 1.9.18alpha8"
.SH NAME
smb.conf \- configuration file for smbd
.SH SYNOPSIS
@@ -15,7 +15,6 @@ program. The
.B smbd
program provides LanManager-like services to clients
using the SMB protocol.
-
.SH FILE FORMAT
The file consists of sections and parameters. A section begins with the
name of the section in square brackets and continues until the next
@@ -35,8 +34,8 @@ within a parameter value is retained verbatim.
Any line beginning with a semicolon is ignored, as are lines containing
only whitespace.
-Any line ending in a \\ is "continued" on the next line in the
-customary unix fashion.
+Any line ending in a \e is "continued" on the next line in the
+customary UNIX fashion.
The values following the equals sign in parameters are all either a string
(no quotes needed) or a boolean, which may be given as yes/no, 0/1 or
@@ -91,7 +90,6 @@ means access will be permitted as the default guest user (specified elsewhere):
read only = true
printable = true
public = true
-
.SH SPECIAL SECTIONS
.SS The [global] section
@@ -124,7 +122,7 @@ If no path was given, the path is set to the user's home directory.
If you decide to use a path= line in your [homes] section then you may
find it useful to use the %S macro. For example path=/data/pchome/%S
would be useful if you have different home directories for your PCs
-than for unix access.
+than for UNIX access.
This is a fast and simple way to give a large number of clients access to
their home directories with a minimum of fuss.
@@ -212,6 +210,7 @@ could be used simply to limit access to a subset of your local printers.
An alias, by the way, is defined as any component of the first entry of a
printcap record. Records are separated by newlines, components (if there are
more than one) are separated by vertical bar symbols ("|").
+.RE
.SH PARAMETERS
Parameters define the specific attributes of services.
@@ -221,7 +220,7 @@ permissible only in normal sections. For the purposes of the following
descriptions the [homes] and [printers] sections will be considered normal.
The letter 'G' in parentheses indicates that a parameter is specific to the
[global] section. The letter 'S' indicates that a parameter can be
-specified in a secvice specific section. Note that all S parameters
+specified in a service specific section. Note that all S parameters
can also be specified in the [global] section - in which case they
will define the default behaviour for all services.
@@ -237,7 +236,7 @@ interpreted as "path = /tmp/john" if the user connected with the
username john.
These substitutions are mostly noted in the descriptions below, but
-there are some general substitions which apply whenever they might be
+there are some general substitutions which apply whenever they might be
relevant. These are:
%S = the name of the current service, if any
@@ -267,6 +266,10 @@ personality".
%M = the internet name of the client machine
+%N = the name of your NIS home directory server. This is obtained from
+your NIS auto.map entry. If you have not compiled Samba with -DAUTOMOUNT
+then this value will be the same as %L.
+
%d = The process id of the current server process
%a = the architecture of the remote machine. Only some are recognised,
@@ -283,7 +286,7 @@ substitutions and other smb.conf options.
.SS NAME MANGLING
-Samba supports "name mangling" so that Dos and Windows clients can use
+Samba supports "name mangling" so that DOS and Windows clients can use
files that don't conform to the 8.3 format. It can also be set to adjust
the case of 8.3 format filenames.
@@ -317,13 +320,25 @@ upper case, or if they are forced to be the "default" case. This option can
be use with "preserve case = yes" to permit long filenames to retain their
case, while short names are lowered. Default no.
-.SS COMPLETE LIST OF GLOBAL PARAMETER
+.SS COMPLETE LIST OF GLOBAL PARAMETERS
Here is a list of all global parameters. See the section of each
parameter for details. Note that some are synonyms.
+announce as
+
+announce version
+
auto services
+bind interfaces only
+
+browse list
+
+character set
+
+client code page
+
config file
deadtime
@@ -336,38 +351,78 @@ default service
dfree command
+dns proxy
+
+domain controller
+
+domain sid
+
+domain group
+
+domain logons
+
+domain master
+
encrypt passwords
getwd cache
+hide files
+
+hide dot files
+
+homedir map
+
hosts equiv
include
+interfaces
+
keepalive
lock dir
load printers
+local master
+
lock directory
log file
log level
+logon drive
+
+logon home
+
+logon path
+
+logon script
+
lpq cache time
mangled stack
max log size
+max mux
+
max packet
+max ttl
+
max xmit
message command
+netbios aliases
+
+netbios name
+
+nis homedir
+
null passwords
os level
@@ -390,6 +445,8 @@ printing
printcap name
+printer driver file
+
protocol
read bmpx
@@ -400,6 +457,8 @@ read raw
read size
+remote announce
+
root
root dir
@@ -410,27 +469,47 @@ security
server string
+shared file entries
+
+shared mem size
+
+smb passwd file
+
smbrun
+socket address
+
socket options
status
strip dot
+syslog
+
+syslog only
+
time offset
+time server
+
+unix realname
+
+username level
+
username map
use rhosts
valid chars
+veto files
+
workgroup
write raw
-.SS COMPLETE LIST OF SERVICE PARAMETER
+.SS COMPLETE LIST OF SERVICE PARAMETERS
Here is a list of all service parameters. See the section of each
parameter for details. Note that some are synonyms.
@@ -459,14 +538,32 @@ comment
default case
+delete readonly
+
+delete veto files
+
deny hosts
directory
+directory mask
+
+directory mode
+
dont descend
+dos filetimes
+
exec
+fake oplocks
+
+follow symlinks
+
+force create mode
+
+force directory mode
+
force group
force user
@@ -519,6 +616,8 @@ only guest
only user
+oplocks
+
path
postexec
@@ -529,6 +628,10 @@ preserve case
print command
+printer driver
+
+printer driver location
+
print ok
printable
@@ -582,9 +685,9 @@ write list
.SS EXPLANATION OF EACH PARAMETER
.RS 3
-.SS admin users (G)
+.SS admin users (S)
-This is a list of users who will be granted administrative privilages
+This is a list of users who will be granted administrative privileges
on the share. This means that they will do all file operations as the
super-user (root).
@@ -598,6 +701,35 @@ file permissions.
.B Example:
admin users = jason
+.SS announce as (G)
+
+This specifies what type of server nmbd will announce itself as in
+browse lists. By default this is set to Windows NT. The valid options
+are "NT", "Win95" or "WfW" meaining Windows NT, Windows 95 and
+Windows for Workgroups respectively. Do not change this parameter
+unless you have a specific need to stop Samba appearing as an NT
+server as this may prevent Samba servers from participating as
+browser servers correctly.
+
+.B Default:
+ announce as = NT
+
+.B Example
+ announce as = Win95
+
+.SS announce version (G)
+
+This specifies the major and minor version numbers that nmbd
+will use when announcing itself as a server. The default is 4.2.
+Do not change this parameter unless you have a specific need to
+set a Samba server to be a downlevel server.
+
+.B Default:
+ announce version = 4.2
+
+.B Example:
+ announce version = 2.0
+
.SS auto services (G)
This is a list of services that you want to be automatically added to
the browse lists. This is most useful for homes and printers services
@@ -612,21 +744,21 @@ then the "load printers" option is easier.
.B Example:
auto services = fred lp colorlp
-
.SS allow hosts (S)
A synonym for this parameter is 'hosts allow'.
This parameter is a comma delimited set of hosts which are permitted to access
-a services. If specified in the [global] section, matching hosts will be
-allowed access to any service that does not specifically exclude them from
-access. Specific services my have their own list, which override those
-specified in the [global] section.
+a service.
+
+If specified in the [global] section then it will apply to all
+services, regardless of whether the individual service has a different
+setting.
You can specify the hosts by name or IP number. For example, you could
restrict access to only the hosts on a Class C subnet with something like
"allow hosts = 150.203.5.". The full syntax of the list is described in
the man page
-.B hosts_access(5).
+.BR hosts_access (5).
You can also specify hosts by network/netmask pairs and by netgroup
names if your system supports netgroups. The EXCEPT keyword can also
@@ -653,11 +785,13 @@ deny access from one particular host
Note that access still requires suitable user-level passwords.
-See testparm(1) for a way of testing your host access to see if it
+See
+.BR testparm (1)
+for a way of testing your host access to see if it
does what you expect.
.B Default:
- none (ie., all hosts permitted access)
+ none (i.e., all hosts permitted access)
.B Example:
allow hosts = 150.203.5. myhost.mynet.edu.au
@@ -665,12 +799,12 @@ does what you expect.
.SS alternate permissions (S)
This option affects the way the "read only" DOS attribute is produced
-for unix files. If this is false then the read only bit is set for
+for UNIX files. If this is false then the read only bit is set for
files on writeable shares which the user cannot write to.
If this is true then it is set for files whos user write bit is not set.
-The latter behaviour of useful for when users copy files from each
+The latter behaviour is useful for when users copy files from each
others directories, and use a file manager that preserves
permissions. Without this option they may get annoyed as all copied
files will have the "read only" bit set.
@@ -690,6 +824,40 @@ ALL attempts to connect to the service will fail. Such failures are logged.
.B Example:
available = no
+
+.SS bind interfaces only (G)
+This global parameter (new for 1.9.18) allows the Samba admin to limit
+what interfaces on a machine will serve smb requests. If affects file service
+(smbd) and name service (nmbd) in slightly different ways.
+
+For name service it causes nmbd to bind to ports 137 and 138 on
+the interfaces listed in the 'interfaces' parameter. nmbd also binds
+to the 'all addresses' interface (0.0.0.0) on ports 137 and 138
+for the purposes of reading broadcast messages. If this option is
+not set then nmbd will service name requests on all of these
+sockets. If "bind interfaces only" is set then nmbd will check
+the source address of any packets coming in on the broadcast
+sockets and discard any that don't match the broadcast addresses
+of the interfaces in the 'interfaces' parameter list. As unicast
+packets are received on the other sockets it allows nmbd to
+refuse to serve names to machines that send packets that arrive
+through any interfaces not listed in the 'interfaces' list.
+IP Source address spoofing does defeat this simple check, however
+so it must not be used seriously as a security feature for nmbd.
+
+For file service it causes smbd to bind only to the interface
+list given in the 'interfaces' parameter. This restricts the
+networks that smbd will serve to packets coming in those interfaces.
+Note that you should not use this parameter for machines that
+are serving ppp or other intermittant or non-broadcast network
+interfaces as it will not cope with non-permanent interfaces.
+
+.B Default:
+ bind interfaces only = False
+
+.B Example:
+ bind interfaces only = True
+
.SS browseable (S)
This controls whether this share is seen in the list of available
shares in a net view and in the browse list.
@@ -699,14 +867,71 @@ shares in a net view and in the browse list.
.B Example:
browseable = No
+.SS browse list(G)
+This controls whether the smbd will serve a browse list to a client
+doing a NetServerEnum call. Normally set to true. You should never
+need to change this.
+
+.B Default:
+ browse list = Yes
+
+.SS case sensitive (G)
+See the discussion on NAME MANGLING.
.SS case sig names (G)
See "case sensitive"
+.SS character set (G)
+This allows a smbd to map incoming characters from a DOS 850 Code page
+to either a Western European (ISO8859-1) or Easter European (ISO8859-2)
+code page. Normally not set, meaning no filename translation is done.
+
+.B Default
+
+ character set =
+
+.B Example
+
+ character set = iso8859-1
+
+.SS client code page (G)
+Currently (Samba 1.9.17 and above) this may be set to one of two
+values, 850 or 437. It specifies the base DOS code page that the
+clients accessing Samba are using. To determine this, open a DOS
+command prompt and type the command "chcp". This will output the
+code page. The default for USA MS-DOS, Windows 95, and Windows NT
+releases is code page 437. The default for western european
+releases of the above operating systems is code page 850.
+
+This parameter co-operates with the "valid chars" parameter in
+determining what characters are valid in filenames and how
+capitalization is done. It has been added as a convenience for
+clients whose code page is either 437 or 850 so a convoluted
+"valid chars" string does not have to be determined. If you
+set both this parameter and the "valid chars" parameter the
+"client code page" parameter MUST be set before the "valid chars"
+in the smb.conf file. The "valid chars" string will then augment
+the character settings in the "client code page" parameter.
+
+If "client code page" is set to a value other than 850 or 437
+it will default to 850.
+
+See also : "valid chars".
+
+.B Default
+
+ client code page = 850
+
+.B Example
+
+ client code page = 437
+
.SS comment (S)
-This is a text field that is seen when a client does a net view to
-list what shares are available. It will also be used when browsing is
-fully supported.
+This is a text field that is seen next to a share when a client does a
+net view to list what shares are available.
+
+If you want to set the string that is displayed next to the machine
+name then see the server string command.
.B Default:
No comment string
@@ -726,11 +951,11 @@ file.
This option takes the usual substitutions, which can be very useful.
-If thew config file doesn't exist then it won't be loaded (allowing
+If the config file doesn't exist then it won't be loaded (allowing
you to special case the config files of just a few clients).
.B Example:
- config file = /usr/local/samba/smb.conf.%m
+ config file = /usr/local/samba/lib/smb.conf.%m
.SS copy (S)
This parameter allows you to 'clone' service entries. The specified
@@ -750,20 +975,37 @@ in the configuration file than the service doing the copying.
.SS create mask (S)
A synonym for this parameter is 'create mode'.
-This parameter is the octal modes which are used when converting DOS modes
-to Unix modes.
+When a file is created, the neccessary permissions are calculated
+according to the mapping from DOS modes to UNIX permissions, and
+the resulting UNIX mode is then bit-wise 'AND'ed with this parameter.
+This parameter may be thought of as a bit-wise MASK for the UNIX
+modes of a file. Any bit *not* set here will be removed from the
+modes set on a file when it is created.
+
+The default value of this parameter removes the 'group' and 'other'
+write and execute bits from the UNIX modes.
+
+Following this Samba will bit-wise 'OR' the UNIX mode created from
+this parameter with the value of the "force create mode" parameter
+which is set to 000 by default.
+
+For Samba 1.9.17 and above this parameter no longer affects directory
+modes. See the parameter 'directory mode' for details.
-Note that Samba will or this value with 0700 as you must have at least
-user read, write and execute for Samba to work properly.
+See also the "force create mode" parameter for forcing particular
+mode bits to be set on created files.
+See also the "directory mode" parameter for masking mode bits on created
+directories.
.B Default:
- create mask = 0755
+ create mask = 0744
.B Example:
create mask = 0775
.SS create mode (S)
See
.B create mask.
+
.SS dead time (G)
The value of the parameter (a decimal integer) represents the number of
minutes of inactivity before a connection is considered dead, and it
@@ -788,7 +1030,9 @@ A deadtime of zero indicates that no auto-disconnection should be performed.
dead time = 15
.SS debug level (G)
The value of the parameter (an integer) allows the debug level
-(logging level) to be specified in the smb.conf file. This is to give
+(logging level) to be specified in the
+.B smb.conf
+file. This is to give
greater flexibility in the configuration of the system.
The default will be the debug level specified on the command line.
@@ -815,7 +1059,7 @@ attempting to connect to a nonexistent service results in an error.
Typically the default service would be a public, read-only service.
-Also not that s of 1.9.14 the apparent service name will be changed to
+Also note that as of 1.9.14 the apparent service name will be changed to
equal that of the requested service, this is very useful as it allows
you to use macros like %S to make a wildcard service.
@@ -831,6 +1075,19 @@ things.
path = /%S
+.SS delete readonly (S)
+This parameter allows readonly files to be deleted. This is not normal DOS
+semantics, but is allowed by UNIX.
+
+This option may be useful for running applications such as rcs, where UNIX
+file ownership prevents changing file permissions, and DOS semantics prevent
+deletion of a read only file.
+
+.B Default:
+ delete readonly = No
+
+.B Example:
+ delete readonly = Yes
.SS deny hosts (S)
A synonym for this parameter is 'hosts deny'.
@@ -839,10 +1096,38 @@ access to services unless the specific services have their own lists to
override this one. Where the lists conflict, the 'allow' list takes precedence.
.B Default:
- none (ie., no hosts specifically excluded)
+ none (i.e., no hosts specifically excluded)
.B Example:
deny hosts = 150.203.4. badhost.mynet.edu.au
+
+.SS delete veto files (S)
+
+This option is used when Samba is attempting to delete a directory
+that contains one or more vetoed directories (see the 'veto files' option).
+If this option is set to False (the default) then if a vetoed directory
+contains any non-vetoed files or directories then the directory delete
+will fail. This is usually what you want.
+
+If this option is set to True, then Samba will attempt
+to recursively delete any files and directories within the vetoed
+directory. This can be useful for integration with file serving
+systems such as Netatalk, which create meta-files within directories
+you might normally veto DOS/Windows users from seeing (eg. .AppleDouble)
+
+Setting 'delete veto files = True' allows these directories to be
+transparently deleted when the parent directory is deleted (so long
+as the user has permissions to do so).
+
+.B Default:
+ delete veto files = False
+
+.B Example:
+ delete veto files = True
+
+See
+.B veto files
+
.SS dfree command (G)
The dfree command setting should only be used on systems where a
problem occurs with the internal disk space calculations. This has
@@ -870,24 +1155,143 @@ Note: Your script should NOT be setuid or setgid and should be owned by
and remaining space will be used.
.B Example:
- dfree command = /usr/local/smb/dfree
+ dfree command = /usr/local/samba/bin/dfree
Where the script dfree (which must be made executable) could be
- #!/bin/sh
- df $1 | tail -1 | awk '{print $2" "$4}'
+.nf
+ #!/bin/sh
+ df $1 | tail -1 | awk '{print $2" "$4}'
+.fi
or perhaps (on Sys V)
+.nf
#!/bin/sh
/usr/bin/df -k $1 | tail -1 | awk '{print $3" "$5}'
-
+.fi
Note that you may have to replace the command names with full
path names on some systems.
.SS directory (S)
See
.B path.
+
+.SS directory mask (S)
+A synonym for this parameter is 'directory mode'.
+
+This parameter is the octal modes which are used when converting DOS modes
+to UNIX modes when creating UNIX directories.
+
+When a directory is created, the neccessary permissions are calculated
+according to the mapping from DOS modes to UNIX permissions, and
+the resulting UNIX mode is then bit-wise 'AND'ed with this parameter.
+This parameter may be thought of as a bit-wise MASK for the UNIX
+modes of a directory. Any bit *not* set here will be removed from the
+modes set on a directory when it is created.
+
+The default value of this parameter removes the 'group' and 'other'
+write bits from the UNIX mode, allowing only the user who owns the
+directory to modify it.
+
+Following this Samba will bit-wise 'OR' the UNIX mode created from
+this parameter with the value of the "force directory mode" parameter.
+This parameter is set to 000 by default (ie. no extra mode bits are added).
+
+See the "force directory mode" parameter to cause particular mode
+bits to always be set on created directories.
+
+See also the "create mode" parameter for masking mode bits on created
+files.
+
+.B Default:
+ directory mask = 0755
+
+.B Example:
+ directory mask = 0775
+
+.SS directory mode (S)
+See
+.B directory mask.
+
+.SS dns proxy (G)
+
+Specifies that nmbd should (as a WINS server), on finding that a NetBIOS
+name has not been registered, treat the NetBIOS name word-for-word as
+a DNS name.
+
+Note that the maximum length for a NetBIOS name is 15
+characters, so the DNS name (or DNS alias) can likewise only be 15
+characters, maximum.
+
+Note also that nmbd will block completely until the DNS name is resolved.
+This will result in temporary loss of browsing and WINS services.
+Enable this option only if you are certain that DNS resolution is fast,
+or you can live with the consequences of periodic pauses in nmbd service.
+
+.B Default:
+ dns proxy = yes
+
+.SS domain controller (G)
+
+Specifies the DNS name or IP address of the machine to refer domain
+logons from Win95 machines to. You should never need to set this parameter.
+
+.B Default:
+ domain controller = no
+
+.SS domain groups (G)
+
+Specifies the NT Domain groups that the user belongs to, and the attributes
+associated with that group. This parameter is a white-space separated list
+of group ids (in decimal), followed by an option attribute (in decimal) which
+defaults to a value of 7 if not specified. A group id and the user attributes
+associated with it are separated by "/".
+
+.B
+It is known that attributes are ignored by NT 4.0 Workstation, but not by
+NT 3.51 Workstation. Furthermore, no information on the exact meaning of
+NT Domain groups is presently known.
+
+.B Default:
+ domain groups = 776/7
+
+.B Example:
+ domain groups = 776 1024/7 777
+
+.SS domain sid (G)
+
+Specifies the SID when using Samba as a Logon Server for NT Workstations.
+The format of SIDs supported by samba at present is S-1-N-nnn-nnn-nnn-nnn-nnn.
+The number N indicates the number of sub-authorities (nnn).
+
+.B Default:
+ domain sid = none
+
+.B Example:
+ domain sid = S-1-5-21-123-456-789-123
+
+.SS domain logons (G)
+
+If set to true, the Samba server will serve Windows 95 domain logons
+for the workgroup it is in. For more details on setting up this feature
+see the file DOMAINS.txt in the Samba source documentation directory.
+
+.B Default:
+ domain logons = no
+
+.SS domain master (G)
+
+Enable WAN-wide browse list collation. Local master browsers on
+broadcast-isolated subnets will give samba their local browse lists, and
+ask for a complete copy of the browse list for the whole wide area network.
+Browser clients will then contact their local master browser, and will
+receive the domain-wide browse list, instead of just the list for their
+broadcast-isolated subnet.
+
+.B Default:
+ domain master = no
+
.SS dont descend (S)
There are certain directories on some systems (eg., the /proc tree under
Linux) that are either not of interest to clients or are infinitely deep
@@ -895,19 +1299,35 @@ Linux) that are either not of interest to clients or are infinitely deep
of directories that the server should always show as empty.
Note that Samba can be very fussy about the exact format of the "dont
-descend" entries. For example you ma need "./proc" instead of just
+descend" entries. For example you may need "./proc" instead of just
"/proc". Experimentation is the best policy :-)
.B Default:
- none (ie., all directories are OK to descend)
+ none (i.e., all directories are OK to descend)
.B Example:
dont descend = /proc,/dev
+.SS dos filetimes (S)
+Under DOS and Windows, if a user can write to a file they can change
+the timestamp on it. Under POSIX semantics, only the owner of the file
+or root may change the timestamp. By default, Samba runs with POSIX
+semantics and refuses to change the timestamp on a file if the user
+smbd is acting on behalf of is not the file owner. Setting this option
+to True allows DOS semantics and smbd will change the file timstamp as
+DOS requires. This is a correct implementation of a previous compile-time
+options (UTIME_WORKAROUND) which was broken and is now removed.
+
+.B Default:
+ dos filetimes = False
+
+.B Example:
+ dos filetimes = True
+
.SS encrypt passwords (G)
This boolean controls whether encrypted passwords will be negotiated
-with the cient. Note that this option has no effect if you haven't
+with the client. Note that this option has no effect if you haven't
compiled in the necessary des libraries and encryption code. It
defaults to no.
@@ -915,6 +1335,86 @@ defaults to no.
This is an alias for preexec
+.SS fake oplocks (S)
+
+Oplocks are the way that SMB clients get permission from a server to
+locally cache file operations. If a server grants an oplock
+(opportunistic lock) then the client is free to assume that it is the
+only one accessing the file and it will aggressively cache file
+data. With some oplock types the client may even cache file open/close
+operations. This can give enormous performance benefits.
+
+When you set "fake oplocks = yes" Samba will always grant oplock
+requests no matter how many clients are using the file.
+
+By enabling this option on all read-only shares or shares that you know
+will only be accessed from one client at a time you will see a big
+performance improvement on many operations. If you enable this option
+on shares where multiple clients may be accessing the files read-write
+at the same time you can get data corruption. Use this option
+carefully!
+
+It is generally much better to use the real oplock support except for
+physically read-only media such as CDROMs.
+
+This option is disabled by default.
+
+.SS follow symlinks (S)
+
+This parameter allows the Samba administrator to stop smbd from
+following symbolic links in a particular share. Setting this
+parameter to "No" prevents any file or directory that is a
+symbolic link from being followed (the user will get an error).
+This option is very useful to stop users from adding a symbolic
+link to /etc/pasword in their home directory for instance.
+However it will slow filename lookups down slightly.
+
+This option is enabled (ie. smbd will follow symbolic links)
+by default.
+
+.SS force create mode (S)
+This parameter specifies a set of UNIX mode bit permissions that
+will *always* be set on a file created by Samba. This is done
+by bitwise 'OR'ing these bits onto the mode bits of a file that
+is being created. The default for this parameter is (in octel)
+000. The modes in this parameter are bitwise 'OR'ed onto the
+file mode after the mask set in the "create mask" parameter
+is applied.
+
+See also the parameter "create mask" for details on masking mode
+bits on created files.
+
+.B Default:
+ force create mode = 000
+
+.B Example:
+ force create mode = 0755
+
+would force all created files to have read and execute permissions
+set for 'group' and 'other' as well as the read/write/execute bits
+set for the 'user'.
+
+.SS force directory mode (S)
+This parameter specifies a set of UNIX mode bit permissions that
+will *always* be set on a directory created by Samba. This is done
+by bitwise 'OR'ing these bits onto the mode bits of a directory that
+is being created. The default for this parameter is (in octel)
+0000 which will not add any extra permission bits to a created
+directory. This operation is done after the mode mask in the parameter
+"directory mask" is applied.
+
+See also the parameter "directory mask" for details on masking mode
+bits on created directories.
+
+.B Default:
+ force directory mode = 000
+
+.B Example:
+ force directory mode = 0755
+
+would force all created directories to have read and execute permissions
+set for 'group' and 'other' as well as the read/write/execute bits
+set for the 'user'.
.SS force group (S)
This specifies a group name that all connections to this service
@@ -943,6 +1443,21 @@ password. Once connected, all file operations will be performed as the
.B Example:
force user = auser
+.SS getwd cache (G)
+This is a tuning option. When this is enabled a cacheing algorithm will
+be used to reduce the time taken for getwd() calls. This can have a
+significant impact on performance, especially when widelinks is False.
+
+.B Default:
+ getwd cache = No
+
+.B Example:
+ getwd cache = Yes
+
+.SS group (S)
+This is an alias for "force group" and is only kept for compatibility
+with old versions of Samba. It may be removed in future versions.
+
.SS guest account (S)
This is a username which will be used for access to services which are
specified as 'guest ok' (see below). Whatever privileges this user has
@@ -953,8 +1468,9 @@ the specified username overrides this one.
One some systems the account "nobody" may not be able to print. Use
another account in this case. You should test this by trying to log in
-as your guest user (perhaps by using the "su -" command) and trying to
-print using lpr.
+as your guest user (perhaps by using the "su \-" command) and trying to
+print using
+.BR lpr .
Note that as of version 1.9 of Samba this option may be set
differently for each service.
@@ -964,16 +1480,6 @@ differently for each service.
.B Example:
guest account = nobody
-.SS getwd cache (G)
-This is a tuning option. When this is enabled a cacheing algorithm will
-be used to reduce the time taken for getwd() calls. This can have a
-significant impact on performance, especially when widelinks is False.
-
-.B Default:
- getwd cache = No
-
-.B Example:
- getwd cache = Yes
.SS guest ok (S)
See
.B public.
@@ -999,6 +1505,62 @@ a dot appear as hidden files.
.B Example:
hide dot files = no
+
+
+.SS hide files(S)
+This is a list of files or directories that are not visible but are
+accessible. The DOS 'hidden' attribute is applied to any files or
+directories that match.
+
+Each entry in the list must be separated by a "/", which allows spaces
+to be included in the entry. '*' and '?' can be used to specify multiple
+files or directories as in DOS wildcards.
+
+Each entry must be a unix path, not a DOS path and must not include the
+unix directory separator "/".
+
+Note that the case sensitivity option is applicable in hiding files.
+
+Setting this parameter will affect the performance of Samba, as
+it will be forced to check all files and directories for a match
+as they are scanned.
+
+See also "hide dot files", "veto files" and "case sensitive"
+
+.B Default
+ No files or directories are hidden by this option (dot files are
+ hidden by default because of the "hide dot files" option).
+
+.B Example
+ hide files = /.*/DesktopFolderDB/TrashFor%m/resource.frk/
+
+The above example is based on files that the Macintosh client (DAVE)
+creates for internal use, and also still hides all files beginning with
+a dot.
+
+.SS homedir map (G)
+If "nis homedir" is true, this parameter specifies the NIS (or YP) map
+from which the server for the user's home directory should be extracted.
+At present, only the Sun auto.home map format is understood. The form of
+the map is:
+
+username server:/some/file/system
+
+and the program will extract the servername from before the first ':'.
+There should probably be a better parsing system that copes with different
+map formats and also Amd (another automounter) maps.
+
+NB: The -DNETGROUP option is required in the Makefile for option to work
+and on some architectures the line -lrpcsvc needs to be added to the
+LIBSM variable. This is required for Solaris 2, FreeBSD and HPUX.
+
+See also "nis homedir"
+
+.B Default:
+ homedir map = auto.home
+
+.B Example:
+ homedir map = amd.homedir
.SS hosts allow (S)
See
.B allow hosts.
@@ -1006,10 +1568,6 @@ See
See
.B deny hosts.
-.SS group (S)
-This is an alias for "force group" and is only kept for compatability
-with old versions of Samba. It may be removed in future versions.
-
.SS hosts equiv (G)
If this global parameter is a non-null string, it specifies the name of
a file to read for the names of hosts and users who will be allowed access
@@ -1033,12 +1591,44 @@ or perhaps on a home network where you trust your wife and kids :-)
.B Example
hosts equiv = /etc/hosts.equiv
+.SS include (G)
+
+This allows you to include one config file inside another. The file is
+included literally, as though typed in place.
+
+It takes the standard substitutions, except %u, %P and %S
+
+.SS interfaces (G)
+
+This option allows you to setup multiple network interfaces, so that
+Samba can properly handle browsing on all interfaces.
+
+The option takes a list of ip/netmask pairs. The netmask may either be
+a bitmask, or a bitlength.
+
+For example, the following line:
+
+interfaces = 192.168.2.10/24 192.168.3.10/24
+
+would configure two network interfaces with IP addresses 192.168.2.10
+and 192.168.3.10. The netmasks of both interfaces would be set to
+255.255.255.0.
+
+You could produce an equivalent result by using:
+
+interfaces = 192.168.2.10/255.255.255.0 192.168.3.10/255.255.255.0
+
+if you prefer that format.
+
+If this option is not set then Samba will attempt to find a primary
+interface, but won't attempt to configure more than one interface.
+
.SS invalid users (S)
This is a list of users that should not be allowed to login to this
service. This is really a "paranoid" check to absolutely ensure an
improper setting does not breach your security.
-A name starting with @ is interpreted as a unix group.
+A name starting with @ is interpreted as a UNIX group.
The current servicename is substituted for %S. This is useful in the
[homes] section.
@@ -1051,13 +1641,6 @@ See also "valid users"
.B Example
invalid users = root fred admin @wheel
-.SS include (G)
-
-This allows you to inlcude one config file inside another. the file is
-included literally, as though typed in place.
-
-It takes the standard substitutions, except %u, %P and %S
-
.SS keep alive (G)
The value of the parameter (an integer) represents the number of seconds
between 'keepalive' packets. If this parameter is zero, no keepalive packets
@@ -1079,20 +1662,32 @@ A boolean variable that controls whether all printers in the printcap
will be loaded for browsing by default.
.B Default:
- load printers = no
+ load printers = yes
.B Example:
- load printers = yes
+ load printers = no
+
+.SS local master (G)
+This option allows the nmbd to become a local master browser on a
+subnet. If set to False then nmbd will not attempt to become a local
+master browser on a subnet and will also lose in all browsing elections.
+By default this value is set to true. Setting this value to true doesn't
+mean that Samba will become the local master browser on a subnet, just
+that the nmbd will participate in elections for local master browser.
+
+.B Default:
+ local master = yes
.SS lock directory (G)
-This options specifies the directory where lock files will be placed.
+This option specifies the directory where lock files will be placed.
The lock files are used to implement the "max connections" option.
.B Default:
lock directory = /tmp/samba
.B Example:
- lock directory = /usr/local/samba/locks
+ lock directory = /usr/local/samba/var/locks
+
.SS locking (S)
This controls whether or not locking will be performed by the server in
response to lock requests from the client.
@@ -1123,11 +1718,102 @@ This option takes the standard substitutions, allowing you to have
separate log files for each user or machine.
.B Example:
- log file = /usr/local/samba/log.%m
+ log file = /usr/local/samba/var/log.%m
.SS log level (G)
see "debug level"
+.SS logon drive (G)
+
+This parameter specifies the local path to which the home directory
+will be connected (see "logon home") and is only used by NT Workstations.
+
+.B Example:
+ logon drive = h:
+
+.SS logon home (G)
+
+This parameter specifies the home directory location when a Win95 or
+NT Workstation logs into a Samba PDC. It allows you to do "NET USE
+H: /HOME" from a command prompt, for example.
+
+.B
+This option takes the standard substitutions, allowing you to have
+separate logon scripts for each user or machine.
+
+.B Example:
+ logon home = "\\\\remote_smb_server\\%U"
+
+.B Default:
+ logon home = "\\\\%N\\%U"
+
+.SS logon path (G)
+
+This parameter specifies the home directory where roaming profiles
+(USER.DAT / USER.MAN files for Windows 95) are stored.
+
+This option takes the standard substitutions, allowing you to have
+separate logon scripts for each user or machine. It also specifies
+the directory from which the "desktop", "start menu", "nethood" and
+"programs" folders, and their contents, are loaded and displayed
+on your Windows 95 client.
+
+The share and the path must be readable by the user for the preferences
+and directories to be loaded onto the Windows 95 client. The share
+must be writeable when the logs in for the first time, in order that
+the Windows 95 client can create the user.dat and other directories.
+
+Thereafter, the directories and any of contents can, if required,
+be made read-only. It is not adviseable that the USER.DAT file be made
+read-only - rename it to USER.MAN to achieve the desired effect
+(a MANdatory profile).
+
+Windows clients can sometimes maintain a connection to the [homes]
+share, even though there is no user logged in. Therefore, it is
+vital that the logon path does not include a reference to the
+homes share (i.e \\\\%N\\HOMES\profile_path will cause problems).
+
+.B
+This option takes the standard substitutions, allowing you to have
+separate logon scripts for each user or machine.
+
+.B Default:
+ logon path = \\\\%N\\%U\\profile
+
+.B Example:
+ logon path = \\\\PROFILESERVER\\HOME_DIR\\%U\\PROFILE
+
+.SS logon script (G)
+
+This parameter specifies the batch file (.bat) or NT command file (.cmd)
+to be downloaded and run on a machine when a user successfully logs in.
+The file must contain the DOS style cr/lf line endings. Using a DOS-style
+editor to create the file is recommended.
+
+The script must be a relative path to the [netlogon] service. If the
+[netlogon] service specifies a path of /usr/local/samba/netlogon, and
+logon script = STARTUP.BAT, then file that will be downloaded is:
+
+.B /usr/local/samba/netlogon/STARTUP.BAT
+
+The contents of the batch file is entirely your choice. A suggested
+command would be to add NET TIME \\\\SERVER /SET /YES, to force every
+machine to synchronise clocks with the same time server. Another use
+would be to add NET USE U: \\\\SERVER\\UTILS for commonly used utilities,
+or NET USE Q: \\\\SERVER\\ISO9001_QA.
+
+Note that it is particularly important not to allow write access to
+the [netlogon] share, or to grant users write permission on the
+batch files in a secure environment, as this would allow the batch
+files to be arbitrarily modified.
+
+.B
+This option takes the standard substitutions, allowing you to have
+separate logon scripts for each user or machine.
+
+.B Example:
+ logon script = scripts/%U.bat
+
.SS lppause command (S)
This parameter specifies the command to be executed on the server host in
order to stop printing or spooling a specific print job.
@@ -1137,9 +1823,11 @@ job number to pause the print job. Currently I don't know of any print
spooler system that can do this with a simple option, except for the PPR
system from Trinity College (ppr\-dist.trincoll.edu/pub/ppr). One way
of implementing this is by using job priorities, where jobs having a too
-low priority wont be sent to the printer. See also the lppause command.
+low priority won't be sent to the printer. See also the
+.B lppause
+command.
-If a %p is given then the printername is put in it's place. A %j is
+If a %p is given then the printername is put in its place. A %j is
replaced with the job number (an integer).
On HPUX (see printing=hpux), if the -p%p option is added to the lpq
command, the job will show up with the correct status, i.e. if the job
@@ -1187,9 +1875,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, LPRNG 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
@@ -1197,7 +1885,7 @@ about. To get around this, the server reports on the first printer service
connected to by the client. This only happens if the connection number sent
is invalid.
-If a %p is given then the printername is put in it's place. Otherwise
+If a %p is given then the printername is put in its place. Otherwise
it is placed at the end of the command.
Note that it is good practice to include the absolute path in the lpq
@@ -1216,7 +1904,7 @@ order to restart or continue printing or spooling a specific print job.
This command should be a program or script which takes a printer name and
job number to resume the print job. See also the lppause command.
-If a %p is given then the printername is put in it's place. A %j is
+If a %p is given then the printername is put in its place. A %j is
replaced with the job number (an integer).
Note that it is good practice to include the absolute path in the lpresume
@@ -1235,11 +1923,11 @@ 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
-expected using the "printing =" option.
+Currently seven styles of printer control are supported; BSD, SYSV, AIX
+HPUX, QNX, LPRNG 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
+If a %p is given then the printername is put in its place. A %j is
replaced with the job number (an integer).
Note that it is good practice to include the absolute path in the lprm
@@ -1269,7 +1957,7 @@ output file content is undefined.
magic output = myfile.txt
.SS magic script (S)
This parameter specifies the name of a file which, if opened, will be
-executed by the server when the file is closed. This allows a Unix script
+executed by the server when the file is closed. This allows a UNIX script
to be sent to the Samba host and executed on behalf of the connected user.
Scripts executed in this way will be deleted upon completion, permissions
@@ -1286,17 +1974,23 @@ marker. Magic scripts must be executable "as is" on the host, which
for some hosts and some shells will require filtering at the DOS end.
Magic scripts are EXPERIMENTAL and should NOT be relied upon.
+
.B Default:
None. Magic scripts disabled.
.B Example:
magic script = user.csh
+
+.SS mangle case (S)
+
+See the section on "NAME MANGLING"
+
.SS mangled map (S)
This is for those who want to directly map UNIX file names which are
not representable on DOS. The mangling of names is not always what is
-needed. In particular you may have documents with file extensiosn
-that differ between dos and unix. For example, under unix it is common
-to use .html for HTML files, whereas under dos .htm is more commonly
+needed. In particular you may have documents with file extensions
+that differ between DOS and UNIX. For example, under UNIX it is common
+to use .html for HTML files, whereas under DOS .htm is more commonly
used.
So to map 'html' to 'htm' you put:
@@ -1304,7 +1998,7 @@ So to map 'html' to 'htm' you put:
mangled map = (*.html *.htm)
One very useful case is to remove the annoying ;1 off the ends of
-filenames on some CDROMS (only visible under some unixes). To do this
+filenames on some CDROMS (only visible under some UNIXes). To do this
use a map of (*;1 *)
.B default:
@@ -1313,12 +2007,8 @@ use a map of (*;1 *)
.B Example:
mangled map = (*;1 *)
-.SS mangle case (S)
-
-See the section on "NAME MANGLING"
-
.SS mangled names (S)
-This controls whether non-DOS names under Unix should be mapped to
+This controls whether non-DOS names under UNIX should be mapped to
DOS-compatible names ("mangled") and made visible, or whether non-DOS names
should simply be ignored.
@@ -1332,7 +2022,7 @@ the filename are preserved, forced to upper case, and appear as the first (up
to) five characters of the mangled name.
- a tilde ("~") is appended to the first part of the mangled name, followed
-by a two-character unique sequence, based on the origonal root name
+by a two-character unique sequence, based on the original root name
(i.e., the original filename minus its final extension). The final
extension is included in the hash calculation only if it contains any upper
case characters or is longer than three characters.
@@ -1346,7 +2036,7 @@ final extension is defined as that part of the original filename after the
rightmost dot. If there are no dots in the filename, the mangled name will
have no extension (except in the case of hidden files - see below).
-- files whose Unix name begins with a dot will be presented as DOS hidden
+- files whose UNIX name begins with a dot will be presented as DOS hidden
files. The mangled name will be created as for other filenames, but with the
leading dot removed and "___" as its extension regardless of actual original
extension (that's three underscores).
@@ -1358,8 +2048,8 @@ This algorithm can cause name collisions only if files in a directory share
the same first five alphanumeric characters. The probability of such a clash
is 1/1300.
-The name mangling (if enabled) allows a file to be copied between Unix
-directories from DOS while retaining the long Unix filename. Unix files can
+The name mangling (if enabled) allows a file to be copied between UNIX
+directories from DOS while retaining the long UNIX filename. UNIX files can
be renamed to a new extension from DOS and will retain the same basename.
Mangled names do not change between sessions.
@@ -1379,33 +2069,6 @@ software. Use this option to set it to whatever you prefer.
.B Example:
mangling char = ^
-.SS max log size (G)
-
-This option (an integer in kilobytes) specifies the max size the log
-file should grow to. Samba periodically checks the size and if it is
-exceeded it will rename the file, adding a .old extension.
-
-A size of 0 means no limit.
-
-.B Default:
- max log size = 5000
-
-.B Example:
- max log size = 1000
-
-.SS max xmit (G)
-
-This option controls the maximum packet size that will be negotiated
-by Samba. The default is 65535, which is the maximum. In some cases
-you may find you get better performance with a smaller value. A value
-below 2048 is likely to cause problems.
-
-.B Default:
- max xmit = 65535
-
-.B Example:
- max xmit = 8192
-
.SS mangled stack (G)
This parameter controls the number of mangled names that should be cached in
the Samba server.
@@ -1415,7 +2078,7 @@ maintained if they are longer than 3 characters or contains upper case
characters).
The larger this value, the more likely it is that mangled names can be
-successfully converted to correct long Unix names. However, large stack
+successfully converted to correct long UNIX names. However, large stack
sizes will slow most directory access. Smaller stacks save memory in the
server (each stack element costs 256 bytes).
@@ -1429,12 +2092,16 @@ be prepared for some surprises!
mangled stack = 100
.SS map archive (S)
-This controls whether the DOS archive attribute should be mapped to Unix
-execute bits. The DOS archive bit is set when a file has been modified
+This controls whether the DOS archive attribute should be mapped to the
+UNIX owner execute bit. The DOS archive bit is set when a file has been modified
since its last backup. One motivation for this option it to keep Samba/your
PC from making any file it touches from becoming executable under UNIX.
This can be quite annoying for shared source code, documents, etc...
+Note that this requires the 'create mask' to be set such that owner
+execute bit is not masked out (ie. it must include 100). See the
+parameter "create mask" for details.
+
.B Default:
map archive = yes
@@ -1442,8 +2109,12 @@ This can be quite annoying for shared source code, documents, etc...
map archive = no
.SS map hidden (S)
-This controls whether DOS style hidden files should be mapped to Unix
-execute bits.
+This controls whether DOS style hidden files should be mapped to the
+UNIX world execute bit.
+
+Note that this requires the 'create mask' to be set such that the world
+execute bit is not masked out (ie. it must include 001).
+See the parameter "create mask" for details.
.B Default:
map hidden = no
@@ -1451,8 +2122,12 @@ execute bits.
.B Example:
map hidden = yes
.SS map system (S)
-This controls whether DOS style system files should be mapped to Unix
-execute bits.
+This controls whether DOS style system files should be mapped to the
+UNIX group execute bit.
+
+Note that this requires the 'create mask' to be set such that the group
+execute bit is not masked out (ie. it must include 010). See the parameter
+"create mask" for details.
.B Default:
map system = no
@@ -1474,23 +2149,76 @@ will be stored in the directory specified by the "lock directory" option.
.B Example:
max connections = 10
-.SS only user (S)
-This is a boolean option that controls whether connections with
-usernames not in the user= list will be allowed. By default this
-option is disabled so a client can supply a username to be used by
-the server.
-Note that this also means Samba won't try to deduce usernames from the
-service name. This can be annoying for the [homes] section. To get
-around this you could use "user = %S" which means your "user" list
-will be just the service name, which for home directories is the name
-of the user.
+.SS max disk size (G)
+This option allows you to put an upper limit on the apparent size of
+disks. If you set this option to 100 then all shares will appear to be
+not larger than 100 MB in size.
-.B Default:
- only user = False
+Note that this option does not limit the amount of data you can put on
+the disk. In the above case you could still store much more than 100
+MB on the disk, but if a client ever asks for the amount of free disk
+space or the total disk size then the result will be bounded by the
+amount specified in "max disk size".
-.B Example:
- only user = True
+This option is primarily useful to work around bugs in some pieces of
+software that can't handle very large disks, particularly disks over
+1GB in size.
+
+A "max disk size" of 0 means no limit.
+
+.B Default:
+ max disk size = 0
+
+.B Example:
+ max disk size = 1000
+
+.SS max log size (G)
+
+This option (an integer in kilobytes) specifies the max size the log
+file should grow to. Samba periodically checks the size and if it is
+exceeded it will rename the file, adding a .old extension.
+
+A size of 0 means no limit.
+
+.B Default:
+ max log size = 5000
+
+.B Example:
+ max log size = 1000
+
+.SS max mux (G)
+
+This option controls the maximum number of outstanding simultaneous SMB
+operations that samba tells the client it will allow. You should never need
+to set this parameter.
+
+.B Default:
+ max mux = 50
+
+.SS max packet (G)
+
+A synonym for this parameter is 'packet size'.
+
+.SS max ttl (G)
+
+This option tells nmbd what the default 'time to live' of NetBIOS
+names should be (in seconds). You should never need to change this parameter.
+
+.B Default:
+ max ttl = 14400
+.SS max xmit (G)
+
+This option controls the maximum packet size that will be negotiated
+by Samba. The default is 65535, which is the maximum. In some cases
+you may find you get better performance with a smaller value. A value
+below 2048 is likely to cause problems.
+
+.B Default:
+ max xmit = 65535
+
+.B Example:
+ max xmit = 8192
.SS message command (G)
@@ -1540,7 +2268,7 @@ If you want to silently delete it then try "message command = rm %s".
For the really adventurous, try something like this:
-message command = csh -c 'csh < %s |& /usr/local/samba/smbclient \\
+message command = csh -c 'csh < %s |& /usr/local/samba/bin/smbclient \e
-M %m; rm %s' &
this would execute the command as a script on the server, then give
@@ -1566,6 +2294,54 @@ kilobytes. The default is 0, which means no limit.
.B Example:
min print space = 2000
+.SS netbios aliases (G)
+
+This is a list of names that nmbd will advertise as additional
+names by which the Samba server is known. This allows one machine
+to appear in browse lists under multiple names. If a machine is
+acting as a browse server or logon server none of these names
+will be advertised as either browse server or logon servers, only
+the primary name of the machine will be advertised with these
+capabilities.
+
+See also 'netbios name'.
+
+.B Example:
+ netbios aliases = TEST TEST1 TEST2
+
+.SS netbios name (G)
+
+This sets the NetBIOS name by which a Samba server is known. By
+default it is the same as the first component of the host's DNS name.
+If a machine is a browse server or logon server this name (or the
+first component of the hosts DNS name) will be the name that these
+services are advertised under.
+
+See also 'netbios aliases'.
+
+.B Example:
+ netbios name = MYNAME
+
+.SS nis homedir (G)
+Get the home share server from a NIS (or YP) map. For unix systems that
+use an automounter, the user's home directory will often be mounted on
+a workstation on demand from a remote server. When the Samba logon server
+is not the actual home directory server, two network hops are required
+to access the home directory and this can be very slow especially with
+writing via Samba to an NFS mounted directory. This option allows samba
+to return the home share as being on a different server to the logon
+server and as long as a samba daemon is running on the home directory
+server, it will be mounted on the Samba client directly from the directory
+server. When Samba is returning the home share to the client, it will
+consult the NIS (or YP) map specified in "homedir map" and return the
+server listed there.
+
+.B Default:
+ nis homedir = false
+
+.B Example:
+ nis homedir = true
+
.SS null passwords (G)
Allow or disallow access to accounts that have null passwords.
@@ -1575,6 +2351,43 @@ Allow or disallow access to accounts that have null passwords.
.B Example:
null passwords = yes
+.SS only guest (S)
+A synonym for this command is 'guest only'.
+
+.SS only user (S)
+This is a boolean option that controls whether connections with
+usernames not in the user= list will be allowed. By default this
+option is disabled so a client can supply a username to be used by
+the server.
+
+Note that this also means Samba won't try to deduce usernames from the
+service name. This can be annoying for the [homes] section. To get
+around this you could use "user = %S" which means your "user" list
+will be just the service name, which for home directories is the name
+of the user.
+
+.B Default:
+ only user = False
+
+.B Example:
+ only user = True
+
+.SS oplocks (S)
+This boolean option tells smbd whether to issue oplocks (opportunistic
+locks) to file open requests on this share. The oplock code was introduced in
+Samba 1.9.18 and can dramatically (approx 30% or more) improve the speed
+of access to files on Samba servers. It allows the clients to agressively
+cache files locally and you may want to disable this option for unreliable
+network environments (it is turned on by default in Windows NT Servers).
+For more information see the file Speed.txt in the Samba docs/ directory.
+
+.B Default:
+ oplocks = True
+
+.B Example:
+ oplocks = False
+
+
.SS os level (G)
This integer value controls what level Samba advertises itself as for
browse elections. See BROWSING.txt for details.
@@ -1585,19 +2398,19 @@ longer implemented as of version 1.7.00, and is kept only so old
configuration files do not become invalid.
.SS passwd chat (G)
-This string coontrols the "chat" conversation that takes places
+This string controls the "chat" conversation that takes places
between smbd and the local password changing program to change the
users password. The string describes a sequence of response-receive
pairs that smbd uses to determine what to send to the passwd program
and what to expect back. If the expected output is not received then
the password is not changed.
-This chat sequence is often quite site specific, deppending on what
+This chat sequence is often quite site specific, depending on what
local methods are used for password control (such as NIS+ etc).
The string can contain the macros %o and %n which are substituted for
-the old and new passwords respectively. It can aso contain the
-standard macros \\n \\r \\t and \\s to give line-feed, carriage-return,
+the old and new passwords respectively. It can also contain the
+standard macros \en \er \et and \es to give line-feed, carriage-return,
tab and space.
The string can also contain a * which matches any sequence of
@@ -1611,17 +2424,18 @@ then no string is sent. Similarly, is the expect string is a fullstop
then no string is expected.
.B Example:
- passwd chat = "*Enter OLD password*" %o\\n "*Enter NEW password*" %n\\n \\
- "*Reenter NEW password*" %n\\n "*Password changed*"
+ passwd chat = "*Enter OLD password*" %o\en "*Enter NEW password*" %n\en \e
+ "*Reenter NEW password*" %n\en "*Password changed*"
+
.B Default:
- passwd chat = *old*password* %o\\n *new*password* %n\\n *new*password* %n\\n *changed*
+ passwd chat = *old*password* %o\en *new*password* %n\en *new*password* %n\en *changed*
.SS passwd program (G)
The name of a program that can be used to set user passwords.
This is only necessary if you have enabled remote password changing at
-compile time. Any occurances of %u will be replaced with the user
+compile time. Any occurrences of %u will be replaced with the user
name.
Also note that many passwd programs insist in "reasonable" passwords,
@@ -1636,7 +2450,7 @@ Workgroups) uppercase the password before sending it.
passwd program = /sbin/passwd %u
.SS password level (G)
-Some client/server conbinations have difficulty with mixed-case passwords.
+Some client/server combinations have difficulty with mixed-case passwords.
One offending client is Windows for Workgroups, which for some reason forces
passwords to upper case when using the LANMAN1 protocol, but leaves them alone
when using COREPLUS!
@@ -1665,7 +2479,7 @@ you probably have a slow crypt() routine. Samba now comes with a fast
sure the PASSWORD_LENGTH option is correct for your system in local.h
and includes.h. On most systems only the first 8 chars of a password
are significant so PASSWORD_LENGTH should be 8, but on some longer
-passwords are significant. The inlcudes.h file tries to select the
+passwords are significant. The includes.h file tries to select the
right length for your system.
.B Default:
@@ -1678,18 +2492,18 @@ right length for your system.
By specifying the name of another SMB server (such as a WinNT box)
with this option, and using "security = server" you can get Samba to
-do all it's username/password validation via a remote server.
+do all its username/password validation via a remote server.
This options sets the name of the password server to use. It must be a
-netbios name, so if the machines netbios name is different from it's
-internet name then you may have to add it's netbios name to
+netbios name, so if the machine's netbios name is different from its
+internet name then you may have to add its netbios name to
/etc/hosts.
The password server much be a machine capable of using the "LM1.2X002"
or the "LM NT 0.12" protocol, and it must be in user level security
mode.
-NOTE: Using a password server means your unix box (running Samba) is
+NOTE: Using a password server means your UNIX box (running Samba) is
only as secure as your password server. DO NOT CHOOSE A PASSWORD
SERVER THAT YOU DON'T COMPLETELY TRUST.
@@ -1706,6 +2520,11 @@ If you list several hosts in the "password server" option then smbd
will try each in turn till it finds one that responds. This is useful
in case your primary server goes down.
+If you are using a WindowsNT server as your password server then you
+will have to ensure that your users are able to login from the Samba
+server, as the network logon will appear to come from there rather
+than from the users workstation.
+
.SS path (S)
A synonym for this parameter is 'directory'.
@@ -1718,8 +2537,8 @@ and the path should be world-writable and have the sticky bit set. This is not
mandatory of course, but you probably won't get the results you expect if you
do otherwise.
-Any occurances of %u in the path will be replaced with the username
-that the client is connecting as. Any occurances of %m will be
+Any occurrences of %u in the path will be replaced with the username
+that the client is connecting as. Any occurrences of %m will be
replaced by the name of the machine they are connecting from. These
replacements are very useful for setting up pseudo home directories
for users.
@@ -1747,7 +2566,7 @@ See also preexec
none (no command executed)
.B Example:
- postexec = echo \"%u disconnected from %S from %m (%I)\" >> /tmp/log
+ postexec = echo \e"%u disconnected from %S from %m (%I)\e" >> /tmp/log
.SS postscript (S)
This parameter forces a printer to interpret the print files as
@@ -1771,8 +2590,8 @@ connected to. It takes the usual substitutions.
An interesting example is to send the users a welcome message every
time they log in. Maybe a message of the day? Here is an example:
-preexec = csh -c 'echo \"Welcome to %S!\" | \
- /usr/local/samba/smbclient -M %m -I %I' &
+preexec = csh -c 'echo \e"Welcome to %S!\e" | \e
+ /usr/local/samba/bin/smbclient -M %m -I %I' &
Of course, this could get annoying after a while :-)
@@ -1782,15 +2601,28 @@ See also postexec
none (no command executed)
.B Example:
- preexec = echo \"%u connected to %S from %m (%I)\" >> /tmp/log
+ preexec = echo \e"%u connected to %S from %m (%I)\e" >> /tmp/log
.SS preferred master (G)
This boolean parameter controls if Samba is a preferred master browser
-for its workgroup. Setting this gives it a slight edge in elections
-and also means it will automatically start an election when it starts
-up.
+for its workgroup.
+If this is set to true, on startup, samba will force an election,
+and it will have a slight advantage in winning the election.
+It is recommended that this parameter is used in conjunction
+with domain master = yes, so that samba can guarantee becoming
+a domain master.
+
+Use this option with caution, because if there are several hosts
+(whether samba servers, Windows 95 or NT) that are preferred master
+browsers on the same subnet, they will each periodically and continuously
+attempt to become the local master browser. This will result in
+unnecessary broadcast traffic and reduced browsing capabilities.
-It is on by default.
+See
+.B os level = nn
+
+.B Default:
+ preferred master = no
.SS preload
This is an alias for "auto services"
@@ -1823,7 +2655,7 @@ below.
The full path name will be used for the filename if %s is not preceded
by a /. If you don't like this (it can stuff up some lpq output) then
-use %f instead. Any occurances of %f get replaced by the spool
+use %f instead. Any occurrences of %f get replaced by the spool
filename without the full path at the front.
The print command MUST contain at least one occurrence of "%s" or %f -
@@ -1838,7 +2670,7 @@ If there is neither a specified print command for a printable service nor a
global print command, spool files will be created but not processed and (most
importantly) not removed.
-Note that printing may fail on some unixes from the "nobody"
+Note that printing may fail on some UNIXes from the "nobody"
account. If this happens then create an alternative guest account that
can print and set the "guest account" in the [global] section.
@@ -1853,10 +2685,10 @@ You may have to vary this command considerably depending on how you
normally print files on your system.
.B Default:
- print command = lpr -r -P %p %s
+ print command = lpr -r -P %p %s
.B Example:
- print command = /usr/local/samba/myprintscript %p %s
+ print command = /usr/local/samba/bin/myprintscript %p %s
.SS print ok (S)
See
.B printable.
@@ -1876,18 +2708,6 @@ parameter controls only non-printing access to the resource.
.B Example:
printable = yes
-.SS printing (G)
-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".
-
-To see what the defaults are for the other print commands when using
-these three options use the "testparm" program.
-
-
.SS printcap name (G)
This parameter may be used to override the compiled-in default printcap
name used by the server (usually /etc/printcap). See the discussion of the
@@ -1900,9 +2720,13 @@ minimal file that looks like a printcap and set "printcap name =" in
A minimal printcap file would look something like this:
print1|My Printer 1
+.br
print2|My Printer 2
+.br
print3|My Printer 3
+.br
print4|My Printer 4
+.br
print5|My Printer 5
where the | separates aliases of a printer. The fact that the second
@@ -1917,6 +2741,7 @@ will assume the file is in AIX "qconfig" format if the string
.B Example:
printcap name = /etc/myprintcap
+
.SS printer (S)
A synonym for this parameter is 'printer name'.
@@ -1931,9 +2756,84 @@ for any printable service that does not have its own printer name specified.
.B Example:
printer name = laserwriter
+
+.SS printer driver (S)
+This option allows you to control the string that clients receive when
+they ask the server for the printer driver associated with a
+printer. If you are using Windows95 or WindowsNT then you can use this
+to automate the setup of printers on your system.
+
+You need to set this parameter to the exact string (case sensitive)
+that describes the appropriate printer driver for your system.
+If you don't know the exact string to use then you should first try
+with no "printer driver" option set and the client will give you a
+list of printer drivers. The appropriate strings are shown in a
+scrollbox after you have chosen the printer manufacturer.
+
+.B Example:
+ printer driver = HP LaserJet 4L
+
.SS printer name (S)
See
.B printer.
+
+.SS printer driver file (G)
+This parameter tells Samba where the printer driver definition file,
+used when serving drivers to Windows 95 clients, is to be found. If
+this is not set, the default is :
+
+SAMBA_INSTALL_DIRECTORY/lib/printers.def
+
+This file is created from Windows 95 'msprint.def' files found on the
+Windows 95 client system. For more details on setting up serving of
+printer drivers to Windows 95 clients, see the documentation file
+docs/PRINTER_DRIVER.txt.
+
+.B Default:
+ None (set in compile).
+
+.B Example:
+ printer driver file = /usr/local/samba/printers/drivers.def
+
+Related parameters.
+.B printer driver location
+
+.SS printer driver location (S)
+This parameter tells clients of a particular printer share where
+to find the printer driver files for the automatic installation
+of drivers for Windows 95 machines. If Samba is set up to serve
+printer drivers to Windows 95 machines, this should be set to
+
+\e\eMACHINE\ePRINTER$
+
+Where MACHINE is the NetBIOS name of your Samba server, and PRINTER$
+is a share you set up for serving printer driver files. For more
+details on setting this up see the documentation file
+docs/PRINTER_DRIVER.txt.
+
+.B Default:
+ None
+
+.B Example:
+ printer driver location = \e\eMACHINE\ePRINTER$
+
+Related paramerers.
+.B printer driver file
+
+
+.SS printing (G)
+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 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.
+
+
.SS protocol (G)
The value of the parameter (a string) is the highest protocol level that will
be supported by the server.
@@ -1941,6 +2841,9 @@ be supported by the server.
Possible values are CORE, COREPLUS, LANMAN1, LANMAN2 and NT1. The relative
merits of each are discussed in the README file.
+Normally this option should not be set as the automatic negotiation
+phase in the SMB protocol takes care of choosing the appropriate protocol.
+
.B Default:
protocol = NT1
@@ -2037,11 +2940,36 @@ pointless and will cause you to allocate memory unnecessarily.
.B Example:
read size = 8192
+.SS remote announce (G)
+
+This option allows you to setup nmbd to periodically announce itself
+to arbitrary IP addresses with an arbitrary workgroup name.
+
+This is useful if you want your Samba server to appear in a remote
+workgroup for which the normal browse propagation rules don't
+work. The remote workgroup can be anywhere that you can send IP
+packets to.
+
+For example:
+
+ remote announce = 192.168.2.255/SERVERS 192.168.4.255/STAFF
+
+the above line would cause nmbd to announce itself to the two given IP
+addresses using the given workgroup names. If you leave out the
+workgroup name then the one given in the "workgroup" option is used
+instead.
+
+The IP addresses you choose would normally be the broadcast addresses
+of the remote networks, but can also be the IP addresses of known
+browse masters if your network config is that stable.
+
+This option replaces similar functionality from the nmbd lmhosts file.
+
.SS revalidate (S)
This options controls whether Samba will allow a previously validated
username/password pair to be used to attach to a share. Thus if you
-connect to \\\\server\\share1 then to \\\\server\\share2 it won't
+connect to \e\eserver\eshare1 then to \e\eserver\eshare2 it won't
automatically allow the client to request connection to the second
share as the same username as the first without a password.
@@ -2084,8 +3012,20 @@ The set of files that must be mirrored is operating system dependent.
.B Example:
root directory = /homes/smb
+.SS root postexec (S)
+
+This is the same as postexec except that the command is run as
+root. This is useful for unmounting filesystems (such as cdroms) after
+a connection is closed.
+
+.SS root preexec (S)
+
+This is the same as preexec except that the command is run as
+root. This is useful for mounting filesystems (such as cdroms) before
+a connection is finalised.
+
.SS security (G)
-This option does affects how clients respond to Samba.
+This option affects how clients respond to Samba.
The option sets the "security mode bit" in replies to protocol negotiations
to turn share level security on or off. Clients decide based on this bit
@@ -2097,8 +3037,8 @@ option at one stage.
The alternatives are "security = user" or "security = server".
If your PCs use usernames that are the same as their usernames on the
-unix machine then you will want to use "security = user". If you
-mostly use usernames that don't exist on the unix box then use
+UNIX machine then you will want to use "security = user". If you
+mostly use usernames that don't exist on the UNIX box then use
"security = share".
There is a bug in WfWg that may affect your decision. When in user
@@ -2123,8 +3063,7 @@ This controls what string will show up in the printer comment box in
print manager and next to the IPC connection in "net view". It can be
any string that you wish to show to your users.
-Note that it DOES NOT affect the string that appears in browse
-lists. That is controlled by a nmbd command line option instead.
+It also sets what will appear in browse lists next to the machine name.
A %v will be replaced with the Samba version number.
@@ -2136,50 +3075,53 @@ A %h will be replaced with the hostname.
.B Example:
server string = University of GNUs Samba Server
-.SS smbrun (G)
-This sets the full path to the smbrun binary. This defaults to the
-value in the Makefile.
+.SS set directory (S)
+If 'set directory = no', then users of the service may not use the setdir
+command to change directory.
-You must get this path right for many services to work correctly.
+The setdir command is only implemented in the Digital Pathworks client. See the
+Pathworks documentation for details.
-.B Default: taken from Makefile
+.B Default:
+ set directory = no
.B Example:
- smbrun = /usr/local/samba/bin/smbrun
-
-.SS short preserve case (S)
-
-This controls if new short filenames are created with the case that
-the client passes, or if they are forced to be the "default" case.
+ set directory = yes
-.B Default:
- short preserve case = no
+.SS shared file entries (G)
+This parameter is only useful when Samba has been compiled with FAST_SHARE_MODES.
+It specifies the number of hash bucket entries used for share file locking.
+You should never change this parameter unless you have studied the source
+and know what you are doing.
-See the section on "NAME MANGLING" for a fuller discussion.
+.B Default
+ shared file entries = 113
-.SS root preexec (S)
+.SS shared mem size (G)
+This parameter is only useful when Samba has been compiled with FAST_SHARE_MODES.
+It specifies the size of the shared memory (in bytes) to use between smbd
+processes. You should never change this parameter unless you have studied
+the source and know what you are doing.
-This is the same as preexec except that the command is run as
-root. This is useful for mounting filesystems (such as cdroms) before
-a connection is finalised.
+.B Default
+ shared mem size = 102400
-.SS root postexec (S)
+.SS smb passwd file (G)
+This option sets the path to the encrypted smbpasswd file. This is a *VERY
+DANGEROUS OPTION* if the smb.conf is user writable. By default the path
+to the smbpasswd file is compiled into Samba.
-This is the same as postexec except that the command is run as
-root. This is useful for unmounting filesystems (such as cdroms) after
-a connection is closed.
+.SS smbrun (G)
+This sets the full path to the smbrun binary. This defaults to the
+value in the Makefile.
-.SS set directory (S)
-If 'set directory = no', then users of the service may not use the setdir
-command to change directory.
+You must get this path right for many services to work correctly.
-The setdir comand is only implemented in the Digital Pathworks client. See the
-Pathworks documentation for details.
.B Default:
- set directory = no
+taken from Makefile
.B Example:
- set directory = yes
+ smbrun = /usr/local/samba/bin/smbrun
.SS share modes (S)
@@ -2187,15 +3129,15 @@ This enables or disables the honouring of the "share modes" during a
file open. These modes are used by clients to gain exclusive read or
write access to a file.
-These open modes are not directly supported by unix, so they are
+These open modes are not directly supported by UNIX, so they are
simulated using lock files in the "lock directory". The "lock
directory" specified in smb.conf must be readable by all users.
The share modes that are enabled by this option are DENY_DOS,
DENY_ALL, DENY_READ, DENY_WRITE, DENY_NONE and DENY_FCB.
-Enabling this option gives full share compatability but may cost a bit
-of processing time on the unix server. They are enabled by default.
+Enabling this option gives full share compatibility but may cost a bit
+of processing time on the UNIX server. They are enabled by default.
.B Default:
share modes = yes
@@ -2203,6 +3145,27 @@ of processing time on the unix server. They are enabled by default.
.B Example:
share modes = no
+.SS short preserve case (S)
+
+This controls if new short filenames are created with the case that
+the client passes, or if they are forced to be the "default" case.
+
+.B Default:
+ short preserve case = no
+
+See the section on "NAME MANGLING" for a fuller discussion.
+
+.SS socket address (G)
+
+This option allows you to control what address Samba will listen for
+connections on. This is used to support multiple virtual interfaces on
+the one server, each with a different configuration.
+
+By default samba will accept connections on any address.
+
+.B Example:
+ socket address = 192.168.2.20
+
.SS socket options (G)
This option (which can also be invoked with the -O command line
option) allows you to set socket options to be used when talking with
@@ -2222,7 +3185,7 @@ You may find that on some systems Samba will say "Unknown socket
option" when you supply an option. This means you either mis-typed it
or you need to add an include file to includes.h for your OS. If the
latter is the case please send the patch to me
-(samba-bugs@anu.edu.au).
+(samba-bugs@samba.anu.edu.au).
Any of the supported socket options may be combined in any way you
like, as long as your OS allows it.
@@ -2284,9 +3247,12 @@ completely. Use these options with caution!
.SS status (G)
This enables or disables logging of connections to a status file that
-smbstatus can read.
+.B smbstatus
+can read.
-With this disabled smbstatus won't be able to tell you what
+With this disabled
+.B smbstatus
+won't be able to tell you what
connections are active.
.B Default:
@@ -2295,15 +3261,6 @@ connections are active.
.B Example:
status = no
-.SS strip dot (G)
-This is a boolean that controls whether to strup trailing dots off
-filenames. This helps with some CDROMs that have filenames ending in a
-single dot.
-
-NOTE: This option is now obsolete, and may be removed in future. You
-should use the "mangled map" option instead as it is much more
-general.
-
.SS strict locking (S)
This is a boolean that controls the handling of file locking in the
server. When this is set to yes the server will check every read and
@@ -2322,11 +3279,42 @@ so in the vast majority of cases "strict locking = no" is preferable.
.B Example:
strict locking = yes
+.SS strip dot (G)
+This is a boolean that controls whether to strip trailing dots off
+UNIX filenames. This helps with some CDROMs that have filenames ending in a
+single dot.
+
+.B Default:
+ strip dot = no
+
+.B Example:
+ strip dot = yes
+
+.SS syslog (G)
+This parameter maps how Samba debug messages are logged onto the
+system syslog logging levels. Samba debug level zero maps onto
+syslog LOG_ERR, debug level one maps onto LOG_WARNING, debug
+level two maps to LOG_NOTICE, debug level three maps onto LOG_INFO.
+The paramter sets the threshold for doing the mapping, all Samba
+debug messages above this threashold are mapped to syslog LOG_DEBUG
+messages.
+
+.B Default:
+
+ syslog = 1
+
+.SS syslog only (G)
+If this parameter is set then Samba debug messages are logged into
+the system syslog only, and not to the debug log files.
+
+.B Default:
+ syslog only = no
+
.SS sync always (S)
This is a boolean parameter that controls whether writes will always
be written to stable storage before the write call returns. If this is
-false then the server will be guided by the clients request in each
+false then the server will be guided by the client's request in each
write call (clients can set a bit indicating that a particular write
should be synchronous). If this is true then every write will be
followed by a fsync() call to ensure the data is written to disk.
@@ -2348,6 +3336,27 @@ that have incorrect daylight saving time handling.
.B Example:
time offset = 60
+.SS time server (G)
+This parameter determines if nmbd advertises itself as a time server
+to Windows clients. The default is False.
+
+.B Default:
+ time server = False
+
+.B Example:
+ time server = True
+
+.SS unix realname (G)
+This boolean parameter when set causes samba to supply the real name field
+from the unix password file to the client. This is useful for setting up
+mail clients and WWW browsers on systems used by more than one person.
+
+.B Default:
+ unix realname = no
+
+.B Example:
+ unix realname = yes
+
.SS user (S)
See
.B username.
@@ -2357,10 +3366,10 @@ A synonym for this parameter is 'user'.
Multiple users may be specified in a comma-delimited list, in which case the
supplied password will be tested against each username in turn (left to right).
-The username= line is needed only when the PC is unable to supply it's own
+The username= line is needed only when the PC is unable to supply its own
username. This is the case for the coreplus protocol or where your
-users have different WfWg usernames to unix usernames. In both these
-cases you may also be better using the \\\\server\\share%user syntax
+users have different WfWg usernames to UNIX usernames. In both these
+cases you may also be better using the \e\eserver\eshare%user syntax
instead.
The username= line is not a great solution in many cases as it means Samba
@@ -2369,7 +3378,7 @@ usernames in the username= line in turn. This is slow and a bad idea for
lots of users in case of duplicate passwords. You may get timeouts or
security breaches using this parameter unwisely.
-Samba relies on the underlying unix security. This parameter does not
+Samba relies on the underlying UNIX security. This parameter does not
restrict who can login, it just offers hints to the Samba server as to
what usernames might correspond to the supplied password. Users can
login as whoever they please and they will be able to do no more
@@ -2395,47 +3404,75 @@ on how this parameter determines access to the services.
username = fred
username = fred, mary, jack, jane, @users, @pcgroup
+.SS username level (G)
+
+This option helps Samba to try and 'guess' at the real UNIX username,
+as many DOS clients send an all-uppercase username. By default Samba
+tries all lowercase, followed by the username with the first letter
+capitalized, and fails if the username is not found on the UNIX machine.
+
+If this parameter is set to non-zero the behaviour changes. This
+parameter is a number that specifies the number of uppercase combinations
+to try whilst trying to determine the UNIX user name. The higher the number
+the more combinations will be tried, but the slower the discovery
+of usernames will be. Use this parameter when you have strange
+usernames on your UNIX machine, such as 'AstrangeUser'.
+
+.B Default:
+ username level = 0
+
+.B Example:
+ username level = 5
+
.SS username map (G)
This option allows you to to specify a file containing a mapping of
usernames from the clients to the server. This can be used for several
-purposes. The most common is to map usernames that users use on dos or
-windows machines to those that the unix box uses. The other is to map
+purposes. The most common is to map usernames that users use on DOS or
+Windows machines to those that the UNIX box uses. The other is to map
multiple users to a single username so that they can more easily share
files.
The map file is parsed line by line. Each line should contain a single
-unix username on the left then a '=' followed by a list of usernames
+UNIX username on the left then a '=' followed by a list of usernames
on the right. The list of usernames on the right may contain names of
-the form @group in which case they will match any unix username in
+the form @group in which case they will match any UNIX username in
that group. The special client name '*' is a wildcard and matches any
name.
The file is processed on each line by taking the supplied username and
comparing it with each username on the right hand side of the '='
-signs. If the supplied name matrches any of the names on the right
+signs. If the supplied name matches any of the names on the right
hand side then it is replaced with the name on the left. Processing
then continues with the next line.
If any line begins with a '#' or a ';' then it is ignored
-For example to map from he name "admin" or "administrator" to the unix
+For example to map from the name "admin" or "administrator" to the UNIX
name "root" you would use
root = admin administrator
-Or to map anyone in the unix group "system" to the unix name "sys" you
+Or to map anyone in the UNIX group "system" to the UNIX name "sys" you
would use
sys = @system
You can have as many mappings as you like in a username map file.
-Note that the remapping is applied to all occurances of
-usernames. Thus if you connect to "\\\\server\\fred" and "fred" is
+You can map Windows usernames that have spaces in them by using double
+quotes around the name. For example:
+
+ tridge = "Andrew Tridgell"
+
+would map the windows username "Andrew Tridgell" to the unix username
+tridge.
+
+Note that the remapping is applied to all occurrences of
+usernames. Thus if you connect to "\e\eserver\efred" and "fred" is
remapped to "mary" then you will actually be connecting to
-"\\\\server\\mary" and will need to supply a password suitable for
-"mary" not "fred". The only exception to this is the username passwed
+"\e\eserver\emary" and will need to supply a password suitable for
+"mary" not "fred". The only exception to this is the username passed
to the "password server" (if you have one). The password server will
receive whatever username the client supplies without modification.
@@ -2462,7 +3499,7 @@ between them then it will be taken as an lowercase:uppercase pair.
If you have an editor capable of entering the characters into the
config file then it is probably easiest to use this method. Otherwise
-you can specify the characters in octal, decimal or hexidecimal form
+you can specify the characters in octal, decimal or hexadecimal form
using the usual C notation.
For example to add the single character 'Z' to the charset (which is a
@@ -2473,11 +3510,20 @@ valid chars = Z
valid chars = z:Z
valid chars = 0132:0172
-The last two examples above actually add two characters, and alters
+The last two examples above actually add two characters, and alter
the uppercase and lowercase mappings appropriately.
+Note that you MUST specify this parameter after the "client code page"
+parameter if you have both set. If "client code page" is set after
+the "valid chars" parameter the "valid chars" settings will be
+overwritten.
+
+See also the "client code page" parameter.
+
.B Default
+.br
Samba defaults to using a reasonable set of valid characters
+.br
for english systems
.B Example
@@ -2486,9 +3532,15 @@ the uppercase and lowercase mappings appropriately.
The above example allows filenames to have the swedish characters in
them.
+NOTE: It is actually quite difficult to correctly produce a "valid
+chars" line for a particular system. To automate the process
+tino@augsburg.net has written a package called "validchars" which will
+automatically produce a complete "valid chars" line for a given client
+system. Look in the examples subdirectory for this package.
+
.SS valid users (S)
This is a list of users that should be allowed to login to this
-service. A name starting with @ is interpreted as a unix group.
+service. A name starting with @ is interpreted as a UNIX group.
If this is empty (the default) then any user can login. If a username
is in both this list and the "invalid users" list then access is
@@ -2505,15 +3557,57 @@ See also "invalid users"
.B Example
valid users = greg, @pcusers
+
+.SS veto files(S)
+This is a list of files and directories that are neither visible nor
+accessible. Each entry in the list must be separated by a "/", which
+allows spaces to be included in the entry. '*' and '?' can be used to
+specify multiple files or directories as in DOS wildcards.
+
+Each entry must be a unix path, not a DOS path and must not include the
+unix directory separator "/".
+
+Note that the case sensitivity option is applicable in vetoing files.
+
+One feature of the veto files parameter that it is important to be
+aware of, is that if a directory contains nothing but files that
+match the veto files parameter (which means that Windows/DOS clients
+cannot ever see them) is deleted, the veto files within that directory
+*are automatically deleted* along with it, if the user has UNIX permissions
+to do so.
+
+Setting this parameter will affect the performance of Samba, as
+it will be forced to check all files and directories for a match
+as they are scanned.
+
+See also "hide files" and "case sensitive"
+
+.B Default
+ No files or directories are vetoed.
+
+.B Examples
+ Example 1.
+ Veto any files containing the word Security,
+ any ending in .tmp, and any directory containing the
+ word root.
+
+ veto files = /*Security*/*.tmp/*root*/
+
+ Example 2.
+ Veto the Apple specific files that a NetAtalk server
+ creates.
+
+ veto files = /.AppleDouble/.bin/.AppleDesktop/Network Trash Folder/
+
.SS volume (S)
This allows you to override the volume label returned for a
-share. Useful for CDROMs whos installation programs insist on a
+share. Useful for CDROMs with installation programs that insist on a
particular volume label.
The default is the name of the share
.SS wide links (S)
-This parameter controls whether or not links in the Unix file system may be
+This parameter controls whether or not links in the UNIX file system may be
followed by the server. Links that point to areas within the directory tree
exported by the server are always allowed; this parameter controls access
only to areas that are outside the directory tree being exported.
@@ -2524,12 +3618,39 @@ 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 server (G)
+
+This specifies the DNS name (or IP address) 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.
+
+You should point this at your WINS server if you have a multi-subnetted
+network.
+.B Default:
+ wins server =
+
+.SS wins support (G)
+
+This boolean controls if Samba will act as a WINS server. You should
+not set this to true unless you have a multi-subnetted network and
+you wish a particular nmbd to be your WINS server. Note that you
+should *NEVER* set this to true on more than one machine in your
+network.
+
+.B Default:
+ wins support = no
.SS workgroup (G)
This controls what workgroup your server will appear to be in when
-queried by clients. This can be different to the workgroup specified
-in the nmbd configuration, but it is probably best if you set them to
-the same value.
+queried by clients.
.B Default:
set in the Makefile
@@ -2537,11 +3658,6 @@ the same value.
.B Example:
workgroup = MYGROUP
-.SS write ok (S)
-See
-.B writable
-and
-.B read only.
.SS writable (S)
A synonym for this parameter is 'write ok'. An inverted synonym is 'read only'.
@@ -2576,6 +3692,11 @@ See also the "read list" option
.B Example:
write list = admin, root, @staff
+.SS write ok (S)
+See
+.B writable
+and
+.B read only.
.SS write raw (G)
This parameter controls whether or not the server will support raw writes when
transferring data from clients.
@@ -2595,15 +3716,15 @@ the following steps are not checked.
If the service is marked "guest only = yes" then steps 1 to 5 are skipped
Step 1: If the client has passed a username/password pair and that
-username/password pair is validated by the unix systems password
+username/password pair is validated by the UNIX system's password
programs then the connection is made as that username. Note that this
-includes the \\\\server\\service%username method of passing a username.
+includes the \e\eserver\eservice%username method of passing a username.
Step 2: If the client has previously registered a username with the
system and now supplies a correct password for that username then the
connection is allowed.
-Step 3: The clients netbios name and any previously used user names
+Step 3: The client's netbios name and any previously used user names
are checked against the supplied password, if they match then the
connection is allowed as the corresponding user.
@@ -2614,7 +3735,7 @@ for this service.
Step 5: If a "user = " field is given in the smb.conf file for the
service and the client has supplied a password, and that password
-matches (according to the unix systems password checking) with one of
+matches (according to the UNIX system's password checking) with one of
the usernames from the user= field then the connection is made as the
username in the "user=" line. If one of the username in the user= list
begins with a @ then that name expands to a list of names in the group
@@ -2623,8 +3744,6 @@ of the same name.
Step 6: If the service is a guest service then a connection is made as
the username given in the "guest account =" for the service,
irrespective of the supplied password.
-
-
.SH WARNINGS
Although the configuration file permits service names to contain spaces,
your client software may not. Spaces will be ignored in comparisons anyway,
@@ -2641,7 +3760,7 @@ administrator easy, but the various combinations of default attributes can be
tricky. Take extreme care when designing these sections. In particular,
ensure that the permissions on spool directories are correct.
.SH VERSION
-This man page is (mostly) correct for version 1.9.00 of the Samba suite, plus some
+This man page is (mostly) correct for version 1.9.18 of the Samba suite, plus some
of the recent patches to it. These notes will necessarily lag behind
development of the software, so it is possible that your version of
the server has extensions or parameter semantics that differ from or are not
@@ -2653,27 +3772,25 @@ radically different (more primitive). If you are using a version earlier than
1.8.05, it is STRONGLY recommended that you upgrade.
.SH OPTIONS
Not applicable.
-
.SH FILES
Not applicable.
-
.SH ENVIRONMENT VARIABLES
Not applicable.
-
.SH SEE ALSO
-.B smbd(8),
-.B smbclient(1),
-.B nmbd(8),
-.B testparm(1),
-.B testprns(1),
-.B lpq(1),
-.B hosts_access(5)
+.BR smbd (8),
+.BR smbclient (1),
+.BR nmbd (8),
+.BR testparm (1),
+.BR testprns (1),
+.BR lpq (1),
+.BR hosts_access (5)
.SH DIAGNOSTICS
[This section under construction]
Most diagnostics issued by the server are logged in a specified log file. The
log file name is specified at compile time, but may be overridden on the
-smbd (see smbd(8)) command line.
+smbd command line (see
+.BR smbd (8)).
The number and nature of diagnostics available depends on the debug level used
by the server. If you have problems, set the debug level to 3 and peruse the
@@ -2684,26 +3801,25 @@ creation of this man page the source code is still too fluid to warrant
describing each and every diagnostic. At this stage your best bet is still
to grep the source code and inspect the conditions that gave rise to the
diagnostics you are seeing.
-
.SH BUGS
None known.
Please send bug reports, comments and so on to:
.RS 3
-.B samba-bugs@anu.edu.au (Andrew Tridgell)
+.B samba-bugs@samba.anu.edu.au (Andrew Tridgell)
.RS 3
-or to the mailing list
+or to the mailing list:
.RE
.B samba@listproc.anu.edu.au
.RE
-You may also like to subscribe to the announcement channel
+You may also like to subscribe to the announcement channel:
.RS 3
-samba-announce@listproc.anu.edu.au
+.B samba-announce@listproc.anu.edu.au
.RE
To subscribe to these lists send a message to
@@ -2714,6 +3830,6 @@ Errors or suggestions for improvements to the Samba man pages should be
mailed to:
.RS 3
-.B samba-bugs@anu.edu.au (Andrew Tridgell)
+.B samba-bugs@samba.anu.edu.au (Andrew Tridgell)
.RE
diff --git a/docs/manpages/smbclient.1 b/docs/manpages/smbclient.1
index 5590e01296e..172e962dbbd 100644
--- a/docs/manpages/smbclient.1
+++ b/docs/manpages/smbclient.1
@@ -1,4 +1,4 @@
-.TH SMBCLIENT 1 17/1/1995 smbclient smbclient
+.TH SMBCLIENT 1 "30 Oct 1997" "smbclient 1.9.18alpha8"
.SH NAME
smbclient \- ftp-like Lan Manager client program
.SH SYNOPSIS
@@ -7,43 +7,51 @@ smbclient \- ftp-like Lan Manager client program
[
.B password
] [
-.B -A
+.B \-A
] [
-.B -E
+.B \-E
] [
-.B -L
+.B \-L
.I host
] [
-.B -M
+.B \-M
.I host
] [
-.B -I
+.B \-I
.I IP number
] [
-.B -N
+.B \-N
] [
-.B -P
+.B \-P
] [
-.B -U
+.B \-U
.I username
] [
-.B -d
+.B \-d
.I debuglevel
] [
-.B -l
+.B \-l
.I log basename
] [
-.B -n
+.B \-n
.I netbios name
] [
-.B -O
+.B \-W
+.I workgroup
+] [
+.B \-O
.I socket options
] [
-.B -p
+.B \-p
.I port number
-.B -T
+] [
+.B \-c
+.I command string
+] [
+.B \-T
.I tar options
-.B -D
+] [
+.B \-D
.I initial directory
]
.SH DESCRIPTION
@@ -54,17 +62,17 @@ is a client that can 'talk' to a Lan Manager server. It offers
an interface similar to that of the
.B ftp
program (see
-.B ftp(1)). Operations include things like getting files from the
+.BR ftp (1)).
+Operations include things like getting files from the
server to the local machine, putting files from the local machine to
the server, retrieving directory information from the server and so on.
-
.SH OPTIONS
.B servicename
.RS 3
.B servicename
is the name of the service you want to use on the server. A service
name takes the form
-.B "\\\\\\\\server\\\\service"
+.B "\e\eserver\eservice"
where
.B server
is the netbios name of the Lan Manager server offering the desired service and
@@ -73,7 +81,7 @@ is the name of the service offered. Thus to connect to the service "printer"
on the Lan Manager server "lanman", you would use the servicename
.RS 10
-.B "\\\\\\\\lanman\\\\printer"
+.B "\e\elanman\eprinter"
.RE
Note that the server name required is NOT necessarily the host name of the
@@ -87,16 +95,16 @@ be the same as the hostname of the machine running the server.
password
is the password required to access the specified service on the
specified server. If supplied, the
-.B -N
+.B \-N
option (suppress password prompt) is assumed.
There is no default password. If no password is supplied on the command line
(either here or using the
-.B -U
+.B \-U
option (see below)) and
-.B -N
+.B \-N
is not specified, the client will prompt for a password, even if the desired
-service does not require one. (If prompted for a password and none is
+service does not require one. (If no password is
required, simply press ENTER to provide a null password.)
Note: Some servers (including OS/2 and Windows for Workgroups) insist
@@ -106,7 +114,7 @@ rejected by these servers.
Be cautious about including passwords in scripts.
.RE
-.B -A
+.B \-A
.RS 3
This parameter, if specified, causes the maximum debug level to be selected.
@@ -115,21 +123,23 @@ a security issue involved, as at the maximum debug level cleartext passwords
may be written to some log files.
.RE
-.B -L
+.B \-L
.RS 3
This option allows you to look at what services are available on a
server. You use it as "smbclient -L host" and a list should appear.
-The -I option may be useful if your netbios names don't match your
+The
+.B \-I
+option may be useful if your netbios names don't match your
tcp/ip host names or if you are trying to reach a host on another
network. For example:
smbclient -L ftp -I ftp.microsoft.com
-will list the shares available on microsofts public server.
+will list the shares available on Microsoft's public server.
.RE
-.B -M
+.B \-M
.RS 3
This options allows you to send messages, using the "WinPopup"
@@ -143,22 +153,30 @@ message will be lost, and no error message will occur.
The message is also automatically truncated if the message is over
1600 bytes, as this is the limit of the protocol.
-One useful trick is to cat the message through smbclient. For example:
+One useful trick is to cat the message through
+.BR smbclient .
+For example:
cat mymessage.txt | smbclient -M FRED
will send the message in the file "mymessage.txt" to the machine FRED.
-You may also find the -U and -I options useful, as they allow you to
+You may also find the
+.B \-U
+and
+.B \-I
+options useful, as they allow you to
control the FROM and TO parts of the message.
-Samba currently has no way of receiving WinPopup messages.
+See the message command section of
+.BR smb.conf (5)
+for a description of how to handle incoming WinPopup messages in Samba.
Note: Copy WinPopup into the startup group on your WfWg PCs if you
want them to always be able to receive messages.
.RE
-.B -E
+.B \-E
.RS 3
This parameter, if specified, causes the client to write messages to the
@@ -168,7 +186,7 @@ By default, the client writes messages to standard output - typically the
user's tty.
.RE
-.B -I
+.B \-I
.I IP number
.RS 3
@@ -185,7 +203,7 @@ There is no default for this parameter. If not supplied, it will be determined
automatically by the client as described above.
.RE
-.B -N
+.B \-N
.RS 3
If specified, this parameter suppresses the normal password prompt from the
@@ -196,14 +214,16 @@ Unless a password is specified on the command line or this parameter is
specified, the client will request a password.
.RE
-.B -O
+.B \-O
.I socket options
-.RS 3
-
-See the socket options section of smb.conf(5) for details
+.RS 3
+See the socket options section of
+.BR smb.conf (5)
+for details.
.RE
-.B -P
+
+.B \-P
.RS 3
If specified, the service requested will be connected to as a printer service
@@ -213,7 +233,7 @@ will not be applicable for such a connection.
By default, services will be connected to as NON-printer services.
.RE
-.B -U
+.B \-U
.I username
.RS 3
@@ -237,21 +257,28 @@ If no
is supplied and neither environment variable exists the user name will
be empty.
+If the USER environment variable containts a '%' character, everything
+after that will be treated as a password. This allows you to set the
+environment variable to be
+.B USER=username%password
+so that a password is not passed on the command line (where it may
+be seen by the ps command).
+
If the service you are connecting to requires a password, it can be supplied
using the
-.B -U
+.B \-U
option, by appending a percent symbol ("%") then the password to
.I username.
For example, to attach to a service as user "fred" with password "secret", you
would specify
-.B -U
+.B \-U
.I fred%secret
on the command line. Note that there are no spaces around the percent symbol.
If you specify the password as part of
.I username
then the
-.B -N
+.B \-N
option (suppress password prompt) is assumed.
If you specify the password as a parameter AND as part of
@@ -269,10 +296,10 @@ rejected by these servers.
Be cautious about including passwords in scripts.
.RE
-.B -d
+.B \-d
.I debuglevel
-.RS 3
+.RS 3
debuglevel is an integer from 0 to 5.
The default value if this parameter is not specified is zero.
@@ -288,7 +315,7 @@ use only by developers and generate HUGE amounts of log data, most of which
is extremely cryptic.
.RE
-.B -l
+.B \-l
.I log basename
.RS 3
@@ -312,9 +339,8 @@ log.client.out (containing outbound transaction data)
The log files generated are never removed by the client.
.RE
-.RE
-.B -n
+.B \-n
.I netbios name
.RS 3
@@ -323,10 +349,18 @@ uppercase) as its netbios name. This parameter allows you to override
the host name and use whatever netbios name you wish.
.RE
-.B -p
-.I port number
+.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
port number is a positive integer value.
The default value if this parameter is not specified is 139.
@@ -336,15 +370,28 @@ the server. The standard (well-known) port number for the server is 139,
hence the default.
This parameter is not normally specified.
+.RE
-.B -T
+.B \-T
.I tar options
-.RS3
-where tar options are one or more of c,x,I,X,b,g,N or a; used as:
+.RS 3
+where
+.I tar options
+consists of one or more of
+.BR c ,
+.BR x ,
+.BR I ,
+.BR X ,
+.BR b ,
+.BR g ,
+.BR N
+or
+.BR a ;
+used as:
.LP
smbclient
-.B "\\\\\\\\server\\\\share"
+.B "\e\eserver\eshare"
\-TcxIXbgNa
[
.IR blocksize
@@ -357,18 +404,25 @@ smbclient
.IR filenames....
]
-.RS3
+.RS 3
.B c
Create a tar file on UNIX. Must be followed by the name of a tar file,
-tape device or "-" for standard output. (May be useful to set debugging
-low (-d0)) to avoid corrupting your tar file if using "-"). Mutually
-exclusive with the x flag.
+tape device or "\-" for standard output. (May be useful to set debugging
+low
+.RB ( -d0 ))
+to avoid corrupting your tar file if using "\-"). Mutually
+exclusive with the
+.B x
+flag.
.B x
-Extract (restore) a local tar file back to a share. Unless the -D
+Extract (restore) a local tar file back to a share. Unless the
+.B \-D
option is given, the tar files will be restored from the top level of
-the share. Must be followed by the name of the tar file, device or "-"
-for standard input. Mutually exclusive with the c flag.
+the share. Must be followed by the name of the tar file, device or "\-"
+for standard input. Mutually exclusive with the
+.B c
+flag.
.B I
Include files and directories. Is the default behaviour when
@@ -389,49 +443,69 @@ blocks.
.B g
Incremental. Only back up files that have the archive bit set. Useful
-only with the c flag.
+only with the
+.B c
+flag.
.B N
Newer than. Must be followed by the name of a file whose date is
compared against files found on the share during a create. Only files
newer than the file specified are backed up to the tar file. Useful
-only with the c flag.
+only with the
+.B c
+flag.
.B a
Set archive bit. Causes the archive bit to be reset when a file is backed
-up. Useful with the g (and c) flags.
+up. Useful with the
+.B g
+(and
+.BR c )
+flags.
.LP
.B Examples
-smbclient \\\\mypc\\myshare "" -N -Tx backup.tar
+smbclient \e\emypc\emyshare "" -N -Tx backup.tar
Restore from tar file backup.tar into myshare on mypc (no password on share).
-smbclient \\\\mypc\\myshare "" -N -TXx backup.tar users/docs
+smbclient \e\emypc\emyshare "" -N -TXx backup.tar users/docs
Restore everything except users/docs
-smbclient \\\\mypc\\myshare "" -N -Tc backup.tar users/docs
+smbclient \e\emypc\emyshare "" -N -Tc backup.tar users/docs
Create a tar file of the files beneath users/docs.
-
+.RE
.RE
-.B -D
+.B \-D
.I initial directory
-.RS3
-
+.RS 3
Change to initial directory before starting. Probably only of any use
-with the tar (\-T) option.
+with the tar
+.RB ( \-T )
+option.
+.RE
+.B \-c
+.I command string
-.RE
+.RS 3
+command string is a semicolon separated list of commands to be
+executed instead of prompting from stdin.
+.B \-N
+is implied by
+.BR \-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,
+Once the client is running, the user is presented with a prompt, "smb: \e>".
+The backslash ("\e") indicates the current working directory on the server,
and will change if the current working directory is changed.
The prompt indicates that the client is ready and waiting to carry out a user
@@ -573,7 +647,9 @@ Copy the file called
from the server to the machine running the client. If specified, name the
local copy
.I local file name.
-Note that all transfers in smbclient are binary. See also the
+Note that all transfers in
+.B smbclient
+are binary. See also the
.B lowercase
command.
.RE
@@ -637,7 +713,7 @@ when using the
and
.B mget
commands. This is often useful when copying (say) MSDOS files from a server,
-because lowercase filenames are the norm on Unix systems.
+because lowercase filenames are the norm on UNIX systems.
.RE
.RE
@@ -747,8 +823,9 @@ operation - refer to the
.B recurse
and
.B mask
-commands for more information. Note that all transfers in smbclient are
-binary. See also the
+commands for more information. Note that all transfers in
+.B smbclient
+are binary. See also the
.B lowercase
command.
.RE
@@ -791,8 +868,9 @@ operation - refer to the
.B recurse
and
.B mask
-commands for more information. Note that all transfers in smbclient are
-binary.
+commands for more information. Note that all transfers in
+.B smbclient
+are binary.
.RE
.RE
@@ -866,7 +944,9 @@ Copy the file called
from the machine running the client to the server. If specified, name the
remote copy
.I remote file name.
-Note that all transfers in smbclient are binary. See also the
+Note that all transfers in
+.B smbclient
+are binary. See also the
.B lowercase
command.
.RE
@@ -927,17 +1007,16 @@ None.
Toggle directory recursion for the commands
.B mget
and
-.B mput
-.
+.BR mput .
When toggled ON, these commands will process all directories in the source
-directory (ie., the directory they are copying
-.I from
-) and will recurse into any that match the mask specified to the command. Only
+directory (i.e., the directory they are copying
+.IR from )
+and will recurse into any that match the mask specified to the command. Only
files that match the mask specified using the
.B mask
command will be retrieved. See also the
-.mask
+.B mask
command.
When recursion is toggled OFF, only files from the current working
@@ -990,11 +1069,13 @@ Remove the specified directory (user access privileges permitting)
.RE
.B Description:
.RS 3
-Performs a tar operation - see -T command line option above. Behaviour
+Performs a tar operation - see the
+.B \-T
+command line option above. Behaviour
may be affected by the
.B tarmode
-command (see below). Using the g (incremental) and N (newer) will affect
-tarmode settings. Note that using the "-" option with tar x may not
+command (see below). Using g (incremental) and N (newer) will affect
+tarmode settings. Note that using the "\-" option with tar x may not
work - use the command line option instead.
.RE
.RE
@@ -1035,7 +1116,7 @@ on all files it backs up (implies read/write share).
.RS 3
.B Parameters
.RS 3
-.I <filename> <perm=[+|-]rsha>
+.I <filename> <perm=[+|\-]rsha>
.RE
.B Description
@@ -1047,14 +1128,13 @@ setmode myfile +r
would make myfile read only.
.RE
.RE
-
.SH NOTES
Some servers are fussy about the case of supplied usernames, passwords, share
names (aka service names) and machine names. If you fail to connect try
giving all parameters in uppercase.
It is often necessary to use the
-.B -n
+.B \-n
option when connecting to some types
of servers. For example OS/2 LanManager insists on a valid netbios name
being used, so you need to supply a valid name that would be known to
@@ -1063,10 +1143,8 @@ the server.
.B smbclient
supports long file names where the server supports the LANMAN2
protocol.
-
.SH FILES
Not applicable.
-
.SH ENVIRONMENT VARIABLES
.B USER
.RS 3
@@ -1074,12 +1152,12 @@ The variable USER may contain the username of the person using the client.
This information is used only if the protocol level is high enough to support
session-level passwords.
.RE
-
.SH INSTALLATION
The location of the client program is a matter for individual system
administrators. The following are thus suggestions only.
-It is recommended that the client software be installed under the /usr/local
+It is recommended that the client software be installed under the
+/usr/local/samba
hierarchy, in a directory readable by all, writeable only by root. The client
program itself should be executable by all. The client should NOT be setuid
or setgid!
@@ -1088,8 +1166,11 @@ The client log files should be put in a directory readable and writable only
by the user.
To test the client, you will need to know the name of a running Lan manager
-server. It is possible to run the smbd (see
-.B smbd(8)) as an ordinary user - running that server as a daemon on a
+server. It is possible to run
+.B smbd
+(see
+.BR smbd (8))
+as an ordinary user - running that server as a daemon on a
user-accessible port (typically any port number over 1024) would
provide a suitable test server.
.SH VERSION
@@ -1100,8 +1181,7 @@ the client has extensions or parameter semantics that differ from or are not
covered by this man page. Please notify these to the address below for
rectification.
.SH SEE ALSO
-.B smbd(8)
-
+.BR smbd (8)
.SH DIAGNOSTICS
[This section under construction]
@@ -1118,16 +1198,14 @@ creation of this man page the source code is still too fluid to warrant
describing each and every diagnostic. At this stage your best bet is still
to grep the source code and inspect the conditions that gave rise to the
diagnostics you are seeing.
-
.SH BUGS
None known.
.SH CREDITS
The original Samba software and related utilities were created by
-Andrew Tridgell (samba-bugs@anu.edu.au). Andrew is also the Keeper
+Andrew Tridgell (samba-bugs@samba.anu.edu.au). Andrew is also the Keeper
of the Source for this project.
-This man page written by Karl Auer (Karl.Auer@anu.edu.au)
-
See
-.B smb.conf(5) for a full list of contributors and details on how to
+.BR smb.conf (5)
+for a full list of contributors and details on how to
submit bug reports, comments etc.
diff --git a/docs/manpages/smbd.8 b/docs/manpages/smbd.8
index bae41b2c479..89f95a1b670 100644
--- a/docs/manpages/smbd.8
+++ b/docs/manpages/smbd.8
@@ -1,46 +1,49 @@
-.TH SMBD 8 17/1/1995 smbd smbd
+.TH SMBD 8 "30 Oct 1997" "smbd 1.9.18alpha8"
.SH NAME
smbd \- provide SMB (aka LanManager) services to clients
.SH SYNOPSIS
.B smbd
[
-.B -D
+.B \-D
] [
-.B -a
+.B \-a
] [
-.B -d
+.B \-d
.I debuglevel
] [
-.B -l
+.B \-l
.I log file
] [
-.B -p
+.B \-p
.I port number
] [
-.B -O
+.B \-O
.I socket options
] [
-.B -s
+.B \-s
.I configuration file
]
.SH DESCRIPTION
This program is part of the Samba suite.
.B smbd
-is a server that can provide most SMB services. The
-server provides filespace and printer services to clients using the SMB
-protocol. This is compatible with the LanManager protocol, and can
-service LanManager clients.
+is a server that can provide most SMB services. The server provides
+filespace and printer services to clients using the SMB protocol. This
+is compatible with the LanManager protocol, and can service LanManager
+clients. These include MSCLIENT 3.0 for DOS, Windows for Workgroups,
+Windows 95, Windows NT, OS/2, DAVE for Macintosh, and smbfs for Linux.
An extensive description of the services that the server can provide is given
in the man page for the configuration file controlling the attributes of those
services (see
-.B smb.conf(5)). This man page will not describe the services, but
+.BR smb.conf (5)).
+This man page will not describe the services, but
will concentrate on the administrative aspects of running the server.
Please note that there are significant security implications to running this
server, and
-.B smb.conf(5) should be regarded as mandatory reading before proceeding with
+.BR smb.conf (5)
+should be regarded as mandatory reading before proceeding with
installation.
A session is created whenever a client requests one. Each client gets a copy
@@ -48,11 +51,13 @@ of the server for each session. This copy then services all connections made
by the client during that session. When all connections from its client are
are closed, the copy of the server for that client terminates.
-The configuration file is automatically reloaded if it changes. You
-can force a reload by sending a SIGHUP to the server.
-
+The configuration file, and any files that it includes, are automatically
+reloaded every minute, if they change. You can force a reload by sending a
+SIGHUP to the server. Reloading the configuration file will not affect
+connections to any service that is already established. Either the user
+will have to disconnect from the service, or smbd killed and restarted.
.SH OPTIONS
-.B -D
+.B \-D
.RS 3
If specified, this parameter causes the server to operate as a daemon. That is,
@@ -62,18 +67,18 @@ appropriate port.
By default, the server will NOT operate as a daemon.
.RE
-.B -a
+.B \-a
.RS 3
If this parameter is specified, the log files will be overwritten with each
new connection. By default, the log files will be appended to.
.RE
-.B -d
+.B \-d
.I debuglevel
.RS 3
-debuglevel is an integer from 0 to 5.
+debuglevel is an integer from 0 to 10.
The default value if this parameter is not specified is zero.
@@ -88,7 +93,7 @@ use only by developers and generate HUGE amounts of log data, most of which
is extremely cryptic.
.RE
-.B -l
+.B \-l
.I log file
.RS 3
@@ -113,14 +118,16 @@ log.out (containing outbound transaction data)
The log files generated are never removed by the server.
.RE
-.B -O
+.B \-O
.I socket options
.RS 3
-See the socket options section of smb.conf(5) for details
+See the socket options section of
+.BR smb.conf (5)
+for details
.RE
-.B -p
+.B \-p
.I port number
.RS 3
@@ -135,10 +142,14 @@ user rather than as root, most systems will require you to use a port number
greater than 1024 - ask your system administrator for help if you are in this
situation.
+In order for the server to be useful by most clients, should you configure
+it on a port other than 139, you will require port redirection services
+on port 139, details of which are outlined in rfc1002.txt section 4.3.5.
+
This parameter is not normally specified except in the above situation.
.RE
-.B -s
+.B \-s
.I configuration file
.RS 3
@@ -148,9 +159,9 @@ The file specified contains the configuration details required by the server.
The information in this file includes server-specific information such as
what printcap file to use, as well as descriptions of all the services that the
server is to provide. See
-.B smb.conf(5) for more information.
+.BR smb.conf (5)
+for more information.
.RE
-
.SH FILES
.B /etc/inetd.conf
@@ -179,23 +190,23 @@ mapping of service name (eg., netbios-ssn) to service port (eg., 139) and
protocol type (eg., tcp). See the section "INSTALLATION" below.
.RE
-.B /usr/local/smb/smb.conf
+.B /usr/local/samba/lib/smb.conf
.RS 3
This file describes all the services the server is to make available to
clients. See
-.B smb.conf(5) for more information.
+.BR smb.conf (5)
+for more information.
.RE
-.RE
-
.SH LIMITATIONS
-On some systems smbd cannot change uid back to root after a setuid() call.
+On some systems
+.B smbd
+cannot change uid back to root after a setuid() call.
Such systems are called "trapdoor" uid systems. If you have such a system,
you will be unable to connect from a client (such as a PC) as two different
users at once. Attempts to connect the second user will result in "access
denied" or similar.
-
.SH ENVIRONMENT VARIABLES
.B PRINTER
@@ -206,13 +217,12 @@ use the value of this variable (or "lp" if this variable is not defined)
as the name of the printer to use. This is not specific to the server,
however.
.RE
-
.SH INSTALLATION
The location of the server and its support files is a matter for individual
system administrators. The following are thus suggestions only.
It is recommended that the server software be installed under the
-/usr/local hierarchy, in a directory readable by all, writeable only
+/usr/local/samba hierarchy, in a directory readable by all, writeable only
by root. The server program itself should be executable by all, as
users may wish to run the server themselves (in which case it will of
course run with their privileges). The server should NOT be
@@ -220,7 +230,7 @@ setuid. On some systems it may be worthwhile to make smbd setgid to an
empty group. This is because some systems may have a security hole where
daemon processes that become a user can be attached to with a
debugger. Making the smbd file setgid to an empty group may prevent
-this hole from being exploited. This secrity hole and the suggested
+this hole from being exploited. This security hole and the suggested
fix has only been confirmed on Linux at the time this was written. It
is possible that this hole only exists in Linux, as testing on other
systems has thus far shown them to be immune.
@@ -239,9 +249,10 @@ modified to suit your needs.
The remaining notes will assume the following:
.RS 3
-smbd (the server program) installed in /usr/local/smb
+.B smbd
+(the server program) installed in /usr/local/samba/bin
-smb.conf (the configuration file) installed in /usr/local/smb
+smb.conf (the configuration file) installed in /usr/local/samba/lib
log files stored in /var/adm/smblogs
.RE
@@ -255,9 +266,13 @@ TCP-wrapper may be used for extra security.
When you've decided, continue with either "RUNNING THE SERVER AS A DAEMON" or
"RUNNING THE SERVER ON REQUEST".
.SH RUNNING THE SERVER AS A DAEMON
-To run the server as a daemon from the command line, simply put the "-D" option
+To run the server as a daemon from the command line, simply put the
+.B \-D
+option
on the command line. There is no need to place an ampersand at the end of the
-command line - the "-D" option causes the server to detach itself from the
+command line - the
+.B \-D
+option causes the server to detach itself from the
tty anyway.
Any user can run the server as a daemon (execute permissions permitting, of
@@ -273,7 +288,7 @@ port number, log file location, configuration file location and debug level as
desired:
.RS 3
-/usr/local/smb/smbd -D -l /var/adm/smblogs/log -s /usr/local/smb/smb.conf
+/usr/local/samba/bin/smbd -D -l /var/adm/smblogs/log -s /usr/local/samba/lib/smb.conf
.RE
(The above should appear in your initialisation script as a single line.
@@ -282,7 +297,9 @@ this man page. If the above appears as more than one line, please treat any
newlines or indentation as a single space or TAB character.)
If the options used at compile time are appropriate for your system, all
-parameters except the desired debug level and "-D" may be omitted. See the
+parameters except the desired debug level and
+.B \-D
+may be omitted. See the
section "OPTIONS" above.
.SH RUNNING THE SERVER ON REQUEST
If your system uses a meta-daemon such as inetd, you can arrange to have the
@@ -294,8 +311,9 @@ assistance of your system administrator to modify the system files.
You will probably want to set up the name server
.B nmbd
at the same time as
-the smbd - refer to the man page
-.B nmbd(8).
+.B smbd
+- refer to the man page
+.BR nmbd (8).
First, ensure that a port is configured in the file /etc/services. The
well-known port 139 should be used if possible, though any port may be used.
@@ -313,11 +331,14 @@ Next, put a suitable line in the file /etc/inetd.conf (in the unlikely event
that you are using a meta-daemon other than inetd, you are on your own). Note
that the first item in this line matches the service name in /etc/services.
Substitute appropriate values for your system in this line (see
-.B inetd(8)):
+.BR inetd (8)):
.RS 3
-netbios-ssn stream tcp nowait root /usr/local/smb/smbd -d1
--l/var/adm/smblogs/log -s/usr/local/smb/smb.conf
+.\" turn off right adjustment
+.ad l
+netbios-ssn stream tcp nowait root /usr/local/samba/bin/smbd -d1
+-l/var/adm/smblogs/log -s/usr/local/samba/lib/smb.conf
+.ad
.RE
(The above should appear in /etc/inetd.conf as a single line. Depending on
@@ -355,27 +376,28 @@ meta-daemon. Some versions of inetd will reread their configuration tables if
they receive a HUP signal.
If your machine's name is "fred" and your name is "mary", you should now be
-able to connect to the service "\\\\fred\\mary".
+able to connect to the service "\e\efred\emary".
To properly test and experiment with the server, we recommend using the
smbclient program (see
-.B smbclient(1)).
+.BR smbclient (1)).
.SH VERSION
-This man page is (mostly) correct for version 1.9.00 of the Samba suite, plus some
-of the recent patches to it. These notes will necessarily lag behind
+This man page is (mostly) correct for version 1.9.00 of the Samba suite,
+plus some of the recent patches to it. These notes will necessarily lag behind
development of the software, so it is possible that your version of
the server has extensions or parameter semantics that differ from or are not
covered by this man page. Please notify these to the address below for
rectification.
.SH SEE ALSO
-.B hosts_access(5),
-.B inetd(8),
-.B nmbd(8),
-.B smb.conf(5),
-.B smbclient(1),
-.B testparm(1),
-.B testprns(1)
-
+.BR hosts_access (5),
+.BR inetd (8),
+.BR nmbd (8),
+.BR smb.conf (5),
+.BR smbclient (1),
+.BR testparm (1),
+.BR testprns (1)
+.BR rfc1001.txt
+.BR rfc1002.txt
.SH DIAGNOSTICS
[This section under construction]
@@ -392,16 +414,15 @@ creation of this man page the source code is still too fluid to warrant
describing each and every diagnostic. At this stage your best bet is still
to grep the source code and inspect the conditions that gave rise to the
diagnostics you are seeing.
-
.SH BUGS
None known.
.SH CREDITS
The original Samba software and related utilities were created by
-Andrew Tridgell (samba-bugs@anu.edu.au). Andrew is also the Keeper
+Andrew Tridgell (samba-bugs@samba.anu.edu.au). Andrew is also the Keeper
of the Source for this project.
-This man page written by Karl Auer (Karl.Auer@anu.edu.au)
See
-.B smb.conf(5) for a full list of contributors and details on how to
+.BR smb.conf (5)
+for a full list of contributors and details on how to
submit bug reports, comments etc.
diff --git a/docs/manpages/smbpasswd.8 b/docs/manpages/smbpasswd.8
new file mode 100644
index 00000000000..edb7775f455
--- /dev/null
+++ b/docs/manpages/smbpasswd.8
@@ -0,0 +1,112 @@
+.TH SMBPASSWD 8 "30 Oct 1997" "smbpasswd 1.9.18alpha8"
+.SH NAME
+smbpasswd \- change a users smb password in the smbpasswd file.
+.SH SYNOPSIS
+.B smbpasswd
+[
+.B \-add
+] [
+.B username
+]
+.SH DESCRIPTION
+
+This program is part of the Samba suite.
+
+.B smbpasswd
+allows a user to change their encrypted smb password which
+is stored in the smbpasswd file (usually kept in the
+.I private
+directory under the
+.I Samba
+directory hierarchy. Ordinary users can only run the command
+with no options. It will prompt them for their old smb password
+and then ask them for their new password twice, to ensure that
+the new password was typed correctly. No passwords will
+be echoed on the screen whilst being typed. If you have a blank
+smb password (specified by the string "NO PASSWORD" in the
+smbpasswd file) then just press the <Enter> key when asked
+for your old password.
+
+The
+.I \-add
+and
+.I username
+options can only be used by a user running as root.
+
+.SH OPTIONS
+.I \-add
+
+.RS 3
+Specifies that the username following should be added to
+the
+.I smbpasswd
+file, with the new password typed (type <Enter> for the
+old password). This option is ignored if the username
+following already exists in the
+.I smbpasswd
+file and it is treated like a regular change password
+command. Note that the user to be added
+.B must
+already exist in the system password file (usually /etc/passwd)
+else the request to add the user will fail.
+
+.RE
+.I username
+
+.RS 3
+You may only specify a username to the smbpasswd command
+if you are running as root. Only root should have the
+permission to modify other users smb passwords.
+
+.RE
+.RE
+.SH INSTALLATION
+
+The location of the server and its support files is a matter for individual
+system administrators. The following are thus suggestions only.
+
+It is recommended that the
+.B smbpasswd
+program be installed in the /usr/local/samba/bin directory. This should be
+a directory readable by all, writeable only by root. The program should be
+executable by all. The program
+.B must
+be setuid root. This means the permissions should
+look like -r-sr-xr-x and the program must be owned by root.
+
+.SH VERSION
+
+This man page is correct for version 1.9.17 of the Samba suite.
+These notes will necessarily lag behind
+development of the software, so it is possible that your version of
+the program has extensions or parameter semantics that differ from or are not
+covered by this man page. Please notify these to the address below for
+rectification.
+.SH SEE ALSO
+.BR smbd (8),
+.BR smb.conf (5)
+.SH
+.B BUGS
+
+.RE
+The
+.B smbpasswd
+command is only useful if
+.I Samba
+has been compiled with encrypted passwords. See the file
+.I ENCRYPTION.txt
+in the docs directory for details on how to do this.
+
+.SH CREDITS
+.RE
+The original Samba software and related utilities were created by
+Andrew Tridgell (samba-bugs@samba.anu.edu.au). Andrew is also the Keeper
+of the Source for this project. smbpasswd and the encrypted password
+file code was written by Jeremy Allison (samba-bugs@samba.anu.edu.au).
+
+This man page was written by Jeremy Allison. Bug reports to samba-bugs@samba.anu.edu.au.
+
+See
+.BR smb.conf (5)
+for a full list of contributors and details of how to
+submit bug reports, comments etc.
diff --git a/docs/manpages/smbrun.1 b/docs/manpages/smbrun.1
index 1608d3bb345..5bd4c601118 100644
--- a/docs/manpages/smbrun.1
+++ b/docs/manpages/smbrun.1
@@ -1,4 +1,4 @@
-.TH SMBRUN 1 17/1/1995 smbrun smbrun
+.TH SMBRUN 1 "30 Oct 1997" "smbrun 1.9.18alpha8"
.SH NAME
smbrun \- interface program between smbd and external programs
.SH SYNOPSIS
@@ -12,7 +12,7 @@ is a very small 'glue' program, which runs shell commands for
the
.B smbd
daemon (see
-.B smbd(8)).
+.BR smbd (8)).
It first changes to the highest effective user and group ID that it can,
then runs the command line provided using the system() call. This program is
@@ -30,14 +30,13 @@ The PATH variable set for the environment in which
.B smbrun
is executed will affect what executables are located and executed if a
fully-qualified path is not given in the command.
-
.SH INSTALLATION
The location of the server and its support files is a matter for individual
system administrators. The following are thus suggestions only.
It is recommended that the
.B smbrun
-program be installed under the /usr/local hierarchy, in a directory readable
+program be installed under the /usr/local/samba hierarchy, in a directory readable
by all, writeable only by root. The program should be executable by all.
The program should NOT be setuid or setgid!
.SH VERSION
@@ -48,23 +47,28 @@ the program has extensions or parameter semantics that differ from or are not
covered by this man page. Please notify these to the address below for
rectification.
.SH SEE ALSO
-.B smbd(8),
-.B smb.conf(8)
+.BR smbd (8),
+.BR smb.conf (8)
.SH DIAGNOSTICS
-If smbrun cannot be located or cannot be executed by
+If
+.B smbrun
+cannot be located or cannot be executed by
+.B smbd
+then appropriate messages will be found in the
.B smbd
-then appropriate messages will be found in the smbd logs. Other diagnostics are
+logs. Other diagnostics are
dependent on the shell-command being run. It is advisable for your shell
commands to issue suitable diagnostics to aid trouble-shooting.
.SH BUGS
None known.
.SH CREDITS
The original Samba software and related utilities were created by
-Andrew Tridgell (samba-bugs@anu.edu.au). Andrew is also the Keeper
+Andrew Tridgell (samba-bugs@samba.anu.edu.au). Andrew is also the Keeper
of the Source for this project.
-This man page was written by Karl Auer (Karl.Auer@anu.edu.au)
+This man page was written by Karl Auer. Bug reports to samba-bugs@samba.anu.edu.au.
See
-.B smb.conf(5) for a full list of contributors and details of how to
+.BR smb.conf (5)
+for a full list of contributors and details of how to
submit bug reports, comments etc.
diff --git a/docs/manpages/smbstatus.1 b/docs/manpages/smbstatus.1
index 76dc50cbb53..07e6dd4f03f 100644
--- a/docs/manpages/smbstatus.1
+++ b/docs/manpages/smbstatus.1
@@ -1,41 +1,58 @@
-.TH SMBSTATUS 1 17/1/1995 smbstatus smbstatus
+.TH SMBSTATUS 1 "30 Oct 1997" "smbstatus 1.9.18alpha8"
.SH NAME
smbstatus \- report on current Samba connections
.SH SYNOPSIS
.B smbstatus
-[-d]
-[-s
+[
+.B \-b
+] [
+.B \-d
+] [
+.B \-p
+] [
+.B \-s
.I configuration file
]
.SH DESCRIPTION
This program is part of the Samba suite.
.B smbstatus
-is a very simple program to list the current Samba connections
+is a very simple program to list the current Samba connections.
-Just run the program and the output is self explanatory. You can offer
-a configuration filename to override the default. The default is
-CONFIGFILE from the Makefile.
+Just run the program and the output is self explanatory.
+.SH OPTIONS
+.B \-b
+gives brief output.
-Option
-.I -d
+.B \-d
gives verbose output.
-.I -p
-print a list of smbd processes and exit. Useful for scripting.
+.B \-p
+print a list of
+.B smbd
+processes and exit. Useful for scripting.
+.B \-s
+.I configuration file
+
+.RS 3
+The default configuration file name is determined at compile time.
+
+The file specified contains the configuration details required by the server.
+See
+.BR smb.conf (5)
+for more information.
+.RE
.SH ENVIRONMENT VARIABLES
Not applicable.
-
.SH INSTALLATION
The location of the server and its support files is a matter for individual
system administrators. The following are thus suggestions only.
It is recommended that the
.B smbstatus
-program be installed under the /usr/local hierarchy, in a directory readable
+program be installed under the /usr/local/samba hierarchy, in a directory readable
by all, writeable only by root. The program itself should be executable by all.
-
.SH VERSION
This man page is (mostly) correct for version 1.9.00 of the Samba suite, plus some
of the recent patches to it. These notes will necessarily lag behind
@@ -44,9 +61,10 @@ the program has extensions or parameter semantics that differ from or are not
covered by this man page. Please notify these to the address below for
rectification.
.SH SEE ALSO
-.B smb.conf(5),
-.B smbd(8)
+.BR smb.conf (5),
+.BR smbd (8)
See
-.B smb.conf(5) for a full list of contributors and details on how to
+.BR smb.conf (5)
+for a full list of contributors and details on how to
submit bug reports, comments etc.
diff --git a/docs/manpages/smbtar.1 b/docs/manpages/smbtar.1
index 0f1c38c271f..391e81e8d0f 100644
--- a/docs/manpages/smbtar.1
+++ b/docs/manpages/smbtar.1
@@ -1,45 +1,51 @@
-.TH SMBTAR 1 18/2/96 smbtar smbtar
+.TH SMBTAR 1 "30 Oct 1997" "smbtar 1.9.18alpha8"
.SH NAME
smbtar \- shell script for backing up SMB shares directly to UNIX tape drive
.SH SYNOPSIS
.B smbtar
.B \-s
.I server
-.B [ \-p
+[
+.B \-p
.I password
-.B ]
-.B [ \-x
+] [
+.B \-x
.I service
-.B ]
-.B [ \-X ]
-.B [ \-d
+] [
+.B \-X
+] [
+.B \-d
.I directory
-.B ]
-.B [ \-u
+] [
+.B \-u
.I user
-.B ]
-.B [ \-t
+] [
+.B \-t
.I tape
-.B ]
-.B [ \-b
+] [
+.B \-b
.I blocksize
-.B ]
-.B [ \-N
+] [
+.B \-N
.I filename
-.B ]
-.B [ \-i ]
-.B [ \-r ]
-.B [ \-l ]
-.B [ \-v ]
+] [
+.B \-i
+] [
+.B \-r
+] [
+.B \-l
+.I log level
+] [
+.B \-v
+]
.I filenames...
-
.SH DESCRIPTION
This program is an extension to the Samba suite.
.B smbtar
-is a very small shell script on top of smbclient, which dumps SMB
-shares directly to tape.
-
+is a very small shell script on top of
+.BR smbclient ,
+which dumps SMB shares directly to tape.
.SH OPTIONS
.B \-s
.I server
@@ -92,13 +98,15 @@ The user id to connect as. Default: UNIX login name.
.RS 3
Tape device. May be regular file or tape device. Default: Tape environmental
variable; if not set, a file called
-.I tar.out.
+.IR tar.out .
.RE
.B \-b
.I blocksize
.RS 3
-Blocking factor. Defaults to 20. See tar(1) for a fuller explanation.
+Blocking factor. Defaults to 20. See
+.BR tar (1)
+for a fuller explanation.
.RE
.B \-N
@@ -120,48 +128,52 @@ Restore. Files are restored to the share from the tar file.
.RE
.B \-l
+.I log level
.RS 3
-Debug level. Corresponds to -d flag on smbclient(1).
+Log (debug) level. Corresponds to
+.B \-d
+flag of
+.BR smbclient (1).
.RE
-
.SH ENVIRONMENT VARIABLES
The TAPE variable specifies the default tape device to write to. May
-be overidden with the -t option.
-
+be overridden with the
+.B \-t
+option.
.SH BUGS
-The smbtar script has different options from ordinary tar and tar
-called from smbclient.
-
+The
+.B smbtar
+script has different options from ordinary tar and tar
+called from
+.BR smbclient .
.SH CAVEATS
Sites that are more careful about security may not like the way
the script handles PC passwords. Backup and restore work on entire shares,
-should work on file lists.
-
+should work on file lists. smbtar works best with GNU tar and may
+not work well with other versions.
.SH VERSION
This man page is correct for version 1.9.15p8 of the Samba suite.
-
.SH SEE ALSO
-.B smbclient
-(8),
-.B smb.conf
-(8)
+.BR smbclient (8),
+.BR smb.conf (8)
.SH DIAGNOSTICS
See diagnostics for
.B smbclient
command.
-
.SH CREDITS
The original Samba software and related utilities were created by
-Andrew Tridgell (samba-bugs@anu.edu.au). Andrew is also the Keeper
+Andrew Tridgell (samba-bugs@samba.anu.edu.au). Andrew is also the Keeper
of the Source for this project.
Ricky Poulten (poultenr@logica.co.uk) wrote the tar extension and this
-man page. The smbtar script was heavily rewritten and improved by
+man page. The
+.B smbtar
+script was heavily rewritten and improved by
Martin Kraemer <Martin.Kraemer@mch.sni.de>. Many thanks to everyone
who suggested extensions, improvements, bug fixes, etc.
See
-.B smb.conf
-(5) for a full list of contributors and details of how to submit bug reports,
+.BR smb.conf (5)
+for a full list of contributors and details of how to submit bug reports,
comments etc.
diff --git a/docs/manpages/testparm.1 b/docs/manpages/testparm.1
index 4a0ffcbc489..a0703f3ec36 100644
--- a/docs/manpages/testparm.1
+++ b/docs/manpages/testparm.1
@@ -1,4 +1,4 @@
-.TH TESTPARM 1 17/1/1995 testparm testparm
+.TH TESTPARM 1 "30 Oct 1997" "testparm 1.9.18alpha8"
.SH NAME
testparm \- check an smbd configuration file for internal correctness
.SH SYNOPSIS
@@ -18,7 +18,9 @@ is a very simple test program to check an
.B smbd
configuration
file for internal correctness. If this program reports no problems, you can use
-the configuration file with confidence that smbd will successfully
+the configuration file with confidence that
+.B smbd
+will successfully
load the configuration file.
Note that this is NOT a guarantee that the services specified in the
@@ -56,18 +58,18 @@ parameter is supplied, or strange things may happen.
.SH FILES
.B smb.conf
.RS 3
-This is usually the name of the configuration file used by smbd.
+This is usually the name of the configuration file used by
+.BR smbd .
.RE
.SH ENVIRONMENT VARIABLES
Not applicable.
-
.SH INSTALLATION
The location of the server and its support files is a matter for individual
system administrators. The following are thus suggestions only.
It is recommended that the
.B testparm
-program be installed under the /usr/local hierarchy, in a directory readable
+program be installed under the /usr/local/samba hierarchy, in a directory readable
by all, writeable only by root. The program itself should be executable by all.
The program should NOT be setuid or setgid!
.SH VERSION
@@ -78,8 +80,8 @@ the program has extensions or parameter semantics that differ from or are not
covered by this man page. Please notify these to the address below for
rectification.
.SH SEE ALSO
-.B smb.conf(5),
-.B smbd(8)
+.BR smb.conf (5),
+.BR smbd (8)
.SH DIAGNOSTICS
The program will issue a message saying whether the configuration file loaded
OK or not. This message may be preceded by errors and warnings if the file
@@ -93,12 +95,15 @@ Other messages are self-explanatory.
None known.
.SH CREDITS
The original Samba software and related utilities were created by
-Andrew Tridgell (samba-bugs@anu.edu.au). Andrew is also the Keeper
+Andrew Tridgell (samba-bugs@samba.anu.edu.au). Andrew is also the Keeper
of the Source for this project.
-The testparm program and this man page were written by Karl Auer
-(Karl.Auer@anu.edu.au)
+The
+.B testparm
+program and this man page were written by Karl Auer. Bug reports to
+samba-bugs@samba.anu.edu.au.
See
-.B samba(7) for a full list of contributors and details on how to
+.BR samba (7)
+for a full list of contributors and details on how to
submit bug reports, comments etc.
diff --git a/docs/manpages/testprns.1 b/docs/manpages/testprns.1
index f1c3d3ef020..1ad5334837d 100644
--- a/docs/manpages/testprns.1
+++ b/docs/manpages/testprns.1
@@ -1,4 +1,4 @@
-.TH TESTPRNS 1 17/1/1995 testprns testprns
+.TH TESTPRNS 1 "30 Oct 1997" "testprns 1.9.18alpha8"
.SH NAME
testprns \- check printer name for validity with smbd
.SH SYNOPSIS
@@ -30,11 +30,12 @@ file, single printer names and sets of aliases separated by vertical bars
syntax is done beyond that required to extract the printer name. It may
be that the print spooling system is more forgiving or less forgiving
than
+.BR testprns .
+However, if
.B testprns
-however if
-.B testprns
-finds the printer then smbd should do as well.
-
+finds the printer then
+.B smbd
+should do so as well.
.RE
.I printcapname
@@ -52,18 +53,17 @@ will attempt to scan the printcap file specified at compile time
.B /etc/printcap
.RS 3
This is usually the default printcap file to scan. See
-.B printcap(5)).
+.BR printcap (5)).
.RE
.SH ENVIRONMENT VARIABLES
Not applicable.
-
.SH INSTALLATION
The location of the server and its support files is a matter for individual
system administrators. The following are thus suggestions only.
It is recommended that the
.B testprns
-program be installed under the /usr/local hierarchy, in a directory readable
+program be installed under the /usr/local/samba hierarchy, in a directory readable
by all, writeable only by root. The program should be executable by all.
The program should NOT be setuid or setgid!
.SH VERSION
@@ -74,9 +74,9 @@ the program has extensions or parameter semantics that differ from or are not
covered by this man page. Please notify these to the address below for
rectification.
.SH SEE ALSO
-.B printcap(5),
-.B smbd(8),
-.B smbclient(1)
+.BR printcap (5),
+.BR smbd (8),
+.BR smbclient (1)
.SH DIAGNOSTICS
If a printer is found to be valid, the message "Printer name <printername> is
valid" will be displayed.
@@ -84,7 +84,9 @@ valid" will be displayed.
If a printer is found to be invalid, the message "Printer name <printername>
is not valid" will be displayed.
-All messages that would normally be logged during operation of smbd are
+All messages that would normally be logged during operation of
+.B smbd
+are
logged by this program to the file
.I test.log
in the current directory. The program runs at debuglevel 3, so quite extensive
@@ -96,12 +98,15 @@ Other messages are self-explanatory.
None known.
.SH CREDITS
The original Samba software and related utilities were created by
-Andrew Tridgell (samba-bugs@anu.edu.au). Andrew is also the Keeper
+Andrew Tridgell (samba-bugs@samba.anu.edu.au). Andrew is also the Keeper
of the Source for this project.
-The testprns program and this man page were written by Karl Auer
-(Karl.Auer@anu.edu.au)
+The
+.B testprns
+program and this man page were written by Karl Auer. Bug reports to
+samba-bugs@samba.anu.edu.au.
See
-.B samba(7) for a full list of contributors and details of how to
+.BR samba (7)
+for a full list of contributors and details of how to
submit bug reports, comments etc.
diff --git a/docs/samba.lsm b/docs/samba.lsm
index 503ba1ec94b..36abbba769a 100644
--- a/docs/samba.lsm
+++ b/docs/samba.lsm
@@ -7,11 +7,11 @@ Desc3 = SMB compatible clients such as WinNT, WfWg, OS/2
Desc4 = and Pathworks. It also includes a ftp-style unix client
Desc5 = and a netbios nameserver.
Author = Andrew Tridgell
-AuthorEmail = samba-bugs@anu.edu.au
+AuthorEmail = samba-bugs@samba.anu.edu.au
Maintainer = Andrew Tridgell
-MaintEmail = samba-bugs@anu.edu.au
-Site1 = nimbus.anu.edu.au
-Path1 = pub/tridge/samba/
+MaintEmail = samba-bugs@samba.anu.edu.au
+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/Application_Serving.txt b/docs/textdocs/Application_Serving.txt
new file mode 100644
index 00000000000..7d48557b50b
--- /dev/null
+++ b/docs/textdocs/Application_Serving.txt
@@ -0,0 +1,53 @@
+!==
+!== Application_Serving.txt for Samba release 1.9.18alpha8 30 Oct 1997
+!==
+January 7, 1997
+Updated: June 27, 1997
+Contributor: John H Terpstra <samba-bugs@samba.anu.edu.au>
+ Copyright (C) 1997 - John H Terpstra
+Status: Current
+
+Subject: Using a Samba share as an administrative share for MS Office, etc.
+==============================================================================
+
+Problem:
+========
+Microsoft Office products can be installed as an administrative installation
+from which the application can either be run off the administratively installed
+product that resides on a shared resource, or from which that product can be
+installed onto workstation clients.
+
+The general mechanism for implementing an adminstrative installation involves
+running:
+ X:\setup /A, where X is the drive letter of either CDROM or floppy
+
+This installation process will NOT install the product for use per se, but
+rather results in unpacking of the compressed distribution files into a target
+shared folder. For this process you need write privilidge to the share and it
+is desirable to enable file locking and share mode operation during this
+process.
+
+Subsequent installation of MS Office from this share will FAIL unless certain
+precautions are taken. This failure will be caused by share mode operation
+which will prevent the MS Office installation process from re-opening various
+dynamic link library files and will cause sporadic file not found problems.
+
+Solution:
+=========
+1. As soon as the administrative installation (unpacking) has completed
+ set the following parameters on the share containing it:
+ [MSOP95]
+ path = /where_you_put_it
+ comment = Your comment
+ volume = "The_CD_ROM_Label"
+ read only = yes
+ available = yes
+ share modes = no
+ locking = no
+ browseable = yes
+ public = yes
+
+2. Now you are ready to run the setup program from the Microsoft Windows
+workstation as follows:-
+ \\"Server_Name"\MSOP95\msoffice\setup
+
diff --git a/docs/textdocs/BROWSING.txt b/docs/textdocs/BROWSING.txt
index 8a09d2274fb..911fd731417 100644
--- a/docs/textdocs/BROWSING.txt
+++ b/docs/textdocs/BROWSING.txt
@@ -1,60 +1,63 @@
+!==
+!== BROWSING.txt for Samba release 1.9.18alpha8 30 Oct 1997
+!==
+Author/s: Many (Thanks to Luke, Jeremy, Andrew, etc.)
+Updated: October 12, 1997
+Status: Current - For VERY Advanced Users ONLY
+
+Summary: This describes how to configure Samba for improved browsing.
+=====================================================================
+
+OVERVIEW:
+=========
+SMB networking provides a mechanism by which clients can access a list
+of machines that are available within the network. This list is called
+the browse list and is heavily used by all SMB clients. Configuration
+of SMB browsing has been problematic for some Samba users, hence this
+document.
+
+=====================================================================
+
BROWSING
========
-
-Samba now fully supports browsing. The browsing is supported by nmbd
-and is also controlled by options in the smb.conf file (see
-smb.conf(5)).
-
-Samba can act as a browse master for a workgroup, but currently cannot
-act as a domain controller. The ability to be a domain controller will
-be added in a later version.
+Samba now fully supports browsing. The browsing is supported by nmbd
+and is also controlled by options in the smb.conf file (see smb.conf(5)).
+
+Samba can act as a local browse master for a workgroup and the ability
+for samba to support domain logons and scripts is now available. See
+DOMAIN.txt for more information on domain logons.
+
+Samba can also act as a domain master browser for a workgroup. This
+means that it will collate lists from local browse masters into a
+wide area network server list. In order for browse clients to
+resolve the names they may find in this list, it is recommended that
+both samba and your clients use a WINS server.
+
+Note that you should NOT set Samba to be the domain master for a
+workgroup that has the same name as an NT Domain: on each wide area
+network, you must only ever have one domain master browser per workgroup,
+regardless of whether it is NT, Samba or any other type of domain master
+that is providing this service.
+
+[Note that nmbd can be configured as a WINS server, but it is not
+necessary to specifically use samba as your WINS server. NTAS can
+be configured as your WINS server. In a mixed NT server and
+samba environment on a Wide Area Network, it is recommended that
+you use the NT server's WINS server capabilities. In a samba-only
+environment, it is recommended that you use one and only one nmbd
+as your WINS server].
To get browsing to work you need to run nmbd as usual, but will need
to use the "workgroup" option in smb.conf to control what workgroup
Samba becomes a part of.
-The -G option is most useful for simple setups where Samba is browsable
-in only one workgroup. In more complex cases the lmhosts file is
-better.
-
-Be very careful setting up your lmhosts file. An incorrectly setup
-lmhosts file can have disasterous results for your net!
-
-A simple lmhosts file might be:
-
-# This is a simple lmhosts file
-#
-# This is a host alias. Anyone querying this name
-# will get the specified IP
-192.0.2.17 SMBDATA
-#
-# first put ourselves in workgroup MYGROUP using
-# our own net address
-0.0.0.0 MYGROUP G
-
-Note in the above that I overrode what workgroup Samba is in using the
-G flag. Also note that the 0.0.0.0 address is used, which will be
-automatically replaced with the broadcast address for groups, and with
-the local IP address for other entries.
-
Samba also has a useful option for a Samba server to offer itself for
-browsing on another subnet.
-
-This works by the lmhosts file specifying a broadcast address on the
-other network to use to find a browse master for the workgroup.
-
-For example if you wanted yourself to appear in the workgroup STAFF on
-the network which has a broadcast of 192.0.3.255 then this entry would
-do the trick:
-
-# put ourselves in the STAFF workgroup on the other subnet
-192.0.3.255 STAFF G
-
-Notice the G at the end! It is very important you include this as this
-entry without the G could cause a broadcast storm!
+browsing on another subnet. It is recommended that this option is only
+used for 'unusual' purposes: announcements over the internet, for
+example. See "remote announce" in the smb.conf man page.
If something doesn't work then hopefully the log.nmb file will
-help you track down the problem. Try a debug level of 2 or 3 for
+help you track down the problem. Try a debug level of 2 or 3 for
finding problems.
Note that if it doesn't work for you, then you should still be able to
@@ -62,84 +65,487 @@ type the server name as \\SERVER in filemanager then hit enter and
filemanager should display the list of available shares.
Some people find browsing fails because they don't have the global
-"guest account" set to a valid account. Remember that the IPC$
+"guest account" set to a valid account. Remember that the IPC$
connection that lists the shares is done as guest, and thus you must
have a valid guest account.
Also, a lot of people are getting bitten by the problem of too many
-parameters on the command line of nmbd in inetd.conf. This trick is to
+parameters on the command line of nmbd in inetd.conf. This trick is to
not use spaces between the option and the parameter (eg: -d2 instead
-of -d 2), and to not use the -B and -N options. New versions of nmbd
+of -d 2), and to not use the -B and -N options. New versions of nmbd
are now far more likely to correctly find your broadcast and network
addess, so in most cases these aren't needed.
The other big problem people have is that their broadcast address,
-netmask or IP address is wrong (specified with the -B, -N and -I
-options to nmbd).
+netmask or IP address is wrong (specified with the "interfaces" option
+in smb.conf)
+
+
+BROWSING ACROSS SUBNETS
+=======================
+
+With the release of Samba 1.9.17(alpha1 and above) Samba has been
+updated to enable it to support the replication of browse lists
+across subnet boundaries. New code and options have been added to
+achieve this. This section describes how to set this feature up
+in different settings.
+
+To see browse lists that span TCP/IP subnets (ie. networks separated
+by routers that don't pass broadcast traffic) you must set up at least
+one WINS server. The WINS server acts as a DNS for NetBIOS names, allowing
+NetBIOS name to IP address translation to be done by doing a direct
+query of the WINS server. This is done via a directed UDP packet on
+port 137 to the WINS server machine. The reason for a WINS server is
+that by default, all NetBIOS name to IP address translation is done
+by broadcasts from the querying machine. This means that machines
+on one subnet will not be able to resolve the names of machines on
+another subnet without using a WINS server.
+
+Remember, for browsing across subnets to work correctly, all machines,
+be they Windows 95, Windows NT, or Samba servers must have the IP address
+of a WINS server given to them by a DHCP server, or by manual configuration
+(for Win95 and WinNT, this is in the TCP/IP Properties, under Network
+settings) for Samba this is in the smb.conf file.
+
+How does cross subnet browsing work ?
+=====================================
+
+Cross subnet browsing is a complicated dance, containing multiple
+moving parts. It has taken Microsoft several years to get the code
+that achieves this correct, and Samba lags behind in some areas.
+However, with the 1.9.17 release, Samba is capable of cross subnet
+browsing when configured correctly.
+
+Consider a network set up as follows :
+
+ (DMB)
+ N1_A N1_B N1_C N1_D N1_E
+ | | | | |
+ -------------------------------------------------------
+ | subnet 1 |
+ +---+ +---+
+ |R1 | Router 1 Router 2 |R2 |
+ +---+ +---+
+ | |
+ | subnet 2 subnet 3 |
+ -------------------------- ------------------------------------
+ | | | | | | | |
+ N2_A N2_B N2_C N2_D N3_A N3_B N3_C N3_D
+ (WINS)
+
+Consisting of 3 subnets (1, 2, 3) conneted by two routers
+(R1, R2) - these do not pass broadcasts. Subnet 1 has 5 machines
+on it, subnet 2 has 4 machines, subnet 3 has 4 machines. Assume
+for the moment that all these machines are configured to be in the
+same workgroup (for simplicities sake). Machine N1_C on subnet 1
+is configured as Domain Master Browser (ie. it will collate the
+browse lists for the workgroup). Machine N2_D is configured as
+WINS server and all the other machines are configured to register
+their NetBIOS names with it.
+
+As all these machines are booted up, elections for master browsers
+will take place on each of the three subnets. Assume that machine
+N1_C wins on subnet 1, N2_B wins on subnet 2, and N3_D wins on
+subnet 3 - these machines are known as local master browsers for
+their particular subnet. N1_C has an advantage in winning as the
+local master browser on subnet 1 as it is set up as Domain Master
+Browser.
+
+On each of the three networks, machines that are configured to
+offer sharing services will broadcast that they are offering
+these services. The local master browser on each subnet will
+receive these broadcasts and keep a record of the fact that
+the machine is offering a service. This list of records is
+the basis of the browse list. For this case, assume that
+all the machines are configured to offer services so all machines
+will be on the browse list.
+
+For each network, the local master browser on that network is
+considered 'authoritative' for all the names it receives via
+local broadcast. This is because a machine seen by the local
+master browser via a local broadcast must be on the same
+network as the local master browser and thus is a 'trusted'
+and 'verifiable' resource. Machines on other networks that
+the local master browsers learn about when collating their
+browse lists have not been directly seen - these records are
+called 'non-authoritative'.
+
+At this point the browse lists look as follows (these are
+the machines you would see in your network neighborhood if
+you looked in it on a particular network right now).
+
+Subnet Browse Master List
+------ ------------- ----
+Subnet1 N1_C N1_A, N1_B, N1_C, N1_D, N1_E
+
+Subnet2 N2_B N2_A, N2_B, N2_C, N2_D
+
+Subnet3 N3_D N3_A, N3_B, N3_C, N3_D
+
+Note that at this point all the subnets are separate, no
+machine is seen across any of the subnets.
+
+Now examine subnet 2. As soon as N2_B has become the local
+master browser it looks for a Domain master browser to synchronize
+its browse list with. It does this by querying the WINS server
+(N2_D) for the IP address associated with the NetBIOS name
+WORKGROUP<1B>. This name was registerd by the Domain master
+browser (N1_C) with the WINS server as soon as it was booted.
+
+Once N2_B knows the address of the Domain master browser it
+tells it that is the local master browser for subnet 2 by
+sending a MasterAnnouncement packet as a UDP port 138 packet.
+It then synchronizes with it by doing a NetServerEnum2 call. This
+tells the Domain Master Browser to send it all the server
+names it knows about. Once the domain master browser receives
+the MasterAnnouncement packet it schedules a synchronization
+request to the sender of that packet. After both synchronizations
+are done the browse lists look like :
+
+Subnet Browse Master List
+------ ------------- ----
+Subnet1 N1_C N1_A, N1_B, N1_C, N1_D, N1_E,
+ N2_A(*), N2_B(*), N2_C(*), N2_D(*)
+
+Subnet2 N2_B N2_A, N2_B, N2_C, N2_D
+ N1_A(*), N1_B(*), N1_C(*), N1_D(*), N1_E(*)
+
+Subnet3 N3_D N3_A, N3_B, N3_C, N3_D
+
+Servers with a (*) after them are non-authoritative names.
+
+At this point users looking in their network neighborhood on
+subnets 1 or 2 will see all the servers on both, users on
+subnet 3 will still only see the servers on their own subnet.
+
+The same sequence of events that occured for N2_B now occurs
+for the local master browser on subnet 3 (N3_D). When it
+synchronizes browse lists with the domain master browser (N1_A)
+it gets both the server entries on subnet 1, and those on
+subnet 2. After N3_D has synchronized with N1_C and vica-versa
+the browse lists look like.
+
+Subnet Browse Master List
+------ ------------- ----
+Subnet1 N1_C N1_A, N1_B, N1_C, N1_D, N1_E,
+ N2_A(*), N2_B(*), N2_C(*), N2_D(*),
+ N3_A(*), N3_B(*), N3_C(*), N3_D(*)
+
+Subnet2 N2_B N2_A, N2_B, N2_C, N2_D
+ N1_A(*), N1_B(*), N1_C(*), N1_D(*), N1_E(*)
+
+Subnet3 N3_D N3_A, N3_B, N3_C, N3_D
+ N1_A(*), N1_B(*), N1_C(*), N1_D(*), N1_E(*),
+ N2_A(*), N2_B(*), N2_C(*), N2_D(*)
+
+Servers with a (*) after them are non-authoritative names.
+
+At this point users looking in their network neighborhood on
+subnets 1 or 3 will see all the servers on all sunbets, users on
+subnet 2 will still only see the servers on subnets 1 and 2, but not 3.
+
+Finally, the local master browser for subnet 2 (N2_B) will sync again
+with the domain master browser (N1_C) and will recieve the missing
+server entries. Finally - and as a steady state (if no machines
+are removed or shut off) the browse lists will look like :
+
+Subnet Browse Master List
+------ ------------- ----
+Subnet1 N1_C N1_A, N1_B, N1_C, N1_D, N1_E,
+ N2_A(*), N2_B(*), N2_C(*), N2_D(*),
+ N3_A(*), N3_B(*), N3_C(*), N3_D(*)
+
+Subnet2 N2_B N2_A, N2_B, N2_C, N2_D
+ N1_A(*), N1_B(*), N1_C(*), N1_D(*), N1_E(*)
+ N3_A(*), N3_B(*), N3_C(*), N3_D(*)
+
+Subnet3 N3_D N3_A, N3_B, N3_C, N3_D
+ N1_A(*), N1_B(*), N1_C(*), N1_D(*), N1_E(*),
+ N2_A(*), N2_B(*), N2_C(*), N2_D(*)
+
+Servers with a (*) after them are non-authoritative names.
+
+Synchronizations between the domain master browser and local
+master browsers will continue to occur, but this should be a
+steady state situation.
+
+If either router R1 or R2 fails the following will occur:
+
+1) Names of computers on each side of the inaccessible network fragments
+will be maintained for as long as 36 minutes, in the network neighbourhood
+lists.
+
+2) Attempts to connect to these inaccessible computers will fail, but the
+names will not be removed from the network neighbourhood lists.
+
+3) If one of the fragments is cut off from the WINS server, it will only
+be able to access servers on its local subnet, by using subnet-isolated
+broadcast NetBIOS name resolution. The effects are similar to that of
+losing access to a DNS server.
+
+Setting up a WINS server
+========================
+
+Either a Samba machine or a Windows NT Server machine may be set up
+as a WINS server. To set a Samba machine to be a WINS server you must
+add the following option to the smb.conf file on the selected machine :
+in the [globals] section add the line
+
+ wins support = yes
+
+Versions of Samba previous to 1.9.17 had this parameter default to
+yes. If you have any older versions of Samba on your network it is
+strongly suggested you upgrade to 1.9.17 or above, or at the very
+least set the parameter to 'no' on all these machines.
+
+Machines with "wins support = yes" will keep a list of all NetBIOS
+names registered with them, acting as a DNS for NetBIOS names.
+
+You should set up only ONE wins server. Do NOT set the
+"wins support = yes" option on more than one Samba server.
+
+To set up a Windows NT Server as a WINS server you need to set up
+the WINS service - see your NT documentation for details. Note that
+Windows NT WINS Servers can replicate to each other, allowing more
+than one to be set up in a complex subnet environment. As Microsoft
+refuse to document these replication protocols Samba cannot currently
+participate in these replications. It is possible in the future that
+a Samba->Samba WINS replication protocol may be defined, in which
+case more than one Samba machine could be set up as a WINS server
+but currently only one Samba server should have the "wins support = yes"
+parameter set.
+
+After the WINS server has been configured you must ensure that all
+machines participating on the network are configured with the address
+of this WINS server. If your WINS server is a Samba machine, fill in
+the Samba machine IP address in the "Primary WINS Server" field of
+the "Control Panel->Network->Protocols->TCP->WINS Server" dialogs
+in Windows 95 or Windows NT. To tell a Samba server the IP address
+of the WINS server add the following line to the [global] section of
+all smb.conf files :
+
+ wins server = <name or IP address>
+
+where <name or IP address> is either the DNS name of the WINS server
+machine or its IP address.
+
+Note that this line MUST NOT BE SET in the smb.conf file of the Samba
+server acting as the WINS server itself. If you set both the
+"wins support = yes" option and the "wins server = <name>" option then
+nmbd will fail to start.
+
+There are two possible scenarios for setting up cross subnet browsing.
+The first details setting up cross subnet browsing on a network containing
+Windows 95, Samba and Windows NT machines that are not configured as
+part of a Windows NT Domain. The second details setting up cross subnet
+browsing on networks that contain NT Domains.
+
+Setting up Browsing in a WORKGROUP
+==================================
+
+To set up cross subnet browsing on a network containing machines
+in up to be in a WORKGROUP, not an NT Domain you need to set up one
+Samba server to be the Domain Master Browser (note that this is *NOT*
+the same as a Primary Domain Controller, although in an NT Domain the
+same machine plays both roles). The role of a Domain master browser is
+to collate the browse lists from local master browsers on all the
+subnets that have a machine participating in the workgroup. Without
+one machine configured as a domain master browser each subnet would
+be an isolated workgroup, unable to see any machines on any other
+subnet. It is the presense of a domain master browser that makes
+cross subnet browsing possible for a workgroup.
+
+In an WORKGROUP environment the domain master browser must be a
+Samba server, and there must only be one domain master browser per
+workgroup name. To set up a Samba server as a domain master browser,
+set the following option in the [global] section of the smb.conf file :
+
+ domain master = yes
+
+The domain master browser should also preferrably be the local master
+browser for its own subnet. In order to achieve this set the following
+options in the [global] section of the smb.conf file :
+
+ domain master = yes
+ local master = yes
+ preferred master = yes
+ os level = 65
+
+The domain master browser may be the same machine as the WINS
+server, if you require.
+
+Next, you should ensure that each of the subnets contains a
+machine that can act as a local master browser for the
+workgroup. Any NT machine should be able to do this, as will
+Windows 95 machines (although these tend to get rebooted more
+often, so it's not such a good idea to use these). To make a
+Samba server a local master browser set the following
+options in the [global] section of the smb.conf file :
+
+ domain master = no
+ local master = yes
+ preferred master = yes
+ os level = 65
+
+Do not do this for more than one Samba server on each subnet,
+or they will war with each other over which is to be the local
+master browser.
+
+The "local master" parameter allows Samba to act as a local master
+browser. The "preferred master" causes nmbd to force a browser
+election on startup and the "os level" parameter sets Samba high
+enough so that it should win any browser elections.
+
+If you have an NT machine on the subnet that you wish to
+be the local master browser then you can disable Samba from
+becoming a local master browser by setting the following
+options in the [global] section of the smb.conf file :
+
+ domain master = no
+ local master = no
+ preferred master = no
+ os level = 0
+
+Setting up Browsing in a DOMAIN
+===============================
+
+If you are adding Samba servers to a Windows NT Domain then
+you must not set up a Samba server as a domain master browser.
+By default, a Windows NT Primary Domain Controller for a Domain
+name is also the Domain master browser for that name, and many
+things will break if a Samba server registers the Domain master
+browser NetBIOS name (DOMAIN<1B>) with WINS instead of the PDC.
+
+For subnets other than the one containing the Windows NT PDC
+you may set up Samba servers as local master browsers as
+described. To make a Samba server a local master browser set
+the following options in the [global] section of the smb.conf
+file :
+
+ domain master = no
+ local master = yes
+ preferred master = yes
+ os level = 65
+
+If you wish to have a Samba server fight the election with machines
+on the same subnet you may set the "os level" parameter to lower
+levels. By doing this you can tune the order of machines that
+will become local master browsers if they are running. For
+more details on this see the section "FORCING SAMBA TO BE THE MASTER"
+below.
+
+If you have Windows NT machines that are members of the domain
+on all subnets, and you are sure they will always be running then
+you can disable Samba from taking part in browser elections and
+ever becoming a local master browser by setting following options
+in the [global] section of the smb.conf file :
+
+ domain master = no
+ local master = no
+ preferred master = no
+ os level = 0
FORCING SAMBA TO BE THE MASTER
==============================
Who becomes the "master browser" is determined by an election process
-using broadcasts. Each election packet contains a number of parameters
+using broadcasts. Each election packet contains a number of parameters
which determine what precedence (bias) a host should have in the
-election. By default Samba uses a very low precedence and thus loses
+election. By default Samba uses a very low precedence and thus loses
elections to just about anyone else.
If you want Samba to win elections then just set the "os level" global
-option in smb.conf to a higher number. It defaults to 0. Using 33
+option in smb.conf to a higher number. It defaults to 0. Using 34
would make it win all elections over every other system (except other
samba systems!)
-A "os level" of 2 would make it beat WfWg and Win95, but not NTAS. A
+A "os level" of 2 would make it beat WfWg and Win95, but not NTAS. A
NTAS domain controller uses level 32.
The maximum os level is 255
+If you want samba to force an election on startup, then set the
+"preferred master" global option in smb.conf to "yes". Samba will
+then have a slight advantage over other potential master browsers
+that are not preferred master browsers. Use this parameter with
+care, as if you have two hosts (whether they are windows 95 or NT or
+samba) on the same local subnet both set with "preferred master" to
+"yes", then periodically and continually they will force an election
+in order to become the local master browser.
+
+If you want samba to be a "domain master browser", then it is
+recommended that you also set "preferred master" to "yes", because
+samba will not become a domain master browser for the whole of your
+LAN or WAN if it is not also a local master browser on its own
+broadcast isolated subnet.
+
+It is possible to configure two samba servers to attempt to become
+the domain master browser for a domain. The first server that comes
+up will be the domain master browser. All other samba servers will
+attempt to become the domain master browser every 5 minutes. They
+will find that another samba server is already the domain master
+browser and will fail. This provides automatic redundancy, should
+the current domain master browser fail.
+
+
MAKING SAMBA THE DOMAIN MASTER
==============================
The domain master is responsible for collating the browse lists of
-multiple subnets so that browsing can occur between subnets. You can
+multiple subnets so that browsing can occur between subnets. You can
make samba act as the domain master by setting "domain master = yes"
-in smb.conf. By default it will not be a domain master.
+in smb.conf. By default it will not be a domain master.
+
+Note that you should NOT set Samba to be the domain master for a
+workgroup that has the same name as an NT Domain.
When samba is the domain master and the master browser it will listen
-for master announcements from other subnets and then contact them to
-synchronise browse lists.
+for master announcements (made roughly every twelve minutes) from local
+master browsers on other subnets and then contact them to synchronise
+browse lists.
If you want samba to be the domain master then I suggest you also set
-the "os level" high enough to make sure it wins elections.
+the "os level" high enough to make sure it wins elections, and set
+"preferred master" to "yes", to get samba to force an election on
+startup.
-NOTIFYING THE DOMAIN CONTROLLER
-===============================
+Note that all your servers (including samba) and clients should be
+using a WINS server to resolve NetBIOS names. If your clients are only
+using broadcasting to resolve NetBIOS names, then two things will occur:
+
+a) your local master browsers will be unable to find a domain master
+ browser, as it will only be looking on the local subnet.
-If you have a domain controller for the domain which Samba is a part
-of then you should add the line "domain controller = address" to
-smb.conf. "address" can either be a name available via DNS or a IP
-address or a broadcast address. If it is a broadcast address then
-Samba will look for a domain controller on that network.
+b) if a client happens to get hold of a domain-wide browse list, and
+ a user attempts to access a host in that list, it will be unable to
+ resolve the NetBIOS name of that host.
-When Samba is the master browser it will regularly contact the domain
-controller to synchronise browse lists.
+If, however, both samba and your clients are using a WINS server, then:
+a) your local master browsers will contact the WINS server and, as long as
+ samba has registered that it is a domain master browser with the WINS
+ server, your local master browser will receive samba's ip address
+ as its domain master browser.
+
+b) when a client receives a domain-wide browse list, and a user attempts
+ to access a host in that list, it will contact the WINS server to
+ resolve the NetBIOS name of that host. as long as that host has
+ registered its NetBIOS name with the same WINS server, the user will
+ be able to see that host.
NOTE ABOUT BROADCAST ADDRESSES
==============================
If your network uses a "0" based broadcast address (for example if it
-ends in a 0) then you will strike problems. Windows for Workgroups
+ends in a 0) then you will strike problems. Windows for Workgroups
does not seem to support a 0's broadcast and you will probably find
that browsing and name lookups won't work.
-You have a few options:
-
-1) change to a 1's broadcast on your unix server. These often end in
-.255 (check with your local network guru for details)
-2) set the nmbd broadcast to a 1's based address on the command line using
-the -B option. This only works if your network setup listens on both
-0s and 1s based broadcasts. The -B option can only control what
-address it sends to, not what it listens on.
+MULTIPLE INTERFACES
+===================
+Samba now supports machines with multiple network interfaces. If you
+have multiple interfaces then you will need to use the "interfaces"
+option in smb.conf to configure them. See smb.conf(5) for details.
diff --git a/docs/textdocs/BUGS.txt b/docs/textdocs/BUGS.txt
index e0fd6951477..bb522b315a8 100644
--- a/docs/textdocs/BUGS.txt
+++ b/docs/textdocs/BUGS.txt
@@ -1,31 +1,34 @@
-This file describes how to report Samba bugs.
+!==
+!== BUGS.txt for Samba release 1.9.18alpha8 30 Oct 1997
+!==
+Contributor: Samba Team
+Updated: June 27, 1997
->> 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)
+Subject: This file describes how to report Samba bugs.
+============================================================================
+>> The email address for bug reports is samba-bugs@samba.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.
+report. Also, please see if it has changed between releases, as we
+may be changing the bug reporting mechanism at some time.
Please also do as much as you can yourself to help track down the
-bug. I only develop Samba in my spare time and I receive far more mail
-about it than I can possibly answer, so you have a much higher chance
-of an answer and a fix if you send me a "developer friendly" bug
-report that lets me fix it fast.
+bug. Samba is maintained by a dedicated group of people who volunteer
+their time, skills and efforts. We receive far more mail about it than
+we can possibly answer, so you have a much higher chance of an answer
+and a fix if you send us a "developer friendly" bug report that lets
+us 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 we 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) 5000 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.anu.edu.au/samba/
GENERAL INFO
@@ -36,6 +39,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.
@@ -54,6 +59,7 @@ To set the debug level use "log level =" in your smb.conf. You may
also find it useful to set the log level higher for just one machine
and keep separate logs for each machine. To do this use:
+log level = 10
log file = /usr/local/samba/lib/log.%m
include = /usr/local/samba/lib/smb.conf.%m
@@ -63,6 +69,15 @@ put any smb.conf commands you want, for example "log level=" may be
useful. This also allows you to experiment with different security
systems, protocol levels etc on just one machine.
+The smb.conf entry "log level =" is synonymous with the entry
+"debuglevel =" that has been used in older versions of Samba and
+is being retained for backwards compatibility of smb.conf files.
+
+As the "log level =" value is increased you will record a significantly
+increasing level of debugging information. For most debugging operations
+you may not need a setting higher than 3. Nearly all bugs can be tracked
+at a setting of 10, but be prepared for a VERY large volume of log data.
+
INTERNAL ERRORs
---------------
@@ -115,7 +130,7 @@ where it occurred.
PATCHES
-------
-The best sort of bug report is one that includes a fix! If you send me
+The best sort of bug report is one that includes a fix! If you send us
patches please use "diff -u" format if your version of diff supports
it, otherwise use "diff -c4". Make sure your do the diff against a
clean version of the source and let me know exactly what version you
diff --git a/docs/textdocs/DIAGNOSIS.txt b/docs/textdocs/DIAGNOSIS.txt
index 6681bdc4bcb..ff640348748 100644
--- a/docs/textdocs/DIAGNOSIS.txt
+++ b/docs/textdocs/DIAGNOSIS.txt
@@ -1,5 +1,11 @@
-DIAGNOSING YOUR SAMBA SERVER
-============================
+!==
+!== DIAGNOSIS.txt for Samba release 1.9.18alpha8 30 Oct 1997
+!==
+Contributor: Andrew Tridgell
+Updated: October 14, 1997
+
+Subject: DIAGNOSING YOUR SAMBA SERVER
+===========================================================================
This file contains a list of tests you can perform to validate your
Samba server. It also tells you what the likely cause of the problem
@@ -11,7 +17,7 @@ carefully choose them so later tests only use capabilities verified in
the earlier tests.
I would welcome additions to this set of tests. Please mail them to
-samba-bugs@anu.edu.au
+samba-bugs@samba.anu.edu.au
If you send me an email saying "it doesn't work" and you have not
followed this test procedure then you should not be surprised if I
@@ -23,10 +29,12 @@ ASSUMPTIONS
In all of the tests I assume you have a Samba server called BIGSERVER
and a PC called ACLIENT. I also assume the PC is running windows for
-workgroups with a recent copy of the microsoft tcp/ip stack. The
-procedure is similar for other types of clients.
+workgroups with a recent copy of the microsoft tcp/ip stack. Alternatively,
+your PC may be running Windows 95 or Windows NT (Workstation or Server).
+
+The procedure is similar for other types of clients.
-I also assume you know the name of a available share in your
+I also assume you know the name of an available share in your
smb.conf. I will assume this share is called "tmp". You can add a
"tmp" share like by adding the following to smb.conf:
@@ -36,15 +44,28 @@ smb.conf. I will assume this share is called "tmp". You can add a
read only = yes
-THESE TESTS ASSUME VERSION 1.9.15 OR LATER OF THE SAMBA SUITE. SOME
+THESE TESTS ASSUME VERSION 1.9.16 OR LATER OF THE SAMBA SUITE. SOME
COMMANDS SHOWN DID NOT EXIST IN EARLIER VERSIONS
+Please pay attention to the error messages you receive. If any error message
+reports that your server is being unfriendly you should first check that you
+IP name resolution is correctly set up. eg: Make sure your /etc/resolv.conf
+file points to name servers that really do exist.
+
+Also, if you do not have DNS server access for name resolution please check
+that the settings for your smb.conf file results in "dns proxy = no". The
+best way to check this is with "testparm smb.conf"
+
TEST 1:
-------
-run the command "testparm". If it reports any errors then your
-smb.conf configuration file is faulty.
+In the directory in which you store your smb.conf file, run the command
+"testparm smb.conf". If it reports any errors then your smb.conf
+configuration file is faulty.
+
+Note: Your smb.conf file may be located in: /etc
+ Or in: /usr/local/samba/lib
TEST 2:
@@ -60,13 +81,18 @@ run ping.
If you get a message saying "host not found" or similar then your DNS
software or /etc/hosts file is not correctly setup. It is possible to
run samba without DNS entries for the server and client, but I assume
-you do have correct entries for the remainder of these tests.
+you do have correct entries for the remainder of these tests.
+
+Another reason why ping might fail is if your host is running firewall
+software. You will need to relax the rules to let in the workstation
+in question, perhaps by allowing access from another subnet (on Linux
+this is done via the ipfwadm program.)
TEST 3:
-------
-run the command "smbclient -L BIGSERVER -U%" on the unix box. You
+Run the command "smbclient -L BIGSERVER" on the unix box. You
should get a list of available shares back.
If you get a error message containing the string "Bad password" then
@@ -77,7 +103,7 @@ temporarily remove any "hosts allow", "hosts deny", "valid users" or
"invalid users" lines.
If you get a "connection refused" response then the smbd server could
-not be run. If you installed it in inetd.conf then you probably edited
+not be running. If you installed it in inetd.conf then you probably edited
that file incorrectly. If you installed it as a daemon then check that
it is running, and check that the netbios-ssn port is in a LISTEN
state using "netstat -a".
@@ -86,16 +112,24 @@ 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 (smb.conf) for syntax errors with "testparm"
+and that the various directories where samba keeps its log and lock
+files exist.
+
+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:
-------
-run the command "nmblookup -B BIGSERVER __SAMBA__". You should get the
+Run the command "nmblookup -B BIGSERVER __SAMBA__". You should get the
IP address of your Samba server back.
If you don't then nmbd is incorrectly installed. Check your inetd.conf
-if yu run it from there, or that the daemon is running and listening
+if you run it from there, or that the daemon is running and listening
to udp port 137.
One common problem is that many inetd implementations can't take many
@@ -103,6 +137,7 @@ parameters on the command line. If this is the case then create a
one-line script that contains the right parameters and run that from
inetd.
+
TEST 5:
-------
@@ -110,14 +145,13 @@ run the command "nmblookup -B ACLIENT '*'"
You should get the PCs IP address back. If you don't then the client
software on the PC isn't installed correctly, or isn't started, or you
-got the name of the PC wrong. Note that you probably won't get a "node
-status response" from the PC due to a bug in the microsoft netbios
-nameserver implementation (it responds to the wrong port number).
+got the name of the PC wrong.
+
TEST 6:
-------
-run the command "nmblookup -d 2 '*'"
+Run the command "nmblookup -d 2 '*'"
This time we are trying the same as the previous test but are trying
it via a broadcast to the default broadcast address. A number of
@@ -128,29 +162,19 @@ hosts.
If this doesn't give a similar result to the previous test then
nmblookup isn't correctly getting your broadcast address through its
-automatic mechanism. In this case you should experiment with the -B
-option which allows you to manually specify the broadcast address,
-overriding the automatic detection. You should try different broadcast
-addresses until your find the one that works. It will most likely be
-something like a.b.c.255 as microsoft tcpip stacks only listen on 1's
-based broadcast addresses. If you get stuck then ask your local
-networking guru for help (and show them this paragraph).
-
-If you find you do need the -B option (ie. the automatic detection
-doesn't work) then you should add the -B option with the right
-broadcast address for your network to the command line of nmbd in
-inetd.conf or in the script you use to start nmbd as a daemon. Once
-you do this go back to the "nmblookup __SAMBA__ -B BIGSERVER" test to
-make sure you have it running properly.
+automatic mechanism. In this case you should experiment use the
+"interfaces" option in smb.conf to manually configure your IP
+address, broadcast and netmask.
If your PC and server aren't on the same subnet then you will need to
use the -B option to set the broadcast address to the that of the PCs
subnet.
+
TEST 7:
-------
-run the command "smbclient '\\BIGSERVER\TMP'". You should then be
+Run the command "smbclient '\\BIGSERVER\TMP'". You should then be
prompted for a password. You should use the password of the account
you are logged into the unix box with. If you want to test with
another account then add the -U <accountname> option to the command
@@ -168,6 +192,8 @@ compile in support for them in smbd
- you have a mixed case password and you haven't enabled the "password
level" option at a high enough level
- the "path =" line in smb.conf is incorrect. Check it with testparm
+- you enabled password encryption but didn't create the SMB encrypted
+password file
Once connected you should be able to use the commands "dir" "get"
"put" etc. Type "help <command>" for instructions. You should
@@ -199,11 +225,16 @@ same fixes apply as they did for the "smbclient -L" test above. In
particular, make sure your "hosts allow" line is correct (see the man
pages)
+If you get "specified computer is not receiving requests" or similar
+it probably means that the host is not contactable via tcp services.
+Check to see if the host is running tcp wrappers, and if so add an entry in
+the hosts.allow file for your client (or subnet, etc.)
+
TEST 9:
--------
-run the command "net use x: \\BIGSERVER\TMP". You should be prompted
+Run the command "net use x: \\BIGSERVER\TMP". You should be prompted
for a password then you should get a "command completed successfully"
message. If not then your PC software is incorrectly installed or your
smb.conf is incorrect. make sure your "hosts allow" and other config
@@ -221,17 +252,24 @@ TEST 10:
From file manager try to browse the server. Your samba server should
appear in the browse list of your local workgroup (or the one you
-specified in the Makefile). You should be able to double click on the
-name of the server and get a list of shares. If you get a "invalid
+specified in smb.conf). You should be able to double click on the name
+of the server and get a list of shares. If you get a "invalid
password" error when you do then you are probably running WinNT and it
is refusing to browse a server that has no encrypted password
-capability and is in user level security mode.
+capability and is in user level security mode. In this case either set
+"security = server" AND "password server = Windows_NT_Machine" in your
+smb.conf file, or enable encrypted passwords AFTER compiling in support
+for encrypted passwords (refer to the Makefile).
Still having troubles?
----------------------
Try the mailing list or newsgroup, or use the tcpdump-smb utility to
-sniff the problem.
+sniff the problem. The official samba mailing list can be reached at
+samba@samba.anu.edu.au. To find out more about samba and how to
+subscribe to the mailing list check out the samba web page at
+ http://samba.anu.edu.au/samba
+Also look at the other docs in the Samba package!
diff --git a/docs/textdocs/DNIX.txt b/docs/textdocs/DNIX.txt
index 51005e6ec8c..f54f9130902 100644
--- a/docs/textdocs/DNIX.txt
+++ b/docs/textdocs/DNIX.txt
@@ -1,3 +1,6 @@
+!==
+!== DNIX.txt for Samba release 1.9.18alpha8 30 Oct 1997
+!==
DNIX has a problem with seteuid() and setegid(). These routines are
needed for Samba to work correctly, but they were left out of the DNIX
C library for some reason.
diff --git a/docs/textdocs/DOMAIN.txt b/docs/textdocs/DOMAIN.txt
index 31e19675fae..4fb6823cea3 100644
--- a/docs/textdocs/DOMAIN.txt
+++ b/docs/textdocs/DOMAIN.txt
@@ -1,68 +1,372 @@
-Samba now supports domain logons and network logon scripts. The
-support is still experimental, but it seems to work.
+!==
+!== DOMAIN.txt for Samba release 1.9.18alpha8 30 Oct 1997
+!==
+Contributor: Samba Team
+Updated: June 27, 1997
-The support is also not complete. Samba does not yet support the
-sharing of the SAM database with other systems yet, or remote
-administration. Support for these kind of things should be added
-sometime in the future.
+Subject: Network Logons and Roving Profiles
+===========================================================================
+
+A domain and a workgroup are exactly the same thing in terms of network
+browsing. The difference is that a distributable authentication
+database is associated with a domain, for secure login access to a
+network. Also, different access rights can be granted to users if they
+successfully authenticate against a domain logon server (samba does not
+support this, but NT server and other systems based on NT server do).
+
+The SMB client logging on to a domain has an expectation that every other
+server in the domain should accept the same authentication information.
+However the network browsing functionality of domains and workgroups is
+identical and is explained in BROWSING.txt.
+
+Issues related to the single-logon network model are discussed in this
+document. Samba supports domain logons, network logon scripts, and user
+profiles. The support is still experimental, but it seems to work.
+
+The support is also not complete. Samba does not yet support the sharing
+of the Windows NT-style SAM database with other systems. However this is
+only one way of having a shared user database: exactly the same effect can
+be achieved by having all servers in a domain share a distributed NIS or
+Kerberos authentication database.
+
+When an SMB client in a domain wishes to logon it broadcast requests for a
+logon server. The first one to reply gets the job, and validates its
+password using whatever mechanism the Samba administrator has installed.
+It is possible (but very stupid) to create a domain where the user
+database is not shared between servers, ie they are effectively workgroup
+servers advertising themselves as participating in a domain. This
+demonstrates how authentication is quite different from but closely
+involved with domains.
+
+Another thing commonly associated with single-logon domains is remote
+administration over the SMB protocol. Again, there is no reason why this
+cannot be implemented with an underlying username database which is
+different from the Windows NT SAM. Support for the Remote Administration
+Protocol is planned for a future release of Samba.
+
+The domain support works for WfWg, and Win95 clients and NT 4.0 and 3.51.
+Domain support is currently at an early experimental stage for NT 4.0 and
+NT 3.51. Support for Windows OS/2 clients is still being worked on and is
+still experimental.
+
+Support for profiles is confirmed as working for Win95, NT 4.0 and NT 3.51.
+It is possible to specify: the profile location; script file to be loaded
+on login; the user's home directory; and for NT a kick-off time could also
+now easily be supported.
+
+With NT Workstations, all this does not require the use or intervention of
+an NT 4.0 or NT 3.51 server: Samba can now replace the logon services
+provided by an NT server, to a limited and experimental degree (for example,
+running "User Manager for Domains" will not provide you with access to
+a domain created by a Samba Server).
+
+With Win95, the help of an NT server can be enlisted, both for profile storage
+and for user authentication. For details on user authentication, see
+security_level.txt. For details on profile storage, see below.
-The domain support only works for WfWg and Win95 clients. Support for
-NT and OS/2 clients is still being worked on.
Using these features you can make your clients verify their logon via
-the Samba server and make clients run a batch file when they logon to
-the network. The latter is particularly useful.
+the Samba server; make clients run a batch file when they logon to
+the network and download their preferences, desktop and start menu.
+
+
+Configuration Instructions: Network Logons
+==========================================
+
+To use domain logons and profiles you need to do the following:
+
-To use domain logons you need to do the following:
+1) Setup nmbd and smbd by configuring smb.conf so that Samba is
+ acting as the master browser. See <your OS>_INSTALL.txt and BROWSING.txt
+ for details.
-1) Setup nmbd and smbd and configure the smb.conf so that Samba is
-acting as the master browser. See INSTALL.txt and BROWSING.txt for
-details.
+2) Setup a WINS server (see NetBIOS.txt) and configure all your clients
+ to use that WINS service.
-2) create a share called [netlogon] in your smb.conf. This share should
-be readable by all users, and probably should not be writeable. This
-share will hold your network logon scripts.
+3) Create a share called [netlogon] in your smb.conf. This share should
+ be readable by all users, and probably should not be writeable. This
+ share will hold your network logon scripts, and the CONFIG.POL file
+ (Note: for details on the CONFIG.POL file, how to use it, what it is,
+ refer to the Microsoft Windows NT Administration documentation.
+ The format of these files is not known, so you will need to use
+ Microsoft tools).
For example I have used:
[netlogon]
path = /data/dos/netlogon
writeable = no
- guest ok = yes
+ guest ok = no
+Note that it is important that this share is not writeable by ordinary
+users, in a secure environment: ordinary users should not be allowed
+to modify or add files that another user's computer would then download
+when they log in.
-3) in the [global] section of smb.conf set the following:
+4) in the [global] section of smb.conf set the following:
domain logons = yes
logon script = %U.bat
-the choice of batch file is, of course, up to you. The above would
+The choice of batch file is, of course, up to you. The above would
give each user a separate batch file as the %U will be changed to
their username automatically. The other standard % macros may also be
-used. You can make the btch files come from a subdirectory by using
-soemthing like:
+used. You can make the batch files come from a subdirectory by using
+something like:
logon script = scripts\%U.bat
-4) create the batch files to be run when the user logs in. If the batch
-file doesn't exist then no batch file will be run.
+5) create the batch files to be run when the user logs in. If the batch
+ file doesn't exist then no batch file will be run.
In the batch files you need to be careful to use DOS style cr/lf line
endings. If you don't then DOS may get confused. I suggest you use a
DOS editor to remotely edit the files if you don't know how to produce
DOS style files under unix.
-5) Use smbclient with the -U option for some users to make sure that
-the \\server\NETLOGON share is available, the batch files are visible
-and they are readable by the users.
-
-6) you will probabaly find that your clients automatically mount the
-\\SERVER\NETLOGON share as drive z: while logging in. You can put some
-useful programs there to execute from the batch files.
+6) Use smbclient with the -U option for some users to make sure that
+ the \\server\NETLOGON share is available, the batch files are
+ visible and they are readable by the users.
+7) you will probabaly find that your clients automatically mount the
+ \\SERVER\NETLOGON share as drive z: while logging in. You can put
+ some useful programs there to execute from the batch files.
NOTE: You must be using "security = user" or "security = server" for
-domain logons to work correctly. Share level security won't work
+domain logons to work correctly. Share level security won't work
correctly.
+
+Configuration Instructions: Setting up Roaming User Profiles
+================================================================
+
+In the [global] section of smb.conf set the following (for example):
+
+ logon path = \\profileserver\profileshare\profilepath\%U\moreprofilepath
+
+The default for this option is \\%N\%U\profile, namely
+\\sambaserver\username\profile. The \\N%\%U service is created
+automatically by the [homes] service.
+
+If you are using a samba server for the profiles, you _must_ make the
+share specified in the logon path browseable. Windows 95 appears to
+check that it can see the share and any subdirectories within that share
+specified by the logon path option, rather than just connecting straight
+away. It also attempts to create the components of the full path for
+you. If the creation of any component fails, or if it cannot see any
+component of the path, the profile creation / reading fails.
+
+[lkcl 26aug96 - we have discovered a problem where Windows clients can
+maintain a connection to the [homes] share in between logins. The
+[homes] share must NOT therefore be used in a profile path.]
+
+
+Windows 95
+----------
+
+When a user first logs in on Windows 95, the file user.DAT is created,
+as are folders "Start Menu", "Desktop", "Programs" and "Nethood".
+These directories and their contents will be merged with the local
+versions stored in c:\windows\profiles\username on subsequent logins,
+taking the most recent from each. You will need to use the [global]
+options "preserve case = yes", "short case preserve = yes" and
+"case sensitive = no" in order to maintain capital letters in shortcuts
+in any of the profile folders.
+
+The user.DAT file contains all the user's preferences. If you wish to
+enforce a set of preferences, rename their user.DAT file to user.MAN,
+and deny them write access to this file.
+
+2) On the Windows 95 machine, go to Control Panel | Passwords and
+ select the User Profiles tab. Select the required level of
+ roaming preferences. Press OK, but do _not_ allow the computer
+ to reboot.
+
+3) On the Windows 95 machine, go to Control Panel | Network |
+ Client for Microsoft Networks | Preferences. Select 'Log on to
+ NT Domain'. Then, ensure that the Primary Logon is 'Client for
+ Microsoft Networks'. Press OK, and this time allow the computer
+ to reboot.
+
+Under Windows 95, Profiles are downloaded from the Primary Logon.
+If you have the Primary Logon as 'Client for Novell Networks', then
+the profiles and logon script will be downloaded from your Novell
+Server. If you have the Primary Logon as 'Windows Logon', then the
+profiles will be loaded from the local machine - a bit against the
+concept of roaming profiles, if you ask me.
+
+You will now find that the Microsoft Networks Login box contains
+[user, password, domain] instead of just [user, password]. Type in
+the samba server's domain name (or any other domain known to exist,
+but bear in mind that the user will be authenticated against this
+domain and profiles downloaded from it, if that domain logon server
+supports it), user name and user's password.
+
+Once the user has been successfully validated, the Windows 95 machine
+will inform you that 'The user has not logged on before' and asks you
+if you wish to save the user's preferences? Select 'yes'.
+
+Once the Windows 95 client comes up with the desktop, you should be able
+to examine the contents of the directory specified in the "logon path"
+on the samba server and verify that the "Desktop", "Start Menu",
+"Programs" and "Nethood" folders have been created.
+
+These folders will be cached locally on the client, and updated when
+the user logs off (if you haven't made them read-only by then :-).
+You will find that if the user creates further folders or short-cuts,
+that the client will merge the profile contents downloaded with the
+contents of the profile directory already on the local client, taking
+the newest folders and short-cuts from each set.
+
+If you have made the folders / files read-only on the samba server,
+then you will get errors from the w95 machine on logon and logout, as
+it attempts to merge the local and the remote profile. Basically, if
+you have any errors reported by the w95 machine, check the unix file
+permissions and ownership rights on the profile directory contents,
+on the samba server.
+
+
+If you have problems creating user profiles, you can reset the user's
+local desktop cache, as shown below. When this user then next logs in,
+they will be told that they are logging in "for the first time".
+
+
+1) instead of logging in under the [user, password, domain] dialog],
+ press escape.
+
+2) run the regedit.exe program, and look in:
+
+ HKEY_LOCAL_MACHINE\Windows\CurrentVersion\ProfileList
+
+ you will find an entry, for each user, of ProfilePath. Note the
+ contents of this key (likely to be c:\windows\profiles\username),
+ then delete the key ProfilePath for the required user.
+
+ [Exit the registry editor].
+
+3) WARNING - before deleting the contents of the directory listed in
+ the ProfilePath (this is likely to be c:\windows\profiles\username),
+ ask them if they have any important files stored on their desktop
+ or in their start menu. delete the contents of the directory
+ ProfilePath (making a backup if any of the files are needed).
+
+ This will have the effect of removing the local (read-only hidden
+ system file) user.DAT in their profile directory, as well as the
+ local "desktop", "nethood", "start menu" and "programs" folders.
+
+4) search for the user's .PWL password-cacheing file in the c:\windows
+ directory, and delete it.
+
+5) log off the windows 95 client.
+
+6) check the contents of the profile path (see "logon path" described
+ above), and delete the user.DAT or user.MAN file for the user,
+ making a backup if required.
+
+
+If all else fails, increase samba's debug log levels to between 3 and 10,
+and / or run a packet trace program such as tcpdump or netmon.exe, and
+look for any error reports.
+
+If you have access to an NT server, then first set up roaming profiles
+and / or netlogons on the NT server. Make a packet trace, or examine
+the example packet traces provided with NT server, and see what the
+differences are with the equivalent samba trace.
+
+
+Windows NT Workstation 4.0
+--------------------------
+
+When a user first logs in to a Windows NT Workstation, the profile
+NTuser.DAT is created. The profile location can be now specified
+through the "logon path" parameter, in exactly the same way as it
+can for Win95. [lkcl 10aug97 - i tried setting the path to
+\\samba-server\homes\profile, and discovered that this fails because
+a background process maintains the connection to the [homes] share
+which does _not_ close down in between user logins. you have to
+have \\samba-server\%L\profile, where user is the username created
+from the [homes] share].
+
+There is a parameter that is now available for use with NT Profiles:
+"logon drive". This should be set to "h:" or any other drive, and
+should be used in conjunction with the new "logon home" parameter.
+
+The entry for the NT 4.0 profile is a _directory_ not a file. The NT
+help on profiles mentions that a directory is also created with a .PDS
+extension. The user, while logging in, must have write permission to
+create the full profile path (and the folder with the .PDS extension)
+[lkcl 10aug97 - i found that the creation of the .PDS directory failed,
+and had to create these manually for each user, with a shell script.
+also, i presume, but have not tested, that the full profile path must
+be browseable just as it is for w95, due to the manner in which they
+attempt to create the full profile path: test existence of each path
+component; create path component].
+
+In the profile directory, NT creates more folders than 95. It creates
+"Application Data" and others, as well as "Desktop", "Nethood",
+"Start Menu" and "Programs". The profile itself is stored in a file
+NTuser.DAT. Nothing appears to be stored in the .PDS directory, and
+its purpose is currently unknown.
+
+You can use the System Control Panel to copy a local profile onto
+a samba server (see NT Help on profiles: it is also capable of firing
+up the correct location in the System Control Panel for you). The
+NT Help file also mentions that renaming NTuser.DAT to NTuser.MAN
+turns a profile into a mandatory one.
+
+[lkcl 10aug97 - i notice that NT Workstation tells me that it is
+downloading a profile from a slow link. whether this is actually the
+case, or whether there is some configuration issue, as yet unknown,
+that makes NT Workstation _think_ that the link is a slow one is a
+matter to be resolved].
+
+[lkcl 20aug97 - after samba digest correspondance, one user found, and
+another confirmed, that profiles cannot be loaded from a samba server
+unless "security = user" and "encrypted passwords = yes" (see the file
+ENCRYPTION.txt) or "security = server" and "password server = ip.address.
+of.yourNTserver" are used. either of these options will allow the NT
+workstation to access the samba server using LAN manager encrypted
+passwords, without the user intervention normally required by NT
+workstation for clear-text passwords].
+
+[lkcl 25aug97 - more comments received about NT profiles: the case of
+the profile _matters_. the file _must_ be called NTuser.DAT or, for
+a mandatory profile, NTuser.MAN].
+
+
+Windows NT Server
+-----------------
+
+There is nothing to stop you specifying any path that you like for the
+location of users' profiles. Therefore, you could specify that the
+profile be stored on a samba server, or any other SMB server, as long as
+that SMB server supports encrypted passwords.
+
+
+
+Sharing Profiles between W95 and NT Workstation 4.0
+---------------------------------------------------
+
+The default logon path is \\%N\U%. NT Workstation will attempt to create
+a directory "\\samba-server\username.PDS" if you specify the logon path
+as "\\samba-server\username" with the NT User Manager. Therefore, you
+will need to specify (for example) "\\samba-server\username\profile".
+NT 4.0 will attempt to create "\\samba-server\username\profile.PDS", which
+is more likely to succeed.
+
+If you then want to share the same Start Menu / Desktop with W95, you will
+need to specify "logon path = \\samba-server\username\profile" [lkcl 10aug97
+this has its drawbacks: i created a shortcut to telnet.exe, which attempts
+to run from the c:\winnt\system32 directory. this directory is obviously
+unlikely to exist on a Win95-only host].
+
+If you have this set up correctly, you will find separate user.DAT and
+NTuser.DAT files in the same profile directory.
+
+[lkcl 25aug97 - there are some issues to resolve with downloading of
+NT profiles, probably to do with time/date stamps. i have found that
+NTuser.DAT is never updated on the workstation after the first time that
+it is copied to the local workstation profile directory. this is in
+contrast to w95, where it _does_ transfer / update profiles correctly].
+
diff --git a/docs/textdocs/DOMAIN_CONTROL.txt b/docs/textdocs/DOMAIN_CONTROL.txt
new file mode 100644
index 00000000000..da7a089b0af
--- /dev/null
+++ b/docs/textdocs/DOMAIN_CONTROL.txt
@@ -0,0 +1,108 @@
+!==
+!== DOMAIN_CONTROL.txt for Samba release 1.9.18alpha8 30 Oct 1997
+!==
+Initial Release: August 22, 1996
+Contributor: John H Terpstra <samba-bugs@samba.anu.edu.au>
+ Copyright (C) 1996-1997 - John H Terpstra
+Updated: August 25, 1997
+Status: Current - New Content
+
+Subject: Windows NT Domain Control & Samba
+============================================================================
+
+****NOTE:****
+=============
+The term "Domain Controller" and those related to it refer to one specific
+method of authentication that can underly an SMB domain. Domain Controllers
+prior to Windows NT Server 3.1 were sold by various companies and based on
+private extensions to the LAN Manager 2.1 protocol. Windows NT introduced
+Microsoft-specific ways of distributing the user authentication database.
+See DOMAIN.txt for examples of how Samba can participate in or create
+SMB domains based on shared authentication database schemes other than the
+Windows NT SAM.
+
+Microsoft Windows NT Domain Control is an extremely complex protocol.
+We have received countless requests to implement Domain Control in Samba.
+The 1.9.18 release of Samba contains experimental code to implement
+this. Please read the file docs/NTDOMAIN.txt for more information on this.
+============================================================================
+
+Windows NT Server can be installed as either a plain file and print server
+(WORKGROUP workstaion or server) or as a server that participates in Domain
+Control (DOMAIN member, Primary Domain controller or Backup Domain controller).
+
+The same is true for OS/2 Warp Server, Digital Pathworks and other similar
+products, all of which can participate in Domain Control along with Windows NT.
+However only those servers which have licenced Windows NT code in them can be
+a primary Domain Controller (eg Windows NT Server, Advanced Server for Unix.)
+
+To many people these terms can be confusing, so let's try to clear the air.
+
+Every Windows NT system (workstation or server) has a registry database.
+The registry contains entries that describe the initialisation information
+for all services (the equivalent of Unix Daemons) that run within the Windows
+NT environment. The registry also contains entries that tell application
+software where to find dynamically loadable libraries that they depend upon.
+In fact, the registry contains entries that describes everything that anything
+may need to know to interact with the rest of the system.
+
+The registry files can be located on any Windows NT machine by opening a
+command prompt and typing:
+ dir %SystemRoot%\System32\config
+
+The environment variable %SystemRoot% value can be obtained by typing:
+ echo %SystemRoot%
+
+The active parts of the registry that you may want to be familiar with are
+the files called: default, system, software, sam and security.
+
+In a domain environment, Microsoft Windows NT domain controllers participate
+in replication of the SAM and SECURITY files so that all controllers within
+the domain have an exactly identical copy of each.
+
+The Microsoft Windows NT system is structured within a security model that
+says that all applications and services must authenticate themselves before
+they can obtain permission from the security manager to do what they set out
+to do.
+
+The Windows NT User database also resides within the registry. This part of
+the registry contains the user's security identifier, home directory, group
+memberships, desktop profile, and so on.
+
+Every Windows NT system (workstation as well as server) will have its own
+registry. Windows NT Servers that participate in Domain Security control
+have a database that they share in common - thus they do NOT own an
+independent full registry database of their own, as do Workstations and
+plain Servers.
+
+The User database is called the SAM (Security Access Manager) database and
+is used for all user authentication as well as for authentication of inter-
+process authentication (ie: to ensure that the service action a user has
+requested is permitted within the limits of that user's privileges).
+
+The Samba team have produced a utility that can dump the Windows NT SAM into
+smbpasswd format: see ENCRYPTION.txt for information on smbpasswd and
+/pub/samba/pwdump on your nearest Samba mirror for the utility. This
+facility is useful but cannot be easily used to implement SAM replication
+to Samba systems.
+
+Windows for Workgroups, Windows 95, and Windows NT Workstations and Servers
+can participate in a Domain security system that is controlled by Windows NT
+servers that have been correctly configured. At most every domain will have
+ONE Primary Domain Controller (PDC). It is desirable that each domain will
+have at least one Backup Domain Controller (BDC).
+
+The PDC and BDCs then participate in replication of the SAM database so that
+each Domain Controlling participant will have an up to date SAM component
+within its registry.
+
+Samba can NOT at this time function as a Domain Controller for any of these
+security services, but like all other domain members can interact with the
+Windows NT security system for all access authentication.
+
+When Samba is configured with the 'security = server' option and the
+'password server = Your_Windows_NT_Server_Name' option, then it will
+redirect all access authentication to that server. This way you can
+use Windows NT to act as your password server with full support for
+Microsoft encrypted passwords.
+
diff --git a/docs/textdocs/ENCRYPTION.txt b/docs/textdocs/ENCRYPTION.txt
index 046b473e9a1..c37b82bd502 100644
--- a/docs/textdocs/ENCRYPTION.txt
+++ b/docs/textdocs/ENCRYPTION.txt
@@ -1,9 +1,16 @@
- LanManager / Samba Password Encryption.
- ---------------------------------------
+!==
+!== ENCRYPTION.txt for Samba release 1.9.18alpha8 30 Oct 1997
+!==
+Contributor: Jeremy Allison <samba-bugs@samba.anu.edu.au>
+Updated: June 27, 1997
+Note: Please refer to WinNT.txt also
-With the development of LanManager compatible password encryption for
-Samba, it is now able to validate user connections in exactly the same
-way as a LanManager or Windows NT server.
+Subject: LanManager / Samba Password Encryption.
+============================================================================
+
+With the development of LanManager and Windows NT compatible password
+encryption for Samba, it is now able to validate user connections in
+exactly the same way as a LanManager or Windows NT server.
This document describes how the SMB password encryption algorithm
works and what issues there are in choosing whether you want to use
@@ -13,7 +20,7 @@ and the "PROS and CONS" section.
How does it work ?
------------------
- LanManager encryption is somewhat similar to UNIX password
+LanManager encryption is somewhat similar to UNIX password
encryption. The server uses a file containing a hashed value of a
users password. This is created by taking the users paintext
password, capitalising it, and either truncating to 14 bytes (or
@@ -22,6 +29,10 @@ two 56 bit DES keys to encrypt a 'magic' eight byte value, forming a
16 byte value which is stored by the server and client. Let this value
be known as the *hashed password*.
+Windows NT encryption is a higher quality mechanism, consisting
+of doing an MD4 hash on a Unicode version of the users password. This
+also produces a 16 byte hash value that is non-reversible.
+
When a client (LanManager, Windows for WorkGroups, Windows 95 or
Windows NT) wishes to mount a Samba drive (or use a Samba resource) it
first requests a connection and negotiates the protocol that the client
@@ -31,7 +42,7 @@ Samba server after the reply is sent and is known as the *challenge*.
The challenge is different for every client connection.
-The client then uses the hashed password (16 byte value described
+The client then uses the hashed password (16 byte values described
above), appended with 5 null bytes, as three 56 bit DES keys, each of
which is used to encrypt the challenge 8 byte value, forming a 24 byte
value known as the *response*.
@@ -39,6 +50,9 @@ value known as the *response*.
In the SMB call SMBsessionsetupX (when user level security is
selected) or the call SMBtconX (when share level security is selected)
the 24 byte response is returned by the client to the Samba server.
+For Windows NT protocol levels the above calculation is done on
+both hashes of the users password and both responses are returned
+in the SMB call, giving two 24 byte values.
The Samba server then reproduces the above calculation, using it's own
stored value of the 16 byte hashed password (read from the smbpasswd
@@ -52,8 +66,8 @@ is this allowed access. If not then the client did not know the
correct password and is denied access.
Note that the Samba server never knows or stores the cleartext of the
-users password - just the 16 byte hashed function derived from it. Also
-note that the cleartext password or 16 byte hashed value are never
+users password - just the 16 byte hashed values derived from it. Also
+note that the cleartext password or 16 byte hashed values are never
transmitted over the network - thus increasing security.
IMPORTANT NOTE ABOUT SECURITY
@@ -63,10 +77,10 @@ The unix and SMB password encryption techniques seem similar on the
surface. This similarity is, however, only skin deep. The unix scheme
typically sends clear text passwords over the nextwork when logging
in. This is bad. The SMB encryption scheme never sends the cleartext
-password over the network but it does store the 16 byte hashed value
-on disk. This is also bad. Why? Because the 16 byte hashed value is a
-"password equivalent". You cannot derive the users password from it,
-but it could potentially be used in a modified client to gain access
+password over the network but it does store the 16 byte hashed values
+on disk. This is also bad. Why? Because the 16 byte hashed values are a
+"password equivalent". You cannot derive the users password from them,
+but they could potentially be used in a modified client to gain access
to a server. This would require considerable technical knowledge on
behalf of the attacker but is perfectly possible. You should thus
treat the smbpasswd file as though it contained the cleartext
@@ -108,17 +122,18 @@ ftp
ftp) which send plain text passwords over the net, so not sending them
for SMB isn't such a big deal.
-- the SMB encryption code in Samba is new and has only had limited
-testing. We have tried hard to make it secure but in any new
-implementation of a password scheme there is the possability of an
-error.
-
+Note that Windows NT 4.0 Service pack 3 changed the default for
+permissible authentication so that plaintext passwords are *never*
+sent over the wire. The solution to this is either to switch to
+encrypted passwords with Samba or edit the Windows NT registry to
+re-enable plaintext passwords. See the document WinNT.txt for
+details on how to do this.
The smbpasswd file.
-------------------
- In order for Samba to participate in the above protocol it must
-be able to look up the 16 byte hashed value given a user name.
+In order for Samba to participate in the above protocol it must
+be able to look up the 16 byte hashed values given a user name.
Unfortunately, as the UNIX password value is also a one way hash
function (ie. it is impossible to retrieve the cleartext of the users
password given the UNIX hash of it) then a separate password file
@@ -162,14 +177,16 @@ chmod 600 smbpasswd.
The format of the smbpasswd file is
-username:uid:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:Long name:user home dir:user shell
+username:uid:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:Long name:user home dir:user shell
Although only the username, uid, and XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
sections are significant and are looked at in the Samba code.
It is *VITALLY* important that there by 32 'X' characters between the
-two ':' characters - the smbpasswd and Samba code will fail to validate
-any entries that do not have 32 characters between ':' characters.
+two ':' characters in the XXX sections - the smbpasswd and Samba code
+will fail to validate any entries that do not have 32 characters
+between ':' characters. The first XXX section is for the Lanman password
+hash, the second is for the Windows NT version.
When the password file is created all users have password entries
consisting of 32 'X' characters. By default this disallows any access
@@ -185,7 +202,7 @@ NO PASSWORD
Eg. To clear the password for user bob, his smbpasswd file entry would
look like :
-bob:100:NO PASSWORDXXXXXXXXXXXXXXXXXXXXX:Bob's full name:/bobhome:/bobshell
+bob:100:NO PASSWORDXXXXXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:Bob's full name:/bobhome:/bobshell
If you are allowing users to use the smbpasswd command to set their own
passwords, you may want to give users NO PASSWORD initially so they do
@@ -200,7 +217,7 @@ normal unix /etc/passwd file.
The smbpasswd Command.
----------------------
- The smbpasswd command maintains the 32 byte password field in
+The smbpasswd command maintains the two 32 byte password fields in
the smbpasswd file. If you wish to make it similar to the unix passwd
or yppasswd programs, install it in /usr/local/samba/bin (or your main
Samba binary directory) and make it setuid root.
@@ -246,7 +263,7 @@ secure by reporting all problems to me (the author, Jeremy Allison).
My email address is :-
-jra@vantive.com
+jallison@whistle.com
Setting up Samba to support LanManager Encryption.
--------------------------------------------------
@@ -255,27 +272,15 @@ This is a very brief description on how to setup samba to support
password encryption. More complete instructions will probably be added
later.
-1) get and compile the libdes libraries. the source is available from
-nimbus.anu.edu.au in pub/tridge/libdes/libdes.tar.92-10-13.gz
-
-2) enable the encryption stuff in the Samba makefile, making sure you
-point it to the libdes library and include file (it needs des.h)
-The entries you need to uncomment are the four lines after the comment :-
-
-# This is for SMB encrypted (lanman) passwords.
-
-Note that you may have to change the variable DES_BASE to
-point at the place where you installed the DES library.
+1) compile and install samba as usual
-3) compile and install samba as usual
-
-4) f your system can't compile the module getsmbpass.c then remove the
+2) if your system can't compile the module getsmbpass.c then remove the
-DSMBGETPASS define from the Makefile.
-5) enable encrypted passwords in smb.conf by adding the line
+3) enable encrypted passwords in smb.conf by adding the line
"encrypt passwords = yes" in the [global] section
-6) create the initial smbpasswd password file in the place you
+4) create the initial smbpasswd password file in the place you
specified in the Makefile. A simple way to do this based on your
existing Makefile (assuming it is in a reasonably standard format) is
like this:
@@ -300,7 +305,7 @@ If this fails then you will find that you will need entries that look
like this:
# SMB password file.
-tridge:148:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:Andrew Tridgell:/home/tridge:/bin/tcsh
+tridge:148:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:Andrew Tridgell:/home/tridge:/bin/tcsh
note that the uid and username fields must be right. Also, you must get
the number of X's right (there should be 32).
@@ -310,24 +315,13 @@ If you wish, install the smbpasswd program as suid root.
chown root /usr/local/samba/bin/smbpasswd
chmod 4555 /usr/local/samba/bin/smbpasswd
-7) set the passwords for users using the smbpasswd command. For
+5) set the passwords for users using the smbpasswd command. For
example, as root you could do "smbpasswd tridge"
-8) try it out!
+6) try it out!
Note that you can test things using smbclient, as it also now supports
encryption.
-NOTE TO USA Sites that Mirror Samba
------------------------------------
-
-The DES library is considered a munition in the USA. Under US Law it is
-illegal to export this software, or to put it in a freely available ftp
-site.
-
-Please do not mirror the DES directory from the site on nimbus.anu.edu.au
-
-Thank you,
-
-Jeremy Allison.
-
+==============================================================================
+Footnote: Please refer to WinNT.txt also
diff --git a/docs/textdocs/Faxing.txt b/docs/textdocs/Faxing.txt
new file mode 100644
index 00000000000..ef330d58cc2
--- /dev/null
+++ b/docs/textdocs/Faxing.txt
@@ -0,0 +1,223 @@
+!==
+!== Faxing.txt for Samba release 1.9.18alpha8 30 Oct 1997
+!==
+Contributor: Gerhard Zuber <zuber@berlin.snafu.de>
+Date: August 5th 1997.
+Status: Current
+
+Subject: F A X I N G with S A M B A
+==========================================================================
+
+This text describes how to turn your SAMBA-server into a fax-server
+for any environment, especially for Windows.
+ Author: Gerhard Zuber <zuber@berlin.snafu.de>
+ Version: 1.4
+ Date: 04. Aug. 1997
+
+Requirements:
+ UNIX box (Linux preferred) with SAMBA and a faxmodem
+ ghostscript package
+ mgetty+sendfax package
+ pbm package (portable bitmap tools)
+
+FTP sites:
+ sunsite.unc.edu:/pub/Linux/system/Serial/mgetty+sendfax*
+ tsx-11.mit.edu:/pub/linux/sources/sbin/mgetty+sendfax
+ ftp.leo.org:/pub/comp/networking/communication/modem/mgetty/mgetty1.1.6-May05.tar.gz
+
+ pbm10dec91.tgz
+ ftp.leo.org:/pub/comp/networking/communication/modem/mgetty/pbm10dec91.tgz
+ sunsite.unc.edu: ..../apps/graphics/convert/pbmplus-10dec91-bin.tar.gz
+ ftp.gwdg.de/pub/linux/grafik/pbmplus.src.tar.Z (this is 10dec91 source)
+ or ??? pbm10dec91.tgz pbmplus10dec91.tgz
+
+
+making mgetty+sendfax running:
+==============================
+
+ go to source tree: /usr/src/mgetty+sendfax
+ cp policy.h-dist policy.h
+
+ change your settings: valid tty ports, modem initstring, Station-Id
+
+#define MODEM_INIT_STRING "AT &F S0=0 &D3 &K3 &C1\\\\N2"
+
+#define FAX_STATION_ID "49 30 12345678"
+
+#define FAX_MODEM_TTYS "ttyS1:ttyS2:ttyS3"
+
+ Modem initstring is for rockwell based modems
+ if you want to use mgetty+sendfax as PPP-dialin-server,
+ define AUTO_PPP in Makefile:
+
+CFLAGS=-O2 -Wall -pipe -DAUTO_PPP
+
+ compile it and install the package.
+ edit your /etc/inittab and let mgetty running on your preferred
+ ports:
+
+s3:45:respawn:/usr/local/sbin/mgetty ttyS2 vt100
+
+ now issue a
+ kill -HUP 1
+ and enjoy with the lightning LEDs on your modem
+ your now are ready to receive faxes !
+
+
+ if you want a PPP dialin-server, edit
+ /usr/local/etc/mgetty+sendfax/login.config
+
+/AutoPPP/ - ppp /usr/sbin/pppd auth debug passive modem
+
+
+ Note: this package automatically decides between a fax call and
+ a modem call. In case of modem call you get a login prompt !
+
+Tools for printing faxes:
+=========================
+
+ your incomed faxes are in:
+ /var/spool/fax/incoming
+
+ print it with:
+
+ for i in *
+ do
+ g3cat $i | g3tolj | lpr -P hp
+ done
+
+ in case of low resolution use instead:
+
+ g3cat $i | g3tolj -aspect 2 | lpr -P hp
+
+
+ g3cat is in the tools-section, g3tolj is in the contrib-section
+ for printing to HP lasers.
+
+ If you want to produce files for displaying and printing with Windows, use
+ some tools from the pbm-package like follow
+
+ g3cat $i | g3topbm - | ppmtopcx - >$i.pcx
+
+ and view it with your favourite Windows tool (maybe paintbrush)
+
+
+Now making the fax-server:
+===========================
+
+ fetch the file
+ mgetty+sendfax/frontends/winword/faxfilter
+
+ and place it in
+
+ /usr/local/etc/mgetty+sendfax/
+
+ prepare your faxspool file as mentioned in this file
+ edit fax/faxspool.in and reinstall or change the final
+ /usr/local/bin/faxspool too.
+
+ if [ "$user" = "root" -o "$user" = "fax" -o \
+ "$user" = "lp" -o "$user" = "daemon" -o "$user" = "bin" ]
+
+ find the first line and change the second.
+
+ make sure you have pbmtext (from the pbm-package). This is
+ needed for creating the small header line on each page.
+ Notes on pbmplus:
+ Some peoples had problems with precompiled binaries (especially
+ at linux) with a shared lib libgr.so.x.x. The better way is
+ to fetch the source and compile it. One needs only pbmtext for
+ generating the small line on top of each page /faxheader). Install
+ only the individual programs you need. If you install the full
+ package then install pbmplus first and then mgetty+sendfax, because
+ this package has some changed programs by itself (but not pbmtext).
+
+ make sure your ghostscript is functional. You need fonts !
+ I prefer these from the OS/2 disks
+
+ prepare your faxheader
+ /usr/local/etc/mgetty+sendfax/faxheader
+
+ edit your /etc/printcap file:
+
+# FAX
+lp3|fax:\
+ :lp=/dev/null:\
+ :sd=/usr/spool/lp3:\
+ :if=/usr/local/etc/mgetty+sendfax/faxfilter:sh:sf:mx#0:\
+ :lf=/usr/spool/lp3/fax-log:
+
+
+
+
+ edit your /usr/local/samba/lib/smb.conf
+
+ so you have a smb based printer named "fax"
+
+
+The final step:
+===============
+
+ Now you have a printer called "fax" which can be used via
+ TCP/IP-printing (lpd-system) or via SAMBA (windows printing).
+
+ On every system you are able to produce postscript-files you
+ are ready to fax.
+
+ On Windows 3.1 95 and NT:
+
+ Install a printer wich produces postscript output,
+ e.g. apple laserwriter
+
+ connect the "fax" to your printer
+
+
+ Now write your first fax. Use your favourite wordprocessor,
+ write, winword, notepad or whatever you want, and start
+ with the headerpage.
+
+ Usually each fax has a header page. It carries your name,
+ your address, your phone/fax-number.
+
+ It carries also the recipient, his address and his *** fax
+ number ***. Now here is the trick:
+
+ Use the text:
+ Fax-Nr: 123456789
+ as the recipients fax-number. Make sure this text does not
+ occur in regular text ! Make sure this text is not broken
+ by formatting information, e.g. format it as a single entity.
+ (Windows Write and Win95 Wordpad are functional, maybe newer
+ versions of Winword are breaking formatting information).
+
+ The trick is that postscript output is human readable and
+ the faxfilter program scans the text for this pattern and
+ uses the found number as the fax-destination-number.
+
+ Now print your fax through the fax-printer and it will be
+ queued for later transmission. Use faxrunq for sending the
+ queue out.
+
+ Notes of SAMBA smb.conf:
+ Simply use fall through from the samba printer to the unix
+ printer. Sample:
+
+
+ printcap name = /etc/printcap
+ print command = /usr/bin/lpr -r -P %p %s
+ lpq command = /usr/bin/lpq -P %p
+ lprm command = /usr/bin/lprm -P %p %j
+
+
+[fax]
+ comment = FAX (mgetty+sendfax)
+ path = /tmp
+ printable = yes
+ public = yes
+ writable = no
+ create mode = 0700
+ browseable = yes
+ guest ok = no
+
+
+
diff --git a/docs/textdocs/GOTCHAS.txt b/docs/textdocs/GOTCHAS.txt
new file mode 100644
index 00000000000..b123250e5a2
--- /dev/null
+++ b/docs/textdocs/GOTCHAS.txt
@@ -0,0 +1,71 @@
+!==
+!== GOTCHAS.txt for Samba release 1.9.18alpha8 30 Oct 1997
+!==
+This file lists Gotchas to watch out for:
+=========================================================================
+Item Number: 1.0
+Description: Problem Detecting Interfaces
+Symptom: Workstations do NOT see Samba server in Browse List
+OS: RedHat - Rembrandt Beta 2
+Platform: Intel
+Date: August 16, 1996
+Submitted By: John H Terpstra
+Details:
+ By default RedHat Rembrandt-II during installation adds an
+ entry to /etc/hosts as follows:-
+ 127.0.0.1 loopback "hostname"."domainname"
+
+ This causes Samba to loop back onto the loopback interface.
+ The result is that Samba fails to communicate correctly with
+ the world and therefor may fail to correctly negotiate who
+ is the master browse list holder and who is the master browser.
+
+Corrective Action: Delete the entry after the word loopback
+ in the line starting 127.0.0.1
+=========================================================================
+Item Number: 2.0
+Description: Problems with MS Windows NT Server network logon service
+Symptom: Loss of Domain Logon Services and failed Windows NT / 95
+ logon attempts.
+OS: All Unix systems with Windows NT Domain Control environments.
+Platform: All
+Date: February 1, 1997
+Submitted By: John H Terpstra
+Details:
+ Samba is configured for Domain logon control in a network
+ where a Windows NT Domain Primary Controller is running.
+
+ Case 1:
+ The Windows NT Server is shut down, then restarted. Then
+ the Samba server is reconfigured so that it NO LONGER offers
+ Domain logon services. Windows NT and 95 workstations can no
+ longer log onto the domain. Ouch!!!
+
+ Case 2:
+ The Windows NT Server which is running the Network logon
+ Service is shut down and restarted while Samba is a domain
+ controller offering the Domain LogOn service. Windows NT
+ Workstation and Server can no longer log onto the network.
+
+ Cause:
+ Windows NT checks at start up to see if any domain logon
+ controllers are already running within the domain. It finds
+ Samba claiming to offer the service and therefore does NOT
+ start its Network Logon Service.
+
+ Windows NT needs the Windows NT network logon service to gain
+ from its Domain controller's SAM database the security
+ identifier for the user loging on.
+
+Work-around: Stop the Samba nmbd and smbd processes, then on the Windows
+ NT Primary Domain Controller start the Network Logon Service.
+ Now restart the Samba nmbd and smbd services.
+
+ Better still: DO NOT CONFIGURE SAMBA AS THE NETWORK LOGON
+ SERVER, DO NOT SET SAMBA TO BE THE DOMAIN MASTER, DO NOT
+ SET SAMBA TO OS LEVEL GREATER THAN 0.
+
+ ie: Let Windows NT Server be the Domain Logon server, the
+ domain master browser and do NOT interfere with any aspect
+ of Microsoft Windows NT Domain Control.
+=========================================================================
diff --git a/docs/textdocs/HINTS.txt b/docs/textdocs/HINTS.txt
index 953650bdd3e..da44572c30b 100644
--- a/docs/textdocs/HINTS.txt
+++ b/docs/textdocs/HINTS.txt
@@ -1,3 +1,13 @@
+!==
+!== HINTS.txt for Samba release 1.9.18alpha8 30 Oct 1997
+!==
+Contributor: Many
+Updated: Not for a long time!
+
+Subject: A collection of hints
+Status: May be useful information but NOT current
+===============================================================================
+
Here are some random hints that you may find useful. These really
should be incorporated in the main docs someday.
@@ -40,7 +50,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/INSTALL.sambatar b/docs/textdocs/INSTALL.sambatar
index 388e2a3eb6f..413f54d3c65 100644
--- a/docs/textdocs/INSTALL.sambatar
+++ b/docs/textdocs/INSTALL.sambatar
@@ -1,3 +1,9 @@
+Contributor: Ricky Poulten <poultenr@logica.co.uk>
+Date: Unknown
+Status: Current
+
+Subject: Using smbtar
+=============================================================================
Please see the readme and the man page for general info.
diff --git a/docs/textdocs/MIRRORS.txt b/docs/textdocs/MIRRORS.txt
new file mode 100755
index 00000000000..331a2ce18b3
--- /dev/null
+++ b/docs/textdocs/MIRRORS.txt
@@ -0,0 +1,84 @@
+!==
+!== MIRRORS.txt for Samba release 1.9.18alpha8 30 Oct 1997
+!==
+The main Samba ftp site is samba.anu.edu.au in pub/samba/. Contact
+samba-bugs@samba.anu.edu.au for help with this site.
+
+The 'Source Only' sites may also contain binary packages as we are now
+including them on samba.anu.edu.au/pub/samba/Binary_Packages
+
+Mirror sites include:
+
+--- Austria ---
+ ftp://gd.tuwien.ac.at/pub/infosys/servers/samba/sources/
+--- Australia ---
+ ftp://samba.anu.edu.au/pub/samba/
+ ftp://choc.satech.net.au/pub/samba/
+--- USA Educational ---
+ ftp://sunsite.unc.edu/pub/packages/samba/sources/
+ ftp://ftp.micro.caltech.edu/pub/samba/
+ ftp://ftp.cs.ucr.edu/pub/software/samba/
+--- Czech Republic ---
+ ftp://sunsite.mff.cuni.cz/Net/Protocols/Samba/
+--- Denmark ---
+ ftp://sunsite.auc.dk/pub/unix/networking/samba/
+--- Finland ---
+ ftp://nic.funet.fi/pub/mirrors/samba.anu.edu.au/
+--- Germany ---
+ ftp://ftp.uni-trier.de/pub/unix/network/samba/
+--- Greece ---
+ ftp://ftp.ntua.gr/pub/net/samba/
+--- Italy ---
+ ftp://volftp.tin.it/mirror/samba/pub/samba/
+ http://www.inferentia.it/archives/samba/ (no binaries)
+--- Japan ---
+ ftp://ring.asahi-net.or.jp/archives/net/samba/
+ ftp://ring.aist.go.jp/archives/net/samba/
+ ftp://ftp.win.or.jp/pub/network/samba/
+--- Korea (South) ---
+ ftp://CAIR-archive.kaist.ac.kr/pub/samba/
+--- Network ---
+ ftp://ftp.gbnet.net/pub/samba/
+ ftp://ftp.ntrl.net/pub/mirror/samba/
+ ftp://despair.capecod.net/pub/Samba/
+--- Poland ---
+ ftp://giswitch.sggw.waw.pl/pub/unix/samba/
+--- Potugal ---
+ ftp://ftp.ua.pt/pub/misc/samba/
+--- Romania ---
+ ftp://ftp.romus.ro/pub/Linux/Network/samba/
+--- Russian Federation ---
+ ftp://ftp.uic.nsu.ru/pub/vendors/samba/
+--- United Kingdom ---
+ ftp://sunsite.doc.ic.ac.uk/packages/samba/
+ ftp://ftp.demon.co.uk/pub/mirrors/samba/
+
+SCO binaries available from:
+ http://www.math.u-szeged.hu/hardsoft/hsdetail.htm
+
+AIX and DEC OSF/1 binaries are available from:
+ ftp://www.inferentia.it/archives/samba (built by davide.migliavacca@inferentia.it)
+
+QNX binaries and source code:
+ ftp://quics.qnx.com/usr/free/staging/samba
+
+Amiga OS binaries and source:
+ http://www.gbar.dtu.dk/~c948374/Amiga/Samba
+
+Stratos VOS binaries and source:
+ ftp://ftp.stratus.com/pub/vos/tools
+
+OS/2 binaries and source:
+ http://carol.wins.uva.nl/~leeuw/samba/samba2.html
+
+IBM OS/390 MVS:
+ ftp://ftp.mks.com/pub/samba
+
+
+There are several others. Give archie a try.
+
+Http sites include:
+===================
+http://samba.anu.edu.au/samba
+
+Japanese - http://samba.bento.ad.jp/
diff --git a/docs/textdocs/NTDOMAIN.txt b/docs/textdocs/NTDOMAIN.txt
new file mode 100644
index 00000000000..e466ca9a629
--- /dev/null
+++ b/docs/textdocs/NTDOMAIN.txt
@@ -0,0 +1,133 @@
+!==
+!== NTDOMAIN.txt for Samba release 1.9.18alpha8 30 Oct 1997
+!==
+Contributor: Luke Kenneth Casson Leighton (samba-bugs@samba.anu.edu.au)
+ Copyright (C) 1997 Luke Kenneth Casson Leighton
+Created: October 20, 1997
+Updated: October 20, 1997
+
+Subject: NT Domain Logons
+===========================================================================
+
+As of 1.9.18alpha1, Samba supports logins for NT 3.51 and 4.0 Workstations,
+without the need, use or intervention of NT Server. This document describes
+how to set this up. Over the continued development of the 1.9.18alpha
+series, this process (and therefore this document) should become simpler.
+
+The support is still experimental, so should be used at your own risk.
+
+NT is not as robust as you might have been led to believe: during the
+development of the Domain Logon Support, one person reported having to
+reinstall NT from scratch: their workstation had become totally unuseable.
+
+This *has* been reported to the NTBUGTRAQ@LISTSERV.NTBUGTRAQ.COM digest.
+
+
+Domain Logons using 1.9.18alpha1
+================================
+
+1) compile samba with -DNTDOMAIN
+
+2) carry out the following unix commands:
+
+ touch /tmp/netlogon
+ touch /tmp/srvsvc
+ touch /tmp/lsarpc
+ chmod 666 /tmp/netlogon
+ chmod 666 /tmp/srvsvc
+ chmod 666 /tmp/lsarpc
+
+3) set up samba with encrypted passwords: see ENCRYPTION.txt (probably out
+ of date: you no longer need the DES libraries, but other than that,
+ ENCRYPTION.txt is current).
+
+4) for each workstation, add a line to smbpasswd with a username of MACHINE$
+ and a password of "machine". this process will be automated in further
+ releases.
+
+5) if using NT server to log in, run the User Manager for Domains, and
+ add the capability to "Log in Locally" to the policies.
+
+6) set up the following parameters in smb.conf
+
+; substitute your workgroup here
+ workgroup = SAMBA
+
+; a description of domain sids can be found elsewhere.
+ domain sid = S-1-5-21-123-456-789-123
+
+; tells workstations to use SAMBA as its Primary Domain Controller.
+ domain logons = yes
+
+7) make sure samba is running before the next step is carried out. if
+ this is your first time, just for fun you might like to switch the
+ debug log level to about 10. the NT pipes produces some very pretty
+ output when decoding requests and generating responses, which would
+ be particularly useful to see in tcpdump at some point.
+
+8) In the NT Network Settings, change the domain to SAMBA. Do
+ not attempt to create an account using the other part of the dialog:
+ it will fail at present.
+
+ You should get a wonderful message saying "Welcome to the SAMBA Domain."
+
+ If you don't, then please first increase your debug log levels and also
+ get a tcpdump (or preferably NetMonitor) trace and examine it carefully.
+ You should see a NETLOGON, a SAMLOGON on UDP port 138. If you don't,
+ then you probably don't have "domain logons = yes" or there is some other
+ problem in resolving the NetBIOS name SAMBA<1c>.
+
+ On port 139, you should see a LSA_OPEN_POLICY, two LSA_QUERY_INFOs (one
+ for a domain SID of S-1-3... and another for S-1-5) and then an LSA_CLOSE
+ or two. If when you get a connection to the SMB pipe NETLOGON, if /netlogon
+ access is refused, then you probably haven't granted the correct access
+ permissions on the /tmp/netlogon file. Likewise for the srvsvc file.
+
+ You may see a pipe connection to a wksta service being refused: this
+ is acceptable, we have found. You may also see a "Net Server Get Info"
+ being issued on the srvsvc pipe.
+
+ Assuming you got the Welcome message, go through the obligatory reboot...
+
+9) When pressing Ctrl-Alt-Delete, the NT login box should have three entries.
+ If there is a delay of about twenty seconds between pressing Ctrl-Alt-Delete
+ and the appearance of this login dialog, then there might be a problem:
+ at this stage the workstation is issuing an LSA_ENUMTRUSTEDDOMAIN request
+
+ The domain box should have two entries: the hostname and the SAMBA domain.
+ Any local accounts are under the hostname domain, from which you will be
+ able to shut down the machine etc. At present, we do not specify that
+ the NT user logging in is a member of any groups, so will have no
+ priveleges, including the ability to shut down the machine.
+
+ Select the SAMBA domain, and type in a valid username and password for
+ which there is a valid entry in the samba server's smbpasswd LM/NT OWF
+ database.
+
+ You should see an LSA_REQ_CHAL, followed by LSA_AUTH2, LSA_NET_SRV_PWSET,
+ and LSA_SAM_LOGON. The SAM Logon will be particularly large (the response
+ can be approximately 600 bytes) as it contains user info.
+
+ Also, there will probably be a "Net Server Get Info" and a "Net Share Enum"
+ amongst this lot. If the SAM Logon is successful, the dialog should
+ disappear, and a standard SMB connection established to download the
+ profile specified in the SAM Logon (if it was).
+
+ At this point, you _may_ encounter difficulties in creating a remote
+ profile, and the login may terminate (generating an LSA_SAM_LOGOFF). If
+ this occurs, then either find an existing profile on the samba server and
+ copy it into the location specified by the "logon path" smb.conf parameter
+ for the user logging in, or log in on the local machine, and use the
+ System | Profiles control panel to make a copy of the _local_ profile onto
+ the samba server.
+
+10) Play around. Look at the Samba Server: see if it can be found in the
+ browse lists. Check that it is accessible; run some applications.
+ Generally stress things. Laugh a lot. Logout of the NT machine
+ (generating an LSA_SAM_LOGOFF) and log back in again. Try logging in
+ two users simultaneously. Try logging the same user in twice.
+ Make Samba fall over, and then send bug reports to us, with NTDOM: at
+ the start of the subject line, as "samba-bugs@samba.anu.edu.au".
+
+Your reports, testing, patches and criticism will help us get this right.
+
diff --git a/docs/textdocs/NetBIOS.txt b/docs/textdocs/NetBIOS.txt
new file mode 100644
index 00000000000..5829a2df031
--- /dev/null
+++ b/docs/textdocs/NetBIOS.txt
@@ -0,0 +1,155 @@
+!==
+!== NetBIOS.txt for Samba release 1.9.18alpha8 30 Oct 1997
+!==
+Contributor: lkcl - samba-bugs@arvidsjaur.anu.edu.au
+ Copyright 1997 Luke Kenneth Casson Leighton
+Date: March 1997
+Status: Current
+Updated: 12jun97
+
+Subject: Definition of NetBIOS Protocol and Name Resolution Modes
+=============================================================================
+
+=======
+NETBIOS
+=======
+
+NetBIOS runs over the following tranports: TCP/IP; NetBEUI and IPX/SPX.
+Samba only uses NetBIOS over TCP/IP. For details on the TCP/IP NetBIOS
+Session Service NetBIOS Datagram Service, and NetBIOS Names, see
+rfc1001.txt and rfc1002.txt.
+
+NetBEUI is a raw NetBIOS frame protocol implementation that allows NetBIOS
+datagrams to be sent out over the 'wire' embedded within LLC frames.
+NetBEUI is not required when using NetBIOS over TCP/IP protocols and it
+is preferable NOT to install NetBEUI if it can be avoided.
+
+IPX/SPX is also not required when using NetBIOS over TCP/IP, and it is
+preferable NOT to install the IPX/SPX transport unless you are using Novell
+servers. At the very least, it is recommended that you do not install
+'NetBIOS over IPX/SPX'.
+
+[When installing Windows 95, you will find that NetBEUI and IPX/SPX are
+installed as the default protocols. This is because they are the simplest
+to manage: no Windows 95 user-configuration is required].
+
+
+NetBIOS applications (such as samba) offer their services (for example,
+SMB file and print sharing) on a NetBIOS name. They must claim this name
+on the network before doing so. The NetBIOS session service will then
+accept connections on the application's behalf (on the NetBIOS name
+claimed by the application). A NetBIOS session between the application
+and the client can then commence.
+
+NetBIOS names consist of 15 characters plus a 'type' character. This is
+similar, in concept, to an IP address and a TCP port number, respectively.
+A NetBIOS-aware application on a host will offer different services under
+different NetBIOS name types, just as a host will offer different TCP/IP
+services on different port numbers.
+
+NetBIOS names must be claimed on a network, and must be defended. The use
+of NetBIOS names is most suitable on a single subnet; a Local Area Network
+or a Wide Area Network.
+
+NetBIOS names are either UNIQUE or GROUP. Only one application can claim a
+UNIQUE NetBIOS name on a network.
+
+There are two kinds of NetBIOS Name resolution: Broadcast and Point-to-Point.
+
+
+=================
+BROADCAST NetBIOS
+=================
+
+Clients can claim names, and therefore offer services on successfully claimed
+names, on their broadcast-isolated subnet. One way to get NetBIOS services
+(such as browsing: see ftp.microsoft.com/drg/developr/CIFS/browdiff.txt; and
+SMB file/print sharing: see cifs4.txt) working on a LAN or WAN is to make
+your routers forward all broadcast packets from TCP/IP ports 137, 138 and 139.
+
+This, however, is not recommended. If you have a large LAN or WAN, you will
+find that some of your hosts spend 95 percent of their time dealing with
+broadcast traffic. [If you have IPX/SPX on your LAN or WAN, you will find
+that this is already happening: a packet analyzer will show, roughly
+every twelve minutes, great swathes of broadcast traffic!].
+
+
+============
+NBNS NetBIOS
+============
+
+rfc1001.txt describes, amongst other things, the implementation and use
+of, a 'NetBIOS Name Service'. NT/AS offers 'Windows Internet Name Service'
+which is fully rfc1001/2 compliant, but has had to take specific action
+with certain NetBIOS names in order to make it useful. (for example, it
+deals with the registration of <1c> <1d> <1e> names all in different ways.
+I recommend the reading of the Microsoft WINS Server Help files for full
+details).
+
+Samba also offers WINS server capabilities. Samba does not interact
+with NT/AS (WINS replication), so if you have a mixed NT server and
+Samba server environment, it is recommended that you use the NT server's
+WINS capabilities, instead of samba's WINS server capabilities.
+
+The use of a WINS server cuts down on broadcast network traffic for
+NetBIOS name resolution. It has the effect of pulling all the broadcast
+isolated subnets together into a single NetBIOS scope, across your LAN
+or WAN, while avoiding the use of TCP/IP broadcast packets.
+
+When you have a WINS server on your LAN, WINS clients will be able to
+contact the WINS server to resolve NetBIOS names. Note that only those
+WINS clients that have registered with the same WINS server will be
+visible. The WINS server _can_ have static NetBIOS entries added to its
+database (usually for security reasons you might want to consider putting
+your domain controllers or other important servers as static entries,
+but you should not rely on this as your sole means of security), but for
+the most part, NetBIOS names are registered dynamically.
+
+[It is important to mention that samba's browsing capabilities (as a WINS
+client) must have access to a WINS server. if you are using samba also
+as a WINS server, then it will have a direct short-cut into the WINS
+database.
+
+This provides some confusion for lots of people, and is worth mentioning
+here: a Browse Server is NOT a WINS Server, even if these services are
+implemented in the same application. A Browse Server _needs_ a WINS server
+because a Browse Server is a WINS client, which is _not_ the same thing].
+
+Clients can claim names, and therefore offer services on successfully claimed
+names, on their broadcast-isolated subnet. One way to get NetBIOS services
+(such as browsing: see ftp.microsoft.com/drg/developr/CIFS/browdiff.txt; and
+SMB file/print sharing: see cifs6.txt) working on a LAN or WAN is to make
+your routers forward all broadcast packets from TCP/IP ports 137, 138 and 139.
+You will find, however, if you do this on a large LAN or a WAN, that your
+network is completely swamped by NetBIOS and browsing packets, which is why
+WINS was developed to minimise the necessity of broadcast traffic.
+
+WINS Clients therefore claim names from the WINS server. If the WINS
+server allows them to register a name, the client's NetBIOS session service
+can then offer services on this name. Other WINS clients will then
+contact the WINS server to resolve a NetBIOS name.
+
+
+=======================
+Samba WINS Capabilities
+=======================
+
+To configure samba as a WINS server, you must add "wins support = yes" to
+the [global] section of your smb.conf file. This will enable WINS server
+capabilities in nmbd.
+
+To configure samba as a WINS client, you must add "wins server = x.x.x.x"
+to the [global] section of your smb.conf file, where x.x.x.x is the TCP/IP
+address of your WINS server. The browsing capabilities in nmbd will then
+register (and resolve) WAN-wide NetBIOS names with this WINS server.
+
+Note that if samba has "wins support = yes", then the browsing capabilities
+will _not_ use the "wins server" option to resolve NetBIOS names: it will
+go directly to the internal WINS database for NetBIOS name resolution. It
+is therefore invalid to have both "wins support = yes" and
+"wins server = x.x.x.x". Note, in particular, that if you configure the
+"wins server" parameter to be the ip address of your samba server itself
+(as might one intuitively think), that you will run into difficulties.
+Do not use both parameters!
+
+
diff --git a/docs/textdocs/OS2-Client-HOWTO.txt b/docs/textdocs/OS2-Client-HOWTO.txt
new file mode 100644
index 00000000000..5507206a410
--- /dev/null
+++ b/docs/textdocs/OS2-Client-HOWTO.txt
@@ -0,0 +1,64 @@
+!==
+!== OS2-Client-HOWTO.txt for Samba release 1.9.18alpha8 30 Oct 1997
+!==
+
+
+Q. How can I configure OS/2 Warp Connect or OS/2 Warp 4 as a client for Samba?
+
+A. A more complete answer to this question can be found on:
+ http://carol.wins.uva.nl/~leeuw/samba/warp.html
+
+ Basically, you need three components:
+
+ * The File and Print Client ('IBM Peer')
+ * TCP/IP ('Internet support')
+ * The "NetBIOS over TCP/IP" driver ('TCPBEUI')
+
+ Installing the first two together with the base operating system on a blank
+ system is explained in the Warp manual. If Warp has already been installed,
+ but you now want to install the networking support, use the "Selective
+ Install for Networking" object in the "System Setup" folder.
+
+ Adding the "NetBIOS over TCP/IP" driver is not described in the manual and
+ just barely in the online documentation. Start MPTS.EXE, click on OK, click
+ on "Configure LAPS" and click on "IBM OS/2 NETBIOS OVER TCP/IP" in
+ 'Protocols'. This line is then moved to 'Current Configuration'. Select
+ that line, click on "Change number" and increase it from 0 to 1. Save this
+ configuration.
+
+ If the Samba server(s) is not on your local subnet, you can optionally add
+ IP names and addresses of these servers to the "Names List", or specify a
+ WINS server ('NetBIOS Nameserver' in IBM and RFC terminology). For Warp
+ Connect you may need to download an update for 'IBM Peer' to bring it on
+ the same level as Warp 4. See the webpage mentioned above.
+
+
+Q. How can I configure OS/2 Warp 3 (not Connect), OS/2 1.2, 1.3 or 2.x for
+ Samba?
+
+A. You can use the free Microsoft LAN Manager 2.2c Client for OS/2 from
+ ftp://ftp.microsoft.com/BusSys/Clients/LANMAN.OS2/
+ See http://carol.wins.uva.nl/~leeuw/lanman.html for more information on
+ how to install and use this client. In a nutshell, edit the file \OS2VER
+ in the root directory of the OS/2 boot partition and add the lines
+
+ 20=setup.exe
+ 20=netwksta.sys
+ 20=netvdd.sys
+
+ before you install the client. Also, don't use the included NE2000 driver
+ because it is buggy. Try the NE2000 or NS2000 driver from
+ <a href="ftp://ftp.cdrom.com/pub/os2/network/ndis/">
+ ftp://ftp.cdrom.com/pub/os2/network/ndis/</a> instead.
+
+
+Q. Are there any other issues when OS/2 (any version) is used as a client?
+
+A. When you do a NET VIEW or use the "File and Print Client Resource Browser",
+ no Samba servers show up. This can be fixed by a patch from
+ http://carol.wins.uva.nl/~leeuw/samba/fix.html
+ The patch will be included in a later version of Samba. It also fixes a
+ couple of other problems, such as preserving long filenames when objects
+ are dragged from the Workplace Shell to the Samba server.
+
+
diff --git a/docs/textdocs/PRINTER_DRIVER.txt b/docs/textdocs/PRINTER_DRIVER.txt
new file mode 100644
index 00000000000..ac6e4913026
--- /dev/null
+++ b/docs/textdocs/PRINTER_DRIVER.txt
@@ -0,0 +1,77 @@
+!==
+!== PRINTER_DRIVER.txt for Samba release 1.9.18alpha8 30 Oct 1997
+!==
+==========================================================================
+ Supporting the famous PRINTER$ share
+
+ Jean-Francois.Micouleau@utc.fr, 10/26/97
+
+===========================================================================
+
+Disclaimer:
+
+ This ONLY works with Windows 95
+ It does NOT work with Windows NT 4
+
+
+Goal:
+
+ When you click on a samba shared printer, you can now install the driver
+ automatically onto the Windows 95 machine, as you would from an NT server.
+
+How To:
+
+ It's a three step config.
+
+ First, create a new directory, where you will put the driver files, and
+ make a share in smb.conf pointing to it.
+
+ Example:
+
+ [printer$]
+ path=/usr/local/samba/printer
+ public=yes
+ writable=no
+ browseable=yes
+
+ Second, you have to build the list of the drivers required for a specific
+ printer. This is the most complicated thing to do. Get the files
+ 'msprint.inf' and 'msprint2.inf' from Windows 95, the easiest way is to
+ grab them from a working Windows 95 computer. They are usually located
+ in 'c:\windows\inf'. Look in them for the printer you have. Run the new
+ program 'mkprinterdef' with the file name and the printer name as
+ parameters.
+ Example:
+
+ mkprinterdef msprint.def "Apple LaserWriter" >>/usr/local/samba/lib/printers.def
+
+ Copy also all the files into the directory you created in step 1
+
+ Third, you need to add 2 new parameters in smb.conf. One is in the
+ [global] section, called 'printer driver file' pointing to the file description,
+ and the other in each printer share, called 'printer driver location' pointing
+ to where the client will get the drivers. Don't forget to set correctly
+ the printer driver parameter to the Windows printer name.
+ Example:
+
+ [global]
+ printer driver file=/usr/local/samba/lib/printers.def
+
+ [lp]
+ comment = My old printer laser
+ browseable = yes
+ printable = yes
+ public = yes
+ writable = no
+ create mode = 0700
+ printer driver=Apple LaserWriter
+ printer driver location=\\JOKER\PRINTER$
+
+ JOKER is in my case my computer name, and PRINTER$ is the name of the
+ share created in step one.
+
+
+If it doesn't work for you, don't send flame ! It worked for me. In case of
+trouble don't hesitate to send me a mail with your smb.conf file and
+printers.def
+
diff --git a/docs/textdocs/PROJECTS b/docs/textdocs/PROJECTS
index cf903f2c6dd..07f82c74d94 100644
--- a/docs/textdocs/PROJECTS
+++ b/docs/textdocs/PROJECTS
@@ -14,35 +14,37 @@ then please let me know! Also, if you are listed below and you have
any corrections or updates then please let me know.
Email contact:
-samba-bugs@anu.edu.au
+samba-bugs@samba.anu.edu.au
========================================================================
Documentation and FAQ
Docs and FAQ files for the Samba suite of software.
-Contact Karl.Auer@anu.edu.au
+Contact samba-bugs@samba.anu.edu.au with the diffs. These are urgently
+required.
-Mark Preston is now working on a set of formatted docs for Samba.
-Contact mpreston@sghms.ac.uk
+The FAQ is being added to on an ad hoc basis, see the web pages for info.
-Docs are currently up to date with version, 1.7.07. FAQ being added to
-as questions arise.
+Mark Preston was working on a set of formatted docs for Samba. Is this
+still happening? Contact mpreston@sghms.ac.uk
-Status last updated 27th September 1994
+Status last updated 2nd October 1996
========================================================================
========================================================================
Netbeui support
-This aims to produce patches so that Samba can be used with clients
+This aimed to produce patches so that Samba can be used with clients
that do not have TCP/IP. It will try to remain as portable as possible.
-
-Contact Brian.Onn@Canada.Sun.COM (Brian Onn)
-
-The project is just startup up.
-
-Status last updated 4th October 1994
+Contact Brian.Onn@Canada.Sun.COM (Brian Onn) Unfortunately it died, and
+although a lot of people have expressed interest nobody has come forward
+to do it. The Novell port (see Samba web pages) includes NetBEUI
+functionality in a proprietrary library which should still be helpful as
+we have the interfaces. Alan Cox (a.cox@li.org) has the information
+required to write the state machine if someone is going to do the work.
+
+Status last updated 2nd October 1996
========================================================================
========================================================================
@@ -52,21 +54,11 @@ A mountable smb filesystem for Linux using the userfs userspace filesystem
Contact lendecke@namu01.gwdg.de (Volker Lendecke)
-Currently this is at version 0.2. It works but is really only for
-people with some knowledge and experience of Linux kernel hacking.
-
-Status last updated 23rd August 1994
-========================================================================
-
-========================================================================
-Nmbd
-
-Aims to produce a complete rfc1001/1002 implementation. The current
-nmbd is a partial implementation.
-
-Contact Fabrice Cetre (cetre@ifhpserv.insa-lyon.fr)
+This works really well, and is measurably more efficient than commercial
+client software. It is now part of the Linux kernel. Long filename support
+is in use.
-Status last updated 23rd August 1994
+Status last updated June 1997
========================================================================
========================================================================
diff --git a/docs/textdocs/Passwords.txt b/docs/textdocs/Passwords.txt
index e06876fecae..41af3a4ab7e 100644
--- a/docs/textdocs/Passwords.txt
+++ b/docs/textdocs/Passwords.txt
@@ -1,5 +1,12 @@
-NOTE ABOUT PASSWORDS
-====================
+!==
+!== Passwords.txt for Samba release 1.9.18alpha8 30 Oct 1997
+!==
+Contributor: Unknown
+Date: Unknown
+Status: Current
+
+Subject: NOTE ABOUT PASSWORDS
+=============================================================================
Unix systems use a wide variety of methods for checking the validity
of a password. This is primarily controlled with the Makefile defines
@@ -33,7 +40,7 @@ only written and tested for AFS 3.3 and later.
SECURITY = SERVER
=================
-Samba can use a remote server to do it's username/password
+Samba can use a remote server to do its username/password
validation. This allows you to have one central machine (for example a
NT box) control the passwords for the Unix box.
diff --git a/docs/textdocs/Printing.txt b/docs/textdocs/Printing.txt
new file mode 100644
index 00000000000..4f29d469f85
--- /dev/null
+++ b/docs/textdocs/Printing.txt
@@ -0,0 +1,96 @@
+!==
+!== Printing.txt for Samba release 1.9.18alpha8 30 Oct 1997
+!==
+Contributor: Unknown <samba-bugs@samba.anu.edu.au>
+Date: Unknown
+Status: Current
+
+Subject: Dubugging Printing Problems
+=============================================================================
+
+This is a short description of how to debug printing problems with
+Samba. This describes how to debug problems with printing from a SMB
+client to a Samba server, not the other way around. For the reverse
+see the examples/printing directory.
+
+Please send enhancements to this file to samba-bugs@samba.anu.edu.au
+
+Ok, so you want to print to a Samba server from your PC. The first
+thing you need to understand is that Samba does not actually do any
+printing itself, it just acts as a middleman between your PC client
+and your Unix printing subsystem. Samba receives the file from the PC
+then passes the file to a external "print command". What print command
+you use is up to you.
+
+The whole things is controlled using options in smb.conf. The most
+relevant options (which you should look up in the smb.conf man page)
+are:
+ print command
+ lpq command
+ lprm command
+
+Samba should set reasonable defaults for these depending on your
+system type, but it isn't clairvoyant. It is not uncommon that you
+have to tweak these for local conditions.
+
+On my system I use the following settings:
+
+ print command = lpr -r -P%p %s
+ lpq command = lpq -P%p
+ lprm command = lprm -P%p %j
+
+The % bits are "macros" that get dynamically replaced with variables
+when they are used. The %s gets replaced with the name of the spool
+file that Samba creates and the %p gets replaced with the name of the
+printer. The %j gets replaced with the "job number" which comes from
+the lpq output.
+
+When I'm debugging printing problems I often replace these command
+with pointers to shell scripts that record the arguments, and the
+contents of the print file. A simple example of this kind of things
+might be:
+
+ print command = cp %s /tmp/tmp.print
+
+then you print a file and look at the /tmp/tmp.print file to see what
+is produced. Try printing this file with lpr. Does it work? If not
+then your problem with with your lpr system, not with Samba. Often
+people have problems with their /etc/printcap file or permissions on
+various print queues.
+
+Another common problem is that /dev/null is not world writeable. Yes,
+amazing as it may seem, some systems make /dev/null only writeable by
+root. Samba uses /dev/null as a place to discard output from external
+commands like the "print command" so if /dev/null is not writeable
+then nothing will work.
+
+Other really common problems:
+
+- lpr isn't in the search path when Samba tries to run it. Fix this by
+using the full path name in the "print command"
+
+- the user that the PC is trying to print as doesn't have permission
+to print. Fix your lpr system.
+
+- you get an extra blank page of output. Fix this in your lpr system,
+probably by editing /etc/printcap. It could also be caused by
+incorrect setting on your client. For example, under Win95 there is a
+option Printers|Printer Name|(Right
+Click)Properties|Postscript|Advanced| that allows you to choose if a
+Ctrl-D is appended to all jobs. This will affect if a blank page is
+output.
+
+- you get raw postscript instead of nice graphics on the output. Fix
+this either by using a "print command" that cleans up the file before
+sending it to lpr or by using the "postscript" option in smb.conf.
+
+Note that you can do some pretty magic things by using your
+imagination with the "print command" option and some shell
+scripts. Doing print accounting is easy by passing the %U option to a
+print command shell script. You could even make the print command
+detect the type of output and its size and send it to an appropriate
+printer.
+
+If the above debug tips don't help, then maybe you need to bring in
+the bug gun, system tracing. See Tracing.txt in this directory.
+
diff --git a/docs/textdocs/README.DCEDFS b/docs/textdocs/README.DCEDFS
index f84b84bb686..da9bb2197da 100644
--- a/docs/textdocs/README.DCEDFS
+++ b/docs/textdocs/README.DCEDFS
@@ -1,9 +1,8 @@
-=============================================================================
-
- Basic DCE/DFS Support for SAMBA 1.9.13
-
- Jim Doyle <doyle@oec.com> 06-02-95
+Contributor: Jim Doyle <doyle@oec.com>
+Date: 06-02-95
+Status: Current but needs updating
+Subject: Basic DCE/DFS Support for SAMBA 1.9.13
=============================================================================
Functionality:
diff --git a/docs/textdocs/README.jis b/docs/textdocs/README.jis
index 2ac6716a6f6..50ff0cced74 100644
--- a/docs/textdocs/README.jis
+++ b/docs/textdocs/README.jis
@@ -14,6 +14,10 @@
$B$rL\E*$H$7$F$$$^$9!#$=$N$?$a!"F|K\8lBP1~$O!"I,MW:G>.8B$7$+9T$J$C$F$*$j$^$;$s!#(B
+ $BF|K\8lBP1~$7$?(B samba $B$rMxMQ$9$k$?$a$K$O!"%3%s%Q%$%k$9$k;~$K!"I,$:!"(BKANJI $B$NDj5A$rDI(B
+ $B2C$7$F$/$@$5$$!#$3$N%*%W%7%g%s$r;XDj$7$F$$$J$$>l9g$O!"F|K\8l$N%U%!%$%kL>$r@5$7$/07(B
+ $B$&$3$H$O$G$-$^$;$s!#!J%3%s%Q%$%k$K$D$$$F$O!"2<5-(B 3. $B$r;2>H$7$F2<$5$$!K(B
+
2. $BMxMQJ}K!(B
(1) $BDI2C$7$?%Q%i%a!<%?(B
@@ -34,6 +38,12 @@
$B$N(B16$B?J?t$rB3$1$k7A<0$K$J$j$^$9!#(B
$B$3$3$G!"(B':' $B$rB>$NJ8;z$KJQ99$7$?$$>l9g$O!"(Bhex $B$N8e$m$K$=$NJ8;z$r;XDj$7$^$9!#(B
$BNc$($P!"(B@$B$rJQ$o$j$K;H$$$?$$>l9g$O!"(B'hex@'$B$N$h$&$K;XDj$7$^$9!#(B
+ cap: 7 bits $B$N(B ASCII $B%3!<%I0J30$N%3!<%I$r0J2<$N7A<0$GI=$9J}<0$H$$$&E@$G$O(B
+ hex$B$HF1MM$G$9$,!"(BCAP (The Columbia AppleTalk Package)$B$H8_49@-$r;}$DJQ49(B
+ $BJ}<0$H$J$C$F$$$^$9!#(Bhex$B$H$N0c$$$O(B0x80$B0J>e$N%3!<%I$N$_(B':80'$B$N$h$&$KJQ49(B
+ $B$5$l!"$=$NB>$O(BASCII$B%3!<%I$G8=$5$l$^$9!#(B
+ $BNc$($P!"(B'$B%*%U%#%9(B'$B$H$$$&L>A0$O!"(B':83I:83t:83B:83X'$B$H$J$j$^$9!#(B
+
JIS $B%3!<%I$K$D$$$F$O!"0J2<$NI=$r;2>H$7$F2<$5$$!#(B
$B(#(!(!(!(((!(!(!(!(((!(!(!(!(((!(!(!(!(((!(!(!(!(((!(!(!(!(((!(!(!(!(!(!(!(!(!($(B
$B(";XDj(B $B("4A;z3+;O("4A;z=*N;("%+%J3+;O("%+%J=*N;("1Q?t3+;O("Hw9M(B $B("(B
@@ -90,6 +100,8 @@
$B%$%kL>$O!"(BEUC $B%3!<%I$K$J$j$^$9!#$3$3$G;XDj$7$?%3!<%I7O$O!"%5!<%P5Z$S%/%i%$%"%s%H(B
$B%W%m%0%i%`$N%G%U%)%k%H$KCM$J$j$^$9!#(B
+ $B>0!"%*%W%7%g%sCf$N(B \ $B$d(B " $B$bK:$l$:$K;XDj$7$F2<$5$$!#(B
+
3. $B@)8B;v9`(B
(1) $B4A;z%3!<%I(B
@@ -104,21 +116,34 @@
$B$A$c$s$H$7$?%9%Z%C%/$,$h$/$o$+$i$J$+$C$?$N$G$9$,!"0l1~!"(BDOS/V $B$NF0:n$HF1$8F0:n$r9T$J(B
$B$&$h$&$K$J$C$F$$$^$9!#(B
+(4) $B%m%s%0%U%!%$%kL>$K$D$$$F(B
+ Windows NT/95 $B$G$O!"%m%s%0%U%!%$%kL>$,07$($^$9!#%m%s%0%U%!%$%kL>$r(B 8.3 $B%U%)!<%^%C%H(B
+ $B$G07$&$?$a$K!"(Bmangling $B$7$F$$$^$9$,!"$3$NJ}K!$O!"(BNT $B$d(B 95 $B$,9T$J$C$F$$$k(B mangling $B$H(B
+ $B$O0[$J$j$^$9$N$GCm0U$7$F2<$5$$!#(B
+
4. $B>c32Ey$N%l%]!<%H$K$D$$$F(B
$BF|K\8l$N%U%!%$%kL>$K4X$7$F!"J8;z2=$1Ey$N>c32$,$"$l$P!";d$K%l%]!<%H$7$FD:$1$l$P9,$$$G(B
$B$9!#$?$@$7!"%*%j%8%J%k$+$i$NLdBjE@$d<ALd$K$D$$$F$O!"%*%j%8%J%k$N:n<T$XD>@\Ld$$9g$o$;$k(B
$B$+!"$b$7$/$O%a!<%j%s%0%j%9%H$J$I$X%l%]!<%H$9$k$h$&$K$7$F2<$5$$!#(B
+$B%l%]!<%H$5$l$k>l9g!"MxMQ$5$l$F$$$k4D6-(B(UNIX $B5Z$S(B PC $BB&$N(BOS$B$J$I(B)$B$H$G$-$^$7$?$i@_Dj%U%!(B
+$B%$%k$d%m%0$J$I$rE:IU$7$FD:$1$k$H9,$$$G$9!#(B
+
5. $B$=$NB>(B
- hex $B7A<0$NJQ49J}K!$O!"(B
+ $B%3!<%IJQ49$O0J2<$NJ}!9$,:n$i$l$?%W%m%0%i%`$rMxMQ$7$F$$$^$9!#(B
- $BBgLZ!wBgDM!&C^GH(B <ohki@gssm.otsuka.tsukuba.ac.jp>$B;a(B
+ hex $B7A<0(B $BBgLZ!wBgDM!&C^GH(B <ohki@gssm.otsuka.tsukuba.ac.jp>$B;a(B
+ cap $B7A<0(B $BI%ED(B $BF;O:(B (michiro@po.iijnet.or.jp)(michiro@dms.toppan.co.jp)$B;a(B
- $B$,:n$i$l$?%3!<%I$rMxMQ$7$F$$$^$9!#(B
+ $B$=$NB>!"$?$/$5$s$NJ}!9$+$i$$$m$$$m$H8f65<($$$?$@$-$"$j$,$H$&$4$6$$$^$7$?!#:#8e$H$b$h(B
+$B$m$7$/$*4j$$CW$7$^$9!#(B
1994$BG/(B10$B7n(B28$BF|(B $BBh#1HG(B
1995$BG/(B 8$B7n(B16$BF|(B $BBh#2HG(B
+1995$BG/(B11$B7n(B24$BF|(B $BBh#3HG(B
+1996$BG/(B 5$B7n(B13$BF|(B $BBh#4HG(B
+
$BF#ED(B $B?r(B fujita@ainix.isac.co.jp
diff --git a/docs/textdocs/README.sambatar b/docs/textdocs/README.sambatar
index 26829952eb6..af7250c2a49 100644
--- a/docs/textdocs/README.sambatar
+++ b/docs/textdocs/README.sambatar
@@ -1,3 +1,11 @@
+Contributor/s: Martin.Kraemer <Martin.Kraemer@mch.sni.de>
+ and Ricky Poulten (ricky@logcam.co.uk)
+Date: Unknown - circa 1994
+Status: Obsoleted - smbtar has been a stable part of Samba
+ since samba-1.9.13
+
+Subject: Sambatar (now smbtar)
+=============================================================================
This is version 1.4 of my small extension to samba that allows PC shares
to be backed up directly to a UNIX tape. It only has been tested under
diff --git a/docs/textdocs/SCO.txt b/docs/textdocs/SCO.txt
index 1b3801471f7..d2efa4cdda2 100644
--- a/docs/textdocs/SCO.txt
+++ b/docs/textdocs/SCO.txt
@@ -1,4 +1,14 @@
-There is an annoying TCPIP bug in SCO Unix. This causes orruption when
+!==
+!== SCO.txt for Samba release 1.9.18alpha8 30 Oct 1997
+!==
+Contributor: Geza Makay <makayg@math.u-szeged.hu>
+Date: Unknown
+Status: Obsolete - Dates to SCO Unix v3.2.4 approx.
+
+Subject: TCP/IP Bug in SCO Unix
+============================================================================
+
+There is an annoying TCPIP bug in SCO Unix. This causes corruption when
transferring files with Samba.
Geza Makay (makayg@math.u-szeged.hu) sends this information:
diff --git a/docs/textdocs/SMBTAR.notes b/docs/textdocs/SMBTAR.notes
index a23cbf2b325..679d776f56c 100644
--- a/docs/textdocs/SMBTAR.notes
+++ b/docs/textdocs/SMBTAR.notes
@@ -1,3 +1,9 @@
+Contributor: Unknown
+Date: 1994
+Status: Mostly Current - refer man page
+
+Subject: Smbtar
+============================================================================
Intro
-----
@@ -37,4 +43,4 @@ newer filename
into its own with sambatar. This causes tar (or get, mget, etc) to
only copy files newer than the specified file name. Could be used
against the previous nights (or whatever) log file to implement incremental
-backups. \ No newline at end of file
+backups.
diff --git a/docs/textdocs/Speed.txt b/docs/textdocs/Speed.txt
index 5dfd70323b1..298374f2fa0 100644
--- a/docs/textdocs/Speed.txt
+++ b/docs/textdocs/Speed.txt
@@ -1,8 +1,14 @@
-This file tries to outline the ways to improve the speed of a Samba server.
+!==
+!== Speed.txt for Samba release 1.9.18alpha8 30 Oct 1997
+!==
+Contributor: Andrew Tridgell
+Date: January 1995
+Status: Current
-Andrew Tridgell
-January 1995
+Subject: Samba performance issues
+============================================================================
+This file tries to outline the ways to improve the speed of a Samba server.
COMPARISONS
-----------
@@ -30,6 +36,47 @@ hardware Samba should certainly be competitive in speed with other
systems.
+OPLOCKS
+-------
+
+Oplocks are the way that SMB clients get permission from a server to
+locally cache file operations. If a server grants an oplock
+(opportunistic lock) then the client is free to assume that it is the
+only one accessing the file and it will agressively cache file
+data. With some oplock types the client may even cache file open/close
+operations. This can give enormous performance benefits.
+
+With the release of Samba 1.9.18 we now correctly support opportunistic
+locks. This is turned on by default, and can be turned off on a share-
+by-share basis by setting the parameter :
+
+oplocks = False
+
+We recommend that you leave oplocks on however, as current benchmark
+tests with NetBench seem to give approximately a 30% improvement in
+speed with them on. This is on average however, and the actual
+improvement seen can be orders of magnitude greater, depending on
+what the client redirector is doing.
+
+Previous to Samba 1.9.18 there was a 'fake oplocks' option. This
+option has been left in the code for backwards compatibility reasons
+but it's use is now deprecated. A short summary of what the old
+code did follows.
+
+Old 'fake oplocks' option - deprecated.
+---------------------------------------
+
+Samba can also fake oplocks, by granting a oplock whenever a client
+asks for one. This is controlled using the smb.conf option "fake
+oplocks". If you set "fake oplocks = yes" then you are telling the
+client that it may agressively cache the file data for all opens.
+
+Enabling 'fake oplocks' on all read-only shares or shares that you know
+will only be accessed from one client at a time you will see a big
+performance improvement on many operations. If you enable this option
+on shares where multiple clients may be accessing the files read-write
+at the same time you can get data corruption.
+
SOCKET OPTIONS
--------------
@@ -80,7 +127,10 @@ MAX XMIT
At startup the client and server negotiate a "maximum transmit" size,
which limits the size of nearly all SMB commands. You can set the
maximum size that Samba will negotiate using the "max xmit = " option
-in smb.conf.
+in smb.conf. Note that this is the maximum size of SMB request that
+Samba will accept, but not the maximum size that the *client* will accept.
+The client maximum receive size is sent to Samba by the client and Samba
+honours this limit.
It defaults to 65536 bytes (the maximum), but it is possible that some
clients may perform better with a smaller transmit unit. Trying values
@@ -111,7 +161,20 @@ no". This will gain you a lot in opening and closing files but will
mean that (in some cases) the system won't force a second user of a
file to open the file read-only if the first has it open
read-write. For many applications that do their own locking this
-doesn't matter, but for some it may.
+doesn't matter, but for some it may. Most Windows applications
+depend heavily on "share modes" working correctly and it is
+recommended that the Samba share mode support be left at the
+default of "on".
+
+The share mode code in Samba has been re-written in the 1.9.17
+release following tests with the Ziff-Davis NetBench PC Benchmarking
+tool. It is now believed that Samba 1.9.17 implements share modes
+similarly to Windows NT.
+
+NOTE: In the most recent versions of Samba there is an option to use
+shared memory via mmap() to implement the share modes. This makes
+things much faster. See the Makefile for how to enable this.
+
LOG LEVEL
---------
@@ -187,7 +250,7 @@ Samba supports reading files via memory mapping them. One some
machines this can give a large boost to performance, on others it
makes not difference at all, and on some it may reduce performance.
-To enable you you have to recompile Samba with the -DUSE_MMAP=1 option
+To enable you you have to recompile Samba with the -DUSE_MMAP option
on the FLAGS line of the Makefile.
Note that memory mapping is only used on files opened read only, and
@@ -239,6 +302,7 @@ person even reported a speed drop of a factor of 30 when he went from
It probably depends a lot on your hardware, and the type of unix box
you have at the other end of the link.
+
MY RESULTS
----------
@@ -269,4 +333,4 @@ COMMENTS
If you've read this far then please give me some feedback! Which of
the above suggestions worked for you?
-Mail the samba mailing list or samba-bugs@anu.edu.au
+Mail the samba mailing list or samba-bugs@samba.anu.edu.au
diff --git a/docs/textdocs/Support.txt b/docs/textdocs/Support.txt
index d71bdaf7b3e..affb647ad8c 100644
--- a/docs/textdocs/Support.txt
+++ b/docs/textdocs/Support.txt
@@ -1,55 +1,526 @@
+!==
+!== Support.txt for Samba release 1.9.18alpha8 30 Oct 1997
+!==
The Samba Consultants List
==========================
-This is a list of people who are prepared to install and support Samba.
-Note that in most countries nobody should admit to "supplying" Samba, since
-there is then an implied warranty with possibly onerous legal obligations.
-Just downloading and installing it isn't supply in this sense, but advertising
-"run our Samba for best results" may be so.
+This is a list of people who are prepared to commercialy support
+Samba. Being on this list does not imply any sort of endorsement by
+anyone, it is just provided in the hope that it will be useful.
-Being on this list does not imply any sort of endorsement by anyone, it is just
-provided in the hope that it will be useful.
+Note that the organisations listed below will expect you to pay for
+The support that they offer. We have been told that several people
+assumed this was a list of kindly companies offering free commercial
+support!
+
+For free support use the Samba mailing list and the comp.protocols.smb
+newsgroup.
If you want to be added to the list, or want your entry modified then
-contact the address below. They are currently listed in the
-order that they were received. If it gets too big we may organise it
-by region. Please make sure to include a header line giving the region
-and country, eg CANBERRA - AUSTRALIA.
+contact the address below. Please make sure to include a header line
+giving the region and country, eg CANBERRA - AUSTRALIA.
+
+The Samba Team reserves the right not to add support providers.
+
+You can contact the maintainers at samba-bugs@samba.anu.edu.au
+
+The support list has now been re-arranged into geographical areas
+and are sorted by state/region/town within these areas.
+These are currently:
+
+Region Number of entries
+----------------------------------------------------
+ AFRICA 2
+ AMERICA - CENTRAL & SOUTH 4
+ AMERICA - USA 35
+ ASIA 1
+ AUSTRALIA & NEW ZEALAND 18
+ CANADA 9
+ EUROPE 36
+ MIDDLE EAST 1
+
+AFRICA
+======
+
+------------------------------------------------------------------------------
+GAUTENG - SOUTH AFRICA
-You can contact the maintainers at samba-bugs@anu.edu.au
+Company: Obsidian Systems
+Street Addr: Boskruin Office Park Unit 3, Bosbok street, Randpark Ridge
+ Gauteng, 2156, South Africa.
+Postal Addr: PO Box 4938, Cresta, South Africa, 2118
+Contact no's: +2711 792-6500/38, Fax: +2711-792-6522
+ Cell: +2783-379-6889/90/91 or +2783-377-4946 or +27832660199
+Our level of experience: Low level programming and support for all samba
+security and compatability issues. We use Samba in South African Schools
+and commercial companies as an affordable solution for LAN and WAN
+networking.
+For futher information, please consult our website www.obsidian.co.za
------------------------------------------------------------------------------
-BRISBANE - AUSTRALIA
-Brett Worth
-Select Computer Technology - Brisbane
-431 Logan Road
-Stones Corner QLD 4120
-E-Mail: brett@sct.com.au
------------------------------------------------------------------------------
+JOHANNESBURG - SOUTH AFRICA
+
+ Company: Symphony Research (Pty) Ltd
+ Contact: Dr Evan Summers, <evan@sr.co.za>, tel 011 728-5742.
+keywords: Samba on Linux, support and consulting
+ Johannesburg (South Africa)
------------------------------------------------------------------------------
-CANBERRA - AUSTRALIA
-Paul Blackman (ictinus@lake.canberra.edu.au, Ph. 06 2012518) is
-available for consultation. Paul's Samba background is with
-Solaris 2.3/4 and WFWG/Win95 machines. Paul is also the maintainer
-of the SAMBA Web Pages.
+
+
+
+
+
+
+AMERICA - CENTRAL & SOUTH
+=========================
+
+
+------------------------------------------------------------------------------
+ARGENTINA - SOUTH AMERICA
+
+Buenos Aires - Argentina
+
+Guillermo Sansovic
+Email: gui@usa.net
+Arkham Software
+Rivadavia 923 Piso 8
+1002 Buenos Aires
+Argentina
+
+Tel: + 54 1 345-0645
+
+At Arkham Software we have been working with Unix systems since 1986. We do
+intranets, software development and system integration. Our experience ith
+Samba dates from 1995.
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-READING - ENGLAND
+CHILE - SOUTH AMERICA
+
+Company: Magic Consulting Group/Magic Dealer
+Street Addr: Alberto Reyes #035 Barrio Bellavista
+ Providencia Santiago
+Contact no's: +56 2 365 19 18, Fax: +56 2 365 14 55
+
+Contact Person: Marcelo Bartsch or Roy Zderich
+
+Email contact:
+Samba Support : samba@mg.dyn.ml.org
+Other NET OS Support : othernetos@mg.dyn.ml.org
+Other Questions : networks@mg.dyn.ml.org
+General Info: info@mg.dyn.ml.org
+
+Our level of experience: support for all Samba and Linux security and
+compatability issues. We use Samba in our local network and we have
+experience instaling it on some other locations. we also provide
+techincal support for Linux, Novell, Windows NT, OS/2 and other
+Operating Systems.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+HONDURAS - CENTRAL AMERICA
+
+Open Systems, S.A.
+
+Open Systems, S.A. provides support to SAMBA in SCO UnixWare 2.X:
+
+Server Platform: SCO UnixWare 2.X
+Client Platform: Windows NT, Windows 95, WFW (3.11), DOS.
+
+Open Systems, S.A. also provides consulting services and technical
+support in the following server platforms since 1987:
+
+SCO Open Server 3.0 and 5.0
+SCO UnixWare 2.X (SVR4.2MP)
+UNIX SVR4 (NCR, UNISYS)
+
+Contact:
+Selim Jose Miselem
+Open Systems, S.A.
+Centro Comercial Dallas
+San Pedro Sula, Honduras, Central America
+Tel/Fax 011 (504) 529868
+e-mail: selim@opensys.hn
+URL: http://www.opensys.hn
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+VILLAHERMOSA, TAB. - MEXICO
+
+Carlos Enrique García Díaz
+E-mail: cgarcia@tnet.net.mx
+Phone: (93) 12-33-91
+
+Samba experience:
+Server: Samba 1.9.15 and above with Solaris (Sparc & x86), SG Irix 5.2 - 6.3,
+AIX 3.2, DEC OSF1 v4.0, DG/UX v4.11, SunOS.
+Client: WinNT, Win95, WfWg, Win 3.1 & LAN WorkPlace.
+------------------------------------------------------------------------------
+
+
+
+
+
+
+
+AMERICA - USA
+=============
+
+------------------------------------------------------------------------------
+ARIZONA - USA
+
+Stephen Greenberg
+Nick Temple
+Coactiv Systems Inc.
+4625 S. Lakeshore Drive, suite 401
+Tempe, AZ 85282
+(602) 345 4114
+(602) 345 4105 fax
+steveg@coactiv.net
+
+We are LAN/WAN integrators who specialize in the standard fare (i.e. Novell
+and NT) as well as UNIX, NTRIGUE and SAMBA.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+BAY AREA, SILICON VALLEY CALIFORNIA - USA
+
+Adital Corp.
+
+7291 Coronado Dr. ,Suite 4 San-Jose Ca 95129
+
+Phone : (408) 257-7717 Fax : (408) 257-7772 E-Mail: ephi@adital.com
+
+Contact: Ephi Dror, Director of software development.
+
+Adital is a company that specialized in networking products development.
+We have been doing many development projects on Windows (NT/95), Macintosh,
+UNIX and embedded system platforms in the area of networking drivers and
+applications during the last few years. In regards to SAMBA, we have a lot
+of experience in SMB/CIFS protocol development.
+
+We have special expertise in porting SAMBA to embedded system environments for
+NT/WIN95/WFW client/server connectivity.
+
+We can help you defining and specifying your product as well as designing,
+implementing, testing, upgrading and maintaining it.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+SAN FRANCISCO BAY AREA - USA
+
+Alex Davis --- President of FTL
+Faster Than Light, 2570 Ocean Ave. #114, San Francisco, California, 94132
+HTTP://www.ftl.net/ EMAIL:davis@ftl.net TEL:415.334.2922 FAX:415.337.6135
+
+We are located in the "Bay Area" of California, USA. We provide
+consultant and training for Unix, Windows, Macintosh applications,
+and hardware. We also provide Internet access to many of the local
+companies as a part of our "one-stop-shop" model.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+SAN FRANCISCO BAY AREA - USA
-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
+2125 Hamilton Ave. Suite 100
+San Jose, CA 95125
+888-ACCLAIM [Inside California]
+(408) 879 - 3100
+(408) 377-4900 [Fax]
+
+We can provide commercial support for Samba. We have created additional
+scripts that we can add to the Samba distribution to create an installation in
+Sun Solaris "package add" format. We are a Sun Reseller, but we can also
+support Samba on HP, SGI, Linux, in addition to Sun Solaris Sparc/X86.
+
+To find out more about our company, look at our website:
+ http://www.acclaim.com
+------------------------------------------------------------------------------
-Samba experience: SVR4,SVR3.2 & Linux <--> WfWg, W3.1, OS2 and MS-LanMan
------------------------------------------------------------------------------
+BAY AREA, BERKELEY CALIFORNIA - USA
+
+Vortex Technology Services
+
+2467 Warring St Suite 206, Berkeley CA 94704
+
+Phone/Fax : (510) 540-VTEX E-Mail: support@vtex.net
+ (510) 540-8839
+Contact: Paul Puey, Chief Network Consultant/Engineer
+
+Vortex Technology is a fast growing technical service company based in
+Berkeley, California. Our Co-founders are composed entirely of UC
+Berkeley engineering graduates with a broad range of skills in the
+technical consultation fields. We provide bay area companies with
+professional web site and database design, LAN and WAN consultation, and
+custom programming. We ourselves use a mixed NT / Linux Samba server
+environment in our office. We are very experienced with Samba
+administration as well as administration of UNIX and NT networks.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+CALIFORNIA - USA
+
+Cliff Skolnick
+Steam Tunnel Operations
+900 Tennessee St, suite 22
+San Francisco, CA 94107
+http://www.steam.com/
+(415) 920-3800
+cliff@steam.com
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+CALIFORNIA - USA
+
+Craftwork Solutions Inc.
+
+Craftwork Solutions Inc. is dedicated to providing the best possible
+services to our customers. The Craftworks team will provide you with a
+total solution package that will work for you both today and tomorrow.
+With our own Linux Distribution which we are constantly improving to make
+it the best and using it to provide total solutions for companies which
+are open to using Linux.
+
+Please contact mary@craftwork.com
+------------------------------------------------------------------------------
+
+-----------------------------------------------------------------------
+SOUTHERN CALIFORNIA - USA
+
+Michael St. Laurent
+Serving Los Angeles and Orange Counties. Please contact via email.
+rowl@earthlink.net
+Michael St. Laurent
+Hartwell Corporation
------------------------------------------------------------------------------
-ILLONOIS - USA
+
+------------------------------------------------------------------------------
+SOUTHERN CALIFORNIA - USA
+
+Yuri Diomin
+Yuri Software
+13791 Ruette Le Parc, Ste. C
+Del Mar, CA 92014
+Phone: 619-350-8541
+Fax: 619-350-7641
+yuri@yurisw.com
+http://www.yurisw.com
+
+We have been supporting Samba in commercial installations for several years
+on a variety of client and server platforms. We have extensive experience
+in all aspects of UNIX-Windows connectivity solutions for mixed platform
+corporate setups. We are a contributor to Samba source code.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+NORTH CAROLINA - USA
+
+Whole Systems Solutions, Inc.
+
+ Whole Systems Solutions, Inc. has been running Samba since the
+1.6 release. We specialize in small to medium sized business network
+solutions. Whole Systems Solutions, Inc. provides outsourcing of IT to
+enhance employee abilities therefore improving productivity. Through
+software beta testing and development network of NT, NetWare, Unix, and
+Win clients we have developed a vast knowledge base for support. Our
+clients choose us for service and support that exceeds their
+expectations. Your business depends on your computers. Your computers
+should depend on WSS.
+
+Jay M. Eisenberg Whole Systems Solutions, Inc.
+President
+Web: http://www.wss.net
+Phone: (910) 297-4977
+Email: jay@wss.net
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+FORT COLLINS, COLORADO - USA
+
+Granite Computing Solutions
+ATTN: Brian Grossman
+P.O. Box 270103
+Fort Collins, CO 80527-0103
+U.S.A.
+Tel: +1 (970) 225-2370
+Email: granite@SoftHome.Net WWW: http://www.SoftHome.Net/granite/
+
+Information services, including WfWG, NT, Apple <=> Unix interoperability.
+WWW solutions. WWW education. Unix education. Custom software
+development - eg. http://www.SoftHome.Net/modsim/.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+COLORADO - USA
+
+Daylight Software
+1062 Lexington Lane
+Estes Park, CO 80517 USA
+(970) 586-6058
+
+We have experience with Samba under SunOS, Solaris and Linux,
+and also with Windows NT and Microsoft Lan Manager.
+
+Contact: daylight@frii.net
+
+Chris Howard Daylight Software
+daylight@frii.net Estes Park, Colorado USA
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+FLORIDA - USA
+
+Swaney & Associates, Inc.
+ATTN: Stephen Swaney
+ 2543 Lincoln Avenue
+ Miami, Florida 33133
+ U.S.A
+ (305) 860-0570
+
+Specializing in:
+ High Availability system & networks
+ UNIX to PC connectivity
+ Market Data systems
+ Messaging Systems (Sendmail & Microsoft Exchange)
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+FLORIDA - USA
+
+Progressive Computer Concepts, Inc.
+1371 Cassat Avenue
+Jacksonville, FL 32205
+info@progressive-comp.com
+800-580-2640 - 904-389-3236 - 904-389-6584 fax
+
+Related Products and Services:
+ ncLinux (Network Computer) consulting, installations, and turnkey
+ networks. Multi-user NT and Samba consulting, installation and
+ administration (both remote and onsite), Internet and Intranet
+ connectivity, LAN and WAN, firewall installation, security,
+ troubleshooting and training, custom LAN/WAN/Intranet business
+ systems development, WWW/CGI development (e.g. database gateways,
+ catalogs).
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+FLORIDA - USA
+
+The PC Doctor
+3009 West Tharpe Street Unit-C
+Tallahassee, Florida 32303
+ph 904.531.0364
+fx 904.531.0128
+
+Contacts: Andy McRory pcdr@pcdr.com
+ David Blodgett david@pcdr.com
+
+The PC Doctor specializes in Linux Internet/Workgroup servers and network
+intergration. We have experience in setup and configuration of SAMBA under
+Caldera/RedHat/Slackware Linux as well as SCO and AIX. We offer workgroup
+Internet gateway servers for Windows client based networks.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+FLORIDA - USA
+
+TradeWeb
+Bill Harris
+(407) 657-8649
+bill@tradeweb.net
+
+http://www.tradeweb.net
+
+We have been working with SAMBA since 1995 and support it in a number of
+large organizations. We are available to Companies in the Central
+Florida area. We are well familiar in the integration of SAMBA and NT
+and in SAMBA configuration on AIX, SCO, Linux And SUN Solaris.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+FLORIDA - USA
+
+The PC Doctor
+Tampa Bay Interactive
+1314 Tampa Rd STE 120
+Palm Harbor, FL 34683
+
+ph 813.781-2209
+fx 813.571-3805
+
+Contacts: Jared Hall: jhall@tbi.net
+ System Operations: support@tbi.net
+
+Tampa Bay Interactive provides complete Internet solutions for the Small
+Office and Home Office. Specializing in Intel-Based UNIX systems; Linux,
+BSD/OS, FreeBSD, SCO. Proxy Server specialists.
+
+~~ Jared Hall ~~~~~~~ Tampa Bay Interactive
+~~~~~~~~~~~~~~~~~~~~~ 1314 Tampa Rd, #120
+~~ jhall@tbi.net ~~~~ Palm Harbor, FL 34683
+~~ (813) 781-2209 ~~~ (http://www.tbi.net)
+
+Telecom Corner - http://www.tbi.net/~jhall
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+GEORGIA - USA
+
+Hoppe Computer Services
+2171 Brooks Road
+Dacula(Atlanta), Georgia 30019
+770-995-5099 fax 770-338-3885
+
+Supporting the Atlanta, Georgia USA area for two and a half years.
+In the computer field for 22 years.
+
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+GEORGIA - USA
+
+Region: ATLANTA, GA - USA
+Company: Advanced Application Development, Inc.
+Address: 4383 Burnleigh Chase
+ Roswell, GA 30075
+Telephone: (770) 552-4248
+email: support@aad.com
+Contact Name: Rich Vaughn
+ rvaughn@aad.com
+
+Provides consulting, development and system integration
+services for businesses throughout the Southeastern US.
+We have been using Samba on various UNIX platforms for
+several years and are familiar with porting and configuration
+issues. Visit our web site at http://www.aad.com.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+IOWA - USA
+
+Afan Ottenheimer
+JEONET
+PO Box 1282
+Iowa City, IA 52244
+Phone: 319-338-6353
+Fax: 319-338-6353
+Email: afan@jeonet.com
+WWW: http://www.jeonet.com/jeonet/
+
+Specializing in systems integration, database, and advanced web
+site design since 1995. Have extensive experience in
+Linux<->NT<->Windows 3.11<->Windows 95 interaction using SAMBA.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+ILLINOIS - USA
Information One, Inc.
736 Hinman Ave, Suite 2W
@@ -61,103 +532,481 @@ Providing custom Internet and networking solutions.
------------------------------------------------------------------------------
------------------------------------------------------------------------------
+ILLINOIS - USA
+
+Honesty Communications Inc.
+1001 W 75th St Suite 179A-200
+Woodridge, IL 60517
+
+http://www.honesty.com
+support@honesty.com
+
+(630) 964-8441
+(708) 399-8158 Emergency Pager
+
+Serving as 'Technical Support for Technical Support' to numerous
+companies across the country Honesty Communications provides
+solutions for all situations with
+
+We can provide Samba installation, configuration, and security analysis
+as well as on-going support, training and upgrades. We also provide
+custom programming and a slew of other services.
+
+Expertise includes:
+
+ UNIX, Windows 95, Windows NT, Windows 3.x, OS/2, Programming (C/C++,
+ Java, Visual Basic, Visual C, etc.), Support, Training
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+KANSAS - USA
+
+NT Integrators
+2400 W. 31st Street
+Lawrence, KS 66046
+USA
+913-842-1100
+http://www.ntintegrators.com/
+email: watts@sunflower.com
+
+My consulting company does NT/Linux/Samba/etc support.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+LAS VEGAS, NEVADA - USA
+
+DPN, Inc. Las Vegas NV
+
+(702) 873-3282 Ph.
+(702) 873-3913 Fax
+Email duane@dpn.com
+
+Can provide commercial support for samba running on any version of
+SCO above 3.0 and for Linux. We currently have installed and are
+supporting several versions of samba on over 25 client sites across
+the US, in addition to our 6 in-house samba servers. Our largest client
+site has approx. 100 users.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+NEW JERSEY - USA
+
+William J. Maggio
+LAN & Computer Integrators, Inc.
+242 Old New Brunswick Road Email: bmaggio@lci.com
+Suite 440 Voice: 908-981-1991
+Piscataway, NJ 08855 Fax : 908-981-1858
+
+ Specializing in Internet connectivity and security, Sun integration and
+ high speed, enterprise network design and deployment.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+NEW YORK - USA
+
+67.2 Psytronics Solutions
+
+ 90 County Line Road
+ Massapequa, NY 11758
+ U.S.A.
+
+Phone: +1 516 598 4619
+
+Fax: +1 516 598 4619
+
+EMail: info@psytronics.com
+
+URL: http://www.psytronics.com
+
+Contact: Jaron Rubenstein
+
+Type of support: Whatever is required. Support contracts available.
+
+Special expertise:
+
+ Familiar with most topics. Specializing in dial-up server (PPP)
+installation and configuration, custom programming, and Internet and
+Intranet server configuration. Authorized Red Hat Reseller.
+
+Sample prices:
+
+ Upon request, usually US$50-$100/hour. Educational discounts
+available.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+OREGON - USA
+
+Warren Birnbaum
+Birnbaum Associates
+2934 N.E. 18th Avenue
+Portland, OR 97212
+Phone: 503-282-6329
+Fax: 503-288-7074
+birnbaum@teleport.com
+
+I have been supporting Samba in commercial installations for several
+years on HP-UX and Solaris server platforms. I have installed Samba on
+over 80 servers used by over 7000 users. I am a contributor to Samba
+source code.
+
+I can provide Samba installation, configuration, and custom coding
+as well as on-going support.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+TEXAS - USA
+
+Jody Winston
+xprt Computer Consulting, Inc.
+731 Voyager
+Houston, TX 77062
+(281) 480 8649, jody@sccsi.com
+
+We have been supporting software from the Free Software Foundation and
+other groups such as Linux for over 8 years. The base rate is 150.00
+US dollars per hour. Please contact us for more information on our
+rates and services.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+TEXAS - USA
+
+The Solutions Group
+P.O. Box 31400
+Houston, TX 77231-1400
+
+Voice: (713) 729-2602
+Fax: (713) 723-9387
+Email: chuckb@LinuxTX.com
+
+The Solutions Group provides support for Linux, Solaris, and SCO UNIX.
+We specialize in mixed environments using Samba. We are certified NT
+as well as UNIX specialists. We can provide onsite support in the
+Houston area and remote support in any other areas.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+UNITED STATES
+
+Stelias Computing is the developer of the InfoMagic Workgroup Server, a
+Linux distribution customized for use as a PC and Macintosh file and
+print server (using Samba and netatalk respectively). Stelias also
+offers custom system programming and Samba support contracts.
+
+For information about the InfoMagic Workgroup Server contact InfoMagic:
+ http://www.infomagic.com/
+ questions@infomagic.com
+ voice: 800-800-6613 or 520-526-9565
+ fax: 520-526-9573
+
+To contact Stelias about custom arrangments, send email to
+info@stelias.com.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+WASHINGTON DC METRO - USA
+
+Asset Software, Inc. has been running Samba since the 1.6 release on various
+platforms, including SunOS 4.x, Solaris 2.x, IRIX 4.x and 5.x, Linux 1.1x,
+1.2x, and 1.3x, and BSD UNIX 4.3 and above. We specialize in small office
+network solutions and provide services to enhance a small office's
+operations. Primarily a custom software operation, our vast knowledge of
+Windows, DOS, Unix, Windows NT, MacOS, and OS/2 enable us to provide quality
+technical assistance to the small office environment at a reasonable price.
+Our upcoming multi-mailbox mail client, IQ Mail, enables users with more
+than one mailbox to send and retrieve their mail from a single, consistent
+mail client running in Windows.
+
+David J. Fenwick Asset Software, Inc.
+President djf@assetsw.com
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+WASHINGTON STATE - USA
+
+Brian Meyer
+Personal Data Services
+9792 Edmonds Way Suite 121
+Seattle, Washington 98020 USA
+Voice: (206) 365-8212
+E-mail: admin@pdsnorth.com
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+WASHINGTON - USA
+
Olympic Peninsula Consulting; 1241 Lansing Ave W., Bremerton, WA 98312-4343
telephone 1+ 360 792 6938; mailto:opc@aa.net; http://www.aa.net/~opc;
Unix Systems and TCP/IP Network design, programming, and administration.
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-SolutionS R Us has been in business for 3+ years providing viable 3rd
-party support in system/network administration. With our own Linux
-distribution which we're constantly improving to make it the best and
-using it to provide total solutions for companies which are open to
-using Linux.
+WASHINGTON STATE - USA
+
+INTERNET: bill@Celestial.COM Bill Campbell; Celestial Systems, Inc.
+UUCP: camco!bill PO Box 820; 2835 82nd Avenue S.E. S-100
+FAX: (206) 232-9186 Mercer Island, WA 98040-0820; (206) 236-1676
+URL: http://www.celestial.com/
+
+We provide support for Samba and many other Unix related systems. Our
+primary systems are SCO, Caldera Linux, and Solaris on Sun systems.
-Mauro DePalma <mauro@sru.com>
+Celestial has been in business since late 1984 working primarily on
+medium to large Unix systems. More information is available on our
+web site, http://www.celestial.com/.
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-BIELEFELD - GERMANY
+WASHINGTON STATE - USA
-I am located in Bielefeld/Germany and have been doing Unix consultancy
-work for the past 8 years throughout Germany and the rest of Europe. I
-can be contacted by email at <jpm@mens.de> or via phone at +49 521
-9225922 or telefax at +49 521 9225924.
+Jeff Clithero jeff@octopi.com APPGEN Vertical
+Interstellar Octopus, Ltd. Voice 360-379-1754 Accounting Solutions
+1829 Lincoln St. PgVm 800-893-9517 Integration Services
+Port Townsend, WA USA FAX 360-379-1753 Sales and Support
+
+We support SAMBA commercially.
+
+In the US/Canada we provide 800 number for our clients and can go
+onsite to customers in the Northwest US and Vancouver, BC areas.
------------------------------------------------------------------------------
+
+
+ASIA
+====
+
------------------------------------------------------------------------------
-CANBERRA - AUSTRALIA
+SEOUL - KOREA
+
+MultiMedia KOREA Inc, E-Mail : info@seoul.korea.co.kr
+Internet,WWW,Network Support Group, TEL : +82-02-597-1631
+ FAX : +82-02-521-4463
+SeoChoGu SeoChoDong 1537-6 WWW : http://www.korea.co.kr
+JungAng B/D #401
+SEOUL KOREA
+
+SAMBA Experience : SunOS, Solaris, Linux, SCO-Unix, Win95/NT/3.1
+------------------------------------------------------------------------------
+
+
+
+
+
+
+AUSTRALIA & NEW ZEALAND
+=======================
-Ben Elliston
-Faculty of Information Sciences and Engineering
-University of Canberra AUSTRALIA
-E-mail: ben@ise.canberra.edu.au (Uni)
------------------------------------------------------------------------------
+ADELAIDE - AUSTRALIA
+
+Richard Sharpe, sharpe@ns.aus.com
+NS Computer Software and Services P/L
+PO Box 86,
+Ingle Farm, SA 5098
+Australia
+
+Contact: Richard Sharpe
+ Ph: +61-8-281-0063 (08-281-0063) AH
+ FAX:+61-8-250-2080 (08-250-2080)
+
+Located in Adelaide, South Australia.
+Proficient with Digital UNIX, ULTRIX, SunOS, Linux, Win 95, WfWg, Win NT.
------------------------------------------------------------------------------
-PALERMO - ITALY
-Francesco Cardinale
-E-Mail: cardinal@palermo.italtel.it
-Samba experience: SVR3.2, SOLARIS, ULTRIX, LINUX <--> DOS LAN-MAN, WFW
------------------------------------------------------------------------------
+ADELAIDE - AUSTRALIA
+
+Loftus Computing Services
+191 Flinders Street
+Adelaide 5000
+South Australia
+
+Phone: +61 8 8407 7577
+Fax: +61 8 8407 7501
+Email: support@loftuscomp.com.au
+
+SAMBA Experience : SunOS, Solaris, SCO-Unix, Free BSD, Win95/NT/3.1
------------------------------------------------------------------------------
-SYDNEY - AUSTRALIA
-John Terpstra - Aquasoft (jht@aquasoft.com.au)
-Business: +612 524 4040
-Home: +612 540 3154
-Shoephone: +612 414 334422 (aka 0414 334422)
------------------------------------------------------------------------------
+BRISBANE - AUSTRALIA
+Brett Worth
+Select Computer Technology - Brisbane
+431 Logan Road
+Stones Corner QLD 4120
+E-Mail: brett@sct.com.au
------------------------------------------------------------------------------
-ONTARIO - CANADA
-Strata Software Limited, Kanata Ontario CANADA
-Tel: +1 (613) 591-1922 Fax: +1 (613) 591-3485
-Email: sales@strataware.com WWW: http://www.strataware.com/
+------------------------------------------------------------------------------
+CANBERRA - AUSTRALIA
-Strata Software Limited is a software development and consulting group
-specializing in data communications (TCP/IP and OSI), X.400, X.500 and
-LDAP, and X.509-based security. We have Samba experience with Windows NT,
-Windows 95, and Windows for Workgroups clients with Linux, Unixware
-(SVR4), and HP-UX servers.
+Paul Blackman (ictinus@lake.canberra.edu.au, Ph. 06 2012518) is
+available for consultation. Paul's Samba background is with
+Solaris 2.3/4 and WFWG/Win95 machines. Paul is also the maintainer
+of the SAMBA Web Pages.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+CANBERRA - AUSTRALIA
+
+Ben Elliston
+E-mail: bje@air.net.au
+Samba systems: Solaris 2.x, Linux, HP-UX.
------------------------------------------------------------------------------
-----------------------------------------------------------------------
-SYDNEY - AUSTRALIA
+MELBOURNE - AUSTRALIA
-We are a Unix & Windows developer with a consulting & support component.
-In business since 1981 with experience on Sun, hp, sgi, IBM rs6000 plus
-Windows, NT and Win95, Using Samba since September 94.
-CodeSmiths, 22 Darley Road, MANLY 2095 NSW; 977 1979; fax: 977 2116
-philm@esi.com.au (Australia; New South Wales; SYDNEY; North East)
+Michael Ciavarella
+Cybersoruce Pty Ltd.
+8/140 Queen Street
+Melbourne VIC 3000
+Phone: +61-3-9642-5997
+Fax: +61-3-9642-5998
+Email: mikec@cyber.com.au
+WWW: http://www.cyber.com.au
+
+Cybersource specialises in TCP/IP network integration and Open Systems
+administration. Cybersource is an Australian-owned and operated
+company, with clients including some of Australia's largest financial,
+petrochemical and state government organisations.
+-----------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+MELBOURNE - AUSTRALIA
+
+Company Name DARX Consulting
+Postal Address PO Box 12329
+ A'Beckett St PO
+ Melbourne 3000
+Area of Service Melb Metro and SE Suburbs
+Phone +61 3 9822 1216
+Email info@darx.com.au
+
+We provide setup and support of samba based systems as well as
+Novell/NT Systems.
-----------------------------------------------------------------------
------------------------------------------------------------------------------
-EDINBUGH - SCOTLAND
+N.T - AUSTRALIA
+
+Open Systems Network Support
+
+Server Platforms - Unix/Linux
+Client Platforms - Windows3.1/95/NT, Macintosh, Unix/Linux
-Charlie Hussey email charlie@edina.demon.co.uk
-Edina Software Limited tel 0131 657 1129
-4 James Street fax 0131 669 9092
-Edinburgh EH15 2DS
+--
+David Schroeder Darwin Network Services
+Ph/Fax (08) 8932 1156 PO Box 82383
+(Int) +61 8 8932 1156 Casuarina N.T
+Email: djsc@it.ntu.edu.au Australia 0811
+-----------------------------------------------------------------------
-SAMBA experience: SCO UNIX <=> WfWg
+------------------------------------------------------------------------------
+NEW SOUTH WALES - AUSTRALIA
+
+BITcom Telecommunications Phone: (02) 9747 0011
+P.O. Box 15 Int'l: +61 2 9747 0011
+Burwood NSW 2134 Australia Fax: (02) 9747 6918
+Contact: Craig Bevins Email: consult@bitcom.net.au
+
+BITcom is an open systems and networking consultancy. We have been
+doing Open Systems since long before the term was coined, a key staff
+member having participated in the IEEE working group which produced
+the POSIX standard for Un*x-like systems in 1988.
+
+We tend to have a Unix orientation (all flavours) but our focus is on
+getting the job done and we are happy to employ other technologies which
+fit. Heck, we even use and support Microsoft's products! Our areas
+of expertise cover general Unix consultancy, support for public domain
+and GNUish software, PC LAN -> Unix integration, Internet, WWW and local
+and wide-area network design, implementation and security. We have a
+collective masochistic streak and actually enjoy hacking on sendmail
+configuration. We are an AUSTEL-licenced telecommunications and data
+cabler and hold a NSW security industry licence.
+
+We know Windows NT, LANMAN, PC-NFS and others. We use, recommend and
+support Samba and have done so since 1994.
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-LONDON - ENGLAND
+PERTH - AUSTRALIA
-Mark H. Preston,
-Network Analyst, | Email : mpreston@sghms.ac.uk
-Computer Unit, | Tel : +44 (0)181 725-5434
-St. George's Hospital Med School, | Fax : +44 (0)181 725-3583
-London SW17 ORE. | WWW : http://www.sghms.ac.uk
+Bruce Cook - Synonet Corporation.
+E-mail: bcook@wantree.com.au
+Mobile: 015 999 330 (International +61 15 999 330)
+Experience: Samba on FreeBSD, Linux, Solaris (Sparc), Sunos-4
+ Microsoft networking using NT/NTAS, Win95, WFW311, DOS
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+PERTH - AUSTRALIA
+
+Geoff Allan Phone: +61 8 9325 9922
+Office Information Fax: +61 8 9325 9938
+Perth, Western Australia Mobile: 0412 903 659
+Email: geoffa@officeinfo.com.au
+
+Office Information has been in existence since 1991. We are (amongst
+other things) systems integrators with experts in Unix, Linux, Novell,
+NT and the other DOS & Windows platforms. We also have a number of
+Clients for whom we have installed and supported Samba.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+QUEENSLAND - AUSTRALIA
+
+Plugged In Software Pty Ltd
+PO Box 4130
+4/242 Hawken Drive
+St. Lucia South, Qld 4067
+Australia
+http://www.plugged.net.au
+info@plugged.net.au
++61 7 3876 7140
++61 7 3876 7142 (fax)
+Point of Contact: David Wood
+------------------------------------------------------------------------------
-Samba Experience:
-Server: Solaris 2.3 & 2.4, Irix 5.2 & 5.3
-Client: WinNT, Win95, WfWg, Win3.1, Ms-LanMan, DHCP support
+------------------------------------------------------------------------------
+SYDNEY - AUSTRALIA
+
+Philip Rhoades
+Pricom Pty Ltd
+http://www.pricom.com.au = http://203.12.131.20
+GPO Box 3411 Sydney NSW 2001 Australia
+Ph: +61:0411:185652
+Fax: +61:2:9959-3481
+E-mail: philr@mail.austasia.net
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+SYDNEY - AUSTRALIA
+
+John Terpstra - Aquasoft (jht@aquasoft.com.au)
+Business: +612 9524 4040
+Home: +612 9540 3154
+Mobile: +612 414 334422 (aka 0414 334422)
+Samba Experience: Member of Samba-Team. Long term contributor to Samba
+ Samba on BSD/OS, Solaris (Sparc & x86), ISC Unix, SCO Unix
+ NCR SVR4, Linux, UnixWare, IBM, HP, DEC, Others.
+ Training Instructor in Windows NT, wide area networking
+ over TCP/IP. Providing paid-for support for Public Domain
+ Software and Linux.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+SYDNEY - AUSTRALIA
+
+We are a Unix & Windows developer with a consulting & support component.
+In business since 1981 with experience on Sun, hp, sgi, IBM rs6000 plus
+Windows, NT and Win95, Using Samba since September 94.
+CodeSmiths, 22 Darley Road, MANLY 2095 NSW; 977 1979; fax: 977 2116
+philm@esi.com.au (Australia; New South Wales; SYDNEY; North East)
------------------------------------------------------------------------------
------------------------------------------------------------------------------
@@ -179,126 +1028,153 @@ info@eram.esi.com.au Voice:+61-2-9063377
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-CHANTILLY - USA
-
-Intelligent Decisions, Inc.
-ATTN: Richard Bullington
-14121 Parke Long Ct. #104
-Chantilly, VA 22021
-U.S.A.
-(703) 803-8070
-rbullington@intdec.com
-
-Samba experience: Linux, DEC ULTRIX <=> WFWG 3.11, Windows NT 3.5
-Specializing in World Wide Web related UNIX-to-PC connectivity.
+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
------------------------------------------------------------------------------
-------------------------------------------------------------------------------
-FORT COLLINS, CO - USA
-Granite Computing Solutions
-ATTN: Brian Grossman
-Box 270103
-Fort Collins, CO 80527-0103
-U.S.A.
-(970) 225-2370
-granite@fortnet.org
-Information services, including WfWG, NT, Apple <=> Unix interoperability.
-Our standard advertisement says:
-> Unix workstations, servers and custom systems <
->> WWW and Unix education <<
->>> Enterprise and departmental computing solutions <<<
->>> Backup & restore <<<
->> Software forensics <<
-> Data translation <
+
+CANADA
+======
+
------------------------------------------------------------------------------
+ONTARIO - CANADA
-----------------------------------------------------------
-Adelaide, Australia
+Strata Software Limited, Kanata Ontario CANADA
+Tel: +1 (613) 591-1922 Fax: +1 (613) 591-3485
+Email: sales@strataware.com WWW: http://www.strataware.com/
-NS Computer Software and Services P/L
-PO Box 86
-Ingle Farm
-SA 5098
+Strata Software Limited is a software development and consulting group
+specializing in data communications (TCP/IP and OSI), X.400, X.500 and
+LDAP, and X.509-based security. We have Samba experience with Windows NT,
+Windows 95, and Windows for Workgroups clients with Linux, Unixware
+(SVR4), and HP-UX servers.
+------------------------------------------------------------------------------
-Contact: Richard Sharpe
- Ph: +61-8-281-0063 (08-281-0063) AH
- FAX:+61-8-250-2080 (08-250-2080)
+------------------------------------------------------------------------------
+ONTARIO - CANADA
-Experience with: ULTRIX, Digital UNIX, SunOS, WfW 3.11, Win95, WNT 3.51
+WW Works Inc.
+3201 Maderna Road
+Burlington, Ontario
+Canada L7M 2W4
-----------------------------------------------------------
+Contact: Wade Weppler
+(905) 332-5844
+FAX: (905) 332-5535
-----------------------------------------------------------
-TECTONIC LIMITED
-WESTWOOD
-78 LOUGHBOROUGH ROAD
-QUORN
-LEICESTERSHIRE
-LE12 8DX
+Information Systems Sales and Consulting.
+Specializing in Turnkey Windows NT Network environments with emphasis on
+Legacy UNIX System integration using Samba.
+------------------------------------------------------------------------------
-TELEPHONE 01509-620922
-FAX 01509-620933
+------------------------------------------------------------------------------
+ONTARIO - CANADA
-CONTACT DAVID ROBINSON
+ Bilyana Aleksic |Email: baleksic@atitech.ca |
+ | |
+ATI Technologies Inc. |Phone: 905-882-2600 x3179 |
+75 Tiverton Court |Fax : 905-475-3930 |
+Unionville, Ontario | |
+Canada, L3R 9S3 | |
+------------------------------------------------------------------------------
-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.
+------------------------------------------------------------------------------
+ONTARIO - CANADA
-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
-----------------------------------------------------------
+Sound Software Ltd.
+20 Abelard Avenue
+Brampton, Ontario Canada
+905 452 0504
+sales@telly.org
+www.telly.org
-----------------------------------------------------------
-MIAMI, FL - USA
+Sound Software company is a Caldera Business Partner, providing support for
+Samba and other applications running under Caldera Linux.
+------------------------------------------------------------------------------
-Swaney & Associates, Inc.
-ATTN: Stephen Swaney
- 2543 Lincoln Avenue
- Miami, Florida 33133
- U.S.A
- (305) 860-0570
+------------------------------------------------------------------------------
+ONTARIO - CANADA
-Specializing in:
- High Availability system & networks
- UNIX to PC connectivity
- Market Data systems
- Messaging Systems (Sendmail & Microsoft Exchange)
-----------------------------------------------------------
+GenX Internet Laboratories Inc.
+20 Madison Ave.
+Toronto, Ontario, Canada
+M5R 1S2
+
+GenX Internet Labs is engaged in systems integration and
+the design and development of software for use over the
+internet and intranets.
+We install, support and can resolve most system/Samba problems
+on Linux. We are also an internet provider and use Samba to
+provide a remote office solution to our customers. This solution
+provides access to the shared resources on a corporate lan.
------------------------------------------------------------------------------
-NEW JERSEY - USA
-William J. Maggio
-LAN & Computer Integrators, Inc.
-242 Old New Brunswick Road Email: bmaggio@lci.com
-Suite 440 Voice: 908-981-1991
-Piscataway, NJ 08855 Fax : 908-981-1858
+------------------------------------------------------------------------------
+ONTARIO - CANADA
- Specializing in Internet connectivity and security, Sun integration and
- high speed, enterprise network design and deployment.
+FSC Internet
+The FSC Building
+188 Davenport Rd
+Toronto, Ontario
+Canada M5R 1J2
+
+(416) 921-4280
+fax (416) 966-2451
+
+info@fscinternet.com
+
+FSC Internet is one of Canada's largest UNIX and NT networking
+consulting firms. FSC's clients include numerous top-tier
+corporations (e.g. Mazda, Heinz), as well as mid-sized companies
+(e.g. the Vermont Telephone Company) and the public sector. FSC
+provides full consulting, implementation, support, and training
+services for all UNIX and NT network applications, including a
+special focus on internetworking (extensive Samba experience),
+security, high-performance Web applications, and Intranets. Please
+email us at info@fscinternet.com or call us at (416) 921-4280 for
+further information.
------------------------------------------------------------------------------
-FAREHAM - ENGLAND
+------------------------------------------------------------------------------
+ONTARIO - CANADA
-High Field Technology Ltd
-Little Park Farm Road, Segensworth West,
-Fareham, Hants PO15 5SJ, UK.
-sales@hft.co.uk tel +44 148 957 0111 fax +44 148 957 0555
+MIS Incorporated, London Ontario CANADA
+Tel: +1 (519) 673-3777 Fax: +1 (519) 673-4292
+Email: samba-support@netcontech.com
-Company skills: Real time hardware and software systems
+MIS Incorporated is a Microsoft Certified Solution Provider,
+and system support group specializing in applying Windows
+front ends to high end relational database servers. Samba
+support available on any unix platform in conjunction with
+WFW, Windows-NT, Win95, OS/2. Dial-in support
+nation-wide, or on-site anywhere in Ontario.
+------------------------------------------------------------------------------
-Samba experience: BSD/OS, Linux, LynxOS <==> WFWG, NT
+------------------------------------------------------------------------------
+OTTAWA - CANADA
+Russell McOrmond
+Open Systems Internet Consultant
+Serving individuals and organizations in the Ottawa (Ontario, Canada) area.
+voice: (613) 235-7584 FAX: (613) 230-1258
+russell@flora.org , http://www.flora.org/russell/work/
------------------------------------------------------------------------------
------------------------------------------------------------------------
+------------------------------------------------------------------------------
QUEBEC - CANADA
Dataden Computer Systems
@@ -316,61 +1192,708 @@ configuring and maintaining Samba for clients for 1-1/2 years now. We
have samba installations on Linx, SunOS and DEC OSF. Our biggest site
has 4 Suns and 3 Linux servers running Samba which are serving a network
of about 50 PC's running WFWg and Win95.
------------------------------------------------------------------------
+------------------------------------------------------------------------------
------------------------------------------------------------------------
-CALIFORNIA - USA
-Ron Halstead
-Open Systems Consulting
-3098-4 Lakemont Drive
-San Ramon, CA 94583 (San Francisco Bay Area)
-(510) 735-7529
-halstead@ix.netcom.com
------------------------------------------------------------------------
------------------------------------------------------------------------
-MELBOURNE - AUSTRALIA
-Michael Ciavarella
-Cybersoruce Pty Ltd.
-8/140 Queen Street
-Melbourne VIC 3000
-Phone: +61-3-9642-5997
-Fax: +61-3-9642-5998
-Email: mikec@cyber.com.au
-WWW: http://www.cyber.com.au
-Cybersource specialises in TCP/IP network integration and Open Systems
-administration. Cybersource is an Australian-owned and operated
-company, with clients including some of Australia's largest financial,
-petrochemical and state government organisations.
------------------------------------------------------------------------
------------------------------------------------------------------------
-SOUTHERN CALIFORNIA - USA
+
+EUROPE
+======
-Michael St. Laurent
-Serving Los Angeles and Orange Counties. Please contact via email.
-rowl@earthlink.net
-Michael St. Laurent
-Hartwell Corporation
------------------------------------------------------------------------------
-WASHINGTON DC METRO - USA
+BRUSSELS - BELGIUM
-Asset Software, Inc. has been running Samba since the 1.6 release on various
-platforms, including SunOS 4.x, Solaris 2.x, IRIX 4.x and 5.x, Linux 1.1x,
-1.2x, and 1.3x, and BSD UNIX 4.3 and above. We specialize in small office
-network solutions and provide services to enhance a small office's
-operations. Primarily a custom software operation, our vast knowledge of
-Windows, DOS, Unix, Windows NT, MacOS, and OS/2 enable us to provide quality
-technical assistance to the small office environment at a reasonable price.
-Our upcoming multi-mailbox mail client, IQ Mail, enables users with more
-than one mailbox to send and retrieve their mail from a single, consistent
-mail client running in Windows.
+Phidani Software SPRL
+Rue de l'autonomie, 1
+1070 Brussels
+Belgium
+Tel : +32 (2) 5220663
+Fax: +32 (2) 5220930
+
+We provide commercial support in Belgium to large organisations
+(eg: N.A.T.O., Unisys, E.C.C. ...)
+------------------------------------------------------------------------------
-David J. Fenwick Asset Software, Inc.
-President djf@assetsw.com
------------------------------------------------------------------------------
+SOFIA - BULGARIA
+
+National Laboratory for Computer Virology and SEA Ltd.
+
+We work mainly in the following fields:
+* Design and testing of antivirus and computer security related software
+ and hardware;
+* Data aquisition equipment
+* Network design and consulting.
+
+Samba is our most common network tool for the export of data collected on
+UNIX machines to PC clients, file services and simple client/server
+processing schemes.
+
+Samba experience: Linux, Ultrix, Solaris, AIX, RiscOS.
+
+Client experience: LanMan, WFW, Win 95, Win NT.
+
+Address:
+
+National Laboratory for Computer Virology BAS,
+Akad. G. Bonchev Str. bl.8,
+Sofia 1113,
+Bulgaria
+E-mail:sales@nlcv.acad.bg
+URL http://www.nlcv.acad.bg
+
+SEA Ltd,
+Akad G.Bonchev Str bl. 8, rm 225,
+Sofia 1113.
+Bulgaria
+E-mail:nmechkov@virbus.bg
+URL http://www.orgchm.acad.bg/~sealtd
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+PRAHA (PRAGUE) - CZECH
+
+AGC Praha,
+David Doubrava
+Sokolovska 141
+PRAHA 8
+180 00
+
+Tel: +42 (2) 6600 2202 Fax: +42 (2) 683 02 55
+Email: ddoubrava@agc.cz WWW: http://corwin.agc.cz/
+
+I have Samba experience with Windows NT,
+Windows 95, and Windows for Workgroups clients with Linux and HP-UX
+servers.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+CAMBRIDGE - ENGLAND. Will travel / provide support world-wide.
+
+Luke Kenneth Casson Leighton
+Phone: +44 1223 570 262 or 570 264 or Mobile +44 410 305 745
+lkcl@switchboard.net
+
+Configuration Experience:
+
+Clients: MSClient 3.0; WfWg; W95; NT 3.5 and 4.0 Workstation.
+Servers: Samba 1.9.15 and above (on-hands experience with Linux, SunOS
+4.1.3 and FreeBSD); NT 4.0 Server.
+
+Present Experience:
+
+Luke Leighton, a Samba Team member since October 1995, understands
+Browsing and WINS from having re-designed and re-written nmbd, and
+SMB/CIFS from attending the two CIFS conferences; by listening to
+discussions amongst the Samba Developers, and from answering user's
+queries on the Samba Digest.
+
+Support offered:
+
+If there are either areas of functionality that are missing or bugs
+that are affecting the performance of your company; if you require
+advice / training on the deployment and administration of SMB/CIFS
+Clients and Servers; if your company's policy only allows you to
+use samba if it is supported commercially... I am available for hire
+anywhere in the world.
+
+Long-term Project Aims:
+
+I would like to implement a CIFS proxying system suitable for Enterprise
+Networks (large Intranets: 10,000 to 150,000 simultaneous users) that is
+backwards compatible with all CIFS/SMB servers (MSClient 3.0 for DOS,
+through to NT 4.0).
+
+I would also like to implement an alternative SMB client for NT and 95.
+This would allow samba to offer secure and authenticated file and print
+access, to the extent that the laws of your country permit.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+CAMBRIDGE - ENGLAND
+
+Mark Ayliffe MBCS, Technical Consultant
+Protechnic Computers Limited http://www.prot.demon.co.uk
+7 Signet Court Tel +44 1223 314855
+Swann's Road Fax +44 1223 368168
+Cambridge CB5 8LA
+England
+
+
+Protechnic Computers Limited has experience of installing and
+maintaining Samba on the following platforms:
+
+HP/UX 9.0x, 10.1x & 10.2x
+DG/UX, Motorola and Intel
+Digital UNIX
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+CORNWALL - ENGLAND
+
+Starstream Communications Ltd
+Unit 9
+Moss Side Industrial Estate
+Callington
+Cornwall
+PL17 7DU
+United Kingdom
+
+Phone +44 1579 384072 Fax +44 1579 384267
+
+Contact : Terry Moore-Read terry@starstream.co.uk
+
+Website : http://www.ndu-star.demon.co.uk shortly moving to
+http://www.starstream.co.uk
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+FAREHAM - ENGLAND
+
+High Field Technology Ltd
+Little Park Farm Road, Segensworth West,
+Fareham, Hants PO15 5SJ, UK.
+sales@hft.co.uk tel +44 148 957 0111 fax +44 148 957 0555
+
+Company skills: Real time hardware and software systems
+
+Samba experience: BSD/OS, Linux, LynxOS <==> WFWG, NT
+
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+LEICESTERSHIRE - ENGLAND
+
+TECTONIC LIMITED
+WESTWOOD
+78 LOUGHBOROUGH ROAD
+QUORN
+LEICESTERSHIRE
+LE12 8DX
+
+TELEPHONE 01509-620922
+FAX 01509-620933
+
+Contact Samantha Hull
+
+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.
+Tectonic are in the process of creating the UK SAMBA USER GROUP and would
+appreciate any feedback or queries.
+
+For samba support, and for details on the UK SAMBA USER GROUP, please contact
+me at: sam@tectonic.demon.co.uk
+
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+LONDON - ENGLAND
+
+Mark H. Preston,
+Network Analyst, | Email : mpreston@sghms.ac.uk
+Computer Unit, | Tel : +44 (0)181 725-5434
+St. George's Hospital Med School, | Fax : +44 (0)181 725-3583
+London SW17 ORE. | WWW : http://www.sghms.ac.uk
+
+Samba Experience:
+Server: Solaris 2.3 & 2.4, Irix 5.2 & 5.3
+Client: WinNT, Win95, WfWg, Win3.1, Ms-LanMan, DHCP support
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+LONDON - ENGLAND
+
+Name: Paul Dunne
+Address: 30 Onslow Gardens
+ London
+ N10 3JU
+ UK
+Phone: +44 (0)181-374 8194
+Fax: None
+E-mail: paul@tiny1.demon.co.uk
+URL: http://www.tiny1.demon.co.uk
+
+Contact: Paul Dunne
+Type of support: E-mail and onsite.
+
+Expertise: Installing and troubleshooting Samba, on Linux and Win95.
+Sample prices: Basic rate £30/hour.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+READING - ENGLAND
+
+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:
+ Server platforms: Linux,SVR4,SVR3.2 & Sequent ptx
+ Clients: WfWg, W3.1, OS2 and MS-LanMan
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+PARIS - FRANCE
+
+Alcove
+7, rue Royer-Bendelé
+92230 Gennevilliers
+ Email: alcove@alcove.fr
+http://www.alcove.fr Phone number: +33 01 40 85 80 06
+ Fax number: +33 01 47 90 40 42
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+BERLIN - GERMANY
+
+Name: innominate
+ Multifunktionale Serverloesungen und IT-Dienstleistungen
+
+Address: Stresemannstraße 128, 10117 Berlin
+Country: Germany
+Phone: +49 30 202 90 477
+Fax: +49 30 202 90 249
+EMail: info@innominate.de
+Web: http://innominate.de
+
+Type of support: vor Ort, Email, Fernzugriff ueber Internet/ISDN,
+
+Wir verfuegen ueber umfangreiche Erfahrung mit Samba, vor allem
+in Intranetumgebungen. Neben Beratung, Dienstleistung
+und Schulung bieten wir auch individuell vorkonfigurierte
+Kommunikationsserver ("Lingo") auf der Basis von Linux an.
+Neben anderen Modulen (ISDN/Internet/Intranet/Email/Proxy
+u.a.) ist in Lingo ein Fileserver-Modul auf Samba-Basis inklusive
+einem mehrstufigen Firewallsystem enthalten.
+Außerdem verfuegt Lingo ueber eine grafische Administrations-
+oberflaeche, mit der z.B. das Hinzufuegen von neuen Benutzern
+von jedem Client per WWW-Browser moeglich ist.
+
+Prices: Komplettpreise fuer Lingo nach Vereinbarung
+ 120 DM/Stunde fuer Dienstleistung
+ Schulung nach Vereinbarung
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+BERLIN - GERMANY
+
+Ing. Buero Buehler
+Dipl.-Ing. Frank Buehler
+Paul-Krause-Str. 5
+14129 Berlin
+Germany
+
+Phone: +49/(0)177/825 33 80 Fax: +49/(0)30/803-3039
+mailto:fb@hydmech.fb12.TU-Berlin.de
+
+We install and maintain small to middle sized Linux-Windows
+networks within the Berlin area and are available for consulting and
+questions about networking, Linux, database systems and electronics.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+BIELEFELD - GERMANY
+
+I am located in Bielefeld/Germany and have been doing Unix consultancy
+work for the past 8 years throughout Germany and the rest of Europe. I
+can be contacted by email at <jpm@mens.de> or via phone at +49 521
+9225922 or telefax at +49 521 9225924.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+BIELEFELD - GERMANY
+
+Name : media engineering gmbh
+Address: Bleichstr. 77a , D-33607 Bielefeld
+Phone : +49-521-1365640
+Fax : +49-521-1365642
+eMail : info@media-eng.bielefeld.com
+URL : http://www.media-eng.bielefeld.com/
+Contact: Dipl.Ing. Hartmut Holzgraefe
+
+Type of support: phone, eMail, inhouse, remote administration
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+DREIEICH - GERMANY
+
+A. G. Schindler <schindler@az1.de>
+c/o Alpha Zero One Gmbh
+Frankfurter Str. 141
+D - 63303 Dreieich
+Germany
+
+AZ1 is a company of Value Added Resellers (VARs) of Digital Equipment
+Corp. products and solution provider for Industry Applications.
+
+We're providing commercial support for Samba running on DEC hardware
+under Digital Unix (R), Digital OpenVMS (R) and Linux.
+
+Contract based and hotline support available. Fast response on-site
+support coming soon for the Franfurt / Main area.
+
+Pathworks or WinNT to Samba migrators welcome !
+
+Please contact us via: schindler@az1.de
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+GOETTINGEN - GERMANY
+
+Service Network GmbH
+Hannah Vogt Str. 1
+37085 Goettingen
+Germany
+Phone: +49-551-507775
+Fax: +49-551-507776
+http://www.sernet.de/
+samba@sernet.de
+
+SerNet is a company doing LAN consulting and training. We offer
+Internet access for our customers. We have experience with many
+different kinds of Unix, especially Linux, as well as NetWare and NT.
+Volker Lendecke, one of our our founders and a Samba Team member,
+has gained a lot of SMB/CIFS and NetWare experience writing smbfs and
+ncpfs, the Linux kernel file systems that enable Linux to access
+Windows NT and other SMB/CIFS servers, and NetWare Servers.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+GREIFSWALD - GERMANY
+
+Mr. Frank Rautenberg, Mr. Heiko Boesel, Mr. Jan Holz
+UniCon Computersysteme GmbH
+Ziegelhof 20
+D-17489 Greifswald
+email: samba@unicon-gmbh.com
+www: http://www.unicon-gmbh.com
+
+We use Samba and we provide support for our customers.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+MUENCHEN - GERMANY
+
+CONSYS GmbH
+Landsberger Str. 402
+81241 München
+Germany
+Phone: +49-89-5808181
+Fax: +49-89-588776
+http://www.consys.de/
+mailto:samba@consys.de
+
+
+CONSYS is a software company. We have experience especially with SCO Unix
+and other Unix systems, as well as with Windows 95 and NT.
+We are a Premium Partner of SCO and know and have used samba for four years.
+Our engineers know a lot about the installation of SCO Unix.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+GREECE
+
+Yiorgos Adamopoulos
+Electrical and Computer Engineer
+email: adamo@InterWorks.org
+
+I can provide Samba support for the following operating systems throughout the
+whole of Greece: Windows 3.11/95/NT, Ultrix, HP-UX, NetBSD, OpenBSD, SunOS,
+Solaris, Linux, Irix.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+SZEGED - HUNGARY
+
+ Name: Geza Makay
+ Institute: Jozsef Attila University of Szeged
+ Mail: Bolyai Institute, Aradi vertanuk tere 1.
+ H-6720, Szeged, Hungary
+ Tel: (62) 454-091 (Hungary's code: 36)
+ Fax/Message: (62) 326-246 (Hungary's code: 36)
+ E-mail: makayg@math.u-szeged.hu
+ World Wide Web: http://www.math.u-szeged.hu/
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+MILANO - ITALY
+
+INFERENTIA S.p.A.
+Via Tacito 6
+20137 MILANO (MI)
+ITALY
+tel: +39 2 599281
+fax: +39 2 59928221
+contact: Consulting Division
+e-mail: consulting@inferentia.it
+www: http://www.inferentia.it
+
+INFERENTIA Consulting is available for establishing commercial support
+contracts on Samba integration with Microsoft Networks-based LANs.
+We can offer a solid experience with:
+- All flavours of Windows (Workgroups, 95, NT)
+- IBM AIX, Digital UNIX, Sun Solaris, Linux, HP/UX
+- geographically distributed networks with WAN links
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+ITALY
+
+InfoTecna di Cesana D. & C. s.n.c.
+Via Cesana e Villa, 29
+20046 Biassono (Mi)
+
+Tel: ++39 39 2324054
+Fax: ++39 39 2324054
+
+e-mail: infotecn@tin.it
+URL: http://space.tin.it/internet/dsbragio
+
+We provide Samba support along with generic Linux support. Specifically we
+have implemented a powerful Fax servicing system for Samba with Win95/NT
+clients. Details could be found at our URL, currently, only in Italian.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+ABANO TERME (PADOVA) - ITALY
+
+PROFUSO di Zanetti Giuseppe - Studio di Consulenza Informatica
+Abano Terme (PD) - ITALY
+profuso@profuso.com
+http://www.profuso.com/
+Phone: ++39 49 8059070 / ++39 348 2220811
+
+We provide all possible support for Linux, UNIX,
+development, security and system integration.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+PALERMO - ITALY
+
+Francesco Cardinale
+E-Mail: cardinal@palermo.italtel.it
+Samba experience: SVR3.2, SOLARIS, ULTRIX, LINUX <--> DOS LAN-MAN, WFW
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+PISA - ITALY
+
+I3 ICUBE s.r.l.
+Via Pascoli 8
+56125 PISA (PI)
+ITALY
+tel: 050/503202
+fax: 050/504617
+contact person: Marco Bizzarri
+e-mail: m.bizzarri@icube.it
+www: http://www.icube.it/
+
+Our company offers commercial support to integrate eterogenous networks.
+We can provide support for the following architectures:
+
+Windows:
+Windows for Workgroup
+Windows 95
+Windows NT
+
+Unix:
+Linux
+Solaris
+Digital Unix
+
+Macintosh
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+ROME - ITALY
+
+Company: Pantheon Srl
+ Via del Tritone 132
+ 00187 ROME - ITALY
+
+Phone/Fax: +39 6 47823666
+URL: http://www.pantheon.it
+
+Contact: Dario Centofanti <dario@pantheon.it>
+
+Pantheon provide support for SaMBa and other TCP/IP applications running
+under Linux. We are also an internet provider.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+VICENZA - ITALY
+
+Company: AVnet srl
+Address: via Fogazzaro, 2
+ 36015 SCHIO (VI)
+ ITALY
+phone: 0445/511445
+fax: 0445/511449
+contact: Giovanni Panozzo
+
+e-mail: samba@avnet.it
+
+
+AVnet provides consulting and support on all problems
+regarding unix-to-win networking. We operate as ISP and we
+offer in depth TCP/IP knowledge for lan, intranet and WANs.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+LUXEMBOURG - EUROPE
+
+E.C.C. sa
+11, Rue Bettlange
+L-9657 HARLANGE
+Grand-Duche de Luxembourg
+Tel. +352 93615 (from 09/97: +352 993615)
+Fax +352 93569 (from 09/97: +352 993569)
+oontact person: Stefaan A Eeckels
+email: Stefaan.Eeckels@ecc.lumail
+
+We're located in Luxembourg, and recently provided support
+for Samba at Eurostat (the European Commision), who are using
+Samba to integrate Windows NT workstations in their Solaris
+/ Windows3.1 network. All in all, things run rather smoothly now.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+DELFT - NETHERLANDS
+
+BitWizard B.V.
+van Bronckhorststraat 12
+2612 XV Delft
+The Netherlands
+Tel: +31-15-2137459
+Email: samba@BitWizard.nl
+http: http://www.bitwizard.nl/
+
+Specific activities:
+
+ - Linux support
+ - GNU software support
+ - Linux device driver writing
+ - Data recovery
+
+BitWizard supports freely distributable software,
+especially quality products like "Samba".
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+GRONINGEN - THE NETHERLANDS
+
+Company: Le Reseau netwerksystemen BV
+Address: Bieslookstraat 31
+City: Groningen
+Zip: NL-9731 HH
+Country: The Netherlands
+
+We already offer commercial support on Linux and other Unices. Together with
+an application house we have developed a office automation environment which
+heavily depends on Samba. This environment consists of a Linux application
+server which is also the Samba server. A NT server for standard office
+applications. A firewall for Internet connectivity. And a large number of
+DOS/Win3.x/W95 clients that connect to the different machines. User's home
+directories are mounted through Sambe.
+
+We also support other Unices like Solaris, SunOS, HP-UX, Digital Unix and
+AIX.
+
+Sincerely,
+
+Arthur Donkers
+Le Reseau
+
+email : arthur@reseau.nl
+phone : (+31) 595 552431
+URL http://www.reseau.nl
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+NIJMEGEN - THE NETHERLANDS
+
+Xtended Internet (http://www.xtdnet.nl/)
+
+Broerdijk 27 Postbus 170 Tel: 31-24-360 39 19
+6523 GM Nijmegen 6500 AD Nijmegen Fax: 31-24-360 19 99
+The Netherlands The Netherlands info@xtdnet.nl
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+UTRECHT - NETHERLANDS
+
+Van den Hout Creative Communications
+Koos van den Hout
+Email : koos@kzdoos.xs4all.nl
+Phone : +31-30-2871002
+Fax : +31-30-2817051
+Samba experience: Setup and configuration for Linux, Solaris, web
+publishing related usage.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+WROCLAW - POLAND
+
+Name: Sergiusz Pawlowicz
+Institute: Wroclaw University of Technology
+Mail: room 120A, Prusa 53/55, Wroclaw 50-370, Poland
+Tel: +48(71)206450
+Fax: +48(71)212448
+E-mail: ser@pwr.wroc.pl
+WWW: http://www.arch.pwr.wroc.pl/
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+VETLANDA - SWEDEN
+
+ IBS Industridata AB
+ Box 95
+ 574 21 VETLANDA
+ SWEDEN
+
+Phone: +46-383-16065
+Fax: +46-8-287905
+E-mail: samba@ibs.se
+http://www.id.ibs.se/ibsid
+
+We have offices in about 20 cities in Sweden and can provide commercial
+support for Samba.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+
+
+
+
+MIDDLE EAST
+===========
+
+------------------------------------------------------------------------------
+ISRAEL
+
+Sela Systems
+10 Ha'Kishon St.
+Bnei-Brak
+Israel 51203
+Phone: +972-3-6190999
+Fax: +972-3-6190992
+Email: info@sela.co.il
+
+We have been involved in Samba projects since 1995.
+We have several large-scale clients using Samba in their network
+and getting support from us. We also provide Unix/NT/Novell/Win95
+system and network services and solutions. Our company also provides
+courses and training in many aspects of systems and networking,
+including TCP/IP and Samba.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
diff --git a/docs/textdocs/Tracing.txt b/docs/textdocs/Tracing.txt
new file mode 100644
index 00000000000..2f25406b13c
--- /dev/null
+++ b/docs/textdocs/Tracing.txt
@@ -0,0 +1,96 @@
+!==
+!== Tracing.txt for Samba release 1.9.18alpha8 30 Oct 1997
+!==
+Contributor: Andrew Tridgell <samba-bugs@samba.anu.edu.au>
+Date: Old
+Status: Questionable
+
+Subject: How to trace samba system calls for debugging purposes
+=============================================================================
+
+This file describes how to do a system call trace on Samba to work out
+what its doing wrong. This is not for the faint of heart, but if you
+are reading this then you are probably desperate.
+
+Actually its not as bad as the the above makes it sound, just don't
+expect the output to be very pretty :-)
+
+Ok, down to business. One of the big advantages of unix systems is
+that they nearly all come with a system trace utility that allows you
+to monitor all system calls that a program is making. This is
+extremely using for debugging and also helps when trying to work out
+why something is slower than you expect. You can use system tracing
+without any special compilation options.
+
+The system trace utility is called different things on different
+systems. On Linux systems its called strace. Under SunOS 4 its called
+trace. Under SVR4 style systems (including solaris) its called
+truss. Under many BSD systems its called ktrace.
+
+The first thing you should do is read the man page for your native
+system call tracer. In the discussion below I'll assume its called
+strace as strace is the only portable system tracer (its available for
+free for many unix types) and its also got some of the nicest
+features.
+
+Next, try using strace on some simple commands. For example, "strace
+ls" or "strace echo hello".
+
+You'll notice that it produces a LOT of output. It is showing you the
+arguments to every system call that the program makes and the
+result. Very little happens in a program without a system call so you
+get lots of output. You'll also find that it produces a lot of
+"preamble" stuff showing the loading of shared libraries etc. Ignore
+this (unless its going wrong!)
+
+For example, the only line that really matters in the "strace echo
+hello" output is:
+
+write(1, "hello\n", 6) = 6
+
+all the rest is just setting up to run the program.
+
+Ok, now you're famialiar with strace. To use it on Samba you need to
+strace the running smbd daemon. The way I tend ot use it is to first
+login from my Windows PC to the Samba server, then use smbstatus to
+find which process ID that client is attached to, then as root I do
+"strace -p PID" to attach to that process. I normally redirect the
+stderr output from this command to a file for later perusal. For
+example, if I'm using a csh style shell:
+
+ strace -f -p 3872 >& strace.out
+
+or with a sh style shell:
+
+ strace -f -p 3872 > strace.out 2>&1
+
+Note the "-f" option. This is only available on some systems, and
+allows you to trace not just the current process, but any children it
+forks. This is great for finding printing problems caused by the
+"print command" being wrong.
+
+Once you are attached you then can do whatever it is on the client
+that is causing problems and you will capture all the system calls
+that smbd makes.
+
+So how do you interpret the results? Generally I search thorugh the
+output for strings that I know will appear when the problem
+happens. For example, if I am having touble with permissions on a file
+I would search for that files name in the strace output and look at
+the surrounding lines. Another trick is to match up file descriptor
+numbers and "follow" what happens to an open file until it is closed.
+
+Beyond this you will have to use your initiative. To give you an idea
+of wehat you are looking for here is a piece of strace output that
+shows that /dev/null is not world writeable, which causes printing to
+fail with Samba:
+
+[pid 28268] open("/dev/null", O_RDWR) = -1 EACCES (Permission denied)
+[pid 28268] open("/dev/null", O_WRONLY) = -1 EACCES (Permission denied)
+
+the process is trying to first open /dev/null read-write then
+read-only. Both fail. This means /dev/null has incorrect permissions.
+
+Have fun!
+
+(please send updates/fixes to this file to samba-bugs@samba.anu.edu.au)
diff --git a/docs/textdocs/UNIX-SMB.txt b/docs/textdocs/UNIX-SMB.txt
index b2c064215cf..06cb258bc5e 100644
--- a/docs/textdocs/UNIX-SMB.txt
+++ b/docs/textdocs/UNIX-SMB.txt
@@ -1,3 +1,12 @@
+!==
+!== UNIX-SMB.txt for Samba release 1.9.18alpha8 30 Oct 1997
+!==
+Contributor: Andrew Tridgell <samba-bugs@samba.anu.edu.au>
+Date: April 1995
+
+Subject: Discussion of NetBIOS in a Unix World
+============================================================================
+
This is a short document that describes some of the issues that
confront a SMB implementation on unix, and how Samba copes with
them. They may help people who are looking at unix<->PC
@@ -6,9 +15,6 @@ interoperability.
It was written to help out a person who was writing a paper on unix to
PC connectivity.
-Andrew Tridgell
-April 1995
-
Usernames
=========
@@ -85,19 +91,17 @@ passwords they are in trouble.
Samba can try to cope with this by either using the "password level"
option which causes Samba to try the offered password with up to the
specified number of case changes, or by using the "password server"
-option which allows Samba to do it's validation via another machine
+option which allows Samba to do its validation via another machine
(typically a WinNT server).
-Samba also doesn't support the password encryption method used by SMB
-clients. This is because the spec isn't sufficiently detailed for an
-implementation (although Jeremy Allison is working on it, to try and
-work it out). Also, there is a fundamental problem with what we
-understand so far in the algorithm, as it seems that the server would
-need to store somewhere on disk a reversibly encrypted (effectively
-plaintext) copy of the users password in order to use the
-algorithm. This goes against the unix policy that "even the super-user
-doesn't know your password" which comes from the use of a one-way hash
-function.
+Samba supports the password encryption method used by SMB
+clients. Note that the use of password encryption in Microsoft
+networking leads to password hashes that are "plain text equivalent".
+This means that it is *VERY* important to ensure that the Samba
+smbpasswd file containing these password hashes is only readable
+by the root user. See the documentation ENCRYPTION.txt for more
+details.
+
Locking
=======
@@ -127,7 +131,7 @@ The second major problem is the "opportunistic locking" requested by
some clients. If a client requests opportunistic locking then it is
asking the server to notify it if anyone else tries to do something on
the same file, at which time the client will say if it is willing to
-give up it's lock. Unix has no simple way of implementing
+give up its lock. Unix has no simple way of implementing
opportunistic locking, and currently Samba has no support for it.
Deny Modes
@@ -140,10 +144,12 @@ allowed by anyone else who tries to use the file at the same time. If
DENY_READ is placed on the file, for example, then any attempt to open
the file for reading should fail.
-Unix has no equivalent notion. To implement these Samba uses lock
+Unix has no equivalent notion. To implement this Samba uses either lock
files based on the files inode and placed in a separate lock
-directory. These are clumsy and consume processing and file resources,
-so they are optional and off by default.
+directory or a shared memory implementation. The lock file method
+is clumsy and consumes processing and file resources,
+the shared memory implementation is vastly prefered and is turned on
+by default for those systems that support it.
Trapdoor UIDs
=============
@@ -155,6 +161,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
============
@@ -216,5 +225,10 @@ this protocol level much easier.
There is also a problem with the SMB specications. SMB is a X/Open
spec, but the X/Open book is far from ideal, and fails to cover many
-important issues, leaving much to the imagination.
+important issues, leaving much to the imagination. Microsoft recently
+renamed the SMB protocol CIFS (Common Internet File System) and have
+published new specifications. These are far superior to the old
+X/Open documents but there are still undocumented calls and features.
+This specification is actively being worked on by a CIFS developers
+mailing list hosted by Microsft.
diff --git a/docs/textdocs/UNIX_INSTALL.txt b/docs/textdocs/UNIX_INSTALL.txt
new file mode 100644
index 00000000000..c0c0bd4fd4a
--- /dev/null
+++ b/docs/textdocs/UNIX_INSTALL.txt
@@ -0,0 +1,346 @@
+!==
+!== UNIX_INSTALL.txt for Samba release 1.9.18alpha8 30 Oct 1997
+!==
+Contributor: Andrew Tridgell <samba-bugs@samba.anu.edu.au>
+Date: Unknown
+Status: Current
+Updated: August 25, 1997
+
+Subject: 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
+
+Unfortunately, having said this, the man pages are sadly out of date and
+really need more effort to maintain them. Other sources of information
+are pointed to by the Samba web site, http://samba.anu.edu.au/samba.
+
+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:
+
+ workgroup = MYGROUP
+
+ [homes]
+ guest ok = no
+ read only = no
+
+which would allow connections by anyone with an account on the server,
+using either their login name or "homes" as the service name. (Note
+that I also set the workgroup that Samba is part of. See BROWSING.txt
+for defails)
+
+Note that "make install" will not install a smb.conf file. You need to
+create it yourself. You will also need to create the path you specify
+in the Makefile for the logs etc, such as /usr/local/samba.
+
+Make sure you put the smb.conf file in the same place you specified in
+the Makefile.
+
+STEP 4. Test your config file with testparm
+
+It's important that you test the validity of your smb.conf file using
+the testparm program. If testparm runs OK then it will list the loaded
+services. If not it will give an error message.
+
+Make sure it runs OK and that the services look resonable before
+proceeding.
+
+STEP 5. Starting the smbd and nmbd.
+
+You must choose to start smbd and nmbd either as daemons or from
+inetd. Don't try to do both! Either you can put them in inetd.conf
+and have them started on demand by inetd, or you can start them as
+daemons either from the command line or in /etc/rc.local. See the man
+pages for details on the command line options.
+
+The main advantage of starting smbd and nmbd as a daemon is that they
+will respond slightly more quickly to an initial connection
+request. This is, however, unlilkely to be a problem.
+
+Step 5a. Starting from inetd.conf
+
+NOTE; The following will be different if you use NIS or NIS+ to
+distributed services maps.
+
+Look at your /etc/services. What is defined at port 139/tcp. If
+nothing is defined then add a line like this:
+
+netbios-ssn 139/tcp
+
+similarly for 137/udp you should have an entry like:
+
+netbios-ns 137/udp
+
+Next edit your /etc/inetd.conf and add two lines something like this:
+
+netbios-ssn stream tcp nowait root /usr/local/samba/bin/smbd smbd
+netbios-ns dgram udp wait root /usr/local/samba/bin/nmbd nmbd
+
+The exact syntax of /etc/inetd.conf varies between unixes. Look at the
+other entries in inetd.conf for a guide.
+
+NOTE: Some unixes already have entries like netbios_ns (note the
+underscore) in /etc/services. You must either edit /etc/services or
+/etc/inetd.conf to make them consistant.
+
+NOTE: On many systems you may need to use the "interfaces" option in
+smb.conf to specify the IP address and netmask of your interfaces. Run
+ifconfig as root if you don't know what the broadcast is for your
+net. nmbd tries to determine it at run time, but fails on some
+unixes. See the section on "testing nmbd" for a method of finding if
+you need to do this.
+
+!!!WARNING!!! Many unixes only accept around 5 parameters on the
+command line in inetd. This means you shouldn't use spaces between the
+options and arguments, or you should use a script, and start the
+script from inetd.
+
+Restart inetd, perhaps just send it a HUP. If you have installed an
+earlier version of nmbd then you may need to kill nmbd as well.
+
+Step 5b. Alternative: starting it as a daemon
+
+To start the server as a daemon you should create a script something
+like this one, perhaps calling it "startsmb"
+
+#!/bin/sh
+/usr/local/samba/bin/smbd -D
+/usr/local/samba/bin/nmbd -D
+
+then make it executable with "chmod +x startsmb"
+
+You can then run startsmb by hand or execute it from /etc/rc.local
+
+To kill it send a kill signal to the processes nmbd and smbd.
+
+NOTE: If you use the SVR4 style init system then you may like to look
+at the examples/svr4-startup script to make Samba fit into that system.
+
+
+STEP 6. 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 7. 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 8. Try connecting from a dos/WfWg/Win95/NT/os-2 client. Try
+mounting disks. eg:
+
+net use d: \\servername\service
+
+Try printing. eg:
+
+net use lpt1: \\servername\spoolservice
+print filename
+
+Celebrate, or send me a bug report!
+
+WHAT IF IT DOESN'T WORK?
+========================
+
+If nothing works and you start to think "who wrote this pile of trash"
+then I suggest you do step 2 again (and again) till you calm down.
+
+Then you might read the file DIAGNOSIS.txt and the FAQ. If you are
+still stuck then try the mailing list or newsgroup (look in the README
+for details). Samba has been successfully installed at thousands of
+sites worldwide, so maybe someone else has hit your problem and has
+overcome it. You could also use the WWW site to scan back issues of
+the samba-digest.
+
+When you fix the problem PLEASE send me some updates to the
+documentation (or source code) so that the next person will find it
+easier.
+
+DIAGNOSING PROBLEMS
+===================
+
+If you have instalation problems then go to DIAGNOSIS.txt to try to
+find the problem.
+
+SCOPE IDs
+=========
+
+By default Samba uses a blank scope ID. This means all your windows
+boxes must also have a blank scope ID. If you really want to use a
+non-blank scope ID then you will need to use the -i <scope> option to
+nmbd, smbd, and smbclient. All your PCs will need to have the same
+setting for this to work. I do not recommend scope IDs.
+
+
+CHOOSING THE PROTOCOL LEVEL
+===========================
+
+The SMB protocol has many dialects. Currently Samba supports 5, called
+CORE, COREPLUS, LANMAN1, LANMAN2 and NT1.
+
+You can choose what maximum protocol 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 its 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. See also the FAST_SHARE_MODES option in the Makefile for a way
+to do full share modes very fast using shared memory (if your OS
+supports it).
+
+
+MAPPING USERNAMES
+=================
+
+If you have different usernames on the PCs and the unix server then
+take a look at the "username map" option. See the smb.conf man page
+for details.
+
+
+OTHER CHARACTER SETS
+====================
+
+If you have problems using filenames with accented characters in them
+(like the German, French or Scandinavian character sets) then I
+recommmend you look at the "valid chars" option in smb.conf and also
+take a look at the validchars package in the examples directory.
diff --git a/docs/textdocs/Win95.txt b/docs/textdocs/Win95.txt
new file mode 100644
index 00000000000..a04af0db6e3
--- /dev/null
+++ b/docs/textdocs/Win95.txt
@@ -0,0 +1,77 @@
+!==
+!== Win95.txt for Samba release 1.9.18alpha8 30 Oct 1997
+!==
+Copyright (C) 1997 - Samba-Team
+Contributed Date: August 20, 1997
+Last Update: August 20, 1997
+
+Subject: Windows 95 and Samba Interoperability
+===============================================================================
+
+Password Handling:
+------------------
+Microsoft periodically release updates to all their operating systems. Some of
+these are welcomed while others cause us to change the way we do things. Few
+people like change, particularly if the change is unexpected. The best advice
+always is to read the documentation provided BEFORE applying an update.
+
+One of the recent Win95 updates (VRDRUPD.EXE) disables plain text (also called
+clear text) password authentication. The effects of this updates are desirable
+where MS Windows NT is providing the password authentication service. This
+update is most undesirable where Samba must provide the authentication service
+unless Samba has been specifically configured to use encrypted passwords _AND_
+has been linked with the libdes library.
+
+If the above conditions have not been complied with, and you are using Samba,
+then Windows 95 clients will NOT be able to authenticate to a Samba server.
+
+To re-enable plain text password capabilities AFTER applying this update
+you must create a new value in the Windows 95 registry.
+
+Either foillow the following procedure or just double click on the
+file Win95_PlainPassword.reg for an easier way to do this.
+
+Procedure:
+1) Launch the Registry Editor as follows:
+ Click on: /Start/Run
+ Type "regedit" and press enter.
+
+2) Double click on: HKEY_LOCAL_MACHINE
+
+3) Locate the following Key:
+ /HKEY_LOCAL_MACHINE/System/CurrentControlSet/Services/VxD/VNETSUP
+
+4) From the menu bar select Edit/New/DWORD Value
+
+5) Rename the entry from "New Value #1" to:
+ EnablePlainTextPassword
+
+6) Press Enter, then double click on the new entry.
+ A dialog box will pop up and enable you to set a value.
+ You must set this value to 1.
+
+-------------------------------------------------------------------------------
+
+Windows 95 Updates:
+-------------------
+When using Windows 95 OEM SR2 the following updates are recommended where Samba
+is being used. Please NOTE that the above change will affect you once these
+updates have been installed.
+
+There are more updates than the ones mentioned here. You are referred to the
+Microsoft Web site for all currently available updates to your specific version
+of Windows 95.
+
+Kernel Update: KRNLUPD.EXE
+Ping Fix: PINGUPD.EXE
+RPC Update: RPCRTUPD.EXE
+TCP/IP Update: VIPUPD.EXE
+Redirector Update: VRDRUPD.EXE
+
+Also, if using MS OutLook it is desirable to install the OLEUPD.EXE fix. This
+fix may stop your machine from hanging for an extended period when exiting
+OutLook and you may also notice a significant speedup when accessing network
+neighborhood services.
+
+-------------------------------------------------------------------------------
+The above password information was provided by: Jochen Huppertz <jhu@nrh.de>
diff --git a/docs/textdocs/WinNT.txt b/docs/textdocs/WinNT.txt
index b57abb7742e..8dae9e18fc5 100644
--- a/docs/textdocs/WinNT.txt
+++ b/docs/textdocs/WinNT.txt
@@ -1,6 +1,20 @@
-There are some particular issues with Samba and Windows NT
+!==
+!== WinNT.txt for Samba release 1.9.18alpha8 30 Oct 1997
+!==
+Contributors: Various
+ Password Section - Copyright (C) 1997 - John H Terpstra
+ Printing Section - Copyright (C) 1997 - Matthew Harrell
+ Priting Info - Copyright (C) 1997 - Frank Varnavas
+Updated: October 16, 1997
+Status: Current
-=====================================================================
+Subject: Samba and Windows NT Password Handling
+=============================================================================
+
+There are some particular issues with Samba and Windows NT.
+
+Passwords:
+==========
One of the most annoying problems with WinNT is that NT refuses to
connect to a server that is in user level security mode and that
doesn't support password encryption unless it first prompts the user
@@ -8,21 +22,34 @@ for a password.
This means even if you have the same password on the NT box and the
Samba server you will get prompted for a password. Entering the
-correct password will get you connected.
+correct password will get you connected only if Windows NT can
+communicate with Samba using a compatible mode of password security.
+
+All versions of Windows NT prior to 4.0 Service Pack 3 could negotiate
+plain text (clear text) passwords. Windows NT 4.0 Service Pack 3 changed
+this default behaviour so it now will only handle encrypted passwords.
+The following registry entry change will re-enable clear text password
+handling:
+
+Run regedt32.exe and locate the hive key entry:
+HKEY_LOCAL_MACHINE\system\CurrentControlSet\Services\Rdr\Parameters\
+
+Add the following value:
+ EnablePlainTextPassword:REG_DWORD=1
+
+Alternatively, use the NT4_PlainPassword.reg file in this directory (either
+by double clicking on it, or run regedit.exe and select "Import Registry
+File" from the "Registry" Menu).
The other major ramification of this feature of NT is that it can't
browse a user level non-encrypted server unless it already has a
connection open. This is because there is no spot for a password
prompt in the browser window. It works fine if you already have a
drive mounted (for example, one auto mounted on startup).
-
-Samba should support encrypted passwords soon, which will solve this
-problem.
=====================================================================
-
-
-=====================================================================
+Printing:
+=========
When you mount a printer using the print manager in NT you may find
the following info from Matthew Harrell <harrell@leech.nrl.navy.mil>
useful:
@@ -49,8 +76,32 @@ time for the NT machine to get verification that the printer queue
actually exists.
I hope this helped in some way...
------------
+
=====================================================================
+Printing Info:
+--------------
+
+From: Frank Varnavas <varnavas@ny.ubs.com>
+Subject: RE: Samba as a print server
+
+When an NT client attempts to connect to a printer on a non-NT print
+server the attempt is failed with an error, something like:
+
+ "You have insufficient access to your computer to perform the
+ operation because a driver needs to be installed"
+
+This is because domain users must have 'Power User' status on the
+desktop to connect to printers on a non-NT print server.
+This error occurs regardless of whether the driver in question is
+already installed or not. What it really means is that the server is
+a non-NT server and the client does not have permission to create
+printers locally. Apparently when a connection to a non-NT print
+server is made the printer is defined locally. Such an action can be
+performed by either a local administrator or a Power User.
+Unfortunately there is no way to limit the powers of a Power User, nor
+is there any way to grant the Printer Creation right to another group.
+This permission policy is documented in PSS database WINNT, ID Q101874
+Frank Varnavas (varnavas@ny.ubs.com)
diff --git a/docs/textdocs/cifsntdomain.txt b/docs/textdocs/cifsntdomain.txt
new file mode 100644
index 00000000000..f69703e9d35
--- /dev/null
+++ b/docs/textdocs/cifsntdomain.txt
@@ -0,0 +1,1416 @@
+!==
+!== cifsntdomain.txt for Samba release 1.9.18alpha8 30 Oct 1997
+!==
+NT Domain Authentication
+------------------------
+
+Authors: - Luke Kenneth Casson Leighton (lkcl@switchboard.net)
+-------- - Paul Ashton (paul@argo.demon.co.uk)
+ - Duncan Stansfield (duncans@sco.com)
+
+ Copyright (C) 1997 Luke Kenneth Casson Leighton
+ Copyright (C) 1997 Paul Ashton
+ Copyright (C) 1997 Duncan Stansfield
+
+Version: 0.020 (26oct97)
+--------
+
+Distribution: Unlimited and encouraged, for the purposes of implementation
+------------- and comments. Feedback welcomed by the authors.
+
+Liability: Absolutely none accepted implicitly or explicitly, direct
+---------- or consequentially, for use, abuse, misuse, lack of use,
+ misunderstandings, mistakes, omissions, mis-information for
+ anything in or not in, related to or not related to, or
+ pertaining to this document, or anything else that a lawyer
+ can think of or not think of.
+
+Warning: Please bear in mind that an incorrect implementation of this
+-------- protocol can cause NT workstation to fail irrevocably, for
+ which the authors accept no liability (see above). Please
+ contact your vendor if you have any problems.
+
+Sources: - Packet Traces from Netmonitor (Service Pack 1 and above)
+-------- - Paul Ashton and Luke Leighton's other "NT Domain" doc.
+ - CIFS documentation - cifs6.txt
+ - CIFS documentation - cifsrap2.txt
+
+Original: http://mailhost.cb1.com/~lkcl/cifsntdomain.txt.
+--------- (Controlled copy maintained by lkcl@switchboard.net)
+
+Credits: - Paul Ashton: loads of work with Net Monitor;
+-------- understanding the NT authentication system;
+ reference implementation of the NT domain support on which
+ this document is originally based.
+ - Duncan Stansfield: low-level analysis of MSRPC Pipes.
+ - Linus Nordberg: producing c-code from Paul's crypto spec.
+ - Windows Sourcer development team
+
+
+Contents:
+---------
+
+ 1) Introduction
+
+ 2) Structures and notes
+
+ 2.1) Notes
+ 2.3) Enumerations
+ 2.3) Structures
+
+ 3) Transact Named Pipe Header/Tail
+
+ 3.1) MSRPC Pipes
+ 3.2) Header
+ 3.3) Tail
+
+ 4) NTLSA Transact Named Pipe
+
+ 4.1) LSA Open Policy
+ 4.2) LSA Query Info Policy
+ 4.3) LSA Enumerate Trusted Domains
+ 4.4) LSA Open Secret
+ 4.5) LSA Close
+ 4.6) LSA Lookup SIDS
+ 4.7) LSA Lookup Names
+
+ 5) NETLOGON rpc Transact Named Pipe
+
+ 5.1) LSA Request Challenge
+ 5.2) LSA Authenticate 2
+ 5.3) LSA Server Password Set
+ 5.4) LSA SAM Logon
+ 5.5) LSA SAM Logoff
+
+ 6) \\MAILSLOT\NET\NTLOGON
+
+ 6.1) Query for PDC
+ 6.2) SAM Logon
+
+ 7) SRVSVC Transact Named Pipe
+
+ 7.1) Net Share Enum
+ 7.2) Net Server Get Info
+
+
+Appendix:
+---------
+
+ A1) Cryptographic side of NT Domain Authentication
+
+ A1.1) Definitions
+ A1.2) Protocol
+ A1.3) Comments
+
+ A2) SIDs and RIDs
+
+ A2.1) Well-known SIDs
+
+ A2.1.1) Universal well-known SIDs
+ A2.1.2) NT well-known SIDs
+
+ A2.2) Well-known RIDS
+
+ A2.2.1) Well-known RID users
+ A2.2.2) Well-known RID groups
+ A2.2.3) Well-known RID aliases
+
+
+
+1) Introduction
+---------------
+
+
+This document contains information to provide an NT workstation with login
+services, without the need for an NT server.
+
+It should be possible to select a domain instead of a workgroup (in the NT
+workstation's TCP/IP settings) and after the obligatory reboot, type in a
+username, password, select a domain and successfully log in. I would
+appreciate any feedback on your experiences with this process, and any
+comments, corrections and additions to this document.
+
+
+The packets described here can be easily derived from (and are probably
+better understood using) Netmon.exe. You will need to use the version
+of Netmon that matches your system, in order to correctly decode the
+NETLOGON, lsarpc and srvsvc Transact pipes. This document is derived from
+NT Service Pack 1 and its corresponding version of Netmon. It is intended
+that an annotated packet trace be produced, which will likely be more
+instructive than this document.
+
+Also needed, to fully implement NT Domain Login Services, is the
+document describing the cryptographic part of the NT authentication.
+This document is available from comp.protocols.smb; from the ntsecurity.net
+digest and from the samba digest, amongst other sources.
+
+A copy is available from:
+
+http://ntbugtraq.rc.on.ca/SCRIPTS/WA.EXE?A2=ind9708&L=ntbugtraq&O=A&P=2935
+http://mailhost.cb1.com/~lkcl/crypt.html
+
+
+A c-code implementation, provided by Linus Nordberg <linus@incolumitas.se>
+of this protocol is available from:
+
+http://samba.anu.edu.au/cgi-bin/mfs/01/digest/1997/97aug/0391.html
+http://mailhost.cb1.com/~lkcl/crypt.txt
+
+
+Also used to provide debugging information is the Check Build version of
+NT workstation, and enabling full debugging in NETLOGON. This is
+achieved by setting the following REG_SZ registry key to 0x1ffffff:
+
+HKLM\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters
+
+- Incorrect direct editing of the registry can cause your machine to fail.
+ Then again, so can incorrect implementation of this protocol.
+ See "Liability:" above.
+
+
+Bear in mind that each packet over-the-wire will have its origin in an
+API call. Therefore, there are likely to be structures, enumerations
+and defines that are usefully documented elsewhere.
+
+
+This document is by no means complete or authoritative. Missing sections
+include, but are not limited to:
+
+- the meaning (and use by NT) of SIDs and RIDs.
+
+- mappings of RIDs to usernames (and vice-versa).
+
+- what a User ID is and what a Group ID is.
+
+- the exact meaning/definition of various magic constants or enumerations.
+
+- the reply error code and use of that error code when a workstation
+ becomes a member of a domain (to be described later). Failure to
+ return this error code will make the workstation report that it is
+ already a member of the domain.
+
+- the cryptographic side of the NetrServerPasswordSet command, which would
+ allow the workstation to change its password. This password is used to
+ generate the long-term session key. [It is possible to reject this
+ command, and keep the default workstation password].
+
+
+2) Notes and Structures
+-----------------------
+
+
+2.1) Notes
+----------
+
+- In the SMB Transact pipes, some "Structures", described here, appear to be
+ 4-byte aligned with the SMB header, at their start. Exactly which
+ "Structures" need aligning is not precisely known or documented.
+
+- In the UDP NTLOGON Mailslots, some "Structures", described here, appear to be
+ 2-byte aligned with the start of the mailslot, at their start.
+
+- Domain SID is of the format S-revision-version-auth1-auth2...authN.
+ e.g S-1-5-123-456-789-123-456. the 5 could be a sub-revision.
+
+- any undocumented buffer pointers must be non-zero if the string buffer it
+ refers to contains characters. exactly what value they should be is unknown.
+ 0x0000 0002 seems to do the trick to indicate that the buffer exists. a
+ NULL buffer pointer indicates that the string buffer is of zero length.
+ If the buffer pointer is NULL, then it is suspected that the structure it
+ refers to is NOT put into (or taken out of) the SMB data stream. This is
+ empirically derived from, for example, the LSA SAM Logon response packet,
+ where if the buffer pointer is NULL, the user information is not inserted
+ into the data stream. Exactly what happens with an array of buffer pointers
+ is not known, although an educated guess can be made.
+
+- an array of structures (a container) appears to have a count and a pointer.
+ if the count is zero, the pointer is also zero. no further data is put
+ into or taken out of the SMB data stream. if the count is non-zero, then
+ the pointer is also non-zero. immediately following the pointer is the
+ count again, followed by an array of container sub-structures. the count
+ appears a third time after the last sub-structure.
+
+
+2.2) Enumerations
+-----------------
+
+- MSRPC Header type. command number in the msrpc packet header
+
+ MSRPC_Request: 0x00
+ MSRPC_Response: 0x02
+ MSRPC_Bind: 0x0B
+ MSRPC_BindAck: 0x0C
+
+- MSRPC Packet info. the meaning of these flags is undocumented
+
+ FirstFrag: 0x01
+ LastFrag: 0x02
+ NotaFrag: 0x04
+ RecRespond: 0x08
+ NoMultiplex: 0x10
+ NotForIdemp: 0x20
+ NotforBcast: 0x40
+ NoUuid: 0x80
+
+
+2.3) Structures
+---------------
+
+- sizeof VOID* is 32 bits.
+
+- sizeof char is 8 bits.
+
+- UTIME is 32 bits, indicating time in seconds since 01jan1970. documented
+ in cifs6.txt (section 3.5 page, page 30).
+
+- NTTIME is 64 bits. documented in cifs6.txt (section 3.5 page, page 30).
+
+- DOM_SID (domain SID structure) :
+
+ UINT32 num of sub-authorities in domain SID
+ UINT8 SID revision number
+ UINT8 num of sub-authorities in domain SID
+ UINT8[6] 6 bytes for domain SID - Identifier Authority.
+ UINT16[n_subauths] domain SID sub-authorities
+
+ Note: the domain SID is documented elsewhere.
+
+- STR (string) :
+
+ char[] null-terminated string of ascii characters.
+
+- UNIHDR (unicode string header) :
+
+ UINT16 length of unicode string
+ UINT16 max length of unicode string
+ UINT32 4 - undocumented.
+
+- UNIHDR2 (unicode string header plus buffer pointer) :
+
+ UNIHDR unicode string header
+ VOID* undocumented buffer pointer
+
+- UNISTR (unicode string) :
+
+ UINT16[] null-terminated string of unicode characters.
+
+- NAME (length-indicated unicode string) :
+
+ UINT32 length of unicode string
+ UINT16[] null-terminated string of unicode characters.
+
+- UNISTR2 (aligned unicode string) :
+
+ UINT8[] padding to get unicode string 4-byte aligned
+ with the start of the SMB header.
+ UINT32 max length of unicode string
+ UINT32 0 - undocumented
+ UINT32 length of unicode string
+ UINT16[] string of uncode characters.
+
+- OBJ_ATTR (object attributes) :
+
+ UINT32 0x18 - length (in bytes) including the length field.
+ VOID* 0 - root directory (pointer)
+ VOID* 0 - object name (pointer)
+ UINT32 0 - attributes (undocumented)
+ VOID* 0 - security descriptior (pointer)
+ UINT32 0 - security quality of service
+
+- POL_HND (LSA policy handle) :
+
+ char[20] policy handle
+
+- DOM_SID2 (domain SID structure, SIDS stored in unicode) :
+
+ UINT32 5 - SID type
+ UINT32 0 - undocumented
+ UNIHDR2 domain SID unicode string header
+ UNISTR domain SID unicode string
+
+ Note: there is a conflict between the unicode string header and the
+ unicode string itself as to which to use to indicate string
+ length. this will need to be resolved.
+
+ Note: the SID type indicates, for example, an alias; a well-known group etc.
+ this is documented somewhere.
+
+- DOM_RID (domain RID structure) :
+
+ UINT32 5 - well-known SID. 1 - user SID (see ShowACLs)
+ UINT32 5 - undocumented
+ UINT32 domain RID
+ UINT32 0 - domain index out of above reference domains
+
+
+- LOG_INFO (server, account, client structure) :
+
+ Note: logon server name starts with two '\' characters and is upper case.
+
+ Note: account name is the logon client name from the LSA Request Challenge,
+ with a $ on the end of it, in upper case.
+
+ VOID* undocumented buffer pointer
+ UNISTR2 logon server unicode string
+ UNISTR2 account name unicode string
+ UINT16 sec_chan - security channel type
+ UNISTR2 logon client machine unicode string
+
+- CLNT_SRV (server, client names structure) :
+
+ Note: logon server name starts with two '\' characters and is upper case.
+
+ VOID* undocumented buffer pointer
+ UNISTR2 logon server unicode string
+ VOID* undocumented buffer pointer
+ UNISTR2 logon client machine unicode string
+
+- CREDS (credentials + time stamp)
+
+ char[8] credentials
+ UTIME time stamp
+
+- CLNT_INFO2 (server, client structure, client credentials) :
+
+ Note: whenever this structure appears in a request, you must take a copy
+ of the client-calculated credentials received, because they will be
+ used in subsequent credential checks. the presumed intention is to
+ maintain an authenticated request/response trail.
+
+ CLNT_SRV client and server names
+ UINT8[] ???? padding, for 4-byte alignment with SMB header.
+ VOID* pointer to client credentials.
+ CREDS client-calculated credentials + client time
+
+- CLNT_INFO (server, account, client structure, client credentials) :
+
+ Note: whenever this structure appears in a request, you must take a copy
+ of the client-calculated credentials received, because they will be
+ used in subsequent credential checks. the presumed intention is to
+ maintain an authenticated request/response trail.
+
+ LOG_INFO logon account info
+ CREDS client-calculated credentials + client time
+
+- ID_INFO_1 (id info structure, auth level 1) :
+
+ VOID* ptr_id_info_1
+ UNIHDR domain name unicode header
+ UINT32 param control
+ UINT64 logon ID
+ UNIHDR user name unicode header
+ UNIHDR workgroup name unicode header
+ char[16] rc4 LM OWF Password
+ char[16] rc4 NT OWF Password
+ UNISTR2 domain name unicode string
+ UNISTR2 user name unicode string
+ UNISTR2 workstation name unicode string
+
+- SAM_INFO (sam logon/logoff id info structure) :
+
+ Note: presumably, the return credentials is supposedly for the server to
+ verify that the credential chain hasn't been compromised.
+
+ CLNT_INFO2 client identification/authentication info
+ VOID* pointer to return credentials.
+ CRED return credentials - ignored.
+ UINT16 logon level
+ UINT16 switch value
+
+ switch (switch_value)
+ case 1:
+ {
+ ID_INFO_1 id_info_1;
+ }
+
+- GID (group id info) :
+
+ UINT32 group id
+ UINT32 user attributes (only used by NT 3.1 and 3.51)
+
+- DOM_REF (domain reference info) :
+
+ VOID* undocumented buffer pointer.
+ UINT32 num referenced domains?
+ VOID* undocumented domain name buffer pointer.
+ UINT32 32 - max number of entries
+ UINT32 4 - num referenced domains?
+
+ UNIHDR2 domain name unicode string header
+ UNIHDR2[num_ref_doms-1] referenced domain unicode string headers
+
+ UNISTR domain name unicode string
+ DOM_SID[num_ref_doms] referenced domain SIDs
+
+- DOM_INFO (domain info, levels 3 and 5 are the same)) :
+
+ UINT8[] ??? padding to get 4-byte alignment with start of SMB header
+ UINT16 domain name string length * 2
+ UINT16 domain name string length * 2
+ VOID* undocumented domain name string buffer pointer
+ VOID* undocumented domain SID string buffer pointer
+ UNISTR2 domain name (unicode string)
+ DOM_SID domain SID
+
+- USER_INFO (user logon info) :
+
+ Note: it would be nice to know what the 16 byte user session key is for.
+
+ NTTIME logon time
+ NTTIME logoff time
+ NTTIME kickoff time
+ NTTIME password last set time
+ NTTIME password can change time
+ NTTIME password must change time
+
+ UNIHDR username unicode string header
+ UNIHDR user's full name unicode string header
+ UNIHDR logon script unicode string header
+ UNIHDR profile path unicode string header
+ UNIHDR home directory unicode string header
+ UNIHDR home directory drive unicode string header
+
+ UINT16 logon count
+ UINT16 bad password count
+
+ UINT32 User ID
+ UINT32 Group ID
+ UINT32 num groups
+ VOID* undocumented buffer pointer to groups.
+
+ UINT32 user flags
+ char[16] user session key
+
+ UNIHDR logon server unicode string header
+ UNIHDR logon domain unicode string header
+ VOID* undocumented logon domain id pointer
+ char[40] 40 undocumented padding bytes. future expansion?
+
+ UINT32 0 - num_other_sids?
+ VOID* NULL - undocumented pointer to other domain SIDs.
+
+ UNISTR2 username unicode string
+ UNISTR2 user's full name unicode string
+ UNISTR2 logon script unicode string
+ UNISTR2 profile path unicode string
+ UNISTR2 home directory unicode string
+ UNISTR2 home directory drive unicode string
+
+ UINT32 num groups
+ GID[num_groups] group info
+
+ UNISTR2 logon server unicode string
+ UNISTR2 logon domain unicode string
+
+ DOM_SID domain SID
+ DOM_SID[num_sids] other domain SIDs?
+
+- SH_INFO_1_PTR (pointers to level 1 share info strings):
+
+Note: see cifsrap2.txt section5, page 10.
+
+ 0 for shi1_type indicates a Disk.
+ 1 for shi1_type indicates a Print Queue.
+ 2 for shi1_type indicates a Device.
+ 3 for shi1_type indicates an IPC pipe.
+ 0x8000 0000 (top bit set in shi1_type) indicates a hidden share.
+
+ VOID* shi1_netname - pointer to net name
+ UINT32 shi1_type - type of share. 0 - undocumented.
+ VOID* shi1_remark - pointer to comment.
+
+- SH_INFO_1_STR (level 1 share info strings) :
+
+ UNISTR2 shi1_netname - unicode string of net name
+ UNISTR2 shi1_remark - unicode string of comment.
+
+- SHARE_INFO_1_CTR :
+
+ share container with 0 entries:
+
+ UINT32 0 - EntriesRead
+ UINT32 0 - Buffer
+
+ share container with > 0 entries:
+
+ UINT32 EntriesRead
+ UINT32 non-zero - Buffer
+ UINT32 EntriesRead
+
+ SH_INFO_1_PTR[EntriesRead] share entry pointers
+ SH_INFO_1_STR[EntriesRead] share entry strings
+
+ UINT8[] padding to get unicode string 4-byte
+ aligned with start of the SMB header.
+ UINT32 EntriesRead
+ UINT32 0 - padding
+
+- SERVER_INFO_101 :
+
+Note: see cifs6.txt section 6.4 - the fields described therein will be
+ of assistance here. for example, the type listed below is the
+ same as fServerType, which is described in 6.4.1.
+
+ SV_TYPE_WORKSTATION 0x00000001 All workstations
+ SV_TYPE_SERVER 0x00000002 All servers
+ SV_TYPE_SQLSERVER 0x00000004 Any server running with SQL
+ server
+ SV_TYPE_DOMAIN_CTRL 0x00000008 Primary domain controller
+ SV_TYPE_DOMAIN_BAKCTRL 0x00000010 Backup domain controller
+ SV_TYPE_TIME_SOURCE 0x00000020 Server running the timesource
+ service
+ SV_TYPE_AFP 0x00000040 Apple File Protocol servers
+ SV_TYPE_NOVELL 0x00000080 Novell servers
+ SV_TYPE_DOMAIN_MEMBER 0x00000100 Domain Member
+ SV_TYPE_PRINTQ_SERVER 0x00000200 Server sharing print queue
+ SV_TYPE_DIALIN_SERVER 0x00000400 Server running dialin service.
+ SV_TYPE_XENIX_SERVER 0x00000800 Xenix server
+ SV_TYPE_NT 0x00001000 NT server
+ SV_TYPE_WFW 0x00002000 Server running Windows for
+
+ SV_TYPE_SERVER_NT 0x00008000 Windows NT non DC server
+ SV_TYPE_POTENTIAL_BROWSER 0x00010000 Server that can run the browser
+ service
+ SV_TYPE_BACKUP_BROWSER 0x00020000 Backup browser server
+ SV_TYPE_MASTER_BROWSER 0x00040000 Master browser server
+ SV_TYPE_DOMAIN_MASTER 0x00080000 Domain Master Browser server
+ SV_TYPE_LOCAL_LIST_ONLY 0x40000000 Enumerate only entries marked
+ "local"
+ SV_TYPE_DOMAIN_ENUM 0x80000000 Enumerate Domains. The pszServer
+ and pszDomain parameters must be
+ NULL.
+
+ UINT32 500 - platform_id
+ VOID* pointer to name
+ UINT32 5 - major version
+ UINT32 4 - minor version
+ UINT32 type (SV_TYPE_... bit field)
+ VOID* pointer to comment
+
+ UNISTR2 sv101_name - unicode string of server name
+ UNISTR2 sv_101_comment - unicode string of server comment.
+
+ UINT8[] padding to get unicode string 4-byte
+ aligned with start of the SMB header.
+
+
+
+3) MSRPC over Transact Named Pipe
+---------------------------------
+
+For details on the SMB Transact Named Pipe, see cifs6.txt
+
+
+3.1) MSRPC Pipes
+----------------
+
+The MSRPC is conducted over an SMB Transact Pipe with a name of "\PIPE\".
+You must first obtain a 16 bit file handle, by sending a SMBopenX with the
+pipe name "\PIPE\srvsvc" for example. You can then perform an SMB Trans,
+and must carry out an SMBclose on the file handle once you are finished.
+
+Trans Requests must be sent with two setup UINT16s, no UINT16 params (none
+known about), and UINT8 data parameters sufficient to contain the MSRPC
+header, and MSRPC data. The first UINT16 setup parameter must be 0x26. The
+second UINT16 parameter must be the file handle for the pipe, obtained above.
+
+MSRPC Responses are sent as response data inside standard SMB Trans
+responses, with the MSRPC Header, MSRPC Data and MSRPC tail.
+
+[section on MSRPC Bind and BindAck to be added once they are understood].
+
+It is suspected that the Trans Requests will need to be at least 2-byte
+aligned (probably 4-byte). This is standard practice for SMBs. It is also
+independent of the observed 4-byte alignments with the start of the MSRPC
+header, including the 4-byte alignment between the MSRPC header and the
+MSRPC data.
+
+
+3.2) Header
+-----------
+
+[section to be rewritten, following receipt of work by Duncan Stansfield]
+
+
+Interesting note: if you set packed data representation to 0x0100 0000
+then all 4-byte and 2-byte word ordering is turned around!
+
+The start of each of the NTLSA and NETLOGON named pipes begins with:
+
+00 UINT8 5 - RPC major version
+01 UINT8 0 - RPC minor version
+02 UINT8 2 - RPC response packet
+03 UINT8 3 - (FirstFrag bit-wise or with LastFrag)
+04 UINT32 0x1000 0000 - packed data representation
+08 UINT16 fragment length - data size (bytes) inc header and tail.
+0A UINT16 0 - authentication length
+0C UINT32 call identifier. matches 12th UINT32 of incoming RPC data.
+10 UINT32 allocation hint - data size (bytes) minus header and tail.
+14 UINT16 0 - presentation context identifier
+16 UINT8 0 - cancel count
+17 UINT8 in replies: 0 - reserved; in requests: opnum - see #defines.
+18 ...... start of data (goes on for allocation_hint bytes)
+
+
+MsrpcPacket for both request and response
+{
+
+ UINT8 versionmaj # reply same as request (0x05)
+ UINT8 versionmin # reply same as request (0x00)
+ UINT8 type # one of the MSRPC_Type enums
+ UINT8 flags # reply same as request (0x00 for Bind, 0x03 for Request)
+ UINT32 representation # reply same as request (0x00000010)
+ UINT16 fraglength # the length of the data section of the SMB trans packet
+ UINT16 authlength
+ UINT32 callid # call identifier. (e.g. 0x00149594)
+
+ * stub USE TvPacket # the remainder of the packet depending on the "type"
+}
+
+
+# the interfaces are numbered. as yet I haven't seen more than one interface
+# used on the same pipe name
+# srvsvc
+# abstract (0x4B324FC8, 0x01D31670, 0x475A7812, 0x88E16EBF, 0x00000003)
+# transfer (0x8A885D04, 0x11C91CEB, 0x0008E89F, 0x6048102B, 0x00000002)
+Msrpcface RW
+{
+ UINT8 byte[16] # 16 bytes of number
+ UINT32 version # the interface number
+}
+
+
+# the remainder of the packet after the header if "type" was Bind
+# in the response header, "type" should be BindAck
+MsrpcReqBind RW
+{
+ UINT16 maxtsize # maximum transmission fragment size (0x1630)
+ UINT16 maxrsize # max receive fragment size (0x1630)
+ UINT32 assocgid # associated group id (0x0)
+ UINT32 numelements # the number of elements (0x1)
+ UINT16 contextid # presentation context identifier (0x0)
+ UINT8 numsyntaxes # the number of syntaxes (has always been 1?)(0x1)
+ UINT8 padding # 0 - 1 byte of padding
+
+ * abstractint USE MsrpcIface # num and vers. of interface client is using
+ * transferint USE MsrpcIface # num and vers. of interface to use for replies
+}
+
+
+# this seems to be the same string name depending on the name of the pipe,
+# but is more likely to be linked to the interface name
+# "srvsvc", "\\PIPE\\ntsvcs"
+# "samr", "\\PIPE\\lsass"
+# "wkssvc", "\\PIPE\\wksvcs"
+# "NETLOGON", "\\PIPE\\NETLOGON"
+MsrpcAddress RW
+{
+ UINT16 length # length of the string including null terminator
+ * port USE string # the string above in single byte, null terminated form
+}
+
+
+# the response to place after the header in the reply packet
+MsrpcResBind RW
+{
+ UINT16 maxtsize # same as request
+ UINT16 maxrsize # same as request
+ UINT32 assocgid # zero
+
+ * secondaddr USE MsrpcAddress # the address string, as described earlier
+
+ UINT8 padding # 0 - one byte padding
+
+ UINT8 numresults # the number of results (0x01)
+
+ UINT8[] # 4-byte alignment padding, against SMB header
+ UINT16 result # result (0x00 = accept)
+ UINT16 reason # reason (0x00 = no reason specified)
+
+ * transfersyntax USE MsrpcIface # the transfer syntax from the request
+}
+
+
+# the remainder of the packet after the header for every other other
+# request
+MsrpcReqNorm RW
+{
+ UINT32 allochint # the size of the stub data in bytes
+ UINT16 prescontext # presentation context identifier (0x0)
+ UINT16 opnum # operation number (0x15)
+
+ * stub USE TvPacket # a packet dependent on the pipe name
+ # (probably the interface) and the op number)
+}
+
+
+# response to a request
+MsrpcResNorm RW
+{
+ UINT32 allochint # size of the stub data in bytes
+ UINT16 prescontext # presentation context identifier (same as request)
+ UINT8 cancelcount # cancel count? (0x0)
+ UINT8 reserved # 0 - one byte padding
+
+ * stub USE TvPacket # the remainder of the reply
+}
+
+
+3.3 Tail
+--------
+
+The end of each of the NTLSA and NETLOGON named pipes ends with:
+
+ ...... end of data
+ UINT32 return code
+
+
+
+4) NTLSA Transact Named Pipe
+----------------------------
+
+Defines for this pipe, identifying the query are:
+
+- LSA Open Policy: 0x2c
+- LSA Query Info Policy: 0x07
+- LSA Enumerate Trusted Domains: 0x0d
+- LSA Open Secret: 0xff
+- LSA Lookup SIDs: 0xfe
+- LSA Lookup Names: 0xfd
+- LSA Close: 0x00
+
+
+4.1) LSA Open Policy
+--------------------
+
+Note: The policy handle can be anything you like.
+
+Request:
+
+ UNISTR2 server name - unicode string starting with two '\'s
+ OBJ_ATTR object attributes
+ UINT32 1 - desired access
+
+Response:
+
+ POL_HND LSA policy handle
+
+ return 0 - indicates success
+
+
+4.2) LSA Query Info Policy
+--------------------------
+
+Note: The info class in response must be the same as that in the request.
+
+Request:
+
+ POL_HND LSA policy handle
+ UINT16 info class (also a policy handle?)
+
+Response:
+
+ VOID* undocumented buffer pointer
+ UINT16 info class (same as info class in request).
+
+ switch (info class)
+ case 3:
+ case 5:
+ {
+ DOM_INFO domain info, levels 3 and 5 (are the same).
+ }
+
+ return 0 - indicates success
+
+
+4.3) LSA Enumerate Trusted Domains
+----------------------------------
+
+Request:
+
+ no extra data
+
+Response:
+
+ UINT32 0 - enumeration context
+ UINT32 0 - entries read
+ UINT32 0 - trust information
+
+ return 0x8000 001a - "no trusted domains" success code
+
+
+4.4) LSA Open Secret
+--------------------
+
+Request:
+
+ no extra data
+
+Response:
+
+ UINT32 0 - undocumented
+ UINT32 0 - undocumented
+ UINT32 0 - undocumented
+ UINT32 0 - undocumented
+ UINT32 0 - undocumented
+
+ return 0x0C00 0034 - "no such secret" success code
+
+
+4.5) LSA Close
+--------------
+
+Request:
+
+ no extra data
+
+Response:
+
+ UINT32 0 - undocumented
+ UINT32 0 - undocumented
+ UINT32 0 - undocumented
+ UINT32 0 - undocumented
+ UINT32 0 - undocumented
+
+ return 0 - indicates success
+
+
+4.6) LSA Lookup SIDS
+--------------------
+
+Note: num_entries in response must be same as num_entries in request.
+
+Request:
+
+ POL_HND LSA policy handle
+ UINT32 num_entries
+ VOID* undocumented domain SID buffer pointer
+ VOID* undocumented domain name buffer pointer
+ VOID*[num_entries] undocumented domain SID pointers to be looked up.
+ DOM_SID[num_entries] domain SIDs to be looked up.
+ char[16] completely undocumented 16 bytes.
+
+Response:
+
+ DOM_REF domain reference response
+
+ UINT32 num_entries (listed above)
+ VOID* undocumented buffer pointer
+
+ UINT32 num_entries (listed above)
+ DOM_SID2[num_entries] domain SIDs (from Request, listed above).
+
+ UINT32 num_entries (listed above)
+
+ return 0 - indicates success
+
+
+4.7) LSA Lookup Names
+---------------------
+
+Note: num_entries in response must be same as num_entries in request.
+
+Request:
+
+ POL_HND LSA policy handle
+ UINT32 num_entries
+ UINT32 num_entries
+ VOID* undocumented domain SID buffer pointer
+ VOID* undocumented domain name buffer pointer
+ NAME[num_entries] names to be looked up.
+ char[] undocumented bytes - falsely translated SID structure?
+
+Response:
+
+ DOM_REF domain reference response
+
+ UINT32 num_entries (listed above)
+ VOID* undocumented buffer pointer
+
+ UINT32 num_entries (listed above)
+ DOM_RID[num_entries] domain SIDs (from Request, listed above).
+
+ UINT32 num_entries (listed above)
+
+ return 0 - indicates success
+
+
+
+5) NETLOGON rpc Transact Named Pipe
+-----------------------------------
+
+Defines for this pipe, identifying the query are:
+
+- LSA Request Challenge: 0x04
+- LSA Server Password Set: 0x06
+- LSA SAM Logon: 0x02
+- LSA SAM Logoff: 0xfc
+- LSA Auth 2: 0x0f
+- LSA Logon Control: 0x0e
+
+
+5.1) LSA Request Challenge
+--------------------------
+
+Note: logon server name starts with two '\' characters and is upper case.
+
+Note: logon client is the machine, not the user.
+
+Note: the initial LanManager password hash, against which the challenge
+ is issued, is the machine name itself (lower case). there will be
+ calls issued (LSA Server Password Set) which will change this, later.
+ refusing these calls allows you to always deal with the same password
+ (i.e the LM# of the machine name in lower case).
+
+Request:
+
+ VOID* undocumented buffer pointer
+ UNISTR2 logon server unicode string
+ UNISTR2 logon client unicode string
+ char[8] client challenge
+
+Response:
+
+ char[8] server challenge
+
+ return 0 - indicates success
+
+
+
+5.2) LSA Authenticate 2
+-----------------------
+
+Note: in between request and response, calculate the client credentials,
+ and check them against the client-calculated credentials (this
+ process uses the previously received client credentials).
+
+Note: neg_flags in the response is the same as that in the request.
+
+Note: you must take a copy of the client-calculated credentials received
+ here, because they will be used in subsequent authentication packets.
+
+Request:
+
+ LOG_INFO client identification info
+
+ char[8] client-calculated credentials
+ UINT8[] padding to 4-byte align with start of SMB header.
+ UINT32 neg_flags - negotiated flags (usual value is 0x0000 01ff)
+
+Response:
+
+ char[8] server credentials.
+ UINT32 neg_flags - same as neg_flags in request.
+
+ return 0 - indicates success. failure value unknown.
+
+
+5.3) LSA Server Password Set
+----------------------------
+
+Note: the new password is suspected to be a DES encryption using the old
+ password to generate the key.
+
+Note: in between request and response, calculate the client credentials,
+ and check them against the client-calculated credentials (this
+ process uses the previously received client credentials).
+
+Note: the server credentials are constructed from the client-calculated
+ credentials and the client time + 1 second.
+
+Note: you must take a copy of the client-calculated credentials received
+ here, because they will be used in subsequent authentication packets.
+
+Request:
+
+ CLNT_INFO client identification/authentication info
+ char[] new password - undocumented.
+
+Response:
+
+ CREDS server credentials. server time stamp appears to be ignored.
+
+ return 0 - indicates success; 0xC000 006a indicates failure
+
+
+5.4) LSA SAM Logon
+------------------
+
+Note: valid_user is True iff the username and password hash are valid for
+ the requested domain.
+
+Request:
+
+ SAM_INFO sam_id structure
+
+Response:
+
+ VOID* undocumented buffer pointer
+ CREDS server credentials. server time stamp appears to be ignored.
+
+ if (valid_user)
+ {
+ UINT16 3 - switch value indicating USER_INFO structure.
+ VOID* non-zero - pointer to USER_INFO structure
+ USER_INFO user logon information
+
+ UINT32 1 - Authoritative response; 0 - Non-Auth?
+
+ return 0 - indicates success
+ }
+ else
+ {
+ UINT16 0 - switch value. value to indicate no user presumed.
+ VOID* 0x0000 0000 - indicates no USER_INFO structure.
+
+ UINT32 1 - Authoritative response; 0 - Non-Auth?
+
+ return 0xC000 0064 - NT_STATUS_NO_SUCH_USER.
+ }
+
+
+5.5) LSA SAM Logoff
+--------------------
+
+Note: presumably, the SAM_INFO structure is validated, and a (currently
+ undocumented) error code returned if the Logoff is invalid.
+
+Request:
+
+ SAM_INFO sam_id structure
+
+Response:
+
+ VOID* undocumented buffer pointer
+ CREDS server credentials. server time stamp appears to be ignored.
+
+ return 0 - indicates success. undocumented failure indication.
+
+
+6) \\MAILSLOT\NET\NTLOGON
+-------------------------
+
+Note: mailslots will contain a response mailslot, to which the response
+ should be sent. the target NetBIOS name is REQUEST_NAME<20>, where
+ REQUEST_NAME is the name of the machine that sent the request.
+
+
+6.1) Query for PDC
+------------------
+
+Note: NTversion, LMNTtoken, LM20token in response are the same as those
+ given in the request.
+
+Request:
+
+ UINT16 0x0007 - Query for PDC
+ STR machine name
+ STR response mailslot
+ UINT8[] padding to 2-byte align with start of mailslot.
+ UNISTR machine name
+ UINT32 NTversion
+ UINT16 LMNTtoken
+ UINT16 LM20token
+
+Response:
+
+ UINT16 0x000A - Respose to Query for PDC
+ STR machine name (in uppercase)
+ UINT8[] padding to 2-byte align with start of mailslot.
+ UNISTR machine name
+ UNISTR domain name
+ UINT32 NTversion (same as received in request)
+ UINT16 LMNTtoken (same as received in request)
+ UINT16 LM20token (same as received in request)
+
+
+6.2) SAM Logon
+--------------
+
+Note: machine name in response is preceded by two '\' characters.
+
+Note: NTversion, LMNTtoken, LM20token in response are the same as those
+ given in the request.
+
+Note: user name in the response is presumably the same as that in the request.
+
+Request:
+
+ UINT16 0x0012 - SAM Logon
+ UINT16 request count
+ UNISTR machine name
+ UNISTR user name
+ STR response mailslot
+ UINT32 alloweable account
+ UINT32 domain SID size
+ char[sid_size] domain SID, of sid_size bytes.
+ UINT8[] ???? padding to 4? 2? -byte align with start of mailslot.
+ UINT32 NTversion
+ UINT16 LMNTtoken
+ UINT16 LM20token
+
+Response:
+
+ UINT16 0x0013 - Response to SAM Logon
+ UNISTR machine name
+ UNISTR user name - workstation trust account
+ UNISTR domain name
+ UINT32 NTversion
+ UINT16 LMNTtoken
+ UINT16 LM20token
+
+
+
+7) SRVSVC Transact Named Pipe
+-----------------------------
+
+
+Defines for this pipe, identifying the query are:
+
+- Net Share Enum : 0x0f
+- Net Server Get Info : 0x15
+
+
+7.1) Net Share Enum
+------------------
+
+Note: share level and switch value in the response are presumably the
+ same as those in the request.
+
+Note: cifsrap2.txt (section 5) may be of limited assistance here.
+
+Request:
+
+ VOID* pointer (to server name?)
+ UNISTR2 server name
+
+ UINT8[] padding to get unicode string 4-byte aligned
+ with the start of the SMB header.
+
+ UINT32 share level
+ UINT32 switch value
+
+ VOID* pointer to SHARE_INFO_1_CTR
+ SHARE_INFO_1_CTR share info with 0 entries
+
+ UINT32 preferred maximum length (0xffff ffff)
+
+Response:
+
+ UINT32 share level
+ UINT32 switch value
+
+ VOID* pointer to SHARE_INFO_1_CTR
+ SHARE_INFO_1_CTR share info (only added if share info ptr is non-zero)
+
+ return 0 - indicates success
+
+
+7.2) Net Server Get Info
+------------------
+
+Note: level is the same value as in the request.
+
+Request:
+
+ UNISTR2 server name
+ UINT32 switch level
+
+Response:
+
+ UINT32 switch level
+ VOID* pointer to SERVER_INFO_101
+
+ SERVER_INFO_101 server info (only added if server info ptr is non-zero)
+
+ return 0 - indicates success
+
+
+
+Appendix
+--------
+
+A1) Cryptographic side of NT Domain Authentication
+--------------------------------------------------
+
+
+A1.1) Definitions
+-----------------
+
+Add(A1,A2): Intel byte ordered addition of corresponding 4 byte words
+in arrays A1 and A2
+
+E(K,D): DES ECB encryption of 8 byte data D using 7 byte key K
+
+lmowf(): Lan man hash
+
+ntowf(): NT hash
+
+PW: md4(machine_password) == md4(lsadump $machine.acc) ==
+pwdump(machine$) (initially) == md4(lmowf(unicode(machine)))
+
+RC4(K,Lk,D,Ld): RC4 encryption of data D of length Ld with key K of
+length Lk
+
+v[m..n(,l)]: subset of v from bytes m to n, optionally padded with
+zeroes to length l
+
+Cred(K,D): E(K[7..7,7],E(K[0..6],D)) computes a credential
+
+Time(): 4 byte current time
+
+Cc,Cs: 8 byte client and server challenges Rc,Rs: 8 byte client and
+server credentials
+
+
+A1.2) Protocol
+--------------
+
+C->S ReqChal,Cc S->C Cs
+
+C & S compute session key Ks = E(PW[9..15],E(PW[0..6],Add(Cc,Cs)))
+
+C: Rc = Cred(Ks,Cc) C->S Authenticate,Rc S: Rs = Cred(Ks,Cs),
+assert(Rc == Cred(Ks,Cc)) S->C Rs C: assert(Rs == Cred(Ks,Cs))
+
+On joining the domain the client will optionally attempt to change its
+password and the domain controller may refuse to update it depending
+on registry settings. This will also occur weekly afterwards.
+
+C: Tc = Time(), Rc' = Cred(Ks,Rc+Tc) C->S ServerPasswordSet,Rc',Tc,
+rc4(Ks[0..7,16],lmowf(randompassword()) C: Rc = Cred(Ks,Rc+Tc+1) S:
+assert(Rc' == Cred(Ks,Rc+Tc)), Ts = Time() S: Rs' = Cred(Ks,Rs+Tc+1)
+S->C Rs',Ts C: assert(Rs' == Cred(Ks,Rs+Tc+1)) S: Rs = Rs'
+
+User: U with password P wishes to login to the domain (incidental data
+such as workstation and domain omitted)
+
+C: Tc = Time(), Rc' = Cred(Ks,Rc+Tc) C->S NetLogonSamLogon,Rc',Tc,U,
+rc4(Ks[0..7,16],16,ntowf(P),16), rc4(Ks[0..7,16],16,lmowf(P),16) S:
+assert(Rc' == Cred(Ks,Rc+Tc)) assert(passwords match those in SAM) S:
+Ts = Time()
+
+S->C Cred(Ks,Cred(Ks,Rc+Tc+1)),userinfo(logon script,UID,SIDs,etc) C:
+assert(Rs == Cred(Ks,Cred(Rc+Tc+1)) C: Rc = Cred(Ks,Rc+Tc+1)
+
+
+A1.3) Comments
+--------------
+
+On first joining the domain the session key could be computed by
+anyone listening in on the network as the machine password has a well
+known value. Until the machine is rebooted it will use this session
+key to encrypt NT and LM one way functions of passwords which are
+password equivalents. Any user who logs in before the machine has been
+rebooted a second time will have their password equivalent exposed. Of
+course the new machine password is exposed at this time anyway.
+
+None of the returned user info such as logon script, profile path and
+SIDs *appear* to be protected by anything other than the TCP checksum.
+
+The server time stamps appear to be ignored.
+
+The client sends a ReturnAuthenticator in the SamLogon request which I
+can't find a use for. However its time is used as the timestamp
+returned by the server.
+
+The password OWFs should NOT be sent over the network reversibly
+encrypted. They should be sent using RC4(Ks,md4(owf)) with the server
+computing the same function using the owf values in the SAM.
+
+
+A2) SIDs and RIDs
+-----------------
+
+SIDs and RIDs are well documented elsewhere.
+
+A SID is an NT Security ID (see DOM_SID structure). They are of the form:
+
+ S-revision-NN-SubAuth1-SubAuth2-SubAuth3...
+ S-revision-0xNNNNNNNNNNNN-SubAuth1-SubAuth2-SubAuth3...
+
+currently, the SID revision is 1.
+The Sub-Authorities are known as Relative IDs (RIDs).
+
+
+A2.1) Well-known SIDs
+---------------------
+
+
+A2.1.1) Universal well-known SIDs
+---------------------------------
+
+ Null SID S-1-0-0
+ World S-1-1-0
+ Local S-1-2-0
+ Creator Owner ID S-1-3-0
+ Creator Group ID S-1-3-1
+ Creator Owner Server ID S-1-3-2
+ Creator Group Server ID S-1-3-3
+
+ (Non-unique IDs) S-1-4
+
+
+A2.1.2) NT well-known SIDs
+--------------------------
+
+ NT Authority S-1-5
+ Dialup S-1-5-1
+
+ Network S-1-5-2
+ Batch S-1-5-3
+ Interactive S-1-5-4
+ Service S-1-5-6
+ AnonymousLogon S-1-5-7 (aka null logon session)
+ Proxy S-1-5-8
+ ServerLogon S-1-5-8 (aka domain controller account)
+
+ (Logon IDs) S-1-5-5-X-Y
+
+ (NT non-unique IDs) S-1-5-0x15-...
+
+ (Built-in domain) s-1-5-0x20
+
+
+
+A2.2) Well-known RIDS
+---------------------
+
+A RID is a sub-authority value, as part of either a SID, or in the case
+of Group RIDs, part of the DOM_GID structure, in the USER_INFO_1
+structure, in the LSA SAM Logon response.
+
+
+A2.2.1) Well-known RID users
+----------------------------
+
+ DOMAIN_USER_RID_ADMIN 0x0000 01F4
+ DOMAIN_USER_RID_GUEST 0x0000 01F5
+
+
+
+A2.2.2) Well-known RID groups
+----------------------------
+
+ DOMAIN_GROUP_RID_ADMINS 0x0000 0200
+ DOMAIN_GROUP_RID_USERS 0x0000 0201
+ DOMAIN_GROUP_RID_GUESTS 0x0000 0202
+
+
+
+A2.2.3) Well-known RID aliases
+------------------------------
+
+ DOMAIN_ALIAS_RID_ADMINS 0x0000 0220
+ DOMAIN_ALIAS_RID_USERS 0x0000 0221
+ DOMAIN_ALIAS_RID_GUESTS 0x0000 0222
+ DOMAIN_ALIAS_RID_POWER_USERS 0x0000 0223
+
+ DOMAIN_ALIAS_RID_ACCOUNT_OPS 0x0000 0224
+ DOMAIN_ALIAS_RID_SYSTEM_OPS 0x0000 0225
+ DOMAIN_ALIAS_RID_PRINT_OPS 0x0000 0226
+ DOMAIN_ALIAS_RID_BACKUP_OPS 0x0000 0227
+
+ DOMAIN_ALIAS_RID_REPLICATOR 0x0000 0228
+
+
diff --git a/docs/textdocs/security_level.txt b/docs/textdocs/security_level.txt
new file mode 100644
index 00000000000..867da2862ec
--- /dev/null
+++ b/docs/textdocs/security_level.txt
@@ -0,0 +1,99 @@
+!==
+!== security_level.txt for Samba release 1.9.18alpha8 30 Oct 1997
+!==
+Contributor: Andrew Tridgell
+Updated: June 27, 1997
+Status: Current
+
+Subject: Description of SMB security levels.
+===========================================================================
+
+Samba supports the following options to the global smb.conf parameter
+"security =":
+ share, user, server
+
+Of the above, "security = server" means that Samba reports to clients that
+it is running in "user mode" but actually passes off all authentication
+requests to another "user mode" server. This requires an additional
+parameter "password server =" that points to the real authentication server.
+That real authentication server can be another Samba server or can be a
+Windows NT server, the later natively capable of encrypted password support.
+
+Below is a more complete description of security levels.
+===========================================================================
+
+A SMB server tells the client at startup what "security level" it is
+running. There are two options "share level" and "user level". Which
+of these two the client receives affects the way the client then tries
+to authenticate itself. It does not directly affect (to any great
+extent) the way the Samba server does security. I know this is
+strange, but it fits in with the client/server approach of SMB. In SMB
+everything is initiated and controlled by the client, and the server
+can only tell the client what is available and whether an action is
+allowed.
+
+I'll describe user level security first, as its simpler. In user level
+security the client will send a "session setup" command directly after
+the protocol negotiation. This contains a username and password. The
+server can either accept or reject that username/password
+combination. Note that at this stage the server has no idea what
+share the client will eventually try to connect to, so it can't base
+the "accept/reject" on anything other than:
+
+- the username/password
+- the machine that the client is coming from
+
+If the server accepts the username/password then the client expects to
+be able to mount any share (using a "tree connection") without
+specifying a password. It expects that all access rights will be as
+the username/password specified in the "session setup".
+
+It is also possible for a client to send multiple "session setup"
+requests. When the server responds it gives the client a "uid" to use
+as an authentication tag for that username/password. The client can
+maintain multiple authentication contexts in this way (WinDD is an
+example of an application that does this)
+
+
+Ok, now for share level security. In share level security (the default
+with samba) the client authenticates itself separately for each
+share. It will send a password along with each "tree connection"
+(share mount). It does not explicitly send a username with this
+operation. The client is expecting a password to be associated with
+each share, independent of the user. This means that samba has to work
+out what username the client probably wants to use. It is never
+explicitly sent the username. Some commercial SMB servers such as NT actually
+associate passwords directly with shares in share level security, but
+samba always uses the unix authentication scheme where it is a
+username/password that is authenticated, not a "share/password".
+
+Many clients send a "session setup" even if the server is in share
+level security. They normally send a valid username but no
+password. Samba records this username in a list of "possible
+usernames". When the client then does a "tree connection" it also adds
+to this list the name of the share they try to connect to (useful for
+home directories) and any users listed in the "user =" smb.conf
+line. The password is then checked in turn against these "possible
+usernames". If a match is found then the client is authenticated as
+that user.
+
+Finally "server level" security. In server level security the samba
+server reports to the client that it is in user level security. The
+client then does a "session setup" as described earlier. The samba
+server takes the username/password that the client sends and attempts
+to login to the "password server" by sending exactly the same
+username/password that it got from the client. If that server is in
+user level security and accepts the password then samba accepts the
+clients connection. This allows the samba server to use another SMB
+server as the "password server".
+
+You should also note that at the very start of all this, where the
+server tells the client what security level it is in, it also tells
+the client if it supports encryption. If it does then it supplies the
+client with a random "cryptkey". The client will then send all
+passwords in encrypted form. You have to compile samba with encryption
+enabled to support this feature, and you have to maintain a separate
+smbpasswd file with SMB style encrypted passwords. It is
+cryptographically impossible to translate from unix style encryption
+to SMB style encryption, although there are some fairly simple management
+schemes by which the two could be kept in sync.
diff --git a/examples/README b/examples/README
index 3e58e0faf1c..c2c36bdcdf1 100644
--- a/examples/README
+++ b/examples/README
@@ -1,6 +1,11 @@
-This directory contains example config files for Samba. If you have an
-interesting config file, then please send it in for inclusion in the
-package.
+Copyright(C) Samba-Team 1993-1997
+
+This directory contains example config files and related material for
+Samba.
+
+At a minimum please refer to the smb.conf.default file for current
+information regarding global and share parameter settings.
+
+Send additions to: samba-bugs@samba.anu.edu.au
-Send it to: Andrew.Tridgell@anu.edu.au
diff --git a/examples/misc/extra_smbstatus b/examples/misc/extra_smbstatus
index b018f3dcce9..584284feb34 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 ^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~
@@ -43,5 +46,5 @@ Cheers,
| | "Spend a little love and get high"
_/ \_ | - Lenny Kravitz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-~~~~ SAMBA Web Pages: http://samba.canberra.edu.au/pub/samba/samba.html ~~~~~
+~~~~~~~~~~~~~~ SAMBA Web Pages: http://samba.anu.edu.au/samba/ ~~~~~~~~~~~~~~
diff --git a/examples/misc/wall.perl b/examples/misc/wall.perl
index fc3dc2e2c05..9303658ce14 100644
--- a/examples/misc/wall.perl
+++ b/examples/misc/wall.perl
@@ -6,40 +6,64 @@
#@(#) ...using "smbclient -M" message to winpopup service.
#@(#) Default usage is to message every connected PC.
#@(#) Alternate usage is to message every pc on the argument list.
-#@(#) Hacked up by Keith Farrar <farrar@parc.xerox.com>
+#@(#) Hacked up by Keith Farrar <farrar@parc.xerox.com>
#
+# Cleanup and corrections by
+# Michal Jaegermann <michal@ellpspace.math.ualberta.ca>
+# Message to send can be now also fed (quietly) from stdin; a pipe will do.
#=============================================================================
-$smbstatus = "/usr/local/bin/smbstatus";
-$smbclient = "/usr/local/bin/smbclient";
-print STDOUT "\nEnter message for Samba clients of this host\n";
-print STDOUT "(terminated with single '.' or end of file):\n";
+$smbstatus = "/usr/local/bin/smbstatus";
+$smbshout = "/usr/local/bin/smbclient -M";
-while ( <STDIN> ) {
- /^\.$/ && last;
- push(@message, $_);
+if (@ARGV) {
+ @clients = @ARGV;
+ undef @ARGV;
}
+else { # no clients specified explicitly
+ open(PCLIST, "$smbstatus |") || die "$smbstatus failed!.\n$!\n";
+ while(<PCLIST>) {
+ last if /^Locked files:/;
+ split(' ', $_, 6);
+ # do not accept this line if less then six fields
+ next unless $_[5];
+ # if you have A LOT of clients you may speed things up by
+ # checking pid - no need to look further if this pid was already
+ # seen; left as an exercise :-)
+ $client = $_[4];
+ next unless $client =~ /^\w+\./; # expect 'dot' in a client name
+ next if grep($_ eq $client, @clients); # we want this name once
+ push(@clients, $client);
+ }
+ close(PCLIST);
+}
+
+if (-t) {
+ print <<'EOT';
-if ( $ARGV[0] ne "" ) {
- $debug && print STDOUT "Was given args: \n\t @ARGV\n";
- foreach $client ( @ARGV ) {
- $pcclient{$client} = $client;
- }
-} else {
- open( PCLIST, "$smbstatus | /bin/awk '/^[a-z]/ {print $5}' | /bin/sort | /bin/uniq|");
- while ( <PCLIST> ) {
- /^[a-z]+[a-z0-9A-Z-_]+.+/ || next;
- ($share, $user, $group, $pid, $client, @junk) = split;
- $pcclient{$client} = $client;
- }
- close(PCLIST);
+Enter message for Samba clients of this host
+(terminated with single '.' or end of file):
+EOT
+
+ while (<>) {
+ last if /^\.$/;
+ push(@message, $_);
+ }
+}
+else { # keep quiet and read message from stdin
+ @message = <>;
}
-foreach $pc ( keys(%pcclient) ) {
- print STDOUT "Sending message ";
- $debug && print STDOUT " <@message> \n";
- print STDOUT "To <$pc>\n";
- open(SENDMSG,"|$smbclient -M $pc") || next;
+foreach(@clients) {
+## print "To $_:\n";
+ if (open(SENDMSG,"|$smbshout $_")) {
print SENDMSG @message;
close(SENDMSG);
+ }
+ else {
+ warn "Cannot notify $_ with $smbshout:\n$!\n";
+ }
}
+
+exit 0;
+
diff --git a/examples/printer-accounting/README b/examples/printer-accounting/README
new file mode 100644
index 00000000000..b7ab42acb96
--- /dev/null
+++ b/examples/printer-accounting/README
@@ -0,0 +1,63 @@
+These are just a few examples of what you can do for printer accounting;
+they are really just hacks to show a manager how may pages were being
+printed out on his new hp5n :)
+
+acct-all will run acct-sum and read the log files to generate some
+stats.
+
+Here is a sample output of the raw stats :
+
+1996-06-10.15:02:15 pkelly master.fcp.oypi.com 538 0
+1996-06-10.15:06:40 pkelly master.fcp.oypi.com 537 0
+1996-06-10.15:32:12 ted master.fcp.oypi.com 547 0
+1996-06-11.09:06:15 violet master.fcp.oypi.com 2667 0
+1996-06-11.09:48:02 violet master.fcp.oypi.com 66304 5
+1996-06-11.09:50:04 violet master.fcp.oypi.com 116975 9
+1996-06-11.09:57:20 violet master.fcp.oypi.com 3013 1
+1996-06-11.10:13:17 pkelly master.fcp.oypi.com 3407 1
+1996-06-11.12:37:06 craig master.fcp.oypi.com 13639 2
+1996-06-11.12:42:23 pkelly master.fcp.oypi.com 13639 2
+1996-06-11.12:45:11 marlene master.fcp.oypi.com 515 0
+1996-06-11.14:17:10 lucie master.fcp.oypi.com 1405 1
+1996-06-11.14:36:03 laura master.fcp.oypi.com 45486 5
+1996-06-11.15:08:21 violet master.fcp.oypi.com 1923 1
+1996-06-11.15:09:42 laura master.fcp.oypi.com 4821 1
+1996-06-11.15:12:28 laura master.fcp.oypi.com 46277 5
+1996-06-11.15:19:38 violet master.fcp.oypi.com 3503 1
+1996-06-11.15:21:49 lucie master.fcp.oypi.com 493 0
+1996-06-11.15:43:36 al master.fcp.oypi.com 3067 1
+
+And the output after the acct-sum is done on a full set of files
+in /var/log/lp/*
+
+master[1072] /var/log/lp$ /etc/conf/acct-all
+
+Sun Jul 21 23:03:16 EDT 1996
+
+Pages are approximate ...
+
+User Jobs Pages Size
+al 1 1 2 KB
+craig 1 2 13 KB
+jack 68 235 1995 KB
+laura 88 328 3050 KB
+lucie 221 379 3529 KB
+marlene 12 151 1539 KB
+melanie 83 365 3691 KB
+michelle 68 219 1987 KB
+mike 2 10 81 KB
+neil 111 225 2753 KB
+operator 44 137 1132 KB
+pkelly 368 984 11154 KB
+root 8 0 29 KB
+ted 158 257 2337 KB
+tony 244 368 2455 KB
+violet 419 1002 10072 KB
+
+
+Printer Jobs Pages
+hp2p 3 4
+hp5 915 2135
+lp 978 2524
+
+<pkelly@ets.net>
diff --git a/examples/printer-accounting/acct-all b/examples/printer-accounting/acct-all
new file mode 100644
index 00000000000..dc8f175b3cb
--- /dev/null
+++ b/examples/printer-accounting/acct-all
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+echo ""
+date
+echo ""
+echo "Pages are approximate ..."
+echo ""
+/etc/conf/acct-sum /var/log/lp/*
+echo ""
diff --git a/examples/printer-accounting/acct-sum b/examples/printer-accounting/acct-sum
new file mode 100644
index 00000000000..ffbfc8d8801
--- /dev/null
+++ b/examples/printer-accounting/acct-sum
@@ -0,0 +1,29 @@
+#!/usr/bin/perl
+
+while (<>) {
+ ($date, $user, $machine, $size, $pages) = split(' ');
+
+ $Printer{$ARGV}++;
+ $PrinterPages{$ARGV} += $pages;
+
+ $Jobs{$user}++;
+ $Size{$user}+= $size;
+ $Pages{$user}+= $pages;
+}
+
+printf "%-15s %5s %8s %8s\n", qw(User Jobs Pages Size);
+foreach $user (sort keys %Jobs) {
+ printf "%-15s %5d %8d %8d \KB\n",
+ $user, $Jobs{$user}, $Pages{$user}, $Size{$user}/1024;
+}
+
+
+print "\n\n";
+printf "%-15s %5s %8s %8s\n", qw(Printer Jobs Pages);
+foreach $prn (sort keys %Printer) {
+ ($name = $prn) =~ s=.*/==;
+ printf "%-15s %5d %8d\n",
+ $name, $Printer{$prn}, $PrinterPages{$prn};
+}
+
+
diff --git a/examples/printer-accounting/hp5-redir b/examples/printer-accounting/hp5-redir
new file mode 100644
index 00000000000..98c2b72edd2
--- /dev/null
+++ b/examples/printer-accounting/hp5-redir
@@ -0,0 +1,43 @@
+#!/usr/bin/perl
+#
+# $Source: /data/src/mirror/cvs/samba/examples/printer-accounting/hp5-redir,v $
+# $Id: hp5-redir,v 1.1 1996/07/23 03:30:56 samba-bugs Exp $
+#
+# 0 == stdin == docuement
+# 1 == stdout == printer
+# 2 == stderr == logging
+#
+# With redirection to another valid /etc/printcap entry
+#
+
+umask(002);
+
+# -w132 -l66 -i0 -n pkelly -h master.fcp.oypi.com /var/log/lp-acct
+require "getopts.pl";
+&Getopts("w:l:i:n:h:");
+
+chomp($date = `date '+%Y-%m-%d.%T'`);
+
+($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
+ $atime,$mtime,$ctime,$blksize,$blocks)
+ = stat(STDIN);
+
+# send to the real printer now.
+open(P, "|lpr -Pmgmt0") || die "Can't print to hp5-real ($!)\n";
+$cnt = 0;
+while (sysread(STDIN, $buf, 10240)) {
+ print P $buf;
+ # this is ugly, but it gives the approx in pages. We
+ # don't print graphics, so ... There must be a better way :)
+ $cnt += ($buf =~ /^L/g);
+}
+close(P);
+
+$acct = shift;
+if (open(ACCT, ">>$acct")) {
+ print ACCT "$date $opt_n $opt_h $size $cnt\n";
+ close(ACCT);
+} else {
+ warn "Err: Can't account for it ($!)\n";
+ warn "Log: $date $opt_n $opt_h $size $cnt\n";
+}
diff --git a/examples/printer-accounting/lp-acct b/examples/printer-accounting/lp-acct
new file mode 100644
index 00000000000..3fe45f877fd
--- /dev/null
+++ b/examples/printer-accounting/lp-acct
@@ -0,0 +1,38 @@
+#!/usr/bin/perl
+#
+# $Source: /data/src/mirror/cvs/samba/examples/printer-accounting/lp-acct,v $
+# $Id: lp-acct,v 1.1 1996/07/23 03:30:56 samba-bugs Exp $
+#
+# 0 == stdin == docuement
+# 1 == stdout == printer
+# 2 == stderr == logging
+#
+# Regular, with no redirection
+#
+
+umask(002);
+
+# -w132 -l66 -i0 -n pkelly -h master.fcp.oypi.com /var/log/lp-acct
+require "getopts.pl";
+&Getopts("w:l:i:n:h:");
+
+chomp($date = `date '+%Y-%m-%d.%T'`);
+
+($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
+ $atime,$mtime,$ctime,$blksize,$blocks)
+ = stat(STDIN);
+
+$cnt = 0;
+while (sysread(STDIN, $buf, 10240)) {
+ print $buf;
+ $cnt += ($buf =~ /^L/g);
+}
+
+$acct = shift;
+if (open(ACCT, ">>$acct")) {
+ print ACCT "$date $opt_n $opt_h $size $cnt\n";
+ close(ACCT);
+} else {
+ warn "Err: Can't account for it ($!)\n";
+ warn "Log: $date $opt_n $opt_h $size $cnt\n";
+}
diff --git a/examples/printer-accounting/printcap b/examples/printer-accounting/printcap
new file mode 100644
index 00000000000..976005a097c
--- /dev/null
+++ b/examples/printer-accounting/printcap
@@ -0,0 +1,22 @@
+# HP5N - Accounting entry
+#
+# This file calls the filter, hp5-redir to do the numbers and then
+# is redirected to the real entry, mgmt0, which is a remote HP5N
+# on the LAN with it's own IP number.
+#
+hp5:lp=/dev/lp1:\
+ :sd=/usr/spool/lpd/hp5-acct:\
+ :lf=/var/log/lp-err:\
+ :af=/var/log/lp/hp5:\
+ :if=/usr/local/bin/lp/hp5-redir:\
+ :sh:sf:\
+ :mx#0:
+
+# HP5N - Real printer location
+mgmt0:\
+ :rm=hp5.fcp.oypi.com:\
+ :rp=hp5.fcp.oypi.com:\
+ :sd=/usr/spool/lpd/mgmt0:\
+ :sh:sf:\
+ :mx#0:
+
diff --git a/examples/printing/smbprint b/examples/printing/smbprint
index a80d60ce4fa..079f20aac41 100755
--- a/examples/printing/smbprint
+++ b/examples/printing/smbprint
@@ -53,7 +53,7 @@ logfile=/tmp/smb-print.log
# Extract the directory name from the file name.
# Concat this with /.config to get the config file.
#
-eval acct_file=\$$#
+eval acct_file=\${$#}
spool_dir=`dirname $acct_file`
config_file=$spool_dir/.config
diff --git a/examples/simple/smb.conf b/examples/simple/smb.conf
index cdf65b337f7..786bf49057c 100644
--- a/examples/simple/smb.conf
+++ b/examples/simple/smb.conf
@@ -80,11 +80,13 @@
writable = no
create mode = 0700
-; you might also want this one
+; you might also want this one, notice that it is read only so as not to give
+; people without an account write access.
+;
; [tmp]
; comment = Temporary file space
; path = /tmp
-; read only = no
+; read only = yes
; public = yes
;
diff --git a/examples/smb.conf.default b/examples/smb.conf.default
new file mode 100644
index 00000000000..a827050e9e3
--- /dev/null
+++ b/examples/smb.conf.default
@@ -0,0 +1,243 @@
+# This is the main Samba configuration file. You should read the
+# smb.conf(5) manual page in order to understand the options listed
+# here. Samba has a huge number of configurable options (perhaps too
+# many!) most of which are not shown in this example
+#
+# Any line which starts with a ; (semi-colon) or a # (hash)
+# is a comment and is ignored. In this example we will use a #
+# for commentry and a ; for parts of the config file that you
+# may wish to enable
+#
+# NOTE: Whenever you modify this file you should run the command "testparm"
+# to check that you have not many any basic syntactic errors.
+#
+#======================= Global Settings =====================================
+[global]
+
+# workgroup = NT-Domain-Name or Workgroup-Name, eg: REDHAT4
+ workgroup = MYGROUP
+
+# server string is the equivalent of the NT Description field
+ server string = Samba Server
+
+# This option is important for security. It allows you to restrict
+# connections to machines which are on your local network. The
+# following example restricts access to two C class networks and
+# the "loopback" interface. For more examples of the syntax see
+# the smb.conf man page
+; hosts allow = 192.168.1. 192.168.2. 127.
+
+# If you want to automatically load your printer list rather
+# than setting them up individually then you'll need this
+ printcap name = /etc/printcap
+ load printers = yes
+
+# It should not be necessary to specify the print system type unless
+# it is non-standard. Currently supported print systems include:
+# bsd, sysv, plp, lprng, aix, hpux, qnx
+; printing = bsd
+
+# Uncomment this if you want a guest account, you must add this to /etc/passwd
+# otherwise the user "nobody" is used
+; guest account = pcguest
+
+# this tells Samba to use a separate log file for each machine
+# that connects
+ log file = /usr/local/samba/var/log.%m
+
+# Put a capping on the size of the log files (in Kb).
+ max log size = 50
+
+# Security mode. Most people will want user level security. See
+# security_level.txt for details.
+ security = user
+# Use password server option only with security = server
+; password server = <NT-Server-Name>
+
+# You may wish to use password encryption. Please read
+# ENCRYPTION.txt, Win95.txt and WinNT.txt in the Samba documentation.
+# Do not enable this option unless you have read those documents
+; encrypt passwords = yes
+
+# Using the following line enables you to customise your configuration
+# on a per machine basis. The %m gets replaced with the netbios name
+# of the machine that is connecting
+; include = /usr/local/samba/lib/smb.conf.%m
+
+# Most people will find that this option gives better performance.
+# See speed.txt and the manual pages for details
+ socket options = TCP_NODELAY
+
+# Configure Samba to use multiple interfaces
+# If you have multiple network interfaces then you must list them
+# here. See the man page for details.
+; interfaces = 192.168.12.2/24 192.168.13.2/24
+
+# Browser Control Options:
+# set local master to no if you don't want Samba to become a master
+# browser on your network. Otherwise the normal election rules apply
+; local master = no
+
+# OS Level determines the precedence of this server in master browser
+# elections. The default value should be reasonable
+; os level = 33
+
+# Domain Master specifies Samba to be the Domain Master Browser. This
+# allows Samba to collate browse lists between subnets. Don't use this
+# if you already have a Windows NT domain controller doing this job
+; domain master = yes
+
+# Preferred Master causes Samba to force a local browser election on startup
+# and gives it a slightly higher chance of winning the election
+; preferred master = yes
+
+# Use only if you have an NT server on your network that has been
+# configured at install time to be a primary domain controller.
+; domain controller = <NT-Domain-Controller-SMBName>
+
+# Enable this if you want Samba to be a domain logon server for
+# Windows95 workstations.
+; domain logons = yes
+
+# if you enable domain logons then you may want a per-machine or
+# per user logon script
+# run a specific logon batch file per workstation (machine)
+; logon script = %m.bat
+# run a specific logon batch file per username
+; logon script = %u.bat
+
+# Where to store roving profiles (only for Win95 and WinNT)
+# %L substitutes for this servers netbios name, %U is username
+# You must uncomment the [Profiles] share below
+; logon path = \\%L\Profiles\%U
+
+# Windows Internet Name Serving Support Section:
+# WINS Support - Tells the NMBD component of Samba to enable it's WINS Server
+; wins support = yes
+
+# WINS Server - Tells the NMBD components of Samba to be a WINS Client
+# Note: Samba can be either a WINS Server, or a WINS Client, but NOT both
+; wins server = w.x.y.z
+
+# WINS Proxy - Tells Samba to answer name resolution queries on
+# behalf of a non WINS capable client, for this to work there must be
+# at least one WINS Server on the network. The default is NO.
+; wins proxy = yes
+
+# DNS Proxy - tells Samba whether or not to try to resolve NetBIOS names
+# via DNS nslookups. The built-in default for versions 1.9.17 is yes,
+# this has been changed in version 1.9.18 to no.
+ dns proxy = no
+
+#============================ Share Definitions ==============================
+[homes]
+ comment = Home Directories
+ browseable = no
+ writable = yes
+
+# Un-comment the following and create the netlogon directory for Domain Logons
+; [netlogon]
+; comment = Network Logon Service
+; path = /usr/local/samba/lib/netlogon
+; guest ok = yes
+; writable = no
+; share modes = no
+
+
+# Un-comment the following to provide a specific roving profile share
+# the default is to use the user's home directory
+;[Profiles]
+; path = /usr/local/samba/profiles
+; browseable = no
+; guest ok = yes
+
+
+# NOTE: If you have a BSD-style print system there is no need to
+# specifically define each individual printer
+[printers]
+ comment = All Printers
+ path = /usr/spool/samba
+ browseable = no
+# Set public = yes to allow user 'guest account' to print
+ guest ok = no
+ writable = no
+ printable = yes
+
+# This one is useful for people to share files
+;[tmp]
+; comment = Temporary file space
+; path = /tmp
+; read only = no
+; public = yes
+
+# A publicly accessible directory, but read only, except for people in
+# the "staff" group
+;[public]
+; comment = Public Stuff
+; path = /home/samba
+; public = yes
+; writable = yes
+; printable = no
+; write list = @staff
+
+# Other examples.
+#
+# A private printer, usable only by fred. Spool data will be placed in fred's
+# home directory. Note that fred must have write access to the spool directory,
+# wherever it is.
+;[fredsprn]
+; comment = Fred's Printer
+; valid users = fred
+; path = /homes/fred
+; printer = freds_printer
+; public = no
+; writable = no
+; printable = yes
+
+# A private directory, usable only by fred. Note that fred requires write
+# access to the directory.
+;[fredsdir]
+; comment = Fred's Service
+; path = /usr/somewhere/private
+; valid users = fred
+; public = no
+; writable = yes
+; printable = no
+
+# a service which has a different directory for each machine that connects
+# this allows you to tailor configurations to incoming machines. You could
+# also use the %u option to tailor it by user name.
+# The %m gets replaced with the machine name that is connecting.
+;[pchome]
+; comment = PC Directories
+; path = /usr/pc/%m
+; public = no
+; writable = yes
+
+# A publicly accessible directory, read/write to all users. Note that all files
+# created in the directory by users will be owned by the default user, so
+# any user with access can delete any other user's files. Obviously this
+# directory must be writable by the default user. Another user could of course
+# be specified, in which case all files would be owned by that user instead.
+;[public]
+; path = /usr/somewhere/else/public
+; public = yes
+; only guest = yes
+; writable = yes
+; printable = no
+
+# The following two entries demonstrate how to share a directory so that two
+# users can place files there that will be owned by the specific users. In this
+# setup, the directory should be writable by both users and should have the
+# sticky bit set on it to prevent abuse. Obviously this could be extended to
+# as many users as required.
+;[myshare]
+; comment = Mary's and Fred's stuff
+; path = /usr/somewhere/shared
+; valid users = mary fred
+; public = no
+; writable = yes
+; printable = no
+; create mask = 0765
+
+
diff --git a/examples/svr4-startup/README b/examples/svr4-startup/README
new file mode 100644
index 00000000000..8ed9f744770
--- /dev/null
+++ b/examples/svr4-startup/README
@@ -0,0 +1,24 @@
+Hi and thanks for this great software.
+
+Solaris (and other sysv) machines have a standardized way of
+starting and shutting down services (you may well know that already).
+
+Here's a piece of code one could place under /etc/init.d
+and create appropriate link from, say
+
+ /etc/rc2.d/S99samba.server
+
+to make smbd start and stop automatically with system bootups and
+shutdowns. Each one should edit the lines containing the
+daemon calls to agree with his/her installation (the code below
+works with the defaults) and workgroup setup (we use the -G and -n
+options).
+
+
+I hope this will be of use --- at least it is for me.
+
+Yours,
+
+Timo Knuutila
+knuutila@cs.utu.fi
+
diff --git a/examples/svr4-startup/samba.server b/examples/svr4-startup/samba.server
new file mode 100755
index 00000000000..0a47fdb10ce
--- /dev/null
+++ b/examples/svr4-startup/samba.server
@@ -0,0 +1,38 @@
+#!/bin/sh
+#ident "@(#)samba.server 1.0 96/06/19 TK" /* SVr4.0 1.1.13.1*/
+#
+# Please send info on modifications to knuutila@cs.utu.fi
+#
+# This file should have uid root, gid sys and chmod 744
+#
+if [ ! -d /usr/bin ]
+then # /usr not mounted
+ exit
+fi
+
+killproc() { # kill the named process(es)
+ pid=`/usr/bin/ps -e |
+ /usr/bin/grep -w $1 |
+ /usr/bin/sed -e 's/^ *//' -e 's/ .*//'`
+ [ "$pid" != "" ] && kill $pid
+}
+
+# Start/stop processes required for samba server
+
+case "$1" in
+
+'start')
+#
+# Edit these lines to suit your installation (paths, workgroup, host)
+#
+ /opt/samba/bin/smbd -D -s/opt/samba/smb.conf
+ /opt/samba/bin/nmbd -D -l/opt/samba/log -s/opt/samba/smb.conf
+ ;;
+'stop')
+ killproc nmbd
+ killproc smbd
+ ;;
+*)
+ echo "Usage: /etc/init.d/samba.server { start | stop }"
+ ;;
+esac
diff --git a/examples/thoralf/smb.conf b/examples/thoralf/smb.conf
new file mode 100644
index 00000000000..f9f147474a8
--- /dev/null
+++ b/examples/thoralf/smb.conf
@@ -0,0 +1,152 @@
+; Configuration file for smbd (Samba 1.9.15p8)
+; created by Thoralf Freitag. Send comments to:
+; <Thoralf.Freitag@remserv.rz.fhtw-berlin.de> or
+; <Thoralf.Freitag@t-online.de>
+; last edit 24.04.1995 01:11
+;
+;
+
+[global]
+
+ protocol = NT1
+ ;long filenames for win95
+ mangle case = yes
+ ;lower and upper letters
+ mangled names = yes
+ default case = lower
+ case sensitive = no
+ preserve case = yes
+ short preserve case = yes
+
+ printing = bsd
+ printcap name = /etc/printcap
+ lpq cache time = 0
+ workgroup = WORKGROUP
+ admin users = su
+ ;su is allowed to do all !!!
+ guest account = ftp
+ ;guest is same as user ftp
+ default service = reference
+ ;is possibly helpful to browsing under win 95
+ os level = 2
+ log file = /var/adm/log.smb
+ max log size = 10
+ debug level = 1
+ share modes = yes
+ lock directory = /var/adm
+
+[JP_360_raw]
+ comment = Networkprinter queue for Olivetti JP 360 (untreated RAW format)
+ browseable = yes
+ available = yes
+ public = no
+ force user = root
+ writable = no
+ printable = yes
+ printer name = samba
+ ;samba is an alias name for an raw_printer in your /etc/printcap
+ path = /samba/tmp
+ create mode = 0700
+
+[JP_360_mono]
+ comment = Networkprinter queue for Olivetti JP 360 Mono (with apsfilter)
+ browseable = yes
+ available = yes
+ public = no
+ force user = root
+ writable = no
+ printable = yes
+ printer name = lp
+ ;lp means the standard printer in your /etc/printcap
+ path = /samba/tmp
+ create mode = 0700
+
+[JP_360_color]
+ comment = Networkprinter queue for Olivetti JP 360 Color (with apsfilter)
+ browseable = yes
+ available = yes
+ public = no
+ force user = root
+ writable = no
+ printable = yes
+ printer name = lp4
+ ;my printer need this to print with his color cartridge
+ ;--> the lpd is drive to the printer as an color printer
+ path = /samba/tmp
+ create mode = 0700
+
+[tmp]
+ comment = the garbage dump
+ browseable = yes
+ available = yes
+ public = yes
+ read only = no
+ printable = no
+ path = /samba/tmp
+ create mask = 0777
+
+[transfer]
+ comment = the market place
+ browseable = yes
+ available = yes
+ public = yes
+ read only = no
+ printable = no
+ path = /samba/transfer
+ create mask = 0777
+
+[homes]
+ comment = home directories
+ browseable = no
+ ;ONLY the home-dirs are visible, not the service itself
+ available = yes
+ guest ok = no
+ read only = no
+ printable = no
+ create mode = 0700
+
+[install]
+ comment = all of the many install files
+ browsable = yes
+ available = yes
+ public = no
+ username = @root, @users
+ writable = yes
+ read list = @users
+ printable = no
+ path = /samba/install
+ create mode = 0755
+
+[doc-help]
+ comment = documentations, helpfiles, FAQ's
+ browsable = yes
+ available = yes
+ public = no
+ username = @root, @users
+ writable = yes
+ read list = @users
+ printable = no
+ path = /samba/doc
+ create mode = 0755
+
+[cd_rom_2]
+ comment = the CD in the CD-ROM drive on PANDORA
+ browsable = yes
+ available = yes
+ public = yes
+ writable = no
+ printable = no
+ path = /cdrom
+
+[reference]
+ ;the default, if invalid accesses
+ comment = PANDORA: Samba LAN manager
+ browsable = yes
+ ;only as an hint
+ available = no
+ ;however no access possible
+ public = yes
+ writable = no
+ printable = no
+ path = /samba/tmp
+
diff --git a/examples/validchars/msdos70.out b/examples/validchars/msdos70.out
new file mode 100644
index 00000000000..a722b83604f
--- /dev/null
+++ b/examples/validchars/msdos70.out
@@ -0,0 +1,257 @@
+255: ok
+254: ok
+253: ok
+252: ok
+251: ok
+250: ok
+249: ok
+248: ok
+247: ok
+246: ok
+245: ok
+244: ok
+243: ok
+242: ok
+241: ok
+240: ok
+239: ok
+238: ok
+237: ok
+236: 237
+235: ok
+234: ok
+233: ok
+232: ok
+231: 232
+230: ok
+229: ok
+228: 229
+227: ok
+226: ok
+225: ok
+224: ok
+223: ok
+222: ok
+221: ok
+220: ok
+219: ok
+218: ok
+217: ok
+216: ok
+215: ok
+214: ok
+213: 73
+212: ok
+211: ok
+210: ok
+209: ok
+208: 209
+207: ok
+206: ok
+205: ok
+204: ok
+203: ok
+202: ok
+201: ok
+200: ok
+199: ok
+198: 199
+197: ok
+196: ok
+195: ok
+194: ok
+193: ok
+192: ok
+191: ok
+190: ok
+189: ok
+188: ok
+187: ok
+186: ok
+185: ok
+184: ok
+183: ok
+182: ok
+181: ok
+180: ok
+179: ok
+178: ok
+177: ok
+176: ok
+175: ok
+174: ok
+173: ok
+172: ok
+171: ok
+170: ok
+169: ok
+168: ok
+167: ok
+166: ok
+165: ok
+164: 165
+163: 233
+162: 224
+161: 214
+160: 181
+159: ok
+158: ok
+157: ok
+156: ok
+155: 157
+154: ok
+153: ok
+152: length 0
+151: 235
+150: 234
+149: 227
+148: 153
+147: 226
+146: ok
+145: 146
+144: ok
+143: ok
+142: ok
+141: 222
+140: 215
+139: 216
+138: 212
+137: 211
+136: 210
+135: 128
+134: 143
+133: 183
+132: 142
+131: 182
+130: 144
+129: 154
+128: ok
+127: ok
+126: ok
+125: ok
+124: open unlink 0
+123: ok
+122: 90
+121: 89
+120: 88
+119: 87
+118: 86
+117: 85
+116: 84
+115: 83
+114: 82
+113: 81
+112: 80
+111: 79
+110: 78
+109: 77
+108: 76
+107: 75
+106: 74
+105: 73
+104: 72
+103: 71
+102: 70
+101: 69
+100: 68
+99: 67
+98: 66
+97: 65
+96: ok
+95: ok
+94: ok
+93: open unlink 0
+92: open unlink 0
+91: open unlink 0
+90: ok
+89: ok
+88: ok
+87: ok
+86: ok
+85: ok
+84: ok
+83: ok
+82: ok
+81: ok
+80: ok
+79: ok
+78: ok
+77: ok
+76: ok
+75: ok
+74: ok
+73: ok
+72: ok
+71: ok
+70: ok
+69: ok
+68: ok
+67: ok
+66: ok
+65: ok
+64: ok
+63: open unlink 0
+62: open unlink 0
+61: open unlink 0
+60: open unlink 0
+59: open unlink 0
+58: open unlink 0
+57: ok
+56: ok
+55: ok
+54: ok
+53: ok
+52: ok
+51: ok
+50: ok
+49: ok
+48: ok
+47: open unlink 0
+46: open unlink 0
+45: ok
+44: open unlink 0
+43: open unlink 0
+42: open unlink 0
+41: ok
+40: ok
+39: ok
+38: ok
+37: ok
+36: ok
+35: ok
+34: open unlink 0
+33: ok
+32: open unlink 0
+31: open unlink 0
+30: open unlink 0
+29: open unlink 0
+28: open unlink 0
+27: open unlink 0
+26: open unlink 0
+25: open unlink 0
+24: open unlink 0
+23: open unlink 0
+22: open unlink 0
+21: open unlink 0
+20: open unlink 0
+19: open unlink 0
+18: open unlink 0
+17: open unlink 0
+16: open unlink 0
+15: open unlink 0
+14: open unlink 0
+13: open unlink 0
+12: open unlink 0
+11: open unlink 0
+10: open unlink 0
+9: open unlink 0
+8: open unlink 0
+7: open unlink 0
+6: open unlink 0
+5: open unlink 0
+4: open unlink 0
+3: open unlink 0
+2: open unlink 0
+1: open unlink 0
+
+ valid chars = 73:213 213:73 73:73 33 35 36 37 38 39 40 41 45 48 49 50 51 52 53 54 55 56 57 64 97:65 98:66 99:67 100:68 101:69 102:70 103:71 104:72 105:73 106:74 107:75 108:76 109:77 110:78 111:79 112:80 113:81 114:82 115:83 116:84 117:85 118:86 119:87 120:88 121:89 122:90 94 95 96 123 125 126 127 135:128 132:142 134:143 130:144 145:146 148:153 129:154 156 155:157 158 159 164:165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 160:181 131:182 133:183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198:199 200 201 202 203 204 205 206 207 208:209 136:210 137:211 138:212 161:214 140:215 139:216 217 218 219 220 221 141:222 223 162:224 225 147:226 149:227 228:229 230 231:232 163:233 150:234 151:235 236:237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
diff --git a/examples/validchars/nwdos70.out b/examples/validchars/nwdos70.out
new file mode 100644
index 00000000000..b0dbf628531
--- /dev/null
+++ b/examples/validchars/nwdos70.out
@@ -0,0 +1,257 @@
+255: ok
+254: ok
+253: ok
+252: ok
+251: ok
+250: ok
+249: ok
+248: ok
+247: ok
+246: ok
+245: ok
+244: ok
+243: ok
+242: ok
+241: ok
+240: ok
+239: ok
+238: ok
+237: ok
+236: ok
+235: ok
+234: ok
+233: ok
+232: ok
+231: ok
+230: ok
+229: ok
+228: ok
+227: ok
+226: ok
+225: ok
+224: ok
+223: ok
+222: ok
+221: ok
+220: ok
+219: ok
+218: ok
+217: ok
+216: ok
+215: ok
+214: ok
+213: ok
+212: ok
+211: ok
+210: ok
+209: ok
+208: ok
+207: ok
+206: ok
+205: ok
+204: ok
+203: ok
+202: ok
+201: ok
+200: ok
+199: ok
+198: ok
+197: ok
+196: ok
+195: ok
+194: ok
+193: ok
+192: ok
+191: ok
+190: ok
+189: ok
+188: ok
+187: ok
+186: ok
+185: ok
+184: ok
+183: ok
+182: ok
+181: ok
+180: ok
+179: ok
+178: ok
+177: ok
+176: ok
+175: ok
+174: ok
+173: ok
+172: ok
+171: ok
+170: ok
+169: ok
+168: ok
+167: ok
+166: ok
+165: ok
+164: 165
+163: 85
+162: 79
+161: 73
+160: 65
+159: ok
+158: ok
+157: ok
+156: ok
+155: ok
+154: ok
+153: ok
+152: 89
+151: 85
+150: 85
+149: 79
+148: 153
+147: 79
+146: ok
+145: 146
+144: ok
+143: ok
+142: ok
+141: 73
+140: 73
+139: 73
+138: 69
+137: 69
+136: 69
+135: 128
+134: 143
+133: 65
+132: 142
+131: 65
+130: 69
+129: 154
+128: ok
+127: ok
+126: ok
+125: ok
+124: open unlink 0
+123: ok
+122: 90
+121: 89
+120: 88
+119: 87
+118: 86
+117: 85
+116: 84
+115: 83
+114: 82
+113: 81
+112: 80
+111: 79
+110: 78
+109: 77
+108: 76
+107: 75
+106: 74
+105: 73
+104: 72
+103: 71
+102: 70
+101: 69
+100: 68
+99: 67
+98: 66
+97: 65
+96: ok
+95: ok
+94: ok
+93: open unlink 0
+92: open unlink 0
+91: open unlink 0
+90: ok
+89: ok
+88: ok
+87: ok
+86: ok
+85: ok
+84: ok
+83: ok
+82: ok
+81: ok
+80: ok
+79: ok
+78: ok
+77: ok
+76: ok
+75: ok
+74: ok
+73: ok
+72: ok
+71: ok
+70: ok
+69: ok
+68: ok
+67: ok
+66: ok
+65: ok
+64: ok
+63: open unlink 0
+62: open unlink 0
+61: open unlink 0
+60: open unlink 0
+59: open unlink 0
+58: open unlink 0
+57: ok
+56: ok
+55: ok
+54: ok
+53: ok
+52: ok
+51: ok
+50: ok
+49: ok
+48: ok
+47: open unlink 0
+46: open unlink 0
+45: ok
+44: open unlink 0
+43: open unlink 0
+42: open unlink 0
+41: ok
+40: ok
+39: ok
+38: ok
+37: ok
+36: ok
+35: ok
+34: open unlink 0
+33: ok
+32: length 0
+31: open unlink 0
+30: open unlink 0
+29: open unlink 0
+28: open unlink 0
+27: open unlink 0
+26: open unlink 0
+25: open unlink 0
+24: open unlink 0
+23: open unlink 0
+22: open unlink 0
+21: open unlink 0
+20: open unlink 0
+19: open unlink 0
+18: open unlink 0
+17: open unlink 0
+16: open unlink 0
+15: open unlink 0
+14: open unlink 0
+13: open unlink 0
+12: open unlink 0
+11: open unlink 0
+10: open unlink 0
+9: open unlink 0
+8: open unlink 0
+7: open unlink 0
+6: open unlink 0
+5: open unlink 0
+4: open unlink 0
+3: open unlink 0
+2: open unlink 0
+1: open unlink 0
+
+ valid chars = 69:130 130:69 69:69 65:131 131:65 65:65 65:133 133:65 65:65 69:136 136:69 69:69 69:137 137:69 69:69 69:138 138:69 69:69 73:139 139:73 73:73 73:140 140:73 73:73 73:141 141:73 73:73 79:147 147:79 79:79 79:149 149:79 79:79 85:150 150:85 85:85 85:151 151:85 85:85 89:152 152:89 89:89 65:160 160:65 65:65 73:161 161:73 73:73 79:162 162:79 79:79 85:163 163:85 85:85 33 35 36 37 38 39 40 41 45 48 49 50 51 52 53 54 55 56 57 64 97:65 98:66 99:67 100:68 101:69 102:70 103:71 104:72 105:73 106:74 107:75 108:76 109:77 110:78 111:79 112:80 113:81 114:82 115:83 116:84 117:85 118:86 119:87 120:88 121:89 122:90 94 95 96 123 125 126 127 135:128 132:142 134:143 144 145:146 148:153 129:154 155 156 157 158 159 164:165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
diff --git a/examples/validchars/readme b/examples/validchars/readme
new file mode 100644
index 00000000000..6487fbd766a
--- /dev/null
+++ b/examples/validchars/readme
@@ -0,0 +1,101 @@
+Note: All files in this directory are DOS formatted (CRLF line terminator).
+
+!!! VIRUS WARNING !!! I do not know if VALIDCHR.COM is virus free !!!
+I think that my system is virus free here because I do not run any games
+or other copied software. I only run Shareware/Freeware etc. from CD-ROMs
+or from registered disks, however I do not use viral scanners because
+I have not registered any (I consider `having no sex' is better than
+`testing for AIDS on a regular basis', if you know what I mean).
+
+This is VALIDCHR, a little DOS program I wrote to create
+an apropriate `valid chars =' config parameter.
+It is freeware and is thought to be distributed freely with Samba.
+
+WARNING:
+ Your SMB driver may use another character map as the one VALIDCHR
+ sees. The only way you can tell this is that some file names fail.
+ Under Win95 everything is fine, though.
+
+Usage:
+ c:
+ mkdir junk_dir
+ cd junk_dir
+ a:validchr > a:output.log
+ cd ..
+ rmdir junk_dir
+
+Siedeffects:
+ Files named *.TST may be deleted.
+
+Verification:
+ For diagnostic purpose you can run VALIDCHR on a Samba mounted drive.
+ Then you can use unix diff to compare the output of the network and
+ the hard drive. These two outputs usually differ! However there
+ should be few differences. I get following on Win95 (c: visa e:)
+ 104c104
+ < 152: length 0
+ ---
+ > 152: 95
+ (diff line for `valid chars =' deleted because it's uninteresting)
+ You can see, `y diaresis' can be mapped on the network drive while
+ it cannot be mapped on the hard drive. Everything else is identical.
+ However this gives a hint that one can improve the mapping.
+
+Bugs:
+ Yes, probably some.
+
+
+VALIDCHR must be run on the system which character mapping should be probed.
+It must be run on the hard drive for this. VALIDCHR ALTERS THE CURRENT
+DIRECTORY AND REMOVES SOME FILES, SO ALWAYS RUN IT IN A junk DIRECTORY !!!
+You should redirect the output of VALIDCHR. At the end of the output is a
+line like
+ valid chars = x:y y:x x:x ... a:b c ...
+which is suitable for your smb.conf file. (you should remove the DOS CR
+character, because DOS uses CRLF while Unix uses LF only.)
+
+Note that some mappings at the beginning of the `valid chars =' line like
+A:B B:A B:B
+might look a little bit strange to you, however sometimes character A
+has to be mapped to character B independently of a default mapping
+to uppercase or lowercase while character B must not be touched. I found
+this out the hard way ... Consider it a crude workaround, because Samba
+lacks the possibility to map characters in one direction only!
+
+VALIDCHR usually issues one warning for character 32.
+You may ignore these and any other warnings.
+
+VALIDCHR does not test for character NUL (this is the directory end marker).
+
+validchr.c is the source code to validchr.com
+ You may do anything with the source code (copy, change, sell, burn)
+validchr.com is a Borland C compiled binary.
+ Beware, it may contain a virus (if my system contains one).
+nwdos70.out is the output of an VALIDCHR-run under Novell DOS 7.0
+ while no codepage (no display.sys) was active.
+msdos70.out is the output of an VALIDCHR-run under MS-DOS 7.0 (Win95 DOS)
+ while codepage 850 was active.
+
+I have no other MS-DOS systems at home currently.
+(I have access to MS-DOS 3.0, 3.2, 3.3, 5.0 and 6.22, however I have no time
+ to run VALIDCHR there)
+
+Some words to the output
+(for people not fammiliar with programming language C):
+
+probed_char: [text] mapped_char
+
+probed_char is the character probed to be written to disk
+text may be empty or contain:
+ open File could not be opened.
+ close File could not be closed (should not happen)
+ length File name was shortened (usually occurs on SPC)
+ unlink File cannot be unlinked (usually when open fails)
+mapped_char is the character which is used by MS-DOS in the directory
+ This is usually the uppercase character.
+ The mapped character is 0 if something failed (you may say
+ that the character is not supported)
+
+The last line in the output is documented in the smb.conf manual page ;)
+
+tino@augsburg.net
diff --git a/examples/validchars/validchr.c b/examples/validchars/validchr.c
new file mode 100644
index 00000000000..415546cb841
--- /dev/null
+++ b/examples/validchars/validchr.c
@@ -0,0 +1,123 @@
+/* by tino@augsburg.net
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <dirent.h>
+
+unsigned char
+test(void)
+{
+ DIR *dir;
+ struct dirent *dp;
+ unsigned char c;
+
+ if ((dir=opendir("."))==0)
+ {
+ perror("open .");
+ return 0;
+ }
+ c = 0;
+ while ((dp=readdir(dir))!=0)
+ {
+ size_t len;
+
+ len = strlen(dp->d_name);
+ if (len<4)
+ continue;
+ if (strcmp(dp->d_name+len-4, ".TST"))
+ continue;
+ if (len!=5)
+ {
+ fprintf(stderr, "warning: %s\n", dp->d_name);
+ printf(" length");
+ continue;
+ }
+ if (c)
+ printf(" double%d\n", c);
+ c = dp->d_name[0];
+ }
+ if (closedir(dir))
+ perror("close .");
+ return c;
+}
+
+int
+main(void)
+{
+ char name[256];
+ unsigned char map[256], upper[256], lower[256];
+ int i, j, c;
+ FILE *fd;
+
+ if (test())
+ {
+ printf("There are *.TST files, please remove\n");
+ return 0;
+ }
+ for (i=0; ++i<256; )
+ {
+ lower[i] = i;
+ upper[i] = 0;
+ }
+ for (i=256; --i; )
+ {
+ map[i] = i;
+ strcpy(name, "..TST");
+ name[0] = i;
+ printf("%d:", i);
+ if ((fd=fopen(name, "w"))==0)
+ printf(" open");
+ else
+ fclose(fd);
+ c = test();
+ if (unlink(name))
+ printf(" unlink");
+ if (c==i)
+ printf(" ok");
+ else
+ printf(" %d", c);
+ printf("\n");
+ if (c!=i)
+ {
+ upper[c]++;
+ lower[c] = i;
+ }
+ map[i] = c;
+ }
+
+ /* Uppercase characters are detected above on:
+ * The character is mapped to itself and there is a
+ * character which maps to it.
+ * Lowercase characters are the lowest character pointing to another one.
+ * Else it is a one way character.
+ *
+ * For this reason we have to process the list
+ * 1) for 'one way' characters
+ * 'one way' is something which is no upper and no lower character.
+ * This is an awful, crude and ugly hack due to missing Samba support.
+ * 2) for true uppercase/lowercase characters
+ * 3) for standalone characters
+ * Note that there might be characters which do not fall into 1 to 3.
+ */
+ printf("\n valid chars =");
+ for (i=0; ++i<256; )
+ if (map[i] && map[i]!=i && lower[map[i]]!=i)
+ {
+ if (!upper[i])
+ printf(" %d:%d %d:%d %d:%d", /*1*/
+ map[i], i, i, map[i], map[i], map[i]);
+ else
+ fprintf(stderr, "ignoring map %d->%d because of %d->%d\n",
+ lower[i], i, i, map[i]);
+ }
+ for (i=0; ++i<256; )
+ if (map[i] && map[i]==i)
+ if (upper[i])
+ printf(" %d:%d", lower[i], i); /*2*/
+ else
+ printf(" %d", i); /*3*/
+ printf("\n");
+ return 0;
+}
diff --git a/examples/validchars/validchr.com b/examples/validchars/validchr.com
new file mode 100644
index 00000000000..ce159568369
--- /dev/null
+++ b/examples/validchars/validchr.com
Binary files differ
diff --git a/packaging/README b/packaging/README
new file mode 100644
index 00000000000..1adb809ae5a
--- /dev/null
+++ b/packaging/README
@@ -0,0 +1,34 @@
+Copyright (C) 1997 - Samba-Team
+Date: August 19, 1997
+Updates: First Release - 19970819
+===============================================================================
+
+Note:
+=====
+This directory is a public repository for platform specific files including
+build files for binary package distributions for specific operating systems
+as well as for source file distribution packages for those systems.
+
+As such, the files contained here are intended for use only by those wishing
+to build their own distribution packages and are NOT considered suitable
+material for anyone who wants to just install Samba from the pristine source
+files contained under the ~/source directory.
+
+All contributions / modifications / additions / etc. to the packaging files
+should be sent to samba-bugs@samba.anu.edu.au with the subject marked:
+ PACKAGING: [add|mod|contrib] Your subject.
+
+Should you, or anyone you know of, have package build instructions and/or files
+that may be of use to the wider community of Samba users please mail the above
+account with subject: PACKAGING: [avail] OS xxxxxxxxxx
+where xxxxxxxxxx is the operating system platform that may be contributed.
+
+We will contact the person who is offering to contribute package build details
+to ensure that their contribution can be included in the official Samba sources.
+
+In the event that anyone wishes to contribute package build information please
+indicate in your response how we may access a suitable system to ensure our
+ability to keep the binary distribution itself current with the released source.
+
+The future of cooperatively developed software such as Samba depends on the
+willingness of all partners to share the fruit of their labours.
diff --git a/packaging/SGI/README b/packaging/SGI/README
new file mode 100644
index 00000000000..17c5780067b
--- /dev/null
+++ b/packaging/SGI/README
@@ -0,0 +1,39 @@
+This directory contains sample files for using Samba on an IRIX
+system. These were taken from a system running IRIX 6.2. The
+client machines were running Win95 and connected via the Ethernet
+using TCP/IP and DNS. Consult the Samba documentation for tips
+on configuring Samba "properly"; this smb.conf file is very simple.
+Consult the Microsoft help/documentation to understand how to
+configure the networking support on the PC clients (Win95, WfW,
+etc.).
+
+This distribution is configured so that various Samba configuration,
+binary, and log files are placed in the /usr/samba file hierarchy.
+Man pages are placed in the /usr/share/catman/u_man hierarchy.
+
+The version number of the distribution is a 10 digit number that
+is created from the samba version number plus a release number.
+Each section of the samba version number forms 2 digits of the
+version number (with leading zeros if necessary).
+
+samba version 1.9.16 first release would become 0109160000
+samba version 1.9.16p9 first release would become 0109160900
+samba version 1.9.16p9 second release would become 0109160901
+
+You can enable all printers on your system to be used by samba
+by running the script /usr/samba/mkprintcap.sh
+
+This distribution automatically configures samba to run as deamons
+by the script /etc/init.d/samba and the file /etc/config/samba
+(used by chkconfig). If you would prefer to have samba started by
+inetd you can run the script /usr/samba/inetd.sh.
+
+To create a Samba distribution you must have the Documenter's WorkBench
+package installed to format the manual pages. In addition you need
+to have the Software Packager software (inst_dev) installed to
+generate the inst images.
+
+From /usr/samba/packaging/SGI directory run the mkrelease.sh script.
+This script uses Perl to generate the Makefile with the proper defines.
+The package files will be placed in ./bins
+
diff --git a/packaging/SGI/inetd.sh b/packaging/SGI/inetd.sh
new file mode 100755
index 00000000000..8c4c6cb8d8b
--- /dev/null
+++ b/packaging/SGI/inetd.sh
@@ -0,0 +1,29 @@
+#! /bin/sh
+#
+# kill any running samba processes
+#
+/etc/killall smbd nmbd
+chkconfig samba off
+
+#
+# add SAMBA deamons to inetd.conf
+#
+cp /etc/inetd.conf /etc/inetd.O
+sed -e "/^netbios/D" -e "/^#SAMBA/D" /etc/inetd.O > /etc/inetd.conf
+echo '#SAMBA services' >> /etc/inetd.conf
+echo netbios-ssn stream tcp nowait root /usr/samba/bin/smbd smbd >> /etc/inetd.conf
+echo netbios-ns dgram udp wait root /usr/samba/bin/nmbd nmbd -S >> /etc/inetd.conf
+
+#
+# add SAMBA service ports to /etc/services
+#
+cp /etc/services /etc/services.O
+sed -e "/^netbios/D" -e "/^#SAMBA/D" /etc/services.O > /etc/services
+echo '#SAMBA services' >> /etc/services
+echo 'netbios-ns 137/udp # SAMBA' >> /etc/services
+echo 'netbios-ssn 139/tcp # SAMBA' >> /etc/services
+
+#
+# restart inetd to start SAMBA
+#
+/etc/killall -HUP inetd
diff --git a/packaging/SGI/legal_notice.html b/packaging/SGI/legal_notice.html
new file mode 100644
index 00000000000..fdb76456289
--- /dev/null
+++ b/packaging/SGI/legal_notice.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<HTML VERSION="2.0">
+<HEAD>
+<TITLE>Silicon Graphics Freeware Legal Notice</TITLE>
+</HEAD>
+
+<BODY>
+<H1><A NAME="LEGAL">Silicon Graphics Freeware Legal Notice</A></H1>
+<HR>
+Copyright 1995, Silicon Graphics, Inc. -- ALL RIGHTS RESERVED
+<P>
+You may copy, modify, use and distribute this software, (i)
+provided that you include the entirety of this reservation of
+rights notice in all such copies, and (ii) you comply with any
+additional or different obligations and/or use restrictions
+specified by any third party owner or supplier of the software
+in other notices that may be included with the software.
+
+<P>
+SGI DISCLAIMS ALL WARRANTIES WITH RESPECT TO THIS SOFTWARE,
+EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION,
+ALL WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE OR NONINFRINGEMENT. SGI SHALL NOT BE LIABLE FOR ANY
+SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING,
+WITHOUT LIMITATION, LOST REVENUES, LOST PROFITS, OR LOSS OF
+PROSPECTIVE ECONOMIC ADVANTAGE, RESULTING FROM THE USE OR MISUSE
+OF THIS SOFTWARE.
+
+<P>
+U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND:
+
+<P>
+
+Use, duplication or disclosure by the Government is subject to
+restrictions as set forth in FAR 52.227.19(c)(2) or subparagraph
+(c)(1)(ii) of the Rights in Technical Data and Computer Software
+clause at DFARS 252.227-7013 and/or in similar or successor
+clauses in the FAR, or the DOD or NASA FAR Supplement.
+Unpublished - rights reserved under the Copyright Laws of United
+States. Contractor/manufacturer is Silicon Graphics, Inc., 2011
+N. Shoreline Blvd. Mountain View, CA 94039-7311.
+
+<H3><A NAME="SUPPORT">Product Support</A></H3>
+
+<P>
+Freeware products are not supported by Silicon Graphics or any
+of its support providers. The software contained in this package
+is made available through the generous efforts of their authors.
+Although they are interested in your feedback, they are under no
+obligation to address bugs, enhancements, or answer questions.
+
+</BODY>
+</HTML>
diff --git a/packaging/SGI/makefile.pl b/packaging/SGI/makefile.pl
new file mode 100755
index 00000000000..0857ecd909f
--- /dev/null
+++ b/packaging/SGI/makefile.pl
@@ -0,0 +1,24 @@
+#!/usr/bin/perl
+
+while (<>) {
+ if (/^BASEDIR =/) {
+ print "BASEDIR = /usr/samba\n";
+ }
+ elsif (/^MANDIR =/) {
+ print "MANDIR = /usr/share/man\n";
+ }
+ elsif (/^# FOR SGI IRIX 6/) {
+ print;
+ $a = <>;
+ print $a;
+ <>;
+ <>;
+ <>;
+ print "FLAGSM = -DSGI5 -DSHADOW_PWD -DHAVE_TIMEZONE -DFAST_SHARE_MODES\n";
+ print "LIBSM =\n";
+ print "FLAGS1 = -O -n32 -g3 -OPT:fold_arith_limit=1256\n";
+ }
+ else {
+ print;
+ }
+}
diff --git a/packaging/SGI/mkman b/packaging/SGI/mkman
new file mode 100755
index 00000000000..fedeb4d7196
--- /dev/null
+++ b/packaging/SGI/mkman
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+if [ ! -d catman ]; then
+ mkdir catman
+fi
+
+# if you wish to make html versions of the man pages then uncomment
+# the following section and the "rman" command below
+#
+# if [ ! -d html ]; then
+# mkdir html
+# fi
+
+FILES="*.?"
+
+cd ../../docs
+for FILE in $FILES ; do
+ neqn $FILE | tbl | nroff -man > ../packaging/SGI/catman/`basename $FILE`
+ compress -f ../packaging/SGI/catman/`basename $FILE`
+# rman -f html -r "%s.%s.html" $FILE > ../packaging/SGI/html/$FILE.html
+done
+cd ../packaging/SGI
diff --git a/packaging/SGI/mkprintcap.sh b/packaging/SGI/mkprintcap.sh
new file mode 100755
index 00000000000..f610e757f06
--- /dev/null
+++ b/packaging/SGI/mkprintcap.sh
@@ -0,0 +1,15 @@
+#! /bin/sh
+#
+# create printcap file
+#
+if [ -r /usr/samba/printcap ]
+then
+ cp /usr/samba/printcap /usr/samba/printcap.O
+fi
+
+echo "#" > /usr/samba/printcap
+echo "# Samba printcap file" >> /usr/samba/printcap
+echo "# Alias names are separated by |, any name with spaces is taken as a comment" >> /usr/samba/printcap
+echo "#" >> /usr/samba/printcap
+lpstat -a | sed -e "s/ .*//" >> /usr/samba/printcap
+
diff --git a/packaging/SGI/mkrelease.sh b/packaging/SGI/mkrelease.sh
new file mode 100755
index 00000000000..052a4d8ddb8
--- /dev/null
+++ b/packaging/SGI/mkrelease.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+# create the catman versions of the manual pages
+#
+echo Making manual pages
+./mkman
+
+# build the sources
+#
+echo Making binaries
+./makefile.pl ../../source/Makefile > Makefile
+cd ../../source
+# make -f ../packaging/SGI/Makefile clean
+make -f ../packaging/SGI/Makefile all
+cd ../packaging/SGI
+
+# generate the packages
+#
+echo Generating Inst Packages
+
+if [ ! -d bins ]; then
+ mkdir bins
+fi
+
+/usr/sbin/gendist -rbase / -sbase ../.. -idb samba.idb -spec samba.spec -dist ./bins -all
+
diff --git a/packaging/SGI/printcap b/packaging/SGI/printcap
new file mode 100644
index 00000000000..b67b9cb167c
--- /dev/null
+++ b/packaging/SGI/printcap
@@ -0,0 +1,5 @@
+#
+# Sample printcap file
+# Alias names are separated by |, any name with spaces is taken as a comment
+#
+lp4js|lp12|LaserJet on the third floor by the coffee machine
diff --git a/packaging/SGI/psfixes.pl b/packaging/SGI/psfixes.pl
new file mode 100755
index 00000000000..c64b67c8d40
--- /dev/null
+++ b/packaging/SGI/psfixes.pl
@@ -0,0 +1,28 @@
+#!/usr/bin/perl
+
+$found_vm = 0;
+
+while (<>) {
+ if (not $found_vm) {
+ if (not /^%/) {
+ if (/^%%Title:/) {
+ s/. $/ /;
+ print;
+ }
+ else {
+ if (/^\/VM?/) {
+ print "/VM? { pop } bind def \n";
+ $found_vm = 1;
+ }
+ else {
+ print;
+ }
+ }
+ }
+ }
+ else {
+ if (/def /) {
+ $found_vm = 0;
+ }
+ }
+}
diff --git a/packaging/SGI/relnotes.html b/packaging/SGI/relnotes.html
new file mode 100644
index 00000000000..eea4cefd0b6
--- /dev/null
+++ b/packaging/SGI/relnotes.html
@@ -0,0 +1,233 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>Samba Release Notes</TITLE>
+</HEAD>
+<BODY>
+
+<H1>Samba Release Notes</H1>
+
+<P>
+<HR></P>
+
+<H2>Table of Contents</H2>
+
+<MENU>
+<LI><B><A HREF="#WHATIS">What is Samba?</A></B> </LI>
+
+<LI><B><A HREF="#Support">Support Policy</A> </B></LI>
+
+<LI><B><A HREF="#Installation">Installation Information</A> </B></LI>
+
+<LI><B><A HREF="legal_notice.html">Silicon
+Graphics Legal Notice</A> </B></LI>
+
+<LI><B><A HREF="#AUTHORNOTES">Author's Notice(s)</A> </B></LI>
+
+<LI><B><A HREF="#Documentation">Documentation Information</A> </B></LI>
+</MENU>
+
+<P>
+<HR></P>
+
+<H2><A NAME="WHATIS"></A>What is Samba?</H2>
+
+<P>Samba is an SMB client and server for Unix. It makes it possible for
+client machines running Windows 95 and Windows for Workgroups to access
+files and/or print services on a Unix system. Samba includes an SMB server
+to provide LanManager-style file and print services to PCs, a Netbios (RFC10001/1002)
+name server, and an FTP-like client application for accessing PC resources
+from Unix. </P>
+
+<P>To make Samba work you'll need to configure your server host to run
+<B>smbd</B> and <B>nmbd</B> whenever you connect to a certain Internet
+port from the client machine. <B>Smbd</B> and <B>nmbd</B> can be started
+either as daemons or from inetd.</P>
+
+<P>By default <B>smbd</B> and <B>nmbd</B> are started as daemons by the
+file <I>/etc/init.d/samba</I> in conjunction with the chkconfig variable
+samba being set to on. If you set chkconfig samba off then the deamons
+will not be automatically started on reboot. In this case you must type
+the following at a shell prompt to start samba after a reboot: </P>
+
+<PRE><B> chkconfig samba on
+ /etc/init.d/samba start</B>
+</PRE>
+
+<P>If you make changes to your configuration files, <B>smbd</B> and <B>nmbd</B>
+may be restarted by typing the following at a shell prompt: </P>
+
+<PRE><B> /etc/init.d/samba start</B>
+</PRE>
+
+<P><B>smbd</B> and <B>nmbd</B> may be killed by typing the following at
+a shell prompt: </P>
+
+<PRE><B> /etc/init.d/samba stop</B>
+</PRE>
+
+<P>To have <B>smbd</B> and <B>nmbd</B> started by inetd you can execute
+the shell script <I>/usr/samba/inetd.sh</I> to automatically configure
+the various files and start the processes. This shell script first kills
+any running <B>smbd</B> and <B>nmbd</B> processes. It then removes any
+existing entries for &quot;netbios*&quot; from <I>/etc/inetd.conf</I> and
+adds the following lines </P>
+
+<PRE><B> netbios-ssn stream tcp nowait root /usr/samba/bin/smbd smbd
+ netbios-ns dgram udp wait root /usr/samba/bin/nmbd nmbd -S</B>
+</PRE>
+
+<P>It then removes any existing entries for &quot;netbios*&quot; from <I>/etc/services</I>
+and adds the following lines </P>
+
+<PRE><B> netbios-ns 137/udp # SAMBA
+ netbios-ssn 139/tcp # SAMBA</B>
+</PRE>
+
+<P><I>Inetd</I> is then restarted by executing:</P>
+
+<PRE><B> /etc/killall -HUP inetd</B>
+</PRE>
+
+<P>If you make changes to your configuration files, <B>smbd</B> and <B>nmbd</B>
+may be restarted by typing the following at a shell prompt: </P>
+
+<PRE><B> /etc/killall smbd nmbd
+ /etc/killall -HUP inetd</B>
+</PRE>
+
+<H3><A NAME="AUTHORNOTES"></A>Author's Notice(s):</H3>
+
+<P>The author of this product is: Andrew Tridgell </P>
+
+<P>Samba is distributed freely under the <A HREF="GNU_COPYING.txt">GNU
+public license</A>. </P>
+
+<H3><A NAME="Support"></A>Support:</H3>
+
+<P>The software in this package is considered unsupported by Silicon Graphics.
+Neither the authors or Silicon Graphics are compelled to help resolve problems
+you may encounter in the installation, setup, or execution of this software.
+To be more to the point, if you call us with an issue regarding products
+in the Freeware package, we'll have to gracefully terminate the call. The
+<A HREF="http://samba.anu.edu.au/pub/samba/">
+Samba Web Page</A> has a listing of companies and individuals that offer
+commercial support for a fee.
+</P>
+
+<H2><A NAME="Installation"></A>Installation Information</H2>
+
+<P>Samba includes these subsystems: </P>
+
+<TABLE>
+<TR>
+<TD ALIGN=LEFT><B>samba.sw.base</B> (<I>default</I>)</TD>
+
+<TD>Execution environment for Samba.</TD>
+</TR>
+
+<TR>
+<TD ALIGN=left><B>samba.man.manpages</B>(<I>default</I>)</TD>
+
+<TD>Samba's online manual pages (preformatted).</TD>
+</TR>
+
+<TR>
+<TD ALIGN=LEFT VALIGN=TOP><B>samba.man.doc</B> (<I>default</I>)</TD>
+
+<TD>Samba documentation: hints on installation and configuration, an FAQ
+(Frequently Asked Questions), help in diagnosing problems, etc..</TD>
+</TR>
+
+<TR>
+<TD ALIGN=left><B>samba.man.relnotes</B> (<I>default</I>) </TD>
+
+<TD>Samba online release notes.</TD>
+</TR>
+
+<TR>
+<TD ALIGN=LEFT VALIGN=TOP><B>samba.src.samba</B> </TD>
+
+<TD>The Samba software distribution from which this product was
+built (including the packaging/SGI directory which will allow this distribution
+to be rebuilt).</TD>
+</TR>
+</TABLE>
+
+<H3>Installation Method</H3>
+
+<P>All of the subsystems for Samba can be installed using IRIX. You do
+not need to use the miniroot. Refer to the <I>Software Installation Administrator's
+Guide</I> for complete installation instructions. </P>
+
+<H3>Prerequisites</H3>
+
+<P>Your workstation must be running IRIX 5.3 or later in order to use this
+product. </P>
+
+<H3>Configuration Files</H3>
+
+<P>Because configuration files often contain modifications, inst treats
+them specially during the installation process. If they have not been modified,
+inst removes the old file and installs the new version during software
+updates. For configuration files that have been modified, the new version
+is installed and the old version is renamed by adding the suffix .O (for
+older) to the name. The no-suffix version contains changes that are required
+for compatibility with the rest of the newly installed software, that increase
+functionality, or that fix bugs. You should use diff(1) or gdiff(1) to
+compare the two versions of the files and transfer information that you
+recognize as machine or site-specific from the .O version to the no-suffix
+version. </P>
+
+<DL>
+<DT><B>/usr/samba/lib/smb.conf</B> </DT>
+
+<DD>Configuration definitions for the <B>smbd</B> program; the SMB server
+process. The default configuration sets up password-based access to home
+directories on a machine as well as open access to to all printers and
+/tmp. The workgroup is set by default to &quot;workgroup&quot;. It is highly
+recommended that administrators review the content of this file when installing
+Samba for the first time.</DD>
+
+<DT><B>/usr/samba/printcap</B> </DT>
+
+<DD>A file that specifies the available printers on a system. It is included
+as an example; administrators may want to replace it or override the reference
+to it in the <B>smb.conf</B> file. The script <B>/usr/samba/mkprintcap.sh</B>
+was used by inst to create a printcap file that contains all printers on
+your system. You may wish to remove some printers or add a comment to each
+printer name to describe its location.</DD>
+</DL>
+
+<H2><A NAME="Documentation"></A>Documentation Information</H2>
+
+<P>Preformatted manual pages are installed by default as are the contents
+of the <B>docs</B> directory from the Samba distribution; consult <I>samba</I>(7)
+for an introduction. </P>
+
+<P>There is a mailing list for discussion of Samba. To subscribe send mail
+to <A HREF="mailto:listproc@samba.anu.edu.au">listproc@samba.anu.edu.au</A>
+with a body of &quot;subscribe samba Your Name&quot; </P>
+
+<P>To send mail to everyone on the list mail to <A HREF="mailto:samba@samba.anu.edu.au">samba@samba.anu.edu.au</A>.
+</P>
+
+<P>There is also an announcement mailing list where new versions are announced.
+To subscribe send mail to <A HREF="mailto:listproc@samba.anu.edu.au">listproc@samba.anu.edu.au</A>
+with a body of &quot;subscribe samba-announce Your Name&quot;. All announcements
+also go to the samba list. </P>
+
+<P>You might also like to look at the Usenet news group <A HREF="news:comp.protocols.smb">comp.protocols.smb</A>
+as it often contains lots of useful info and is frequented by lots of Samba
+users. The newsgroup was initially setup by people on the Samba mailing
+list. It is not, however, exclusive to Samba, it is a forum for discussing
+the SMB protocol (which Samba implements). </P>
+
+<P>A Samba WWW site has been setup with lots of useful info. Connect to:
+<A HREF="http://samba.anu.edu.au/pub/samba/">http://samba.anu.edu.au/pub/samba/</A>.
+It is maintained by Paul Blackman (thanks Paul!). You can contact him at
+<A HREF="mailto:ictinus@lake.canberra.edu.au">ictinus@lake.canberra.edu.au</A>.
+</P>
+
+</BODY>
+</HTML>
diff --git a/packaging/SGI/samba.config b/packaging/SGI/samba.config
new file mode 100644
index 00000000000..b3d86404ab5
--- /dev/null
+++ b/packaging/SGI/samba.config
@@ -0,0 +1 @@
+on
diff --git a/packaging/SGI/samba.idb b/packaging/SGI/samba.idb
new file mode 100644
index 00000000000..358f3499ca9
--- /dev/null
+++ b/packaging/SGI/samba.idb
@@ -0,0 +1,432 @@
+f 0644 root sys etc/config/samba packaging/SGI/samba.config samba.sw.base config(update)
+f 0755 root sys etc/init.d/samba packaging/SGI/samba.rc samba.sw.base
+l 0000 root sys etc/rc0.d/K39samba packaging/SGI samba.sw.base symval(../init.d/samba)
+l 0000 root sys etc/rc2.d/S81samba packaging/SGI samba.sw.base symval(../init.d/samba)
+d 0755 root sys usr/relnotes/samba packaging/SGI samba.man.relnotes
+f 0644 root sys usr/relnotes/samba/GNU_COPYING.txt COPYING samba.man.relnotes
+f 0644 root sys usr/relnotes/samba/legal_notice.html packaging/SGI/legal_notice.html samba.man.relnotes
+f 0644 root sys usr/relnotes/samba/samba-relnotes.html packaging/SGI/relnotes.html samba.man.relnotes
+d 0755 root sys usr/samba packaging/SGI samba.sw.base
+f 0444 root sys usr/samba/README packaging/SGI/README samba.sw.base
+d 0755 root sys usr/samba/bin packaging/SGI samba.sw.base
+f 0755 root sys usr/samba/bin/addtosmbpass source/addtosmbpass samba.sw.base
+f 0775 root sys usr/samba/bin/nmbd source/nmbd samba.sw.base
+f 0755 root sys usr/samba/bin/nmblookup source/nmblookup samba.sw.base
+f 0644 root sys usr/samba/bin/psfixes.pl packaging/SGI/psfixes.pl samba.sw.base
+f 0755 root sys usr/samba/bin/sambalp packaging/SGI/sambalp samba.sw.base
+f 0755 root sys usr/samba/bin/smbclient source/smbclient samba.sw.base
+f 0775 root sys usr/samba/bin/smbd source/smbd samba.sw.base
+f 4555 root sys usr/samba/bin/smbpasswd source/smbpasswd samba.sw.base
+f 0755 root sys usr/samba/bin/smbprint packaging/SGI/smbprint samba.sw.base
+f 0755 root sys usr/samba/bin/smbrun source/smbrun samba.sw.base
+f 0755 root sys usr/samba/bin/smbstatus source/smbstatus samba.sw.base
+f 0755 root sys usr/samba/bin/smbtar source/smbtar samba.sw.base
+f 0775 root sys usr/samba/bin/testparm source/testparm samba.sw.base
+f 0775 root sys usr/samba/bin/testprns source/testprns samba.sw.base
+d 0755 root sys usr/samba/docs docs samba.man.doc
+f 0644 root sys usr/samba/docs/Application_Serving.txt docs/Application_Serving.txt samba.man.doc
+f 0644 root sys usr/samba/docs/BROWSING.txt docs/BROWSING.txt samba.man.doc
+f 0644 root sys usr/samba/docs/BUGS.txt docs/BUGS.txt samba.man.doc
+f 0644 root sys usr/samba/docs/DIAGNOSIS.txt docs/DIAGNOSIS.txt samba.man.doc
+f 0644 root sys usr/samba/docs/DNIX.txt docs/DNIX.txt samba.man.doc
+f 0644 root sys usr/samba/docs/DOMAIN.txt docs/DOMAIN.txt samba.man.doc
+f 0644 root sys usr/samba/docs/DOMAIN_CONTROL.txt docs/DOMAIN_CONTROL.txt samba.man.doc
+f 0644 root sys usr/samba/docs/ENCRYPTION.txt docs/ENCRYPTION.txt samba.man.doc
+f 0644 root sys usr/samba/docs/Faxing.txt docs/Faxing.txt samba.man.doc
+f 0644 root sys usr/samba/docs/GOTCHAS.txt docs/GOTCHAS.txt samba.man.doc
+f 0644 root sys usr/samba/docs/HINTS.txt docs/HINTS.txt samba.man.doc
+f 0644 root sys usr/samba/docs/INSTALL.sambatar docs/INSTALL.sambatar samba.man.doc
+f 0644 root sys usr/samba/docs/MIRRORS.txt docs/MIRRORS.txt samba.man.doc
+f 0644 root sys usr/samba/docs/NT4_PlainPassword.reg docs/NT4_PlainPassword.reg samba.man.doc
+f 0644 root sys usr/samba/docs/NetBIOS.txt docs/NetBIOS.txt samba.man.doc
+f 0644 root sys usr/samba/docs/OS2-Client-HOWTO.txt docs/OS2-Client-HOWTO.txt samba.man.doc
+f 0644 root sys usr/samba/docs/PROJECTS docs/PROJECTS samba.man.doc
+f 0644 root sys usr/samba/docs/Passwords.txt docs/Passwords.txt samba.man.doc
+f 0644 root sys usr/samba/docs/Printing.txt docs/Printing.txt samba.man.doc
+f 0644 root sys usr/samba/docs/README.DCEDFS docs/README.DCEDFS samba.man.doc
+f 0644 root sys usr/samba/docs/README.jis docs/README.jis samba.man.doc
+f 0644 root sys usr/samba/docs/README.sambatar docs/README.sambatar samba.man.doc
+f 0644 root sys usr/samba/docs/SCO.txt docs/SCO.txt samba.man.doc
+f 0644 root sys usr/samba/docs/SMBTAR.notes docs/SMBTAR.notes samba.man.doc
+f 0644 root sys usr/samba/docs/Speed.txt docs/Speed.txt samba.man.doc
+f 0644 root sys usr/samba/docs/Support.txt docs/Support.txt samba.man.doc
+f 0644 root sys usr/samba/docs/THANKS docs/THANKS samba.man.doc
+f 0644 root sys usr/samba/docs/Tracing.txt docs/Tracing.txt samba.man.doc
+f 0644 root sys usr/samba/docs/UNIX-SMB.txt docs/UNIX-SMB.txt samba.man.doc
+f 0644 root sys usr/samba/docs/UNIX_INSTALL.txt docs/UNIX_INSTALL.txt samba.man.doc
+f 0644 root sys usr/samba/docs/Win95.txt docs/Win95.txt samba.man.doc
+f 0644 root sys usr/samba/docs/Win95_PlainPassword.reg docs/Win95_PlainPassword.reg samba.man.doc
+f 0644 root sys usr/samba/docs/WinNT.txt docs/WinNT.txt samba.man.doc
+f 0644 root sys usr/samba/docs/announce docs/announce samba.man.doc
+d 0755 root sys usr/samba/docs/faq docs/faq samba.man.doc
+f 0644 root sys usr/samba/docs/faq/Samba-Server-FAQ-1.html docs/faq/Samba-Server-FAQ-1.html samba.man.doc
+f 0644 root sys usr/samba/docs/faq/Samba-Server-FAQ-2.html docs/faq/Samba-Server-FAQ-2.html samba.man.doc
+f 0644 root sys usr/samba/docs/faq/Samba-Server-FAQ.html docs/faq/Samba-Server-FAQ.html samba.man.doc
+f 0644 root sys usr/samba/docs/faq/Samba-Server-FAQ.sgml docs/faq/Samba-Server-FAQ.sgml samba.man.doc
+f 0644 root sys usr/samba/docs/faq/Samba-meta-FAQ-1.html docs/faq/Samba-meta-FAQ-1.html samba.man.doc
+f 0644 root sys usr/samba/docs/faq/Samba-meta-FAQ-2.html docs/faq/Samba-meta-FAQ-2.html samba.man.doc
+f 0644 root sys usr/samba/docs/faq/Samba-meta-FAQ-3.html docs/faq/Samba-meta-FAQ-3.html samba.man.doc
+f 0644 root sys usr/samba/docs/faq/Samba-meta-FAQ-4.html docs/faq/Samba-meta-FAQ-4.html samba.man.doc
+f 0644 root sys usr/samba/docs/faq/Samba-meta-FAQ-5.html docs/faq/Samba-meta-FAQ-5.html samba.man.doc
+f 0644 root sys usr/samba/docs/faq/Samba-meta-FAQ-6.html docs/faq/Samba-meta-FAQ-6.html samba.man.doc
+f 0644 root sys usr/samba/docs/faq/Samba-meta-FAQ.html docs/faq/Samba-meta-FAQ.html samba.man.doc
+f 0644 root sys usr/samba/docs/faq/Samba-meta-FAQ.sgml docs/faq/Samba-meta-FAQ.sgml samba.man.doc
+f 0644 root sys usr/samba/docs/faq/Samba-meta-FAQ.txt docs/faq/Samba-meta-FAQ.txt samba.man.doc
+f 0644 root sys usr/samba/docs/faq/sambafaq-1.html docs/faq/sambafaq-1.html samba.man.doc
+f 0644 root sys usr/samba/docs/faq/sambafaq-2.html docs/faq/sambafaq-2.html samba.man.doc
+f 0644 root sys usr/samba/docs/faq/sambafaq-3.html docs/faq/sambafaq-3.html samba.man.doc
+f 0644 root sys usr/samba/docs/faq/sambafaq-4.html docs/faq/sambafaq-4.html samba.man.doc
+f 0644 root sys usr/samba/docs/faq/sambafaq-5.html docs/faq/sambafaq-5.html samba.man.doc
+f 0644 root sys usr/samba/docs/faq/sambafaq.html docs/faq/sambafaq.html samba.man.doc
+f 0644 root sys usr/samba/docs/faq/sambafaq.sgml docs/faq/sambafaq.sgml samba.man.doc
+f 0644 root sys usr/samba/docs/faq/sambafaq.txt docs/faq/sambafaq.txt samba.man.doc
+f 0644 root sys usr/samba/docs/history docs/history samba.man.doc
+f 0644 root sys usr/samba/docs/internals.doc source/internals.doc samba.man.doc
+f 0644 root sys usr/samba/docs/nameannounce.doc source/nameannounce.doc samba.man.doc
+f 0644 root sys usr/samba/docs/namebrowse.doc source/namebrowse.doc samba.man.doc
+f 0644 root sys usr/samba/docs/namedbname.doc source/namedbname.doc samba.man.doc
+f 0644 root sys usr/samba/docs/namedbresp.doc source/namedbresp.doc samba.man.doc
+f 0644 root sys usr/samba/docs/nameelect.doc source/nameelect.doc samba.man.doc
+f 0644 root sys usr/samba/docs/namelogon.doc source/namelogon.doc samba.man.doc
+f 0644 root sys usr/samba/docs/namepacket.doc source/namepacket.doc samba.man.doc
+f 0644 root sys usr/samba/docs/namequery.doc source/namequery.doc samba.man.doc
+f 0644 root sys usr/samba/docs/nameresp.doc source/nameresp.doc samba.man.doc
+f 0644 root sys usr/samba/docs/nameserv.doc source/nameserv.doc samba.man.doc
+f 0644 root sys usr/samba/docs/nameservreply.doc source/nameservreply.doc samba.man.doc
+f 0644 root sys usr/samba/docs/nameservresp.doc source/nameservresp.doc samba.man.doc
+f 0644 root sys usr/samba/docs/namework.doc source/namework.doc samba.man.doc
+f 0644 root sys usr/samba/docs/nmbd.8 docs/nmbd.8 samba.man.doc
+f 0644 root sys usr/samba/docs/samba.7 docs/samba.7 samba.man.doc
+f 0644 root sys usr/samba/docs/samba.lsm docs/samba.lsm samba.man.doc
+f 0644 root sys usr/samba/docs/security_level.txt docs/security_level.txt samba.man.doc
+f 0644 root sys usr/samba/docs/smb.conf.5 docs/smb.conf.5 samba.man.doc
+f 0644 root sys usr/samba/docs/smbclient.1 docs/smbclient.1 samba.man.doc
+f 0644 root sys usr/samba/docs/smbd.8 docs/smbd.8 samba.man.doc
+f 0644 root sys usr/samba/docs/smbpasswd.8 docs/smbpasswd.8 samba.man.doc
+f 0644 root sys usr/samba/docs/smbrun.1 docs/smbrun.1 samba.man.doc
+f 0644 root sys usr/samba/docs/smbstatus.1 docs/smbstatus.1 samba.man.doc
+f 0644 root sys usr/samba/docs/smbtar.1 docs/smbtar.1 samba.man.doc
+f 0644 root sys usr/samba/docs/testparm.1 docs/testparm.1 samba.man.doc
+f 0644 root sys usr/samba/docs/testprns.1 docs/testprns.1 samba.man.doc
+f 0644 root sys usr/samba/docs/wfw_slip.htm docs/wfw_slip.htm samba.man.doc
+f 0755 root sys usr/samba/inetd.sh packaging/SGI/inetd.sh samba.sw.base
+d 0755 root sys usr/samba/lib packaging/SGI samba.sw.base
+f 0644 root sys usr/samba/lib/smb.conf packaging/SGI/smb.conf samba.sw.base config(update)
+f 0775 root sys usr/samba/mkprintcap.sh packaging/SGI/mkprintcap.sh samba.sw.base exitop(/usr/samba/mkprintcap.sh) removeop(rm /usr/samba/printcap)
+d 0755 root sys usr/samba/src source samba.src.samba
+f 0644 root sys usr/samba/src/COPYING COPYING samba.src.samba
+f 0644 root sys usr/samba/src/COPYING.LGPL COPYING.LGPL samba.src.samba
+f 0644 root sys usr/samba/src/Manifest Manifest samba.src.samba
+f 0644 root sys usr/samba/src/README README samba.src.samba
+f 0644 root sys usr/samba/src/README.UBI README.UBI samba.src.samba
+f 0644 root sys usr/samba/src/Read-Manifest-Now Read-Manifest-Now samba.src.samba
+f 0644 root sys usr/samba/src/Roadmap Roadmap samba.src.samba
+f 0644 root sys usr/samba/src/WHATSNEW.txt WHATSNEW.txt samba.src.samba
+d 0755 root sys usr/samba/src/docs docs samba.src.samba
+f 0644 root sys usr/samba/src/docs/Application_Serving.txt docs/Application_Serving.txt samba.src.samba
+f 0644 root sys usr/samba/src/docs/BROWSING.txt docs/BROWSING.txt samba.src.samba
+f 0644 root sys usr/samba/src/docs/BUGS.txt docs/BUGS.txt samba.src.samba
+f 0644 root sys usr/samba/src/docs/DIAGNOSIS.txt docs/DIAGNOSIS.txt samba.src.samba
+f 0644 root sys usr/samba/src/docs/DNIX.txt docs/DNIX.txt samba.src.samba
+f 0644 root sys usr/samba/src/docs/DOMAIN.txt docs/DOMAIN.txt samba.src.samba
+f 0644 root sys usr/samba/src/docs/DOMAIN_CONTROL.txt docs/DOMAIN_CONTROL.txt samba.src.samba
+f 0644 root sys usr/samba/src/docs/ENCRYPTION.txt docs/ENCRYPTION.txt samba.src.samba
+f 0644 root sys usr/samba/src/docs/Faxing.txt docs/Faxing.txt samba.src.samba
+f 0644 root sys usr/samba/src/docs/GOTCHAS.txt docs/GOTCHAS.txt samba.src.samba
+f 0644 root sys usr/samba/src/docs/HINTS.txt docs/HINTS.txt samba.src.samba
+f 0644 root sys usr/samba/src/docs/INSTALL.sambatar docs/INSTALL.sambatar samba.src.samba
+f 0644 root sys usr/samba/src/docs/MIRRORS.txt docs/MIRRORS.txt samba.src.samba
+f 0644 root sys usr/samba/src/docs/NT4_PlainPassword.reg docs/NT4_PlainPassword.reg samba.src.samba
+f 0644 root sys usr/samba/src/docs/NTDOMAIN.txt docs/NTDOMAIN.txt samba.src.samba
+f 0644 root sys usr/samba/src/docs/NetBIOS.txt docs/NetBIOS.txt samba.src.samba
+f 0644 root sys usr/samba/src/docs/OS2-Client-HOWTO.txt docs/OS2-Client-HOWTO.txt samba.src.samba
+f 0644 root sys usr/samba/src/docs/PROJECTS docs/PROJECTS samba.src.samba
+f 0644 root sys usr/samba/src/docs/Passwords.txt docs/Passwords.txt samba.src.samba
+f 0644 root sys usr/samba/src/docs/Printing.txt docs/Printing.txt samba.src.samba
+f 0644 root sys usr/samba/src/docs/README.DCEDFS docs/README.DCEDFS samba.src.samba
+f 0644 root sys usr/samba/src/docs/README.jis docs/README.jis samba.src.samba
+f 0644 root sys usr/samba/src/docs/README.sambatar docs/README.sambatar samba.src.samba
+f 0644 root sys usr/samba/src/docs/SCO.txt docs/SCO.txt samba.src.samba
+f 0644 root sys usr/samba/src/docs/SMBTAR.notes docs/SMBTAR.notes samba.src.samba
+f 0644 root sys usr/samba/src/docs/Speed.txt docs/Speed.txt samba.src.samba
+f 0644 root sys usr/samba/src/docs/Support.txt docs/Support.txt samba.src.samba
+f 0644 root sys usr/samba/src/docs/THANKS docs/THANKS samba.src.samba
+f 0644 root sys usr/samba/src/docs/Tracing.txt docs/Tracing.txt samba.src.samba
+f 0644 root sys usr/samba/src/docs/UNIX-SMB.txt docs/UNIX-SMB.txt samba.src.samba
+f 0644 root sys usr/samba/src/docs/UNIX_INSTALL.txt docs/UNIX_INSTALL.txt samba.src.samba
+f 0644 root sys usr/samba/src/docs/Win95.txt docs/Win95.txt samba.src.samba
+f 0644 root sys usr/samba/src/docs/Win95_PlainPassword.reg docs/Win95_PlainPassword.reg samba.src.samba
+f 0644 root sys usr/samba/src/docs/WinNT.txt docs/WinNT.txt samba.src.samba
+f 0644 root sys usr/samba/src/docs/announce docs/announce samba.src.samba
+f 0644 root sys usr/samba/src/docs/cifsntdomain.txt docs/cifsntdomain.txt samba.src.samba
+d 0755 root sys usr/samba/src/docs/faq docs/faq samba.src.samba
+f 0644 root sys usr/samba/src/docs/faq/Samba-Server-FAQ-1.html docs/faq/Samba-Server-FAQ-1.html samba.src.samba
+f 0644 root sys usr/samba/src/docs/faq/Samba-Server-FAQ-2.html docs/faq/Samba-Server-FAQ-2.html samba.src.samba
+f 0644 root sys usr/samba/src/docs/faq/Samba-Server-FAQ.html docs/faq/Samba-Server-FAQ.html samba.src.samba
+f 0644 root sys usr/samba/src/docs/faq/Samba-Server-FAQ.sgml docs/faq/Samba-Server-FAQ.sgml samba.src.samba
+f 0644 root sys usr/samba/src/docs/faq/Samba-meta-FAQ-1.html docs/faq/Samba-meta-FAQ-1.html samba.src.samba
+f 0644 root sys usr/samba/src/docs/faq/Samba-meta-FAQ-2.html docs/faq/Samba-meta-FAQ-2.html samba.src.samba
+f 0644 root sys usr/samba/src/docs/faq/Samba-meta-FAQ-3.html docs/faq/Samba-meta-FAQ-3.html samba.src.samba
+f 0644 root sys usr/samba/src/docs/faq/Samba-meta-FAQ-4.html docs/faq/Samba-meta-FAQ-4.html samba.src.samba
+f 0644 root sys usr/samba/src/docs/faq/Samba-meta-FAQ-5.html docs/faq/Samba-meta-FAQ-5.html samba.src.samba
+f 0644 root sys usr/samba/src/docs/faq/Samba-meta-FAQ-6.html docs/faq/Samba-meta-FAQ-6.html samba.src.samba
+f 0644 root sys usr/samba/src/docs/faq/Samba-meta-FAQ.html docs/faq/Samba-meta-FAQ.html samba.src.samba
+f 0644 root sys usr/samba/src/docs/faq/Samba-meta-FAQ.sgml docs/faq/Samba-meta-FAQ.sgml samba.src.samba
+f 0644 root sys usr/samba/src/docs/faq/Samba-meta-FAQ.txt docs/faq/Samba-meta-FAQ.txt samba.src.samba
+f 0644 root sys usr/samba/src/docs/faq/sambafaq-1.html docs/faq/sambafaq-1.html samba.src.samba
+f 0644 root sys usr/samba/src/docs/faq/sambafaq-2.html docs/faq/sambafaq-2.html samba.src.samba
+f 0644 root sys usr/samba/src/docs/faq/sambafaq-3.html docs/faq/sambafaq-3.html samba.src.samba
+f 0644 root sys usr/samba/src/docs/faq/sambafaq-4.html docs/faq/sambafaq-4.html samba.src.samba
+f 0644 root sys usr/samba/src/docs/faq/sambafaq-5.html docs/faq/sambafaq-5.html samba.src.samba
+f 0644 root sys usr/samba/src/docs/faq/sambafaq.html docs/faq/sambafaq.html samba.src.samba
+f 0644 root sys usr/samba/src/docs/faq/sambafaq.sgml docs/faq/sambafaq.sgml samba.src.samba
+f 0644 root sys usr/samba/src/docs/faq/sambafaq.txt docs/faq/sambafaq.txt samba.src.samba
+f 0644 root sys usr/samba/src/docs/history docs/history samba.src.samba
+f 0644 root sys usr/samba/src/docs/make_smbcodepage.1 docs/make_smbcodepage.1 samba.src.samba
+f 0644 root sys usr/samba/src/docs/nmbd.8 docs/nmbd.8 samba.src.samba
+f 0644 root sys usr/samba/src/docs/samba.7 docs/samba.7 samba.src.samba
+f 0644 root sys usr/samba/src/docs/samba.lsm docs/samba.lsm samba.src.samba
+f 0644 root sys usr/samba/src/docs/security_level.txt docs/security_level.txt samba.src.samba
+f 0644 root sys usr/samba/src/docs/smb.conf.5 docs/smb.conf.5 samba.src.samba
+f 0644 root sys usr/samba/src/docs/smbclient.1 docs/smbclient.1 samba.src.samba
+f 0644 root sys usr/samba/src/docs/smbd.8 docs/smbd.8 samba.src.samba
+f 0644 root sys usr/samba/src/docs/smbpasswd.8 docs/smbpasswd.8 samba.src.samba
+f 0644 root sys usr/samba/src/docs/smbrun.1 docs/smbrun.1 samba.src.samba
+f 0644 root sys usr/samba/src/docs/smbstatus.1 docs/smbstatus.1 samba.src.samba
+f 0644 root sys usr/samba/src/docs/smbtar.1 docs/smbtar.1 samba.src.samba
+f 0644 root sys usr/samba/src/docs/testparm.1 docs/testparm.1 samba.src.samba
+f 0644 root sys usr/samba/src/docs/testprns.1 docs/testprns.1 samba.src.samba
+f 0644 root sys usr/samba/src/docs/wfw_slip.htm docs/wfw_slip.htm samba.src.samba
+d 0755 root sys usr/samba/src/examples examples samba.src.samba
+f 0664 root sys usr/samba/src/examples/README examples/README samba.src.samba
+d 0755 root sys usr/samba/src/examples/dce-dfs examples/dce-dfs samba.src.samba
+f 0644 root sys usr/samba/src/examples/dce-dfs/README examples/dce-dfs/README samba.src.samba
+f 0644 root sys usr/samba/src/examples/dce-dfs/smb.conf examples/dce-dfs/smb.conf samba.src.samba
+d 0755 root sys usr/samba/src/examples/misc examples/misc samba.src.samba
+f 0644 root sys usr/samba/src/examples/misc/extra_smbstatus examples/misc/extra_smbstatus samba.src.samba
+f 0644 root sys usr/samba/src/examples/misc/wall.perl examples/misc/wall.perl samba.src.samba
+d 0775 root sys usr/samba/src/examples/printer-accounting examples/printer-accounting samba.src.samba
+f 0664 root sys usr/samba/src/examples/printer-accounting/README examples/printer-accounting/README samba.src.samba
+f 0664 root sys usr/samba/src/examples/printer-accounting/acct-all examples/printer-accounting/acct-all samba.src.samba
+f 0664 root sys usr/samba/src/examples/printer-accounting/acct-sum examples/printer-accounting/acct-sum samba.src.samba
+f 0664 root sys usr/samba/src/examples/printer-accounting/hp5-redir examples/printer-accounting/hp5-redir samba.src.samba
+f 0664 root sys usr/samba/src/examples/printer-accounting/lp-acct examples/printer-accounting/lp-acct samba.src.samba
+f 0664 root sys usr/samba/src/examples/printer-accounting/printcap examples/printer-accounting/printcap samba.src.samba
+d 0755 root sys usr/samba/src/examples/printing examples/printing samba.src.samba
+f 0755 root sys usr/samba/src/examples/printing/smbprint examples/printing/smbprint samba.src.samba
+f 0644 root sys usr/samba/src/examples/printing/smbprint.sysv examples/printing/smbprint.sysv samba.src.samba
+d 0755 root sys usr/samba/src/examples/simple examples/simple samba.src.samba
+f 0644 root sys usr/samba/src/examples/simple/README examples/simple/README samba.src.samba
+f 0644 root sys usr/samba/src/examples/simple/smb.conf examples/simple/smb.conf samba.src.samba
+f 0664 root sys usr/samba/src/examples/smb.conf.default examples/smb.conf.default samba.src.samba
+d 0775 root sys usr/samba/src/examples/svr4-startup examples/svr4-startup samba.src.samba
+f 0664 root sys usr/samba/src/examples/svr4-startup/README examples/svr4-startup/README samba.src.samba
+f 0775 root sys usr/samba/src/examples/svr4-startup/samba.server examples/svr4-startup/samba.server samba.src.samba
+d 0755 root sys usr/samba/src/examples/thoralf examples/thoralf samba.src.samba
+f 0644 root sys usr/samba/src/examples/thoralf/smb.conf examples/thoralf/smb.conf samba.src.samba
+d 0755 root sys usr/samba/src/examples/tridge examples/tridge samba.src.samba
+f 0644 root sys usr/samba/src/examples/tridge/README examples/tridge/README samba.src.samba
+f 0644 root sys usr/samba/src/examples/tridge/smb.conf examples/tridge/smb.conf samba.src.samba
+f 0644 root sys usr/samba/src/examples/tridge/smb.conf.WinNT examples/tridge/smb.conf.WinNT samba.src.samba
+f 0644 root sys usr/samba/src/examples/tridge/smb.conf.fjall examples/tridge/smb.conf.fjall samba.src.samba
+f 0644 root sys usr/samba/src/examples/tridge/smb.conf.lapland examples/tridge/smb.conf.lapland samba.src.samba
+f 0644 root sys usr/samba/src/examples/tridge/smb.conf.vittjokk examples/tridge/smb.conf.vittjokk samba.src.samba
+d 0775 root sys usr/samba/src/examples/validchars examples/validchars samba.src.samba
+f 0664 root sys usr/samba/src/examples/validchars/msdos70.out examples/validchars/msdos70.out samba.src.samba
+f 0664 root sys usr/samba/src/examples/validchars/nwdos70.out examples/validchars/nwdos70.out samba.src.samba
+f 0664 root sys usr/samba/src/examples/validchars/readme examples/validchars/readme samba.src.samba
+f 0664 root sys usr/samba/src/examples/validchars/validchr.c examples/validchars/validchr.c samba.src.samba
+f 0664 root sys usr/samba/src/examples/validchars/validchr.com examples/validchars/validchr.com samba.src.samba
+d 0755 root sys usr/samba/src/packaging packaging samba.src.samba
+f 0644 root sys usr/samba/src/packaging/README packaging/README samba.src.samba
+d 0755 root sys usr/samba/src/packaging/SGI packaging/SGI samba.src.samba
+f 0644 root sys usr/samba/src/packaging/SGI/Makefile packaging/SGI/Makefile samba.src.samba
+f 0644 root sys usr/samba/src/packaging/SGI/README packaging/SGI/README samba.src.samba
+f 0755 root sys usr/samba/src/packaging/SGI/inetd.sh packaging/SGI/inetd.sh samba.src.samba
+f 0644 root sys usr/samba/src/packaging/SGI/legal_notice.html packaging/SGI/legal_notice.html samba.src.samba
+f 0755 root sys usr/samba/src/packaging/SGI/mkman packaging/SGI/mkman samba.src.samba
+f 0755 root sys usr/samba/src/packaging/SGI/mkprintcap.sh packaging/SGI/mkprintcap.sh samba.src.samba
+f 0755 root sys usr/samba/src/packaging/SGI/mkrelease.sh packaging/SGI/mkrelease.sh samba.src.samba
+f 0644 root sys usr/samba/src/packaging/SGI/printcap packaging/SGI/printcap samba.src.samba
+f 0644 root sys usr/samba/src/packaging/SGI/psfixes.pl packaging/SGI/psfixes.pl samba.src.samba
+f 0644 root sys usr/samba/src/packaging/SGI/relnotes.html packaging/SGI/relnotes.html samba.src.samba
+f 0644 root sys usr/samba/src/packaging/SGI/samba.config packaging/SGI/samba.config samba.src.samba
+f 0644 root sys usr/samba/src/packaging/SGI/samba.idb packaging/SGI/samba.idb samba.src.samba
+f 0644 root sys usr/samba/src/packaging/SGI/samba.rc packaging/SGI/samba.rc samba.src.samba
+f 0644 root sys usr/samba/src/packaging/SGI/samba.spec packaging/SGI/samba.spec samba.src.samba
+f 0644 root sys usr/samba/src/packaging/SGI/sambalp packaging/SGI/sambalp samba.src.samba
+f 0644 root sys usr/samba/src/packaging/SGI/smb.conf packaging/SGI/smb.conf samba.src.samba
+f 0644 root sys usr/samba/src/packaging/SGI/smbpasswd packaging/SGI/smbpasswd samba.src.samba
+f 0644 root sys usr/samba/src/packaging/SGI/smbprint packaging/SGI/smbprint samba.src.samba
+d 0755 root sys usr/samba/src/packaging/Solaris packaging/Solaris samba.src.samba
+d 0755 root sys usr/samba/src/packaging/Solaris/pkg-specs packaging/Solaris/pkg-specs samba.src.samba
+f 0644 root sys usr/samba/src/packaging/Solaris/pkg-specs/Packaging.script packaging/Solaris/pkg-specs/Packaging.script samba.src.samba
+f 0644 root sys usr/samba/src/packaging/Solaris/pkg-specs/mkprototype packaging/Solaris/pkg-specs/mkprototype samba.src.samba
+f 0644 root sys usr/samba/src/packaging/Solaris/pkg-specs/pkginfo packaging/Solaris/pkg-specs/pkginfo samba.src.samba
+f 0644 root sys usr/samba/src/packaging/Solaris/pkg-specs/postinstall packaging/Solaris/pkg-specs/postinstall samba.src.samba
+f 0644 root sys usr/samba/src/packaging/Solaris/pkg-specs/postremove packaging/Solaris/pkg-specs/postremove samba.src.samba
+d 0755 root sys usr/samba/src/packaging/redhat packaging/redhat samba.src.samba
+f 0644 root sys usr/samba/src/packaging/redhat/Instructions packaging/redhat/Instructions samba.src.samba
+f 0755 root sys usr/samba/src/packaging/redhat/makeldirs.sh packaging/redhat/makeldirs.sh samba.src.samba
+f 0755 root sys usr/samba/src/packaging/redhat/makerpms.sh packaging/redhat/makerpms.sh samba.src.samba
+f 0644 root sys usr/samba/src/packaging/redhat/samba-axp.patch packaging/redhat/samba-axp.patch samba.src.samba
+f 0644 root sys usr/samba/src/packaging/redhat/samba-make.patch packaging/redhat/samba-make.patch samba.src.samba
+f 0644 root sys usr/samba/src/packaging/redhat/samba.log packaging/redhat/samba.log samba.src.samba
+f 0644 root sys usr/samba/src/packaging/redhat/samba.pamd packaging/redhat/samba.pamd samba.src.samba
+f 0644 root sys usr/samba/src/packaging/redhat/samba.spec packaging/redhat/samba.spec samba.src.samba
+f 0644 root sys usr/samba/src/packaging/redhat/smb.conf packaging/redhat/smb.conf samba.src.samba
+f 0755 root sys usr/samba/src/packaging/redhat/smb.init packaging/redhat/smb.init samba.src.samba
+f 0755 root sys usr/samba/src/packaging/redhat/smbadduser packaging/redhat/smbadduser samba.src.samba
+f 0755 root sys usr/samba/src/packaging/redhat/smbprint packaging/redhat/smbprint samba.src.samba
+d 0755 root sys usr/samba/src/source source samba.src.samba
+f 0644 root sys usr/samba/src/source/Makefile source/Makefile samba.src.samba
+f 0644 root sys usr/samba/src/source/Makefile.OS2 source/Makefile.OS2 samba.src.samba
+f 0644 root sys usr/samba/src/source/access.c source/access.c samba.src.samba
+f 0644 root sys usr/samba/src/source/addtosmbpass source/addtosmbpass samba.src.samba
+f 0644 root sys usr/samba/src/source/byteorder.h source/byteorder.h samba.src.samba
+f 0644 root sys usr/samba/src/source/cgi.c source/cgi.c samba.src.samba
+f 0644 root sys usr/samba/src/source/change-log source/change-log samba.src.samba
+f 0644 root sys usr/samba/src/source/charcnv.c source/charcnv.c samba.src.samba
+f 0644 root sys usr/samba/src/source/charset.c source/charset.c samba.src.samba
+f 0644 root sys usr/samba/src/source/charset.h source/charset.h samba.src.samba
+f 0644 root sys usr/samba/src/source/checkos.sh source/checkos.sh samba.src.samba
+f 0644 root sys usr/samba/src/source/chgpasswd.c source/chgpasswd.c samba.src.samba
+f 0644 root sys usr/samba/src/source/client.c source/client.c samba.src.samba
+f 0644 root sys usr/samba/src/source/clientgen.c source/clientgen.c samba.src.samba
+f 0644 root sys usr/samba/src/source/clientutil.c source/clientutil.c samba.src.samba
+f 0644 root sys usr/samba/src/source/clitar.c source/clitar.c samba.src.samba
+f 0644 root sys usr/samba/src/source/clitar.h source/clitar.h samba.src.samba
+f 0644 root sys usr/samba/src/source/codepage_def.437 source/codepage_def.437 samba.src.samba
+f 0644 root sys usr/samba/src/source/codepage_def.850 source/codepage_def.850 samba.src.samba
+f 0644 root sys usr/samba/src/source/codepage_def.852 source/codepage_def.852 samba.src.samba
+f 0644 root sys usr/samba/src/source/codepage_def.932 source/codepage_def.932 samba.src.samba
+f 0644 root sys usr/samba/src/source/credentials.c source/credentials.c samba.src.samba
+f 0644 root sys usr/samba/src/source/cvs.log source/cvs.log samba.src.samba
+f 0644 root sys usr/samba/src/source/dir.c source/dir.c samba.src.samba
+f 0644 root sys usr/samba/src/source/fault.c source/fault.c samba.src.samba
+f 0644 root sys usr/samba/src/source/getsmbpass.c source/getsmbpass.c samba.src.samba
+f 0644 root sys usr/samba/src/source/includes.h source/includes.h samba.src.samba
+f 0644 root sys usr/samba/src/source/installbin.sh source/installbin.sh samba.src.samba
+f 0644 root sys usr/samba/src/source/installcp.sh source/installcp.sh samba.src.samba
+f 0644 root sys usr/samba/src/source/installman.sh source/installman.sh samba.src.samba
+f 0644 root sys usr/samba/src/source/installscripts.sh source/installscripts.sh samba.src.samba
+f 0644 root sys usr/samba/src/source/interface.c source/interface.c samba.src.samba
+f 0644 root sys usr/samba/src/source/internals.doc source/internals.doc samba.src.samba
+f 0644 root sys usr/samba/src/source/ipc.c source/ipc.c samba.src.samba
+f 0644 root sys usr/samba/src/source/kanji.c source/kanji.c samba.src.samba
+f 0644 root sys usr/samba/src/source/kanji.h source/kanji.h samba.src.samba
+f 0644 root sys usr/samba/src/source/loadparm.c source/loadparm.c samba.src.samba
+f 0644 root sys usr/samba/src/source/local.h source/local.h samba.src.samba
+f 0644 root sys usr/samba/src/source/locking.c source/locking.c samba.src.samba
+f 0644 root sys usr/samba/src/source/locking_shm.c source/locking_shm.c samba.src.samba
+f 0644 root sys usr/samba/src/source/locking_slow.c source/locking_slow.c samba.src.samba
+f 0644 root sys usr/samba/src/source/lsaparse.c source/lsaparse.c samba.src.samba
+f 0644 root sys usr/samba/src/source/make_smbcodepage.c source/make_smbcodepage.c samba.src.samba
+f 0644 root sys usr/samba/src/source/mangle.c source/mangle.c samba.src.samba
+f 0644 root sys usr/samba/src/source/md4.c source/md4.c samba.src.samba
+f 0644 root sys usr/samba/src/source/message.c source/message.c samba.src.samba
+f 0644 root sys usr/samba/src/source/mkproto.awk source/mkproto.awk samba.src.samba
+f 0644 root sys usr/samba/src/source/mksmbpasswd.sh source/mksmbpasswd.sh samba.src.samba
+f 0644 root sys usr/samba/src/source/nameannounce.c source/nameannounce.c samba.src.samba
+f 0644 root sys usr/samba/src/source/nameannounce.doc source/nameannounce.doc samba.src.samba
+f 0644 root sys usr/samba/src/source/namebrowse.c source/namebrowse.c samba.src.samba
+f 0644 root sys usr/samba/src/source/namebrowse.doc source/namebrowse.doc samba.src.samba
+f 0644 root sys usr/samba/src/source/nameconf.c source/nameconf.c samba.src.samba
+f 0644 root sys usr/samba/src/source/namedbname.c source/namedbname.c samba.src.samba
+f 0644 root sys usr/samba/src/source/namedbname.doc source/namedbname.doc samba.src.samba
+f 0644 root sys usr/samba/src/source/namedbresp.c source/namedbresp.c samba.src.samba
+f 0644 root sys usr/samba/src/source/namedbresp.doc source/namedbresp.doc samba.src.samba
+f 0644 root sys usr/samba/src/source/namedbserver.c source/namedbserver.c samba.src.samba
+f 0644 root sys usr/samba/src/source/namedbsubnet.c source/namedbsubnet.c samba.src.samba
+f 0644 root sys usr/samba/src/source/namedbwork.c source/namedbwork.c samba.src.samba
+f 0644 root sys usr/samba/src/source/nameelect.c source/nameelect.c samba.src.samba
+f 0644 root sys usr/samba/src/source/nameelect.doc source/nameelect.doc samba.src.samba
+f 0644 root sys usr/samba/src/source/namelogon.c source/namelogon.c samba.src.samba
+f 0644 root sys usr/samba/src/source/namelogon.doc source/namelogon.doc samba.src.samba
+f 0644 root sys usr/samba/src/source/namepacket.c source/namepacket.c samba.src.samba
+f 0644 root sys usr/samba/src/source/namepacket.doc source/namepacket.doc samba.src.samba
+f 0644 root sys usr/samba/src/source/namequery.c source/namequery.c samba.src.samba
+f 0644 root sys usr/samba/src/source/namequery.doc source/namequery.doc samba.src.samba
+f 0644 root sys usr/samba/src/source/nameresp.c source/nameresp.c samba.src.samba
+f 0644 root sys usr/samba/src/source/nameresp.doc source/nameresp.doc samba.src.samba
+f 0644 root sys usr/samba/src/source/nameserv.c source/nameserv.c samba.src.samba
+f 0644 root sys usr/samba/src/source/nameserv.doc source/nameserv.doc samba.src.samba
+f 0644 root sys usr/samba/src/source/nameserv.h source/nameserv.h samba.src.samba
+f 0644 root sys usr/samba/src/source/nameservreply.c source/nameservreply.c samba.src.samba
+f 0644 root sys usr/samba/src/source/nameservreply.doc source/nameservreply.doc samba.src.samba
+f 0644 root sys usr/samba/src/source/nameservresp.c source/nameservresp.c samba.src.samba
+f 0644 root sys usr/samba/src/source/nameservresp.doc source/nameservresp.doc samba.src.samba
+f 0644 root sys usr/samba/src/source/namework.c source/namework.c samba.src.samba
+f 0644 root sys usr/samba/src/source/namework.doc source/namework.doc samba.src.samba
+f 0644 root sys usr/samba/src/source/nmbd.c source/nmbd.c samba.src.samba
+f 0644 root sys usr/samba/src/source/nmblib.c source/nmblib.c samba.src.samba
+f 0644 root sys usr/samba/src/source/nmblookup.c source/nmblookup.c samba.src.samba
+f 0644 root sys usr/samba/src/source/nmbsync.c source/nmbsync.c samba.src.samba
+f 0644 root sys usr/samba/src/source/nterr.h source/nterr.h samba.src.samba
+f 0644 root sys usr/samba/src/source/params.c source/params.c samba.src.samba
+f 0644 root sys usr/samba/src/source/password.c source/password.c samba.src.samba
+f 0644 root sys usr/samba/src/source/pcap.c source/pcap.c samba.src.samba
+f 0644 root sys usr/samba/src/source/pipenetlog.c source/pipenetlog.c samba.src.samba
+f 0644 root sys usr/samba/src/source/pipentlsa.c source/pipentlsa.c samba.src.samba
+f 0644 root sys usr/samba/src/source/pipes.c source/pipes.c samba.src.samba
+f 0644 root sys usr/samba/src/source/pipesrvsvc.c source/pipesrvsvc.c samba.src.samba
+f 0644 root sys usr/samba/src/source/pipeutil.c source/pipeutil.c samba.src.samba
+f 0644 root sys usr/samba/src/source/predict.c source/predict.c samba.src.samba
+f 0644 root sys usr/samba/src/source/printing.c source/printing.c samba.src.samba
+f 0644 root sys usr/samba/src/source/proto.h source/proto.h samba.src.samba
+f 0644 root sys usr/samba/src/source/quotas.c source/quotas.c samba.src.samba
+f 0644 root sys usr/samba/src/source/replace.c source/replace.c samba.src.samba
+f 0644 root sys usr/samba/src/source/reply.c source/reply.c samba.src.samba
+f 0644 root sys usr/samba/src/source/revert.sh source/revert.sh samba.src.samba
+f 0644 root sys usr/samba/src/source/server.c source/server.c samba.src.samba
+f 0644 root sys usr/samba/src/source/shmem.c source/shmem.c samba.src.samba
+f 0644 root sys usr/samba/src/source/smb.h source/smb.h samba.src.samba
+f 0644 root sys usr/samba/src/source/smbadduser source/smbadduser samba.src.samba
+f 0644 root sys usr/samba/src/source/smbdes.c source/smbdes.c samba.src.samba
+f 0644 root sys usr/samba/src/source/smbencrypt.c source/smbencrypt.c samba.src.samba
+f 0644 root sys usr/samba/src/source/smbparse.c source/smbparse.c samba.src.samba
+f 0644 root sys usr/samba/src/source/smbpass.c source/smbpass.c samba.src.samba
+f 0644 root sys usr/samba/src/source/smbpasswd.c source/smbpasswd.c samba.src.samba
+f 0644 root sys usr/samba/src/source/smbrun.c source/smbrun.c samba.src.samba
+f 0644 root sys usr/samba/src/source/smbtar source/smbtar samba.src.samba
+f 0644 root sys usr/samba/src/source/srvparse.c source/srvparse.c samba.src.samba
+f 0644 root sys usr/samba/src/source/status.c source/status.c samba.src.samba
+f 0644 root sys usr/samba/src/source/system.c source/system.c samba.src.samba
+f 0644 root sys usr/samba/src/source/testparm.c source/testparm.c samba.src.samba
+f 0644 root sys usr/samba/src/source/testprns.c source/testprns.c samba.src.samba
+f 0644 root sys usr/samba/src/source/time.c source/time.c samba.src.samba
+f 0644 root sys usr/samba/src/source/trans2.c source/trans2.c samba.src.samba
+f 0644 root sys usr/samba/src/source/trans2.h source/trans2.h samba.src.samba
+f 0644 root sys usr/samba/src/source/ubi_dLinkList.c source/ubi_dLinkList.c samba.src.samba
+f 0644 root sys usr/samba/src/source/ubi_dLinkList.h source/ubi_dLinkList.h samba.src.samba
+f 0644 root sys usr/samba/src/source/ufc.c source/ufc.c samba.src.samba
+f 0644 root sys usr/samba/src/source/uid.c source/uid.c samba.src.samba
+f 0644 root sys usr/samba/src/source/uninstallbin.sh source/uninstallbin.sh samba.src.samba
+f 0644 root sys usr/samba/src/source/uninstallcp.sh source/uninstallcp.sh samba.src.samba
+f 0644 root sys usr/samba/src/source/uninstallman.sh source/uninstallman.sh samba.src.samba
+f 0644 root sys usr/samba/src/source/uninstallscripts.sh source/uninstallscripts.sh samba.src.samba
+f 0644 root sys usr/samba/src/source/updatesmbpasswd.sh source/updatesmbpasswd.sh samba.src.samba
+f 0644 root sys usr/samba/src/source/username.c source/username.c samba.src.samba
+f 0644 root sys usr/samba/src/source/util.c source/util.c samba.src.samba
+f 0644 root sys usr/samba/src/source/version.h source/version.h samba.src.samba
+f 0644 root sys usr/samba/src/source/vt_mode.c source/vt_mode.c samba.src.samba
+f 0644 root sys usr/samba/src/source/vt_mode.h source/vt_mode.h samba.src.samba
+f 0644 root sys usr/samba/src/source/wsmbconf.c source/wsmbconf.c samba.src.samba
+f 0644 root sys usr/samba/src/source/wsmbstatus.c source/wsmbstatus.c samba.src.samba
+d 0775 root sys usr/samba/var/locks packaging/SGI samba.sw.base
+d 0755 root sys usr/share/catman/u_man packaging/SGI/catman samba.man.manpages
+d 0755 root sys usr/share/catman/u_man/cat1 packaging/SGI/catman samba.man.manpages
+f 0664 root sys usr/share/catman/u_man/cat1/smbclient.1.Z packaging/SGI/catman/smbclient.1.Z samba.man.manpages
+f 0664 root sys usr/share/catman/u_man/cat1/smbrun.1.Z packaging/SGI/catman/smbrun.1.Z samba.man.manpages
+f 0664 root sys usr/share/catman/u_man/cat1/smbstatus.1.Z packaging/SGI/catman/smbstatus.1.Z samba.man.manpages
+f 0664 root sys usr/share/catman/u_man/cat1/smbtar.1.Z packaging/SGI/catman/smbtar.1.Z samba.man.manpages
+f 0664 root sys usr/share/catman/u_man/cat1/testparm.1.Z packaging/SGI/catman/testparm.1.Z samba.man.manpages
+f 0664 root sys usr/share/catman/u_man/cat1/testprns.1.Z packaging/SGI/catman/testprns.1.Z samba.man.manpages
+d 0755 root sys usr/share/catman/u_man/cat5 packaging/SGI/catman samba.man.manpages
+f 0664 root sys usr/share/catman/u_man/cat5/smb.conf.5.Z packaging/SGI/catman/smb.conf.5.Z samba.man.manpages
+d 0755 root sys usr/share/catman/u_man/cat7 packaging/SGI/catman samba.man.manpages
+f 0664 root sys usr/share/catman/u_man/cat7/samba.7.Z packaging/SGI/catman/samba.7.Z samba.man.manpages
+d 0755 root sys usr/share/catman/u_man/cat8 packaging/SGI/catman samba.man.manpages
+f 0664 root sys usr/share/catman/u_man/cat8/nmbd.8.Z packaging/SGI/catman/nmbd.8.Z samba.man.manpages
+f 0664 root sys usr/share/catman/u_man/cat8/smbd.8.Z packaging/SGI/catman/smbd.8.Z samba.man.manpages
+f 0664 root sys usr/share/catman/u_man/cat8/smbpasswd.8.Z packaging/SGI/catman/smbpasswd.8.Z samba.man.manpages
diff --git a/packaging/SGI/samba.rc b/packaging/SGI/samba.rc
new file mode 100644
index 00000000000..121b3400a38
--- /dev/null
+++ b/packaging/SGI/samba.rc
@@ -0,0 +1,42 @@
+#! /bin/sh
+
+#
+# Samba server control
+#
+
+IS_ON=/etc/chkconfig
+KILLALL=/sbin/killall
+
+SAMBAD=/usr/samba/bin/smbd
+#SAMBA_OPTS=-d2
+NMBD=/usr/samba/bin/nmbd
+#NMBD_OPTS=-d1
+
+if test ! -x $IS_ON ; then
+ IS_ON=true
+fi
+
+if $IS_ON verbose ; then
+ ECHO=echo
+else # For a quiet startup and shutdown
+ ECHO=:
+fi
+
+case $1 in
+'start')
+ if $IS_ON samba && test -x $SAMBAD; then
+ $KILLALL -15 smbd nmbd
+ $ECHO "Samba:\c"
+ $SAMBAD $SAMBA_OPTS -D; $ECHO " smbd\c"
+ $NMBD $NMBD_OPTS -D; $ECHO " nmbd\c"
+ $ECHO "."
+ fi
+ ;;
+'stop')
+ $ECHO "Stopping Samba Servers."
+ $KILLALL -15 smbd nmbd
+ ;;
+*)
+ echo "usage: /etc/init.d/samba {start|stop}"
+ ;;
+esac
diff --git a/packaging/SGI/samba.spec b/packaging/SGI/samba.spec
new file mode 100644
index 00000000000..62941a2711c
--- /dev/null
+++ b/packaging/SGI/samba.spec
@@ -0,0 +1,45 @@
+product samba
+ id "Samba version 1.9.18alpha3"
+ image sw
+ id "Samba Execution Environment"
+ version 0109180003
+ order 0
+ subsys base default
+ id "Samba Execution Environment"
+ replaces fw_samba.sw.base 0 9999999999
+ replaces fw_samba.sw.samba 0 9999999999
+ exp samba.sw.base
+ endsubsys
+ endimage
+ image man
+ id "Samba Online Documentation"
+ version 0109180003
+ order 1
+ subsys manpages default
+ id "Samba Man Page"
+ replaces fw_samba.man.manpages 0 9999999999
+ replaces fw_samba.man.samba 0 9999999999
+ exp samba.man.manpages
+ endsubsys
+ subsys doc default
+ id "Samba Documentation"
+ replaces fw_samba.man.doc 0 9999999999
+ exp samba.man.doc
+ endsubsys
+ subsys relnotes default
+ id "Samba Release Notes"
+ replaces fw_samba.man.relnotes 0 9999999999
+ exp samba.man.relnotes
+ endsubsys
+ endimage
+ image src
+ id "Samba Source Code"
+ version 0109180003
+ order 2
+ subsys samba
+ id "Samba Source Code"
+ replaces fw_samba.src.samba 0 9999999999
+ exp samba.src.samba
+ endsubsys
+ endimage
+endproduct
diff --git a/packaging/SGI/sambalp b/packaging/SGI/sambalp
new file mode 100644
index 00000000000..cb95ef089f2
--- /dev/null
+++ b/packaging/SGI/sambalp
@@ -0,0 +1,20 @@
+#! /bin/sh
+#
+# Workaround Win95 printer driver/Impressario bug by removing
+# the PS check for available virtual memory. Note that this
+# bug appears to be in all Win95 print drivers that generate
+# PostScript; but is for certain there with a QMS-PS 810 (the
+# printer type I configure on the Win95-side for printing with
+# Samba).
+#
+# the perl script fixes 3 different bugs.
+# 1. remove the JCL statements added by some HP printer drivers to the
+# beginning of the postscript output.
+# 2. Fix a bug in output from word files with long filenames. A non-printing
+# character added to the end of the title comment by word is
+# removed.
+# 3. The VM fix described above.
+#
+
+/usr/samba/bin/psfixes.pl $2 | /usr/bin/lp -c -d$1 -t"$3 on $4"
+rm $2
diff --git a/packaging/SGI/smb.conf b/packaging/SGI/smb.conf
new file mode 100644
index 00000000000..b484cc918b2
--- /dev/null
+++ b/packaging/SGI/smb.conf
@@ -0,0 +1,86 @@
+; Configuration file for smbd.
+; ============================================================================
+; For the format of this file and comprehensive descriptions of all the
+; configuration option, please refer to the man page for smb.conf(5).
+
+; This is a sample configuration for IRIX 6.x systems
+;
+; The following configuration should suit most systems for basic usage and
+; initial testing. It gives all clients access to their home directories and
+; allows access to all printers specified in /etc/printcap as well as /usr/tmp.
+;
+[global]
+ comment = Samba %v
+ workgroup = workgroup
+ printing = sysv
+;
+; A printcap file is created during installation that contains the names
+; of all printers attached to your system. Names longer than 8 characters
+; will not be visible to clients.
+;
+ printcap name = /usr/samba/printcap
+;
+; If you are using Impressario 1.x then you'll want to use the
+; sambalp script provided with this package. It works around
+; a problem in the PostScript generated by the standard Windows
+; drivers--there is a check to verify sufficient virtual memory
+; is available in the printer to print the job, but this fails
+; under Impressario because of a bug in Impressario 1.x. The sambalp
+; script strips out the vmstatus check. BTW, when using this
+; setup to print be sure to configure a Windows printer driver
+; that generates PostScript--QMS-PS 810 is one that should work
+; with the sambalp script.
+;
+; print command = /usr/samba/bin/sambalp %p %s %U %m
+ print command = /usr/bin/lp -c -d%p -t"%U on machine %m" %s ; rm %s
+
+ load printers = yes
+ guest account = nobody
+ browseable = yes
+
+; Set a max size for log files in Kb
+ log file = /usr/samba/var
+ max log size = 50
+
+; You will need a world readable lock directory and "share modes=yes"
+; if you want to support the file sharing modes for multiple users
+; of the same files
+ locking = yes
+ lock directory = /usr/samba/var/locks
+ share modes = yes
+
+; security = user
+
+; You need to test to see if this makes a difference on your system
+ socket options = TCP_NODELAY
+
+; Set the os level to > 32 if there is no NT server for your workgroup
+ os level = 0
+ preferred master = no
+ domain master = no
+ local master = no
+ wins support = no
+ wins server =
+
+ preserve case = yes
+ short preserve case = yes
+
+[homes]
+ comment = Home Directories
+ browseable = no
+ writable = yes
+
+[printers]
+ comment = All Printers
+ path = /usr/tmp
+ browseable = no
+ printable = yes
+ public = yes
+ writable = no
+ create mask = 0700
+
+[tmp]
+ comment = Temporary file space
+ path = /usr/tmp
+ read only = no
+ public = yes
diff --git a/packaging/SGI/smbpasswd b/packaging/SGI/smbpasswd
new file mode 100644
index 00000000000..79c834dc354
--- /dev/null
+++ b/packaging/SGI/smbpasswd
@@ -0,0 +1 @@
+username:uid:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:Long name:user home dir:user shell
diff --git a/packaging/SGI/smbprint b/packaging/SGI/smbprint
new file mode 100644
index 00000000000..935f98bf923
--- /dev/null
+++ b/packaging/SGI/smbprint
@@ -0,0 +1,52 @@
+#!/bin/sh
+#
+# @(#) smbprint.sysv version 1.0 Ross Wakelin <r.wakelin@march.co.uk>
+#
+# Version 1.0 13 January 1995
+# modified from the original smbprint (bsd) script
+#
+# this script is a System 5 printer interface script. It
+# uses the smbclient program to print the file to the specified smb-based
+# server and service.
+#
+# To add this to your lp system, copy this file into your samba directory
+# (the example here is /opt/samba), modify the server and service variables
+# and then execute the following command (as root)
+#
+# lpadmin -punixprintername -v/dev/null -i/opt/samba/smbprint
+#
+# where unixprintername is the name that the printer will be known as
+# on your unix box.
+#
+# the script smbprint will be copied into your printer administration
+# directory (/usr/lib/lp or /etc/lp) as a new interface
+# (interface/unixprintername)
+# Then you have to enable unixprintername and accept unixprintername
+#
+# This script will then be called by the lp service to print the files
+# This script will have 6 or more parameters passed to it by the lp service.
+# The first five will contain details of the print job, who queued it etc,
+# while parameters 6 onwards are a list of files to print. We just
+# cat these at the samba client.
+#
+# Set these to the server and service you wish to print to
+# In this example I have a WfWg PC called "lapland" that has a printer
+# exported called "printer" with no password.
+#
+# clear out the unwanted parameters
+shift;shift;shift;shift;shift
+# now the argument list is just the files to print
+
+server=admin
+service=hplj2
+password=""
+
+(
+# NOTE You may wish to add the line `echo translate' if you want automatic
+# CR/LF translation when printing.
+ echo translate
+ echo "print -"
+ cat $*
+) | /usr/samba/bin/smbclient "\\\\$server\\$service" $password -N -P > /dev/null
+exit $?
+
diff --git a/packaging/Solaris/pkg-specs/Packaging.script b/packaging/Solaris/pkg-specs/Packaging.script
new file mode 100644
index 00000000000..6f182c33e52
--- /dev/null
+++ b/packaging/Solaris/pkg-specs/Packaging.script
@@ -0,0 +1,5 @@
+#!/bin/sh
+./mkprototype
+pkgmk -o -d /tmp -b `pwd` -f ./prototype
+cd /tmp
+pkgtrans . samba.pkg samba
diff --git a/packaging/Solaris/pkg-specs/mkprototype b/packaging/Solaris/pkg-specs/mkprototype
new file mode 100644
index 00000000000..5ca0746beea
--- /dev/null
+++ b/packaging/Solaris/pkg-specs/mkprototype
@@ -0,0 +1,31 @@
+#!/bin/sh
+# this creates prototype files
+pkgproto * > prototype
+nawk 'BEGIN { print "# d directory"
+ print "# e a file to be edited upon installation or removal"
+ print "# f a standard executable or data file"
+ print "# i installation script or information file"
+ print "# l linked file"
+ print "# s symbolic link"
+ print "# v volatile file (one whose contents are expected to
+change)"
+ print "#" }
+/ pkginfo / { print "i pkginfo" ; next }
+/ postinstall / { print "i postinstall" ; next }
+/ postremove / { print "i postremove" ; next }
+/d none usr / { print "d none usr ? ? ?" ; next }
+/d none usr\/local / { print "d none usr/local ? ? ?" ; next }
+/d none etc / { print "d none etc ? ? ?" ; next }
+/f none etc\// { $1 = "v" }
+/d none opt / { print "d none opt ? ? ?" ; next }
+/d none var / { print "d none var ? ? ?" ; next }
+/none prototype / { next }
+/none mkprototype / { next }
+/ src[ \/]/ { next }
+/^[dfv]/ { $5 = "bin"
+ $6 = "bin"
+ print
+ next }
+{ print }' prototype >/tmp/prototype.$$
+mv /tmp/prototype.$$ prototype
+
diff --git a/packaging/Solaris/pkg-specs/pkginfo b/packaging/Solaris/pkg-specs/pkginfo
new file mode 100644
index 00000000000..ab06b3fffab
--- /dev/null
+++ b/packaging/Solaris/pkg-specs/pkginfo
@@ -0,0 +1,12 @@
+PSTAMP=Mon Sep 29 17:26:14 BST 1997
+PKG=samba
+NAME=SMB based file/printer sharing
+VERSION=1.9.17p2,REV=1
+ARCH=sparc
+CATEGORY=system
+VENDOR=samba group
+DESC=File and printer sharing for NT workstations
+CLASSES=none
+INTONLY=1
+HOTLINE=Please contact your local UNIX support group
+BASEDIR=/
diff --git a/packaging/Solaris/pkg-specs/postinstall b/packaging/Solaris/pkg-specs/postinstall
new file mode 100644
index 00000000000..0fbe9da10b5
--- /dev/null
+++ b/packaging/Solaris/pkg-specs/postinstall
@@ -0,0 +1,37 @@
+#!/bin/sh
+# install samba
+
+nawk '/^netbios-[ns]*[ ]/ {next}
+{print}
+END { print "netbios-ssn 139/tcp"
+ print "netbios-ns 137/udp # samba service" }' \
+ ${PKG_INSTALL_ROOT}/etc/inet/services > /tmp/services.$$ && \
+ mv -f /tmp/services.$$ ${PKG_INSTALL_ROOT}/etc/inet/services &&
+\
+ chmod 644 ${PKG_INSTALL_ROOT}/etc/inet/services && \
+ echo "Updated ${PKG_INSTALL_ROOT}/etc/inet/services"
+
+nawk '/samba.*mbd[ ]/ { next }
+{print}
+END { print "# samba connections are handled by smbd and nmbd"
+ print "netbios-ssn stream tcp nowait root /opt/samba/bin/smbd
+smbd"
+ print "netbios-ns dgram udp wait root /opt/samba/bin/nmbd nmbd" }'
+\
+ ${PKG_INSTALL_ROOT}/etc/inet/inetd.conf > /tmp/inetd.conf.$$ &&
+\
+ mv -f /tmp/inetd.conf.$$ ${PKG_INSTALL_ROOT}/etc/inet/inetd.conf
+&& \
+ chmod 644 ${PKG_INSTALL_ROOT}/etc/inet/inetd.conf && \
+ echo "Updated ${PKG_INSTALL_ROOT}/etc/inet/inetd.conf"
+
+echo "Installed samba service into ${PKG_INSTALL_ROOT:-/}"
+
+inetpid=`/bin/ps -ef | awk '/ \/usr\/sbin\/inetd / { print $2 } '`
+if [ "X$inetpid" = "X" ]; then
+ echo "inetd not running"
+else
+ echo "Restarting inetd($inetpid)"
+ kill -HUP $inetpid
+fi
+
diff --git a/packaging/Solaris/pkg-specs/postremove b/packaging/Solaris/pkg-specs/postremove
new file mode 100644
index 00000000000..7f7a5c1f8e4
--- /dev/null
+++ b/packaging/Solaris/pkg-specs/postremove
@@ -0,0 +1,30 @@
+#!/bin/sh
+# remove samba
+
+nawk '/^netbios-[ns]*[ ]/ {next}
+{print} ' \
+ ${PKG_INSTALL_ROOT}/etc/inet/services > /tmp/services.$$ && \
+ mv -f /tmp/services.$$ ${PKG_INSTALL_ROOT}/etc/inet/services &&
+\
+ chmod 644 ${PKG_INSTALL_ROOT}/etc/inet/services && \
+ echo "Updated ${PKG_INSTALL_ROOT}/etc/inet/services"
+
+nawk '/samba.*mbd[ ]/ { next }
+{print} ' \
+ ${PKG_INSTALL_ROOT}/etc/inet/inetd.conf > /tmp/inetd.conf.$$ &&
+\
+ mv -f /tmp/inetd.conf.$$ ${PKG_INSTALL_ROOT}/etc/inet/inetd.conf
+&& \
+ chmod 644 ${PKG_INSTALL_ROOT}/etc/inet/inetd.conf && \
+ echo "Updated ${PKG_INSTALL_ROOT}/etc/inet/inetd.conf"
+
+echo "Removed samba service from ${PKG_INSTALL_ROOT:-/}"
+
+inetpid=`/bin/ps -ef | awk '/ \/usr\/sbin\/inetd / { print $2 } '`
+if [ "X$inetpid" = "X" ]; then
+ echo "inetd not running"
+else
+ echo "Restarting inetd($inetpid)"
+ kill -HUP $inetpid
+fi
+
diff --git a/source/.cvsignore b/source/.cvsignore
new file mode 100644
index 00000000000..1e48a541752
--- /dev/null
+++ b/source/.cvsignore
@@ -0,0 +1,14 @@
+Makefile.RPM
+makefile
+makefile.sunos5
+make_smbcodepage
+make_printerdef
+nmbd
+nmblookup
+smbclient
+smbd
+smbpasswd
+smbrun
+smbstatus
+testparm
+testprns
diff --git a/source/cgi.c b/source/cgi.c
new file mode 100644
index 00000000000..56c293985d6
--- /dev/null
+++ b/source/cgi.c
@@ -0,0 +1,163 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ some simple CGI helper routines
+ Copyright (C) Andrew Tridgell 1997
+
+ 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"
+
+#define MAX_VARIABLES 512
+
+struct var {
+ char *name;
+ char *value;
+};
+
+static struct var variables[MAX_VARIABLES];
+static int num_variables;
+
+
+static int grab_line(int *cl, char *line, int maxsize)
+{
+ int i = 0;
+
+ while ((*cl)) {
+ int c = fgetc(stdin);
+ (*cl)--;
+
+ if (c == EOF) {
+ (*cl) = 0;
+ break;
+ }
+
+ if (c == '+') {
+ c = ' ';
+ }
+
+ if (c == '\r') continue;
+
+ if (strchr("\n&", c)) break;
+
+ if (c == '%' && (*cl) >= 2) {
+ int c1, c2;
+ c1 = fgetc(stdin);
+ c2 = fgetc(stdin);
+ (*cl) -= 2;
+ if (c1 == EOF || c2 == EOF) break;
+ if (c1 >= '0' && c1 <= '9')
+ c1 = c1 - '0';
+ else if (c1 >= 'A' && c1 <= 'F')
+ c1 = 10 + c1 - 'A';
+ else if (c1 >= 'a' && c1 <= 'f')
+ c1 = 10 + c1 - 'a';
+ else break;
+
+ if (c2 >= '0' && c2 <= '9')
+ c2 = c2 - '0';
+ else if (c2 >= 'A' && c2 <= 'F')
+ c2 = 10 + c2 - 'A';
+ else if (c2 >= 'a' && c2 <= 'f')
+ c2 = 10 + c2 - 'a';
+ else break;
+
+ c = (c1<<4) | c2;
+ }
+
+ line[i++] = c;
+
+ if (i == maxsize) break;
+ }
+
+ /* now unescape the line */
+
+
+ line[i] = 0;
+ return 1;
+}
+
+
+/***************************************************************************
+ load all the variables passed to the CGI program
+ ***************************************************************************/
+void cgi_load_variables(void)
+{
+ static pstring line;
+ char *p;
+ int len;
+
+ if (!(p=getenv("CONTENT_LENGTH"))) return;
+
+ len = atoi(p);
+
+ if (len <= 0) return;
+
+
+
+ while (len && grab_line(&len, line, sizeof(line)-1)) {
+ p = strchr(line,'=');
+ if (!p) continue;
+
+ *p = 0;
+
+ variables[num_variables].name = strdup(line);
+ variables[num_variables].value = strdup(p+1);
+
+ if (!variables[num_variables].name ||
+ !variables[num_variables].value)
+ continue;
+
+#if 0
+ printf("%s=%s<br>\n",
+ variables[num_variables].name,
+ variables[num_variables].value);
+#endif
+
+ num_variables++;
+ if (num_variables == MAX_VARIABLES) break;
+ }
+
+ fclose(stdin);
+}
+
+
+/***************************************************************************
+ find a variable passed via CGI
+ ***************************************************************************/
+char *cgi_variable(char *name)
+{
+ int i;
+
+ for (i=0;i<num_variables;i++)
+ if (strcmp(variables[i].name, name) == 0)
+ return variables[i].value;
+ return NULL;
+}
+
+
+/***************************************************************************
+ return the value of a CGI boolean variable.
+ ***************************************************************************/
+int cgi_boolean(char *name, int def)
+{
+ char *p = cgi_variable(name);
+
+ if (!p) return def;
+
+ return strcmp(p, "1") == 0;
+}
diff --git a/source/change-log b/source/change-log
index e120ac6f02a..42a27fe6f68 100644
--- a/source/change-log
+++ b/source/change-log
@@ -1,10 +1,13 @@
-Change Log for Samba
+SUPERCEDED Change Log for Samba
+^^^^^^^^^^
Unless otherwise attributed, all changes were made by
-Andrew.Tridgell@anu.edu.au
+Andrew.Tridgell@anu.edu.au. All bugs to samba-bugs@samba.anu.edu.au.
NOTE: THIS LOG IS IN CHRONOLOGICAL ORDER
+NOTE: From now on the cvs.log file will be used to give a complete log of
+changes to samba. This change-log is now obsolete.
1.5.00 announced to mailing list
@@ -1793,6 +1796,9 @@ NOTE: THIS LOG IS IN CHRONOLOGICAL ORDER
- Linux quota patch from xeno@mix.hsv.no
- try to work around NT passlen2 problem in session setup
- released alpha1
+
+NOTE: From now on the cvs.log file will be used to give a complete log of
+changes to samba. This change-log is now obsolete.
==========
@@ -1869,4 +1875,4 @@ lpd stuff:
Tony Aiuto (tony@ics.com)
make max disk size local
- \ No newline at end of file
+
diff --git a/source/client/client.c b/source/client/client.c
index 504cb5a0bb4..6528919051d 100644
--- a/source/client/client.c
+++ b/source/client/client.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
SMB client
- Copyright (C) Andrew Tridgell 1994-1995
+ Copyright (C) Andrew Tridgell 1994-1997
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
@@ -24,7 +24,6 @@
#endif
#include "includes.h"
-#include "nameserv.h"
#ifndef REGISTER
#define REGISTER 0
@@ -32,20 +31,20 @@
pstring cur_dir = "\\";
pstring cd_path = "";
-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;
-extern struct in_addr bcast_ip;
-static BOOL got_bcast=False;
-
-char cryptkey[8];
-BOOL doencrypt=False;
+extern pstring service;
+extern pstring desthost;
+extern pstring myname;
+extern pstring myhostname;
+extern pstring password;
+extern pstring username;
+extern pstring workgroup;
+char *cmdstr="";
+extern BOOL got_pass;
+extern BOOL connect_as_printer;
+extern BOOL connect_as_ipc;
+extern struct in_addr ipzero;
+
+extern BOOL doencrypt;
extern pstring user_socket_options;
@@ -56,43 +55,43 @@ extern pstring user_socket_options;
/* value for unused fid field in trans2 secondary request */
#define FID_UNUSED (0xFFFF)
-int name_type = 0x20;
+extern int name_type;
-int max_protocol = PROTOCOL_NT1;
+extern int max_protocol;
time_t newer_than = 0;
int archive_level = 0;
-extern struct in_addr myip;
-
extern pstring debugf;
extern int DEBUGLEVEL;
BOOL translation = False;
+extern int cnum;
+extern int mid;
+extern int pid;
+extern int tid;
+extern int gid;
+extern int uid;
+
+extern BOOL have_ip;
+extern int max_xmit;
+
+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 do_this_one(file_info *finfo);
+
/* 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 */
-int cnum = 0;
-int pid = 0;
-int gid = 0;
-int uid = 0;
-int mid = 0;
int myumask = 0755;
-int max_xmit = BUFFER_SIZE;
-
extern pstring scope;
BOOL prompt = True;
@@ -102,8 +101,6 @@ int printmode = 1;
BOOL recurse = False;
BOOL lowercase = False;
-BOOL have_ip = False;
-
struct in_addr dest_ip;
#define SEPARATORS " \t\n\r"
@@ -112,8 +109,8 @@ BOOL abort_mget = True;
extern int Protocol;
-BOOL readbraw_supported = False;
-BOOL writebraw_supported = False;
+extern BOOL readbraw_supported ;
+extern BOOL writebraw_supported;
pstring fileselection = "";
@@ -125,17 +122,15 @@ int get_total_time_ms = 0;
int put_total_size = 0;
int put_total_time_ms = 0;
+/* totals globals */
+int dir_total = 0;
extern int Client;
#define USENMB
-#ifdef KANJI
extern int coding_system;
-#define CNV_LANG(s) (coding_system == DOSV_CODE?s:dos_to_unix(s, False))
-#define CNV_INPUT(s) (coding_system == DOSV_CODE?s:unix_to_dos(s, True))
-static BOOL
-setup_term_code (char *code)
+static BOOL setup_term_code (char *code)
{
int new;
new = interpret_coding_system (code, UNKNOWN_CODE);
@@ -145,38 +140,25 @@ setup_term_code (char *code)
}
return False;
}
-#else
#define CNV_LANG(s) dos2unix_format(s,False)
#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
+send an SMBclose on an SMB file handle
****************************************************************************/
-void setup_pkt(char *outbuf)
+void cli_smb_close(char *inbuf, char *outbuf, int clnt_fd, int c_num, int f_num)
{
- 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);
- }
+ bzero(outbuf,smb_size);
+ set_message(outbuf,3,0,True);
+
+ CVAL (outbuf,smb_com) = SMBclose;
+ SSVAL(outbuf,smb_tid,c_num);
+ cli_setup_pkt(outbuf);
+ SSVAL (outbuf,smb_vwv0, f_num);
+ SIVALS(outbuf,smb_vwv1, -1);
+
+ send_smb(clnt_fd, outbuf);
+ receive_smb(clnt_fd,inbuf,CLIENT_TIMEOUT);
}
/****************************************************************************
@@ -234,7 +216,8 @@ static int readfile(char *b, int size, int n, FILE *f)
n++;
}
- b[i++] = c;
+ if(i < n)
+ b[i++] = c;
}
return(i);
@@ -275,12 +258,24 @@ static BOOL chkpath(char *path,BOOL report)
set_message(outbuf,0,4 + strlen(path2),True);
SCVAL(outbuf,smb_com,SMBchkpth);
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
p = smb_buf(outbuf);
*p++ = 4;
strcpy(p,path2);
+#if 0
+ {
+ /* this little bit of code can be used to extract NT error codes.
+ Just feed a bunch of "cd foo" commands to smbclient then watch
+ in netmon (tridge) */
+ static int code=0;
+ SIVAL(outbuf, smb_rcls, code | 0xC0000000);
+ SSVAL(outbuf, smb_flg2, SVAL(outbuf, smb_flg2) | (1<<14));
+ code++;
+ }
+#endif
+
send_smb(Client,outbuf);
receive_smb(Client,inbuf,CLIENT_TIMEOUT);
@@ -403,7 +398,7 @@ static void do_dskattr(void)
set_message(outbuf,0,0,True);
CVAL(outbuf,smb_com) = SMBdskattr;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
send_smb(Client,outbuf);
receive_smb(Client,inbuf,CLIENT_TIMEOUT);
@@ -477,209 +472,188 @@ static void cmd_cd(char *inbuf,char *outbuf)
****************************************************************************/
static void display_finfo(file_info *finfo)
{
- time_t t = finfo->mtime; /* the time is assumed to be passed as GMT */
- DEBUG(0,(" %-30s%7.7s%10d %s",
- CNV_LANG(finfo->name),
+ if (do_this_one(finfo)) {
+ time_t t = finfo->mtime; /* the time is assumed to be passed as GMT */
+ DEBUG(0,(" %-30s%7.7s%10d %s",
+ CNV_LANG(finfo->name),
attrib_string(finfo->mode),
finfo->size,
- asctime(LocalTime(&t,GMT_TO_LOCAL))));
+ asctime(LocalTime(&t))));
+ dir_total += finfo->size;
+ }
}
+
/****************************************************************************
- do a directory listing, calling fn on each file found
+ do a directory listing, calling fn on each file found. Use the TRANSACT2
+ call for long filenames
****************************************************************************/
-void do_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir)
-{
- DEBUG(5,("do_dir(%s,%x,%s)\n",Mask,attribute,BOOLSTR(recurse_dir)));
- if (Protocol >= PROTOCOL_LANMAN2)
- {
- if (do_long_dir(inbuf,outbuf,Mask,attribute,fn,recurse_dir) > 0)
- return;
- }
-
- expand_mask(Mask,False);
- do_short_dir(inbuf,outbuf,Mask,attribute,fn,recurse_dir);
- return;
-}
-
-/*******************************************************************
- decide if a file should be operated on
- ********************************************************************/
-static BOOL do_this_one(file_info *finfo)
+static int do_long_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir)
{
- if (finfo->mode & aDIR) return(True);
-
- if (newer_than && finfo->mtime < newer_than)
- return(False);
-
- if ((archive_level==1 || archive_level==2) && !(finfo->mode & aARCH))
- return(False);
-
- return(True);
-}
+ 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;
-/****************************************************************************
-interpret a short filename structure
-The length of the structure is returned
-****************************************************************************/
-static int interpret_short_filename(char *p,file_info *finfo)
-{
- finfo->mode = CVAL(p,21);
+ 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;
- /* this date is converted to GMT by make_unix_date */
- finfo->ctime = make_unix_date(p+22);
- finfo->mtime = finfo->atime = finfo->ctime;
- finfo->size = IVAL(p,26);
- strcpy(finfo->name,p+30);
-
- return(DIR_STRUCT_SIZE);
-}
+ uint16 setup;
+ pstring param;
-/****************************************************************************
-interpret a long filename structure - this is mostly guesses at the moment
-The length of the structure is returned
-The structure of a long filename depends on the info level. 260 is used
-by NT and 2 is used by OS/2
-****************************************************************************/
-static int interpret_long_filename(int level,char *p,file_info *finfo)
-{
- if (finfo)
- memcpy(finfo,&def_finfo,sizeof(*finfo));
+ strcpy(mask,Mask);
- switch (level)
+ while (ff_eos == 0)
{
- case 1: /* OS/2 understands this */
- if (finfo)
+ loop_count++;
+ if (loop_count > 200)
{
- /* these dates are converted to GMT by make_unix_date */
- finfo->ctime = make_unix_date2(p+4);
- finfo->atime = make_unix_date2(p+8);
- finfo->mtime = make_unix_date2(p+12);
- finfo->size = IVAL(p,16);
- finfo->mode = CVAL(p,24);
- strcpy(finfo->name,p+27);
+ DEBUG(0,("Error: Looping in FIND_NEXT??\n"));
+ break;
}
- return(28 + CVAL(p,26));
- case 2: /* this is what OS/2 uses mostly */
- if (finfo)
+ if (First)
{
- /* these dates are converted to GMT by make_unix_date */
- finfo->ctime = make_unix_date2(p+4);
- finfo->atime = make_unix_date2(p+8);
- finfo->mtime = make_unix_date2(p+12);
- finfo->size = IVAL(p,16);
- finfo->mode = CVAL(p,24);
- strcpy(finfo->name,p+31);
+ 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);
}
- return(32 + CVAL(p,30));
-
- /* levels 3 and 4 are untested */
- case 3:
- if (finfo)
+ else
{
- /* these dates are probably like the other ones */
- finfo->ctime = make_unix_date2(p+8);
- finfo->atime = make_unix_date2(p+12);
- finfo->mtime = make_unix_date2(p+16);
- finfo->size = IVAL(p,20);
- finfo->mode = CVAL(p,28);
- strcpy(finfo->name,p+33);
+ 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));
}
- return(SVAL(p,4)+4);
+ /* ??? original code added 1 pad byte after param */
- case 4:
- if (finfo)
+ cli_send_trans_request(outbuf,SMBtrans2,NULL,FID_UNUSED,0,
+ NULL,param,&setup,
+ 0,12+strlen(mask)+1,1,
+ BUFFER_SIZE,10,0);
+
+ if (!cli_receive_trans_response(inbuf,SMBtrans2,
+ &resp_data_len,&resp_param_len,
+ &resp_data,&resp_param))
{
- /* these dates are probably like the other ones */
- finfo->ctime = make_unix_date2(p+8);
- finfo->atime = make_unix_date2(p+12);
- finfo->mtime = make_unix_date2(p+16);
- finfo->size = IVAL(p,20);
- finfo->mode = CVAL(p,28);
- strcpy(finfo->name,p+37);
+ DEBUG(3,("FIND%s gave %s\n",First?"FIRST":"NEXT",smb_errstr(inbuf)));
+ break;
}
- return(SVAL(p,4)+4);
- case 260: /* NT uses this, but also accepts 2 */
- if (finfo)
+ /* parse out some important return info */
+ p = resp_param;
+ if (First)
{
- int ret = SVAL(p,0);
- int namelen;
- p += 4; /* next entry offset */
- p += 4; /* fileindex */
+ 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);
+ }
- /* these dates appear to arrive in a weird way. It seems to
- be localtime plus the serverzone given in the initial
- connect. This is GMT when DST is not in effect and one
- hour from GMT otherwise. Can this really be right??
+ if (ff_searchcount == 0)
+ break;
- I suppose this could be called kludge-GMT. Is is the GMT
- you get by using the current DST setting on a different
- localtime. It will be cheap to calculate, I suppose, as
- no DST tables will be needed */
+ /* point to the data bytes */
+ p = resp_data;
- finfo->ctime = interpret_long_date(p); p += 8;
- finfo->atime = interpret_long_date(p); p += 8;
- finfo->mtime = interpret_long_date(p); p += 8; p += 8;
- finfo->size = IVAL(p,0); p += 8;
- p += 8; /* alloc size */
- finfo->mode = CVAL(p,0); p += 4;
- namelen = IVAL(p,0); p += 4;
- p += 4; /* EA size */
- p += 2; /* short name len? */
- p += 24; /* short name? */
- StrnCpy(finfo->name,p,namelen);
- return(ret);
+ /* 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;
+ }
}
- return(SVAL(p,0));
- }
-
- DEBUG(1,("Unknown long filename format %d\n",level));
- return(SVAL(p,0));
-}
+ 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;
-/****************************************************************************
- act on the files in a dir listing
- ****************************************************************************/
-static void dir_action(char *inbuf,char *outbuf,int attribute,file_info *finfo,BOOL recurse_dir,void (*fn)(),BOOL longdir)
-{
+ total_received += ff_searchcount;
- if (!((finfo->mode & aDIR) == 0 && *fileselection &&
- !mask_match(finfo->name,fileselection,False,False)) &&
- !(recurse_dir && (strequal(finfo->name,".") ||
- strequal(finfo->name,".."))))
- {
- if (recurse_dir && (finfo->mode & aDIR))
- {
- pstring mask2;
- pstring sav_dir;
- strcpy(sav_dir,cur_dir);
- strcat(cur_dir,finfo->name);
- strcat(cur_dir,"\\");
- strcpy(mask2,cur_dir);
+ if (resp_data) free(resp_data); resp_data = NULL;
+ if (resp_param) free(resp_param); resp_param = NULL;
- if (!fn)
- DEBUG(0,("\n%s\n",CNV_LANG(cur_dir)));
+ DEBUG(3,("received %d entries (eos=%d resume=%d)\n",
+ ff_searchcount,ff_eos,ff_resume_key));
- strcat(mask2,"*");
+ First = False;
+ }
- if (longdir)
- do_long_dir(inbuf,outbuf,mask2,attribute,fn,True);
- else
- do_dir(inbuf,outbuf,mask2,attribute,fn,True);
+ if (!fn)
+ for (p=dirlist,i=0;i<total_received;i++)
+ {
+ p += interpret_long_filename(info_level,p,&finfo);
+ display_finfo(&finfo);
+ }
- strcpy(cur_dir,sav_dir);
- }
- else
- {
- if (fn && do_this_one(finfo))
- fn(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);
}
@@ -721,7 +695,7 @@ static int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (
CVAL(outbuf,smb_com) = SMBsearch;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,num_asked);
SSVAL(outbuf,smb_vwv1,attribute);
@@ -782,7 +756,7 @@ static int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (
CVAL(outbuf,smb_com) = SMBfclose;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
p = smb_buf(outbuf);
*p++ = 4;
@@ -796,7 +770,7 @@ static int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (
memcpy(p,status,21);
send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT,False);
+ receive_smb(Client,inbuf,CLIENT_TIMEOUT);
if (CVAL(inbuf,smb_rcls) != 0)
DEBUG(0,("Error closing search: %s\n",smb_errstr(inbuf)));
@@ -820,249 +794,231 @@ static int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (
return(num_received);
}
+
+
/****************************************************************************
- receive a SMB trans or trans2 response allocating the necessary memory
+ do a directory listing, calling fn on each file found
****************************************************************************/
-static BOOL receive_trans_response(char *inbuf,int trans,
- int *data_len,int *param_len,
- char **data,char **param)
+void do_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir)
{
- int total_data=0;
- int total_param=0;
- int this_data,this_param;
+ DEBUG(5,("do_dir(%s,%x,%s)\n",Mask,attribute,BOOLSTR(recurse_dir)));
+ if (Protocol >= PROTOCOL_LANMAN2)
+ {
+ if (do_long_dir(inbuf,outbuf,Mask,attribute,fn,recurse_dir) > 0)
+ return;
+ }
- *data_len = *param_len = 0;
+ expand_mask(Mask,False);
+ do_short_dir(inbuf,outbuf,Mask,attribute,fn,recurse_dir);
+ return;
+}
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
- show_msg(inbuf);
+/*******************************************************************
+ decide if a file should be operated on
+ ********************************************************************/
+static BOOL do_this_one(file_info *finfo)
+{
+ if (finfo->mode & aDIR) return(True);
- /* 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)
+ if (newer_than && finfo->mtime < newer_than)
return(False);
- /* parse out the lengths */
- total_data = SVAL(inbuf,smb_tdrcnt);
- total_param = SVAL(inbuf,smb_tprcnt);
+ if ((archive_level==1 || archive_level==2) && !(finfo->mode & aARCH))
+ return(False);
- /* allocate it */
- *data = Realloc(*data,total_data);
- *param = Realloc(*param,total_param);
+ return(True);
+}
- 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);
+/*****************************************************************************
+ Convert a character pointer in a cli_call_api() response to a form we can use.
+ This function contains code to prevent core dumps if the server returns
+ invalid data.
+*****************************************************************************/
+static char *fix_char_ptr(unsigned int datap, unsigned int converter, char *rdata, int rdrcnt)
+{
+if( datap == 0 ) /* turn NULL pointers */
+ { /* into zero length strings */
+ return "";
+ }
+else
+ {
+ unsigned int offset = datap - converter;
- /* 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);
+ if( offset >= rdrcnt )
+ {
+ DEBUG(1,("bad char ptr: datap=%u, converter=%u, rdata=%lu, rdrcnt=%d>", datap, converter, (unsigned long)rdata, rdrcnt));
+ return "<ERROR>";
}
-
- return(True);
+ else
+ {
+ return &rdata[offset];
+ }
+ }
}
/****************************************************************************
- 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)
+interpret a short filename structure
+The length of the structure is returned
+****************************************************************************/
+static int interpret_short_filename(char *p,file_info *finfo)
{
- 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;
+ finfo->mode = CVAL(p,21);
- uint16 setup;
- pstring param;
+ /* this date is converted to GMT by make_unix_date */
+ finfo->ctime = make_unix_date(p+22);
+ finfo->mtime = finfo->atime = finfo->ctime;
+ finfo->size = IVAL(p,26);
+ strcpy(finfo->name,p+30);
+
+ return(DIR_STRUCT_SIZE);
+}
- strcpy(mask,Mask);
+/****************************************************************************
+interpret a long filename structure - this is mostly guesses at the moment
+The length of the structure is returned
+The structure of a long filename depends on the info level. 260 is used
+by NT and 2 is used by OS/2
+****************************************************************************/
+static int interpret_long_filename(int level,char *p,file_info *finfo)
+{
+ if (finfo)
+ memcpy(finfo,&def_finfo,sizeof(*finfo));
- while (ff_eos == 0)
+ switch (level)
{
- loop_count++;
- if (loop_count > 200)
+ case 1: /* OS/2 understands this */
+ if (finfo)
{
- DEBUG(0,("ERROR: Looping in FIND_NEXT??\n"));
- break;
+ /* these dates are converted to GMT by make_unix_date */
+ finfo->ctime = make_unix_date2(p+4);
+ finfo->atime = make_unix_date2(p+8);
+ finfo->mtime = make_unix_date2(p+12);
+ finfo->size = IVAL(p,16);
+ finfo->mode = CVAL(p,24);
+ strcpy(finfo->name,p+27);
}
+ return(28 + CVAL(p,26));
- 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
+ case 2: /* this is what OS/2 uses mostly */
+ if (finfo)
{
- 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));
+ /* these dates are converted to GMT by make_unix_date */
+ finfo->ctime = make_unix_date2(p+4);
+ finfo->atime = make_unix_date2(p+8);
+ finfo->mtime = make_unix_date2(p+12);
+ finfo->size = IVAL(p,16);
+ finfo->mode = CVAL(p,24);
+ strcpy(finfo->name,p+31);
}
- /* ??? 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);
+ return(32 + CVAL(p,30));
- if (!receive_trans_response(inbuf,SMBtrans2,
- &resp_data_len,&resp_param_len,
- &resp_data,&resp_param))
+ /* levels 3 and 4 are untested */
+ case 3:
+ if (finfo)
{
- DEBUG(3,("FIND%s gave %s\n",First?"FIRST":"NEXT",smb_errstr(inbuf)));
- break;
+ /* these dates are probably like the other ones */
+ finfo->ctime = make_unix_date2(p+8);
+ finfo->atime = make_unix_date2(p+12);
+ finfo->mtime = make_unix_date2(p+16);
+ finfo->size = IVAL(p,20);
+ finfo->mode = CVAL(p,28);
+ strcpy(finfo->name,p+33);
}
+ return(SVAL(p,4)+4);
- /* parse out some important return info */
- p = resp_param;
- if (First)
+ case 4:
+ if (finfo)
{
- ff_dir_handle = SVAL(p,0);
- ff_searchcount = SVAL(p,2);
- ff_eos = SVAL(p,4);
- ff_lastname = SVAL(p,8);
+ /* these dates are probably like the other ones */
+ finfo->ctime = make_unix_date2(p+8);
+ finfo->atime = make_unix_date2(p+12);
+ finfo->mtime = make_unix_date2(p+16);
+ finfo->size = IVAL(p,20);
+ finfo->mode = CVAL(p,28);
+ strcpy(finfo->name,p+37);
}
- else
+ return(SVAL(p,4)+4);
+
+ case 260: /* NT uses this, but also accepts 2 */
+ if (finfo)
{
- ff_searchcount = SVAL(p,0);
- ff_eos = SVAL(p,2);
- ff_lastname = SVAL(p,6);
- }
+ int ret = SVAL(p,0);
+ int namelen;
+ p += 4; /* next entry offset */
+ p += 4; /* fileindex */
- if (ff_searchcount == 0)
- break;
+ /* these dates appear to arrive in a weird way. It seems to
+ be localtime plus the serverzone given in the initial
+ connect. This is GMT when DST is not in effect and one
+ hour from GMT otherwise. Can this really be right??
- /* point to the data bytes */
- p = resp_data;
+ I suppose this could be called kludge-GMT. Is is the GMT
+ you get by using the current DST setting on a different
+ localtime. It will be cheap to calculate, I suppose, as
+ no DST tables will be needed */
- /* 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;
- }
+ finfo->ctime = interpret_long_date(p); p += 8;
+ finfo->atime = interpret_long_date(p); p += 8;
+ finfo->mtime = interpret_long_date(p); p += 8; p += 8;
+ finfo->size = IVAL(p,0); p += 8;
+ p += 8; /* alloc size */
+ finfo->mode = CVAL(p,0); p += 4;
+ namelen = IVAL(p,0); p += 4;
+ p += 4; /* EA size */
+ p += 2; /* short name len? */
+ p += 24; /* short name? */
+ StrnCpy(finfo->name,p,namelen);
+ return(ret);
}
- else
- strcpy(mask,"");
-
- /* and add them to the dirlist pool */
- dirlist = Realloc(dirlist,dirlist_len + resp_data_len);
+ return(SVAL(p,0));
+ }
- if (!dirlist)
- {
- DEBUG(0,("Failed to expand dirlist\n"));
- break;
- }
+ DEBUG(1,("Unknown long filename format %d\n",level));
+ return(SVAL(p,0));
+}
- /* 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;
+/****************************************************************************
+ act on the files in a dir listing
+ ****************************************************************************/
+static void dir_action(char *inbuf,char *outbuf,int attribute,file_info *finfo,BOOL recurse_dir,void (*fn)(),BOOL longdir)
+{
- DEBUG(3,("received %d entries (eos=%d resume=%d)\n",
- ff_searchcount,ff_eos,ff_resume_key));
+ if (!((finfo->mode & aDIR) == 0 && *fileselection &&
+ !mask_match(finfo->name,fileselection,False,False)) &&
+ !(recurse_dir && (strequal(finfo->name,".") ||
+ strequal(finfo->name,".."))))
+ {
+ if (recurse_dir && (finfo->mode & aDIR))
+ {
+ pstring mask2;
+ pstring sav_dir;
+ strcpy(sav_dir,cur_dir);
+ strcat(cur_dir,finfo->name);
+ strcat(cur_dir,"\\");
+ strcpy(mask2,cur_dir);
- First = False;
- }
+ if (!fn)
+ DEBUG(0,("\n%s\n",CNV_LANG(cur_dir)));
- if (!fn)
- for (p=dirlist,i=0;i<total_received;i++)
- {
- p += interpret_long_filename(info_level,p,&finfo);
- display_finfo(&finfo);
- }
+ strcat(mask2,"*");
- 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);
- }
+ if (longdir)
+ do_long_dir(inbuf,outbuf,mask2,attribute,fn,True);
+ else
+ do_dir(inbuf,outbuf,mask2,attribute,fn,True);
- /* free up the dirlist buffer */
- if (dirlist) free(dirlist);
- return(total_received);
+ strcpy(cur_dir,sav_dir);
+ }
+ else
+ {
+ if (fn && do_this_one(finfo))
+ fn(finfo);
+ }
+ }
}
@@ -1076,6 +1032,7 @@ static void cmd_dir(char *inbuf,char *outbuf)
fstring buf;
char *p=buf;
+ dir_total = 0;
strcpy(mask,cur_dir);
if(mask[strlen(mask)-1]!='\\')
strcat(mask,"\\");
@@ -1094,6 +1051,8 @@ static void cmd_dir(char *inbuf,char *outbuf)
do_dir(inbuf,outbuf,mask,attribute,NULL,recurse);
do_dskattr();
+
+ DEBUG(3, ("Total bytes listed: %d\n", dir_total));
}
@@ -1140,7 +1099,7 @@ static void do_get(char *rname,char *lname,file_info *finfo1)
CVAL(outbuf,smb_com) = SMBopenX;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,0xFF);
SSVAL(outbuf,smb_vwv2,1);
@@ -1148,6 +1107,8 @@ static void do_get(char *rname,char *lname,file_info *finfo1)
SSVAL(outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
SSVAL(outbuf,smb_vwv5,aSYSTEM | aHIDDEN);
SSVAL(outbuf,smb_vwv8,1);
+ SSVAL(outbuf,smb_vwv11,0xffff);
+ SSVAL(outbuf,smb_vwv12,0xffff);
p = smb_buf(outbuf);
strcpy(p,rname);
@@ -1191,7 +1152,7 @@ static void do_get(char *rname,char *lname,file_info *finfo1)
{
if (CVAL(inbuf,smb_rcls) == ERRSRV &&
SVAL(inbuf,smb_err) == ERRnoresource &&
- reopen_connection(inbuf,outbuf))
+ cli_reopen_connection(inbuf,outbuf))
{
do_get(rname,lname,finfo1);
return;
@@ -1281,7 +1242,7 @@ static void do_get(char *rname,char *lname,file_info *finfo1)
set_message(outbuf,10,0,True);
CVAL(outbuf,smb_com) = SMBreadX;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
if (close_done)
{
@@ -1345,7 +1306,7 @@ static void do_get(char *rname,char *lname,file_info *finfo1)
set_message(outbuf,8,0,True);
CVAL(outbuf,smb_com) = SMBreadbraw;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,fnum);
SIVAL(outbuf,smb_vwv1,nread);
SSVAL(outbuf,smb_vwv3,MIN(finfo.size-nread,readbraw_size));
@@ -1397,7 +1358,7 @@ static void do_get(char *rname,char *lname,file_info *finfo1)
set_message(outbuf,5,0,True);
CVAL(outbuf,smb_com) = SMBread;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,fnum);
SSVAL(outbuf,smb_vwv1,MIN(max_xmit-200,finfo.size - nread));
@@ -1439,17 +1400,7 @@ static void do_get(char *rname,char *lname,file_info *finfo1)
if (!close_done)
{
- bzero(outbuf,smb_size);
- set_message(outbuf,3,0,True);
- CVAL(outbuf,smb_com) = SMBclose;
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
-
- SSVAL(outbuf,smb_vwv0,fnum);
- SIVALS(outbuf,smb_vwv1,-1);
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ cli_smb_close(inbuf, outbuf, Client, cnum, fnum);
if (!ignore_close_error && CVAL(inbuf,smb_rcls) != 0)
{
@@ -1469,7 +1420,7 @@ static void do_get(char *rname,char *lname,file_info *finfo1)
set_message(outbuf,8,strlen(rname)+4,True);
CVAL(outbuf,smb_com) = SMBsetatr;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,finfo.mode & ~(aARCH));
SIVALS(outbuf,smb_vwv1,0);
p = smb_buf(outbuf);
@@ -1493,7 +1444,7 @@ static void do_get(char *rname,char *lname,file_info *finfo1)
get_total_time_ms += this_time;
get_total_size += finfo.size;
- DEBUG(2,("(%g kb/s) (average %g kb/s)\n",
+ DEBUG(1,("(%g kb/s) (average %g kb/s)\n",
finfo.size / (1.024*this_time + 1.0e-4),
get_total_size / (1.024*get_total_time_ms)));
}
@@ -1623,7 +1574,7 @@ static void cmd_more(void)
strcpy(rname,cur_dir);
strcat(rname,"\\");
- sprintf(tmpname,"/tmp/smbmore.%d",getpid());
+ sprintf(tmpname,"%s/smbmore.%d",tmpdir(),(int)getpid());
strcpy(lname,tmpname);
if (!next_token(NULL,rname+strlen(rname),NULL)) {
@@ -1704,7 +1655,7 @@ static BOOL do_mkdir(char *name)
CVAL(outbuf,smb_com) = SMBmkdir;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
p = smb_buf(outbuf);
@@ -1786,7 +1737,7 @@ static int smb_writeraw(char *outbuf,int fnum,int pos,char *buf,int n)
CVAL(outbuf,smb_com) = SMBwritebraw;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,fnum);
SSVAL(outbuf,smb_vwv1,n);
@@ -1828,7 +1779,7 @@ static int smb_writefile(char *outbuf,int fnum,int pos,char *buf,int n)
CVAL(outbuf,smb_com) = SMBwrite;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,fnum);
SSVAL(outbuf,smb_vwv1,n);
@@ -1885,7 +1836,7 @@ static void do_put(char *rname,char *lname,file_info *finfo)
CVAL(outbuf,smb_com) = SMBcreate;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,finfo->mode);
put_dos_date3(outbuf,smb_vwv1,finfo->mtime);
@@ -1961,7 +1912,7 @@ static void do_put(char *rname,char *lname,file_info *finfo)
set_message(outbuf,3,0,True);
CVAL(outbuf,smb_com) = SMBclose;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,fnum);
put_dos_date3(outbuf,smb_vwv1,close_time);
@@ -1994,7 +1945,7 @@ static void do_put(char *rname,char *lname,file_info *finfo)
put_total_time_ms += this_time;
put_total_size += finfo->size;
- DEBUG(2,("(%g kb/s) (average %g kb/s)\n",
+ DEBUG(1,("(%g kb/s) (average %g kb/s)\n",
finfo->size / (1.024*this_time + 1.0e-4),
put_total_size / (1.024*put_total_time_ms)));
}
@@ -2097,7 +2048,7 @@ static void cmd_mput(void)
pstring tmpname;
FILE *f;
- sprintf(tmpname,"/tmp/ls.smb.%d",(int)getpid());
+ sprintf(tmpname,"%s/ls.smb.%d",tmpdir(),(int)getpid());
if (recurse)
sprintf(cmd,"find . -name \"%s\" -print > %s",p,tmpname);
else
@@ -2131,13 +2082,12 @@ static void cmd_mput(void)
strcpy(rname,cur_dir);
strcat(rname,lname);
- if (!do_mkdir(rname))
- {
- strcat(lname,"/");
- if (!seek_list(f,lname))
- break;
- goto again1;
- }
+ if (!chkpath(rname,False) && !do_mkdir(rname)) {
+ strcat(lname,"/");
+ if (!seek_list(f,lname))
+ break;
+ goto again1;
+ }
continue;
}
@@ -2178,7 +2128,7 @@ static void do_cancel(int job)
bzero(param,sizeof(param));
p = param;
- SSVAL(p,0,81); /* api number */
+ SSVAL(p,0,81); /* DosPrintJobDel() */
p += 2;
strcpy(p,"W");
p = skip_string(p,1);
@@ -2187,10 +2137,10 @@ static void do_cancel(int job)
SSVAL(p,0,job);
p += 2;
- if (call_api(PTR_DIFF(p,param),0,
- 6,1000,
+ if (cli_call_api(PIPE_LANMAN, PTR_DIFF(p,param),0, 0,
+ 6, 1000,
&rprcnt,&rdrcnt,
- param,NULL,
+ param,NULL, NULL,
&rparam,&rdata))
{
int res = SVAL(rparam,0);
@@ -2261,12 +2211,12 @@ static void cmd_stat(char *inbuf,char *outbuf)
strcpy(p,cur_dir);
strcat(p,buf);
- send_trans_request(outbuf,SMBtrans2,NULL,FID_UNUSED,0,
+ cli_send_trans_request(outbuf,SMBtrans2,NULL,FID_UNUSED,0,
NULL,param,&setup,
0,6 + strlen(p)+1,1,
BUFFER_SIZE,2,0);
- receive_trans_response(inbuf,SMBtrans2,
+ cli_receive_trans_response(inbuf,SMBtrans2,
&resp_data_len,&resp_param_len,
&resp_data,&resp_param);
@@ -2324,7 +2274,7 @@ static void cmd_print(char *inbuf,char *outbuf )
CVAL(outbuf,smb_com) = SMBsplopen;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,0);
SSVAL(outbuf,smb_vwv1,printmode);
@@ -2380,7 +2330,7 @@ static void cmd_print(char *inbuf,char *outbuf )
CVAL(outbuf,smb_com) = SMBsplwr;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,fnum);
SSVAL(outbuf,smb_vwv1,n+3);
@@ -2405,7 +2355,7 @@ static void cmd_print(char *inbuf,char *outbuf )
set_message(outbuf,1,0,True);
CVAL(outbuf,smb_com) = SMBsplclose;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,fnum);
@@ -2425,7 +2375,8 @@ static void cmd_print(char *inbuf,char *outbuf )
}
/****************************************************************************
-print a file
+show a print queue - this is deprecated as it uses the old smb that
+has limited support - the correct call is the cmd_p_queue_4() after this.
****************************************************************************/
static void cmd_queue(char *inbuf,char *outbuf )
{
@@ -2437,7 +2388,7 @@ static void cmd_queue(char *inbuf,char *outbuf )
CVAL(outbuf,smb_com) = SMBsplretq;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,32); /* a max of 20 entries is to be shown */
SSVAL(outbuf,smb_vwv1,0); /* the index into the queue */
@@ -2487,6 +2438,222 @@ static void cmd_queue(char *inbuf,char *outbuf )
/****************************************************************************
+show information about a print queue
+****************************************************************************/
+static void cmd_p_queue_4(char *inbuf,char *outbuf )
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt, rprcnt;
+ pstring param;
+ int result_code=0;
+
+ if (!connect_as_printer)
+ {
+ DEBUG(0,("WARNING: You didn't use the -P option to smbclient.\n"));
+ DEBUG(0,("Trying to print without -P may fail\n"));
+ }
+
+ bzero(param,sizeof(param));
+
+ p = param;
+ SSVAL(p,0,76); /* API function number 76 (DosPrintJobEnum) */
+ p += 2;
+ strcpy(p,"zWrLeh"); /* parameter description? */
+ p = skip_string(p,1);
+ strcpy(p,"WWzWWDDzz"); /* returned data format */
+ p = skip_string(p,1);
+ strcpy(p,strrchr(service,'\\')+1); /* name of queue */
+ p = skip_string(p,1);
+ SSVAL(p,0,2); /* API function level 2, PRJINFO_2 data structure */
+ SSVAL(p,2,1000); /* size of bytes of returned data buffer */
+ p += 4;
+ strcpy(p,""); /* subformat */
+ p = skip_string(p,1);
+
+ DEBUG(1,("Calling DosPrintJobEnum()...\n"));
+ if( cli_call_api(PIPE_LANMAN, PTR_DIFF(p,param), 0,
+ 10, 0, 4096,
+ &rprcnt, &rdrcnt,
+ param, NULL, NULL,
+ &rparam, &rdata) )
+ {
+ int converter;
+ result_code = SVAL(rparam,0);
+ converter = SVAL(rparam,2); /* conversion factor */
+
+ DEBUG(2,("returned %d bytes of parameters, %d bytes of data, %d records\n", rprcnt, rdrcnt, SVAL(rparam,4) ));
+
+ if (result_code == 0) /* if no error, */
+ {
+ int i;
+ uint16 JobId;
+ uint16 Priority;
+ uint32 Size;
+ char *UserName;
+ char *JobName;
+ char *JobTimeStr;
+ time_t JobTime;
+ char PrinterName[20];
+
+ strcpy(PrinterName,strrchr(service,'\\')+1); /* name of queue */
+ strlower(PrinterName); /* in lower case */
+
+ p = rdata; /* received data */
+ for( i = 0; i < SVAL(rparam,4); ++i)
+ {
+ JobId = SVAL(p,0);
+ Priority = SVAL(p,2);
+ UserName = fix_char_ptr(SVAL(p,4), converter, rdata, rdrcnt);
+ strlower(UserName);
+ Priority = SVAL(p,2);
+ JobTime = make_unix_date3( p + 12);
+ JobTimeStr = asctime(LocalTime( &JobTime));
+ Size = IVAL(p,16);
+ JobName = fix_char_ptr(SVAL(p,24), converter, rdata, rdrcnt);
+
+
+ printf("%s-%u %s priority %u %s %s %u bytes\n",
+ PrinterName, JobId, UserName,
+ Priority, JobTimeStr, JobName, Size);
+
+#if 0 /* DEBUG code */
+ printf("Job Id: \"%u\"\n", SVAL(p,0));
+ printf("Priority: \"%u\"\n", SVAL(p,2));
+
+ printf("User Name: \"%s\"\n", fix_char_ptr(SVAL(p,4), converter, rdata, rdrcnt) );
+ printf("Position: \"%u\"\n", SVAL(p,8));
+ printf("Status: \"%u\"\n", SVAL(p,10));
+
+ JobTime = make_unix_date3( p + 12);
+ printf("Submitted: \"%s\"\n", asctime(LocalTime(&JobTime)));
+ printf("date: \"%u\"\n", SVAL(p,12));
+
+ printf("Size: \"%u\"\n", SVAL(p,16));
+ printf("Comment: \"%s\"\n", fix_char_ptr(SVAL(p,20), converter, rdata, rdrcnt) );
+ printf("Document: \"%s\"\n", fix_char_ptr(SVAL(p,24), converter, rdata, rdrcnt) );
+#endif /* DEBUG CODE */
+ p += 28;
+ }
+ }
+ }
+ else /* cli_call_api() failed */
+ {
+ printf("Failed, error = %d\n", result_code);
+ }
+
+ /* If any parameters or data were returned, free the storage. */
+ if(rparam) free(rparam);
+ if(rdata) free(rdata);
+
+ return;
+}
+
+/****************************************************************************
+show information about a print queue
+****************************************************************************/
+static void cmd_qinfo(char *inbuf,char *outbuf )
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt, rprcnt;
+ pstring param;
+ int result_code=0;
+
+ bzero(param,sizeof(param));
+
+ p = param;
+ SSVAL(p,0,70); /* API function number 70 (DosPrintQGetInfo) */
+ p += 2;
+ strcpy(p,"zWrLh"); /* parameter description? */
+ p = skip_string(p,1);
+ strcpy(p,"zWWWWzzzzWWzzl"); /* returned data format */
+ p = skip_string(p,1);
+ strcpy(p,strrchr(service,'\\')+1); /* name of queue */
+ p = skip_string(p,1);
+ SSVAL(p,0,3); /* API function level 3, just queue info, no job info */
+ SSVAL(p,2,1000); /* size of bytes of returned data buffer */
+ p += 4;
+ strcpy(p,""); /* subformat */
+ p = skip_string(p,1);
+
+ DEBUG(1,("Calling DosPrintQueueGetInfo()...\n"));
+ if( cli_call_api(PIPE_LANMAN, PTR_DIFF(p,param), 0, 0,
+ 10, 4096,
+ &rprcnt, &rdrcnt,
+ param, NULL, NULL,
+ &rparam, &rdata) )
+ {
+ int converter;
+ result_code = SVAL(rparam,0);
+ converter = SVAL(rparam,2); /* conversion factor */
+
+ DEBUG(2,("returned %d bytes of parameters, %d bytes of data, %d records\n", rprcnt, rdrcnt, SVAL(rparam,4) ));
+
+ if (result_code == 0) /* if no error, */
+ {
+ p = rdata; /* received data */
+
+ printf("Name: \"%s\"\n", fix_char_ptr(SVAL(p,0), converter, rdata, rdrcnt) );
+ printf("Priority: %u\n", SVAL(p,4) );
+ printf("Start time: %u\n", SVAL(p,6) );
+ printf("Until time: %u\n", SVAL(p,8) );
+ printf("Seperator file: \"%s\"\n", fix_char_ptr(SVAL(p,12), converter, rdata, rdrcnt) );
+ printf("Print processor: \"%s\"\n", fix_char_ptr(SVAL(p,16), converter, rdata, rdrcnt) );
+ printf("Parameters: \"%s\"\n", fix_char_ptr(SVAL(p,20), converter, rdata, rdrcnt) );
+ printf("Comment: \"%s\"\n", fix_char_ptr(SVAL(p,24), converter, rdata, rdrcnt) );
+ printf("Status: %u\n", SVAL(p,28) );
+ printf("Jobs: %u\n", SVAL(p,30) );
+ printf("Printers: \"%s\"\n", fix_char_ptr(SVAL(p,32), converter, rdata, rdrcnt) );
+ printf("Drivername: \"%s\"\n", fix_char_ptr(SVAL(p,36), converter, rdata, rdrcnt) );
+
+ /* Dump the driver data */
+ {
+ int count, x, y, c;
+ char *ddptr;
+
+ ddptr = rdata + SVAL(p,40) - converter;
+ if( SVAL(p,40) == 0 ) {count = 0;} else {count = IVAL(ddptr,0);}
+ printf("Driverdata: size=%d, version=%u\n", count, IVAL(ddptr,4) );
+
+ for(x=8; x < count; x+=16)
+ {
+ for(y=0; y < 16; y++)
+ {
+ if( (x+y) < count )
+ printf("%2.2X ", CVAL(ddptr,(x+y)) );
+ else
+ fputs(" ", stdout);
+ }
+ for(y=0; y < 16 && (x+y) < count; y++)
+ {
+ c = CVAL(ddptr,(x+y));
+ if(isprint(c))
+ fputc(c, stdout);
+ else
+ fputc('.', stdout);
+ }
+ fputc('\n', stdout);
+ }
+ }
+
+ }
+ }
+ else /* cli_call_api() failed */
+ {
+ printf("Failed, error = %d\n", result_code);
+ }
+
+ /* If any parameters or data were returned, free the storage. */
+ if(rparam) free(rparam);
+ if(rdata) free(rdata);
+
+ return;
+}
+
+/****************************************************************************
delete some files
****************************************************************************/
static void do_del(file_info *finfo)
@@ -2515,7 +2682,7 @@ static void do_del(file_info *finfo)
CVAL(outbuf,smb_com) = SMBunlink;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,0);
@@ -2581,7 +2748,7 @@ static void cmd_rmdir(char *inbuf,char *outbuf )
CVAL(outbuf,smb_com) = SMBrmdir;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
p = smb_buf(outbuf);
@@ -2625,7 +2792,7 @@ static void cmd_rename(char *inbuf,char *outbuf )
CVAL(outbuf,smb_com) = SMBmv;
SSVAL(outbuf,smb_tid,cnum);
SSVAL(outbuf,smb_vwv0,aHIDDEN | aDIR | aSYSTEM);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
p = smb_buf(outbuf);
*p++ = 4;
@@ -2670,7 +2837,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;
@@ -2776,649 +2943,18 @@ static void cmd_lcd(void)
/****************************************************************************
-send a session request
-****************************************************************************/
-static BOOL send_session_request(char *inbuf,char *outbuf)
-{
- fstring dest;
- char *p;
- int len = 4;
- /* send a session request (RFC 8002) */
-
- strcpy(dest,desthost);
- p = strchr(dest,'.');
- if (p) *p = 0;
-
- /* put in the destination name */
- p = outbuf+len;
- name_mangle(dest,p,name_type);
- len += name_len(p);
-
- /* and my name */
- p = outbuf+len;
- name_mangle(myname,p,0);
- len += name_len(p);
-
- /* setup the packet length */
- _smb_setlen(outbuf,len);
- CVAL(outbuf,0) = 0x81;
-
- send_smb(Client,outbuf);
- DEBUG(5,("Sent session request\n"));
-
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- if (CVAL(inbuf,0) == 0x84) /* C. Hoch 9/14/95 Start */
- {
- /* For information, here is the response structure.
- * We do the byte-twiddling to for portability.
- struct RetargetResponse{
- unsigned char type;
- unsigned char flags;
- int16 length;
- int32 ip_addr;
- int16 port;
- };
- */
- extern int Client;
- int port = (CVAL(inbuf,8)<<8)+CVAL(inbuf,9);
- /* SESSION RETARGET */
- putip((char *)&dest_ip,inbuf+4);
-
- close_sockets();
- Client = open_socket_out(SOCK_STREAM, &dest_ip, port);
- if (Client == -1)
- return False;
-
- DEBUG(3,("Retargeted\n"));
-
- set_socket_options(Client,user_socket_options);
-
- /* Try again */
- return 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);
-}
-
-
-/****************************************************************************
-send a login command
-****************************************************************************/
-static BOOL 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;
- struct {
- int prot;
- char *name;
- }
- prots[] =
- {
- {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
- {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
- {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
- {PROTOCOL_LANMAN1,"LANMAN1.0"},
- {PROTOCOL_LANMAN2,"LM1.2X002"},
- {PROTOCOL_LANMAN2,"Samba"},
- {PROTOCOL_NT1,"NT LM 0.12"},
- {PROTOCOL_NT1,"NT LANMAN 1.0"},
- {-1,NULL}
- };
- char *pass = NULL;
- pstring dev;
- char *p;
- int numprots;
-
- if (was_null)
- {
- inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
- outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
- }
-
-#if AJT
- if (strstr(service,"IPC$")) connect_as_ipc = True;
-#endif
-
- strcpy(dev,"A:");
- if (connect_as_printer)
- strcpy(dev,"LPT1:");
- if (connect_as_ipc)
- strcpy(dev,"IPC");
-
-
- if (start_session && !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;
- setup_pkt(outbuf);
-
- CVAL(smb_buf(outbuf),0) = 2;
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- show_msg(inbuf);
-
- if (CVAL(inbuf,smb_rcls) != 0 || ((int)SVAL(inbuf,smb_vwv0) >= numprots))
- {
- DEBUG(0,("SMBnegprot failed. myname=%s destname=%s - %s \n",
- myname,desthost,smb_errstr(inbuf)));
- if (was_null)
- {
- free(inbuf);
- free(outbuf);
- }
- return(False);
- }
-
- Protocol = prots[SVAL(inbuf,smb_vwv0)].prot;
-
-
- if (Protocol < PROTOCOL_NT1) {
- sec_mode = SVAL(inbuf,smb_vwv1);
- max_xmit = SVAL(inbuf,smb_vwv2);
- sesskey = IVAL(inbuf,smb_vwv6);
- serverzone = SVALS(inbuf,smb_vwv10)*60;
- /* this time is converted to GMT by make_unix_date */
- servertime = make_unix_date(inbuf+smb_vwv8);
- if (Protocol >= PROTOCOL_COREPLUS) {
- readbraw_supported = ((SVAL(inbuf,smb_vwv5) & 0x1) != 0);
- writebraw_supported = ((SVAL(inbuf,smb_vwv5) & 0x2) != 0);
- }
- crypt_len = smb_buflen(inbuf);
- memcpy(cryptkey,smb_buf(inbuf),8);
- DEBUG(3,("max mux %d\n",SVAL(inbuf,smb_vwv3)));
- max_vcs = SVAL(inbuf,smb_vwv4);
- DEBUG(3,("max vcs %d\n",max_vcs));
- DEBUG(3,("max blk %d\n",SVAL(inbuf,smb_vwv5)));
- } else {
- /* NT protocol */
- sec_mode = CVAL(inbuf,smb_vwv1);
- max_xmit = IVAL(inbuf,smb_vwv3+1);
- sesskey = IVAL(inbuf,smb_vwv7+1);
- serverzone = SVALS(inbuf,smb_vwv15+1)*60;
- /* this time arrives in real GMT */
- servertime = interpret_long_date(inbuf+smb_vwv11+1);
- crypt_len = CVAL(inbuf,smb_vwv16+1);
- memcpy(cryptkey,smb_buf(inbuf),8);
- if (IVAL(inbuf,smb_vwv9+1) & 1)
- readbraw_supported = writebraw_supported = True;
- DEBUG(3,("max mux %d\n",SVAL(inbuf,smb_vwv1+1)));
- max_vcs = SVAL(inbuf,smb_vwv2+1);
- DEBUG(3,("max vcs %d\n",max_vcs));
- DEBUG(3,("max raw %d\n",IVAL(inbuf,smb_vwv5+1)));
- DEBUG(3,("capabilities 0x%x\n",IVAL(inbuf,smb_vwv9+1)));
- }
-
- DEBUG(3,("Sec mode %d\n",SVAL(inbuf,smb_vwv1)));
- DEBUG(3,("max xmt %d\n",max_xmit));
- DEBUG(3,("Got %d byte crypt key\n",crypt_len));
- DEBUG(3,("Chose protocol [%s]\n",prots[SVAL(inbuf,smb_vwv0)].name));
-
- doencrypt = ((sec_mode & 2) != 0);
-
- if (servertime) {
- static BOOL done_time = False;
- if (!done_time) {
- DEBUG(1,("Server time is %sTimezone is UTC%+02.1f\n",
- asctime(LocalTime(&servertime,GMT_TO_LOCAL)),
- -(double)(serverzone/3600.0)));
- done_time = True;
- }
- }
-
- get_pass:
-
- if (got_pass)
- pass = password;
- else
- pass = (char *)getpass("Password: ");
-
- if (Protocol >= PROTOCOL_LANMAN1 && use_setup)
- {
- fstring pword;
- int passlen = strlen(pass)+1;
- strcpy(pword,pass);
-
-#ifdef SMB_PASSWD
- if (doencrypt && *pass) {
- DEBUG(3,("Using encrypted passwords\n"));
- passlen = 24;
- SMBencrypt(pass,cryptkey,pword);
- }
-#else
- doencrypt = False;
-#endif
-
- /* if in share level security then don't send a password now */
- if (!(sec_mode & 1)) {strcpy(pword, "");passlen=1;}
-
- /* send a session setup command */
- bzero(outbuf,smb_size);
-
- if (Protocol < PROTOCOL_NT1) {
- set_message(outbuf,10,1 + strlen(username) + passlen,True);
- CVAL(outbuf,smb_com) = SMBsesssetupX;
- 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;
- setup_pkt(outbuf);
-
- CVAL(outbuf,smb_vwv0) = 0xFF;
- SSVAL(outbuf,smb_vwv2,BUFFER_SIZE);
- SSVAL(outbuf,smb_vwv3,2);
- SSVAL(outbuf,smb_vwv4,getpid());
- SIVAL(outbuf,smb_vwv5,sesskey);
- SSVAL(outbuf,smb_vwv7,passlen);
- SSVAL(outbuf,smb_vwv8,0);
- p = smb_buf(outbuf);
- memcpy(p,pword,passlen); p += SVAL(outbuf,smb_vwv7);
- strcpy(p,username);p = skip_string(p,1);
- strcpy(p,workgroup);p = skip_string(p,1);
- strcpy(p,"Unix");p = skip_string(p,1);
- strcpy(p,"Samba");p = skip_string(p,1);
- set_message(outbuf,13,PTR_DIFF(p,smb_buf(outbuf)),False);
- }
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- show_msg(inbuf);
-
- if (CVAL(inbuf,smb_rcls) != 0)
- {
- if (! *pass &&
- ((CVAL(inbuf,smb_rcls) == ERRDOS &&
- SVAL(inbuf,smb_err) == ERRnoaccess) ||
- (CVAL(inbuf,smb_rcls) == ERRSRV &&
- SVAL(inbuf,smb_err) == ERRbadpw)))
- {
- got_pass = False;
- DEBUG(3,("resending login\n"));
- goto get_pass;
- }
-
- DEBUG(0,("Session setup failed for username=%s myname=%s destname=%s %s\n",
- username,myname,desthost,smb_errstr(inbuf)));
- DEBUG(0,("You might find the -U, -W or -n options useful\n"));
- DEBUG(0,("Sometimes you have to use `-n USERNAME' (particularly with OS/2)\n"));
- DEBUG(0,("Some servers also insist on uppercase-only passwords\n"));
- if (was_null)
- {
- free(inbuf);
- free(outbuf);
- }
- return(False);
- }
-
- if (Protocol >= PROTOCOL_NT1) {
- char *domain,*os,*lanman;
- p = smb_buf(inbuf);
- os = p;
- lanman = skip_string(os,1);
- domain = skip_string(lanman,1);
- if (*domain || *os || *lanman)
- DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",domain,os,lanman));
- }
-
- /* use the returned uid from now on */
- if (SVAL(inbuf,smb_uid) != uid)
- DEBUG(3,("Server gave us a UID of %d. We gave %d\n",
- SVAL(inbuf,smb_uid),uid));
- uid = SVAL(inbuf,smb_uid);
- }
-
- /* now we've got a connection - send a tcon message */
- bzero(outbuf,smb_size);
-
- if (strncmp(service,"\\\\",2) != 0)
- {
- DEBUG(0,("\nWarning: Your service name doesn't start with \\\\. This is probably incorrect.\n"));
- DEBUG(0,("Perhaps try replacing each \\ with \\\\ on the command line?\n\n"));
- }
-
-
- again2:
-
- {
- int passlen = strlen(pass)+1;
- fstring pword;
- strcpy(pword,pass);
-
-#ifdef SMB_PASSWD
- if (doencrypt && *pass) {
- passlen=24;
- SMBencrypt(pass,cryptkey,pword);
- }
-#endif
-
- /* if in user level security then don't send a password now */
- if ((sec_mode & 1)) {
- strcpy(pword, ""); passlen=1;
- }
-
- set_message(outbuf,4,2 + strlen(service) + passlen + strlen(dev),True);
- CVAL(outbuf,smb_com) = SMBtconX;
- setup_pkt(outbuf);
-
- SSVAL(outbuf,smb_vwv0,0xFF);
- SSVAL(outbuf,smb_vwv3,passlen);
-
- p = smb_buf(outbuf);
- memcpy(p,pword,passlen);
- p += passlen;
- strcpy(p,service);
- p = skip_string(p,1);
- strcpy(p,dev);
- }
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-
- /* trying again with a blank password */
- if (CVAL(inbuf,smb_rcls) != 0 &&
- (int)strlen(pass) > 0 &&
- !doencrypt &&
- Protocol >= PROTOCOL_LANMAN1)
- {
- DEBUG(2,("first SMBtconX failed, trying again. %s\n",smb_errstr(inbuf)));
- strcpy(pass,"");
- goto again2;
- }
-
- if (CVAL(inbuf,smb_rcls) != 0)
- {
- DEBUG(0,("SMBtconX failed. %s\n",smb_errstr(inbuf)));
- DEBUG(0,("Perhaps you are using the wrong sharename, username or password?\n"));
- DEBUG(0,("Some servers insist that these be in uppercase\n"));
- if (was_null)
- {
- free(inbuf);
- free(outbuf);
- }
- return(False);
- }
-
-
- max_xmit = MIN(max_xmit,BUFFER_SIZE-4);
- if (max_xmit <= 0)
- max_xmit = BUFFER_SIZE - 4;
-
- cnum = SVAL(inbuf,smb_tid);
-
- DEBUG(3,("Connected with cnum=%d max_xmit=%d\n",cnum,max_xmit));
-
- if (was_null)
- {
- free(inbuf);
- free(outbuf);
- }
- return True;
-}
-
-
-/****************************************************************************
-send a logout command
-****************************************************************************/
-static void 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);
- 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
-****************************************************************************/
-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 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);
-
- send_trans_request(outbuf,SMBtrans,"\\PIPE\\LANMAN",0,0,
- data,param,NULL,
- drcnt,prcnt,0,
- mdrcnt,mprcnt,0);
-
- return (receive_trans_response(inbuf,SMBtrans,
- rdrcnt,rprcnt,
- rdata,rparam));
-}
-
-/****************************************************************************
- send a SMB trans or trans2 request
- ****************************************************************************/
-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)
-{
- 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);
- 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);
-}
-
-/****************************************************************************
try and browse available connections on a host
****************************************************************************/
static BOOL browse_host(BOOL sort)
{
#ifdef NOSTRCASECMP
+/* If strcasecmp is already defined, remove it. */
+#ifdef strcasecmp
+#undef strcasecmp
+#endif /* strcasecmp */
#define strcasecmp StrCaseCmp
-#endif
+#endif /* NOSTRCASECMP */
+
extern int strcasecmp();
char *rparam = NULL;
@@ -3440,10 +2976,10 @@ static BOOL browse_host(BOOL sort)
SSVAL(p,2,BUFFER_SIZE);
p += 4;
- if (call_api(PTR_DIFF(p,param),0,
- 1024,BUFFER_SIZE,
+ if (cli_call_api(PIPE_LANMAN, PTR_DIFF(p,param),0, 0,
+ 1024, BUFFER_SIZE,
&rprcnt,&rdrcnt,
- param,NULL,
+ param,NULL, NULL,
&rparam,&rdata))
{
int res = SVAL(rparam,0);
@@ -3522,7 +3058,7 @@ static void server_info()
bzero(param,sizeof(param));
p = param;
- SSVAL(p,0,63); /* api number */
+ SSVAL(p,0,63); /* NetServerGetInfo()? */
p += 2;
strcpy(p,"WrLh");
p = skip_string(p,1);
@@ -3532,10 +3068,10 @@ static void server_info()
SSVAL(p,2,1000);
p += 6;
- if (call_api(PTR_DIFF(p,param),0,
- 6,1000,
+ if (cli_call_api(PIPE_LANMAN, PTR_DIFF(p,param),0, 0,
+ 6, 1000,
&rprcnt,&rdrcnt,
- param,NULL,
+ param,NULL, NULL,
&rparam,&rdata))
{
int res = SVAL(rparam,0);
@@ -3563,39 +3099,54 @@ static void server_info()
/****************************************************************************
try and browse available connections on a host
****************************************************************************/
-static BOOL list_servers()
+static BOOL list_servers(char *wk_grp)
{
char *rparam = NULL;
char *rdata = NULL;
int rdrcnt,rprcnt;
- char *p;
+ char *p,*svtype_p;
pstring param;
int uLevel = 1;
int count = 0;
+ BOOL ok = False;
+ BOOL generic_request = False;
+
+
+ if (strequal(wk_grp,"WORKGROUP")) {
+ /* we won't specify a workgroup */
+ generic_request = True;
+ }
/* now send a SMBtrans command with api ServerEnum? */
p = param;
SSVAL(p,0,0x68); /* api number */
p += 2;
- strcpy(p,"WrLehDO");
+
+ strcpy(p,generic_request?"WrLehDO":"WrLehDz");
p = skip_string(p,1);
strcpy(p,"B16BBDz");
-#if 0
- strcpy(p,getenv("XX_STR2"));
-#endif
p = skip_string(p,1);
SSVAL(p,0,uLevel);
- SSVAL(p,2,0x2000); /* buf length */
+ SSVAL(p,2,BUFFER_SIZE - SAFETY_MARGIN); /* buf length */
p += 4;
- SIVAL(p,0,SV_TYPE_ALL);
+ svtype_p = p;
+ p += 4;
- if (call_api(PTR_DIFF(p+4,param),0,
- 8,10000,
+ if (!generic_request) {
+ strcpy(p, wk_grp);
+ p = skip_string(p,1);
+ }
+
+ /* first ask for a list of servers in this workgroup */
+ SIVAL(svtype_p,0,SV_TYPE_ALL);
+
+ if (cli_call_api(PIPE_LANMAN, PTR_DIFF(p+4,param),0, 0,
+ 8, BUFFER_SIZE - SAFETY_MARGIN,
&rprcnt,&rdrcnt,
- param,NULL,
+ param,NULL, NULL,
&rparam,&rdata))
{
int res = SVAL(rparam,0);
@@ -3618,7 +3169,8 @@ static BOOL list_servers()
printf("\t%-16.16s %s\n",
sname,
comment_offset?rdata+comment_offset-converter:"");
-
+
+ ok=True;
p2 += 26;
}
}
@@ -3627,12 +3179,13 @@ static BOOL list_servers()
if (rparam) {free(rparam); rparam = NULL;}
if (rdata) {free(rdata); rdata = NULL;}
- SIVAL(p,0,SV_TYPE_DOMAIN_ENUM);
+ /* now ask for a list of workgroups */
+ SIVAL(svtype_p,0,SV_TYPE_DOMAIN_ENUM);
- if (call_api(PTR_DIFF(p+4,param),0,
- 8,10000,
+ if (cli_call_api(PIPE_LANMAN, PTR_DIFF(p+4,param),0, 0,
+ 8, BUFFER_SIZE - SAFETY_MARGIN,
&rprcnt,&rdrcnt,
- param,NULL,
+ param,NULL, NULL,
&rparam,&rdata))
{
int res = SVAL(rparam,0);
@@ -3656,6 +3209,7 @@ static BOOL list_servers()
sname,
comment_offset?rdata+comment_offset-converter:"");
+ ok=True;
p2 += 26;
}
}
@@ -3664,14 +3218,10 @@ static BOOL list_servers()
if (rparam) free(rparam);
if (rdata) free(rdata);
- return(count>0);
+ return(ok);
}
-
-
-void cmd_help();
-
/* This defines the commands supported by this client */
struct
{
@@ -3698,6 +3248,7 @@ struct
{"md",cmd_mkdir,"<directory> make a directory"},
{"rmdir",cmd_rmdir,"<directory> remove a directory"},
{"rd",cmd_rmdir,"<directory> remove a directory"},
+ {"pq",cmd_p_queue_4,"enumerate the print queue"},
{"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput"},
{"recurse",cmd_recurse,"toggle directory recursion for mget and mput"},
{"translate",cmd_translate,"toggle text translation for printing"},
@@ -3705,11 +3256,12 @@ struct
{"print",cmd_print,"<file name> print a file"},
{"printmode",cmd_printmode,"<graphics or text> set the print mode"},
{"queue",cmd_queue,"show the print queue"},
+ {"qinfo",cmd_qinfo,"show print queue information"},
{"cancel",cmd_cancel,"<jobid> cancel a print queue entry"},
{"stat",cmd_stat,"<file> get info on a file (experimental!)"},
- {"quit",send_logout,"logoff the server"},
- {"q",send_logout,"logoff the server"},
- {"exit",send_logout,"logoff the server"},
+ {"quit",cli_send_logout,"logoff the server"},
+ {"q",cli_send_logout,"logoff the server"},
+ {"exit",cli_send_logout,"logoff the server"},
{"newer",cmd_newer,"<file> only mget files newer than the specified local file"},
{"archive",cmd_archive,"<level>\n0=ignore archive bit\n1=only get archive files\n2=only get archive files and reset archive bit\n3=get all files and reset archive bit"},
{"tar",cmd_tar,"tar <c|x>[IXbgNa] current directory to/from <file name>" },
@@ -3783,92 +3335,6 @@ void cmd_help(void)
}
/****************************************************************************
-open the client sockets
-****************************************************************************/
-static BOOL open_sockets(int port )
-{
- static int last_port;
- char *host;
- pstring service2;
- extern int Client;
-#ifdef USENMB
- BOOL failed = True;
-#endif
-
- if (port == 0) port=last_port;
- last_port=port;
-
- strupper(service);
-
- if (*desthost)
- {
- host = desthost;
- }
- else
- {
- strcpy(service2,service);
- host = strtok(service2,"\\/");
- if (!host) {
- DEBUG(0,("Badly formed host name\n"));
- return(False);
- }
- strcpy(desthost,host);
- }
-
- DEBUG(3,("Opening sockets\n"));
-
- if (*myname == 0)
- {
- get_myname(myname,NULL);
- strupper(myname);
- }
-
- if (!have_ip)
- {
- struct hostent *hp;
-
- if ((hp = Get_Hostbyname(host))) {
- putip((char *)&dest_ip,(char *)hp->h_addr);
- failed = False;
- } else {
-#ifdef USENMB
- /* Try and resolve the name with the netbios server */
- int bcast;
- pstring hs;
- struct in_addr ip1, ip2;
-
- if ((bcast = open_socket_in(SOCK_DGRAM, 0, 3)) != -1) {
- set_socket_options (bcast, "SO_BROADCAST");
-
- if (!got_bcast && get_myname(hs, &ip1)) {
- get_broadcast(&ip1, &bcast_ip, &ip2);
- }
-
- if (name_query(bcast, host, 0x20, True, True, bcast_ip, &dest_ip,0)){
- failed = False;
- }
- close (bcast);
- }
-#endif
- if (failed) {
- DEBUG(0,("Get_Hostbyname: Unknown host %s.\n",host));
- return False;
- }
- }
- }
-
- Client = open_socket_out(SOCK_STREAM, &dest_ip, port);
- if (Client == -1)
- return False;
-
- DEBUG(3,("Connected\n"));
-
- set_socket_options(Client,user_socket_options);
-
- return True;
-}
-
-/****************************************************************************
wait for keyboard activity, swallowing network packets
****************************************************************************/
#ifdef CLIX
@@ -3907,13 +3373,11 @@ static void wait_keyboard(char *buffer)
#else
{
char ch;
- int f_flags;
int readret;
-
- f_flags = fcntl(fileno(stdin), F_GETFL, 0);
- fcntl( fileno(stdin), F_SETFL, f_flags | O_NONBLOCK);
+
+ set_blocking(fileno(stdin), False);
readret = read_data( fileno(stdin), &ch, 1);
- fcntl(fileno(stdin), F_SETFL, f_flags);
+ set_blocking(fileno(stdin), True);
if (readret == -1)
{
if (errno != EAGAIN)
@@ -3946,39 +3410,13 @@ static void wait_keyboard(char *buffer)
/****************************************************************************
-close and open the connection again
-****************************************************************************/
-BOOL 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);
- setup_pkt(outbuf);
-
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,SHORT_TIMEOUT);
-
- close_sockets();
- if (!open_sockets(0)) return(False);
-
- return(send_login(inbuf,outbuf,True,True));
-}
-
-/****************************************************************************
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);
@@ -3988,12 +3426,49 @@ BOOL process(char *base_directory)
bzero(OutBuffer,smb_size);
- if (!send_login(InBuffer,OutBuffer,True,True))
+ if (!cli_send_login(InBuffer,OutBuffer,True,True))
return(False);
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;
@@ -4001,7 +3476,7 @@ BOOL process(char *base_directory)
bzero(OutBuffer,smb_size);
/* display a prompt */
- DEBUG(1,("smb: %s> ", CNV_LANG(cur_dir)));
+ DEBUG(0,("smb: %s> ", CNV_LANG(cur_dir)));
fflush(dbf);
#ifdef CLIX
@@ -4045,23 +3520,18 @@ BOOL process(char *base_directory)
DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
}
- send_logout();
+ cli_send_logout();
return(True);
}
-
/****************************************************************************
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));
-#ifdef KANJI
- DEBUG(0,("[-t termcode] "));
-#endif /* KANJI */
-
DEBUG(0,("\nVersion %s\n",VERSION));
DEBUG(0,("\t-p port listen on the specified port\n"));
DEBUG(0,("\t-d debuglevel set the debuglevel\n"));
@@ -4076,31 +3546,38 @@ 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"));
-#ifdef KANJI
+ DEBUG(0,("\t-c command string execute semicolon separated commands\n"));
DEBUG(0,("\t-t terminal code terminal i/o code {sjis|euc|jis7|jis8|junet|hex}\n"));
-#endif /* KANJI */
DEBUG(0,("\t-T<c|x>IXgbNa command line tar\n"));
DEBUG(0,("\t-D directory start from directory\n"));
DEBUG(0,("\n"));
}
-
-
/****************************************************************************
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;
extern int optind;
pstring query_host;
BOOL message = False;
+ BOOL nt_domain_logon = False;
extern char tar_type;
+ static pstring servicesf = CONFIGFILE;
+ pstring term_code;
+ char *p;
+
+#ifdef KANJI
+ strcpy(term_code, KANJI);
+#else /* KANJI */
+ *term_code = 0;
+#endif /* KANJI */
*query_host = 0;
*base_directory = 0;
@@ -4120,10 +3597,27 @@ int main(int argc,char *argv[])
umask(myumask);
if (getenv("USER"))
+ {
+ strcpy(username,getenv("USER"));
+
+ /* modification to support userid%passwd syntax in the USER var
+ 25.Aug.97, jdblair@uab.edu */
+
+ if ((p=strchr(username,'%')))
{
- strcpy(username,getenv("USER"));
- strupper(username);
+ *p = 0;
+ strcpy(password,p+1);
+ got_pass = True;
+ memset(strchr(getenv("USER"),'%')+1,'X',strlen(password));
}
+ strupper(username);
+ }
+
+ /* modification to support PASSWD environmental var
+ 25.Aug.97, jdblair@uab.edu */
+
+ if (getenv("PASSWD"))
+ strcpy(password,getenv("PASSWD"));
if (*username == 0 && getenv("LOGNAME"))
{
@@ -4141,6 +3635,8 @@ int main(int argc,char *argv[])
{
strcpy(service,argv[1]);
+ /* Convert any '/' characters in the service name to '\' characters */
+ string_replace( service, '/','\\');
argc--;
argv++;
@@ -4170,12 +3666,8 @@ 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 */
+ while ((opt =
+ getopt(argc, argv,"s:B:O:M:S:i:Nn:d:Pp:l:hI:EB:U:L:t:m:W:T:D:c:")) != EOF)
switch (opt)
{
case 'm':
@@ -4184,15 +3676,19 @@ int main(int argc,char *argv[])
case 'O':
strcpy(user_socket_options,optarg);
break;
+ case 'S':
+ strcpy(desthost,optarg);
+ strupper(desthost);
+ nt_domain_logon = True;
+ break;
case 'M':
- name_type = 3;
+ name_type = 0x03; /* messages are sent to NetBIOS name type 0x3 */
strcpy(desthost,optarg);
strupper(desthost);
message = True;
break;
case 'B':
- bcast_ip = *interpret_addr2(optarg);
- got_bcast = True;
+ iface_set_default(NULL,optarg,NULL);
break;
case 'D':
strcpy(base_directory,optarg);
@@ -4212,12 +3708,12 @@ int main(int argc,char *argv[])
break;
case 'U':
{
- char *p;
+ char *lp;
strcpy(username,optarg);
- if ((p=strchr(username,'%')))
+ if ((lp=strchr(username,'%')))
{
- *p = 0;
- strcpy(password,p+1);
+ *lp = 0;
+ strcpy(password,lp+1);
got_pass = True;
memset(strchr(optarg,'%')+1,'X',strlen(password));
}
@@ -4258,19 +3754,20 @@ int main(int argc,char *argv[])
case 'p':
port = atoi(optarg);
break;
+ case 'c':
+ cmdstr = optarg;
+ got_pass = True;
+ break;
case 'h':
usage(pname);
exit(0);
break;
-#ifdef KANJI
+ case 's':
+ strcpy(servicesf, optarg);
+ break;
case 't':
- if (!setup_term_code (optarg)) {
- DEBUG(0, ("%s: unknown terminal code name\n", optarg));
- usage (pname);
- exit (1);
- }
+ strcpy(term_code, optarg);
break;
-#endif /* KANJI */
default:
usage(pname);
exit(1);
@@ -4285,13 +3782,38 @@ int main(int argc,char *argv[])
DEBUG(3,("%s client started (version %s)\n",timestring(),VERSION));
- get_myname(*myname?NULL:myname,&myip);
+ if(!get_myname(myhostname,NULL))
+ {
+ DEBUG(0,("Failed to get my hostname.\n"));
+ }
+
+ if (!lp_load(servicesf,True)) {
+ fprintf(stderr, "Can't load %s - run testparm to debug it\n", servicesf);
+ }
+
+ codepage_initialise(lp_client_code_page());
+
+ if(lp_client_code_page() == KANJI_CODEPAGE)
+ {
+ if (!setup_term_code (term_code))
+ {
+ DEBUG(0, ("%s: unknown terminal code name\n", optarg));
+ usage (pname);
+ exit (1);
+ }
+ }
+
+ if (*workgroup == 0)
+ strcpy(workgroup,lp_workgroup());
+
+ load_interfaces();
+ get_myname((*myname)?NULL:myname,NULL);
strupper(myname);
if (tar_type) {
recurse=True;
- if (open_sockets(port)) {
+ if (cli_open_sockets(port)) {
char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
int ret;
@@ -4300,32 +3822,32 @@ int main(int argc,char *argv[])
return(1);
bzero(OutBuffer,smb_size);
- if (!send_login(InBuffer,OutBuffer,True,True))
+ if (!cli_send_login(InBuffer,OutBuffer,True,True))
return(False);
if (*base_directory) do_cd(base_directory);
ret=process_tar(InBuffer, OutBuffer);
- send_logout();
+ cli_send_logout();
close_sockets();
return(ret);
} else
return(1);
}
- if (*query_host)
+ if (*query_host && !nt_domain_logon)
{
int ret = 0;
sprintf(service,"\\\\%s\\IPC$",query_host);
strupper(service);
connect_as_ipc = True;
- if (open_sockets(port))
+ if (cli_open_sockets(port))
{
#if 0
*username = 0;
#endif
- if (!send_login(NULL,NULL,True,True))
+ if (!cli_send_login(NULL,NULL,True,True))
return(1);
server_info();
@@ -4333,12 +3855,12 @@ int main(int argc,char *argv[])
sleep(1);
browse_host(True);
}
- if (!list_servers()) {
+ if (!list_servers(workgroup)) {
sleep(1);
- list_servers();
+ list_servers(workgroup);
}
- send_logout();
+ cli_send_logout();
close_sockets();
}
@@ -4348,11 +3870,11 @@ int main(int argc,char *argv[])
if (message)
{
int ret = 0;
- if (open_sockets(port))
+ if (cli_open_sockets(port))
{
pstring inbuf,outbuf;
bzero(outbuf,smb_size);
- if (!send_session_request(inbuf,outbuf))
+ if (!cli_send_session_request(inbuf,outbuf))
return(1);
send_message(inbuf,outbuf);
@@ -4363,7 +3885,32 @@ int main(int argc,char *argv[])
return(ret);
}
- if (open_sockets(port))
+#ifdef NTDOMAIN
+
+ if (nt_domain_logon)
+ {
+ int ret = 0;
+ sprintf(service,"\\\\%s\\IPC$",query_host);
+ strupper(service);
+ connect_as_ipc = True;
+
+ DEBUG(5,("NT Domain Logon. Service: %s\n", service));
+
+ if (cli_open_sockets(port))
+ {
+ if (!cli_send_login(NULL,NULL,True,True)) return(1);
+
+ do_nt_login(desthost, myhostname, Client, cnum);
+
+ cli_send_logout();
+ close_sockets();
+ }
+
+ return(ret);
+ }
+#endif
+
+ if (cli_open_sockets(port))
{
if (!process(base_directory))
{
@@ -4379,156 +3926,3 @@ int main(int argc,char *argv[])
}
-/* 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."},
- {"ERRinvgroup",2455,"Invalid workgroup (try the -W option)"},
- {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/clientutil.c b/source/client/clientutil.c
new file mode 100644
index 00000000000..d05be8ae9b8
--- /dev/null
+++ b/source/client/clientutil.c
@@ -0,0 +1,1099 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB client
+ Copyright (C) Andrew Tridgell 1994-1997
+
+ 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="";
+extern 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;
+
+extern 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_COREPLUS)
+ {
+ SCVAL(outbuf,smb_flg,0x8);
+ SSVAL(outbuf,smb_flg2,0x1);
+ }
+}
+
+/****************************************************************************
+call a remote api
+****************************************************************************/
+BOOL cli_call_api(char *pipe_name, int prcnt,int drcnt, int srcnt,
+ int mprcnt,int mdrcnt,
+ int *rprcnt,int *rdrcnt,
+ char *param,char *data, uint16 *setup,
+ 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_name, 0,0,
+ data, param, setup,
+ drcnt, prcnt, srcnt,
+ mdrcnt, mprcnt, 0);
+
+ return (cli_receive_trans_response(inbuf,SMBtrans,
+ rdrcnt,rprcnt,
+ rdata,rparam));
+}
+
+
+/****************************************************************************
+ 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 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);
+}
+
+
+/****************************************************************************
+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); /* 0x20 is the SMB server NetBIOS 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, LONG_CONNECT_TIMEOUT);
+ if (Client == -1)
+ return False;
+
+ DEBUG(3,("Retargeted\n"));
+
+ set_socket_options(Client,user_socket_options);
+
+ /* Try again */
+ return cli_send_session_request(inbuf,outbuf);
+ } /* C. Hoch 9/14/95 End */
+
+
+ if (CVAL(inbuf,0) != 0x82)
+ {
+ int ecode = CVAL(inbuf,4);
+ DEBUG(0,("Session request failed (%d,%d) with myname=%s destname=%s\n",
+ CVAL(inbuf,0),ecode,myname,desthost));
+ switch (ecode)
+ {
+ case 0x80:
+ DEBUG(0,("Not listening on called name\n"));
+ DEBUG(0,("Try to connect to another name (instead of %s)\n",desthost));
+ DEBUG(0,("You may find the -I option useful for this\n"));
+ break;
+ case 0x81:
+ DEBUG(0,("Not listening for calling name\n"));
+ DEBUG(0,("Try to connect as another name (instead of %s)\n",myname));
+ DEBUG(0,("You may find the -n option useful for this\n"));
+ break;
+ case 0x82:
+ DEBUG(0,("Called name not present\n"));
+ DEBUG(0,("Try to connect to another name (instead of %s)\n",desthost));
+ DEBUG(0,("You may find the -I option useful for this\n"));
+ break;
+ case 0x83:
+ DEBUG(0,("Called name present, but insufficient resources\n"));
+ DEBUG(0,("Perhaps you should try again later?\n"));
+ break;
+ default:
+ DEBUG(0,("Unspecified error 0x%X\n",ecode));
+ DEBUG(0,("Your server software is being unfriendly\n"));
+ break;
+ }
+ return(False);
+ }
+ return(True);
+}
+
+static struct {
+ int prot;
+ char *name;
+} prots[] = {
+ {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
+ {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
+ {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
+ {PROTOCOL_LANMAN1,"LANMAN1.0"},
+ {PROTOCOL_LANMAN2,"LM1.2X002"},
+ {PROTOCOL_LANMAN2,"Samba"},
+ {PROTOCOL_NT1,"NT LM 0.12"},
+ {PROTOCOL_NT1,"NT LANMAN 1.0"},
+ {-1,NULL}
+};
+
+
+/****************************************************************************
+send a login command
+****************************************************************************/
+BOOL cli_send_login(char *inbuf,char *outbuf,BOOL start_session,BOOL use_setup)
+{
+ BOOL was_null = (!inbuf && !outbuf);
+ int sesskey=0;
+ time_t servertime = 0;
+ extern int serverzone;
+ int sec_mode=0;
+ int crypt_len;
+ int max_vcs=0;
+ char *pass = NULL;
+ pstring dev;
+ char *p;
+ int numprots;
+ int tries=0;
+
+ if (was_null)
+ {
+ inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+ outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+ }
+
+#if AJT
+ if (strstr(service,"IPC$")) connect_as_ipc = True;
+#endif
+
+ strcpy(dev,"A:");
+ if (connect_as_printer)
+ strcpy(dev,"LPT1:");
+ if (connect_as_ipc)
+ strcpy(dev,"IPC");
+
+
+ if (start_session && !cli_send_session_request(inbuf,outbuf))
+ {
+ if (was_null)
+ {
+ free(inbuf);
+ free(outbuf);
+ }
+ return(False);
+ }
+
+ bzero(outbuf,smb_size);
+
+ /* setup the protocol strings */
+ {
+ int plength;
+
+ for (plength=0,numprots=0;
+ prots[numprots].name && prots[numprots].prot<=max_protocol;
+ numprots++)
+ plength += strlen(prots[numprots].name)+2;
+
+ set_message(outbuf,0,plength,True);
+
+ p = smb_buf(outbuf);
+ for (numprots=0;
+ prots[numprots].name && prots[numprots].prot<=max_protocol;
+ numprots++)
+ {
+ *p++ = 2;
+ strcpy(p,prots[numprots].name);
+ p += strlen(p) + 1;
+ }
+ }
+
+ CVAL(outbuf,smb_com) = SMBnegprot;
+ cli_setup_pkt(outbuf);
+
+ CVAL(smb_buf(outbuf),0) = 2;
+
+ send_smb(Client,outbuf);
+ receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+
+ show_msg(inbuf);
+
+ if (CVAL(inbuf,smb_rcls) != 0 || ((int)SVAL(inbuf,smb_vwv0) >= numprots))
+ {
+ DEBUG(0,("SMBnegprot failed. myname=%s destname=%s - %s \n",
+ myname,desthost,smb_errstr(inbuf)));
+ if (was_null)
+ {
+ free(inbuf);
+ free(outbuf);
+ }
+ return(False);
+ }
+
+ Protocol = prots[SVAL(inbuf,smb_vwv0)].prot;
+
+
+ if (Protocol < PROTOCOL_NT1) {
+ sec_mode = SVAL(inbuf,smb_vwv1);
+ max_xmit = SVAL(inbuf,smb_vwv2);
+ sesskey = IVAL(inbuf,smb_vwv6);
+ serverzone = SVALS(inbuf,smb_vwv10)*60;
+ /* this time is converted to GMT by make_unix_date */
+ servertime = make_unix_date(inbuf+smb_vwv8);
+ if (Protocol >= PROTOCOL_COREPLUS) {
+ readbraw_supported = ((SVAL(inbuf,smb_vwv5) & 0x1) != 0);
+ writebraw_supported = ((SVAL(inbuf,smb_vwv5) & 0x2) != 0);
+ }
+ crypt_len = smb_buflen(inbuf);
+ memcpy(cryptkey,smb_buf(inbuf),8);
+ DEBUG(3,("max mux %d\n",SVAL(inbuf,smb_vwv3)));
+ max_vcs = SVAL(inbuf,smb_vwv4);
+ DEBUG(3,("max vcs %d\n",max_vcs));
+ DEBUG(3,("max blk %d\n",SVAL(inbuf,smb_vwv5)));
+ } else {
+ /* NT protocol */
+ sec_mode = CVAL(inbuf,smb_vwv1);
+ max_xmit = IVAL(inbuf,smb_vwv3+1);
+ sesskey = IVAL(inbuf,smb_vwv7+1);
+ serverzone = SVALS(inbuf,smb_vwv15+1)*60;
+ /* this time arrives in real GMT */
+ servertime = interpret_long_date(inbuf+smb_vwv11+1);
+ crypt_len = CVAL(inbuf,smb_vwv16+1);
+ memcpy(cryptkey,smb_buf(inbuf),8);
+ if (IVAL(inbuf,smb_vwv9+1) & 1)
+ readbraw_supported = writebraw_supported = True;
+ DEBUG(3,("max mux %d\n",SVAL(inbuf,smb_vwv1+1)));
+ max_vcs = SVAL(inbuf,smb_vwv2+1);
+ DEBUG(3,("max vcs %d\n",max_vcs));
+ DEBUG(3,("max raw %d\n",IVAL(inbuf,smb_vwv5+1)));
+ DEBUG(3,("capabilities 0x%x\n",IVAL(inbuf,smb_vwv9+1)));
+ }
+
+ DEBUG(3,("Sec mode %d\n",SVAL(inbuf,smb_vwv1)));
+ DEBUG(3,("max xmt %d\n",max_xmit));
+ DEBUG(3,("Got %d byte crypt key\n",crypt_len));
+ DEBUG(3,("Chose protocol [%s]\n",prots[SVAL(inbuf,smb_vwv0)].name));
+
+ doencrypt = ((sec_mode & 2) != 0);
+
+ if (servertime) {
+ static BOOL done_time = False;
+ if (!done_time) {
+ DEBUG(1,("Server time is %sTimezone is UTC%+02.1f\n",
+ asctime(LocalTime(&servertime)),
+ -(double)(serverzone/3600.0)));
+ done_time = True;
+ }
+ }
+
+ get_pass:
+
+ if (got_pass)
+ pass = password;
+ else
+ pass = (char *)getpass("Password: ");
+
+ /* use a blank username for the 2nd try with a blank password */
+ if (tries++ && !*pass)
+ *username = 0;
+
+ if (Protocol >= PROTOCOL_LANMAN1 && use_setup)
+ {
+ fstring pword;
+ int passlen = strlen(pass)+1;
+ strcpy(pword,pass);
+
+ if (doencrypt && *pass) {
+ DEBUG(3,("Using encrypted passwords\n"));
+ passlen = 24;
+ SMBencrypt((uchar *)pass,(uchar *)cryptkey,(uchar *)pword);
+ }
+
+ /* if in share level security then don't send a password now */
+ if (!(sec_mode & 1)) {strcpy(pword, "");passlen=1;}
+
+ /* send a session setup command */
+ bzero(outbuf,smb_size);
+
+ if (Protocol < PROTOCOL_NT1) {
+ set_message(outbuf,10,1 + strlen(username) + passlen,True);
+ CVAL(outbuf,smb_com) = SMBsesssetupX;
+ cli_setup_pkt(outbuf);
+
+ CVAL(outbuf,smb_vwv0) = 0xFF;
+ SSVAL(outbuf,smb_vwv2,max_xmit);
+ SSVAL(outbuf,smb_vwv3,2);
+ SSVAL(outbuf,smb_vwv4,max_vcs-1);
+ SIVAL(outbuf,smb_vwv5,sesskey);
+ SSVAL(outbuf,smb_vwv7,passlen);
+ p = smb_buf(outbuf);
+ memcpy(p,pword,passlen);
+ p += passlen;
+ strcpy(p,username);
+ } else {
+ if (!doencrypt) passlen--;
+ /* for Win95 */
+ set_message(outbuf,13,0,True);
+ CVAL(outbuf,smb_com) = SMBsesssetupX;
+ cli_setup_pkt(outbuf);
+
+ CVAL(outbuf,smb_vwv0) = 0xFF;
+ SSVAL(outbuf,smb_vwv2,BUFFER_SIZE);
+ SSVAL(outbuf,smb_vwv3,2);
+ SSVAL(outbuf,smb_vwv4,getpid());
+ SIVAL(outbuf,smb_vwv5,sesskey);
+ SSVAL(outbuf,smb_vwv7,passlen);
+ SSVAL(outbuf,smb_vwv8,0);
+ p = smb_buf(outbuf);
+ memcpy(p,pword,passlen); p += SVAL(outbuf,smb_vwv7);
+ strcpy(p,username);p = skip_string(p,1);
+ strcpy(p,workgroup);p = skip_string(p,1);
+ strcpy(p,"Unix");p = skip_string(p,1);
+ strcpy(p,"Samba");p = skip_string(p,1);
+ set_message(outbuf,13,PTR_DIFF(p,smb_buf(outbuf)),False);
+ }
+
+ send_smb(Client,outbuf);
+ receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+
+ show_msg(inbuf);
+
+ if (CVAL(inbuf,smb_rcls) != 0)
+ {
+ if (! *pass &&
+ ((CVAL(inbuf,smb_rcls) == ERRDOS &&
+ SVAL(inbuf,smb_err) == ERRnoaccess) ||
+ (CVAL(inbuf,smb_rcls) == ERRSRV &&
+ SVAL(inbuf,smb_err) == ERRbadpw)))
+ {
+ got_pass = False;
+ DEBUG(3,("resending login\n"));
+ goto get_pass;
+ }
+
+ DEBUG(0,("Session setup failed for username=%s myname=%s destname=%s %s\n",
+ username,myname,desthost,smb_errstr(inbuf)));
+ DEBUG(0,("You might find the -U, -W or -n options useful\n"));
+ DEBUG(0,("Sometimes you have to use `-n USERNAME' (particularly with OS/2)\n"));
+ DEBUG(0,("Some servers also insist on uppercase-only passwords\n"));
+ if (was_null)
+ {
+ free(inbuf);
+ free(outbuf);
+ }
+ return(False);
+ }
+
+ if (Protocol >= PROTOCOL_NT1) {
+ char *domain,*os,*lanman;
+ p = smb_buf(inbuf);
+ os = p;
+ lanman = skip_string(os,1);
+ domain = skip_string(lanman,1);
+ if (*domain || *os || *lanman)
+ DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",domain,os,lanman));
+ }
+
+ /* use the returned uid from now on */
+ if (SVAL(inbuf,smb_uid) != uid)
+ DEBUG(3,("Server gave us a UID of %d. We gave %d\n",
+ SVAL(inbuf,smb_uid),uid));
+ uid = SVAL(inbuf,smb_uid);
+ }
+
+ if (sec_mode & 1) {
+ if (SVAL(inbuf, smb_vwv2) & 1)
+ DEBUG(1,("connected as guest "));
+ DEBUG(1,("security=user\n"));
+ } else {
+ DEBUG(1,("security=share\n"));
+ }
+
+ /* 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);
+
+ if (doencrypt && *pass) {
+ passlen=24;
+ SMBencrypt((uchar *)pass,(uchar *)cryptkey,(uchar *)pword);
+ }
+
+ /* if in user level security then don't send a password now */
+ if ((sec_mode & 1)) {
+ strcpy(pword, ""); passlen=1;
+ }
+
+ if (Protocol <= PROTOCOL_COREPLUS) {
+ set_message(outbuf,0,6 + strlen(service) + passlen + strlen(dev),True);
+ CVAL(outbuf,smb_com) = SMBtcon;
+ cli_setup_pkt(outbuf);
+
+ 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;
+ 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);
+ }
+
+
+ if (Protocol <= PROTOCOL_COREPLUS) {
+ 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);
+ }
+
+ DEBUG(3,("Connected with cnum=%d max_xmit=%d\n",cnum,max_xmit));
+
+ if (was_null)
+ {
+ free(inbuf);
+ free(outbuf);
+ }
+
+ return True;
+}
+
+
+/****************************************************************************
+send a logout command
+****************************************************************************/
+void cli_send_logout(void )
+{
+ pstring inbuf,outbuf;
+
+ DEBUG(5,("cli_send_logout\n"));
+
+ 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);
+}
+
+
+/****************************************************************************
+open the client sockets
+****************************************************************************/
+BOOL cli_open_sockets(int port )
+{
+ static int last_port;
+ char *host;
+ pstring service2;
+ extern int Client;
+ BOOL failed = True;
+
+ if (port == 0) port=last_port;
+ last_port=port;
+
+ strupper(service);
+
+ if (*desthost)
+ {
+ host = desthost;
+ }
+ else
+ {
+ strcpy(service2,service);
+ host = strtok(service2,"\\/");
+ if (!host) {
+ DEBUG(0,("Badly formed host name\n"));
+ return(False);
+ }
+ strcpy(desthost,host);
+ }
+
+ if (!(*myname)) {
+ get_myname(myname,NULL);
+ }
+ strupper(myname);
+
+ DEBUG(3,("Opening sockets\n"));
+
+ if (!have_ip)
+ {
+ struct hostent *hp;
+
+ if ((hp = Get_Hostbyname(host)))
+ {
+ putip((char *)&dest_ip,(char *)hp->h_addr);
+ failed = False;
+ }
+ else
+ {
+#ifdef USENMB
+ /* Try and resolve the name with the netbios server */
+ int bcast;
+
+ if ((bcast = open_socket_in(SOCK_DGRAM, 0, 3,
+ interpret_addr(lp_socket_address()))) != -1) {
+ set_socket_options(bcast, "SO_BROADCAST");
+
+ if (name_query(bcast, host, name_type, True, True, *iface_bcast(dest_ip),
+ &dest_ip,0)) {
+ failed = False;
+ }
+ close (bcast);
+ }
+#endif
+ if (failed) {
+ DEBUG(0,("Get_Hostbyname: Unknown host %s.\n",host));
+ return False;
+ }
+ }
+ }
+
+ Client = open_socket_out(SOCK_STREAM, &dest_ip, port, LONG_CONNECT_TIMEOUT);
+ if (Client == -1)
+ return False;
+
+ DEBUG(3,("Connected\n"));
+
+ set_socket_options(Client,user_socket_options);
+
+ return True;
+}
+
+/****************************************************************************
+close and open the connection again
+****************************************************************************/
+BOOL cli_reopen_connection(char *inbuf,char *outbuf)
+{
+ static int open_count=0;
+
+ open_count++;
+
+ if (open_count>5) return(False);
+
+ DEBUG(1,("Trying to re-open connection\n"));
+
+ set_message(outbuf,0,0,True);
+ SCVAL(outbuf,smb_com,SMBtdis);
+ SSVAL(outbuf,smb_tid,cnum);
+ cli_setup_pkt(outbuf);
+
+ send_smb(Client,outbuf);
+ receive_smb(Client,inbuf,SHORT_TIMEOUT);
+
+ close_sockets();
+ if (!cli_open_sockets(0)) return(False);
+
+ return(cli_send_login(inbuf,outbuf,True,True));
+}
+
+/* error code stuff - put together by Merik Karman
+ merik@blackadder.dsh.oz.au */
+
+typedef struct
+{
+ char *name;
+ int code;
+ char *message;
+} err_code_struct;
+
+/* Dos Error Messages */
+err_code_struct dos_msgs[] = {
+ {"ERRbadfunc",1,"Invalid function."},
+ {"ERRbadfile",2,"File not found."},
+ {"ERRbadpath",3,"Directory invalid."},
+ {"ERRnofids",4,"No file descriptors available"},
+ {"ERRnoaccess",5,"Access denied."},
+ {"ERRbadfid",6,"Invalid file handle."},
+ {"ERRbadmcb",7,"Memory control blocks destroyed."},
+ {"ERRnomem",8,"Insufficient server memory to perform the requested function."},
+ {"ERRbadmem",9,"Invalid memory block address."},
+ {"ERRbadenv",10,"Invalid environment."},
+ {"ERRbadformat",11,"Invalid format."},
+ {"ERRbadaccess",12,"Invalid open mode."},
+ {"ERRbaddata",13,"Invalid data."},
+ {"ERR",14,"reserved."},
+ {"ERRbaddrive",15,"Invalid drive specified."},
+ {"ERRremcd",16,"A Delete Directory request attempted to remove the server's current directory."},
+ {"ERRdiffdevice",17,"Not same device."},
+ {"ERRnofiles",18,"A File Search command can find no more files matching the specified criteria."},
+ {"ERRbadshare",32,"The sharing mode specified for an Open conflicts with existing FIDs on the file."},
+ {"ERRlock",33,"A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."},
+ {"ERRnosuchshare", 67, "You specified an invalid share name"},
+ {"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."},
+ {"ERRinvgroup",2455,"Invalid workgroup (try the -W option)"},
+ {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,"An 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..1e7c45691b2 100644
--- a/source/client/clitar.c
+++ b/source/client/clitar.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Tar Extensions
- Copyright (C) Ricky Poulten 1995
+ Copyright (C) Ricky Poulten 1995-1997
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
@@ -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"
@@ -47,7 +41,7 @@ static int attribute = aDIR | aSYSTEM | aHIDDEN;
#endif
static char *tarbuf;
-static int tp, ntarf, tbufsiz;
+static int tp, ntarf, tbufsiz, ttarf;
/* Incremental mode */
BOOL tar_inc=False;
/* Reset archive bit */
@@ -81,10 +75,7 @@ static void dozerobuf();
static void dotareof();
static void initarbuf();
static int do_setrattr();
-void cmd_tar();
-int process_tar();
-char **toktocliplist();
-int clipfind();
+
/* restore functions */
static long readtarheader();
static long unoct();
@@ -99,7 +90,7 @@ static void unfixtarname();
Write a tar header to buffer
****************************************************************************/
static void writetarheader(int f, char *aname, int size, time_t mtime,
- char *amode)
+ char *amode)
{
union hblock hb;
int i, chk, l;
@@ -108,10 +99,21 @@ static void writetarheader(int f, char *aname, int size, time_t mtime,
memset(hb.dummy, 0, sizeof(hb.dummy));
l=strlen(aname);
- if (l >= NAMSIZ)
- {
- DEBUG(0, ("tar file %s name length exceeds NAMSIZ\n", aname));
- }
+ if (l >= NAMSIZ) {
+ /* write a GNU tar style long header */
+ char *b;
+ b = (char *)malloc(l+TBLOCK+100);
+ if (!b) {
+ DEBUG(0,("out of memory\n"));
+ exit(1);
+ }
+ writetarheader(f, "/./@LongLink", l+1, 0, " 0 \0");
+ memset(b, 0, l+TBLOCK+100);
+ fixtarname(b, aname, l+1);
+ i = strlen(b)+1;
+ dotarbuf(f, b, TBLOCK*((i+(TBLOCK-1)/TBLOCK)));
+ free(b);
+ }
/* use l + 1 to do the null too */
fixtarname(hb.dbuf.name, aname, (l >= NAMSIZ) ? NAMSIZ : l + 1);
@@ -128,8 +130,13 @@ static void writetarheader(int f, char *aname, int size, time_t mtime,
oct_it((long) size, 13, hb.dbuf.size);
oct_it((long) mtime, 13, hb.dbuf.mtime);
memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
- hb.dbuf.linkflag='0';
memset(hb.dbuf.linkname, 0, NAMSIZ);
+ if (strcmp("/./@LongLink", aname) == 0) {
+ /* we're doing a GNU tar long filename */
+ hb.dbuf.linkflag='L';
+ } else {
+ hb.dbuf.linkflag='0';
+ }
for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;) chk+=(0xFF & *jp++);
@@ -280,8 +287,8 @@ static void initarbuf()
tbufsiz=blocksize*TBLOCK;
tarbuf=malloc(tbufsiz);
- /* reset tar buffer pointer and tar file counter */
- tp=0; ntarf=0;
+ /* reset tar buffer pointer and tar file counter and total dumped */
+ tp=0; ntarf=0; ttarf=0;
}
/****************************************************************************
@@ -315,27 +322,35 @@ static void fixtarname(char *tptr, char *fp, int l)
* to lovely unix /'s :-} */
*tptr++='.';
-#ifdef KANJI
- while (l > 0) {
- if (is_shift_jis (*fp)) {
- *tptr++ = *fp++;
- *tptr++ = *fp++;
- l -= 2;
- } else if (is_kana (*fp)) {
- *tptr++ = *fp++;
- l--;
- } else if (*fp == '\\') {
- *tptr++ = '/';
+ if(lp_client_code_page() == KANJI_CODEPAGE)
+ {
+ while (l > 0) {
+ if (is_shift_jis (*fp)) {
+ *tptr++ = *fp++;
+ *tptr++ = *fp++;
+ l -= 2;
+ } else if (is_kana (*fp)) {
+ *tptr++ = *fp++;
+ l--;
+ } else if (*fp == '\\') {
+ *tptr++ = '/';
+ fp++;
+ l--;
+ } else {
+ *tptr++ = *fp++;
+ l--;
+ }
+ }
+ }
+ else
+ {
+ while (l--)
+ {
+ *tptr=(*fp == '\\') ? '/' : *fp;
+ tptr++;
fp++;
- l--;
- } else {
- *tptr++ = *fp++;
- l--;
}
}
-#else
- while (l--) { *tptr=(*fp == '\\') ? '/' : *fp; tptr++; fp++; }
-#endif
}
/****************************************************************************
@@ -381,10 +396,14 @@ static long unoct(char *p, int ndgs)
}
/****************************************************************************
-Compare two strings in a slash insensitive way
+Compare two strings in a slash insensitive way, allowing s1 to match s2
+if s1 is an "initial" string (up to directory marker). Thus, if s2 is
+a file in any subdirectory of s1, declare a match.
***************************************************************************/
-int strslashcmp(const char *s1, const char *s2)
+static int strslashcmp(char *s1, char *s2)
{
+ char *s1_0=s1;
+
while(*s1 && *s2 &&
(*s1 == *s2
|| tolower(*s1) == tolower(*s2)
@@ -393,6 +412,17 @@ int strslashcmp(const char *s1, const char *s2)
s1++; s2++;
}
+ /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
+ string of s2.
+ */
+ if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\')) return 0;
+
+ /* ignore trailing slash on s1 */
+ if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1)) return 0;
+
+ /* check for s1 is an "initial" string of s2 */
+ if (*s2 == '/' || *s2 == '\\') return 0;
+
return *s1-*s2;
}
@@ -431,7 +461,7 @@ static int do_setrattr(char *fname, int attr, int setit)
set_message(outbuf,0,2 + strlen(fname),True);
CVAL(outbuf,smb_com) = SMBgetatr;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
p = smb_buf(outbuf);
*p++ = 4;
@@ -467,7 +497,7 @@ static int do_setrattr(char *fname, int attr, int setit)
set_message(outbuf,8,4 + strlen(fname),True);
CVAL(outbuf,smb_com) = SMBsetatr;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,attr);
@@ -507,7 +537,7 @@ static BOOL smbcreat(file_info finfo, int *fnum, char *inbuf, char *outbuf)
set_message(outbuf,3,2 + strlen(finfo.name),True);
CVAL(outbuf,smb_com) = SMBcreate;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,finfo.mode);
put_dos_date3(outbuf,smb_vwv1,finfo.mtime);
@@ -546,7 +576,7 @@ static BOOL smbwrite(int fnum, int n, int low, int high, int left,
set_message(outbuf,5,n + 3, False);
CVAL(outbuf,smb_com) = SMBwrite;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,fnum);
SSVAL(outbuf,smb_vwv1,n);
@@ -585,13 +615,13 @@ static BOOL smbshut(file_info finfo, int fnum, char *inbuf, char *outbuf)
set_message(outbuf,3,0,True);
CVAL(outbuf,smb_com) = SMBclose;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,fnum);
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);
@@ -618,7 +648,7 @@ static BOOL smbchkpath(char *fname, char *inbuf, char *outbuf)
set_message(outbuf,0,4 + strlen(fname),True);
CVAL(outbuf,smb_com) = SMBchkpth;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
p = smb_buf(outbuf);
*p++ = 4;
@@ -645,7 +675,7 @@ static BOOL smbmkdir(char *fname, char *inbuf, char *outbuf)
CVAL(outbuf,smb_com) = SMBmkdir;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
p = smb_buf(outbuf);
*p++ = 4;
@@ -711,6 +741,22 @@ static BOOL ensurepath(char *fname, char *inbuf, char *outbuf)
return True;
}
+int padit(char *buf, int bufsize, int padsize)
+{
+ int berr= 0;
+ int bytestowrite;
+
+ DEBUG(0, ("Padding with %d zeros\n", padsize));
+ memset(buf, 0, bufsize);
+ while( !berr && padsize > 0 ) {
+ bytestowrite= MIN(bufsize, padsize);
+ berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
+ padsize -= bytestowrite;
+ }
+
+ return berr;
+}
+
/*
* smbclient functions
*/
@@ -752,7 +798,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
CVAL(outbuf,smb_com) = SMBopenX;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,0xFF);
SSVAL(outbuf,smb_vwv2,1);
@@ -788,7 +834,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
{
if (CVAL(inbuf,smb_rcls) == ERRSRV &&
SVAL(inbuf,smb_err) == ERRnoresource &&
- reopen_connection(inbuf,outbuf))
+ cli_reopen_connection(inbuf,outbuf))
{
do_atar(rname,lname,finfo1);
free(inbuf);free(outbuf);
@@ -832,7 +878,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
datalen = 0;
}
- DEBUG(2,("getting file %s of size %d bytes as a tar file %s",
+ DEBUG(1,("getting file %s of size %d bytes as a tar file %s",
finfo.name,
finfo.size,
lname));
@@ -884,7 +930,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
set_message(outbuf,10,0,True);
CVAL(outbuf,smb_com) = SMBreadX;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
if (close_done)
{
@@ -950,7 +996,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
set_message(outbuf,8,0,True);
CVAL(outbuf,smb_com) = SMBreadbraw;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,fnum);
SIVAL(outbuf,smb_vwv1,nread);
SSVAL(outbuf,smb_vwv3,MIN(finfo.size-nread,readbraw_size));
@@ -1002,7 +1048,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
set_message(outbuf,5,0,True);
CVAL(outbuf,smb_com) = SMBread;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,fnum);
SSVAL(outbuf,smb_vwv1,MIN(max_xmit-200,finfo.size - nread));
@@ -1028,7 +1074,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
* write out in 512 byte intervals */
if (dotarbuf(tarhandle,dataptr,datalen) != datalen)
{
- DEBUG(0,("Error writing local file\n"));
+ DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
break;
}
@@ -1042,11 +1088,20 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
dataptr=NULL;
datalen=0;
}
-
+
+ /* pad tar file with zero's if we couldn't get entire file */
+ if (nread < finfo.size)
+ {
+ DEBUG(0, ("Didn't get entire file. size=%d, nread=%d\n", finfo.size, nread));
+ if (padit(inbuf, BUFFER_SIZE, finfo.size - nread))
+ DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
+ }
+
/* round tar file to nearest block */
if (finfo.size % TBLOCK)
dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
+ ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
ntarf++;
}
@@ -1056,7 +1111,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
set_message(outbuf,3,0,True);
CVAL(outbuf,smb_com) = SMBclose;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,fnum);
SIVALS(outbuf,smb_vwv1,-1);
@@ -1088,7 +1143,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
get_total_size += finfo.size;
/* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
- DEBUG(2,("(%g kb/s) (average %g kb/s)\n",
+ DEBUG(1,("(%g kb/s) (average %g kb/s)\n",
finfo.size / MAX(0.001, (1.024*this_time)),
get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
}
@@ -1113,11 +1168,6 @@ static void do_tar(file_info *finfo)
strcpy(exclaim, cur_dir);
*(exclaim+strlen(exclaim)-1)='\0';
- if (clipfind(cliplist, clipn, exclaim)) {
- DEBUG(3,("Skipping directory %s\n", exclaim));
- return;
- }
-
strcat(exclaim, "\\");
strcat(exclaim, finfo->name);
@@ -1177,27 +1227,35 @@ static void unfixtarname(char *tptr, char *fp, int l)
if (*fp == '.') fp++;
if (*fp == '\\' || *fp == '/') fp++;
-#ifdef KANJI
- while (l > 0) {
- if (is_shift_jis (*fp)) {
- *tptr++ = *fp++;
- *tptr++ = *fp++;
- l -= 2;
- } else if (is_kana (*fp)) {
- *tptr++ = *fp++;
- l--;
- } else if (*fp == '/') {
- *tptr++ = '\\';
+ if(lp_client_code_page() == KANJI_CODEPAGE)
+ {
+ while (l > 0) {
+ if (is_shift_jis (*fp)) {
+ *tptr++ = *fp++;
+ *tptr++ = *fp++;
+ l -= 2;
+ } else if (is_kana (*fp)) {
+ *tptr++ = *fp++;
+ l--;
+ } else if (*fp == '/') {
+ *tptr++ = '\\';
+ fp++;
+ l--;
+ } else {
+ *tptr++ = *fp++;
+ l--;
+ }
+ }
+ }
+ else
+ {
+ while (l--)
+ {
+ *tptr=(*fp == '/') ? '\\' : *fp;
+ tptr++;
fp++;
- l--;
- } else {
- *tptr++ = *fp++;
- l--;
}
}
-#else
- while (l--) { *tptr=(*fp == '/') ? '\\' : *fp; tptr++; fp++; }
-#endif
}
static void do_tarput()
@@ -1415,7 +1473,7 @@ void cmd_block(void)
}
blocksize=block;
- DEBUG(2,("blocksize is now %d\n", blocksize));
+ DEBUG(1,("blocksize is now %d\n", blocksize));
}
/****************************************************************************
@@ -1492,7 +1550,7 @@ void cmd_setmode(void)
return;
}
-DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
+ DEBUG(1, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
(void) do_setrattr(fname, attra[ATTRSET], ATTRSET);
(void) do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
}
@@ -1580,6 +1638,7 @@ int process_tar(char *inbuf, char *outbuf)
free(tarbuf);
DEBUG(0, ("tar: dumped %d tar files\n", ntarf));
+ DEBUG(0, ("Total bytes written: %d\n", ttarf));
break;
}
@@ -1655,7 +1714,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"));
@@ -1690,21 +1749,20 @@ int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
return 0;
}
+ tar_excl=tar_clipfl!='X';
+ if (Optind+1<argc) {
+ cliplist=argv+Optind+1;
+ clipn=argc-Optind-1;
+ }
if (Optind>=argc || !strcmp(argv[Optind], "-")) {
/* Sets tar handle to either 0 or 1, as appropriate */
tarhandle=(tar_type=='c');
} else {
- tar_excl=tar_clipfl!='X';
-
- if (Optind+1<argc) {
- cliplist=argv+Optind+1;
- clipn=argc-Optind-1;
- }
-
if ((tar_type=='x' && (tarhandle = open(argv[Optind], O_RDONLY)) == -1)
|| (tar_type=='c' && (tarhandle=creat(argv[Optind], 0644)) < 0))
{
- DEBUG(0,("Error opening local file %s\n",argv[Optind]));
+ DEBUG(0,("Error opening local file %s - %s\n",
+ argv[Optind], strerror(errno)));
return(0);
}
}
diff --git a/source/client/ntclient.c b/source/client/ntclient.c
new file mode 100644
index 00000000000..89775cd3aac
--- /dev/null
+++ b/source/client/ntclient.c
@@ -0,0 +1,323 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NT Domain Authentication SMB / MSRPC client
+ Copyright (C) Andrew Tridgell 1994-1997
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+
+ 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"
+
+extern int DEBUGLEVEL;
+extern pstring username;
+extern pstring workgroup;
+
+#define CLIENT_TIMEOUT (30*1000)
+
+#ifdef NTDOMAIN
+
+
+/****************************************************************************
+experimental nt login.
+****************************************************************************/
+BOOL do_nt_login(char *desthost, char *myhostname,
+ int Client, int cnum)
+{
+ DOM_CHAL clnt_chal;
+ DOM_CHAL srv_chal;
+
+ DOM_CRED clnt_cred;
+
+ DOM_CHAL auth2_srv_chal;
+
+ DOM_CRED sam_logon_clnt_cred;
+ DOM_CRED sam_logon_rtn_cred;
+ DOM_CRED sam_logon_srv_cred;
+
+ DOM_CRED sam_logoff_clnt_cred;
+ DOM_CRED sam_logoff_rtn_cred;
+ DOM_CRED sam_logoff_srv_cred;
+
+ DOM_ID_INFO_1 id1;
+ LSA_USER_INFO user_info1;
+ LSA_POL_HND pol;
+ int i;
+
+ UTIME zerotime;
+
+ uint32 sess_key[2];
+ char nt_owf_mach_pwd[16];
+ fstring mach_acct;
+ fstring mach_pwd;
+ fstring server_name;
+
+ RPC_IFACE abstract;
+ RPC_IFACE transfer;
+
+ static char abs_data[16];
+ static char trn_data[16];
+
+ /* received from LSA Query Info Policy, level 5 */
+ fstring level5_domain_name;
+ pstring level5_domain_sid;
+
+ /* received from LSA Query Info Policy, level 3 */
+ fstring level3_domain_name;
+ pstring level3_domain_sid;
+
+ uint16 fnum;
+ uint32 call_id = 0;
+ char *inbuf,*outbuf;
+
+ zerotime.time = 0;
+
+ inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+ outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+
+ if (!inbuf || !outbuf)
+ {
+ DEBUG(0,("out of memory\n"));
+ return False;
+ }
+
+ /******************* open the \PIPE\lsarpc file *****************/
+
+ if ((fnum = open_rpc_pipe(inbuf, outbuf, PIPE_LSARPC, Client, cnum)) == 0xffff)
+ {
+ free(inbuf); free(outbuf);
+ return False;
+ }
+
+ /******************* bind request on \PIPE\lsarpc *****************/
+
+ /* create and send a MSRPC command with api LSA_OPENPOLICY */
+
+ DEBUG(4,("LSA RPC Bind[%d]\n", fnum));
+
+ for (i = 0; i < sizeof(trn_data); i++)
+ {
+ trn_data[i] = 2 * i;
+ }
+
+ for (i = 0; i < sizeof(abs_data); i++)
+ {
+ abs_data[i] = i;
+ }
+
+ /* create interface UUIDs. */
+ make_rpc_iface(&abstract, abs_data, 0x0);
+ make_rpc_iface(&transfer, trn_data, 0x2);
+
+ if (!bind_rpc_pipe(PIPE_LSARPC, fnum, ++call_id, &abstract, &transfer))
+ {
+ free(inbuf); free(outbuf);
+ return False;
+ }
+
+ /******************* Open Policy ********************/
+
+ fstrcpy(server_name, ("\\\\"));
+ fstrcpy(&server_name[2], myhostname);
+
+ /* send an open policy request; receive a policy handle */
+ if (!do_lsa_open_policy(fnum, ++call_id, server_name, &pol))
+ {
+ cli_smb_close(inbuf, outbuf, Client, cnum, fnum);
+ free(inbuf); free(outbuf);
+ return False;
+ }
+
+ /**************** Query Info Policy, level 3 ********************/
+
+ /* send a query info policy at level 3; receive an info policy */
+ if (!do_lsa_query_info_pol(fnum, ++call_id, &pol, 0x3,
+ level3_domain_name, level3_domain_sid))
+ {
+ cli_smb_close(inbuf, outbuf, Client, cnum, fnum);
+ free(inbuf); free(outbuf);
+ return False;
+ }
+
+ /**************** Query Info Policy, level 5 ********************/
+
+ /* send a query info policy at level 5; receive an info policy */
+ if (!do_lsa_query_info_pol(fnum, ++call_id, &pol, 0x5,
+ level5_domain_name, level5_domain_sid))
+ {
+ cli_smb_close(inbuf, outbuf, Client, cnum, fnum);
+ free(inbuf); free(outbuf);
+ return False;
+ }
+
+ /******************* Open Policy ********************/
+
+ /* send a close policy request; receive a close pol response */
+ if (!do_lsa_close(fnum, ++call_id, &pol))
+ {
+ cli_smb_close(inbuf, outbuf, Client, cnum, fnum);
+ free(inbuf); free(outbuf);
+ return False;
+ }
+
+ /******************* close the \PIPE\lsarpc file *******************/
+
+ cli_smb_close(inbuf, outbuf, Client, cnum, fnum);
+
+
+
+ /******************* open the \PIPE\NETLOGON file *****************/
+
+ if ((fnum = open_rpc_pipe(inbuf, outbuf, PIPE_NETLOGON, Client, cnum)) == 0xffff)
+ {
+ free(inbuf); free(outbuf);
+ return False;
+ }
+
+ /******************* bind request on \PIPE\NETLOGON *****************/
+
+ if (!bind_rpc_pipe(PIPE_NETLOGON, fnum, ++call_id, &abstract, &transfer))
+ {
+ free(inbuf); free(outbuf);
+ return False;
+ }
+
+ /******************* Request Challenge ********************/
+
+ fstrcpy(mach_acct, myhostname);
+ strlower(mach_pwd);
+
+ fstrcpy(mach_pwd , myhostname);
+ strcat(mach_acct, "$");
+
+ clnt_chal.data[0] = 0x11111111;
+ clnt_chal.data[1] = 0x22222222;
+
+ /* send a client challenge; receive a server challenge */
+ if (!do_lsa_req_chal(fnum, ++call_id, desthost, myhostname, &clnt_chal, &srv_chal))
+ {
+ cli_smb_close(inbuf, outbuf, Client, cnum, fnum);
+ free(inbuf); free(outbuf);
+ return False;
+ }
+
+ /************ Long-term Session key (default) **********/
+
+#if 0
+ /* DAMN! can't get the machine password - need become_root() to do it! */
+ /* get the machine password */
+ if (!get_md4pw(mach_acct, nt_owf_mach_pwd))
+ {
+ cli_smb_close(inbuf, outbuf, Client, cnum, fnum);
+ free(inbuf); free(outbuf);
+ return False;
+ }
+
+ DEBUG(5,("got nt owf from smbpasswd entry: %s\n", mach_pwd));
+#else
+
+ {
+ char lm_owf_mach_pwd[16];
+ nt_lm_owf_gen(mach_pwd, nt_owf_mach_pwd, lm_owf_mach_pwd);
+ DEBUG(5,("generating nt owf from initial machine pwd: %s\n", mach_pwd));
+ }
+
+#endif
+
+ dump_data(6, nt_owf_mach_pwd, 16);
+
+ /* calculate the session key */
+ cred_session_key(&clnt_chal, &srv_chal, nt_owf_mach_pwd, sess_key);
+
+
+ /******************* Authenticate 2 ********************/
+
+ /* calculate auth-2 credentials */
+ cred_create(sess_key, &clnt_chal, zerotime, &(clnt_cred.challenge));
+
+ /* send client auth-2 challenge; receive an auth-2 challenge */
+ if (!do_lsa_auth2(fnum, ++call_id, desthost, mach_acct, 2, myhostname,
+ &(clnt_cred.challenge), 0x000001ff, &auth2_srv_chal))
+ {
+ cli_smb_close(inbuf, outbuf, Client, cnum, fnum);
+ free(inbuf); free(outbuf);
+ return False;
+ }
+
+
+ /*********************** SAM Info ***********************/
+
+ /* this is used in both the SAM Logon and the SAM Logoff */
+ make_id_info1(&id1, workgroup, 0,
+ getuid(), 0,
+ username, myhostname,
+ NULL, NULL);
+
+ /*********************** SAM Logon **********************/
+
+ clnt_cred.timestamp.time = sam_logon_clnt_cred.timestamp.time = time(NULL);
+
+ /* calculate sam logon credentials, using the auth2 client challenge */
+ cred_create(sess_key, &(clnt_cred.challenge), sam_logon_clnt_cred.timestamp,
+ &(sam_logon_clnt_cred.challenge));
+
+ /* send client sam-logon challenge; receive a sam-logon challenge */
+ if (!do_lsa_sam_logon(fnum, ++call_id, sess_key, &clnt_cred,
+ desthost, mach_acct,
+ &sam_logon_clnt_cred, &sam_logon_rtn_cred,
+ 1, 1, &id1, &user_info1,
+ &sam_logon_srv_cred))
+ {
+ cli_smb_close(inbuf, outbuf, Client, cnum, fnum);
+ free(inbuf); free(outbuf);
+ return False;
+ }
+
+ /*********************** SAM Logoff *********************/
+
+ clnt_cred.timestamp.time = sam_logoff_clnt_cred.timestamp.time = time(NULL);
+
+ /* calculate sam logoff credentials, using the sam logon return challenge */
+ cred_create(sess_key, &(clnt_cred.challenge),
+ sam_logoff_clnt_cred.timestamp,
+ &(sam_logoff_clnt_cred.challenge));
+
+ /* send client sam-logoff challenge; receive a sam-logoff challenge */
+ if (!do_lsa_sam_logoff(fnum, ++call_id, sess_key, &clnt_cred,
+ desthost, mach_acct,
+ &sam_logoff_clnt_cred, &sam_logoff_rtn_cred,
+ 1, 1, &id1,
+ &sam_logoff_srv_cred))
+ {
+ cli_smb_close(inbuf, outbuf, Client, cnum, fnum);
+ free(inbuf); free(outbuf);
+ return False;
+ }
+
+ /******************** close the \PIPE\NETLOGON file **************/
+
+ cli_smb_close(inbuf, outbuf, Client, cnum, fnum);
+
+ /* free memory used in all rpc transactions, above */
+ free(inbuf); free(outbuf);
+
+ return True;
+}
+#endif /* NTDOMAIN */
diff --git a/source/codepages/codepage_def.437 b/source/codepages/codepage_def.437
new file mode 100644
index 00000000000..d357c074e44
--- /dev/null
+++ b/source/codepages/codepage_def.437
@@ -0,0 +1,70 @@
+#
+# 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.
+#
+
+# Codepage definition file for IBM Code Page 437 - MS-DOS Latin US
+# defines lower->upper mapping.
+# Written by Jeremy Allison <jallison@whistle.com>
+
+# The columns are :
+# lower upper map upper to lower map lower to upper
+#
+ 0x87 0x80 True True
+ 0x81 0x9A True True
+ 0x82 0x90 True True
+ 0x83 0x41 True False
+ 0x84 0x8E True True
+ 0x85 0x41 True False
+ 0x86 0x8F True True
+ 0x88 0x45 True False
+ 0x89 0x45 True False
+ 0x8A 0x45 True False
+ 0x8B 0x49 True False
+ 0x8C 0x49 True False
+ 0x8D 0x49 True False
+ 0x91 0x92 True True
+ 0x93 0x4F True False
+ 0x94 0x99 True True
+ 0x95 0x4F True False
+ 0x96 0x55 True False
+ 0x97 0x55 True False
+ 0x9B 0 False False
+ 0x9C 0 False False
+ 0x9D 0 False False
+ 0xA0 0x41 True False
+ 0xA1 0x49 True False
+ 0xA2 0x4F True False
+ 0xA3 0x55 True False
+ 0xA4 0xA5 True True
+ 0xA8 0 False False
+ 0xAD 0 False False
+ 0xAE 0 False False
+ 0xAF 0 False False
+ 0xE0 0 False False
+ 0xE1 0 False False
+ 0xE2 0 False False
+ 0xE3 0 False False
+ 0xE4 0 False False
+ 0xE5 0 False False
+ 0xE6 0 False False
+ 0xE7 0 False False
+ 0xE8 0 False False
+ 0xE9 0 False False
+ 0xEA 0 False False
+ 0xEB 0 False False
+ 0xEC 0 False False
+ 0xED 0 False False
+ 0xEE 0 False False
+ 0xEF 0 False False
diff --git a/source/codepages/codepage_def.850 b/source/codepages/codepage_def.850
new file mode 100644
index 00000000000..e2466a707af
--- /dev/null
+++ b/source/codepages/codepage_def.850
@@ -0,0 +1,54 @@
+#
+# 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.
+#
+
+# Codepage definition file for IBM Code Page 850 - MS-DOS Latin 1
+# defines lower->upper mapping.
+# Written by Jeremy Allison (jallison@whistle.com)
+
+# The columns are :
+# lower upper map upper to lower map lower to upper
+#
+ 0x85 0xB7 True True
+ 0xA0 0xB5 True True
+ 0x83 0xB6 True True
+ 0xC6 0xC7 True True
+ 0x84 0x8E True True
+ 0x86 0x8F True True
+ 0x91 0x92 True True
+ 0x87 0x80 True True
+ 0x8A 0xD4 True True
+ 0x82 0x90 True True
+ 0x88 0xD2 True True
+ 0x89 0xD3 True True
+ 0x8D 0xDE True True
+ 0xA1 0xD6 True True
+ 0x8C 0xD7 True True
+ 0x8B 0xD8 True True
+ 0xD0 0xD1 True True
+ 0xA4 0xA5 True True
+ 0x95 0xE3 True True
+ 0xA2 0xE0 True True
+ 0x93 0xE2 True True
+ 0xE4 0xE5 True True
+ 0x94 0x99 True True
+ 0x9B 0x9D True True
+ 0x97 0xEB True True
+ 0xA3 0xE9 True True
+ 0x96 0xEA True True
+ 0x81 0x9A True True
+ 0xEC 0xED True True
+ 0xE7 0xE8 True True
+ 0x9C 0 False False
diff --git a/source/codepages/codepage_def.852 b/source/codepages/codepage_def.852
new file mode 100644
index 00000000000..ed1423428ca
--- /dev/null
+++ b/source/codepages/codepage_def.852
@@ -0,0 +1,63 @@
+#
+# 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.
+#
+
+# Codepage definition file for IBM Code Page 852 - MS-DOS Latin 2
+# defines lower->upper mapping.
+# Written by Leos Bitto <bitto@altec.cz>
+
+# The columns are :
+# lower upper map upper to lower map lower to upper
+#
+ 0x81 0x9A True True
+ 0x82 0x90 True True
+ 0x83 0xB6 True True
+ 0x84 0x8E True True
+ 0x85 0xDE True True
+ 0x86 0x8F True True
+ 0x87 0x80 True True
+ 0x88 0x9D True True
+ 0x89 0xD3 True True
+ 0x8B 0x8A True True
+ 0x8C 0xD7 True True
+ 0x92 0x91 True True
+ 0x93 0xE2 True True
+ 0x94 0x99 True True
+ 0x96 0x95 True True
+ 0x98 0x97 True True
+ 0x9C 0x9B True True
+ 0x9F 0xAC True True
+ 0xA0 0xB5 True True
+ 0xA1 0xD6 True True
+ 0xA2 0xE0 True True
+ 0xA3 0xE9 True True
+ 0xA5 0xA4 True True
+ 0xA7 0xA6 True True
+ 0xA9 0xA8 True True
+ 0xAB 0x8D True True
+ 0xAD 0xB8 True True
+ 0xBE 0xBD True True
+ 0xC7 0xC6 True True
+ 0xD0 0xD1 True True
+ 0xD4 0xD2 True True
+ 0xD8 0xB7 True True
+ 0xE4 0xE3 True True
+ 0xE5 0xD5 True True
+ 0xE7 0xE6 True True
+ 0xEA 0xE8 True True
+ 0xEC 0xED True True
+ 0xEE 0xDD True True
+ 0xFB 0xEB True True
+ 0xFD 0xFC True True
diff --git a/source/codepages/codepage_def.932 b/source/codepages/codepage_def.932
new file mode 100644
index 00000000000..8d9ff631fba
--- /dev/null
+++ b/source/codepages/codepage_def.932
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+
+# Codepage definition file for IBM Code Page 932 - MS-DOS Japanese SJIS
+# defines lower->upper mapping.
+# Written by Jeremy Allison <jallison@whistle.com>
+
+# The columns are :
+# lower upper map upper to lower map lower to upper
+#
+# This file is intentionaly empty - no mappings are done. \ No newline at end of file
diff --git a/source/include/byteorder.h b/source/include/byteorder.h
index 899cd6c4991..4d972a5cac2 100644
--- a/source/include/byteorder.h
+++ b/source/include/byteorder.h
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
SMB Byte handling
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1997
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
@@ -22,8 +22,98 @@
/*
This file implements macros for machine independent short and
int manipulation
+
+Here is a description of this file that I emailed to the samba list once:
+
+> I am confused about the way that byteorder.h works in Samba. I have
+> looked at it, and I would have thought that you might make a distinction
+> between LE and BE machines, but you only seem to distinguish between 386
+> and all other architectures.
+>
+> Can you give me a clue?
+
+sure.
+
+The distinction between 386 and other architectures is only there as
+an optimisation. You can take it out completely and it will make no
+difference. The routines (macros) in byteorder.h are totally byteorder
+independent. The 386 optimsation just takes advantage of the fact that
+the x86 processors don't care about alignment, so we don't have to
+align ints on int boundaries etc. If there are other processors out
+there that aren't alignment sensitive then you could also define
+CAREFUL_ALIGNMENT=0 on those processors as well.
+
+Ok, now to the macros themselves. I'll take a simple example, say we
+want to extract a 2 byte integer from a SMB packet and put it into a
+type called uint16 that is in the local machines byte order, and you
+want to do it with only the assumption that uint16 is _at_least_ 16
+bits long (this last condition is very important for architectures
+that don't have any int types that are 2 bytes long)
+
+You do this:
+
+#define CVAL(buf,pos) (((unsigned char *)(buf))[pos])
+#define PVAL(buf,pos) ((unsigned)CVAL(buf,pos))
+#define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
+
+then to extract a uint16 value at offset 25 in a buffer you do this:
+
+char *buffer = foo_bar();
+uint16 xx = SVAL(buffer,25);
+
+We are using the byteoder independence of the ANSI C bitshifts to do
+the work. A good optimising compiler should turn this into efficient
+code, especially if it happens to have the right byteorder :-)
+
+I know these macros can be made a bit tidier by removing some of the
+casts, but you need to look at byteorder.h as a whole to see the
+reasoning behind them. byteorder.h defines the following macros:
+
+SVAL(buf,pos) - extract a 2 byte SMB value
+IVAL(buf,pos) - extract a 4 byte SMB value
+SVALS(buf,pos) signed version of SVAL()
+IVALS(buf,pos) signed version of IVAL()
+
+SSVAL(buf,pos,val) - put a 2 byte SMB value into a buffer
+SIVAL(buf,pos,val) - put a 4 byte SMB value into a buffer
+SSVALS(buf,pos,val) - signed version of SSVAL()
+SIVALS(buf,pos,val) - signed version of SIVAL()
+
+RSVAL(buf,pos) - like SVAL() but for NMB byte ordering
+RIVAL(buf,pos) - like IVAL() but for NMB byte ordering
+RSSVAL(buf,pos,val) - like SSVAL() but for NMB ordering
+RSIVAL(buf,pos,val) - like SIVAL() but for NMB ordering
+
+it also defines lots of intermediate macros, just ignore those :-)
+
*/
+/* some switch macros that do both store and read to and from SMB buffers */
+
+#define RW_PCVAL(read,inbuf,outbuf,len) \
+ if (read) { PCVAL (inbuf,0,outbuf,len) } \
+ else { PSCVAL(inbuf,0,outbuf,len) }
+
+#define RW_PIVAL(read,inbuf,outbuf,len) \
+ if (read) { PIVAL (inbuf,0,outbuf,len) } \
+ else { PSIVAL(inbuf,0,outbuf,len) }
+
+#define RW_PSVAL(read,inbuf,outbuf,len) \
+ if (read) { PSVAL (inbuf,0,outbuf,len) } \
+ else { PSSVAL(inbuf,0,outbuf,len) }
+
+#define RW_CVAL(read, inbuf, outbuf, offset) \
+ if (read) (outbuf) = CVAL (inbuf,offset); \
+ else SCVAL(inbuf,offset,outbuf);
+
+#define RW_IVAL(read, inbuf, outbuf, offset) \
+ if (read) (outbuf)= IVAL (inbuf,offset); \
+ else SIVAL(inbuf,offset,outbuf);
+
+#define RW_SVAL(read, inbuf, outbuf, offset) \
+ if (read) (outbuf)= SVAL (inbuf,offset); \
+ else SSVAL(inbuf,offset,outbuf);
+
#undef CAREFUL_ALIGNMENT
/* we know that the 386 can handle misalignment and has the "right"
@@ -42,6 +132,7 @@
#if CAREFUL_ALIGNMENT
+
#define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
#define IVAL(buf,pos) (SVAL(buf,pos)|SVAL(buf,(pos)+2)<<16)
#define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8)
@@ -52,24 +143,56 @@
#define SIVAL(buf,pos,val) SIVALX((buf),(pos),((uint32)(val)))
#define SSVALS(buf,pos,val) SSVALX((buf),(pos),((int16)(val)))
#define SIVALS(buf,pos,val) SIVALX((buf),(pos),((int32)(val)))
+
#else
+
/* this handles things for architectures like the 386 that can handle
alignment errors */
/*
WARNING: This section is dependent on the length of int16 and int32
being correct
*/
+
+/* get single value from an SMB buffer */
#define SVAL(buf,pos) (*(uint16 *)((char *)(buf) + (pos)))
#define IVAL(buf,pos) (*(uint32 *)((char *)(buf) + (pos)))
#define SVALS(buf,pos) (*(int16 *)((char *)(buf) + (pos)))
#define IVALS(buf,pos) (*(int32 *)((char *)(buf) + (pos)))
+
+/* store single value in an SMB buffer */
#define SSVAL(buf,pos,val) SVAL(buf,pos)=((uint16)(val))
#define SIVAL(buf,pos,val) IVAL(buf,pos)=((uint32)(val))
#define SSVALS(buf,pos,val) SVALS(buf,pos)=((int16)(val))
#define SIVALS(buf,pos,val) IVALS(buf,pos)=((int32)(val))
+
#endif
+/* macros for reading / writing arrays */
+
+#define SMBMACRO(macro,buf,pos,val,len,size) \
+{ int l; for (l = 0; l < (len); l++) (val)[l] = macro((buf), (pos) + (size)*l); }
+
+#define SSMBMACRO(macro,buf,pos,val,len,size) \
+{ int l; for (l = 0; l < (len); l++) macro((buf), (pos) + (size)*l, (val)[l]); }
+
+/* reads multiple data from an SMB buffer */
+#define PCVAL(buf,pos,val,len) SMBMACRO(CVAL,buf,pos,val,len,1)
+#define PSVAL(buf,pos,val,len) SMBMACRO(SVAL,buf,pos,val,len,2)
+#define PIVAL(buf,pos,val,len) SMBMACRO(IVAL,buf,pos,val,len,4)
+#define PCVALS(buf,pos,val,len) SMBMACRO(CVALS,buf,pos,val,len,1)
+#define PSVALS(buf,pos,val,len) SMBMACRO(SVALS,buf,pos,val,len,2)
+#define PIVALS(buf,pos,val,len) SMBMACRO(IVALS,buf,pos,val,len,4)
+
+/* stores multiple data in an SMB buffer */
+#define PSCVAL(buf,pos,val,len) SSMBMACRO(SCVAL,buf,pos,val,len,1)
+#define PSSVAL(buf,pos,val,len) SSMBMACRO(SSVAL,buf,pos,val,len,2)
+#define PSIVAL(buf,pos,val,len) SSMBMACRO(SIVAL,buf,pos,val,len,4)
+#define PSCVALS(buf,pos,val,len) SSMBMACRO(SCVALS,buf,pos,val,len,1)
+#define PSSVALS(buf,pos,val,len) SSMBMACRO(SSVALS,buf,pos,val,len,2)
+#define PSIVALS(buf,pos,val,len) SSMBMACRO(SIVALS,buf,pos,val,len,4)
+
+
/* now the reverse routines - these are used in nmb packets (mostly) */
#define SREV(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF))
#define IREV(x) ((SREV(x)<<16) | (SREV((x)>>16)))
@@ -78,3 +201,43 @@
#define RIVAL(buf,pos) IREV(IVAL(buf,pos))
#define RSSVAL(buf,pos,val) SSVAL(buf,pos,SREV(val))
#define RSIVAL(buf,pos,val) SIVAL(buf,pos,IREV(val))
+
+#define DBG_RW_PCVAL(charmode,string,depth,base,read,inbuf,outbuf,len) \
+ RW_PCVAL(read,inbuf,outbuf,len) \
+ DEBUG(5,("%s%04x %s: ", \
+ tab_depth(depth), PTR_DIFF(inbuf,base),string)); \
+ if (charmode) print_asc(5, (unsigned char*)(outbuf), (len)); else \
+ { int idx; for (idx = 0; idx < len; idx++) { DEBUG(5,("%02x ", (outbuf)[idx])); } } \
+ DEBUG(5,("\n"));
+
+#define DBG_RW_PSVAL(charmode,string,depth,base,read,inbuf,outbuf,len) \
+ RW_PSVAL(read,inbuf,outbuf,len) \
+ DEBUG(5,("%s%04x %s: ", \
+ tab_depth(depth), PTR_DIFF(inbuf,base),string)); \
+ if (charmode) print_asc(5, (unsigned char*)(outbuf), 2*(len)); else \
+ { int idx; for (idx = 0; idx < len; idx++) { DEBUG(5,("%04x ", (outbuf)[idx])); } } \
+ DEBUG(5,("\n"));
+
+#define DBG_RW_PIVAL(charmode,string,depth,base,read,inbuf,outbuf,len) \
+ RW_PIVAL(read,inbuf,outbuf,len) \
+ DEBUG(5,("%s%04x %s: ", \
+ tab_depth(depth), PTR_DIFF(inbuf,base),string)); \
+ if (charmode) print_asc(5, (unsigned char*)(outbuf), 4*(len)); else \
+ { int idx; for (idx = 0; idx < len; idx++) { DEBUG(5,("%08x ", (outbuf)[idx])); } } \
+ DEBUG(5,("\n"));
+
+#define DBG_RW_CVAL(string,depth,base,read,inbuf,outbuf) \
+ RW_CVAL(read,inbuf,outbuf,0) \
+ DEBUG(5,("%s%04x %s: %02x\n", \
+ tab_depth(depth), PTR_DIFF(inbuf,base), string, outbuf));
+
+#define DBG_RW_SVAL(string,depth,base,read,inbuf,outbuf) \
+ RW_SVAL(read,inbuf,outbuf,0) \
+ DEBUG(5,("%s%04x %s: %04x\n", \
+ tab_depth(depth), PTR_DIFF(inbuf,base), string, outbuf));
+
+#define DBG_RW_IVAL(string,depth,base,read,inbuf,outbuf) \
+ RW_IVAL(read,inbuf,outbuf,0) \
+ DEBUG(5,("%s%04x %s: %08x\n", \
+ tab_depth(depth), PTR_DIFF(inbuf,base), string, outbuf));
+
diff --git a/source/include/charset.h b/source/include/charset.h
index 7091732223a..fb184897c07 100644
--- a/source/include/charset.h
+++ b/source/include/charset.h
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Character set handling
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1997
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
@@ -51,11 +51,25 @@ extern void charset_initialise(void);
#undef isspace
#endif
-#define toupper(c) upper_char_map[(char)(c)]
-#define tolower(c) lower_char_map[(char)(c)]
-#define isupper(c) (((char)(c)) != tolower(c))
-#define islower(c) (((char)(c)) != toupper(c))
-#define isdoschar(c) (dos_char_map[(char)(c)] != 0)
+#define toupper(c) (upper_char_map[(c&0xff)] & 0xff)
+#define tolower(c) (lower_char_map[(c&0xff)] & 0xff)
+#define isupper(c) ((c&0xff) != tolower(c&0xff))
+#define islower(c) ((c&0xff) != toupper(c&0xff))
+#define isdoschar(c) (dos_char_map[(c&0xff)] != 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&0xff)) || strchr("-._",c))
#endif
+/* Dynamic codepage files defines. */
+
+/* Version id for dynamically loadable codepage files. */
+#define CODEPAGE_FILE_VERSION_ID 0x1
+/* Version 1 codepage file header size. */
+#define CODEPAGE_HEADER_SIZE 8
+/* Offsets for codepage file header entries. */
+#define CODEPAGE_VERSION_OFFSET 0
+#define CODEPAGE_CLIENT_CODEPAGE_OFFSET 2
+#define CODEPAGE_LENGTH_OFFSET 4
diff --git a/source/include/includes.h b/source/include/includes.h
index cc2bbbfad7c..4c7ec56367c 100644
--- a/source/include/includes.h
+++ b/source/include/includes.h
@@ -4,7 +4,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Machine customisation and include handling
- Copyright (C) Andrew Tridgell 1994-1995
+ Copyright (C) Andrew Tridgell 1994-1997
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
@@ -117,6 +117,7 @@
by the previous section
*/
#include "local.h"
+#include "ubi_dLinkList.h"
#include <stdio.h>
#ifdef POSIX_STDLIBH
#include <posix/stdlib.h>
@@ -139,6 +140,9 @@
#endif
#include <sys/socket.h>
+#ifdef AXPROC
+#include <termio.h>
+#endif
#include <sys/ioctl.h>
#include <stddef.h>
#ifdef POSIX_H
@@ -183,10 +187,6 @@
#endif
#endif
-#if USE_MMAP
-#include <sys/mman.h>
-#endif
-
#if defined(GETPWANAM)
#include <sys/types.h>
#include <sys/label.h>
@@ -194,31 +194,10 @@
#include <pwdadj.h>
#endif
-#if defined(SHADOW_PWD) && !defined(NETBSD) && !defined(CONVEX)
+#if defined(SHADOW_PWD) && !defined(NETBSD) && !defined(FreeBSD) && !defined(CONVEX)
#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
@@ -239,17 +218,36 @@ Here come some platform specific sections
#ifndef NO_ASMSIGNALH
#include <asm/signal.h>
#endif
+#ifdef GLIBC2
+#define _LINUX_C_LIB_VERSION_MAJOR 6
+#include <termios.h>
+#include <rpcsvc/ypclnt.h>
+#include <crypt.h>
+#include <netinet/tcp.h>
+#include <netinet/ip.h>
+#endif
#define SIGNAL_CAST (__sighandler_t)
#define USE_GETCWD
#define USE_SETSID
#define HAVE_BZERO
#define HAVE_MEMMOVE
+#define USE_SIGPROCMASK
+#define USE_WAITPID
+#define USE_SYSV_IPC
+#if 0
+/* SETFS disabled until we can check on some bug reports */
+#if _LINUX_C_LIB_VERSION_MAJOR >= 5
+#define USE_SETFS
+#endif
+#endif
#ifdef SHADOW_PWD
+#if _LINUX_C_LIB_VERSION_MAJOR < 5
#ifndef crypt
#define crypt pw_encrypt
#endif
#endif
#endif
+#endif
#ifdef SUNOS4
#define SIGNAL_CAST (void (*)(int))
@@ -271,9 +269,22 @@ typedef unsigned short mode_t;
#include <utime.h>
#define NO_STRERROR
#endif
+#ifndef REPLACE_GETPASS
#define REPLACE_GETPASS
+#endif
+#ifndef BSD_TERMIO
#define BSD_TERMIO
#endif
+#ifndef USE_SIGPROCMASK
+#define USE_SIGPROCMASK
+#endif
+#ifndef USE_WAITPID
+#define USE_WAITPID
+#endif
+#define USE_SYSV_IPC
+/* SunOS doesn't have POSIX atexit */
+#define atexit on_exit
+#endif
#ifdef SUNOS5
@@ -290,8 +301,11 @@ typedef unsigned short mode_t;
#include <string.h>
#include <arpa/inet.h>
#include <rpcsvc/ypclnt.h>
-#include <crypt.h>
#include <termios.h>
+#include <sys/stropts.h>
+#ifndef USE_LIBDES
+#include <crypt.h>
+#endif /* USE_LIBDES */
extern int gettimeofday (struct timeval *, void *);
extern int gethostname (char *name, int namelen);
extern int innetgr (const char *, const char *, const char *, const char *);
@@ -305,7 +319,19 @@ extern int innetgr (const char *, const char *, const char *, const char *);
#define USE_STATVFS
#define USE_GETCWD
#define USE_SETSID
+#define USE_SYSV_IPC
+
+union semun {
+ int val;
+ struct semid_ds *buf;
+ ushort *array;
+};
+
+
+#ifndef REPLACE_GETPASS
#define REPLACE_GETPASS
+#endif /* REPLACE_GETPASS */
+#define USE_SIGPROCMASK
#endif
@@ -323,9 +349,10 @@ char *getwd(char *);
#define SIGNAL_CAST (void(*)(int))
#endif
#define USE_DIRECT
+#define USE_WAITPID
#endif
-#ifdef SGI
+#ifdef SGI4
#include <netinet/tcp.h>
#include <sys/statfs.h>
#include <string.h>
@@ -337,10 +364,15 @@ char *getwd(char *);
#define STATFS4
#define USE_WAITPID
#define USE_DIRECT
+#define USE_SETSID
+#define USE_SYSV_IPC
#endif
-#ifdef SGI5
+#if defined(SGI5) || defined(SGI6)
+#include <arpa/inet.h>
#include <netinet/tcp.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
#include <sys/statvfs.h>
#include <string.h>
#include <signal.h>
@@ -353,6 +385,8 @@ char *getwd(char *);
#define SIGNAL_CAST (void (*)())
#define USE_STATVFS
#define USE_WAITPID
+#define USE_SETSID
+#define USE_SYSV_IPC
#endif
@@ -409,6 +443,7 @@ extern struct passwd *getpwnam();
#define USE_STATVFS
#define USE_GETCWD
#define USE_SETSID
+#define USE_SYSV_IPC
#endif
@@ -423,6 +458,7 @@ char *mktemp(char *); /* No standard include */
#define SIGNAL_CAST ( void (*) (int) )
#define STATFS3
#define USE_F_FSIZE
+#define USE_SETSID
#include <netinet/tcp.h>
#ifdef OSF1_ENH_SEC
#include <pwd.h>
@@ -433,6 +469,7 @@ char *mktemp(char *); /* No standard include */
#define PASSWORD_LENGTH 16
#define NEED_AUTH_PARAMETERS
#endif /* OSF1_ENH_SEC */
+#define USE_SYSV_IPC
#endif
@@ -448,7 +485,9 @@ char *mktemp(char *); /* No standard include */
#define NO_FSYNC
#define USE_GETCWD
#define USE_SETSID
+#ifndef REPLACE_GETPASS
#define REPLACE_GETPASS
+#endif /* REPLACE_GETPASS */
#define NO_GETRLIMIT
#endif /* CLIX */
@@ -475,13 +514,22 @@ char *mktemp(char *); /* No standard include */
#ifdef FreeBSD
+#include <arpa/inet.h>
#include <strings.h>
#include <netinet/tcp.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#define SIGNAL_CAST (void (*)())
+#define USE_SETVBUF
+#define USE_SETSID
+#define USE_GETCWD
+#define USE_WAITPID
#define USE_DIRECT
-#define REPLACE_INNETGR
+#define HAVE_MEMMOVE
+#define HAVE_BZERO
+#define HAVE_GETTIMEOFDAY
+#define HAVE_PATHCONF
+#define HAVE_GETGRNAM 1
#endif
@@ -496,10 +544,14 @@ char *mktemp(char *); /* No standard include */
#include <sys/id.h>
#include <sys/priv.h>
#include <netinet/tcp.h>
+#include <locale.h>
#define SYSV
#define USE_WAITPID
+#define USE_SIGBLOCK
#define SIGNAL_CAST (void (*)())
#define DEFAULT_PRINTING PRINT_AIX
+/* we undef this because sys/param.h is broken in aix. uggh. */
+#undef MAXHOSTNAMELEN
#endif
@@ -517,16 +569,21 @@ char *mktemp(char *); /* No standard include */
#define NEED_AUTH_PARAMETERS
#endif
#define SIGNAL_CAST (void (*)(__harg))
+#ifndef HPUX10 /* This is only needed for HPUX 9.x */
#define SELECT_CAST (int *)
+#endif /* HPUX10 */
#define SYSV
#define USE_WAITPID
#define WAIT3_CAST2 (int *)
#define USE_GETCWD
#define USE_SETSID
#define USE_SETRES
+#define USE_SYSV_IPC
#define DEFAULT_PRINTING PRINT_HPUX
-#define SIGCLD_IGNORE
-#endif
+/* Ken Weiss <krweiss@ucdavis.edu> tells us that SIGCLD_IGNORE is
+ not good for HPUX */
+/* #define SIGCLD_IGNORE */
+#endif /* HPUX */
#ifdef SEQUENT
@@ -546,8 +603,39 @@ char *mktemp(char *); /* No standard include */
#define NO_EID
#define STATFS4
#define USE_DIRECT
+#ifdef PTX4
+#undef USE_DIRECT
+#endif
#endif
+
+
+#ifdef SEQUENT_PTX4
+#include <string.h>
+#include <sys/dir.h>
+#include <dirent.h>
+#include <sys/statfs.h>
+#include <sys/statvfs.h>
+#include <sys/vfs.h>
+#include <fcntl.h>
+#include <sys/sockio.h>
+#include <netinet/tcp.h>
+#include <stropts.h>
+#include <termios.h>
+#define SYSV
+#define USE_WAITPID
+#define SIGNAL_CAST (void (*)(int))
+#define USE_STATVFS
+#define USE_GETCWD
+#ifndef seteuid
+#define seteuid(uid) setreuid(-1,uid)
+#endif
+#ifndef setegid
+#define setegid(gid) setregid(-1,gid)
+#endif
+#endif
+
+
#ifdef NEXT2
#include <sys/types.h>
#include <strings.h>
@@ -575,6 +663,7 @@ char *mktemp(char *); /* No standard include */
#define mode_t int
#define GID_TYPE int
#define gid_t int
+#define pid_t int
#define SIGNAL_CAST (void (*)(int))
#define WAIT3_CAST1 (union wait *)
#define HAVE_GMTOFF
@@ -603,44 +692,43 @@ char *mktemp(char *); /* No standard include */
#include <sys/netinet/ip.h>
#include <dirent.h>
#include <string.h>
+#include <termios.h>
#include <fcntl.h>
#include <sys/statfs.h>
#include <sys/stropts.h>
#include <limits.h>
+#include <locale.h>
#ifdef EVEREST
#include <unistd.h>
-#endif
+#endif /* EVEREST */
#ifdef NETGROUP
#include <rpcsvc/ypclnt.h>
-#endif
+#endif /* NETGROUP */
#ifdef SecureWare
#include <sys/security.h>
#include <sys/audit.h>
#include <prot.h>
#define crypt bigcrypt
-#endif
-#ifndef EVEREST
- #define ftruncate(f,l) syscall(0x0a28,f,l)
-#endif
+#endif /* SecureWare */
#define SIGNAL_CAST (void (*)(int))
#define USE_WAITPID
#define USE_GETCWD
#define USE_SETSID
#ifdef SCO3_2_2
-#define NO_EID
-#else
+#define setuid(u) setreuid(u,-1)
+#define seteuid(u) setreuid(-1,u)
+#else /* SCO3_2_2 */
#ifndef EVEREST
+#define ftruncate(f,l) syscall(0x0a28,f,l)
#define USE_IFREQ
-#endif
-#endif
+#define NO_INITGROUPS
+#endif /* EVEREST */
+#endif /* SCO3_2_2 */
#define STATFS4
#define NO_FSYNC
-#ifndef EVEREST
-#define NO_INITGROUPS
-#endif
#define HAVE_PATHCONF
#define NO_GETRLIMIT
-#endif
+#endif /* SCO */
@@ -734,7 +822,6 @@ char *strdup (char *);
#endif /* DNIX */
#ifdef CONVEX
-#define SIGNAL_CAST (void (*)(int))
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <dirent.h>
@@ -870,10 +957,66 @@ typedef int mode_t;
#endif
+#ifdef BOS
+#define SIGNAL_CAST (void (*)(int))
+#include <string.h>
+#include <sys/dir.h>
+#include <sys/select.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/statfs.h>
+#include <sys/bsdioctl.h>
+#endif
+
+#ifdef AMIGA
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <string.h>
+#include <netinet/tcp.h>
+#include <sys/acct.h>
+#include <sys/fcntl.h>
+#include <sys/filio.h>
+#include <sys/sockio.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <sys/termios.h>
+#include <limits.h>
+#include <sys/timeb.h>
+
+#define SIGNAL_CAST (void (*)(int))
+#define USE_GETCWD
+#define HAVE_BZERO
+#define HAVE_MEMMOVE
+#define USE_SIGPROCMASK
+#define USE_WAITPID
+#define USE_DIRECT
+#define USE_F_FSIZE
+#define HAVE_FCNTL_LOCK 0
+#define HAVE_GETTIMEOFDAY
+#define HAVE_PATHCONF
+
+#define HAVE_NO_PROC
+#define NO_FORK_DEBUG
+#define HAVE_FORK 0
+#define HAVE_VFORK 1
+#endif
+
+/* For UnixWare 2.x's ia_uinfo routines. (tangent@cyberport.com) */
+#ifdef IA_UINFO
+#include <iaf.h>
+#include <ia.h>
+#endif
+
+
/*******************************************************************
end of the platform specific sections
********************************************************************/
+#if defined(USE_MMAP) || defined(FAST_SHARE_MODES)
+#include <sys/mman.h>
+#endif
+
#ifdef SecureWare
#define NEED_AUTH_PARAMETERS
#endif
@@ -891,10 +1034,6 @@ extern char *getsmbpass(char *);
#define FD_SETSIZE 255
#endif
-#ifndef MAXINT
-#define MAXINT ((((unsigned)1)<<(sizeof(int)*8-1))-1)
-#endif
-
#ifndef __STDC__
#define const
#endif
@@ -942,6 +1081,11 @@ struct spwd { /* fake shadow password structure */
#endif
#endif
+#ifdef USE_SYSV_IPC
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <sys/shm.h>
+#endif
#ifdef AFS_AUTH
#include <afs/stds.h>
@@ -953,6 +1097,10 @@ struct spwd { /* fake shadow password structure */
#include <dce/sec_login.h>
#endif
+#ifdef KRB5_AUTH
+#include <krb5.h>
+#endif
+
#ifdef NO_UTIMBUF
struct utimbuf {
time_t actime;
@@ -977,10 +1125,9 @@ extern char *sys_errlist[];
#include "version.h"
#include "smb.h"
+#include "nameserv.h"
+#include "proto.h"
#include "byteorder.h"
-#ifdef SMB_PASSWD
-#include "smbpass.h"
-#endif
#include "kanji.h"
#include "charset.h"
@@ -990,11 +1137,15 @@ extern char *sys_errlist[];
#endif
#ifndef S_ISREG
-#define S_ISREG(x) ((S_IFREG & x)!=0)
+#define S_ISREG(x) ((S_IFREG & (x))!=0)
#endif
#ifndef S_ISDIR
-#define S_ISDIR(x) ((S_IFDIR & x)!=0)
+#define S_ISDIR(x) ((S_IFDIR & (x))!=0)
+#endif
+
+#if !defined(S_ISLNK) && defined(S_IFLNK)
+#define S_ISLNK(x) ((S_IFLNK & (x))!=0)
#endif
#ifdef UFC_CRYPT
@@ -1048,6 +1199,10 @@ it works and getting lots of bug reports */
#define SIGCLD SIGCHLD
#endif
+#ifndef MAP_FILE
+#define MAP_FILE 0
+#endif
+
#ifndef HAVE_FCNTL_LOCK
#define HAVE_FCNTL_LOCK 1
#endif
@@ -1064,9 +1219,13 @@ it works and getting lots of bug reports */
#define QSORT_CAST (int (*)())
#endif
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK 0x7f000001
+#endif /* INADDR_LOOPBACK */
+
/* this is a rough check to see if this machine has a lstat() call.
it is not guaranteed to work */
-#if !(defined(S_ISLNK) || defined(S_IFLNK))
+#if !defined(S_ISLNK)
#define lstat stat
#endif
diff --git a/source/include/kanji.h b/source/include/kanji.h
index 4f18305c637..cf303659208 100644
--- a/source/include/kanji.h
+++ b/source/include/kanji.h
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Kanji Extensions
- Copyright (C) Andrew Tridgell 1992-1994
+ Copyright (C) Andrew Tridgell 1992-1997
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
@@ -22,12 +22,11 @@
and extend coding system to EUC/SJIS/JIS/HEX at 1994.10.11
and add all jis codes sequence at 1995.8.16
Notes: Hexadecimal code by <ohki@gssm.otuka.tsukuba.ac.jp>
+ and add upper/lower case conversion 1997.8.21
*/
#ifndef _KANJI_H_
#define _KANJI_H_
-#ifdef KANJI
-
/* FOR SHIFT JIS CODE */
#define is_shift_jis(c) \
((0x81 <= ((unsigned char) (c)) && ((unsigned char) (c)) <= 0x9f) \
@@ -37,6 +36,22 @@
&& ((unsigned char) (c)) != 0x7f)
#define is_kana(c) ((0xa0 <= ((unsigned char) (c)) && ((unsigned char) (c)) <= 0xdf))
+/* case conversion */
+#define is_sj_upper2(c) \
+ ((0x60 <= (unsigned char) (c)) && ((unsigned char) (c) <= 0x79))
+#define is_sj_lower2(c) \
+ ((0x81 <= (unsigned char) (c)) && ((unsigned char) (c) <= 0x9A))
+#define sjis_alph 0x82
+#define is_sj_alph(c) (sjis_alph == (unsigned char) (c))
+#define is_sj_upper(c1, c2) (is_sj_alph (c1) && is_sj_upper2 (c2))
+#define is_sj_lower(c1, c2) (is_sj_alph (c1) && is_sj_lower2 (c2))
+#define sj_toupper2(c) \
+ (is_sj_lower2 (c) ? ((int) ((unsigned char) (c) - 0x81 + 0x60)) : \
+ ((int) (unsigned char) (c)))
+#define sj_tolower2(c) \
+ (is_sj_upper2 (c) ? ((int) ((unsigned char) (c) - 0x60 + 0x81)) : \
+ ((int) (unsigned char) (c)))
+
#ifdef _KANJI_C_
/* FOR EUC CODE */
#define euc_kana (0x8e)
@@ -90,16 +105,8 @@
#else /* not _KANJI_C_ */
-extern char* (*_dos_to_unix) (const char *str, BOOL overwrite);
-extern char* (*_unix_to_dos) (const char *str, BOOL overwrite);
-
-#define unix_to_dos (*_unix_to_dos)
-#define dos_to_unix (*_dos_to_unix)
-
-extern char *sj_strtok (char *s1, const char *s2);
-extern char *sj_strchr (const char *s, int c);
-extern char *sj_strrchr (const char *s, int c);
-extern char *sj_strstr (const char *s1, const char *s2);
+extern char *(*_dos_to_unix)(char *str, BOOL overwrite);
+extern char *(*_unix_to_dos)(char *str, BOOL overwrite);
#define strchr sj_strchr
#define strrchr sj_strrchr
@@ -120,11 +127,7 @@ extern char *sj_strstr (const char *s1, const char *s2);
int interpret_coding_system (char *str, int def);
-#else
-
-#define unix_to_dos(x,y) (x)
-#define dos_to_unix(x,y) (x)
-
-#endif /* not KANJI */
+#define unix_to_dos(x,y) unix2dos_format(x,y)
+#define dos_to_unix(x,y) dos2unix_format(x,y)
#endif /* _KANJI_H_ */
diff --git a/source/include/local.h b/source/include/local.h
index 2775453e150..c1f1de2132b 100644
--- a/source/include/local.h
+++ b/source/include/local.h
@@ -42,28 +42,20 @@
#define WORDMAX 0xFFFF
+/* the maximum password length before we declare a likely attack */
+#define MAX_PASS_LEN 200
/* separators for lists */
#define LIST_SEP " \t,;:\n\r"
#ifndef LOCKDIR
+/* this should have been set in the Makefile */
#define LOCKDIR "/tmp/samba"
#endif
/* this is where browse lists are kept in the lock dir */
#define SERVER_LIST "browse.dat"
-/* the print command on the server, %s is replaced with the filename */
-/* note that the -r removes the file after printing - you'll run out */
-/* of disk pretty quickly if you don't. This command is only used as */
-/* the default - it can be overridden in the configuration file. */
-#define PRINT_COMMAND "lpr -r %s"
-
-/* the lpq command on the server. the printername is passed as an argument */
-#ifndef LPQ_COMMAND
-#define LPQ_COMMAND "lpq -P"
-#endif
-
/* shall guest entries in printer queues get changed to user entries,
so they can be deleted using the windows print manager? */
#define LPQ_GUEST_TO_USER
@@ -83,12 +75,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
@@ -130,9 +116,7 @@
/* the following control timings of various actions. Don't change
them unless you know what you are doing. These are all in seconds */
#define DEFAULT_SMBD_TIMEOUT (60*60*24*7)
-#define SMBD_RELOAD_CHECK (10)
-#define SHARE_MODES_CHECK (10)
-#define SHARE_MODES_CLEAN (300)
+#define SMBD_RELOAD_CHECK (60)
#define IDLE_CLOSED_TIMEOUT (60)
#define DPTR_IDLE_TIMEOUT (120)
#define SMBD_SELECT_LOOP (10)
@@ -163,5 +147,22 @@
/* shall we support browse requests via a FIFO to nmbd? */
#define ENABLE_FIFO 1
+/* how long to wait for a socket connect to happen */
+#define LONG_CONNECT_TIMEOUT 30
+#define SHORT_CONNECT_TIMEOUT 5
+
+
+/* the directory to sit in when idle */
+/* #define IDLE_DIR "/" */
+
+/* Timout (in seconds) to wait for an oplock break
+ message to return. */
+
+#define OPLOCK_BREAK_TIMEOUT 30
+
+
+/* the read preciction code has been disabled until some problems with
+ it are worked out */
+#define USE_READ_PREDICTION 0
#endif
diff --git a/source/include/nameserv.h b/source/include/nameserv.h
index 168dd4ba866..2a7bb290709 100644
--- a/source/include/nameserv.h
+++ b/source/include/nameserv.h
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
NBT netbios header - version 2
- Copyright (C) Andrew Tridgell 1994-1995
+ Copyright (C) Andrew Tridgell 1994-1997
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,17 +20,112 @@
*/
-#define MAX_DGRAM_SIZE 576
+#define GET_TTL(ttl) ((ttl)?MIN(ttl,lp_max_ttl()):lp_max_ttl())
+
+/* NTAS uses 2, NT uses 1, WfWg uses 0 */
+#define MAINTAIN_LIST 2
+#define ELECTION_VERSION 1
+
+#define MAX_DGRAM_SIZE (576) /* tcp/ip datagram limit is 576 bytes */
#define MIN_DGRAM_SIZE 12
-#define NMB_PORT 137
-#define DGRAM_PORT 138
-#define SMB_PORT 139
+#define NMB_QUERY 0x20
+#define NMB_STATUS 0x21
+
+#define NMB_REG 0x05 /* see rfc1002.txt 4.2.2,3,5,6,7,8 */
+#define NMB_REG_REFRESH 0x09 /* see rfc1002.txt 4.2.4 */
+#define NMB_REL 0x06 /* see rfc1002.txt 4.2.9,10,11 */
+#define NMB_WAIT_ACK 0x07 /* see rfc1002.txt 4.2.16 */
+/* XXXX what about all the other types?? 0x1, 0x2, 0x3, 0x4, 0x8? */
+
+#define FIND_ANY_NAME 0
+#define FIND_SELF_NAME 1
+
+/* NetBIOS flags */
+#define NB_GROUP 0x80
+#define NB_PERM 0x02
+#define NB_ACTIVE 0x04
+#define NB_CONFL 0x08
+#define NB_DEREG 0x10
+#define NB_BFLAG 0x00 /* broadcast node type */
+#define NB_PFLAG 0x20 /* point-to-point node type */
+#define NB_MFLAG 0x40 /* mixed bcast & p-p node type */
+#define NB_HFLAG 0x60 /* microsoft 'hybrid' node type */
+#define NB_FLGMSK 0x60
+
+#define REFRESH_TIME (15*60)
+#define NAME_POLL_REFRESH_TIME (5*60)
+#define NAME_POLL_INTERVAL 15
-enum name_source {LMHOSTS, REGISTER, SELF, DNS, DNSFAIL};
+/* NetBIOS flag identifier */
+#define NAME_PERMANENT(p) ((p) & NB_PERM)
+#define NAME_ACTIVE(p) ((p) & NB_ACTIVE)
+#define NAME_CONFLICT(p) ((p) & NB_CONFL)
+#define NAME_DEREG(p) ((p) & NB_DEREG)
+#define NAME_GROUP(p) ((p) & NB_GROUP)
+
+#define NAME_BFLAG(p) (((p) & NB_FLGMSK) == NB_BFLAG)
+#define NAME_PFLAG(p) (((p) & NB_FLGMSK) == NB_PFLAG)
+#define NAME_MFLAG(p) (((p) & NB_FLGMSK) == NB_MFLAG)
+#define NAME_HFLAG(p) (((p) & NB_FLGMSK) == NB_HFLAG)
+
+/* server type identifiers */
+#define AM_MASTER(work) (work->ServerType & SV_TYPE_MASTER_BROWSER)
+#define AM_BACKUP(work) (work->ServerType & SV_TYPE_BACKUP_BROWSER)
+#define AM_DOMMST(work) (work->ServerType & SV_TYPE_DOMAIN_MASTER)
+#define AM_DOMMEM(work) (work->ServerType & SV_TYPE_DOMAIN_MEMBER)
+
+/* microsoft browser NetBIOS name */
+#define MSBROWSE "\001\002__MSBROWSE__\002"
+
+/* mail slots */
+#define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE"
+#define NET_LOGON_MAILSLOT "\\MAILSLOT\\NET\\NETLOGON"
+#define NT_LOGON_MAILSLOT "\\MAILSLOT\\NET\\NTLOGON"
+
+enum name_source {STATUS_QUERY, LMHOSTS, REGISTER, SELF, DNS, DNSFAIL};
enum node_type {B_NODE=0, P_NODE=1, M_NODE=2, NBDD_NODE=3};
enum packet_type {NMB_PACKET, DGRAM_PACKET};
+enum master_state
+{
+ MST_POTENTIAL,
+ MST_BACK,
+ MST_MSB,
+ MST_BROWSER
+};
+
+enum domain_state
+{
+ DOMAIN_NONE,
+ DOMAIN_WAIT,
+ DOMAIN_MST
+};
+
+enum logon_state
+{
+ LOGON_NONE,
+ LOGON_WAIT,
+ LOGON_SRV
+};
+
+enum state_type
+{
+ NAME_STATUS_DOM_SRV_CHK,
+ NAME_STATUS_SRV_CHK,
+ NAME_REGISTER_CHALLENGE,
+ NAME_REGISTER,
+ NAME_RELEASE,
+ NAME_QUERY_CONFIRM,
+ NAME_QUERY_SYNC_LOCAL,
+ NAME_QUERY_SYNC_REMOTE,
+ NAME_QUERY_DOM_SRV_CHK,
+ NAME_QUERY_SRV_CHK,
+ NAME_QUERY_FIND_MST,
+ NAME_QUERY_MST_CHK,
+ NAME_QUERY_DOMAIN
+};
+
/* a netbios name structure */
struct nmb_name {
char name[17];
@@ -38,40 +133,167 @@ struct nmb_name {
int name_type;
};
+/* a netbios flags + ip address structure */
+/* this is used for multi-homed systems and for internet group names */
+struct nmb_ip
+{
+ struct in_addr ip; /* ip address of host that owns this name */
+ uint16 nb_flags; /* netbios flags */
+};
+
/* this is the structure used for the local netbios name list */
struct name_record
{
struct name_record *next;
struct name_record *prev;
- struct nmb_name name;
- time_t death_time;
- struct in_addr ip;
- BOOL unique;
- enum name_source source;
+
+ struct nmb_name name; /* the netbios name */
+ struct nmb_ip *ip_flgs; /* the ip + flags */
+ int num_ips; /* number of ip+flags entries */
+
+ enum name_source source; /* where the name came from */
+
+ time_t death_time; /* time record must be removed (do not remove if 0) */
+ time_t refresh_time; /* time record should be refreshed */
};
-/* this is used by the list of domains */
-struct domain_record
+struct subnet_record;
+
+/* browse and backup server cache for synchronising browse list */
+struct browse_cache_record
{
- struct domain_record *next;
- struct domain_record *prev;
- fstring name;
- time_t lastannounce_time;
- int announce_interval;
- struct in_addr bcast_ip;
+ struct browse_cache_record *next;
+ struct browse_cache_record *prev;
+
+ pstring name;
+ int type;
+ pstring group;
+ struct in_addr ip;
+ time_t sync_time;
+ BOOL synced;
+ BOOL local;
+ struct subnet_record *subnet;
};
-/* this is used to hold the list of servers in my domain */
+/* this is used to hold the list of servers in my domain, and is */
+/* contained within lists of domains */
struct server_record
{
struct server_record *next;
struct server_record *prev;
- fstring name;
- fstring comment;
- uint32 servertype;
+
+ struct server_info_struct serv;
time_t death_time;
};
+/* a workgroup structure. it contains a list of servers */
+struct work_record
+{
+ struct work_record *next;
+ struct work_record *prev;
+
+ struct server_record *serverlist;
+
+ /* stage of development from non-local-master up to local-master browser */
+ enum master_state mst_state;
+
+ /* stage of development from non-domain-master to domain master browser */
+ enum domain_state dom_state;
+
+ /* stage of development from non-logon-server to logon server */
+ enum logon_state log_state;
+
+ /* work group info */
+ fstring work_group;
+ int token; /* used when communicating with backup browsers */
+ int ServerType;
+
+ /* announce info */
+ time_t lastannounce_time;
+ int announce_interval;
+ BOOL needannounce;
+
+
+ /* election info */
+ BOOL RunningElection;
+ BOOL needelection;
+ int ElectionCount;
+ uint32 ElectionCriterion;
+};
+
+/* initiated name queries recorded in this list to track any responses... */
+/* sadly, we need to group everything together. i suppose that if this
+ gets unwieldy, then a union ought to be considered. oh for c++... */
+struct response_record
+{
+ struct response_record *next;
+ struct response_record *prev;
+
+ uint16 response_id;
+ enum state_type state;
+
+ int fd;
+ int quest_type;
+ struct nmb_name name;
+ int nb_flags;
+ time_t ttl;
+
+ int server_type;
+ fstring my_name;
+ fstring my_comment;
+
+ BOOL bcast;
+ BOOL recurse;
+ struct in_addr send_ip;
+ struct in_addr reply_to_ip;
+ int reply_id;
+
+ int num_msgs;
+
+ time_t repeat_time;
+ time_t repeat_interval;
+ int repeat_count;
+};
+
+/* a subnet structure. it contains a list of workgroups and netbios names*/
+
+/* note that a subnet of 255.255.255.255 contains all the WINS netbios names.
+ all communication from such nodes are on a non-broadcast basis: they
+ are point-to-point (P nodes) or mixed point-to-point and broadcast
+ (M nodes). M nodes use point-to-point as a preference, and will use
+ broadcasting for certain activities, or will resort to broadcasting as a
+ last resort, if the WINS server fails (users of wfwg will notice that their
+ machine often freezes for 30 seconds at a time intermittently, if the WINS
+ server is down).
+
+ B nodes will have their own, totally separate subnet record, with their
+ own netbios name set. these do NOT interact with other subnet records'
+ netbios names, INCLUDING the WINS one (with an ip "address", so called,
+ of 255.255.255.255)
+
+ there is a separate response list for each subnet record. in the case of
+ the 255.255.255.255 subnet record (WINS), the WINS server will be able to
+ use this to poll (infrequently!) each of its entries, to ensure that the
+ names are still in use.
+ XXXX this polling is a planned feature for a really over-cautious WINS server
+*/
+
+struct subnet_record
+{
+ struct subnet_record *next;
+ struct subnet_record *prev;
+
+ struct work_record *workgrouplist; /* list of workgroups */
+ struct name_record *namelist; /* list of netbios names */
+ struct response_record *responselist; /* list of responses expected */
+
+ struct in_addr bcast_ip;
+ struct in_addr mask_ip;
+ struct in_addr myip;
+ int nmb_sock; /* socket to listen for unicast 137. */
+ int dgram_sock; /* socket to listen for unicast 138. */
+};
+
/* a resource record */
struct res_rec {
struct nmb_name rr_name;
@@ -140,45 +362,76 @@ struct dgram_packet {
list of nmb packets */
struct packet_struct
{
- struct packet_struct *next;
- struct packet_struct *prev;
- struct in_addr ip;
- int port;
- int fd;
- time_t timestamp;
- enum packet_type packet_type;
- union {
- struct nmb_packet nmb;
- struct dgram_packet dgram;
- } packet;
-};
-
-
-/* this defines a list of network interfaces */
-struct net_interface {
- struct net_interface *next;
- struct in_addr ip;
- struct in_addr bcast;
- struct in_addr netmask;
-};
-
-
-/* prototypes */
-void free_nmb_packet(struct nmb_packet *nmb);
-void free_packet(struct packet_struct *packet);
-struct packet_struct *read_packet(int fd,enum packet_type packet_type);
-BOOL send_packet(struct packet_struct *p);
-struct packet_struct *receive_packet(int fd,enum packet_type type,int timeout);
-void make_nmb_name(struct nmb_name *n,char *name,int type,char *this_scope);
-BOOL name_query(int fd,char *name,int name_type,
- BOOL bcast,BOOL recurse,
- struct in_addr to_ip, struct in_addr *ip,void (*fn)());
-BOOL name_status(int fd,char *name,int name_type,BOOL recurse,
- struct in_addr to_ip,char *master,char *rname,
- void (*fn)());
-BOOL send_mailslot_reply(char *mailslot,int fd,char *buf,int len,
- char *srcname,char *dstname,
- int src_type,int dest_type,
- struct in_addr dest_ip,
- struct in_addr src_ip);
-char *namestr(struct nmb_name *n);
+ struct packet_struct *next;
+ struct packet_struct *prev;
+ BOOL locked;
+ struct in_addr ip;
+ int port;
+ int fd;
+ time_t timestamp;
+ enum packet_type packet_type;
+ union {
+ struct nmb_packet nmb;
+ struct dgram_packet dgram;
+ } packet;
+};
+
+/* NETLOGON opcodes */
+#define QUERYFORPDC 7 /* Query for PDC */
+#define QUERYFORPDC_R 12 /* Response to Query for PDC */
+#define SAMLOGON 18
+#define SAMLOGON_R 19
+
+
+/* ids for netbios packet types */
+#define ANN_HostAnnouncement 1
+#define ANN_AnnouncementRequest 2
+#define ANN_Election 8
+#define ANN_GetBackupListReq 9
+#define ANN_GetBackupListResp 10
+#define ANN_BecomeBackup 11
+#define ANN_DomainAnnouncement 12
+#define ANN_MasterAnnouncement 13
+#define ANN_ResetBrowserState 14
+#define ANN_LocalMasterAnnouncement 15
+
+
+/* broadcast packet announcement intervals, in minutes */
+
+/* attempt to add domain logon and domain master names */
+#define CHECK_TIME_ADD_DOM_NAMES 5
+
+/* search for master browsers of workgroups samba knows about,
+ except default */
+#define CHECK_TIME_MST_BROWSE 5
+
+/* request backup browser announcements from other servers */
+#define CHECK_TIME_ANNOUNCE_BACKUP 15
+
+/* request host announcements from other servers: min and max of interval */
+#define CHECK_TIME_MIN_HOST_ANNCE 3
+#define CHECK_TIME_MAX_HOST_ANNCE 12
+
+/* announce as master to WINS server and any Primary Domain Controllers */
+#define CHECK_TIME_MST_ANNOUNCE 15
+
+/* do all remote announcements this often */
+#define REMOTE_ANNOUNCE_INTERVAL 180
+
+/* Types of machine we can announce as */
+#define ANNOUNCE_AS_NT 1
+#define ANNOUNCE_AS_WIN95 2
+#define ANNOUNCE_AS_WFW 3
+
+/* Macro's to enumerate subnets either with or without
+ the WINS subnet. */
+
+extern struct subnet_record *subnetlist;
+extern struct subnet_record *wins_client_subnet;
+
+#define FIRST_SUBNET subnetlist
+#define NEXT_SUBNET_EXCLUDING_WINS(x) ((x)->next)
+#define NEXT_SUBNET_INCLUDING_WINS(x) ( ((x) == wins_client_subnet) ? NULL : \
+ (((x)->next == NULL) ? wins_client_subnet : \
+ (x)->next))
+
diff --git a/source/include/nterr.h b/source/include/nterr.h
new file mode 100644
index 00000000000..92f02612dbc
--- /dev/null
+++ b/source/include/nterr.h
@@ -0,0 +1,505 @@
+/* these are the NT error codes less than 1000. They are here for when
+ we start supporting NT error codes in Samba. They were extracted
+ using a loop in smbclient then printing a netmon sniff to a file */
+
+#define NT_STATUS_UNSUCCESSFUL (1)
+#define NT_STATUS_NOT_IMPLEMENTED (2)
+#define NT_STATUS_INVALID_INFO_CLASS (3)
+#define NT_STATUS_INFO_LENGTH_MISMATCH (4)
+#define NT_STATUS_ACCESS_VIOLATION (5)
+#define NT_STATUS_IN_PAGE_ERROR (6)
+#define NT_STATUS_PAGEFILE_QUOTA (7)
+#define NT_STATUS_INVALID_HANDLE (8)
+#define NT_STATUS_BAD_INITIAL_STACK (9)
+#define NT_STATUS_BAD_INITIAL_PC (10)
+#define NT_STATUS_INVALID_CID (11)
+#define NT_STATUS_TIMER_NOT_CANCELED (12)
+#define NT_STATUS_INVALID_PARAMETER (13)
+#define NT_STATUS_NO_SUCH_DEVICE (14)
+#define NT_STATUS_NO_SUCH_FILE (15)
+#define NT_STATUS_INVALID_DEVICE_REQUEST (16)
+#define NT_STATUS_END_OF_FILE (17)
+#define NT_STATUS_WRONG_VOLUME (18)
+#define NT_STATUS_NO_MEDIA_IN_DEVICE (19)
+#define NT_STATUS_UNRECOGNIZED_MEDIA (20)
+#define NT_STATUS_NONEXISTENT_SECTOR (21)
+#define NT_STATUS_MORE_PROCESSING_REQUIRED (22)
+#define NT_STATUS_NO_MEMORY (23)
+#define NT_STATUS_CONFLICTING_ADDRESSES (24)
+#define NT_STATUS_NOT_MAPPED_VIEW (25)
+#define NT_STATUS_UNABLE_TO_FREE_VM (26)
+#define NT_STATUS_UNABLE_TO_DELETE_SECTION (27)
+#define NT_STATUS_INVALID_SYSTEM_SERVICE (28)
+#define NT_STATUS_ILLEGAL_INSTRUCTION (29)
+#define NT_STATUS_INVALID_LOCK_SEQUENCE (30)
+#define NT_STATUS_INVALID_VIEW_SIZE (31)
+#define NT_STATUS_INVALID_FILE_FOR_SECTION (32)
+#define NT_STATUS_ALREADY_COMMITTED (33)
+#define NT_STATUS_ACCESS_DENIED (34)
+#define NT_STATUS_BUFFER_TOO_SMALL (35)
+#define NT_STATUS_OBJECT_TYPE_MISMATCH (36)
+#define NT_STATUS_NONCONTINUABLE_EXCEPTION (37)
+#define NT_STATUS_INVALID_DISPOSITION (38)
+#define NT_STATUS_UNWIND (39)
+#define NT_STATUS_BAD_STACK (40)
+#define NT_STATUS_INVALID_UNWIND_TARGET (41)
+#define NT_STATUS_NOT_LOCKED (42)
+#define NT_STATUS_PARITY_ERROR (43)
+#define NT_STATUS_UNABLE_TO_DECOMMIT_VM (44)
+#define NT_STATUS_NOT_COMMITTED (45)
+#define NT_STATUS_INVALID_PORT_ATTRIBUTES (46)
+#define NT_STATUS_PORT_MESSAGE_TOO_LONG (47)
+#define NT_STATUS_INVALID_PARAMETER_MIX (48)
+#define NT_STATUS_INVALID_QUOTA_LOWER (49)
+#define NT_STATUS_DISK_CORRUPT_ERROR (50)
+#define NT_STATUS_OBJECT_NAME_INVALID (51)
+#define NT_STATUS_OBJECT_NAME_NOT_FOUND (52)
+#define NT_STATUS_OBJECT_NAME_COLLISION (53)
+#define NT_STATUS_HANDLE_NOT_WAITABLE (54)
+#define NT_STATUS_PORT_DISCONNECTED (55)
+#define NT_STATUS_DEVICE_ALREADY_ATTACHED (56)
+#define NT_STATUS_OBJECT_PATH_INVALID (57)
+#define NT_STATUS_OBJECT_PATH_NOT_FOUND (58)
+#define NT_STATUS_OBJECT_PATH_SYNTAX_BAD (59)
+#define NT_STATUS_DATA_OVERRUN (60)
+#define NT_STATUS_DATA_LATE_ERROR (61)
+#define NT_STATUS_DATA_ERROR (62)
+#define NT_STATUS_CRC_ERROR (63)
+#define NT_STATUS_SECTION_TOO_BIG (64)
+#define NT_STATUS_PORT_CONNECTION_REFUSED (65)
+#define NT_STATUS_INVALID_PORT_HANDLE (66)
+#define NT_STATUS_SHARING_VIOLATION (67)
+#define NT_STATUS_QUOTA_EXCEEDED (68)
+#define NT_STATUS_INVALID_PAGE_PROTECTION (69)
+#define NT_STATUS_MUTANT_NOT_OWNED (70)
+#define NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED (71)
+#define NT_STATUS_PORT_ALREADY_SET (72)
+#define NT_STATUS_SECTION_NOT_IMAGE (73)
+#define NT_STATUS_SUSPEND_COUNT_EXCEEDED (74)
+#define NT_STATUS_THREAD_IS_TERMINATING (75)
+#define NT_STATUS_BAD_WORKING_SET_LIMIT (76)
+#define NT_STATUS_INCOMPATIBLE_FILE_MAP (77)
+#define NT_STATUS_SECTION_PROTECTION (78)
+#define NT_STATUS_EAS_NOT_SUPPORTED (79)
+#define NT_STATUS_EA_TOO_LARGE (80)
+#define NT_STATUS_NONEXISTENT_EA_ENTRY (81)
+#define NT_STATUS_NO_EAS_ON_FILE (82)
+#define NT_STATUS_EA_CORRUPT_ERROR (83)
+#define NT_STATUS_FILE_LOCK_CONFLICT (84)
+#define NT_STATUS_LOCK_NOT_GRANTED (85)
+#define NT_STATUS_DELETE_PENDING (86)
+#define NT_STATUS_CTL_FILE_NOT_SUPPORTED (87)
+#define NT_STATUS_UNKNOWN_REVISION (88)
+#define NT_STATUS_REVISION_MISMATCH (89)
+#define NT_STATUS_INVALID_OWNER (90)
+#define NT_STATUS_INVALID_PRIMARY_GROUP (91)
+#define NT_STATUS_NO_IMPERSONATION_TOKEN (92)
+#define NT_STATUS_CANT_DISABLE_MANDATORY (93)
+#define NT_STATUS_NO_LOGON_SERVERS (94)
+#define NT_STATUS_NO_SUCH_LOGON_SESSION (95)
+#define NT_STATUS_NO_SUCH_PRIVILEGE (96)
+#define NT_STATUS_PRIVILEGE_NOT_HELD (97)
+#define NT_STATUS_INVALID_ACCOUNT_NAME (98)
+#define NT_STATUS_USER_EXISTS (99)
+#define NT_STATUS_NO_SUCH_USER (100)
+#define NT_STATUS_GROUP_EXISTS (101)
+#define NT_STATUS_NO_SUCH_GROUP (102)
+#define NT_STATUS_MEMBER_IN_GROUP (103)
+#define NT_STATUS_MEMBER_NOT_IN_GROUP (104)
+#define NT_STATUS_LAST_ADMIN (105)
+#define NT_STATUS_WRONG_PASSWORD (106)
+#define NT_STATUS_ILL_FORMED_PASSWORD (107)
+#define NT_STATUS_PASSWORD_RESTRICTION (108)
+#define NT_STATUS_LOGON_FAILURE (109)
+#define NT_STATUS_ACCOUNT_RESTRICTION (110)
+#define NT_STATUS_INVALID_LOGON_HOURS (111)
+#define NT_STATUS_INVALID_WORKSTATION (112)
+#define NT_STATUS_PASSWORD_EXPIRED (113)
+#define NT_STATUS_ACCOUNT_DISABLED (114)
+#define NT_STATUS_NONE_MAPPED (115)
+#define NT_STATUS_TOO_MANY_LUIDS_REQUESTED (116)
+#define NT_STATUS_LUIDS_EXHAUSTED (117)
+#define NT_STATUS_INVALID_SUB_AUTHORITY (118)
+#define NT_STATUS_INVALID_ACL (119)
+#define NT_STATUS_INVALID_SID (120)
+#define NT_STATUS_INVALID_SECURITY_DESCR (121)
+#define NT_STATUS_PROCEDURE_NOT_FOUND (122)
+#define NT_STATUS_INVALID_IMAGE_FORMAT (123)
+#define NT_STATUS_NO_TOKEN (124)
+#define NT_STATUS_BAD_INHERITANCE_ACL (125)
+#define NT_STATUS_RANGE_NOT_LOCKED (126)
+#define NT_STATUS_DISK_FULL (127)
+#define NT_STATUS_SERVER_DISABLED (128)
+#define NT_STATUS_SERVER_NOT_DISABLED (129)
+#define NT_STATUS_TOO_MANY_GUIDS_REQUESTED (130)
+#define NT_STATUS_GUIDS_EXHAUSTED (131)
+#define NT_STATUS_INVALID_ID_AUTHORITY (132)
+#define NT_STATUS_AGENTS_EXHAUSTED (133)
+#define NT_STATUS_INVALID_VOLUME_LABEL (134)
+#define NT_STATUS_SECTION_NOT_EXTENDED (135)
+#define NT_STATUS_NOT_MAPPED_DATA (136)
+#define NT_STATUS_RESOURCE_DATA_NOT_FOUND (137)
+#define NT_STATUS_RESOURCE_TYPE_NOT_FOUND (138)
+#define NT_STATUS_RESOURCE_NAME_NOT_FOUND (139)
+#define NT_STATUS_ARRAY_BOUNDS_EXCEEDED (140)
+#define NT_STATUS_FLOAT_DENORMAL_OPERAND (141)
+#define NT_STATUS_FLOAT_DIVIDE_BY_ZERO (142)
+#define NT_STATUS_FLOAT_INEXACT_RESULT (143)
+#define NT_STATUS_FLOAT_INVALID_OPERATION (144)
+#define NT_STATUS_FLOAT_OVERFLOW (145)
+#define NT_STATUS_FLOAT_STACK_CHECK (146)
+#define NT_STATUS_FLOAT_UNDERFLOW (147)
+#define NT_STATUS_INTEGER_DIVIDE_BY_ZERO (148)
+#define NT_STATUS_INTEGER_OVERFLOW (149)
+#define NT_STATUS_PRIVILEGED_INSTRUCTION (150)
+#define NT_STATUS_TOO_MANY_PAGING_FILES (151)
+#define NT_STATUS_FILE_INVALID (152)
+#define NT_STATUS_ALLOTTED_SPACE_EXCEEDED (153)
+#define NT_STATUS_INSUFFICIENT_RESOURCES (154)
+#define NT_STATUS_DFS_EXIT_PATH_FOUND (155)
+#define NT_STATUS_DEVICE_DATA_ERROR (156)
+#define NT_STATUS_DEVICE_NOT_CONNECTED (157)
+#define NT_STATUS_DEVICE_POWER_FAILURE (158)
+#define NT_STATUS_FREE_VM_NOT_AT_BASE (159)
+#define NT_STATUS_MEMORY_NOT_ALLOCATED (160)
+#define NT_STATUS_WORKING_SET_QUOTA (161)
+#define NT_STATUS_MEDIA_WRITE_PROTECTED (162)
+#define NT_STATUS_DEVICE_NOT_READY (163)
+#define NT_STATUS_INVALID_GROUP_ATTRIBUTES (164)
+#define NT_STATUS_BAD_IMPERSONATION_LEVEL (165)
+#define NT_STATUS_CANT_OPEN_ANONYMOUS (166)
+#define NT_STATUS_BAD_VALIDATION_CLASS (167)
+#define NT_STATUS_BAD_TOKEN_TYPE (168)
+#define NT_STATUS_BAD_MASTER_BOOT_RECORD (169)
+#define NT_STATUS_INSTRUCTION_MISALIGNMENT (170)
+#define NT_STATUS_INSTANCE_NOT_AVAILABLE (171)
+#define NT_STATUS_PIPE_NOT_AVAILABLE (172)
+#define NT_STATUS_INVALID_PIPE_STATE (173)
+#define NT_STATUS_PIPE_BUSY (174)
+#define NT_STATUS_ILLEGAL_FUNCTION (175)
+#define NT_STATUS_PIPE_DISCONNECTED (176)
+#define NT_STATUS_PIPE_CLOSING (177)
+#define NT_STATUS_PIPE_CONNECTED (178)
+#define NT_STATUS_PIPE_LISTENING (179)
+#define NT_STATUS_INVALID_READ_MODE (180)
+#define NT_STATUS_IO_TIMEOUT (181)
+#define NT_STATUS_FILE_FORCED_CLOSED (182)
+#define NT_STATUS_PROFILING_NOT_STARTED (183)
+#define NT_STATUS_PROFILING_NOT_STOPPED (184)
+#define NT_STATUS_COULD_NOT_INTERPRET (185)
+#define NT_STATUS_FILE_IS_A_DIRECTORY (186)
+#define NT_STATUS_NOT_SUPPORTED (187)
+#define NT_STATUS_REMOTE_NOT_LISTENING (188)
+#define NT_STATUS_DUPLICATE_NAME (189)
+#define NT_STATUS_BAD_NETWORK_PATH (190)
+#define NT_STATUS_NETWORK_BUSY (191)
+#define NT_STATUS_DEVICE_DOES_NOT_EXIST (192)
+#define NT_STATUS_TOO_MANY_COMMANDS (193)
+#define NT_STATUS_ADAPTER_HARDWARE_ERROR (194)
+#define NT_STATUS_INVALID_NETWORK_RESPONSE (195)
+#define NT_STATUS_UNEXPECTED_NETWORK_ERROR (196)
+#define NT_STATUS_BAD_REMOTE_ADAPTER (197)
+#define NT_STATUS_PRINT_QUEUE_FULL (198)
+#define NT_STATUS_NO_SPOOL_SPACE (199)
+#define NT_STATUS_PRINT_CANCELLED (200)
+#define NT_STATUS_NETWORK_NAME_DELETED (201)
+#define NT_STATUS_NETWORK_ACCESS_DENIED (202)
+#define NT_STATUS_BAD_DEVICE_TYPE (203)
+#define NT_STATUS_BAD_NETWORK_NAME (204)
+#define NT_STATUS_TOO_MANY_NAMES (205)
+#define NT_STATUS_TOO_MANY_SESSIONS (206)
+#define NT_STATUS_SHARING_PAUSED (207)
+#define NT_STATUS_REQUEST_NOT_ACCEPTED (208)
+#define NT_STATUS_REDIRECTOR_PAUSED (209)
+#define NT_STATUS_NET_WRITE_FAULT (210)
+#define NT_STATUS_PROFILING_AT_LIMIT (211)
+#define NT_STATUS_NOT_SAME_DEVICE (212)
+#define NT_STATUS_FILE_RENAMED (213)
+#define NT_STATUS_VIRTUAL_CIRCUIT_CLOSED (214)
+#define NT_STATUS_NO_SECURITY_ON_OBJECT (215)
+#define NT_STATUS_CANT_WAIT (216)
+#define NT_STATUS_PIPE_EMPTY (217)
+#define NT_STATUS_CANT_ACCESS_DOMAIN_INFO (218)
+#define NT_STATUS_CANT_TERMINATE_SELF (219)
+#define NT_STATUS_INVALID_SERVER_STATE (220)
+#define NT_STATUS_INVALID_DOMAIN_STATE (221)
+#define NT_STATUS_INVALID_DOMAIN_ROLE (222)
+#define NT_STATUS_NO_SUCH_DOMAIN (223)
+#define NT_STATUS_DOMAIN_EXISTS (224)
+#define NT_STATUS_DOMAIN_LIMIT_EXCEEDED (225)
+#define NT_STATUS_OPLOCK_NOT_GRANTED (226)
+#define NT_STATUS_INVALID_OPLOCK_PROTOCOL (227)
+#define NT_STATUS_INTERNAL_DB_CORRUPTION (228)
+#define NT_STATUS_INTERNAL_ERROR (229)
+#define NT_STATUS_GENERIC_NOT_MAPPED (230)
+#define NT_STATUS_BAD_DESCRIPTOR_FORMAT (231)
+#define NT_STATUS_INVALID_USER_BUFFER (232)
+#define NT_STATUS_UNEXPECTED_IO_ERROR (233)
+#define NT_STATUS_UNEXPECTED_MM_CREATE_ERR (234)
+#define NT_STATUS_UNEXPECTED_MM_MAP_ERROR (235)
+#define NT_STATUS_UNEXPECTED_MM_EXTEND_ERR (236)
+#define NT_STATUS_NOT_LOGON_PROCESS (237)
+#define NT_STATUS_LOGON_SESSION_EXISTS (238)
+#define NT_STATUS_INVALID_PARAMETER_1 (239)
+#define NT_STATUS_INVALID_PARAMETER_2 (240)
+#define NT_STATUS_INVALID_PARAMETER_3 (241)
+#define NT_STATUS_INVALID_PARAMETER_4 (242)
+#define NT_STATUS_INVALID_PARAMETER_5 (243)
+#define NT_STATUS_INVALID_PARAMETER_6 (244)
+#define NT_STATUS_INVALID_PARAMETER_7 (245)
+#define NT_STATUS_INVALID_PARAMETER_8 (246)
+#define NT_STATUS_INVALID_PARAMETER_9 (247)
+#define NT_STATUS_INVALID_PARAMETER_10 (248)
+#define NT_STATUS_INVALID_PARAMETER_11 (249)
+#define NT_STATUS_INVALID_PARAMETER_12 (250)
+#define NT_STATUS_REDIRECTOR_NOT_STARTED (251)
+#define NT_STATUS_REDIRECTOR_STARTED (252)
+#define NT_STATUS_STACK_OVERFLOW (253)
+#define NT_STATUS_NO_SUCH_PACKAGE (254)
+#define NT_STATUS_BAD_FUNCTION_TABLE (255)
+#define NT_STATUS_DIRECTORY_NOT_EMPTY (257)
+#define NT_STATUS_FILE_CORRUPT_ERROR (258)
+#define NT_STATUS_NOT_A_DIRECTORY (259)
+#define NT_STATUS_BAD_LOGON_SESSION_STATE (260)
+#define NT_STATUS_LOGON_SESSION_COLLISION (261)
+#define NT_STATUS_NAME_TOO_LONG (262)
+#define NT_STATUS_FILES_OPEN (263)
+#define NT_STATUS_CONNECTION_IN_USE (264)
+#define NT_STATUS_MESSAGE_NOT_FOUND (265)
+#define NT_STATUS_PROCESS_IS_TERMINATING (266)
+#define NT_STATUS_INVALID_LOGON_TYPE (267)
+#define NT_STATUS_NO_GUID_TRANSLATION (268)
+#define NT_STATUS_CANNOT_IMPERSONATE (269)
+#define NT_STATUS_IMAGE_ALREADY_LOADED (270)
+#define NT_STATUS_ABIOS_NOT_PRESENT (271)
+#define NT_STATUS_ABIOS_LID_NOT_EXIST (272)
+#define NT_STATUS_ABIOS_LID_ALREADY_OWNED (273)
+#define NT_STATUS_ABIOS_NOT_LID_OWNER (274)
+#define NT_STATUS_ABIOS_INVALID_COMMAND (275)
+#define NT_STATUS_ABIOS_INVALID_LID (276)
+#define NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE (277)
+#define NT_STATUS_ABIOS_INVALID_SELECTOR (278)
+#define NT_STATUS_NO_LDT (279)
+#define NT_STATUS_INVALID_LDT_SIZE (280)
+#define NT_STATUS_INVALID_LDT_OFFSET (281)
+#define NT_STATUS_INVALID_LDT_DESCRIPTOR (282)
+#define NT_STATUS_INVALID_IMAGE_NE_FORMAT (283)
+#define NT_STATUS_RXACT_INVALID_STATE (284)
+#define NT_STATUS_RXACT_COMMIT_FAILURE (285)
+#define NT_STATUS_MAPPED_FILE_SIZE_ZERO (286)
+#define NT_STATUS_TOO_MANY_OPENED_FILES (287)
+#define NT_STATUS_CANCELLED (288)
+#define NT_STATUS_CANNOT_DELETE (289)
+#define NT_STATUS_INVALID_COMPUTER_NAME (290)
+#define NT_STATUS_FILE_DELETED (291)
+#define NT_STATUS_SPECIAL_ACCOUNT (292)
+#define NT_STATUS_SPECIAL_GROUP (293)
+#define NT_STATUS_SPECIAL_USER (294)
+#define NT_STATUS_MEMBERS_PRIMARY_GROUP (295)
+#define NT_STATUS_FILE_CLOSED (296)
+#define NT_STATUS_TOO_MANY_THREADS (297)
+#define NT_STATUS_THREAD_NOT_IN_PROCESS (298)
+#define NT_STATUS_TOKEN_ALREADY_IN_USE (299)
+#define NT_STATUS_PAGEFILE_QUOTA_EXCEEDED (300)
+#define NT_STATUS_COMMITMENT_LIMIT (301)
+#define NT_STATUS_INVALID_IMAGE_LE_FORMAT (302)
+#define NT_STATUS_INVALID_IMAGE_NOT_MZ (303)
+#define NT_STATUS_INVALID_IMAGE_PROTECT (304)
+#define NT_STATUS_INVALID_IMAGE_WIN_16 (305)
+#define NT_STATUS_LOGON_SERVER_CONFLICT (306)
+#define NT_STATUS_TIME_DIFFERENCE_AT_DC (307)
+#define NT_STATUS_SYNCHRONIZATION_REQUIRED (308)
+#define NT_STATUS_DLL_NOT_FOUND (309)
+#define NT_STATUS_OPEN_FAILED (310)
+#define NT_STATUS_IO_PRIVILEGE_FAILED (311)
+#define NT_STATUS_ORDINAL_NOT_FOUND (312)
+#define NT_STATUS_ENTRYPOINT_NOT_FOUND (313)
+#define NT_STATUS_CONTROL_C_EXIT (314)
+#define NT_STATUS_LOCAL_DISCONNECT (315)
+#define NT_STATUS_REMOTE_DISCONNECT (316)
+#define NT_STATUS_REMOTE_RESOURCES (317)
+#define NT_STATUS_LINK_FAILED (318)
+#define NT_STATUS_LINK_TIMEOUT (319)
+#define NT_STATUS_INVALID_CONNECTION (320)
+#define NT_STATUS_INVALID_ADDRESS (321)
+#define NT_STATUS_DLL_INIT_FAILED (322)
+#define NT_STATUS_MISSING_SYSTEMFILE (323)
+#define NT_STATUS_UNHANDLED_EXCEPTION (324)
+#define NT_STATUS_APP_INIT_FAILURE (325)
+#define NT_STATUS_PAGEFILE_CREATE_FAILED (326)
+#define NT_STATUS_NO_PAGEFILE (327)
+#define NT_STATUS_INVALID_LEVEL (328)
+#define NT_STATUS_WRONG_PASSWORD_CORE (329)
+#define NT_STATUS_ILLEGAL_FLOAT_CONTEXT (330)
+#define NT_STATUS_PIPE_BROKEN (331)
+#define NT_STATUS_REGISTRY_CORRUPT (332)
+#define NT_STATUS_REGISTRY_IO_FAILED (333)
+#define NT_STATUS_NO_EVENT_PAIR (334)
+#define NT_STATUS_UNRECOGNIZED_VOLUME (335)
+#define NT_STATUS_SERIAL_NO_DEVICE_INITED (336)
+#define NT_STATUS_NO_SUCH_ALIAS (337)
+#define NT_STATUS_MEMBER_NOT_IN_ALIAS (338)
+#define NT_STATUS_MEMBER_IN_ALIAS (339)
+#define NT_STATUS_ALIAS_EXISTS (340)
+#define NT_STATUS_LOGON_NOT_GRANTED (341)
+#define NT_STATUS_TOO_MANY_SECRETS (342)
+#define NT_STATUS_SECRET_TOO_LONG (343)
+#define NT_STATUS_INTERNAL_DB_ERROR (344)
+#define NT_STATUS_FULLSCREEN_MODE (345)
+#define NT_STATUS_TOO_MANY_CONTEXT_IDS (346)
+#define NT_STATUS_LOGON_TYPE_NOT_GRANTED (347)
+#define NT_STATUS_NOT_REGISTRY_FILE (348)
+#define NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED (349)
+#define NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR (350)
+#define NT_STATUS_FT_MISSING_MEMBER (351)
+#define NT_STATUS_ILL_FORMED_SERVICE_ENTRY (352)
+#define NT_STATUS_ILLEGAL_CHARACTER (353)
+#define NT_STATUS_UNMAPPABLE_CHARACTER (354)
+#define NT_STATUS_UNDEFINED_CHARACTER (355)
+#define NT_STATUS_FLOPPY_VOLUME (356)
+#define NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND (357)
+#define NT_STATUS_FLOPPY_WRONG_CYLINDER (358)
+#define NT_STATUS_FLOPPY_UNKNOWN_ERROR (359)
+#define NT_STATUS_FLOPPY_BAD_REGISTERS (360)
+#define NT_STATUS_DISK_RECALIBRATE_FAILED (361)
+#define NT_STATUS_DISK_OPERATION_FAILED (362)
+#define NT_STATUS_DISK_RESET_FAILED (363)
+#define NT_STATUS_SHARED_IRQ_BUSY (364)
+#define NT_STATUS_FT_ORPHANING (365)
+#define NT_STATUS_PARTITION_FAILURE (370)
+#define NT_STATUS_INVALID_BLOCK_LENGTH (371)
+#define NT_STATUS_DEVICE_NOT_PARTITIONED (372)
+#define NT_STATUS_UNABLE_TO_LOCK_MEDIA (373)
+#define NT_STATUS_UNABLE_TO_UNLOAD_MEDIA (374)
+#define NT_STATUS_EOM_OVERFLOW (375)
+#define NT_STATUS_NO_MEDIA (376)
+#define NT_STATUS_NO_SUCH_MEMBER (378)
+#define NT_STATUS_INVALID_MEMBER (379)
+#define NT_STATUS_KEY_DELETED (380)
+#define NT_STATUS_NO_LOG_SPACE (381)
+#define NT_STATUS_TOO_MANY_SIDS (382)
+#define NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED (383)
+#define NT_STATUS_KEY_HAS_CHILDREN (384)
+#define NT_STATUS_CHILD_MUST_BE_VOLATILE (385)
+#define NT_STATUS_DEVICE_CONFIGURATION_ERROR (386)
+#define NT_STATUS_DRIVER_INTERNAL_ERROR (387)
+#define NT_STATUS_INVALID_DEVICE_STATE (388)
+#define NT_STATUS_IO_DEVICE_ERROR (389)
+#define NT_STATUS_DEVICE_PROTOCOL_ERROR (390)
+#define NT_STATUS_BACKUP_CONTROLLER (391)
+#define NT_STATUS_LOG_FILE_FULL (392)
+#define NT_STATUS_TOO_LATE (393)
+#define NT_STATUS_NO_TRUST_LSA_SECRET (394)
+#define NT_STATUS_NO_TRUST_SAM_ACCOUNT (395)
+#define NT_STATUS_TRUSTED_DOMAIN_FAILURE (396)
+#define NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE (397)
+#define NT_STATUS_EVENTLOG_FILE_CORRUPT (398)
+#define NT_STATUS_EVENTLOG_CANT_START (399)
+#define NT_STATUS_TRUST_FAILURE (400)
+#define NT_STATUS_MUTANT_LIMIT_EXCEEDED (401)
+#define NT_STATUS_NETLOGON_NOT_STARTED (402)
+#define NT_STATUS_ACCOUNT_EXPIRED (403)
+#define NT_STATUS_POSSIBLE_DEADLOCK (404)
+#define NT_STATUS_NETWORK_CREDENTIAL_CONFLICT (405)
+#define NT_STATUS_REMOTE_SESSION_LIMIT (406)
+#define NT_STATUS_EVENTLOG_FILE_CHANGED (407)
+#define NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT (408)
+#define NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT (409)
+#define NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT (410)
+#define NT_STATUS_DOMAIN_TRUST_INCONSISTENT (411)
+#define NT_STATUS_FS_DRIVER_REQUIRED (412)
+#define NT_STATUS_NO_USER_SESSION_KEY (514)
+#define NT_STATUS_USER_SESSION_DELETED (515)
+#define NT_STATUS_RESOURCE_LANG_NOT_FOUND (516)
+#define NT_STATUS_INSUFF_SERVER_RESOURCES (517)
+#define NT_STATUS_INVALID_BUFFER_SIZE (518)
+#define NT_STATUS_INVALID_ADDRESS_COMPONENT (519)
+#define NT_STATUS_INVALID_ADDRESS_WILDCARD (520)
+#define NT_STATUS_TOO_MANY_ADDRESSES (521)
+#define NT_STATUS_ADDRESS_ALREADY_EXISTS (522)
+#define NT_STATUS_ADDRESS_CLOSED (523)
+#define NT_STATUS_CONNECTION_DISCONNECTED (524)
+#define NT_STATUS_CONNECTION_RESET (525)
+#define NT_STATUS_TOO_MANY_NODES (526)
+#define NT_STATUS_TRANSACTION_ABORTED (527)
+#define NT_STATUS_TRANSACTION_TIMED_OUT (528)
+#define NT_STATUS_TRANSACTION_NO_RELEASE (529)
+#define NT_STATUS_TRANSACTION_NO_MATCH (530)
+#define NT_STATUS_TRANSACTION_RESPONDED (531)
+#define NT_STATUS_TRANSACTION_INVALID_ID (532)
+#define NT_STATUS_TRANSACTION_INVALID_TYPE (533)
+#define NT_STATUS_NOT_SERVER_SESSION (534)
+#define NT_STATUS_NOT_CLIENT_SESSION (535)
+#define NT_STATUS_CANNOT_LOAD_REGISTRY_FILE (536)
+#define NT_STATUS_DEBUG_ATTACH_FAILED (537)
+#define NT_STATUS_SYSTEM_PROCESS_TERMINATED (538)
+#define NT_STATUS_DATA_NOT_ACCEPTED (539)
+#define NT_STATUS_NO_BROWSER_SERVERS_FOUND (540)
+#define NT_STATUS_VDM_HARD_ERROR (541)
+#define NT_STATUS_DRIVER_CANCEL_TIMEOUT (542)
+#define NT_STATUS_REPLY_MESSAGE_MISMATCH (543)
+#define NT_STATUS_MAPPED_ALIGNMENT (544)
+#define NT_STATUS_IMAGE_CHECKSUM_MISMATCH (545)
+#define NT_STATUS_LOST_WRITEBEHIND_DATA (546)
+#define NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID (547)
+#define NT_STATUS_PASSWORD_MUST_CHANGE (548)
+#define NT_STATUS_NOT_FOUND (549)
+#define NT_STATUS_NOT_TINY_STREAM (550)
+#define NT_STATUS_RECOVERY_FAILURE (551)
+#define NT_STATUS_STACK_OVERFLOW_READ (552)
+#define NT_STATUS_FAIL_CHECK (553)
+#define NT_STATUS_DUPLICATE_OBJECTID (554)
+#define NT_STATUS_OBJECTID_EXISTS (555)
+#define NT_STATUS_CONVERT_TO_LARGE (556)
+#define NT_STATUS_RETRY (557)
+#define NT_STATUS_FOUND_OUT_OF_SCOPE (558)
+#define NT_STATUS_ALLOCATE_BUCKET (559)
+#define NT_STATUS_PROPSET_NOT_FOUND (560)
+#define NT_STATUS_MARSHALL_OVERFLOW (561)
+#define NT_STATUS_INVALID_VARIANT (562)
+#define NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND (563)
+#define NT_STATUS_ACCOUNT_LOCKED_OUT (564)
+#define NT_STATUS_HANDLE_NOT_CLOSABLE (565)
+#define NT_STATUS_CONNECTION_REFUSED (566)
+#define NT_STATUS_GRACEFUL_DISCONNECT (567)
+#define NT_STATUS_ADDRESS_ALREADY_ASSOCIATED (568)
+#define NT_STATUS_ADDRESS_NOT_ASSOCIATED (569)
+#define NT_STATUS_CONNECTION_INVALID (570)
+#define NT_STATUS_CONNECTION_ACTIVE (571)
+#define NT_STATUS_NETWORK_UNREACHABLE (572)
+#define NT_STATUS_HOST_UNREACHABLE (573)
+#define NT_STATUS_PROTOCOL_UNREACHABLE (574)
+#define NT_STATUS_PORT_UNREACHABLE (575)
+#define NT_STATUS_REQUEST_ABORTED (576)
+#define NT_STATUS_CONNECTION_ABORTED (577)
+#define NT_STATUS_BAD_COMPRESSION_BUFFER (578)
+#define NT_STATUS_USER_MAPPED_FILE (579)
+#define NT_STATUS_AUDIT_FAILED (580)
+#define NT_STATUS_TIMER_RESOLUTION_NOT_SET (581)
+#define NT_STATUS_CONNECTION_COUNT_LIMIT (582)
+#define NT_STATUS_LOGIN_TIME_RESTRICTION (583)
+#define NT_STATUS_LOGIN_WKSTA_RESTRICTION (584)
+#define NT_STATUS_IMAGE_MP_UP_MISMATCH (585)
+#define NT_STATUS_INSUFFICIENT_LOGON_INFO (592)
+#define NT_STATUS_BAD_DLL_ENTRYPOINT (593)
+#define NT_STATUS_BAD_SERVICE_ENTRYPOINT (594)
+#define NT_STATUS_LPC_REPLY_LOST (595)
+#define NT_STATUS_IP_ADDRESS_CONFLICT1 (596)
+#define NT_STATUS_IP_ADDRESS_CONFLICT2 (597)
+#define NT_STATUS_REGISTRY_QUOTA_LIMIT (598)
+#define NT_STATUS_PATH_NOT_COVERED (599)
+#define NT_STATUS_NO_CALLBACK_ACTIVE (600)
+#define NT_STATUS_LICENSE_QUOTA_EXCEEDED (601)
+#define NT_STATUS_PWD_TOO_SHORT (602)
+#define NT_STATUS_PWD_TOO_RECENT (603)
+#define NT_STATUS_PWD_HISTORY_CONFLICT (604)
+#define NT_STATUS_PLUGPLAY_NO_DEVICE (606)
+#define NT_STATUS_UNSUPPORTED_COMPRESSION (607)
+#define NT_STATUS_INVALID_HW_PROFILE (608)
+#define NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH (609)
+#define NT_STATUS_DRIVER_ORDINAL_NOT_FOUND (610)
+#define NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND (611)
+#define NT_STATUS_RESOURCE_NOT_OWNED (612)
+#define NT_STATUS_TOO_MANY_LINKS (613)
+#define NT_STATUS_QUOTA_LIST_INCONSISTENT (614)
+#define NT_STATUS_FILE_IS_OFFLINE (615)
diff --git a/source/include/proto.h b/source/include/proto.h
new file mode 100644
index 00000000000..ee7bd41dbdc
--- /dev/null
+++ b/source/include/proto.h
@@ -0,0 +1,1265 @@
+/* This file is automatically generated with "make proto". DO NOT EDIT */
+
+
+/*The following definitions come from access.c */
+
+BOOL check_access(int snum);
+BOOL allow_access(char *deny_list,char *allow_list,char *cname,char *caddr);
+
+/*The following definitions come from asyncdns.c */
+
+int asyncdns_fd(void);
+void start_async_dns(void);
+void run_dns_queue(void);
+BOOL queue_dns_query(struct packet_struct *p,struct nmb_name *question,
+ struct name_record **n);
+BOOL queue_dns_query(struct packet_struct *p,struct nmb_name *question,
+ struct name_record **n);
+
+/*The following definitions come from charcnv.c */
+
+char *unix2dos_format(char *str,BOOL overwrite);
+char *dos2unix_format(char *str, BOOL overwrite);
+int interpret_character_set(char *str, int def);
+
+/*The following definitions come from charset.c */
+
+void charset_initialise();
+void codepage_initialise(int client_codepage);
+void add_char_string(char *s);
+
+/*The following definitions come from chgpasswd.c */
+
+BOOL chat_with_program(char *passwordprogram,char *name,char *chatsequence);
+BOOL chgpasswd(char *name,char *oldpass,char *newpass);
+BOOL chgpasswd(char *name,char *oldpass,char *newpass);
+
+/*The following definitions come from client.c */
+
+void cli_smb_close(char *inbuf, char *outbuf, int clnt_fd, int c_num, int f_num);
+void do_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir);
+void cmd_help(void);
+
+/*The following definitions come from clientgen.c */
+
+BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation);
+BOOL cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
+ void (*fn)(char *, uint32, char *));
+BOOL cli_session_setup(struct cli_state *cli,
+ char *user,
+ char *pass, int passlen,
+ char *ntpass, int ntpasslen,
+ char *workgroup);
+BOOL cli_send_tconX(struct cli_state *cli,
+ char *share, char *dev, char *pword, int passlen);
+BOOL cli_tdis(struct cli_state *cli);
+BOOL cli_negprot(struct cli_state *cli);
+BOOL cli_session_request(struct cli_state *cli, char *host, int name_type,
+ char *myname);
+BOOL cli_connect(struct cli_state *cli, char *host, struct in_addr *ip);
+BOOL cli_initialise(struct cli_state *cli);
+void cli_shutdown(struct cli_state *cli);
+
+/*The following definitions come from clientutil.c */
+
+void cli_setup_pkt(char *outbuf);
+BOOL cli_call_api(char *pipe_name, int prcnt,int drcnt, int srcnt,
+ int mprcnt,int mdrcnt,
+ int *rprcnt,int *rdrcnt,
+ char *param,char *data, uint16 *setup,
+ char **rparam,char **rdata);
+BOOL cli_receive_trans_response(char *inbuf,int trans,
+ int *data_len,int *param_len,
+ char **data,char **param);
+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_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_open_sockets(int port );
+BOOL cli_reopen_connection(char *inbuf,char *outbuf);
+char *smb_errstr(char *inbuf);
+
+/*The following definitions come from clitar.c */
+
+int padit(char *buf, int bufsize, int padsize);
+void cmd_block(void);
+void cmd_tarmode(void);
+void cmd_setmode(void);
+void cmd_tar(char *inbuf, char *outbuf);
+int process_tar(char *inbuf, char *outbuf);
+int clipfind(char **aret, int ret, char *tok);
+int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind);
+
+/*The following definitions come from credentials.c */
+
+void cred_session_key(DOM_CHAL *clnt_chal, DOM_CHAL *srv_chal, char *pass,
+ uint32 session_key[2]);
+void cred_create(uint32 session_key[2], DOM_CHAL *stor_cred, UTIME timestamp,
+ DOM_CHAL *cred);
+int cred_assert(DOM_CHAL *cred, uint32 session_key[2], DOM_CHAL *stored_cred,
+ UTIME timestamp);
+BOOL clnt_deal_with_creds(uint32 sess_key[2],
+ DOM_CRED *sto_clnt_cred, DOM_CRED *rcv_srv_cred);
+BOOL deal_with_creds(uint32 sess_key[2],
+ DOM_CRED *sto_clnt_cred,
+ DOM_CRED *rcv_clnt_cred, DOM_CRED *rtn_srv_cred);
+
+/*The following definitions come from dir.c */
+
+void init_dptrs(void);
+char *dptr_path(int key);
+char *dptr_wcard(int key);
+BOOL dptr_set_wcard(int key, char *wcard);
+BOOL dptr_set_attr(int key, uint16 attr);
+uint16 dptr_attr(int key);
+void dptr_close(int key);
+void dptr_closecnum(int cnum);
+void dptr_idlecnum(int cnum);
+void dptr_closepath(char *path,int pid);
+int dptr_create(int cnum,char *path, BOOL expect_close,int pid);
+BOOL dptr_fill(char *buf1,unsigned int key);
+BOOL dptr_zero(char *buf);
+void *dptr_fetch(char *buf,int *num);
+void *dptr_fetch_lanman2(char *params,int dptr_num);
+BOOL dir_check_ftype(int cnum,int mode,struct stat *st,int dirtype);
+BOOL get_dir_entry(int cnum,char *mask,int dirtype,char *fname,int *size,int *mode,time_t *date,BOOL check_descend);
+void *OpenDir(int cnum, char *name, BOOL use_veto);
+void CloseDir(void *p);
+char *ReadDirName(void *p);
+BOOL SeekDir(void *p,int pos);
+int TellDir(void *p);
+void DirCacheAdd( char *path, char *name, char *dname, int snum );
+char *DirCacheCheck( char *path, char *name, int snum );
+void DirCacheFlush( int snum );
+
+/*The following definitions come from fault.c */
+
+void fault_setup(void (*fn)());
+
+/*The following definitions come from getsmbpass.c */
+
+char *getsmbpass(char *prompt) ;
+
+/*The following definitions come from interface.c */
+
+void load_interfaces(void);
+void iface_set_default(char *ip,char *bcast,char *nmask);
+BOOL ismyip(struct in_addr ip);
+BOOL ismybcast(struct in_addr bcast);
+BOOL is_local_net(struct in_addr from);
+int iface_count(void);
+struct in_addr *iface_n_ip(int n);
+struct in_addr *iface_bcast(struct in_addr ip);
+struct in_addr *iface_nmask(struct in_addr ip);
+struct in_addr *iface_ip(struct in_addr ip);
+
+/*The following definitions come from ipc.c */
+
+int get_printerdrivernumber(int snum);
+int reply_trans(char *inbuf,char *outbuf);
+
+/*The following definitions come from kanji.c */
+
+char *sj_strtok(char *s1, char *s2);
+char *sj_strstr(char *s1, char *s2);
+char *sj_strchr (char *s, int c);
+char *sj_strrchr(char *s, int c);
+int interpret_coding_system(char *str, int def);
+
+/*The following definitions come from loadparm.c */
+
+char *lp_string(char *s);
+char *lp_logfile(void);
+char *lp_smbrun(void);
+char *lp_configfile(void);
+char *lp_smb_passwd_file(void);
+char *lp_serverstring(void);
+char *lp_printcapname(void);
+char *lp_lockdir(void);
+char *lp_rootdir(void);
+char *lp_defaultservice(void);
+char *lp_msg_command(void);
+char *lp_dfree_command(void);
+char *lp_hosts_equiv(void);
+char *lp_auto_services(void);
+char *lp_passwd_program(void);
+char *lp_passwd_chat(void);
+char *lp_passwordserver(void);
+char *lp_workgroup(void);
+char *lp_domain_controller(void);
+char *lp_username_map(void);
+char *lp_character_set(void);
+char *lp_logon_script(void);
+char *lp_logon_path(void);
+char *lp_logon_drive(void);
+char *lp_logon_home(void);
+char *lp_remote_announce(void);
+char *lp_wins_server(void);
+char *lp_interfaces(void);
+char *lp_socket_address(void);
+char *lp_nis_home_map_name(void);
+char *lp_announce_version(void);
+char *lp_netbios_aliases(void);
+char *lp_driverfile(void);
+char *lp_domain_sid(void);
+char *lp_domain_other_sids(void);
+char *lp_domain_groups(void);
+char *lp_domain_admin_users(void);
+char *lp_domain_guest_users(void);
+BOOL lp_dns_proxy(void);
+BOOL lp_wins_support(void);
+BOOL lp_wins_proxy(void);
+BOOL lp_local_master(void);
+BOOL lp_domain_master(void);
+BOOL lp_domain_logons(void);
+BOOL lp_preferred_master(void);
+BOOL lp_load_printers(void);
+BOOL lp_use_rhosts(void);
+BOOL lp_getwdcache(void);
+BOOL lp_readprediction(void);
+BOOL lp_readbmpx(void);
+BOOL lp_readraw(void);
+BOOL lp_writeraw(void);
+BOOL lp_null_passwords(void);
+BOOL lp_strip_dot(void);
+BOOL lp_encrypted_passwords(void);
+BOOL lp_syslog_only(void);
+BOOL lp_browse_list(void);
+BOOL lp_unix_realname(void);
+BOOL lp_nis_home_map(void);
+BOOL lp_time_server(void);
+BOOL lp_bind_interfaces_only(void);
+int lp_os_level(void);
+int lp_max_ttl(void);
+int lp_max_log_size(void);
+int lp_mangledstack(void);
+int lp_maxxmit(void);
+int lp_maxmux(void);
+int lp_maxpacket(void);
+int lp_keepalive(void);
+int lp_passwordlevel(void);
+int lp_usernamelevel(void);
+int lp_readsize(void);
+int lp_shmem_size(void);
+int lp_deadtime(void);
+int lp_maxprotocol(void);
+int lp_security(void);
+int lp_printing(void);
+int lp_maxdisksize(void);
+int lp_lpqcachetime(void);
+int lp_syslog(void);
+int lp_client_code_page(void);
+int lp_announce_as(void);
+char *lp_preexec(int );
+char *lp_postexec(int );
+char *lp_rootpreexec(int );
+char *lp_rootpostexec(int );
+char *lp_servicename(int );
+char *lp_pathname(int );
+char *lp_dontdescend(int );
+char *lp_username(int );
+char *lp_guestaccount(int );
+char *lp_invalid_users(int );
+char *lp_valid_users(int );
+char *lp_admin_users(int );
+char *lp_printcommand(int );
+char *lp_lpqcommand(int );
+char *lp_lprmcommand(int );
+char *lp_lppausecommand(int );
+char *lp_lpresumecommand(int );
+char *lp_printername(int );
+char *lp_printerdriver(int );
+char *lp_hostsallow(int );
+char *lp_hostsdeny(int );
+char *lp_magicscript(int );
+char *lp_magicoutput(int );
+char *lp_comment(int );
+char *lp_force_user(int );
+char *lp_force_group(int );
+char *lp_readlist(int );
+char *lp_writelist(int );
+char *lp_volume(int );
+char *lp_mangled_map(int );
+char *lp_veto_files(int );
+char *lp_hide_files(int );
+char *lp_driverlocation(int );
+BOOL lp_alternate_permissions(int );
+BOOL lp_revalidate(int );
+BOOL lp_casesensitive(int );
+BOOL lp_preservecase(int );
+BOOL lp_shortpreservecase(int );
+BOOL lp_casemangle(int );
+BOOL lp_status(int );
+BOOL lp_hide_dot_files(int );
+BOOL lp_browseable(int );
+BOOL lp_readonly(int );
+BOOL lp_no_set_dir(int );
+BOOL lp_guest_ok(int );
+BOOL lp_guest_only(int );
+BOOL lp_print_ok(int );
+BOOL lp_postscript(int );
+BOOL lp_map_hidden(int );
+BOOL lp_map_archive(int );
+BOOL lp_locking(int );
+BOOL lp_strict_locking(int );
+BOOL lp_share_modes(int );
+BOOL lp_oplocks(int );
+BOOL lp_onlyuser(int );
+BOOL lp_manglednames(int );
+BOOL lp_widelinks(int );
+BOOL lp_symlinks(int );
+BOOL lp_syncalways(int );
+BOOL lp_map_system(int );
+BOOL lp_delete_readonly(int );
+BOOL lp_fake_oplocks(int );
+BOOL lp_recursive_veto_delete(int );
+BOOL lp_dos_filetimes(int );
+int lp_create_mode(int );
+int lp_force_create_mode(int );
+int lp_dir_mode(int );
+int lp_force_dir_mode(int );
+int lp_max_connections(int );
+int lp_defaultcase(int );
+int lp_minprintspace(int );
+char lp_magicchar(int );
+BOOL lp_add_home(char *pszHomename, int iDefaultService, char *pszHomedir);
+int lp_add_service(char *pszService, int iDefaultService);
+BOOL lp_add_printer(char *pszPrintername, int iDefaultService);
+BOOL lp_file_list_changed(void);
+BOOL lp_do_parameter(int snum, char *pszParmName, char *pszParmValue);
+int lp_next_parameter(int snum, int *i, char *label,
+ char *value, int allparameters);
+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(FILE *f);
+int lp_servicenumber(char *pszServiceName);
+char *volume_label(int snum);
+void lp_rename_service(int snum, char *new_name);
+void lp_remove_service(int snum);
+void lp_copy_service(int snum, char *new_name);
+int lp_default_server_announce(void);
+int lp_major_announce_version(void);
+int lp_minor_announce_version(void);
+
+/*The following definitions come from locking.c */
+
+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);
+BOOL locking_init(int read_only);
+BOOL locking_end(void);
+BOOL lock_share_entry(int cnum, uint32 dev, uint32 inode, int *ptok);
+BOOL unlock_share_entry(int cnum, uint32 dev, uint32 inode, int token);
+int get_share_modes(int cnum, int token, uint32 dev, uint32 inode,
+ share_mode_entry **shares);
+void del_share_mode(int token, int fnum);
+BOOL set_share_mode(int token, int fnum, uint16 port, uint16 op_type);
+BOOL remove_share_oplock(int fnum, int token);
+int share_mode_forall(void (*fn)(share_mode_entry *, char *));
+void share_status(FILE *f);
+
+/*The following definitions come from locking_shm.c */
+
+struct share_ops *locking_shm_init(int ronly);
+
+/*The following definitions come from locking_slow.c */
+
+struct share_ops *locking_slow_init(int ronly);
+
+/*The following definitions come from lsaparse.c */
+
+void make_q_open_pol(LSA_Q_OPEN_POL *r_q, char *server_name,
+ uint32 attributes, uint32 sec_qos,
+ uint16 desired_access);
+char* lsa_io_q_open_pol(BOOL io, LSA_Q_OPEN_POL *r_q, char *q, char *base, int align, int depth);
+char* lsa_io_r_open_pol(BOOL io, LSA_R_OPEN_POL *r_p, char *q, char *base, int align, int depth);
+void make_q_query(LSA_Q_QUERY_INFO *q_q, LSA_POL_HND *hnd, uint16 info_class);
+char* lsa_io_q_query(BOOL io, LSA_Q_QUERY_INFO *q_q, char *q, char *base, int align, int depth);
+void make_q_close(LSA_Q_CLOSE *q_c, LSA_POL_HND *hnd);
+char* lsa_io_q_close(BOOL io, LSA_Q_CLOSE *q_c, char *q, char *base, int align, int depth);
+void make_r_close(LSA_R_CLOSE *q_r, LSA_POL_HND *hnd);
+char* lsa_io_r_close(BOOL io, LSA_R_CLOSE *r_c, char *q, char *base, int align, int depth);
+char* lsa_io_r_query(BOOL io, LSA_R_QUERY_INFO *r_q, char *q, char *base, int align, int depth);
+char* lsa_io_q_lookup_sids(BOOL io, LSA_Q_LOOKUP_SIDS *q_s, char *q, char *base, int align, int depth);
+char* lsa_io_r_lookup_sids(BOOL io, LSA_R_LOOKUP_SIDS *r_s, char *q, char *base, int align, int depth);
+char* lsa_io_q_lookup_rids(BOOL io, LSA_Q_LOOKUP_RIDS *q_r, char *q, char *base, int align, int depth);
+char* lsa_io_r_lookup_rids(BOOL io, LSA_R_LOOKUP_RIDS *r_r, char *q, char *base, int align, int depth);
+void make_q_req_chal(LSA_Q_REQ_CHAL *q_c,
+ char *logon_srv, char *logon_clnt,
+ DOM_CHAL *clnt_chal);
+char* lsa_io_q_req_chal(BOOL io, LSA_Q_REQ_CHAL *q_c, char *q, char *base, int align, int depth);
+char* lsa_io_r_req_chal(BOOL io, LSA_R_REQ_CHAL *r_c, char *q, char *base, int align, int depth);
+void make_q_auth_2(LSA_Q_AUTH_2 *q_a,
+ char *logon_srv, char *acct_name, uint16 sec_chan, char *comp_name,
+ DOM_CHAL *clnt_chal, uint32 clnt_flgs);
+char* lsa_io_q_auth_2(BOOL io, LSA_Q_AUTH_2 *q_a, char *q, char *base, int align, int depth);
+char* lsa_io_r_auth_2(BOOL io, LSA_R_AUTH_2 *r_a, char *q, char *base, int align, int depth);
+char* lsa_io_q_srv_pwset(BOOL io, LSA_Q_SRV_PWSET *q_s, char *q, char *base, int align, int depth);
+char* lsa_io_r_srv_pwset(BOOL io, LSA_R_SRV_PWSET *r_s, char *q, char *base, int align, int depth);
+char* lsa_io_user_info(BOOL io, LSA_USER_INFO *usr, char *q, char *base, int align, int depth);
+char* lsa_io_q_sam_logon(BOOL io, LSA_Q_SAM_LOGON *q_l, char *q, char *base, int align, int depth);
+char* lsa_io_r_sam_logon(BOOL io, LSA_R_SAM_LOGON *r_l, char *q, char *base, int align, int depth);
+char* lsa_io_q_sam_logoff(BOOL io, LSA_Q_SAM_LOGOFF *q_l, char *q, char *base, int align, int depth);
+char* lsa_io_r_sam_logoff(BOOL io, LSA_R_SAM_LOGOFF *r_l, char *q, char *base, int align, int depth);
+
+/*The following definitions come from mangle.c */
+
+int str_checksum(char *s);
+BOOL is_8_3(char *fname, BOOL check_case);
+void create_mangled_stack(int size);
+BOOL check_mangled_stack(char *s);
+BOOL is_mangled(char *s);
+void mangle_name_83(char *s);
+BOOL name_map_mangle(char *OutName,BOOL need83,int snum);
+
+/*The following definitions come from md4.c */
+
+void mdfour(unsigned char *out, unsigned char *in, int n);
+
+/*The following definitions come from message.c */
+
+int reply_sends(char *inbuf,char *outbuf);
+int reply_sendstrt(char *inbuf,char *outbuf);
+int reply_sendtxt(char *inbuf,char *outbuf);
+int reply_sendend(char *inbuf,char *outbuf);
+
+/*The following definitions come from nameannounce.c */
+
+void announce_request(struct work_record *work, struct in_addr ip);
+void do_announce_request(char *info, char *to_name, int announce_type,
+ int from,
+ int to, struct in_addr dest_ip);
+void sync_server(enum state_type state, char *serv_name, char *work_name,
+ int name_type,
+ struct subnet_record *d,
+ struct in_addr ip);
+void announce_my_servers_removed(void);
+void announce_server(struct subnet_record *d, struct work_record *work,
+ char *name, char *comment, time_t ttl, int server_type);
+void announce_host(time_t t);
+void reset_announce_timer();
+void announce_master(time_t t);
+void announce_remote(time_t t);
+
+/*The following definitions come from namebrowse.c */
+
+void expire_browse_cache(time_t t);
+struct browse_cache_record *add_browser_entry(char *name, int type, char *wg,
+ time_t ttl, struct subnet_record *d,
+ struct in_addr ip, BOOL local);
+void do_browser_lists(time_t t);
+
+/*The following definitions come from namedbname.c */
+
+void set_samba_nb_type(void);
+BOOL name_equal(struct nmb_name *n1,struct nmb_name *n2);
+BOOL ms_browser_name(char *name, int type);
+void remove_name(struct subnet_record *d, struct name_record *n);
+struct name_record *find_name_on_subnet(struct subnet_record *d,
+ struct nmb_name *name, BOOL self_only);
+void dump_names(void);
+void load_netbios_names(void);
+void remove_netbios_name(struct subnet_record *d,
+ char *name,int type, enum name_source source);
+struct name_record *add_netbios_entry(struct subnet_record *d,
+ char *name, int type, int nb_flags, int ttl,
+ enum name_source source, struct in_addr ip, BOOL new_only);
+void expire_names(time_t t);
+
+/*The following definitions come from namedbresp.c */
+
+void add_response_record(struct subnet_record *d,
+ struct response_record *n);
+void remove_response_record(struct subnet_record *d,
+ struct response_record *n);
+struct response_record *make_response_queue_record(enum state_type state,
+ int id,uint16 fd,
+ int quest_type, char *name,int type, int nb_flags, time_t ttl,
+ int server_type, char *my_name, char *my_comment,
+ BOOL bcast,BOOL recurse,
+ struct in_addr send_ip, struct in_addr reply_to_ip,
+ int reply_id);
+struct response_record *find_response_record(struct subnet_record **d,
+ uint16 id);
+
+/*The following definitions come from namedbserver.c */
+
+void remove_old_servers(struct work_record *work, time_t t,
+ BOOL remove_all);
+struct server_record *find_server(struct work_record *work, char *name);
+struct server_record *add_server_entry(struct subnet_record *d,
+ struct work_record *work,
+ char *name,int servertype,
+ int ttl,char *comment,
+ BOOL replace);
+void expire_servers(time_t t);
+
+/*The following definitions come from namedbsubnet.c */
+
+struct subnet_record *find_subnet(struct in_addr ip);
+struct subnet_record *find_subnet_all(struct in_addr ip);
+void add_workgroup_to_subnet( struct subnet_record *d, char *group);
+void add_my_subnets(char *group);
+void write_browse_list(time_t t);
+
+/*The following definitions come from namedbwork.c */
+
+struct work_record *remove_workgroup(struct subnet_record *d,
+ struct work_record *work,
+ BOOL remove_all_servers);
+struct work_record *find_workgroupstruct(struct subnet_record *d,
+ fstring name, BOOL add);
+void dump_workgroups(void);
+
+/*The following definitions come from nameelect.c */
+
+void check_master_browser(time_t t);
+void browser_gone(char *work_name, struct in_addr ip);
+void send_election(struct subnet_record *d, char *group,uint32 criterion,
+ int timeup,char *name);
+void name_unregister_work(struct subnet_record *d, char *name, int name_type);
+void name_register_work(struct subnet_record *d, char *name, int name_type,
+ int nb_flags, time_t ttl, struct in_addr ip, BOOL bcast);
+void become_local_master(struct subnet_record *d, struct work_record *work);
+void become_domain_master(struct subnet_record *d, struct work_record *work);
+void become_logon_server(struct subnet_record *d, struct work_record *work);
+void unbecome_local_master(struct subnet_record *d, struct work_record *work,
+ int remove_type);
+void unbecome_domain_master(struct subnet_record *d, struct work_record *work,
+ int remove_type);
+void unbecome_logon_server(struct subnet_record *d, struct work_record *work,
+ int remove_type);
+void run_elections(time_t t);
+void process_election(struct packet_struct *p,char *buf);
+BOOL check_elections(void);
+
+/*The following definitions come from namelogon.c */
+
+void process_logon_packet(struct packet_struct *p,char *buf,int len);
+
+/*The following definitions come from namepacket.c */
+
+void debug_browse_data(char *outbuf, int len);
+void initiate_netbios_packet(uint16 *id,
+ int fd,int quest_type,char *name,int name_type,
+ int nb_flags,BOOL bcast,BOOL recurse,
+ struct in_addr to_ip);
+void reply_netbios_packet(struct packet_struct *p1,int trn_id,
+ int rcode, int rcv_code, int opcode,
+ BOOL recursion_available,
+ BOOL recursion_desired,
+ struct nmb_name *rr_name,int rr_type,int rr_class,int ttl,
+ char *data,int len);
+void queue_packet(struct packet_struct *packet);
+void run_packet_queue();
+BOOL listen_for_packets(BOOL run_election);
+BOOL send_mailslot_reply(BOOL unique, char *mailslot,int fd,char *buf,int len,char *srcname,
+ char *dstname,int src_type,int dest_type,
+ struct in_addr dest_ip,struct in_addr src_ip);
+
+/*The following definitions come from namequery.c */
+
+BOOL name_status(int fd,char *name,int name_type,BOOL recurse,
+ struct in_addr to_ip,char *master,char *rname,
+ void (*fn)());
+BOOL name_query(int fd,char *name,int name_type,
+ BOOL bcast,BOOL recurse,
+ struct in_addr to_ip, struct in_addr *ip,void (*fn)());
+
+/*The following definitions come from nameresp.c */
+
+void expire_netbios_response_entries(time_t t);
+struct response_record *queue_netbios_pkt_wins(
+ int fd,int quest_type,enum state_type state,
+ char *name,int name_type,int nb_flags, time_t ttl,
+ int server_type, char *my_name, char *my_comment,
+ struct in_addr send_ip, struct in_addr reply_to_ip);
+struct response_record *queue_netbios_packet(struct subnet_record *d,
+ int fd,int quest_type,enum state_type state,char *name,
+ int name_type,int nb_flags, time_t ttl,
+ int server_type, char *my_name, char *my_comment,
+ BOOL bcast,BOOL recurse,
+ struct in_addr send_ip, struct in_addr reply_to_ip,
+ int reply_id);
+
+/*The following definitions come from nameserv.c */
+
+void remove_name_entry(struct subnet_record *d, char *name,int type);
+void add_my_name_entry(struct subnet_record *d,char *name,int type,int nb_flags);
+void add_domain_logon_names(void);
+void add_domain_master_bcast(void);
+void add_domain_master_wins(void);
+void add_domain_names(time_t t);
+void add_my_names(void);
+void remove_my_names();
+void refresh_my_names(time_t t);
+void query_refresh_names(time_t t);
+
+/*The following definitions come from nameservreply.c */
+
+void add_name_respond(struct subnet_record *d, int fd, struct in_addr from_ip,
+ uint16 response_id,
+ struct nmb_name *name,
+ int nb_flags, int ttl, struct in_addr register_ip,
+ BOOL new_owner, struct in_addr reply_to_ip);
+void reply_name_release(struct packet_struct *p);
+void reply_name_reg(struct packet_struct *p);
+void reply_name_status(struct packet_struct *p);
+void reply_name_query(struct packet_struct *p);
+
+/*The following definitions come from nameservresp.c */
+
+void debug_state_type(int state);
+void response_netbios_packet(struct packet_struct *p);
+
+/*The following definitions come from namework.c */
+
+void reset_server(char *name, int state, struct in_addr ip);
+void tell_become_backup(void);
+BOOL same_context(struct dgram_packet *dgram);
+void process_browse_packet(struct packet_struct *p,char *buf,int len);
+
+/*The following definitions come from nmbd.c */
+
+BOOL reload_services(BOOL test);
+
+/*The following definitions come from nmblib.c */
+
+char *lookup_opcode_name( int opcode );
+void debug_nmb_packet(struct packet_struct *p);
+char *namestr(struct nmb_name *n);
+void free_nmb_packet(struct nmb_packet *nmb);
+void free_packet(struct packet_struct *packet);
+struct packet_struct *read_packet(int fd,enum packet_type packet_type);
+void make_nmb_name(struct nmb_name *n,char *name,int type,char *this_scope);
+BOOL send_packet(struct packet_struct *p);
+struct packet_struct *receive_packet(int fd,enum packet_type type,int t);
+
+/*The following definitions come from nmblookup.c */
+
+int main(int argc,char *argv[]);
+
+/*The following definitions come from nmbsync.c */
+
+void sync_browse_lists(struct subnet_record *d, struct work_record *work,
+ char *name, int nm_type, struct in_addr ip, BOOL local);
+
+/*The following definitions come from ntclient.c */
+
+BOOL do_nt_login(char *desthost, char *myhostname,
+ int Client, int cnum);
+
+/*The following definitions come from ntclientlsa.c */
+
+BOOL do_lsa_open_policy(uint16 fnum, uint32 call_id,
+ char *server_name, LSA_POL_HND *hnd);
+BOOL do_lsa_query_info_pol(uint16 fnum, uint32 call_id,
+ LSA_POL_HND *hnd, uint16 info_class,
+ fstring domain_name, pstring domain_sid);
+BOOL do_lsa_close(uint16 fnum, uint32 call_id,
+ LSA_POL_HND *hnd);
+
+/*The following definitions come from ntclientnet.c */
+
+BOOL do_lsa_req_chal(uint16 fnum, uint32 call_id,
+ char *desthost, char *myhostname,
+ DOM_CHAL *clnt_chal, DOM_CHAL *srv_chal);
+BOOL do_lsa_auth2(uint16 fnum, uint32 call_id,
+ char *logon_srv, char *acct_name, uint16 sec_chan, char *comp_name,
+ DOM_CHAL *clnt_chal, uint32 neg_flags, DOM_CHAL *srv_chal);
+BOOL do_lsa_sam_logon(uint16 fnum, uint32 call_id,
+ uint32 sess_key[2], DOM_CRED *sto_clnt_cred,
+ char *logon_srv, char *comp_name,
+ DOM_CRED *clnt_cred, DOM_CRED *rtn_cred,
+ uint16 logon_level, uint16 switch_value, DOM_ID_INFO_1 *id1,
+ LSA_USER_INFO *user_info,
+ DOM_CRED *srv_cred);
+BOOL do_lsa_sam_logoff(uint16 fnum, uint32 call_id,
+ uint32 sess_key[2], DOM_CRED *sto_clnt_cred,
+ char *logon_srv, char *comp_name,
+ DOM_CRED *clnt_cred, DOM_CRED *rtn_cred,
+ uint16 logon_level, uint16 switch_value, DOM_ID_INFO_1 *id1,
+ DOM_CRED *srv_cred);
+
+/*The following definitions come from ntclientpipe.c */
+
+uint16 open_rpc_pipe(char *inbuf, char *outbuf, char *rname, int Client, int cnum);
+BOOL bind_rpc_pipe(char *pipe_name, uint16 fnum, uint32 call_id,
+ RPC_IFACE *abstract, RPC_IFACE *transfer);
+
+/*The following definitions come from params.c */
+
+BOOL pm_process( char *FileName,
+ BOOL (*sfunc)(char *),
+ BOOL (*pfunc)(char *, char *) );
+
+/*The following definitions come from password.c */
+
+void generate_next_challenge(char *challenge);
+BOOL set_challenge(char *challenge);
+BOOL last_challenge(char *challenge);
+user_struct *get_valid_user_struct(uint16 vuid);
+void invalidate_vuid(uint16 vuid);
+char *validated_username(uint16 vuid);
+uint16 register_vuid(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 user_ok(char *user,int snum);
+BOOL authorise_login(int snum,char *user,char *password, int pwlen,
+ BOOL *guest,BOOL *force,uint16 vuid);
+BOOL check_hosts_equiv(char *user);
+struct cli_state *server_client(void);
+struct cli_state *server_cryptkey(void);
+BOOL server_validate(char *user, char *domain,
+ char *pass, int passlen,
+ char *ntpass, int ntpasslen);
+
+/*The following definitions come from pcap.c */
+
+BOOL pcap_printername_ok(char *pszPrintername, char *pszPrintcapname);
+void pcap_printer_fn(void (*fn)());
+
+/*The following definitions come from pipenetlog.c */
+
+BOOL get_md4pw(char *md4pw, char *mach_acct);
+BOOL api_netlogrpcTNP(int cnum,int uid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len);
+
+/*The following definitions come from pipentlsa.c */
+
+BOOL api_ntLsarpcTNP(int cnum,int uid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len);
+
+/*The following definitions come from pipes.c */
+
+int reply_open_pipe_and_X(char *inbuf,char *outbuf,int length,int bufsize);
+BOOL api_LsarpcSNPHS(int cnum,int uid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len);
+BOOL api_LsarpcTNP(int cnum,int uid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len);
+
+/*The following definitions come from pipesrvsvc.c */
+
+BOOL api_srvsvcTNP(int cnum,int uid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len);
+
+/*The following definitions come from pipeutil.c */
+
+void initrpcreply(char *inbuf, char *q);
+void endrpcreply(char *inbuf, char *q, int datalen, int rtnval, int *rlen);
+BOOL name_to_rid(char *user_name, uint32 *u_rid, uint32 *g_rid);
+char *dom_sid_to_string(DOM_SID *sid);
+int make_dom_sids(char *sids_str, DOM_SID *sids, int max_sids);
+int make_dom_gids(char *gids_str, DOM_GID *gids);
+int create_rpc_request(uint32 call_id, uint8 op_num, char *q, int data_len);
+int create_rpc_reply(uint32 call_id, char *q, int data_len);
+
+/*The following definitions come from predict.c */
+
+int read_predict(int fd,int offset,char *buf,char **ptr,int num);
+void do_read_prediction();
+void invalidate_read_prediction(int fd);
+
+/*The following definitions come from printing.c */
+
+void lpq_reset(int snum);
+void print_file(int fnum);
+int get_printqueue(int snum,int cnum,print_queue_struct **queue,
+ print_status_struct *status);
+void del_printqueue(int cnum,int snum,int jobid);
+void status_printjob(int cnum,int snum,int jobid,int status);
+int printjob_encode(int snum, int job);
+void printjob_decode(int jobid, int *snum, int *job);
+
+/*The following definitions come from quotas.c */
+
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize);
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize);
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize);
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize);
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize);
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize);
+
+/*The following definitions come from replace.c */
+
+char *Strstr(char *s, char *p);
+time_t Mktime(struct tm *t);
+int InNetGr(char *group,char *host,char *user,char *dom);
+void *malloc_wrapped(int size,char *file,int line);
+void *realloc_wrapped(void *ptr,int size,char *file,int line);
+void free_wrapped(void *ptr,char *file,int line);
+void *memcpy_wrapped(void *d,void *s,int l,char *fname,int line);
+
+/*The following definitions come from reply.c */
+
+int reply_special(char *inbuf,char *outbuf);
+int reply_tcon(char *inbuf,char *outbuf);
+int reply_tcon_and_X(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_unknown(char *inbuf,char *outbuf);
+int reply_ioctl(char *inbuf,char *outbuf);
+int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_chkpth(char *inbuf,char *outbuf);
+int reply_getatr(char *inbuf,char *outbuf);
+int reply_setatr(char *inbuf,char *outbuf);
+int reply_dskattr(char *inbuf,char *outbuf);
+int reply_search(char *inbuf,char *outbuf);
+int reply_fclose(char *inbuf,char *outbuf);
+int reply_open(char *inbuf,char *outbuf);
+int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_ulogoffX(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_mknew(char *inbuf,char *outbuf);
+int reply_ctemp(char *inbuf,char *outbuf);
+int reply_unlink(char *inbuf,char *outbuf);
+int reply_readbraw(char *inbuf, char *outbuf);
+int reply_lockread(char *inbuf,char *outbuf);
+int reply_read(char *inbuf,char *outbuf);
+int reply_read_and_X(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_writebraw(char *inbuf,char *outbuf);
+int reply_writeunlock(char *inbuf,char *outbuf);
+int reply_write(char *inbuf,char *outbuf,int dum1,int dum2);
+int reply_write_and_X(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_lseek(char *inbuf,char *outbuf);
+int reply_flush(char *inbuf,char *outbuf);
+int reply_exit(char *inbuf,char *outbuf);
+int reply_close(char *inbuf,char *outbuf);
+int reply_writeclose(char *inbuf,char *outbuf);
+int reply_lock(char *inbuf,char *outbuf);
+int reply_unlock(char *inbuf,char *outbuf);
+int reply_tdis(char *inbuf,char *outbuf);
+int reply_echo(char *inbuf,char *outbuf);
+int reply_printopen(char *inbuf,char *outbuf);
+int reply_printclose(char *inbuf,char *outbuf);
+int reply_printqueue(char *inbuf,char *outbuf);
+int reply_printwrite(char *inbuf,char *outbuf);
+int reply_mkdir(char *inbuf,char *outbuf);
+int reply_rmdir(char *inbuf,char *outbuf);
+int reply_mv(char *inbuf,char *outbuf);
+int reply_copy(char *inbuf,char *outbuf);
+int reply_setdir(char *inbuf,char *outbuf);
+int reply_lockingX(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_readbmpx(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_writebmpx(char *inbuf,char *outbuf);
+int reply_writebs(char *inbuf,char *outbuf);
+int reply_setattrE(char *inbuf,char *outbuf);
+int reply_getattrE(char *inbuf,char *outbuf);
+
+/*The following definitions come from server.c */
+
+void *dflt_sig(void);
+void killkids(void);
+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);
+int file_utime(int cnum, char *fname, struct utimbuf *times);
+BOOL set_filetime(int cnum, char *fname, time_t mtime);
+BOOL unix_convert(char *name,int cnum,pstring saved_last_component, BOOL *bad_path);
+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 sync_file(int fnum);
+void close_file(int fnum, BOOL normal_close);
+BOOL check_file_sharing(int cnum,char *fname);
+int check_share_mode( share_mode_entry *share, int deny_mode, char *fname,
+ BOOL fcbopen, int *flags);
+void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
+ int mode,int oplock_request, int *Access,int *action);
+int seek_file(int fnum,uint32 pos);
+int read_file(int fnum,char *data,uint32 pos,int n);
+int write_file(int fnum,char *data,int n);
+BOOL become_service(int cnum,BOOL do_chdir);
+int find_service(char *service);
+int cached_error_packet(char *inbuf,char *outbuf,int fnum,int line);
+int unix_error_packet(char *inbuf,char *outbuf,int def_class,uint32 def_code,int line);
+int error_packet(char *inbuf,char *outbuf,int error_class,uint32 error_code,int line);
+BOOL oplock_break(uint32 dev, uint32 inode, struct timeval *tval);
+BOOL request_oplock_break(share_mode_entry *share_entry,
+ uint32 dev, uint32 inode);
+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 **p_attrs);
+int make_connection(char *service,char *user,char *password, int pwlen, char *dev,uint16 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 close_cnum(int cnum, uint16 vuid);
+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 *str);
+char *smb_fn_name(int type);
+int chain_reply(char *inbuf,char *outbuf,int size,int bufsize);
+int construct_reply(char *inbuf,char *outbuf,int size,int bufsize);
+
+/*The following definitions come from shmem.c */
+
+struct shmem_ops *smb_shm_open(int ronly);
+
+/*The following definitions come from shmem_sysv.c */
+
+struct shmem_ops *sysv_shm_open(int ronly);
+
+/*The following definitions come from smbdes.c */
+
+void E_P16(unsigned char *p14,unsigned char *p16);
+void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24);
+void cred_hash1(unsigned char *out,unsigned char *in,unsigned char *key);
+void cred_hash2(unsigned char *out,unsigned char *in,unsigned char *key);
+
+/*The following definitions come from smbencrypt.c */
+
+void SMBencrypt(uchar *passwd, uchar *c8, uchar *p24);
+void E_md4hash(uchar *passwd, uchar *p16);
+void SMBNTencrypt(uchar *passwd, uchar *c8, uchar *p24);
+void nt_lm_owf_gen(char *pwd, char *nt_p16, char *p16);
+
+/*The following definitions come from smbparse.c */
+
+char* smb_io_utime(BOOL io, UTIME *t, char *q, char *base, int align, int depth);
+char* smb_io_time(BOOL io, NTTIME *nttime, char *q, char *base, int align, int depth);
+void make_dom_sid(DOM_SID *sid, char *domsid);
+char* smb_io_dom_sid(BOOL io, DOM_SID *sid, char *q, char *base, int align, int depth);
+void make_uni_hdr(UNIHDR *hdr, int max_len, int len, uint16 terminate);
+char* smb_io_unihdr(BOOL io, UNIHDR *hdr, char *q, char *base, int align, int depth);
+void make_uni_hdr2(UNIHDR2 *hdr, int max_len, int len, uint16 terminate);
+char* smb_io_unihdr2(BOOL io, UNIHDR2 *hdr2, char *q, char *base, int align, int depth);
+void make_unistr(UNISTR *str, char *buf);
+char* smb_io_unistr(BOOL io, UNISTR *uni, char *q, char *base, int align, int depth);
+void make_unistr2(UNISTR2 *str, char *buf, int len);
+char* smb_io_unistr2(BOOL io, UNISTR2 *uni2, char *q, char *base, int align, int depth);
+void make_dom_sid2(DOM_SID2 *sid2, char *sid_str);
+char* smb_io_dom_sid2(BOOL io, DOM_SID2 *sid2, char *q, char *base, int align, int depth);
+void make_dom_rid2(DOM_RID2 *rid2, uint32 rid);
+char* smb_io_dom_rid2(BOOL io, DOM_RID2 *rid2, char *q, char *base, int align, int depth);
+void make_clnt_srv(DOM_CLNT_SRV *log, char *logon_srv, char *comp_name);
+char* smb_io_clnt_srv(BOOL io, DOM_CLNT_SRV *log, char *q, char *base, int align, int depth);
+void make_log_info(DOM_LOG_INFO *log, char *logon_srv, char *acct_name,
+ uint16 sec_chan, char *comp_name);
+char* smb_io_log_info(BOOL io, DOM_LOG_INFO *log, char *q, char *base, int align, int depth);
+char* smb_io_chal(BOOL io, DOM_CHAL *chal, char *q, char *base, int align, int depth);
+char* smb_io_cred(BOOL io, DOM_CRED *cred, char *q, char *base, int align, int depth);
+void make_clnt_info2(DOM_CLNT_INFO2 *clnt,
+ char *logon_srv, char *comp_name,
+ DOM_CRED *clnt_cred);
+char* smb_io_clnt_info2(BOOL io, DOM_CLNT_INFO2 *clnt, char *q, char *base, int align, int depth);
+char* smb_io_clnt_info(BOOL io, DOM_CLNT_INFO *clnt, char *q, char *base, int align, int depth);
+void make_logon_id(DOM_LOGON_ID *log, uint32 log_id_low, uint32 log_id_high);
+char* smb_io_logon_id(BOOL io, DOM_LOGON_ID *log, char *q, char *base, int align, int depth);
+void make_arc4_owf(ARC4_OWF *hash, char data[16]);
+char* smb_io_arc4_owf(BOOL io, ARC4_OWF *hash, char *q, char *base, int align, int depth);
+void make_id_info1(DOM_ID_INFO_1 *id, char *domain_name,
+ uint32 param_ctrl, uint32 log_id_low, uint32 log_id_high,
+ char *user_name, char *wksta_name,
+ char arc4_lm_owf[16], char arc4_nt_owf[16]);
+char* smb_io_id_info1(BOOL io, DOM_ID_INFO_1 *id, char *q, char *base, int align, int depth);
+void make_sam_info(DOM_SAM_INFO *sam,
+ char *logon_srv, char *comp_name, DOM_CRED *clnt_cred,
+ DOM_CRED *rtn_cred, uint16 logon_level, uint16 switch_value,
+ DOM_ID_INFO_1 *id1);
+char* smb_io_sam_info(BOOL io, DOM_SAM_INFO *sam, char *q, char *base, int align, int depth);
+char* smb_io_gid(BOOL io, DOM_GID *gid, char *q, char *base, int align, int depth);
+void make_rpc_hdr(RPC_HDR *hdr, enum RPC_PKT_TYPE pkt_type, uint8 frag,
+ uint32 call_id, int data_len);
+char* smb_io_rpc_hdr(BOOL io, RPC_HDR *rpc, char *q, char *base, int align, int depth);
+void make_rpc_iface(RPC_IFACE *ifc, char data[16], uint32 version);
+char* smb_io_rpc_iface(BOOL io, RPC_IFACE *ifc, char *q, char *base, int align, int depth);
+void make_rpc_addr_str(RPC_ADDR_STR *str, char *name);
+char* smb_io_rpc_addr_str(BOOL io, RPC_ADDR_STR *str, char *q, char *base, int align, int depth);
+void make_rpc_hdr_bba(RPC_HDR_BBA *bba, uint16 max_tsize, uint16 max_rsize, uint32 assoc_gid);
+char* smb_io_rpc_hdr_bba(BOOL io, RPC_HDR_BBA *rpc, char *q, char *base, int align, int depth);
+void make_rpc_hdr_rb(RPC_HDR_RB *rpc,
+ uint16 max_tsize, uint16 max_rsize, uint32 assoc_gid,
+ uint32 num_elements, uint16 context_id, uint8 num_syntaxes,
+ RPC_IFACE *abstract, RPC_IFACE *transfer);
+char* smb_io_rpc_hdr_rb(BOOL io, RPC_HDR_RB *rpc, char *q, char *base, int align, int depth);
+void make_rpc_results(RPC_RESULTS *res,
+ uint8 num_results, uint16 result, uint16 reason);
+char* smb_io_rpc_results(BOOL io, RPC_RESULTS *res, char *q, char *base, int align, int depth);
+void make_rpc_hdr_ba(RPC_HDR_BA *rpc,
+ uint16 max_tsize, uint16 max_rsize, uint32 assoc_gid,
+ char *pipe_addr,
+ uint8 num_results, uint16 result, uint16 reason,
+ RPC_IFACE *transfer);
+char* smb_io_rpc_hdr_ba(BOOL io, RPC_HDR_BA *rpc, char *q, char *base, int align, int depth);
+void make_obj_attr(LSA_OBJ_ATTR *attr, uint32 attributes, uint32 sec_qos);
+char* smb_io_obj_attr(BOOL io, LSA_OBJ_ATTR *attr, char *q, char *base, int align, int depth);
+void make_rpc_hdr_rr(RPC_HDR_RR *hdr, enum RPC_PKT_TYPE pkt_type,
+ uint32 call_id, int data_len, uint8 opnum);
+char* smb_io_rpc_hdr_rr(BOOL io, RPC_HDR_RR *rpc, char *q, char *base, int align, int depth);
+char* smb_io_pol_hnd(BOOL io, LSA_POL_HND *pol, char *q, char *base, int align, int depth);
+char* smb_io_dom_query_3(BOOL io, DOM_QUERY_3 *d_q, char *q, char *base, int align, int depth);
+char* smb_io_dom_query_5(BOOL io, DOM_QUERY_3 *d_q, char *q, char *base, int align, int depth);
+char* smb_io_dom_query(BOOL io, DOM_QUERY *d_q, char *q, char *base, int align, int depth);
+char* smb_io_dom_r_ref(BOOL io, DOM_R_REF *r_r, char *q, char *base, int align, int depth);
+char* smb_io_dom_name(BOOL io, DOM_NAME *name, char *q, char *base, int align, int depth);
+char* smb_io_neg_flags(BOOL io, NEG_FLAGS *neg, char *q, char *base, int align, int depth);
+
+/*The following definitions come from smbpass.c */
+
+int pw_file_lock(char *name, int type, int secs);
+int pw_file_unlock(int fd);
+struct smb_passwd *get_smbpwnam(char *name);
+
+/*The following definitions come from smbpasswd.c */
+
+
+/*The following definitions come from smbrun.c */
+
+
+/*The following definitions come from srvparse.c */
+
+char* srv_io_share_info1_str(BOOL io, SH_INFO_1_STR *sh1, char *q, char *base, int align, int depth);
+char* srv_io_share_info1(BOOL io, SH_INFO_1 *sh1, char *q, char *base, int align, int depth);
+char* srv_io_share_1_ctr(BOOL io, SHARE_INFO_1_CTR *ctr, char *q, char *base, int align, int depth);
+char* srv_io_q_net_share_enum(BOOL io, SRV_Q_NET_SHARE_ENUM *q_n, char *q, char *base, int align, int depth);
+char* srv_io_r_net_share_enum(BOOL io, SRV_R_NET_SHARE_ENUM *r_n, char *q, char *base, int align, int depth);
+
+/*The following definitions come from status.c */
+
+void Ucrit_addUsername(pstring username);
+unsigned int Ucrit_checkUsername(pstring username);
+void Ucrit_addPid(int pid);
+unsigned int Ucrit_checkPid(int pid);
+
+/*The following definitions come from system.c */
+
+int sys_select(fd_set *fds,struct timeval *tval);
+int sys_select(fd_set *fds,struct timeval *tval);
+int sys_unlink(char *fname);
+int sys_open(char *fname,int flags,int mode);
+DIR *sys_opendir(char *dname);
+int sys_stat(char *fname,struct stat *sbuf);
+int sys_waitpid(pid_t pid,int *status,int options);
+int sys_lstat(char *fname,struct stat *sbuf);
+int sys_mkdir(char *dname,int mode);
+int sys_rmdir(char *dname);
+int sys_chdir(char *dname);
+int sys_utime(char *fname,struct utimbuf *times);
+int sys_rename(char *from, char *to);
+int sys_chmod(char *fname,int mode);
+char *sys_getwd(char *s);
+int sys_chown(char *fname,int uid,int gid);
+int sys_chroot(char *dname);
+struct hostent *sys_gethostbyname(char *name);
+
+/*The following definitions come from testparm.c */
+
+
+/*The following definitions come from testprns.c */
+
+int main(int argc, char *argv[]);
+
+/*The following definitions come from time.c */
+
+void GetTimeOfDay(struct timeval *tval);
+void TimeInit(void);
+int TimeDiff(time_t t);
+struct tm *LocalTime(time_t *t);
+time_t interpret_long_date(char *p);
+void put_long_date(char *p,time_t t);
+BOOL null_mtime(time_t mtime);
+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);
+char *timestring(void );
+
+/*The following definitions come from trans2.c */
+
+int reply_findclose(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_findnclose(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_transs2(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_trans2(char *inbuf,char *outbuf,int length,int bufsize);
+
+/*The following definitions come from ubi_dLinkList.c */
+
+
+/*The following definitions come from ufc.c */
+
+char *ufc_crypt(char *key,char *salt);
+
+/*The following definitions come from uid.c */
+
+void init_uid(void);
+BOOL become_guest(void);
+BOOL become_user(connection_struct *conn, int cnum, uint16 vuid);
+BOOL unbecome_user(void );
+int smbrun(char *cmd,char *outfile,BOOL shared);
+void become_root(BOOL save_dir) ;
+void unbecome_root(BOOL restore_dir);
+
+/*The following definitions come from username.c */
+
+char *get_home_dir(char *user);
+void map_username(char *user);
+struct passwd *Get_Pwnam(char *user,BOOL allow_change);
+BOOL user_in_list(char *user,char *list);
+
+/*The following definitions come from util.c */
+
+void setup_logging(char *pname,BOOL interactive);
+void reopen_logs(void);
+char *tmpdir(void);
+BOOL is_a_socket(int fd);
+BOOL next_token(char **ptr,char *buff,char *sep);
+char **toktocliplist(int *ctok, char *sep);
+void *MemMove(void *dest,void *src,int size);
+void array_promote(char *array,int elsize,int element);
+void set_socket_options(int fd, char *options);
+void close_sockets(void );
+BOOL in_group(gid_t group, int current_gid, int ngroups, int *groups);
+char *StrCpy(char *dest,char *src);
+char *StrnCpy(char *dest,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 set_blocking(int fd, BOOL set);
+int write_socket(int fd,char *buf,int len);
+int read_udp_socket(int fd,char *buf,int len);
+int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out);
+int read_max_udp(int fd,char *buffer,int bufsize,int maxtime);
+int TvalDiff(struct timeval *tvalold,struct timeval *tvalnew);
+BOOL send_keepalive(int client);
+int read_data(int fd,char *buffer,int N);
+int write_data(int fd,char *buffer,int N);
+int transfer_file(int infd,int outfd,int n,char *header,int headlen,int align);
+int read_smb_length(int fd,char *inbuf,int timeout);
+BOOL receive_smb(int fd,char *buffer, int timeout);
+BOOL receive_local_message(int fd, char *buffer, int buffer_len, int timeout);
+BOOL push_local_message(char *buf, int msg_len);
+BOOL receive_message_or_smb(int smbfd, int oplock_fd,
+ char *buffer, int buffer_len,
+ int timeout, BOOL *got_smb);
+BOOL send_smb(int fd,char *buffer);
+char *name_ptr(char *buf,int ofs);
+int name_extract(char *buf,int ofs,char *name);
+int name_len( char *s );
+BOOL send_one_packet(char *buf,int len,struct in_addr ip,int port,int type);
+void msleep(int t);
+BOOL in_list(char *s,char *list,BOOL casesensitive);
+BOOL string_init(char **dest,char *src);
+void string_free(char **s);
+BOOL string_set(char **dest,char *src);
+BOOL string_sub(char *s,char *pattern,char *insert);
+BOOL do_match(char *str, char *regexp, int case_sig);
+BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2);
+void become_daemon(void);
+BOOL yesno(char *p);
+char *fgets_slash(char *s2,int maxlen,FILE *f);
+int set_filelen(int fd, long len);
+int byte_checksum(char *buf,int len);
+char *dirname_dos(char *path,char *buf);
+void *Realloc(void *p,int size);
+void Abort(void );
+BOOL get_myname(char *my_name,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,uint32 socket_addr);
+int open_socket_out(int type, struct in_addr *addr, int port ,int timeout);
+int interpret_protocol(char *str,int def);
+int interpret_security(char *str,int def);
+uint32 interpret_addr(char *str);
+struct in_addr *interpret_addr2(char *str);
+BOOL zero_ip(struct in_addr ip);
+void reset_globals_after_fork();
+char *client_name(void);
+char *client_addr(void);
+char *automount_server(char *user_name);
+void standard_sub_basic(char *str);
+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,int signum);
+void ajt_panic(void);
+char *readdirname(void *p);
+BOOL is_in_path(char *name, name_compare_entry *namelist);
+void set_namearray(name_compare_entry **ppname_array, char *namelist);
+void free_namearray(name_compare_entry *name_array);
+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_myname(char *s);
+void set_remote_arch(enum remote_arch_types type);
+enum remote_arch_types get_remote_arch();
+char *skip_unicode_string(char *buf,int n);
+char *unistrn2(uint16 *buf, int len);
+char *unistr2(uint16 *buf);
+int struni2(uint16 *p, char *buf);
+char *unistr(char *buf);
+int unistrncpy(char *dst, char *src, int len);
+int unistrcpy(char *dst, char *src);
+void fstrcpy(char *dest, char *src);
+void pstrcpy(char *dest, char *src);
+char *align4(char *q, char *base);
+char *align2(char *q, char *base);
+char *align_offset(char *q, char *base, int align_offset_len);
+void print_asc(int level, unsigned char *buf,int len);
+void dump_data(int level,char *buf1,int len);
+char *tab_depth(int depth);
diff --git a/source/include/smb.h b/source/include/smb.h
index b7faffa9e92..9b54385eeee 100644
--- a/source/include/smb.h
+++ b/source/include/smb.h
@@ -2,7 +2,10 @@
Unix SMB/Netbios implementation.
Version 1.9.
SMB parameters and setup
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1997
+ Copyright (C) John H Terpstra 1996-1997
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+ Copyright (C) Paul Ashton 1997
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
@@ -36,10 +39,15 @@
#define BUFFER_SIZE (0xFFFF)
#define SAFETY_MARGIN 1024
-#ifndef EXTERN
-# define EXTERN extern
+/* Default size of shared memory used for share mode locking */
+#ifndef SHMEM_SIZE
+#define SHMEM_SIZE 102400
#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")
@@ -49,6 +57,12 @@
typedef int BOOL;
+/* offset in shared memory */
+#define NULL_OFFSET (int)(0)
+
+/* limiting size of ipc replies */
+#define REALLOC(ptr,size) Realloc(ptr,MAX((size),4*1024))
+
/*
Samba needs type definitions for int16, int32, uint16 and uint32.
@@ -64,6 +78,10 @@ typedef short int16;
typedef int int32;
#endif
+#ifndef uint8
+typedef unsigned char uint8;
+#endif
+
#ifndef uint16
typedef unsigned short uint16;
#endif
@@ -72,26 +90,43 @@ 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
#define DEF_CREATE_MASK (0755)
#endif
-#ifndef DEFAULT_PIPE_TIMEOUT
-#define DEFAULT_PIPE_TIMEOUT 10000000 /* Ten seconds */
-#endif
+/* how long to wait for secondary SMB packets (milli-seconds) */
+#define SMB_SECONDARY_WAIT (60*1000)
/* debugging code */
#ifndef SYSLOG
#define DEBUG(level,body) ((DEBUGLEVEL>=(level))?(Debug1 body):0)
#else
-EXTERN int syslog_level;
+extern int syslog_level;
-#define DEBUG(level,body) ((DEBUGLEVEL>=(level))? \
- (syslog_level = (level), Debug1 body):0)
+#define DEBUG(level,body) ((DEBUGLEVEL>=(level))? (syslog_level = (level), Debug1 body):0)
#endif
+/* this defines the error codes that receive_smb can put in smb_read_error */
+#define READ_TIMEOUT 1
+#define READ_EOF 2
+#define READ_ERROR 3
+
+
#define DIR_STRUCT_SIZE 43
/* these define all the command types recognised by the server - there
@@ -117,10 +152,11 @@ implemented */
#define DENY_FCB 7
/* share types */
-#define STYPE_DISKTREE 0 /* Disk drive */
-#define STYPE_PRINTQ 1 /* Spooler queue */
-#define STYPE_DEVICE 2 /* Serial device */
-#define STYPE_IPC 3 /* Interprocess communication (IPC) */
+#define STYPE_DISKTREE 0 /* Disk drive */
+#define STYPE_PRINTQ 1 /* Spooler queue */
+#define STYPE_DEVICE 2 /* Serial device */
+#define STYPE_IPC 3 /* Interprocess communication (IPC) */
+#define STYPE_HIDDEN 0x80000000 /* share is a hidden one (ends with $) */
/* SMB X/Open error codes for the ERRdos error class */
#define ERRbadfunc 1 /* Invalid function (or system call) */
@@ -142,14 +178,16 @@ implemented */
#define ERRbadshare 32 /* Share mode on file conflict with open mode */
#define ERRlock 33 /* Lock request conflicts with existing lock */
#define ERRfilexists 80 /* File in operation already exists */
+#define ERRcannotopen 110 /* Cannot open the file specified */
+#define ERRunknownlevel 124
#define ERRbadpipe 230 /* Named pipe invalid */
#define ERRpipebusy 231 /* All instances of pipe are busy */
#define ERRpipeclosing 232 /* named pipe close in progress */
#define ERRnotconnected 233 /* No process on other end of named pipe */
#define ERRmoredata 234 /* More data to be returned */
+#define ERRbaddirectory 267 /* Invalid directory name in a path. */
#define ERROR_EAS_DIDNT_FIT 275 /* Extended attributes didn't fit */
-#define ERROR_EAS_NOT_SUPPORTED 282 /* Extended attributes not suppored */
-#define ERRunknownlevel 124
+#define ERROR_EAS_NOT_SUPPORTED 282 /* Extended attributes not supported */
#define ERRunknownipc 2142
@@ -216,6 +254,940 @@ typedef char pstring[1024];
typedef char fstring[128];
typedef fstring string;
+
+/* pipe strings */
+#define PIPE_LANMAN "\\PIPE\\LANMAN"
+#define PIPE_SRVSVC "\\PIPE\\srvsvc"
+#define PIPE_NETLOGON "\\PIPE\\NETLOGON"
+#define PIPE_NTLSA "\\PIPE\\ntlsa"
+#define PIPE_LSASS "\\PIPE\\lsass"
+#define PIPE_LSARPC "\\PIPE\\lsarpc"
+
+/* NETLOGON opcodes and data structures */
+
+enum RPC_PKT_TYPE
+{
+ RPC_REQUEST = 0x00,
+ RPC_RESPONSE = 0x02,
+ RPC_BIND = 0x0B,
+ RPC_BINDACK = 0x0C
+};
+
+#define NET_QUERYFORPDC 7 /* Query for PDC */
+#define NET_QUERYFORPDC_R 12 /* Response to Query for PDC */
+#define NET_SAMLOGON 18
+#define NET_SAMLOGON_R 19
+
+/* Allowable account control bits */
+#define ACB_DISABLED 1 /* 1 = User account disabled */
+#define ACB_HOMDIRREQ 2 /* 1 = Home directory required */
+#define ACB_PWNOTREQ 4 /* 1 = User password not required */
+#define ACB_TEMPDUP /* 1 = Temporary duplicate account */
+#define ACB_NORMAL /* 1 = Normal user account */
+#define ACB_MNS /* 1 = MNS logon user account */
+#define ACB_DOMTRUST /* 1 = Interdomain trust account */
+#define ACB_WSTRUST /* 1 = Workstation trust account */
+#define ACB_SVRTRUST /* 1 = Server trust account */
+#define ACB_PWNOEXP /* 1 = User password does not expire */
+#define ACB_AUTOLOCK /* 1 = Account auto locked */
+
+#define LSA_OPENPOLICY 0x2c
+#define LSA_QUERYINFOPOLICY 0x07
+#define LSA_ENUMTRUSTDOM 0x0d
+#define LSA_REQCHAL 0x04
+#define LSA_SRVPWSET 0x06
+#define LSA_SAMLOGON 0x02
+#define LSA_AUTH2 0x0f
+#define LSA_CLOSE 0x00
+
+/* unknown .... */
+#define LSA_OPENSECRET 0xFF
+#define LSA_LOOKUPSIDS 0xFE
+#define LSA_LOOKUPNAMES 0xFD
+#define LSA_SAMLOGOFF 0xFC
+
+/* srvsvc pipe */
+#define NETSERVERGETINFO 0x15
+#define NETSHAREENUM 0x0f
+
+/* well-known RIDs - Relative IDs */
+
+/* RIDs - Well-known users ... */
+#define DOMAIN_USER_RID_ADMIN (0x000001F4L)
+#define DOMAIN_USER_RID_GUEST (0x000001F5L)
+
+/* RIDs - well-known groups ... */
+#define DOMAIN_GROUP_RID_ADMINS (0x00000200L)
+#define DOMAIN_GROUP_RID_USERS (0x00000201L)
+#define DOMAIN_GROUP_RID_GUESTS (0x00000202L)
+
+/* RIDs - well-known aliases ... */
+#define DOMAIN_ALIAS_RID_ADMINS (0x00000220L)
+#define DOMAIN_ALIAS_RID_USERS (0x00000221L)
+#define DOMAIN_ALIAS_RID_GUESTS (0x00000222L)
+#define DOMAIN_ALIAS_RID_POWER_USERS (0x00000223L)
+
+#define DOMAIN_ALIAS_RID_ACCOUNT_OPS (0x00000224L)
+#define DOMAIN_ALIAS_RID_SYSTEM_OPS (0x00000225L)
+#define DOMAIN_ALIAS_RID_PRINT_OPS (0x00000226L)
+#define DOMAIN_ALIAS_RID_BACKUP_OPS (0x00000227L)
+
+#define DOMAIN_ALIAS_RID_REPLICATOR (0x00000228L)
+
+
+
+/* 32 bit time (sec) since 01jan1970 - cifs6.txt, section 3.5, page 30 */
+typedef struct time_info
+{
+ uint32 time;
+
+} UTIME;
+
+/* 64 bit time (100usec) since ????? - cifs6.txt, section 3.5, page 30 */
+typedef struct nttime_info
+{
+ uint32 low;
+ uint32 high;
+
+} NTTIME;
+
+
+#define MAXSUBAUTHS 15 /* max sub authorities in a SID */
+
+/* DOM_SID - security id */
+typedef struct sid_info
+{
+ uint8 sid_rev_num; /* SID revision number */
+ uint8 num_auths; /* number of sub-authorities */
+ uint8 id_auth[6]; /* Identifier Authority */
+ uint32 sub_auths[MAXSUBAUTHS]; /* pointer to sub-authorities. */
+
+} DOM_SID;
+
+/* UNIHDR - unicode string header */
+typedef struct unihdr_info
+{
+ uint16 uni_max_len;
+ uint16 uni_str_len;
+ uint32 undoc; /* usually has a value of 4 */
+
+} UNIHDR;
+
+/* UNIHDR2 - unicode string header and undocumented buffer */
+typedef struct unihdr2_info
+{
+ UNIHDR unihdr;
+ uint32 undoc_buffer; /* undocumented 32 bit buffer pointer */
+
+} UNIHDR2;
+
+/* clueless as to what maximum length should be */
+#define MAX_UNISTRLEN 1024
+
+/* UNISTR - unicode string size and buffer */
+typedef struct unistr_info
+{
+ uint16 buffer[MAX_UNISTRLEN]; /* unicode characters. ***MUST*** be null-terminated */
+
+} UNISTR;
+
+/* UNISTR2 - unicode string size and buffer */
+typedef struct unistr2_info
+{
+ uint32 uni_max_len;
+ uint32 undoc;
+ uint32 uni_str_len;
+ uint16 buffer[MAX_UNISTRLEN]; /* unicode characters. **NOT** necessarily null-terminated */
+
+} UNISTR2;
+
+/* DOM_SID2 - domain SID structure - SIDs stored in unicode */
+typedef struct domsid2_info
+{
+ uint32 type; /* value is 5 */
+ uint32 undoc; /* value is 0 */
+
+ UNIHDR2 hdr; /* XXXX conflict between hdr and str for length */
+ UNISTR str; /* XXXX conflict between hdr and str for length */
+
+} DOM_SID2;
+
+/* DOM_RID2 - domain RID structure */
+typedef struct domrid2_info
+{
+ uint32 type; /* value is 5 */
+ uint32 undoc; /* value is 5 */
+ uint32 rid;
+ uint32 rid_idx; /* don't know what this is */
+
+} DOM_RID2;
+
+/* DOM_CLNT_SRV - client / server names */
+typedef struct clnt_srv_info
+{
+ uint32 undoc_buffer; /* undocumented 32 bit buffer pointer */
+ UNISTR2 uni_logon_srv; /* logon server name */
+ uint32 undoc_buffer2; /* undocumented 32 bit buffer pointer */
+ UNISTR2 uni_comp_name; /* client machine name */
+
+} DOM_CLNT_SRV;
+
+/* DOM_LOG_INFO - login info */
+typedef struct log_info
+{
+ uint32 undoc_buffer; /* undocumented 32 bit buffer pointer */
+ UNISTR2 uni_logon_srv; /* logon server name */
+ UNISTR2 uni_acct_name; /* account name */
+ uint16 sec_chan; /* secure channel type */
+ UNISTR2 uni_comp_name; /* client machine name */
+
+} DOM_LOG_INFO;
+
+/* DOM_CHAL - challenge info */
+typedef struct chal_info
+{
+ uint32 data[2]; /* credentials */
+
+} DOM_CHAL;
+
+/* DOM_CREDs - timestamped client or server credentials */
+typedef struct cred_info
+{
+ DOM_CHAL challenge; /* credentials */
+ UTIME timestamp; /* credential time-stamp */
+
+} DOM_CRED;
+
+/* DOM_CLNT_INFO - client info */
+typedef struct clnt_info
+{
+ DOM_LOG_INFO login;
+ DOM_CRED cred;
+
+} DOM_CLNT_INFO;
+
+/* DOM_CLNT_INFO2 - client info */
+typedef struct clnt_info2
+{
+ DOM_CLNT_SRV login;
+ uint32 ptr_cred;
+ DOM_CRED cred;
+
+} DOM_CLNT_INFO2;
+
+/* DOM_LOGON_ID - logon id */
+typedef struct logon_info
+{
+ uint32 low;
+ uint32 high;
+
+} DOM_LOGON_ID;
+
+/* ARC4_OWF */
+typedef struct arc4_owf_info
+{
+ uint8 data[16];
+
+} ARC4_OWF;
+
+
+/* DOM_ID_INFO_1 */
+typedef struct id_info_1
+{
+ uint32 ptr_id_info1; /* pointer to id_info_1 */
+ UNIHDR hdr_domain_name; /* domain name unicode header */
+ uint32 param_ctrl; /* param control */
+ DOM_LOGON_ID logon_id; /* logon ID */
+ UNIHDR hdr_user_name; /* user name unicode header */
+ UNIHDR hdr_wksta_name; /* workgroup name unicode header */
+ ARC4_OWF arc4_lm_owf; /* arc4 LM OWF Password */
+ ARC4_OWF arc4_nt_owf; /* arc4 NT OWF Password */
+ UNISTR2 uni_domain_name; /* domain name unicode string */
+ UNISTR2 uni_user_name; /* user name unicode string */
+ UNISTR2 uni_wksta_name; /* workgroup name unicode string */
+
+} DOM_ID_INFO_1;
+
+/* SAM_INFO - sam logon/off id structure */
+typedef struct sam_info
+{
+ DOM_CLNT_INFO2 client;
+ uint32 ptr_rtn_cred; /* pointer to return credentials */
+ DOM_CRED rtn_cred; /* return credentials */
+ uint16 logon_level;
+ uint16 switch_value;
+
+ union
+ {
+ DOM_ID_INFO_1 *id1; /* auth-level 1 */
+
+ } auth;
+
+} DOM_SAM_INFO;
+
+/* DOM_GID - group id + user attributes */
+typedef struct gid_info
+{
+ uint32 g_rid; /* a group RID */
+ uint32 attr;
+
+} DOM_GID;
+
+/* RPC_HDR - ms rpc header */
+typedef struct rpc_hdr_info
+{
+ uint8 major; /* 5 - RPC major version */
+ uint8 minor; /* 0 - RPC minor version */
+ uint8 pkt_type; /* 2 - RPC response packet */
+ uint8 frag; /* 3 - first frag + last frag */
+ uint32 pack_type; /* 0x1000 0000 - packed data representation */
+ uint16 frag_len; /* fragment length - data size (bytes) inc header and tail. */
+ uint16 auth_len; /* 0 - authentication length */
+ uint32 call_id; /* call identifier. matches 12th uint32 of incoming RPC data. */
+
+} RPC_HDR;
+
+/* RPC_HDR_RR - ms request / response rpc header */
+typedef struct rpc_hdr_rr_info
+{
+ RPC_HDR hdr;
+
+ uint32 alloc_hint; /* allocation hint - data size (bytes) minus header and tail. */
+ uint16 context_id; /* 0 - presentation context identifier */
+ uint8 cancel_count; /* 0 - cancel count */
+ uint8 opnum; /* request: 0 - reserved. response: opnum */
+
+} RPC_HDR_RR;
+
+/* the interfaces are numbered. as yet I haven't seen more than one interface
+ * used on the same pipe name
+ * srvsvc
+ * abstract (0x4B324FC8, 0x01D31670, 0x475A7812, 0x88E16EBF, 0x00000003)
+ * transfer (0x8A885D04, 0x11C91CEB, 0x0008E89F, 0x6048102B, 0x00000002)
+ */
+/* RPC_IFACE */
+typedef struct rpc_iface_info
+{
+ uint8 data[16]; /* 16 bytes of number */
+ uint32 version; /* the interface number */
+
+} RPC_IFACE;
+
+
+/* this seems to be the same string name depending on the name of the pipe,
+ * but is more likely to be linked to the interface name
+ * "srvsvc", "\\PIPE\\ntsvcs"
+ * "samr", "\\PIPE\\lsass"
+ * "wkssvc", "\\PIPE\\wksvcs"
+ * "NETLOGON", "\\PIPE\\NETLOGON"
+ */
+/* RPC_ADDR_STR */
+typedef struct rpc_addr_info
+{
+ uint16 len; /* length of the string including null terminator */
+ fstring str; /* the string above in single byte, null terminated form */
+
+} RPC_ADDR_STR;
+
+/* RPC_HDR_BBA */
+typedef struct rpc_hdr_bba_info
+{
+ uint16 max_tsize; /* maximum transmission fragment size (0x1630) */
+ uint16 max_rsize; /* max receive fragment size (0x1630) */
+ uint32 assoc_gid; /* associated group id (0x0) */
+
+} RPC_HDR_BBA;
+
+/* RPC_BIND_REQ - ms req bind */
+typedef struct rpc_bind_req_info
+{
+ RPC_HDR_BBA bba;
+
+ uint32 num_elements; /* the number of elements (0x1) */
+ uint16 context_id; /* presentation context identifier (0x0) */
+ uint8 num_syntaxes; /* the number of syntaxes (has always been 1?)(0x1) */
+
+ RPC_IFACE abstract; /* num and vers. of interface client is using */
+ RPC_IFACE transfer; /* num and vers. of interface to use for replies */
+
+} RPC_HDR_RB;
+
+/* RPC_RESULTS - can only cope with one reason, right now... */
+typedef struct rpc_results_info
+{
+/* uint8[] # 4-byte alignment padding, against SMB header */
+
+ uint8 num_results; /* the number of results (0x01) */
+
+/* uint8[] # 4-byte alignment padding, against SMB header */
+
+ uint16 result; /* result (0x00 = accept) */
+ uint16 reason; /* reason (0x00 = no reason specified) */
+
+} RPC_RESULTS;
+
+/* RPC_HDR_BA */
+typedef struct rpc_hdr_ba_info
+{
+ RPC_HDR_BBA bba;
+
+ RPC_ADDR_STR addr ; /* the secondary address string, as described earlier */
+ RPC_RESULTS res ; /* results and reasons */
+ RPC_IFACE transfer; /* the transfer syntax from the request */
+
+} RPC_HDR_BA;
+
+
+/* DOM_QUERY - info class 3 and 5 LSA Query response */
+typedef struct dom_query_info
+{
+ uint16 uni_dom_max_len; /* domain name string length * 2 */
+ uint16 uni_dom_str_len; /* domain name string length * 2 */
+ uint32 buffer_dom_name; /* undocumented domain name string buffer pointer */
+ uint32 buffer_dom_sid; /* undocumented domain SID string buffer pointer */
+ UNISTR2 uni_domain_name; /* domain name (unicode string) */
+ DOM_SID dom_sid; /* domain SID */
+
+} DOM_QUERY;
+
+/* level 5 is same as level 3. we hope. */
+typedef DOM_QUERY DOM_QUERY_3;
+typedef DOM_QUERY DOM_QUERY_5;
+
+#define POL_HND_SIZE 20
+
+/* LSA_POL_HND */
+typedef struct lsa_policy_info
+{
+ uint8 data[POL_HND_SIZE]; /* policy handle */
+
+} LSA_POL_HND;
+
+/* OBJ_ATTR (object attributes) */
+typedef struct object_attributes_info
+{
+ uint32 len; /* 0x18 - length (in bytes) inc. the length field. */
+ uint32 ptr_root_dir; /* 0 - root directory (pointer) */
+ uint32 ptr_obj_name; /* 0 - object name (pointer) */
+ uint32 attributes; /* 0 - attributes (undocumented) */
+ uint32 ptr_sec_desc; /* 0 - security descriptior (pointer) */
+ uint32 sec_qos; /* 0 - security quality of service */
+
+} LSA_OBJ_ATTR;
+
+/* LSA_Q_OPEN_POL - LSA Query Open Policy */
+typedef struct lsa_q_open_pol_info
+{
+ UNISTR2 uni_server_name; /* server name, starting with two '\'s */
+ LSA_OBJ_ATTR attr ; /* object attributes */
+
+ uint32 des_access; /* desired access attributes */
+
+} LSA_Q_OPEN_POL;
+
+/* LSA_R_OPEN_POL - response to LSA Open Policy */
+typedef struct lsa_r_open_pol_info
+{
+ LSA_POL_HND pol; /* policy handle */
+
+ uint32 status; /* return code */
+
+} LSA_R_OPEN_POL;
+
+/* LSA_Q_QUERY_INFO - LSA query info policy */
+typedef struct lsa_query_info
+{
+ LSA_POL_HND pol; /* policy handle */
+ uint16 info_class; /* info class */
+
+} LSA_Q_QUERY_INFO;
+
+/* LSA_R_QUERY_INFO - response to LSA query info policy */
+typedef struct lsa_r_query_info
+{
+ uint32 undoc_buffer; /* undocumented buffer pointer */
+ uint16 info_class; /* info class (same as info class in request) */
+
+ union
+ {
+ DOM_QUERY_3 id3;
+ DOM_QUERY_5 id5;
+
+ } dom;
+
+ uint32 status; /* return code */
+
+} LSA_R_QUERY_INFO;
+
+/* LSA_Q_CLOSE */
+typedef struct lsa_q_close_info
+{
+ LSA_POL_HND pol; /* policy handle */
+
+} LSA_Q_CLOSE;
+
+/* LSA_R_CLOSE */
+typedef struct lsa_r_close_info
+{
+ LSA_POL_HND pol; /* policy handle. should be all zeros. */
+
+ uint32 status; /* return code */
+
+} LSA_R_CLOSE;
+
+
+#define MAX_REF_DOMAINS 10
+
+/* DOM_R_REF */
+typedef struct dom_ref_info
+{
+ uint32 undoc_buffer; /* undocumented buffer pointer. */
+ uint32 num_ref_doms_1; /* num referenced domains? */
+ uint32 buffer_dom_name; /* undocumented domain name buffer pointer. */
+ uint32 max_entries; /* 32 - max number of entries */
+ uint32 num_ref_doms_2; /* 4 - num referenced domains? */
+
+ UNIHDR2 hdr_dom_name; /* domain name unicode string header */
+ UNIHDR2 hdr_ref_dom[MAX_REF_DOMAINS]; /* referenced domain unicode string headers */
+
+ UNISTR uni_dom_name; /* domain name unicode string */
+ DOM_SID ref_dom[MAX_REF_DOMAINS]; /* referenced domain SIDs */
+
+} DOM_R_REF;
+
+#define MAX_LOOKUP_SIDS 10
+
+/* LSA_Q_LOOKUP_SIDS - LSA Lookup SIDs */
+typedef struct lsa_q_lookup_sids
+{
+ LSA_POL_HND pol_hnd; /* policy handle */
+ uint32 num_entries;
+ uint32 buffer_dom_sid; /* undocumented domain SID buffer pointer */
+ uint32 buffer_dom_name; /* undocumented domain name buffer pointer */
+ uint32 buffer_lookup_sids[MAX_LOOKUP_SIDS]; /* undocumented domain SID pointers to be looked up. */
+ DOM_SID dom_sids[MAX_LOOKUP_SIDS]; /* domain SIDs to be looked up. */
+ uint8 undoc[16]; /* completely undocumented 16 bytes */
+
+} LSA_Q_LOOKUP_SIDS;
+
+/* LSA_R_LOOKUP_SIDS - response to LSA Lookup SIDs */
+typedef struct lsa_r_lookup_sids
+{
+ DOM_R_REF dom_ref; /* domain reference info */
+
+ uint32 num_entries;
+ uint32 undoc_buffer; /* undocumented buffer pointer */
+ uint32 num_entries2;
+
+ DOM_SID2 dom_sid[MAX_LOOKUP_SIDS]; /* domain SIDs being looked up */
+
+ uint32 num_entries3;
+
+ uint32 status; /* return code */
+
+} LSA_R_LOOKUP_SIDS;
+
+/* DOM_NAME - XXXX not sure about this structure */
+typedef struct dom_name_info
+{
+ uint32 uni_str_len;
+ UNISTR str;
+
+} DOM_NAME;
+
+
+#define UNKNOWN_LEN 1
+
+/* LSA_Q_LOOKUP_RIDS - LSA Lookup RIDs */
+typedef struct lsa_q_lookup_rids
+{
+
+ LSA_POL_HND pol_hnd; /* policy handle */
+ uint32 num_entries;
+ uint32 num_entries2;
+ uint32 buffer_dom_sid; /* undocumented domain SID buffer pointer */
+ uint32 buffer_dom_name; /* undocumented domain name buffer pointer */
+ DOM_NAME lookup_name[MAX_LOOKUP_SIDS]; /* names to be looked up */
+ uint8 undoc[UNKNOWN_LEN]; /* completely undocumented bytes of unknown length */
+
+} LSA_Q_LOOKUP_RIDS;
+
+/* LSA_R_LOOKUP_RIDS - response to LSA Lookup Names */
+typedef struct lsa_r_lookup_rids
+{
+ DOM_R_REF dom_ref; /* domain reference info */
+
+ uint32 num_entries;
+ uint32 undoc_buffer; /* undocumented buffer pointer */
+
+ uint32 num_entries2;
+ DOM_RID2 dom_rid[MAX_LOOKUP_SIDS]; /* domain RIDs being looked up */
+
+ uint32 num_entries3;
+
+ uint32 status; /* return code */
+
+} LSA_R_LOOKUP_RIDS;
+
+
+
+/* NEG_FLAGS */
+typedef struct lsa_neg_flags_info
+{
+ uint32 neg_flags; /* negotiated flags */
+
+} NEG_FLAGS;
+
+
+/* LSA_Q_REQ_CHAL */
+typedef struct lsa_q_req_chal_info
+{
+ uint32 undoc_buffer; /* undocumented buffer pointer */
+ UNISTR2 uni_logon_srv; /* logon server unicode string */
+ UNISTR2 uni_logon_clnt; /* logon client unicode string */
+ DOM_CHAL clnt_chal; /* client challenge */
+
+} LSA_Q_REQ_CHAL;
+
+
+/* LSA_R_REQ_CHAL */
+typedef struct lsa_r_req_chal_info
+{
+ DOM_CHAL srv_chal; /* server challenge */
+
+ uint32 status; /* return code */
+
+} LSA_R_REQ_CHAL;
+
+
+
+/* LSA_Q_AUTH_2 */
+typedef struct lsa_q_auth2_info
+{
+ DOM_LOG_INFO clnt_id; /* client identification info */
+ DOM_CHAL clnt_chal; /* client-calculated credentials */
+
+ NEG_FLAGS clnt_flgs; /* usually 0x0000 01ff */
+
+} LSA_Q_AUTH_2;
+
+
+/* LSA_R_AUTH_2 */
+typedef struct lsa_r_auth2_info
+{
+ DOM_CHAL srv_chal; /* server-calculated credentials */
+ NEG_FLAGS srv_flgs; /* usually 0x0000 01ff */
+
+ uint32 status; /* return code */
+
+} LSA_R_AUTH_2;
+
+
+/* LSA_Q_SRV_PWSET */
+typedef struct lsa_q_srv_pwset_info
+{
+ DOM_CLNT_INFO clnt_id; /* client identification/authentication info */
+ char pwd[16]; /* new password - undocumented. */
+
+} LSA_Q_SRV_PWSET;
+
+/* LSA_R_SRV_PWSET */
+typedef struct lsa_r_srv_pwset_info
+{
+ DOM_CRED srv_cred; /* server-calculated credentials */
+
+ uint32 status; /* return code */
+
+} LSA_R_SRV_PWSET;
+
+#define LSA_MAX_GROUPS 32
+#define LSA_MAX_SIDS 32
+
+/* LSA_USER_INFO */
+typedef struct lsa_q_user_info
+{
+ uint32 ptr_user_info;
+
+ NTTIME logon_time; /* logon time */
+ NTTIME logoff_time; /* logoff time */
+ NTTIME kickoff_time; /* kickoff time */
+ NTTIME pass_last_set_time; /* password last set time */
+ NTTIME pass_can_change_time; /* password can change time */
+ NTTIME pass_must_change_time; /* password must change time */
+
+ UNIHDR hdr_user_name; /* username unicode string header */
+ UNIHDR hdr_full_name; /* user's full name unicode string header */
+ UNIHDR hdr_logon_script; /* logon script unicode string header */
+ UNIHDR hdr_profile_path; /* profile path unicode string header */
+ UNIHDR hdr_home_dir; /* home directory unicode string header */
+ UNIHDR hdr_dir_drive; /* home directory drive unicode string header */
+
+ uint16 logon_count; /* logon count */
+ uint16 bad_pw_count; /* bad password count */
+
+ uint32 user_id; /* User ID */
+ uint32 group_id; /* Group ID */
+ uint32 num_groups; /* num groups */
+ uint32 buffer_groups; /* undocumented buffer pointer to groups. */
+ uint32 user_flgs; /* user flags */
+
+ char user_sess_key[16]; /* unused user session key */
+
+ UNIHDR hdr_logon_srv; /* logon server unicode string header */
+ UNIHDR hdr_logon_dom; /* logon domain unicode string header */
+
+ uint32 buffer_dom_id; /* undocumented logon domain id pointer */
+ char padding[40]; /* unused padding bytes. expansion room */
+
+ uint32 num_other_sids; /* 0 - num_sids */
+ uint32 buffer_other_sids; /* NULL - undocumented pointer to SIDs. */
+
+ UNISTR2 uni_user_name; /* username unicode string */
+ UNISTR2 uni_full_name; /* user's full name unicode string */
+ UNISTR2 uni_logon_script; /* logon script unicode string */
+ UNISTR2 uni_profile_path; /* profile path unicode string */
+ UNISTR2 uni_home_dir; /* home directory unicode string */
+ UNISTR2 uni_dir_drive; /* home directory drive unicode string */
+
+ uint32 num_groups2; /* num groups */
+ DOM_GID gids[LSA_MAX_GROUPS]; /* group info */
+
+ UNISTR2 uni_logon_srv; /* logon server unicode string */
+ UNISTR2 uni_logon_dom; /* logon domain unicode string */
+
+ DOM_SID dom_sid; /* domain SID */
+ DOM_SID other_sids[LSA_MAX_SIDS]; /* undocumented - domain SIDs */
+
+} LSA_USER_INFO;
+
+
+/* LSA_Q_SAM_LOGON */
+typedef struct lsa_q_sam_logon_info
+{
+ DOM_SAM_INFO sam_id;
+
+} LSA_Q_SAM_LOGON;
+
+/* LSA_R_SAM_LOGON */
+typedef struct lsa_r_sam_logon_info
+{
+ uint32 buffer_creds; /* undocumented buffer pointer */
+ DOM_CRED srv_creds; /* server credentials. server time stamp appears to be ignored. */
+
+ uint16 switch_value; /* 3 - indicates type of USER INFO */
+ LSA_USER_INFO *user;
+
+ uint32 auth_resp; /* 1 - Authoritative response; 0 - Non-Auth? */
+
+ uint32 status; /* return code */
+
+} LSA_R_SAM_LOGON;
+
+
+/* LSA_Q_SAM_LOGOFF */
+typedef struct lsa_q_sam_logoff_info
+{
+ DOM_SAM_INFO sam_id;
+
+} LSA_Q_SAM_LOGOFF;
+
+/* LSA_R_SAM_LOGOFF */
+typedef struct lsa_r_sam_logoff_info
+{
+ uint32 buffer_creds; /* undocumented buffer pointer */
+ DOM_CRED srv_creds; /* server credentials. server time stamp appears to be ignored. */
+
+ uint32 status; /* return code */
+
+} LSA_R_SAM_LOGOFF;
+
+
+/* SH_INFO_1 (pointers to level 1 share info strings) */
+typedef struct ptr_share_info1
+{
+ uint32 ptr_netname; /* pointer to net name. */
+ uint32 type; /* type of share. 0 - undocumented. */
+ uint32 ptr_remark; /* pointer to comment. */
+
+} SH_INFO_1;
+
+/* SH_INFO_1_STR (level 1 share info strings) */
+typedef struct str_share_info1
+{
+ UNISTR2 uni_netname; /* unicode string of net name */
+ UNISTR2 uni_remark; /* unicode string of comment. */
+
+} SH_INFO_1_STR;
+
+/* oops - this is going to take up a *massive* amount of stack. */
+/* the UNISTR2s already have 1024 uint16 chars in them... */
+#define MAX_SHARE_ENTRIES 32
+
+/* SHARE_INFO_1_CONTAINER */
+typedef struct share_info_ctr
+{
+ uint32 num_entries_read; /* EntriesRead */
+ uint32 ptr_share_info; /* Buffer */
+ uint32 num_entries_read2; /* EntriesRead */
+ SH_INFO_1 info_1 [MAX_SHARE_ENTRIES]; /* share entry pointers */
+ SH_INFO_1_STR info_1_str[MAX_SHARE_ENTRIES]; /* share entry strings */
+ uint32 num_entries_read3; /* EntriesRead2 */
+ uint32 padding; /* padding */
+
+} SHARE_INFO_1_CTR;
+
+
+/* SRV_Q_NET_SHARE_ENUM */
+typedef struct q_net_share_enum_info
+{
+ uint32 ptr_srv_name; /* pointer (to server name?) */
+ UNISTR2 uni_srv_name; /* server name */
+
+ uint32 share_level; /* share level */
+ uint32 switch_value; /* switch value */
+
+ uint32 ptr_share_info; /* pointer to SHARE_INFO_1_CTR */
+
+ union
+ {
+ SHARE_INFO_1_CTR info1; /* share info with 0 entries */
+
+ } share;
+
+ uint32 preferred_len; /* preferred maximum length (0xffff ffff) */
+
+} SRV_Q_NET_SHARE_ENUM;
+
+
+/* SRV_R_NET_SHARE_ENUM */
+typedef struct r_net_share_enum_info
+{
+ uint32 share_level; /* share level */
+ uint32 switch_value; /* switch value */
+
+ uint32 ptr_share_info; /* pointer to SHARE_INFO_1_CTR */
+ union
+ {
+ SHARE_INFO_1_CTR info1; /* share info container */
+
+ } share;
+
+ uint32 status; /* return status */
+
+} SRV_R_NET_SHARE_ENUM;
+
+
+
+/*
+
+Yet to be turned into structures:
+
+6) \\MAILSLOT\NET\NTLOGON
+-------------------------
+
+6.1) Query for PDC
+------------------
+
+Request:
+
+ uint16 0x0007 - Query for PDC
+ STR machine name
+ STR response mailslot
+ uint8[] padding to 2-byte align with start of mailslot.
+ UNISTR machine name
+ uint32 NTversion
+ uint16 LMNTtoken
+ uint16 LM20token
+
+Response:
+
+ uint16 0x000A - Respose to Query for PDC
+ STR machine name (in uppercase)
+ uint8[] padding to 2-byte align with start of mailslot.
+ UNISTR machine name
+ UNISTR domain name
+ uint32 NTversion (same as received in request)
+ uint16 LMNTtoken (same as received in request)
+ uint16 LM20token (same as received in request)
+
+
+6.2) SAM Logon
+--------------
+
+Request:
+
+ uint16 0x0012 - SAM Logon
+ uint16 request count
+ UNISTR machine name
+ UNISTR user name
+ STR response mailslot
+ uint32 alloweable account
+ uint32 domain SID size
+ char[sid_size] domain SID, of sid_size bytes.
+ uint8[] ???? padding to 4? 2? -byte align with start of mailslot.
+ uint32 NTversion
+ uint16 LMNTtoken
+ uint16 LM20token
+
+Response:
+
+ uint16 0x0013 - Response to SAM Logon
+ UNISTR machine name
+ UNISTR user name - workstation trust account
+ UNISTR domain name
+ uint32 NTversion
+ uint16 LMNTtoken
+ uint16 LM20token
+
+*/
+
+
+struct smb_passwd
+{
+ int smb_userid;
+ char *smb_name;
+ unsigned char *smb_passwd; /* Null if no password */
+ unsigned char *smb_nt_passwd; /* Null if no password */
+ /* Other fields / flags may be added later */
+};
+
+
+struct cli_state {
+ int fd;
+ int cnum;
+ int pid;
+ int mid;
+ int uid;
+ int protocol;
+ int sec_mode;
+ int error;
+ int privilages;
+ fstring eff_name;
+ fstring desthost;
+ char cryptkey[8];
+ uint32 sesskey;
+ int serverzone;
+ uint32 servertime;
+ int readbraw_supported;
+ int writebraw_supported;
+ int timeout;
+ int max_xmit;
+ char *outbuf;
+ char *inbuf;
+ int bufsize;
+ int initialised;
+};
+
+struct current_user
+{
+ int cnum, id;
+ int uid, gid;
+ int ngroups;
+ gid_t *groups;
+ int *igroups;
+ int *attrs;
+};
+
typedef struct
{
int size;
@@ -227,6 +1199,7 @@ typedef struct
time_t atime;
time_t ctime;
pstring name;
+
} file_info;
@@ -241,25 +1214,43 @@ typedef struct
BOOL wr_discard; /* discard all further data */
} write_bmpx_struct;
+/*
+ * Structure used to indirect fd's from the files_struct.
+ * Needed as POSIX locking is based on file and process, not
+ * file descriptor and process.
+ */
+
typedef struct
{
- int cnum;
+ uint16 ref_count;
+ uint32 dev;
+ uint32 inode;
int fd;
+ int fd_readonly;
+ int fd_writeonly;
+ int real_open_flags;
+} file_fd_struct;
+
+typedef struct
+{
+ int cnum;
+ file_fd_struct *fd_ptr;
int pos;
- int size;
+ uint32 size;
int mode;
+ int uid;
char *mmap_ptr;
- int mmap_size;
+ uint32 mmap_size;
write_bmpx_struct *wbmpx_ptr;
- time_t open_time;
+ struct timeval open_time;
BOOL open;
BOOL can_lock;
BOOL can_read;
BOOL can_write;
BOOL share_mode;
- BOOL share_pending;
BOOL print_file;
BOOL modified;
+ BOOL granted_oplock;
char *name;
} files_struct;
@@ -271,10 +1262,14 @@ struct uid_cache {
typedef struct
{
+ char *name;
+ BOOL is_wild;
+} name_compare_entry;
+
+typedef struct
+{
int service;
BOOL force_user;
- int uid; /* uid of user who *opened* this connection */
- int gid; /* gid of user who *opened* this connection */
struct uid_cache uid_cache;
void *dirptr;
BOOL open;
@@ -286,28 +1281,61 @@ typedef struct
char *connectpath;
char *origpath;
char *user; /* name of user who *opened* this connection */
+ int uid; /* uid of user who *opened* this connection */
+ int gid; /* gid of user who *opened* this connection */
+
+ uint16 vuid; /* vuid of user who *opened* this connection, or UID_FIELD_INVALID */
+
/* following groups stuff added by ih */
+
/* This groups info is valid for the user that *opened* the connection */
int ngroups;
gid_t *groups;
int *igroups; /* an integer version - some OSes are broken :-( */
+ int *attrs;
+
time_t lastused;
BOOL used;
int num_files_open;
+ name_compare_entry *hide_list; /* Per-share list of files to return as hidden. */
+ name_compare_entry *veto_list; /* Per-share list of files to veto (never show). */
+
} connection_struct;
+/* Domain controller authentication protocol info */
+struct dcinfo
+{
+ DOM_CHAL clnt_chal; /* Initial challenge received from client */
+ DOM_CHAL srv_chal; /* Initial server challenge */
+ DOM_CRED clnt_cred; /* Last client credential */
+ DOM_CRED srv_cred; /* Last server credential */
+
+ uint32 sess_key[2]; /* Session key */
+ uchar md4pw[16]; /* md4(machine password) */
+};
typedef struct
{
int uid; /* uid of a validated user */
int gid; /* gid of a validated user */
+
fstring name; /* name of a validated user */
+ fstring real_name; /* to store real name from password file - simeon */
BOOL guest;
+
/* following groups stuff added by ih */
/* This groups info is needed for when we become_user() for this uid */
- int user_ngroups;
- gid_t *user_groups;
- int *user_igroups; /* an integer version - some OSes are broken :-( */
+ int n_groups;
+ gid_t *groups;
+ int *igroups; /* an integer version - some OSes are broken :-( */
+ int *attrs; /* attributes associated with each gid */
+
+ int n_sids;
+ int *sids;
+
+ /* per-user authentication information on NT RPCs */
+ struct dcinfo dc;
+
} user_struct;
@@ -332,6 +1360,66 @@ typedef struct
int status;
} print_status_struct;
+/* used for server information: client, nameserv and ipc */
+struct server_info_struct
+{
+ fstring name;
+ uint32 type;
+ fstring comment;
+ fstring domain; /* used ONLY in ipc.c NOT namework.c */
+ BOOL server_added; /* used ONLY in ipc.c NOT namework.c */
+};
+
+
+/* used for network interfaces */
+struct interface
+{
+ struct interface *next;
+ struct in_addr ip;
+ struct in_addr bcast;
+ struct in_addr nmask;
+};
+
+/* struct returned by get_share_modes */
+typedef struct
+{
+ int pid;
+ uint16 op_port;
+ uint16 op_type;
+ int share_mode;
+ struct timeval time;
+} share_mode_entry;
+
+
+/* each implementation of the share mode code needs
+ to support the following operations */
+struct share_ops {
+ BOOL (*stop_mgmt)(void);
+ BOOL (*lock_entry)(int , uint32 , uint32 , int *);
+ BOOL (*unlock_entry)(int , uint32 , uint32 , int );
+ BOOL (*get_entries)(int , int , uint32 , uint32 , share_mode_entry **);
+ void (*del_entry)(int , int );
+ BOOL (*set_entry)(int , int , uint16 , uint16 );
+ BOOL (*remove_oplock)(int , int);
+ int (*forall)(void (*)(share_mode_entry *, char *));
+ void (*status)(FILE *);
+};
+
+/* each implementation of the shared memory code needs
+ to support the following operations */
+struct shmem_ops {
+ BOOL (*close)( void );
+ int (*alloc)(int );
+ BOOL (*free)(int );
+ int (*get_userdef_off)(void);
+ void *(*offset2addr)(int );
+ int (*addr2offset)(void *addr);
+ BOOL (*lock_hash_entry)(unsigned int);
+ BOOL (*unlock_hash_entry)( unsigned int );
+ BOOL (*get_usage)(int *,int *,int *);
+ unsigned (*hash_size)(void);
+};
+
/* this is used for smbstatus */
struct connect_record
@@ -347,8 +1435,9 @@ struct connect_record
time_t start;
};
-
-#define LOCKING_VERSION 2
+#ifndef LOCKING_VERSION
+#define LOCKING_VERSION 4
+#endif /* LOCKING_VERSION */
/* these are useful macros for checking validity of handles */
#define VALID_FNUM(fnum) (((fnum) >= 0) && ((fnum) < MAX_OPEN_FILES))
@@ -356,6 +1445,7 @@ struct connect_record
#define VALID_CNUM(cnum) (((cnum) >= 0) && ((cnum) < MAX_CONNECTIONS))
#define OPEN_CNUM(cnum) (VALID_CNUM(cnum) && Connections[cnum].open)
#define IS_IPC(cnum) (VALID_CNUM(cnum) && Connections[cnum].ipc)
+#define IS_PRINT(cnum) (VALID_CNUM(cnum) && Connections[cnum].printer)
#define FNUM_OK(fnum,c) (OPEN_FNUM(fnum) && (c)==Files[fnum].cnum)
#define CHECK_FNUM(fnum,c) if (!FNUM_OK(fnum,c)) \
@@ -385,12 +1475,10 @@ struct connect_record
#define MAP_HIDDEN(cnum) (OPEN_CNUM(cnum) && lp_map_hidden(SNUM(cnum)))
#define MAP_SYSTEM(cnum) (OPEN_CNUM(cnum) && lp_map_system(SNUM(cnum)))
#define MAP_ARCHIVE(cnum) (OPEN_CNUM(cnum) && lp_map_archive(SNUM(cnum)))
-#define CREATE_MODE(cnum) (lp_create_mode(SNUM(cnum)) | 0700)
-#ifdef SMB_PASSWD
+#define IS_HIDDEN_PATH(cnum,path) (is_in_path((path),Connections[(cnum)].hide_list))
+#define IS_VETO_PATH(cnum,path) (is_in_path((path),Connections[(cnum)].veto_list))
+
#define SMBENCRYPT() (lp_encrypted_passwords())
-#else
-#define SMBENCRYPT() (False)
-#endif
/* the basic packet size, assuming no words or bytes */
#define smb_size 39
@@ -510,23 +1598,38 @@ struct connect_record
#define SMBfindnclose 0x35 /* Terminate a TRANSACT2_FINDNOTIFYFIRST */
#define SMBulogoffX 0x74 /* user logoff */
-
-/* these are the TRANS2 sub commands */
-#define TRANSACT2_OPEN 0
-#define TRANSACT2_FINDFIRST 1
-#define TRANSACT2_FINDNEXT 2
-#define TRANSACT2_QFSINFO 3
-#define TRANSACT2_SETFSINFO 4
-#define TRANSACT2_QPATHINFO 5
-#define TRANSACT2_SETPATHINFO 6
-#define TRANSACT2_QFILEINFO 7
-#define TRANSACT2_SETFILEINFO 8
-#define TRANSACT2_FSCTL 9
-#define TRANSACT2_IOCTL 10
-#define TRANSACT2_FINDNOTIFYFIRST 11
-#define TRANSACT2_FINDNOTIFYNEXT 12
-#define TRANSACT2_MKDIR 13
-
+/* NT SMB extensions. */
+#define SMBnttrans 0xA0 /* NT transact */
+#define SMBnttranss 0xA1 /* NT transact secondary */
+#define SMBntcreateX 0xA2 /* NT create and X */
+#define SMBntcancel 0xA4 /* NT cancel */
+
+/* These are the TRANS2 sub commands */
+#define TRANSACT2_OPEN 0
+#define TRANSACT2_FINDFIRST 1
+#define TRANSACT2_FINDNEXT 2
+#define TRANSACT2_QFSINFO 3
+#define TRANSACT2_SETFSINFO 4
+#define TRANSACT2_QPATHINFO 5
+#define TRANSACT2_SETPATHINFO 6
+#define TRANSACT2_QFILEINFO 7
+#define TRANSACT2_SETFILEINFO 8
+#define TRANSACT2_FSCTL 9
+#define TRANSACT2_IOCTL 0xA
+#define TRANSACT2_FINDNOTIFYFIRST 0xB
+#define TRANSACT2_FINDNOTIFYNEXT 0xC
+#define TRANSACT2_MKDIR 0xD
+#define TRANSACT2_SESSION_SETUP 0xE
+#define TRANSACT2_GET_DFS_REFERRAL 0x10
+#define TRANSACT2_REPORT_DFS_INCONSISTANCY 0x11
+
+/* These are the NT transact sub commands. */
+#define NT_TRANSACT_CREATE 1
+#define NT_TRANSACT_IOCTL 2
+#define NT_TRANSACT_SET_SECURITY_DESC 3
+#define NT_TRANSACT_NOTIFY_CHANGE 4
+#define NT_TRANSACT_RENAME 5
+#define NT_TRANSACT_QUERY_SECURITY_DESC 6
/* these are the trans2 sub fields for primary requests */
#define smb_tpscnt smb_vwv0
@@ -575,289 +1678,29 @@ struct connect_record
#define ERRHRD 0x03 /* Error is an hardware error. */
#define ERRCMD 0xFF /* Command was not in the "SMB" format. */
-/* structure used to hold the incoming hosts info */
-struct from_host {
- char *name; /* host name */
- char *addr; /* host address */
- 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
@@ -951,12 +1794,43 @@ char *Strstr(char *s, char *p);
#define SV_TYPE_DOMAIN_MASTER 0x00080000
#define SV_TYPE_SERVER_OSF 0x00100000
#define SV_TYPE_SERVER_VMS 0x00200000
+#define SV_TYPE_WIN95_PLUS 0x00400000
#define SV_TYPE_ALTERNATE_XPORT 0x20000000
#define SV_TYPE_LOCAL_LIST_ONLY 0x40000000
#define SV_TYPE_DOMAIN_ENUM 0x80000000
#define SV_TYPE_ALL 0xFFFFFFFF
-
+/* what server type are we currently - JHT Says we ARE 4.20 */
+/* this was set by JHT in liaison with Jeremy Allison early 1997 */
+/* setting to 4.20 at same time as announcing ourselves as NT Server */
+/* History: */
+/* Version 4.0 - never made public */
+/* Version 4.10 - New to 1.9.16p2, lost in space 1.9.16p3 to 1.9.16p9 */
+/* - Reappeared in 1.9.16p11 with fixed smbd services */
+/* Version 4.20 - To indicate that nmbd and browsing now works better */
+
+#define DEFAULT_MAJOR_VERSION 0x04
+#define DEFAULT_MINOR_VERSION 0x02
+
+/* Browser Election Values */
+#define BROWSER_ELECTION_VERSION 0x010f
+#define BROWSER_CONSTANT 0xaa55
+
+
+/* Capabilities. see ftp.microsoft.com/developr/drg/cifs/cifs/cifs4.txt */
+
+#define CAP_RAW_MODE 0x0001
+#define CAP_MPX_MODE 0x0002
+#define CAP_UNICODE 0x0004
+#define CAP_LARGE_FILES 0x0008
+#define CAP_NT_SMBS 0x0010
+#define CAP_RPC_REMOTE_APIS 0x0020
+#define CAP_STATUS32 0x0040
+#define CAP_LEVEL_II_OPLOCKS 0x0080
+#define CAP_LOCK_AND_READ 0x0100
+#define CAP_NT_FIND 0x0200
+#define CAP_DFS 0x1000
+#define CAP_LARGE_READX 0x4000
/* protocol types. It assumes that higher protocols include lower protocols
as subsets */
@@ -966,8 +1840,11 @@ 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,PRINT_LPRNG};
+/* Remote architectures we know about. */
+enum remote_arch_types {RA_UNKNOWN, RA_WFWG, RA_OS2, RA_WIN95, RA_WINNT, RA_SAMBA};
/* case handling */
enum case_handling {CASE_LOWER,CASE_UPPER};
@@ -1002,5 +1879,107 @@ enum case_handling {CASE_LOWER,CASE_UPPER};
#define ROUNDUP(x,g) (((x)+((g)-1))&~((g)-1))
+/*
+ * Global value meaing that the smb_uid field should be
+ * ingored (in share level security and protocol level == CORE)
+ */
+
+#define UID_FIELD_INVALID 0
+#define VUID_OFFSET 100 /* Amount to bias returned vuid numbers */
+
#endif
+
+/* Defines needed for multi-codepage support. */
+#define KANJI_CODEPAGE 932
+
+#ifdef KANJI
+/*
+ * Default client code page - Japanese
+ */
+#define DEFAULT_CLIENT_CODE_PAGE KANJI_CODEPAGE
+#else /* KANJI */
+/*
+ * Default client code page - 850 - Western European
+ */
+#define DEFAULT_CLIENT_CODE_PAGE 850
+#endif /* KANJI */
+
+/*
+ * Size of buffer to use when moving files across filesystems.
+ */
+#define COPYBUF_SIZE (8*1024)
+
+/*
+ * Integers used to override error codes.
+ */
+extern int unix_ERR_class;
+extern int unix_ERR_code;
+
+/*
+ * Map the Core and Extended Oplock requesst bits down
+ * to common bits (EXCLUSIVE_OPLOCK & BATCH_OPLOCK).
+ */
+
+/*
+ * Core protocol.
+ */
+#define CORE_OPLOCK_REQUEST(inbuf) ((CVAL(inbuf,smb_flg)&((1<<5)|(1<<6)))>>5)
+
+/*
+ * Extended protocol.
+ */
+#define EXTENDED_OPLOCK_REQUEST(inbuf) ((SVAL(inbuf,smb_vwv2)&((1<<1)|(1<<2)))>>1)
+
+/* Lock types. */
+#define LOCKING_ANDX_SHARED_LOCK 0x1
+#define LOCKING_ANDX_OPLOCK_RELEASE 0x2
+#define LOCKING_ANDX_CHANGE_LOCKTYPE 0x4
+#define LOCKING_ANDX_CANCEL_LOCK 0x8
+#define LOCKING_ANDX_LARGE_FILES 0x10
+
+/* Oplock levels */
+#define OPLOCKLEVEL_NONE 0
+#define OPLOCKLEVEL_II 1
+
+/*
+ * Bits we test with.
+ */
+#define EXCLUSIVE_OPLOCK 1
+#define BATCH_OPLOCK 2
+
+#define CORE_OPLOCK_GRANTED (1<<5)
+#define EXTENDED_OPLOCK_GRANTED (1<<15)
+
+/*
+ * Loopback command offsets.
+ */
+
+#define UDP_CMD_LEN_OFFSET 0
+#define UDP_CMD_PORT_OFFSET 4
+#define UDP_CMD_HEADER_LEN 6
+
+#define UDP_MESSAGE_CMD_OFFSET 0
+
+/*
+ * Oplock break command code to send over the udp socket.
+ *
+ * Form of this is :
+ *
+ * 0 2 6 10 14 18 22
+ * +----+--------+--------+--------+-------+--------+
+ * | cmd| pid | dev | inode | sec | usec |
+ * +----+--------+--------+--------+-------+--------+
+ */
+
+#define OPLOCK_BREAK_CMD 0x1
+#define OPLOCK_BREAK_PID_OFFSET 2
+#define OPLOCK_BREAK_DEV_OFFSET 6
+#define OPLOCK_BREAK_INODE_OFFSET 10
+#define OPLOCK_BREAK_SEC_OFFSET 14
+#define OPLOCK_BREAK_USEC_OFFSET 18
+#define OPLOCK_BREAK_MSG_LEN 22
+
+
+#define CMD_REPLY 0x8000
+
/* _SMB_H */
diff --git a/source/include/trans2.h b/source/include/trans2.h
index cc366ccaea0..9a2de631095 100644
--- a/source/include/trans2.h
+++ b/source/include/trans2.h
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
SMB transaction2 handling
- Copyright (C) Jeremy Allison 1994
+ Copyright (C) Jeremy Allison 1994-1997
Extensively modified by Andrew Tridgell, 1995
@@ -194,6 +194,11 @@ Byte offset Type name description
} FSINFO;
*************************************************************/
+#define SMB_INFO_STANDARD 1
+#define SMB_INFO_QUERY_EA_SIZE 2
+#define SMB_INFO_QUERY_EAS_FROM_LIST 3
+#define SMB_INFO_QUERY_ALL_EAS 4
+#define SMB_INFO_IS_NAME_VALID 6
#define SMB_QUERY_FS_LABEL_INFO 0x101
#define SMB_QUERY_FS_VOLUME_INFO 0x102
#define SMB_QUERY_FS_SIZE_INFO 0x103
@@ -228,6 +233,11 @@ Byte offset Type name description
#define DIRLEN_GUESS (45+MAX(l1_achName,l2_achName))
+/* NT uses a FILE_ATTRIBUTE_NORMAL when no other attributes
+ are set. */
+
+#define NT_FILE_ATTRIBUTE_NORMAL 0x80
+
/* Function prototypes */
diff --git a/source/include/version.h b/source/include/version.h
index 9ad8b7d44b5..b32566cc2ff 100644
--- a/source/include/version.h
+++ b/source/include/version.h
@@ -1 +1 @@
-#define VERSION "1.9.16alpha1"
+#define VERSION "1.9.18alpha8"
diff --git a/source/internals.doc b/source/internals.doc
new file mode 100644
index 00000000000..971f2567388
--- /dev/null
+++ b/source/internals.doc
@@ -0,0 +1,212 @@
+internals.txt, 8 May 1996
+Written by David Chappell <David.Chappell@mail.trincoll.edu>.
+
+This document describes some of the internal functions which must be
+understood by anyone wishing to add features to Samba.
+
+
+
+
+
+=============================================================================
+This section describes the macros defined in byteorder.h. These macros
+are used extensively in the Samba code.
+
+-----------------------------------------------------------------------------
+CVAL(buf,pos)
+
+returns the byte at offset pos within buffer buf as an unsigned character.
+
+-----------------------------------------------------------------------------
+PVAL(buf,pos)
+
+returns the value of CVAL(buf,pos) cast to type unsigned integer.
+
+-----------------------------------------------------------------------------
+SCVAL(buf,pos,val)
+
+sets the byte at offset pos within buffer buf to value val.
+
+-----------------------------------------------------------------------------
+SVAL(buf,pos)
+
+returns the value of the unsigned short (16 bit) little-endian integer at
+offset pos within buffer buf. An integer of this type is sometimes
+refered to as "USHORT".
+
+-----------------------------------------------------------------------------
+IVAL(buf,pos)
+
+returns the value of the unsigned 32 bit little-endian integer at offset
+pos within buffer buf.
+
+-----------------------------------------------------------------------------
+SVALS(buf,pos)
+
+returns the value of the signed short (16 bit) little-endian integer at
+offset pos within buffer buf.
+
+-----------------------------------------------------------------------------
+IVALS(buf,pos)
+
+returns the value of the signed 32 bit little-endian integer at offset pos
+within buffer buf.
+
+-----------------------------------------------------------------------------
+SSVAL(buf,pos,val)
+
+sets the unsigned short (16 bit) little-endian integer at offset pos within
+buffer buf to value val.
+
+-----------------------------------------------------------------------------
+SIVAL(buf,pos,val)
+
+sets the unsigned 32 bit little-endian integer at offset pos within buffer
+buf to the value val.
+
+-----------------------------------------------------------------------------
+SSVALS(buf,pos,val)
+
+sets the short (16 bit) signed little-endian integer at offset pos within
+buffer buf to the value val.
+
+-----------------------------------------------------------------------------
+SIVALS(buf,pos,val)
+
+sets the signed 32 bit little-endian integer at offset pos withing buffer
+buf to the value val.
+
+-----------------------------------------------------------------------------
+RSVAL(buf,pos)
+
+returns the value of the unsigned short (16 bit) big-endian integer at
+offset pos within buffer buf.
+
+-----------------------------------------------------------------------------
+RIVAL(buf,pos)
+
+returns the value of the unsigned 32 bit big-endian integer at offset
+pos within buffer buf.
+
+-----------------------------------------------------------------------------
+RSSVAL(buf,pos,val)
+
+sets the value of the unsigned short (16 bit) big-endian integer at
+offset pos within buffer buf to value val.
+refered to as "USHORT".
+
+-----------------------------------------------------------------------------
+RSIVAL(buf,pos,val)
+
+sets the value of the unsigned 32 bit big-endian integer at offset
+pos within buffer buf to value val.
+
+
+
+
+
+=============================================================================
+This section describes the functions need to make a LAN Manager RPC call.
+This information had been obtained by examining the Samba code and the LAN
+Manager 2.0 API documentation. It should not be considered entirely
+reliable.
+
+-----------------------------------------------------------------------------
+call_api(int prcnt, int drcnt, int mprcnt, int mdrcnt,
+ char *param, char *data, char **rparam, char **rdata);
+
+This function is defined in client.c. It uses an SMB transaction to call a
+remote api.
+
+The parameters are as follows:
+
+prcnt: the number of bytes of parameters begin sent.
+drcnt: the number of bytes of data begin sent.
+mprcnt: the maximum number of bytes of parameters which should be returned
+mdrcnt: the maximum number of bytes of data which should be returned
+param: a pointer to the parameters to be sent.
+data: a pointer to the data to be sent.
+rparam: a pointer to a pointer which will be set to point to the returned
+ paramters. The caller of call_api() must deallocate this memory.
+rdata: a pointer to a pointer which will be set to point to the returned
+ data. The caller of call_api() must deallocate this memory.
+
+-----------------------------------------------------------------------------
+These are the parameters which you ought to send, in the order of their
+appearance in the parameter block:
+
+* An unsigned 16 bit integer API number. You should set this value with
+SSVAL(). I do not know where these numbers are described.
+
+* An ASCIIZ string describing the parameters to the API function as defined
+in the LAN Manager documentation. The first parameter, which is the server
+name, is ommited. This string is based uppon the API function as described
+in the manual, not the data which is actually passed.
+
+* An ASCIIZ string describing the data structure which ought to be returned.
+
+* Any parameters which appear in the function call, as defined in the LAN
+Manager API documentation, after the "Server" and up to and including the
+"uLevel" parameters.
+
+* An unsigned 16 bit integer which gives the size in bytes of the buffer we
+will use to receive the returned array of data structures. Presumably this
+should be the same as mdrcnt. This value should be set with SSVAL().
+
+* An ASCIIZ string describing substructures which should be returned. If no
+substructures apply, this string is of zero length.
+
+-----------------------------------------------------------------------------
+The code in client.c always calls call_api() with no data. It is unclear
+when a non-zero length data buffer would be sent.
+
+-----------------------------------------------------------------------------
+The returned parameters (pointed to by rparam), in their order of appearance
+are:
+
+* An unsigned 16 bit integer which contains the API function's return code.
+This value should be read with SVAL().
+
+* An adjustment which tells the amount by which pointers in the returned
+data should be adjusted. This value should be read with SVAL(). Basically,
+the address of the start of the returned data buffer should have the returned
+pointer value added to it and then have this value subtracted from it in
+order to obtain the currect offset into the returned data buffer.
+
+* A count of the number of elements in the array of structures returned.
+It is also possible that this may sometimes be the number of bytes returned.
+
+-----------------------------------------------------------------------------
+When call_api() returns, rparam points to the returned parameters. The
+first if these is the result code. It will be zero if the API call
+suceeded. This value by be read with "SVAL(rparam,0)".
+
+The second parameter may be read as "SVAL(rparam,2)". It is a 16 bit offset
+which indicates what the base address of the returned data buffer was when
+it was built on the server. It should be used to correct pointer before
+use.
+
+The returned data buffer contains the array of returned data structures.
+Note that all pointers must be adjusted before use. The function
+fix_char_ptr() in client.c can be used for this purpose.
+
+The third parameter (which may be read as "SVAL(rparam,4)") has something to
+do with indicating the amount of data returned or possibly the amount of
+data which can be returned if enough buffer space is allowed.
+
+-----------------------------------------------------------------------------
+Certain data structures are described by means of ASCIIz strings containing
+code characters. These are the code characters:
+
+W a type byte little-endian unsigned integer
+N a count of substructures which follow
+D a four byte little-endian unsigned integer
+B a byte (with optional count expressed as trailing ASCII digits)
+z a four byte offset to a NULL terminated string
+l a four byte offset to non-string user data
+b an offset to data (with count expressed as trailing ASCII digits)
+r pointer to returned data buffer???
+L length in bytes of returned data buffer???
+h number of bytes of information available???
+
+----------------------------------------------------------------------------
diff --git a/source/lib/access.c b/source/lib/access.c
index 14a84b2fb44..c338517ed67 100644
--- a/source/lib/access.c
+++ b/source/lib/access.c
@@ -5,22 +5,20 @@ by Wietse Venema, Eindhoven University of Technology, The Netherlands.
The code is used here with permission.
The code has been considerably changed from the original. Bug reports
-should be sent to Andrew.Tridgell@anu.edu.au
+should be sent to samba-bugs@samba.anu.edu.au
*/
#include "includes.h"
-#include "loadparm.h"
#define ALLOW_PURE_ADDRESSES
extern int DEBUGLEVEL;
#ifndef INADDR_NONE
-#define INADDR_NONE ((unsigned long)~0)
+#define INADDR_NONE ((uint32)~0)
#endif
-#define FROM_ADDRLEN (4*3+3+1)
#define Good True
#define Bad False
@@ -37,24 +35,17 @@ static char sep[] = ", \t";
#define FAIL (-1)
/* Forward declarations. */
-BOOL allow_access(char *deny_list,char *allow_list,struct from_host *client);
static int list_match(char *list,char *item, int (*match_fn)());
static int client_match(char *tok,char *item);
static int string_match(char *tok,char *s);
static int masked_match(char *tok, char *slash, char *s);
-static int matchname(char *remotehost,struct in_addr addr);
-BOOL fromhost(int sock,struct from_host *f);
-
/* Size of logical line buffer. */
#define BUFLEN 2048
-
/* return true if access should be allowed to a service*/
BOOL check_access(int snum)
{
- extern int Client;
- extern struct from_host Client_info;
char *denyl,*allowl;
BOOL ret = False;
@@ -64,32 +55,24 @@ BOOL check_access(int snum)
allowl = lp_hostsallow(snum);
if (allowl) allowl = strdup(allowl);
-
- fromhost(Client,&Client_info);
-
if ((!denyl || *denyl==0) && (!allowl || *allowl==0))
ret = True;
if (!ret)
{
- if (!fromhost(Client,&Client_info))
- DEBUG(0,("ERROR: Can't get from_host info\n"));
- else
+ if (allow_access(denyl,allowl,client_name(),client_addr()))
{
- if (allow_access(denyl,allowl,&Client_info))
- {
- if (snum >= 0)
- DEBUG(2,("Allowed connection from %s (%s) to %s\n",
- Client_info.name,Client_info.addr,
- lp_servicename(snum)));
- ret = True;
- }
- else
- if (snum >= 0)
- DEBUG(0,("Denied connection from %s (%s) to %s\n",
- Client_info.name,Client_info.addr,
- lp_servicename(snum)));
+ if (snum >= 0)
+ DEBUG(2,("Allowed connection from %s (%s) to %s\n",
+ client_name(),client_addr(),
+ lp_servicename(snum)));
+ ret = True;
}
+ else
+ if (snum >= 0)
+ DEBUG(0,("%s Denied connection from %s (%s) to %s\n",
+ timestring(), client_name(),client_addr(),
+ lp_servicename(snum)));
}
if (denyl) free(denyl);
@@ -99,8 +82,13 @@ BOOL check_access(int snum)
/* return true if access should be allowed */
-BOOL allow_access(char *deny_list,char *allow_list,struct from_host *client)
+BOOL allow_access(char *deny_list,char *allow_list,char *cname,char *caddr)
{
+ char *client[2];
+
+ client[0] = cname;
+ client[1] = caddr;
+
/* if theres no deny list and no allow list then allow access */
if ((!deny_list || *deny_list == 0) && (!allow_list || *allow_list == 0))
return(True);
@@ -175,7 +163,7 @@ static int list_match(char *list,char *item, int (*match_fn)())
/* client_match - match host name and address against token */
static int client_match(char *tok,char *item)
{
- struct from_host *client = (struct from_host *) item;
+ char **client = (char **)item;
int match;
/*
@@ -183,9 +171,9 @@ static int client_match(char *tok,char *item)
* name if available.
*/
- if ((match = string_match(tok, client->addr)) == 0)
- if (client->name[0] != 0)
- match = string_match(tok, client->name);
+ if ((match = string_match(tok, client[1])) == 0)
+ if (client[0][0] != 0)
+ match = string_match(tok, client[0]);
return (match);
}
@@ -221,6 +209,10 @@ static int string_match(char *tok,char *s)
if (!mydomain) yp_get_default_domain(&mydomain);
+ if (!mydomain) {
+ DEBUG(0,("Unable to get default yp domain.\n"));
+ return NO;
+ }
if (!(hostname = strdup(s))) {
DEBUG(1,("out of memory for strdup!\n"));
return NO;
@@ -251,7 +243,7 @@ static int string_match(char *tok,char *s)
if (netgroup_ok) return(YES);
#else
- DEBUG(0,("access: netgroup support is not configured"));
+ DEBUG(0,("access: netgroup support is not configured\n"));
return (NO);
#endif
} else if (strcasecmp(tok, "ALL") == 0) { /* all: match any */
@@ -276,114 +268,22 @@ static int string_match(char *tok,char *s)
/* masked_match - match address against netnumber/netmask */
static int masked_match(char *tok, char *slash, char *s)
{
- unsigned long net;
- unsigned long mask;
- unsigned long addr;
-
- if ((addr = interpret_addr(s)) == INADDR_NONE)
- return (NO);
- *slash = 0;
- net = interpret_addr(tok);
- *slash = '/';
- if (net == INADDR_NONE || (mask = interpret_addr(slash + 1)) == INADDR_NONE) {
- DEBUG(0,("access: bad net/mask access control: %s", tok));
- return (NO);
- }
- return ((addr & mask) == net);
-}
-
+ uint32 net;
+ uint32 mask;
+ uint32 addr;
-/* fromhost - find out what is at the other end of a socket */
-BOOL fromhost(int sock,struct from_host *f)
-{
- static struct sockaddr sa;
- struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
- struct hostent *hp;
- int length = sizeof(sa);
- static char addr_buf[FROM_ADDRLEN];
- static char name_buf[MAXHOSTNAMELEN];
- BOOL takeAddressAsHostname = False;
-
- if (getpeername(sock, &sa, &length) < 0)
- {
- DEBUG(0,("getpeername failed\n"));
- return(False);
- }
-
- f->sin = sockin;
- f->addr = strcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr));
-
- /* Look up the remote host name. */
- if ((hp = gethostbyaddr((char *) &sockin->sin_addr,
- sizeof(sockin->sin_addr),
- AF_INET)) == 0) {
- DEBUG(1,("Gethostbyaddr failed for %s\n",addr_buf));
-#ifdef ALLOW_PURE_ADDRESSES
- takeAddressAsHostname = True;
-#else
- return(False);
-#endif
- }
-
- /* Save the host name. A later gethostbyxxx() call may clobber it. */
- f->name = StrnCpy(name_buf,
- takeAddressAsHostname? f->addr : hp->h_name,
- sizeof(name_buf) - 1);
-
- /*
- * Verify that the host name does not belong to someone else. If host
- * name verification fails, pretend that the host name lookup failed.
- */
- if (!takeAddressAsHostname && !matchname(f->name, sockin->sin_addr))
- {
- DEBUG(0,("Matchname failed\n"));
- return(False);
- }
-
- return(True);
+ if ((addr = interpret_addr(s)) == INADDR_NONE)
+ return (NO);
+ *slash = 0;
+ net = interpret_addr(tok);
+ *slash = '/';
+ if (net == INADDR_NONE || (mask = interpret_addr(slash + 1)) == INADDR_NONE) {
+ DEBUG(0,("access: bad net/mask access control: %s", tok));
+ return (NO);
+ }
+ return ((addr & mask) == net);
}
-/* matchname - determine if host name matches IP address */
-static int matchname(char *remotehost,struct in_addr addr)
-{
- struct hostent *hp;
- int i;
-
- if ((hp = Get_Hostbyname(remotehost)) == 0) {
- DEBUG(0,("Get_Hostbyname(%s): lookup failure", remotehost));
- return (Bad);
- }
- /*
- * Make sure that gethostbyname() returns the "correct" host name.
- * Unfortunately, gethostbyname("localhost") sometimes yields
- * "localhost.domain". Since the latter host name comes from the
- * local DNS, we just have to trust it (all bets are off if the local
- * DNS is perverted). We always check the address list, though.
- */
-
- if (strcasecmp(remotehost, hp->h_name)
- && strcasecmp(remotehost, "localhost")) {
- DEBUG(0,("host name/name mismatch: %s != %s",
- remotehost, hp->h_name));
- return (Bad);
- }
-
- /* Look up the host address in the address list we just got. */
- for (i = 0; hp->h_addr_list[i]; i++) {
- if (memcmp(hp->h_addr_list[i], (caddr_t) & addr, sizeof(addr)) == 0)
- return (Good);
- }
-
- /*
- * The host name does not map to the original host address. Perhaps
- * someone has compromised a name server. More likely someone botched
- * it, but that could be dangerous, too.
- */
-
- DEBUG(0,("host name/address mismatch: %s != %s",
- inet_ntoa(addr), hp->h_name));
- return (Bad);
-}
diff --git a/source/lib/charcnv.c b/source/lib/charcnv.c
index 049390f2a43..a7dff4224be 100644
--- a/source/lib/charcnv.c
+++ b/source/lib/charcnv.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Character set conversion Extensions
- Copyright (C) Andrew Tridgell 1992-1994
+ Copyright (C) Andrew Tridgell 1992-1997
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,11 +20,12 @@
*/
#include "includes.h"
+#define CTRLZ 26
extern int DEBUGLEVEL;
static char cvtbuf[1024];
-static mapsinited = 0;
+static BOOL mapsinited = 0;
static char unix2dos[256];
static char dos2unix[256];
@@ -35,7 +36,7 @@ static void initmaps() {
for (k = 0; k < 256; k++) unix2dos[k] = k;
for (k = 0; k < 256; k++) dos2unix[k] = k;
- mapsinited = 1;
+ mapsinited = True;
}
static void update_map(char * str) {
@@ -50,61 +51,98 @@ static void update_map(char * str) {
}
}
-static void initiso() {
+static void init_iso8859_1() {
+ int i;
if (!mapsinited) initmaps();
- update_map("\241\255\242\233\243\234\244\236\245\235\246\272\247\025\250\251");
- update_map("\251\273\252\246\253\256\254\252\255\274\256\310\257\257\260\370");
- update_map("\261\361\262\375\263\264\264\265\265\266\266\024\267\371\270\267");
- update_map("\271\270\272\247\273\275\274\254\275\253\276\276\277\250\200\277");
- update_map("\301\300\302\301\303\302\304\216\305\217\306\222\307\200\310\303");
- update_map("\311\220\312\305\313\306\314\307\315\315\316\317\317\320\320\311");
- update_map("\321\245\322\321\323\322\324\323\325\324\326\231\327\312\330\325");
- update_map("\331\326\332\327\333\330\334\232\335\313\336\314\337\341\340\205");
- update_map("\341\240\342\203\343\331\344\204\345\206\346\221\347\207\350\212");
- update_map("\351\202\352\210\353\211\354\215\355\241\356\214\357\213\360\316");
- update_map("\361\244\362\225\363\242\364\223\365\332\366\224\367\366\370\362");
- update_map("\371\227\372\243\373\226\374\201\375\304\376\263\377\230");
+ /* Do not map undefined characters to some accidental code */
+ for (i = 128; i < 256; i++)
+ {
+ unix2dos[i] = CTRLZ;
+ dos2unix[i] = CTRLZ;
+ }
+
+/* MSDOS Code Page 850 -> ISO-8859 */
+update_map("\240\377\241\255\242\275\243\234\244\317\245\276\246\335\247\365");
+update_map("\250\371\251\270\252\246\253\256\254\252\255\360\256\251\257\356");
+update_map("\260\370\261\361\262\375\263\374\264\357\265\346\266\364\267\372");
+update_map("\270\367\271\373\272\247\273\257\274\254\275\253\276\363\277\250");
+update_map("\300\267\301\265\302\266\303\307\304\216\305\217\306\222\307\200");
+update_map("\310\324\311\220\312\322\313\323\314\336\315\326\316\327\317\330");
+update_map("\320\321\321\245\322\343\323\340\324\342\325\345\326\231\327\236");
+update_map("\330\235\331\353\332\351\333\352\334\232\335\355\336\350\337\341");
+update_map("\340\205\341\240\342\203\343\306\344\204\345\206\346\221\347\207");
+update_map("\350\212\351\202\352\210\353\211\354\215\355\241\356\214\357\213");
+update_map("\360\320\361\244\362\225\363\242\364\223\365\344\366\224\367\366");
+update_map("\370\233\371\227\372\243\373\226\374\201\375\354\376\347\377\230");
+
+}
+
+/* Init for eastern european languages. May need more work ? */
+
+static void init_iso8859_2() {
+
+ int i;
+ if (!mapsinited) initmaps();
+
+ /* Do not map undefined characters to some accidental code */
+ for (i = 128; i < 256; i++)
+ {
+ unix2dos[i] = CTRLZ;
+ dos2unix[i] = CTRLZ;
+ }
+
+update_map("\241\244\306\217\312\250\243\235\321\343\323\340\246\227\254\215");
+update_map("\257\275\261\245\346\206\352\251\263\210\361\344\363\242\266\230");
+update_map("\274\253\277\276");
}
/*
* Convert unix to dos
*/
-char *
-unix2dos_format(char *str,BOOL overwrite)
+char *unix2dos_format(char *str,BOOL overwrite)
{
char *p;
char *dp;
if (!mapsinited) initmaps();
- if (overwrite) {
- for (p = str; *p; p++) *p = unix2dos[(unsigned char)*p];
- return str;
- } else {
- for (p = str, dp = cvtbuf; *p; p++,dp++) *dp = unix2dos[(unsigned char)*p];
- *dp = 0;
- return cvtbuf;
+
+ if(lp_client_code_page() == KANJI_CODEPAGE)
+ return (*_unix_to_dos)(str, overwrite);
+ else {
+ if (overwrite) {
+ for (p = str; *p; p++) *p = unix2dos[(unsigned char)*p];
+ return str;
+ } else {
+ for (p = str, dp = cvtbuf; *p; p++,dp++) *dp = unix2dos[(unsigned char)*p];
+ *dp = 0;
+ return cvtbuf;
+ }
}
}
/*
* Convert dos to unix
*/
-char *
-dos2unix_format (char *str, BOOL overwrite)
+char *dos2unix_format(char *str, BOOL overwrite)
{
char *p;
char *dp;
if (!mapsinited) initmaps();
- if (overwrite) {
- for (p = str; *p; p++) *p = dos2unix[(unsigned char)*p];
- return str;
- } else {
- for (p = str, dp = cvtbuf; *p; p++,dp++) *dp = dos2unix[(unsigned char)*p];
- *dp = 0;
- return cvtbuf;
+
+ if(lp_client_code_page() == KANJI_CODEPAGE)
+ return (*_dos_to_unix)(str, overwrite);
+ else {
+ if (overwrite) {
+ for (p = str; *p; p++) *p = dos2unix[(unsigned char)*p];
+ return str;
+ } else {
+ for (p = str, dp = cvtbuf; *p; p++,dp++) *dp = dos2unix[(unsigned char)*p];
+ *dp = 0;
+ return cvtbuf;
+ }
}
}
@@ -112,13 +150,13 @@ 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")) {
- initiso();
- return def;
+ init_iso8859_1();
+ } else if (strequal (str, "iso8859-2")) {
+ init_iso8859_2();
} else {
DEBUG(0,("unrecognized character set\n"));
}
diff --git a/source/lib/charset.c b/source/lib/charset.c
index ada3ef790aa..4869e09fecf 100644
--- a/source/lib/charset.c
+++ b/source/lib/charset.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Character set handling
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1997
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
@@ -24,67 +24,339 @@
extern int DEBUGLEVEL;
+/*
+ * Codepage definitions.
+ */
+
+#if !defined(KANJI)
+/* lower->upper mapping for IBM Code Page 850 - MS-DOS Latin 1 */
+unsigned char cp_850[][4] = {
+/* dec col/row oct hex description */
+/* 133 08/05 205 85 a grave */
+/* 183 11/07 267 B7 A grave */ {0x85,0xB7,1,1},
+/* 160 10/00 240 A0 a acute */
+/* 181 11/05 265 B5 A acute */ {0xA0,0xB5,1,1},
+/* 131 08/03 203 83 a circumflex */
+/* 182 11/06 266 B6 A circumflex */ {0x83,0xB6,1,1},
+/* 198 12/06 306 C6 a tilde */
+/* 199 12/07 307 C7 A tilde */ {0xC6,0xC7,1,1},
+/* 132 08/04 204 84 a diaeresis */
+/* 142 08/14 216 8E A diaeresis */ {0x84,0x8E,1,1},
+/* 134 08/06 206 86 a ring */
+/* 143 08/15 217 8F A ring */ {0x86,0x8F,1,1},
+/* 145 09/01 221 91 ae diphthong */
+/* 146 09/02 222 92 AE diphthong */ {0x91,0x92,1,1},
+/* 135 08/07 207 87 c cedilla */
+/* 128 08/00 200 80 C cedilla */ {0x87,0x80,1,1},
+/* 138 08/10 212 8A e grave */
+/* 212 13/04 324 D4 E grave */ {0x8A,0xD4,1,1},
+/* 130 08/02 202 82 e acute */
+/* 144 09/00 220 90 E acute */ {0x82,0x90,1,1},
+/* 136 08/08 210 88 e circumflex */
+/* 210 13/02 322 D2 E circumflex */ {0x88,0xD2,1,1},
+/* 137 08/09 211 89 e diaeresis */
+/* 211 13/03 323 D3 E diaeresis */ {0x89,0xD3,1,1},
+/* 141 08/13 215 8D i grave */
+/* 222 13/14 336 DE I grave */ {0x8D,0xDE,1,1},
+/* 161 10/01 241 A1 i acute */
+/* 214 13/06 326 D6 I acute */ {0xA1,0xD6,1,1},
+/* 140 08/12 214 8C i circumflex */
+/* 215 13/07 327 D7 I circumflex */ {0x8C,0xD7,1,1},
+/* 139 08/11 213 8B i diaeresis */
+/* 216 13/08 330 D8 I diaeresis */ {0x8B,0xD8,1,1},
+/* 208 13/00 320 D0 Icelandic eth */
+/* 209 13/01 321 D1 Icelandic Eth */ {0xD0,0xD1,1,1},
+/* 164 10/04 244 A4 n tilde */
+/* 165 10/05 245 A5 N tilde */ {0xA4,0xA5,1,1},
+/* 149 09/05 225 95 o grave */
+/* 227 14/03 343 E3 O grave */ {0x95,0xE3,1,1},
+/* 162 10/02 242 A2 o acute */
+/* 224 14/00 340 E0 O acute */ {0xA2,0xE0,1,1},
+/* 147 09/03 223 93 o circumflex */
+/* 226 14/02 342 E2 O circumflex */ {0x93,0xE2,1,1},
+/* 228 14/04 344 E4 o tilde */
+/* 229 14/05 345 E5 O tilde */ {0xE4,0xE5,1,1},
+/* 148 09/04 224 94 o diaeresis */
+/* 153 09/09 231 99 O diaeresis */ {0x94,0x99,1,1},
+/* 155 09/11 233 9B o slash */
+/* 157 09/13 235 9D O slash */ {0x9B,0x9D,1,1},
+/* 151 09/07 227 97 u grave */
+/* 235 14/11 353 EB U grave */ {0x97,0xEB,1,1},
+/* 163 10/03 243 A3 u acute */
+/* 233 14/09 351 E9 U acute */ {0xA3,0xE9,1,1},
+/* 150 09/06 226 96 u circumflex */
+/* 234 14/10 352 EA U circumflex */ {0x96,0xEA,1,1},
+/* 129 08/01 201 81 u diaeresis */
+/* 154 09/10 232 9A U diaeresis */ {0x81,0x9A,1,1},
+/* 236 14/12 354 EC y acute */
+/* 237 14/13 355 ED Y acute */ {0xEC,0xED,1,1},
+/* 231 14/07 347 E7 Icelandic thorn */
+/* 232 14/08 350 E8 Icelandic Thorn */ {0xE7,0xE8,1,1},
+
+ {0x9C,0,0,0}, /* Pound */
+ {0,0,0,0}
+};
+#else /* KANJI */
+/* lower->upper mapping for IBM Code Page 932 - MS-DOS Japanese SJIS */
+unsigned char cp_932[][4] = {
+ {0,0,0,0}
+};
+#endif /* KANJI */
+
char xx_dos_char_map[256];
char xx_upper_char_map[256];
char xx_lower_char_map[256];
-char *dos_char_map = NULL;
-char *upper_char_map = NULL;
-char *lower_char_map = NULL;
+char *dos_char_map = xx_dos_char_map;
+char *upper_char_map = xx_upper_char_map;
+char *lower_char_map = xx_lower_char_map;
+
+/*
+ * This code has been extended to deal with ascynchronous mappings
+ * like MS-DOS Latin US (Code page 437) where things like :
+ * a acute are capitalized to 'A', but the reverse mapping
+ * must not hold true. This allows the filename case insensitive
+ * matching in do_match() to work, as the DOS/Win95/NT client
+ * uses 'A' as a mask to match against characters like a acute.
+ * This is the meaning behind the parameters that allow a
+ * mapping from lower to upper, but not upper to lower.
+ */
-static void add_dos_char(int lower, int upper)
+static void add_dos_char(int lower, BOOL map_lower_to_upper,
+ int upper, BOOL map_upper_to_lower)
{
- DEBUG(6,("Adding chars 0%o 0%o\n",lower,upper));
- if (lower) dos_char_map[(char)lower] = 1;
- if (upper) dos_char_map[(char)upper] = 1;
+ lower &= 0xff;
+ upper &= 0xff;
+ DEBUG(6,("Adding chars 0x%x 0x%x (l->u = %s) (u->l = %s)\n",lower,upper,
+ map_lower_to_upper ? "True" : "False",
+ map_upper_to_lower ? "True" : "False"));
+ if (lower) dos_char_map[lower] = 1;
+ if (upper) dos_char_map[upper] = 1;
if (lower && upper) {
- lower_char_map[(char)upper] = (char)lower;
- upper_char_map[(char)lower] = (char)upper;
+ if(map_upper_to_lower)
+ lower_char_map[upper] = (char)lower;
+ if(map_lower_to_upper)
+ upper_char_map[lower] = (char)upper;
}
}
/****************************************************************************
initialise the charset arrays
****************************************************************************/
-void charset_initialise(void)
+void charset_initialise()
{
int i;
- dos_char_map = &xx_dos_char_map[128];
- upper_char_map = &xx_upper_char_map[128];
- lower_char_map = &xx_lower_char_map[128];
+#ifdef LC_ALL
+ /* include <locale.h> in includes.h if available for OS */
+ /* we take only standard 7-bit ASCII definitions from ctype */
+ setlocale(LC_ALL,"C");
+#endif
- for (i= -128;i<=127;i++) {
- dos_char_map[(char)i] = 0;
+ for (i= 0;i<=255;i++) {
+ dos_char_map[i] = 0;
}
for (i=0;i<=127;i++) {
if (isalnum((char)i) || strchr("._^$~!#%&-{}()@'`",(char)i))
- add_dos_char(i,0);
+ add_dos_char(i,False,0,False);
}
- for (i= -128;i<=127;i++) {
+ for (i=0; i<=255; i++) {
char c = (char)i;
upper_char_map[i] = lower_char_map[i] = c;
- if (isupper(c)) lower_char_map[c] = tolower(c);
- if (islower(c)) upper_char_map[c] = toupper(c);
- }
-
- /* valid for all DOS PC */
- add_dos_char(142,0); /* A trema */
- add_dos_char(143,0); /* A o */
- add_dos_char(144,0); /* E ' */
- add_dos_char(146,0); /* AE */
- add_dos_char(153,0); /* O trema */
- add_dos_char(154,0); /* U trema */
- add_dos_char(165,0); /* N tilda */
- add_dos_char(128,0); /* C cedille */
- add_dos_char(156,0); /* Pound */
- add_dos_char(183,0); /* A ` (WIN)*/
- add_dos_char(157,0); /* Phi (WIN)*/
- add_dos_char(212,0); /* E` (WIN)*/
+ if (isupper(c)) lower_char_map[i] = tolower(c);
+ if (islower(c)) upper_char_map[i] = toupper(c);
+ }
+}
+
+/****************************************************************************
+load the client codepage.
+****************************************************************************/
+
+typedef unsigned char (*codepage_p)[4];
+
+static codepage_p load_client_codepage( int client_codepage )
+{
+ pstring codepage_file_name;
+ unsigned char buf[8];
+ FILE *fp = NULL;
+ unsigned int size;
+ codepage_p cp_p = NULL;
+ struct stat st;
+
+ DEBUG(5, ("load_client_codepage: loading codepage %d.\n", client_codepage));
+
+ if(strlen(CODEPAGEDIR) + 14 > sizeof(codepage_file_name))
+ {
+ DEBUG(0,("load_client_codepage: filename too long to load\n"));
+ return NULL;
+ }
+
+ strcpy(codepage_file_name, CODEPAGEDIR);
+ strcat(codepage_file_name, "/");
+ strcat(codepage_file_name, "codepage.");
+ sprintf( &codepage_file_name[strlen(codepage_file_name)], "%03d",
+ client_codepage);
+
+ if(!file_exist(codepage_file_name,&st))
+ {
+ DEBUG(0,("load_client_codepage: filename %s does not exist.\n",
+ codepage_file_name));
+ return NULL;
+ }
+
+ /* Check if it is at least big enough to hold the required
+ data. Should be 2 byte version, 2 byte codepage, 4 byte length,
+ plus zero or more bytes of data. Note that the data cannot be more
+ than 512 bytes - giving a max size of 520.
+ */
+ size = (unsigned int)st.st_size;
+
+ if( size < CODEPAGE_HEADER_SIZE || size > (CODEPAGE_HEADER_SIZE + 256))
+ {
+ DEBUG(0,("load_client_codepage: file %s is an incorrect size for a \
+code page file.\n", codepage_file_name));
+ return NULL;
+ }
+
+ /* Read the first 8 bytes of the codepage file - check
+ the version number and code page number. All the data
+ is held in little endian format.
+ */
+
+ if((fp = fopen( codepage_file_name, "r")) == NULL)
+ {
+ DEBUG(0,("load_client_codepage: cannot open file %s. Error was %s\n",
+ codepage_file_name, strerror(errno)));
+ return NULL;
+ }
+
+ if(fread( buf, 1, CODEPAGE_HEADER_SIZE, fp)!=CODEPAGE_HEADER_SIZE)
+ {
+ DEBUG(0,("load_client_codepage: cannot read header from file %s. Error was %s\n",
+ codepage_file_name, strerror(errno)));
+ goto clean_and_exit;
+ }
+
+ /* Check the version value */
+ if(SVAL(buf,CODEPAGE_VERSION_OFFSET) != CODEPAGE_FILE_VERSION_ID)
+ {
+ DEBUG(0,("load_client_codepage: filename %s has incorrect version id. \
+Needed %hu, got %hu.\n",
+ codepage_file_name, (uint16)CODEPAGE_FILE_VERSION_ID,
+ SVAL(buf,CODEPAGE_VERSION_OFFSET)));
+ goto clean_and_exit;
+ }
+
+ /* Check the codepage matches */
+ if(SVAL(buf,CODEPAGE_CLIENT_CODEPAGE_OFFSET) != (uint16)client_codepage)
+ {
+ DEBUG(0,("load_client_codepage: filename %s has incorrect codepage. \
+Needed %hu, got %hu.\n",
+ codepage_file_name, (uint16)client_codepage,
+ SVAL(buf,CODEPAGE_CLIENT_CODEPAGE_OFFSET)));
+ goto clean_and_exit;
+ }
+
+ /* Check the length is correct. */
+ if(IVAL(buf,CODEPAGE_LENGTH_OFFSET) !=
+ (unsigned int)(size - CODEPAGE_HEADER_SIZE))
+ {
+ DEBUG(0,("load_client_codepage: filename %s has incorrect size headers. \
+Needed %u, got %u.\n", codepage_file_name, size - CODEPAGE_HEADER_SIZE,
+ IVAL(buf,CODEPAGE_LENGTH_OFFSET)));
+ goto clean_and_exit;
+ }
+
+ size -= CODEPAGE_HEADER_SIZE; /* Remove header */
+
+ /* Make sure the size is a multiple of 4. */
+ if((size % 4 ) != 0)
+ {
+ DEBUG(0,("load_client_codepage: filename %s has a codepage size not a \
+multiple of 4.\n", codepage_file_name));
+ goto clean_and_exit;
+ }
+
+ /* Allocate space for the code page file and read it all in. */
+ if((cp_p = (codepage_p)malloc( size + 4 )) == NULL)
+ {
+ DEBUG(0,("load_client_codepage: malloc fail.\n"));
+ goto clean_and_exit;
+ }
+
+ if(fread( (char *)cp_p, 1, size, fp)!=size)
+ {
+ DEBUG(0,("load_client_codepage: read fail on file %s. Error was %s.\n",
+ codepage_file_name, strerror(errno)));
+ goto clean_and_exit;
+ }
+
+ /* Ensure array is correctly terminated. */
+ memset(((char *)cp_p) + size, '\0', 4);
+
+ fclose(fp);
+ return cp_p;
+
+clean_and_exit:
+
+ /* pseudo destructor :-) */
+
+ if(fp != NULL)
+ fclose(fp);
+ if(cp_p)
+ free((char *)cp_p);
+ return NULL;
}
+/****************************************************************************
+initialise the client codepage.
+****************************************************************************/
+void codepage_initialise(int client_codepage)
+{
+ int i;
+ codepage_p cp = NULL;
+ static BOOL done = False;
+
+ if(done == True)
+ {
+ DEBUG(6,
+ ("codepage_initialise: called twice - ignoring second client code page = %d\n",
+ client_codepage));
+ return;
+ }
+
+ DEBUG(6,("codepage_initialise: client code page = %d\n", client_codepage));
+
+ /*
+ * Known client codepages - these can be added to.
+ */
+ cp = load_client_codepage( client_codepage );
+
+ if(cp == NULL)
+ {
+#ifdef KANJI
+ DEBUG(6,("codepage_initialise: loading dynamic codepage file %s/codepage.%d \
+for code page %d failed. Using default client codepage 932\n",
+ CODEPAGEDIR, client_codepage, client_codepage));
+ cp = cp_932;
+#else /* KANJI */
+ DEBUG(6,("codepage_initialise: loading dynamic codepage file %s/codepage.%d \
+for code page %d failed. Using default client codepage 850\n",
+ CODEPAGEDIR, client_codepage, client_codepage));
+ cp = cp_850;
+#endif /* KANJI */
+ }
+
+ if(cp)
+ {
+ for(i = 0; !((cp[i][0] == '\0') && (cp[i][1] == '\0')); i++)
+ add_dos_char(cp[i][0], (BOOL)cp[i][2], cp[i][1], (BOOL)cp[i][3]);
+ }
+
+ done = True;
+}
/*******************************************************************
add characters depending on a string passed by the user
@@ -98,12 +370,12 @@ void add_char_string(char *s)
for (t=strtok(extra_chars," \t\r\n"); t; t=strtok(NULL," \t\r\n")) {
char c1=0,c2=0;
int i1=0,i2=0;
- if (isdigit(*t) || (*t)=='-') {
+ if (isdigit((unsigned char)*t) || (*t)=='-') {
sscanf(t,"%i:%i",&i1,&i2);
- add_dos_char(i1,i2);
+ add_dos_char(i1,True,i2,True);
} else {
sscanf(t,"%c:%c",&c1,&c2);
- add_dos_char(c1,c2);
+ add_dos_char((unsigned char)c1,True,(unsigned char)c2, True);
}
}
diff --git a/source/lib/fault.c b/source/lib/fault.c
index 20c75f7876c..61715a4f225 100644
--- a/source/lib/fault.c
+++ b/source/lib/fault.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Critical Fault handling
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1997
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
@@ -19,10 +19,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#ifdef LINUX
-#define __KERNEL__
-#endif
-
#include "includes.h"
extern int DEBUGLEVEL;
diff --git a/source/lib/getsmbpass.c b/source/lib/getsmbpass.c
index 07a7dbfd9b5..e8cb683d0b1 100644
--- a/source/lib/getsmbpass.c
+++ b/source/lib/getsmbpass.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
+/* Copyright (C) 1992-1997 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -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, 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, struct sgttyb *t)
{
return ioctl(fd, TIOCSETP, (char *)t);
}
@@ -92,8 +92,7 @@ static struct termios t;
#endif /* BSD_TERMIO */
#endif /* SYSV_TERMIO */
-char *
-getsmbpass(char *prompt)
+char *getsmbpass(char *prompt)
{
FILE *in, *out;
int echo_off;
@@ -162,5 +161,5 @@ getsmbpass(char *prompt)
#else
-void getsmbpasswd_dummy() {;}
+ void getsmbpasswd_dummy() {;}
#endif
diff --git a/source/lib/interface.c b/source/lib/interface.c
new file mode 100644
index 00000000000..3b038dcda69
--- /dev/null
+++ b/source/lib/interface.c
@@ -0,0 +1,477 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ multiple interface handling
+ Copyright (C) Andrew Tridgell 1992-1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+struct in_addr ipzero;
+struct in_addr wins_ip;
+struct in_addr loopback_ip;
+static struct in_addr default_ip;
+static struct in_addr default_bcast;
+static struct in_addr default_nmask;
+static BOOL got_ip=False;
+static BOOL got_bcast=False;
+static BOOL got_nmask=False;
+
+struct interface *local_interfaces = NULL;
+
+struct interface *last_iface;
+
+/****************************************************************************
+calculate the default netmask for an address
+****************************************************************************/
+static void default_netmask(struct in_addr *inm, struct in_addr *iad)
+{
+ uint32 ad = ntohl(iad->s_addr);
+ uint32 nm;
+ /*
+ ** Guess a netmask based on the class of the IP address given.
+ */
+ if ( (ad & 0x80000000) == 0 ) {
+ /* class A address */
+ nm = 0xFF000000;
+ } else if ( (ad & 0xC0000000) == 0x80000000 ) {
+ /* class B address */
+ nm = 0xFFFF0000;
+ } else if ( (ad & 0xE0000000) == 0xC0000000 ) {
+ /* class C address */
+ nm = 0xFFFFFF00;
+ } else {
+ /* class D or E; netmask doesn't make much sense - guess 4 bits */
+ nm = 0xFFFFFFF0;
+ }
+ inm->s_addr = htonl(nm);
+}
+
+
+/****************************************************************************
+ get the broadcast address for our address
+(troyer@saifr00.ateng.az.honeywell.com)
+****************************************************************************/
+static void get_broadcast(struct in_addr *if_ipaddr,
+ struct in_addr *if_bcast,
+ struct in_addr *if_nmask)
+{
+ BOOL found = False;
+#ifndef NO_GET_BROADCAST
+ int sock = -1; /* AF_INET raw socket desc */
+ char buff[1024];
+ struct ifreq *ifr=NULL;
+ int i;
+
+#if defined(EVEREST)
+ int n_interfaces;
+ struct ifconf ifc;
+ struct ifreq *ifreqs;
+#elif defined(USE_IFREQ)
+ struct ifreq ifreq;
+ struct strioctl strioctl;
+ struct ifconf *ifc;
+#else
+ struct ifconf ifc;
+#endif
+#endif
+
+ /* get a default netmask and broadcast */
+ default_netmask(if_nmask, if_ipaddr);
+
+#ifndef NO_GET_BROADCAST
+ /* Create a socket to the INET kernel. */
+#if USE_SOCKRAW
+ if ((sock = socket(AF_INET, SOCK_RAW, PF_INET )) < 0)
+#else
+ if ((sock = socket(AF_INET, SOCK_DGRAM, 0 )) < 0)
+#endif
+ {
+ DEBUG(0,( "Unable to open socket to get broadcast address\n"));
+ return;
+ }
+
+ /* Get a list of the configured interfaces */
+#ifdef EVEREST
+ /* This is part of SCO Openserver 5: The ioctls are no longer part
+ if the lower level STREAMS interface glue. They are now real
+ ioctl calls */
+
+ if (ioctl(sock, SIOCGIFANUM, &n_interfaces) < 0) {
+ DEBUG(0,( "SIOCGIFANUM: %s\n", strerror(errno)));
+ } else {
+ DEBUG(0,( "number of interfaces returned is: %d\n", n_interfaces));
+
+ ifc.ifc_len = sizeof(struct ifreq) * n_interfaces;
+ ifc.ifc_buf = (caddr_t) alloca(ifc.ifc_len);
+
+ if (ioctl(sock, SIOCGIFCONF, &ifc) < 0)
+ DEBUG(0, ( "SIOCGIFCONF: %s\n", strerror(errno)));
+ else {
+ ifr = ifc.ifc_req;
+
+ for (i = 0; i < n_interfaces; ++i) {
+ if (if_ipaddr->s_addr ==
+ ((struct sockaddr_in *) &ifr[i].ifr_addr)->sin_addr.s_addr) {
+ found = True;
+ break;
+ }
+ }
+ }
+ }
+#elif defined(USE_IFREQ)
+ ifc = (struct ifconf *)buff;
+ ifc->ifc_len = BUFSIZ - sizeof(struct ifconf);
+ strioctl.ic_cmd = SIOCGIFCONF;
+ strioctl.ic_dp = (char *)ifc;
+ strioctl.ic_len = sizeof(buff);
+ if (ioctl(sock, I_STR, &strioctl) < 0) {
+ DEBUG(0,( "I_STR/SIOCGIFCONF: %s\n", strerror(errno)));
+ } else {
+ ifr = (struct ifreq *)ifc->ifc_req;
+
+ /* Loop through interfaces, looking for given IP address */
+ for (i = ifc->ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) {
+ if (if_ipaddr->s_addr ==
+ (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) {
+ found = True;
+ break;
+ }
+ }
+ }
+#elif defined(__FreeBSD__) || defined(NETBSD) || defined(AMIGA) || defined(_AIX41)
+ ifc.ifc_len = sizeof(buff);
+ ifc.ifc_buf = buff;
+ if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
+ DEBUG(0,("SIOCGIFCONF: %s\n", strerror(errno)));
+ } else {
+ ifr = ifc.ifc_req;
+ /* Loop through interfaces, looking for given IP address */
+ i = ifc.ifc_len;
+ while (i > 0) {
+ if (if_ipaddr->s_addr ==
+ (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) {
+ found = True;
+ break;
+ }
+ i -= ifr->ifr_addr.sa_len + IFNAMSIZ;
+ ifr = (struct ifreq*) ((char*) ifr + ifr->ifr_addr.sa_len + IFNAMSIZ);
+ }
+ }
+#else
+ ifc.ifc_len = sizeof(buff);
+ ifc.ifc_buf = buff;
+ if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
+ DEBUG(0,("SIOCGIFCONF: %s\n", strerror(errno)));
+ } else {
+ ifr = ifc.ifc_req;
+
+ /* Loop through interfaces, looking for given IP address */
+ for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) {
+#ifdef BSDI
+ if (ioctl(sock, SIOCGIFADDR, ifr) < 0) break;
+#endif
+ if (if_ipaddr->s_addr ==
+ (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) {
+ found = True;
+ break;
+ }
+ }
+ }
+#endif
+
+ if (!found) {
+ DEBUG(0,("No interface found for address %s\n", inet_ntoa(*if_ipaddr)));
+ } else {
+ /* Get the netmask address from the kernel */
+#ifdef USE_IFREQ
+ ifreq = *ifr;
+
+ strioctl.ic_cmd = SIOCGIFNETMASK;
+ strioctl.ic_dp = (char *)&ifreq;
+ strioctl.ic_len = sizeof(struct ifreq);
+ if (ioctl(sock, I_STR, &strioctl) < 0)
+ DEBUG(0,("Failed I_STR/SIOCGIFNETMASK: %s\n", strerror(errno)));
+ else
+ *if_nmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
+#else
+ if (ioctl(sock, SIOCGIFNETMASK, ifr) < 0)
+ DEBUG(0,("SIOCGIFNETMASK failed\n"));
+ else
+ *if_nmask = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
+#endif
+
+ DEBUG(4,("Netmask for %s = %s\n", ifr->ifr_name,
+ inet_ntoa(*if_nmask)));
+ }
+
+ /* Close up shop */
+ (void) close(sock);
+
+#endif
+
+ /* sanity check on the netmask */
+ {
+ uint32 nm = ntohl(if_nmask->s_addr);
+ if ((nm >> 24) != 0xFF) {
+ DEBUG(0,("Impossible netmask %s - using defaults\n",inet_ntoa(*if_nmask)));
+ default_netmask(if_nmask, if_ipaddr);
+ }
+ }
+
+ /* derive the broadcast assuming a 1's broadcast, as this is what
+ all MS operating systems do, we have to comply even if the unix
+ box is setup differently */
+ {
+ uint32 ad = ntohl(if_ipaddr->s_addr);
+ uint32 nm = ntohl(if_nmask->s_addr);
+ uint32 bc = (ad & nm) | (0xffffffff & ~nm);
+ if_bcast->s_addr = htonl(bc);
+ }
+
+ DEBUG(4,("Derived broadcast address %s\n", inet_ntoa(*if_bcast)));
+} /* get_broadcast */
+
+
+
+/****************************************************************************
+load a list of network interfaces
+****************************************************************************/
+static void interpret_interfaces(char *s, struct interface **interfaces,
+ char *description)
+{
+ char *ptr = s;
+ fstring token;
+ struct interface *iface;
+ struct in_addr ip;
+
+ ipzero = *interpret_addr2("0.0.0.0");
+ wins_ip = *interpret_addr2("255.255.255.255");
+ loopback_ip = *interpret_addr2("127.0.0.1");
+
+ while (next_token(&ptr,token,NULL)) {
+ /* parse it into an IP address/netmasklength pair */
+ char *p = strchr(token,'/');
+ if (p) *p = 0;
+
+ ip = *interpret_addr2(token);
+
+ /* maybe we already have it listed */
+ {
+ struct interface *i;
+ for (i=(*interfaces);i;i=i->next)
+ if (ip_equal(ip,i->ip)) break;
+ if (i) continue;
+ }
+
+ iface = (struct interface *)malloc(sizeof(*iface));
+ if (!iface) return;
+
+ iface->ip = ip;
+
+ if (p) {
+ if (strlen(p+1)>2)
+ iface->nmask = *interpret_addr2(p+1);
+ else
+ iface->nmask.s_addr = htonl(~((1<<(32-atoi(p+1)))-1));
+ } else {
+ default_netmask(&iface->nmask,&iface->ip);
+ }
+ iface->bcast.s_addr = iface->ip.s_addr | ~iface->nmask.s_addr;
+ iface->next = NULL;
+
+ if (!(*interfaces)) {
+ (*interfaces) = iface;
+ } else {
+ last_iface->next = iface;
+ }
+ last_iface = iface;
+ DEBUG(1,("Added %s ip=%s ",description,inet_ntoa(iface->ip)));
+ DEBUG(1,("bcast=%s ",inet_ntoa(iface->bcast)));
+ DEBUG(1,("nmask=%s\n",inet_ntoa(iface->nmask)));
+ }
+
+ if (*interfaces) return;
+
+ /* setup a default interface */
+ iface = (struct interface *)malloc(sizeof(*iface));
+ if (!iface) return;
+
+ iface->next = NULL;
+
+ if (got_ip) {
+ iface->ip = default_ip;
+ } else {
+ get_myname(NULL,&iface->ip);
+ }
+
+ if (got_bcast) {
+ iface->bcast = default_bcast;
+ } else {
+ get_broadcast(&iface->ip,&iface->bcast,&iface->nmask);
+ }
+
+ if (got_nmask) {
+ iface->nmask = default_nmask;
+ iface->bcast.s_addr = iface->ip.s_addr | ~iface->nmask.s_addr;
+ }
+
+ if (iface->bcast.s_addr != (iface->ip.s_addr | ~iface->nmask.s_addr)) {
+ DEBUG(2,("Warning: inconsistant interface %s\n",inet_ntoa(iface->ip)));
+ }
+
+ iface->next = NULL;
+ (*interfaces) = last_iface = iface;
+
+ DEBUG(2,("Added interface ip=%s ",inet_ntoa(iface->ip)));
+ DEBUG(2,("bcast=%s ",inet_ntoa(iface->bcast)));
+ DEBUG(2,("nmask=%s\n",inet_ntoa(iface->nmask)));
+}
+
+
+/****************************************************************************
+load the remote and local interfaces
+****************************************************************************/
+void load_interfaces(void)
+{
+ /* add the machine's interfaces to local interface structure*/
+ interpret_interfaces(lp_interfaces(), &local_interfaces,"interface");
+}
+
+
+/****************************************************************************
+ override the defaults
+ **************************************************************************/
+void iface_set_default(char *ip,char *bcast,char *nmask)
+{
+ if (ip) {
+ got_ip = True;
+ default_ip = *interpret_addr2(ip);
+ }
+
+ if (bcast) {
+ got_bcast = True;
+ default_bcast = *interpret_addr2(bcast);
+ }
+
+ if (nmask) {
+ got_nmask = True;
+ default_nmask = *interpret_addr2(nmask);
+ }
+}
+
+
+/****************************************************************************
+ check if an IP is one of mine
+ **************************************************************************/
+BOOL ismyip(struct in_addr ip)
+{
+ struct interface *i;
+ for (i=local_interfaces;i;i=i->next)
+ if (ip_equal(i->ip,ip)) return True;
+ return False;
+}
+
+/****************************************************************************
+ check if a bcast is one of mine
+ **************************************************************************/
+BOOL ismybcast(struct in_addr bcast)
+{
+ struct interface *i;
+ for (i=local_interfaces;i;i=i->next)
+ if (ip_equal(i->bcast,bcast)) return True;
+ return False;
+}
+
+/****************************************************************************
+ check if a packet is from a local (known) net
+ **************************************************************************/
+BOOL is_local_net(struct in_addr from)
+{
+ struct interface *i;
+ for (i=local_interfaces;i;i=i->next)
+ if((from.s_addr & i->nmask.s_addr) == (i->ip.s_addr & i->nmask.s_addr))
+ return True;
+ return False;
+}
+
+/****************************************************************************
+ how many interfaces do we have
+ **************************************************************************/
+int iface_count(void)
+{
+ int ret = 0;
+ struct interface *i;
+
+ for (i=local_interfaces;i;i=i->next)
+ ret++;
+ return ret;
+}
+
+/****************************************************************************
+ return IP of the Nth interface
+ **************************************************************************/
+struct in_addr *iface_n_ip(int n)
+{
+ struct interface *i;
+
+ for (i=local_interfaces;i && n;i=i->next)
+ n--;
+
+ if (i) return &i->ip;
+ return NULL;
+}
+
+/****************************************************************************
+Try and find an interface that matches an ip. If we cannot, return NULL
+ **************************************************************************/
+static struct interface *iface_find(struct in_addr ip)
+{
+ struct interface *i;
+ if (zero_ip(ip)) return local_interfaces;
+
+ for (i=local_interfaces;i;i=i->next)
+ if (same_net(i->ip,ip,i->nmask)) return i;
+
+ return NULL;
+}
+
+/* these 3 functions return the ip/bcast/nmask for the interface
+ most appropriate for the given ip address */
+
+struct in_addr *iface_bcast(struct in_addr ip)
+{
+ struct interface *i = iface_find(ip);
+ return(i ? &i->bcast : &local_interfaces->bcast);
+}
+
+struct in_addr *iface_nmask(struct in_addr ip)
+{
+ struct interface *i = iface_find(ip);
+ return(i ? &i->nmask : &local_interfaces->nmask);
+}
+
+struct in_addr *iface_ip(struct in_addr ip)
+{
+ struct interface *i = iface_find(ip);
+ return(i ? &i->ip : &local_interfaces->ip);
+}
+
+
+
diff --git a/source/lib/kanji.c b/source/lib/kanji.c
index 0af476eb157..5d7de87248d 100644
--- a/source/lib/kanji.c
+++ b/source/lib/kanji.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Kanji Extensions
- Copyright (C) Andrew Tridgell 1992-1994
+ Copyright (C) Andrew Tridgell 1992-1997
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
@@ -23,7 +23,6 @@
and add all jis codes sequence type at 1995.8.16
Notes: Hexadecimal code by <ohki@gssm.otuka.tsukuba.ac.jp>
*/
-#ifdef KANJI
#define _KANJI_C_
#include "includes.h"
@@ -43,8 +42,7 @@ char hex_tag = HEXTAG;
search token from S1 separated any char of S2
S1 contain SHIFT JIS chars.
********************************************************************/
-char *
-sj_strtok (char *s1, const char *s2)
+char *sj_strtok(char *s1, char *s2)
{
static char *s = NULL;
char *q;
@@ -83,10 +81,9 @@ sj_strtok (char *s1, const char *s2)
search string S2 from S1
S1 contain SHIFT JIS chars.
********************************************************************/
-char *
-sj_strstr (const char *s1, const char *s2)
+char *sj_strstr(char *s1, char *s2)
{
- register int len = strlen ((char *) s2);
+ int len = strlen ((char *) s2);
if (!*s2)
return (char *) s1;
for (;*s1;) {
@@ -107,8 +104,7 @@ sj_strstr (const char *s1, const char *s2)
Search char C from beginning of S.
S contain SHIFT JIS chars.
********************************************************************/
-char *
-sj_strchr (const char *s, int c)
+char *sj_strchr (char *s, int c)
{
for (; *s; ) {
if (*s == c)
@@ -126,10 +122,9 @@ sj_strchr (const char *s, int c)
Search char C end of S.
S contain SHIFT JIS chars.
********************************************************************/
-char *
-sj_strrchr (const char *s, int c)
+char *sj_strrchr(char *s, int c)
{
- register char *q;
+ char *q;
for (q = 0; *s; ) {
if (*s == c) {
@@ -153,8 +148,7 @@ static char cvtbuf[1024];
/*******************************************************************
EUC <-> SJIS
********************************************************************/
-static int
-euc2sjis (register int hi, register int lo)
+static int euc2sjis (int hi, int lo)
{
if (hi & 1)
return ((hi / 2 + (hi < 0xdf ? 0x31 : 0x71)) << 8) |
@@ -163,8 +157,7 @@ euc2sjis (register int hi, register int lo)
return ((hi / 2 + (hi < 0xdf ? 0x30 : 0x70)) << 8) | (lo - 2);
}
-static int
-sjis2euc (register int hi, register int lo)
+static int sjis2euc (int hi, int lo)
{
if (lo >= 0x9f)
return ((hi * 2 - (hi >= 0xe0 ? 0xe0 : 0x60)) << 8) | (lo + 2);
@@ -177,10 +170,9 @@ sjis2euc (register int hi, register int lo)
Convert FROM contain SHIFT JIS codes to EUC codes
return converted buffer
********************************************************************/
-static char *
-sj_to_euc (const char *from, BOOL overwrite)
+static char *sj_to_euc(char *from, BOOL overwrite)
{
- register char *out;
+ char *out;
char *save;
save = (char *) from;
@@ -210,10 +202,9 @@ sj_to_euc (const char *from, BOOL overwrite)
Convert FROM contain EUC codes to SHIFT JIS codes
return converted buffer
********************************************************************/
-static char *
-euc_to_sj (const char *from, BOOL overwrite)
+static char *euc_to_sj(char *from, BOOL overwrite)
{
- register char *out;
+ char *out;
char *save;
save = (char *) from;
@@ -242,8 +233,7 @@ euc_to_sj (const char *from, BOOL overwrite)
/*******************************************************************
JIS7,JIS8,JUNET <-> SJIS
********************************************************************/
-static int
-sjis2jis (register int hi, register int lo)
+static int sjis2jis(int hi, int lo)
{
if (lo >= 0x9f)
return ((hi * 2 - (hi >= 0xe0 ? 0x160 : 0xe0)) << 8) | (lo - 0x7e);
@@ -252,8 +242,7 @@ sjis2jis (register int hi, register int lo)
(lo - (lo >= 0x7f ? 0x20 : 0x1f));
}
-static int
-jis2sjis (register int hi, register int lo)
+static int jis2sjis(int hi, int lo)
{
if (hi & 1)
return ((hi / 2 + (hi < 0x5f ? 0x71 : 0xb1)) << 8) |
@@ -266,11 +255,10 @@ jis2sjis (register int hi, register int lo)
Convert FROM contain JIS codes to SHIFT JIS codes
return converted buffer
********************************************************************/
-static char *
-jis8_to_sj (const char *from, BOOL overwrite)
+static char *jis8_to_sj(char *from, BOOL overwrite)
{
- register char *out;
- register int shifted;
+ char *out;
+ int shifted;
char *save;
shifted = _KJ_ROMAN;
@@ -317,11 +305,10 @@ jis8_to_sj (const char *from, BOOL overwrite)
Convert FROM contain SHIFT JIS codes to JIS codes
return converted buffer
********************************************************************/
-static char *
-sj_to_jis8 (const char *from, BOOL overwrite)
+static char *sj_to_jis8(char *from, BOOL overwrite)
{
- register char *out;
- register int shifted;
+ char *out;
+ int shifted;
char *save;
shifted = _KJ_ROMAN;
@@ -374,11 +361,10 @@ sj_to_jis8 (const char *from, BOOL overwrite)
Convert FROM contain 7 bits JIS codes to SHIFT JIS codes
return converted buffer
********************************************************************/
-static char *
-jis7_to_sj (const char *from, BOOL overwrite)
+static char *jis7_to_sj(char *from, BOOL overwrite)
{
- register char *out;
- register int shifted;
+ char *out;
+ int shifted;
char *save;
shifted = _KJ_ROMAN;
@@ -434,11 +420,10 @@ jis7_to_sj (const char *from, BOOL overwrite)
Convert FROM contain SHIFT JIS codes to 7 bits JIS codes
return converted buffer
********************************************************************/
-static char *
-sj_to_jis7 (const char *from, BOOL overwrite)
+static char *sj_to_jis7(char *from, BOOL overwrite)
{
- register char *out;
- register int shifted;
+ char *out;
+ int shifted;
char *save;
shifted = _KJ_ROMAN;
@@ -511,11 +496,10 @@ sj_to_jis7 (const char *from, BOOL overwrite)
Convert FROM contain 7 bits JIS(junet) codes to SHIFT JIS codes
return converted buffer
********************************************************************/
-static char *
-junet_to_sj (const char *from, BOOL overwrite)
+static char *junet_to_sj(char *from, BOOL overwrite)
{
- register char *out;
- register int shifted;
+ char *out;
+ int shifted;
char *save;
shifted = _KJ_ROMAN;
@@ -568,11 +552,10 @@ junet_to_sj (const char *from, BOOL overwrite)
Convert FROM contain SHIFT JIS codes to 7 bits JIS(junet) codes
return converted buffer
********************************************************************/
-static char *
-sj_to_junet (const char *from, BOOL overwrite)
+static char *sj_to_junet(char *from, BOOL overwrite)
{
- register char *out;
- register int shifted;
+ char *out;
+ int shifted;
char *save;
shifted = _KJ_ROMAN;
@@ -638,8 +621,7 @@ sj_to_junet (const char *from, BOOL overwrite)
HEX <-> SJIS
********************************************************************/
/* ":xx" -> a byte */
-static char *
-hex_to_sj (const char *from, BOOL overwrite)
+static char *hex_to_sj(char *from, BOOL overwrite)
{
char *sp, *dp;
@@ -664,8 +646,7 @@ hex_to_sj (const char *from, BOOL overwrite)
/*******************************************************************
kanji/kana -> ":xx"
********************************************************************/
-static char *
-sj_to_hex (const char *from, BOOL overwrite)
+static char *sj_to_hex(char *from, BOOL overwrite)
{
unsigned char *sp, *dp;
@@ -701,8 +682,7 @@ sj_to_hex (const char *from, BOOL overwrite)
/*******************************************************************
kanji/kana -> ":xx"
********************************************************************/
-static char *
-sj_to_cap (const char *from, BOOL overwrite)
+static char *sj_to_cap(char *from, BOOL overwrite)
{
unsigned char *sp, *dp;
@@ -730,8 +710,7 @@ sj_to_cap (const char *from, BOOL overwrite)
/*******************************************************************
sj to sj
********************************************************************/
-static char *
-sj_to_sj (const char *from, BOOL overwrite)
+static char *sj_to_sj(char *from, BOOL overwrite)
{
if (!overwrite) {
strcpy (cvtbuf, (char *) from);
@@ -746,11 +725,10 @@ sj_to_sj (const char *from, BOOL overwrite)
_dos_to_unix _unix_to_dos
************************************************************************/
-char* (*_dos_to_unix) (const char *str, BOOL overwrite) = sj_to_sj;
-char* (*_unix_to_dos) (const char *str, BOOL overwrite) = sj_to_sj;
+char *(*_dos_to_unix)(char *str, BOOL overwrite) = sj_to_sj;
+char *(*_unix_to_dos)(char *str, BOOL overwrite) = sj_to_sj;
-static int
-setup_string_function (int codes)
+static int setup_string_function(int codes)
{
switch (codes) {
default:
@@ -796,8 +774,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;
@@ -889,7 +866,3 @@ interpret_coding_system (char *str, int def)
}
return setup_string_function (codes);
}
-#else
-int kanji_dummy_procedure(void)
-{return 0;}
-#endif /* KANJI */
diff --git a/source/lib/md4.c b/source/lib/md4.c
index 485e231a784..1c9c2e6ecd5 100644
--- a/source/lib/md4.c
+++ b/source/lib/md4.c
@@ -1,299 +1,171 @@
-#ifdef SMB_PASSWD
-/*
- This code is from rfc1186.
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ a implementation of MD4 designed for use in the SMB authentication protocol
+ Copyright (C) Andrew Tridgell 1997
+
+ 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.
*/
- /*
- ** ********************************************************************
- ** md4.c -- Implementation of MD4 Message Digest Algorithm **
- ** Updated: 2/16/90 by Ronald L. Rivest **
- ** (C) 1990 RSA Data Security, Inc. **
- ** ********************************************************************
- */
- /*
- ** To use MD4:
- ** -- Include md4.h in your program
- ** -- Declare an MDstruct MD to hold the state of the digest
- ** computation.
- ** -- Initialize MD using MDbegin(&MD)
- ** -- For each full block (64 bytes) X you wish to process, call
- ** MDupdate(&MD,X,512)
- ** (512 is the number of bits in a full block.)
- ** -- For the last block (less than 64 bytes) you wish to process,
- ** MDupdate(&MD,X,n)
- ** where n is the number of bits in the partial block. A partial
- ** block terminates the computation, so every MD computation
- ** should terminate by processing a partial block, even if it
- ** has n = 0.
- ** -- The message digest is available in MD.buffer[0] ...
- ** MD.buffer[3]. (Least-significant byte of each word
- ** should be output first.)
- ** -- You can print out the digest using MDprint(&MD)
- */
+/* NOTE: This code makes no attempt to be fast!
- /* Implementation notes:
- ** This implementation assumes that ints are 32-bit quantities.
- ** If the machine stores the least-significant byte of an int in the
- ** least-addressed byte (e.g., VAX and 8086), then LOWBYTEFIRST
- ** should be set to TRUE. Otherwise (e.g., SUNS), LOWBYTEFIRST
- ** should be set to FALSE. Note that on machines with LOWBYTEFIRST
- ** FALSE the routine MDupdate modifies has a side-effect on its input
- ** array (the order of bytes in each word are reversed). If this is
- ** undesired a call to MDreverse(X) can reverse the bytes of X back
- ** into order after each call to MDupdate.
- */
-
-#define TRUE 1
-#define FALSE 0
-
- /* Compile-time includes
- */
-
-#include <stdio.h>
-#include "md4.h"
-
-#define uchar unsigned char
-#define int16 unsigned short
-#define uint32 unsigned int
-
-#include "byteorder.h"
-
- /* Compile-time declarations of MD4 "magic constants".
- */
-#define I0 0x67452301 /* Initial values for MD buffer */
-#define I1 0xefcdab89
-#define I2 0x98badcfe
-#define I3 0x10325476
-#define C2 013240474631 /* round 2 constant = sqrt(2) in octal */
-#define C3 015666365641 /* round 3 constant = sqrt(3) in octal */
- /* C2 and C3 are from Knuth, The Art of Programming, Volume 2
- ** (Seminumerical Algorithms), Second Edition (1981), Addison-Wesley.
- ** Table 2, page 660.
- */
-
-#define fs1 3 /* round 1 shift amounts */
-#define fs2 7
-#define fs3 11
-#define fs4 19
-#define gs1 3 /* round 2 shift amounts */
-#define gs2 5
-#define gs3 9
-#define gs4 13
-#define hs1 3 /* round 3 shift amounts */
-#define hs2 9
-#define hs3 11
-#define hs4 15
-
- /* Compile-time macro declarations for MD4.
- ** Note: The "rot" operator uses the variable "tmp".
- ** It assumes tmp is declared as unsigned int, so that the >>
- ** operator will shift in zeros rather than extending the sign bit.
- */
-#define f(X,Y,Z) ((X&Y) | ((~X)&Z))
-#define g(X,Y,Z) ((X&Y) | (X&Z) | (Y&Z))
-#define h(X,Y,Z) (X^Y^Z)
-#define rot(X,S) (tmp=X,(tmp<<S) | (tmp>>(32-S)))
-#define ff(A,B,C,D,i,s) A = rot((A + f(B,C,D) + X[i]),s)
-#define gg(A,B,C,D,i,s) A = rot((A + g(B,C,D) + X[i] + C2),s)
-#define hh(A,B,C,D,i,s) A = rot((A + h(B,C,D) + X[i] + C3),s)
+ It assumes that a int is at least 32 bits long
+*/
- /* MDprint(MDp)
- ** Print message digest buffer MDp as 32 hexadecimal digits.
- ** Order is from low-order byte of buffer[0] to high-order byte of
- ** buffer[3].
- ** Each byte is printed with high-order hexadecimal digit first.
- ** This is a user-callable routine.
- */
- void
- MDprint(MDp)
- MDptr MDp;
- { int i,j;
- for (i=0;i<4;i++)
- for (j=0;j<32;j=j+8)
- printf("%02x",(MDp->buffer[i]>>j) & 0xFF);
- }
+typedef unsigned int uint32;
+
+static uint32 A, B, C, D;
+
+static uint32 F(uint32 X, uint32 Y, uint32 Z)
+{
+ return (X&Y) | ((~X)&Z);
+}
+
+static uint32 G(uint32 X, uint32 Y, uint32 Z)
+{
+ return (X&Y) | (X&Z) | (Y&Z);
+}
+
+static uint32 H(uint32 X, uint32 Y, uint32 Z)
+{
+ return X^Y^Z;
+}
+
+static uint32 lshift(uint32 x, int s)
+{
+ x &= 0xFFFFFFFF;
+ return ((x<<s)&0xFFFFFFFF) | (x>>(32-s));
+}
+
+#define ROUND1(a,b,c,d,k,s) a = lshift(a + F(b,c,d) + X[k], s)
+#define ROUND2(a,b,c,d,k,s) a = lshift(a + G(b,c,d) + X[k] + (uint32)0x5A827999,s)
+#define ROUND3(a,b,c,d,k,s) a = lshift(a + H(b,c,d) + X[k] + (uint32)0x6ED9EBA1,s)
+
+/* this applies md4 to 64 byte chunks */
+static void mdfour64(uint32 *M)
+{
+ int j;
+ uint32 AA, BB, CC, DD;
+ uint32 X[16];
+
+ for (j=0;j<16;j++)
+ X[j] = M[j];
+
+ AA = A; BB = B; CC = C; DD = D;
+
+ ROUND1(A,B,C,D, 0, 3); ROUND1(D,A,B,C, 1, 7);
+ ROUND1(C,D,A,B, 2, 11); ROUND1(B,C,D,A, 3, 19);
+ ROUND1(A,B,C,D, 4, 3); ROUND1(D,A,B,C, 5, 7);
+ ROUND1(C,D,A,B, 6, 11); ROUND1(B,C,D,A, 7, 19);
+ ROUND1(A,B,C,D, 8, 3); ROUND1(D,A,B,C, 9, 7);
+ ROUND1(C,D,A,B, 10, 11); ROUND1(B,C,D,A, 11, 19);
+ ROUND1(A,B,C,D, 12, 3); ROUND1(D,A,B,C, 13, 7);
+ ROUND1(C,D,A,B, 14, 11); ROUND1(B,C,D,A, 15, 19);
+
+ ROUND2(A,B,C,D, 0, 3); ROUND2(D,A,B,C, 4, 5);
+ ROUND2(C,D,A,B, 8, 9); ROUND2(B,C,D,A, 12, 13);
+ ROUND2(A,B,C,D, 1, 3); ROUND2(D,A,B,C, 5, 5);
+ ROUND2(C,D,A,B, 9, 9); ROUND2(B,C,D,A, 13, 13);
+ ROUND2(A,B,C,D, 2, 3); ROUND2(D,A,B,C, 6, 5);
+ ROUND2(C,D,A,B, 10, 9); ROUND2(B,C,D,A, 14, 13);
+ ROUND2(A,B,C,D, 3, 3); ROUND2(D,A,B,C, 7, 5);
+ ROUND2(C,D,A,B, 11, 9); ROUND2(B,C,D,A, 15, 13);
+
+ ROUND3(A,B,C,D, 0, 3); ROUND3(D,A,B,C, 8, 9);
+ ROUND3(C,D,A,B, 4, 11); ROUND3(B,C,D,A, 12, 15);
+ ROUND3(A,B,C,D, 2, 3); ROUND3(D,A,B,C, 10, 9);
+ ROUND3(C,D,A,B, 6, 11); ROUND3(B,C,D,A, 14, 15);
+ ROUND3(A,B,C,D, 1, 3); ROUND3(D,A,B,C, 9, 9);
+ ROUND3(C,D,A,B, 5, 11); ROUND3(B,C,D,A, 13, 15);
+ ROUND3(A,B,C,D, 3, 3); ROUND3(D,A,B,C, 11, 9);
+ ROUND3(C,D,A,B, 7, 11); ROUND3(B,C,D,A, 15, 15);
+
+ A += AA; B += BB; C += CC; D += DD;
+
+ A &= 0xFFFFFFFF; B &= 0xFFFFFFFF;
+ C &= 0xFFFFFFFF; D &= 0xFFFFFFFF;
+
+ for (j=0;j<16;j++)
+ X[j] = 0;
+}
+
+static void copy64(uint32 *M, unsigned char *in)
+{
+ int i;
+
+ for (i=0;i<16;i++)
+ M[i] = (in[i*4+3]<<24) | (in[i*4+2]<<16) |
+ (in[i*4+1]<<8) | (in[i*4+0]<<0);
+}
+
+static void copy4(unsigned char *out,uint32 x)
+{
+ out[0] = x&0xFF;
+ out[1] = (x>>8)&0xFF;
+ out[2] = (x>>16)&0xFF;
+ out[3] = (x>>24)&0xFF;
+}
+
+/* produce a md4 message digest from data of length n bytes */
+void mdfour(unsigned char *out, unsigned char *in, int n)
+{
+ unsigned char buf[128];
+ uint32 M[16];
+ uint32 b = n * 8;
+ int i;
+
+ A = 0x67452301;
+ B = 0xefcdab89;
+ C = 0x98badcfe;
+ D = 0x10325476;
+
+ while (n > 64) {
+ copy64(M, in);
+ mdfour64(M);
+ in += 64;
+ n -= 64;
+ }
- /* MDbegin(MDp)
- ** Initialize message digest buffer MDp.
- ** This is a user-callable routine.
- */
- void
- MDbegin(MDp)
- MDptr MDp;
- { int i;
- MDp->buffer[0] = I0;
- MDp->buffer[1] = I1;
- MDp->buffer[2] = I2;
- MDp->buffer[3] = I3;
- for (i=0;i<8;i++) MDp->count[i] = 0;
- MDp->done = 0;
- }
+ for (i=0;i<128;i++)
+ buf[i] = 0;
+ memcpy(buf, in, n);
+ buf[n] = 0x80;
+
+ if (n <= 55) {
+ copy4(buf+56, b);
+ copy64(M, buf);
+ mdfour64(M);
+ } else {
+ copy4(buf+120, b);
+ copy64(M, buf);
+ mdfour64(M);
+ copy64(M, buf+64);
+ mdfour64(M);
+ }
- /* MDreverse(X)
- ** Reverse the byte-ordering of every int in X.
- ** Assumes X is an array of 16 ints.
- ** The macro revx reverses the byte-ordering of the next word of X.
- */
- void MDreverse(X)
- unsigned int *X;
- { register unsigned int t;
- register unsigned int i;
+ for (i=0;i<128;i++)
+ buf[i] = 0;
+ copy64(M, buf);
- for(i = 0; i < 16; i++) {
- t = X[i];
- SIVAL(X,i*4,t);
- }
- }
+ copy4(out, A);
+ copy4(out+4, B);
+ copy4(out+8, C);
+ copy4(out+12, D);
- /* MDblock(MDp,X)
- ** Update message digest buffer MDp->buffer using 16-word data block X.
- ** Assumes all 16 words of X are full of data.
- ** Does not update MDp->count.
- ** This routine is not user-callable.
- */
- static void
- MDblock(MDp,X)
- MDptr MDp;
- unsigned int *X;
- {
- register unsigned int tmp, A, B, C, D;
- MDreverse(X);
- A = MDp->buffer[0];
- B = MDp->buffer[1];
- C = MDp->buffer[2];
- D = MDp->buffer[3];
- /* Update the message digest buffer */
- ff(A , B , C , D , 0 , fs1); /* Round 1 */
- ff(D , A , B , C , 1 , fs2);
- ff(C , D , A , B , 2 , fs3);
- ff(B , C , D , A , 3 , fs4);
- ff(A , B , C , D , 4 , fs1);
- ff(D , A , B , C , 5 , fs2);
- ff(C , D , A , B , 6 , fs3);
- ff(B , C , D , A , 7 , fs4);
- ff(A , B , C , D , 8 , fs1);
- ff(D , A , B , C , 9 , fs2);
- ff(C , D , A , B , 10 , fs3);
- ff(B , C , D , A , 11 , fs4);
- ff(A , B , C , D , 12 , fs1);
- ff(D , A , B , C , 13 , fs2);
- ff(C , D , A , B , 14 , fs3);
- ff(B , C , D , A , 15 , fs4);
- gg(A , B , C , D , 0 , gs1); /* Round 2 */
- gg(D , A , B , C , 4 , gs2);
- gg(C , D , A , B , 8 , gs3);
- gg(B , C , D , A , 12 , gs4);
- gg(A , B , C , D , 1 , gs1);
- gg(D , A , B , C , 5 , gs2);
- gg(C , D , A , B , 9 , gs3);
- gg(B , C , D , A , 13 , gs4);
- gg(A , B , C , D , 2 , gs1);
- gg(D , A , B , C , 6 , gs2);
- gg(C , D , A , B , 10 , gs3);
- gg(B , C , D , A , 14 , gs4);
- gg(A , B , C , D , 3 , gs1);
- gg(D , A , B , C , 7 , gs2);
- gg(C , D , A , B , 11 , gs3);
- gg(B , C , D , A , 15 , gs4);
- hh(A , B , C , D , 0 , hs1); /* Round 3 */
- hh(D , A , B , C , 8 , hs2);
- hh(C , D , A , B , 4 , hs3);
- hh(B , C , D , A , 12 , hs4);
- hh(A , B , C , D , 2 , hs1);
- hh(D , A , B , C , 10 , hs2);
- hh(C , D , A , B , 6 , hs3);
- hh(B , C , D , A , 14 , hs4);
- hh(A , B , C , D , 1 , hs1);
- hh(D , A , B , C , 9 , hs2);
- hh(C , D , A , B , 5 , hs3);
- hh(B , C , D , A , 13 , hs4);
- hh(A , B , C , D , 3 , hs1);
- hh(D , A , B , C , 11 , hs2);
- hh(C , D , A , B , 7 , hs3);
- hh(B , C , D , A , 15 , hs4);
- MDp->buffer[0] += A;
- MDp->buffer[1] += B;
- MDp->buffer[2] += C;
- MDp->buffer[3] += D;
- }
+ A = B = C = D = 0;
+}
- /* MDupdate(MDp,X,count)
- ** Input: MDp -- an MDptr
- ** X -- a pointer to an array of unsigned characters.
- ** count -- the number of bits of X to use.
- ** (if not a multiple of 8, uses high bits of last byte.)
- ** Update MDp using the number of bits of X given by count.
- ** This is the basic input routine for an MD4 user.
- ** The routine completes the MD computation when count < 512, so
- ** every MD computation should end with one call to MDupdate with a
- ** count less than 512. A call with count 0 will be ignored if the
- ** MD has already been terminated (done != 0), so an extra call with
- ** count 0 can be given as a "courtesy close" to force termination
- ** if desired.
- */
- void
- MDupdate(MDp,X,count)
- MDptr MDp;
- unsigned char *X;
- unsigned int count;
- { unsigned int i, tmp, bit, byte, mask;
- unsigned char XX[64];
- unsigned char *p;
- /* return with no error if this is a courtesy close with count
- ** zero and MDp->done is true.
- */
- if (count == 0 && MDp->done) return;
- /* check to see if MD is already done and report error */
- if (MDp->done)
- { printf("\nError: MDupdate MD already done."); return; }
- /* Add count to MDp->count */
- tmp = count;
- p = MDp->count;
- while (tmp)
- { tmp += *p;
- *p++ = tmp;
- tmp = tmp >> 8;
- }
- /* Process data */
- if (count == 512)
- { /* Full block of data to handle */
- MDblock(MDp,(unsigned int *)X);
- }
- else if (count > 512) /* Check for count too large */
- { printf("\nError: MDupdate called with illegal count value %d."
- ,count);
- return;
- }
- else /* partial block -- must be last block so finish up */
- { /* Find out how many bytes and residual bits there are */
- byte = count >> 3;
- bit = count & 7;
- /* Copy X into XX since we need to modify it */
- for (i=0;i<=byte;i++) XX[i] = X[i];
- for (i=byte+1;i<64;i++) XX[i] = 0;
- /* Add padding '1' bit and low-order zeros in last byte */
- mask = 1 << (7 - bit);
- XX[byte] = (XX[byte] | mask) & ~( mask - 1);
- /* If room for bit count, finish up with this block */
- if (byte <= 55)
- { for (i=0;i<8;i++) XX[56+i] = MDp->count[i];
- MDblock(MDp,(unsigned int *)XX);
- }
- else /* need to do two blocks to finish up */
- { MDblock(MDp,(unsigned int *)XX);
- for (i=0;i<56;i++) XX[i] = 0;
- for (i=0;i<8;i++) XX[56+i] = MDp->count[i];
- MDblock(MDp,(unsigned int *)XX);
- }
- /* Set flag saying we're done with MD computation */
- MDp->done = 1;
- }
- }
- /*
- ** End of md4.c
- */
-#else
-void md4_dummy() {;}
-#endif
diff --git a/source/lib/replace.c b/source/lib/replace.c
new file mode 100644
index 00000000000..67c18a15237
--- /dev/null
+++ b/source/lib/replace.c
@@ -0,0 +1,325 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ replacement routines for broken systems
+ Copyright (C) Andrew Tridgell 1992-1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+
+ void replace_dummy(void)
+{}
+
+#ifdef REPLACE_STRLEN
+/****************************************************************************
+a replacement strlen() that returns int for solaris
+****************************************************************************/
+ int Strlen(char *s)
+{
+ int ret=0;
+ if (!s) return(0);
+ while (*s++) ret++;
+ return(ret);
+}
+#endif
+
+#ifdef NO_FTRUNCATE
+ /*******************************************************************
+ftruncate for operating systems that don't have it
+********************************************************************/
+ int ftruncate(int f,long l)
+{
+ struct flock fl;
+
+ fl.l_whence = 0;
+ fl.l_len = 0;
+ fl.l_start = l;
+ fl.l_type = F_WRLCK;
+ return fcntl(f, F_FREESP, &fl);
+}
+#endif
+
+
+#ifdef REPLACE_STRSTR
+/****************************************************************************
+Mips version of strstr doesn't seem to work correctly.
+There is a #define in includes.h to redirect calls to this function.
+****************************************************************************/
+char *Strstr(char *s, char *p)
+{
+ int len = strlen(p);
+
+ while ( *s != '\0' ) {
+ if ( strncmp(s, p, len) == 0 )
+ return s;
+ s++;
+ }
+
+ return NULL;
+}
+#endif /* REPLACE_STRSTR */
+
+
+#ifdef REPLACE_MKTIME
+/*******************************************************************
+a mktime() replacement for those who don't have it - contributed by
+C.A. Lademann <cal@zls.com>
+********************************************************************/
+#define MINUTE 60
+#define HOUR 60*MINUTE
+#define DAY 24*HOUR
+#define YEAR 365*DAY
+time_t Mktime(struct tm *t)
+{
+ struct tm *u;
+ time_t epoch = 0;
+ int mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+ y, m, i;
+
+ if(t->tm_year < 70)
+ return((time_t)-1);
+
+ epoch = (t->tm_year - 70) * YEAR +
+ (t->tm_year / 4 - 70 / 4 - t->tm_year / 100) * DAY;
+
+ y = t->tm_year;
+ m = 0;
+
+ for(i = 0; i < t->tm_mon; i++) {
+ epoch += mon [m] * DAY;
+ if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
+ epoch += DAY;
+
+ if(++m > 11) {
+ m = 0;
+ y++;
+ }
+ }
+
+ epoch += (t->tm_mday - 1) * DAY;
+ epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec;
+
+ if((u = localtime(&epoch)) != NULL) {
+ t->tm_sec = u->tm_sec;
+ t->tm_min = u->tm_min;
+ t->tm_hour = u->tm_hour;
+ t->tm_mday = u->tm_mday;
+ t->tm_mon = u->tm_mon;
+ t->tm_year = u->tm_year;
+ t->tm_wday = u->tm_wday;
+ t->tm_yday = u->tm_yday;
+ t->tm_isdst = u->tm_isdst;
+#ifndef NO_TM_NAME
+ memcpy(t->tm_name, u->tm_name, LTZNMAX);
+#endif
+ }
+
+ return(epoch);
+}
+#endif /* REPLACE_MKTIME */
+
+
+
+#ifdef REPLACE_RENAME
+/* Rename a file. (from libiberty in GNU binutils) */
+ int rename (zfrom, zto)
+ const char *zfrom;
+ const char *zto;
+{
+ if (link (zfrom, zto) < 0)
+ {
+ if (errno != EEXIST)
+ return -1;
+ if (unlink (zto) < 0
+ || link (zfrom, zto) < 0)
+ return -1;
+ }
+ return unlink (zfrom);
+}
+#endif
+
+
+#ifdef REPLACE_INNETGR
+/*
+ * Search for a match in a netgroup. This replaces it on broken systems.
+ */
+int InNetGr(char *group,char *host,char *user,char *dom)
+{
+ char *hst, *usr, *dm;
+
+ setnetgrent(group);
+ while (getnetgrent(&hst, &usr, &dm))
+ if (((host == 0) || (hst == 0) || !strcmp(host, hst)) &&
+ ((user == 0) || (usr == 0) || !strcmp(user, usr)) &&
+ ((dom == 0) || (dm == 0) || !strcmp(dom, dm))) {
+ endnetgrent();
+ return (1);
+ }
+ endnetgrent();
+ return (0);
+}
+#endif
+
+
+
+#ifdef NO_INITGROUPS
+#include <sys/types.h>
+#include <limits.h>
+#include <grp.h>
+
+#ifndef NULL
+#define NULL (void *)0
+#endif
+
+/****************************************************************************
+ some systems don't have an initgroups call
+****************************************************************************/
+ int initgroups(char *name,gid_t id)
+{
+#ifdef NO_SETGROUPS
+ /* yikes! no SETGROUPS or INITGROUPS? how can this work? */
+ return(0);
+#else
+ gid_t grouplst[NGROUPS_MAX];
+ int i,j;
+ struct group *g;
+ char *gr;
+
+ grouplst[0] = id;
+ i = 1;
+ while (i < NGROUPS_MAX &&
+ ((g = (struct group *)getgrent()) != (struct group *)NULL))
+ {
+ if (g->gr_gid == id)
+ continue;
+ j = 0;
+ gr = g->gr_mem[0];
+ while (gr && (*gr != (char)NULL)) {
+ if (strcmp(name,gr) == 0) {
+ grouplst[i] = g->gr_gid;
+ i++;
+ gr = (char *)NULL;
+ break;
+ }
+ gr = g->gr_mem[++j];
+ }
+ }
+ endgrent();
+ return(setgroups(i,grouplst));
+#endif
+}
+#endif
+
+
+#if (defined(SecureWare) && defined(SCO))
+/* This is needed due to needing the nap() function but we don't want
+ to include the Xenix libraries since that will break other things...
+ BTW: system call # 0x0c28 is the same as calling nap() */
+long nap(long milliseconds) {
+ return syscall(0x0c28, milliseconds);
+}
+#endif
+
+
+
+#if WRAP_MALLOC
+
+/* undo the wrapping temporarily */
+#undef malloc
+#undef realloc
+#undef free
+
+/****************************************************************************
+wrapper for malloc() to catch memory errors
+****************************************************************************/
+void *malloc_wrapped(int size,char *file,int line)
+{
+#ifdef xx_old_malloc
+ void *res = xx_old_malloc(size);
+#else
+ void *res = malloc(size);
+#endif
+ DEBUG(3,("Malloc called from %s(%d) with size=%d gave ptr=0x%X\n",
+ file,line,
+ size,(unsigned int)res));
+ return(res);
+}
+
+/****************************************************************************
+wrapper for realloc() to catch memory errors
+****************************************************************************/
+void *realloc_wrapped(void *ptr,int size,char *file,int line)
+{
+#ifdef xx_old_realloc
+ void *res = xx_old_realloc(ptr,size);
+#else
+ void *res = realloc(ptr,size);
+#endif
+ DEBUG(3,("Realloc\n"));
+ DEBUG(3,("free called from %s(%d) with ptr=0x%X\n",
+ file,line,
+ (unsigned int)ptr));
+ DEBUG(3,("Malloc called from %s(%d) with size=%d gave ptr=0x%X\n",
+ file,line,
+ size,(unsigned int)res));
+ return(res);
+}
+
+/****************************************************************************
+wrapper for free() to catch memory errors
+****************************************************************************/
+void free_wrapped(void *ptr,char *file,int line)
+{
+#ifdef xx_old_free
+ xx_old_free(ptr);
+#else
+ free(ptr);
+#endif
+ DEBUG(3,("free called from %s(%d) with ptr=0x%X\n",
+ file,line,(unsigned int)ptr));
+ return;
+}
+
+/* and re-do the define for spots lower in this file */
+#define malloc(size) malloc_wrapped(size,__FILE__,__LINE__)
+#define realloc(ptr,size) realloc_wrapped(ptr,size,__FILE__,__LINE__)
+#define free(ptr) free_wrapped(ptr,__FILE__,__LINE__)
+
+#endif
+
+
+#if WRAP_MEMCPY
+#undef memcpy
+/*******************************************************************
+a wrapper around memcpy for diagnostic purposes
+********************************************************************/
+void *memcpy_wrapped(void *d,void *s,int l,char *fname,int line)
+{
+ if (l>64 && (((int)d)%4) != (((int)s)%4))
+ DEBUG(4,("Misaligned memcpy(0x%X,0x%X,%d) at %s(%d)\n",d,s,l,fname,line));
+#ifdef xx_old_memcpy
+ return(xx_old_memcpy(d,s,l));
+#else
+ return(memcpy(d,s,l));
+#endif
+}
+#define memcpy(d,s,l) memcpy_wrapped(d,s,l,__FILE__,__LINE__)
+#endif
+
diff --git a/source/lib/system.c b/source/lib/system.c
index 938746e9c9d..1486600339a 100644
--- a/source/lib/system.c
+++ b/source/lib/system.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Samba system utilities
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1997
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
@@ -25,13 +25,17 @@ extern int DEBUGLEVEL;
/*
The idea is that this file will eventually have wrappers around all
- important system calls in samba. The aim is twofold:
+ important system calls in samba. The aims are:
- to enable easier porting by putting OS dependent stuff in here
- to allow for hooks into other "pseudo-filesystems"
- to allow easier integration of things like the japanese extensions
+
+ - to support the philosophy of Samba to expose the features of
+ the OS within the SMB model. In general whatever file/printer/variable
+ expansions/etc make sense to the OS should be acceptable to Samba.
*/
@@ -79,7 +83,7 @@ int sys_select(fd_set *fds,struct timeval *tval)
return(found);
}
- if (tval && tval.tv_sec < counter) return(0);
+ if (tval && tval->tv_sec < counter) return(0);
sleep(1);
counter++;
}
@@ -94,7 +98,7 @@ int sys_select(fd_set *fds,struct timeval *tval)
do {
if (tval) memcpy((void *)&t2,(void *)tval,sizeof(t2));
errno = 0;
- selrtn = select(16,SELECT_CAST fds,NULL,NULL,tval?&t2:NULL);
+ selrtn = select(255,SELECT_CAST fds,NULL,NULL,tval?&t2:NULL);
} while (selrtn<0 && errno == EINTR);
return(selrtn);
@@ -138,6 +142,18 @@ int sys_stat(char *fname,struct stat *sbuf)
}
/*******************************************************************
+The wait() calls vary between systems
+********************************************************************/
+int sys_waitpid(pid_t pid,int *status,int options)
+{
+#ifdef USE_WAITPID
+ return waitpid(pid,status,options);
+#else /* USE_WAITPID */
+ return wait4(pid, status, options, NULL);
+#endif /* USE_WAITPID */
+}
+
+/*******************************************************************
don't forget lstat()
********************************************************************/
int sys_lstat(char *fname,struct stat *sbuf)
@@ -178,24 +194,166 @@ now for utime()
********************************************************************/
int sys_utime(char *fname,struct utimbuf *times)
{
+ /* if the modtime is 0 or -1 then ignore the call and
+ return success */
+ if (times->modtime == (time_t)0 || times->modtime == (time_t)-1)
+ return 0;
+
+ /* if the access time is 0 or -1 then set it to the modtime */
+ if (times->actime == (time_t)0 || times->actime == (time_t)-1)
+ times->actime = times->modtime;
+
return(utime(dos_to_unix(fname,False),times));
}
+/*********************************************************
+for rename across filesystems Patch from Warren Birnbaum
+<warrenb@hpcvscdp.cv.hp.com>
+**********************************************************/
+
+static int copy_reg(char *source, const char *dest)
+{
+ struct stat source_stats;
+ int ifd;
+ int full_write();
+ int safe_read();
+ int ofd;
+ char *buf;
+ int len; /* Number of bytes read into `buf'. */
+
+ lstat (source, &source_stats);
+ if (!S_ISREG (source_stats.st_mode))
+ {
+ return 1;
+ }
+
+ if (unlink (dest) && errno != ENOENT)
+ {
+ return 1;
+ }
+
+ if((ifd = open (source, O_RDONLY, 0)) < 0)
+ {
+ return 1;
+ }
+ if((ofd = open (dest, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0 )
+ {
+ close (ifd);
+ return 1;
+ }
+
+ if((buf = malloc( COPYBUF_SIZE )) == NULL)
+ {
+ close (ifd);
+ close (ofd);
+ unlink (dest);
+ return 1;
+ }
+
+ while ((len = read(ifd, buf, COPYBUF_SIZE)) > 0)
+ {
+ if (write_data(ofd, buf, len) < 0)
+ {
+ close (ifd);
+ close (ofd);
+ unlink (dest);
+ free(buf);
+ return 1;
+ }
+ }
+ free(buf);
+ if (len < 0)
+ {
+ close (ifd);
+ close (ofd);
+ unlink (dest);
+ return 1;
+ }
+
+ if (close (ifd) < 0)
+ {
+ close (ofd);
+ return 1;
+ }
+ if (close (ofd) < 0)
+ {
+ return 1;
+ }
+
+ /* chown turns off set[ug]id bits for non-root,
+ so do the chmod last. */
+
+ /* Try to copy the old file's modtime and access time. */
+ {
+ struct utimbuf tv;
+
+ tv.actime = source_stats.st_atime;
+ tv.modtime = source_stats.st_mtime;
+ if (utime (dest, &tv))
+ {
+ return 1;
+ }
+ }
+
+ /* Try to preserve ownership. For non-root it might fail, but that's ok.
+ But root probably wants to know, e.g. if NFS disallows it. */
+ if (chown (dest, source_stats.st_uid, source_stats.st_gid)
+ && (errno != EPERM))
+ {
+ return 1;
+ }
+
+ if (chmod (dest, source_stats.st_mode & 07777))
+ {
+ return 1;
+ }
+ unlink (source);
+ return 0;
+}
+
/*******************************************************************
for rename()
********************************************************************/
int sys_rename(char *from, char *to)
{
-#ifdef KANJI
+ int rcode;
pstring zfrom, zto;
- strcpy (zfrom, dos_to_unix (from, False));
- strcpy (zto, dos_to_unix (to, False));
- return rename (zfrom, zto);
-#else
- return rename (from, to);
-#endif /* KANJI */
+
+ pstrcpy (zfrom, dos_to_unix (from, False));
+ pstrcpy (zto, dos_to_unix (to, False));
+ rcode = rename (zfrom, zto);
+
+ if (errno == EXDEV)
+ {
+ /* Rename across filesystems needed. */
+ rcode = copy_reg (zfrom, zto);
+ }
+ return rcode;
}
+/*******************************************************************
+for chmod
+********************************************************************/
+int sys_chmod(char *fname,int mode)
+{
+ return(chmod(dos_to_unix(fname,False),mode));
+}
+
+/*******************************************************************
+for getwd
+********************************************************************/
+char *sys_getwd(char *s)
+{
+ char *wd;
+#ifdef USE_GETCWD
+ wd = (char *) getcwd (s, sizeof (pstring));
+#else
+ wd = (char *) getwd (s);
+#endif
+ if (wd)
+ unix_to_dos (wd, True);
+ return wd;
+}
/*******************************************************************
chown isn't used much but OS/2 doesn't have it
@@ -220,3 +378,45 @@ int sys_chroot(char *dname)
return(chroot(dname));
#endif
}
+
+/**************************************************************************
+A wrapper for gethostbyname() that tries avoids looking up hostnames
+in the root domain, which can cause dial-on-demand links to come up for no
+apparent reason.
+****************************************************************************/
+struct hostent *sys_gethostbyname(char *name)
+{
+#ifdef REDUCE_ROOT_DNS_LOOKUPS
+ char query[256], hostname[256];
+ char *domain;
+
+ /* Does this name have any dots in it? If so, make no change */
+
+ if (strchr(name, '.'))
+ return(gethostbyname(name));
+
+ /* Get my hostname, which should have domain name
+ attached. If not, just do the gethostname on the
+ original string.
+ */
+
+ gethostname(hostname, sizeof(hostname) - 1);
+ hostname[sizeof(hostname) - 1] = 0;
+ if ((domain = strchr(hostname, '.')) == NULL)
+ return(gethostbyname(name));
+
+ /* Attach domain name to query and do modified query.
+ If names too large, just do gethostname on the
+ original string.
+ */
+
+ if((strlen(name) + strlen(domain)) >= sizeof(query))
+ return(gethostbyname(name));
+
+ sprintf(query, "%s%s", name, domain);
+ return(gethostbyname(query));
+#else /* REDUCE_ROOT_DNS_LOOKUPS */
+ return(gethostbyname(name));
+#endif /* REDUCE_ROOT_DNS_LOOKUPS */
+}
+
diff --git a/source/lib/time.c b/source/lib/time.c
new file mode 100644
index 00000000000..ad6b04484c5
--- /dev/null
+++ b/source/lib/time.c
@@ -0,0 +1,476 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ time handling functions
+ Copyright (C) Andrew Tridgell 1992-1997
+
+ 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 ((time_t)0 < (time_t) -1 ? (time_t) 0 \
+ : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1))
+#endif
+#ifndef TIME_T_MAX
+#define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN)
+#endif
+
+
+
+/*******************************************************************
+a gettimeofday wrapper
+********************************************************************/
+void GetTimeOfDay(struct timeval *tval)
+{
+#ifdef GETTIMEOFDAY1
+ gettimeofday(tval);
+#else
+ gettimeofday(tval,NULL);
+#endif
+}
+
+#define TM_YEAR_BASE 1900
+
+/*******************************************************************
+yield the difference between *A and *B, in seconds, ignoring leap seconds
+********************************************************************/
+static int tm_diff(struct tm *a, struct tm *b)
+{
+ int ay = a->tm_year + (TM_YEAR_BASE - 1);
+ int by = b->tm_year + (TM_YEAR_BASE - 1);
+ int intervening_leap_days =
+ (ay/4 - by/4) - (ay/100 - by/100) + (ay/400 - by/400);
+ int years = ay - by;
+ int days = 365*years + intervening_leap_days + (a->tm_yday - b->tm_yday);
+ int hours = 24*days + (a->tm_hour - b->tm_hour);
+ int minutes = 60*hours + (a->tm_min - b->tm_min);
+ int seconds = 60*minutes + (a->tm_sec - b->tm_sec);
+ return seconds;
+}
+
+/*******************************************************************
+ return the UTC offset in seconds west of UTC
+ ******************************************************************/
+static int TimeZone(time_t t)
+{
+ struct tm tm_utc = *(gmtime(&t));
+ return tm_diff(&tm_utc,localtime(&t));
+}
+
+
+/*******************************************************************
+init the time differences
+********************************************************************/
+void TimeInit(void)
+{
+ serverzone = TimeZone(time(NULL));
+ DEBUG(4,("Serverzone is %d\n",serverzone));
+}
+
+
+/*******************************************************************
+return the same value as TimeZone, but it should be more efficient.
+
+We keep a table of DST offsets to prevent calling localtime() on each
+call of this function. This saves a LOT of time on many unixes.
+
+Updated by Paul Eggert <eggert@twinsun.com>
+********************************************************************/
+static int TimeZoneFaster(time_t t)
+{
+ static struct dst_table {time_t start,end; int zone;} *dst_table = NULL;
+ static int table_size = 0;
+ int i;
+ int zone = 0;
+
+ if (t == 0) t = time(NULL);
+
+ /* Tunis has a 8 day DST region, we need to be careful ... */
+#define MAX_DST_WIDTH (365*24*60*60)
+#define MAX_DST_SKIP (7*24*60*60)
+
+ for (i=0;i<table_size;i++)
+ if (t >= dst_table[i].start && t <= dst_table[i].end) break;
+
+ if (i<table_size) {
+ zone = dst_table[i].zone;
+ } else {
+ time_t low,high;
+
+ zone = TimeZone(t);
+ dst_table = (struct dst_table *)Realloc(dst_table,
+ sizeof(dst_table[0])*(i+1));
+ if (!dst_table) {
+ table_size = 0;
+ } else {
+ table_size++;
+
+ dst_table[i].zone = zone;
+ dst_table[i].start = dst_table[i].end = t;
+
+ /* no entry will cover more than 6 months */
+ low = t - MAX_DST_WIDTH/2;
+ if (t < low)
+ low = TIME_T_MIN;
+
+ high = t + MAX_DST_WIDTH/2;
+ if (high < t)
+ high = TIME_T_MAX;
+
+ /* widen the new entry using two bisection searches */
+ while (low+60*60 < dst_table[i].start) {
+ if (dst_table[i].start - low > MAX_DST_SKIP*2)
+ t = dst_table[i].start - MAX_DST_SKIP;
+ else
+ t = low + (dst_table[i].start-low)/2;
+ if (TimeZone(t) == zone)
+ dst_table[i].start = t;
+ else
+ low = t;
+ }
+
+ while (high-60*60 > dst_table[i].end) {
+ if (high - dst_table[i].end > MAX_DST_SKIP*2)
+ t = dst_table[i].end + MAX_DST_SKIP;
+ else
+ t = high - (high-dst_table[i].end)/2;
+ if (TimeZone(t) == zone)
+ dst_table[i].end = t;
+ else
+ high = t;
+ }
+#if 0
+ DEBUG(1,("Added DST entry from %s ",
+ asctime(localtime(&dst_table[i].start))));
+ DEBUG(1,("to %s (%d)\n",asctime(localtime(&dst_table[i].end)),
+ dst_table[i].zone));
+#endif
+ }
+ }
+ return zone;
+}
+
+/****************************************************************************
+ return the UTC offset in seconds west of UTC, adjusted for extra time offset
+ **************************************************************************/
+int TimeDiff(time_t t)
+{
+ return TimeZoneFaster(t) + 60*extra_time_offset;
+}
+
+
+/****************************************************************************
+ return the UTC offset in seconds west of UTC, adjusted for extra time
+ offset, for a local time value. If ut = lt + LocTimeDiff(lt), then
+ lt = ut - TimeDiff(ut), but the converse does not necessarily hold near
+ daylight savings transitions because some local times are ambiguous.
+ LocTimeDiff(t) equals TimeDiff(t) except near daylight savings transitions.
+ +**************************************************************************/
+static int LocTimeDiff(time_t lte)
+{
+ time_t lt = lte - 60*extra_time_offset;
+ int d = TimeZoneFaster(lt);
+ time_t t = lt + d;
+
+ /* if overflow occurred, ignore all the adjustments so far */
+ if (((lte < lt) ^ (extra_time_offset < 0)) | ((t < lt) ^ (d < 0)))
+ t = lte;
+
+ /* now t should be close enough to the true UTC to yield the right answer */
+ return TimeDiff(t);
+}
+
+
+/****************************************************************************
+try to optimise the localtime call, it can be quite expenive on some machines
+****************************************************************************/
+struct tm *LocalTime(time_t *t)
+{
+ time_t t2 = *t;
+
+ t2 -= TimeDiff(t2);
+
+ return(gmtime(&t2));
+}
+
+
+#define TIME_FIXUP_CONSTANT (369.0*365.25*24*60*60-(3.0*24*60*60+6.0*60*60))
+
+/****************************************************************************
+interpret an 8 byte "filetime" structure to a time_t
+It's originally in "100ns units since jan 1st 1601"
+
+It appears to be kludge-GMT (at least for file listings). This means
+its the GMT you get by taking a localtime and adding the
+serverzone. This is NOT the same as GMT in some cases. This routine
+converts this to real GMT.
+****************************************************************************/
+time_t interpret_long_date(char *p)
+{
+ double d;
+ time_t ret;
+ uint32 tlow,thigh;
+ tlow = IVAL(p,0);
+ thigh = IVAL(p,4);
+
+ if (thigh == 0) return(0);
+
+ d = ((double)thigh)*4.0*(double)(1<<30);
+ d += (tlow&0xFFF00000);
+ d *= 1.0e-7;
+
+ /* now adjust by 369 years to make the secs since 1970 */
+ d -= TIME_FIXUP_CONSTANT;
+
+ if (!(TIME_T_MIN <= d && d <= TIME_T_MAX))
+ return(0);
+
+ ret = (time_t)(d+0.5);
+
+ /* this takes us from kludge-GMT to real GMT */
+ ret -= serverzone;
+ ret += LocTimeDiff(ret);
+
+ return(ret);
+}
+
+
+/****************************************************************************
+put a 8 byte filetime from a time_t
+This takes real GMT as input and converts to kludge-GMT
+****************************************************************************/
+void put_long_date(char *p,time_t t)
+{
+ uint32 tlow,thigh;
+ double d;
+
+ if (t==0) {
+ SIVAL(p,0,0); SIVAL(p,4,0);
+ return;
+ }
+
+ /* this converts GMT to kludge-GMT */
+ t -= TimeDiff(t) - serverzone;
+
+ d = (double) (t);
+
+ d += TIME_FIXUP_CONSTANT;
+
+ d *= 1.0e7;
+
+ thigh = (uint32)(d * (1.0/(4.0*(double)(1<<30))));
+ tlow = (uint32)(d - ((double)thigh)*4.0*(double)(1<<30));
+
+ SIVAL(p,0,tlow);
+ SIVAL(p,4,thigh);
+}
+
+
+/****************************************************************************
+check if it's a null mtime
+****************************************************************************/
+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);
+}
+
+/****************************************************************************
+ return the date and time as a string
+****************************************************************************/
+char *timestring(void )
+{
+ static fstring TimeBuf;
+ time_t t = time(NULL);
+ struct tm *tm = LocalTime(&t);
+
+#ifdef NO_STRFTIME
+ fstrcpy(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..0fa5cfd3a0f 100644
--- a/source/lib/ufc.c
+++ b/source/lib/ufc.c
@@ -21,7 +21,7 @@
/*
* UFC-crypt: ultra fast crypt(3) implementation
*
- * Copyright (C) 1991, 1992, Free Software Foundation, Inc.
+ * Copyright (C) 1991-1997, Free Software Foundation, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -656,11 +656,11 @@ static char *output_conversion(v1, v2, salt)
return outbuf;
}
-ufc_long *_ufc_doit();
-
/*
* UNIX crypt function
*/
+
+ufc_long *_ufc_doit(ufc_long , ufc_long, ufc_long, ufc_long, ufc_long);
char *ufc_crypt(char *key,char *salt)
{ ufc_long *s;
@@ -702,7 +702,7 @@ extern long32 _ufc_sb0[], _ufc_sb1[], _ufc_sb2[], _ufc_sb3[];
#define SBA(sb, v) (*(long32*)((char*)(sb)+(v)))
-ufc_long *_ufc_doit(l1, l2, r1, r2, itr)
+static ufc_long *_ufc_doit(l1, l2, r1, r2, itr)
ufc_long l1, l2, r1, r2, itr;
{ int i;
long32 s, *k;
@@ -742,7 +742,7 @@ extern long64 _ufc_sb0[], _ufc_sb1[], _ufc_sb2[], _ufc_sb3[];
#define SBA(sb, v) (*(long64*)((char*)(sb)+(v)))
-ufc_long *_ufc_doit(l1, l2, r1, r2, itr)
+static ufc_long *_ufc_doit(l1, l2, r1, r2, itr)
ufc_long l1, l2, r1, r2, itr;
{ int i;
long64 l, r, s, *k;
@@ -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/username.c b/source/lib/username.c
index 3d214fbbdab..a9f64259916 100644
--- a/source/lib/username.c
+++ b/source/lib/username.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Username handling
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1997
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,9 +20,11 @@
*/
#include "includes.h"
-#include "loadparm.h"
extern int DEBUGLEVEL;
+/* internal functions - modified versions of the ones in password.c */
+static struct passwd *uname_string_combinations(char *s, struct passwd * (*fn) (), int N);
+static struct passwd *uname_string_combinations2(char *s, int offset, struct passwd * (*fn) (), int N);
/****************************************************************************
get a users home directory. tries as-is then lower case
@@ -63,7 +65,7 @@ void map_username(char *user)
if (strequal(user,last_from)) {
DEBUG(3,("Mapped user %s to %s\n",user,last_to));
- strcpy(user,last_to);
+ fstrcpy(user,last_to);
return;
}
@@ -142,6 +144,8 @@ Note that this changes user!
struct passwd *Get_Pwnam(char *user,BOOL allow_change)
{
fstring user2;
+ int last_char;
+ int usernamelevel = lp_usernamelevel();
struct passwd *ret;
@@ -173,8 +177,21 @@ struct passwd *Get_Pwnam(char *user,BOOL allow_change)
ret = _Get_Pwnam(user);
if (ret) return(ret);
+ /* try with last letter capitalised */
+ strlower(user);
+ last_char = strlen(user)-1;
+ user[last_char] = toupper(user[last_char]);
+ DEBUG(3, ("Trying username %s\n", user));
+ ret = _Get_Pwnam(user);
+ if (ret) return(ret);
+
+ /* try all combinations up to usernamelevel */
+ strlower(user);
+ ret = uname_string_combinations(user, _Get_Pwnam, usernamelevel);
+ if (ret) return(ret);
+
if (allow_change)
- strcpy(user,user2);
+ fstrcpy(user,user2);
return(NULL);
}
@@ -199,15 +216,23 @@ BOOL user_in_list(char *user,char *list)
static char *mydomain = NULL;
if (mydomain == 0)
yp_get_default_domain(&mydomain);
+
+ if(mydomain == 0)
+ {
+ DEBUG(5,("Unable to get default yp domain\n"));
+ }
+ else
+ {
- DEBUG(5,("looking for user %s of domain %s in netgroup %s\n",
+ DEBUG(5,("looking for user %s of domain %s in netgroup %s\n",
user, mydomain, &tok[1]));
- DEBUG(5,("innetgr is %s\n",
+ DEBUG(5,("innetgr is %s\n",
innetgr(&tok[1], (char *) 0, user, mydomain)
? "TRUE" : "FALSE"));
- if (innetgr(&tok[1], (char *)0, user, mydomain))
- return (True);
+ if (innetgr(&tok[1], (char *)0, user, mydomain))
+ return (True);
+ }
}
#endif
@@ -243,4 +268,57 @@ BOOL user_in_list(char *user,char *list)
return(False);
}
+/* The functions below have been taken from password.c and slightly modified */
+/****************************************************************************
+apply a function to upper/lower case combinations
+of a string and return true if one of them returns true.
+try all combinations with N uppercase letters.
+offset is the first char to try and change (start with 0)
+it assumes the string starts lowercased
+****************************************************************************/
+static struct passwd *uname_string_combinations2(char *s,int offset,struct passwd *(*fn)(),int N)
+{
+ int len = strlen(s);
+ int i;
+ struct passwd *ret;
+
+#ifdef PASSWORD_LENGTH
+ len = MIN(len,PASSWORD_LENGTH);
+#endif
+
+ if (N <= 0 || offset >= len)
+ return(fn(s));
+
+
+ for (i=offset;i<(len-(N-1));i++)
+
+ {
+ char c = s[i];
+ if (!islower(c)) continue;
+ s[i] = toupper(c);
+ ret = uname_string_combinations2(s,i+1,fn,N-1);
+ if(ret) return(ret);
+ s[i] = c;
+ }
+ return(NULL);
+}
+
+/****************************************************************************
+apply a function to upper/lower case combinations
+of a string and return true if one of them returns true.
+try all combinations with up to N uppercase letters.
+offset is the first char to try and change (start with 0)
+it assumes the string starts lowercased
+****************************************************************************/
+static struct passwd * uname_string_combinations(char *s,struct passwd * (*fn)(),int N)
+{
+ int n;
+ struct passwd *ret;
+ for (n=1;n<=N;n++)
+ {
+ ret = uname_string_combinations2(s,0,fn,n);
+ if(ret) return(ret);
+ }
+ return(NULL);
+}
diff --git a/source/lib/util.c b/source/lib/util.c
index 7bd6298c4ca..4d098013f24 100644
--- a/source/lib/util.c
+++ b/source/lib/util.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Samba utility functions
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1997
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,7 +20,10 @@
*/
#include "includes.h"
-#include "loadparm.h"
+
+#if (defined(NETGROUP) && defined (AUTOMOUNT))
+#include "rpcsvc/ypclnt.h"
+#endif
pstring scope = "";
@@ -30,8 +33,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,""};
@@ -41,20 +42,14 @@ FILE *dbf = NULL;
/* the client file descriptor */
int Client = -1;
-/* info on the client */
-struct from_host Client_info=
-{"UNKNOWN","0.0.0.0",NULL};
-
/* the last IP received from */
struct in_addr lastip;
/* the last port received from */
int lastport=0;
-/* my IP, the broadcast IP and the Netmask */
-struct in_addr myip;
-struct in_addr bcast_ip;
-struct in_addr Netmask;
+/* this is used by the chaining code */
+int chain_size = 0;
int trans_num = 0;
@@ -63,11 +58,7 @@ int trans_num = 0;
*/
int case_default = CASE_LOWER;
-
-/* size of reads during a direct file to file transfer */
-int ReadSize = 16*1024;
-
-pstring debugf = "/tmp/log.samba";
+pstring debugf = "";
int syslog_level;
/* the following control case operations - they are put here so the
@@ -81,16 +72,25 @@ BOOL case_mangle;
fstring remote_machine="";
fstring local_machine="";
fstring remote_arch="UNKNOWN";
+static enum remote_arch_types ra_type = RA_UNKNOWN;
fstring remote_proto="UNKNOWN";
pstring myhostname="";
pstring user_socket_options="";
+
pstring sesssetup_user="";
+pstring samlogon_user="";
+BOOL sam_logon_in_ssb = False;
-static char *filename_dos(char *path,char *buf);
+pstring myname = "";
+fstring myworkgroup = "";
+char **my_netbios_names;
+
+int smb_read_error = 0;
static BOOL stdout_logging = False;
+static char *filename_dos(char *path,char *buf);
/*******************************************************************
get ready for syslog stuff
@@ -101,7 +101,11 @@ void setup_logging(char *pname,BOOL interactive)
if (!interactive) {
char *p = strrchr(pname,'/');
if (p) pname = p+1;
+#ifdef LOG_DAEMON
openlog(pname, LOG_PID, LOG_DAEMON);
+#else /* LOG_DAEMON - for old systems that have no facility codes. */
+ openlog(pname, LOG_PID);
+#endif /* LOG_DAEMON */
}
#endif
if (interactive) {
@@ -130,6 +134,7 @@ void reopen_logs(void)
if (!strcsequal(fname,debugf) || !dbf || !file_exist(debugf,NULL))
{
+ int oldumask = umask(022);
strcpy(debugf,fname);
if (dbf) fclose(dbf);
if (append_log)
@@ -137,6 +142,7 @@ void reopen_logs(void)
else
dbf = fopen(debugf,"w");
if (dbf) setbuf(dbf,NULL);
+ umask(oldumask);
}
}
else
@@ -151,71 +157,78 @@ 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 || getuid() != 0) 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;
-
+ int old_errno = errno;
+
+ 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);
+ errno = old_errno;
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())
#endif
{
- if (!dbf)
- {
- dbf = fopen(debugf,"w");
- if (dbf)
- setbuf(dbf,NULL);
- else
- return(0);
- }
+ if (!dbf) {
+ int oldumask = umask(022);
+ dbf = fopen(debugf,"w");
+ umask(oldumask);
+ if (dbf) {
+ setbuf(dbf,NULL);
+ } else {
+ errno = old_errno;
+ return(0);
+ }
+ }
}
#ifdef SYSLOG
@@ -241,7 +254,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,277 +272,37 @@ va_dcl
if (!lp_syslog_only())
#endif
{
- vfprintf(dbf,format_str,ap);
- fflush(dbf);
- }
-
- va_end(ap);
- return(0);
-}
-
-/****************************************************************************
-routine to do file locking
-****************************************************************************/
-BOOL fcntl_lock(int fd,int op,uint32 offset,uint32 count,int type)
-{
-#if HAVE_FCNTL_LOCK
- struct flock lock;
- int ret;
-
-#if 1
- uint32 mask = 0xC0000000;
-
- /* make sure the count is reasonable, we might kill the lockd otherwise */
- count &= ~mask;
-
- /* the offset is often strange - remove 2 of its bits if either of
- the top two bits are set. Shift the top ones by two bits. This
- still allows OLE2 apps to operate, but should stop lockd from
- dieing */
- if ((offset & mask) != 0)
- offset = (offset & ~mask) | ((offset & mask) >> 2);
-#else
- unsigned long mask = ((unsigned)1<<31);
-
- /* interpret negative counts as large numbers */
- if (count < 0)
- count &= ~mask;
-
- /* no negative offsets */
- offset &= ~mask;
-
- /* count + offset must be in range */
- while ((offset < 0 || (offset + count < 0)) && mask)
- {
- offset &= ~mask;
- mask = mask >> 1;
- }
-#endif
-
-
- DEBUG(5,("fcntl_lock %d %d %d %d %d\n",fd,op,(int)offset,(int)count,type));
-
- lock.l_type = type;
- lock.l_whence = SEEK_SET;
- lock.l_start = (int)offset;
- lock.l_len = (int)count;
- lock.l_pid = 0;
-
- errno = 0;
-
- ret = fcntl(fd,op,&lock);
-
- if (errno != 0)
- DEBUG(3,("fcntl lock gave errno %d (%s)\n",errno,strerror(errno)));
-
- /* a lock query */
- if (op == F_GETLK)
- {
- if ((ret != -1) &&
- (lock.l_type != F_UNLCK) &&
- (lock.l_pid != 0) &&
- (lock.l_pid != getpid()))
- {
- DEBUG(3,("fd %d is locked by pid %d\n",fd,lock.l_pid));
- return(True);
- }
-
- /* it must be not locked or locked by me */
- return(False);
- }
-
- /* a lock set or unset */
- if (ret == -1)
- {
- DEBUG(3,("lock failed at offset %d count %d op %d type %d (%s)\n",
- offset,count,op,type,strerror(errno)));
-
- /* perhaps it doesn't support this sort of locking?? */
- if (errno == EINVAL)
- {
- DEBUG(3,("locking not supported? returning True\n"));
- return(True);
- }
-
- return(False);
- }
-
- /* everything went OK */
- DEBUG(5,("Lock call successful\n"));
-
- return(True);
-#else
- return(False);
-#endif
-}
-
-/*******************************************************************
-lock a file - returning a open file descriptor or -1 on failure
-The timeout is in seconds. 0 means no timeout
-********************************************************************/
-int file_lock(char *name,int timeout)
-{
- int fd = open(name,O_RDWR|O_CREAT,0666);
- time_t t=0;
- if (fd < 0) return(-1);
-
-#if HAVE_FCNTL_LOCK
- if (timeout) t = time(NULL);
- while (!timeout || (time(NULL)-t < timeout)) {
- if (fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)) return(fd);
- msleep(LOCK_RETRY_TIMEOUT);
- }
- return(-1);
-#else
- return(fd);
-#endif
-}
-
-/*******************************************************************
-unlock a file locked by file_lock
-********************************************************************/
-void file_unlock(int fd)
-{
- if (fd<0) return;
-#if HAVE_FCNTL_LOCK
- fcntl_lock(fd,F_SETLK,0,1,F_UNLCK);
-#endif
- close(fd);
-}
-
-/*******************************************************************
-a gettimeofday wrapper
-********************************************************************/
-void GetTimeOfDay(struct timeval *tval)
-{
-#ifdef GETTIMEOFDAY1
- gettimeofday(tval);
-#else
- gettimeofday(tval,NULL);
-#endif
-}
-
-int extra_time_offset = 0;
-
-static int timediff = 0;
-
-/*******************************************************************
-init the time differences
-********************************************************************/
-void TimeInit(void)
-{
- struct tm tm_utc,tm_local;
- time_t t;
-
- t = time(NULL);
-
- tm_utc = *(gmtime(&t));
- tm_local = *(localtime(&t));
-
-#ifdef HAVE_GMTOFF
- timediff = -tm_local.tm_gmtoff;
+#ifdef __STDC__
+ va_start(ap, format_str);
#else
- timediff = mktime(&tm_utc) - mktime(&tm_local);
+ va_start(ap);
+ format_str = va_arg(ap,char *);
#endif
-
- if (serverzone == 0) {
- serverzone = timediff - DSTDiff(t);
- DEBUG(4,("Serverzone is %d\n",serverzone));
- }
-}
-
-
-/*******************************************************************
-return the DST offset for a particular time
-We keep a table of DST offsets to prevent calling localtime() on each
-call of this function. This saves a LOT of time on many unixes.
-********************************************************************/
-int DSTDiff(time_t t)
-{
- static struct dst_table {time_t start,end; BOOL is_dst;} *dst_table = NULL;
- static int table_size = 0;
- int i;
- BOOL is_dst = False;
-
- if (t == 0) t = time(NULL);
-
-#ifndef NO_ISDST
- for (i=0;i<table_size;i++)
- if (t >= dst_table[i].start && t <= dst_table[i].end) break;
-
- if (i<table_size) {
- is_dst = dst_table[i].is_dst;
- } else {
- time_t low,high;
-
- dst_table = (struct dst_table *)Realloc(dst_table,
- sizeof(dst_table[0])*(i+1));
- if (!dst_table) {
- table_size = 0;
- return(0);
+ vfprintf(dbf,format_str,ap);
+ va_end(ap);
+ fflush(dbf);
}
- table_size++;
+ check_log_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;
- }
+ errno = old_errno;
- 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(0);
}
/****************************************************************************
-return the difference between local and GMT time
-****************************************************************************/
-int TimeDiff(time_t t)
+ find a suitable temporary directory. The result should be copied immediately
+ as it may be overwritten by a subsequent call
+ ****************************************************************************/
+char *tmpdir(void)
{
- static BOOL initialised = False;
- if (!initialised) {initialised=True; TimeInit();}
- return(timediff - DSTDiff(t));
+ char *p;
+ if ((p = getenv("TMPDIR"))) {
+ return p;
+ }
+ return "/tmp";
}
-/****************************************************************************
-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));
-}
/****************************************************************************
@@ -733,6 +513,12 @@ struct
#ifdef SO_RCVLOWAT
{"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
#endif
+#ifdef SO_SNDTIMEO
+ {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
+#endif
+#ifdef SO_RCVTIMEO
+ {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
+#endif
{NULL,0,0,0,0}};
@@ -805,32 +591,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)
@@ -873,7 +633,7 @@ char *StrCpy(char *dest,char *src)
/****************************************************************************
line strncpy but always null terminates. Make sure there is room!
****************************************************************************/
-char *StrnCpy(char *dest,const char *src,int n)
+char *StrnCpy(char *dest,char *src,int n)
{
char *d = dest;
if (!dest) return(NULL);
@@ -938,48 +698,61 @@ static int name_interpret(char *in,char *out)
/****************************************************************************
mangle a name into netbios format
+
+ Note: <Out> must be (33 + strlen(scope) + 2) bytes long, at minimum.
****************************************************************************/
-int name_mangle(char *In,char *Out,char name_type)
-{
- fstring name;
- char buf[20];
- char *in = (char *)&buf[0];
- char *out = (char *)Out;
- char *p, *label;
- int i;
+int name_mangle( char *In, char *Out, char name_type )
+ {
+ int i;
+ int c;
+ int len;
+ char buf[20];
+ char *p = Out;
+
+ /* Safely copy the input string, In, into buf[]. */
+ (void)memset( buf, 0, 20 );
+ if( '*' == In[0] )
+ buf[0] = '*';
+ else
+ (void)sprintf( buf, "%-15.15s%c", In, name_type );
- if (In[0] != '*') {
- StrnCpy(name,In,sizeof(name)-1);
- sprintf(buf,"%-15.15s%c",name,name_type);
- } else {
- buf[0]='*';
- memset(&buf[1],0,16);
- }
+ /* Place the length of the first field into the output buffer. */
+ p[0] = 32;
+ p++;
- *out++ = 32;
- for (i=0;i<16;i++) {
- char c = toupper(in[i]);
- out[i*2] = (c>>4) + 'A';
- out[i*2+1] = (c & 0xF) + 'A';
- }
- out[32]=0;
- out += 32;
-
- label = scope;
- while (*label)
+ /* Now convert the name to the rfc1001/1002 format. */
+ for( i = 0; i < 16; i++ )
{
- p = strchr(label, '.');
- if (p == 0)
- p = label + strlen(label);
- *out++ = p - label;
- memcpy(out, label, p - label);
- out += p - label;
- label += p - label + (*p == '.');
+ c = toupper( buf[i] );
+ p[i*2] = ( (c >> 4) & 0x000F ) + 'A';
+ p[(i*2)+1] = (c & 0x000F) + 'A';
}
- *out = 0;
- return(name_len(Out));
-}
+ p += 32;
+ p[0] = '\0';
+ /* Add the scope string. */
+ for( i = 0, len = 0; NULL != scope; i++, len++ )
+ {
+ switch( scope[i] )
+ {
+ case '\0':
+ p[0] = len;
+ if( len > 0 )
+ p[len+1] = 0;
+ return( name_len(Out) );
+ case '.':
+ p[0] = len;
+ p += (len + 1);
+ len = 0;
+ break;
+ default:
+ p[len+1] = scope[i];
+ break;
+ }
+ }
+
+ return( name_len(Out) );
+ } /* name_mangle */
/*******************************************************************
check if a file exists
@@ -1014,12 +787,17 @@ time_t file_modtime(char *fname)
BOOL directory_exist(char *dname,struct stat *st)
{
struct stat st2;
+ BOOL ret;
+
if (!st) st = &st2;
if (sys_stat(dname,st) != 0)
return(False);
- return(S_ISDIR(st->st_mode));
+ ret = S_ISDIR(st->st_mode);
+ if(!ret)
+ errno = ENOTDIR;
+ return ret;
}
/*******************************************************************
@@ -1033,159 +811,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
********************************************************************/
@@ -1211,10 +836,63 @@ char *attrib_string(int mode)
********************************************************************/
int StrCaseCmp(char *s, char *t)
{
- for (; tolower(*s) == tolower(*t); ++s, ++t)
- if (!*s) return 0;
+ /* compare until we run out of string, either t or s, or find a difference */
+ /* We *must* use toupper rather than tolower here due to the
+ asynchronous upper to lower mapping.
+ */
+#if !defined(KANJI_WIN95_COMPATIBILITY)
+ if(lp_client_code_page() == KANJI_CODEPAGE)
+ {
+ /* Win95 treats full width ascii characters as case sensitive. */
+ int diff;
+ for (;;)
+ {
+ if (!*s || !*t)
+ return toupper (*s) - toupper (*t);
+ else if (is_sj_alph (*s) && is_sj_alph (*t))
+ {
+ diff = sj_toupper2 (*(s+1)) - sj_toupper2 (*(t+1));
+ if (diff)
+ return diff;
+ s += 2;
+ t += 2;
+ }
+ else if (is_shift_jis (*s) && is_shift_jis (*t))
+ {
+ diff = ((int) (unsigned char) *s) - ((int) (unsigned char) *t);
+ if (diff)
+ return diff;
+ diff = ((int) (unsigned char) *(s+1)) - ((int) (unsigned char) *(t+1));
+ if (diff)
+ return diff;
+ s += 2;
+ t += 2;
+ }
+ else if (is_shift_jis (*s))
+ return 1;
+ else if (is_shift_jis (*t))
+ return -1;
+ else
+ {
+ diff = toupper (*s) - toupper (*t);
+ if (diff)
+ return diff;
+ s++;
+ t++;
+ }
+ }
+ }
+ else
+#endif /* KANJI_WIN95_COMPATIBILITY */
+ {
+ while (*s && *t && toupper(*s) == toupper(*t))
+ {
+ s++;
+ t++;
+ }
- return tolower(*s) - tolower(*t);
+ return(toupper(*s) - toupper(*t));
+ }
}
/*******************************************************************
@@ -1222,19 +900,79 @@ int StrCaseCmp(char *s, char *t)
********************************************************************/
int StrnCaseCmp(char *s, char *t, int n)
{
- while (n-- && *s && *t) {
- if (tolower(*s) != tolower(*t)) return(tolower(*s) - tolower(*t));
- s++; t++;
+ /* compare until we run out of string, either t or s, or chars */
+ /* We *must* use toupper rather than tolower here due to the
+ asynchronous upper to lower mapping.
+ */
+#if !defined(KANJI_WIN95_COMPATIBILITY)
+ if(lp_client_code_page() == KANJI_CODEPAGE)
+ {
+ /* Win95 treats full width ascii characters as case sensitive. */
+ int diff;
+ for (;n > 0;)
+ {
+ if (!*s || !*t)
+ return toupper (*s) - toupper (*t);
+ else if (is_sj_alph (*s) && is_sj_alph (*t))
+ {
+ diff = sj_toupper2 (*(s+1)) - sj_toupper2 (*(t+1));
+ if (diff)
+ return diff;
+ s += 2;
+ t += 2;
+ n -= 2;
+ }
+ else if (is_shift_jis (*s) && is_shift_jis (*t))
+ {
+ diff = ((int) (unsigned char) *s) - ((int) (unsigned char) *t);
+ if (diff)
+ return diff;
+ diff = ((int) (unsigned char) *(s+1)) - ((int) (unsigned char) *(t+1));
+ if (diff)
+ return diff;
+ s += 2;
+ t += 2;
+ n -= 2;
+ }
+ else if (is_shift_jis (*s))
+ return 1;
+ else if (is_shift_jis (*t))
+ return -1;
+ else
+ {
+ diff = toupper (*s) - toupper (*t);
+ if (diff)
+ return diff;
+ s++;
+ t++;
+ n--;
+ }
+ }
+ return 0;
}
- if (n) return(tolower(*s) - tolower(*t));
+ else
+#endif /* KANJI_WIN95_COMPATIBILITY */
+ {
+ while (n-- && *s && *t && toupper(*s) == toupper(*t))
+ {
+ s++;
+ t++;
+ }
- return(0);
+ /* not run out of chars - strings are different lengths */
+ if (n)
+ return(toupper(*s) - toupper(*t));
+
+ /* identical up to where we run out of chars,
+ and strings are same length */
+ return(0);
+ }
}
/*******************************************************************
compare 2 strings
********************************************************************/
-BOOL strequal(char *s1,char *s2)
+BOOL strequal(char *s1, char *s2)
{
if (s1 == s2) return(True);
if (!s1 || !s2) return(False);
@@ -1271,23 +1009,36 @@ BOOL strcsequal(char *s1,char *s2)
void strlower(char *s)
{
while (*s)
+ {
+#if !defined(KANJI_WIN95_COMPATIBILITY)
+ if(lp_client_code_page() == KANJI_CODEPAGE)
+ {
+ /* Win95 treats full width ascii characters as case sensitive. */
+ if (is_shift_jis (*s))
+ {
+ if (is_sj_upper (s[0], s[1]))
+ s[1] = sj_tolower2 (s[1]);
+ s += 2;
+ }
+ else if (is_kana (*s))
+ {
+ s++;
+ }
+ else
+ {
+ if (isupper(*s))
+ *s = tolower(*s);
+ s++;
+ }
+ }
+ else
+#endif /* KANJI_WIN95_COMPATIBILITY */
{
-#ifdef KANJI
- if (is_shift_jis (*s)) {
- s += 2;
- } else if (is_kana (*s)) {
- s++;
- } else {
- if (isupper(*s))
- *s = tolower(*s);
- s++;
- }
-#else
if (isupper(*s))
- *s = tolower(*s);
+ *s = tolower(*s);
s++;
-#endif /* KANJI */
}
+ }
}
/*******************************************************************
@@ -1296,23 +1047,36 @@ void strlower(char *s)
void strupper(char *s)
{
while (*s)
+ {
+#if !defined(KANJI_WIN95_COMPATIBILITY)
+ if(lp_client_code_page() == KANJI_CODEPAGE)
+ {
+ /* Win95 treats full width ascii characters as case sensitive. */
+ if (is_shift_jis (*s))
+ {
+ if (is_sj_lower (s[0], s[1]))
+ s[1] = sj_toupper2 (s[1]);
+ s += 2;
+ }
+ else if (is_kana (*s))
+ {
+ s++;
+ }
+ else
+ {
+ if (islower(*s))
+ *s = toupper(*s);
+ s++;
+ }
+ }
+ else
+#endif /* KANJI_WIN95_COMPATIBILITY */
{
-#ifdef KANJI
- if (is_shift_jis (*s)) {
- s += 2;
- } else if (is_kana (*s)) {
- s++;
- } else {
- if (islower(*s))
- *s = toupper(*s);
- s++;
- }
-#else
if (islower(*s))
- *s = toupper(*s);
+ *s = toupper(*s);
s++;
-#endif
}
+ }
}
/*******************************************************************
@@ -1344,23 +1108,30 @@ BOOL strisnormal(char *s)
void string_replace(char *s,char oldc,char newc)
{
while (*s)
+ {
+#if !defined(KANJI_WIN95_COMPATIBILITY)
+ if(lp_client_code_page() == KANJI_CODEPAGE)
+ {
+ /* Win95 treats full width ascii characters as case sensitive. */
+ if (is_shift_jis (*s))
+ s += 2;
+ else if (is_kana (*s))
+ s++;
+ else
+ {
+ if (oldc == *s)
+ *s = newc;
+ s++;
+ }
+ }
+ else
+#endif /* KANJI_WIN95_COMPATIBILITY */
{
-#ifdef KANJI
- if (is_shift_jis (*s)) {
- s += 2;
- } else if (is_kana (*s)) {
- s++;
- } else {
- if (oldc == *s)
- *s = newc;
- s++;
- }
-#else
if (oldc == *s)
- *s = newc;
+ *s = newc;
s++;
-#endif /* KANJI */
}
+ }
}
/****************************************************************************
@@ -1370,13 +1141,10 @@ void unix_format(char *fname)
{
pstring namecopy;
string_replace(fname,'\\','/');
-#ifndef KANJI
- dos2unix_format(fname, True);
-#endif /* KANJI */
if (*fname == '/')
{
- strcpy(namecopy,fname);
+ pstrcpy(namecopy,fname);
strcpy(fname,".");
strcat(fname,namecopy);
}
@@ -1387,9 +1155,6 @@ void unix_format(char *fname)
****************************************************************************/
void dos_format(char *fname)
{
-#ifndef KANJI
- unix2dos_format(fname, True);
-#endif /* KANJI */
string_replace(fname,'/','\\');
}
@@ -1401,8 +1166,8 @@ void show_msg(char *buf)
{
int i;
int bcc=0;
- if (DEBUGLEVEL < 5)
- return;
+
+ if (DEBUGLEVEL < 5) return;
DEBUG(5,("size=%d\nsmb_com=0x%x\nsmb_rcls=%d\nsmb_reh=%d\nsmb_err=%d\nsmb_flg=%d\nsmb_flg2=%d\n",
smb_len(buf),
@@ -1418,16 +1183,17 @@ void show_msg(char *buf)
(int)SVAL(buf,smb_uid),
(int)SVAL(buf,smb_mid),
(int)CVAL(buf,smb_wct)));
+
for (i=0;i<(int)CVAL(buf,smb_wct);i++)
DEBUG(5,("smb_vwv[%d]=%d (0x%X)\n",i,
SVAL(buf,smb_vwv+2*i),SVAL(buf,smb_vwv+2*i)));
+
bcc = (int)SVAL(buf,smb_vwv+2*(CVAL(buf,smb_wct)));
DEBUG(5,("smb_bcc=%d\n",bcc));
- if (DEBUGLEVEL < 10)
- return;
- for (i=0;i<MIN(bcc,128);i++)
- DEBUG(10,("%X ",CVAL(smb_buf(buf),i)));
- DEBUG(10,("\n"));
+
+ if (DEBUGLEVEL < 10) return;
+
+ dump_data(10, smb_buf(buf), MIN(bcc, 512));
}
/*******************************************************************
@@ -1512,7 +1278,7 @@ return the SMB offset into an SMB buffer
********************************************************************/
int smb_offset(char *p,char *buf)
{
- return(PTR_DIFF(p,buf+4));
+ return(PTR_DIFF(p,buf+4) + chain_size);
}
@@ -1570,7 +1336,7 @@ void dos_clean_name(char *s)
pstring s1;
*p = 0;
- strcpy(s1,p+3);
+ pstrcpy(s1,p+3);
if ((p=strrchr(s,'\\')) != NULL)
*p = 0;
@@ -1596,12 +1362,19 @@ void unix_clean_name(char *s)
/* remove any double slashes */
string_sub(s, "//","/");
+ /* Remove leading ./ characters */
+ if(strncmp(s, "./", 2) == 0) {
+ trim_string(s, "./", NULL);
+ if(*s == 0)
+ strcpy(s,"./");
+ }
+
while ((p = strstr(s,"/../")) != NULL)
{
pstring s1;
*p = 0;
- strcpy(s1,p+3);
+ pstrcpy(s1,p+3);
if ((p=strrchr(s,'/')) != NULL)
*p = 0;
@@ -1628,24 +1401,10 @@ int ChDir(char *path)
DEBUG(3,("chdir to %s\n",path));
res = sys_chdir(path);
if (!res)
- strcpy(LastDir,path);
+ pstrcpy(LastDir,path);
return(res);
}
-
-/*******************************************************************
- return the absolute current directory path. A dumb version.
-********************************************************************/
-static char *Dumb_GetWd(char *s)
-{
-#ifdef USE_GETCWD
- return ((char *)getcwd(s,sizeof(pstring)));
-#else
- return ((char *)getwd(s));
-#endif
-}
-
-
/* number of list structures for a caching GetWd function. */
#define MAX_GETWDCACHE (50)
@@ -1672,7 +1431,7 @@ char *GetWd(char *str)
*s = 0;
if (!use_getwd_cache)
- return(Dumb_GetWd(str));
+ return(sys_getwd(str));
/* init the cache */
if (!getwd_cache_init)
@@ -1691,7 +1450,7 @@ char *GetWd(char *str)
if (stat(".",&st) == -1)
{
DEBUG(0,("Very strange, couldn't stat \".\"\n"));
- return(Dumb_GetWd(str));
+ return(sys_getwd(str));
}
@@ -1735,9 +1494,9 @@ char *GetWd(char *str)
The very slow getcwd, which spawns a process on some systems, or the
not quite so bad getwd. */
- if (!Dumb_GetWd(s))
+ if (!sys_getwd(s))
{
- DEBUG(0,("Getwd failed, errno %d\n",errno));
+ DEBUG(0,("Getwd failed, errno %s\n",strerror(errno)));
return (NULL);
}
@@ -1790,6 +1549,10 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks)
DEBUG(3,("Illegal file name? (%s)\n",s));
return(False);
}
+
+ if (strlen(s) == 0)
+ strcpy(s,"./");
+
return(True);
}
@@ -1798,7 +1561,7 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks)
/* remove any double slashes */
string_sub(s,"//","/");
- strcpy(basename,s);
+ pstrcpy(basename,s);
p = strrchr(basename,'/');
if (!p)
@@ -1868,12 +1631,12 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks)
if (relative)
{
if (newname[l] == '/')
- strcpy(s,newname + l + 1);
+ pstrcpy(s,newname + l + 1);
else
- strcpy(s,newname+l);
+ pstrcpy(s,newname+l);
}
else
- strcpy(s,newname);
+ pstrcpy(s,newname);
}
ChDir(wd);
@@ -1897,10 +1660,10 @@ static void expand_one(char *Mask,int len)
int lfill = (len+1) - strlen(Mask);
int l1= (p1 - Mask);
pstring tmp;
- strcpy(tmp,Mask);
+ pstrcpy(tmp,Mask);
memset(tmp+l1,'?',lfill);
- strcpy(tmp + l1 + lfill,Mask + l1 + 1);
- strcpy(Mask,tmp);
+ pstrcpy(tmp + l1 + lfill,Mask + l1 + 1);
+ pstrcpy(Mask,tmp);
}
}
@@ -1924,20 +1687,20 @@ void expand_mask(char *Mask,BOOL doext)
filename_dos(Mask,filepart);
- strcpy(mbeg,filepart);
+ pstrcpy(mbeg,filepart);
if ((p1 = strchr(mbeg,'.')) != NULL)
{
hasdot = True;
*p1 = 0;
p1++;
- strcpy(mext,p1);
+ pstrcpy(mext,p1);
}
else
{
strcpy(mext,"");
if (strlen(mbeg) > 8)
{
- strcpy(mext,mbeg + 8);
+ pstrcpy(mext,mbeg + 8);
mbeg[8] = 0;
}
}
@@ -1955,7 +1718,7 @@ void expand_mask(char *Mask,BOOL doext)
if (*mext)
expand_one(mext,3);
- strcpy(Mask,dirpart);
+ pstrcpy(Mask,dirpart);
if (*dirpart || absolute) strcat(Mask,"\\");
strcat(Mask,mbeg);
strcat(Mask,".");
@@ -1971,21 +1734,30 @@ does a string have any uppercase chars in it?
BOOL strhasupper(char *s)
{
while (*s)
+ {
+#if !defined(KANJI_WIN95_COMPATIBILITY)
+ if(lp_client_code_page() == KANJI_CODEPAGE)
{
-#ifdef KANJI
- if (is_shift_jis (*s)) {
- s += 2;
- } else if (is_kana (*s)) {
- s++;
- } else {
- if (isupper(*s)) return(True);
- s++;
- }
-#else
- if (isupper(*s)) return(True);
+ /* Win95 treats full width ascii characters as case sensitive. */
+ if (is_shift_jis (*s))
+ s += 2;
+ else if (is_kana (*s))
+ s++;
+ else
+ {
+ if (isupper(*s))
+ return(True);
+ s++;
+ }
+ }
+ else
+#endif /* KANJI_WIN95_COMPATIBILITY */
+ {
+ if (isupper(*s))
+ return(True);
s++;
-#endif /* KANJI */
}
+ }
return(False);
}
@@ -1995,21 +1767,38 @@ does a string have any lowercase chars in it?
BOOL strhaslower(char *s)
{
while (*s)
+ {
+#if !defined(KANJI_WIN95_COMPATIBILITY)
+ if(lp_client_code_page() == KANJI_CODEPAGE)
{
-#ifdef KANJI
- if (is_shift_jis (*s)) {
- s += 2;
- } else if (is_kana (*s)) {
- s++;
- } else {
- if (islower(*s)) return(True);
- s++;
- }
-#else
- if (islower(*s)) return(True);
+ /* Win95 treats full width ascii characters as case sensitive. */
+ if (is_shift_jis (*s))
+ {
+ if (is_sj_upper (s[0], s[1]))
+ return(True);
+ if (is_sj_lower (s[0], s[1]))
+ return (True);
+ s += 2;
+ }
+ else if (is_kana (*s))
+ {
+ s++;
+ }
+ else
+ {
+ if (islower(*s))
+ return(True);
+ s++;
+ }
+ }
+ else
+#endif /* KANJI_WIN95_COMPATIBILITY */
+ {
+ if (islower(*s))
+ return(True);
s++;
-#endif /* KANJI */
}
+ }
return(False);
}
@@ -2019,12 +1808,33 @@ find the number of chars in a string
int count_chars(char *s,char c)
{
int count=0;
- while (*s)
+
+#if !defined(KANJI_WIN95_COMPATIBILITY)
+ if(lp_client_code_page() == KANJI_CODEPAGE)
+ {
+ /* Win95 treats full width ascii characters as case sensitive. */
+ while (*s)
+ {
+ if (is_shift_jis (*s))
+ s += 2;
+ else
+ {
+ if (*s == c)
+ count++;
+ s++;
+ }
+ }
+ }
+ else
+#endif /* KANJI_WIN95_COMPATIBILITY */
+ {
+ while (*s)
{
if (*s == c)
- count++;
+ count++;
s++;
}
+ }
return(count);
}
@@ -2037,7 +1847,7 @@ void make_dir_struct(char *buf,char *mask,char *fname,unsigned int size,int mode
char *p;
pstring mask2;
- strcpy(mask2,mask);
+ pstrcpy(mask2,mask);
if ((mode & aDIR) != 0)
size = 0;
@@ -2089,6 +1899,35 @@ void close_low_fds(void)
}
}
+/****************************************************************************
+Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
+else
+if SYSV use O_NDELAY
+if BSD use FNDELAY
+****************************************************************************/
+int set_blocking(int fd, BOOL set)
+{
+ int val;
+#ifdef O_NONBLOCK
+#define FLAG_TO_SET O_NONBLOCK
+#else
+#ifdef SYSV
+#define FLAG_TO_SET O_NDELAY
+#else /* BSD */
+#define FLAG_TO_SET FNDELAY
+#endif
+#endif
+
+ if((val = fcntl(fd, F_GETFL, 0)) == -1)
+ return -1;
+ if(set) /* Turn blocking on - ie. clear nonblock flag */
+ val &= ~FLAG_TO_SET;
+ else
+ val |= FLAG_TO_SET;
+ return fcntl( fd, F_SETFL, val);
+#undef FLAG_TO_SET
+}
+
/****************************************************************************
write to a socket
@@ -2119,68 +1958,18 @@ 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=%s\n",strerror(errno)));
+ return(0);
+ }
lastip = *(struct in_addr *) &sock.sa_data[2];
lastport = ntohs(((struct sockaddr_in *)&sock)->sin_port);
- return(ret);
-}
+ DEBUG(10,("read_udp_socket: lastip %s lastport %d read: %d\n",
+ inet_ntoa(lastip), lastport, ret));
-/****************************************************************************
-Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
-else
-if SYSV use O_NDELAY
-if BSD use FNDELAY
-****************************************************************************/
-int set_blocking(int fd, BOOL set)
-{
-int val;
-#ifdef O_NONBLOCK
-#define FLAG_TO_SET O_NONBLOCK
-#else
-#ifdef SYSV
-#define FLAG_TO_SET O_NDELAY
-#else /* BSD */
-#define FLAG_TO_SET FNDELAY
-#endif
-#endif
-
- if((val = fcntl(fd, F_GETFL, 0))==-1)
- return -1;
- if(set) /* Turn blocking on - ie. clear nonblock flag */
- val &= ~FLAG_TO_SET;
- else
- val |= FLAG_TO_SET;
- return fcntl( fd, F_SETFL, val);
-#undef FLAG_TO_SET
-}
-
-
-/****************************************************************************
-Calculate the difference in timeout values. Return 1 if val1 > val2,
-0 if val1 == val2, -1 if val1 < val2. Stores result in retval. retval
-may be == val1 or val2
-****************************************************************************/
-static int tval_sub( struct timeval *retval, struct timeval *val1, struct timeval *val2)
-{
- int usecdiff = val1->tv_usec - val2->tv_usec;
- int secdiff = val1->tv_sec - val2->tv_sec;
- if(usecdiff < 0) {
- usecdiff = 1000000 + usecdiff;
- secdiff--;
- }
- retval->tv_sec = secdiff;
- retval->tv_usec = usecdiff;
- if(secdiff < 0)
- return -1;
- if(secdiff > 0)
- return 1;
- return (usecdiff < 0 ) ? -1 : ((usecdiff > 0 ) ? 1 : 0);
+ return(ret);
}
/****************************************************************************
@@ -2188,46 +1977,39 @@ read data from a device with a timout in msec.
mincount = if timeout, minimum to read before returning
maxcount = number to be read.
****************************************************************************/
-int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out,BOOL exact)
+int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out)
{
fd_set fds;
int selrtn;
int readret;
int nread = 0;
- struct timeval timeout, tval1, tval2, tvaldiff;
- int error_limit = 5;
+ struct timeval timeout;
/* just checking .... */
if (maxcnt <= 0) return(0);
- if(time_out == -2)
- time_out = DEFAULT_PIPE_TIMEOUT;
+ smb_read_error = 0;
/* Blocking read */
- if(time_out < 0) {
+ if (time_out <= 0) {
if (mincnt == 0) mincnt = maxcnt;
- while (nread < mincnt)
- {
- readret = read(fd, buf + nread, maxcnt - nread);
- if (readret <= 0) return(nread);
- nread += readret;
+ while (nread < mincnt) {
+ readret = read(fd, buf + nread, maxcnt - nread);
+ if (readret == 0) {
+ smb_read_error = READ_EOF;
+ return -1;
+ }
+
+ if (readret == -1) {
+ smb_read_error = READ_ERROR;
+ return -1;
}
+ nread += readret;
+ }
return(nread);
}
- /* Non blocking read */
- if(time_out == 0) {
- set_blocking(fd, False);
- nread = read_data(fd, buf, mincnt);
- if (nread < maxcnt)
- nread += read(fd,buf+nread,maxcnt-nread);
- if(nread == -1 && errno == EWOULDBLOCK)
- nread = 0;
- set_blocking(fd,True);
- return nread;
- }
-
/* Most difficult - timeout read */
/* If this is ever called on a disk file and
mincnt is greater then the filesize then
@@ -2238,71 +2020,40 @@ int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out,BOOL
timeout.tv_sec = time_out / 1000;
timeout.tv_usec = 1000 * (time_out % 1000);
- /* As most UNIXes don't modify the value of timeout
- when they return from select we need to get the timeofday (in usec)
- now, and also after the select returns so we know
- how much time has elapsed */
-
- if (exact)
- GetTimeOfDay( &tval1);
- nread = 0; /* Number of bytes we have read */
-
- for(;;)
+ for (nread=0; nread<mincnt; )
{
FD_ZERO(&fds);
FD_SET(fd,&fds);
selrtn = sys_select(&fds,&timeout);
-
+
/* Check if error */
if(selrtn == -1) {
- errno = EBADF;
+ /* something is wrong. Maybe the socket is dead? */
+ smb_read_error = READ_ERROR;
return -1;
}
/* Did we timeout ? */
if (selrtn == 0) {
- if (nread < mincnt) return -1;
- break; /* Yes */
+ smb_read_error = READ_TIMEOUT;
+ return -1;
}
readret = read(fd, buf+nread, maxcnt-nread);
- if (readret == 0 && nread < mincnt) {
- /* error_limit should not really be needed, but some systems
- do strange things ... I don't want to just continue
- indefinately in case we get an infinite loop */
- if (error_limit--) continue;
- return(-1);
+ if (readret == 0) {
+ /* we got EOF on the file descriptor */
+ smb_read_error = READ_EOF;
+ return -1;
}
- if (readret < 0) {
- /* force a particular error number for
- portability */
- DEBUG(5,("read gave error %s\n",strerror(errno)));
- errno = EBADF;
+ if (readret == -1) {
+ /* the descriptor is probably dead */
+ smb_read_error = READ_ERROR;
return -1;
}
nread += readret;
-
- /* If we have read more than mincnt then return */
- if (nread >= mincnt)
- break;
-
- /* We need to do another select - but first reduce the
- time_out by the amount of time already elapsed - if
- this is less than zero then return */
- if (exact) {
- GetTimeOfDay(&tval2);
- (void)tval_sub( &tvaldiff, &tval2, &tval1);
-
- if (tval_sub(&timeout, &timeout, &tvaldiff) <= 0)
- break; /* We timed out */
- }
-
- /* Save the time of day as we need to do the select
- again (saves a system call) */
- tval1 = tval2;
}
/* Return the number we got */
@@ -2369,16 +2120,19 @@ int read_data(int fd,char *buffer,int N)
int ret;
int total=0;
+ smb_read_error = 0;
+
while (total < N)
{
ret = read(fd,buffer + total,N - total);
-
- /* this is for portability */
- if (ret < 0)
- errno = EBADF;
-
- if (ret <= 0)
- return total;
+ if (ret == 0) {
+ smb_read_error = READ_EOF;
+ return 0;
+ }
+ if (ret == -1) {
+ smb_read_error = READ_ERROR;
+ return -1;
+ }
total += ret;
}
return total;
@@ -2397,8 +2151,8 @@ int write_data(int fd,char *buffer,int N)
{
ret = write(fd,buffer + total,N - total);
- if (ret <= 0)
- return total;
+ if (ret == -1) return -1;
+ if (ret == 0) return total;
total += ret;
}
@@ -2406,142 +2160,28 @@ int write_data(int fd,char *buffer,int N)
}
-/* variables used by the read prediction module */
-int rp_fd = -1;
-int rp_offset = 0;
-int rp_length = 0;
-int rp_alloced = 0;
-int rp_predict_fd = -1;
-int rp_predict_offset = 0;
-int rp_predict_length = 0;
-int rp_timeout = 5;
-time_t rp_time = 0;
-char *rp_buffer = NULL;
-BOOL predict_skip=False;
-time_t smb_last_time=(time_t)0;
-
-/****************************************************************************
-handle read prediction on a file
-****************************************************************************/
-int read_predict(int fd,int offset,char *buf,char **ptr,int num)
-{
- int ret = 0;
- int possible = rp_length - (offset - rp_offset);
-
- possible = MIN(possible,num);
-
- /* give data if possible */
- if (fd == rp_fd &&
- offset >= rp_offset &&
- possible>0 &&
- smb_last_time-rp_time < rp_timeout)
- {
- ret = possible;
- if (buf)
- memcpy(buf,rp_buffer + (offset-rp_offset),possible);
- else
- *ptr = rp_buffer + (offset-rp_offset);
- DEBUG(5,("read-prediction gave %d bytes of %d\n",ret,num));
- }
-
- if (ret == num) {
- predict_skip = True;
- } else {
- predict_skip = False;
-
- /* prepare the next prediction */
- rp_predict_fd = fd;
- rp_predict_offset = offset + num;
- rp_predict_length = num;
- }
-
- if (ret < 0) ret = 0;
-
- return(ret);
-}
-
-/****************************************************************************
-pre-read some data
-****************************************************************************/
-void do_read_prediction()
-{
- if (predict_skip) return;
-
- if (rp_predict_fd == -1)
- return;
-
- rp_fd = rp_predict_fd;
- rp_offset = rp_predict_offset;
- rp_length = 0;
-
- rp_predict_fd = -1;
-
- rp_predict_length = MIN(rp_predict_length,2*ReadSize);
- rp_predict_length = MAX(rp_predict_length,1024);
- rp_offset = (rp_offset/1024)*1024;
- rp_predict_length = (rp_predict_length/1024)*1024;
-
- if (rp_predict_length > rp_alloced)
- {
- rp_buffer = Realloc(rp_buffer,rp_predict_length);
- rp_alloced = rp_predict_length;
- if (!rp_buffer)
- {
- DEBUG(0,("can't allocate read-prediction buffer\n"));
- rp_predict_fd = -1;
- rp_fd = -1;
- rp_alloced = 0;
- return;
- }
- }
-
- if (lseek(rp_fd,rp_offset,SEEK_SET) != rp_offset) {
- rp_fd = -1;
- rp_predict_fd = -1;
- return;
- }
-
- rp_length = read(rp_fd,rp_buffer,rp_predict_length);
- rp_time = time(NULL);
- if (rp_length < 0)
- rp_length = 0;
-}
-
-/****************************************************************************
-invalidate read-prediction on a fd
-****************************************************************************/
-void invalidate_read_prediction(int fd)
-{
- if (rp_fd == fd)
- rp_fd = -1;
- if (rp_predict_fd == fd)
- rp_predict_fd = -1;
-}
-
-
/****************************************************************************
transfer some data between two fd's
****************************************************************************/
int transfer_file(int infd,int outfd,int n,char *header,int headlen,int align)
{
static char *buf=NULL;
+ static int size=0;
char *buf1,*abuf;
- static int size = 0;
int total = 0;
DEBUG(4,("transfer_file %d (head=%d) called\n",n,headlen));
- if ((size < ReadSize) && buf) {
- free(buf);
- buf = NULL;
+ if (size == 0) {
+ size = lp_readsize();
+ size = MAX(size,1024);
}
- size = MAX(ReadSize,1024);
-
while (!buf && size>0) {
buf = (char *)Realloc(buf,size+8);
if (!buf) size /= 2;
}
+
if (!buf) {
DEBUG(0,("Can't allocate transfer buffer!\n"));
exit(1);
@@ -2616,30 +2256,19 @@ int read_smb_length(int fd,char *inbuf,int timeout)
while (!ok)
{
if (timeout > 0)
- ok = (read_with_timeout(fd,buffer,4,4,timeout,False) == 4);
- else
+ ok = (read_with_timeout(fd,buffer,4,4,timeout) == 4);
+ else
ok = (read_data(fd,buffer,4) == 4);
if (!ok)
- {
- if (timeout>0)
- {
- DEBUG(10,("select timeout (%d)\n", timeout));
- return(-1);
- }
- else
- {
- DEBUG(6,("couldn't read from client\n"));
- exit(1);
- }
- }
+ return(-1);
len = smb_len(buffer);
msg_type = CVAL(buffer,0);
if (msg_type == 0x85)
{
- DEBUG(5,( "Got keepalive packet\n"));
+ DEBUG(5,("Got keepalive packet\n"));
ok = False;
}
}
@@ -2652,13 +2281,15 @@ int read_smb_length(int fd,char *inbuf,int timeout)
/****************************************************************************
- read an smb from a fd and return it's length
+ read an smb from a fd. Note that the buffer *MUST* be of size
+ BUFFER_SIZE+SAFETY_MARGIN.
The timeout is in milli seconds
****************************************************************************/
-BOOL receive_smb(int fd,char *buffer,int timeout)
+BOOL receive_smb(int fd,char *buffer, int timeout)
{
- int len;
- BOOL ok;
+ int len,ret;
+
+ smb_read_error = 0;
bzero(buffer,smb_size + 100);
@@ -2666,24 +2297,217 @@ 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);
+ }
+
+ ret = read_data(fd,buffer+4,len);
+ if (ret != len) {
+ smb_read_error = READ_ERROR;
+ return False;
+ }
+
+ return(True);
+}
+
+/****************************************************************************
+ read a message from a udp fd.
+The timeout is in milli seconds
+****************************************************************************/
+BOOL receive_local_message(int fd, char *buffer, int buffer_len, int timeout)
+{
+ struct sockaddr_in from;
+ int fromlen = sizeof(from);
+ int32 msg_len = 0;
+
+ if(timeout != 0)
+ {
+ struct timeval to;
+ fd_set fds;
+ int selrtn;
+
+ FD_ZERO(&fds);
+ FD_SET(fd,&fds);
- ok = (read_data(fd,buffer+4,len) == len);
+ to.tv_sec = timeout / 1000;
+ to.tv_usec = (timeout % 1000) * 1000;
- if (!ok)
+ selrtn = sys_select(&fds,&to);
+
+ /* Check if error */
+ if(selrtn == -1)
{
- close_sockets();
- exit(1);
+ /* something is wrong. Maybe the socket is dead? */
+ smb_read_error = READ_ERROR;
+ return False;
+ }
+
+ /* Did we timeout ? */
+ if (selrtn == 0)
+ {
+ smb_read_error = READ_TIMEOUT;
+ return False;
}
+ }
- return(True);
+ /*
+ * Read a loopback udp message.
+ */
+ msg_len = recvfrom(fd, &buffer[UDP_CMD_HEADER_LEN],
+ buffer_len - UDP_CMD_HEADER_LEN, 0,
+ (struct sockaddr *)&from, &fromlen);
+
+ if(msg_len < 0)
+ {
+ DEBUG(0,("receive_local_message. Error in recvfrom. (%s).\n",strerror(errno)));
+ return False;
+ }
+
+ /* Validate message length. */
+ if(msg_len > (buffer_len - UDP_CMD_HEADER_LEN))
+ {
+ DEBUG(0,("receive_local_message: invalid msg_len (%d) max can be %d\n",
+ msg_len,
+ buffer_len - UDP_CMD_HEADER_LEN));
+ return False;
+ }
+
+ /* Validate message from address (must be localhost). */
+ if(from.sin_addr.s_addr != htonl(INADDR_LOOPBACK))
+ {
+ DEBUG(0,("receive_local_message: invalid 'from' address \
+(was %x should be 127.0.0.1\n", from.sin_addr.s_addr));
+ return False;
+ }
+
+ /* Setup the message header */
+ SIVAL(buffer,UDP_CMD_LEN_OFFSET,msg_len);
+ SSVAL(buffer,UDP_CMD_PORT_OFFSET,ntohs(from.sin_port));
+
+ return True;
}
+/****************************************************************************
+ structure to hold a linked list of local udp messages.
+ for processing.
+****************************************************************************/
+
+typedef struct _udp_message_list {
+ struct _udp_message_list *msg_next;
+ char *msg_buf;
+ int msg_len;
+} udp_message_list;
+
+static udp_message_list *udp_msg_head = NULL;
+
+/****************************************************************************
+ Function to push a linked list of local udp messages ready
+ for processing.
+****************************************************************************/
+BOOL push_local_message(char *buf, int msg_len)
+{
+ udp_message_list *msg = (udp_message_list *)malloc(sizeof(udp_message_list));
+
+ if(msg == NULL)
+ {
+ DEBUG(0,("push_local_message: malloc fail (1)\n"));
+ return False;
+ }
+
+ msg->msg_buf = (char *)malloc(msg_len);
+ if(msg->msg_buf == NULL)
+ {
+ DEBUG(0,("push_local_message: malloc fail (2)\n"));
+ free((char *)msg);
+ return False;
+ }
+
+ memcpy(msg->msg_buf, buf, msg_len);
+ msg->msg_len = msg_len;
+
+ msg->msg_next = udp_msg_head;
+ udp_msg_head = msg;
+
+ return True;
+}
+
+/****************************************************************************
+ Do a select on an two fd's - with timeout.
+
+ If a local udp message has been pushed onto the
+ queue (this can only happen during oplock break
+ processing) return this first.
+
+ If the first smbfd is ready then read an smb from it.
+ if the second (loopback UDP) fd is ready then read a message
+ from it and setup the buffer header to identify the length
+ and from address.
+ Returns False on timeout or error.
+ Else returns True.
+
+The timeout is in milli seconds
+****************************************************************************/
+BOOL receive_message_or_smb(int smbfd, int oplock_fd,
+ char *buffer, int buffer_len,
+ int timeout, BOOL *got_smb)
+{
+ fd_set fds;
+ int selrtn;
+ struct timeval to;
+
+ *got_smb = False;
+
+ /*
+ * Check to see if we already have a message on the udp queue.
+ * If so - copy and return it.
+ */
+
+ if(udp_msg_head)
+ {
+ udp_message_list *msg = udp_msg_head;
+ memcpy(buffer, msg->msg_buf, MIN(buffer_len, msg->msg_len));
+ udp_msg_head = msg->msg_next;
+
+ /* Free the message we just copied. */
+ free((char *)msg->msg_buf);
+ free((char *)msg);
+ return True;
+ }
+
+ FD_ZERO(&fds);
+ FD_SET(smbfd,&fds);
+ FD_SET(oplock_fd,&fds);
+
+ to.tv_sec = timeout / 1000;
+ to.tv_usec = (timeout % 1000) * 1000;
+
+ selrtn = sys_select(&fds,timeout>0?&to:NULL);
+
+ /* Check if error */
+ if(selrtn == -1) {
+ /* something is wrong. Maybe the socket is dead? */
+ smb_read_error = READ_ERROR;
+ return False;
+ }
+
+ /* Did we timeout ? */
+ if (selrtn == 0) {
+ smb_read_error = READ_TIMEOUT;
+ return False;
+ }
+
+ if (FD_ISSET(smbfd,&fds))
+ {
+ *got_smb = True;
+ return receive_smb(smbfd, buffer, 0);
+ }
+ else
+ {
+ return receive_local_message(oplock_fd, buffer, buffer_len, 0);
+ }
+}
/****************************************************************************
send an smb to a fd
@@ -2742,21 +2566,27 @@ int name_extract(char *buf,int ofs,char *name)
strcpy(name,"");
if (d < -50 || d > 50) return(0);
return(name_interpret(p,name));
-}
+}
-
/****************************************************************************
return the total storage length of a mangled name
****************************************************************************/
-int name_len(char *s)
-{
- char *s0=s;
- unsigned char c = *(unsigned char *)s;
- if ((c & 0xC0) == 0xC0)
+int name_len( char *s )
+ {
+ int len;
+
+ /* If the two high bits of the byte are set, return 2. */
+ if( 0xC0 == (*(unsigned char *)s & 0xC0) )
return(2);
- while (*s) s += (*s)+1;
- return(PTR_DIFF(s,s0)+1);
-}
+
+ /* Add up the length bytes. */
+ for( len = 1; (*s); s += (*s) + 1 )
+ {
+ len += *s + 1;
+ }
+
+ return( len );
+ } /* name_len */
/****************************************************************************
send a single packet to a port on another machine
@@ -2792,8 +2622,8 @@ BOOL send_one_packet(char *buf,int len,struct in_addr ip,int port,int type)
ret = (sendto(out_fd,buf,len,0,(struct sockaddr *)&sock_out,sizeof(sock_out)) >= 0);
if (!ret)
- DEBUG(0,("Packet send to %s(%d) failed ERRNO=%d\n",
- inet_ntoa(ip),port,errno));
+ DEBUG(0,("Packet send to %s(%d) failed ERRNO=%s\n",
+ inet_ntoa(ip),port,strerror(errno)));
close(out_fd);
return(ret);
@@ -2871,7 +2701,12 @@ BOOL string_init(char **dest,char *src)
}
else
{
- *dest = (char *)malloc(l+1);
+ (*dest) = (char *)malloc(l+1);
+ if ((*dest) == NULL) {
+ DEBUG(0,("Out of memory in string_init\n"));
+ return False;
+ }
+
strcpy(*dest,src);
}
return(True);
@@ -3040,35 +2875,35 @@ BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2)
if (strequal(p1,"*")) return(True);
- DEBUG(5,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", p2, p1, case_sig));
+ DEBUG(8,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", p2, p1, case_sig));
if (trans2) {
- strcpy(ebase,p1);
- strcpy(sbase,p2);
+ fstrcpy(ebase,p1);
+ fstrcpy(sbase,p2);
} else {
if ((p=strrchr(p1,'.'))) {
*p = 0;
- strcpy(ebase,p1);
- strcpy(eext,p+1);
+ fstrcpy(ebase,p1);
+ fstrcpy(eext,p+1);
} else {
- strcpy(ebase,p1);
+ fstrcpy(ebase,p1);
eext[0] = 0;
}
if (!strequal(p2,".") && !strequal(p2,"..") && (p=strrchr(p2,'.'))) {
*p = 0;
- strcpy(sbase,p2);
- strcpy(sext,p+1);
+ fstrcpy(sbase,p2);
+ fstrcpy(sext,p+1);
} else {
- strcpy(sbase,p2);
- strcpy(sext,"");
+ fstrcpy(sbase,p2);
+ fstrcpy(sext,"");
}
}
matched = do_match(sbase,ebase,case_sig) &&
(trans2 || do_match(sext,eext,case_sig));
- DEBUG(5,("mask_match returning %d\n", matched));
+ DEBUG(8,("mask_match returning %d\n", matched));
return matched;
}
@@ -3087,7 +2922,7 @@ void become_daemon(void)
/* detach from the terminal */
#ifdef USE_SETSID
setsid();
-#else
+#else /* USE_SETSID */
#ifdef TIOCNOTTY
{
int i = open("/dev/tty", O_RDWR);
@@ -3097,221 +2932,13 @@ void become_daemon(void)
close(i);
}
}
-#endif
-#endif
-#endif
+#endif /* TIOCNOTTY */
+#endif /* USE_SETSID */
+ /* Close fd's 0,1,2. Needed if started by rsh */
+ close_low_fds();
+#endif /* NO_FORK_DEBUG */
}
-/****************************************************************************
-calculate the default netmask for an address
-****************************************************************************/
-static void default_netmask(struct in_addr *inm, struct in_addr *iad)
-{
- unsigned long ad = ntohl(iad->s_addr);
- unsigned long nm;
- /*
- ** Guess a netmask based on the class of the IP address given.
- */
- if ( (ad & 0x80000000) == 0 ) {
- /* class A address */
- nm = 0xFF000000;
- } else if ( (ad & 0xC0000000) == 0x80000000 ) {
- /* class B address */
- nm = 0xFFFF0000;
- } else if ( (ad & 0xE0000000) == 0xC0000000 ) {
- /* class C address */
- nm = 0xFFFFFF00;
- } else {
- /* class D or E; netmask doesn't make much sense - guess 4 bits */
- nm = 0xFFFFFFF0;
- }
- inm->s_addr = htonl(nm);
-}
-
-/****************************************************************************
- get the broadcast address for our address
-(troyer@saifr00.ateng.az.honeywell.com)
-****************************************************************************/
-void get_broadcast(struct in_addr *if_ipaddr,
- struct in_addr *if_bcast,
- struct in_addr *if_nmask)
-{
- BOOL found = False;
-#ifndef NO_GET_BROADCAST
- int sock = -1; /* AF_INET raw socket desc */
- char buff[1024];
- struct ifreq *ifr=NULL;
- int i;
-
-#if defined(EVEREST)
- int n_interfaces;
- struct ifconf ifc;
- struct ifreq *ifreqs;
-#elif defined(USE_IFREQ)
- struct ifreq ifreq;
- struct strioctl strioctl;
- struct ifconf *ifc;
-#else
- struct ifconf ifc;
-#endif
-#endif
-
- /* get a default netmask and broadcast */
- default_netmask(if_nmask, if_ipaddr);
-
-#ifndef NO_GET_BROADCAST
- /* Create a socket to the INET kernel. */
-#if USE_SOCKRAW
- if ((sock = socket(AF_INET, SOCK_RAW, PF_INET )) < 0)
-#else
- if ((sock = socket(AF_INET, SOCK_DGRAM, 0 )) < 0)
-#endif
- {
- DEBUG(0,( "Unable to open socket to get broadcast address\n"));
- return;
- }
-
- /* Get a list of the configured interfaces */
-#ifdef EVEREST
- /* This is part of SCO Openserver 5: The ioctls are no longer part
- if the lower level STREAMS interface glue. They are now real
- ioctl calls */
-
- if (ioctl(sock, SIOCGIFANUM, &n_interfaces) < 0) {
- DEBUG(0,( "SIOCGIFANUM: %s\n", strerror(errno)));
- } else {
- DEBUG(0,( "number of interfaces returned is: %d\n", n_interfaces));
-
- ifc.ifc_len = sizeof(struct ifreq) * n_interfaces;
- ifc.ifc_buf = (caddr_t) alloca(ifc.ifc_len);
-
- if (ioctl(sock, SIOCGIFCONF, &ifc) < 0)
- DEBUG(0, ( "SIOCGIFCONF: %s\n", strerror(errno)));
- else {
- ifr = ifc.ifc_req;
-
- for (i = 0; i < n_interfaces; ++i) {
- if (if_ipaddr->s_addr ==
- ((struct sockaddr_in *) &ifr[i].ifr_addr)->sin_addr.s_addr) {
- found = True;
- break;
- }
- }
- }
- }
-#elif defined(USE_IFREQ)
- ifc = (struct ifconf *)buff;
- ifc->ifc_len = BUFSIZ - sizeof(struct ifconf);
- strioctl.ic_cmd = SIOCGIFCONF;
- strioctl.ic_dp = (char *)ifc;
- strioctl.ic_len = sizeof(buff);
- if (ioctl(sock, I_STR, &strioctl) < 0) {
- DEBUG(0,( "I_STR/SIOCGIFCONF: %s\n", strerror(errno)));
- } else {
- ifr = (struct ifreq *)ifc->ifc_req;
-
- /* Loop through interfaces, looking for given IP address */
- for (i = ifc->ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) {
- if (if_ipaddr->s_addr ==
- (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) {
- found = True;
- break;
- }
- }
- }
-#elif defined(__FreeBSD__) || defined(NETBSD)
- ifc.ifc_len = sizeof(buff);
- ifc.ifc_buf = buff;
- if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
- DEBUG(0,("SIOCGIFCONF: %s\n", strerror(errno)));
- } else {
- ifr = ifc.ifc_req;
- /* Loop through interfaces, looking for given IP address */
- i = ifc.ifc_len;
- while (i > 0) {
- if (if_ipaddr->s_addr ==
- (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) {
- found = True;
- break;
- }
- i -= ifr->ifr_addr.sa_len + IFNAMSIZ;
- ifr = (struct ifreq*) ((char*) ifr + ifr->ifr_addr.sa_len + IFNAMSIZ);
- }
- }
-#else
- ifc.ifc_len = sizeof(buff);
- ifc.ifc_buf = buff;
- if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
- DEBUG(0,("SIOCGIFCONF: %s\n", strerror(errno)));
- } else {
- ifr = ifc.ifc_req;
-
- /* Loop through interfaces, looking for given IP address */
- for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) {
-#ifdef BSDI
- if (ioctl(sock, SIOCGIFADDR, ifr) < 0) break;
-#endif
- if (if_ipaddr->s_addr ==
- (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) {
- found = True;
- break;
- }
- }
- }
-#endif
-
- if (!found) {
- DEBUG(0,("No interface found for address %s\n", inet_ntoa(*if_ipaddr)));
- } else {
- /* Get the netmask address from the kernel */
-#ifdef USE_IFREQ
- ifreq = *ifr;
-
- strioctl.ic_cmd = SIOCGIFNETMASK;
- strioctl.ic_dp = (char *)&ifreq;
- strioctl.ic_len = sizeof(struct ifreq);
- if (ioctl(sock, I_STR, &strioctl) < 0)
- DEBUG(0,("Failed I_STR/SIOCGIFNETMASK: %s\n", strerror(errno)));
- else
- *if_nmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
-#else
- if (ioctl(sock, SIOCGIFNETMASK, ifr) < 0)
- DEBUG(0,("SIOCGIFNETMASK failed\n"));
- else
- *if_nmask = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
-#endif
-
- DEBUG(2,("Netmask for %s = %s\n", ifr->ifr_name,
- inet_ntoa(*if_nmask)));
- }
-
- /* Close up shop */
- (void) close(sock);
-
-#endif
-
- /* sanity check on the netmask */
- {
- unsigned long nm = ntohl(if_nmask->s_addr);
- if ((nm >> 24) != 0xFF) {
- DEBUG(0,("Impossible netmask %s - using defaults\n",inet_ntoa(*if_nmask)));
- default_netmask(if_nmask, if_ipaddr);
- }
- }
-
- /* derive the broadcast assuming a 1's broadcast, as this is what
- all MS operating systems do, we have to comply even if the unix
- box is setup differently */
- {
- unsigned long ad = ntohl(if_ipaddr->s_addr);
- unsigned long nm = ntohl(if_nmask->s_addr);
- unsigned long bc = (ad & nm) | (0xffffffff & ~nm);
- if_bcast->s_addr = htonl(bc);
- }
-
- DEBUG(2,("Derived broadcast address %s\n", inet_ntoa(*if_bcast)));
-} /* get_broadcast */
-
/****************************************************************************
put up a yes/no prompt
@@ -3462,7 +3089,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 +3139,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 +3157,11 @@ void *Realloc(void *p,int size)
return(ret);
}
-/****************************************************************************
-set the time on a file
-****************************************************************************/
-BOOL set_filetime(char *fname,time_t mtime)
-{
- struct utimbuf times;
-
- if (null_mtime(mtime)) return(True);
-
- times.modtime = times.actime = mtime;
-
- if (sys_utime(fname,&times)) {
- DEBUG(4,("set_filetime(%s) failed: %s\n",fname,strerror(errno)));
- }
-
- return(True);
-}
-
-
#ifdef NOSTRDUP
/****************************************************************************
duplicate a string
****************************************************************************/
-char *strdup(char *s)
+ char *strdup(char *s)
{
char *ret = NULL;
if (!s) return(NULL);
@@ -3567,94 +3182,10 @@ void Abort(void )
exit(2);
}
-
-#ifdef REPLACE_STRLEN
-/****************************************************************************
-a replacement strlen() that returns int for solaris
-****************************************************************************/
-int Strlen(char *s)
-{
- int ret=0;
- if (!s) return(0);
- while (*s++) ret++;
- return(ret);
-}
-#endif
-
-
-/****************************************************************************
-return a time at the start of the current month
-****************************************************************************/
-time_t start_of_month(void)
-{
- time_t t = time(NULL);
- struct tm *t2;
-
- t2 = gmtime(&t);
-
- t2->tm_mday = 1;
- t2->tm_hour = 0;
- t2->tm_min = 0;
- t2->tm_sec = 0;
-
- return(mktime(t2));
-}
-
-
-/*******************************************************************
- check for a sane unix date
-********************************************************************/
-BOOL sane_unix_date(time_t unixdate)
-{
- struct tm t,today;
- time_t t_today = time(NULL);
-
- t = *(LocalTime(&unixdate,LOCAL_TO_GMT));
- today = *(LocalTime(&t_today,LOCAL_TO_GMT));
-
- if (t.tm_year < 80)
- return(False);
-
- if (t.tm_year > today.tm_year)
- return(False);
-
- if (t.tm_year == today.tm_year &&
- t.tm_mon > today.tm_mon)
- return(False);
-
-
- if (t.tm_year == today.tm_year &&
- t.tm_mon == today.tm_mon &&
- t.tm_mday > (today.tm_mday+1))
- return(False);
-
- return(True);
-}
-
-
-
-#ifdef NO_FTRUNCATE
- /*******************************************************************
-ftruncate for operating systems that don't have it
-********************************************************************/
-int ftruncate(int f,long l)
-{
- struct flock fl;
-
- fl.l_whence = 0;
- fl.l_len = 0;
- fl.l_start = l;
- fl.l_type = F_WRLCK;
- return fcntl(f, F_FREESP, &fl);
-}
-#endif
-
-
-
/****************************************************************************
get my own name and IP
****************************************************************************/
-BOOL get_myname(char *myname,struct in_addr *ip)
+BOOL get_myname(char *my_name,struct in_addr *ip)
{
struct hostent *hp;
pstring hostname;
@@ -3675,13 +3206,13 @@ BOOL get_myname(char *myname,struct in_addr *ip)
return False;
}
- if (myname)
+ if (my_name)
{
/* split off any parts after an initial . */
char *p = strchr(hostname,'.');
if (p) *p = 0;
- strcpy(myname,hostname);
+ fstrcpy(my_name,hostname);
}
if (ip)
@@ -3696,7 +3227,7 @@ true if two IP addresses are equal
****************************************************************************/
BOOL ip_equal(struct in_addr ip1,struct in_addr ip2)
{
- unsigned long a1,a2;
+ uint32 a1,a2;
a1 = ntohl(ip1.s_addr);
a2 = ntohl(ip2.s_addr);
return(a1 == a2);
@@ -3706,7 +3237,7 @@ BOOL ip_equal(struct in_addr ip1,struct in_addr ip2)
/****************************************************************************
open a socket of the specified type, port and address for incoming data
****************************************************************************/
-int open_socket_in(int type, int port, int dlevel)
+int open_socket_in(int type, int port, int dlevel,uint32 socket_addr)
{
struct hostent *hp;
struct sockaddr_in sock;
@@ -3714,11 +3245,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 */
@@ -3735,7 +3262,7 @@ int open_socket_in(int type, int port, int dlevel)
#endif
sock.sin_port = htons( port );
sock.sin_family = hp->h_addrtype;
- sock.sin_addr.s_addr = INADDR_ANY;
+ sock.sin_addr.s_addr = socket_addr;
res = socket(hp->h_addrtype, type, 0);
if (res == -1)
{ DEBUG(0,("socket failed\n")); return -1; }
@@ -3749,16 +3276,16 @@ 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)
- DEBUG(dlevel,("bind failed on port %d (%s)\n",
- port,strerror(errno)));
+ if (port == SMB_PORT || port == NMB_PORT)
+ DEBUG(dlevel,("bind failed on port %d socket_addr=%s (%s)\n",
+ port,inet_ntoa(sock.sin_addr),strerror(errno)));
close(res);
if (dlevel > 0 && port < 1000)
port = 7999;
if (port >= 1000 && port < 9000)
- return(open_socket_in(type,port+1,dlevel));
+ return(open_socket_in(type,port+1,dlevel,socket_addr));
}
return(-1);
@@ -3772,10 +3299,12 @@ int open_socket_in(int type, int port, int dlevel)
/****************************************************************************
create an outgoing socket
**************************************************************************/
-int open_socket_out(int type, struct in_addr *addr, int port )
+int open_socket_out(int type, struct in_addr *addr, int port ,int timeout)
{
struct sockaddr_in sock_out;
- int res;
+ int res,ret;
+ int connect_loop = 250; /* 250 milliseconds */
+ int loops = (timeout * 1000) / connect_loop;
/* create a socket to write to */
res = socket(PF_INET, type, 0);
@@ -3790,15 +3319,45 @@ int open_socket_out(int type, struct in_addr *addr, int port )
sock_out.sin_port = htons( port );
sock_out.sin_family = PF_INET;
+ /* set it non-blocking */
+ set_blocking(res,False);
+
DEBUG(3,("Connecting to %s at port %d\n",inet_ntoa(*addr),port));
/* and connect it to the destination */
- if (connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out))<0) {
- DEBUG(0,("connect error: %s\n",strerror(errno)));
- close(res);
- return(-1);
+connect_again:
+ ret = connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out));
+
+ /* Some systems return EAGAIN when they mean EINPROGRESS */
+ if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
+ errno == EAGAIN) && loops--) {
+ msleep(connect_loop);
+ goto connect_again;
+ }
+
+ if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
+ errno == EAGAIN)) {
+ DEBUG(1,("timeout connecting to %s:%d\n",inet_ntoa(*addr),port));
+ close(res);
+ return -1;
}
+#ifdef EISCONN
+ if (ret < 0 && errno == EISCONN) {
+ errno = 0;
+ ret = 0;
+ }
+#endif
+
+ if (ret < 0) {
+ DEBUG(1,("error connecting to %s:%d (%s)\n",
+ inet_ntoa(*addr),port,strerror(errno)));
+ return -1;
+ }
+
+ /* set it blocking again */
+ set_blocking(res,True);
+
return res;
}
@@ -3847,27 +3406,38 @@ int interpret_security(char *str,int def)
/****************************************************************************
interpret an internet address or name into an IP address in 4 byte form
****************************************************************************/
-unsigned long interpret_addr(char *str)
+uint32 interpret_addr(char *str)
{
struct hostent *hp;
- unsigned long res;
+ uint32 res;
+ int i;
+ BOOL pure_address = True;
if (strcmp(str,"0.0.0.0") == 0) return(0);
if (strcmp(str,"255.255.255.255") == 0) return(0xFFFFFFFF);
+ for (i=0; pure_address && str[i]; i++)
+ if (!(isdigit(str[i]) || str[i] == '.'))
+ pure_address = False;
+
/* if it's in the form of an IP address then get the lib to interpret it */
- if (isdigit(str[0])) {
+ if (pure_address) {
res = inet_addr(str);
} else {
- /* otherwise assume it's a network name of some sort and use Get_Hostbyname */
+ /* otherwise assume it's a network name of some sort and use
+ Get_Hostbyname */
if ((hp = Get_Hostbyname(str)) == 0) {
DEBUG(3,("Get_Hostbyname: Unknown host. %s\n",str));
return 0;
}
+ if(hp->h_addr == NULL) {
+ DEBUG(3,("Get_Hostbyname: host address is invalid for host %s.\n",str));
+ return 0;
+ }
putip((char *)&res,(char *)hp->h_addr);
}
- if (res == (unsigned long)-1) return(0);
+ if (res == (uint32)-1) return(0);
return(res);
}
@@ -3878,8 +3448,8 @@ unsigned long interpret_addr(char *str)
struct in_addr *interpret_addr2(char *str)
{
static struct in_addr ret;
- unsigned long a = interpret_addr(str);
- putip((char *)&ret,(char *)&a);
+ uint32 a = interpret_addr(str);
+ ret.s_addr = a;
return(&ret);
}
@@ -3888,121 +3458,251 @@ struct in_addr *interpret_addr2(char *str)
******************************************************************/
BOOL zero_ip(struct in_addr ip)
{
- unsigned long a;
+ uint32 a;
putip((char *)&a,(char *)&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)
+/*******************************************************************
+ matchname - determine if host name matches IP address
+ ******************************************************************/
+static BOOL matchname(char *remotehost,struct in_addr addr)
{
- double d;
- time_t ret;
- uint32 tlow,thigh;
- tlow = IVAL(p,0);
- thigh = IVAL(p,4);
-
- if (thigh == 0) return(0);
+ struct hostent *hp;
+ int i;
+
+ if ((hp = Get_Hostbyname(remotehost)) == 0) {
+ DEBUG(0,("Get_Hostbyname(%s): lookup failure", remotehost));
+ return False;
+ }
- 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;
+ /*
+ * Make sure that gethostbyname() returns the "correct" host name.
+ * Unfortunately, gethostbyname("localhost") sometimes yields
+ * "localhost.domain". Since the latter host name comes from the
+ * local DNS, we just have to trust it (all bets are off if the local
+ * DNS is perverted). We always check the address list, though.
+ */
+
+ if (strcasecmp(remotehost, hp->h_name)
+ && strcasecmp(remotehost, "localhost")) {
+ DEBUG(0,("host name/name mismatch: %s != %s",
+ remotehost, hp->h_name));
+ return False;
+ }
+
+ /* Look up the host address in the address list we just got. */
+ for (i = 0; hp->h_addr_list[i]; i++) {
+ if (memcmp(hp->h_addr_list[i], (caddr_t) & addr, sizeof(addr)) == 0)
+ return True;
+ }
- if (d>=MAXINT)
- return(0);
+ /*
+ * The host name does not map to the original host address. Perhaps
+ * someone has compromised a name server. More likely someone botched
+ * it, but that could be dangerous, too.
+ */
+
+ DEBUG(0,("host name/address mismatch: %s != %s",
+ inet_ntoa(addr), hp->h_name));
+ return False;
+}
- ret = (time_t)(d+0.5);
+/*******************************************************************
+ Reset the 'done' variables so after a client process is created
+ from a fork call these calls will be re-done. This should be
+ expanded if more variables need reseting.
+ ******************************************************************/
- /* this takes us from kludge-GMT to real GMT */
- ret += TimeDiff(ret) - serverzone;
+static BOOL global_client_name_done = False;
+static BOOL global_client_addr_done = False;
- return(ret);
+void reset_globals_after_fork()
+{
+ global_client_name_done = False;
+ global_client_addr_done = False;
}
+
+/*******************************************************************
+ return the DNS name of the client
+ ******************************************************************/
+char *client_name(void)
+{
+ extern int Client;
+ struct sockaddr sa;
+ struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
+ int length = sizeof(sa);
+ static pstring name_buf;
+ struct hostent *hp;
+ if (global_client_name_done)
+ return name_buf;
-/****************************************************************************
-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;
+ strcpy(name_buf,"UNKNOWN");
- if (t==0) {
- SIVAL(p,0,0); SIVAL(p,4,0);
- return;
+ if (getpeername(Client, &sa, &length) < 0) {
+ DEBUG(0,("getpeername failed\n"));
+ return name_buf;
}
- /* this converts GMT to kludge-GMT */
- t -= TimeDiff(t) - serverzone;
+ /* Look up the remote host name. */
+ if ((hp = gethostbyaddr((char *) &sockin->sin_addr,
+ sizeof(sockin->sin_addr),
+ AF_INET)) == 0) {
+ DEBUG(1,("Gethostbyaddr failed for %s\n",client_addr()));
+ StrnCpy(name_buf,client_addr(),sizeof(name_buf) - 1);
+ } else {
+ StrnCpy(name_buf,(char *)hp->h_name,sizeof(name_buf) - 1);
+ if (!matchname(name_buf, sockin->sin_addr)) {
+ DEBUG(0,("Matchname failed on %s %s\n",name_buf,client_addr()));
+ strcpy(name_buf,"UNKNOWN");
+ }
+ }
+ global_client_name_done = True;
+ return name_buf;
+}
- d = (double) (t);
+/*******************************************************************
+ return the IP addr of the client as a string
+ ******************************************************************/
+char *client_addr(void)
+{
+ extern int Client;
+ struct sockaddr sa;
+ struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
+ int length = sizeof(sa);
+ static fstring addr_buf;
- d += TIME_FIXUP_CONSTANT;
+ if (global_client_addr_done)
+ return addr_buf;
- d *= 1.0e7;
+ strcpy(addr_buf,"0.0.0.0");
- thigh = (uint32)(d * (1.0/(4.0*(double)(1<<30))));
- tlow = (uint32)(d - ((double)thigh)*4.0*(double)(1<<30));
+ if (getpeername(Client, &sa, &length) < 0) {
+ DEBUG(0,("getpeername failed\n"));
+ return addr_buf;
+ }
- SIVAL(p,0,tlow);
- SIVAL(p,4,thigh);
+ fstrcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr));
+
+ global_client_addr_done = True;
+ return addr_buf;
}
-/*******************************************************************
-sub strings with useful parameters
-********************************************************************/
-void standard_sub_basic(char *s)
+char *automount_server(char *user_name)
{
- if (!strchr(s,'%')) return;
+ static pstring server_name;
- string_sub(s,"%R",remote_proto);
- string_sub(s,"%a",remote_arch);
- string_sub(s,"%m",remote_machine);
- string_sub(s,"%L",local_machine);
+#if (defined(NETGROUP) && defined (AUTOMOUNT))
+ int nis_error; /* returned by yp all functions */
+ char *nis_result; /* yp_match inits this */
+ int nis_result_len; /* and set this */
+ char *nis_domain; /* yp_get_default_domain inits this */
+ char *nis_map = (char *)lp_nis_home_map_name();
+ int home_server_len;
- if (!strchr(s,'%')) return;
+ /* set to default of local machine */
+ pstrcpy(server_name, local_machine);
- string_sub(s,"%v",VERSION);
- string_sub(s,"%h",myhostname);
- string_sub(s,"%U",sesssetup_user);
+ if ((nis_error = yp_get_default_domain(&nis_domain)) != 0)
+ {
+ DEBUG(3, ("YP Error: %s\n", yperr_string(nis_error)));
+ }
- if (!strchr(s,'%')) return;
+ DEBUG(5, ("NIS Domain: %s\n", nis_domain));
- string_sub(s,"%I",Client_info.addr);
- string_sub(s,"%M",Client_info.name);
- string_sub(s,"%T",timestring());
+ if ((nis_error = yp_match(nis_domain, nis_map,
+ user_name, strlen(user_name),
+ &nis_result, &nis_result_len)) != 0)
+ {
+ DEBUG(3, ("YP Error: %s\n", yperr_string(nis_error)));
+ }
- if (!strchr(s,'%')) return;
+ if (!nis_error && lp_nis_home_map())
+ {
+ home_server_len = strcspn(nis_result,":");
+ DEBUG(5, ("NIS lookup succeeded. Home server length: %d\n",home_server_len));
+ if (home_server_len > sizeof(pstring))
+ {
+ home_server_len = sizeof(pstring);
+ }
+ strncpy(server_name, nis_result, home_server_len);
+ }
+#else
+ /* use the local machine name instead of the auto-map server */
+ pstrcpy(server_name, local_machine);
+#endif
- {
- char pidstr[10];
- sprintf(pidstr,"%d",(int)getpid());
- string_sub(s,"%d",pidstr);
- }
+ DEBUG(4,("Home server: %s\n", server_name));
- if (!strchr(s,'%')) return;
+ return server_name;
+}
- {
- struct passwd *pass = Get_Pwnam(sesssetup_user,False);
- if (pass) {
- string_sub(s,"%G",gidtoname(pass->pw_gid));
- }
- }
+/*******************************************************************
+sub strings with useful parameters
+Rewritten by Stefaan A Eeckels <Stefaan.Eeckels@ecc.lu> and
+Paul Rippin <pr3245@nopc.eurostat.cec.be>
+********************************************************************/
+void standard_sub_basic(char *str)
+{
+ char *s, *p;
+ char pidstr[10];
+ struct passwd *pass;
+ char *username = sam_logon_in_ssb ? samlogon_user : sesssetup_user;
+
+ for (s = str ; (p = strchr(s,'%')) != NULL ; s = p )
+ {
+ switch (*(p+1))
+ {
+ case 'G' :
+ {
+ if ((pass = Get_Pwnam(sesssetup_user,False))!=NULL)
+ {
+ string_sub(p,"%G",gidtoname(pass->pw_gid));
+ }
+ else
+ {
+ p += 2;
+ }
+ break;
+ }
+ case 'N' : string_sub(p,"%N", automount_server(username)); break;
+ case 'I' : string_sub(p,"%I", client_addr()); break;
+ case 'L' : string_sub(p,"%L", local_machine); break;
+ case 'M' : string_sub(p,"%M", client_name()); break;
+ case 'R' : string_sub(p,"%R", remote_proto); break;
+ case 'T' : string_sub(p,"%T", timestring()); break;
+ case 'U' : string_sub(p,"%U", username); break;
+ case 'a' : string_sub(p,"%a", remote_arch); break;
+ case 'd' :
+ {
+ sprintf(pidstr,"%d",(int)getpid());
+ string_sub(p,"%d", pidstr);
+ break;
+ }
+ case 'h' : string_sub(p,"%h", myhostname); break;
+ case 'm' : string_sub(p,"%m", remote_machine); break;
+ case 'v' : string_sub(p,"%v", VERSION); break;
+ case '\0': p++; break; /* don't run off end if last character is % */
+ default : p+=2; break;
+ }
+ }
+ return;
+}
+
+/*******************************************************************
+are two IPs on the same subnet?
+********************************************************************/
+BOOL same_net(struct in_addr ip1,struct in_addr ip2,struct in_addr mask)
+{
+ uint32 net1,net2,nmask;
+
+ nmask = ntohl(mask.s_addr);
+ net1 = ntohl(ip1.s_addr);
+ net2 = ntohl(ip2.s_addr);
+
+ return((net1 & nmask) == (net2 & nmask));
}
@@ -4022,34 +3722,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
@@ -4071,7 +3743,7 @@ struct hostent *Get_Hostbyname(char *name)
return(NULL);
}
- ret = gethostbyname(name2);
+ ret = sys_gethostbyname(name2);
if (ret != NULL)
{
free(name2);
@@ -4080,7 +3752,7 @@ struct hostent *Get_Hostbyname(char *name)
/* try with all lowercase */
strlower(name2);
- ret = gethostbyname(name2);
+ ret = sys_gethostbyname(name2);
if (ret != NULL)
{
free(name2);
@@ -4089,7 +3761,7 @@ struct hostent *Get_Hostbyname(char *name)
/* try with all uppercase */
strupper(name2);
- ret = gethostbyname(name2);
+ ret = sys_gethostbyname(name2);
if (ret != NULL)
{
free(name2);
@@ -4118,7 +3790,7 @@ BOOL process_exists(int pid)
fstring s;
if (!tested) {
tested = True;
- sprintf(s,"/proc/%05d",getpid());
+ sprintf(s,"/proc/%05d",(int)getpid());
ok = file_exist(s,NULL);
}
if (ok) {
@@ -4127,11 +3799,8 @@ BOOL process_exists(int pid)
}
}
- /* a best guess for non root access */
- if (geteuid() != 0) return(True);
-
- /* otherwise use kill */
- return(pid == getpid() || kill(pid,0) == 0);
+ /* CGH 8/16/96 - added ESRCH test */
+ return(pid == getpid() || kill(pid,0) == 0 || errno != ESRCH);
#endif
}
@@ -4163,16 +3832,20 @@ char *gidtoname(int gid)
/*******************************************************************
block sigs
********************************************************************/
-void BlockSignals(BOOL block)
+void BlockSignals(BOOL block,int signum)
{
#ifdef USE_SIGBLOCK
- int block_mask = (sigmask(SIGTERM)|sigmask(SIGQUIT)|sigmask(SIGSEGV)
- |sigmask(SIGCHLD)|sigmask(SIGQUIT)|sigmask(SIGBUS)|
- sigmask(SIGINT));
+ int block_mask = sigmask(signum);
+ static int oldmask = 0;
if (block)
- sigblock(block_mask);
+ oldmask = sigblock(block_mask);
else
- sigunblock(block_mask);
+ sigsetmask(oldmask);
+#elif defined(USE_SIGPROCMASK)
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set,signum);
+ sigprocmask(block?SIG_BLOCK:SIG_UNBLOCK,&set,NULL);
#endif
}
@@ -4182,8 +3855,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 ljus:0 /tmp/ERROR_FAULT");
}
#endif
@@ -4209,15 +3881,6 @@ char *readdirname(void *p)
dname = ptr->d_name;
-#ifdef KANJI
- {
- static pstring buf;
- strcpy(buf, dname);
- unix_to_dos(buf, True);
- dname = buf;
- }
-#endif
-
#ifdef NEXT2
if (telldir(p) < 0) return(NULL);
#endif
@@ -4233,278 +3896,668 @@ char *readdirname(void *p)
broken_readdir = True;
}
if (broken_readdir)
- return(dname-2);
+ dname = dname - 2;
}
#endif
+ {
+ static pstring buf;
+ pstrcpy(buf, dname);
+ unix_to_dos(buf, True);
+ dname = buf;
+ }
+
return(dname);
}
+/*******************************************************************
+ Utility function used to decide if the last component
+ of a path matches a (possibly wildcarded) entry in a namelist.
+********************************************************************/
+BOOL is_in_path(char *name, name_compare_entry *namelist)
+{
+ pstring last_component;
+ char *p;
-#if (defined(SecureWare) && defined(SCO))
-/* This is needed due to needing the nap() function but we don't want
- to include the Xenix libraries since that will break other things...
- BTW: system call # 0x0c28 is the same as calling nap() */
-long nap(long milliseconds) {
- return syscall(0x0c28, milliseconds);
-}
-#endif
+ DEBUG(8, ("is_in_path: %s\n", name));
-#ifdef NO_INITGROUPS
-#include <sys/types.h>
-#include <limits.h>
-#include <grp.h>
+ /* if we have no list it's obviously not in the path */
+ if((namelist == NULL ) || ((namelist != NULL) && (namelist[0].name == NULL)))
+ {
+ DEBUG(8,("is_in_path: no name list.\n"));
+ return False;
+ }
-#ifndef NULL
-#define NULL (void *)0
-#endif
+ /* Get the last component of the unix name. */
+ p = strrchr(name, '/');
+ strncpy(last_component, p ? p : name, sizeof(last_component)-1);
+ last_component[sizeof(last_component)-1] = '\0';
-/****************************************************************************
- some systems don't have an initgroups call
-****************************************************************************/
-int initgroups(char *name,gid_t id)
-{
-#ifdef NO_SETGROUPS
- /* yikes! no SETGROUPS or INITGROUPS? how can this work? */
- return(0);
-#else
- gid_t grouplst[NGROUPS_MAX];
- int i,j;
- struct group *g;
- char *gr;
-
- grouplst[0] = id;
- i = 1;
- while (i < NGROUPS_MAX &&
- ((g = (struct group *)getgrent()) != (struct group *)NULL))
+ for(; namelist->name != NULL; namelist++)
+ {
+ if(namelist->is_wild)
{
- if (g->gr_gid == id)
- continue;
- j = 0;
- gr = g->gr_mem[0];
- while (gr && (*gr != (char)NULL)) {
- if (strcmp(name,gr) == 0) {
- grouplst[i] = g->gr_gid;
- i++;
- gr = (char *)NULL;
- break;
- }
- gr = g->gr_mem[++j];
+ /* look for a wildcard match. */
+ if (mask_match(last_component, namelist->name, case_sensitive, False))
+ {
+ DEBUG(8,("is_in_path: mask match succeeded\n"));
+ return True;
}
}
- endgrent();
- return(setgroups(i,grouplst));
-#endif
+ else
+ {
+ if((case_sensitive && (strcmp(last_component, namelist->name) == 0))||
+ (!case_sensitive && (StrCaseCmp(last_component, namelist->name) == 0)))
+ {
+ DEBUG(8,("is_in_path: match succeeded\n"));
+ return True;
+ }
+ }
+ }
+ DEBUG(8,("is_in_path: match not found\n"));
+
+ return False;
}
-#endif
+/*******************************************************************
+ Strip a '/' separated list into an array of
+ name_compare_enties structures suitable for
+ passing to is_in_path(). We do this for
+ speed so we can pre-parse all the names in the list
+ and don't do it for each call to is_in_path().
+ namelist is modified here and is assumed to be
+ a copy owned by the caller.
+ We also check if the entry contains a wildcard to
+ remove a potentially expensive call to mask_match
+ if possible.
+********************************************************************/
+
+void set_namearray(name_compare_entry **ppname_array, char *namelist)
+{
+ char *name_end;
+ char *nameptr = namelist;
+ int num_entries = 0;
+ int i;
-#if WRAP_MALLOC
+ (*ppname_array) = NULL;
+
+ if((nameptr == NULL ) || ((nameptr != NULL) && (*nameptr == '\0')))
+ return;
+
+ /* We need to make two passes over the string. The
+ first to count the number of elements, the second
+ to split it.
+ */
+ while(*nameptr)
+ {
+ if ( *nameptr == '/' )
+ {
+ /* cope with multiple (useless) /s) */
+ nameptr++;
+ continue;
+ }
+ /* find the next / */
+ name_end = strchr(nameptr, '/');
+
+ /* oops - the last check for a / didn't find one. */
+ if (name_end == NULL)
+ break;
+
+ /* next segment please */
+ nameptr = name_end + 1;
+ num_entries++;
+ }
+
+ if(num_entries == 0)
+ return;
+
+ if(( (*ppname_array) = (name_compare_entry *)malloc(
+ (num_entries + 1) * sizeof(name_compare_entry))) == NULL)
+ {
+ DEBUG(0,("set_namearray: malloc fail\n"));
+ return;
+ }
+
+ /* Now copy out the names */
+ nameptr = namelist;
+ i = 0;
+ while(*nameptr)
+ {
+ if ( *nameptr == '/' )
+ {
+ /* cope with multiple (useless) /s) */
+ nameptr++;
+ continue;
+ }
+ /* find the next / */
+ if ((name_end = strchr(nameptr, '/')) != NULL)
+ {
+ *name_end = 0;
+ }
+
+ /* oops - the last check for a / didn't find one. */
+ if(name_end == NULL)
+ break;
+
+ (*ppname_array)[i].is_wild = ((strchr( nameptr, '?')!=NULL) ||
+ (strchr( nameptr, '*')!=NULL));
+ if(((*ppname_array)[i].name = strdup(nameptr)) == NULL)
+ {
+ DEBUG(0,("set_namearray: malloc fail (1)\n"));
+ return;
+ }
+
+ /* next segment please */
+ nameptr = name_end + 1;
+ i++;
+ }
+
+ (*ppname_array)[i].name = NULL;
-/* undo the wrapping temporarily */
-#undef malloc
-#undef realloc
-#undef free
+ return;
+}
/****************************************************************************
-wrapper for malloc() to catch memory errors
+routine to free a namearray.
****************************************************************************/
-void *malloc_wrapped(int size,char *file,int line)
+
+void free_namearray(name_compare_entry *name_array)
{
-#ifdef xx_old_malloc
- void *res = xx_old_malloc(size);
-#else
- void *res = malloc(size);
-#endif
- DEBUG(3,("Malloc called from %s(%d) with size=%d gave ptr=0x%X\n",
- file,line,
- size,(unsigned int)res));
- return(res);
+ if(name_array == 0)
+ return;
+
+ if(name_array->name != NULL)
+ free(name_array->name);
+
+ free((char *)name_array);
}
/****************************************************************************
-wrapper for realloc() to catch memory errors
+routine to do file locking
****************************************************************************/
-void *realloc_wrapped(void *ptr,int size,char *file,int line)
+BOOL fcntl_lock(int fd,int op,uint32 offset,uint32 count,int type)
{
-#ifdef xx_old_realloc
- void *res = xx_old_realloc(ptr,size);
+#if HAVE_FCNTL_LOCK
+ struct flock lock;
+ int ret;
+
+#if 1
+ uint32 mask = 0xC0000000;
+
+ /* make sure the count is reasonable, we might kill the lockd otherwise */
+ count &= ~mask;
+
+ /* the offset is often strange - remove 2 of its bits if either of
+ the top two bits are set. Shift the top ones by two bits. This
+ still allows OLE2 apps to operate, but should stop lockd from
+ dieing */
+ if ((offset & mask) != 0)
+ offset = (offset & ~mask) | ((offset & mask) >> 2);
#else
- void *res = realloc(ptr,size);
+ uint32 mask = ((unsigned)1<<31);
+
+ /* interpret negative counts as large numbers */
+ if (count < 0)
+ count &= ~mask;
+
+ /* no negative offsets */
+ offset &= ~mask;
+
+ /* count + offset must be in range */
+ while ((offset < 0 || (offset + count < 0)) && mask)
+ {
+ offset &= ~mask;
+ mask = mask >> 1;
+ }
#endif
- DEBUG(3,("Realloc\n"));
- DEBUG(3,("free called from %s(%d) with ptr=0x%X\n",
- file,line,
- (unsigned int)ptr));
- DEBUG(3,("Malloc called from %s(%d) with size=%d gave ptr=0x%X\n",
- file,line,
- size,(unsigned int)res));
- return(res);
-}
-/****************************************************************************
-wrapper for free() to catch memory errors
-****************************************************************************/
-void free_wrapped(void *ptr,char *file,int line)
-{
-#ifdef xx_old_free
- xx_old_free(ptr);
+
+ DEBUG(8,("fcntl_lock %d %d %d %d %d\n",fd,op,(int)offset,(int)count,type));
+
+ lock.l_type = type;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = (int)offset;
+ lock.l_len = (int)count;
+ lock.l_pid = 0;
+
+ errno = 0;
+
+ ret = fcntl(fd,op,&lock);
+
+ if (errno != 0)
+ DEBUG(3,("fcntl lock gave errno %d (%s)\n",errno,strerror(errno)));
+
+ /* a lock query */
+ if (op == F_GETLK)
+ {
+ if ((ret != -1) &&
+ (lock.l_type != F_UNLCK) &&
+ (lock.l_pid != 0) &&
+ (lock.l_pid != getpid()))
+ {
+ DEBUG(3,("fd %d is locked by pid %d\n",fd,lock.l_pid));
+ return(True);
+ }
+
+ /* it must be not locked or locked by me */
+ return(False);
+ }
+
+ /* a lock set or unset */
+ if (ret == -1)
+ {
+ DEBUG(3,("lock failed at offset %d count %d op %d type %d (%s)\n",
+ offset,count,op,type,strerror(errno)));
+
+ /* perhaps it doesn't support this sort of locking?? */
+ if (errno == EINVAL)
+ {
+ DEBUG(3,("locking not supported? returning True\n"));
+ return(True);
+ }
+
+ return(False);
+ }
+
+ /* everything went OK */
+ DEBUG(8,("Lock call successful\n"));
+
+ return(True);
#else
- free(ptr);
+ return(False);
#endif
- DEBUG(3,("free called from %s(%d) with ptr=0x%X\n",
- file,line,(unsigned int)ptr));
- return;
}
-/* and re-do the define for spots lower in this file */
-#define malloc(size) malloc_wrapped(size,__FILE__,__LINE__)
-#define realloc(ptr,size) realloc_wrapped(ptr,size,__FILE__,__LINE__)
-#define free(ptr) free_wrapped(ptr,__FILE__,__LINE__)
+/*******************************************************************
+lock a file - returning a open file descriptor or -1 on failure
+The timeout is in seconds. 0 means no timeout
+********************************************************************/
+int file_lock(char *name,int timeout)
+{
+ int fd = open(name,O_RDWR|O_CREAT,0666);
+ time_t t=0;
+ if (fd < 0) return(-1);
+#if HAVE_FCNTL_LOCK
+ if (timeout) t = time(NULL);
+ while (!timeout || (time(NULL)-t < timeout)) {
+ if (fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)) return(fd);
+ msleep(LOCK_RETRY_TIMEOUT);
+ }
+ return(-1);
+#else
+ return(fd);
#endif
+}
-#ifdef REPLACE_STRSTR
-/****************************************************************************
-Mips version of strstr doesn't seem to work correctly.
-There is a #define in includes.h to redirect calls to this function.
-****************************************************************************/
-char *Strstr(char *s, char *p)
+/*******************************************************************
+unlock a file locked by file_lock
+********************************************************************/
+void file_unlock(int fd)
{
- int len = strlen(p);
+ if (fd<0) return;
+#if HAVE_FCNTL_LOCK
+ fcntl_lock(fd,F_SETLK,0,1,F_UNLCK);
+#endif
+ close(fd);
+}
- while ( *s != '\0' ) {
- if ( strncmp(s, p, len) == 0 )
- return s;
- s++;
- }
+/*******************************************************************
+is the name specified one of my netbios names
+returns true is it is equal, false otherwise
+********************************************************************/
+BOOL is_myname(char *s)
+{
+ int n;
+ BOOL ret = False;
- return NULL;
+ for (n=0; my_netbios_names[n]; n++) {
+ if (strequal(my_netbios_names[n], s))
+ ret=True;
+ }
+ DEBUG(8, ("is_myname(\"%s\") returns %d\n", s, ret));
+ return(ret);
}
-#endif /* REPLACE_STRSTR */
-
-#ifdef REPLACE_MKTIME
/*******************************************************************
-a mktime() replacement for those who don't have it - contributed by
-C.A. Lademann <cal@zls.com>
+set the horrid remote_arch string based on an enum.
********************************************************************/
-#define MINUTE 60
-#define HOUR 60*MINUTE
-#define DAY 24*HOUR
-#define YEAR 365*DAY
-time_t Mktime(struct tm *t)
-{
- struct tm *u;
- time_t epoch = 0;
- int mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
- y, m, i;
-
- if(t->tm_year < 70)
- return((time_t)-1);
-
- epoch = (t->tm_year - 70) * YEAR +
- (t->tm_year / 4 - 70 / 4 - t->tm_year / 100) * DAY;
-
- y = t->tm_year;
- m = 0;
-
- for(i = 0; i < t->tm_mon; i++) {
- epoch += mon [m] * DAY;
- if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
- epoch += DAY;
-
- if(++m > 11) {
- m = 0;
- y++;
- }
+void set_remote_arch(enum remote_arch_types type)
+{
+ ra_type = type;
+ switch( type )
+ {
+ case RA_WFWG:
+ strcpy(remote_arch, "WfWg");
+ return;
+ case RA_OS2:
+ strcpy(remote_arch, "OS2");
+ return;
+ case RA_WIN95:
+ strcpy(remote_arch, "Win95");
+ return;
+ case RA_WINNT:
+ strcpy(remote_arch, "WinNT");
+ return;
+ case RA_SAMBA:
+ strcpy(remote_arch,"Samba");
+ return;
+ default:
+ ra_type = RA_UNKNOWN;
+ strcpy(remote_arch, "UNKNOWN");
+ break;
}
+}
- epoch += (t->tm_mday - 1) * DAY;
- epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec;
-
- if((u = localtime(&epoch)) != NULL) {
- t->tm_sec = u->tm_sec;
- t->tm_min = u->tm_min;
- t->tm_hour = u->tm_hour;
- t->tm_mday = u->tm_mday;
- t->tm_mon = u->tm_mon;
- t->tm_year = u->tm_year;
- t->tm_wday = u->tm_wday;
- t->tm_yday = u->tm_yday;
- t->tm_isdst = u->tm_isdst;
-#ifndef NO_TM_NAME
- memcpy(t->tm_name, u->tm_name, LTZNMAX);
-#endif
+/*******************************************************************
+ Get the remote_arch type.
+********************************************************************/
+enum remote_arch_types get_remote_arch()
+{
+ return ra_type;
+}
+
+
+/*******************************************************************
+skip past some unicode strings in a buffer
+********************************************************************/
+char *skip_unicode_string(char *buf,int n)
+{
+ while (n--)
+ {
+ while (*buf)
+ buf += 2;
+ buf += 2;
}
+ return(buf);
+}
+
+/*******************************************************************
+Return a ascii version of a unicode string
+Hack alert: uses fixed buffer(s) and only handles ascii strings
+********************************************************************/
+#define MAXUNI 1024
+char *unistrn2(uint16 *buf, int len)
+{
+ static char lbufs[8][MAXUNI];
+ static int nexti;
+ char *lbuf = lbufs[nexti];
+ char *p;
- return(epoch);
+ nexti = (nexti+1)%8;
+
+ DEBUG(10, ("unistrn2: "));
+
+ for (p = lbuf; *buf && p-lbuf < MAXUNI-2 && len > 0; len--, p++, buf++)
+ {
+ DEBUG(10, ("%4x ", *buf));
+ *p = *buf;
+ }
+
+ DEBUG(10,("\n"));
+
+ *p = 0;
+ return lbuf;
}
-#endif /* REPLACE_MKTIME */
+/*******************************************************************
+Return a ascii version of a unicode string
+Hack alert: uses fixed buffer(s) and only handles ascii strings
+********************************************************************/
+#define MAXUNI 1024
+char *unistr2(uint16 *buf)
+{
+ static char lbufs[8][MAXUNI];
+ static int nexti;
+ char *lbuf = lbufs[nexti];
+ char *p;
+
+ nexti = (nexti+1)%8;
+
+ DEBUG(10, ("unistr2: "));
+
+ for (p = lbuf; *buf && p-lbuf < MAXUNI-2; p++, buf++)
+ {
+ DEBUG(10, ("%4x ", *buf));
+ *p = *buf;
+ }
+
+ DEBUG(10,("\n"));
+ *p = 0;
+ return lbuf;
+}
-#ifdef REPLACE_RENAME
-/* Rename a file. (from libiberty in GNU binutils) */
-int
-rename (zfrom, zto)
- const char *zfrom;
- const char *zto;
+/*******************************************************************
+create a null-terminated unicode string from a null-terminated ascii string.
+return number of unicode chars copied, excluding the null character.
+
+only handles ascii strings
+********************************************************************/
+#define MAXUNI 1024
+int struni2(uint16 *p, char *buf)
{
- if (link (zfrom, zto) < 0)
- {
- if (errno != EEXIST)
- return -1;
- if (unlink (zto) < 0
- || link (zfrom, zto) < 0)
- return -1;
- }
- return unlink (zfrom);
+ int len = 0;
+
+ if (p == NULL) return 0;
+
+ DEBUG(10, ("struni2: "));
+
+ if (buf != NULL)
+ {
+ for (; *buf && len < MAXUNI-2; len++, p++, buf++)
+ {
+ DEBUG(10, ("%2x ", *buf));
+ *p = *buf;
+ }
+
+ DEBUG(10,("\n"));
+ }
+
+ *p = 0;
+
+ return len;
}
-#endif
+/*******************************************************************
+Return a ascii version of a unicode string
+Hack alert: uses fixed buffer(s) and only handles ascii strings
+********************************************************************/
+#define MAXUNI 1024
+char *unistr(char *buf)
+{
+ static char lbufs[8][MAXUNI];
+ static int nexti;
+ char *lbuf = lbufs[nexti];
+ char *p;
-#ifdef REPLACE_INNETGR
-/*
- * Search for a match in a netgroup. This replaces it on broken systems.
- */
-int InNetGr(group, host, user, dom)
- char *group, *host, *user, *dom;
+ nexti = (nexti+1)%8;
+
+ for (p = lbuf; *buf && p-lbuf < MAXUNI-2; p++, buf += 2)
+ {
+ *p = *buf;
+ }
+ *p = 0;
+ return lbuf;
+}
+
+/*******************************************************************
+strncpy for unicode strings
+********************************************************************/
+int unistrncpy(char *dst, char *src, int len)
{
- char *hst, *usr, *dm;
-
- setnetgrent(group);
- while (getnetgrent(&hst, &usr, &dm))
- if (((host == 0) || (hst == 0) || !strcmp(host, hst)) &&
- ((user == 0) || (usr == 0) || !strcmp(user, usr)) &&
- ((dom == 0) || (dm == 0) || !strcmp(dom, dm))) {
- endnetgrent();
- return (1);
+ int num_wchars = 0;
+
+ while (*src && len > 0)
+ {
+ *dst++ = *src++;
+ *dst++ = *src++;
+ len--;
+ num_wchars++;
+ }
+ *dst++ = 0;
+ *dst++ = 0;
+
+ return num_wchars;
+}
+
+
+/*******************************************************************
+strcpy for unicode strings. returns length (in num of wide chars)
+********************************************************************/
+int unistrcpy(char *dst, char *src)
+{
+ int num_wchars = 0;
+
+ while (*src)
+ {
+ *dst++ = *src++;
+ *dst++ = *src++;
+ num_wchars++;
+ }
+ *dst++ = 0;
+ *dst++ = 0;
+
+ return num_wchars;
+}
+
+
+/*******************************************************************
+safe string copy into a fstring
+********************************************************************/
+void fstrcpy(char *dest, char *src)
+{
+ int maxlength = sizeof(fstring) - 1;
+ if (!dest) {
+ DEBUG(0,("ERROR: NULL dest in fstrcpy\n"));
+ return;
}
- endnetgrent();
- return (0);
+
+ if (!src) {
+ *dest = 0;
+ return;
+ }
+
+ while (maxlength-- && *src)
+ *dest++ = *src++;
+ *dest = 0;
+ if (*src) {
+ DEBUG(0,("ERROR: string overflow by %d in fstrcpy\n",
+ strlen(src)));
+ }
+}
+
+/*******************************************************************
+safe string copy into a pstring
+********************************************************************/
+void pstrcpy(char *dest, char *src)
+{
+ int maxlength = sizeof(pstring) - 1;
+ if (!dest) {
+ DEBUG(0,("ERROR: NULL dest in pstrcpy\n"));
+ return;
+ }
+
+ if (!src) {
+ *dest = 0;
+ return;
+ }
+
+ while (maxlength-- && *src)
+ *dest++ = *src++;
+ *dest = 0;
+ if (*src) {
+ DEBUG(0,("ERROR: string overflow by %d in pstrcpy\n",
+ strlen(src)));
+ }
+}
+
+
+/*******************************************************************
+align a pointer to a multiple of 4 bytes
+********************************************************************/
+char *align4(char *q, char *base)
+{
+ if ((q - base) & 3)
+ {
+ q += 4 - ((q - base) & 3);
+ }
+ return q;
}
-#endif
+/*******************************************************************
+align a pointer to a multiple of 2 bytes
+********************************************************************/
+char *align2(char *q, char *base)
+{
+ if ((q - base) & 1)
+ {
+ q++;
+ }
+ return q;
+}
-#if WRAP_MEMCPY
-#undef memcpy
/*******************************************************************
-a wrapper around memcpy for diagnostic purposes
+align a pointer to a multiple of align_offset bytes. looks like it
+will work for offsets of 0, 2 and 4...
********************************************************************/
-void *memcpy_wrapped(void *d,void *s,int l,char *fname,int line)
+char *align_offset(char *q, char *base, int align_offset_len)
{
- if (l>64 && (((int)d)%4) != (((int)s)%4))
- DEBUG(4,("Misaligned memcpy(0x%X,0x%X,%d) at %s(%d)\n",d,s,l,fname,line));
-#ifdef xx_old_memcpy
- return(xx_old_memcpy(d,s,l));
-#else
- return(memcpy(d,s,l));
-#endif
+ int mod = ((q - base) & (align_offset_len-1));
+ if (align_offset_len != 0 && mod != 0)
+ {
+ q += align_offset_len - mod;
+ }
+ return q;
+}
+
+void print_asc(int level, unsigned char *buf,int len)
+{
+ int i;
+ for (i=0;i<len;i++)
+ DEBUG(level,("%c", isprint(buf[i])?buf[i]:'.'));
+}
+
+void dump_data(int level,char *buf1,int len)
+{
+ unsigned char *buf = (unsigned char *)buf1;
+ int i=0;
+ if (len<=0) return;
+
+ DEBUG(level,("[%03X] ",i));
+ for (i=0;i<len;) {
+ DEBUG(level,("%02X ",(int)buf[i]));
+ i++;
+ if (i%8 == 0) DEBUG(level,(" "));
+ if (i%16 == 0) {
+ print_asc(level,&buf[i-16],8); DEBUG(level,(" "));
+ print_asc(level,&buf[i-8],8); DEBUG(level,("\n"));
+ if (i<len) DEBUG(level,("[%03X] ",i));
+ }
+ }
+ if (i%16) {
+ int n;
+
+ n = 16 - (i%16);
+ DEBUG(level,(" "));
+ if (n>8) DEBUG(level,(" "));
+ while (n--) DEBUG(level,(" "));
+
+ n = MIN(8,i%16);
+ print_asc(level,&buf[i-(i%16)],n); DEBUG(level,(" "));
+ n = (i%16) - n;
+ if (n>0) print_asc(level,&buf[i-n],n);
+ DEBUG(level,("\n"));
+ }
}
-#define memcpy(d,s,l) memcpy_wrapped(d,s,l,__FILE__,__LINE__)
-#endif
+char *tab_depth(int depth)
+{
+ static pstring spaces;
+ memset(spaces, ' ', depth * 4);
+ spaces[depth * 4] = 0;
+ return spaces;
+}
diff --git a/source/libsmb/clientgen.c b/source/libsmb/clientgen.c
new file mode 100644
index 00000000000..b6ad1611ace
--- /dev/null
+++ b/source/libsmb/clientgen.c
@@ -0,0 +1,746 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB client generic functions
+ Copyright (C) Andrew Tridgell 1994-1997
+
+ 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"
+
+
+extern int DEBUGLEVEL;
+
+/****************************************************************************
+setup basics in a outgoing packet
+****************************************************************************/
+static void cli_setup_packet(struct cli_state *cli)
+{
+ SSVAL(cli->outbuf,smb_pid,cli->pid);
+ SSVAL(cli->outbuf,smb_uid,cli->uid);
+ SSVAL(cli->outbuf,smb_mid,cli->mid);
+ if (cli->protocol > PROTOCOL_CORE) {
+ SCVAL(cli->outbuf,smb_flg,0x8);
+ SSVAL(cli->outbuf,smb_flg2,0x1);
+ }
+}
+
+
+/****************************************************************************
+ send a SMB trans or trans2 request
+ ****************************************************************************/
+static BOOL cli_send_trans(struct cli_state *cli,
+ 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;
+ char *p;
+
+ this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*SIZEOFWORD)); /* hack */
+ this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*SIZEOFWORD+this_lparam));
+
+ bzero(cli->outbuf,smb_size);
+ set_message(cli->outbuf,14+lsetup,0,True);
+ CVAL(cli->outbuf,smb_com) = trans;
+ SSVAL(cli->outbuf,smb_tid, cli->cnum);
+ cli_setup_packet(cli);
+
+ outparam = smb_buf(cli->outbuf)+(trans==SMBtrans ? strlen(name)+1 : 3);
+ outdata = outparam+this_lparam;
+
+ /* primary request */
+ SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */
+ SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */
+ SSVAL(cli->outbuf,smb_mprcnt,mparam); /* mprcnt */
+ SSVAL(cli->outbuf,smb_mdrcnt,mdata); /* mdrcnt */
+ SCVAL(cli->outbuf,smb_msrcnt,msetup); /* msrcnt */
+ SSVAL(cli->outbuf,smb_flags,flags); /* flags */
+ SIVAL(cli->outbuf,smb_timeout,0); /* timeout */
+ SSVAL(cli->outbuf,smb_pscnt,this_lparam); /* pscnt */
+ SSVAL(cli->outbuf,smb_psoff,smb_offset(outparam,cli->outbuf)); /* psoff */
+ SSVAL(cli->outbuf,smb_dscnt,this_ldata); /* dscnt */
+ SSVAL(cli->outbuf,smb_dsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
+ SCVAL(cli->outbuf,smb_suwcnt,lsetup); /* suwcnt */
+ for (i=0;i<lsetup;i++) /* setup[] */
+ SSVAL(cli->outbuf,smb_setup+i*SIZEOFWORD,setup[i]);
+ p = smb_buf(cli->outbuf);
+ if (trans==SMBtrans) {
+ strcpy(p,name); /* name[] */
+ } else {
+ *p++ = 0; /* put in a null smb_name */
+ *p++ = 'D'; *p++ = ' '; /* observed in OS/2 */
+ }
+ if (this_lparam) /* param[] */
+ memcpy(outparam,param,this_lparam);
+ if (this_ldata) /* data[] */
+ memcpy(outdata,data,this_ldata);
+ set_message(cli->outbuf,14+lsetup, /* wcnt, bcc */
+ PTR_DIFF(outdata+this_ldata,smb_buf(cli->outbuf)),False);
+
+ show_msg(cli->outbuf);
+ send_smb(cli->fd,cli->outbuf);
+
+ if (this_ldata < ldata || this_lparam < lparam) {
+ /* receive interim response */
+ if (!receive_smb(cli->fd,cli->inbuf,cli->timeout) ||
+ CVAL(cli->inbuf,smb_rcls) != 0) {
+ return(False);
+ }
+
+ tot_data = this_ldata;
+ tot_param = this_lparam;
+
+ while (tot_data < ldata || tot_param < lparam) {
+ this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
+ this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
+
+ set_message(cli->outbuf,trans==SMBtrans?8:9,0,True);
+ CVAL(cli->outbuf,smb_com) = trans==SMBtrans ? SMBtranss : SMBtranss2;
+
+ outparam = smb_buf(cli->outbuf);
+ outdata = outparam+this_lparam;
+
+ /* secondary request */
+ SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */
+ SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */
+ SSVAL(cli->outbuf,smb_spscnt,this_lparam); /* pscnt */
+ SSVAL(cli->outbuf,smb_spsoff,smb_offset(outparam,cli->outbuf)); /* psoff */
+ SSVAL(cli->outbuf,smb_spsdisp,tot_param); /* psdisp */
+ SSVAL(cli->outbuf,smb_sdscnt,this_ldata); /* dscnt */
+ SSVAL(cli->outbuf,smb_sdsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
+ SSVAL(cli->outbuf,smb_sdsdisp,tot_data); /* dsdisp */
+ if (trans==SMBtrans2)
+ SSVAL(cli->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(cli->outbuf,trans==SMBtrans?8:9, /* wcnt, bcc */
+ PTR_DIFF(outdata+this_ldata,smb_buf(cli->outbuf)),False);
+
+ show_msg(cli->outbuf);
+ send_smb(cli->fd,cli->outbuf);
+
+ tot_data += this_ldata;
+ tot_param += this_lparam;
+ }
+ }
+
+ return(True);
+}
+
+
+/****************************************************************************
+ receive a SMB trans or trans2 response allocating the necessary memory
+ ****************************************************************************/
+static BOOL cli_receive_trans(struct cli_state *cli,
+ 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;
+
+ if (!receive_smb(cli->fd,cli->inbuf,cli->timeout))
+ return False;
+
+ show_msg(cli->inbuf);
+
+ /* sanity check */
+ if (CVAL(cli->inbuf,smb_com) != trans) {
+ DEBUG(0,("Expected %s response, got command 0x%02x\n",
+ trans==SMBtrans?"SMBtrans":"SMBtrans2",
+ CVAL(cli->inbuf,smb_com)));
+ return(False);
+ }
+ if (CVAL(cli->inbuf,smb_rcls) != 0)
+ return(False);
+
+ /* parse out the lengths */
+ total_data = SVAL(cli->inbuf,smb_tdrcnt);
+ total_param = SVAL(cli->inbuf,smb_tprcnt);
+
+ /* allocate it */
+ *data = Realloc(*data,total_data);
+ *param = Realloc(*param,total_param);
+
+ while (1) {
+ this_data = SVAL(cli->inbuf,smb_drcnt);
+ this_param = SVAL(cli->inbuf,smb_prcnt);
+
+ if (this_data + *data_len > total_data ||
+ this_param + *param_len > total_param) {
+ DEBUG(1,("Data overflow in cli_receive_trans\n"));
+ return False;
+ }
+
+ if (this_data)
+ memcpy(*data + SVAL(cli->inbuf,smb_drdisp),
+ smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_droff),
+ this_data);
+ if (this_param)
+ memcpy(*param + SVAL(cli->inbuf,smb_prdisp),
+ smb_base(cli->inbuf) + SVAL(cli->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(cli->inbuf,smb_tdrcnt);
+ total_param = SVAL(cli->inbuf,smb_tprcnt);
+
+ if (total_data <= *data_len && total_param <= *param_len)
+ break;
+
+ if (!receive_smb(cli->fd,cli->inbuf,cli->timeout))
+ return False;
+
+ show_msg(cli->inbuf);
+
+ /* sanity check */
+ if (CVAL(cli->inbuf,smb_com) != trans) {
+ DEBUG(0,("Expected %s response, got command 0x%02x\n",
+ trans==SMBtrans?"SMBtrans":"SMBtrans2",
+ CVAL(cli->inbuf,smb_com)));
+ return(False);
+ }
+ if (CVAL(cli->inbuf,smb_rcls) != 0)
+ return(False);
+ }
+
+ return(True);
+}
+
+
+/****************************************************************************
+call a remote api
+****************************************************************************/
+static BOOL cli_api(struct cli_state *cli,
+ int prcnt,int drcnt,int mprcnt,int mdrcnt,int *rprcnt,
+ int *rdrcnt, char *param,char *data,
+ char **rparam, char **rdata)
+{
+ cli_send_trans(cli,SMBtrans,"\\PIPE\\LANMAN",0,0,
+ data,param,NULL,
+ drcnt,prcnt,0,
+ mdrcnt,mprcnt,0);
+
+ return (cli_receive_trans(cli,SMBtrans,
+ rdrcnt,rprcnt,
+ rdata,rparam));
+}
+
+
+/****************************************************************************
+perform a NetWkstaUserLogon
+****************************************************************************/
+BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt;
+ pstring param;
+
+ memset(param, 0, sizeof(param));
+
+ /* send a SMBtrans command with api NetWkstaUserLogon */
+ p = param;
+ SSVAL(p,0,132); /* api number */
+ p += 2;
+ strcpy(p,"OOWb54WrLh");
+ p = skip_string(p,1);
+ strcpy(p,"WB21BWDWWDDDDDDDzzzD");
+ p = skip_string(p,1);
+ SSVAL(p,0,1);
+ p += 2;
+ strcpy(p,user);
+ strupper(p);
+ p += 21; p++; p += 15; p++;
+ strcpy(p, workstation);
+ strupper(p);
+ p += 16;
+ SSVAL(p, 0, BUFFER_SIZE);
+ p += 2;
+ SSVAL(p, 0, BUFFER_SIZE);
+ p += 2;
+
+ cli->error = -1;
+
+ if (cli_api(cli, PTR_DIFF(p,param),0,
+ 1024,BUFFER_SIZE,
+ &rprcnt,&rdrcnt,
+ param,NULL,
+ &rparam,&rdata)) {
+ cli->error = SVAL(rparam,0);
+ p = rdata;
+
+ if (cli->error == 0) {
+ DEBUG(4,("NetWkstaUserLogon success\n"));
+ cli->privilages = SVAL(p, 24);
+ fstrcpy(cli->eff_name,p+2);
+ } else {
+ DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->error));
+ }
+ }
+
+ if (rparam) free(rparam);
+ if (rdata) free(rdata);
+ return cli->error == 0;
+}
+
+
+/****************************************************************************
+call a NetServerEnum for the specified workgroup and servertype mask.
+This function then calls the specified callback function for each name returned.
+
+The callback function takes 3 arguments: the machine name, the server type and
+the comment.
+****************************************************************************/
+BOOL cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
+ void (*fn)(char *, uint32, char *))
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rdrcnt,rprcnt;
+ char *p;
+ pstring param;
+ int uLevel = 1;
+ int count = -1;
+
+ /* send a SMBtrans command with api NetServerEnum */
+ p = param;
+ SSVAL(p,0,0x68); /* api number */
+ p += 2;
+ strcpy(p,"WrLehDz");
+ p = skip_string(p,1);
+
+ strcpy(p,"B16BBDz");
+
+ p = skip_string(p,1);
+ SSVAL(p,0,uLevel);
+ SSVAL(p,2,BUFFER_SIZE);
+ p += 4;
+ SIVAL(p,0,stype);
+ p += 4;
+
+ pstrcpy(p, workgroup);
+ p = skip_string(p,1);
+
+ if (cli_api(cli,
+ PTR_DIFF(p,param), /* param count */
+ 8, /*data count */
+ 0, /* mprcount */
+ BUFFER_SIZE, /* mdrcount */
+ &rprcnt,&rdrcnt,
+ param, NULL,
+ &rparam,&rdata)) {
+ int res = SVAL(rparam,0);
+ int converter=SVAL(rparam,2);
+ int i;
+
+ if (res == 0) {
+ count=SVAL(rparam,4);
+ p = rdata;
+
+ for (i = 0;i < count;i++, p += 26) {
+ char *sname = p;
+ int comment_offset = IVAL(p,22) & 0xFFFF;
+ char *cmnt = comment_offset?(rdata+comment_offset-converter):"";
+
+ stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
+
+ fn(sname, stype, cmnt);
+ }
+ }
+ }
+
+ if (rparam) free(rparam);
+ if (rdata) free(rdata);
+
+ return(count > 0);
+}
+
+
+
+
+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 session setup
+****************************************************************************/
+BOOL cli_session_setup(struct cli_state *cli,
+ char *user,
+ char *pass, int passlen,
+ char *ntpass, int ntpasslen,
+ char *workgroup)
+{
+ char *p;
+ fstring pword;
+
+ if (cli->protocol < PROTOCOL_LANMAN1)
+ return False;
+
+ if (passlen > sizeof(pword)-1) {
+ return False;
+ }
+
+ if ((cli->sec_mode & 2) && *pass && passlen != 24) {
+ passlen = 24;
+ SMBencrypt((uchar *)pass,(uchar *)cli->cryptkey,(uchar *)pword);
+ } else {
+ memcpy(pword, pass, passlen);
+ }
+
+ /* if in share level security then don't send a password now */
+ if (!(cli->sec_mode & 1)) {fstrcpy(pword, "");passlen=1;}
+
+ /* send a session setup command */
+ bzero(cli->outbuf,smb_size);
+
+ if (cli->protocol < PROTOCOL_NT1) {
+ set_message(cli->outbuf,10,1 + strlen(user) + passlen,True);
+ CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
+ cli_setup_packet(cli);
+
+ CVAL(cli->outbuf,smb_vwv0) = 0xFF;
+ SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
+ SSVAL(cli->outbuf,smb_vwv3,2);
+ SSVAL(cli->outbuf,smb_vwv4,1);
+ SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
+ SSVAL(cli->outbuf,smb_vwv7,passlen);
+ p = smb_buf(cli->outbuf);
+ memcpy(p,pword,passlen);
+ p += passlen;
+ strcpy(p,user);
+ strupper(p);
+ } else {
+ set_message(cli->outbuf,13,0,True);
+ CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
+ cli_setup_packet(cli);
+
+ CVAL(cli->outbuf,smb_vwv0) = 0xFF;
+ SSVAL(cli->outbuf,smb_vwv2,BUFFER_SIZE);
+ SSVAL(cli->outbuf,smb_vwv3,2);
+ SSVAL(cli->outbuf,smb_vwv4,cli->pid);
+ SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
+ SSVAL(cli->outbuf,smb_vwv7,passlen);
+ SSVAL(cli->outbuf,smb_vwv8,ntpasslen);
+ p = smb_buf(cli->outbuf);
+ memcpy(p,pword,passlen);
+ p += SVAL(cli->outbuf,smb_vwv7);
+ memcpy(p,ntpass,ntpasslen);
+ p += SVAL(cli->outbuf,smb_vwv8);
+ strcpy(p,user);
+ strupper(p);
+ p = skip_string(p,1);
+ strcpy(p,workgroup);
+ strupper(p);
+ p = skip_string(p,1);
+ strcpy(p,"Unix");p = skip_string(p,1);
+ strcpy(p,"Samba");p = skip_string(p,1);
+ set_message(cli->outbuf,13,PTR_DIFF(p,smb_buf(cli->outbuf)),False);
+ }
+
+ send_smb(cli->fd,cli->outbuf);
+ if (!receive_smb(cli->fd,cli->inbuf,cli->timeout))
+ return False;
+
+ show_msg(cli->inbuf);
+
+ if (CVAL(cli->inbuf,smb_rcls) != 0) {
+ return False;
+ }
+
+ /* use the returned uid from now on */
+ cli->uid = SVAL(cli->inbuf,smb_uid);
+
+ return True;
+}
+
+
+/****************************************************************************
+send a tconX
+****************************************************************************/
+BOOL cli_send_tconX(struct cli_state *cli,
+ char *share, char *dev, char *pword, int passlen)
+{
+ char *p;
+ bzero(cli->outbuf,smb_size);
+ bzero(cli->inbuf,smb_size);
+
+ set_message(cli->outbuf,4,
+ 2 + strlen(share) + passlen + strlen(dev),True);
+ CVAL(cli->outbuf,smb_com) = SMBtconX;
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv3,passlen);
+
+ p = smb_buf(cli->outbuf);
+ memcpy(p,pword,passlen);
+ p += passlen;
+ strcpy(p,share);
+ p = skip_string(p,1);
+ strcpy(p,dev);
+
+ SCVAL(cli->inbuf,smb_rcls, 1);
+
+ send_smb(cli->fd,cli->outbuf);
+ if (!receive_smb(cli->fd,cli->inbuf,cli->timeout))
+ return False;
+
+ if (CVAL(cli->inbuf,smb_rcls) != 0) {
+ return False;
+ }
+
+ cli->cnum = SVAL(cli->inbuf,smb_tid);
+ return True;
+}
+
+
+/****************************************************************************
+send a tree disconnect
+****************************************************************************/
+BOOL cli_tdis(struct cli_state *cli)
+{
+ bzero(cli->outbuf,smb_size);
+ set_message(cli->outbuf,0,0,True);
+ CVAL(cli->outbuf,smb_com) = SMBtdis;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ send_smb(cli->fd,cli->outbuf);
+ if (!receive_smb(cli->fd,cli->inbuf,cli->timeout))
+ return False;
+
+ return CVAL(cli->inbuf,smb_rcls) == 0;
+}
+
+
+/****************************************************************************
+send a negprot command
+****************************************************************************/
+BOOL cli_negprot(struct cli_state *cli)
+{
+ char *p;
+ int numprots;
+ int plength;
+
+ bzero(cli->outbuf,smb_size);
+
+ /* setup the protocol strings */
+ for (plength=0,numprots=0;
+ prots[numprots].name && prots[numprots].prot<=cli->protocol;
+ numprots++)
+ plength += strlen(prots[numprots].name)+2;
+
+ set_message(cli->outbuf,0,plength,True);
+
+ p = smb_buf(cli->outbuf);
+ for (numprots=0;
+ prots[numprots].name && prots[numprots].prot<=cli->protocol;
+ numprots++) {
+ *p++ = 2;
+ strcpy(p,prots[numprots].name);
+ p += strlen(p) + 1;
+ }
+
+ CVAL(cli->outbuf,smb_com) = SMBnegprot;
+ cli_setup_packet(cli);
+
+ CVAL(smb_buf(cli->outbuf),0) = 2;
+
+ send_smb(cli->fd,cli->outbuf);
+ if (!receive_smb(cli->fd,cli->inbuf,cli->timeout))
+ return False;
+
+ show_msg(cli->inbuf);
+
+ if (CVAL(cli->inbuf,smb_rcls) != 0 ||
+ ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
+ return(False);
+ }
+
+ cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
+
+
+ if (cli->protocol < PROTOCOL_NT1) {
+ cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
+ cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
+ cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
+ cli->serverzone = SVALS(cli->inbuf,smb_vwv10)*60;
+ /* this time is converted to GMT by make_unix_date */
+ cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
+ if (cli->protocol >= PROTOCOL_COREPLUS) {
+ cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
+ cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
+ }
+ memcpy(cli->cryptkey,smb_buf(cli->inbuf),8);
+ } else {
+ /* NT protocol */
+ cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
+ cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
+ cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
+ cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1)*60;
+ /* this time arrives in real GMT */
+ cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
+ memcpy(cli->cryptkey,smb_buf(cli->inbuf),8);
+ if (IVAL(cli->inbuf,smb_vwv9+1) & 1)
+ cli->readbraw_supported =
+ cli->writebraw_supported = True;
+ }
+
+ return True;
+}
+
+
+/****************************************************************************
+ send a session request
+****************************************************************************/
+BOOL cli_session_request(struct cli_state *cli, char *host, int name_type,
+ char *myname)
+{
+ fstring dest;
+ char *p;
+ int len = 4;
+ /* send a session request (RFC 1002) */
+
+ fstrcpy(dest,host);
+
+ p = strchr(dest,'.');
+ if (p) *p = 0;
+
+ fstrcpy(cli->desthost, dest);
+
+ /* put in the destination name */
+ p = cli->outbuf+len;
+ name_mangle(dest,p,name_type);
+ len += name_len(p);
+
+ /* and my name */
+ p = cli->outbuf+len;
+ name_mangle(myname,p,0);
+ len += name_len(p);
+
+ /* setup the packet length */
+ _smb_setlen(cli->outbuf,len);
+ CVAL(cli->outbuf,0) = 0x81;
+
+ send_smb(cli->fd,cli->outbuf);
+ DEBUG(5,("Sent session request\n"));
+
+ if (!receive_smb(cli->fd,cli->inbuf,cli->timeout))
+ return False;
+
+ if (CVAL(cli->inbuf,0) != 0x82) {
+ cli->error = CVAL(cli->inbuf,0);
+ return False;
+ }
+ return(True);
+}
+
+
+/****************************************************************************
+open the client sockets
+****************************************************************************/
+BOOL cli_connect(struct cli_state *cli, char *host, struct in_addr *ip)
+{
+ struct in_addr dest_ip;
+
+ fstrcpy(cli->desthost, host);
+
+ if (!ip) {
+ struct hostent *hp;
+
+ if ((hp = Get_Hostbyname(cli->desthost)) == 0) {
+ return False;
+ }
+
+ putip((char *)&dest_ip,(char *)hp->h_addr);
+ } else {
+ dest_ip = *ip;
+ }
+
+
+ cli->fd = open_socket_out(SOCK_STREAM, &dest_ip, 139, cli->timeout);
+ if (cli->fd == -1)
+ return False;
+
+ return True;
+}
+
+
+/****************************************************************************
+initialise a client structure
+****************************************************************************/
+BOOL cli_initialise(struct cli_state *cli)
+{
+ if (cli->initialised) cli_shutdown(cli);
+
+ memset(cli, 0, sizeof(*cli));
+ cli->fd = -1;
+ cli->cnum = -1;
+ cli->pid = getpid();
+ cli->mid = 1;
+ cli->uid = getuid();
+ cli->protocol = PROTOCOL_NT1;
+ cli->timeout = 20000;
+ cli->bufsize = 0x10000;
+ cli->max_xmit = cli->bufsize - 4;
+ cli->outbuf = (char *)malloc(cli->bufsize);
+ cli->inbuf = (char *)malloc(cli->bufsize);
+ if (!cli->outbuf || !cli->inbuf) return False;
+ cli->initialised = 1;
+ return True;
+}
+
+/****************************************************************************
+shutdown a client structure
+****************************************************************************/
+void cli_shutdown(struct cli_state *cli)
+{
+ if (cli->outbuf) free(cli->outbuf);
+ if (cli->inbuf) free(cli->inbuf);
+ if (cli->fd != -1) close(cli->fd);
+ memset(cli, 0, sizeof(*cli));
+}
diff --git a/source/libsmb/credentials.c b/source/libsmb/credentials.c
new file mode 100644
index 00000000000..6711604f6d9
--- /dev/null
+++ b/source/libsmb/credentials.c
@@ -0,0 +1,224 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ code to manipulate domain credentials
+ Copyright (C) Andrew Tridgell 1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+/****************************************************************************
+ setup the session key.
+Input: 8 byte challenge block
+ 8 byte server challenge block
+ 16 byte md4 encrypted password
+Output:
+ 8 byte session key
+****************************************************************************/
+void cred_session_key(DOM_CHAL *clnt_chal, DOM_CHAL *srv_chal, char *pass,
+ uint32 session_key[2])
+{
+ uint32 sum[2];
+ unsigned char sum2[8];
+ unsigned char netsesskey[8];
+
+ sum[0] = IVAL(clnt_chal->data, 0) + IVAL(srv_chal->data, 0);
+ sum[1] = IVAL(clnt_chal->data, 4) + IVAL(srv_chal->data, 4);
+
+ SIVAL(sum2,0,sum[0]);
+ SIVAL(sum2,4,sum[1]);
+
+ cred_hash1(netsesskey, sum2,(unsigned char *)pass);
+
+ session_key[0] = IVAL(netsesskey, 0);
+ session_key[1] = IVAL(netsesskey, 4);
+
+ /* debug output */
+ DEBUG(4,("cred_session_key\n"));
+
+ DEBUG(5,(" clnt_chal: %lx %lx\n", clnt_chal->data[0], clnt_chal->data[1]));
+ DEBUG(5,(" srv_chal : %lx %lx\n", srv_chal ->data[0], srv_chal ->data[1]));
+ DEBUG(5,(" clnt+srv : %lx %lx\n", sum [0], sum [1]));
+ DEBUG(5,(" sess_key : %lx %lx\n", session_key [0], session_key [1]));
+}
+
+
+/****************************************************************************
+create a credential
+
+Input:
+ 8 byte sesssion key
+ 8 byte stored credential
+ 4 byte timestamp
+
+Output:
+ 8 byte credential
+****************************************************************************/
+void cred_create(uint32 session_key[2], DOM_CHAL *stor_cred, UTIME timestamp,
+ DOM_CHAL *cred)
+{
+ DOM_CHAL time_cred;
+ unsigned char calc_cred[8];
+ unsigned char timecred[8];
+ unsigned char netsesskey[8];
+
+ SIVAL(netsesskey, 0, session_key[0]);
+ SIVAL(netsesskey, 4, session_key[1]);
+
+ SIVAL(timecred, 0, IVAL(stor_cred, 0) + timestamp.time);
+ SIVAL(timecred, 4, IVAL(stor_cred, 4));
+
+ cred_hash2(calc_cred, timecred, netsesskey);
+
+ cred->data[0] = IVAL(calc_cred, 0);
+ cred->data[1] = IVAL(calc_cred, 4);
+
+ time_cred.data[0] = IVAL(timecred, 0);
+ time_cred.data[1] = IVAL(timecred, 4);
+
+ /* debug output*/
+ DEBUG(4,("cred_create\n"));
+
+ DEBUG(5,(" sess_key : %lx %lx\n", session_key [0], session_key [1]));
+ DEBUG(5,(" stor_cred: %lx %lx\n", stor_cred->data[0], stor_cred->data[1]));
+ DEBUG(5,(" timestamp: %lx\n" , timestamp.time));
+ DEBUG(5,(" timecred : %lx %lx\n", time_cred .data[0], time_cred .data[1]));
+ DEBUG(5,(" calc_cred: %lx %lx\n", cred ->data[0], cred ->data[1]));
+}
+
+
+/****************************************************************************
+ check a supplied credential
+
+Input:
+ 8 byte received credential
+ 8 byte sesssion key
+ 8 byte stored credential
+ 4 byte timestamp
+
+Output:
+ returns 1 if computed credential matches received credential
+ returns 0 otherwise
+****************************************************************************/
+int cred_assert(DOM_CHAL *cred, uint32 session_key[2], DOM_CHAL *stored_cred,
+ UTIME timestamp)
+{
+ DOM_CHAL cred2;
+
+ cred_create(session_key, stored_cred, timestamp, &cred2);
+
+ /* debug output*/
+ DEBUG(4,("cred_assert\n"));
+
+ DEBUG(5,(" challenge : %lx %lx\n", cred->data[0], cred->data[1]));
+ DEBUG(5,(" calculated: %lx %lx\n", cred2.data[0], cred2.data[1]));
+
+ if (memcmp(cred->data, cred2.data, 8) == 0)
+ {
+ DEBUG(5, ("credentials check ok\n"));
+ return True;
+ }
+ else
+ {
+ DEBUG(5, ("credentials check wrong\n"));
+ return False;
+ }
+}
+
+
+/****************************************************************************
+ checks credentials; generates next step in the credential chain
+****************************************************************************/
+BOOL clnt_deal_with_creds(uint32 sess_key[2],
+ DOM_CRED *sto_clnt_cred, DOM_CRED *rcv_srv_cred)
+{
+ UTIME new_clnt_time;
+ uint32 new_cred;
+
+ DEBUG(5,("clnt_deal_with_creds: %d\n", __LINE__));
+
+ /* increment client time by one second */
+ new_clnt_time.time = sto_clnt_cred->timestamp.time + 1;
+
+ /* check that the received server credentials are valid */
+ if (!cred_assert(&(rcv_srv_cred->challenge), sess_key,
+ &(sto_clnt_cred->challenge), new_clnt_time))
+ {
+ return False;
+ }
+
+ /* first 4 bytes of the new seed is old client 4 bytes + clnt time + 1 */
+ new_cred = IVAL(sto_clnt_cred->challenge.data, 0);
+ new_cred += new_clnt_time.time;
+
+ /* store new seed in client credentials */
+ SIVAL(sto_clnt_cred->challenge.data, 0, new_cred);
+
+ DEBUG(5,(" new clnt cred: %lx %lx\n", sto_clnt_cred->challenge.data[0],
+ sto_clnt_cred->challenge.data[1]));
+ return True;
+}
+
+
+/****************************************************************************
+ checks credentials; generates next step in the credential chain
+****************************************************************************/
+BOOL deal_with_creds(uint32 sess_key[2],
+ DOM_CRED *sto_clnt_cred,
+ DOM_CRED *rcv_clnt_cred, DOM_CRED *rtn_srv_cred)
+{
+ UTIME new_clnt_time;
+ uint32 new_cred;
+
+ DEBUG(5,("deal_with_creds: %d\n", __LINE__));
+
+ /* check that the received client credentials are valid */
+ if (!cred_assert(&(rcv_clnt_cred->challenge), sess_key,
+ &(sto_clnt_cred->challenge), rcv_clnt_cred->timestamp))
+ {
+ return False;
+ }
+
+ /* increment client time by one second */
+ new_clnt_time.time = rcv_clnt_cred->timestamp.time + 1;
+
+ /* first 4 bytes of the new seed is old client 4 bytes + clnt time + 1 */
+ new_cred = IVAL(sto_clnt_cred->challenge.data, 0);
+ new_cred += new_clnt_time.time;
+
+ DEBUG(5,("deal_with_creds: new_cred[0]=%lx\n", new_cred));
+
+ /* doesn't matter that server time is 0 */
+ rtn_srv_cred->timestamp.time = 0;
+
+ DEBUG(5,("deal_with_creds: new_clnt_time=%lx\n", new_clnt_time.time));
+
+ /* create return credentials for inclusion in the reply */
+ cred_create(sess_key, &(sto_clnt_cred->challenge), new_clnt_time,
+ &(rtn_srv_cred->challenge));
+
+ DEBUG(5,("deal_with_creds: clnt_cred[0]=%lx\n",
+ sto_clnt_cred->challenge.data[0]));
+
+ /* store new seed in client credentials */
+ SIVAL(sto_clnt_cred->challenge.data, 0, new_cred);
+
+ return True;
+}
+
+
diff --git a/source/libsmb/namequery.c b/source/libsmb/namequery.c
new file mode 100644
index 00000000000..55f70be1222
--- /dev/null
+++ b/source/libsmb/namequery.c
@@ -0,0 +1,295 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ name query routines
+ Copyright (C) Andrew Tridgell 1994-1997
+
+ 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 numnames = CVAL(p,0);
+ DEBUG(1,("received %d names\n",numnames));
+
+ if (rname) *rname = 0;
+ if (master) *master = 0;
+
+ p += 1;
+ while (numnames--)
+ {
+ char qname[17];
+ int type;
+ fstring flags;
+ int i;
+ *flags = 0;
+ StrnCpy(qname,p,15);
+ type = CVAL(p,15);
+ p += 16;
+
+ strcat(flags, (p[0] & 0x80) ? "<GROUP> " : " ");
+ if ((p[0] & 0x60) == 0x00) strcat(flags,"B ");
+ if ((p[0] & 0x60) == 0x20) strcat(flags,"P ");
+ if ((p[0] & 0x60) == 0x40) strcat(flags,"M ");
+ if ((p[0] & 0x60) == 0x60) strcat(flags,"H ");
+ if (p[0] & 0x10) strcat(flags,"<DEREGISTERING> ");
+ if (p[0] & 0x08) strcat(flags,"<CONFLICT> ");
+ if (p[0] & 0x04) strcat(flags,"<ACTIVE> ");
+ if (p[0] & 0x02) strcat(flags,"<PERMANENT> ");
+
+ if (master && !*master && type == 0x1d) {
+ StrnCpy(master,qname,15);
+ trim_string(master,NULL," ");
+ }
+
+ if (rname && !*rname && type == 0x20 && !(p[0]&0x80)) {
+ StrnCpy(rname,qname,15);
+ trim_string(rname,NULL," ");
+ }
+
+ for (i = strlen( qname) ; --i >= 0 ; ) {
+ if (!isprint(qname[i])) qname[i] = '.';
+ }
+ DEBUG(1,("\t%-15s <%02x> - %s\n",qname,type,flags));
+ p+=2;
+ }
+ DEBUG(1,("num_good_sends=%d num_good_receives=%d\n",
+ IVAL(p,20),IVAL(p,24)));
+}
+
+
+/****************************************************************************
+ do a netbios name status query on a host
+
+ the "master" parameter is a hack used for finding workgroups.
+ **************************************************************************/
+BOOL name_status(int fd,char *name,int name_type,BOOL recurse,
+ struct in_addr to_ip,char *master,char *rname,
+ void (*fn)())
+{
+ BOOL found=False;
+ int retries = 2;
+ int retry_time = 5000;
+ struct timeval tval;
+ struct packet_struct p;
+ struct packet_struct *p2;
+ struct nmb_packet *nmb = &p.packet.nmb;
+ static int name_trn_id = 0;
+
+ bzero((char *)&p,sizeof(p));
+
+ if (!name_trn_id) name_trn_id = (time(NULL)%(unsigned)0x7FFF) +
+ (getpid()%(unsigned)100);
+ name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
+
+ nmb->header.name_trn_id = name_trn_id;
+ nmb->header.opcode = 0;
+ nmb->header.response = False;
+ nmb->header.nm_flags.bcast = False;
+ nmb->header.nm_flags.recursion_available = False;
+ nmb->header.nm_flags.recursion_desired = False;
+ nmb->header.nm_flags.trunc = False;
+ nmb->header.nm_flags.authoritative = False;
+ nmb->header.rcode = 0;
+ nmb->header.qdcount = 1;
+ nmb->header.ancount = 0;
+ nmb->header.nscount = 0;
+ nmb->header.arcount = 0;
+
+ make_nmb_name(&nmb->question.question_name,name,name_type,scope);
+
+ nmb->question.question_type = 0x21;
+ nmb->question.question_class = 0x1;
+
+ p.ip = to_ip;
+ p.port = NMB_PORT;
+ p.fd = fd;
+ p.timestamp = time(NULL);
+ p.packet_type = NMB_PACKET;
+
+ GetTimeOfDay(&tval);
+
+ if (!send_packet(&p))
+ return(False);
+
+ retries--;
+
+ while (1)
+ {
+ struct timeval tval2;
+ GetTimeOfDay(&tval2);
+ if (TvalDiff(&tval,&tval2) > retry_time) {
+ if (!retries) break;
+ if (!found && !send_packet(&p))
+ return False;
+ GetTimeOfDay(&tval);
+ retries--;
+ }
+
+ if ((p2=receive_packet(fd,NMB_PACKET,90)))
+ {
+ struct nmb_packet *nmb2 = &p2->packet.nmb;
+ debug_nmb_packet(p2);
+
+ if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
+ !nmb2->header.response) {
+ /* its not for us - maybe deal with it later */
+ if (fn)
+ fn(p2);
+ else
+ free_packet(p2);
+ continue;
+ }
+
+ if (nmb2->header.opcode != 0 ||
+ nmb2->header.nm_flags.bcast ||
+ nmb2->header.rcode ||
+ !nmb2->header.ancount ||
+ nmb2->answers->rr_type != 0x21) {
+ /* XXXX what do we do with this? could be a redirect, but
+ we'll discard it for the moment */
+ free_packet(p2);
+ continue;
+ }
+
+ _interpret_node_status(&nmb2->answers->rdata[0], master,rname);
+ free_packet(p2);
+ return(True);
+ }
+ }
+
+
+ DEBUG(0,("No status response (this is not unusual)\n"));
+
+ return(False);
+}
+
+
+/****************************************************************************
+ do a netbios name query to find someones IP
+ ****************************************************************************/
+BOOL name_query(int fd,char *name,int name_type,
+ BOOL bcast,BOOL recurse,
+ struct in_addr to_ip, struct in_addr *ip,void (*fn)())
+{
+ BOOL found=False;
+ int retries = 3;
+ int retry_time = bcast?250:2000;
+ struct timeval tval;
+ struct packet_struct p;
+ struct packet_struct *p2;
+ struct nmb_packet *nmb = &p.packet.nmb;
+ static int name_trn_id = 0;
+
+ bzero((char *)&p,sizeof(p));
+
+ if (!name_trn_id) name_trn_id = (time(NULL)%(unsigned)0x7FFF) +
+ (getpid()%(unsigned)100);
+ name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
+
+ nmb->header.name_trn_id = name_trn_id;
+ nmb->header.opcode = 0;
+ nmb->header.response = False;
+ nmb->header.nm_flags.bcast = bcast;
+ nmb->header.nm_flags.recursion_available = False;
+ nmb->header.nm_flags.recursion_desired = True;
+ nmb->header.nm_flags.trunc = False;
+ nmb->header.nm_flags.authoritative = False;
+ nmb->header.rcode = 0;
+ nmb->header.qdcount = 1;
+ nmb->header.ancount = 0;
+ nmb->header.nscount = 0;
+ nmb->header.arcount = 0;
+
+ make_nmb_name(&nmb->question.question_name,name,name_type,scope);
+
+ nmb->question.question_type = 0x20;
+ nmb->question.question_class = 0x1;
+
+ p.ip = to_ip;
+ p.port = NMB_PORT;
+ p.fd = fd;
+ p.timestamp = time(NULL);
+ p.packet_type = NMB_PACKET;
+
+ GetTimeOfDay(&tval);
+
+ if (!send_packet(&p))
+ return(False);
+
+ retries--;
+
+ while (1)
+ {
+ struct timeval tval2;
+ GetTimeOfDay(&tval2);
+ if (TvalDiff(&tval,&tval2) > retry_time) {
+ if (!retries) break;
+ if (!found && !send_packet(&p))
+ return False;
+ GetTimeOfDay(&tval);
+ retries--;
+ }
+
+ if ((p2=receive_packet(fd,NMB_PACKET,90)))
+ {
+ struct nmb_packet *nmb2 = &p2->packet.nmb;
+ debug_nmb_packet(p2);
+
+ if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
+ !nmb2->header.response) {
+ /* its not for us - maybe deal with it later
+ (put it on the queue?) */
+ if (fn)
+ fn(p2);
+ else
+ free_packet(p2);
+ continue;
+ }
+
+ if (nmb2->header.opcode != 0 ||
+ nmb2->header.nm_flags.bcast ||
+ nmb2->header.rcode ||
+ !nmb2->header.ancount) {
+ /* XXXX what do we do with this? could be a redirect, but
+ we'll discard it for the moment */
+ free_packet(p2);
+ continue;
+ }
+
+ if (ip) {
+ putip((char *)ip,&nmb2->answers->rdata[2]);
+ DEBUG(fn?3:2,("Got a positive name query response from %s",
+ inet_ntoa(p2->ip)));
+ DEBUG(fn?3:2,(" (%s)\n",inet_ntoa(*ip)));
+ }
+ found=True; retries=0;
+ free_packet(p2);
+ if (fn) break;
+ }
+ }
+
+ return(found);
+}
diff --git a/source/libsmb/nmblib.c b/source/libsmb/nmblib.c
index 67432271737..6a91b20ea87 100644
--- a/source/libsmb/nmblib.c
+++ b/source/libsmb/nmblib.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
NBT netbios library routines
- Copyright (C) Andrew Tridgell 1994-1995
+ Copyright (C) Andrew Tridgell 1994-1997
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
@@ -21,15 +21,131 @@
*/
#include "includes.h"
-#include "nameserv.h"
extern int DEBUGLEVEL;
-int num_good_sends=0;
-int num_good_receives=0;
-static uint16 name_trn_id = 0;
-BOOL CanRecurse = True;
+int num_good_sends = 0;
+int num_good_receives = 0;
extern pstring scope;
+extern pstring myname;
+extern struct in_addr ipzero;
+
+static struct opcode_names {
+ char *nmb_opcode_name;
+ int opcode;
+} nmb_header_opcode_names[] = {
+ { "Query", 0 },
+ {"Registration", 5 },
+ {"Release", 6 },
+ {"WACK", 7 },
+ {"refresh", 8 },
+ {0, -1 }
+};
+
+/****************************************************************************
+ * Lookup a nmb opcode name.
+ ****************************************************************************/
+
+char *lookup_opcode_name( int opcode )
+{
+ struct opcode_names *op_namep;
+ int i;
+
+ for(i = 0; nmb_header_opcode_names[i].nmb_opcode_name != 0; i++) {
+ op_namep = &nmb_header_opcode_names[i];
+ if(opcode == op_namep->opcode)
+ return op_namep->nmb_opcode_name;
+ }
+ return "<unknown opcode>";
+}
+
+/****************************************************************************
+ 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(%d) header: id=%d opcode=%s(%d) response=%s\n",
+ inet_ntoa(p->ip), p->port,
+ nmb->header.name_trn_id,
+ lookup_opcode_name(nmb->header.opcode),
+ 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 +154,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 +170,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 +301,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);
@@ -304,6 +418,9 @@ static BOOL parse_nmb(char *inbuf,int length,struct nmb_packet *nmb)
/* parse the header */
nmb->header.name_trn_id = RSVAL(inbuf,0);
+
+ DEBUG(10,("parse_nmb: packet id = %d\n", nmb->header.name_trn_id));
+
nmb->header.opcode = (CVAL(inbuf,2) >> 3) & 0xF;
nmb->header.response = ((CVAL(inbuf,2)>>7)&1)?True:False;
nm_flags = ((CVAL(inbuf,2) & 0x7) << 4) + (CVAL(inbuf,3)>>4);
@@ -311,7 +428,7 @@ static BOOL parse_nmb(char *inbuf,int length,struct nmb_packet *nmb)
nmb->header.nm_flags.recursion_available = (nm_flags&8)?True:False;
nmb->header.nm_flags.recursion_desired = (nm_flags&0x10)?True:False;
nmb->header.nm_flags.trunc = (nm_flags&0x20)?True:False;
- nmb->header.nm_flags.authoritative = (nm_flags&0x40)?True:False;
+ nmb->header.nm_flags.authoritative = (nm_flags&0x40)?True:False;
nmb->header.rcode = CVAL(inbuf,3) & 0xF;
nmb->header.qdcount = RSVAL(inbuf,4);
nmb->header.ancount = RSVAL(inbuf,6);
@@ -365,9 +482,11 @@ void free_nmb_packet(struct nmb_packet *nmb)
******************************************************************/
void free_packet(struct packet_struct *packet)
{
- if (packet->packet_type == NMB_PACKET)
- free_nmb_packet(&packet->packet.nmb);
- free(packet);
+ if (packet->locked)
+ return;
+ if (packet->packet_type == NMB_PACKET)
+ free_nmb_packet(&packet->packet.nmb);
+ free(packet);
}
/*******************************************************************
@@ -382,7 +501,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);
@@ -394,6 +513,7 @@ struct packet_struct *read_packet(int fd,enum packet_type packet_type)
packet->ip = lastip;
packet->port = lastport;
packet->fd = fd;
+ packet->locked = False;
packet->timestamp = time(NULL);
packet->packet_type = packet_type;
switch (packet_type)
@@ -407,13 +527,15 @@ struct packet_struct *read_packet(int fd,enum packet_type packet_type)
break;
}
if (!ok) {
+ DEBUG(10,("parse_nmb: discarding packet id = %d\n",
+ packet->packet.nmb.header.name_trn_id));
free(packet);
return(NULL);
}
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 +556,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,
@@ -497,10 +619,10 @@ static int build_dgram(char *buf,struct packet_struct *p)
******************************************************************/
void make_nmb_name(struct nmb_name *n,char *name,int type,char *this_scope)
{
- strcpy(n->name,name);
+ fstrcpy(n->name,name);
strupper(n->name);
n->name_type = type;
- strcpy(n->scope,this_scope);
+ fstrcpy(n->scope,this_scope);
}
@@ -522,12 +644,15 @@ static int build_nmb(char *buf,struct packet_struct *p)
RSSVAL(ubuf,offset,nmb->header.name_trn_id);
ubuf[offset+2] = (nmb->header.opcode & 0xF) << 3;
if (nmb->header.response) ubuf[offset+2] |= (1<<7);
- if (nmb->header.nm_flags.authoritative) ubuf[offset+2] |= 0x4;
+ if (nmb->header.nm_flags.authoritative &&
+ nmb->header.response) ubuf[offset+2] |= 0x4;
if (nmb->header.nm_flags.trunc) ubuf[offset+2] |= 0x2;
if (nmb->header.nm_flags.recursion_desired) ubuf[offset+2] |= 0x1;
- if (nmb->header.nm_flags.recursion_available) ubuf[offset+3] |= 0x80;
+ if (nmb->header.nm_flags.recursion_available &&
+ nmb->header.response) ubuf[offset+3] |= 0x80;
if (nmb->header.nm_flags.bcast) ubuf[offset+3] |= 0x10;
ubuf[offset+3] |= (nmb->header.rcode & 0xF);
+
RSSVAL(ubuf,offset+4,nmb->header.qdcount);
RSSVAL(ubuf,offset+6,nmb->header.ancount);
RSSVAL(ubuf,offset+8,nmb->header.nscount);
@@ -572,6 +697,7 @@ BOOL send_packet(struct packet_struct *p)
{
case NMB_PACKET:
len = build_nmb(buf,p);
+ debug_nmb_packet(p);
break;
case DGRAM_PACKET:
@@ -607,330 +733,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/nterr.c b/source/libsmb/nterr.c
new file mode 100644
index 00000000000..bda0f882a64
--- /dev/null
+++ b/source/libsmb/nterr.c
@@ -0,0 +1,514 @@
+
+#include "nterr.h"
+
+static struct
+{
+ char *nt_errstr;
+ uint16 nt_errcode;
+
+} nt_errs[] =
+{
+ { "NT_STATUS_UNSUCCESSFUL", NT_STATUS_UNSUCCESSFUL },
+ { "NT_STATUS_NOT_IMPLEMENTED", NT_STATUS_NOT_IMPLEMENTED },
+ { "NT_STATUS_INVALID_INFO_CLASS", NT_STATUS_INVALID_INFO_CLASS },
+ { "NT_STATUS_INFO_LENGTH_MISMATCH", NT_STATUS_INFO_LENGTH_MISMATCH },
+ { "NT_STATUS_ACCESS_VIOLATION", NT_STATUS_ACCESS_VIOLATION },
+ { "NT_STATUS_IN_PAGE_ERROR", NT_STATUS_IN_PAGE_ERROR },
+ { "NT_STATUS_PAGEFILE_QUOTA", NT_STATUS_PAGEFILE_QUOTA },
+ { "NT_STATUS_INVALID_HANDLE", NT_STATUS_INVALID_HANDLE },
+ { "NT_STATUS_BAD_INITIAL_STACK", NT_STATUS_BAD_INITIAL_STACK },
+ { "NT_STATUS_BAD_INITIAL_PC", NT_STATUS_BAD_INITIAL_PC },
+ { "NT_STATUS_INVALID_CID", NT_STATUS_INVALID_CID },
+ { "NT_STATUS_TIMER_NOT_CANCELED", NT_STATUS_TIMER_NOT_CANCELED },
+ { "NT_STATUS_INVALID_PARAMETER", NT_STATUS_INVALID_PARAMETER },
+ { "NT_STATUS_NO_SUCH_DEVICE", NT_STATUS_NO_SUCH_DEVICE },
+ { "NT_STATUS_NO_SUCH_FILE", NT_STATUS_NO_SUCH_FILE },
+ { "NT_STATUS_INVALID_DEVICE_REQUEST", NT_STATUS_INVALID_DEVICE_REQUEST },
+ { "NT_STATUS_END_OF_FILE", NT_STATUS_END_OF_FILE },
+ { "NT_STATUS_WRONG_VOLUME", NT_STATUS_WRONG_VOLUME },
+ { "NT_STATUS_NO_MEDIA_IN_DEVICE", NT_STATUS_NO_MEDIA_IN_DEVICE },
+ { "NT_STATUS_UNRECOGNIZED_MEDIA", NT_STATUS_UNRECOGNIZED_MEDIA },
+ { "NT_STATUS_NONEXISTENT_SECTOR", NT_STATUS_NONEXISTENT_SECTOR },
+ { "NT_STATUS_MORE_PROCESSING_REQUIRED", NT_STATUS_MORE_PROCESSING_REQUIRED },
+ { "NT_STATUS_NO_MEMORY", NT_STATUS_NO_MEMORY },
+ { "NT_STATUS_CONFLICTING_ADDRESSES", NT_STATUS_CONFLICTING_ADDRESSES },
+ { "NT_STATUS_NOT_MAPPED_VIEW", NT_STATUS_NOT_MAPPED_VIEW },
+ { "NT_STATUS_UNABLE_TO_FREE_VM", NT_STATUS_UNABLE_TO_FREE_VM },
+ { "NT_STATUS_UNABLE_TO_DELETE_SECTION", NT_STATUS_UNABLE_TO_DELETE_SECTION },
+ { "NT_STATUS_INVALID_SYSTEM_SERVICE", NT_STATUS_INVALID_SYSTEM_SERVICE },
+ { "NT_STATUS_ILLEGAL_INSTRUCTION", NT_STATUS_ILLEGAL_INSTRUCTION },
+ { "NT_STATUS_INVALID_LOCK_SEQUENCE", NT_STATUS_INVALID_LOCK_SEQUENCE },
+ { "NT_STATUS_INVALID_VIEW_SIZE", NT_STATUS_INVALID_VIEW_SIZE },
+ { "NT_STATUS_INVALID_FILE_FOR_SECTION", NT_STATUS_INVALID_FILE_FOR_SECTION },
+ { "NT_STATUS_ALREADY_COMMITTED", NT_STATUS_ALREADY_COMMITTED },
+ { "NT_STATUS_ACCESS_DENIED", NT_STATUS_ACCESS_DENIED },
+ { "NT_STATUS_BUFFER_TOO_SMALL", NT_STATUS_BUFFER_TOO_SMALL },
+ { "NT_STATUS_OBJECT_TYPE_MISMATCH", NT_STATUS_OBJECT_TYPE_MISMATCH },
+ { "NT_STATUS_NONCONTINUABLE_EXCEPTION", NT_STATUS_NONCONTINUABLE_EXCEPTION },
+ { "NT_STATUS_INVALID_DISPOSITION", NT_STATUS_INVALID_DISPOSITION },
+ { "NT_STATUS_UNWIND", NT_STATUS_UNWIND },
+ { "NT_STATUS_BAD_STACK", NT_STATUS_BAD_STACK },
+ { "NT_STATUS_INVALID_UNWIND_TARGET", NT_STATUS_INVALID_UNWIND_TARGET },
+ { "NT_STATUS_NOT_LOCKED", NT_STATUS_NOT_LOCKED },
+ { "NT_STATUS_PARITY_ERROR", NT_STATUS_PARITY_ERROR },
+ { "NT_STATUS_UNABLE_TO_DECOMMIT_VM", NT_STATUS_UNABLE_TO_DECOMMIT_VM },
+ { "NT_STATUS_NOT_COMMITTED", NT_STATUS_NOT_COMMITTED },
+ { "NT_STATUS_INVALID_PORT_ATTRIBUTES", NT_STATUS_INVALID_PORT_ATTRIBUTES },
+ { "NT_STATUS_PORT_MESSAGE_TOO_LONG", NT_STATUS_PORT_MESSAGE_TOO_LONG },
+ { "NT_STATUS_INVALID_PARAMETER_MIX", NT_STATUS_INVALID_PARAMETER_MIX },
+ { "NT_STATUS_INVALID_QUOTA_LOWER", NT_STATUS_INVALID_QUOTA_LOWER },
+ { "NT_STATUS_DISK_CORRUPT_ERROR", NT_STATUS_DISK_CORRUPT_ERROR },
+ { "NT_STATUS_OBJECT_NAME_INVALID", NT_STATUS_OBJECT_NAME_INVALID },
+ { "NT_STATUS_OBJECT_NAME_NOT_FOUND", NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ { "NT_STATUS_OBJECT_NAME_COLLISION", NT_STATUS_OBJECT_NAME_COLLISION },
+ { "NT_STATUS_HANDLE_NOT_WAITABLE", NT_STATUS_HANDLE_NOT_WAITABLE },
+ { "NT_STATUS_PORT_DISCONNECTED", NT_STATUS_PORT_DISCONNECTED },
+ { "NT_STATUS_DEVICE_ALREADY_ATTACHED", NT_STATUS_DEVICE_ALREADY_ATTACHED },
+ { "NT_STATUS_OBJECT_PATH_INVALID", NT_STATUS_OBJECT_PATH_INVALID },
+ { "NT_STATUS_OBJECT_PATH_NOT_FOUND", NT_STATUS_OBJECT_PATH_NOT_FOUND },
+ { "NT_STATUS_OBJECT_PATH_SYNTAX_BAD", NT_STATUS_OBJECT_PATH_SYNTAX_BAD },
+ { "NT_STATUS_DATA_OVERRUN", NT_STATUS_DATA_OVERRUN },
+ { "NT_STATUS_DATA_LATE_ERROR", NT_STATUS_DATA_LATE_ERROR },
+ { "NT_STATUS_DATA_ERROR", NT_STATUS_DATA_ERROR },
+ { "NT_STATUS_CRC_ERROR", NT_STATUS_CRC_ERROR },
+ { "NT_STATUS_SECTION_TOO_BIG", NT_STATUS_SECTION_TOO_BIG },
+ { "NT_STATUS_PORT_CONNECTION_REFUSED", NT_STATUS_PORT_CONNECTION_REFUSED },
+ { "NT_STATUS_INVALID_PORT_HANDLE", NT_STATUS_INVALID_PORT_HANDLE },
+ { "NT_STATUS_SHARING_VIOLATION", NT_STATUS_SHARING_VIOLATION },
+ { "NT_STATUS_QUOTA_EXCEEDED", NT_STATUS_QUOTA_EXCEEDED },
+ { "NT_STATUS_INVALID_PAGE_PROTECTION", NT_STATUS_INVALID_PAGE_PROTECTION },
+ { "NT_STATUS_MUTANT_NOT_OWNED", NT_STATUS_MUTANT_NOT_OWNED },
+ { "NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED", NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED },
+ { "NT_STATUS_PORT_ALREADY_SET", NT_STATUS_PORT_ALREADY_SET },
+ { "NT_STATUS_SECTION_NOT_IMAGE", NT_STATUS_SECTION_NOT_IMAGE },
+ { "NT_STATUS_SUSPEND_COUNT_EXCEEDED", NT_STATUS_SUSPEND_COUNT_EXCEEDED },
+ { "NT_STATUS_THREAD_IS_TERMINATING", NT_STATUS_THREAD_IS_TERMINATING },
+ { "NT_STATUS_BAD_WORKING_SET_LIMIT", NT_STATUS_BAD_WORKING_SET_LIMIT },
+ { "NT_STATUS_INCOMPATIBLE_FILE_MAP", NT_STATUS_INCOMPATIBLE_FILE_MAP },
+ { "NT_STATUS_SECTION_PROTECTION", NT_STATUS_SECTION_PROTECTION },
+ { "NT_STATUS_EAS_NOT_SUPPORTED", NT_STATUS_EAS_NOT_SUPPORTED },
+ { "NT_STATUS_EA_TOO_LARGE", NT_STATUS_EA_TOO_LARGE },
+ { "NT_STATUS_NONEXISTENT_EA_ENTRY", NT_STATUS_NONEXISTENT_EA_ENTRY },
+ { "NT_STATUS_NO_EAS_ON_FILE", NT_STATUS_NO_EAS_ON_FILE },
+ { "NT_STATUS_EA_CORRUPT_ERROR", NT_STATUS_EA_CORRUPT_ERROR },
+ { "NT_STATUS_FILE_LOCK_CONFLICT", NT_STATUS_FILE_LOCK_CONFLICT },
+ { "NT_STATUS_LOCK_NOT_GRANTED", NT_STATUS_LOCK_NOT_GRANTED },
+ { "NT_STATUS_DELETE_PENDING", NT_STATUS_DELETE_PENDING },
+ { "NT_STATUS_CTL_FILE_NOT_SUPPORTED", NT_STATUS_CTL_FILE_NOT_SUPPORTED },
+ { "NT_STATUS_UNKNOWN_REVISION", NT_STATUS_UNKNOWN_REVISION },
+ { "NT_STATUS_REVISION_MISMATCH", NT_STATUS_REVISION_MISMATCH },
+ { "NT_STATUS_INVALID_OWNER", NT_STATUS_INVALID_OWNER },
+ { "NT_STATUS_INVALID_PRIMARY_GROUP", NT_STATUS_INVALID_PRIMARY_GROUP },
+ { "NT_STATUS_NO_IMPERSONATION_TOKEN", NT_STATUS_NO_IMPERSONATION_TOKEN },
+ { "NT_STATUS_CANT_DISABLE_MANDATORY", NT_STATUS_CANT_DISABLE_MANDATORY },
+ { "NT_STATUS_NO_LOGON_SERVERS", NT_STATUS_NO_LOGON_SERVERS },
+ { "NT_STATUS_NO_SUCH_LOGON_SESSION", NT_STATUS_NO_SUCH_LOGON_SESSION },
+ { "NT_STATUS_NO_SUCH_PRIVILEGE", NT_STATUS_NO_SUCH_PRIVILEGE },
+ { "NT_STATUS_PRIVILEGE_NOT_HELD", NT_STATUS_PRIVILEGE_NOT_HELD },
+ { "NT_STATUS_INVALID_ACCOUNT_NAME", NT_STATUS_INVALID_ACCOUNT_NAME },
+ { "NT_STATUS_USER_EXISTS", NT_STATUS_USER_EXISTS },
+ { "NT_STATUS_NO_SUCH_USER", NT_STATUS_NO_SUCH_USER },
+ { "NT_STATUS_GROUP_EXISTS", NT_STATUS_GROUP_EXISTS },
+ { "NT_STATUS_NO_SUCH_GROUP", NT_STATUS_NO_SUCH_GROUP },
+ { "NT_STATUS_MEMBER_IN_GROUP", NT_STATUS_MEMBER_IN_GROUP },
+ { "NT_STATUS_MEMBER_NOT_IN_GROUP", NT_STATUS_MEMBER_NOT_IN_GROUP },
+ { "NT_STATUS_LAST_ADMIN", NT_STATUS_LAST_ADMIN },
+ { "NT_STATUS_WRONG_PASSWORD", NT_STATUS_WRONG_PASSWORD },
+ { "NT_STATUS_ILL_FORMED_PASSWORD", NT_STATUS_ILL_FORMED_PASSWORD },
+ { "NT_STATUS_PASSWORD_RESTRICTION", NT_STATUS_PASSWORD_RESTRICTION },
+ { "NT_STATUS_LOGON_FAILURE", NT_STATUS_LOGON_FAILURE },
+ { "NT_STATUS_ACCOUNT_RESTRICTION", NT_STATUS_ACCOUNT_RESTRICTION },
+ { "NT_STATUS_INVALID_LOGON_HOURS", NT_STATUS_INVALID_LOGON_HOURS },
+ { "NT_STATUS_INVALID_WORKSTATION", NT_STATUS_INVALID_WORKSTATION },
+ { "NT_STATUS_PASSWORD_EXPIRED", NT_STATUS_PASSWORD_EXPIRED },
+ { "NT_STATUS_ACCOUNT_DISABLED", NT_STATUS_ACCOUNT_DISABLED },
+ { "NT_STATUS_NONE_MAPPED", NT_STATUS_NONE_MAPPED },
+ { "NT_STATUS_TOO_MANY_LUIDS_REQUESTED", NT_STATUS_TOO_MANY_LUIDS_REQUESTED },
+ { "NT_STATUS_LUIDS_EXHAUSTED", NT_STATUS_LUIDS_EXHAUSTED },
+ { "NT_STATUS_INVALID_SUB_AUTHORITY", NT_STATUS_INVALID_SUB_AUTHORITY },
+ { "NT_STATUS_INVALID_ACL", NT_STATUS_INVALID_ACL },
+ { "NT_STATUS_INVALID_SID", NT_STATUS_INVALID_SID },
+ { "NT_STATUS_INVALID_SECURITY_DESCR", NT_STATUS_INVALID_SECURITY_DESCR },
+ { "NT_STATUS_PROCEDURE_NOT_FOUND", NT_STATUS_PROCEDURE_NOT_FOUND },
+ { "NT_STATUS_INVALID_IMAGE_FORMAT", NT_STATUS_INVALID_IMAGE_FORMAT },
+ { "NT_STATUS_NO_TOKEN", NT_STATUS_NO_TOKEN },
+ { "NT_STATUS_BAD_INHERITANCE_ACL", NT_STATUS_BAD_INHERITANCE_ACL },
+ { "NT_STATUS_RANGE_NOT_LOCKED", NT_STATUS_RANGE_NOT_LOCKED },
+ { "NT_STATUS_DISK_FULL", NT_STATUS_DISK_FULL },
+ { "NT_STATUS_SERVER_DISABLED", NT_STATUS_SERVER_DISABLED },
+ { "NT_STATUS_SERVER_NOT_DISABLED", NT_STATUS_SERVER_NOT_DISABLED },
+ { "NT_STATUS_TOO_MANY_GUIDS_REQUESTED", NT_STATUS_TOO_MANY_GUIDS_REQUESTED },
+ { "NT_STATUS_GUIDS_EXHAUSTED", NT_STATUS_GUIDS_EXHAUSTED },
+ { "NT_STATUS_INVALID_ID_AUTHORITY", NT_STATUS_INVALID_ID_AUTHORITY },
+ { "NT_STATUS_AGENTS_EXHAUSTED", NT_STATUS_AGENTS_EXHAUSTED },
+ { "NT_STATUS_INVALID_VOLUME_LABEL", NT_STATUS_INVALID_VOLUME_LABEL },
+ { "NT_STATUS_SECTION_NOT_EXTENDED", NT_STATUS_SECTION_NOT_EXTENDED },
+ { "NT_STATUS_NOT_MAPPED_DATA", NT_STATUS_NOT_MAPPED_DATA },
+ { "NT_STATUS_RESOURCE_DATA_NOT_FOUND", NT_STATUS_RESOURCE_DATA_NOT_FOUND },
+ { "NT_STATUS_RESOURCE_TYPE_NOT_FOUND", NT_STATUS_RESOURCE_TYPE_NOT_FOUND },
+ { "NT_STATUS_RESOURCE_NAME_NOT_FOUND", NT_STATUS_RESOURCE_NAME_NOT_FOUND },
+ { "NT_STATUS_ARRAY_BOUNDS_EXCEEDED", NT_STATUS_ARRAY_BOUNDS_EXCEEDED },
+ { "NT_STATUS_FLOAT_DENORMAL_OPERAND", NT_STATUS_FLOAT_DENORMAL_OPERAND },
+ { "NT_STATUS_FLOAT_DIVIDE_BY_ZERO", NT_STATUS_FLOAT_DIVIDE_BY_ZERO },
+ { "NT_STATUS_FLOAT_INEXACT_RESULT", NT_STATUS_FLOAT_INEXACT_RESULT },
+ { "NT_STATUS_FLOAT_INVALID_OPERATION", NT_STATUS_FLOAT_INVALID_OPERATION },
+ { "NT_STATUS_FLOAT_OVERFLOW", NT_STATUS_FLOAT_OVERFLOW },
+ { "NT_STATUS_FLOAT_STACK_CHECK", NT_STATUS_FLOAT_STACK_CHECK },
+ { "NT_STATUS_FLOAT_UNDERFLOW", NT_STATUS_FLOAT_UNDERFLOW },
+ { "NT_STATUS_INTEGER_DIVIDE_BY_ZERO", NT_STATUS_INTEGER_DIVIDE_BY_ZERO },
+ { "NT_STATUS_INTEGER_OVERFLOW", NT_STATUS_INTEGER_OVERFLOW },
+ { "NT_STATUS_PRIVILEGED_INSTRUCTION", NT_STATUS_PRIVILEGED_INSTRUCTION },
+ { "NT_STATUS_TOO_MANY_PAGING_FILES", NT_STATUS_TOO_MANY_PAGING_FILES },
+ { "NT_STATUS_FILE_INVALID", NT_STATUS_FILE_INVALID },
+ { "NT_STATUS_ALLOTTED_SPACE_EXCEEDED", NT_STATUS_ALLOTTED_SPACE_EXCEEDED },
+ { "NT_STATUS_INSUFFICIENT_RESOURCES", NT_STATUS_INSUFFICIENT_RESOURCES },
+ { "NT_STATUS_DFS_EXIT_PATH_FOUND", NT_STATUS_DFS_EXIT_PATH_FOUND },
+ { "NT_STATUS_DEVICE_DATA_ERROR", NT_STATUS_DEVICE_DATA_ERROR },
+ { "NT_STATUS_DEVICE_NOT_CONNECTED", NT_STATUS_DEVICE_NOT_CONNECTED },
+ { "NT_STATUS_DEVICE_POWER_FAILURE", NT_STATUS_DEVICE_POWER_FAILURE },
+ { "NT_STATUS_FREE_VM_NOT_AT_BASE", NT_STATUS_FREE_VM_NOT_AT_BASE },
+ { "NT_STATUS_MEMORY_NOT_ALLOCATED", NT_STATUS_MEMORY_NOT_ALLOCATED },
+ { "NT_STATUS_WORKING_SET_QUOTA", NT_STATUS_WORKING_SET_QUOTA },
+ { "NT_STATUS_MEDIA_WRITE_PROTECTED", NT_STATUS_MEDIA_WRITE_PROTECTED },
+ { "NT_STATUS_DEVICE_NOT_READY", NT_STATUS_DEVICE_NOT_READY },
+ { "NT_STATUS_INVALID_GROUP_ATTRIBUTES", NT_STATUS_INVALID_GROUP_ATTRIBUTES },
+ { "NT_STATUS_BAD_IMPERSONATION_LEVEL", NT_STATUS_BAD_IMPERSONATION_LEVEL },
+ { "NT_STATUS_CANT_OPEN_ANONYMOUS", NT_STATUS_CANT_OPEN_ANONYMOUS },
+ { "NT_STATUS_BAD_VALIDATION_CLASS", NT_STATUS_BAD_VALIDATION_CLASS },
+ { "NT_STATUS_BAD_TOKEN_TYPE", NT_STATUS_BAD_TOKEN_TYPE },
+ { "NT_STATUS_BAD_MASTER_BOOT_RECORD", NT_STATUS_BAD_MASTER_BOOT_RECORD },
+ { "NT_STATUS_INSTRUCTION_MISALIGNMENT", NT_STATUS_INSTRUCTION_MISALIGNMENT },
+ { "NT_STATUS_INSTANCE_NOT_AVAILABLE", NT_STATUS_INSTANCE_NOT_AVAILABLE },
+ { "NT_STATUS_PIPE_NOT_AVAILABLE", NT_STATUS_PIPE_NOT_AVAILABLE },
+ { "NT_STATUS_INVALID_PIPE_STATE", NT_STATUS_INVALID_PIPE_STATE },
+ { "NT_STATUS_PIPE_BUSY", NT_STATUS_PIPE_BUSY },
+ { "NT_STATUS_ILLEGAL_FUNCTION", NT_STATUS_ILLEGAL_FUNCTION },
+ { "NT_STATUS_PIPE_DISCONNECTED", NT_STATUS_PIPE_DISCONNECTED },
+ { "NT_STATUS_PIPE_CLOSING", NT_STATUS_PIPE_CLOSING },
+ { "NT_STATUS_PIPE_CONNECTED", NT_STATUS_PIPE_CONNECTED },
+ { "NT_STATUS_PIPE_LISTENING", NT_STATUS_PIPE_LISTENING },
+ { "NT_STATUS_INVALID_READ_MODE", NT_STATUS_INVALID_READ_MODE },
+ { "NT_STATUS_IO_TIMEOUT", NT_STATUS_IO_TIMEOUT },
+ { "NT_STATUS_FILE_FORCED_CLOSED", NT_STATUS_FILE_FORCED_CLOSED },
+ { "NT_STATUS_PROFILING_NOT_STARTED", NT_STATUS_PROFILING_NOT_STARTED },
+ { "NT_STATUS_PROFILING_NOT_STOPPED", NT_STATUS_PROFILING_NOT_STOPPED },
+ { "NT_STATUS_COULD_NOT_INTERPRET", NT_STATUS_COULD_NOT_INTERPRET },
+ { "NT_STATUS_FILE_IS_A_DIRECTORY", NT_STATUS_FILE_IS_A_DIRECTORY },
+ { "NT_STATUS_NOT_SUPPORTED", NT_STATUS_NOT_SUPPORTED },
+ { "NT_STATUS_REMOTE_NOT_LISTENING", NT_STATUS_REMOTE_NOT_LISTENING },
+ { "NT_STATUS_DUPLICATE_NAME", NT_STATUS_DUPLICATE_NAME },
+ { "NT_STATUS_BAD_NETWORK_PATH", NT_STATUS_BAD_NETWORK_PATH },
+ { "NT_STATUS_NETWORK_BUSY", NT_STATUS_NETWORK_BUSY },
+ { "NT_STATUS_DEVICE_DOES_NOT_EXIST", NT_STATUS_DEVICE_DOES_NOT_EXIST },
+ { "NT_STATUS_TOO_MANY_COMMANDS", NT_STATUS_TOO_MANY_COMMANDS },
+ { "NT_STATUS_ADAPTER_HARDWARE_ERROR", NT_STATUS_ADAPTER_HARDWARE_ERROR },
+ { "NT_STATUS_INVALID_NETWORK_RESPONSE", NT_STATUS_INVALID_NETWORK_RESPONSE },
+ { "NT_STATUS_UNEXPECTED_NETWORK_ERROR", NT_STATUS_UNEXPECTED_NETWORK_ERROR },
+ { "NT_STATUS_BAD_REMOTE_ADAPTER", NT_STATUS_BAD_REMOTE_ADAPTER },
+ { "NT_STATUS_PRINT_QUEUE_FULL", NT_STATUS_PRINT_QUEUE_FULL },
+ { "NT_STATUS_NO_SPOOL_SPACE", NT_STATUS_NO_SPOOL_SPACE },
+ { "NT_STATUS_PRINT_CANCELLED", NT_STATUS_PRINT_CANCELLED },
+ { "NT_STATUS_NETWORK_NAME_DELETED", NT_STATUS_NETWORK_NAME_DELETED },
+ { "NT_STATUS_NETWORK_ACCESS_DENIED", NT_STATUS_NETWORK_ACCESS_DENIED },
+ { "NT_STATUS_BAD_DEVICE_TYPE", NT_STATUS_BAD_DEVICE_TYPE },
+ { "NT_STATUS_BAD_NETWORK_NAME", NT_STATUS_BAD_NETWORK_NAME },
+ { "NT_STATUS_TOO_MANY_NAMES", NT_STATUS_TOO_MANY_NAMES },
+ { "NT_STATUS_TOO_MANY_SESSIONS", NT_STATUS_TOO_MANY_SESSIONS },
+ { "NT_STATUS_SHARING_PAUSED", NT_STATUS_SHARING_PAUSED },
+ { "NT_STATUS_REQUEST_NOT_ACCEPTED", NT_STATUS_REQUEST_NOT_ACCEPTED },
+ { "NT_STATUS_REDIRECTOR_PAUSED", NT_STATUS_REDIRECTOR_PAUSED },
+ { "NT_STATUS_NET_WRITE_FAULT", NT_STATUS_NET_WRITE_FAULT },
+ { "NT_STATUS_PROFILING_AT_LIMIT", NT_STATUS_PROFILING_AT_LIMIT },
+ { "NT_STATUS_NOT_SAME_DEVICE", NT_STATUS_NOT_SAME_DEVICE },
+ { "NT_STATUS_FILE_RENAMED", NT_STATUS_FILE_RENAMED },
+ { "NT_STATUS_VIRTUAL_CIRCUIT_CLOSED", NT_STATUS_VIRTUAL_CIRCUIT_CLOSED },
+ { "NT_STATUS_NO_SECURITY_ON_OBJECT", NT_STATUS_NO_SECURITY_ON_OBJECT },
+ { "NT_STATUS_CANT_WAIT", NT_STATUS_CANT_WAIT },
+ { "NT_STATUS_PIPE_EMPTY", NT_STATUS_PIPE_EMPTY },
+ { "NT_STATUS_CANT_ACCESS_DOMAIN_INFO", NT_STATUS_CANT_ACCESS_DOMAIN_INFO },
+ { "NT_STATUS_CANT_TERMINATE_SELF", NT_STATUS_CANT_TERMINATE_SELF },
+ { "NT_STATUS_INVALID_SERVER_STATE", NT_STATUS_INVALID_SERVER_STATE },
+ { "NT_STATUS_INVALID_DOMAIN_STATE", NT_STATUS_INVALID_DOMAIN_STATE },
+ { "NT_STATUS_INVALID_DOMAIN_ROLE", NT_STATUS_INVALID_DOMAIN_ROLE },
+ { "NT_STATUS_NO_SUCH_DOMAIN", NT_STATUS_NO_SUCH_DOMAIN },
+ { "NT_STATUS_DOMAIN_EXISTS", NT_STATUS_DOMAIN_EXISTS },
+ { "NT_STATUS_DOMAIN_LIMIT_EXCEEDED", NT_STATUS_DOMAIN_LIMIT_EXCEEDED },
+ { "NT_STATUS_OPLOCK_NOT_GRANTED", NT_STATUS_OPLOCK_NOT_GRANTED },
+ { "NT_STATUS_INVALID_OPLOCK_PROTOCOL", NT_STATUS_INVALID_OPLOCK_PROTOCOL },
+ { "NT_STATUS_INTERNAL_DB_CORRUPTION", NT_STATUS_INTERNAL_DB_CORRUPTION },
+ { "NT_STATUS_INTERNAL_ERROR", NT_STATUS_INTERNAL_ERROR },
+ { "NT_STATUS_GENERIC_NOT_MAPPED", NT_STATUS_GENERIC_NOT_MAPPED },
+ { "NT_STATUS_BAD_DESCRIPTOR_FORMAT", NT_STATUS_BAD_DESCRIPTOR_FORMAT },
+ { "NT_STATUS_INVALID_USER_BUFFER", NT_STATUS_INVALID_USER_BUFFER },
+ { "NT_STATUS_UNEXPECTED_IO_ERROR", NT_STATUS_UNEXPECTED_IO_ERROR },
+ { "NT_STATUS_UNEXPECTED_MM_CREATE_ERR", NT_STATUS_UNEXPECTED_MM_CREATE_ERR },
+ { "NT_STATUS_UNEXPECTED_MM_MAP_ERROR", NT_STATUS_UNEXPECTED_MM_MAP_ERROR },
+ { "NT_STATUS_UNEXPECTED_MM_EXTEND_ERR", NT_STATUS_UNEXPECTED_MM_EXTEND_ERR },
+ { "NT_STATUS_NOT_LOGON_PROCESS", NT_STATUS_NOT_LOGON_PROCESS },
+ { "NT_STATUS_LOGON_SESSION_EXISTS", NT_STATUS_LOGON_SESSION_EXISTS },
+ { "NT_STATUS_INVALID_PARAMETER_1", NT_STATUS_INVALID_PARAMETER_1 },
+ { "NT_STATUS_INVALID_PARAMETER_2", NT_STATUS_INVALID_PARAMETER_2 },
+ { "NT_STATUS_INVALID_PARAMETER_3", NT_STATUS_INVALID_PARAMETER_3 },
+ { "NT_STATUS_INVALID_PARAMETER_4", NT_STATUS_INVALID_PARAMETER_4 },
+ { "NT_STATUS_INVALID_PARAMETER_5", NT_STATUS_INVALID_PARAMETER_5 },
+ { "NT_STATUS_INVALID_PARAMETER_6", NT_STATUS_INVALID_PARAMETER_6 },
+ { "NT_STATUS_INVALID_PARAMETER_7", NT_STATUS_INVALID_PARAMETER_7 },
+ { "NT_STATUS_INVALID_PARAMETER_8", NT_STATUS_INVALID_PARAMETER_8 },
+ { "NT_STATUS_INVALID_PARAMETER_9", NT_STATUS_INVALID_PARAMETER_9 },
+ { "NT_STATUS_INVALID_PARAMETER_10", NT_STATUS_INVALID_PARAMETER_10 },
+ { "NT_STATUS_INVALID_PARAMETER_11", NT_STATUS_INVALID_PARAMETER_11 },
+ { "NT_STATUS_INVALID_PARAMETER_12", NT_STATUS_INVALID_PARAMETER_12 },
+ { "NT_STATUS_REDIRECTOR_NOT_STARTED", NT_STATUS_REDIRECTOR_NOT_STARTED },
+ { "NT_STATUS_REDIRECTOR_STARTED", NT_STATUS_REDIRECTOR_STARTED },
+ { "NT_STATUS_STACK_OVERFLOW", NT_STATUS_STACK_OVERFLOW },
+ { "NT_STATUS_NO_SUCH_PACKAGE", NT_STATUS_NO_SUCH_PACKAGE },
+ { "NT_STATUS_BAD_FUNCTION_TABLE", NT_STATUS_BAD_FUNCTION_TABLE },
+ { "NT_STATUS_DIRECTORY_NOT_EMPTY", NT_STATUS_DIRECTORY_NOT_EMPTY },
+ { "NT_STATUS_FILE_CORRUPT_ERROR", NT_STATUS_FILE_CORRUPT_ERROR },
+ { "NT_STATUS_NOT_A_DIRECTORY", NT_STATUS_NOT_A_DIRECTORY },
+ { "NT_STATUS_BAD_LOGON_SESSION_STATE", NT_STATUS_BAD_LOGON_SESSION_STATE },
+ { "NT_STATUS_LOGON_SESSION_COLLISION", NT_STATUS_LOGON_SESSION_COLLISION },
+ { "NT_STATUS_NAME_TOO_LONG", NT_STATUS_NAME_TOO_LONG },
+ { "NT_STATUS_FILES_OPEN", NT_STATUS_FILES_OPEN },
+ { "NT_STATUS_CONNECTION_IN_USE", NT_STATUS_CONNECTION_IN_USE },
+ { "NT_STATUS_MESSAGE_NOT_FOUND", NT_STATUS_MESSAGE_NOT_FOUND },
+ { "NT_STATUS_PROCESS_IS_TERMINATING", NT_STATUS_PROCESS_IS_TERMINATING },
+ { "NT_STATUS_INVALID_LOGON_TYPE", NT_STATUS_INVALID_LOGON_TYPE },
+ { "NT_STATUS_NO_GUID_TRANSLATION", NT_STATUS_NO_GUID_TRANSLATION },
+ { "NT_STATUS_CANNOT_IMPERSONATE", NT_STATUS_CANNOT_IMPERSONATE },
+ { "NT_STATUS_IMAGE_ALREADY_LOADED", NT_STATUS_IMAGE_ALREADY_LOADED },
+ { "NT_STATUS_ABIOS_NOT_PRESENT", NT_STATUS_ABIOS_NOT_PRESENT },
+ { "NT_STATUS_ABIOS_LID_NOT_EXIST", NT_STATUS_ABIOS_LID_NOT_EXIST },
+ { "NT_STATUS_ABIOS_LID_ALREADY_OWNED", NT_STATUS_ABIOS_LID_ALREADY_OWNED },
+ { "NT_STATUS_ABIOS_NOT_LID_OWNER", NT_STATUS_ABIOS_NOT_LID_OWNER },
+ { "NT_STATUS_ABIOS_INVALID_COMMAND", NT_STATUS_ABIOS_INVALID_COMMAND },
+ { "NT_STATUS_ABIOS_INVALID_LID", NT_STATUS_ABIOS_INVALID_LID },
+ { "NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE", NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE },
+ { "NT_STATUS_ABIOS_INVALID_SELECTOR", NT_STATUS_ABIOS_INVALID_SELECTOR },
+ { "NT_STATUS_NO_LDT", NT_STATUS_NO_LDT },
+ { "NT_STATUS_INVALID_LDT_SIZE", NT_STATUS_INVALID_LDT_SIZE },
+ { "NT_STATUS_INVALID_LDT_OFFSET", NT_STATUS_INVALID_LDT_OFFSET },
+ { "NT_STATUS_INVALID_LDT_DESCRIPTOR", NT_STATUS_INVALID_LDT_DESCRIPTOR },
+ { "NT_STATUS_INVALID_IMAGE_NE_FORMAT", NT_STATUS_INVALID_IMAGE_NE_FORMAT },
+ { "NT_STATUS_RXACT_INVALID_STATE", NT_STATUS_RXACT_INVALID_STATE },
+ { "NT_STATUS_RXACT_COMMIT_FAILURE", NT_STATUS_RXACT_COMMIT_FAILURE },
+ { "NT_STATUS_MAPPED_FILE_SIZE_ZERO", NT_STATUS_MAPPED_FILE_SIZE_ZERO },
+ { "NT_STATUS_TOO_MANY_OPENED_FILES", NT_STATUS_TOO_MANY_OPENED_FILES },
+ { "NT_STATUS_CANCELLED", NT_STATUS_CANCELLED },
+ { "NT_STATUS_CANNOT_DELETE", NT_STATUS_CANNOT_DELETE },
+ { "NT_STATUS_INVALID_COMPUTER_NAME", NT_STATUS_INVALID_COMPUTER_NAME },
+ { "NT_STATUS_FILE_DELETED", NT_STATUS_FILE_DELETED },
+ { "NT_STATUS_SPECIAL_ACCOUNT", NT_STATUS_SPECIAL_ACCOUNT },
+ { "NT_STATUS_SPECIAL_GROUP", NT_STATUS_SPECIAL_GROUP },
+ { "NT_STATUS_SPECIAL_USER", NT_STATUS_SPECIAL_USER },
+ { "NT_STATUS_MEMBERS_PRIMARY_GROUP", NT_STATUS_MEMBERS_PRIMARY_GROUP },
+ { "NT_STATUS_FILE_CLOSED", NT_STATUS_FILE_CLOSED },
+ { "NT_STATUS_TOO_MANY_THREADS", NT_STATUS_TOO_MANY_THREADS },
+ { "NT_STATUS_THREAD_NOT_IN_PROCESS", NT_STATUS_THREAD_NOT_IN_PROCESS },
+ { "NT_STATUS_TOKEN_ALREADY_IN_USE", NT_STATUS_TOKEN_ALREADY_IN_USE },
+ { "NT_STATUS_PAGEFILE_QUOTA_EXCEEDED", NT_STATUS_PAGEFILE_QUOTA_EXCEEDED },
+ { "NT_STATUS_COMMITMENT_LIMIT", NT_STATUS_COMMITMENT_LIMIT },
+ { "NT_STATUS_INVALID_IMAGE_LE_FORMAT", NT_STATUS_INVALID_IMAGE_LE_FORMAT },
+ { "NT_STATUS_INVALID_IMAGE_NOT_MZ", NT_STATUS_INVALID_IMAGE_NOT_MZ },
+ { "NT_STATUS_INVALID_IMAGE_PROTECT", NT_STATUS_INVALID_IMAGE_PROTECT },
+ { "NT_STATUS_INVALID_IMAGE_WIN_16", NT_STATUS_INVALID_IMAGE_WIN_16 },
+ { "NT_STATUS_LOGON_SERVER_CONFLICT", NT_STATUS_LOGON_SERVER_CONFLICT },
+ { "NT_STATUS_TIME_DIFFERENCE_AT_DC", NT_STATUS_TIME_DIFFERENCE_AT_DC },
+ { "NT_STATUS_SYNCHRONIZATION_REQUIRED", NT_STATUS_SYNCHRONIZATION_REQUIRED },
+ { "NT_STATUS_DLL_NOT_FOUND", NT_STATUS_DLL_NOT_FOUND },
+ { "NT_STATUS_OPEN_FAILED", NT_STATUS_OPEN_FAILED },
+ { "NT_STATUS_IO_PRIVILEGE_FAILED", NT_STATUS_IO_PRIVILEGE_FAILED },
+ { "NT_STATUS_ORDINAL_NOT_FOUND", NT_STATUS_ORDINAL_NOT_FOUND },
+ { "NT_STATUS_ENTRYPOINT_NOT_FOUND", NT_STATUS_ENTRYPOINT_NOT_FOUND },
+ { "NT_STATUS_CONTROL_C_EXIT", NT_STATUS_CONTROL_C_EXIT },
+ { "NT_STATUS_LOCAL_DISCONNECT", NT_STATUS_LOCAL_DISCONNECT },
+ { "NT_STATUS_REMOTE_DISCONNECT", NT_STATUS_REMOTE_DISCONNECT },
+ { "NT_STATUS_REMOTE_RESOURCES", NT_STATUS_REMOTE_RESOURCES },
+ { "NT_STATUS_LINK_FAILED", NT_STATUS_LINK_FAILED },
+ { "NT_STATUS_LINK_TIMEOUT", NT_STATUS_LINK_TIMEOUT },
+ { "NT_STATUS_INVALID_CONNECTION", NT_STATUS_INVALID_CONNECTION },
+ { "NT_STATUS_INVALID_ADDRESS", NT_STATUS_INVALID_ADDRESS },
+ { "NT_STATUS_DLL_INIT_FAILED", NT_STATUS_DLL_INIT_FAILED },
+ { "NT_STATUS_MISSING_SYSTEMFILE", NT_STATUS_MISSING_SYSTEMFILE },
+ { "NT_STATUS_UNHANDLED_EXCEPTION", NT_STATUS_UNHANDLED_EXCEPTION },
+ { "NT_STATUS_APP_INIT_FAILURE", NT_STATUS_APP_INIT_FAILURE },
+ { "NT_STATUS_PAGEFILE_CREATE_FAILED", NT_STATUS_PAGEFILE_CREATE_FAILED },
+ { "NT_STATUS_NO_PAGEFILE", NT_STATUS_NO_PAGEFILE },
+ { "NT_STATUS_INVALID_LEVEL", NT_STATUS_INVALID_LEVEL },
+ { "NT_STATUS_WRONG_PASSWORD_CORE", NT_STATUS_WRONG_PASSWORD_CORE },
+ { "NT_STATUS_ILLEGAL_FLOAT_CONTEXT", NT_STATUS_ILLEGAL_FLOAT_CONTEXT },
+ { "NT_STATUS_PIPE_BROKEN", NT_STATUS_PIPE_BROKEN },
+ { "NT_STATUS_REGISTRY_CORRUPT", NT_STATUS_REGISTRY_CORRUPT },
+ { "NT_STATUS_REGISTRY_IO_FAILED", NT_STATUS_REGISTRY_IO_FAILED },
+ { "NT_STATUS_NO_EVENT_PAIR", NT_STATUS_NO_EVENT_PAIR },
+ { "NT_STATUS_UNRECOGNIZED_VOLUME", NT_STATUS_UNRECOGNIZED_VOLUME },
+ { "NT_STATUS_SERIAL_NO_DEVICE_INITED", NT_STATUS_SERIAL_NO_DEVICE_INITED },
+ { "NT_STATUS_NO_SUCH_ALIAS", NT_STATUS_NO_SUCH_ALIAS },
+ { "NT_STATUS_MEMBER_NOT_IN_ALIAS", NT_STATUS_MEMBER_NOT_IN_ALIAS },
+ { "NT_STATUS_MEMBER_IN_ALIAS", NT_STATUS_MEMBER_IN_ALIAS },
+ { "NT_STATUS_ALIAS_EXISTS", NT_STATUS_ALIAS_EXISTS },
+ { "NT_STATUS_LOGON_NOT_GRANTED", NT_STATUS_LOGON_NOT_GRANTED },
+ { "NT_STATUS_TOO_MANY_SECRETS", NT_STATUS_TOO_MANY_SECRETS },
+ { "NT_STATUS_SECRET_TOO_LONG", NT_STATUS_SECRET_TOO_LONG },
+ { "NT_STATUS_INTERNAL_DB_ERROR", NT_STATUS_INTERNAL_DB_ERROR },
+ { "NT_STATUS_FULLSCREEN_MODE", NT_STATUS_FULLSCREEN_MODE },
+ { "NT_STATUS_TOO_MANY_CONTEXT_IDS", NT_STATUS_TOO_MANY_CONTEXT_IDS },
+ { "NT_STATUS_LOGON_TYPE_NOT_GRANTED", NT_STATUS_LOGON_TYPE_NOT_GRANTED },
+ { "NT_STATUS_NOT_REGISTRY_FILE", NT_STATUS_NOT_REGISTRY_FILE },
+ { "NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED", NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED },
+ { "NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR", NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR },
+ { "NT_STATUS_FT_MISSING_MEMBER", NT_STATUS_FT_MISSING_MEMBER },
+ { "NT_STATUS_ILL_FORMED_SERVICE_ENTRY", NT_STATUS_ILL_FORMED_SERVICE_ENTRY },
+ { "NT_STATUS_ILLEGAL_CHARACTER", NT_STATUS_ILLEGAL_CHARACTER },
+ { "NT_STATUS_UNMAPPABLE_CHARACTER", NT_STATUS_UNMAPPABLE_CHARACTER },
+ { "NT_STATUS_UNDEFINED_CHARACTER", NT_STATUS_UNDEFINED_CHARACTER },
+ { "NT_STATUS_FLOPPY_VOLUME", NT_STATUS_FLOPPY_VOLUME },
+ { "NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND", NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND },
+ { "NT_STATUS_FLOPPY_WRONG_CYLINDER", NT_STATUS_FLOPPY_WRONG_CYLINDER },
+ { "NT_STATUS_FLOPPY_UNKNOWN_ERROR", NT_STATUS_FLOPPY_UNKNOWN_ERROR },
+ { "NT_STATUS_FLOPPY_BAD_REGISTERS", NT_STATUS_FLOPPY_BAD_REGISTERS },
+ { "NT_STATUS_DISK_RECALIBRATE_FAILED", NT_STATUS_DISK_RECALIBRATE_FAILED },
+ { "NT_STATUS_DISK_OPERATION_FAILED", NT_STATUS_DISK_OPERATION_FAILED },
+ { "NT_STATUS_DISK_RESET_FAILED", NT_STATUS_DISK_RESET_FAILED },
+ { "NT_STATUS_SHARED_IRQ_BUSY", NT_STATUS_SHARED_IRQ_BUSY },
+ { "NT_STATUS_FT_ORPHANING", NT_STATUS_FT_ORPHANING },
+ { "NT_STATUS_PARTITION_FAILURE", NT_STATUS_PARTITION_FAILURE },
+ { "NT_STATUS_INVALID_BLOCK_LENGTH", NT_STATUS_INVALID_BLOCK_LENGTH },
+ { "NT_STATUS_DEVICE_NOT_PARTITIONED", NT_STATUS_DEVICE_NOT_PARTITIONED },
+ { "NT_STATUS_UNABLE_TO_LOCK_MEDIA", NT_STATUS_UNABLE_TO_LOCK_MEDIA },
+ { "NT_STATUS_UNABLE_TO_UNLOAD_MEDIA", NT_STATUS_UNABLE_TO_UNLOAD_MEDIA },
+ { "NT_STATUS_EOM_OVERFLOW", NT_STATUS_EOM_OVERFLOW },
+ { "NT_STATUS_NO_MEDIA", NT_STATUS_NO_MEDIA },
+ { "NT_STATUS_NO_SUCH_MEMBER", NT_STATUS_NO_SUCH_MEMBER },
+ { "NT_STATUS_INVALID_MEMBER", NT_STATUS_INVALID_MEMBER },
+ { "NT_STATUS_KEY_DELETED", NT_STATUS_KEY_DELETED },
+ { "NT_STATUS_NO_LOG_SPACE", NT_STATUS_NO_LOG_SPACE },
+ { "NT_STATUS_TOO_MANY_SIDS", NT_STATUS_TOO_MANY_SIDS },
+ { "NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED", NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED },
+ { "NT_STATUS_KEY_HAS_CHILDREN", NT_STATUS_KEY_HAS_CHILDREN },
+ { "NT_STATUS_CHILD_MUST_BE_VOLATILE", NT_STATUS_CHILD_MUST_BE_VOLATILE },
+ { "NT_STATUS_DEVICE_CONFIGURATION_ERROR", NT_STATUS_DEVICE_CONFIGURATION_ERROR },
+ { "NT_STATUS_DRIVER_INTERNAL_ERROR", NT_STATUS_DRIVER_INTERNAL_ERROR },
+ { "NT_STATUS_INVALID_DEVICE_STATE", NT_STATUS_INVALID_DEVICE_STATE },
+ { "NT_STATUS_IO_DEVICE_ERROR", NT_STATUS_IO_DEVICE_ERROR },
+ { "NT_STATUS_DEVICE_PROTOCOL_ERROR", NT_STATUS_DEVICE_PROTOCOL_ERROR },
+ { "NT_STATUS_BACKUP_CONTROLLER", NT_STATUS_BACKUP_CONTROLLER },
+ { "NT_STATUS_LOG_FILE_FULL", NT_STATUS_LOG_FILE_FULL },
+ { "NT_STATUS_TOO_LATE", NT_STATUS_TOO_LATE },
+ { "NT_STATUS_NO_TRUST_LSA_SECRET", NT_STATUS_NO_TRUST_LSA_SECRET },
+ { "NT_STATUS_NO_TRUST_SAM_ACCOUNT", NT_STATUS_NO_TRUST_SAM_ACCOUNT },
+ { "NT_STATUS_TRUSTED_DOMAIN_FAILURE", NT_STATUS_TRUSTED_DOMAIN_FAILURE },
+ { "NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE", NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE },
+ { "NT_STATUS_EVENTLOG_FILE_CORRUPT", NT_STATUS_EVENTLOG_FILE_CORRUPT },
+ { "NT_STATUS_EVENTLOG_CANT_START", NT_STATUS_EVENTLOG_CANT_START },
+ { "NT_STATUS_TRUST_FAILURE", NT_STATUS_TRUST_FAILURE },
+ { "NT_STATUS_MUTANT_LIMIT_EXCEEDED", NT_STATUS_MUTANT_LIMIT_EXCEEDED },
+ { "NT_STATUS_NETLOGON_NOT_STARTED", NT_STATUS_NETLOGON_NOT_STARTED },
+ { "NT_STATUS_ACCOUNT_EXPIRED", NT_STATUS_ACCOUNT_EXPIRED },
+ { "NT_STATUS_POSSIBLE_DEADLOCK", NT_STATUS_POSSIBLE_DEADLOCK },
+ { "NT_STATUS_NETWORK_CREDENTIAL_CONFLICT", NT_STATUS_NETWORK_CREDENTIAL_CONFLICT },
+ { "NT_STATUS_REMOTE_SESSION_LIMIT", NT_STATUS_REMOTE_SESSION_LIMIT },
+ { "NT_STATUS_EVENTLOG_FILE_CHANGED", NT_STATUS_EVENTLOG_FILE_CHANGED },
+ { "NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT", NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT },
+ { "NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT", NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT },
+ { "NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT", NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT },
+ { "NT_STATUS_DOMAIN_TRUST_INCONSISTENT", NT_STATUS_DOMAIN_TRUST_INCONSISTENT },
+ { "NT_STATUS_FS_DRIVER_REQUIRED", NT_STATUS_FS_DRIVER_REQUIRED },
+ { "NT_STATUS_NO_USER_SESSION_KEY", NT_STATUS_NO_USER_SESSION_KEY },
+ { "NT_STATUS_USER_SESSION_DELETED", NT_STATUS_USER_SESSION_DELETED },
+ { "NT_STATUS_RESOURCE_LANG_NOT_FOUND", NT_STATUS_RESOURCE_LANG_NOT_FOUND },
+ { "NT_STATUS_INSUFF_SERVER_RESOURCES", NT_STATUS_INSUFF_SERVER_RESOURCES },
+ { "NT_STATUS_INVALID_BUFFER_SIZE", NT_STATUS_INVALID_BUFFER_SIZE },
+ { "NT_STATUS_INVALID_ADDRESS_COMPONENT", NT_STATUS_INVALID_ADDRESS_COMPONENT },
+ { "NT_STATUS_INVALID_ADDRESS_WILDCARD", NT_STATUS_INVALID_ADDRESS_WILDCARD },
+ { "NT_STATUS_TOO_MANY_ADDRESSES", NT_STATUS_TOO_MANY_ADDRESSES },
+ { "NT_STATUS_ADDRESS_ALREADY_EXISTS", NT_STATUS_ADDRESS_ALREADY_EXISTS },
+ { "NT_STATUS_ADDRESS_CLOSED", NT_STATUS_ADDRESS_CLOSED },
+ { "NT_STATUS_CONNECTION_DISCONNECTED", NT_STATUS_CONNECTION_DISCONNECTED },
+ { "NT_STATUS_CONNECTION_RESET", NT_STATUS_CONNECTION_RESET },
+ { "NT_STATUS_TOO_MANY_NODES", NT_STATUS_TOO_MANY_NODES },
+ { "NT_STATUS_TRANSACTION_ABORTED", NT_STATUS_TRANSACTION_ABORTED },
+ { "NT_STATUS_TRANSACTION_TIMED_OUT", NT_STATUS_TRANSACTION_TIMED_OUT },
+ { "NT_STATUS_TRANSACTION_NO_RELEASE", NT_STATUS_TRANSACTION_NO_RELEASE },
+ { "NT_STATUS_TRANSACTION_NO_MATCH", NT_STATUS_TRANSACTION_NO_MATCH },
+ { "NT_STATUS_TRANSACTION_RESPONDED", NT_STATUS_TRANSACTION_RESPONDED },
+ { "NT_STATUS_TRANSACTION_INVALID_ID", NT_STATUS_TRANSACTION_INVALID_ID },
+ { "NT_STATUS_TRANSACTION_INVALID_TYPE", NT_STATUS_TRANSACTION_INVALID_TYPE },
+ { "NT_STATUS_NOT_SERVER_SESSION", NT_STATUS_NOT_SERVER_SESSION },
+ { "NT_STATUS_NOT_CLIENT_SESSION", NT_STATUS_NOT_CLIENT_SESSION },
+ { "NT_STATUS_CANNOT_LOAD_REGISTRY_FILE", NT_STATUS_CANNOT_LOAD_REGISTRY_FILE },
+ { "NT_STATUS_DEBUG_ATTACH_FAILED", NT_STATUS_DEBUG_ATTACH_FAILED },
+ { "NT_STATUS_SYSTEM_PROCESS_TERMINATED", NT_STATUS_SYSTEM_PROCESS_TERMINATED },
+ { "NT_STATUS_DATA_NOT_ACCEPTED", NT_STATUS_DATA_NOT_ACCEPTED },
+ { "NT_STATUS_NO_BROWSER_SERVERS_FOUND", NT_STATUS_NO_BROWSER_SERVERS_FOUND },
+ { "NT_STATUS_VDM_HARD_ERROR", NT_STATUS_VDM_HARD_ERROR },
+ { "NT_STATUS_DRIVER_CANCEL_TIMEOUT", NT_STATUS_DRIVER_CANCEL_TIMEOUT },
+ { "NT_STATUS_REPLY_MESSAGE_MISMATCH", NT_STATUS_REPLY_MESSAGE_MISMATCH },
+ { "NT_STATUS_MAPPED_ALIGNMENT", NT_STATUS_MAPPED_ALIGNMENT },
+ { "NT_STATUS_IMAGE_CHECKSUM_MISMATCH", NT_STATUS_IMAGE_CHECKSUM_MISMATCH },
+ { "NT_STATUS_LOST_WRITEBEHIND_DATA", NT_STATUS_LOST_WRITEBEHIND_DATA },
+ { "NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID", NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID },
+ { "NT_STATUS_PASSWORD_MUST_CHANGE", NT_STATUS_PASSWORD_MUST_CHANGE },
+ { "NT_STATUS_NOT_FOUND", NT_STATUS_NOT_FOUND },
+ { "NT_STATUS_NOT_TINY_STREAM", NT_STATUS_NOT_TINY_STREAM },
+ { "NT_STATUS_RECOVERY_FAILURE", NT_STATUS_RECOVERY_FAILURE },
+ { "NT_STATUS_STACK_OVERFLOW_READ", NT_STATUS_STACK_OVERFLOW_READ },
+ { "NT_STATUS_FAIL_CHECK", NT_STATUS_FAIL_CHECK },
+ { "NT_STATUS_DUPLICATE_OBJECTID", NT_STATUS_DUPLICATE_OBJECTID },
+ { "NT_STATUS_OBJECTID_EXISTS", NT_STATUS_OBJECTID_EXISTS },
+ { "NT_STATUS_CONVERT_TO_LARGE", NT_STATUS_CONVERT_TO_LARGE },
+ { "NT_STATUS_RETRY", NT_STATUS_RETRY },
+ { "NT_STATUS_FOUND_OUT_OF_SCOPE", NT_STATUS_FOUND_OUT_OF_SCOPE },
+ { "NT_STATUS_ALLOCATE_BUCKET", NT_STATUS_ALLOCATE_BUCKET },
+ { "NT_STATUS_PROPSET_NOT_FOUND", NT_STATUS_PROPSET_NOT_FOUND },
+ { "NT_STATUS_MARSHALL_OVERFLOW", NT_STATUS_MARSHALL_OVERFLOW },
+ { "NT_STATUS_INVALID_VARIANT", NT_STATUS_INVALID_VARIANT },
+ { "NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND", NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND },
+ { "NT_STATUS_ACCOUNT_LOCKED_OUT", NT_STATUS_ACCOUNT_LOCKED_OUT },
+ { "NT_STATUS_HANDLE_NOT_CLOSABLE", NT_STATUS_HANDLE_NOT_CLOSABLE },
+ { "NT_STATUS_CONNECTION_REFUSED", NT_STATUS_CONNECTION_REFUSED },
+ { "NT_STATUS_GRACEFUL_DISCONNECT", NT_STATUS_GRACEFUL_DISCONNECT },
+ { "NT_STATUS_ADDRESS_ALREADY_ASSOCIATED", NT_STATUS_ADDRESS_ALREADY_ASSOCIATED },
+ { "NT_STATUS_ADDRESS_NOT_ASSOCIATED", NT_STATUS_ADDRESS_NOT_ASSOCIATED },
+ { "NT_STATUS_CONNECTION_INVALID", NT_STATUS_CONNECTION_INVALID },
+ { "NT_STATUS_CONNECTION_ACTIVE", NT_STATUS_CONNECTION_ACTIVE },
+ { "NT_STATUS_NETWORK_UNREACHABLE", NT_STATUS_NETWORK_UNREACHABLE },
+ { "NT_STATUS_HOST_UNREACHABLE", NT_STATUS_HOST_UNREACHABLE },
+ { "NT_STATUS_PROTOCOL_UNREACHABLE", NT_STATUS_PROTOCOL_UNREACHABLE },
+ { "NT_STATUS_PORT_UNREACHABLE", NT_STATUS_PORT_UNREACHABLE },
+ { "NT_STATUS_REQUEST_ABORTED", NT_STATUS_REQUEST_ABORTED },
+ { "NT_STATUS_CONNECTION_ABORTED", NT_STATUS_CONNECTION_ABORTED },
+ { "NT_STATUS_BAD_COMPRESSION_BUFFER", NT_STATUS_BAD_COMPRESSION_BUFFER },
+ { "NT_STATUS_USER_MAPPED_FILE", NT_STATUS_USER_MAPPED_FILE },
+ { "NT_STATUS_AUDIT_FAILED", NT_STATUS_AUDIT_FAILED },
+ { "NT_STATUS_TIMER_RESOLUTION_NOT_SET", NT_STATUS_TIMER_RESOLUTION_NOT_SET },
+ { "NT_STATUS_CONNECTION_COUNT_LIMIT", NT_STATUS_CONNECTION_COUNT_LIMIT },
+ { "NT_STATUS_LOGIN_TIME_RESTRICTION", NT_STATUS_LOGIN_TIME_RESTRICTION },
+ { "NT_STATUS_LOGIN_WKSTA_RESTRICTION", NT_STATUS_LOGIN_WKSTA_RESTRICTION },
+ { "NT_STATUS_IMAGE_MP_UP_MISMATCH", NT_STATUS_IMAGE_MP_UP_MISMATCH },
+ { "NT_STATUS_INSUFFICIENT_LOGON_INFO", NT_STATUS_INSUFFICIENT_LOGON_INFO },
+ { "NT_STATUS_BAD_DLL_ENTRYPOINT", NT_STATUS_BAD_DLL_ENTRYPOINT },
+ { "NT_STATUS_BAD_SERVICE_ENTRYPOINT", NT_STATUS_BAD_SERVICE_ENTRYPOINT },
+ { "NT_STATUS_LPC_REPLY_LOST", NT_STATUS_LPC_REPLY_LOST },
+ { "NT_STATUS_IP_ADDRESS_CONFLICT1", NT_STATUS_IP_ADDRESS_CONFLICT1 },
+ { "NT_STATUS_IP_ADDRESS_CONFLICT2", NT_STATUS_IP_ADDRESS_CONFLICT2 },
+ { "NT_STATUS_REGISTRY_QUOTA_LIMIT", NT_STATUS_REGISTRY_QUOTA_LIMIT },
+ { "NT_STATUS_PATH_NOT_COVERED", NT_STATUS_PATH_NOT_COVERED },
+ { "NT_STATUS_NO_CALLBACK_ACTIVE", NT_STATUS_NO_CALLBACK_ACTIVE },
+ { "NT_STATUS_LICENSE_QUOTA_EXCEEDED", NT_STATUS_LICENSE_QUOTA_EXCEEDED },
+ { "NT_STATUS_PWD_TOO_SHORT", NT_STATUS_PWD_TOO_SHORT },
+ { "NT_STATUS_PWD_TOO_RECENT", NT_STATUS_PWD_TOO_RECENT },
+ { "NT_STATUS_PWD_HISTORY_CONFLICT", NT_STATUS_PWD_HISTORY_CONFLICT },
+ { "NT_STATUS_PLUGPLAY_NO_DEVICE", NT_STATUS_PLUGPLAY_NO_DEVICE },
+ { "NT_STATUS_UNSUPPORTED_COMPRESSION", NT_STATUS_UNSUPPORTED_COMPRESSION },
+ { "NT_STATUS_INVALID_HW_PROFILE", NT_STATUS_INVALID_HW_PROFILE },
+ { "NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH", NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH },
+ { "NT_STATUS_DRIVER_ORDINAL_NOT_FOUND", NT_STATUS_DRIVER_ORDINAL_NOT_FOUND },
+ { "NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND", NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND },
+ { "NT_STATUS_RESOURCE_NOT_OWNED", NT_STATUS_RESOURCE_NOT_OWNED },
+ { "NT_STATUS_TOO_MANY_LINKS", NT_STATUS_TOO_MANY_LINKS },
+ { "NT_STATUS_QUOTA_LIST_INCONSISTENT", NT_STATUS_QUOTA_LIST_INCONSISTENT },
+ { "NT_STATUS_FILE_IS_OFFLINE", NT_STATUS_FILE_IS_OFFLINE },
+ { NULL, 0 }
+};
+
diff --git a/source/libsmb/smbdes.c b/source/libsmb/smbdes.c
new file mode 100644
index 00000000000..e4f8280f9bc
--- /dev/null
+++ b/source/libsmb/smbdes.c
@@ -0,0 +1,337 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+
+ a partial implementation of DES designed for use in the
+ SMB authentication protocol
+
+ Copyright (C) Andrew Tridgell 1997
+
+ 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.
+*/
+
+
+/* NOTES:
+
+ This code makes no attempt to be fast! In fact, it is a very
+ slow implementation
+
+ This code is NOT a complete DES implementation. It implements only
+ the minimum necessary for SMB authentication, as used by all SMB
+ products (including every copy of Microsoft Windows95 ever sold)
+
+ In particular, it can only do a unchained forward DES pass. This
+ means it is not possible to use this code for encryption/decryption
+ of data, instead it is only useful as a "hash" algorithm.
+
+ There is no entry point into this code that allows normal DES operation.
+
+ I believe this means that this code does not come under ITAR
+ regulations but this is NOT a legal opinion. If you are concerned
+ about the applicability of ITAR regulations to this code then you
+ should confirm it for yourself (and maybe let me know if you come
+ up with a different answer to the one above)
+*/
+
+
+
+static int perm1[56] = {57, 49, 41, 33, 25, 17, 9,
+ 1, 58, 50, 42, 34, 26, 18,
+ 10, 2, 59, 51, 43, 35, 27,
+ 19, 11, 3, 60, 52, 44, 36,
+ 63, 55, 47, 39, 31, 23, 15,
+ 7, 62, 54, 46, 38, 30, 22,
+ 14, 6, 61, 53, 45, 37, 29,
+ 21, 13, 5, 28, 20, 12, 4};
+
+static int perm2[48] = {14, 17, 11, 24, 1, 5,
+ 3, 28, 15, 6, 21, 10,
+ 23, 19, 12, 4, 26, 8,
+ 16, 7, 27, 20, 13, 2,
+ 41, 52, 31, 37, 47, 55,
+ 30, 40, 51, 45, 33, 48,
+ 44, 49, 39, 56, 34, 53,
+ 46, 42, 50, 36, 29, 32};
+
+static int perm3[64] = {58, 50, 42, 34, 26, 18, 10, 2,
+ 60, 52, 44, 36, 28, 20, 12, 4,
+ 62, 54, 46, 38, 30, 22, 14, 6,
+ 64, 56, 48, 40, 32, 24, 16, 8,
+ 57, 49, 41, 33, 25, 17, 9, 1,
+ 59, 51, 43, 35, 27, 19, 11, 3,
+ 61, 53, 45, 37, 29, 21, 13, 5,
+ 63, 55, 47, 39, 31, 23, 15, 7};
+
+static int perm4[48] = { 32, 1, 2, 3, 4, 5,
+ 4, 5, 6, 7, 8, 9,
+ 8, 9, 10, 11, 12, 13,
+ 12, 13, 14, 15, 16, 17,
+ 16, 17, 18, 19, 20, 21,
+ 20, 21, 22, 23, 24, 25,
+ 24, 25, 26, 27, 28, 29,
+ 28, 29, 30, 31, 32, 1};
+
+static int perm5[32] = { 16, 7, 20, 21,
+ 29, 12, 28, 17,
+ 1, 15, 23, 26,
+ 5, 18, 31, 10,
+ 2, 8, 24, 14,
+ 32, 27, 3, 9,
+ 19, 13, 30, 6,
+ 22, 11, 4, 25};
+
+
+static int perm6[64] ={ 40, 8, 48, 16, 56, 24, 64, 32,
+ 39, 7, 47, 15, 55, 23, 63, 31,
+ 38, 6, 46, 14, 54, 22, 62, 30,
+ 37, 5, 45, 13, 53, 21, 61, 29,
+ 36, 4, 44, 12, 52, 20, 60, 28,
+ 35, 3, 43, 11, 51, 19, 59, 27,
+ 34, 2, 42, 10, 50, 18, 58, 26,
+ 33, 1, 41, 9, 49, 17, 57, 25};
+
+
+static int sc[16] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
+
+static int sbox[8][4][16] = {
+ {{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
+ {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
+ {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
+ {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}},
+
+ {{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
+ {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
+ {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
+ {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}},
+
+ {{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
+ {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
+ {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
+ {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}},
+
+ {{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
+ {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
+ {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
+ {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}},
+
+ {{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
+ {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
+ {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},
+ {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}},
+
+ {{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},
+ {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},
+ {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},
+ {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}},
+
+ {{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
+ {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},
+ {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},
+ {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}},
+
+ {{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},
+ {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
+ {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},
+ {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}}};
+
+static void permute(char *out, char *in, int *p, int n)
+{
+ int i;
+ for (i=0;i<n;i++)
+ out[i] = in[p[i]-1];
+}
+
+static void lshift(char *d, int count, int n)
+{
+ char out[64];
+ int i;
+ for (i=0;i<n;i++)
+ out[i] = d[(i+count)%n];
+ for (i=0;i<n;i++)
+ d[i] = out[i];
+}
+
+static void concat(char *out, char *in1, char *in2, int l1, int l2)
+{
+ while (l1--)
+ *out++ = *in1++;
+ while (l2--)
+ *out++ = *in2++;
+}
+
+static void xor(char *out, char *in1, char *in2, int n)
+{
+ int i;
+ for (i=0;i<n;i++)
+ out[i] = in1[i] ^ in2[i];
+}
+
+static void dohash(char *out, char *in, char *key)
+{
+ int i, j, k;
+ char pk1[56];
+ char c[28];
+ char d[28];
+ char cd[56];
+ char ki[16][48];
+ char pd1[64];
+ char l[32], r[32];
+ char rl[64];
+
+ permute(pk1, key, perm1, 56);
+
+ for (i=0;i<28;i++)
+ c[i] = pk1[i];
+ for (i=0;i<28;i++)
+ d[i] = pk1[i+28];
+
+ for (i=0;i<16;i++) {
+ lshift(c, sc[i], 28);
+ lshift(d, sc[i], 28);
+
+ concat(cd, c, d, 28, 28);
+ permute(ki[i], cd, perm2, 48);
+ }
+
+ permute(pd1, in, perm3, 64);
+
+ for (j=0;j<32;j++) {
+ l[j] = pd1[j];
+ r[j] = pd1[j+32];
+ }
+
+ for (i=0;i<16;i++) {
+ char er[48];
+ char erk[48];
+ char b[8][6];
+ char cb[32];
+ char pcb[32];
+ char r2[32];
+
+ permute(er, r, perm4, 48);
+
+ xor(erk, er, ki[i], 48);
+
+ for (j=0;j<8;j++)
+ for (k=0;k<6;k++)
+ b[j][k] = erk[j*6 + k];
+
+ for (j=0;j<8;j++) {
+ int m, n;
+ m = (b[j][0]<<1) | b[j][5];
+
+ n = (b[j][1]<<3) | (b[j][2]<<2) | (b[j][3]<<1) | b[j][4];
+
+ for (k=0;k<4;k++)
+ b[j][k] = (sbox[j][m][n] & (1<<(3-k)))?1:0;
+ }
+
+ for (j=0;j<8;j++)
+ for (k=0;k<4;k++)
+ cb[j*4+k] = b[j][k];
+ permute(pcb, cb, perm5, 32);
+
+ xor(r2, l, pcb, 32);
+
+ for (j=0;j<32;j++)
+ l[j] = r[j];
+
+ for (j=0;j<32;j++)
+ r[j] = r2[j];
+ }
+
+ concat(rl, r, l, 32, 32);
+
+ permute(out, rl, perm6, 64);
+}
+
+static void str_to_key(unsigned char *str,unsigned char *key)
+{
+ int i;
+
+ key[0] = str[0]>>1;
+ key[1] = ((str[0]&0x01)<<6) | (str[1]>>2);
+ key[2] = ((str[1]&0x03)<<5) | (str[2]>>3);
+ key[3] = ((str[2]&0x07)<<4) | (str[3]>>4);
+ key[4] = ((str[3]&0x0F)<<3) | (str[4]>>5);
+ key[5] = ((str[4]&0x1F)<<2) | (str[5]>>6);
+ key[6] = ((str[5]&0x3F)<<1) | (str[6]>>7);
+ key[7] = str[6]&0x7F;
+ for (i=0;i<8;i++) {
+ key[i] = (key[i]<<1);
+ }
+}
+
+
+static void smbhash(unsigned char *out, unsigned char *in, unsigned char *key)
+{
+ int i;
+ char outb[64];
+ char inb[64];
+ char keyb[64];
+ unsigned char key2[8];
+
+ str_to_key(key, key2);
+
+ for (i=0;i<64;i++) {
+ inb[i] = (in[i/8] & (1<<(7-(i%8)))) ? 1 : 0;
+ keyb[i] = (key2[i/8] & (1<<(7-(i%8)))) ? 1 : 0;
+ outb[i] = 0;
+ }
+
+ dohash(outb, inb, keyb);
+
+ for (i=0;i<8;i++) {
+ out[i] = 0;
+ }
+
+ for (i=0;i<64;i++) {
+ if (outb[i])
+ out[i/8] |= (1<<(7-(i%8)));
+ }
+}
+
+void E_P16(unsigned char *p14,unsigned char *p16)
+{
+ unsigned char sp8[8] = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
+ smbhash(p16, sp8, p14);
+ smbhash(p16+8, sp8, p14+7);
+}
+
+void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24)
+{
+ smbhash(p24, c8, p21);
+ smbhash(p24+8, c8, p21+7);
+ smbhash(p24+16, c8, p21+14);
+}
+
+void cred_hash1(unsigned char *out,unsigned char *in,unsigned char *key)
+{
+ unsigned char buf[8];
+
+ smbhash(buf, in, key);
+ smbhash(out, buf, key+9);
+}
+
+void cred_hash2(unsigned char *out,unsigned char *in,unsigned char *key)
+{
+ unsigned char buf[8];
+ static unsigned char key2[8];
+
+ smbhash(buf, in, key);
+ key2[0] = key[7];
+ smbhash(out, buf, key2);
+}
+
diff --git a/source/libsmb/smbencrypt.c b/source/libsmb/smbencrypt.c
index a0683b5d282..38d414cf23d 100644
--- a/source/libsmb/smbencrypt.c
+++ b/source/libsmb/smbencrypt.c
@@ -1,9 +1,8 @@
-#ifdef SMB_PASSWD
/*
Unix SMB/Netbios implementation.
Version 1.9.
SMB parameters and setup
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1997
Modified by Jeremy Allison 1995.
This program is free software; you can redistribute it and/or modify
@@ -22,90 +21,11 @@
*/
#include "includes.h"
-#include "loadparm.h"
-#include "des.h"
-#include "md4.h"
extern int DEBUGLEVEL;
-#ifndef uchar
-#define uchar unsigned char
-#endif
-#ifndef int16
-#define int16 unsigned short
-#endif
-#ifndef uint16
-#define uint16 unsigned short
-#endif
-#ifndef uint32
-#define uint32 unsigned int
-#endif
-
#include "byteorder.h"
-void str_to_key(uchar *str,uchar *key)
-{
- void des_set_odd_parity(des_cblock *);
- int i;
-
- key[0] = str[0]>>1;
- key[1] = ((str[0]&0x01)<<6) | (str[1]>>2);
- key[2] = ((str[1]&0x03)<<5) | (str[2]>>3);
- key[3] = ((str[2]&0x07)<<4) | (str[3]>>4);
- key[4] = ((str[3]&0x0F)<<3) | (str[4]>>5);
- key[5] = ((str[4]&0x1F)<<2) | (str[5]>>6);
- key[6] = ((str[5]&0x3F)<<1) | (str[6]>>7);
- key[7] = str[6]&0x7F;
- for (i=0;i<8;i++) {
- key[i] = (key[i]<<1);
- }
- des_set_odd_parity((des_cblock *)key);
-}
-
-void D1(uchar *k, uchar *d, uchar *out)
-{
- des_key_schedule ks;
- des_cblock deskey;
-
- str_to_key(k,(uchar *)deskey);
- des_set_key(deskey,ks);
- des_ecb_encrypt(d, out, ks, DES_DECRYPT);
-}
-
-void E1(uchar *k, uchar *d, uchar *out)
-{
- des_key_schedule ks;
- des_cblock deskey;
-
- str_to_key(k,(uchar *)deskey);
- des_set_key(deskey,ks);
- des_ecb_encrypt(d, out, ks, DES_ENCRYPT);
-}
-
-void E_P16(uchar *p14,uchar *p16)
-{
- uchar sp7[7];
- /* the following constant makes us compatible with other
- implementations. Note that publishing this constant does not reduce the
- security of the encryption mechanism */
- uchar sp8[] = {0xAA,0xD3,0xB4,0x35,0xB5,0x14,0x4,0xEE};
- uchar x[8];
-
- memset(sp7,'\0',7);
-
- D1(sp7, sp8, x);
- E1(p14, x, p16);
- E1(p14+7, x, p16+8);
-}
-
-void E_P24(uchar *p21, uchar *c8, uchar *p24)
-{
- E1(p21, c8, p24);
- E1(p21+7, c8, p24+8);
- E1(p21+14, c8, p24+16);
-}
-
-
/*
This implements the X/Open SMB password encryption
It takes a password, a 8 byte "crypt key" and puts 24 bytes of
@@ -161,28 +81,20 @@ static int _my_mbstowcs(int16 *dst, uchar *src, int len)
void E_md4hash(uchar *passwd, uchar *p16)
{
- int i, len;
+ int len;
int16 wpwd[129];
- 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 */
- _my_mbstowcs( wpwd, passwd, len);
+ _my_mbstowcs(wpwd, passwd, len);
wpwd[len] = 0; /* Ensure string is null terminated */
/* Calculate length in bytes */
len = _my_wcslen(wpwd) * sizeof(int16);
-
- MDbegin(&MD);
- for(i = 0; i + 64 <= len; i += 64)
- MDupdate(&MD,wpwd + (i/2), 512);
- MDupdate(&MD,wpwd + (i/2),(len-i)*8);
- SIVAL(p16,0,MD.buffer[0]);
- SIVAL(p16,4,MD.buffer[1]);
- SIVAL(p16,8,MD.buffer[2]);
- SIVAL(p16,12,MD.buffer[3]);
+
+ mdfour(p16, (unsigned char *)wpwd, len);
}
/* Does the NT MD4 hash then des encryption. */
@@ -197,6 +109,27 @@ void SMBNTencrypt(uchar *passwd, uchar *c8, uchar *p24)
E_P24(p21, c8, p24);
}
-#else
-void smbencrypt_dummy(void){}
-#endif
+/* Does both the NT and LM owfs of a user's password */
+
+void nt_lm_owf_gen(char *pwd, char *nt_p16, char *p16)
+{
+ char passwd[130];
+ StrnCpy(passwd, pwd, sizeof(passwd)-1);
+
+ /* Calculate the MD4 hash (NT compatible) of the password */
+ memset(nt_p16, '\0', 16);
+ E_md4hash((uchar *)passwd, (uchar *)nt_p16);
+
+ /* Mangle the passwords into Lanman format */
+ passwd[14] = '\0';
+ strupper(passwd);
+
+ /* Calculate the SMB (lanman) hash functions of the password */
+
+ memset(p16, '\0', 16);
+ E_P16((uchar *) passwd, (uchar *)p16);
+
+ /* clear out local copy of user's password (just being paranoid). */
+ bzero(passwd, sizeof(passwd));
+}
+
diff --git a/source/locking/locking.c b/source/locking/locking.c
index 6ff3ab5d125..d654d038c81 100644
--- a/source/locking/locking.c
+++ b/source/locking/locking.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Locking functions
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1997
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
@@ -17,16 +17,26 @@
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:
+
+ 12 aug 96: Erik.Devriendt@te6.siemens.be
+ added support for shared memory implementation of share mode locking
+
+ May 1997. Jeremy Allison (jallison@whistle.com). Modified share mode
+ locking to deal with multiple share modes per open file.
+
+ September 1997. Jeremy Allison (jallison@whistle.com). Added oplock
+ support.
+
*/
#include "includes.h"
-#include "loadparm.h"
extern int DEBUGLEVEL;
extern connection_struct Connections[];
extern files_struct Files[];
-pstring share_del_pending="";
-
+static struct share_ops *share_ops;
/****************************************************************************
utility function called to see if a file region is locked
@@ -41,8 +51,8 @@ BOOL is_locked(int fnum,int cnum,uint32 count,uint32 offset)
if (!lp_locking(snum) || !lp_strict_locking(snum))
return(False);
- return(fcntl_lock(Files[fnum].fd,F_GETLK,offset,count,
- (Files[fnum].can_write?F_WRLCK:F_RDLCK)));
+ return(fcntl_lock(Files[fnum].fd_ptr->fd,F_GETLK,offset,count,
+ (Files[fnum].can_write?F_WRLCK:F_RDLCK)));
}
@@ -63,8 +73,8 @@ BOOL do_lock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ec
}
if (Files[fnum].can_lock && OPEN_FNUM(fnum) && (Files[fnum].cnum == cnum))
- ok = fcntl_lock(Files[fnum].fd,F_SETLK,offset,count,
- (Files[fnum].can_write?F_WRLCK:F_RDLCK));
+ ok = fcntl_lock(Files[fnum].fd_ptr->fd,F_SETLK,offset,count,
+ (Files[fnum].can_write?F_WRLCK:F_RDLCK));
if (!ok) {
*eclass = ERRDOS;
@@ -86,7 +96,7 @@ BOOL do_unlock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *
return(True);
if (Files[fnum].can_lock && OPEN_FNUM(fnum) && (Files[fnum].cnum == cnum))
- ok = fcntl_lock(Files[fnum].fd,F_SETLK,offset,count,F_UNLCK);
+ ok = fcntl_lock(Files[fnum].fd_ptr->fd,F_SETLK,offset,count,F_UNLCK);
if (!ok) {
*eclass = ERRDOS;
@@ -96,235 +106,106 @@ BOOL do_unlock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *
return True; /* Did unlock */
}
-/*******************************************************************
- name a share file
- ******************************************************************/
-static BOOL share_name(int cnum,struct stat *st,char *name)
+
+
+/****************************************************************************
+ initialise the locking functions
+****************************************************************************/
+BOOL locking_init(int read_only)
{
- strcpy(name,lp_lockdir());
- standard_sub(cnum,name);
- trim_string(name,"","/");
- if (!*name) return(False);
- name += strlen(name);
-
- sprintf(name,"/share.%d.%d",(int)st->st_dev,(int)st->st_ino);
- return(True);
+ if (share_ops) return True;
+
+#ifdef FAST_SHARE_MODES
+ share_ops = locking_shm_init(read_only);
+ if (!share_ops) {
+ DEBUG(0,("ERROR: Failed to initialise fast share modes - trying slow code\n"));
+ }
+ if (share_ops) return True;
+#endif
+
+ share_ops = locking_slow_init(read_only);
+ if (!share_ops) {
+ DEBUG(0,("ERROR: Failed to initialise share modes!\n"));
+ return False;
+ }
+
+ return True;
}
/*******************************************************************
- use the fnum to get the share file name
+ deinitialize the share_mode management
******************************************************************/
-static BOOL share_name_fnum(int fnum,char *name)
+BOOL locking_end(void)
{
- struct stat st;
- if (fstat(Files[fnum].fd,&st) != 0) return(False);
- return(share_name(Files[fnum].cnum,&st,name));
+ if (share_ops)
+ return share_ops->stop_mgmt();
+ return True;
}
/*******************************************************************
- get the share mode of a file using the fnum
+ lock a hash bucket entry
******************************************************************/
-int get_share_mode_by_fnum(int cnum,int fnum,int *pid)
+BOOL lock_share_entry(int cnum, uint32 dev, uint32 inode, int *ptok)
{
- struct stat sbuf;
- if (fstat(Files[fnum].fd,&sbuf) == -1) return(0);
- return(get_share_mode(cnum,&sbuf,pid));
+ return share_ops->lock_entry(cnum, dev, inode, ptok);
}
/*******************************************************************
- get the share mode of a file using the files name
+ unlock a hash bucket entry
******************************************************************/
-int get_share_mode_byname(int cnum,char *fname,int *pid)
+BOOL unlock_share_entry(int cnum, uint32 dev, uint32 inode, int token)
{
- struct stat sbuf;
- if (stat(fname,&sbuf) == -1) return(0);
- return(get_share_mode(cnum,&sbuf,pid));
-}
-
+ return share_ops->unlock_entry(cnum, dev, inode, token);
+}
/*******************************************************************
-get the share mode of a file
+get all share mode entries for a dev/inode pair.
********************************************************************/
-int get_share_mode(int cnum,struct stat *sbuf,int *pid)
+int get_share_modes(int cnum, int token, uint32 dev, uint32 inode,
+ share_mode_entry **shares)
{
- pstring fname;
- int fd2;
- char buf[16];
- int ret;
- time_t t;
-
- *pid = 0;
-
- if (!share_name(cnum,sbuf,fname)) return(0);
-
- fd2 = open(fname,O_RDONLY,0);
- if (fd2 < 0) return(0);
-
- if (read(fd2,buf,16) != 16) {
- close(fd2);
- unlink(fname);
- return(0);
- }
- close(fd2);
-
- t = IVAL(buf,0);
- ret = IVAL(buf,4);
- *pid = IVAL(buf,8);
-
- if (IVAL(buf,12) != LOCKING_VERSION) {
- if (!unlink(fname)) DEBUG(2,("Deleted old locking file %s",fname));
- *pid = 0;
- return(0);
- }
-
- if (*pid && !process_exists(*pid)) {
- ret=0;
- *pid = 0;
- }
-
- if (! *pid) unlink(fname); /* XXXXX race, race */
-
- if (*pid)
- DEBUG(5,("Read share file %s mode 0x%X pid=%d\n",fname,ret,*pid));
-
- return(ret);
+ return share_ops->get_entries(cnum, token, dev, inode, shares);
}
-
/*******************************************************************
-del the share mode of a file, if we set it last
+del the share mode of a file.
********************************************************************/
-void del_share_mode(int fnum)
+void del_share_mode(int token, int fnum)
{
- pstring fname;
- int fd2;
- char buf[16];
- time_t t=0;
- int pid=0;
- BOOL del = False;
-
- if (!share_name_fnum(fnum,fname)) return;
-
- fd2 = open(fname,O_RDONLY,0);
- if (fd2 < 0) return;
- if (read(fd2,buf,16) != 16)
- del = True;
- close(fd2);
-
- if (!del) {
- t = IVAL(buf,0);
- pid = IVAL(buf,8);
- }
-
- if (!del)
- if (IVAL(buf,12) != LOCKING_VERSION || !pid || !process_exists(pid))
- del = True;
-
- if (!del && t == Files[fnum].open_time && pid==(int)getpid())
- del = True;
-
- if (del) {
- if (!unlink(fname))
- DEBUG(2,("Deleted share file %s\n",fname));
- else {
- DEBUG(3,("Pending delete share file %s\n",fname));
- if (*share_del_pending) DEBUG(0,("Share del clash!\n"));
- strcpy(share_del_pending,fname);
- }
- }
+ share_ops->del_entry(token, fnum);
}
-
/*******************************************************************
-set the share mode of a file
+set the share mode of a file. Return False on fail, True on success.
********************************************************************/
-BOOL set_share_mode(int fnum,int mode)
+BOOL set_share_mode(int token, int fnum, uint16 port, uint16 op_type)
{
- pstring fname;
- int fd2;
- char buf[16];
- int pid = (int)getpid();
-
- if (!share_name_fnum(fnum,fname)) return(False);
-
- {
- int old_umask = umask(0);
- fd2 = open(fname,O_WRONLY|O_CREAT|O_TRUNC,0644);
- umask(old_umask);
- }
- if (fd2 < 0) {
- DEBUG(2,("Failed to create share file %s\n",fname));
- return(False);
- }
-
- SIVAL(buf,0,Files[fnum].open_time);
- SIVAL(buf,4,mode);
- SIVAL(buf,8,pid);
- SIVAL(buf,12,LOCKING_VERSION);
-
- if (write(fd2,buf,16) != 16) {
- close(fd2);
- unlink(fname);
- return(False);
- }
-
- write(fd2,Files[fnum].name,strlen(Files[fnum].name)+1);
+ return share_ops->set_entry(token, fnum, port, op_type);
+}
- close(fd2);
+/*******************************************************************
+Remove an oplock port and mode entry from a share mode.
+********************************************************************/
+BOOL remove_share_oplock(int fnum, int token)
+{
+ return share_ops->remove_oplock(fnum, token);
+}
- DEBUG(3,("Created share file %s with mode 0x%X pid=%d\n",fname,mode,pid));
- return(True);
+/*******************************************************************
+call the specified function on each entry under management by the
+share mode system
+********************************************************************/
+int share_mode_forall(void (*fn)(share_mode_entry *, char *))
+{
+ return share_ops->forall(fn);
}
-
/*******************************************************************
-cleanup any stale share files
+dump the state of the system
********************************************************************/
-void clean_share_files(void)
+void share_status(FILE *f)
{
- char *lockdir = lp_lockdir();
- void *dir;
- char *s;
-
- if (!*lockdir) return;
-
- dir = opendir(lockdir);
- if (!dir) return;
-
- while ((s=readdirname(dir))) {
- char buf[16];
- int pid;
- int fd;
- pstring lname;
- int dev,inode;
-
- if (sscanf(s,"share.%d.%d",&dev,&inode)!=2) continue;
-
- strcpy(lname,lp_lockdir());
- trim_string(lname,NULL,"/");
- strcat(lname,"/");
- strcat(lname,s);
-
- fd = open(lname,O_RDONLY,0);
- if (fd < 0) continue;
-
- if (read(fd,buf,16) != 16) {
- close(fd);
- if (!unlink(lname))
- printf("Deleted corrupt share file %s\n",s);
- continue;
- }
- close(fd);
-
- pid = IVAL(buf,8);
-
- if (IVAL(buf,12) != LOCKING_VERSION || !process_exists(pid)) {
- if (!unlink(lname))
- printf("Deleted stale share file %s\n",s);
- }
- }
-
- closedir(dir);
+ share_ops->status(f);
}
diff --git a/source/locking/locking_shm.c b/source/locking/locking_shm.c
new file mode 100644
index 00000000000..d299e34caae
--- /dev/null
+++ b/source/locking/locking_shm.c
@@ -0,0 +1,714 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ shared memory locking implementation
+ Copyright (C) Andrew Tridgell 1992-1997
+
+ 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:
+
+ 12 aug 96: Erik.Devriendt@te6.siemens.be
+ added support for shared memory implementation of share mode locking
+
+ May 1997. Jeremy Allison (jallison@whistle.com). Modified share mode
+ locking to deal with multiple share modes per open file.
+
+ September 1997. Jeremy Allison (jallison@whistle.com). Added oplock
+ support.
+
+ October 1997 - split into separate file (tridge)
+*/
+
+#ifdef FAST_SHARE_MODES
+
+#include "includes.h"
+extern int DEBUGLEVEL;
+extern connection_struct Connections[];
+extern files_struct Files[];
+
+static struct shmem_ops *shmops;
+
+/* share mode record pointed to in shared memory hash bucket */
+typedef struct
+{
+ int next_offset; /* offset of next record in chain from hash bucket */
+ int locking_version;
+ int32 st_dev;
+ int32 st_ino;
+ int num_share_mode_entries;
+ int share_mode_entries; /* Chain of share mode entries for this file */
+ char file_name[1];
+} share_mode_record;
+
+/* share mode entry pointed to by share_mode_record struct */
+typedef struct
+{
+ int next_share_mode_entry;
+ share_mode_entry e;
+} shm_share_mode_entry;
+
+static int read_only;
+
+
+/* Conversion to hash entry index from device and inode numbers. */
+#define HASH_ENTRY(dev,ino) ((((uint32)(dev)) * ((uint32)(ino))) % shmops->hash_size())
+
+
+/*******************************************************************
+ deinitialize the shared memory for share_mode management
+ ******************************************************************/
+static BOOL shm_stop_share_mode_mgmt(void)
+{
+ return shmops->close();
+}
+
+/*******************************************************************
+ lock a hash bucket entry in shared memory for share_mode management
+ ******************************************************************/
+static BOOL shm_lock_share_entry(int cnum, uint32 dev, uint32 inode, int *ptok)
+{
+ return shmops->lock_hash_entry(HASH_ENTRY(dev, inode));
+}
+
+/*******************************************************************
+ unlock a hash bucket entry in shared memory for share_mode management
+ ******************************************************************/
+static BOOL shm_unlock_share_entry(int cnum, uint32 dev, uint32 inode, int token)
+{
+ return shmops->unlock_hash_entry(HASH_ENTRY(dev, inode));
+}
+
+/*******************************************************************
+get all share mode entries in shared memory for a dev/inode pair.
+********************************************************************/
+static int shm_get_share_modes(int cnum, int token, uint32 dev, uint32 inode,
+ share_mode_entry **old_shares)
+{
+ int *mode_array;
+ unsigned int hash_entry = HASH_ENTRY(dev, inode);
+ share_mode_record *file_scanner_p;
+ share_mode_record *file_prev_p;
+ shm_share_mode_entry *entry_scanner_p;
+ shm_share_mode_entry *entry_prev_p;
+ int num_entries;
+ int num_entries_copied;
+ BOOL found = False;
+ share_mode_entry *share_array = (share_mode_entry *)0;
+
+ *old_shares = 0;
+
+ mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
+
+ if(mode_array[hash_entry] == NULL_OFFSET)
+ {
+ DEBUG(5,("get_share_modes (FAST_SHARE_MODES): hash bucket %d empty\n", hash_entry));
+ return 0;
+ }
+
+ file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]);
+ file_prev_p = file_scanner_p;
+ while(file_scanner_p)
+ {
+ if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
+ {
+ found = True;
+ break;
+ }
+ else
+ {
+ file_prev_p = file_scanner_p ;
+ file_scanner_p = (share_mode_record *)shmops->offset2addr(
+ file_scanner_p->next_offset);
+ }
+ }
+
+ if(!found)
+ {
+ DEBUG(5,("get_share_modes (FAST_SHARE_MODES): no entry for \
+file dev = %d, ino = %d in hash_bucket %d\n", dev, inode, hash_entry));
+ return (0);
+ }
+
+ if(file_scanner_p->locking_version != LOCKING_VERSION)
+ {
+ DEBUG(0,("ERROR:get_share_modes (FAST_SHARE_MODES): Deleting old share mode \
+record due to old locking version %d for file dev = %d, inode = %d in hash \
+bucket %d\n", file_scanner_p->locking_version, dev, inode, hash_entry));
+ if(file_prev_p == file_scanner_p)
+ mode_array[hash_entry] = file_scanner_p->next_offset;
+ else
+ file_prev_p->next_offset = file_scanner_p->next_offset;
+ shmops->free(shmops->addr2offset(file_scanner_p));
+ return (0);
+ }
+
+ /* Allocate the old_shares array */
+ num_entries = file_scanner_p->num_share_mode_entries;
+ if(num_entries)
+ {
+ *old_shares = share_array = (share_mode_entry *)
+ malloc(num_entries * sizeof(share_mode_entry));
+ if(*old_shares == 0)
+ {
+ DEBUG(0,("get_share_modes (FAST_SHARE_MODES): malloc fail !\n"));
+ return 0;
+ }
+ }
+
+ num_entries_copied = 0;
+
+ entry_scanner_p = (shm_share_mode_entry*)shmops->offset2addr(
+ file_scanner_p->share_mode_entries);
+ entry_prev_p = entry_scanner_p;
+ while(entry_scanner_p)
+ {
+ int pid = entry_scanner_p->e.pid;
+
+ if (pid && !process_exists(pid))
+ {
+ /* Delete this share mode entry */
+ shm_share_mode_entry *delete_entry_p = entry_scanner_p;
+ int share_mode = entry_scanner_p->e.share_mode;
+
+ if(entry_prev_p == entry_scanner_p)
+ {
+ /* We are at start of list */
+ file_scanner_p->share_mode_entries = entry_scanner_p->next_share_mode_entry;
+ entry_scanner_p = (shm_share_mode_entry*)shmops->offset2addr(
+ file_scanner_p->share_mode_entries);
+ entry_prev_p = entry_scanner_p;
+ }
+ else
+ {
+ entry_prev_p->next_share_mode_entry = entry_scanner_p->next_share_mode_entry;
+ entry_scanner_p = (shm_share_mode_entry*)
+ shmops->offset2addr(entry_scanner_p->next_share_mode_entry);
+ }
+ /* Decrement the number of share mode entries on this share mode record */
+ file_scanner_p->num_share_mode_entries -= 1;
+
+ /* PARANOIA TEST */
+ if(file_scanner_p->num_share_mode_entries < 0)
+ {
+ DEBUG(0,("PANIC ERROR:get_share_mode (FAST_SHARE_MODES): num_share_mode_entries < 0 (%d) \
+for dev = %d, ino = %d, hashbucket %d\n", file_scanner_p->num_share_mode_entries,
+ dev, inode, hash_entry));
+ return 0;
+ }
+
+ DEBUG(0,("get_share_modes (FAST_SHARE_MODES): process %d no longer exists and \
+it left a share mode entry with mode 0x%X for file dev = %d, ino = %d in hash \
+bucket %d (number of entries now = %d)\n",
+ pid, share_mode, dev, inode, hash_entry,
+ file_scanner_p->num_share_mode_entries));
+
+ shmops->free(shmops->addr2offset(delete_entry_p));
+ }
+ else
+ {
+ /* This is a valid share mode entry and the process that
+ created it still exists. Copy it into the output array.
+ */
+ share_array[num_entries_copied].pid = entry_scanner_p->e.pid;
+ share_array[num_entries_copied].share_mode = entry_scanner_p->e.share_mode;
+ share_array[num_entries_copied].op_port = entry_scanner_p->e.op_port;
+ share_array[num_entries_copied].op_type = entry_scanner_p->e.op_type;
+ memcpy(&share_array[num_entries_copied].time, &entry_scanner_p->e.time,
+ sizeof(struct timeval));
+ num_entries_copied++;
+ DEBUG(5,("get_share_modes (FAST_SHARE_MODES): Read share mode \
+record mode 0x%X pid=%d\n", entry_scanner_p->e.share_mode, entry_scanner_p->e.pid));
+ entry_prev_p = entry_scanner_p;
+ entry_scanner_p = (shm_share_mode_entry *)
+ shmops->offset2addr(entry_scanner_p->next_share_mode_entry);
+ }
+ }
+
+ /* If no valid share mode entries were found then this record shouldn't exist ! */
+ if(num_entries_copied == 0)
+ {
+ DEBUG(0,("get_share_modes (FAST_SHARE_MODES): file with dev %d, inode %d in \
+hash bucket %d has a share mode record but no entries - deleting\n",
+ dev, inode, hash_entry));
+ if(*old_shares)
+ free((char *)*old_shares);
+ *old_shares = 0;
+
+ if(file_prev_p == file_scanner_p)
+ mode_array[hash_entry] = file_scanner_p->next_offset;
+ else
+ file_prev_p->next_offset = file_scanner_p->next_offset;
+ shmops->free(shmops->addr2offset(file_scanner_p));
+ }
+
+ DEBUG(5,("get_share_modes (FAST_SHARE_MODES): file with dev %d, inode %d in \
+hash bucket %d returning %d entries\n", dev, inode, hash_entry, num_entries_copied));
+
+ return(num_entries_copied);
+}
+
+/*******************************************************************
+del the share mode of a file.
+********************************************************************/
+static void shm_del_share_mode(int token, int fnum)
+{
+ uint32 dev, inode;
+ int *mode_array;
+ unsigned int hash_entry;
+ share_mode_record *file_scanner_p;
+ share_mode_record *file_prev_p;
+ shm_share_mode_entry *entry_scanner_p;
+ shm_share_mode_entry *entry_prev_p;
+ BOOL found = False;
+ int pid = getpid();
+
+ dev = Files[fnum].fd_ptr->dev;
+ inode = Files[fnum].fd_ptr->inode;
+
+ hash_entry = HASH_ENTRY(dev, inode);
+
+ mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
+
+ if(mode_array[hash_entry] == NULL_OFFSET)
+ {
+ DEBUG(0,("PANIC ERROR:del_share_mode (FAST_SHARE_MODES): hash bucket %d empty\n",
+ hash_entry));
+ return;
+ }
+
+ file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]);
+ file_prev_p = file_scanner_p;
+
+ while(file_scanner_p)
+ {
+ if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
+ {
+ found = True;
+ break;
+ }
+ else
+ {
+ file_prev_p = file_scanner_p ;
+ file_scanner_p = (share_mode_record *)
+ shmops->offset2addr(file_scanner_p->next_offset);
+ }
+ }
+
+ if(!found)
+ {
+ DEBUG(0,("ERROR:del_share_mode (FAST_SHARE_MODES): no entry found for dev %d, \
+inode %d in hash bucket %d\n", dev, inode, hash_entry));
+ return;
+ }
+
+ if(file_scanner_p->locking_version != LOCKING_VERSION)
+ {
+ DEBUG(0,("ERROR: del_share_modes (FAST_SHARE_MODES): Deleting old share mode \
+record due to old locking version %d for file dev %d, inode %d hash bucket %d\n",
+ file_scanner_p->locking_version, dev, inode, hash_entry ));
+ if(file_prev_p == file_scanner_p)
+ mode_array[hash_entry] = file_scanner_p->next_offset;
+ else
+ file_prev_p->next_offset = file_scanner_p->next_offset;
+ shmops->free(shmops->addr2offset(file_scanner_p));
+ return;
+ }
+
+ found = False;
+ entry_scanner_p = (shm_share_mode_entry*)shmops->offset2addr(
+ file_scanner_p->share_mode_entries);
+ entry_prev_p = entry_scanner_p;
+ while(entry_scanner_p)
+ {
+ if( (pid == entry_scanner_p->e.pid) &&
+ (memcmp(&entry_scanner_p->e.time,
+ &Files[fnum].open_time,sizeof(struct timeval)) == 0) )
+ {
+ found = True;
+ break;
+ }
+ else
+ {
+ entry_prev_p = entry_scanner_p;
+ entry_scanner_p = (shm_share_mode_entry *)
+ shmops->offset2addr(entry_scanner_p->next_share_mode_entry);
+ }
+ }
+
+ if (found)
+ {
+ /* Decrement the number of entries in the record. */
+ file_scanner_p->num_share_mode_entries -= 1;
+
+ DEBUG(2,("del_share_modes (FAST_SHARE_MODES): \
+Deleting share mode entry dev = %d, inode = %d in hash bucket %d (num entries now = %d)\n",
+ dev, inode, hash_entry, file_scanner_p->num_share_mode_entries));
+ if(entry_prev_p == entry_scanner_p)
+ /* We are at start of list */
+ file_scanner_p->share_mode_entries = entry_scanner_p->next_share_mode_entry;
+ else
+ entry_prev_p->next_share_mode_entry = entry_scanner_p->next_share_mode_entry;
+ shmops->free(shmops->addr2offset(entry_scanner_p));
+
+ /* PARANOIA TEST */
+ if(file_scanner_p->num_share_mode_entries < 0)
+ {
+ DEBUG(0,("PANIC ERROR:del_share_mode (FAST_SHARE_MODES): num_share_mode_entries < 0 (%d) \
+for dev = %d, ino = %d, hashbucket %d\n", file_scanner_p->num_share_mode_entries,
+ dev, inode, hash_entry));
+ return;
+ }
+
+ /* If we deleted the last share mode entry then remove the share mode record. */
+ if(file_scanner_p->num_share_mode_entries == 0)
+ {
+ DEBUG(2,("del_share_modes (FAST_SHARE_MODES): num entries = 0, deleting share_mode \
+record dev = %d, inode = %d in hash bucket %d\n", dev, inode, hash_entry));
+ if(file_prev_p == file_scanner_p)
+ mode_array[hash_entry] = file_scanner_p->next_offset;
+ else
+ file_prev_p->next_offset = file_scanner_p->next_offset;
+ shmops->free(shmops->addr2offset(file_scanner_p));
+ }
+ }
+ else
+ {
+ DEBUG(0,("ERROR: del_share_modes (FAST_SHARE_MODES): No share mode record found \
+dev = %d, inode = %d in hash bucket %d\n", dev, inode, hash_entry));
+ }
+}
+
+/*******************************************************************
+set the share mode of a file. Return False on fail, True on success.
+********************************************************************/
+static BOOL shm_set_share_mode(int token, int fnum, uint16 port, uint16 op_type)
+{
+ files_struct *fs_p = &Files[fnum];
+ int32 dev, inode;
+ int *mode_array;
+ unsigned int hash_entry;
+ share_mode_record *file_scanner_p;
+ share_mode_record *file_prev_p;
+ shm_share_mode_entry *new_entry_p;
+ int new_entry_offset;
+ BOOL found = False;
+
+ dev = fs_p->fd_ptr->dev;
+ inode = fs_p->fd_ptr->inode;
+
+ hash_entry = HASH_ENTRY(dev, inode);
+
+ mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
+
+ file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]);
+ file_prev_p = file_scanner_p;
+
+ while(file_scanner_p)
+ {
+ if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
+ {
+ found = True;
+ break;
+ }
+ else
+ {
+ file_prev_p = file_scanner_p ;
+ file_scanner_p = (share_mode_record *)
+ shmops->offset2addr(file_scanner_p->next_offset);
+ }
+ }
+
+ if(!found)
+ {
+ /* We must create a share_mode_record */
+ share_mode_record *new_mode_p = NULL;
+ int new_offset = shmops->alloc( sizeof(share_mode_record) +
+ strlen(fs_p->name) + 1);
+ if(new_offset == NULL_OFFSET)
+ {
+ DEBUG(0,("ERROR:set_share_mode (FAST_SHARE_MODES): shmops->alloc fail !\n"));
+ return False;
+ }
+ new_mode_p = shmops->offset2addr(new_offset);
+ new_mode_p->locking_version = LOCKING_VERSION;
+ new_mode_p->st_dev = dev;
+ new_mode_p->st_ino = inode;
+ new_mode_p->num_share_mode_entries = 0;
+ new_mode_p->share_mode_entries = NULL_OFFSET;
+ strcpy(new_mode_p->file_name, fs_p->name);
+
+ /* Chain onto the start of the hash chain (in the hope we will be used first). */
+ new_mode_p->next_offset = mode_array[hash_entry];
+ mode_array[hash_entry] = new_offset;
+
+ file_scanner_p = new_mode_p;
+
+ DEBUG(3,("set_share_mode (FAST_SHARE_MODES): Created share record for %s (dev %d \
+inode %d in hash bucket %d\n", fs_p->name, dev, inode, hash_entry));
+ }
+
+ /* Now create the share mode entry */
+ new_entry_offset = shmops->alloc( sizeof(shm_share_mode_entry));
+ if(new_entry_offset == NULL_OFFSET)
+ {
+ int delete_offset = mode_array[hash_entry];
+ DEBUG(0,("ERROR:set_share_mode (FAST_SHARE_MODES): shmops->alloc fail 1!\n"));
+ /* Unlink the damaged record */
+ mode_array[hash_entry] = file_scanner_p->next_offset;
+ /* And delete it */
+ shmops->free( delete_offset );
+ return False;
+ }
+
+ new_entry_p = shmops->offset2addr(new_entry_offset);
+
+ new_entry_p->e.pid = getpid();
+ new_entry_p->e.share_mode = fs_p->share_mode;
+ new_entry_p->e.op_port = port;
+ new_entry_p->e.op_type = op_type;
+ memcpy( (char *)&new_entry_p->e.time, (char *)&fs_p->open_time, sizeof(struct timeval));
+
+ /* Chain onto the share_mode_record */
+ new_entry_p->next_share_mode_entry = file_scanner_p->share_mode_entries;
+ file_scanner_p->share_mode_entries = new_entry_offset;
+
+ /* PARANOIA TEST */
+ if(file_scanner_p->num_share_mode_entries < 0)
+ {
+ DEBUG(0,("PANIC ERROR:set_share_mode (FAST_SHARE_MODES): num_share_mode_entries < 0 (%d) \
+for dev = %d, ino = %d, hashbucket %d\n", file_scanner_p->num_share_mode_entries,
+ dev, inode, hash_entry));
+ return False;
+ }
+
+ /* Increment the share_mode_entries counter */
+ file_scanner_p->num_share_mode_entries += 1;
+
+ DEBUG(3,("set_share_mode (FAST_SHARE_MODES): Created share entry for %s with mode \
+0x%X pid=%d (num_entries now = %d)\n",fs_p->name, fs_p->share_mode, new_entry_p->e.pid,
+ file_scanner_p->num_share_mode_entries));
+
+ return(True);
+}
+
+/*******************************************************************
+Remove an oplock port and mode entry from a share mode.
+********************************************************************/
+static BOOL shm_remove_share_oplock(int fnum, int token)
+{
+ uint32 dev, inode;
+ int *mode_array;
+ unsigned int hash_entry;
+ share_mode_record *file_scanner_p;
+ share_mode_record *file_prev_p;
+ shm_share_mode_entry *entry_scanner_p;
+ shm_share_mode_entry *entry_prev_p;
+ BOOL found = False;
+ int pid = getpid();
+
+ dev = Files[fnum].fd_ptr->dev;
+ inode = Files[fnum].fd_ptr->inode;
+
+ hash_entry = HASH_ENTRY(dev, inode);
+
+ mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
+
+ if(mode_array[hash_entry] == NULL_OFFSET)
+ {
+ DEBUG(0,("PANIC ERROR:remove_share_oplock (FAST_SHARE_MODES): hash bucket %d empty\n",
+ hash_entry));
+ return False;
+ }
+
+ file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]);
+ file_prev_p = file_scanner_p;
+
+ while(file_scanner_p)
+ {
+ if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
+ {
+ found = True;
+ break;
+ }
+ else
+ {
+ file_prev_p = file_scanner_p ;
+ file_scanner_p = (share_mode_record *)
+ shmops->offset2addr(file_scanner_p->next_offset);
+ }
+ }
+
+ if(!found)
+ {
+ DEBUG(0,("ERROR:remove_share_oplock (FAST_SHARE_MODES): no entry found for dev %d, \
+inode %d in hash bucket %d\n", dev, inode, hash_entry));
+ return False;
+ }
+
+ if(file_scanner_p->locking_version != LOCKING_VERSION)
+ {
+ DEBUG(0,("ERROR: remove_share_oplock (FAST_SHARE_MODES): Deleting old share mode \
+record due to old locking version %d for file dev %d, inode %d hash bucket %d\n",
+ file_scanner_p->locking_version, dev, inode, hash_entry ));
+ if(file_prev_p == file_scanner_p)
+ mode_array[hash_entry] = file_scanner_p->next_offset;
+ else
+ file_prev_p->next_offset = file_scanner_p->next_offset;
+ shmops->free(shmops->addr2offset(file_scanner_p));
+ return False;
+ }
+
+ found = False;
+ entry_scanner_p = (shm_share_mode_entry*)shmops->offset2addr(
+ file_scanner_p->share_mode_entries);
+ entry_prev_p = entry_scanner_p;
+ while(entry_scanner_p)
+ {
+ if( (pid == entry_scanner_p->e.pid) &&
+ (entry_scanner_p->e.share_mode == Files[fnum].share_mode) &&
+ (memcmp(&entry_scanner_p->e.time,
+ &Files[fnum].open_time,sizeof(struct timeval)) == 0) )
+ {
+ /* Delete the oplock info. */
+ entry_scanner_p->e.op_port = 0;
+ entry_scanner_p->e.op_type = 0;
+ found = True;
+ break;
+ }
+ else
+ {
+ entry_prev_p = entry_scanner_p;
+ entry_scanner_p = (shm_share_mode_entry *)
+ shmops->offset2addr(entry_scanner_p->next_share_mode_entry);
+ }
+ }
+
+ if(!found)
+ {
+ DEBUG(0,("ERROR: remove_share_oplock (FAST_SHARE_MODES): No oplock granted share \
+mode record found dev = %d, inode = %d in hash bucket %d\n", dev, inode, hash_entry));
+ return False;
+ }
+
+ return True;
+}
+
+
+/*******************************************************************
+call the specified function on each entry under management by the
+share mode system
+********************************************************************/
+static int shm_share_forall(void (*fn)(share_mode_entry *, char *))
+{
+ int i, count=0;
+ int *mode_array;
+ share_mode_record *file_scanner_p;
+
+ mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
+
+ for( i = 0; i < shmops->hash_size(); i++) {
+ shmops->lock_hash_entry(i);
+ if(mode_array[i] == NULL_OFFSET) {
+ shmops->unlock_hash_entry(i);
+ continue;
+ }
+
+ file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[i]);
+ while((file_scanner_p != 0) &&
+ (file_scanner_p->num_share_mode_entries != 0)) {
+ shm_share_mode_entry *entry_scanner_p =
+ (shm_share_mode_entry *)
+ shmops->offset2addr(file_scanner_p->share_mode_entries);
+
+ while(entry_scanner_p != 0) {
+
+ fn(&entry_scanner_p->e,
+ file_scanner_p->file_name);
+
+ entry_scanner_p =
+ (shm_share_mode_entry *)
+ shmops->offset2addr(
+ entry_scanner_p->next_share_mode_entry);
+ count++;
+ } /* end while entry_scanner_p */
+ file_scanner_p = (share_mode_record *)
+ shmops->offset2addr(file_scanner_p->next_offset);
+ } /* end while file_scanner_p */
+ shmops->unlock_hash_entry(i);
+ } /* end for */
+
+ return count;
+}
+
+
+/*******************************************************************
+dump the state of the system
+********************************************************************/
+static void shm_share_status(FILE *f)
+{
+ int bytes_free, bytes_used, bytes_overhead, bytes_total;
+
+ shmops->get_usage(&bytes_free, &bytes_used, &bytes_overhead);
+ bytes_total = bytes_free + bytes_used + bytes_overhead;
+
+ fprintf(f, "Share mode memory usage (bytes):\n");
+ fprintf(f, " %d(%d%%) free + %d(%d%%) used + %d(%d%%) overhead = %d(100%%) total\n",
+ bytes_free, (bytes_free * 100)/bytes_total,
+ bytes_used, (bytes_used * 100)/bytes_total,
+ bytes_overhead, (bytes_overhead * 100)/bytes_total,
+ bytes_total);
+}
+
+
+static struct share_ops share_ops = {
+ shm_stop_share_mode_mgmt,
+ shm_lock_share_entry,
+ shm_unlock_share_entry,
+ shm_get_share_modes,
+ shm_del_share_mode,
+ shm_set_share_mode,
+ shm_remove_share_oplock,
+ shm_share_forall,
+ shm_share_status,
+};
+
+/*******************************************************************
+ initialize the shared memory for share_mode management
+ ******************************************************************/
+struct share_ops *locking_shm_init(int ronly)
+{
+ pstring shmem_file_name;
+
+ read_only = ronly;
+
+#ifdef USE_SYSV_IPC
+ shmops = sysv_shm_open(read_only);
+ if (shmops) return &share_ops;
+#endif
+
+ shmops = smb_shm_open(read_only);
+ if (shmops) return &share_ops;
+
+ return NULL;
+}
+
+#else
+ int locking_shm_dummy_procedure(void)
+{return 0;}
+#endif
+
+
+
diff --git a/source/locking/locking_slow.c b/source/locking/locking_slow.c
new file mode 100644
index 00000000000..9bd6d65aa79
--- /dev/null
+++ b/source/locking/locking_slow.c
@@ -0,0 +1,1050 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ slow (lockfile) locking implementation
+ Copyright (C) Andrew Tridgell 1992-1997
+
+ 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:
+
+ 12 aug 96: Erik.Devriendt@te6.siemens.be
+ added support for shared memory implementation of share mode locking
+
+ May 1997. Jeremy Allison (jallison@whistle.com). Modified share mode
+ locking to deal with multiple share modes per open file.
+
+ September 1997. Jeremy Allison (jallison@whistle.com). Added oplock
+ support.
+
+ October 1997 - split into separate file (tridge)
+*/
+
+#include "includes.h"
+extern int DEBUGLEVEL;
+extern connection_struct Connections[];
+extern files_struct Files[];
+
+/*
+ * Locking file header lengths & offsets.
+ */
+#define SMF_VERSION_OFFSET 0
+#define SMF_NUM_ENTRIES_OFFSET 4
+#define SMF_FILENAME_LEN_OFFSET 8
+#define SMF_HEADER_LENGTH 10
+
+#define SMF_ENTRY_LENGTH 20
+
+/*
+ * Share mode record offsets.
+ */
+
+#define SME_SEC_OFFSET 0
+#define SME_USEC_OFFSET 4
+#define SME_SHAREMODE_OFFSET 8
+#define SME_PID_OFFSET 12
+#define SME_PORT_OFFSET 16
+#define SME_OPLOCK_TYPE_OFFSET 18
+
+/* we need world read for smbstatus to function correctly */
+#ifdef SECURE_SHARE_MODES
+#define SHARE_FILE_MODE 0600
+#else
+#define SHARE_FILE_MODE 0644
+#endif
+
+static int read_only;
+
+/*******************************************************************
+ deinitialize share_mode management
+ ******************************************************************/
+static BOOL slow_stop_share_mode_mgmt(void)
+{
+ return True;
+}
+
+
+/*******************************************************************
+ name a share file
+ ******************************************************************/
+static BOOL share_name(int cnum, uint32 dev, uint32 inode, char *name)
+{
+ strcpy(name,lp_lockdir());
+ trim_string(name,"","/");
+ if (!*name) return(False);
+ name += strlen(name);
+
+ sprintf(name,"/share.%u.%u",dev,inode);
+ return(True);
+}
+
+/*******************************************************************
+Force a share file to be deleted.
+********************************************************************/
+static int delete_share_file( int cnum, char *fname )
+{
+ if (read_only) return -1;
+
+ /* the share file could be owned by anyone, so do this as root */
+ become_root(False);
+
+ if(unlink(fname) != 0)
+ {
+ DEBUG(0,("delete_share_file: Can't delete share file %s (%s)\n",
+ fname, strerror(errno)));
+ }
+ else
+ {
+ DEBUG(5,("delete_share_file: Deleted share file %s\n", fname));
+ }
+
+ /* return to our previous privilage level */
+ unbecome_root(False);
+
+ return 0;
+}
+
+/*******************************************************************
+ lock a share mode file.
+ ******************************************************************/
+static BOOL slow_lock_share_entry(int cnum, uint32 dev, uint32 inode, int *ptok)
+{
+ pstring fname;
+ int fd;
+ int ret = True;
+
+ *ptok = (int)-1;
+
+ if(!share_name(cnum, dev, inode, fname))
+ return False;
+
+ if (read_only) return True;
+
+ /* we need to do this as root */
+ become_root(False);
+
+ {
+ BOOL gotlock = False;
+ /*
+ * There was a race condition in the original slow share mode code.
+ * A smbd could open a share mode file, and before getting
+ * the lock, another smbd could delete the last entry for
+ * the share mode file and delete the file entry from the
+ * directory. Thus this smbd would be left with a locked
+ * share mode fd attached to a file that no longer had a
+ * directory entry. Thus another smbd would think that
+ * there were no outstanding opens on the file. To fix
+ * this we now check we can do a stat() call on the filename
+ * before allowing the lock to proceed, and back out completely
+ * and try the open again if we cannot.
+ * Jeremy Allison (jallison@whistle.com).
+ */
+
+ do
+ {
+ struct stat dummy_stat;
+
+ fd = (int)open(fname,read_only?O_RDONLY:(O_RDWR|O_CREAT),
+ SHARE_FILE_MODE);
+
+ if(fd < 0)
+ {
+ DEBUG(0,("ERROR lock_share_entry: failed to open share file %s. Error was %s\n",
+ fname, strerror(errno)));
+ ret = False;
+ break;
+ }
+
+ /* At this point we have an open fd to the share mode file.
+ Lock the first byte exclusively to signify a lock. */
+ if(fcntl_lock(fd, F_SETLKW, 0, 1, F_WRLCK) == False)
+ {
+ DEBUG(0,("ERROR lock_share_entry: fcntl_lock on file %s failed with %s\n",
+ fname, strerror(errno)));
+ close(fd);
+ ret = False;
+ break;
+ }
+
+ /*
+ * If we cannot stat the filename, the file was deleted between
+ * the open and the lock call. Back out and try again.
+ */
+
+ if(stat(fname, &dummy_stat)!=0)
+ {
+ DEBUG(2,("lock_share_entry: Re-issuing open on %s to fix race. Error was %s\n",
+ fname, strerror(errno)));
+ close(fd);
+ }
+ else
+ gotlock = True;
+ } while(!gotlock);
+
+ /*
+ * We have to come here if any of the above calls fail
+ * as we don't want to return and leave ourselves running
+ * as root !
+ */
+ }
+
+ *ptok = (int)fd;
+
+ /* return to our previous privilage level */
+ unbecome_root(False);
+
+ return ret;
+}
+
+/*******************************************************************
+ unlock a share mode file.
+ ******************************************************************/
+static BOOL slow_unlock_share_entry(int cnum, uint32 dev, uint32 inode, int token)
+{
+ int fd = (int)token;
+ int ret = True;
+ struct stat sb;
+ pstring fname;
+
+ if (read_only) return True;
+
+ /* Fix for zero length share files from
+ Gerald Werner <wernerg@mfldclin.edu> */
+
+ share_name(cnum, dev, inode, fname);
+
+ /* get the share mode file size */
+ if(fstat((int)token, &sb) != 0)
+ {
+ DEBUG(0,("ERROR: unlock_share_entry: Failed to do stat on share file %s (%s)\n",
+ fname, strerror(errno)));
+ sb.st_size = 1;
+ ret = False;
+ }
+
+ /* If the file was zero length, we must delete before
+ doing the unlock to avoid a race condition (see
+ the code in lock_share_mode_entry for details.
+ */
+
+ /* remove the share file if zero length */
+ if(sb.st_size == 0)
+ delete_share_file(cnum, fname);
+
+ /* token is the fd of the open share mode file. */
+ /* Unlock the first byte. */
+ if(fcntl_lock(fd, F_SETLKW, 0, 1, F_UNLCK) == False)
+ {
+ DEBUG(0,("ERROR unlock_share_entry: fcntl_lock failed with %s\n",
+ strerror(errno)));
+ ret = False;
+ }
+
+ close(fd);
+ return ret;
+}
+
+/*******************************************************************
+Read a share file into a buffer.
+********************************************************************/
+static int read_share_file(int cnum, int fd, char *fname, char **out, BOOL *p_new_file)
+{
+ struct stat sb;
+ char *buf;
+ int size;
+
+ *out = 0;
+ *p_new_file = False;
+
+ if(fstat(fd, &sb) != 0)
+ {
+ DEBUG(0,("ERROR: read_share_file: Failed to do stat on share file %s (%s)\n",
+ fname, strerror(errno)));
+ return -1;
+ }
+
+ if(sb.st_size == 0)
+ {
+ *p_new_file = True;
+ return 0;
+ }
+
+ /* Allocate space for the file */
+ if((buf = (char *)malloc(sb.st_size)) == NULL)
+ {
+ DEBUG(0,("read_share_file: malloc for file size %d fail !\n", sb.st_size));
+ return -1;
+ }
+
+ if(lseek(fd, 0, SEEK_SET) != 0)
+ {
+ DEBUG(0,("ERROR: read_share_file: Failed to reset position to 0 \
+for share file %s (%s)\n", fname, strerror(errno)));
+ if(buf)
+ free(buf);
+ return -1;
+ }
+
+ if (read(fd,buf,sb.st_size) != sb.st_size)
+ {
+ DEBUG(0,("ERROR: read_share_file: Failed to read share file %s (%s)\n",
+ fname, strerror(errno)));
+ if(buf)
+ free(buf);
+ return -1;
+ }
+
+ if (IVAL(buf,SMF_VERSION_OFFSET) != LOCKING_VERSION) {
+ DEBUG(0,("ERROR: read_share_file: share file %s has incorrect \
+locking version (was %d, should be %d).\n",fname,
+ IVAL(buf,SMF_VERSION_OFFSET), LOCKING_VERSION));
+ if(buf)
+ free(buf);
+ delete_share_file(cnum, fname);
+ return -1;
+ }
+
+ /* Sanity check for file contents */
+ size = sb.st_size;
+ size -= SMF_HEADER_LENGTH; /* Remove the header */
+
+ /* Remove the filename component. */
+ size -= SVAL(buf, SMF_FILENAME_LEN_OFFSET);
+
+ /* The remaining size must be a multiple of SMF_ENTRY_LENGTH - error if not. */
+ if((size % SMF_ENTRY_LENGTH) != 0)
+ {
+ DEBUG(0,("ERROR: read_share_file: share file %s is an incorrect length - \
+deleting it.\n", fname));
+ if(buf)
+ free(buf);
+ delete_share_file(cnum, fname);
+ return -1;
+ }
+
+ *out = buf;
+ return 0;
+}
+
+/*******************************************************************
+get all share mode entries in a share file for a dev/inode pair.
+********************************************************************/
+static int slow_get_share_modes(int cnum, int token, uint32 dev, uint32 inode,
+ share_mode_entry **old_shares)
+{
+ int fd = (int)token;
+ pstring fname;
+ int i;
+ int num_entries;
+ int num_entries_copied;
+ int newsize;
+ share_mode_entry *share_array;
+ char *buf = 0;
+ char *base = 0;
+ BOOL new_file;
+
+ *old_shares = 0;
+
+ /* Read the share file header - this is of the form:
+ 0 - locking version.
+ 4 - number of share mode entries.
+ 8 - 2 byte name length
+ [n bytes] file name (zero terminated).
+
+ Followed by <n> share mode entries of the form :
+
+ 0 - tv_sec
+ 4 - tv_usec
+ 8 - share_mode
+ 12 - pid
+ 16 - oplock port (if oplocks in use) - 2 bytes.
+ */
+
+ share_name(cnum, dev, inode, fname);
+
+ if(read_share_file( cnum, fd, fname, &buf, &new_file) != 0)
+ {
+ DEBUG(0,("ERROR: get_share_modes: Failed to read share file %s\n",
+ fname));
+ return 0;
+ }
+
+ if(new_file == True)
+ return 0;
+
+ num_entries = IVAL(buf,SMF_NUM_ENTRIES_OFFSET);
+
+ DEBUG(5,("get_share_modes: share file %s has %d share mode entries.\n",
+ fname, num_entries));
+
+ /* PARANOIA TEST */
+ if(num_entries < 0)
+ {
+ DEBUG(0,("PANIC ERROR:get_share_mode: num_share_mode_entries < 0 (%d) \
+for share file %d\n", num_entries, fname));
+ return 0;
+ }
+
+ if(num_entries)
+ {
+ *old_shares = share_array = (share_mode_entry *)
+ malloc(num_entries * sizeof(share_mode_entry));
+ if(*old_shares == 0)
+ {
+ DEBUG(0,("get_share_modes: malloc fail !\n"));
+ return 0;
+ }
+ }
+ else
+ {
+ /* No entries - just delete the file. */
+ DEBUG(0,("get_share_modes: share file %s has no share mode entries - deleting.\n",
+ fname));
+ if(buf)
+ free(buf);
+ delete_share_file(cnum, fname);
+ return 0;
+ }
+
+ num_entries_copied = 0;
+ base = buf + SMF_HEADER_LENGTH + SVAL(buf,SMF_FILENAME_LEN_OFFSET);
+
+ for( i = 0; i < num_entries; i++)
+ {
+ int pid;
+ char *p = base + (i*SMF_ENTRY_LENGTH);
+
+ pid = IVAL(p,SME_PID_OFFSET);
+
+ if(!process_exists(pid))
+ {
+ DEBUG(0,("get_share_modes: process %d no longer exists and \
+it left a share mode entry with mode 0x%X in share file %s\n",
+ pid, IVAL(p,SME_SHAREMODE_OFFSET), fname));
+ continue;
+ }
+ share_array[num_entries_copied].time.tv_sec = IVAL(p,SME_SEC_OFFSET);
+ share_array[num_entries_copied].time.tv_usec = IVAL(p,SME_USEC_OFFSET);
+ share_array[num_entries_copied].share_mode = IVAL(p,SME_SHAREMODE_OFFSET);
+ share_array[num_entries_copied].pid = pid;
+ share_array[num_entries_copied].op_port = SVAL(p,SME_PORT_OFFSET);
+ share_array[num_entries_copied].op_type = SVAL(p,SME_OPLOCK_TYPE_OFFSET);
+
+ num_entries_copied++;
+ }
+
+ if(num_entries_copied == 0)
+ {
+ /* Delete the whole file. */
+ DEBUG(0,("get_share_modes: share file %s had no valid entries - deleting it !\n",
+ fname));
+ if(*old_shares)
+ free((char *)*old_shares);
+ *old_shares = 0;
+ if(buf)
+ free(buf);
+ delete_share_file(cnum, fname);
+ return 0;
+ }
+
+ /* If we deleted some entries we need to re-write the whole number of
+ share mode entries back into the file. */
+
+ if(num_entries_copied != num_entries)
+ {
+ if(lseek(fd, 0, SEEK_SET) != 0)
+ {
+ DEBUG(0,("ERROR: get_share_modes: lseek failed to reset to \
+position 0 for share mode file %s (%s)\n", fname, strerror(errno)));
+ if(*old_shares)
+ free((char *)*old_shares);
+ *old_shares = 0;
+ if(buf)
+ free(buf);
+ return 0;
+ }
+
+ SIVAL(buf, SMF_NUM_ENTRIES_OFFSET, num_entries_copied);
+ for( i = 0; i < num_entries_copied; i++)
+ {
+ char *p = base + (i*SMF_ENTRY_LENGTH);
+
+ SIVAL(p,SME_PID_OFFSET,share_array[i].pid);
+ SIVAL(p,SME_SHAREMODE_OFFSET,share_array[i].share_mode);
+ SIVAL(p,SME_SEC_OFFSET,share_array[i].time.tv_sec);
+ SIVAL(p,SME_USEC_OFFSET,share_array[i].time.tv_usec);
+ SSVAL(p,SME_PORT_OFFSET,share_array[i].op_port);
+ SSVAL(p,SME_OPLOCK_TYPE_OFFSET,share_array[i].op_type);
+ }
+
+ newsize = (base - buf) + (SMF_ENTRY_LENGTH*num_entries_copied);
+ if(write(fd, buf, newsize) != newsize)
+ {
+ DEBUG(0,("ERROR: get_share_modes: failed to re-write share \
+mode file %s (%s)\n", fname, strerror(errno)));
+ if(*old_shares)
+ free((char *)*old_shares);
+ *old_shares = 0;
+ if(buf)
+ free(buf);
+ return 0;
+ }
+ /* Now truncate the file at this point. */
+ if(ftruncate(fd, newsize)!= 0)
+ {
+ DEBUG(0,("ERROR: get_share_modes: failed to ftruncate share \
+mode file %s to size %d (%s)\n", fname, newsize, strerror(errno)));
+ if(*old_shares)
+ free((char *)*old_shares);
+ *old_shares = 0;
+ if(buf)
+ free(buf);
+ return 0;
+ }
+ }
+
+ if(buf)
+ free(buf);
+
+ DEBUG(5,("get_share_modes: Read share file %s returning %d entries\n",fname,
+ num_entries_copied));
+
+ return num_entries_copied;
+}
+
+/*******************************************************************
+del a share mode from a share mode file.
+********************************************************************/
+static void slow_del_share_mode(int token, int fnum)
+{
+ pstring fname;
+ int fd = (int)token;
+ char *buf = 0;
+ char *base = 0;
+ int num_entries;
+ int newsize;
+ int i;
+ files_struct *fs_p = &Files[fnum];
+ int pid;
+ BOOL deleted = False;
+ BOOL new_file;
+
+ share_name(fs_p->cnum, fs_p->fd_ptr->dev,
+ fs_p->fd_ptr->inode, fname);
+
+ if(read_share_file( fs_p->cnum, fd, fname, &buf, &new_file) != 0)
+ {
+ DEBUG(0,("ERROR: del_share_mode: Failed to read share file %s\n",
+ fname));
+ return;
+ }
+
+ if(new_file == True)
+ {
+ DEBUG(0,("ERROR:del_share_mode: share file %s is new (size zero), deleting it.\n",
+ fname));
+ delete_share_file(fs_p->cnum, fname);
+ return;
+ }
+
+ num_entries = IVAL(buf,SMF_NUM_ENTRIES_OFFSET);
+
+ DEBUG(5,("del_share_mode: share file %s has %d share mode entries.\n",
+ fname, num_entries));
+
+ /* PARANOIA TEST */
+ if(num_entries < 0)
+ {
+ DEBUG(0,("PANIC ERROR:del_share_mode: num_share_mode_entries < 0 (%d) \
+for share file %d\n", num_entries, fname));
+ return;
+ }
+
+ if(num_entries == 0)
+ {
+ /* No entries - just delete the file. */
+ DEBUG(0,("del_share_mode: share file %s has no share mode entries - deleting.\n",
+ fname));
+ if(buf)
+ free(buf);
+ delete_share_file(fs_p->cnum, fname);
+ return;
+ }
+
+ pid = getpid();
+
+ /* Go through the entries looking for the particular one
+ we have set - delete it.
+ */
+
+ base = buf + SMF_HEADER_LENGTH + SVAL(buf,SMF_FILENAME_LEN_OFFSET);
+
+ for(i = 0; i < num_entries; i++)
+ {
+ char *p = base + (i*SMF_ENTRY_LENGTH);
+
+ if((IVAL(p,SME_SEC_OFFSET) != fs_p->open_time.tv_sec) ||
+ (IVAL(p,SME_USEC_OFFSET) != fs_p->open_time.tv_usec) ||
+ (IVAL(p,SME_SHAREMODE_OFFSET) != fs_p->share_mode) ||
+ (IVAL(p,SME_PID_OFFSET) != pid))
+ continue;
+
+ DEBUG(5,("del_share_mode: deleting entry number %d (of %d) from the share file %s\n",
+ i, num_entries, fname));
+
+ /* Remove this entry. */
+ if(i != num_entries - 1)
+ memcpy(p, p + SMF_ENTRY_LENGTH, (num_entries - i - 1)*SMF_ENTRY_LENGTH);
+
+ deleted = True;
+ break;
+ }
+
+ if(!deleted)
+ {
+ DEBUG(0,("del_share_mode: entry not found in share file %s\n", fname));
+ if(buf)
+ free(buf);
+ return;
+ }
+
+ num_entries--;
+ SIVAL(buf,SMF_NUM_ENTRIES_OFFSET, num_entries);
+
+ if(num_entries == 0)
+ {
+ /* Deleted the last entry - remove the file. */
+ DEBUG(5,("del_share_mode: removed last entry in share file - deleting share file %s\n",
+ fname));
+ if(buf)
+ free(buf);
+ delete_share_file(fs_p->cnum,fname);
+ return;
+ }
+
+ /* Re-write the file - and truncate it at the correct point. */
+ if(lseek(fd, 0, SEEK_SET) != 0)
+ {
+ DEBUG(0,("ERROR: del_share_mode: lseek failed to reset to \
+position 0 for share mode file %s (%s)\n", fname, strerror(errno)));
+ if(buf)
+ free(buf);
+ return;
+ }
+
+ newsize = (base - buf) + (SMF_ENTRY_LENGTH*num_entries);
+ if(write(fd, buf, newsize) != newsize)
+ {
+ DEBUG(0,("ERROR: del_share_mode: failed to re-write share \
+mode file %s (%s)\n", fname, strerror(errno)));
+ if(buf)
+ free(buf);
+ return;
+ }
+ /* Now truncate the file at this point. */
+ if(ftruncate(fd, newsize) != 0)
+ {
+ DEBUG(0,("ERROR: del_share_mode: failed to ftruncate share \
+mode file %s to size %d (%s)\n", fname, newsize, strerror(errno)));
+ if(buf)
+ free(buf);
+ return;
+ }
+}
+
+/*******************************************************************
+set the share mode of a file
+********************************************************************/
+static BOOL slow_set_share_mode(int token,int fnum, uint16 port, uint16 op_type)
+{
+ files_struct *fs_p = &Files[fnum];
+ pstring fname;
+ int fd = (int)token;
+ int pid = (int)getpid();
+ struct stat sb;
+ char *buf;
+ int num_entries;
+ int header_size;
+ char *p;
+
+ share_name(fs_p->cnum, fs_p->fd_ptr->dev,
+ fs_p->fd_ptr->inode, fname);
+
+ if(fstat(fd, &sb) != 0)
+ {
+ DEBUG(0,("ERROR: set_share_mode: Failed to do stat on share file %s\n",
+ fname));
+ return False;
+ }
+
+ /* Sanity check for file contents (if it's not a new share file). */
+ if(sb.st_size != 0)
+ {
+ int size = sb.st_size;
+
+ /* Allocate space for the file plus one extra entry */
+ if((buf = (char *)malloc(sb.st_size + SMF_ENTRY_LENGTH)) == NULL)
+ {
+ DEBUG(0,("set_share_mode: malloc for file size %d fail !\n",
+ sb.st_size + SMF_ENTRY_LENGTH));
+ return False;
+ }
+
+ if(lseek(fd, 0, SEEK_SET) != 0)
+ {
+ DEBUG(0,("ERROR: set_share_mode: Failed to reset position \
+to 0 for share file %s (%s)\n", fname, strerror(errno)));
+ if(buf)
+ free(buf);
+ return False;
+ }
+
+ if (read(fd,buf,sb.st_size) != sb.st_size)
+ {
+ DEBUG(0,("ERROR: set_share_mode: Failed to read share file %s (%s)\n",
+ fname, strerror(errno)));
+ if(buf)
+ free(buf);
+ return False;
+ }
+
+ if (IVAL(buf,SMF_VERSION_OFFSET) != LOCKING_VERSION)
+ {
+ DEBUG(0,("ERROR: set_share_mode: share file %s has incorrect \
+locking version (was %d, should be %d).\n",fname, IVAL(buf,SMF_VERSION_OFFSET),
+ LOCKING_VERSION));
+ if(buf)
+ free(buf);
+ delete_share_file(fs_p->cnum, fname);
+ return False;
+ }
+
+ size -= (SMF_HEADER_LENGTH + SVAL(buf, SMF_FILENAME_LEN_OFFSET)); /* Remove the header */
+
+ /* The remaining size must be a multiple of SMF_ENTRY_LENGTH - error if not. */
+ if((size % SMF_ENTRY_LENGTH) != 0)
+ {
+ DEBUG(0,("ERROR: set_share_mode: share file %s is an incorrect length - \
+deleting it.\n", fname));
+ if(buf)
+ free(buf);
+ delete_share_file(fs_p->cnum, fname);
+ return False;
+ }
+
+ }
+ else
+ {
+ /* New file - just use a single_entry. */
+ if((buf = (char *)malloc(SMF_HEADER_LENGTH +
+ strlen(fs_p->name) + 1 + SMF_ENTRY_LENGTH)) == NULL)
+ {
+ DEBUG(0,("ERROR: set_share_mode: malloc failed for single entry.\n"));
+ return False;
+ }
+ SIVAL(buf,SMF_VERSION_OFFSET,LOCKING_VERSION);
+ SIVAL(buf,SMF_NUM_ENTRIES_OFFSET,0);
+ SSVAL(buf,SMF_FILENAME_LEN_OFFSET,strlen(fs_p->name) + 1);
+ strcpy(buf + SMF_HEADER_LENGTH, fs_p->name);
+ }
+
+ num_entries = IVAL(buf,SMF_NUM_ENTRIES_OFFSET);
+ header_size = SMF_HEADER_LENGTH + SVAL(buf,SMF_FILENAME_LEN_OFFSET);
+ p = buf + header_size + (num_entries * SMF_ENTRY_LENGTH);
+ SIVAL(p,SME_SEC_OFFSET,fs_p->open_time.tv_sec);
+ SIVAL(p,SME_USEC_OFFSET,fs_p->open_time.tv_usec);
+ SIVAL(p,SME_SHAREMODE_OFFSET,fs_p->share_mode);
+ SIVAL(p,SME_PID_OFFSET,pid);
+ SSVAL(p,SME_PORT_OFFSET,port);
+ SSVAL(p,SME_OPLOCK_TYPE_OFFSET,op_type);
+
+ num_entries++;
+
+ SIVAL(buf,SMF_NUM_ENTRIES_OFFSET,num_entries);
+
+ if(lseek(fd, 0, SEEK_SET) != 0)
+ {
+ DEBUG(0,("ERROR: set_share_mode: (1) Failed to reset position to \
+0 for share file %s (%s)\n", fname, strerror(errno)));
+ if(buf)
+ free(buf);
+ return False;
+ }
+
+ if (write(fd,buf,header_size + (num_entries*SMF_ENTRY_LENGTH)) !=
+ (header_size + (num_entries*SMF_ENTRY_LENGTH)))
+ {
+ DEBUG(2,("ERROR: set_share_mode: Failed to write share file %s - \
+deleting it (%s).\n",fname, strerror(errno)));
+ delete_share_file(fs_p->cnum, fname);
+ if(buf)
+ free(buf);
+ return False;
+ }
+
+ /* Now truncate the file at this point - just for safety. */
+ if(ftruncate(fd, header_size + (SMF_ENTRY_LENGTH*num_entries))!= 0)
+ {
+ DEBUG(0,("ERROR: set_share_mode: failed to ftruncate share \
+mode file %s to size %d (%s)\n", fname, header_size + (SMF_ENTRY_LENGTH*num_entries),
+ strerror(errno)));
+ if(buf)
+ free(buf);
+ return False;
+ }
+
+ if(buf)
+ free(buf);
+
+ DEBUG(3,("set_share_mode: Created share file %s with \
+mode 0x%X pid=%d\n",fname,fs_p->share_mode,pid));
+
+ return True;
+}
+
+/*******************************************************************
+Remove an oplock port and mode entry from a share mode.
+********************************************************************/
+static BOOL slow_remove_share_oplock(int fnum, int token)
+{
+ pstring fname;
+ int fd = (int)token;
+ char *buf = 0;
+ char *base = 0;
+ int num_entries;
+ int fsize;
+ int i;
+ files_struct *fs_p = &Files[fnum];
+ int pid;
+ BOOL found = False;
+ BOOL new_file;
+
+ share_name(fs_p->cnum, fs_p->fd_ptr->dev,
+ fs_p->fd_ptr->inode, fname);
+
+ if(read_share_file( fs_p->cnum, fd, fname, &buf, &new_file) != 0)
+ {
+ DEBUG(0,("ERROR: remove_share_oplock: Failed to read share file %s\n",
+ fname));
+ return False;
+ }
+
+ if(new_file == True)
+ {
+ DEBUG(0,("ERROR: remove_share_oplock: share file %s is new (size zero), \
+deleting it.\n", fname));
+ delete_share_file(fs_p->cnum, fname);
+ return False;
+ }
+
+ num_entries = IVAL(buf,SMF_NUM_ENTRIES_OFFSET);
+
+ DEBUG(5,("remove_share_oplock: share file %s has %d share mode entries.\n",
+ fname, num_entries));
+
+ /* PARANOIA TEST */
+ if(num_entries < 0)
+ {
+ DEBUG(0,("PANIC ERROR:remove_share_oplock: num_share_mode_entries < 0 (%d) \
+for share file %d\n", num_entries, fname));
+ return False;
+ }
+
+ if(num_entries == 0)
+ {
+ /* No entries - just delete the file. */
+ DEBUG(0,("remove_share_oplock: share file %s has no share mode entries - deleting.\n",
+ fname));
+ if(buf)
+ free(buf);
+ delete_share_file(fs_p->cnum, fname);
+ return False;
+ }
+
+ pid = getpid();
+
+ /* Go through the entries looking for the particular one
+ we have set - remove the oplock settings on it.
+ */
+
+ base = buf + SMF_HEADER_LENGTH + SVAL(buf,SMF_FILENAME_LEN_OFFSET);
+
+ for(i = 0; i < num_entries; i++)
+ {
+ char *p = base + (i*SMF_ENTRY_LENGTH);
+
+ if((IVAL(p,SME_SEC_OFFSET) != fs_p->open_time.tv_sec) ||
+ (IVAL(p,SME_USEC_OFFSET) != fs_p->open_time.tv_usec) ||
+ (IVAL(p,SME_SHAREMODE_OFFSET) != fs_p->share_mode) ||
+ (IVAL(p,SME_PID_OFFSET) != pid))
+ continue;
+
+ DEBUG(5,("remove_share_oplock: clearing oplock on entry number %d (of %d) \
+from the share file %s\n", i, num_entries, fname));
+
+ SSVAL(p,SME_PORT_OFFSET,0);
+ SSVAL(p,SME_OPLOCK_TYPE_OFFSET,0);
+ found = True;
+ break;
+ }
+
+ if(!found)
+ {
+ DEBUG(0,("remove_share_oplock: entry not found in share file %s\n", fname));
+ if(buf)
+ free(buf);
+ return False;
+ }
+
+ /* Re-write the file - and truncate it at the correct point. */
+ if(lseek(fd, 0, SEEK_SET) != 0)
+ {
+ DEBUG(0,("ERROR: remove_share_oplock: lseek failed to reset to \
+position 0 for share mode file %s (%s)\n", fname, strerror(errno)));
+ if(buf)
+ free(buf);
+ return False;
+ }
+
+ fsize = (base - buf) + (SMF_ENTRY_LENGTH*num_entries);
+ if(write(fd, buf, fsize) != fsize)
+ {
+ DEBUG(0,("ERROR: remove_share_oplock: failed to re-write share \
+mode file %s (%s)\n", fname, strerror(errno)));
+ if(buf)
+ free(buf);
+ return False;
+ }
+
+ return True;
+}
+
+
+
+/*******************************************************************
+call the specified function on each entry under management by the
+share ode system
+********************************************************************/
+static int slow_share_forall(void (*fn)(share_mode_entry *, char *))
+{
+ int i, count=0;
+ void *dir;
+ char *s;
+ share_mode_entry e;
+
+ dir = opendir(lp_lockdir());
+ if (!dir) {
+ return(0);
+ }
+
+ while ((s=readdirname(dir))) {
+ char *buf;
+ char *base;
+ int fd;
+ pstring lname;
+ uint32 dev,inode;
+ BOOL new_file;
+ pstring fname;
+
+ if (sscanf(s,"share.%u.%u",&dev,&inode)!=2) continue;
+
+ strcpy(lname,lp_lockdir());
+ trim_string(lname,NULL,"/");
+ strcat(lname,"/");
+ strcat(lname,s);
+
+ fd = open(lname,read_only?O_RDONLY:O_RDWR,0);
+ if (fd < 0) {
+ continue;
+ }
+
+ /* Lock the share mode file while we read it. */
+ if(!read_only &&
+ fcntl_lock(fd, F_SETLKW, 0, 1, F_WRLCK) == False) {
+ close(fd);
+ continue;
+ }
+
+ if(read_share_file( 0, fd, lname, &buf, &new_file)) {
+ close(fd);
+ continue;
+ }
+ strcpy( fname, &buf[10]);
+ close(fd);
+
+ base = buf + SMF_HEADER_LENGTH +
+ SVAL(buf,SMF_FILENAME_LEN_OFFSET);
+ for( i = 0; i < IVAL(buf, SMF_NUM_ENTRIES_OFFSET); i++) {
+ char *p = base + (i*SMF_ENTRY_LENGTH);
+ e.pid = IVAL(p,SME_PID_OFFSET);
+ e.share_mode = IVAL(p,SME_SHAREMODE_OFFSET);
+ e.time.tv_sec = IVAL(p,SME_SEC_OFFSET);
+ e.time.tv_usec = IVAL(p,SME_USEC_OFFSET);
+ e.op_port = SVAL(p,SME_PORT_OFFSET);
+ e.pid = SVAL(p,SME_PID_OFFSET);
+ e.op_type = SVAL(p,SME_OPLOCK_TYPE_OFFSET);
+
+ fn(&e, fname);
+ count++;
+ } /* end for i */
+
+ if(buf)
+ free(buf);
+ base = 0;
+ } /* end while */
+ closedir(dir);
+
+ return count;
+}
+
+
+/*******************************************************************
+dump the state of the system
+********************************************************************/
+static void slow_share_status(FILE *f)
+{
+
+}
+
+
+static struct share_ops share_ops = {
+ slow_stop_share_mode_mgmt,
+ slow_lock_share_entry,
+ slow_unlock_share_entry,
+ slow_get_share_modes,
+ slow_del_share_mode,
+ slow_set_share_mode,
+ slow_remove_share_oplock,
+ slow_share_forall,
+ slow_share_status,
+};
+
+/*******************************************************************
+ initialize the slow share_mode management
+ ******************************************************************/
+struct share_ops *locking_slow_init(int ronly)
+{
+
+ read_only = ronly;
+
+ if (!directory_exist(lp_lockdir(),NULL)) {
+ if (!read_only)
+ mkdir(lp_lockdir(),0755);
+ if (!directory_exist(lp_lockdir(),NULL))
+ return NULL;
+ }
+
+ return &share_ops;
+}
diff --git a/source/locking/shmem.c b/source/locking/shmem.c
new file mode 100644
index 00000000000..909e8dd4352
--- /dev/null
+++ b/source/locking/shmem.c
@@ -0,0 +1,874 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Shared memory functions
+ Copyright (C) Erik Devriendt 1996-1997
+
+ 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"
+
+
+#ifdef FAST_SHARE_MODES
+
+
+extern int DEBUGLEVEL;
+
+
+#define SMB_SHM_MAGIC 0x53484100
+/* = "SHM" in hex */
+
+#define SMB_SHM_VERSION 2
+
+/* we need world read for smbstatus to function correctly */
+#ifdef SECURE_SHARE_MODES
+#define SHM_FILE_MODE 0600
+#else
+#define SHM_FILE_MODE 0644
+#endif
+
+#define SHMEM_HASH_SIZE 113
+
+
+/* WARNING : offsets are used because mmap() does not guarantee that all processes have the
+ shared memory mapped to the same address */
+
+struct SmbShmHeader
+{
+ int smb_shm_magic;
+ int smb_shm_version;
+ int total_size; /* in bytes */
+ BOOL consistent;
+ int first_free_off;
+ int userdef_off; /* a userdefined offset. can be used to store root of tree or list */
+ struct { /* a cell is a range of bytes of sizeof(struct SmbShmBlockDesc) size */
+ int cells_free;
+ int cells_used;
+ int cells_system; /* number of cells used as allocated block descriptors */
+ } statistics;
+};
+
+#define SMB_SHM_NOT_FREE_OFF (-1)
+struct SmbShmBlockDesc
+{
+ int next; /* offset of next block in the free list or SMB_SHM_NOT_FREE_OFF when block in use */
+ int size; /* user size in BlockDescSize units */
+};
+
+#define EOList_Addr (struct SmbShmBlockDesc *)( 0 )
+#define EOList_Off (NULL_OFFSET)
+
+#define CellSize sizeof(struct SmbShmBlockDesc)
+
+/* HeaderSize aligned on 8 byte boundary */
+#define AlignedHeaderSize ((sizeof(struct SmbShmHeader)+7) & ~7)
+
+static int smb_shm_fd = -1;
+static pstring smb_shm_processreg_name = "";
+
+static struct SmbShmHeader *smb_shm_header_p = (struct SmbShmHeader *)0;
+static int smb_shm_times_locked = 0;
+
+static BOOL smb_shm_initialize_called = False;
+
+static int read_only;
+
+static BOOL smb_shm_global_lock(void)
+{
+ if (smb_shm_fd < 0)
+ {
+ DEBUG(0,("ERROR smb_shm_global_lock : bad smb_shm_fd (%d)\n",smb_shm_fd));
+ return False;
+ }
+
+ smb_shm_times_locked++;
+
+ if(smb_shm_times_locked > 1)
+ {
+ DEBUG(5,("smb_shm_global_lock : locked %d times\n",smb_shm_times_locked));
+ return True;
+ }
+
+ if (read_only)
+ return True;
+
+ /* Do an exclusive wait lock on the first byte of the file */
+ if (fcntl_lock(smb_shm_fd, F_SETLKW, 0, 1, F_WRLCK) == False)
+ {
+ DEBUG(0,("ERROR smb_shm_global_lock : fcntl_lock failed with code %s\n",strerror(errno)));
+ smb_shm_times_locked--;
+ return False;
+ }
+
+ return True;
+
+}
+
+static BOOL smb_shm_global_unlock(void)
+{
+ if (smb_shm_fd < 0)
+ {
+ DEBUG(0,("ERROR smb_shm_global_unlock : bad smb_shm_fd (%d)\n",smb_shm_fd));
+ return False;
+ }
+
+ if(smb_shm_times_locked == 0)
+ {
+ DEBUG(0,("ERROR smb_shm_global_unlock : shmem not locked\n",smb_shm_fd));
+ return False;
+ }
+
+ smb_shm_times_locked--;
+
+ if(smb_shm_times_locked > 0)
+ {
+ DEBUG(5,("smb_shm_global_unlock : still locked %d times\n",smb_shm_times_locked));
+ return True;
+ }
+
+ if (read_only)
+ return True;
+
+ /* Do a wait unlock on the first byte of the file */
+ if (fcntl_lock(smb_shm_fd, F_SETLKW, 0, 1, F_UNLCK) == False)
+ {
+ DEBUG(0,("ERROR smb_shm_global_unlock : fcntl_lock failed with code %s\n",strerror(errno)));
+ smb_shm_times_locked++;
+ return False;
+ }
+
+ return True;
+
+}
+
+
+static void *smb_shm_offset2addr(int offset)
+{
+ if (offset == NULL_OFFSET )
+ return (void *)(0);
+
+ if (!smb_shm_header_p)
+ return (void *)(0);
+
+ return (void *)((char *)smb_shm_header_p + offset );
+}
+
+static int smb_shm_addr2offset(void *addr)
+{
+ if (!addr)
+ return NULL_OFFSET;
+
+ if (!smb_shm_header_p)
+ return NULL_OFFSET;
+
+ return (int)((char *)addr - (char *)smb_shm_header_p);
+}
+
+
+
+static int smb_shm_alloc(int size)
+{
+ unsigned num_cells ;
+ struct SmbShmBlockDesc *scanner_p;
+ struct SmbShmBlockDesc *prev_p;
+ struct SmbShmBlockDesc *new_p;
+ int result_offset;
+
+
+ if( !smb_shm_header_p )
+ {
+ /* not mapped yet */
+ DEBUG(0,("ERROR smb_shm_alloc : shmem not mapped\n"));
+ return NULL_OFFSET;
+ }
+
+ smb_shm_global_lock();
+
+ if( !smb_shm_header_p->consistent)
+ {
+ DEBUG(0,("ERROR smb_shm_alloc : shmem not consistent\n"));
+ smb_shm_global_unlock();
+ return NULL_OFFSET;
+ }
+
+
+ /* calculate the number of cells */
+ num_cells = (size + CellSize -1) / CellSize;
+
+ /* set start of scan */
+ prev_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(smb_shm_header_p->first_free_off);
+ scanner_p = prev_p ;
+
+ /* scan the free list to find a matching free space */
+ while ( ( scanner_p != EOList_Addr ) && ( scanner_p->size < num_cells ) )
+ {
+ prev_p = scanner_p;
+ scanner_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(scanner_p->next);
+ }
+
+ /* at this point scanner point to a block header or to the end of the list */
+ if ( scanner_p == EOList_Addr )
+ {
+ DEBUG(0,("ERROR smb_shm_alloc : alloc of %d bytes failed, no free space found\n",size));
+ smb_shm_global_unlock();
+ return (NULL_OFFSET);
+ }
+
+ /* going to modify shared mem */
+ smb_shm_header_p->consistent = False;
+
+ /* if we found a good one : scanner == the good one */
+ if ( scanner_p->size <= num_cells + 2 )
+ {
+ /* there is no use in making a new one, it will be too small anyway
+ * we will link out scanner
+ */
+ if ( prev_p == scanner_p )
+ {
+ smb_shm_header_p->first_free_off = scanner_p->next ;
+ }
+ else
+ {
+ prev_p->next = scanner_p->next ;
+ }
+ smb_shm_header_p->statistics.cells_free -= scanner_p->size;
+ smb_shm_header_p->statistics.cells_used += scanner_p->size;
+ }
+ else
+ {
+ /* Make a new one */
+ new_p = scanner_p + 1 + num_cells;
+ new_p->size = scanner_p->size - num_cells - 1;
+ new_p->next = scanner_p->next;
+ scanner_p->size = num_cells;
+ scanner_p->next = smb_shm_addr2offset(new_p);
+
+ if ( prev_p != scanner_p )
+ {
+ prev_p->next = smb_shm_addr2offset(new_p) ;
+ }
+ else
+ {
+ smb_shm_header_p->first_free_off = smb_shm_addr2offset(new_p) ;
+ }
+ smb_shm_header_p->statistics.cells_free -= num_cells+1;
+ smb_shm_header_p->statistics.cells_used += num_cells;
+ smb_shm_header_p->statistics.cells_system += 1;
+ }
+
+ result_offset = smb_shm_addr2offset( &(scanner_p[1]) );
+ scanner_p->next = SMB_SHM_NOT_FREE_OFF ;
+
+ /* end modification of shared mem */
+ smb_shm_header_p->consistent = True;
+
+ DEBUG(6,("smb_shm_alloc : request for %d bytes, allocated %d bytes at offset %d\n",size,scanner_p->size*CellSize,result_offset ));
+
+ smb_shm_global_unlock();
+ return ( result_offset );
+}
+
+
+
+
+/*
+ * Function to create the hash table for the share mode entries. Called
+ * when smb shared memory is global locked.
+ */
+static BOOL smb_shm_create_hash_table( unsigned int size )
+{
+ size *= sizeof(int);
+
+ smb_shm_global_lock();
+ smb_shm_header_p->userdef_off = smb_shm_alloc( size );
+
+ if(smb_shm_header_p->userdef_off == NULL_OFFSET)
+ {
+ DEBUG(0,("smb_shm_create_hash_table: Failed to create hash table of size %d\n",size));
+ smb_shm_global_unlock();
+ return False;
+ }
+
+ /* Clear hash buckets. */
+ memset( smb_shm_offset2addr(smb_shm_header_p->userdef_off), '\0', size);
+ smb_shm_global_unlock();
+ return True;
+}
+
+static BOOL smb_shm_register_process(char *processreg_file, pid_t pid, BOOL *other_processes)
+{
+ int smb_shm_processes_fd = -1;
+ int nb_read;
+ pid_t other_pid;
+ int seek_back = -((int)sizeof(other_pid));
+ int free_slot = -1;
+ int erased_slot;
+
+ smb_shm_processes_fd = open(processreg_file,
+ read_only?O_RDONLY:(O_RDWR|O_CREAT),
+ SHM_FILE_MODE);
+
+ if ( smb_shm_processes_fd < 0 )
+ {
+ DEBUG(0,("ERROR smb_shm_register_process : processreg_file open failed with code %s\n",strerror(errno)));
+ return False;
+ }
+
+ *other_processes = False;
+
+ while ((nb_read = read(smb_shm_processes_fd, &other_pid, sizeof(other_pid))) > 0)
+ {
+ if(other_pid)
+ {
+ if(process_exists(other_pid))
+ *other_processes = True;
+ else
+ {
+ /* erase old pid */
+ DEBUG(5,("smb_shm_register_process : erasing stale record for pid %d (seek_back = %d)\n",
+ other_pid, seek_back));
+ other_pid = (pid_t)0;
+ erased_slot = lseek(smb_shm_processes_fd, seek_back, SEEK_CUR);
+ write(smb_shm_processes_fd, &other_pid, sizeof(other_pid));
+ if(free_slot < 0)
+ free_slot = erased_slot;
+ }
+ }
+ else
+ if(free_slot < 0)
+ free_slot = lseek(smb_shm_processes_fd, seek_back, SEEK_CUR);
+ }
+ if (nb_read < 0)
+ {
+ DEBUG(0,("ERROR smb_shm_register_process : processreg_file read failed with code %s\n",strerror(errno)));
+ close(smb_shm_processes_fd);
+ return False;
+ }
+
+ if(free_slot < 0)
+ free_slot = lseek(smb_shm_processes_fd, 0, SEEK_END);
+
+ DEBUG(5,("smb_shm_register_process : writing record for pid %d at offset %d\n",pid,free_slot));
+ lseek(smb_shm_processes_fd, free_slot, SEEK_SET);
+ if(write(smb_shm_processes_fd, &pid, sizeof(pid)) < 0)
+ {
+ DEBUG(0,("ERROR smb_shm_register_process : processreg_file write failed with code %s\n",strerror(errno)));
+ close(smb_shm_processes_fd);
+ return False;
+ }
+
+ close(smb_shm_processes_fd);
+
+ return True;
+}
+
+static BOOL smb_shm_unregister_process(char *processreg_file, pid_t pid)
+{
+ int smb_shm_processes_fd = -1;
+ int nb_read;
+ pid_t other_pid;
+ int seek_back = -((int)sizeof(other_pid));
+ int erased_slot;
+ BOOL found = False;
+
+
+ smb_shm_processes_fd = open(processreg_file, O_RDWR);
+ if ( smb_shm_processes_fd < 0 )
+ {
+ DEBUG(0,("ERROR smb_shm_unregister_process : processreg_file open failed with code %s\n",strerror(errno)));
+ return False;
+ }
+
+ while ((nb_read = read(smb_shm_processes_fd, &other_pid, sizeof(other_pid))) > 0)
+ {
+ DEBUG(5,("smb_shm_unregister_process : read record for pid %d\n",other_pid));
+ if(other_pid == pid)
+ {
+ /* erase pid */
+ DEBUG(5,("smb_shm_unregister_process : erasing record for pid %d (seek_val = %d)\n",
+ other_pid, seek_back));
+ other_pid = (pid_t)0;
+ erased_slot = lseek(smb_shm_processes_fd, seek_back, SEEK_CUR);
+ if(write(smb_shm_processes_fd, &other_pid, sizeof(other_pid)) < 0)
+ {
+ DEBUG(0,("ERROR smb_shm_unregister_process : processreg_file write failed with code %s\n",strerror(errno)));
+ close(smb_shm_processes_fd);
+ return False;
+ }
+
+ found = True;
+ break;
+ }
+ }
+ if (nb_read < 0)
+ {
+ DEBUG(0,("ERROR smb_shm_unregister_process : processreg_file read failed with code %s\n",strerror(errno)));
+ close(smb_shm_processes_fd);
+ return False;
+ }
+
+ if(!found)
+ {
+ DEBUG(0,("ERROR smb_shm_unregister_process : couldn't find pid %d in file %s\n",pid,processreg_file));
+ close(smb_shm_processes_fd);
+ return False;
+ }
+
+
+ close(smb_shm_processes_fd);
+
+ return True;
+}
+
+
+static BOOL smb_shm_validate_header(int size)
+{
+ if( !smb_shm_header_p )
+ {
+ /* not mapped yet */
+ DEBUG(0,("ERROR smb_shm_validate_header : shmem not mapped\n"));
+ return False;
+ }
+
+ if(smb_shm_header_p->smb_shm_magic != SMB_SHM_MAGIC)
+ {
+ DEBUG(0,("ERROR smb_shm_validate_header : bad magic\n"));
+ return False;
+ }
+ if(smb_shm_header_p->smb_shm_version != SMB_SHM_VERSION)
+ {
+ DEBUG(0,("ERROR smb_shm_validate_header : bad version %X\n",smb_shm_header_p->smb_shm_version));
+ return False;
+ }
+
+ if(smb_shm_header_p->total_size != size)
+ {
+ DEBUG(0,("ERROR smb_shm_validate_header : shmem size mismatch (old = %d, new = %d)\n",smb_shm_header_p->total_size,size));
+ return False;
+ }
+
+ if(!smb_shm_header_p->consistent)
+ {
+ DEBUG(0,("ERROR smb_shm_validate_header : shmem not consistent\n"));
+ return False;
+ }
+ return True;
+}
+
+static BOOL smb_shm_initialize(int size)
+{
+ struct SmbShmBlockDesc * first_free_block_p;
+
+ DEBUG(5,("smb_shm_initialize : initializing shmem file of size %d\n",size));
+
+ if( !smb_shm_header_p )
+ {
+ /* not mapped yet */
+ DEBUG(0,("ERROR smb_shm_initialize : shmem not mapped\n"));
+ return False;
+ }
+
+ smb_shm_header_p->smb_shm_magic = SMB_SHM_MAGIC;
+ smb_shm_header_p->smb_shm_version = SMB_SHM_VERSION;
+ smb_shm_header_p->total_size = size;
+ smb_shm_header_p->first_free_off = AlignedHeaderSize;
+ smb_shm_header_p->userdef_off = NULL_OFFSET;
+
+ first_free_block_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(smb_shm_header_p->first_free_off);
+ first_free_block_p->next = EOList_Off;
+ first_free_block_p->size = ( size - AlignedHeaderSize - CellSize ) / CellSize ;
+
+ smb_shm_header_p->statistics.cells_free = first_free_block_p->size;
+ smb_shm_header_p->statistics.cells_used = 0;
+ smb_shm_header_p->statistics.cells_system = 1;
+
+ smb_shm_header_p->consistent = True;
+
+ smb_shm_initialize_called = True;
+
+ return True;
+}
+
+static void smb_shm_solve_neighbors(struct SmbShmBlockDesc *head_p )
+{
+ struct SmbShmBlockDesc *next_p;
+
+ /* Check if head_p and head_p->next are neighbors and if so join them */
+ if ( head_p == EOList_Addr ) return ;
+ if ( head_p->next == EOList_Off ) return ;
+
+ next_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(head_p->next);
+ if ( ( head_p + head_p->size + 1 ) == next_p)
+ {
+ head_p->size += next_p->size +1 ; /* adapt size */
+ head_p->next = next_p->next ; /* link out */
+
+ smb_shm_header_p->statistics.cells_free += 1;
+ smb_shm_header_p->statistics.cells_system -= 1;
+ }
+}
+
+
+
+static BOOL smb_shm_close( void )
+{
+
+ if(smb_shm_initialize_called == False)
+ return True;
+
+ DEBUG(5,("smb_shm_close\n"));
+ if(smb_shm_times_locked > 0)
+ DEBUG(0,("WARNING smb_shm_close : shmem was still locked %d times\n",smb_shm_times_locked));;
+ if ((smb_shm_header_p != NULL) &&
+ (munmap((caddr_t)smb_shm_header_p, smb_shm_header_p->total_size) < 0))
+ {
+ DEBUG(0,("ERROR smb_shm_close : munmap failed with code %s\n",strerror(errno)));
+ }
+
+ smb_shm_global_lock();
+ DEBUG(5,("calling smb_shm_unregister_process(%s, %d)\n", smb_shm_processreg_name, getpid()));
+ smb_shm_unregister_process(smb_shm_processreg_name, getpid());
+ smb_shm_global_unlock();
+
+ close(smb_shm_fd);
+
+ smb_shm_fd = -1;
+ smb_shm_processreg_name[0] = '\0';
+
+ smb_shm_header_p = (struct SmbShmHeader *)0;
+ smb_shm_times_locked = 0;
+
+ return True;
+}
+
+
+static BOOL smb_shm_free(int offset)
+{
+ struct SmbShmBlockDesc *header_p ; /* pointer to header of block to free */
+ struct SmbShmBlockDesc *scanner_p ; /* used to scan the list */
+ struct SmbShmBlockDesc *prev_p ; /* holds previous in the list */
+
+ if( !smb_shm_header_p )
+ {
+ /* not mapped yet */
+ DEBUG(0,("ERROR smb_shm_free : shmem not mapped\n"));
+ return False;
+ }
+
+ smb_shm_global_lock();
+
+ if( !smb_shm_header_p->consistent)
+ {
+ DEBUG(0,("ERROR smb_shm_free : shmem not consistent\n"));
+ smb_shm_global_unlock();
+ return False;
+ }
+
+ header_p = ( (struct SmbShmBlockDesc *)smb_shm_offset2addr(offset) - 1); /* make pointer to header of block */
+
+ if (header_p->next != SMB_SHM_NOT_FREE_OFF)
+ {
+ DEBUG(0,("ERROR smb_shm_free : bad offset (%d)\n",offset));
+ smb_shm_global_unlock();
+ return False;
+ }
+
+ /* find a place in the free_list to put the header in */
+
+ /* set scanner and previous pointer to start of list */
+ prev_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(smb_shm_header_p->first_free_off);
+ scanner_p = prev_p ;
+
+ while ( ( scanner_p != EOList_Addr) && (scanner_p < header_p) ) /* while we didn't scan past its position */
+ {
+ prev_p = scanner_p ;
+ scanner_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(scanner_p->next);
+ }
+
+ smb_shm_header_p->consistent = False;
+
+ DEBUG(6,("smb_shm_free : freeing %d bytes at offset %d\n",header_p->size*CellSize,offset));
+
+ if ( scanner_p == prev_p )
+ {
+ smb_shm_header_p->statistics.cells_free += header_p->size;
+ smb_shm_header_p->statistics.cells_used -= header_p->size;
+
+ /* we must free it at the beginning of the list */
+ smb_shm_header_p->first_free_off = smb_shm_addr2offset(header_p); /* set the free_list_pointer to this block_header */
+
+ /* scanner is the one that was first in the list */
+ header_p->next = smb_shm_addr2offset(scanner_p);
+ smb_shm_solve_neighbors( header_p ); /* if neighbors then link them */
+
+ smb_shm_header_p->consistent = True;
+ smb_shm_global_unlock();
+ return True;
+ }
+ else
+ {
+ smb_shm_header_p->statistics.cells_free += header_p->size;
+ smb_shm_header_p->statistics.cells_used -= header_p->size;
+
+ prev_p->next = smb_shm_addr2offset(header_p);
+ header_p->next = smb_shm_addr2offset(scanner_p);
+ smb_shm_solve_neighbors(header_p) ;
+ smb_shm_solve_neighbors(prev_p) ;
+
+ smb_shm_header_p->consistent = True;
+ smb_shm_global_unlock();
+ return True;
+ }
+}
+
+static int smb_shm_get_userdef_off(void)
+{
+ if (!smb_shm_header_p)
+ return NULL_OFFSET;
+ else
+ return smb_shm_header_p->userdef_off;
+}
+
+/*******************************************************************
+ Lock a particular hash bucket entry.
+ ******************************************************************/
+static BOOL smb_shm_lock_hash_entry( unsigned int entry)
+{
+ int start = (smb_shm_header_p->userdef_off + (entry * sizeof(int)));
+
+ if (smb_shm_fd < 0)
+ {
+ DEBUG(0,("ERROR smb_shm_lock_hash_entry : bad smb_shm_fd (%d)\n",smb_shm_fd));
+ return False;
+ }
+
+ /* Do an exclusive wait lock on the 4 byte region mapping into this entry */
+ if (fcntl_lock(smb_shm_fd, F_SETLKW, start, sizeof(int), F_WRLCK) == False)
+ {
+ DEBUG(0,("ERROR smb_shm_lock_hash_entry : fcntl_lock failed with code %s\n",strerror(errno)));
+ return False;
+ }
+
+ DEBUG(9,("smb_shm_lock_hash_entry: locked hash bucket %d\n", entry));
+ return True;
+}
+
+/*******************************************************************
+ Unlock a particular hash bucket entry.
+ ******************************************************************/
+static BOOL smb_shm_unlock_hash_entry( unsigned int entry )
+{
+ int start = (smb_shm_header_p->userdef_off + (entry * sizeof(int)));
+
+ if (smb_shm_fd < 0)
+ {
+ DEBUG(0,("ERROR smb_shm_unlock_hash_entry : bad smb_shm_fd (%d)\n",smb_shm_fd));
+ return False;
+ }
+
+ /* Do a wait lock on the 4 byte region mapping into this entry */
+ if (fcntl_lock(smb_shm_fd, F_SETLKW, start, sizeof(int), F_UNLCK) == False)
+ {
+ DEBUG(0,("ERROR smb_shm_unlock_hash_entry : fcntl_lock failed with code %s\n",strerror(errno)));
+ return False;
+ }
+
+ DEBUG(9,("smb_shm_unlock_hash_entry: unlocked hash bucket %d\n", entry));
+ return True;
+}
+
+/*******************************************************************
+ Gather statistics on shared memory usage.
+ ******************************************************************/
+static BOOL smb_shm_get_usage(int *bytes_free,
+ int *bytes_used,
+ int *bytes_overhead)
+{
+ if( !smb_shm_header_p )
+ {
+ /* not mapped yet */
+ DEBUG(0,("ERROR smb_shm_free : shmem not mapped\n"));
+ return False;
+ }
+ *bytes_free = smb_shm_header_p->statistics.cells_free * CellSize;
+ *bytes_used = smb_shm_header_p->statistics.cells_used * CellSize;
+ *bytes_overhead = smb_shm_header_p->statistics.cells_system * CellSize + AlignedHeaderSize;
+
+ return True;
+}
+
+/*******************************************************************
+hash a number into a hash_entry
+ ******************************************************************/
+static unsigned smb_shm_hash_size(void)
+{
+ return SHMEM_HASH_SIZE;
+}
+
+static struct shmem_ops shmops = {
+ smb_shm_close,
+ smb_shm_alloc,
+ smb_shm_free,
+ smb_shm_get_userdef_off,
+ smb_shm_offset2addr,
+ smb_shm_addr2offset,
+ smb_shm_lock_hash_entry,
+ smb_shm_unlock_hash_entry,
+ smb_shm_get_usage,
+ smb_shm_hash_size,
+};
+
+/*******************************************************************
+ open the shared memory
+ ******************************************************************/
+struct shmem_ops *smb_shm_open(int ronly)
+{
+ pstring file_name;
+ int filesize;
+ BOOL created_new = False;
+ BOOL other_processes = True;
+ int size = lp_shmem_size();
+
+ read_only = ronly;
+
+ pstrcpy(file_name,lp_lockdir());
+ if (!directory_exist(file_name,NULL)) {
+ if (read_only) return NULL;
+ mkdir(file_name,0755);
+ }
+ trim_string(file_name,"","/");
+ if (!*file_name) return(False);
+ strcat(file_name, "/SHARE_MEM_FILE");
+
+ DEBUG(5,("smb_shm_open : using shmem file %s to be of size %d\n",file_name,size));
+
+ smb_shm_fd = open(file_name, read_only?O_RDONLY:(O_RDWR|O_CREAT),
+ SHM_FILE_MODE);
+
+ if ( smb_shm_fd < 0 )
+ {
+ DEBUG(0,("ERROR smb_shm_open : open failed with code %s\n",strerror(errno)));
+ return NULL;
+ }
+
+ if (!smb_shm_global_lock())
+ {
+ DEBUG(0,("ERROR smb_shm_open : can't do smb_shm_global_lock\n"));
+ return NULL;
+ }
+
+ if( (filesize = lseek(smb_shm_fd, 0, SEEK_END)) < 0)
+ {
+ DEBUG(0,("ERROR smb_shm_open : lseek failed with code %s\n",strerror(errno)));
+ smb_shm_global_unlock();
+ close(smb_shm_fd);
+ return NULL;
+ }
+
+ /* return the file offset to 0 to save on later seeks */
+ lseek(smb_shm_fd,0,SEEK_SET);
+
+ if (filesize == 0)
+ {
+ /* we just created a new one */
+ created_new = True;
+ }
+
+ /* to find out if some other process is already mapping the file,
+ we use a registration file containing the processids of the file mapping processes
+ */
+
+ /* construct processreg file name */
+ strcpy(smb_shm_processreg_name, file_name);
+ strcat(smb_shm_processreg_name, ".processes");
+
+ if (!read_only &&
+ !smb_shm_register_process(smb_shm_processreg_name, getpid(), &other_processes))
+ {
+ smb_shm_global_unlock();
+ close(smb_shm_fd);
+ return NULL;
+ }
+
+ if (!read_only && (created_new || !other_processes))
+ {
+ /* we just created a new one, or are the first opener, lets set it size */
+ if( ftruncate(smb_shm_fd, size) <0)
+ {
+ DEBUG(0,("ERROR smb_shm_open : ftruncate failed with code %s\n",strerror(errno)));
+ smb_shm_unregister_process(smb_shm_processreg_name, getpid());
+ smb_shm_global_unlock();
+ close(smb_shm_fd);
+ return NULL;
+ }
+
+ /* paranoia */
+ lseek(smb_shm_fd,0,SEEK_SET);
+
+ filesize = size;
+ }
+
+ if (size != filesize )
+ {
+ /* the existing file has a different size and we are not the first opener.
+ Since another process is still using it, we will use the file size */
+ DEBUG(0,("WARNING smb_shm_open : filesize (%d) != expected size (%d), using filesize\n",filesize,size));
+ size = filesize;
+ }
+
+ smb_shm_header_p = (struct SmbShmHeader *)mmap(NULL, size,
+ read_only?PROT_READ:
+ (PROT_READ | PROT_WRITE),
+ MAP_FILE | MAP_SHARED,
+ smb_shm_fd, 0);
+ /* WARNING, smb_shm_header_p can be different for different processes mapping the same file ! */
+ if (smb_shm_header_p == (struct SmbShmHeader *)(-1))
+ {
+ DEBUG(0,("ERROR smb_shm_open : mmap failed with code %s\n",strerror(errno)));
+ smb_shm_unregister_process(smb_shm_processreg_name, getpid());
+ smb_shm_global_unlock();
+ close(smb_shm_fd);
+ return NULL;
+ }
+
+
+ if (!read_only && (created_new || !other_processes))
+ {
+ smb_shm_initialize(size);
+ /* Create the hash buckets for the share file entries. */
+ smb_shm_create_hash_table(SHMEM_HASH_SIZE);
+ }
+ else if (!smb_shm_validate_header(size) )
+ {
+ /* existing file is corrupt, samba admin should remove it by hand */
+ DEBUG(0,("ERROR smb_shm_open : corrupt shared mem file, remove it manually\n"));
+ munmap((caddr_t)smb_shm_header_p, size);
+ smb_shm_unregister_process(smb_shm_processreg_name, getpid());
+ smb_shm_global_unlock();
+ close(smb_shm_fd);
+ return NULL;
+ }
+
+ smb_shm_global_unlock();
+ return &shmops;
+}
+
+
+#else /* FAST_SHARE_MODES */
+ int shmem_dummy_procedure(void)
+{return 0;}
+#endif /* FAST_SHARE_MODES */
diff --git a/source/locking/shmem_sysv.c b/source/locking/shmem_sysv.c
new file mode 100644
index 00000000000..8832902820a
--- /dev/null
+++ b/source/locking/shmem_sysv.c
@@ -0,0 +1,680 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Shared memory functions - SYSV IPC implementation
+ Copyright (C) Erik Devriendt 1996-1997
+
+ 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"
+
+
+#ifdef USE_SYSV_IPC
+
+extern int DEBUGLEVEL;
+
+#define SHMEM_KEY ((key_t)0x280267)
+#define SEMAPHORE_KEY (SHMEM_KEY+2)
+
+#define SHM_MAGIC 0x53484100
+#define SHM_VERSION 2
+
+#ifdef SHM_R
+#define IPC_PERMS ((SHM_R | SHM_W) | (SHM_R>>3) | (SHM_R>>6))
+#else
+#define IPC_PERMS 0644
+#endif
+
+#ifdef SECURE_SEMAPHORES
+/* secure semaphores are slow because we have to do a become_root()
+ on every call! */
+#define SEMAPHORE_PERMS IPC_PERMS
+#else
+#define SEMAPHORE_PERMS 0666
+#endif
+
+#ifdef SEMMSL
+#define SHMEM_HASH_SIZE (SEMMSL-1)
+#else
+#define SHMEM_HASH_SIZE 63
+#endif
+
+#define MIN_SHM_SIZE 10240
+
+static int shm_id;
+static int sem_id;
+static int shm_size;
+static int hash_size;
+static int global_lock_count;
+
+struct ShmHeader {
+ int shm_magic;
+ int shm_version;
+ int total_size; /* in bytes */
+ BOOL consistent;
+ int first_free_off;
+ int userdef_off; /* a userdefined offset. can be used to store
+ root of tree or list */
+ struct { /* a cell is a range of bytes of sizeof(struct
+ ShmBlockDesc) size */
+ int cells_free;
+ int cells_used;
+ int cells_system; /* number of cells used as allocated
+ block descriptors */
+ } statistics;
+};
+
+#define SHM_NOT_FREE_OFF (-1)
+struct ShmBlockDesc
+{
+ int next; /* offset of next block in the free list or
+ SHM_NOT_FREE_OFF when block in use */
+ int size; /* user size in BlockDescSize units */
+};
+
+#define EOList_Addr (struct ShmBlockDesc *)( 0 )
+#define EOList_Off (NULL_OFFSET)
+
+#define CellSize sizeof(struct ShmBlockDesc)
+
+/* HeaderSize aligned on 8 byte boundary */
+#define AlignedHeaderSize ((sizeof(struct ShmHeader)+7) & ~7)
+
+static struct ShmHeader *shm_header_p = (struct ShmHeader *)0;
+
+static BOOL shm_initialize_called = False;
+
+static int read_only;
+
+static BOOL sem_change(int i, int op)
+{
+#ifdef SECURE_SEMAPHORES
+ extern struct current_user current_user;
+ int became_root=0;
+#endif
+ struct sembuf sb;
+ int ret;
+
+ if (read_only) return True;
+
+#ifdef SECURE_SEMAPHORES
+ if (current_user.uid != 0) {
+ become_root(0);
+ became_root = 1;
+ }
+#endif
+
+ sb.sem_num = i;
+ sb.sem_op = op;
+ sb.sem_flg = SEM_UNDO;
+
+ ret = semop(sem_id, &sb, 1);
+
+ if (ret != 0) {
+ DEBUG(0,("ERROR: sem_change(%d,%d) failed (%s)\n",
+ i, op, strerror(errno)));
+ }
+
+#ifdef SECURE_SEMAPHORES
+ if (became_root) {
+ unbecome_root(0);
+ }
+#endif
+
+ return ret == 0;
+}
+
+static BOOL global_lock(void)
+{
+ global_lock_count++;
+ if (global_lock_count == 1)
+ return sem_change(0, -1);
+ return True;
+}
+
+static BOOL global_unlock(void)
+{
+ global_lock_count--;
+ if (global_lock_count == 0)
+ return sem_change(0, 1);
+ return True;
+}
+
+static void *shm_offset2addr(int offset)
+{
+ if (offset == NULL_OFFSET )
+ return (void *)(0);
+
+ if (!shm_header_p)
+ return (void *)(0);
+
+ return (void *)((char *)shm_header_p + offset );
+}
+
+static int shm_addr2offset(void *addr)
+{
+ if (!addr)
+ return NULL_OFFSET;
+
+ if (!shm_header_p)
+ return NULL_OFFSET;
+
+ return (int)((char *)addr - (char *)shm_header_p);
+}
+
+
+static int shm_alloc(int size)
+{
+ unsigned num_cells ;
+ struct ShmBlockDesc *scanner_p;
+ struct ShmBlockDesc *prev_p;
+ struct ShmBlockDesc *new_p;
+ int result_offset;
+
+
+ if (!shm_header_p) {
+ /* not mapped yet */
+ DEBUG(0,("ERROR shm_alloc : shmem not mapped\n"));
+ return NULL_OFFSET;
+ }
+
+ global_lock();
+
+ if (!shm_header_p->consistent) {
+ DEBUG(0,("ERROR shm_alloc : shmem not consistent\n"));
+ global_unlock();
+ return NULL_OFFSET;
+ }
+
+ /* calculate the number of cells */
+ num_cells = (size + CellSize -1) / CellSize;
+
+ /* set start of scan */
+ prev_p = (struct ShmBlockDesc *)shm_offset2addr(shm_header_p->first_free_off);
+ scanner_p = prev_p ;
+
+ /* scan the free list to find a matching free space */
+ while ((scanner_p != EOList_Addr) && (scanner_p->size < num_cells)) {
+ prev_p = scanner_p;
+ scanner_p = (struct ShmBlockDesc *)shm_offset2addr(scanner_p->next);
+ }
+
+ /* at this point scanner point to a block header or to the end of
+ the list */
+ if (scanner_p == EOList_Addr) {
+ DEBUG(0,("ERROR shm_alloc : alloc of %d bytes failed, no free space found\n",size));
+ global_unlock();
+ return (NULL_OFFSET);
+ }
+
+ /* going to modify shared mem */
+ shm_header_p->consistent = False;
+
+ /* if we found a good one : scanner == the good one */
+ if (scanner_p->size <= num_cells + 2) {
+ /* there is no use in making a new one, it will be too small anyway
+ * we will link out scanner
+ */
+ if ( prev_p == scanner_p ) {
+ shm_header_p->first_free_off = scanner_p->next ;
+ } else {
+ prev_p->next = scanner_p->next ;
+ }
+ shm_header_p->statistics.cells_free -= scanner_p->size;
+ shm_header_p->statistics.cells_used += scanner_p->size;
+ } else {
+ /* Make a new one */
+ new_p = scanner_p + 1 + num_cells;
+ new_p->size = scanner_p->size - num_cells - 1;
+ new_p->next = scanner_p->next;
+ scanner_p->size = num_cells;
+ scanner_p->next = shm_addr2offset(new_p);
+
+ if (prev_p != scanner_p) {
+ prev_p->next = shm_addr2offset(new_p) ;
+ } else {
+ shm_header_p->first_free_off = shm_addr2offset(new_p);
+ }
+ shm_header_p->statistics.cells_free -= num_cells+1;
+ shm_header_p->statistics.cells_used += num_cells;
+ shm_header_p->statistics.cells_system += 1;
+ }
+
+ result_offset = shm_addr2offset( &(scanner_p[1]) );
+ scanner_p->next = SHM_NOT_FREE_OFF ;
+
+ /* end modification of shared mem */
+ shm_header_p->consistent = True;
+
+ DEBUG(6,("shm_alloc : request for %d bytes, allocated %d bytes at offset %d\n",size,scanner_p->size*CellSize,result_offset ));
+
+ global_unlock();
+ return result_offset;
+}
+
+
+
+/*
+ * Function to create the hash table for the share mode entries. Called
+ * when smb shared memory is global locked.
+ */
+static BOOL shm_create_hash_table( unsigned int size )
+{
+ size *= sizeof(int);
+
+ global_lock();
+ shm_header_p->userdef_off = shm_alloc( size );
+
+ if(shm_header_p->userdef_off == NULL_OFFSET) {
+ DEBUG(0,("shm_create_hash_table: Failed to create hash table of size %d\n",size));
+ global_unlock();
+ return False;
+ }
+
+ /* Clear hash buckets. */
+ memset( shm_offset2addr(shm_header_p->userdef_off), '\0', size);
+ global_unlock();
+ return True;
+}
+
+static BOOL shm_validate_header(int size)
+{
+ if( !shm_header_p ) {
+ /* not mapped yet */
+ DEBUG(0,("ERROR shm_validate_header : shmem not mapped\n"));
+ return False;
+ }
+
+ if(shm_header_p->shm_magic != SHM_MAGIC) {
+ DEBUG(0,("ERROR shm_validate_header : bad magic\n"));
+ return False;
+ }
+
+ if(shm_header_p->shm_version != SHM_VERSION) {
+ DEBUG(0,("ERROR shm_validate_header : bad version %X\n",shm_header_p->shm_version));
+ return False;
+ }
+
+ if(shm_header_p->total_size != size) {
+ DEBUG(0,("ERROR shm_validate_header : shmem size mismatch (old = %d, new = %d)\n",shm_header_p->total_size,size));
+ return False;
+ }
+
+ if(!shm_header_p->consistent) {
+ DEBUG(0,("ERROR shm_validate_header : shmem not consistent\n"));
+ return False;
+ }
+ return True;
+}
+
+static BOOL shm_initialize(int size)
+{
+ struct ShmBlockDesc * first_free_block_p;
+
+ DEBUG(5,("shm_initialize : initializing shmem file of size %d\n",size));
+
+ if( !shm_header_p ) {
+ /* not mapped yet */
+ DEBUG(0,("ERROR shm_initialize : shmem not mapped\n"));
+ return False;
+ }
+
+ shm_header_p->shm_magic = SHM_MAGIC;
+ shm_header_p->shm_version = SHM_VERSION;
+ shm_header_p->total_size = size;
+ shm_header_p->first_free_off = AlignedHeaderSize;
+ shm_header_p->userdef_off = NULL_OFFSET;
+
+ first_free_block_p = (struct ShmBlockDesc *)shm_offset2addr(shm_header_p->first_free_off);
+ first_free_block_p->next = EOList_Off;
+ first_free_block_p->size = ( size - AlignedHeaderSize - CellSize ) / CellSize ;
+
+ shm_header_p->statistics.cells_free = first_free_block_p->size;
+ shm_header_p->statistics.cells_used = 0;
+ shm_header_p->statistics.cells_system = 1;
+
+ shm_header_p->consistent = True;
+
+ shm_initialize_called = True;
+
+ return True;
+}
+
+static void shm_solve_neighbors(struct ShmBlockDesc *head_p )
+{
+ struct ShmBlockDesc *next_p;
+
+ /* Check if head_p and head_p->next are neighbors and if so
+ join them */
+ if ( head_p == EOList_Addr ) return ;
+ if ( head_p->next == EOList_Off ) return ;
+
+ next_p = (struct ShmBlockDesc *)shm_offset2addr(head_p->next);
+ if ( ( head_p + head_p->size + 1 ) == next_p) {
+ head_p->size += next_p->size +1 ; /* adapt size */
+ head_p->next = next_p->next ; /* link out */
+
+ shm_header_p->statistics.cells_free += 1;
+ shm_header_p->statistics.cells_system -= 1;
+ }
+}
+
+
+
+
+static BOOL shm_close( void )
+{
+ return True;
+}
+
+
+static BOOL shm_free(int offset)
+{
+ struct ShmBlockDesc *header_p; /* pointer to header of
+ block to free */
+ struct ShmBlockDesc *scanner_p; /* used to scan the list */
+ struct ShmBlockDesc *prev_p; /* holds previous in the
+ list */
+
+ if (!shm_header_p) {
+ /* not mapped yet */
+ DEBUG(0,("ERROR shm_free : shmem not mapped\n"));
+ return False;
+ }
+
+ global_lock();
+
+ if (!shm_header_p->consistent) {
+ DEBUG(0,("ERROR shm_free : shmem not consistent\n"));
+ global_unlock();
+ return False;
+ }
+
+ /* make pointer to header of block */
+ header_p = ((struct ShmBlockDesc *)shm_offset2addr(offset) - 1);
+
+ if (header_p->next != SHM_NOT_FREE_OFF) {
+ DEBUG(0,("ERROR shm_free : bad offset (%d)\n",offset));
+ global_unlock();
+ return False;
+ }
+
+ /* find a place in the free_list to put the header in */
+
+ /* set scanner and previous pointer to start of list */
+ prev_p = (struct ShmBlockDesc *)shm_offset2addr(shm_header_p->first_free_off);
+ scanner_p = prev_p ;
+
+ while ((scanner_p != EOList_Addr) &&
+ (scanner_p < header_p)) {
+ /* while we didn't scan past its position */
+ prev_p = scanner_p ;
+ scanner_p = (struct ShmBlockDesc *)shm_offset2addr(scanner_p->next);
+ }
+
+ shm_header_p->consistent = False;
+
+ DEBUG(6,("shm_free : freeing %d bytes at offset %d\n",
+ header_p->size*CellSize,offset));
+
+ if (scanner_p == prev_p) {
+ shm_header_p->statistics.cells_free += header_p->size;
+ shm_header_p->statistics.cells_used -= header_p->size;
+
+ /* we must free it at the beginning of the list */
+ shm_header_p->first_free_off = shm_addr2offset(header_p); /* set the free_list_pointer to this block_header */
+
+ /* scanner is the one that was first in the list */
+ header_p->next = shm_addr2offset(scanner_p);
+ shm_solve_neighbors( header_p ); /* if neighbors then link them */
+
+ shm_header_p->consistent = True;
+ } else {
+ shm_header_p->statistics.cells_free += header_p->size;
+ shm_header_p->statistics.cells_used -= header_p->size;
+
+ prev_p->next = shm_addr2offset(header_p);
+ header_p->next = shm_addr2offset(scanner_p);
+ shm_solve_neighbors(header_p) ;
+ shm_solve_neighbors(prev_p) ;
+
+ shm_header_p->consistent = True;
+ }
+
+ global_unlock();
+ return True;
+}
+
+
+static int shm_get_userdef_off(void)
+{
+ if (!shm_header_p)
+ return NULL_OFFSET;
+ else
+ return shm_header_p->userdef_off;
+}
+
+/*******************************************************************
+ Lock a particular hash bucket entry.
+ ******************************************************************/
+static BOOL shm_lock_hash_entry(unsigned int entry)
+{
+ return sem_change(entry+1, -1);
+}
+
+/*******************************************************************
+ Unlock a particular hash bucket entry.
+ ******************************************************************/
+static BOOL shm_unlock_hash_entry(unsigned int entry)
+{
+ return sem_change(entry+1, 1);
+}
+
+
+/*******************************************************************
+ Gather statistics on shared memory usage.
+ ******************************************************************/
+static BOOL shm_get_usage(int *bytes_free,
+ int *bytes_used,
+ int *bytes_overhead)
+{
+ if(!shm_header_p) {
+ /* not mapped yet */
+ DEBUG(0,("ERROR shm_free : shmem not mapped\n"));
+ return False;
+ }
+
+ *bytes_free = shm_header_p->statistics.cells_free * CellSize;
+ *bytes_used = shm_header_p->statistics.cells_used * CellSize;
+ *bytes_overhead = shm_header_p->statistics.cells_system * CellSize + AlignedHeaderSize;
+
+ return True;
+}
+
+
+/*******************************************************************
+hash a number into a hash_entry
+ ******************************************************************/
+static unsigned shm_hash_size(void)
+{
+ return hash_size;
+}
+
+
+static struct shmem_ops shmops = {
+ shm_close,
+ shm_alloc,
+ shm_free,
+ shm_get_userdef_off,
+ shm_offset2addr,
+ shm_addr2offset,
+ shm_lock_hash_entry,
+ shm_unlock_hash_entry,
+ shm_get_usage,
+ shm_hash_size,
+};
+
+/*******************************************************************
+ open the shared memory
+ ******************************************************************/
+struct shmem_ops *sysv_shm_open(int ronly)
+{
+ BOOL created_new = False;
+ BOOL other_processes;
+ struct shmid_ds shm_ds;
+ struct semid_ds sem_ds;
+ union semun su;
+ int i;
+
+ read_only = ronly;
+
+ shm_size = lp_shmem_size();
+
+ DEBUG(4,("Trying sysv shmem open of size %d\n", shm_size));
+
+ /* first the semaphore */
+ sem_id = semget(SEMAPHORE_KEY, 0, 0);
+ if (sem_id == -1) {
+ if (read_only) return NULL;
+
+ hash_size = SHMEM_HASH_SIZE;
+
+ while (hash_size > 1) {
+ sem_id = semget(SEMAPHORE_KEY, hash_size+1,
+ IPC_CREAT|IPC_EXCL| SEMAPHORE_PERMS);
+ if (sem_id != -1 || errno != EINVAL) break;
+ hash_size--;
+ }
+
+ if (sem_id == -1) {
+ DEBUG(0,("Can't create or use semaphore %s\n",
+ strerror(errno)));
+ }
+
+ if (sem_id != -1) {
+ su.val = 1;
+ for (i=0;i<hash_size+1;i++) {
+ if (semctl(sem_id, i, SETVAL, su) != 0) {
+ DEBUG(1,("Failed to init semaphore %d\n", i));
+ }
+ }
+ }
+ }
+ if (shm_id == -1) {
+ sem_id = semget(SEMAPHORE_KEY, 0, 0);
+ }
+ if (sem_id == -1) {
+ DEBUG(0,("Can't create or use semaphore %s\n",
+ strerror(errno)));
+ return NULL;
+ }
+
+ su.buf = &sem_ds;
+ if (semctl(sem_id, 0, IPC_STAT, su) != 0) {
+ DEBUG(0,("ERROR shm_open : can't IPC_STAT\n"));
+ }
+ hash_size = sem_ds.sem_nsems-1;
+
+ if (!read_only) {
+ if (sem_ds.sem_perm.cuid != 0 || sem_ds.sem_perm.cgid != 0) {
+ DEBUG(0,("ERROR: root did not create the semaphore\n"));
+ return NULL;
+ }
+
+ sem_ds.sem_perm.mode = SEMAPHORE_PERMS;
+ if (semctl(sem_id, 0, IPC_SET, su) != 0) {
+ DEBUG(0,("ERROR shm_open : can't IPC_SET\n"));
+ }
+ }
+
+
+
+ if (!global_lock())
+ return NULL;
+
+ /* try to use an existing key */
+ shm_id = shmget(SHMEM_KEY, shm_size, 0);
+
+ /* if that failed then create one */
+ if (shm_id == -1) {
+ if (read_only) return NULL;
+ while (shm_size > MIN_SHM_SIZE) {
+ shm_id = shmget(SHMEM_KEY, shm_size,
+ IPC_CREAT | IPC_EXCL | IPC_PERMS);
+ if (shm_id != -1 || errno != EINVAL) break;
+ shm_size *= 0.9;
+ }
+ created_new = (shm_id != -1);
+ }
+
+ if (shm_id == -1) {
+ DEBUG(0,("Can't create or use IPC area\n"));
+ global_unlock();
+ return NULL;
+ }
+
+
+ shm_header_p = (struct ShmHeader *)shmat(shm_id, 0,
+ read_only?SHM_RDONLY:0);
+ if ((int)shm_header_p == -1) {
+ DEBUG(0,("Can't attach to IPC area\n"));
+ global_unlock();
+ return NULL;
+ }
+
+ /* to find out if some other process is already mapping the file,
+ we use a registration file containing the processids of the file
+ mapping processes */
+ if (shmctl(shm_id, IPC_STAT, &shm_ds) != 0) {
+ DEBUG(0,("ERROR shm_open : can't IPC_STAT\n"));
+ }
+
+ if (!read_only) {
+ if (shm_ds.shm_perm.cuid != 0 || shm_ds.shm_perm.cgid != 0) {
+ DEBUG(0,("ERROR: root did not create the shmem\n"));
+ global_unlock();
+ return NULL;
+ }
+ }
+
+ shm_size = shm_ds.shm_segsz;
+
+ other_processes = (shm_ds.shm_nattch > 1);
+
+ if (!read_only && !other_processes) {
+ memset((char *)shm_header_p, 0, shm_size);
+ shm_initialize(shm_size);
+ shm_create_hash_table(hash_size);
+ DEBUG(3,("Initialised IPC area of size %d\n", shm_size));
+ } else if (!shm_validate_header(shm_size)) {
+ /* existing file is corrupt, samba admin should remove
+ it by hand */
+ DEBUG(0,("ERROR shm_open : corrupt IPC area - remove it!\n"));
+ global_unlock();
+ return NULL;
+ }
+
+ global_unlock();
+ return &shmops;
+}
+
+
+
+#else
+ int ipc_dummy_procedure(void)
+{return 0;}
+#endif
diff --git a/source/lsaparse.c b/source/lsaparse.c
new file mode 100644
index 00000000000..1da67da6155
--- /dev/null
+++ b/source/lsaparse.c
@@ -0,0 +1,675 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Samba utility functions
+ Copyright (C) Luke Leighton 1996 - 1997 Paul Ashton 1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+
+/*******************************************************************
+makes an LSA_Q_OPEN_POL structure.
+********************************************************************/
+void make_q_open_pol(LSA_Q_OPEN_POL *r_q, char *server_name,
+ uint32 attributes, uint32 sec_qos,
+ uint16 desired_access)
+{
+ if (r_q == NULL) return;
+
+ DEBUG(5,("make_open_pol\n"));
+
+ make_unistr2 (&(r_q->uni_server_name), server_name, strlen(server_name));
+ make_obj_attr(&(r_q->attr ), attributes, sec_qos);
+
+ r_q->des_access = desired_access;
+}
+
+/*******************************************************************
+reads or writes an LSA_Q_OPEN_POL structure.
+********************************************************************/
+char* lsa_io_q_open_pol(BOOL io, LSA_Q_OPEN_POL *r_q, char *q, char *base, int align, int depth)
+{
+ if (r_q == NULL) return NULL;
+
+ DEBUG(5,("%s%04x lsa_io_q_open_pol\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = smb_io_unistr2 (io, &(r_q->uni_server_name), q, base, align, depth);
+ q = smb_io_obj_attr(io, &(r_q->attr ), q, base, align, depth);
+
+ DBG_RW_SVAL("des_access", depth, base, io, q, r_q->des_access); q += 2;
+
+ return q;
+}
+
+/*******************************************************************
+reads or writes an LSA_R_OPEN_POL structure.
+********************************************************************/
+char* lsa_io_r_open_pol(BOOL io, LSA_R_OPEN_POL *r_p, char *q, char *base, int align, int depth)
+{
+ if (r_p == NULL) return NULL;
+
+ DEBUG(5,("%s%04x lsa_io_r_open_pol\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = smb_io_pol_hnd(io, &(r_p->pol), q, base, align, depth);
+
+ DBG_RW_IVAL("status", depth, base, io, q, r_p->status); q += 4;
+
+ return q;
+}
+
+/*******************************************************************
+makes an LSA_Q_QUERY_INFO structure.
+********************************************************************/
+void make_q_query(LSA_Q_QUERY_INFO *q_q, LSA_POL_HND *hnd, uint16 info_class)
+{
+ if (q_q == NULL || hnd == NULL) return;
+
+ DEBUG(5,("make_q_query\n"));
+
+ memcpy(&(q_q->pol), hnd, sizeof(q_q->pol));
+
+ q_q->info_class = info_class;
+}
+
+/*******************************************************************
+reads or writes an LSA_Q_QUERY_INFO structure.
+********************************************************************/
+char* lsa_io_q_query(BOOL io, LSA_Q_QUERY_INFO *q_q, char *q, char *base, int align, int depth)
+{
+ if (q_q == NULL) return NULL;
+
+ DEBUG(5,("%s%04x lsa_io_q_query\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = smb_io_pol_hnd(io, &(q_q->pol), q, base, align, depth);
+
+ DBG_RW_SVAL("info_class", depth, base, io, q, q_q->info_class); q += 2;
+
+ return q;
+}
+
+/*******************************************************************
+makes an LSA_Q_CLOSE structure.
+********************************************************************/
+void make_q_close(LSA_Q_CLOSE *q_c, LSA_POL_HND *hnd)
+{
+ if (q_c == NULL || hnd == NULL) return;
+
+ DEBUG(5,("make_q_close\n"));
+
+ memcpy(&(q_c->pol), hnd, sizeof(q_c->pol));
+}
+
+
+/*******************************************************************
+reads or writes an LSA_Q_CLOSE structure.
+********************************************************************/
+char* lsa_io_q_close(BOOL io, LSA_Q_CLOSE *q_c, char *q, char *base, int align, int depth)
+{
+ if (q_c == NULL) return NULL;
+
+ DEBUG(5,("%s%04x lsa_io_q_close\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = smb_io_pol_hnd(io, &(q_c->pol), q, base, align, depth);
+
+ return q;
+}
+
+/*******************************************************************
+makes an LSA_R_CLOSE structure.
+********************************************************************/
+void make_r_close(LSA_R_CLOSE *q_r, LSA_POL_HND *hnd)
+{
+ if (q_r == NULL || hnd == NULL) return;
+
+ DEBUG(5,("make_r_close\n"));
+
+ memcpy(&(q_r->pol), hnd, sizeof(q_r->pol));
+}
+
+
+/*******************************************************************
+reads or writes an LSA_R_CLOSE structure.
+********************************************************************/
+char* lsa_io_r_close(BOOL io, LSA_R_CLOSE *r_c, char *q, char *base, int align, int depth)
+{
+ if (r_c == NULL) return NULL;
+
+ DEBUG(5,("%s%04x lsa_io_r_close\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = smb_io_pol_hnd(io, &(r_c->pol), q, base, align, depth);
+
+ DBG_RW_IVAL("status", depth, base, io, q, r_c->status); q += 4;
+
+ return q;
+}
+
+/*******************************************************************
+reads or writes an LSA_Q_QUERY_INFO structure.
+********************************************************************/
+char* lsa_io_r_query(BOOL io, LSA_R_QUERY_INFO *r_q, char *q, char *base, int align, int depth)
+{
+ if (r_q == NULL) return NULL;
+
+ DEBUG(5,("%s%04x lsa_io_r_query\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ DBG_RW_IVAL("undoc_buffer", depth, base, io, q, r_q->undoc_buffer); q += 4;
+
+ if (r_q->undoc_buffer != 0)
+ {
+ DBG_RW_SVAL("info_class", depth, base, io, q, r_q->info_class); q += 2;
+
+ switch (r_q->info_class)
+ {
+ case 3:
+ {
+ q = smb_io_dom_query_3(io, &(r_q->dom.id3), q, base, align, depth);
+ break;
+ }
+ case 5:
+ {
+ q = smb_io_dom_query_5(io, &(r_q->dom.id3), q, base, align, depth);
+ break;
+ }
+ default:
+ {
+ /* PANIC! */
+ break;
+ }
+ }
+ }
+
+ DBG_RW_IVAL("status", depth, base, io, q, r_q->status); q += 4;
+
+ return q;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+char* lsa_io_q_lookup_sids(BOOL io, LSA_Q_LOOKUP_SIDS *q_s, char *q, char *base, int align, int depth)
+{
+ int i;
+
+ if (q_s == NULL) return NULL;
+
+ DEBUG(5,("%s%04x lsa_io_q_lookup_sids\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ q = smb_io_pol_hnd(io, &(q_s->pol_hnd), q, base, align, depth); /* policy handle */
+
+ DBG_RW_IVAL("num_entries ", depth, base, io, q, q_s->num_entries); q += 4;
+ DBG_RW_IVAL("buffer_dom_sid ", depth, base, io, q, q_s->buffer_dom_sid); q += 4; /* undocumented domain SID buffer pointer */
+ DBG_RW_IVAL("buffer_dom_name ", depth, base, io, q, q_s->buffer_dom_name); q += 4; /* undocumented domain name buffer pointer */
+
+ for (i = 0; i < q_s->num_entries; i++)
+ {
+ fstring temp;
+ sprintf(temp, "buffer_lookup_sids[%d] ", i);
+ DBG_RW_IVAL(temp, depth, base, io, q, q_s->buffer_lookup_sids[i]); q += 4; /* undocumented domain SID pointers to be looked up. */
+ }
+
+ for (i = 0; i < q_s->num_entries; i++)
+ {
+ q = smb_io_dom_sid(io, &(q_s->dom_sids[i]), q, base, align, depth); /* domain SIDs to be looked up. */
+ }
+
+ DBG_RW_PCVAL(False, "undoc ", depth, base, io, q, q_s->undoc, 16); q += 16; /* completely undocumented 16 bytes */
+
+ return q;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+char* lsa_io_r_lookup_sids(BOOL io, LSA_R_LOOKUP_SIDS *r_s, char *q, char *base, int align, int depth)
+{
+ int i;
+
+ if (r_s == NULL) return NULL;
+
+ DEBUG(5,("%s%04x lsa_io_r_lookup_sids\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ q = smb_io_dom_r_ref(io, &(r_s->dom_ref), q, base, align, depth); /* domain reference info */
+
+ DBG_RW_IVAL("num_entries ", depth, base, io, q, r_s->num_entries); q += 4;
+ DBG_RW_IVAL("undoc_buffer", depth, base, io, q, r_s->undoc_buffer); q += 4;
+ DBG_RW_IVAL("num_entries2", depth, base, io, q, r_s->num_entries2); q += 4;
+
+ for (i = 0; i < r_s->num_entries2; i++)
+ {
+ q = smb_io_dom_sid2(io, &(r_s->dom_sid[i]), q, base, align, depth); /* domain SIDs being looked up */
+ }
+
+ DBG_RW_IVAL("num_entries3", depth, base, io, q, r_s->num_entries3); q += 4;
+
+ DBG_RW_IVAL("status ", depth, base, io, q, r_s->status); q += 4;
+
+ return q;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+char* lsa_io_q_lookup_rids(BOOL io, LSA_Q_LOOKUP_RIDS *q_r, char *q, char *base, int align, int depth)
+{
+ int i;
+
+ if (q_r == NULL) return NULL;
+
+ DEBUG(5,("%s%04x lsa_io_q_lookup_rids\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ q = smb_io_pol_hnd(io, &(q_r->pol_hnd), q, base, align, depth); /* policy handle */
+
+ DBG_RW_IVAL("num_entries ", depth, base, io, q, q_r->num_entries); q += 4;
+ DBG_RW_IVAL("num_entries2 ", depth, base, io, q, q_r->num_entries2); q += 4;
+ DBG_RW_IVAL("buffer_dom_sid ", depth, base, io, q, q_r->buffer_dom_sid); q += 4; /* undocumented domain SID buffer pointer */
+ DBG_RW_IVAL("buffer_dom_name", depth, base, io, q, q_r->buffer_dom_name); q += 4; /* undocumented domain name buffer pointer */
+
+ for (i = 0; i < q_r->num_entries; i++)
+ {
+ q = smb_io_dom_name(io, &(q_r->lookup_name[i]), q, base, align, depth); /* names to be looked up */
+ }
+
+ DBG_RW_PCVAL(False, "undoc ", depth, base, io, q, q_r->undoc, UNKNOWN_LEN); q += UNKNOWN_LEN; /* completely undocumented bytes of unknown length */
+
+ return q;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+char* lsa_io_r_lookup_rids(BOOL io, LSA_R_LOOKUP_RIDS *r_r, char *q, char *base, int align, int depth)
+{
+ int i;
+
+ if (r_r == NULL) return NULL;
+
+ DEBUG(5,("%s%04x lsa_io_r_lookup_rids\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ q = smb_io_dom_r_ref(io, &(r_r->dom_ref), q, base, align, depth); /* domain reference info */
+
+ DBG_RW_IVAL("num_entries ", depth, base, io, q, r_r->num_entries); q += 4;
+ DBG_RW_IVAL("undoc_buffer", depth, base, io, q, r_r->undoc_buffer); q += 4;
+ DBG_RW_IVAL("num_entries2", depth, base, io, q, r_r->num_entries2); q += 4;
+
+ for (i = 0; i < r_r->num_entries2; i++)
+ {
+ q = smb_io_dom_rid2(io, &(r_r->dom_rid[i]), q, base, align, depth); /* domain RIDs being looked up */
+ }
+
+ DBG_RW_IVAL("num_entries3", depth, base, io, q, r_r->num_entries3); q += 4;
+
+ DBG_RW_IVAL("status ", depth, base, io, q, r_r->status); q += 4;
+
+ return q;
+}
+
+/*******************************************************************
+makes an LSA_Q_REQ_CHAL structure.
+********************************************************************/
+void make_q_req_chal(LSA_Q_REQ_CHAL *q_c,
+ char *logon_srv, char *logon_clnt,
+ DOM_CHAL *clnt_chal)
+{
+ if (q_c == NULL) return;
+
+ DEBUG(5,("make_q_req_chal: %d\n", __LINE__));
+
+ q_c->undoc_buffer = 1; /* don't know what this buffer is */
+
+ make_unistr2(&(q_c->uni_logon_srv ), logon_srv , strlen(logon_srv ));
+ make_unistr2(&(q_c->uni_logon_clnt), logon_clnt, strlen(logon_clnt));
+
+ memcpy(q_c->clnt_chal.data, clnt_chal->data, sizeof(clnt_chal->data));
+
+ DEBUG(5,("make_q_req_chal: %d\n", __LINE__));
+}
+
+/*******************************************************************
+reads or writes an LSA_Q_REQ_CHAL structure.
+********************************************************************/
+char* lsa_io_q_req_chal(BOOL io, LSA_Q_REQ_CHAL *q_c, char *q, char *base, int align, int depth)
+{
+ if (q_c == NULL) return NULL;
+
+ DEBUG(5,("%s%04x lsa_io_q_req_chal\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_IVAL("undoc_buffer", depth, base, io, q, q_c->undoc_buffer); q += 4;
+
+ q = smb_io_unistr2(io, &(q_c->uni_logon_srv), q, base, align, depth); /* logon server unicode string */
+ q = smb_io_unistr2(io, &(q_c->uni_logon_clnt), q, base, align, depth); /* logon client unicode string */
+
+ /* client challenge is _not_ aligned after the unicode strings */
+ q = smb_io_chal(io, &(q_c->clnt_chal), q, base, 0, depth); /* client challenge */
+
+ return q;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+char* lsa_io_r_req_chal(BOOL io, LSA_R_REQ_CHAL *r_c, char *q, char *base, int align, int depth)
+{
+ if (r_c == NULL) return NULL;
+
+ DEBUG(5,("%s%04x lsa_io_r_req_chal\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ q = smb_io_chal(io, &(r_c->srv_chal), q, base, align, depth); /* server challenge */
+
+ DBG_RW_IVAL("status", depth, base, io, q, r_c->status); q += 4;
+
+ return q;
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void make_q_auth_2(LSA_Q_AUTH_2 *q_a,
+ char *logon_srv, char *acct_name, uint16 sec_chan, char *comp_name,
+ DOM_CHAL *clnt_chal, uint32 clnt_flgs)
+{
+ if (q_a == NULL) return;
+
+ DEBUG(5,("make_q_auth_2: %d\n", __LINE__));
+
+ make_log_info(&(q_a->clnt_id), logon_srv, acct_name, sec_chan, comp_name);
+ memcpy(q_a->clnt_chal.data, clnt_chal->data, sizeof(clnt_chal->data));
+ q_a->clnt_flgs.neg_flags = clnt_flgs;
+
+ DEBUG(5,("make_q_auth_2: %d\n", __LINE__));
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+char* lsa_io_q_auth_2(BOOL io, LSA_Q_AUTH_2 *q_a, char *q, char *base, int align, int depth)
+{
+ if (q_a == NULL) return NULL;
+
+ DEBUG(5,("%s%04x lsa_io_q_auth_2\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ q = smb_io_log_info (io, &(q_a->clnt_id), q, base, align, depth); /* client identification info */
+ /* client challenge is _not_ aligned */
+ q = smb_io_chal (io, &(q_a->clnt_chal), q, base, 0, depth); /* client-calculated credentials */
+ q = smb_io_neg_flags(io, &(q_a->clnt_flgs), q, base, align, depth);
+
+ return q;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+char* lsa_io_r_auth_2(BOOL io, LSA_R_AUTH_2 *r_a, char *q, char *base, int align, int depth)
+{
+ if (r_a == NULL) return NULL;
+
+ DEBUG(5,("%s%04x lsa_io_r_auth_2\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ q = smb_io_chal (io, &(r_a->srv_chal), q, base, align, depth); /* server challenge */
+ q = smb_io_neg_flags(io, &(r_a->srv_flgs), q, base, align, depth);
+
+ DBG_RW_IVAL("status", depth, base, io, q, r_a->status); q += 4;
+
+ return q;
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+char* lsa_io_q_srv_pwset(BOOL io, LSA_Q_SRV_PWSET *q_s, char *q, char *base, int align, int depth)
+{
+ if (q_s == NULL) return NULL;
+
+ DEBUG(5,("%s%04x lsa_io_q_srv_pwset\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ q = smb_io_clnt_info(io, &(q_s->clnt_id), q, base, align, depth); /* client identification/authentication info */
+ DBG_RW_PCVAL(False, "pwd", depth, base, io, q, q_s->pwd, 16); q += 16; /* new password - undocumented */
+
+ return q;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+char* lsa_io_r_srv_pwset(BOOL io, LSA_R_SRV_PWSET *r_s, char *q, char *base, int align, int depth)
+{
+ if (r_s == NULL) return NULL;
+
+ DEBUG(5,("%s%04x lsa_io_r_srv_pwset\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ q = smb_io_cred(io, &(r_s->srv_cred), q, base, align, depth); /* server challenge */
+
+ DBG_RW_IVAL("status", depth, base, io, q, r_s->status); q += 4;
+
+ return q;
+}
+
+/* LSA_USER_INFO */
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+char* lsa_io_user_info(BOOL io, LSA_USER_INFO *usr, char *q, char *base, int align, int depth)
+{
+ int i;
+
+ if (usr == NULL) return NULL;
+
+ DEBUG(5,("%s%04x lsa_io_user_info\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_IVAL("ptr_user_info ", depth, base, io, q, usr->ptr_user_info); q += 4;
+
+ if (usr->ptr_user_info != 0)
+ {
+ q = smb_io_time(io, &(usr->logon_time) , q, base, align, depth); /* logon time */
+ q = smb_io_time(io, &(usr->logoff_time) , q, base, align, depth); /* logoff time */
+ q = smb_io_time(io, &(usr->kickoff_time) , q, base, align, depth); /* kickoff time */
+ q = smb_io_time(io, &(usr->pass_last_set_time) , q, base, align, depth); /* password last set time */
+ q = smb_io_time(io, &(usr->pass_can_change_time) , q, base, align, depth); /* password can change time */
+ q = smb_io_time(io, &(usr->pass_must_change_time), q, base, align, depth); /* password must change time */
+
+ q = smb_io_unihdr(io, &(usr->hdr_user_name) , q, base, align, depth); /* username unicode string header */
+ q = smb_io_unihdr(io, &(usr->hdr_full_name) , q, base, align, depth); /* user's full name unicode string header */
+ q = smb_io_unihdr(io, &(usr->hdr_logon_script), q, base, align, depth); /* logon script unicode string header */
+ q = smb_io_unihdr(io, &(usr->hdr_profile_path), q, base, align, depth); /* profile path unicode string header */
+ q = smb_io_unihdr(io, &(usr->hdr_home_dir) , q, base, align, depth); /* home directory unicode string header */
+ q = smb_io_unihdr(io, &(usr->hdr_dir_drive) , q, base, align, depth); /* home directory drive unicode string header */
+
+ DBG_RW_SVAL("logon_count ", depth, base, io, q, usr->logon_count ); q += 2; /* logon count */
+ DBG_RW_SVAL("bad_pw_count ", depth, base, io, q, usr->bad_pw_count); q += 2; /* bad password count */
+
+ DBG_RW_IVAL("user_id ", depth, base, io, q, usr->user_id ); q += 4; /* User ID */
+ DBG_RW_IVAL("group_id ", depth, base, io, q, usr->group_id ); q += 4; /* Group ID */
+ DBG_RW_IVAL("num_groups ", depth, base, io, q, usr->num_groups ); q += 4; /* num groups */
+ DBG_RW_IVAL("buffer_groups ", depth, base, io, q, usr->buffer_groups); q += 4; /* undocumented buffer pointer to groups. */
+ DBG_RW_IVAL("user_flgs ", depth, base, io, q, usr->user_flgs ); q += 4; /* user flags */
+
+ DBG_RW_PCVAL(False, "user_sess_key", depth, base, io, q, usr->user_sess_key, 16); q += 16; /* unused user session key */
+
+ q = smb_io_unihdr(io, &(usr->hdr_logon_srv), q, base, align, depth); /* logon server unicode string header */
+ q = smb_io_unihdr(io, &(usr->hdr_logon_dom), q, base, align, depth); /* logon domain unicode string header */
+
+ DBG_RW_IVAL("buffer_dom_id ", depth, base, io, q, usr->buffer_dom_id); q += 4; /* undocumented logon domain id pointer */
+ DBG_RW_PCVAL(False, "padding ", depth, base, io, q, usr->padding, 40); q += 40; /* unused padding bytes? */
+
+ DBG_RW_IVAL("num_other_sids", depth, base, io, q, usr->num_other_sids); q += 4; /* 0 - num_sids */
+ DBG_RW_IVAL("buffer_other_sids", depth, base, io, q, usr->buffer_other_sids); q += 4; /* NULL - undocumented pointer to SIDs. */
+
+ q = smb_io_unistr2(io, &(usr->uni_user_name) , q, base, align, depth); /* username unicode string */
+ q = smb_io_unistr2(io, &(usr->uni_full_name) , q, base, align, depth); /* user's full name unicode string */
+ q = smb_io_unistr2(io, &(usr->uni_logon_script), q, base, align, depth); /* logon script unicode string */
+ q = smb_io_unistr2(io, &(usr->uni_profile_path), q, base, align, depth); /* profile path unicode string */
+ q = smb_io_unistr2(io, &(usr->uni_home_dir) , q, base, align, depth); /* home directory unicode string */
+ q = smb_io_unistr2(io, &(usr->uni_dir_drive) , q, base, align, depth); /* home directory drive unicode string */
+
+ DBG_RW_IVAL("num_groups2 ", depth, base, io, q, usr->num_groups2); q += 4; /* num groups */
+ for (i = 0; i < usr->num_groups2; i++)
+ {
+ q = smb_io_gid(io, &(usr->gids[i]), q, base, align, depth); /* group info */
+ }
+
+ q = smb_io_unistr2(io, &( usr->uni_logon_srv), q, base, align, depth); /* logon server unicode string */
+ q = smb_io_unistr2(io, &( usr->uni_logon_dom), q, base, align, depth); /* logon domain unicode string */
+
+ q = smb_io_dom_sid(io, &(usr->dom_sid), q, base, align, depth); /* domain SID */
+
+ for (i = 0; i < usr->num_other_sids; i++)
+ {
+ q = smb_io_dom_sid(io, &(usr->other_sids[i]), q, base, align, depth); /* other domain SIDs */
+ }
+ }
+
+ return q;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+char* lsa_io_q_sam_logon(BOOL io, LSA_Q_SAM_LOGON *q_l, char *q, char *base, int align, int depth)
+{
+ if (q_l == NULL) return NULL;
+
+ DEBUG(5,("%s%04x lsa_io_q_sam_logon\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ q = smb_io_sam_info(io, &(q_l->sam_id), q, base, align, depth); /* domain SID */
+
+ return q;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+char* lsa_io_r_sam_logon(BOOL io, LSA_R_SAM_LOGON *r_l, char *q, char *base, int align, int depth)
+{
+ if (r_l == NULL) return NULL;
+
+ DEBUG(5,("%s%04x lsa_io_r_sam_logon\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_IVAL("buffer_creds", depth, base, io, q, r_l->buffer_creds); q += 4; /* undocumented buffer pointer */
+ q = smb_io_cred(io, &(r_l->srv_creds), q, base, align, depth); /* server credentials. server time stamp appears to be ignored. */
+
+ DBG_RW_SVAL("switch_value", depth, base, io, q, r_l->switch_value); q += 2; /* 1 - Authoritative response; 0 - Non-Auth? */
+ q = align_offset(q, base, align);
+ q = lsa_io_user_info(io, r_l->user, q, base, align, depth);
+ DBG_RW_IVAL("auth_resp ", depth, base, io, q, r_l->auth_resp); q += 4; /* 1 - Authoritative response; 0 - Non-Auth? */
+
+ DBG_RW_IVAL("status ", depth, base, io, q, r_l->status); q += 4;
+
+ return q;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+char* lsa_io_q_sam_logoff(BOOL io, LSA_Q_SAM_LOGOFF *q_l, char *q, char *base, int align, int depth)
+{
+ if (q_l == NULL) return NULL;
+
+ DEBUG(5,("%s%04x lsa_io_q_sam_logoff\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ q = smb_io_sam_info(io, &(q_l->sam_id), q, base, align, depth); /* domain SID */
+
+ return q;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+char* lsa_io_r_sam_logoff(BOOL io, LSA_R_SAM_LOGOFF *r_l, char *q, char *base, int align, int depth)
+{
+ if (r_l == NULL) return NULL;
+
+ DEBUG(5,("%s%04x lsa_io_r_sam_logoff\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_IVAL("buffer_creds", depth, base, io, q, r_l->buffer_creds); q += 4; /* undocumented buffer pointer */
+ q = smb_io_cred(io, &(r_l->srv_creds), q, base, align, depth); /* server credentials. server time stamp appears to be ignored. */
+
+ DBG_RW_IVAL("status ", depth, base, io, q, r_l->status); q += 4;
+
+ return q;
+}
+
+#if 0
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+ char* lsa_io_(BOOL io, *, char *q, char *base, int align, int depth)
+{
+ if (== NULL) return NULL;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_IVAL("", depth, base, io, q, ); q += 4;
+
+ return q;
+}
+#endif
diff --git a/source/md4.h b/source/md4.h
deleted file mode 100644
index 3f60d75fe3c..00000000000
--- a/source/md4.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- This code is from rfc1186.
-*/
-
- /*
- ** ********************************************************************
- ** md4.h -- Header file for implementation of **
- ** MD4 Message Digest Algorithm **
- ** Updated: 2/13/90 by Ronald L. Rivest **
- ** (C) 1990 RSA Data Security, Inc. **
- ** ********************************************************************
- */
-
- /* MDstruct is the data structure for a message digest computation.
- */
- typedef struct {
- unsigned int buffer[4]; /* Holds 4-word result of MD computation */
- unsigned char count[8]; /* Number of bits processed so far */
- unsigned int done; /* Nonzero means MD computation finished */
- } MDstruct, *MDptr;
-
- /* MDbegin(MD)
-
-
-
- ** Input: MD -- an MDptr
- ** Initialize the MDstruct prepatory to doing a message digest
- ** computation.
- */
- extern void MDbegin();
-
- /* MDupdate(MD,X,count)
- ** Input: MD -- an MDptr
- ** X -- a pointer to an array of unsigned characters.
- ** count -- the number of bits of X to use (an unsigned int).
- ** Updates MD using the first "count" bits of X.
- ** The array pointed to by X is not modified.
- ** If count is not a multiple of 8, MDupdate uses high bits of
- ** last byte.
- ** This is the basic input routine for a user.
- ** The routine terminates the MD computation when count < 512, so
- ** every MD computation should end with one call to MDupdate with a
- ** count less than 512. Zero is OK for a count.
- */
- extern void MDupdate();
-
- /* MDprint(MD)
- ** Input: MD -- an MDptr
- ** Prints message digest buffer MD as 32 hexadecimal digits.
- ** Order is from low-order byte of buffer[0] to high-order byte
- ** of buffer[3].
- ** Each byte is printed with high-order hexadecimal digit first.
- */
- extern void MDprint();
-
- /*
- ** End of md4.h
- */
diff --git a/source/nameannounce.c b/source/nameannounce.c
new file mode 100644
index 00000000000..03fab914deb
--- /dev/null
+++ b/source/nameannounce.c
@@ -0,0 +1,520 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1997
+
+ SMB Version handling
+ Copyright (C) John H Terpstra 1995-1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+*/
+
+#include "includes.h"
+
+#define TEST_CODE
+
+extern int DEBUGLEVEL;
+extern BOOL CanRecurse;
+
+extern struct in_addr ipzero;
+
+extern pstring myname;
+extern fstring myworkgroup;
+extern char **my_netbios_names;
+
+extern int ClientDGRAM;
+extern int ClientNMB;
+
+/* this is our domain/workgroup/server database */
+extern struct subnet_record *subnetlist;
+
+extern int updatecount;
+extern int workgroup_count;
+
+extern struct in_addr wins_ip;
+
+extern pstring scope;
+
+/****************************************************************************
+ send a announce request to the local net
+ **************************************************************************/
+void announce_request(struct work_record *work, struct in_addr ip)
+{
+ pstring outbuf;
+ char *p;
+
+ if (!work) return;
+
+ work->needannounce = True;
+
+ DEBUG(2,("sending announce request to %s for workgroup %s\n",
+ inet_ntoa(ip),work->work_group));
+
+ bzero(outbuf,sizeof(outbuf));
+ p = outbuf;
+ CVAL(p,0) = ANN_AnnouncementRequest;
+ p++;
+
+ CVAL(p,0) = work->token; /* (local) unique workgroup token id */
+ p++;
+ StrnCpy(p,myname,16);
+ strupper(p);
+ p = skip_string(p,1);
+
+ /* XXXX note: if we sent the announcement request to 0x1d instead
+ of 0x1e, then we could get the master browser to announce to
+ us instead of the members of the workgroup. wha-hey! */
+
+ send_mailslot_reply(False, BROWSE_MAILSLOT, ClientDGRAM,
+ outbuf,PTR_DIFF(p,outbuf),
+ myname,work->work_group,0x20,0x1e,ip,*iface_ip(ip));
+}
+
+
+/****************************************************************************
+ request an announcement
+ **************************************************************************/
+void do_announce_request(char *info, char *to_name, int announce_type,
+ int from,
+ int to, struct in_addr dest_ip)
+{
+ pstring outbuf;
+ char *p;
+
+ bzero(outbuf,sizeof(outbuf));
+ p = outbuf;
+ CVAL(p,0) = announce_type;
+ p++;
+
+ DEBUG(2,("sending announce type %d: info %s to %s - server %s(%x)\n",
+ announce_type, info, inet_ntoa(dest_ip),to_name,to));
+
+ StrnCpy(p,info,16);
+ strupper(p);
+ p = skip_string(p,1);
+
+ send_mailslot_reply(False,BROWSE_MAILSLOT, ClientDGRAM,
+ outbuf,PTR_DIFF(p,outbuf),
+ myname,to_name,from,to,dest_ip,*iface_ip(dest_ip));
+}
+
+
+/****************************************************************************
+ find a server responsible for a workgroup, and sync browse lists
+ control ends up back here via response_name_query.
+ **************************************************************************/
+void sync_server(enum state_type state, char *serv_name, char *work_name,
+ int name_type,
+ struct subnet_record *d,
+ struct in_addr ip)
+{
+ /* with a domain master we can get the whole list (not local only list) */
+ BOOL local_only = (state != NAME_STATUS_DOM_SRV_CHK);
+
+ add_browser_entry(serv_name, name_type, work_name, 0, d, ip, local_only);
+
+ if (state == NAME_STATUS_DOM_SRV_CHK)
+ {
+ /* announce ourselves as a master browser to serv_name */
+ do_announce_request(myname, serv_name, ANN_MasterAnnouncement,
+ 0x20, 0, ip);
+ }
+}
+
+
+/****************************************************************************
+ send a host announcement packet
+ **************************************************************************/
+static void do_announce_host(int command,
+ char *from_name, int from_type, struct in_addr from_ip,
+ char *to_name , int to_type , struct in_addr to_ip,
+ time_t announce_interval,
+ char *server_name, int server_type, char *server_comment)
+{
+ pstring outbuf;
+ char *p;
+
+ bzero(outbuf,sizeof(outbuf));
+ p = outbuf+1;
+
+ /* command type */
+ CVAL(outbuf,0) = command;
+
+ /* announcement parameters */
+ CVAL(p,0) = updatecount;
+ SIVAL(p,1,announce_interval*1000); /* ms - despite the spec */
+
+ StrnCpy(p+5,server_name,16);
+ strupper(p+5);
+
+ CVAL(p,21) = lp_major_announce_version(); /* major version */
+ CVAL(p,22) = lp_minor_announce_version(); /* minor version */
+
+ SIVAL(p,23,server_type & ~SV_TYPE_LOCAL_LIST_ONLY);
+ /* browse version: got from NT/AS 4.00 - Value defined in smb.h (JHT)*/
+ SSVAL(p,27,BROWSER_ELECTION_VERSION);
+ SSVAL(p,29,BROWSER_CONSTANT); /* browse signature */
+
+ pstrcpy(p+31,server_comment);
+ p += 31;
+ p = skip_string(p,1);
+
+ debug_browse_data(outbuf, PTR_DIFF(p,outbuf));
+
+ /* send the announcement */
+ send_mailslot_reply(False,BROWSE_MAILSLOT, ClientDGRAM, outbuf,
+ PTR_DIFF(p,outbuf),
+ from_name, to_name,
+ from_type, to_type,
+ to_ip, from_ip);
+}
+
+
+/****************************************************************************
+announce all samba's server entries as 'gone'.
+****************************************************************************/
+void announce_my_servers_removed(void)
+{
+ struct subnet_record *d;
+ for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
+ {
+ 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 (!is_myname(s->serv.name)) continue;
+ announce_server(d, work, s->serv.name, s->serv.comment, 0, 0);
+ }
+ }
+ }
+}
+
+
+/****************************************************************************
+ announce a server entry
+ ****************************************************************************/
+void announce_server(struct subnet_record *d, struct work_record *work,
+ char *name, char *comment, time_t ttl, int server_type)
+{
+ /* domain type cannot have anything in it that might confuse
+ a client into thinking that the domain is in fact a server.
+ (SV_TYPE_SERVER_UNIX, for example)
+ */
+ uint32 domain_type = SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT;
+ BOOL wins_iface = ip_equal(d->bcast_ip, wins_ip);
+
+ if(wins_iface)
+ {
+ DEBUG(0,("announce_server: error - announcement requested on WINS \
+interface for workgroup %s, name %s\n", work->work_group, name));
+ return;
+ }
+
+ /* Only do domain announcements if we are a master and it's
+ our name we're being asked to announce. */
+ if (AM_MASTER(work) && strequal(myname,name))
+ {
+ DEBUG(3,("sending local master announce to %s for %s(1e)\n",
+ inet_ntoa(d->bcast_ip),work->work_group));
+
+ do_announce_host(ANN_LocalMasterAnnouncement,
+ name , 0x00, d->myip,
+ work->work_group, 0x1e, d->bcast_ip,
+ ttl,
+ name, server_type, comment);
+
+ DEBUG(3,("sending domain announce to %s for %s\n",
+ inet_ntoa(d->bcast_ip),work->work_group));
+
+ /* XXXX should we do a domain-announce-kill? */
+ if (server_type != 0)
+ {
+ do_announce_host(ANN_DomainAnnouncement,
+ name , 0x00, d->myip,
+ MSBROWSE, 0x01, d->bcast_ip,
+ ttl,
+ work->work_group, server_type ? domain_type : 0,
+ name);
+ }
+ }
+ else
+ {
+ DEBUG(3,("sending host announce to %s for %s(1d)\n",
+ inet_ntoa(d->bcast_ip),work->work_group));
+
+ do_announce_host(ANN_HostAnnouncement,
+ name , 0x00, d->myip,
+ work->work_group, 0x1d, d->bcast_ip,
+ ttl,
+ name, server_type, comment);
+ }
+}
+
+/****************************************************************************
+ construct a host announcement unicast
+ **************************************************************************/
+void announce_host(time_t t)
+{
+ struct subnet_record *d;
+ pstring comment;
+ char *my_name;
+
+ StrnCpy(comment, lp_serverstring(), 43);
+
+ my_name = *myname ? myname : "NoName";
+
+ for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
+ {
+ struct work_record *work;
+
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ uint32 stype = work->ServerType;
+ struct server_record *s;
+
+ /* must work on the code that does announcements at up to
+ 30 seconds later if a master browser sends us a request
+ announce.
+ */
+
+ if (work->needannounce) {
+ /* drop back to a max 3 minute announce - this is to prevent a
+ single lost packet from stuffing things up for too long */
+ work->announce_interval = MIN(work->announce_interval,
+ CHECK_TIME_MIN_HOST_ANNCE*60);
+ work->lastannounce_time = t - (work->announce_interval+1);
+ }
+
+ /* announce every minute at first then progress to every 12 mins */
+ if (work->lastannounce_time &&
+ (t - work->lastannounce_time) < work->announce_interval)
+ continue;
+
+ if (work->announce_interval < CHECK_TIME_MAX_HOST_ANNCE * 60)
+ work->announce_interval += 60;
+
+ work->lastannounce_time = t;
+
+ for (s = work->serverlist; s; s = s->next) {
+ if (is_myname(s->serv.name)) {
+ /* If we are any kind of browser or logon server, only
+ announce it for our primary name, not our aliases. */
+ if(!strequal(myname, s->serv.name))
+ stype &= ~(SV_TYPE_MASTER_BROWSER|SV_TYPE_POTENTIAL_BROWSER|
+ SV_TYPE_DOMAIN_MASTER|SV_TYPE_DOMAIN_MEMBER);
+ announce_server(d,work,s->serv.name,comment,
+ work->announce_interval,stype);
+ }
+ }
+
+ if (work->needannounce)
+ {
+ work->needannounce = False;
+ break;
+ /* sorry: can't do too many announces. do some more later */
+ }
+ }
+ }
+}
+
+/* Announce timer. Moved into global static so it can be reset
+ when a machine becomes a master browser. */
+static time_t announce_timer_last=0;
+
+/****************************************************************************
+ Reset the announce_timer so that a master browser announce will be done
+ immediately.
+ ****************************************************************************/
+
+void reset_announce_timer()
+{
+ announce_timer_last = time(NULL) - (CHECK_TIME_MST_ANNOUNCE * 60);
+}
+
+/****************************************************************************
+ announce myself as a master to all other domain master browsers.
+
+ this actually gets done in search_and_sync_workgroups() via the
+ NAME_QUERY_DOM_SRV_CHK command, if there is a response from the
+ name query initiated here. see response_name_query()
+ **************************************************************************/
+void announce_master(time_t t)
+{
+ struct subnet_record *d;
+ struct work_record *work;
+ BOOL am_master = False; /* are we a master of some sort? :-) */
+
+ if (!announce_timer_last) announce_timer_last = t;
+ if (t-announce_timer_last < CHECK_TIME_MST_ANNOUNCE * 60)
+ {
+ DEBUG(10,("announce_master: t (%d) - last(%d) < %d\n",
+ t, announce_timer_last, CHECK_TIME_MST_ANNOUNCE * 60 ));
+ return;
+ }
+
+ if(wins_client_subnet == NULL)
+ {
+ DEBUG(10,("announce_master: no wins subnet, ignoring.\n"));
+ return;
+ }
+
+ announce_timer_last = t;
+
+ for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
+ {
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ if (AM_MASTER(work))
+ {
+ am_master = True;
+ DEBUG(4,( "announce_master: am_master = %d for \
+workgroup %s\n", am_master, work->work_group));
+ }
+ }
+ }
+
+ if (!am_master) return; /* only proceed if we are a master browser */
+
+ /* Note that we don't do this if we are domain master browser
+ and that we *only* do this on the WINS subnet. */
+
+ /* Try and find our workgroup on the WINS subnet */
+ work = find_workgroupstruct(wins_client_subnet, myworkgroup, False);
+
+ if (work)
+ {
+ /* assume that the domain master browser we want to sync
+ with is our own domain.
+ */
+ char *name = work->work_group;
+ int type = 0x1b;
+
+ /* check the existence of a dmb 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_wins_support() && *lp_wins_server() )
+ {
+ DEBUG(4, ("Local Announce: find %s<%02x> from WINS server %s\n",
+ name, type, lp_wins_server()));
+
+ queue_netbios_pkt_wins(ClientNMB,
+ NMB_QUERY,NAME_QUERY_DOM_SRV_CHK,
+ name, type, 0,0,0,
+ work->work_group,NULL,
+ ipzero, ipzero);
+ }
+ else if(lp_wins_support())
+ {
+ /* We are the WINS server - query ourselves for the dmb name. */
+
+ struct nmb_name netb_name;
+ struct name_record *nr = 0;
+
+ make_nmb_name(&netb_name, name, type, scope);
+
+ if ((nr = find_name_on_subnet(wins_client_subnet, &netb_name, FIND_ANY_NAME)) == 0)
+ {
+ DEBUG(0, ("announce_master: unable to find domain master browser for workgroup %s \
+in our own WINS database.\n", work->work_group));
+ return;
+ }
+
+ /* Check that this isn't one of our addresses (ie. we are not domain master
+ ourselves) */
+ if(ismyip(nr->ip_flgs[0].ip) || ip_equal(nr->ip_flgs[0].ip, ipzero))
+ {
+ DEBUG(4, ("announce_master: domain master ip found (%s) for workgroup %s \
+is one of our interfaces.\n", work->work_group, inet_ntoa(nr->ip_flgs[0].ip) ));
+ return;
+ }
+
+ /* Issue a NAME_STATUS_DOM_SRV_CHK immediately - short circuit the
+ NAME_QUERY_DOM_SRV_CHK which is done only if we are talking to a
+ remote WINS server. */
+
+ DEBUG(4, ("announce_master: doing name status for %s<%02x> to domain master ip %s \
+for workgroup %s\n", name, type, inet_ntoa(nr->ip_flgs[0].ip), work->work_group ));
+
+ queue_netbios_packet(wins_client_subnet, ClientNMB,
+ NMB_STATUS,NAME_STATUS_DOM_SRV_CHK,
+ name, type, 0,0,0,
+ work->work_group,NULL,
+ False, False, nr->ip_flgs[0].ip, nr->ip_flgs[0].ip, 0);
+ }
+ }
+}
+
+/****************************************************************************
+ do all the "remote" announcements. These are used to put ourselves
+ on a remote browse list. They are done blind, no checking is done to
+ see if there is actually a browse master at the other end.
+ **************************************************************************/
+void announce_remote(time_t t)
+{
+ char *s,*ptr;
+ static time_t last_time = 0;
+ pstring s2;
+ struct in_addr addr;
+ char *comment,*workgroup;
+ int stype = lp_default_server_announce();
+
+ if (last_time && t < last_time + REMOTE_ANNOUNCE_INTERVAL)
+ return;
+
+ last_time = t;
+
+ s = lp_remote_announce();
+ if (!*s) return;
+
+ comment = lp_serverstring();
+ workgroup = myworkgroup;
+
+ for (ptr=s; next_token(&ptr,s2,NULL); )
+ {
+ /* the entries are of the form a.b.c.d/WORKGROUP with
+ WORKGROUP being optional */
+ char *wgroup;
+ int n;
+
+ wgroup = strchr(s2,'/');
+ if (wgroup) *wgroup++ = 0;
+ if (!wgroup || !*wgroup)
+ wgroup = workgroup;
+
+ addr = *interpret_addr2(s2);
+
+ /* Announce all our names including aliases */
+ for (n=0; my_netbios_names[n]; n++)
+ {
+ char *name = my_netbios_names[n];
+ do_announce_host(ANN_HostAnnouncement,name,0x20,*iface_ip(addr),
+ wgroup,0x1e,addr,
+ REMOTE_ANNOUNCE_INTERVAL,
+ name,stype,comment);
+ }
+ }
+
+}
diff --git a/source/nameannounce.doc b/source/nameannounce.doc
new file mode 100644
index 00000000000..e04a59209a1
--- /dev/null
+++ b/source/nameannounce.doc
@@ -0,0 +1,265 @@
+/*
+ Unix SMB/Netbios documentation.
+ Version 0.2
+ Copyright (C) Luke Leighton Andrew Tridgell 1996
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Document name: nameannounce.doc
+
+ Revision History:
+
+ 0.0 - 02jul96 : lkcl@pires.co.uk
+ created
+
+ 0.1 - 22jul96 : Andrew.Tridgell@anu.edu.au
+ tridge's comments on first revision
+
+ 0.2 - 05aug96 : lkcl@pires.co.uk
+ actioned tridge comments about pdc -> domain master
+ documented NAME_QUERY_ANNOUNCE_HOST
+
+*/
+
+
+this module deals with announcements: the sending of announcement requests
+and the sending of announcements either to refresh other servers' records
+or as a response to announcement requests.
+
+
+/*************************************************************************
+ announce_master()
+ *************************************************************************/
+
+this function is responsible for announcing samba as a master browser
+to all known domain masters.
+
+this announcement is sent out at CHECK_TIME_MST_ANNOUNCE minute
+intervals, only if samba is a master browser on one or more of
+its local interfaces.
+
+if no domain controller has been specified (lp_domain_controller())
+samba goes through its list of servers looking for domain master
+browsers. when it finds one (other than itself) it will either
+initiate a NAME_QUERY_PDC_SRV_CHK by broadcast or with a WINS
+server. this will result in a NAME_STATUS_PDC_SRV_CHK, which
+will result in a sync browse list and an announcement
+ANN_MasterAnnounce being sent (see sync_server()).
+
+if a domain controller has been specified, samba will search for
+a domain master browser for its workgroup (either by directed
+packet or by broadcast if it cannot resolve the domain controller
+name using DNS), which results in the same action as listed above.
+
+------------
+NOTE FROM TRIDGE:
+
+PDC in the above should really be DMB (domain master browser). They
+might be separate entities.
+
+I also propose a simpler scheme :-)
+
+If a DMB is not configured with lp_domain_controller() (perhaps
+renamed to lp_domain_master()?) then just don't do master
+announcements. Remember that most peoples networks are very simple and
+don't need DMB capabilities. Those that do need them will have more
+complex network topologies and they really need to choose themselves
+which box will act as the "hub" for netbios name resolution. Doing it
+via name queries will just lead to lag and propogation delays, because
+if two parts of the net choose different DMBs then the data will be
+very slow to propoogate.
+
+If a DMB is configured then just send the master announcemnt to that
+box! Thats all that needs to be done. Just send a udp 138 packet and
+forget it. If the recipient is indeed a DMB (as it should be if the
+config file is correct) then it should initiate a browse list sync
+with us at some later time, but that is take care of by smbd and nmbd
+doesn't even need to know it happened.
+
+Additionally, if a DMB is configured we need to sync our workgroup
+list and server list with them occasionally. Note that this is only
+time a non-DMB should do a browse sync, and it should only do it with
+a DMB. Essentially WAN based netbios is just a simple star. There is a
+DMB in the centre, and the individual master browsers for each subnet
+talk to it, but never talk to each other. If they start talking to
+each other then the network load will go as the square of the number
+of machines, which will result in meltdown :-)
+-------------
+
+
+/*************************************************************************
+ announce_host()
+ *************************************************************************/
+
+this complex-looking function is responsible for announcing samba's
+existence to other servers by broadcast. the actual announcement
+is carried out by announce_server().
+
+the time period between samba's announcement will stretch from one
+minute to twelve minutes by one minute. if samba has received an
+announce request from a master browser, then it should answer at
+any random interval between zero and thirty seconds after the
+request is received. this is to ensure that the master browser
+does not get overloaded with responses!
+
+
+/*************************************************************************
+ announce_server()
+ *************************************************************************/
+
+this function is responsible for sending announcement packets.
+these packets are received by other servers, which will then
+update their records accordingly: what services we have, our
+name, our comment field and our time to live (to name a few).
+
+if samba is a non-master then we need to see if there is a
+domain master (on a remote subnet) that we need to announce to
+it.
+
+if samba is not the WINS server (and it is using another
+WINS server) then we need to do a name query to the WINS
+server to ask it what the domain controller is. this is done
+using a samba 'state' NAME_QUERY_ANNOUNCE_HOST, which passes
+sufficient information on to be able to carry out the
+host announcement using a unicasted do_announce_host() if and
+when a reply comes back. if there is no reply to the name query,
+this is not necessarily an error - there may genuinely be no
+domain master currently up and running for samba's workgroup.
+
+if samba is a WINS server, then samba will need to look up the
+domain controller for its workgroup in its WINS records. an
+over-cautious samba could carry out a name query on that
+domain controller to make sure that it is alive and that samba's
+WINS records are up-to-date. in any event, it will send a unicast
+do_announce_host() to inform the domain master browser, if one
+exists, of samba's server status.
+
+if we are a master browser, then using do_announce_host() we
+must send a broadcast announcement on the local interface
+notifying members of that workgroup that we are their master
+browser, and another announcement indicating to all backup
+browsers and master browsers that we are a master browser.
+
+(note: if another master browser receives this broadcasted
+announcement and thinks that it is also the master browser
+for this workgroup, it stops being a master browser and forces
+an election).
+
+if we are not a master browser, then we send a broacast
+announcement notifying the master browser that we are a member
+of its workgroup, on the local interface.
+
+
+/*************************************************************************
+ remove_my_servers()
+ *************************************************************************/
+
+this function is responsible for informing other servers that
+samba is about to go down. it announces, on all subnets, that
+samba's time to live is zero and that it has no services.
+
+
+/*************************************************************************
+ do_announce_host()
+ *************************************************************************/
+
+this function is responsible for sending out an announcement
+MAILSLOT browse packet. it contains information such as the
+time to live, name of the server, services that the server
+offers etc.
+
+the format of this MAILSLOT browse packet is described in
+draft-heizer-cifs-v1-spec-00.txt 3.9.50.4.1 page 165-6.
+
+
+/*************************************************************************
+ announce_backup()
+ *************************************************************************/
+
+this function is responsible for getting master browsers and domain
+controllers to send us lists of backup servers. this is done by
+sending an ANN_GetBackupListReq browse mailslot.
+
+the local master browser, or domain master browser, should respond
+with an ANN_GetBackupListResp browse mailslot containing the list
+of backup servers.
+
+--------------
+NOTE FROM TRIDGE: I don't see why nmbd should ever send one of
+these. The only reason I can see for any part of Samba sending one of
+these is if we implement it in smbclient.
+
+This packet is used to request a list of backup master browsers from
+the master browser. It is used by clients (not servers!) to spread the
+browse load over more than one server. The only server that needs to
+know what the list of backups is is the master browser, and as it is
+also responsible for generating this list it will never ask anyone
+else for it.
+--------------
+
+
+/*************************************************************************
+ sync_server()
+ *************************************************************************/
+
+this function is responsible for initiating a sync browse list
+sequence and, if necessary, carrying out an ANN_MasterAnnouncement
+to the domain master browser (that we are also sync'ing browse lists
+with).
+
+see nameservresp.c:response_name_status_check().
+
+
+/*************************************************************************
+ announce_request()
+ *************************************************************************/
+
+this function is responsible for sending an announcement request to
+another server. this server should respond with an announcement.
+
+if the announce request is sent to WORKGROUP(0x1e) then members of
+the workgroup will respond (with ANN_HostAnnounce packets)
+
+if the announce request is sent to WORKGROUP(0x1d) then the master
+browser of the workgroup should respond (ANN_LocalMasterAnnounce).
+this is untested.
+
+if the announce request is sent to ^1^2__MSBROWSE__^2(0x1) then
+(and this is pure speculation), all backup browsers and master
+browsers should respond with ANN_DomainAnnounce packets.
+this is untested.
+
+-----------
+NOTE FROM TRIDGE:
+
+I had great trouble getting machines to actually respond to this
+packet. Either we have the format wrong or MS chose not to implement
+it.
+
+Not implementing it doesn't break anything, it just means a new master
+browser won't get a complete server list as quickly.
+
+Also note that this packet should be used as little as possible as it
+could easily cause meltdown if too many servers used it. Imagine a
+dozen samba servers on a net all sending this packet! You will get 244
+responses all within 30 seconds. now imagine 50 samba servers ....
+
+So I think we should restrict ourselves to sending this packet only if
+we are already the master browser for a workgroup. We could send a
+single "announce request" when we become the master, just to prime our
+server lists. From then on the normal announce cycles should take care
+of keeping it uptodate.
+-----------
+
diff --git a/source/namebrowse.c b/source/namebrowse.c
new file mode 100644
index 00000000000..c0deaff0fae
--- /dev/null
+++ b/source/namebrowse.c
@@ -0,0 +1,246 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+*/
+
+#include "includes.h"
+#include "smb.h"
+
+extern int ClientNMB;
+
+extern int DEBUGLEVEL;
+
+extern struct in_addr wins_ip;
+
+/* this is our browse master/backup cache database */
+static struct browse_cache_record *browserlist = NULL;
+
+
+/***************************************************************************
+ add a browser into the list
+ **************************************************************************/
+static void add_browse_cache(struct browse_cache_record *b)
+{
+ struct browse_cache_record *b2;
+
+ if (!browserlist)
+ {
+ browserlist = b;
+ b->prev = NULL;
+ b->next = NULL;
+ return;
+ }
+
+ for (b2 = browserlist; b2->next; b2 = b2->next) ;
+
+ b2->next = b;
+ b->next = NULL;
+ b->prev = b2;
+}
+
+
+/*******************************************************************
+ remove old browse entries
+ ******************************************************************/
+void expire_browse_cache(time_t t)
+{
+ struct browse_cache_record *b;
+ struct browse_cache_record *nextb;
+
+ /* expire old entries in the serverlist */
+ for (b = browserlist; b; b = nextb)
+ {
+ if (b->synced && b->sync_time < t)
+ {
+ DEBUG(3,("Removing dead cached browser %s\n",b->name));
+ nextb = b->next;
+
+ if (b->prev) b->prev->next = b->next;
+ if (b->next) b->next->prev = b->prev;
+
+ if (browserlist == b) browserlist = b->next;
+
+ free(b);
+ }
+ else
+ {
+ nextb = b->next;
+ }
+ }
+}
+
+/****************************************************************************
+ add a browser entry
+ ****************************************************************************/
+struct browse_cache_record *add_browser_entry(char *name, int type, char *wg,
+ time_t ttl, struct subnet_record *d,
+ struct in_addr ip, BOOL local)
+{
+ BOOL newentry=False;
+
+ struct browse_cache_record *b;
+
+ /* search for the entry: if it's already in the cache, update that entry */
+ for (b = browserlist; b; b = b->next)
+ {
+ if (ip_equal(ip,b->ip) && strequal(b->group, wg)) break;
+ }
+
+ if (b && b->synced)
+ {
+ /* entries get left in the cache for a while. this stops sync'ing too
+ often if the network is large */
+ DEBUG(4, ("browser %s %s %s already sync'd at time %d\n",
+ b->name, b->group, inet_ntoa(b->ip), b->sync_time));
+ return NULL;
+ }
+
+ if (!b)
+ {
+ newentry = True;
+ b = (struct browse_cache_record *)malloc(sizeof(*b));
+
+ if (!b) return(NULL);
+
+ bzero((char *)b,sizeof(*b));
+ }
+
+ /* update the entry */
+ ttl = time(NULL)+ttl;
+
+ StrnCpy(b->name ,name,sizeof(b->name )-1);
+ StrnCpy(b->group,wg ,sizeof(b->group)-1);
+ strupper(b->name);
+ strupper(b->group);
+
+ b->ip = ip;
+ b->type = type;
+ b->local = local; /* local server list sync or complete sync required */
+ b->subnet = d;
+
+ if (newentry || ttl < b->sync_time)
+ b->sync_time = ttl;
+
+ if (newentry)
+ {
+ b->synced = False;
+ add_browse_cache(b);
+
+ DEBUG(3,("Added cache entry %s %s(%2x) %s ttl %d\n",
+ wg, name, type, inet_ntoa(ip),ttl));
+ }
+ else
+ {
+ DEBUG(3,("Updated cache entry %s %s(%2x) %s ttl %d\n",
+ wg, name, type, inet_ntoa(ip),ttl));
+ }
+
+ return(b);
+}
+
+
+/****************************************************************************
+find a server responsible for a workgroup, and sync browse lists
+**************************************************************************/
+static void start_sync_browse_entry(struct browse_cache_record *b)
+{
+ struct subnet_record *d = b->subnet;
+ struct work_record *work;
+
+ /* Check panic conditions - these should not be true. */
+ if(b->subnet != wins_client_subnet) {
+ DEBUG(0,
+ ("start_sync_browse_entry: ERROR sync requested on non-WINS subnet.\n"));
+ return;
+ }
+
+ if (!(work = find_workgroupstruct(d, b->group, False))) {
+ DEBUG(0, ("start_sync_browse_entry: failed to get a \
+workgroup for a browse cache entry workgroup %s, server %s\n",
+ b->group, b->name));
+ return;
+ }
+
+ DEBUG(4, ("start_sync_browse_entry: Initiating %s sync with %s<0x20>, \
+workgroup %s\n",
+ b->local ? "local" : "remote", b->name, b->group));
+
+ /* first check whether the server we intend to sync with exists. if it
+ doesn't, the server must have died. o dear. */
+
+ /* see response_netbios_packet() or expire_netbios_response_entries() */
+ /* We cheat here by using the my_comment field of the response_record
+ struct as the workgroup name we are going to do the sync for.
+ This is because the reply packet doesn't include the workgroup, but
+ we need it when the reply comes back.
+ */
+ queue_netbios_packet(d,ClientNMB,NMB_QUERY,
+ b->local?NAME_QUERY_SYNC_LOCAL:NAME_QUERY_SYNC_REMOTE,
+ b->name,0x20,0,0,0,NULL,b->group,
+ False,False,b->ip,b->ip, 0);
+
+ b->synced = True;
+}
+
+
+/****************************************************************************
+ search through browser list for an entry to sync with
+ **************************************************************************/
+void do_browser_lists(time_t t)
+{
+ struct browse_cache_record *b;
+ static time_t last = 0;
+
+ if (t-last < 20)
+ {
+ DEBUG(9,("do_browser_lists: returning due to t(%d) - last(%d) < 20\n",
+ t, last));
+ return; /* don't do too many of these at once! */
+ /* XXXX equally this period should not be too long
+ the server may die in the intervening gap */
+ }
+ last = t;
+
+ /* pick any entry in the list, preferably one whose time is up */
+ for (b = browserlist; b && b->next; b = b->next)
+ {
+ if (b->sync_time < t && b->synced == False) break;
+ }
+
+ if (b && !b->synced)
+ {
+ /* sync with the selected entry then remove some dead entries */
+ DEBUG(4,("do_browser_lists: Initiating sync with %s, workgroup %s\n",
+ b->name, b->group));
+ start_sync_browse_entry(b);
+ }
+ else
+ {
+ DEBUG(9, ("do_browser_lists: no entries to sync.\n"));
+ }
+
+ expire_browse_cache(t - 60);
+}
+
diff --git a/source/namebrowse.doc b/source/namebrowse.doc
new file mode 100644
index 00000000000..82713d85708
--- /dev/null
+++ b/source/namebrowse.doc
@@ -0,0 +1,149 @@
+/*
+ Unix SMB/Netbios documentation.
+ Version 0.1
+ Copyright (C) Luke Leighton Andrew Tridgell 1996
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Document name: namebrowse.doc
+
+ Revision History:
+
+ 0.0 - 02jul96 : lkcl@pires.co.uk
+ created
+
+ 0.1 - 22jul96 Andrew.Tridgell@anu.edu.au
+ tridge's comments on first revision
+*/
+
+this module deals with queueing servers that samba must sync browse
+lists with. it will always issue a name query immediately before
+actually carrying out the NetServerEnum call, to ensure that time
+is not wasted by a remote server's failure.
+
+this module was created to minimise the amount of NetServerEnum calls
+that samba may be asked to perform, by maintaining the name of a server
+for up to a minute after the NetServerEnum call was issued, and
+disallowing further NetServerEnum calls to this remote server until
+the entry is removed.
+
+samba can ask for a NetServerEnum call to be issued to grab a remote
+server's list of servers and workgroups either in its capacity as
+a domain master browser, as a local master browser.
+
+samba does not deal with becoming a backup master browser properly
+at present.
+
+-------------
+NOTE FROM TRIDGE:
+
+Yes, samba can send these either in its capacity as a DMB or as a
+MB. There are only two situations:
+
+- If samba is a DMB then it should sync with the "local only" bit set
+with any master browser that has sent it a "master announce".
+
+- if samba is not a DMB then it can only sync with the DMB, and should
+not set the "local only" bit.
+
+Note that samba should never sync with other non-DMB servers when it
+is not a DMB.
+
+Try to do a sync under any other circumstances is dangerous without a
+multi-threaded nmbd. I have a print server at home that knows some SMB
+and NBT, but if you try to sync browse lists with it then it clogs up,
+and also clogs up nmbd while it times out the connection. If we
+follow the above two rules then we can't get into this sort of
+trouble as:
+
+- if we are a DMB and a master browser sends us a "master announce"
+then it is expecting to receive a NetServerEnum SMB connection soon,
+and must be capabable of handling it.
+
+- if we are not a DMB then we will only sync with the DMB, which must
+be capable of doing this stuff or things are really in a mess :-)
+--------------
+
+
+/*************************************************************************
+ do_browser_lists()
+ *************************************************************************/
+
+this function is responsible for finding an appropriate entry in the
+sync browser cache, initiating a name query (which results in a
+NetServerEnum call if there is a positive response), and then
+removing all entries that have been actioned and have been around
+for over a minute.
+
+
+/*************************************************************************
+ start_sync_browse_entry()
+ *************************************************************************/
+
+this function is responsible for initiating a name query. if a
+positive response is received, then this will result in a
+NetServerEnum api call.
+
+samba will only initiate this process if it is a master browser
+for this workgroup.
+
+-----------
+NOTE FROM TRIDGE:
+
+I'd actually prefer to skip the name query completely if we can
+resolve the DMBs name via gethostbyname(). For the name query to work
+we either have to have WINS working, or we need to know the broadcast
+address of the network that the DMB is on. This makes us too dependent
+on too many thing being right.
+
+If the gethostbyname() fails then sure, go for a normal name query,
+but if it works then we have saved ourselves a lot of trouble and
+gained a lot of robustness.
+
+This is best handled by a generic "resolve netbios name" routine that
+tries DNS first then resorts to WINS or bcast if that fails. It also
+needs to cache the results.
+-------------
+
+
+/*************************************************************************
+ add_browser_entry()
+ *************************************************************************/
+
+this function is responsible for adding a browser into the list of
+servers to sync browse lists with. if the server entry has already
+been added and syncing browse lists has already been initiated, it
+will not be added again.
+
+
+/*************************************************************************
+ expire_browse_cache()
+ *************************************************************************/
+
+this function is responsible for removing entries that have had the
+sync browse list initiated (whether that succeeded or not is beyond
+this function's scope) and have been in the cache for a while.
+
+
+/*************************************************************************
+ add_browse_entry()
+ *************************************************************************/
+
+this function is responsible for adding a new entry into the list
+of servers to sync browse lists with at some point in the near future.
+
+
+
+
diff --git a/source/nameconf.c b/source/nameconf.c
new file mode 100644
index 00000000000..19068780611
--- /dev/null
+++ b/source/nameconf.c
@@ -0,0 +1,350 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) David Chappell 1996-1997
+
+ 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:
+
+ 30 July 96: David.Chappell@mail.trincoll.edu
+ Expanded multiple workgroup domain master browser support.
+
+*/
+
+/*
+** nameconf.c
+** These functions dispense information from smbbrowse.conf.
+**
+**
+*/
+
+#include "includes.h"
+extern int DEBUGLEVEL;
+
+extern fstring myworkgroup;
+
+#if 0
+struct smbbrowse_parms
+ {
+ char *name;
+ BOOL (*reader)(char *string, void *toset);
+ } smbbrowse_table[] =
+{
+ {"preferred master", NULL},
+ {"local master", NULL},
+ {"domain master", NULL}
+} ;
+#endif
+
+/*
+** Structure for the list of workgroups from smbbrowse.conf. This
+** structure should only be manipulated thru the functions in this file.
+** That is why it is not defined in a header file.
+*/
+struct smbbrowse
+{
+ char work_name[16]; /* workgroup name */
+ char browsing_alias[16]; /* alias for our role in this workgroup */
+ struct server_identity *my_names; /* a list of server name we should appear here as */
+ BOOL should_workgroup_member; /* should we try to become a member of this workgroup? */
+ BOOL should_local_master; /* should we try to become a master browser? */
+ BOOL should_domain_master; /* should we try to become the domain master browser? */
+} ;
+
+/* The whole list */
+static struct smbbrowse *smbbrowse_workgroups = (struct smbbrowse*)NULL;
+
+/* The size of the list */
+static int array_size = 0;
+
+/* The next available space in the list */
+static int nexttoken = 0;
+
+int get_num_workgroups(void)
+{
+ return nexttoken;
+}
+
+/*
+** This makes a new workgroup structure, possibly taking an
+** old one as a model.
+*/
+static struct smbbrowse *new_workgroup(struct smbbrowse *model,
+ char *workgroup_name,
+ char *default_name)
+{
+ struct smbbrowse *new;
+
+ if( ! (array_size > nexttoken) )
+ {
+ array_size += 10;
+ smbbrowse_workgroups = (struct smbbrowse*)realloc(smbbrowse_workgroups,
+ array_size * sizeof(struct smbbrowse));
+ }
+
+ new = &smbbrowse_workgroups[nexttoken];
+
+ if(model != (struct smbbrowse *)NULL )
+ memcpy(new, model, sizeof(struct smbbrowse));
+ else
+ memset(new, 0, sizeof(struct smbbrowse));
+
+ StrnCpy(new->work_name, workgroup_name, 15);
+ strupper(new->work_name);
+
+ if (strequal(myworkgroup, workgroup_name))
+ StrnCpy(new->browsing_alias, default_name, 15);
+ else
+ sprintf(new->browsing_alias, "%.14s%x", default_name, nexttoken);
+ strupper(new->browsing_alias);
+
+ DEBUG(4,("wg: %s alias: %s token: %x\n",
+ new->work_name, new->browsing_alias, nexttoken));
+
+ nexttoken++;
+ return new;
+}
+
+/*
+** If fed a workgroup name, this function returns its token number.
+** If the workgroup does not exist a new token is assigned unless
+** new workgroups are not allowed.
+*/
+int conf_workgroup_name_to_token(char *workgroup_name,char *default_name)
+{
+ int idx;
+
+ /* Look for an existing instance. */
+ for(idx=0; idx < nexttoken; idx++)
+ {
+ if(strequal(workgroup_name, smbbrowse_workgroups[idx].work_name))
+ {
+ return idx;
+ }
+ }
+
+ /* See if creating new ones in admissable. */
+ for(idx=0; idx < nexttoken; idx++)
+ {
+ if(strequal("*", smbbrowse_workgroups[idx].work_name))
+ {
+ struct smbbrowse *w = new_workgroup(&smbbrowse_workgroups[idx],
+ workgroup_name, default_name);
+ w->should_workgroup_member = False;
+
+ return (nexttoken - 1);
+ }
+ }
+
+ /* Not allowed */
+ DEBUG(4, ("refusing to allow new workgroup\n"));
+ return -1;
+}
+
+/*
+** This is a workgroups array bounds checker.
+*/
+static int range_check(int token)
+{
+ if(token < 0 || token >= nexttoken)
+ {
+ DEBUG(0, ("range_check(): failed\n"));
+ return True;
+ }
+
+ return False;
+}
+
+/*
+** Given a token, return the name.
+*/
+char *conf_workgroup_name(int token)
+{
+ if(range_check(token))
+ return (char*)NULL;
+
+ return smbbrowse_workgroups[token].work_name;
+}
+
+/*
+** Given a token, return True if we should try
+** to become a master browser.
+*/
+int conf_should_workgroup_member(int token)
+ {
+
+ if(range_check(token))
+ return False;
+
+ return smbbrowse_workgroups[token].should_workgroup_member;
+ }
+
+/*
+** Given a token, return True if we should try
+** to become a master browser.
+*/
+int conf_should_local_master(int token)
+ {
+ if(range_check(token))
+ return False;
+
+ return smbbrowse_workgroups[token].should_local_master;
+ }
+
+/*
+** Given a token, return True if we should try
+** to become a domain master browser.
+*/
+int conf_should_domain_master(int token)
+ {
+ if(range_check(token))
+ return False;
+
+ return smbbrowse_workgroups[token].should_domain_master;
+ }
+
+/*
+** Given a token, return the name.
+*/
+char *conf_browsing_alias(int token)
+ {
+ if(range_check(token))
+ return (char*)NULL;
+
+ return smbbrowse_workgroups[token].browsing_alias;
+ }
+
+/*
+** Return the server comment which should be used with the
+** browsing alias.
+*/
+char *conf_browsing_alias_comment(int token)
+{
+ if(range_check(token))
+ return (char*) NULL;
+
+ return "Browser";
+ }
+
+/*
+** Given an alias name for this server, return the name of the workgroup
+** for which it is the browsing alias.
+*/
+char *conf_alias_to_workgroup(char *alias)
+{
+ int x;
+
+ DEBUG(4,("alias_to_workgroup: %s", alias));
+
+ for(x=0; x < nexttoken; x++)
+ {
+ DEBUG(4,("%s ", smbbrowse_workgroups[x].browsing_alias));
+
+ if(strequal(alias, smbbrowse_workgroups[x].browsing_alias))
+ {
+ DEBUG(4,("OK\n"));
+ return smbbrowse_workgroups[x].work_name;
+ }
+ }
+ DEBUG(4,("not found\n"));
+ return (char*)NULL;
+}
+
+/*
+** Given an alias name for this server, return the name of the workgroup
+** for which it is the browsing alias.
+*/
+int conf_alias_to_token(char *alias)
+{
+ int x;
+
+ for(x=0; x < nexttoken; x++)
+ {
+ if(strequal(alias, smbbrowse_workgroups[x].browsing_alias))
+ {
+ return x;
+ }
+ }
+ return -1;
+}
+
+/*
+** Since there is no smbbrowse.conf file, we will fill in
+** the structures with information from the smb.conf file.
+*/
+static void default_smbbrowse_conf(char *default_name)
+{
+ struct smbbrowse *w;
+
+ /* The workgroup specified in smb.conf */
+ w = new_workgroup((struct smbbrowse *)NULL, myworkgroup, default_name);
+ w->should_local_master = lp_preferred_master();
+ w->should_domain_master = lp_domain_master();
+ w->should_workgroup_member = True;
+
+ /* default action: allow any new workgroup to be added */
+ w = new_workgroup((struct smbbrowse *)NULL, "*", default_name);
+ w->should_local_master = False;
+ w->should_domain_master = False;
+ w->should_workgroup_member = False;
+}
+
+/*
+** This function is called from main().
+*/
+void read_smbbrowse_conf(char *default_name)
+{
+ FILE *f = fopen(BROWSEFILE,"r");
+ if (f)
+ {
+ while (!feof(f))
+ {
+ pstring line;
+ char *ptr;
+ int count = 0;
+
+ pstring work_name;
+ struct smbbrowse *w;
+
+ if (!fgets_slash(line,sizeof(pstring),f)) continue;
+
+ if (*line == '#') continue;
+
+ strcpy(work_name,"");
+
+ ptr = line;
+
+ if (next_token(&ptr, work_name, NULL)) ++count;
+
+ if (count <= 0) continue;
+
+ w = new_workgroup((struct smbbrowse *)NULL, work_name, default_name);
+ w->should_local_master = lp_local_master();
+ w->should_domain_master = lp_domain_master();
+ w->should_workgroup_member = True;
+ }
+
+ fclose(f);
+ }
+ else
+ {
+ DEBUG(2,("Can't open browse configuration file %s\n",BROWSEFILE));
+ }
+ default_smbbrowse_conf(default_name);
+}
+
+
diff --git a/source/namedbname.c b/source/namedbname.c
new file mode 100644
index 00000000000..6ff20f4d45c
--- /dev/null
+++ b/source/namedbname.c
@@ -0,0 +1,518 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Module name: namedbname.c
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+ 04 jul 96: lkcl@pires.co.uk
+ created module namedbname containing name database functions
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+extern pstring scope;
+extern struct in_addr ipzero;
+extern struct in_addr wins_ip;
+extern BOOL updatedlists;
+
+extern struct subnet_record *subnetlist;
+
+#define WINS_LIST "wins.dat"
+
+uint16 nb_type = 0; /* samba's NetBIOS name type */
+
+
+/****************************************************************************
+ samba's NetBIOS name type
+
+ XXXX maybe functionality could be set: B, M, P or H name registration
+ and resolution could be set through nb_type. just a thought.
+ ****************************************************************************/
+void set_samba_nb_type(void)
+{
+ if (lp_wins_support() || (*lp_wins_server()))
+ {
+ nb_type = NB_MFLAG; /* samba is a 'hybrid' node type */
+ }
+ else
+ {
+ nb_type = NB_BFLAG; /* samba is broadcast-only node type */
+ }
+}
+
+
+/****************************************************************************
+ true if two netbios names are equal
+****************************************************************************/
+BOOL name_equal(struct nmb_name *n1,struct nmb_name *n2)
+{
+ return n1->name_type == n2->name_type &&
+ strequal(n1->name ,n2->name ) &&
+ strequal(n1->scope,n2->scope);
+}
+
+
+/****************************************************************************
+ true if the netbios name is ^1^2__MSBROWSE__^2^1
+
+ note: this name is registered if as a master browser or backup browser
+ you are responsible for a workgroup (when you announce a domain by
+ broadcasting on your local subnet, you announce it as coming from this
+ name: see announce_host()).
+
+ **************************************************************************/
+BOOL ms_browser_name(char *name, int type)
+{
+ return strequal(name,MSBROWSE) && type == 0x01;
+}
+
+
+/****************************************************************************
+ add a netbios name into the namelist
+ **************************************************************************/
+static void add_name(struct subnet_record *d, struct name_record *n)
+{
+ struct name_record *n2;
+
+ if (!d) return;
+
+ if (!d->namelist)
+ {
+ d->namelist = n;
+ n->prev = NULL;
+ n->next = NULL;
+ return;
+ }
+
+ for (n2 = d->namelist; n2->next; n2 = n2->next) ;
+
+ n2->next = n;
+ n->next = NULL;
+ n->prev = n2;
+
+ if((d == wins_client_subnet) && lp_wins_support())
+ updatedlists = True;
+}
+
+
+/****************************************************************************
+ remove a name from the namelist. The pointer must be an element just
+ retrieved
+ **************************************************************************/
+void remove_name(struct subnet_record *d, struct name_record *n)
+{
+ struct name_record *nlist;
+ if (!d) return;
+
+ nlist = d->namelist;
+
+ while (nlist && nlist != n) nlist = nlist->next;
+
+ if (nlist)
+ {
+ if (nlist->next) nlist->next->prev = nlist->prev;
+ if (nlist->prev) nlist->prev->next = nlist->next;
+
+ if(nlist == d->namelist)
+ d->namelist = nlist->next;
+
+ if(nlist->ip_flgs != NULL)
+ free(nlist->ip_flgs);
+ free(nlist);
+ }
+
+ if((d == wins_client_subnet) && lp_wins_support())
+ updatedlists = True;
+}
+
+
+/****************************************************************************
+ find a name in a subnet.
+ **************************************************************************/
+struct name_record *find_name_on_subnet(struct subnet_record *d,
+ struct nmb_name *name, BOOL self_only)
+{
+ struct name_record *n = d->namelist;
+ struct name_record *ret;
+
+ for (ret = n; ret; ret = ret->next)
+ {
+ if (name_equal(&ret->name,name))
+ {
+ /* self search: self names only */
+ if (self_only && (ret->source != SELF))
+ {
+ continue;
+ }
+ DEBUG(9,("find_name_on_subnet: on subnet %s - found name %s(%02x) source=%d\n",
+ inet_ntoa(d->bcast_ip), name->name, name->name_type, ret->source));
+ return ret;
+ }
+ }
+ DEBUG(9,("find_name_on_subnet: on subnet %s - name %s(%02x) NOT FOUND\n",
+ inet_ntoa(d->bcast_ip), name->name, name->name_type));
+ return NULL;
+}
+
+/****************************************************************************
+ dump a copy of the name table
+ **************************************************************************/
+void dump_names(void)
+{
+ struct name_record *n;
+ fstring fname, fnamenew;
+ time_t t = time(NULL);
+
+ FILE *f;
+
+ if(lp_wins_support() == False || wins_client_subnet == NULL)
+ return;
+
+ fstrcpy(fname,lp_lockdir());
+ trim_string(fname,NULL,"/");
+ strcat(fname,"/");
+ strcat(fname,WINS_LIST);
+ fstrcpy(fnamenew,fname);
+ strcat(fnamenew,".");
+
+ f = fopen(fnamenew,"w");
+
+ if (!f)
+ {
+ DEBUG(3,("Can't open %s - %s\n",fnamenew,strerror(errno)));
+ return;
+ }
+
+ DEBUG(4,("Dump of WINS name table:\n"));
+
+ for (n = wins_client_subnet->namelist; n; n = n->next)
+ {
+ int i;
+
+ DEBUG(4,("%15s ", inet_ntoa(wins_client_subnet->bcast_ip)));
+ DEBUG(4,("%15s ", inet_ntoa(wins_client_subnet->mask_ip)));
+ DEBUG(4,("%-19s TTL=%ld ",
+ namestr(&n->name),
+ n->death_time?n->death_time-t:0));
+
+ for (i = 0; i < n->num_ips; i++)
+ {
+ DEBUG(4,("%15s NB=%2x source=%d",
+ inet_ntoa(n->ip_flgs[i].ip),
+ n->ip_flgs[i].nb_flags,n->source));
+
+ }
+ DEBUG(4,("\n"));
+
+ if (f && ((n->source == REGISTER) || (n->source == SELF)))
+ {
+ /* XXXX i have little imagination as to how to output nb_flags as
+ anything other than as a hexadecimal number :-) */
+
+ fprintf(f, "%s#%02x %ld ",
+ n->name.name,n->name.name_type, /* XXXX ignore scope for now */
+ n->death_time);
+
+ for (i = 0; i < n->num_ips; i++)
+ {
+ fprintf(f, "%s %2x%c ",
+ inet_ntoa(n->ip_flgs[i].ip),
+ n->ip_flgs[i].nb_flags, (n->source == REGISTER ? 'R' : 'S'));
+ }
+ fprintf(f, "\n");
+ }
+
+ }
+
+ fclose(f);
+ unlink(fname);
+ chmod(fnamenew,0644);
+ rename(fnamenew,fname);
+
+ DEBUG(3,("Wrote wins database %s\n",fname));
+}
+
+
+/****************************************************************************
+ load a netbios name database file
+
+ XXXX we cannot cope with loading Internet Group names, yet
+ ****************************************************************************/
+void load_netbios_names(void)
+{
+ struct subnet_record *d = wins_client_subnet;
+ fstring fname;
+
+ FILE *f;
+ pstring line;
+
+ if (!d) return;
+
+ fstrcpy(fname,lp_lockdir());
+ trim_string(fname,NULL,"/");
+ strcat(fname,"/");
+ strcat(fname,WINS_LIST);
+
+ f = fopen(fname,"r");
+
+ if (!f) {
+ DEBUG(2,("Can't open wins database file %s\n",fname));
+ return;
+ }
+
+ while (!feof(f))
+ {
+ pstring name_str, ip_str, ttd_str, nb_flags_str;
+
+ pstring name;
+ int type = 0;
+ unsigned int nb_flags;
+ time_t ttd;
+ struct in_addr ipaddr;
+
+ enum name_source source;
+
+ char *ptr;
+ int count = 0;
+
+ char *p;
+
+ if (!fgets_slash(line,sizeof(pstring),f)) continue;
+
+ if (*line == '#') continue;
+
+ ptr = line;
+
+ if (next_token(&ptr,name_str ,NULL)) ++count;
+ if (next_token(&ptr,ttd_str ,NULL)) ++count;
+ if (next_token(&ptr,ip_str ,NULL)) ++count;
+ if (next_token(&ptr,nb_flags_str,NULL)) ++count;
+
+ if (count <= 0) continue;
+
+ if (count != 4) {
+ DEBUG(0,("Ill formed wins line"));
+ DEBUG(0,("[%s]: name#type abs_time ip nb_flags\n",line));
+ continue;
+ }
+
+ /* Deal with SELF or REGISTER name encoding. Default is REGISTER
+ for compatibility with old nmbds. */
+ if(nb_flags_str[strlen(nb_flags_str)-1] == 'S')
+ {
+ DEBUG(5,("Ignoring SELF name %s\n", line));
+ continue;
+ }
+
+ if(nb_flags_str[strlen(nb_flags_str)-1] == 'R')
+ nb_flags_str[strlen(nb_flags_str)-1] = '\0';
+
+ /* netbios name. # divides the name from the type (hex): netbios#xx */
+ pstrcpy(name,name_str);
+
+ p = strchr(name,'#');
+
+ if (p) {
+ *p = 0;
+ sscanf(p+1,"%x",&type);
+ }
+
+ /* decode the netbios flags (hex) and the time-to-die (seconds) */
+ sscanf(nb_flags_str,"%x",&nb_flags);
+ sscanf(ttd_str,"%ld",&ttd);
+
+ ipaddr = *interpret_addr2(ip_str);
+
+ if (ip_equal(ipaddr,ipzero)) {
+ source = SELF;
+ }
+ else
+ {
+ source = REGISTER;
+ }
+
+ DEBUG(4, ("add WINS line: %s#%02x %ld %s %2x\n",
+ name,type, ttd, inet_ntoa(ipaddr), nb_flags));
+
+ /* add all entries that have 60 seconds or more to live */
+ if (ttd - 60 > time(NULL) || ttd == 0)
+ {
+ time_t t = (ttd?ttd-time(NULL):0) / 3;
+
+ /* add netbios entry read from the wins.dat file. IF it's ok */
+ add_netbios_entry(d,name,type,nb_flags,t,source,ipaddr,True);
+ }
+ }
+
+ fclose(f);
+}
+
+
+/****************************************************************************
+ remove an entry from the name list
+ ****************************************************************************/
+void remove_netbios_name(struct subnet_record *d,
+ char *name,int type, enum name_source source)
+{
+ struct nmb_name nn;
+ struct name_record *n;
+
+ make_nmb_name(&nn, name, type, scope);
+ n = find_name_on_subnet(d, &nn, FIND_ANY_NAME);
+
+ if (n && n->source == source) remove_name(d,n);
+}
+
+
+/****************************************************************************
+ add an entry to the name list.
+
+ this is a multi-purpose function.
+
+ it adds samba's own names in to its records on each interface, keeping a
+ record of whether it is a master browser, domain master, or WINS server.
+
+ it also keeps a record of WINS entries.
+
+ ****************************************************************************/
+struct name_record *add_netbios_entry(struct subnet_record *d,
+ char *name, int type, int nb_flags, int ttl,
+ enum name_source source, struct in_addr ip, BOOL new_only)
+{
+ struct name_record *n;
+ struct name_record *n2=NULL;
+ BOOL self = (source == SELF) ? FIND_SELF_NAME : FIND_ANY_NAME;
+ /* It's a WINS add if we're adding to the wins_client_subnet. */
+ BOOL wins = ( wins_client_subnet && (d == wins_client_subnet));
+
+ if(d == NULL)
+ {
+ DEBUG(0,("add_netbios_entry: called with NULL subnet record. This is a bug - \
+please report this.!\n"));
+ return NULL;
+ }
+
+ if (!self)
+ {
+ if (!wins && (type != 0x1b))
+ {
+ /* the only broadcast (non-WINS) names we are adding are ours
+ (SELF) and Domain Master type names */
+ return NULL;
+ }
+ if(wins && (type == 0x1d))
+ {
+ /* Do not allow any 0x1d names to be registered in a WINS,
+ database although we return success for them.
+ */
+ return NULL;
+ }
+ }
+
+ n = (struct name_record *)malloc(sizeof(*n));
+ if (!n) return(NULL);
+
+ bzero((char *)n,sizeof(*n));
+
+ n->num_ips = 1; /* XXXX ONLY USE THIS FUNCTION FOR ONE ENTRY */
+ n->ip_flgs = (struct nmb_ip*)malloc(sizeof(*n->ip_flgs) * n->num_ips);
+ if (!n->ip_flgs)
+ {
+ free(n);
+ return NULL;
+ }
+
+ bzero((char *)n->ip_flgs, sizeof(*n->ip_flgs) * n->num_ips);
+
+ make_nmb_name(&n->name,name,type,scope);
+
+ if ((n2 = find_name_on_subnet(d, &n->name, self)))
+ {
+ free(n->ip_flgs);
+ free(n);
+ if (new_only || (n2->source==SELF && source!=SELF)) return n2;
+ n = n2;
+ }
+
+ if (ttl)
+ n->death_time = time(NULL)+ttl*3;
+ n->refresh_time = time(NULL)+GET_TTL(ttl);
+
+ /* XXXX only one entry expected with this function */
+ n->ip_flgs[0].ip = ip;
+ n->ip_flgs[0].nb_flags = nb_flags;
+
+ n->source = source;
+
+ if (!n2) add_name(d,n);
+
+ DEBUG(3,("Added netbios name %s at %s ttl=%d nb_flags=%2x to interface %s\n",
+ namestr(&n->name),inet_ntoa(ip),ttl,nb_flags,
+ wins ? "WINS" : (char *)inet_ntoa(d->bcast_ip)));
+
+ return(n);
+}
+
+
+/*******************************************************************
+ expires old names in the namelist
+ ******************************************************************/
+void expire_names(time_t t)
+{
+ struct name_record *n;
+ struct name_record *next;
+ struct subnet_record *d;
+
+ /* expire old names */
+ for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
+ {
+ for (n = d->namelist; n; n = next)
+ {
+ next = n->next;
+ if (n->death_time && n->death_time < t)
+ {
+ if (n->source == SELF)
+ {
+ DEBUG(3,("not expiring SELF name %s\n", namestr(&n->name)));
+ n->death_time += 300;
+ continue;
+ }
+ DEBUG(3,("Removing dead name %s\n", namestr(&n->name)));
+
+ if (n->prev) n->prev->next = n->next;
+ if (n->next) n->next->prev = n->prev;
+
+ if (d->namelist == n) d->namelist = n->next;
+
+ if(n->ip_flgs != NULL)
+ free(n->ip_flgs);
+ free(n);
+ }
+ }
+ }
+}
+
+
diff --git a/source/namedbname.doc b/source/namedbname.doc
new file mode 100644
index 00000000000..34a791dbb89
--- /dev/null
+++ b/source/namedbname.doc
@@ -0,0 +1,182 @@
+/*
+ Unix SMB/Netbios documentation.
+ Version 0.0
+ Copyright (C) Luke Leighton Andrew Tridgell 1996
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Document name: namedbname.doc
+
+ Revision History:
+
+ 0.0 - 02jul96 : lkcl@pires.co.uk
+ created
+*/
+
+this module deals with the NetBIOS name database for samba. it deals
+directly with adding, removing, finding, loading and saving of names.
+
+/*************************************************************************
+ search_for_name()
+ *************************************************************************/
+
+this function is responsible for finding a name in the appropriate part
+of samba's NetBIOS name database. if the name cannot be found, then it
+should look the name up using DNS. later modifications will be to
+forward the request on to another WINS server, should samba not be able
+to find out about the requested name (this will be implemented through
+issuing a new type of samba 'state').
+
+the name is first searched for in the NetBIOS cache. if it cannot be
+found, then it if the name looks like it's a server-type name (0x20
+0x0 or 0x1b) then DNS is used to look for the name.
+
+if DNS fails, then a record of this failure is kept. if it succeeds, then
+a new NetBIOS entry is added.
+
+the successfully found name is returned. on failure, NULL is returned.
+
+
+/*************************************************************************
+ expire_names()
+ *************************************************************************/
+
+this function is responsible for removing old NetBIOS names from its
+database. no further action is required.
+
+for over-zealous WINS systems, the use of query_refresh_names() is
+recommended. this function initiates polling of hosts that have
+registered with samba in its capacity as a WINS server. an alternative
+means to achieve the same end as query_refresh_names() is to
+reduce the time to live when the name is registered with samba,
+except that in this instance the responsibility for refreshing the
+name is with the owner of the name, not the server with which the name
+is registered.
+
+
+/*************************************************************************
+ add_netbios_entry()
+ *************************************************************************/
+
+this function is responsible for adding or updating a NetBIOS name
+in the database. into the local interface records, the only names
+that will be added are those of domain master browsers and
+samba's own names. into the WINS records, all names are added.
+
+the name to be added / updated will be looked up in the records.
+if it is found, then we will not overwrite the entry if the flag
+'newonly' is True, or if the name is being added as a non-SELF
+(non-samba) name and the records indicate that samba owns the
+name.
+
+otherwise, the name is added or updated with the new details.
+
+
+/*************************************************************************
+ remove_netbios_entry()
+ *************************************************************************/
+
+this function is responsible for removing a NetBIOS entry from
+the database. the name is searched for in the records using
+find_name_search(). if the ip is zero, then the ip is ignored.
+
+the name is removed if the expected source (e.g SELF, REGISTER)
+matches that in the database.
+
+
+/*************************************************************************
+ load_netbios_names()
+ *************************************************************************/
+
+this function is responsible for loading any NetBIOS names that samba,
+in its WINS capacity, has written out to disk. all the relevant details
+are recorded in this file, including the time-to-live. should the
+time left to live be small, the name is not added back in to samba's
+WINS database.
+
+
+/*************************************************************************
+ dump_names()
+ *************************************************************************/
+
+this function is responsible for outputting NetBIOS names in two formats.
+firstly, as debugging information, and secondly, all names that have been
+registered with samba in its capacity as a WINS server are written to
+disk.
+
+writing all WINS names allows two things. firstly, if samba's NetBIOS
+daemon dies or is terminated, on restarting the daemon most if not all
+of the registered WINS names will be preserved (which is a good reason
+why query_netbios_names() should be used).
+
+
+/*************************************************************************
+ find_name_search()
+ *************************************************************************/
+
+this function is a wrapper around find_name(). find_name_search() can
+be told whether to search for the name in a local subnet structure or
+in the WINS database. on top of this, it can be told to search only
+for samba's SELF names.
+
+if it finds the name in the WINS database, it will set the subnet_record
+and also return the name it finds.
+
+
+/*************************************************************************
+ find_name()
+ *************************************************************************/
+
+this function is a low-level search function that searches a single
+interface's NetBIOS records for a name. if the ip to be found is
+zero then the ip address is ignored. this is to enable a name to
+be found without knowing its ip address, and also to find the exact
+name if a large number of group names are added with different ip
+addresses.
+
+
+/*************************************************************************
+ remove_name()
+ *************************************************************************/
+
+this function is responsible for removing a specific NetBIOS entry
+from a subnet list's records. only if the pointer to the entry is
+in the list will the name be removed.
+
+
+/*************************************************************************
+ add_name()
+ *************************************************************************/
+
+this function is responsible for adding a NetBIOS entry into a
+subnet list's records.
+
+
+/*************************************************************************
+ ms_browser_name()
+ *************************************************************************/
+
+this function returns True if the NetBIOS name passed to it is
+^1^2__MSBROWSE__^2^1
+
+
+/*************************************************************************
+ name_equal()
+ *************************************************************************/
+
+this function returns True if the two NetBIOS names passed to it
+match in name, type and scope: the NetBIOS names are equal.
+
+
diff --git a/source/namedbresp.c b/source/namedbresp.c
new file mode 100644
index 00000000000..e9fe39c3d73
--- /dev/null
+++ b/source/namedbresp.c
@@ -0,0 +1,167 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios library routines
+ Copyright (C) Andrew Tridgell 1994-1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Module name: namedbresp.c
+
+*/
+
+#include "includes.h"
+
+extern int ClientNMB;
+
+extern struct subnet_record *subnetlist;
+
+extern int DEBUGLEVEL;
+
+extern pstring scope;
+extern pstring myname;
+extern struct in_addr ipzero;
+
+int num_response_packets = 0;
+
+/***************************************************************************
+ add an expected response record into the list
+ **************************************************************************/
+void add_response_record(struct subnet_record *d,
+ struct response_record *n)
+{
+ struct response_record *n2;
+
+ if (!d) return;
+
+ num_response_packets++; /* count of total number of packets still around */
+
+ DEBUG(4,("adding response record id:%d num_records:%d\n",
+ n->response_id, num_response_packets));
+
+ if (!d->responselist)
+ {
+ d->responselist = n;
+ n->prev = NULL;
+ n->next = NULL;
+ return;
+ }
+
+ for (n2 = d->responselist; n2->next; n2 = n2->next) ;
+
+ n2->next = n;
+ n->next = NULL;
+ n->prev = n2;
+}
+
+
+/***************************************************************************
+ remove an expected response record from the list
+ **************************************************************************/
+void remove_response_record(struct subnet_record *d,
+ struct response_record *n)
+{
+ if (!d) return;
+
+ if (n->prev) n->prev->next = n->next;
+ if (n->next) n->next->prev = n->prev;
+
+ if (d->responselist == n) d->responselist = n->next;
+
+ free(n);
+
+ num_response_packets--; /* count of total number of packets still around */
+}
+
+
+/****************************************************************************
+ create a name query response record
+ **************************************************************************/
+struct response_record *make_response_queue_record(enum state_type state,
+ int id,uint16 fd,
+ int quest_type, char *name,int type, int nb_flags, time_t ttl,
+ int server_type, char *my_name, char *my_comment,
+ BOOL bcast,BOOL recurse,
+ struct in_addr send_ip, struct in_addr reply_to_ip,
+ int reply_id)
+{
+ struct response_record *n;
+
+ if (!name || !name[0]) return NULL;
+
+ if (!(n = (struct response_record *)malloc(sizeof(*n))))
+ return(NULL);
+
+ bzero((char *)n, sizeof(*n));
+
+ n->response_id = id;
+ n->state = state;
+ n->fd = fd;
+ n->quest_type = quest_type;
+ make_nmb_name(&n->name, name, type, scope);
+ n->nb_flags = nb_flags;
+ n->ttl = ttl;
+ n->server_type = server_type;
+ n->bcast = bcast;
+ n->recurse = recurse;
+ n->send_ip = send_ip;
+ n->reply_to_ip = reply_to_ip;
+ n->reply_id = reply_id;
+ if(my_name)
+ StrnCpy(n->my_name, my_name, sizeof(n->my_name)-1);
+ else
+ *n->my_name = 0;
+ if(my_comment)
+ StrnCpy(n->my_comment, my_comment, sizeof(n->my_comment)-1);
+ else
+ *n->my_comment = 0;
+ n->repeat_interval = 1; /* XXXX should be in ms */
+ n->repeat_count = 3; /* 3 retries */
+ n->repeat_time = time(NULL) + n->repeat_interval; /* initial retry time */
+
+ n->num_msgs = 0;
+
+ return n;
+}
+
+
+/****************************************************************************
+ find a response in a subnet's name query response list.
+ **************************************************************************/
+struct response_record *find_response_record(struct subnet_record **d,
+ uint16 id)
+{
+ struct response_record *n;
+
+ if (!d) return NULL;
+
+ for ((*d) = FIRST_SUBNET; (*d); (*d) = NEXT_SUBNET_INCLUDING_WINS(*d))
+ {
+ for (n = (*d)->responselist; n; n = n->next)
+ {
+ if (n->response_id == id) {
+ DEBUG(4, ("found response record on %s: %d\n",
+ inet_ntoa((*d)->bcast_ip), id));
+ return n;
+ }
+ }
+ }
+
+ *d = NULL;
+
+ return NULL;
+}
+
+
diff --git a/source/namedbresp.doc b/source/namedbresp.doc
new file mode 100644
index 00000000000..a54c0702758
--- /dev/null
+++ b/source/namedbresp.doc
@@ -0,0 +1,100 @@
+/*
+ Unix SMB/Netbios documentation.
+ Version 0.1
+ Copyright (C) Luke Leighton Andrew Tridgell 1996
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Document name: namedbresp.doc
+
+ Revision History:
+
+ 0.0 - 02jul96 : lkcl@pires.co.uk
+ created
+
+ 0.1 - 22jul96 Andrew.Tridgell@anu.edu.au
+ tridge's comments on first revision
+*/
+
+module namedbresp deals with the maintenance of the list of expected
+responses - creating, finding and removal.
+
+module nameresp deals with the initial transmission, re-transmission
+and time-out of netbios response records.
+
+
+/*************************************************************************
+ find_response_record()
+ *************************************************************************/
+
+this function is responsible for matching the unique response transaction
+id with an expected response record. as a side-effect of this search,
+it will find the subnet (or the WINS pseudo-subnet) that samba expected
+the response to come from.
+
+
+/*************************************************************************
+ make_response_queue_record()
+ *************************************************************************/
+
+this function is responsible for creating a response record, which will
+be queued awaiting a response.
+
+the number of retries is set to 3, and the retry period set to 1 second.
+if no response is received, then the packet is re-transmitted, which is
+why so much information is stored in the response record.
+
+the number of expected responses queued is kept, so listen_for_packets()
+knows it must time-out after 1 second if one or more responses are
+expected.
+
+
+/*************************************************************************
+ remove_response_record()
+ *************************************************************************/
+
+this function is responsible for removing a response record from the
+expected response queue. the number of expected responses is decreased.
+
+
+/*************************************************************************
+ add_response_record()
+ *************************************************************************/
+
+this function is responsible for adding the response record created by
+make_response_queue_record() into the appropriate response record queue.
+
+
+-----------------
+NOTE FROM TRIDGE:
+
+namedbresp.c is interesting because it implements a novel way of
+getting most of the advantages of a multi-threaded nmbd daemon without
+the portability problems.
+
+The NBT specs (rfc1001/1002) talk about the 16 bit IDs in the packets
+as being used to ensure that packets are unique, and to stop packets
+from being confused. It suggests incrementing the ID by 1 each time.
+
+Instead Luke uses these IDs to identify individual threads of control
+in nmbd. So when nmbd sends out a NBT packet as part of some complex
+processing, it adds to a linked list the information required to
+continue the processing when the reply comes in (or it times
+out). When a reply arrives this list can be searched to find the
+matching query and the next step in the processing can be carried out.
+
+This is really good stuff, and allows for much more complex behaviour
+than was possible with the old nmbd.
+----------------
diff --git a/source/namedbserver.c b/source/namedbserver.c
new file mode 100644
index 00000000000..7440b42494a
--- /dev/null
+++ b/source/namedbserver.c
@@ -0,0 +1,211 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+ 04 jul 96: lkcl@pires.co.uk
+ created module namedbserver containing server database functions
+
+*/
+
+#include "includes.h"
+#include "smb.h"
+
+extern int ClientNMB;
+
+extern int DEBUGLEVEL;
+
+extern pstring myname;
+extern fstring myworkgroup;
+
+/* this is our domain/workgroup/server database */
+extern struct subnet_record *subnetlist;
+
+extern BOOL updatedlists;
+
+
+/*******************************************************************
+ expire old servers in the serverlist
+ time of -1 indicates everybody dies except those with time of 0
+ remove_all_servers indicates everybody dies.
+ ******************************************************************/
+void remove_old_servers(struct work_record *work, time_t t,
+ BOOL remove_all)
+{
+ struct server_record *s;
+ struct server_record *nexts;
+
+ /* expire old entries in the serverlist */
+ for (s = work->serverlist; s; s = nexts)
+ {
+ if (remove_all || (s->death_time && (t == -1 || s->death_time < t)))
+ {
+ DEBUG(3,("Removing dead server %s\n",s->serv.name));
+ updatedlists = True;
+ nexts = s->next;
+
+ if (s->prev) s->prev->next = s->next;
+ if (s->next) s->next->prev = s->prev;
+
+ if (work->serverlist == s)
+ work->serverlist = s->next;
+
+ free(s);
+ }
+ else
+ {
+ nexts = s->next;
+ }
+ }
+}
+
+
+/***************************************************************************
+ add a server into the list
+ **************************************************************************/
+static void add_server(struct work_record *work,struct server_record *s)
+{
+ struct server_record *s2;
+
+ if (!work->serverlist) {
+ work->serverlist = s;
+ s->prev = NULL;
+ s->next = NULL;
+ return;
+ }
+
+ for (s2 = work->serverlist; s2->next; s2 = s2->next) ;
+
+ s2->next = s;
+ s->next = NULL;
+ s->prev = s2;
+}
+
+
+/****************************************************************************
+ find a server in a server list.
+ **************************************************************************/
+struct server_record *find_server(struct work_record *work, char *name)
+{
+ struct server_record *ret;
+
+ if (!work) return NULL;
+
+ for (ret = work->serverlist; ret; ret = ret->next)
+ {
+ if (strequal(ret->serv.name,name))
+ {
+ return ret;
+ }
+ }
+ return NULL;
+}
+
+
+/****************************************************************************
+ add a server entry
+ ****************************************************************************/
+struct server_record *add_server_entry(struct subnet_record *d,
+ struct work_record *work,
+ char *name,int servertype,
+ int ttl,char *comment,
+ BOOL replace)
+{
+ BOOL newentry=False;
+ struct server_record *s;
+
+ if (name[0] == '*')
+ {
+ return (NULL);
+ }
+
+ s = find_server(work, name);
+
+ if (s && !replace)
+ {
+ DEBUG(4,("Not replacing %s\n",name));
+ return(s);
+ }
+
+ if (!s || s->serv.type != servertype || !strequal(s->serv.comment, comment))
+ updatedlists=True;
+
+ if (!s)
+ {
+ newentry = True;
+ s = (struct server_record *)malloc(sizeof(*s));
+
+ if (!s) return(NULL);
+
+ bzero((char *)s,sizeof(*s));
+ }
+
+
+ /* update the entry */
+ StrnCpy(s->serv.name,name,sizeof(s->serv.name)-1);
+ StrnCpy(s->serv.comment,comment,sizeof(s->serv.comment)-1);
+ strupper(s->serv.name);
+ s->serv.type = servertype;
+ s->death_time = servertype ? (ttl?time(NULL)+ttl*3:0) : (time(NULL)-1);
+
+ /* for a domain entry, the comment field refers to the server name */
+
+ if (s->serv.type & SV_TYPE_DOMAIN_ENUM) strupper(s->serv.comment);
+
+ if (newentry)
+ {
+ add_server(work, s);
+
+ DEBUG(3,("Added "));
+ }
+ else
+ {
+ DEBUG(3,("Updated "));
+ }
+
+ DEBUG(3,("server entry %s of type %x (%s) to %s %s\n",
+ name,servertype,comment,
+ work->work_group,inet_ntoa(d->bcast_ip)));
+
+ return(s);
+}
+
+
+/*******************************************************************
+ expire old servers in the serverlist
+ ******************************************************************/
+void expire_servers(time_t t)
+{
+ struct subnet_record *d;
+
+ for (d = FIRST_SUBNET; d ; d = NEXT_SUBNET_INCLUDING_WINS(d))
+ {
+ struct work_record *work;
+
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ remove_old_servers(work, t, False);
+ }
+ }
+}
+
diff --git a/source/namedbsubnet.c b/source/namedbsubnet.c
new file mode 100644
index 00000000000..27c1a0470e3
--- /dev/null
+++ b/source/namedbsubnet.c
@@ -0,0 +1,402 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+ 04 jul 96: lkcl@pires.co.uk
+ created module namedbsubnet containing subnet database functions
+
+*/
+
+#include "includes.h"
+#include "smb.h"
+
+extern int ClientNMB;
+extern int ClientDGRAM;
+extern int global_nmb_port;
+
+extern int DEBUGLEVEL;
+
+extern struct in_addr wins_ip;
+extern struct in_addr ipzero;
+
+extern pstring myname;
+extern fstring myworkgroup;
+extern char **my_netbios_names;
+
+BOOL updatedlists = True;
+int updatecount = 0;
+
+/* local interfaces structure */
+extern struct interface *local_interfaces;
+
+/* this is our domain/workgroup/server database */
+struct subnet_record *subnetlist = NULL;
+
+/* WINS subnet - keep this separate so enumeration code doesn't
+ run onto it by mistake. */
+struct subnet_record *wins_client_subnet = NULL;
+
+extern uint16 nb_type; /* samba's NetBIOS name type */
+
+/****************************************************************************
+ add a domain into the list
+ **************************************************************************/
+static void add_subnet(struct subnet_record *d)
+{
+ struct subnet_record *d2;
+
+ if (!subnetlist)
+ {
+ subnetlist = d;
+ d->prev = NULL;
+ d->next = NULL;
+ return;
+ }
+
+ for (d2 = subnetlist; d2->next; d2 = d2->next);
+
+ d2->next = d;
+ d->next = NULL;
+ d->prev = d2;
+}
+
+
+/****************************************************************************
+ find a subnet in the subnetlist that a given IP address could
+ match - not including WINS. Returns NULL if no match.
+ **************************************************************************/
+struct subnet_record *find_subnet(struct in_addr ip)
+{
+ struct subnet_record *d = NULL;
+
+ /* search through subnet list for broadcast/netmask that matches
+ the source ip address. */
+
+ for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
+ {
+ if (same_net(ip, d->bcast_ip, d->mask_ip))
+ break;
+ }
+
+ return d;
+}
+
+/****************************************************************************
+ find a subnet in the subnetlist - if the subnet is not found
+ then return the WINS client subnet.
+ **************************************************************************/
+struct subnet_record *find_subnet_all(struct in_addr ip)
+{
+ struct subnet_record *d = find_subnet(ip);
+ if(!d)
+ return wins_client_subnet;
+ return d;
+}
+
+/****************************************************************************
+ create a subnet entry
+ ****************************************************************************/
+static struct subnet_record *make_subnet(struct in_addr myip, struct in_addr bcast_ip,
+ struct in_addr mask_ip, BOOL add)
+{
+ struct subnet_record *d = NULL;
+ int nmb_sock, dgram_sock;
+
+ /* Check if we are creating the WINS subnet - if so don't create
+ sockets, use the ClientNMB and ClientDGRAM sockets instead.
+ */
+
+ if(ip_equal(bcast_ip, wins_ip))
+ {
+ nmb_sock = -1;
+ dgram_sock = -1;
+ }
+ else
+ {
+ /*
+ * Attempt to open the sockets on port 137/138 for this interface
+ * and bind them.
+ * Fail the subnet creation if this fails.
+ */
+
+ if((nmb_sock = open_socket_in(SOCK_DGRAM, global_nmb_port,0, myip.s_addr)) == -1)
+ {
+ DEBUG(0,("make_subnet: Failed to open nmb socket on interface %s \
+for port %d. Error was %s\n", inet_ntoa(myip), global_nmb_port, strerror(errno)));
+ return NULL;
+ }
+
+ if((dgram_sock = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3, myip.s_addr)) == -1)
+ {
+ DEBUG(0,("make_subnet: Failed to open dgram socket on interface %s \
+for port %d. Error was %s\n", inet_ntoa(myip), DGRAM_PORT, strerror(errno)));
+ return NULL;
+ }
+
+ /* Make sure we can broadcast from these sockets. */
+ set_socket_options(nmb_sock,"SO_BROADCAST");
+ set_socket_options(dgram_sock,"SO_BROADCAST");
+
+ }
+
+ d = (struct subnet_record *)malloc(sizeof(*d));
+
+ if (!d)
+ {
+ DEBUG(0,("make_subnet: malloc fail !\n"));
+ close(nmb_sock);
+ close(dgram_sock);
+ return(NULL);
+ }
+
+ bzero((char *)d,sizeof(*d));
+
+ DEBUG(4, ("making subnet %s ", inet_ntoa(bcast_ip)));
+ DEBUG(4, ("%s\n", inet_ntoa(mask_ip)));
+
+ d->bcast_ip = bcast_ip;
+ d->mask_ip = mask_ip;
+ d->myip = myip;
+ d->nmb_sock = nmb_sock;
+ d->dgram_sock = dgram_sock;
+ d->workgrouplist = NULL;
+
+ if(add)
+ add_subnet(d);
+
+ return d;
+}
+
+/****************************************************************************
+ add a domain entry. creates a workgroup, if necessary, and adds the domain
+ to the named a workgroup.
+ ****************************************************************************/
+static struct subnet_record *add_subnet_entry(struct in_addr myip,
+ struct in_addr bcast_ip,
+ struct in_addr mask_ip, char *name,
+ BOOL create_subnets, BOOL add)
+{
+ struct subnet_record *d = NULL;
+
+ if (zero_ip(bcast_ip))
+ bcast_ip = *iface_bcast(bcast_ip);
+
+ /* Note that we should also add into the WINS subnet as add_subnet_entry
+ should be called to add NetBIOS names and server entries on all
+ interfaces, including the WINS interface
+ */
+
+ if(create_subnets == True)
+ {
+ /* Create new subnets. */
+ if((d = make_subnet(myip, bcast_ip, mask_ip, add)) == NULL)
+ {
+ DEBUG(0,("add_subnet_entry: Unable to create subnet %s\n",
+ inet_ntoa(bcast_ip) ));
+ return NULL;
+ }
+ return d;
+ }
+ if(ip_equal(bcast_ip, wins_ip))
+ return wins_client_subnet;
+ return find_subnet(bcast_ip);
+}
+
+/****************************************************************************
+ Add a workgroup into a subnet, and if it's our primary workgroup,
+ add the required names to it.
+**************************************************************************/
+
+void add_workgroup_to_subnet( struct subnet_record *d, char *group)
+{
+ struct work_record *w = NULL;
+
+ DEBUG(5,("add_workgroup_to_subnet: Adding workgroup %s to subnet %s\n",
+ group, inet_ntoa(d->bcast_ip)));
+
+ /* This next statement creates the workgroup struct if it doesn't
+ already exist.
+ */
+ if((w = find_workgroupstruct(d, group, True)) == NULL)
+ {
+ DEBUG(0,("add_workgroup_to_subnet: Unable to add workgroup %s to subnet %s\n",
+ group, inet_ntoa(d->bcast_ip) ));
+ return;
+ }
+
+ /* add WORKGROUP(00) entries into name database
+ or register with WINS server, if it's our workgroup.
+ */
+ if (strequal(myworkgroup, group))
+ {
+ int n;
+
+ add_my_name_entry(d,group,0x0 ,nb_type|NB_ACTIVE|NB_GROUP);
+
+ /* Only register the WORKGROUP<0x1e> name if we could be a local master
+ browser. */
+ if(lp_local_master())
+ add_my_name_entry(d,group,0x1e,nb_type|NB_ACTIVE|NB_GROUP);
+
+ /* Add all our server names to the workgroup list. We remove any
+ browser or logon server flags from all but the primary name.
+ */
+ for( n = 0; my_netbios_names[n]; n++)
+ {
+ char *name = my_netbios_names[n];
+ int stype = w->ServerType;
+
+ if(!strequal(myname, name))
+ stype &= ~(SV_TYPE_MASTER_BROWSER|SV_TYPE_POTENTIAL_BROWSER|
+ SV_TYPE_DOMAIN_MASTER|SV_TYPE_DOMAIN_MEMBER);
+
+ add_server_entry(d,w,name,stype|SV_TYPE_LOCAL_LIST_ONLY,0,
+ lp_serverstring(),True);
+ DEBUG(3,("add_workgroup_to_subnet: Added server name entry %s \
+to subnet %s\n", name, inet_ntoa(d->bcast_ip)));
+ }
+ }
+}
+
+/****************************************************************************
+ create subnet / workgroup / server entries
+
+ - add or create the subnet lists
+ - add or create the workgroup entries in each subnet entry
+ - register appropriate NetBIOS names for the workgroup entries
+
+**************************************************************************/
+void add_my_subnets(char *group)
+{
+ static BOOL create_subnets = True;
+ struct subnet_record *d = NULL;
+ struct interface *i = NULL;
+
+ if (*group == '*') return;
+
+ /* Create subnets from all the local interfaces and thread them onto
+ the linked list.
+ */
+ for (i = local_interfaces; i; i = i->next)
+ {
+ add_subnet_entry(i->ip, i->bcast,i->nmask,group, create_subnets, True);
+ }
+
+ /* If we are using WINS, then we must add the workgroup to the WINS
+ subnet. This is used as a place to keep collated server lists.
+ */
+
+ /* Create the WINS subnet if we are using WINS - but don't thread it
+ onto the linked subnet list.
+ */
+ if (lp_wins_support() || lp_wins_server())
+ {
+ struct in_addr wins_nmask = ipzero;
+ wins_client_subnet = add_subnet_entry(ipzero, wins_ip, wins_nmask, group, create_subnets, False);
+ }
+
+ /* Ensure we only create the subnets once. */
+ create_subnets = False;
+
+ /* Now we have created all the subnets - we can add the names
+ that make us a client member in the workgroup.
+ */
+ for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
+ add_workgroup_to_subnet(d, group);
+}
+
+/*******************************************************************
+ write out browse.dat
+ ******************************************************************/
+void write_browse_list(time_t t)
+{
+ struct subnet_record *d;
+ pstring fname,fnamenew;
+ FILE *f;
+
+ static time_t lasttime = 0;
+
+ if (!lasttime) lasttime = t;
+ if (!updatedlists || t - lasttime < 5) return;
+
+ lasttime = t;
+ updatedlists = False;
+ updatecount++;
+
+ dump_names();
+ dump_workgroups();
+
+ pstrcpy(fname,lp_lockdir());
+ trim_string(fname,NULL,"/");
+ strcat(fname,"/");
+ strcat(fname,SERVER_LIST);
+ pstrcpy(fnamenew,fname);
+ strcat(fnamenew,".");
+
+ f = fopen(fnamenew,"w");
+
+ if (!f)
+ {
+ DEBUG(4,("Can't open %s - %s\n",fnamenew,strerror(errno)));
+ return;
+ }
+
+ for (d = FIRST_SUBNET; d ; d = NEXT_SUBNET_INCLUDING_WINS(d))
+ {
+ struct work_record *work;
+ for (work = d->workgrouplist; work ; work = work->next)
+ {
+ struct server_record *s;
+ for (s = work->serverlist; s ; s = s->next)
+ {
+ fstring tmp;
+
+ /* don't list domains I don't have a master for */
+ if ((s->serv.type & SV_TYPE_DOMAIN_ENUM) && !s->serv.comment[0])
+ {
+ continue;
+ }
+
+ /* output server details, plus what workgroup/domain
+ they're in. without the domain information, the
+ combined list of all servers in all workgroups gets
+ sent to anyone asking about any workgroup! */
+
+ sprintf(tmp, "\"%s\"", s->serv.name);
+ fprintf(f, "%-25s ", tmp);
+ fprintf(f, "%08x ", s->serv.type);
+ sprintf(tmp, "\"%s\" ", s->serv.comment);
+ fprintf(f, "%-30s", tmp);
+ fprintf(f, "\"%s\"\n", work->work_group);
+ }
+ }
+ }
+
+ fclose(f);
+ unlink(fname);
+ chmod(fnamenew,0644);
+ rename(fnamenew,fname);
+ DEBUG(3,("Wrote browse list %s\n",fname));
+}
+
diff --git a/source/namedbwork.c b/source/namedbwork.c
new file mode 100644
index 00000000000..a6260aab467
--- /dev/null
+++ b/source/namedbwork.c
@@ -0,0 +1,245 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+ 04 jul 96: lkcl@pires.co.uk
+ created module namedbwork containing workgroup database functions
+
+*/
+
+#include "includes.h"
+#include "smb.h"
+
+extern int ClientNMB;
+
+extern int DEBUGLEVEL;
+
+/* this is our domain/workgroup/server database */
+extern struct subnet_record *subnetlist;
+
+extern struct in_addr wins_ip;
+
+extern fstring myworkgroup;
+
+int workgroup_count = 0; /* unique index key: one for each workgroup */
+
+
+
+/****************************************************************************
+ add a workgroup into the domain list
+ **************************************************************************/
+static void add_workgroup(struct work_record *work, struct subnet_record *d)
+{
+ struct work_record *w2;
+
+ if (!work || !d) return;
+
+ if (!d->workgrouplist)
+ {
+ d->workgrouplist = work;
+ work->prev = NULL;
+ work->next = NULL;
+ return;
+ }
+
+ for (w2 = d->workgrouplist; w2->next; w2 = w2->next);
+
+ w2->next = work;
+ work->next = NULL;
+ work->prev = w2;
+}
+
+
+/****************************************************************************
+ create a blank workgroup
+ **************************************************************************/
+static struct work_record *make_workgroup(char *name)
+{
+ struct work_record *work;
+ struct subnet_record *d;
+ int t = -1;
+
+ if (!name || !name[0]) return NULL;
+
+ work = (struct work_record *)malloc(sizeof(*work));
+ if (!work) return(NULL);
+ bzero((char *)work, sizeof(*work));
+
+ StrnCpy(work->work_group,name,sizeof(work->work_group)-1);
+ work->serverlist = NULL;
+
+ work->ServerType = lp_default_server_announce() | (lp_local_master() ?
+ SV_TYPE_POTENTIAL_BROWSER : 0 );
+ work->RunningElection = False;
+ work->ElectionCount = 0;
+ work->announce_interval = 0;
+ work->needelection = False;
+ work->needannounce = True;
+ work->mst_state = MST_POTENTIAL;
+ work->dom_state = DOMAIN_NONE;
+ work->log_state = LOGON_NONE;
+
+ /* make sure all token representations of workgroups are unique */
+
+ for (d = FIRST_SUBNET; d && t == -1; d = NEXT_SUBNET_INCLUDING_WINS(d))
+ {
+ 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)|(ELECTION_VERSION<<8);
+ work->ElectionCriterion |= (lp_os_level() << 24);
+ if (lp_domain_master()) {
+ work->ElectionCriterion |= 0x80;
+ }
+
+ return work;
+}
+
+
+/*******************************************************************
+ remove workgroups
+ ******************************************************************/
+struct work_record *remove_workgroup(struct subnet_record *d,
+ struct work_record *work,
+ BOOL remove_all_servers)
+{
+ struct work_record *ret_work = NULL;
+
+ if (!d || !work) return NULL;
+
+ DEBUG(3,("Removing old workgroup %s\n", work->work_group));
+
+ ret_work = work->next;
+
+ remove_old_servers(work, -1, remove_all_servers);
+
+ if (!work->serverlist)
+ {
+ if (work->prev) work->prev->next = work->next;
+ if (work->next) work->next->prev = work->prev;
+
+ if (d->workgrouplist == work) d->workgrouplist = work->next;
+
+ free(work);
+ }
+
+ return ret_work;
+}
+
+
+/****************************************************************************
+ find a workgroup in the workgrouplist
+ only create it if the domain allows it, or the parameter 'add' insists
+ that it get created/added anyway. this allows us to force entries in
+ lmhosts file to be added.
+ **************************************************************************/
+struct work_record *find_workgroupstruct(struct subnet_record *d,
+ fstring name, BOOL add)
+{
+ struct work_record *ret, *work;
+
+ if (!d) return NULL;
+
+ DEBUG(4, ("workgroup search for %s: ", name));
+
+ for (ret = d->workgrouplist; ret; ret = ret->next) {
+ if (!strcmp(ret->work_group,name)) {
+ DEBUG(4, ("found\n"));
+ return(ret);
+ }
+ }
+
+ if (!add) {
+ DEBUG(4, ("not found\n"));
+ return NULL;
+ }
+
+ DEBUG(4,("not found: creating\n"));
+
+ if ((work = make_workgroup(name)))
+ {
+ if (!ip_equal(d->bcast_ip, wins_ip) &&
+ lp_preferred_master() && lp_local_master() &&
+ strequal(myworkgroup, name))
+ {
+ DEBUG(3, ("preferred master startup for %s\n", work->work_group));
+ work->needelection = True;
+ work->ElectionCriterion |= (1<<3);
+ }
+ add_workgroup(work, d);
+ return(work);
+ }
+ return NULL;
+}
+
+
+/****************************************************************************
+ dump a copy of the workgroup/domain database
+ **************************************************************************/
+void dump_workgroups(void)
+{
+ struct subnet_record *d;
+
+ for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
+ {
+ if (d->workgrouplist)
+ {
+ struct work_record *work;
+
+ DEBUG(4,("dump domain bcast=%15s: ", inet_ntoa(d->bcast_ip)));
+ DEBUG(4,(" netmask=%15s:\n", inet_ntoa(d->mask_ip)));
+
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ DEBUG(4,("\t%s(%d)\n", work->work_group, work->token));
+ if (work->serverlist)
+ {
+ struct server_record *s;
+ for (s = work->serverlist; s; s = s->next)
+ {
+ DEBUG(4,("\t\t%s %8x (%s)\n",
+ s->serv.name, s->serv.type, s->serv.comment));
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/source/nameelect.c b/source/nameelect.c
new file mode 100644
index 00000000000..391320e84f8
--- /dev/null
+++ b/source/nameelect.c
@@ -0,0 +1,856 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Module name: nameelect.c
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+ 04 jul 96: lkcl@pires.co.uk
+ added system to become a master browser by stages.
+
+
+*/
+
+#include "includes.h"
+
+extern int ClientNMB;
+extern int ClientDGRAM;
+
+extern int DEBUGLEVEL;
+extern pstring scope;
+
+extern pstring myname;
+extern fstring myworkgroup;
+extern struct in_addr ipzero;
+extern struct in_addr wins_ip;
+
+/* here are my election parameters */
+
+extern time_t StartupTime;
+
+extern struct subnet_record *subnetlist;
+
+extern uint16 nb_type; /* samba's NetBIOS name type */
+
+
+/*******************************************************************
+ occasionally check to see if the master browser is around
+ ******************************************************************/
+void check_master_browser(time_t t)
+{
+ static time_t lastrun=0;
+ struct subnet_record *d;
+
+ if (!lastrun) lastrun = t;
+ if (t < lastrun + CHECK_TIME_MST_BROWSE * 60) return;
+
+ lastrun = t;
+
+ dump_workgroups();
+
+ for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
+ {
+ struct work_record *work;
+
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ if (strequal(work->work_group, myworkgroup) && !AM_MASTER(work))
+ {
+ if (lp_local_master() && lp_preferred_master())
+ {
+ /* potential master browser - not a master browser. force
+ becoming a master browser, hence the log message.
+ */
+
+ DEBUG(2,("%s potential master for %s %s - force election\n",
+ timestring(), work->work_group,
+ inet_ntoa(d->bcast_ip)));
+
+ browser_gone(work->work_group, d->bcast_ip);
+ }
+ else
+ {
+ /* if we are not the browse master of a workgroup,
+ and we can't find a browser on the subnet, do
+ something about it.
+ */
+
+ queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_MST_CHK,
+ work->work_group,0x1d,0,0,0,NULL,NULL,
+ True,False,d->bcast_ip,d->bcast_ip, 0);
+ }
+ }
+ }
+ }
+}
+
+
+/*******************************************************************
+ what to do if a master browser DOESN't exist.
+
+ option 1: force an election, and participate in it
+ option 2: force an election, and let everyone else participate.
+
+ ******************************************************************/
+void browser_gone(char *work_name, struct in_addr ip)
+{
+ struct subnet_record *d = find_subnet(ip);
+ struct work_record *work = find_workgroupstruct(d, work_name, False);
+
+ /* i don't know about this workgroup, therefore i don't care */
+ if (!work || !d) return;
+
+ /* don't do election stuff on the WINS subnet */
+ if (ip_equal(d->bcast_ip,wins_ip))
+ return;
+
+ if (strequal(work->work_group, myworkgroup))
+ {
+
+ if (lp_local_master())
+ {
+ /* we have discovered that there is no local master
+ browser, and we are configured to initiate
+ an election under exactly such circumstances.
+ */
+ DEBUG(2,("Forcing election on %s %s\n",
+ work->work_group,inet_ntoa(d->bcast_ip)));
+
+ /* we can attempt to become master browser */
+ work->needelection = True;
+ }
+ else
+ {
+ /* we need to force an election, because we are configured
+ not to _become_ the local master, but we still _need_ one,
+ having detected that one doesn't exist.
+ */
+
+ /* local interfaces: force an election */
+ send_election(d, work->work_group, 0, 0, myname);
+
+ /* only removes workgroup completely on a local interface
+ persistent lmhosts entries on a local interface _will_ be removed).
+ */
+ remove_workgroup(d, work,True);
+ add_workgroup_to_subnet(d, work->work_group);
+ }
+ }
+}
+
+
+/****************************************************************************
+ send an election packet
+ **************************************************************************/
+void send_election(struct subnet_record *d, char *group,uint32 criterion,
+ int timeup,char *name)
+{
+ pstring outbuf;
+ char *p;
+
+ if (!d) return;
+
+ DEBUG(2,("Sending election to %s for workgroup %s\n",
+ inet_ntoa(d->bcast_ip),group));
+
+ bzero(outbuf,sizeof(outbuf));
+ p = outbuf;
+ CVAL(p,0) = ANN_Election; /* election */
+ p++;
+
+ CVAL(p,0) = (criterion == 0 && timeup == 0) ? 0 : ELECTION_VERSION;
+ SIVAL(p,1,criterion);
+ SIVAL(p,5,timeup*1000); /* ms - despite the spec */
+ p += 13;
+ pstrcpy(p,name);
+ strupper(p);
+ p = skip_string(p,1);
+
+ send_mailslot_reply(False,BROWSE_MAILSLOT,ClientDGRAM,
+ outbuf,PTR_DIFF(p,outbuf),
+ name,group,0,0x1e,d->bcast_ip,*iface_ip(d->bcast_ip));
+}
+
+
+/****************************************************************************
+ un-register a SELF name that got rejected.
+
+ if this name happens to be rejected when samba is in the process
+ of becoming a master browser (registering __MSBROWSE__, WORKGROUP(1d)
+ or WORKGROUP(1b)) then we must stop being a master browser. sad.
+
+ **************************************************************************/
+void name_unregister_work(struct subnet_record *d, char *name, int name_type)
+{
+ struct work_record *work;
+ int remove_type_local = 0;
+ int remove_type_domain = 0;
+ int remove_type_logon = 0;
+
+ remove_netbios_name(d,name,name_type,SELF);
+
+ if (!(work = find_workgroupstruct(d, name, False))) return;
+
+ /* work out what to unbecome, from the name type being removed */
+
+ if (ms_browser_name(name, name_type))
+ {
+ remove_type_local |= SV_TYPE_MASTER_BROWSER;
+ }
+ if (AM_MASTER(work) && strequal(name, myworkgroup) && name_type == 0x1d)
+ {
+ remove_type_local |= SV_TYPE_MASTER_BROWSER;
+ }
+ if (AM_DOMMST(work) && strequal(name, myworkgroup) && name_type == 0x1b)
+ {
+ remove_type_domain |= SV_TYPE_DOMAIN_MASTER;
+ }
+ if (AM_DOMMEM(work) && strequal(name, myworkgroup) && name_type == 0x1c)
+ {
+ remove_type_logon|= SV_TYPE_DOMAIN_MEMBER;
+ }
+
+ if (remove_type_local ) unbecome_local_master (d, work, remove_type_local );
+ if (remove_type_domain) unbecome_domain_master(d, work, remove_type_domain);
+ if (remove_type_logon ) unbecome_logon_server (d, work, remove_type_logon );
+}
+
+
+/****************************************************************************
+ registers a name.
+
+ if the name being added is a SELF name, we must additionally check
+ whether to proceed to the next stage in samba becoming a master browser.
+
+ **************************************************************************/
+void name_register_work(struct subnet_record *d, char *name, int name_type,
+ int nb_flags, time_t ttl, struct in_addr ip, BOOL bcast)
+{
+ enum name_source source = (ismyip(ip) || ip_equal(ip, ipzero)) ?
+ SELF : REGISTER;
+
+ if (source == SELF)
+ {
+ struct work_record *work = find_workgroupstruct(d,
+ myworkgroup, False);
+
+ struct subnet_record *add_subnet = (!bcast) ? wins_client_subnet : d;
+ add_netbios_entry(add_subnet,name,name_type,nb_flags,ttl,source,ip,True);
+
+ if (work)
+ {
+ int add_type_local = False;
+ int add_type_domain = False;
+ int add_type_logon = False;
+
+ DEBUG(4,("checking next stage: name_register_work %s\n", name));
+
+ /* work out what to become, from the name type being added */
+
+ if (ms_browser_name(name, name_type))
+ {
+ add_type_local = True;
+ }
+ if (strequal(name, myworkgroup) && name_type == 0x1d)
+ {
+ add_type_local = True;
+ }
+ if (strequal(name, myworkgroup) && name_type == 0x1b)
+ {
+ add_type_domain = True;
+ }
+ if (strequal(name, myworkgroup) && name_type == 0x1c)
+ {
+ add_type_logon = True;
+ }
+
+ if (add_type_local ) become_local_master (d, work);
+ if (add_type_domain) become_domain_master(d, work);
+ if (add_type_logon ) become_logon_server (d, work);
+ }
+ }
+}
+
+
+/*******************************************************************
+ become the local master browser.
+
+ this is done in stages. note that this could take a while,
+ particularly on a broadcast subnet, as we have to wait for
+ the implicit registration of each name to be accepted.
+
+ as each name is successfully registered, become_local_master() is
+ called again, in order to initiate the next stage. see
+ dead_netbios_entry() - deals with implicit name registration
+ and response_name_reg() - deals with explicit registration
+ with a WINS server.
+
+ stage 1: was MST_POTENTIAL - go to MST_POTENTIAL and register ^1^2__MSBROWSE__^2^1.
+ stage 2: was MST_BACK - go to MST_MSB and register WORKGROUP(0x1d)
+ stage 3: was MST_MSB - go to MST_BROWSER and stay there
+
+ XXXX note: this code still does not cope with the distinction
+ between different types of nodes, particularly between M and P
+ nodes. that comes later.
+
+ ******************************************************************/
+void become_local_master(struct subnet_record *d, struct work_record *work)
+{
+ /* domain type must be limited to domain enum + server type. it must
+ not have SV_TYPE_SERVER or anything else with SERVER in it, else
+ clients get confused and start thinking this entry is a server
+ not a workgroup
+ */
+ uint32 domain_type = SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT;
+
+ if (!work || !d)
+ return;
+
+ if (!lp_local_master())
+ {
+ DEBUG(0,("Samba not configured as a local master browser.\n"));
+ return;
+ }
+
+ DEBUG(2,("Becoming master for %s %s (currently at stage %d)\n",
+ work->work_group,inet_ntoa(d->bcast_ip),work->mst_state));
+
+ switch (work->mst_state)
+ {
+ case MST_POTENTIAL: /* while we were nothing but a server... */
+ {
+ DEBUG(3,("go to first stage: register ^1^2__MSBROWSE__^2^1\n"));
+ work->mst_state = MST_BACK; /* an election win was successful */
+
+ work->ElectionCriterion |= 0x5;
+
+ /* update our server status */
+ work->ServerType &= ~SV_TYPE_POTENTIAL_BROWSER;
+ add_server_entry(d,work,myname,work->ServerType|SV_TYPE_LOCAL_LIST_ONLY,
+ 0,lp_serverstring(),True);
+
+ /* add special browser name */
+ add_my_name_entry(d,MSBROWSE,0x01,nb_type|NB_ACTIVE|NB_GROUP);
+
+ /* DON'T do anything else after calling add_my_name_entry() */
+ break;
+ }
+
+ case MST_BACK: /* while nothing had happened except we won an election... */
+ {
+ DEBUG(3,("go to second stage: register as master browser\n"));
+ work->mst_state = MST_MSB; /* registering MSBROWSE was successful */
+
+ /* add server entry on successful registration of MSBROWSE */
+ add_server_entry(d,work,work->work_group,domain_type|SV_TYPE_LOCAL_LIST_ONLY,
+ 0,myname,True);
+
+ /* add master name */
+ add_my_name_entry(d,work->work_group,0x1d,nb_type|NB_ACTIVE);
+
+ /* DON'T do anything else after calling add_my_name_entry() */
+ break;
+ }
+
+ case MST_MSB: /* while we were still only registered MSBROWSE state... */
+ {
+ int i = 0;
+ struct server_record *sl;
+
+ DEBUG(3,("2nd stage complete: registered as master browser for workgroup %s \
+on subnet %s\n", work->work_group, inet_ntoa(d->bcast_ip)));
+ work->mst_state = MST_BROWSER; /* registering WORKGROUP(1d) succeeded */
+
+ /* update our server status */
+ work->ServerType |= SV_TYPE_MASTER_BROWSER;
+
+ DEBUG(3,("become_local_master: updating our server %s to type %x\n",
+ myname, work->ServerType));
+
+ add_server_entry(d,work,myname,work->ServerType|SV_TYPE_LOCAL_LIST_ONLY,
+ 0,lp_serverstring(),True);
+
+ /* Count the number of servers we have on our list. If it's
+ less than 10 (just a heuristic) request the servers
+ to announce themselves.
+ */
+ for( sl = work->serverlist; sl != NULL; sl = sl->next)
+ i++;
+
+ if (i < 10)
+ {
+ /* ask all servers on our local net to announce to us */
+ announce_request(work, d->bcast_ip);
+ }
+
+ /* Reset the announce master timer so that we do an announce as soon as possible
+ now we are a master. */
+ reset_announce_timer();
+
+ DEBUG(0,("Samba is now a local master browser for workgroup %s on subnet %s\n",
+ work->work_group, inet_ntoa(d->bcast_ip)));
+
+ break;
+ }
+
+ case MST_BROWSER:
+ {
+ /* don't have to do anything: just report success */
+ DEBUG(3,("3rd stage: become master browser!\n"));
+ break;
+ }
+ }
+}
+
+
+/*******************************************************************
+ become the domain master browser.
+
+ this is done in stages. note that this could take a while,
+ particularly on a broadcast subnet, as we have to wait for
+ the implicit registration of each name to be accepted.
+
+ as each name is successfully registered, become_domain_master() is
+ called again, in order to initiate the next stage. see
+ dead_netbios_entry() - deals with implicit name registration
+ and response_name_reg() - deals with explicit registration
+ with a WINS server.
+
+ stage 1: was DOMAIN_NONE - go to DOMAIN_MST
+
+ XXXX note: this code still does not cope with the distinction
+ between different types of nodes, particularly between M and P
+ nodes. that comes later.
+
+ ******************************************************************/
+void become_domain_master(struct subnet_record *d, struct work_record *work)
+{
+ /* domain type must be limited to domain enum + server type. it must
+ not have SV_TYPE_SERVER or anything else with SERVER in it, else
+ clients get confused and start thinking this entry is a server
+ not a workgroup
+ */
+
+ if (!work || !d) return;
+
+ if (!lp_domain_master())
+ {
+ DEBUG(0,("Samba not configured as a domain master browser.\n"));
+ return;
+ }
+
+ DEBUG(2,("Becoming domain master for %s %s (currently at stage %d)\n",
+ work->work_group,inet_ntoa(d->bcast_ip),work->dom_state));
+
+ switch (work->dom_state)
+ {
+ case DOMAIN_NONE: /* while we were nothing but a server... */
+ {
+ DEBUG(3,("become_domain_master: go to first stage: register <1b> name\n"));
+ work->dom_state = DOMAIN_WAIT;
+
+ /* XXXX the 0x1b is domain master browser name */
+ add_my_name_entry(d, work->work_group,0x1b,nb_type|NB_ACTIVE);
+
+ /* DON'T do anything else after calling add_my_name_entry() */
+ break;
+ }
+
+ case DOMAIN_WAIT:
+ {
+ work->dom_state = DOMAIN_MST; /* ... become domain master */
+ DEBUG(3,("become_domain_master: first stage - register as domain member\n"));
+
+ /* update our server status */
+ work->ServerType |= SV_TYPE_NT|SV_TYPE_DOMAIN_MASTER;
+ add_server_entry(d,work,myname,work->ServerType|SV_TYPE_LOCAL_LIST_ONLY,
+ 0, lp_serverstring(),True);
+
+ DEBUG(0,("Samba is now a domain master browser for workgroup %s on subnet %s\n",
+ work->work_group, inet_ntoa(d->bcast_ip)));
+
+ if (d == wins_client_subnet)
+ {
+ /* ok! we successfully registered by unicast with the
+ WINS server. we now expect to become the domain
+ master on the local subnets. if this fails, it's
+ probably a 1.9.16p2 to 1.9.16p11 server's fault.
+
+ this is a configuration issue that should be addressed
+ by the network administrator - you shouldn't have
+ several machines configured as a domain master browser
+ for the same WINS scope (except if they are 1.9.17 or
+ greater, and you know what you're doing.
+
+ see DOMAIN.txt.
+
+ */
+ add_domain_master_bcast();
+ }
+ break;
+ }
+
+ case DOMAIN_MST:
+ {
+ /* don't have to do anything: just report success */
+ DEBUG(3,("domain second stage: there isn't one!\n"));
+ break;
+ }
+ }
+}
+
+
+/*******************************************************************
+ become a logon server.
+ ******************************************************************/
+void become_logon_server(struct subnet_record *d, struct work_record *work)
+{
+ if (!work || !d) return;
+
+ if (!lp_domain_logons())
+ {
+ DEBUG(0,("samba not configured as a logon master.\n"));
+ return;
+ }
+
+ DEBUG(2,("Becoming logon server for %s %s (currently at stage %d)\n",
+ work->work_group,inet_ntoa(d->bcast_ip),work->log_state));
+
+ switch (work->log_state)
+ {
+ case LOGON_NONE: /* while we were nothing but a server... */
+ {
+ DEBUG(3,("go to first stage: register <1c> name\n"));
+ work->log_state = LOGON_WAIT;
+
+ /* XXXX the 0x1c is apparently something to do with domain logons */
+ add_my_name_entry(d, myworkgroup,0x1c,nb_type|NB_ACTIVE|NB_GROUP);
+
+ /* DON'T do anything else after calling add_my_name_entry() */
+ break;
+ }
+
+ case LOGON_WAIT:
+ {
+ work->log_state = LOGON_SRV; /* ... become logon server */
+ DEBUG(3,("logon second stage: register \n"));
+
+ /* update our server status */
+ work->ServerType |= SV_TYPE_NT|SV_TYPE_DOMAIN_MEMBER;
+ add_server_entry(d,work,myname,work->ServerType|SV_TYPE_LOCAL_LIST_ONLY
+ ,0, lp_serverstring(),True);
+
+ /* DON'T do anything else after calling add_my_name_entry() */
+ break;
+ }
+
+ case LOGON_SRV:
+ {
+ DEBUG(3,("logon third stage: there isn't one!\n"));
+ break;
+ }
+ }
+}
+
+
+/*******************************************************************
+ unbecome the local master browser. initates removal of necessary netbios
+ names, and tells the world that we are no longer a master browser.
+
+ XXXX this _should_ be used to demote to a backup master browser, without
+ going straight to non-master browser. another time.
+
+ ******************************************************************/
+void unbecome_local_master(struct subnet_record *d, struct work_record *work,
+ int remove_type)
+{
+ int new_server_type = work->ServerType;
+
+ /* can only remove master types with this function */
+ remove_type &= SV_TYPE_MASTER_BROWSER;
+
+ new_server_type &= ~remove_type;
+
+ if (remove_type)
+ {
+ DEBUG(2,("Becoming local non-master for %s\n",work->work_group));
+
+ /* no longer a master browser of any sort */
+
+ work->ServerType |= SV_TYPE_POTENTIAL_BROWSER;
+ work->ElectionCriterion &= ~0x4;
+ work->mst_state = MST_POTENTIAL;
+
+ /* announce ourselves as no longer active as a master browser. */
+ announce_server(d, work, work->work_group, myname, 0, 0);
+ remove_name_entry(d,MSBROWSE ,0x01);
+ remove_name_entry(d,work->work_group,0x1d);
+ }
+}
+
+
+/*******************************************************************
+ unbecome the domain master browser. initates removal of necessary netbios
+ names, and tells the world that we are no longer a domain browser.
+ ******************************************************************/
+void unbecome_domain_master(struct subnet_record *d, struct work_record *work,
+ int remove_type)
+{
+ int new_server_type = work->ServerType;
+
+ DEBUG(2,("Becoming domain non-master for %s\n",work->work_group));
+
+ /* can only remove master or domain types with this function */
+ remove_type &= SV_TYPE_DOMAIN_MASTER;
+
+ new_server_type &= ~remove_type;
+
+ if (remove_type)
+ {
+ /* no longer a domain master browser of any sort */
+
+ work->dom_state = DOMAIN_NONE;
+
+ /* announce ourselves as no longer active as a master browser on
+ all our local subnets. */
+ for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
+ {
+ work = find_workgroupstruct(d, myworkgroup, False);
+
+ /* Remove the name entry without any NetBIOS traffic as that's
+ how it was registered. */
+ remove_name_entry(d,work->work_group,0x1b);
+ }
+
+ /* Unregister the 1b name from the WINS server. */
+ if(wins_client_subnet != NULL)
+ remove_name_entry(wins_client_subnet, myworkgroup, 0x1b);
+ }
+}
+
+
+/*******************************************************************
+ unbecome the logon server. initates removal of necessary netbios
+ names, and tells the world that we are no longer a logon server.
+ ******************************************************************/
+void unbecome_logon_server(struct subnet_record *d, struct work_record *work,
+ int remove_type)
+{
+ int new_server_type = work->ServerType;
+
+ DEBUG(2,("Becoming logon non-server for %s\n",work->work_group));
+
+ /* can only remove master or domain types with this function */
+ remove_type &= SV_TYPE_DOMAIN_MEMBER;
+
+ new_server_type &= ~remove_type;
+
+ if (remove_type)
+ {
+ /* no longer a master browser of any sort */
+
+ work->log_state = LOGON_NONE;
+
+ remove_name_entry(d,work->work_group,0x1c);
+ }
+}
+
+
+/*******************************************************************
+ run the election
+ ******************************************************************/
+void run_elections(time_t t)
+{
+ static time_t lastime = 0;
+
+ struct subnet_record *d;
+
+ /* send election packets once a second */
+ if (lastime && t-lastime <= 0) return;
+
+ lastime = t;
+
+ for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
+ {
+ struct work_record *work;
+
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ if (work->RunningElection)
+ {
+ send_election(d,work->work_group, work->ElectionCriterion,
+ t-StartupTime,myname);
+
+ if (work->ElectionCount++ >= 4)
+ {
+ /* I won! now what :-) */
+ DEBUG(2,(">>> Won election on %s %s <<<\n",
+ work->work_group,inet_ntoa(d->bcast_ip)));
+
+ work->RunningElection = False;
+ work->mst_state = MST_POTENTIAL;
+
+ become_local_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)
+{
+ int mytimeup = time(NULL) - StartupTime;
+ uint32 mycriterion = work->ElectionCriterion;
+
+ /* If local master is false then never win
+ in election broadcasts. */
+ if(!lp_local_master())
+ {
+ DEBUG(3,("win_election: Losing election as local master == False\n"));
+ return False;
+ }
+
+ DEBUG(4,("election comparison: %x:%x %x:%x %d:%d %s:%s\n",
+ version,ELECTION_VERSION,
+ criterion,mycriterion,
+ timeup,mytimeup,
+ name,myname));
+
+ if (version > ELECTION_VERSION) return(False);
+ if (version < ELECTION_VERSION) return(True);
+
+ if (criterion > mycriterion) return(False);
+ if (criterion < mycriterion) return(True);
+
+ if (timeup > mytimeup) return(False);
+ if (timeup < mytimeup) return(True);
+
+ if (strcasecmp(myname,name) > 0) return(False);
+
+ return(True);
+}
+
+
+/*******************************************************************
+ process a election packet
+
+ An election dynamically decides who will be the master.
+ ******************************************************************/
+void process_election(struct packet_struct *p,char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ struct in_addr ip = dgram->header.source_ip;
+ struct subnet_record *d = find_subnet(ip);
+ int version = CVAL(buf,0);
+ uint32 criterion = IVAL(buf,1);
+ int timeup = IVAL(buf,5)/1000;
+ char *name = buf+13;
+ struct work_record *work;
+
+ if (!d) return;
+
+ if (ip_equal(d->bcast_ip,wins_ip))
+ {
+ DEBUG(0,("Unexpected election request from %s %s on WINS net\n",
+ name, inet_ntoa(p->ip)));
+ return;
+ }
+
+ name[15] = 0;
+
+ DEBUG(3,("Election request from %s %s vers=%d criterion=%08x timeup=%d\n",
+ name,inet_ntoa(p->ip),version,criterion,timeup));
+
+ if (same_context(dgram)) return;
+
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ if (!strequal(work->work_group, myworkgroup))
+ continue;
+
+ if (win_election(work, version,criterion,timeup,name))
+ {
+ if (!work->RunningElection)
+ {
+ work->needelection = True;
+ work->ElectionCount=0;
+ work->mst_state = MST_POTENTIAL;
+ }
+ }
+ else
+ {
+ work->needelection = False;
+
+ if (work->RunningElection || AM_MASTER(work))
+ {
+ work->RunningElection = False;
+ DEBUG(3,(">>> Lost election on %s %s <<<\n",
+ work->work_group,inet_ntoa(d->bcast_ip)));
+ if (AM_MASTER(work))
+ {
+ unbecome_local_master(d, work, SV_TYPE_MASTER_BROWSER);
+ }
+ }
+ }
+ }
+}
+
+
+/****************************************************************************
+ checks whether a browser election is to be run on any workgroup
+
+ this function really ought to return the time between election
+ packets (which depends on whether samba intends to be a domain
+ master or a master browser) in milliseconds.
+
+ ***************************************************************************/
+BOOL check_elections(void)
+{
+ struct subnet_record *d;
+ BOOL run_any_election = False;
+
+ for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
+ {
+ struct work_record *work;
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ run_any_election |= work->RunningElection;
+
+ if (work->needelection && !work->RunningElection)
+ {
+ DEBUG(3,(">>> Starting election on %s %s <<<\n",
+ work->work_group,inet_ntoa(d->bcast_ip)));
+ work->ElectionCount = 0;
+ work->RunningElection = True;
+ work->needelection = False;
+ }
+ }
+ }
+ return run_any_election;
+}
+
diff --git a/source/nameelect.doc b/source/nameelect.doc
new file mode 100644
index 00000000000..df025e2069a
--- /dev/null
+++ b/source/nameelect.doc
@@ -0,0 +1,256 @@
+/*
+ Unix SMB/Netbios documentation.
+ Version 0.1
+ Copyright (C) Luke Leighton Andrew Tridgell 1996
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Document name: nameelect.doc
+
+ Revision History:
+
+ 0.0 - 02jul96 : lkcl@pires.co.uk
+ created
+
+ 0.1 - 22jul96 Andrew.Tridgell@anu.edu.au
+ tridge's comments on first revision
+*/
+
+the module nameelect.c deals with initiating, winning, losing
+browsing elections, and checking if browsers are still around,
+and the consequences of getting involved in all this.
+
+an election packet can be received at any time, which will initiate
+an election. samba can also detect that there is no longer a
+master browser and will initiate an election.
+
+there is one way to become a master browser, but there are two
+ways to un-become a master browser. if you lose an election, you
+must stop being a master browser. if you fail to register your
+unique special browser names (either on your local subnet or with
+the WINS server) then you must stop being a master browser.
+
+this is a double fail-safe mechanism to ensure that there is only
+one master browser per workgroup per subnet (and one domain master
+browser - per domain (workgroup) per wide area network).
+
+(a wide area network is created when one or more servers on a
+broadcast-isolated subnet point to the same WINS server).
+
+--------
+NOTE FROM TRIDGE:
+
+I'd say "domain master browser" not "WINS server" here. WINS doesn't
+have much to do with browsing, it is the WAN varient of name
+resolution. The name resolution and browsing functions of a netbios
+network are almost entirely separate. Both grew out of systems that
+could only be used on local networks.
+
+To adapt them to WANs, WINS was added for name resolution, and "domain
+master browsers" were added for browse lists. It would be perfectly
+possible to have a WINS server that doesn't even listen to UDP port
+138.
+--------
+
+/*************************************************************************
+ check_elections()
+ *************************************************************************/
+
+this function returns True if samba is in the process of running an
+election on any of its interfaces. a better version of this function
+should return the time-out period in between election packets, in
+milliseconds.
+
+
+/*************************************************************************
+ process_election()
+ *************************************************************************/
+
+this function is responsible for dealing with the receipt of an election
+browse MAILSLOT packet.
+
+if samba is running an election, it checks the criteria in the packet
+received using win_election() to see if it has lost the election or if
+it should join in the election.
+
+if it loses the election, then it becomes a non-master.
+
+
+/*************************************************************************
+ win_election()
+ *************************************************************************/
+
+this function returns True if samba has won an election. the criteria
+in order of precedence are:
+
+the election version; the election criteria; the time since samba was
+started; and as a last resort, a name comparison is used.
+
+
+/*************************************************************************
+ run_elections()
+ *************************************************************************/
+
+this function is responsible for sending out election packets if
+samba is running in an election. once the fourth packet is sent
+out, it is assumed that we have won, and samba initiates becoming
+a master browser.
+
+(it looks like samba sends out an extra packet just to be sure...)
+
+
+/*************************************************************************
+ become_nonmaster()
+ *************************************************************************/
+
+this function is responsible for down-grading samba's status from
+either domain master to master browser or nothing, or master browser
+to nothing, depending on its current status.
+
+samba can become a non-master in three ways: by losing an election -
+see process_election(); by having one of its special browser names
+de-registered - see name_unregister_work(); by receiving and
+processing a browser reset packet - see process_reset_browser().
+
+when samba stops being a domain master, it must release its unique
+0x1b name. when samba stops being a master browser, it must release
+its unique 0x1d name.
+
+becoming non-master is done on a per-subnet basis.
+
+
+/*************************************************************************
+ become_master()
+ *************************************************************************/
+
+this function is responsible for slowly turning samba into a
+local master browser or a domain master browser.
+
+
+this is done in stages. note that this could take a while,
+particularly on a broadcast subnet, as we have to wait for
+the implicit registration of each name to be accepted.
+
+as each name is successfully registered, become_master() is
+called again via name_register_work(), in order to initiate
+the next stage (see dead_netbios_entry() - deals with implicit
+name registration and response_name_reg() - deals with explicit
+registration with a WINS server).
+
+stage 1: was MST_NONE - go to MST_NONE and register ^1^2__MSBROWSE__^2^1.
+stage 2: was MST_WON - go to MST_MSB and register WORKGROUP(0x1d)
+stage 3: was MST_MSB - go to MST_BROWSER and register WORKGROUP(0x1b)
+stage 4: was MST_BROWSER - go to MST_DOMAIN (do not pass GO, do not...)
+
+note that this code still does not cope with the distinction
+between different types of nodes, particularly between M and P
+nodes (see rfc1001.txt). that will be developed later.
+
+
+/*************************************************************************
+ name_register_work()
+ *************************************************************************/
+
+this function is called when a NetBIOS name is successfully
+registered. it will add the registered name into samba's NetBIOS
+records.
+
+it has the additional responsibility that when samba is becoming
+a master browser, it must initiate the next stage in the progress
+towards becoming a master browser.
+
+implicit name registration is done through dead_netbios_entry()
+by time-out. explicit name registration is done through
+response_name_reg() with a WINS server.
+
+
+/*************************************************************************
+ name_unregister_work()
+ *************************************************************************/
+
+this function is called when there is an objection to a NetBIOS
+name being registered. this will always be done through a negative
+response to a name registration, whether it be by a host that
+already owns the unique name being registered on a subnet, or
+by a WINS server.
+
+the name being objected to must be removed from samba's records.
+
+it has the additional responsibility of checking whether samba is
+currently a master browser or not, and if so it should initiate
+becoming a non-master.
+
+
+
+/*************************************************************************
+ send_election()
+ *************************************************************************/
+
+this function is responsible for sending a browse mailslot
+datagram election packet (of type ANN_Election). it constructs
+the packet with all the relevant info needed to participate:
+election version; election criteria; time since startup and
+our name.
+
+this function can be used to ensure that initiate but lose an
+election by specifying a criteria and time up of zero. this
+is necessary if we are a master browser and we are about to
+go down (politely!) - see nmbd.c:sig_term().
+
+
+/*************************************************************************
+ browser_gone()
+ *************************************************************************/
+
+this function is responsible for dealing with the instance when
+the master browser we thought was present on a subnet is no longer
+responding.
+
+if it is samba's workgroup, and it's a local interface, samba
+detects that it can participate in an election on that interface
+and potentially become a master browser or domain master.
+
+if it's a local subnet and not one of samba's workgroups, then
+samba will force an election (which it is not obliged to do).
+remove_workgroup() will be expected to remove all references
+to this workgroup and the servers in it from the database.
+
+if it's a remote subnet and not one of samba's workgroups then
+no election is forced, and remove_workgroup() will be expected
+to remove all server entries from this workgroup _except_ those
+added from the lmhosts file. if there are entries added from
+the lmhosts file, then the workgroup entry will remain,
+otherwise it too will be removed.
+
+
+/*************************************************************************
+ check_master_browser()
+ *************************************************************************/
+
+this function is responsible for periodically checking whether
+master browsers that samba expects to be alive are alive. this
+is done every CHECK_TIME_MST_BROWSE minutes.
+
+for every workgroup record for which samba is not a master browser,
+on both local and remote interfaces, samba will initiate a
+broadcast query for a master browser on that subnet.
+
+(browser_gone() will be called to deal with the case where no
+response is received to the NAME_QUERY_MST_CHK initiated here.
+no action is required when a response _is_ received, however:
+see nameservresp.c:response_process() and dead_netbios_entry()
+for details)
+
+
diff --git a/source/namelogon.c b/source/namelogon.c
new file mode 100644
index 00000000000..d8e0fcfc768
--- /dev/null
+++ b/source/namelogon.c
@@ -0,0 +1,233 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+*/
+
+#include "includes.h"
+
+extern int ClientDGRAM;
+
+extern int DEBUGLEVEL;
+
+extern pstring myname;
+
+
+/****************************************************************************
+ process a domain logon packet
+
+ **************************************************************************/
+void process_logon_packet(struct packet_struct *p,char *buf,int len)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ pstring my_name;
+ fstring reply_name;
+ BOOL add_slashes = False;
+ pstring outbuf;
+ int code,reply_code;
+ char unknown_byte = 0;
+ uint16 request_count = 0;
+ uint16 token = 0;
+
+ uint32 ntversion;
+ uint16 lmnttoken;
+ uint16 lm20token;
+ uint32 allowableaccount; /* Control bits, i.e. 0x80 == workstation trust a/c */
+ uint32 domainsidsize;
+ uint16 requestcount;
+ char *domainsid;
+ char *uniuser; /* Unicode user name */
+ pstring ascuser;
+ char *mailslot;
+ char *unicomp; /* Unicode computer name */
+ struct smb_passwd *smb_pass; /* To check if machine account exists */
+
+ if (!lp_domain_logons())
+ {
+ DEBUG(3,("No domain logons\n"));
+ return;
+ }
+
+ strcpy(my_name, myname);
+ strupper(my_name);
+
+ code = SVAL(buf,0);
+ DEBUG(1,("namelogon from %s: %x\n", inet_ntoa(p->ip), code));
+
+ switch (code)
+ {
+ case 0:
+ {
+ char *q = buf + 2;
+ char *machine = q;
+ char *user = skip_string(machine,1);
+
+ mailslot = skip_string(user,1);
+ q = skip_string(mailslot,1);
+ unknown_byte = CVAL(q,0);
+ request_count = SVAL(q,1);
+ token = SVAL(q,3);
+
+ reply_code = 0x6;
+ strcpy(reply_name,my_name);
+ add_slashes = True;
+
+ DEBUG(3,("Domain login request from %s(%s) user=%s token=%x\n",
+ machine,inet_ntoa(p->ip),user,token));
+
+ q = outbuf;
+ SSVAL(q, 0, 6); q += 2;
+
+ strcpy(reply_name, "\\\\");
+ strcat(reply_name, my_name);
+ strcpy(q, reply_name); q = skip_string(q, 1); /* PDC name */
+
+ SSVAL(q, 0, token); q += 2;
+
+ dump_data(4, outbuf, PTR_DIFF(q, outbuf));
+
+ send_mailslot_reply(True, mailslot, ClientDGRAM,
+ outbuf,PTR_DIFF(q,outbuf),
+ my_name,&dgram->source_name.name[0],0x20,0,
+ p->ip, *iface_ip(p->ip));
+ break;
+ }
+
+ case QUERYFORPDC:
+ {
+ char *q = buf + 2;
+ char *machine = q;
+ mailslot = skip_string(machine,1);
+ unicomp = skip_string(mailslot,1);
+
+ q = align2(q, buf);
+
+ q = skip_unicode_string(unicomp,1);
+
+ ntversion = IVAL(q, 0); q += 4;
+ lmnttoken = SVAL(q, 0); q += 2;
+ lm20token = SVAL(q, 0); q += 2;
+
+ /* construct reply */
+
+ q = outbuf;
+ SSVAL(q, 0, QUERYFORPDC_R); q += 2;
+
+ strcpy(reply_name,my_name);
+ strcpy(q, reply_name); q = skip_string(q, 1); /* PDC name */
+
+ q = align2(q, buf);
+
+ PutUniCode(q, my_name); q = skip_unicode_string(q, 1); /* PDC name */
+ PutUniCode(q, lp_workgroup()); q = skip_unicode_string(q, 1); /* Domain name. */
+
+ SIVAL(q, 0, ntversion); q += 4;
+ SSVAL(q, 0, lmnttoken); q += 2;
+ SSVAL(q, 0, lm20token); q += 2;
+
+ DEBUG(3,("GETDC request from %s(%s), reporting %s domain %s 0x%x ntversion=%x lm_nt token=%x lm_20 token=%x\n",
+ machine,inet_ntoa(p->ip), reply_name, lp_workgroup(),
+ QUERYFORPDC_R, (uint32)ntversion, (uint32)lmnttoken,
+ (uint32)lm20token));
+
+ dump_data(4, outbuf, PTR_DIFF(q, outbuf));
+
+ send_mailslot_reply(True, mailslot,ClientDGRAM,
+ outbuf,PTR_DIFF(q,outbuf),
+ my_name,&dgram->source_name.name[0],0x20,0,
+ p->ip, *iface_ip(p->ip));
+ return;
+ }
+
+ case SAMLOGON:
+ {
+ char *q = buf + 2;
+
+ requestcount = SVAL(q, 0); q += 2;
+ unicomp = q;
+ uniuser = skip_unicode_string(unicomp,1);
+ mailslot = skip_unicode_string(uniuser,1);
+ q = skip_string(mailslot,1);
+ allowableaccount = IVAL(q, 0); q += 4;
+ domainsidsize = IVAL(q, 0); q += 4;
+ domainsid = q;
+ q += domainsidsize + 3;
+ ntversion = IVAL(q, 0); q += 4;
+ lmnttoken = SVAL(q, 0); q += 2;
+ lm20token = SVAL(q, 0); q += 2;
+ DEBUG(3,("SAMLOGON sidsize %d ntv %d\n", domainsidsize, ntversion));
+
+ /*
+ If MACHINE$ is in our password database then respond, else ignore.
+ Let's ignore the SID.
+ */
+ strcpy(ascuser,unistr(uniuser));
+ DEBUG(3,("SAMLOGON user %s\n", ascuser));
+ strcpy(reply_name,"\\\\"); /* Here it wants \\LOGONSERVER */
+ strcpy(reply_name+2,my_name); /* PAXX: Assuming we are logon svr */
+ smb_pass = get_smbpwnam(ascuser);
+
+ if(!smb_pass)
+ {
+ DEBUG(3,("SAMLOGON request from %s(%s) for %s, not in password file\n",
+ unistr(unicomp),inet_ntoa(p->ip), ascuser));
+ return;
+ }
+ else
+ {
+ DEBUG(3,("SAMLOGON request from %s(%s) for %s, returning logon svr %s domain %s code %x token=%x\n",
+ unistr(unicomp),inet_ntoa(p->ip), ascuser, reply_name, lp_workgroup(),
+ SAMLOGON_R ,lmnttoken));
+ }
+
+ /* construct reply */
+
+ q = outbuf;
+ SSVAL(q, 0, SAMLOGON_R); q += 2;
+
+ PutUniCode(q, reply_name); q = skip_unicode_string(q, 1);
+ unistrcpy(q, uniuser); q = skip_unicode_string(q, 1); /* User name (workstation trust account) */
+ PutUniCode(q, lp_workgroup()); q = skip_unicode_string(q, 1); /* Domain name. */
+
+ SIVAL(q, 0, ntversion); q += 4;
+ SSVAL(q, 0, lmnttoken); q += 2;
+ SSVAL(q, 0, lm20token); q += 2;
+
+ dump_data(4, outbuf, PTR_DIFF(q, outbuf));
+
+ send_mailslot_reply(True, mailslot,ClientDGRAM,
+ outbuf,PTR_DIFF(q,outbuf),
+ my_name,&dgram->source_name.name[0],0x20,0,
+ p->ip, *iface_ip(p->ip));
+ break;
+ }
+
+ default:
+ {
+ DEBUG(3,("Unknown domain request %d\n",code));
+ return;
+ }
+ }
+
+}
diff --git a/source/namelogon.doc b/source/namelogon.doc
new file mode 100644
index 00000000000..c4a97d0cf16
--- /dev/null
+++ b/source/namelogon.doc
@@ -0,0 +1,36 @@
+/*
+ Unix SMB/Netbios documentation.
+ Version 0.0
+ Copyright (C) Luke Leighton Andrew Tridgell 1996
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Document name: namelogon.doc
+
+ Revision History:
+
+ 0.0 - 02jul96 : lkcl@pires.co.uk
+ created
+*/
+
+this module deals with the first stage of domain logons. there is much
+more work to be done on this: it's all totally undocumented.
+
+
+/*************************************************************************
+ process_logon_packet()
+ *************************************************************************/
+
+a function that processes logon packets (the most helpful comment yet :-).
diff --git a/source/namepacket.c b/source/namepacket.c
new file mode 100644
index 00000000000..626e50b788a
--- /dev/null
+++ b/source/namepacket.c
@@ -0,0 +1,777 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+*/
+
+#include "includes.h"
+
+extern int ClientNMB;
+extern int ClientDGRAM;
+
+extern int DEBUGLEVEL;
+
+extern int num_response_packets;
+
+BOOL CanRecurse = True;
+extern pstring scope;
+extern struct in_addr wins_ip;
+extern struct in_addr loopback_ip;
+
+static uint16 name_trn_id=0;
+
+
+/***************************************************************************
+ updates the unique transaction identifier
+ **************************************************************************/
+void debug_browse_data(char *outbuf, int len)
+{
+ int i,j;
+ for (i = 0; i < len; i+= 16)
+ {
+ DEBUG(4, ("%3x char ", i));
+
+ for (j = 0; j < 16; j++)
+ {
+ unsigned char x = outbuf[i+j];
+ if (x < 32 || x > 127) x = '.';
+
+ if (i+j >= len) break;
+ DEBUG(4, ("%c", x));
+ }
+
+ DEBUG(4, (" hex ", i));
+
+ for (j = 0; j < 16; j++)
+ {
+ if (i+j >= len) break;
+ DEBUG(4, (" %02x", (unsigned char)outbuf[i+j]));
+ }
+
+ DEBUG(4, ("\n"));
+ }
+
+}
+
+
+/***************************************************************************
+ updates the unique transaction identifier
+ **************************************************************************/
+static void update_name_trn_id(void)
+{
+ if (!name_trn_id)
+ {
+ name_trn_id = (time(NULL)%(unsigned)0x7FFF) + (getpid()%(unsigned)100);
+ }
+ name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
+}
+
+
+/****************************************************************************
+ initiate a netbios packet
+ ****************************************************************************/
+void initiate_netbios_packet(uint16 *id,
+ int fd,int quest_type,char *name,int name_type,
+ int nb_flags,BOOL bcast,BOOL recurse,
+ struct in_addr to_ip)
+{
+ struct packet_struct p;
+ struct nmb_packet *nmb = &p.packet.nmb;
+ struct res_rec additional_rec;
+ char *packet_type = "unknown";
+ int opcode = -1;
+
+ if (!id) return;
+
+ if (quest_type == NMB_STATUS) { packet_type = "nmb_status"; opcode = 0; }
+ if (quest_type == NMB_QUERY ) { packet_type = "nmb_query"; opcode = 0; }
+ if (quest_type == NMB_REG ) { packet_type = "nmb_reg"; opcode = 5; }
+ if (quest_type == NMB_REG_REFRESH ) { packet_type = "nmb_reg_refresh"; opcode = 9; }
+ if (quest_type == NMB_REL ) { packet_type = "nmb_rel"; opcode = 6; }
+
+ DEBUG(4,("initiating netbios packet: %s %s(%x) (bcast=%s) %s\n",
+ packet_type, name, name_type, BOOLSTR(bcast), inet_ntoa(to_ip)));
+
+ if (opcode == -1) return;
+
+ bzero((char *)&p,sizeof(p));
+
+ if (*id == 0xffff) {
+ update_name_trn_id();
+ *id = name_trn_id; /* allow resending with same id */
+ }
+
+ nmb->header.name_trn_id = *id;
+ nmb->header.opcode = opcode;
+ nmb->header.response = False;
+
+ nmb->header.nm_flags.bcast = bcast;
+ nmb->header.nm_flags.recursion_available = False;
+ nmb->header.nm_flags.recursion_desired = recurse;
+ nmb->header.nm_flags.trunc = False;
+ nmb->header.nm_flags.authoritative = False;
+
+ nmb->header.rcode = 0;
+ nmb->header.qdcount = 1;
+ nmb->header.ancount = 0;
+ nmb->header.nscount = 0;
+ nmb->header.arcount = (quest_type==NMB_REG ||
+ quest_type==NMB_REL ||
+ quest_type==NMB_REG_REFRESH) ? 1 : 0;
+
+ make_nmb_name(&nmb->question.question_name,name,name_type,scope);
+
+ nmb->question.question_type = quest_type == NMB_STATUS ? 0x21 : 0x20;
+ nmb->question.question_class = 0x1;
+
+ if (quest_type == NMB_REG ||
+ quest_type == NMB_REG_REFRESH ||
+ 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 = 0x20;
+ nmb->additional->rr_class = 0x1;
+
+ if (quest_type == NMB_REG || quest_type == NMB_REG_REFRESH)
+ nmb->additional->ttl = lp_max_ttl();
+ else
+ nmb->additional->ttl = 0;
+
+ nmb->additional->rdlength = 6;
+ nmb->additional->rdata[0] = nb_flags;
+ putip(&nmb->additional->rdata[2],(char *)iface_ip(to_ip));
+ }
+
+ p.ip = to_ip;
+ p.port = NMB_PORT;
+ p.fd = fd;
+ p.timestamp = time(NULL);
+ p.packet_type = NMB_PACKET;
+ p.locked = False;
+
+ debug_nmb_packet(&p);
+
+ if (!send_packet(&p)) {
+ DEBUG(3,("send_packet to %s %d failed\n",inet_ntoa(p.ip),p.port));
+ *id = 0xffff;
+ }
+
+ return;
+}
+
+
+/****************************************************************************
+ reply to a netbios name packet. see rfc1002.txt
+ ****************************************************************************/
+void reply_netbios_packet(struct packet_struct *p1,int trn_id,
+ int rcode, int rcv_code, int opcode,
+ BOOL recursion_available,
+ BOOL recursion_desired,
+ 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;
+
+ switch (rcv_code)
+ {
+ case NMB_STATUS:
+ {
+ packet_type = "nmb_status";
+ break;
+ }
+ case NMB_QUERY:
+ {
+ packet_type = "nmb_query";
+ break;
+ }
+ case NMB_REG:
+ {
+ packet_type = "nmb_reg";
+ break;
+ }
+ case NMB_REL:
+ {
+ packet_type = "nmb_rel";
+ break;
+ }
+ case NMB_WAIT_ACK:
+ {
+ packet_type = "nmb_wack";
+ break;
+ }
+ default:
+ {
+ DEBUG(1,("replying netbios packet: %s %s %s\n",
+ packet_type, namestr(rr_name), inet_ntoa(p.ip)));
+
+ return;
+ }
+ }
+
+ DEBUG(4,("replying netbios packet: %s %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 = recursion_available;
+ nmb->header.nm_flags.recursion_desired = recursion_desired;
+ nmb->header.nm_flags.trunc = False;
+ nmb->header.nm_flags.authoritative = True;
+
+ nmb->header.qdcount = 0;
+ nmb->header.ancount = 1;
+ nmb->header.nscount = 0;
+ nmb->header.arcount = 0;
+ nmb->header.rcode = rcode;
+
+ bzero((char*)&nmb->question,sizeof(nmb->question));
+
+ nmb->answers = &answers;
+ bzero((char*)nmb->answers,sizeof(*nmb->answers));
+
+ nmb->answers->rr_name = *rr_name;
+ nmb->answers->rr_type = rr_type;
+ nmb->answers->rr_class = rr_class;
+ nmb->answers->ttl = ttl;
+
+ if (data && len)
+ {
+ nmb->answers->rdlength = len;
+ memcpy(nmb->answers->rdata, data, len);
+ }
+
+ p.packet_type = NMB_PACKET;
+
+ debug_nmb_packet(&p);
+
+ send_packet(&p);
+}
+
+
+/*******************************************************************
+ the global packet linked-list. incoming entries are added to the
+ end of this list. it is supposed to remain fairly short so we
+ won't bother with an end pointer.
+ ******************************************************************/
+static struct packet_struct *packet_queue = NULL;
+
+/*******************************************************************
+ queue a packet into the packet queue
+ ******************************************************************/
+void queue_packet(struct packet_struct *packet)
+{
+ struct packet_struct *p;
+
+ if (!packet_queue) {
+ packet->prev = NULL;
+ packet->next = NULL;
+ packet_queue = packet;
+ return;
+ }
+
+ /* find the bottom */
+ for (p=packet_queue;p->next;p=p->next) ;
+
+ p->next = packet;
+ packet->next = NULL;
+ packet->prev = p;
+}
+
+/****************************************************************************
+ determine if a packet is for us. Note that to have any chance of
+ being efficient we need to drop as many packets as possible at this
+ stage as subsequent processing is expensive.
+
+ We also must make absolutely sure we don't tread on another machines
+ property by answering a packet that is not for us.
+ ****************************************************************************/
+static BOOL listening(struct packet_struct *p,struct nmb_name *n)
+{
+ struct subnet_record *d;
+ struct name_record *n1 = NULL;
+
+ if((d = find_subnet_all(p->ip)) != NULL)
+ n1 = find_name_on_subnet(d, n, FIND_SELF_NAME);
+
+ return (n1 != NULL);
+}
+
+
+/****************************************************************************
+ 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 we aren't listening to the destination name then ignore the packet */
+ if (!listening(p,&dgram->dest_name))
+ {
+ DEBUG(5,("process_dgram: ignoring dgram packet sent to name %s(%x) from %s\n",
+ dgram->dest_name.name, dgram->dest_name.name_type, inet_ntoa(p->ip)));
+ return;
+ }
+
+ if (dgram->header.msg_type != 0x10 &&
+ dgram->header.msg_type != 0x11 &&
+ dgram->header.msg_type != 0x12)
+ {
+ /* don't process error packets etc yet */
+ DEBUG(5,("process_dgram: ignoring dgram packet sent to name %s(%d) from %s as it is \
+ an error packet of type %x\n",
+ dgram->dest_name.name, dgram->dest_name.name_type,
+ inet_ntoa(p->ip), dgram->header.msg_type));
+ 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,("process_dgram: datagram from %s to %s(%s)for %s of type %d len=%d\n",
+ namestr(&dgram->source_name),namestr(&dgram->dest_name),
+ inet_ntoa(p->ip), smb_buf(buf),CVAL(buf2,0),len));
+
+
+ if (len <= 0) return;
+
+ /* datagram packet received for the browser mailslot */
+ if (strequal(smb_buf(buf),BROWSE_MAILSLOT)) {
+ process_browse_packet(p,buf2,len);
+ return;
+ }
+
+ /* datagram packet received for the domain log on mailslot */
+ if (strequal(smb_buf(buf),NET_LOGON_MAILSLOT)) {
+ process_logon_packet(p,buf2,len);
+ return;
+ }
+
+ /* datagram packet received for the NT domain log on mailslot */
+ if (strequal(smb_buf(buf),NT_LOGON_MAILSLOT)) {
+ process_logon_packet(p,buf2,len);
+ return;
+ }
+}
+
+/****************************************************************************
+ process a nmb packet
+ ****************************************************************************/
+static void process_nmb(struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+
+ debug_nmb_packet(p);
+
+ switch (nmb->header.opcode)
+ {
+ case 8: /* what is this?? */
+ case NMB_REG:
+ case NMB_REG_REFRESH:
+ {
+ if (nmb->header.response)
+ {
+ if (nmb->header.ancount ==0) break;
+ response_netbios_packet(p); /* response to registration dealt
+ with here */
+ }
+ else
+ {
+ if (nmb->header.qdcount==0 || nmb->header.arcount==0) break;
+ reply_name_reg(p);
+ }
+ break;
+ }
+
+ case 0:
+ {
+ if (nmb->header.response)
+ {
+ switch (nmb->question.question_type)
+ {
+ case 0x0:
+ {
+ response_netbios_packet(p);
+ break;
+ }
+ }
+ return;
+ }
+ else if (nmb->header.qdcount>0)
+ {
+ switch (nmb->question.question_type)
+ {
+ case NMB_QUERY:
+ {
+ reply_name_query(p);
+ break;
+ }
+ case NMB_STATUS:
+ {
+ reply_name_status(p);
+ break;
+ }
+ }
+ return;
+ }
+ break;
+ }
+
+ case NMB_REL:
+ {
+ if (nmb->header.response)
+ {
+ if (nmb->header.ancount ==0) break;
+ response_netbios_packet(p); /* response to release dealt
+ with here */
+ }
+ else
+ {
+ if (nmb->header.qdcount==0 || nmb->header.arcount==0) break;
+ reply_name_release(p);
+ }
+ break;
+ }
+ }
+}
+
+
+/*******************************************************************
+ run elements off the packet queue till its empty
+ ******************************************************************/
+void run_packet_queue()
+{
+ struct packet_struct *p;
+
+ while ((p=packet_queue)) {
+ packet_queue = p->next;
+ if (packet_queue) packet_queue->prev = NULL;
+ p->next = p->prev = NULL;
+
+ switch (p->packet_type) {
+ case NMB_PACKET:
+ process_nmb(p);
+ break;
+
+ case DGRAM_PACKET:
+ process_dgram(p);
+ break;
+ }
+ free_packet(p);
+ }
+}
+
+
+/****************************************************************************
+ Create an fd_set containing all the sockets in the subnet structures,
+ plus the broadcast sockets.
+ ***************************************************************************/
+static BOOL create_listen_fdset(fd_set **ppset, int **psock_array, int *listen_number)
+{
+ int *sock_array = NULL;
+ struct subnet_record *d = NULL;
+ int count = 0;
+ int num = 0;
+ fd_set *pset = (fd_set *)malloc(sizeof(fd_set));
+
+ if(pset == NULL)
+ {
+ DEBUG(0,("create_listen_fdset: malloc fail !\n"));
+ return True;
+ }
+
+ /* Check that we can add all the fd's we need. */
+ for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
+ count++;
+
+ if((count*2) + 2 > FD_SETSIZE)
+ {
+ DEBUG(0,("create_listen_fdset: Too many file descriptors needed (%d). We can \
+only use %d.\n", (count*2) + 2, FD_SETSIZE));
+ return True;
+ }
+
+ if((sock_array = (int *)malloc(((count*2) + 2)*sizeof(int))) == NULL)
+ {
+ DEBUG(0,("create_listen_fdset: malloc fail for socket array.\n"));
+ return True;
+ }
+
+ FD_ZERO(pset);
+
+ /* Add in the broadcast socket on 137. */
+ FD_SET(ClientNMB,pset);
+ sock_array[num++] = ClientNMB;
+
+ /* Add in the 137 sockets on all the interfaces. */
+ for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
+ {
+ FD_SET(d->nmb_sock,pset);
+ sock_array[num++] = d->nmb_sock;
+ }
+
+ /* Add in the broadcast socket on 138. */
+ FD_SET(ClientDGRAM,pset);
+ sock_array[num++] = ClientDGRAM;
+
+ /* Add in the 138 sockets on all the interfaces. */
+ for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
+ {
+ FD_SET(d->dgram_sock,pset);
+ sock_array[num++] = d->dgram_sock;
+ }
+
+ *listen_number = (count*2) + 2;
+ *ppset = pset;
+ *psock_array = sock_array;
+
+ return False;
+}
+
+/****************************************************************************
+ listens for NMB or DGRAM packets, and queues them
+ ***************************************************************************/
+BOOL listen_for_packets(BOOL run_election)
+{
+ static fd_set *listen_set = NULL;
+ static int listen_number = 0;
+ static int *sock_array = NULL;
+
+ fd_set fds;
+ int selrtn;
+ struct timeval timeout;
+#ifndef SYNC_DNS
+ int dns_fd;
+#endif
+
+ if(listen_set == NULL)
+ {
+ if(create_listen_fdset(&listen_set, &sock_array, &listen_number))
+ {
+ DEBUG(0,("listen_for_packets: Fatal error. unable to create listen set. Exiting.\n"));
+ return True;
+ }
+ }
+
+ memcpy((char *)&fds, (char *)listen_set, sizeof(fd_set));
+
+#ifndef SYNC_DNS
+ dns_fd = asyncdns_fd();
+ if (dns_fd != -1) {
+ FD_SET(dns_fd, &fds);
+ }
+#endif
+
+
+ /* during elections and when expecting a netbios response packet we
+ need to send election packets at tighter intervals
+
+ ideally it needs to be the interval (in ms) between time now and
+ the time we are expecting the next netbios packet */
+
+ timeout.tv_sec = (run_election||num_response_packets) ? 1:NMBD_SELECT_LOOP;
+ timeout.tv_usec = 0;
+
+ /* We can only take term signals when we are in the select. */
+ BlockSignals(False, SIGTERM);
+ selrtn = sys_select(&fds,&timeout);
+ BlockSignals(True, SIGTERM);
+
+ if(selrtn > 0)
+ {
+ int i;
+
+#ifndef SYNC_DNS
+ if (dns_fd != -1 && FD_ISSET(dns_fd,&fds)) {
+ run_dns_queue();
+ }
+#endif
+
+ for(i = 0; i < listen_number; i++)
+ {
+ if(i < (listen_number/2))
+ {
+ /* Processing a 137 socket. */
+ if (FD_ISSET(sock_array[i],&fds))
+ {
+ struct packet_struct *packet = read_packet(sock_array[i], NMB_PACKET);
+ if (packet)
+ {
+ /*
+ * If we got a packet on the broadcast socket and interfaces
+ * only is set then check it came from one of our local nets.
+ */
+ if(lp_bind_interfaces_only() && (sock_array[i] == ClientNMB) &&
+ (!is_local_net(packet->ip)))
+ {
+ DEBUG(7,("discarding nmb packet sent to broadcast socket from %s:%d\n",
+ inet_ntoa(packet->ip),packet->port));
+ free_packet(packet);
+ }
+ else if ((ip_equal(loopback_ip, packet->ip) ||
+ ismyip(packet->ip)) && packet->port == NMB_PORT)
+ {
+ DEBUG(7,("discarding own packet from %s:%d\n",
+ inet_ntoa(packet->ip),packet->port));
+ free_packet(packet);
+ }
+ else
+ {
+ queue_packet(packet);
+ }
+ }
+ }
+ }
+ else
+ {
+ /* Processing a 138 socket. */
+
+ if (FD_ISSET(sock_array[i],&fds))
+ {
+ struct packet_struct *packet = read_packet(sock_array[i], DGRAM_PACKET);
+ if (packet)
+ {
+ /*
+ * If we got a packet on the broadcast socket and interfaces
+ * only is set then check it came from one of our local nets.
+ */
+ if(lp_bind_interfaces_only() && (sock_array[i] == ClientDGRAM) &&
+ (!is_local_net(packet->ip)))
+ {
+ DEBUG(7,("discarding dgram packet sent to broadcast socket from %s:%d\n",
+ inet_ntoa(packet->ip),packet->port));
+ free_packet(packet);
+ }
+ else if ((ip_equal(loopback_ip, packet->ip) ||
+ ismyip(packet->ip)) && packet->port == DGRAM_PORT)
+ {
+ DEBUG(7,("discarding own packet from %s:%d\n",
+ inet_ntoa(packet->ip),packet->port));
+ free_packet(packet);
+ }
+ else
+ {
+ queue_packet(packet);
+ }
+ }
+ }
+ } /* end processing 138 socket. */
+ } /* end for */
+ } /* end if selret > 0 */
+ return False;
+}
+
+
+
+/****************************************************************************
+ 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(BOOL unique, 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];
+
+ /* ha ha. no. do NOT send packets to 255.255.255.255: it's a pseudo address */
+ if (ip_equal(wins_ip, dest_ip)) return False;
+
+ bzero((char *)&p,sizeof(p));
+
+ update_name_trn_id();
+
+ /* DIRECT GROUP or UNIQUE datagram */
+ dgram->header.msg_type = unique ? 0x10 : 0x11;
+ 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;
+
+ DEBUG(4,("send mailslot %s from %s %s", mailslot,
+ inet_ntoa(src_ip),namestr(&dgram->source_name)));
+ DEBUG(4,("to %s %s\n", inet_ntoa(dest_ip),namestr(&dgram->dest_name)));
+
+ return(send_packet(&p));
+}
diff --git a/source/namepacket.doc b/source/namepacket.doc
new file mode 100644
index 00000000000..159a50738c5
--- /dev/null
+++ b/source/namepacket.doc
@@ -0,0 +1,133 @@
+/*
+ Unix SMB/Netbios documentation.
+ Version 0.0
+ Copyright (C) Luke Leighton Andrew Tridgell 1996
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Document name: namepacket.doc
+
+ Revision History:
+
+ 0.0 - 02jul96 : lkcl@pires.co.uk
+ created
+*/
+
+this module deals with packets: sending, receiving, queueing
+and some basic interpretation (e.g it excludes datagram
+error packets at the moment).
+
+the packet queueing mechanism was originally introduced when
+samba dealt with responses by sending a packet, receiving
+packets and queueing all packets that didn't match up with
+the response expected. this is fine in a single-thread
+environment, but samba now deals with response packets by
+queueing the responses. to some extent, therefore, this
+queue_packet mechanism is redundant.
+
+
+/*************************************************************************
+ send_mailslot_reply()
+ *************************************************************************/
+
+this function is responsible for sending a MAILSLOT packet.
+
+it will _not_ send packets to the pseudo WINS subnet's address of
+255.255.255.255: this would be disastrous.
+
+each packet sent out has a unique transaction identifier. this is done
+so that responses can be matched later with the original purpose for
+the packet being sent out in the first place.
+
+
+/*************************************************************************
+ listen_for_packets()
+ *************************************************************************/
+
+this function is responsible for reading NMB and DGRAM packets, and then
+queueing them. it will normally time-out for NMBD_SELECT_LOOP seconds, but
+if there is an election currently running or we are expecting a response
+then this time is reduced to 1 second.
+
+note: the time-out period needs refining to the millisecond level.
+
+
+/*************************************************************************
+ queue_packet()
+ *************************************************************************/
+
+this function is responsible for queueing any NMB and DGRAM packets passed
+to it. these packets will be removed from the queue in run_packet_queue().
+
+
+/*************************************************************************
+ run_packet_queue()
+ *************************************************************************/
+
+this function is responsible for taking a packet off the queue,
+identifying whether it is an NMB or a DGRAM packet, processing
+it accordingly and deleting it. this process continues until
+there are no more packets on the queue.
+
+
+/*************************************************************************
+ process_nmb()
+ *************************************************************************/
+
+this function receives a packet identified as a netbios packet.
+it further identifies whether it is a response or a query packet.
+by identifying the type of packet (name registration, query etc)
+process_nmb() will call the appropriate function to deal with the
+type of packet received.
+
+
+/*************************************************************************
+ process_dgram()
+ *************************************************************************/
+
+this function is responsible for identifying whether the datagram
+packet received is a browser packet or a domain logon packet. it
+also does some filtering of certain types of packets (e.g it
+filters out error packets).
+
+
+/*************************************************************************
+ reply_netbios_packet()
+ *************************************************************************/
+
+this function is responsible for sending a reply to another NetBIOS
+packet from another host. it can be used to send a reply to a name
+registration, name release, name query or name status request.
+
+the reply can be either a positive or a negative one.
+
+
+/*************************************************************************
+ initiate_netbios_packet()
+ *************************************************************************/
+
+this function is responsible for construction a netbios packet and sending
+it. if the packet has not had a unique transaction id allocated to it,
+then initiate_netbios_packet() will give it one.
+
+
+/*************************************************************************
+ update_name_trn_id()
+ *************************************************************************/
+
+this function is responsible for allocating unique transaction identifiers
+for each new packet sent on the network.
+
+
diff --git a/source/namequery.doc b/source/namequery.doc
new file mode 100644
index 00000000000..4337cfb7e2a
--- /dev/null
+++ b/source/namequery.doc
@@ -0,0 +1,83 @@
+/*
+ Unix SMB/Netbios documentation.
+ Version 0.0
+ Copyright (C) Luke Leighton Andrew Tridgell 1996
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Document name: namequery.doc
+
+ Revision History:
+
+ 0.0 - 02jul96 : lkcl@pires.co.uk
+ created
+*/
+
+this module contains non-threaded versions of name status and name
+query functions. if a multi-threaded nmbd was to be written, these
+functions would be the starting point.
+
+at the moment, the expected response queueing system is used to
+replace these functions without needing to multi-thread nmbd.
+
+these functions are used in smbclient and nmblookup at present to
+avoid having the vast quantities of complex and unused code needed
+to support even a simple name query (or providing stubs for the
+unused side of these functions).
+
+there is a down-side to these functions, which is all microsoft's
+fault. microsoft machines always always reply to queries on the
+priveleged ports, rather than following the usual tcp/ip mechanism
+of replying on the client's port (the exception to this i am led
+to believe is windows nt 3.50).
+
+as a result of this, in order to receive a response to a name
+query from a microsoft machine, we must be able to listen on
+the priveleged netbios name server ports. this is simply not
+possible with some versions of unix, unless you have root access.
+
+it is also not possible if you run smbclient or nmblookup on an
+interface that already has been claimed by the netbios name server
+daemon nmbd.
+
+all in all, i wish that microsoft would fix this.
+
+a solution does exist: nmbd _does_ actually reply on the client's
+port, so if smbclient and nmblookup were to use nmbd as a proxy
+forwarder of queries (or to use samba's WINS capabilities) then
+a query could be made without needing access to the priveleged
+ports. in order to do this properly, samba must implement secured
+netbios name server functionality (see rfc1001.txt 15.1.6).
+(lkcl 01aug96: samba now supports secured name registration)
+
+/*************************************************************************
+ name_query()
+ *************************************************************************/
+
+
+
+/*************************************************************************
+ name_status()
+ *************************************************************************/
+
+
+
+/*************************************************************************
+ _interpret_node_status()
+ *************************************************************************/
+
+
+this is a older version of interpret_node_status().
+
diff --git a/source/nameresp.c b/source/nameresp.c
new file mode 100644
index 00000000000..de1f33c7172
--- /dev/null
+++ b/source/nameresp.c
@@ -0,0 +1,318 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios library routines
+ Copyright (C) Andrew Tridgell 1994-1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Module name: nameresp.c
+
+*/
+
+#include "includes.h"
+
+extern int ClientNMB;
+
+extern struct subnet_record *subnetlist;
+
+extern int DEBUGLEVEL;
+
+extern pstring scope;
+extern struct in_addr ipzero;
+extern struct in_addr wins_ip;
+
+
+/***************************************************************************
+ deals with an entry before it dies
+ **************************************************************************/
+static void dead_netbios_entry(struct subnet_record *d,
+ struct response_record *n)
+{
+ DEBUG(3,("Removing dead netbios entry for %s %s (num_msgs=%d)\n",
+ inet_ntoa(n->send_ip), namestr(&n->name), n->num_msgs));
+
+ debug_state_type(n->state);
+
+ switch (n->state)
+ {
+ case NAME_QUERY_CONFIRM:
+ {
+ if (!lp_wins_support()) return; /* only if we're a WINS server */
+
+ if (n->num_msgs == 0)
+ {
+ /* oops. name query had no response. check that the name is
+ unique and then remove it from our WINS database */
+
+ /* IMPORTANT: see query_refresh_names() */
+
+ if ((!NAME_GROUP(n->nb_flags)))
+ {
+ struct subnet_record *d1 = wins_client_subnet;
+ if (d1)
+ {
+ /* remove the name that had been registered with us,
+ and we're now getting no response when challenging.
+ see rfc1001.txt 15.5.2
+ */
+ remove_netbios_name(d1, n->name.name, n->name.name_type, REGISTER);
+ }
+ }
+ }
+ break;
+ }
+
+ case NAME_QUERY_MST_CHK:
+ {
+ /* if no response received, the master browser must have gone
+ down on that subnet, without telling anyone. */
+
+ /* IMPORTANT: see response_netbios_packet() */
+
+ if (n->num_msgs == 0)
+ browser_gone(n->name.name, n->send_ip);
+ break;
+ }
+
+ case NAME_RELEASE:
+ {
+ /* if no response received, it must be OK for us to release the
+ name. nobody objected (including a potentially dead or deaf
+ WINS server) */
+
+ /* IMPORTANT: see response_name_release() */
+
+ if (ismyip(n->send_ip))
+ {
+ name_unregister_work(d,n->name.name,n->name.name_type);
+ }
+ if (!n->bcast && n->num_msgs == 0)
+ {
+ DEBUG(0,("WINS server did not respond to name release!\n"));
+ /* XXXX whoops. we have problems. must deal with this */
+ }
+ break;
+ }
+
+ case NAME_REGISTER_CHALLENGE:
+ {
+ /* name challenge: no reply. we can reply to the person that
+ wanted the unique name and tell them that they can have it
+ */
+
+ add_name_respond(d,n->fd,d->myip, n->reply_id ,&n->name,
+ n->nb_flags, GET_TTL(0),
+ n->reply_to_ip, True, n->reply_to_ip);
+ break;
+ }
+
+ case NAME_REGISTER:
+ {
+ /* if no response received, and we are using a broadcast registration
+ method, it must be OK for us to register the name: nobody objected
+ on that subnet. if we are using a WINS server, then the WINS
+ server must be dead or deaf.
+ */
+ if (n->num_msgs == 0)
+ {
+ if (n->bcast)
+ {
+ /* broadcast method: implicit acceptance of the name registration
+ by not receiving any objections. */
+
+ /* IMPORTANT: see response_name_reg() */
+
+ name_register_work(d,n->name.name,n->name.name_type,
+ n->nb_flags, n->ttl, n->reply_to_ip, n->bcast);
+ }
+ else
+ {
+ /* received no response. rfc1001.txt states that after retrying,
+ we should assume the WINS server is dead, and fall back to
+ broadcasting (see bits about M nodes: can't find any right
+ now) */
+
+ DEBUG(1,("WINS server did not respond to name registration!\n"));
+ /* XXXX whoops. we have problems. must deal with this */
+ }
+ }
+ break;
+ }
+
+ case NAME_QUERY_DOMAIN:
+ {
+ /* if no response was received, there is no domain controller for
+ this DOMAIN registered within WINS. it's ok for us to register
+ the DOMAIN<1b> name.
+ */
+
+ if (n->num_msgs == 0)
+ {
+ struct work_record *work = find_workgroupstruct(d,n->name.name,False);
+ if (work && d)
+ {
+ become_domain_master(d,work);
+ }
+ }
+ else
+ {
+ DEBUG(1, ("nmbd configured as domain master and one already exists\n"));
+ }
+ break;
+ }
+
+ default:
+ {
+ /* nothing to do but delete the dead expected-response structure */
+ /* this is normal. */
+ break;
+ }
+ }
+}
+
+
+/*******************************************************************
+ remove old name response entries
+
+ XXXX retry code needs to be added, including a retry wait period and a count
+ see name_query() and name_status() for suggested implementation.
+
+ ******************************************************************/
+void expire_netbios_response_entries(time_t t)
+{
+ struct subnet_record *d;
+
+ for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
+ {
+ struct response_record *n, *nextn;
+
+ for (n = d->responselist; n; n = nextn)
+ {
+ nextn = n->next;
+
+ if (n->repeat_time <= t)
+ {
+ if (n->repeat_count > 0)
+ {
+ /* resend the entry */
+ initiate_netbios_packet(&n->response_id, n->fd, n->quest_type,
+ n->name.name, n->name.name_type,
+ n->nb_flags, n->bcast, n->recurse, n->send_ip);
+
+ n->repeat_time += n->repeat_interval; /* XXXX ms needed */
+ n->repeat_count--;
+
+ }
+ else
+ {
+ DEBUG(4,("timeout response %d for %s %s\n",
+ n->response_id, namestr(&n->name),
+ inet_ntoa(n->send_ip)));
+
+ dead_netbios_entry(d,n); /* process the non-response */
+ remove_response_record(d,n); /* remove the non-response */
+
+ continue;
+ }
+ }
+ }
+ }
+}
+
+
+/****************************************************************************
+ wrapper function to override a broadcast message and send it to the WINS
+ name server instead, if it exists. if wins is false, and there has been no
+ WINS server specified, the packet will NOT be sent.
+ ****************************************************************************/
+struct response_record *queue_netbios_pkt_wins(
+ int fd,int quest_type,enum state_type state,
+ char *name,int name_type,int nb_flags, time_t ttl,
+ int server_type, char *my_name, char *my_comment,
+ struct in_addr send_ip, struct in_addr reply_to_ip)
+{
+ /* XXXX note: please see rfc1001.txt section 10 for details on this
+ function: it is currently inappropriate to use this - it will do
+ for now - once there is a clarification of B, M and P nodes and
+ which one samba is supposed to be
+ */
+
+ if ((!lp_wins_support()) && (*lp_wins_server()))
+ {
+ /* samba is not a WINS server, and we are using a WINS server */
+ struct in_addr real_wins_ip;
+ real_wins_ip = *interpret_addr2(lp_wins_server());
+
+ if (!zero_ip(real_wins_ip))
+ {
+ send_ip = real_wins_ip;
+ }
+ else
+ {
+ /* oops. smb.conf's wins server parameter MUST be a host_name
+ or an ip_address. */
+ DEBUG(0,("invalid smb.conf parameter 'wins server'\n"));
+ }
+ }
+
+ if (zero_ip(send_ip)) return NULL;
+
+ return queue_netbios_packet(wins_client_subnet,fd, quest_type, state,
+ name, name_type, nb_flags, ttl,
+ server_type,my_name,my_comment,
+ False, True, send_ip, reply_to_ip, 0);
+}
+
+
+/****************************************************************************
+ initiate a netbios name query to find someone's or someones' IP
+ this is intended to be used (not exclusively) for broadcasting to
+ master browsers (WORKGROUP(1d or 1b) or __MSBROWSE__(1)) to get
+ complete lists across a wide area network
+ ****************************************************************************/
+struct response_record *queue_netbios_packet(struct subnet_record *d,
+ int fd,int quest_type,enum state_type state,char *name,
+ int name_type,int nb_flags, time_t ttl,
+ int server_type, char *my_name, char *my_comment,
+ BOOL bcast,BOOL recurse,
+ struct in_addr send_ip, struct in_addr reply_to_ip,
+ int reply_id)
+{
+ struct response_record *n;
+ uint16 id = 0xffff;
+
+ /* ha ha. no. do NOT broadcast to 255.255.255.255: it's a pseudo address */
+ if (ip_equal(wins_ip, send_ip)) return NULL;
+
+ initiate_netbios_packet(&id, fd, quest_type, name, name_type,
+ nb_flags, bcast, recurse, send_ip);
+
+ if (id == 0xffff) {
+ DEBUG(4,("did not initiate netbios packet: %s\n", inet_ntoa(send_ip)));
+ return NULL;
+ }
+
+ if ((n = make_response_queue_record(state,id,fd,
+ quest_type,name,name_type,nb_flags,ttl,
+ server_type,my_name, my_comment,
+ bcast,recurse,send_ip,reply_to_ip,
+ reply_id)))
+ {
+ add_response_record(d,n);
+ return n;
+ }
+ return NULL;
+}
diff --git a/source/nameresp.doc b/source/nameresp.doc
new file mode 100644
index 00000000000..cfe63500c88
--- /dev/null
+++ b/source/nameresp.doc
@@ -0,0 +1,178 @@
+/*
+ Unix SMB/Netbios documentation.
+ Version 0.0
+ Copyright (C) Luke Leighton Andrew Tridgell 1996
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Document name: nameresp.doc
+
+ Revision History:
+
+ 0.0 - 02jul96 : lkcl@pires.co.uk
+ created
+*/
+
+the netbios expected response code is a key part of samba's NetBIOS
+handling capabilities. it allows samba to carry on dealing with
+other things while expecting a response from one or more hosts.
+
+this allows samba to simultaneously deal with registering its names
+with another WINS server, register its names on its local subnets,
+query any hosts that have registered with samba in its capacity as
+a WINS server, and at a later date it will be also be able handle
+END-NODE CHALLENGES (see rfc1001.txt 15.2.2.2 and 15.2.2.3 - secured
+NBNS functionality).
+
+all at once!
+
+when a netbios packet is sent out by samba and it expects a response,
+a record of all the relevant information is kept (most importantly,
+the unique transaction id associated which will come back to us in
+a response packet is recorded, and also recorded is the reason that
+the original packet was sent out by samba in the first place!).
+
+if a response is received, then the unique transaction identifier
+returned in the response packet is searched for in the expected
+response records. the record indicates why the initial request was
+made (and therefore the type of response can be verified) and
+appropriate action can be taken.
+
+when no responses, after a number of retries, are not received, then
+samba may take appropriate action. this is a crucial part of samba's
+operation: for a key number of NetBIOS operations, no response is an
+implicit positive response.
+
+module nameresp deals with the initial transmission, re-transmission
+and time-out of netbios response records.
+
+module namedbresp deals with the maintenance of the list of expected
+responses - creation, finding and removal.
+
+
+/*************************************************************************
+ queue_netbios_packet()
+ *************************************************************************/
+
+this function is responsible for sending out a netbios packet, and then
+making a record of the information that was sent out. a response will
+be expected later (or not, as the case may be).
+
+if a response is received, response_netbios_packet() will deal with it.
+otherwise, it will be dealt with in expire_netbios_response_entries().
+
+
+/*************************************************************************
+ queue_netbios_pkt_wins()
+ *************************************************************************/
+
+this function is a wrapper around queue_netbios_packet(). there is
+some confusion about B, M and P nodes (see rfc1001.txt section 10) -
+confusion introduced by luke :-) - which needs sorting out.
+
+for example, rfc1001.txt 15.2.3 - an M node must attempt to register a
+name first as a B node, then attempt to register as an M node. negative
+responses on either of these attempts is a failure to register the
+name.
+
+this is NOT the case with a P node.
+
+
+/*************************************************************************
+ expire_netbios_response_entries()
+ *************************************************************************/
+
+this function is responsible for dealing with queued response records
+that have not received a response packet matching their unique
+transaction id.
+
+if the retry count for any record is non-zero, and its time-out period
+has expired, the retry count is reduced, the time-out period is stepped
+forward and the packet is re-transmitted (from the information stored
+in the queued response record) with the same unique transaction id of
+the initial attempt at soliciting a response.
+
+if the retry count is zero, then the packet is assumed to have expired.
+dead_netbios_entry() is called to deal with the possibility of an error
+or a problem (or in certain instances, no answer is an implicit
+positive response!).
+
+the expected response record is then deleted, and the number of expected
+responses reduced. when this count gets to zero, listen_for_packets()
+will no longer time-out for 1 second on account of expecting response
+packets.
+
+
+/*************************************************************************
+ dead_netbios_entry()
+ *************************************************************************/
+
+this function is responsible for dealing with the case when a NetBIOS
+response to a packet sent out by samba was not received. for certain
+transactions, this may be normal. for others, under certain conditions
+it may constitute either an error or a problem with or failure of one
+or more hosts.
+
+- NAME_QUERY_CONFIRM
+
+when a samba 'state' of type NAME_QUERY_CONFIRM is sent, a response
+may or may not be forthcoming. if no response is received to a unique
+name, then the record is removed from samba's WINS database. non-unique
+names are simply expected to die off on a time-to-live basis (see
+rfc1001.txt 15.1.3.4)
+
+query_refresh_names() issues this samba 'state'
+response_name_query_sync() deals with responses to NAME_QUERY_CONFIRM.
+
+- NAME_QUERY_MST_CHK
+
+when a samba 'state' of type NAME_QUERY_MST_CHK is sent, and a response
+is not received, this implies that a master browser will have failed.
+remedial action may need to be taken, for example if samba is a member
+of that workgroup and it is also a potential master browser it could
+force an election.
+
+check_master_browser() issues this samba 'state'.
+response_process() does nothing if a response is received. this is normal.
+
+- NAME_RELEASE
+
+when a samba 'state' of type NAME_RELEASE is sent, and a response is
+not received, it is assumed to be acceptable to release the name. if the
+original response was sent to another WINS server, then that WINS server
+may be inaccessible or may have failed. if so, then at a later date
+samba should take this into account (see rfc1001.txt 10.3).
+
+remove_name_entry() issues this samba 'state'
+response_name_rel() deals with responses to NAME_RELEASE.
+
+- NAME_REGISTER
+
+when a samba 'state' of type NAME_REGISTER is sent, and a response is
+not received, if the registration was done by broadcast, it is assumed
+that there are no objections to the registration of this name, and samba
+adds the name to the appropriate subnet record name database. if the
+registration was point-to-point (i.e with another WINS server) then that
+WINS server may be inaccessible or may have failed. if so, then at a later
+date samba should take this into account (see rfc1001.txt 10.3).
+
+add_my_name_entry() issues this samba 'state'
+response_name_reg() deals with responses to NAME_REGISTER.
+
+no action is taken for any other kinds of samba 'states' if a response
+is not received. this is not to say that action may not be appropriate,
+just that it's not been looked at yet :-)
+
+
diff --git a/source/nameserv.c b/source/nameserv.c
index 802b98ec0a0..a05db3983ec 100644
--- a/source/nameserv.c
+++ b/source/nameserv.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
NBT netbios routines and daemon - version 2
- Copyright (C) Andrew Tridgell 1994-1995
+ Copyright (C) Andrew Tridgell 1994-1997
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,2301 +18,481 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ Module name: nameserv.c
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+ 04 jul 96: lkcl@pires.co.uk
+ module nameserv contains name server management functions
*/
#include "includes.h"
-#include "loadparm.h"
-#include "nameserv.h"
-
-static void queue_packet(struct packet_struct *packet);
-void process(void);
-static void dump_names(void);
-static void announce_request(char *group);
-void sync_browse_lists(char *name,int name_type,char *myname,
- char *domain,struct in_addr ip);
+extern int ClientNMB;
extern int DEBUGLEVEL;
-extern pstring debugf;
-pstring servicesf = CONFIGFILE;
-
extern pstring scope;
+extern pstring myname;
+extern fstring myworkgroup;
+extern char **my_netbios_names;
+extern struct in_addr ipzero;
+extern struct in_addr wins_ip;
-extern BOOL CanRecurse;
-
-extern struct in_addr myip;
-extern struct in_addr bcast_ip;
-extern struct in_addr Netmask;
-extern pstring myhostname;
-static pstring host_file;
-static pstring myname="";
-
-static int ClientNMB= -1;
-static int ClientDGRAM= -1;
-
-static BOOL needannounce=True;
-
-/* this is our name database */
-static struct name_record *namelist = NULL;
-
-/* list of servers to be returned by NetServerEnum */
-static struct server_record *serverlist = NULL;
-
-/* this is the domain list. For the moment we will assume that our
- primary domain is the first one listed in this list */
-static struct domain_record *domainlist = NULL;
-
-/* are we running as a daemon ? */
-static BOOL is_daemon = False;
-
-/* machine comment for host announcements */
-static pstring ServerComment="";
-
-static BOOL got_bcast = False;
-static BOOL got_myip = False;
-static BOOL got_nmask = False;
-
-static BOOL updatedlists = False;
-static int updatecount=0;
-
-/* what server type are we currently */
-static int ServerType =
-SV_TYPE_WORKSTATION | SV_TYPE_SERVER | SV_TYPE_TIME_SOURCE |
-SV_TYPE_SERVER_UNIX |
-SV_TYPE_PRINTQ_SERVER | SV_TYPE_POTENTIAL_BROWSER;
-
-/* here are my election parameters */
-
-/* NTAS uses 2, NT uses 1, WfWg uses 0 */
-#define MAINTAIN_LIST 1
-#define ELECTION_VERSION 1
-
-static BOOL RunningElection = False;
-static BOOL needelection = False;
-static int ElectionCount = 0;
-static int StartupTime =0;
-
+extern struct subnet_record *subnetlist;
-/* 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"
-
-#define GET_TTL(ttl) ((ttl)?MIN(ttl,lp_max_ttl()):lp_max_ttl())
-
-#define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE"
+extern uint16 nb_type; /* samba's NetBIOS type */
/****************************************************************************
-catch a sighup
-****************************************************************************/
-static int sig_hup()
-{
- BlockSignals(True);
-
- DEBUG(0,("Got SIGHUP (reload not implemented)\n"));
- dump_names();
- reload_services(True);
+ remove an entry from the name list
- BlockSignals(False);
-#ifndef DONT_REINSTALL_SIG
- signal(SIGHUP,SIGNAL_CAST sig_hup);
-#endif
- return(0);
-}
+ note: the name will _always_ be removed
+ XXXX at present, the name is removed _even_ if a WINS server says keep it.
-/****************************************************************************
-catch a sigpipe
-****************************************************************************/
-static int sig_pipe()
+ ****************************************************************************/
+void remove_name_entry(struct subnet_record *d, char *name,int type)
{
- BlockSignals(True);
+ /* XXXX BUG: if samba is offering WINS support, it should still broadcast
+ a de-registration packet to the local subnet before removing the
+ name from its local-subnet name database. */
- DEBUG(0,("Got SIGPIPE\n"));
- if (!is_daemon)
- exit(1);
- BlockSignals(False);
- return(0);
-}
+ struct name_record n;
+ struct name_record *n2=NULL;
+
+ make_nmb_name(&n.name,name,type,scope);
-#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
+ if ((n2 = find_name_on_subnet(d, &n.name, FIND_SELF_NAME)))
{
- 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
-****************************************************************************/
-static BOOL name_equal(struct nmb_name *n1,struct nmb_name *n2)
-{
- if (n1->name_type != n2->name_type) return(False);
-
- return(strequal(n1->name,n2->name) && strequal(n1->scope,n2->scope));
-}
-
-/****************************************************************************
- add a netbios name into the namelist
- **************************************************************************/
-static void add_name(struct name_record *n)
-{
- struct name_record *n2;
-
- if (!namelist) {
- namelist = n;
- n->prev = NULL;
- n->next = NULL;
- return;
- }
-
- for (n2 = namelist; n2->next; n2 = n2->next) ;
-
- n2->next = n;
- n->next = NULL;
- n->prev = n2;
-}
-
-/****************************************************************************
- add a domain into the list
- **************************************************************************/
-static void add_domain(struct domain_record *d)
-{
- struct domain_record *d2;
+ /* check name isn't already being de-registered */
+ if (NAME_DEREG(n2->ip_flgs[0].nb_flags))
+ return;
- if (!domainlist) {
- domainlist = d;
- d->prev = NULL;
- d->next = NULL;
- return;
+ /* mark the name as in the process of deletion. */
+ n2->ip_flgs[0].nb_flags &= NB_DEREG;
}
- for (d2 = domainlist; d2->next; d2 = d2->next) ;
-
- d2->next = d;
- d->next = NULL;
- d->prev = d2;
-}
+ if (!n2) return;
-
-/****************************************************************************
- 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;
+ /* Only remove names with non-zero death times. */
+ if(n2->death_time == 0)
+ {
+ DEBUG(5,("remove_name_entry: Name %s(%d) has zero ttl - not removing.\n",
+ name, type));
return;
}
- for (s2 = serverlist; s2->next; s2 = s2->next) ;
-
- s2->next = s;
- s->next = NULL;
- s->prev = s2;
-}
-
-/****************************************************************************
- remove a name from the namelist. The pointer must be an element just
- retrieved
- **************************************************************************/
-static void remove_name(struct name_record *n)
-{
- struct name_record *nlist = namelist;
- while (nlist && nlist != n) nlist = nlist->next;
- if (nlist) {
- if (nlist->next) nlist->next->prev = nlist->prev;
- if (nlist->prev) nlist->prev->next = nlist->next;
- free(nlist);
- }
-}
-
-/****************************************************************************
- find a name in the namelist
- **************************************************************************/
-static struct name_record *find_name(struct nmb_name *n)
-{
- struct name_record *ret;
- for (ret = namelist; ret; ret = ret->next)
- if (name_equal(&ret->name,n)) return(ret);
-
- return(NULL);
-}
+ /* remove the name immediately. even if the spec says we should
+ first try to release them, this is too dangerous with our current
+ name structures as otherwise we will end up replying to names we
+ don't really own */
+ remove_netbios_name(d,name,type,SELF);
-/****************************************************************************
- dump a copy of the name table
- **************************************************************************/
-static void dump_names(void)
-{
- time_t t = time(NULL);
- struct name_record *n;
- struct domain_record *d;
-
- DEBUG(3,("Dump of local name table:\n"));
-
- for (n = namelist; n; n = n->next) {
- DEBUG(3,("%s %s TTL=%d Unique=%s\n",
- namestr(&n->name),
- inet_ntoa(n->ip),
- n->death_time?n->death_time-t:0,
- BOOLSTR(n->unique)));
+ if (ip_equal(d->bcast_ip, wins_ip))
+ {
+ if (!lp_wins_support())
+ {
+ /* not a WINS server: we have to release them on the network */
+ queue_netbios_pkt_wins(ClientNMB,NMB_REL,NAME_RELEASE,
+ name, type, 0, 0,0,NULL,NULL,
+ ipzero, ipzero);
}
-
- DEBUG(3,("\nDump of domain list:\n"));
- for (d = domainlist; d; d = d->next)
- DEBUG(3,("%s %s\n",d->name,inet_ntoa(d->bcast_ip)));
-}
-
-
-/****************************************************************************
- add a host entry to the name list
- ****************************************************************************/
-static struct name_record *add_host_entry(char *name,int type,BOOL unique,int ttl,
- enum name_source source,
- struct in_addr ip)
-{
- struct name_record *n;
- struct name_record *n2=NULL;
-
- n = (struct name_record *)malloc(sizeof(*n));
- if (!n) return(NULL);
-
- bzero((char *)n,sizeof(*n));
-
- make_nmb_name(&n->name,name,type,scope);
- if ((n2=find_name(&n->name))) {
- free(n);
- n = n2;
}
-
- if (ttl) n->death_time = time(NULL)+ttl*3;
- n->ip = ip;
- n->unique = unique;
- n->source = source;
-
- if (!n2) add_name(n);
-
- DEBUG(3,("Added host entry %s at %s ttl=%d unique=%s\n",
- namestr(&n->name),inet_ntoa(ip),ttl,BOOLSTR(unique)));
-
- return(n);
+ else
+ {
+ /* local interface: release them on the network */
+ queue_netbios_packet(d,ClientNMB,NMB_REL,NAME_RELEASE,
+ name, type, 0, 0,0,NULL,NULL,
+ True, False, d->bcast_ip, d->bcast_ip, 0);
+ }
}
/****************************************************************************
- add a domain entry
- ****************************************************************************/
-static struct domain_record *add_domain_entry(char *name,struct in_addr ip)
-{
- struct domain_record *d;
-
- d = (struct domain_record *)malloc(sizeof(*d));
-
- if (!d) return(NULL);
-
- bzero((char *)d,sizeof(*d));
-
- if (zero_ip(ip)) ip = bcast_ip;
-
- StrnCpy(d->name,name,sizeof(d->name)-1);
- d->bcast_ip = ip;
-
- if (!PrimaryGroup[0] && ip_equal(bcast_ip,ip) && name[0] != '*') {
- strcpy(PrimaryGroup,name);
- strupper(PrimaryGroup);
- DEBUG(3,("Setting primary group to %s (%s)\n",PrimaryGroup,inet_ntoa(ip)));
- }
-
- add_domain(d);
-
- ip = *interpret_addr2("255.255.255.255");
- if (name[0] != '*') add_host_entry(name,0x1e,False,0,SELF,ip);
-
- DEBUG(3,("Added domain entry %s at %s\n",
- name,inet_ntoa(ip)));
-
- return(d);
-}
+ add an entry to the name list
+
+ big note: our name will _always_ be added (if there are no objections).
+ it's just a matter of when this will be done (e.g after a time-out).
-/****************************************************************************
- add a server entry
****************************************************************************/
-struct server_record *add_server_entry(char *name,int servertype,
- int ttl,char *comment,BOOL replace)
+void add_my_name_entry(struct subnet_record *d,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;
+ BOOL re_reg = False;
+ struct nmb_name n;
- if (s && !replace) {
- DEBUG(4,("Not replacing %s\n",name));
- return(s);
- }
-
- updatedlists=True;
-
- if (!s) {
- newentry = True;
- s = (struct server_record *)malloc(sizeof(*s));
-
- if (!s) return(NULL);
-
- bzero((char *)s,sizeof(*s));
- }
-
- /* update the entry */
- StrnCpy(s->name,name,sizeof(s->name)-1);
- StrnCpy(s->comment,comment,sizeof(s->comment)-1);
- s->servertype = servertype;
- s->death_time = ttl?time(NULL)+ttl*3:0;
- strupper(s->name);
- if (s->servertype & SV_TYPE_DOMAIN_ENUM) strupper(s->comment);
-
- if (!newentry) return(s);
-
- add_server(s);
-
- if (newentry) {
- DEBUG(3,("Added server entry %s of type %x (%s)\n",
- name,servertype,comment));
- } else {
- DEBUG(3,("Updated server entry %s of type %x (%s)\n",
- name,servertype,comment));
- }
-
- return(s);
-}
-
-
-/****************************************************************************
- add the magic samba names, useful for finding samba servers
- **************************************************************************/
-static void add_my_names(void)
-{
- struct in_addr ip;
-
- ip = *interpret_addr2("0.0.0.0");
-
- add_host_entry(myname,0x20,True,0,SELF,ip);
- add_host_entry(myname,0x0,True,0,SELF,ip);
- add_host_entry(myname,0x1f,True,0,SELF,ip); /* used for chat?? */
- add_host_entry(myname,0x3,True,0,SELF,ip); /* used for winpopup */
-
- if (!domainlist)
- add_domain_entry(lp_workgroup(),bcast_ip);
- add_server_entry(myname,
- ServerType,
- 0,ServerComment,True);
-
- add_host_entry("__SAMBA__",0x20,True,0,SELF,ip);
- add_host_entry("__SAMBA__",0x0,True,0,SELF,ip);
-
- if (lp_preferred_master()) {
- DEBUG(3,("Preferred master startup\n"));
- needelection = True;
- ElectionCriterion |= (1<<3);
- }
+ if (!d) return;
- ElectionCriterion |= (lp_os_level() << 24);
-}
+ /* not that it particularly matters, but if the SELF name already exists,
+ it must be re-registered, rather than just registered */
+ make_nmb_name(&n, name, type, scope);
+ if (find_name_on_subnet(d, &n, FIND_SELF_NAME))
+ re_reg = True;
-/*******************************************************************
- write out browse.dat
- ******************************************************************/
-static void write_browse_list(void)
-{
- struct server_record *s;
- pstring fname,fnamenew;
- FILE *f;
-
- updatecount++;
-
- strcpy(fname,lp_lockdir());
- trim_string(fname,NULL,"/");
- strcat(fname,"/");
- strcat(fname,SERVER_LIST);
- strcpy(fnamenew,fname);
- strcat(fnamenew,".");
-
- f = fopen(fnamenew,"w");
-
- if (!f) {
- DEBUG(4,("Can't open %s - %s\n",fnamenew,strerror(errno)));
- return;
- }
-
- for (s=serverlist; s ; s = s->next) {
- /* don't list domains I don't have a master for */
- if ((s->servertype & SV_TYPE_DOMAIN_ENUM) && !s->comment[0]) continue;
-
- fprintf(f,"\"%s\"\t%08x\t\"%s\"\n",s->name,s->servertype,s->comment);
- }
-
-
- fclose(f);
- chmod(fnamenew,0644);
- /* unlink(fname); */
- rename(fnamenew,fname);
- DEBUG(3,("Wrote browse list %s\n",fname));
-}
+ /* XXXX BUG: if samba is offering WINS support, it should still add the
+ name entry to a local-subnet name database. see rfc1001.txt 15.1.1 p28
+ regarding the point about M-nodes. */
-/*******************************************************************
- expire old names in the namelist and serverlist
- ******************************************************************/
-static void expire_names(void)
-{
- static time_t lastrun=0;
- time_t t = time(NULL);
- struct name_record *n;
- struct name_record *next;
- struct server_record *s;
- struct server_record *nexts;
-
- if (!lastrun) lastrun = t;
- if (t < lastrun + 5) return;
- lastrun = t;
-
- /* expire old names */
- for (n = namelist; n; n = next) {
- if (n->death_time && n->death_time < t) {
- DEBUG(3,("Removing dead name %s\n",
- namestr(&n->name)));
- next = n->next;
- if (n->prev) n->prev->next = n->next;
- if (n->next) n->next->prev = n->prev;
- if (namelist == n) namelist = n->next;
- free(n);
- } else {
- next = n->next;
+ if (ip_equal(d->bcast_ip, wins_ip))
+ {
+ if (lp_wins_support())
+ {
+ /* we are a WINS server. */
+ if(lp_wins_support())
+ {
+ DEBUG(4,("add_my_name_entry: samba as WINS server adding: "));
+ }
+
+ /* this will call add_netbios_entry() */
+ name_register_work(d, name, type, nb_flags,0, ipzero, False);
}
- }
-
- /* 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;
+ else
+ {
+ DEBUG(4,("add_my_name_entry registering name %s with WINS server.\n",
+ name));
+
+ /* a time-to-live allows us to refresh this name with the WINS server. */
+ queue_netbios_pkt_wins(ClientNMB,
+ re_reg ? NMB_REG_REFRESH : NMB_REG, NAME_REGISTER,
+ name, type, nb_flags, GET_TTL(0),0,NULL,NULL,
+ ipzero, ipzero);
}
}
-}
-
-
-/*******************************************************************
- delete old names from the namelist
- ******************************************************************/
-static void housekeeping(void)
-{
- time_t t = time(NULL);
-
- expire_names();
-
- /* write out the browse.dat database for smbd to get */
- if (updatedlists) {
- write_browse_list();
- updatedlists = False;
- }
-
+ else
{
- /* 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;
- }
+ /* broadcast the packet */
+ queue_netbios_packet(d,ClientNMB,
+ re_reg ? NMB_REG_REFRESH : NMB_REG, NAME_REGISTER,
+ name, type, nb_flags, GET_TTL(0),0,NULL,NULL,
+ True, False, d->bcast_ip, ipzero, 0);
}
}
/****************************************************************************
- reload the services file
- **************************************************************************/
-BOOL reload_services(BOOL test)
+ add the internet group <1c> domain logon names by wins unicast and broadcast.
+ ****************************************************************************/
+void add_domain_logon_names(void)
{
- 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;
- }
- }
+ struct subnet_record *d;
- if (test && !lp_file_list_changed())
- return(True);
+ if (!lp_domain_logons()) return;
- ret = lp_load(servicesf,True);
-
- /* perhaps the config filename is now set */
- if (!test)
- reload_services(True);
-
- return(ret);
-}
-
-
-
-/****************************************************************************
-load a netbios hosts file
-****************************************************************************/
-static void load_hosts_file(char *fname)
-{
- FILE *f = fopen(fname,"r");
- pstring line;
- if (!f) {
- DEBUG(2,("Can't open lmhosts file %s\n",fname));
- return;
- }
+ for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
+ {
+ struct work_record *work = find_workgroupstruct(d, myworkgroup, True);
- while (!feof(f))
+ if (work && work->log_state == LOGON_NONE)
{
- if (!fgets_slash(line,sizeof(pstring),f)) continue;
-
- if (*line == '#') continue;
+ struct nmb_name n;
+ make_nmb_name(&n,myworkgroup,0x1c,scope);
+ if (!find_name_on_subnet(d, &n, FIND_SELF_NAME))
{
- 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;
+ /* logon servers are group names. don't expect failure */
- 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);
- }
+ DEBUG(0,("%s attempting to become logon server for %s %s\n",
+ timestring(), myworkgroup, inet_ntoa(d->bcast_ip)));
- ipaddr = *interpret_addr2(ip);
-
- if (group) {
- add_domain_entry(name,ipaddr);
- } else {
- add_host_entry(name,0x20,True,0,source,ipaddr);
- }
+ become_logon_server(d, work);
}
}
-
- fclose(f);
-}
-
-/*******************************************************************
- check if 2 IPs are on the same net
- we will assume the local netmask, although this could be wrong XXXX
- ******************************************************************/
-static BOOL same_net(struct in_addr ip1,struct in_addr ip2)
-{
- unsigned long net1,net2,nmask;
-
- nmask = ntohl(Netmask.s_addr);
- net1 = ntohl(ip1.s_addr);
- net2 = ntohl(ip2.s_addr);
-
- return((net1 & nmask) == (net2 & nmask));
-}
-
-/****************************************************************************
- send an election packet
- **************************************************************************/
-static void send_election(char *group,uint32 criterion,int timeup,char *name)
-{
- pstring outbuf;
- char *p;
-
- DEBUG(2,("Sending election to %s for workgroup %s\n",
- inet_ntoa(bcast_ip),group));
-
- bzero(outbuf,sizeof(outbuf));
- p = outbuf;
- CVAL(p,0) = 8; /* election */
- p++;
-
- CVAL(p,0) = ELECTION_VERSION;
- SIVAL(p,1,criterion);
- SIVAL(p,5,timeup*1000); /* ms - despite the spec */
- p += 13;
- strcpy(p,name);
- strupper(p);
- p = skip_string(p,1);
-
- send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
- name,group,0,0x1e,bcast_ip,myip);
-}
-
-
-/****************************************************************************
- send a backup list response
- **************************************************************************/
-static void send_backup_list(char *name,int token,struct nmb_name *to,
- struct in_addr ip)
-{
- pstring outbuf;
- char *p;
-
- DEBUG(2,("Sending backup list to %s for workgroup %s\n",
- inet_ntoa(ip),PrimaryGroup));
-
- bzero(outbuf,sizeof(outbuf));
- p = outbuf;
- CVAL(p,0) = 10; /* backup list response */
- p++;
-
- CVAL(p,0) = 1; /* count */
- SIVAL(p,1,token);
- p += 5;
- strcpy(p,name);
- strupper(p);
- p = skip_string(p,1) + 1;
-
- send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
- myname,to->name,0,to->name_type,ip,myip);
-}
-
-
-/*******************************************************************
- become the master browser
- ******************************************************************/
-static void become_master(void)
-{
- uint32 domain_type = SV_TYPE_DOMAIN_ENUM | SV_TYPE_SERVER_UNIX;
- DEBUG(2,("Becoming master for %s\n",PrimaryGroup));
-
- ServerType |= SV_TYPE_MASTER_BROWSER;
- ServerType |= SV_TYPE_BACKUP_BROWSER;
- ElectionCriterion |= 0x5;
-
- add_host_entry(PrimaryGroup,0x1d,True,0,SELF,myip);
- add_host_entry(PrimaryGroup,0x0,False,0,SELF,myip);
- add_host_entry(MSBROWSE,1,False,0,SELF,myip);
-
- if (lp_domain_master()) {
- add_host_entry(myname,0x1b,True,0,SELF,myip);
- add_host_entry(PrimaryGroup,0x1b,True,0,SELF,myip);
- add_host_entry(PrimaryGroup,0x1c,False,0,SELF,myip);
- ServerType |= SV_TYPE_DOMAIN_MASTER;
- if (lp_domain_logons()) {
- ServerType |= SV_TYPE_DOMAIN_CTRL;
- ServerType |= SV_TYPE_DOMAIN_MEMBER;
- domain_type |= SV_TYPE_DOMAIN_CTRL;
- }
- }
-
- add_server_entry(PrimaryGroup,domain_type,0,myname,True);
- add_server_entry(myname,ServerType,0,ServerComment,True);
-
- announce_request(PrimaryGroup);
-
- needannounce = True;
-}
-
-
-/*******************************************************************
- unbecome the master browser
- ******************************************************************/
-static void become_nonmaster(void)
-{
- struct name_record *n;
- struct nmb_name nn;
-
- DEBUG(2,("Becoming non-master for %s\n",PrimaryGroup));
-
- ServerType &= ~SV_TYPE_MASTER_BROWSER;
- ServerType &= ~SV_TYPE_DOMAIN_CTRL;
- ServerType &= ~SV_TYPE_DOMAIN_MASTER;
-
- ElectionCriterion &= ~0x4;
-
- make_nmb_name(&nn,PrimaryGroup,0x1d,scope);
- n = find_name(&nn);
- if (n && n->source == SELF) remove_name(n);
-
- make_nmb_name(&nn,PrimaryGroup,0x1b,scope);
- n = find_name(&nn);
- if (n && n->source == SELF) remove_name(n);
-
- make_nmb_name(&nn,MSBROWSE,1,scope);
- n = find_name(&nn);
- if (n && n->source == SELF) remove_name(n);
-}
-
-
-/*******************************************************************
- run the election
- ******************************************************************/
-static void run_election(void)
-{
- time_t t = time(NULL);
- static time_t lastime = 0;
-
- if (!PrimaryGroup[0] || !RunningElection) return;
-
- /* send election packets once a second */
- if (lastime &&
- t-lastime <= 0) return;
-
- lastime = t;
-
- send_election(PrimaryGroup,ElectionCriterion,t-StartupTime,myname);
-
- if (ElectionCount++ < 4) return;
-
- /* I won! now what :-) */
- RunningElection = False;
- DEBUG(2,(">>> Won election on %s <<<\n",PrimaryGroup));
- become_master();
-}
-
-
-/****************************************************************************
- construct a host announcement unicast
- **************************************************************************/
-static void announce_host(struct domain_record *d,char *my_name,char *comment)
-{
- time_t t = time(NULL);
- pstring outbuf;
- char *p;
- char *namep;
- char *stypep;
- char *commentp;
- uint32 stype = ServerType;
-
- if (needannounce) {
- /* drop back to a max 3 minute announce - this is to prevent a
- single lost packet from stuffing things up for too long */
- d->announce_interval = MIN(d->announce_interval,3*60);
- d->lastannounce_time = t - (d->announce_interval+1);
- }
-
- /* announce every minute at first then progress to every 12 mins */
- if (d->lastannounce_time &&
- (t - d->lastannounce_time) < d->announce_interval)
- return;
-
- if (d->announce_interval < 12*60) d->announce_interval += 60;
- d->lastannounce_time = t;
-
- DEBUG(2,("Sending announcement to %s for workgroup %s\n",
- inet_ntoa(d->bcast_ip),d->name));
-
- if (!strequal(PrimaryGroup,d->name) ||
- !ip_equal(bcast_ip,d->bcast_ip)) {
- stype &= ~(SV_TYPE_POTENTIAL_BROWSER | SV_TYPE_MASTER_BROWSER |
- SV_TYPE_DOMAIN_MASTER | SV_TYPE_BACKUP_BROWSER |
- SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_MEMBER);
- }
-
- 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)
-{
- struct dgram_packet *dgram = &p->packet.dgram;
- int update_count = CVAL(buf,0);
- int ttl = IVAL(buf,1)/1000;
- char *name = buf+5;
- int osmajor=CVAL(buf,21);
- int osminor=CVAL(buf,22);
- uint32 servertype = IVAL(buf,23);
- char *comment = buf+31;
-
- name[15] = 0;
- comment[43] = 0;
-
- DEBUG(3,("Announce(%d) %s count=%d ttl=%d OS=(%d,%d) type=%08x comment=%s\n",
- command,name,update_count,ttl,osmajor,osminor,
- servertype,comment));
-
- if (strequal(dgram->source_name.name,myname)) return;
-
- if (!listening(&dgram->dest_name)) return;
-
- ttl = GET_TTL(ttl);
-
- /* add them to our browse list */
- add_server_entry(name,servertype,ttl,comment,True);
-
-}
-
-/*******************************************************************
- process a master announcement frame
- ******************************************************************/
-static void process_master_announce(struct packet_struct *p,char *buf)
-{
- struct dgram_packet *dgram = &p->packet.dgram;
- char *name = buf;
-
- name[15] = 0;
-
- DEBUG(3,("Master Announce from %s (%s)\n",name,inet_ntoa(p->ip)));
-
- if (strequal(dgram->source_name.name,myname)) return;
-
- if (!AM_MASTER || !listening(&dgram->dest_name)) return;
-
- /* merge browse lists with them */
- if (lp_domain_master())
- sync_browse_lists(name,0x20,myname,PrimaryGroup,p->ip);
-}
-
-
-/*******************************************************************
- process a backup list request
-
- A client send a backup list request to ask for a list of servers on
- the net that maintain server lists for a domain. A server is then
- chosen from this list to send NetServerEnum commands to to list
- available servers.
-
- Currently samba only sends back one name in the backup list, its
- wn. For larger nets we'll have to add backups and send "become
- backup" requests occasionally.
- ******************************************************************/
-static void process_backup_list(struct packet_struct *p,char *buf)
-{
- struct dgram_packet *dgram = &p->packet.dgram;
- int count = CVAL(buf,0);
- int token = IVAL(buf,1);
-
- DEBUG(3,("Backup request to %s token=%d\n",
- namestr(&dgram->dest_name),
- token));
-
- if (strequal(dgram->source_name.name,myname)) return;
-
- if (count <= 0) return;
-
- if (!AM_MASTER ||
- !strequal(PrimaryGroup,dgram->dest_name.name))
- return;
-
- if (!listening(&dgram->dest_name)) return;
-
- send_backup_list(myname,token,
- &dgram->source_name,
- p->ip);
-}
-
-
-/*******************************************************************
- work out if I win an election
- ******************************************************************/
-static BOOL win_election(int version,uint32 criterion,int timeup,char *name)
-{
- time_t t = time(NULL);
- uint32 mycriterion;
- if (version > ELECTION_VERSION) return(False);
- if (version < ELECTION_VERSION) return(True);
-
- mycriterion = ElectionCriterion;
-
- if (criterion > mycriterion) return(False);
- if (criterion < mycriterion) return(True);
-
- if (timeup > (t - StartupTime)) return(False);
- if (timeup < (t - StartupTime)) return(True);
-
- if (strcasecmp(myname,name) > 0) return(False);
-
- return(True);
-}
-
-
-/*******************************************************************
- process a election packet
-
- An election dynamically decides who will be the master.
- ******************************************************************/
-static void process_election(struct packet_struct *p,char *buf)
+ add the <1b> domain master names by broadcast.
+ ****************************************************************************/
+void add_domain_master_bcast(void)
{
- 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;
+ struct subnet_record *d;
- name[15] = 0;
-
- DEBUG(3,("Election request from %s vers=%d criterion=%08x timeup=%d\n",
- name,version,criterion,timeup));
+ if (!lp_domain_master()) return;
- if (strequal(dgram->source_name.name,myname)) return;
+ for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
+ {
+ struct work_record *work = find_workgroupstruct(d, myworkgroup, True);
- if (!listening(&dgram->dest_name)) return;
+ if (work && work->dom_state == DOMAIN_NONE)
+ {
+ struct nmb_name n;
+ make_nmb_name(&n,myworkgroup,0x1b,scope);
- 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 (!find_name_on_subnet(d, &n, FIND_SELF_NAME))
+ {
+ DEBUG(0,("%s add_domain_names: attempting to become domain \
+master browser on workgroup %s %s\n", timestring(), myworkgroup, inet_ntoa(d->bcast_ip)));
+
+ /* send out a query to establish whether there's a
+ domain controller on the local subnet. if not,
+ we can become a domain controller. it's only
+ polite that we check, before claiming the
+ NetBIOS name 0x1b.
+ */
+
+ DEBUG(0,("add_domain_names:querying subnet %s \
+for domain master on workgroup %s\n", inet_ntoa(d->bcast_ip), myworkgroup));
+
+ queue_netbios_packet(d,ClientNMB,NMB_QUERY,
+ NAME_QUERY_DOMAIN,
+ myworkgroup, 0x1b,
+ 0, 0,0,NULL,NULL,
+ True, False,
+ d->bcast_ip, d->bcast_ip, 0);
+ }
}
}
}
-/*******************************************************************
- 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)
+ add the <1b> domain master name by wins unicast.
+ ****************************************************************************/
+void add_domain_master_wins(void)
{
- int command = CVAL(buf,0);
- switch (command)
- {
- case 1: /* host announce */
- case 12: /* domain announce */
- case 15: /* local master announce */
- process_announce(p,command,buf+1);
- break;
-
- case 2: /* announce request */
- process_announce_request(p,buf+1);
- break;
-
- case 8: /* election */
- process_election(p,buf+1);
- break;
-
- case 9: /* get backup list */
- process_backup_list(p,buf+1);
- break;
-
- case 13: /* master announcement */
- process_master_announce(p,buf+1);
- break;
- }
-}
+ struct work_record *work;
+ if (!lp_domain_master() || wins_client_subnet == NULL) return;
-/****************************************************************************
- process a domain logon packet
- **************************************************************************/
-static void process_logon_packet(struct packet_struct *p,char *buf,int len)
-{
- char *logname,*q;
- pstring outbuf;
- struct dgram_packet *dgram = &p->packet.dgram;
- int code;
+ work = find_workgroupstruct(wins_client_subnet, myworkgroup, True);
- 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));
+ if (work && work->dom_state == DOMAIN_NONE)
+ {
+ struct nmb_name n;
+ make_nmb_name(&n,myworkgroup,0x1b,scope);
- code = SVAL(buf,0);
- switch (code) {
- case 0:
- {
- char *machine = buf+2;
- char *user = skip_string(machine,1);
- logname = skip_string(user,1);
-
- SSVAL(q,0,6);
- q += 2;
- strcpy(q,"\\\\");
- q += 2;
- StrnCpy(q,myname,16);
- strupper(q);
- q = skip_string(q,1);
- SSVAL(q,0,0xFFFF);
- q += 2;
-
- DEBUG(3,("Domain login request from %s(%s) user=%s\n",
- machine,inet_ntoa(p->ip),user));
- }
- break;
- case 7:
+ if (!find_name_on_subnet(wins_client_subnet, &n, FIND_SELF_NAME))
{
- 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));
+ DEBUG(0,("%s add_domain_names: attempting to become domain \
+master browser on workgroup %s %s\n",
+ timestring(), myworkgroup, inet_ntoa(wins_client_subnet->bcast_ip)));
- 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] != '*');
-}
+ if (lp_wins_support())
+ {
+ /* use the wins server's capabilities (indirectly). if
+ someone has already registered the domain<1b>
+ name with the WINS server, then the WINS
+ server's job is to _check_ that the owner still
+ wants it, before giving it away.
+ */
+ DEBUG(1,("%s initiate become domain master for %s\n",
+ timestring(), myworkgroup));
-/****************************************************************************
- 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);
+ become_domain_master(wins_client_subnet, work);
+ }
+ else
+ {
+ /* send out a query to establish whether there's a
+ domain controller on the WINS subnet. if not,
+ we can become a domain controller. it's only
+ polite that we check, before claiming the
+ NetBIOS name 0x1b.
+ */
+
+ DEBUG(0,("add_domain_names:querying WINS \
+for domain master on workgroup %s\n", myworkgroup));
+
+ queue_netbios_pkt_wins(ClientNMB,NMB_QUERY,
+ NAME_QUERY_DOMAIN,
+ myworkgroup, 0x1b,
+ 0, 0,0,NULL,NULL,
+ ipzero, ipzero);
}
}
-
- 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;
- }
+ add the domain logon server and domain master browser names
- /* 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);
-}
+ this code was written so that several samba servers can co-operate in
+ sharing the task of (one server) being a domain master, and of being
+ domain logon servers.
-/****************************************************************************
- reply to a reg request
**************************************************************************/
-static void reply_name_reg(struct packet_struct *p)
+void add_domain_names(time_t t)
{
- struct nmb_packet *nmb = &p->packet.nmb;
- char *qname = nmb->question.question_name.name;
- BOOL wildcard = (qname[0] == '*');
- BOOL bcast = nmb->header.nm_flags.bcast;
- int ttl = GET_TTL(nmb->additional->ttl);
- int name_type = nmb->question.question_name.name_type;
- int nb_flags = nmb->additional->rdata[0];
- struct packet_struct p2;
- struct nmb_packet *nmb2;
- struct res_rec answer_rec;
- struct in_addr ip;
- BOOL group = (nb_flags&0x80)?True:False;
- int rcode = 0;
-
- if (wildcard) return;
-
- putip((char *)&ip,&nmb->additional->rdata[2]);
-
- if (group) {
- /* apparently we should return 255.255.255.255 for group queries (email from MS) */
- ip = *interpret_addr2("255.255.255.255");
- }
-
- {
- struct name_record *n = find_name(&nmb->question.question_name);
-
- if (n) {
- if (!group && !ip_equal(ip,n->ip)) {
- /* check if the previous owner still wants it,
- if so reject the registration, otherwise change the owner
- and refresh */
- if (n->source != REGISTER || confirm_name(n)) {
- rcode = 6;
- } else {
- n->ip = ip;
- n->death_time = ttl?p->timestamp+ttl*3:0;
- DEBUG(3,("%s changed owner to %s\n",
- namestr(&n->name),inet_ntoa(n->ip)));
- }
- } else {
- /* refresh the name */
- if (n->source != SELF)
- n->death_time = ttl?p->timestamp + ttl*3:0;
- }
- } else {
- /* add the name to our database */
- n = add_host_entry(qname,name_type,!group,ttl,REGISTER,ip);
- }
- }
-
- if (bcast) return;
-
- DEBUG(3,("Name registration for name %s at %s rcode=%d\n",
- namestr(&nmb->question.question_name),
- inet_ntoa(ip),rcode));
-
- /* Send a NAME REGISTRATION RESPONSE */
- /* a lot of fields get copied from the query. This gives us the IP
- and port the reply will be sent to etc */
- p2 = *p;
- nmb2 = &p2.packet.nmb;
-
- nmb2->header.opcode = 5;
- nmb2->header.response = True;
- nmb2->header.nm_flags.bcast = False;
- nmb2->header.nm_flags.recursion_available = CanRecurse;
- nmb2->header.nm_flags.trunc = False;
- nmb2->header.nm_flags.authoritative = True;
- nmb2->header.qdcount = 0;
- nmb2->header.ancount = 1;
- nmb2->header.nscount = 0;
- nmb2->header.arcount = 0;
- nmb2->header.rcode = rcode;
-
- nmb2->answers = &answer_rec;
- bzero((char *)nmb2->answers,sizeof(*nmb2->answers));
-
- nmb2->answers->rr_name = nmb->question.question_name;
- nmb2->answers->rr_type = nmb->question.question_type;
- nmb2->answers->rr_class = nmb->question.question_class;
-
- nmb2->answers->ttl = ttl;
- nmb2->answers->rdlength = 6;
- nmb2->answers->rdata[0] = nb_flags;
- putip(&nmb2->answers->rdata[2],(char *)&ip);
-
- send_packet(&p2);
-}
+ static time_t lastrun = 0;
+ if (lastrun != 0 && t < lastrun + CHECK_TIME_ADD_DOM_NAMES * 60) return;
+ lastrun = t;
-/****************************************************************************
-reply to a name status query
-****************************************************************************/
-static void reply_name_status(struct packet_struct *p)
-{
- struct nmb_packet *nmb = &p->packet.nmb;
- char *qname = nmb->question.question_name.name;
- BOOL wildcard = (qname[0] == '*');
- struct packet_struct p2;
- struct nmb_packet *nmb2;
- struct res_rec answer_rec;
- char *buf;
- int count;
- int rcode = 0;
- struct name_record *n = find_name(&nmb->question.question_name);
-
- DEBUG(3,("Name status for name %s\n",
- namestr(&nmb->question.question_name)));
-
- if (!wildcard && (!n || n->source != SELF))
- return;
-
- /* Send a POSITIVE NAME STATUS RESPONSE */
- /* a lot of fields get copied from the query. This gives us the IP
- and port the reply will be sent to etc */
- p2 = *p;
- nmb2 = &p2.packet.nmb;
-
- nmb2->header.response = True;
- nmb2->header.nm_flags.bcast = False;
- nmb2->header.nm_flags.recursion_available = CanRecurse;
- nmb2->header.nm_flags.trunc = False;
- nmb2->header.nm_flags.authoritative = True; /* WfWg ignores
- non-authoritative answers */
- nmb2->header.qdcount = 0;
- nmb2->header.ancount = 1;
- nmb2->header.nscount = 0;
- nmb2->header.arcount = 0;
- nmb2->header.rcode = rcode;
-
- nmb2->answers = &answer_rec;
- bzero((char *)nmb2->answers,sizeof(*nmb2->answers));
-
-
- nmb2->answers->rr_name = nmb->question.question_name;
- nmb2->answers->rr_type = nmb->question.question_type;
- nmb2->answers->rr_class = nmb->question.question_class;
- nmb2->answers->ttl = 0;
-
- for (count=0, n = namelist ; n; n = n->next) {
- if (n->source != SELF) continue;
- count++;
- }
+ /* do the "internet group" - <1c> names */
+ add_domain_logon_names();
- count = MIN(count,400/18); /* XXXX hack, we should calculate exactly
- how many will fit */
-
-
- buf = &nmb2->answers->rdata[0];
- SCVAL(buf,0,count);
- buf += 1;
-
- for (n = namelist ; n; n = n->next)
- {
- if (n->source != SELF) continue;
-
- bzero(buf,18);
- strcpy(buf,n->name.name);
- strupper(buf);
- buf[15] = n->name.name_type;
- buf += 16;
- buf[0] = 0x4; /* active */
- if (!n->unique) buf[0] |= 0x80; /* group */
- buf += 2;
- count--;
- }
-
- /* XXXXXXX we should fill in more fields of the statistics structure */
- bzero(buf,64);
- {
- extern int num_good_sends,num_good_receives;
- SIVAL(buf,20,num_good_sends);
- SIVAL(buf,24,num_good_receives);
- }
- SIVAL(buf,46,0xFFB8E5); /* undocumented - used by NT */
-
- buf += 64;
+ /* do the domain master names */
+ if (wins_client_subnet != NULL)
+ {
+ /* if the registration of the <1b> name is successful, then
+ add_domain_master_bcast() will be called. this will
+ result in domain logon services being gracefully provided,
+ as opposed to the aggressive nature of 1.9.16p2 to 1.9.16p11.
- nmb2->answers->rdlength = PTR_DIFF(buf,&nmb2->answers->rdata[0]);
+ which, due to a bug in namelogon.c from 1.9.16p2 to 1.9.16p11
+ cannot _provide_ domain master / domain logon services!!!
- send_packet(&p2);
+ */
+ add_domain_master_wins();
+ }
+ else
+ {
+ add_domain_master_bcast();
+ }
}
-
-
/****************************************************************************
-reply to a name query
-****************************************************************************/
-static void reply_name_query(struct packet_struct *p)
+ add the magic samba names, useful for finding samba servers
+ **************************************************************************/
+void add_my_names(void)
{
- struct nmb_packet *nmb = &p->packet.nmb;
- char *qname = nmb->question.question_name.name;
- BOOL wildcard = (qname[0] == '*');
- BOOL bcast = nmb->header.nm_flags.bcast;
- struct in_addr retip;
- int name_type = nmb->question.question_name.name_type;
- struct packet_struct p2;
- struct nmb_packet *nmb2;
- struct res_rec answer_rec;
- int ttl=0;
- int rcode=0;
- BOOL unique = True;
-
- DEBUG(3,("Name query for %s from %s (bcast=%s) - ",
- namestr(&nmb->question.question_name),
- inet_ntoa(p->ip),
- BOOLSTR(bcast)));
-
- if (wildcard)
- retip = myip;
-
- if (!wildcard) {
- struct name_record *n = find_name(&nmb->question.question_name);
-
- if (!n) {
- struct in_addr ip;
- unsigned long a;
-
- /* only do DNS lookups if the query is for type 0x20 or type 0x0 */
- if (name_type != 0x20 && name_type != 0) {
- DEBUG(3,("not found\n"));
- return;
- }
-
- /* look it up with DNS */
- a = interpret_addr(qname);
-
- putip((char *)&ip,(char *)&a);
-
- if (!a) {
- /* no luck with DNS. We could possibly recurse here XXXX */
- /* if this isn't a bcast then we should send a negative reply XXXX */
- DEBUG(3,("no recursion\n"));
- add_host_entry(qname,name_type,True,60*60,DNSFAIL,ip);
- return;
- }
-
- /* add it to our cache of names. give it 2 hours in the cache */
- n = add_host_entry(qname,name_type,True,2*60*60,DNS,ip);
-
- /* failed to add it? yikes! */
- if (!n) return;
- }
-
- /* don't respond to bcast queries for group names unless we own them */
- if (bcast && !n->unique && !n->source == SELF) {
- DEBUG(3,("no bcast replies\n"));
- return;
- }
-
- /* don't respond to bcast queries for addresses on the same net as the
- machine doing the querying unless its our IP */
- if (bcast &&
- n->source != SELF &&
- same_net(n->ip,p->ip)) {
- DEBUG(3,("same net\n"));
- return;
- }
+ struct subnet_record *d;
+ /* each subnet entry, including WINS pseudo-subnet, has SELF names */
- /* is our entry already dead? */
- if (n->death_time) {
- if (n->death_time < p->timestamp) return;
- ttl = n->death_time - p->timestamp;
- }
+ /* XXXX if there was a transport layer added to samba (ipx/spx etc) then
+ there would be yet _another_ for-loop, this time on the transport type
+ */
- retip = n->ip;
- unique = n->unique;
+ for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
+ {
+ int n;
- /* it may have been an earlier failure */
- if (n->source == DNSFAIL) {
- DEBUG(3,("DNSFAIL\n"));
- return;
+ /* Add all our names including aliases. */
+ for (n=0; my_netbios_names[n]; n++)
+ {
+ add_my_name_entry(d, my_netbios_names[n],0x20,nb_type|NB_ACTIVE);
+ add_my_name_entry(d, my_netbios_names[n],0x03,nb_type|NB_ACTIVE);
+ add_my_name_entry(d, my_netbios_names[n],0x00,nb_type|NB_ACTIVE);
}
+
+ /* these names are added permanently (ttl of zero) and will NOT be
+ refreshed with the WINS server */
+ add_netbios_entry(d,"*",0x0,nb_type|NB_ACTIVE,0,SELF,d->myip,False);
+ add_netbios_entry(d,"*",0x20,nb_type|NB_ACTIVE,0,SELF,d->myip,False);
+ add_netbios_entry(d,"__SAMBA__",0x20,nb_type|NB_ACTIVE,0,SELF,d->myip,False);
+ add_netbios_entry(d,"__SAMBA__",0x00,nb_type|NB_ACTIVE,0,SELF,d->myip,False);
}
-
- /* if the IP is 0 then substitute my IP - we should see which one is on the
- right interface for the caller to do this right XXX */
- if (zero_ip(retip)) retip = myip;
-
- DEBUG(3,("OK %s rcode=%d\n",inet_ntoa(retip),rcode));
-
- /* a lot of fields get copied from the query. This gives us the IP
- and port the reply will be sent to etc */
- p2 = *p;
- nmb2 = &p2.packet.nmb;
-
- nmb2->header.response = True;
- nmb2->header.nm_flags.bcast = False;
- nmb2->header.nm_flags.recursion_available = CanRecurse;
- nmb2->header.nm_flags.trunc = False;
- nmb2->header.nm_flags.authoritative = True; /* WfWg ignores
- non-authoritative answers */
- nmb2->header.qdcount = 0;
- nmb2->header.ancount = 1;
- nmb2->header.nscount = 0;
- nmb2->header.arcount = 0;
- nmb2->header.rcode = rcode;
-
- nmb2->answers = &answer_rec;
- bzero((char *)nmb2->answers,sizeof(*nmb2->answers));
-
- nmb2->answers->rr_name = nmb->question.question_name;
- nmb2->answers->rr_type = nmb->question.question_type;
- nmb2->answers->rr_class = nmb->question.question_class;
- nmb2->answers->ttl = ttl;
- nmb2->answers->rdlength = 6;
- nmb2->answers->rdata[0] = unique?0:0x80;
- nmb2->answers->rdata[1] = 0;
- putip(&nmb2->answers->rdata[2],(char *)&retip);
-
- send_packet(&p2);
}
-
-/* the global packet linked-list. incoming entries are added to the
- end of this list. it is supposed to remain fairly short so we
- won't bother with an end pointer. */
-static struct packet_struct *packet_queue = NULL;
-
-
-/*******************************************************************
- queue a packet into the packet queue
- ******************************************************************/
-static void queue_packet(struct packet_struct *packet)
-{
- struct packet_struct *p;
- if (!packet_queue) {
- packet->prev = NULL;
- packet->next = NULL;
- packet_queue = packet;
- return;
- }
-
- /* find the bottom */
- for (p=packet_queue;p->next;p=p->next) ;
-
- p->next = packet;
- packet->next = NULL;
- packet->prev = p;
-}
-
/****************************************************************************
- process a nmb packet
- ****************************************************************************/
-static void process_nmb(struct packet_struct *p)
+ remove all the samba names... from a WINS server if necessary.
+ **************************************************************************/
+void remove_my_names()
{
- struct nmb_packet *nmb = &p->packet.nmb;
+ struct subnet_record *d;
- /* if this is a response then ignore it */
- if (nmb->header.response) return;
-
- switch (nmb->header.opcode)
- {
- case 5:
- case 8:
- case 9:
- if (nmb->header.qdcount>0 &&
- nmb->header.arcount>0) {
- reply_name_reg(p);
- return;
- }
- break;
-
- case 0:
- if (nmb->header.qdcount>0)
+ for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
{
- switch (nmb->question.question_type)
- {
- case 0x20:
- reply_name_query(p);
- break;
-
- case 0x21:
- reply_name_status(p);
- break;
- }
- return;
+ struct name_record *n, *next;
+
+ for (n = d->namelist; n; n = next)
+ {
+ next = n->next;
+ if (n->source == SELF)
+ {
+ /* get all SELF names removed from the WINS server's database */
+ /* XXXX note: problem occurs if this removes the wrong one! */
+
+ remove_name_entry(d,n->name.name, n->name.name_type);
+ }
+ }
}
- break;
-
- case 6:
- if (nmb->header.qdcount>0 &&
- nmb->header.arcount>0) {
- reply_name_release(p);
- return;
- }
- break;
- }
-
}
-
/*******************************************************************
- run elements off the packet queue till its empty
+ refresh my own names
******************************************************************/
-static void run_packet_queue(void)
-{
- 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)
+void refresh_my_names(time_t t)
{
+ struct subnet_record *d;
- while (True)
+ for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
+ {
+ struct name_record *n;
+
+ for (n = d->namelist; n; n = n->next)
{
- fd_set fds;
- int selrtn;
- struct timeval timeout;
-
- if (needelection && PrimaryGroup[0] && !RunningElection) {
- DEBUG(3,(">>> Starting election on %s <<<\n",PrimaryGroup));
- ElectionCount = 0;
- RunningElection = True;
- needelection = False;
- }
-
- FD_ZERO(&fds);
- FD_SET(ClientNMB,&fds);
- FD_SET(ClientDGRAM,&fds);
- /* during elections we need to send election packets at one
- second intervals */
- timeout.tv_sec = RunningElection?1:NMBD_SELECT_LOOP;
- timeout.tv_usec = 0;
-
- selrtn = sys_select(&fds,&timeout);
-
- if (FD_ISSET(ClientNMB,&fds)) {
- struct packet_struct *packet = read_packet(ClientNMB,NMB_PACKET);
- if (packet) queue_packet(packet);
- }
-
- if (FD_ISSET(ClientDGRAM,&fds)) {
- struct packet_struct *packet = read_packet(ClientDGRAM,DGRAM_PACKET);
- if (packet) queue_packet(packet);
+ /* each SELF name has an individual time to be refreshed */
+ if (n->source == SELF && n->refresh_time < t &&
+ n->death_time != 0)
+ {
+ add_my_name_entry(d,n->name.name,n->name.name_type,
+ n->ip_flgs[0].nb_flags);
+ /* they get a new lease on life :-) */
+ n->death_time += GET_TTL(0);
+ n->refresh_time += GET_TTL(0);
}
-
- if (RunningElection)
- run_election();
-
- run_packet_queue();
-
- do_announcements();
-
- housekeeping();
}
-}
-
-
-/****************************************************************************
- open the socket communication
-****************************************************************************/
-static BOOL open_sockets(BOOL isdaemon,int port)
-{
- struct hostent *hp;
-
- /* get host info */
- if ((hp = Get_Hostbyname(myhostname)) == 0)
- {
- DEBUG(0,( "Get_Hostbyname: Unknown host. %s\n",myhostname));
- return False;
- }
-
- if (isdaemon)
- ClientNMB = open_socket_in(SOCK_DGRAM, port,0);
- else
- ClientNMB = 0;
-
- ClientDGRAM = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3);
-
- if (ClientNMB == -1)
- return(False);
-
- signal(SIGPIPE, SIGNAL_CAST sig_pipe);
-
- set_socket_options(ClientNMB,"SO_BROADCAST");
- set_socket_options(ClientDGRAM,"SO_BROADCAST");
-
- DEBUG(3, ("Socket opened.\n"));
- return True;
+ }
}
/*******************************************************************
- check that a IP, bcast and netmask and consistent. Must be a 1s
- broadcast
- ******************************************************************/
-static BOOL ip_consistent(struct in_addr ip,struct in_addr bcast,
- struct in_addr nmask)
-{
- unsigned long a_ip,a_bcast,a_nmask;
+ queries names occasionally. an over-cautious, non-trusting WINS server!
- a_ip = ntohl(ip.s_addr);
- a_bcast = ntohl(bcast.s_addr);
- a_nmask = ntohl(nmask.s_addr);
+ this function has been added because nmbd could be restarted. it
+ is generally a good idea to check all the names that have been
+ reloaded from file.
- /* check the netmask is sane */
- if (((a_nmask>>24)&0xFF) != 0xFF) {
- DEBUG(0,("Insane netmask %s\n",inet_ntoa(nmask)));
- return(False);
- }
-
- /* check the IP and bcast are on the same net */
- if ((a_ip&a_nmask) != (a_bcast&a_nmask)) {
- DEBUG(0,("IP and broadcast are on different nets!\n"));
- return(False);
- }
-
- /* check the IP and bcast are on the same net */
- if ((a_bcast|a_nmask) != 0xFFFFFFFF) {
- DEBUG(0,("Not a ones based broadcast %s\n",inet_ntoa(bcast)));
- return(False);
- }
-
- return(True);
-}
-
-/****************************************************************************
- initialise connect, service and file structs
-****************************************************************************/
-static BOOL init_structs(void )
+ XXXX which names to poll and which not can be refined at a later date.
+ ******************************************************************/
+void query_refresh_names(time_t t)
{
- if (!get_myname(myhostname,got_myip?NULL:&myip))
- return(False);
+ struct name_record *n;
+ struct subnet_record *d = wins_client_subnet;
- /* Read the broadcast address from the interface */
- {
- struct in_addr ip0,ip1,ip2;
+ static time_t lasttime = 0;
- ip0 = myip;
+ int count = 0;
+ int name_refresh_time = NAME_POLL_REFRESH_TIME;
+ int max_count = name_refresh_time * 2 / NAME_POLL_INTERVAL;
+ if (max_count > 10) max_count = 10;
- if (!(got_bcast && got_nmask))
- {
- get_broadcast(&ip0,&ip1,&ip2);
+ name_refresh_time = NAME_POLL_INTERVAL * max_count / 2;
- if (!got_myip)
- myip = ip0;
-
- if (!got_bcast)
- bcast_ip = ip1;
-
- if (!got_nmask)
- Netmask = ip2;
- }
+ /* if (!lp_poll_wins()) return; polling of registered names allowed */
- 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 (!d) return;
- 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 (!lasttime) lasttime = t;
+ if (t - lasttime < NAME_POLL_INTERVAL) return;
- if (! *myname) {
- char *p;
- strcpy(myname,myhostname);
- p = strchr(myname,'.');
- if (p) *p = 0;
- }
+ lasttime = time(NULL);
- {
- extern fstring local_machine;
- strcpy(local_machine,myname);
- strupper(local_machine);
- }
-
- return True;
-}
-
-/****************************************************************************
-usage on the program
-****************************************************************************/
-static void usage(char *pname)
-{
- DEBUG(0,("Incorrect program usage - is the command line correct?\n"));
-
- printf("Usage: %s [-n name] [-B bcast address] [-D] [-p port] [-d debuglevel] [-l log basename]\n",pname);
- printf("Version %s\n",VERSION);
- printf("\t-D become a daemon\n");
- printf("\t-p port listen on the specified port\n");
- printf("\t-d debuglevel set the debuglevel\n");
- printf("\t-l log basename. Basename for log/debug files\n");
- printf("\t-n netbiosname. the netbios name to advertise for this host\n");
- printf("\t-B broadcast address the address to use for broadcasts\n");
- printf("\t-N netmask the netmask to use for subnet determination\n");
- printf("\t-H hosts file load a netbios hosts file\n");
- printf("\t-I ip-address override the IP address\n");
- printf("\t-G group name add a group name to be part of\n");
- printf("\t-C comment sets the machine comment that appears in browse lists\n");
- printf("\n");
+ for (n = d->namelist; n; n = n->next)
+ {
+ /* only do unique, registered names */
+
+ if (n->source != REGISTER) continue;
+ if (!NAME_GROUP(n->ip_flgs[0].nb_flags)) continue;
+
+ if (n->refresh_time < t)
+ {
+ DEBUG(3,("Polling name %s\n", namestr(&n->name)));
+
+ queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_CONFIRM,
+ n->name.name, n->name.name_type,
+ 0,0,0,NULL,NULL,
+ False,False,n->ip_flgs[0].ip,n->ip_flgs[0].ip,
+ 0);
+ count++;
+ }
+
+ if (count >= max_count)
+ {
+ /* don't do too many of these at once, but do enough to
+ cover everyone in the list */
+ return;
+ }
+
+ /* this name will be checked on again, if it's not removed */
+ n->refresh_time += name_refresh_time;
+ }
}
-
-/****************************************************************************
- main program
- **************************************************************************/
-int main(int argc,char *argv[])
-{
- int port = NMB_PORT;
- int opt;
- extern FILE *dbf;
- extern char *optarg;
-
- *host_file = 0;
-
-#if 0
- sleep(10);
-#endif
-
- StartupTime = time(NULL);
-
- TimeInit();
-
- strcpy(debugf,NMBLOGFILE);
-
- setup_logging(argv[0],False);
-
- charset_initialise();
-
-#ifdef LMHOSTSFILE
- strcpy(host_file,LMHOSTSFILE);
-#endif
-
- /* this is for people who can't start the program correctly */
- while (argc > 1 && (*argv[1] != '-'))
- {
- argv++;
- argc--;
- }
-
- fault_setup(fault_continue);
-
- signal(SIGHUP,SIGNAL_CAST sig_hup);
-
- bcast_ip = *interpret_addr2("0.0.0.0");
- myip = *interpret_addr2("0.0.0.0");
-
- while ((opt = getopt (argc, argv, "s:T:I:C:bAi:B:N:Rn:l:d:Dp:hSH:G:")) != EOF)
- switch (opt)
- {
- case 's':
- strcpy(servicesf,optarg);
- break;
- case 'C':
- strcpy(ServerComment,optarg);
- break;
- case 'G':
- add_domain_entry(optarg,bcast_ip);
- break;
- case 'H':
- strcpy(host_file,optarg);
- break;
- case 'I':
- myip = *interpret_addr2(optarg);
- got_myip = True;
- break;
- case 'B':
- bcast_ip = *interpret_addr2(optarg);
- got_bcast = True;
- break;
- case 'N':
- Netmask = *interpret_addr2(optarg);
- got_nmask = True;
- break;
- case 'n':
- strcpy(myname,optarg);
- break;
- case 'l':
- sprintf(debugf,"%s.nmb",optarg);
- break;
- case 'i':
- strcpy(scope,optarg);
- strupper(scope);
- break;
- case 'D':
- is_daemon = True;
- break;
- case 'd':
- DEBUGLEVEL = atoi(optarg);
- break;
- case 'p':
- port = atoi(optarg);
- break;
- case 'h':
- usage(argv[0]);
- exit(0);
- break;
- default:
- if (!is_a_socket(0))
- usage(argv[0]);
- break;
- }
-
- DEBUG(1,("%s netbios nameserver version %s started\n",timestring(),VERSION));
- DEBUG(1,("Copyright Andrew Tridgell 1994\n"));
-
- init_structs();
-
- if (!reload_services(False))
- return(-1);
-
- if (*host_file)
- {
- load_hosts_file(host_file);
- DEBUG(3,("Loaded hosts file\n"));
- }
-
- if (!*ServerComment)
- strcpy(ServerComment,"Samba %v");
- string_sub(ServerComment,"%v",VERSION);
- string_sub(ServerComment,"%h",myhostname);
-
- add_my_names();
-
- DEBUG(3,("Checked names\n"));
-
- dump_names();
-
- DEBUG(3,("Dumped names\n"));
-
- if (!is_daemon && !is_a_socket(0)) {
- DEBUG(0,("standard input is not a socket, assuming -D option\n"));
- is_daemon = True;
- }
-
-
- if (is_daemon) {
- DEBUG(2,("%s becoming a daemon\n",timestring()));
- become_daemon();
- }
-
-
- DEBUG(3,("Opening sockets\n"));
-
- if (open_sockets(is_daemon,port))
- {
- process();
- close_sockets();
- }
-
- if (dbf)
- fclose(dbf);
- return(0);
-}
diff --git a/source/nameserv.doc b/source/nameserv.doc
new file mode 100644
index 00000000000..af4934ade21
--- /dev/null
+++ b/source/nameserv.doc
@@ -0,0 +1,159 @@
+/*
+ Unix SMB/Netbios documentation.
+ Version 0.0
+ Copyright (C) Luke Leighton Andrew Tridgell 1996
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Document name: nameserv.doc
+
+ Revision History:
+
+ 0.0 - 02jul96 : lkcl@pires.co.uk
+ created
+*/
+
+this module deals with general maintenance of NetBIOS names.
+
+/*************************************************************************
+ query_refresh_names()
+ *************************************************************************/
+
+this function is responsible for polling all names registered in the
+WINS database. it is planned to enable this function should samba
+detect an inconsistency on the network, which could occur if the
+samba NetBIOS daemon dies and is restarted.
+
+polling is done very infrequently, but all names will be covered
+within a period NAME_POLL_REFRESH_TIME. a group of at most ten names
+will be queried at once, at intervals of NAME_POLL_INTERVAL seconds.
+if the total number of names queried in this way will take too long,
+then the time that an individual name will next be polled is
+increased accordingly.
+
+name query polling is functionality over-and-above the normal
+requirement (see rfc1001.txt 15.1.7 point 7). it is normally the
+responsibility of the owner of a name to re-register the name at
+regular intervals.
+
+
+/*************************************************************************
+ refresh_my_names()
+ *************************************************************************/
+
+this function is responsible for refreshing samba's names that have
+been registered with other servers on a local subnet, or with another
+WINS server if samba is using one.
+
+samba's names' refresh_time will be updated through the use of the function
+add_my_name_entry().
+
+
+/*************************************************************************
+ remove_my_names()
+ *************************************************************************/
+
+this function is responsible for removing all samba's SELF names. it
+is used when samba receives a SIG_TERM. samba at present does not wait
+for the WINS server to reply to the name releases sent out.
+
+
+/*************************************************************************
+ add_my_names()
+ *************************************************************************/
+
+this function is responsible for adding and registering if necessary all
+samba's SELF names, on each of its local subnets and with another WINS
+server if samba is using one.
+
+/*************************************************************************
+ add_my_name_entry()
+ *************************************************************************/
+
+this function is responsible for registering or re-registering one of
+samba's names, either on the local subnet or with another WINS server
+if samba is using one.
+
+if the name is already in samba's database, then it is re-registered,
+otherwise it is simply registered.
+
+if the name is being registered in a WINS capacity (the subnet to which
+the name should be added is the WINS pseudo-subnet) then we add the entry
+immediately if samba is a WINS server. it uses name_register_work()
+because if the name is being added as part of becoming a master browser,
+we want to carry on that process. if the name is registered with another
+WINS server, we must wait for an answer from that WINS server. either
+name_register_work() or name_unregister_work() will be called as a result.
+
+if the name is being registered on a local subnet, then it is
+broadcast. an explicit rejection from another host will result
+in name_unregister_work() being called. no response will, after
+retrying, result in name_register_work() being called.
+
+what ever method is used, the name will either be registered
+or rejected, and what ever process was taking place (becoming
+a master browser for example) will carry on.
+
+expire_netbios_response_entries() is responsible for taking further
+action if no response to the registration is received.
+
+note that there may be a large number of function calls on the
+stack if become_master() is called and samba is configured as
+a WINS server. the loop will be:
+
+become_master(), add_my_name_entry(), name_register_work() and
+back to become_master() with the new value of the workgroup
+'state'.
+
+
+/*************************************************************************
+ remove_name_entry()
+ *************************************************************************/
+
+this function is responsible for removing a NetBIOS name. if the name
+being removed is registered on a local subnet, a name release should be
+broadcast on the local subnet.
+
+if the name is being released in a WINS capacity (the subnet to
+which the name should be added is the WINS pseudo-subnet) then we
+remove the entry immediately if samba is a WINS server. it uses
+name_unregister_work() because if the name is being added as part of
+becoming a master browser, we want to terminate that process. if the
+name is released from another WINS server, we must wait for an
+answer from that WINS server. name_unregister_work() will
+definitely be called as a result, because at present we ignore
+negative responses for a name release from a WINS server.
+
+if the name is being releasedd on a local subnet, then it is
+broadcast. name_unregister_work() will definitely be called
+because we ignore negative name releases at present.
+
+what ever method is used, the name will be released. (NOT TRUE!
+see response_name_release())
+
+expire_netbios_response_entries() is responsible for taking further action
+if no response to the name release is received.
+
+
+/*************************************************************************
+ load_netbios_names()
+ *************************************************************************/
+
+this function is responsible for loading any NetBIOS names that samba,
+in its WINS capacity, has written out to disk. all the relevant details
+are recorded in this file, including the time-to-live. should the
+time left to live be small, the name is not added back in to samba's
+WINS database.
+
diff --git a/source/nameservreply.c b/source/nameservreply.c
new file mode 100644
index 00000000000..d1cbbb026d5
--- /dev/null
+++ b/source/nameservreply.c
@@ -0,0 +1,685 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Module name: nameservreply.c
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+ 04 jul 96: lkcl@pires.co.uk
+ created module nameservreply containing NetBIOS reply functions
+
+*/
+
+#include "includes.h"
+
+extern int ClientNMB;
+
+extern int DEBUGLEVEL;
+
+extern struct in_addr wins_ip;
+
+/****************************************************************************
+send a registration / release response: pos/neg
+**************************************************************************/
+static void send_name_response(int fd, struct in_addr from_ip,
+ int name_trn_id, int opcode, BOOL success,
+ BOOL recursion_available, BOOL recursion_desired,
+ struct nmb_name *reply_name, int nb_flags, int ttl,
+ struct in_addr ip)
+{
+ char rdata[6];
+ struct packet_struct p;
+
+ int rcode = 0;
+
+ if (success == False)
+ {
+ /* NEGATIVE RESPONSE */
+ rcode = 6;
+ }
+ else if (opcode == NMB_REG && !recursion_available)
+ {
+ /* END-NODE CHALLENGE REGISTRATION RESPONSE */
+ rcode = 0;
+ }
+
+ rdata[0] = nb_flags;
+ rdata[1] = 0;
+ putip(&rdata[2],(char *)&ip);
+
+ p.ip = from_ip;
+ p.port = NMB_PORT;
+ p.fd = fd;
+ p.timestamp = time(NULL);
+ p.packet_type = NMB_PACKET;
+
+ reply_netbios_packet(&p,name_trn_id,
+ rcode,opcode,opcode,
+ recursion_available, recursion_desired,
+ reply_name, 0x20, 0x1,
+ ttl,
+ rdata, 6);
+}
+
+/****************************************************************************
+ add a netbios entry. respond to the (possibly new) owner.
+ **************************************************************************/
+void add_name_respond(struct subnet_record *d, int fd, struct in_addr from_ip,
+ uint16 response_id,
+ struct nmb_name *name,
+ int nb_flags, int ttl, struct in_addr register_ip,
+ BOOL new_owner, struct in_addr reply_to_ip)
+{
+ /* register the old or the new owners' ip */
+ add_netbios_entry(wins_client_subnet,name->name,name->name_type,
+ nb_flags,ttl,REGISTER,register_ip,False);
+
+ /* reply yes or no to the host that requested the name */
+ /* see rfc1002.txt - 4.2.10 and 4.2.11 */
+
+ send_name_response(fd, reply_to_ip, response_id, NMB_REG,
+ new_owner,
+ True, True,
+ name, nb_flags, ttl, reply_to_ip);
+}
+
+
+/****************************************************************************
+reply to a name release
+****************************************************************************/
+void reply_name_release(struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct in_addr ip;
+ int nb_flags = nmb->additional->rdata[0];
+ BOOL bcast = nmb->header.nm_flags.bcast;
+ struct name_record *n;
+ struct subnet_record *d = NULL;
+ BOOL success = False;
+
+ putip((char *)&ip,&nmb->additional->rdata[2]);
+
+ DEBUG(3,("Name release on name %s\n",
+ namestr(&nmb->question.question_name)));
+
+ if(!bcast)
+ d = wins_client_subnet;
+ else
+ d = find_subnet(p->ip);
+
+ if (!d)
+ {
+ DEBUG(3,("response packet: can't match address %s to subnet\n",
+ inet_ntoa(p->ip)));
+ return;
+ }
+
+ n = find_name_on_subnet(d, &nmb->question.question_name, FIND_ANY_NAME);
+
+ /* XXXX under what conditions should we reject the removal?? */
+ /* For now - remove if the names match and the group bit matches. */
+ if (n && (n->source != SELF) && (NAME_GROUP(n->ip_flgs[0].nb_flags) == NAME_GROUP(nb_flags)))
+ {
+ success = True;
+
+ /* If it's a group name not ending in 1c (not an internet name)
+ then just allow it to fade out of existance by timing out. */
+ if(NAME_GROUP(nb_flags) && (n->name.name_type != 0x1c))
+ {
+ DEBUG(5, ("reply_name_release: Allow group name %s(%d) to fade out on \
+subnet %s\n", namestr(&nmb->question.question_name), n->name.name_type,
+ inet_ntoa(d->bcast_ip)));
+ }
+ else
+ {
+ DEBUG(5, ("reply_name_release: Removing name %s on subnet %s\n",
+ namestr(&nmb->question.question_name), inet_ntoa(d->bcast_ip)));
+ remove_name(d,n);
+ n = NULL;
+ }
+ }
+
+ if (bcast) return;
+
+ /* Send a NAME RELEASE RESPONSE (pos/neg) see rfc1002.txt 4.2.10-11 */
+ send_name_response(p->fd,p->ip, nmb->header.name_trn_id, NMB_REL,
+ success, False, False,
+ &nmb->question.question_name, nb_flags, 0, ip);
+}
+
+
+/****************************************************************************
+reply to a reg request
+**************************************************************************/
+void reply_name_reg(struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
+
+ struct nmb_name *reply_name = question;
+
+ char *qname = question->name;
+ int qname_type = question->name_type;
+
+ BOOL bcast = nmb->header.nm_flags.bcast;
+
+ int ttl = GET_TTL(nmb->additional->ttl);
+ int nb_flags = nmb->additional->rdata[0];
+ BOOL group = NAME_GROUP(nb_flags);
+
+ struct subnet_record *d = NULL;
+ struct name_record *n = NULL;
+
+ BOOL success = True;
+ BOOL secured_redirect = False;
+
+ struct in_addr ip, from_ip;
+
+ putip((char *)&from_ip,&nmb->additional->rdata[2]);
+ ip = from_ip;
+
+ DEBUG(3,("Name registration for name %s at %s - ",
+ namestr(question),inet_ntoa(ip)));
+
+ if (group)
+ {
+ /* apparently we should return 255.255.255.255 for group queries
+ (email from MS) */
+ ip = *interpret_addr2("255.255.255.255");
+ }
+
+ if (!bcast)
+ d = wins_client_subnet;
+ else
+ d = find_subnet(p->ip);
+
+ if (!d)
+ {
+ DEBUG(3,("reply_name_reg: can't match address %s to subnet\n",
+ inet_ntoa(p->ip)));
+ return;
+ }
+
+ /* see if the name already exists */
+ n = find_name_on_subnet(d, question, FIND_ANY_NAME);
+
+ if (n)
+ {
+ DEBUG(3,("found\n"));
+ if (!group) /* unique names */
+ {
+ if (n->source == SELF || NAME_GROUP(n->ip_flgs[0].nb_flags))
+ {
+ /* no-one can register one of samba's names, nor can they
+ register a name that's a group name as a unique name */
+
+ success = False;
+ }
+ else if(!ip_equal(ip, n->ip_flgs[0].ip))
+ {
+ /* XXXX rfc1001.txt says:
+ * if we are doing secured WINS, we must send a Wait-Acknowledge
+ * packet (WACK) to the person who wants the name, then do a
+ * name query on the person who currently owns the unique name.
+ * if the current owner still says they own it, the person who wants
+ * the name can't have it. if they do not, or are not alive, they can.
+ */
+
+ secured_redirect = True;
+
+ reply_name = &n->name;
+ }
+ else
+ {
+ n->ip_flgs[0].ip = ip;
+ n->death_time = ttl?p->timestamp+ttl*3:0;
+ DEBUG(3,("%s owner: %s\n",namestr(&n->name),inet_ntoa(n->ip_flgs[0].ip)));
+ }
+ }
+ else
+ {
+ /* refresh the name */
+ if (n->source != SELF)
+ {
+ n->death_time = ttl?p->timestamp + ttl*3:0;
+ }
+ }
+
+ /* XXXX bug reported by terryt@ren.pc.athabascau.ca */
+ /* names that people have checked for and not found get DNSFAILed.
+ we need to update the name record if someone then registers */
+
+ if (n->source == DNSFAIL)
+ n->source = REGISTER;
+
+ }
+ else
+ {
+ DEBUG(3,("not found\n"));
+ /* add the name to our name/subnet, or WINS, database */
+ n = add_netbios_entry(d,qname,qname_type,nb_flags,ttl,REGISTER,ip,True);
+ }
+
+ /* if samba owns a unique name on a subnet, then it must respond and
+ disallow the attempted registration. if the registration is
+ successful by broadcast, only then is there no need to respond
+ (implicit registration: see rfc1001.txt 15.2.1).
+ */
+
+ if (bcast && success) return;
+
+ if (secured_redirect)
+ {
+ char rdata[2];
+
+ /* XXXX i am confused. RSVAL or SSVAL? assume NMB byte ordering */
+ RSSVAL(rdata,0,(nmb->header.opcode&0xf) + ((nb_flags&0xff) << 4));
+
+ /* XXXX mistake in rfc1002.txt? 4.2.16: NULL is 0xa see 4.2.1.3
+ type = 0x0a; see rfc1002.txt 4.2.1.3
+ class = 0x01; see rfc1002.txt 4.2.16
+ */
+
+ /* send WAIT ACKNOWLEDGEMENT see rfc1002.txt 4.2.16 */
+ reply_netbios_packet(p,nmb->header.name_trn_id,
+ 0,NMB_WAIT_ACK,NMB_WAIT_ACK,
+ False,False,
+ reply_name, 0x0a, 0x01,
+ 15*1000, /* 15 seconds long enough to wait? */
+ rdata, 2);
+
+ /* initiate some enquiries to the current owner. */
+ queue_netbios_packet(d,ClientNMB,NMB_QUERY,
+ NAME_REGISTER_CHALLENGE,
+ reply_name->name,reply_name->name_type,
+ nb_flags,0,0,NULL,NULL,
+ False, False,
+ n->ip_flgs[0].ip, p->ip,
+ nmb->header.name_trn_id);
+ }
+ else
+ {
+ /* Send a NAME REGISTRATION RESPONSE (pos/neg) see rfc1002.txt 4.2.5-6
+ or an END-NODE CHALLENGE REGISTRATION RESPONSE see rfc1002.txt 4.2.7
+ */
+
+ send_name_response(p->fd,p->ip, nmb->header.name_trn_id, NMB_REG,
+ success,
+ True, True,
+ reply_name, nb_flags, ttl, ip);
+ }
+}
+
+/* this is used to sort names for a name status into a sensible order
+ we put our own names first, then in alphabetical order */
+static int status_compare(char *n1,char *n2)
+{
+ extern pstring myname;
+ int l1,l2,l3;
+
+ /* its a bit tricky because the names are space padded */
+ for (l1=0;l1<15 && n1[l1] && n1[l1] != ' ';l1++) ;
+ for (l2=0;l2<15 && n2[l2] && n2[l2] != ' ';l2++) ;
+ l3 = strlen(myname);
+
+ if ((l1==l3) && strncmp(n1,myname,l3) == 0 &&
+ (l2!=l3 || strncmp(n2,myname,l3) != 0))
+ return -1;
+
+ if ((l2==l3) && strncmp(n2,myname,l3) == 0 &&
+ (l1!=l3 || strncmp(n1,myname,l3) != 0))
+ return 1;
+
+ return memcmp(n1,n2,18);
+}
+
+
+/****************************************************************************
+ reply to a name status query
+
+ combine the list of the local interface on which the query was made with
+ the names registered via wins.
+ ****************************************************************************/
+void reply_name_status(struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ char *qname = nmb->question.question_name.name;
+ int ques_type = nmb->question.question_name.name_type;
+ char rdata[MAX_DGRAM_SIZE];
+ char *countptr, *buf, *bufend, *buf0;
+ int names_added,i;
+ struct name_record *n;
+ struct subnet_record *d = wins_client_subnet;
+ BOOL bcast = nmb->header.nm_flags.bcast;
+
+ /* This query shoud only be made point to point. */
+ if(bcast)
+ {
+ DEBUG(3,("Name status req: ignoring bcast from %s\n",
+ inet_ntoa(p->ip)));
+ return;
+ }
+
+ if(d == NULL)
+ {
+ /* We are working broadcast only (no wins_client_subnet).
+ Use the first matching subnet. If none matches
+ then return.
+ */
+ if((d = find_subnet(p->ip)) == NULL)
+ {
+ DEBUG(3,("Name status req: can't match address %s to subnet\n",
+ inet_ntoa(p->ip)));
+ return;
+ }
+ }
+
+ DEBUG(3,("Name status for name %s from ip %s\n",
+ namestr(&nmb->question.question_name),
+ inet_ntoa(p->ip)));
+
+ n = find_name_on_subnet(d, &nmb->question.question_name, FIND_SELF_NAME);
+
+ if (!n) return;
+
+ /* XXXX hack, we should calculate exactly how many will fit */
+ bufend = &rdata[MAX_DGRAM_SIZE] - 18;
+ countptr = buf = rdata;
+ buf += 1;
+ buf0 = buf;
+
+ names_added = 0;
+
+ n = d->namelist;
+
+ while (buf < bufend)
+ {
+ if (n->source == SELF)
+ {
+ int name_type = n->name.name_type;
+
+ /* check if we want to exclude other workgroup names
+ from the response. if we don't exclude them, windows clients
+ get confused and will respond with an error for NET VIEW */
+
+ if (!strequal(n->name.name,"*") &&
+ !strequal(n->name.name,"__SAMBA__") &&
+ (name_type < 0x1b || name_type >= 0x20 ||
+ ques_type < 0x1b || ques_type >= 0x20 ||
+ strequal(qname, n->name.name)))
+ {
+ /* start with first bit of putting info in buffer: the name */
+ bzero(buf,18);
+ sprintf(buf,"%-15.15s",n->name.name);
+ strupper(buf);
+
+ /* put name type and netbios flags in buffer */
+ buf[15] = name_type;
+ buf[16] = n->ip_flgs[0].nb_flags;
+
+ buf += 18;
+
+ names_added++;
+ }
+ }
+
+ /* remove duplicate names */
+ qsort(buf0,names_added,18,QSORT_CAST status_compare);
+
+ for (i=1;i<names_added;i++) {
+ if (memcmp(buf0 + 18*i,buf0 + 18*(i-1),16) == 0) {
+ names_added--;
+ if (names_added == i) break;
+ memmove(buf0 + 18*i,buf0 + 18*(i+1),18*(names_added-i));
+ i--;
+ }
+ }
+
+ buf = buf0 + 18*names_added;
+
+ n = n->next;
+
+ if (!n)
+ {
+ /* end of this name list: add wins names too? */
+ struct subnet_record *w_d;
+
+ if (!(w_d = wins_client_subnet)) break;
+
+ if (w_d != d)
+ {
+ d = w_d;
+ n = d->namelist; /* start on the wins name list */
+ }
+ }
+ if (!n) break;
+ }
+
+ SCVAL(countptr,0,names_added);
+
+ /* we don't send any stats as they could be used to attack
+ the protocol */
+ bzero(buf,64);
+
+ buf += 46;
+
+ /* Send a POSITIVE NAME STATUS RESPONSE */
+ reply_netbios_packet(p,nmb->header.name_trn_id,
+ 0,NMB_STATUS,0,False, False,
+ &nmb->question.question_name,
+ 0x21, 0x01,
+ 0, rdata,PTR_DIFF(buf,rdata));
+}
+
+
+/***************************************************************************
+reply to a name query.
+
+with broadcast name queries:
+
+ - only reply if the query is for one of YOUR names. all other machines on
+ the network will be doing the same thing (that is, only replying to a
+ broadcast query if they own it)
+ NOTE: broadcast name queries should only be sent out by a machine
+ if they HAVEN'T been configured to use WINS. this is generally bad news
+ in a wide area tcp/ip network and should be rectified by the systems
+ administrator. USE WINS! :-)
+ - the exception to this is if the query is for a Primary Domain Controller
+ type name (0x1b), in which case, a reply is sent.
+
+ - NEVER send a negative response to a broadcast query. no-one else will!
+
+with directed name queries:
+
+ - if you are the WINS server, you are expected to respond with either
+ a negative response, a positive response, or a wait-for-acknowledgement
+ packet, and then later on a pos/neg response.
+
+****************************************************************************/
+void reply_name_query(struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
+ int name_type = question->name_type;
+
+ BOOL bcast = nmb->header.nm_flags.bcast;
+ BOOL query_is_to_wins_server = (!bcast &&
+ nmb->header.nm_flags.recursion_desired);
+ int ttl=0;
+ int rcode = 0;
+ int nb_flags = 0;
+ struct in_addr retip;
+ char rdata[6];
+ struct subnet_record *d = NULL;
+ BOOL success = True;
+ struct name_record *n = NULL;
+ BOOL acting_as_wins_server = lp_wins_support();
+
+ /* directed queries are for WINS server: broadcasts are local SELF queries.
+ the exception is Domain Master names. */
+
+ if (query_is_to_wins_server)
+ {
+ /* queries to the WINS server involve the WINS server subnet */
+ if (!(d = wins_client_subnet))
+ {
+ DEBUG(3,("name query: wins server query from %s and no wins subnet being used.\n",
+ inet_ntoa(p->ip)));
+ success = False;
+ }
+ }
+ else
+ {
+ /* queries to the WINS client involve, unfortunately, the WINS subnet
+ because it contains WINS client (SELF) entries, as _well_ as WINS
+ server entries. not good.
+ */
+
+ if (!(d = find_subnet_all(p->ip)))
+ {
+ DEBUG(3,("name query: can't match address %s to subnet\n",
+ inet_ntoa(p->ip)));
+ success = False;
+ }
+ }
+
+ DEBUG(3,("Name query from %s for name %s<0x%x>\n",
+ inet_ntoa(p->ip), question->name, question->name_type));
+
+ if (!bcast && (name_type == 0x1d) && lp_wins_support())
+ {
+ /* see WINS manager HELP - 'How WINS Handles Special Names' */
+ /* a WINS query (unicasted) for a 0x1d name must always return False */
+ success = False;
+ }
+
+ if (success)
+ {
+ /* look up the name in the cache */
+ n = find_name_on_subnet(d, question, FIND_ANY_NAME);
+
+ /* check for a previous DNS lookup (these are stored
+ on the wins_client_subnet name list, if it exists */
+
+ if (!n && wins_client_subnet && (d != wins_client_subnet) &&
+ (n = find_name_on_subnet(wins_client_subnet, question, FIND_ANY_NAME))) {
+ if (n->source != DNS && n->source != DNSFAIL) {
+ n = NULL;
+ } else {
+ DEBUG(5,("Found DNS cache entry %s\n", namestr(&n->name)));
+ }
+ }
+
+ /* it is a name that already failed DNS lookup or it's expired */
+ if (n && (n->source == DNSFAIL ||
+ (n->death_time && n->death_time < p->timestamp))) {
+ DEBUG(5,("expired name %s\n", namestr(&n->name)));
+ success = False;
+ }
+
+
+ /* do we want to do dns lookups? */
+ if (success && !n && (lp_dns_proxy() || !bcast)) {
+ BOOL dns_type = (name_type == 0x20 || name_type == 0);
+ if (dns_type && wins_client_subnet) {
+ /* add it to the dns name query queue */
+ if (queue_dns_query(p, question, &n))
+ return;
+ }
+ }
+ }
+
+ if (!n) success = False;
+
+ if (success)
+ {
+ if (bcast && n->source != SELF && name_type != 0x1b)
+ {
+ /* 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 (!lp_wins_proxy() ||
+ same_net(p->ip,n->ip_flgs[0].ip,*iface_nmask(p->ip)))
+ {
+ /* never reply with a negative response to broadcast queries */
+ return;
+ }
+ }
+
+ /* name is directed query, or it's self, or it's a Domain Master type
+ name, or we're replying on behalf of a caller because they are on a
+ different subnet and cannot hear the broadcast. XXXX lp_wins_proxy
+ should be switched off in environments where broadcasts are forwarded
+ */
+
+ /* XXXX note: for proxy servers, we should forward the query on to
+ another WINS server if the name is not in our database, or we are
+ not a WINS server ourselves
+ */
+ ttl = n->death_time ? n->death_time - p->timestamp : GET_TTL(0);
+ retip = n->ip_flgs[0].ip;
+ nb_flags = n->ip_flgs[0].nb_flags;
+ }
+
+ if (!success && bcast) return; /* never reply negative response to bcasts */
+
+ /* if the IP is 0 then substitute my IP */
+ if (zero_ip(retip)) retip = *iface_ip(p->ip);
+
+ /* SPECIAL CASE... If we are a WINS server and the request is explicitly
+ *to* the WINS server and the name type is WORKGROUP<0x1e> we should
+ respond with the local broadcast address 255.255.255.255.
+ */
+ if(!bcast && (name_type == 0x1e) && lp_wins_support())
+ retip = *interpret_addr2("255.255.255.255");
+
+ if (success)
+ {
+ rcode = 0;
+ DEBUG(3,("OK %s\n",inet_ntoa(retip)));
+ }
+ else
+ {
+ rcode = 3;
+ DEBUG(3,("UNKNOWN\n"));
+ }
+
+ if (success)
+ {
+ rdata[0] = nb_flags;
+ rdata[1] = 0;
+ putip(&rdata[2],(char *)&retip);
+ }
+
+ /* see rfc1002.txt 4.2.13 */
+
+ reply_netbios_packet(p,nmb->header.name_trn_id,
+ rcode,NMB_QUERY,0,
+ (query_is_to_wins_server && acting_as_wins_server ?
+ True : False), /* recursion_available flag */
+ True, /* recursion_desired_flag */
+ &nmb->question.question_name,
+ 0x20, 0x01,
+ ttl,
+ rdata, success ? 6 : 0);
+}
diff --git a/source/nameservreply.doc b/source/nameservreply.doc
new file mode 100644
index 00000000000..a5acf8a9c26
--- /dev/null
+++ b/source/nameservreply.doc
@@ -0,0 +1,213 @@
+/*
+ Unix SMB/Netbios documentation.
+ Version 0.0
+ Copyright (C) Luke Leighton Andrew Tridgell 1996
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Document name: nameservreply.doc
+
+ Revision History:
+
+ 0.0 - 02jul96 : lkcl@pires.co.uk
+ created
+*/
+
+/*************************************************************************
+ reply_name_query()
+ *************************************************************************/
+
+this function is responsible for replying to a NetBIOS name query.
+
+there are two kinds of name queries: directed, and broadcast. directed
+queries are usually sent to samba in its WINS capacity. such hosts are
+termed 'point-to-point' hosts. broadcast queries are usually sent from
+'broadcast' or 'mixed' hosts.
+
+broadcasting is used by either older NetBIOS hosts, new NetBIOS hosts that
+have not had WINS capabilities added and new NetBIOS hosts that think the
+WINS server has died.
+
+the samba NetBIOS name database is divided into sections, on a
+per-subnet basis. there is also a WINS NetBIOS name database, and for
+convenience this is added as a pseudo-subnet with the ip address of
+255.255.255.255.
+
+the local subnet NetBIOS name databases only contain samba's names.
+the reason for this is that if a broadcast query is received, a NetBIOS
+hosts is only expected to respond if that query is for one of its own
+names (the exception to this is if a host is configured as a 'proxy'
+server, in which case, samba should redirect the query to another WINS
+server).
+
+the WINS pseudo-subnet NetBIOS database contains all NetBIOS names
+that are not 'special browser' type names (regarding this i am a
+_bit_ confused :-). names of type 0x01, 0x1d and 0x1e i consider to
+be 'special browser' names. at the moment. maybe.
+
+the type of search to be initiated is determined. if the NetBIOS name
+type is a non-special-browser name, then the WINS database is included
+in the search.
+
+if the name is not a special browser name, then we need to find the
+right subnet that the query came from. this is done using
+find_req_subnet(). this also has the benefit of stopping any queries
+from subnets that samba does not know about.
+
+if the query is a broadcast query, then the database of the local subnet
+is included in the search.
+
+the name is then searched for in the appropriate NetBIOS data structures.
+if it is found, then we need to check whether it is appropriate for us
+to reply to such a query.
+
+we will only reply if the query is a directed query, the name belongs to
+samba on that subnet, or the name is a domain master browser type,
+or we're doing replies on behalf of hosts on subnets not known to the
+host issuing the query. in the latter instance, it would be appropriate
+if samba is using a WINS server for it to forward the name query on to
+this WINS server.
+
+reply_name_query() then takes note of all the information that is
+needed to construct a reply to the caller. a negative reply (if the
+name is unknown to samba) or a positive reply (the name is known to
+samba) is then issued.
+
+
+/*************************************************************************
+ reply_name_status()
+ *************************************************************************/
+
+this function is responsible for constructing a reply to a NetBIOS
+name status query. this response contains all samba's NetBIOS names
+on the subnet that the query came in from.
+
+a reply will only be made if the NetBIOS name being queried exists.
+
+see rfc1001.txt and rfc1002.txt for details of the name status reply.
+
+
+/*************************************************************************
+ reply_name_reg()
+ *************************************************************************/
+
+this function is responsible for updating the NetBIOS name database
+from registration packets sent out by hosts wishing to register a
+name, and for informing them, if necessary, if this is acceptable
+or not.
+
+name registration can be done by broadcast or by point-to-point,
+i.e the registration is sent directly to samba in its capacity as
+a WINS server.
+
+if the name registration is done by broadcast (see rfc1001.txt 15.2.1),
+then samba's involvement in replying is limited to whether that name
+is owned by samba or not, on the relevant subnet.
+
+if the name registration is done point-to-point (see rfc1001.txt 15.2.2)
+then samba will first need to check its WINS name database records and
+proceed accordingly.
+
+samba looks for the appropriate subnet record that the registration
+should be added to / checked against, using find_req_subnet().
+
+next, the name is searched for in the local database or the WINS
+database as appropriate.
+
+if the name is not found, then it is added to the NetBIOS name database,
+using add_netbios_entry(), which may choose not to add the name (not
+that this affects the registration of the name on the network in any way).
+it will only add names to the WINS database, and even then it will only
+add non-special-browser type names.
+
+if the name is found, then samba must decide whether to accept the name
+or not. a group name is always added. for unique names, further checks
+need to be carried out.
+
+firstly, if the name in the database is one of samba's names, or if the
+name in the database is a group name, then it cannot be added as a unique
+name belonging to someone else. it is therefore rejected.
+
+secondly, if the ip address of the name being registered does not match
+against the ip in the database, then the unique name may belong to
+someone else. a check needs to be carried out with the owner in case
+they still wish to keep this name. a detailed discussion of what action
+to take is in rfc1001.txt 15.2.2.2 and 15.2.2.3.
+
+samba currently implements non-secured WINS, whereupon the responsibility
+for checking the name is passed on to the host doing the registration.
+rfc1001.txt refers to this as an END-NODE CHALLENGE REGISTRATION RESPONSE.
+(samba itself cannot yet cope with receiving such responses if it
+registers its names with another WINS server).
+
+having decided what kind of response to send (if any - acceptance of
+name registrations by broadcast is implicit), samba will send either a
+positive or negative NAME REGISTRATION RESPONSE, or an END-NODE CHALLENGE
+REGISTRATION RESPONSE to the host that initially sent the registration.
+
+whew.
+
+
+/*************************************************************************
+ reply_name_release()
+ *************************************************************************/
+
+this function is responsible for removing a NetBIOS name from the
+database when a server sends a release packet.
+
+samba looks for the appropriate subnet record that the release should
+be removed from, using find_req_subnet(). next, the name is searched
+for in the local database or the WINS database as appropriate.
+
+if the name is found, it is removed from the database and a
+positive reply is sent confirming this. if the name is not
+found, a negative reply is sent.
+
+a reply is _not_ sent if the release was done by broadcast: the
+release is implicit, and we should be grateful that they bothered
+to tell us. if the release was done by directed packet, then
+we deal with it as a WINS server and must reply (pos / neg).
+
+at present, the criteria for removing a name have yet to be
+developed / experimented with. at present, the only flags that
+are checked are the NetBIOS flags.
+
+
+/*************************************************************************
+ send_name_response()
+ *************************************************************************/
+
+this function is a wrap around reply_netbios_packet(). it sends
+a response to a name registration or release packet, minimising
+the function parameters needed to do this.
+
+if the function is called with the parameter 'success' set to
+True, then a positive response (to the registration or release)
+is made (see rfc1002.txt 4.2.5 and 4.2.10). if this parameter
+is False, then a negative response is issued (see rfc1002.txt
+4.2.6 and 4.2.11)
+
+if the function is called with a registration code, and the
+parameter 'recurse' is False, then an End-Node Challenge
+Registration response is issued (see rfc1002.txt 4.2.7)
+
+note: this function could also easily be used for name conflict
+demand (see rfc1002.txt 4.2.8).
+
+note: End-Node Challenge Registration response is only sent in
+non-secured NetBIOS Name Server implementations. samba now
+implements secured NetBIOS Name Server functionality (see
+rfc1001.txt 15.1.6).
+
diff --git a/source/nameservresp.c b/source/nameservresp.c
new file mode 100644
index 00000000000..3349610da6e
--- /dev/null
+++ b/source/nameservresp.c
@@ -0,0 +1,851 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+ Module name: nameservresp.c
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+ 05 jul 96: lkcl@pires.co.uk
+ created module nameservresp containing NetBIOS response functions
+
+*/
+
+#include "includes.h"
+
+extern int ClientNMB;
+
+extern int DEBUGLEVEL;
+
+extern pstring scope;
+extern fstring myworkgroup;
+extern struct in_addr ipzero;
+extern struct in_addr wins_ip;
+extern struct in_addr ipzero;
+
+
+#define GET_TTL(ttl) ((ttl)?MIN(ttl,lp_max_ttl()):lp_max_ttl())
+
+
+/****************************************************************************
+ response for a reg release received. samba has asked a WINS server if it
+ could release a name.
+ **************************************************************************/
+static void response_name_release(struct nmb_name *ans_name,
+ struct subnet_record *d, struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ char *name = ans_name->name;
+ int type = ans_name->name_type;
+
+ DEBUG(4,("response name release received\n"));
+
+ if (nmb->header.rcode == 0 && nmb->answers && nmb->answers->rdata)
+ {
+ /* IMPORTANT: see expire_netbios_response_entries() */
+
+ struct in_addr found_ip;
+ putip((char*)&found_ip,&nmb->answers->rdata[2]);
+
+ /* NOTE: we only release our own names at present */
+ if (ismyip(found_ip))
+ {
+ name_unregister_work(d,name,type);
+ }
+ else
+ {
+ DEBUG(2,("name release for different ip! %s %s\n",
+ inet_ntoa(found_ip), namestr(ans_name)));
+ }
+ }
+ else
+ {
+ DEBUG(2,("name release for %s rejected!\n", namestr(ans_name)));
+
+ /* XXXX PANIC! what to do if it's one of samba's own names? */
+
+ /* XXXX do we honestly care if our name release was rejected?
+ only if samba is issuing the release on behalf of some out-of-sync
+ server. if it's one of samba's SELF names, we don't care. */
+ }
+}
+
+
+/****************************************************************************
+response for a reg request received
+**************************************************************************/
+static void response_name_reg(struct nmb_name *ans_name,
+ struct subnet_record *d, struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ BOOL bcast = nmb->header.nm_flags.bcast;
+ char *name = ans_name->name;
+ int type = ans_name->name_type;
+
+ DEBUG(4,("response name registration received!\n"));
+
+#if 1
+ /* This code is neccesitated due to bugs in earlier versions of
+ Samba (up to 1.9.16p11). They respond to a broadcast
+ name registration of WORKGROUP<1b> when they should
+ not. Hence, until these versions are gone, we should
+ treat such errors as success for this particular
+ case only. jallison@whistle.com.
+ */
+ if ( ((d != wins_client_subnet) && (nmb->header.rcode == 6) && strequal(myworkgroup, name) &&
+ (type == 0x1b)) ||
+ (nmb->header.rcode == 0 && nmb->answers && nmb->answers->rdata))
+#else
+ if (nmb->header.rcode == 0 && nmb->answers && nmb->answers->rdata)
+#endif
+ {
+ /* IMPORTANT: see expire_netbios_response_entries() */
+
+ int nb_flags = nmb->answers->rdata[0];
+ int ttl = nmb->answers->ttl;
+ struct in_addr found_ip;
+
+ putip((char*)&found_ip,&nmb->answers->rdata[2]);
+
+ name_register_work(d,name,type,nb_flags,ttl,found_ip,bcast);
+ }
+ else
+ {
+ DEBUG(2,("name registration for %s rejected by ip %s!\n",
+ namestr(ans_name), inet_ntoa(p->ip)));
+
+ /* oh dear. we have problems. possibly unbecome a master browser. */
+ name_unregister_work(d,name,type);
+ }
+}
+
+/****************************************************************************
+ response from a name query server check. states of type NAME_QUERY_DOM_SRV_CHK,
+ NAME_QUERY_SRV_CHK, and NAME_QUERY_FIND_MST dealt with here.
+ ****************************************************************************/
+static void response_server_check(struct nmb_name *ans_name,
+ struct response_record *n, struct subnet_record *d, struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct in_addr send_ip;
+ enum state_type cmd;
+
+ /* This next fix was from Bernhard Laeser <nlaesb@ascom.ch>
+ who noticed we were replying directly back to the server
+ we sent to - rather than reading the response.
+ */
+
+ if (nmb->header.rcode == 0 && nmb->answers && nmb->answers->rdata)
+ putip((char*)&send_ip,&nmb->answers->rdata[2]);
+ else
+ {
+
+ DEBUG(2,("response_server_check: name query for %s failed\n",
+ namestr(ans_name)));
+ return;
+ }
+
+ /* issue another state: this time to do a name status check */
+
+ cmd = (n->state == NAME_QUERY_DOM_SRV_CHK) ?
+ NAME_STATUS_DOM_SRV_CHK : NAME_STATUS_SRV_CHK;
+
+ /* initiate a name status check on address given in the reply
+ record. In addition, the workgroup being checked has been stored
+ in the response_record->my_name (see announce_master) we
+ also propagate this into the same field. */
+ queue_netbios_packet(d,ClientNMB,NMB_STATUS, cmd,
+ ans_name->name, ans_name->name_type,
+ 0,0,0,n->my_name,NULL,
+ False,False,send_ip,n->reply_to_ip, 0);
+}
+
+
+/****************************************************************************
+ interpret a node status response. this is pretty hacked: we need two bits of
+ info. a) the name of the workgroup b) the name of the server. it will also
+ add all the names it finds into the namelist.
+****************************************************************************/
+static BOOL interpret_node_status(struct subnet_record *d,
+ char *p, struct nmb_name *name,int t,
+ char *serv_name, struct in_addr ip, BOOL bcast)
+{
+ int numnames = CVAL(p,0);
+ BOOL found = False;
+
+ DEBUG(4,("received %d names\n",numnames));
+
+ p += 1;
+
+ if (serv_name) *serv_name = 0;
+
+ while (numnames--)
+ {
+ char qname[17];
+ int type;
+ fstring flags;
+ int nb_flags;
+
+ BOOL group = False;
+ BOOL add = False;
+
+ *flags = 0;
+
+ StrnCpy(qname,p,15);
+ type = CVAL(p,15);
+ nb_flags = p[16];
+ trim_string(qname,NULL," ");
+
+ p += 18;
+
+ if (NAME_GROUP (nb_flags)) { strcat(flags,"<GROUP> "); group=True;}
+ if (NAME_BFLAG (nb_flags)) { strcat(flags,"B "); }
+ if (NAME_PFLAG (nb_flags)) { strcat(flags,"P "); }
+ if (NAME_MFLAG (nb_flags)) { strcat(flags,"M "); }
+ if (NAME_HFLAG (nb_flags)) { strcat(flags,"H "); }
+ if (NAME_DEREG (nb_flags)) { strcat(flags,"<DEREGISTERING> "); }
+ if (NAME_CONFLICT (nb_flags)) { strcat(flags,"<CONFLICT> "); }
+ if (NAME_ACTIVE (nb_flags)) { strcat(flags,"<ACTIVE> "); add=True; }
+ if (NAME_PERMANENT(nb_flags)) { strcat(flags,"<PERMANENT> "); add=True;}
+
+ /* we want the server name */
+ if (serv_name && !*serv_name && !group && type == 0x20)
+ {
+ 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 || t == 0x20 ) && !group) ||
+ ((t == 0x1c || t == 0x1e ) && group))
+ {
+ found = True;
+ make_nmb_name(name,qname,type,scope);
+ }
+ }
+
+ DEBUG(4,("\t%s(0x%x)\t%s\n",qname,type,flags));
+ }
+ DEBUG(4,("num_good_sends=%d num_good_receives=%d\n",
+ IVAL(p,20),IVAL(p,24)));
+ return found;
+}
+
+
+/****************************************************************************
+ response from a name status check. states of type NAME_STATUS_DOM_SRV_CHK
+ and NAME_STATUS_SRV_CHK dealt with here.
+ ****************************************************************************/
+static void response_name_status_check(struct in_addr ip,
+ struct nmb_packet *nmb, BOOL bcast,
+ struct response_record *n, struct subnet_record *d)
+{
+ /* NMB_STATUS arrives: contains workgroup name and server name required.
+ amongst other things. */
+
+ struct nmb_name name;
+ fstring serv_name;
+
+ if (nmb->answers &&
+ interpret_node_status(d,nmb->answers->rdata,
+ &name,0x20,serv_name,ip,bcast))
+ {
+ if (*serv_name)
+ {
+ /* response_record->my_name contains the
+ workgroup name to sync with. See
+ response_server_check() */
+ sync_server(n->state,serv_name,
+ n->my_name,name.name_type, d, n->send_ip);
+ }
+ }
+ else
+ {
+ DEBUG(1,("No 0x20 name type in interpret_node_status()\n"));
+ }
+}
+
+
+/****************************************************************************
+ response from a name query for secured WINS registration. a state of
+ NAME_REGISTER_CHALLENGE is dealt with here.
+ ****************************************************************************/
+static void response_name_query_register(struct nmb_packet *nmb,
+ struct nmb_name *ans_name,
+ struct response_record *n, struct subnet_record *d)
+{
+ struct in_addr register_ip;
+ BOOL new_owner;
+
+ DEBUG(4, ("Name query at %s ip %s - ",
+ namestr(&n->name), inet_ntoa(n->send_ip)));
+
+ if (!name_equal(&n->name, ans_name))
+ {
+ /* someone gave us the wrong name as a reply. oops. */
+ /* XXXX should say to them 'oi! release that name!' */
+
+ DEBUG(4,("unexpected name received: %s\n", namestr(ans_name)));
+ return;
+ }
+
+ if (nmb->header.rcode == 0 && nmb->answers && nmb->answers->rdata)
+ {
+ /* we had sent out a name query to the current owner
+ of a name because someone else wanted it. now they
+ have responded saying that they still want the name,
+ so the other host can't have it.
+ */
+
+ /* first check all the details are correct */
+
+ int nb_flags = nmb->answers->rdata[0];
+ struct in_addr found_ip;
+
+ putip((char*)&found_ip,&nmb->answers->rdata[2]);
+
+ if (nb_flags != n->nb_flags)
+ {
+ /* someone gave us the wrong nb_flags as a reply. oops. */
+ /* XXXX should say to them 'oi! release that name!' */
+
+ DEBUG(4,("expected nb_flags: %d\n", n->nb_flags));
+ DEBUG(4,("unexpected nb_flags: %d\n", nb_flags));
+ return;
+ }
+
+ if (!ip_equal(n->send_ip, found_ip))
+ {
+ /* someone gave us the wrong ip as a reply. oops. */
+ /* XXXX should say to them 'oi! release that name!' */
+
+ DEBUG(4,("expected ip: %s\n", inet_ntoa(n->send_ip)));
+ DEBUG(4,("unexpected ip: %s\n", inet_ntoa(found_ip)));
+ return;
+ }
+
+ DEBUG(4, (" OK: %s\n", inet_ntoa(found_ip)));
+
+ /* fine: now tell the other host they can't have the name */
+ register_ip = n->send_ip;
+ new_owner = False;
+ }
+ else
+ {
+ DEBUG(4, (" NEGATIVE RESPONSE!\n"));
+
+ /* the owner didn't want the name: the other host can have it */
+ register_ip = n->reply_to_ip;
+ new_owner = True;
+ }
+
+ /* register the old or the new owners' ip */
+ add_name_respond(d, n->fd, d->myip, n->reply_id,&n->name,n->nb_flags,
+ GET_TTL(0), register_ip,
+ new_owner, n->reply_to_ip);
+
+ remove_response_record(d,n); /* remove the response record */
+}
+
+
+/****************************************************************************
+ response from a name query to sync browse lists or to update our netbios
+ entry. states of type NAME_QUERY_SYNC and NAME_QUERY_CONFIRM
+ ****************************************************************************/
+static void response_name_query_sync(struct nmb_packet *nmb,
+ struct nmb_name *ans_name, BOOL bcast,
+ struct response_record *n, struct subnet_record *d)
+{
+ DEBUG(4, ("Name query at %s ip %s - ",
+ namestr(&n->name), inet_ntoa(n->send_ip)));
+
+ if (!name_equal(&n->name, ans_name))
+ {
+ /* someone gave us the wrong name as a reply. oops. */
+ DEBUG(4,("unexpected name received: %s\n", namestr(ans_name)));
+ return;
+ }
+
+ if (nmb->header.rcode == 0 && nmb->answers && nmb->answers->rdata)
+ {
+ int nb_flags = nmb->answers->rdata[0];
+ struct in_addr found_ip;
+
+ putip((char*)&found_ip,&nmb->answers->rdata[2]);
+
+ if (!ip_equal(n->send_ip, found_ip))
+ {
+ /* someone gave us the wrong ip as a reply. oops. */
+ DEBUG(4,("expected ip: %s\n", inet_ntoa(n->send_ip)));
+ DEBUG(4,("unexpected ip: %s\n", inet_ntoa(found_ip)));
+ return;
+ }
+
+ DEBUG(4, (" OK: %s\n", inet_ntoa(found_ip)));
+
+ if (n->state == NAME_QUERY_SYNC_LOCAL ||
+ n->state == NAME_QUERY_SYNC_REMOTE)
+ {
+ struct work_record *work = NULL;
+ /* We cheat here as we know that the workgroup name has
+ been placed in the my_comment field of the
+ response_record struct by the code in
+ start_sync_browse_entry().
+ */
+ if ((work = find_workgroupstruct(d, n->my_comment, False)))
+ {
+ BOOL local_list_only = n->state == NAME_QUERY_SYNC_LOCAL;
+
+ /* the server is there: sync quick before it (possibly) dies! */
+ sync_browse_lists(d, work, ans_name->name, ans_name->name_type,
+ found_ip, local_list_only);
+ }
+ }
+ else
+ {
+ struct subnet_record *add_rec = (!bcast) ? wins_client_subnet : d;
+
+ /* update our netbios name list (re-register it if necessary) */
+ add_netbios_entry(add_rec, ans_name->name, ans_name->name_type,
+ nb_flags,GET_TTL(0),REGISTER,
+ found_ip,False);
+ }
+ }
+ else
+ {
+ DEBUG(4, (" NEGATIVE RESPONSE!\n"));
+
+ if (n->state == NAME_QUERY_CONFIRM)
+ {
+ /* XXXX remove_netbios_entry()? */
+ /* lots of things we ought to do, here. if we get here,
+ then we're in a mess: our name database doesn't match
+ reality. sort it out
+ */
+ remove_netbios_name(d,n->name.name, n->name.name_type, REGISTER);
+ }
+ }
+}
+
+/****************************************************************************
+ response from a name query for DOMAIN<1b>
+ NAME_QUERY_DOMAIN is dealt with here - we are trying to become a domain
+ master browser and WINS replied - check it's our address.
+ ****************************************************************************/
+static void response_name_query_domain(struct nmb_name *ans_name,
+ struct nmb_packet *nmb,
+ struct response_record *n, struct subnet_record *d)
+{
+ DEBUG(4, ("response_name_query_domain: Got %s response from %s for query \
+for %s\n", nmb->header.rcode == 0 ? "success" : "failure",
+ inet_ntoa(n->send_ip), namestr(ans_name)));
+
+ /* Check the name is correct and ip address returned is our own. If it is then we
+ just remove the response record.
+ */
+ if (name_equal(&n->name, ans_name) && (nmb->header.rcode == 0) && nmb->answers && (nmb->answers->rdata))
+ {
+ struct in_addr found_ip;
+
+ putip((char*)&found_ip,&nmb->answers->rdata[2]);
+ /* Samba 1.9.16p11 servers seem to return the broadcast address for this
+ query. */
+ if (ismyip(found_ip) || ip_equal(wins_ip, found_ip) || ip_equal(ipzero, found_ip))
+ {
+ DEBUG(4, ("response_name_query_domain: WINS server returned our ip \
+address. Pretending we never received response.\n"));
+ n->num_msgs = 0;
+ n->repeat_count = 0;
+ n->repeat_time = 0;
+ }
+ else
+ {
+ DEBUG(0,("response_name_query_domain: WINS server already has a \
+domain master browser registered %s at address %s\n",
+ namestr(ans_name), inet_ntoa(found_ip)));
+ }
+ }
+ else
+ {
+ /* Negative/incorrect response. No domain master
+ browser was registered - pretend we didn't get this response.
+ */
+ n->num_msgs = 0;
+ n->repeat_count = 0;
+ n->repeat_time = 0;
+ }
+
+}
+
+/****************************************************************************
+ report the response record type
+ ****************************************************************************/
+static void debug_rr_type(int rr_type)
+{
+ switch (rr_type)
+ {
+ case NMB_STATUS: DEBUG(3,("Name status ")); break;
+ case NMB_QUERY : DEBUG(3,("Name query ")); break;
+ case NMB_REG : DEBUG(3,("Name registration ")); break;
+ case NMB_REL : DEBUG(3,("Name release ")); break;
+ default : DEBUG(1,("wrong response packet type received")); break;
+ }
+}
+
+/****************************************************************************
+ report the response record nmbd state
+ ****************************************************************************/
+void debug_state_type(int state)
+{
+ /* report the state type to help debugging */
+ switch (state)
+ {
+ case NAME_QUERY_DOM_SRV_CHK : DEBUG(4,("NAME_QUERY_DOM_SRV_CHK\n")); break;
+ case NAME_QUERY_SRV_CHK : DEBUG(4,("NAME_QUERY_SRV_CHK\n")); break;
+ case NAME_QUERY_FIND_MST : DEBUG(4,("NAME_QUERY_FIND_MST\n")); break;
+ case NAME_QUERY_MST_CHK : DEBUG(4,("NAME_QUERY_MST_CHK\n")); break;
+ case NAME_QUERY_CONFIRM : DEBUG(4,("NAME_QUERY_CONFIRM\n")); break;
+ case NAME_QUERY_SYNC_LOCAL : DEBUG(4,("NAME_QUERY_SYNC_LOCAL\n")); break;
+ case NAME_QUERY_SYNC_REMOTE : DEBUG(4,("NAME_QUERY_SYNC_REMOTE\n")); break;
+ case NAME_QUERY_DOMAIN : DEBUG(4,("NAME_QUERY_DOMAIN\n")); break;
+
+ case NAME_REGISTER : DEBUG(4,("NAME_REGISTER\n")); break;
+ case NAME_REGISTER_CHALLENGE : DEBUG(4,("NAME_REGISTER_CHALLENGE\n"));break;
+
+ case NAME_RELEASE : DEBUG(4,("NAME_RELEASE\n")); break;
+
+ case NAME_STATUS_DOM_SRV_CHK : DEBUG(4,("NAME_STATUS_DOM_SRV_CHK\n")); break;
+ case NAME_STATUS_SRV_CHK : DEBUG(4,("NAME_STATUS_SRV_CHK\n")); break;
+
+ default: break;
+ }
+}
+
+/****************************************************************************
+ report any problems with the fact that a response has been received.
+
+ (responses for certain types of operations are only expected from one host)
+ ****************************************************************************/
+static BOOL response_problem_check(struct response_record *n,
+ struct nmb_packet *nmb, char *ans_name)
+{
+ switch (nmb->answers->rr_type)
+ {
+ case NMB_REL:
+ {
+ if (n->num_msgs > 1)
+ {
+ DEBUG(1,("more than one release name response received!\n"));
+ return True;
+ }
+ break;
+ }
+
+ case NMB_REG:
+ {
+ if (n->num_msgs > 1)
+ {
+ DEBUG(1,("more than one register name response received!\n"));
+ return True;
+ }
+ break;
+ }
+
+ case NMB_QUERY:
+ {
+ if (n->num_msgs > 1)
+ {
+ if (nmb->header.rcode == 0 && nmb->answers && nmb->answers->rdata)
+ {
+ int nb_flags = nmb->answers->rdata[0];
+
+ if ((!NAME_GROUP(nb_flags)))
+ {
+ /* oh dear. more than one person responded to a
+ unique name.
+ there is either a network problem, a
+ configuration problem
+ or a server is mis-behaving */
+
+ /* XXXX mark the name as in conflict, and then let the
+ person who just responded know that they
+ must also mark it
+ as in conflict, and therefore must NOT use it.
+ see rfc1001.txt 15.1.3.5 */
+
+ /* this may cause problems for some
+ early versions of nmbd */
+
+ switch (n->state)
+ {
+ case NAME_QUERY_FIND_MST:
+ {
+ /* query for ^1^2__MSBROWSE__^2^1 expect
+ lots of responses */
+ return False;
+ }
+ case NAME_QUERY_DOM_SRV_CHK:
+ case NAME_QUERY_SRV_CHK:
+ case NAME_QUERY_MST_CHK:
+ {
+ if (!strequal(ans_name,n->name.name))
+ {
+ /* one subnet, one master browser
+ per workgroup */
+ /* XXXX force an election? */
+
+ DEBUG(3,("more than one master browser replied!\n"));
+ return True;
+ }
+ break;
+ }
+ default: break;
+ }
+ DEBUG(3,("Unique Name conflict detected!\n"));
+ return True;
+ }
+ }
+ else
+ {
+ /* we have received a negative reply,
+ having already received
+ at least one response (pos/neg).
+ something's really wrong! */
+
+ DEBUG(3,("wierd name query problem detected!\n"));
+ return True;
+ }
+ }
+ }
+ }
+ return False;
+}
+
+#if 0
+/****************************************************************************
+ check that the response received is compatible with the response record
+ ****************************************************************************/
+static BOOL response_compatible(struct response_record *n,
+ struct nmb_packet *nmb)
+{
+ switch (n->state)
+ {
+ case NAME_RELEASE:
+ {
+ if (nmb->answers->rr_type != 0x20)
+ {
+ DEBUG(1,("Name release reply has wrong answer rr_type\n"));
+ return False;
+ }
+ break;
+ }
+
+ case NAME_REGISTER:
+ {
+ if (nmb->answers->rr_type != 0x20)
+ {
+ DEBUG(1,("Name register reply has wrong answer rr_type\n"));
+ return False;
+ }
+ break;
+ }
+
+ case NAME_REGISTER_CHALLENGE: /* this is a query: we then do a register */
+ case NAME_QUERY_CONFIRM:
+ case NAME_QUERY_SYNC_LOCAL:
+ case NAME_QUERY_SYNC_REMOTE:
+ case NAME_QUERY_DOM_SRV_CHK:
+ case NAME_QUERY_SRV_CHK:
+ case NAME_QUERY_FIND_MST:
+ case NAME_QUERY_MST_CHK:
+ {
+ if (nmb->answers->rr_type != 0x20)
+ {
+ DEBUG(1,("Name query reply has wrong answer rr_type\n"));
+ return False;
+ }
+ break;
+ }
+
+ case NAME_STATUS_DOM_SRV_CHK:
+ case NAME_STATUS_SRV_CHK:
+ {
+ if (nmb->answers->rr_type != 0x21)
+ {
+ DEBUG(1,("Name status reply has wrong answer rr_type\n"));
+ return False;
+ }
+ break;
+ }
+
+ default:
+ {
+ DEBUG(1,("unknown state type received in response_netbios_packet\n"));
+ return False;
+ }
+ }
+ return True;
+}
+#endif
+
+
+/****************************************************************************
+ process the response packet received
+ ****************************************************************************/
+static void response_process(struct subnet_record *d, struct packet_struct *p,
+ struct response_record *n, struct nmb_packet *nmb,
+ BOOL bcast, struct nmb_name *ans_name)
+{
+ switch (n->state)
+ {
+ case NAME_RELEASE:
+ {
+ response_name_release(ans_name, d, p);
+ break;
+ }
+
+ case NAME_REGISTER:
+ {
+ response_name_reg(ans_name, d, p);
+ break;
+ }
+
+ case NAME_REGISTER_CHALLENGE:
+ {
+ response_name_query_register(nmb, ans_name, n, d);
+ break;
+ }
+
+ case NAME_QUERY_DOM_SRV_CHK:
+ case NAME_QUERY_SRV_CHK:
+ case NAME_QUERY_FIND_MST:
+ {
+ response_server_check(ans_name, n, d, p);
+ break;
+ }
+
+ case NAME_STATUS_DOM_SRV_CHK:
+ case NAME_STATUS_SRV_CHK:
+ {
+ response_name_status_check(p->ip, nmb, bcast, n, d);
+ break;
+ }
+
+ case NAME_QUERY_CONFIRM:
+ case NAME_QUERY_SYNC_LOCAL:
+ case NAME_QUERY_SYNC_REMOTE:
+ {
+ response_name_query_sync(nmb, ans_name, bcast, n, d);
+ break;
+ }
+ case NAME_QUERY_MST_CHK:
+ {
+ /* no action required here. it's when NO responses are received
+ that we need to do something. see expire_name_query_entries() */
+
+ DEBUG(4, ("Master browser exists for %s at %s (just checking!)\n",
+ namestr(&n->name), inet_ntoa(n->send_ip)));
+ break;
+ }
+
+ case NAME_QUERY_DOMAIN:
+ {
+ /* We were asking to be a domain master browser, and someone
+ replied. If it was the WINS server and the IP it is
+ returning is our own - then remove the record and pretend
+ we didn't get a response. Else we do nothing and let
+ dead_netbios_entry deal with it.
+ We can only become domain master browser
+ when no broadcast responses are received and WINS
+ either contains no entry for the DOMAIN<1b> name or
+ contains our IP address.
+ */
+ response_name_query_domain(ans_name, nmb, n, d);
+ break;
+ }
+ default:
+ {
+ DEBUG(1,("unknown state type received in response_netbios_packet\n"));
+ break;
+ }
+ }
+}
+
+
+/****************************************************************************
+ response from a netbios packet.
+ ****************************************************************************/
+void response_netbios_packet(struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *ans_name = NULL;
+ BOOL bcast = nmb->header.nm_flags.bcast;
+ struct response_record *n;
+ struct subnet_record *d = NULL;
+
+ if (!(n = find_response_record(&d,nmb->header.name_trn_id))) {
+ DEBUG(2,("unknown netbios response id %d (received late or from nmblookup?)\n",
+ nmb->header.name_trn_id));
+ return;
+ }
+
+ if (!d)
+ {
+ DEBUG(2,("response packet: subnet %s not known\n", inet_ntoa(p->ip)));
+ return;
+ }
+
+ /* args wrong way round: spotted by ccm@shentel.net */
+ if (!same_net(d->bcast_ip, p->ip, d->mask_ip)) /* copes with WINS 'subnet' */
+ {
+ DEBUG(2,("response from %s. ", inet_ntoa(p->ip)));
+ DEBUG(2,("expected on subnet %s. hmm.\n", inet_ntoa(d->bcast_ip)));
+ }
+
+ if (nmb->answers == NULL) {
+ /* if there is no name is the response then the name is the one
+ we queried on */
+ ans_name = &n->name;
+ } else {
+ ans_name = &nmb->answers->rr_name;
+ debug_rr_type(nmb->answers->rr_type);
+ }
+
+ DEBUG(3,("response for %s from %s(%d) (bcast=%s)\n",
+ namestr(ans_name), inet_ntoa(p->ip), p->port, BOOLSTR(bcast)));
+
+ n->num_msgs++; /* count number of responses received */
+ n->repeat_count = 0; /* don't resend: see expire_netbios_packets() */
+
+ debug_state_type(n->state);
+
+ /* problem checking: multiple responses etc */
+ if (nmb->answers && response_problem_check(n, nmb, ans_name->name))
+ return;
+
+ /* now deal with the current state */
+ response_process(d, p, n, nmb, bcast, ans_name);
+}
diff --git a/source/nameservresp.doc b/source/nameservresp.doc
new file mode 100644
index 00000000000..635db45084f
--- /dev/null
+++ b/source/nameservresp.doc
@@ -0,0 +1,191 @@
+/*
+ Unix SMB/Netbios documentation.
+ Version 0.0
+ Copyright (C) Luke Leighton Andrew Tridgell 1996
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Document name: nameservresp.doc
+
+ Revision History:
+
+ 0.0 - 02jul96 : lkcl@pires.co.uk
+ created
+*/
+
+this module deals with the receipt of response packets. the
+response packets are expected to be received, and there is a
+record of this kept (see also: modules nameresp and namedbresp)
+
+point of interest to design purists: every function in this
+module is static except response_netbios_packet().
+
+/*************************************************************************
+ response_netbios_packet()
+ *************************************************************************/
+
+this function receives netbios response packets. the samba server
+(or a rogue tcp/ip system, or nmblookup) will have sent out a packet
+requesting a response. a client (or a rogue tcp/ip system) responds
+to that request.
+
+this function checks the validity of the packet it receives.
+the expected response records are searched for the transaction id,
+to see if it's a response expected by the samba server. if it isn't
+it's reported as such, and ignored.
+
+if the response is found, then the subnet it was expected from will
+also have been found. the subnet it actually came in on can be
+checked against the subnet it was expected from and reported,
+otherwise this function just carries on.
+
+the number of responses received is increased, and the number of
+retries left to be sent is set to zero.
+
+after debug information is reported, and validation of the netbios
+packet (e.g only one response from one machine is expected for some
+functions) has occurred, the packet is processed. when the initial
+request was sent out, the expected response record was flagged with,
+for lack of a better word, a samba 'state' type. whenever a
+response is received, the appropriate function is called to carry on
+where the program control flow was interrupted while awaiting exactly
+such a response.
+
+please note that _not_ receiving a response is dealt with in another
+area of code - expire_netbios_response_entries().
+
+
+/*************************************************************************
+ response_name_query_sync()
+ *************************************************************************/
+
+this function receives responses to samba 'states' NAME_QUERY_SYNC and
+NAME_QUERY_CONFIRM.
+
+NAME_QUERY_SYNC: name query a server before synchronising browse lists.
+NAME_QUERY_CONFIRM: name query a server to check that it's alive.
+
+a NAME_QUERY_SYNC will be carried out in order to check that a server
+is alive before syncing browse lists. we don't want to delay the SMB
+NetServerEnum api just because the server has gone down: we have too
+much else to do.
+
+a NAME_QUERY_CONFIRM is just a name query to see whether the server is
+alive. these queries are sent out by samba's WINS server side, to verify
+its netbios name database of all machines that have registered with it.
+
+we don't normally expect a negative response from such a query, although
+we may do so if the query was sent to another WINS server. the registered
+entry should be removed if we receive a negative response.
+
+
+/*************************************************************************
+ response_name_status_check()
+ *************************************************************************/
+
+this function receives responses to samba 'states' NAME_STATUS_SRV_CHK
+and NAME_STATUS_DOM_SRV_CHK
+
+NAME_STATUS_DOM_SRV_CHK: name status a domain master browser
+ confirm its domain and then initiate syncing
+ its browse list.
+
+NAME_STATUS_SRV_CHK: same as NAME_STATUS_DOM_SRV_CHK except the
+ name status is issued to a master browser.
+
+if we don't know what workgroup a server is responsible for, but we
+know that there is a master browser at a certain ip, we can issue a
+name status check. from the response received, there will be
+a master browser netbios entry. this will allow us to synchronise
+browse lists with that machine and then add the information to the
+correct part of samba's workgroup - server database.
+
+
+/*************************************************************************
+ response_server_check()
+ *************************************************************************/
+
+this function receives responses to samba 'states' NAME_QUERY_DOM_SRV_CHK,
+NAME_QUERY_SRV_CHK and NAME_QUERY_FIND_MST.
+
+NAME_QUERY_FIND_MST: issued as a broadcast when we wish to find out all
+ master browsers (i.e all servers that have registered
+ the NetBIOS name ^1^2__MSBROWSE__^2(0x1), and then
+ issue a NAME_STATUS_MASTER_CHECK on any servers that
+ respond, which will initiate a sync browse lists.
+
+NAME_QUERY_DOM_SRV_CHK: same as a NAME_QUERY_FIND_MST except this is sent
+ to a domain master browser.
+
+NAME_QUERY_SRV_CHK: same as a NAME_QUERY_DOM_SRV_CHK except this is sent to
+ a master browser.
+
+the purpose of each of these states is to do a broadcast name query, or
+a name query directed at a WINS server, then to all hosts that respond,
+we issue a name status check, which will confirm for us the workgroup
+or domain name, and then initiate issuing a sync browse list call with
+that server.
+
+a NAME_QUERY_SRV_CHK is sent when samba receives a list of backup
+browsers. it checks to see if that server is alive (by doing a
+name query on a server) and then syncs browse lists with it.
+
+
+/*************************************************************************
+ response_name_reg()
+ *************************************************************************/
+
+this function is responsible for dealing with samba's registration
+attempts, by broadcast to a local subnet, or point-to-point with
+another WINS server.
+
+please note that it cannot cope with END-NODE CHALLENGE REGISTRATION
+RESPONSEs at present.
+
+when a response is received, samba determines if the response is a
+positive or a negative one. if it is a positive response, the name
+is added to samba's database.
+
+when a negative response is received, samba will remove the name
+from its database. if, however, the name is a browser type (0x1b is
+a domain master browser type name; or 0x1d, which is a local master
+browser type name) then it must also stop being a domain master
+browser or master browser respectively, depending on what kind
+of name was rejected.
+
+(when no response is received, then expire_netbios_response_entries()
+is expected to deal with this. the only case that is dealt with here
+at present is when the registration was done by broadcast. if there
+is no challenge to the broadcast registration, it is implicitly
+assumed that claiming the name is acceptable).
+
+
+/*************************************************************************
+ response_name_release()
+ *************************************************************************/
+
+this function is responsible for removing samba's NetBIOS name when
+samba contacts another WINS server with which it had registered the
+name.
+
+only positive name releases are expected and dealt with. exactly what
+to do if a negative name release (i.e someone says 'oi! you have to
+keep that name!') is received is uncertain.
+
+(when no response is received, then expire_netbios_response_entries()
+is expected to deal with this. if there is no challenge to the release
+of the name, the name is then removed from that subnet's NetBIOS
+name database).
+
diff --git a/source/namework.c b/source/namework.c
new file mode 100644
index 00000000000..540aec5bfea
--- /dev/null
+++ b/source/namework.c
@@ -0,0 +1,724 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+*/
+
+#include "includes.h"
+
+extern int ClientNMB;
+extern int ClientDGRAM;
+
+#define TEST_CODE /* want to debug unknown browse packets */
+
+extern int DEBUGLEVEL;
+extern pstring scope;
+extern BOOL CanRecurse;
+
+extern pstring myname;
+extern fstring myworkgroup;
+
+extern int ClientNMB;
+extern int ClientDGRAM;
+
+extern struct in_addr ipzero;
+
+extern int workgroup_count; /* total number of workgroups we know about */
+
+/* this is our domain/workgroup/server database */
+extern struct subnet_record *subnetlist;
+
+extern int updatecount;
+
+/* backup request types: which servers are to be included */
+#define MASTER_TYPE (SV_TYPE_MASTER_BROWSER)
+#define DOMCTL_TYPE (SV_TYPE_DOMAIN_CTRL )
+
+extern time_t StartupTime;
+
+extern BOOL updatedlists;
+
+/****************************************************************************
+tell a server to become a backup browser
+state - 0x01 become backup instead of master
+ - 0x02 remove all entries in browse list and become non-master
+ - 0x04 stop master browser service altogether. NT ignores this
+**************************************************************************/
+void reset_server(char *name, int state, struct in_addr ip)
+{
+ char outbuf[20];
+ char *p;
+
+ bzero(outbuf,sizeof(outbuf));
+ p = outbuf;
+
+ CVAL(p,0) = ANN_ResetBrowserState;
+ CVAL(p,2) = state;
+ p += 2;
+
+ DEBUG(2,("sending reset to %s %s of state %d\n",
+ name,inet_ntoa(ip),state));
+
+ send_mailslot_reply(False,BROWSE_MAILSLOT,ClientDGRAM,
+ outbuf,PTR_DIFF(p,outbuf),
+ myname,name,0x20,0x1d,ip,*iface_ip(ip));
+}
+
+
+/****************************************************************************
+tell a server to become a backup browser
+**************************************************************************/
+void tell_become_backup(void)
+{
+ /* XXXX note: this function is currently unsuitable for use, as it
+ does not properly check that a server is in a fit state to become
+ a backup browser before asking it to be one.
+ */
+
+ struct subnet_record *d;
+ for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
+ {
+ 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 (is_myname(s->serv.name)) continue;
+
+ if (s->serv.type & SV_TYPE_BACKUP_BROWSER) {
+ num_backups++;
+ continue;
+ }
+
+ if (s->serv.type & SV_TYPE_MASTER_BROWSER) continue;
+
+ if (!(s->serv.type & SV_TYPE_POTENTIAL_BROWSER)) continue;
+
+ DEBUG(3,("num servers: %d num backups: %d\n",
+ num_servers, num_backups));
+
+ /* make first server a backup server. thereafter make every
+ tenth server a backup server */
+ if (num_backups != 0 && (num_servers+9) / num_backups > 10)
+ {
+ continue;
+ }
+
+ DEBUG(2,("sending become backup to %s %s for %s\n",
+ s->serv.name, inet_ntoa(d->bcast_ip),
+ work->work_group));
+
+ /* type 11 request from MYNAME(20) to WG(1e) for SERVER */
+ do_announce_request(s->serv.name, work->work_group,
+ ANN_BecomeBackup, 0x20, 0x1e, d->bcast_ip);
+ }
+ }
+ }
+}
+
+
+/*******************************************************************
+ same context: scope. should check name_type as well, and makes sure
+ we don't process messages from ourselves
+ ******************************************************************/
+BOOL same_context(struct dgram_packet *dgram)
+{
+ if (!strequal(dgram->dest_name .scope,scope )) return(True);
+ if ( is_myname(dgram->source_name.name)) 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_localnet_announce(struct packet_struct *p,uint16 command,char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ struct subnet_record *d = find_subnet(p->ip); /* Explicitly exclude WINS - local nets only */
+ int update_count = CVAL(buf,0);
+
+ int ttl = IVAL(buf,1)/1000;
+ char *name = buf+5;
+ int osmajor=CVAL(buf,21);
+ int osminor=CVAL(buf,22);
+ uint32 servertype = IVAL(buf,23);
+ uint32 browse_type= CVAL(buf,27);
+ uint32 browse_sig = CVAL(buf,29);
+ char *comment = buf+31;
+
+ struct work_record *work;
+ char *work_name;
+ char *serv_name = dgram->source_name.name;
+ BOOL add = False;
+
+ comment[43] = 0;
+
+ DEBUG(4,("Announce(%d) %s(%x)",command,name,name[15]));
+ DEBUG(4,("%s count=%d ttl=%d OS=(%d,%d) type=%08x sig=%4x %4x comment=%s\n",
+ namestr(&dgram->dest_name),update_count,ttl,osmajor,osminor,
+ servertype,browse_type,browse_sig,comment));
+
+ name[15] = 0;
+
+ if (dgram->dest_name.name_type == 0 && command == ANN_HostAnnouncement)
+ {
+ DEBUG(2,("Announce to nametype(0) not supported yet\n"));
+ return;
+ }
+
+ if (command == ANN_DomainAnnouncement &&
+ ((!strequal(dgram->dest_name.name, MSBROWSE)) ||
+ dgram->dest_name.name_type != 0x1))
+ {
+ DEBUG(0,("Announce(%d) from %s should be __MSBROWSE__(1) not %s\n",
+ command, inet_ntoa(p->ip), namestr(&dgram->dest_name)));
+ return;
+ }
+
+ if (!strequal(dgram->dest_name.scope,scope )) return;
+
+ if (command == ANN_DomainAnnouncement) {
+ /* XXXX if we are a master browser for the workgroup work_name,
+ then there is a local subnet configuration problem. only
+ we should be sending out such domain announcements, because
+ as the master browser, that is our job.
+
+ stop being a master browser, and force an election. this will
+ sort out the network problem. hopefully.
+ */
+
+ work_name = name;
+ add = True;
+ } else {
+ work_name = dgram->dest_name.name;
+ }
+
+ /* we need some way of finding out about new workgroups
+ that appear to be sending packets to us. The name_type checks make
+ sure we don't add host names as workgroups */
+ if (command == ANN_HostAnnouncement &&
+ (dgram->dest_name.name_type == 0x1d ||
+ dgram->dest_name.name_type == 0x1e))
+ add = True;
+
+ DEBUG(4,("search for workgroup: %s (add? %s)\n",
+ work_name, BOOLSTR(add)));
+
+ if (!(work = find_workgroupstruct(d, work_name,add)))
+ return;
+
+ DEBUG(4, ("workgroup %s on %s\n", work->work_group, serv_name));
+
+ ttl = GET_TTL(ttl);
+
+ /* add them to our browse list, and update the browse.dat file */
+ add_server_entry(d,work,name,servertype|SV_TYPE_LOCAL_LIST_ONLY,ttl,comment,True);
+ updatedlists = True;
+
+#if 0
+ /* the tell become backup code is broken, no great harm is done by
+ disabling it */
+ tell_become_backup();
+#endif
+}
+
+/*******************************************************************
+ process a master announcement frame
+ Domain master browsers recieve these from local masters. The Domain
+ master should then issue a sync with the local master, asking for
+ that machines local server list.
+ ******************************************************************/
+static void process_master_announce(struct packet_struct *p,char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ char *name = buf;
+ struct work_record *work;
+ name[15] = 0;
+
+ DEBUG(3,("process_master_announce: Master Announce from %s (%s)\n",name,inet_ntoa(p->ip)));
+
+ if (same_context(dgram)) return;
+
+ if (!wins_client_subnet)
+ {
+ DEBUG(3,("process_master_announce: No wins subnet !\n"));
+ return;
+ }
+
+ if (!lp_domain_master())
+ {
+ DEBUG(3,("process_master_announce: Not configured as domain master - ignoring master announce.\n"));
+ return;
+ }
+
+ for (work = wins_client_subnet->workgrouplist; work; work = work->next)
+ {
+ if (AM_MASTER(work) || AM_DOMMST(work))
+ {
+ /* merge browse lists with them */
+ add_browser_entry(name,0x1d, work->work_group,30,wins_client_subnet,p->ip,True);
+ }
+ }
+}
+
+/*******************************************************************
+ process a receive backup list request
+
+ we receive a list of servers, and we attempt to locate them all on
+ our local subnet, and sync browse lists with them on the workgroup
+ they are said to be in.
+
+ XXXX NOTE: this function is in overdrive. it should not really do
+ half of what it actually does (it should pick _one_ name from the
+ list received and sync with it at regular intervals, rather than
+ sync with them all only once!)
+
+ ******************************************************************/
+static void process_rcv_backup_list(struct packet_struct *p,char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ int count = CVAL(buf,0);
+ uint32 info = IVAL(buf,1); /* XXXX caller's incremental info */
+ char *buf1;
+
+ DEBUG(3,("Receive Backup ack for %s from %s total=%d info=%d\n",
+ namestr(&dgram->dest_name), inet_ntoa(p->ip),
+ count, info));
+
+ if (same_context(dgram)) return;
+
+ if (count <= 0) return;
+
+ /* go through the list of servers attempting to sync browse lists */
+ for (buf1 = buf+5; *buf1 && count; buf1 = skip_string(buf1, 1), --count)
+ {
+ struct in_addr back_ip;
+ /* struct subnet_record *d; */
+
+ DEBUG(4,("Searching for backup browser %s at %s...\n",
+ buf1, inet_ntoa(p->ip)));
+
+ /* XXXX assume name is a DNS name NOT a netbios name. a more complete
+ approach is to use reply_name_query functionality to find the name */
+
+ back_ip = *interpret_addr2(buf1);
+
+ if (zero_ip(back_ip))
+ {
+ DEBUG(4,("Failed to find backup browser server using DNS\n"));
+ continue;
+ }
+
+ DEBUG(4,("Found browser server at %s\n", inet_ntoa(back_ip)));
+ DEBUG(4,("END THIS LOOP: CODE NEEDS UPDATING\n"));
+
+#if 0
+ /* XXXX function needs work */
+ continue;
+
+ if ((d = find_subnet(back_ip)))
+ {
+ struct subnet_record *d1;
+ for (d1 = subnetlist; d1; d1 = d1->next)
+ {
+ struct work_record *work;
+ for (work = d1->workgrouplist; work; work = work->next)
+ {
+ if (work->token == 0 /* token */)
+ {
+ queue_netbios_packet(d1,ClientNMB,NMB_QUERY,NAME_QUERY_SRV_CHK,
+ work->work_group,0x1d,
+ 0,0,0,NULL,NULL,
+ False,False,back_ip,back_ip,
+ 0);
+ return;
+ }
+ }
+ }
+ }
+#endif
+ }
+}
+
+
+/****************************************************************************
+ send a backup list response.
+ **************************************************************************/
+static void send_backup_list(char *work_name, struct nmb_name *src_name,
+ int token, uint32 info,
+ int name_type, struct in_addr ip)
+{
+ char outbuf[1024];
+ char *p, *countptr, *nameptr;
+ int count = 0;
+ char *theirname = src_name->name;
+
+ DEBUG(3,("sending backup list of %s to %s: %s(%x) %s(%x)\n",
+ work_name, inet_ntoa(ip),
+ myname,0x0,theirname,0x0));
+
+ if (name_type == 0x1d)
+ {
+ DEBUG(4,("master browsers: "));
+ }
+ else if (name_type == 0x1b)
+ {
+ DEBUG(4,("domain controllers: "));
+ }
+ else
+ {
+ DEBUG(0,("backup request for unknown type %0x\n", name_type));
+ return;
+ }
+
+ bzero(outbuf,sizeof(outbuf));
+ p = outbuf;
+
+ CVAL(p,0) = ANN_GetBackupListResp; /* backup list response */
+
+ p++;
+ countptr = p;
+
+ SIVAL(p,1,info); /* the sender's unique info */
+
+ p += 5;
+
+ nameptr = p;
+
+#if 0
+
+ for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
+ {
+ struct work_record *work;
+
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ struct server_record *s;
+
+ if (!strequal(work->work_group, work_name)) continue;
+
+ for (s = work->serverlist; s; s = s->next)
+ {
+ BOOL found = False;
+ char *n;
+
+ if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue;
+
+ for (n = nameptr; n < p; n = skip_string(n, 1))
+ {
+ if (strequal(n, s->serv.name)) found = True;
+ }
+
+ if (found) continue; /* exclude names already added */
+
+ /* workgroup request: include all backup browsers in the list */
+ /* domain request: include all domain members in the list */
+
+ if ((name_type == 0x1d && (s->serv.type & MASTER_TYPE)) ||
+ (name_type == 0x1b && (s->serv.type & DOMCTL_TYPE)))
+ {
+ DEBUG(4, ("%s ", s->serv.name));
+
+ count++;
+ strcpy(p,s->serv.name);
+ strupper(p);
+ p = skip_string(p,1);
+ }
+ }
+ }
+ }
+
+#endif
+
+ count++;
+ strcpy(p,myname);
+ strupper(p);
+ p = skip_string(p,1);
+
+ if (count == 0)
+ {
+ DEBUG(4, ("none\n"));
+ }
+ else
+ {
+ DEBUG(4, (" - count %d\n", count));
+ }
+
+ CVAL(countptr, 0) = count;
+
+ {
+ int len = PTR_DIFF(p, outbuf);
+ debug_browse_data(outbuf, len);
+ }
+ send_mailslot_reply(False,BROWSE_MAILSLOT,ClientDGRAM,
+ outbuf,PTR_DIFF(p,outbuf),
+ myname,theirname,0x0,0x0,ip,*iface_ip(ip));
+}
+
+
+/*******************************************************************
+ process a send backup list request
+
+ A client sends a backup list request to ask for a list of servers on
+ the net that maintain server lists for a domain. A server is then
+ chosen from this list to send NetServerEnum commands to to list
+ available servers.
+
+ Currently samba only sends back one name in the backup list, its
+ own. For larger nets we'll have to add backups and send "become
+ backup" requests occasionally.
+ ******************************************************************/
+static void process_send_backup_list(struct packet_struct *p,char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ struct in_addr ip = dgram->header.source_ip;
+ struct subnet_record *d;
+ struct work_record *work;
+
+ int token = CVAL(buf,0); /* sender's key index for the workgroup */
+ uint32 info = IVAL(buf,1); /* XXXX don't know: some sort of info */
+ int name_type = dgram->dest_name.name_type;
+
+ if (same_context(dgram)) return;
+
+ if (name_type != 0x1b && name_type != 0x1d) {
+ DEBUG(0,("backup request to wrong type %d from %s\n",
+ name_type,inet_ntoa(ip)));
+ return;
+ }
+
+ for (d = subnetlist; d; d = d->next)
+ {
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ if (strequal(work->work_group, dgram->dest_name.name))
+ {
+ DEBUG(2,("sending backup list to %s %s id=%x\n",
+ namestr(&dgram->dest_name),inet_ntoa(ip),info));
+
+ send_backup_list(work->work_group,&dgram->source_name,
+ token,info,name_type,ip);
+ return;
+ }
+ }
+ }
+}
+
+
+/*******************************************************************
+ process a reset browser state
+
+ diagnostic packet:
+ 0x1 - stop being a master browser and become a backup browser.
+ 0x2 - discard browse lists, stop being a master browser, try again.
+ 0x4 - stop being a master browser forever. no way. ain't gonna.
+
+ ******************************************************************/
+static void process_reset_browser(struct packet_struct *p,char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ int state = CVAL(buf,0);
+
+ DEBUG(1,("received diagnostic browser reset request to %s state=0x%X\n",
+ namestr(&dgram->dest_name), state));
+
+ /* stop being a master but still deal with being a backup browser */
+ if (state & 0x1)
+ {
+ struct subnet_record *d;
+ for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
+ {
+ struct work_record *work;
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ if (AM_MASTER(work))
+ {
+ unbecome_local_master(d,work,SV_TYPE_MASTER_BROWSER);
+ }
+ }
+ }
+ }
+
+ /* XXXX documentation inconsistency: the above description does not
+ exactly tally with what is implemented for state & 0x2
+ */
+
+ /* totally delete all servers and start afresh */
+ if (state & 0x2)
+ {
+ struct subnet_record *d;
+ for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
+ {
+ struct work_record *work;
+ for (work=d->workgrouplist;work;work=remove_workgroup(d,work,True));
+ }
+ add_my_subnets(myworkgroup);
+ }
+
+ /* stop browsing altogether. i don't think this is a good idea! */
+ if (state & 0x4)
+ {
+ DEBUG(1,("ignoring request to stop being a browser. sorry!\n"));
+ }
+}
+
+/*******************************************************************
+ process a announcement request
+
+ clients send these when they want everyone to send an announcement
+ immediately. This can cause quite a storm of packets!
+ ******************************************************************/
+static void process_announce_request(struct packet_struct *p,char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ struct work_record *work;
+ struct in_addr ip = dgram->header.source_ip;
+ struct subnet_record *d = find_subnet(ip); /* Explicitly NO WINS */
+ int token = CVAL(buf,0);
+ char *name = buf+1;
+
+ name[15] = 0;
+
+ DEBUG(3,("process_announce_request: Announce request from %s to %s token=0x%X\n",
+ name,namestr(&dgram->dest_name), token));
+
+ if (is_myname(dgram->source_name.name)) return;
+
+ /* XXXX BUG or FEATURE?: need to ensure that we are a member of
+ this workgroup before announcing, particularly as we only
+ respond on local interfaces anyway.
+
+ if (strequal(dgram->dest_name, myworkgroup) return; ???
+ */
+
+ if (!d)
+ {
+ DEBUG(3,("process_announce_request: No local interface to announce to %s\n",
+ name));
+ return;
+ }
+
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ /* XXXX BUG: the destination name type should also be checked,
+ not just the name. e.g if the name is WORKGROUP(0x1d) then
+ we should only respond if we own that name */
+
+ if (strequal(dgram->dest_name.name,work->work_group))
+ {
+ work->needannounce = True;
+ }
+ }
+}
+
+
+
+/****************************************************************************
+process a browse frame
+****************************************************************************/
+void process_browse_packet(struct packet_struct *p,char *buf,int len)
+{
+ int command = CVAL(buf,0);
+ switch (command)
+ {
+ case ANN_HostAnnouncement:
+ case ANN_DomainAnnouncement:
+ case ANN_LocalMasterAnnouncement:
+ {
+ debug_browse_data(buf, len);
+ process_localnet_announce(p,command,buf+1);
+ break;
+ }
+
+ case ANN_AnnouncementRequest:
+ {
+ process_announce_request(p,buf+1);
+ break;
+ }
+
+ case ANN_Election:
+ {
+ process_election(p,buf+1);
+ break;
+ }
+
+ case ANN_GetBackupListReq:
+ {
+ debug_browse_data(buf, len);
+ process_send_backup_list(p,buf+1);
+ break;
+ }
+
+ case ANN_GetBackupListResp:
+ {
+ debug_browse_data(buf, len);
+ process_rcv_backup_list(p, buf+1);
+ break;
+ }
+
+ case ANN_ResetBrowserState:
+ {
+ process_reset_browser(p, buf+1);
+ break;
+ }
+
+ case ANN_MasterAnnouncement:
+ {
+ process_master_announce(p,buf+1);
+ break;
+ }
+
+ default:
+ {
+ struct dgram_packet *dgram = &p->packet.dgram;
+ DEBUG(4,("ignoring browse packet %d from %s %s to %s\n",
+ command, namestr(&dgram->source_name),
+ inet_ntoa(p->ip), namestr(&dgram->dest_name)));
+ }
+ }
+}
+
+
diff --git a/source/namework.doc b/source/namework.doc
new file mode 100644
index 00000000000..958a86c8668
--- /dev/null
+++ b/source/namework.doc
@@ -0,0 +1,363 @@
+/*
+ Unix SMB/Netbios documentation.
+ Version 0.1
+ Copyright (C) Luke Leighton Andrew Tridgell 1996
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Document name: namework.doc
+
+ Revision History:
+
+ 0.0 - 02jul96 : lkcl@pires.co.uk
+ created
+
+ 0.1 - 22jul96 Andrew.Tridgell@anu.edu.au
+ tridge's comments on first revision
+*/
+
+the module namework.c deals with NetBIOS datagram packets, primarily.
+it deals with nmbd's workgroup browser side and the domain log in
+side. none of the functionality here has specification documents available.
+empirical observation of packet traces has been the order of the day,
+along with some guess-work.
+
+beware!
+
+the receipt of datagram packets for workgroup browsing are dealt with here.
+some of the functions listed here will call others outside of this
+module, or will activate functionality dealt with by other modules
+(namedb, nameannounce, nameelect, namelogon, and namebrowse).
+
+
+/*************************************************************************
+ process_browse_packet()
+ *************************************************************************/
+
+this function is responsible for further identifying which type of
+browser datagram packet has been received, and dealing with it
+accordingly. if the packet is not dealt with, then an error is
+logged along with the type of packet that has been received.
+
+if listening_type() was in use, then it would be used here.
+
+the types of packets received and dealt with are:
+
+- ANN_HostAnnouncement
+- ANN_DomainAnnouncement
+- ANN_LocalMasterAnnouncement
+
+these are all identical in format and can all be processed by
+process_announce(). an announcement is received from a host
+(either a master browser telling us about itself, a server
+telling us about itself or a master browser telling us about
+a domain / workgroup)
+
+- ANN_AnnouncementRequest
+
+these are sent by master browsers or by servers. it is a
+request to announce ourselves as appropriate by sending
+either a ANN_HostAnnouncement datagram or both an
+ANN_DomainAnnouncement and an ANN_LocalMasterAnnouncement
+if we are a master browser (but not both).
+
+- ANN_Election
+
+this is an election datagram. if samba has been configured
+as a domain master then it will also send out election
+datagrams.
+
+- ANN_GetBackupListReq
+
+this is a request from another server for us to send a
+backup list of all servers that we know about. we respond
+by sending a datagram ANN_GetBackupListResp. the protocol
+here is a little dicey.
+
+- ANN_GetBackupListResp
+
+this is a response from another server that we have sent an
+ANN_GetBackupListReq to. the protocol is a little dicey.
+
+- ANN_BecomeBackup
+
+this is a message sent by a master browser to a
+potential master browser, indicating that it should become
+a backup master browser for the workgroup it is a member
+of. samba does not respond at present to such datagrams,
+and it also sends out such datagrams for the wrong reasons
+(this code has now been disabled until this is fixed).
+
+- ANN_ResetBrowserState
+
+this datagram is sent for trouble-shooting purposes.
+it asks a browser to clear out its server lists, or to
+stop becoming a master browser altogether. NT/AS and
+samba do not implement this latter option.
+
+- ANN_MasterAnnouncement
+
+this datagram is sent by a master browser to a domain master
+browser. it is a way to ensure that master browsers are kept in sync
+with a domain master browser across a wide area network. on
+receipt of an ANN_MasterAnnouncement we should sync browse lists with
+the sender.
+
+(i never got the hang of this one when i was experimenting.
+i forget exactly what it's for, and i never fully worked
+out how to coax a server to send it. :-)
+
+NOTE FROM TRIDGE: The reason you didn't work out how to coax a server
+into sending it is that you can't (or shouldn't try!). Basically these
+"master announce" datagrams are the way that separate netbios subnets
+are linked together to form a complete browse net. The way it works is
+that the local master decides it is going to inform the domain master
+of its presence, then sends this master announce to the domain
+master. The domain master then syncs with the local master using a
+"local only" sync. The whole transaction is initiated by the local
+master, not the domain master, so the domain master should not do any
+of this if it does not first receive a "master announcement". The
+local domain masters need to be configured to know the IP address of
+the domain master.
+
+
+/*************************************************************************
+ listening_type()
+ *************************************************************************/
+
+
+a datagram packet is sent from one NetBIOS name of a specific type
+to another NetBIOS name of a specific type. certain types of
+datagrams are only expected from certain types of NetBIOS names.
+
+this function is intended to catch errors in the type of datagrams
+received from different NetBIOS names. it is currently incomplete
+due to lack of information on the types of names and the datagrams
+they send.
+
+
+/*************************************************************************
+ process_announce_request()
+ *************************************************************************/
+
+this function is responsible for dealing with announcement requests.
+if the type of name that the request is sent to matches our current
+status, then we should respond. otherwise, the datagram should be
+ignored.
+
+samba only responds on its local subnets.
+
+at present, just the name is checked to see if the packet is for us.
+what should be done is that if we own the name (e.g WORGROUP(0x1d)
+or WORKGROUP(0x1b) then we should respond, otherwise, ignore the
+datagram.
+
+if the name is for us, and we are a member of that workgroup, then
+samba should respond.
+
+note that samba does not respond immediately. this is to ensure that
+if the master browser for the workgroup that samba is a member of
+sends out a broadcast request announcement, that that master browser
+is not swamped with replies. it is therefore up to samba to reply
+at some random interval. hence, a flag is set indicating the need
+to announce later.
+
+
+/*************************************************************************
+ process_reset_browser()
+ *************************************************************************/
+
+this function is responsible for dealing with reset state datagrams.
+there are three kinds of diagnostic reset requests:
+
+- stop being a master browser
+- discard browse lists, stop being a master browser, and run for re-election
+- stop being a master browser forever.
+
+samba and windows nt do not implement the latter option.
+
+there appears to be a discrepancy between this description and the
+code actually implemented.
+
+
+/*************************************************************************
+ process_send_backup_list()
+ *************************************************************************/
+
+this function is part of samba's domain master browser functionality.
+
+it is responsible for giving master browsers a list of other browsers
+that maintain backup lists of servers for that master browser's workgroup.
+
+it is also responsible for giving master browsers a list of domain master
+browsers for that local master browser's domain.
+
+a correct way to think of this function is that it is a 'request to
+send out a backup list for the requested workgroup or domain'.
+
+i have some suspicions and intuitions about this function and how it
+is to actually be used. there is no documentation on this, so it is a
+matter of experimenting until it's right.
+
+
+/*************************************************************************
+ send_backup_list()
+ *************************************************************************/
+
+this function is responsible for compiling a list of either master
+browsers and backup master browsers or domain master browsers and
+backup domain master browsers. samba constructs this list from its
+workgroup / server database.
+
+the list is then sent to the host that requested it by sending an
+ANN_GetBackupListResp datagram to this host.
+
+
+NOTE FROM TRIDGE: The "backup list" stuff is only relevant to
+local subnets. It has nothing to do with PDCs or domain masters. Its
+function is twofold:
+
+1) spread the browsing load over multiple servers so one server
+doesn't get overloaded with browse requests
+2) make sure the database doesn't get lost completely if the master
+goes down
+
+To accomplish this a few things are supposed to be done:
+
+- the master browser maintains a list of "backup browsers".
+
+- backup browsers are are machines that are just like ordinary servers
+but also maintain a browse list and respond to "NetServerEnum"
+requests
+
+- when a server initially announces itself to the master it may set
+its "maintain browse list" flag to auto.
+
+- when a master browser sees a server announcement with "auto" set it
+may send a "become backup" to that server telling it to become a
+backup.
+
+- the master has a simple algorithm to determine how many backups it wants
+given the number of hosts on the net
+
+- when a client wishes to get a browse list it asks the master for a
+backup list. The master sends it the current list of backup browsers,
+including itself. The client caches this list. The client then sends
+the NetServerEnum to a random member of this list easch time it wants
+to browse. This spreads the load.
+
+
+
+/*************************************************************************
+ process_rcv_backup_list()
+ *************************************************************************/
+
+this function is implemented with a slightly over-kill algorithm.
+the correct functionality is to pick any three names at random from
+the list that is received from this datagram, and then at intervals
+contact _one_ of them for a list of browser, in order to update
+samba's browse list.
+
+samba contacts every single one of the backup browsers listed, through
+the use of a NAME_QUERY_SRV_CHK 'state'.
+
+
+/*************************************************************************
+ process_master_announce()
+ *************************************************************************/
+
+this function is responsible for synchronising browse lists with a
+master browser that contacts samba in its capacity as a domain master
+browser.
+
+the function add_browser_entry() is used to add the server that
+contacts us to our list of browser to sync browse lists with at
+some point in the near future.
+
+
+/*************************************************************************
+ process_announce()
+ *************************************************************************/
+
+this function is responsible for dealing with the three types of
+announcement type datagrams that samba recognises. some appropriate
+type-checking is done on the name that the datagram is sent to.
+
+samba does not at present deal with LanManager announcements.
+
+these announcements are for updating the browse entry records.
+each browse entry has a time-to-live associated with it. each server
+must refresh its entry with all other servers by broadcasting
+Announcements. if it does not do so, then other servers will not
+know about that machine, and the records on each server of that
+other machine will die.
+
+if an ANN_DomainAnnouncement is received, then this will be from
+a master browser. only one machine on any given broadcast area (e.g
+a subnet) should be broadcasting such announcements. the information
+it contains tells other servers that there is a master browser for
+this workgroup. if another server thinks that it is also a master
+browser for the same workgroup, then it should stop being a master
+browser and force an election.
+
+if an ANN_LocalMasterAnnouncement is received, then a master browser
+is telling us that it exists. i am uncertain that anything else
+actually needs to be done with this, other than to shout 'hooray' and
+'thank you for informing me of this fact'.
+
+
+/*************************************************************************
+ listening_name()
+ *************************************************************************/
+
+this function is an over-simplified way of identifying whether we
+should be responding to a datagram that has been received.
+
+
+/*************************************************************************
+ same_context()
+ *************************************************************************/
+
+this function helps us to identify whether we should be responding to
+a datagram that has been received.
+
+
+/*************************************************************************
+ tell_become_backup()
+ *************************************************************************/
+
+this function is part of samba's domain master browser capabilities.
+it is responsible for finding appropriate servers to tell to become a
+backup master browser for the domain that samba controls.
+
+other servers that contact samba asking for a list of backup browsers
+will then be given that server's name, and that server can expect to
+receive NetServerEnum requests for lists of servers and workgroups.
+
+this function must be updated before it is in a fit state to be used.
+it must properly check whether a server is prepared to become a backup
+browser before actually asking it to be one.
+
+
+/*************************************************************************
+ reset_server()
+ *************************************************************************/
+
+this function is responsible for issuing an ANN_ResetBrowserState to
+the specified server, asking it to reset its browser information.
+
+see process_reset_browser() for details on this function.
+
+
diff --git a/source/nmbd/asyncdns.c b/source/nmbd/asyncdns.c
new file mode 100644
index 00000000000..94fd65b147a
--- /dev/null
+++ b/source/nmbd/asyncdns.c
@@ -0,0 +1,257 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ a async DNS handler
+ Copyright (C) Andrew Tridgell 1994-1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+
+/***************************************************************************
+ add a DNS result to the name cache
+ ****************************************************************************/
+static struct name_record *add_dns_result(struct nmb_name *question, struct in_addr addr)
+{
+ int name_type = question->name_type;
+ char *qname = question->name;
+
+ if (!addr.s_addr) {
+ /* add the fail to WINS cache of names. give it 1 hour in the cache */
+ DEBUG(3,("Negative DNS answer for %s\n", qname));
+ add_netbios_entry(wins_client_subnet,qname,name_type,NB_ACTIVE,60*60,
+ DNSFAIL,addr,True);
+ return NULL;
+ }
+
+ /* add it to our WINS cache of names. give it 2 hours in the cache */
+ DEBUG(3,("DNS gave answer for %s of %s\n", qname, inet_ntoa(addr)));
+
+ return add_netbios_entry(wins_client_subnet,qname,name_type,NB_ACTIVE,
+ 2*60*60,DNS,addr, True);
+}
+
+
+
+#ifndef SYNC_DNS
+
+static int fd_in = -1, fd_out = -1;
+static int child_pid = -1;
+static int in_dns;
+
+/* this is the structure that is passed between the parent and child */
+struct query_record {
+ struct nmb_name name;
+ struct in_addr result;
+};
+
+/* a queue of pending requests waiting for DNS responses */
+static struct packet_struct *dns_queue;
+
+
+
+/***************************************************************************
+ return the fd used to gather async dns replies. This is added to the select
+ loop
+ ****************************************************************************/
+int asyncdns_fd(void)
+{
+ return fd_in;
+}
+
+/***************************************************************************
+ handle DNS queries arriving from the parent
+ ****************************************************************************/
+static void asyncdns_process(void)
+{
+ struct query_record r;
+ fstring qname;
+
+ DEBUGLEVEL = 0;
+
+ while (1) {
+ if (read_data(fd_in, (char *)&r, sizeof(r)) != sizeof(r))
+ break;
+
+ fstrcpy(qname, r.name.name);
+
+ r.result.s_addr = interpret_addr(qname);
+
+ if (write_data(fd_out, (char *)&r, sizeof(r)) != sizeof(r))
+ break;
+ }
+
+ exit(0);
+}
+
+
+/***************************************************************************
+ create a child process to handle DNS lookups
+ ****************************************************************************/
+void start_async_dns(void)
+{
+ int fd1[2], fd2[2];
+
+ signal(SIGCLD, SIG_IGN);
+
+ if (pipe(fd1) || pipe(fd2)) {
+ return;
+ }
+
+ child_pid = fork();
+
+ if (child_pid) {
+ fd_in = fd1[0];
+ fd_out = fd2[1];
+ close(fd1[1]);
+ close(fd2[0]);
+ DEBUG(3,("async DNS initialised\n"));
+ return;
+ }
+
+ fd_in = fd2[0];
+ fd_out = fd1[1];
+
+ asyncdns_process();
+}
+
+
+/***************************************************************************
+check if a particular name is already being queried
+ ****************************************************************************/
+static BOOL query_in_queue(struct query_record *r)
+{
+ struct packet_struct *p;
+ for (p = dns_queue; p; p = p->next) {
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
+
+ if (name_equal(question, &r->name))
+ return True;
+ }
+ return False;
+}
+
+
+/***************************************************************************
+ check the DNS queue
+ ****************************************************************************/
+void run_dns_queue(void)
+{
+ struct query_record r;
+ struct packet_struct *p, *p2;
+
+ if (fd_in == -1)
+ return;
+
+ if (read_data(fd_in, (char *)&r, sizeof(r)) != sizeof(r)) {
+ DEBUG(0,("Incomplete DNS answer from child!\n"));
+ fd_in = -1;
+ return;
+ }
+
+ add_dns_result(&r.name, r.result);
+
+ /* loop over the whole dns queue looking for entries that
+ match the result we just got */
+ for (p = dns_queue; p;) {
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
+
+ if (name_equal(question, &r.name)) {
+ DEBUG(3,("DNS calling reply_name_query\n"));
+ in_dns = 1;
+ reply_name_query(p);
+ in_dns = 0;
+ p->locked = False;
+
+ if (p->prev)
+ p->prev->next = p->next;
+ else
+ dns_queue = p->next;
+ if (p->next)
+ p->next->prev = p->prev;
+ p2 = p->next;
+ free_packet(p);
+ p = p2;
+ } else {
+ p = p->next;
+ }
+ }
+
+}
+
+/***************************************************************************
+queue a DNS query
+ ****************************************************************************/
+BOOL queue_dns_query(struct packet_struct *p,struct nmb_name *question,
+ struct name_record **n)
+{
+ struct query_record r;
+
+ if (in_dns || fd_in == -1)
+ return False;
+
+ r.name = *question;
+
+ if (!query_in_queue(&r) &&
+ !write_data(fd_out, (char *)&r, sizeof(r))) {
+ DEBUG(3,("failed to send DNS query to child!\n"));
+ return False;
+ }
+
+ p->locked = True;
+ p->next = dns_queue;
+ p->prev = NULL;
+ if (p->next)
+ p->next->prev = p;
+ dns_queue = p;
+
+
+ DEBUG(3,("added DNS query for %s\n", namestr(question)));
+ return True;
+}
+
+#else
+
+
+/***************************************************************************
+ we use this then we can't do async DNS lookups
+ ****************************************************************************/
+BOOL queue_dns_query(struct packet_struct *p,struct nmb_name *question,
+ struct name_record **n)
+{
+ int name_type = question->name_type;
+ char *qname = question->name;
+ struct in_addr dns_ip;
+
+ DEBUG(3,("DNS search for %s - ", namestr(question)));
+
+ dns_ip.s_addr = interpret_addr(qname);
+
+ *n = add_dns_result(question, dns_ip);
+ return False;
+}
+#endif
diff --git a/source/nmbd/nmbd.c b/source/nmbd/nmbd.c
new file mode 100644
index 00000000000..d53ec8c2e0c
--- /dev/null
+++ b/source/nmbd/nmbd.c
@@ -0,0 +1,659 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+extern pstring debugf;
+pstring servicesf = CONFIGFILE;
+
+extern pstring scope;
+
+int ClientNMB = -1;
+int ClientDGRAM = -1;
+int global_nmb_port = -1;
+
+extern pstring myhostname;
+static pstring host_file;
+extern pstring myname;
+extern fstring myworkgroup;
+extern char **my_netbios_names;
+
+/* are we running as a daemon ? */
+static BOOL is_daemon = False;
+
+/* what server type are we currently */
+
+time_t StartupTime =0;
+
+extern struct in_addr ipzero;
+
+ /****************************************************************************
+ catch a sigterm
+ ****************************************************************************/
+static int sig_term()
+{
+ BlockSignals(True,SIGTERM);
+
+ DEBUG(0,("Got SIGTERM: going down...\n"));
+
+ /* write out wins.dat file if samba is a WINS server */
+ dump_names();
+
+ /* remove all samba names, with wins server if necessary. */
+ remove_my_names();
+
+ /* announce all server entries as 0 time-to-live, 0 type */
+ /* XXXX don't care if we never receive a response back... yet */
+ announce_my_servers_removed();
+
+ /* XXXX other things: if we are a master browser, force an election? */
+
+ exit(0);
+ /* Keep compiler happy.. */
+ return 0;
+}
+
+
+/****************************************************************************
+catch a sighup
+****************************************************************************/
+static int sig_hup(void)
+{
+ BlockSignals(True,SIGHUP);
+
+ DEBUG(0,("Got SIGHUP (reload not implemented)\n"));
+ dump_names();
+ reload_services(True);
+
+ set_samba_nb_type();
+
+ BlockSignals(False,SIGHUP);
+#ifndef DONT_REINSTALL_SIG
+ signal(SIGHUP,SIGNAL_CAST sig_hup);
+#endif
+ return(0);
+}
+
+/****************************************************************************
+catch a sigpipe
+****************************************************************************/
+static int sig_pipe(void)
+{
+ BlockSignals(True,SIGPIPE);
+
+ DEBUG(0,("Got SIGPIPE\n"));
+ if (!is_daemon)
+ exit(1);
+ BlockSignals(False,SIGPIPE);
+ return(0);
+}
+
+#if DUMP_CORE
+/*******************************************************************
+prepare to dump a core file - carefully!
+********************************************************************/
+static BOOL dump_core(void)
+{
+ char *p;
+ pstring dname;
+ pstrcpy(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(time_t t)
+{
+ static time_t lastrun = 0;
+
+ 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;
+ pstrcpy(fname,lp_configfile());
+ if (file_exist(fname,NULL) && !strcsequal(fname,servicesf))
+ {
+ pstrcpy(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);
+ }
+
+ /* Do a sanity check for a misconfigured nmbd */
+ if(lp_wins_support() && *lp_wins_server()) {
+ DEBUG(0,("ERROR: both 'wins support = true' and 'wins server = <server>' \
+cannot be set in the smb.conf file. nmbd aborting.\n"));
+ exit(10);
+ }
+
+ 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))
+ {
+ pstring ip,name,flags,extra;
+ struct subnet_record *d;
+ char *ptr;
+ int count = 0;
+ struct in_addr ipaddr;
+ enum name_source source = LMHOSTS;
+
+ if (!fgets_slash(line,sizeof(pstring),f)) continue;
+
+ if (*line == '#') continue;
+
+ strcpy(ip,"");
+ strcpy(name,"");
+ strcpy(flags,"");
+
+ 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 (count >= 4) {
+ DEBUG(0,("too many columns in %s (obsolete syntax)\n",fname));
+ continue;
+ }
+
+ DEBUG(4, ("lmhost entry: %s %s %s\n", ip, name, flags));
+
+ if (strchr(flags,'G') || strchr(flags,'S')) {
+ DEBUG(0,("group flag in %s ignored (obsolete)\n",fname));
+ continue;
+ }
+
+ if (strchr(flags,'M')) {
+ source = SELF;
+ pstrcpy(myname,name);
+ }
+
+ ipaddr = *interpret_addr2(ip);
+ d = find_subnet_all(ipaddr);
+ if (d) {
+ add_netbios_entry(d,name,0x00,NB_ACTIVE,0,source,ipaddr,True);
+ add_netbios_entry(d,name,0x20,NB_ACTIVE,0,source,ipaddr,True);
+ }
+ }
+
+ fclose(f);
+}
+
+
+/****************************************************************************
+ The main select loop.
+ ***************************************************************************/
+static void process(void)
+{
+ BOOL run_election;
+
+ while (True)
+ {
+ time_t t = time(NULL);
+ run_election = check_elections();
+ if(listen_for_packets(run_election))
+ return;
+
+ run_packet_queue();
+ run_elections(t);
+
+ announce_host(t);
+ announce_master(t);
+ announce_remote(t);
+
+ query_refresh_names(t);
+
+ expire_names_and_servers(t);
+ expire_netbios_response_entries(t);
+ refresh_my_names(t);
+
+ write_browse_list(t);
+ do_browser_lists(t);
+ check_master_browser(t);
+ add_domain_names(t);
+ }
+}
+
+
+/****************************************************************************
+ open the socket communication
+****************************************************************************/
+static BOOL open_sockets(BOOL isdaemon, int port)
+{
+ /* The sockets opened here will be used to receive broadcast
+ packets *only*. Interface specific sockets are opened in
+ make_subnet() in namedbsubnet.c. Thus we bind to the
+ address "0.0.0.0". The parameter 'socket address' is
+ now deprecated.
+ */
+
+ if (isdaemon)
+ ClientNMB = open_socket_in(SOCK_DGRAM, port,0,0);
+ else
+ ClientNMB = 0;
+
+ ClientDGRAM = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3,0);
+
+ 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,("open_sockets: Broadcast sockets opened.\n"));
+ return True;
+}
+
+
+/****************************************************************************
+ initialise connect, service and file structs
+****************************************************************************/
+static BOOL init_structs()
+{
+ extern fstring local_machine;
+ char *p, *ptr;
+ int namecount;
+ int n;
+ int nodup;
+ pstring nbname;
+
+ if (! *myname) {
+ fstrcpy(myname,myhostname);
+ p = strchr(myname,'.');
+ if (p) *p = 0;
+ }
+ strupper(myname);
+
+ /* Add any NETBIOS name aliases. Ensure that the first entry
+ is equal to myname. */
+ /* Work out the max number of netbios aliases that we have */
+ ptr=lp_netbios_aliases();
+ for (namecount=0; next_token(&ptr,nbname,NULL); namecount++)
+ ;
+ if (*myname)
+ namecount++;
+
+ /* Allocate space for the netbios aliases */
+ if((my_netbios_names=(char **)malloc(sizeof(char *)*(namecount+1))) == NULL)
+ {
+ DEBUG(0,("init_structs: malloc fail.\n"));
+ return False;
+ }
+
+ /* Use the myname string first */
+ namecount=0;
+ if (*myname)
+ my_netbios_names[namecount++] = myname;
+
+ ptr=lp_netbios_aliases();
+ while (next_token(&ptr,nbname,NULL)) {
+ strupper(nbname);
+ /* Look for duplicates */
+ nodup=1;
+ for(n=0; n<namecount; n++) {
+ if (strcmp(nbname, my_netbios_names[n])==0)
+ nodup=0;
+ }
+ if (nodup)
+ my_netbios_names[namecount++]=strdup(nbname);
+ }
+
+ /* Check the strdups succeeded. */
+ for(n = 0; n < namecount; n++)
+ if(my_netbios_names[n]==NULL)
+ {
+ DEBUG(0,("init_structs: malloc fail when allocating names.\n"));
+ return False;
+ }
+
+ /* Terminate name list */
+ my_netbios_names[namecount++]=NULL;
+
+ fstrcpy(local_machine,myname);
+ trim_string(local_machine," "," ");
+ p = strchr(local_machine,' ');
+ if (p)
+ *p = 0;
+ strlower(local_machine);
+
+ DEBUG(5, ("Netbios name list:-\n"));
+ for (n=0; my_netbios_names[n]; n++)
+ DEBUG(5, ("my_netbios_names[%d]=\"%s\"\n", n, my_netbios_names[n]));
+
+ 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] [-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-H hosts file load a netbios hosts file\n");
+ printf("\n");
+}
+
+
+/****************************************************************************
+ main program
+ **************************************************************************/
+ int main(int argc,char *argv[])
+{
+ int opt;
+ extern FILE *dbf;
+ extern char *optarg;
+ char pidFile[100] = { 0 };
+
+ global_nmb_port = NMB_PORT;
+ *host_file = 0;
+
+ StartupTime = time(NULL);
+
+ TimeInit();
+
+ strcpy(debugf,NMBLOGFILE);
+
+ setup_logging(argv[0],False);
+
+ charset_initialise();
+
+#ifdef LMHOSTSFILE
+ strcpy(host_file,LMHOSTSFILE);
+#endif
+
+ /* this is for people who can't start the program correctly */
+ while (argc > 1 && (*argv[1] != '-')) {
+ argv++;
+ argc--;
+ }
+
+ fault_setup(fault_continue);
+
+ signal(SIGHUP ,SIGNAL_CAST sig_hup);
+ signal(SIGTERM,SIGNAL_CAST sig_term);
+
+ while ((opt = getopt(argc, argv, "as:T:I:C:bAi:B:N:Rn:l:d:Dp:hSH:G:f:")) != EOF)
+ {
+ switch (opt)
+ {
+ case 'f':
+ strncpy(pidFile, optarg, sizeof(pidFile));
+ break;
+ case 's':
+ pstrcpy(servicesf,optarg);
+ break;
+ case 'N':
+ case 'B':
+ case 'I':
+ case 'C':
+ case 'G':
+ DEBUG(0,("Obsolete option '%c' used\n",opt));
+ break;
+ case 'H':
+ pstrcpy(host_file,optarg);
+ break;
+ case 'n':
+ pstrcpy(myname,optarg);
+ strupper(myname);
+ break;
+ case 'l':
+ sprintf(debugf,"%s.nmb",optarg);
+ break;
+ case 'i':
+ pstrcpy(scope,optarg);
+ strupper(scope);
+ break;
+ case 'a':
+ {
+ extern BOOL append_log;
+ append_log = !append_log;
+ }
+ break;
+ case 'D':
+ is_daemon = True;
+ break;
+ case 'd':
+ DEBUGLEVEL = atoi(optarg);
+ break;
+ case 'p':
+ global_nmb_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-1997\n"));
+
+ if(!get_myname(myhostname,NULL))
+ {
+ DEBUG(0,("Unable to get my hostname - exiting.\n"));
+ return -1;
+ }
+
+ if (!reload_services(False))
+ return(-1);
+
+ codepage_initialise(lp_client_code_page());
+
+ if(!init_structs())
+ return -1;
+
+ reload_services(True);
+
+ pstrcpy(myworkgroup, lp_workgroup());
+
+ if (strequal(myworkgroup,"*")) {
+ DEBUG(0,("ERROR: a workgroup name of * is no longer supported\n"));
+ exit(1);
+ }
+
+ set_samba_nb_type();
+
+ 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();
+ }
+
+#ifndef SYNC_DNS
+ start_async_dns();
+#endif
+
+ if (*pidFile)
+ {
+ int fd;
+ char buf[20];
+
+ if ((fd = open(pidFile,
+#ifdef O_NONBLOCK
+ O_NONBLOCK |
+#endif
+ O_CREAT | O_WRONLY | O_TRUNC, 0644)) < 0)
+ {
+ DEBUG(0,("ERROR: can't open %s: %s\n", pidFile, strerror(errno)));
+ exit(1);
+ }
+ if (fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)==False)
+ {
+ DEBUG(0,("ERROR: nmbd is already running\n"));
+ exit(1);
+ }
+ sprintf(buf, "%u\n", (unsigned int) getpid());
+ if (write(fd, buf, strlen(buf)) < 0)
+ {
+ DEBUG(0,("ERROR: can't write to %s: %s\n", pidFile, strerror(errno)));
+ exit(1);
+ }
+ /* Leave pid file open & locked for the duration... */
+ }
+
+
+ DEBUG(3,("Opening sockets %d\n", global_nmb_port));
+
+ if (!open_sockets(is_daemon,global_nmb_port)) return 1;
+
+ load_interfaces();
+ add_my_subnets(myworkgroup);
+
+ add_my_names();
+
+ DEBUG(3,("Checked names\n"));
+
+ load_netbios_names();
+
+ DEBUG(3,("Loaded names\n"));
+
+ if (*host_file) {
+ load_hosts_file(host_file);
+ DEBUG(3,("Loaded hosts file\n"));
+ }
+
+ write_browse_list(time(NULL));
+
+ DEBUG(3,("Dumped names\n"));
+
+ /* We can only take sigterm signals in the select. */
+ BlockSignals(True,SIGTERM);
+
+ process();
+ close_sockets();
+
+ if (dbf)
+ fclose(dbf);
+ return(0);
+}
diff --git a/source/nmbsync.c b/source/nmbsync.c
index 5a77d6cc486..5fa41e127a5 100644
--- a/source/nmbsync.c
+++ b/source/nmbsync.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
NBT netbios routines to synchronise browse lists
- Copyright (C) Andrew Tridgell 1994-1995
+ Copyright (C) Andrew Tridgell 1994-1997
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
@@ -21,283 +21,100 @@
*/
#include "includes.h"
-#include "loadparm.h"
-#include "nameserv.h"
extern int DEBUGLEVEL;
-struct server_record *add_server_entry(char *name,int servertype,
- int ttl,char *comment,BOOL replace);
+static struct work_record *call_w;
+static struct subnet_record *call_d;
-
-/****************************************************************************
-call a remote api
-****************************************************************************/
-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)
+/*******************************************************************
+ This is the NetServerEnum callback
+ ******************************************************************/
+static void callback(char *sname, uint32 stype, char *comment)
{
- 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);
+ struct work_record *w = call_w;
+
+ stype &= ~SV_TYPE_LOCAL_LIST_ONLY;
+
+ if (stype & SV_TYPE_DOMAIN_ENUM) {
+ /* creates workgroup on remote subnet */
+ if ((w = find_workgroupstruct(call_d,sname,True))) {
+ announce_request(w, call_d->bcast_ip);
+ }
+ }
+
+ if (w) {
+ add_server_entry(call_d,w,sname,stype,
+ lp_max_ttl(),comment,False);
+ }
}
/*******************************************************************
- synchronise browse lists with another browse server
+ synchronise browse lists with another browse server.
+
+ log in on the remote server's SMB port to their IPC$ service,
+ do a NetServerEnum and update our server and workgroup databases.
******************************************************************/
-void sync_browse_lists(char *name,int name_type,char *myname,
- char *domain,struct in_addr ip)
+void sync_browse_lists(struct subnet_record *d, struct work_record *work,
+ char *name, int nm_type, struct in_addr ip, BOOL local)
{
- char *protocol = "LM1.2X002";
- char *service = "IPC$";
- char *dev = "IPC";
- int timeout=2000;
- char *inbuf=NULL;
- pstring outbuf;
- char *p;
- int len;
- uint32 sesskey;
- int cnum,uid;
- BOOL ret;
-
- int fd = open_socket_out(SOCK_STREAM, &ip, SMB_PORT);
- if (fd < 0) {
- DEBUG(3,("Failed to connect to %s at %s\n",name,inet_ntoa(ip)));
- return;
- }
-
- if (!(inbuf = (char *)malloc(0xFFFF+1024))) return;
-
- /* put in the destination name */
- len = 4;
- p = outbuf+len;
- name_mangle(name,p,name_type);
- len += name_len(p);
-
- /* and my name */
- p = outbuf+len;
- name_mangle(myname,p,0x20);
- len += name_len(p);
-
- _smb_setlen(outbuf,len);
- CVAL(outbuf,0) = 0x81;
-
- send_smb(fd,outbuf);
- receive_smb(fd,inbuf,5000);
-
- bzero(outbuf,smb_size);
-
- /* setup the protocol string */
- set_message(outbuf,0,strlen(protocol)+2,True);
- p = smb_buf(outbuf);
- *p++ = 2;
- strcpy(p,protocol);
-
- CVAL(outbuf,smb_com) = SMBnegprot;
- CVAL(outbuf,smb_flg) = 0x8;
- SSVAL(outbuf,smb_flg2,0x1);
-
- send_smb(fd,outbuf);
- bzero(inbuf,smb_size);
- ret = receive_smb(fd,inbuf,timeout);
-
- if (!ret || CVAL(inbuf,smb_rcls) || SVAL(inbuf,smb_vwv0)) {
- DEBUG(3,("%s rejected the protocol\n",name));
- close(fd);
- if (inbuf) free(inbuf);
- return;
- }
-
- sesskey = IVAL(inbuf,smb_vwv6);
-
- bzero(outbuf,smb_size);
- set_message(outbuf,10,2,True);
- CVAL(outbuf,smb_com) = SMBsesssetupX;
-
- CVAL(outbuf,smb_vwv0) = 0xFF;
- SSVAL(outbuf,smb_vwv2,0xFFFF);
- SSVAL(outbuf,smb_vwv3,2);
- SSVAL(outbuf,smb_vwv4,1);
- SIVAL(outbuf,smb_vwv5,sesskey);
- SSVAL(outbuf,smb_vwv7,1);
-
- send_smb(fd,outbuf);
- bzero(inbuf,smb_size);
- ret = receive_smb(fd,inbuf,timeout);
- if (!ret || CVAL(inbuf,smb_rcls)) {
- DEBUG(3,("%s rejected session setup\n",name));
- close(fd);
- if (inbuf) free(inbuf);
- return;
- }
-
- uid = SVAL(inbuf,smb_uid);
-
- bzero(outbuf,smb_size);
- set_message(outbuf,4,2 + (2 + strlen(name) + 1 + strlen(service)) +
- 1 + strlen(dev),True);
- CVAL(outbuf,smb_com) = SMBtconX;
- SSVAL(outbuf,smb_uid,uid);
-
- SSVAL(outbuf,smb_vwv0,0xFF);
- SSVAL(outbuf,smb_vwv3,1);
-
- p = smb_buf(outbuf) + 1;
- strcpy(p, "\\\\");
- strcat(p, name);
- strcat(p, "\\");
- strcat(p,service);
- p = skip_string(p,1);
- strcpy(p,dev);
-
- send_smb(fd,outbuf);
- bzero(inbuf,smb_size);
- ret = receive_smb(fd,inbuf,timeout);
- if (!ret || CVAL(inbuf,smb_rcls)) {
- DEBUG(3,("%s rejected IPC connect (%d,%d)\n",name,
- CVAL(inbuf,smb_rcls),SVAL(inbuf,smb_err)));
- close(fd);
- if (inbuf) free(inbuf);
- return;
- }
-
- cnum = SVAL(inbuf,smb_tid);
-
- /* now I need to send a NetServerEnum */
- {
- fstring param;
- uint32 *typep;
- char *rparam,*rdata;
-
- p = param;
- SSVAL(p,0,0x68); /* api number */
- p += 2;
- strcpy(p,"WrLehDz");
- p = skip_string(p,1);
-
- strcpy(p,"B16BBDz");
-
- p = skip_string(p,1);
- SSVAL(p,0,1); /* level 1 */
- SSVAL(p,2,0xFFFF - 500); /* buf length */
- p += 4;
- typep = (uint32 *)p;
- p += 4;
- strcpy(p,domain);
- strupper(p);
- p = skip_string(p,1);
-
- SIVAL(typep,0,0x80000000); /* domain list */
-
- if (call_remote_api(fd,cnum,uid,timeout,inbuf,outbuf,
- PTR_DIFF(p,param),0,
- 8,0xFFFF - 500,
- NULL,NULL,
- param,NULL,
- &rparam,&rdata) && SVAL(rparam,0)==0)
- {
- int converter=SVAL(rparam,2);
- int count=SVAL(rparam,4);
- int i;
- char *p2 = rdata;
- for (i=0;i<count;i++) {
- char *sname = p2;
- uint32 type = IVAL(p2,18);
- int comment_offset = IVAL(p2,22) & 0xFFFF;
- char *comment = comment_offset?(rdata+comment_offset-converter):"";
-
- add_server_entry(sname,type,lp_max_ttl(),comment,False);
- p2 += 26;
- }
- }
-
- SIVAL(typep,0,0xFFFFFFFF); /* server list */
-
- if (call_remote_api(fd,cnum,uid,timeout,inbuf,outbuf,
- PTR_DIFF(p,param),0,
- 8,0xFFFF - 500,
- NULL,NULL,
- param,NULL,
- &rparam,&rdata) && SVAL(rparam,0)==0)
- {
- int converter=SVAL(rparam,2);
- int count=SVAL(rparam,4);
- int i;
-
- p = rdata;
- for (i=0;i<count;i++) {
- char *sname = p;
- uint32 type = IVAL(p,18);
- int comment_offset = IVAL(p,22) & 0xFFFF;
- char *comment = comment_offset?(rdata+comment_offset-converter):"";
-
- add_server_entry(sname,type,lp_max_ttl(),comment,False);
- p += 26;
- }
- }
- }
-
- /* close up */
- bzero(outbuf,smb_size);
- set_message(outbuf,0,0,True);
- CVAL(outbuf,smb_com) = SMBtdis;
- SSVAL(outbuf,smb_uid,uid);
- SSVAL(outbuf,smb_tid,cnum);
- send_smb(fd,outbuf);
- receive_smb(fd,inbuf,1000);
-
- close(fd);
- if (inbuf) free(inbuf);
+ extern fstring local_machine;
+ fstring share;
+ static struct cli_state cli;
+ uint32 local_type = local ? SV_TYPE_LOCAL_LIST_ONLY : 0;
+
+ if (!d || !work ) return;
+
+ if(d != wins_client_subnet) {
+ DEBUG(0,("sync_browse_lists: ERROR sync requested on non-WINS subnet.\n"));
+ return;
+ }
+
+ DEBUG(2,("sync_browse_lists: Sync browse lists with %s for %s %s\n",
+ name, work->work_group, inet_ntoa(ip)));
+
+ if (!cli_initialise(&cli) || !cli_connect(&cli, name, &ip)) {
+ DEBUG(1,("Failed to start browse sync with %s\n", name));
+ }
+
+ if (!cli_session_request(&cli, name, nm_type, local_machine)) {
+ DEBUG(1,("%s rejected the browse sync session\n",name));
+ cli_shutdown(&cli);
+ return;
+ }
+
+ if (!cli_negprot(&cli)) {
+ DEBUG(1,("%s rejected the negprot\n",name));
+ cli_shutdown(&cli);
+ return;
+ }
+
+ if (!cli_session_setup(&cli, "", "", 1, "", 0, work->work_group)) {
+ DEBUG(1,("%s rejected the browse sync sessionsetup\n",
+ name));
+ cli_shutdown(&cli);
+ return;
+ }
+
+ sprintf(share,"\\\\%s\\IPC$", name);
+
+ if (!cli_send_tconX(&cli, share, "IPC", "", 1)) {
+ DEBUG(1,("%s refused browse sync IPC$ connect\n", name));
+ cli_shutdown(&cli);
+ return;
+ }
+
+ call_w = work;
+ call_d = d;
+
+ cli_NetServerEnum(&cli, work->work_group,
+ local_type|SV_TYPE_DOMAIN_ENUM,
+ callback);
+
+ cli_NetServerEnum(&cli, work->work_group,
+ local?SV_TYPE_LOCAL_LIST_ONLY:SV_TYPE_ALL,
+ callback);
+
+ cli_shutdown(&cli);
}
diff --git a/source/ntclientlsa.c b/source/ntclientlsa.c
new file mode 100644
index 00000000000..5cf945f2ede
--- /dev/null
+++ b/source/ntclientlsa.c
@@ -0,0 +1,380 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NT Domain Authentication SMB / MSRPC client
+ Copyright (C) Andrew Tridgell 1994-1997
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+
+ 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"
+
+extern int DEBUGLEVEL;
+extern pstring username;
+extern pstring workgroup;
+
+#define CLIENT_TIMEOUT (30*1000)
+
+#ifdef NTDOMAIN
+
+/****************************************************************************
+do a LSA Open Policy
+****************************************************************************/
+BOOL do_lsa_open_policy(uint16 fnum, uint32 call_id,
+ char *server_name, LSA_POL_HND *hnd)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt;
+ pstring data; /* only 1024 bytes */
+ uint16 setup[2]; /* only need 2 uint16 setup parameters */
+ LSA_Q_OPEN_POL q_o;
+ BOOL valid_pol = False;
+
+ if (hnd == NULL) return False;
+
+ /* create and send a MSRPC command with api LSA_OPENPOLICY */
+
+ DEBUG(4,("LSA Open Policy\n"));
+
+ /* store the parameters */
+ make_q_open_pol(&q_o, server_name, 0, 0, 0x1);
+
+ /* turn parameters into data stream */
+ p = lsa_io_q_open_pol(False, &q_o, data + 0x18, data, 4, 0);
+
+ /* create the request RPC_HDR_RR with no data */
+ create_rpc_request(call_id, LSA_OPENPOLICY, data, PTR_DIFF(p, data));
+
+ /* create setup parameters. */
+ setup[0] = 0x0026; /* 0x26 indicates "transact named pipe" */
+ setup[1] = fnum; /* file handle, from the SMBcreateX pipe, earlier */
+
+ /* send the data on \PIPE\ */
+ if (cli_call_api("\\PIPE\\", 0, PTR_DIFF(p, data), 2, 1024,
+ BUFFER_SIZE,
+ &rprcnt, &rdrcnt,
+ NULL, data, setup,
+ &rparam, &rdata))
+ {
+ LSA_R_OPEN_POL r_o;
+ RPC_HDR_RR hdr;
+ int hdr_len;
+ int pkt_len;
+
+ DEBUG(5, ("cli_call_api: return OK\n"));
+
+ p = rdata;
+
+ if (p) p = smb_io_rpc_hdr_rr (True, &hdr, p, rdata, 4, 0);
+ if (p) p = align_offset(p, rdata, 4); /* oh, what a surprise */
+
+ hdr_len = PTR_DIFF(p, rdata);
+
+ if (p && hdr_len != hdr.hdr.frag_len - hdr.alloc_hint)
+ {
+ /* header length not same as calculated header length */
+ DEBUG(2,("do_lsa_open_policy: hdr_len %x != frag_len-alloc_hint %x\n",
+ hdr_len, hdr.hdr.frag_len - hdr.alloc_hint));
+ p = NULL;
+ }
+
+ if (p) p = lsa_io_r_open_pol(True, &r_o, p, rdata, 4, 0);
+
+ pkt_len = PTR_DIFF(p, rdata);
+
+ if (p && pkt_len != hdr.hdr.frag_len)
+ {
+ /* packet data size not same as reported fragment length */
+ DEBUG(2,("do_lsa_open_policy: pkt_len %x != frag_len \n",
+ pkt_len, hdr.hdr.frag_len));
+ p = NULL;
+ }
+
+ if (p && r_o.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("LSA_OPENPOLICY: nt_status error %lx\n", r_o.status));
+ p = NULL;
+ }
+
+ if (p)
+ {
+ /* ok, at last: we're happy. return the policy handle */
+ memcpy(hnd, r_o.pol.data, sizeof(hnd->data));
+ valid_pol = True;
+ }
+ }
+
+ if (rparam) free(rparam);
+ if (rdata) free(rdata);
+
+ return valid_pol;
+}
+
+/****************************************************************************
+do a LSA Query Info Policy
+****************************************************************************/
+BOOL do_lsa_query_info_pol(uint16 fnum, uint32 call_id,
+ LSA_POL_HND *hnd, uint16 info_class,
+ fstring domain_name, pstring domain_sid)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt;
+ pstring data; /* only 1024 bytes */
+ uint16 setup[2]; /* only need 2 uint16 setup parameters */
+ LSA_Q_QUERY_INFO q_q;
+ BOOL valid_response = False;
+
+ if (hnd == NULL || domain_name == NULL || domain_sid == NULL) return False;
+
+ /* create and send a MSRPC command with api LSA_QUERYINFOPOLICY */
+
+ DEBUG(4,("LSA Query Info Policy\n"));
+
+ /* store the parameters */
+ make_q_query(&q_q, hnd, info_class);
+
+ /* turn parameters into data stream */
+ p = lsa_io_q_query(False, &q_q, data + 0x18, data, 4, 0);
+
+ /* create the request RPC_HDR_RR with no data */
+ create_rpc_request(call_id, LSA_QUERYINFOPOLICY, data, PTR_DIFF(p, data));
+
+ /* create setup parameters. */
+ setup[0] = 0x0026; /* 0x26 indicates "transact named pipe" */
+ setup[1] = fnum; /* file handle, from the SMBcreateX pipe, earlier */
+
+ /* send the data on \PIPE\ */
+ if (cli_call_api("\\PIPE\\", 0, PTR_DIFF(p, data), 2, 1024,
+ BUFFER_SIZE,
+ &rprcnt, &rdrcnt,
+ NULL, data, setup,
+ &rparam, &rdata))
+ {
+ LSA_R_QUERY_INFO r_q;
+ RPC_HDR_RR hdr;
+ int hdr_len;
+ int pkt_len;
+
+ DEBUG(5, ("cli_call_api: return OK\n"));
+
+ p = rdata;
+
+ if (p) p = smb_io_rpc_hdr_rr (True, &hdr, p, rdata, 4, 0);
+ if (p) p = align_offset(p, rdata, 4); /* oh, what a surprise */
+
+ hdr_len = PTR_DIFF(p, rdata);
+
+ if (p && hdr_len != hdr.hdr.frag_len - hdr.alloc_hint)
+ {
+ /* header length not same as calculated header length */
+ DEBUG(2,("do_lsa_query_info: hdr_len %x != frag_len-alloc_hint %x\n",
+ hdr_len, hdr.hdr.frag_len - hdr.alloc_hint));
+ p = NULL;
+ }
+
+ if (p) p = lsa_io_r_query(True, &r_q, p, rdata, 4, 0);
+
+ pkt_len = PTR_DIFF(p, rdata);
+
+ if (p && pkt_len != hdr.hdr.frag_len)
+ {
+ /* packet data size not same as reported fragment length */
+ DEBUG(2,("do_lsa_query_info: pkt_len %x != frag_len \n",
+ pkt_len, hdr.hdr.frag_len));
+ p = NULL;
+ }
+
+ if (p && r_q.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("LSA_QUERYINFOPOLICY: nt_status error %lx\n", r_q.status));
+ p = NULL;
+ }
+
+ if (p && r_q.info_class != q_q.info_class)
+ {
+ /* report different info classes */
+ DEBUG(0,("LSA_QUERYINFOPOLICY: error info_class (q,r) differ - (%x,%x)\n",
+ q_q.info_class, r_q.info_class));
+ p = NULL;
+ }
+
+ if (p)
+ {
+ /* ok, at last: we're happy. */
+ switch (r_q.info_class)
+ {
+ case 3:
+ {
+ char *dom_name = unistrn2(r_q.dom.id3.uni_domain_name.buffer,
+ r_q.dom.id3.uni_domain_name.uni_str_len);
+ char *dom_sid = dom_sid_to_string(&(r_q.dom.id3.dom_sid));
+ fstrcpy(domain_name, dom_name);
+ pstrcpy(domain_sid , dom_sid);
+
+ valid_response = True;
+ break;
+ }
+ case 5:
+ {
+ char *dom_name = unistrn2(r_q.dom.id5.uni_domain_name.buffer,
+ r_q.dom.id5.uni_domain_name.uni_str_len);
+ char *dom_sid = dom_sid_to_string(&(r_q.dom.id5.dom_sid));
+ fstrcpy(domain_name, dom_name);
+ pstrcpy(domain_sid , dom_sid);
+
+ valid_response = True;
+ break;
+ }
+ default:
+ {
+ DEBUG(3,("LSA_QUERYINFOPOLICY: unknown info class\n"));
+ domain_name[0] = 0;
+ domain_sid [0] = 0;
+
+ break;
+ }
+ }
+ DEBUG(3,("LSA_QUERYINFOPOLICY (level %x): domain:%s domain sid:%s\n",
+ r_q.info_class, domain_name, domain_sid));
+ }
+ }
+
+ if (rparam) free(rparam);
+ if (rdata) free(rdata);
+
+ return valid_response;
+}
+
+/****************************************************************************
+do a LSA Close
+****************************************************************************/
+BOOL do_lsa_close(uint16 fnum, uint32 call_id,
+ LSA_POL_HND *hnd)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt;
+ pstring data; /* only 1024 bytes */
+ uint16 setup[2]; /* only need 2 uint16 setup parameters */
+ LSA_Q_CLOSE q_c;
+ BOOL valid_close = False;
+
+ if (hnd == NULL) return False;
+
+ /* create and send a MSRPC command with api LSA_OPENPOLICY */
+
+ DEBUG(4,("LSA Close\n"));
+
+ /* store the parameters */
+ make_q_close(&q_c, hnd);
+
+ /* turn parameters into data stream */
+ p = lsa_io_q_close(False, &q_c, data + 0x18, data, 4, 0);
+
+ /* create the request RPC_HDR_RR with no data */
+ create_rpc_request(call_id, LSA_CLOSE, data, PTR_DIFF(p, data));
+
+ /* create setup parameters. */
+ setup[0] = 0x0026; /* 0x26 indicates "transact named pipe" */
+ setup[1] = fnum; /* file handle, from the SMBcreateX pipe, earlier */
+
+ /* send the data on \PIPE\ */
+ if (cli_call_api("\\PIPE\\", 0, PTR_DIFF(p, data), 2, 1024,
+ BUFFER_SIZE,
+ &rprcnt, &rdrcnt,
+ NULL, data, setup,
+ &rparam, &rdata))
+ {
+ LSA_R_CLOSE r_c;
+ RPC_HDR_RR hdr;
+ int hdr_len;
+ int pkt_len;
+
+ DEBUG(5, ("cli_call_api: return OK\n"));
+
+ p = rdata;
+
+ if (p) p = smb_io_rpc_hdr_rr (True, &hdr, p, rdata, 4, 0);
+ if (p) p = align_offset(p, rdata, 4); /* oh, what a surprise */
+
+ hdr_len = PTR_DIFF(p, rdata);
+
+ if (p && hdr_len != hdr.hdr.frag_len - hdr.alloc_hint)
+ {
+ /* header length not same as calculated header length */
+ DEBUG(2,("do_lsa_close: hdr_len %x != frag_len-alloc_hint %x\n",
+ hdr_len, hdr.hdr.frag_len - hdr.alloc_hint));
+ p = NULL;
+ }
+
+ if (p) p = lsa_io_r_close(True, &r_c, p, rdata, 4, 0);
+
+ pkt_len = PTR_DIFF(p, rdata);
+
+ if (p && pkt_len != hdr.hdr.frag_len)
+ {
+ /* packet data size not same as reported fragment length */
+ DEBUG(2,("do_lsa_close: pkt_len %x != frag_len \n",
+ pkt_len, hdr.hdr.frag_len));
+ p = NULL;
+ }
+
+ if (p && r_c.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("LSA_OPENPOLICY: nt_status error %lx\n", r_c.status));
+ p = NULL;
+ }
+
+ if (p)
+ {
+ /* check that the returned policy handle is all zeros */
+ int i;
+ valid_close = True;
+
+ for (i = 0; i < sizeof(r_c.pol.data); i++)
+ {
+ if (r_c.pol.data[i] != 0)
+ {
+ valid_close = False;
+ break;
+ }
+ }
+ if (!valid_close)
+ {
+ DEBUG(0,("LSA_CLOSE: non-zero handle returned\n"));
+ }
+ }
+ }
+
+ if (rparam) free(rparam);
+ if (rdata) free(rdata);
+
+ return valid_close;
+}
+
+#endif /* NTDOMAIN */
diff --git a/source/ntclientnet.c b/source/ntclientnet.c
new file mode 100644
index 00000000000..b89613f441d
--- /dev/null
+++ b/source/ntclientnet.c
@@ -0,0 +1,481 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NT Domain Authentication SMB / MSRPC client
+ Copyright (C) Andrew Tridgell 1994-1997
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+
+ 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"
+
+extern int DEBUGLEVEL;
+extern pstring username;
+extern pstring workgroup;
+
+#define CLIENT_TIMEOUT (30*1000)
+
+#ifdef NTDOMAIN
+
+/****************************************************************************
+do a LSA Request Challenge
+****************************************************************************/
+BOOL do_lsa_req_chal(uint16 fnum, uint32 call_id,
+ char *desthost, char *myhostname,
+ DOM_CHAL *clnt_chal, DOM_CHAL *srv_chal)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt;
+ pstring data; /* only 1024 bytes */
+ uint16 setup[2]; /* only need 2 uint16 setup parameters */
+ LSA_Q_REQ_CHAL q_c;
+ BOOL valid_chal = False;
+
+ if (srv_chal == NULL || clnt_chal == NULL) return False;
+
+ /* create and send a MSRPC command with api LSA_REQCHAL */
+
+ DEBUG(4,("LSA Request Challenge from %s to %s: %lx %lx\n",
+ desthost, myhostname, clnt_chal->data[0], clnt_chal->data[1]));
+
+ /* store the parameters */
+ make_q_req_chal(&q_c, desthost, myhostname, clnt_chal);
+
+
+ /* turn parameters into data stream */
+ p = lsa_io_q_req_chal(False, &q_c, data + 0x18, data, 4, 0);
+
+ /* create the request RPC_HDR_RR _after_ the main data: length is now known */
+ create_rpc_request(call_id, LSA_REQCHAL, data, PTR_DIFF(p, data));
+
+ /* create setup parameters. */
+ setup[0] = 0x0026; /* 0x26 indicates "transact named pipe" */
+ setup[1] = fnum; /* file handle, from the SMBcreateX pipe, earlier */
+
+ /* send the data on \PIPE\ */
+ if (cli_call_api("\\PIPE\\", 0, PTR_DIFF(p, data), 2, 1024,
+ BUFFER_SIZE,
+ &rprcnt,&rdrcnt,
+ NULL, data, setup,
+ &rparam,&rdata))
+ {
+ LSA_R_REQ_CHAL r_c;
+ RPC_HDR_RR hdr;
+ int hdr_len;
+ int pkt_len;
+
+ DEBUG(5, ("cli_call_api: return OK\n"));
+
+ p = rdata;
+
+ if (p) p = smb_io_rpc_hdr_rr (True, &hdr, p, rdata, 4, 0);
+ if (p) p = align_offset(p, rdata, 4); /* oh, what a surprise */
+
+ hdr_len = PTR_DIFF(p, rdata);
+
+ if (p && hdr_len != hdr.hdr.frag_len - hdr.alloc_hint)
+ {
+ /* header length not same as calculated header length */
+ DEBUG(2,("do_lsa_req_chal: hdr_len %x != frag_len-alloc_hint %x\n",
+ hdr_len, hdr.hdr.frag_len - hdr.alloc_hint));
+ p = NULL;
+ }
+
+ if (p) p = lsa_io_r_req_chal(True, &r_c, p, rdata, 4, 0);
+
+ pkt_len = PTR_DIFF(p, rdata);
+
+ if (p && pkt_len != hdr.hdr.frag_len)
+ {
+ /* packet data size not same as reported fragment length */
+ DEBUG(2,("do_lsa_req_chal: pkt_len %x != frag_len \n",
+ pkt_len, hdr.hdr.frag_len));
+ p = NULL;
+ }
+
+ if (p && r_c.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("LSA_REQ_CHAL: nt_status error %lx\n", r_c.status));
+ p = NULL;
+ }
+
+ if (p)
+ {
+ /* ok, at last: we're happy. return the challenge */
+ memcpy(srv_chal, r_c.srv_chal.data, sizeof(srv_chal->data));
+ valid_chal = True;
+ }
+ }
+
+ if (rparam) free(rparam);
+ if (rdata) free(rdata);
+
+ return valid_chal;
+}
+
+/****************************************************************************
+do a LSA Authenticate 2
+****************************************************************************/
+BOOL do_lsa_auth2(uint16 fnum, uint32 call_id,
+ char *logon_srv, char *acct_name, uint16 sec_chan, char *comp_name,
+ DOM_CHAL *clnt_chal, uint32 neg_flags, DOM_CHAL *srv_chal)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt;
+ pstring data; /* only 1024 bytes */
+ uint16 setup[2]; /* only need 2 uint16 setup parameters */
+ LSA_Q_AUTH_2 q_a;
+ BOOL valid_chal = False;
+
+ if (srv_chal == NULL || clnt_chal == NULL) return False;
+
+ /* create and send a MSRPC command with api LSA_AUTH2 */
+
+ DEBUG(4,("LSA Authenticate 2: srv:%s acct:%s sc:%x mc: %s chal %lx %lx neg: %lx\n",
+ logon_srv, acct_name, sec_chan, comp_name,
+ clnt_chal->data[0], clnt_chal->data[1], neg_flags));
+
+ /* store the parameters */
+ make_q_auth_2(&q_a, logon_srv, acct_name, sec_chan, comp_name,
+ clnt_chal, neg_flags);
+
+ /* turn parameters into data stream */
+ p = lsa_io_q_auth_2(False, &q_a, data + 0x18, data, 4, 0);
+
+ /* create the request RPC_HDR_RR _after_ the main data: length is now known */
+ create_rpc_request(call_id, LSA_AUTH2, data, PTR_DIFF(p, data));
+
+ /* create setup parameters. */
+ setup[0] = 0x0026; /* 0x26 indicates "transact named pipe" */
+ setup[1] = fnum; /* file handle, from the SMBcreateX pipe, earlier */
+
+ /* send the data on \PIPE\ */
+ if (cli_call_api("\\PIPE\\", 0, PTR_DIFF(p, data), 2, 1024,
+ BUFFER_SIZE,
+ &rprcnt,&rdrcnt,
+ NULL, data, setup,
+ &rparam,&rdata))
+ {
+ LSA_R_AUTH_2 r_a;
+ RPC_HDR_RR hdr;
+ int hdr_len;
+ int pkt_len;
+
+ DEBUG(5, ("cli_call_api: return OK\n"));
+
+ p = rdata;
+
+ if (p) p = smb_io_rpc_hdr_rr (True, &hdr, p, rdata, 4, 0);
+ if (p) p = align_offset(p, rdata, 4); /* oh, what a surprise */
+
+ hdr_len = PTR_DIFF(p, rdata);
+
+ if (p && hdr_len != hdr.hdr.frag_len - hdr.alloc_hint)
+ {
+ /* header length not same as calculated header length */
+ DEBUG(2,("do_lsa_auth2: hdr_len %x != frag_len-alloc_hint %x\n",
+ hdr_len, hdr.hdr.frag_len - hdr.alloc_hint));
+ p = NULL;
+ }
+
+ if (p) p = lsa_io_r_auth_2(True, &r_a, p, rdata, 4, 0);
+
+ pkt_len = PTR_DIFF(p, rdata);
+
+ if (p && pkt_len != hdr.hdr.frag_len)
+ {
+ /* packet data size not same as reported fragment length */
+ DEBUG(2,("do_lsa_auth2: pkt_len %x != frag_len \n",
+ pkt_len, hdr.hdr.frag_len));
+ p = NULL;
+ }
+
+ if (p && r_a.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("LSA_AUTH2: nt_status error %lx\n", r_a.status));
+ p = NULL;
+ }
+
+ if (p && r_a.srv_flgs.neg_flags != q_a.clnt_flgs.neg_flags)
+ {
+ /* report different neg_flags */
+ DEBUG(0,("LSA_AUTH2: error neg_flags (q,r) differ - (%lx,%lx)\n",
+ q_a.clnt_flgs.neg_flags, r_a.srv_flgs.neg_flags));
+ p = NULL;
+ }
+
+ if (p)
+ {
+ /* ok, at last: we're happy. return the challenge */
+ memcpy(srv_chal, r_a.srv_chal.data, sizeof(srv_chal->data));
+ valid_chal = True;
+ }
+ }
+
+ if (rparam) free(rparam);
+ if (rdata) free(rdata);
+
+ return valid_chal;
+}
+
+/***************************************************************************
+do a LSA SAM Logon
+****************************************************************************/
+BOOL do_lsa_sam_logon(uint16 fnum, uint32 call_id,
+ uint32 sess_key[2], DOM_CRED *sto_clnt_cred,
+ char *logon_srv, char *comp_name,
+ DOM_CRED *clnt_cred, DOM_CRED *rtn_cred,
+ uint16 logon_level, uint16 switch_value, DOM_ID_INFO_1 *id1,
+ LSA_USER_INFO *user_info,
+ DOM_CRED *srv_cred)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt;
+ pstring data; /* only 1024 bytes */
+ uint16 setup[2]; /* only need 2 uint16 setup parameters */
+ LSA_Q_SAM_LOGON q_s;
+ BOOL valid_cred = False;
+
+ if (srv_cred == NULL || clnt_cred == NULL || rtn_cred == NULL || user_info == NULL) return False;
+
+ /* create and send a MSRPC command with api LSA_SAMLOGON */
+
+ DEBUG(4,("LSA SAM Logon: srv:%s mc:%s clnt %lx %lx %lx rtn: %lx %lx %lx ll: %d\n",
+ logon_srv, comp_name,
+ clnt_cred->challenge.data[0], clnt_cred->challenge.data[1], clnt_cred->timestamp.time,
+ rtn_cred ->challenge.data[0], rtn_cred ->challenge.data[1], rtn_cred ->timestamp.time,
+ logon_level));
+
+ /* store the parameters */
+ make_sam_info(&(q_s.sam_id), logon_srv, comp_name,
+ clnt_cred, rtn_cred, logon_level, switch_value, id1);
+
+ /* turn parameters into data stream */
+ p = lsa_io_q_sam_logon(False, &q_s, data + 0x18, data, 4, 0);
+
+ /* create the request RPC_HDR_RR _after_ the main data: length is now known */
+ create_rpc_request(call_id, LSA_SAMLOGON, data, PTR_DIFF(p, data));
+
+ /* create setup parameters. */
+ setup[0] = 0x0026; /* 0x26 indicates "transact named pipe" */
+ setup[1] = fnum; /* file handle, from the SMBcreateX pipe, earlier */
+
+ /* send the data on \PIPE\ */
+ if (cli_call_api("\\PIPE\\", 0, PTR_DIFF(p, data), 2, 1024,
+ BUFFER_SIZE,
+ &rprcnt,&rdrcnt,
+ NULL, data, setup,
+ &rparam,&rdata))
+ {
+ LSA_R_SAM_LOGON r_s;
+ RPC_HDR_RR hdr;
+ int hdr_len;
+ int pkt_len;
+
+ r_s.user = user_info;
+
+ DEBUG(5, ("cli_call_api: return OK\n"));
+
+ p = rdata;
+
+ if (p) p = smb_io_rpc_hdr_rr (True, &hdr, p, rdata, 4, 0);
+ if (p) p = align_offset(p, rdata, 4); /* oh, what a surprise */
+
+ hdr_len = PTR_DIFF(p, rdata);
+
+ if (p && hdr_len != hdr.hdr.frag_len - hdr.alloc_hint)
+ {
+ /* header length not same as calculated header length */
+ DEBUG(2,("do_lsa_sam_logon: hdr_len %x != frag_len-alloc_hint %x\n",
+ hdr_len, hdr.hdr.frag_len - hdr.alloc_hint));
+ p = NULL;
+ }
+
+ if (p) p = lsa_io_r_sam_logon(True, &r_s, p, rdata, 4, 0);
+
+ pkt_len = PTR_DIFF(p, rdata);
+
+ if (p && pkt_len != hdr.hdr.frag_len)
+ {
+ /* packet data size not same as reported fragment length */
+ DEBUG(2,("do_lsa_sam_logon: pkt_len %x != frag_len \n",
+ pkt_len, hdr.hdr.frag_len));
+ p = NULL;
+ }
+
+ if (p && r_s.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("LSA_SAMLOGON: nt_status error %lx\n", r_s.status));
+ p = NULL;
+ }
+
+ if (p && r_s.switch_value != 3)
+ {
+ /* report different switch_value */
+ DEBUG(0,("LSA_SAMLOGON: switch_value of 3 expected %x\n",
+ r_s.switch_value));
+ p = NULL;
+ }
+
+ if (p)
+ {
+ if (clnt_deal_with_creds(sess_key, sto_clnt_cred, &(r_s.srv_creds)))
+ {
+ DEBUG(5, ("do_lsa_sam_logon: server credential check OK\n"));
+ /* ok, at last: we're happy. return the challenge */
+ memcpy(srv_cred, &(r_s.srv_creds), sizeof(r_s.srv_creds));
+ valid_cred = True;
+ }
+ else
+ {
+ DEBUG(5, ("do_lsa_sam_logon: server credential check failed\n"));
+ }
+ }
+ }
+
+ if (rparam) free(rparam);
+ if (rdata) free(rdata);
+
+ return valid_cred;
+}
+
+/***************************************************************************
+do a LSA SAM Logoff
+****************************************************************************/
+BOOL do_lsa_sam_logoff(uint16 fnum, uint32 call_id,
+ uint32 sess_key[2], DOM_CRED *sto_clnt_cred,
+ char *logon_srv, char *comp_name,
+ DOM_CRED *clnt_cred, DOM_CRED *rtn_cred,
+ uint16 logon_level, uint16 switch_value, DOM_ID_INFO_1 *id1,
+ DOM_CRED *srv_cred)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt;
+ pstring data; /* only 1024 bytes */
+ uint16 setup[2]; /* only need 2 uint16 setup parameters */
+ LSA_Q_SAM_LOGOFF q_s;
+ BOOL valid_cred = False;
+
+ if (srv_cred == NULL || clnt_cred == NULL || rtn_cred == NULL) return False;
+
+ /* create and send a MSRPC command with api LSA_SAMLOGON */
+
+ DEBUG(4,("LSA SAM Logoff: srv:%s mc:%s clnt %lx %lx %lx rtn: %lx %lx %lx ll: %d\n",
+ logon_srv, comp_name,
+ clnt_cred->challenge.data[0], clnt_cred->challenge.data[1], clnt_cred->timestamp.time,
+ rtn_cred ->challenge.data[0], rtn_cred ->challenge.data[1], rtn_cred ->timestamp.time,
+ logon_level));
+
+ /* store the parameters */
+ make_sam_info(&(q_s.sam_id), logon_srv, comp_name,
+ clnt_cred, rtn_cred, logon_level, switch_value, id1);
+
+ /* turn parameters into data stream */
+ p = lsa_io_q_sam_logoff(False, &q_s, data + 0x18, data, 4, 0);
+
+ /* create the request RPC_HDR_RR _after_ the main data: length is now known */
+ create_rpc_request(call_id, LSA_SAMLOGOFF, data, PTR_DIFF(p, data));
+
+ /* create setup parameters. */
+ setup[0] = 0x0026; /* 0x26 indicates "transact named pipe" */
+ setup[1] = fnum; /* file handle, from the SMBcreateX pipe, earlier */
+
+ /* send the data on \PIPE\ */
+ if (cli_call_api("\\PIPE\\", 0, PTR_DIFF(p, data), 2, 1024,
+ BUFFER_SIZE,
+ &rprcnt,&rdrcnt,
+ NULL, data, setup,
+ &rparam,&rdata))
+ {
+ LSA_R_SAM_LOGOFF r_s;
+ RPC_HDR_RR hdr;
+ int hdr_len;
+ int pkt_len;
+
+ DEBUG(5, ("cli_call_api: return OK\n"));
+
+ p = rdata;
+
+ if (p) p = smb_io_rpc_hdr_rr (True, &hdr, p, rdata, 4, 0);
+ if (p) p = align_offset(p, rdata, 4); /* oh, what a surprise */
+
+ hdr_len = PTR_DIFF(p, rdata);
+
+ if (p && hdr_len != hdr.hdr.frag_len - hdr.alloc_hint)
+ {
+ /* header length not same as calculated header length */
+ DEBUG(2,("do_lsa_sam_logoff: hdr_len %x != frag_len-alloc_hint %x\n",
+ hdr_len, hdr.hdr.frag_len - hdr.alloc_hint));
+ p = NULL;
+ }
+
+ if (p) p = lsa_io_r_sam_logoff(True, &r_s, p, rdata, 4, 0);
+
+ pkt_len = PTR_DIFF(p, rdata);
+
+ if (p && pkt_len != hdr.hdr.frag_len)
+ {
+ /* packet data size not same as reported fragment length */
+ DEBUG(2,("do_lsa_sam_logoff: pkt_len %x != frag_len \n",
+ pkt_len, hdr.hdr.frag_len));
+ p = NULL;
+ }
+
+ if (p && r_s.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("LSA_SAMLOGOFF: nt_status error %lx\n", r_s.status));
+ p = NULL;
+ }
+
+ if (p)
+ {
+ if (clnt_deal_with_creds(sess_key, sto_clnt_cred, &(r_s.srv_creds)))
+ {
+ DEBUG(5, ("do_lsa_sam_logoff: server credential check OK\n"));
+ /* ok, at last: we're happy. return the challenge */
+ memcpy(srv_cred, &(r_s.srv_creds), sizeof(r_s.srv_creds));
+ valid_cred = True;
+ }
+ else
+ {
+ DEBUG(5, ("do_lsa_sam_logoff: server credential check failed\n"));
+ }
+ }
+ }
+
+ if (rparam) free(rparam);
+ if (rdata) free(rdata);
+
+ return valid_cred;
+}
+
+#endif /* NTDOMAIN */
diff --git a/source/ntclientpipe.c b/source/ntclientpipe.c
new file mode 100644
index 00000000000..80991cea517
--- /dev/null
+++ b/source/ntclientpipe.c
@@ -0,0 +1,257 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NT Domain Authentication SMB / MSRPC client
+ Copyright (C) Andrew Tridgell 1994-1997
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+
+ 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"
+
+extern int DEBUGLEVEL;
+extern pstring username;
+extern pstring workgroup;
+
+#define CLIENT_TIMEOUT (30*1000)
+
+#ifdef NTDOMAIN
+
+/****************************************************************************
+ open an rpc pipe (\NETLOGON or \srvsvc for example)
+ ****************************************************************************/
+uint16 open_rpc_pipe(char *inbuf, char *outbuf, char *rname, int Client, int cnum)
+{
+ int fnum;
+ char *p;
+
+ DEBUG(5,("open_rpc_pipe: %s\n", rname));
+
+ bzero(outbuf,smb_size);
+ set_message(outbuf,15,1 + strlen(rname),True);
+
+ CVAL(outbuf,smb_com) = SMBopenX;
+ SSVAL(outbuf,smb_tid, cnum);
+ cli_setup_pkt(outbuf);
+
+ SSVAL(outbuf,smb_vwv0,0xFF);
+ SSVAL(outbuf,smb_vwv2,1);
+ SSVAL(outbuf,smb_vwv3,(DENY_NONE<<4));
+ SSVAL(outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
+ SSVAL(outbuf,smb_vwv5,aSYSTEM | aHIDDEN);
+ SSVAL(outbuf,smb_vwv8,1);
+
+ p = smb_buf(outbuf);
+ strcpy(p,rname);
+ p = skip_string(p,1);
+
+ send_smb(Client,outbuf);
+ receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+
+ if (CVAL(inbuf,smb_rcls) != 0)
+ {
+ if (CVAL(inbuf,smb_rcls) == ERRSRV &&
+ SVAL(inbuf,smb_err) == ERRnoresource &&
+ cli_reopen_connection(inbuf,outbuf))
+ {
+ return open_rpc_pipe(inbuf, outbuf, rname, Client, cnum);
+ }
+ DEBUG(0,("opening remote pipe %s - error %s\n", rname, smb_errstr(inbuf)));
+
+ return 0xffff;
+ }
+
+ fnum = SVAL(inbuf, smb_vwv2);
+
+ DEBUG(5,("opening pipe: fnum %d\n", fnum));
+
+ return fnum;
+}
+
+struct
+{
+ char *client;
+ char *server;
+} pipe_names [] =
+{
+ { PIPE_LSARPC , PIPE_LSASS },
+ { PIPE_NETLOGON, PIPE_NETLOGON },
+ { NULL , NULL }
+};
+
+/****************************************************************************
+do an rpc bind
+****************************************************************************/
+BOOL bind_rpc_pipe(char *pipe_name, uint16 fnum, uint32 call_id,
+ RPC_IFACE *abstract, RPC_IFACE *transfer)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt;
+ int data_len;
+ pstring data; /* only 1024 bytes */
+ uint16 setup[2]; /* only need 2 uint16 setup parameters */
+
+ RPC_HDR hdr;
+
+ RPC_HDR_RB hdr_rb;
+
+ BOOL valid_ack = False;
+
+ if (pipe_name == NULL || abstract == NULL || transfer == NULL) return False;
+
+ DEBUG(5,("Bind RPC Pipe[%d]: %s\n", fnum, pipe_name));
+
+ /* create the request RPC_HDR_RB */
+ make_rpc_hdr_rb(&hdr_rb,
+ 0x1630, 0x1630, 0x0,
+ 0x1, 0x1, 0x1,
+ abstract, transfer);
+
+ /* stream the bind request data */
+ p = smb_io_rpc_hdr_rb(False, &hdr_rb, data + 0x10, data, 4, 0);
+
+ data_len = PTR_DIFF(p, data);
+
+ /* create the request RPC_HDR */
+ make_rpc_hdr(&hdr, RPC_BIND, 0x0, call_id, PTR_DIFF(p, data + 0x10));
+
+ /* stream the header into data */
+ p = smb_io_rpc_hdr(False, &hdr, data, data, 4, 0);
+
+ /* create setup parameters. */
+ setup[0] = 0x0026; /* 0x26 indicates "transact named pipe" */
+ setup[1] = fnum; /* file handle, from the SMBcreateX pipe, earlier */
+
+ /* send the data on \PIPE\ */
+ if (cli_call_api("\\PIPE\\", 0, data_len, 2, 1024,
+ BUFFER_SIZE,
+ &rprcnt, &rdrcnt,
+ NULL, data, setup,
+ &rparam, &rdata))
+ {
+ RPC_HDR_BA hdr_ba;
+ int hdr_len;
+ int pkt_len;
+ int i = 0;
+
+ DEBUG(5, ("cli_call_api: return OK\n"));
+
+ p = rdata;
+
+ if (p) p = smb_io_rpc_hdr(True, &hdr, p, rdata, 4, 0);
+ if (p) p = align_offset(p, rdata, 4); /* oh, what a surprise */
+
+ hdr_len = PTR_DIFF(p, rdata);
+
+ if (p) p = smb_io_rpc_hdr_ba(True, &hdr_ba, p, rdata, 4, 0);
+
+ pkt_len = PTR_DIFF(p, rdata);
+#if 0
+ if (p && hdr_len != hdr.hdr.frag_len - hdr.alloc_hint)
+ {
+ /* header length not same as calculated header length */
+ DEBUG(2,("bind_rpc_pipe: hdr_len %x != frag_len-alloc_hint %x\n",
+ hdr_len, hdr.hdr.frag_len - hdr.alloc_hint));
+ p = NULL;
+ }
+
+
+ if (p && pkt_len != hdr.hdr.frag_len)
+ {
+ /* packet data size not same as reported fragment length */
+ DEBUG(2,("bind_rpc_pipe: pkt_len %x != frag_len \n",
+ pkt_len, hdr.hdr.frag_len));
+ p = NULL;
+ }
+#endif
+
+ while (p && (pipe_names[i].server != NULL))
+ {
+ DEBUG(6,("bind_rpc_pipe: searching pipe name: client:%s server:%s\n",
+ pipe_names[i].client, pipe_names[i].server));
+
+ if ((strcmp(pipe_name , pipe_names[i].client) == 0))
+ {
+ if (strcmp(hdr_ba.addr.str, pipe_names[i].server) == 0)
+ {
+ DEBUG(5,("bind_rpc_pipe: server pipe_name found: %s\n",
+ pipe_names[i].server));
+ break;
+ }
+ else
+ {
+ DEBUG(2,("bind_rpc_pipe: pipe_name %s != expected pipe %s\n",
+ pipe_names[i].server, hdr_ba.addr.str));
+ p = NULL;
+ }
+ }
+ else
+ {
+ i++;
+ }
+ }
+
+ if (p && pipe_names[i].server == NULL)
+ {
+ DEBUG(2,("bind_rpc_pipe: pipe name %s unsupported\n", hdr_ba.addr.str));
+ p = NULL;
+ }
+
+ if (p)
+ {
+ /* check the transfer syntax */
+ valid_ack = (hdr_ba.transfer.version == transfer->version) &&
+ (memcmp(hdr_ba.transfer.data, transfer->data,
+ sizeof(transfer->version)) ==0);
+ if (!valid_ack)
+ {
+ DEBUG(2,("bind_rpc_pipe: transfer syntax differs\n"));
+ p = NULL;
+ }
+ }
+
+ if (p)
+ {
+ /* check the results */
+ valid_ack = (hdr_ba.res.num_results == 0x1) &&
+ (hdr_ba.res.result == 0);
+
+ if (!valid_ack)
+ {
+ DEBUG(2,("bind_rpc_pipe: bind denied results: %d reason: %x\n",
+ hdr_ba.res.num_results,
+ hdr_ba.res.reason));
+ p = NULL;
+ }
+ else
+ {
+ DEBUG(5,("bind_rpc_pipe: accepted!\n"));
+ }
+ }
+ }
+
+ if (rparam) free(rparam);
+ if (rdata) free(rdata);
+
+ return valid_ack;
+}
+#endif /* NTDOMAIN */
diff --git a/source/param/loadparm.c b/source/param/loadparm.c
index c61ab26781f..6c88168b829 100644
--- a/source/param/loadparm.c
+++ b/source/param/loadparm.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Parameter loading functions
- Copyright (C) Karl Auer 1993,1994
+ Copyright (C) Karl Auer 1993,1997
Largely re-written by Andrew Tridgell, September 1994
@@ -49,16 +49,16 @@
#include "includes.h"
-#include "params.h"
-#include "loadparm.h"
-#include "pcap.h"
+/* Set default coding system for KANJI if none specified in Makefile. */
+#ifndef KANJI
+#define KANJI "sjis"
+#endif /* KANJI */
BOOL bLoaded = False;
extern int DEBUGLEVEL;
-extern int ReadSize;
extern pstring user_socket_options;
-extern pstring smbrun_path;
+extern pstring myname;
#ifndef GLOBAL_NAME
#define GLOBAL_NAME "global"
@@ -89,7 +89,8 @@ extern pstring smbrun_path;
/* these are the types of parameter we have */
typedef enum
{
- P_BOOL,P_BOOLREV,P_CHAR,P_INTEGER,P_OCTAL,P_STRING,P_GSTRING
+ P_BOOL,P_BOOLREV,P_CHAR,P_INTEGER,P_OCTAL,
+ P_STRING,P_USTRING,P_GSTRING,P_UGSTRING
} parm_type;
typedef enum
@@ -101,66 +102,94 @@ int keepalive=0;
extern BOOL use_getwd_cache;
extern int extra_time_offset;
-#ifdef KANJI
extern int coding_system;
-#endif
/*
* This structure describes global (ie., server-wide) parameters.
*/
typedef struct
{
- char *szPrintcapname;
- char *szLockDir;
- char *szRootdir;
- char *szDefaultService;
- char *szDfree;
- char *szMsgCommand;
- char *szHostsEquiv;
- char *szServerString;
- char *szAutoServices;
- char *szPasswdProgram;
- char *szPasswdChat;
- char *szLogFile;
- char *szConfigFile;
- char *szSMBPasswdFile;
- char *szPasswordServer;
- char *szSocketOptions;
- char *szValidChars;
- char *szWorkGroup;
- char *szDomainController;
- char *szUsernameMap;
- char *szCharacterSet;
- char *szLogonScript;
- int max_log_size;
- int mangled_stack;
- int max_xmit;
- int max_mux;
- int max_packet;
- int pwordlevel;
- int deadtime;
- int maxprotocol;
- int security;
- int printing;
- int maxdisksize;
- int lpqcachetime;
- int syslog;
- int os_level;
- int max_ttl;
- BOOL bPreferredMaster;
- BOOL bDomainMaster;
- BOOL bDomainLogons;
- BOOL bEncryptPasswords;
- BOOL bStripDot;
- BOOL bNullPasswords;
- BOOL bLoadPrinters;
- BOOL bUseRhosts;
- BOOL bReadRaw;
- BOOL bWriteRaw;
- BOOL bReadPrediction;
- BOOL bReadbmpx;
- BOOL bSyslogOnly;
- BOOL bBrowseList;
+ char *szPrintcapname;
+ char *szLockDir;
+ char *szRootdir;
+ char *szDefaultService;
+ char *szDfree;
+ char *szMsgCommand;
+ char *szHostsEquiv;
+ char *szServerString;
+ char *szAutoServices;
+ char *szPasswdProgram;
+ char *szPasswdChat;
+ char *szLogFile;
+ char *szConfigFile;
+ char *szSMBPasswdFile;
+ char *szPasswordServer;
+ char *szSocketOptions;
+ char *szValidChars;
+ char *szWorkGroup;
+ char *szDomainController;
+ char *szDomainAdminUsers;
+ char *szDomainGuestUsers;
+ char *szUsernameMap;
+ char *szCharacterSet;
+ char *szLogonScript;
+ char *szLogonPath;
+ char *szLogonDrive;
+ char *szLogonHome;
+ char *szSmbrun;
+ char *szWINSserver;
+ char *szInterfaces;
+ char *szRemoteAnnounce;
+ char *szSocketAddress;
+ char *szNISHomeMapName;
+ char *szAnnounceVersion; /* This is initialised in init_globals */
+ char *szNetbiosAliases;
+ char *szDomainSID;
+ char *szDomainOtherSIDs;
+ char *szDomainGroups;
+ char *szDriverFile;
+ int max_log_size;
+ int mangled_stack;
+ int max_xmit;
+ int max_mux;
+ int max_packet;
+ int pwordlevel;
+ int unamelevel;
+ int deadtime;
+ int maxprotocol;
+ int security;
+ int printing;
+ int maxdisksize;
+ int lpqcachetime;
+ int syslog;
+ int os_level;
+ int max_ttl;
+ int ReadSize;
+ int shmem_size;
+ int client_code_page;
+ int announce_as; /* This is initialised in init_globals */
+ BOOL bDNSproxy;
+ BOOL bWINSsupport;
+ BOOL bWINSproxy;
+ BOOL bLocalMaster;
+ BOOL bPreferredMaster;
+ BOOL bDomainMaster;
+ BOOL bDomainLogons;
+ BOOL bEncryptPasswords;
+ BOOL bStripDot;
+ BOOL bNullPasswords;
+ BOOL bLoadPrinters;
+ BOOL bUseRhosts;
+ BOOL bReadRaw;
+ BOOL bWriteRaw;
+ BOOL bReadPrediction;
+ BOOL bReadbmpx;
+ BOOL bSyslogOnly;
+ BOOL bBrowseList;
+ BOOL bUnixRealname;
+ BOOL bNISHomeMap;
+ BOOL bTimeServer;
+ BOOL bBindInterfacesOnly;
} global;
static global Globals;
@@ -192,12 +221,16 @@ typedef struct
char *szLppausecommand;
char *szLpresumecommand;
char *szPrintername;
+ char *szPrinterDriver;
+ char *szPrinterDriverLocation;
char *szDontdescend;
char *szHostsallow;
char *szHostsdeny;
char *szMagicScript;
char *szMagicOutput;
char *szMangledMap;
+ char *szVetoFiles;
+ char *szHideFiles;
char *comment;
char *force_user;
char *force_group;
@@ -205,7 +238,10 @@ typedef struct
char *writelist;
char *volume;
int iMinPrintSpace;
- int iCreate_mode;
+ int iCreate_mask;
+ int iCreate_force_mode;
+ int iDir_mask;
+ int iDir_force_mode;
int iMaxConnections;
int iDefaultCase;
BOOL bAlternatePerm;
@@ -230,12 +266,18 @@ typedef struct
BOOL bLocking;
BOOL bStrictLocking;
BOOL bShareModes;
+ BOOL bOpLocks;
BOOL bOnlyUser;
BOOL bMangledNames;
BOOL bWidelinks;
+ BOOL bSymlinks;
BOOL bSyncAlways;
char magic_char;
BOOL *copymap;
+ BOOL bDeleteReadonly;
+ BOOL bFakeOplocks;
+ BOOL bDeleteVetoFiles;
+ BOOL bDosFiletimes;
char dummy[3]; /* for alignment */
} service;
@@ -247,7 +289,7 @@ static service sDefault =
NULL, /* szService */
NULL, /* szPath */
NULL, /* szUsername */
- NULL, /* szGuestAccount */
+ NULL, /* szGuestAccount - this is set in init_globals() */
NULL, /* szInvalidUsers */
NULL, /* szValidUsers */
NULL, /* szAdminUsers */
@@ -263,12 +305,16 @@ static service sDefault =
NULL, /* szLppausecommand */
NULL, /* szLpresumecommand */
NULL, /* szPrintername */
+ NULL, /* szPrinterDriver - this is set in init_globals() */
+ NULL, /* szPrinterDriverLocation */
NULL, /* szDontdescend */
NULL, /* szHostsallow */
NULL, /* szHostsdeny */
NULL, /* szMagicScript */
NULL, /* szMagicOutput */
NULL, /* szMangledMap */
+ NULL, /* szVetoFiles */
+ NULL, /* szHideFiles */
NULL, /* comment */
NULL, /* force user */
NULL, /* force group */
@@ -276,7 +322,10 @@ static service sDefault =
NULL, /* writelist */
NULL, /* volume */
0, /* iMinPrintSpace */
- 0755, /* iCreate_mode */
+ 0744, /* iCreate_mask */
+ 0000, /* iCreate_force_mode */
+ 0755, /* iDir_mask */
+ 0000, /* iDir_force_mode */
0, /* iMaxConnections */
CASE_LOWER, /* iDefaultCase */
False, /* bAlternatePerm */
@@ -301,12 +350,18 @@ static service sDefault =
True, /* bLocking */
False, /* bStrictLocking */
True, /* bShareModes */
+ True, /* bOpLocks */
False, /* bOnlyUser */
True, /* bMangledNames */
True, /* bWidelinks */
+ True, /* bSymlinks */
False, /* bSyncAlways */
'~', /* magic char */
NULL, /* copymap */
+ False, /* bDeleteReadonly */
+ False, /* bFakeOplocks */
+ False, /* bDeleteVetoFiles */
+ False, /* bDosFiletimes */
"" /* dummy */
};
@@ -318,7 +373,7 @@ static int iNumServices = 0;
static int iServiceIndex = 0;
static BOOL bInGlobalSection = True;
static BOOL bGlobalOnly = False;
-
+static int default_server_announce;
#define NUMPARAMETERS (sizeof(parm_table) / sizeof(struct parm_struct))
@@ -331,9 +386,10 @@ static BOOL handle_security(char *pszParmValue,int *val);
static BOOL handle_case(char *pszParmValue,int *val);
static BOOL handle_printing(char *pszParmValue,int *val);
static BOOL handle_character_set(char *pszParmValue,int *val);
-#ifdef KANJI
+static BOOL handle_announce_as(char *pszParmValue, int *val);
static BOOL handle_coding_system(char *pszParmValue,int *val);
-#endif /* KANJI */
+
+static void set_default_server_announce_type(void);
struct parm_struct
{
@@ -353,6 +409,7 @@ struct parm_struct
{"printing", P_INTEGER, P_GLOBAL, &Globals.printing,handle_printing},
{"max disk size", P_INTEGER, P_GLOBAL, &Globals.maxdisksize, NULL},
{"lpq cache time", P_INTEGER, P_GLOBAL, &Globals.lpqcachetime, NULL},
+ {"announce as", P_INTEGER, P_GLOBAL, &Globals.announce_as, handle_announce_as},
{"encrypt passwords",P_BOOL, P_GLOBAL, &Globals.bEncryptPasswords, NULL},
{"getwd cache", P_BOOL, P_GLOBAL, &use_getwd_cache, NULL},
{"read prediction", P_BOOL, P_GLOBAL, &Globals.bReadPrediction, NULL},
@@ -363,9 +420,13 @@ struct parm_struct
{"load printers", P_BOOL, P_GLOBAL, &Globals.bLoadPrinters, NULL},
{"null passwords", P_BOOL, P_GLOBAL, &Globals.bNullPasswords, NULL},
{"strip dot", P_BOOL, P_GLOBAL, &Globals.bStripDot, NULL},
+ {"interfaces", P_STRING, P_GLOBAL, &Globals.szInterfaces, NULL},
+ {"bind interfaces only", P_BOOL,P_GLOBAL, &Globals.bBindInterfacesOnly,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},
+ {"netbios name", P_UGSTRING,P_GLOBAL, myname, NULL},
+ {"netbios aliases", P_STRING, P_GLOBAL, &Globals.szNetbiosAliases, 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},
@@ -387,11 +448,23 @@ struct parm_struct
{"passwd program", P_STRING, P_GLOBAL, &Globals.szPasswdProgram, NULL},
{"passwd chat", P_STRING, P_GLOBAL, &Globals.szPasswdChat, NULL},
{"valid chars", P_STRING, P_GLOBAL, &Globals.szValidChars, handle_valid_chars},
- {"workgroup", P_STRING, P_GLOBAL, &Globals.szWorkGroup, NULL},
+ {"workgroup", P_USTRING, P_GLOBAL, &Globals.szWorkGroup, NULL},
+ {"domain sid", P_USTRING, P_GLOBAL, &Globals.szDomainSID, NULL},
+ {"domain other sids", P_USTRING, P_GLOBAL, &Globals.szDomainOtherSIDs, NULL},
+ {"domain groups", P_USTRING, P_GLOBAL, &Globals.szDomainGroups, NULL},
{"domain controller",P_STRING, P_GLOBAL, &Globals.szDomainController,NULL},
+ {"domain admin users",P_STRING, P_GLOBAL, &Globals.szDomainAdminUsers, NULL},
+ {"domain guest users",P_STRING, P_GLOBAL, &Globals.szDomainGuestUsers, NULL},
{"username map", P_STRING, P_GLOBAL, &Globals.szUsernameMap, NULL},
{"character set", P_STRING, P_GLOBAL, &Globals.szCharacterSet, handle_character_set},
{"logon script", P_STRING, P_GLOBAL, &Globals.szLogonScript, NULL},
+ {"logon path", P_STRING, P_GLOBAL, &Globals.szLogonPath, NULL},
+ {"logon drive", P_STRING, P_GLOBAL, &Globals.szLogonDrive, NULL},
+ {"logon home", P_STRING, P_GLOBAL, &Globals.szLogonHome, NULL},
+ {"remote announce", P_STRING, P_GLOBAL, &Globals.szRemoteAnnounce, NULL},
+ {"socket address", P_STRING, P_GLOBAL, &Globals.szSocketAddress, NULL},
+ {"homedir map", P_STRING, P_GLOBAL, &Globals.szNISHomeMapName, NULL},
+ {"announce version", P_STRING, P_GLOBAL, &Globals.szAnnounceVersion, NULL},
{"max log size", P_INTEGER, P_GLOBAL, &Globals.max_log_size, NULL},
{"mangled stack", P_INTEGER, P_GLOBAL, &Globals.mangled_stack, NULL},
{"max mux", P_INTEGER, P_GLOBAL, &Globals.max_mux, NULL},
@@ -399,21 +472,30 @@ struct parm_struct
{"max packet", P_INTEGER, P_GLOBAL, &Globals.max_packet, NULL},
{"packet size", P_INTEGER, P_GLOBAL, &Globals.max_packet, NULL},
{"password level", P_INTEGER, P_GLOBAL, &Globals.pwordlevel, NULL},
+ {"username level", P_INTEGER, P_GLOBAL, &Globals.unamelevel, NULL},
{"keepalive", P_INTEGER, P_GLOBAL, &keepalive, NULL},
{"deadtime", P_INTEGER, P_GLOBAL, &Globals.deadtime, NULL},
{"time offset", P_INTEGER, P_GLOBAL, &extra_time_offset, NULL},
- {"read size", P_INTEGER, P_GLOBAL, &ReadSize, NULL},
-#ifdef KANJI
+ {"read size", P_INTEGER, P_GLOBAL, &Globals.ReadSize, NULL},
+ {"shared mem size", P_INTEGER, P_GLOBAL, &Globals.shmem_size, NULL},
{"coding system", P_INTEGER, P_GLOBAL, &coding_system, handle_coding_system},
-#endif /* KANJI */
+ {"client code page", P_INTEGER, P_GLOBAL, &Globals.client_code_page, NULL},
{"os level", P_INTEGER, P_GLOBAL, &Globals.os_level, NULL},
{"max ttl", P_INTEGER, P_GLOBAL, &Globals.max_ttl, NULL},
+ {"dns proxy", P_BOOL, P_GLOBAL, &Globals.bDNSproxy, 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},
+ {"local master", P_BOOL, P_GLOBAL, &Globals.bLocalMaster, NULL},
{"domain master", P_BOOL, P_GLOBAL, &Globals.bDomainMaster, NULL},
{"domain logons", P_BOOL, P_GLOBAL, &Globals.bDomainLogons, NULL},
{"browse list", P_BOOL, P_GLOBAL, &Globals.bBrowseList, NULL},
-
+ {"unix realname", P_BOOL, P_GLOBAL, &Globals.bUnixRealname, NULL},
+ {"NIS homedir", P_BOOL, P_GLOBAL, &Globals.bNISHomeMap, NULL},
+ {"time server", P_BOOL, P_GLOBAL, &Globals.bTimeServer, NULL},
+ {"printer driver file", P_STRING, P_GLOBAL, &Globals.szDriverFile, NULL},
{"-valid", P_BOOL, P_LOCAL, &sDefault.valid, NULL},
{"comment", P_STRING, P_LOCAL, &sDefault.comment, NULL},
{"copy", P_STRING, P_LOCAL, &sDefault.szCopy, handle_copy},
@@ -456,11 +538,18 @@ struct parm_struct
{"writable", P_BOOLREV, P_LOCAL, &sDefault.bRead_only, NULL},
{"max connections", P_INTEGER, P_LOCAL, &sDefault.iMaxConnections, NULL},
{"min print space", P_INTEGER, P_LOCAL, &sDefault.iMinPrintSpace, NULL},
- {"create mask", P_OCTAL, P_LOCAL, &sDefault.iCreate_mode, NULL},
- {"create mode", P_OCTAL, P_LOCAL, &sDefault.iCreate_mode, NULL},
+ {"create mask", P_OCTAL, P_LOCAL, &sDefault.iCreate_mask, NULL},
+ {"create mode", P_OCTAL, P_LOCAL, &sDefault.iCreate_mask, NULL},
+ {"force create mode",P_OCTAL, P_LOCAL, &sDefault.iCreate_force_mode, NULL},
+ {"directory mask", P_OCTAL, P_LOCAL, &sDefault.iDir_mask, NULL},
+ {"directory mode", P_OCTAL, P_LOCAL, &sDefault.iDir_mask, NULL},
+ {"force directory mode", P_OCTAL, P_LOCAL, &sDefault.iDir_force_mode, NULL},
{"set directory", P_BOOLREV, P_LOCAL, &sDefault.bNo_set_dir, NULL},
{"status", P_BOOL, P_LOCAL, &sDefault.status, NULL},
{"hide dot files", P_BOOL, P_LOCAL, &sDefault.bHideDotFiles, NULL},
+ {"delete veto files",P_BOOL, P_LOCAL, &sDefault.bDeleteVetoFiles, NULL},
+ {"veto files", P_STRING, P_LOCAL, &sDefault.szVetoFiles, NULL},
+ {"hide files", P_STRING, P_LOCAL, &sDefault.szHideFiles, NULL},
{"guest only", P_BOOL, P_LOCAL, &sDefault.bGuest_only, NULL},
{"only guest", P_BOOL, P_LOCAL, &sDefault.bGuest_only, NULL},
{"guest ok", P_BOOL, P_LOCAL, &sDefault.bGuest_ok, NULL},
@@ -474,10 +563,13 @@ struct parm_struct
{"locking", P_BOOL, P_LOCAL, &sDefault.bLocking, NULL},
{"strict locking", P_BOOL, P_LOCAL, &sDefault.bStrictLocking, NULL},
{"share modes", P_BOOL, P_LOCAL, &sDefault.bShareModes, NULL},
+ {"oplocks", P_BOOL, P_LOCAL, &sDefault.bOpLocks, NULL},
{"only user", P_BOOL, P_LOCAL, &sDefault.bOnlyUser, NULL},
{"wide links", P_BOOL, P_LOCAL, &sDefault.bWidelinks, NULL},
+ {"follow symlinks", P_BOOL, P_LOCAL, &sDefault.bSymlinks, NULL},
{"sync always", P_BOOL, P_LOCAL, &sDefault.bSyncAlways, NULL},
{"mangled names", P_BOOL, P_LOCAL, &sDefault.bMangledNames, NULL},
+ {"fake oplocks", P_BOOL, P_LOCAL, &sDefault.bFakeOplocks, NULL},
{"print command", P_STRING, P_LOCAL, &sDefault.szPrintcommand, NULL},
{"lpq command", P_STRING, P_LOCAL, &sDefault.szLpqcommand, NULL},
{"lprm command", P_STRING, P_LOCAL, &sDefault.szLprmcommand, NULL},
@@ -485,6 +577,8 @@ struct parm_struct
{"lpresume command", P_STRING, P_LOCAL, &sDefault.szLpresumecommand,NULL},
{"printer", P_STRING, P_LOCAL, &sDefault.szPrintername, NULL},
{"printer name", P_STRING, P_LOCAL, &sDefault.szPrintername, NULL},
+ {"printer driver", P_STRING, P_LOCAL, &sDefault.szPrinterDriver, NULL},
+ {"printer driver location", P_STRING, P_LOCAL, &sDefault.szPrinterDriverLocation, NULL},
{"hosts allow", P_STRING, P_LOCAL, &sDefault.szHostsallow, NULL},
{"allow hosts", P_STRING, P_LOCAL, &sDefault.szHostsallow, NULL},
{"hosts deny", P_STRING, P_LOCAL, &sDefault.szHostsdeny, NULL},
@@ -493,6 +587,8 @@ 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},
+ {"dos filetimes", P_BOOL, P_LOCAL, &sDefault.bDosFiletimes, NULL},
{NULL, P_BOOL, P_NONE, NULL, NULL}
};
@@ -513,11 +609,13 @@ static void init_globals(void)
bzero((void *)&Globals,sizeof(Globals));
for (i = 0; parm_table[i].label; i++)
- if (parm_table[i].type == P_STRING &&
+ if ((parm_table[i].type == P_STRING ||
+ parm_table[i].type == P_USTRING) &&
parm_table[i].ptr)
string_init(parm_table[i].ptr,"");
string_set(&sDefault.szGuestaccount, GUEST_ACCOUNT);
+ string_set(&sDefault.szPrinterDriver, "NULL");
done_init = True;
}
@@ -530,24 +628,32 @@ static void init_globals(void)
#endif
string_set(&Globals.szPasswdChat,"*old*password* %o\\n *new*password* %n\\n *new*password* %n\\n *changed*");
string_set(&Globals.szWorkGroup, WORKGROUP);
-#ifdef SMB_PASSWD
string_set(&Globals.szPasswdProgram, SMB_PASSWD);
-#else
- string_set(&Globals.szPasswdProgram, "/bin/passwd");
-#endif
string_set(&Globals.szPrintcapname, PRINTCAP_NAME);
+ string_set(&Globals.szDriverFile, DRIVERFILE);
string_set(&Globals.szLockDir, LOCKDIR);
string_set(&Globals.szRootdir, "/");
+ string_set(&Globals.szSmbrun, SMBRUN);
+ string_set(&Globals.szSocketAddress, "0.0.0.0");
sprintf(s,"Samba %s",VERSION);
string_set(&Globals.szServerString,s);
+ sprintf(s,"%d.%d", DEFAULT_MAJOR_VERSION, DEFAULT_MINOR_VERSION);
+ string_set(&Globals.szAnnounceVersion,s);
+
+ string_set(&Globals.szLogonDrive, "");
+ /* %N is the NIS auto.home server if -DAUTOHOME is used, else same as %L */
+ string_set(&Globals.szLogonHome, "\\\\%N\\%U");
+ string_set(&Globals.szLogonPath, "\\\\%N\\%U\\profile");
+
Globals.bLoadPrinters = True;
Globals.bUseRhosts = False;
Globals.max_packet = 65535;
Globals.mangled_stack = 50;
- Globals.max_xmit = Globals.max_packet;
- Globals.max_mux = 2;
+ Globals.max_xmit = 65535;
+ Globals.max_mux = 50; /* This is *needed* for profile support. */
Globals.lpqcachetime = 10;
Globals.pwordlevel = 0;
+ Globals.unamelevel = 0;
Globals.deadtime = 0;
Globals.max_log_size = 5000;
Globals.maxprotocol = PROTOCOL_NT1;
@@ -564,15 +670,51 @@ static void init_globals(void)
Globals.bSyslogOnly = False;
Globals.os_level = 0;
Globals.max_ttl = 60*60*4; /* 2 hours default */
- Globals.bPreferredMaster = True;
+ Globals.ReadSize = 16*1024;
+ Globals.shmem_size = SHMEM_SIZE;
+ Globals.announce_as = ANNOUNCE_AS_NT;
+ Globals.bUnixRealname = False;
+#if (defined(NETGROUP) && defined(AUTOMOUNT))
+ Globals.bNISHomeMap = False;
+ string_set(&Globals.szNISHomeMapName, "auto.home");
+#endif
+ coding_system = interpret_coding_system (KANJI, SJIS_CODE);
+ Globals.client_code_page = DEFAULT_CLIENT_CODE_PAGE;
+ Globals.bTimeServer = False;
+ Globals.bBindInterfacesOnly = False;
+
+/* these parameters are set to defaults that are more appropriate
+ for the increasing samba install base:
+
+ as a member of the workgroup, that will possibly become a
+ _local_ master browser (lm = True). this is opposed to a forced
+ local master browser startup (pm = True).
+
+ doesn't provide WINS server service by default (wsupp = False),
+ and doesn't provide domain master browser services by default, either.
+
+*/
+
+ Globals.bPreferredMaster = False;
+ Globals.bLocalMaster = True;
Globals.bDomainMaster = False;
Globals.bDomainLogons = False;
Globals.bBrowseList = True;
+ Globals.bWINSsupport = False;
+ Globals.bWINSproxy = False;
-#ifdef KANJI
- coding_system = interpret_coding_system (KANJI, SJIS_CODE);
-#endif /* KANJI */
+/* this parameter is currently set to the default functionality
+ in samba. given that w95 and NT is starting to use DNS for
+ server resolution, i expect that at some point it would be
+ sensible to default this to False.
+ this parameter is added because nmbd is a single process, and
+ gethostbyname is a blocking call, which can take out nmbd for
+ several seconds while a dns lookup is performed.
+
+ */
+
+ Globals.bDNSproxy = True;
}
/***************************************************************************
@@ -595,6 +737,8 @@ static void init_locals(void)
{
case PRINT_BSD:
case PRINT_AIX:
+ case PRINT_LPRNG:
+ 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");
@@ -622,24 +766,51 @@ static void init_locals(void)
}
-/*******************************************************************
-a convenience rooutine to grab string parameters into a rotating
-static buffer, and run standard_sub_basic on them. The buffers
-can be written to by callers
+/******************************************************************* a
+convenience routine to grab string parameters into a rotating buffer,
+and run standard_sub_basic on them. The buffers can be written to by
+callers without affecting the source string.
********************************************************************/
char *lp_string(char *s)
{
- static pstring bufs[10];
- static int next=0;
+ static char *bufs[10];
+ static int buflen[10];
+ static int next = -1;
char *ret;
-
+ int i;
+ int len = s?strlen(s):0;
+
+ if (next == -1) {
+ /* initialisation */
+ for (i=0;i<10;i++) {
+ bufs[i] = NULL;
+ buflen[i] = 0;
+ }
+ next = 0;
+ }
+
+ len = MAX(len+100,sizeof(pstring)); /* the +100 is for some
+ substitution room */
+
+ if (buflen[next] != len) {
+ buflen[next] = len;
+ if (bufs[next]) free(bufs[next]);
+ bufs[next] = (char *)malloc(len);
+ if (!bufs[next]) {
+ DEBUG(0,("out of memory in lp_string()"));
+ exit(1);
+ }
+ }
+
ret = &bufs[next][0];
next = (next+1)%10;
if (!s)
*ret = 0;
else
- StrnCpy(ret,s,sizeof(pstring)-1);
+ StrCpy(ret,s);
+
+ trim_string(ret, "\"", "\"");
standard_sub_basic(ret);
return(ret);
@@ -670,6 +841,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 +861,28 @@ 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_logon_path,&Globals.szLogonPath)
+FN_GLOBAL_STRING(lp_logon_drive,&Globals.szLogonDrive)
+FN_GLOBAL_STRING(lp_logon_home,&Globals.szLogonHome)
+FN_GLOBAL_STRING(lp_remote_announce,&Globals.szRemoteAnnounce)
+FN_GLOBAL_STRING(lp_wins_server,&Globals.szWINSserver)
+FN_GLOBAL_STRING(lp_interfaces,&Globals.szInterfaces)
+FN_GLOBAL_STRING(lp_socket_address,&Globals.szSocketAddress)
+FN_GLOBAL_STRING(lp_nis_home_map_name,&Globals.szNISHomeMapName)
+FN_GLOBAL_STRING(lp_announce_version,&Globals.szAnnounceVersion)
+FN_GLOBAL_STRING(lp_netbios_aliases,&Globals.szNetbiosAliases)
+FN_GLOBAL_STRING(lp_driverfile,&Globals.szDriverFile)
+
+FN_GLOBAL_STRING(lp_domain_sid,&Globals.szDomainSID)
+FN_GLOBAL_STRING(lp_domain_other_sids,&Globals.szDomainOtherSIDs)
+FN_GLOBAL_STRING(lp_domain_groups,&Globals.szDomainGroups)
+FN_GLOBAL_STRING(lp_domain_admin_users,&Globals.szDomainAdminUsers)
+FN_GLOBAL_STRING(lp_domain_guest_users,&Globals.szDomainGuestUsers)
+
+FN_GLOBAL_BOOL(lp_dns_proxy,&Globals.bDNSproxy)
+FN_GLOBAL_BOOL(lp_wins_support,&Globals.bWINSsupport)
+FN_GLOBAL_BOOL(lp_wins_proxy,&Globals.bWINSproxy)
+FN_GLOBAL_BOOL(lp_local_master,&Globals.bLocalMaster)
FN_GLOBAL_BOOL(lp_domain_master,&Globals.bDomainMaster)
FN_GLOBAL_BOOL(lp_domain_logons,&Globals.bDomainLogons)
FN_GLOBAL_BOOL(lp_preferred_master,&Globals.bPreferredMaster)
@@ -705,6 +898,10 @@ FN_GLOBAL_BOOL(lp_strip_dot,&Globals.bStripDot)
FN_GLOBAL_BOOL(lp_encrypted_passwords,&Globals.bEncryptPasswords)
FN_GLOBAL_BOOL(lp_syslog_only,&Globals.bSyslogOnly)
FN_GLOBAL_BOOL(lp_browse_list,&Globals.bBrowseList)
+FN_GLOBAL_BOOL(lp_unix_realname,&Globals.bUnixRealname)
+FN_GLOBAL_BOOL(lp_nis_home_map,&Globals.bNISHomeMap)
+FN_GLOBAL_BOOL(lp_time_server,&Globals.bTimeServer)
+FN_GLOBAL_BOOL(lp_bind_interfaces_only,&Globals.bBindInterfacesOnly)
FN_GLOBAL_INTEGER(lp_os_level,&Globals.os_level)
FN_GLOBAL_INTEGER(lp_max_ttl,&Globals.max_ttl)
@@ -715,6 +912,9 @@ FN_GLOBAL_INTEGER(lp_maxmux,&Globals.max_mux)
FN_GLOBAL_INTEGER(lp_maxpacket,&Globals.max_packet)
FN_GLOBAL_INTEGER(lp_keepalive,&keepalive)
FN_GLOBAL_INTEGER(lp_passwordlevel,&Globals.pwordlevel)
+FN_GLOBAL_INTEGER(lp_usernamelevel,&Globals.unamelevel)
+FN_GLOBAL_INTEGER(lp_readsize,&Globals.ReadSize)
+FN_GLOBAL_INTEGER(lp_shmem_size,&Globals.shmem_size)
FN_GLOBAL_INTEGER(lp_deadtime,&Globals.deadtime)
FN_GLOBAL_INTEGER(lp_maxprotocol,&Globals.maxprotocol)
FN_GLOBAL_INTEGER(lp_security,&Globals.security)
@@ -722,6 +922,8 @@ FN_GLOBAL_INTEGER(lp_printing,&Globals.printing)
FN_GLOBAL_INTEGER(lp_maxdisksize,&Globals.maxdisksize)
FN_GLOBAL_INTEGER(lp_lpqcachetime,&Globals.lpqcachetime)
FN_GLOBAL_INTEGER(lp_syslog,&Globals.syslog)
+FN_GLOBAL_INTEGER(lp_client_code_page,&Globals.client_code_page)
+FN_GLOBAL_INTEGER(lp_announce_as,&Globals.announce_as)
FN_LOCAL_STRING(lp_preexec,szPreExec)
FN_LOCAL_STRING(lp_postexec,szPostExec)
@@ -741,6 +943,7 @@ FN_LOCAL_STRING(lp_lprmcommand,szLprmcommand)
FN_LOCAL_STRING(lp_lppausecommand,szLppausecommand)
FN_LOCAL_STRING(lp_lpresumecommand,szLpresumecommand)
FN_LOCAL_STRING(lp_printername,szPrintername)
+FN_LOCAL_STRING(lp_printerdriver,szPrinterDriver)
FN_LOCAL_STRING(lp_hostsallow,szHostsallow)
FN_LOCAL_STRING(lp_hostsdeny,szHostsdeny)
FN_LOCAL_STRING(lp_magicscript,szMagicScript)
@@ -752,6 +955,9 @@ FN_LOCAL_STRING(lp_readlist,readlist)
FN_LOCAL_STRING(lp_writelist,writelist)
FN_LOCAL_STRING(lp_volume,volume)
FN_LOCAL_STRING(lp_mangled_map,szMangledMap)
+FN_LOCAL_STRING(lp_veto_files,szVetoFiles)
+FN_LOCAL_STRING(lp_hide_files,szHideFiles)
+FN_LOCAL_STRING(lp_driverlocation,szPrinterDriverLocation)
FN_LOCAL_BOOL(lp_alternate_permissions,bAlternatePerm)
FN_LOCAL_BOOL(lp_revalidate,bRevalidate)
@@ -773,13 +979,22 @@ FN_LOCAL_BOOL(lp_map_archive,bMap_archive)
FN_LOCAL_BOOL(lp_locking,bLocking)
FN_LOCAL_BOOL(lp_strict_locking,bStrictLocking)
FN_LOCAL_BOOL(lp_share_modes,bShareModes)
+FN_LOCAL_BOOL(lp_oplocks,bOpLocks)
FN_LOCAL_BOOL(lp_onlyuser,bOnlyUser)
FN_LOCAL_BOOL(lp_manglednames,bMangledNames)
FN_LOCAL_BOOL(lp_widelinks,bWidelinks)
+FN_LOCAL_BOOL(lp_symlinks,bSymlinks)
FN_LOCAL_BOOL(lp_syncalways,bSyncAlways)
FN_LOCAL_BOOL(lp_map_system,bMap_system)
-
-FN_LOCAL_INTEGER(lp_create_mode,iCreate_mode)
+FN_LOCAL_BOOL(lp_delete_readonly,bDeleteReadonly)
+FN_LOCAL_BOOL(lp_fake_oplocks,bFakeOplocks)
+FN_LOCAL_BOOL(lp_recursive_veto_delete,bDeleteVetoFiles)
+FN_LOCAL_BOOL(lp_dos_filetimes,bDosFiletimes)
+
+FN_LOCAL_INTEGER(lp_create_mode,iCreate_mask)
+FN_LOCAL_INTEGER(lp_force_create_mode,iCreate_force_mode)
+FN_LOCAL_INTEGER(lp_dir_mode,iDir_mask)
+FN_LOCAL_INTEGER(lp_force_dir_mode,iDir_force_mode)
FN_LOCAL_INTEGER(lp_max_connections,iMaxConnections)
FN_LOCAL_INTEGER(lp_defaultcase,iDefaultCase)
FN_LOCAL_INTEGER(lp_minprintspace,iMinPrintSpace)
@@ -799,8 +1014,6 @@ static void copy_service( service *pserviceDest,
static BOOL service_ok(int iService);
static BOOL do_parameter(char *pszParmName, char *pszParmValue);
static BOOL do_section(char *pszSectionName);
-static void dump_globals(void);
-static void dump_a_service(service *pService);
static void init_copymap(service *pservice);
@@ -824,7 +1037,9 @@ static void free_service(service *pservice)
return;
for (i=0;parm_table[i].label;i++)
- if (parm_table[i].type == P_STRING && parm_table[i].class == P_LOCAL)
+ if ((parm_table[i].type == P_STRING ||
+ parm_table[i].type == P_STRING) &&
+ parm_table[i].class == P_LOCAL)
string_free((char **)(((char *)pservice) + PTR_DIFF(parm_table[i].ptr,&sDefault)));
}
@@ -927,7 +1142,7 @@ static BOOL lp_add_ipc(void)
sprintf(comment,"IPC Service (%s)",lp_serverstring());
- string_set(&iSERVICE(i).szPath,"/tmp");
+ string_set(&iSERVICE(i).szPath,tmpdir());
string_set(&iSERVICE(i).szUsername,"");
string_set(&iSERVICE(i).comment,comment);
iSERVICE(i).status = False;
@@ -965,6 +1180,14 @@ BOOL lp_add_printer(char *pszPrintername, int iDefaultService)
string_set(&iSERVICE(i).szPrintername,pszPrintername);
string_set(&iSERVICE(i).comment,comment);
iSERVICE(i).bBrowseable = sDefault.bBrowseable;
+ /* Printers cannot be read_only. */
+ iSERVICE(i).bRead_only = False;
+ /* No share modes on printer services. */
+ iSERVICE(i).bShareModes = False;
+ /* No oplocks on printer services. */
+ iSERVICE(i).bOpLocks = False;
+ /* Printer services must be printable. */
+ iSERVICE(i).bPrint_ok = True;
DEBUG(3,("adding printer service %s\n",pszPrintername));
@@ -1113,6 +1336,11 @@ static void copy_service(service *pserviceDest,
case P_STRING:
string_set(dest_ptr,*(char **)src_ptr);
break;
+
+ case P_USTRING:
+ string_set(dest_ptr,*(char **)src_ptr);
+ strupper(*(char **)dest_ptr);
+ break;
default:
break;
}
@@ -1156,8 +1384,8 @@ static BOOL service_ok(int iService)
if (iSERVICE(iService).szPath[0] == '\0' &&
strwicmp(iSERVICE(iService).szService,HOMES_NAME) != 0)
{
- DEBUG(0,("No path in service %s - using /tmp\n",iSERVICE(iService).szService));
- string_set(&iSERVICE(iService).szPath,"/tmp");
+ DEBUG(0,("No path in service %s - using %s\n",iSERVICE(iService).szService,tmpdir()));
+ string_set(&iSERVICE(iService).szPath,tmpdir());
}
/* If a service is flagged unavailable, log the fact at level 0. */
@@ -1201,7 +1429,7 @@ static void add_to_file_list(char *fname)
{
pstring n2;
- strcpy(n2,fname);
+ pstrcpy(n2,fname);
standard_sub_basic(n2);
f->modtime = file_modtime(n2);
}
@@ -1214,17 +1442,31 @@ check if a config file has changed date
BOOL lp_file_list_changed(void)
{
struct file_lists *f = file_lists;
- while (f) {
+ DEBUG(6,("lp_file_list_changed()\n"));
+
+ while (f)
+ {
pstring n2;
- strcpy(n2,f->name);
+ time_t mod_time;
+
+ pstrcpy(n2,f->name);
standard_sub_basic(n2);
- if (f->modtime != file_modtime(n2)) return(True);
+
+ DEBUG(6,("file %s -> %s last mod_time: %s\n",
+ f->name, n2, ctime(&f->modtime)));
+
+ mod_time = file_modtime(n2);
+
+ if (f->modtime != mod_time) {
+ DEBUG(6,("file %s modified: %s\n", n2, ctime(&mod_time)));
+ f->modtime = mod_time;
+ return(True);
+ }
f = f->next;
}
return(False);
}
-#ifdef KANJI
/***************************************************************************
handle the interpretation of the coding system parameter
*************************************************************************/
@@ -1233,7 +1475,6 @@ static BOOL handle_coding_system(char *pszParmValue,int *val)
*val = interpret_coding_system(pszParmValue,*val);
return(True);
}
-#endif /* KANJI */
/***************************************************************************
handle the interpretation of the character set system parameter
@@ -1269,9 +1510,9 @@ handle the interpretation of the default case
***************************************************************************/
static BOOL handle_case(char *pszParmValue,int *val)
{
- if (strequal(pszParmValue,"LOWER"))
+ if (strnequal(pszParmValue,"LOWER", 5))
*val = CASE_LOWER;
- else if (strequal(pszParmValue,"UPPER"))
+ else if (strnequal(pszParmValue,"UPPER", 5))
*val = CASE_UPPER;
return(True);
}
@@ -1281,26 +1522,50 @@ handle the interpretation of the printing system
***************************************************************************/
static BOOL handle_printing(char *pszParmValue,int *val)
{
- if (strequal(pszParmValue,"sysv"))
+ if (strnequal(pszParmValue,"sysv", 4))
*val = PRINT_SYSV;
- else if (strequal(pszParmValue,"aix"))
+ else if (strnequal(pszParmValue,"aix", 3))
*val = PRINT_AIX;
- else if (strequal(pszParmValue,"hpux"))
+ else if (strnequal(pszParmValue,"hpux", 4))
*val = PRINT_HPUX;
- else if (strequal(pszParmValue,"bsd"))
+ else if (strnequal(pszParmValue,"bsd", 3))
*val = PRINT_BSD;
- else if (strequal(pszParmValue,"qnx"))
+ else if (strnequal(pszParmValue,"qnx",3))
*val = PRINT_QNX;
+ else if (strnequal(pszParmValue,"plp", 3))
+ *val = PRINT_PLP;
+ else if (strnequal(pszParmValue,"lprng", 5))
+ *val = PRINT_LPRNG;
return(True);
}
/***************************************************************************
+handle the announce as parameter
+***************************************************************************/
+static BOOL handle_announce_as(char *pszParmValue,int *val)
+{
+ if (strnequal(pszParmValue,"NT", 2))
+ *val = ANNOUNCE_AS_NT;
+ else if (strnequal(pszParmValue,"win95", 5))
+ *val = ANNOUNCE_AS_WIN95;
+ else if (strnequal(pszParmValue,"WfW", 3))
+ *val = ANNOUNCE_AS_WFW;
+ return True;
+}
+
+/***************************************************************************
handle the valid chars lines
***************************************************************************/
static BOOL handle_valid_chars(char *pszParmValue,char **ptr)
{
string_set(ptr,pszParmValue);
+ /* A dependency here is that the parameter client code page must be
+ set before this is called - as calling codepage_initialise()
+ would overwrite the valid char lines.
+ */
+ codepage_initialise(lp_client_code_page());
+
add_char_string(pszParmValue);
return(True);
}
@@ -1312,7 +1577,7 @@ handle the include operation
static BOOL handle_include(char *pszParmValue,char **ptr)
{
pstring fname;
- strcpy(fname,pszParmValue);
+ pstrcpy(fname,pszParmValue);
add_to_file_list(fname);
@@ -1390,18 +1655,15 @@ static void init_copymap(service *pservice)
/***************************************************************************
-Process a parameter.
+Process a parameter for a particular service number. If snum < 0
+then assume we are in the globals
***************************************************************************/
-static BOOL do_parameter(char *pszParmName, char *pszParmValue)
+BOOL lp_do_parameter(int snum, char *pszParmName, char *pszParmValue)
{
int parmnum;
void *parm_ptr=NULL; /* where we are going to store the result */
void *def_ptr=NULL;
- if (!bInGlobalSection && bGlobalOnly) return(True);
-
- DEBUG(3,("doing parameter %s = %s\n",pszParmName,pszParmValue));
-
parmnum = map_parameter(pszParmName);
if (parmnum < 0)
@@ -1413,37 +1675,33 @@ static BOOL do_parameter(char *pszParmName, char *pszParmValue)
def_ptr = parm_table[parmnum].ptr;
/* we might point at a service, the default service or a global */
- if (bInGlobalSection)
+ if (snum < 0) {
parm_ptr = def_ptr;
- else
- {
- if (parm_table[parmnum].class == P_GLOBAL)
- {
+ } else {
+ if (parm_table[parmnum].class == P_GLOBAL) {
DEBUG(0,( "Global parameter %s found in service section!\n",pszParmName));
return(True);
}
- parm_ptr = ((char *)pSERVICE(iServiceIndex)) + PTR_DIFF(def_ptr,&sDefault);
- }
+ parm_ptr = ((char *)pSERVICE(snum)) + PTR_DIFF(def_ptr,&sDefault);
+ }
- if (!bInGlobalSection)
- {
- int i;
- if (!iSERVICE(iServiceIndex).copymap)
- init_copymap(pSERVICE(iServiceIndex));
-
- /* this handles the aliases - set the copymap for other entries with
- the same data pointer */
- for (i=0;parm_table[i].label;i++)
- if (parm_table[i].ptr == parm_table[parmnum].ptr)
- iSERVICE(iServiceIndex).copymap[i] = False;
- }
+ if (snum >= 0) {
+ int i;
+ if (!iSERVICE(snum).copymap)
+ init_copymap(pSERVICE(snum));
+
+ /* this handles the aliases - set the copymap for other entries with
+ the same data pointer */
+ for (i=0;parm_table[i].label;i++)
+ if (parm_table[i].ptr == parm_table[parmnum].ptr)
+ iSERVICE(snum).copymap[i] = False;
+ }
/* if it is a special case then go ahead */
- if (parm_table[parmnum].special)
- {
- parm_table[parmnum].special(pszParmValue,parm_ptr);
- return(True);
- }
+ if (parm_table[parmnum].special) {
+ parm_table[parmnum].special(pszParmValue,parm_ptr);
+ return(True);
+ }
/* now switch on the type of variable it is */
switch (parm_table[parmnum].type)
@@ -1473,55 +1731,124 @@ static BOOL do_parameter(char *pszParmName, char *pszParmValue)
string_set(parm_ptr,pszParmValue);
break;
+ case P_USTRING:
+ string_set(parm_ptr,pszParmValue);
+ strupper(*(char **)parm_ptr);
+ break;
+
case P_GSTRING:
strcpy((char *)parm_ptr,pszParmValue);
break;
+
+ case P_UGSTRING:
+ strcpy((char *)parm_ptr,pszParmValue);
+ strupper((char *)parm_ptr);
+ break;
}
return(True);
}
/***************************************************************************
+Process a parameter.
+***************************************************************************/
+static BOOL do_parameter(char *pszParmName, char *pszParmValue)
+{
+ if (!bInGlobalSection && bGlobalOnly) return(True);
+
+ DEBUG(3,("doing parameter %s = %s\n",pszParmName,pszParmValue));
+
+ return lp_do_parameter(bInGlobalSection?-2:iServiceIndex, pszParmName, pszParmValue);
+}
+
+
+/***************************************************************************
print a parameter of the specified type
***************************************************************************/
-static void print_parameter(parm_type type,void *ptr)
+static void print_parameter(parm_type type,void *ptr, FILE *f)
{
switch (type)
{
case P_BOOL:
- printf("%s",BOOLSTR(*(BOOL *)ptr));
+ fprintf(f,"%s",BOOLSTR(*(BOOL *)ptr));
break;
case P_BOOLREV:
- printf("%s",BOOLSTR(! *(BOOL *)ptr));
+ fprintf(f,"%s",BOOLSTR(! *(BOOL *)ptr));
break;
case P_INTEGER:
- printf("%d",*(int *)ptr);
+ fprintf(f,"%d",*(int *)ptr);
break;
case P_CHAR:
- printf("%c",*(char *)ptr);
+ fprintf(f,"%c",*(char *)ptr);
break;
case P_OCTAL:
- printf("0%o",*(int *)ptr);
+ fprintf(f,"0%o",*(int *)ptr);
break;
case P_GSTRING:
+ case P_UGSTRING:
if ((char *)ptr)
- printf("%s",(char *)ptr);
+ fprintf(f,"%s",(char *)ptr);
break;
case P_STRING:
+ case P_USTRING:
if (*(char **)ptr)
- printf("%s",*(char **)ptr);
+ fprintf(f,"%s",*(char **)ptr);
break;
}
}
/***************************************************************************
+print a parameter of the specified type
+***************************************************************************/
+static void parameter_string(parm_type type,void *ptr,char *s)
+{
+ s[0] = 0;
+
+ switch (type)
+ {
+ case P_BOOL:
+ sprintf(s, "%s",BOOLSTR(*(BOOL *)ptr));
+ break;
+
+ case P_BOOLREV:
+ sprintf(s, "%s",BOOLSTR(! *(BOOL *)ptr));
+ break;
+
+ case P_INTEGER:
+ sprintf(s, "%d",*(int *)ptr);
+ break;
+
+ case P_CHAR:
+ sprintf(s, "%c",*(char *)ptr);
+ break;
+
+ case P_OCTAL:
+ sprintf(s, "0%o",*(int *)ptr);
+ break;
+
+ case P_GSTRING:
+ case P_UGSTRING:
+ if ((char *)ptr)
+ sprintf(s, "%s",(char *)ptr);
+ break;
+
+ case P_STRING:
+ case P_USTRING:
+ if (*(char **)ptr)
+ sprintf(s, "%s",*(char **)ptr);
+ break;
+ }
+}
+
+
+/***************************************************************************
check if two parameters are equal
***************************************************************************/
static BOOL equal_parameter(parm_type type,void *ptr1,void *ptr2)
@@ -1540,6 +1867,7 @@ static BOOL equal_parameter(parm_type type,void *ptr1,void *ptr2)
return(*((char *)ptr1) == *((char *)ptr2));
case P_GSTRING:
+ case P_UGSTRING:
{
char *p1 = (char *)ptr1, *p2 = (char *)ptr2;
if (p1 && !*p1) p1 = NULL;
@@ -1547,6 +1875,7 @@ static BOOL equal_parameter(parm_type type,void *ptr1,void *ptr2)
return(p1==p2 || strequal(p1,p2));
}
case P_STRING:
+ case P_USTRING:
{
char *p1 = *(char **)ptr1, *p2 = *(char **)ptr2;
if (p1 && !*p1) p1 = NULL;
@@ -1611,32 +1940,32 @@ static BOOL do_section(char *pszSectionName)
/***************************************************************************
Display the contents of the global structure.
***************************************************************************/
-static void dump_globals(void)
+static void dump_globals(FILE *f)
{
int i;
- printf("Global parameters:\n");
+ fprintf(f, "# Global parameters\n");
for (i=0;parm_table[i].label;i++)
if (parm_table[i].class == P_GLOBAL &&
parm_table[i].ptr &&
(i == 0 || (parm_table[i].ptr != parm_table[i-1].ptr)))
{
- printf("\t%s: ",parm_table[i].label);
- print_parameter(parm_table[i].type,parm_table[i].ptr);
- printf("\n");
+ fprintf(f,"\t%s = ",parm_table[i].label);
+ print_parameter(parm_table[i].type,parm_table[i].ptr, f);
+ fprintf(f,"\n");
}
}
/***************************************************************************
Display the contents of a single services record.
***************************************************************************/
-static void dump_a_service(service *pService)
+static void dump_a_service(service *pService, FILE *f)
{
int i;
if (pService == &sDefault)
- printf("\nDefault service parameters:\n");
+ fprintf(f,"\n\n# Default service parameters\n");
else
- printf("\nService parameters [%s]:\n",pService->szService);
+ fprintf(f,"\n[%s]\n",pService->szService);
for (i=0;parm_table[i].label;i++)
if (parm_table[i].class == P_LOCAL &&
@@ -1650,14 +1979,69 @@ static void dump_a_service(service *pService)
((char *)pService) + pdiff,
((char *)&sDefault) + pdiff))
{
- printf("\t%s: ",parm_table[i].label);
+ fprintf(f,"\t%s = ",parm_table[i].label);
print_parameter(parm_table[i].type,
- ((char *)pService) + pdiff);
- printf("\n");
+ ((char *)pService) + pdiff, f);
+ fprintf(f,"\n");
}
}
}
+
+/***************************************************************************
+return info about the next service in a service. snum==-1 gives the default
+serice and snum==-2 gives the globals
+
+return 0 when out of parameters
+***************************************************************************/
+int lp_next_parameter(int snum, int *i, char *label,
+ char *value, int allparameters)
+{
+ if (snum == -2) {
+ /* do the globals */
+ for (;parm_table[*i].label;(*i)++)
+ if (parm_table[*i].class == P_GLOBAL &&
+ parm_table[*i].ptr &&
+ (*parm_table[*i].label != '-') &&
+ ((*i) == 0 ||
+ (parm_table[*i].ptr != parm_table[(*i)-1].ptr))) {
+ strcpy(label, parm_table[*i].label);
+ parameter_string(parm_table[*i].type,
+ parm_table[*i].ptr,
+ value);
+ (*i)++;
+ return 1;
+ }
+ return 0;
+ } else {
+ service *pService = (snum==-1?&sDefault:pSERVICE(snum));
+
+ for (;parm_table[*i].label;(*i)++)
+ if (parm_table[*i].class == P_LOCAL &&
+ parm_table[*i].ptr &&
+ (*parm_table[*i].label != '-') &&
+ ((*i) == 0 ||
+ (parm_table[*i].ptr != parm_table[(*i)-1].ptr))) {
+ int pdiff = PTR_DIFF(parm_table[*i].ptr,&sDefault);
+
+ if (snum == -1 || allparameters ||
+ !equal_parameter(parm_table[*i].type,
+ ((char *)pService) + pdiff,
+ ((char *)&sDefault) + pdiff)) {
+ strcpy(label, parm_table[*i].label);
+ parameter_string(parm_table[*i].type,
+ ((char *)pService) + pdiff,
+ value);
+ (*i)++;
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
#if 0
/***************************************************************************
Display the contents of a single copy structure.
@@ -1766,7 +2150,7 @@ void lp_killunused(BOOL (*snumused)(int ))
{
int i;
for (i=0;i<iNumServices;i++)
- if (VALID(i) && !snumused(i))
+ if (VALID(i) && (!snumused || !snumused(i)))
{
iSERVICE(i).valid = False;
free_service(pSERVICE(i));
@@ -1781,7 +2165,7 @@ BOOL lp_load(char *pszFname,BOOL global_only)
{
pstring n2;
BOOL bRetval;
-
+
add_to_file_list(pszFname);
bRetval = False;
@@ -1791,7 +2175,7 @@ BOOL lp_load(char *pszFname,BOOL global_only)
init_globals();
- strcpy(n2,pszFname);
+ pstrcpy(n2,pszFname);
standard_sub_basic(n2);
/* We get sections first, so have to start 'behind' to make up */
@@ -1810,6 +2194,8 @@ BOOL lp_load(char *pszFname,BOOL global_only)
lp_add_ipc();
+ set_default_server_announce_type();
+
bLoaded = True;
return (bRetval);
@@ -1827,13 +2213,13 @@ int lp_numservices(void)
/***************************************************************************
Display the contents of the services array in human-readable form.
***************************************************************************/
-void lp_dump(void)
+void lp_dump(FILE *f)
{
int iService;
- dump_globals();
+ dump_globals(f);
- dump_a_service(&sDefault);
+ dump_a_service(&sDefault, f);
for (iService = 0; iService < iNumServices; iService++)
{
@@ -1841,11 +2227,12 @@ void lp_dump(void)
{
if (iSERVICE(iService).szService[0] == '\0')
break;
- dump_a_service(pSERVICE(iService));
+ dump_a_service(pSERVICE(iService), f);
}
}
}
+
/***************************************************************************
Return the number of the service with the given name, or -1 if it doesn't
exist. Note that this is a DIFFERENT ANIMAL from the internal function
@@ -1867,25 +2254,146 @@ int lp_servicenumber(char *pszServiceName)
return (iService);
}
+/*******************************************************************
+ a useful volume label function
+ ******************************************************************/
+char *volume_label(int snum)
+{
+ char *ret = lp_volume(snum);
+ if (!*ret) return(lp_servicename(snum));
+ return(ret);
+}
+#if 0
+/*
+ * nmbd only loads the global section. There seems to be no way to
+ * determine exactly is a service is printable by only looking at the
+ * [global] section so for now always announce as a print server. This
+ * will need looking at in the future. Jeremy (jallison@whistle.com).
+ */
+/*******************************************************************
+ Return true if any printer services are defined.
+ ******************************************************************/
+static BOOL lp_printer_services(void)
+{
+ int iService;
+ for (iService = iNumServices - 1; iService >= 0; iService--)
+ if (VALID(iService) && iSERVICE(iService).bPrint_ok)
+ return True;
+ return False;
+}
+#endif
/*******************************************************************
- get a workgroup - but map to standalone if '*'
- ******************************************************************/
-char *my_workgroup(void)
+ Set the server type we will announce as via nmbd.
+********************************************************************/
+static void set_default_server_announce_type()
+{
+ default_server_announce = (SV_TYPE_WORKSTATION | SV_TYPE_SERVER |
+ SV_TYPE_SERVER_UNIX | SV_TYPE_PRINTQ_SERVER);
+ if(lp_announce_as() == ANNOUNCE_AS_NT)
+ default_server_announce |= (SV_TYPE_SERVER_NT | SV_TYPE_NT);
+ else if(lp_announce_as() == ANNOUNCE_AS_WIN95)
+ default_server_announce |= SV_TYPE_WIN95_PLUS;
+ else if(lp_announce_as() == ANNOUNCE_AS_WFW)
+ default_server_announce |= SV_TYPE_WFW;
+ default_server_announce |= (lp_time_server() ? SV_TYPE_TIME_SOURCE : 0);
+/*
+ * nmbd only loads the [global] section. There seems to be no way to
+ * determine exactly if any service is printable by only looking at the
+ * [global] section so for now always announce as a print server. This
+ * will need looking at in the future. Jeremy (jallison@whistle.com).
+ */
+#if 0
+ default_server_announce |= (lp_printer_services() ? SV_TYPE_PRINTQ_SERVER : 0);
+#endif
+}
+
+
+/*******************************************************************
+rename a service
+********************************************************************/
+void lp_rename_service(int snum, char *new_name)
{
- char *res = lp_workgroup();
- if (*res == '*') return("STANDALONE");
- return(res);
+ string_set(&pSERVICE(snum)->szService, new_name);
}
/*******************************************************************
- a useful volume label function
- ******************************************************************/
-char *volume_label(int snum)
+remove a service
+********************************************************************/
+void lp_remove_service(int snum)
{
- char *ret = lp_volume(snum);
- if (!*ret) return(lp_servicename(snum));
- return(ret);
+ pSERVICE(snum)->valid = False;
+}
+
+/*******************************************************************
+copy a service
+********************************************************************/
+void lp_copy_service(int snum, char *new_name)
+{
+ char *oldname = lp_servicename(snum);
+ do_section(new_name);
+ if (snum >= 0) {
+ snum = lp_servicenumber(new_name);
+ if (snum >= 0)
+ lp_do_parameter(snum, "copy", oldname);
+ }
+}
+
+
+/*******************************************************************
+ Get the default server type we will announce as via nmbd.
+********************************************************************/
+int lp_default_server_announce(void)
+{
+ return default_server_announce;
+}
+
+/*******************************************************************
+ Split the announce version into major and minor numbers.
+********************************************************************/
+int lp_major_announce_version(void)
+{
+ static BOOL got_major = False;
+ static int major_version = DEFAULT_MAJOR_VERSION;
+ char *vers;
+ char *p;
+
+ if(got_major)
+ return major_version;
+
+ got_major = True;
+ if((vers = lp_announce_version()) == NULL)
+ return major_version;
+
+ if((p = strchr(vers, '.')) == 0)
+ return major_version;
+
+ *p = '\0';
+ major_version = atoi(vers);
+ return major_version;
}
+
+int lp_minor_announce_version(void)
+{
+ static BOOL got_minor = False;
+ static int minor_version = DEFAULT_MINOR_VERSION;
+ char *vers;
+ char *p;
+
+ if(got_minor)
+ return minor_version;
+
+ got_minor = True;
+ if((vers = lp_announce_version()) == NULL)
+ return minor_version;
+
+ if((p = strchr(vers, '.')) == 0)
+ return minor_version;
+
+ p++;
+ minor_version = atoi(p);
+ return minor_version;
+}
+
diff --git a/source/param/params.c b/source/param/params.c
index b9d61382a18..4d1c191b479 100644
--- a/source/param/params.c
+++ b/source/param/params.c
@@ -1,335 +1,566 @@
-/*
- Unix SMB/Netbios implementation.
- Version 1.9.
- Parameter loading utlities
- 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.C
-
-Copyright (C) 1990, 1991, 1992, 1993, 1994 Karl Auer
-
-This module provides for streamlines retrieval of information from a
-Windows-like parameter files. There is a function which will search for
-all sections in the file and call a specified function with each. There is
-a similar function which will call a specified function for all parameters
-in a section. The idea is that you pass the addresses of suitable functions
-to a single function in this module which will then enumerate all sections,
-and within each section all parameters, to your program.
-
-Parameter files contain text lines (newline delimited) which consist of
-either a section name in square brackets or a parameter name, delimited
-from the parameter value by an equals sign. Blank lines or lines where the
-first non-whitespace character is a colon are ignored. All whitespace in
-section names and parameter names is compressed to single spaces. Leading
-and trailing whitespace on parameter names and parameter values is stripped.
-
-Only the first equals sign in a parameter line is significant - parameter
-values may contain equals signs, square brackets and semicolons. Internal
-whitespace is retained in parameter values. Parameter names may not start
-with a square bracket, an equals sign or a semicolon, for obvious reasons.
-
-A sample parameter file might look like this:
-
-[things]
-this=1
-that=2
-[other things]
-the other = 3
-
-**************************************************************************/
+/* -------------------------------------------------------------------------- **
+ * Microsoft Network Services for Unix, AKA., Andrew Tridgell's SAMBA.
+ *
+ * This module Copyright (C) 1990, 1991, 1992, 1993, 1994 Karl Auer
+ *
+ * Rewritten almost completely by Christopher R. Hertel
+ * at the University of Minnesota, September, 1997.
+ * This module Copyright (C) 1997 by the University of Minnesota
+ * -------------------------------------------------------------------------- **
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * Module name: params
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * This module performs lexical analysis and initial parsing of a
+ * Windows-like parameter file. It recognizes and handles four token
+ * types: section-name, parameter-name, parameter-value, and
+ * end-of-file. Comments and line continuation are handled
+ * internally.
+ *
+ * The entry point to the module is function pm_process(). This
+ * function opens the source file, calls the Parse() function to parse
+ * the input, and then closes the file when either the EOF is reached
+ * or a fatal error is encountered.
+ *
+ * A sample parameter file might look like this:
+ *
+ * [section one]
+ * parameter one = value string
+ * parameter two = another value
+ * [section two]
+ * new parameter = some value or t'other
+ *
+ * The parameter file is divided into sections by section headers:
+ * section names enclosed in square brackets (eg. [section one]).
+ * Each section contains parameter lines, each of which consist of a
+ * parameter name and value delimited by an equal sign. Roughly, the
+ * syntax is:
+ *
+ * <file> :== { <section> } EOF
+ *
+ * <section> :== <section header> { <parameter line> }
+ *
+ * <section header> :== '[' NAME ']'
+ *
+ * <parameter line> :== NAME '=' VALUE '\n'
+ *
+ * Blank lines and comment lines are ignored. Comment lines are lines
+ * beginning with either a semicolon (';') or a pound sign ('#').
+ *
+ * All whitespace in section names and parameter names is compressed
+ * to single spaces. Leading and trailing whitespace is stipped from
+ * both names and values.
+ *
+ * Only the first equals sign in a parameter line is significant.
+ * Parameter values may contain equals signs, square brackets and
+ * semicolons. Internal whitespace is retained in parameter values,
+ * with the exception of the '\r' character, which is stripped for
+ * historic reasons. Parameter names may not start with a left square
+ * bracket, an equal sign, a pound sign, or a semicolon, because these
+ * are used to identify other tokens.
+ *
+ * -------------------------------------------------------------------------- **
+ */
#include "includes.h"
-#include "smb.h"
-#include "params.h"
+/* -------------------------------------------------------------------------- **
+ * Constants...
+ */
+
+#define BUFR_INC 1024
+
+
+/* -------------------------------------------------------------------------- **
+ * Variables...
+ *
+ * DEBUGLEVEL - The ubiquitous DEBUGLEVEL. This determines which DEBUG()
+ * messages will be produced.
+ * bufr - pointer to a global buffer. This is probably a kludge,
+ * but it was the nicest kludge I could think of (for now).
+ * bSize - The size of the global buffer <bufr>.
+ */
-/* local variable pointing to passed filename */
-static char *pszParmFile = NULL;
extern int DEBUGLEVEL;
-/* local prototypes */
-static BOOL enumerate_parameters(FILE *infile, PM_PARMFUNC pfunc);
-static BOOL enumerate_sections(FILE *infile,
- PM_SECFUNC sfunc, PM_PARMFUNC pfunc);
-
-/* prototypes for local toolbox functions */
-static void trimleft(char *psz);
-static void trimright(char *psz);
-static void collapse_spaces(char *psz);
-static int firstnonwhite(char *psz);
-
-/**************************************************************************
-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)
-{
- pstring szBuf;
- char *pszTemp;
- BOOL bRetval;
- long lFileOffset;
- int cTemp;
- BOOL bParmFound;
-
- bRetval = False;
- bParmFound = False;
- while (True)
- {
- /* first remember where we are */
- if ((lFileOffset = ftell(fileIn)) >= 0L)
+static char *bufr = NULL;
+static int bSize = 0;
+
+/* -------------------------------------------------------------------------- **
+ * Functions...
+ */
+
+static int EatWhitespace( FILE *InFile )
+ /* ------------------------------------------------------------------------ **
+ * Scan past whitespace (see ctype(3C)) and return the first non-whitespace
+ * character, or newline, or EOF.
+ *
+ * Input: InFile - Input source.
+ *
+ * Output: The next non-whitespace character in the input stream.
+ *
+ * Notes: Because the config files use a line-oriented grammar, we
+ * explicitly exclude the newline character from the list of
+ * whitespace characters.
+ * - Note that both EOF (-1) and the nul character ('\0') are
+ * considered end-of-file markers.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ int c;
+
+ for( c = getc( InFile ); isspace( c ) && ('\n' != c); c = getc( InFile ) )
+ ;
+ return( c );
+ } /* EatWhitespace */
+
+static int EatComment( FILE *InFile )
+ /* ------------------------------------------------------------------------ **
+ * Scan to the end of a comment.
+ *
+ * Input: InFile - Input source.
+ *
+ * Output: The character that marks the end of the comment. Normally,
+ * this will be a newline, but it *might* be an EOF.
+ *
+ * Notes: Because the config files use a line-oriented grammar, we
+ * explicitly exclude the newline character from the list of
+ * whitespace characters.
+ * - Note that both EOF (-1) and the nul character ('\0') are
+ * considered end-of-file markers.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ int c;
+
+ for( c = getc( InFile ); ('\n'!=c) && (EOF!=c) && (c>0); c = getc( InFile ) )
+ ;
+ return( c );
+ } /* EatComment */
+
+static int Continuation( char *line, int pos )
+ /* ------------------------------------------------------------------------ **
+ * Scan backards within a string to discover if the last non-whitespace
+ * character is a line-continuation character ('\\').
+ *
+ * Input: line - A pointer to a buffer containing the string to be
+ * scanned.
+ * pos - This is taken to be the offset of the end of the
+ * string. This position is *not* scanned.
+ *
+ * Output: The offset of the '\\' character if it was found, or -1 to
+ * indicate that it was not.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ pos--;
+ while( (pos >= 0) && isspace(line[pos]) )
+ pos--;
+
+ return( ((pos >= 0) && ('\\' == line[pos])) ? pos : -1 );
+ } /* Continuation */
+
+
+static BOOL Section( FILE *InFile, BOOL (*sfunc)(char *) )
+ /* ------------------------------------------------------------------------ **
+ * Scan a section name, and pass the name to function sfunc().
+ *
+ * Input: InFile - Input source.
+ * sfunc - Pointer to the function to be called if the section
+ * name is successfully read.
+ *
+ * Output: True if the section name was read and True was returned from
+ * <sfunc>. False if <sfunc> failed or if a lexical error was
+ * encountered.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ int c;
+ int i;
+ int end;
+ char *func = "params.c:Section() -";
+
+ i = 0; /* <i> is the offset of the next free byte in bufr[] and */
+ end = 0; /* <end> is the current "end of string" offset. In most */
+ /* cases these will be the same, but if the last */
+ /* character written to bufr[] is a space, then <end> */
+ /* will be one less than <i>. */
+
+ c = EatWhitespace( InFile ); /* We've already got the '['. Scan */
+ /* past initial white space. */
+
+ while( (EOF != c) && (c > 0) )
+ {
+
+ /* Check that the buffer is big enough for the next character. */
+ if( i > (bSize - 2) )
{
- /* then get and check a line */
- if (fgets_slash(szBuf, sizeof(szBuf)-1, fileIn) == NULL)
- {
- /* stop - return OK unless file error */
- bRetval = !ferror(fileIn);
- if (!bRetval)
- DEBUG(0,( "Read error on configuration file (enumerating parameters)!\n"));
- break;
- }
- else
- /* if first non-white is a '[', stop (new section) */
- if ((cTemp = firstnonwhite(szBuf)) == '[')
- {
- /* restore position to start of new section */
- if (fseek(fileIn, lFileOffset, SEEK_SET) < 0L)
- {
- DEBUG(0,( "Seek error on configuration file!\n"));
- break;
- }
-
- /* return success */
- bRetval = True;
- break;
- }
- else
- /* if it's a semicolon or line is blank, ignore the line */
- if (!cTemp || strchr(";#",cTemp))
- {
- continue;
- }
- else
- /* if no equals sign and line contains non-whitespace */
- /* then line is badly formed */
- if ((pszTemp = strchr(szBuf, '=')) == NULL)
- {
- DEBUG(0,( "Ignoring badly formed line: %s", szBuf));
- }
- else
- {
- /* Note that we have found a parameter */
- bParmFound = True;
- /* cut line at the equals sign */
- *pszTemp++ = '\0';
- /* trim leading and trailing space from both halves */
- trimright(szBuf);
- trimleft(szBuf);
- trimright(pszTemp);
- trimleft(pszTemp);
- /* process the parameter iff passed pointer not NULL */
- if (pfunc != NULL)
- if (!pfunc(szBuf, pszTemp))
- break;
- }
+ bSize += BUFR_INC;
+ bufr = Realloc( bufr, bSize );
+ if( NULL == bufr )
+ {
+ DEBUG(0, ("%s Memory re-allocation failure.", func) );
+ return( False );
+ }
}
- }
- return (bRetval);
-}
-
-
-/***********************************************************************
-Close up s by n chars, at offset start.
-***********************************************************************/
-static void closestr(char *s, int start, int n)
-{
- char *src;
- char *dest;
- int len;
-
- if (n > 0)
- if ((src = dest = s) != NULL)
+
+ /* Handle a single character. */
+ switch( c )
{
- len = strlen(s);
- if (start >= 0 && start < len - n)
- {
- src += start + n;
- dest += start;
-
- while (*src)
- *dest++ = *src++;
- *dest = '\0';
- }
+ case ']': /* Found the closing bracket. */
+ bufr[end] = '\0';
+ if( 0 == end ) /* Don't allow an empty name. */
+ {
+ DEBUG(0, ("%s Empty section name in configuration file.\n", func ));
+ return( False );
+ }
+ if( !sfunc( bufr ) ) /* Got a valid name. Deal with it. */
+ return( False );
+ (void)EatComment( InFile ); /* Finish off the line. */
+ return( True );
+
+ case '\n': /* Got newline before closing ']'. */
+ i = Continuation( bufr, i ); /* Check for line continuation. */
+ if( i < 0 )
+ {
+ bufr[end] = '\0';
+ DEBUG(0, ("%s Badly formed line in configuration file: %s\n",
+ func, bufr ));
+ return( False );
+ }
+ end = ( (i > 0) && (' ' == bufr[i - 1]) ) ? (i - 1) : (i);
+ c = getc( InFile ); /* Continue with next line. */
+ break;
+
+ default: /* All else are a valid name chars. */
+ if( isspace( c ) ) /* One space per whitespace region. */
+ {
+ bufr[end] = ' ';
+ i = end + 1;
+ c = EatWhitespace( InFile );
+ }
+ else /* All others copy verbatim. */
+ {
+ bufr[i++] = c;
+ end = i;
+ c = getc( InFile );
+ }
}
-}
-
-/**************************************************************************
-Identifies all sections in the parameter file, calls passed section_func()
-for each, passing the section name, then calls enumerate_parameters().
-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)
-{
- pstring szBuf;
- BOOL bRetval;
- BOOL bSectionFound;
-
- /* this makes sure we get include lines right */
- enumerate_parameters(fileIn, pfunc);
-
- bRetval = False;
- bSectionFound = False;
- while (True)
- {
- if (fgets_slash(szBuf, sizeof(szBuf)-1, fileIn) == NULL)
+ }
+
+ /* We arrive here if we've met the EOF before the closing bracket. */
+ DEBUG(0, ("%s Unexpected EOF in the configuration file: %s\n", func, bufr ));
+ return( False );
+ } /* Section */
+
+static BOOL Parameter( FILE *InFile, BOOL (*pfunc)(char *, char *), int c )
+ /* ------------------------------------------------------------------------ **
+ * Scan a parameter name and value, and pass these two fields to pfunc().
+ *
+ * Input: InFile - The input source.
+ * pfunc - A pointer to the function that will be called to
+ * process the parameter, once it has been scanned.
+ * c - The first character of the parameter name, which
+ * would have been read by Parse(). Unlike a comment
+ * line or a section header, there is no lead-in
+ * character that can be discarded.
+ *
+ * Output: True if the parameter name and value were scanned and processed
+ * successfully, else False.
+ *
+ * Notes: This function is in two parts. The first loop scans the
+ * parameter name. Internal whitespace is compressed, and an
+ * equal sign (=) terminates the token. Leading and trailing
+ * whitespace is discarded. The second loop scans the parameter
+ * value. When both have been successfully identified, they are
+ * passed to pfunc() for processing.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ int i = 0; /* Position within bufr. */
+ int end = 0; /* bufr[end] is current end-of-string. */
+ int vstart = 0; /* Starting position of the parameter value. */
+ char *func = "params.c:Parameter() -";
+
+ /* Read the parameter name. */
+ while( 0 == vstart ) /* Loop until we've found the start of the value. */
+ {
+
+ if( i > (bSize - 2) ) /* Ensure there's space for next char. */
{
- /* stop - return OK unless file error */
- bRetval = !ferror(fileIn);
- if (!bRetval)
- DEBUG(0,( "Read error on configuration file (enumerating sections)!\n"));
- break;
+ bSize += BUFR_INC;
+ bufr = Realloc( bufr, bSize );
+ if( NULL == bufr )
+ {
+ DEBUG(0, ("%s Memory re-allocation failure.", func) );
+ return( False );
+ }
}
- else
+
+ switch( c )
{
- trimleft(szBuf);
- trimright(szBuf);
- if (szBuf[0] == '[')
- {
- closestr(szBuf, 0, 1);
- if (strlen(szBuf) > 1)
- if (szBuf[strlen(szBuf) - 1] == ']')
- {
- /* found a section - note the fact */
- bSectionFound = True;
- /* remove trailing metabracket */
- szBuf[strlen(szBuf) - 1] = '\0';
- /* remove leading and trailing whitespace from name */
- trimleft(szBuf);
- trimright(szBuf);
- /* reduce all internal whitespace to one space */
- collapse_spaces(szBuf);
- /* process it - stop if the processing fails */
- if (sfunc != NULL)
- if (!sfunc(szBuf))
- break;
- if (!enumerate_parameters(fileIn, pfunc))
- break;
- }
- }
+ case '=': /* Equal sign marks end of param name. */
+ if( 0 == end ) /* Don't allow an empty name. */
+ {
+ DEBUG(0, ("%s Invalid parameter name in config. file.\n", func ));
+ return( False );
+ }
+ bufr[end++] = '\0'; /* Mark end of string & advance. */
+ i = end; /* New string starts here. */
+ vstart = end; /* New string is parameter value. */
+ bufr[i] = '\0'; /* New string is nul, for now. */
+ break;
+
+ case '\n': /* Find continuation char, else error. */
+ i = Continuation( bufr, i );
+ if( i < 0 )
+ {
+ bufr[end] = '\0';
+ DEBUG(1,("%s Ignoring badly formed line in configuration file: %s\n",
+ func, bufr ));
+ return( True );
+ }
+ end = ( (i > 0) && (' ' == bufr[i - 1]) ) ? (i - 1) : (i);
+ c = getc( InFile ); /* Read past eoln. */
+ break;
+
+ case '\0': /* Shouldn't have EOF within param name. */
+ case EOF:
+ bufr[i] = '\0';
+ DEBUG(1,("%s Unexpected end-of-file at: %s\n", func, bufr ));
+ return( True );
+
+ default:
+ if( isspace( c ) ) /* One ' ' per whitespace region. */
+ {
+ bufr[end] = ' ';
+ i = end + 1;
+ c = EatWhitespace( InFile );
+ }
+ else /* All others verbatim. */
+ {
+ bufr[i++] = c;
+ end = i;
+ c = getc( InFile );
+ }
}
- }
-
- return (bRetval);
-}
-
-/**************************************************************************
-Process the passed parameter file.
+ }
-Returns True if successful, else False.
-**************************************************************************/
-BOOL pm_process(char *pszFileName, PM_SECFUNC sfunc, PM_PARMFUNC pfunc)
-{
- FILE *fileIn;
- BOOL bRetval;
+ /* Now parse the value. */
+ c = EatWhitespace( InFile ); /* Again, trim leading whitespace. */
+ while( (EOF !=c) && (c > 0) )
+ {
- bRetval = False;
-
- /* record the filename for use in error messages one day... */
- pszParmFile = pszFileName;
-
- if (pszParmFile == NULL || strlen(pszParmFile) < 1)
- DEBUG(0,( "No configuration filename specified!\n"));
- else
- if ((fileIn = fopen(pszParmFile, "r")) == NULL)
- DEBUG(0,( "Unable to open configuration file \"%s\"!\n", pszParmFile));
- else
+ if( i > (bSize - 2) ) /* Make sure there's enough room. */
{
- DEBUG(2,( "Processing configuration file \"%s\"\n", pszParmFile));
- bRetval = enumerate_sections(fileIn, sfunc, pfunc);
- fclose(fileIn);
+ bSize += BUFR_INC;
+ bufr = Realloc( bufr, bSize );
+ if( NULL == bufr )
+ {
+ DEBUG(0, ("%s Memory re-allocation failure.", func) );
+ return( False );
+ }
}
- if (!bRetval)
- DEBUG(0,("pm_process retuned false\n"));
- return (bRetval);
-}
-
-
-/**************************************************************************
-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))
+ switch( c )
+ {
+ case '\r': /* Explicitly remove '\r' because the older */
+ c = getc( InFile ); /* version called fgets_slash() which also */
+ break; /* removes them. */
+
+ case '\n': /* Marks end of value unless there's a '\'. */
+ i = Continuation( bufr, i );
+ if( i < 0 )
+ c = 0;
+ else
+ {
+ for( end = i; (end >= 0) && isspace(bufr[end]); end-- )
+ ;
+ c = getc( InFile );
+ }
+ break;
+
+ default: /* All others verbatim. Note that spaces do */
+ bufr[i++] = c; /* not advance <end>. This allows trimming */
+ if( !isspace( c ) ) /* of whitespace at the end of the line. */
+ end = i;
+ c = getc( InFile );
+ break;
+ }
+ }
+ bufr[end] = '\0'; /* End of value. */
+
+ return( pfunc( bufr, &bufr[vstart] ) ); /* Pass name & value to pfunc(). */
+ } /* Parameter */
+
+static BOOL Parse( FILE *InFile,
+ BOOL (*sfunc)(char *),
+ BOOL (*pfunc)(char *, char *) )
+ /* ------------------------------------------------------------------------ **
+ * Scan & parse the input.
+ *
+ * Input: InFile - Input source.
+ * sfunc - Function to be called when a section name is scanned.
+ * See Section().
+ * pfunc - Function to be called when a parameter is scanned.
+ * See Parameter().
+ *
+ * Output: True if the file was successfully scanned, else False.
+ *
+ * Notes: The input can be viewed in terms of 'lines'. There are four
+ * types of lines:
+ * Blank - May contain whitespace, otherwise empty.
+ * Comment - First non-whitespace character is a ';' or '#'.
+ * The remainder of the line is ignored.
+ * Section - First non-whitespace character is a '['.
+ * Parameter - The default case.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ int c;
+
+ c = EatWhitespace( InFile );
+ while( (EOF != c) && (c > 0) )
+ {
+ switch( c )
+ {
+ case '\n': /* Blank line. */
+ c = EatWhitespace( InFile );
+ break;
+
+ case ';': /* Comment line. */
+ case '#':
+ c = EatComment( InFile );
+ break;
+
+ case '[': /* Section Header. */
+ if( !Section( InFile, sfunc ) )
+ return( False );
+ c = EatWhitespace( InFile );
+ break;
+
+ case '\\': /* Bogus backslash. */
+ c = EatWhitespace( InFile );
+ break;
+
+ default: /* Parameter line. */
+ if( !Parameter( InFile, pfunc, c ) )
+ return( False );
+ c = EatWhitespace( InFile );
+ break;
+ }
+ }
+ return( True );
+ } /* Parse */
+
+static FILE *OpenConfFile( char *FileName )
+ /* ------------------------------------------------------------------------ **
+ * Open a configuration file.
+ *
+ * Input: FileName - The pathname of the config file to be opened.
+ *
+ * Output: A pointer of type (FILE *) to the opened file, or NULL if the
+ * file could not be opened.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ FILE *OpenedFile;
+ char *func = "params.c:OpenConfFile() -";
+
+ if( NULL == FileName || 0 == *FileName )
+ {
+ DEBUG( 0, ("%s No configuration filename specified.\n", func) );
+ return( NULL );
+ }
+
+ OpenedFile = fopen( FileName, "r" );
+ if( NULL == OpenedFile )
+ {
+ DEBUG( 0,
+ ("%s Unable to open configuration file \"%s\":\n\t%s\n",
+ func, FileName, strerror(errno)) );
+ }
+
+ return( OpenedFile );
+ } /* OpenConfFile */
+
+BOOL pm_process( char *FileName,
+ BOOL (*sfunc)(char *),
+ BOOL (*pfunc)(char *, char *) )
+ /* ------------------------------------------------------------------------ **
+ * Process the named parameter file.
+ *
+ * Input: FileName - The pathname of the parameter file to be opened.
+ * sfunc - A pointer to a function that will be called when
+ * a section name is discovered.
+ * pfunc - A pointer to a function that will be called when
+ * a parameter name and value are discovered.
+ *
+ * Output: TRUE if the file was successfully parsed, else FALSE.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ int result;
+ FILE *InFile;
+ char *func = "params.c:pm_process() -";
+
+ InFile = OpenConfFile( FileName ); /* Open the config file. */
+ if( NULL == InFile )
+ return( False );
+
+ DEBUG( 3, ("%s Processing configuration file \"%s\"\n", func, FileName) );
+
+ if( NULL != bufr ) /* If we already have a buffer */
+ result = Parse( InFile, sfunc, pfunc ); /* (recursive call), then just */
+ /* use it. */
+
+ else /* If we don't have a buffer */
+ { /* allocate one, then parse, */
+ bSize = BUFR_INC; /* then free. */
+ bufr = (char *)malloc( bSize );
+ if( NULL == bufr )
{
- *psz++ = ' ';
- trimleft(psz);
+ DEBUG(0,("%s memory allocation failure.\n", func));
+ return( False );
}
- 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);
-}
+ result = Parse( InFile, sfunc, pfunc );
+ free( bufr );
+ bufr = NULL;
+ bSize = 0;
+ }
+
+ if( !result ) /* Generic failure. */
+ {
+ DEBUG(0,("%s Failed. Error returned from params.c:parse().\n", func));
+ return( False );
+ }
+
+ return( True ); /* Generic success. */
+ } /* pm_process */
+
+/* -------------------------------------------------------------------------- */
diff --git a/source/passdb/smbpass.c b/source/passdb/smbpass.c
index 2dec15ffb43..441ab94ffbb 100644
--- a/source/passdb/smbpass.c
+++ b/source/passdb/smbpass.c
@@ -1,7 +1,6 @@
-#ifdef SMB_PASSWD
/*
* Unix SMB/Netbios implementation. Version 1.9. SMB parameters and setup
- * Copyright (C) Andrew Tridgell 1992-1995 Modified by Jeremy Allison 1995.
+ * Copyright (C) Andrew Tridgell 1992-1997 Modified by 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
@@ -19,7 +18,6 @@
*/
#include "includes.h"
-#include "loadparm.h"
extern int DEBUGLEVEL;
@@ -59,10 +57,9 @@ do_pw_lock(int fd, int waitsecs, int type)
return ret;
}
-int
-pw_file_lock(char *name, int type, int secs)
+int pw_file_lock(char *name, int type, int secs)
{
- int fd = open(name, O_RDWR | O_CREAT, 0666);
+ int fd = open(name, O_RDWR | O_CREAT, 0600);
if (fd < 0)
return (-1);
if (do_pw_lock(fd, secs, type)) {
@@ -72,8 +69,7 @@ pw_file_lock(char *name, int type, int secs)
return fd;
}
-int
-pw_file_unlock(int fd)
+int pw_file_unlock(int fd)
{
do_pw_lock(fd, 5, F_UNLCK);
return close(fd);
@@ -110,8 +106,7 @@ static int gethexpwd(char *p, char *pwd)
/*
* Routine to search the smbpasswd file for an entry matching the username.
*/
-struct smb_passwd *
-get_smbpwnam(char *name)
+struct smb_passwd *get_smbpwnam(char *name)
{
/* Static buffers we will return. */
static struct smb_passwd pw_buf;
@@ -262,7 +257,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 +275,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;
}
}
@@ -296,9 +291,3 @@ get_smbpwnam(char *name)
pw_file_unlock(lockfd);
return NULL;
}
-#else
-void
-smbpass_dummy(void)
-{
-} /* To avoid compiler complaints */
-#endif
diff --git a/source/pipenetlog.c b/source/pipenetlog.c
new file mode 100644
index 00000000000..0064a31caa9
--- /dev/null
+++ b/source/pipenetlog.c
@@ -0,0 +1,660 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Pipe SMB reply routines
+ Copyright (C) Andrew Tridgell 1992-1997,
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997.
+ Copyright (C) Paul Ashton 1997.
+
+ 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 file handles reply_ calls on named pipes that the server
+ makes to handle specific protocols
+*/
+
+
+#include "includes.h"
+#include "trans2.h"
+#include "nterr.h"
+
+extern int DEBUGLEVEL;
+
+extern BOOL sam_logon_in_ssb;
+extern pstring samlogon_user;
+
+#ifdef NTDOMAIN
+
+static void make_lsa_r_req_chal(LSA_R_REQ_CHAL *r_c,
+ DOM_CHAL *srv_chal, int status)
+{
+ DEBUG(6,("make_lsa_r_req_chal: %d\n", __LINE__));
+ memcpy(r_c->srv_chal.data, srv_chal->data, sizeof(srv_chal->data));
+ r_c->status = status;
+}
+
+static int lsa_reply_req_chal(LSA_Q_REQ_CHAL *q_c, char *q, char *base,
+ DOM_CHAL *srv_chal, uint32 srv_time)
+{
+ LSA_R_REQ_CHAL r_c;
+
+ DEBUG(6,("lsa_reply_req_chal: %d\n", __LINE__));
+
+ /* set up the LSA REQUEST CHALLENGE response */
+ make_lsa_r_req_chal(&r_c, srv_chal, srv_time);
+
+ /* store the response in the SMB stream */
+ q = lsa_io_r_req_chal(False, &r_c, q, base, 4, 0);
+
+ DEBUG(6,("lsa_reply_req_chal: %d\n", __LINE__));
+
+ /* return length of SMB data stored */
+ return PTR_DIFF(q, base);
+}
+
+static void make_lsa_r_auth_2(LSA_R_AUTH_2 *r_a,
+ DOM_CHAL *resp_cred, NEG_FLAGS *flgs, int status)
+{
+ memcpy( r_a->srv_chal.data, resp_cred->data, sizeof(resp_cred->data));
+ memcpy(&(r_a->srv_flgs) , flgs , sizeof(r_a->srv_flgs));
+ r_a->status = status;
+}
+
+static int lsa_reply_auth_2(LSA_Q_AUTH_2 *q_a, char *q, char *base,
+ DOM_CHAL *resp_cred, int status)
+{
+ LSA_R_AUTH_2 r_a;
+
+ /* set up the LSA AUTH 2 response */
+
+ make_lsa_r_auth_2(&r_a, resp_cred, &(q_a->clnt_flgs), status);
+
+ /* store the response in the SMB stream */
+ q = lsa_io_r_auth_2(False, &r_a, q, base, 4, 0);
+
+ /* return length of SMB data stored */
+ return PTR_DIFF(q, base);
+}
+
+static void make_lsa_r_srv_pwset(LSA_R_SRV_PWSET *r_s,
+ DOM_CRED *srv_cred, int status)
+{
+ DEBUG(5,("make_lsa_r_srv_pwset: %d\n", __LINE__));
+
+ memcpy(&(r_s->srv_cred), srv_cred, sizeof(r_s->srv_cred));
+ r_s->status = status;
+
+ DEBUG(5,("make_lsa_r_srv_pwset: %d\n", __LINE__));
+}
+
+static int lsa_reply_srv_pwset(LSA_Q_SRV_PWSET *q_s, char *q, char *base,
+ DOM_CRED *srv_cred, int status)
+{
+ LSA_R_SRV_PWSET r_s;
+
+ DEBUG(5,("lsa_srv_pwset: %d\n", __LINE__));
+
+ /* set up the LSA Server Password Set response */
+ make_lsa_r_srv_pwset(&r_s, srv_cred, status);
+
+ /* store the response in the SMB stream */
+ q = lsa_io_r_srv_pwset(False, &r_s, q, base, 4, 0);
+
+ DEBUG(5,("lsa_srv_pwset: %d\n", __LINE__));
+
+ /* return length of SMB data stored */
+ return PTR_DIFF(q, base);
+}
+
+static void make_lsa_user_info(LSA_USER_INFO *usr,
+
+ NTTIME *logon_time,
+ NTTIME *logoff_time,
+ NTTIME *kickoff_time,
+ NTTIME *pass_last_set_time,
+ NTTIME *pass_can_change_time,
+ NTTIME *pass_must_change_time,
+
+ char *user_name,
+ char *full_name,
+ char *logon_script,
+ char *profile_path,
+ char *home_dir,
+ char *dir_drive,
+
+ uint16 logon_count,
+ uint16 bad_pw_count,
+
+ uint32 user_id,
+ uint32 group_id,
+ uint32 num_groups,
+ DOM_GID *gids,
+ uint32 user_flgs,
+
+ char sess_key[16],
+
+ char *logon_srv,
+ char *logon_dom,
+
+ char *dom_sid,
+ char *other_sids) /* space-delimited set of SIDs */
+{
+ /* only cope with one "other" sid, right now. */
+ /* need to count the number of space-delimited sids */
+ int i;
+ int num_other_sids = 0;
+
+ int len_user_name = strlen(user_name );
+ int len_full_name = strlen(full_name );
+ int len_logon_script = strlen(logon_script);
+ int len_profile_path = strlen(profile_path);
+ int len_home_dir = strlen(home_dir );
+ int len_dir_drive = strlen(dir_drive );
+
+ int len_logon_srv = strlen(logon_srv);
+ int len_logon_dom = strlen(logon_dom);
+
+ usr->ptr_user_info = 1; /* yes, we're bothering to put USER_INFO data here */
+
+ usr->logon_time = *logon_time;
+ usr->logoff_time = *logoff_time;
+ usr->kickoff_time = *kickoff_time;
+ usr->pass_last_set_time = *pass_last_set_time;
+ usr->pass_can_change_time = *pass_can_change_time;
+ usr->pass_must_change_time = *pass_must_change_time;
+
+ make_uni_hdr(&(usr->hdr_user_name ), len_user_name , len_user_name , 4);
+ make_uni_hdr(&(usr->hdr_full_name ), len_full_name , len_full_name , 4);
+ make_uni_hdr(&(usr->hdr_logon_script), len_logon_script, len_logon_script, 4);
+ make_uni_hdr(&(usr->hdr_profile_path), len_profile_path, len_profile_path, 4);
+ make_uni_hdr(&(usr->hdr_home_dir ), len_home_dir , len_home_dir , 4);
+ make_uni_hdr(&(usr->hdr_dir_drive ), len_dir_drive , len_dir_drive , 4);
+
+ usr->logon_count = logon_count;
+ usr->bad_pw_count = bad_pw_count;
+
+ usr->user_id = user_id;
+ usr->group_id = group_id;
+ usr->num_groups = num_groups;
+ usr->buffer_groups = 1; /* indicates fill in groups, below, even if there are none */
+ usr->user_flgs = user_flgs;
+
+ if (sess_key != NULL)
+ {
+ memcpy(usr->user_sess_key, sess_key, sizeof(usr->user_sess_key));
+ }
+ else
+ {
+ bzero(usr->user_sess_key, sizeof(usr->user_sess_key));
+ }
+
+ make_uni_hdr(&(usr->hdr_logon_srv), len_logon_srv, len_logon_srv, 4);
+ make_uni_hdr(&(usr->hdr_logon_dom), len_logon_dom, len_logon_dom, 4);
+
+ usr->buffer_dom_id = dom_sid ? 1 : 0; /* yes, we're bothering to put a domain SID in */
+
+ bzero(usr->padding, sizeof(usr->padding));
+
+ num_other_sids = make_dom_sids(other_sids, usr->other_sids, LSA_MAX_SIDS);
+
+ usr->num_other_sids = num_other_sids;
+ usr->buffer_other_sids = num_other_sids != 0 ? 1 : 0;
+
+ make_unistr2(&(usr->uni_user_name ), user_name , len_user_name );
+ make_unistr2(&(usr->uni_full_name ), full_name , len_full_name );
+ make_unistr2(&(usr->uni_logon_script), logon_script, len_logon_script);
+ make_unistr2(&(usr->uni_profile_path), profile_path, len_profile_path);
+ make_unistr2(&(usr->uni_home_dir ), home_dir , len_home_dir );
+ make_unistr2(&(usr->uni_dir_drive ), dir_drive , len_dir_drive );
+
+ usr->num_groups2 = num_groups;
+ for (i = 0; i < num_groups; i++)
+ {
+ usr->gids[i] = gids[i];
+ }
+
+ make_unistr2(&(usr->uni_logon_srv), logon_srv, len_logon_srv);
+ make_unistr2(&(usr->uni_logon_dom), logon_dom, len_logon_dom);
+
+ make_dom_sid(&(usr->dom_sid), dom_sid);
+ /* "other" sids are set up above */
+}
+
+
+static int lsa_reply_sam_logon(LSA_Q_SAM_LOGON *q_s, char *q, char *base,
+ DOM_CRED *srv_cred, LSA_USER_INFO *user_info)
+{
+ LSA_R_SAM_LOGON r_s;
+
+ /* XXXX maybe we want to say 'no', reject the client's credentials */
+ r_s.buffer_creds = 1; /* yes, we have valid server credentials */
+ memcpy(&(r_s.srv_creds), srv_cred, sizeof(r_s.srv_creds));
+
+ /* store the user information, if there is any. */
+ r_s.user = user_info;
+ if (user_info != NULL && user_info->ptr_user_info != 0)
+ {
+ r_s.switch_value = 3; /* indicates type of validation user info */
+ r_s.status = 0;
+ }
+ else
+ {
+ r_s.switch_value = 0; /* don't know what this value is supposed to be */
+ r_s.status = 0xC000000|NT_STATUS_NO_SUCH_USER;
+ }
+
+ r_s.auth_resp = 1; /* authoritative response */
+
+ /* store the response in the SMB stream */
+ q = lsa_io_r_sam_logon(False, &r_s, q, base, 4, 0);
+
+ /* return length of SMB data stored */
+ return PTR_DIFF(q, base);
+}
+
+
+static int lsa_reply_sam_logoff(LSA_Q_SAM_LOGOFF *q_s, char *q, char *base,
+ DOM_CRED *srv_cred,
+ uint32 status)
+{
+ LSA_R_SAM_LOGOFF r_s;
+
+ /* XXXX maybe we want to say 'no', reject the client's credentials */
+ r_s.buffer_creds = 1; /* yes, we have valid server credentials */
+ memcpy(&(r_s.srv_creds), srv_cred, sizeof(r_s.srv_creds));
+
+ r_s.status = status;
+
+ /* store the response in the SMB stream */
+ q = lsa_io_r_sam_logoff(False, &r_s, q, base, 4, 0);
+
+ /* return length of SMB data stored */
+ return PTR_DIFF(q, base);
+}
+
+/****************************************************************************
+ gets a machine password entry
+****************************************************************************/
+BOOL get_md4pw(char *md4pw, char *mach_acct)
+{
+ struct smb_passwd *smb_pass;
+
+ become_root(True);
+ smb_pass = get_smbpwnam(mach_acct);
+ unbecome_root(True);
+
+ if (smb_pass != NULL)
+ {
+ memcpy(md4pw, smb_pass->smb_nt_passwd, 16);
+ dump_data(5, md4pw, 16);
+
+ return True;
+ }
+ else
+ {
+ /* No such machine account. Should error out here, but we'll
+ print and carry on */
+ DEBUG(1,("No account in domain for %s\n", mach_acct));
+ return False;
+ }
+}
+
+static void api_lsa_req_chal( int cnum, uint16 vuid,
+ user_struct *vuser,
+ char *param, char *data,
+ char **rdata, int *rdata_len )
+{
+ LSA_Q_REQ_CHAL q_r;
+
+ fstring mach_acct;
+
+ /* grab the challenge... */
+ lsa_io_q_req_chal(True, &q_r, data + 0x18, data, 4, 0);
+
+ fstrcpy(mach_acct, unistrn2(q_r.uni_logon_clnt.buffer,
+ q_r.uni_logon_clnt.uni_str_len));
+
+ strcat(mach_acct, "$");
+
+ DEBUG(6,("q_r.clnt_chal.data: %lx %lx\n",
+ q_r.clnt_chal.data[0], q_r.clnt_chal.data[1]));
+
+ if (get_md4pw(vuser->dc.md4pw, mach_acct))
+ {
+ /* copy the client credentials */
+ memcpy(vuser->dc.clnt_chal.data , q_r.clnt_chal.data, sizeof(q_r.clnt_chal.data));
+ memcpy(vuser->dc.clnt_cred.challenge.data, q_r.clnt_chal.data, sizeof(q_r.clnt_chal.data));
+
+ /* create a server challenge for the client */
+ /* PAXX: set these to random values. */
+ /* lkcl: paul, you mentioned that it doesn't really matter much */
+ vuser->dc.srv_chal.data[0] = 0x11111111;
+ vuser->dc.srv_chal.data[1] = 0x11111111;
+ vuser->dc.srv_cred.challenge.data[0] = vuser->dc.srv_chal.data[0];
+ vuser->dc.srv_cred.challenge.data[1] = vuser->dc.srv_chal.data[1];
+
+ /* from client / server challenges and md4 password, generate sess key */
+ cred_session_key(&(vuser->dc.clnt_chal), &(vuser->dc.srv_chal),
+ vuser->dc.md4pw, vuser->dc.sess_key);
+ }
+
+ /* construct reply. return status is always 0x0 */
+ *rdata_len = lsa_reply_req_chal(&q_r, *rdata + 0x18, *rdata,
+ &(vuser->dc.srv_chal), 0);
+
+}
+
+static void api_lsa_auth_2( user_struct *vuser,
+ char *param, char *data,
+ char **rdata, int *rdata_len )
+{
+ LSA_Q_AUTH_2 q_a;
+
+ DOM_CHAL srv_cred;
+ UTIME srv_time;
+
+ srv_time.time = 0;
+
+ /* grab the challenge... */
+ lsa_io_q_auth_2(True, &q_a, data + 0x18, data, 4, 0);
+
+ /* check that the client credentials are valid */
+ cred_assert(&(q_a.clnt_chal), vuser->dc.sess_key,
+ &(vuser->dc.clnt_cred.challenge), srv_time);
+
+ /* create server challenge for inclusion in the reply */
+ cred_create(vuser->dc.sess_key, &(vuser->dc.srv_cred.challenge), srv_time, &srv_cred);
+
+ /* copy the received client credentials for use next time */
+ memcpy(vuser->dc.clnt_cred.challenge.data, &(q_a.clnt_chal.data), sizeof(q_a.clnt_chal.data));
+ memcpy(vuser->dc.srv_cred .challenge.data, &(q_a.clnt_chal.data), sizeof(q_a.clnt_chal.data));
+
+ /* construct reply. */
+ *rdata_len = lsa_reply_auth_2(&q_a, *rdata + 0x18, *rdata,
+ &srv_cred, 0x0);
+}
+
+
+static void api_lsa_srv_pwset( user_struct *vuser,
+ char *param, char *data,
+ char **rdata, int *rdata_len )
+{
+ LSA_Q_SRV_PWSET q_a;
+
+ DOM_CRED srv_cred;
+
+ /* grab the challenge and encrypted password ... */
+ lsa_io_q_srv_pwset(True, &q_a, data + 0x18, data, 4, 0);
+
+ /* checks and updates credentials. creates reply credentials */
+ deal_with_creds(vuser->dc.sess_key, &(vuser->dc.clnt_cred),
+ &(q_a.clnt_id.cred), &srv_cred);
+ memcpy(&(vuser->dc.srv_cred), &(vuser->dc.clnt_cred), sizeof(vuser->dc.clnt_cred));
+
+ DEBUG(5,("api_lsa_srv_pwset: %d\n", __LINE__));
+
+ /* construct reply. always indicate failure. nt keeps going... */
+ *rdata_len = lsa_reply_srv_pwset(&q_a, *rdata + 0x18, *rdata,
+ &srv_cred,
+ NT_STATUS_WRONG_PASSWORD|0xC0000000);
+}
+
+
+static void api_lsa_sam_logoff( user_struct *vuser,
+ char *param, char *data,
+ char **rdata, int *rdata_len )
+{
+ LSA_Q_SAM_LOGOFF q_l;
+ DOM_ID_INFO_1 id1;
+
+ DOM_CRED srv_cred;
+
+ /* the DOM_ID_INFO_1 structure is a bit big. plus we might want to
+ dynamically allocate it inside lsa_io_q_sam_logon, at some point */
+ q_l.sam_id.auth.id1 = &id1;
+
+ /* grab the challenge... */
+ lsa_io_q_sam_logoff(True, &q_l, data + 0x18, data, 4, 0);
+
+ /* checks and updates credentials. creates reply credentials */
+ deal_with_creds(vuser->dc.sess_key, &(vuser->dc.clnt_cred),
+ &(q_l.sam_id.client.cred), &srv_cred);
+ memcpy(&(vuser->dc.srv_cred), &(vuser->dc.clnt_cred), sizeof(vuser->dc.clnt_cred));
+
+ /* construct reply. always indicate success */
+ *rdata_len = lsa_reply_sam_logoff(&q_l, *rdata + 0x18, *rdata,
+ &srv_cred,
+ 0x0);
+}
+
+
+static void api_lsa_sam_logon( user_struct *vuser,
+ char *param, char *data,
+ char **rdata, int *rdata_len )
+{
+ LSA_Q_SAM_LOGON q_l;
+ DOM_ID_INFO_1 id1;
+ LSA_USER_INFO usr_info;
+
+ DOM_CRED srv_cred;
+
+ /* the DOM_ID_INFO_1 structure is a bit big. plus we might want to
+ dynamically allocate it inside lsa_io_q_sam_logon, at some point */
+ q_l.sam_id.auth.id1 = &id1;
+
+ lsa_io_q_sam_logon(True, &q_l, data + 0x18, data, 4, 0);
+
+ /* checks and updates credentials. creates reply credentials */
+ deal_with_creds(vuser->dc.sess_key, &(vuser->dc.clnt_cred),
+ &(q_l.sam_id.client.cred), &srv_cred);
+ memcpy(&(vuser->dc.srv_cred), &(vuser->dc.clnt_cred), sizeof(vuser->dc.clnt_cred));
+
+ usr_info.ptr_user_info = 0;
+
+ if (vuser != NULL)
+ {
+ DOM_GID gids[LSA_MAX_GROUPS];
+ int num_gids;
+ NTTIME dummy_time;
+ pstring logon_script;
+ pstring profile_path;
+ pstring home_dir;
+ pstring home_drive;
+ pstring my_name;
+ pstring my_workgroup;
+ pstring domain_groups;
+ pstring dom_sid;
+ pstring other_sids;
+ fstring tmp;
+ extern pstring myname;
+ uint32 r_uid;
+ uint32 r_gid;
+ UNISTR2 *uni_samlogon_user = &(q_l.sam_id.auth.id1->uni_user_name);
+
+ dummy_time.low = 0xffffffff;
+ dummy_time.high = 0x7fffffff;
+
+ get_myname(myname, NULL);
+
+ pstrcpy(samlogon_user, unistrn2(uni_samlogon_user->buffer,
+ uni_samlogon_user->uni_str_len));
+
+ DEBUG(3,("SAM Logon. Domain:[%s]. User:[%s]\n",
+ lp_workgroup(), samlogon_user));
+
+ /* hack to get standard_sub_basic() to use the sam logon username */
+ sam_logon_in_ssb = True;
+
+ pstrcpy(logon_script, lp_logon_script ());
+ pstrcpy(profile_path, lp_logon_path ());
+ pstrcpy(dom_sid , lp_domain_sid ());
+ pstrcpy(other_sids , lp_domain_other_sids());
+ pstrcpy(my_workgroup, lp_workgroup ());
+
+ pstrcpy(home_drive , lp_logon_drive ());
+ pstrcpy(home_dir , lp_logon_home ());
+
+ /* any additional groups this user is in. e.g power users */
+ pstrcpy(domain_groups, lp_domain_groups());
+
+ /* can only be a user or a guest. cannot be guest _and_ admin */
+ if (user_in_list(samlogon_user, lp_domain_guest_users()))
+ {
+ sprintf(tmp, " %ld/7 ", DOMAIN_GROUP_RID_GUESTS);
+ strcat(domain_groups, tmp);
+
+ DEBUG(3,("domain guest access %s granted\n", tmp));
+ }
+ else
+ {
+ sprintf(tmp, " %ld/7 ", DOMAIN_GROUP_RID_USERS);
+ strcat(domain_groups, tmp);
+
+ DEBUG(3,("domain user access %s granted\n", tmp));
+
+ if (user_in_list(samlogon_user, lp_domain_admin_users()))
+ {
+ sprintf(tmp, " %ld/7 ", DOMAIN_GROUP_RID_ADMINS);
+ strcat(domain_groups, tmp);
+
+ DEBUG(3,("domain admin access %s granted\n", tmp));
+ }
+ }
+
+ num_gids = make_dom_gids(domain_groups, gids);
+
+ sam_logon_in_ssb = False;
+
+ pstrcpy(my_name , myname );
+ strupper(my_name);
+
+ if (name_to_rid(samlogon_user, &r_uid, &r_gid))
+ {
+ make_lsa_user_info(&usr_info,
+
+ &dummy_time, /* logon_time */
+ &dummy_time, /* logoff_time */
+ &dummy_time, /* kickoff_time */
+ &dummy_time, /* pass_last_set_time */
+ &dummy_time, /* pass_can_change_time */
+ &dummy_time, /* pass_must_change_time */
+
+ samlogon_user, /* user_name */
+ vuser->real_name, /* full_name */
+ logon_script, /* logon_script */
+ profile_path, /* profile_path */
+ home_dir, /* home_dir */
+ home_drive, /* dir_drive */
+
+ 0, /* logon_count */
+ 0, /* bad_pw_count */
+
+ r_uid, /* RID user_id */
+ r_gid, /* RID group_id */
+ num_gids, /* uint32 num_groups */
+ gids, /* DOM_GID *gids */
+ 0x20, /* uint32 user_flgs */
+
+ NULL, /* char sess_key[16] */
+
+ my_name , /* char *logon_srv */
+ my_workgroup, /* char *logon_dom */
+
+ dom_sid, /* char *dom_sid */
+ other_sids); /* char *other_sids */
+ }
+ }
+
+ *rdata_len = lsa_reply_sam_logon(&q_l, *rdata + 0x18, *rdata,
+ &srv_cred, &usr_info);
+}
+
+
+BOOL api_netlogrpcTNP(int cnum,int uid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ user_struct *vuser;
+
+ RPC_HDR_RR hdr;
+
+ if (data == NULL)
+ {
+ DEBUG(2,("api_netlogrpcTNP: NULL data received\n"));
+ return False;
+ }
+
+ smb_io_rpc_hdr_rr(True, &hdr, data, data, 4, 0);
+
+ DEBUG(4,("netlogon TransactNamedPipe op %x\n",hdr.opnum));
+
+ if ((vuser = get_valid_user_struct(uid)) == NULL) return False;
+
+ DEBUG(3,("Username of UID %d is %s\n", vuser->uid, vuser->name));
+
+ switch (hdr.opnum)
+ {
+ case LSA_REQCHAL:
+ {
+ DEBUG(3,("LSA_REQCHAL\n"));
+ api_lsa_req_chal(cnum, uid, vuser, param, data, rdata, rdata_len);
+ create_rpc_reply(hdr.hdr.call_id, *rdata, *rdata_len);
+ break;
+ }
+
+ case LSA_AUTH2:
+ {
+ DEBUG(3,("LSA_AUTH2\n"));
+ api_lsa_auth_2(vuser, param, data, rdata, rdata_len);
+ create_rpc_reply(hdr.hdr.call_id, *rdata, *rdata_len);
+ break;
+ }
+
+ case LSA_SRVPWSET:
+ {
+ DEBUG(3,("LSA_SRVPWSET\n"));
+ api_lsa_srv_pwset(vuser, param, data, rdata, rdata_len);
+ create_rpc_reply(hdr.hdr.call_id, *rdata, *rdata_len);
+ break;
+ }
+
+ case LSA_SAMLOGON:
+ {
+ DEBUG(3,("LSA_SAMLOGON\n"));
+ api_lsa_sam_logon(vuser, param, data, rdata, rdata_len);
+ create_rpc_reply(hdr.hdr.call_id, *rdata, *rdata_len);
+ break;
+ }
+
+ case LSA_SAMLOGOFF:
+ {
+ DEBUG(3,("LSA_SAMLOGOFF\n"));
+ api_lsa_sam_logoff(vuser, param, data, rdata, rdata_len);
+ create_rpc_reply(hdr.hdr.call_id, *rdata, *rdata_len);
+ break;
+ }
+
+ default:
+ {
+ DEBUG(4, ("**** netlogon, unknown code: %lx\n", hdr.opnum));
+ break;
+ }
+ }
+
+ return True;
+}
+
+#endif /* NTDOMAIN */
diff --git a/source/pipentlsa.c b/source/pipentlsa.c
new file mode 100644
index 00000000000..ef0f1b3a129
--- /dev/null
+++ b/source/pipentlsa.c
@@ -0,0 +1,464 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Pipe SMB reply routines
+ Copyright (C) Andrew Tridgell 1992-1997,
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997.
+ Copyright (C) Paul Ashton 1997.
+
+ 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 file handles reply_ calls on named pipes that the server
+ makes to handle specific protocols
+*/
+
+
+#include "includes.h"
+#include "trans2.h"
+#include "nterr.h"
+
+extern int DEBUGLEVEL;
+
+#ifdef NTDOMAIN
+
+/***************************************************************************
+lsa_reply_open_policy
+ ***************************************************************************/
+static int lsa_reply_open_policy(char *q, char *base)
+{
+ int i;
+ LSA_R_OPEN_POL r_o;
+
+ /* set up the LSA QUERY INFO response */
+ bzero(&(r_o.pol.data), POL_HND_SIZE);
+ for (i = 4; i < POL_HND_SIZE; i++)
+ {
+ r_o.pol.data[i] = i;
+ }
+ r_o.status = 0x0;
+
+ /* store the response in the SMB stream */
+ q = lsa_io_r_open_pol(False, &r_o, q, base, 4, 0);
+
+ /* return length of SMB data stored */
+ return PTR_DIFF(q, base);
+}
+
+/***************************************************************************
+make_dom_query
+ ***************************************************************************/
+static void make_dom_query(DOM_QUERY *d_q, char *dom_name, char *dom_sid)
+{
+ int domlen = strlen(dom_name);
+
+ d_q->uni_dom_max_len = domlen * 2;
+ d_q->uni_dom_str_len = domlen * 2;
+
+ d_q->buffer_dom_name = 4; /* domain buffer pointer */
+ d_q->buffer_dom_sid = 2; /* domain sid pointer */
+
+ /* this string is supposed to be character short */
+ make_unistr2(&(d_q->uni_domain_name), dom_name, domlen);
+
+ make_dom_sid(&(d_q->dom_sid), dom_sid);
+}
+
+/***************************************************************************
+lsa_reply_query_info
+ ***************************************************************************/
+static int lsa_reply_query_info(LSA_Q_QUERY_INFO *q_q, char *q, char *base,
+ char *dom_name, char *dom_sid)
+{
+ LSA_R_QUERY_INFO r_q;
+
+ /* set up the LSA QUERY INFO response */
+
+ r_q.undoc_buffer = 0x22000000; /* bizarre */
+ r_q.info_class = q_q->info_class;
+
+ make_dom_query(&r_q.dom.id5, dom_name, dom_sid);
+
+ r_q.status = 0x0;
+
+ /* store the response in the SMB stream */
+ q = lsa_io_r_query(False, &r_q, q, base, 4, 0);
+
+ /* return length of SMB data stored */
+ return PTR_DIFF(q, base);
+}
+
+/***************************************************************************
+make_dom_ref
+
+ pretty much hard-coded choice of "other" sids, unfortunately...
+
+ ***************************************************************************/
+static void make_dom_ref(DOM_R_REF *ref,
+ char *dom_name, char *dom_sid,
+ char *other_sid1, char *other_sid2, char *other_sid3)
+{
+ int len_dom_name = strlen(dom_name);
+ int len_other_sid1 = strlen(other_sid1);
+ int len_other_sid2 = strlen(other_sid2);
+ int len_other_sid3 = strlen(other_sid3);
+
+ ref->undoc_buffer = 1;
+ ref->num_ref_doms_1 = 4;
+ ref->buffer_dom_name = 1;
+ ref->max_entries = 32;
+ ref->num_ref_doms_2 = 4;
+
+ make_uni_hdr2(&(ref->hdr_dom_name ), len_dom_name , len_dom_name , 0);
+ make_uni_hdr2(&(ref->hdr_ref_dom[0]), len_other_sid1, len_other_sid1, 0);
+ make_uni_hdr2(&(ref->hdr_ref_dom[1]), len_other_sid2, len_other_sid2, 0);
+ make_uni_hdr2(&(ref->hdr_ref_dom[2]), len_other_sid3, len_other_sid3, 0);
+
+ if (dom_name != NULL)
+ {
+ make_unistr(&(ref->uni_dom_name), dom_name);
+ }
+
+ make_dom_sid(&(ref->ref_dom[0]), dom_sid );
+ make_dom_sid(&(ref->ref_dom[1]), other_sid1);
+ make_dom_sid(&(ref->ref_dom[2]), other_sid2);
+ make_dom_sid(&(ref->ref_dom[3]), other_sid3);
+}
+
+/***************************************************************************
+make_reply_lookup_rids
+ ***************************************************************************/
+static void make_reply_lookup_rids(LSA_R_LOOKUP_RIDS *r_l,
+ int num_entries, uint32 dom_rids[MAX_LOOKUP_SIDS],
+ char *dom_name, char *dom_sid,
+ char *other_sid1, char *other_sid2, char *other_sid3)
+{
+ int i;
+
+ make_dom_ref(&(r_l->dom_ref), dom_name, dom_sid,
+ other_sid1, other_sid2, other_sid3);
+
+ r_l->num_entries = num_entries;
+ r_l->undoc_buffer = 1;
+ r_l->num_entries2 = num_entries;
+
+ for (i = 0; i < num_entries; i++)
+ {
+ make_dom_rid2(&(r_l->dom_rid[i]), dom_rids[i]);
+ }
+
+ r_l->num_entries3 = num_entries;
+}
+
+/***************************************************************************
+make_reply_lookup_sids
+ ***************************************************************************/
+static void make_reply_lookup_sids(LSA_R_LOOKUP_SIDS *r_l,
+ int num_entries, fstring dom_sids[MAX_LOOKUP_SIDS],
+ char *dom_name, char *dom_sid,
+ char *other_sid1, char *other_sid2, char *other_sid3)
+{
+ int i;
+
+ make_dom_ref(&(r_l->dom_ref), dom_name, dom_sid,
+ other_sid1, other_sid2, other_sid3);
+
+ r_l->num_entries = num_entries;
+ r_l->undoc_buffer = 1;
+ r_l->num_entries2 = num_entries;
+
+ for (i = 0; i < num_entries; i++)
+ {
+ make_dom_sid2(&(r_l->dom_sid[i]), dom_sids[i]);
+ }
+
+ r_l->num_entries3 = num_entries;
+}
+
+/***************************************************************************
+lsa_reply_lookup_sids
+ ***************************************************************************/
+static int lsa_reply_lookup_sids(char *q, char *base,
+ int num_entries, fstring dom_sids[MAX_LOOKUP_SIDS],
+ char *dom_name, char *dom_sid,
+ char *other_sid1, char *other_sid2, char *other_sid3)
+{
+ LSA_R_LOOKUP_SIDS r_l;
+
+ /* set up the LSA Lookup SIDs response */
+ make_reply_lookup_sids(&r_l, num_entries, dom_sids,
+ dom_name, dom_sid, other_sid1, other_sid2, other_sid3);
+ r_l.status = 0x0;
+
+ /* store the response in the SMB stream */
+ q = lsa_io_r_lookup_sids(False, &r_l, q, base, 4, 0);
+
+ /* return length of SMB data stored */
+ return PTR_DIFF(q, base);
+}
+
+/***************************************************************************
+lsa_reply_lookup_rids
+ ***************************************************************************/
+static int lsa_reply_lookup_rids(char *q, char *base,
+ int num_entries, uint32 dom_rids[MAX_LOOKUP_SIDS],
+ char *dom_name, char *dom_sid,
+ char *other_sid1, char *other_sid2, char *other_sid3)
+{
+ LSA_R_LOOKUP_RIDS r_l;
+
+ /* set up the LSA Lookup RIDs response */
+ make_reply_lookup_rids(&r_l, num_entries, dom_rids,
+ dom_name, dom_sid, other_sid1, other_sid2, other_sid3);
+ r_l.status = 0x0;
+
+ /* store the response in the SMB stream */
+ q = lsa_io_r_lookup_rids(False, &r_l, q, base, 4, 0);
+
+ /* return length of SMB data stored */
+ return PTR_DIFF(q, base);
+}
+
+/***************************************************************************
+api_lsa_open_policy
+ ***************************************************************************/
+static void api_lsa_open_policy( char *param, char *data,
+ char **rdata, int *rdata_len )
+{
+ LSA_Q_OPEN_POL q_o;
+
+ /* grab the server, object attributes and desired access flag...*/
+ lsa_io_q_open_pol(True, &q_o, data + 0x18, data, 4, 0);
+
+ /* lkclXXXX having decoded it, ignore all fields in the open policy! */
+
+ /* return a 20 byte policy handle */
+ *rdata_len = lsa_reply_open_policy(*rdata + 0x18, *rdata);
+}
+
+/***************************************************************************
+api_lsa_query_info
+ ***************************************************************************/
+static void api_lsa_query_info( char *param, char *data,
+ char **rdata, int *rdata_len )
+{
+ LSA_Q_QUERY_INFO q_i;
+ pstring dom_name;
+ pstring dom_sid;
+
+ /* grab the info class and policy handle */
+ lsa_io_q_query(True, &q_i, data + 0x18, data, 4, 0);
+
+ pstrcpy(dom_name, lp_workgroup());
+ pstrcpy(dom_sid , lp_domain_sid());
+
+ /* construct reply. return status is always 0x0 */
+ *rdata_len = lsa_reply_query_info(&q_i, *rdata + 0x18, *rdata,
+ dom_name, dom_sid);
+}
+
+/***************************************************************************
+api_lsa_lookup_sids
+ ***************************************************************************/
+static void api_lsa_lookup_sids( char *param, char *data,
+ char **rdata, int *rdata_len )
+{
+ int i;
+ LSA_Q_LOOKUP_SIDS q_l;
+ pstring dom_name;
+ pstring dom_sid;
+ fstring dom_sids[MAX_LOOKUP_SIDS];
+
+ /* grab the info class and policy handle */
+ lsa_io_q_lookup_sids(True, &q_l, data + 0x18, data, 4, 0);
+
+ pstrcpy(dom_name, lp_workgroup());
+ pstrcpy(dom_sid , lp_domain_sid());
+
+ /* convert received SIDs to strings, so we can do them. */
+ for (i = 0; i < q_l.num_entries; i++)
+ {
+ fstrcpy(dom_sids[i], dom_sid_to_string(&(q_l.dom_sids[i])));
+ }
+
+ /* construct reply. return status is always 0x0 */
+ *rdata_len = lsa_reply_lookup_sids(*rdata + 0x18, *rdata,
+ q_l.num_entries, dom_sids, /* text-converted SIDs */
+ dom_name, dom_sid, /* domain name, domain SID */
+ "S-1-1", "S-1-3", "S-1-5"); /* the three other SIDs */
+}
+
+/***************************************************************************
+api_lsa_lookup_names
+ ***************************************************************************/
+static void api_lsa_lookup_names( char *param, char *data,
+ char **rdata, int *rdata_len )
+{
+ int i;
+ LSA_Q_LOOKUP_RIDS q_l;
+ pstring dom_name;
+ pstring dom_sid;
+ uint32 dom_rids[MAX_LOOKUP_SIDS];
+ uint32 dummy_g_rid;
+
+ /* grab the info class and policy handle */
+ lsa_io_q_lookup_rids(True, &q_l, data + 0x18, data, 4, 0);
+
+ pstrcpy(dom_name, lp_workgroup());
+ pstrcpy(dom_sid , lp_domain_sid());
+
+ /* convert received RIDs to strings, so we can do them. */
+ for (i = 0; i < q_l.num_entries; i++)
+ {
+ char *user_name = unistr2(q_l.lookup_name[i].str.buffer);
+ if (!name_to_rid(user_name, &dom_rids[i], &dummy_g_rid))
+ {
+ /* WHOOPS! we should really do something about this... */
+ dom_rids[i] = 0;
+ }
+ }
+
+ /* construct reply. return status is always 0x0 */
+ *rdata_len = lsa_reply_lookup_rids(*rdata + 0x18, *rdata,
+ q_l.num_entries, dom_rids, /* text-converted SIDs */
+ dom_name, dom_sid, /* domain name, domain SID */
+ "S-1-1", "S-1-3", "S-1-5"); /* the three other SIDs */
+}
+
+/***************************************************************************
+api_ntLsarpcTNP
+ ***************************************************************************/
+BOOL api_ntLsarpcTNP(int cnum,int uid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ RPC_HDR_RR hdr;
+
+ if (data == NULL)
+ {
+ DEBUG(2,("api_ntLsarpcTNP: NULL data received\n"));
+ return False;
+ }
+
+ smb_io_rpc_hdr_rr(True, &hdr, data, data, 4, 0);
+
+ DEBUG(4,("lsarpc TransactNamedPipe op %x\n",hdr.opnum));
+
+ switch (hdr.opnum)
+ {
+ case LSA_OPENPOLICY:
+ {
+ DEBUG(3,("LSA_OPENPOLICY\n"));
+ api_lsa_open_policy(param, data, rdata, rdata_len);
+ create_rpc_reply(hdr.hdr.call_id, *rdata, *rdata_len);
+ break;
+ }
+
+ case LSA_QUERYINFOPOLICY:
+ {
+ DEBUG(3,("LSA_QUERYINFOPOLICY\n"));
+
+ api_lsa_query_info(param, data, rdata, rdata_len);
+ create_rpc_reply(hdr.hdr.call_id, *rdata, *rdata_len);
+ break;
+ }
+
+ case LSA_ENUMTRUSTDOM:
+ {
+ char *q = *rdata + 0x18;
+
+ DEBUG(3,("LSA_ENUMTRUSTDOM\n"));
+
+ initrpcreply(data, *rdata);
+
+ SIVAL(q, 0, 0); /* enumeration context */
+ SIVAL(q, 0, 4); /* entries read */
+ SIVAL(q, 0, 8); /* trust information */
+
+ q += 12;
+
+ endrpcreply(data, *rdata, q-*rdata, 0x8000001a, rdata_len);
+
+ break;
+ }
+
+ case LSA_CLOSE:
+ {
+ char *q;
+
+ DEBUG(3,("LSA_CLOSE\n"));
+
+ initrpcreply(data, *rdata);
+
+ q = *rdata + 0x18;
+
+ SIVAL(q, 0, 0); q += 4;
+ SIVAL(q, 0, 0); q += 4;
+ SIVAL(q, 0, 0); q += 4;
+ SIVAL(q, 0, 0); q += 4;
+ SIVAL(q, 0, 0); q += 4;
+
+ endrpcreply(data, *rdata, q-*rdata, 0, rdata_len);
+
+ break;
+ }
+
+ case LSA_OPENSECRET:
+ {
+ char *q = *rdata + 0x18;
+ DEBUG(3,("LSA_OPENSECRET\n"));
+
+ initrpcreply(data, *rdata);
+
+ SIVAL(q, 0, 0);
+ SIVAL(q, 0, 4);
+ SIVAL(q, 0, 8);
+ SIVAL(q, 0, 12);
+ SIVAL(q, 0, 16);
+
+ q += 20;
+
+ endrpcreply(data, *rdata, q-*rdata, 0xc000034, rdata_len);
+
+ break;
+ }
+
+ case LSA_LOOKUPSIDS:
+ {
+ DEBUG(3,("LSA_OPENSECRET\n"));
+ api_lsa_lookup_sids(param, data, rdata, rdata_len);
+ create_rpc_reply(hdr.hdr.call_id, *rdata, *rdata_len);
+ break;
+ }
+
+ case LSA_LOOKUPNAMES:
+ {
+ DEBUG(3,("LSA_LOOKUPNAMES\n"));
+ api_lsa_lookup_names(param, data, rdata, rdata_len);
+ create_rpc_reply(hdr.hdr.call_id, *rdata, *rdata_len);
+ break;
+ }
+
+ default:
+ {
+ DEBUG(4, ("NTLSARPC, unknown code: %lx\n", hdr.opnum));
+ break;
+ }
+ }
+ return True;
+}
+
+#endif /* NTDOMAIN */
diff --git a/source/pipesrvsvc.c b/source/pipesrvsvc.c
new file mode 100644
index 00000000000..6e15b2e14b1
--- /dev/null
+++ b/source/pipesrvsvc.c
@@ -0,0 +1,264 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Pipe SMB reply routines - srvsvc pipe
+ Copyright (C) Andrew Tridgell 1992-1997,
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997.
+ Copyright (C) Paul Ashton 1997.
+
+ 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 "trans2.h"
+#include "nterr.h"
+
+extern int DEBUGLEVEL;
+
+
+/*******************************************************************
+********************************************************************/
+static void make_srv_share_info1_str(SH_INFO_1_STR *sh1, char *net_name, char *remark)
+{
+ if (sh1 == NULL) return;
+
+ DEBUG(5,("make_srv_share_info1_str: %s %s\n", net_name, remark));
+
+ make_unistr2(&(sh1->uni_netname), net_name, strlen(net_name)+1);
+ make_unistr2(&(sh1->uni_remark ), remark , strlen(remark )+1);
+}
+
+/*******************************************************************
+********************************************************************/
+static void make_srv_share_info1(SH_INFO_1 *sh1, char *net_name, uint32 type, char *remark)
+{
+ if (sh1 == NULL) return;
+
+ DEBUG(5,("make_srv_share_info1_str: %s %8x %s\n", net_name, type, remark));
+
+ sh1->ptr_netname = net_name != NULL ? 1 : 0;
+ sh1->type = type;
+ sh1->ptr_remark = remark != NULL ? 1 : 0;
+}
+
+/*******************************************************************
+fill in a share info level 1 structure.
+
+this function breaks the rule that i'd like to be in place, namely
+it doesn't receive its data as arguments: it has to call lp_xxxx()
+functions itself. yuck.
+
+this function is identical to api_RNetShareEnum(). maybe it even
+generates the same output! (too much to hope for, really...)
+
+********************************************************************/
+static void make_srv_share_1_ctr(SHARE_INFO_1_CTR *ctr)
+{
+ int snum;
+ int num_entries = 0;
+ int svcs = lp_numservices();
+
+ if (ctr == NULL) return;
+
+ DEBUG(5,("make_srv_share_1_ctr\n"));
+
+ for (snum = 0; snum < svcs && num_entries < MAX_SHARE_ENTRIES; num_entries++, snum++)
+ {
+ int len_net_name;
+ pstring net_name;
+ pstring remark;
+ uint32 type;
+
+ if (lp_browseable(snum) && lp_snum_ok(snum))
+ {
+ /* see ipc.c:fill_share_info() */
+
+ pstrcpy(net_name, lp_servicename(snum));
+ pstrcpy(remark , lp_comment (snum));
+ len_net_name = strlen(net_name);
+
+ /* work out the share type */
+ type = STYPE_DISKTREE;
+
+ if (lp_print_ok(snum)) type = STYPE_PRINTQ;
+ if (strequal("IPC$", net_name)) type = STYPE_IPC;
+ if (net_name[len_net_name] == '$') type |= STYPE_HIDDEN;
+
+ make_srv_share_info1 (&(ctr->info_1 [num_entries]), net_name, type, remark);
+ make_srv_share_info1_str(&(ctr->info_1_str[num_entries]), net_name, remark);
+ }
+ }
+
+ ctr->num_entries_read = num_entries;
+ ctr->ptr_share_info = num_entries > 0 ? 1 : 0;
+ ctr->num_entries_read2 = num_entries;
+ ctr->num_entries_read3 = num_entries;
+ ctr->padding = 0;
+}
+
+/*******************************************************************
+********************************************************************/
+static void make_srv_net_share_enum(SRV_R_NET_SHARE_ENUM *r_n,
+ int share_level, int switch_value, int status)
+{
+ DEBUG(5,("make_srv_net_share_enum: %d\n", __LINE__));
+
+ r_n->share_level = share_level;
+ r_n->switch_value = switch_value;
+ r_n->status = status;
+
+ switch (switch_value)
+ {
+ case 1:
+ {
+ make_srv_share_1_ctr(&(r_n->share.info1));
+ r_n->ptr_share_info = r_n->share.info1.num_entries_read > 0 ? 1 : 0;
+ break;
+ }
+ default:
+ {
+ DEBUG(5,("make_srv_net_share_enum: unsupported switch value %d\n",
+ switch_value));
+ r_n->ptr_share_info = 0;
+ break;
+ }
+ }
+}
+
+/*******************************************************************
+********************************************************************/
+static int srv_reply_net_share_enum(SRV_Q_NET_SHARE_ENUM *q_n,
+ char *q, char *base,
+ int status)
+{
+ SRV_R_NET_SHARE_ENUM r_n;
+
+ DEBUG(5,("srv_net_share_enum: %d\n", __LINE__));
+
+ /* set up the */
+ make_srv_net_share_enum(&r_n, q_n->share_level, q_n->switch_value, status);
+
+ /* store the response in the SMB stream */
+ q = srv_io_r_net_share_enum(False, &r_n, q, base, 4, 0);
+
+ DEBUG(5,("srv_srv_pwset: %d\n", __LINE__));
+
+ /* return length of SMB data stored */
+ return PTR_DIFF(q, base);
+}
+
+/*******************************************************************
+********************************************************************/
+static void api_srv_net_share_info( char *param, char *data,
+ char **rdata, int *rdata_len )
+{
+ SRV_Q_NET_SHARE_ENUM q_n;
+
+ /* grab the net share enum */
+ srv_io_q_net_share_enum(True, &q_n, data + 0x18, data, 4, 0);
+
+ /* XXXX push the reply buffer size up a bit, and hope it's sufficient */
+ /* for the current maximum limit of 32 share entries */
+ *rdata_len = 4096;
+ *rdata = REALLOC(*rdata, *rdata_len);
+
+ /* construct reply. always indicate success */
+ *rdata_len = srv_reply_net_share_enum(&q_n, *rdata + 0x18, *rdata, 0x0);
+}
+
+
+/*******************************************************************
+receives a srvsvc pipe and responds.
+********************************************************************/
+BOOL api_srvsvcTNP(int cnum,int uid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ RPC_HDR_RR hdr;
+
+ if (data == NULL)
+ {
+ DEBUG(2,("api_srvsvcTNP: NULL data received\n"));
+ return False;
+ }
+
+ smb_io_rpc_hdr_rr(True, &hdr, data, data, 4, 0);
+
+ DEBUG(4,("srvsvc TransactNamedPipe op %x\n",hdr.opnum));
+
+ switch (hdr.opnum)
+ {
+ case NETSHAREENUM:
+ {
+ api_srv_net_share_info( param, data, rdata, rdata_len);
+ create_rpc_reply(hdr.hdr.call_id, *rdata, *rdata_len);
+ break;
+ }
+
+ case NETSERVERGETINFO:
+ {
+ extern pstring myname;
+ char *q;
+ char *servername;
+ uint32 level;
+ UNISTR2 uni_str;
+
+ q = data + 0x18;
+
+ servername = q + 16;
+ q = skip_unicode_string(servername,1);
+ if (strlen(unistr(servername)) % 2 == 0)
+ q += 2;
+ level = IVAL(q, 0); q += 4;
+
+ /* ignore the rest for the moment */
+ initrpcreply(data, *rdata);
+ q = *rdata + 0x18;
+
+ SIVAL(q, 0, 101); q += 4; /* switch value */
+ SIVAL(q, 0, 2); q += 4; /* bufptr */
+ SIVAL(q, 0, 0x1f4); q += 4; /* platform id */
+ SIVAL(q, 0, 2); q += 4; /* bufptr for name */
+ SIVAL(q, 0, 5); q += 4; /* major version */
+ SIVAL(q, 0, 4); q += 4; /* minor version == 5.4 */
+ SIVAL(q, 0, 0x4100B); q += 4; /* type */
+ SIVAL(q, 0, 2); q += 4; /* comment */
+
+ get_myname(myname,NULL);
+
+ make_unistr2(&uni_str, myname, strlen(myname));
+ q = smb_io_unistr2(False, &uni_str, q, *rdata, 4, 0);
+
+ make_unistr2(&uni_str, lp_serverstring(), strlen(lp_serverstring()));
+ q = smb_io_unistr2(False, &uni_str, q, *rdata, 4, 0);
+
+ q = align_offset(q, *rdata, 4);
+
+ endrpcreply(data, *rdata, q-*rdata, 0, rdata_len);
+ break;
+ }
+
+ default:
+ {
+ DEBUG(4, ("srvsvc, unknown code: %lx\n", hdr.opnum));
+ break;
+ }
+ }
+
+ return(True);
+}
+
diff --git a/source/pipeutil.c b/source/pipeutil.c
new file mode 100644
index 00000000000..c242dc0fde5
--- /dev/null
+++ b/source/pipeutil.c
@@ -0,0 +1,235 @@
+
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Pipe SMB utility routines
+ Copyright (C) Andrew Tridgell 1992-1997,
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997.
+ Copyright (C) Paul Ashton 1997.
+
+ 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 file handles reply_ calls on named pipes that the server
+ makes to handle specific protocols
+*/
+
+
+#include "includes.h"
+#include "trans2.h"
+
+extern int DEBUGLEVEL;
+
+/* this function is due to be replaced */
+void initrpcreply(char *inbuf, char *q)
+{
+ uint32 callid;
+
+ SCVAL(q, 0, 5); q++; /* RPC version 5 */
+ SCVAL(q, 0, 0); q++; /* minor version 0 */
+ SCVAL(q, 0, 2); q++; /* RPC response packet */
+ SCVAL(q, 0, 3); q++; /* first frag + last frag */
+ RSIVAL(q, 0, 0x10000000); q += 4; /* packed data representation */
+ RSSVAL(q, 0, 0); q += 2; /* fragment length, fill in later */
+ SSVAL(q, 0, 0); q += 2; /* authentication length */
+ callid = RIVAL(inbuf, 12);
+ RSIVAL(q, 0, callid); q += 4; /* call identifier - match incoming RPC */
+ SIVAL(q, 0, 0x18); q += 4; /* allocation hint (no idea) */
+ SSVAL(q, 0, 0); q += 2; /* presentation context identifier */
+ SCVAL(q, 0, 0); q++; /* cancel count */
+ SCVAL(q, 0, 0); q++; /* reserved */
+}
+
+/* this function is due to be replaced */
+void endrpcreply(char *inbuf, char *q, int datalen, int rtnval, int *rlen)
+{
+ SSVAL(q, 8, datalen + 4);
+ SIVAL(q,0x10,datalen+4-0x18); /* allocation hint */
+ SIVAL(q, datalen, rtnval);
+ *rlen = datalen + 4;
+ { int fd; fd = open("/tmp/rpc", O_RDWR); write(fd, q, datalen + 4); }
+}
+
+/* Group and User RID username mapping function */
+BOOL name_to_rid(char *user_name, uint32 *u_rid, uint32 *g_rid)
+{
+ struct passwd *pw = Get_Pwnam(user_name, False);
+
+ if (u_rid == NULL || g_rid == NULL || user_name == NULL)
+ {
+ return False;
+ }
+
+ if (!pw)
+ {
+ DEBUG(1,("Username %s is invalid on this system\n", user_name));
+ return False;
+ }
+
+ if (user_in_list(user_name, lp_domain_guest_users()))
+ {
+ *u_rid = DOMAIN_USER_RID_GUEST;
+ }
+ else if (user_in_list(user_name, lp_domain_admin_users()))
+ {
+ *u_rid = DOMAIN_USER_RID_ADMIN;
+ }
+ else
+ {
+ /* turn the unix UID into a Domain RID. this is what the posix
+ sub-system does (adds 1000 to the uid) */
+ *u_rid = (uint32)(pw->pw_uid + 1000);
+ }
+
+ /* absolutely no idea what to do about the unix GID to Domain RID mapping */
+ *g_rid = (uint32)(pw->pw_gid + 1000);
+
+ return True;
+}
+
+
+/* BIG NOTE: this function only does SIDS where the identauth is not >= 2^32 */
+char *dom_sid_to_string(DOM_SID *sid)
+{
+ static pstring sidstr;
+ char subauth[16];
+ int i;
+ uint32 ia = (sid->id_auth[5]) +
+ (sid->id_auth[4] << 8 ) +
+ (sid->id_auth[3] << 16) +
+ (sid->id_auth[2] << 24);
+
+ sprintf(sidstr, "S-%d-%d", sid->sid_rev_num, ia);
+
+ for (i = 0; i < sid->num_auths; i++)
+ {
+ sprintf(subauth, "-%d", sid->sub_auths[i]);
+ strcat(sidstr, subauth);
+ }
+
+ DEBUG(5,("dom_sid_to_string returning %s\n", sidstr));
+ return sidstr;
+}
+
+int make_dom_sids(char *sids_str, DOM_SID *sids, int max_sids)
+{
+ char *ptr;
+ pstring s2;
+ int count;
+
+ DEBUG(4,("make_dom_sids: %s\n", sids_str));
+
+ if (sids_str == NULL || *sids_str == 0) return 0;
+
+ for (count = 0, ptr = sids_str; next_token(&ptr, s2, NULL) && count < max_sids; count++)
+ {
+ make_dom_sid(&sids[count], s2);
+ }
+
+ return count;
+}
+
+/* array lookup of well-known RID aliases. the purpose of these escapes me.. */
+/* XXXX this structure should not have the well-known RID groups added to it,
+ i.e the DOMAIN_GROUP_RID_ADMIN/USER/GUEST. */
+static struct
+{
+ uint32 rid;
+ char *rid_name;
+
+} rid_lookups[] =
+{
+ { DOMAIN_ALIAS_RID_ADMINS , "admins" },
+ { DOMAIN_ALIAS_RID_USERS , "users" },
+ { DOMAIN_ALIAS_RID_GUESTS , "guests" },
+ { DOMAIN_ALIAS_RID_POWER_USERS , "power_users" },
+
+ { DOMAIN_ALIAS_RID_ACCOUNT_OPS , "account_ops" },
+ { DOMAIN_ALIAS_RID_SYSTEM_OPS , "system_ops" },
+ { DOMAIN_ALIAS_RID_PRINT_OPS , "print_ops" },
+ { DOMAIN_ALIAS_RID_BACKUP_OPS , "backup_ops" },
+ { DOMAIN_ALIAS_RID_REPLICATOR , "replicator" },
+ { 0 , NULL }
+};
+
+int make_dom_gids(char *gids_str, DOM_GID *gids)
+{
+ char *ptr;
+ pstring s2;
+ int count;
+
+ DEBUG(4,("make_dom_gids: %s\n", gids_str));
+
+ if (gids_str == NULL || *gids_str == 0) return 0;
+
+ for (count = 0, ptr = gids_str; next_token(&ptr, s2, NULL) && count < LSA_MAX_GROUPS; count++)
+ {
+ /* the entries are of the form GID/ATTR, ATTR being optional.*/
+ char *attr;
+ uint32 rid = 0;
+ int i;
+
+ attr = strchr(s2,'/');
+ if (attr) *attr++ = 0;
+ if (!attr || !*attr) attr = "7"; /* default value for attribute is 7 */
+
+ /* look up the RID string and see if we can turn it into a rid number */
+ for (i = 0; rid_lookups[i].rid_name != NULL; i++)
+ {
+ if (strequal(rid_lookups[i].rid_name, s2))
+ {
+ rid = rid_lookups[i].rid;
+ break;
+ }
+ }
+
+ if (rid == 0) rid = atoi(s2);
+
+ if (rid == 0)
+ {
+ DEBUG(1,("make_dom_gids: unknown well-known alias RID %s/%s\n",
+ s2, attr));
+ count--;
+ }
+ else
+ {
+ gids[count].g_rid = rid;
+ gids[count].attr = atoi(attr);
+
+ DEBUG(5,("group id: %d attr: %d\n",
+ gids[count].g_rid,
+ gids[count].attr));
+ }
+ }
+
+ return count;
+}
+
+int create_rpc_request(uint32 call_id, uint8 op_num, char *q, int data_len)
+{
+ RPC_HDR_RR hdr;
+
+ make_rpc_hdr_rr(&hdr, RPC_REQUEST, call_id, data_len, op_num);
+ return smb_io_rpc_hdr_rr(False, &hdr, q, q, 4, 0) - q;
+}
+
+int create_rpc_reply(uint32 call_id, char *q, int data_len)
+{
+ RPC_HDR_RR hdr;
+
+ make_rpc_hdr_rr(&hdr, RPC_RESPONSE, call_id, data_len, 0);
+ return smb_io_rpc_hdr_rr(False, &hdr, q, q, 4, 0) - q;
+}
+
diff --git a/source/printing/pcap.c b/source/printing/pcap.c
index 8973b1627fb..65195ab1af6 100644
--- a/source/printing/pcap.c
+++ b/source/printing/pcap.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
printcap parsing
- Copyright (C) Karl Auer 1993,1994
+ Copyright (C) Karl Auer 1993-1997
Re-working by Martin Kiff, 1994
@@ -54,8 +54,6 @@
#include "includes.h"
#include "smb.h"
-#include "loadparm.h"
-#include "pcap.h"
extern int DEBUGLEVEL;
@@ -360,8 +358,8 @@ void pcap_printer_fn(void (*fn)())
if (strlen(p) <= 8 && strlen(p)>strlen(name) && !has_punctuation)
{
- if (!*comment) strcpy(comment,name);
- strcpy(name,p);
+ if (!*comment) pstrcpy(comment,name);
+ pstrcpy(name,p);
continue;
}
diff --git a/source/printing/printing.c b/source/printing/printing.c
index 1dd8921800a..51fd3a992eb 100644
--- a/source/printing/printing.c
+++ b/source/printing/printing.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
printing routines
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1997
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,7 +20,6 @@
*/
#include "includes.h"
-#include "loadparm.h"
extern int DEBUGLEVEL;
extern connection_struct Connections[];
extern files_struct Files[];
@@ -74,7 +73,7 @@ static char *build_print_command(int cnum, char *command, char *syscmd, char *fi
}
if (strstr(syscmd,"%s")) {
- int iOffset = strstr(syscmd, "%s") - syscmd;
+ int iOffset = PTR_DIFF(strstr(syscmd, "%s"),syscmd);
/* construct the full path for the filename, shouldn't be necessary unless
the subshell causes a "cd" to be executed.
@@ -86,7 +85,7 @@ static char *build_print_command(int cnum, char *command, char *syscmd, char *fi
strcat(filename,filename1);
}
else
- strcpy(filename,filename1);
+ pstrcpy(filename,filename1);
string_sub(syscmd, "%s", filename);
}
@@ -131,7 +130,7 @@ void print_file(int fnum)
tempstr = build_print_command(cnum, PRINTCOMMAND(snum), syscmd, Files[fnum].name);
if (tempstr != NULL)
{
- int ret = smbrun(syscmd,NULL);
+ int ret = smbrun(syscmd,NULL,False);
DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
}
else
@@ -149,7 +148,7 @@ process time fields
********************************************************************/
static time_t EntryTime(string tok[], int ptr, int count, int minimum)
{
- time_t jobtime;
+ time_t jobtime,jobtime1;
jobtime = time(NULL); /* default case: take current time */
if (count >= minimum) {
@@ -181,7 +180,9 @@ static time_t EntryTime(string tok[], int ptr, int count, int minimum)
t->tm_hour = hour;
t->tm_min = min;
t->tm_sec = sec;
- jobtime = mktime(t);
+ jobtime1 = mktime(t);
+ if (jobtime1 != (time_t)-1)
+ jobtime = jobtime1;
}
}
return jobtime;
@@ -257,7 +258,7 @@ static BOOL parse_lpq_bsd(char *line,print_queue_struct *buf,BOOL first)
if (p)
{
strcpy(tmp,p+1);
- strcpy(tok[FILETOK],tmp);
+ fstrcpy(tok[FILETOK],tmp);
}
}
@@ -276,6 +277,157 @@ static BOOL parse_lpq_bsd(char *line,print_queue_struct *buf,BOOL first)
return(True);
}
+/*
+<magnus@hum.auc.dk>
+LPRng_time modifies the current date by inserting the hour and minute from
+the lpq output. The lpq time looks like "23:15:07"
+*/
+static time_t LPRng_time(string tok[],int pos)
+{
+ time_t jobtime;
+ struct tm *t;
+ char tmp_time[9];
+
+ jobtime = time(NULL); /* default case: take current time */
+ t = localtime(&jobtime);
+ t->tm_hour = atoi(tok[pos]);
+ StrnCpy(tmp_time,tok[pos],sizeof(tmp_time));
+ t->tm_min = atoi(tmp_time+3);
+ t->tm_sec = atoi(tmp_time+6);
+ jobtime = mktime(t);
+
+ return jobtime;
+}
+
+
+/****************************************************************************
+ parse a lpq line
+ <magnus@hum.auc.dk>
+ Most of the code is directly reused from parse_lpq_bsd()
+
+here are two examples of lpq output under lprng (LPRng-2.3.0)
+
+Printer: humprn@hum-fak
+ Queue: 1 printable job
+ Server: pid 4840 active, Unspooler: pid 4841 active
+ Status: job 'cfA659hum-fak', closing device at Fri Jun 21 10:10:21 1996
+ Rank Owner Class Job Files Size Time
+active magnus@hum-fak A 659 /var/spool/smb/Notesblok-ikke-na4024 10:03:31
+
+Printer: humprn@hum-fak (printing disabled)
+ Queue: 1 printable job
+ Warning: no server present
+ Status: finished operations at Fri Jun 21 10:10:32 1996
+ Rank Owner Class Job Files Size Time
+1 magnus@hum-fak A 387 /var/spool/smb/netbudget.xls 21230 10:50:53
+
+****************************************************************************/
+static BOOL parse_lpq_lprng(char *line,print_queue_struct *buf,BOOL first)
+{
+#define LPRNG_RANKTOK 0
+#define LPRNG_USERTOK 1
+#define LPRNG_PRIOTOK 2
+#define LPRNG_JOBTOK 3
+#define LPRNG_FILETOK 4
+#define LPRNG_TOTALTOK 5
+#define LPRNG_TIMETOK 6
+#define LPRNG_NTOK 7
+
+/****************************************************************************
+From lpd_status.c in LPRng source.
+0 1 2 3 4 5 6 7
+12345678901234567890123456789012345678901234567890123456789012345678901234
+" Rank Owner Class Job Files Size Time"
+ plp_snprintf( msg, sizeof(msg), "%-6s %-19s %c %03d %-32s",
+ number, line, priority, cfp->number, error );
+ plp_snprintf( msg + len, sizeof(msg)-len, "%4d",
+ cfp->jobsize );
+ plp_snprintf( msg+len, sizeof(msg)-len, " %s",
+ Time_str( 1, cfp->statb.st_ctime ) );
+****************************************************************************/
+ /* The following define's are to be able to adjust the values if the
+LPRng source changes. This is from version 2.3.0. Magnus */
+#define SPACE_W 1
+#define RANK_W 6
+#define OWNER_W 19
+#define CLASS_W 1
+#define JOB_W 3
+#define FILE_W 32
+/* The JOBSIZE_W is too small for big jobs, so time is pushed to the right */
+#define JOBSIZE_W 4
+
+#define RANK_POS 0
+#define OWNER_POS RANK_POS+RANK_W+SPACE_W
+#define CLASS_POS OWNER_POS+OWNER_W+SPACE_W
+#define JOB_POS CLASS_POS+CLASS_W+SPACE_W
+#define FILE_POS JOB_POS+JOB_W+SPACE_W
+#define JOBSIZE_POS FILE_POS+FILE_W
+
+
+ string tok[LPRNG_NTOK];
+ int count=0;
+
+/*
+Need to insert one space in front of the size, to be able to use
+next_token() unchanged. I would have liked to be able to insert a
+space instead, to prevent losing that one char, but perl has spoiled
+me :-\ So I did it the easiest way.
+
+HINT: Use as short a path as possible for the samba spool directory.
+A long spool-path will just waste significant chars of the file name.
+*/
+
+ line[JOBSIZE_POS-1]=' ';
+
+ /* handle the case of "(stdin)" as a filename */
+ string_sub(line,"stdin","STDIN");
+ string_sub(line,"(","\"");
+ string_sub(line,")","\"");
+
+ for (count=0; count<LPRNG_NTOK && next_token(&line,tok[count],NULL); count++) ;
+
+ /* we must get LPRNG_NTOK tokens */
+ if (count < LPRNG_NTOK)
+ return(False);
+
+ /* the Job and Total columns must be integer */
+ if (!isdigit(*tok[LPRNG_JOBTOK]) || !isdigit(*tok[LPRNG_TOTALTOK])) return(False);
+
+ /* if the fname contains a space then use STDIN */
+ /* I do not understand how this would be possible. Magnus. */
+ if (strchr(tok[LPRNG_FILETOK],' '))
+ strcpy(tok[LPRNG_FILETOK],"STDIN");
+
+ /* only take the last part of the filename */
+ {
+ string tmp;
+ char *p = strrchr(tok[LPRNG_FILETOK],'/');
+ if (p)
+ {
+ fstrcpy(tmp,p+1);
+ fstrcpy(tok[LPRNG_FILETOK],tmp);
+ }
+ }
+
+
+ buf->job = atoi(tok[LPRNG_JOBTOK]);
+ buf->size = atoi(tok[LPRNG_TOTALTOK]);
+ buf->status = strequal(tok[LPRNG_RANKTOK],"active")?LPQ_PRINTING:LPQ_QUEUED;
+ /* buf->time = time(NULL); */
+ buf->time = LPRng_time(tok,LPRNG_TIMETOK);
+DEBUG(3,("Time reported for job %d is %s", buf->job, ctime(&buf->time)));
+ StrnCpy(buf->user,tok[LPRNG_USERTOK],sizeof(buf->user)-1);
+ StrnCpy(buf->file,tok[LPRNG_FILETOK],sizeof(buf->file)-1);
+#ifdef LPRNG_PRIOTOK
+ /* Here I try to map the CLASS char to a number, but the number
+ is never shown in Print Manager under NT anyway... Magnus. */
+ buf->priority = atoi(tok[LPRNG_PRIOTOK]-('A'-1));
+#else
+ buf->priority = 1;
+#endif
+ return(True);
+}
+
/*******************************************************************
@@ -320,8 +472,8 @@ static BOOL parse_lpq_aix(char *line,print_queue_struct *buf,BOOL first)
char *p = strrchr(tok[2],'/');
if (p)
{
- strcpy(tmp,p+1);
- strcpy(tok[2],tmp);
+ fstrcpy(tmp,p+1);
+ fstrcpy(tok[2],tmp);
}
}
@@ -354,8 +506,8 @@ static BOOL parse_lpq_aix(char *line,print_queue_struct *buf,BOOL first)
char *p = strrchr(tok[4],'/');
if (p)
{
- strcpy(tmp,p+1);
- strcpy(tok[4],tmp);
+ fstrcpy(tmp,p+1);
+ fstrcpy(tok[4],tmp);
}
}
@@ -514,8 +666,8 @@ static BOOL parse_lpq_sysv(char *line,print_queue_struct *buf,BOOL first)
if ((p=strchr(tok[2],'!')))
{
string tmp;
- strcpy(tmp,p+1);
- strcpy(tok[2],tmp);
+ fstrcpy(tmp,p+1);
+ fstrcpy(tok[2],tmp);
}
@@ -579,8 +731,8 @@ static BOOL parse_lpq_qnx(char *line,print_queue_struct *buf,BOOL first)
char *p = strrchr(tok[6],'/');
if (p)
{
- strcpy(tmp,p+1);
- strcpy(tok[6],tmp);
+ fstrcpy(tmp,p+1);
+ fstrcpy(tok[6],tmp);
}
}
@@ -596,6 +748,76 @@ static BOOL parse_lpq_qnx(char *line,print_queue_struct *buf,BOOL first)
}
+/****************************************************************************
+ parse a lpq line for the plp printing system
+ Bertrand Wallrich <Bertrand.Wallrich@loria.fr>
+
+redone by tridge. Here is a sample queue:
+
+Local Printer 'lp2' (fjall):
+ Printing (started at Jun 15 13:33:58, attempt 1).
+ Rank Owner Pr Opt Job Host Files Size Date
+ active tridge X - 6 fjall /etc/hosts 739 Jun 15 13:33
+ 3rd tridge X - 7 fjall /etc/hosts 739 Jun 15 13:33
+
+****************************************************************************/
+static BOOL parse_lpq_plp(char *line,print_queue_struct *buf,BOOL first)
+{
+ string tok[11];
+ int count=0;
+
+ /* handle the case of "(standard input)" as a filename */
+ string_sub(line,"stdin","STDIN");
+ string_sub(line,"(","\"");
+ string_sub(line,")","\"");
+
+ for (count=0; count<11 && next_token(&line,tok[count],NULL); count++) ;
+
+ /* we must get 11 tokens */
+ if (count < 11)
+ return(False);
+
+ /* the first must be "active" or begin with an integer */
+ if (strcmp(tok[0],"active") && !isdigit(tok[0][0]))
+ return(False);
+
+ /* the 5th and 8th must be integer */
+ if (!isdigit(*tok[4]) || !isdigit(*tok[7]))
+ return(False);
+
+ /* if the fname contains a space then use STDIN */
+ if (strchr(tok[6],' '))
+ strcpy(tok[6],"STDIN");
+
+ /* only take the last part of the filename */
+ {
+ string tmp;
+ char *p = strrchr(tok[6],'/');
+ if (p)
+ {
+ fstrcpy(tmp,p+1);
+ fstrcpy(tok[6],tmp);
+ }
+ }
+
+
+ buf->job = atoi(tok[4]);
+
+ buf->size = atoi(tok[7]);
+ if (strchr(tok[7],'K'))
+ buf->size *= 1024;
+ if (strchr(tok[7],'M'))
+ buf->size *= 1024*1024;
+
+ buf->status = strequal(tok[0],"active")?LPQ_PRINTING:LPQ_QUEUED;
+ buf->priority = 0;
+ buf->time = time(NULL);
+ StrnCpy(buf->user,tok[1],sizeof(buf->user)-1);
+ StrnCpy(buf->file,tok[6],sizeof(buf->file)-1);
+ return(True);
+}
+
+
char *stat0_strings[] = { "enabled", "online", "idle", "no entries", "free", "ready", NULL };
char *stat1_strings[] = { "offline", "disabled", "down", "off", "waiting", "no daemon", NULL };
@@ -624,6 +846,12 @@ static BOOL parse_lpq_entry(int snum,char *line,
case PRINT_QNX:
ret = parse_lpq_qnx(line,buf,first);
break;
+ case PRINT_LPRNG:
+ ret = parse_lpq_lprng(line,buf,first);
+ break;
+ case PRINT_PLP:
+ ret = parse_lpq_plp(line,buf,first);
+ break;
default:
ret = parse_lpq_bsd(line,buf,first);
break;
@@ -635,10 +863,16 @@ static BOOL parse_lpq_entry(int snum,char *line,
/* change guest entries to the current logged in user to make
them appear deletable to windows */
if (sesssetup_user[0] && strequal(buf->user,lp_guestaccount(snum)))
- strcpy(buf->user,sesssetup_user);
+ pstrcpy(buf->user,sesssetup_user);
}
#endif
+ /* We don't want the newline in the status message. */
+ {
+ char *p = strchr(line,'\n');
+ if (p) *p = 0;
+ }
+
if (status && !ret)
{
/* a few simple checks to see if the line might be a
@@ -689,15 +923,14 @@ int get_printqueue(int snum,int cnum,print_queue_struct **queue,
struct stat sbuf;
BOOL dorun=True;
int cachetime = lp_lpqcachetime();
- int lfd = -1;
*line = 0;
check_lpq_cache(snum);
if (!printername || !*printername)
{
- DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
- lp_servicename(snum),snum));
+ DEBUG(6,("xx replacing printer name with service (snum=(%s,%d))\n",
+ lp_servicename(snum),snum));
printername = lp_servicename(snum);
}
@@ -707,12 +940,12 @@ int get_printqueue(int snum,int cnum,print_queue_struct **queue,
return(0);
}
- strcpy(syscmd,lpq_command);
+ pstrcpy(syscmd,lpq_command);
string_sub(syscmd,"%p",printername);
standard_sub(cnum,syscmd);
- sprintf(outfile,"/tmp/lpq.%08x",str_checksum(syscmd));
+ sprintf(outfile,"%s/lpq.%08x",tmpdir(),str_checksum(syscmd));
if (!lpq_cache_reset[snum] && cachetime && !stat(outfile,&sbuf))
{
@@ -720,20 +953,10 @@ int get_printqueue(int snum,int cnum,print_queue_struct **queue,
DEBUG(3,("Using cached lpq output\n"));
dorun = False;
}
-
- if (dorun) {
- lfd = file_lock(outfile,LPQ_LOCK_TIMEOUT);
- if (lfd<0 ||
- (!fstat(lfd,&sbuf) && (time(NULL) - sbuf.st_mtime)<cachetime)) {
- DEBUG(3,("Using cached lpq output\n"));
- dorun = False;
- file_unlock(lfd); lfd = -1;
- }
- }
}
if (dorun) {
- ret = smbrun(syscmd,outfile);
+ ret = smbrun(syscmd,outfile,True);
DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
}
@@ -741,7 +964,6 @@ int get_printqueue(int snum,int cnum,print_queue_struct **queue,
f = fopen(outfile,"r");
if (!f) {
- if (lfd >= 0) file_unlock(lfd);
return(0);
}
@@ -772,12 +994,13 @@ int get_printqueue(int snum,int cnum,print_queue_struct **queue,
fclose(f);
- if (lfd >= 0) file_unlock(lfd);
-
- if (!cachetime)
+ if (!cachetime) {
unlink(outfile);
- else
+ } else {
+ /* we only expect this to succeed on trapdoor systems, on normal systems
+ the file is owned by root */
chmod(outfile,0666);
+ }
return(count);
}
@@ -808,12 +1031,12 @@ void del_printqueue(int cnum,int snum,int jobid)
sprintf(jobstr,"%d",jobid);
- strcpy(syscmd,lprm_command);
+ pstrcpy(syscmd,lprm_command);
string_sub(syscmd,"%p",printername);
string_sub(syscmd,"%j",jobstr);
standard_sub(cnum,syscmd);
- ret = smbrun(syscmd,NULL);
+ ret = smbrun(syscmd,NULL,False);
DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
lpq_reset(snum); /* queue has changed */
}
@@ -846,14 +1069,34 @@ void status_printjob(int cnum,int snum,int jobid,int status)
sprintf(jobstr,"%d",jobid);
- strcpy(syscmd,lpstatus_command);
+ pstrcpy(syscmd,lpstatus_command);
string_sub(syscmd,"%p",printername);
string_sub(syscmd,"%j",jobstr);
standard_sub(cnum,syscmd);
- ret = smbrun(syscmd,NULL);
+ ret = smbrun(syscmd,NULL,False);
DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
lpq_reset(snum); /* queue has changed */
}
+
+/****************************************************************************
+we encode print job numbers over the wire so that when we get them back we can
+tell not only what print job they are but also what service it belongs to,
+this is to overcome the problem that windows clients tend to send the wrong
+service number when doing print queue manipulation!
+****************************************************************************/
+int printjob_encode(int snum, int job)
+{
+ return ((snum&0xFF)<<8) | (job & 0xFF);
+}
+
+/****************************************************************************
+and now decode them again ...
+****************************************************************************/
+void printjob_decode(int jobid, int *snum, int *job)
+{
+ (*snum) = (jobid >> 8) & 0xFF;
+ (*job) = jobid & 0xFF;
+}
diff --git a/source/script/installbin.sh b/source/script/installbin.sh
index 633e6cb5bb2..b976a3e5ea8 100755
--- a/source/script/installbin.sh
+++ b/source/script/installbin.sh
@@ -34,7 +34,9 @@ done
cat << EOF
======================================================================
The binaries are installed. You may restore the old binaries (if there
-were any) using the command "make revert"
+were any) using the command "make revert". You may uninstall the binaries
+using the command "make uninstallbin" or "make uninstall" to uninstall
+binaries, man pages and shell scripts.
======================================================================
EOF
diff --git a/source/script/installcp.sh b/source/script/installcp.sh
new file mode 100755
index 00000000000..bafd84146d7
--- /dev/null
+++ b/source/script/installcp.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+LIBDIR=$1
+CODEPAGEDIR=$2
+BINDIR=$3
+
+shift
+shift
+shift
+
+echo Installing codepage files in $CODEPAGEDIR
+for d in $LIBDIR $CODEPAGEDIR; do
+if [ ! -d $d ]; then
+mkdir $d
+if [ ! -d $d ]; then
+ echo Failed to make directory $d
+ exit 1
+fi
+fi
+done
+
+for p in $*; do
+ echo Creating codepage file $CODEPAGEDIR/codepage.$p from codepage_def.$p
+ $BINDIR/make_smbcodepage c $p codepage_def.$p $CODEPAGEDIR/codepage.$p
+done
+
+
+cat << EOF
+======================================================================
+The code pages have been installed. You may uninstall them using the command
+the command "make uninstallcp" or make "uninstall" to uninstall binaries,
+man pages, shell scripts and code pages.
+======================================================================
+EOF
+
+exit 0
+
diff --git a/source/script/installman.sh b/source/script/installman.sh
index a79d157c5f5..3c8fc718654 100755
--- a/source/script/installman.sh
+++ b/source/script/installman.sh
@@ -1,4 +1,6 @@
#!/bin/sh
+#5 July 96 Dan.Shearer@unisa.edu.au removed hardcoded values
+
MANDIR=$1
SRCDIR=$2
@@ -8,28 +10,29 @@ for d in $MANDIR $MANDIR/man1 $MANDIR/man5 $MANDIR/man7 $MANDIR/man8; do
if [ ! -d $d ]; then
mkdir $d
if [ ! -d $d ]; then
- echo Failed to make directory $d
+ echo Failed to make directory $d, does $USER have privileges?
exit 1
fi
fi
done
-cp $SRCDIR../docs/*.1 $MANDIR/man1
-cp $SRCDIR../docs/*.5 $MANDIR/man5
-cp $SRCDIR../docs/*.8 $MANDIR/man8
-cp $SRCDIR../docs/*.7 $MANDIR/man7
-echo Setting permissions on man pages
-chmod 0644 $MANDIR/man1/smbstatus.1
-chmod 0644 $MANDIR/man1/smbclient.1
-chmod 0644 $MANDIR/man1/smbrun.1
-chmod 0644 $MANDIR/man1/testparm.1
-chmod 0644 $MANDIR/man1/testprns.1
-chmod 0644 $MANDIR/man1/smbtar.1
-chmod 0644 $MANDIR/man5/smb.conf.5
-chmod 0644 $MANDIR/man7/samba.7
-chmod 0644 $MANDIR/man8/smbd.8
-chmod 0644 $MANDIR/man8/nmbd.8
+for sect in 1 5 7 8 ; do
+ for m in $MANDIR/man$sect ; do
+ for s in $SRCDIR../docs/*$sect; do
+ FNAME=$m/`basename $s`
+ cp $s $m || echo Cannot create $FNAME... does $USER have privileges?
+ chmod 0644 $FNAME
+ done
+ done
+done
+
+cat << EOF
+======================================================================
+The man pages have been installed. You may uninstall them using the command
+the command "make uninstallman" or make "uninstall" to uninstall binaries,
+man pages and shell scripts.
+======================================================================
+EOF
-echo Man pages installed
exit 0
diff --git a/source/script/installscripts.sh b/source/script/installscripts.sh
new file mode 100755
index 00000000000..1a230c8cfa2
--- /dev/null
+++ b/source/script/installscripts.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+# this script courtesy of James_K._Foote.PARC@xerox.com
+# 5 July 96 Dan.Shearer@UniSA.Edu.Au Don't hardcode script names, get from Make
+
+INSTALLPERMS=$1
+BINDIR=$2
+
+shift
+shift
+
+echo Installing scripts in $BINDIR
+
+for d in $BINDIR; do
+ if [ ! -d $d ]; then
+ mkdir $d
+ if [ ! -d $d ]; then
+ echo Failed to make directory $d
+ echo Have you run installbin first?
+ exit 1
+ fi
+ fi
+done
+
+for p in $*; do
+ echo Installing $BINDIR/$p
+ cp $p $BINDIR/$p
+ if [ ! -f $BINDIR/$p ]; then
+ echo Cannot copy $p... does $USER have privileges?
+ fi
+ echo Setting permissions on $BINDIR/$p
+ chmod $INSTALLPERMS $BINDIR/$p
+done
+
+cat << EOF
+======================================================================
+The scripts have been installed. You may uninstall them using
+the command "make uninstallscripts" or "make install" to install binaries,
+man pages and shell scripts. You may recover the previous version (if any
+by "make revert".
+======================================================================
+EOF
+
+exit 0
diff --git a/source/script/mkproto.awk b/source/script/mkproto.awk
new file mode 100644
index 00000000000..1ccf2fb2b0a
--- /dev/null
+++ b/source/script/mkproto.awk
@@ -0,0 +1,82 @@
+BEGIN {
+ inheader=0;
+ current_file="";
+ print "/* This file is automatically generated with \"make proto\". DO NOT EDIT */"
+ print ""
+}
+
+{
+ if (FILENAME!=current_file) {
+ print ""
+ print "/*The following definitions come from ",FILENAME," */"
+ print ""
+ current_file=FILENAME
+ }
+ if (inheader) {
+ if (match($0,"[)][ \t]*$")) {
+ inheader = 0;
+ printf "%s;\n",$0;
+ } else {
+ printf "%s\n",$0;
+ }
+ next;
+ }
+}
+
+# we handle the loadparm.c fns separately
+
+/^FN_LOCAL_BOOL/ {
+ split($0,a,"[,()]")
+ printf "BOOL %s(int );\n", a[2]
+}
+
+/^FN_LOCAL_STRING/ {
+ split($0,a,"[,()]")
+ printf "char *%s(int );\n", a[2]
+}
+
+/^FN_LOCAL_INT/ {
+ split($0,a,"[,()]")
+ printf "int %s(int );\n", a[2]
+}
+
+/^FN_LOCAL_CHAR/ {
+ split($0,a,"[,()]")
+ printf "char %s(int );\n", a[2]
+}
+
+/^FN_GLOBAL_BOOL/ {
+ split($0,a,"[,()]")
+ printf "BOOL %s(void);\n", a[2]
+}
+
+/^FN_GLOBAL_STRING/ {
+ split($0,a,"[,()]")
+ printf "char *%s(void);\n", a[2]
+}
+
+/^FN_GLOBAL_INT/ {
+ split($0,a,"[,()]")
+ printf "int %s(void);\n", a[2]
+}
+
+/^static|^extern/ || !/^[a-zA-Z]/ || /[;]/ {
+ next;
+}
+
+!/^unsigned|^mode_t|^DIR|^user|^int|^char|^uint|^struct|^BOOL|^void|^time|^smb_shm_offset_t|^shm_offset_t|^enum remote_arch_types|arc4_key/ {
+ next;
+}
+
+
+/[(].*[)][ \t]*$/ {
+ printf "%s;\n",$0;
+ next;
+}
+
+/[(]/ {
+ inheader=1;
+ printf "%s\n",$0;
+ next;
+}
+
diff --git a/source/script/smbtar b/source/script/smbtar
index fc032ed41cd..dcf01edb208 100644
--- a/source/script/smbtar
+++ b/source/script/smbtar
@@ -11,8 +11,8 @@ case $0 in
# when called by absolute path, assume smbclient is in the same directory
/*)
SMBCLIENT="`dirname $0`/smbclient";;
- *) # edit this to show where your smbclient is
- SMBCLIENT="./smbclient";;
+ *) # you may need to edit this to show where your smbclient is
+ SMBCLIENT="smbclient";;
esac
# These are the default values. You could fill them in if you know what
@@ -88,7 +88,7 @@ while getopts rivl:b:d:N:s:p:x:u:Xt: c; do
server="$OPTARG"
;;
b) # specify [b]locksize
- blocksize="blocksize $OPTARG"
+ blocksize="$OPTARG"
case "$OPTARG" in
[0-9]*) ;;
*) echo >&2 "$0: Error, block size not numeric: -b $OPTARG"
@@ -138,4 +138,3 @@ eval $SMBCLIENT "'\\\\$server\\$service'" "'$password'" -U "'$username'" \
-E -N $log -D "'$cdcmd'" \
-T${tarcmd}${tarargs} $blocksize $newer $tapefile $* $verbose
-
diff --git a/source/script/uninstallbin.sh b/source/script/uninstallbin.sh
new file mode 100755
index 00000000000..fab36804a29
--- /dev/null
+++ b/source/script/uninstallbin.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+#4 July 96 Dan.Shearer@UniSA.edu.au
+
+INSTALLPERMS=$1
+BASEDIR=$2
+BINDIR=$3
+LIBDIR=$4
+VARDIR=$5
+shift
+shift
+shift
+shift
+shift
+
+if [ ! -d $BINDIR ]; then
+ echo Directory $BINDIR does not exist!
+ echo Do a "make installbin" or "make install" first.
+ exit 1
+fi
+
+for p in $*; do
+ if [ ! -f $BINDIR/$p ]; then
+ echo $BINDIR/$p does not exist!
+ else
+ echo Removing $BINDIR/$p
+ rm -f $BINDIR/$p
+ if [ -f $BINDIR/$p ]; then
+ echo Cannot remove $BINDIR/$p... does $USER have privileges?
+ fi
+ fi
+done
+
+
+cat << EOF
+======================================================================
+The binaries have been uninstalled. You may restore the binaries using
+the command "make installbin" or "make install" to install binaries,
+man pages and shell scripts. You can restore a previous version of the
+binaries (if there were any) using "make revert".
+======================================================================
+EOF
+
+exit 0
diff --git a/source/script/uninstallcp.sh b/source/script/uninstallcp.sh
new file mode 100755
index 00000000000..bd7013c358f
--- /dev/null
+++ b/source/script/uninstallcp.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+CPDIR=$1
+shift
+
+if [ ! -d $CPDIR ]; then
+ echo Directory $CPDIR does not exist!
+ echo Do a "make installcp" or "make install" first.
+ exit 1
+fi
+
+for p in $*; do
+ if [ ! -f $CPDIR/codepage.$p ]; then
+ echo $CPDIR/codepage.$p does not exist!
+ else
+ echo Removing $CPDIR/codepage.$p
+ rm -f $CPDIR/codepage.$p
+ if [ -f $CPDIR/codepage.$p ]; then
+ echo Cannot remove $CPDIR/codepage.$p... does $USER have privileges?
+ fi
+ fi
+done
+
+cat << EOF
+======================================================================
+The code pages have been uninstalled. You may reinstall them using
+the command "make installcp" or "make install" to install binaries,
+man pages, shell scripts and code pages. You may recover a previous version
+(if any with "make revert").
+======================================================================
+EOF
+
+exit 0
diff --git a/source/script/uninstallman.sh b/source/script/uninstallman.sh
new file mode 100755
index 00000000000..b4d4bfc1f92
--- /dev/null
+++ b/source/script/uninstallman.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+#4 July 96 Dan.Shearer@UniSA.edu.au
+
+MANDIR=$1
+SRCDIR=$2
+
+echo Uninstalling man pages from $MANDIR
+
+for sect in 1 5 7 8 ; do
+ for m in $MANDIR/man$sect ; do
+ for s in $SRCDIR../docs/*$sect; do
+ FNAME=$m/`basename $s`
+ if test -f $FNAME; then
+ echo Deleting $FNAME
+ rm -f $FNAME
+ test -f $FNAME && echo Cannot remove $FNAME... does $USER have privileges?
+ else
+ echo $FNAME does not exist! Check defines in the Makefile
+ fi
+ done
+ done
+done
+
+cat << EOF
+======================================================================
+The man pages have been uninstalled. You may install them again using
+the command "make installman" or make "install" to install binaries,
+man pages and shell scripts.
+======================================================================
+EOF
+exit 0
diff --git a/source/script/uninstallscripts.sh b/source/script/uninstallscripts.sh
new file mode 100755
index 00000000000..ae907546f2e
--- /dev/null
+++ b/source/script/uninstallscripts.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+# 5 July 96 Dan.Shearer@UniSA.Edu.Au - almost identical to uninstallbin.sh
+
+INSTALLPERMS=$1
+BINDIR=$2
+
+shift
+shift
+
+if [ ! -d $BINDIR ]; then
+ echo Directory $BINDIR does not exist!
+ echo Do a "make installscripts" or "make install" first.
+ exit 1
+fi
+
+for p in $*; do
+ if [ ! -f $BINDIR/$p ]; then
+ echo $BINDIR/$p does not exist!
+ else
+ echo Removing $BINDIR/$p
+ rm -f $BINDIR/$p
+ if [ -f $BINDIR/$p ]; then
+ echo Cannot remove $BINDIR/$p... does $USER have privileges?
+ fi
+ fi
+done
+
+cat << EOF
+======================================================================
+The scripts have been uninstalled. You may reinstall them using
+the command "make installscripts" or "make install" to install binaries,
+man pages and shell scripts. You may recover a previous version (if any
+with "make revert".
+======================================================================
+EOF
+
+exit 0
diff --git a/source/smbadduser b/source/smbadduser
new file mode 100755
index 00000000000..e4e1b273d14
--- /dev/null
+++ b/source/smbadduser
@@ -0,0 +1,73 @@
+#!/bin/csh
+#
+# smbadduser - Written by Mike Zakharoff
+#
+unalias *
+set path = ($path /usr/local/samba/bin)
+
+set smbpasswd = /usr/local/samba/private/smbpasswd
+set user_map = /usr/local/samba/lib/users.map
+#
+# Set to site specific passwd command
+#
+#set passwd = "cat /etc/passwd"
+#set passwd = "niscat passwd.org_dir"
+set passwd = "ypcat passwd"
+
+set line = "----------------------------------------------------------"
+if ($#argv == 0) then
+ echo $line
+ echo "Written: Mike Zakharoff email: michael.j.zakharoff@boeing.com"
+ echo ""
+ echo " 1) Updates $smbpasswd"
+ echo " 2) Updates $user_map"
+ echo " 3) Executes smbpasswd for each new user"
+ echo ""
+ echo "smbadduser unixid:ntid unixid:ntid ..."
+ echo ""
+ echo "Example: smbadduser zak:zakharoffm johns:smithj"
+ echo $line
+ exit 1
+endif
+
+touch $smbpasswd $user_map
+set new = ()
+foreach one ($argv)
+ echo $one | grep ':' >& /dev/null
+ if ($status != 0) then
+ echo "ERROR: Must use unixid:ntid like -> zak:zakharoffm"
+ continue
+ endif
+ set unix = `echo $one | awk -F: '{print $1}'`
+ set ntid = `echo $one | awk -F: '{print $2}'`
+
+ set usr = `eval $passwd | awk -F: '$1==USR {print $1}' USR=$unix`
+ if ($#usr != 1) then
+ echo "ERROR: $unix Not in passwd database SKIPPING..."
+ continue
+ endif
+ set tmp = `cat $smbpasswd | awk -F: '$1==USR {print $1}' USR=$unix`
+ if ($#tmp != 0) then
+ echo "ERROR: $unix is already in $smbpasswd SKIPPING..."
+ continue
+ endif
+
+ echo "Adding: $unix to $smbpasswd"
+ eval $passwd | \
+ awk -F: '$1==USR { \
+ printf( "%s:%s:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:%s:%s:%s\n", $1, $3, $5, $6, $7) }' USR=$unix >> $smbpasswd
+ if ($unix != $ntid) then
+ echo "Adding: {$unix = $ntid} to $user_map"
+ echo "$unix = $ntid" >> $user_map
+ endif
+ set new = ($new $unix)
+end
+
+#
+# Enter password for new users
+#
+foreach one ($new)
+ echo $line
+ echo "ENTER password for $one"
+ smbpasswd $one
+end
diff --git a/source/smbd/chgpasswd.c b/source/smbd/chgpasswd.c
index dc0514c1ed7..17401410cec 100644
--- a/source/smbd/chgpasswd.c
+++ b/source/smbd/chgpasswd.c
@@ -1,3 +1,24 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1997
+
+ 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.
+*/
+
/* fork a child process to exec passwd and write to its
* tty to change a users password. This is running as the
* user who is attempting to change the password.
@@ -27,7 +48,6 @@
*/
#include "includes.h"
-#include "loadparm.h"
extern int DEBUGLEVEL;
@@ -39,29 +59,33 @@ extern int DEBUGLEVEL;
static int findpty(char **slave)
{
int master;
-#ifdef SVR4
+#if defined(SVR4) || defined(SUNOS5)
extern char *ptsname();
-#else
- static char line[12] = "/dev/ptyXX";
+#else /* defined(SVR4) || defined(SUNOS5) */
+ static char line[12];
void *dirp;
char *dpname;
-#endif
+#endif /* defined(SVR4) || defined(SUNOS5) */
-#ifdef SVR4
+#if defined(SVR4) || defined(SUNOS5)
if ((master = open("/dev/ptmx", O_RDWR)) >= 1) {
grantpt(master);
unlockpt(master);
*slave = ptsname(master);
return (master);
}
-#else
- dirp = OpenDir("/dev");
+#else /* defined(SVR4) || defined(SUNOS5) */
+ strcpy( line, "/dev/ptyXX" );
+
+ dirp = OpenDir(-1, "/dev", True);
if (!dirp) return(-1);
while ((dpname = ReadDirName(dirp)) != NULL) {
if (strncmp(dpname, "pty", 3) == 0 && strlen(dpname) == 5) {
+ DEBUG(3,("pty: try to open %s, line was %s\n", dpname, line ) );
line[8] = dpname[3];
line[9] = dpname[4];
if ((master = open(line, O_RDWR)) >= 0) {
+ DEBUG(3,("pty: opened %s\n", line ) );
line[5] = 't';
*slave = line;
CloseDir(dirp);
@@ -70,7 +94,7 @@ static int findpty(char **slave)
}
}
CloseDir(dirp);
-#endif
+#endif /* defined(SVR4) || defined(SUNOS5) */
return (-1);
}
@@ -84,9 +108,9 @@ static int dochild(int master,char *slavedev, char *name, char *passwordprogram)
#ifdef USE_SETRES
setresuid(0,0,0);
-#else
+#else /* USE_SETRES */
setuid(0);
-#endif
+#endif /* USE_SETRES */
/* Start new session - gets rid of controlling terminal. */
if (setsid() < 0) {
@@ -100,15 +124,15 @@ static int dochild(int master,char *slavedev, char *name, char *passwordprogram)
slavedev));
return(False);
}
-#ifdef SVR4
+#if defined(SVR4) || defined(SUNOS5) || defined(SCO)
ioctl(slave, I_PUSH, "ptem");
ioctl(slave, I_PUSH, "ldterm");
-#else
+#else /* defined(SVR4) || defined(SUNOS5) || defined(SCO) */
if (ioctl(slave,TIOCSCTTY,0) <0) {
DEBUG(3,("Error in ioctl call for slave pty\n"));
/* return(False); */
}
-#endif
+#endif /* defined(SVR4) || defined(SUNOS5) || defined(SCO) */
/* Close master. */
close(master);
@@ -179,7 +203,7 @@ static int expect(int master,char *expected,char *buf)
}
/* allow 4 seconds for some output to appear */
- m = read_with_timeout(master, buf+n, 1, BUFSIZE-1-n, 4000, True);
+ m = read_with_timeout(master, buf+n, 1, BUFSIZE-1-n, 4000);
if (m < 0)
return False;
@@ -188,8 +212,8 @@ static int expect(int master,char *expected,char *buf)
{
pstring s1,s2;
- strcpy(s1,buf);
- strcpy(s2,expected);
+ pstrcpy(s1,buf);
+ pstrcpy(s2,expected);
if (do_match(s1, s2, False))
return(True);
}
@@ -281,7 +305,7 @@ BOOL chat_with_program(char *passwordprogram,char *name,char *chatsequence)
kill(pid, SIGKILL); /* be sure to end this process */
return(False);
}
- if ((wpid = waitpid(pid, &wstat, 0)) < 0) {
+ if ((wpid = sys_waitpid(pid, &wstat, 0)) < 0) {
DEBUG(3,("The process is no longer waiting!\n\n"));
return(False);
}
@@ -340,11 +364,11 @@ BOOL chgpasswd(char *name,char *oldpass,char *newpass)
}
#if (defined(PASSWD_PROGRAM) && defined(PASSWD_CHAT))
- strcpy(passwordprogram,PASSWD_PROGRAM);
- strcpy(chatsequence,PASSWD_CHAT);
+ pstrcpy(passwordprogram,PASSWD_PROGRAM);
+ pstrcpy(chatsequence,PASSWD_CHAT);
#else
- strcpy(passwordprogram,lp_passwd_program());
- strcpy(chatsequence,lp_passwd_chat());
+ pstrcpy(passwordprogram,lp_passwd_program());
+ pstrcpy(chatsequence,lp_passwd_chat());
#endif
if (!*chatsequence) {
diff --git a/source/smbd/dir.c b/source/smbd/dir.c
index ac6f918b9da..c12305499a5 100644
--- a/source/smbd/dir.c
+++ b/source/smbd/dir.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Directory handling routines
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1997
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,7 +20,6 @@
*/
#include "includes.h"
-#include "loadparm.h"
extern int DEBUGLEVEL;
extern connection_struct Connections[];
@@ -111,16 +110,18 @@ get the dir ptr for a dir index
****************************************************************************/
static void *dptr_get(int key,uint32 lastused)
{
- if (dirptrs[key].valid) {
- if (lastused) dirptrs[key].lastused = lastused;
- if (!dirptrs[key].ptr) {
+ struct dptr_struct *dp = &dirptrs[key];
+
+ if (dp->valid) {
+ if (lastused) dp->lastused = lastused;
+ if (!dp->ptr) {
if (dptrs_open >= MAXDIR)
dptr_idleoldest();
DEBUG(4,("Reopening dptr key %d\n",key));
- if ((dirptrs[key].ptr = OpenDir(dirptrs[key].path)))
+ if ((dp->ptr = OpenDir(dp->cnum, dp->path, True)))
dptrs_open++;
}
- return(dirptrs[key].ptr);
+ return(dp->ptr);
}
return(NULL);
}
@@ -186,6 +187,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) {
@@ -247,7 +261,7 @@ static BOOL start_dir(int cnum,char *directory)
if (! *directory)
directory = ".";
- Connections[cnum].dirptr = OpenDir(directory);
+ Connections[cnum].dirptr = OpenDir(cnum, directory, True);
if (Connections[cnum].dirptr) {
dptrs_open++;
string_set(&Connections[cnum].dirpath,directory);
@@ -268,7 +282,7 @@ int dptr_create(int cnum,char *path, BOOL expect_close,int pid)
int oldi;
if (!start_dir(cnum,path))
- return(-1);
+ return(-2); /* Code to say use a unix error return code. */
if (dptrs_open >= MAXDIR)
dptr_idleoldest();
@@ -399,6 +413,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)
@@ -411,6 +435,7 @@ BOOL get_dir_entry(int cnum,char *mask,int dirtype,char *fname,int *size,int *mo
BOOL isrootdir;
pstring filename;
BOOL matched;
+ BOOL needslash;
*path = *pathreal = *filename = 0;
@@ -418,6 +443,9 @@ BOOL get_dir_entry(int cnum,char *mask,int dirtype,char *fname,int *size,int *mo
strequal(Connections[cnum].dirpath,".") ||
strequal(Connections[cnum].dirpath,"/"));
+ needslash =
+ ( Connections[cnum].dirpath[strlen(Connections[cnum].dirpath) -1] != '/');
+
if (!Connections[cnum].dirptr)
return(False);
@@ -433,7 +461,7 @@ BOOL get_dir_entry(int cnum,char *mask,int dirtype,char *fname,int *size,int *mo
matched = False;
- strcpy(filename,dname);
+ pstrcpy(filename,dname);
if ((strcmp(filename,mask) == 0) ||
(name_map_mangle(filename,True,SNUM(cnum)) &&
@@ -442,11 +470,12 @@ BOOL get_dir_entry(int cnum,char *mask,int dirtype,char *fname,int *size,int *mo
if (isrootdir && (strequal(filename,"..") || strequal(filename,".")))
continue;
- strcpy(fname,filename);
+ pstrcpy(fname,filename);
*path = 0;
- strcpy(path,Connections[cnum].dirpath);
- strcat(path,"/");
- strcpy(pathreal,path);
+ pstrcpy(path,Connections[cnum].dirpath);
+ if(needslash)
+ strcat(path,"/");
+ pstrcpy(pathreal,path);
strcat(path,fname);
strcat(pathreal,dname);
if (sys_stat(pathreal,&sbuf) != 0)
@@ -461,11 +490,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;
@@ -493,7 +522,7 @@ typedef struct
/*******************************************************************
open a directory
********************************************************************/
-void *OpenDir(char *name)
+void *OpenDir(int cnum, char *name, BOOL use_veto)
{
Dir *dirp;
char *n;
@@ -509,8 +538,13 @@ void *OpenDir(char *name)
dirp->pos = dirp->numentries = dirp->mallocsize = 0;
dirp->data = dirp->current = NULL;
- while ((n = readdirname(p))) {
+ while ((n = readdirname(p)))
+ {
int l = strlen(n)+1;
+
+ /* If it's a vetoed file, pretend it doesn't even exist */
+ if (use_veto && IS_VETO_PATH(cnum, n)) continue;
+
if (used + l > dirp->mallocsize) {
int s = MAX(used+l,used+2000);
char *r;
@@ -594,90 +628,133 @@ int TellDir(void *p)
}
-static int dir_cache_size = 0;
-static struct dir_cache {
- struct dir_cache *next;
- struct dir_cache *prev;
- char *path;
- char *name;
- char *dname;
- int snum;
-} *dir_cache = NULL;
-
-/*******************************************************************
-add an entry to the directory cache
-********************************************************************/
-void DirCacheAdd(char *path,char *name,char *dname,int snum)
-{
- struct dir_cache *entry = (struct dir_cache *)malloc(sizeof(*entry));
- if (!entry) return;
- entry->path = strdup(path);
- entry->name = strdup(name);
- entry->dname = strdup(dname);
- entry->snum = snum;
- if (!entry->path || !entry->name || !entry->dname) return;
-
- entry->next = dir_cache;
- entry->prev = NULL;
- if (entry->next) entry->next->prev = entry;
- dir_cache = entry;
-
- DEBUG(4,("Added dir cache entry %s %s -> %s\n",path,name,dname));
-
- if (dir_cache_size == DIRCACHESIZE) {
- for (entry=dir_cache; entry->next; entry=entry->next) ;
- free(entry->path);
- free(entry->name);
- free(entry->dname);
- if (entry->prev) entry->prev->next = entry->next;
- free(entry);
- } else {
- dir_cache_size++;
- }
-}
+/* -------------------------------------------------------------------------- **
+ * This section manages a global directory cache.
+ * (It should probably be split into a separate module. crh)
+ * -------------------------------------------------------------------------- **
+ */
+typedef struct
+ {
+ ubi_dlNode node;
+ char *path;
+ char *name;
+ char *dname;
+ int snum;
+ } dir_cache_entry;
+
+static ubi_dlList dir_cache[1] = { { NULL, NULL, 0 } };
+
+void DirCacheAdd( char *path, char *name, char *dname, int snum )
+ /* ------------------------------------------------------------------------ **
+ * Add an entry to the directory cache.
+ *
+ * Input: path -
+ * name -
+ * dname -
+ * snum -
+ *
+ * Output: None.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ int pathlen;
+ int namelen;
+ dir_cache_entry *entry;
+
+ /* Allocate the structure & string space in one go so that it can be freed
+ * in one call to free().
+ */
+ pathlen = strlen( path ) +1; /* Bytes required to store path (with nul). */
+ namelen = strlen( name ) +1; /* Bytes required to store name (with nul). */
+ entry = (dir_cache_entry *)malloc( sizeof( dir_cache_entry )
+ + pathlen
+ + namelen
+ + strlen( dname ) +1 );
+ if( NULL == entry ) /* Not adding to the cache is not fatal, */
+ return; /* so just return as if nothing happened. */
+
+ /* Set pointers correctly and load values. */
+ entry->path = strcpy( (char *)&entry[1], path);
+ entry->name = strcpy( &(entry->path[pathlen]), name);
+ entry->dname = strcpy( &(entry->name[namelen]), dname);
+ entry->snum = snum;
+
+ /* Add the new entry to the linked list. */
+ (void)ubi_dlAddHead( dir_cache, entry );
+ DEBUG( 4, ("Added dir cache entry %s %s -> %s\n", path, name, dname ) );
+
+ /* Free excess cache entries. */
+ while( DIRCACHESIZE < dir_cache->count )
+ free( ubi_dlRemTail( dir_cache ) );
+
+ } /* DirCacheAdd */
+
+
+char *DirCacheCheck( char *path, char *name, int snum )
+ /* ------------------------------------------------------------------------ **
+ * Search for an entry to the directory cache.
+ *
+ * Input: path -
+ * name -
+ * snum -
+ *
+ * Output: The dname string of the located entry, or NULL if the entry was
+ * not found.
+ *
+ * Notes: This uses a linear search, which is is okay because of
+ * the small size of the cache. Use a splay tree or hash
+ * for large caches.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ dir_cache_entry *entry;
-/*******************************************************************
-check for an entry in the directory cache
-********************************************************************/
-char *DirCacheCheck(char *path,char *name,int snum)
-{
- struct dir_cache *entry;
-
- for (entry=dir_cache; entry; entry=entry->next) {
- if (entry->snum == snum &&
- strcmp(path,entry->path) == 0 &&
- strcmp(name,entry->name) == 0) {
- DEBUG(4,("Got dir cache hit on %s %s -> %s\n",path,name,entry->dname));
- return(entry->dname);
+ for( entry = (dir_cache_entry *)ubi_dlFirst( dir_cache );
+ NULL != entry;
+ entry = (dir_cache_entry *)ubi_dlNext( entry ) )
+ {
+ if( entry->snum == snum
+ && 0 == strcmp( name, entry->name )
+ && 0 == strcmp( path, entry->path ) )
+ {
+ DEBUG(4, ("Got dir cache hit on %s %s -> %s\n",path,name,entry->dname));
+ return( entry->dname );
+ }
}
- }
return(NULL);
-}
+ } /* DirCacheCheck */
+
+void DirCacheFlush( int snum )
+ /* ------------------------------------------------------------------------ **
+ * Remove all cache entries which have an snum that matches the input.
+ *
+ * Input: snum -
+ *
+ * Output: None.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ dir_cache_entry *entry;
+ ubi_dlNodePtr next;
-/*******************************************************************
-flush entries in the dir_cache
-********************************************************************/
-void DirCacheFlush(int snum)
-{
- struct dir_cache *entry,*next;
-
- for (entry=dir_cache; entry; entry=next) {
- if (entry->snum == snum) {
- free(entry->path);
- free(entry->dname);
- free(entry->name);
- next = entry->next;
- if (entry->prev) entry->prev->next = entry->next;
- if (entry->next) entry->next->prev = entry->prev;
- if (dir_cache == entry) dir_cache = entry->next;
- free(entry);
- } else {
- next = entry->next;
+ for( entry = (dir_cache_entry *)ubi_dlFirst( dir_cache ); NULL != entry; )
+ {
+ next = ubi_dlNext( entry );
+ if( entry->snum == snum )
+ free( ubi_dlRemThis( dir_cache, entry ) );
+ entry = (dir_cache_entry *)next;
}
- }
-}
+ } /* DirCacheFlush */
+
+/* -------------------------------------------------------------------------- **
+ * End of the section that manages the global directory cache.
+ * -------------------------------------------------------------------------- **
+ */
#ifdef REPLACE_GETWD
diff --git a/source/smbd/ipc.c b/source/smbd/ipc.c
index 8852e57e8b6..0d57b1ecfee 100644
--- a/source/smbd/ipc.c
+++ b/source/smbd/ipc.c
@@ -2,7 +2,10 @@
Unix SMB/Netbios implementation.
Version 1.9.
Inter-process communication and named pipe handling
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1997
+
+ SMB Version handling
+ Copyright (C) John H Terpstra 1995-1997
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
@@ -24,8 +27,6 @@
*/
#include "includes.h"
-#include "loadparm.h"
-#include "pcap.h"
#ifdef CHECK_TYPES
#undef CHECK_TYPES
@@ -33,11 +34,12 @@
#define CHECK_TYPES 0
extern int DEBUGLEVEL;
-extern int maxxmit;
+extern int max_send;
extern files_struct Files[];
extern connection_struct Connections[];
extern fstring local_machine;
+extern fstring myworkgroup;
#define NERR_Success 0
#define NERR_badpass 86
@@ -50,8 +52,6 @@ extern fstring local_machine;
#define ERROR_INVALID_LEVEL 124
#define ERROR_MORE_DATA 234
-#define REALLOC(ptr,size) Realloc(ptr,MAX((size),4*1024))
-
#define ACCESS_READ 0x01
#define ACCESS_WRITE 0x02
#define ACCESS_CREATE 0x04
@@ -63,6 +63,16 @@ extern fstring local_machine;
extern int Client;
+static BOOL api_Unsupported(int cnum,uint16 vuid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len);
+static BOOL api_TooSmall(int cnum,uint16 vuid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len);
+
+
static int CopyExpanded(int cnum, int snum, char** dst, char* src, int* n)
{
pstring buf;
@@ -131,8 +141,8 @@ static void send_trans_reply(char *outbuf,char *data,char *param,uint16 *setup,
int tot_data=0,tot_param=0;
int align;
- this_lparam = MIN(lparam,maxxmit - (500+lsetup*SIZEOFWORD)); /* hack */
- this_ldata = MIN(ldata,maxxmit - (500+lsetup*SIZEOFWORD+this_lparam));
+ this_lparam = MIN(lparam,max_send - (500+lsetup*SIZEOFWORD)); /* hack */
+ this_ldata = MIN(ldata,max_send - (500+lsetup*SIZEOFWORD+this_lparam));
align = (this_lparam%4);
@@ -162,8 +172,8 @@ static void send_trans_reply(char *outbuf,char *data,char *param,uint16 *setup,
while (tot_data < ldata || tot_param < lparam)
{
- this_lparam = MIN(lparam-tot_param,maxxmit - 500); /* hack */
- this_ldata = MIN(ldata-tot_data,maxxmit - (500+this_lparam));
+ this_lparam = MIN(lparam-tot_param,max_send - 500); /* hack */
+ this_ldata = MIN(ldata-tot_data,max_send - (500+this_lparam));
align = (this_lparam%4);
@@ -189,12 +199,6 @@ static void send_trans_reply(char *outbuf,char *data,char *param,uint16 *setup,
}
}
-
-
-/****************************************************************************
- get a print queue
- ****************************************************************************/
-
struct pack_desc {
char* format; /* formatstring for structure */
char* subformat; /* subformat for structure */
@@ -418,6 +422,11 @@ static void PACKS(struct pack_desc* desc,char *t,char *v)
PACK(desc,t,v);
}
+
+/****************************************************************************
+ get a print queue
+ ****************************************************************************/
+
static void PackDriverData(struct pack_desc* desc)
{
char drivdata[4+4+32];
@@ -429,7 +438,7 @@ static void PackDriverData(struct pack_desc* desc)
}
static int check_printq_info(struct pack_desc* desc,
- int uLevel, const char* id1, const char* id2)
+ int uLevel, char *id1, char *id2)
{
desc->subformat = NULL;
switch( uLevel ) {
@@ -453,6 +462,10 @@ static int check_printq_info(struct pack_desc* desc,
case 5:
desc->format = "z";
break;
+ case 52:
+ desc->format = "WzzzzzzzzN";
+ desc->subformat = "z";
+ break;
default: return False;
}
if (strcmp(desc->format,id1) != 0) return False;
@@ -467,9 +480,9 @@ 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 */
+ PACKI(desc,"W",printjob_encode(snum, queue->job)); /* uJobId */
if (uLevel == 1) {
PACKS(desc,"B21",queue->user); /* szUserName */
PACKS(desc,"B",""); /* pad */
@@ -479,7 +492,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 +501,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 */
@@ -512,11 +525,18 @@ static void fill_printq_info(int cnum, int snum, int uLevel,
int count, print_queue_struct* queue,
print_status_struct* status)
{
- if (uLevel < 3) {
- PACKS(desc,"B13",SERVICE(snum));
- } else {
- PACKS(desc,"z",Expand(cnum,snum,SERVICE(snum)));
+ switch (uLevel) {
+ case 1:
+ case 2:
+ PACKS(desc,"B13",SERVICE(snum));
+ break;
+ case 3:
+ case 4:
+ case 5:
+ PACKS(desc,"z",Expand(cnum,snum,SERVICE(snum)));
+ break;
}
+
if (uLevel == 1 || uLevel == 2) {
PACKS(desc,"B",""); /* alignment */
PACKI(desc,"W",5); /* priority */
@@ -545,7 +565,7 @@ static void fill_printq_info(int cnum, int snum, int uLevel,
PACKI(desc,"W",0); /* uUntiltime */
PACKI(desc,"W",5); /* pad1 */
PACKS(desc,"z",""); /* pszSepFile */
- PACKS(desc,"z","lpd"); /* pszPrProc */
+ PACKS(desc,"z","WinPrint"); /* pszPrProc */
PACKS(desc,"z",""); /* pszParms */
if (!status || !status->message[0]) {
PACKS(desc,"z",Expand(cnum,snum,lp_comment(snum))); /* pszComment */
@@ -556,7 +576,7 @@ static void fill_printq_info(int cnum, int snum, int uLevel,
}
PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
- PACKS(desc,"z","NULL"); /* pszDriverName */
+ PACKS(desc,"z",lp_printerdriver(snum)); /* pszDriverName */
PackDriverData(desc); /* pDriverData */
}
if (uLevel == 2 || uLevel == 4) {
@@ -564,11 +584,120 @@ static void fill_printq_info(int cnum, int snum, int uLevel,
for (i=0;i<count;i++)
fill_printjob_info(cnum,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
}
-
+
+ if (uLevel==52) {
+ int i,ok=0;
+ pstring tok,driver,short_name;
+ char *p,*q;
+ FILE *f;
+ pstring fname;
+
+ strcpy(fname,lp_driverfile());
+
+ f=fopen(fname,"r");
+ if (!f) {
+ DEBUG(0,("fill_printq_info: Can't open %s - %s\n",fname,strerror(errno)));
+ }
+
+ p=(char *)malloc(8192*sizeof(char));
+ bzero(p, 8192*sizeof(char));
+ q=p;
+
+ /* lookup the long printer driver name in the file description */
+ while (f && !feof(f) && !ok)
+ {
+ fgets(p,8191,f);
+ p[strlen(p)-1]='\0';
+ next_token(&p,tok,":");
+ if(!strncmp(tok,lp_printerdriver(snum),strlen(lp_printerdriver(snum)))) ok=1;
+ }
+
+ fclose(f);
+
+ next_token(&p,short_name,":");
+ next_token(&p,driver,":");
+
+ PACKI(desc,"W",0x0400); /* don't know */
+ PACKS(desc,"z",lp_printerdriver(snum)); /* long printer name */
+
+ if (ok)
+ {
+ PACKS(desc,"z",driver); /* Driver Name */
+ PACKS(desc,"z",short_name); /* short printer name */
+ DEBUG(3,("Driver:%s:\n",driver));
+ DEBUG(3,("short name:%s:\n",short_name));
+ }
+ else
+ {
+ PACKS(desc,"z","");
+ PACKS(desc,"z","");
+ }
+
+ PACKS(desc,"z","");
+ PACKS(desc,"z",lp_driverlocation(snum)); /* share to retrieve files */
+ PACKS(desc,"z","EMF");
+ PACKS(desc,"z","");
+ if (ok)
+ PACKS(desc,"z",driver); /* driver name */
+ else
+ PACKS(desc,"z","");
+ PACKI(desc,"N",count); /* number of files to copy */
+ for (i=0;i<count;i++)
+ {
+ next_token(&p,tok,",");
+ PACKS(desc,"z",tok); /* driver files to copy */
+ DEBUG(3,("file:%s:\n",tok));
+ }
+ free(q);
+ }
+
DEBUG(3,("fill_printq_info on <%s> gave %d entries\n",SERVICE(snum),count));
}
-static BOOL api_DosPrintQGetInfo(int cnum,int uid, char *param,char *data,
+/* This function returns the number of file for a given driver */
+int get_printerdrivernumber(int snum)
+{
+ int i=0,ok=0;
+ pstring tok;
+ char *p,*q;
+ FILE *f;
+ pstring fname;
+
+ strcpy(fname,lp_driverfile());
+
+ DEBUG(4,("In get_printerdrivernumber: %s\n",fname));
+ f=fopen(fname,"r");
+ if (!f) {
+ DEBUG(0,("get_printerdrivernumber: Can't open %s - %s\n",fname,strerror(errno)));
+ return(0);
+ }
+
+ p=(char *)malloc(8192*sizeof(char));
+ q=p; /* need it to free memory because p change ! */
+
+ /* lookup the long printer driver name in the file description */
+ while (!feof(f) && !ok)
+ {
+ fgets(p,8191,f);
+ next_token(&p,tok,":");
+ if(!strncmp(tok,lp_printerdriver(snum),strlen(lp_printerdriver(snum)))) ok=1;
+ }
+
+ if (ok) {
+ /* skip 2 fields */
+ next_token(&p,tok,":"); /* short name */
+ next_token(&p,tok,":"); /* driver name */
+ /* count the number of files */
+ while (next_token(&p,tok,","))
+ i++;
+ }
+ fclose(f);
+ free(q);
+
+ return(i);
+}
+
+static BOOL api_DosPrintQGetInfo(int cnum,uint16 vuid, char *param,char *data,
int mdrcnt,int mprcnt,
char **rdata,char **rparam,
int *rdata_len,int *rparam_len)
@@ -593,6 +722,7 @@ static BOOL api_DosPrintQGetInfo(int cnum,int uid, char *param,char *data,
cbBuf = SVAL(p,2);
str3 = p + 4;
+ /* remove any trailing username */
if ((p = strchr(QueueName,'%'))) *p = 0;
DEBUG(3,("PrintQueue uLevel=%d name=%s\n",uLevel,QueueName));
@@ -612,7 +742,14 @@ static BOOL api_DosPrintQGetInfo(int cnum,int uid, char *param,char *data,
if (snum < 0 || !VALID_SNUM(snum)) return(False);
- count = get_printqueue(snum,cnum,&queue,&status);
+ if (uLevel==52)
+ {
+ count = get_printerdrivernumber(snum);
+ DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
+ }
+ else
+ count = get_printqueue(snum,cnum,&queue,&status);
+
if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
desc.base = *rdata;
desc.buflen = mdrcnt;
@@ -640,7 +777,7 @@ static BOOL api_DosPrintQGetInfo(int cnum,int uid, char *param,char *data,
/****************************************************************************
view list of all print jobs on all queues
****************************************************************************/
-static BOOL api_DosPrintQEnum(int cnum, int uid, char* param, char* data,
+static BOOL api_DosPrintQEnum(int cnum, uint16 vuid, char* param, char* data,
int mdrcnt, int mprcnt,
char **rdata, char** rparam,
int *rdata_len, int *rparam_len)
@@ -662,7 +799,7 @@ static BOOL api_DosPrintQEnum(int cnum, int uid, char* param, char* data,
DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
- if (prefix_ok(param_format,"WrLeh")) return False;
+ if (!prefix_ok(param_format,"WrLeh")) return False;
if (!check_printq_info(&desc,uLevel,output_format1,output_format2))
return False;
queuecnt = 0;
@@ -737,66 +874,32 @@ static BOOL check_server_info(int uLevel, char* id)
return True;
}
-/* used for server information: client, nameserv and ipc */
struct srv_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 */
+ fstring domain;
+ BOOL server_added;
};
-/*******************************************************************
- filter out unwanted server info
- ******************************************************************/
-static BOOL filter_server_info(struct srv_info_struct *server,
- char *domain)
-{
- if (*domain)
- return(strequal(domain, server->domain));
-
- return (True); /* be indiscriminate: get all servers! */
-}
-
-/*******************************************************************
- find server in the files saved by nmbd. Return True if we find it.
- ******************************************************************/
-static BOOL find_server(struct srv_info_struct *servers, int num_servers,
- char *domain, char *name)
-{
- 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);
- }
- }
- 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,
+ char *domain)
{
FILE *f;
pstring fname;
int count=0;
int alloced=0;
pstring line;
+ BOOL local_list_only;
- strcpy(fname,lp_lockdir());
+ pstrcpy(fname,lp_lockdir());
trim_string(fname,NULL,"/");
strcat(fname,"/");
strcat(fname,SERVER_LIST);
@@ -807,18 +910,26 @@ static int get_server_info(uint32 servertype,
DEBUG(4,("Can't open %s - %s\n",fname,strerror(errno)));
return(0);
}
- if (servertype == SV_TYPE_ALL) servertype &= ~SV_TYPE_DOMAIN_ENUM;
+
+ /* request for everything is code for request all servers */
+ if (servertype == SV_TYPE_ALL)
+ servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
+
+ local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY);
+
+ DEBUG(4,("Servertype search: %8x\n",servertype));
while (!feof(f))
{
fstring stype;
struct srv_info_struct *s;
char *ptr = line;
+ BOOL ok = True;
*ptr = 0;
fgets(line,sizeof(line)-1,f);
if (!*line) continue;
-
+
if (count == alloced) {
alloced += 10;
(*servers) = (struct srv_info_struct *)
@@ -827,36 +938,69 @@ 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 */
- strcpy(s->domain,my_workgroup());
+ /* this allows us to cope with an old nmbd */
+ strcpy(s->domain,myworkgroup);
+ }
+
+ if (sscanf(stype,"%X",&s->type) != 1) {
+ DEBUG(4,("r:host file "));
+ ok = False;
}
+
+ /* Filter the servers/domains we return based on what was asked for. */
- if (sscanf(stype,"%X",&s->type) != 1) continue;
+ /* Check to see if we are being asked for a local list only. */
+ if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) {
+ DEBUG(4,("r: local list only"));
+ 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));
+ 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: dom mismatch "));
+ ok = False;
+ }
+
+ if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM))
+ {
+ ok = False;
+ }
+
+ /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */
+ s->type &= ~SV_TYPE_LOCAL_LIST_ONLY;
- count++;
+ if (ok)
+ {
+ DEBUG(4,("**SV** %20s %8x %25s %15s\n",
+ s->name, s->type, s->comment, s->domain));
+
+ s->server_added = True;
+ count++;
+ }
+ else
+ {
+ DEBUG(4,("%20s %8x %25s %15s\n",
+ s->name, s->type, s->comment, s->domain));
+ }
}
-
+
fclose(f);
return(count);
}
+
/*******************************************************************
fill in a server info structure
******************************************************************/
@@ -936,11 +1080,16 @@ static int fill_srv_info(struct srv_info_struct *service,
}
+static BOOL srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2)
+{
+ return(strcmp(s1->name,s2->name));
+}
+
/****************************************************************************
view list of servers available (or possibly domains). The info is
extracted from lists saved by nmbd on the local host
****************************************************************************/
-static BOOL api_RNetServerEnum(int cnum, int uid, char *param, char *data,
+static BOOL api_RNetServerEnum(int cnum, uint16 vuid, char *param, char *data,
int mdrcnt, int mprcnt, char **rdata,
char **rparam, int *rdata_len, int *rparam_len)
{
@@ -955,60 +1104,74 @@ static BOOL api_RNetServerEnum(int cnum, int uid, char *param, char *data,
int f_len, s_len;
struct srv_info_struct *servers=NULL;
int counted=0,total=0;
- int i;
+ int i,missed;
fstring domain;
- BOOL domain_request = (servertype & SV_TYPE_DOMAIN_ENUM) &&
- !(servertype == SV_TYPE_ALL);
+ BOOL domain_request;
+ BOOL local_request;
+
+ /* If someone sets all the bits they don't really mean to set
+ DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the
+ known servers. */
+
+ if (servertype == SV_TYPE_ALL)
+ servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);
+
+ /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set
+ any other bit (they may just set this bit on it's own) they
+ want all the locally seen servers. However this bit can be
+ set on its own so set the requested servers to be
+ ALL - DOMAIN_ENUM. */
+
+ if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM))
+ servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);
+
+ domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0);
+ local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0);
- domain[0] = 0;
p += 8;
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 */
- }
- else if (strcmp(str1, "WrLehDz") == 0)
- {
- /* asking for a specific workgroup */
+ if (strcmp(str1, "WrLehDz") == 0) {
StrnCpy(domain, p, sizeof(fstring)-1);
+ } else {
+ StrnCpy(domain, myworkgroup, 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,domain);
data_len = fixed_len = string_len = 0;
+ missed = 0;
- for (i=0;i<total;i++)
- if (filter_server_info(&servers[i],domain)) {
- data_len += fill_srv_info(&servers[i],uLevel,0,&f_len,0,&s_len,0);
- if (data_len <= buf_len)
- {
+ qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
+
+ {
+ char *lastname=NULL;
+
+ for (i=0;i<total;i++)
+ {
+ struct srv_info_struct *s = &servers[i];
+ if (lastname && strequal(lastname,s->name)) continue;
+ lastname = s->name;
+ data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0);
+ DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
+ s->name, s->type, s->comment, s->domain));
+
+ if (data_len <= buf_len) {
counted++;
fixed_len += f_len;
string_len += s_len;
- }
+ } else {
+ missed++;
+ }
}
+ }
*rdata_len = fixed_len + string_len;
*rdata = REALLOC(*rdata,*rdata_len);
@@ -1020,26 +1183,31 @@ static BOOL api_RNetServerEnum(int cnum, int uid, char *param, char *data,
s_len = string_len;
{
+ char *lastname=NULL;
int count2 = counted;
- for (i = 0; i < total && count2;i++) {
- if (filter_server_info(&servers[i],domain)) {
- fill_srv_info(&servers[i],uLevel,&p,&f_len,&p2,&s_len,*rdata);
+ for (i = 0; i < total && count2;i++)
+ {
+ struct srv_info_struct *s = &servers[i];
+ if (lastname && strequal(lastname,s->name)) continue;
+ lastname = s->name;
+ fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata);
+ DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n",
+ s->name, s->type, s->comment, s->domain));
count2--;
}
- }
}
*rparam_len = 8;
*rparam = REALLOC(*rparam,*rparam_len);
- SSVAL(*rparam,0,NERR_Success);
+ SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERROR_MORE_DATA));
SSVAL(*rparam,2,0);
SSVAL(*rparam,4,counted);
- SSVAL(*rparam,6,total);
+ SSVAL(*rparam,6,counted+missed);
if (servers) free(servers);
DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
- domain,uLevel,counted,total));
+ domain,uLevel,counted,counted+missed));
return(True);
}
@@ -1163,7 +1331,7 @@ static int fill_share_info(int cnum, int snum, int uLevel,
return len;
}
-static BOOL api_RNetShareGetInfo(int cnum,int uid, char *param,char *data,
+static BOOL api_RNetShareGetInfo(int cnum,uint16 vuid, char *param,char *data,
int mdrcnt,int mprcnt,
char **rdata,char **rparam,
int *rdata_len,int *rparam_len)
@@ -1198,7 +1366,7 @@ static BOOL api_RNetShareGetInfo(int cnum,int uid, char *param,char *data,
/****************************************************************************
view list of shares available
****************************************************************************/
-static BOOL api_RNetShareEnum(int cnum,int uid, char *param,char *data,
+static BOOL api_RNetShareEnum(int cnum,uint16 vuid, char *param,char *data,
int mdrcnt,int mprcnt,
char **rdata,char **rparam,
int *rdata_len,int *rparam_len)
@@ -1262,7 +1430,7 @@ static BOOL api_RNetShareEnum(int cnum,int uid, char *param,char *data,
/****************************************************************************
get the time of day info
****************************************************************************/
-static BOOL api_NetRemoteTOD(int cnum,int uid, char *param,char *data,
+static BOOL api_NetRemoteTOD(int cnum,uint16 vuid, char *param,char *data,
int mdrcnt,int mprcnt,
char **rdata,char **rparam,
int *rdata_len,int *rparam_len)
@@ -1289,7 +1457,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;
@@ -1311,7 +1479,7 @@ static BOOL api_NetRemoteTOD(int cnum,int uid, char *param,char *data,
/****************************************************************************
set the user password
****************************************************************************/
-static BOOL api_SetUserPassword(int cnum,int uid, char *param,char *data,
+static BOOL api_SetUserPassword(int cnum,uint16 vuid, char *param,char *data,
int mdrcnt,int mprcnt,
char **rdata,char **rparam,
int *rdata_len,int *rparam_len)
@@ -1320,7 +1488,7 @@ static BOOL api_SetUserPassword(int cnum,int uid, char *param,char *data,
fstring user;
fstring pass1,pass2;
- strcpy(user,p);
+ fstrcpy(user,p);
p = skip_string(p,1);
@@ -1332,14 +1500,16 @@ static BOOL api_SetUserPassword(int cnum,int uid, char *param,char *data,
*rdata_len = 0;
- SSVAL(*rparam,0,NERR_Success);
+ SSVAL(*rparam,0,NERR_badpass);
SSVAL(*rparam,2,0); /* converter word */
DEBUG(3,("Set password for <%s>\n",user));
- if (!password_ok(user,pass1,strlen(pass1),NULL,False) ||
- !chgpasswd(user,pass1,pass2))
- SSVAL(*rparam,0,NERR_badpass);
+ if (password_ok(user,pass1,strlen(pass1),NULL) &&
+ chgpasswd(user,pass1,pass2))
+ {
+ SSVAL(*rparam,0,NERR_Success);
+ }
bzero(pass1,sizeof(fstring));
bzero(pass2,sizeof(fstring));
@@ -1351,7 +1521,7 @@ static BOOL api_SetUserPassword(int cnum,int uid, char *param,char *data,
delete a print job
Form: <W> <>
****************************************************************************/
-static BOOL api_RDosPrintJobDel(int cnum,int uid, char *param,char *data,
+static BOOL api_RDosPrintJobDel(int cnum,uint16 vuid, char *param,char *data,
int mdrcnt,int mprcnt,
char **rdata,char **rparam,
int *rdata_len,int *rparam_len)
@@ -1360,11 +1530,10 @@ static BOOL api_RDosPrintJobDel(int cnum,int uid, char *param,char *data,
char *str1 = param+2;
char *str2 = skip_string(str1,1);
char *p = skip_string(str2,1);
- int jobid = (SVAL(p,0)&0xFF); /* the snum and jobid are encoded
- by the print queue api */
- int snum = (SVAL(p,0)>>8);
+ int jobid, snum;
int i, count;
+ printjob_decode(SVAL(p,0), &snum, &jobid);
/* check it's a supported varient */
if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
@@ -1384,7 +1553,7 @@ static BOOL api_RDosPrintJobDel(int cnum,int uid, char *param,char *data,
count = get_printqueue(snum,cnum,&queue,NULL);
for (i=0;i<count;i++)
- if ((queue[i].job%0xFF) == jobid)
+ if ((queue[i].job&0xFF) == jobid)
{
switch (function) {
case 81: /* delete */
@@ -1413,7 +1582,7 @@ static BOOL api_RDosPrintJobDel(int cnum,int uid, char *param,char *data,
return(True);
}
-static BOOL api_WPrintQueuePurge(int cnum,int uid, char *param,char *data,
+static BOOL api_WPrintQueuePurge(int cnum,uint16 vuid, char *param,char *data,
int mdrcnt,int mprcnt,
char **rdata,char **rparam,
int *rdata_len,int *rparam_len)
@@ -1484,7 +1653,7 @@ static int check_printjob_info(struct pack_desc* desc,
return True;
}
-static BOOL api_PrintJobInfo(int cnum,int uid,char *param,char *data,
+static BOOL api_PrintJobInfo(int cnum,uint16 vuid,char *param,char *data,
int mdrcnt,int mprcnt,
char **rdata,char **rparam,
int *rdata_len,int *rparam_len)
@@ -1493,13 +1662,13 @@ static BOOL api_PrintJobInfo(int cnum,int uid,char *param,char *data,
char *str1 = param+2;
char *str2 = skip_string(str1,1);
char *p = skip_string(str2,1);
- int jobid = (SVAL(p,0)&0xFF); /* the snum and jobid are encoded
- by the print queue api */
- int snum = (SVAL(p,0)>>8);
+ int jobid, snum;
int uLevel = SVAL(p,2);
int function = SVAL(p,4); /* what is this ?? */
int i;
char *s = data;
+
+ printjob_decode(SVAL(p,0), &snum, &jobid);
*rparam_len = 4;
*rparam = REALLOC(*rparam,*rparam_len);
@@ -1520,7 +1689,7 @@ static BOOL api_PrintJobInfo(int cnum,int uid,char *param,char *data,
lpq_reset(snum);
count = get_printqueue(snum,cnum,&queue,NULL);
for (i=0;i<count;i++) /* find job */
- if ((queue[i].job%0xFF) == jobid) break;
+ if ((queue[i].job&0xFF) == jobid) break;
if (i==count) {
desc.errcode=NERR_JobNotFound;
@@ -1551,29 +1720,33 @@ 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;
DEBUG(3,("Setting print name to %s\n",name));
+ become_root(True);
+
for (i=0;i<MAX_OPEN_FILES;i++)
if (Files[i].open && Files[i].print_file)
{
pstring wd;
+ int fcnum = Files[i].cnum;
GetWd(wd);
unbecome_user();
- if (!become_user(Files[i].cnum,uid) ||
- !become_service(Files[i].cnum,True))
+ if (!become_user(&Connections[fcnum], fcnum,vuid) ||
+ !become_service(fcnum,True))
break;
if (sys_rename(Files[i].name,name) == 0)
string_set(&Files[i].name,name);
break;
}
+
+ unbecome_root(True);
}
desc.errcode=NERR_Success;
@@ -1592,7 +1765,7 @@ static BOOL api_PrintJobInfo(int cnum,int uid,char *param,char *data,
/****************************************************************************
get info about the server
****************************************************************************/
-static BOOL api_RNetServerGetInfo(int cnum,int uid, char *param,char *data,
+static BOOL api_RNetServerGetInfo(int cnum,uint16 vuid, char *param,char *data,
int mdrcnt,int mprcnt,
char **rdata,char **rparam,
int *rdata_len,int *rparam_len)
@@ -1653,23 +1826,24 @@ static BOOL api_RNetServerGetInfo(int cnum,int uid, char *param,char *data,
struct srv_info_struct *servers=NULL;
int i,count;
pstring comment;
- uint32 servertype=SV_TYPE_SERVER_UNIX|SV_TYPE_WORKSTATION|
- SV_TYPE_SERVER|SV_TYPE_TIME_SOURCE;
+ uint32 servertype= lp_default_server_announce();
- strcpy(comment,lp_serverstring());
+ pstrcpy(comment,lp_serverstring());
- if ((count=get_server_info(SV_TYPE_ALL,&servers))>0) {
+ if ((count=get_server_info(SV_TYPE_ALL,&servers,myworkgroup))>0) {
for (i=0;i<count;i++)
- if (strequal(servers[i].name,local_machine)) {
+ if (strequal(servers[i].name,local_machine))
+ {
servertype = servers[i].type;
- strcpy(comment,servers[i].comment);
+ pstrcpy(comment,servers[i].comment);
}
}
if (servers) free(servers);
- SCVAL(p,0,2); /* version_major */
- SCVAL(p,1,0); /* version_minor */
+ SCVAL(p,0,lp_major_announce_version());
+ SCVAL(p,1,lp_minor_announce_version());
SIVAL(p,2,servertype);
+
if (mdrcnt == struct_len) {
SIVAL(p,6,0);
} else {
@@ -1699,7 +1873,7 @@ static BOOL api_RNetServerGetInfo(int cnum,int uid, char *param,char *data,
/****************************************************************************
get info about the server
****************************************************************************/
-static BOOL api_NetWkstaGetInfo(int cnum,int uid, char *param,char *data,
+static BOOL api_NetWkstaGetInfo(int cnum,uint16 vuid, char *param,char *data,
int mdrcnt,int mprcnt,
char **rdata,char **rparam,
int *rdata_len,int *rparam_len)
@@ -1729,8 +1903,10 @@ static BOOL api_NetWkstaGetInfo(int cnum,int uid, char *param,char *data,
p = *rdata;
p2 = p + 22;
- SIVAL(p,0,PTR_DIFF(p2,*rdata));
+
+ SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */
strcpy(p2,local_machine);
+ strupper(p2);
p2 = skip_string(p2,1);
p += 4;
@@ -1739,21 +1915,22 @@ static BOOL api_NetWkstaGetInfo(int cnum,int uid, char *param,char *data,
p2 = skip_string(p2,1);
p += 4;
- SIVAL(p,0,PTR_DIFF(p2,*rdata));
- strcpy(p2,my_workgroup());
+ SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
+ strcpy(p2,myworkgroup);
+ strupper(p2);
p2 = skip_string(p2,1);
p += 4;
- SCVAL(p,0,2); /* major version?? */
- SCVAL(p,1,1); /* minor version?? */
+ SCVAL(p,0,lp_major_announce_version()); /* system version - e.g 4 in 4.1 */
+ SCVAL(p,1,lp_minor_announce_version()); /* system version - e.g .1 in 4.1 */
p += 2;
SIVAL(p,0,PTR_DIFF(p2,*rdata));
- strcpy(p2,my_workgroup()); /* login domain?? */
+ strcpy(p2,myworkgroup); /* don't know. login domain?? */
p2 = skip_string(p2,1);
p += 4;
- SIVAL(p,0,PTR_DIFF(p2,*rdata));
+ SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
strcpy(p2,"");
p2 = skip_string(p2,1);
p += 4;
@@ -1765,154 +1942,331 @@ static BOOL api_NetWkstaGetInfo(int cnum,int uid, char *param,char *data,
return(True);
}
-
/****************************************************************************
get info about a user
+
+ struct user_info_11 {
+ char usri11_name[21]; 0-20
+ char usri11_pad; 21
+ char *usri11_comment; 22-25
+ char *usri11_usr_comment; 26-29
+ unsigned short usri11_priv; 30-31
+ unsigned long usri11_auth_flags; 32-35
+ long usri11_password_age; 36-39
+ char *usri11_homedir; 40-43
+ char *usri11_parms; 44-47
+ long usri11_last_logon; 48-51
+ long usri11_last_logoff; 52-55
+ unsigned short usri11_bad_pw_count; 56-57
+ unsigned short usri11_num_logons; 58-59
+ char *usri11_logon_server; 60-63
+ unsigned short usri11_country_code; 64-65
+ char *usri11_workstations; 66-69
+ unsigned long usri11_max_storage; 70-73
+ unsigned short usri11_units_per_week; 74-75
+ unsigned char *usri11_logon_hours; 76-79
+ unsigned short usri11_code_page; 80-81
+ };
+
+where:
+
+ usri11_name specifies the user name for which information is retireved
+
+ usri11_pad aligns the next data structure element to a word boundary
+
+ usri11_comment is a null terminated ASCII comment
+
+ usri11_user_comment is a null terminated ASCII comment about the user
+
+ usri11_priv specifies the level of the privilege assigned to the user.
+ The possible values are:
+
+Name Value Description
+USER_PRIV_GUEST 0 Guest privilege
+USER_PRIV_USER 1 User privilege
+USER_PRV_ADMIN 2 Administrator privilege
+
+ usri11_auth_flags specifies the account operator privileges. The
+ possible values are:
+
+Name Value Description
+AF_OP_PRINT 0 Print operator
+
+
+Leach, Naik [Page 28]
+
+
+INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
+
+
+AF_OP_COMM 1 Communications operator
+AF_OP_SERVER 2 Server operator
+AF_OP_ACCOUNTS 3 Accounts operator
+
+
+ usri11_password_age specifies how many seconds have elapsed since the
+ password was last changed.
+
+ usri11_home_dir points to a null terminated ASCII string that contains
+ the path name of the user's home directory.
+
+ usri11_parms points to a null terminated ASCII string that is set
+ aside for use by applications.
+
+ usri11_last_logon specifies the time when the user last logged on.
+ This value is stored as the number of seconds elapsed since
+ 00:00:00, January 1, 1970.
+
+ usri11_last_logoff specifies the time when the user last logged off.
+ This value is stored as the number of seconds elapsed since
+ 00:00:00, January 1, 1970. A value of 0 means the last logoff
+ time is unknown.
+
+ usri11_bad_pw_count specifies the number of incorrect passwords
+ entered since the last successful logon.
+
+ usri11_log1_num_logons specifies the number of times this user has
+ logged on. A value of -1 means the number of logons is unknown.
+
+ usri11_logon_server points to a null terminated ASCII string that
+ contains the name of the server to which logon requests are sent.
+ A null string indicates logon requests should be sent to the
+ domain controller.
+
+ usri11_country_code specifies the country code for the user's language
+ of choice.
+
+ usri11_workstations points to a null terminated ASCII string that
+ contains the names of workstations the user may log on from.
+ There may be up to 8 workstations, with the names separated by
+ commas. A null strings indicates there are no restrictions.
+
+ usri11_max_storage specifies the maximum amount of disk space the user
+ can occupy. A value of 0xffffffff indicates there are no
+ restrictions.
+
+ usri11_units_per_week specifies the equal number of time units into
+ which a week is divided. This value must be equal to 168.
+
+ usri11_logon_hours points to a 21 byte (168 bits) string that
+ specifies the time during which the user can log on. Each bit
+ represents one unique hour in a week. The first bit (bit 0, word
+ 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is
+
+
+
+Leach, Naik [Page 29]
+
+
+INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997
+
+
+ Sunday, 1:00 to 1:59 and so on. A null pointer indicates there
+ are no restrictions.
+
+ usri11_code_page specifies the code page for the user's language of
+ choice
+
+All of the pointers in this data structure need to be treated
+specially. The pointer is a 32 bit pointer. The higher 16 bits need
+to be ignored. The converter word returned in the parameters section
+needs to be subtracted from the lower 16 bits to calculate an offset
+into the return buffer where this ASCII string resides.
+
+There is no auxiliary data in the response.
+
****************************************************************************/
+#define usri11_name 0
+#define usri11_pad 21
+#define usri11_comment 22
+#define usri11_usr_comment 26
+#define usri11_full_name 30
+#define usri11_priv 34
+#define usri11_auth_flags 36
+#define usri11_password_age 40
+#define usri11_homedir 44
+#define usri11_parms 48
+#define usri11_last_logon 52
+#define usri11_last_logoff 56
+#define usri11_bad_pw_count 60
+#define usri11_num_logons 62
+#define usri11_logon_server 64
+#define usri11_country_code 68
+#define usri11_workstations 70
+#define usri11_max_storage 74
+#define usri11_units_per_week 78
+#define usri11_logon_hours 80
+#define usri11_code_page 84
+#define usri11_end 86
+
#define USER_PRIV_GUEST 0
#define USER_PRIV_USER 1
#define USER_PRIV_ADMIN 2
-static BOOL api_RNetUserGetInfo(int cnum,int uid, char *param,char *data,
+#define AF_OP_PRINT 0
+#define AF_OP_COMM 1
+#define AF_OP_SERVER 2
+#define AF_OP_ACCOUNTS 3
+
+
+static BOOL api_RNetUserGetInfo(int cnum,uint16 vuid, char *param,char *data,
int mdrcnt,int mprcnt,
char **rdata,char **rparam,
int *rdata_len,int *rparam_len)
{
- char *str1 = param+2;
- char *str2 = skip_string(str1,1);
- char *UserName = skip_string(str2,1);
- char *p = skip_string(UserName,1);
- int uLevel = SVAL(p,0);
- char *p2;
+ char *str1 = param+2;
+ char *str2 = skip_string(str1,1);
+ char *UserName = skip_string(str2,1);
+ char *p = skip_string(UserName,1);
+ int uLevel = SVAL(p,0);
+ char *p2;
- *rparam_len = 6;
- *rparam = REALLOC(*rparam,*rparam_len);
+ /* get NIS home of a previously validated user - simeon */
+ user_struct *vuser = get_valid_user_struct(vuid);
+ DEBUG(3,(" Username of UID %d is %s\n", vuser->uid, vuser->name));
- /* check it's a supported varient */
- if (strcmp(str1,"zWrLh") != 0) return False;
- switch( uLevel ) {
- case 0: p2 = "B21"; break;
- case 1: p2 = "B21BB16DWzzWz"; break;
- case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
- case 10: p2 = "B21Bzzz"; break;
- case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
- default: return False;
- }
- if (strcmp(p2,str2) != 0) return False;
+ *rparam_len = 6;
+ *rparam = REALLOC(*rparam,*rparam_len);
- *rdata_len = mdrcnt + 1024;
- *rdata = REALLOC(*rdata,*rdata_len);
+ DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel));
+
+ /* check it's a supported variant */
+ if (strcmp(str1,"zWrLh") != 0) return False;
+ switch( uLevel )
+ {
+ case 0: p2 = "B21"; break;
+ case 1: p2 = "B21BB16DWzzWz"; break;
+ case 2: p2 = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break;
+ case 10: p2 = "B21Bzzz"; break;
+ case 11: p2 = "B21BzzzWDDzzDDWWzWzDWb21W"; break;
+ default: return False;
+ }
- SSVAL(*rparam,0,NERR_Success);
- SSVAL(*rparam,2,0); /* converter word */
+ if (strcmp(p2,str2) != 0) return False;
- p = *rdata;
- p2 = p + 86;
+ *rdata_len = mdrcnt + 1024;
+ *rdata = REALLOC(*rdata,*rdata_len);
- memset(p,0,21);
- strcpy(p,UserName);
- if (uLevel > 0) {
- SCVAL(p,21,0);
- *p2 = 0;
- if (uLevel >= 10) {
- SIVAL(p,22,PTR_DIFF(p2,p)); /* comment */
- strcpy(p2,"<Comment>");
- p2 = skip_string(p2,1);
- SIVAL(p,26,PTR_DIFF(p2,p)); /* user_comment */
- strcpy(p2,"<UserComment>");
- p2 = skip_string(p2,1);
- SIVAL(p,30,PTR_DIFF(p2,p)); /* full name */
- strcpy(p2,"<FullName>");
- p2 = skip_string(p2,1);
- }
- if (uLevel == 11) { /* modelled after NTAS 3.51 reply */
- SSVAL(p,34,USER_PRIV_USER); /* user privilege */
- SIVAL(p,36,0); /* auth flags */
- SIVALS(p,40,-1); /* password age */
- SIVAL(p,44,PTR_DIFF(p2,p)); /* home dir */
- strcpy(p2,"\\\\%L\\HOMES");
- standard_sub_basic(p2);
- p2 = skip_string(p2,1);
- SIVAL(p,48,PTR_DIFF(p2,p)); /* parms */
- strcpy(p2,"");
- p2 = skip_string(p2,1);
- SIVAL(p,52,0); /* last logon */
- SIVAL(p,56,0); /* last logoff */
- SSVALS(p,60,-1); /* bad pw counts */
- SSVALS(p,62,-1); /* num logons */
- SIVAL(p,64,PTR_DIFF(p2,p)); /* logon server */
- strcpy(p2,"\\\\*");
- p2 = skip_string(p2,1);
- SSVAL(p,68,0); /* country code */
-
- SIVAL(p,70,PTR_DIFF(p2,p)); /* workstations */
- strcpy(p2,"");
- p2 = skip_string(p2,1);
-
- SIVALS(p,74,-1); /* max storage */
- SSVAL(p,78,168); /* units per week */
- SIVAL(p,80,PTR_DIFF(p2,p)); /* logon hours */
- memset(p2,-1,21);
- SCVAL(p2,21,0); /* fix zero termination */
- p2 = skip_string(p2,1);
-
- SSVAL(p,84,0); /* code page */
- }
- if (uLevel == 1 || uLevel == 2) {
- memset(p+22,' ',16); /* password */
- SIVALS(p,38,-1); /* password age */
- SSVAL(p,42,USER_PRIV_ADMIN); /* user privilege */
- SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
- strcpy(p2,"\\\\%L\\HOMES");
- standard_sub_basic(p2);
- p2 = skip_string(p2,1);
- SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
- *p2++ = 0;
- SSVAL(p,52,0); /* flags */
- SIVAL(p,54,0); /* script_path */
- if (uLevel == 2) {
- SIVAL(p,60,0); /* auth_flags */
- SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
- strcpy(p2,"<Full Name>");
- p2 = skip_string(p2,1);
- SIVAL(p,68,0); /* urs_comment */
- SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
- strcpy(p2,"");
- p2 = skip_string(p2,1);
- SIVAL(p,76,0); /* workstations */
- SIVAL(p,80,0); /* last_logon */
- SIVAL(p,84,0); /* last_logoff */
- SIVALS(p,88,-1); /* acct_expires */
- SIVALS(p,92,-1); /* max_storage */
- SSVAL(p,96,168); /* units_per_week */
- SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
- memset(p2,-1,21);
- p2 += 21;
- SSVALS(p,102,-1); /* bad_pw_count */
- SSVALS(p,104,-1); /* num_logons */
- SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
- strcpy(p2,"\\\\%L");
- standard_sub_basic(p2);
- p2 = skip_string(p2,1);
- SSVAL(p,110,49); /* country_code */
- SSVAL(p,112,860); /* code page */
- }
- }
- }
+ SSVAL(*rparam,0,NERR_Success);
+ SSVAL(*rparam,2,0); /* converter word */
- *rdata_len = PTR_DIFF(p2,*rdata);
+ p = *rdata;
+ p2 = p + usri11_end;
- SSVAL(*rparam,4,*rdata_len); /* is this right?? */
+ memset(p,0,21);
+ fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
- return(True);
-}
+ if (uLevel > 0)
+ {
+ SCVAL(p,usri11_pad,0); /* padding - 1 byte */
+ *p2 = 0;
+ }
+ if (uLevel >= 10)
+ {
+ SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */
+ strcpy(p2,"Comment");
+ p2 = skip_string(p2,1);
+
+ SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */
+ strcpy(p2,"UserComment");
+ p2 = skip_string(p2,1);
+
+ /* EEK! the cifsrap.txt doesn't have this in!!!! */
+ SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */
+ strcpy(p2,vuser->real_name); /* simeon */
+ p2 = skip_string(p2,1);
+ }
+
+ if (uLevel == 11) /* modelled after NTAS 3.51 reply */
+ {
+ SSVAL(p,usri11_priv,Connections[cnum].admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
+ SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */
+ SIVALS(p,usri11_password_age,0xffffffff); /* password age */
+ SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */
+ strcpy(p2, lp_logon_path());
+ p2 = skip_string(p2,1);
+ SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */
+ strcpy(p2,"");
+ p2 = skip_string(p2,1);
+ SIVAL(p,usri11_last_logon,0); /* last logon */
+ SIVAL(p,usri11_last_logoff,0); /* last logoff */
+ SSVALS(p,usri11_bad_pw_count,0xffffffff); /* bad pw counts */
+ SSVALS(p,usri11_num_logons,0xffffffff); /* num logons */
+ SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */
+ strcpy(p2,"\\\\*");
+ p2 = skip_string(p2,1);
+ SSVAL(p,usri11_country_code,0); /* country code */
+
+ SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */
+ strcpy(p2,"");
+ p2 = skip_string(p2,1);
+
+ SIVALS(p,usri11_max_storage,0xffffffff); /* max storage */
+ SSVAL(p,usri11_units_per_week,168); /* units per week */
+ SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */
+
+ /* a simple way to get logon hours at all times. */
+ memset(p2,0xff,21);
+ SCVAL(p2,21,0); /* fix zero termination */
+ p2 = skip_string(p2,1);
+
+ SSVAL(p,usri11_code_page,0); /* code page */
+ }
+ if (uLevel == 1 || uLevel == 2)
+ {
+ memset(p+22,' ',16); /* password */
+ SIVALS(p,38,-1); /* password age */
+ SSVAL(p,42,
+ Connections[cnum].admin_user?USER_PRIV_ADMIN:USER_PRIV_USER);
+ SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */
+ strcpy(p2,lp_logon_path());
+ p2 = skip_string(p2,1);
+ SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */
+ *p2++ = 0;
+ SSVAL(p,52,0); /* flags */
+ SIVAL(p,54,0); /* script_path */
+ if (uLevel == 2)
+ {
+ SIVAL(p,60,0); /* auth_flags */
+ SIVAL(p,64,PTR_DIFF(p2,*rdata)); /* full_name */
+ strcpy(p2,vuser->real_name); /* simeon */
+ p2 = skip_string(p2,1);
+ SIVAL(p,68,0); /* urs_comment */
+ SIVAL(p,72,PTR_DIFF(p2,*rdata)); /* parms */
+ strcpy(p2,"");
+ p2 = skip_string(p2,1);
+ SIVAL(p,76,0); /* workstations */
+ SIVAL(p,80,0); /* last_logon */
+ SIVAL(p,84,0); /* last_logoff */
+ SIVALS(p,88,-1); /* acct_expires */
+ SIVALS(p,92,-1); /* max_storage */
+ SSVAL(p,96,168); /* units_per_week */
+ SIVAL(p,98,PTR_DIFF(p2,*rdata)); /* logon_hours */
+ memset(p2,-1,21);
+ p2 += 21;
+ SSVALS(p,102,-1); /* bad_pw_count */
+ SSVALS(p,104,-1); /* num_logons */
+ SIVAL(p,106,PTR_DIFF(p2,*rdata)); /* logon_server */
+ strcpy(p2,"\\\\%L");
+ standard_sub_basic(p2);
+ p2 = skip_string(p2,1);
+ SSVAL(p,110,49); /* country_code */
+ SSVAL(p,112,860); /* code page */
+ }
+ }
+ *rdata_len = PTR_DIFF(p2,*rdata);
+
+ SSVAL(*rparam,4,*rdata_len); /* is this right?? */
+
+ return(True);
+}
/*******************************************************************
get groups that a user is a member of
******************************************************************/
-static BOOL api_NetUserGetGroups(int cnum,int uid, char *param,char *data,
+static BOOL api_NetUserGetGroups(int cnum,uint16 vuid, char *param,char *data,
int mdrcnt,int mprcnt,
char **rdata,char **rparam,
int *rdata_len,int *rparam_len)
@@ -1959,7 +2313,7 @@ static BOOL api_NetUserGetGroups(int cnum,int uid, char *param,char *data,
}
-static BOOL api_WWkstaUserLogon(int cnum,int uid, char *param,char *data,
+static BOOL api_WWkstaUserLogon(int cnum,uint16 vuid, char *param,char *data,
int mdrcnt,int mprcnt,
char **rdata,char **rparam,
int *rdata_len,int *rparam_len)
@@ -1970,6 +2324,7 @@ static BOOL api_WWkstaUserLogon(int cnum,int uid, char *param,char *data,
int uLevel;
struct pack_desc desc;
char* name;
+ char* logon_script;
uLevel = SVAL(p,0);
name = p + 2;
@@ -1987,9 +2342,8 @@ static BOOL api_WWkstaUserLogon(int cnum,int uid, char *param,char *data,
desc.subformat = NULL;
desc.format = str2;
-
-
- if (init_package(&desc,1,0)) {
+ if (init_package(&desc,1,0))
+ {
PACKI(&desc,"W",0); /* code */
PACKS(&desc,"B21",name); /* eff. name */
PACKS(&desc,"B",""); /* pad */
@@ -1998,7 +2352,7 @@ static BOOL api_WWkstaUserLogon(int cnum,int uid, char *param,char *data,
PACKI(&desc,"D",0); /* auth flags XXX */
PACKI(&desc,"W",0); /* num logons */
PACKI(&desc,"W",0); /* bad pw count */
- PACKI(&desc,"D",-1); /* last logon */
+ PACKI(&desc,"D",0); /* last logon */
PACKI(&desc,"D",-1); /* last logoff */
PACKI(&desc,"D",-1); /* logoff time */
PACKI(&desc,"D",-1); /* kickoff time */
@@ -2012,9 +2366,16 @@ static BOOL api_WWkstaUserLogon(int cnum,int uid, char *param,char *data,
strupper(mypath);
PACKS(&desc,"z",mypath); /* computer */
}
- PACKS(&desc,"z",my_workgroup());/* domain */
- PACKS(&desc,"z",lp_logon_script()); /* script path */
- PACKI(&desc,"D",0); /* reserved */
+ PACKS(&desc,"z",myworkgroup);/* domain */
+
+/* JHT - By calling lp_logon_script() and standard_sub() we have */
+/* made sure all macros are fully substituted and available */
+ logon_script = lp_logon_script();
+ standard_sub( cnum, logon_script );
+ PACKS(&desc,"z", logon_script); /* script path */
+/* End of JHT mods */
+
+ PACKI(&desc,"D",0x00000000); /* reserved */
}
*rdata_len = desc.usedlen;
@@ -2032,7 +2393,7 @@ static BOOL api_WWkstaUserLogon(int cnum,int uid, char *param,char *data,
/****************************************************************************
api_WAccessGetUserPerms
****************************************************************************/
-static BOOL api_WAccessGetUserPerms(int cnum,int uid, char *param,char *data,
+static BOOL api_WAccessGetUserPerms(int cnum,uint16 vuid, char *param,char *data,
int mdrcnt,int mprcnt,
char **rdata,char **rparam,
int *rdata_len,int *rparam_len)
@@ -2060,7 +2421,7 @@ static BOOL api_WAccessGetUserPerms(int cnum,int uid, char *param,char *data,
/****************************************************************************
api_WPrintJobEnumerate
****************************************************************************/
-static BOOL api_WPrintJobGetInfo(int cnum,int uid, char *param,char *data,
+static BOOL api_WPrintJobGetInfo(int cnum,uint16 vuid, char *param,char *data,
int mdrcnt,int mprcnt,
char **rdata,char **rparam,
int *rdata_len,int *rparam_len)
@@ -2068,7 +2429,6 @@ static BOOL api_WPrintJobGetInfo(int cnum,int uid, char *param,char *data,
char *str1 = param+2;
char *str2 = skip_string(str1,1);
char *p = skip_string(str2,1);
- int uJobId = SVAL(p,0);
int uLevel,cbBuf;
int count;
int i;
@@ -2084,20 +2444,19 @@ static BOOL api_WPrintJobGetInfo(int cnum,int uid, char *param,char *data,
bzero(&desc,sizeof(desc));
bzero(&status,sizeof(status));
- DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,uJobId));
+ DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0)));
/* check it's a supported varient */
if (strcmp(str1,"WWrLh") != 0) return False;
if (!check_printjob_info(&desc,uLevel,str2)) return False;
- snum = (unsigned int)uJobId >> 8; /*## valid serice number??*/
- job = uJobId & 0xFF;
+ printjob_decode(SVAL(p,0), &snum, &job);
if (snum < 0 || !VALID_SNUM(snum)) return(False);
count = get_printqueue(snum,cnum,&queue,&status);
for (i = 0; i < count; i++) {
- if ((queue[i].job % 0xFF) == job) break;
+ if ((queue[i].job & 0xFF) == job) break;
}
if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
desc.base = *rdata;
@@ -2126,7 +2485,7 @@ static BOOL api_WPrintJobGetInfo(int cnum,int uid, char *param,char *data,
return(True);
}
-static BOOL api_WPrintJobEnumerate(int cnum,int uid, char *param,char *data,
+static BOOL api_WPrintJobEnumerate(int cnum,uint16 vuid, char *param,char *data,
int mdrcnt,int mprcnt,
char **rdata,char **rparam,
int *rdata_len,int *rparam_len)
@@ -2215,7 +2574,8 @@ static void fill_printdest_info(int cnum, int snum, int uLevel,
struct pack_desc* desc)
{
char buf[100];
- strcpy(buf,SERVICE(snum));
+ strncpy(buf,SERVICE(snum),sizeof(buf)-1);
+ buf[sizeof(buf)-1] = 0;
strupper(buf);
if (uLevel <= 1) {
PACKS(desc,"B9",buf); /* szName */
@@ -2243,7 +2603,7 @@ static void fill_printdest_info(int cnum, int snum, int uLevel,
}
}
-static BOOL api_WPrintDestGetInfo(int cnum,int uid, char *param,char *data,
+static BOOL api_WPrintDestGetInfo(int cnum,uint16 vuid, char *param,char *data,
int mdrcnt,int mprcnt,
char **rdata,char **rparam,
int *rdata_len,int *rparam_len)
@@ -2302,7 +2662,7 @@ static BOOL api_WPrintDestGetInfo(int cnum,int uid, char *param,char *data,
return(True);
}
-static BOOL api_WPrintDestEnum(int cnum,int uid, char *param,char *data,
+static BOOL api_WPrintDestEnum(int cnum,uint16 vuid, char *param,char *data,
int mdrcnt,int mprcnt,
char **rdata,char **rparam,
int *rdata_len,int *rparam_len)
@@ -2360,7 +2720,7 @@ static BOOL api_WPrintDestEnum(int cnum,int uid, char *param,char *data,
return(True);
}
-static BOOL api_WPrintDriverEnum(int cnum,int uid, char *param,char *data,
+static BOOL api_WPrintDriverEnum(int cnum,uint16 vuid, char *param,char *data,
int mdrcnt,int mprcnt,
char **rdata,char **rparam,
int *rdata_len,int *rparam_len)
@@ -2405,7 +2765,7 @@ static BOOL api_WPrintDriverEnum(int cnum,int uid, char *param,char *data,
return(True);
}
-static BOOL api_WPrintQProcEnum(int cnum,int uid, char *param,char *data,
+static BOOL api_WPrintQProcEnum(int cnum,uint16 vuid, char *param,char *data,
int mdrcnt,int mprcnt,
char **rdata,char **rparam,
int *rdata_len,int *rparam_len)
@@ -2451,7 +2811,7 @@ static BOOL api_WPrintQProcEnum(int cnum,int uid, char *param,char *data,
return(True);
}
-static BOOL api_WPrintPortEnum(int cnum,int uid, char *param,char *data,
+static BOOL api_WPrintPortEnum(int cnum,uint16 vuid, char *param,char *data,
int mdrcnt,int mprcnt,
char **rdata,char **rparam,
int *rdata_len,int *rparam_len)
@@ -2498,10 +2858,177 @@ static BOOL api_WPrintPortEnum(int cnum,int uid, char *param,char *data,
return(True);
}
+
+struct
+{
+ char * name;
+ char * pipe_clnt_name;
+#ifdef NTDOMAIN
+ char * pipe_srv_name;
+#endif
+ int subcommand;
+ BOOL (*fn) ();
+} api_fd_commands [] =
+ {
+#ifdef NTDOMAIN
+ { "SetNmdPpHndState", "lsarpc", "lsass", 1, api_LsarpcSNPHS },
+ { "SetNmdPpHndState", "srvsvc", "lsass", 1, api_LsarpcSNPHS },
+ { "SetNmdPpHndState", "NETLOGON", "NETLOGON", 1, api_LsarpcSNPHS },
+ { "TransactNmPipe", "lsarpc", "lsass", 0x26, api_ntLsarpcTNP },
+ { "TransactNmPipe", "srvsvc", "lsass", 0x26, api_srvsvcTNP },
+ { "TransactNmPipe", "NETLOGON", "NETLOGON", 0x26, api_netlogrpcTNP },
+ { NULL, NULL, NULL, -1, (BOOL (*)())api_Unsupported }
+#else
+ { "SetNmdPpHndState", "lsarpc", 1, api_LsarpcSNPHS },
+ { "TransactNmPipe" , "lsarpc", 0x26, api_LsarpcTNP },
+ { NULL, NULL, -1, (BOOL (*)())api_Unsupported }
+#endif
+ };
+
+/****************************************************************************
+ handle remote api calls delivered to a named pipe already opened.
+ ****************************************************************************/
+static int api_fd_reply(int cnum,uint16 vuid,char *outbuf,
+ uint16 *setup,char *data,char *params,
+ int suwcnt,int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
+{
+ char *rdata = NULL;
+ char *rparam = NULL;
+ int rdata_len = 0;
+ int rparam_len = 0;
+
+ BOOL reply = False;
+ BOOL bind_req = False;
+
+ int i;
+ int fd;
+ int subcommand;
+ pstring pipe_name;
+
+ DEBUG(5,("api_fd_reply\n"));
+ /* First find out the name of this file. */
+ if (suwcnt != 2)
+ {
+ DEBUG(0,("Unexpected named pipe transaction.\n"));
+ return(-1);
+ }
+
+ /* Get the file handle and hence the file name. */
+ fd = setup[1];
+ subcommand = setup[0];
+ if (fd >= 0 && fd < MAX_OPEN_FILES)
+ {
+ pstrcpy(pipe_name, Files[fd].name);
+ }
+ else
+ {
+ pipe_name[0] = 0;
+ DEBUG(1,("api_fd_reply: INVALID FILE HANDLE: %x\n", fd));
+ }
+
+ DEBUG(3,("Got API command %d on pipe %s (fd %x)",
+ subcommand, pipe_name, fd));
+ DEBUG(3,("(tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d,cnum=%d,vuid=%d)\n",
+ tdscnt,tpscnt,mdrcnt,mprcnt,cnum,vuid));
+
+ for (i = 0; api_fd_commands[i].name; i++)
+ {
+ if (strequal(api_fd_commands[i].pipe_clnt_name, pipe_name) &&
+ api_fd_commands[i].subcommand == subcommand &&
+ api_fd_commands[i].fn)
+ {
+ DEBUG(3,("Doing %s\n", api_fd_commands[i].name));
+ break;
+ }
+ }
+
+ rdata = (char *)malloc(1024); if (rdata ) bzero(rdata ,1024);
+ rparam = (char *)malloc(1024); if (rparam) bzero(rparam,1024);
+
+#ifdef NTDOMAIN
+ if (data != NULL && api_fd_commands[i].subcommand != -1)
+ {
+ RPC_HDR hdr;
+
+ /* process the rpc header */
+ char *q = smb_io_rpc_hdr(True, &hdr, data, data, 4, 0);
+
+ /* bind request received */
+ if ((bind_req = ((q != NULL) && (hdr.pkt_type == RPC_BIND))))
+ {
+ RPC_HDR_RB hdr_rb;
+
+ /* decode the bind request */
+ char *p = smb_io_rpc_hdr_rb(True, &hdr_rb, q, data, 4, 0);
+
+ if ((bind_req = (p != NULL)))
+ {
+ RPC_HDR_BA hdr_ba;
+ fstring ack_pipe_name;
+
+ /* name has to be \PIPE\xxxxx */
+ strcpy(ack_pipe_name, "\\PIPE\\");
+ strcat(ack_pipe_name, api_fd_commands[i].pipe_srv_name);
+
+ /* make a bind acknowledgement */
+ make_rpc_hdr_ba(&hdr_ba,
+ hdr_rb.bba.max_tsize, hdr_rb.bba.max_rsize, hdr_rb.bba.assoc_gid,
+ ack_pipe_name,
+ 0x1, 0x0, 0x0,
+ &(hdr_rb.transfer));
+
+ p = smb_io_rpc_hdr_ba(False, &hdr_ba, rdata + 0x10, rdata, 4, 0);
+
+ rdata_len = PTR_DIFF(p, rdata);
+
+ make_rpc_hdr(&hdr, RPC_BINDACK, 0x0, hdr.call_id, rdata_len);
+
+ p = smb_io_rpc_hdr(False, &hdr, rdata, rdata, 4, 0);
+
+ reply = (p != NULL);
+ }
+ }
+ }
+#endif
+
+ if (!bind_req)
+ {
+ DEBUG(10,("calling api_fd_command\n"));
+
+ reply = api_fd_commands[i].fn(cnum,vuid,params,data,mdrcnt,mprcnt,
+ &rdata,&rparam,&rdata_len,&rparam_len);
+ DEBUG(10,("called api_fd_command\n"));
+ }
+
+ if (rdata_len > mdrcnt || rparam_len > mprcnt)
+ {
+ reply = api_TooSmall(cnum,vuid,params,data,mdrcnt,mprcnt,
+ &rdata,&rparam,&rdata_len,&rparam_len);
+ }
+
+
+ /* if we get False back then it's actually unsupported */
+ if (!reply)
+ api_Unsupported(cnum,vuid,params,data,mdrcnt,mprcnt,
+ &rdata,&rparam,&rdata_len,&rparam_len);
+
+ /* now send the reply */
+ send_trans_reply(outbuf,rdata,rparam,NULL,rdata_len,rparam_len,0);
+
+ if (rdata)
+ free(rdata);
+ if (rparam)
+ free(rparam);
+
+ return(-1);
+}
+
+
+
/****************************************************************************
the buffer was too small
****************************************************************************/
-static BOOL api_TooSmall(int cnum,int uid, char *param,char *data,
+static BOOL api_TooSmall(int cnum,uint16 vuid, char *param,char *data,
int mdrcnt,int mprcnt,
char **rdata,char **rparam,
int *rdata_len,int *rparam_len)
@@ -2522,7 +3049,7 @@ static BOOL api_TooSmall(int cnum,int uid, char *param,char *data,
/****************************************************************************
the request is not supported
****************************************************************************/
-static BOOL api_Unsupported(int cnum,int uid, char *param,char *data,
+static BOOL api_Unsupported(int cnum,uint16 vuid, char *param,char *data,
int mdrcnt,int mprcnt,
char **rdata,char **rparam,
int *rdata_len,int *rparam_len)
@@ -2550,38 +3077,38 @@ struct
BOOL (*fn)();
int flags;
} api_commands[] = {
- {"RNetShareEnum", 0, api_RNetShareEnum,0},
- {"RNetShareGetInfo", 1, api_RNetShareGetInfo,0},
- {"RNetServerGetInfo", 13, api_RNetServerGetInfo,0},
- {"RNetUserGetInfo", 56, api_RNetUserGetInfo,0},
- {"NetUserGetGroups", 59, api_NetUserGetGroups,0},
- {"NetWkstaGetInfo", 63, api_NetWkstaGetInfo,0},
- {"DosPrintQEnum", 69, api_DosPrintQEnum,0},
- {"DosPrintQGetInfo", 70, api_DosPrintQGetInfo,0},
- {"WPrintJobEnumerate",76, api_WPrintJobEnumerate,0},
- {"WPrintJobGetInfo", 77, api_WPrintJobGetInfo,0},
- {"RDosPrintJobDel", 81, api_RDosPrintJobDel,0},
- {"RDosPrintJobPause", 82, api_RDosPrintJobDel,0},
- {"RDosPrintJobResume",83, api_RDosPrintJobDel,0},
- {"WPrintDestEnum", 84, api_WPrintDestEnum,0},
- {"WPrintDestGetInfo", 85, api_WPrintDestGetInfo,0},
- {"NetRemoteTOD", 91, api_NetRemoteTOD,0},
- {"WPrintQueuePurge", 103, api_WPrintQueuePurge,0},
- {"NetServerEnum", 104, api_RNetServerEnum,0},
- {"WAccessGetUserPerms",105, api_WAccessGetUserPerms,0},
- {"SetUserPassword", 115, api_SetUserPassword,0},
- {"WWkstaUserLogon", 132, api_WWkstaUserLogon,0},
- {"PrintJobInfo", 147, api_PrintJobInfo,0},
- {"WPrintDriverEnum", 205, api_WPrintDriverEnum,0},
- {"WPrintQProcEnum", 206, api_WPrintQProcEnum,0},
- {"WPrintPortEnum", 207, api_WPrintPortEnum,0},
- {NULL, -1, api_Unsupported,0}};
+ {"RNetShareEnum", 0, (BOOL (*)())api_RNetShareEnum,0},
+ {"RNetShareGetInfo", 1, (BOOL (*)())api_RNetShareGetInfo,0},
+ {"RNetServerGetInfo", 13, (BOOL (*)())api_RNetServerGetInfo,0},
+ {"RNetUserGetInfo", 56, (BOOL (*)())api_RNetUserGetInfo,0},
+ {"NetUserGetGroups", 59, (BOOL (*)())api_NetUserGetGroups,0},
+ {"NetWkstaGetInfo", 63, (BOOL (*)())api_NetWkstaGetInfo,0},
+ {"DosPrintQEnum", 69, (BOOL (*)())api_DosPrintQEnum,0},
+ {"DosPrintQGetInfo", 70, (BOOL (*)())api_DosPrintQGetInfo,0},
+ {"WPrintJobEnumerate",76, (BOOL (*)())api_WPrintJobEnumerate,0},
+ {"WPrintJobGetInfo", 77, (BOOL (*)())api_WPrintJobGetInfo,0},
+ {"RDosPrintJobDel", 81, (BOOL (*)())api_RDosPrintJobDel,0},
+ {"RDosPrintJobPause", 82, (BOOL (*)())api_RDosPrintJobDel,0},
+ {"RDosPrintJobResume",83, (BOOL (*)())api_RDosPrintJobDel,0},
+ {"WPrintDestEnum", 84, (BOOL (*)())api_WPrintDestEnum,0},
+ {"WPrintDestGetInfo", 85, (BOOL (*)())api_WPrintDestGetInfo,0},
+ {"NetRemoteTOD", 91, (BOOL (*)())api_NetRemoteTOD,0},
+ {"WPrintQueuePurge", 103, (BOOL (*)())api_WPrintQueuePurge,0},
+ {"NetServerEnum", 104, (BOOL (*)())api_RNetServerEnum,0},
+ {"WAccessGetUserPerms",105, (BOOL (*)())api_WAccessGetUserPerms,0},
+ {"SetUserPassword", 115, (BOOL (*)())api_SetUserPassword,0},
+ {"WWkstaUserLogon", 132, (BOOL (*)())api_WWkstaUserLogon,0},
+ {"PrintJobInfo", 147, (BOOL (*)())api_PrintJobInfo,0},
+ {"WPrintDriverEnum", 205, (BOOL (*)())api_WPrintDriverEnum,0},
+ {"WPrintQProcEnum", 206, (BOOL (*)())api_WPrintQProcEnum,0},
+ {"WPrintPortEnum", 207, (BOOL (*)())api_WPrintPortEnum,0},
+ {NULL, -1, (BOOL (*)())api_Unsupported,0}};
/****************************************************************************
handle remote api calls
****************************************************************************/
-static int api_reply(int cnum,int uid,char *outbuf,char *data,char *params,
+static int api_reply(int cnum,uint16 vuid,char *outbuf,char *data,char *params,
int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
{
int api_command = SVAL(params,0);
@@ -2606,21 +3133,21 @@ static int api_reply(int cnum,int uid,char *outbuf,char *data,char *params,
rdata = (char *)malloc(1024); if (rdata) bzero(rdata,1024);
rparam = (char *)malloc(1024); if (rparam) bzero(rparam,1024);
- reply = api_commands[i].fn(cnum,uid,params,data,mdrcnt,mprcnt,
+ reply = api_commands[i].fn(cnum,vuid,params,data,mdrcnt,mprcnt,
&rdata,&rparam,&rdata_len,&rparam_len);
if (rdata_len > mdrcnt ||
rparam_len > mprcnt)
{
- reply = api_TooSmall(cnum,uid,params,data,mdrcnt,mprcnt,
+ reply = api_TooSmall(cnum,vuid,params,data,mdrcnt,mprcnt,
&rdata,&rparam,&rdata_len,&rparam_len);
}
/* if we get False back then it's actually unsupported */
if (!reply)
- api_Unsupported(cnum,uid,params,data,mdrcnt,mprcnt,
+ api_Unsupported(cnum,vuid,params,data,mdrcnt,mprcnt,
&rdata,&rparam,&rdata_len,&rparam_len);
@@ -2639,19 +3166,29 @@ static int api_reply(int cnum,int uid,char *outbuf,char *data,char *params,
/****************************************************************************
handle named pipe commands
****************************************************************************/
-static int named_pipe(int cnum,int uid, char *outbuf,char *name,
+static int named_pipe(int cnum,uint16 vuid, char *outbuf,char *name,
uint16 *setup,char *data,char *params,
int suwcnt,int tdscnt,int tpscnt,
int msrcnt,int mdrcnt,int mprcnt)
{
+ DEBUG(3,("named pipe command on <%s> name\n", name));
- if (strequal(name,"LANMAN"))
- return(api_reply(cnum,uid,outbuf,data,params,tdscnt,tpscnt,mdrcnt,mprcnt));
+ if (strequal(name,"LANMAN"))
+ {
+ return api_reply(cnum,vuid,outbuf,data,params,tdscnt,tpscnt,mdrcnt,mprcnt);
+ }
- DEBUG(3,("named pipe command on <%s> 0x%X setup1=%d\n",
- name,(int)setup[0],(int)setup[1]));
-
- return(0);
+ if (strlen(name) < 1)
+ {
+ return api_fd_reply(cnum,vuid,outbuf,setup,data,params,suwcnt,tdscnt,tpscnt,mdrcnt,mprcnt);
+ }
+
+ if (setup)
+ {
+ DEBUG(3,("unknown named pipe: setup 0x%X setup1=%d\n", (int)setup[0],(int)setup[1]));
+ }
+
+ return 0;
}
@@ -2667,7 +3204,7 @@ int reply_trans(char *inbuf,char *outbuf)
int outsize = 0;
int cnum = SVAL(inbuf,smb_tid);
- int uid = SVAL(inbuf,smb_uid);
+ uint16 vuid = SVAL(inbuf,smb_uid);
int tpscnt = SVAL(inbuf,smb_vwv0);
int tdscnt = SVAL(inbuf,smb_vwv1);
@@ -2682,7 +3219,12 @@ int reply_trans(char *inbuf,char *outbuf)
int dsoff = SVAL(inbuf,smb_vwv12);
int suwcnt = CVAL(inbuf,smb_vwv13);
- StrnCpy(name,smb_buf(inbuf),sizeof(name)-1);
+ bzero(name, sizeof(name));
+ fstrcpy(name,smb_buf(inbuf));
+
+ if (dscnt > tdscnt || pscnt > tpscnt) {
+ exit_server("invalid trans parameters\n");
+ }
if (tdscnt)
{
@@ -2717,12 +3259,9 @@ int reply_trans(char *inbuf,char *outbuf)
while (pscnt < tpscnt || dscnt < tdscnt)
{
int pcnt,poff,dcnt,doff,pdisp,ddisp;
-
- receive_smb(Client,inbuf, 0);
- show_msg(inbuf);
-
- /* Ensure this is still a trans packet (sanity check) */
- if(CVAL(inbuf, smb_com) != SMBtrans)
+
+ if (!receive_smb(Client,inbuf, SMB_SECONDARY_WAIT) ||
+ CVAL(inbuf, smb_com) != SMBtrans)
{
DEBUG(2,("Invalid secondary trans2 packet\n"));
if (params) free(params);
@@ -2730,6 +3269,8 @@ int reply_trans(char *inbuf,char *outbuf)
if (setup) free(setup);
return(ERROR(ERRSRV,ERRerror));
}
+
+ show_msg(inbuf);
tpscnt = SVAL(inbuf,smb_vwv0);
tdscnt = SVAL(inbuf,smb_vwv1);
@@ -2745,6 +3286,10 @@ int reply_trans(char *inbuf,char *outbuf)
pscnt += pcnt;
dscnt += dcnt;
+ if (dscnt > tdscnt || pscnt > tpscnt) {
+ exit_server("invalid trans parameters\n");
+ }
+
if (pcnt)
memcpy(params+pdisp,smb_base(inbuf)+poff,pcnt);
if (dcnt)
@@ -2753,11 +3298,18 @@ int reply_trans(char *inbuf,char *outbuf)
DEBUG(3,("trans <%s> data=%d params=%d setup=%d\n",name,tdscnt,tpscnt,suwcnt));
-
if (strncmp(name,"\\PIPE\\",strlen("\\PIPE\\")) == 0)
- outsize = named_pipe(cnum,uid,outbuf,name+strlen("\\PIPE\\"),setup,data,params,
+ {
+ DEBUG(5,("calling named_pipe\n"));
+ outsize = named_pipe(cnum,vuid,outbuf,name+strlen("\\PIPE\\"),setup,data,params,
suwcnt,tdscnt,tpscnt,msrcnt,mdrcnt,mprcnt);
+ }
+ else
+ {
+ DEBUG(3,("invalid pipe name\n"));
+ outsize = 0;
+ }
if (data) free(data);
@@ -2765,7 +3317,7 @@ int reply_trans(char *inbuf,char *outbuf)
if (setup) free(setup);
if (close_on_completion)
- close_cnum(cnum,uid);
+ close_cnum(cnum,vuid);
if (one_way)
return(-1);
@@ -2775,5 +3327,3 @@ int reply_trans(char *inbuf,char *outbuf)
return(outsize);
}
-
-
diff --git a/source/smbd/mangle.c b/source/smbd/mangle.c
index 8f1490c528d..829e307a85b 100644
--- a/source/smbd/mangle.c
+++ b/source/smbd/mangle.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Name mangling
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1997
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,7 +20,6 @@
*/
#include "includes.h"
-#include "loadparm.h"
extern int DEBUGLEVEL;
extern int case_default;
@@ -80,7 +79,7 @@ static BOOL is_reserved_msdos(char *fname)
/****************************************************************************
return True if a name is in 8.3 dos format
****************************************************************************/
-BOOL is_8_3(char *fname)
+BOOL is_8_3(char *fname, BOOL check_case)
{
int len;
char *dot_pos;
@@ -90,11 +89,9 @@ 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)
+ if (check_case && case_mangle)
switch (case_default)
{
case CASE_LOWER:
@@ -122,32 +119,38 @@ 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
- dot_pos = 0;
- while (*p)
+ if(lp_client_code_page() == KANJI_CODEPAGE)
+ {
+ dot_pos = 0;
+ while (*p)
{
- if (is_shift_jis (*p)) {
- p += 2;
- } else if (is_kana (*p)) {
- p ++;
- } else {
- if (*p == '.' && !dot_pos)
- dot_pos = (char *) p;
- if (!isdoschar(*p))
- return(False);
- p++;
- }
- }
-#else
- while (*p)
+ if (is_shift_jis (*p))
+ p += 2;
+ else if (is_kana (*p))
+ p ++;
+ else
+ {
+ if (*p == '.' && !dot_pos)
+ dot_pos = (char *) p;
+ if (!isdoschar(*p))
+ return(False);
+ p++;
+ }
+ }
+ }
+ else
+ {
+ while (*p)
{
- if (!isdoschar(*p))
- return(False);
- p++;
+ if (!isdoschar(*p))
+ return(False);
+ p++;
}
-#endif /* KANJI */
+ }
}
/* no dot and less than 9 means OK */
@@ -270,7 +273,7 @@ BOOL check_mangled_stack(char *s)
}
if (check_extension && !strchr(mangled_stack[i],'.'))
{
- strcpy(tmpname,mangled_stack[i]);
+ pstrcpy(tmpname,mangled_stack[i]);
strcat(tmpname,extension);
mangle_name_83(tmpname);
if (strequal(tmpname,s))
@@ -304,7 +307,7 @@ static char *map_filename(char *s, /* This is null terminated */
pstring pat;
StrnCpy(pat, pattern, len); /* Get pattern into a proper string! */
- strcpy(matching_bit,""); /* Match but no star gets this. */
+ pstrcpy(matching_bit,""); /* Match but no star gets this. */
pp = pat; /* Initialise the pointers. */
sp = s;
if ((len == 1) && (*pattern == '*')) {
@@ -384,13 +387,10 @@ BOOL is_mangled(char *s)
/****************************************************************************
return a base 36 character. v must be from 0 to 35.
****************************************************************************/
-static char base36(int v)
+static char base36(unsigned int v)
{
- v = v % 36;
- if (v < 10)
- return('0'+v);
- else /* needed to work around a DEC C compiler bug */
- return('A' + (v-10));
+ static char basechars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ return basechars[v % 36];
}
@@ -418,9 +418,9 @@ static void do_fwd_mangled_map(char *s, char *MangledMap)
while (*start) {
while ((*start) && (*start != '('))
start++;
- start++; /* Skip the ( */
if (!*start)
continue; /* Always check for the end. */
+ start++; /* Skip the ( */
end = start; /* Search for the ' ' or a ')' */
DEBUG(5,("Start of first in pair '%s'\n", start));
while ((*end) && !((*end == ' ') || (*end == ')')))
@@ -446,7 +446,7 @@ static void do_fwd_mangled_map(char *s, char *MangledMap)
continue; /* Always check for the end. */
}
if (*end == '*') {
- strcpy(np, match_string);
+ pstrcpy(np, match_string);
np += strlen(match_string);
end++; /* Skip the '*' */
while ((*end) /* Not the end of string. */
@@ -460,7 +460,7 @@ static void do_fwd_mangled_map(char *s, char *MangledMap)
}
*np++ = '\0'; /* NULL terminate it. */
DEBUG(5,("End of second in pair '%s'\n", end));
- strcpy(s, new_string); /* Substitute with the new name. */
+ pstrcpy(s, new_string); /* Substitute with the new name. */
DEBUG(5,("s is now '%s'\n", s));
}
start = end; /* Skip a bit which cannot be wanted */
@@ -502,30 +502,90 @@ void mangle_name_83(char *s)
DEBUG(5,("Mangling name %s to ",s));
if (p)
- {
- if (p == s)
- strcpy(extension,"___");
- else
+ {
+ if (p == s)
+ strcpy(extension,"___");
+ else
{
*p++ = 0;
while (*p && extlen < 3)
- {
- if (isdoschar(*p) && *p != '.')
- extension[extlen++] = *p;
- p++;
- }
+ {
+ if(lp_client_code_page() == KANJI_CODEPAGE)
+ {
+ if (is_shift_jis (*p))
+ {
+ if (extlen < 2)
+ {
+ extension[extlen++] = p[0];
+ extension[extlen++] = p[1];
+ }
+ else
+ {
+ extension[extlen++] = base36 (((unsigned char) *p) % 36);
+ }
+ p += 2;
+ }
+ else if (is_kana (*p))
+ {
+ extension[extlen++] = p[0];
+ p++;
+ }
+ else
+ {
+ if (isdoschar (*p) && *p != '.')
+ extension[extlen++] = p[0];
+ p++;
+ }
+ }
+ else
+ {
+ if (isdoschar(*p) && *p != '.')
+ extension[extlen++] = *p;
+ p++;
+ }
+ }
extension[extlen] = 0;
- }
}
+ }
p = s;
while (*p && baselen < 5)
+ {
+ if(lp_client_code_page() == KANJI_CODEPAGE)
+ {
+ if (is_shift_jis (*p))
+ {
+ if (baselen < 4)
+ {
+ base[baselen++] = p[0];
+ base[baselen++] = p[1];
+ }
+ else
+ {
+ base[baselen++] = base36 (((unsigned char) *p) % 36);
+ }
+ p += 2;
+ }
+ else if (is_kana (*p))
+ {
+ base[baselen++] = p[0];
+ p++;
+ }
+ else
+ {
+ if (isdoschar (*p) && *p != '.')
+ base[baselen++] = p[0];
+ p++;
+ }
+ }
+ else
{
if (isdoschar(*p) && *p != '.')
- base[baselen++] = *p;
+ base[baselen++] = *p;
p++;
}
+ }
base[baselen] = 0;
csum = csum % (36*36);
@@ -551,8 +611,9 @@ static BOOL illegal_name(char *name)
static BOOL initialised=False;
unsigned char *s;
- if (!initialised) {
- char *ill = "*\\/?<>|\":{}";
+ if (!initialised)
+ {
+ char *ill = "*\\/?<>|\":";
initialised = True;
bzero((char *)illegal,256);
@@ -560,21 +621,23 @@ static BOOL illegal_name(char *name)
illegal[*s] = True;
}
-#ifdef KANJI
- for (s = (unsigned char *)name; *s;) {
- if (is_shift_jis (*s)) {
- s += 2;
- } else if (illegal[*s]) {
- return(True);
- } else {
- s++;
+ if(lp_client_code_page() == KANJI_CODEPAGE)
+ {
+ for (s = (unsigned char *)name; *s;) {
+ if (is_shift_jis (*s)) {
+ s += 2;
+ } else if (illegal[*s]) {
+ return(True);
+ } else {
+ s++;
+ }
}
}
-#else
- for (s = (unsigned char *)name;*s;s++)
- if (illegal[*s]) return(True);
-#endif
-
+ else
+ {
+ for (s = (unsigned char *)name;*s;s++)
+ if (illegal[*s]) return(True);
+ }
return(False);
}
@@ -597,7 +660,7 @@ BOOL name_map_mangle(char *OutName,BOOL need83,int snum)
}
/* check if it's already in 8.3 format */
- if (need83 && !is_8_3(OutName)) {
+ if (need83 && !is_8_3(OutName, True)) {
if (!lp_manglednames(snum)) return(False);
/* mangle it into 8.3 */
diff --git a/source/smbd/message.c b/source/smbd/message.c
index 6a96b4c7a9c..64253932abb 100644
--- a/source/smbd/message.c
+++ b/source/smbd/message.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
SMB messaging
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1997
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
@@ -25,7 +25,6 @@
#include "includes.h"
-#include "loadparm.h"
/* look in server.c for some explanation of these variables */
extern int DEBUGLEVEL;
@@ -43,8 +42,8 @@ static void msg_deliver(void)
{
pstring s;
fstring name;
- FILE *f;
int i;
+ int fd;
if (! (*lp_msg_command()))
{
@@ -54,35 +53,33 @@ static void msg_deliver(void)
}
/* put it in a temporary file */
- sprintf(s,"/tmp/msg.XXXXXX");
- strcpy(name,(char *)mktemp(s));
-
- f = fopen(name,"w");
- if (!f)
- {
- DEBUG(1,("can't open message file %s\n",name));
- return;
+ sprintf(s,"%s/msg.XXXXXX",tmpdir());
+ fstrcpy(name,(char *)mktemp(s));
+
+ fd = open(name,O_WRONLY|O_CREAT|O_TRUNC|O_EXCL,0600);
+ if (fd == -1) {
+ DEBUG(1,("can't open message file %s\n",name));
+ return;
+ }
+
+ for (i=0;i<msgpos;) {
+ if (msgbuf[i]=='\r' && i<(msgpos-1) && msgbuf[i+1]=='\n') {
+ i++; continue;
}
-
- for (i=0;i<msgpos;)
- {
- if (msgbuf[i]=='\r' && i<(msgpos-1) && msgbuf[i+1]=='\n')
- i++;
- fputc(msgbuf[i++],f);
- }
-
- fclose(f);
+ write(fd,&msgbuf[i++],1);
+ }
+ close(fd);
/* run the command */
if (*lp_msg_command())
{
- strcpy(s,lp_msg_command());
+ pstrcpy(s,lp_msg_command());
string_sub(s,"%s",name);
string_sub(s,"%f",msgfrom);
string_sub(s,"%t",msgto);
standard_sub(-1,s);
- smbrun(s,NULL);
+ smbrun(s,NULL,False);
}
msgpos = 0;
@@ -111,8 +108,8 @@ int reply_sends(char *inbuf,char *outbuf)
dest = skip_string(orig,1)+1;
msg = skip_string(dest,1)+1;
- strcpy(msgfrom,orig);
- strcpy(msgto,dest);
+ fstrcpy(msgfrom,orig);
+ fstrcpy(msgto,dest);
len = SVAL(msg,0);
len = MIN(len,1600-msgpos);
@@ -146,10 +143,10 @@ int reply_sendstrt(char *inbuf,char *outbuf)
orig = smb_buf(inbuf)+1;
dest = skip_string(orig,1)+1;
- strcpy(msgfrom,orig);
- strcpy(msgto,dest);
+ fstrcpy(msgfrom,orig);
+ fstrcpy(msgto,dest);
- DEBUG(3,("%s SMBsendstrt (from %s to %s)\n",timestring(),orig,dest));
+ DEBUG(3,("%s SMBsendstrt (from %s to %s)\n",timestring(),msgfrom,msgto));
return(outsize);
}
diff --git a/source/smbd/password.c b/source/smbd/password.c
index 87c1fef94c5..24ee52ed692 100644
--- a/source/smbd/password.c
+++ b/source/smbd/password.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Password and authentication handling
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1997
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,7 +20,10 @@
*/
#include "includes.h"
-#include "loadparm.h"
+
+#if (defined(NETGROUP) && defined (AUTOMOUNT))
+#include "rpcsvc/ypclnt.h"
+#endif
extern int DEBUGLEVEL;
extern int Protocol;
@@ -33,7 +36,6 @@ static char this_user[100]="";
static char this_salt[100]="";
static char this_crypted[100]="";
-#ifdef SMB_PASSWD
/* Data to do lanman1/2 password challenge. */
static unsigned char saved_challenge[8];
static BOOL challenge_sent=False;
@@ -43,18 +45,24 @@ Get the next challenge value - no repeats.
********************************************************************/
void generate_next_challenge(char *challenge)
{
- extern void E1(char *,char *,char *);
- static int counter = 0;
- struct timeval tval;
- int v1,v2;
- GetTimeOfDay(&tval);
- v1 = (counter++) + getpid() + tval.tv_sec;
- v2 = (counter++) * getpid() + tval.tv_usec;
- SIVAL(challenge,0,v1);
- SIVAL(challenge,4,v2);
- E1(challenge,"SAMBA",saved_challenge);
- memcpy(challenge,saved_challenge,8);
- challenge_sent = True;
+ unsigned char buf[16];
+ static int counter = 0;
+ struct timeval tval;
+ int v1,v2;
+
+ /* get a sort-of random number */
+ GetTimeOfDay(&tval);
+ v1 = (counter++) + getpid() + tval.tv_sec;
+ v2 = (counter++) * getpid() + tval.tv_usec;
+ SIVAL(challenge,0,v1);
+ SIVAL(challenge,4,v2);
+
+ /* mash it up with md4 */
+ mdfour(buf, (unsigned char *)challenge, 8);
+
+ memcpy(saved_challenge, buf, 8);
+ memcpy(challenge,buf,8);
+ challenge_sent = True;
}
/*******************************************************************
@@ -76,38 +84,23 @@ BOOL last_challenge(char *challenge)
memcpy(challenge,saved_challenge,8);
return(True);
}
-#endif
/* this holds info on user ids that are already validated for this VC */
static user_struct *validated_users = NULL;
static int num_validated_users = 0;
/****************************************************************************
-check if a uid has been validated, and return an index if it has. -1 if not
-****************************************************************************/
-int valid_uid(int uid)
-{
- int i;
- if (uid == -1) return(-1);
-
- for (i=0;i<num_validated_users;i++)
- if (validated_users[i].uid == uid)
- {
- DEBUG(3,("valid uid %d mapped to vuid %d (user=%s)\n",
- uid,i,validated_users[i].name));
- return(i);
- }
- return(-1);
-}
-
-/****************************************************************************
check if a uid has been validated, and return an pointer to the user_struct
-if it has. NULL if not
+if it has. NULL if not. vuid is biased by an offset. This allows us to
+tell random client vuid's (normally zero) from valid vuids.
****************************************************************************/
-user_struct *get_valid_user_struct(int uid)
+user_struct *get_valid_user_struct(uint16 vuid)
{
- int vuid = valid_uid(uid);
- if(vuid == -1 || validated_users[vuid].guest)
+ if (vuid == UID_FIELD_INVALID)
+ return NULL;
+ vuid -= VUID_OFFSET;
+ if ((vuid >= (uint16)num_validated_users) ||
+ (validated_users[vuid].uid == -1) || (validated_users[vuid].gid == -1))
return NULL;
return &validated_users[vuid];
}
@@ -115,75 +108,124 @@ user_struct *get_valid_user_struct(int uid)
/****************************************************************************
invalidate a uid
****************************************************************************/
-void invalidate_uid(int uid)
+void invalidate_vuid(uint16 vuid)
{
- int i;
- for (i=0;i<num_validated_users;i++)
- if (validated_users[i].uid == uid)
- {
- user_struct *vuser = &validated_users[i];
- vuser->uid = -1;
- vuser->gid = -1;
- vuser->user_ngroups = 0;
- if(vuser->user_groups &&
- (vuser->user_groups != (gid_t *)vuser->user_igroups))
- free(vuser->user_groups);
- vuser->user_groups = NULL;
- if(vuser->user_igroups)
- free(vuser->user_igroups);
- vuser->user_igroups = NULL;
- }
+ user_struct *vuser = get_valid_user_struct(vuid);
+
+ if (vuser == NULL) return;
+
+ vuser->uid = -1;
+ vuser->gid = -1;
+
+ vuser->n_sids = 0;
+
+ /* same number of igroups as groups as attrs */
+ vuser->n_groups = 0;
+
+ if (vuser->groups && (vuser->groups != (gid_t *)vuser->igroups))
+ free(vuser->groups);
+
+ if (vuser->igroups) free(vuser->igroups);
+ if (vuser->attrs ) free(vuser->attrs);
+ if (vuser->sids ) free(vuser->sids);
+
+ vuser->attrs = NULL;
+ vuser->sids = NULL;
+ vuser->igroups = NULL;
+ vuser->groups = NULL;
}
/****************************************************************************
return a validated username
****************************************************************************/
-char *validated_username(int vuid)
+char *validated_username(uint16 vuid)
{
- return(validated_users[vuid].name);
+ user_struct *vuser = get_valid_user_struct(vuid);
+ if (vuser == NULL)
+ return 0;
+ return(vuser->name);
}
/****************************************************************************
register a uid/name pair as being valid and that a valid password
-has been given.
+has been given. vuid is biased by an offset. This allows us to
+tell random client vuid's (normally zero) from valid vuids.
****************************************************************************/
-void register_uid(int uid,int gid, char *name,BOOL guest)
+uint16 register_vuid(int uid,int gid, char *name,BOOL guest)
{
user_struct *vuser;
+ struct passwd *pwfile; /* for getting real name from passwd file */
- if (valid_uid(uid) >= 0)
- return;
- validated_users = (user_struct *)Realloc(validated_users,
- sizeof(user_struct)*
- (num_validated_users+1));
+#if 0
+ /*
+ * After observing MS-Exchange services writing to a Samba share
+ * I belive this code is incorrect. Each service does its own
+ * sessionsetup_and_X for the same user, and as each service shuts
+ * down, it does a user_logoff_and_X. As we are consolidating multiple
+ * sessionsetup_and_X's onto the same vuid here, when the first service
+ * shuts down, it invalidates all the open files for the other services.
+ * Hence I am removing this code and forcing each sessionsetup_and_X
+ * to get a new vuid.
+ * Jeremy Allison. (jallison@whistle.com).
+ */
+
+ int i;
+ for(i = 0; i < num_validated_users; i++) {
+ vuser = &validated_users[i];
+ if ( vuser->uid == uid )
+ return (uint16)(i + VUID_OFFSET); /* User already validated */
+ }
+#endif
+ validated_users = (user_struct *)Realloc(validated_users,
+ sizeof(user_struct)*
+ (num_validated_users+1));
+
if (!validated_users)
{
DEBUG(0,("Failed to realloc users struct!\n"));
- return;
+ num_validated_users = 0;
+ return UID_FIELD_INVALID;
}
vuser = &validated_users[num_validated_users];
+ num_validated_users++;
+
vuser->uid = uid;
vuser->gid = gid;
vuser->guest = guest;
strcpy(vuser->name,name);
- vuser->user_ngroups = 0;
- vuser->user_groups = NULL;
- vuser->user_igroups = NULL;
+ vuser->n_sids = 0;
+ vuser->sids = NULL;
+
+ vuser->n_groups = 0;
+ vuser->groups = NULL;
+ vuser->igroups = NULL;
+ vuser->attrs = NULL;
/* Find all the groups this uid is in and store them.
Used by become_user() */
setup_groups(name,uid,gid,
- &vuser->user_ngroups,
- &vuser->user_igroups,
- &vuser->user_groups);
+ &vuser->n_groups,
+ &vuser->igroups,
+ &vuser->groups,
+ &vuser->attrs);
DEBUG(3,("uid %d registered to name %s\n",uid,name));
-
- num_validated_users++;
+
+ DEBUG(3, ("Clearing default real name\n"));
+ fstrcpy(vuser->real_name, "<Full Name>\0");
+ if (lp_unix_realname()) {
+ if ((pwfile=getpwnam(vuser->name))!= NULL)
+ {
+ DEBUG(3, ("User name: %s\tReal name: %s\n",vuser->name,pwfile->pw_gecos));
+ fstrcpy(vuser->real_name, pwfile->pw_gecos);
+ }
+ }
+
+ return (uint16)((num_validated_users - 1) + VUID_OFFSET);
}
@@ -287,15 +329,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 +344,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 )
{
@@ -320,6 +360,103 @@ static void update_protected_database( char *user, BOOL result)
}
+#ifdef USE_PAM
+/*******************************************************************
+check on PAM authentication
+********************************************************************/
+
+/* We first need some helper functions */
+#include <security/pam_appl.h>
+/* Static variables used to communicate between the conversation function
+ * and the server_login function
+ */
+static char *PAM_username;
+static char *PAM_password;
+
+/* PAM conversation function
+ * Here we assume (for now, at least) that echo on means login name, and
+ * echo off means password.
+ */
+static int PAM_conv (int num_msg,
+ struct pam_message **msg,
+ struct pam_response **resp,
+ void *appdata_ptr) {
+ int replies = 0;
+ struct pam_response *reply = NULL;
+
+ #define COPY_STRING(s) (s) ? strdup(s) : NULL
+
+ reply = malloc(sizeof(struct pam_response) * num_msg);
+ if (!reply) return PAM_CONV_ERR;
+
+ for (replies = 0; replies < num_msg; replies++) {
+ switch (msg[replies]->msg_style) {
+ case PAM_PROMPT_ECHO_ON:
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = COPY_STRING(PAM_username);
+ /* PAM frees resp */
+ break;
+ case PAM_PROMPT_ECHO_OFF:
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = COPY_STRING(PAM_password);
+ /* PAM frees resp */
+ break;
+ case PAM_TEXT_INFO:
+ /* fall through */
+ case PAM_ERROR_MSG:
+ /* ignore it... */
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = NULL;
+ break;
+ default:
+ /* Must be an error of some sort... */
+ free (reply);
+ return PAM_CONV_ERR;
+ }
+ }
+ if (reply) *resp = reply;
+ return PAM_SUCCESS;
+}
+static struct pam_conv PAM_conversation = {
+ &PAM_conv,
+ NULL
+};
+
+
+static BOOL pam_auth(char *this_user,char *password)
+{
+ pam_handle_t *pamh;
+ int pam_error;
+
+ /* Now use PAM to do authentication. For now, we won't worry about
+ * session logging, only authentication. Bail out if there are any
+ * errors. Since this is a limited protocol, and an even more limited
+ * function within a server speaking this protocol, we can't be as
+ * verbose as would otherwise make sense.
+ * Query: should we be using PAM_SILENT to shut PAM up?
+ */
+ #define PAM_BAIL if (pam_error != PAM_SUCCESS) { \
+ pam_end(pamh, 0); return False; \
+ }
+ PAM_password = password;
+ PAM_username = this_user;
+ pam_error = pam_start("samba", this_user, &PAM_conversation, &pamh);
+ PAM_BAIL;
+ pam_error = pam_authenticate(pamh, 0);
+ PAM_BAIL;
+ /* It is not clear to me that account management is the right thing
+ * to do, but it is not clear that it isn't, either. This can be
+ * removed if no account management should be done. Alternately,
+ * put a pam_allow.so entry in /etc/pam.conf for account handling. */
+ pam_error = pam_acct_mgmt(pamh, 0);
+ PAM_BAIL;
+ pam_end(pamh, PAM_SUCCESS);
+ /* If this point is reached, the user has been authenticated. */
+ return(True);
+}
+#endif
+
+
#ifdef AFS_AUTH
/*******************************************************************
check on AFS authentication
@@ -441,6 +578,86 @@ void dfs_unlogin(void)
#endif
+#ifdef KRB5_AUTH
+/*******************************************************************
+check on Kerberos authentication
+********************************************************************/
+static BOOL krb5_auth(char *this_user,char *password)
+{
+ krb5_data tgtname = {
+ 0,
+ KRB5_TGS_NAME_SIZE,
+ KRB5_TGS_NAME
+ };
+ krb5_context kcontext;
+ krb5_principal kprinc;
+ krb5_principal server;
+ krb5_creds kcreds;
+ int options = 0;
+ krb5_address **addrs = (krb5_address **)0;
+ krb5_preauthtype *preauth = NULL;
+ krb5_keytab keytab = NULL;
+ krb5_timestamp now;
+ krb5_ccache ccache = NULL;
+ int retval;
+ char *name;
+
+ if ( retval=krb5_init_context(&kcontext))
+ {
+ return(False);
+ }
+
+ if ( retval = krb5_timeofday(kcontext, &now) )
+ {
+ return(False);
+ }
+
+ if ( retval = krb5_cc_default(kcontext, &ccache) )
+ {
+ return(False);
+ }
+
+ if ( retval = krb5_parse_name(kcontext, this_user, &kprinc) )
+ {
+ return(False);
+ }
+
+ memset((char *)&kcreds, 0, sizeof(kcreds));
+
+ kcreds.client = kprinc;
+
+ if ((retval = krb5_build_principal_ext(kcontext, &server,
+ krb5_princ_realm(kcontext, kprinc)->length,
+ krb5_princ_realm(kcontext, kprinc)->data,
+ tgtname.length,
+ tgtname.data,
+ krb5_princ_realm(kcontext, kprinc)->length,
+ krb5_princ_realm(kcontext, kprinc)->data,
+ 0)))
+ {
+ return(False);
+ }
+
+ kcreds.server = server;
+
+ retval = krb5_get_in_tkt_with_password(kcontext,
+ options,
+ addrs,
+ NULL,
+ preauth,
+ password,
+ 0,
+ &kcreds,
+ 0);
+
+ if ( retval )
+ {
+ return(False);
+ }
+
+ return(True);
+}
+#endif /* KRB5_AUTH */
#ifdef LINUX_BIGCRYPT
/****************************************************************************
@@ -457,7 +674,7 @@ static int linux_bigcrypt(char *password,char *salt1, char *crypted)
for ( i=strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS) {
char * p = crypt(password,salt) + 2;
- if(strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0)
+ if (strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0)
return(0);
password += LINUX_PASSWORD_SEG_CHARS;
crypted += strlen(p);
@@ -521,6 +738,20 @@ core of password checking routine
****************************************************************************/
BOOL password_check(char *password)
{
+
+#ifdef USE_PAM
+/* This falls through if the password check fails
+ - if NO_CRYPT is defined this causes an error msg
+ saying Warning - no crypt available
+ - if NO_CRYPT is NOT defined this is a potential security hole
+ as it may authenticate via the crypt call when PAM
+ settings say it should fail.
+ if (pam_auth(this_user,password)) return(True);
+Hence we make a direct return to avoid a second chance!!!
+*/
+ return (pam_auth(this_user,password));
+#endif
+
#ifdef AFS_AUTH
if (afs_auth(this_user,password)) return(True);
#endif
@@ -529,6 +760,10 @@ BOOL password_check(char *password)
if (dfs_auth(this_user,password)) return(True);
#endif
+#ifdef KRB5_AUTH
+ if (krb5_auth(this_user,password)) return(True);
+#endif
+
#ifdef PWDAUTH
if (pwdauth(this_user,password) == 0)
return(True);
@@ -554,7 +789,6 @@ BOOL password_check(char *password)
#endif
}
-#ifdef SMB_PASSWD
/****************************************************************************
core of smb password checking routine.
****************************************************************************/
@@ -564,10 +798,10 @@ BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned cha
unsigned char p21[21];
unsigned char p24[24];
- if(part_passwd == NULL)
+ if (part_passwd == NULL)
DEBUG(10,("No password set - allowing access\n"));
/* No password set - always true ! */
- if(part_passwd == NULL)
+ if (part_passwd == NULL)
return 1;
memset(p21,'\0',21);
@@ -596,31 +830,25 @@ BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned cha
#endif
return (memcmp(p24, password, 24) == 0);
}
-#endif
/****************************************************************************
check if a username/password is OK
****************************************************************************/
-BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd, BOOL is_nt_password)
+BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd)
{
pstring pass2;
int level = lp_passwordlevel();
struct passwd *pass;
-#ifdef SMB_PASSWD
char challenge[8];
struct smb_passwd *smb_pass;
BOOL challenge_done = False;
-#endif
if (password) password[pwlen] = 0;
-#ifdef SMB_PASSWD
if (pwlen == 24)
challenge_done = last_challenge(challenge);
-#endif
#if DEBUG_PASSWORD
-#ifdef SMB_PASSWD
if (challenge_done)
{
int i;
@@ -628,10 +856,9 @@ BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd, BOOL
for( i = 0; i < 24; i++)
DEBUG(100,("%0x ", (unsigned char)password[i]));
DEBUG(100,("]\n"));
+ } else {
+ DEBUG(100,("checking user=[%s] pass=[%s]\n",user,password));
}
- else
-#endif
- DEBUG(100,("checking user=[%s] pass=[%s]\n",user,password));
#endif
if (!password)
@@ -648,11 +875,9 @@ BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd, BOOL
else
pass = Get_Pwnam(user,True);
-#ifdef SMB_PASSWD
-
DEBUG(4,("SMB Password - pwlen = %d, challenge_done = %d\n", pwlen, challenge_done));
- if((pwlen == 24) && challenge_done)
+ if ((pwlen == 24) && challenge_done)
{
DEBUG(4,("Checking SMB password for user %s (l=24)\n",user));
@@ -663,48 +888,49 @@ BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd, BOOL
}
smb_pass = get_smbpwnam(user);
- if(!smb_pass)
+ if (!smb_pass)
{
DEBUG(3,("Couldn't find user %s in smb_passwd file.\n", user));
return(False);
}
/* Ensure the uid's match */
- if(smb_pass->smb_userid != pass->pw_uid)
+ if (smb_pass->smb_userid != pass->pw_uid)
{
DEBUG(3,("Error : UNIX and SMB uids in password files do not match !\n"));
return(False);
}
- if(Protocol >= PROTOCOL_NT1 && is_nt_password)
+ if (Protocol >= PROTOCOL_NT1)
{
/* We have the NT MD4 hash challenge available - see if we can
use it (ie. does it exist in the smbpasswd file).
*/
- if(smb_pass->smb_nt_passwd != NULL)
+ 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,
+ (unsigned char *)challenge))
{
update_protected_database(user,True);
return(True);
}
DEBUG(4,("NT MD4 password check failed\n"));
- return (False);
}
}
/* 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,
+ (unsigned char *)challenge)) {
+ update_protected_database(user,True);
+ return(True);
+ }
DEBUG(3,("Error smb_password_check failed\n"));
}
-#endif
DEBUG(4,("Checking password for user %s (l=%d)\n",user,pwlen));
@@ -727,6 +953,15 @@ BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd, BOOL
if (spass && spass->sp_pwdp)
pass->pw_passwd = spass->sp_pwdp;
}
+#elif defined(IA_UINFO)
+ {
+ /* Need to get password with SVR4.2's ia_ functions instead of
+ get{sp,pw}ent functions. Required by UnixWare 2.x, tested on
+ version 2.1. (tangent@cyberport.com) */
+ uinfo_t uinfo;
+ if (ia_openinfo(pass->pw_name, &uinfo) != -1)
+ ia_get_logpwd(uinfo, &(pass->pw_passwd));
+ }
#endif
#ifdef SecureWare
@@ -777,6 +1012,7 @@ BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd, BOOL
/* extract relevant info */
strcpy(this_user,pass->pw_name);
strcpy(this_salt,pass->pw_passwd);
+ this_salt[2] = 0;
strcpy(this_crypted,pass->pw_passwd);
if (!*this_crypted) {
@@ -817,7 +1053,7 @@ BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd, BOOL
}
/* give up? */
- if(level < 1)
+ if (level < 1)
{
update_protected_database(user,False);
@@ -889,7 +1125,7 @@ static char *validate_group(char *group,char *password,int pwlen,int snum)
while (getnetgrent(&host, &user, &domain)) {
if (user) {
if (user_ok(user, snum) &&
- password_ok(user,password,pwlen,NULL,False)) {
+ password_ok(user,password,pwlen,NULL)) {
endnetgrent();
return(user);
}
@@ -911,7 +1147,7 @@ static char *validate_group(char *group,char *password,int pwlen,int snum)
static fstring name;
strcpy(name,*member);
if (user_ok(name,snum) &&
- password_ok(name,password,pwlen,NULL,False))
+ password_ok(name,password,pwlen,NULL))
return(&name[0]);
member++;
}
@@ -924,7 +1160,7 @@ static char *validate_group(char *group,char *password,int pwlen,int snum)
while (pwd = getpwent ()) {
if (*(pwd->pw_passwd) && pwd->pw_gid == gptr->gr_gid) {
/* This Entry have PASSWORD and same GID then check pwd */
- if (password_ok(NULL, password, pwlen, pwd,False)) {
+ if (password_ok(NULL, password, pwlen, pwd)) {
strcpy(tm, pwd->pw_name);
endpwent ();
return tm;
@@ -946,7 +1182,7 @@ static char *validate_group(char *group,char *password,int pwlen,int snum)
check for authority to login to a service with a given username/password
****************************************************************************/
BOOL authorise_login(int snum,char *user,char *password, int pwlen,
- BOOL *guest,BOOL *force,int vuid)
+ BOOL *guest,BOOL *force,uint16 vuid)
{
BOOL ok = False;
@@ -956,7 +1192,7 @@ BOOL authorise_login(int snum,char *user,char *password, int pwlen,
DEBUG(100,("checking authorisation on user=%s pass=%s\n",user,password));
#endif
- /* there are several possabilities:
+ /* there are several possibilities:
1) login as the given user with given password
2) login as a previously registered username with the given password
3) login as a session list username with the given password
@@ -973,18 +1209,20 @@ BOOL authorise_login(int snum,char *user,char *password, int pwlen,
if (!(GUEST_ONLY(snum) && GUEST_OK(snum)))
{
+ user_struct *vuser = get_valid_user_struct(vuid);
+
/* check the given username and password */
if (!ok && (*user) && user_ok(user,snum)) {
- ok = password_ok(user,password, pwlen, NULL, False);
+ ok = password_ok(user,password, pwlen, NULL);
if (ok) DEBUG(3,("ACCEPTED: given username password ok\n"));
}
/* check for a previously registered guest username */
- if (!ok && (vuid >= 0) && validated_users[vuid].guest) {
- if (user_ok(validated_users[vuid].name,snum) &&
- password_ok(validated_users[vuid].name, password, pwlen, NULL, False)) {
- strcpy(user, validated_users[vuid].name);
- validated_users[vuid].guest = False;
+ if (!ok && (vuser != 0) && vuser->guest) {
+ if (user_ok(vuser->name,snum) &&
+ password_ok(vuser->name, password, pwlen, NULL)) {
+ strcpy(user, vuser->name);
+ vuser->guest = False;
DEBUG(3,("ACCEPTED: given password with registered user %s\n", user));
ok = True;
}
@@ -1006,7 +1244,7 @@ BOOL authorise_login(int snum,char *user,char *password, int pwlen,
strcpy(user2,auser);
if (!user_ok(user2,snum)) continue;
- if (password_ok(user2,password, pwlen, NULL, False)) {
+ if (password_ok(user2,password, pwlen, NULL)) {
ok = True;
strcpy(user,user2);
DEBUG(3,("ACCEPTED: session list username and given password ok\n"));
@@ -1017,9 +1255,9 @@ BOOL authorise_login(int snum,char *user,char *password, int pwlen,
/* check for a previously validated username/password pair */
if (!ok && !lp_revalidate(snum) &&
- (vuid >= 0) && !validated_users[vuid].guest &&
- user_ok(validated_users[vuid].name,snum)) {
- strcpy(user,validated_users[vuid].name);
+ (vuser != 0) && !vuser->guest &&
+ user_ok(vuser->name,snum)) {
+ strcpy(user,vuser->name);
*guest = False;
DEBUG(3,("ACCEPTED: validated uid ok as non-guest\n"));
ok = True;
@@ -1058,7 +1296,7 @@ BOOL authorise_login(int snum,char *user,char *password, int pwlen,
fstring user2;
strcpy(user2,auser);
if (user_ok(user2,snum) &&
- password_ok(user2,password,pwlen,NULL, False))
+ password_ok(user2,password,pwlen,NULL))
{
ok = True;
strcpy(user,user2);
@@ -1147,19 +1385,19 @@ static BOOL check_user_equiv(char *user, char *remote, char *equiv_file)
}
file_host = strtok(bp, " \t\n");
file_user = strtok(NULL, " \t\n");
- DEBUG(7, ("check_user_equiv %s %s\n", file_host, file_user));
+ DEBUG(7, ("check_user_equiv %s %s\n", file_host ? file_host : "(null)",
+ file_user ? file_user : "(null)" ));
if (file_host && *file_host)
{
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
@@ -1210,20 +1448,15 @@ BOOL check_hosts_equiv(char *user)
pstring rhostsfile;
struct passwd *pass = Get_Pwnam(user,True);
- extern struct from_host Client_info;
- extern int Client;
-
if (!pass)
return(False);
- fromhost(Client,&Client_info);
-
fname = lp_hosts_equiv();
/* note: don't allow hosts.equiv on root */
if (fname && *fname && (pass->pw_uid != 0))
{
- if (check_user_equiv(user,Client_info.name,fname))
+ if (check_user_equiv(user,client_name(),fname))
return(True);
}
@@ -1233,7 +1466,7 @@ BOOL check_hosts_equiv(char *user)
if (home)
{
sprintf(rhostsfile, "%s/.rhosts", home);
- if (check_user_equiv(user,Client_info.name,rhostsfile))
+ if (check_user_equiv(user,client_name(),rhostsfile))
return(True);
}
}
@@ -1242,175 +1475,143 @@ BOOL check_hosts_equiv(char *user)
}
-static int password_client = -1;
-static fstring pserver;
+static struct cli_state cli;
/****************************************************************************
-attempted support for server level security
+return the client state structure
****************************************************************************/
-BOOL server_cryptkey(char *buf)
+struct cli_state *server_client(void)
{
- pstring inbuf,outbuf;
- fstring pass_protocol;
- extern fstring remote_machine;
- char *p;
- int len;
- fstring desthost;
- struct in_addr dest_ip;
- extern struct in_addr myip;
- int port = 139;
- BOOL ret;
-
- if (password_client >= 0)
- close(password_client);
- password_client = -1;
-
- if (Protocol < PROTOCOL_NT1) {
- strcpy(pass_protocol,"LM1.2X002");
- } else {
- strcpy(pass_protocol,"NT LM 0.12");
- }
-
- bzero(inbuf,sizeof(inbuf));
- bzero(outbuf,sizeof(outbuf));
-
- for (p=strtok(lp_passwordserver(),LIST_SEP); p ; p = strtok(NULL,LIST_SEP)) {
- strcpy(desthost,p);
- standard_sub_basic(desthost);
- strupper(desthost);
-
- dest_ip = *interpret_addr2(desthost);
- if (zero_ip(dest_ip)) {
- DEBUG(1,("Can't resolve address for %s\n",p));
- continue;
- }
-
- if (memcmp(&dest_ip,&myip,sizeof(dest_ip)) == 0) {
- DEBUG(1,("Password server loop - disabling password server %s\n",p));
- continue;
- }
-
- password_client = open_socket_out(SOCK_STREAM, &dest_ip, port);
- if (password_client >= 0) {
- DEBUG(3,("connected to password server %s\n",p));
- StrnCpy(pserver,p,sizeof(pserver)-1);
- break;
- }
- }
-
- if (password_client < 0) {
- DEBUG(1,("password server not available\n"));
- return(False);
- }
-
-
- /* send a session request (RFC 8002) */
-
- /* put in the destination name */
- len = 4;
- p = outbuf+len;
- name_mangle(desthost,p,' ');
- len += name_len(p);
-
- /* and my name */
- p = outbuf+len;
- name_mangle(remote_machine,p,' ');
- len += name_len(p);
-
- _smb_setlen(outbuf,len);
- CVAL(outbuf,0) = 0x81;
-
- send_smb(password_client,outbuf);
- receive_smb(password_client,inbuf,5000);
-
- if (CVAL(inbuf,0) != 0x82) {
- DEBUG(1,("%s rejected the session\n",pserver));
- close(password_client); password_client = -1;
- return(False);
- }
+ return &cli;
+}
- DEBUG(3,("got session\n"));
+/****************************************************************************
+support for server level security
+****************************************************************************/
+struct cli_state *server_cryptkey(void)
+{
+ fstring desthost;
+ struct in_addr dest_ip;
+ extern fstring local_machine;
+ char *p;
+
+ if (!cli_initialise(&cli))
+ return NULL;
+
+ for (p=strtok(lp_passwordserver(),LIST_SEP); p ; p = strtok(NULL,LIST_SEP)) {
+ fstrcpy(desthost,p);
+ standard_sub_basic(desthost);
+ strupper(desthost);
+
+ dest_ip = *interpret_addr2(desthost);
+ if (zero_ip(dest_ip)) {
+ DEBUG(1,("Can't resolve address for %s\n",p));
+ continue;
+ }
- bzero(outbuf,smb_size);
+ if (ismyip(dest_ip)) {
+ DEBUG(1,("Password server loop - disabling password server %s\n",p));
+ continue;
+ }
- /* setup the protocol string */
- set_message(outbuf,0,strlen(pass_protocol)+2,True);
- p = smb_buf(outbuf);
- *p++ = 2;
- strcpy(p,pass_protocol);
+ if (cli_connect(&cli, desthost, &dest_ip)) {
+ DEBUG(3,("connected to password server %s\n",p));
+ break;
+ }
+ }
- CVAL(outbuf,smb_com) = SMBnegprot;
- CVAL(outbuf,smb_flg) = 0x8;
- SSVAL(outbuf,smb_flg2,0x1);
+ if (!p) {
+ DEBUG(1,("password server not available\n"));
+ cli_shutdown(&cli);
+ return NULL;
+ }
- send_smb(password_client,outbuf);
- ret = receive_smb(password_client,inbuf,5000);
+ if (!cli_session_request(&cli, desthost, 0x20, local_machine)) {
+ DEBUG(1,("%s rejected the session\n",desthost));
+ cli_shutdown(&cli);
+ return NULL;
+ }
- if (!ret || CVAL(inbuf,smb_rcls) || SVAL(inbuf,smb_vwv0)) {
- DEBUG(1,("%s rejected the protocol\n",pserver));
- close(password_client); password_client= -1;
- return(False);
- }
+ DEBUG(3,("got session\n"));
- if (!(CVAL(inbuf,smb_vwv1) & 1)) {
- DEBUG(1,("%s isn't in user level security mode\n",pserver));
- close(password_client); password_client= -1;
- return(False);
- }
+ if (!cli_negprot(&cli)) {
+ DEBUG(1,("%s rejected the negprot\n",desthost));
+ cli_shutdown(&cli);
+ return NULL;
+ }
- memcpy(buf,inbuf,smb_len(inbuf)+4);
+ if (cli.protocol < PROTOCOL_LANMAN2 ||
+ !(cli.sec_mode & 1)) {
+ DEBUG(1,("%s isn't in user level security mode\n",desthost));
+ cli_shutdown(&cli);
+ return NULL;
+ }
- DEBUG(3,("password server OK\n"));
+ DEBUG(3,("password server OK\n"));
- return(True);
+ return &cli;
}
/****************************************************************************
-attempted support for server level security
+validate a password with the password server
****************************************************************************/
-BOOL server_validate(char *buf)
+BOOL server_validate(char *user, char *domain,
+ char *pass, int passlen,
+ char *ntpass, int ntpasslen)
{
- pstring inbuf,outbuf;
- BOOL ret;
+ extern fstring local_machine;
+ fstring share;
- if (password_client < 0) {
- DEBUG(1,("%s not connected\n",pserver));
- return(False);
- }
+ if (!cli.initialised) {
+ DEBUG(1,("password server %s is not connected\n", cli.desthost));
+ return(False);
+ }
- bzero(inbuf,sizeof(inbuf));
- memcpy(outbuf,buf,sizeof(outbuf));
+ if (!cli_session_setup(&cli, user, pass, passlen, ntpass, ntpasslen, domain)) {
+ DEBUG(1,("password server %s rejected the password\n", cli.desthost));
+ return False;
+ }
- /* send a session setup command */
- CVAL(outbuf,smb_flg) = 0x8;
- SSVAL(outbuf,smb_flg2,0x1);
- CVAL(outbuf,smb_vwv0) = 0xFF;
+ /* if logged in as guest then reject */
+ if ((SVAL(cli.inbuf,smb_vwv2) & 1) != 0) {
+ DEBUG(1,("password server %s gave us guest only\n", cli.desthost));
+ return(False);
+ }
- set_message(outbuf,smb_numwords(outbuf),smb_buflen(outbuf),False);
- SCVAL(inbuf,smb_rcls,1);
+ sprintf(share,"\\\\%s\\IPC$", cli.desthost);
- send_smb(password_client,outbuf);
- ret = receive_smb(password_client,inbuf,5000);
+ if (!cli_send_tconX(&cli, share, "IPC", "", 1)) {
+ DEBUG(1,("password server %s refused IPC$ connect\n", cli.desthost));
+ return False;
+ }
- if (!ret || CVAL(inbuf,smb_rcls) != 0) {
- DEBUG(1,("password server %s rejected the password\n",pserver));
- return(False);
- }
- /* if logged in as guest then reject */
- if ((SVAL(inbuf,smb_vwv2) & 1) != 0) {
- DEBUG(1,("password server %s gave us guest only\n",pserver));
- return(False);
- }
+ if (!cli_NetWkstaUserLogon(&cli,user,local_machine)) {
+ DEBUG(1,("password server %s failed NetWkstaUserLogon\n", cli.desthost));
+ cli_tdis(&cli);
+ return False;
+ }
- DEBUG(3,("password server %s accepted the password\n",pserver));
+ if (cli.privilages == 0) {
+ DEBUG(1,("password server %s gave guest privilages\n", cli.desthost));
+ cli_tdis(&cli);
+ return False;
+ }
-#ifndef KEEP_PASSWORD_SERVER_OPEN
- close(password_client); password_client= -1;
-#endif
+ if (!strequal(cli.eff_name, user)) {
+ DEBUG(1,("password server %s gave different username %s\n",
+ cli.desthost,
+ cli.eff_name));
+ cli_tdis(&cli);
+ return False;
+ }
- return(True);
+ DEBUG(3,("password server %s accepted the password\n", cli.desthost));
+
+ cli_tdis(&cli);
+
+ return(True);
}
diff --git a/source/smbd/pipes.c b/source/smbd/pipes.c
new file mode 100644
index 00000000000..901d7e682ab
--- /dev/null
+++ b/source/smbd/pipes.c
@@ -0,0 +1,366 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Pipe SMB reply routines
+ Copyright (C) Andrew Tridgell 1992-1997,
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997.
+ Copyright (C) Paul Ashton 1997.
+
+ 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 file handles reply_ calls on named pipes that the server
+ makes to handle specific protocols
+*/
+
+
+#include "includes.h"
+#include "trans2.h"
+
+#define PIPE "\\PIPE\\"
+#define PIPELEN strlen(PIPE)
+
+#define REALLOC(ptr,size) Realloc(ptr,MAX((size),4*1024))
+
+/* look in server.c for some explanation of these variables */
+extern int Protocol;
+extern int DEBUGLEVEL;
+extern int chain_fnum;
+extern char magic_char;
+extern connection_struct Connections[];
+extern files_struct Files[];
+extern BOOL case_sensitive;
+extern pstring sesssetup_user;
+extern int Client;
+extern fstring myworkgroup;
+
+/* this macro should always be used to extract an fnum (smb_fid) from
+a packet to ensure chaining works correctly */
+#define GETFNUM(buf,where) (chain_fnum!= -1?chain_fnum:SVAL(buf,where))
+
+char * known_pipes [] =
+{
+ "lsarpc",
+#if NTDOMAIN
+ "NETLOGON",
+ "srvsvc",
+#endif
+ NULL
+};
+
+/****************************************************************************
+ reply to an open and X on a named pipe
+
+ In fact what we do is to open a regular file with the same name in
+ /tmp. This can then be closed as normal. Reading and writing won't
+ make much sense, but will do *something*. The real reason for this
+ support is to be able to do transactions on them (well, on lsarpc
+ for domain login purposes...).
+
+ This code is basically stolen from reply_open_and_X with some
+ wrinkles to handle pipes.
+****************************************************************************/
+int reply_open_pipe_and_X(char *inbuf,char *outbuf,int length,int bufsize)
+{
+ pstring fname;
+ int cnum = SVAL(inbuf,smb_tid);
+ int fnum = -1;
+ int smb_mode = SVAL(inbuf,smb_vwv3);
+ int smb_attr = SVAL(inbuf,smb_vwv5);
+#if 0
+ int open_flags = SVAL(inbuf,smb_vwv2);
+ int smb_sattr = SVAL(inbuf,smb_vwv4);
+ uint32 smb_time = make_unix_date3(inbuf+smb_vwv6);
+#endif
+ int smb_ofun = SVAL(inbuf,smb_vwv8);
+ int unixmode;
+ int size=0,fmode=0,mtime=0,rmode=0;
+ struct stat sbuf;
+ int smb_action = 0;
+ int i;
+ BOOL bad_path = False;
+
+ /* XXXX we need to handle passed times, sattr and flags */
+ pstrcpy(fname,smb_buf(inbuf));
+
+ /* If the name doesn't start \PIPE\ then this is directed */
+ /* at a mailslot or something we really, really don't understand, */
+ /* not just something we really don't understand. */
+ if ( strncmp(fname,PIPE,PIPELEN) != 0 )
+ return(ERROR(ERRSRV,ERRaccess));
+
+ DEBUG(4,("Opening pipe %s.\n", fname));
+
+ /* Strip \PIPE\ off the name. */
+ pstrcpy(fname,smb_buf(inbuf) + PIPELEN);
+
+ /* See if it is one we want to handle. */
+ for( i = 0; known_pipes[i] ; i++ )
+ if( strcmp(fname,known_pipes[i]) == 0 )
+ break;
+
+ if ( known_pipes[i] == NULL )
+ return(ERROR(ERRSRV,ERRaccess));
+
+ /* Known pipes arrive with DIR attribs. Remove it so a regular file */
+ /* can be opened and add it in after the open. */
+ DEBUG(3,("Known pipe %s opening.\n",fname));
+ smb_attr &= ~aDIR;
+ Connections[cnum].read_only = 0;
+ smb_ofun |= 0x10; /* Add Create it not exists flag */
+
+ unix_convert(fname,cnum,0,&bad_path);
+
+ fnum = find_free_file();
+ if (fnum < 0)
+ return(ERROR(ERRSRV,ERRnofids));
+
+ if (!check_name(fname,cnum))
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+
+ unixmode = unix_mode(cnum,smb_attr);
+
+ open_file_shared(fnum,cnum,fname,smb_mode,smb_ofun,unixmode,
+ 0, &rmode,&smb_action);
+
+ if (!Files[fnum].open)
+ {
+ /* Change the error code if bad_path was set. */
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+
+ if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) {
+ close_file(fnum,False);
+ return(ERROR(ERRDOS,ERRnoaccess));
+ }
+
+ size = sbuf.st_size;
+ fmode = dos_mode(cnum,fname,&sbuf);
+ mtime = sbuf.st_mtime;
+ if (fmode & aDIR) {
+ close_file(fnum,False);
+ return(ERROR(ERRDOS,ERRnoaccess));
+ }
+
+ /* Prepare the reply */
+ set_message(outbuf,15,0,True);
+
+ /* Put things back the way they were. */
+ Connections[cnum].read_only = 1;
+
+ /* Mark the opened file as an existing named pipe in message mode. */
+ SSVAL(outbuf,smb_vwv9,2);
+ SSVAL(outbuf,smb_vwv10,0xc700);
+ if (rmode == 2)
+ {
+ DEBUG(4,("Resetting open result to open from create.\n"));
+ rmode = 1;
+ }
+
+ SSVAL(outbuf,smb_vwv2,fnum);
+ SSVAL(outbuf,smb_vwv3,fmode);
+ put_dos_date3(outbuf,smb_vwv4,mtime);
+ SIVAL(outbuf,smb_vwv6,size);
+ SSVAL(outbuf,smb_vwv8,rmode);
+ SSVAL(outbuf,smb_vwv11,smb_action);
+
+ chain_fnum = fnum;
+
+ DEBUG(4,("Opened pipe %s with handle %d, saved name %s.\n",
+ fname, fnum, Files[fnum].name));
+
+ return chain_reply(inbuf,outbuf,length,bufsize);
+}
+
+
+/****************************************************************************
+ api_LsarpcSNPHS
+
+ SetNamedPipeHandleState on \PIPE\lsarpc. We can't really do much here,
+ so just blithely return True. This is really only for NT domain stuff,
+ we we're only handling that - don't assume Samba now does complete
+ named pipe handling.
+****************************************************************************/
+BOOL api_LsarpcSNPHS(int cnum,int uid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ uint16 id;
+
+ id = param[0] + (param[1] << 8);
+ DEBUG(4,("lsarpc SetNamedPipeHandleState to code %x\n",id));
+ return(True);
+}
+
+
+/****************************************************************************
+ api_LsarpcTNP
+
+ TransactNamedPipe on \PIPE\lsarpc.
+****************************************************************************/
+static void LsarpcTNP1(char *data,char **rdata, int *rdata_len)
+{
+ uint32 dword1, dword2;
+ char pname[] = "\\PIPE\\lsass";
+
+ /* All kinds of mysterious numbers here */
+ *rdata_len = 68;
+ *rdata = REALLOC(*rdata,*rdata_len);
+
+ dword1 = IVAL(data,0xC);
+ dword2 = IVAL(data,0x10);
+
+ SIVAL(*rdata,0,0xc0005);
+ SIVAL(*rdata,4,0x10);
+ SIVAL(*rdata,8,0x44);
+ SIVAL(*rdata,0xC,dword1);
+
+ SIVAL(*rdata,0x10,dword2);
+ SIVAL(*rdata,0x14,0x15);
+ SSVAL(*rdata,0x18,sizeof(pname));
+ strcpy(*rdata + 0x1a,pname);
+ SIVAL(*rdata,0x28,1);
+ memcpy(*rdata + 0x30, data + 0x34, 0x14);
+}
+
+static void LsarpcTNP2(char *data,char **rdata, int *rdata_len)
+{
+ uint32 dword1;
+
+ /* All kinds of mysterious numbers here */
+ *rdata_len = 48;
+ *rdata = REALLOC(*rdata,*rdata_len);
+
+ dword1 = IVAL(data,0xC);
+
+ SIVAL(*rdata,0,0x03020005);
+ SIVAL(*rdata,4,0x10);
+ SIVAL(*rdata,8,0x30);
+ SIVAL(*rdata,0xC,dword1);
+ SIVAL(*rdata,0x10,0x18);
+ SIVAL(*rdata,0x1c,0x44332211);
+ SIVAL(*rdata,0x20,0x88776655);
+ SIVAL(*rdata,0x24,0xCCBBAA99);
+ SIVAL(*rdata,0x28,0x11FFEEDD);
+}
+
+static void LsarpcTNP3(char *data,char **rdata, int *rdata_len)
+{
+ uint32 dword1;
+ uint16 word1;
+ char * workgroup = myworkgroup;
+ int wglen = strlen(workgroup);
+ int i;
+
+ /* All kinds of mysterious numbers here */
+ *rdata_len = 90 + 2 * wglen;
+ *rdata = REALLOC(*rdata,*rdata_len);
+
+ dword1 = IVAL(data,0xC);
+ word1 = SVAL(data,0x2C);
+
+ SIVAL(*rdata,0,0x03020005);
+ SIVAL(*rdata,4,0x10);
+ SIVAL(*rdata,8,0x60);
+ SIVAL(*rdata,0xC,dword1);
+ SIVAL(*rdata,0x10,0x48);
+ SSVAL(*rdata,0x18,0x5988); /* This changes */
+ SSVAL(*rdata,0x1A,0x15);
+ SSVAL(*rdata,0x1C,word1);
+ SSVAL(*rdata,0x20,6);
+ SSVAL(*rdata,0x22,8);
+ SSVAL(*rdata,0x24,0x8E8); /* So does this */
+ SSVAL(*rdata,0x26,0x15);
+ SSVAL(*rdata,0x28,0x4D48); /* And this */
+ SSVAL(*rdata,0x2A,0x15);
+ SIVAL(*rdata,0x2C,4);
+ SIVAL(*rdata,0x34,wglen);
+ for ( i = 0 ; i < wglen ; i++ )
+ (*rdata)[0x38 + i * 2] = workgroup[i];
+
+ /* Now fill in the rest */
+ i = 0x38 + wglen * 2;
+ SSVAL(*rdata,i,0x648);
+ SIVAL(*rdata,i+2,4);
+ SIVAL(*rdata,i+6,0x401);
+ SSVAL(*rdata,i+0xC,0x500);
+ SIVAL(*rdata,i+0xE,0x15);
+ SIVAL(*rdata,i+0x12,0x2372FE1);
+ SIVAL(*rdata,i+0x16,0x7E831BEF);
+ SIVAL(*rdata,i+0x1A,0x4B454B2);
+}
+
+static void LsarpcTNP4(char *data,char **rdata, int *rdata_len)
+{
+ uint32 dword1;
+
+ /* All kinds of mysterious numbers here */
+ *rdata_len = 48;
+ *rdata = REALLOC(*rdata,*rdata_len);
+
+ dword1 = IVAL(data,0xC);
+
+ SIVAL(*rdata,0,0x03020005);
+ SIVAL(*rdata,4,0x10);
+ SIVAL(*rdata,8,0x30);
+ SIVAL(*rdata,0xC,dword1);
+ SIVAL(*rdata,0x10,0x18);
+}
+
+
+BOOL api_LsarpcTNP(int cnum,int uid, char *param,char *data,
+ int mdrcnt,int mprcnt,
+ char **rdata,char **rparam,
+ int *rdata_len,int *rparam_len)
+{
+ uint32 id,id2;
+
+ id = IVAL(data,0);
+
+ DEBUG(4,("lsarpc TransactNamedPipe id %lx\n",id));
+ switch (id)
+ {
+ case 0xb0005:
+ LsarpcTNP1(data,rdata,rdata_len);
+ break;
+
+ case 0x03000005:
+ id2 = IVAL(data,8);
+ DEBUG(4,("\t- Suboperation %lx\n",id2));
+ switch (id2 & 0xF)
+ {
+ case 8:
+ LsarpcTNP2(data,rdata,rdata_len);
+ break;
+
+ case 0xC:
+ LsarpcTNP4(data,rdata,rdata_len);
+ break;
+
+ case 0xE:
+ LsarpcTNP3(data,rdata,rdata_len);
+ break;
+ }
+ break;
+ }
+ return(True);
+}
+
diff --git a/source/smbd/predict.c b/source/smbd/predict.c
new file mode 100644
index 00000000000..f5f0a2102e3
--- /dev/null
+++ b/source/smbd/predict.c
@@ -0,0 +1,162 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ file read prediction routines
+ Copyright (C) Andrew Tridgell 1992-1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+#if USE_READ_PREDICTION
+
+/* variables used by the read prediction module */
+static int rp_fd = -1;
+static int rp_offset = 0;
+static int rp_length = 0;
+static int rp_alloced = 0;
+static int rp_predict_fd = -1;
+static int rp_predict_offset = 0;
+static int rp_predict_length = 0;
+static int rp_timeout = 5;
+static time_t rp_time = 0;
+static char *rp_buffer = NULL;
+static BOOL predict_skip=False;
+extern time_t smb_last_time;
+
+/****************************************************************************
+handle read prediction on a file
+****************************************************************************/
+int read_predict(int fd,int offset,char *buf,char **ptr,int num)
+{
+ int ret = 0;
+ int possible = rp_length - (offset - rp_offset);
+
+ possible = MIN(possible,num);
+
+ /* give data if possible */
+ if (fd == rp_fd &&
+ offset >= rp_offset &&
+ possible>0 &&
+ smb_last_time-rp_time < rp_timeout)
+ {
+ ret = possible;
+ if (buf)
+ memcpy(buf,rp_buffer + (offset-rp_offset),possible);
+ else
+ *ptr = rp_buffer + (offset-rp_offset);
+ DEBUG(5,("read-prediction gave %d bytes of %d\n",ret,num));
+ }
+
+ if (ret == num) {
+ predict_skip = True;
+ } else {
+ struct stat rp_stat;
+
+ /* Find the end of the file - ensure we don't
+ read predict beyond it. */
+ if(fstat(fd,&rp_stat) < 0)
+ {
+ DEBUG(0,("read-prediction failed on fstat. Error was %s\n", strerror(errno)));
+ predict_skip = True;
+ }
+ else
+ {
+ predict_skip = False;
+
+ /* prepare the next prediction */
+ rp_predict_fd = fd;
+ /* Make sure we don't seek beyond the end of the file. */
+ rp_predict_offset = MIN((offset + num),rp_stat.st_size);
+ rp_predict_length = num;
+ }
+ }
+
+ if (ret < 0) ret = 0;
+
+ return(ret);
+}
+
+/****************************************************************************
+pre-read some data
+****************************************************************************/
+void do_read_prediction()
+{
+ static int readsize = 0;
+
+ if (predict_skip) return;
+
+ if (rp_predict_fd == -1)
+ return;
+
+ rp_fd = rp_predict_fd;
+ rp_offset = rp_predict_offset;
+ rp_length = 0;
+
+ rp_predict_fd = -1;
+
+ if (readsize == 0) {
+ readsize = lp_readsize();
+ readsize = MAX(readsize,1024);
+ }
+
+ rp_predict_length = MIN(rp_predict_length,2*readsize);
+ rp_predict_length = MAX(rp_predict_length,1024);
+ rp_offset = (rp_offset/1024)*1024;
+ rp_predict_length = (rp_predict_length/1024)*1024;
+
+ if (rp_predict_length > rp_alloced)
+ {
+ rp_buffer = Realloc(rp_buffer,rp_predict_length);
+ rp_alloced = rp_predict_length;
+ if (!rp_buffer)
+ {
+ DEBUG(0,("can't allocate read-prediction buffer\n"));
+ rp_predict_fd = -1;
+ rp_fd = -1;
+ rp_alloced = 0;
+ return;
+ }
+ }
+
+ if (lseek(rp_fd,rp_offset,SEEK_SET) != rp_offset) {
+ rp_fd = -1;
+ rp_predict_fd = -1;
+ return;
+ }
+
+ rp_length = read(rp_fd,rp_buffer,rp_predict_length);
+ rp_time = time(NULL);
+ if (rp_length < 0)
+ rp_length = 0;
+}
+
+/****************************************************************************
+invalidate read-prediction on a fd
+****************************************************************************/
+void invalidate_read_prediction(int fd)
+{
+ if (rp_fd == fd)
+ rp_fd = -1;
+ if (rp_predict_fd == fd)
+ rp_predict_fd = -1;
+}
+
+#else
+ void read_prediction_dummy(void) ;
+#endif
diff --git a/source/smbd/quotas.c b/source/smbd/quotas.c
new file mode 100644
index 00000000000..8810bcd909d
--- /dev/null
+++ b/source/smbd/quotas.c
@@ -0,0 +1,657 @@
+#ifdef QUOTAS
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ support for quotas
+ Copyright (C) Andrew Tridgell 1992-1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+/*
+ * This is one of the most system dependent parts of Samba, and its
+ * done a litle differently. Each system has its own way of doing
+ * things :-(
+ */
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+#ifdef LINUX
+
+#include <sys/types.h>
+#include <asm/types.h>
+#include <sys/quota.h>
+
+#include <mntent.h>
+#include <linux/unistd.h>
+
+_syscall4(int, quotactl, int, cmd, const char *, special, int, id, caddr_t, addr);
+
+/****************************************************************************
+try to get the disk space from disk quotas (LINUX version)
+****************************************************************************/
+
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
+{
+ uid_t euser_id;
+ int r;
+ struct dqblk D;
+ struct stat S;
+ FILE *fp;
+ struct mntent *mnt;
+ int devno;
+ int found;
+
+ /* 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))) {
+ if ( stat(mnt->mnt_dir,&S) == -1 )
+ continue ;
+ if (S.st_dev == devno) {
+ found = True ;
+ break ;
+ }
+ }
+ endmntent(fp) ;
+
+ if (!found) {
+ return(False);
+ }
+
+ euser_id=geteuid();
+ seteuid(0);
+ r=quotactl(QCMD(Q_GETQUOTA,USRQUOTA), mnt->mnt_fsname, euser_id, (caddr_t)&D);
+ seteuid(euser_id);
+
+ /* 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_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
+ (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
+ (D.dqb_isoftlimit && D.dqb_curinodes>=D.dqb_isoftlimit) ||
+ (D.dqb_ihardlimit && D.dqb_curinodes>=D.dqb_ihardlimit)
+ )
+ {
+ *dfree = 0;
+ *dsize = D.dqb_curblocks;
+ }
+ else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
+ {
+ return(False);
+ }
+ else {
+ *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
+ *dsize = D.dqb_bsoftlimit;
+ }
+ return (True);
+}
+
+#elif defined(CRAY)
+
+#include <sys/quota.h>
+#include <mntent.h>
+
+/****************************************************************************
+try to get the disk space from disk quotas (CRAY VERSION)
+****************************************************************************/
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
+{
+ struct mntent *mnt;
+ FILE *fd;
+ struct stat sbuf;
+ dev_t devno ;
+ static dev_t devno_cached = 0 ;
+ static char name[MNTMAXSTR] ;
+ struct q_request request ;
+ struct qf_header header ;
+ static int quota_default = 0 ;
+ int found ;
+
+ if ( stat(path,&sbuf) == -1 )
+ return(False) ;
+
+ devno = sbuf.st_dev ;
+
+ if ( devno != devno_cached ) {
+
+ devno_cached = devno ;
+
+ if ((fd = setmntent(KMTAB)) == NULL)
+ return(False) ;
+
+ found = False ;
+
+ while ((mnt = getmntent(fd)) != NULL) {
+
+ if ( stat(mnt->mnt_dir,&sbuf) == -1 )
+ continue ;
+
+ if (sbuf.st_dev == devno) {
+
+ found = True ;
+ break ;
+
+ }
+
+ }
+
+ strcpy(name,mnt->mnt_dir) ;
+ endmntent(fd) ;
+
+ if ( ! found )
+ return(False) ;
+ }
+
+ request.qf_magic = QF_MAGIC ;
+ request.qf_entry.id = geteuid() ;
+
+ if (quotactl(name, Q_GETQUOTA, &request) == -1)
+ return(False) ;
+
+ if ( ! request.user )
+ return(False) ;
+
+ if ( request.qf_entry.user_q.f_quota == QFV_DEFAULT ) {
+
+ if ( ! quota_default ) {
+
+ if ( quotactl(name, Q_GETHEADER, &header) == -1 )
+ return(False) ;
+ else
+ quota_default = header.user_h.def_fq ;
+ }
+
+ *dfree = quota_default ;
+
+ }else if ( request.qf_entry.user_q.f_quota == QFV_PREVENT ) {
+
+ *dfree = 0 ;
+
+ }else{
+
+ *dfree = request.qf_entry.user_q.f_quota ;
+
+ }
+
+ *dsize = request.qf_entry.user_q.f_use ;
+
+ if ( *dfree )
+ *dfree -= *dsize ;
+
+ if ( *dfree < 0 )
+ *dfree = 0 ;
+
+ *bsize = 4096 ; /* Cray blocksize */
+
+ return(True) ;
+
+}
+
+
+#elif defined(SUNOS5) || defined(SUNOS4)
+
+#include <fcntl.h>
+#if defined(SUNOS5)
+#include <sys/fs/ufs_quota.h>
+#include <sys/mnttab.h>
+#else /* defined(SUNOS4) */
+#include <ufs/quota.h>
+#include <mntent.h>
+#endif
+
+/****************************************************************************
+try to get the disk space from disk quotas (solaris 2 version)
+****************************************************************************/
+/* Quota code by Peter Urbanec (amiga@cse.unsw.edu.au) */
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
+{
+ uid_t user_id, euser_id;
+ int ret;
+ struct dqblk D;
+#if defined(SUNOS5)
+ struct quotctl command;
+ int file;
+ struct mnttab mnt;
+ static char name[MNT_LINE_MAX] ;
+#else
+ struct mntent *mnt;
+ static char name[MNTMAXSTR] ;
+#endif
+ FILE *fd;
+ struct stat sbuf;
+ dev_t devno ;
+ static dev_t devno_cached = 0 ;
+ int found ;
+
+ if ( stat(path,&sbuf) == -1 )
+ return(False) ;
+
+ devno = sbuf.st_dev ;
+ DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%o\n", path,devno));
+ if ( devno != devno_cached ) {
+ devno_cached = devno ;
+#if defined(SUNOS5)
+ if ((fd = fopen(MNTTAB, "r")) == NULL)
+ return(False) ;
+
+ found = False ;
+ while (getmntent(fd, &mnt) == 0) {
+ if ( stat(mnt.mnt_mountp,&sbuf) == -1 )
+ continue ;
+ DEBUG(5,("disk_quotas: testing \"%s\" devno=%o\n",
+ mnt.mnt_mountp,sbuf.st_dev));
+ if (sbuf.st_dev == devno) {
+ found = True ;
+ break ;
+ }
+ }
+
+ strcpy(name,mnt.mnt_mountp) ;
+ strcat(name,"/quotas") ;
+ fclose(fd) ;
+#else
+ if ((fd = setmntent(MOUNTED, "r")) == NULL)
+ return(False) ;
+
+ found = False ;
+ while ((mnt = getmntent(fd)) != NULL) {
+ if ( stat(mnt->mnt_dir,&sbuf) == -1 )
+ continue ;
+ DEBUG(5,("disk_quotas: testing \"%s\" devno=%o\n",
+ mnt->mnt_dir,sbuf.st_dev));
+ if (sbuf.st_dev == devno) {
+ found = True ;
+ break ;
+ }
+ }
+
+ strcpy(name,mnt->mnt_fsname) ;
+ endmntent(fd) ;
+#endif
+
+ if ( ! found )
+ return(False) ;
+ }
+
+ euser_id = geteuid();
+ user_id = getuid();
+
+ setuid(0); /* Solaris seems to want to give info only to super-user */
+ seteuid(0);
+
+#if defined(SUNOS5)
+ DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
+ if((file=open(name, O_RDONLY))<0) {
+ setuid(user_id); /* Restore the original UID status */
+ seteuid(euser_id);
+ return(False);
+ }
+ command.op = Q_GETQUOTA;
+ command.uid = euser_id;
+ command.addr = (caddr_t) &D;
+ ret = ioctl(file, Q_QUOTACTL, &command);
+ close(file);
+#else
+ DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
+ ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
+#endif
+
+ setuid(user_id); /* Restore the original uid status. */
+ seteuid(euser_id);
+
+ if (ret < 0) {
+ DEBUG(2,("disk_quotas ioctl (Solaris) failed\n"));
+ return(False);
+ }
+
+
+ /* Use softlimit to determine disk space. A user exceeding the quota is told
+ * that there's no space left. Writes might actually work for a bit if the
+ * hardlimit is set higher than softlimit. Effectively the disk becomes
+ * made of rubber latex and begins to expand to accommodate the user :-)
+ */
+
+ if (D.dqb_bsoftlimit==0)
+ return(False);
+ *bsize = 512;
+ *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
+ *dsize = D.dqb_bsoftlimit;
+ if(*dfree < 0)
+ {
+ *dfree = 0;
+ *dsize = D.dqb_curblocks;
+ }
+
+DEBUG(5,("disk_quotas for path \"%s\" returning bsize %d, dfree %d, dsize %d\n",
+ path,*bsize,*dfree,*dsize));
+
+ return(True);
+}
+
+
+#elif defined(OSF1)
+#include <ufs/quota.h>
+
+/****************************************************************************
+try to get the disk space from disk quotas - OFS1 version
+****************************************************************************/
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
+{
+ uid_t user_id, euser_id;
+ int r, save_errno;
+ struct dqblk D;
+ struct stat S;
+
+ euser_id = geteuid();
+ user_id = getuid();
+
+ setreuid(euser_id, -1);
+ r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
+ if (r)
+ save_errno = errno;
+
+ if (setreuid(user_id, -1) == -1)
+ DEBUG(5,("Unable to reset uid to %d\n", user_id));
+
+ *bsize = DEV_BSIZE;
+
+ if (r)
+ {
+ if (save_errno == EDQUOT) // disk quota exceeded
+ {
+ *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_bsoftlimit==0)
+ return(False);
+
+ if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
+ *dfree = 0;
+ *dsize = D.dqb_curblocks;
+ } else {
+ *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
+ *dsize = D.dqb_bsoftlimit;
+ }
+ return (True);
+}
+
+#elif defined (SGI6)
+/****************************************************************************
+try to get the disk space from disk quotas (IRIX 6.2 version)
+****************************************************************************/
+
+#include <sys/quota.h>
+#include <mntent.h>
+
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
+{
+ uid_t euser_id;
+ int r;
+ struct dqblk D;
+ struct fs_disk_quota F;
+ struct stat S;
+ FILE *fp;
+ struct mntent *mnt;
+ int devno;
+ int found;
+
+ /* 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))) {
+ if ( stat(mnt->mnt_dir,&S) == -1 )
+ continue ;
+ if (S.st_dev == devno) {
+ found = True ;
+ break ;
+ }
+ }
+ endmntent(fp) ;
+
+ if (!found) {
+ return(False);
+ }
+
+ euser_id=geteuid();
+ seteuid(0);
+
+ /* Use softlimit to determine disk space, except when it has been exceeded */
+
+ *bsize = 512;
+
+ if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
+ {
+ r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
+
+ if (r==-1)
+ return(False);
+
+ /* Use softlimit to determine disk space, except when it has been exceeded */
+ if (
+ (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
+ (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
+ (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
+ (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
+ )
+ {
+ *dfree = 0;
+ *dsize = D.dqb_curblocks;
+ }
+ else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
+ {
+ return(False);
+ }
+ else
+ {
+ *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
+ *dsize = D.dqb_bsoftlimit;
+ }
+
+ }
+ else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
+ {
+ r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
+
+ if (r==-1)
+ return(False);
+
+ /* Use softlimit to determine disk space, except when it has been exceeded */
+ if (
+ (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
+ (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
+ (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
+ (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
+ )
+ {
+ /*
+ * Fixme!: these are __uint64_t, this may truncate values
+ */
+ *dfree = 0;
+ *dsize = (int) F.d_bcount;
+ }
+ else if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
+ {
+ return(False);
+ }
+ else
+ {
+ *dfree = (int)(F.d_blk_softlimit - F.d_bcount);
+ *dsize = (int)F.d_blk_softlimit;
+ }
+
+ }
+ else
+ return(False);
+
+ return (True);
+
+}
+
+#else
+
+#ifdef __FreeBSD__
+#include <ufs/ufs/quota.h>
+#include <machine/param.h>
+#elif AIX
+/* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
+#include <jfs/quota.h>
+/* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
+#define dqb_curfiles dqb_curinodes
+#define dqb_fhardlimit dqb_ihardlimit
+#define dqb_fsoftlimit dqb_isoftlimit
+#else /* !__FreeBSD__ && !AIX */
+#include <sys/quota.h>
+#include <devnm.h>
+#endif
+
+/****************************************************************************
+try to get the disk space from disk quotas - default version
+****************************************************************************/
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
+{
+ uid_t euser_id;
+ int r;
+ struct dqblk D;
+#if !defined(__FreeBSD__) && !defined(AIX)
+ char dev_disk[256];
+ 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);
+#endif
+
+ euser_id = geteuid();
+
+#ifdef USE_SETRES
+ {
+ uid_t user_id;
+
+ /* for HPUX, real uid must be same as euid to execute quotactl for euid */
+ user_id = getuid();
+ setresuid(euser_id,-1,-1);
+ r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
+ if (setresuid(user_id,-1,-1))
+ DEBUG(5,("Unable to reset uid to %d\n", user_id));
+ }
+#else /* USE_SETRES */
+#if defined(__FreeBSD__)
+ {
+ /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
+ uid_t user_id;
+ gid_t egrp_id;
+
+ /* Need to be root to get quotas in FreeBSD */
+ user_id = getuid();
+ egrp_id = getegid();
+ setuid(0);
+ seteuid(0);
+ r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
+
+ /* As FreeBSD has group quotas, if getting the user
+ quota fails, try getting the group instead. */
+ if (r)
+ r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
+ setuid(user_id);
+ seteuid(euser_id);
+ }
+#elif defined(AIX)
+ /* AIX has both USER and GROUP quotas:
+ Get the USER quota (ohnielse@fysik.dtu.dk) */
+ r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
+#else /* !__FreeBSD__ && !AIX */
+ r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
+#endif /* !__FreeBSD__ && !AIX */
+#endif /* USE_SETRES */
+
+ /* Use softlimit to determine disk space, except when it has been exceeded */
+#if defined(__FreeBSD__)
+ *bsize = DEV_BSIZE;
+#else /* !__FreeBSD__ */
+ *bsize = 1024;
+#endif /*!__FreeBSD__ */
+
+ if (r)
+ {
+ if (errno == EDQUOT)
+ {
+ *dfree =0;
+ *dsize =D.dqb_curblocks;
+ return (True);
+ }
+ else return(False);
+ }
+ if (D.dqb_bsoftlimit==0)
+ return(False);
+ /* Use softlimit to determine disk space, except when it has been exceeded */
+ if ((D.dqb_curblocks>D.dqb_bsoftlimit)
+#if !defined(__FreeBSD__)
+||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
+#endif
+ ) {
+ *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..9484f3b85fe 100644
--- a/source/smbd/reply.c
+++ b/source/smbd/reply.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Main SMB reply routines
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1997
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
@@ -25,21 +25,25 @@
#include "includes.h"
-#include "loadparm.h"
#include "trans2.h"
+#include "nterr.h"
/* look in server.c for some explanation of these variables */
extern int Protocol;
extern int DEBUGLEVEL;
-extern int chain_size;
-extern int maxxmit;
+extern int max_send;
+extern int max_recv;
extern int chain_fnum;
extern char magic_char;
extern connection_struct Connections[];
extern files_struct Files[];
extern BOOL case_sensitive;
+extern BOOL case_preserve;
+extern BOOL short_case_preserve;
extern pstring sesssetup_user;
+extern fstring myworkgroup;
extern int Client;
+extern int global_oplock_break;
/* this macro should always be used to extract an fnum (smb_fid) from
a packet to ensure chaining works correctly */
@@ -47,62 +51,102 @@ a packet to ensure chaining works correctly */
/****************************************************************************
- reply to an special message
+report a possible attack via the password buffer overflow bug
****************************************************************************/
-int reply_special(char *inbuf,char *outbuf)
+static void overflow_attack(int len)
{
- int outsize = 4;
- int msg_type = CVAL(inbuf,0);
- int msg_flags = CVAL(inbuf,1);
- pstring name1,name2;
- extern fstring remote_machine;
- extern fstring local_machine;
- char *p;
+ DEBUG(0,("ERROR: Invalid password length %d\n", len));
+ DEBUG(0,("your machine may be under attack by a user exploiting an old bug\n"));
+ DEBUG(0,("Attack was from IP=%s\n", client_addr()));
+ exit_server("possible attack");
+}
- *name1 = *name2 = 0;
- smb_setlen(outbuf,0);
+/****************************************************************************
+ reply to an special message
+****************************************************************************/
+int reply_special(char *inbuf,char *outbuf)
+{
+ int outsize = 4;
+ int msg_type = CVAL(inbuf,0);
+ int msg_flags = CVAL(inbuf,1);
+ pstring name1,name2;
+ extern fstring remote_machine;
+ extern fstring local_machine;
+ char *p;
+ int len;
+ char name_type = 0;
+
+ *name1 = *name2 = 0;
+
+ smb_setlen(outbuf,0);
+
+ switch (msg_type) {
+ case 0x81: /* session request */
+ CVAL(outbuf,0) = 0x82;
+ CVAL(outbuf,3) = 0;
+ if (name_len(inbuf+4) > 50 ||
+ name_len(inbuf+4 + name_len(inbuf + 4)) > 50) {
+ DEBUG(0,("Invalid name length in session request\n"));
+ return(0);
+ }
+ name_extract(inbuf,4,name1);
+ name_extract(inbuf,4 + name_len(inbuf + 4),name2);
+ DEBUG(2,("netbios connect: name1=%s name2=%s\n",
+ name1,name2));
+
+ fstrcpy(remote_machine,name2);
+ trim_string(remote_machine," "," ");
+ p = strchr(remote_machine,' ');
+ strlower(remote_machine);
+ if (p) *p = 0;
+
+ fstrcpy(local_machine,name1);
+ trim_string(local_machine," "," ");
+ len = strlen(local_machine);
+ if (len == 16) {
+ name_type = local_machine[15];
+ local_machine[15] = 0;
+ }
+ p = strchr(local_machine,' ');
+ strlower(local_machine);
+ if (p) *p = 0;
+
+ if (name_type == 'R') {
+ /* We are being asked for a pathworks session ---
+ no thanks! */
+ CVAL(outbuf, 0) = 0x83;
+ break;
+ }
- switch (msg_type)
- {
- case 0x81: /* session request */
- CVAL(outbuf,0) = 0x82;
- CVAL(outbuf,3) = 0;
- if (name_len(inbuf+4) > 50)
- {
- DEBUG(0,("Invalid name length in session request\n"));
- return(0);
+ add_session_user(remote_machine);
+
+ reload_services(True);
+ reopen_logs();
+
+ break;
+
+ case 0x89: /* session keepalive request
+ (some old clients produce this?) */
+ CVAL(outbuf,0) = 0x85;
+ CVAL(outbuf,3) = 0;
+ break;
+
+ case 0x82: /* positive session response */
+ case 0x83: /* negative session response */
+ case 0x84: /* retarget session response */
+ DEBUG(0,("Unexpected session response\n"));
+ break;
+
+ case 0x85: /* session keepalive */
+ default:
+ return(0);
}
- name_extract(inbuf,4,name1);
- name_extract(inbuf,4 + name_len(inbuf + 4),name2);
- DEBUG(2,("netbios connect: name1=%s name2=%s\n",name1,name2));
-
- strcpy(remote_machine,name2);
- trim_string(remote_machine," "," ");
- p = strchr(remote_machine,' ');
- strlower(remote_machine);
- if (p) *p = 0;
-
- strcpy(local_machine,name1);
- trim_string(local_machine," "," ");
- p = strchr(local_machine,' ');
- strlower(local_machine);
- if (p) *p = 0;
-
- add_session_user(remote_machine);
-
- reload_services(True);
- reopen_logs();
-
- break;
- case 0x85: /* session keepalive */
- default:
- return(0);
- }
-
- DEBUG(5,("%s init msg_type=0x%x msg_flags=0x%x\n",timestring(),msg_type,msg_flags));
-
- return(outsize);
+
+ DEBUG(5,("%s init msg_type=0x%x msg_flags=0x%x\n",
+ timestring(),msg_type,msg_flags));
+
+ return(outsize);
}
@@ -132,6 +176,44 @@ static int connection_error(char *inbuf,char *outbuf,int connection_num)
}
+
+/****************************************************************************
+ parse a share descriptor string
+****************************************************************************/
+static void parse_connect(char *p,char *service,char *user,
+ char *password,int *pwlen,char *dev)
+{
+ char *p2;
+
+ DEBUG(4,("parsing connect string %s\n",p));
+
+ p2 = strrchr(p,'\\');
+ if (p2 == NULL)
+ fstrcpy(service,p);
+ else
+ fstrcpy(service,p2+1);
+
+ p += strlen(p) + 2;
+
+ fstrcpy(password,p);
+ *pwlen = strlen(password);
+
+ p += strlen(p) + 2;
+
+ fstrcpy(dev,p);
+
+ *user = 0;
+ p = strchr(service,'%');
+ if (p != NULL)
+ {
+ *p = 0;
+ fstrcpy(user,p+1);
+ }
+}
+
+
+
+
/****************************************************************************
reply to a tcon
****************************************************************************/
@@ -143,15 +225,12 @@ int reply_tcon(char *inbuf,char *outbuf)
pstring dev;
int connection_num;
int outsize = 0;
- int uid = SVAL(inbuf,smb_uid);
- int vuid;
- int pwlen;
+ uint16 vuid = SVAL(inbuf,smb_uid);
+ int pwlen=0;
*service = *user = *password = *dev = 0;
- vuid = valid_uid(uid);
-
- parse_connect(inbuf,service,user,password,&pwlen,dev);
+ parse_connect(smb_buf(inbuf)+1,service,user,password,&pwlen,dev);
connection_num = make_connection(service,user,password,pwlen,dev,vuid);
@@ -159,7 +238,7 @@ int reply_tcon(char *inbuf,char *outbuf)
return(connection_error(inbuf,outbuf,connection_num));
outsize = set_message(outbuf,2,0,True);
- SSVAL(outbuf,smb_vwv0,maxxmit);
+ SSVAL(outbuf,smb_vwv0,max_recv);
SSVAL(outbuf,smb_vwv1,connection_num);
SSVAL(outbuf,smb_tid,connection_num);
@@ -179,39 +258,44 @@ int reply_tcon_and_X(char *inbuf,char *outbuf,int length,int bufsize)
pstring password;
pstring devicename;
int connection_num;
- int outsize = 0;
- int uid = SVAL(inbuf,smb_uid);
- int vuid;
- int smb_com2 = SVAL(inbuf,smb_vwv0);
- int smb_off2 = SVAL(inbuf,smb_vwv1);
+ uint16 vuid = SVAL(inbuf,smb_uid);
int passlen = SVAL(inbuf,smb_vwv3);
+ BOOL doencrypt = SMBENCRYPT();
*service = *user = *password = *devicename = 0;
/* we might have to close an old one */
if ((SVAL(inbuf,smb_vwv2) & 0x1) != 0)
- close_cnum(SVAL(inbuf,smb_tid),uid);
-
- vuid = valid_uid(uid);
+ close_cnum(SVAL(inbuf,smb_tid),vuid);
+
+ if (passlen > MAX_PASS_LEN) {
+ overflow_attack(passlen);
+ }
{
char *path;
char *p;
memcpy(password,smb_buf(inbuf),passlen);
- password[passlen]=0;
+ password[passlen]=0;
path = smb_buf(inbuf) + passlen;
- DEBUG(4,("parsing net-path %s, passlen=%d\n",path,passlen));
- strcpy(service,path+2);
+
+ if (!doencrypt || passlen != 24) {
+ if (strequal(password," "))
+ *password = 0;
+ passlen = strlen(password);
+ }
+
+ fstrcpy(service,path+2);
p = strchr(service,'\\');
if (!p)
return(ERROR(ERRSRV,ERRinvnetname));
*p = 0;
- strcpy(service,p+1);
+ fstrcpy(service,p+1);
p = strchr(service,'%');
if (p)
{
*p++ = 0;
- strcpy(user,p);
+ fstrcpy(user,p);
}
StrnCpy(devicename,path + strlen(path) + 1,6);
DEBUG(4,("Got device type %s\n",devicename));
@@ -222,7 +306,26 @@ int reply_tcon_and_X(char *inbuf,char *outbuf,int length,int bufsize)
if (connection_num < 0)
return(connection_error(inbuf,outbuf,connection_num));
- outsize = set_message(outbuf,2,strlen(devicename)+1,True);
+ if (Protocol < PROTOCOL_NT1)
+ {
+ set_message(outbuf,2,strlen(devicename)+1,True);
+ strcpy(smb_buf(outbuf),devicename);
+ }
+ else
+ {
+ char *fsname = "SAMBA";
+ char *p;
+
+ set_message(outbuf,3,3,True);
+
+ p = smb_buf(outbuf);
+ strcpy(p,devicename); p = skip_string(p,1); /* device name */
+ strcpy(p,fsname); p = skip_string(p,1); /* filesystem type e.g NTFS */
+
+ set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False);
+
+ SSVAL(outbuf, smb_vwv2, 0x0); /* optional support */
+ }
DEBUG(3,("%s tconX service=%s user=%s cnum=%d\n",timestring(),service,user,connection_num));
@@ -230,17 +333,7 @@ int reply_tcon_and_X(char *inbuf,char *outbuf,int length,int bufsize)
SSVAL(inbuf,smb_tid,connection_num);
SSVAL(outbuf,smb_tid,connection_num);
- CVAL(outbuf,smb_vwv0) = smb_com2;
- SSVAL(outbuf,smb_vwv1,(chain_size + outsize)-4);
-
- strcpy(smb_buf(outbuf),devicename);
-
- if (smb_com2 != 0xFF)
- outsize += chain_reply(smb_com2,inbuf,inbuf+smb_off2+4,
- outbuf,outbuf+outsize,
- length,bufsize);
-
- return(outsize);
+ return chain_reply(inbuf,outbuf,length,bufsize);
}
@@ -269,8 +362,13 @@ int reply_unknown(char *inbuf,char *outbuf)
int reply_ioctl(char *inbuf,char *outbuf)
{
DEBUG(3,("ignoring ioctl\n"));
-
+#if 0
+ /* we just say it succeeds and hope its all OK.
+ some day it would be nice to interpret them individually */
+ return set_message(outbuf,1,0,True);
+#else
return(ERROR(ERRSRV,ERRnosupport));
+#endif
}
@@ -279,28 +377,28 @@ reply to a session setup command
****************************************************************************/
int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
{
- int outsize = 0;
- int sess_uid;
+ uint16 sess_vuid;
int gid;
- int smb_com2;
- int smb_off2;
+ int uid;
int smb_bufsize;
int smb_mpxmax;
int smb_vc_num;
uint32 smb_sesskey;
- int smb_apasslen;
+ int smb_apasslen = 0;
pstring smb_apasswd;
int smb_ntpasslen = 0;
pstring smb_ntpasswd;
BOOL valid_nt_password = False;
pstring user;
BOOL guest=False;
+ BOOL computer_id=False;
+ static BOOL done_sesssetup = False;
+ BOOL doencrypt = SMBENCRYPT();
+ char *domain = "";
*smb_apasswd = 0;
+ *smb_ntpasswd = 0;
- sess_uid = SVAL(inbuf,smb_uid);
- smb_com2 = CVAL(inbuf,smb_vwv0);
- smb_off2 = SVAL(inbuf,smb_vwv1);
smb_bufsize = SVAL(inbuf,smb_vwv2);
smb_mpxmax = SVAL(inbuf,smb_vwv3);
smb_vc_num = SVAL(inbuf,smb_vwv4);
@@ -308,16 +406,48 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
if (Protocol < PROTOCOL_NT1) {
smb_apasslen = SVAL(inbuf,smb_vwv7);
+ if (smb_apasslen > MAX_PASS_LEN)
+ {
+ overflow_attack(smb_apasslen);
+ }
+
memcpy(smb_apasswd,smb_buf(inbuf),smb_apasslen);
- StrnCpy(user,smb_buf(inbuf)+smb_apasslen,sizeof(user)-1);
+ pstrcpy(user,smb_buf(inbuf)+smb_apasslen);
+
+ if (lp_security() != SEC_SERVER && !doencrypt) {
+ smb_apasslen = strlen(smb_apasswd);
+ }
} else {
uint16 passlen1 = SVAL(inbuf,smb_vwv7);
uint16 passlen2 = SVAL(inbuf,smb_vwv8);
- BOOL doencrypt = SMBENCRYPT();
- char *p = smb_buf(inbuf);
- if (passlen1 > 256) passlen1 = 0;
- if (passlen2 > 256) passlen2 = 0; /* I don't know why NT gives weird
- lengths sometimes */
+ uint32 client_caps = IVAL(inbuf,smb_vwv11);
+ enum remote_arch_types ra_type = get_remote_arch();
+
+ char *p = smb_buf(inbuf);
+
+ /* client_caps is used as final determination if client is NT or Win95.
+ This is needed to return the correct error codes in some
+ circumstances.
+ */
+
+ if(ra_type == RA_WINNT || ra_type == RA_WIN95)
+ {
+ if(client_caps & (CAP_NT_SMBS | CAP_STATUS32))
+ set_remote_arch( RA_WINNT);
+ else
+ set_remote_arch( RA_WIN95);
+ }
+
+ if (passlen1 != 24 && passlen2 != 24)
+ doencrypt = False;
+
+ if (passlen1 > MAX_PASS_LEN) {
+ overflow_attack(passlen1);
+ }
+
+ passlen1 = MIN(passlen1, MAX_PASS_LEN);
+ passlen2 = MIN(passlen2, MAX_PASS_LEN);
+
if(doencrypt) {
/* Save the lanman2 password and the NT md4 password. */
smb_apasslen = passlen1;
@@ -325,31 +455,86 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
smb_ntpasslen = passlen2;
memcpy(smb_ntpasswd,p+passlen1,smb_ntpasslen);
} else {
- /* for Win95 */
- if (passlen1 > passlen2) {
- smb_apasslen = passlen1;
- StrnCpy(smb_apasswd,p,smb_apasslen);
- } else {
- smb_apasslen = passlen2;
- StrnCpy(smb_apasswd,p + passlen1,smb_apasslen);
+ /* both Win95 and WinNT stuff up the password lengths for
+ non-encrypting systems. Uggh.
+
+ if passlen1==24 its a win95 system, and its setting the
+ password length incorrectly. Luckily it still works with the
+ default code because Win95 will null terminate the password
+ anyway
+
+ if passlen1>0 and passlen2>0 then maybe its a NT box and its
+ setting passlen2 to some random value which really stuffs
+ things up. we need to fix that one. */
+ if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 &&
+ passlen2 != 1) {
+ passlen2 = 0;
+ }
+ /* we use the first password that they gave */
+ smb_apasslen = passlen1;
+ StrnCpy(smb_apasswd,p,smb_apasslen);
+
+ /* trim the password */
+ smb_apasslen = strlen(smb_apasswd);
+
+ /* wfwg sometimes uses a space instead of a null */
+ if (strequal(smb_apasswd," ")) {
+ smb_apasslen = 0;
+ *smb_apasswd = 0;
}
}
- if (passlen2 == 1) {
- /* apparently NT sometimes sets passlen2 to 1 when it means 0. This
- tries to work around that problem */
- passlen2 = 0;
- }
+
p += passlen1 + passlen2;
- strcpy(user,p); p = skip_string(p,1);
+ fstrcpy(user,p); p = skip_string(p,1);
+ domain = p;
+
DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s]\n",
- p,skip_string(p,1),skip_string(p,2)));
+ domain,skip_string(p,1),skip_string(p,2)));
}
DEBUG(3,("sesssetupX:name=[%s]\n",user));
+ /* If name ends in $ then I think it's asking about whether a */
+ /* computer with that name (minus the $) has access. For now */
+ /* say yes to everything ending in $. */
+ if (user[strlen(user) - 1] == '$') {
+#ifdef NTDOMAIN
+ struct smb_passwd *smb_pass; /* To check if machine account exists */
+/*
+ PAXX: Ack. We don't want to do this. The workstation trust account
+ with a $ on the end should exist in the local password database
+ or be mapped to something generic, but not modified. For NT
+ domain support we must reject this used in certain circumstances
+ with a code to indicate to the client that it is an invalid use
+ of a workstation trust account. NTWKS needs this error to join
+ a domain. This may be the source of future bugs if we cannot
+ be sure whether to reject this or not.
+*/
+ smb_pass = get_smbpwnam(user);
+ if(smb_pass)
+ {
+ /* PAXX: This is the NO LOGON workstation trust account stuff */
+ DEBUG(4,("Rejecting workstation trust account %s",user));
+ SSVAL(outbuf, smb_flg2, 0xc003); /* PAXX: Someone please unhack this */
+ CVAL(outbuf, smb_reh) = 1; /* PAXX: Someone please unhack this */
+ return(ERROR(NT_STATUS_ALLOTTED_SPACE_EXCEEDED, 0xc000)); /* 0x99 NT error, 0xc00 */
+ }
+ computer_id = True;
+#else /* not NTDOMAIN, leave this in. PAXX: Someone get rid of this */
+ user[strlen(user) - 1] = '\0';
+#endif
+ }
+
+
+ /* If no username is sent use the guest account */
if (!*user)
- strcpy(user,lp_guestaccount(-1));
+ {
+ strcpy(user,lp_guestaccount(-1));
+ /* If no user and no password then set guest flag. */
+ if( *smb_apasswd == 0)
+ guest = True;
+ }
strlower(user);
@@ -359,27 +544,35 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
add_session_user(user);
+ /* Check if the given username was the guest user with no password.
+ We need to do this check after add_session_user() as that
+ call can potentially change the username (via map_user).
+ */
+
+ if(!guest && strequal(user,lp_guestaccount(-1)) && (*smb_apasswd == 0))
+ guest = True;
- if (!(lp_security() == SEC_SERVER && server_validate(inbuf)) &&
+ if (!guest && !(lp_security() == SEC_SERVER &&
+ server_validate(user, domain,
+ smb_apasswd, smb_apasslen,
+ smb_ntpasswd, smb_ntpasslen)) &&
!check_hosts_equiv(user))
{
- if (strequal(user,lp_guestaccount(-1)) && (*smb_apasswd == 0))
- guest = True;
-
/* now check if it's a valid username/password */
/* If an NT password was supplied try and validate with that
- first. This is superior as the passwords are mixed case 128 length unicode */
- if(smb_ntpasslen && !guest)
+ first. This is superior as the passwords are mixed case
+ 128 length unicode */
+ if(smb_ntpasslen)
{
- if(!password_ok(user,smb_ntpasswd,smb_ntpasslen,NULL,True))
+ if(!password_ok(user,smb_ntpasswd,smb_ntpasslen,NULL))
DEBUG(0,("NT Password did not match ! Defaulting to Lanman\n"));
else
valid_nt_password = True;
}
- if (!valid_nt_password && !guest && !password_ok(user,smb_apasswd,smb_apasslen,NULL,False))
+ if (!valid_nt_password && !password_ok(user,smb_apasswd,smb_apasslen,NULL))
{
- if (lp_security() >= SEC_USER) {
+ if (!computer_id && lp_security() >= SEC_USER) {
#if (GUEST_SESSSETUP == 0)
return(ERROR(ERRSRV,ERRbadpw));
#endif
@@ -413,15 +606,15 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
/* it's ok - setup a reply */
if (Protocol < PROTOCOL_NT1) {
- outsize = set_message(outbuf,3,0,True);
+ set_message(outbuf,3,0,True);
} else {
char *p;
- outsize = set_message(outbuf,3,3,True);
+ set_message(outbuf,3,3,True);
p = smb_buf(outbuf);
strcpy(p,"Unix"); p = skip_string(p,1);
strcpy(p,"Samba "); strcat(p,VERSION); p = skip_string(p,1);
- strcpy(p,my_workgroup()); p = skip_string(p,1);
- outsize = set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False);
+ strcpy(p,myworkgroup); p = skip_string(p,1);
+ set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False);
/* perhaps grab OS version here?? */
}
@@ -436,28 +629,27 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
return(ERROR(ERRSRV,ERRbadpw));
}
gid = pw->pw_gid;
- SSVAL(outbuf,smb_uid,(uint16)pw->pw_uid);
- SSVAL(inbuf,smb_uid,(uint16)pw->pw_uid);
+ uid = pw->pw_uid;
}
- CVAL(outbuf,smb_vwv0) = smb_com2;
- SSVAL(outbuf,smb_vwv1,(chain_size+outsize)-4);
-
- if (guest)
+ if (guest && !computer_id)
SSVAL(outbuf,smb_vwv2,1);
/* register the name and uid as being validated, so further connections
to a uid can get through without a password, on the same VC */
- register_uid(SVAL(inbuf,smb_uid),gid,user,guest);
+ sess_vuid = register_vuid(uid,gid,user,guest);
- maxxmit = MIN(maxxmit,smb_bufsize);
+ SSVAL(outbuf,smb_uid,sess_vuid);
+ SSVAL(inbuf,smb_uid,sess_vuid);
- if (smb_com2 != 0xFF)
- outsize += chain_reply(smb_com2,inbuf,inbuf+smb_off2+4,
- outbuf,outbuf+outsize,
- length,bufsize);
+ if (!done_sesssetup)
+ max_send = MIN(max_send,smb_bufsize);
- return(outsize);
+ DEBUG(6,("Client requested max send size of %d\n", max_send));
+
+ done_sesssetup = True;
+
+ return chain_reply(inbuf,outbuf,length,bufsize);
}
@@ -470,11 +662,12 @@ int reply_chkpth(char *inbuf,char *outbuf)
int cnum,mode;
pstring name;
BOOL ok = False;
-
+ BOOL bad_path = False;
+
cnum = SVAL(inbuf,smb_tid);
- strcpy(name,smb_buf(inbuf) + 1);
- unix_convert(name,cnum);
+ pstrcpy(name,smb_buf(inbuf) + 1);
+ unix_convert(name,cnum,0,&bad_path);
mode = SVAL(inbuf,smb_vwv0);
@@ -482,8 +675,31 @@ int reply_chkpth(char *inbuf,char *outbuf)
ok = directory_exist(name,NULL);
if (!ok)
- return(ERROR(ERRDOS,ERRbadpath));
-
+ {
+ /* We special case this - as when a Windows machine
+ is parsing a path is steps through the components
+ one at a time - if a component fails it expects
+ ERRbadpath, not ERRbadfile.
+ */
+ if(errno == ENOENT)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+
+#if 0
+ /* Ugly - NT specific hack - maybe not needed ? (JRA) */
+ if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) &&
+ (get_remote_arch() == RA_WINNT))
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbaddirectory;
+ }
+#endif
+
+ return(UNIXERROR(ERRDOS,ERRbadpath));
+ }
+
outsize = set_message(outbuf,0,0,True);
DEBUG(3,("%s chkpth %s cnum=%d mode=%d\n",timestring(),name,cnum,mode));
@@ -505,11 +721,12 @@ int reply_getatr(char *inbuf,char *outbuf)
int mode=0;
uint32 size=0;
time_t mtime=0;
-
+ BOOL bad_path = False;
+
cnum = SVAL(inbuf,smb_tid);
- strcpy(fname,smb_buf(inbuf) + 1);
- unix_convert(fname,cnum);
+ pstrcpy(fname,smb_buf(inbuf) + 1);
+ unix_convert(fname,cnum,0,&bad_path);
/* dos smetimes asks for a stat of "" - it returns a "hidden directory"
under WfWg - weird! */
@@ -523,23 +740,31 @@ int reply_getatr(char *inbuf,char *outbuf)
}
else
if (check_name(fname,cnum))
+ {
+ if (sys_stat(fname,&sbuf) == 0)
{
- if (sys_stat(fname,&sbuf) == 0)
- {
- mode = dos_mode(cnum,fname,&sbuf);
- size = sbuf.st_size;
- mtime = sbuf.st_mtime;
- if (mode & aDIR)
- size = 0;
- ok = True;
- }
- else
- DEBUG(3,("stat of %s failed (%s)\n",fname,strerror(errno)));
+ mode = dos_mode(cnum,fname,&sbuf);
+ size = sbuf.st_size;
+ mtime = sbuf.st_mtime;
+ if (mode & aDIR)
+ size = 0;
+ ok = True;
+ }
+ else
+ DEBUG(3,("stat of %s failed (%s)\n",fname,strerror(errno)));
}
if (!ok)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+
return(UNIXERROR(ERRDOS,ERRbadfile));
-
+ }
+
outsize = set_message(outbuf,10,0,True);
SSVAL(outbuf,smb_vwv0,mode);
@@ -550,7 +775,7 @@ int reply_getatr(char *inbuf,char *outbuf)
char *p = strrchr(fname,'/');
uint16 flg2 = SVAL(outbuf,smb_flg2);
if (!p) p = fname;
- if (!is_8_3(fname))
+ if (!is_8_3(fname, True))
SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */
}
@@ -571,11 +796,12 @@ int reply_setatr(char *inbuf,char *outbuf)
BOOL ok=False;
int mode;
time_t mtime;
-
+ BOOL bad_path = False;
+
cnum = SVAL(inbuf,smb_tid);
- strcpy(fname,smb_buf(inbuf) + 1);
- unix_convert(fname,cnum);
+ pstrcpy(fname,smb_buf(inbuf) + 1);
+ unix_convert(fname,cnum,0,&bad_path);
mode = SVAL(inbuf,smb_vwv0);
mtime = make_unix_date3(inbuf+smb_vwv1);
@@ -585,11 +811,19 @@ int reply_setatr(char *inbuf,char *outbuf)
if (check_name(fname,cnum))
ok = (dos_chmod(cnum,fname,mode,NULL) == 0);
if (ok)
- ok = set_filetime(fname,mtime);
+ ok = set_filetime(cnum,fname,mtime);
if (!ok)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+
return(UNIXERROR(ERRDOS,ERRnoaccess));
-
+ }
+
outsize = set_message(outbuf,0,0,True);
DEBUG(3,("%s setatr name=%s mode=%d\n",timestring(),fname,mode));
@@ -651,6 +885,7 @@ int reply_search(char *inbuf,char *outbuf)
BOOL check_descend = False;
BOOL expect_close = False;
BOOL can_open = True;
+ BOOL bad_path = False;
*mask = *directory = *fname = 0;
@@ -676,28 +911,34 @@ int reply_search(char *inbuf,char *outbuf)
{
pstring dir2;
- strcpy(directory,smb_buf(inbuf)+1);
- strcpy(dir2,smb_buf(inbuf)+1);
- unix_convert(directory,cnum);
+ pstrcpy(directory,smb_buf(inbuf)+1);
+ pstrcpy(dir2,smb_buf(inbuf)+1);
+ unix_convert(directory,cnum,0,&bad_path);
unix_format(dir2);
if (!check_name(directory,cnum))
- can_open = False;
+ can_open = False;
p = strrchr(dir2,'/');
if (p == NULL)
- {strcpy(mask,dir2);*dir2 = 0;}
+ {
+ strcpy(mask,dir2);
+ *dir2 = 0;
+ }
else
- {*p = 0;strcpy(mask,p+1);}
+ {
+ *p = 0;
+ pstrcpy(mask,p+1);
+ }
p = strrchr(directory,'/');
if (!p)
- *directory = 0;
+ *directory = 0;
else
- *p = 0;
+ *p = 0;
if (strlen(directory) == 0)
- strcpy(directory,"./");
+ strcpy(directory,"./");
bzero(status,21);
CVAL(status,0) = dirtype;
}
@@ -721,7 +962,7 @@ int reply_search(char *inbuf,char *outbuf)
if ((p = strrchr(mask,' ')))
{
fstring ext;
- strcpy(ext,p+1);
+ fstrcpy(ext,p+1);
*p = 0;
trim_string(mask,NULL," ");
strcat(mask,".");
@@ -743,7 +984,7 @@ int reply_search(char *inbuf,char *outbuf)
if (!strchr(mask,'.') && strlen(mask)>8)
{
fstring tmp;
- strcpy(tmp,&mask[8]);
+ fstrcpy(tmp,&mask[8]);
mask[8] = '.';
mask[9] = 0;
strcat(mask,tmp);
@@ -761,7 +1002,18 @@ int reply_search(char *inbuf,char *outbuf)
{
dptr_num = dptr_create(cnum,directory,expect_close,SVAL(inbuf,smb_pid));
if (dptr_num < 0)
- return(ERROR(ERRDOS,ERRnofids));
+ {
+ if(dptr_num == -2)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ return (UNIXERROR(ERRDOS,ERRnofids));
+ }
+ return(ERROR(ERRDOS,ERRnofids));
+ }
}
DEBUG(4,("dptr_num is %d\n",dptr_num));
@@ -906,30 +1158,50 @@ int reply_open(char *inbuf,char *outbuf)
int unixmode;
int rmode=0;
struct stat sbuf;
-
+ BOOL bad_path = False;
+ files_struct *fsp;
+ int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
+
cnum = SVAL(inbuf,smb_tid);
share_mode = SVAL(inbuf,smb_vwv0);
- strcpy(fname,smb_buf(inbuf)+1);
- unix_convert(fname,cnum);
+ pstrcpy(fname,smb_buf(inbuf)+1);
+ unix_convert(fname,cnum,0,&bad_path);
fnum = find_free_file();
if (fnum < 0)
return(ERROR(ERRSRV,ERRnofids));
if (!check_name(fname,cnum))
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
-
+ }
+
unixmode = unix_mode(cnum,aARCH);
- open_file_shared(fnum,cnum,fname,share_mode,3,unixmode,&rmode,NULL);
+ open_file_shared(fnum,cnum,fname,share_mode,3,unixmode,
+ oplock_request,&rmode,NULL);
- if (!Files[fnum].open)
+ fsp = &Files[fnum];
+
+ if (!fsp->open)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
- if (fstat(Files[fnum].fd,&sbuf) != 0) {
- close_file(fnum);
+ if (fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
+ close_file(fnum,False);
return(ERROR(ERRDOS,ERRnoaccess));
}
@@ -939,7 +1211,7 @@ int reply_open(char *inbuf,char *outbuf)
if (fmode & aDIR) {
DEBUG(3,("attempt to open a directory %s\n",fname));
- close_file(fnum);
+ close_file(fnum,False);
return(ERROR(ERRDOS,ERRnoaccess));
}
@@ -949,7 +1221,13 @@ int reply_open(char *inbuf,char *outbuf)
put_dos_date3(outbuf,smb_vwv2,mtime);
SIVAL(outbuf,smb_vwv4,size);
SSVAL(outbuf,smb_vwv6,rmode);
+
+ if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+ }
+ if(fsp->granted_oplock)
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
return(outsize);
}
@@ -962,12 +1240,9 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
pstring fname;
int cnum = SVAL(inbuf,smb_tid);
int fnum = -1;
- int outsize = 0;
- int openmode = 0;
- int smb_com2 = CVAL(inbuf,smb_vwv0);
- int smb_off2 = SVAL(inbuf,smb_vwv1);
int smb_mode = SVAL(inbuf,smb_vwv3);
int smb_attr = SVAL(inbuf,smb_vwv5);
+ BOOL oplock_request = EXTENDED_OPLOCK_REQUEST(inbuf);
#if 0
int open_flags = SVAL(inbuf,smb_vwv2);
int smb_sattr = SVAL(inbuf,smb_vwv4);
@@ -978,35 +1253,51 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
int size=0,fmode=0,mtime=0,rmode=0;
struct stat sbuf;
int smb_action = 0;
+ BOOL bad_path = False;
+ files_struct *fsp;
+
+ /* If it's an IPC, pass off the pipe handler. */
+ if (IS_IPC(cnum))
+ return reply_open_pipe_and_X(inbuf,outbuf,length,bufsize);
/* XXXX we need to handle passed times, sattr and flags */
- strcpy(fname,smb_buf(inbuf));
- unix_convert(fname,cnum);
+ pstrcpy(fname,smb_buf(inbuf));
+ unix_convert(fname,cnum,0,&bad_path);
- /* now add create and trunc bits */
- if (smb_ofun & 0x10)
- openmode |= O_CREAT;
- if ((smb_ofun & 0x3) == 2)
- openmode |= O_TRUNC;
-
fnum = find_free_file();
if (fnum < 0)
return(ERROR(ERRSRV,ERRnofids));
if (!check_name(fname,cnum))
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
unixmode = unix_mode(cnum,smb_attr | aARCH);
open_file_shared(fnum,cnum,fname,smb_mode,smb_ofun,unixmode,
- &rmode,&smb_action);
+ oplock_request, &rmode,&smb_action);
- if (!Files[fnum].open)
+ fsp = &Files[fnum];
+
+ if (!fsp->open)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
- if (fstat(Files[fnum].fd,&sbuf) != 0) {
- close_file(fnum);
+ if (fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
+ close_file(fnum,False);
return(ERROR(ERRDOS,ERRnoaccess));
}
@@ -1014,13 +1305,21 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
fmode = dos_mode(cnum,fname,&sbuf);
mtime = sbuf.st_mtime;
if (fmode & aDIR) {
- close_file(fnum);
+ close_file(fnum,False);
return(ERROR(ERRDOS,ERRnoaccess));
}
- outsize = set_message(outbuf,15,0,True);
- CVAL(outbuf,smb_vwv0) = smb_com2;
- SSVAL(outbuf,smb_vwv1,(chain_size+outsize)-4);
+ if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
+ smb_action |= EXTENDED_OPLOCK_GRANTED;
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+ }
+
+ if(fsp->granted_oplock) {
+ smb_action |= EXTENDED_OPLOCK_GRANTED;
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+ }
+
+ set_message(outbuf,15,0,True);
SSVAL(outbuf,smb_vwv2,fnum);
SSVAL(outbuf,smb_vwv3,fmode);
put_dos_date3(outbuf,smb_vwv4,mtime);
@@ -1030,14 +1329,7 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
chain_fnum = fnum;
- if (smb_com2 != 0xFF)
- outsize += chain_reply(smb_com2,inbuf,inbuf+smb_off2+4,
- outbuf,outbuf+outsize,
- length,bufsize);
-
- chain_fnum = -1;
-
- return(outsize);
+ return chain_reply(inbuf,outbuf,length,bufsize);
}
@@ -1046,31 +1338,35 @@ 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 outsize = 0;
- int smb_com2 = CVAL(inbuf,smb_vwv0);
- int smb_off2 = SVAL(inbuf,smb_vwv1);
- int uid = SVAL(inbuf,smb_uid);
+ uint16 vuid = SVAL(inbuf,smb_uid);
+ user_struct *vuser = get_valid_user_struct(vuid);
- invalidate_uid(uid);
+ if(vuser == 0) {
+ DEBUG(3,("ulogoff, vuser id %d does not map to user.\n", vuid));
+ }
- outsize = set_message(outbuf,2,0,True);
- CVAL(outbuf,smb_vwv0) = smb_com2;
- SSVAL(outbuf,smb_vwv1,(chain_size+outsize)-4);
+ /* in user level security we are supposed to close any files
+ open by this user */
+ if ((vuser != 0) && (lp_security() != SEC_SHARE)) {
+ int i;
+ for (i=0;i<MAX_OPEN_FILES;i++)
+ if (Files[i].uid == vuser->uid && Files[i].open) {
+ close_file(i,False);
+ }
+ }
- DEBUG(3,("%s ulogoffX uid=%d\n",timestring(),uid));
+ invalidate_vuid(vuid);
- if (smb_com2 != 0xFF)
- outsize += chain_reply(smb_com2,inbuf,inbuf+smb_off2+4,
- outbuf,outbuf+outsize,
- length,bufsize);
+ set_message(outbuf,2,0,True);
-
- return(outsize);
+ DEBUG(3,("%s ulogoffX vuid=%d\n",timestring(),vuid));
+
+ return chain_reply(inbuf,outbuf,length,bufsize);
}
/****************************************************************************
- reply to a mknew
+ reply to a mknew or a create
****************************************************************************/
int reply_mknew(char *inbuf,char *outbuf)
{
@@ -1080,13 +1376,17 @@ int reply_mknew(char *inbuf,char *outbuf)
int outsize = 0;
int createmode;
mode_t unixmode;
-
+ int ofun = 0;
+ BOOL bad_path = False;
+ files_struct *fsp;
+ int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
+
com = SVAL(inbuf,smb_com);
cnum = SVAL(inbuf,smb_tid);
createmode = SVAL(inbuf,smb_vwv0);
- strcpy(fname,smb_buf(inbuf)+1);
- unix_convert(fname,cnum);
+ pstrcpy(fname,smb_buf(inbuf)+1);
+ unix_convert(fname,cnum,0,&bad_path);
if (createmode & aVOLID)
{
@@ -1095,26 +1395,59 @@ int reply_mknew(char *inbuf,char *outbuf)
unixmode = unix_mode(cnum,createmode);
- if (com == SMBmknew && file_exist(fname,NULL))
- return(ERROR(ERRDOS,ERRfilexists));
-
fnum = find_free_file();
if (fnum < 0)
return(ERROR(ERRSRV,ERRnofids));
if (!check_name(fname,cnum))
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
- open_file(fnum,cnum,fname,O_RDWR | O_CREAT | O_TRUNC,unixmode);
+ if(com == SMBmknew)
+ {
+ /* We should fail if file exists. */
+ ofun = 0x10;
+ }
+ else
+ {
+ /* SMBcreate - Create if file doesn't exist, truncate if it does. */
+ ofun = 0x12;
+ }
+
+ /* Open file in dos compatibility share mode. */
+ open_file_shared(fnum,cnum,fname,(DENY_FCB<<4)|0xF, ofun, unixmode,
+ oplock_request, NULL, NULL);
- if (!Files[fnum].open)
+ fsp = &Files[fnum];
+
+ if (!fsp->open)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
-
+ }
+
outsize = set_message(outbuf,1,0,True);
SSVAL(outbuf,smb_vwv0,fnum);
-
+
+ if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+ }
+
+ if(fsp->granted_oplock)
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+
DEBUG(2,("new file %s\n",fname));
- DEBUG(3,("%s mknew %s fd=%d fnum=%d cnum=%d dmode=%d umode=%o\n",timestring(),fname,Files[fnum].fd,fnum,cnum,createmode,unixmode));
+ DEBUG(3,("%s mknew %s fd=%d fnum=%d cnum=%d dmode=%d umode=%o\n",timestring(),fname,Files[fnum].fd_ptr->fd,fnum,cnum,createmode,unixmode));
return(outsize);
}
@@ -1132,11 +1465,15 @@ int reply_ctemp(char *inbuf,char *outbuf)
int outsize = 0;
int createmode;
mode_t unixmode;
-
+ BOOL bad_path = False;
+ files_struct *fsp;
+ int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
+
cnum = SVAL(inbuf,smb_tid);
createmode = SVAL(inbuf,smb_vwv0);
- sprintf(fname,"%s/TMXXXXXX",smb_buf(inbuf)+1);
- unix_convert(fname,cnum);
+ pstrcpy(fname,smb_buf(inbuf)+1);
+ strcat(fname,"/TMXXXXXX");
+ unix_convert(fname,cnum,0,&bad_path);
unixmode = unix_mode(cnum,createmode);
@@ -1145,22 +1482,48 @@ int reply_ctemp(char *inbuf,char *outbuf)
return(ERROR(ERRSRV,ERRnofids));
if (!check_name(fname,cnum))
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
strcpy(fname2,(char *)mktemp(fname));
- open_file(fnum,cnum,fname2,O_RDWR | O_CREAT | O_TRUNC,unixmode);
+ /* Open file in dos compatibility share mode. */
+ /* We should fail if file exists. */
+ open_file_shared(fnum,cnum,fname2,(DENY_FCB<<4)|0xF, 0x10, unixmode,
+ oplock_request, NULL, NULL);
- if (!Files[fnum].open)
+ fsp = &Files[fnum];
+
+ if (!fsp->open)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
outsize = set_message(outbuf,1,2 + strlen(fname2),True);
SSVAL(outbuf,smb_vwv0,fnum);
CVAL(smb_buf(outbuf),0) = 4;
strcpy(smb_buf(outbuf) + 1,fname2);
+
+ if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+ }
+ if(fsp->granted_oplock)
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+
DEBUG(2,("created temp file %s\n",fname2));
- DEBUG(3,("%s ctemp %s fd=%d fnum=%d cnum=%d dmode=%d umode=%o\n",timestring(),fname2,Files[fnum].fd,fnum,cnum,createmode,unixmode));
+ DEBUG(3,("%s ctemp %s fd=%d fnum=%d cnum=%d dmode=%d umode=%o\n",timestring(),fname2,Files[fnum].fd_ptr->fd,fnum,cnum,createmode,unixmode));
return(outsize);
}
@@ -1179,7 +1542,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);
@@ -1202,17 +1567,18 @@ int reply_unlink(char *inbuf,char *outbuf)
int error = ERRnoaccess;
BOOL has_wild;
BOOL exists=False;
+ BOOL bad_path = False;
*directory = *mask = 0;
cnum = SVAL(inbuf,smb_tid);
dirtype = SVAL(inbuf,smb_vwv0);
- strcpy(name,smb_buf(inbuf) + 1);
+ pstrcpy(name,smb_buf(inbuf) + 1);
DEBUG(3,("reply_unlink : %s\n",name));
- unix_convert(name,cnum);
+ unix_convert(name,cnum,0,&bad_path);
p = strrchr(name,'/');
if (!p) {
@@ -1239,7 +1605,12 @@ int reply_unlink(char *inbuf,char *outbuf)
char *dname;
if (check_name(directory,cnum))
- dirptr = OpenDir(directory);
+ dirptr = OpenDir(cnum, directory, True);
+
+ /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
+ the pattern matches against the long name, otherwise the short name
+ We don't implement this yet XXXX
+ */
if (dirptr)
{
@@ -1251,7 +1622,7 @@ int reply_unlink(char *inbuf,char *outbuf)
while ((dname = ReadDirName(dirptr)))
{
pstring fname;
- strcpy(fname,dname);
+ pstrcpy(fname,dname);
if(!mask_match(fname, mask, case_sensitive, False)) continue;
@@ -1269,7 +1640,14 @@ int reply_unlink(char *inbuf,char *outbuf)
if (exists)
return(ERROR(ERRDOS,error));
else
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,error));
+ }
}
outsize = set_message(outbuf,0,0,True);
@@ -1285,12 +1663,26 @@ int reply_readbraw(char *inbuf, char *outbuf)
{
int cnum,maxcount,mincount,fnum;
int nread = 0;
- int startpos;
+ uint32 startpos;
char *header = outbuf;
int ret=0;
int fd;
char *fname;
+ /*
+ * Special check if an oplock break has been issued
+ * and the readraw request croses on the wire, we must
+ * return a zero length response here.
+ */
+
+ if(global_oplock_break)
+ {
+ _smb_setlen(header,0);
+ transfer_file(0,Client,0,header,4,0);
+ DEBUG(5,("readbraw - oplock break finished\n"));
+ return -1;
+ }
+
cnum = SVAL(inbuf,smb_tid);
fnum = GETFNUM(inbuf,smb_vwv0);
@@ -1311,7 +1703,7 @@ int reply_readbraw(char *inbuf, char *outbuf)
}
else
{
- fd = Files[fnum].fd;
+ fd = Files[fnum].fd_ptr->fd;
fname = Files[fnum].name;
}
@@ -1323,13 +1715,13 @@ int reply_readbraw(char *inbuf, char *outbuf)
if (size < sizeneeded) {
struct stat st;
- if (fstat(Files[fnum].fd,&st) == 0)
+ if (fstat(Files[fnum].fd_ptr->fd,&st) == 0)
size = st.st_size;
if (!Files[fnum].can_write)
Files[fnum].size = size;
}
- nread = MIN(maxcount,size - startpos);
+ nread = MIN(maxcount,(int)(size - startpos));
}
if (nread < mincount)
@@ -1345,8 +1737,10 @@ int reply_readbraw(char *inbuf, char *outbuf)
int predict=0;
_smb_setlen(header,nread);
+#if USE_READ_PREDICTION
if (!Files[fnum].can_write)
predict = read_predict(fd,startpos,header+4,NULL,nread);
+#endif
if ((nread-predict) > 0)
seek_file(fnum,startpos + predict);
@@ -1360,7 +1754,7 @@ int reply_readbraw(char *inbuf, char *outbuf)
fname,startpos,nread,ret));
#else
- ret = read_file(fnum,header+4,startpos,nread,nread,-1,False);
+ ret = read_file(fnum,header+4,startpos,nread);
if (ret < mincount) ret = 0;
_smb_setlen(header,ret);
@@ -1402,7 +1796,7 @@ int reply_lockread(char *inbuf,char *outbuf)
if(!do_lock( fnum, cnum, numtoread, startpos, &eclass, &ecode))
return (ERROR(eclass,ecode));
- nread = read_file(fnum,data,startpos,numtoread,numtoread,-1,False);
+ nread = read_file(fnum,data,startpos,numtoread);
if (nread < 0)
return(UNIXERROR(ERRDOS,ERRnoaccess));
@@ -1426,7 +1820,7 @@ int reply_read(char *inbuf,char *outbuf)
int cnum,numtoread,fnum;
int nread = 0;
char *data;
- int startpos;
+ uint32 startpos;
int outsize = 0;
cnum = SVAL(inbuf,smb_tid);
@@ -1447,7 +1841,7 @@ int reply_read(char *inbuf,char *outbuf)
return(ERROR(ERRDOS,ERRlock));
if (numtoread > 0)
- nread = read_file(fnum,data,startpos,numtoread,numtoread,-1,False);
+ nread = read_file(fnum,data,startpos,numtoread);
if (nread < 0)
return(UNIXERROR(ERRDOS,ERRnoaccess));
@@ -1469,8 +1863,6 @@ int reply_read(char *inbuf,char *outbuf)
****************************************************************************/
int reply_read_and_X(char *inbuf,char *outbuf,int length,int bufsize)
{
- int smb_com2 = CVAL(inbuf,smb_vwv0);
- int smb_off2 = SVAL(inbuf,smb_vwv1);
int fnum = GETFNUM(inbuf,smb_vwv2);
uint32 smb_offs = IVAL(inbuf,smb_vwv3);
int smb_maxcnt = SVAL(inbuf,smb_vwv5);
@@ -1478,7 +1870,6 @@ int reply_read_and_X(char *inbuf,char *outbuf,int length,int bufsize)
int cnum;
int nread = -1;
char *data;
- int outsize = 0;
BOOL ok = False;
cnum = SVAL(inbuf,smb_tid);
@@ -1487,38 +1878,28 @@ int reply_read_and_X(char *inbuf,char *outbuf,int length,int bufsize)
CHECK_READ(fnum);
CHECK_ERROR(fnum);
- outsize = set_message(outbuf,12,0,True);
+ set_message(outbuf,12,0,True);
data = smb_buf(outbuf);
if (is_locked(fnum,cnum,smb_maxcnt,smb_offs))
return(ERROR(ERRDOS,ERRlock));
- nread = read_file(fnum,data,smb_offs,smb_maxcnt,smb_maxcnt,-1,False);
+ nread = read_file(fnum,data,smb_offs,smb_maxcnt);
ok = True;
if (nread < 0)
return(UNIXERROR(ERRDOS,ERRnoaccess));
- outsize += nread;
- CVAL(outbuf,smb_vwv0) = smb_com2;
- SSVAL(outbuf,smb_vwv1,(outsize+chain_size)-4);
SSVAL(outbuf,smb_vwv5,nread);
- SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf) + chain_size);
+ SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
SSVAL(smb_buf(outbuf),-2,nread);
- DEBUG(3,("%s readX fnum=%d cnum=%d min=%d max=%d nread=%d com2=%d off2=%d\n",
+ DEBUG(3,("%s readX fnum=%d cnum=%d min=%d max=%d nread=%d\n",
timestring(),fnum,cnum,
- smb_mincnt,smb_maxcnt,nread,smb_com2,smb_off2));
+ smb_mincnt,smb_maxcnt,nread));
chain_fnum = fnum;
- if (smb_com2 != 0xFF)
- outsize += chain_reply(smb_com2,inbuf,inbuf+smb_off2+4,
- outbuf,outbuf+outsize,
- length,bufsize);
-
- chain_fnum = -1;
-
- return(outsize);
+ return chain_reply(inbuf,outbuf,length,bufsize);
}
@@ -1587,7 +1968,7 @@ int reply_writebraw(char *inbuf,char *outbuf)
send_smb(Client,outbuf);
/* Now read the raw data into the buffer and write it */
- if(read_smb_length(Client,inbuf,0) == -1) {
+ if (read_smb_length(Client,inbuf,SMB_SECONDARY_WAIT) == -1) {
exit_server("secondary writebraw failed");
}
@@ -1600,7 +1981,7 @@ int reply_writebraw(char *inbuf,char *outbuf)
tcount,nwritten,numtowrite));
}
- nwritten = transfer_file(Client,Files[fnum].fd,numtowrite,NULL,0,
+ nwritten = transfer_file(Client,Files[fnum].fd_ptr->fd,numtowrite,NULL,0,
startpos+nwritten);
total_written += nwritten;
@@ -1720,7 +2101,7 @@ int reply_write(char *inbuf,char *outbuf,int dum1,int dum2)
zero then the file size should be extended or
truncated to the size given in smb_vwv[2-3] */
if(numtowrite == 0)
- nwritten = set_filelen(Files[fnum].fd, startpos);
+ nwritten = set_filelen(Files[fnum].fd_ptr->fd, startpos);
else
nwritten = write_file(fnum,data,numtowrite);
@@ -1750,8 +2131,6 @@ 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 smb_com2 = CVAL(inbuf,smb_vwv0);
- int smb_off2 = SVAL(inbuf,smb_vwv1);
int fnum = GETFNUM(inbuf,smb_vwv2);
uint32 smb_offs = IVAL(inbuf,smb_vwv3);
int smb_dsize = SVAL(inbuf,smb_vwv10);
@@ -1759,7 +2138,6 @@ int reply_write_and_X(char *inbuf,char *outbuf,int length,int bufsize)
BOOL write_through = BITSETW(inbuf+smb_vwv7,0);
int cnum;
int nwritten = -1;
- int outsize = 0;
char *data;
cnum = SVAL(inbuf,smb_tid);
@@ -1787,10 +2165,8 @@ int reply_write_and_X(char *inbuf,char *outbuf,int length,int bufsize)
if(((nwritten == 0) && (smb_dsize != 0))||(nwritten < 0))
return(UNIXERROR(ERRDOS,ERRnoaccess));
- outsize = set_message(outbuf,6,0,True);
+ set_message(outbuf,6,0,True);
- CVAL(outbuf,smb_vwv0) = smb_com2;
- SSVAL(outbuf,smb_vwv1,(outsize+chain_size)-4);
SSVAL(outbuf,smb_vwv2,nwritten);
if (nwritten < smb_dsize) {
@@ -1805,14 +2181,7 @@ int reply_write_and_X(char *inbuf,char *outbuf,int length,int bufsize)
if (lp_syncalways(SNUM(cnum)) || write_through)
sync_file(fnum);
- if (smb_com2 != 0xFF)
- outsize += chain_reply(smb_com2,inbuf,inbuf+smb_off2+4,
- outbuf,outbuf+outsize,
- length,bufsize);
-
- chain_fnum = -1;
-
- return(outsize);
+ return chain_reply(inbuf,outbuf,length,bufsize);
}
@@ -1845,7 +2214,7 @@ int reply_lseek(char *inbuf,char *outbuf)
umode = SEEK_SET; break;
}
- res = lseek(Files[fnum].fd,startpos,umode);
+ res = lseek(Files[fnum].fd_ptr->fd,startpos,umode);
Files[fnum].pos = res;
outsize = set_message(outbuf,2,0,True);
@@ -1924,17 +2293,17 @@ 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);
+ set_filetime(cnum, Files[fnum].name,mtime);
+
+ close_file(fnum,True);
/* We have a cached error */
if(eclass || err)
return(ERROR(eclass,err));
DEBUG(3,("%s close fd=%d fnum=%d cnum=%d (numopen=%d)\n",
- timestring(),Files[fnum].fd,fnum,cnum,
+ timestring(),Files[fnum].fd_ptr->fd,fnum,cnum,
Connections[cnum].num_files_open));
return(outsize);
@@ -1972,10 +2341,10 @@ int reply_writeclose(char *inbuf,char *outbuf)
nwritten = write_file(fnum,data,numtowrite);
- close_file(fnum);
-
- set_filetime(Files[fnum].name,mtime);
+ set_filetime(cnum, Files[fnum].name,mtime);
+ close_file(fnum,True);
+
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));
@@ -2010,7 +2379,7 @@ int reply_lock(char *inbuf,char *outbuf)
count = IVAL(inbuf,smb_vwv1);
offset = IVAL(inbuf,smb_vwv3);
- DEBUG(3,("%s lock fd=%d fnum=%d cnum=%d ofs=%d cnt=%d\n",timestring(),Files[fnum].fd,fnum,cnum,offset,count));
+ DEBUG(3,("%s lock fd=%d fnum=%d cnum=%d ofs=%d cnt=%d\n",timestring(),Files[fnum].fd_ptr->fd,fnum,cnum,offset,count));
if(!do_lock( fnum, cnum, count, offset, &eclass, &ecode))
return (ERROR(eclass,ecode));
@@ -2042,7 +2411,7 @@ int reply_unlock(char *inbuf,char *outbuf)
if(!do_unlock(fnum, cnum, count, offset, &eclass, &ecode))
return (ERROR(eclass,ecode));
- DEBUG(3,("%s unlock fd=%d fnum=%d cnum=%d ofs=%d cnt=%d\n",timestring(),Files[fnum].fd,fnum,cnum,offset,count));
+ DEBUG(3,("%s unlock fd=%d fnum=%d cnum=%d ofs=%d cnt=%d\n",timestring(),Files[fnum].fd_ptr->fd,fnum,cnum,offset,count));
return(outsize);
}
@@ -2053,15 +2422,21 @@ int reply_unlock(char *inbuf,char *outbuf)
****************************************************************************/
int reply_tdis(char *inbuf,char *outbuf)
{
- int cnum, uid;
+ int cnum;
int outsize = set_message(outbuf,0,0,True);
-
+ uint16 vuid;
+
cnum = SVAL(inbuf,smb_tid);
- uid = SVAL(inbuf,smb_uid);
+ vuid = SVAL(inbuf,smb_uid);
+
+ if (!OPEN_CNUM(cnum)) {
+ DEBUG(4,("Invalid cnum in tdis (%d)\n",cnum));
+ return(ERROR(ERRSRV,ERRinvnid));
+ }
Connections[cnum].used = False;
- close_cnum(cnum,uid);
+ close_cnum(cnum,vuid);
DEBUG(3,("%s tdis cnum=%d\n",timestring(),cnum));
@@ -2083,11 +2458,17 @@ int reply_echo(char *inbuf,char *outbuf)
cnum = SVAL(inbuf,smb_tid);
+ /* According to the latest CIFS spec we shouldn't
+ care what the TID is.
+ */
+
+#if 0
if (cnum != 0xFFFF && !OPEN_CNUM(cnum))
{
DEBUG(4,("Invalid cnum in echo (%d)\n",cnum));
return(ERROR(ERRSRV,ERRinvnid));
}
+#endif
/* copy any incoming data back out */
if (data_len > 0)
@@ -2135,7 +2516,7 @@ int reply_printopen(char *inbuf,char *outbuf)
{
pstring s;
char *p;
- StrnCpy(s,smb_buf(inbuf)+1,sizeof(pstring)-1);
+ pstrcpy(s,smb_buf(inbuf)+1);
p = s;
while (*p)
{
@@ -2158,8 +2539,9 @@ int reply_printopen(char *inbuf,char *outbuf)
if (!check_name(fname2,cnum))
return(ERROR(ERRDOS,ERRnoaccess));
- open_file(fnum,cnum,fname2,O_WRONLY | O_CREAT | O_TRUNC,
- unix_mode(cnum,0));
+ /* Open for exclusive use, write only. */
+ open_file_shared(fnum,cnum,fname2,(DENY_ALL<<4)|1, 0x12, unix_mode(cnum,0),
+ 0, NULL, NULL);
if (!Files[fnum].open)
return(UNIXERROR(ERRDOS,ERRnoaccess));
@@ -2170,7 +2552,7 @@ int reply_printopen(char *inbuf,char *outbuf)
outsize = set_message(outbuf,1,0,True);
SSVAL(outbuf,smb_vwv0,fnum);
- DEBUG(3,("%s openprint %s fd=%d fnum=%d cnum=%d\n",timestring(),fname2,Files[fnum].fd,fnum,cnum));
+ DEBUG(3,("%s openprint %s fd=%d fnum=%d cnum=%d\n",timestring(),fname2,Files[fnum].fd_ptr->fd,fnum,cnum));
return(outsize);
}
@@ -2193,9 +2575,9 @@ int reply_printclose(char *inbuf,char *outbuf)
if (!CAN_PRINT(cnum))
return(ERROR(ERRDOS,ERRnoaccess));
- close_file(fnum);
+ close_file(fnum,True);
- DEBUG(3,("%s printclose fd=%d fnum=%d cnum=%d\n",timestring(),Files[fnum].fd,fnum,cnum));
+ DEBUG(3,("%s printclose fd=%d fnum=%d cnum=%d\n",timestring(),Files[fnum].fd_ptr->fd,fnum,cnum));
return(outsize);
}
@@ -2206,13 +2588,14 @@ int reply_printclose(char *inbuf,char *outbuf)
****************************************************************************/
int reply_printqueue(char *inbuf,char *outbuf)
{
- int cnum, uid;
+ int cnum;
int outsize = set_message(outbuf,2,3,True);
int max_count = SVAL(inbuf,smb_vwv0);
int start_index = SVAL(inbuf,smb_vwv1);
+ uint16 vuid;
cnum = SVAL(inbuf,smb_tid);
- uid = SVAL(inbuf,smb_uid);
+ vuid = SVAL(inbuf,smb_uid);
/* allow checking the queue for anyone */
#if 0
@@ -2248,7 +2631,7 @@ int reply_printqueue(char *inbuf,char *outbuf)
DEBUG(5,("connection not open or not a printer, using cnum %d\n",cnum));
}
- if (!become_user(cnum,uid))
+ if (!become_user(&Connections[cnum], cnum, vuid))
return(ERROR(ERRSRV,ERRinvnid));
{
@@ -2269,7 +2652,7 @@ int reply_printqueue(char *inbuf,char *outbuf)
{
put_dos_date2(p,0,queue[i].time);
CVAL(p,4) = (queue[i].status==LPQ_PRINTING?2:3);
- SSVAL(p,5,queue[i].job);
+ SSVAL(p,5,printjob_encode(SNUM(cnum), queue[i].job));
SIVAL(p,7,queue[i].size);
CVAL(p,11) = 0;
StrnCpy(p+12,queue[i].user,16);
@@ -2334,17 +2717,25 @@ int reply_mkdir(char *inbuf,char *outbuf)
pstring directory;
int cnum;
int outsize,ret= -1;
-
- strcpy(directory,smb_buf(inbuf) + 1);
+ BOOL bad_path = False;
+
+ pstrcpy(directory,smb_buf(inbuf) + 1);
cnum = SVAL(inbuf,smb_tid);
- unix_convert(directory,cnum);
+ unix_convert(directory,cnum,0,&bad_path);
if (check_name(directory,cnum))
ret = sys_mkdir(directory,unix_mode(cnum,aDIR));
if (ret < 0)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
-
+ }
+
outsize = set_message(outbuf,0,0,True);
DEBUG(3,("%s mkdir %s cnum=%d ret=%d\n",timestring(),directory,cnum,ret));
@@ -2352,6 +2743,66 @@ int reply_mkdir(char *inbuf,char *outbuf)
return(outsize);
}
+/****************************************************************************
+Static function used by reply_rmdir to delete an entire directory
+tree recursively.
+****************************************************************************/
+static BOOL recursive_rmdir(char *directory)
+{
+ char *dname = NULL;
+ BOOL ret = False;
+ void *dirptr = OpenDir(-1, directory, False);
+
+ if(dirptr == NULL)
+ return True;
+
+ while((dname = ReadDirName(dirptr)))
+ {
+ pstring fullname;
+ struct stat st;
+
+ if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
+ continue;
+
+ /* Construct the full name. */
+ if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname))
+ {
+ errno = ENOMEM;
+ ret = True;
+ break;
+ }
+ strcpy(fullname, directory);
+ strcat(fullname, "/");
+ strcat(fullname, dname);
+
+ if(sys_lstat(fullname, &st) != 0)
+ {
+ ret = True;
+ break;
+ }
+
+ if(st.st_mode & S_IFDIR)
+ {
+ if(recursive_rmdir(fullname)!=0)
+ {
+ ret = True;
+ break;
+ }
+ if(sys_rmdir(fullname) != 0)
+ {
+ ret = True;
+ break;
+ }
+ }
+ else if(sys_unlink(fullname) != 0)
+ {
+ ret = True;
+ break;
+ }
+ }
+ CloseDir(dirptr);
+ return ret;
+}
/****************************************************************************
reply to a rmdir
@@ -2362,23 +2813,102 @@ int reply_rmdir(char *inbuf,char *outbuf)
int cnum;
int outsize = 0;
BOOL ok = False;
-
+ BOOL bad_path = False;
+
cnum = SVAL(inbuf,smb_tid);
- strcpy(directory,smb_buf(inbuf) + 1);
- unix_convert(directory,cnum);
+ pstrcpy(directory,smb_buf(inbuf) + 1);
+ unix_convert(directory,cnum,0,&bad_path);
if (check_name(directory,cnum))
{
+
dptr_closepath(directory,SVAL(inbuf,smb_pid));
ok = (sys_rmdir(directory) == 0);
+ if(!ok && (errno == ENOTEMPTY) && lp_veto_files(SNUM(cnum)))
+ {
+ /* Check to see if the only thing in this directory are
+ vetoed files/directories. If so then delete them and
+ retry. If we fail to delete any of them (and we *don't*
+ do a recursive delete) then fail the rmdir. */
+ BOOL all_veto_files = True;
+ char *dname;
+ void *dirptr = OpenDir(cnum, directory, False);
+
+ if(dirptr != NULL)
+ {
+ int dirpos = TellDir(dirptr);
+ while ((dname = ReadDirName(dirptr)))
+ {
+ if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
+ continue;
+ if(!IS_VETO_PATH(cnum, dname))
+ {
+ all_veto_files = False;
+ break;
+ }
+ }
+ if(all_veto_files)
+ {
+ SeekDir(dirptr,dirpos);
+ while ((dname = ReadDirName(dirptr)))
+ {
+ pstring fullname;
+ struct stat st;
+
+ if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
+ continue;
+
+ /* Construct the full name. */
+ if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname))
+ {
+ errno = ENOMEM;
+ break;
+ }
+ pstrcpy(fullname, directory);
+ strcat(fullname, "/");
+ strcat(fullname, dname);
+
+ if(sys_lstat(fullname, &st) != 0)
+ break;
+ if(st.st_mode & S_IFDIR)
+ {
+ if(lp_recursive_veto_delete(SNUM(cnum)))
+ {
+ if(recursive_rmdir(fullname) != 0)
+ break;
+ }
+ if(sys_rmdir(fullname) != 0)
+ break;
+ }
+ else if(sys_unlink(fullname) != 0)
+ break;
+ }
+ CloseDir(dirptr);
+ /* Retry the rmdir */
+ ok = (sys_rmdir(directory) == 0);
+ }
+ else
+ CloseDir(dirptr);
+ }
+ else
+ errno = ENOTEMPTY;
+ }
+
if (!ok)
- DEBUG(3,("couldn't remove directory %s : %s\n",
+ DEBUG(3,("couldn't remove directory %s : %s\n",
directory,strerror(errno)));
}
if (!ok)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRbadpath));
-
+ }
+
outsize = set_message(outbuf,0,0,True);
DEBUG(3,("%s rmdir %s\n",timestring(),directory));
@@ -2401,21 +2931,21 @@ static BOOL resolve_wildcards(char *name1,char *name2)
if (!name1 || !name2) return(False);
- strcpy(root1,name1);
- strcpy(root2,name2);
+ fstrcpy(root1,name1);
+ fstrcpy(root2,name2);
p = strrchr(root1,'.');
if (p) {
*p = 0;
- strcpy(ext1,p+1);
+ fstrcpy(ext1,p+1);
} else {
- strcpy(ext1,"");
+ fstrcpy(ext1,"");
}
p = strrchr(root2,'.');
if (p) {
*p = 0;
- strcpy(ext2,p+1);
+ fstrcpy(ext2,p+1);
} else {
- strcpy(ext2,"");
+ fstrcpy(ext2,"");
}
p = root1;
@@ -2476,32 +3006,45 @@ int reply_mv(char *inbuf,char *outbuf)
int cnum;
pstring directory;
pstring mask,newname;
+ pstring newname_last_component;
char *p;
int count=0;
int error = ERRnoaccess;
BOOL has_wild;
BOOL exists=False;
+ BOOL bad_path1 = False;
+ BOOL bad_path2 = False;
*directory = *mask = 0;
cnum = SVAL(inbuf,smb_tid);
- strcpy(name,smb_buf(inbuf) + 1);
- strcpy(newname,smb_buf(inbuf) + 3 + strlen(name));
+ pstrcpy(name,smb_buf(inbuf) + 1);
+ pstrcpy(newname,smb_buf(inbuf) + 3 + strlen(name));
DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
- unix_convert(name,cnum);
- unix_convert(newname,cnum);
+ unix_convert(name,cnum,0,&bad_path1);
+ unix_convert(newname,cnum,newname_last_component,&bad_path2);
+
+ /*
+ * Split the old name into directory and last component
+ * strings. Note that unix_convert may have stripped off a
+ * leading ./ from both name and newname if the rename is
+ * at the root of the share. We need to make sure either both
+ * name and newname contain a / character or neither of them do
+ * as this is checked in resolve_wildcards().
+ */
p = strrchr(name,'/');
if (!p) {
- strcpy(directory,"./");
+ strcpy(directory,".");
strcpy(mask,name);
} else {
*p = 0;
strcpy(directory,name);
strcpy(mask,p+1);
+ *p = '/'; /* Replace needed for exceptional test below. */
}
if (is_mangled(mask))
@@ -2510,12 +3053,64 @@ int reply_mv(char *inbuf,char *outbuf)
has_wild = strchr(mask,'*') || strchr(mask,'?');
if (!has_wild) {
+ BOOL is_short_name = is_8_3(name, True);
+
+ /* Add a terminating '/' to the directory name. */
strcat(directory,"/");
strcat(directory,mask);
+
+ /* Ensure newname contains a '/' also */
+ if(strrchr(newname,'/') == 0) {
+ pstring tmpstr;
+
+ strcpy(tmpstr, "./");
+ strcat(tmpstr, newname);
+ strcpy(newname, tmpstr);
+ }
+
+ DEBUG(3,("reply_mv : case_sensitive = %d, case_preserve = %d, short case preserve = %d, directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n",
+ case_sensitive, case_preserve, short_case_preserve, directory,
+ newname, newname_last_component, is_short_name));
+
+ /*
+ * Check for special case with case preserving and not
+ * case sensitive, if directory and newname are identical,
+ * and the old last component differs from the original
+ * last component only by case, then we should allow
+ * the rename (user is trying to change the case of the
+ * filename).
+ */
+ if((case_sensitive == False) && ( ((case_preserve == True) && (is_short_name == False)) ||
+ ((short_case_preserve == True) && (is_short_name == True))) &&
+ strcsequal(directory, newname)) {
+ pstring newname_modified_last_component;
+
+ /*
+ * Get the last component of the modified name.
+ * Note that we guarantee that newname contains a '/'
+ * character above.
+ */
+ p = strrchr(newname,'/');
+ strcpy(newname_modified_last_component,p+1);
+
+ if(strcsequal(newname_modified_last_component,
+ newname_last_component) == False) {
+ /*
+ * Replace the modified last component with
+ * the original.
+ */
+ strcpy(p+1, newname_last_component);
+ }
+ }
+
if (resolve_wildcards(directory,newname) &&
can_rename(directory,cnum) &&
!file_exist(newname,NULL) &&
!sys_rename(directory,newname)) count++;
+
+ DEBUG(3,("reply_mv : %s doing rename on %s -> %s\n",(count != 0) ? "succeeded" : "failed",
+ directory,newname));
+
if (!count) exists = file_exist(directory,NULL);
if (!count && exists && file_exist(newname,NULL)) {
exists = True;
@@ -2527,7 +3122,7 @@ int reply_mv(char *inbuf,char *outbuf)
pstring destname;
if (check_name(directory,cnum))
- dirptr = OpenDir(directory);
+ dirptr = OpenDir(cnum, directory, True);
if (dirptr)
{
@@ -2539,14 +3134,14 @@ int reply_mv(char *inbuf,char *outbuf)
while ((dname = ReadDirName(dirptr)))
{
pstring fname;
- strcpy(fname,dname);
+ pstrcpy(fname,dname);
if(!mask_match(fname, mask, case_sensitive, False)) continue;
error = ERRnoaccess;
sprintf(fname,"%s/%s",directory,dname);
if (!can_rename(fname,cnum)) continue;
- strcpy(destname,newname);
+ pstrcpy(destname,newname);
if (!resolve_wildcards(fname,destname)) continue;
@@ -2565,7 +3160,14 @@ int reply_mv(char *inbuf,char *outbuf)
if (exists)
return(ERROR(ERRDOS,error));
else
+ {
+ if((errno == ENOENT) && (bad_path1 || bad_path2))
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,error));
+ }
}
outsize = set_message(outbuf,0,0,True);
@@ -2585,7 +3187,7 @@ static BOOL copy_file(char *src,char *dest1,int cnum,int ofun,
int fnum1,fnum2;
pstring dest;
- strcpy(dest,dest1);
+ pstrcpy(dest,dest1);
if (target_is_directory) {
char *p = strrchr(src,'/');
if (p)
@@ -2601,7 +3203,7 @@ static BOOL copy_file(char *src,char *dest1,int cnum,int ofun,
fnum1 = find_free_file();
if (fnum1<0) return(False);
open_file_shared(fnum1,cnum,src,(DENY_NONE<<4),
- 1,0,&Access,&action);
+ 1,0,0,&Access,&action);
if (!Files[fnum1].open) return(False);
@@ -2610,26 +3212,26 @@ static BOOL copy_file(char *src,char *dest1,int cnum,int ofun,
fnum2 = find_free_file();
if (fnum2<0) {
- close_file(fnum1);
+ close_file(fnum1,False);
return(False);
}
open_file_shared(fnum2,cnum,dest,(DENY_NONE<<4)|1,
- ofun,st.st_mode,&Access,&action);
+ ofun,st.st_mode,0,&Access,&action);
if (!Files[fnum2].open) {
- close_file(fnum1);
+ close_file(fnum1,False);
return(False);
}
if ((ofun&3) == 1) {
- lseek(Files[fnum2].fd,0,SEEK_END);
+ lseek(Files[fnum2].fd_ptr->fd,0,SEEK_END);
}
if (st.st_size)
- ret = transfer_file(Files[fnum1].fd,Files[fnum2].fd,st.st_size,NULL,0,0);
+ ret = transfer_file(Files[fnum1].fd_ptr->fd,Files[fnum2].fd_ptr->fd,st.st_size,NULL,0,0);
- close_file(fnum1);
- close_file(fnum2);
+ close_file(fnum1,False);
+ close_file(fnum2,False);
return(ret == st.st_size);
}
@@ -2655,13 +3257,15 @@ int reply_copy(char *inbuf,char *outbuf)
int ofun = SVAL(inbuf,smb_vwv1);
int flags = SVAL(inbuf,smb_vwv2);
BOOL target_is_directory=False;
+ BOOL bad_path1 = False;
+ BOOL bad_path2 = False;
*directory = *mask = 0;
cnum = SVAL(inbuf,smb_tid);
- strcpy(name,smb_buf(inbuf));
- strcpy(newname,smb_buf(inbuf) + 1 + strlen(name));
+ pstrcpy(name,smb_buf(inbuf));
+ pstrcpy(newname,smb_buf(inbuf) + 1 + strlen(name));
DEBUG(3,("reply_copy : %s -> %s\n",name,newname));
@@ -2671,8 +3275,8 @@ int reply_copy(char *inbuf,char *outbuf)
return(ERROR(ERRSRV,ERRinvdevice));
}
- unix_convert(name,cnum);
- unix_convert(newname,cnum);
+ unix_convert(name,cnum,0,&bad_path1);
+ unix_convert(newname,cnum,0,&bad_path2);
target_is_directory = directory_exist(newname,NULL);
@@ -2718,7 +3322,7 @@ int reply_copy(char *inbuf,char *outbuf)
pstring destname;
if (check_name(directory,cnum))
- dirptr = OpenDir(directory);
+ dirptr = OpenDir(cnum, directory, True);
if (dirptr)
{
@@ -2730,7 +3334,7 @@ int reply_copy(char *inbuf,char *outbuf)
while ((dname = ReadDirName(dirptr)))
{
pstring fname;
- strcpy(fname,dname);
+ pstrcpy(fname,dname);
if(!mask_match(fname, mask, case_sensitive, False)) continue;
@@ -2750,7 +3354,14 @@ int reply_copy(char *inbuf,char *outbuf)
if (exists)
return(ERROR(ERRDOS,error));
else
+ {
+ if((errno == ENOENT) && (bad_path1 || bad_path2))
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,error));
+ }
}
outsize = set_message(outbuf,1,0,True);
@@ -2777,7 +3388,7 @@ int reply_setdir(char *inbuf,char *outbuf)
if (!CAN_SETDIR(snum))
return(ERROR(ERRDOS,ERRnoaccess));
- strcpy(newdir,smb_buf(inbuf) + 1);
+ pstrcpy(newdir,smb_buf(inbuf) + 1);
strlower(newdir);
if (strlen(newdir) == 0)
@@ -2806,10 +3417,11 @@ int reply_setdir(char *inbuf,char *outbuf)
****************************************************************************/
int reply_lockingX(char *inbuf,char *outbuf,int length,int bufsize)
{
- int smb_com2 = CVAL(inbuf,smb_vwv0);
- int smb_off2 = SVAL(inbuf,smb_vwv1);
int fnum = GETFNUM(inbuf,smb_vwv2);
- uint16 locktype = SVAL(inbuf,smb_vwv3);
+ unsigned char locktype = CVAL(inbuf,smb_vwv3);
+#if 0
+ unsigned char oplocklevel = CVAL(inbuf,smb_vwv3+1);
+#endif
uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
uint16 num_locks = SVAL(inbuf,smb_vwv7);
uint32 count, offset;
@@ -2818,7 +3430,7 @@ int reply_lockingX(char *inbuf,char *outbuf,int length,int bufsize)
int i;
char *data;
uint32 ecode=0, dummy2;
- int outsize, eclass=0, dummy1;
+ int eclass=0, dummy1;
cnum = SVAL(inbuf,smb_tid);
@@ -2826,6 +3438,48 @@ int reply_lockingX(char *inbuf,char *outbuf,int length,int bufsize)
CHECK_ERROR(fnum);
data = smb_buf(inbuf);
+
+ /* Check if this is an oplock break on a file
+ we have granted an oplock on.
+ */
+ if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE))
+ {
+ int token;
+ files_struct *fsp = &Files[fnum];
+ uint32 dev = fsp->fd_ptr->dev;
+ uint32 inode = fsp->fd_ptr->inode;
+
+ DEBUG(5,("reply_lockingX: oplock break reply from client for fnum = %d\n",
+ fnum));
+ /*
+ * Make sure we have granted an oplock on this file.
+ */
+ if(!fsp->granted_oplock)
+ {
+ DEBUG(0,("reply_lockingX: Error : oplock break from client for fnum = %d and \
+no oplock granted on this file.\n", fnum));
+ return ERROR(ERRDOS,ERRlock);
+ }
+
+ /* Remove the oplock flag from the sharemode. */
+ lock_share_entry(fsp->cnum, dev, inode, &token);
+ if(remove_share_oplock( fnum, token)==False) {
+ DEBUG(0,("reply_lockingX: failed to remove share oplock for fnum %d, \
+dev = %x, inode = %x\n",
+ fnum, dev, inode));
+ unlock_share_entry(fsp->cnum, dev, inode, token);
+ } else {
+ unlock_share_entry(fsp->cnum, dev, inode, token);
+
+ /* Clear the granted flag and return. */
+ fsp->granted_oplock = False;
+ }
+
+ /* if this is a pure oplock break request then don't send a reply */
+ if (num_locks == 0 && num_ulocks == 0)
+ return -1;
+ }
+
/* Data now points at the beginning of the list
of smb_unlkrng structs */
for(i = 0; i < (int)num_ulocks; i++) {
@@ -2857,24 +3511,14 @@ int reply_lockingX(char *inbuf,char *outbuf,int length,int bufsize)
return ERROR(eclass,ecode);
}
- outsize = set_message(outbuf,2,0,True);
-
- CVAL(outbuf,smb_vwv0) = smb_com2;
- SSVAL(outbuf,smb_vwv1,(outsize+chain_size)-4);
+ set_message(outbuf,2,0,True);
DEBUG(3,("%s lockingX fnum=%d cnum=%d type=%d num_locks=%d num_ulocks=%d\n",
- timestring(),fnum,cnum,locktype,num_locks,num_ulocks));
+ timestring(),fnum,cnum,(unsigned int)locktype,num_locks,num_ulocks));
chain_fnum = fnum;
- if (smb_com2 != 0xFF)
- outsize += chain_reply(smb_com2,inbuf,inbuf+smb_off2+4,
- outbuf,outbuf+outsize,
- length,bufsize);
-
- chain_fnum = -1;
-
- return(outsize);
+ return chain_reply(inbuf,outbuf,length,bufsize);
}
@@ -2887,7 +3531,7 @@ int reply_readbmpx(char *inbuf,char *outbuf,int length,int bufsize)
int nread = -1;
int total_read;
char *data;
- int32 startpos;
+ uint32 startpos;
int outsize, mincount, maxcount;
int max_per_packet;
int tcount;
@@ -2911,7 +3555,7 @@ int reply_readbmpx(char *inbuf,char *outbuf,int length,int bufsize)
mincount = SVAL(inbuf,smb_vwv4);
data = smb_buf(outbuf);
- pad = ((int)data)%4;
+ pad = ((long)data)%4;
if (pad) pad = 4 - pad;
data += pad;
@@ -2926,7 +3570,7 @@ int reply_readbmpx(char *inbuf,char *outbuf,int length,int bufsize)
{
int N = MIN(max_per_packet,tcount-total_read);
- nread = read_file(fnum,data,startpos,N,N,-1,False);
+ nread = read_file(fnum,data,startpos,N);
if (nread <= 0) nread = 0;
@@ -2958,7 +3602,7 @@ int reply_writebmpx(char *inbuf,char *outbuf)
int cnum,numtowrite,fnum;
int nwritten = -1;
int outsize = 0;
- int32 startpos;
+ uint32 startpos;
int tcount, write_through, smb_doff;
char *data;
@@ -3147,11 +3791,31 @@ int reply_setattrE(char *inbuf,char *outbuf)
unix_times.actime = make_unix_date2(inbuf+smb_vwv3);
unix_times.modtime = make_unix_date2(inbuf+smb_vwv5);
+ /*
+ * Patch from Ray Frush <frush@engr.colostate.edu>
+ * Sometimes times are sent as zero - ignore them.
+ */
+
+ if ((unix_times.actime == 0) && (unix_times.modtime == 0))
+ {
+ /* Ignore request */
+ DEBUG(3,("%s reply_setattrE fnum=%d cnum=%d ignoring zero request - \
+not setting timestamps of 0\n",
+ timestring(), fnum,cnum,unix_times.actime,unix_times.modtime));
+ return(outsize);
+ }
+ else if ((unix_times.actime != 0) && (unix_times.modtime == 0))
+ {
+ /* set modify time = to access time if modify time was 0 */
+ unix_times.modtime = unix_times.actime;
+ }
+
/* Set the date on this file */
- if(sys_utime(Files[fnum].name, &unix_times))
+ if(file_utime(cnum, Files[fnum].name, &unix_times))
return(ERROR(ERRDOS,ERRnoaccess));
- DEBUG(3,("%s reply_setattrE fnum=%d cnum=%d\n",timestring(),fnum,cnum));
+ DEBUG(3,("%s reply_setattrE fnum=%d cnum=%d actime=%d modtime=%d\n",
+ timestring(), fnum,cnum,unix_times.actime,unix_times.modtime));
return(outsize);
}
@@ -3176,7 +3840,7 @@ int reply_getattrE(char *inbuf,char *outbuf)
CHECK_ERROR(fnum);
/* Do an fstat on this file */
- if(fstat(Files[fnum].fd, &sbuf))
+ if(fstat(Files[fnum].fd_ptr->fd, &sbuf))
return(UNIXERROR(ERRDOS,ERRnoaccess));
mode = dos_mode(cnum,Files[fnum].name,&sbuf);
@@ -3203,8 +3867,3 @@ int reply_getattrE(char *inbuf,char *outbuf)
return(outsize);
}
-
-
-
-
-
diff --git a/source/smbd/server.c b/source/smbd/server.c
index 5d8facef33f..93042e119b0 100644
--- a/source/smbd/server.c
+++ b/source/smbd/server.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Main SMB server routines
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1997
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,29 +20,19 @@
*/
#include "includes.h"
-#include "loadparm.h"
-#include "pcap.h"
#include "trans2.h"
-#include "reply.h"
pstring servicesf = CONFIGFILE;
-pstring OriginalDir ="/";
extern pstring debugf;
extern pstring sesssetup_user;
+extern fstring myworkgroup;
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;
+int am_parent = 1;
+int atexit_set = 0;
/* the last message the was processed */
int last_message = -1;
@@ -58,18 +48,35 @@ extern BOOL case_preserve;
extern BOOL use_mangled_map;
extern BOOL short_case_preserve;
extern BOOL case_mangle;
-extern time_t smb_last_time;
+time_t smb_last_time=(time_t)0;
+
+extern int smb_read_error;
extern pstring user_socket_options;
connection_struct Connections[MAX_CONNECTIONS];
files_struct Files[MAX_OPEN_FILES];
-extern int Protocol;
+/*
+ * Indirection for file fd's. Needed as POSIX locking
+ * is based on file/process, not fd/process.
+ */
+file_fd_struct FileFd[MAX_OPEN_FILES];
+int max_file_fd_used = 0;
-int maxxmit = BUFFER_SIZE;
+extern int Protocol;
-int chain_size = 0;
+/*
+ * Size of data we can send to client. Set
+ * by the client for all protocols above CORE.
+ * Set by us for CORE protocol.
+ */
+int max_send = BUFFER_SIZE;
+/*
+ * Size of the data we can receive. Set by us.
+ * Can be modified by the max xmit parameter.
+ */
+int max_recv = BUFFER_SIZE;
/* a fnum to use when chaining */
int chain_fnum = -1;
@@ -77,8 +84,17 @@ int chain_fnum = -1;
/* number of open connections */
static int num_connections_open = 0;
+/* Oplock ipc UDP socket. */
+int oplock_sock = -1;
+uint16 oplock_port = 0;
+/* Current number of oplocks we have outstanding. */
+int32 global_oplocks_open = 0;
+
+BOOL global_oplock_break = False;
+
extern fstring remote_machine;
+extern pstring OriginalDir;
/* these can be set by some functions to override the error codes */
int unix_ERR_class=SUCCESS;
@@ -88,16 +104,9 @@ int unix_ERR_code=0;
extern int extra_time_offset;
extern pstring myhostname;
-extern struct in_addr myip;
-
static int find_free_connection(int hash);
-#ifdef SMB_PASSWD
-extern void generate_next_challenge(char *challenge);
-extern void set_challenge(char *challenge);
-#endif
-
/* for readability... */
#define IS_DOS_READONLY(test_mode) (((test_mode) & aRONLY) != 0)
#define IS_DOS_DIR(test_mode) (((test_mode) & aDIR) != 0)
@@ -105,7 +114,21 @@ extern void set_challenge(char *challenge);
#define IS_DOS_SYSTEM(test_mode) (((test_mode) & aSYSTEM) != 0)
#define IS_DOS_HIDDEN(test_mode) (((test_mode) & aHIDDEN) != 0)
-
+/****************************************************************************
+ when exiting, take the whole family
+****************************************************************************/
+void *dflt_sig(void)
+{
+ exit_server("caught signal");
+ return 0; /* Keep -Wall happy :-) */
+}
+/****************************************************************************
+ Send a SIGTERM to our process group.
+*****************************************************************************/
+void killkids(void)
+{
+ if(am_parent) kill(0,SIGTERM);
+}
/****************************************************************************
change a dos mode to a unix mode
@@ -115,8 +138,12 @@ extern void set_challenge(char *challenge);
dos archive is represented in unix by the user's execute bit
dos system is represented in unix by the group's execute bit
dos hidden is represented in unix by the other's execute bit
+ Then apply create mask,
+ then add force bits.
base permission for directories:
dos directory is represented in unix by unix's dir bit and the exec bit
+ Then apply create mask,
+ then add force bits.
****************************************************************************/
mode_t unix_mode(int cnum,int dosmode)
{
@@ -125,19 +152,29 @@ mode_t unix_mode(int cnum,int dosmode)
if ( !IS_DOS_READONLY(dosmode) )
result |= (S_IWUSR | S_IWGRP | S_IWOTH);
- if (IS_DOS_DIR(dosmode))
+ if (IS_DOS_DIR(dosmode)) {
+ /* We never make directories read only for the owner as under DOS a user
+ can always create a file in a read-only directory. */
result |= (S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH | S_IWUSR);
+ /* Apply directory mask */
+ result &= lp_dir_mode(SNUM(cnum));
+ /* Add in force bits */
+ result |= lp_force_dir_mode(SNUM(cnum));
+ } else {
+ if (MAP_ARCHIVE(cnum) && IS_DOS_ARCHIVE(dosmode))
+ result |= S_IXUSR;
+
+ if (MAP_SYSTEM(cnum) && IS_DOS_SYSTEM(dosmode))
+ result |= S_IXGRP;
- if (MAP_ARCHIVE(cnum) && IS_DOS_ARCHIVE(dosmode))
- result |= S_IXUSR;
-
- if (MAP_SYSTEM(cnum) && IS_DOS_SYSTEM(dosmode))
- result |= S_IXGRP;
-
- if (MAP_HIDDEN(cnum) && IS_DOS_HIDDEN(dosmode))
- result |= S_IXOTH;
+ if (MAP_HIDDEN(cnum) && IS_DOS_HIDDEN(dosmode))
+ result |= S_IXOTH;
- result &= CREATE_MODE(cnum);
+ /* Apply mode mask */
+ result &= lp_create_mode(SNUM(cnum));
+ /* Add in force bits */
+ result |= lp_force_create_mode(SNUM(cnum));
+ }
return(result);
}
@@ -148,33 +185,24 @@ 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;
+
+ DEBUG(8,("dos_mode: %d %s\n", cnum, path));
-#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)
+ if (MAP_ARCHIVE(cnum) && ((sbuf->st_mode & S_IXUSR) != 0))
result |= aARCH;
if (MAP_SYSTEM(cnum) && ((sbuf->st_mode & S_IXGRP) != 0))
@@ -186,10 +214,12 @@ int dos_mode(int cnum,char *path,struct stat *sbuf)
if (S_ISDIR(sbuf->st_mode))
result = aDIR | (result & aRONLY);
+#ifdef S_ISLNK
#if LINKS_READ_ONLY
if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
result |= aRONLY;
#endif
+#endif
/* hide files with a name starting with a . */
if (lp_hide_dot_files(SNUM(cnum)))
@@ -204,10 +234,26 @@ int dos_mode(int cnum,char *path,struct stat *sbuf)
result |= aHIDDEN;
}
+ /* Optimization : Only call is_hidden_path if it's not already
+ hidden. */
+ if (!(result & aHIDDEN) && IS_HIDDEN_PATH(cnum,path))
+ {
+ result |= aHIDDEN;
+ }
+
+ DEBUG(8,("dos_mode returning "));
+
+ if (result & aHIDDEN) DEBUG(8, ("h"));
+ if (result & aRONLY ) DEBUG(8, ("r"));
+ if (result & aSYSTEM) DEBUG(8, ("s"));
+ if (result & aDIR ) DEBUG(8, ("d"));
+ if (result & aARCH ) DEBUG(8, ("a"));
+
+ DEBUG(8,("\n"));
+
return(result);
}
-
/*******************************************************************
chmod a file - but preserve some bits
********************************************************************/
@@ -257,10 +303,77 @@ int dos_chmod(int cnum,char *fname,int dosmode,struct stat *st)
unixmode &= ~(S_IWUSR|S_IWGRP|S_IWOTH);
unixmode |= tmp;
}
-
- return(chmod(fname,unixmode));
+
+ return(sys_chmod(fname,unixmode));
}
+/*******************************************************************
+Wrapper around sys_utime that possibly allows DOS semantics rather
+than POSIX.
+*******************************************************************/
+
+int file_utime(int cnum, char *fname, struct utimbuf *times)
+{
+ extern struct current_user current_user;
+ struct stat sb;
+ int ret = -1;
+
+ errno = 0;
+
+ if(sys_utime(fname, times) == 0)
+ return 0;
+
+ if((errno != EPERM) && (errno != EACCES))
+ return -1;
+
+ if(!lp_dos_filetimes(SNUM(cnum)))
+ return -1;
+
+ /* We have permission (given by the Samba admin) to
+ break POSIX semantics and allow a user to change
+ the time on a file they don't own but can write to
+ (as DOS does).
+ */
+
+ if(sys_stat(fname,&sb) != 0)
+ return -1;
+
+ /* Check if we have write access. */
+ if (CAN_WRITE(cnum)) {
+ if (((sb.st_mode & S_IWOTH) ||
+ Connections[cnum].admin_user ||
+ ((sb.st_mode & S_IWUSR) && current_user.uid==sb.st_uid) ||
+ ((sb.st_mode & S_IWGRP) &&
+ in_group(sb.st_gid,current_user.gid,
+ current_user.ngroups,current_user.igroups)))) {
+ /* We are allowed to become root and change the filetime. */
+ become_root(False);
+ ret = sys_utime(fname, times);
+ unbecome_root(False);
+ }
+ }
+
+ return ret;
+}
+
+/*******************************************************************
+Change a filetime - possibly allowing DOS semantics.
+*******************************************************************/
+
+BOOL set_filetime(int cnum, char *fname, time_t mtime)
+{
+ struct utimbuf times;
+
+ if (null_mtime(mtime)) return(True);
+
+ times.modtime = times.actime = mtime;
+
+ if (file_utime(cnum, fname, &times)) {
+ DEBUG(4,("set_filetime(%s) failed: %s\n",fname,strerror(errno)));
+ }
+
+ return(True);
+}
/****************************************************************************
check if two filenames are equal
@@ -306,7 +419,7 @@ static BOOL mangled_equal(char *name1, char *name2)
{
pstring tmpname;
- if (is_8_3(name2))
+ if (is_8_3(name2, True))
return(False);
strcpy(tmpname,name2);
@@ -321,12 +434,12 @@ scan a directory to find a filename, matching without case sensitivity
If the name looks like a mangled name then try via the mangling functions
****************************************************************************/
-static BOOL scan_directory(char *path, char *name,int snum,BOOL docache)
+static BOOL scan_directory(char *path, char *name,int cnum,BOOL docache)
{
void *cur_dir;
char *dname;
BOOL mangled;
- fstring name2;
+ pstring name2;
mangled = is_mangled(name);
@@ -334,7 +447,7 @@ static BOOL scan_directory(char *path, char *name,int snum,BOOL docache)
if (*path == 0)
path = ".";
- if (docache && (dname = DirCacheCheck(path,name,snum))) {
+ if (docache && (dname = DirCacheCheck(path,name,SNUM(cnum)))) {
strcpy(name, dname);
return(True);
}
@@ -343,7 +456,7 @@ static BOOL scan_directory(char *path, char *name,int snum,BOOL docache)
check_mangled_stack(name);
/* open the directory */
- if (!(cur_dir = OpenDir(path)))
+ if (!(cur_dir = OpenDir(cnum, path, True)))
{
DEBUG(3,("scan dir didn't open dir [%s]\n",path));
return(False);
@@ -356,14 +469,14 @@ static BOOL scan_directory(char *path, char *name,int snum,BOOL docache)
(strequal(dname,".") || strequal(dname,"..")))
continue;
- strcpy(name2,dname);
- if (!name_map_mangle(name2,False,snum)) continue;
+ pstrcpy(name2,dname);
+ if (!name_map_mangle(name2,False,SNUM(cnum))) continue;
if ((mangled && mangled_equal(name,name2))
- || fname_equal(name, name2))
+ || fname_equal(name, name2)) /* name2 here was changed to dname - since 1.9.16p2 - not sure of reason (jra) */
{
/* we've found the file, change it's name and return */
- if (docache) DirCacheAdd(path,name,dname,snum);
+ if (docache) DirCacheAdd(path,name,dname,SNUM(cnum));
strcpy(name, dname);
CloseDir(cur_dir);
return(True);
@@ -384,34 +497,64 @@ for this service.
The function will return False if some part of the name except for the last
part cannot be resolved
+
+If the saved_last_component != 0, then the unmodified last component
+of the pathname is returned there. This is used in an exceptional
+case in reply_mv (so far). If saved_last_component == 0 then nothing
+is returned there.
+
+The bad_path arg is set to True if the filename walk failed. This is
+used to pick the correct error code to return between ENOENT and ENOTDIR
+as Windows applications depend on ERRbadpath being returned if a component
+of a pathname does not exist.
****************************************************************************/
-BOOL unix_convert(char *name,int cnum)
+BOOL unix_convert(char *name,int cnum,pstring saved_last_component, BOOL *bad_path)
{
struct stat st;
char *start, *end;
pstring dirpath;
+ int saved_errno;
*dirpath = 0;
+ *bad_path = False;
+
+ if(saved_last_component)
+ *saved_last_component = 0;
/* convert to basic unix format - removing \ chars and cleaning it up */
unix_format(name);
unix_clean_name(name);
- if (!case_sensitive &&
- (!case_preserve || (is_8_3(name) && !short_case_preserve)))
- strnorm(name);
-
/* names must be relative to the root of the service - trim any leading /.
also trim trailing /'s */
trim_string(name,"/","/");
+ /*
+ * Ensure saved_last_component is valid even if file exists.
+ */
+ if(saved_last_component) {
+ end = strrchr(name, '/');
+ if(end)
+ strcpy(saved_last_component, end + 1);
+ else
+ strcpy(saved_last_component, name);
+ }
+
+ if (!case_sensitive &&
+ (!case_preserve || (is_8_3(name, False) && !short_case_preserve)))
+ strnorm(name);
+
/* check if it's a printer file */
if (Connections[cnum].printer)
{
- if ((! *name) || strchr(name,'/') || !is_8_3(name))
+ if ((! *name) || strchr(name,'/') || !is_8_3(name, True))
{
+ 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);
@@ -421,12 +564,14 @@ BOOL unix_convert(char *name,int cnum)
if (sys_stat(name,&st) == 0)
return(True);
+ saved_errno = errno;
+
DEBUG(5,("unix_convert(%s,%d)\n",name,cnum));
/* a special case - if we don't have any mangling chars and are case
sensitive then searching won't help */
if (case_sensitive && !is_mangled(name) &&
- !lp_strip_dot() && !use_mangled_map)
+ !lp_strip_dot() && !use_mangled_map && (saved_errno != ENOENT))
return(False);
/* now we need to recursively match the name against the real
@@ -444,7 +589,10 @@ BOOL unix_convert(char *name,int cnum)
end = strchr(start, '/');
/* chop the name at this point */
- if (end) *end = 0;
+ if (end) *end = 0;
+
+ if(saved_last_component != 0)
+ strcpy(saved_last_component, end ? end + 1 : start);
/* check if the name exists up to this point */
if (sys_stat(name, &st) == 0)
@@ -467,18 +615,24 @@ BOOL unix_convert(char *name,int cnum)
/* remember the rest of the pathname so it can be restored
later */
- if (end) strcpy(rest,end+1);
-
+ if (end) pstrcpy(rest,end+1);
/* try to find this part of the path in the directory */
if (strchr(start,'?') || strchr(start,'*') ||
- !scan_directory(dirpath, start, SNUM(cnum), end?True:False))
+ !scan_directory(dirpath, start, cnum, end?True:False))
{
if (end)
{
/* an intermediate part of the name can't be found */
DEBUG(5,("Intermediate not found %s\n",start));
*end = '/';
+ /* We need to return the fact that the intermediate
+ name resolution failed. This is used to return an
+ error of ERRbadpath rather than ERRbadfile. Some
+ Windows applications depend on the difference between
+ these two errors.
+ */
+ *bad_path = True;
return(False);
}
@@ -522,251 +676,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
****************************************************************************/
@@ -806,6 +715,14 @@ static void disk_norm(int *bsize,int *dfree,int *dsize)
int disk_free(char *path,int *bsize,int *dfree,int *dsize)
{
char *df_command = lp_dfree_command();
+ int dfree_retval;
+#ifdef QUOTAS
+ int dfreeq_retval;
+ int dfreeq = 0;
+ int bsizeq = *bsize;
+ int dsizeq = *dsize;
+#endif
+
#ifndef NO_STATFS
#ifdef USE_STATVFS
struct statvfs fs;
@@ -818,15 +735,6 @@ int disk_free(char *path,int *bsize,int *dfree,int *dsize)
#endif
#endif
-#ifdef QUOTAS
- if (disk_quotas(path, bsize, dfree, dsize))
- {
- disk_norm(bsize,dfree,dsize);
- return(((*bsize)/1024)*(*dfree));
- }
-#endif
-
-
/* possibly use system() to get the result */
if (df_command && *df_command)
{
@@ -834,30 +742,58 @@ int disk_free(char *path,int *bsize,int *dfree,int *dsize)
pstring syscmd;
pstring outfile;
- sprintf(outfile,"/tmp/dfree.smb.%d",(int)getpid());
+ sprintf(outfile,"%s/dfree.smb.%d",tmpdir(),(int)getpid());
sprintf(syscmd,"%s %s",df_command,path);
standard_sub_basic(syscmd);
- ret = smbrun(syscmd,outfile);
+ ret = smbrun(syscmd,outfile,False);
DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
{
- FILE *f = fopen(outfile,"r");
- *dsize = 0;
- *dfree = 0;
- *bsize = 1024;
- if (f)
- {
- fscanf(f,"%d %d %d",dsize,dfree,bsize);
- fclose(f);
- }
- else
- DEBUG(0,("Can't open %s\n",outfile));
+ FILE *f = fopen(outfile,"r");
+ *dsize = 0;
+ *dfree = 0;
+ *bsize = 1024;
+ if (f)
+ {
+ fscanf(f,"%d %d %d",dsize,dfree,bsize);
+ fclose(f);
+ }
+ else
+ DEBUG(0,("Can't open %s\n",outfile));
}
unlink(outfile);
disk_norm(bsize,dfree,dsize);
- return(((*bsize)/1024)*(*dfree));
+ dfree_retval = ((*bsize)/1024)*(*dfree);
+#ifdef QUOTAS
+ /* Ensure we return the min value between the users quota and
+ what's free on the disk. Thanks to Albrecht Gebhardt
+ <albrecht.gebhardt@uni-klu.ac.at> for this fix.
+ */
+ if (disk_quotas(path, &bsizeq, &dfreeq, &dsizeq))
+ {
+ disk_norm(&bsizeq, &dfreeq, &dsizeq);
+ dfreeq_retval = ((bsizeq)/1024)*(dfreeq);
+ dfree_retval = ( dfree_retval < dfreeq_retval ) ?
+ dfree_retval : dfreeq_retval ;
+ /* maybe dfree and dfreeq are calculated using different bsizes
+ so convert dfree from bsize into bsizeq */
+ /* avoid overflows due to multiplication, so do not:
+ *dfree = ((*dfree) * (*bsize)) / (bsizeq);
+ bsize and bsizeq are powers of 2 so its better to
+ to divide them getting a multiplication or division factor
+ for dfree. Rene Nieuwenhuizen (07-10-1997) */
+ if (*bsize >= bsizeq)
+ *dfree = *dfree * (*bsize / bsizeq);
+ else
+ *dfree = *dfree / (bsizeq / *bsize);
+ *dfree = ( *dfree < dfreeq ) ? *dfree : dfreeq ;
+ *bsize = bsizeq;
+ *dsize = dsizeq;
+ }
+#endif
+ return(dfree_retval);
}
#ifdef NO_STATFS
@@ -927,7 +863,35 @@ if ((*bsize) < 512 || (*bsize)>0xFFFF) *bsize = 1024;
*dsize = 20*1024*1024/(*bsize);
*dfree = MAX(1,*dfree);
}
- return(((*bsize)/1024)*(*dfree));
+ dfree_retval = ((*bsize)/1024)*(*dfree);
+#ifdef QUOTAS
+ /* Ensure we return the min value between the users quota and
+ what's free on the disk. Thanks to Albrecht Gebhardt
+ <albrecht.gebhardt@uni-klu.ac.at> for this fix.
+ */
+ if (disk_quotas(path, &bsizeq, &dfreeq, &dsizeq))
+ {
+ disk_norm(&bsizeq, &dfreeq, &dsizeq);
+ dfreeq_retval = ((bsizeq)/1024)*(dfreeq);
+ dfree_retval = ( dfree_retval < dfreeq_retval ) ?
+ dfree_retval : dfreeq_retval ;
+ /* maybe dfree and dfreeq are calculated using different bsizes
+ so convert dfree from bsize into bsizeq */
+ /* avoid overflows due to multiplication, so do not:
+ *dfree = ((*dfree) * (*bsize)) / (bsizeq);
+ bsize and bsizeq are powers of 2 so its better to
+ to divide them getting a multiplication or division factor
+ for dfree. Rene Nieuwenhuizen (07-10-1997) */
+ if (*bsize >= bsizeq)
+ *dfree = *dfree * (*bsize / bsizeq);
+ else
+ *dfree = *dfree / (bsizeq / *bsize);
+ *dfree = ( *dfree < dfreeq ) ? *dfree : dfreeq ;
+ *bsize = bsizeq;
+ *dsize = dsizeq;
+ }
+#endif
+ return(dfree_retval);
#endif
}
@@ -955,7 +919,31 @@ BOOL check_name(char *name,int cnum)
errno = 0;
+ if( IS_VETO_PATH(cnum, name))
+ {
+ DEBUG(5,("file path name %s vetoed\n",name));
+ return(0);
+ }
+
ret = reduce_name(name,Connections[cnum].connectpath,lp_widelinks(SNUM(cnum)));
+
+ /* Check if we are allowing users to follow symlinks */
+ /* Patch from David Clerc <David.Clerc@cui.unige.ch>
+ University of Geneva */
+
+#ifdef S_ISLNK
+ if (!lp_symlinks(SNUM(cnum)))
+ {
+ struct stat statbuf;
+ if ( (sys_lstat(name,&statbuf) != -1) &&
+ (S_ISLNK(statbuf.st_mode)) )
+ {
+ DEBUG(3,("check_name: denied: file path name %s is a symlink\n",name));
+ ret=0;
+ }
+ }
+#endif
+
if (!ret)
DEBUG(5,("check_name on %s failed\n",name));
@@ -979,19 +967,185 @@ static void check_for_pipe(char *fname)
}
}
+/****************************************************************************
+fd support routines - attempt to do a sys_open
+****************************************************************************/
+static int fd_attempt_open(char *fname, int flags, int mode)
+{
+ int fd = sys_open(fname,flags,mode);
+
+ /* Fix for files ending in '.' */
+ if((fd == -1) && (errno == ENOENT) &&
+ (strchr(fname,'.')==NULL))
+ {
+ strcat(fname,".");
+ fd = sys_open(fname,flags,mode);
+ }
+
+#if (defined(ENAMETOOLONG) && defined(HAVE_PATHCONF))
+ if ((fd == -1) && (errno == ENAMETOOLONG))
+ {
+ int max_len;
+ char *p = strrchr(fname, '/');
+
+ if (p == fname) /* name is "/xxx" */
+ {
+ max_len = pathconf("/", _PC_NAME_MAX);
+ p++;
+ }
+ else if ((p == NULL) || (p == fname))
+ {
+ p = fname;
+ max_len = pathconf(".", _PC_NAME_MAX);
+ }
+ else
+ {
+ *p = '\0';
+ max_len = pathconf(fname, _PC_NAME_MAX);
+ *p = '/';
+ p++;
+ }
+ if (strlen(p) > max_len)
+ {
+ char tmp = p[max_len];
+
+ p[max_len] = '\0';
+ if ((fd = sys_open(fname,flags,mode)) == -1)
+ p[max_len] = tmp;
+ }
+ }
+#endif
+ return fd;
+}
+
+/****************************************************************************
+fd support routines - attempt to find an already open file by dev
+and inode - increments the ref_count of the returned file_fd_struct *.
+****************************************************************************/
+static file_fd_struct *fd_get_already_open(struct stat *sbuf)
+{
+ int i;
+ file_fd_struct *fd_ptr;
+
+ if(sbuf == 0)
+ return 0;
+
+ for(i = 0; i <= max_file_fd_used; i++) {
+ fd_ptr = &FileFd[i];
+ if((fd_ptr->ref_count > 0) &&
+ (((uint32)sbuf->st_dev) == fd_ptr->dev) &&
+ (((uint32)sbuf->st_ino) == fd_ptr->inode)) {
+ fd_ptr->ref_count++;
+ DEBUG(3,
+ ("Re-used file_fd_struct %d, dev = %x, inode = %x, ref_count = %d\n",
+ i, fd_ptr->dev, fd_ptr->inode, fd_ptr->ref_count));
+ return fd_ptr;
+ }
+ }
+ return 0;
+}
+
+/****************************************************************************
+fd support routines - attempt to find a empty slot in the FileFd array.
+Increments the ref_count of the returned entry.
+****************************************************************************/
+static file_fd_struct *fd_get_new()
+{
+ int i;
+ file_fd_struct *fd_ptr;
+
+ for(i = 0; i < MAX_OPEN_FILES; i++) {
+ fd_ptr = &FileFd[i];
+ if(fd_ptr->ref_count == 0) {
+ fd_ptr->dev = (uint32)-1;
+ fd_ptr->inode = (uint32)-1;
+ fd_ptr->fd = -1;
+ fd_ptr->fd_readonly = -1;
+ fd_ptr->fd_writeonly = -1;
+ fd_ptr->real_open_flags = -1;
+ fd_ptr->ref_count++;
+ /* Increment max used counter if neccessary, cuts down
+ on search time when re-using */
+ if(i > max_file_fd_used)
+ max_file_fd_used = i;
+ DEBUG(3,("Allocated new file_fd_struct %d, dev = %x, inode = %x\n",
+ i, fd_ptr->dev, fd_ptr->inode));
+ return fd_ptr;
+ }
+ }
+ DEBUG(1,("ERROR! Out of file_fd structures - perhaps increase MAX_OPEN_FILES?\
+n"));
+ return 0;
+}
+
+/****************************************************************************
+fd support routines - attempt to re-open an already open fd as O_RDWR.
+Save the already open fd (we cannot close due to POSIX file locking braindamage.
+****************************************************************************/
+static void fd_attempt_reopen(char *fname, int mode, file_fd_struct *fd_ptr)
+{
+ int fd = sys_open( fname, O_RDWR, mode);
+
+ if(fd == -1)
+ return;
+
+ if(fd_ptr->real_open_flags == O_RDONLY)
+ fd_ptr->fd_readonly = fd_ptr->fd;
+ if(fd_ptr->real_open_flags == O_WRONLY)
+ fd_ptr->fd_writeonly = fd_ptr->fd;
+
+ fd_ptr->fd = fd;
+ fd_ptr->real_open_flags = O_RDWR;
+}
+
+/****************************************************************************
+fd support routines - attempt to close the file referenced by this fd.
+Decrements the ref_count and returns it.
+****************************************************************************/
+static int fd_attempt_close(file_fd_struct *fd_ptr)
+{
+ DEBUG(3,("fd_attempt_close on file_fd_struct %d, fd = %d, dev = %x, inode = %x, open_flags = %d, ref_count = %d.\n",
+ fd_ptr - &FileFd[0],
+ fd_ptr->fd, fd_ptr->dev, fd_ptr->inode,
+ fd_ptr->real_open_flags,
+ fd_ptr->ref_count));
+ if(fd_ptr->ref_count > 0) {
+ fd_ptr->ref_count--;
+ if(fd_ptr->ref_count == 0) {
+ if(fd_ptr->fd != -1)
+ close(fd_ptr->fd);
+ if(fd_ptr->fd_readonly != -1)
+ close(fd_ptr->fd_readonly);
+ if(fd_ptr->fd_writeonly != -1)
+ close(fd_ptr->fd_writeonly);
+ fd_ptr->fd = -1;
+ fd_ptr->fd_readonly = -1;
+ fd_ptr->fd_writeonly = -1;
+ fd_ptr->real_open_flags = -1;
+ fd_ptr->dev = (uint32)-1;
+ fd_ptr->inode = (uint32)-1;
+ }
+ }
+ return fd_ptr->ref_count;
+}
/****************************************************************************
open a file
****************************************************************************/
-void open_file(int fnum,int cnum,char *fname1,int flags,int mode)
+static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct stat *sbuf)
{
+ extern struct current_user current_user;
pstring fname;
+ struct stat statbuf;
+ file_fd_struct *fd_ptr;
+ files_struct *fsp = &Files[fnum];
- Files[fnum].open = False;
- Files[fnum].fd = -1;
+ fsp->open = False;
+ fsp->fd_ptr = 0;
+ fsp->granted_oplock = False;
errno = EPERM;
- strcpy(fname,fname1);
+ pstrcpy(fname,fname1);
/* check permissions */
if ((flags != O_RDONLY) && !CAN_WRITE(cnum) && !Connections[cnum].printer)
@@ -1011,107 +1165,170 @@ void open_file(int fnum,int cnum,char *fname1,int flags,int mode)
DEBUG(3,("Bug in client? Set O_WRONLY without O_CREAT\n"));
*/
-#if UTIME_WORKAROUND
- /* XXXX - is this OK?? */
- /* this works around a utime bug but can cause other problems */
- if ((flags & (O_WRONLY|O_RDWR)) && (flags & O_CREAT) && !(flags & O_APPEND))
- sys_unlink(fname);
-#endif
+ /*
+ * Ensure we have a valid struct stat so we can search the
+ * open fd table.
+ */
+ if(sbuf == 0) {
+ if(stat(fname, &statbuf) < 0) {
+ if(errno != ENOENT) {
+ DEBUG(3,("Error doing stat on file %s (%s)\n",
+ fname,strerror(errno)));
+
+ check_for_pipe(fname);
+ return;
+ }
+ sbuf = 0;
+ } else {
+ sbuf = &statbuf;
+ }
+ }
+
+ /*
+ * Check to see if we have this file already
+ * open. If we do, just use the already open fd and increment the
+ * reference count (fd_get_already_open increments the ref_count).
+ */
+ if((fd_ptr = fd_get_already_open(sbuf))!= 0) {
+ int accmode = (flags & (O_RDONLY | O_WRONLY | O_RDWR));
+
+ /* File was already open. */
+ if((flags & O_CREAT) && (flags & O_EXCL)) {
+ fd_ptr->ref_count--;
+ errno = EEXIST;
+ return;
+ }
- Files[fnum].fd = sys_open(fname,flags,mode);
+ /*
+ * If not opened O_RDWR try
+ * and do that here - a chmod may have been done
+ * between the last open and now.
+ */
+ if(fd_ptr->real_open_flags != O_RDWR)
+ fd_attempt_reopen(fname, mode, fd_ptr);
+
+ /*
+ * Ensure that if we wanted write access
+ * it has been opened for write, and if we wanted read it
+ * was open for read.
+ */
+ if(((accmode == O_WRONLY) && (fd_ptr->real_open_flags == O_RDONLY)) ||
+ ((accmode == O_RDONLY) && (fd_ptr->real_open_flags == O_WRONLY)) ||
+ ((accmode == O_RDWR) && (fd_ptr->real_open_flags != O_RDWR))) {
+ DEBUG(3,("Error opening (already open for flags=%d) file %s (%s) (flags=%d)\n",
+ fd_ptr->real_open_flags, fname,strerror(EACCES),flags));
+ check_for_pipe(fname);
+ fd_ptr->ref_count--;
+ return;
+ }
- if ((Files[fnum].fd>=0) &&
+ } else {
+ int open_flags;
+ /* We need to allocate a new file_fd_struct (this increments the
+ ref_count). */
+ if((fd_ptr = fd_get_new()) == 0)
+ return;
+ /*
+ * Whatever the requested flags, attempt read/write access,
+ * as we don't know what flags future file opens may require.
+ * If this fails, try again with the required flags.
+ * Even if we open read/write when only read access was
+ * requested the setting of the can_write flag in
+ * the file_struct will protect us from errant
+ * write requests. We never need to worry about O_APPEND
+ * as this is not set anywhere in Samba.
+ */
+ fd_ptr->real_open_flags = O_RDWR;
+ /* Set the flags as needed without the read/write modes. */
+ open_flags = flags & ~(O_RDWR|O_WRONLY|O_RDONLY);
+ fd_ptr->fd = fd_attempt_open(fname, open_flags|O_RDWR, mode);
+ /*
+ * On some systems opening a file for R/W access on a read only
+ * filesystems sets errno to EROFS.
+ */
+#ifdef EROFS
+ if((fd_ptr->fd == -1) && ((errno == EACCES) || (errno == EROFS))) {
+#else /* No EROFS */
+ if((fd_ptr->fd == -1) && (errno == EACCES)) {
+#endif /* EROFS */
+ if(flags & O_WRONLY) {
+ fd_ptr->fd = fd_attempt_open(fname, open_flags|O_WRONLY, mode);
+ fd_ptr->real_open_flags = O_WRONLY;
+ } else {
+ fd_ptr->fd = fd_attempt_open(fname, open_flags|O_RDONLY, mode);
+ fd_ptr->real_open_flags = O_RDONLY;
+ }
+ }
+ }
+
+ if ((fd_ptr->fd >=0) &&
Connections[cnum].printer && lp_minprintspace(SNUM(cnum))) {
pstring dname;
int dum1,dum2,dum3;
char *p;
- strcpy(dname,fname);
+ pstrcpy(dname,fname);
p = strrchr(dname,'/');
if (p) *p = 0;
if (sys_disk_free(dname,&dum1,&dum2,&dum3) <
lp_minprintspace(SNUM(cnum))) {
- close(Files[fnum].fd);
- Files[fnum].fd = -1;
- sys_unlink(fname);
+ fd_attempt_close(fd_ptr);
+ fsp->fd_ptr = 0;
+ if(fd_ptr->ref_count == 0)
+ sys_unlink(fname);
errno = ENOSPC;
return;
}
}
-
- /* Fix for files ending in '.' */
- if((Files[fnum].fd == -1) && (errno == ENOENT) &&
- (strchr(fname,'.')==NULL))
- {
- strcat(fname,".");
- Files[fnum].fd = sys_open(fname,flags,mode);
- }
-
-#if (defined(ENAMETOOLONG) && defined(HAVE_PATHCONF))
- if ((Files[fnum].fd == -1) && (errno == ENAMETOOLONG))
- {
- int max_len;
- char *p = strrchr(fname, '/');
-
- if (p == fname) /* name is "/xxx" */
- {
- max_len = pathconf("/", _PC_NAME_MAX);
- p++;
- }
- else if ((p == NULL) || (p == fname))
- {
- p = fname;
- max_len = pathconf(".", _PC_NAME_MAX);
- }
- else
- {
- *p = '\0';
- max_len = pathconf(fname, _PC_NAME_MAX);
- *p = '/';
- p++;
- }
- if (strlen(p) > max_len)
- {
- char tmp = p[max_len];
-
- p[max_len] = '\0';
- if ((Files[fnum].fd = sys_open(fname,flags,mode)) == -1)
- p[max_len] = tmp;
- }
- }
-#endif
-
- if (Files[fnum].fd < 0)
+ if (fd_ptr->fd < 0)
{
DEBUG(3,("Error opening file %s (%s) (flags=%d)\n",
fname,strerror(errno),flags));
+ /* Ensure the ref_count is decremented. */
+ fd_attempt_close(fd_ptr);
check_for_pipe(fname);
return;
}
- if (Files[fnum].fd >= 0)
+ if (fd_ptr->fd >= 0)
{
- struct stat st;
+ if(sbuf == 0) {
+ /* Do the fstat */
+ if(fstat(fd_ptr->fd, &statbuf) == -1) {
+ /* Error - backout !! */
+ DEBUG(3,("Error doing fstat on fd %d, file %s (%s)\n",
+ fd_ptr->fd, fname,strerror(errno)));
+ /* Ensure the ref_count is decremented. */
+ fd_attempt_close(fd_ptr);
+ return;
+ }
+ sbuf = &statbuf;
+ }
+ /* Set the correct entries in fd_ptr. */
+ fd_ptr->dev = (uint32)sbuf->st_dev;
+ fd_ptr->inode = (uint32)sbuf->st_ino;
+
+ fsp->fd_ptr = fd_ptr;
Connections[cnum].num_files_open++;
- fstat(Files[fnum].fd,&st);
- Files[fnum].mode = st.st_mode;
- Files[fnum].open_time = time(NULL);
- Files[fnum].size = 0;
- Files[fnum].pos = -1;
- Files[fnum].open = True;
- Files[fnum].mmap_ptr = NULL;
- Files[fnum].mmap_size = 0;
- Files[fnum].can_lock = True;
- Files[fnum].can_read = ((flags & O_WRONLY)==0);
- Files[fnum].can_write = ((flags & (O_WRONLY|O_RDWR))!=0);
- Files[fnum].share_mode = 0;
- Files[fnum].share_pending = False;
- Files[fnum].print_file = Connections[cnum].printer;
- Files[fnum].modified = False;
- Files[fnum].cnum = cnum;
- string_set(&Files[fnum].name,fname);
- Files[fnum].wbmpx_ptr = NULL;
+ fsp->mode = sbuf->st_mode;
+ GetTimeOfDay(&fsp->open_time);
+ fsp->uid = current_user.id;
+ fsp->size = 0;
+ fsp->pos = -1;
+ fsp->open = True;
+ fsp->mmap_ptr = NULL;
+ fsp->mmap_size = 0;
+ fsp->can_lock = True;
+ fsp->can_read = ((flags & O_WRONLY)==0);
+ fsp->can_write = ((flags & (O_WRONLY|O_RDWR))!=0);
+ fsp->share_mode = 0;
+ fsp->print_file = Connections[cnum].printer;
+ fsp->modified = False;
+ fsp->granted_oplock = False;
+ fsp->cnum = cnum;
+ string_set(&fsp->name,dos_to_unix(fname,False));
+ fsp->wbmpx_ptr = NULL;
/*
* If the printer is marked as postscript output a leading
@@ -1120,8 +1337,8 @@ void open_file(int fnum,int cnum,char *fname1,int flags,int mode)
* This has a similar effect as CtrlD=0 in WIN.INI file.
* tim@fsg.com 09/06/94
*/
- if (Files[fnum].print_file && POSTSCRIPT(cnum) &&
- Files[fnum].can_write)
+ if (fsp->print_file && POSTSCRIPT(cnum) &&
+ fsp->can_write)
{
DEBUG(3,("Writing postscript line\n"));
write_file(fnum,"%!\n",3);
@@ -1129,23 +1346,23 @@ void open_file(int fnum,int cnum,char *fname1,int flags,int mode)
DEBUG(2,("%s %s opened file %s read=%s write=%s (numopen=%d fnum=%d)\n",
timestring(),Connections[cnum].user,fname,
- BOOLSTR(Files[fnum].can_read),BOOLSTR(Files[fnum].can_write),
+ BOOLSTR(fsp->can_read),BOOLSTR(fsp->can_write),
Connections[cnum].num_files_open,fnum));
}
#if USE_MMAP
/* mmap it if read-only */
- if (!Files[fnum].can_write)
+ if (!fsp->can_write)
{
- Files[fnum].mmap_size = file_size(fname);
- Files[fnum].mmap_ptr = (char *)mmap(NULL,Files[fnum].mmap_size,
- PROT_READ,MAP_SHARED,Files[fnum].fd,0);
+ fsp->mmap_size = file_size(fname);
+ fsp->mmap_ptr = (char *)mmap(NULL,fsp->mmap_size,
+ PROT_READ,MAP_SHARED,fsp->fd_ptr->fd,0);
- if (Files[fnum].mmap_ptr == (char *)-1 || !Files[fnum].mmap_ptr)
+ if (fsp->mmap_ptr == (char *)-1 || !fsp->mmap_ptr)
{
DEBUG(3,("Failed to mmap() %s - %s\n",fname,strerror(errno)));
- Files[fnum].mmap_ptr = NULL;
+ fsp->mmap_ptr = NULL;
}
}
#endif
@@ -1157,7 +1374,7 @@ sync a file
void sync_file(int fnum)
{
#ifndef NO_FSYNC
- fsync(Files[fnum].fd);
+ fsync(Files[fnum].fd_ptr->fd);
#endif
}
@@ -1186,15 +1403,15 @@ static void check_magic(int fnum,int cnum)
int ret;
pstring magic_output;
pstring fname;
- strcpy(fname,Files[fnum].name);
+ pstrcpy(fname,Files[fnum].name);
if (*lp_magicoutput(SNUM(cnum)))
- strcpy(magic_output,lp_magicoutput(SNUM(cnum)));
+ pstrcpy(magic_output,lp_magicoutput(SNUM(cnum)));
else
sprintf(magic_output,"%s.out",fname);
chmod(fname,0755);
- ret = smbrun(fname,magic_output);
+ ret = smbrun(fname,magic_output,False);
DEBUG(3,("Invoking magic command %s gave %d\n",fname,ret));
unlink(fname);
}
@@ -1203,51 +1420,61 @@ static void check_magic(int fnum,int cnum)
/****************************************************************************
close a file - possibly invalidating the read prediction
+
+If normal_close is 1 then this came from a normal SMBclose (or equivalent)
+operation otherwise it came as the result of some other operation such as
+the closing of the connection. In the latter case printing and
+magic scripts are not run
****************************************************************************/
-void close_file(int fnum)
+void close_file(int fnum, BOOL normal_close)
{
- int cnum = Files[fnum].cnum;
- invalidate_read_prediction(Files[fnum].fd);
- Files[fnum].open = False;
+ files_struct *fs_p = &Files[fnum];
+ int cnum = fs_p->cnum;
+ uint32 dev = fs_p->fd_ptr->dev;
+ uint32 inode = fs_p->fd_ptr->inode;
+ int token;
+
+#if USE_READ_PREDICTION
+ invalidate_read_prediction(fs_p->fd_ptr->fd);
+#endif
+
+ fs_p->open = False;
Connections[cnum].num_files_open--;
- if(Files[fnum].wbmpx_ptr)
- {
- free((char *)Files[fnum].wbmpx_ptr);
- Files[fnum].wbmpx_ptr = NULL;
- }
+ if(fs_p->wbmpx_ptr)
+ {
+ free((char *)fs_p->wbmpx_ptr);
+ fs_p->wbmpx_ptr = NULL;
+ }
#if USE_MMAP
- if(Files[fnum].mmap_ptr)
- {
- munmap(Files[fnum].mmap_ptr,Files[fnum].mmap_size);
- Files[fnum].mmap_ptr = NULL;
- }
+ if(fs_p->mmap_ptr)
+ {
+ munmap(fs_p->mmap_ptr,fs_p->mmap_size);
+ fs_p->mmap_ptr = NULL;
+ }
#endif
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);
- }
- }
+ {
+ lock_share_entry( cnum, dev, inode, &token);
+ del_share_mode(token, fnum);
}
- close(Files[fnum].fd);
+ fd_attempt_close(fs_p->fd_ptr);
+
+ if (lp_share_modes(SNUM(cnum)))
+ unlock_share_entry( cnum, dev, inode, token);
/* NT uses smbclose to start a print - weird */
- if (Files[fnum].print_file)
+ if (normal_close && fs_p->print_file)
print_file(fnum);
/* check for magic scripts */
- check_magic(fnum,cnum);
+ if (normal_close)
+ check_magic(fnum,cnum);
DEBUG(2,("%s %s closed file %s (numopen=%d)\n",
- timestring(),Connections[cnum].user,Files[fnum].name,
+ timestring(),Connections[cnum].user,fs_p->name,
Connections[cnum].num_files_open));
}
@@ -1262,7 +1489,8 @@ static int access_table(int new_deny,int old_deny,int old_mode,
if (new_deny == DENY_ALL || old_deny == DENY_ALL) return(AFAIL);
if (new_deny == DENY_DOS || old_deny == DENY_DOS) {
- if (old_deny == new_deny && share_pid == getpid())
+ int pid = getpid();
+ if (old_deny == new_deny && share_pid == pid)
return(AALL);
if (old_mode == 0) return(AREAD);
@@ -1309,17 +1537,95 @@ return True if sharing doesn't prevent the operation
********************************************************************/
BOOL check_file_sharing(int cnum,char *fname)
{
- int pid=0;
- int share_mode = get_share_mode_byname(cnum,fname,&pid);
+ int i;
+ int ret = False;
+ share_mode_entry *old_shares = 0;
+ int num_share_modes;
+ struct stat sbuf;
+ int token;
+ int pid = getpid();
+ uint32 dev, inode;
- if (!pid || !share_mode) return(True);
-
- if (share_mode == DENY_DOS)
- return(pid == getpid());
+ if(!lp_share_modes(SNUM(cnum)))
+ return True;
+
+ if (stat(fname,&sbuf) == -1) return(True);
+
+ dev = (uint32)sbuf.st_dev;
+ inode = (uint32)sbuf.st_ino;
+
+ lock_share_entry(cnum, dev, inode, &token);
+ num_share_modes = get_share_modes(cnum, token, dev, inode, &old_shares);
+
+ /*
+ * Check if the share modes will give us access.
+ */
+
+ if(num_share_modes != 0)
+ {
+ BOOL broke_oplock;
+
+ do
+ {
+
+ broke_oplock = False;
+ for(i = 0; i < num_share_modes; i++)
+ {
+ share_mode_entry *share_entry = &old_shares[i];
+
+ /*
+ * Break oplocks before checking share modes. See comment in
+ * open_file_shared for details.
+ * Check if someone has an oplock on this file. If so we must
+ * break it before continuing.
+ */
+ if(share_entry->op_type & BATCH_OPLOCK)
+ {
+
+ DEBUG(5,("check_file_sharing: breaking oplock (%x) on file %s, \
+dev = %x, inode = %x\n", share_entry->op_type, fname, dev, inode));
+
+ /* Oplock break.... */
+ unlock_share_entry(cnum, dev, inode, token);
+ if(request_oplock_break(share_entry, dev, inode) == False)
+ {
+ free((char *)old_shares);
+ DEBUG(0,("check_file_sharing: FAILED when breaking oplock (%x) on file %s, \
+dev = %x, inode = %x\n", old_shares[i].op_type, fname, dev, inode));
+ return False;
+ }
+ lock_share_entry(cnum, dev, inode, &token);
+ broke_oplock = True;
+ break;
+ }
+
+ /* someone else has a share lock on it, check to see
+ if we can too */
+ if ((share_entry->share_mode != DENY_DOS) || (share_entry->pid != pid))
+ goto free_and_exit;
+
+ } /* end for */
+
+ if(broke_oplock)
+ {
+ free((char *)old_shares);
+ num_share_modes = get_share_modes(cnum, token, dev, inode, &old_shares);
+ }
+ } while(broke_oplock);
+ }
/* XXXX exactly what share mode combinations should be allowed for
deleting/renaming? */
- return(False);
+ /* If we got here then either there were no share modes or
+ all share modes were DENY_DOS and the pid == getpid() */
+ ret = True;
+
+free_and_exit:
+
+ unlock_share_entry(cnum, dev, inode, token);
+ if(old_shares != NULL)
+ free((char *)old_shares);
+ return(ret);
}
/****************************************************************************
@@ -1327,46 +1633,107 @@ BOOL check_file_sharing(int cnum,char *fname)
Helper for open_file_shared.
Truncate a file after checking locking; close file if locked.
**************************************************************************/
-static void truncate_unless_locked(int fnum, int cnum)
+static void truncate_unless_locked(int fnum, int cnum, int token,
+ BOOL *share_locked)
{
if (Files[fnum].can_write){
if (is_locked(fnum,cnum,0x3FFFFFFF,0)){
- close_file(fnum);
+ /* If share modes are in force for this connection we
+ have the share entry locked. Unlock it before closing. */
+ if (*share_locked && lp_share_modes(SNUM(cnum)))
+ unlock_share_entry( cnum, Files[fnum].fd_ptr->dev,
+ Files[fnum].fd_ptr->inode, token);
+ close_file(fnum,False);
+ /* Share mode no longer locked. */
+ *share_locked = False;
errno = EACCES;
unix_ERR_class = ERRDOS;
unix_ERR_code = ERRlock;
}
else
- ftruncate(Files[fnum].fd,0);
+ ftruncate(Files[fnum].fd_ptr->fd,0);
}
}
+/****************************************************************************
+check if we can open a file with a share mode
+****************************************************************************/
+int check_share_mode( share_mode_entry *share, int deny_mode, char *fname,
+ BOOL fcbopen, int *flags)
+{
+ int old_open_mode = share->share_mode &0xF;
+ int old_deny_mode = (share->share_mode >>4)&7;
+
+ if (old_deny_mode > 4 || old_open_mode > 2)
+ {
+ DEBUG(0,("Invalid share mode found (%d,%d,%d) on file %s\n",
+ deny_mode,old_deny_mode,old_open_mode,fname));
+ return False;
+ }
+
+ {
+ int access_allowed = access_table(deny_mode,old_deny_mode,old_open_mode,
+ share->pid,fname);
+
+ if ((access_allowed == AFAIL) ||
+ (!fcbopen && (access_allowed == AREAD && *flags == O_RDWR)) ||
+ (access_allowed == AREAD && *flags == O_WRONLY) ||
+ (access_allowed == AWRITE && *flags == O_RDONLY))
+ {
+ DEBUG(2,("Share violation on file (%d,%d,%d,%d,%s) = %d\n",
+ deny_mode,old_deny_mode,old_open_mode,
+ share->pid,fname, access_allowed));
+ return False;
+ }
+
+ if (access_allowed == AREAD)
+ *flags = O_RDONLY;
+
+ if (access_allowed == AWRITE)
+ *flags = O_WRONLY;
+
+ }
+ return True;
+}
/****************************************************************************
open a file with a share mode
****************************************************************************/
void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
- int mode,int *Access,int *action)
+ int mode,int oplock_request, int *Access,int *action)
{
+ files_struct *fs_p = &Files[fnum];
int flags=0;
int flags2=0;
int deny_mode = (share_mode>>4)&7;
struct stat sbuf;
BOOL file_existed = file_exist(fname,&sbuf);
+ BOOL share_locked = False;
BOOL fcbopen = False;
- int share_pid=0;
+ int token;
+ uint32 dev = 0;
+ uint32 inode = 0;
+ int num_share_modes = 0;
- Files[fnum].open = False;
- Files[fnum].fd = -1;
+ fs_p->open = False;
+ fs_p->fd_ptr = 0;
/* this is for OS/2 EAs - try and say we don't support them */
- if (strstr(fname,".+,;=[].")) {
+ if (strstr(fname,".+,;=[]."))
+ {
unix_ERR_class = ERRDOS;
+ /* OS/2 Workplace shell fix may be main code stream in a later release. */
+#ifdef OS2_WPS_FIX
+ unix_ERR_code = ERRcannotopen;
+#else /* OS2_WPS_FIX */
unix_ERR_code = ERROR_EAS_NOT_SUPPORTED;
+#endif /* OS2_WPS_FIX */
+
return;
}
- if ((ofun & 0x3) == 0 && file_existed) {
+ if ((ofun & 0x3) == 0 && file_existed)
+ {
errno = EEXIST;
return;
}
@@ -1380,7 +1747,7 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
append does not mean the same thing under dos and unix */
switch (share_mode&0xF)
- {
+ {
case 1:
flags = O_WRONLY;
break;
@@ -1394,18 +1761,21 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
default:
flags = O_RDONLY;
break;
- }
+ }
if (flags != O_RDONLY && file_existed &&
- (!CAN_WRITE(cnum) || IS_DOS_READONLY(dos_mode(cnum,fname,&sbuf)))) {
- if (!fcbopen) {
+ (!CAN_WRITE(cnum) || IS_DOS_READONLY(dos_mode(cnum,fname,&sbuf))))
+ {
+ if (!fcbopen)
+ {
errno = EACCES;
return;
}
flags = O_RDONLY;
}
- if (deny_mode > DENY_NONE && deny_mode!=DENY_FCB) {
+ if (deny_mode > DENY_NONE && deny_mode!=DENY_FCB)
+ {
DEBUG(2,("Invalid deny mode %d on file %s\n",deny_mode,fname));
errno = EINVAL;
return;
@@ -1413,172 +1783,225 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
if (deny_mode == DENY_FCB) deny_mode = DENY_DOS;
- if (lp_share_modes(SNUM(cnum))) {
- int old_share=0;
+ if (lp_share_modes(SNUM(cnum)))
+ {
+ int i;
+ share_mode_entry *old_shares = 0;
if (file_existed)
- old_share = get_share_mode(cnum,&sbuf,&share_pid);
-
- if (share_pid) {
- /* someone else has a share lock on it, check to see
- if we can too */
- int old_open_mode = old_share&0xF;
- int old_deny_mode = (old_share>>4)&7;
-
- if (deny_mode > 4 || old_deny_mode > 4 || old_open_mode > 2) {
- DEBUG(2,("Invalid share mode (%d,%d,%d) on file %s\n",
- deny_mode,old_deny_mode,old_open_mode,fname));
- errno = EACCES;
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadshare;
- return;
- }
+ {
+ dev = (uint32)sbuf.st_dev;
+ inode = (uint32)sbuf.st_ino;
+ lock_share_entry(cnum, dev, inode, &token);
+ share_locked = True;
+ num_share_modes = get_share_modes(cnum, token, dev, inode, &old_shares);
+ }
+
+ /*
+ * Check if the share modes will give us access.
+ */
+
+ if(share_locked && (num_share_modes != 0))
+ {
+ BOOL broke_oplock;
+ do
{
- int access_allowed = access_table(deny_mode,old_deny_mode,old_open_mode,
- share_pid,fname);
-
- if ((access_allowed == AFAIL) ||
- (access_allowed == AREAD && flags == O_WRONLY) ||
- (access_allowed == AWRITE && flags == O_RDONLY)) {
- DEBUG(2,("Share violation on file (%d,%d,%d,%d,%s) = %d\n",
- deny_mode,old_deny_mode,old_open_mode,
- share_pid,fname,
- access_allowed));
- errno = EACCES;
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadshare;
- return;
- }
-
- if (access_allowed == AREAD)
- flags = O_RDONLY;
-
- if (access_allowed == AWRITE)
- flags = O_WRONLY;
- }
+
+ broke_oplock = False;
+ for(i = 0; i < num_share_modes; i++)
+ {
+ share_mode_entry *share_entry = &old_shares[i];
+
+ /*
+ * By observation of NetBench, oplocks are broken *before* share
+ * modes are checked. This allows a file to be closed by the client
+ * if the share mode would deny access and the client has an oplock.
+ * Check if someone has an oplock on this file. If so we must break
+ * it before continuing.
+ */
+ if(share_entry->op_type & (EXCLUSIVE_OPLOCK|BATCH_OPLOCK))
+ {
+
+ DEBUG(5,("open_file_shared: breaking oplock (%x) on file %s, \
+dev = %x, inode = %x\n", share_entry->op_type, fname, dev, inode));
+
+ /* Oplock break.... */
+ unlock_share_entry(cnum, dev, inode, token);
+ if(request_oplock_break(share_entry, dev, inode) == False)
+ {
+ free((char *)old_shares);
+ DEBUG(0,("open_file_shared: FAILED when breaking oplock (%x) on file %s, \
+dev = %x, inode = %x\n", old_shares[i].op_type, fname, dev, inode));
+ errno = EACCES;
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadshare;
+ return;
+ }
+ lock_share_entry(cnum, dev, inode, &token);
+ broke_oplock = True;
+ break;
+ }
+
+ /* someone else has a share lock on it, check to see
+ if we can too */
+ if(check_share_mode(share_entry, deny_mode, fname, fcbopen, &flags) == False)
+ {
+ free((char *)old_shares);
+ unlock_share_entry(cnum, dev, inode, token);
+ errno = EACCES;
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadshare;
+ return;
+ }
+
+ } /* end for */
+
+ if(broke_oplock)
+ {
+ free((char *)old_shares);
+ num_share_modes = get_share_modes(cnum, token, dev, inode, &old_shares);
+ }
+ } while(broke_oplock);
}
+
+ if(old_shares != 0)
+ free((char *)old_shares);
}
DEBUG(4,("calling open_file with flags=0x%X flags2=0x%X mode=0%o\n",
flags,flags2,mode));
- open_file(fnum,cnum,fname,flags|(flags2&~(O_TRUNC)),mode);
- if (!Files[fnum].open && flags==O_RDWR && errno!=ENOENT && fcbopen) {
+ open_file(fnum,cnum,fname,flags|(flags2&~(O_TRUNC)),mode,file_existed ? &sbuf : 0);
+ if (!fs_p->open && flags==O_RDWR && errno!=ENOENT && fcbopen)
+ {
flags = O_RDONLY;
- open_file(fnum,cnum,fname,flags,mode);
+ open_file(fnum,cnum,fname,flags,mode,file_existed ? &sbuf : 0 );
}
- if (Files[fnum].open) {
+ if (fs_p->open)
+ {
int open_mode=0;
- switch (flags) {
- case O_RDONLY:
- open_mode = 0;
- break;
- case O_RDWR:
- open_mode = 2;
- break;
- case O_WRONLY:
- open_mode = 1;
- break;
+
+ if((share_locked == False) && lp_share_modes(SNUM(cnum)))
+ {
+ /* We created the file - thus we must now lock the share entry before creating it. */
+ dev = fs_p->fd_ptr->dev;
+ inode = fs_p->fd_ptr->inode;
+ lock_share_entry(cnum, dev, inode, &token);
+ share_locked = True;
+ }
+
+ switch (flags)
+ {
+ case O_RDONLY:
+ open_mode = 0;
+ break;
+ case O_RDWR:
+ open_mode = 2;
+ break;
+ case O_WRONLY:
+ open_mode = 1;
+ break;
}
- Files[fnum].share_mode = (deny_mode<<4) | open_mode;
- Files[fnum].share_pending = True;
+ fs_p->share_mode = (deny_mode<<4) | open_mode;
- if (Access) {
+ if (Access)
(*Access) = open_mode;
- }
-
- if (action) {
+
+ if (action)
+ {
if (file_existed && !(flags2 & O_TRUNC)) *action = 1;
if (!file_existed) *action = 2;
if (file_existed && (flags2 & O_TRUNC)) *action = 3;
}
+ /* We must create the share mode entry before truncate as
+ truncate can fail due to locking and have to close the
+ file (which expects the share_mode_entry to be there).
+ */
+ if (lp_share_modes(SNUM(cnum)))
+ {
+ uint16 port = 0;
+ /* JRA. Currently this only services Exlcusive and batch
+ oplocks (no other opens on this file). This needs to
+ be extended to level II oplocks (multiple reader
+ oplocks). */
- if (!share_pid)
- share_mode_pending = True;
-
- if ((flags2&O_TRUNC) && file_existed)
- truncate_unless_locked(fnum,cnum);
- }
-}
-
+ if(oplock_request && (num_share_modes == 0) && lp_oplocks(SNUM(cnum)))
+ {
+ fs_p->granted_oplock = True;
+ global_oplocks_open++;
+ port = oplock_port;
+ DEBUG(5,("open_file_shared: granted oplock (%x) on file %s, \
+dev = %x, inode = %x\n", oplock_request, fname, dev, inode));
-/*******************************************************************
-check for files that we should now set our share modes on
-********************************************************************/
-static void check_share_modes(void)
-{
- int i;
- for (i=0;i<MAX_OPEN_FILES;i++)
- if(Files[i].open && Files[i].share_pending) {
- if (lp_share_modes(SNUM(Files[i].cnum))) {
- int pid=0;
- get_share_mode_by_fnum(Files[i].cnum,i,&pid);
- if (!pid) {
- set_share_mode(i,Files[i].share_mode);
- Files[i].share_pending = False;
- }
- } else {
- Files[i].share_pending = False;
}
+ else
+ {
+ port = 0;
+ oplock_request = 0;
+ }
+ set_share_mode(token, fnum, port, oplock_request);
}
-}
+ if ((flags2&O_TRUNC) && file_existed)
+ truncate_unless_locked(fnum,cnum,token,&share_locked);
+ }
+
+ if (share_locked && lp_share_modes(SNUM(cnum)))
+ unlock_share_entry( cnum, dev, inode, token);
+}
/****************************************************************************
seek a file. Try to avoid the seek if possible
****************************************************************************/
-int seek_file(int fnum,int pos)
+int seek_file(int fnum,uint32 pos)
{
- int offset = 0;
+ uint32 offset = 0;
if (Files[fnum].print_file && POSTSCRIPT(Files[fnum].cnum))
offset = 3;
- Files[fnum].pos = lseek(Files[fnum].fd,pos+offset,SEEK_SET) - offset;
+ Files[fnum].pos = (int)(lseek(Files[fnum].fd_ptr->fd,pos+offset,SEEK_SET)
+ - offset);
return(Files[fnum].pos);
}
/****************************************************************************
read from a file
****************************************************************************/
-int read_file(int fnum,char *data,int pos,int mincnt,int maxcnt,int timeout,BOOL exact)
+int read_file(int fnum,char *data,uint32 pos,int n)
{
- int ret=0;
+ int ret=0,readret;
+#if USE_READ_PREDICTION
if (!Files[fnum].can_write)
{
- ret = read_predict(Files[fnum].fd,
- pos,
- data,
- NULL,
- maxcnt);
+ ret = read_predict(Files[fnum].fd_ptr->fd,pos,data,NULL,n);
data += ret;
- maxcnt -= ret;
- mincnt = MAX(mincnt-ret,0);
+ n -= ret;
pos += ret;
}
+#endif
#if USE_MMAP
if (Files[fnum].mmap_ptr)
{
- int num = MIN(maxcnt,Files[fnum].mmap_size-pos);
+ int num = MIN(n,(int)(Files[fnum].mmap_size-pos));
if (num > 0)
{
memcpy(data,Files[fnum].mmap_ptr+pos,num);
data += num;
pos += num;
- maxcnt -= num;
- mincnt = MAX(mincnt-num,0);
+ n -= num;
ret += num;
}
}
#endif
- if (maxcnt <= 0)
+ if (n <= 0)
return(ret);
if (seek_file(fnum,pos) != pos)
@@ -1587,13 +2010,10 @@ int read_file(int fnum,char *data,int pos,int mincnt,int maxcnt,int timeout,BOOL
return(ret);
}
- if (maxcnt > 0)
- ret += read_with_timeout(Files[fnum].fd,
- data,
- mincnt,
- maxcnt,
- timeout,
- exact);
+ if (n > 0) {
+ readret = read(Files[fnum].fd_ptr->fd,data,n);
+ if (readret > 0) ret += readret;
+ }
return(ret);
}
@@ -1609,14 +2029,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_ptr->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));
+ return(write_data(Files[fnum].fd_ptr->fd,data,n));
}
-static int old_umask = 022;
-
/****************************************************************************
load parameters specific to a connection/service
****************************************************************************/
@@ -1662,261 +2089,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)
@@ -2023,6 +2195,7 @@ struct
{EPERM,ERRDOS,ERRnoaccess},
{EACCES,ERRDOS,ERRnoaccess},
{ENOENT,ERRDOS,ERRbadfile},
+ {ENOTDIR,ERRDOS,ERRbadpath},
{EIO,ERRHRD,ERRgeneral},
{EBADF,ERRSRV,ERRsrverror},
{EINVAL,ERRSRV,ERRsrverror},
@@ -2043,7 +2216,6 @@ struct
{0,0,0}
};
-
/****************************************************************************
create an error packet from errno
****************************************************************************/
@@ -2063,15 +2235,15 @@ int unix_error_packet(char *inbuf,char *outbuf,int def_class,uint32 def_code,int
else
{
while (unix_smb_errmap[i].smbclass != 0)
- {
- if (unix_smb_errmap[i].unixerror == errno)
+ {
+ if (unix_smb_errmap[i].unixerror == errno)
{
eclass = unix_smb_errmap[i].smbclass;
ecode = unix_smb_errmap[i].smbcode;
break;
}
i++;
- }
+ }
}
return(error_packet(inbuf,outbuf,eclass,ecode,line));
@@ -2120,11 +2292,11 @@ static int sig_cld()
}
depth++;
- BlockSignals(True);
+ BlockSignals(True,SIGCLD);
DEBUG(5,("got SIGCLD\n"));
#ifdef USE_WAITPID
- while (waitpid((pid_t)-1,(int *)NULL, WNOHANG) > 0);
+ while (sys_waitpid((pid_t)-1,(int *)NULL, WNOHANG) > 0);
#endif
/* Stop zombies */
@@ -2146,7 +2318,7 @@ static int sig_cld()
while (wait3(WAIT3_CAST1 NULL, WNOHANG, WAIT3_CAST2 NULL) > 0);
#endif
depth--;
- BlockSignals(False);
+ BlockSignals(False,SIGCLD);
return 0;
}
#endif
@@ -2156,8 +2328,21 @@ static int sig_cld()
**************************************************************************/
static int sig_pipe()
{
- exit_server("Got sigpipe\n");
- return(0);
+ struct cli_state *cli;
+ BlockSignals(True,SIGPIPE);
+
+ if ((cli = server_client()) && cli->initialised) {
+ DEBUG(3,("lost connection to password server\n"));
+ cli_shutdown(cli);
+#ifndef DONT_REINSTALL_SIG
+ signal(SIGPIPE, SIGNAL_CAST sig_pipe);
+#endif
+ BlockSignals(False,SIGPIPE);
+ return 0;
+ }
+
+ exit_server("Got sigpipe\n");
+ return(0);
}
/****************************************************************************
@@ -2168,91 +2353,722 @@ static BOOL open_sockets(BOOL is_daemon,int port)
extern int Client;
if (is_daemon)
- {
- int s;
- struct sockaddr addr;
- int in_addrlen = sizeof(addr);
-
- /* Stop zombies */
+ {
+ int num_interfaces = iface_count();
+ int fd_listenset[FD_SETSIZE];
+ fd_set listen_set;
+ int s;
+ int i;
+
+ /* Stop zombies */
#ifdef SIGCLD_IGNORE
- signal(SIGCLD, SIG_IGN);
+ signal(SIGCLD, SIG_IGN);
#else
- signal(SIGCLD, SIGNAL_CAST sig_cld);
+ signal(SIGCLD, SIGNAL_CAST sig_cld);
#endif
+ if(atexit_set == 0)
+ atexit(killkids);
+
+ FD_ZERO(&listen_set);
+
+ if(lp_interfaces() && lp_bind_interfaces_only())
+ {
+ /* We have been given an interfaces line, and been
+ told to only bind to those interfaces. Create a
+ socket per interface and bind to only these.
+ */
+
+ if(num_interfaces > FD_SETSIZE)
+ {
+ DEBUG(0,("open_sockets: Too many interfaces specified to bind to. Number was %d \
+max can be %d\n", num_interfaces, FD_SETSIZE));
+ return False;
+ }
+
+ /* Now open a listen socket for each of the interfaces. */
+ for(i = 0; i < num_interfaces; i++)
+ {
+ struct in_addr *ifip = iface_n_ip(i);
+
+ if(ifip == NULL)
+ {
+ DEBUG(0,("open_sockets: interface %d has NULL IP address !\n", i));
+ continue;
+ }
+ s = fd_listenset[i] = open_socket_in(SOCK_STREAM, port, 0, ifip->s_addr);
+ if(s == -1)
+ return False;
+ /* ready to listen */
+ if (listen(s, 5) == -1)
+ {
+ DEBUG(0,("listen: %s\n",strerror(errno)));
+ close(s);
+ return False;
+ }
+ FD_SET(s,&listen_set);
+ }
+ }
+ else
+ {
+ /* Just bind to 0.0.0.0 - accept connections from anywhere. */
+ num_interfaces = 1;
+
/* open an incoming socket */
- s = open_socket_in(SOCK_STREAM, port, 0);
+ s = open_socket_in(SOCK_STREAM, port, 0,interpret_addr(lp_socket_address()));
if (s == -1)
- return(False);
+ return(False);
/* ready to listen */
if (listen(s, 5) == -1)
- {
- DEBUG(0,("listen: %s",strerror(errno)));
- close(s);
- return False;
- }
-
- /* now accept incoming connections - forking a new process
- for each incoming connection */
- DEBUG(2,("waiting for a connection\n"));
- while (1)
- {
- Client = accept(s,&addr,&in_addrlen);
+ {
+ DEBUG(0,("open_sockets: listen: %s\n",strerror(errno)));
+ close(s);
+ return False;
+ }
- if (Client == -1 && errno == EINTR)
- continue;
+ fd_listenset[0] = s;
+ FD_SET(s,&listen_set);
+ }
- if (Client == -1)
- {
- DEBUG(0,("accept: %s",strerror(errno)));
- return False;
- }
+ /* now accept incoming connections - forking a new process
+ for each incoming connection */
+ DEBUG(2,("waiting for a connection\n"));
+ while (1)
+ {
+ fd_set lfds;
+ int num;
+
+ memcpy((char *)&lfds, (char *)&listen_set, sizeof(listen_set));
+
+ num = sys_select(&lfds,NULL);
+
+ if (num == -1 && errno == EINTR)
+ continue;
+
+ /* Find the sockets that are read-ready - accept on these. */
+ for( ; num > 0; num--)
+ {
+ struct sockaddr addr;
+ int in_addrlen = sizeof(addr);
+
+ s = -1;
+ for(i = 0; i < num_interfaces; i++)
+ {
+ if(FD_ISSET(fd_listenset[i],&lfds))
+ {
+ s = fd_listenset[i];
+ /* Clear this so we don't look at it again. */
+ FD_CLR(fd_listenset[i],&lfds);
+ break;
+ }
+ }
+
+ Client = accept(s,&addr,&in_addrlen);
+
+ if (Client == -1 && errno == EINTR)
+ continue;
+
+ if (Client == -1)
+ {
+ DEBUG(0,("open_sockets: accept: %s\n",strerror(errno)));
+ continue;
+ }
#ifdef NO_FORK_DEBUG
#ifndef NO_SIGNAL_TEST
+ signal(SIGPIPE, SIGNAL_CAST sig_pipe);
+ signal(SIGCLD, SIGNAL_CAST SIG_DFL);
+#endif /* NO_SIGNAL_TEST */
+ return True;
+#else /* NO_FORK_DEBUG */
+ if (Client != -1 && fork()==0)
+ {
+ /* Child code ... */
+
+#ifndef NO_SIGNAL_TEST
signal(SIGPIPE, SIGNAL_CAST sig_pipe);
signal(SIGCLD, SIGNAL_CAST SIG_DFL);
-#endif
- return True;
-#else
- if (Client != -1 && fork()==0)
- {
+#endif /* NO_SIGNAL_TEST */
+ /* close the listening socket(s) */
+ for(i = 0; i < num_interfaces; i++)
+ close(fd_listenset[i]);
+
+ /* close our standard file descriptors */
+ close_low_fds();
+ am_parent = 0;
+
+ set_socket_options(Client,"SO_KEEPALIVE");
+ set_socket_options(Client,user_socket_options);
+
+ /* Reset global variables in util.c so that
+ client substitutions will be done correctly
+ in the process.
+ */
+ reset_globals_after_fork();
+ return True;
+ }
+ close(Client); /* The parent doesn't need this socket */
+#endif /NO_FORK_DEBUG */
+ } /* end for num */
+ } /* end while 1 */
+ } /* end if is_daemon */
+ else
+ {
+ /* Started from inetd. fd 0 is the socket. */
+ /* We will abort gracefully when the client or remote system
+ goes away */
#ifndef NO_SIGNAL_TEST
- signal(SIGPIPE, SIGNAL_CAST sig_pipe);
- signal(SIGCLD, SIGNAL_CAST SIG_DFL);
+ signal(SIGPIPE, SIGNAL_CAST sig_pipe);
#endif
- /* close our standard file descriptors */
- close_low_fds();
-
- set_socket_options(Client,"SO_KEEPALIVE");
- set_socket_options(Client,user_socket_options);
+ Client = dup(0);
- return True;
- }
- close(Client); /* The parent doesn't need this socket */
+ /* close our standard file descriptors */
+ close_low_fds();
+
+ set_socket_options(Client,"SO_KEEPALIVE");
+ set_socket_options(Client,user_socket_options);
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ process an smb from the client - split out from the process() code so
+ it can be used by the oplock break code.
+****************************************************************************/
+
+static void process_smb(char *inbuf, char *outbuf)
+{
+ extern int Client;
+ static int trans_num;
+ int msg_type = CVAL(inbuf,0);
+ int32 len = smb_len(inbuf);
+ int nread = len + 4;
+
+ if (trans_num == 0) {
+ /* on the first packet, check the global hosts allow/ hosts
+ deny parameters before doing any parsing of the packet
+ passed to us by the client. This prevents attacks on our
+ parsing code from hosts not in the hosts allow list */
+ if (!check_access(-1)) {
+ /* send a negative session response "not listining on calling
+ name" */
+ static unsigned char buf[5] = {0x83, 0, 0, 1, 0x81};
+ DEBUG(1,("%s Connection denied from %s\n",
+ timestring(),client_addr()));
+ send_smb(Client,(char *)buf);
+ exit_server("connection denied");
+ }
+ }
+
+ DEBUG(6,("got message type 0x%x of len 0x%x\n",msg_type,len));
+ DEBUG(3,("%s Transaction %d of length %d\n",timestring(),trans_num,nread));
+
+#ifdef WITH_VTP
+ if(trans_num == 1 && VT_Check(inbuf))
+ {
+ VT_Process();
+ return;
+ }
#endif
- }
+
+ if (msg_type == 0)
+ show_msg(inbuf);
+
+ nread = construct_reply(inbuf,outbuf,nread,max_send);
+
+ if(nread > 0)
+ {
+ if (CVAL(outbuf,0) == 0)
+ show_msg(outbuf);
+
+ if (nread != smb_len(outbuf) + 4)
+ {
+ DEBUG(0,("ERROR: Invalid message response size! %d %d\n",
+ nread, smb_len(outbuf)));
}
- else
+ else
+ send_smb(Client,outbuf);
+ }
+ trans_num++;
+}
+
+/****************************************************************************
+ open the oplock IPC socket communication
+****************************************************************************/
+static BOOL open_oplock_ipc()
+{
+ struct sockaddr_in sock_name;
+ int len = sizeof(sock_name);
+
+ DEBUG(3,("open_oplock_ipc: opening loopback UDP socket.\n"));
+
+ /* Open a lookback UDP socket on a random port. */
+ oplock_sock = open_socket_in(SOCK_DGRAM, 0, 0, htonl(INADDR_LOOPBACK));
+ if (oplock_sock == -1)
+ {
+ DEBUG(0,("open_oplock_ipc: Failed to get local UDP socket for \
+address %x. Error was %s\n", htonl(INADDR_LOOPBACK), strerror(errno)));
+ oplock_port = 0;
+ return(False);
+ }
+
+ /* Find out the transient UDP port we have been allocated. */
+ if(getsockname(oplock_sock, (struct sockaddr *)&sock_name, &len)<0)
+ {
+ DEBUG(0,("open_oplock_ipc: Failed to get local UDP port. Error was %s\n",
+ strerror(errno)));
+ close(oplock_sock);
+ oplock_sock = -1;
+ oplock_port = 0;
+ return False;
+ }
+ oplock_port = ntohs(sock_name.sin_port);
+
+ DEBUG(3,("open_oplock ipc: pid = %d, oplock_port = %u\n",
+ getpid(), oplock_port));
+
+ return True;
+}
+
+/****************************************************************************
+ process an oplock break message.
+****************************************************************************/
+static BOOL process_local_message(int sock, char *buffer, int buf_size)
+{
+ int32 msg_len;
+ uint16 from_port;
+ char *msg_start;
+
+ msg_len = IVAL(buffer,UDP_CMD_LEN_OFFSET);
+ from_port = SVAL(buffer,UDP_CMD_PORT_OFFSET);
+
+ msg_start = &buffer[UDP_CMD_HEADER_LEN];
+
+ DEBUG(5,("process_local_message: Got a message of length %d from port (%d)\n",
+ msg_len, from_port));
+
+ /* Switch on message command - currently OPLOCK_BREAK_CMD is the
+ only valid request. */
+
+ switch(SVAL(msg_start,UDP_MESSAGE_CMD_OFFSET))
+ {
+ case OPLOCK_BREAK_CMD:
+ /* Ensure that the msg length is correct. */
+ if(msg_len != OPLOCK_BREAK_MSG_LEN)
+ {
+ DEBUG(0,("process_local_message: incorrect length for OPLOCK_BREAK_CMD (was %d, \
+should be %d).\n", msg_len, OPLOCK_BREAK_MSG_LEN));
+ return False;
+ }
+ {
+ uint32 remotepid = IVAL(msg_start,OPLOCK_BREAK_PID_OFFSET);
+ uint32 dev = IVAL(msg_start,OPLOCK_BREAK_DEV_OFFSET);
+ uint32 inode = IVAL(msg_start, OPLOCK_BREAK_INODE_OFFSET);
+ struct timeval tval;
+ struct sockaddr_in toaddr;
+
+ tval.tv_sec = IVAL(msg_start, OPLOCK_BREAK_SEC_OFFSET);
+ tval.tv_usec = IVAL(msg_start, OPLOCK_BREAK_USEC_OFFSET);
+
+ DEBUG(5,("process_local_message: oplock break request from \
+pid %d, port %d, dev = %x, inode = %x\n", remotepid, from_port, dev, inode));
+
+ /*
+ * If we have no record of any currently open oplocks,
+ * it's not an error, as a close command may have
+ * just been issued on the file that was oplocked.
+ * Just return success in this case.
+ */
+
+ if(global_oplocks_open != 0)
+ {
+ if(oplock_break(dev, inode, &tval) == False)
+ {
+ DEBUG(0,("process_local_message: oplock break failed - \
+not returning udp message.\n"));
+ return False;
+ }
+ }
+ else
+ {
+ DEBUG(3,("process_local_message: oplock break requested with no outstanding \
+oplocks. Returning success.\n"));
+ }
+
+ /* Send the message back after OR'ing in the 'REPLY' bit. */
+ SSVAL(msg_start,UDP_MESSAGE_CMD_OFFSET,OPLOCK_BREAK_CMD | CMD_REPLY);
+
+ bzero((char *)&toaddr,sizeof(toaddr));
+ toaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ toaddr.sin_port = htons(from_port);
+ toaddr.sin_family = AF_INET;
+
+ if(sendto( sock, msg_start, OPLOCK_BREAK_MSG_LEN, 0,
+ (struct sockaddr *)&toaddr, sizeof(toaddr)) < 0)
+ {
+ DEBUG(0,("process_local_message: sendto process %d failed. Errno was %s\n",
+ remotepid, strerror(errno)));
+ return False;
+ }
+
+ DEBUG(5,("process_local_message: oplock break reply sent to \
+pid %d, port %d, for file dev = %x, inode = %x\n", remotepid,
+ from_port, dev, inode));
+
+ }
+ break;
+ /*
+ * Keep this as a debug case - eventually we can remove it.
+ */
+ case 0x8001:
+ DEBUG(0,("process_local_message: Received unsolicited break \
+reply - dumping info.\n"));
+
+ if(msg_len != OPLOCK_BREAK_MSG_LEN)
+ {
+ DEBUG(0,("process_local_message: ubr: incorrect length for reply \
+(was %d, should be %d).\n", msg_len, OPLOCK_BREAK_MSG_LEN));
+ return False;
+ }
+
+ {
+ uint32 remotepid = IVAL(msg_start,OPLOCK_BREAK_PID_OFFSET);
+ uint32 dev = IVAL(msg_start,OPLOCK_BREAK_DEV_OFFSET);
+ uint32 inode = IVAL(msg_start, OPLOCK_BREAK_INODE_OFFSET);
+
+ DEBUG(0,("process_local_message: unsolicited oplock break reply from \
+pid %d, port %d, dev = %x, inode = %x\n", remotepid, from_port, dev, inode));
+
+ }
+ return False;
+
+ default:
+ DEBUG(0,("process_local_message: unknown UDP message command code (%x) - ignoring.\n",
+ (unsigned int)SVAL(msg_start,0)));
+ return False;
+ }
+ return True;
+}
+
+/****************************************************************************
+ Process an oplock break directly.
+****************************************************************************/
+BOOL oplock_break(uint32 dev, uint32 inode, struct timeval *tval)
+{
+ extern int Client;
+ static char *inbuf = NULL;
+ static char *outbuf = NULL;
+ files_struct *fsp = NULL;
+ int fnum;
+ time_t start_time;
+ BOOL shutdown_server = False;
+
+ DEBUG(5,("oplock_break: called for dev = %x, inode = %x. Current \
+global_oplocks_open = %d\n", dev, inode, global_oplocks_open));
+
+ if(inbuf == NULL)
+ {
+ inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+ if(inbuf == NULL) {
+ DEBUG(0,("oplock_break: malloc fail for input buffer.\n"));
+ return False;
+ }
+ outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+ if(outbuf == NULL) {
+ DEBUG(0,("oplock_break: malloc fail for output buffer.\n"));
+ free(inbuf);
+ inbuf = NULL;
+ return False;
+ }
+ }
+
+ /* We need to search the file open table for the
+ entry containing this dev and inode, and ensure
+ we have an oplock on it. */
+ for( fnum = 0; fnum < MAX_OPEN_FILES; fnum++)
+ {
+ if(OPEN_FNUM(fnum))
{
- /* We will abort gracefully when the client or remote system
- goes away */
-#ifndef NO_SIGNAL_TEST
- signal(SIGPIPE, SIGNAL_CAST sig_pipe);
-#endif
- Client = dup(0);
+ fsp = &Files[fnum];
+ if((fsp->fd_ptr->dev == dev) && (fsp->fd_ptr->inode == inode) &&
+ (fsp->open_time.tv_sec == tval->tv_sec) &&
+ (fsp->open_time.tv_usec == tval->tv_usec))
+ break;
+ }
+ }
- /* close our standard file descriptors */
- close_low_fds();
+ if(fsp == NULL)
+ {
+ /* The file could have been closed in the meantime - return success. */
+ DEBUG(3,("oplock_break: cannot find open file with dev = %x, inode = %x (fnum = %d) \
+allowing break to succeed.\n", dev, inode, fnum));
+ return True;
+ }
- set_socket_options(Client,"SO_KEEPALIVE");
- set_socket_options(Client,user_socket_options);
+ /* Ensure we have an oplock on the file */
+
+ /* There is a potential race condition in that an oplock could
+ have been broken due to another udp request, and yet there are
+ still oplock break messages being sent in the udp message
+ queue for this file. So return true if we don't have an oplock,
+ as we may have just freed it.
+ */
+
+ if(!fsp->granted_oplock)
+ {
+ DEBUG(3,("oplock_break: file %s (fnum = %d, dev = %x, inode = %x) has no oplock. \
+Allowing break to succeed regardless.\n", fsp->name, fnum, dev, inode));
+ return True;
+ }
+
+ /* Now comes the horrid part. We must send an oplock break to the client,
+ and then process incoming messages until we get a close or oplock release.
+ */
+
+ /* Prepare the SMBlockingX message. */
+ bzero(outbuf,smb_size);
+ set_message(outbuf,8,0,True);
+
+ SCVAL(outbuf,smb_com,SMBlockingX);
+ SSVAL(outbuf,smb_tid,fsp->cnum);
+ SSVAL(outbuf,smb_pid,0xFFFF);
+ SSVAL(outbuf,smb_uid,0);
+ SSVAL(outbuf,smb_mid,0xFFFF);
+ SCVAL(outbuf,smb_vwv0,0xFF);
+ SSVAL(outbuf,smb_vwv2,fnum);
+ SCVAL(outbuf,smb_vwv3,LOCKING_ANDX_OPLOCK_RELEASE);
+ /* Change this when we have level II oplocks. */
+ SCVAL(outbuf,smb_vwv3+1,OPLOCKLEVEL_NONE);
+
+ send_smb(Client, outbuf);
+
+ global_oplock_break = True;
+
+ /* Process incoming messages. */
+
+ /* JRA - If we don't get a break from the client in OPLOCK_BREAK_TIMEOUT
+ seconds we should just die.... */
+
+ start_time = time(NULL);
+
+ while(OPEN_FNUM(fnum) && fsp->granted_oplock)
+ {
+ if(receive_smb(Client,inbuf,OPLOCK_BREAK_TIMEOUT * 1000) == False)
+ {
+ /*
+ * Die if we got an error.
+ */
+
+ if (smb_read_error == READ_EOF)
+ DEBUG(0,("oplock_break: end of file from client\n"));
+
+ if (smb_read_error == READ_ERROR)
+ DEBUG(0,("oplock_break: receive_smb error (%s)\n",
+ strerror(errno)));
+
+ if (smb_read_error == READ_TIMEOUT)
+ DEBUG(0,("oplock_break: receive_smb timed out after %d seconds.\n",
+ OPLOCK_BREAK_TIMEOUT));
+
+ DEBUG(0,("oplock_break failed for file %s (fnum = %d, dev = %x, \
+inode = %x).\n", fsp->name, fnum, dev, inode));
+ shutdown_server = True;
+ break;
+ }
+ process_smb(inbuf, outbuf);
+
+ /* We only need this in case a readraw crossed on the wire. */
+ if(global_oplock_break)
+ global_oplock_break = False;
+
+ /*
+ * Die if we go over the time limit.
+ */
+
+ if((time(NULL) - start_time) > OPLOCK_BREAK_TIMEOUT)
+ {
+ DEBUG(0,("oplock_break: no break received from client within \
+%d seconds.\n", OPLOCK_BREAK_TIMEOUT));
+ DEBUG(0,("oplock_break failed for file %s (fnum = %d, dev = %x, \
+inode = %x).\n", fsp->name, fnum, dev, inode));
+ shutdown_server = True;
+ break;
}
+ }
+
+ /*
+ * If the client did not respond we must die.
+ */
+
+ if(shutdown_server)
+ {
+ DEBUG(0,("oplock_break: client failure in break - shutting down this smbd.\n"));
+ close_sockets();
+ close(oplock_sock);
+ exit_server("oplock break failure");
+ }
+
+ if(OPEN_FNUM(fnum))
+ {
+ /* The lockingX reply will have removed the oplock flag
+ from the sharemode. */
+ /* Paranoia.... */
+ fsp->granted_oplock = False;
+ }
+
+ global_oplocks_open--;
+
+ /* Santity check - remove this later. JRA */
+ if(global_oplocks_open < 0)
+ {
+ DEBUG(0,("oplock_break: global_oplocks_open < 0 (%d). PANIC ERROR\n",
+ global_oplocks_open));
+ exit_server("oplock_break: global_oplocks_open < 0");
+ }
+
+ DEBUG(5,("oplock_break: returning success for fnum = %d, dev = %x, inode = %x. Current \
+global_oplocks_open = %d\n", fnum, dev, inode, global_oplocks_open));
return True;
}
+/****************************************************************************
+Send an oplock break message to another smbd process. If the oplock is held
+by the local smbd then call the oplock break function directly.
+****************************************************************************/
+
+BOOL request_oplock_break(share_mode_entry *share_entry,
+ uint32 dev, uint32 inode)
+{
+ char op_break_msg[OPLOCK_BREAK_MSG_LEN];
+ struct sockaddr_in addr_out;
+ int pid = getpid();
+
+ if(pid == share_entry->pid)
+ {
+ /* We are breaking our own oplock, make sure it's us. */
+ if(share_entry->op_port != oplock_port)
+ {
+ DEBUG(0,("request_oplock_break: corrupt share mode entry - pid = %d, port = %d \
+should be %d\n", pid, share_entry->op_port, oplock_port));
+ return False;
+ }
+
+ DEBUG(5,("request_oplock_break: breaking our own oplock\n"));
+
+ /* Call oplock break direct. */
+ return oplock_break(dev, inode, &share_entry->time);
+ }
+
+ /* We need to send a OPLOCK_BREAK_CMD message to the
+ port in the share mode entry. */
+
+ SSVAL(op_break_msg,UDP_MESSAGE_CMD_OFFSET,OPLOCK_BREAK_CMD);
+ SIVAL(op_break_msg,OPLOCK_BREAK_PID_OFFSET,pid);
+ SIVAL(op_break_msg,OPLOCK_BREAK_DEV_OFFSET,dev);
+ SIVAL(op_break_msg,OPLOCK_BREAK_INODE_OFFSET,inode);
+ SIVAL(op_break_msg,OPLOCK_BREAK_SEC_OFFSET,(uint32)share_entry->time.tv_sec);
+ SIVAL(op_break_msg,OPLOCK_BREAK_USEC_OFFSET,(uint32)share_entry->time.tv_usec);
+
+ /* set the address and port */
+ bzero((char *)&addr_out,sizeof(addr_out));
+ addr_out.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ addr_out.sin_port = htons( share_entry->op_port );
+ addr_out.sin_family = AF_INET;
+
+ DEBUG(3,("request_oplock_break: sending a oplock break message to pid %d on port %d \
+for dev = %x, inode = %x\n", share_entry->pid, share_entry->op_port, dev, inode));
+
+ if(sendto(oplock_sock,op_break_msg,OPLOCK_BREAK_MSG_LEN,0,
+ (struct sockaddr *)&addr_out,sizeof(addr_out)) < 0)
+ {
+ DEBUG(0,("request_oplock_break: failed when sending a oplock break message \
+to pid %d on port %d for dev = %x, inode = %x. Error was %s\n",
+ share_entry->pid, share_entry->op_port, dev, inode,
+ strerror(errno)));
+ return False;
+ }
+
+ /*
+ * Now we must await the oplock broken message coming back
+ * from the target smbd process. Timeout if it fails to
+ * return in OPLOCK_BREAK_TIMEOUT seconds.
+ * While we get messages that aren't ours, loop.
+ */
+
+ while(1)
+ {
+ char op_break_reply[UDP_CMD_HEADER_LEN+OPLOCK_BREAK_MSG_LEN];
+ int32 reply_msg_len;
+ uint16 reply_from_port;
+ char *reply_msg_start;
+
+ if(receive_local_message(oplock_sock, op_break_reply, sizeof(op_break_reply),
+ OPLOCK_BREAK_TIMEOUT * 1000) == False)
+ {
+ if(smb_read_error == READ_TIMEOUT)
+ DEBUG(0,("request_oplock_break: no response received to oplock break request to \
+pid %d on port %d for dev = %x, inode = %x\n", share_entry->pid,
+ share_entry->op_port, dev, inode));
+ else
+ DEBUG(0,("request_oplock_break: error in response received to oplock break request to \
+pid %d on port %d for dev = %x, inode = %x. Error was (%s).\n", share_entry->pid,
+ share_entry->op_port, dev, inode, strerror(errno)));
+ return False;
+ }
+
+ /*
+ * If the response we got was not an answer to our message, but
+ * was a completely different request, push it onto the pending
+ * udp message stack so that we can deal with it in the main loop.
+ * It may be another oplock break request to us.
+ */
+
+ /*
+ * Local note from JRA. There exists the possibility of a denial
+ * of service attack here by allowing non-root processes running
+ * on a local machine sending many of these pending messages to
+ * a smbd port. Currently I'm not sure how to restrict the messages
+ * I will queue (although I could add a limit to the queue) to
+ * those received by root processes only. There should be a
+ * way to make this bulletproof....
+ */
+
+ reply_msg_len = IVAL(op_break_reply,UDP_CMD_LEN_OFFSET);
+ reply_from_port = SVAL(op_break_reply,UDP_CMD_PORT_OFFSET);
+
+ reply_msg_start = &op_break_reply[UDP_CMD_HEADER_LEN];
+
+ if(reply_msg_len != OPLOCK_BREAK_MSG_LEN)
+ {
+ /* Ignore it. */
+ DEBUG(0,("request_oplock_break: invalid message length received. Ignoring\n"));
+ continue;
+ }
+
+ if(((SVAL(reply_msg_start,UDP_MESSAGE_CMD_OFFSET) & CMD_REPLY) == 0) ||
+ (reply_from_port != share_entry->op_port) ||
+ (memcmp(&reply_msg_start[OPLOCK_BREAK_PID_OFFSET],
+ &op_break_msg[OPLOCK_BREAK_PID_OFFSET],
+ OPLOCK_BREAK_MSG_LEN - OPLOCK_BREAK_PID_OFFSET) != 0))
+ {
+ DEBUG(3,("request_oplock_break: received other message whilst awaiting \
+oplock break response from pid %d on port %d for dev = %x, inode = %x.\n",
+ share_entry->pid, share_entry->op_port, dev, inode));
+ if(push_local_message(op_break_reply, sizeof(op_break_reply)) == False)
+ return False;
+ continue;
+ }
+
+ break;
+ }
+
+ DEBUG(3,("request_oplock_break: broke oplock.\n"));
+
+ return True;
+}
/****************************************************************************
check if a snum is in use
@@ -2276,10 +3092,10 @@ BOOL reload_services(BOOL test)
if (lp_loaded())
{
pstring fname;
- strcpy(fname,lp_configfile());
+ pstrcpy(fname,lp_configfile());
if (file_exist(fname,NULL) && !strcsequal(fname,servicesf))
{
- strcpy(servicesf,fname);
+ pstrcpy(servicesf,fname);
test = False;
}
}
@@ -2299,6 +3115,8 @@ BOOL reload_services(BOOL test)
reopen_logs();
+ load_interfaces();
+
{
extern int Client;
if (Client != -1) {
@@ -2322,13 +3140,13 @@ this prevents zombie child processes
****************************************************************************/
static int sig_hup()
{
- BlockSignals(True);
+ BlockSignals(True,SIGHUP);
DEBUG(0,("Got SIGHUP\n"));
reload_services(False);
#ifndef DONT_REINSTALL_SIG
signal(SIGHUP,SIGNAL_CAST sig_hup);
#endif
- BlockSignals(False);
+ BlockSignals(False,SIGHUP);
return(0);
}
@@ -2336,7 +3154,8 @@ static int sig_hup()
Setup the groups a user belongs to.
****************************************************************************/
int setup_groups(char *user, int uid, int gid, int *p_ngroups,
- int **p_igroups, gid_t **p_groups)
+ int **p_igroups, gid_t **p_groups,
+ int **p_attrs)
{
if (-1 == initgroups(user,gid))
{
@@ -2351,19 +3170,25 @@ int setup_groups(char *user, int uid, int gid, int *p_ngroups,
{
int i,ngroups;
int *igroups;
+ int *attrs;
gid_t grp = 0;
ngroups = getgroups(0,&grp);
if (ngroups <= 0)
ngroups = 32;
igroups = (int *)malloc(sizeof(int)*ngroups);
+ attrs = (int *)malloc(sizeof(int)*ngroups);
for (i=0;i<ngroups;i++)
+ {
+ attrs [i] = 0x7; /* XXXX don't know what NT user attributes are yet! */
igroups[i] = 0x42424242;
+ }
ngroups = getgroups(ngroups,(gid_t *)igroups);
if (igroups[0] == 0x42424242)
ngroups = 0;
*p_ngroups = ngroups;
+ *p_attrs = attrs;
/* The following bit of code is very strange. It is due to the
fact that some OSes use int* and some use gid_t* for
@@ -2385,16 +3210,18 @@ int setup_groups(char *user, int uid, int gid, int *p_ngroups,
groups_use_ints = False;
if (groups_use_ints)
- {
+ {
*p_igroups = igroups;
*p_groups = (gid_t *)igroups;
- }
+ }
else
- {
+ {
gid_t *groups = (gid_t *)igroups;
igroups = (int *)malloc(sizeof(int)*ngroups);
for (i=0;i<ngroups;i++)
+ {
igroups[i] = groups[i];
+ }
*p_igroups = igroups;
*p_groups = (gid_t *)groups;
}
@@ -2410,7 +3237,7 @@ int setup_groups(char *user, int uid, int gid, int *p_ngroups,
/****************************************************************************
make a connection to a service
****************************************************************************/
-int make_connection(char *service,char *user,char *password, int pwlen, char *dev,int vuid)
+int make_connection(char *service,char *user,char *password, int pwlen, char *dev,uint16 vuid)
{
int cnum;
int snum;
@@ -2520,8 +3347,17 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
}
/* admin user check */
- if (user_in_list(user,lp_admin_users(snum)) &&
- !pcon->read_only)
+
+ /* JRA - original code denied admin user if the share was
+ marked read_only. Changed as I don't think this is needed,
+ but old code left in case there is a problem here.
+ */
+ if (user_in_list(user,lp_admin_users(snum))
+#if 0
+ && !pcon->read_only)
+#else
+ )
+#endif
{
pcon->admin_user = True;
DEBUG(0,("%s logged in as admin user (root privileges)\n",user));
@@ -2530,6 +3366,7 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
pcon->admin_user = False;
pcon->force_user = force;
+ pcon->vuid = vuid;
pcon->uid = pass->pw_uid;
pcon->gid = pass->pw_gid;
pcon->num_files_open = 0;
@@ -2539,20 +3376,29 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
pcon->printer = (strncmp(dev,"LPT",3) == 0);
pcon->ipc = (strncmp(dev,"IPC",3) == 0);
pcon->dirptr = NULL;
+ pcon->veto_list = NULL;
+ pcon->hide_list = NULL;
string_set(&pcon->dirpath,"");
string_set(&pcon->user,user);
#if HAVE_GETGRNAM
if (*lp_force_group(snum))
{
- struct group *gptr = (struct group *)getgrnam(lp_force_group(snum));
+ struct group *gptr;
+ pstring gname;
+
+ StrnCpy(gname,lp_force_group(snum),sizeof(pstring)-1);
+ /* default service may be a group name */
+ string_sub(gname,"%S",service);
+ gptr = (struct group *)getgrnam(gname);
+
if (gptr)
{
pcon->gid = gptr->gr_gid;
- DEBUG(3,("Forced group %s\n",lp_force_group(snum)));
+ DEBUG(3,("Forced group %s\n",gname));
}
else
- DEBUG(1,("Couldn't find group %s\n",lp_force_group(snum)));
+ DEBUG(1,("Couldn't find group %s\n",gname));
}
#endif
@@ -2560,13 +3406,13 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
{
struct passwd *pass2;
fstring fuser;
- strcpy(fuser,lp_force_user(snum));
+ fstrcpy(fuser,lp_force_user(snum));
pass2 = (struct passwd *)Get_Pwnam(fuser,True);
if (pass2)
{
pcon->uid = pass2->pw_uid;
string_set(&pcon->user,fuser);
- strcpy(user,fuser);
+ fstrcpy(user,fuser);
pcon->force_user = True;
DEBUG(3,("Forced user %s\n",fuser));
}
@@ -2576,7 +3422,7 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
{
pstring s;
- strcpy(s,lp_pathname(snum));
+ pstrcpy(s,lp_pathname(snum));
standard_sub(cnum,s);
string_set(&pcon->connectpath,s);
DEBUG(3,("Connect path is %s\n",s));
@@ -2584,12 +3430,15 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
/* groups stuff added by ih */
pcon->ngroups = 0;
+ pcon->igroups = NULL;
pcon->groups = NULL;
+ pcon->attrs = NULL;
if (!IS_IPC(cnum))
{
/* Find all the groups this uid is in and store them. Used by become_user() */
- setup_groups(pcon->user,pcon->uid,pcon->gid,&pcon->ngroups,&pcon->igroups,&pcon->groups);
+ setup_groups(pcon->user,pcon->uid,pcon->gid,
+ &pcon->ngroups,&pcon->igroups,&pcon->groups,&pcon->attrs);
/* check number of connections */
if (!claim_connection(cnum,
@@ -2612,13 +3461,13 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
if (*lp_rootpreexec(SNUM(cnum)))
{
pstring cmd;
- strcpy(cmd,lp_rootpreexec(SNUM(cnum)));
+ pstrcpy(cmd,lp_rootpreexec(SNUM(cnum)));
standard_sub(cnum,cmd);
DEBUG(5,("cmd=%s\n",cmd));
- smbrun(cmd,NULL);
+ smbrun(cmd,NULL,False);
}
- if (!become_user(cnum,pcon->uid))
+ if (!become_user(&Connections[cnum], cnum,pcon->vuid))
{
DEBUG(0,("Can't become connected user!\n"));
pcon->open = False;
@@ -2633,7 +3482,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)) {
@@ -2651,7 +3501,7 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
/* resolve any soft links early */
{
pstring s;
- strcpy(s,pcon->connectpath);
+ pstrcpy(s,pcon->connectpath);
GetWd(s);
string_set(&pcon->connectpath,s);
ChDir(pcon->connectpath);
@@ -2665,19 +3515,26 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
if (*lp_preexec(SNUM(cnum)))
{
pstring cmd;
- strcpy(cmd,lp_preexec(SNUM(cnum)));
+ pstrcpy(cmd,lp_preexec(SNUM(cnum)));
standard_sub(cnum,cmd);
- smbrun(cmd,NULL);
+ smbrun(cmd,NULL,False);
}
/* we've finished with the sensitive stuff */
unbecome_user();
+ /* Add veto/hide lists */
+ if (!IS_IPC(cnum) && !IS_PRINT(cnum))
+ {
+ set_namearray( &pcon->veto_list, lp_veto_files(SNUM(cnum)));
+ set_namearray( &pcon->hide_list, lp_hide_files(SNUM(cnum)));
+ }
+
{
- extern struct from_host Client_info;
DEBUG(IS_IPC(cnum)?3:1,("%s %s (%s) connect to service %s as user %s (uid=%d,gid=%d) (pid %d)\n",
timestring(),
- Client_info.name,Client_info.addr,
+ remote_machine,
+ client_addr(),
lp_servicename(SNUM(cnum)),user,
pcon->uid,
pcon->gid,
@@ -2694,6 +3551,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);
@@ -2783,23 +3642,14 @@ int reply_lanman1(char *outbuf)
set_message(outbuf,13,doencrypt?8:0,True);
SSVAL(outbuf,smb_vwv1,secword);
-#ifdef SMB_PASSWD
/* Create a token value and add it to the outgoing packet. */
if (doencrypt)
generate_next_challenge(smb_buf(outbuf));
-#endif
Protocol = PROTOCOL_LANMAN1;
- if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) {
- DEBUG(3,("using password server validation\n"));
-#ifdef SMB_PASSWD
- if (doencrypt) set_challenge(smb_buf(outbuf));
-#endif
- }
-
CVAL(outbuf,smb_flg) = 0x81; /* Reply, SMBlockread, SMBwritelock supported */
- SSVAL(outbuf,smb_vwv2,maxxmit);
+ SSVAL(outbuf,smb_vwv2,max_recv);
SSVAL(outbuf,smb_vwv3,lp_maxmux()); /* maxmux */
SSVAL(outbuf,smb_vwv4,1);
SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support
@@ -2822,31 +3672,42 @@ int reply_lanman2(char *outbuf)
int secword=0;
BOOL doencrypt = SMBENCRYPT();
time_t t = time(NULL);
+ struct cli_state *cli = NULL;
+ char cryptkey[8];
+ char crypt_len = 0;
+
+ if (lp_security() == SEC_SERVER) {
+ cli = server_cryptkey();
+ }
+
+ if (cli) {
+ DEBUG(3,("using password server validation\n"));
+ doencrypt = ((cli->sec_mode & 2) != 0);
+ }
if (lp_security()>=SEC_USER) secword |= 1;
if (doencrypt) secword |= 2;
- set_message(outbuf,13,doencrypt?8:0,True);
- SSVAL(outbuf,smb_vwv1,secword);
-#ifdef SMB_PASSWD
- /* Create a token value and add it to the outgoing packet. */
- if (doencrypt)
- generate_next_challenge(smb_buf(outbuf));
-#endif
+ if (doencrypt) {
+ crypt_len = 8;
+ if (!cli) {
+ generate_next_challenge(cryptkey);
+ } else {
+ memcpy(cryptkey, cli->cryptkey, 8);
+ set_challenge(cli->cryptkey);
+ }
+ }
+ set_message(outbuf,13,crypt_len,True);
+ SSVAL(outbuf,smb_vwv1,secword);
SIVAL(outbuf,smb_vwv6,getpid());
+ if (doencrypt)
+ memcpy(smb_buf(outbuf), cryptkey, 8);
Protocol = PROTOCOL_LANMAN2;
- if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) {
- DEBUG(3,("using password server validation\n"));
-#ifdef SMB_PASSWD
- if (doencrypt) set_challenge(smb_buf(outbuf));
-#endif
- }
-
CVAL(outbuf,smb_flg) = 0x81; /* Reply, SMBlockread, SMBwritelock supported */
- SSVAL(outbuf,smb_vwv2,maxxmit);
+ SSVAL(outbuf,smb_vwv2,max_recv);
SSVAL(outbuf,smb_vwv3,lp_maxmux());
SSVAL(outbuf,smb_vwv4,1);
SSVAL(outbuf,smb_vwv5,raw); /* readbraw and/or writebraw */
@@ -2856,55 +3717,82 @@ int reply_lanman2(char *outbuf)
return (smb_len(outbuf)+4);
}
+
/****************************************************************************
reply for the nt protocol
****************************************************************************/
int reply_nt1(char *outbuf)
{
- int capabilities=0x300; /* has dual names + lock_and_read */
+ /* dual names + lock_and_read + nt SMBs + remote API calls */
+ int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ;
+/*
+ other valid capabilities which we may support at some time...
+ CAP_LARGE_FILES|CAP_NT_SMBS|CAP_RPC_REMOTE_APIS;
+ CAP_LARGE_READX|CAP_STATUS32|CAP_LEVEL_II_OPLOCKS;
+ */
+
int secword=0;
BOOL doencrypt = SMBENCRYPT();
+ time_t t = time(NULL);
+ int data_len;
+ struct cli_state *cli = NULL;
+ char cryptkey[8];
+ char crypt_len = 0;
- if (lp_security()>=SEC_USER) secword |= 1;
- if (doencrypt) secword |= 2;
+ if (lp_security() == SEC_SERVER) {
+ cli = server_cryptkey();
+ }
+
+ if (cli) {
+ DEBUG(3,("using password server validation\n"));
+ doencrypt = ((cli->sec_mode & 2) != 0);
+ }
- set_message(outbuf,17,doencrypt?8:0,True);
- CVAL(outbuf,smb_vwv1) = secword;
-#ifdef SMB_PASSWD
- /* Create a token value and add it to the outgoing packet. */
if (doencrypt) {
- generate_next_challenge(smb_buf(outbuf));
- /* Tell the nt machine how long the challenge is. */
- SSVALS(outbuf,smb_vwv16+1,8);
+ crypt_len = 8;
+ if (!cli) {
+ generate_next_challenge(cryptkey);
+ } else {
+ memcpy(cryptkey, cli->cryptkey, 8);
+ set_challenge(cli->cryptkey);
+ }
}
-#endif
- SIVAL(outbuf,smb_vwv7+1,getpid()); /* session key */
+ if (lp_readraw() && lp_writeraw()) {
+ capabilities |= CAP_RAW_MODE;
+ }
- Protocol = PROTOCOL_NT1;
+ if (lp_security() >= SEC_USER) secword |= 1;
+ if (doencrypt) secword |= 2;
- if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) {
- DEBUG(3,("using password server validation\n"));
-#ifdef SMB_PASSWD
- if (doencrypt) set_challenge(smb_buf(outbuf));
-#endif
- }
+ /* decide where (if) to put the encryption challenge, and
+ follow it with the OEM'd domain name
+ */
+ data_len = crypt_len + strlen(myworkgroup) + 1;
- if (lp_readraw() && lp_writeraw())
- capabilities |= 1;
+ set_message(outbuf,17,data_len,True);
+ strcpy(smb_buf(outbuf)+crypt_len, myworkgroup);
+
+ CVAL(outbuf,smb_vwv1) = secword;
+ SSVALS(outbuf,smb_vwv16+1,crypt_len);
+ if (doencrypt)
+ memcpy(smb_buf(outbuf), cryptkey, 8);
+
+ Protocol = PROTOCOL_NT1;
SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */
SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */
- SIVAL(outbuf,smb_vwv3+1,0xFFFF); /* max buffer */
- SIVAL(outbuf,smb_vwv5+1,0xFFFF); /* raw size */
+ SIVAL(outbuf,smb_vwv3+1,0xffff); /* max buffer. LOTS! */
+ SIVAL(outbuf,smb_vwv5+1,0xffff); /* raw size. LOTS! */
+ SIVAL(outbuf,smb_vwv7+1,getpid()); /* session key */
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);
+ SSVAL(outbuf,smb_vwv17,data_len); /* length of challenge+domain strings */
return (smb_len(outbuf)+4);
}
-
/* these are the protocol lists used for auto architecture detection:
WinNT 3.51:
@@ -2989,7 +3877,6 @@ struct {
****************************************************************************/
static int reply_negprot(char *inbuf,char *outbuf)
{
- extern fstring remote_arch;
int outsize = set_message(outbuf,1,0,True);
int Index=0;
int choice= -1;
@@ -3029,22 +3916,22 @@ static int reply_negprot(char *inbuf,char *outbuf)
switch ( arch ) {
case ARCH_SAMBA:
- strcpy(remote_arch,"Samba");
+ set_remote_arch(RA_SAMBA);
break;
case ARCH_WFWG:
- strcpy(remote_arch,"WfWg");
+ set_remote_arch(RA_WFWG);
break;
case ARCH_WIN95:
- strcpy(remote_arch,"Win95");
+ set_remote_arch(RA_WIN95);
break;
case ARCH_WINNT:
- strcpy(remote_arch,"WinNT");
+ set_remote_arch(RA_WINNT);
break;
case ARCH_OS2:
- strcpy(remote_arch,"OS2");
+ set_remote_arch(RA_OS2);
break;
default:
- strcpy(remote_arch,"UNKNOWN");
+ set_remote_arch(RA_UNKNOWN);
break;
}
@@ -3076,7 +3963,7 @@ static int reply_negprot(char *inbuf,char *outbuf)
SSVAL(outbuf,smb_vwv0,choice);
if(choice != -1) {
extern fstring remote_proto;
- strcpy(remote_proto,supported_protocols[protocol].short_name);
+ fstrcpy(remote_proto,supported_protocols[protocol].short_name);
reload_services(True);
outsize = supported_protocols[protocol].proto_reply_fn(outbuf);
DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name));
@@ -3093,41 +3980,6 @@ static int reply_negprot(char *inbuf,char *outbuf)
/****************************************************************************
- parse a connect packet
-****************************************************************************/
-void parse_connect(char *buf,char *service,char *user,char *password,int *pwlen,char *dev)
-{
- char *p = smb_buf(buf) + 1;
- char *p2;
-
- DEBUG(4,("parsing connect string %s\n",p));
-
- p2 = strrchr(p,'\\');
- if (p2 == NULL)
- strcpy(service,p);
- else
- strcpy(service,p2+1);
-
- p += strlen(p) + 2;
-
- strcpy(password,p);
- *pwlen = strlen(password);
-
- p += strlen(p) + 2;
-
- strcpy(dev,p);
-
- *user = 0;
- p = strchr(service,'%');
- if (p != NULL)
- {
- *p = 0;
- strcpy(user,p+1);
- }
-}
-
-
-/****************************************************************************
close all open files for a connection
****************************************************************************/
static void close_open_files(int cnum)
@@ -3135,7 +3987,7 @@ static void close_open_files(int cnum)
int i;
for (i=0;i<MAX_OPEN_FILES;i++)
if( Files[i].cnum == cnum && Files[i].open) {
- close_file(i);
+ close_file(i,False);
}
}
@@ -3144,10 +3996,8 @@ static void close_open_files(int cnum)
/****************************************************************************
close a cnum
****************************************************************************/
-void close_cnum(int cnum, int uid)
+void close_cnum(int cnum, uint16 vuid)
{
- extern struct from_host Client_info;
-
DirCacheFlush(SNUM(cnum));
unbecome_user();
@@ -3160,7 +4010,7 @@ void close_cnum(int cnum, int uid)
DEBUG(IS_IPC(cnum)?3:1,("%s %s (%s) closed connection to service %s\n",
timestring(),
- Client_info.name,Client_info.addr,
+ remote_machine,client_addr(),
lp_servicename(SNUM(cnum))));
yield_connection(cnum,
@@ -3174,12 +4024,12 @@ void close_cnum(int cnum, int uid)
dptr_closecnum(cnum);
/* execute any "postexec = " line */
- if (*lp_postexec(SNUM(cnum)) && become_user(cnum,uid))
+ if (*lp_postexec(SNUM(cnum)) && become_user(&Connections[cnum], cnum,vuid))
{
pstring cmd;
strcpy(cmd,lp_postexec(SNUM(cnum)));
standard_sub(cnum,cmd);
- smbrun(cmd,NULL);
+ smbrun(cmd,NULL,False);
unbecome_user();
}
@@ -3190,7 +4040,7 @@ void close_cnum(int cnum, int uid)
pstring cmd;
strcpy(cmd,lp_rootpostexec(SNUM(cnum)));
standard_sub(cnum,cmd);
- smbrun(cmd,NULL);
+ smbrun(cmd,NULL,False);
}
Connections[cnum].open = False;
@@ -3205,6 +4055,9 @@ void close_cnum(int cnum, int uid)
Connections[cnum].ngroups = 0;
}
+ free_namearray(Connections[cnum].veto_list);
+ free_namearray(Connections[cnum].hide_list);
+
string_set(&Connections[cnum].user,"");
string_set(&Connections[cnum].dirpath,"");
string_set(&Connections[cnum].connectpath,"");
@@ -3229,7 +4082,7 @@ BOOL yield_connection(int cnum,char *name,int max_connections)
bzero(&crec,sizeof(crec));
- strcpy(fname,lp_lockdir());
+ pstrcpy(fname,lp_lockdir());
standard_sub(cnum,fname);
trim_string(fname,"","/");
@@ -3240,7 +4093,7 @@ BOOL yield_connection(int cnum,char *name,int max_connections)
f = fopen(fname,"r+");
if (!f)
{
- DEBUG(2,("Coudn't open lock file %s (%s)\n",fname,strerror(errno)));
+ DEBUG(2,("Couldn't open lock file %s (%s)\n",fname,strerror(errno)));
return(False);
}
@@ -3301,7 +4154,7 @@ BOOL claim_connection(int cnum,char *name,int max_connections,BOOL Clear)
DEBUG(5,("trying claim %s %s %d\n",lp_lockdir(),name,max_connections));
- strcpy(fname,lp_lockdir());
+ pstrcpy(fname,lp_lockdir());
standard_sub(cnum,fname);
trim_string(fname,"","/");
@@ -3314,8 +4167,10 @@ BOOL claim_connection(int cnum,char *name,int max_connections,BOOL Clear)
if (!file_exist(fname,NULL))
{
+ int oldmask = umask(022);
f = fopen(fname,"w");
if (f) fclose(f);
+ umask(oldmask);
}
total_recs = file_size(fname) / sizeof(crec);
@@ -3372,11 +4227,8 @@ BOOL claim_connection(int cnum,char *name,int max_connections,BOOL Clear)
StrnCpy(crec.name,lp_servicename(snum),sizeof(crec.name)-1);
crec.start = time(NULL);
- {
- extern struct from_host Client_info;
- StrnCpy(crec.machine,Client_info.name,sizeof(crec.machine)-1);
- StrnCpy(crec.addr,Client_info.addr,sizeof(crec.addr)-1);
- }
+ StrnCpy(crec.machine,remote_machine,sizeof(crec.machine)-1);
+ StrnCpy(crec.addr,client_addr(),sizeof(crec.addr)-1);
/* make our mark */
if (fseek(f,foundi*sizeof(crec),SEEK_SET) != 0 ||
@@ -3398,7 +4250,7 @@ static BOOL dump_core(void)
{
char *p;
pstring dname;
- strcpy(dname,debugf);
+ pstrcpy(dname,debugf);
if ((p=strrchr(dname,'/'))) *p=0;
strcat(dname,"/corefiles");
mkdir(dname,0700);
@@ -3441,7 +4293,7 @@ void exit_server(char *reason)
DEBUG(2,("Closing connections\n"));
for (i=0;i<MAX_CONNECTIONS;i++)
if (Connections[i].open)
- close_cnum(i,-1);
+ close_cnum(i,(uint16)-1);
#ifdef DFS_AUTH
if (dcelogin_atmost_once)
dfs_unlogin();
@@ -3458,6 +4310,9 @@ void exit_server(char *reason)
if (dump_core()) return;
#endif
}
+
+ locking_end();
+
DEBUG(3,("%s Server exit (%s)\n",timestring(),reason?reason:""));
exit(0);
}
@@ -3465,22 +4320,28 @@ void exit_server(char *reason)
/****************************************************************************
do some standard substitutions in a string
****************************************************************************/
-void standard_sub(int cnum,char *s)
+void standard_sub(int cnum,char *str)
{
- if (!strchr(s,'%')) return;
-
- if (VALID_CNUM(cnum))
- {
- string_sub(s,"%S",lp_servicename(Connections[cnum].service));
- string_sub(s,"%P",Connections[cnum].connectpath);
- string_sub(s,"%u",Connections[cnum].user);
- if (strstr(s,"%H")) {
- char *home = get_home_dir(Connections[cnum].user);
- if (home) string_sub(s,"%H",home);
+ if (VALID_CNUM(cnum)) {
+ char *p, *s, *home;
+
+ for ( s=str ; (p=strchr(s, '%')) != NULL ; s=p ) {
+ switch (*(p+1)) {
+ case 'H' : if ((home = get_home_dir(Connections[cnum].user))!=NULL)
+ string_sub(p,"%H",home);
+ else
+ p += 2;
+ break;
+ case 'P' : string_sub(p,"%P",Connections[cnum].connectpath); break;
+ case 'S' : string_sub(p,"%S",lp_servicename(Connections[cnum].service)); break;
+ case 'g' : string_sub(p,"%g",gidtoname(Connections[cnum].gid)); break;
+ case 'u' : string_sub(p,"%u",Connections[cnum].user); break;
+ case '\0' : p++; break; /* don't run off the end of the string */
+ default : p+=2; break;
}
- string_sub(s,"%g",gidtoname(Connections[cnum].gid));
}
- standard_sub_basic(s);
+ }
+ standard_sub_basic(str);
}
/*
@@ -3524,7 +4385,7 @@ struct smb_message_struct
{SMBecho,"SMBecho",reply_echo,0},
{SMBsesssetupX,"SMBsesssetupX",reply_sesssetup_and_X,0},
{SMBtconX,"SMBtconX",reply_tcon_and_X,0},
- {SMBulogoffX, "SMBulogoffX", reply_ulogoffX, 0},
+ {SMBulogoffX, "SMBulogoffX", reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */
{SMBgetatr,"SMBgetatr",reply_getatr,AS_USER},
{SMBsetatr,"SMBsetatr",reply_setatr,AS_USER | NEED_WRITE},
{SMBchkpth,"SMBchkpth",reply_chkpth,AS_USER},
@@ -3538,7 +4399,7 @@ struct smb_message_struct
{SMBunlink,"SMBunlink",reply_unlink,AS_USER | NEED_WRITE},
{SMBread,"SMBread",reply_read,AS_USER},
{SMBwrite,"SMBwrite",reply_write,AS_USER},
- {SMBclose,"SMBclose",reply_close,AS_USER},
+ {SMBclose,"SMBclose",reply_close,AS_USER | CAN_IPC},
{SMBmkdir,"SMBmkdir",reply_mkdir,AS_USER | NEED_WRITE},
{SMBrmdir,"SMBrmdir",reply_rmdir,AS_USER | NEED_WRITE},
{SMBdskattr,"SMBdskattr",reply_dskattr,AS_USER},
@@ -3553,7 +4414,7 @@ struct smb_message_struct
{SMBctemp,"SMBctemp",reply_ctemp,AS_USER},
{SMBsplopen,"SMBsplopen",reply_printopen,AS_USER},
{SMBsplclose,"SMBsplclose",reply_printclose,AS_USER},
- {SMBsplretq,"SMBsplretq",reply_printqueue,AS_USER},
+ {SMBsplretq,"SMBsplretq",reply_printqueue,AS_USER|AS_GUEST},
{SMBsplwr,"SMBsplwr",reply_printwrite,AS_USER},
{SMBlock,"SMBlock",reply_lock,AS_USER},
{SMBunlock,"SMBunlock",reply_unlock,AS_USER},
@@ -3581,7 +4442,7 @@ struct smb_message_struct
{SMBcopy,"SMBcopy",reply_copy,AS_USER | NEED_WRITE},
{SMBmove,"SMBmove",NULL,AS_USER | NEED_WRITE},
- {SMBopenX,"SMBopenX",reply_open_and_X,AS_USER},
+ {SMBopenX,"SMBopenX",reply_open_and_X,AS_USER | CAN_IPC},
{SMBreadX,"SMBreadX",reply_read_and_X,AS_USER},
{SMBwriteX,"SMBwriteX",reply_write_and_X,AS_USER},
{SMBlockingX,"SMBlockingX",reply_lockingX,AS_USER},
@@ -3679,15 +4540,24 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize
{
int cnum = SVAL(inbuf,smb_tid);
int flags = smb_messages[match].flags;
- int uid = SVAL(inbuf,smb_uid);
+ uint16 session_tag = SVAL(inbuf,smb_uid);
/* does this protocol need to be run as root? */
if (!(flags & AS_USER))
unbecome_user();
/* does this protocol need to be run as the connected user? */
- if ((flags & AS_USER) && !become_user(cnum,uid))
- return(ERROR(ERRSRV,ERRinvnid));
+ if ((flags & AS_USER) && !become_user(&Connections[cnum], cnum,session_tag)) {
+ if (flags & AS_GUEST)
+ flags &= ~AS_USER;
+ else
+ return(ERROR(ERRSRV,ERRinvnid));
+ }
+ /* this code is to work around a bug is MS client 3 without
+ introducing a security hole - it needs to be able to do
+ print queue checks as guest if it isn't logged in properly */
+ if (flags & AS_USER)
+ flags &= ~AS_GUEST;
/* does it need write permission? */
if ((flags & NEED_WRITE) && !CAN_WRITE(cnum))
@@ -3739,103 +4609,99 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize
/****************************************************************************
-construct a chained reply and add it to the already made reply
-
-inbuf points to the original message start.
-inbuf2 points to the smb_wct part of the secondary message
-type is the type of the secondary message
-outbuf points to the original outbuffer
-outbuf2 points to the smb_wct field of the new outbuffer
-size is the total length of the incoming message (from inbuf1)
-bufsize is the total buffer size
-
-return how many bytes were added to the response
-****************************************************************************/
-int chain_reply(int type,char *inbuf,char *inbuf2,char *outbuf,char *outbuf2,int size,int bufsize)
+ construct a chained reply and add it to the already made reply
+ **************************************************************************/
+int chain_reply(char *inbuf,char *outbuf,int size,int bufsize)
{
- int outsize = 0;
- char *ibuf,*obuf;
- static BOOL in_chain = False;
- static char *last_outbuf=NULL;
- BOOL was_inchain = in_chain;
- int insize_remaining;
- static int insize_deleted;
-
-
- chain_size += PTR_DIFF(outbuf2,outbuf) - smb_wct;
- if (was_inchain)
- outbuf = last_outbuf;
- else
- insize_deleted = 0;
+ static char *orig_inbuf;
+ static char *orig_outbuf;
+ int smb_com1, smb_com2 = CVAL(inbuf,smb_vwv0);
+ unsigned smb_off2 = SVAL(inbuf,smb_vwv1);
+ char *inbuf2, *outbuf2;
+ int outsize2;
+ char inbuf_saved[smb_wct];
+ char outbuf_saved[smb_wct];
+ extern int chain_size;
+ int wct = CVAL(outbuf,smb_wct);
+ int outsize = smb_size + 2*wct + SVAL(outbuf,smb_vwv0+2*wct);
+
+ /* maybe its not chained */
+ if (smb_com2 == 0xFF) {
+ CVAL(outbuf,smb_vwv0) = 0xFF;
+ return outsize;
+ }
+ if (chain_size == 0) {
+ /* this is the first part of the chain */
+ orig_inbuf = inbuf;
+ orig_outbuf = outbuf;
+ }
- insize_deleted = 0;
- inbuf2 -= insize_deleted;
- insize_remaining = size - PTR_DIFF(inbuf2,inbuf);
- insize_deleted += size - (insize_remaining + smb_wct);
+ /* we need to tell the client where the next part of the reply will be */
+ SSVAL(outbuf,smb_vwv1,smb_offset(outbuf+outsize,outbuf));
+ CVAL(outbuf,smb_vwv0) = smb_com2;
- in_chain = True;
- last_outbuf = outbuf;
+ /* remember how much the caller added to the chain, only counting stuff
+ after the parameter words */
+ chain_size += outsize - smb_wct;
+ /* work out pointers into the original packets. The
+ headers on these need to be filled in */
+ inbuf2 = orig_inbuf + smb_off2 + 4 - smb_wct;
+ outbuf2 = orig_outbuf + SVAL(outbuf,smb_vwv1) + 4 - smb_wct;
- /* allocate some space for the in and out buffers of the chained message */
- ibuf = (char *)malloc(size + SAFETY_MARGIN);
- obuf = (char *)malloc(bufsize + SAFETY_MARGIN);
+ /* remember the original command type */
+ smb_com1 = CVAL(orig_inbuf,smb_com);
- if (!ibuf || !obuf)
- {
- DEBUG(0,("Out of memory in chain reply\n"));
- return(ERROR(ERRSRV,ERRnoresource));
- }
+ /* save the data which will be overwritten by the new headers */
+ memcpy(inbuf_saved,inbuf2,smb_wct);
+ memcpy(outbuf_saved,outbuf2,smb_wct);
- ibuf += SMB_ALIGNMENT;
- obuf += SMB_ALIGNMENT;
+ /* give the new packet the same header as the last part of the SMB */
+ memmove(inbuf2,inbuf,smb_wct);
/* create the in buffer */
- memcpy(ibuf,inbuf,smb_wct);
- memcpy(ibuf+smb_wct,inbuf2,insize_remaining);
- CVAL(ibuf,smb_com) = type;
+ CVAL(inbuf2,smb_com) = smb_com2;
/* create the out buffer */
- bzero(obuf,smb_size);
-
- set_message(obuf,0,0,True);
- CVAL(obuf,smb_com) = CVAL(ibuf,smb_com);
+ bzero(outbuf2,smb_size);
+ set_message(outbuf2,0,0,True);
+ CVAL(outbuf2,smb_com) = CVAL(inbuf2,smb_com);
- memcpy(obuf+4,ibuf+4,4);
- CVAL(obuf,smb_rcls) = SUCCESS;
- CVAL(obuf,smb_reh) = 0;
- CVAL(obuf,smb_flg) = 0x80 | (CVAL(ibuf,smb_flg) & 0x8); /* bit 7 set
- means a reply */
- SSVAL(obuf,smb_flg2,1); /* say we support long filenames */
- SSVAL(obuf,smb_err,SUCCESS);
- SSVAL(obuf,smb_tid,SVAL(inbuf,smb_tid));
- SSVAL(obuf,smb_pid,SVAL(inbuf,smb_pid));
- SSVAL(obuf,smb_uid,SVAL(inbuf,smb_uid));
- SSVAL(obuf,smb_mid,SVAL(inbuf,smb_mid));
+ memcpy(outbuf2+4,inbuf2+4,4);
+ CVAL(outbuf2,smb_rcls) = SUCCESS;
+ CVAL(outbuf2,smb_reh) = 0;
+ CVAL(outbuf2,smb_flg) = 0x80 | (CVAL(inbuf2,smb_flg) & 0x8); /* bit 7 set
+ means a reply */
+ SSVAL(outbuf2,smb_flg2,1); /* say we support long filenames */
+ SSVAL(outbuf2,smb_err,SUCCESS);
+ SSVAL(outbuf2,smb_tid,SVAL(inbuf2,smb_tid));
+ SSVAL(outbuf2,smb_pid,SVAL(inbuf2,smb_pid));
+ SSVAL(outbuf2,smb_uid,SVAL(inbuf2,smb_uid));
+ SSVAL(outbuf2,smb_mid,SVAL(inbuf2,smb_mid));
DEBUG(3,("Chained message\n"));
- show_msg(ibuf);
+ show_msg(inbuf2);
/* process the request */
- outsize = switch_message(type,ibuf,obuf,smb_wct+insize_remaining,
- bufsize-chain_size);
-
- /* copy the new reply header over the old one, but preserve
- the smb_com field */
- memcpy(outbuf+smb_com+1,obuf+smb_com+1,smb_wct-(smb_com+1));
+ outsize2 = switch_message(smb_com2,inbuf2,outbuf2,size-chain_size,
+ bufsize-chain_size);
- /* and copy the data from the reply to the right spot */
- memcpy(outbuf2,obuf+smb_wct,outsize - smb_wct);
+ /* copy the new reply and request headers over the old ones, but
+ preserve the smb_com field */
+ memmove(orig_outbuf,outbuf2,smb_wct);
+ CVAL(orig_outbuf,smb_com) = smb_com1;
- /* free the allocated buffers */
- if (ibuf) free(ibuf-SMB_ALIGNMENT);
- if (obuf) free(obuf-SMB_ALIGNMENT);
-
- in_chain = was_inchain;
+ /* restore the saved data, being careful not to overwrite any
+ data from the reply header */
+ memcpy(inbuf2,inbuf_saved,smb_wct);
+ {
+ int ofs = smb_wct - PTR_DIFF(outbuf2,orig_outbuf);
+ if (ofs < 0) ofs = 0;
+ memmove(outbuf2+ofs,outbuf_saved+ofs,smb_wct-ofs);
+ }
- /* return how much extra has been added to the packet */
- return(outsize - smb_wct);
+ return outsize2;
}
@@ -3848,10 +4714,12 @@ int construct_reply(char *inbuf,char *outbuf,int size,int bufsize)
int type = CVAL(inbuf,smb_com);
int outsize = 0;
int msg_type = CVAL(inbuf,0);
+ extern int chain_size;
smb_last_time = time(NULL);
chain_size = 0;
+ chain_fnum = -1;
bzero(outbuf,smb_size);
@@ -3875,24 +4743,20 @@ int construct_reply(char *inbuf,char *outbuf,int size,int bufsize)
outsize = switch_message(type,inbuf,outbuf,size,bufsize);
+ outsize += chain_size;
+
if(outsize > 4)
smb_setlen(outbuf,outsize - 4);
return(outsize);
}
-
/****************************************************************************
process commands from the client
****************************************************************************/
-void process(void )
+static void process(void)
{
- static int trans_num = 0;
- int nread;
- extern struct from_host Client_info;
extern int Client;
- fromhost(Client,&Client_info);
-
InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
if ((InBuffer == NULL) || (OutBuffer == NULL))
@@ -3908,153 +4772,117 @@ 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;
- int msg_type;
- int msg_flags;
- int type;
- int deadtime = lp_deadtime()*60;
- int counter;
- int last_keepalive=0;
+ {
+ int deadtime = lp_deadtime()*60;
+ int counter;
+ int last_keepalive=0;
+ int service_load_counter = 0;
+ BOOL got_smb = False;
+
+ if (deadtime <= 0)
+ deadtime = DEFAULT_SMBD_TIMEOUT;
+
+#if USE_READ_PREDICTION
+ if (lp_readprediction())
+ do_read_prediction();
+#endif
- if (deadtime <= 0)
- deadtime = DEFAULT_SMBD_TIMEOUT;
+ errno = 0;
- if (lp_readprediction())
- do_read_prediction();
+ for (counter=SMBD_SELECT_LOOP;
+ !receive_message_or_smb(Client,oplock_sock,
+ InBuffer,BUFFER_SIZE,SMBD_SELECT_LOOP*1000,&got_smb);
+ counter += SMBD_SELECT_LOOP)
+ {
+ int i;
+ time_t t;
+ BOOL allidle = True;
+ extern int keepalive;
+ if (counter > 365 * 3600) /* big number of seconds. */
{
- extern pstring share_del_pending;
- if (*share_del_pending) {
- unbecome_user();
- if (!unlink(share_del_pending))
- DEBUG(3,("Share file deleted %s\n",share_del_pending));
- else
- DEBUG(2,("Share del failed of %s\n",share_del_pending));
- share_del_pending[0] = 0;
- }
+ counter = 0;
+ service_load_counter = 0;
}
- if (share_mode_pending) {
- unbecome_user();
- check_share_modes();
- share_mode_pending=False;
+ if (smb_read_error == READ_EOF)
+ {
+ DEBUG(3,("end of file from client\n"));
+ return;
}
- errno = 0;
-
- for (counter=SMBD_SELECT_LOOP;
- !receive_smb(Client,InBuffer,SMBD_SELECT_LOOP*1000);
- counter += SMBD_SELECT_LOOP)
- {
- int i;
- time_t t;
- BOOL allidle = True;
- extern int keepalive;
-
- /* check for socket failure */
- if (errno == EBADF) {
- DEBUG(3,("%s Bad file descriptor - exiting\n",timestring()));
- return;
- }
-
- t = time(NULL);
-
- /* become root again if waiting */
- unbecome_user();
-
- /* check for smb.conf reload */
- if (!(counter%SMBD_RELOAD_CHECK))
- reload_services(True);
-
- /* check the share modes every 10 secs */
- if (!(counter%SHARE_MODES_CHECK))
- check_share_modes();
-
- /* clean the share modes every 5 minutes */
- if (!(counter%SHARE_MODES_CLEAN))
- clean_share_files();
-
- /* automatic timeout if all connections are closed */
- if (num_connections_open==0 && counter >= IDLE_CLOSED_TIMEOUT) {
- DEBUG(2,("%s Closing idle connection\n",timestring()));
- return;
- }
-
- if (keepalive && (counter-last_keepalive)>keepalive) {
- if (!send_keepalive(Client)) {
- DEBUG(2,("%s Keepalive failed - exiting\n",timestring()));
- return;
- }
- last_keepalive = counter;
- }
-
- /* check for connection timeouts */
- for (i=0;i<MAX_CONNECTIONS;i++)
- if (Connections[i].open)
- {
- /* close dirptrs on connections that are idle */
- if ((t-Connections[i].lastused)>DPTR_IDLE_TIMEOUT)
- dptr_idlecnum(i);
-
- if (Connections[i].num_files_open > 0 ||
- (t-Connections[i].lastused)<deadtime)
- allidle = False;
- }
-
- if (allidle && num_connections_open>0) {
- DEBUG(2,("%s Closing idle connection 2\n",timestring()));
- return;
- }
- }
+ if (smb_read_error == READ_ERROR)
+ {
+ DEBUG(3,("receive_smb error (%s) exiting\n",
+ strerror(errno)));
+ return;
+ }
- msg_type = CVAL(InBuffer,0);
- msg_flags = CVAL(InBuffer,1);
- type = CVAL(InBuffer,smb_com);
+ t = time(NULL);
- len = smb_len(InBuffer);
+ /* become root again if waiting */
+ unbecome_user();
- DEBUG(6,("got message type 0x%x of len 0x%x\n",msg_type,len));
+ /* check for smb.conf reload */
+ if (counter >= service_load_counter + SMBD_RELOAD_CHECK)
+ {
+ service_load_counter = counter;
- nread = len + 4;
-
- DEBUG(3,("%s Transaction %d of length %d\n",timestring(),trans_num,nread));
+ /* reload services, if files have changed. */
+ reload_services(True);
+ }
-#ifdef WITH_VTP
- if(trans_num == 1 && VT_Check(InBuffer)) {
- VT_Process();
+ /* automatic timeout if all connections are closed */
+ if (num_connections_open==0 && counter >= IDLE_CLOSED_TIMEOUT)
+ {
+ DEBUG(2,("%s Closing idle connection\n",timestring()));
return;
}
-#endif
+ if (keepalive && (counter-last_keepalive)>keepalive)
+ {
+ struct cli_state *cli = server_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 (cli && cli->initialised)
+ send_keepalive(cli->fd);
+ last_keepalive = counter;
+ }
- if (msg_type == 0)
- show_msg(InBuffer);
+ /* check for connection timeouts */
+ for (i=0;i<MAX_CONNECTIONS;i++)
+ if (Connections[i].open)
+ {
+ /* close dirptrs on connections that are idle */
+ if ((t-Connections[i].lastused)>DPTR_IDLE_TIMEOUT)
+ dptr_idlecnum(i);
- nread = construct_reply(InBuffer,OutBuffer,nread,maxxmit);
-
- if(nread > 0) {
- if (CVAL(OutBuffer,0) == 0)
- show_msg(OutBuffer);
-
- if (nread != smb_len(OutBuffer) + 4)
- {
- DEBUG(0,("ERROR: Invalid message response size! %d %d\n",
- nread,
- smb_len(OutBuffer)));
- }
- else
- send_smb(Client,OutBuffer);
+ if (Connections[i].num_files_open > 0 ||
+ (t-Connections[i].lastused)<deadtime)
+ allidle = False;
+ }
+
+ if (allidle && num_connections_open>0)
+ {
+ DEBUG(2,("%s Closing idle connection 2\n",timestring()));
+ return;
}
- trans_num++;
}
+
+ if(got_smb)
+ process_smb(InBuffer, OutBuffer);
+ else
+ process_local_message(oplock_sock, InBuffer, BUFFER_SIZE);
+ }
}
@@ -4064,7 +4892,7 @@ void process(void )
static void init_structs(void )
{
int i;
- get_myname(myhostname,&myip);
+ get_myname(myhostname,NULL);
for (i=0;i<MAX_CONNECTIONS;i++)
{
@@ -4082,6 +4910,19 @@ static void init_structs(void )
{
Files[i].open = False;
string_init(&Files[i].name,"");
+
+ }
+
+ for (i=0;i<MAX_OPEN_FILES;i++)
+ {
+ file_fd_struct *fd_ptr = &FileFd[i];
+ fd_ptr->ref_count = 0;
+ fd_ptr->dev = (int32)-1;
+ fd_ptr->inode = (int32)-1;
+ fd_ptr->fd = -1;
+ fd_ptr->fd_readonly = -1;
+ fd_ptr->fd_writeonly = -1;
+ fd_ptr->real_open_flags = -1;
}
init_dptrs();
@@ -4090,7 +4931,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,14 +4951,15 @@ 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;
+ char pidFile[100] = { 0 };
#ifdef NEED_AUTH_PARAMETERS
set_auth_parameters(argc,argv);
@@ -4149,25 +4991,15 @@ int main(int argc,char *argv[])
#endif
fault_setup(exit_server);
+ signal(SIGTERM , SIGNAL_CAST dflt_sig);
- 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
- }
+ /* we want total control over the permissions on created files,
+ so set our umask to 0 */
+ umask(0);
- initial_uid = geteuid();
- initial_gid = getegid();
+ GetWd(OriginalDir);
+ init_uid();
/* this is for people who can't start the program correctly */
while (argc > 1 && (*argv[1] != '-'))
@@ -4176,9 +5008,12 @@ int main(int argc,char *argv[])
argc--;
}
- while ((opt = getopt(argc, argv, "O:i:l:s:d:Dp:hPa")) != EOF)
+ while ((opt = getopt(argc, argv, "O:i:l:s:d:Dp:hPaf:")) != EOF)
switch (opt)
{
+ case 'f':
+ strncpy(pidFile, optarg, sizeof(pidFile));
+ break;
case 'O':
strcpy(user_socket_options,optarg);
break;
@@ -4227,9 +5062,7 @@ int main(int argc,char *argv[])
reopen_logs();
DEBUG(2,("%s smbd version %s started\n",timestring(),VERSION));
- DEBUG(2,("Copyright Andrew Tridgell 1992-1995\n"));
-
- GetWd(OriginalDir);
+ DEBUG(2,("Copyright Andrew Tridgell 1992-1997\n"));
#ifndef NO_GETRLIMIT
#ifdef RLIMIT_NOFILE
@@ -4259,6 +5092,10 @@ int main(int argc,char *argv[])
if (!reload_services(False))
return(-1);
+ codepage_initialise(lp_client_code_page());
+
+ strcpy(myworkgroup, lp_workgroup());
+
#ifndef NO_SIGNAL_TEST
signal(SIGHUP,SIGNAL_CAST sig_hup);
#endif
@@ -4277,22 +5114,58 @@ int main(int argc,char *argv[])
become_daemon();
}
- if (open_sockets(is_daemon,port))
- {
- /* possibly reload the services file. */
- reload_services(True);
+ if (*pidFile)
+ {
+ int fd;
+ char buf[20];
- maxxmit = MIN(lp_maxxmit(),BUFFER_SIZE);
+ if ((fd = open(pidFile,
+#ifdef O_NONBLOCK
+ O_NONBLOCK |
+#endif
+ O_CREAT | O_WRONLY | O_TRUNC, 0644)) < 0)
+ {
+ DEBUG(0,("ERROR: can't open %s: %s\n", pidFile, strerror(errno)));
+ exit(1);
+ }
+ if(fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)==False)
+ {
+ DEBUG(0,("ERROR: smbd is already running\n"));
+ exit(1);
+ }
+ sprintf(buf, "%u\n", (unsigned int) getpid());
+ if (write(fd, buf, strlen(buf)) < 0)
+ {
+ DEBUG(0,("ERROR: can't write to %s: %s\n", pidFile, strerror(errno)));
+ exit(1);
+ }
+ /* Leave pid file open & locked for the duration... */
+ }
- if (*lp_rootdir())
- {
- if (sys_chroot(lp_rootdir()) == 0)
- DEBUG(2,("%s changed root to %s\n",timestring(),lp_rootdir()));
- }
+ if (!open_sockets(is_daemon,port))
+ exit(1);
- process();
- close_sockets();
+ if (!locking_init(0))
+ exit(1);
+
+ /* possibly reload the services file. */
+ reload_services(True);
+
+ max_recv = MIN(lp_maxxmit(),BUFFER_SIZE);
+
+ if (*lp_rootdir())
+ {
+ if (sys_chroot(lp_rootdir()) == 0)
+ DEBUG(2,("%s changed root to %s\n",timestring(),lp_rootdir()));
}
+
+ /* Setup the oplock IPC socket. */
+ if(!open_oplock_ipc())
+ exit(1);
+
+ process();
+ close_sockets();
+
exit_server("normal exit");
return(0);
}
diff --git a/source/smbd/smbrun.c b/source/smbd/smbrun.c
index df12ae1f85c..42ce7f60ad0 100644
--- a/source/smbd/smbrun.c
+++ b/source/smbd/smbrun.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
external program running routine
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1997
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
@@ -41,56 +41,57 @@ static void close_fds(void)
/*
-This is a wrapper around the system call to allow commands to run correctly
+This is a wrapper around the system() call to allow commands to run correctly
as non root from a program which is switching between root and non-root
-It takes one argument as argv[1] and runs it after becoming a non-root
-user
-*/
-int main(int argc,char *argv[])
+It takes 3 arguments as uid,gid,command and runs command after
+becoming a non-root user */
+ int main(int argc,char *argv[])
{
+ int uid,gid;
+
close_fds();
- if (getuid() != geteuid())
- {
- int uid,gid;
-
- if (getuid() == 0)
- uid = geteuid();
- else
- uid = getuid();
-
- if (getgid() == 0)
- gid = getegid();
- else
- gid = getgid();
-
+ if (argc != 4) exit(2);
+
+ uid = atoi(argv[1]);
+ gid = atoi(argv[2]);
+
+ /* first become root - we may need to do this in order to lose
+ our privilages! */
#ifdef USE_SETRES
- setresgid(0,0,0);
- setresuid(0,0,0);
- setresgid(gid,gid,gid);
- setresuid(uid,uid,uid);
+ setresgid(0,0,0);
+ setresuid(0,0,0);
#else
- setuid(0);
- seteuid(0);
- setgid(gid);
- setegid(gid);
- setuid(uid);
- seteuid(uid);
+ setuid(0);
+ seteuid(0);
#endif
- if (getuid() != uid)
- return(3);
- }
+#ifdef USE_SETFS
+ setfsuid(uid);
+ setfsgid(gid);
+#endif
+
+#ifdef USE_SETRES
+ setresgid(gid,gid,gid);
+ setresuid(uid,uid,uid);
+#else
+ setgid(gid);
+ setegid(gid);
+ setuid(uid);
+ seteuid(uid);
+#endif
- if (geteuid() != getuid())
- return(1);
- if (argc < 2)
- return(2);
+ /* paranoia :-) */
+ if (getuid() != uid)
+ return(3);
+
+ if (geteuid() != getuid())
+ return(4);
/* this is to make sure that the system() call doesn't run forever */
alarm(30);
- return(system(argv[1]));
+ return(system(argv[3]));
}
diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c
index 9d02123cf87..6a7fc292fae 100644
--- a/source/smbd/trans2.c
+++ b/source/smbd/trans2.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
SMB transaction2 handling
- Copyright (C) Jeremy Allison 1994
+ Copyright (C) Jeremy Allison 1994-1997
Extensively modified by Andrew Tridgell, 1995
@@ -22,7 +22,6 @@
*/
#include "includes.h"
-#include "loadparm.h"
#include "trans2.h"
extern int DEBUGLEVEL;
@@ -41,13 +40,13 @@ extern int Client;
static int send_trans2_replies(char *outbuf, int bufsize, char *params,
int paramsize, char *pdata, int datasize)
{
- /* As we are using a protocol > LANMAN1 then the maxxmit
+ /* As we are using a protocol > LANMAN1 then the max_send
variable must have been set in the sessetupX call.
This takes precedence over the max_xmit field in the
global struct. These different max_xmit variables should
be merged as this is now too confusing */
- extern int maxxmit;
+ extern int max_send;
int data_to_send = datasize;
int params_to_send = paramsize;
int useable_space;
@@ -69,15 +68,18 @@ static int send_trans2_replies(char *outbuf, int bufsize, char *params,
}
/* Space is bufsize minus Netbios over TCP header minus SMB header */
- /* The + 1 is to align the param and data bytes on an even byte
+ /* The alignment_offset is to align the param and data bytes on an even byte
boundary. NT 4.0 Beta needs this to work correctly. */
useable_space = bufsize - ((smb_buf(outbuf)+alignment_offset) - outbuf);
- useable_space = MIN(useable_space, maxxmit); /* XXX is this needed? correct? */
+ /* useable_space can never be more than max_send minus the
+ alignment offset. */
+ useable_space = MIN(useable_space, max_send - alignment_offset);
while( params_to_send || data_to_send)
{
/* Calculate whether we will totally or partially fill this packet */
total_sent_thistime = params_to_send + data_to_send + alignment_offset;
+ /* We can never send more than useable_space */
total_sent_thistime = MIN(total_sent_thistime, useable_space);
set_message(outbuf, 10, total_sent_thistime, True);
@@ -164,6 +166,7 @@ static int call_trans2open(char *inbuf, char *outbuf, int bufsize, int cnum,
char *params = *pparams;
int16 open_mode = SVAL(params, 2);
int16 open_attr = SVAL(params,6);
+ BOOL oplock_request = (((SVAL(params,0)|(1<<1))>>1) | ((SVAL(params,0)|(1<<2))>>1));
#if 0
BOOL return_additional_info = BITSETW(params,0);
int16 open_sattr = SVAL(params, 4);
@@ -181,6 +184,7 @@ static int call_trans2open(char *inbuf, char *outbuf, int bufsize, int cnum,
int32 inode = 0;
struct stat sbuf;
int smb_action = 0;
+ BOOL bad_path = False;
StrnCpy(fname,pname,namelen);
@@ -189,26 +193,40 @@ static int call_trans2open(char *inbuf, char *outbuf, int bufsize, int cnum,
/* XXXX we need to handle passed times, sattr and flags */
- unix_convert(fname,cnum);
+ unix_convert(fname,cnum,0,&bad_path);
fnum = find_free_file();
if (fnum < 0)
return(ERROR(ERRSRV,ERRnofids));
if (!check_name(fname,cnum))
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
unixmode = unix_mode(cnum,open_attr | aARCH);
open_file_shared(fnum,cnum,fname,open_mode,open_ofun,unixmode,
- &rmode,&smb_action);
+ oplock_request, &rmode,&smb_action);
if (!Files[fnum].open)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
- if (fstat(Files[fnum].fd,&sbuf) != 0) {
- close_file(fnum);
+ if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) {
+ close_file(fnum,False);
return(ERROR(ERRDOS,ERRnoaccess));
}
@@ -217,7 +235,7 @@ static int call_trans2open(char *inbuf, char *outbuf, int bufsize, int cnum,
mtime = sbuf.st_mtime;
inode = sbuf.st_ino;
if (fmode & aDIR) {
- close_file(fnum);
+ close_file(fnum,False);
return(ERROR(ERRDOS,ERRnoaccess));
}
@@ -233,6 +251,10 @@ static int call_trans2open(char *inbuf, char *outbuf, int bufsize, int cnum,
SIVAL(params,8, size);
SSVAL(params,12,rmode);
+ if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
+ smb_action |= EXTENDED_OPLOCK_GRANTED;
+ }
+
SSVAL(params,18,smb_action);
SIVAL(params,20,inode);
@@ -264,11 +286,13 @@ 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,"/"));
BOOL was_8_3;
+ int nt_extmode; /* Used for NT connections instead of mode */
+ BOOL needslash = ( Connections[cnum].dirpath[strlen(Connections[cnum].dirpath) -1] != '/');
*fname = 0;
*out_of_space = False;
@@ -282,10 +306,10 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
if(p[1] == '\0')
strcpy(mask,"*.*");
else
- strcpy(mask, p+1);
+ pstrcpy(mask, p+1);
}
else
- strcpy(mask, path_mask);
+ pstrcpy(mask, path_mask);
while (!found)
{
@@ -295,7 +319,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
reskey = TellDir(Connections[cnum].dirptr);
- DEBUG(6,("get_lanman2_dir_entry:readdir on dirptr 0x%x now at offset %d\n",
+ DEBUG(8,("get_lanman2_dir_entry:readdir on dirptr 0x%x now at offset %d\n",
Connections[cnum].dirptr,TellDir(Connections[cnum].dirptr)));
if (!dname)
@@ -303,7 +327,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
matched = False;
- strcpy(fname,dname);
+ pstrcpy(fname,dname);
if(mask_match(fname, mask, case_sensitive, True))
{
@@ -314,9 +338,10 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
if (isrootdir && isdots)
continue;
- strcpy(pathreal,Connections[cnum].dirpath);
- strcat(pathreal,"/");
- strcat(pathreal,fname);
+ pstrcpy(pathreal,Connections[cnum].dirpath);
+ if(needslash)
+ strcat(pathreal,"/");
+ strcat(pathreal,dname);
if (sys_stat(pathreal,&sbuf) != 0)
{
DEBUG(5,("get_lanman2_dir_entry:Couldn't stat [%s] (%s)\n",pathreal,strerror(errno)));
@@ -325,11 +350,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;
@@ -343,15 +368,12 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
}
}
-
-#ifndef KANJI
- unix2dos_format(fname, True);
-#endif
+ name_map_mangle(fname,False,SNUM(cnum));
p = pdata;
- name_ptr = p;
+ nameptr = p;
- name_map_mangle(fname,False,SNUM(cnum));
+ nt_extmode = mode ? mode : NT_FILE_ATTRIBUTE_NORMAL;
switch (info_level)
{
@@ -368,7 +390,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 +409,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 +424,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,12 +442,12 @@ 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;
case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
- was_8_3 = is_8_3(fname);
+ was_8_3 = is_8_3(fname, True);
len = 94+strlen(fname);
len = (len + 3) & ~3;
SIVAL(p,0,len); p += 4;
@@ -436,15 +458,11 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
put_long_date(p,mdate); p += 8;
SIVAL(p,0,size); p += 8;
SIVAL(p,0,size); p += 8;
- SIVAL(p,0,mode); p += 4;
+ SIVAL(p,0,nt_extmode); p += 4;
SIVAL(p,0,strlen(fname)); p += 4;
SIVAL(p,0,0); p += 4;
if (!was_8_3) {
-#ifndef KANJI
- strcpy(p+2,unix2dos_format(fname,False));
-#else
strcpy(p+2,fname);
-#endif
if (!name_map_mangle(p+2,True,SNUM(cnum)))
(p+2)[12] = 0;
} else
@@ -452,7 +470,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;
@@ -468,7 +486,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
put_long_date(p,mdate); p += 8;
SIVAL(p,0,size); p += 8;
SIVAL(p,0,size); p += 8;
- SIVAL(p,0,mode); p += 4;
+ SIVAL(p,0,nt_extmode); p += 4;
SIVAL(p,0,strlen(fname)); p += 4;
strcpy(p,fname);
p = pdata + len;
@@ -486,7 +504,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
put_long_date(p,mdate); p += 8;
SIVAL(p,0,size); p += 8;
SIVAL(p,0,size); p += 8;
- SIVAL(p,0,mode); p += 4;
+ SIVAL(p,0,nt_extmode); p += 4;
SIVAL(p,0,strlen(fname)); p += 4;
SIVAL(p,0,0); p += 4;
strcpy(p,fname);
@@ -517,7 +535,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);
@@ -554,6 +572,7 @@ static int call_trans2findfirst(char *inbuf, char *outbuf, int bufsize, int cnum
BOOL dont_descend = False;
BOOL out_of_space = False;
int space_remaining;
+ BOOL bad_path = False;
*directory = *mask = 0;
@@ -576,13 +595,29 @@ static int call_trans2findfirst(char *inbuf, char *outbuf, int bufsize, int cnum
return(ERROR(ERRDOS,ERRunknownlevel));
}
- strcpy(directory, params + 12); /* Complete directory path with
+ pstrcpy(directory, params + 12); /* Complete directory path with
wildcard mask appended */
DEBUG(5,("path=%s\n",directory));
- unix_convert(directory,cnum);
+ unix_convert(directory,cnum,0,&bad_path);
if(!check_name(directory,cnum)) {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+
+#if 0
+ /* Ugly - NT specific hack - maybe not needed ? (JRA) */
+ if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) &&
+ (get_remote_arch() == RA_WINNT))
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbaddirectory;
+ }
+#endif
+
return(ERROR(ERRDOS,ERRbadpath));
}
@@ -609,7 +644,29 @@ static int call_trans2findfirst(char *inbuf, char *outbuf, int bufsize, int cnum
dptr_num = dptr_create(cnum,directory, True ,SVAL(inbuf,smb_pid));
if (dptr_num < 0)
- return(ERROR(ERRDOS,ERRbadpath));
+ {
+ if(dptr_num == -2)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+
+#if 0
+ /* Ugly - NT specific hack - maybe not needed ? (JRA) */
+ if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) &&
+ (get_remote_arch() == RA_WINNT))
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbaddirectory;
+ }
+#endif
+
+ return (UNIXERROR(ERRDOS,ERRbadpath));
+ }
+ return(ERROR(ERRDOS,ERRbadpath));
+ }
/* convert the formatted masks */
{
@@ -913,7 +970,7 @@ static int call_trans2qfsinfo(char *inbuf, char *outbuf, int length, int bufsize
put_dos_date2(pdata,l2_vol_fdateCreation,st.st_ctime);
SCVAL(pdata,l2_vol_cch,volname_len);
StrnCpy(pdata+l2_vol_szVolLabel,vname,volname_len);
- DEBUG(5,("call_trans2qfsinfo : time = %x, namelen = %d, name = %s\n",st.st_ctime,volname_len,
+ DEBUG(5,("call_trans2qfsinfo : time = %x, namelen = %d, name = %s\n",st.st_ctime, volname_len,
pdata+l2_vol_szVolLabel));
break;
}
@@ -930,9 +987,11 @@ static int call_trans2qfsinfo(char *inbuf, char *outbuf, int length, int bufsize
strcpy(pdata+4,vname);
break;
case SMB_QUERY_FS_VOLUME_INFO:
- data_len = 17 + strlen(vname);
- SIVAL(pdata,12,strlen(vname));
- strcpy(pdata+17,vname);
+ data_len = 18 + 2*strlen(vname);
+ SIVAL(pdata,12,2*strlen(vname));
+ PutUniCode(pdata+18,vname);
+ DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol = %s\n", strlen(vname),
+ vname));
break;
case SMB_QUERY_FS_SIZE_INFO:
{
@@ -1001,29 +1060,34 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
char *fname;
char *p;
int l,pos;
-
+ BOOL bad_path = False;
if (tran_call == TRANSACT2_QFILEINFO) {
- int16 fnum = SVAL(params,0);
+ int16 fnum = SVALS(params,0);
info_level = SVAL(params,2);
CHECK_FNUM(fnum,cnum);
CHECK_ERROR(fnum);
fname = Files[fnum].name;
- if (fstat(Files[fnum].fd,&sbuf) != 0) {
+ if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) {
DEBUG(3,("fstat of fnum %d failed (%s)\n",fnum, strerror(errno)));
return(UNIXERROR(ERRDOS,ERRbadfid));
}
- pos = lseek(Files[fnum].fd,0,SEEK_CUR);
+ pos = lseek(Files[fnum].fd_ptr->fd,0,SEEK_CUR);
} else {
/* qpathinfo */
info_level = SVAL(params,0);
fname = &fname1[0];
- strcpy(fname,&params[6]);
- unix_convert(fname,cnum);
+ pstrcpy(fname,&params[6]);
+ unix_convert(fname,cnum,0,&bad_path);
if (!check_name(fname,cnum) || sys_stat(fname,&sbuf)) {
DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno)));
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRbadpath));
}
pos = 0;
@@ -1050,34 +1114,28 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
if (total_data > 0 && IVAL(pdata,0) == total_data) {
/* uggh, EAs for OS2 */
DEBUG(4,("Rejecting EA request with total_data=%d\n",total_data));
-#if 0
- SSVAL(params,0,ERROR_EAS_NOT_SUPPORTED);
- send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
- return(-1);
-#else
return(ERROR(ERRDOS,ERROR_EAS_NOT_SUPPORTED));
-#endif
}
bzero(pdata,data_size);
switch (info_level)
{
- case 1:
- case 2:
+ case SMB_INFO_STANDARD:
+ case SMB_INFO_QUERY_EA_SIZE:
data_size = (info_level==1?22:26);
- put_dos_date2(pdata,l1_fdateCreation,sbuf.st_ctime);
- put_dos_date2(pdata,l1_fdateLastAccess,sbuf.st_atime);
- put_dos_date2(pdata,l1_fdateLastWrite,sbuf.st_mtime);
+ put_dos_date2(pdata,l1_fdateCreation,sbuf.st_ctime); /* create = inode mod */
+ put_dos_date2(pdata,l1_fdateLastAccess,sbuf.st_atime); /* access time */
+ put_dos_date2(pdata,l1_fdateLastWrite,sbuf.st_mtime); /* write time */
SIVAL(pdata,l1_cbFile,size);
SIVAL(pdata,l1_cbFileAlloc,ROUNDUP(size,1024));
SSVAL(pdata,l1_attrFile,mode);
SIVAL(pdata,l1_attrFile+2,4); /* this is what OS2 does */
break;
- case 3:
+ case SMB_INFO_QUERY_EAS_FROM_LIST:
data_size = 24;
- put_dos_date2(pdata,0,sbuf.st_ctime);
+ put_dos_date2(pdata,0,sbuf.st_ctime); /* create time = inode mod time */
put_dos_date2(pdata,4,sbuf.st_atime);
put_dos_date2(pdata,8,sbuf.st_mtime);
SIVAL(pdata,12,size);
@@ -1085,7 +1143,7 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
SIVAL(pdata,20,mode);
break;
- case 4:
+ case SMB_INFO_QUERY_ALL_EAS:
data_size = 4;
SIVAL(pdata,0,data_size);
break;
@@ -1094,12 +1152,20 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
return(ERROR(ERRDOS,ERRbadfunc)); /* os/2 needs this */
case SMB_QUERY_FILE_BASIC_INFO:
- data_size = 36;
- put_long_date(pdata,sbuf.st_ctime);
- put_long_date(pdata+8,sbuf.st_atime);
- put_long_date(pdata+16,sbuf.st_mtime);
- put_long_date(pdata+24,sbuf.st_mtime);
+ data_size = 36; /* w95 returns 40 bytes not 36 - why ?. */
+ put_long_date(pdata,sbuf.st_ctime); /* create time = inode mod time */
+ put_long_date(pdata+8,sbuf.st_atime); /* access time */
+ put_long_date(pdata+16,sbuf.st_mtime); /* write time */
+ put_long_date(pdata+24,sbuf.st_mtime); /* change time */
SIVAL(pdata,32,mode);
+
+ DEBUG(5,("SMB_QFBI - "));
+ DEBUG(5,("create: %s ", ctime(&sbuf.st_ctime)));
+ DEBUG(5,("access: %s ", ctime(&sbuf.st_atime)));
+ DEBUG(5,("write: %s ", ctime(&sbuf.st_mtime)));
+ DEBUG(5,("change: %s ", ctime(&sbuf.st_mtime)));
+ DEBUG(5,("mode: %x\n", mode));
+
break;
case SMB_QUERY_FILE_STANDARD_INFO:
@@ -1115,12 +1181,32 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
data_size = 4;
break;
- case SMB_QUERY_FILE_NAME_INFO:
+ /* Get the 8.3 name - used if NT SMB was negotiated. */
case SMB_QUERY_FILE_ALT_NAME_INFO:
+ {
+ pstring short_name;
+ pstrcpy(short_name,fname);
+ /* Mangle if not already 8.3 */
+ if(!is_8_3(short_name, True))
+ {
+ if(!name_map_mangle(short_name,True,SNUM(cnum)))
+ *short_name = '\0';
+ }
+ strncpy(pdata + 4,short_name,12);
+ (pdata + 4)[12] = 0;
+ strupper(pdata + 4);
+ l = strlen(pdata + 4);
+ data_size = 4 + l;
+ SIVAL(pdata,0,l);
+ }
+ break;
+
+ case SMB_QUERY_FILE_NAME_INFO:
data_size = 4 + l;
SIVAL(pdata,0,l);
- strcpy(pdata+4,fname);
+ pstrcpy(pdata+4,fname);
break;
+
case SMB_QUERY_FILE_ALLOCATION_INFO:
case SMB_QUERY_FILE_END_OF_FILEINFO:
data_size = 8;
@@ -1128,10 +1214,10 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
break;
case SMB_QUERY_FILE_ALL_INFO:
- put_long_date(pdata,sbuf.st_ctime);
- put_long_date(pdata+8,sbuf.st_atime);
- put_long_date(pdata+16,sbuf.st_mtime);
- put_long_date(pdata+24,sbuf.st_mtime);
+ put_long_date(pdata,sbuf.st_ctime); /* create time = inode mod time */
+ put_long_date(pdata+8,sbuf.st_atime); /* access time */
+ put_long_date(pdata+16,sbuf.st_mtime); /* write time */
+ put_long_date(pdata+24,sbuf.st_mtime); /* change time */
SIVAL(pdata,32,mode);
pdata += 40;
SIVAL(pdata,0,size);
@@ -1153,7 +1239,7 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
pdata += 4;
pdata += 4; /* alignment */
SIVAL(pdata,0,l);
- strcpy(pdata+4,fname);
+ pstrcpy(pdata+4,fname);
pdata += 4 + l;
data_size = PTR_DIFF(pdata,(*ppdata));
break;
@@ -1164,7 +1250,7 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
SIVAL(pdata,4,size);
SIVAL(pdata,12,size);
SIVAL(pdata,20,l);
- strcpy(pdata+24,fname);
+ pstrcpy(pdata+24,fname);
break;
default:
return(ERROR(ERRDOS,ERRunknownlevel));
@@ -1193,19 +1279,20 @@ static int call_trans2setfilepathinfo(char *inbuf, char *outbuf, int length,
pstring fname1;
char *fname;
int fd = -1;
+ BOOL bad_path = False;
if (!CAN_WRITE(cnum))
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);
CHECK_ERROR(fnum);
fname = Files[fnum].name;
- fd = Files[fnum].fd;
+ fd = Files[fnum].fd_ptr->fd;
if(fstat(fd,&st)!=0) {
DEBUG(3,("fstat of %s failed (%s)\n", fname, strerror(errno)));
@@ -1215,14 +1302,26 @@ static int call_trans2setfilepathinfo(char *inbuf, char *outbuf, int length,
/* set path info */
info_level = SVAL(params,0);
fname = fname1;
- strcpy(fname,&params[6]);
- unix_convert(fname,cnum);
+ pstrcpy(fname,&params[6]);
+ unix_convert(fname,cnum,0,&bad_path);
if(!check_name(fname, cnum))
- return(ERROR(ERRDOS,ERRbadpath));
-
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ return(UNIXERROR(ERRDOS,ERRbadpath));
+ }
+
if(sys_stat(fname,&st)!=0) {
DEBUG(3,("stat of %s failed (%s)\n", fname, strerror(errno)));
- return(ERROR(ERRDOS,ERRbadpath));
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ return(UNIXERROR(ERRDOS,ERRbadpath));
}
}
@@ -1242,37 +1341,37 @@ static int call_trans2setfilepathinfo(char *inbuf, char *outbuf, int length,
if (total_data > 0 && IVAL(pdata,0) == total_data) {
/* uggh, EAs for OS2 */
DEBUG(4,("Rejecting EA request with total_data=%d\n",total_data));
- SSVAL(params,0,ERROR_EAS_NOT_SUPPORTED);
-
- send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
-
- return(-1);
+ return(ERROR(ERRDOS,ERROR_EAS_NOT_SUPPORTED));
}
switch (info_level)
+ {
+ case SMB_INFO_STANDARD:
+ case SMB_INFO_QUERY_EA_SIZE:
{
- case 1:
+ /* access time */
tvs.actime = make_unix_date2(pdata+l1_fdateLastAccess);
- tvs.modtime = make_unix_date2(pdata+l1_fdateLastWrite);
- mode = SVAL(pdata,l1_attrFile);
- size = IVAL(pdata,l1_cbFile);
- break;
- case 2:
- tvs.actime = make_unix_date2(pdata+l1_fdateLastAccess);
+ /* write time */
tvs.modtime = make_unix_date2(pdata+l1_fdateLastWrite);
+
mode = SVAL(pdata,l1_attrFile);
size = IVAL(pdata,l1_cbFile);
break;
+ }
- case 3:
+ /* XXXX um, i don't think this is right.
+ it's also not in the cifs6.txt spec.
+ */
+ case SMB_INFO_QUERY_EAS_FROM_LIST:
tvs.actime = make_unix_date2(pdata+8);
tvs.modtime = make_unix_date2(pdata+12);
size = IVAL(pdata,16);
mode = IVAL(pdata,24);
break;
- case 4:
+ /* XXXX nor this. not in cifs6.txt, either. */
+ case SMB_INFO_QUERY_ALL_EAS:
tvs.actime = make_unix_date2(pdata+8);
tvs.modtime = make_unix_date2(pdata+12);
size = IVAL(pdata,16);
@@ -1280,48 +1379,87 @@ static int call_trans2setfilepathinfo(char *inbuf, char *outbuf, int length,
break;
case SMB_SET_FILE_BASIC_INFO:
- pdata += 8; /* create time */
- tvs.actime = interpret_long_date(pdata); pdata += 8;
- tvs.modtime=MAX(interpret_long_date(pdata),interpret_long_date(pdata+8));
- pdata += 16;
- mode = IVAL(pdata,0);
+ {
+ /* Ignore create time at offset pdata. */
+
+ /* access time */
+ tvs.actime = interpret_long_date(pdata+8);
+
+ /* write time + changed time, combined. */
+ tvs.modtime=MAX(interpret_long_date(pdata+16),
+ interpret_long_date(pdata+24));
+
+#if 0 /* Needs more testing... */
+ /* Test from Luke to prevent Win95 from
+ setting incorrect values here.
+ */
+ if (tvs.actime < tvs.modtime)
+ return(ERROR(ERRDOS,ERRnoaccess));
+#endif /* Needs more testing... */
+
+ /* attributes */
+ mode = IVAL(pdata,32);
break;
+ }
case SMB_SET_FILE_END_OF_FILE_INFO:
+ {
if (IVAL(pdata,4) != 0) /* more than 32 bits? */
- return(ERROR(ERRDOS,ERRunknownlevel));
+ return(ERROR(ERRDOS,ERRunknownlevel));
size = IVAL(pdata,0);
break;
+ }
case SMB_SET_FILE_DISPOSITION_INFO: /* not supported yet */
case SMB_SET_FILE_ALLOCATION_INFO: /* not supported yet */
default:
+ {
return(ERROR(ERRDOS,ERRunknownlevel));
}
+ }
+ DEBUG(6,("actime: %s " , ctime(&tvs.actime)));
+ DEBUG(6,("modtime: %s ", ctime(&tvs.modtime)));
+ DEBUG(6,("size: %x " , size));
+ DEBUG(6,("mode: %x\n" , mode));
+ /* get some defaults (no modifications) if any info is zero. */
if (!tvs.actime) tvs.actime = st.st_atime;
if (!tvs.modtime) tvs.modtime = st.st_mtime;
if (!size) size = st.st_size;
- /* Try and set the times, size and mode of this file - if they are different
- from the current values */
- if(st.st_mtime != tvs.modtime || st.st_atime != tvs.actime) {
- if(sys_utime(fname, &tvs)!=0)
+ /* Try and set the times, size and mode of this file -
+ if they are different from the current values
+ */
+ if (st.st_mtime != tvs.modtime || st.st_atime != tvs.actime)
+ {
+ if(file_utime(cnum, fname, &tvs)!=0)
+ {
return(ERROR(ERRDOS,ERRnoaccess));
+ }
}
- if(mode != dos_mode(cnum,fname,&st) && dos_chmod(cnum,fname,mode,NULL)) {
+
+ /* check the mode isn't different, before changing it */
+ if (mode != dos_mode(cnum, fname, &st) && dos_chmod(cnum, fname, mode, NULL))
+ {
DEBUG(2,("chmod of %s failed (%s)\n", fname, strerror(errno)));
return(ERROR(ERRDOS,ERRnoaccess));
}
- if(size != st.st_size) {
- if (fd == -1) {
+
+ if(size != st.st_size)
+ {
+ if (fd == -1)
+ {
fd = sys_open(fname,O_RDWR,0);
if (fd == -1)
- return(ERROR(ERRDOS,ERRbadpath));
+ {
+ return(ERROR(ERRDOS,ERRbadpath));
+ }
set_filelen(fd, size);
close(fd);
- } else {
+ }
+ else
+ {
set_filelen(fd, size);
}
}
@@ -1342,21 +1480,27 @@ static int call_trans2mkdir(char *inbuf, char *outbuf, int length, int bufsize,
char *params = *pparams;
pstring directory;
int ret = -1;
+ BOOL bad_path = False;
if (!CAN_WRITE(cnum))
return(ERROR(ERRSRV,ERRaccess));
- strcpy(directory, &params[4]);
+ pstrcpy(directory, &params[4]);
DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
- unix_convert(directory,cnum);
+ unix_convert(directory,cnum,0,&bad_path);
if (check_name(directory,cnum))
ret = sys_mkdir(directory,unix_mode(cnum,aDIR));
if(ret < 0)
{
DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno)));
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
@@ -1444,7 +1588,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);
@@ -1543,6 +1687,9 @@ int reply_trans2(char *inbuf,char *outbuf,int length,int bufsize)
num_params = num_params_sofar = SVAL(inbuf,smb_pscnt);
num_data = num_data_sofar = SVAL(inbuf, smb_dscnt);
+ if (num_params > total_params || num_data > total_data)
+ exit_server("invalid params in reply_trans2");
+
memcpy( params, smb_base(inbuf) + SVAL(inbuf, smb_psoff), num_params);
memcpy( data, smb_base(inbuf) + SVAL(inbuf, smb_dsoff), num_data);
@@ -1555,10 +1702,8 @@ int reply_trans2(char *inbuf,char *outbuf,int length,int bufsize)
while( num_data_sofar < total_data || num_params_sofar < total_params)
{
- receive_smb(Client,inbuf, 0);
-
- /* Ensure this is still a trans2 packet (sanity check) */
- if(CVAL(inbuf, smb_com) != SMBtranss2)
+ if(!receive_smb(Client,inbuf, SMB_SECONDARY_WAIT) ||
+ CVAL(inbuf, smb_com) != SMBtranss2)
{
outsize = set_message(outbuf,0,0,True);
DEBUG(2,("Invalid secondary trans2 packet\n"));
@@ -1572,6 +1717,9 @@ int reply_trans2(char *inbuf,char *outbuf,int length,int bufsize)
total_data = SVAL(inbuf, smb_tdscnt);
num_params_sofar += (num_params = SVAL(inbuf,smb_spscnt));
num_data_sofar += ( num_data = SVAL(inbuf, smb_sdscnt));
+ if (num_params_sofar > total_params || num_data_sofar > total_data)
+ exit_server("data overflow in trans2");
+
memcpy( &params[ SVAL(inbuf, smb_spsdisp)],
smb_base(inbuf) + SVAL(inbuf, smb_spsoff), num_params);
memcpy( &data[SVAL(inbuf, smb_sdsdisp)],
diff --git a/source/smbd/uid.c b/source/smbd/uid.c
new file mode 100644
index 00000000000..645d078979c
--- /dev/null
+++ b/source/smbd/uid.c
@@ -0,0 +1,555 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ uid/user handling
+ Copyright (C) Andrew Tridgell 1992-1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+static int initial_uid;
+static int initial_gid;
+
+/* what user is current? */
+struct current_user current_user;
+
+pstring OriginalDir;
+
+/****************************************************************************
+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;
+
+ ChDir(OriginalDir);
+}
+
+
+/****************************************************************************
+ become the specified uid
+****************************************************************************/
+static BOOL become_uid(int uid)
+{
+ if (initial_uid != 0)
+ return(True);
+
+ if (uid == -1 || uid == 65535) {
+ DEBUG(1,("WARNING: using uid %d is a security risk\n",uid));
+ }
+
+#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)\n"));
+ }
+#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);
+
+ if (gid == -1 || gid == 65535) {
+ DEBUG(1,("WARNING: using gid %d is a security risk\n",gid));
+ }
+
+#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(connection_struct *conn, user_struct *vuser,int snum)
+{
+ int i;
+ for (i=0;i<conn->uid_cache.entries;i++)
+ if (conn->uid_cache.list[i] == vuser->uid) return(True);
+
+ if (!user_ok(vuser->name,snum)) return(False);
+
+ i = conn->uid_cache.entries % UID_CACHE_SIZE;
+ conn->uid_cache.list[i] = vuser->uid;
+
+ if (conn->uid_cache.entries < UID_CACHE_SIZE)
+ conn->uid_cache.entries++;
+
+ return(True);
+}
+
+
+/****************************************************************************
+ become the user of a connection number
+****************************************************************************/
+BOOL become_user(connection_struct *conn, int cnum, uint16 vuid)
+{
+ user_struct *vuser = get_valid_user_struct(vuid);
+ int snum,gid;
+ int uid;
+
+ if (current_user.cnum == cnum && vuser != 0 && current_user.id == vuser->uid) {
+ DEBUG(4,("Skipping become_user - already user\n"));
+ return(True);
+ }
+
+ unbecome_user();
+
+ if (!(VALID_CNUM(cnum) && conn->open)) {
+ DEBUG(2,("Connection %d not open\n",cnum));
+ return(False);
+ }
+
+ snum = conn->service;
+
+ if (conn->force_user ||
+ lp_security() == SEC_SHARE ||
+ !(vuser) || (vuser->guest) ||
+ !check_user_ok(conn, vuser, snum))
+ {
+ uid = conn->uid;
+ gid = conn->gid;
+ current_user.groups = conn->groups;
+ current_user.igroups = conn->igroups;
+ current_user.ngroups = conn->ngroups;
+ current_user.attrs = vuser->attrs;
+ }
+ else
+ {
+ if (!vuser) {
+ DEBUG(2,("Invalid vuid used %d\n",vuid));
+ return(False);
+ }
+ uid = vuser->uid;
+ if(!*lp_force_group(snum))
+ gid = vuser->gid;
+ else
+ gid = conn->gid;
+ current_user.ngroups = vuser->n_groups;
+ current_user.groups = vuser->groups;
+ current_user.igroups = vuser->igroups;
+ current_user.attrs = vuser->attrs;
+ }
+
+ if (initial_uid == 0)
+ {
+ if (!become_gid(gid)) return(False);
+
+#ifndef NO_SETGROUPS
+ if (!(VALID_CNUM(cnum) && conn->ipc)) {
+ /* 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 (!conn->admin_user && !become_uid(uid))
+ return(False);
+ }
+
+ current_user.cnum = cnum;
+ current_user.id = uid;
+
+ DEBUG(5,("become_user uid=(%d,%d) gid=(%d,%d)\n",
+ getuid(),geteuid(),getgid(),getegid()));
+
+ return(True);
+}
+
+/****************************************************************************
+ unbecome the user of a connection number
+****************************************************************************/
+BOOL unbecome_user(void )
+{
+ if (current_user.cnum == -1)
+ return(False);
+
+ ChDir(OriginalDir);
+
+ 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);
+}
+
+
+/****************************************************************************
+This is a utility function of smbrun(). It must be called only from
+the child as it may leave the caller in a privilaged state.
+****************************************************************************/
+static BOOL setup_stdout_file(char *outfile,BOOL shared)
+{
+ int fd;
+ struct stat st;
+ mode_t mode = S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH;
+ int flags = O_RDWR|O_CREAT|O_TRUNC|O_EXCL;
+
+ close(1);
+
+ if (shared) {
+ /* become root - unprivilaged users can't delete these files */
+#ifdef USE_SETRES
+ setresgid(0,0,0);
+ setresuid(0,0,0);
+#else
+ setuid(0);
+ seteuid(0);
+#endif
+ }
+
+ if(stat(outfile, &st) == 0) {
+ /* Check we're not deleting a device file. */
+ if(st.st_mode & S_IFREG)
+ unlink(outfile);
+ else
+ flags = O_RDWR;
+ }
+ /* now create the file */
+ fd = open(outfile,flags,mode);
+
+ if (fd == -1) return False;
+
+ if (fd != 1) {
+ if (dup2(fd,1) != 0) {
+ DEBUG(2,("Failed to create stdout file descriptor\n"));
+ close(fd);
+ return False;
+ }
+ close(fd);
+ }
+ return True;
+}
+
+
+/****************************************************************************
+run a command being careful about uid/gid handling and putting the output in
+outfile (or discard it if outfile is NULL).
+
+if shared is True then ensure the file will be writeable by all users
+but created such that its owned by root. This overcomes a security hole.
+
+if shared is not set then open the file with O_EXCL set
+****************************************************************************/
+int smbrun(char *cmd,char *outfile,BOOL shared)
+{
+ int fd,pid;
+ int uid = current_user.uid;
+ int gid = current_user.gid;
+
+#if USE_SYSTEM
+ int ret;
+ pstring syscmd;
+ char *path = lp_smbrun();
+
+ /* in the old method we use system() to execute smbrun which then
+ executes the command (using system() again!). This involves lots
+ of shell launches and is very slow. It also suffers from a
+ potential security hole */
+ 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,uid,gid,cmd,
+ outfile?outfile:"/dev/null");
+
+ DEBUG(5,("smbrun - running %s ",syscmd));
+ ret = system(syscmd);
+ DEBUG(5,("gave %d\n",ret));
+ return(ret);
+#else
+ /* in this newer method we will exec /bin/sh with the correct
+ arguments, after first setting stdout to point at the file */
+
+ if ((pid=fork())) {
+ int status=0;
+ /* the parent just waits for the child to exit */
+ if (sys_waitpid(pid,&status,0) != pid) {
+ DEBUG(2,("waitpid(%d) : %s\n",pid,strerror(errno)));
+ return -1;
+ }
+ return status;
+ }
+
+
+ /* we are in the child. we exec /bin/sh to do the work for us. we
+ don't directly exec the command we want because it may be a
+ pipeline or anything else the config file specifies */
+
+ /* point our stdout at the file we want output to go into */
+ if (outfile && !setup_stdout_file(outfile,shared)) {
+ exit(80);
+ }
+
+ /* now completely lose our privilages. This is a fairly paranoid
+ way of doing it, but it does work on all systems that I know of */
+#ifdef USE_SETRES
+ setresgid(0,0,0);
+ setresuid(0,0,0);
+ setresgid(gid,gid,gid);
+ setresuid(uid,uid,uid);
+#else
+ setuid(0);
+ seteuid(0);
+ setgid(gid);
+ setegid(gid);
+ setuid(uid);
+ seteuid(uid);
+#endif
+
+ if (getuid() != uid || geteuid() != uid ||
+ getgid() != gid || getegid() != gid) {
+ /* we failed to lose our privilages - do not execute the command */
+ exit(81); /* we can't print stuff at this stage, instead use exit codes
+ for debugging */
+ }
+
+ /* close all other file descriptors, leaving only 0, 1 and 2. 0 and
+ 2 point to /dev/null from the startup code */
+ for (fd=3;fd<256;fd++) close(fd);
+
+ execl("/bin/sh","sh","-c",cmd,NULL);
+
+ /* not reached */
+ exit(82);
+#endif
+ return 1;
+}
+
+static struct current_user current_user_saved;
+static int become_root_depth;
+static pstring become_root_dir;
+
+/****************************************************************************
+This is used when we need to do a privilaged operation (such as mucking
+with share mode files) and temporarily need root access to do it. This
+call should always be paired with an unbecome_root() call immediately
+after the operation
+
+Set save_dir if you also need to save/restore the CWD
+****************************************************************************/
+void become_root(BOOL save_dir)
+{
+ if (become_root_depth) {
+ DEBUG(0,("ERROR: become root depth is non zero\n"));
+ }
+ if (save_dir)
+ GetWd(become_root_dir);
+
+ current_user_saved = current_user;
+ become_root_depth = 1;
+
+ become_uid(0);
+ become_gid(0);
+}
+
+/****************************************************************************
+When the privilaged operation is over call this
+
+Set save_dir if you also need to save/restore the CWD
+****************************************************************************/
+void unbecome_root(BOOL restore_dir)
+{
+ if (become_root_depth != 1) {
+ DEBUG(0,("ERROR: unbecome root depth is %d\n",
+ become_root_depth));
+ }
+
+ /* we might have done a become_user() while running as root,
+ if we have then become root again in order to become
+ non root! */
+ if (current_user.uid != 0) {
+ become_uid(0);
+ }
+
+ /* restore our gid first */
+ if (!become_gid(current_user_saved.gid)) {
+ DEBUG(0,("ERROR: Failed to restore gid\n"));
+ exit_server("Failed to restore gid");
+ }
+
+#ifndef NO_SETGROUPS
+ if (current_user_saved.ngroups > 0) {
+ if (setgroups(current_user_saved.ngroups,
+ current_user_saved.groups)<0)
+ DEBUG(0,("ERROR: setgroups call failed!\n"));
+ }
+#endif
+
+ /* now restore our uid */
+ if (!become_uid(current_user_saved.uid)) {
+ DEBUG(0,("ERROR: Failed to restore uid\n"));
+ exit_server("Failed to restore uid");
+ }
+
+ if (restore_dir)
+ ChDir(become_root_dir);
+
+ current_user = current_user_saved;
+
+ become_root_depth = 0;
+}
diff --git a/source/smbd/vt_mode.c b/source/smbd/vt_mode.c
index 83b62a38ac2..07558274a52 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;
@@ -82,7 +81,7 @@ VT_Start_utmp()
setutent();
- strcpy(u.ut_line, VT_Line);
+ fstrcpy(u.ut_line, VT_Line);
if((v = getutline(&u)) == NULL) {
if(strncmp(VT_Line, "tty", 3) == 0)
@@ -92,12 +91,12 @@ VT_Start_utmp()
else
tt = VT_Line;
- strcpy(u.ut_id, tt);
+ fstrcpy(u.ut_id, tt);
u.ut_time = time((time_t*)0);
}
- strcpy(u.ut_user, "LOGIN");
- strcpy(u.ut_line, VT_Line);
+ fstrcpy(u.ut_user, "LOGIN");
+ fstrcpy(u.ut_line, VT_Line);
u.ut_pid = getpid();
u.ut_type = LOGIN_PROCESS;
pututline(&u);
@@ -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;
@@ -119,10 +118,10 @@ VT_Stop_utmp()
if(VT_Line != NULL) {
setutent();
- strcpy(u.ut_line, VT_Line);
+ fstrcpy(u.ut_line, VT_Line);
if((v = getutline(&u)) != NULL) {
- strcpy(v->ut_user, "");
+ fstrcpy(v->ut_user, "");
v->ut_type = DEAD_PROCESS;
v->ut_time = time((time_t*)0);
pututline(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/smbparse.c b/source/smbparse.c
new file mode 100644
index 00000000000..b238cd513b1
--- /dev/null
+++ b/source/smbparse.c
@@ -0,0 +1,1290 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Samba utility functions
+ Copyright (C) Luke Leighton 1996 - 1997 Paul Ashton 1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+/*******************************************************************
+reads or writes a UTIME type.
+********************************************************************/
+char* smb_io_utime(BOOL io, UTIME *t, char *q, char *base, int align, int depth)
+{
+ if (t == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_utime\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_IVAL ("time", depth, base, io, q, t->time); q += 4;
+
+ return q;
+}
+
+/*******************************************************************
+reads or writes an NTTIME structure.
+********************************************************************/
+char* smb_io_time(BOOL io, NTTIME *nttime, char *q, char *base, int align, int depth)
+{
+ if (nttime == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_time\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_IVAL("low ", depth, base, io, q, nttime->low ); q += 4; /* low part */
+ DBG_RW_IVAL("high", depth, base, io, q, nttime->high); q += 4; /* high part */
+
+ return q;
+}
+
+/*******************************************************************
+creates a DOM_SID structure.
+
+BIG NOTE: this function only does SIDS where the identauth is not >= 2^32
+identauth >= 2^32 can be detected because it will be specified in hex
+
+********************************************************************/
+void make_dom_sid(DOM_SID *sid, char *domsid)
+{
+ int identauth;
+ char *p;
+
+ if (sid == NULL) return;
+
+ if (domsid == NULL)
+ {
+ DEBUG(4,("netlogon domain SID: none\n"));
+ sid->sid_rev_num = 0;
+ sid->num_auths = 0;
+ return;
+ }
+
+ DEBUG(4,("netlogon domain SID: %s\n", domsid));
+
+ /* assume, but should check, that domsid starts "S-" */
+ p = strtok(domsid+2,"-");
+ sid->sid_rev_num = atoi(p);
+
+ /* identauth in decimal should be < 2^32 */
+ /* identauth in hex should be >= 2^32 */
+ identauth = atoi(strtok(0,"-"));
+
+ DEBUG(4,("netlogon rev %d\n", sid->sid_rev_num));
+ DEBUG(4,("netlogon %s ia %d\n", p, identauth));
+
+ sid->id_auth[0] = 0;
+ sid->id_auth[1] = 0;
+ sid->id_auth[2] = (identauth & 0xff000000) >> 24;
+ sid->id_auth[3] = (identauth & 0x00ff0000) >> 16;
+ sid->id_auth[4] = (identauth & 0x0000ff00) >> 8;
+ sid->id_auth[5] = (identauth & 0x000000ff);
+
+ sid->num_auths = 0;
+
+ while ((p = strtok(0, "-")) != NULL)
+ {
+ sid->sub_auths[sid->num_auths++] = atoi(p);
+ }
+}
+
+/*******************************************************************
+reads or writes a DOM_SID structure.
+********************************************************************/
+char* smb_io_dom_sid(BOOL io, DOM_SID *sid, char *q, char *base, int align, int depth)
+{
+ int i;
+
+ if (sid == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_dom_sid\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_IVAL("num_auths ", depth, base, io, q, sid->num_auths); q += 4;
+ DBG_RW_CVAL("sid_rev_num", depth, base, io, q, sid->sid_rev_num); q++;
+ DBG_RW_CVAL("num_auths ", depth, base, io, q, sid->num_auths); q++;
+
+ for (i = 0; i < 6; i++)
+ {
+ fstring tmp;
+ sprintf(tmp, "id_auth[%d] ", i);
+ DBG_RW_CVAL(tmp, depth, base, io, q, sid->id_auth[i]); q++;
+ }
+
+ /* oops! XXXX should really issue a warning here... */
+ if (sid->num_auths > MAXSUBAUTHS) sid->num_auths = MAXSUBAUTHS;
+
+ DBG_RW_PIVAL(False, "sub_auths ", depth, base, io, q, sid->sub_auths, sid->num_auths); q += sid->num_auths * 4;
+
+ return q;
+}
+
+/*******************************************************************
+creates a UNIHDR structure.
+********************************************************************/
+void make_uni_hdr(UNIHDR *hdr, int max_len, int len, uint16 terminate)
+{
+ hdr->uni_max_len = 2 * max_len;
+ hdr->uni_str_len = 2 * len;
+ hdr->undoc = terminate;
+}
+
+/*******************************************************************
+reads or writes a UNIHDR structure.
+********************************************************************/
+char* smb_io_unihdr(BOOL io, UNIHDR *hdr, char *q, char *base, int align, int depth)
+{
+ if (hdr == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_unihdr\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_SVAL("uni_str_len", depth, base, io, q, hdr->uni_str_len); q += 2;
+ DBG_RW_SVAL("uni_max_len", depth, base, io, q, hdr->uni_max_len); q += 2;
+ DBG_RW_IVAL("undoc ", depth, base, io, q, hdr->undoc ); q += 4;
+
+ /* oops! XXXX maybe issue a warning that this is happening... */
+ if (hdr->uni_max_len > MAX_UNISTRLEN) hdr->uni_max_len = MAX_UNISTRLEN;
+ if (hdr->uni_str_len > MAX_UNISTRLEN) hdr->uni_str_len = MAX_UNISTRLEN;
+
+ return q;
+}
+
+/*******************************************************************
+creates a UNIHDR2 structure.
+********************************************************************/
+void make_uni_hdr2(UNIHDR2 *hdr, int max_len, int len, uint16 terminate)
+{
+ make_uni_hdr(&(hdr->unihdr), max_len, len, terminate);
+ hdr->undoc_buffer = len > 0 ? 1 : 0;
+}
+
+/*******************************************************************
+reads or writes a UNIHDR2 structure.
+********************************************************************/
+char* smb_io_unihdr2(BOOL io, UNIHDR2 *hdr2, char *q, char *base, int align, int depth)
+{
+ if (hdr2 == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_unihdr2\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ q = smb_io_unihdr(io, &(hdr2->unihdr), q, base, align, depth);
+ DBG_RW_IVAL("undoc_buffer", depth, base, io, q, hdr2->undoc_buffer); q += 4;
+
+ return q;
+}
+
+/*******************************************************************
+creates a UNISTR structure.
+********************************************************************/
+void make_unistr(UNISTR *str, char *buf)
+{
+ /* store the string (null-terminated copy) */
+ struni2(str->buffer, buf);
+}
+
+/*******************************************************************
+reads or writes a UNISTR structure.
+XXXX NOTE: UNISTR structures NEED to be null-terminated.
+********************************************************************/
+char* smb_io_unistr(BOOL io, UNISTR *uni, char *q, char *base, int align, int depth)
+{
+ int i = 0;
+
+ if (uni == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_unistr\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ do
+ {
+ RW_SVAL(io, q, uni->buffer[i], 0); q += 2;
+ i++;
+
+ } while ((i < sizeof(uni->buffer) / sizeof(uni->buffer[0])) &&
+ (uni->buffer[i] != 0));
+
+ return q;
+}
+
+/*******************************************************************
+creates a UNISTR2 structure.
+********************************************************************/
+void make_unistr2(UNISTR2 *str, char *buf, int len)
+{
+ /* set up string lengths. add one if string is not null-terminated */
+ str->uni_max_len = len;
+ str->undoc = 0;
+ str->uni_str_len = len;
+
+ /* store the string (null-terminated copy) */
+ struni2(str->buffer, buf);
+}
+
+/*******************************************************************
+reads or writes a UNISTR2 structure.
+XXXX NOTE: UNISTR2 structures need NOT be null-terminated.
+ the uni_str_len member tells you how long the string is;
+ the uni_max_len member tells you how large the buffer is.
+********************************************************************/
+char* smb_io_unistr2(BOOL io, UNISTR2 *uni2, char *q, char *base, int align, int depth)
+{
+ if (uni2 == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_unistr2\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ /* should be value 0, so enforce it. */
+ uni2->undoc = 0;
+
+ DBG_RW_IVAL("uni_max_len", depth, base, io, q, uni2->uni_max_len); q += 4;
+ DBG_RW_IVAL("undoc ", depth, base, io, q, uni2->undoc ); q += 4;
+ DBG_RW_IVAL("uni_str_len", depth, base, io, q, uni2->uni_str_len); q += 4;
+
+ /* oops! XXXX maybe issue a warning that this is happening... */
+ if (uni2->uni_max_len > MAX_UNISTRLEN) uni2->uni_max_len = MAX_UNISTRLEN;
+ if (uni2->uni_str_len > MAX_UNISTRLEN) uni2->uni_str_len = MAX_UNISTRLEN;
+
+ /* buffer advanced by indicated length of string
+ NOT by searching for null-termination */
+ DBG_RW_PSVAL(True, "buffer ", depth, base, io, q, uni2->buffer, uni2->uni_max_len); q += uni2->uni_max_len * 2;
+
+ return q;
+}
+
+/*******************************************************************
+creates a DOM_SID2 structure.
+********************************************************************/
+void make_dom_sid2(DOM_SID2 *sid2, char *sid_str)
+{
+ int len_sid_str = strlen(sid_str);
+
+ sid2->type = 0x5;
+ sid2->undoc = 0;
+ make_uni_hdr2(&(sid2->hdr), len_sid_str, len_sid_str, 0);
+ make_unistr (&(sid2->str), sid_str);
+}
+
+/*******************************************************************
+reads or writes a DOM_SID2 structure.
+********************************************************************/
+char* smb_io_dom_sid2(BOOL io, DOM_SID2 *sid2, char *q, char *base, int align, int depth)
+{
+ if (sid2 == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_dom_sid2\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ /* should be value 5, so enforce it */
+ sid2->type = 5;
+
+ /* should be value 0, so enforce it */
+ sid2->undoc = 0;
+
+ DBG_RW_IVAL("type ", depth, base, io, q, sid2->type ); q += 4;
+ DBG_RW_IVAL("undoc", depth, base, io, q, sid2->undoc); q += 4;
+
+ q = smb_io_unihdr2(io, &(sid2->hdr), q, base, align, depth);
+ q = smb_io_unistr (io, &(sid2->str), q, base, align, depth);
+
+ return q;
+}
+
+/*******************************************************************
+creates a DOM_RID2 structure.
+********************************************************************/
+void make_dom_rid2(DOM_RID2 *rid2, uint32 rid)
+{
+ rid2->type = 0x5;
+ rid2->undoc = 0x5;
+ rid2->rid = rid;
+ rid2->rid_idx = 0;
+}
+
+/*******************************************************************
+reads or writes a DOM_RID2 structure.
+********************************************************************/
+char* smb_io_dom_rid2(BOOL io, DOM_RID2 *rid2, char *q, char *base, int align, int depth)
+{
+ if (rid2 == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_dom_rid2\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ /* should be value 5, so enforce it */
+ rid2->type = 5;
+
+ /* should be value 5, so enforce it */
+ rid2->undoc = 5;
+
+ DBG_RW_IVAL("type ", depth, base, io, q, rid2->type); q += 4;
+ DBG_RW_IVAL("undoc ", depth, base, io, q, rid2->undoc ); q += 4;
+ DBG_RW_IVAL("rid ", depth, base, io, q, rid2->rid ); q += 4;
+ DBG_RW_IVAL("rid_idx", depth, base, io, q, rid2->rid_idx ); q += 4;
+
+ return q;
+}
+
+/*******************************************************************
+makes a DOM_CLNT_SRV structure.
+********************************************************************/
+void make_clnt_srv(DOM_CLNT_SRV *log, char *logon_srv, char *comp_name)
+{
+ if (log == NULL) return;
+
+ DEBUG(5,("make_clnt_srv: %d\n", __LINE__));
+
+ if (logon_srv != NULL)
+ {
+ log->undoc_buffer = 1;
+ make_unistr2(&(log->uni_logon_srv), logon_srv, strlen(logon_srv));
+ }
+ else
+ {
+ log->undoc_buffer = 1;
+ }
+
+ if (comp_name != NULL)
+ {
+ log->undoc_buffer2 = 1;
+ make_unistr2(&(log->uni_comp_name), comp_name, strlen(comp_name));
+ }
+ else
+ {
+ log->undoc_buffer2 = 1;
+ }
+}
+
+/*******************************************************************
+reads or writes a DOM_CLNT_SRV structure.
+********************************************************************/
+char* smb_io_clnt_srv(BOOL io, DOM_CLNT_SRV *log, char *q, char *base, int align, int depth)
+{
+ if (log == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_clnt_srv\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_IVAL("undoc_buffer ", depth, base, io, q, log->undoc_buffer ); q += 4;
+ q = smb_io_unistr2(io, &(log->uni_logon_srv), q, base, align, depth);
+
+ DBG_RW_IVAL("undoc_buffer2", depth, base, io, q, log->undoc_buffer2); q += 4;
+ q = smb_io_unistr2(io, &(log->uni_comp_name), q, base, align, depth);
+
+ return q;
+}
+
+/*******************************************************************
+makes a DOM_LOG_INFO structure.
+********************************************************************/
+void make_log_info(DOM_LOG_INFO *log, char *logon_srv, char *acct_name,
+ uint16 sec_chan, char *comp_name)
+{
+ if (log == NULL) return;
+
+ DEBUG(5,("make_log_info %d\n", __LINE__));
+
+ log->undoc_buffer = 1;
+
+ make_unistr2(&(log->uni_logon_srv), logon_srv, strlen(logon_srv));
+ make_unistr2(&(log->uni_acct_name), acct_name, strlen(acct_name));
+
+ log->sec_chan = sec_chan;
+
+ make_unistr2(&(log->uni_comp_name), comp_name, strlen(comp_name));
+}
+
+/*******************************************************************
+reads or writes a DOM_LOG_INFO structure.
+********************************************************************/
+char* smb_io_log_info(BOOL io, DOM_LOG_INFO *log, char *q, char *base, int align, int depth)
+{
+ if (log == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_log_info\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_IVAL("undoc_buffer", depth, base, io, q, log->undoc_buffer); q += 4;
+
+ q = smb_io_unistr2(io, &(log->uni_logon_srv), q, base, align, depth);
+ q = smb_io_unistr2(io, &(log->uni_acct_name), q, base, align, depth);
+
+ DBG_RW_SVAL("sec_chan", depth, base, io, q, log->sec_chan); q += 2;
+
+ q = smb_io_unistr2(io, &(log->uni_comp_name), q, base, align, depth);
+
+ return q;
+}
+
+/*******************************************************************
+reads or writes a DOM_CHAL structure.
+********************************************************************/
+char* smb_io_chal(BOOL io, DOM_CHAL *chal, char *q, char *base, int align, int depth)
+{
+ if (chal == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_chal\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_IVAL("data[0]", depth, base, io, q, chal->data[0]); q += 4;
+ DBG_RW_IVAL("data[1]", depth, base, io, q, chal->data[1]); q += 4;
+/*
+ DBG_RW_PCVAL(False, "data", depth, base, io, q, chal->data, 8); q += 8;
+*/
+ return q;
+}
+
+/*******************************************************************
+reads or writes a DOM_CRED structure.
+********************************************************************/
+char* smb_io_cred(BOOL io, DOM_CRED *cred, char *q, char *base, int align, int depth)
+{
+ if (cred == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_cred\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ q = smb_io_chal (io, &(cred->challenge), q, base, align, depth);
+ q = smb_io_utime(io, &(cred->timestamp), q, base, align, depth);
+
+ return q;
+}
+
+/*******************************************************************
+makes a DOM_CLNT_INFO2 structure.
+********************************************************************/
+void make_clnt_info2(DOM_CLNT_INFO2 *clnt,
+ char *logon_srv, char *comp_name,
+ DOM_CRED *clnt_cred)
+{
+ if (clnt == NULL) return;
+
+ DEBUG(5,("make_clnt_info: %d\n", __LINE__));
+
+ make_clnt_srv(&(clnt->login), logon_srv, comp_name);
+
+ if (clnt_cred != NULL)
+ {
+ clnt->ptr_cred = 1;
+ memcpy(&(clnt->cred), clnt_cred, sizeof(clnt->cred));
+ }
+ else
+ {
+ clnt->ptr_cred = 0;
+ }
+}
+
+/*******************************************************************
+reads or writes a DOM_CLNT_INFO2 structure.
+********************************************************************/
+char* smb_io_clnt_info2(BOOL io, DOM_CLNT_INFO2 *clnt, char *q, char *base, int align, int depth)
+{
+ if (clnt == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_clnt_info2\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ q = smb_io_clnt_srv(io, &(clnt->login), q, base, align, depth);
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_IVAL("ptr_cred", depth, base, io, q, clnt->ptr_cred); q += 4;
+ q = smb_io_cred (io, &(clnt->cred ), q, base, align, depth);
+
+ return q;
+}
+
+/*******************************************************************
+reads or writes a DOM_CLNT_INFO structure.
+********************************************************************/
+char* smb_io_clnt_info(BOOL io, DOM_CLNT_INFO *clnt, char *q, char *base, int align, int depth)
+{
+ if (clnt == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_clnt_info\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ q = smb_io_log_info(io, &(clnt->login), q, base, align, depth);
+ q = smb_io_cred (io, &(clnt->cred ), q, base, align, depth);
+
+ return q;
+}
+
+/*******************************************************************
+makes a DOM_LOGON_ID structure.
+********************************************************************/
+void make_logon_id(DOM_LOGON_ID *log, uint32 log_id_low, uint32 log_id_high)
+{
+ if (log == NULL) return;
+
+ DEBUG(5,("make_logon_id: %d\n", __LINE__));
+
+ log->low = log_id_low;
+ log->high = log_id_high;
+}
+
+/*******************************************************************
+reads or writes a DOM_LOGON_ID structure.
+********************************************************************/
+char* smb_io_logon_id(BOOL io, DOM_LOGON_ID *log, char *q, char *base, int align, int depth)
+{
+ if (log == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_logon_id\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_IVAL("low ", depth, base, io, q, log->low ); q += 4;
+ DBG_RW_IVAL("high", depth, base, io, q, log->high); q += 4;
+
+ return q;
+}
+
+/*******************************************************************
+makes an ARC4_OWF structure.
+********************************************************************/
+void make_arc4_owf(ARC4_OWF *hash, char data[16])
+{
+ if (hash == NULL) return;
+
+ DEBUG(5,("make_arc4_owf: %d\n", __LINE__));
+
+ if (data != NULL)
+ {
+ memcpy(hash->data, data, sizeof(hash->data));
+ }
+ else
+ {
+ bzero(hash->data, sizeof(hash->data));
+ }
+}
+
+/*******************************************************************
+reads or writes an ARC4_OWF structure.
+********************************************************************/
+char* smb_io_arc4_owf(BOOL io, ARC4_OWF *hash, char *q, char *base, int align, int depth)
+{
+ if (hash == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_arc4_owf\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_PCVAL(False, "data", depth, base, io, q, hash->data, 16); q += 16;
+
+ return q;
+}
+
+/*******************************************************************
+makes a DOM_ID_INFO_1 structure.
+********************************************************************/
+void make_id_info1(DOM_ID_INFO_1 *id, char *domain_name,
+ uint32 param_ctrl, uint32 log_id_low, uint32 log_id_high,
+ char *user_name, char *wksta_name,
+ char arc4_lm_owf[16], char arc4_nt_owf[16])
+{
+ int len_domain_name = strlen(domain_name);
+ int len_user_name = strlen(user_name );
+ int len_wksta_name = strlen(wksta_name );
+
+ if (id == NULL) return;
+
+ DEBUG(5,("make_id_info1: %d\n", __LINE__));
+
+ id->ptr_id_info1 = 1;
+
+ make_uni_hdr(&(id->hdr_domain_name), len_domain_name, len_domain_name, 4);
+
+ id->param_ctrl = param_ctrl;
+ make_logon_id(&(id->logon_id), log_id_low, log_id_high);
+
+ make_uni_hdr(&(id->hdr_user_name ), len_user_name , len_user_name , 4);
+ make_uni_hdr(&(id->hdr_wksta_name ), len_wksta_name , len_wksta_name , 4);
+
+ make_arc4_owf(&(id->arc4_lm_owf), arc4_lm_owf);
+ make_arc4_owf(&(id->arc4_nt_owf), arc4_nt_owf);
+
+ make_unistr2(&(id->uni_domain_name), domain_name, len_domain_name);
+ make_unistr2(&(id->uni_user_name ), user_name , len_user_name );
+ make_unistr2(&(id->uni_wksta_name ), wksta_name , len_wksta_name );
+}
+
+/*******************************************************************
+reads or writes an DOM_ID_INFO_1 structure.
+********************************************************************/
+char* smb_io_id_info1(BOOL io, DOM_ID_INFO_1 *id, char *q, char *base, int align, int depth)
+{
+ if (id == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_id_info1\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_IVAL("ptr_id_info1", depth, base, io, q, id->ptr_id_info1); q += 4;
+
+ if (id->ptr_id_info1 != 0)
+ {
+ q = smb_io_unihdr(io, &(id->hdr_domain_name), q, base, align, depth);
+
+ DBG_RW_IVAL("param_ctrl", depth, base, io, q, id->param_ctrl); q += 4;
+ q = smb_io_logon_id(io, &(id->logon_id), q, base, align, depth);
+
+ q = smb_io_unihdr(io, &(id->hdr_user_name ), q, base, align, depth);
+ q = smb_io_unihdr(io, &(id->hdr_wksta_name ), q, base, align, depth);
+
+ q = smb_io_arc4_owf(io, &(id->arc4_lm_owf), q, base, align, depth);
+ q = smb_io_arc4_owf(io, &(id->arc4_nt_owf), q, base, align, depth);
+
+ q = smb_io_unistr2(io, &(id->uni_domain_name), q, base, align, depth);
+ q = smb_io_unistr2(io, &(id->uni_user_name ), q, base, align, depth);
+ q = smb_io_unistr2(io, &(id->uni_wksta_name ), q, base, align, depth);
+ }
+
+ return q;
+}
+
+/*******************************************************************
+makes a DOM_SAM_INFO structure.
+********************************************************************/
+void make_sam_info(DOM_SAM_INFO *sam,
+ char *logon_srv, char *comp_name, DOM_CRED *clnt_cred,
+ DOM_CRED *rtn_cred, uint16 logon_level, uint16 switch_value,
+ DOM_ID_INFO_1 *id1)
+{
+ if (sam == NULL) return;
+
+ DEBUG(5,("make_sam_info: %d\n", __LINE__));
+
+ make_clnt_info2(&(sam->client), logon_srv, comp_name, clnt_cred);
+
+ if (rtn_cred != NULL)
+ {
+ sam->ptr_rtn_cred = 1;
+ memcpy(&(sam->rtn_cred), rtn_cred, sizeof(sam->rtn_cred));
+ }
+ else
+ {
+ sam->ptr_rtn_cred = 0;
+ }
+
+ sam->logon_level = logon_level;
+ sam->switch_value = switch_value;
+
+ switch (sam->switch_value)
+ {
+ case 1:
+ {
+ sam->auth.id1 = id1;
+ break;
+ }
+ default:
+ {
+ /* PANIC! */
+ DEBUG(4,("make_sam_info: unknown switch_value!\n"));
+ break;
+ }
+ }
+}
+
+/*******************************************************************
+reads or writes a DOM_SAM_INFO structure.
+********************************************************************/
+char* smb_io_sam_info(BOOL io, DOM_SAM_INFO *sam, char *q, char *base, int align, int depth)
+{
+ if (sam == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_sam_info\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ q = smb_io_clnt_info2(io, &(sam->client ), q, base, align, depth);
+
+ DBG_RW_IVAL("ptr_rtn_cred", depth, base, io, q, sam->ptr_rtn_cred); q += 4;
+ q = smb_io_cred (io, &(sam->rtn_cred), q, base, align, depth);
+
+ DBG_RW_SVAL("logon_level ", depth, base, io, q, sam->logon_level); q += 2;
+ DBG_RW_SVAL("switch_value", depth, base, io, q, sam->switch_value); q += 2;
+
+ switch (sam->switch_value)
+ {
+ case 1:
+ {
+ q = smb_io_id_info1(io, sam->auth.id1, q, base, align, depth);
+ break;
+ }
+ default:
+ {
+ /* PANIC! */
+ DEBUG(4,("smb_io_sam_info: unknown switch_value!\n"));
+ break;
+ }
+ }
+ return q;
+}
+
+/*******************************************************************
+reads or writes a DOM_GID structure.
+********************************************************************/
+char* smb_io_gid(BOOL io, DOM_GID *gid, char *q, char *base, int align, int depth)
+{
+ if (gid == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_gid\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_IVAL("g_rid", depth, base, io, q, gid->g_rid); q += 4;
+ DBG_RW_IVAL("attr ", depth, base, io, q, gid->attr ); q += 4;
+
+ return q;
+}
+
+/*******************************************************************
+creates an RPC_HDR structure.
+********************************************************************/
+void make_rpc_hdr(RPC_HDR *hdr, enum RPC_PKT_TYPE pkt_type, uint8 frag,
+ uint32 call_id, int data_len)
+{
+ if (hdr == NULL) return;
+
+ hdr->major = 5; /* RPC version 5 */
+ hdr->minor = 0; /* minor version 0 */
+ hdr->pkt_type = pkt_type; /* RPC packet type */
+ hdr->frag = frag; /* first frag + last frag */
+ hdr->pack_type = 0x10; /* packed data representation */
+ hdr->frag_len = data_len; /* fragment length, fill in later */
+ hdr->auth_len = 0; /* authentication length */
+ hdr->call_id = call_id; /* call identifier - match incoming RPC */
+}
+
+/*******************************************************************
+reads or writes an RPC_HDR structure.
+********************************************************************/
+char* smb_io_rpc_hdr(BOOL io, RPC_HDR *rpc, char *q, char *base, int align, int depth)
+{
+ if (rpc == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_rpc_hdr\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ DBG_RW_CVAL("major ", depth, base, io, q, rpc->major); q++;
+ DBG_RW_CVAL("minor ", depth, base, io, q, rpc->minor); q++;
+ DBG_RW_CVAL("pkt_type ", depth, base, io, q, rpc->pkt_type); q++;
+ DBG_RW_CVAL("frag ", depth, base, io, q, rpc->frag); q++;
+ DBG_RW_IVAL("pack_type ", depth, base, io, q, rpc->pack_type); q += 4;
+ DBG_RW_SVAL("frag_len ", depth, base, io, q, rpc->frag_len); q += 2;
+ DBG_RW_SVAL("auth_len ", depth, base, io, q, rpc->auth_len); q += 2;
+ DBG_RW_IVAL("call_id ", depth, base, io, q, rpc->call_id); q += 4;
+
+ return q;
+}
+
+/*******************************************************************
+creates an RPC_IFACE structure.
+********************************************************************/
+void make_rpc_iface(RPC_IFACE *ifc, char data[16], uint32 version)
+{
+ if (ifc == NULL || data == NULL) return;
+
+ memcpy(ifc->data, data, sizeof(ifc->data)); /* 16 bytes of number */
+ ifc->version = version; /* the interface number */
+}
+
+/*******************************************************************
+reads or writes an RPC_IFACE structure.
+********************************************************************/
+char* smb_io_rpc_iface(BOOL io, RPC_IFACE *ifc, char *q, char *base, int align, int depth)
+{
+ if (ifc == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_rpc_iface\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_PCVAL(False, "data ", depth, base, io, q, ifc->data, sizeof(ifc->data)); q += sizeof(ifc->data);
+ DBG_RW_IVAL ( "version", depth, base, io, q, ifc->version); q += 4;
+
+ return q;
+}
+
+/*******************************************************************
+creates an RPC_ADDR_STR structure.
+********************************************************************/
+void make_rpc_addr_str(RPC_ADDR_STR *str, char *name)
+{
+ if (str == NULL || name == NULL) return;
+
+ str->len = strlen(name) + 1;
+ fstrcpy(str->str, name);
+}
+
+/*******************************************************************
+reads or writes an RPC_ADDR_STR structure.
+********************************************************************/
+char* smb_io_rpc_addr_str(BOOL io, RPC_ADDR_STR *str, char *q, char *base, int align, int depth)
+{
+ if (str == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_rpc_addr_str\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_IVAL ( "len", depth, base, io, q, str->len); q += 2;
+ DBG_RW_PCVAL(True, "str", depth, base, io, q, str->str, str->len); q += str->len;
+
+ return q;
+}
+
+/*******************************************************************
+creates an RPC_HDR_BBA structure.
+********************************************************************/
+void make_rpc_hdr_bba(RPC_HDR_BBA *bba, uint16 max_tsize, uint16 max_rsize, uint32 assoc_gid)
+{
+ if (bba == NULL) return;
+
+ bba->max_tsize = max_tsize; /* maximum transmission fragment size (0x1630) */
+ bba->max_rsize = max_rsize; /* max receive fragment size (0x1630) */
+ bba->assoc_gid = assoc_gid; /* associated group id (0x0) */
+}
+
+/*******************************************************************
+reads or writes an RPC_HDR_BBA structure.
+********************************************************************/
+char* smb_io_rpc_hdr_bba(BOOL io, RPC_HDR_BBA *rpc, char *q, char *base, int align, int depth)
+{
+ if (rpc == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_rpc_hdr_bba\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ DBG_RW_SVAL("max_tsize", depth, base, io, q, rpc->max_tsize); q += 2;
+ DBG_RW_SVAL("max_rsize", depth, base, io, q, rpc->max_rsize); q += 2;
+ DBG_RW_IVAL("assoc_gid", depth, base, io, q, rpc->assoc_gid); q += 4;
+
+ return q;
+}
+
+/*******************************************************************
+creates an RPC_HDR_RB structure.
+********************************************************************/
+void make_rpc_hdr_rb(RPC_HDR_RB *rpc,
+ uint16 max_tsize, uint16 max_rsize, uint32 assoc_gid,
+ uint32 num_elements, uint16 context_id, uint8 num_syntaxes,
+ RPC_IFACE *abstract, RPC_IFACE *transfer)
+{
+ if (rpc == NULL) return;
+
+ make_rpc_hdr_bba(&(rpc->bba), max_tsize, max_rsize, assoc_gid);
+
+ rpc->num_elements = num_elements ; /* the number of elements (0x1) */
+ rpc->context_id = context_id ; /* presentation context identifier (0x0) */
+ rpc->num_syntaxes = num_syntaxes ; /* the number of syntaxes (has always been 1?)(0x1) */
+
+ /* num and vers. of interface client is using */
+ memcpy(&(rpc->abstract), abstract, sizeof(rpc->abstract));
+
+ /* num and vers. of interface to use for replies */
+ memcpy(&(rpc->transfer), transfer, sizeof(rpc->transfer));
+}
+
+/*******************************************************************
+reads or writes an RPC_HDR_RB structure.
+********************************************************************/
+char* smb_io_rpc_hdr_rb(BOOL io, RPC_HDR_RB *rpc, char *q, char *base, int align, int depth)
+{
+ if (rpc == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_rpc_hdr_bba\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = smb_io_rpc_hdr_bba(io, &(rpc->bba), q, base, align, depth);
+
+ DBG_RW_IVAL("num_elements", depth, base, io, q, rpc->num_elements); q += 4;
+ DBG_RW_IVAL("context_id ", depth, base, io, q, rpc->context_id ); q += 4;
+ DBG_RW_IVAL("num_syntaxes", depth, base, io, q, rpc->num_syntaxes); q += 4;
+
+ q = smb_io_rpc_iface(io, &(rpc->abstract), q, base, align, depth);
+ q = smb_io_rpc_iface(io, &(rpc->transfer), q, base, align, depth);
+
+ return q;
+}
+
+/*******************************************************************
+creates an RPC_RESULTS structure.
+
+lkclXXXX only one reason at the moment!
+
+********************************************************************/
+void make_rpc_results(RPC_RESULTS *res,
+ uint8 num_results, uint16 result, uint16 reason)
+{
+ if (res == NULL) return;
+
+ res->num_results = num_results; /* the number of results (0x01) */
+ res->result = result ; /* result (0x00 = accept) */
+ res->reason = reason ; /* reason (0x00 = no reason specified) */
+}
+
+/*******************************************************************
+reads or writes an RPC_RESULTS structure.
+
+lkclXXXX only one reason at the moment!
+
+********************************************************************/
+char* smb_io_rpc_results(BOOL io, RPC_RESULTS *res, char *q, char *base, int align, int depth)
+{
+ if (res == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_rpc_results\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_CVAL("num_results", depth, base, io, q, res->num_results); q++;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_SVAL("result ", depth, base, io, q, res->result ); q += 2;
+ DBG_RW_SVAL("reason ", depth, base, io, q, res->reason ); q += 2;
+
+ return q;
+}
+
+/*******************************************************************
+creates an RPC_HDR_BA structure.
+
+lkclXXXX only one reason at the moment!
+
+********************************************************************/
+void make_rpc_hdr_ba(RPC_HDR_BA *rpc,
+ uint16 max_tsize, uint16 max_rsize, uint32 assoc_gid,
+ char *pipe_addr,
+ uint8 num_results, uint16 result, uint16 reason,
+ RPC_IFACE *transfer)
+{
+ if (rpc == NULL || transfer == NULL || pipe_addr == NULL) return;
+
+ make_rpc_hdr_bba (&(rpc->bba ), max_tsize, max_rsize, assoc_gid);
+ make_rpc_addr_str(&(rpc->addr), pipe_addr);
+ make_rpc_results (&(rpc->res ), num_results, result, reason);
+
+ /* the transfer syntax from the request */
+ memcpy(&(rpc->transfer), transfer, sizeof(rpc->transfer));
+}
+
+/*******************************************************************
+reads or writes an RPC_HDR_BA structure.
+********************************************************************/
+char* smb_io_rpc_hdr_ba(BOOL io, RPC_HDR_BA *rpc, char *q, char *base, int align, int depth)
+{
+ if (rpc == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_rpc_hdr_ba\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = smb_io_rpc_hdr_bba (io, &(rpc->bba) , q, base, align, depth);
+ q = smb_io_rpc_addr_str(io, &(rpc->addr) , q, base, align, depth);
+ q = smb_io_rpc_results (io, &(rpc->res) , q, base, align, depth);
+ q = smb_io_rpc_iface (io, &(rpc->transfer), q, base, align, depth);
+
+ return q;
+}
+
+/*******************************************************************
+makes an LSA_OBJ_ATTR structure.
+********************************************************************/
+void make_obj_attr(LSA_OBJ_ATTR *attr, uint32 attributes, uint32 sec_qos)
+{
+ if (attr == NULL) return;
+
+ DEBUG(5,("make_obj_attr\n"));
+
+ attr->len = 0x18; /* length of object attribute block, in bytes */
+ attr->ptr_root_dir = 0;
+ attr->ptr_obj_name = 0;
+ attr->attributes = attributes;
+ attr->ptr_sec_desc = 0;
+ attr->sec_qos = sec_qos;
+}
+
+/*******************************************************************
+reads or writes an LSA_OBJ_ATTR structure.
+********************************************************************/
+char* smb_io_obj_attr(BOOL io, LSA_OBJ_ATTR *attr, char *q, char *base, int align, int depth)
+{
+ char *start;
+
+ if (attr == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_obj_attr\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ start = q;
+
+ /* these pointers had _better_ be zero, because we don't know
+ what they point to!
+ */
+ DBG_RW_IVAL("len" , depth, base, io, q, attr->len ); q += 4; /* 0x18 - length (in bytes) inc. the length field. */
+ DBG_RW_IVAL("ptr_root_dir", depth, base, io, q, attr->ptr_root_dir); q += 4; /* 0 - root directory (pointer) */
+ DBG_RW_IVAL("ptr_obj_name", depth, base, io, q, attr->ptr_obj_name); q += 4; /* 0 - object name (pointer) */
+ DBG_RW_IVAL("attributes" , depth, base, io, q, attr->attributes ); q += 4; /* 0 - attributes (undocumented) */
+ DBG_RW_IVAL("ptr_sec_desc", depth, base, io, q, attr->ptr_sec_desc); q += 4; /* 0 - security descriptior (pointer) */
+ DBG_RW_IVAL("sec_qos" , depth, base, io, q, attr->sec_qos ); q += 4; /* 0 - security quality of service */
+
+ if (attr->len != PTR_DIFF(q, start))
+ {
+ DEBUG(3,("smb_io_obj_attr: length %lx does not match size %lx\n",
+ attr->len, PTR_DIFF(q, start)));
+ }
+
+ return q;
+}
+
+/*******************************************************************
+creates an RPC_HDR_RR structure.
+********************************************************************/
+void make_rpc_hdr_rr(RPC_HDR_RR *hdr, enum RPC_PKT_TYPE pkt_type,
+ uint32 call_id, int data_len, uint8 opnum)
+{
+ if (hdr == NULL) return;
+
+ /* frag is FIRST_FRAG | LAST_FRAG. lkclXXXX must define these */
+ make_rpc_hdr(&(hdr->hdr), pkt_type, 0x03, call_id, data_len);
+
+ hdr->alloc_hint = data_len - 0x18; /* allocation hint */
+ hdr->context_id = 0; /* presentation context identifier */
+ hdr->cancel_count = 0; /* cancel count */
+ hdr->opnum = opnum; /* opnum */
+}
+
+/*******************************************************************
+reads or writes an RPC_HDR_RR structure.
+********************************************************************/
+char* smb_io_rpc_hdr_rr(BOOL io, RPC_HDR_RR *rpc, char *q, char *base, int align, int depth)
+{
+ if (rpc == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_rpc_hdr_rr\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = smb_io_rpc_hdr(io, &(rpc->hdr), q, base, align, depth);
+
+ DBG_RW_IVAL("alloc_hint", depth, base, io, q, rpc->alloc_hint); q += 4;
+ DBG_RW_CVAL("context_id", depth, base, io, q, rpc->context_id); q++;
+ DBG_RW_CVAL("cancel_ct ", depth, base, io, q, rpc->cancel_count); q++;
+ DBG_RW_CVAL("opnum ", depth, base, io, q, rpc->opnum); q++;
+
+ return q;
+}
+/*******************************************************************
+reads or writes an LSA_POL_HND structure.
+********************************************************************/
+char* smb_io_pol_hnd(BOOL io, LSA_POL_HND *pol, char *q, char *base, int align, int depth)
+{
+ if (pol == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_pol_hnd\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_PCVAL(False, "data", depth, base, io, q, pol->data, POL_HND_SIZE); q += POL_HND_SIZE;
+
+ return q;
+}
+
+/*******************************************************************
+reads or writes a dom query structure.
+********************************************************************/
+char* smb_io_dom_query_3(BOOL io, DOM_QUERY_3 *d_q, char *q, char *base, int align, int depth)
+{
+ return smb_io_dom_query(io, d_q, q, base, align, depth);
+}
+
+/*******************************************************************
+reads or writes a dom query structure.
+********************************************************************/
+char* smb_io_dom_query_5(BOOL io, DOM_QUERY_3 *d_q, char *q, char *base, int align, int depth)
+{
+ return smb_io_dom_query(io, d_q, q, base, align, depth);
+}
+
+/*******************************************************************
+reads or writes a dom query structure.
+********************************************************************/
+char* smb_io_dom_query(BOOL io, DOM_QUERY *d_q, char *q, char *base, int align, int depth)
+{
+ if (d_q == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_dom_query\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_SVAL("uni_dom_max_len", depth, base, io, q, d_q->uni_dom_max_len); q += 2; /* domain name string length * 2 */
+ DBG_RW_SVAL("uni_dom_str_len", depth, base, io, q, d_q->uni_dom_str_len); q += 2; /* domain name string length * 2 */
+
+ DBG_RW_IVAL("buffer_dom_name", depth, base, io, q, d_q->buffer_dom_name); q += 4; /* undocumented domain name string buffer pointer */
+ DBG_RW_IVAL("buffer_dom_sid ", depth, base, io, q, d_q->buffer_dom_sid ); q += 4; /* undocumented domain SID string buffer pointer */
+
+ if (d_q->buffer_dom_name != 0)
+ {
+ q = smb_io_unistr2(io, &(d_q->uni_domain_name), q, base, align, depth); /* domain name (unicode string) */
+ }
+ if (d_q->buffer_dom_sid != 0)
+ {
+ q = smb_io_dom_sid(io, &(d_q->dom_sid), q, base, align, depth); /* domain SID */
+ }
+
+ return q;
+}
+
+/*******************************************************************
+reads or writes a DOM_R_REF structure.
+********************************************************************/
+char* smb_io_dom_r_ref(BOOL io, DOM_R_REF *r_r, char *q, char *base, int align, int depth)
+{
+ int i;
+
+ DEBUG(5,("%s%04x smb_io_dom_r_ref\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ if (r_r == NULL) return NULL;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_IVAL("undoc_buffer ", depth, base, io, q, r_r->undoc_buffer); q += 4; /* undocumented buffer pointer. */
+ DBG_RW_IVAL("num_ref_doms_1 ", depth, base, io, q, r_r->num_ref_doms_1); q += 4; /* num referenced domains? */
+ DBG_RW_IVAL("buffer_dom_name", depth, base, io, q, r_r->buffer_dom_name); q += 4; /* undocumented domain name buffer pointer. */
+ DBG_RW_IVAL("max_entries ", depth, base, io, q, r_r->max_entries); q += 4; /* 32 - max number of entries */
+ DBG_RW_IVAL("num_ref_doms_2 ", depth, base, io, q, r_r->num_ref_doms_2); q += 4; /* 4 - num referenced domains? */
+
+ q = smb_io_unihdr2(io, &(r_r->hdr_dom_name), q, base, align, depth); /* domain name unicode string header */
+
+ for (i = 0; i < r_r->num_ref_doms_1-1; i++)
+ {
+ q = smb_io_unihdr2(io, &(r_r->hdr_ref_dom[i]), q, base, align, depth);
+ }
+
+ q = smb_io_unistr(io, &(r_r->uni_dom_name), q, base, align, depth); /* domain name unicode string */
+
+ for (i = 0; i < r_r->num_ref_doms_2; i++)
+ {
+ q = smb_io_dom_sid(io, &(r_r->ref_dom[i]), q, base, align, depth); /* referenced domain SIDs */
+ }
+ return q;
+}
+
+/*******************************************************************
+reads or writes a DOM_NAME structure.
+********************************************************************/
+char* smb_io_dom_name(BOOL io, DOM_NAME *name, char *q, char *base, int align, int depth)
+{
+ if (name == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_dom_name\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_IVAL("uni_str_len", depth, base, io, q, name->uni_str_len); q += 4;
+
+ /* don't know if len is specified by uni_str_len member... */
+ /* assume unicode string is unicode-null-terminated, instead */
+
+ q = smb_io_unistr(io, &(name->str), q, base, align, depth);
+
+ return q;
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+char* smb_io_neg_flags(BOOL io, NEG_FLAGS *neg, char *q, char *base, int align, int depth)
+{
+ if (neg == NULL) return NULL;
+
+ DEBUG(5,("%s%04x smb_io_neg_flags\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_IVAL("neg_flags", depth, base, io, q, neg->neg_flags); q += 4;
+
+ return q;
+}
+
+
+#if 0
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+ char* smb_io_(BOOL io, *, char *q, char *base, int align, int depth)
+{
+ if (== NULL) return NULL;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_IVAL("", depth, base, io, q, ); q += 4;
+
+ return q;
+}
+#endif
+
diff --git a/source/srvparse.c b/source/srvparse.c
new file mode 100644
index 00000000000..d65a529e329
--- /dev/null
+++ b/source/srvparse.c
@@ -0,0 +1,205 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1994 - 1997
+ Copyright (C) Luke Kenneth Casson Leighton 1996 - 1997
+ Copyright (C) Paul Ashton 1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+char* srv_io_share_info1_str(BOOL io, SH_INFO_1_STR *sh1, char *q, char *base, int align, int depth)
+{
+ if (sh1 == NULL) return NULL;
+
+ DEBUG(5,("%s%04x srv_io_share_info1_str\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ q = smb_io_unistr2(io, &(sh1->uni_netname), q, base, align, depth);
+ q = smb_io_unistr2(io, &(sh1->uni_remark ), q, base, align, depth);
+
+ return q;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+char* srv_io_share_info1(BOOL io, SH_INFO_1 *sh1, char *q, char *base, int align, int depth)
+{
+ if (sh1 == NULL) return NULL;
+
+ DEBUG(5,("%s%04x srv_io_share_info1\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_IVAL("ptr_netname", depth, base, io, q, sh1->ptr_netname); q += 4;
+ DBG_RW_IVAL("type ", depth, base, io, q, sh1->type ); q += 4;
+ DBG_RW_IVAL("ptr_remark ", depth, base, io, q, sh1->ptr_remark); q += 4;
+
+ return q;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+char* srv_io_share_1_ctr(BOOL io, SHARE_INFO_1_CTR *ctr, char *q, char *base, int align, int depth)
+{
+ if (ctr == NULL) return NULL;
+
+ DEBUG(5,("%s%04x srv_io_share_1_ctr\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_IVAL("num_entries_read", depth, base, io, q, ctr->num_entries_read); q += 4;
+ DBG_RW_IVAL("ptr_share_info", depth, base, io, q, ctr->ptr_share_info); q += 4;
+
+ if (ctr->ptr_share_info != 0)
+ {
+ int i;
+ int num_entries = ctr->num_entries_read;
+ if (num_entries > MAX_SHARE_ENTRIES)
+ {
+ num_entries = MAX_SHARE_ENTRIES; /* report this! */
+ }
+
+ DBG_RW_IVAL("num_entries_read2", depth, base, io, q, ctr->num_entries_read2); q += 4;
+
+ for (i = 0; i < num_entries; i++)
+ {
+ q = srv_io_share_info1(io, &(ctr->info_1[i]), q, base, align, depth);
+ }
+
+ for (i = 0; i < num_entries; i++)
+ {
+ q = srv_io_share_info1_str(io, &(ctr->info_1_str[i]), q, base, align, depth);
+ }
+
+ q = align_offset(q, base, align);
+ DBG_RW_IVAL("num_entries_read3", depth, base, io, q, ctr->num_entries_read3); q += 4;
+ DBG_RW_IVAL("padding ", depth, base, io, q, ctr->padding); q += 4;
+ }
+
+ return q;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+char* srv_io_q_net_share_enum(BOOL io, SRV_Q_NET_SHARE_ENUM *q_n, char *q, char *base, int align, int depth)
+{
+ if (q_n == NULL) return NULL;
+
+ DEBUG(5,("%s%04x srv_io_q_net_share_enum\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_IVAL("ptr_srv_name", depth, base, io, q, q_n->ptr_srv_name); q += 4;
+ q = smb_io_unistr2(io, &(q_n->uni_srv_name), q, base, align, depth);
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_IVAL("share_level ", depth, base, io, q, q_n->share_level); q += 4;
+ DBG_RW_IVAL("switch_value ", depth, base, io, q, q_n->switch_value); q += 4;
+
+ DBG_RW_IVAL("ptr_share_info", depth, base, io, q, q_n->ptr_share_info); q += 4;
+ if (q_n->ptr_share_info != 0)
+ {
+ switch (q_n->switch_value)
+ {
+ case 1:
+ {
+ q = srv_io_share_1_ctr(io, &(q_n->share.info1), q, base, align, depth);
+ break;
+ }
+ default:
+ {
+ DEBUG(5,("%s% no share info at switch_value %d\n",
+ tab_depth(depth), q_n->switch_value));
+ break;
+ }
+ }
+ }
+ DBG_RW_IVAL("preferred_len ", depth, base, io, q, q_n->preferred_len); q += 4;
+
+ return q;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+char* srv_io_r_net_share_enum(BOOL io, SRV_R_NET_SHARE_ENUM *r_n, char *q, char *base, int align, int depth)
+{
+ if (r_n == NULL) return NULL;
+
+ DEBUG(5,("%s%04x srv_io_q_net_share_enum\n", tab_depth(depth), PTR_DIFF(q, base)));
+ depth++;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_IVAL("share_level ", depth, base, io, q, r_n->share_level); q += 4;
+ DBG_RW_IVAL("switch_value ", depth, base, io, q, r_n->switch_value); q += 4;
+
+ DBG_RW_IVAL("ptr_share_info", depth, base, io, q, r_n->ptr_share_info); q += 4;
+ if (r_n->ptr_share_info != 0)
+ {
+ switch (r_n->switch_value)
+ {
+ case 1:
+ {
+ q = srv_io_share_1_ctr(io, &(r_n->share.info1), q, base, align, depth);
+ break;
+ }
+ default:
+ {
+ DEBUG(5,("%s% no share info at switch_value %d\n",
+ tab_depth(depth), r_n->switch_value));
+ break;
+ }
+ }
+ }
+ DBG_RW_IVAL("status ", depth, base, io, q, r_n->status); q += 4;
+
+ return q;
+}
+
+#if 0
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+ char* lsa_io_(BOOL io, *, char *q, char *base, int align, int depth)
+{
+ if (== NULL) return NULL;
+
+ q = align_offset(q, base, align);
+
+ DBG_RW_IVAL("", depth, base, io, q, ); q += 4;
+
+ return q;
+}
+#endif
diff --git a/source/ubi_dLinkList.c b/source/ubi_dLinkList.c
new file mode 100644
index 00000000000..e82b9df1324
--- /dev/null
+++ b/source/ubi_dLinkList.c
@@ -0,0 +1,147 @@
+/* ========================================================================== **
+ * ubi_dLinkList.c
+ *
+ * Copyright (C) 1997 by Christopher R. Hertel
+ *
+ * Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ * This module implements simple doubly-linked lists.
+ * -------------------------------------------------------------------------- **
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * Revision 0.3 1997/10/15 03:05:39 crh
+ * Added some handy type casting to the macros. Added AddHere and RemThis
+ * macros.
+ *
+ * Revision 0.2 1997/10/08 03:07:21 crh
+ * Fixed a few forgotten link-ups in Insert(), and fixed the AddHead()
+ * macro, which was passing the wrong value for <After> to Insert().
+ *
+ * Revision 0.1 1997/10/07 04:34:07 crh
+ * Initial Revision.
+ *
+ *
+ * ========================================================================== **
+ */
+
+#include "includes.h"
+#include "ubi_dLinkList.h"
+
+/* ========================================================================== **
+ * Functions...
+ */
+
+ubi_dlListPtr ubi_dlInitList( ubi_dlListPtr ListPtr )
+ /* ------------------------------------------------------------------------ **
+ * Initialize a doubly-linked list header.
+ *
+ * Input: ListPtr - A pointer to the list structure that is to be
+ * initialized for use.
+ *
+ * Output: A pointer to the initialized list header (i.e., same as
+ * <ListPtr>).
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ListPtr->Head = NULL;
+ ListPtr->Tail = NULL;
+ ListPtr->count = 0;
+ return( ListPtr );
+ } /* ubi_dlInitList */
+
+ubi_dlNodePtr ubi_dlInsert( ubi_dlListPtr ListPtr,
+ ubi_dlNodePtr New,
+ ubi_dlNodePtr After )
+ /* ------------------------------------------------------------------------ **
+ * Insert a new node into the list.
+ *
+ * Input: ListPtr - A pointer to the list into which the node is to
+ * be inserted.
+ * New - Pointer to the new node.
+ * After - NULL, or a pointer to a node that is already in the
+ * list.
+ * If NULL, then <New> will be added at the head of the
+ * list, else it will be added following <After>.
+ *
+ * Output: A pointer to the node that was inserted into the list (i.e.,
+ * the same as <New>).
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ if( NULL == After )
+ {
+ New->Next = ListPtr->Head;
+ New->Prev = NULL;
+ if( NULL != ListPtr->Head )
+ ListPtr->Head->Prev = New;
+ else
+ ListPtr->Tail = New;
+ ListPtr->Head = New;
+ }
+ else
+ {
+ New->Next = After->Next;
+ New->Prev = After;
+ if( NULL != After->Next )
+ After->Next->Prev = New;
+ else
+ ListPtr->Tail = New;
+ After->Next = New;
+ }
+
+ ++(ListPtr->count);
+
+ return( New );
+ } /* ubi_dlInsert */
+
+ubi_dlNodePtr ubi_dlRemove( ubi_dlListPtr ListPtr, ubi_dlNodePtr Old )
+ /* ------------------------------------------------------------------------ **
+ * Remove a node from the list.
+ *
+ * Input: ListPtr - A pointer to the list from which <Old> is to be
+ * removed.
+ * Old - A pointer to the node that is to be removed from the
+ * list.
+ *
+ * Output: A pointer to the node that was removed (i.e., <Old>).
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ if( NULL != Old )
+ {
+ if( Old->Next )
+ Old->Next->Prev = Old->Prev;
+ else
+ ListPtr->Tail = Old->Prev;
+
+ if( Old->Prev )
+ Old->Prev->Next = Old->Next;
+ else
+ ListPtr->Head = Old->Next;
+
+ --(ListPtr->count);
+ }
+
+ return( Old );
+ } /* ubi_dlRemove */
+
+
+/* ================================ The End ================================= */
diff --git a/source/ubi_dLinkList.h b/source/ubi_dLinkList.h
new file mode 100644
index 00000000000..1facf92d3b1
--- /dev/null
+++ b/source/ubi_dLinkList.h
@@ -0,0 +1,178 @@
+#ifndef ubi_dLinkList_H
+#define ubi_dLinkList_H
+/* ========================================================================== **
+ * ubi_dLinkList.h
+ *
+ * Copyright (C) 1997 by Christopher R. Hertel
+ *
+ * Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ * This module implements simple doubly-linked lists.
+ * -------------------------------------------------------------------------- **
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * Revision 0.3 1997/10/15 03:04:31 crh
+ * Added some handy type casting to the macros. Added AddHere and RemThis
+ * macros.
+ *
+ * Revision 0.2 1997/10/08 03:08:16 crh
+ * Fixed a few forgotten link-ups in Insert(), and fixed the AddHead()
+ * macro, which was passing the wrong value for <After> to Insert().
+ *
+ * Revision 0.1 1997/10/07 04:34:38 crh
+ * Initial Revision.
+ *
+ *
+ * ========================================================================== **
+ */
+
+#include <stdlib.h>
+
+
+/* ========================================================================== **
+ * Typedefs...
+ *
+ * ubi_dlNode - This is the basic node structure.
+ * ubi_dlNodePtr - Pointer to a node.
+ * ubi_dlList - This is the list header structure.
+ * ubi_dlListPtr - Pointer to a List (i.e., a list header structure).
+ *
+ */
+
+typedef struct ubi_dlListNode
+ {
+ struct ubi_dlListNode *Next;
+ struct ubi_dlListNode *Prev;
+ } ubi_dlNode;
+
+typedef ubi_dlNode *ubi_dlNodePtr;
+
+typedef struct
+ {
+ ubi_dlNodePtr Head;
+ ubi_dlNodePtr Tail;
+ unsigned long count;
+ } ubi_dlList;
+
+typedef ubi_dlList *ubi_dlListPtr;
+
+/* ========================================================================== **
+ * Macros...
+ *
+ * ubi_dlAddHead - Add a new node at the head of the list.
+ * ubi_dlAddTail - Add a new node at the tail of the list.
+ * ubi_dlAddHere - Add a node following the given node.
+ * ubi_dlRemHead - Remove the node at the head of the list, if any.
+ * ubi_dlRemTail - Remove the node at the tail of the list, if any.
+ * ubi_dlRemThis - Remove the indicated node.
+ * ubi_dlFirst - Return a pointer to the first node in the list, if any.
+ * ubi_dlLast - Return a pointer to the last node in the list, if any.
+ * ubi_dlNext - Given a node, return a pointer to the next node.
+ * ubi_dlPrev - Given a node, return a pointer to the previous node.
+ *
+ * Note that all of these provide type casting of the parameters. The
+ * Add and Rem macros are nothing more than nice front-ends to the
+ * Insert and Remove operations.
+ *
+ */
+
+#define ubi_dlAddHead( L, N ) \
+ ubi_dlInsert( (ubi_dlListPtr)(L), (ubi_dlNodePtr)(N), NULL )
+
+#define ubi_dlAddTail( L, N ) \
+ ubi_dlInsert( (ubi_dlListPtr)(L), \
+ (ubi_dlNodePtr)(N), \
+ (((ubi_dlListPtr)(L))->Tail) )
+
+#define ubi_dlAddHere( L, N, P ) \
+ ubi_dlInsert( (ubi_dlListPtr)(L), \
+ (ubi_dlNodePtr)(N), \
+ (ubi_dlNodePtr)(P) )
+
+#define ubi_dlRemHead( L ) ubi_dlRemove( (ubi_dlListPtr)(L), \
+ (((ubi_dlListPtr)(L))->Head) )
+
+#define ubi_dlRemTail( L ) ubi_dlRemove( (ubi_dlListPtr)(L), \
+ (((ubi_dlListPtr)(L))->Tail) )
+
+#define ubi_dlRemThis( L, N ) ubi_dlRemove( (ubi_dlListPtr)(L), \
+ (ubi_dlNodePtr)(N) )
+
+#define ubi_dlFirst( L ) (((ubi_dlListPtr)(L))->Head)
+
+#define ubi_dlLast( L ) (((ubi_dlListPtr)(L))->Tail)
+
+#define ubi_dlNext( N ) (((ubi_dlNodePtr)(N))->Next)
+
+#define ubi_dlPrev( N ) (((ubi_dlNodePtr)(N))->Prev)
+
+
+/* ========================================================================== **
+ * Function prototypes...
+ */
+
+ubi_dlListPtr ubi_dlInitList( ubi_dlListPtr ListPtr );
+ /* ------------------------------------------------------------------------ **
+ * Initialize a doubly-linked list header.
+ *
+ * Input: ListPtr - A pointer to the list structure that is to be
+ * initialized for use.
+ *
+ * Output: A pointer to the initialized list header (i.e., same as
+ * <ListPtr>).
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_dlNodePtr ubi_dlInsert( ubi_dlListPtr ListPtr,
+ ubi_dlNodePtr New,
+ ubi_dlNodePtr After );
+ /* ------------------------------------------------------------------------ **
+ * Insert a new node into the list.
+ *
+ * Input: ListPtr - A pointer to the list into which the node is to
+ * be inserted.
+ * New - Pointer to the new node.
+ * After - NULL, or a pointer to a node that is already in the
+ * list.
+ * If NULL, then <New> will be added at the head of the
+ * list, else it will be added following <After>.
+ *
+ * Output: A pointer to the node that was inserted into the list (i.e.,
+ * the same as <New>).
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_dlNodePtr ubi_dlRemove( ubi_dlListPtr ListPtr, ubi_dlNodePtr Old );
+ /* ------------------------------------------------------------------------ **
+ * Remove a node from the list.
+ *
+ * Input: ListPtr - A pointer to the list from which <Old> is to be
+ * removed.
+ * Old - A pointer to the node that is to be removed from the
+ * list.
+ *
+ * Output: A pointer to the node that was removed (i.e., <Old>).
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+
+/* ================================ The End ================================= */
+#endif /* ubi_dLinkList_H */
diff --git a/source/utils/make_printerdef.c b/source/utils/make_printerdef.c
new file mode 100644
index 00000000000..8b49925ad86
--- /dev/null
+++ b/source/utils/make_printerdef.c
@@ -0,0 +1,301 @@
+ /*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Create printer definition files.
+
+ Copyright (C) Jean-Francois.Micouleau@utc.fr, 10/26/97
+
+ 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"
+
+/*
+#define DEBUG
+*/
+char *files_to_copy;
+char *driverfile;
+char buffer[50][255];
+char sub_dir[50][2][255];
+
+void usage(char *name)
+{
+ fprintf(stderr,"%s: printer.def \"Printer Name\"\n", name);
+}
+
+/*
+ This function split a line in two parts
+ on both side of the equal sign
+ "entry=value"
+*/
+char *scan(char *chaine,char **entry)
+{
+ char *value;
+ char *temp;
+ int i=0;
+
+ *entry=(char *)malloc(255*sizeof(char));
+ value=(char *)malloc(255*sizeof(char));
+ strcpy(*entry,chaine);
+ temp=chaine;
+ while( temp[i]!='=' && temp[i]!='\0') {
+ i++;
+ }
+ (*entry)[i]='\0';
+ strcpy(value,temp+i+1);
+ return (value);
+}
+
+void build_subdir()
+{
+ int i=0;
+ char *entry;
+ char *data;
+
+ while (*buffer[i]!='\0') {
+ data=scan(buffer[i],&entry);
+#ifdef DEBUG
+ fprintf(stderr,"\tentry=data %s:%s\n",entry,data);
+#endif
+
+ if (strcmp(data,"11")==0) {
+ strcpy(sub_dir[i][0],entry);
+ strcpy(sub_dir[i][1],"");
+ }
+ if (strcmp(data,"23")==0) {
+ strcpy(sub_dir[i][0],entry);
+ strcpy(sub_dir[i][1],"color\\");
+ }
+#ifdef DEBUG
+ fprintf(stderr,"\tsubdir %s:%s\n",sub_dir[i][0],sub_dir[i][1]);
+#endif
+ i++;
+ }
+}
+
+/*
+ Lockup an entry in a file
+ Return all the lines between the entry and the next one or the end of file
+ An entry is something between braces.
+*/
+void lookup_entry(FILE *fichier,char *chaine)
+{
+ int found=0,pointeur=0,i=0;
+ char *temp,*temp2;
+
+ temp=(char *)malloc(255*sizeof(char));
+ temp2=(char *)malloc(255*sizeof(char));
+
+ *buffer[0]='\0';
+
+ strcpy(temp2,"[");
+ strcat(temp2,chaine);
+ strcat(temp2,"]");
+
+ rewind(fichier);
+#ifdef DEBUG
+ fprintf(stderr,"\tLooking for %s\n",chaine);
+#endif
+
+ while (!feof(fichier) && found==0) {
+ *temp='\0';
+ fgets(temp,255,fichier);
+ if (strncmp(temp,temp2,strlen(temp2))==0) found=1;
+ }
+
+
+ while (!feof(fichier) && found==1) {
+ *temp='\0';
+ fgets(temp,255,fichier);
+ if (*temp=='[') {
+ found=2;
+ *buffer[pointeur]='\0';
+ }
+ else {
+ strcpy(buffer[pointeur],temp);
+ i=strlen(buffer[pointeur])-1;
+ while (buffer[pointeur][i]=='\r' || buffer[pointeur][i]=='\n')
+ buffer[pointeur][i--]='\0';
+ pointeur++;
+ }
+ }
+#ifdef DEBUG
+ fprintf(stderr,"\t\tFound %d entries\n",pointeur-1);
+#endif
+}
+
+
+
+char *find_desc(FILE *fichier,char *text)
+{
+ char *chaine;
+ char *long_desc;
+ char *short_desc;
+ char *crap;
+ char *p;
+
+ int found=0;
+
+ chaine=(char *)malloc(255*sizeof(char));
+ long_desc=(char *)malloc(40*sizeof(char));
+ short_desc=(char *)malloc(13*sizeof(char));
+
+ while (!feof(fichier) && found==0)
+ {
+ fgets(chaine,255,fichier);
+
+ long_desc=strtok(chaine,"=");
+ crap=strtok(NULL,",");
+
+ p=long_desc;
+ while(*p!='"' && *p!='\0')
+ p++;
+ if (*p=='"' && *(p+1)!='\0') p++;
+ long_desc=p;
+
+ if (*p!='\0')
+ {
+ p++;
+ while(*p!='\"')
+ p++;
+ *p='\0';
+ }
+ if (!strcmp(text,long_desc)) found=1;
+ }
+ free(chaine);
+ while(*crap==' ') crap++;
+ strcpy(short_desc,crap);
+ if (found) return(short_desc);
+ else return(NULL);
+}
+
+void scan_copyfiles(FILE *fichier, char *chaine)
+{
+ char *part;
+ int i;
+ char direc[255];
+#ifdef DEBUG
+ fprintf(stderr,"In scan_copyfiles Lookup up of %s\n",chaine);
+#endif
+ part=strtok(chaine,", ");
+ do {
+ /* If the entry start with a @ then it's a file to copy
+ else it's an entry refering to files to copy
+ the main difference is when it's an entry
+ you can have a directory to append before the file name
+ */
+ if (*part=='@') {
+ strcpy(files_to_copy,", ");
+ strcpy(files_to_copy,part);
+ } else {
+ lookup_entry(fichier,part);
+ i=0;
+ strcpy(direc,"");
+ while (*sub_dir[i][0]!='\0') {
+#ifdef DEBUG
+ fprintf(stderr,"\tsubdir %s:%s\n",sub_dir[i][0],sub_dir[i][1]);
+#endif
+ if (strcmp(sub_dir[i][0],part)==0)
+ strcpy(direc,sub_dir[i][1]);
+ i++;
+ }
+ i=0;
+ while (*buffer[i]!='\0') {
+ strcat(files_to_copy,", ");
+ strcat(files_to_copy,direc);
+ strcat(files_to_copy,buffer[i]);
+ i++;
+ }
+ }
+ part=strtok(NULL,", ");
+ }
+ while (part!=NULL);
+}
+
+
+void scan_short_desc(FILE *fichier, char *short_desc)
+{
+ int i=0;
+ char *chaine;
+ char *temp;
+ char *copyfiles=0,*datasection=0,*datafile=0,*helpfile=0;
+
+ chaine=(char *)malloc(255*sizeof(char));
+ temp=(char *)malloc(255*sizeof(char));
+
+ driverfile=short_desc;
+
+ lookup_entry(fichier,short_desc);
+
+ while(*buffer[i]!='\0') {
+#ifdef DEBUG
+ fprintf(stderr,"\tLookup up of %s\n",buffer[i]);
+#endif
+ if (strncmp(buffer[i],"CopyFiles",9)==0) copyfiles=scan(buffer[i],&temp);
+ if (strncmp(buffer[i],"DataSection",11)==0) datasection=scan(buffer[i],&temp);
+ if (strncmp(buffer[i],"DataFile",8)==0) datafile=scan(buffer[i],&temp);
+ if (strncmp(buffer[i],"DriverFile",10)==0) driverfile=scan(buffer[i],&temp);
+ if (strncmp(buffer[i],"HelpFile",8)==0) helpfile=scan(buffer[i],&temp);
+ i++;
+ }
+ if (i) fprintf(stderr,"End of section found\n");
+
+ fprintf(stderr,"CopyFiles: %s\n",copyfiles);
+ fprintf(stderr,"Datasection: %s\n",datasection);
+ fprintf(stderr,"Datafile: %s\n",datafile);
+ fprintf(stderr,"Driverfile: %s\n",driverfile);
+ fprintf(stderr,"Helpfile: %s\n",helpfile);
+ if (copyfiles) scan_copyfiles(fichier,copyfiles);
+/* if (datasection) scan_copyfiles(fichier,datasection);*/
+ if (datafile) scan_copyfiles(fichier,datafile);
+ if (helpfile) scan_copyfiles(fichier,helpfile);
+}
+
+int main(int argc, char *argv[])
+{
+ char *short_desc;
+ FILE *inf_file;
+
+ if (argc!=3)
+ {
+ usage(argv[0]);
+ return(-1);
+ }
+
+ inf_file=fopen(argv[1],"r");
+ if (!inf_file)
+ {
+ fprintf(stderr,"Description file not found, bye\n");
+ return(-1);
+ }
+
+ short_desc=find_desc(inf_file,argv[2]);
+ if (short_desc==NULL)
+ {
+ fprintf(stderr,"Printer not found\n");
+ return(-1);
+ }
+ else fprintf(stderr,"Found:%s\n",short_desc);
+
+ lookup_entry(inf_file,"DestinationDirs");
+ build_subdir();
+
+ files_to_copy=(char *)malloc(2048*sizeof(char));
+ scan_short_desc(inf_file,short_desc);
+ fprintf(stdout,"%s:%s:%s:",argv[2],short_desc,driverfile);
+ fprintf(stdout,"%s\n",files_to_copy);
+ return 0;
+}
+
diff --git a/source/utils/make_smbcodepage.c b/source/utils/make_smbcodepage.c
new file mode 100644
index 00000000000..b4cb1523349
--- /dev/null
+++ b/source/utils/make_smbcodepage.c
@@ -0,0 +1,472 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Create codepage files from codepage_def.XXX files.
+
+ Copyright (C) Jeremy Allison 1997
+
+ 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"
+
+static char *prog_name = NULL;
+
+/*
+ * Print program usage and die.
+ */
+
+void codepage_usage(char *progname)
+{
+ fprintf(stderr, "Usage is : %s [c|d] <codepage> <inputfile> <outputfile>\n",
+ progname);
+ exit(1);
+}
+
+/*
+ * Read a line from a buffer into a line buffer. Ensure null
+ * terminated.
+ */
+
+void read_line( char **buf, char *line_buf, int size)
+{
+ char *p = *buf;
+ int num = 0;
+
+ for(; *p && (*p != '\n'); p++)
+ {
+ if(num < (size - 1))
+ line_buf[num++] = *p;
+ }
+ if(*p)
+ p++; /* Go past the '\n' */
+ line_buf[num] = '\0';
+ *buf = p;
+}
+
+/*
+ * Strip comment lines and blank lines from the data.
+ * Copies into a new buffer and frees the old.
+ * Returns the number of lines copied.
+ */
+
+int clean_data( char **buf, uint32 *size)
+{
+ char linebuf[512];
+ char *p = *buf;
+ int num_lines = 0;
+ char *newbuf = (char *)malloc( *size + 1);
+ char *newbuf_p = NULL;
+
+ if(newbuf == NULL)
+ {
+ fprintf(stderr, "%s: malloc fail for size %d.\n", prog_name, *size + 1);
+ exit(1);
+ }
+
+ newbuf_p = newbuf;
+ *newbuf_p = '\0';
+
+ while( *p )
+ {
+ char *cp;
+
+ read_line( &p, linebuf, sizeof(linebuf));
+ /* Null terminate after comment. */
+ if((cp = strchr( linebuf, '#'))!= NULL)
+ *cp = '\0';
+
+ for(cp = linebuf;*cp && isspace(*cp); cp++)
+ ;
+
+ if(*cp == '\0')
+ continue;
+
+ strcpy(newbuf_p, cp);
+ num_lines++;
+ newbuf_p += (strlen(newbuf_p) + 1);
+ }
+
+ free(*buf);
+ *buf = newbuf;
+ return num_lines;
+}
+
+/*
+ * Parse a byte from a codepage file.
+ */
+
+BOOL parse_byte(char *buf, unsigned char *bp)
+{
+ unsigned int b;
+ char *endptr = NULL;
+
+ b = (unsigned int)strtol(buf, &endptr, 0);
+ if(endptr == buf || b > 255)
+ return False;
+
+ *bp = (unsigned char)b;
+ return True;
+}
+
+/*
+ * Parse a bool from a codepage file.
+ */
+
+BOOL parse_bool(char *buf, unsigned char *bp)
+{
+ if(isdigit(*buf))
+ {
+ char *endptr = NULL;
+
+ *bp = (unsigned char)strtol(buf, &endptr, 0);
+ if(endptr == buf )
+ return False;
+ if(*bp != 0)
+ *bp = 1;
+ } else {
+ if(strcasecmp(buf, "True") && strcasecmp(buf, "False"))
+ return False;
+ if(strcasecmp(buf, "True")==0)
+ *bp = 1;
+ else
+ *bp = 0;
+ }
+ return True;
+}
+
+/*
+ * Print a parse error and exit.
+ */
+
+void parse_error(char *buf, char *msg)
+{
+ fprintf(stderr, "%s: %s whilst parsing line \n%s\n", prog_name,
+ msg, buf);
+ exit(1);
+}
+
+/*
+ * Create a compiled codepage file from a codepage definition file.
+ */
+
+int do_compile(int codepage, char *input_file, char *output_file)
+{
+ FILE *fp = NULL;
+ uint32 size = 0;
+ char *buf = NULL;
+ char output_buf[CODEPAGE_HEADER_SIZE + 512];
+ int num_lines = 0;
+ int i = 0;
+ struct stat st;
+
+ /* Get the size of the input file. Read the entire thing into memory. */
+ if(stat((char *)input_file, &st)!= 0)
+ {
+ fprintf(stderr, "%s: failed to get the file size for file %s. Error was %s\n",
+ prog_name, input_file, strerror(errno));
+ exit(1);
+ }
+
+ size = (uint32)st.st_size;
+
+ /* I don't believe these things should be bigger than 100k :-) */
+ if(size > 100*1024)
+ {
+ fprintf(stderr, "%s: filesize %d is too large for a codepage definition file. \
+The maximum size I will believe is 100k.\n", prog_name, size);
+ exit(1);
+ }
+
+ if((fp = fopen(input_file, "r")) == NULL)
+ {
+ fprintf(stderr, "%s: cannot open file %s for input.\n", prog_name, input_file);
+ exit(1);
+ }
+
+ /* As we will be reading text, allocate one more byte for a '\0' */
+ if((buf = (char *)malloc( size + 1 )) == NULL)
+ {
+ fprintf(stderr, "%s: malloc fail for size %d.\n", prog_name, size + 1);
+ fclose(fp);
+ exit(1);
+ }
+
+ if(fread( buf, 1, size, fp) != size)
+ {
+ fprintf(stderr, "%s: read failed for file %s. Error was %s.\n", prog_name,
+ input_file, strerror(errno));
+ free((char *)buf);
+ fclose(fp);
+ exit(1);
+ }
+
+ /* Null terminate the text read. */
+ buf[size] = '\0';
+
+ /* Go through the data line by line, strip out comments (anything
+ after a '#' to end-of-line) and blank lines. The rest should be
+ the codepage data.
+ */
+
+ num_lines = clean_data( &buf, &size);
+
+ /* There can be a maximum of 128 lines. */
+ if(num_lines > 128)
+ {
+ fprintf(stderr, "%s: There can be a maximum 128 lines of data in a codepage \
+definition file. File %s has %d.\n", prog_name, input_file, num_lines);
+ exit(1);
+ }
+
+ /* Setup the output file header. */
+ SSVAL(output_buf,CODEPAGE_VERSION_OFFSET,CODEPAGE_FILE_VERSION_ID);
+ SSVAL(output_buf,CODEPAGE_CLIENT_CODEPAGE_OFFSET,(uint16)codepage);
+ SIVAL(output_buf,CODEPAGE_LENGTH_OFFSET,(num_lines * 4));
+
+ /* Now convert the lines into the compiled form. */
+ for(i = 0; i < num_lines; i++)
+ {
+ char token_buf[512];
+ char *p = buf;
+ unsigned char b = 0;
+
+ /* Get the 'lower' value. */
+ if(!next_token(&p, token_buf, NULL))
+ parse_error(buf, "cannot parse first value");
+ if(!parse_byte( token_buf, &b))
+ parse_error(buf, "first value doesn't resolve to a byte");
+
+ /* Add this to the output buffer. */
+ SCVAL(output_buf,CODEPAGE_HEADER_SIZE+(i*4),b);
+
+ /* Get the 'upper' value. */
+ if(!next_token(&p, token_buf, NULL))
+ parse_error(buf, "cannot parse second value");
+ if(!parse_byte( token_buf, &b))
+ parse_error(buf, "second value doesn't resolve to a byte");
+
+ /* Add this to the output buffer. */
+ SCVAL(output_buf,CODEPAGE_HEADER_SIZE+(i*4) + 1,b);
+
+ /* Get the 'upper to lower' value. */
+ if(!next_token(&p, token_buf, NULL))
+ parse_error(buf, "cannot parse third value");
+ if(!parse_bool( token_buf, &b))
+ parse_error(buf, "third value doesn't resolve to a boolean");
+
+ /* Add this to the output buffer. */
+ SCVAL(output_buf,CODEPAGE_HEADER_SIZE+(i*4) + 2,b);
+
+ /* Get the 'lower to upper' value. */
+ if(!next_token(&p, token_buf, NULL))
+ parse_error(buf, "cannot parse fourth value");
+ if(!parse_bool( token_buf, &b))
+ parse_error(buf, "fourth value doesn't resolve to a boolean");
+
+ /* Add this to the output buffer. */
+ SCVAL(output_buf,CODEPAGE_HEADER_SIZE+(i*4) + 3,b);
+
+ buf += (strlen(buf) + 1);
+ }
+
+ /* Now write out the output_buf. */
+ if((fp = fopen(output_file, "w"))==NULL)
+ {
+ fprintf(stderr, "%s: Cannot open output file %s. Error was %s.\n",
+ prog_name, output_file, strerror(errno));
+ exit(1);
+ }
+
+ if(fwrite(output_buf, 1, CODEPAGE_HEADER_SIZE + (num_lines*4), fp) !=
+ CODEPAGE_HEADER_SIZE + (num_lines*4))
+ {
+ fprintf(stderr, "%s: Cannot write output file %s. Error was %s.\n",
+ prog_name, output_file, strerror(errno));
+ exit(1);
+ }
+
+ fclose(fp);
+
+ return 0;
+}
+
+/*
+ * Placeholder for now.
+ */
+
+int do_decompile( int codepage, char *input_file, char *output_file)
+{
+ uint32 size = 0;
+ struct stat st;
+ char header_buf[CODEPAGE_HEADER_SIZE];
+ char *buf = NULL;
+ FILE *fp = NULL;
+ int num_lines = 0;
+ int i = 0;
+
+ /* Get the size of the input file. Read the entire thing into memory. */
+ if(stat((char *)input_file, &st)!= 0)
+ {
+ fprintf(stderr, "%s: failed to get the file size for file %s. Error was %s\n",
+ prog_name, input_file, strerror(errno));
+ exit(1);
+ }
+
+ size = (uint32)st.st_size;
+
+ if( size < CODEPAGE_HEADER_SIZE || size > (CODEPAGE_HEADER_SIZE + 256))
+ {
+ fprintf(stderr, "%s: file %s is an incorrect size for a \
+code page file.\n", prog_name, input_file);
+ exit(1);
+ }
+
+ /* Read the first 8 bytes of the codepage file - check
+ the version number and code page number. All the data
+ is held in little endian format.
+ */
+
+ if((fp = fopen( input_file, "r")) == NULL)
+ {
+ fprintf(stderr, "%s: cannot open file %s. Error was %s\n",
+ prog_name, input_file, strerror(errno));
+ exit(1);
+ }
+
+ if(fread( header_buf, 1, CODEPAGE_HEADER_SIZE, fp)!=CODEPAGE_HEADER_SIZE)
+ {
+ fprintf(stderr, "%s: cannot read header from file %s. Error was %s\n",
+ prog_name, input_file, strerror(errno));
+ exit(1);
+ }
+
+ /* Check the version value */
+ if(SVAL(header_buf,CODEPAGE_VERSION_OFFSET) != CODEPAGE_FILE_VERSION_ID)
+ {
+ fprintf(stderr, "%s: filename %s has incorrect version id. \
+Needed %hu, got %hu.\n",
+ prog_name, input_file, (uint16)CODEPAGE_FILE_VERSION_ID,
+ SVAL(header_buf,CODEPAGE_VERSION_OFFSET));
+ exit(1);
+ }
+
+ /* Check the codepage matches */
+ if(SVAL(header_buf,CODEPAGE_CLIENT_CODEPAGE_OFFSET) != (uint16)codepage)
+ {
+ fprintf(stderr, "%s: filename %s has incorrect codepage. \
+Needed %hu, got %hu.\n",
+ prog_name, input_file, (uint16)codepage,
+ SVAL(header_buf,CODEPAGE_CLIENT_CODEPAGE_OFFSET));
+ exit(1);
+ }
+
+ /* Check the length is correct. */
+ if(IVAL(header_buf,CODEPAGE_LENGTH_OFFSET) !=
+ (unsigned int)(size - CODEPAGE_HEADER_SIZE))
+ {
+ fprintf(stderr, "%s: filename %s has incorrect size headers. \
+Needed %u, got %u.\n", prog_name, input_file, size - CODEPAGE_HEADER_SIZE,
+ IVAL(header_buf,CODEPAGE_LENGTH_OFFSET));
+ exit(1);
+ }
+
+ size -= CODEPAGE_HEADER_SIZE; /* Remove header */
+
+ /* Make sure the size is a multiple of 4. */
+ if((size % 4 ) != 0)
+ {
+ fprintf(stderr, "%s: filename %s has a codepage size not a \
+multiple of 4.\n", prog_name, input_file);
+ exit(1);
+ }
+
+ /* Allocate space for the code page file and read it all in. */
+ if((buf = (char *)malloc( size )) == NULL)
+ {
+ fprintf (stderr, "%s: malloc fail for size %d.\n",
+ prog_name, size );
+ exit(1);
+ }
+
+ if(fread( buf, 1, size, fp)!=size)
+ {
+ fprintf(stderr, "%s: read fail on file %s. Error was %s.\n",
+ prog_name, input_file, strerror(errno));
+ exit(1);
+ }
+
+ fclose(fp);
+
+ /* Now dump the codepage into an ascii file. */
+ if((fp = fopen(output_file, "w")) == NULL)
+ {
+ fprintf(stderr, "%s: cannot open file %s. Error was %s\n",
+ prog_name, output_file, strerror(errno));
+ exit(1);
+ }
+
+ fprintf(fp, "#\n# Codepage definition file for IBM Code Page %d.\n#\n",
+ codepage);
+ fprintf(fp, "# This file was automatically generated.\n#\n");
+ fprintf(fp, "# defines lower->upper mapping.\n");
+ fprintf(fp, "#\n#The columns are :\n# lower\tupper\tu-t-l\tl-t-u\n#\n");
+
+ num_lines = size / 4;
+ for( i = 0; i < num_lines; i++)
+ {
+ fprintf(fp, "0x%02X\t0x%02X\t%s\t%s\n", CVAL(buf, (i*4)), CVAL(buf, (i*4)+1),
+ CVAL(buf, (i*4)+2) ? "True" : "False",
+ CVAL(buf, (i*4)+3) ? "True" : "False");
+ }
+ fclose(fp);
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int codepage = 0;
+ char *input_file = NULL;
+ char *output_file = NULL;
+ BOOL compile = False;
+
+ prog_name = argv[0];
+
+ if(argc != 5)
+ codepage_usage(prog_name);
+
+ if(argv[1][0] != 'c' && argv[1][0] != 'C' && argv[1][0] != 'd' &&
+ argv[1][0] != 'D')
+ codepage_usage(prog_name);
+
+ input_file = argv[3];
+ output_file = argv[4];
+
+ /* Are we compiling or decompiling. */
+ if(argv[1][0] == 'c' || argv[1][0] == 'C')
+ compile = True;
+
+ /* Convert the second argument into a client codepage value. */
+ if((codepage = atoi(argv[2])) == 0)
+ {
+ fprintf(stderr, "%s: %s is not a valid codepage.\n", prog_name, argv[2]);
+ exit(1);
+ }
+
+ if(compile)
+ return do_compile( codepage, input_file, output_file);
+ else
+ return do_decompile( codepage, input_file, output_file);
+}
diff --git a/source/utils/nmblookup.c b/source/utils/nmblookup.c
index aa431733322..a44dad511e2 100644
--- a/source/utils/nmblookup.c
+++ b/source/utils/nmblookup.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
NBT client - used to lookup netbios names
- Copyright (C) Andrew Tridgell 1994-1995
+ Copyright (C) Andrew Tridgell 1994-1997
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
@@ -25,34 +25,27 @@
#endif
#include "includes.h"
-#include "nameserv.h"
extern int DEBUGLEVEL;
extern pstring scope;
-extern struct in_addr bcast_ip;
extern pstring myhostname;
-
-static BOOL got_bcast = False;
+extern struct in_addr ipzero;
int ServerFD= -1;
+int RootPort = 0;
+
/****************************************************************************
open the socket communication
**************************************************************************/
static BOOL open_sockets(void)
{
- struct hostent *hp;
-
- /* get host info */
- if ((hp = Get_Hostbyname(myhostname)) == 0)
- {
- DEBUG(0,( "Get_Hostbyname: Unknown host. %s\n",myhostname));
- return False;
- }
-
- ServerFD = open_socket_in(SOCK_DGRAM, 0,3);
+ ServerFD = open_socket_in( SOCK_DGRAM,
+ (RootPort ? 137 :0),
+ 3,
+ interpret_addr(lp_socket_address()) );
if (ServerFD == -1)
return(False);
@@ -69,24 +62,9 @@ static BOOL open_sockets(void)
****************************************************************************/
static BOOL init_structs(void )
{
- struct in_addr myip;
-
- if (!get_myname(myhostname,&myip))
+ if (!get_myname(myhostname,NULL))
return(False);
- /* Read the broadcast address from the interface */
- {
- struct in_addr ip0,ip2;
-
- ip0 = myip;
-
- if (!got_bcast) {
- get_broadcast(&ip0,&bcast_ip,&ip2);
-
- DEBUG(2,("Using broadcast %s\n",inet_ntoa(bcast_ip)));
- }
- }
-
return True;
}
@@ -101,6 +79,8 @@ static void usage(void)
printf("\t-B broadcast address the address to use for broadcasts\n");
printf("\t-M searches for a master browser\n");
printf("\t-S lookup node status as well\n");
+ printf("\t-r Use root port 137 (Win95 only replies to this)\n");
+ printf("\t-A Do a node status on <name> as an IP Address\n");
printf("\n");
}
@@ -111,13 +91,18 @@ static void usage(void)
int main(int argc,char *argv[])
{
int opt;
- unsigned int lookup_type = 0x20;
+ unsigned int lookup_type = 0x0;
pstring lookup;
extern int optind;
extern char *optarg;
BOOL find_master=False;
BOOL find_status=False;
int i;
+ static pstring servicesf = CONFIGFILE;
+ struct in_addr bcast_addr;
+ BOOL use_bcast = True;
+ BOOL got_bcast = False;
+ BOOL lookup_by_ip = False;
DEBUGLEVEL = 1;
*lookup = 0;
@@ -128,18 +113,23 @@ int main(int argc,char *argv[])
charset_initialise();
- while ((opt = getopt(argc, argv, "p:d:B:i:SMh")) != EOF)
+ while ((opt = getopt(argc, argv, "d:B:U:i:s:SMrhA")) != EOF)
switch (opt)
{
case 'B':
- {
- unsigned long a = interpret_addr(optarg);
- putip((char *)&bcast_ip,(char *)&a);
- got_bcast = True;
- }
+ iface_set_default(NULL,optarg,NULL);
+ bcast_addr = *interpret_addr2(optarg);
+ got_bcast = True;
+ use_bcast = True;
+ break;
+ case 'U':
+ iface_set_default(NULL,optarg,NULL);
+ bcast_addr = *interpret_addr2(optarg);
+ got_bcast = True;
+ use_bcast = False;
break;
case 'i':
- strcpy(scope,optarg);
+ fstrcpy(scope,optarg);
strupper(scope);
break;
case 'M':
@@ -151,10 +141,19 @@ int main(int argc,char *argv[])
case 'd':
DEBUGLEVEL = atoi(optarg);
break;
+ case 's':
+ pstrcpy(servicesf, optarg);
+ break;
+ case 'r':
+ RootPort = -1;
+ break;
case 'h':
usage();
exit(0);
break;
+ case 'A':
+ lookup_by_ip = True;
+ break;
default:
usage();
exit(1);
@@ -165,20 +164,37 @@ int main(int argc,char *argv[])
exit(1);
}
+ if (!lp_load(servicesf,True)) {
+ fprintf(stderr, "Can't load %s - run testparm to debug it\n", servicesf);
+ }
+
+ load_interfaces();
init_structs();
if (!open_sockets()) return(1);
- DEBUG(1,("Sending queries to %s\n",inet_ntoa(bcast_ip)));
+ if (!got_bcast)
+ bcast_addr = *iface_bcast(ipzero);
+
+ DEBUG(1,("Sending queries to %s\n",inet_ntoa(bcast_addr)));
for (i=optind;i<argc;i++)
- {
- BOOL bcast = True;
+ {
int retries = 2;
char *p;
struct in_addr ip;
- strcpy(lookup,argv[i]);
+ fstrcpy(lookup,argv[i]);
+
+ if(lookup_by_ip)
+ {
+ strcpy(lookup,"*");
+ ip = *interpret_addr2(argv[i]);
+ printf("Looking up status of %s\n",inet_ntoa(ip));
+ name_status(ServerFD,lookup,lookup_type,True,ip,NULL,NULL,NULL);
+ printf("\n");
+ continue;
+ }
if (find_master) {
if (*lookup == '-') {
@@ -194,24 +210,29 @@ int main(int argc,char *argv[])
if (p) {
*p = 0;
sscanf(p+1,"%x",&lookup_type);
- bcast = False;
retries = 1;
}
- if (name_query(ServerFD,lookup,lookup_type,bcast,True,
- bcast_ip,&ip,NULL))
+ if (name_query(ServerFD,lookup,lookup_type,use_bcast,True,
+ bcast_addr,&ip,NULL))
+ {
+ printf("%s %s\n",inet_ntoa(ip),lookup);
+
+ /* We can only do find_status if the ip address returned
+ was valid - ie. name_query returned true.
+ */
+ if (find_status)
{
- printf("%s %s\n",inet_ntoa(ip),lookup);
- if (find_status)
- {
printf("Looking up status of %s\n",inet_ntoa(ip));
name_status(ServerFD,lookup,lookup_type,True,ip,NULL,NULL,NULL);
printf("\n");
- }
- } else {
- printf("couldn't find name %s\n",lookup);
+ }
}
- }
+ else
+ {
+ printf("name_query failed to find name %s\n", lookup);
+ }
+ }
return(0);
}
diff --git a/source/utils/smbpasswd.c b/source/utils/smbpasswd.c
index 167eb2ed5f3..cba7754fc93 100644
--- a/source/utils/smbpasswd.c
+++ b/source/utils/smbpasswd.c
@@ -1,8 +1,6 @@
-#ifdef SMB_PASSWD
-
/*
* Unix SMB/Netbios implementation. Version 1.9. smbpasswd module. Copyright
- * (C) Jeremy Allison 1995.
+ * (C) Jeremy Allison 1995-1997.
*
* 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
@@ -20,7 +18,6 @@
*/
#include "includes.h"
-#include "des.h"
/* Static buffers we will return. */
static struct smb_passwd pw_buf;
@@ -152,8 +149,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 +164,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 +186,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 +198,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);
+ fprintf(stderr, "Usage is : %s [-add] [username] [password]\n", name);
exit(1);
}
-int main(int argc, char **argv)
+ int main(int argc, char **argv)
{
int real_uid;
struct passwd *pwd;
@@ -223,6 +219,8 @@ int main(int argc, char **argv)
FILE *fp;
BOOL valid_old_pwd = False;
BOOL got_valid_nt_entry = False;
+ BOOL add_user = False;
+ int add_pass = 0;
long seekpos;
int pwfd;
char ascii_p16[66];
@@ -232,6 +230,8 @@ int main(int argc, char **argv)
char *pfile = SMB_PASSWD_FILE;
char readbuf[16 * 1024];
+ TimeInit();
+
setup_logging(argv[0],True);
charset_initialise();
@@ -248,20 +248,51 @@ int main(int argc, char **argv)
real_uid = getuid();
/* Deal with usage problems */
- if (real_uid == 0) {
- /* As root we can change anothers password. */
- if (argc != 1 && argc != 2)
+ if (real_uid == 0)
+ {
+ /* As root we can change anothers password and add a user. */
+ if (argc > 4 )
usage(argv[0]);
- } else if (argc != 1)
+ }
+ else if (argc == 2 || argc > 3)
+ {
+ fprintf(stderr, "%s: Only root can set anothers password.\n", argv[0]);
usage(argv[0]);
+ }
-
- if (real_uid == 0 && argc == 2) {
- /* If we are root we can change anothers password. */
- strncpy(user_name, argv[1], sizeof(user_name) - 1);
+ if (real_uid == 0 && (argc > 1))
+ {
+ /* We are root - check if we should add the user */
+ if ((argv[1][0] == '-') && (argv[1][1] == 'a'))
+ add_user = True;
+
+ if(add_user && (argc <= 2 || argc > 4))
+ usage(argv[0]);
+
+ /* root can specify password on command-line */
+ if (argc == (add_user ? 4 : 3))
+ {
+ /* -a argument (add_user): new password is 3rd argument. */
+ /* no -a argument (add_user): new password is 2nd argument */
+
+ add_pass = add_user ? 3 : 2;
+ }
+
+ /* If we are root we can change another's password. */
+ strncpy(user_name, add_user ? argv[2] : argv[1], sizeof(user_name) - 1);
user_name[sizeof(user_name) - 1] = '\0';
+
pwd = getpwnam(user_name);
- } else {
+ }
+ else
+ {
+ /* non-root can specify old pass / new pass on command-line */
+ if (argc == 3)
+ {
+ /* non-root specifies new password as 2nd argument */
+ add_pass = 2;
+ }
+
pwd = getpwuid(real_uid);
}
@@ -269,24 +300,50 @@ int main(int argc, char **argv)
fprintf(stderr, "%s: Unable to get UNIX password entry for user.\n", argv[0]);
exit(1);
}
+
/* If we are root we don't ask for the old password. */
old_passwd[0] = '\0';
- if (real_uid != 0) {
- p = getpass("Old SMB password:");
- strncpy(old_passwd, p, sizeof(fstring));
+ if (real_uid != 0)
+ {
+ if (add_pass)
+ {
+ /* old password, as non-root, is 1st argument */
+ strncpy(old_passwd, argv[1], sizeof(fstring));
+ }
+ else
+ {
+ p = getpass("Old SMB password:");
+ strncpy(old_passwd, p, sizeof(fstring));
+ }
old_passwd[sizeof(fstring)-1] = '\0';
}
- new_passwd[0] = '\0';
- p = getpass("New SMB password:");
- strncpy(new_passwd, p, sizeof(fstring));
- new_passwd[sizeof(fstring)-1] = '\0';
- p = getpass("Retype new SMB password:");
- if (strcmp(p, new_passwd)) {
- fprintf(stderr, "%s: Mismatch - password unchanged.\n", argv[0]);
- exit(1);
+
+ if (add_pass)
+ {
+ /* new password is specified on the command line */
+ strncpy(new_passwd, argv[add_user ? 3 : 2], sizeof(new_passwd) - 1);
+ new_passwd[sizeof(new_passwd) - 1] = '\0';
+ }
+ else
+ {
+ new_passwd[0] = '\0';
+
+ p = getpass("New SMB password:");
+
+ strncpy(new_passwd, p, sizeof(fstring));
+ new_passwd[sizeof(fstring)-1] = '\0';
+
+ p = getpass("Retype new SMB password:");
+
+ if (strncmp(p, new_passwd, sizeof(fstring)-1))
+ {
+ fprintf(stderr, "%s: Mismatch - password unchanged.\n", argv[0]);
+ exit(1);
+ }
}
- if (new_passwd[0] == '\0') {
+ if (new_passwd[0] == '\0')
+ {
printf("Password not set\n");
exit(0);
}
@@ -318,20 +375,30 @@ int main(int argc, char **argv)
* Open the smbpaswd file XXXX - we need to parse smb.conf to get the
* filename
*/
- if ((fp = fopen(pfile, "r+")) == NULL) {
- err = errno;
- fprintf(stderr, "%s: Failed to open password file %s.\n",
- argv[0], pfile);
- errno = err;
- perror(argv[0]);
- exit(err);
+ fp = fopen(pfile, "r+");
+ if (!fp && errno == ENOENT) {
+ fp = fopen(pfile, "w");
+ if (fp) {
+ fprintf(fp, "# Samba SMB password file\n");
+ fclose(fp);
+ fp = fopen(pfile, "r+");
+ }
}
+ if (!fp) {
+ err = errno;
+ fprintf(stderr, "%s: Failed to open password file %s.\n",
+ argv[0], pfile);
+ errno = err;
+ perror(argv[0]);
+ exit(err);
+ }
+
/* Set read buffer to 16k for effiecient reads */
setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf));
/* make sure it is only rw by the owner */
chmod(pfile, 0600);
-
+
/* Lock the smbpasswd file for write. */
if ((lockfd = pw_file_lock(pfile, F_WRLCK, 5)) < 0) {
err = errno;
@@ -346,26 +413,95 @@ int main(int argc, char **argv)
smb_pwent = _my_get_smbpwnam(fp, pwd->pw_name, &valid_old_pwd,
&got_valid_nt_entry, &seekpos);
if (smb_pwent == NULL) {
- fprintf(stderr, "%s: Failed to find entry for user %s in file %s.\n",
- argv[0], pwd->pw_name, pfile);
- fclose(fp);
- pw_file_unlock(lockfd);
- exit(1);
- }
- /* If we are root we don't need to check the old password. */
- if (real_uid != 0) {
- if ((valid_old_pwd == False) || (smb_pwent->smb_passwd == NULL)) {
- fprintf(stderr, "%s: User %s is disabled, plase contact your administrator to enable it.\n", argv[0], pwd->pw_name);
+ if(add_user == False) {
+ fprintf(stderr, "%s: Failed to find entry for user %s in file %s.\n",
+ argv[0], pwd->pw_name, pfile);
fclose(fp);
pw_file_unlock(lockfd);
exit(1);
}
- /* Check the old Lanman password */
- if (memcmp(old_p16, smb_pwent->smb_passwd, 16)) {
- fprintf(stderr, "%s: Couldn't change password.\n", argv[0]);
- fclose(fp);
- pw_file_unlock(lockfd);
- exit(1);
+
+ /* Create a new smb passwd entry and set it to the given password. */
+ {
+ int fd;
+ int new_entry_length;
+ char *new_entry;
+ long offpos;
+
+ /* The add user write needs to be atomic - so get the fd from
+ the fp and do a raw write() call.
+ */
+ fd = fileno(fp);
+
+ if((offpos = lseek(fd, 0, SEEK_END)) == -1) {
+ fprintf(stderr, "%s: Failed to add entry for user %s to file %s. \
+Error was %s\n", argv[0], pwd->pw_name, pfile, strerror(errno));
+ fclose(fp);
+ pw_file_unlock(lockfd);
+ exit(1);
+ }
+
+ new_entry_length = strlen(pwd->pw_name) + 1 + 15 + 1 +
+ 32 + 1 + 32 + 1 + strlen(pwd->pw_gecos) +
+ 1 + strlen(pwd->pw_dir) + 1 +
+ strlen(pwd->pw_shell) + 1;
+ if((new_entry = (char *)malloc( new_entry_length )) == 0) {
+ fprintf(stderr, "%s: Failed to add entry for user %s to file %s. \
+Error was %s\n", argv[0], pwd->pw_name, pfile, strerror(errno));
+ fclose(fp);
+ pw_file_unlock(lockfd);
+ exit(1);
+ }
+
+ sprintf(new_entry, "%s:%u:", pwd->pw_name, (unsigned)pwd->pw_uid);
+ p = &new_entry[strlen(new_entry)];
+ for( i = 0; i < 16; i++)
+ sprintf(&p[i*2], "%02X", new_p16[i]);
+ p += 32;
+ *p++ = ':';
+ for( i = 0; i < 16; i++)
+ sprintf(&p[i*2], "%02X", new_nt_p16[i]);
+ p += 32;
+ *p++ = ':';
+ sprintf(p, "%s:%s:%s\n", pwd->pw_gecos,
+ pwd->pw_dir, pwd->pw_shell);
+ if(write(fd, new_entry, strlen(new_entry)) != strlen(new_entry)) {
+ fprintf(stderr, "%s: Failed to add entry for user %s to file %s. \
+Error was %s\n", argv[0], pwd->pw_name, pfile, strerror(errno));
+ /* Remove the entry we just wrote. */
+ if(ftruncate(fd, offpos) == -1) {
+ fprintf(stderr, "%s: ERROR failed to ftruncate file %s. \
+Error was %s. Password file may be corrupt ! Please examine by hand !\n",
+ argv[0], pwd->pw_name, strerror(errno));
+ }
+ fclose(fp);
+ pw_file_unlock(lockfd);
+ exit(1);
+ }
+
+ fclose(fp);
+ pw_file_unlock(lockfd);
+ exit(0);
+ }
+ } else {
+ /* the entry already existed */
+ add_user = False;
+ }
+
+ /* If we are root or the password is 'NO PASSWORD' then
+ we don't need to check the old password. */
+ if (real_uid != 0) {
+ if (valid_old_pwd == False) {
+ fprintf(stderr, "%s: User %s has no old SMB password.\n", argv[0], pwd->pw_name);
+ }
+ /* Check the old Lanman password - NULL means 'NO PASSWORD' */
+ if (smb_pwent->smb_passwd != NULL) {
+ if (memcmp(old_p16, smb_pwent->smb_passwd, 16)) {
+ fprintf(stderr, "%s: Couldn't change password.\n", argv[0]);
+ fclose(fp);
+ pw_file_unlock(lockfd);
+ exit(1);
+ }
}
/* Check the NT password if it exists */
if (smb_pwent->smb_nt_passwd != NULL) {
@@ -443,14 +579,3 @@ int main(int argc, char **argv)
return 0;
}
-#else
-
-#include "includes.h"
-
-int
-main(int argc, char **argv)
-{
- printf("smb password encryption not selected in Makefile\n");
- return 0;
-}
-#endif
diff --git a/source/utils/status.c b/source/utils/status.c
index ed0ae532114..1a05f2b1afe 100644
--- a/source/utils/status.c
+++ b/source/utils/status.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
status reporting
- Copyright (C) Andrew Tridgell 1994-1995
+ Copyright (C) Andrew Tridgell 1994-1997
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
@@ -17,6 +17,11 @@
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:
+
+ 12 aug 96: Erik.Devriendt@te6.siemens.be
+ added support for shared memory implementation of share mode locking
*/
/*
@@ -28,35 +33,88 @@
#endif
#include "includes.h"
-#include "loadparm.h"
struct connect_record crec;
+
+struct session_record{
+ int pid;
+ int uid;
+ char machine[31];
+ time_t start;
+ struct session_record *next;
+} *srecs;
+
extern int DEBUGLEVEL;
extern FILE *dbf;
+extern pstring myhostname;
static pstring Ucrit_username = ""; /* added by OH */
int Ucrit_pid[100]; /* Ugly !!! */ /* added by OH */
int Ucrit_MaxPid=0; /* added by OH */
unsigned int Ucrit_IsActive = 0; /* added by OH */
-void Ucrit_addUsername(pstring username); /* added by OH */
-unsigned int Ucrit_checkUsername(pstring username); /* added by OH */
-void Ucrit_addPid(int pid); /* added by OH */
-unsigned int Ucrit_checkPid(int pid); /* added by OH */
-int main(int argc, char *argv[])
+/* we need these because we link to locking*.o */
+ void become_root(BOOL save_dir) {}
+ void unbecome_root(BOOL restore_dir) {}
+connection_struct Connections[MAX_CONNECTIONS];
+files_struct Files[MAX_OPEN_FILES];
+struct current_user current_user;
+
+
+static void print_share_mode(share_mode_entry *e, char *fname)
+{
+ static int count;
+ if (count==0) {
+ printf("Locked files:\n");
+ printf("Pid DenyMode R/W Oplock Name\n");
+ printf("--------------------------------------------------\n");
+ }
+ count++;
+
+ printf("%-5d ",e->pid);
+ switch ((e->share_mode>>4)&0xF) {
+ case DENY_NONE: printf("DENY_NONE "); break;
+ case DENY_ALL: printf("DENY_ALL "); break;
+ case DENY_DOS: printf("DENY_DOS "); break;
+ case DENY_READ: printf("DENY_READ "); break;
+ case DENY_WRITE:printf("DENY_WRITE "); break;
+ }
+ switch (e->share_mode&0xF) {
+ case 0: printf("RDONLY "); break;
+ case 1: printf("WRONLY "); break;
+ case 2: printf("RDWR "); break;
+ }
+
+ if((e->op_type &
+ (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) ==
+ (EXCLUSIVE_OPLOCK|BATCH_OPLOCK))
+ printf("EXCLUSIVE+BATCH ");
+ else if (e->op_type & EXCLUSIVE_OPLOCK)
+ printf("EXCLUSIVE ");
+ else if (e->op_type & BATCH_OPLOCK)
+ printf("BATCH ");
+ else
+ printf("NONE ");
+
+ printf(" %s %s",fname,asctime(LocalTime((time_t *)&e->time.tv_sec)));
+}
+
+
+
+ int main(int argc, char *argv[])
{
FILE *f;
pstring fname;
- int uid, c, n;
+ int uid, c;
static pstring servicesf = CONFIGFILE;
extern char *optarg;
- int verbose = 0;
- void *dir;
- char *s;
- BOOL firstopen=True;
+ int verbose = 0, brief =0;
BOOL processes_only=False;
int last_pid=0;
+ struct session_record *ptr;
+
+ TimeInit();
setup_logging(argv[0],True);
charset_initialise();
@@ -69,8 +127,11 @@ int main(int argc, char *argv[])
return(1);
}
- while ((c = getopt(argc, argv, "pdsu:")) != EOF) {
+ while ((c = getopt(argc, argv, "pds:u:b")) != EOF) {
switch (c) {
+ case 'b':
+ brief = 1;
+ break;
case 'd':
verbose = 1;
break;
@@ -89,7 +150,7 @@ int main(int argc, char *argv[])
}
}
-
+ get_myname(myhostname, NULL);
if (!lp_load(servicesf,False)) {
fprintf(stderr, "Can't load %s - run testparm to debug it\n", servicesf);
@@ -113,14 +174,25 @@ 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();
if (!processes_only) {
printf("\nSamba version %s\n",VERSION);
- printf("Service uid gid pid machine\n");
- printf("----------------------------------------------\n");
+ if (brief)
+ {
+ printf("PID Username Machine Time logged in\n");
+ printf("-------------------------------------------------------------------\n");
+ }
+ else
+ {
+ printf("Service uid gid pid machine\n");
+ printf("----------------------------------------------\n");
+ }
}
while (!feof(f))
@@ -131,94 +203,76 @@ int main(int argc, char *argv[])
&& Ucrit_checkUsername(uidtoname(crec.uid)) /* added by OH */
)
{
- Ucrit_addPid(crec.pid); /* added by OH */
- if (processes_only) {
- if (last_pid != crec.pid)
- printf("%d\n",crec.pid);
- last_pid = crec.pid; /* XXXX we can still get repeats, have to
- add a sort at some time */
- }
- else
- 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)));
+ if (brief)
+ {
+ ptr=srecs;
+ while (ptr!=NULL)
+ {
+ if ((ptr->pid==crec.pid)&&(strncmp(ptr->machine,crec.machine,30)==0))
+ {
+ if (ptr->start > crec.start)
+ ptr->start=crec.start;
+ break;
+ }
+ ptr=ptr->next;
+ }
+ if (ptr==NULL)
+ {
+ ptr=(struct session_record *) malloc(sizeof(struct session_record));
+ ptr->uid=crec.uid;
+ ptr->pid=crec.pid;
+ ptr->start=crec.start;
+ strncpy(ptr->machine,crec.machine,30);
+ ptr->machine[30]='\0';
+ ptr->next=srecs;
+ srecs=ptr;
+ }
+ }
+ else
+ {
+ Ucrit_addPid(crec.pid); /* added by OH */
+ if (processes_only) {
+ if (last_pid != crec.pid)
+ printf("%d\n",crec.pid);
+ last_pid = crec.pid; /* XXXX we can still get repeats, have to
+ add a sort at some time */
+ }
+ else
+ 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)));
+ }
}
}
fclose(f);
if (processes_only) exit(0);
+
+ if (brief)
+ {
+ ptr=srecs;
+ while (ptr!=NULL)
+ {
+ printf("%-8d%-10.10s%-30.30s%s",ptr->pid,uidtoname(ptr->uid),ptr->machine,asctime(LocalTime(&(ptr->start))));
+ ptr=ptr->next;
+ }
+ printf("\n");
+ exit(0);
+ }
printf("\n");
- dir = opendir(lp_lockdir());
- if (!dir) return(0);
- while ((s=readdirname(dir))) {
- char buf[16];
- int pid,mode;
- time_t t;
- int fd;
- pstring lname;
- int dev,inode;
-
- if (sscanf(s,"share.%d.%d",&dev,&inode)!=2) continue;
-
- strcpy(lname,lp_lockdir());
- trim_string(lname,NULL,"/");
- strcat(lname,"/");
- strcat(lname,s);
-
- fd = open(lname,O_RDONLY,0);
- if (fd < 0) continue;
- if (read(fd,buf,16) != 16) continue;
- n = read(fd,fname,sizeof(fname));
- fname[MAX(n,0)]=0;
- close(fd);
-
- t = IVAL(buf,0);
- mode = IVAL(buf,4);
- pid = IVAL(buf,8);
-
- if ( !Ucrit_checkPid(pid) ) /* added by OH */
- continue;
-
- if (IVAL(buf,12) != LOCKING_VERSION || !process_exists(pid)) {
- if (unlink(lname)==0)
- printf("Deleted stale share file %s\n",s);
- continue;
- }
-
- fname[sizeof(fname)-1] = 0;
+ locking_init(1);
- if (firstopen) {
- firstopen=False;
- printf("Locked files:\n");
- printf("Pid DenyMode R/W Name\n");
- printf("------------------------------\n");
- }
+ if (share_mode_forall(print_share_mode) <= 0)
+ printf("No locked files\n");
+ printf("\n");
- printf("%-5d ",pid);
- switch ((mode>>4)&0xF)
- {
- case DENY_NONE: printf("DENY_NONE "); break;
- case DENY_ALL: printf("DENY_ALL "); break;
- case DENY_DOS: printf("DENY_DOS "); break;
- case DENY_READ: printf("DENY_READ "); break;
- case DENY_WRITE:printf("DENY_WRITE "); break;
- }
- switch (mode&0xF)
- {
- case 0: printf("RDONLY "); break;
- case 1: printf("WRONLY "); break;
- case 2: printf("RDWR "); break;
- }
- printf(" %s %s",fname,asctime(LocalTime(&t,GMT_TO_LOCAL)));
- }
- closedir(dir);
+ share_status(stdout);
- if (firstopen)
- printf("No locked files\n");
+ locking_end();
return (0);
}
diff --git a/source/utils/testparm.c b/source/utils/testparm.c
index e1f070a4b83..ca364cb8c94 100644
--- a/source/utils/testparm.c
+++ b/source/utils/testparm.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Test validity of smb.conf
- Copyright (C) Karl Auer 1993, 1994
+ Copyright (C) Karl Auer 1993, 1994-1997
Extensively modified by Andrew Tridgell, 1995
@@ -34,18 +34,18 @@
#include "includes.h"
#include "smb.h"
-#include "params.h"
-#include "loadparm.h"
/* these live in util.c */
extern FILE *dbf;
extern int DEBUGLEVEL;
-int main(int argc, char *argv[])
+ int main(int argc, char *argv[])
{
pstring configfile;
int s;
+ TimeInit();
+
setup_logging(argv[0],True);
charset_initialise();
@@ -82,28 +82,27 @@ int main(int argc, char *argv[])
printf("Press enter to see a dump of your service definitions\n");
fflush(stdout);
getc(stdin);
- lp_dump();
+ lp_dump(stdout);
}
if (argc == 4)
{
- struct from_host f;
- f.name = argv[2];
- f.addr = argv[3];
+ char *cname = argv[2];
+ char *caddr = argv[3];
/* this is totally ugly, a real `quick' hack */
for (s=0;s<1000;s++)
if (VALID_SNUM(s))
{
- if (allow_access(lp_hostsdeny(s),lp_hostsallow(s),&f))
+ if (allow_access(lp_hostsdeny(s),lp_hostsallow(s),cname,caddr))
{
printf("Allow connection from %s (%s) to %s\n",
- f.name,f.addr,lp_servicename(s));
+ cname,caddr,lp_servicename(s));
}
else
{
printf("Deny connection from %s (%s) to %s\n",
- f.name,f.addr,lp_servicename(s));
+ cname,caddr,lp_servicename(s));
}
}
}
diff --git a/source/utils/testprns.c b/source/utils/testprns.c
index 89c615898d7..4a2ddb7c635 100644
--- a/source/utils/testprns.c
+++ b/source/utils/testprns.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
test printer setup
- Copyright (C) Karl Auer 1993, 1994
+ Copyright (C) Karl Auer 1993, 1994-1997
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
@@ -33,7 +33,6 @@
#include "includes.h"
#include "smb.h"
-#include "pcap.h"
/* these live in util.c */
extern FILE *dbf;
@@ -43,6 +42,8 @@ int main(int argc, char *argv[])
{
char *pszTemp;
+ TimeInit();
+
setup_logging(argv[0],True);
charset_initialise();
@@ -52,10 +53,9 @@ int main(int argc, char *argv[])
else
{
dbf = fopen("test.log", "w");
- if (dbf == NULL)
+ if (dbf == NULL) {
printf("Unable to open logfile.\n");
- else
- {
+ } else {
DEBUGLEVEL = 3;
pszTemp = (argc < 3) ? PRINTCAP_NAME : argv[2];
printf("Looking for printer %s in printcap file %s\n",
diff --git a/source/web/cgi.c b/source/web/cgi.c
new file mode 100644
index 00000000000..56c293985d6
--- /dev/null
+++ b/source/web/cgi.c
@@ -0,0 +1,163 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ some simple CGI helper routines
+ Copyright (C) Andrew Tridgell 1997
+
+ 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"
+
+#define MAX_VARIABLES 512
+
+struct var {
+ char *name;
+ char *value;
+};
+
+static struct var variables[MAX_VARIABLES];
+static int num_variables;
+
+
+static int grab_line(int *cl, char *line, int maxsize)
+{
+ int i = 0;
+
+ while ((*cl)) {
+ int c = fgetc(stdin);
+ (*cl)--;
+
+ if (c == EOF) {
+ (*cl) = 0;
+ break;
+ }
+
+ if (c == '+') {
+ c = ' ';
+ }
+
+ if (c == '\r') continue;
+
+ if (strchr("\n&", c)) break;
+
+ if (c == '%' && (*cl) >= 2) {
+ int c1, c2;
+ c1 = fgetc(stdin);
+ c2 = fgetc(stdin);
+ (*cl) -= 2;
+ if (c1 == EOF || c2 == EOF) break;
+ if (c1 >= '0' && c1 <= '9')
+ c1 = c1 - '0';
+ else if (c1 >= 'A' && c1 <= 'F')
+ c1 = 10 + c1 - 'A';
+ else if (c1 >= 'a' && c1 <= 'f')
+ c1 = 10 + c1 - 'a';
+ else break;
+
+ if (c2 >= '0' && c2 <= '9')
+ c2 = c2 - '0';
+ else if (c2 >= 'A' && c2 <= 'F')
+ c2 = 10 + c2 - 'A';
+ else if (c2 >= 'a' && c2 <= 'f')
+ c2 = 10 + c2 - 'a';
+ else break;
+
+ c = (c1<<4) | c2;
+ }
+
+ line[i++] = c;
+
+ if (i == maxsize) break;
+ }
+
+ /* now unescape the line */
+
+
+ line[i] = 0;
+ return 1;
+}
+
+
+/***************************************************************************
+ load all the variables passed to the CGI program
+ ***************************************************************************/
+void cgi_load_variables(void)
+{
+ static pstring line;
+ char *p;
+ int len;
+
+ if (!(p=getenv("CONTENT_LENGTH"))) return;
+
+ len = atoi(p);
+
+ if (len <= 0) return;
+
+
+
+ while (len && grab_line(&len, line, sizeof(line)-1)) {
+ p = strchr(line,'=');
+ if (!p) continue;
+
+ *p = 0;
+
+ variables[num_variables].name = strdup(line);
+ variables[num_variables].value = strdup(p+1);
+
+ if (!variables[num_variables].name ||
+ !variables[num_variables].value)
+ continue;
+
+#if 0
+ printf("%s=%s<br>\n",
+ variables[num_variables].name,
+ variables[num_variables].value);
+#endif
+
+ num_variables++;
+ if (num_variables == MAX_VARIABLES) break;
+ }
+
+ fclose(stdin);
+}
+
+
+/***************************************************************************
+ find a variable passed via CGI
+ ***************************************************************************/
+char *cgi_variable(char *name)
+{
+ int i;
+
+ for (i=0;i<num_variables;i++)
+ if (strcmp(variables[i].name, name) == 0)
+ return variables[i].value;
+ return NULL;
+}
+
+
+/***************************************************************************
+ return the value of a CGI boolean variable.
+ ***************************************************************************/
+int cgi_boolean(char *name, int def)
+{
+ char *p = cgi_variable(name);
+
+ if (!p) return def;
+
+ return strcmp(p, "1") == 0;
+}
diff --git a/source/wsmbconf.c b/source/wsmbconf.c
new file mode 100644
index 00000000000..203952c204f
--- /dev/null
+++ b/source/wsmbconf.c
@@ -0,0 +1,251 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ html smb.conf editing - prototype only
+ Copyright (C) Andrew Tridgell 1997
+
+ 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"
+#include "smb.h"
+
+#define SDEFAULTS "Service defaults"
+#define SGLOBAL "Global Parameters"
+#define GLOBALS_SNUM -2
+#define DEFAULTS_SNUM -1
+
+
+/* start the page with standard stuff */
+static void print_header(void)
+{
+ printf("Content-type: text/html\n\n");
+ printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\">\n");
+ printf("<HTML>\n<HEAD>\n<TITLE>smb.conf</TITLE>\n</HEAD>\n<BODY>\n\n");
+}
+
+
+/* finish off the page */
+static void print_footer(void)
+{
+ printf("\n</BODY>\n</HTML>\n");
+}
+
+/* setup persisant variables */
+static void set_persistent(char *name)
+{
+ char *p;
+ p = cgi_variable(name);
+ if (!p) return;
+ printf("<input type=hidden name=%s value=%s>\n", name, p);
+}
+
+/* display a servce, ready for editing */
+static void show_service(int snum, int allparameters)
+{
+ int i = 0;
+ pstring label, value;
+ char *sname;
+
+ if (snum == GLOBALS_SNUM)
+ sname = SGLOBAL;
+ else if (snum == DEFAULTS_SNUM)
+ sname = SDEFAULTS;
+ else sname = lp_servicename(snum);
+
+ printf("\n<p><table border=0>\n<tr>\n<td></td><td>\n\n");
+ printf("<form method=POST>\n");
+ printf("<H3>%s</H3>\n", sname);
+ printf("<input type=hidden name=service value=\"%s\">\n", sname);
+ printf("<input type=submit name=request value=Change>\n");
+ printf("<input type=submit name=request value=Rename>\n");
+ printf("<input type=submit name=request value=Copy>\n");
+ printf("<input type=submit name=request value=Remove>\n");
+ printf("<br><input name=newvalue><br>\n");
+ printf("<select name=parameter size=5>\n");
+
+ while (lp_next_parameter(snum, &i, label, value, allparameters)) {
+ printf("<option value=\"%s\">%s = %s\n",
+ label, label, value);
+ }
+
+ printf("</select>\n");
+ printf("</form>\n</td>\n</tr>\n</table>\n");
+
+ printf("<p>\n");
+}
+
+
+/* loop over all services, displaying them one after the other */
+static void show_services(void)
+{
+ int i;
+ int n;
+ int allparameters = cgi_boolean("allparameters", 0);
+
+ printf("<FORM METHOD=POST>\n");
+ printf("<p>Show all parameters?\n");
+ printf("<INPUT NAME=allparameters TYPE=checkbox VALUE=1 %s>\n",
+ allparameters?"CHECKED":"");
+
+ printf("<INPUT TYPE=submit NAME=reload VALUE=Reload>\n");
+
+ printf("</FORM>\n");
+
+ n = lp_numservices();
+
+ show_service(GLOBALS_SNUM, allparameters);
+ show_service(DEFAULTS_SNUM, allparameters);
+
+ for (i=0;i<n;i++)
+ if (VALID_SNUM(i))
+ show_service(i, allparameters);
+}
+
+
+/* load the smb.conf file into loadparm. this also does the chroot
+ to the config directory. This must be called _BEFORE_ any client
+ supplied data is parsed */
+static int load_config(void)
+{
+ static pstring servicesf = CONFIGFILE;
+ char *p;
+
+ p = strrchr(servicesf,'/');
+ if (!p) return 0;
+
+ *p = 0;
+
+ setuid(0);
+
+ if (chdir(servicesf) || chroot(servicesf)) {
+ printf("wsmbconf is not configured correctly\n");
+ return 0;
+ }
+
+ *p = '/';
+
+ if (!lp_load(p,False)) {
+ printf("<b>Can't load %s - using defaults</b><p>\n",
+ servicesf);
+ }
+ return 1;
+}
+
+
+static int save_reload(void)
+{
+ static pstring servicesf = CONFIGFILE;
+ char *p;
+ FILE *f;
+
+ p = strrchr(servicesf,'/');
+ if (!p) return 0;
+
+ f = fopen(p,"w");
+ if (!f) {
+ printf("failed to open %s for writing\n", servicesf);
+ return 0;
+ }
+
+ fprintf(f, "# Samba config file created using wsmbconf\n");
+
+ lp_dump(f);
+
+ fclose(f);
+
+ lp_killunused(NULL);
+
+ if (!lp_load(p,False)) {
+ printf("Can't reload %s\n", servicesf);
+ return 0;
+ }
+
+ return 1;
+}
+
+static void process_requests(void)
+{
+ char *req = cgi_variable("request");
+ char *newvalue = cgi_variable("newvalue");
+ char *parameter = cgi_variable("parameter");
+ char *service = cgi_variable("service");
+ int snum=0;
+
+ if (!req) return;
+
+ if (service) {
+ /* work out what service it is */
+ if (strcmp(service,SGLOBAL) == 0) {
+ snum = GLOBALS_SNUM;
+ } else if (strcmp(service,SDEFAULTS) == 0) {
+ snum = DEFAULTS_SNUM;
+ } else {
+ snum = lp_servicenumber(service);
+ if (snum < 0) return;
+ }
+ }
+
+ if (!newvalue)
+ newvalue = "";
+
+ if (strcmp(req,"Change") == 0) {
+ /* change the value of a parameter */
+ if (!parameter || !service) return;
+
+ lp_do_parameter(snum, parameter, newvalue);
+ } else if (strcmp(req,"Rename") == 0) {
+ /* rename a service */
+ if (!newvalue || !service) return;
+
+ lp_rename_service(snum, newvalue);
+ } else if (strcmp(req,"Remove") == 0) {
+ /* remove a service */
+ if (!service) return;
+
+ lp_remove_service(snum);
+ } else if (strcmp(req,"Copy") == 0) {
+ /* copy a service */
+ if (!service || !newvalue) return;
+
+ lp_copy_service(snum, newvalue);
+ }
+
+ save_reload();
+}
+
+
+int main(int argc, char *argv[])
+{
+ extern FILE *dbf;
+
+ print_header();
+
+ dbf = stderr;
+
+ charset_initialise();
+
+ if (load_config()) {
+ cgi_load_variables();
+ process_requests();
+ show_services();
+ }
+ print_footer();
+ return 0;
+}
diff --git a/source/wsmbstatus.c b/source/wsmbstatus.c
new file mode 100644
index 00000000000..2762b8610e7
--- /dev/null
+++ b/source/wsmbstatus.c
@@ -0,0 +1,87 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ html status reporting
+ Copyright (C) Andrew Tridgell 1997
+
+ 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"
+
+static void print_header(void)
+{
+ printf("Content-type: text/html\n\n");
+ printf("<HTML>\n<HEAD>\n<TITLE>smbstatus</TITLE>\n</HEAD>\n<BODY>\n\n");
+}
+
+static void print_footer(void)
+{
+ printf("\n</BODY>\n</HTML>\n");
+}
+
+static void show_connections(void)
+{
+ static pstring servicesf = CONFIGFILE;
+ pstring fname;
+ FILE *f;
+ struct connect_record crec;
+
+ if (!lp_load(servicesf,False)) {
+ printf("Can't load %s - run testparm to debug it\n", servicesf);
+ return;
+ }
+
+ strcpy(fname,lp_lockdir());
+ standard_sub_basic(fname);
+ trim_string(fname,"","/");
+ strcat(fname,"/STATUS..LCK");
+
+ f = fopen(fname,"r");
+ if (!f) {
+ printf("Couldn't open status file %s\n",fname);
+ if (!lp_status(-1))
+ printf("You need to have status=yes in your smb config file\n");
+ return;
+ }
+
+
+ printf("\nSamba version %s\n<p>",VERSION);
+
+ while (!feof(f)) {
+ if (fread(&crec,sizeof(crec),1,f) != 1)
+ break;
+ if (crec.magic == 0x280267 && process_exists(crec.pid)) {
+ printf("%-10.10s %-8s %-8s %5d %-8s (%s) %s<br>",
+ crec.name,uidtoname(crec.uid),
+ gidtoname(crec.gid),crec.pid,
+ crec.machine,crec.addr,
+ asctime(LocalTime(&crec.start)));
+ }
+ }
+ fclose(f);
+}
+
+int main(int argc, char *argv[])
+{
+ print_header();
+ show_connections();
+ print_footer();
+ return 0;
+}