summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--COPYING339
-rw-r--r--README111
-rw-r--r--docs/THANKS119
-rw-r--r--docs/announce129
-rw-r--r--docs/history165
-rw-r--r--docs/htmldocs/wfw_slip.htm175
-rw-r--r--docs/manpages/nmbd.8491
-rw-r--r--docs/manpages/samba.7190
-rw-r--r--docs/manpages/smb.conf.52719
-rw-r--r--docs/manpages/smbclient.11133
-rw-r--r--docs/manpages/smbd.8407
-rw-r--r--docs/manpages/smbrun.170
-rw-r--r--docs/manpages/smbstatus.152
-rw-r--r--docs/manpages/smbtar.1167
-rw-r--r--docs/manpages/testparm.1104
-rw-r--r--docs/manpages/testprns.1107
-rw-r--r--docs/samba.lsm26
-rw-r--r--docs/textdocs/BROWSING.txt145
-rw-r--r--docs/textdocs/BUGS.txt123
-rw-r--r--docs/textdocs/DIAGNOSIS.txt237
-rw-r--r--docs/textdocs/DNIX.txt69
-rw-r--r--docs/textdocs/DOMAIN.txt68
-rw-r--r--docs/textdocs/ENCRYPTION.txt333
-rw-r--r--docs/textdocs/HINTS.txt202
-rw-r--r--docs/textdocs/INSTALL.sambatar27
-rw-r--r--docs/textdocs/PROJECTS96
-rw-r--r--docs/textdocs/Passwords.txt42
-rw-r--r--docs/textdocs/README.DCEDFS79
-rw-r--r--docs/textdocs/README.jis124
-rw-r--r--docs/textdocs/README.sambatar15
-rw-r--r--docs/textdocs/SCO.txt12
-rw-r--r--docs/textdocs/SMBTAR.notes40
-rw-r--r--docs/textdocs/Speed.txt272
-rw-r--r--docs/textdocs/Support.txt376
-rw-r--r--docs/textdocs/UNIX-SMB.txt220
-rw-r--r--docs/textdocs/WinNT.txt56
-rw-r--r--examples/README6
-rw-r--r--examples/dce-dfs/README4
-rw-r--r--examples/dce-dfs/smb.conf42
-rw-r--r--examples/misc/extra_smbstatus47
-rw-r--r--examples/misc/wall.perl45
-rwxr-xr-xexamples/printing/smbprint77
-rw-r--r--examples/printing/smbprint.sysv52
-rw-r--r--examples/simple/README2
-rw-r--r--examples/simple/smb.conf165
-rw-r--r--examples/tridge/README8
-rw-r--r--examples/tridge/smb.conf101
-rw-r--r--examples/tridge/smb.conf.WinNT14
-rw-r--r--examples/tridge/smb.conf.fjall21
-rw-r--r--examples/tridge/smb.conf.lapland14
-rw-r--r--examples/tridge/smb.conf.vittjokk14
-rw-r--r--source/.cvsignore14
-rw-r--r--source/Makefile.lib32
-rw-r--r--source/cgi.c621
-rw-r--r--source/change-log12
-rw-r--r--source/client/client.c2352
-rw-r--r--source/client/clientutil.c951
-rw-r--r--source/client/clitar.c242
-rw-r--r--source/client/ntclient.c354
-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.h284
-rw-r--r--source/include/kanji.h43
-rw-r--r--source/include/local.h45
-rw-r--r--source/include/nameserv.h383
-rw-r--r--source/include/nterr.h505
-rw-r--r--source/include/proto.h1373
-rw-r--r--source/include/smb.h1816
-rw-r--r--source/include/trans2.h15
-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.c116
-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.c120
-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.c477
-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.c1395
-rw-r--r--source/libsmb/credentials.c222
-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/libsmb/smberr.c182
-rw-r--r--source/locking/locking.c283
-rw-r--r--source/locking/locking_shm.c696
-rw-r--r--source/locking/locking_slow.c1050
-rw-r--r--source/locking/shmem.c874
-rw-r--r--source/locking/shmem_sysv.c704
-rw-r--r--source/md4.h58
-rw-r--r--source/nameannounce.c554
-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.c400
-rw-r--r--source/namedbwork.c248
-rw-r--r--source/nameelect.c859
-rw-r--r--source/nameelect.doc256
-rw-r--r--source/namelogon.c238
-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.c280
-rw-r--r--source/nmbd/nmbd.c664
-rw-r--r--source/nmbsync.c352
-rw-r--r--source/param/loadparm.c1317
-rw-r--r--source/param/params.c862
-rw-r--r--source/passdb/smbpass.c650
-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.c1310
-rw-r--r--source/smbd/mangle.c618
-rw-r--r--source/smbd/message.c51
-rw-r--r--source/smbd/password.c745
-rw-r--r--source/smbd/pipes.c322
-rw-r--r--source/smbd/predict.c162
-rw-r--r--source/smbd/quotas.c664
-rw-r--r--source/smbd/reply.c1483
-rw-r--r--source/smbd/server.c3580
-rw-r--r--source/smbd/smbrun.c77
-rw-r--r--source/smbd/trans2.c414
-rw-r--r--source/smbd/uid.c555
-rw-r--r--source/smbd/vt_mode.c38
-rw-r--r--source/ubiqx/COPYING.LIB481
-rw-r--r--source/ubiqx/README.UBI15
-rw-r--r--source/ubiqx/ubi_AVLtree.c689
-rw-r--r--source/ubiqx/ubi_AVLtree.h331
-rw-r--r--source/ubiqx/ubi_BinTree.c1032
-rw-r--r--source/ubiqx/ubi_BinTree.h735
-rw-r--r--source/ubiqx/ubi_SplayTree.c462
-rw-r--r--source/ubiqx/ubi_SplayTree.h329
-rw-r--r--source/ubiqx/ubi_StackQueue.c149
-rw-r--r--source/ubiqx/ubi_StackQueue.h180
-rw-r--r--source/ubiqx/ubi_dLinkList.c147
-rw-r--r--source/ubiqx/ubi_dLinkList.h178
-rw-r--r--source/ubiqx/ubi_sLinkList.c112
-rw-r--r--source/ubiqx/ubi_sLinkList.h145
-rw-r--r--source/utils/make_printerdef.c301
-rw-r--r--source/utils/make_smbcodepage.c472
-rw-r--r--source/utils/nmblookup.c135
-rw-r--r--source/utils/smbpasswd.c273
-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/utils/torture.c919
-rw-r--r--source/web/cgi.c621
-rw-r--r--source/wsmbconf.c237
-rw-r--r--source/wsmbstatus.c87
191 files changed, 47098 insertions, 21136 deletions
diff --git a/COPYING b/COPYING
deleted file mode 100644
index a43ea2126fb..00000000000
--- a/COPYING
+++ /dev/null
@@ -1,339 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 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.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.) You can apply it to
-your programs, 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 software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, 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 redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-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 give any other recipients of the Program a copy of this License
-along with the Program.
-
-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 Program or any portion
-of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-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 Program, 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 Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) 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; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, 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 executable. 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.
-
-If distribution of executable or 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 counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program 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.
-
- 5. 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 Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program 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.
-
- 7. 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 Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program 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 Program.
-
-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.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program 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.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the 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 Program
-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 Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, 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
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), 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 Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. 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 program's name and a brief idea of what it does.>
- Copyright (C) 19yy <name of author>
-
- 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.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) 19yy name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- <signature of Ty Coon>, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Library General
-Public License instead of this License.
diff --git a/README b/README
deleted file mode 100644
index b7ef5d55957..00000000000
--- a/README
+++ /dev/null
@@ -1,111 +0,0 @@
-This is version 1.9 of Samba, the free SMB client and server for unix.
-
->>>> Please read THE WHOLE of this file as it gives important information
->>>> about the configuration and use of Samba.
-
-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 CAN SAMBA DO?
-==================
-
-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 Netbios (rfc1001/1002) nameserver
-
-- a ftp-like SMB client so you can access PC resources (disks and
-printers) from unix
-
-- a tar extension to the client for backing up PCs
-
-Related packages include:
-
-- ksmbfs, a linux-only filesystem allowing you to mount remote SMB
-filesystems from PCs on your linux box
-
-- tcpdump-smb, a extension to tcpdump to allow you to investigate SMB
-networking problems over netbeui and tcp/ip
-
-
-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.
-
-You could also send hardware/software/money/jewelry or pizza
-vouchers directly to me. The pizza vouchers would be especially
-welcome :-)
-
-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.
-
-Andrew Tridgell
-Email: samba-bugs@anu.edu.au
-
-3 Ballow Crescent
-Macgregor, A.C.T.
-2615 Australia
-
-
-MORE INFO
-=========
-
-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.
-
-FTP SITE
---------
-
-The main anonymous ftp distribution site for this software is
-nimbus.anu.edu.au in the directory pub/tridge/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"
-
-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.
-
-
-NEWS GROUP
-----------
-
-You might also like to look at the usenet news group
-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).
-
-
-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.
-
-
-
diff --git a/docs/THANKS b/docs/THANKS
deleted file mode 100644
index 6405da3f9f4..00000000000
--- a/docs/THANKS
+++ /dev/null
@@ -1,119 +0,0 @@
-=====================================================================
-This file is for thanks to individuals or organisations who have
-helped with the development of Samba, other than by coding or bug
-reports. Their contributions are gratefully acknowledged.
-
-Please refer to the manual pages and change-log for a list of those
-who have contributed in the form of patches, bug fixes or other
-direct changes to the package.
-
-Contributions of any kind are welcomed. If you want to help then
-please contact Andrew.Tridgell@anu.edu.au, or via normal mail at
-
- Andrew Tridgell
- 3 Ballow Crescent
- Macgregor, A.C.T
- 2615 Australia
-=====================================================================
-
-
-Lee Fisher (leefi@microsoft.com)
-Charles Fox (cfox@microsoft.com)
-Dan Perry (danp@exchnge.microsoft.com)
-
- These Microsoft people have been very helpful and supportive of
- the development of Samba.
-
- Lee very kindly supplied me with a copy of the X/Open SMB
- specs. These have been invaluable in getting the details of the
- implementation right. They will become even more important as we move
- towards a Lanman 2.1 compliant server. Lee has provided very
- useful advice on several aspects of the server.
- Lee has also provided me with copies of Windows NTAS 3.1, Visual C
- and a developers CD-ROM. Being able to run NT at home is a
- great help.
-
- Charles has helped out in numerous ways with the provision of SMB
- specifications and helpful advice. He has been following the
- discussion of Samba on the mailing list and has stepped in
- regularly to clarify points and to offer help.
-
- Dan has put me in touch with NT developers to help sort out bugs and
- compatability issues. He has also supplied me with a copy of the
- NT browsing spec, which will help a lot in the development of the
- Samba browser code.
-
-
-Bruce Perens (bruce@pixar.com)
-
- In appreciation of his effort on Samba we have sent Andrew copies of
- various Pixar computer-graphics software products. Pixar is best known
- for its "Renderman" product, the 3-D renderer used by ILM to make special
- effects for "Terminator II" and "Jurassic Park". We won the first Oscar
- given to a computer graphic animated feature for our short film "Tin Toy".
- Our retail products "Typestry" and "Showplace", incorporate the same
- renderer used on the films, and are available on Windows and the
- Macintosh.
-
-
-
-Henry Lee (hyl@microplex.co)
-
- Henry sent me a M202 ethernet print server, making my little lan
- one of the few home networks to have it's own print server!
-
- ``Microplex Systems Ltd. is a manufacturer of local and wide area
- network communications equipment based in beautiful Vancouver, British
- Columbia, Canada. Microplex's first products were synchronous wide
- area network devices used in the mainframe communication networks. In
- August 1991 Microplex introduced its first LAN product, the M200 print
- server, the first high performance print server under US$1,000.''
-
-
-Tom Haapanen (tomh@metrics.com)
-
- Tom sent me two 16 bit SMC ethernet cards to replace my ancient 8
- bit ones. The performance is much better!
-
- Software Metrics Inc. is a small custom software development and
- consulting firm located in Waterloo, Ontario, Canada. We work
- with a variety of environments (such as Windows, Windows NT and
- Unix), tools and application areas, and can provide assistance for
- development work ranging from a few days to to multiple man-year
- projects. You can find more information at http://www.metrics.com/.
-
-
-Steve Kennedy (steve@gbnet.net)
-
- Steve sent me 16Mb of ram so that I could install/test
- NT3.5. I previous had only 8Mb ram in my test machine, which
- wasn't enough to install a properly functioning copy of
- NTAS. Being able to directly test NT3.5 allowed me to solve
- several long standing NT<->Samba problems. Thanks Steve!
-
-John Terpstra (jht@aquasoft.com.au)
-
- Aquasoft are a speciaist consulting company whose Samba using
- customers span the world.
-
- Aquasoft have been avid supporters of the Samba project. As a
- token of appreciation Aquasoft have donated a 486DX2/66 PC with
- a 540MB EIDE drive and 20MB RAM.
-
- John has helped to isolate quite a few little glitches over time
- and has managed to implement some very interesting installations
- of Samba.
-
- The donation of the new PC will make it possible to more fully
- diagnose and observe the behaviour of Samba in conjuction with
- other SMB protocol utilising systems.
-
-
-Timothy F. Sipples (tsipple@vnet.IBM.COM)
-Steve Withers (swithers@vnet.IBM.COM)
-
- Tim and Steve from IBM organised a copy of the OS/2 developers
- connection CD set for me, and gave lots of help in getting
- 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.
diff --git a/docs/announce b/docs/announce
deleted file mode 100644
index f761320f43e..00000000000
--- a/docs/announce
+++ /dev/null
@@ -1,129 +0,0 @@
- Announcing Samba version 1.9
- ============================
-
-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
-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.
-
-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
-available on the PC.
-
-The client part of the package will also allow you to attach to other
-SMB-based servers (such as windows NT and windows for workgroups) so
-that you can copy files to and from your unix host. The client also
-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?
-------------------------
-
-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,
-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
-included with the package for a full list of features.
-
-What's new since 1.8?
----------------------
-
-Lots of stuff. See the change log and man pages for details.
-
-Where can I get a client for my PC?
------------------------------------
-
-There is a free client for MS-DOS based PCs available from
-ftp.microsoft.com in the directory bussys/Clients/MSCLIENT/. Please
-read the licencing information before downloading. The built in
-Windows for Workgroups client is also very good.
-
-What network protocols are supported?
--------------------------------------
-
-Currently only TCP/IP is supported. There has been some discussion
-about ports to other protocols but nothing is yet available.
-
-There is a free TCP/IP implementation for Windows for Workgroups
-available from ftp.microsoft.com (it's small, fast and quite reliable).
-
-How much does it cost?
-----------------------
-
-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?
----------------------------------------
-
-The code has been written to be as portable as possible. It has been
-"ported" to many unixes, which mostly required changing only a few
-lines of code. It has been run (to my knowledge) on at least these
-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.
-
-Some of these have received more testing than others. If it doesn't
-work with your unix then it should be easy to fix.
-
-Who wrote it?
--------------
-
-Many people on the internet have contributed to the development of
-Samba. The maintainer and original author is Andrew Tridgell, but
-large parts of the package were contributed by several people from all
-over the world. Please look at the file `change-log' for information
-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/.
-
-What about SMBServer?
----------------------
-
-Samba used to be known as SMBServer, until it was pointed out that
-Syntax, who make a commercial Unix SMB based server, have trademarked
-that name. The name was then changed to Samba. Also, in 1992 a very
-early incarnation of Samba was distributed as nbserver.
-
-If you see any copies of nbserver or smbserver on ftp sites please let
-me or the ftp archive maintainer know, as I want to get them deleted.
-
-Where can I get more info?
----------------------------
-
-Please join the mailing list if you want to discuss the development or
-use of Samba. To join the mailing list send mail to
-listproc@listproc.anu.edu.au with a body of "subscribe samba Your
-Name".
-
-There is also an announcement mailing list for new version
-announcements. Subscribe as above but with "subscribe samba-announce
-Your Name".
-
-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/
-
-Andrew Tridgell (Contact: samba-bugs@anu.edu.au)
-January 1995
diff --git a/docs/history b/docs/history
deleted file mode 100644
index 83761e23b86..00000000000
--- a/docs/history
+++ /dev/null
@@ -1,165 +0,0 @@
-Note: This file is now quite out of date - but perhaps that's
-appropriate?
-
-
-=========
-
-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
-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
-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.
-
-eXcursion ran (at the time) only with Dec's `Pathworks' network for
-DOS. I had up till then been using PC-NFS to connect to our local sun
-workstations, and was reasonably happy with it. In order to run
-pathworks I had to stop using PC-NFS and try using pathworks to mount
-disk space. Unfortunately pathworks was only available for digital
-workstations running VMS or Ultrix so I couldn't mount from the suns
-anymore.
-
-I had access to a a decstation 3100 running Ultrix that I used to
-administer, and I got the crazy notion that the protocol that
-pathworks used to talk to ultrix couldn't be that hard, and maybe I
-could work it out. I had never written a network program before, and
-certainly didn't know what a socket was.
-
-In a few days, after looking at some example code for sockets, I
-discovered it was pretty easy to write a program to "spy" on the file
-sharing protocol. I wrote and installed this program (the sockspy.c
-program supplied with this package) and captured everything that the
-pathworks client said to the pathworks server.
-
-I then tried writing short C programs (using Turbo C under DOS) to do
-simple file operations on the network drive (open, read, cd etc) and
-looked at the packets that the server and client exchanged. From this
-I worked out what some of the bytes in the packets meant, and started
-to write my own program to do the same thing on a sun.
-
-After a day or so more I had my first successes and actually managed
-to get a connection and to read a file. From there it was all
-downhill, and a week later I was happily (if a little unreliably)
-mounting disk space from a sun to my PC running pathworks. The server
-code had a lot of `magic' values in it, which seemed to be always
-present with the ultrix server. It was not till 2 years later that I
-found out what all these values meant.
-
-Anyway, I thought other people might be interested in what I had done,
-so I asked a few people at uni, and noone seemed much interested. I
-also spoke to a person at Digital in Canberra (the person who had
-organised a beta test of eXcursion) and asked if I could distribute
-what I'd done, or was it illegal. It was then that I first heard the
-word "netbios" when he told me that he thought it was all covered by a
-spec of some sort (the netbios spec) and thus what I'd done was not
-only legal, but silly.
-
-I found the netbios spec after asking around a bit (the RFC1001 and
-RFC1002 specs) and found they looked nothing like what I'd written, so
-I thought maybe the Digital person was mistaken. I didn't realise RFCs
-referred to the name negotiation and packet encapsulation over TCP/IP,
-and what I'd written was really a SMB implementation.
-
-Anyway, he encouraged me to release it so I put out "Server 0.1" in
-January 1992. I got quite a good response from people wanting to use
-pathworks with non-digital unix workstations, and I soon fixed a few
-bugs, and released "Server 0.5" closely followed by "Server 1.0". All
-three releases came out within about a month of each other.
-
-At this point I got an X Terminal on my desk, and I no longer needed eXcursion
-and I prompty forgot about the whole project, apart from a few people
-who e-mailed me occasionally about it.
-
-Nearly two years then passed with just occasional e-mails asking about
-new versions and bugs. I even added a note to the ftp site asking for
-a volunteer to take over the code as I no longer used it. No one
-volunteered.
-
-During this time I did hear from a couple of people who said it should
-be possible to use my code with Lanmanager, but I never got any
-definite confirmation.
-
-One e-mail I got about the code did, however, make an impression. It
-was from Dan Shearer at the university of South Australia, and he said
-this:
-
-
- I heard a hint about a free Pathworks server for Unix in the
- Net channel of the Linux list. After quite a bit of chasing
- (and lots of interested followups from other Linux people) I
- got hold of a release news article from you, posted in Jan 92,
- from someone in the UK.
-
- Can you tell me what the latest status is? I think you might
- suddenly find a whole lot of interested hackers in the Linux
- world at least, which is a place where things tend to happen
- fast (and even some reliable code gets written, BION!)
-
-I asked him what Linux was, and he told me it was a free Unix for PCs.
-This was in November 1992 and a few months later I was a Linux
-convert! I still didn't need a pathworks server though, so I didn't do
-the port, but I think Dan did.
-
-At about this time I got an e-mail from Digital, from a person working
-on the Alpha software distribution. He asked if I would mind if they
-included my server with the "contributed" cd-rom. This was a bit of a
-shock to me as I never expected Dec to ask me if they could use my
-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
-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.
-
-At this time a person from our computer center offered me a couple of
-cheap ethernet cards (3c505s for $15 each) and coincidentially someone
-announced on one of the Linux channels that he had written a 3c505
-driver for Linux. I bought the cards, hacked the driver a little and
-setup a home network between my wifes PC and my Linux box. I then
-needed some way to connect the two, and I didn't own PC-NFS at home,
-so I thought maybe my server could be useful. On the newsgroup among
-the discussions of my server someone had mentioned that there was a
-free client that might work with my server that Microsoft had put up
-for ftp. I downloaded it and found to my surprise that it worked first
-time with my `pathworks' server!
-
-Well, I then did a bit of hacking, asked around a bit and found (I
-think from Dan) that the spec I needed was for the "SMB" protocol, and
-that it was available via ftp. I grabbed it and started removing all
-those ugly constants from the code, now that all was explained.
-
-On December 1st 1993 I announced the start of the "Netbios for Unix"
-project, seeding the mailing list with all the people who had e-mailed
-me over the years asking about the server.
-
-About 35 versions (and two months) later I wrote a short history of
-the project, which you have just read. There are now over a hundred
-people on the mailing list, and lots of people report that they use
-the code and like it. In a few days I will be announcing the release
-of version 1.6 to some of the more popular (and relevant) newsgroups.
-
-
-Andrew Tridgell
-6th February 1994
-
----------------------
-
-It is now May 1995 and there are about 1400 people on the mailing
-list. I got downloads from the main Samba ftp site from around 5000
-unique hosts in a two month period. There are several mirror
-sites as well. The current version number is 1.9.13.
-
----------------------
-
-
----------------------
-It's now March 1996 and version 1.9.16alpha1 has just been
-released. There have been lots of changes recently with master browser
-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.
----------------------
diff --git a/docs/htmldocs/wfw_slip.htm b/docs/htmldocs/wfw_slip.htm
deleted file mode 100644
index 5b4a0a5e539..00000000000
--- a/docs/htmldocs/wfw_slip.htm
+++ /dev/null
@@ -1,175 +0,0 @@
-<HTML>
-<HEAD>
-<TITLE>Peter Karrer Announces SLIP for WFW</TITLE>
-</HEAD>
-<BODY>
-<H1><I>Winserve</I></H1>
-<HR>
-<H2><I>Peter Karrer Announces SLIP for WFW</I></H2>
-[NEW 03-22-95)
-<HR>
-<B>Hello,</B>
-<P>
-I've discovered a way to run WfW's TCP/IP-32 over a SLIP packet driver. This
-allows WfW users to do Windows networking over dialup lines just like it is
-possible with NT and the Windows 95 beta!
-<P>
-For instance, you can mount Microsoft's FTP server as a network drive in File
-Manager or connect to an MS Mail post office over the Internet. Of course,
-the usual Internet stuff works as well. Another interesting site is
-WINSERVE.001; check out www.winserve.com.
-<HR>
-This method should work with any class 1 (Ethernet II) packet driver. However,
-I'm not in a position to try anything else than SLIPPER/CSLIPPER.
-<HR>
-<H3>Files you need:</H3>
-<B>WFWT32.EXE:</B> ftp://ftp.microsoft.com/bussys/msclient/wfw/wfwt32.exe
-<P>
- Microsoft's free TCP/IP for WfW. It's a self-extracting archive which
- should be executed in an empty directory.
-<P>
-<B>SLIPPER.EXE:</B> ftp://biocserver.bioc.cwru.edu/pub/dos/slipper/slippr15.zip
-<P>
- Peter Tattam's SLIP packet driver. CSLIPPER.EXE is a variant which supports
- VJ header compression.
-<P>
-<B>PDETHER.EXE:</B> ftp://sjf-lwp.idz.sjf.novell.com/odi/pdether/pde105.zip
-<P>
- Don Provan's ODI-over-Packet Driver shim. This *must* be version 1.05 (or
- above).
-<P>
-<B>LSL.COM:</B>
-<P>
- Novell's LAN Support Layer. If you're an owner of Windows 3.10, you'll
- have it on one of your install disks. Use "expand a:lsl.co_ lsl.com" to
- expand it. Microsoft has stopped bundling LSL.COM with WfW 3.11, though.
- The newest version of LSL.COM can be downloaded as part of
- ftp://ftp.novell.com/pub/netware/nwos/dosclnt12/vlms/vlmup2.exe.
- However, it's not clear if this one may be legally used outside Netware
- environments.
-<P>
-<B>NET.CFG:</B>
-<P>
- A configuration file for LSL and PDETHER. It should contain the following
- text:
-<P>
-<PRE>
-Link Support
- Buffers 8 1600
-Link Driver PDETHER
- Int 60
- Frame Ethernet_II
- Protocol IP 800 Ethernet_II
- Protocol ARP 806 Ethernet_II
- Protocol RARP 8035 Ethernet_II
-</PRE>
-<P>
-<B>DISCOMX.COM:</B>
-<P>
- A little hack of mine to disable the COM port used by the SLIP packet driver.
- Usage is e.g. "discomx 2" to disable COM2. This should be run before
- starting WfW, otherwise you'll get "device conflict" messages. Here it is:
-<P><PRE>
-begin 644 discomx.com
-F,=N)V8H.@`"P(+^!`/.N3XH="=MT!DN`XP/1XS')!R:)CP`$S2``
-`
-end
- </PRE>
- (Save this text to disk as <I>filename</I>, then run "uudecode <I>filename</I>".
- uudecode can be found, for instance, at
- ftp://ftp.switch.ch/mirror/simtel/msdos/starter/uudecode.com )
-<P>
-<B>LMHOSTS:</B>
- <P>
- An optional file which should be stored in your Windows subdirectory. It is
- used to map NetBIOS computer names to IP addresses. Example:
-<P>
-<PRE>
-198.105.232.1 ftp #PRE # ftp.microsoft.com
-204.118.34.11 winserve.001 #PRE # Winserve
-</PRE>
-<HR>
-<H3>How to install it:</H3>
-<P>
-<UL>
-<LI>Put the files mentioned above into a directory, e.g. C:\SLIP.
-<P>
-<LI>Put the following lines into AUTOEXEC.BAT:
-<P><PRE>
- cd \slip
- slipper com1 vec=60 baud=57600 ether (may vary with your modem setup)
- lsl
- pdether
- discomx 1 (must correspond to SLIPPER's COM port)
-</PRE>
- (If you use another vec= setting, you must update that in NET.CFG as well.)
- Use CSLIPPER instead of SLIPPER if your SLIP provider supports VJC.
-<P>
-<LI>Start WfW.
-<UL>
-<LI>Under Windows Setup, choose "Change Network Settings".
-<LI>Select "Install Microsoft Windows Network".
-<LI>In "Drivers...", choose "Add Adapter"
- and install the "IPXODI Support driver (Ethernet) [ODI/NDIS3]".
-<LI>In "Add Protocols...", select "Unlisted or Updated Protocol". When asked for a
- driver disk, enter the directory where you expanded WFWT32.EXE.
-<LI>Configure TCP/IP (IP address, enable LMHOSTS lookup, try 204.118.34.11 as primary
- WINS server). Remove all other protocols (NetBEUI, IPX/SPX).
-</UL>
-<P>
-<LI>Windows will probably update the first lines of AUTOEXEC.BAT with
-<P>
-<PRE>
- c:\windows\net start
- c:\windows\odihlp.exe.
-</PRE>
- The "odihlp" line must be moved behind the "pdether" line.
-<P>
-<LI>Windows will also update NET.CFG with some "Frame" lines. These must
- be removed (except "Frame Ethernet_II").
-<P>
-<LI>Somehow, you will have to dial in to your SLIP provider. I do it manually
- before slipper (or cslipper) gets loaded, using a DOS-based terminal program.
- But there are some automatic dialers around. I've seen recommendations for
- ftp://mvmpc9.ciw.uni-karlsruhe.de/x-slip/slip_it.exe.
-<P>
-<LI>To connect to Microsoft's FTP server (or Winserve) go into File Manager,
- choose "Connect Network drive" and enter "\\ftp" or "\\winserve.001" into
- the "Path:" field.
-</UL>
-<HR>
-<H3>How it works:</H3>
-<P>
-Microsoft's TCP/IP-32 requires an NDIS3 interface. NDIS is Microsoft's way
-to interface with a network.
-<P>
-WfW also contains an NDIS3-over-ODI "shim", whose real mode component is
-ODIHLP.EXE. ODI is Novell's way to interface with a network.
-<P>
-SLIPPER is a Packet Driver (PD) for use over serial lines. PDs are everybody
-else's way to interface with a network. SLIPPER's "ether" option makes it
-look like an Ethernet PD to applications using it.
-<P>
-A "shim" is a program which simulates a network application programming
-interface on top of another.
-<P>
-There is no NDIS SLIP driver which would work with WfW.
-<P>
-There is no NDIS-over-PD shim.
-<P>
-However, there's an ODI-over-PD shim (PDETHER) and an NDIS-over-ODI shim
-(ODIHLP etc.)
-<P>
-OK, so let's do NDIS-over-ODI-over-PD!
- <P>
-This should have worked all the time; however, a non-feature in PDETHER
-versions < 1.05 has prevented the method from functioning until now.
-<HR>
-<B>Questions, suggestions etc. please to
-<P>
-<PRE>
-Peter Karrer pkarrer@ife.ee.ethz.ch
-</PRE>
-</B>
-</BODY>
-</HTML>
diff --git a/docs/manpages/nmbd.8 b/docs/manpages/nmbd.8
deleted file mode 100644
index e42f194cdee..00000000000
--- a/docs/manpages/nmbd.8
+++ /dev/null
@@ -1,491 +0,0 @@
-.TH NMBD 8 17/1/1995 nmbd nmbd
-.SH NAME
-nmbd \- provide netbios nameserver support to clients
-.SH SYNOPSIS
-.B nmbd
-[
-.B -B
-.I broadcast address
-] [
-.B -I
-.I IP address
-] [
-.B -D
-] [
-.B -C comment string
-] [
-.B -G
-.I group name
-] [
-.B -H
-.I netbios hosts file
-] [
-.B -N
-.I netmask
-] [
-.B -d
-.I debuglevel
-] [
-.B -l
-.I log basename
-] [
-.B -n
-.I netbios name
-] [
-.B -p
-.I port number
-] [
-.B -s
-.I config file name
-]
-
-.SH DESCRIPTION
-This program is part of the Samba suite.
-
-.B nmbd
-is a server that understands and can reply to netbios
-name service requests, like those produced by LanManager
-clients. It also controls browsing.
-
-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.
-.SH OPTIONS
-.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.
-.RE
-.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.
-.RE
-
-.B -D
-
-.RS 3
-If specified, this parameter causes the server to operate as a daemon. That is,
-it detaches itself and runs in the background, fielding requests on the
-appropriate port.
-
-By default, the server will NOT operate as a daemon.
-.RE
-
-.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".
-.RE
-
-.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.
-.RE
-
-.B -H
-
-.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.
-
-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.
-
-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.
-
-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).
-
-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.
-
-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 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.
-
-.B Example:
-
- # This is a sample netbios hosts file
-
- # DO NOT USE THIS FILE AS-IS
- # YOU MAY INCONVENIENCE THE OWNERS OF THESE IPs
- # 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
-
-.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.
-
-.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
-.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.
-.RE
-
-.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 log files generated are never removed by the server.
-.RE
-.RE
-
-.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.
-.RE
-
-.B /etc/services
-
-.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.
-.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:
-
-.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:
-
-.RS 3
-/usr/local/smb/nmbd -D -l/var/adm/smblogs/log
-.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:
-
-.RS 3
-netbios-ns 137/udp
-.RE
-
-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
-.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.
-.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.
-.SH CREDITS
-The original Samba software and related utilities were created by
-Andrew Tridgell (samba-bugs@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
deleted file mode 100644
index 0c81f736b6e..00000000000
--- a/docs/manpages/samba.7
+++ /dev/null
@@ -1,190 +0,0 @@
-.TH SAMBA 7 29/3/95 Samba Samba
-.SH NAME
-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
-as the LanManager or Netbios protocol.
-
-.SH COMPONENTS
-
-The Samba suite is made up of several components. Each component is
-described in a separate manual page. It is strongly recommended that
-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,
-such as Windows for Workgroups, Windows NT or LanManager. The
-configuration file for this daemon is described in smb.conf(5).
-
-The 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
-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
-attached to any SMB server (such as a PC running WfWg).
-
-The testparm(1) utility allows you to test your smb.conf(5)
-configuration file.
-
-The smbstatus(1) utility allows you to tell who is currently using the
-smbd(8) server.
-
-.SH AVAILABILITY
-
-The Samba software suite is licensed under the Gnu Public License. A
-copy of that license should have come with the package. You are
-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
-also available on several mirror sites worldwide.
-
-You may also find useful information about Samba on the newsgroup
-comp.protocols.smb and the Samba mailing list. Details on how to join
-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/
-
-.SH AUTHOR
-
-The main author of the Samba suite is Andrew Tridgell. He may be
-contacted via e-mail at samba-bugs@anu.edu.au.
-
-There have also been an enourmous number of contributors to Samba from
-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.
-
-.SH CREDITS
-
-Contributors to the project are (in alphabetical order by email address):
-
-(NOTE: This list is very out of date)
-
- Adams, Graham
- (gadams@ddrive.demon.co.uk)
- Allison, Jeremy
- (jeremy@netcom.com)
- Andrus, Ross
- (ross@augie.insci.com)
- Auer, Karl
- (Karl.Auer@anu.edu.au)
- Bogstad, Bill
- (bogstad@cs.jhu.edu)
- Boreham, Bryan
- (Bryan@alex.com)
- Boreham, David
- (davidb@ndl.co.uk)
- Butler, Michael
- (imb@asstdc.scgt.oz.au)
- ???
- (charlie@edina.demon.co.uk)
- Chua, Michael
- (lpc@solomon.technet.sg)
- Cochran, Marc
- (mcochran@wellfleet.com)
- Dey, Martin N
- (mnd@netmgrs.co.uk)
- Errath, Maximilian
- (errath@balu.kfunigraz.ac.at)
- Fisher, Lee
- (leefi@microsoft.com)
- Foderaro, Sean
- (jkf@frisky.Franz.COM)
- Greer, Brad
- (brad@cac.washington.edu)
- Griffith, Michael A
- (grif@cs.ucr.edu)
- Grosen, Mark
- (MDGrosen@spectron.COM)
- ????
- (gunjkoa@dep.sa.gov.au)
- Haapanen, Tom
- (tomh@metrics.com)
- Hench, Mike
- (hench@cae.uwm.edu)
- Horstman, Mark A
- (mh2620@sarek.sbc.com)
- Hudson, Tim
- (tim.hudson@gslmail.mincom.oz.au)
- Hulthen, Erik Magnus
- (magnus@axiom.se)
- ???
- (imb@asstdc.scgt.oz.au)
- Iversen, Per Steinar
- (iversen@dsfys1.fi.uib.no)
- Kaara, Pasi
- (ppk@atk.tpo.fi)
- Karman, Merik
- (merik@blackadder.dsh.oz.au)
- Kiff, Martin
- (mgk@newton.npl.co.uk)
- Kiick, Chris
- (cjkiick@flinx.b11.ingr.com)
- Kukulies, Christoph
- (kuku@acds.physik.rwth-aachen.de)
- ???
- (lance@fox.com)
- Lendecke, Volker
- (lendecke@namu01.gwdg.de)
- ???
- (lonnie@itg.ti.com)
- Mahoney, Paul Thomas
- (ptm@xact1.xact.com)
- Mauelshagen, Heinz
- (mauelsha@ez.da.telekom.de)
- Merrick, Barry G
- (bgm@atml.co.uk)
- Mol, Marcel
- (marcel@fanout.et.tudeflt.nl)
- ???
- (njw@cpsg.com.au)
- ???
- (noses@oink.rhein.de)
- Owens, John
- (john@micros.com)
- Pierson, Jacques
- (pierson@ketje.enet.dec.com)
- Powell, Mark
- (mark@scot1.ucsalf.ac.uk)
- Reiz, Steven
- (sreiz@aie.nl)
- Schlaeger, Joerg
- (joergs@toppoint.de)
- S{rkel{, Vesa
- (vesku@rankki.kcl.fi)
- Tridgell, Andrew
- (samba-bugs@anu.edu.au)
- Troyer, Dean
- (troyer@saifr00.ateng.az.honeywell.com)
- Wakelin, Ross
- (rossw@march.co.uk)
- Wessels, Stefan
- (SWESSELS@dos-lan.cs.up.ac.za)
- Young, Ian A
- (iay@threel.co.uk)
- van der Zwan, Paul
- (paulzn@olivetti.nl)
-
diff --git a/docs/manpages/smb.conf.5 b/docs/manpages/smb.conf.5
deleted file mode 100644
index 933d71ff0c3..00000000000
--- a/docs/manpages/smb.conf.5
+++ /dev/null
@@ -1,2719 +0,0 @@
-.TH SMB.CONF 5 11/10/94 smb.conf smb.conf
-.SH NAME
-smb.conf \- configuration file for smbd
-.SH SYNOPSIS
-.B smb.conf
-.SH DESCRIPTION
-The
-.B smb.conf
-file is a configuration file for the Samba suite.
-
-.B smb.conf
-contains runtime configuration information for the
-.B smbd
-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
-section begins. Sections contain parameters of the form 'name = value'.
-
-The file is line-based - that is, each newline-terminated line represents
-either a comment, a section name or a parameter.
-
-Section and parameter names are not case sensitive.
-
-Only the first equals sign in a parameter is significant. Whitespace before
-or after the first equals sign is discarded. Leading, trailing and internal
-whitespace in section and parameter names is irrelevant. Leading and
-trailing whitespace in a parameter value is discarded. Internal whitespace
-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.
-
-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
-true/false. Case is not significant in boolean values, but is preserved
-in string values. Some items such as create modes are numeric.
-.SH SERVICE DESCRIPTIONS
-Each section in the configuration file describes a service. The section name
-is the service name and the parameters within the section define the service's
-attributes.
-
-There are three special sections, [global], [homes] and [printers], which are
-described under 'special sections'. The following notes apply to ordinary
-service descriptions.
-
-A service consists of a directory to which access is being given plus a
-description of the access rights which are granted to the user of the
-service. Some housekeeping options are also specifiable.
-
-Services are either filespace services (used by the client as an extension of
-their native file systems) or printable services (used by the client to access
-print services on the host running the server).
-
-Services may be guest services, in which case no password is required to
-access them. A specified guest account is used to define access privileges
-in this case.
-
-Services other than guest services will require a password to access
-them. The client provides the username. As many clients only provide
-passwords and not usernames, you may specify a list of usernames to
-check against the password using the "user=" option in the service
-definition.
-
-Note that the access rights granted by the server are masked by the access
-rights granted to the specified or guest user by the host system. The
-server does not grant more access than the host system grants.
-
-The following sample section defines a file space service. The user has write
-access to the path /home/bar. The service is accessed via the service name
-"foo":
-
- [foo]
- path = /home/bar
- writable = true
-
-The following sample section defines a printable service. The service is
-readonly, but printable. That is, the only write access permitted is via
-calls to open, write to and close a spool file. The 'guest ok' parameter
-means access will be permitted as the default guest user (specified elsewhere):
-
- [aprinter]
- path = /usr/spool/public
- read only = true
- printable = true
- public = true
-
-.SH SPECIAL SECTIONS
-
-.SS The [global] section
-.RS 3
-Parameters in this section apply to the server as a whole, or are defaults
-for services which do not specifically define certain items. See the notes
-under 'Parameters' for more information.
-.RE
-
-.SS The [homes] section
-.RS 3
-If a section called 'homes' is included in the configuration file, services
-connecting clients to their home directories can be created on the fly by the
-server.
-
-When the connection request is made, the existing services are scanned. If a
-match is found, it is used. If no match is found, the requested service name is
-treated as a user name and looked up in the local passwords file. If the
-name exists and the correct password has been given, a service is created
-by cloning the [homes] section.
-
-Some modifications are then made to the newly created section:
-
-.RS 3
-The service name is changed from 'homes' to the located username
-
-If no path was given, the path is set to the user's home directory.
-.RE
-
-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.
-
-This is a fast and simple way to give a large number of clients access to
-their home directories with a minimum of fuss.
-
-A similar process occurs if the requested service name is "homes", except that
-the service name is not changed to that of the requesting user. This method
-of using the [homes] section works well if different users share a client PC.
-
-The [homes] section can specify all the parameters a normal service section
-can specify, though some make more sense than others. The following is a
-typical and suitable [homes] section:
-
- [homes]
- writable = yes
-
-An important point:
-
-.RS 3
-If guest access is specified in the [homes] section, all home directories will
-be accessible to all clients
-.B without a password.
-In the very unlikely event
-that this is actually desirable, it would be wise to also specify read only
-access.
-.RE
-.RE
-
-Note that the browseable flag for auto home directories will be
-inherited from the global browseable flag, not the [homes] browseable
-flag. This is useful as it means setting browseable=no in the [homes]
-section will hide the [homes] service but make any auto home
-directories visible.
-
-.SS The [printers] section
-.RS 3
-This section works like [homes], but for printers.
-
-If a [printers] section occurs in the configuration file, users are able
-to connect to any printer specified in the local host's printcap file.
-
-When a connection request is made, the existing services are scanned. If a
-match is found, it is used. If no match is found, but a [homes] section
-exists, it is used as described above. Otherwise, the requested service name is
-treated as a printer name and the appropriate printcap file is scanned to
-see if the requested service name is a valid printer name. If a match is
-found, a new service is created by cloning the [printers] section.
-
-A few modifications are then made to the newly created section:
-
-.RS 3
-The service name is set to the located printer name
-
-If no printer name was given, the printer name is set to the located printer
-name
-
-If the service does not permit guest access and no username was given, the
-username is set to the located printer name.
-.RE
-
-Note that the [printers] service MUST be printable - if you specify otherwise,
-the server will refuse to load the configuration file.
-
-Typically the path specified would be that of a world-writable spool directory
-with the sticky bit set on it. A typical [printers] entry would look like this:
-
- [printers]
- path = /usr/spool/public
- writable = no
- public = yes
- printable = yes
-
-All aliases given for a printer in the printcap file are legitimate printer
-names as far as the server is concerned. If your printing subsystem doesn't
-work like that, you will have to set up a pseudo-printcap. This is a file
-consisting of one or more lines like this:
-
- alias|alias|alias|alias...
-
-Each alias should be an acceptable printer name for your printing
-subsystem. In the [global] section, specify the new file as your printcap.
-The server will then only recognise names found in your pseudo-printcap,
-which of course can contain whatever aliases you like. The same technique
-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 ("|").
-.SH PARAMETERS
-Parameters define the specific attributes of services.
-
-Some parameters are specific to the [global] section (eg., security).
-Some parameters are usable in all sections (eg., create mode). All others are
-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
-can also be specified in the [global] section - in which case they
-will define the default behaviour for all services.
-
-Parameters are arranged here in alphabetical order - this may not create
-best bedfellows, but at least you can find them! Where there are synonyms,
-the preferred synonym is described, others refer to the preferred synonym.
-
-.SS VARIABLE SUBSTITUTIONS
-
-Many of the strings that are settable in the config file can take
-substitutions. For example the option "path = /tmp/%u" would be
-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
-relevant. These are:
-
-%S = the name of the current service, if any
-
-%P = the root directory of the current service, if any
-
-%u = user name of the current service, if any
-
-%g = primary group name of %u
-
-%U = session user name (the user name that the client wanted, not
-necessarily the same as the one they got)
-
-%G = primary group name of %U
-
-%H = the home directory of the user given by %u
-
-%v = the Samba version
-
-%h = the hostname that Samba is running on
-
-%m = the netbios name of the client machine (very useful)
-
-%L = the netbios name of the server. This allows you to change your
-config based on what the client calls you. Your server can have a "dual
-personality".
-
-%M = the internet name of the client machine
-
-%d = The process id of the current server process
-
-%a = the architecture of the remote machine. Only some are recognised,
-and those may not be 100% reliable. It currently recognises Samba,
-WfWg, WinNT and Win95. Anything else will be known as "UNKNOWN". If it
-gets it wrong then sending me a level 3 log should allow me to fix it.
-
-%I = The IP address of the client machine
-
-%T = the current date and time
-
-There are some quite creative things that can be done with these
-substitutions and other smb.conf options.
-
-.SS NAME MANGLING
-
-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.
-
-There are several options that control the way mangling is performed,
-and they are grouped here rather than listed separately. For the
-defaults look at the output of the testparm program.
-
-All of these options can be set separately for each service (or
-globally, of course).
-
-The options are:
-
-"mangle case = yes/no" controls if names that have characters that
-aren't of the "default" case are mangled. For example, if this is yes
-then a name like "Mail" would be mangled. Default no.
-
-"case sensitive = yes/no" controls whether filenames are case
-sensitive. If they aren't then Samba must do a filename search and
-match on passed names. Default no.
-
-"default case = upper/lower" controls what the default case is for new
-filenames. Default lower.
-
-"preserve case = yes/no" controls if new files are created with the
-case that the client passes, or if they are forced to be the "default"
-case. Default no.
-
-"short preserve case = yes/no" controls if new files which conform to 8.3
-syntax, that is all in upper case and of suitable length, are created
-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
-
-Here is a list of all global parameters. See the section of each
-parameter for details. Note that some are synonyms.
-
-auto services
-
-config file
-
-deadtime
-
-debuglevel
-
-default
-
-default service
-
-dfree command
-
-encrypt passwords
-
-getwd cache
-
-hosts equiv
-
-include
-
-keepalive
-
-lock dir
-
-load printers
-
-lock directory
-
-log file
-
-log level
-
-lpq cache time
-
-mangled stack
-
-max log size
-
-max packet
-
-max xmit
-
-message command
-
-null passwords
-
-os level
-
-packet size
-
-passwd chat
-
-passwd program
-
-password level
-
-password server
-
-preferred master
-
-preload
-
-printing
-
-printcap name
-
-protocol
-
-read bmpx
-
-read prediction
-
-read raw
-
-read size
-
-root
-
-root dir
-
-root directory
-
-security
-
-server string
-
-smbrun
-
-socket options
-
-status
-
-strip dot
-
-time offset
-
-username map
-
-use rhosts
-
-valid chars
-
-workgroup
-
-write raw
-
-.SS COMPLETE LIST OF SERVICE PARAMETER
-
-Here is a list of all service parameters. See the section of each
-parameter for details. Note that some are synonyms.
-
-admin users
-
-allow hosts
-
-alternate permissions
-
-available
-
-browseable
-
-case sensitive
-
-case sig names
-
-copy
-
-create mask
-
-create mode
-
-comment
-
-default case
-
-deny hosts
-
-directory
-
-dont descend
-
-exec
-
-force group
-
-force user
-
-guest account
-
-guest ok
-
-guest only
-
-hide dot files
-
-hosts allow
-
-hosts deny
-
-invalid users
-
-locking
-
-lppause command
-
-lpq command
-
-lpresume command
-
-lprm command
-
-magic output
-
-magic script
-
-mangle case
-
-mangled names
-
-mangling char
-
-map archive
-
-map hidden
-
-map system
-
-max connections
-
-min print space
-
-only guest
-
-only user
-
-path
-
-postexec
-
-postscript
-
-preserve case
-
-print command
-
-print ok
-
-printable
-
-printer
-
-printer name
-
-public
-
-read only
-
-read list
-
-revalidate
-
-root postexec
-
-root preexec
-
-set directory
-
-share modes
-
-short preserve case
-
-strict locking
-
-sync always
-
-user
-
-username
-
-users
-
-valid users
-
-volume
-
-wide links
-
-writable
-
-write ok
-
-writeable
-
-write list
-
-.SS EXPLANATION OF EACH PARAMETER
-.RS 3
-
-.SS admin users (G)
-
-This is a list of users who will be granted administrative privilages
-on the share. This means that they will do all file operations as the
-super-user (root).
-
-You should use this option very carefully, as any user in this list
-will be able to do anything they like on the share, irrespective of
-file permissions.
-
-.B Default:
- no admin users
-
-.B Example:
- admin users = jason
-
-.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
-that would otherwise not be visible.
-
-Note that if you just want all printers in your printcap file loaded
-then the "load printers" option is easier.
-
-.B Default:
- no auto services
-
-.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.
-
-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).
-
-You can also specify hosts by network/netmask pairs and by netgroup
-names if your system supports netgroups. The EXCEPT keyword can also
-be used to limit a wildcard list. The following examples may provide
-some help:
-
-Example 1: allow all IPs in 150.203.*.* except one
-
- hosts allow = 150.203. EXCEPT 150.203.6.66
-
-Example 2: allow hosts that match the given network/netmask
-
- hosts allow = 150.203.15.0/255.255.255.0
-
-Example 3: allow a couple of hosts
-
- hosts allow = lapland, arvidsjaur
-
-Example 4: allow only hosts in netgroup "foonet" or localhost, but
-deny access from one particular host
-
- hosts allow = @foonet, localhost
- hosts deny = pirate
-
-Note that access still requires suitable user-level passwords.
-
-See testparm(1) for a way of testing your host access to see if it
-does what you expect.
-
-.B Default:
- none (ie., all hosts permitted access)
-
-.B Example:
- allow hosts = 150.203.5. myhost.mynet.edu.au
-
-.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
-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
-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.
-
-.B Default:
- alternate permissions = no
-
-.B Example:
- alternate permissions = yes
-
-.SS available (S)
-This parameter lets you 'turn off' a service. If 'available = no', then
-ALL attempts to connect to the service will fail. Such failures are logged.
-
-.B Default:
- available = yes
-
-.B Example:
- available = no
-.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.
-
-.B Default:
- browseable = Yes
-
-.B Example:
- browseable = No
-
-.SS case sig names (G)
-See "case sensitive"
-
-.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.
-
-.B Default:
- No comment string
-
-.B Example:
- comment = Fred's Files
-
-.SS config file (G)
-
-This allows you to override the config file to use, instead of the
-default (usually smb.conf). There is a chicken and egg problem here as
-this option is set in the config file!
-
-For this reason, if the name of the config file has changed when the
-parameters are loaded then it will reload them from the new config
-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
-you to special case the config files of just a few clients).
-
-.B Example:
- config file = /usr/local/samba/smb.conf.%m
-
-.SS copy (S)
-This parameter allows you to 'clone' service entries. The specified
-service is simply duplicated under the current service's name. Any
-parameters specified in the current section will override those in the
-section being copied.
-
-This feature lets you set up a 'template' service and create similar
-services easily. Note that the service being copied must occur earlier
-in the configuration file than the service doing the copying.
-
-.B Default:
- none
-
-.B Example:
- copy = otherservice
-.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.
-
-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.
-
-.B Default:
- create mask = 0755
-
-.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
-is disconnected. The deadtime only takes effect if the number of open files
-is zero.
-
-This is useful to stop a server's resources being exhausted by a large
-number of inactive connections.
-
-Most clients have an auto-reconnect feature when a connection is broken so
-in most cases this parameter should be transparent to users.
-
-Using this parameter with a timeout of a few minutes is recommended
-for most systems.
-
-A deadtime of zero indicates that no auto-disconnection should be performed.
-
-.B Default:
- dead time = 0
-
-.B Example:
- 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
-greater flexibility in the configuration of the system.
-
-The default will be the debug level specified on the command line.
-
-.B Example:
- debug level = 3
-.SS default (G)
-See
-.B default service.
-.SS default case (S)
-
-See the section on "NAME MANGLING" Also note the addition of "short
-preserve case"
-
-.SS default service (G)
-A synonym for this parameter is 'default'.
-
-This parameter specifies the name of a service which will be connected to
-if the service actually requested cannot be found. Note that the square
-brackets are NOT given in the parameter value (see example below).
-
-There is no default value for this parameter. If this parameter is not given,
-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
-equal that of the requested service, this is very useful as it allows
-you to use macros like %S to make a wildcard service.
-
-Note also that any _ characters in the name of the service used in the
-default service will get mapped to a /. This allows for interesting
-things.
-
-
-.B Example:
- default service = pub
-
- [pub]
- path = /%S
-
-
-.SS deny hosts (S)
-A synonym for this parameter is 'hosts deny'.
-
-The opposite of 'allow hosts' - hosts listed here are NOT permitted
-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)
-
-.B Example:
- deny hosts = 150.203.4. badhost.mynet.edu.au
-.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
-been known to happen with Ultrix, but may occur with other operating
-systems. The symptom that was seen was an error of "Abort Retry
-Ignore" at the end of each directory listing.
-
-This setting allows the replacement of the internal routines to
-calculate the total disk space and amount available with an external
-routine. The example below gives a possible script that might fulfill
-this function.
-
-The external program will be passed a single parameter indicating a
-directory in the filesystem being queried. This will typically consist
-of the string "./". The script should return two integers in ascii. The
-first should be the total disk space in blocks, and the second should
-be the number of available blocks. An optional third return value
-can give the block size in bytes. The default blocksize is 1024 bytes.
-
-Note: Your script should NOT be setuid or setgid and should be owned by
-(and writable only by) root!
-
-.B Default:
- By default internal routines for determining the disk capacity
-and remaining space will be used.
-
-.B Example:
- dfree command = /usr/local/smb/dfree
-
- Where the script dfree (which must be made executable) could be
-
- #!/bin/sh
- df $1 | tail -1 | awk '{print $2" "$4}'
-
- or perhaps (on Sys V)
-
- #!/bin/sh
- /usr/bin/df -k $1 | tail -1 | awk '{print $3" "$5}'
-
-
- Note that you may have to replace the command names with full
-path names on some systems.
-.SS directory (S)
-See
-.B path.
-.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
-(recursive). This parameter allows you to specify a comma-delimited list
-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
-"/proc". Experimentation is the best policy :-)
-
-.B Default:
- none (ie., all directories are OK to descend)
-
-.B Example:
- dont descend = /proc,/dev
-
-.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
-compiled in the necessary des libraries and encryption code. It
-defaults to no.
-
-.SS exec (S)
-
-This is an alias for preexec
-
-
-.SS force group (S)
-This specifies a group name that all connections to this service
-should be made as. This may be useful for sharing files.
-
-.B Default:
- no forced group
-
-.B Example:
- force group = agroup
-
-.SS force user (S)
-This specifies a user name that all connections to this service
-should be made as. This may be useful for sharing files. You should
-also use it carefully as using it incorrectly can cause security
-problems.
-
-This user name only gets used once a connection is established. Thus
-clients still need to connect as a valid user and supply a valid
-password. Once connected, all file operations will be performed as the
-"forced user", not matter what username the client connected as.
-
-.B Default:
- no forced user
-
-.B Example:
- force user = auser
-
-.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
-will be available to any client connecting to the guest
-service. Typically this user will exist in the password file, but will
-not have a valid login. If a username is specified in a given service,
-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.
-
-Note that as of version 1.9 of Samba this option may be set
-differently for each service.
-
-.B Default:
- specified at compile time
-
-.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.
-.SS guest only (S)
-If this parameter is 'yes' for a service, then only guest connections to the
-service are permitted. This parameter will have no affect if "guest ok" or
-"public" is not set for the service.
-
-See the section below on user/password validation for more information about
-this option.
-
-.B Default:
- guest only = no
-
-.B Example:
- guest only = yes
-.SS hide dot files (S)
-This is a boolean parameter that controls whether files starting with
-a dot appear as hidden files.
-
-.B Default:
- hide dot files = yes
-
-.B Example:
- hide dot files = no
-.SS hosts allow (S)
-See
-.B allow hosts.
-.SS hosts deny (S)
-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
-without specifying a password.
-
-This is not be confused with
-.B allow hosts
-which is about hosts access to services and is more useful for guest services.
-.B hosts equiv
-may be useful for NT clients which will not supply passwords to samba.
-
-NOTE: The use of hosts.equiv can be a major security hole. This is
-because you are trusting the PC to supply the correct username. It is
-very easy to get a PC to supply a false username. I recommend that the
-hosts.equiv option be only used if you really know what you are doing,
-or perhaps on a home network where you trust your wife and kids :-)
-
-.B Default
- No host equivalences
-
-.B Example
- hosts equiv = /etc/hosts.equiv
-
-.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.
-
-The current servicename is substituted for %S. This is useful in the
-[homes] section.
-
-See also "valid users"
-
-.B Default
- No invalid 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
-will be sent. Keepalive packets, if sent, allow the server to tell whether a
-client is still present and responding.
-
-Keepalives should, in general, not be needed if the socket being used
-has the SO_KEEPALIVE attribute set on it (see "socket
-options"). Basically you should only use this option if you strike
-difficulties.
-
-.B Default:
- keep alive = 0
-
-.B Example:
- keep alive = 60
-.SS load printers (G)
-A boolean variable that controls whether all printers in the printcap
-will be loaded for browsing by default.
-
-.B Default:
- load printers = no
-
-.B Example:
- load printers = yes
-
-.SS lock directory (G)
-This options 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
-.SS locking (S)
-This controls whether or not locking will be performed by the server in
-response to lock requests from the client.
-
-If "locking = no", all lock and unlock requests will appear to succeed and
-all lock queries will indicate that the queried lock is clear.
-
-If "locking = yes", real locking will be performed by the server.
-
-This option may be particularly useful for read-only filesystems which
-do not need locking (such as cdrom drives).
-
-Be careful about disabling locking either globally or in a specific
-service, as lack of locking may result in data corruption.
-
-.B Default:
- locking = yes
-
-.B Example:
- locking = no
-
-.SS log file (G)
-
-This options allows you to override the name of the Samba log file
-(also known as the debug file).
-
-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
-
-.SS log level (G)
-see "debug level"
-
-.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.
-
-This command should be a program or script which takes a printer name and
-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.
-
-If a %p is given then the printername is put in it's 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
-priority is lower than the set fence priority it will have the PAUSED
-status, whereas if the priority is equal or higher it will have the
-SPOOLED or PRINTING status.
-
-Note that it is good practice to include the absolute path in the lppause
-command as the PATH may not be available to the server.
-
-.B Default:
- Currently no default value is given to this string
-
-.B Example for HPUX:
- lppause command = /usr/bin/lpalt %p-%j -p0
-
-.SS lpq cache time (G)
-
-This controls how long lpq info will be cached for to prevent the lpq
-command being called too often. A separate cache is kept for each
-variation of the lpq command used by the system, so if you use
-different lpq commands for different users then they won't share cache
-information.
-
-The cache files are stored in /tmp/lpq.xxxx where xxxx is a hash
-of the lpq command in use.
-
-The default is 10 seconds, meaning that the cached results of a
-previous identical lpq command will be used if the cached data is less
-than 10 seconds old. A large value may be advisable if your lpq
-command is very slow.
-
-A value of 0 will disable cacheing completely.
-
-.B Default:
- lpq cache time = 10
-
-.B Example:
- lpq cache time = 30
-
-.SS lpq command (S)
-This parameter specifies the command to be executed on the server host in
-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.
-
-Some clients (notably Windows for Workgroups) may not correctly send the
-connection number for the printer they are requesting status information
-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
-it is placed at the end of the command.
-
-Note that it is good practice to include the absolute path in the lpq
-command as the PATH may not be available to the server.
-
-.B Default:
- depends on the setting of "printing ="
-
-.B Example:
- lpq command = /usr/bin/lpq %p
-
-.SS lpresume command (S)
-This parameter specifies the command to be executed on the server host in
-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
-replaced with the job number (an integer).
-
-Note that it is good practice to include the absolute path in the lpresume
-command as the PATH may not be available to the server.
-
-.B Default:
- Currently no default value is given to this string
-
-.B Example for HPUX:
- lpresume command = /usr/bin/lpalt %p-%j -p2
-
-.SS lprm command (S)
-This parameter specifies the command to be executed on the server host in
-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.
-
-If a %p is given then the printername is put in it's 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
-command as the PATH may not be available to the server.
-
-.B Default:
- depends on the setting of "printing ="
-
-.B Example 1:
- lprm command = /usr/bin/lprm -P%p %j
-
-.B Example 2:
- lprm command = /usr/bin/cancel %p-%j
-
-.SS magic output (S)
-This parameter specifies the name of a file which will contain output
-created by a magic script (see
-.I magic script
-below).
-
-Warning: If two clients use the same magic script in the same directory the
-output file content is undefined.
-.B Default:
- magic output = <magic script name>.out
-
-.B Example:
- 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
-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
-permitting.
-
-If the script generates output, output will be sent to the file specified by
-the
-.I magic output
-parameter (see above).
-
-Note that some shells are unable to interpret scripts containing
-carriage-return-linefeed instead of linefeed as the end-of-line
-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 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
-used.
-
-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
-use a map of (*;1 *)
-
-.B default:
- no mangled map
-
-.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
-DOS-compatible names ("mangled") and made visible, or whether non-DOS names
-should simply be ignored.
-
-See the section on "NAME MANGLING" for details on how to control the
-mangling process.
-
-If mangling is used then the mangling algorithm is as follows:
-.RS
-- the first (up to) five alphanumeric characters before the rightmost dot of
-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
-(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.
-
-Note that the character to use may be specified using the "mangling
-char" option, if you don't like ~.
-
-- the first three alphanumeric characters of the final extension are preserved,
-forced to upper case and appear as the extension of the mangled name. The
-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. 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).
-.RE
-
-The two-digit hash value consists of upper case alphanumeric characters.
-
-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
-be renamed to a new extension from DOS and will retain the same basename.
-Mangled names do not change between sessions.
-
-.B Default:
- mangled names = yes
-
-.B Example:
- mangled names = no
-.SS mangling char (S)
-This controls what character is used as the "magic" character in name
-mangling. The default is a ~ but this may interfere with some
-software. Use this option to set it to whatever you prefer.
-
-.B Default:
- mangling char = ~
-
-.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.
-
-This stack is a list of recently mangled base names (extensions are only
-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
-sizes will slow most directory access. Smaller stacks save memory in the
-server (each stack element costs 256 bytes).
-
-It is not possible to absolutely guarantee correct long file names, so
-be prepared for some surprises!
-
-.B Default:
- mangled stack = 50
-
-.B Example:
- 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
-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...
-
-.B Default:
- map archive = yes
-
-.B Example:
- map archive = no
-
-.SS map hidden (S)
-This controls whether DOS style hidden files should be mapped to Unix
-execute bits.
-
-.B Default:
- map hidden = no
-
-.B Example:
- map hidden = yes
-.SS map system (S)
-This controls whether DOS style system files should be mapped to Unix
-execute bits.
-
-.B Default:
- map system = no
-
-.B Example:
- map system = yes
-.SS max connections (S)
-This option allows the number of simultaneous connections to a
-service to be limited. If "max connections" is greater than 0 then
-connections will be refused if this number of connections to the
-service are already open. A value of zero mean an unlimited number of
-connections may be made.
-
-Record lock files are used to implement this feature. The lock files
-will be stored in the directory specified by the "lock directory" option.
-
-.B Default:
- max connections = 0
-
-.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.
-
-.B Default:
- only user = False
-
-.B Example:
- only user = True
-
-.SS message command (G)
-
-This specifies what command to run when the server receives a WinPopup
-style message.
-
-This would normally be a command that would deliver the message
-somehow. How this is to be done is up to your imagination.
-
-What I use is:
-
- message command = csh -c 'xedit %s;rm %s' &
-
-This delivers the message using xedit, then removes it
-afterwards. NOTE THAT IT IS VERY IMPORTANT THAT THIS COMMAND RETURN
-IMMEDIATELY. That's why I have the & on the end. If it doesn't return
-immediately then your PCs may freeze when sending messages (they
-should recover after 30secs, hopefully).
-
-All messages are delivered as the global guest user. The command takes
-the standard substitutions, although %u won't work (%U may be better
-in this case).
-
-Apart from the standard substitutions, some additional ones apply. In
-particular:
-
-%s = the filename containing the message
-
-%t = the destination that the message was sent to (probably the server
-name)
-
-%f = who the message is from
-
-You could make this command send mail, or whatever else takes your
-fancy. Please let me know of any really interesting ideas you have.
-
-Here's a way of sending the messages as mail to root:
-
-message command = /bin/mail -s 'message from %f on %m' root < %s; rm %s
-
-If you don't have a message command then the message won't be
-delivered and Samba will tell the sender there was an
-error. Unfortunately WfWg totally ignores the error code and carries
-on regardless, saying that the message was delivered.
-
-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 \\
- -M %m; rm %s' &
-
-this would execute the command as a script on the server, then give
-them the result in a WinPopup message. Note that this could cause a
-loop if you send a message from the server using smbclient! You better
-wrap the above in a script that checks for this :-)
-
-.B Default:
- no message command
-
-.B Example:
- message command = csh -c 'xedit %s;rm %s' &
-
-.SS min print space (S)
-
-This sets the minimum amount of free disk space that must be available
-before a user will be able to spool a print job. It is specified in
-kilobytes. The default is 0, which means no limit.
-
-.B Default:
- min print space = 0
-
-.B Example:
- min print space = 2000
-
-.SS null passwords (G)
-Allow or disallow access to accounts that have null passwords.
-
-.B Default:
- null passwords = no
-
-.B Example:
- null passwords = yes
-
-.SS os level (G)
-This integer value controls what level Samba advertises itself as for
-browse elections. See BROWSING.txt for details.
-
-.SS packet size (G)
-The maximum transmit packet size during a raw read. This option is no
-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
-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
-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,
-tab and space.
-
-The string can also contain a * which matches any sequence of
-characters.
-
-Double quotes can be used to collect strings with spaces in them into
-a single string.
-
-If the send string in any part of the chat sequence is a fullstop "."
-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*"
-
-.B Default:
- passwd chat = *old*password* %o\\n *new*password* %n\\n *new*password* %n\\n *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
-name.
-
-Also note that many passwd programs insist in "reasonable" passwords,
-such as a minimum length, or the inclusion of mixed case chars and
-digits. This can pose a problem as some clients (such as Windows for
-Workgroups) uppercase the password before sending it.
-
-.B Default:
- passwd program = /bin/passwd
-
-.B Example:
- passwd program = /sbin/passwd %u
-
-.SS password level (G)
-Some client/server conbinations 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!
-
-This parameter defines the maximum number of characters that may be upper case
-in passwords.
-
-For example, say the password given was "FRED". If
-.B password level
-is set to 1 (one), the following combinations would be tried if "FRED" failed:
-"Fred", "fred", "fRed", "frEd", "freD". If
-.B password level was set to 2 (two), the following combinations would also be
-tried: "FRed", "FrEd", "FreD", "fREd", "fReD", "frED". And so on.
-
-The higher value this parameter is set to the more likely it is that a mixed
-case password will be matched against a single case password. However, you
-should be aware that use of this parameter reduces security and increases the
-time taken to process a new connection.
-
-A value of zero will cause only two attempts to be made - the password as is
-and the password in all-lower case.
-
-If you find the connections are taking too long with this option then
-you probably have a slow crypt() routine. Samba now comes with a fast
-"ufc crypt" that you can select in the Makefile. You should also make
-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
-right length for your system.
-
-.B Default:
- password level = 0
-
-.B Example:
- password level = 4
-
-.SS password server (G)
-
-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.
-
-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
-/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
-only as secure as your password server. DO NOT CHOOSE A PASSWORD
-SERVER THAT YOU DON'T COMPLETELY TRUST.
-
-Never point a Samba server at itself for password serving. This will
-cause a loop and could lock up your Samba server!
-
-The name of the password server takes the standard substitutions, but
-probably the only useful one is %m, which means the Samba server will
-use the incoming client as the password server. If you use this then
-you better trust your clients, and you better restrict them with hosts
-allow!
-
-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.
-
-.SS path (S)
-A synonym for this parameter is 'directory'.
-
-This parameter specifies a directory to which the user of the service is to
-be given access. In the case of printable services, this is where print data
-will spool prior to being submitted to the host for printing.
-
-For a printable service offering guest access, the service should be readonly
-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
-replaced by the name of the machine they are connecting from. These
-replacements are very useful for setting up pseudo home directories
-for users.
-
-Note that this path will be based on 'root dir' if one was specified.
-.B Default:
- none
-
-.B Example:
- path = /home/fred+
-
-.SS postexec (S)
-
-This option specifies a command to be run whenever the service is
-disconnected. It takes the usual substitutions. The command may be run
-as the root on some systems.
-
-An interesting example may be do unmount server resources:
-
-postexec = /etc/umount /cdrom
-
-See also preexec
-
-.B Default:
- none (no command executed)
-
-.B Example:
- postexec = echo \"%u disconnected from %S from %m (%I)\" >> /tmp/log
-
-.SS postscript (S)
-This parameter forces a printer to interpret the print files as
-postscript. This is done by adding a %! to the start of print output.
-
-This is most useful when you have lots of PCs that persist in putting
-a control-D at the start of print jobs, which then confuses your
-printer.
-
-.B Default:
- postscript = False
-
-.B Example:
- postscript = True
-
-.SS preexec (S)
-
-This option specifies a command to be run whenever the service is
-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' &
-
-Of course, this could get annoying after a while :-)
-
-See also postexec
-
-.B Default:
- none (no command executed)
-
-.B Example:
- preexec = echo \"%u connected to %S from %m (%I)\" >> /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.
-
-It is on by default.
-
-.SS preload
-This is an alias for "auto services"
-
-.SS preserve case (S)
-
-This controls if new filenames are created with the case that the
-client passes, or if they are forced to be the "default" case.
-
-.B Default:
- preserve case = no
-
-See the section on "NAME MANGLING" for a fuller discussion.
-
-.SS print command (S)
-After a print job has finished spooling to a service, this command will be
-used via a system() call to process the spool file. Typically the command
-specified will submit the spool file to the host's printing subsystem, but
-there is no requirement that this be the case. The server will not remove the
-spool file, so whatever command you specify should remove the spool file when
-it has been processed, otherwise you will need to manually remove old spool
-files.
-
-The print command is simply a text string. It will be used verbatim,
-with two exceptions: All occurrences of "%s" will be replaced by the
-appropriate spool file name, and all occurrences of "%p" will be
-replaced by the appropriate printer name. The spool file name is
-generated automatically by the server, the printer name is discussed
-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
-filename without the full path at the front.
-
-The print command MUST contain at least one occurrence of "%s" or %f -
-the "%p" is optional. At the time a job is submitted, if no printer
-name is supplied the "%p" will be silently removed from the printer
-command.
-
-If specified in the [global] section, the print command given will be used
-for any printable service that does not have its own print command specified.
-
-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"
-account. If this happens then create an alternative guest account that
-can print and set the "guest account" in the [global] section.
-
-You can form quite complex print commands by realising that they are
-just passed to a shell. For example the following will log a print
-job, print the file, then remove it. Note that ; is the usual
-separator for command in shell scripts.
-
-print command = echo Printing %s >> /tmp/print.log; lpr -P %p %s; rm %s
-
-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
-
-.B Example:
- print command = /usr/local/samba/myprintscript %p %s
-.SS print ok (S)
-See
-.B printable.
-.SS printable (S)
-A synonym for this parameter is 'print ok'.
-
-If this parameter is 'yes', then clients may open, write to and submit spool
-files on the directory specified for the service.
-
-Note that a printable service will ALWAYS allow writing to the service path
-(user privileges permitting) via the spooling of print data. The 'read only'
-parameter controls only non-printing access to the resource.
-
-.B Default:
- printable = no
-
-.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
-[printers] section above for reasons why you might want to do this.
-
-For those of you without a printcap (say on SysV) you can just create a
-minimal file that looks like a printcap and set "printcap name =" in
-[global] to point at it.
-
-A minimal printcap file would look something like this:
-
-print1|My Printer 1
-print2|My Printer 2
-print3|My Printer 3
-print4|My Printer 4
-print5|My Printer 5
-
-where the | separates aliases of a printer. The fact that the second
-alias has a space in it gives a hint to Samba that it's a comment.
-
-NOTE: Under AIX the default printcap name is "/etc/qconfig". Samba
-will assume the file is in AIX "qconfig" format if the string
-"/qconfig" appears in the printcap filename.
-
-.B Default:
- printcap name = /etc/printcap
-
-.B Example:
- printcap name = /etc/myprintcap
-.SS printer (S)
-A synonym for this parameter is 'printer name'.
-
-This parameter specifies the name of the printer to which print jobs spooled
-through a printable service will be sent.
-
-If specified in the [global] section, the printer name given will be used
-for any printable service that does not have its own printer name specified.
-
-.B Default:
- none (but may be 'lp' on many systems)
-
-.B Example:
- printer name = laserwriter
-.SS printer name (S)
-See
-.B printer.
-.SS protocol (G)
-The value of the parameter (a string) is the highest protocol level that will
-be supported by the server.
-
-Possible values are CORE, COREPLUS, LANMAN1, LANMAN2 and NT1. The relative
-merits of each are discussed in the README file.
-
-.B Default:
- protocol = NT1
-
-.B Example:
- protocol = LANMAN1
-.SS public (S)
-A synonym for this parameter is 'guest ok'.
-
-If this parameter is 'yes' for a service, then no password is required
-to connect to the service. Privileges will be those of the guest
-account.
-
-See the section below on user/password validation for more information about
-this option.
-
-.B Default:
- public = no
-
-.B Example:
- public = yes
-.SS read list (S)
-This is a list of users that are given read-only access to a
-service. If the connecting user is in this list then they will
-not be given write access, no matter what the "read only" option
-is set to. The list can include group names using the @group syntax.
-
-See also the "write list" option
-
-.B Default:
- read list =
-
-.B Example:
- read list = mary, @students
-
-.SS read only (S)
-See
-.B writable
-and
-.B write ok.
-Note that this is an inverted synonym for writable and write ok.
-.SS read prediction (G)
-This options enables or disables the read prediction code used to
-speed up reads from the server. When enabled the server will try to
-pre-read data from the last accessed file that was opened read-only
-while waiting for packets.
-
-.SS Default:
- read prediction = False
-
-.SS Example:
- read prediction = True
-.SS read raw (G)
-This parameter controls whether or not the server will support raw reads when
-transferring data to clients.
-
-If enabled, raw reads allow reads of 65535 bytes in one packet. This
-typically provides a major performance benefit.
-
-However, some clients either negotiate the allowable block size incorrectly
-or are incapable of supporting larger block sizes, and for these clients you
-may need to disable raw reads.
-
-In general this parameter should be viewed as a system tuning tool and left
-severely alone. See also
-.B write raw.
-
-.B Default:
- read raw = yes
-
-.B Example:
- read raw = no
-.SS read size (G)
-
-The option "read size" affects the overlap of disk reads/writes with
-network reads/writes. If the amount of data being transferred in
-several of the SMB commands (currently SMBwrite, SMBwriteX and
-SMBreadbraw) is larger than this value then the server begins writing
-the data before it has received the whole packet from the network, or
-in the case of SMBreadbraw, it begins writing to the network before
-all the data has been read from disk.
-
-This overlapping works best when the speeds of disk and network access
-are similar, having very little effect when the speed of one is much
-greater than the other.
-
-The default value is 2048, but very little experimentation has been
-done yet to determine the optimal value, and it is likely that the best
-value will vary greatly between systems anyway. A value over 65536 is
-pointless and will cause you to allocate memory unnecessarily.
-
-.B Default:
- read size = 2048
-
-.B Example:
- read size = 8192
-
-.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
-automatically allow the client to request connection to the second
-share as the same username as the first without a password.
-
-If "revalidate" is True then the client will be denied automatic
-access as the same username.
-
-.B Default:
- revalidate = False
-
-.B Example:
- revalidate = True
-
-.SS root (G)
-See
-.B root directory.
-.SS root dir (G)
-See
-.B root directory.
-.SS root directory (G)
-Synonyms for this parameter are 'root dir' and 'root'.
-
-The server will chroot() to this directory on startup. This is not
-strictly necessary for secure operation. Even without it the server
-will deny access to files not in one of the service entries. It may
-also check for, and deny access to, soft links to other parts of the
-filesystem, or attempts to use .. in file names to access other
-directories (depending on the setting of the "wide links" parameter).
-
-Adding a "root dir" entry other than "/" adds an extra level of security,
-but at a price. It absolutely ensures that no access is given to files not
-in the sub-tree specified in the "root dir" option, *including* some files
-needed for complete operation of the server. To maintain full operability
-of the server you will need to mirror some system files into the "root dir"
-tree. In particular you will need to mirror /etc/passwd (or a subset of it),
-and any binaries or configuration files needed for printing (if required).
-The set of files that must be mirrored is operating system dependent.
-
-.B Default:
- root directory = /
-
-.B Example:
- root directory = /homes/smb
-.SS security (G)
-This option does 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
-whether (and how) to transfer user and password information to the server.
-
-The default is "security=SHARE", mainly because that was the only
-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
-"security = share".
-
-There is a bug in WfWg that may affect your decision. When in user
-level security a WfWg client will totally ignore the password you type
-in the "connect drive" dialog box. This makes it very difficult (if
-not impossible) to connect to a Samba service as anyone except the
-user that you are logged into WfWg as.
-
-If you use "security = server" then Samba will try to validate the
-username/password by passing it to another SMB server, such as an NT
-box. If this fails it will revert to "security = USER".
-
-See the "password server" option for more details.
-
-.B Default:
- security = SHARE
-
-.B Example:
- security = USER
-.SS server string (G)
-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.
-
-A %v will be replaced with the Samba version number.
-
-A %h will be replaced with the hostname.
-
-.B Default:
- server string = Samba %v
-
-.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.
-
-You must get this path right for many services to work correctly.
-
-.B Default: taken from Makefile
-
-.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.
-
-.B Default:
- short preserve case = no
-
-See the section on "NAME MANGLING" for a fuller discussion.
-
-.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 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 set directory (S)
-If 'set directory = no', then users of the service may not use the setdir
-command to change directory.
-
-The setdir comand is only implemented in the Digital Pathworks client. See the
-Pathworks documentation for details.
-.B Default:
- set directory = no
-
-.B Example:
- set directory = yes
-
-.SS share modes (S)
-
-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
-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.
-
-.B Default:
- share modes = yes
-
-.B Example:
- share modes = no
-
-.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
-the client.
-
-Socket options are controls on the networking layer of the operating
-systems which allow the connection to be tuned.
-
-This option will typically be used to tune your Samba server for
-optimal performance for your local network. There is no way that Samba
-can know what the optimal parameters are for your net, so you must
-experiment and choose them yourself. I strongly suggest you read the
-appropriate documentation for your operating system first (perhaps
-"man setsockopt" will help).
-
-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).
-
-Any of the supported socket options may be combined in any way you
-like, as long as your OS allows it.
-
-This is the list of socket options currently settable using this
-option:
-
- SO_KEEPALIVE
-
- SO_REUSEADDR
-
- SO_BROADCAST
-
- TCP_NODELAY
-
- IPTOS_LOWDELAY
-
- IPTOS_THROUGHPUT
-
- SO_SNDBUF *
-
- SO_RCVBUF *
-
- SO_SNDLOWAT *
-
- SO_RCVLOWAT *
-
-Those marked with a * take an integer argument. The others can
-optionally take a 1 or 0 argument to enable or disable the option, by
-default they will be enabled if you don't specify 1 or 0.
-
-To specify an argument use the syntax SOME_OPTION=VALUE for example
-SO_SNDBUF=8192. Note that you must not have any spaces before or after
-the = sign.
-
-If you are on a local network then a sensible option might be
-
-socket options = IPTOS_LOWDELAY
-
-If you have an almost unloaded local network and you don't mind a lot
-of extra CPU usage in the server then you could try
-
-socket options = IPTOS_LOWDELAY TCP_NODELAY
-
-If you are on a wide area network then perhaps try setting
-IPTOS_THROUGHPUT.
-
-Note that several of the options may cause your Samba server to fail
-completely. Use these options with caution!
-
-.B Default:
- no socket options
-
-.B Example:
- socket options = IPTOS_LOWDELAY
-
-
-
-
-.SS status (G)
-This enables or disables logging of connections to a status file that
-smbstatus can read.
-
-With this disabled smbstatus won't be able to tell you what
-connections are active.
-
-.B Default:
- status = yes
-
-.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
-write access for file locks, and deny access if locks exist. This can
-be slow on some systems.
-
-When strict locking is "no" the server does file lock checks only when
-the client explicitly asks for them.
-
-Well behaved clients always ask for lock checks when it is important,
-so in the vast majority of cases "strict locking = no" is preferable.
-
-.B Default:
- strict locking = no
-
-.B Example:
- strict locking = yes
-
-.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
-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.
-
-.B Default:
- sync always = no
-
-.B Example:
- sync always = yes
-
-.SS time offset (G)
-This parameter is a setting in minutes to add to the normal GMT to
-local time conversion. This is useful if you are serving a lot of PCs
-that have incorrect daylight saving time handling.
-
-.B Default:
- time offset = 0
-
-.B Example:
- time offset = 60
-
-.SS user (S)
-See
-.B username.
-.SS username (S)
-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
-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
-instead.
-
-The username= line is not a great solution in many cases as it means Samba
-will try to validate the supplied password against each of the
-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
-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
-damage than if they started a telnet session. The daemon runs as the
-user that they log in as, so they cannot do anything that user cannot
-do.
-
-To restrict a service to a particular set of users you can use the
-"valid users=" line.
-
-If any of the usernames begin with a @ then the name will be looked up
-in the groups file and will expand to a list of all users in the group
-of that name. Note that searching though a groups file can take quite
-some time, and some clients may time out during the search.
-
-See the section below on username/password validation for more information
-on how this parameter determines access to the services.
-
-.B Default:
- The guest account if a guest service, else the name of the service.
-
-.B Examples:
- username = fred
- username = fred, mary, jack, jane, @users, @pcgroup
-
-.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
-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
-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
-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
-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
-name "root" you would use
-
- root = admin administrator
-
-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
-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
-to the "password server" (if you have one). The password server will
-receive whatever username the client supplies without modification.
-
-Also note that no reverse mapping is done. The main effect this has is
-with printing. Users who have been mapped may have trouble deleting
-print jobs as PrintManager under WfWg will think they don't own the
-print job.
-
-.B Default
- no username map
-
-.B Example
- username map = /usr/local/samba/lib/users.map
-
-.SS valid chars (S)
-
-The option allows you to specify additional characters that should be
-considered valid by the server in filenames. This is particularly
-useful for national character sets, such as adding u-umlaut or a-ring.
-
-The option takes a list of characters in either integer or character
-form with spaces between them. If you give two characters with a colon
-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
-using the usual C notation.
-
-For example to add the single character 'Z' to the charset (which is a
-pointless thing to do as it's already there) you could do one of the
-following
-
-valid chars = Z
-valid chars = z:Z
-valid chars = 0132:0172
-
-The last two examples above actually add two characters, and alters
-the uppercase and lowercase mappings appropriately.
-
-.B Default
- Samba defaults to using a reasonable set of valid characters
- for english systems
-
-.B Example
- valid chars = 0345:0305 0366:0326 0344:0304
-
-The above example allows filenames to have the swedish characters in
-them.
-
-.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.
-
-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
-denied for that user.
-
-The current servicename is substituted for %S. This is useful in the
-[homes] section.
-
-See also "invalid users"
-
-.B Default
- No valid users list. (anyone can login)
-
-.B Example
- valid users = greg, @pcusers
-
-.SS volume (S)
-This allows you to override the volume label returned for a
-share. Useful for CDROMs whos installation programs 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
-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.
-
-.B Default:
- wide links = yes
-
-.B Example:
- wide links = 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.
-
-.B Default:
- set in the Makefile
-
-.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'.
-
-If this parameter is 'no', then users of a service may not create or modify
-files in the service's directory.
-
-Note that a printable service ('printable = yes') will ALWAYS allow
-writing to the directory (user privileges permitting), but only via
-spooling operations.
-
-.B Default:
- writable = no
-
-.B Examples:
- read only = no
- writable = yes
- write ok = yes
-.SS write list (S)
-This is a list of users that are given read-write access to a
-service. If the connecting user is in this list then they will be
-given write access, no matter what the "read only" option is set
-to. The list can include group names using the @group syntax.
-
-Note that if a user is in both the read list and the write list then
-they will be given write access.
-
-See also the "read list" option
-
-.B Default:
- write list =
-
-.B Example:
- write list = admin, root, @staff
-
-.SS write raw (G)
-This parameter controls whether or not the server will support raw writes when
-transferring data from clients.
-
-.B Default:
- write raw = yes
-
-.B Example:
- write raw = no
-.SH NOTE ABOUT USERNAME/PASSWORD VALIDATION
-There are a number of ways in which a user can connect to a
-service. The server follows the following steps in determining if it
-will allow a connection to a specified service. If all the steps fail
-then the connection request is rejected. If one of the steps pass then
-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
-programs then the connection is made as that username. Note that this
-includes the \\\\server\\service%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
-are checked against the supplied password, if they match then the
-connection is allowed as the corresponding user.
-
-Step 4: If the client has previously validated a username/password
-pair with the server and the client has passed the validation token
-then that username is used. This step is skipped if "revalidate = yes"
-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
-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
-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,
-so it shouldn't be a problem - but be aware of the possibility.
-
-On a similar note, many clients - especially DOS clients - limit service
-names to eight characters. Smbd has no such limitation, but attempts
-to connect from such clients will fail if they truncate the service names.
-For this reason you should probably keep your service names down to eight
-characters in length.
-
-Use of the [homes] and [printers] special sections make life for an
-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
-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.
-
-Prior to version 1.5.21 of the Samba suite, the configuration file was
-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)
-.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.
-
-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.
-
-Please send bug reports, comments and so on to:
-
-.RS 3
-.B samba-bugs@anu.edu.au (Andrew Tridgell)
-
-.RS 3
-or to the mailing list
-.RE
-
-.B samba@listproc.anu.edu.au
-
-.RE
-You may also like to subscribe to the announcement channel
-
-.RS 3
-samba-announce@listproc.anu.edu.au
-.RE
-
-To subscribe to these lists send a message to
-listproc@listproc.anu.edu.au with a body of "subscribe samba Your
-Name" or "subscribe samba-announce Your Name".
-
-Errors or suggestions for improvements to the Samba man pages should be
-mailed to:
-
-.RS 3
-.B samba-bugs@anu.edu.au (Andrew Tridgell)
-.RE
-
diff --git a/docs/manpages/smbclient.1 b/docs/manpages/smbclient.1
deleted file mode 100644
index 5590e01296e..00000000000
--- a/docs/manpages/smbclient.1
+++ /dev/null
@@ -1,1133 +0,0 @@
-.TH SMBCLIENT 1 17/1/1995 smbclient smbclient
-.SH NAME
-smbclient \- ftp-like Lan Manager client program
-.SH SYNOPSIS
-.B smbclient
-.B servicename
-[
-.B password
-] [
-.B -A
-] [
-.B -E
-] [
-.B -L
-.I host
-] [
-.B -M
-.I host
-] [
-.B -I
-.I IP number
-] [
-.B -N
-] [
-.B -P
-] [
-.B -U
-.I username
-] [
-.B -d
-.I debuglevel
-] [
-.B -l
-.I log basename
-] [
-.B -n
-.I netbios name
-] [
-.B -O
-.I socket options
-] [
-.B -p
-.I port number
-.B -T
-.I tar options
-.B -D
-.I initial directory
-]
-.SH DESCRIPTION
-This program is part of the Samba suite.
-
-.B smbclient
-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
-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"
-where
-.B server
-is the netbios name of the Lan Manager server offering the desired service and
-.B service
-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"
-.RE
-
-Note that the server name required is NOT necessarily the host name of the
-server! The name required is a Lan Manager server name, which may or may not
-be the same as the hostname of the machine running the server.
-.RE
-
-.B password
-.RS 3
-.B
-password
-is the password required to access the specified service on the
-specified server. If supplied, the
-.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
-option (see below)) and
-.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
-required, simply press ENTER to provide a null password.)
-
-Note: Some servers (including OS/2 and Windows for Workgroups) insist
-on an uppercase password. Lowercase or mixed case passwords may be
-rejected by these servers.
-
-Be cautious about including passwords in scripts.
-.RE
-
-.B -A
-
-.RS 3
-This parameter, if specified, causes the maximum debug level to be selected.
-Be warned that this generates prodigious amounts of debug data. There is also
-a security issue involved, as at the maximum debug level cleartext passwords
-may be written to some log files.
-.RE
-
-.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
-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.
-.RE
-
-.B -M
-
-.RS 3
-This options allows you to send messages, using the "WinPopup"
-protocol, to another computer. Once a connection is established you
-then type your message, pressing ^D (control-D) to end.
-
-If the receiving computer is running WinPopup the user will receive
-the message and probably a beep. If they are not running WinPopup the
-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:
-
-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
-control the FROM and TO parts of the message.
-
-Samba currently has no way of receiving WinPopup messages.
-
-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
-
-.RS 3
-This parameter, if specified, causes the client to write messages to the
-standard error stream (stderr) rather than to the standard output stream.
-
-By default, the client writes messages to standard output - typically the
-user's tty.
-.RE
-
-.B -I
-.I IP number
-
-.RS 3
-.I IP number
-represents the IP number of the server to connect to. It should
-be specified in standard "a.b.c.d" notation.
-
-Normally the client will attempt to locate the specified Lan Manager server
-by looking it up - that is, broadcasting a request for the given server to
-identify itself. Using this parameter will force the client to assume that
-the server is on the machine with the specified IP number.
-
-There is no default for this parameter. If not supplied, it will be determined
-automatically by the client as described above.
-.RE
-
-.B -N
-
-.RS 3
-If specified, this parameter suppresses the normal password prompt from the
-client to the user. This is useful when accessing a service that does not
-require a password.
-
-Unless a password is specified on the command line or this parameter is
-specified, the client will request a password.
-.RE
-
-.B -O
-.I socket options
-.RS 3
-
-See the socket options section of smb.conf(5) for details
-
-.RE
-.B -P
-
-.RS 3
-If specified, the service requested will be connected to as a printer service
-rather than as a normal filespace service. Operations such as put and get
-will not be applicable for such a connection.
-
-By default, services will be connected to as NON-printer services.
-.RE
-
-.B -U
-.I username
-
-.RS 3
-.I username
-is the user name that will be used by the client to make a connection,
-assuming your server is running a protocol that allows for usernames.
-
-Some servers are fussy about the case of this name, and some insist
-that it must be a valid netbios name.
-
-If no
-.I username
-is supplied, it will default to an uppercase version of the
-environment variable
-.B USER
-or
-.B LOGNAME
-in that order.
-If no
-.I username
-is supplied and neither environment variable exists the user name will
-be empty.
-
-If the service you are connecting to requires a password, it can be supplied
-using the
-.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
-.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
-option (suppress password prompt) is assumed.
-
-If you specify the password as a parameter AND as part of
-.I username
-then the password as part of
-.I username
-will take precedence. Putting nothing before or nothing after the percent
-symbol will cause an empty username or an empty password to be used,
-respectively.
-
-Note: Some servers (including OS/2 and Windows for Workgroups) insist
-on an uppercase password. Lowercase or mixed case passwords may be
-rejected by these servers.
-
-Be cautious about including passwords in scripts.
-.RE
-
-.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 client. 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.
-.RE
-
-.B -l
-.I log basename
-
-.RS 3
-If specified,
-.I log basename
-specifies a base filename into which operational data from the running client
-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.client.debug (containing debugging information)
-
-log.client.in (containing inbound transaction data)
-
-log.client.out (containing outbound transaction data)
-.RE
-
-The log files generated are never removed by the client.
-.RE
-.RE
-
-.B -n
-.I netbios name
-
-.RS 3
-By default, the client will use the local machine's hostname (in
-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
-.RS 3
-
-port number is a positive integer value.
-
-The default value if this parameter is not specified is 139.
-
-This number is the port number that will be used when making connections to
-the server. The standard (well-known) port number for the server is 139,
-hence the default.
-
-This parameter is not normally specified.
-
-.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:
-.LP
-smbclient
-.B "\\\\\\\\server\\\\share"
-\-TcxIXbgNa
-[
-.IR blocksize
-]
-[
-.IR newer-file
-]
-.IR tarfile
-[
-.IR filenames....
-]
-
-.RS3
-.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.
-
-.B x
-Extract (restore) a local tar file back to a share. Unless the -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.
-
-.B I
-Include files and directories. Is the default behaviour when
-.IR filenames
-are specified above. Causes tar files to be included in an extract or create
-(and therefore everything else to be excluded). See example below.
-Filename globbing does not work for included files for extractions (yet).
-
-.B X
-Exclude files and directories. Causes tar files to be excluded from
-an extract or create. See example below.
-Filename globbing does not work for excluded files (yet).
-
-.B b
-Blocksize. Must be followed by a valid (greater than zero) blocksize.
-Causes tar file to be written out in blocksize*TBLOCK (usually 512 byte)
-blocks.
-
-.B g
-Incremental. Only back up files that have the archive bit set. Useful
-only with the 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.
-
-.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.
-.LP
-
-.B Examples
-
-smbclient \\\\mypc\\myshare "" -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
-
-Restore everything except users/docs
-
-smbclient \\\\mypc\\myshare "" -N -Tc backup.tar users/docs
-
-Create a tar file of the files beneath users/docs.
-
-.RE
-
-.B -D
-.I initial directory
-
-.RS3
-
-Change to initial directory before starting. Probably only of any use
-with the tar (\-T) option.
-
-
-.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,
-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
-command. Each command is a single word, optionally followed by parameters
-specific to that command. Command and parameters are space-delimited unless
-these notes specifically state otherwise. All commands are case-insensitive.
-Parameters to commands may or may not be case sensitive, depending on the
-command.
-
-You can specify file names which have spaces in them by quoting the
-name with double quotes, for example "a long file name".
-
-Parameters shown in square brackets (eg., "[parameter]") are optional. If not
-given, the command will use suitable defaults. Parameters shown in angle
-brackets (eg., "<parameter>") are required.
-
-Note that all commands operating on the server are actually performed by
-issuing a request to the server. Thus the behaviour may vary from server to
-server, depending on how the server was implemented.
-
-The commands available are given here in alphabetical order.
-
-.B ?
-.RS 3
-.B Parameters:
-.RS 3
-.I [command]
-
-.RE
-.B Description:
-.RS 3
-If
-.I command
-is specified, the
-.B ?
-command will display a brief informative message about the specified command.
-
-If no command is specified, a list of available commands will be displayed.
-.RE
-.RE
-
-.B !
-.RS 3
-.B Parameters:
-.RS 3
-.I [shell command]
-
-.RE
-.B Description:
-.RS 3
-If
-.I shell command
-is specified, the
-.B !
-command will execute a shell locally and run the specified shell command. If
-no command is specified, a shell will be run.
-.RE
-.RE
-
-.B cd
-.RS 3
-.B Parameters:
-.RS 3
-.I [directory name]
-
-.RE
-.B Description:
-.RS 3
-If
-.I directory name
-is specified, the current working directory
-.B on the server
-will be changed to the directory specified. This operation will fail if for
-any reason the specified directory is inaccessible.
-
-If no directory name is specified, the current working directory
-.B on the server
-will be reported.
-.RE
-.RE
-
-.B del
-.RS 3
-.B Parameters:
-.RS 3
-.I <mask>
-
-.RE
-.B Description:
-.RS 3
-The client will request that the server attempt to delete all files matching
-.I mask
-from the current working directory
-.B on the server.
-.RE
-.RE
-
-.B dir
-.RS 3
-.B Parameters:
-.RS 3
-.I <mask>
-
-.RE
-.B Description:
-.RS 3
-A list of the files matching
-.I mask
-in the current working directory
-.B on the server
-will be retrieved from the server and displayed.
-.RE
-.RE
-
-.B exit
-.RS 3
-.B Parameters:
-.RS 3
-None.
-
-.RE
-.B Description:
-.RS 3
-Terminate the connection with the server and exit from the program.
-.RE
-.RE
-
-.B get
-.RS 3
-.B Parameters:
-.RS 3
-.I <remote file name> [local file name]
-
-.RE
-.B Description:
-.RS 3
-Copy the file called
-.I remote file name
-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
-.B lowercase
-command.
-.RE
-.RE
-
-.B help
-.RS 3
-.B Parameters:
-.RS 3
-.I [command]
-
-.RE
-.B Description:
-.RS 3
-See the
-.B ?
-command above.
-.RE
-.RE
-
-.B lcd
-.RS 3
-.B Parameters:
-.RS 3
-.I [directory name]
-
-.RE
-.B Description:
-.RS 3
-If
-.I directory name
-is specified, the current working directory
-.B on the local machine
-will be changed to the directory specified. This operation will fail if for
-any reason the specified directory is inaccessible.
-
-If no directory name is specified, the name of the current working directory
-.B on the local machine
-will be reported.
-.RE
-.RE
-
-.B lowercase
-.RS 3
-.B Parameters:
-.RS 3
-None.
-
-.RE
-.B Description:
-.RS 3
-Toggle lowercasing of filenames for the
-.B get
-and
-.B mget
-commands.
-
-When lowercasing is toggled ON, local filenames are converted to lowercase
-when using the
-.B get
-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.
-.RE
-.RE
-
-.B ls
-.RS 3
-.B Parameters:
-.RS 3
-.I <mask>
-
-.RE
-.B Description:
-.RS 3
-See the
-.B dir
-command above.
-.RE
-.RE
-
-.B mask
-.RS 3
-.B Parameters:
-.RS 3
-.I <mask>
-
-.RE
-.B Description:
-.RS 3
-This command allows the user to set up a mask which will be used during
-recursive operation of the
-.B mget
-and
-.B mput
-commands.
-
-The masks specified to the
-.B mget
-and
-.B mput
-commands act as filters for directories
-rather than files when recursion is toggled ON.
-
-The mask specified with the
-.B mask
-command is necessary to filter files within those directories. For example,
-if the mask specified in an
-.B mget
-command is "source*"
-.I and
-the mask specified with the
-.B mask
-command is "*.c"
-.I and
-recursion is toggled ON, the
-.B mget
-command will retrieve all files matching "*.c" in all directories below
-and including all directories matching "source*" in the current working
-directory.
-
-Note that the value for
-.I mask
-defaults to blank (equivalent to "*") and remains so until the
-.B mask
-command is used to change it. It retains the most recently specified value
-indefinitely. To avoid unexpected results it would be wise to change the
-value of
-.I mask
-back to "*" after using the
-.B mget
-or
-.B mput
-commands.
-.RE
-.RE
-
-.B md
-.RS 3
-.B Parameters:
-.RS 3
-.I <directory name>
-
-.RE
-.B Description:
-.RS 3
-See the
-.B mkdir
-command.
-.RE
-.RE
-
-.B mget
-.RS 3
-.B Parameters:
-.RS 3
-.I <mask>
-
-.RE
-.B Description:
-.RS 3
-Copy all files matching
-.I mask
-from the server to the machine running the client.
-
-Note that
-.I mask
-is interpreted differently during recursive operation and non-recursive
-operation - refer to the
-.B recurse
-and
-.B mask
-commands for more information. Note that all transfers in smbclient are
-binary. See also the
-.B lowercase
-command.
-.RE
-.RE
-
-.B mkdir
-.RS 3
-.B Parameters:
-.RS 3
-.I <directory name>
-
-.RE
-.B Description:
-.RS 3
-Create a new directory
-.B on the server
-(user access privileges permitting) with the specified name.
-.RE
-.RE
-
-.B mput
-.RS 3
-.B Parameters:
-.RS 3
-.I <mask>
-
-.RE
-.B Description:
-.RS 3
-Copy all files matching
-.I mask
-in the current working directory
-.B on the local machine
-to the current working directory on the server.
-
-Note that
-.I mask
-is interpreted differently during recursive operation and non-recursive
-operation - refer to the
-.B recurse
-and
-.B mask
-commands for more information. Note that all transfers in smbclient are
-binary.
-.RE
-.RE
-
-.B print
-.RS 3
-.B Parameters:
-.RS 3
-.I <file name>
-
-.RE
-.B Description:
-.RS 3
-Print the specified file
-.B from the local machine
-through a printable service on the server.
-
-See also the
-.B printmode
-command.
-.RE
-.RE
-
-.B printmode
-.RS 3
-.B Parameters:
-.RS 3
-.I <graphics or text>
-
-.RE
-.B Description:
-.RS 3
-Set the print mode to suit either binary data (such as graphical information)
-or text. Subsequent
-.B print
-commands will use the currently set print mode.
-.RE
-.RE
-
-.B prompt
-.RS 3
-.B Parameters:
-.RS 3
-None.
-
-.RE
-.B Description:
-.RS 3
-Toggle prompting for filenames during operation of the
-.B mget
-and
-.B mput
-commands.
-
-When toggled ON, the user will be prompted to confirm the transfer of each
-file during these commands. When toggled OFF, all specified files will be
-transferred without prompting.
-.RE
-.RE
-
-.B put
-.RS 3
-.B Parameters:
-.RS 3
-.I <local file name> [remote file name]
-
-.RE
-.B Description:
-.RS 3
-Copy the file called
-.I local file name
-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
-.B lowercase
-command.
-.RE
-.RE
-
-.B queue
-.RS 3
-.B Parameters:
-.RS 3
-None.
-
-.RE
-.B Description:
-.RS 3
-Displays the print queue, showing the job id, name, size and current status.
-.RE
-.RE
-
-.B quit
-.RS 3
-.B Parameters:
-.RS 3
-None.
-
-.RE
-.B Description:
-.RS 3
-See the
-.B exit
-command.
-.RE
-.RE
-
-.B rd
-.RS 3
-.B Parameters:
-.RS 3
-.I <directory name>
-
-.RE
-.B Description:
-.RS 3
-See the
-.B rmdir
-command.
-.RE
-.RE
-
-.B recurse
-.RS 3
-.B Parameters:
-.RS 3
-None.
-
-.RE
-.B Description:
-.RS 3
-Toggle directory recursion for the commands
-.B mget
-and
-.B 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
-files that match the mask specified using the
-.B mask
-command will be retrieved. See also the
-.mask
-command.
-
-When recursion is toggled OFF, only files from the current working
-directory on the source machine that match the mask specified to the
-.B mget
-or
-.B mput
-commands will be copied, and any mask specified using the
-.B mask
-command will be ignored.
-.RE
-.RE
-
-.B rm
-.RS 3
-.B Parameters:
-.RS 3
-.I <mask>
-
-.RE
-.B Description:
-.RS 3
-Remove all files matching
-.I mask
-from the current working directory
-.B on the server.
-.RE
-.RE
-
-.B rmdir
-.RS 3
-.B Parameters:
-.RS 3
-.I <directory name>
-
-.RE
-.B Description:
-.RS 3
-Remove the specified directory (user access privileges permitting)
-.B from the server.
-.RE
-.RE
-
-.B tar
-.RS 3
-.B Parameters:
-.RS 3
-.I <c|x>[IXbgNa]
-
-.RE
-.B Description:
-.RS 3
-Performs a tar operation - see -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
-work - use the command line option instead.
-.RE
-.RE
-
-.B blocksize
-.RS 3
-.B Parameters
-.RS 3
-.I <blocksize>
-
-.RE
-.B Description
-.RS 3
-Blocksize. Must be followed by a valid (greater than zero) blocksize.
-Causes tar file to be written out in blocksize*TBLOCK (usually 512 byte)
-blocks.
-.RE
-.RE
-
-.B tarmode
-.RS 3
-.B Parameters
-.RS 3
-.I <full|inc|reset|noreset>
-
-.RE
-.B Description
-.RS 3
-Changes tar's behaviour with regard to archive bits. In full mode,
-tar will back up everything regardless of the archive bit setting (this
-is the default mode). In incremental mode, tar will only back up files
-with the archive bit set. In reset mode, tar will reset the archive bit
-on all files it backs up (implies read/write share).
-.RE
-.RE
-
-.B setmode
-.RS 3
-.B Parameters
-.RS 3
-.I <filename> <perm=[+|-]rsha>
-
-.RE
-.B Description
-.RS 3
-A version of the DOS attrib command to set file permissions. For example,
-
-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
-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
-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
-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
-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!
-
-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
-user-accessible port (typically any port number over 1024) would
-provide a suitable test server.
-.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 client software, so it is possible that your version of
-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)
-
-.SH DIAGNOSTICS
-[This section under construction]
-
-Most diagnostics issued by the client are logged in a 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 client. 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.
-.SH CREDITS
-The original Samba software and related utilities were created by
-Andrew Tridgell (samba-bugs@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/smbd.8 b/docs/manpages/smbd.8
deleted file mode 100644
index bae41b2c479..00000000000
--- a/docs/manpages/smbd.8
+++ /dev/null
@@ -1,407 +0,0 @@
-.TH SMBD 8 17/1/1995 smbd smbd
-.SH NAME
-smbd \- provide SMB (aka LanManager) services to clients
-.SH SYNOPSIS
-.B smbd
-[
-.B -D
-] [
-.B -a
-] [
-.B -d
-.I debuglevel
-] [
-.B -l
-.I log file
-] [
-.B -p
-.I port number
-] [
-.B -O
-.I socket options
-] [
-.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.
-
-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
-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
-installation.
-
-A session is created whenever a client requests one. Each client gets a copy
-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.
-
-.SH OPTIONS
-.B -D
-
-.RS 3
-If specified, this parameter causes the server to operate as a daemon. That is,
-it detaches itself and runs in the background, fielding requests on the
-appropriate port.
-
-By default, the server will NOT operate as a daemon.
-.RE
-
-.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
-.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.
-.RE
-
-.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.debug (containing debugging information)
-
-log.in (containing inbound transaction data)
-
-log.out (containing outbound transaction data)
-.RE
-
-The log files generated are never removed by the server.
-.RE
-
-.B -O
-.I socket options
-.RS 3
-
-See the socket options section of smb.conf(5) for details
-
-.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.
-
-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 139, 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.
-
-This parameter is not normally specified except in the above situation.
-.RE
-
-.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.
-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.
-.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
-
-.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.
-.RE
-
-.B /etc/services
-
-.RS 3
-If running the server via the meta-daemon inetd, this file must contain a
-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
-
-.RS 3
-This file describes all the services the server is to make available to
-clients. See
-.B smb.conf(5) for more information.
-.RE
-.RE
-
-.SH LIMITATIONS
-
-On some systems 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
-
-.RS 3
-If no printer name is specified to printable services, most systems will
-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
-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. 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
-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.
-
-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 configuration file should be placed in a directory readable and writable
-only by root, as the configuration file controls security for the services
-offered by the server. The configuration file can be made readable by all if
-desired, but this is not necessary for correct operation of the server and
-is not recommended. A sample configuration file "smb.conf.sample" is supplied
-with the source to the server - this may be renamed to "smb.conf" and
-modified to suit your needs.
-
-The remaining notes will assume the following:
-
-.RS 3
-smbd (the server program) installed in /usr/local/smb
-
-smb.conf (the configuration file) 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, and may even be useful as a
-temporary substitute for something like ftp. When run this way, however, the
-server will only have the privileges of the user who ran it.
-
-To ensure that the server is run as a daemon whenever the machine is started,
-and to ensure that it runs as root so that it can serve multiple clients, you
-will need to modify the system startup files. Wherever appropriate (for
-example, in /etc/rc), insert the following line, substituting
-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
-.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 "OPTIONS" above.
-.SH RUNNING THE SERVER ON REQUEST
-If your system uses a meta-daemon such as inetd, you can arrange to have the
-smbd 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.
-
-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).
-
-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.
-
-Ensure that a line similar to the following is in /etc/services:
-
-.RS 3
-netbios-ssn 139/tcp
-.RE
-
-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-ssn stream tcp nowait root /usr/local/smb/smbd -d1
--l/var/adm/smblogs/log -s/usr/local/smb/smb.conf
-.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.
-
-Lastly, edit the configuration file to provide suitable services. To start
-with, the following two services should be all you need:
-
-.RS 3
-[homes]
-.RS 3
- writable = yes
-.RE
-
-[printers]
-.RS 3
- writable = no
- printable = yes
- path = /tmp
- public = yes
-.RE
-.RE
-
-This will allow you to connect to your home directory and print to any printer
-supported by the host (user privileges permitting).
-.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.
-
-If your machine's name is "fred" and your name is "mary", you should now be
-able to connect to the service "\\\\fred\\mary".
-
-To properly test and experiment with the server, we recommend using the
-smbclient program (see
-.B 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
-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)
-
-.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
-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.
-.SH CREDITS
-The original Samba software and related utilities were created by
-Andrew Tridgell (samba-bugs@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/smbrun.1 b/docs/manpages/smbrun.1
deleted file mode 100644
index 1608d3bb345..00000000000
--- a/docs/manpages/smbrun.1
+++ /dev/null
@@ -1,70 +0,0 @@
-.TH SMBRUN 1 17/1/1995 smbrun smbrun
-.SH NAME
-smbrun \- interface program between smbd and external programs
-.SH SYNOPSIS
-.B smbrun
-.I shell-command
-.SH DESCRIPTION
-This program is part of the Samba suite.
-
-.B smbrun
-is a very small 'glue' program, which runs shell commands for
-the
-.B smbd
-daemon (see
-.B 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
-necessary to allow some operating systems to run external programs as non-root.
-.SH OPTIONS
-.I shell-command
-
-.RS 3
-The shell command to execute.
-
-The command should have a fully-qualified path.
-.RE
-.SH ENVIRONMENT VARIABLES
-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
-by all, writeable only by root. The program 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.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 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)
-.SH DIAGNOSTICS
-If smbrun cannot be located or cannot be executed by
-.B smbd
-then appropriate messages will be found in the smbd 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
-of the Source for this project.
-
-This man page was written by Karl Auer (Karl.Auer@anu.edu.au)
-
-See
-.B 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
deleted file mode 100644
index 76dc50cbb53..00000000000
--- a/docs/manpages/smbstatus.1
+++ /dev/null
@@ -1,52 +0,0 @@
-.TH SMBSTATUS 1 17/1/1995 smbstatus smbstatus
-.SH NAME
-smbstatus \- report on current Samba connections
-.SH SYNOPSIS
-.B smbstatus
-[-d]
-[-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
-
-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.
-
-Option
-.I -d
-gives verbose output.
-
-.I -p
-print a list of smbd processes and exit. Useful for scripting.
-
-.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
-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
-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
-.B smb.conf(5),
-.B smbd(8)
-
-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/smbtar.1 b/docs/manpages/smbtar.1
deleted file mode 100644
index 0f1c38c271f..00000000000
--- a/docs/manpages/smbtar.1
+++ /dev/null
@@ -1,167 +0,0 @@
-.TH SMBTAR 1 18/2/96 smbtar smbtar
-.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
-.I password
-.B ]
-.B [ \-x
-.I service
-.B ]
-.B [ \-X ]
-.B [ \-d
-.I directory
-.B ]
-.B [ \-u
-.I user
-.B ]
-.B [ \-t
-.I tape
-.B ]
-.B [ \-b
-.I blocksize
-.B ]
-.B [ \-N
-.I filename
-.B ]
-.B [ \-i ]
-.B [ \-r ]
-.B [ \-l ]
-.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.
-
-.SH OPTIONS
-.B \-s
-.I server
-.RS 3
-The PC that the share resides upon.
-.RE
-
-.B \-x
-.I service
-.RS 3
-The share name on the PC to connect to. Default:
-.I backup.
-.RE
-
-.B \-X
-.RS 3
-Exclude mode. Exclude
-.I filenames...
-from tar create or restore.
-.RE
-
-.B \-d
-.I directory
-.RS 3
-Change to initial
-.I directory
-before restoring / backing up files.
-.RE
-
-.B \-v
-.RS 3
-Verbose mode.
-.RE
-
-.B \-p
-.I password
-
-.RS 3
-The password to use to access a share. Default: none
-.RE
-
-.B \-u
-.I user
-.RS 3
-The user id to connect as. Default: UNIX login name.
-.RE
-
-.B \-t
-.I tape
-.RS 3
-Tape device. May be regular file or tape device. Default: Tape environmental
-variable; if not set, a file called
-.I tar.out.
-.RE
-
-.B \-b
-.I blocksize
-.RS 3
-Blocking factor. Defaults to 20. See tar(1) for a fuller explanation.
-.RE
-
-.B \-N
-.I filename
-.RS 3
-Backup only files newer than filename. Could be used (for example) on a log
-file to implement incremental backups.
-.RE
-
-.B \-i
-.RS 3
-Incremental mode; tar files are only backed up if they have the
-archive bit set. The archive bit is reset after each file is read.
-.RE
-
-.B \-r
-.RS 3
-Restore. Files are restored to the share from the tar file.
-.RE
-
-.B \-l
-.RS 3
-Debug level. Corresponds to -d flag on smbclient(1).
-.RE
-
-.SH ENVIRONMENT VARIABLES
-The TAPE variable specifies the default tape device to write to. May
-be overidden with the -t option.
-
-.SH BUGS
-The smbtar script has different options from ordinary tar and tar
-called from 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.
-
-.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)
-.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
-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
-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,
-comments etc.
-
diff --git a/docs/manpages/testparm.1 b/docs/manpages/testparm.1
deleted file mode 100644
index 4a0ffcbc489..00000000000
--- a/docs/manpages/testparm.1
+++ /dev/null
@@ -1,104 +0,0 @@
-.TH TESTPARM 1 17/1/1995 testparm testparm
-.SH NAME
-testparm \- check an smbd configuration file for internal correctness
-.SH SYNOPSIS
-.B testparm
-[
-.I configfilename
-[
-.I hostname
-.I hostIP
-]
-]
-.SH DESCRIPTION
-This program is part of the Samba suite.
-
-.B testparm
-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
-load the configuration file.
-
-Note that this is NOT a guarantee that the services specified in the
-configuration file will be available or will operate as expected.
-
-If the optional host name and host IP address are specified on the
-command line, this test program will run through the service entries
-reporting whether the specified host has access to each service.
-.SH OPTIONS
-.I configfilename
-
-.RS 3
-This is the name of the configuration file to check.
-.RE
-
-.I hostname
-
-.RS 3
-This is the name of the host to check access on.
-
-If this parameter is supplied, the
-.I hostIP
-parameter must also be supplied, or strange things may happen.
-.RE
-
-.I hostIP
-
-.RS 3
-This is the IP number of the host specified in the previous parameter.
-
-This number must be supplied if the
-.I hostname
-parameter is supplied, or strange things may happen.
-.RE
-.SH FILES
-.B smb.conf
-.RS 3
-This is usually the name of the configuration file used by 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
-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.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 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)
-.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
-did not load. If the file was loaded OK, the program then dumps all known
-service details to stdout.
-
-If a host name is specified but no host IP number, all bets are off.
-
-Other messages are self-explanatory.
-.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
-of the Source for this project.
-
-The testparm program and this man page were written by Karl Auer
-(Karl.Auer@anu.edu.au)
-
-See
-.B 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
deleted file mode 100644
index f1c3d3ef020..00000000000
--- a/docs/manpages/testprns.1
+++ /dev/null
@@ -1,107 +0,0 @@
-.TH TESTPRNS 1 17/1/1995 testprns testprns
-.SH NAME
-testprns \- check printer name for validity with smbd
-.SH SYNOPSIS
-.B testprns
-.I printername
-[
-.I printcapname
-]
-.SH DESCRIPTION
-This program is part of the Samba suite.
-
-.B testprns
-is a very simple test program to determine whether a given
-printer name is valid for use in a service to be provided by
-.B smbd.
-
-"Valid" in this context means "can be found in the printcap specified". This
-program is very stupid - so stupid in fact that it would be wisest to always
-specify the printcap file to use.
-.SH OPTIONS
-.I printername
-
-.RS 3
-The printer name to validate.
-
-Printer names are taken from the first field in each record in the printcap
-file, single printer names and sets of aliases separated by vertical bars
-("|") are recognised. Note that no validation or checking of the printcap
-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
-.B testprns
-however if
-.B testprns
-finds the printer then smbd should do as well.
-
-.RE
-
-.I printcapname
-
-.RS 3
-This is the name of the printcap file to search for the given printer name
-in.
-
-If no printcap name is specified,
-.B testprns
-will attempt to scan the printcap file specified at compile time
-(PRINTCAP_NAME).
-.RE
-.SH FILES
-.B /etc/printcap
-.RS 3
-This is usually the default printcap file to scan. See
-.B 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
-by all, writeable only by root. The program 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.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 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)
-.SH DIAGNOSTICS
-If a printer is found to be valid, the message "Printer name <printername> is
-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
-logged by this program to the file
-.I test.log
-in the current directory. The program runs at debuglevel 3, so quite extensive
-logging information is written. The log should be checked carefully for errors
-and warnings.
-
-Other messages are self-explanatory.
-.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
-of the Source for this project.
-
-The testprns program and this man page were written by Karl Auer
-(Karl.Auer@anu.edu.au)
-
-See
-.B 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
deleted file mode 100644
index 503ba1ec94b..00000000000
--- a/docs/samba.lsm
+++ /dev/null
@@ -1,26 +0,0 @@
-Begin2
-Title = Samba
-Version = 1.8.0
-Desc1 = Samba is a SMB based file and print server for unix. It
-Desc2 = provides access to unix file and print services from
-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
-Maintainer = Andrew Tridgell
-MaintEmail = samba-bugs@anu.edu.au
-Site1 = nimbus.anu.edu.au
-Path1 = pub/tridge/samba/
-File1 = samba-latest.tar.gz
-FileSize1 = 200K
-Required1 = Ansi-C compiler and a TCP/IP network.
-CopyPolicy1 = GNU Public License
-Keywords = LanManager, SMB, Networking
-Comment1 = To join the Samba mailing list send mail to
-Comment2 = listproc@listproc.anu.edu.au with a body of
-Comment3 = "subscribe samba Your Name"
-Entered = October 1994
-EnteredBy = Andrew Tridgell
-End
-
diff --git a/docs/textdocs/BROWSING.txt b/docs/textdocs/BROWSING.txt
deleted file mode 100644
index 8a09d2274fb..00000000000
--- a/docs/textdocs/BROWSING.txt
+++ /dev/null
@@ -1,145 +0,0 @@
-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.
-
-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!
-
-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
-finding problems.
-
-Note that if it doesn't work for you, then you should still be able to
-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$
-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
-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
-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).
-
-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
-which determine what precedence (bias) a host should have in the
-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
-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
-NTAS domain controller uses level 32.
-
-The maximum os level is 255
-
-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
-make samba act as the domain master by setting "domain master = yes"
-in smb.conf. By default it will not be a domain master.
-
-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.
-
-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.
-
-NOTIFYING THE DOMAIN CONTROLLER
-===============================
-
-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.
-
-When Samba is the master browser it will regularly contact the domain
-controller to synchronise browse lists.
-
-
-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
-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.
-
-
diff --git a/docs/textdocs/BUGS.txt b/docs/textdocs/BUGS.txt
deleted file mode 100644
index e0fd6951477..00000000000
--- a/docs/textdocs/BUGS.txt
+++ /dev/null
@@ -1,123 +0,0 @@
-This file describes how to report Samba bugs.
-
->> The email address for bug reports is samba-bugs@anu.edu.au <<
-
-(NOTE: This mail may not be in place yet. If you have troubles with it
-then use samba-bugs@arvidsjaur.anu.edu.au)
-
-
-Please take the time to read this file before you submit a bug
-report. Also, please see if it has changed between releases, as I
-may be changing the bug reporting mechanism sometime soon.
-
-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.
-
-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
-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/
-
-
-GENERAL INFO
-------------
-
-Before submitting a bug report check your config for silly
-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.
-
-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.
-
-
-DEBUG LEVELS
-------------
-
-If the bug has anything to do with Samba behaving incorrectly as a
-server (like refusing to open a file) then the log files will probably
-be very useful. Depending on the problem a log level of between 3 and
-10 showing the problem may be appropriate. A higher level givesmore
-detail, but may use too much disk space.
-
-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 file = /usr/local/samba/lib/log.%m
-include = /usr/local/samba/lib/smb.conf.%m
-
-then create a file "/usr/local/samba/lib/smb.conf.machine" where
-"machine" is the name of the client you wish to debug. In that file
-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.
-
-
-INTERNAL ERRORs
----------------
-
-If you get a "INTERNAL ERROR" message in your log files it means that
-Samba got an unexpected signal while running. It is probably a
-segmentation fault and almost certainly means a bug in Samba (unless
-you have faulty hardware or system software)
-
-If the message came from smbd then it will probably be accompanied by
-a message which details the last SMB message received by smbd. This
-info is often very useful in tracking down the problem so please
-include it in your bug report.
-
-You should also detail how to reproduce the problem, if
-possible. Please make this reasonably detailed.
-
-You may also find that a core file appeared in a "corefiles"
-subdirectory of the directory where you keep your samba log
-files. This file is the most useful tool for tracking down the bug. To
-use it you do this:
-
-gdb smbd core
-
-adding appropriate paths to smbd and core so gdb can find them. If you
-don't have gdb then try "dbx". Then within the debugger use the
-command "where" to give a stack trace of where the problem
-occurred. Include this in your mail.
-
-If you known any assembly language then do a "disass" of the routine
-where the problem occurred (if its in a library routine then
-disassemble the routine that called it) and try to work out exactly
-where the problem is by looking at the surrounding code. Even if you
-don't know assembly then incuding this info in the bug report can be
-useful.
-
-
-ATTACHING TO A RUNNING PROCESS
-------------------------------
-
-Unfortunately some unixes (in particular some recent linux kernels)
-refuse to dump a core file if the task has changed uid (which smbd
-does often). To debug with this sort of system you could try to attach
-to the running process using "gdb smbd PID" where you get PID from
-smbstatus. Then use "c" to continue and try to cause the core dump
-using the client. The debugger should catch the fault and tell you
-where it occurred.
-
-
-PATCHES
--------
-
-The best sort of bug report is one that includes a fix! If you send me
-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
-used.
-
diff --git a/docs/textdocs/DIAGNOSIS.txt b/docs/textdocs/DIAGNOSIS.txt
deleted file mode 100644
index 6681bdc4bcb..00000000000
--- a/docs/textdocs/DIAGNOSIS.txt
+++ /dev/null
@@ -1,237 +0,0 @@
-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
-is if it fails any one of these steps. If it passes all these tests
-then it is probably working fine.
-
-You should do ALL the tests, in the order shown. I have tried to
-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
-
-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
-ignore your email.
-
-
-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.
-
-I also assume you know the name of a 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:
-
-[tmp]
- comment = temporary files
- path = /tmp
- read only = yes
-
-
-THESE TESTS ASSUME VERSION 1.9.15 OR LATER OF THE SAMBA SUITE. SOME
-COMMANDS SHOWN DID NOT EXIST IN EARLIER VERSIONS
-
-
-TEST 1:
--------
-
-run the command "testparm". If it reports any errors then your
-smb.conf configuration file is faulty.
-
-
-TEST 2:
--------
-
-run the command "ping BIGSERVER" from the PC and "ping ACLIENT" from
-the unix box. If you don't get a valid response then your TCP/IP
-software is not correctly installed.
-
-Note that you will need to start a "dos prompt" window on the PC to
-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.
-
-
-TEST 3:
--------
-
-run the command "smbclient -L BIGSERVER -U%" 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
-you probably have either an incorrect "hosts allow", "hosts deny" or
-"valid users" line in your smb.conf, or your guest account is not
-valid. Check what your guest account is using "testparm" and
-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
-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".
-
-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".
-
-TEST 4:
--------
-
-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
-to udp port 137.
-
-One common problem is that many inetd implementations can't take many
-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:
--------
-
-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).
-
-TEST 6:
--------
-
-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
-Netbios/TCPIP hosts on the network should respond, although Samba may
-not catch all of the responses in the short time it listens. You
-should see "got a positive name query response" messages from several
-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.
-
-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
-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
-line.
-
-Once you enter the password you should get the "smb>" prompt. If you
-don't then look at the error message. If it says "invalid network
-name" then the service "tmp" is not correctly setup in your smb.conf.
-
-If it says "bad password" then the likely causes are:
-
-- you have shadow passords (or some other password system) but didn't
-compile in support for them in smbd
-- your "valid users" configuration is incorrect
-- 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
-
-Once connected you should be able to use the commands "dir" "get"
-"put" etc. Type "help <command>" for instructions. You should
-especially check that the amount of free disk space shown is correct
-when you type "dir".
-
-
-TEST 8:
--------
-
-On the PC type the command "net view \\BIGSERVER". You will need to do
-this from within a "dos prompt" window. You should get back a list of
-available shares on the server.
-
-If you get a "network name not found" or similar error then netbios
-name resolution is not working. This is usually caused by a problem in
-nmbd. To overcome it you could do one of the following (you only need
-to choose one of them):
-
-- fixup the nmbd installation
-- add the IP address of BIGSERVER to the "wins server" box in the
-advanced tcp/ip setup on the PC.
-- enable windows name resolution via DNS in the advanced section of
-the tcp/ip setup
-- add BIGSERVER to your lmhosts file on the PC.
-
-If you get a "invalid network name" or "bad password error" then the
-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)
-
-
-TEST 9:
---------
-
-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
-lines in smb.conf are correct.
-
-It's also possible that the server can't work out what user name to
-connect you as. To see if this is the problem add the line "user =
-USERNAME" to the [tmp] section of smb.conf where "USERNAME" is the
-username corresponding to the password you typed. If you find this
-fixes things you may need the username mapping option.
-
-
-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
-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.
-
-
-Still having troubles?
-----------------------
-
-Try the mailing list or newsgroup, or use the tcpdump-smb utility to
-sniff the problem.
-
-
diff --git a/docs/textdocs/DNIX.txt b/docs/textdocs/DNIX.txt
deleted file mode 100644
index 51005e6ec8c..00000000000
--- a/docs/textdocs/DNIX.txt
+++ /dev/null
@@ -1,69 +0,0 @@
-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.
-
-For this reason Samba by default defines the macro NO_EID in the DNIX
-section of includes.h. This works around the problem in a limited way,
-but it is far from ideal, some things still won't work right.
-
-To fix the problem properly you need to assemble the following two
-functions and then either add them to your C library or link them into
-Samba.
-
-put this in the file setegid.s:
-
- .globl _setegid
-_setegid:
- moveq #47,d0
- movl #100,a0
- moveq #1,d1
- movl 4(sp),a1
- trap #9
- bccs 1$
- jmp cerror
-1$:
- clrl d0
- rts
-
-
-put this in the file seteuid.s:
-
- .globl _seteuid
-_seteuid:
- moveq #47,d0
- movl #100,a0
- moveq #0,d1
- movl 4(sp),a1
- trap #9
- bccs 1$
- jmp cerror
-1$:
- clrl d0
- rts
-
-after creating the above files you then assemble them using
-
-as seteuid.s
-as setegid.s
-
-that should produce the files seteuid.o and setegid.o
-
-then you need to add these to the LIBSM line in the DNIX section of
-the Samba Makefile. Your LIBSM line will then look something like this:
-
-LIBSM = setegid.o seteuid.o -ln
-
-You should then remove the line:
-
-#define NO_EID
-
-from the DNIX section of includes.h
-
-Then recompile and try it out!
-
-Note that this file was derived from an email from Peter Olsson
-<pol@leissner.se>. I don't have DNIX myself, so you're probably better
-off contacting Peter if you have problems.
-
-Andrew
-
diff --git a/docs/textdocs/DOMAIN.txt b/docs/textdocs/DOMAIN.txt
deleted file mode 100644
index 31e19675fae..00000000000
--- a/docs/textdocs/DOMAIN.txt
+++ /dev/null
@@ -1,68 +0,0 @@
-Samba now supports domain logons and network logon scripts. 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 SAM database with other systems yet, or remote
-administration. Support for these kind of things should be added
-sometime in the future.
-
-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.
-
-To use domain logons you need to do the following:
-
-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) 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.
-
-For example I have used:
-
- [netlogon]
- path = /data/dos/netlogon
- writeable = no
- guest ok = yes
-
-
-3) 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
-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:
-
- 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.
-
-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.
-
-
-NOTE: You must be using "security = user" or "security = server" for
-domain logons to work correctly. Share level security won't work
-correctly.
-
-
diff --git a/docs/textdocs/ENCRYPTION.txt b/docs/textdocs/ENCRYPTION.txt
deleted file mode 100644
index 046b473e9a1..00000000000
--- a/docs/textdocs/ENCRYPTION.txt
+++ /dev/null
@@ -1,333 +0,0 @@
- LanManager / Samba Password Encryption.
- ---------------------------------------
-
-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.
-
-This document describes how the SMB password encryption algorithm
-works and what issues there are in choosing whether you want to use
-it. You should read it carefully, especially the part about security
-and the "PROS and CONS" section.
-
-How does it work ?
-------------------
-
- 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
-padding to 14 bytes with null bytes). This 14 byte value is used as
-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*.
-
-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
-and server will use. In the reply to this request the Samba server
-generates and appends an 8 byte, random value - this is stored in the
-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
-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*.
-
-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.
-
-The Samba server then reproduces the above calculation, using it's own
-stored value of the 16 byte hashed password (read from the smbpasswd
-file - described later) and the challenge value that it kept from the
-negotiate protocol reply. It then checks to see if the 24 byte value it
-calculates matches the 24 byte value returned to it from the client.
-
-If these values match exactly, then the client knew the correct
-password (or the 16 byte hashed value - see security note below) and
-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
-transmitted over the network - thus increasing security.
-
-IMPORTANT NOTE ABOUT SECURITY
------------------------------
-
-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
-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
-passwords of all your users. Its contents must be kept secret, and the
-file should be protected accordingly.
-
-Ideally we would like a password scheme which neither requires plain
-text passwords on the net or on disk. Unfortunately this is not
-available as Samba is stuck with being compatible with other SMB
-systems (WinNT, WfWg, Win95 etc).
-
-
-PROS AND CONS
--------------
-
-There are advantages and disadvantages to both schemes.
-
-Advantages of SMB Encryption:
------------------------------
-
-- plain text passwords are not passed across the network. Someone using
-a network sniffer cannot just record passwords going to the SMB server.
-
-- WinNT doesn't like talking to a server that isn't using SMB
-encrypted passwords. It will refuse to browse the server if the server
-is also in user level security mode. It will insist on promting the
-user for the password on each connection, which is very annoying. The
-only things you can do to stop this is to use SMB encryption.
-
-Advantages of non-encrypted passwords:
---------------------------------------
-
-- plain text passwords are not kept on disk.
-
-- uses same password file as other unix services such as login and
-ftp
-
-- you are probably already using other services (such as telnet and
-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.
-
-
-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.
-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
-containing this 16 byte value must be kept. To minimise problems with
-these two password files, getting out of sync, the UNIX /etc/passwd and
-the smbpasswd file, a utility, mksmbpasswd.sh, is provided to generate
-a smbpasswd file from a UNIX /etc/passwd file.
-
-To generate the smbpasswd file from your /etc/passwd file use the
-following command :-
-
-cat /etc/passwd | mksmbpasswd.sh >/usr/local/samba/private/smbpasswd
-
-If you are running on a system that uses NIS, use
-
-ypcat passwd | mksmbpasswd.sh >/usr/local/samba/private/smbpasswd
-
-The mksmbpasswd.sh program is found in the Samba source directory. By
-default, the smbpasswd file is stored in :-
-
-/usr/local/samba/private/smbpasswd
-
-The owner of the /usr/local/samba/private directory should be set to
-root, and the permissions on it should be set to :-
-
-r-x------
-
-The command
-
-chmod 500 /usr/local/samba/private
-
-will do the trick. Likewise, the smbpasswd file inside the private
-directory should be owned by root and the permissions on is should be
-set to
-
-rw-------
-
-by the command :-
-
-chmod 600 smbpasswd.
-
-The format of the smbpasswd file is
-
-username:uid: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.
-
-When the password file is created all users have password entries
-consisting of 32 'X' characters. By default this disallows any access
-as this user. When a user has a password set, the 'X' characters change
-to 32 ascii hexadecimal digits (0-9, A-F). These are an ascii
-representation of the 16 byte hashed value of a users password.
-
-To set a user to have no password (not recommended), edit the file
-using vi, and replace the first 11 characters with the asci text
-
-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
-
-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
-not have to enter a previous password when changing to their new
-password (not recommended).
-
-Note : This file should be protected very carefully. Anyone with
-access to this file can (with enough knowledge of the protocols) gain
-access to your SMB server. The file is thus more sensitive than a
-normal unix /etc/passwd file.
-
-The smbpasswd Command.
-----------------------
-
- The smbpasswd command maintains the 32 byte password field 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.
-
-Note that if you do not do this then the root user will have to set all
-users passwords.
-
-To set up smbpasswd as setuid root, change to the Samba binary install
-directory and then type (as root) :
-
-chown root smbpasswd
-chmod 4555 smbpasswd
-
-If smbpasswd is installed as setuid root then you would use it as
-follows.
-
-smbpasswd
-Old SMB password: <type old alue here - just hit return if there is NO PASSWORD>
-New SMB Password: < type new value >
-Repeat New SMB Password: < re-type new value >
-
-If the old value does not match the current value stored for that user,
-or the two new values do not match each other, then the password will
-not be changed.
-
-If invoked by an ordinary user it will only allow the user to change
-his or her own Samba password.
-
-If run by the root user smbpasswd may take an optional argument,
-specifying the user name whose SMB password you wish to change. Note
-that when run as root smbpasswd does not prompt for or check the old
-password value, thus allowing root to set passwords for users who have
-forgotten their passwords.
-
-smbpasswd is designed to work in the same way and be familiar to UNIX
-users who use the passwd or yppasswd commands.
-
-NOTE. As smbpasswd is designed to be installed as setuid root I would
-appreciate it if everyone examined the source code to look for
-potential security flaws. A setuid program, if not written properly can
-be an open door to a system cracker. Please help make this program
-secure by reporting all problems to me (the author, Jeremy Allison).
-
-My email address is :-
-
-jra@vantive.com
-
-Setting up Samba to support LanManager Encryption.
---------------------------------------------------
-
-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.
-
-3) compile and install samba as usual
-
-4) f 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
-"encrypt passwords = yes" in the [global] section
-
-6) 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:
-
-cat /etc/passwd | mksmbpasswd.sh > /usr/local/samba/private/smbpasswd
-
-Change ownership of private and smbpasswd to root.
-
-chown -R root /usr/local/samba/private
-
-Set the correct permissions on /usr/local/samba/private
-
-chmod 500 /usr/local/samba/private
-
-Set the correct permissions on /usr/local/samba/private/smbpasswd
-
-chmod 600 /usr/local/samba/private/smbpasswd
-
-note that the mksmbpasswd.sh script is in the samba source directory.
-
-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
-
-note that the uid and username fields must be right. Also, you must get
-the number of X's right (there should be 32).
-
-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
-example, as root you could do "smbpasswd tridge"
-
-8) 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.
-
diff --git a/docs/textdocs/HINTS.txt b/docs/textdocs/HINTS.txt
deleted file mode 100644
index 953650bdd3e..00000000000
--- a/docs/textdocs/HINTS.txt
+++ /dev/null
@@ -1,202 +0,0 @@
-Here are some random hints that you may find useful. These really
-should be incorporated in the main docs someday.
-
-
-----------------------
-HINT: Always test your smb.conf with testparm before using it
-
-If your smb.conf file is invalid then samba will fail to load. Run
-testparm over it before you install it just to make sure there aren't
-any basic syntax or logical errors.
-
-
-----------------------
-HINT: Try printing with smbclient first
-
-If you have problems printing, test with smbclient first. Just connect using
-"smbclient '\\server\printer' -P" and use the "print" command.
-
-Once this works, you know that Samba is setup correctly for printing,
-and you should be able to get it to work from your PCs.
-
-This particularly helps in getting the "print command" right.
-
-
-----------------------
-HINT: Mount cdroms with conv=binary
-
-Some OSes (notably Linux) default to auto detection of file type on
-cdroms and do cr/lf translation. This is a very bad idea when use with
-Samba. It causes all sorts of stuff ups.
-
-To overcome this problem use conv=binary when mounting the cdrom
-before exporting it with Samba.
-
-
-----------------------
-HINT: Convert between unix and dos text formats
-
-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
-
-----------------------
-HINT: Use the "username map" option
-
-If the usernames used on your PCs don't match those used on the unix
-server then you will find the "username map" option useful.
-
------------------------
-HINT: Use "security = user" in [global]
-
-If you have the same usernames on the unix box and the PCs or have
-mapped them with the "username map" option then choose "security =
-user" in the [global] section of smb.conf.
-
-This will mean your password is checked only when you first connect,
-and subsequent connections to printers, disks etc will go more
-smoothly and much faster.
-
-The main problem with "security = user" if you use WfWg is that you
-will ONLY be able to connect as the username that you log into WfWg
-with. This is because WfWg silently ignores the password field in the
-connect drive dialog box if the server is in user security mode.
-
-------------------------
-HINT: Make your printers not "guest ok"
-
-If your printers are not "guest ok" and you are using "security =
-user" and have matching unix and PC usernames then you will attach to
-the printer without trouble as your own username. This will mean you
-will be able to delete print jobs (in 1.8.06 and above) and printer
-accounting will be possible.
-
-
------------------------
-HINT: Use a sensible "guest" account
-
-Even if all your services are not available to "guest" you will need a
-guest account. This is because the browsing is done as guest. In many
-cases setting "guest account = ftp" will do the trick. Using the
-default guest account or "guest account = nobody" will give problems on
-many unixes. If in doubt create another account with minimal
-privilages and use it instead. Your users don't need to know the
-password of the guest account.
-
-
------------------------
-HINT: Use the latest TCP/IP stack from microsoft if you use Windows
-for workgroups.
-
-The early TCP/IP stacks had lots of bugs.
-
-Microsoft has released an incremental upgrade to their TCP/IP 32-Bit
-VxD drivers. The latest release can be found on their ftp site at
-ftp.microsoft.com, located in /peropsys/windows/public/tcpip/wfwt32.exe.
-There is an update.txt file there that describes the problems that were
-fixed. New files include WINSOCK.DLL, TELNET.EXE, WSOCK.386, VNBT.386,
-WSTCP.386, TRACERT.EXE, NETSTAT.EXE, and NBTSTAT.EXE.
-
-
------------------------
-HINT: nmbd can act as a "WINS" server
-
-By default SMB clients use broadcasts to find shares. Recent clients
-(such as WfWg) can use a "wins" server instead, whcih reduces your
-broadcast traffic and allows you to find names across routers.
-
-Just point your WfWg, Win95 and NT clients at the Samba box in the WINS option.
-
-Note: nmbd does not support all WINS operations. Anyone out there have
-a spec they could send me?
-
------------------------
-HINT: you may need to delete your .pwl files when you change password.
-
-WfWg does a lousy job with passwords. I find that if I change my
-password on either the unix box or the PC the safest thing to do is to
-delete the .pwl files in the windows directory. The PC will complain about not finding the files, but will soon get over it, allowing you to enter the new password.
-
-If you don't do this you may find that WfWg remembers and uses the old
-password, even if you told it a new one.
-
-Often WfWg will totally ignore a password you give it in a dialog box.
-
-----------------------
-HINT: Using MS Access
-
-Here are some notes on running MS-Access on a Samba drive from Stefan
-Kjellberg <stefank@esi.com.au>
-
-1. Opening a database in 'exclusive' mode does NOT work. Samba ignores
- r/w/share modes on file open.
-
-2. Make sure that you open the database as 'shared' and to 'lock modified
- records'
-
-3. Of course locking must be enabled for the particular share (smb.conf)
-
-
----------------------
-HINT: password cacheing in WfWg
-
-Here is a hint from michael@ecel.uwa.edu.au (Michael Simmons):
-
-In case people where not aware. There is a program call admincfg.exe
-on the last disk (disk 8) of the WFW 3.11 disk set. To install it
-type EXPAND A:\ADMINCFG.EX_ C:\WINDOWS\ADMINCFG.EXE Then add an icon
-for it via the "Progam Manager" "New" Menu. This program allows you
-to control how WFW handles passwords. ie disable Password Caching etc
-for use with "security = user"
-
-
---------------------
-HINT: file descriptor limits
-
-If you have problems with the limits on the number of open files you
-can edit local.h to fix it.
-
---------------------
-HINT: HPUX initgroups() problem
-
-here is a hint from Frank Wales [frank@arcglade.demon.co.uk]:
-
-HP's implementation of supplementary groups is, er, non-standard (for
-hysterical reasons). There are two group files, /etc/group and
-/etc/logingroup; the system maps UIDs to numbers using the former, but
-initgroups() reads the latter. Most system admins who know the ropes
-symlink /etc/group to /etc/logingroup (hard link doesn't work for reasons
-too stupid to go into here). initgroups() will complain if one of the
-groups you're in in /etc/logingroup has what it considers to be an invalid
-ID, which means outside the range [0..UID_MAX], where UID_MAX is (I think)
-60000 currently on HP-UX. This precludes -2 and 65534, the usual 'nobody'
-GIDs.
-
-Perhaps you could suggest to users that, if they encounter this problem,
-they make sure that the programs that are failing to initgroups() be
-run as users not in any groups with GIDs outside the allowed range.
-
-This is documented in the HP manual pages under setgroups(2) and passwd(4).
-
-
----------------------
-HINT: Patch your SCO system
-
-If you run SCO Unix then you may need to get important TCP/IP patches
-for Samba to work correctly. Try
-
-Paul_Davis@mindlink.bc.ca writes:
-
- I was having problems with Accpac using 1.9.02 on SCO Unix. One
- posting function reported corrupted data. After installing uod385a,
- the problem went away (a restore from backup and then another
- run-thru).
-
- It appears that the uod385a update for SCO may be fairly important for
- a lot of different DOS and Windows software under Samba.
-
- uod385a can be found at ftp.sco.com /SLS/uod385a.Z and uod385a.ltr.Z.
-
-
diff --git a/docs/textdocs/INSTALL.sambatar b/docs/textdocs/INSTALL.sambatar
deleted file mode 100644
index 388e2a3eb6f..00000000000
--- a/docs/textdocs/INSTALL.sambatar
+++ /dev/null
@@ -1,27 +0,0 @@
-
-Please see the readme and the man page for general info.
-
-1) Follow the samba installation instructions.
-
-2) If all goes well, test it out by creating a share on your PC (called
-backup for example) then doing something like,
-
- ./smbtar -s mypc -t /dev/rmt/0ubn -x backup
-
-substituting whatever your tape drive is for the -t option, or set your
-tape environmental variable.
-
-If all does not go well, feel free to mail the author (poultenr@logica.co.uk)
-about bug reports / help / money / pizza / etc.
-
-3) Read the man page and the NOTES file for more information
-
-4) Work smbtar into your usual nightly backup scheme (presuming you
-have one :-}).
-
-
-NOTE:
-
-If you have problems with smbtar then it's probably best to contact the
-author Ricky Poulten (poultenr@logica.co.uk).
-
diff --git a/docs/textdocs/PROJECTS b/docs/textdocs/PROJECTS
deleted file mode 100644
index cf903f2c6dd..00000000000
--- a/docs/textdocs/PROJECTS
+++ /dev/null
@@ -1,96 +0,0 @@
- Samba Projects Directory
- ========================
-
-
->>>>> NOTE: THIS FILE IS NOW VERY OUT OF DATE <<<<<
-
-
-This is a list of who's working on what in Samba. It's not guaranteed
-to be uptodate or accurate but I hope it will help us getting
-coordinated.
-
-If you are working on something to do with Samba and you aren't here
-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
-
-========================================================================
-Documentation and FAQ
-
-Docs and FAQ files for the Samba suite of software.
-
-Contact Karl.Auer@anu.edu.au
-
-Mark Preston is now working on a set of formatted docs for Samba.
-Contact mpreston@sghms.ac.uk
-
-Docs are currently up to date with version, 1.7.07. FAQ being added to
-as questions arise.
-
-Status last updated 27th September 1994
-========================================================================
-
-========================================================================
-Netbeui support
-
-This aims 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
-========================================================================
-
-========================================================================
-Smbfs
-
-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)
-
-Status last updated 23rd August 1994
-========================================================================
-
-========================================================================
-Admin Tool
-
-Aims to produce a nice smb.conf editor and other useful tools for
-administering a Samba system.
-
-Contact: Steve Brown (steve@unicorn.dungeon.com)
-
-In the design phase.
-
-Status last updated 4th September 1994
-========================================================================
-
-
-========================================================================
-Lanman Client.
-
-Contact: john@amanda.xs4all.nl (John Stewart)
-
-Aims to produce a reliable LANMAN Client implementation for LINUX,
-and possibly other variations of UNIX. Project ably started by
-Tor Lillqvist; tml@hemuli.tte.vtt.fi
-
-Status last updated 17th January 1995
-========================================================================
diff --git a/docs/textdocs/Passwords.txt b/docs/textdocs/Passwords.txt
deleted file mode 100644
index e06876fecae..00000000000
--- a/docs/textdocs/Passwords.txt
+++ /dev/null
@@ -1,42 +0,0 @@
-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
-mentioned in the Makefile.
-
-Also note that some clients (notably WfWg) uppercase the password
-before sending it. The server tries the password as it receives it and
-also after lowercasing it.
-
-The Samba server can also be configured to try different
-upper/lowercase combinations. This is controlled by the [global]
-parameter "password level". A level of N means to try all combinations
-up to N uppercase characters in the password. A high value can chew a
-fair bit of CPU time and can lower the security of your system. Do not
-use this options unless you really need it - the time taken for
-password checking can become so high that clients time out.
-
-If you do use the "password level" option then you might like to use
--DUFC_CRYPT in your Makefile. On some machine this makes password
-checking _much_ faster. This is also useful if you use the @group
-syntax in the user= option.
-
-If your site uses AFS (the Andrew File System), you can use the AFS section
-in the Makefile. This will first attempt to authenticate a username and
-password to AFS. If that succeeds, then the associated AFS rights will be
-granted. Otherwise, the password checking routine falls back to whatever
-Unix password checking method you are using. Note that the AFS code is
-only written and tested for AFS 3.3 and later.
-
-
-SECURITY = SERVER
-=================
-
-Samba can use a remote server to do it's username/password
-validation. This allows you to have one central machine (for example a
-NT box) control the passwords for the Unix box.
-
-See the section on "security =" in smb.conf(5) for details.
-
-
diff --git a/docs/textdocs/README.DCEDFS b/docs/textdocs/README.DCEDFS
deleted file mode 100644
index f84b84bb686..00000000000
--- a/docs/textdocs/README.DCEDFS
+++ /dev/null
@@ -1,79 +0,0 @@
-=============================================================================
-
- Basic DCE/DFS Support for SAMBA 1.9.13
-
- Jim Doyle <doyle@oec.com> 06-02-95
-
-=============================================================================
-
-Functionality:
---------------
-
- Per-instance authentication for DCE/DFS.
-
-Missing Functionality in this Implementation:
----------------------------------------------
-
- * No automatic refresh of credentials
-
- To do so would not be that hard.. One could simply
- stash the clear-text key in memory, spawn a key management
- thread to wake up right before credentials expire and
- refresh the login context.
-
- * No UNIX Signals support (SIGCLD, SIGPIPE, SIGHUP, SIGBUS, SIGSEGV)
-
-
- There is no support for signal processing in Samba daemons
- that need to authenticate with DCE. The explanation for this
- is that the smbd is linked against thread-safe libraries in
- order to be able to use DCE authentication mechanisms.
- Because smbd uses signal() and fork(), it represents the
- worst case scenario for DCE portability. In order
- to properly support signals in a forked server environment,
- some rework of smbd is needed in order to properly
- construct, shutdown and reconstruct asynchronous signal
- handling threads and synchronous signal traps across the
- parent and child. I have not had contiguous time to work
- on it, I expect it to be a weeks worth of work to cleanly
- integrate thread-safe signal handing into the code and
- test it. Until I can get to this task, I will leave it up
- to someone adventurous enough to engineer it and negotiate
- with Andrew to integrate the changes into the mainline branch.
-
- The lack of full signal support means that you cannot
- rely upon SIGHUP-ing the parent daemon to refresh
- the configuration data. Likewise, you cannot take advantage
- of the builtin SIGBUS/SIGSEGV traps to diagnose failures.
- You will have to halt Samba in order to make changes
- and then have them take effect.
-
- The SMBD server as it stands is suitable to use if you
- already have experience with configuring and running
- SAMBA.
-
-Tested Platforms:
------------------
-
- HP-UX 9.05 / HP-UX DCE 1.2.1
- AIX 3.2.5 / AIX DCE/6000 1.3
- DEC OSF-1 3.0 / DEC DCE 1.3
-
-Building:
----------
-
- - Uncomment the the appropriate block in the Makefile
- for the platform you wish to build on.
-
- - Samples of Samba server configuration files for our
- DFS environment are included in samples.dcedfs/
-
-
-
-Bugs, Suggestions, etc..
---------------------------
-
- Please post them to the mailing list.
- That way I will see them and they will become part of
- the archives so others can share the knowledge.
-
diff --git a/docs/textdocs/README.jis b/docs/textdocs/README.jis
deleted file mode 100644
index 2ac6716a6f6..00000000000
--- a/docs/textdocs/README.jis
+++ /dev/null
@@ -1,124 +0,0 @@
-$B!|(B samba $BF|K\8lBP1~$K$D$$$F(B
-
-1. $BL\E*(B
-
- $BF|K\8lBP1~$O!"(B
-
- (1) MS-Windows $B>e$G!"4A;z%U%!%$%kL>$r$I$&$7$F$b07$&I,MW$N$"$k%"%W%j%1!<%7%g%s$,$A$c(B
- $B$s$HF0:n$9$k!#Nc$($P!"(BMS-WORD 5 $B$J$I$O!"%$%s%9%H!<%k;~$K4A;z$N%U%!%$%kL>$r>!<j(B
- $B$K$D$1$F$7$^$$$^$9!#$3$&$$$C$?>l9g$K$A$c$s$HBP1~$G$-$k$h$&$K$9$k!#(B
-
- (2) UNIX $B$O!":G6a$G$O$[$H$s$I$N$b$N$,(B 8 bits $B$N%U%!%$%kL>$r%5%]!<%H$7$F$$$^$9$,!"(B
- $BCf$K$O!"$3$l$r%5%]!<%H$7$F$$$J$$$b$N$b$"$j$^$9!#$3$N$h$&$J>l9g$G$b!"(B(1)$B$NL\E*(B
- $B$,K~B-$G$-$k$h$&$K$9$k!#(B
-
- $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
-
-2. $BMxMQJ}K!(B
-
-(1) $BDI2C$7$?%Q%i%a!<%?(B
-
- smb.conf $B%U%!%$%k$N(B global $B%;%/%7%g%s$K0J2<$N%Q%i%a!<%?$r@_Dj$G$-$k$h$&$K$7$^$7$?!#(B
-
- [global]
- ....
- coding system = <$B%3!<%I7O(B>
-
- $B$3$3$G;XDj$5$l$?%3!<%I7O$,(B UNIX $B>e$N%U%!%$%k%7%9%F%`$N%U%!%$%kL>$N%3!<%I$K$J$j$^$9!#(B
- $B@_Dj$G$-$k$b$N$O!"<!$N$h$&$K$J$C$F$$$^$9!#(B
-
- sjis: SHIFT JIS (MS $B4A;z%3!<%I(B)
- euc: EUC $B%3!<%I(B
- hex: 7 bits $B$N(B ASCII $B%3!<%I0J30$N%3!<%I$r0J2<$N7A<0$GI=$9J}<0$G$9!#Nc$($P!"(B
- '$B%*%U%#%9(B' $B$H$$$&L>A0$O!"(B':83:49:83:74:83:42:83:58' $B$N$h$&$K!"(B':' $B$N8e$K#27e(B
- $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
- 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
- $B('(!(!(!(+(!(!(!(!(+(!(!(!(!(+(!(!(!(!(+(!(!(!(!(+(!(!(!(!(+(!(!(!(!(!(!(!(!(!()(B
- $B("(Bjis7 $B("(B\E$B $B("(B\E(J $B("(B0x0e $B("(B0x0f $B("(B\E(J $B("(Bjis 7$BC10LId9f(B $B("(B
- $B("(Bjunet $B("(B\E$B $B("(B\E(J $B("(B\E(I $B("(B\E(J $B("(B\E(J $B("(B7bits $B%3!<%I(B $B("(B
- $B("(Bjis8 $B("(B\E$B $B("(B\E(J $B("(B-- $B("(B-- $B("(B\E(J $B("(Bjis 8$BC10LId9f(B $B("(B
- $B("(Bj7bb $B("(B\E$B $B("(B\E(B $B("(B0x0e $B("(B0x0f $B("(B\E(B $B("(B $B("(B
- $B("(Bj7bj $B("(B\E$B $B("(B\E(J $B("(B0x0e $B("(B0x0f $B("(B\E(J $B("(Bjis7$B$HF1$8(B $B("(B
- $B("(Bj7bh $B("(B\E$B $B("(B\E(H $B("(B0x0e $B("(B0x0f $B("(B\E(H $B("(B $B("(B
- $B("(Bj7@b $B("(B\E$@ $B("(B\E(B $B("(B0x0e $B("(B0x0f $B("(B\E(B $B("(B $B("(B
- $B("(Bj7@j $B("(B\E$@ $B("(B\E(J $B("(B0x0e $B("(B0x0f $B("(B\E(J $B("(B $B("(B
- $B("(Bj7@h $B("(B\E$@ $B("(B\E(H $B("(B0x0e $B("(B0x0f $B("(B\E(H $B("(B $B("(B
- $B("(Bj8bb $B("(B\E$B $B("(B\E(B $B("(B-- $B("(B-- $B("(B\E(B $B("(B $B("(B
- $B("(Bj8bj $B("(B\E$B $B("(B\E(J $B("(B-- $B("(B-- $B("(B\E(J $B("(Bjis8$B$HF1$8(B $B("(B
- $B("(Bj8bh $B("(B\E$B $B("(B\E(H $B("(B-- $B("(B-- $B("(B\E(H $B("(B $B("(B
- $B("(Bj8@b $B("(B\E@@ $B("(B\E(B $B("(B-- $B("(B-- $B("(B\E(B $B("(B $B("(B
- $B("(Bj8@j $B("(B\E$@ $B("(B\E(J $B("(B-- $B("(B-- $B("(B\E(J $B("(B $B("(B
- $B("(Bj8@h $B("(B\E$@ $B("(B\E(H $B("(B-- $B("(B-- $B("(B\E(H $B("(B $B("(B
- $B("(Bjubb $B("(B\E$B $B("(B\E(B $B("(B\E(I $B("(B\E(B $B("(B\E(B $B("(B $B("(B
- $B("(Bjubj $B("(B\E$B $B("(B\E(J $B("(B\E(I $B("(B\E(J $B("(B\E(J $B("(Bjunet$B$HF1$8(B $B("(B
- $B("(Bjubh $B("(B\E$B $B("(B\E(H $B("(B\E(I $B("(B\E(H $B("(B\E(H $B("(B $B("(B
- $B("(Bju@b $B("(B\E$@ $B("(B\E(B $B("(B\E(I $B("(B\E(B $B("(B\E(B $B("(B $B("(B
- $B("(Bju@j $B("(B\E$@ $B("(B\E(J $B("(B\E(I $B("(B\E(J $B("(B\E(J $B("(B $B("(B
- $B("(Bju@h $B("(B\E$@ $B("(B\E(H $B("(B\E(I $B("(B\E(H $B("(B\E(H $B("(B $B("(B
- $B(&(!(!(!(*(!(!(!(!(*(!(!(!(!(*(!(!(!(!(*(!(!(!(!(*(!(!(!(!(*(!(!(!(!(!(!(!(!(!(%(B
-
- $B$$$:$l$N>l9g$b!"$9$G$KB8:_$7$F$$$kL>A0$KBP$7$F$O!"4A;z$N3+;O=*N;%7!<%1%s%9$O!"0J2<(B
- $B$N$b$N$rG'<1$7$^$9!#(B
- $B4A;z$N;O$^$j(B: \E$B $B$+(B \E$@
- $B4A;z$N=*$j(B: \E(J $B$+(B \E(B $B$+(B \E(H
-
-(2) smbclient $B$N%*%W%7%g%s(B
-
- $B%/%i%$%"%s%H%W%m%0%i%`$G$b!"4A;z$d2>L>$r4^$s$@%U%!%$%k$r07$($k$h$&$K!"<!$N%*%W%7%g%s(B
- $B$rDI2C$7$^$7$?!#(B
-
- -t <$B%?!<%_%J%k%3!<%I7O(B>
-
- $B$3$3$G!"(B<$B%?!<%_%J%k%3!<%I7O(B>$B$K;XDj$G$-$k$b$N$O!">e$N(B<$B%3!<%I7O(B>$B$HF1$8$b$N$G$9!#(B
-
-(3) $B%G%U%)%k%H(B
-
- $B%G%U%)%k%H$N%3!<%I7O$O!"%3%s%Q%$%k;~$K7h$^$j$^$9!#(B
-
-3. $B%3%s%Q%$%k;~$N@_Dj(B
-
- Makefile $B$K@_Dj$9$k9`L\$r0J2<$K<($7$^$9!#(B
-
-(1) KANJI $B%U%i%0(B
-
- $B%3%s%Q%$%k%*%W%7%g%s$K(B -DKANJI=\"$B%3!<%I7O(B\" $B$r;XDj$7$^$9!#$3$N%3!<%I7O$O(B 2. $B$G;X(B
- $BDj$9$k$b$N$HF1$8$G$9!#Nc$($P!"(B-DKANJI=\"euc\" $B$r(BFLAGSM $B$K@_Dj$9$k$H(B UNIX $B>e$N%U%!(B
- $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
-
-3. $B@)8B;v9`(B
-
-(1) $B4A;z%3!<%I(B
- smbd $B$rF0:n$5$;$k%[%9%H$N(B UNIX $B$,%5%]!<%H$7$F$$$J$$4A;z%3!<%I$O!"MxMQ$G$-$J$$$3$H$,(B
- $B$"$j$^$9!#JQ$JF0:n$r$9$k$h$&$J$i(B hex $B$N;XDj$r$9$k$N$,NI$$$G$7$g$&!#(B
-
-(2) smbclient $B%3%^%s%I(B
- $B%7%U%H%3!<%I$J$I$N4X78$G!"4A;z$d2>L>$r4^$s$@%U%!%$%kL>$N(B ls $B$NI=<($,Mp$l$k$3$H$,$"$j(B
- $B$^$9!#(B
-
-(3) $B%o%$%k%I%+!<%I$K$D$$$F(B
- $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>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
-
-5. $B$=$NB>(B
-
- hex $B7A<0$NJQ49J}K!$O!"(B
-
- $BBgLZ!wBgDM!&C^GH(B <ohki@gssm.otsuka.tsukuba.ac.jp>$B;a(B
-
- $B$,:n$i$l$?%3!<%I$rMxMQ$7$F$$$^$9!#(B
-
-1994$BG/(B10$B7n(B28$BF|(B $BBh#1HG(B
-1995$BG/(B 8$B7n(B16$BF|(B $BBh#2HG(B
-$BF#ED(B $B?r(B fujita@ainix.isac.co.jp
-
diff --git a/docs/textdocs/README.sambatar b/docs/textdocs/README.sambatar
deleted file mode 100644
index 26829952eb6..00000000000
--- a/docs/textdocs/README.sambatar
+++ /dev/null
@@ -1,15 +0,0 @@
-
-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
-Solaris 2.3, Linux 1.1.59 and DG/UX 5.4r3.10 with version 1.9.13 of samba.
-
-See the file INSTALL for installation instructions, and
-the man page and NOTES file for some basic usage. Please let me know if you
-have any problems getting it to work under your flavour of Unix.
-
-This is only (yet another) intermediate version of sambatar.
-This version also comes with an extra gift, zen.bas, written in
-microsoft qbasic by a colleague. It is (apparently) based on a 70s
-British sci-fi series known as Blake's 7. If you have any questions
-about this program, or any suggestions (e.g. what about servillan.bas
-?), feel free to mail the author (of zen.bas) greenm@lilhd.logica.com.
diff --git a/docs/textdocs/SCO.txt b/docs/textdocs/SCO.txt
deleted file mode 100644
index 1b3801471f7..00000000000
--- a/docs/textdocs/SCO.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-There is an annoying TCPIP bug in SCO Unix. This causes orruption when
-transferring files with Samba.
-
-Geza Makay (makayg@math.u-szeged.hu) sends this information:
-
-The patch you need is UOD385 Connection Drivers SLS. It is available from
-SCO (ftp.sco.com, directory SLS, files uod385a.Z and uod385a.ltr.Z).
-
-You do not need anything else but the above patch. It installs in seconds,
-and corrected the Excel problem. We also had some other minor problems (not
-only with Samba) that disappeared by installing this patch.
-
diff --git a/docs/textdocs/SMBTAR.notes b/docs/textdocs/SMBTAR.notes
deleted file mode 100644
index a23cbf2b325..00000000000
--- a/docs/textdocs/SMBTAR.notes
+++ /dev/null
@@ -1,40 +0,0 @@
-
-Intro
------
-
-sambatar is just a small extension to the smbclient program distributed with
-samba. A basic front end shell script, smbtar, is provided as an interface
-to the smbclient extensions.
-
-Extensions
-----------
-
-This release adds the following extensions to smbclient,
-
-tar [c|x] filename
- creates or restores from a tar file. The tar file may be a tape
-or a unix tar file. tar's behaviour is modified with the newer and tarmode
-commands.
-
-tarmode [full|inc|reset|noreset]
- With no arguments, tarmode prints the current tar mode (by default full,
-noreset). In full mode, every file is backed up during a tar command.
-In incremental, only files with the dos archive bit set are backed up.
-The archive bit is reset if in reset mode, or left untouched if in noreset.
-In reset mode, the share has to be writable, which makes sambatar even
-less secure. An alternative might be to use tarmode inc noreset which
-would implement an "expanding incremental" backup (which some may prefer
-anyway).
-
-setmode <setmode string> filename
- This is a "freebie" - nothing really to do with sambatar. This
-is a crude attrib like command (only the other way around). Setmode string
-is a combination of +-rhsa. So for example -rh would reset the read only
-bit on filename.
-
-newer filename
- This is in fact part of the 1.9.13 samba distribution, but comes
-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
diff --git a/docs/textdocs/Speed.txt b/docs/textdocs/Speed.txt
deleted file mode 100644
index 5dfd70323b1..00000000000
--- a/docs/textdocs/Speed.txt
+++ /dev/null
@@ -1,272 +0,0 @@
-This file tries to outline the ways to improve the speed of a Samba server.
-
-Andrew Tridgell
-January 1995
-
-
-COMPARISONS
------------
-
-The Samba server uses TCP to talk to the client. Thus if you are
-trying to see if it performs well you should really compare it to
-programs that use the same protocol. The most readily available
-programs for file transfer that use TCP are ftp or another TCP based
-SMB server.
-
-If you want to test against something like a NT or WfWg server then
-you will have to disable all but TCP on either the client or
-server. Otherwise you may well be using a totally different protocol
-(such as Netbeui) and comparisons may not be valid.
-
-Generally you should find that Samba performs similarly to ftp at raw
-transfer speed. It should perform quite a bit faster than NFS,
-although this very much depends on your system.
-
-Several people have done comparisons between Samba and Novell, NFS or
-WinNT. In some cases Samba performed the best, in others the worst. I
-suspect the biggest factor is not Samba vs some other system but the
-hardware and drivers used on the various systems. Given similar
-hardware Samba should certainly be competitive in speed with other
-systems.
-
-
-SOCKET OPTIONS
---------------
-
-There are a number of socket options that can greatly affect the
-performance of a TCP based server like Samba.
-
-The socket options that Samba uses are settable both on the command
-line with the -O option, or in the smb.conf file.
-
-The "socket options" section of the smb.conf manual page describes how
-to set these and gives recommendations.
-
-Getting the socket options right can make a big difference to your
-performance, but getting them wrong can degrade it by just as
-much. The correct settings are very dependent on your local network.
-
-The socket option TCP_NODELAY is the one that seems to make the
-biggest single difference for most networks. Many people report that
-adding "socket options = TCP_NODELAY" doubles the read performance of
-a Samba drive. The best explanation I have seen for this is that the
-Microsoft TCP/IP stack is slow in sending tcp ACKs.
-
-
-READ SIZE
----------
-
-The option "read size" affects the overlap of disk reads/writes with
-network reads/writes. If the amount of data being transferred in
-several of the SMB commands (currently SMBwrite, SMBwriteX and
-SMBreadbraw) is larger than this value then the server begins writing
-the data before it has received the whole packet from the network, or
-in the case of SMBreadbraw, it begins writing to the network before
-all the data has been read from disk.
-
-This overlapping works best when the speeds of disk and network access
-are similar, having very little effect when the speed of one is much
-greater than the other.
-
-The default value is 16384, but very little experimentation has been
-done yet to determine the optimal value, and it is likely that the best
-value will vary greatly between systems anyway. A value over 65536 is
-pointless and will cause you to allocate memory unnecessarily.
-
-
-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.
-
-It defaults to 65536 bytes (the maximum), but it is possible that some
-clients may perform better with a smaller transmit unit. Trying values
-of less than 2048 is likely to cause severe problems.
-
-In most cases the default is the best option.
-
-
-LOCKING
--------
-
-By default Samba does not implement strict locking on each read/write
-call (although it did in previous versions). If you enable strict
-locking (using "strict locking = yes") then you may find that you
-suffer a severe performance hit on some systems.
-
-The performance hit will probably be greater on NFS mounted
-filesystems, but could be quite high even on local disks.
-
-
-SHARE MODES
------------
-
-Some people find that opening files is very slow. This is often
-because of the "share modes" code needed to fully implement the dos
-share modes stuff. You can disable this code using "share modes =
-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.
-
-LOG LEVEL
----------
-
-If you set the log level (also known as "debug level") higher than 2
-then you may suffer a large drop in performance. This is because the
-server flushes the log file after each operation, which can be very
-expensive.
-
-
-WIDE LINKS
-----------
-
-The "wide links" option is now enabled by default, but if you disable
-it (for better security) then you may suffer a performance hit in
-resolving filenames. The performance loss is lessened if you have
-"getwd cache = yes", which is now the default.
-
-
-READ RAW
---------
-
-The "read raw" operation is designed to be an optimised, low-latency
-file read operation. A server may choose to not support it,
-however. and Samba makes support for "read raw" optional, with it
-being enabled by default.
-
-In some cases clients don't handle "read raw" very well and actually
-get lower performance using it than they get using the conventional
-read operations.
-
-So you might like to try "read raw = no" and see what happens on your
-network. It might lower, raise or not affect your performance. Only
-testing can really tell.
-
-
-WRITE RAW
----------
-
-The "write raw" operation is designed to be an optimised, low-latency
-file write operation. A server may choose to not support it,
-however. and Samba makes support for "write raw" optional, with it
-being enabled by default.
-
-Some machines may find "write raw" slower than normal write, in which
-case you may wish to change this option.
-
-READ PREDICTION
----------------
-
-Samba can do read prediction on some of the SMB commands. Read
-prediction means that Samba reads some extra data on the last file it
-read while waiting for the next SMB command to arrive. It can then
-respond more quickly when the next read request arrives.
-
-This is disabled by default. You can enable it by using "read
-prediction = yes".
-
-Note that read prediction is only used on files that were opened read
-only.
-
-Read prediction should particularly help for those silly clients (such
-as "Write" under NT) which do lots of very small reads on a file.
-
-Samba will not read ahead more data than the amount specified in the
-"read size" option. It always reads ahead on 1k block boundaries.
-
-
-MEMORY MAPPING
---------------
-
-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
-on the FLAGS line of the Makefile.
-
-Note that memory mapping is only used on files opened read only, and
-is not used by the "read raw" operation. Thus you may find memory
-mapping is more effective if you disable "read raw" using "read raw =
-no".
-
-
-SLOW CLIENTS
-------------
-
-One person has reported that setting the protocol to COREPLUS rather
-than LANMAN2 gave a dramatic speed improvement (from 10k/s to 150k/s).
-
-I suspect that his PC's (386sx16 based) were asking for more data than
-they could chew. I suspect a similar speed could be had by setting
-"read raw = no" and "max xmit = 2048", instead of changing the
-protocol. Lowering the "read size" might also help.
-
-
-SLOW LOGINS
------------
-
-Slow logins are almost always due to the password checking time. Using
-the lowest practical "password level" will improve things a lot. You
-could also enable the "UFC crypt" option in the Makefile.
-
-CLIENT TUNING
--------------
-
-Often a speed problem can be traced to the client. The client (for
-example Windows for Workgroups) can often be tuned for better TCP
-performance.
-
-See your client docs for details. In particular, I have heard rumours
-that the WfWg options TCPWINDOWSIZE and TCPSEGMENTSIZE can have a
-large impact on performance.
-
-Also note that some people have found that setting DefaultRcvWindow in
-the [MSTCP] section of the SYSTEM.INI file under WfWg to 3072 gives a
-big improvement. I don't know why.
-
-My own experience wth DefaultRcvWindow is that I get much better
-performance with a large value (16384 or larger). Other people have
-reported that anything over 3072 slows things down enourmously. One
-person even reported a speed drop of a factor of 30 when he went from
-3072 to 8192. I don't know why.
-
-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
-----------
-
-Some people want to see real numbers in a document like this, so here
-they are. I have a 486sx33 client running WfWg 3.11 with the 3.11b
-tcp/ip stack. It has a slow IDE drive and 20Mb of ram. It has a SMC
-Elite-16 ISA bus ethernet card. The only WfWg tuning I've done is to
-set DefaultRcvWindow in the [MSTCP] section of system.ini to 16384. My
-server is a 486dx3-66 running Linux. It also has 20Mb of ram and a SMC
-Elite-16 card. You can see my server config in the examples/tridge/
-subdirectory of the distribution.
-
-I get 490k/s on reading a 8Mb file with copy.
-I get 441k/s writing the same file to the samba server.
-
-Of course, there's a lot more to benchmarks than 2 raw throughput
-figures, but it gives you a ballpark figure.
-
-I've also tested Win95 and WinNT, and found WinNT gave me the best
-speed as a samba client. The fastest client of all (for me) is
-smbclient running on another linux box. Maybe I'll add those results
-here someday ...
-
-
-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
diff --git a/docs/textdocs/Support.txt b/docs/textdocs/Support.txt
deleted file mode 100644
index d71bdaf7b3e..00000000000
--- a/docs/textdocs/Support.txt
+++ /dev/null
@@ -1,376 +0,0 @@
-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.
-
-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.
-
-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.
-
-You can contact the maintainers at samba-bugs@anu.edu.au
-
-
-------------------------------------------------------------------------------
-BRISBANE - AUSTRALIA
-
-Brett Worth
-Select Computer Technology - Brisbane
-431 Logan Road
-Stones Corner QLD 4120
-E-Mail: brett@sct.com.au
-------------------------------------------------------------------------------
-
-------------------------------------------------------------------------------
-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.
-------------------------------------------------------------------------------
-
-------------------------------------------------------------------------------
-READING - ENGLAND
-
-Philip Hands | E-Mail: info@hands.com
-Philip Hands Computing Ltd. | Tel: +44 1734 476287 Fax: 1734 474655
-Unit 1, Cherry Close, Caversham, Reading RG4 8UP UK
-
-Samba experience: SVR4,SVR3.2 & Linux <--> WfWg, W3.1, OS2 and MS-LanMan
-------------------------------------------------------------------------------
-
-------------------------------------------------------------------------------
-ILLONOIS - USA
-
-Information One, Inc.
-736 Hinman Ave, Suite 2W
-Evanston, IL 60202
-708-328-9137 708-328-0117 FAX
-info@info1.com
-
-Providing custom Internet and networking solutions.
-------------------------------------------------------------------------------
-
-------------------------------------------------------------------------------
-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.
-
-Mauro DePalma <mauro@sru.com>
-------------------------------------------------------------------------------
-
-------------------------------------------------------------------------------
-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.
-------------------------------------------------------------------------------
-
-------------------------------------------------------------------------------
-CANBERRA - AUSTRALIA
-
-Ben Elliston
-Faculty of Information Sciences and Engineering
-University of Canberra AUSTRALIA
-E-mail: ben@ise.canberra.edu.au (Uni)
-------------------------------------------------------------------------------
-
-------------------------------------------------------------------------------
-PALERMO - ITALY
-
-Francesco Cardinale
-E-Mail: cardinal@palermo.italtel.it
-Samba experience: SVR3.2, SOLARIS, ULTRIX, LINUX <--> DOS LAN-MAN, WFW
-------------------------------------------------------------------------------
-
-------------------------------------------------------------------------------
-SYDNEY - AUSTRALIA
-
-John Terpstra - Aquasoft (jht@aquasoft.com.au)
-Business: +612 524 4040
-Home: +612 540 3154
-Shoephone: +612 414 334422 (aka 0414 334422)
-------------------------------------------------------------------------------
-
-------------------------------------------------------------------------------
-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/
-
-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.
-------------------------------------------------------------------------------
-
------------------------------------------------------------------------
-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)
------------------------------------------------------------------------
-
-------------------------------------------------------------------------------
-EDINBUGH - SCOTLAND
-
-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
-
-SAMBA experience: SCO UNIX <=> WfWg
-------------------------------------------------------------------------------
-
-------------------------------------------------------------------------------
-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
-------------------------------------------------------------------------------
-
-------------------------------------------------------------------------------
-SYDNEY - AUSTRALIA
-
-Pacific ESI has used and installed Samba since 1.6 on a range
-of machines running SunOS, BSD/OS, SCO/UNIX, HP/UX, and Solaris,
-and WfWG and Windows95. The largest system worked on to date
-involved an Australia wide network of machines with PCs and SUNs
-at the various nodes. The in-house testing site is a wide area
-network with three sites, remotely connected with PPP and with
-SUN servers at each site to all of which are connected several
-PCs running mainly WfWG.
-
-Stefan Kjellberg Pacific Engineering Systems
-International
-info@eram.esi.com.au Voice:+61-2-9063377
-... Fax:+61-2-9063468
-------------------------------------------------------------------------------
-
-------------------------------------------------------------------------------
-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.
-------------------------------------------------------------------------------
-
-------------------------------------------------------------------------------
-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 <
-------------------------------------------------------------------------------
-
-----------------------------------------------------------
-Adelaide, Australia
-
-NS Computer Software and Services P/L
-PO Box 86
-Ingle Farm
-SA 5098
-
-Contact: Richard Sharpe
- Ph: +61-8-281-0063 (08-281-0063) AH
- FAX:+61-8-250-2080 (08-250-2080)
-
-Experience with: ULTRIX, Digital UNIX, SunOS, WfW 3.11, Win95, WNT 3.51
-
-----------------------------------------------------------
-
-----------------------------------------------------------
-TECTONIC LIMITED
-WESTWOOD
-78 LOUGHBOROUGH ROAD
-QUORN
-LEICESTERSHIRE
-LE12 8DX
-
-TELEPHONE 01509-620922
-FAX 01509-620933
-
-CONTACT DAVID ROBINSON
-
-WE ARE UNIX ORIENTATED BUT ALSO SPECIALISE IN PC TO UNIX COMMUNICATIONS, WE
-KNOW AND UNDERSTAND PC-NFS, (HENCE OUR INTEREST IN SAMBA).
-WE SUPPORT SUNOS, SOLARIS 1.X AND 2.X, HP-UX 9.0 AND 10.0, OSF (or DEC UNIX,
-whichever you prefer), WinNT, WfWG and Win95.
-
-WE ARE 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
-----------------------------------------------------------
-
-----------------------------------------------------------
-MIAMI, FL - 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)
-----------------------------------------------------------
-
-------------------------------------------------------------------------------
-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.
-------------------------------------------------------------------------------
-
-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
-
-------------------------------------------------------------------------------
-
------------------------------------------------------------------------
-QUEBEC - CANADA
-
-Dataden Computer Systems
-Attn: Danny Arseneau
-arseneau@parkmed.com
-895 2nd Avenue
-Ile Bizard, Quebec
-Canada, H9C 1K3
-Tel: (514)891-2293
-Fax: (514)696-0848
-
-Dataden is company that specializes in Unix--TCP/IP networking.
-We have over 15 years of experience. We have been installing,
-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
-
-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
-
-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
-------------------------------------------------------------------------------
-
diff --git a/docs/textdocs/UNIX-SMB.txt b/docs/textdocs/UNIX-SMB.txt
deleted file mode 100644
index b2c064215cf..00000000000
--- a/docs/textdocs/UNIX-SMB.txt
+++ /dev/null
@@ -1,220 +0,0 @@
-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
-interoperability.
-
-It was written to help out a person who was writing a paper on unix to
-PC connectivity.
-
-Andrew Tridgell
-April 1995
-
-
-Usernames
-=========
-
-The SMB protocol has only a loose username concept. Early SMB
-protocols (such as CORE and COREPLUS) have no username concept at
-all. Even in later protocols clients often attempt operations
-(particularly printer operations) without first validating a username
-on the server.
-
-Unix security is based around username/password pairs. A unix box
-should not allow clients to do any substantive operation without some
-sort of validation.
-
-The problem mostly manifests itself when the unix server is in "share
-level" security mode. This is the default mode as the alternative
-"user level" security mode usually forces a client to connect to the
-server as the same user for each connected share, which is
-inconvenient in many sites.
-
-In "share level" security the client normally gives a username in the
-"session setup" protocol, but does not supply an accompanying
-password. The client then connects to resources using the "tree
-connect" protocol, and supplies a password. The problem is that the
-user on the PC types the username and the password in different
-contexts, unaware that they need to go together to give access to the
-server. The username is normally the one the user typed in when they
-"logged onto" the PC (this assumes Windows for Workgroups). The
-password is the one they chose when connecting to the disk or printer.
-
-The user often chooses a totally different username for their login as
-for the drive connection. Often they also want to access different
-drives as different usernames. The unix server needs some way of
-divining the correct username to combine with each password.
-
-Samba tries to avoid this problem using several methods. These succeed
-in the vast majority of cases. The methods include username maps, the
-service%user syntax, the saving of session setup usernames for later
-validation and the derivation of the username from the service name
-(either directly or via the user= option).
-
-File Ownership
-==============
-
-The commonly used SMB protocols have no way of saying "you can't do
-that because you don't own the file". They have, in fact, no concept
-of file ownership at all.
-
-This brings up all sorts of interesting problems. For example, when
-you copy a file to a unix drive, and the file is world writeable but
-owned by another user the file will transfer correctly but will
-receive the wrong date. This is because the utime() call under unix
-only succeeds for the owner of the file, or root, even if the file is
-world writeable. For security reasons Samba does all file operations
-as the validated user, not root, so the utime() fails. This can stuff
-up shared development diectories as programs like "make" will not get
-file time comparisons right.
-
-There are several possible solutions to this problem, including
-username mapping, and forcing a specific username for particular
-shares.
-
-Passwords
-=========
-
-Many SMB clients uppercase passwords before sending them. I have no
-idea why they do this. Interestingly WfWg uppercases the password only
-if the server is running a protocol greater than COREPLUS, so
-obviously it isn't just the data entry routines that are to blame.
-
-Unix passwords are case sensitive. So if users use mixed case
-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
-(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.
-
-Locking
-=======
-
-The locking calls available under a DOS/Windows environment are much
-richer than those available in unix. This means a unix server (like
-Samba) choosing to use the standard fcntl() based unix locking calls
-to implement SMB locking has to improvise a bit.
-
-One major problem is that dos locks can be in a 32 bit (unsigned)
-range. Unix locking calls are 32 bits, but are signed, giving only a 31
-bit range. Unfortunately OLE2 clients use the top bit to select a
-locking range used for OLE semaphores.
-
-To work around this problem Samba compresses the 32 bit range into 31
-bits by appropriate bit shifting. This seems to work but is not
-ideal. In a future version a separate SMB lockd may be added to cope
-with the problem.
-
-It also doesn't help that many unix lockd daemons are very buggy and
-crash at the slightest provocation. They normally go mostly unused in
-a unix environment because few unix programs use byte range
-locking. The stress of huge numbers of lock requests from dos/windows
-clients can kill the daemon on some systems.
-
-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
-opportunistic locking, and currently Samba has no support for it.
-
-Deny Modes
-==========
-
-When a SMB client opens a file it asks for a particular "deny mode" to
-be placed on the file. These modes (DENY_NONE, DENY_READ, DENY_WRITE,
-DENY_ALL, DENY_FCB and DENY_DOS) specify what actions should be
-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
-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.
-
-Trapdoor UIDs
-=============
-
-A SMB session can run with several uids on the one socket. This
-happens when a user connects to two shares with different
-usernames. To cope with this the unix server needs to switch uids
-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.
-
-Port numbers
-============
-
-There is a convention that clients on sockets use high "unprivilaged"
-port numbers (>1000) and connect to servers on low "privilaged" port
-numbers. This is enforced in Unix as non-root users can't open a
-socket for listening on port numbers less than 1000.
-
-Most PC based SMB clients (such as WfWg and WinNT) don't follow this
-convention completely. The main culprit is the netbios nameserving on
-udp port 137. Name query requests come from a source port of 137. This
-is a problem when you combine it with the common firewalling technique
-of not allowing incoming packets on low port numbers. This means that
-these clients can't query a netbios nameserver on the other side of a
-low port based firewall.
-
-The problem is more severe with netbios node status queries. I've
-found that WfWg, Win95 and WinNT3.5 all respond to netbios node status
-queries on port 137 no matter what the source port was in the
-request. This works between machines that are both using port 137, but
-it means it's not possible for a unix user to do a node status request
-to any of these OSes unless they are running as root. The answer comes
-back, but it goes to port 137 which the unix user can't listen
-on. Interestingly WinNT3.1 got this right - it sends node status
-responses back to the source port in the request.
-
-
-Protocol Complexity
-===================
-
-There are many "protocol levels" in the SMB protocol. It seems that
-each time new functionality was added to a Microsoft operating system,
-they added the equivalent functions in a new protocol level of the SMB
-protocol to "externalise" the new capabilities.
-
-This means the protocol is very "rich", offering many ways of doing
-each file operation. This means SMB servers need to be complex and
-large. It also means it is very difficult to make them bug free. It is
-not just Samba that suffers from this problem, other servers such as
-WinNT don't support every variation of every call and it has almost
-certainly been a headache for MS developers to support the myriad of
-SMB calls that are available.
-
-There are about 65 "top level" operations in the SMB protocol (things
-like SMBread and SMBwrite). Some of these include hundreds of
-sub-functions (SMBtrans has at least 120 sub-functions, like
-DosPrintQAdd and NetSessionEnum). All of them take several options
-that can change the way they work. Many take dozens of possible
-"information levels" that change the structures that need to be
-returned. Samba supports all but 2 of the "top level" functions. It
-supports only 8 (so far) of the SMBtrans sub-functions. Even NT
-doesn't support them all.
-
-Samba currently supports up to the "NT LM 0.12" protocol, which is the
-one preferred by Win95 and WinNT3.5. Luckily this protocol level has a
-"capabilities" field which specifies which super-duper new-fangled
-options the server suports. This helps to make the implementation of
-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.
-
diff --git a/docs/textdocs/WinNT.txt b/docs/textdocs/WinNT.txt
deleted file mode 100644
index b57abb7742e..00000000000
--- a/docs/textdocs/WinNT.txt
+++ /dev/null
@@ -1,56 +0,0 @@
-There are some particular issues with Samba and Windows NT
-
-=====================================================================
-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
-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.
-
-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.
-=====================================================================
-
-
-
-=====================================================================
-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:
-
-------------
- I noticed in your change-log you noted that some people were
-still unable to use print manager under NT. If this is the same problem
-that I encountered, it's caused by the length of time it takes NT to
-determine if the printer is ready.
-
-The problem occurs when you double-click on a printer to connect it to
-the NT machine. Because it's unable to determine if the printer is ready
-in the short span of time it has, it assumes it isn't and gives some
-strange error about not having enough resources (I forget what the error
-is). A solution to this that seems to work fine for us is to click
-once on the printer, look at the bottom of the window and wait until
-it says it's ready, then clilck on "OK".
-
-By the way, this problem probably occurs in our group because the
-Samba server doesn't actually have the printers - it queues them to
-remote printers either on other machines or using their own network
-cards. Because of this "middle layer", it takes an extra amount of
-time for the NT machine to get verification that the printer queue
-actually exists.
-
-I hope this helped in some way...
------------
-=====================================================================
-
-
-
diff --git a/examples/README b/examples/README
deleted file mode 100644
index 3e58e0faf1c..00000000000
--- a/examples/README
+++ /dev/null
@@ -1,6 +0,0 @@
-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.
-
-Send it to: Andrew.Tridgell@anu.edu.au
-
diff --git a/examples/dce-dfs/README b/examples/dce-dfs/README
deleted file mode 100644
index 4aaba8bb33e..00000000000
--- a/examples/dce-dfs/README
+++ /dev/null
@@ -1,4 +0,0 @@
-this is a sample configuration file from Jim Doyle <doyle@oec.com> who
-did the DCE/DFS patches for Samba. It shows how to make DCE/DFS shares
-available.
-
diff --git a/examples/dce-dfs/smb.conf b/examples/dce-dfs/smb.conf
deleted file mode 100644
index f5f155b8e6c..00000000000
--- a/examples/dce-dfs/smb.conf
+++ /dev/null
@@ -1,42 +0,0 @@
-[global]
- printing = bsd
- printcap name = /etc/printcap
- load printers = no
- guest account = guest
- log file = /usr/local/samba/var/log.%m
- log level = 8
- password level = 8
-
-[homes]
- comment = Home Directories
- browseable = no
- read only = no
- create mode = 0750
-
-[test]
- comment = test stuff
- path = /dept/mis/home/testacct
- valid users = testacct
- public = no
- writable = yes
-
-[namespace]
- comment = DCE-DFS Global Root
- path = /...
- public = no
- writable = yes
-
-[oecdfs]
- comment = Corporate Cell
- path = /.../corp.boston.oec.com/fs
- browseable = no
- read only = no
- create mode = 0750
-
-[develdfs]
- comment = Technology Development Cell
- path = /.../devel.boston.oec.com/fs
- browseable = no
- read only = no
- create mode = 0750
-
diff --git a/examples/misc/extra_smbstatus b/examples/misc/extra_smbstatus
deleted file mode 100644
index b018f3dcce9..00000000000
--- a/examples/misc/extra_smbstatus
+++ /dev/null
@@ -1,47 +0,0 @@
-Here's something that Paul Blackman sent me that may be useful:
-
--------------------
-I created this script to do a few things that smbstatus doesn't at the
-moment. Perhaps you might want to include these. Sorry I haven't
-added things at source level, script was quick&easy.
-
-*******
-#!/bin/csh
-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.
- else if ($1 == "-l") then
- echo `date '+ %d/%m/%y %H:%M:%S'` `smbstatus -p |sort -u |grep -n -v z
-|grep -c :` >>$2
-else
- smbstatus |sort +3 -4 -u
-endif
-******
-
-The '-p' option was just to show unique PIDs.
-
-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.
-
-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)
-
-Cheers,
-~^ MIME OK ^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~
- o | Paul Blackman ictinus@lake.canberra.edu.au
- o | Co-operative Research ------------------------
- o _ | Centre For Freshwater Ecology. Ph. (Aus) 06 2012518
- -- (") o | University of Canberra, Australia. Fax. " 06 2015038
- \_|_-- |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- | | "Spend a little love and get high"
- _/ \_ | - Lenny Kravitz
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-~~~~ SAMBA Web Pages: http://samba.canberra.edu.au/pub/samba/samba.html ~~~~~
-
diff --git a/examples/misc/wall.perl b/examples/misc/wall.perl
deleted file mode 100644
index fc3dc2e2c05..00000000000
--- a/examples/misc/wall.perl
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/usr/local/bin/perl
-#
-#@(#) smb-wall.pl Description:
-#@(#) A perl script which allows you to announce whatever you choose to
-#@(#) every PC client currently connected to a Samba Server...
-#@(#) ...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>
-#
-#=============================================================================
-$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";
-
-while ( <STDIN> ) {
- /^\.$/ && last;
- push(@message, $_);
-}
-
-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);
-}
-
-foreach $pc ( keys(%pcclient) ) {
- print STDOUT "Sending message ";
- $debug && print STDOUT " <@message> \n";
- print STDOUT "To <$pc>\n";
- open(SENDMSG,"|$smbclient -M $pc") || next;
- print SENDMSG @message;
- close(SENDMSG);
-}
diff --git a/examples/printing/smbprint b/examples/printing/smbprint
deleted file mode 100755
index a80d60ce4fa..00000000000
--- a/examples/printing/smbprint
+++ /dev/null
@@ -1,77 +0,0 @@
-#!/bin/sh -x
-
-# This script is an input filter for printcap printing on a unix machine. It
-# uses the smbclient program to print the file to the specified smb-based
-# server and service.
-# For example you could have a printcap entry like this
-#
-# smb:lp=/dev/null:sd=/usr/spool/smb:sh:if=/usr/local/samba/smbprint
-#
-# which would create a unix printer called "smb" that will print via this
-# script. You will need to create the spool directory /usr/spool/smb with
-# appropriate permissions and ownerships for your system.
-
-# 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.
-
-#
-# Script further altered by hamiltom@ecnz.co.nz (Michael Hamilton)
-# so that the server, service, and password can be read from
-# a /usr/var/spool/lpd/PRINTNAME/.config file.
-#
-# In order for this to work the /etc/printcap entry must include an
-# accounting file (af=...):
-#
-# cdcolour:\
-# :cm=CD IBM Colorjet on 6th:\
-# :sd=/var/spool/lpd/cdcolour:\
-# :af=/var/spool/lpd/cdcolour/acct:\
-# :if=/usr/local/etc/smbprint:\
-# :mx=0:\
-# :lp=/dev/null:
-#
-# The /usr/var/spool/lpd/PRINTNAME/.config file should contain:
-# server=PC_SERVER
-# service=PR_SHARENAME
-# password="password"
-#
-# E.g.
-# server=PAULS_PC
-# service=CJET_371
-# password=""
-
-#
-# Debugging log file, change to /dev/null if you like.
-#
-logfile=/tmp/smb-print.log
-# logfile=/dev/null
-
-
-#
-# The last parameter to the filter is the accounting file name.
-# Extract the directory name from the file name.
-# Concat this with /.config to get the config file.
-#
-eval acct_file=\$$#
-spool_dir=`dirname $acct_file`
-config_file=$spool_dir/.config
-
-# Should read the following variables set in the config file:
-# server
-# service
-# password
-eval `cat $config_file`
-
-#
-# Some debugging help, change the >> to > if you want to same space.
-#
-echo "server $server, service $service" >> $logfile
-
-(
-# 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/local/samba/bin/smbclient "\\\\$server\\$service" $password -U $server -N -P >> $logfile
diff --git a/examples/printing/smbprint.sysv b/examples/printing/smbprint.sysv
deleted file mode 100644
index 3e1cec47f50..00000000000
--- a/examples/printing/smbprint.sysv
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/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 $*
-) | /opt/samba/smbclient "\\\\$server\\$service" $password -N -P > /dev/null
-exit $?
-
diff --git a/examples/simple/README b/examples/simple/README
deleted file mode 100644
index 9628aa8260d..00000000000
--- a/examples/simple/README
+++ /dev/null
@@ -1,2 +0,0 @@
-This is the "original" sample config file.
-
diff --git a/examples/simple/smb.conf b/examples/simple/smb.conf
deleted file mode 100644
index cdf65b337f7..00000000000
--- a/examples/simple/smb.conf
+++ /dev/null
@@ -1,165 +0,0 @@
-; 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).
-;
-; 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.
-;
-; Things you need to check:
-; --------------------------
-;
-; 1: Check the path to your printcap file. If you are using a system that does
-; not use printcap (eg., Solaris), create a file containing lines of the
-; form
-;
-; printername|printername|printername|
-;
-; where each "printername" is the name of a printer you want to provide
-; access to. Then alter the "printcap =" entry to point to the new file.
-;
-; If using Solaris, the following command will generate a suitable printcap
-; file:
-;
-; lpc status | grep ":" | sed s/:/\|/ > myprintcap
-;
-; 2: Make sure the "print command" entry is correct for your system. This
-; command should submit a file (represented by %s) to a printer
-; (represented by %p) for printing and should REMOVE the file after
-; printing.
-;
-; One most systems the default will be OK, as long as you get "printing ="
-; right.
-;
-; It is also a good idea to use an absolute path in the print command
-; as there is no guarantee the search path will be set correctly.
-;
-; 3: Make sure the "printing =" option is set correctly for your system.
-; Possible values are "sysv", "bsd" or "aix".
-;
-; 4: Make sure the "lpq command" entry is correct for your system. The default
-; may not work for you.
-;
-; 5: Make sure that the user specified in "guest account" exists. Typically
-; this will be a user that cannot log in and has minimal privileges.
-; Often the "nobody" account doesn't work (very system dependant).
-;
-; 6: You should consider the "security =" option. See a full description
-; in the main documentation and the smb.conf(5) manual page
-;
-; 7: Look at the "hosts allow" option, unless you want everyone on the internet
-; to be able to access your files.
-;
-[global]
- printing = bsd
- printcap name = /etc/printcap
- load printers = yes
- guest account = pcguest
-; This next option sets a separate log file for each client. Remove
-; it if you want a combined log file.
- log file = /usr/local/samba/log.%m
-
-; 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
-; lock directory = /usr/local/samba/var/locks
-; share modes = yes
-
-[homes]
- comment = Home Directories
- browseable = no
- read only = no
- create mode = 0750
-
-[printers]
- comment = All Printers
- browseable = no
- printable = yes
- public = no
- writable = no
- create mode = 0700
-
-; you might also want this one
-; [tmp]
-; comment = Temporary file space
-; path = /tmp
-; read only = no
-; public = yes
-
-;
-; 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 publicly accessible directory, but read only, except for people in
-; the staff group
-;[public]
-; comment = Public Stuff
-; path = /usr/somewhere/public
-; public = yes
-; writable = no
-; printable = no
-; write list = @staff
-;
-; 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
-; writeable = 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/tridge/README b/examples/tridge/README
deleted file mode 100644
index 11c72f20b3a..00000000000
--- a/examples/tridge/README
+++ /dev/null
@@ -1,8 +0,0 @@
-This is the configuration I use at home. I have 2 client PCs, one
-running Win95, one running alternately WfWg and NTAS3.5. My server is
-a 486dx2-66 Linux box.
-
-Note that I use the %a and %m macros to load smb.conf extensions
-particular to machines and architectures. This gives me a lot of
-flexibility in how I handle each of the machines.
-
diff --git a/examples/tridge/smb.conf b/examples/tridge/smb.conf
deleted file mode 100644
index a2f269f3b76..00000000000
--- a/examples/tridge/smb.conf
+++ /dev/null
@@ -1,101 +0,0 @@
-[global]
- config file = /usr/local/samba/smb.conf.%m
- status = yes
- security = user
- encrypt passwords = yes
- server string = Tridge (%v,%h)
- load printers = yes
- log level = 1
- log file = /usr/local/samba/var/log.%m
- guest account = pcguest
- hosts allow = 192.0.2. localhost
- password level = 2
- auto services = tridge susan
- message command = csh -c '/usr/bin/X11/xedit -display :0 %s;rm %s' &
- read prediction = yes
- socket options = TCP_NODELAY
- valid chars = ö:Ö å:Å ä:Ä
- share modes = yes
- locking = yes
- strict locking = yes
- keepalive = 30
- include = /usr/local/samba/lib/smb.conf.%m
- include = /usr/local/samba/lib/smb.conf.%a
-
-
-[uniprint]
- comment = University Printing
- path = /home/susan/print
- user = susan
- postscript = yes
- print ok = yes
- print command = xmenu -heading "%s" OK&
-
-[testprn]
- comment = Test printer
- path = /tmp
- user = susan
- print ok = yes
- print command = cp %s /tmp/smb.%U.prn
- lpq command = cat /tmp/xxyz
-
-[amd]
- comment = amd area
- path = /mount
- force user = tridge
- read only = no
-
-[homes]
- browseable = no
- guest ok = no
- read only = no
- create mask = 0755
-
-[printers]
- browseable = no
- comment = Printer in Printcap
- guest ok = no
- path = /tmp
- read only = no
- print ok = yes
-
-[dos]
- browseable = yes
- comment = Dos Files
- force group = samba
- create mode = 0775
- path = /home/tridge/dos
- copy = homes
-
-[msoffice]
- browseable = yes
- comment = Microsoft Office
- force group = samba
- create mode = 0775
- path = /data/msoffice
- read only = yes
-
-[root]
- comment = Root Dir
- copy = dos
- path = /
- dont descend = /proc ./proc /etc
-
-[tmp]
- comment = tmp files
- copy = dos
- path = /tmp
- read only = no
-
-
-[cdrom]
- comment = Tridge's CdRom
- path = /mount/cdrom
- read only = yes
- locking = no
-
-[data]
- comment = Data Partition
- path = /data
- read only = yes
- guest ok = yes
diff --git a/examples/tridge/smb.conf.WinNT b/examples/tridge/smb.conf.WinNT
deleted file mode 100644
index f490f830ca7..00000000000
--- a/examples/tridge/smb.conf.WinNT
+++ /dev/null
@@ -1,14 +0,0 @@
-#log level = 4
-#readraw = no
-#writeraw = no
-
-
-
-
-
-
-
-
-
-
-
diff --git a/examples/tridge/smb.conf.fjall b/examples/tridge/smb.conf.fjall
deleted file mode 100644
index 76f4d0e3cad..00000000000
--- a/examples/tridge/smb.conf.fjall
+++ /dev/null
@@ -1,21 +0,0 @@
-;log level = 4
-;readraw = no
-;writeraw = no
-;password level = 4
-;mangled map = (;1 )
-;protocol = lanman1
-;user = susan
-;getwd cache = no
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/examples/tridge/smb.conf.lapland b/examples/tridge/smb.conf.lapland
deleted file mode 100644
index f490f830ca7..00000000000
--- a/examples/tridge/smb.conf.lapland
+++ /dev/null
@@ -1,14 +0,0 @@
-#log level = 4
-#readraw = no
-#writeraw = no
-
-
-
-
-
-
-
-
-
-
-
diff --git a/examples/tridge/smb.conf.vittjokk b/examples/tridge/smb.conf.vittjokk
deleted file mode 100644
index 919ecd15420..00000000000
--- a/examples/tridge/smb.conf.vittjokk
+++ /dev/null
@@ -1,14 +0,0 @@
-;protocol = LANMAN2
-log level = 2
-
-
-
-
-
-
-
-
-
-
-
-
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/Makefile.lib b/source/Makefile.lib
new file mode 100644
index 00000000000..22102d7dfb9
--- /dev/null
+++ b/source/Makefile.lib
@@ -0,0 +1,32 @@
+###########################################################################
+# Library Makefile for Samba SMB client/server for unix
+# Copyright (C) Andrew Tridgell 1992-1996
+# Copyright (C) John H Terpstra 1995-1997
+# Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+###########################################################################
+
+all : $(THIS_LIB)
+
+.SUFFIXES:
+.SUFFIXES: .c .o .h
+
+.c.o: $(INCLUDES)
+ @echo Compiling $*.c
+ @$(CC) $(CFLAGS) -c $*.c -o $*.o
+
+$(THIS_LIB): $(THIS_OBJ) $(LIB_INCS)
+ @echo Linking $@
+ @$(AR) $@ $(THIS_OBJ)
+ @$(RANLIB) $@
+
+clean:
+ rm -f core $(THIS_OBJ) $(THIS_LIB) *~
+
+cleandir: clean
+ rm -f .depend tags
+
+realclean: clean
+
+proto:
+ @$(SHELL) ../checkos.sh $(FLAGSM)
+ $(AWK) -f ../mkproto.awk `echo $(THIS_PROTO_OBJ) | sed -e 's/\.o/\.c/g' | tr ' ' '\n' | sort | uniq` > $(LIBNAME)_proto.h
diff --git a/source/cgi.c b/source/cgi.c
new file mode 100644
index 00000000000..f165c56110b
--- /dev/null
+++ b/source/cgi.c
@@ -0,0 +1,621 @@
+/*
+ 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 <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pwd.h>
+
+#define MAX_VARIABLES 10000
+
+#ifdef DEBUG_COMMENTS
+extern void print_title(char *fmt, ...);
+#endif
+
+struct var {
+ char *name;
+ char *value;
+};
+
+static struct var variables[MAX_VARIABLES];
+static int num_variables;
+static int content_length;
+static int request_post;
+static int request_get;
+static char *query_string;
+
+static void unescape(char *buf)
+{
+ char *p=buf;
+
+ while ((p=strchr(p,'+')))
+ *p = ' ';
+
+ p = buf;
+
+ while (p && *p && (p=strchr(p,'%'))) {
+ int c1 = p[1];
+ int c2 = p[2];
+
+ 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 {p++; continue;}
+
+ 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 {p++; continue;}
+
+ *p = (c1<<4) | c2;
+
+ memcpy(p+1, p+3, strlen(p+3)+1);
+ p++;
+ }
+}
+
+
+static char *grab_line(FILE *f, int *cl)
+{
+ char *ret;
+ int i = 0;
+ int len = 1024;
+
+ ret = (char *)malloc(len);
+ if (!ret) return NULL;
+
+
+ while ((*cl)) {
+ int c = fgetc(f);
+ (*cl)--;
+
+ if (c == EOF) {
+ (*cl) = 0;
+ break;
+ }
+
+ if (c == '\r') continue;
+
+ if (strchr("\n&", c)) break;
+
+ ret[i++] = c;
+
+ if (i == len-1) {
+ char *ret2;
+ ret2 = (char *)realloc(ret, len*2);
+ if (!ret2) return ret;
+ len *= 2;
+ ret = ret2;
+ }
+ }
+
+
+ ret[i] = 0;
+ return ret;
+}
+
+/***************************************************************************
+ load all the variables passed to the CGI program. May have multiple variables
+ with the same name and the same or different values. Takes a file parameter
+ for simulating CGI invocation eg loading saved preferences.
+ ***************************************************************************/
+void cgi_load_variables(FILE *f1)
+{
+ FILE *f = f1;
+ static char *line;
+ char *p, *s, *tok;
+ int len;
+
+#ifdef DEBUG_COMMENTS
+ char dummy[100]="";
+ print_title(dummy);
+ printf("<!== Start dump in cgi_load_variables() %s ==>\n",__FILE__);
+#endif
+
+ if (!f1) {
+ f = stdin;
+ if (!content_length) {
+ p = getenv("CONTENT_LENGTH");
+ len = p?atoi(p):0;
+ } else {
+ len = content_length;
+ }
+ } else {
+ fseek(f, 0, SEEK_END);
+ len = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ }
+
+
+ if (len > 0 &&
+ (f1 || request_post ||
+ ((s=getenv("REQUEST_METHOD")) &&
+ strcasecmp(s,"POST")==0))) {
+ while (len && (line=grab_line(f, &len))) {
+ p = strchr(line,'=');
+ if (!p) continue;
+
+ *p = 0;
+
+ variables[num_variables].name = strdup(line);
+ variables[num_variables].value = strdup(p+1);
+
+ free(line);
+
+ if (!variables[num_variables].name ||
+ !variables[num_variables].value)
+ continue;
+
+ unescape(variables[num_variables].value);
+ unescape(variables[num_variables].name);
+
+#ifdef DEBUG_COMMENTS
+ printf("<!== POST var %s has value \"%s\" ==>\n",
+ variables[num_variables].name,
+ variables[num_variables].value);
+#endif
+
+ num_variables++;
+ if (num_variables == MAX_VARIABLES) break;
+ }
+ }
+
+ if (f1) {
+#ifdef DEBUG_COMMENTS
+ printf("<!== End dump in cgi_load_variables() ==>\n");
+#endif
+ return;
+ }
+
+ fclose(stdin);
+
+ if ((s=query_string) || (s=getenv("QUERY_STRING"))) {
+ for (tok=strtok(s,"&;");tok;tok=strtok(NULL,"&;")) {
+ p = strchr(tok,'=');
+ if (!p) continue;
+
+ *p = 0;
+
+ variables[num_variables].name = strdup(tok);
+ variables[num_variables].value = strdup(p+1);
+
+ if (!variables[num_variables].name ||
+ !variables[num_variables].value)
+ continue;
+
+ unescape(variables[num_variables].value);
+ unescape(variables[num_variables].name);
+
+#ifdef DEBUG_COMMENTS
+ printf("<!== Commandline var %s has value \"%s\" ==>\n",
+ variables[num_variables].name,
+ variables[num_variables].value);
+#endif
+ num_variables++;
+ if (num_variables == MAX_VARIABLES) break;
+ }
+
+ }
+#ifdef DEBUG_COMMENTS
+ printf("<!== End dump in cgi_load_variables() ==>\n");
+#endif
+}
+
+
+/***************************************************************************
+ find a variable passed via CGI
+ Doesn't quite do what you think in the case of POST text variables, because
+ if they exist they might have a value of "" or even " ", depending on the
+ browser. Also doesn't allow for variables[] containing multiple variables
+ with the same name and the same or different values.
+ ***************************************************************************/
+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 a particular cgi variable
+ ***************************************************************************/
+char *cgi_vnum(int i, char **name)
+{
+ if (i < 0 || i >= num_variables) return NULL;
+ *name = variables[i].name;
+ return variables[i].value;
+}
+
+/***************************************************************************
+ 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;
+}
+
+/***************************************************************************
+like strdup() but quotes < > and &
+ ***************************************************************************/
+char *quotedup(char *s)
+{
+ int i, n=0;
+ int len;
+ char *ret;
+ char *d;
+
+ if (!s) return strdup("");
+
+ len = strlen(s);
+
+ for (i=0;i<len;i++)
+ if (s[i] == '<' || s[i] == '>' || s[i] == '&')
+ n++;
+
+ ret = malloc(len + n*6 + 1);
+
+ if (!ret) return NULL;
+
+ d = ret;
+
+ for (i=0;i<len;i++) {
+ switch (s[i]) {
+ case '<':
+ strcpy(d, "&lt;");
+ d += 4;
+ break;
+
+ case '>':
+ strcpy(d, "&gt;");
+ d += 4;
+ break;
+
+ case '&':
+ strcpy(d, "&amp;");
+ d += 5;
+ break;
+
+ default:
+ *d++ = s[i];
+ }
+ }
+
+ *d = 0;
+
+ return ret;
+}
+
+
+/***************************************************************************
+like strdup() but quotes a wide range of characters
+ ***************************************************************************/
+char *urlquote(char *s)
+{
+ int i, n=0;
+ int len;
+ char *ret;
+ char *d;
+ char *qlist = "\"\n\r'&<> \t+;";
+
+ if (!s) return strdup("");
+
+ len = strlen(s);
+
+ for (i=0;i<len;i++)
+ if (strchr(qlist, s[i])) n++;
+
+ ret = malloc(len + n*2 + 1);
+
+ if (!ret) return NULL;
+
+ d = ret;
+
+ for (i=0;i<len;i++) {
+ if (strchr(qlist,s[i])) {
+ sprintf(d, "%%%02X", (int)s[i]);
+ d += 3;
+ } else {
+ *d++ = s[i];
+ }
+ }
+
+ *d = 0;
+
+ return ret;
+}
+
+
+/***************************************************************************
+like strdup() but quotes " characters
+ ***************************************************************************/
+char *quotequotes(char *s)
+{
+ int i, n=0;
+ int len;
+ char *ret;
+ char *d;
+
+ if (!s) return strdup("");
+
+ len = strlen(s);
+
+ for (i=0;i<len;i++)
+ if (s[i] == '"')
+ n++;
+
+ ret = malloc(len + n*6 + 1);
+
+ if (!ret) return NULL;
+
+ d = ret;
+
+ for (i=0;i<len;i++) {
+ switch (s[i]) {
+ case '"':
+ strcpy(d, "&quot;");
+ d += 6;
+ break;
+
+ default:
+ *d++ = s[i];
+ }
+ }
+
+ *d = 0;
+
+ return ret;
+}
+
+
+/***************************************************************************
+quote spaces in a buffer
+ ***************************************************************************/
+void quote_spaces(char *buf)
+{
+ while (*buf) {
+ if (*buf == ' ') *buf = '+';
+ buf++;
+ }
+}
+
+
+
+/***************************************************************************
+tell a browser about a fatal error in the http processing
+ ***************************************************************************/
+static void cgi_setup_error(char *err, char *header, char *info)
+{
+ printf("HTTP/1.1 %s\r\n%sConnection: close\r\nContent-Type: text/html\r\n\r\n<HTML><HEAD><TITLE>%s</TITLE></HEAD><BODY><H1>%s</H1>%s<p></BODY></HTML>\r\n", err, header, err, err, info);
+ exit(0);
+}
+
+
+/***************************************************************************
+decode a base64 string in-place - simple and slow algorithm
+ ***************************************************************************/
+static void base64_decode(char *s)
+{
+ char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ int bit_offset, byte_offset, idx, i;
+ unsigned char *d = (unsigned char *)s;
+ char *p;
+
+ i=0;
+
+ while (*s && (p=strchr(b64,*s))) {
+ idx = (int)(p - b64);
+ byte_offset = (i*6)/8;
+ bit_offset = (i*6)%8;
+ d[byte_offset] &= ~((1<<(8-bit_offset))-1);
+ if (bit_offset < 3) {
+ d[byte_offset] |= (idx << (2-bit_offset));
+ } else {
+ d[byte_offset] |= (idx >> (bit_offset-2));
+ d[byte_offset+1] = 0;
+ d[byte_offset+1] |= (idx << (8-(bit_offset-2))) & 0xFF;
+ }
+ s++; i++;
+ }
+}
+
+
+/***************************************************************************
+handle a http authentication line
+ ***************************************************************************/
+static int cgi_handle_authorization(char *line)
+{
+ char *p, *user, *pass;
+ struct passwd *pwd;
+ int ret=0;
+
+ if (strncasecmp(line,"Basic ", 6)) {
+ cgi_setup_error("401 Bad Authorization", "",
+ "Only basic authorization is understood");
+ }
+ line += 6;
+ while (line[0] == ' ') line++;
+ base64_decode(line);
+ if (!(p=strchr(line,':'))) {
+ cgi_setup_error("401 Bad Authorization", "",
+ "username/password must be supplied");
+ }
+ *p = 0;
+ user = line;
+ pass = p+1;
+
+ /* currently only allow connections as root */
+ if (strcasecmp(user,"root")) {
+ cgi_setup_error("401 Bad Authorization", "",
+ "incorrect username/password");
+ }
+
+ pwd = getpwnam(user);
+
+ if (!strcmp((char *)crypt(pass, pwd->pw_passwd),pwd->pw_passwd)) {
+ ret = 1;
+ }
+
+ memset(pass, 0, strlen(pass));
+
+ return ret;
+}
+
+
+/***************************************************************************
+handle a file download
+ ***************************************************************************/
+static void cgi_download(char *file)
+{
+ struct stat st;
+ char buf[1024];
+ int fd, l, i;
+ char *p;
+
+ /* sanitise the filename */
+ for (i=0;file[i];i++) {
+ if (!isalnum(file[i]) && !strchr("/.-_", file[i])) {
+ cgi_setup_error("404 File Not Found","",
+ "Illegal character in filename");
+ }
+ }
+
+ if (strstr(file,"..")) {
+ cgi_setup_error("404 File Not Found","",
+ "Relative paths not allowed");
+ }
+
+ if (!file_exist(file, &st)) {
+ cgi_setup_error("404 File Not Found","",
+ "The requested file was not found");
+ }
+ fd = open(file,O_RDONLY);
+ if (fd == -1) {
+ cgi_setup_error("404 File Not Found","",
+ "The requested file was not found");
+ }
+ printf("HTTP/1.1 200 OK\r\n");
+ if ((p=strrchr(file,'.'))) {
+ if (strcmp(p,".gif")==0 || strcmp(p,".jpg")==0) {
+ printf("Content-Type: image/gif\r\n");
+ } else {
+ printf("Content-Type: text/html\r\n");
+ }
+ }
+ printf("Content-Length: %d\r\n\r\n", (int)st.st_size);
+ while ((l=read(fd,buf,sizeof(buf)))>0) {
+ fwrite(buf, 1, l, stdout);
+ }
+ close(fd);
+ exit(0);
+}
+
+
+/***************************************************************************
+setup the cgi framework, handling the possability that this program is either
+run as a true cgi program by a web browser or is itself a mini web server
+ ***************************************************************************/
+void cgi_setup(char *rootdir)
+{
+ int authenticated = 0;
+ char line[1024];
+ char *url=NULL;
+ char *p;
+
+ if (chdir(rootdir)) {
+ cgi_setup_error("400 Server Error", "",
+ "chdir failed - the server is not configured correctly");
+ }
+
+ if (getenv("CONTENT_LENGTH") || getenv("REQUEST_METHOD")) {
+ /* assume we are running under a real web server */
+ return;
+ }
+
+ /* we are a mini-web server. We need to read the request from stdin
+ and handle authentication etc */
+ while (fgets(line, sizeof(line)-1, stdin)) {
+ if (line[0] == '\r' || line[0] == '\n') break;
+ if (strncasecmp(line,"GET ", 4)==0) {
+ request_get = 1;
+ url = strdup(&line[4]);
+ } else if (strncasecmp(line,"POST ", 5)==0) {
+ request_post = 1;
+ url = strdup(&line[5]);
+ } else if (strncasecmp(line,"PUT ", 4)==0) {
+ cgi_setup_error("400 Bad Request", "",
+ "This server does not accept PUT requests");
+ } else if (strncasecmp(line,"Authorization: ", 15)==0) {
+ authenticated = cgi_handle_authorization(&line[15]);
+ } else if (strncasecmp(line,"Content-Length: ", 16)==0) {
+ content_length = atoi(&line[16]);
+ }
+ /* ignore all other requests! */
+ }
+
+ if (!authenticated) {
+ cgi_setup_error("401 Authorization Required",
+ "WWW-Authenticate: Basic realm=\"root\"\r\n",
+ "You must be authenticated to use this service");
+ }
+
+ if (!url) {
+ cgi_setup_error("400 Bad Request", "",
+ "You must specify a GET or POST request");
+ }
+
+ /* trim the URL */
+ if ((p = strchr(url,' ')) || (p=strchr(url,'\t'))) {
+ *p = 0;
+ }
+ while (*url && strchr("\r\n",url[strlen(url)-1])) {
+ url[strlen(url)-1] = 0;
+ }
+
+ /* anything following a ? in the URL is part of the query string */
+ if ((p=strchr(url,'?'))) {
+ query_string = p+1;
+ *p = 0;
+ }
+
+ if (strcmp(url,"/")) {
+ cgi_download(url+1);
+ }
+
+ printf("HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Type: text/html\r\n\r\n");
+
+}
+
+
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..4333092b07a 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,58 +122,37 @@ 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);
- if (new != UNKNOWN_CODE) {
- coding_system = new;
+ interpret_coding_system(code);
return True;
- }
- 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 +210,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 +252,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 +392,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 +466,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,0,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 +689,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 +750,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 +764,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 +788,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 +1026,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 +1045,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,14 +1093,16 @@ 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);
+ SSVAL(outbuf,smb_vwv2,1); /* return additional info */
SSVAL(outbuf,smb_vwv3,(DENY_NONE<<4));
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 +1146,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 +1236,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 +1300,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 +1352,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 +1394,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 +1414,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 +1438,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 +1568,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 +1649,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 +1731,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 +1773,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 +1830,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 +1906,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 +1939,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 +2042,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 +2076,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 +2122,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 +2131,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, 0,PTR_DIFF(p,param),0, 0,
+ 6, 1000,
&rprcnt,&rdrcnt,
- param,NULL,
+ param,NULL, NULL,
&rparam,&rdata))
{
int res = SVAL(rparam,0);
@@ -2261,12 +2205,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,0,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 +2268,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 +2324,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 +2349,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 +2369,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 +2382,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 +2432,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, 0,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, 0,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 +2676,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 +2742,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 +2786,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 +2831,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 +2937,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 +2970,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, 0,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 +3052,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 +3062,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, 0,PTR_DIFF(p,param),0, 0,
+ 6, 1000,
&rprcnt,&rdrcnt,
- param,NULL,
+ param,NULL, NULL,
&rparam,&rdata))
{
int res = SVAL(rparam,0);
@@ -3563,39 +3093,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, 0,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 +3163,8 @@ static BOOL list_servers()
printf("\t%-16.16s %s\n",
sname,
comment_offset?rdata+comment_offset-converter:"");
-
+
+ ok=True;
p2 += 26;
}
}
@@ -3627,12 +3173,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, 0,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 +3203,7 @@ static BOOL list_servers()
sname,
comment_offset?rdata+comment_offset-converter:"");
+ ok=True;
p2 += 26;
}
}
@@ -3664,14 +3212,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 +3242,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 +3250,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 +3329,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 +3367,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 +3404,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 +3420,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 +3470,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 +3514,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 +3540,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 +3591,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 +3629,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 +3660,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 +3670,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 +3702,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 +3748,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 +3776,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 +3816,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 +3849,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 +3864,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 +3879,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 +3920,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..4064dbecd78
--- /dev/null
+++ b/source/client/clientutil.c
@@ -0,0 +1,951 @@
+/*
+ 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 smb_login_passwd = "";
+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 pipe_name_len,
+ 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);
+
+ if (pipe_name_len == 0) pipe_name_len = strlen(pipe_name);
+
+ cli_send_trans_request(outbuf,SMBtrans,pipe_name, pipe_name_len, 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 namelen, 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 ? namelen+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)
+ memcpy(p,name, namelen+1); /* 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: ");
+
+ pstrcpy(smb_login_passwd, pass);
+
+ /* 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));
+}
+
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..7e360981c02
--- /dev/null
+++ b/source/client/ntclient.c
@@ -0,0 +1,354 @@
+/*
+ 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 smb_login_passwd;
+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;
+
+ uchar sess_key[8];
+ 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 = rpc_pipe_open(inbuf, outbuf, PIPE_LSARPC, Client, cnum)) == 0xffff)
+ {
+ free(inbuf); free(outbuf);
+ return False;
+ }
+
+ /**************** Set Named Pipe State ***************/
+ if (!rpc_pipe_set_hnd_state(PIPE_LSARPC, fnum, 0x4300))
+ {
+ 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[%x]\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 (!rpc_pipe_bind(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 = rpc_pipe_open(inbuf, outbuf, PIPE_NETLOGON, Client, cnum)) == 0xffff)
+ {
+ free(inbuf); free(outbuf);
+ return False;
+ }
+
+ /**************** Set Named Pipe State ***************/
+ if (!rpc_pipe_set_hnd_state(PIPE_NETLOGON, fnum, 0x4300))
+ {
+ free(inbuf); free(outbuf);
+ return False;
+ }
+
+ /******************* bind request on \PIPE\NETLOGON *****************/
+
+ if (!rpc_pipe_bind(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, "$");
+
+ SIVAL(clnt_chal.data, 0, 0x11111111);
+ SIVAL(clnt_chal.data, 4, 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 ***********************/
+
+ {
+ char lm_owf_user_pwd[16];
+ char nt_owf_user_pwd[16];
+ nt_lm_owf_gen(smb_login_passwd, nt_owf_user_pwd, lm_owf_user_pwd);
+
+#ifdef DEBUG_PASSWORD
+
+ DEBUG(100,("nt owf of user password: "));
+ dump_data(100, lm_owf_user_pwd, 16);
+
+ DEBUG(100,("nt owf of user password: "));
+ dump_data(100, nt_owf_user_pwd, 16);
+
+#endif
+
+ /* this is used in both the SAM Logon and the SAM Logoff */
+ make_id_info1(&id1, workgroup, 0,
+ getuid(), 0,
+ username, myhostname,
+ sess_key, lm_owf_user_pwd, nt_owf_user_pwd);
+ }
+
+ /*********************** 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..cada77e7326 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
@@ -139,6 +139,9 @@
#endif
#include <sys/socket.h>
+#ifdef AXPROC
+#include <termio.h>
+#endif
#include <sys/ioctl.h>
#include <stddef.h>
#ifdef POSIX_H
@@ -183,10 +186,6 @@
#endif
#endif
-#if USE_MMAP
-#include <sys/mman.h>
-#endif
-
#if defined(GETPWANAM)
#include <sys/types.h>
#include <sys/label.h>
@@ -194,31 +193,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
@@ -236,20 +214,36 @@ Here come some platform specific sections
#include <string.h>
#include <sys/vfs.h>
#include <netinet/in.h>
-#ifndef NO_ASMSIGNALH
-#include <asm/signal.h>
+#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 +265,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 +297,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 +315,12 @@ extern int innetgr (const char *, const char *, const char *, const char *);
#define USE_STATVFS
#define USE_GETCWD
#define USE_SETSID
+#define USE_SYSV_IPC
+#define NO_SEMUN
+#ifndef REPLACE_GETPASS
#define REPLACE_GETPASS
+#endif /* REPLACE_GETPASS */
+#define USE_SIGPROCMASK
#endif
@@ -323,9 +338,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 +353,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 +374,8 @@ char *getwd(char *);
#define SIGNAL_CAST (void (*)())
#define USE_STATVFS
#define USE_WAITPID
+#define USE_SETSID
+#define USE_SYSV_IPC
#endif
@@ -409,6 +432,8 @@ extern struct passwd *getpwnam();
#define USE_STATVFS
#define USE_GETCWD
#define USE_SETSID
+#define USE_SYSV_IPC
+#define NO_SEMUN
#endif
@@ -423,6 +448,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 +459,8 @@ char *mktemp(char *); /* No standard include */
#define PASSWORD_LENGTH 16
#define NEED_AUTH_PARAMETERS
#endif /* OSF1_ENH_SEC */
+#define USE_SYSV_IPC
+#define NO_SEMUN
#endif
@@ -448,7 +476,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 +505,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 +535,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 +560,22 @@ 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 NO_SEMUN
#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 +595,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 +655,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 +684,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 +814,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 +949,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 +1026,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 +1073,18 @@ struct spwd { /* fake shadow password structure */
#endif
#endif
+#ifdef USE_SYSV_IPC
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <sys/shm.h>
+#ifdef NO_SEMUN
+union semun {
+ int val;
+ struct semid_ds *buf;
+ unsigned short *array;
+};
+#endif
+#endif
#ifdef AFS_AUTH
#include <afs/stds.h>
@@ -953,6 +1096,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,24 +1124,33 @@ extern char *sys_errlist[];
#include "version.h"
#include "smb.h"
+#include "nameserv.h"
+#include "ubiqx/ubi_dLinkList.h"
+
#include "byteorder.h"
-#ifdef SMB_PASSWD
-#include "smbpass.h"
-#endif
#include "kanji.h"
#include "charset.h"
+/***** automatically generated prototypes *****/
+#include "proto.h"
+
+
+
#ifndef S_IFREG
#define S_IFREG 0100000
#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 +1204,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 +1224,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..528680d88a9 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
@@ -118,13 +125,7 @@ extern char *sj_strstr (const char *s1, const char *s2);
#define CAP_CODE (6)
#define DOSV_CODE SJIS_CODE
-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..ae791d84e62 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,26 @@
/* 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 from the client. */
+
+#define OPLOCK_BREAK_TIMEOUT 30
+
+/* Timout (in seconds) to add to the oplock break timeout
+ to wait for the smbd to smbd message to return. */
+
+#define OPLOCK_BREAK_TIMEOUT_FUDGEFACTOR 2
+
+/* 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..1b8d5be1417
--- /dev/null
+++ b/source/include/proto.h
@@ -0,0 +1,1373 @@
+/* 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 cgi.c */
+
+void cgi_load_variables(FILE *f1);
+char *cgi_variable(char *name);
+char *cgi_vnum(int i, char **name);
+int cgi_boolean(char *name, int def);
+char *quotedup(char *s);
+char *urlquote(char *s);
+char *quotequotes(char *s);
+void quote_spaces(char *buf);
+void cgi_setup(char *rootdir);
+
+/*The following definitions come from charcnv.c */
+
+char *unix2dos_format(char *str,BOOL overwrite);
+char *dos2unix_format(char *str, BOOL overwrite);
+void interpret_character_set(char *str);
+
+/*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 *pass, int passlen);
+BOOL cli_tdis(struct cli_state *cli);
+BOOL cli_unlink(struct cli_state *cli, char *fname);
+BOOL cli_mkdir(struct cli_state *cli, char *dname);
+BOOL cli_rmdir(struct cli_state *cli, char *dname);
+int cli_open(struct cli_state *cli, char *fname, int flags, int share_mode);
+BOOL cli_close(struct cli_state *cli, int fnum);
+BOOL cli_lock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout);
+BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout);
+int cli_read(struct cli_state *cli, int fnum, char *buf, uint32 offset, uint16 size);
+int cli_write(struct cli_state *cli, int fnum, char *buf, uint32 offset, uint16 size);
+BOOL cli_getatr(struct cli_state *cli, char *fname,
+ int *attr, uint32 *size, time_t *t);
+BOOL cli_setatr(struct cli_state *cli, char *fname, int attr, time_t t);
+BOOL cli_qpathinfo(struct cli_state *cli, char *fname,
+ time_t *c_time, time_t *a_time, time_t *m_time, uint32 *size);
+BOOL cli_qpathinfo2(struct cli_state *cli, char *fname,
+ time_t *c_time, time_t *a_time, time_t *m_time,
+ time_t *w_time, uint32 *size);
+BOOL cli_qfileinfo(struct cli_state *cli, int fnum,
+ time_t *c_time, time_t *a_time, time_t *m_time, uint32 *size);
+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);
+char *cli_errstr(struct cli_state *cli);
+void cli_error(struct cli_state *cli, int *eclass, int *num);
+void cli_sockopt(struct cli_state *cli, char *options);
+int cli_setpid(struct cli_state *cli, int pid);
+
+/*The following definitions come from clientutil.c */
+
+void cli_setup_pkt(char *outbuf);
+BOOL cli_call_api(char *pipe_name, int pipe_name_len,
+ 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 namelen, 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);
+
+/*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 */
+
+char *credstr(uchar *cred);
+void cred_session_key(DOM_CHAL *clnt_chal, DOM_CHAL *srv_chal, char *pass,
+ uchar session_key[8]);
+void cred_create(uchar session_key[8], DOM_CHAL *stor_cred, UTIME timestamp,
+ DOM_CHAL *cred);
+int cred_assert(DOM_CHAL *cred, uchar session_key[8], DOM_CHAL *stored_cred,
+ UTIME timestamp);
+BOOL clnt_deal_with_creds(uchar sess_key[8],
+ DOM_CRED *sto_clnt_cred, DOM_CRED *rcv_srv_cred);
+BOOL deal_with_creds(uchar sess_key[8],
+ 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, int size, int bufsize);
+
+/*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);
+
+/*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_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_remote_browse_sync(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);
+char *lp_domain_hostsallow(void);
+char *lp_domain_hostsdeny(void);
+BOOL lp_dns_proxy(void);
+BOOL lp_wins_support(void);
+BOOL lp_wins_proxy(void);
+BOOL lp_local_master(void);
+BOOL lp_domain_controller(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_veto_oplocks(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 mangle.c */
+
+int str_checksum(char *s);
+BOOL is_8_3(char *fname, BOOL check_case);
+void reset_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);
+void browse_sync_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 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 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 pipes.c */
+
+int reply_open_pipe_and_X(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_pipe_close(char *inbuf,char *outbuf);
+BOOL api_LsarpcSNPHS(int pnum, int cnum, char *param);
+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 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 rpc_pipes/lsa_hnd.c */
+
+void init_lsa_policy_hnd(void);
+BOOL open_lsa_policy_hnd(LSA_POL_HND *hnd);
+BOOL set_lsa_policy_samr_rid(LSA_POL_HND *hnd, uint32 rid);
+BOOL set_lsa_policy_samr_pol_status(LSA_POL_HND *hnd, uint32 pol_status);
+BOOL set_lsa_policy_samr_sid(LSA_POL_HND *hnd, DOM_SID *sid);
+uint32 get_lsa_policy_samr_rid(LSA_POL_HND *hnd);
+BOOL close_lsa_policy_hnd(LSA_POL_HND *hnd);
+
+/*The following definitions come from rpc_pipes/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);
+char* lsa_io_q_enum_trust_dom(BOOL io, LSA_Q_ENUM_TRUST_DOM *q_e, char *q, char *base, int align, int depth);
+void make_r_enum_trust_dom(LSA_R_ENUM_TRUST_DOM *r_e, LSA_POL_HND *hnd, uint32 status);
+char* lsa_io_r_enum_trust_dom(BOOL io, LSA_R_ENUM_TRUST_DOM *r_e, 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);
+void make_q_srv_pwset(LSA_Q_SRV_PWSET *q_s, char sess_key[8],
+ char *logon_srv, char *acct_name, uint16 sec_chan, char *comp_name,
+ DOM_CRED *cred, char nt_cypher[16]);
+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 rpc_pipes/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 rpc_pipes/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_srv_pwset(uint16 fnum, uint32 call_id,
+ uchar sess_key[8],
+ char *logon_srv, char *mach_acct, uint16 sec_chan_type, char *comp_name,
+ DOM_CRED *clnt_cred, DOM_CRED *srv_cred,
+ char nt_owf_new_mach_pwd[16]);
+BOOL do_lsa_sam_logon(uint16 fnum, uint32 call_id,
+ uchar sess_key[8], 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,
+ uchar sess_key[8], 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 rpc_pipes/ntclientpipe.c */
+
+uint16 rpc_pipe_open(char *inbuf, char *outbuf, char *rname, int Client, int cnum);
+BOOL rpc_pipe_set_hnd_state(char *pipe_name, uint16 fnum, uint16 device_state);
+BOOL rpc_pipe_bind(char *pipe_name, uint16 fnum, uint32 call_id,
+ RPC_IFACE *abstract, RPC_IFACE *transfer);
+
+/*The following definitions come from rpc_pipes/pipe_hnd.c */
+
+void reset_chain_pnum(void);
+void init_rpc_pipe_hnd(void);
+int open_rpc_pipe_hnd(char *pipe_name, int cnum);
+char *get_rpc_pipe_hnd_name(int pnum);
+BOOL set_rpc_pipe_hnd_state(int pnum, int cnum, uint16 device_state);
+BOOL close_rpc_pipe_hnd(int pnum, int cnum);
+int get_rpc_pipe_num(char *buf, int where);
+
+/*The following definitions come from rpc_pipes/pipenetlog.c */
+
+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 rpc_pipes/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 rpc_pipes/pipesamr.c */
+
+BOOL api_samrTNP(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 rpc_pipes/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 rpc_pipes/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 rpc_pipes/pipewkssvc.c */
+
+BOOL api_wkssvcTNP(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 rpc_pipes/samrparse.c */
+
+char* samr_io_q_close(BOOL io, SAMR_Q_CLOSE *q_u, char *q, char *base, int align, int depth);
+char* samr_io_r_close(BOOL io, SAMR_R_CLOSE *r_u, char *q, char *base, int align, int depth);
+char* samr_io_q_open_secret(BOOL io, SAMR_Q_OPEN_SECRET *q_u, char *q, char *base, int align, int depth);
+char* samr_io_r_open_secret(BOOL io, SAMR_R_OPEN_SECRET *r_u, char *q, char *base, int align, int depth);
+char* samr_io_q_lookup_rids(BOOL io, SAMR_Q_LOOKUP_RIDS *q_u, char *q, char *base, int align, int depth);
+void make_samr_r_lookup_rids(SAMR_R_LOOKUP_RIDS *r_u,
+ uint32 num_rids, uint32 rid, uint32 status);
+char* samr_io_r_lookup_rids(BOOL io, SAMR_R_LOOKUP_RIDS *r_u, char *q, char *base, int align, int depth);
+char* samr_io_q_unknown_22(BOOL io, SAMR_Q_UNKNOWN_22 *q_u, char *q, char *base, int align, int depth);
+char* samr_io_r_unknown_22(BOOL io, SAMR_R_UNKNOWN_22 *r_u, char *q, char *base, int align, int depth);
+char* samr_io_q_unknown_24(BOOL io, SAMR_Q_UNKNOWN_24 *q_u, char *q, char *base, int align, int depth);
+void make_samr_r_unknown_24(SAMR_R_UNKNOWN_24 *r_u,
+ uint16 unknown_0, NTTIME *expiry, char *mach_acct,
+ uint32 unknown_id_0, uint32 status);
+char* samr_io_r_unknown_24(BOOL io, SAMR_R_UNKNOWN_24 *r_u, char *q, char *base, int align, int depth);
+char* samr_io_q_unknown_32(BOOL io, SAMR_Q_UNKNOWN_32 *q_u, char *q, char *base, int align, int depth);
+char* samr_io_r_unknown_32(BOOL io, SAMR_R_UNKNOWN_32 *r_u, char *q, char *base, int align, int depth);
+char* samr_io_q_open_policy(BOOL io, SAMR_Q_OPEN_POLICY *q_u, char *q, char *base, int align, int depth);
+char* samr_io_r_open_policy(BOOL io, SAMR_R_OPEN_POLICY *r_u, char *q, char *base, int align, int depth);
+
+/*The following definitions come from rpc_pipes/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_dom_rid3(DOM_RID3 *rid3, uint32 rid);
+char* smb_io_dom_rid3(BOOL io, DOM_RID3 *rid3, 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* make_clnt_info(DOM_CLNT_INFO *clnt,
+ char *logon_srv, char *acct_name,
+ uint16 sec_chan, char *comp_name,
+ DOM_CRED *cred);
+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 *sess_key,
+ unsigned char lm_cypher[16], unsigned char nt_cypher[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 rpc_pipes/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 rpc_pipes/wksparse.c */
+
+char* wks_io_q_unknown_0(BOOL io, WKS_Q_UNKNOWN_0 *q_u, char *q, char *base, int align, int depth);
+char* wks_io_r_unknown_0(BOOL io, WKS_R_UNKNOWN_0 *r_u, char *q, char *base, int align, int depth);
+
+/*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 receive_next_smb(int smbfd, int oplockfd, char *inbuf, int bufsize, int timeout);
+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 smberr.c */
+
+char *smb_errstr(char *inbuf);
+
+/*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_smbpwd_entry(char *name, int smb_userid);
+BOOL add_smbpwd_entry(struct smb_passwd* pwd);
+BOOL mod_smbpwd_entry(struct smb_passwd* pwd);
+
+/*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 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 ubiqx/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..6056ccd70f7 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,9 @@
typedef int BOOL;
+/* 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 +75,10 @@ typedef short int16;
typedef int int32;
#endif
+#ifndef uint8
+typedef unsigned char uint8;
+#endif
+
#ifndef uint16
typedef unsigned short uint16;
#endif
@@ -72,26 +87,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 +149,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 +175,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 +251,1146 @@ 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_SAMR "\\PIPE\\samr"
+#define PIPE_WKSSVC "\\PIPE\\wkssvc"
+#define PIPE_NETLOGON "\\PIPE\\NETLOGON"
+#define PIPE_NTLSA "\\PIPE\\ntlsa"
+#define PIPE_NTSVCS "\\PIPE\\ntsvcs"
+#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 SAMR_CLOSE 0x01
+#define SAMR_OPEN_SECRET 0x07
+#define SAMR_LOOKUP_RIDS 0x11
+#define SAMR_UNKNOWN_3 0x03
+#define SAMR_UNKNOWN_22 0x22
+#define SAMR_UNKNOWN_24 0x24
+#define SAMR_UNKNOWN_34 0x34
+#define SAMR_OPEN_POLICY 0x39
+
+#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_SAMLOGOFF 0x03
+#define LSA_AUTH2 0x0f
+#define LSA_CLOSE 0x00
+
+/* XXXX these are here to get a compile! */
+
+#define LSA_OPENSECRET 0xFF
+#define LSA_LOOKUPSIDS 0xFE
+#define LSA_LOOKUPRIDS 0xFD
+#define LSA_LOOKUPNAMES 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 for ntlsa pipe */
+typedef struct domrid2_info
+{
+ uint32 type; /* value is 5 */
+ uint32 undoc; /* value is non-zero */
+ uint32 rid;
+ uint32 rid_idx; /* don't know what this is */
+
+} DOM_RID2;
+
+/* DOM_RID3 - domain RID structure for samr pipe */
+typedef struct domrid3_info
+{
+ uint32 rid; /* domain-relative (to a SID) id */
+ uint32 type1; /* value is 0x1 */
+ uint32 ptr_type; /* undocumented pointer */
+ uint32 type2; /* value is 0x1 */
+
+} DOM_RID3;
+
+/* 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
+{
+ uchar data[8]; /* 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
+{
+ uint32 ptr; /* undocumented buffer pointer */
+ 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_ENUM_TRUST_DOM - LSA enumerate trusted domains */
+typedef struct lsa_enum_trust_dom_info
+{
+ LSA_POL_HND pol; /* policy handle */
+ uint32 enum_context; /* enumeration context handle */
+ uint32 preferred_len; /* preferred maximum length */
+
+} LSA_Q_ENUM_TRUST_DOM;
+
+/* LSA_R_ENUM_TRUST_DOM - response to LSA enumerate trusted domains */
+typedef struct lsa_r_enum_trust_dom_info
+{
+ LSA_POL_HND pol; /* policy handle */
+
+ uint32 status; /* return code */
+
+} LSA_R_ENUM_TRUST_DOM;
+
+/* 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 RIDs by name */
+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;
+
+
+/* SAMR_Q_CLOSE - probably a policy handle close */
+typedef struct q_samr_close_info
+{
+ LSA_POL_HND pol; /* policy handle */
+
+} SAMR_Q_CLOSE;
+
+
+/* SAMR_R_CLOSE - probably a policy handle close */
+typedef struct r_samr_close_info
+{
+ LSA_POL_HND pol; /* policy handle */
+ uint32 status; /* return status */
+
+} SAMR_R_CLOSE;
+
+
+/****************************************************************************
+SAMR_Q_OPEN_SECRET - unknown_0 values seen associated with SIDs:
+
+0x0000 0200 and a specific domain sid - S-1-5-21-44c01ca6-797e5c3d-33f83fd0
+0x0000 0280 and a well-known domain sid - S-1-5-20
+0x2000 0000 and a well-known domain sid - S-1-5-20
+0x2000 0000 and a specific domain sid - S-1-5-21-44c01ca6-797e5c3d-33f83fd0
+*****************************************************************************/
+
+/* SAMR_Q_OPEN_SECRET - probably an open secret */
+typedef struct q_samr_open_secret_info
+{
+ LSA_POL_HND pol; /* policy handle */
+ uint32 unknown_0; /* 0x2000 0000; 0x0000 0211; 0x0000 0280; 0x0000 0200 - unknown */
+ DOM_SID dom_sid; /* domain SID */
+
+} SAMR_Q_OPEN_SECRET;
+
+
+/* SAMR_R_OPEN_SECRET - probably an open */
+typedef struct r_samr_open_secret_info
+{
+ LSA_POL_HND pol; /* policy handle associated with the SID */
+ uint32 status; /* return status */
+
+} SAMR_R_OPEN_SECRET;
+
+
+/****************************************************************************
+SAMR_Q_LOOKUP_RIDS - do a conversion (only one!) from name to RID.
+
+the policy handle allocated by an "samr open secret" call is associated
+with a SID. this policy handle is what is queried here, *not* the SID
+itself. the response to the lookup rids is relative to this SID.
+*****************************************************************************/
+/* SAMR_Q_LOOKUP_RIDS - probably a "read SAM entry" */
+typedef struct q_samr_lookup_names_info
+{
+ LSA_POL_HND pol; /* policy handle */
+
+ uint32 num_rids1; /* 1 - number of rids being looked up */
+ uint32 rid; /* 0000 03e8 - RID of the server being queried? */
+ uint32 ptr; /* 0 - 32 bit unknown */
+ uint32 num_rids2; /* 1 - number of rids being looked up */
+
+ UNIHDR hdr_mach_acct; /* unicode machine account name header */
+ UNISTR2 uni_mach_acct; /* unicode machine account name */
+
+} SAMR_Q_LOOKUP_RIDS;
+
+
+/* SAMR_R_LOOKUP_RIDS - probably an open */
+typedef struct r_samr_lookup_names_info
+{
+ uint32 num_entries;
+ uint32 undoc_buffer; /* undocumented buffer pointer */
+
+ uint32 num_entries2;
+ DOM_RID3 dom_rid[MAX_LOOKUP_SIDS]; /* domain RIDs being looked up */
+
+ uint32 num_entries3;
+
+ uint32 status; /* return code */
+
+} SAMR_R_LOOKUP_RIDS;
+
+
+/* SAMR_Q_UNKNOWN_22 - probably an open */
+typedef struct q_samr_unknown_22_info
+{
+ LSA_POL_HND pol; /* policy handle */
+ uint32 unknown_id_0; /* 0x0000 03E8 - 32 bit unknown id */
+
+} SAMR_Q_UNKNOWN_22;
+
+
+/* SAMR_R_UNKNOWN_22 - probably an open */
+typedef struct r_samr_unknown_22_info
+{
+ LSA_POL_HND pol; /* policy handle associated with unknown id */
+ uint32 status; /* return status */
+
+} SAMR_R_UNKNOWN_22;
+
+
+/* SAMR_Q_UNKNOWN_24 - probably a get sam info */
+typedef struct q_samr_unknown_24_info
+{
+ LSA_POL_HND pol; /* policy handle associated with unknown id */
+ uint16 unknown_0; /* 0x0015 or 0x0011 - 16 bit unknown */
+
+} SAMR_Q_UNKNOWN_24;
+
+
+/* SAMR_R_UNKNOWN_24 - probably a get sam info */
+typedef struct r_samr_unknown_24_info
+{
+ uint32 ptr; /* pointer */
+ uint16 unknown_0; /* 0x0015 or 0x0011 - 16 bit unknown (same as above) */
+ uint16 unknown_1; /* 0x8b73 - 16 bit unknown */
+ uint8 padding_0[16]; /* 0 - padding 16 bytes */
+ NTTIME expiry; /* expiry time or something? */
+ uint8 padding_1[24]; /* 0 - padding 24 bytes */
+
+ UNIHDR hdr_mach_acct; /* unicode header for machine account */
+ uint32 padding_2; /* 0 - padding 4 bytes */
+
+ uint32 ptr_1; /* pointer */
+ uint8 padding_3[32]; /* 0 - padding 32 bytes */
+ uint32 padding_4; /* 0 - padding 4 bytes */
+
+ uint32 ptr_2; /* pointer */
+ uint32 padding_5; /* 0 - padding 4 bytes */
+
+ uint32 ptr_3; /* pointer */
+ uint8 padding_6[32]; /* 0 - padding 32 bytes */
+
+ uint32 unknown_id_0; /* unknown id associated with policy handle */
+ uint16 unknown_2; /* 0x0201 - 16 bit unknown */
+ uint32 unknown_3; /* 0x0000 0080 - 32 bit unknown */
+ uint16 unknown_4; /* 0x003f - 16 bit unknown */
+ uint16 unknown_5; /* 0x003c - 16 bit unknown */
+
+ uint8 padding_7[16]; /* 0 - padding 16 bytes */
+ uint32 padding_8; /* 0 - padding 4 bytes */
+
+ UNISTR2 uni_mach_acct; /* unicode string for machine account */
+
+ uint8 padding_9[48]; /* 0 - padding 48 bytes */
+
+ uint32 status; /* return status */
+
+} SAMR_R_UNKNOWN_24;
+
+
+/* SAMR_Q_UNKNOWN_32 - probably a "create SAM entry" */
+typedef struct q_samr_unknown_32_info
+{
+ LSA_POL_HND pol; /* policy handle */
+
+ UNIHDR hdr_mach_acct; /* unicode machine account name header */
+ UNISTR2 uni_mach_acct; /* unicode machine account name */
+
+ uint32 unknown_0; /* 32 bit unknown */
+ uint16 unknown_1; /* 16 bit unknown */
+ uint16 unknown_2; /* 16 bit unknown */
+
+} SAMR_Q_UNKNOWN_32;
+
+
+/* SAMR_R_UNKNOWN_32 - probably a "create SAM entry" */
+typedef struct r_samr_unknown_32_info
+{
+ LSA_POL_HND pol; /* policy handle */
+ uint32 unknown_0; /* 0x0000 0030 - 32 bit unknown */
+ uint32 padding; /* 0 - 4 byte padding */
+
+ uint32 status; /* return status - 0xC000 0099: user exists */
+
+} SAMR_R_UNKNOWN_32;
+
+
+/* SAMR_Q_OPEN_POLICY - probably an open */
+typedef struct q_samr_open_policy_info
+{
+ uint32 ptr_srv_name; /* pointer (to server name?) */
+ UNISTR2 uni_srv_name; /* unicode server name starting with '\\' */
+
+ uint32 unknown_0; /* 32 bit unknown */
+
+} SAMR_Q_OPEN_POLICY;
+
+
+/* SAMR_R_OPEN_POLICY - probably an open */
+typedef struct r_samr_open_policy_info
+{
+ LSA_POL_HND pol; /* policy handle */
+ uint32 status; /* return status */
+
+} SAMR_R_OPEN_POLICY;
+
+
+/* WKS_Q_UNKNOWN_0 - probably a capabilities request */
+typedef struct q_wks_unknown_0_info
+{
+ uint32 ptr_srv_name; /* pointer (to server name?) */
+ UNISTR2 uni_srv_name; /* unicode server name starting with '\\' */
+
+ uint32 unknown_0; /* 0x64 - 32 bit unknown */
+ uint16 unknown_1; /* 16 bit unknown */
+
+} WKS_Q_UNKNOWN_0;
+
+
+/* WKS_R_UNKNOWN_0 - probably a capabilities request */
+typedef struct r_wks_unknown_0_info
+{
+ uint32 unknown_0; /* 64 - unknown */
+ uint32 ptr_1; /* pointer 1 */
+ uint32 unknown_1; /* 0x0000 01f4 - unknown */
+ uint32 ptr_srv_name; /* pointer to server name */
+ uint32 ptr_dom_name; /* pointer to domain name */
+ uint32 unknown_2; /* 4 - unknown */
+ uint32 unknown_3; /* 0 - unknown */
+
+ UNISTR2 uni_srv_name; /* unicode server name */
+ UNISTR2 uni_dom_name; /* unicode domainn name */
+ uint32 status; /* return status */
+
+} WKS_R_UNKNOWN_0;
+
+
+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 +1402,7 @@ typedef struct
time_t atime;
time_t ctime;
pstring name;
+
} file_info;
@@ -241,25 +1417,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 +1465,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 +1484,62 @@ 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). */
+ name_compare_entry *veto_oplock_list; /* Per-share list of files to refuse oplocks on. */
+
} 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 */
+
+ uchar sess_key[8]; /* 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 +1564,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 +1639,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 +1649,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 +1679,11 @@ 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 IS_VETO_OPLOCK_PATH(cnum,path) (is_in_path((path),Connections[(cnum)].veto_oplock_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 +1803,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 +1883,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 +1999,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 +2045,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 +2084,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..5218604e0e1 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,12 +233,10 @@ Byte offset Type name description
#define DIRLEN_GUESS (45+MAX(l1_achName,l2_achName))
-/* Function prototypes */
+/* NT uses a FILE_ATTRIBUTE_NORMAL when no other attributes
+ are set. */
-
-int reply_findnclose(char *inbuf,char *outbuf,int length,int bufsize);
-
-int reply_findclose(char *inbuf,char *outbuf,int length,int bufsize);
+#define NT_FILE_ATTRIBUTE_NORMAL 0x80
#endif
diff --git a/source/include/version.h b/source/include/version.h
index 9ad8b7d44b5..29917b10874 100644
--- a/source/include/version.h
+++ b/source/include/version.h
@@ -1 +1 @@
-#define VERSION "1.9.16alpha1"
+#define VERSION "1.9.18alpha11"
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..e1a7ac01db5 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,15 +150,13 @@ dos2unix_format (char *str, BOOL overwrite)
/*
* Interpret character set.
*/
-int
-interpret_character_set (char *str, int def)
+void interpret_character_set(char *str)
{
-
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"));
}
- return def;
}
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..8af2696a446
--- /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(2,("Added %s ip=%s ",description,inet_ntoa(iface->ip)));
+ DEBUG(2,("bcast=%s ",inet_ntoa(iface->bcast)));
+ DEBUG(2,("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..75d1affb200 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,18 +23,14 @@
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"
-/* coding system keep in */
-int coding_system = SJIS_CODE;
-
/* jis si/so sequence */
-char jis_kso = JIS_KSO;
-char jis_ksi = JIS_KSI;
-char hex_tag = HEXTAG;
+static char jis_kso = JIS_KSO;
+static char jis_ksi = JIS_KSI;
+static char hex_tag = HEXTAG;
/*******************************************************************
SHIFT JIS functions
@@ -43,8 +39,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 +78,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 +101,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 +119,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 +145,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 +154,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 +167,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 +199,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 +230,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 +239,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 +252,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 +302,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 +358,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 +417,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 +493,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 +549,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 +618,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 +643,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 +679,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 +707,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 +722,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,10 +771,9 @@ setup_string_function (int codes)
/*
* Interpret coding system.
*/
-int
-interpret_coding_system (char *str, int def)
+int interpret_coding_system(char *str)
{
- int codes = def;
+ int codes = UNKNOWN_CODE;
if (strequal (str, "sjis")) {
codes = SJIS_CODE;
@@ -889,7 +863,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..bab80ad6214
--- /dev/null
+++ b/source/lib/time.c
@@ -0,0 +1,477 @@
+/*
+ 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 -= LocTimeDiff(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,"%m/%d/%Y %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,"%m/%d/%Y %T",tm);
+ sprintf(TimeBuf+len," %c%02d%02d",
+ zone<0?'+':'-',absZoneMinutes/60,absZoneMinutes%60);
+ }
+#else
+ strftime(TimeBuf,100,"%m/%d/%Y %T",tm);
+#endif
+ return(TimeBuf);
+}
+
diff --git a/source/lib/ufc.c b/source/lib/ufc.c
index 8417285821a..3330111c2f5 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
*/
+
+static 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..1bd55cffe86
--- /dev/null
+++ b/source/libsmb/clientgen.c
@@ -0,0 +1,1395 @@
+/*
+ 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"
+#include "trans2.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*2)); /* hack */
+ this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+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*2,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)
+ SSVALS(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 */
+ 0, /*data count */
+ 8, /* 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)-converter;
+ char *cmnt = comment_offset?(rdata+comment_offset):"";
+ if (comment_offset < 0 || comment_offset > rdrcnt) continue;
+
+ 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 True;
+
+ 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 *pass, int passlen)
+{
+ fstring fullshare, pword;
+ char *p;
+ bzero(cli->outbuf,smb_size);
+ bzero(cli->inbuf,smb_size);
+
+ if (cli->sec_mode & 1) {
+ passlen = 1;
+ pass = "";
+ }
+
+ if ((cli->sec_mode & 2) && *pass && passlen != 24) {
+ passlen = 24;
+ SMBencrypt((uchar *)pass,(uchar *)cli->cryptkey,(uchar *)pword);
+ } else {
+ memcpy(pword, pass, passlen);
+ }
+
+ sprintf(fullshare, "\\\\%s\\%s", cli->desthost, share);
+
+ set_message(cli->outbuf,4,
+ 2 + strlen(fullshare) + 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,fullshare);
+ 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;
+}
+
+/****************************************************************************
+delete a file
+****************************************************************************/
+BOOL cli_unlink(struct cli_state *cli, char *fname)
+{
+ char *p;
+
+ bzero(cli->outbuf,smb_size);
+ bzero(cli->inbuf,smb_size);
+
+ set_message(cli->outbuf,1, 2 + strlen(fname),True);
+
+ CVAL(cli->outbuf,smb_com) = SMBunlink;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ strcpy(p,fname);
+
+ 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;
+ }
+
+ return True;
+}
+
+
+/****************************************************************************
+create a directory
+****************************************************************************/
+BOOL cli_mkdir(struct cli_state *cli, char *dname)
+{
+ char *p;
+
+ bzero(cli->outbuf,smb_size);
+ bzero(cli->inbuf,smb_size);
+
+ set_message(cli->outbuf,0, 2 + strlen(dname),True);
+
+ CVAL(cli->outbuf,smb_com) = SMBmkdir;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ strcpy(p,dname);
+
+ 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;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+remove a directory
+****************************************************************************/
+BOOL cli_rmdir(struct cli_state *cli, char *dname)
+{
+ char *p;
+
+ bzero(cli->outbuf,smb_size);
+ bzero(cli->inbuf,smb_size);
+
+ set_message(cli->outbuf,0, 2 + strlen(dname),True);
+
+ CVAL(cli->outbuf,smb_com) = SMBrmdir;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ strcpy(p,dname);
+
+ 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;
+ }
+
+ return True;
+}
+
+
+
+/****************************************************************************
+open a file
+****************************************************************************/
+int cli_open(struct cli_state *cli, char *fname, int flags, int share_mode)
+{
+ char *p;
+ unsigned openfn=0;
+ unsigned accessmode=0;
+
+ if (flags & O_CREAT)
+ openfn |= (1<<4);
+ if (!(flags & O_EXCL)) {
+ if (flags & O_TRUNC)
+ openfn |= (1<<1);
+ else
+ openfn |= (1<<0);
+ }
+
+ accessmode = (share_mode<<4);
+
+ if ((flags & O_RDWR) == O_RDWR) {
+ accessmode |= 2;
+ } else if ((flags & O_WRONLY) == O_WRONLY) {
+ accessmode |= 1;
+ }
+
+ bzero(cli->outbuf,smb_size);
+ bzero(cli->inbuf,smb_size);
+
+ set_message(cli->outbuf,15,1 + strlen(fname),True);
+
+ CVAL(cli->outbuf,smb_com) = SMBopenX;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
+ SSVAL(cli->outbuf,smb_vwv3,accessmode);
+ SSVAL(cli->outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
+ SSVAL(cli->outbuf,smb_vwv5,0);
+ SSVAL(cli->outbuf,smb_vwv8,openfn);
+
+ p = smb_buf(cli->outbuf);
+ strcpy(p,fname);
+ p = skip_string(p,1);
+
+ send_smb(cli->fd,cli->outbuf);
+ if (!receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
+ return -1;
+ }
+
+ if (CVAL(cli->inbuf,smb_rcls) != 0) {
+ return -1;
+ }
+
+ return SVAL(cli->inbuf,smb_vwv2);
+}
+
+
+
+
+/****************************************************************************
+ close a file
+****************************************************************************/
+BOOL cli_close(struct cli_state *cli, int fnum)
+{
+ bzero(cli->outbuf,smb_size);
+ bzero(cli->inbuf,smb_size);
+
+ set_message(cli->outbuf,3,0,True);
+
+ CVAL(cli->outbuf,smb_com) = SMBclose;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,fnum);
+ SIVALS(cli->outbuf,smb_vwv1,-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;
+ }
+
+ return True;
+}
+
+
+/****************************************************************************
+ lock a file
+****************************************************************************/
+BOOL cli_lock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout)
+{
+ char *p;
+
+ bzero(cli->outbuf,smb_size);
+ bzero(cli->inbuf,smb_size);
+
+ set_message(cli->outbuf,8,10,True);
+
+ CVAL(cli->outbuf,smb_com) = SMBlockingX;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ CVAL(cli->outbuf,smb_vwv0) = 0xFF;
+ SSVAL(cli->outbuf,smb_vwv2,fnum);
+ CVAL(cli->outbuf,smb_vwv3) = 0;
+ SIVALS(cli->outbuf, smb_vwv4, timeout);
+ SSVAL(cli->outbuf,smb_vwv6,0);
+ SSVAL(cli->outbuf,smb_vwv7,1);
+
+ p = smb_buf(cli->outbuf);
+ SSVAL(p, 0, cli->pid);
+ SIVAL(p, 2, offset);
+ SIVAL(p, 6, len);
+
+ 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;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ unlock a file
+****************************************************************************/
+BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout)
+{
+ char *p;
+
+ bzero(cli->outbuf,smb_size);
+ bzero(cli->inbuf,smb_size);
+
+ set_message(cli->outbuf,8,10,True);
+
+ CVAL(cli->outbuf,smb_com) = SMBlockingX;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ CVAL(cli->outbuf,smb_vwv0) = 0xFF;
+ SSVAL(cli->outbuf,smb_vwv2,fnum);
+ CVAL(cli->outbuf,smb_vwv3) = 0;
+ SIVALS(cli->outbuf, smb_vwv4, timeout);
+ SSVAL(cli->outbuf,smb_vwv6,1);
+ SSVAL(cli->outbuf,smb_vwv7,0);
+
+ p = smb_buf(cli->outbuf);
+ SSVAL(p, 0, cli->pid);
+ SIVAL(p, 2, offset);
+ SIVAL(p, 6, len);
+
+ 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;
+ }
+
+ return True;
+}
+
+
+/****************************************************************************
+ read from a file
+****************************************************************************/
+int cli_read(struct cli_state *cli, int fnum, char *buf, uint32 offset, uint16 size)
+{
+ char *p;
+
+ bzero(cli->outbuf,smb_size);
+ bzero(cli->inbuf,smb_size);
+
+ set_message(cli->outbuf,10,0,True);
+
+ CVAL(cli->outbuf,smb_com) = SMBreadX;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ CVAL(cli->outbuf,smb_vwv0) = 0xFF;
+ SSVAL(cli->outbuf,smb_vwv2,fnum);
+ SIVAL(cli->outbuf,smb_vwv3,offset);
+ SSVAL(cli->outbuf,smb_vwv5,size);
+ SSVAL(cli->outbuf,smb_vwv6,size);
+
+ send_smb(cli->fd,cli->outbuf);
+ if (!receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
+ return -1;
+ }
+
+ if (CVAL(cli->inbuf,smb_rcls) != 0) {
+ return -1;
+ }
+
+ size = SVAL(cli->inbuf, smb_vwv5);
+ p = smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_vwv6);
+
+ memcpy(buf, p, size);
+
+ return size;
+}
+
+
+/****************************************************************************
+ write to a file
+****************************************************************************/
+int cli_write(struct cli_state *cli, int fnum, char *buf, uint32 offset, uint16 size)
+{
+ char *p;
+
+ bzero(cli->outbuf,smb_size);
+ bzero(cli->inbuf,smb_size);
+
+ set_message(cli->outbuf,12,size,True);
+
+ CVAL(cli->outbuf,smb_com) = SMBwriteX;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ CVAL(cli->outbuf,smb_vwv0) = 0xFF;
+ SSVAL(cli->outbuf,smb_vwv2,fnum);
+ SIVAL(cli->outbuf,smb_vwv3,offset);
+
+ SSVAL(cli->outbuf,smb_vwv10,size);
+ SSVAL(cli->outbuf,smb_vwv11,smb_buf(cli->outbuf) - smb_base(cli->outbuf));
+
+ p = smb_base(cli->outbuf) + SVAL(cli->outbuf,smb_vwv11);
+ memcpy(p, buf, size);
+
+ send_smb(cli->fd,cli->outbuf);
+ if (!receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
+ return -1;
+ }
+
+ if (CVAL(cli->inbuf,smb_rcls) != 0) {
+ return -1;
+ }
+
+ return SVAL(cli->inbuf, smb_vwv2);
+}
+
+
+/****************************************************************************
+do a SMBgetatr call
+****************************************************************************/
+BOOL cli_getatr(struct cli_state *cli, char *fname,
+ int *attr, uint32 *size, time_t *t)
+{
+ char *p;
+
+ bzero(cli->outbuf,smb_size);
+ bzero(cli->inbuf,smb_size);
+
+ set_message(cli->outbuf,0,strlen(fname)+2,True);
+
+ CVAL(cli->outbuf,smb_com) = SMBgetatr;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ p = smb_buf(cli->outbuf);
+ *p = 4;
+ strcpy(p+1, fname);
+
+ 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;
+ }
+
+ if (size) {
+ *size = IVAL(cli->inbuf, smb_vwv3);
+ }
+
+ if (t) {
+ *t = make_unix_date3(cli->inbuf+smb_vwv1);
+ }
+
+ if (attr) {
+ *attr = SVAL(cli->inbuf,smb_vwv0);
+ }
+
+
+ return True;
+}
+
+
+/****************************************************************************
+do a SMBsetatr call
+****************************************************************************/
+BOOL cli_setatr(struct cli_state *cli, char *fname, int attr, time_t t)
+{
+ char *p;
+
+ bzero(cli->outbuf,smb_size);
+ bzero(cli->inbuf,smb_size);
+
+ set_message(cli->outbuf,8,strlen(fname)+2,True);
+
+ CVAL(cli->outbuf,smb_com) = SMBsetatr;
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0, attr);
+ put_dos_date3(cli->outbuf,smb_vwv1, t);
+
+ p = smb_buf(cli->outbuf);
+ *p = 4;
+ strcpy(p+1, fname);
+
+ 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;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+send a qpathinfo call
+****************************************************************************/
+BOOL cli_qpathinfo(struct cli_state *cli, char *fname,
+ time_t *c_time, time_t *a_time, time_t *m_time, uint32 *size)
+{
+ int data_len = 0;
+ int param_len = 0;
+ uint16 setup = TRANSACT2_QPATHINFO;
+ pstring param;
+ char *rparam=NULL, *rdata=NULL;
+
+ param_len = strlen(fname) + 7;
+
+ memset(param, 0, param_len);
+ SSVAL(param, 0, SMB_INFO_STANDARD);
+ pstrcpy(&param[6], fname);
+
+ if (!cli_send_trans(cli, SMBtrans2, NULL, -1, 0,
+ NULL, param, &setup,
+ data_len, param_len, 1,
+ cli->max_xmit, 10, 0)) {
+ return False;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2, &data_len, &param_len,
+ &rdata, &rparam)) {
+ return False;
+ }
+
+ if (!rdata || data_len < 22) {
+ return False;
+ }
+
+ if (c_time) {
+ *c_time = make_unix_date2(rdata+0);
+ }
+ if (a_time) {
+ *a_time = make_unix_date2(rdata+4);
+ }
+ if (m_time) {
+ *m_time = make_unix_date2(rdata+8);
+ }
+ if (size) {
+ *size = IVAL(rdata, 12);
+ }
+
+ if (rdata) free(rdata);
+ if (rparam) free(rparam);
+ return True;
+}
+
+/****************************************************************************
+send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level
+****************************************************************************/
+BOOL cli_qpathinfo2(struct cli_state *cli, char *fname,
+ time_t *c_time, time_t *a_time, time_t *m_time,
+ time_t *w_time, uint32 *size)
+{
+ int data_len = 0;
+ int param_len = 0;
+ uint16 setup = TRANSACT2_QPATHINFO;
+ pstring param;
+ char *rparam=NULL, *rdata=NULL;
+
+ param_len = strlen(fname) + 7;
+
+ memset(param, 0, param_len);
+ SSVAL(param, 0, SMB_QUERY_FILE_ALL_INFO);
+ pstrcpy(&param[6], fname);
+
+ if (!cli_send_trans(cli, SMBtrans2, NULL, -1, 0,
+ NULL, param, &setup,
+ data_len, param_len, 1,
+ cli->max_xmit, 10, 0)) {
+ return False;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2, &data_len, &param_len,
+ &rdata, &rparam)) {
+ return False;
+ }
+
+ if (!rdata || data_len < 22) {
+ return False;
+ }
+
+ if (c_time) {
+ *c_time = interpret_long_date(rdata+0) - cli->serverzone;
+ }
+ if (a_time) {
+ *a_time = interpret_long_date(rdata+8) - cli->serverzone;
+ }
+ if (m_time) {
+ *m_time = interpret_long_date(rdata+16) - cli->serverzone;
+ }
+ if (w_time) {
+ *w_time = interpret_long_date(rdata+24) - cli->serverzone;
+ }
+ if (size) {
+ *size = IVAL(rdata, 40);
+ }
+
+ if (rdata) free(rdata);
+ if (rparam) free(rparam);
+ return True;
+}
+
+
+/****************************************************************************
+send a qfileinfo call
+****************************************************************************/
+BOOL cli_qfileinfo(struct cli_state *cli, int fnum,
+ time_t *c_time, time_t *a_time, time_t *m_time, uint32 *size)
+{
+ int data_len = 0;
+ int param_len = 0;
+ uint16 setup = TRANSACT2_QFILEINFO;
+ pstring param;
+ char *rparam=NULL, *rdata=NULL;
+
+ param_len = 4;
+
+ memset(param, 0, param_len);
+ SSVAL(param, 0, fnum);
+ SSVAL(param, 2, SMB_INFO_STANDARD);
+
+ if (!cli_send_trans(cli, SMBtrans2, NULL, -1, 0,
+ NULL, param, &setup,
+ data_len, param_len, 1,
+ cli->max_xmit, 2, 0)) {
+ return False;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2, &data_len, &param_len,
+ &rdata, &rparam)) {
+ return False;
+ }
+
+ if (!rdata || data_len < 22) {
+ return False;
+ }
+
+ if (c_time) {
+ *c_time = make_unix_date2(rdata+0);
+ }
+ if (a_time) {
+ *a_time = make_unix_date2(rdata+4);
+ }
+ if (m_time) {
+ *m_time = make_unix_date2(rdata+8);
+ }
+ if (size) {
+ *size = IVAL(rdata, 12);
+ }
+
+ if (rdata) free(rdata);
+ if (rparam) free(rparam);
+ return True;
+}
+
+
+/****************************************************************************
+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) {
+ /* 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;
+ } else if (cli->protocol >= PROTOCOL_LANMAN1) {
+ 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);
+ 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 {
+ /* the old core protocol */
+ cli->sec_mode = 0;
+ cli->serverzone = TimeDiff(time(NULL));
+ }
+
+ 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));
+}
+
+/****************************************************************************
+ return a description of the error
+****************************************************************************/
+char *cli_errstr(struct cli_state *cli)
+{
+ return smb_errstr(cli->inbuf);
+}
+
+/****************************************************************************
+ return error codes for the last packet
+****************************************************************************/
+void cli_error(struct cli_state *cli, int *eclass, int *num)
+{
+ *eclass = CVAL(cli->inbuf,smb_rcls);
+ *num = SVAL(cli->inbuf,smb_err);
+}
+
+/****************************************************************************
+set socket options on a open connection
+****************************************************************************/
+void cli_sockopt(struct cli_state *cli, char *options)
+{
+ set_socket_options(cli->fd, options);
+}
+
+/****************************************************************************
+set the PID to use for smb messages. Return the old pid.
+****************************************************************************/
+int cli_setpid(struct cli_state *cli, int pid)
+{
+ int ret = cli->pid;
+ cli->pid = pid;
+ return ret;
+}
diff --git a/source/libsmb/credentials.c b/source/libsmb/credentials.c
new file mode 100644
index 00000000000..b06ca6ffc6d
--- /dev/null
+++ b/source/libsmb/credentials.c
@@ -0,0 +1,222 @@
+/*
+ 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;
+
+
+
+/****************************************************************************
+represent a credential as a string
+****************************************************************************/
+char *credstr(uchar *cred)
+{
+ static fstring buf;
+ sprintf(buf,"%02X%02X%02X%02X%02X%02X%02X%02X",
+ cred[0], cred[1], cred[2], cred[3],
+ cred[4], cred[5], cred[6], cred[7]);
+ return buf;
+}
+
+
+/****************************************************************************
+ 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,
+ uchar session_key[8])
+{
+ uint32 sum[2];
+ unsigned char sum2[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(session_key, sum2,(unsigned char *)pass);
+
+ /* debug output */
+ DEBUG(4,("cred_session_key\n"));
+
+ DEBUG(5,(" clnt_chal: %s\n", credstr(clnt_chal->data)));
+ DEBUG(5,(" srv_chal : %s\n", credstr(srv_chal->data)));
+ DEBUG(5,(" clnt+srv : %s\n", credstr(sum2)));
+ DEBUG(5,(" sess_key : %s\n", credstr(session_key)));
+}
+
+
+/****************************************************************************
+create a credential
+
+Input:
+ 8 byte sesssion key
+ 8 byte stored credential
+ 4 byte timestamp
+
+Output:
+ 8 byte credential
+****************************************************************************/
+void cred_create(uchar session_key[8], DOM_CHAL *stor_cred, UTIME timestamp,
+ DOM_CHAL *cred)
+{
+ DOM_CHAL time_cred;
+
+ SIVAL(time_cred.data, 0, IVAL(stor_cred->data, 0) + timestamp.time);
+ SIVAL(time_cred.data, 4, IVAL(stor_cred->data, 4));
+
+ cred_hash2(cred->data, time_cred.data, session_key);
+
+ /* debug output*/
+ DEBUG(4,("cred_create\n"));
+
+ DEBUG(5,(" sess_key : %s\n", credstr(session_key)));
+ DEBUG(5,(" stor_cred: %s\n", credstr(stor_cred->data)));
+ DEBUG(5,(" timestamp: %lx\n" , timestamp.time));
+ DEBUG(5,(" timecred : %s\n", credstr(time_cred.data)));
+ DEBUG(5,(" calc_cred: %s\n", credstr(cred->data)));
+}
+
+
+/****************************************************************************
+ 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, uchar session_key[8], 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 : %s\n", credstr(cred->data)));
+ DEBUG(5,(" calculated: %s\n", credstr(cred2.data)));
+
+ 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(uchar sess_key[8],
+ 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: %s\n", credstr(sto_clnt_cred->challenge.data)));
+ return True;
+}
+
+
+/****************************************************************************
+ checks credentials; generates next step in the credential chain
+****************************************************************************/
+BOOL deal_with_creds(uchar sess_key[8],
+ 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=%s\n", credstr(sto_clnt_cred->challenge.data)));
+
+ /* 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..15bf58bc559
--- /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 = 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;
+ 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/libsmb/smberr.c b/source/libsmb/smberr.c
new file mode 100644
index 00000000000..5149568c045
--- /dev/null
+++ b/source/libsmb/smberr.c
@@ -0,0 +1,182 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ 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"
+
+extern int DEBUGLEVEL;
+
+/* 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/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..45ab14d452f
--- /dev/null
+++ b/source/locking/locking_shm.c
@@ -0,0 +1,696 @@
+/*
+ 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] == 0)
+ {
+ DEBUG(5,("get_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 no entry for file dev = %d ino = %d\n",
+ dev, inode));
+ return (0);
+ }
+
+ if(file_scanner_p->locking_version != LOCKING_VERSION)
+ {
+ DEBUG(0,("ERROR: get_share_modes Deleting old share mode v1 %d dev=%d ino=%d\n",
+ file_scanner_p->locking_version, dev, inode));
+ 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: 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;
+
+ 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: entries=%d dev=%d ino=%d\n",
+ file_scanner_p->num_share_mode_entries,dev, inode));
+ return 0;
+ }
+
+ DEBUG(0,("get_share_modes: process %d no longer exists\n", pid));
+
+ 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 Read share 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: file with dev %d inode %d empty\n",
+ dev, inode));
+ 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: file with dev %d inode %d -> %d entries\n",
+ dev, inode, 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] == 0)
+ {
+ DEBUG(0,("PANIC ERROR:del_share_mode 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 no entry for dev %d inode %d\n",
+ dev, inode));
+ return;
+ }
+
+ if(file_scanner_p->locking_version != LOCKING_VERSION)
+ {
+ DEBUG(0,("ERROR: del_share_modes Deleting old share mode v1 %d dev=%d ino=%d\n",
+ file_scanner_p->locking_version, dev, inode));
+ 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 Deleting share mode entry dev=%d ino=%d\n",
+ dev, inode));
+ 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 num_share_mode_entries=%d\n",
+ file_scanner_p->num_share_mode_entries));
+ 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 num entries = 0, deleting share_mode dev=%d ino=%d\n",
+ dev, inode));
+ 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 No share mode dev=%d ino=%d\n",
+ dev, inode));
+ }
+}
+
+/*******************************************************************
+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 == 0) {
+ DEBUG(0,("ERROR:set_share_mode 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 = 0;
+ 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: Created share record for %s (dev %d inode %d)\n",
+ fs_p->name, dev, inode));
+ }
+
+ /* Now create the share mode entry */
+ new_entry_offset = shmops->alloc(sizeof(shm_share_mode_entry));
+ if(new_entry_offset == 0) {
+ int delete_offset = mode_array[hash_entry];
+ DEBUG(0,("ERROR:set_share_mode: 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 num_share_mode_entries=%d\n",
+ file_scanner_p->num_share_mode_entries));
+ return False;
+ }
+
+ /* Increment the share_mode_entries counter */
+ file_scanner_p->num_share_mode_entries += 1;
+
+ DEBUG(3,("set_share_mode: Created share entry for %s with mode 0x%X pid=%d\n",
+ fs_p->name, fs_p->share_mode, new_entry_p->e.pid));
+
+ 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] == 0)
+ {
+ DEBUG(0,("PANIC ERROR:remove_share_oplock: 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: no entry found for dev=%d ino=%d\n",
+ dev, inode));
+ return False;
+ }
+
+ if(file_scanner_p->locking_version != LOCKING_VERSION)
+ {
+ DEBUG(0,("ERROR: remove_share_oplock: Deleting old share mode v1=%d dev=%d ino=%d\n",
+ file_scanner_p->locking_version, dev, inode));
+ 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: No oplock granted. dev=%d ino=%d\n",
+ dev, inode));
+ 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] == 0) {
+ 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)
+{
+ 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..864f7c298b6
--- /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 0
+
+#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 == 0 )
+ 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 0;
+
+ if (!smb_shm_header_p)
+ return 0;
+
+ 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 0;
+ }
+
+ 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 0;
+ }
+
+
+ /* 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 (0);
+ }
+
+ /* 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 == 0)
+ {
+ 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 = 0;
+
+ 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 0;
+ 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..826de5694cb
--- /dev/null
+++ b/source/locking/shmem_sysv.c
@@ -0,0 +1,704 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Shared memory functions - SYSV IPC implementation
+ 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"
+
+
+#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 0x1000
+
+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 NULL
+#define EOList_Off (0)
+
+#define CellSize sizeof(struct ShmBlockDesc)
+
+/* HeaderSize aligned on a 8 byte boundary */
+#define AlignedHeaderSize ((sizeof(struct ShmHeader)+7) & ~7)
+
+static struct ShmHeader *shm_header_p = NULL;
+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 = 0;
+
+ 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 == 0 )
+ 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 0;
+
+ if (!shm_header_p)
+ return 0;
+
+ 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 0;
+ }
+
+ global_lock();
+
+ if (!shm_header_p->consistent) {
+ DEBUG(0,("ERROR shm_alloc : shmem not consistent\n"));
+ global_unlock();
+ return 0;
+ }
+
+ /* 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\n",size));
+ global_unlock();
+ return (0);
+ }
+
+ /* 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) {
+ /* 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);
+
+ shm_header_p->statistics.cells_free -= 1;
+ shm_header_p->statistics.cells_system += 1;
+ }
+
+ /* take it from the free list */
+ 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;
+
+ result_offset = shm_addr2offset(&(scanner_p[1]));
+ scanner_p->next = SHM_NOT_FREE_OFF;
+
+ /* end modification of shared mem */
+ shm_header_p->consistent = True;
+
+ global_unlock();
+
+ DEBUG(6,("shm_alloc : allocated %d bytes at offset %d\n",
+ size,result_offset));
+
+ return result_offset;
+}
+
+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_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);
+
+ 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;
+}
+
+
+/*
+ * 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 hash_entries)
+{
+ int size = hash_entries * sizeof(int);
+
+ global_lock();
+ shm_header_p->userdef_off = shm_alloc(size);
+
+ if(shm_header_p->userdef_off == 0) {
+ 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 shmem size mismatch (old = %d, new = %d)\n",
+ shm_header_p->total_size,size));
+ return False;
+ }
+
+ if(!shm_header_p->consistent) {
+ DEBUG(0,("ERROR 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 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 = 0;
+
+ 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 BOOL shm_close( void )
+{
+ return True;
+}
+
+
+static int shm_get_userdef_off(void)
+{
+ if (!shm_header_p)
+ return 0;
+ 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;
+ int pid;
+
+ 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;
+ }
+
+ if (semctl(sem_id, 0, GETVAL, su) == 0 &&
+ !process_exists((pid=semctl(sem_id, 0, GETPID, su)))) {
+ DEBUG(0,("WARNING: clearing global IPC lock set by dead process %d\n",
+ pid));
+ su.val = 1;
+ if (semctl(sem_id, 0, SETVAL, su) != 0) {
+ DEBUG(0,("ERROR: Failed to clear global lock\n"));
+ }
+ }
+
+ 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;
+
+
+ for (i=1;i<hash_size+1;i++) {
+ if (semctl(sem_id, i, GETVAL, su) == 0 &&
+ !process_exists((pid=semctl(sem_id, i, GETPID, su)))) {
+ DEBUG(1,("WARNING: clearing IPC lock %d set by dead process %d\n",
+ i, pid));
+ su.val = 1;
+ if (semctl(sem_id, i, SETVAL, su) != 0) {
+ DEBUG(0,("ERROR: Failed to clear IPC lock %d\n", i));
+ }
+ }
+ }
+
+ /* 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/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..28ebe5da90c
--- /dev/null
+++ b/source/nameannounce.c
@@ -0,0 +1,554 @@
+/*
+ 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);
+ }
+ }
+}
+
+/****************************************************************************
+ do all the "remote" browse synchronisation stuff.
+ These are used to put our browse lists into remote browse lists.
+ **************************************************************************/
+void browse_sync_remote(time_t t)
+{
+ char *s,*ptr;
+ static time_t last_time = 0;
+ pstring s2;
+ struct in_addr addr;
+
+ if (last_time && t < last_time + REMOTE_ANNOUNCE_INTERVAL)
+ return;
+
+ last_time = t;
+
+ s = lp_remote_browse_sync();
+ if (!*s) return;
+
+ for (ptr=s; next_token(&ptr,s2,NULL); )
+ {
+ /* the entries are of the form a.b.c.d */
+ int n;
+
+ 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_request(name, "*", ANN_MasterAnnouncement, 0x20, 0, addr);
+ }
+ }
+}
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..816203ea3c9
--- /dev/null
+++ b/source/namedbsubnet.c
@@ -0,0 +1,400 @@
+/*
+ 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);
+
+ /* Register the WORKGROUP<0x1e> name. */
+ 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..b01eb927e80
--- /dev/null
+++ b/source/namedbwork.c
@@ -0,0 +1,248 @@
+/*
+ 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;
+
+ /* set up initial value for server announce type */
+ work->ServerType = lp_default_server_announce();
+ work->ServerType |= lp_local_master() ? SV_TYPE_POTENTIAL_BROWSER : 0;
+ work->ServerType |= lp_domain_controller() ? SV_TYPE_DOMAIN_CTRL : 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..c5d145f9791
--- /dev/null
+++ b/source/nameelect.c
@@ -0,0 +1,859 @@
+/*
+ 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 (lp_domain_controller()) domain_type |= SV_TYPE_DOMAIN_CTRL;
+
+ 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_MASTER_BROWSER;
+ 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..697a11a16a4
--- /dev/null
+++ b/source/namelogon.c
@@ -0,0 +1,238 @@
+/*
+ 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(unicomp, buf);
+
+ q = skip_unicode_string(q, 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);
+
+ smb_pass = get_smbpwd_entry(ascuser, 0);
+
+ 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..6c7bfde03e2
--- /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 && (qname_type != 0x1c))
+ {
+ /* 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..3d1b3cc9951
--- /dev/null
+++ b/source/nmbd/asyncdns.c
@@ -0,0 +1,280 @@
+/*
+ Unix SMB/Netbios implementation.
+ a async DNS handler
+ 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;
+
+
+/***************************************************************************
+ 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 to be sent to the DNS child */
+static struct packet_struct *dns_queue;
+
+/* the packet currently being processed by the dns child */
+static struct packet_struct *dns_current;
+
+
+/***************************************************************************
+ 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 = -1;
+
+ 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]);
+ return;
+ }
+
+ fd_in = fd2[0];
+ fd_out = fd1[1];
+
+ asyncdns_process();
+}
+
+
+/***************************************************************************
+check if a particular name is already being queried
+ ****************************************************************************/
+static BOOL query_current(struct query_record *r)
+{
+ return dns_current &&
+ name_equal(&r->name,
+ &dns_current->packet.nmb.question.question_name);
+}
+
+
+/***************************************************************************
+ write a query to the child process
+ ****************************************************************************/
+static BOOL write_child(struct packet_struct *p)
+{
+ struct query_record r;
+
+ r.name = p->packet.nmb.question.question_name;
+
+ return write_data(fd_out, (char *)&r, sizeof(r)) == sizeof(r);
+}
+
+/***************************************************************************
+ 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);
+
+ if (dns_current) {
+ if (query_current(&r)) {
+ DEBUG(3,("DNS calling reply_name_query\n"));
+ in_dns = 1;
+ reply_name_query(dns_current);
+ in_dns = 0;
+ }
+
+ dns_current->locked = False;
+ free_packet(dns_current);
+ dns_current = NULL;
+ }
+
+ /* 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;
+ }
+ }
+
+ if (dns_queue) {
+ dns_current = dns_queue;
+ dns_queue = dns_queue->next;
+ if (dns_queue) dns_queue->prev = NULL;
+ dns_current->next = NULL;
+
+ if (!write_child(dns_current)) {
+ DEBUG(3,("failed to send DNS query to child!\n"));
+ return;
+ }
+ }
+
+}
+
+/***************************************************************************
+queue a DNS query
+ ****************************************************************************/
+BOOL queue_dns_query(struct packet_struct *p,struct nmb_name *question,
+ struct name_record **n)
+{
+ if (in_dns || fd_in == -1)
+ return False;
+
+ if (!dns_current) {
+ if (!write_child(p)) {
+ DEBUG(3,("failed to send DNS query to child!\n"));
+ return False;
+ }
+ dns_current = p;
+ p->locked = True;
+ } else {
+ 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..1e4a2d9a790
--- /dev/null
+++ b/source/nmbd/nmbd.c
@@ -0,0 +1,664 @@
+/*
+ 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);
+ browse_sync_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;
+ }
+
+#ifndef SYNC_DNS
+ start_async_dns();
+#endif
+
+ 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();
+ }
+
+ if (!directory_exist(lp_lockdir(), NULL)) {
+ mkdir(lp_lockdir(), 0755);
+ }
+
+ 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..c1db37ff5cc 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,97 @@
*/
#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;
+ 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;
+ }
+
+ if (!cli_send_tconX(&cli, "IPC$", "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/param/loadparm.c b/source/param/loadparm.c
index c61ab26781f..8858455f6a4 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,P_ENUM
} parm_type;
typedef enum
@@ -101,66 +102,97 @@ 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 *szDomainAdminUsers;
+ char *szDomainGuestUsers;
+ char *szDomainHostsallow;
+ char *szDomainHostsdeny;
+ char *szUsernameMap;
+ char *szCharacterSet;
+ char *szLogonScript;
+ char *szLogonPath;
+ char *szLogonDrive;
+ char *szLogonHome;
+ char *szSmbrun;
+ char *szWINSserver;
+ char *szCodingSystem;
+ char *szInterfaces;
+ char *szRemoteAnnounce;
+ char *szRemoteBrowseSync;
+ 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 bDomainController;
+ 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 +224,17 @@ 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 *szVetoOplockFiles;
char *comment;
char *force_user;
char *force_group;
@@ -205,7 +242,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 +270,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 +293,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 +309,17 @@ 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, /* szVetoOplockFiles */
NULL, /* comment */
NULL, /* force user */
NULL, /* force group */
@@ -276,7 +327,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 +355,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 +378,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))
@@ -326,175 +386,241 @@ static BOOL bGlobalOnly = False;
static BOOL handle_valid_chars(char *pszParmValue, char **ptr);
static BOOL handle_include(char *pszParmValue, char **ptr);
static BOOL handle_copy(char *pszParmValue, char **ptr);
-static BOOL handle_protocol(char *pszParmValue,int *val);
-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_coding_system(char *pszParmValue,int *val);
-#endif /* KANJI */
+static BOOL handle_character_set(char *pszParmValue,char **ptr);
+static BOOL handle_coding_system(char *pszParmValue,char **ptr);
+
+static void set_default_server_announce_type(void);
+
+struct enum_list {
+ int value;
+ char *name;
+};
-struct parm_struct
+static struct enum_list enum_protocol[] = {{PROTOCOL_NT1, "NT1"}, {PROTOCOL_LANMAN2, "LANMAN2"},
+ {PROTOCOL_LANMAN1, "LANMAN1"}, {PROTOCOL_CORE,"CORE"},
+ {PROTOCOL_COREPLUS, "COREPLUS"},
+ {PROTOCOL_COREPLUS, "CORE+"}, {-1, NULL}};
+
+static struct enum_list enum_security[] = {{SEC_SHARE, "SHARE"}, {SEC_USER, "USER"},
+ {SEC_SERVER, "SERVER"}, {-1, NULL}};
+
+static struct enum_list enum_printing[] = {{PRINT_SYSV, "sysv"}, {PRINT_AIX, "aix"},
+ {PRINT_HPUX, "hpux"}, {PRINT_BSD, "bsd"},
+ {PRINT_QNX, "qnx"}, {PRINT_PLP, "plp"},
+ {PRINT_LPRNG, "lprng"}, {-1, NULL}};
+
+static struct enum_list enum_announce_as[] = {{ANNOUNCE_AS_NT, "NT"}, {ANNOUNCE_AS_WIN95, "win95"},
+ {ANNOUNCE_AS_WFW, "WfW"}, {-1, NULL}};
+
+static struct enum_list enum_case[] = {{CASE_LOWER, "lower"}, {CASE_UPPER, "upper"}, {-1, NULL}};
+
+static struct parm_struct
{
- char *label;
- parm_type type;
- parm_class class;
- void *ptr;
- BOOL (*special)();
+ char *label;
+ parm_type type;
+ parm_class class;
+ void *ptr;
+ BOOL (*special)();
+ struct enum_list *enum_list;
} parm_table[] =
{
- {"debuglevel", P_INTEGER, P_GLOBAL, &DEBUGLEVEL, NULL},
- {"log level", P_INTEGER, P_GLOBAL, &DEBUGLEVEL, NULL},
- {"syslog", P_INTEGER, P_GLOBAL, &Globals.syslog, NULL},
- {"syslog only", P_BOOL, P_GLOBAL, &Globals.bSyslogOnly, NULL},
- {"protocol", P_INTEGER, P_GLOBAL, &Globals.maxprotocol,handle_protocol},
- {"security", P_INTEGER, P_GLOBAL, &Globals.security,handle_security},
- {"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},
- {"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},
- {"read bmpx", P_BOOL, P_GLOBAL, &Globals.bReadbmpx, NULL},
- {"read raw", P_BOOL, P_GLOBAL, &Globals.bReadRaw, NULL},
- {"write raw", P_BOOL, P_GLOBAL, &Globals.bWriteRaw, NULL},
- {"use rhosts", P_BOOL, P_GLOBAL, &Globals.bUseRhosts, NULL},
- {"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},
- {"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},
- {"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},
- {"hosts equiv", P_STRING, P_GLOBAL, &Globals.szHostsEquiv, NULL},
- {"preload", P_STRING, P_GLOBAL, &Globals.szAutoServices, NULL},
- {"auto services", P_STRING, P_GLOBAL, &Globals.szAutoServices, NULL},
- {"server string", P_STRING, P_GLOBAL, &Globals.szServerString, NULL},
- {"printcap name", P_STRING, P_GLOBAL, &Globals.szPrintcapname, NULL},
- {"printcap", P_STRING, P_GLOBAL, &Globals.szPrintcapname, NULL},
- {"lock dir", P_STRING, P_GLOBAL, &Globals.szLockDir, NULL},
- {"lock directory", P_STRING, P_GLOBAL, &Globals.szLockDir, NULL},
- {"root directory", P_STRING, P_GLOBAL, &Globals.szRootdir, NULL},
- {"root dir", P_STRING, P_GLOBAL, &Globals.szRootdir, NULL},
- {"root", P_STRING, P_GLOBAL, &Globals.szRootdir, NULL},
- {"default service", P_STRING, P_GLOBAL, &Globals.szDefaultService, NULL},
- {"default", P_STRING, P_GLOBAL, &Globals.szDefaultService, NULL},
- {"message command", P_STRING, P_GLOBAL, &Globals.szMsgCommand, NULL},
- {"dfree command", P_STRING, P_GLOBAL, &Globals.szDfree, NULL},
- {"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},
- {"domain controller",P_STRING, P_GLOBAL, &Globals.szDomainController,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},
- {"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},
- {"max xmit", P_INTEGER, P_GLOBAL, &Globals.max_xmit, NULL},
- {"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},
- {"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
- {"coding system", P_INTEGER, P_GLOBAL, &coding_system, handle_coding_system},
-#endif /* KANJI */
- {"os level", P_INTEGER, P_GLOBAL, &Globals.os_level, NULL},
- {"max ttl", P_INTEGER, P_GLOBAL, &Globals.max_ttl, NULL},
- {"preferred master", P_BOOL, P_GLOBAL, &Globals.bPreferredMaster, NULL},
- {"prefered master", P_BOOL, P_GLOBAL, &Globals.bPreferredMaster, NULL},
- {"domain master", P_BOOL, P_GLOBAL, &Globals.bDomainMaster, NULL},
- {"domain logons", P_BOOL, P_GLOBAL, &Globals.bDomainLogons, NULL},
- {"browse list", P_BOOL, P_GLOBAL, &Globals.bBrowseList, 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},
- {"include", P_STRING, P_LOCAL, &sDefault.szInclude, handle_include},
- {"exec", P_STRING, P_LOCAL, &sDefault.szPreExec, NULL},
- {"preexec", P_STRING, P_LOCAL, &sDefault.szPreExec, NULL},
- {"postexec", P_STRING, P_LOCAL, &sDefault.szPostExec, NULL},
- {"root preexec", P_STRING, P_LOCAL, &sDefault.szRootPreExec, NULL},
- {"root postexec", P_STRING, P_LOCAL, &sDefault.szRootPostExec, NULL},
- {"alternate permissions",P_BOOL,P_LOCAL, &sDefault.bAlternatePerm, NULL},
- {"revalidate", P_BOOL, P_LOCAL, &sDefault.bRevalidate, NULL},
- {"default case", P_INTEGER, P_LOCAL, &sDefault.iDefaultCase, handle_case},
- {"case sensitive", P_BOOL, P_LOCAL, &sDefault.bCaseSensitive, NULL},
- {"casesignames", P_BOOL, P_LOCAL, &sDefault.bCaseSensitive, NULL},
- {"preserve case", P_BOOL, P_LOCAL, &sDefault.bCasePreserve, NULL},
- {"short preserve case",P_BOOL, P_LOCAL, &sDefault.bShortCasePreserve,NULL},
- {"mangle case", P_BOOL, P_LOCAL, &sDefault.bCaseMangle, NULL},
- {"mangling char", P_CHAR, P_LOCAL, &sDefault.magic_char, NULL},
- {"browseable", P_BOOL, P_LOCAL, &sDefault.bBrowseable, NULL},
- {"browsable", P_BOOL, P_LOCAL, &sDefault.bBrowseable, NULL},
- {"available", P_BOOL, P_LOCAL, &sDefault.bAvailable, NULL},
- {"path", P_STRING, P_LOCAL, &sDefault.szPath, NULL},
- {"directory", P_STRING, P_LOCAL, &sDefault.szPath, NULL},
- {"username", P_STRING, P_LOCAL, &sDefault.szUsername, NULL},
- {"user", P_STRING, P_LOCAL, &sDefault.szUsername, NULL},
- {"users", P_STRING, P_LOCAL, &sDefault.szUsername, NULL},
- {"guest account", P_STRING, P_LOCAL, &sDefault.szGuestaccount, NULL},
- {"invalid users", P_STRING, P_LOCAL, &sDefault.szInvalidUsers, NULL},
- {"valid users", P_STRING, P_LOCAL, &sDefault.szValidUsers, NULL},
- {"admin users", P_STRING, P_LOCAL, &sDefault.szAdminUsers, NULL},
- {"read list", P_STRING, P_LOCAL, &sDefault.readlist, NULL},
- {"write list", P_STRING, P_LOCAL, &sDefault.writelist, NULL},
- {"volume", P_STRING, P_LOCAL, &sDefault.volume, NULL},
- {"force user", P_STRING, P_LOCAL, &sDefault.force_user, NULL},
- {"force group", P_STRING, P_LOCAL, &sDefault.force_group, NULL},
- {"group", P_STRING, P_LOCAL, &sDefault.force_group, NULL},
- {"read only", P_BOOL, P_LOCAL, &sDefault.bRead_only, NULL},
- {"write ok", P_BOOLREV, P_LOCAL, &sDefault.bRead_only, NULL},
- {"writeable", P_BOOLREV, P_LOCAL, &sDefault.bRead_only, NULL},
- {"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},
- {"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},
- {"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},
- {"public", P_BOOL, P_LOCAL, &sDefault.bGuest_ok, NULL},
- {"print ok", P_BOOL, P_LOCAL, &sDefault.bPrint_ok, NULL},
- {"printable", P_BOOL, P_LOCAL, &sDefault.bPrint_ok, NULL},
- {"postscript", P_BOOL, P_LOCAL, &sDefault.bPostscript, NULL},
- {"map system", P_BOOL, P_LOCAL, &sDefault.bMap_system, NULL},
- {"map hidden", P_BOOL, P_LOCAL, &sDefault.bMap_hidden, NULL},
- {"map archive", P_BOOL, P_LOCAL, &sDefault.bMap_archive, NULL},
- {"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},
- {"only user", P_BOOL, P_LOCAL, &sDefault.bOnlyUser, NULL},
- {"wide links", P_BOOL, P_LOCAL, &sDefault.bWidelinks, NULL},
- {"sync always", P_BOOL, P_LOCAL, &sDefault.bSyncAlways, NULL},
- {"mangled names", P_BOOL, P_LOCAL, &sDefault.bMangledNames, 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},
- {"lppause command", P_STRING, P_LOCAL, &sDefault.szLppausecommand, NULL},
- {"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},
- {"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},
- {"deny hosts", P_STRING, P_LOCAL, &sDefault.szHostsdeny, NULL},
- {"dont descend", P_STRING, P_LOCAL, &sDefault.szDontdescend, NULL},
- {"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},
-
- {NULL, P_BOOL, P_NONE, NULL, NULL}
+ {"debuglevel", P_INTEGER, P_GLOBAL, &DEBUGLEVEL, NULL, NULL},
+ {"log level", P_INTEGER, P_GLOBAL, &DEBUGLEVEL, NULL, NULL},
+ {"syslog", P_INTEGER, P_GLOBAL, &Globals.syslog, NULL, NULL},
+ {"syslog only", P_BOOL, P_GLOBAL, &Globals.bSyslogOnly, NULL, NULL},
+ {"protocol", P_ENUM, P_GLOBAL, &Globals.maxprotocol, NULL, enum_protocol},
+ {"security", P_ENUM, P_GLOBAL, &Globals.security, NULL, enum_security},
+ {"printing", P_ENUM, P_GLOBAL, &Globals.printing, NULL, enum_printing},
+ {"max disk size", P_INTEGER, P_GLOBAL, &Globals.maxdisksize, NULL, NULL},
+ {"lpq cache time", P_INTEGER, P_GLOBAL, &Globals.lpqcachetime, NULL, NULL},
+ {"announce as", P_ENUM, P_GLOBAL, &Globals.announce_as, NULL, enum_announce_as},
+ {"encrypt passwords",P_BOOL, P_GLOBAL, &Globals.bEncryptPasswords, NULL, NULL},
+ {"getwd cache", P_BOOL, P_GLOBAL, &use_getwd_cache, NULL, NULL},
+ {"read prediction", P_BOOL, P_GLOBAL, &Globals.bReadPrediction, NULL, NULL},
+ {"read bmpx", P_BOOL, P_GLOBAL, &Globals.bReadbmpx, NULL, NULL},
+ {"read raw", P_BOOL, P_GLOBAL, &Globals.bReadRaw, NULL, NULL},
+ {"write raw", P_BOOL, P_GLOBAL, &Globals.bWriteRaw, NULL, NULL},
+ {"use rhosts", P_BOOL, P_GLOBAL, &Globals.bUseRhosts, NULL, NULL},
+ {"load printers", P_BOOL, P_GLOBAL, &Globals.bLoadPrinters, NULL, NULL},
+ {"null passwords", P_BOOL, P_GLOBAL, &Globals.bNullPasswords, NULL, NULL},
+ {"strip dot", P_BOOL, P_GLOBAL, &Globals.bStripDot, NULL, NULL},
+ {"interfaces", P_STRING, P_GLOBAL, &Globals.szInterfaces, NULL, NULL},
+ {"bind interfaces only", P_BOOL,P_GLOBAL, &Globals.bBindInterfacesOnly,NULL, NULL},
+ {"password server", P_STRING, P_GLOBAL, &Globals.szPasswordServer, NULL, NULL},
+ {"socket options", P_GSTRING, P_GLOBAL, user_socket_options, NULL, NULL},
+ {"netbios name", P_UGSTRING,P_GLOBAL, myname, NULL, NULL},
+ {"netbios aliases", P_STRING, P_GLOBAL, &Globals.szNetbiosAliases, NULL, NULL},
+ {"smbrun", P_STRING, P_GLOBAL, &Globals.szSmbrun, NULL, NULL},
+ {"log file", P_STRING, P_GLOBAL, &Globals.szLogFile, NULL, NULL},
+ {"config file", P_STRING, P_GLOBAL, &Globals.szConfigFile, NULL, NULL},
+ {"smb passwd file", P_STRING, P_GLOBAL, &Globals.szSMBPasswdFile, NULL, NULL},
+ {"hosts equiv", P_STRING, P_GLOBAL, &Globals.szHostsEquiv, NULL, NULL},
+ {"preload", P_STRING, P_GLOBAL, &Globals.szAutoServices, NULL, NULL},
+ {"auto services", P_STRING, P_GLOBAL, &Globals.szAutoServices, NULL, NULL},
+ {"server string", P_STRING, P_GLOBAL, &Globals.szServerString, NULL, NULL},
+ {"printcap name", P_STRING, P_GLOBAL, &Globals.szPrintcapname, NULL, NULL},
+ {"printcap", P_STRING, P_GLOBAL, &Globals.szPrintcapname, NULL, NULL},
+ {"lock dir", P_STRING, P_GLOBAL, &Globals.szLockDir, NULL, NULL},
+ {"lock directory", P_STRING, P_GLOBAL, &Globals.szLockDir, NULL, NULL},
+ {"root directory", P_STRING, P_GLOBAL, &Globals.szRootdir, NULL, NULL},
+ {"root dir", P_STRING, P_GLOBAL, &Globals.szRootdir, NULL, NULL},
+ {"root", P_STRING, P_GLOBAL, &Globals.szRootdir, NULL, NULL},
+ {"default service", P_STRING, P_GLOBAL, &Globals.szDefaultService, NULL, NULL},
+ {"default", P_STRING, P_GLOBAL, &Globals.szDefaultService, NULL, NULL},
+ {"message command", P_STRING, P_GLOBAL, &Globals.szMsgCommand, NULL, NULL},
+ {"dfree command", P_STRING, P_GLOBAL, &Globals.szDfree, NULL, NULL},
+ {"passwd program", P_STRING, P_GLOBAL, &Globals.szPasswdProgram, NULL, NULL},
+ {"passwd chat", P_STRING, P_GLOBAL, &Globals.szPasswdChat, NULL, NULL},
+ {"valid chars", P_STRING, P_GLOBAL, &Globals.szValidChars, handle_valid_chars, NULL},
+ {"workgroup", P_USTRING, P_GLOBAL, &Globals.szWorkGroup, NULL, NULL},
+ {"domain sid", P_USTRING, P_GLOBAL, &Globals.szDomainSID, NULL, NULL},
+ {"domain other sids",P_STRING, P_GLOBAL, &Globals.szDomainOtherSIDs, NULL, NULL},
+ {"domain groups", P_STRING, P_GLOBAL, &Globals.szDomainGroups, NULL, NULL},
+ {"domain controller",P_BOOL , P_GLOBAL, &Globals.bDomainController,NULL, NULL},
+ {"domain admin users",P_STRING, P_GLOBAL, &Globals.szDomainAdminUsers, NULL, NULL},
+ {"domain guest users",P_STRING, P_GLOBAL, &Globals.szDomainGuestUsers, NULL, NULL},
+ {"domain hosts allow",P_STRING, P_GLOBAL, &Globals.szDomainHostsallow, NULL, NULL},
+ {"domain allow hosts",P_STRING, P_GLOBAL, &Globals.szDomainHostsallow, NULL, NULL},
+ {"domain hosts deny", P_STRING, P_GLOBAL, &Globals.szDomainHostsdeny, NULL, NULL},
+ {"domain deny hosts", P_STRING, P_GLOBAL, &Globals.szDomainHostsdeny, NULL, NULL},
+ {"username map", P_STRING, P_GLOBAL, &Globals.szUsernameMap, NULL, NULL},
+ {"character set", P_STRING, P_GLOBAL, &Globals.szCharacterSet, handle_character_set, NULL},
+ {"logon script", P_STRING, P_GLOBAL, &Globals.szLogonScript, NULL, NULL},
+ {"logon path", P_STRING, P_GLOBAL, &Globals.szLogonPath, NULL, NULL},
+ {"logon drive", P_STRING, P_GLOBAL, &Globals.szLogonDrive, NULL, NULL},
+ {"logon home", P_STRING, P_GLOBAL, &Globals.szLogonHome, NULL, NULL},
+ {"remote announce", P_STRING, P_GLOBAL, &Globals.szRemoteAnnounce, NULL, NULL},
+ {"remote browse sync",P_STRING, P_GLOBAL, &Globals.szRemoteBrowseSync,NULL, NULL},
+ {"socket address", P_STRING, P_GLOBAL, &Globals.szSocketAddress, NULL, NULL},
+ {"homedir map", P_STRING, P_GLOBAL, &Globals.szNISHomeMapName, NULL, NULL},
+ {"announce version", P_STRING, P_GLOBAL, &Globals.szAnnounceVersion, NULL, NULL},
+ {"max log size", P_INTEGER, P_GLOBAL, &Globals.max_log_size, NULL, NULL},
+ {"mangled stack", P_INTEGER, P_GLOBAL, &Globals.mangled_stack, NULL, NULL},
+ {"max mux", P_INTEGER, P_GLOBAL, &Globals.max_mux, NULL, NULL},
+ {"max xmit", P_INTEGER, P_GLOBAL, &Globals.max_xmit, NULL, NULL},
+ {"max packet", P_INTEGER, P_GLOBAL, &Globals.max_packet, NULL, NULL},
+ {"packet size", P_INTEGER, P_GLOBAL, &Globals.max_packet, NULL, NULL},
+ {"password level", P_INTEGER, P_GLOBAL, &Globals.pwordlevel, NULL, NULL},
+ {"username level", P_INTEGER, P_GLOBAL, &Globals.unamelevel, NULL, NULL},
+ {"keepalive", P_INTEGER, P_GLOBAL, &keepalive, NULL, NULL},
+ {"deadtime", P_INTEGER, P_GLOBAL, &Globals.deadtime, NULL, NULL},
+ {"time offset", P_INTEGER, P_GLOBAL, &extra_time_offset, NULL, NULL},
+ {"read size", P_INTEGER, P_GLOBAL, &Globals.ReadSize, NULL, NULL},
+ {"shared mem size", P_INTEGER, P_GLOBAL, &Globals.shmem_size, NULL, NULL},
+ {"coding system", P_STRING, P_GLOBAL, &Globals.szCodingSystem, handle_coding_system, NULL},
+ {"client code page", P_INTEGER, P_GLOBAL, &Globals.client_code_page, NULL, NULL},
+ {"os level", P_INTEGER, P_GLOBAL, &Globals.os_level, NULL, NULL},
+ {"max ttl", P_INTEGER, P_GLOBAL, &Globals.max_ttl, NULL, NULL},
+ {"dns proxy", P_BOOL, P_GLOBAL, &Globals.bDNSproxy, NULL, NULL},
+ {"wins support", P_BOOL, P_GLOBAL, &Globals.bWINSsupport, NULL, NULL},
+ {"wins proxy", P_BOOL, P_GLOBAL, &Globals.bWINSproxy, NULL, NULL},
+ {"wins server", P_STRING, P_GLOBAL, &Globals.szWINSserver, NULL, NULL},
+ {"preferred master", P_BOOL, P_GLOBAL, &Globals.bPreferredMaster, NULL, NULL},
+ {"prefered master", P_BOOL, P_GLOBAL, &Globals.bPreferredMaster, NULL, NULL},
+ {"local master", P_BOOL, P_GLOBAL, &Globals.bLocalMaster, NULL, NULL},
+ {"domain master", P_BOOL, P_GLOBAL, &Globals.bDomainMaster, NULL, NULL},
+ {"domain logons", P_BOOL, P_GLOBAL, &Globals.bDomainLogons, NULL, NULL},
+ {"browse list", P_BOOL, P_GLOBAL, &Globals.bBrowseList, NULL, NULL},
+ {"unix realname", P_BOOL, P_GLOBAL, &Globals.bUnixRealname, NULL, NULL},
+ {"NIS homedir", P_BOOL, P_GLOBAL, &Globals.bNISHomeMap, NULL, NULL},
+ {"time server", P_BOOL, P_GLOBAL, &Globals.bTimeServer, NULL, NULL},
+ {"printer driver file", P_STRING, P_GLOBAL, &Globals.szDriverFile, NULL, NULL},
+ {"-valid", P_BOOL, P_LOCAL, &sDefault.valid, NULL, NULL},
+ {"comment", P_STRING, P_LOCAL, &sDefault.comment, NULL, NULL},
+ {"copy", P_STRING, P_LOCAL, &sDefault.szCopy, handle_copy, NULL},
+ {"include", P_STRING, P_LOCAL, &sDefault.szInclude, handle_include, NULL},
+ {"exec", P_STRING, P_LOCAL, &sDefault.szPreExec, NULL, NULL},
+ {"preexec", P_STRING, P_LOCAL, &sDefault.szPreExec, NULL, NULL},
+ {"postexec", P_STRING, P_LOCAL, &sDefault.szPostExec, NULL, NULL},
+ {"root preexec", P_STRING, P_LOCAL, &sDefault.szRootPreExec, NULL, NULL},
+ {"root postexec", P_STRING, P_LOCAL, &sDefault.szRootPostExec, NULL, NULL},
+ {"alternate permissions",P_BOOL,P_LOCAL, &sDefault.bAlternatePerm, NULL, NULL},
+ {"revalidate", P_BOOL, P_LOCAL, &sDefault.bRevalidate, NULL, NULL},
+ {"default case", P_ENUM, P_LOCAL, &sDefault.iDefaultCase, NULL, enum_case},
+ {"case sensitive", P_BOOL, P_LOCAL, &sDefault.bCaseSensitive, NULL, NULL},
+ {"casesignames", P_BOOL, P_LOCAL, &sDefault.bCaseSensitive, NULL, NULL},
+ {"preserve case", P_BOOL, P_LOCAL, &sDefault.bCasePreserve, NULL, NULL},
+ {"short preserve case",P_BOOL, P_LOCAL, &sDefault.bShortCasePreserve,NULL, NULL},
+ {"mangle case", P_BOOL, P_LOCAL, &sDefault.bCaseMangle, NULL, NULL},
+ {"mangling char", P_CHAR, P_LOCAL, &sDefault.magic_char, NULL, NULL},
+ {"browseable", P_BOOL, P_LOCAL, &sDefault.bBrowseable, NULL, NULL},
+ {"browsable", P_BOOL, P_LOCAL, &sDefault.bBrowseable, NULL, NULL},
+ {"available", P_BOOL, P_LOCAL, &sDefault.bAvailable, NULL, NULL},
+ {"path", P_STRING, P_LOCAL, &sDefault.szPath, NULL, NULL},
+ {"directory", P_STRING, P_LOCAL, &sDefault.szPath, NULL, NULL},
+ {"username", P_STRING, P_LOCAL, &sDefault.szUsername, NULL, NULL},
+ {"user", P_STRING, P_LOCAL, &sDefault.szUsername, NULL, NULL},
+ {"users", P_STRING, P_LOCAL, &sDefault.szUsername, NULL, NULL},
+ {"guest account", P_STRING, P_LOCAL, &sDefault.szGuestaccount, NULL, NULL},
+ {"invalid users", P_STRING, P_LOCAL, &sDefault.szInvalidUsers, NULL, NULL},
+ {"valid users", P_STRING, P_LOCAL, &sDefault.szValidUsers, NULL, NULL},
+ {"admin users", P_STRING, P_LOCAL, &sDefault.szAdminUsers, NULL, NULL},
+ {"read list", P_STRING, P_LOCAL, &sDefault.readlist, NULL, NULL},
+ {"write list", P_STRING, P_LOCAL, &sDefault.writelist, NULL, NULL},
+ {"volume", P_STRING, P_LOCAL, &sDefault.volume, NULL, NULL},
+ {"force user", P_STRING, P_LOCAL, &sDefault.force_user, NULL, NULL},
+ {"force group", P_STRING, P_LOCAL, &sDefault.force_group, NULL, NULL},
+ {"group", P_STRING, P_LOCAL, &sDefault.force_group, NULL, NULL},
+ {"read only", P_BOOL, P_LOCAL, &sDefault.bRead_only, NULL, NULL},
+ {"write ok", P_BOOLREV, P_LOCAL, &sDefault.bRead_only, NULL, NULL},
+ {"writeable", P_BOOLREV, P_LOCAL, &sDefault.bRead_only, NULL, NULL},
+ {"writable", P_BOOLREV, P_LOCAL, &sDefault.bRead_only, NULL, NULL},
+ {"max connections", P_INTEGER, P_LOCAL, &sDefault.iMaxConnections, NULL, NULL},
+ {"min print space", P_INTEGER, P_LOCAL, &sDefault.iMinPrintSpace, NULL, NULL},
+ {"create mask", P_OCTAL, P_LOCAL, &sDefault.iCreate_mask, NULL, NULL},
+ {"create mode", P_OCTAL, P_LOCAL, &sDefault.iCreate_mask, NULL, NULL},
+ {"force create mode",P_OCTAL, P_LOCAL, &sDefault.iCreate_force_mode, NULL, NULL},
+ {"directory mask", P_OCTAL, P_LOCAL, &sDefault.iDir_mask, NULL, NULL},
+ {"directory mode", P_OCTAL, P_LOCAL, &sDefault.iDir_mask, NULL, NULL},
+ {"force directory mode", P_OCTAL, P_LOCAL, &sDefault.iDir_force_mode, NULL, NULL},
+ {"set directory", P_BOOLREV, P_LOCAL, &sDefault.bNo_set_dir, NULL, NULL},
+ {"status", P_BOOL, P_LOCAL, &sDefault.status, NULL, NULL},
+ {"hide dot files", P_BOOL, P_LOCAL, &sDefault.bHideDotFiles, NULL, NULL},
+ {"delete veto files",P_BOOL, P_LOCAL, &sDefault.bDeleteVetoFiles, NULL, NULL},
+ {"veto files", P_STRING, P_LOCAL, &sDefault.szVetoFiles, NULL, NULL},
+ {"hide files", P_STRING, P_LOCAL, &sDefault.szHideFiles, NULL, NULL},
+ {"veto oplock files",P_STRING, P_LOCAL, &sDefault.szVetoOplockFiles,NULL, NULL},
+ {"guest only", P_BOOL, P_LOCAL, &sDefault.bGuest_only, NULL, NULL},
+ {"only guest", P_BOOL, P_LOCAL, &sDefault.bGuest_only, NULL, NULL},
+ {"guest ok", P_BOOL, P_LOCAL, &sDefault.bGuest_ok, NULL, NULL},
+ {"public", P_BOOL, P_LOCAL, &sDefault.bGuest_ok, NULL, NULL},
+ {"print ok", P_BOOL, P_LOCAL, &sDefault.bPrint_ok, NULL, NULL},
+ {"printable", P_BOOL, P_LOCAL, &sDefault.bPrint_ok, NULL, NULL},
+ {"postscript", P_BOOL, P_LOCAL, &sDefault.bPostscript, NULL, NULL},
+ {"map system", P_BOOL, P_LOCAL, &sDefault.bMap_system, NULL, NULL},
+ {"map hidden", P_BOOL, P_LOCAL, &sDefault.bMap_hidden, NULL, NULL},
+ {"map archive", P_BOOL, P_LOCAL, &sDefault.bMap_archive, NULL, NULL},
+ {"locking", P_BOOL, P_LOCAL, &sDefault.bLocking, NULL, NULL},
+ {"strict locking", P_BOOL, P_LOCAL, &sDefault.bStrictLocking, NULL, NULL},
+ {"share modes", P_BOOL, P_LOCAL, &sDefault.bShareModes, NULL, NULL},
+ {"oplocks", P_BOOL, P_LOCAL, &sDefault.bOpLocks, NULL, NULL},
+ {"only user", P_BOOL, P_LOCAL, &sDefault.bOnlyUser, NULL, NULL},
+ {"wide links", P_BOOL, P_LOCAL, &sDefault.bWidelinks, NULL, NULL},
+ {"follow symlinks", P_BOOL, P_LOCAL, &sDefault.bSymlinks, NULL, NULL},
+ {"sync always", P_BOOL, P_LOCAL, &sDefault.bSyncAlways, NULL, NULL},
+ {"mangled names", P_BOOL, P_LOCAL, &sDefault.bMangledNames, NULL, NULL},
+ {"fake oplocks", P_BOOL, P_LOCAL, &sDefault.bFakeOplocks, NULL, NULL},
+ {"print command", P_STRING, P_LOCAL, &sDefault.szPrintcommand, NULL, NULL},
+ {"lpq command", P_STRING, P_LOCAL, &sDefault.szLpqcommand, NULL, NULL},
+ {"lprm command", P_STRING, P_LOCAL, &sDefault.szLprmcommand, NULL, NULL},
+ {"lppause command", P_STRING, P_LOCAL, &sDefault.szLppausecommand, NULL, NULL},
+ {"lpresume command", P_STRING, P_LOCAL, &sDefault.szLpresumecommand,NULL, NULL},
+ {"printer", P_STRING, P_LOCAL, &sDefault.szPrintername, NULL, NULL},
+ {"printer name", P_STRING, P_LOCAL, &sDefault.szPrintername, NULL, NULL},
+ {"printer driver", P_STRING, P_LOCAL, &sDefault.szPrinterDriver, NULL, NULL},
+ {"printer driver location", P_STRING, P_LOCAL, &sDefault.szPrinterDriverLocation, NULL, NULL},
+ {"hosts allow", P_STRING, P_LOCAL, &sDefault.szHostsallow, NULL, NULL},
+ {"allow hosts", P_STRING, P_LOCAL, &sDefault.szHostsallow, NULL, NULL},
+ {"hosts deny", P_STRING, P_LOCAL, &sDefault.szHostsdeny, NULL, NULL},
+ {"deny hosts", P_STRING, P_LOCAL, &sDefault.szHostsdeny, NULL, NULL},
+ {"dont descend", P_STRING, P_LOCAL, &sDefault.szDontdescend, NULL, NULL},
+ {"magic script", P_STRING, P_LOCAL, &sDefault.szMagicScript, NULL, NULL},
+ {"magic output", P_STRING, P_LOCAL, &sDefault.szMagicOutput, NULL, NULL},
+ {"mangled map", P_STRING, P_LOCAL, &sDefault.szMangledMap, NULL, NULL},
+ {"delete readonly", P_BOOL, P_LOCAL, &sDefault.bDeleteReadonly, NULL, NULL},
+ {"dos filetimes", P_BOOL, P_LOCAL, &sDefault.bDosFiletimes, NULL, NULL},
+
+ {NULL, P_BOOL, P_NONE, NULL, NULL, NULL}
};
@@ -513,11 +639,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 +658,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 +700,40 @@ 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
+ interpret_coding_system(KANJI);
+ 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 */
-
+ Globals.bDNSproxy = True;
}
/***************************************************************************
@@ -595,6 +756,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 +785,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 +860,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)
@@ -685,11 +876,36 @@ FN_GLOBAL_STRING(lp_passwd_program,&Globals.szPasswdProgram)
FN_GLOBAL_STRING(lp_passwd_chat,&Globals.szPasswdChat)
FN_GLOBAL_STRING(lp_passwordserver,&Globals.szPasswordServer)
FN_GLOBAL_STRING(lp_workgroup,&Globals.szWorkGroup)
-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_remote_browse_sync,&Globals.szRemoteBrowseSync)
+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_STRING(lp_domain_hostsallow,&Globals.szDomainHostsallow)
+FN_GLOBAL_STRING(lp_domain_hostsdeny,&Globals.szDomainHostsdeny)
+
+
+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_controller,&Globals.bDomainController)
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 +921,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 +935,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 +945,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 +966,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 +978,10 @@ 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_veto_oplocks,szVetoFiles)
+FN_LOCAL_STRING(lp_driverlocation,szPrinterDriverLocation)
FN_LOCAL_BOOL(lp_alternate_permissions,bAlternatePerm)
FN_LOCAL_BOOL(lp_revalidate,bRevalidate)
@@ -773,13 +1003,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 +1038,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 +1061,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 +1166,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 +1204,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));
@@ -1102,6 +1349,7 @@ static void copy_service(service *pserviceDest,
break;
case P_INTEGER:
+ case P_ENUM:
case P_OCTAL:
*(int *)dest_ptr = *(int *)src_ptr;
break;
@@ -1113,6 +1361,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 +1409,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 +1454,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,85 +1467,51 @@ 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
*************************************************************************/
-static BOOL handle_coding_system(char *pszParmValue,int *val)
+static BOOL handle_coding_system(char *pszParmValue,char **ptr)
{
- *val = interpret_coding_system(pszParmValue,*val);
- return(True);
+ string_set(ptr,pszParmValue);
+ interpret_coding_system(pszParmValue);
+ return(True);
}
-#endif /* KANJI */
/***************************************************************************
handle the interpretation of the character set system parameter
***************************************************************************/
-static BOOL handle_character_set(char *pszParmValue,int *val)
-{
- string_set(&Globals.szCharacterSet,pszParmValue);
- *val = interpret_character_set(pszParmValue,*val);
- return(True);
-}
-
-
-/***************************************************************************
-handle the interpretation of the protocol parameter
-***************************************************************************/
-static BOOL handle_protocol(char *pszParmValue,int *val)
-{
- *val = interpret_protocol(pszParmValue,*val);
- return(True);
-}
-
-/***************************************************************************
-handle the interpretation of the security parameter
-***************************************************************************/
-static BOOL handle_security(char *pszParmValue,int *val)
-{
- *val = interpret_security(pszParmValue,*val);
- return(True);
-}
-
-/***************************************************************************
-handle the interpretation of the default case
-***************************************************************************/
-static BOOL handle_case(char *pszParmValue,int *val)
+static BOOL handle_character_set(char *pszParmValue,char **ptr)
{
- if (strequal(pszParmValue,"LOWER"))
- *val = CASE_LOWER;
- else if (strequal(pszParmValue,"UPPER"))
- *val = CASE_UPPER;
- return(True);
+ string_set(ptr,pszParmValue);
+ interpret_character_set(pszParmValue);
+ return(True);
}
-/***************************************************************************
-handle the interpretation of the printing system
-***************************************************************************/
-static BOOL handle_printing(char *pszParmValue,int *val)
-{
- if (strequal(pszParmValue,"sysv"))
- *val = PRINT_SYSV;
- else if (strequal(pszParmValue,"aix"))
- *val = PRINT_AIX;
- else if (strequal(pszParmValue,"hpux"))
- *val = PRINT_HPUX;
- else if (strequal(pszParmValue,"bsd"))
- *val = PRINT_BSD;
- else if (strequal(pszParmValue,"qnx"))
- *val = PRINT_QNX;
- return(True);
-}
/***************************************************************************
handle the valid chars lines
@@ -1301,6 +1520,12 @@ 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 +1537,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 +1615,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;
+ int parmnum, i;
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 +1635,32 @@ 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) {
+ 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,51 +1690,147 @@ 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;
+
+ case P_ENUM:
+ for (i=0;parm_table[parmnum].enum_list[i].name;i++) {
+ if (strequal(pszParmValue, parm_table[parmnum].enum_list[i].name)) {
+ *(int *)parm_ptr = parm_table[parmnum].enum_list[i].value;
+ break;
+ }
+ }
+ 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(struct parm_struct *p,void *ptr, FILE *f)
{
- switch (type)
- {
- case P_BOOL:
- printf("%s",BOOLSTR(*(BOOL *)ptr));
- break;
+ int i;
+ switch (p->type) {
+ case P_ENUM:
+ for (i=0;p->enum_list[i].name;i++) {
+ if (*(int *)ptr == p->enum_list[i].value) {
+ fprintf(f,"%s",p->enum_list[i].name);
+ break;
+ }
+ }
+ break;
+
+ case P_BOOL:
+ fprintf(f,"%s",BOOLSTR(*(BOOL *)ptr));
+ break;
- case P_BOOLREV:
- printf("%s",BOOLSTR(! *(BOOL *)ptr));
- break;
+ case P_BOOLREV:
+ fprintf(f,"%s",BOOLSTR(! *(BOOL *)ptr));
+ break;
- case P_INTEGER:
- printf("%d",*(int *)ptr);
- break;
+ case P_INTEGER:
+ fprintf(f,"%d",*(int *)ptr);
+ break;
- case P_CHAR:
- printf("%c",*(char *)ptr);
- break;
+ case P_CHAR:
+ fprintf(f,"%c",*(char *)ptr);
+ break;
- case P_OCTAL:
- printf("0%o",*(int *)ptr);
- break;
+ case P_OCTAL:
+ fprintf(f,"0%o",*(int *)ptr);
+ break;
- case P_GSTRING:
- if ((char *)ptr)
- printf("%s",(char *)ptr);
- break;
+ case P_GSTRING:
+ case P_UGSTRING:
+ if ((char *)ptr)
+ fprintf(f,"%s",(char *)ptr);
+ break;
+
+ case P_STRING:
+ case P_USTRING:
+ if (*(char **)ptr)
+ fprintf(f,"%s",*(char **)ptr);
+ break;
+ }
+}
- case P_STRING:
- if (*(char **)ptr)
- printf("%s",*(char **)ptr);
- break;
- }
+
+/***************************************************************************
+print a parameter of the specified type
+***************************************************************************/
+static void parameter_string(struct parm_struct *p,void *ptr,char *s)
+{
+ int i;
+ s[0] = 0;
+
+ switch (p->type) {
+ case P_ENUM:
+ for (i=0;p->enum_list[i].name;i++) {
+ if (*(int *)ptr == p->enum_list[i].value) {
+ sprintf(s,"%s",p->enum_list[i].name);
+ break;
+ }
+ }
+ break;
+
+ 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;
+ }
}
@@ -1533,6 +1846,7 @@ static BOOL equal_parameter(parm_type type,void *ptr1,void *ptr2)
return(*((BOOL *)ptr1) == *((BOOL *)ptr2));
case P_INTEGER:
+ case P_ENUM:
case P_OCTAL:
return(*((int *)ptr1) == *((int *)ptr2));
@@ -1540,6 +1854,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 +1862,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 +1927,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],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 +1966,69 @@ static void dump_a_service(service *pService)
((char *)pService) + pdiff,
((char *)&sDefault) + pdiff))
{
- printf("\t%s: ",parm_table[i].label);
- print_parameter(parm_table[i].type,
- ((char *)pService) + pdiff);
- printf("\n");
+ fprintf(f,"\t%s = ",parm_table[i].label);
+ print_parameter(&parm_table[i],
+ ((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],
+ 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],
+ ((char *)pService) + pdiff,
+ value);
+ (*i)++;
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
#if 0
/***************************************************************************
Display the contents of a single copy structure.
@@ -1766,7 +2137,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 +2152,7 @@ BOOL lp_load(char *pszFname,BOOL global_only)
{
pstring n2;
BOOL bRetval;
-
+
add_to_file_list(pszFname);
bRetval = False;
@@ -1791,7 +2162,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 +2181,8 @@ BOOL lp_load(char *pszFname,BOOL global_only)
lp_add_ipc();
+ set_default_server_announce_type();
+
bLoaded = True;
return (bRetval);
@@ -1827,13 +2200,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 +2214,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 +2241,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
+/*******************************************************************
+ 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
+}
/*******************************************************************
- get a workgroup - but map to standalone if '*'
- ******************************************************************/
-char *my_workgroup(void)
+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..a0a259c0070 100644
--- a/source/param/params.c
+++ b/source/param/params.c
@@ -1,335 +1,569 @@
-/*
- 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;
-
- bRetval = False;
+ }
- /* record the filename for use in error messages one day... */
- pszParmFile = pszFileName;
+ /* Now parse the value. */
+ c = EatWhitespace( InFile ); /* Again, trim leading whitespace. */
+ while( (EOF !=c) && (c > 0) )
+ {
- 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 )
{
- *psz++ = ' ';
- trimleft(psz);
+ 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;
}
- 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);
-}
+ }
+ 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 )
+ {
+ DEBUG(0,("%s memory allocation failure.\n", func));
+ fclose(InFile);
+ return( False );
+ }
+ result = Parse( InFile, sfunc, pfunc );
+ free( bufr );
+ bufr = NULL;
+ bSize = 0;
+ }
+
+ fclose(InFile);
+
+ 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..4109383fb47 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);
@@ -107,11 +103,11 @@ static int gethexpwd(char *p, char *pwd)
return (True);
}
-/*
- * Routine to search the smbpasswd file for an entry matching the username.
- */
-struct smb_passwd *
-get_smbpwnam(char *name)
+/*************************************************************************
+ Routine to search the smbpasswd file for an entry matching the username
+ or user id. if the name is NULL, then the smb_uid is used instead.
+ *************************************************************************/
+struct smb_passwd *get_smbpwd_entry(char *name, int smb_userid)
{
/* Static buffers we will return. */
static struct smb_passwd pw_buf;
@@ -132,19 +128,28 @@ get_smbpwnam(char *name)
DEBUG(0, ("No SMB password file set\n"));
return (NULL);
}
- DEBUG(10, ("get_smbpwnam: opening file %s\n", pfile));
+ DEBUG(10, ("get_smbpwd_entry: opening file %s\n", pfile));
+
+ if (name != NULL)
+ {
+ DEBUG(10, ("get_smbpwd_entry: search by name: %s\n", name));
+ }
+ else
+ {
+ DEBUG(10, ("get_smbpwd_entry: search by smb_userid: %x\n", smb_userid));
+ }
fp = fopen(pfile, "r");
if (fp == NULL) {
- DEBUG(0, ("get_smbpwnam: unable to open file %s\n", pfile));
+ DEBUG(0, ("get_smbpwd_entry: unable to open file %s\n", pfile));
return NULL;
}
/* Set a 16k buffer to do more efficient reads */
setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf));
if ((lockfd = pw_file_lock(pfile, F_RDLCK, 5)) < 0) {
- DEBUG(0, ("get_smbpwnam: unable to lock file %s\n", pfile));
+ DEBUG(0, ("get_smbpwd_entry: unable to lock file %s\n", pfile));
fclose(fp);
return NULL;
}
@@ -180,10 +185,10 @@ get_smbpwnam(char *name)
linebuf[linebuf_len - 1] = '\0';
#ifdef DEBUG_PASSWORD
- DEBUG(100, ("get_smbpwnam: got line |%s|\n", linebuf));
+ DEBUG(100, ("get_smbpwd_entry: got line |%s|\n", linebuf));
#endif
if ((linebuf[0] == 0) && feof(fp)) {
- DEBUG(4, ("get_smbpwnam: end of file reached\n"));
+ DEBUG(4, ("get_smbpwd_entry: end of file reached\n"));
break;
}
/*
@@ -200,12 +205,12 @@ get_smbpwnam(char *name)
*/
if (linebuf[0] == '#' || linebuf[0] == '\0') {
- DEBUG(6, ("get_smbpwnam: skipping comment or blank line\n"));
+ DEBUG(6, ("get_smbpwd_entry: skipping comment or blank line\n"));
continue;
}
p = (unsigned char *) strchr(linebuf, ':');
if (p == NULL) {
- DEBUG(0, ("get_smbpwnam: malformed password entry (no :)\n"));
+ DEBUG(0, ("get_smbpwd_entry: malformed password entry (no :)\n"));
continue;
}
/*
@@ -214,55 +219,89 @@ get_smbpwnam(char *name)
*/
strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
user_name[PTR_DIFF(p, linebuf)] = '\0';
- if (!strequal(user_name, name))
- continue;
- /* User name matches - get uid and password */
+ /* get smb uid */
+
p++; /* Go past ':' */
if (!isdigit(*p)) {
- DEBUG(0, ("get_smbpwnam: malformed password entry (uid not number)\n"));
+ DEBUG(0, ("get_smbpwd_entry: malformed password entry (uid not number)\n"));
fclose(fp);
pw_file_unlock(lockfd);
return NULL;
}
+
uidval = atoi((char *) p);
+
while (*p && isdigit(*p))
+ {
p++;
- if (*p != ':') {
- DEBUG(0, ("get_smbpwnam: malformed password entry (no : after uid)\n"));
+ }
+
+ if (*p != ':')
+ {
+ DEBUG(0, ("get_smbpwd_entry: malformed password entry (no : after uid)\n"));
fclose(fp);
pw_file_unlock(lockfd);
return NULL;
}
+
+ if (name != NULL)
+ {
+ /* search is by user name */
+ if (!strequal(user_name, name)) continue;
+ DEBUG(10, ("get_smbpwd_entry: found by name: %s\n", user_name));
+ }
+ else
+ {
+ /* search is by user id */
+ if (uidval != smb_userid) continue;
+ DEBUG(10, ("get_smbpwd_entry: found by smb_userid: %x\n", uidval));
+ }
+
+ /* if we're here, the entry has been found (either by name or uid) */
+
/*
* Now get the password value - this should be 32 hex digits
* which are the ascii representations of a 16 byte string.
* Get two at a time and put them into the password.
*/
+
+ /* skip the ':' */
p++;
- if (*p == '*' || *p == 'X') {
+
+ if (*p == '*' || *p == 'X')
+ {
/* Password deliberately invalid - end here. */
- DEBUG(10, ("get_smbpwnam: entry invalidated for user %s\n", user_name));
+ DEBUG(10, ("get_smbpwd_entry: entry invalidated for user %s\n", user_name));
fclose(fp);
pw_file_unlock(lockfd);
return NULL;
}
- if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
- DEBUG(0, ("get_smbpwnam: malformed password entry (passwd too short)\n"));
+
+ if (linebuf_len < (PTR_DIFF(p, linebuf) + 33))
+ {
+ DEBUG(0, ("get_smbpwd_entry: malformed password entry (passwd too short)\n"));
fclose(fp);
pw_file_unlock(lockfd);
return (False);
}
- if (p[32] != ':') {
- DEBUG(0, ("get_smbpwnam: malformed password entry (no terminating :)\n"));
+
+ if (p[32] != ':')
+ {
+ DEBUG(0, ("get_smbpwd_entry: malformed password entry (no terminating :)\n"));
fclose(fp);
pw_file_unlock(lockfd);
return NULL;
}
- if (!strncasecmp((char *) p, "NO PASSWORD", 11)) {
+
+ if (!strncasecmp((char *) p, "NO PASSWORD", 11))
+ {
pw_buf.smb_passwd = NULL;
- } else {
- if(!gethexpwd(p,smbpwd)) {
+ }
+ else
+ {
+ if (!gethexpwd((char *)p, (char *)smbpwd))
+ {
DEBUG(0, ("Malformed Lanman password entry (non hex chars)\n"));
fclose(fp);
pw_file_unlock(lockfd);
@@ -270,6 +309,7 @@ get_smbpwnam(char *name)
}
pw_buf.smb_passwd = smbpwd;
}
+
pw_buf.smb_name = user_name;
pw_buf.smb_userid = uidval;
pw_buf.smb_nt_passwd = NULL;
@@ -280,14 +320,14 @@ 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;
}
}
fclose(fp);
pw_file_unlock(lockfd);
- DEBUG(5, ("get_smbpwname: returning passwd entry for user %s, uid %d\n",
+ DEBUG(5, ("get_smbpwd_entrye: returning passwd entry for user %s, uid %d\n",
user_name, uidval));
return &pw_buf;
}
@@ -296,9 +336,537 @@ get_smbpwnam(char *name)
pw_file_unlock(lockfd);
return NULL;
}
-#else
-void
-smbpass_dummy(void)
+
+/*
+ * Routine to search the smbpasswd file for an entry matching the username.
+ */
+BOOL add_smbpwd_entry(struct smb_passwd* pwd)
{
-} /* To avoid compiler complaints */
+ /* Static buffers we will return. */
+ static pstring user_name;
+
+ char linebuf[256];
+ char readbuf[16 * 1024];
+ unsigned char c;
+ unsigned char *p;
+ long linebuf_len;
+ FILE *fp;
+ int lockfd;
+ char *pfile = lp_smb_passwd_file();
+
+ int i;
+ int wr_len;
+
+ int fd;
+ int new_entry_length;
+ char *new_entry;
+ long offpos;
+
+ if (!*pfile)
+ {
+ DEBUG(0, ("No SMB password file set\n"));
+ return False;
+ }
+ DEBUG(10, ("add_smbpwd_entry: opening file %s\n", pfile));
+
+ fp = fopen(pfile, "r+");
+
+ if (fp == NULL)
+ {
+ DEBUG(0, ("add_smbpwd_entry: unable to open file %s\n", pfile));
+ return False;
+ }
+ /* Set a 16k buffer to do more efficient reads */
+ setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf));
+
+ if ((lockfd = pw_file_lock(pfile, F_RDLCK | F_WRLCK, 5)) < 0)
+ {
+ DEBUG(0, ("add_smbpwd_entry: unable to lock file %s\n", pfile));
+ fclose(fp);
+ return False;
+ }
+ /* make sure it is only rw by the owner */
+ chmod(pfile, 0600);
+
+ /* We have a write lock on the file. */
+ /*
+ * Scan the file, a line at a time and check if the name matches.
+ */
+ while (!feof(fp))
+ {
+ linebuf[0] = '\0';
+
+ fgets(linebuf, 256, fp);
+ if (ferror(fp))
+ {
+ fclose(fp);
+ pw_file_unlock(lockfd);
+ return False;
+ }
+
+ /*
+ * Check if the string is terminated with a newline - if not
+ * then we must keep reading and discard until we get one.
+ */
+ linebuf_len = strlen(linebuf);
+ if (linebuf[linebuf_len - 1] != '\n')
+ {
+ c = '\0';
+ while (!ferror(fp) && !feof(fp))
+ {
+ c = fgetc(fp);
+ if (c == '\n')
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ linebuf[linebuf_len - 1] = '\0';
+ }
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("add_smbpwd_entry: got line |%s|\n", linebuf));
+#endif
+
+ if ((linebuf[0] == 0) && feof(fp))
+ {
+ DEBUG(4, ("add_smbpwd_entry: end of file reached\n"));
+ break;
+ }
+
+ /*
+ * The line we have should be of the form :-
+ *
+ * username:uid:[32hex bytes]:....other flags presently
+ * ignored....
+ *
+ * or,
+ *
+ * username:uid:[32hex bytes]:[32hex bytes]:....ignored....
+ *
+ * if Windows NT compatible passwords are also present.
+ */
+
+ if (linebuf[0] == '#' || linebuf[0] == '\0')
+ {
+ DEBUG(6, ("add_smbpwd_entry: skipping comment or blank line\n"));
+ continue;
+ }
+
+ p = (unsigned char *) strchr(linebuf, ':');
+
+ if (p == NULL)
+ {
+ DEBUG(0, ("add_smbpwd_entry: malformed password entry (no :)\n"));
+ continue;
+ }
+
+ /*
+ * As 256 is shorter than a pstring we don't need to check
+ * length here - if this ever changes....
+ */
+ strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
+ user_name[PTR_DIFF(p, linebuf)] = '\0';
+ if (strequal(user_name, pwd->smb_name))
+ {
+ DEBUG(6, ("add_smbpwd_entry: entry already exists\n"));
+ return False;
+ }
+ }
+
+ /* ok - entry doesn't exist. we can add it */
+
+ /* Create a new smb passwd entry and set it to the given password. */
+ /* 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)
+ {
+ DEBUG(0, ("add_smbpwd_entry(lseek): Failed to add entry for user %s to file %s. \
+Error was %s\n", pwd->smb_name, pfile, strerror(errno)));
+
+ fclose(fp);
+ pw_file_unlock(lockfd);
+ return False;
+ }
+
+ new_entry_length = strlen(pwd->smb_name) + 1 + 15 + 1 + 32 + 1 + 32 + 1 + 2;
+
+ if((new_entry = (char *)malloc( new_entry_length )) == 0)
+ {
+ DEBUG(0, ("add_smbpwd_entry(malloc): Failed to add entry for user %s to file %s. \
+Error was %s\n",
+ pwd->smb_name, pfile, strerror(errno)));
+
+ fclose(fp);
+ pw_file_unlock(lockfd);
+ return False;
+ }
+
+ sprintf(new_entry, "%s:%u:", pwd->smb_name, (unsigned)pwd->smb_userid);
+ p = (unsigned char *)&new_entry[strlen(new_entry)];
+
+ for( i = 0; i < 16; i++)
+ {
+ sprintf((char *)&p[i*2], "%02X", pwd->smb_passwd[i]);
+ }
+ p += 32;
+
+ *p++ = ':';
+
+ for( i = 0; i < 16; i++)
+ {
+ sprintf((char *)&p[i*2], "%02X", pwd->smb_nt_passwd[i]);
+ }
+ p += 32;
+
+ *p++ = ':';
+ sprintf((char *)p,"\n");
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("add_smbpwd_entry(%d): new_entry_len %d entry_len %d made line |%s|\n",
+ fd, new_entry_length, strlen(new_entry), new_entry));
+#endif
+
+ if ((wr_len = write(fd, new_entry, strlen(new_entry))) != strlen(new_entry))
+ {
+ DEBUG(0, ("add_smbpwd_entry(write): %d Failed to add entry for user %s to file %s. \
+Error was %s\n", wr_len, pwd->smb_name, pfile, strerror(errno)));
+
+ /* Remove the entry we just wrote. */
+ if(ftruncate(fd, offpos) == -1)
+ {
+ DEBUG(0, ("add_smbpwd_entry: ERROR failed to ftruncate file %s. \
+Error was %s. Password file may be corrupt ! Please examine by hand !\n",
+ pwd->smb_name, strerror(errno)));
+ }
+
+ fclose(fp);
+ pw_file_unlock(lockfd);
+ return False;
+ }
+
+ fclose(fp);
+ pw_file_unlock(lockfd);
+ return True;
+}
+/*
+ * Routine to search the smbpasswd file for an entry matching the username.
+ * and then modify its password entry
+ */
+BOOL mod_smbpwd_entry(struct smb_passwd* pwd)
+{
+ /* Static buffers we will return. */
+ static pstring user_name;
+
+ char linebuf[256];
+ char readbuf[16 * 1024];
+ unsigned char c;
+ char ascii_p16[66];
+ unsigned char *p = NULL;
+ long linebuf_len = 0;
+ FILE *fp;
+ int lockfd;
+ char *pfile = lp_smb_passwd_file();
+ BOOL found_entry = False;
+
+ long pwd_seekpos = 0;
+
+ int i;
+ int wr_len;
+ int fd;
+
+ if (!*pfile)
+ {
+ DEBUG(0, ("No SMB password file set\n"));
+ return False;
+ }
+ DEBUG(10, ("mod_smbpwd_entry: opening file %s\n", pfile));
+
+ fp = fopen(pfile, "r+");
+
+ if (fp == NULL)
+ {
+ DEBUG(0, ("mod_smbpwd_entry: unable to open file %s\n", pfile));
+ return False;
+ }
+ /* Set a 16k buffer to do more efficient reads */
+ setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf));
+
+ if ((lockfd = pw_file_lock(pfile, F_RDLCK | F_WRLCK, 5)) < 0)
+ {
+ DEBUG(0, ("mod_smbpwd_entry: unable to lock file %s\n", pfile));
+ fclose(fp);
+ return False;
+ }
+ /* make sure it is only rw by the owner */
+ chmod(pfile, 0600);
+
+ /* We have a write lock on the file. */
+ /*
+ * Scan the file, a line at a time and check if the name matches.
+ */
+ while (!feof(fp))
+ {
+ pwd_seekpos = ftell(fp);
+
+ linebuf[0] = '\0';
+
+ fgets(linebuf, 256, fp);
+ if (ferror(fp))
+ {
+ fclose(fp);
+ pw_file_unlock(lockfd);
+ return False;
+ }
+
+ /*
+ * Check if the string is terminated with a newline - if not
+ * then we must keep reading and discard until we get one.
+ */
+ linebuf_len = strlen(linebuf);
+ if (linebuf[linebuf_len - 1] != '\n')
+ {
+ c = '\0';
+ while (!ferror(fp) && !feof(fp))
+ {
+ c = fgetc(fp);
+ if (c == '\n')
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ linebuf[linebuf_len - 1] = '\0';
+ }
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("mod_smbpwd_entry: got line |%s|\n", linebuf));
#endif
+
+ if ((linebuf[0] == 0) && feof(fp))
+ {
+ DEBUG(4, ("mod_smbpwd_entry: end of file reached\n"));
+ break;
+ }
+
+ /*
+ * The line we have should be of the form :-
+ *
+ * username:uid:[32hex bytes]:....other flags presently
+ * ignored....
+ *
+ * or,
+ *
+ * username:uid:[32hex bytes]:[32hex bytes]:....ignored....
+ *
+ * if Windows NT compatible passwords are also present.
+ */
+
+ if (linebuf[0] == '#' || linebuf[0] == '\0')
+ {
+ DEBUG(6, ("mod_smbpwd_entry: skipping comment or blank line\n"));
+ continue;
+ }
+
+ p = (unsigned char *) strchr(linebuf, ':');
+
+ if (p == NULL)
+ {
+ DEBUG(0, ("mod_smbpwd_entry: malformed password entry (no :)\n"));
+ continue;
+ }
+
+ /*
+ * As 256 is shorter than a pstring we don't need to check
+ * length here - if this ever changes....
+ */
+ strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
+ user_name[PTR_DIFF(p, linebuf)] = '\0';
+ if (strequal(user_name, pwd->smb_name))
+ {
+ found_entry = True;
+ break;
+ }
+ }
+
+ if (!found_entry) return False;
+
+ DEBUG(6, ("mod_smbpwd_entry: entry exists\n"));
+
+ /* User name matches - get uid and password */
+ p++; /* Go past ':' */
+
+ if (!isdigit(*p))
+ {
+ DEBUG(0, ("mod_smbpwd_entry: malformed password entry (uid not number)\n"));
+ fclose(fp);
+ pw_file_unlock(lockfd);
+ return False;
+ }
+
+ while (*p && isdigit(*p))
+ p++;
+ if (*p != ':')
+ {
+ DEBUG(0, ("mod_smbpwd_entry: malformed password entry (no : after uid)\n"));
+ fclose(fp);
+ pw_file_unlock(lockfd);
+ return False;
+ }
+ /*
+ * Now get the password value - this should be 32 hex digits
+ * which are the ascii representations of a 16 byte string.
+ * Get two at a time and put them into the password.
+ */
+ p++;
+
+ /* record exact password position */
+ pwd_seekpos += PTR_DIFF(p, linebuf);
+
+ if (*p == '*' || *p == 'X')
+ {
+ /* Password deliberately invalid - end here. */
+ DEBUG(10, ("get_smbpwd_entry: entry invalidated for user %s\n", user_name));
+ fclose(fp);
+ pw_file_unlock(lockfd);
+ return False;
+ }
+
+ if (linebuf_len < (PTR_DIFF(p, linebuf) + 33))
+ {
+ DEBUG(0, ("mod_smbpwd_entry: malformed password entry (passwd too short)\n"));
+ fclose(fp);
+ pw_file_unlock(lockfd);
+ return (False);
+ }
+
+ if (p[32] != ':')
+ {
+ DEBUG(0, ("mod_smbpwd_entry: malformed password entry (no terminating :)\n"));
+ fclose(fp);
+ pw_file_unlock(lockfd);
+ return False;
+ }
+
+ if (*p == '*' || *p == 'X')
+ {
+ fclose(fp);
+ pw_file_unlock(lockfd);
+ return False;
+ }
+ if (!strncasecmp((char *) p, "NO PASSWORD", 11))
+ {
+ fclose(fp);
+ pw_file_unlock(lockfd);
+ return False;
+ }
+
+ /* Now check if the NT compatible password is
+ available. */
+ p += 33; /* Move to the first character of the line after
+ the lanman password. */
+ if (linebuf_len < (PTR_DIFF(p, linebuf) + 33))
+ {
+ DEBUG(0, ("mod_smbpwd_entry: malformed password entry (passwd too short)\n"));
+ fclose(fp);
+ pw_file_unlock(lockfd);
+ return (False);
+ }
+
+ if (p[32] != ':')
+ {
+ DEBUG(0, ("mod_smbpwd_entry: malformed password entry (no terminating :)\n"));
+ fclose(fp);
+ pw_file_unlock(lockfd);
+ return False;
+ }
+
+ if (*p == '*' || *p == 'X')
+ {
+ fclose(fp);
+ pw_file_unlock(lockfd);
+ return False;
+ }
+
+ /* whew. entry is correctly formed. */
+
+ /*
+ * Do an atomic write into the file at the position defined by
+ * seekpos.
+ */
+
+ /* The mod user write needs to be atomic - so get the fd from
+ the fp and do a raw write() call.
+ */
+
+ fd = fileno(fp);
+
+ if (lseek(fd, pwd_seekpos - 1, SEEK_SET) != pwd_seekpos - 1)
+ {
+ DEBUG(1, ("mod_smbpwd_entry: seek fail on file %s.\n", pfile));
+ fclose(fp);
+ pw_file_unlock(lockfd);
+ return False;
+ }
+
+ /* Sanity check - ensure the character is a ':' */
+ if (read(fd, &c, 1) != 1)
+ {
+ DEBUG(1, ("mod_smbpwd_entry: read fail on file %s.\n", pfile));
+ fclose(fp);
+ pw_file_unlock(lockfd);
+ return False;
+ }
+
+ if (c != ':')
+ {
+ DEBUG(1, ("mod_smbpwd_entry: check on passwd file %s failed.\n", pfile));
+ fclose(fp);
+ pw_file_unlock(lockfd);
+ return False;
+ }
+
+ /* Create the 32 byte representation of the new p16 */
+ for (i = 0; i < 16; i++)
+ {
+ sprintf(&ascii_p16[i*2], "%02X", (uchar) pwd->smb_passwd[i]);
+ }
+ if (pwd->smb_nt_passwd != NULL)
+ {
+ /* Add on the NT md4 hash */
+ ascii_p16[32] = ':';
+ for (i = 0; i < 16; i++)
+ {
+ sprintf(&ascii_p16[(i*2)+33], "%02X", (uchar) pwd->smb_nt_passwd[i]);
+ }
+ wr_len = 65;
+ }
+ else
+ {
+ wr_len = 32;
+ }
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("mod_smbpwd_entry: "));
+ dump_data(100, ascii_p16, wr_len);
+#endif
+
+ if (write(fd, ascii_p16, wr_len) != wr_len)
+ {
+ DEBUG(1, ("mod_smbpwd_entry: write failed in passwd file %s\n", pfile));
+ fclose(fp);
+ pw_file_unlock(lockfd);
+ return False;
+ }
+
+ fclose(fp);
+ pw_file_unlock(lockfd);
+ return True;
+}
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..c862ff3b389 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
@@ -62,6 +62,18 @@ extern fstring local_machine;
#define QNLEN 12 /* queue name maximum length */
extern int Client;
+extern int oplock_sock;
+extern int smb_read_error;
+
+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)
{
@@ -131,10 +143,15 @@ 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));
+#ifdef CONFUSE_NETMONITOR_MSRPC_DECODING
+ /* if you don't want Net Monitor to decode your packets, do this!!! */
+ align = ((this_lparam+1)%4);
+#else
align = (this_lparam%4);
+#endif
set_message(outbuf,10+lsetup,align+this_ldata+this_lparam,True);
if (this_lparam)
@@ -162,8 +179,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 +206,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 +429,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 +445,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 +469,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 +487,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 +499,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 +508,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 +532,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 +572,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 +583,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 +591,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 +729,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 +749,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 +784,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 +806,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 +881,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 +917,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 +945,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 +1087,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 +1111,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 +1190,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 +1338,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 +1373,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 +1437,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 +1464,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 +1486,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 +1495,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 +1507,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 +1528,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 +1537,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 +1560,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 +1589,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 +1660,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 +1669,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 +1696,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 +1727,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 +1772,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 +1833,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 +1880,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 +1910,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 +1922,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 +1949,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 +2320,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 +2331,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 +2349,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 +2359,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 +2373,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 +2400,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 +2428,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 +2436,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 +2451,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 +2492,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 +2581,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 +2610,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 +2669,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 +2727,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 +2772,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 +2818,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 +2865,180 @@ 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
+ { "TransactNmPipe", "lsarpc", "lsass", 0x26, api_ntLsarpcTNP },
+ { "TransactNmPipe", "samr", "lsass", 0x26, api_samrTNP },
+ { "TransactNmPipe", "srvsvc", "lsass", 0x26, api_srvsvcTNP },
+ { "TransactNmPipe", "wkssvc", "ntsvcs", 0x26, api_wkssvcTNP },
+ { "TransactNmPipe", "NETLOGON", "NETLOGON", 0x26, api_netlogrpcTNP },
+ { NULL, NULL, NULL, -1, (BOOL (*)())api_Unsupported }
+#else
+ { "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;
+ BOOL set_nphs = False;
+
+ int i;
+ int fd;
+ int subcommand;
+ char *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];
+ pipe_name = get_rpc_pipe_hnd_name(fd);
+
+ if (pipe_name == NULL)
+ {
+ DEBUG(1,("api_fd_reply: INVALID PIPE 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
+ /* RPC Pipe command 0x26. */
+ if (data != NULL && api_fd_commands[i].subcommand == 0x26)
+ {
+ 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
+
+ /* Set Named Pipe Handle state */
+ if (subcommand == 0x1)
+ {
+ set_nphs = True;
+ reply = api_LsarpcSNPHS(fd, cnum, params);
+ }
+
+ if (!bind_req && !set_nphs)
+ {
+ 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 +3059,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 +3087,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 +3143,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,26 +3176,36 @@ 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,vuid,outbuf,data,params,tdscnt,tpscnt,mdrcnt,mprcnt);
+ }
- if (strequal(name,"LANMAN"))
- return(api_reply(cnum,uid,outbuf,data,params,tdscnt,tpscnt,mdrcnt,mprcnt));
+ if (strlen(name) < 1)
+ {
+ return api_fd_reply(cnum,vuid,outbuf,setup,data,params,suwcnt,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 (setup)
+ {
+ DEBUG(3,("unknown named pipe: setup 0x%X setup1=%d\n", (int)setup[0],(int)setup[1]));
+ }
+
+ return 0;
}
/****************************************************************************
reply to a SMBtrans
****************************************************************************/
-int reply_trans(char *inbuf,char *outbuf)
+int reply_trans(char *inbuf,char *outbuf, int size, int bufsize)
{
fstring name;
@@ -2667,7 +3214,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 +3229,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)
{
@@ -2716,20 +3268,25 @@ int reply_trans(char *inbuf,char *outbuf)
/* receive the rest of the trans packet */
while (pscnt < tpscnt || dscnt < tdscnt)
{
+ BOOL ret;
int pcnt,poff,dcnt,doff,pdisp,ddisp;
+
+ ret = receive_next_smb(Client,oplock_sock,inbuf,bufsize,SMB_SECONDARY_WAIT);
- receive_smb(Client,inbuf, 0);
- show_msg(inbuf);
-
- /* Ensure this is still a trans packet (sanity check) */
- if(CVAL(inbuf, smb_com) != SMBtrans)
+ if ((ret && (CVAL(inbuf, smb_com) != SMBtrans)) || !ret)
{
- DEBUG(2,("Invalid secondary trans2 packet\n"));
+ if(ret)
+ DEBUG(0,("reply_trans: Invalid secondary trans packet\n"));
+ else
+ DEBUG(0,("reply_trans: %s in getting secondary trans response.\n",
+ (smb_read_error == READ_ERROR) ? "error" : "timeout" ));
if (params) free(params);
if (data) free(data);
if (setup) free(setup);
return(ERROR(ERRSRV,ERRerror));
}
+
+ show_msg(inbuf);
tpscnt = SVAL(inbuf,smb_vwv0);
tdscnt = SVAL(inbuf,smb_vwv1);
@@ -2745,6 +3302,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 +3314,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 +3333,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 +3343,3 @@ int reply_trans(char *inbuf,char *outbuf)
return(outsize);
}
-
-
diff --git a/source/smbd/mangle.c b/source/smbd/mangle.c
index 8f1490c528d..bf264757155 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,34 +20,39 @@
*/
#include "includes.h"
-#include "loadparm.h"
extern int DEBUGLEVEL;
extern int case_default;
extern BOOL case_mangle;
/****************************************************************************
-provide a checksum on a string
-****************************************************************************/
+ * Provide a checksum on a string
+ *
+ * Input: s - the nul-terminated character string for which the checksum
+ * will be calculated.
+ * Output: The checksum value calculated for s.
+ *
+ ****************************************************************************/
int str_checksum(char *s)
-{
+ {
int res = 0;
int c;
int i=0;
- while (*s)
+
+ while( *s )
{
- c = *s;
- res ^= (c << (i % 15)) ^ (c >> (15-(i%15)));
- s++; i++;
+ c = *s;
+ res ^= (c << (i % 15)) ^ (c >> (15-(i%15)));
+ s++; i++;
}
return(res);
-}
+ } /* str_checksum */
/****************************************************************************
return True if a name is a special msdos reserved name
****************************************************************************/
static BOOL is_reserved_msdos(char *fname)
-{
+ {
char upperFname[13];
char *p;
@@ -73,44 +78,45 @@ static BOOL is_reserved_msdos(char *fname)
return (True) ;
return (False);
-}
+ } /* is_reserved_msdos */
/****************************************************************************
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;
char *slash_pos = strrchr(fname,'/');
int l;
- if (slash_pos) fname = slash_pos+1;
+ 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:
- if (strhasupper(fname)) return(False);
- break;
+ if (strhasupper(fname)) return(False);
+ break;
case CASE_UPPER:
- if (strhaslower(fname)) return(False);
- break;
+ if (strhaslower(fname)) return(False);
+ break;
}
+ }
/* can't be longer than 12 chars */
- if (len == 0 || len > 12)
+ if( len == 0 || len > 12 )
return(False);
/* can't be an MS-DOS Special file such as lpt1 or even lpt1.txt */
- if (is_reserved_msdos(fname))
+ if( is_reserved_msdos(fname) )
return(False);
/* can't contain invalid dos chars */
@@ -122,180 +128,220 @@ 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)
{
- 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++;
- }
+ 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)
+ else
{
- if (!isdoschar(*p))
- return(False);
- p++;
- }
-#endif /* KANJI */
- }
+ while (*p)
+ {
+ if (!isdoschar(*p))
+ return(False);
+ p++;
+ }
+ }
+ }
/* no dot and less than 9 means OK */
if (!dot_pos)
return(len <= 8);
-
+
l = PTR_DIFF(dot_pos,fname);
/* base must be at least 1 char except special cases . and .. */
- if (l == 0)
+ if( l == 0 )
return(strcmp(fname,".") == 0 || strcmp(fname,"..") == 0);
/* base can't be greater than 8 */
- if (l > 8)
+ if( l > 8 )
return(False);
- if (lp_strip_dot() &&
+ if( lp_strip_dot() &&
len - l == 1 &&
- !strchr(dot_pos+1,'.'))
+ !strchr(dot_pos+1,'.') )
{
- *dot_pos = 0;
- return(True);
+ *dot_pos = 0;
+ return(True);
}
/* extension must be between 1 and 3 */
- if ( (len - l < 2 ) || (len - l > 4) )
+ if( (len - l < 2 ) || (len - l > 4) )
return(False);
/* extension can't have a dot */
- if (strchr(dot_pos+1,'.'))
+ if( strchr(dot_pos+1,'.') )
return(False);
/* must be in 8.3 format */
return(True);
-}
+ } /* is_8_3 */
+
+/* -------------------------------------------------------------------------- **
+ * This section creates and maintains a stack of name mangling results.
+ * The original comments read: "keep a stack of name mangling results - just
+ * so file moves and copies have a chance of working" (whatever that means).
+ *
+ * There are three functions to manage the stack:
+ * reset_mangled_stack() -
+ * push_mangled_name() -
+ * check_mangled_stack() -
+ */
-
-
-/*
-keep a stack of name mangling results - just
-so file moves and copies have a chance of working
-*/
fstring *mangled_stack = NULL;
int mangled_stack_size = 0;
int mangled_stack_len = 0;
/****************************************************************************
-create the mangled stack
-****************************************************************************/
-void create_mangled_stack(int size)
-{
- if (mangled_stack)
+ * create the mangled stack CRH
+ ****************************************************************************/
+void reset_mangled_stack( int size )
+ {
+ if( mangled_stack )
+ {
+ free(mangled_stack);
+ mangled_stack_size = 0;
+ mangled_stack_len = 0;
+ }
+
+ if( size > 0 )
{
- free(mangled_stack);
- mangled_stack_size = 0;
- mangled_stack_len = 0;
+ mangled_stack = (fstring *)malloc( sizeof(fstring) * size );
+ if( mangled_stack )
+ mangled_stack_size = size;
}
- if (size > 0)
- mangled_stack = (fstring *)malloc(sizeof(fstring)*size);
- if (mangled_stack) mangled_stack_size = size;
-}
+ else
+ mangled_stack = NULL;
+ } /* create_mangled_stack */
/****************************************************************************
-push a mangled name onto the stack
-****************************************************************************/
+ * push a mangled name onto the stack CRH
+ ****************************************************************************/
static void push_mangled_name(char *s)
-{
+ {
int i;
char *p;
- if (!mangled_stack)
+ /* If the stack doesn't exist... Fail. */
+ if( !mangled_stack )
return;
- for (i=0;i<mangled_stack_len;i++)
- if (strcmp(s,mangled_stack[i]) == 0)
+ /* If name <s> is already on the stack, move it to the top. */
+ for( i=0; i<mangled_stack_len; i++ )
+ {
+ if( strcmp( s, mangled_stack[i] ) == 0 )
{
- array_promote(mangled_stack[0],sizeof(fstring),i);
- return;
+ array_promote( mangled_stack[0],sizeof(fstring), i );
+ return;
}
+ }
- memmove(mangled_stack[1],mangled_stack[0],
- sizeof(fstring)*MIN(mangled_stack_len,mangled_stack_size-1));
- strcpy(mangled_stack[0],s);
- p = strrchr(mangled_stack[0],'.');
- if (p && (!strhasupper(p+1)) && (strlen(p+1) < 4))
+ /* If name <s> wasn't already there, add it to the top of the stack. */
+ memmove( mangled_stack[1], mangled_stack[0],
+ sizeof(fstring) * MIN(mangled_stack_len, mangled_stack_size-1) );
+ strcpy( mangled_stack[0], s );
+ mangled_stack_len = MIN( mangled_stack_size, mangled_stack_len+1 );
+
+ /* Hmmm...
+ * Find the last dot '.' in the name,
+ * if there are any upper case characters past the last dot
+ * and there are no more than three characters past the last dot
+ * then terminate the name *at* the last dot.
+ */
+ p = strrchr( mangled_stack[0], '.' );
+ if( p && (!strhasupper(p+1)) && (strlen(p+1) < (size_t)4) )
*p = 0;
- mangled_stack_len = MIN(mangled_stack_size,mangled_stack_len+1);
-}
+
+ } /* push_mangled_name */
/****************************************************************************
-check for a name on the mangled name stack
-****************************************************************************/
+ * check for a name on the mangled name stack CRH
+ ****************************************************************************/
BOOL check_mangled_stack(char *s)
-{
+ {
int i;
pstring tmpname;
char extension[5];
- char *p = strrchr(s,'.');
+ char *p = strrchr( s, '.' );
BOOL check_extension = False;
extension[0] = 0;
- if (!mangled_stack) return(False);
+ /* If the stack doesn't exist, fail. */
+ if( !mangled_stack )
+ return(False);
- if (p)
+ /* If there is a file extension, then we need to play with it, too. */
+ if( p )
{
- check_extension = True;
- StrnCpy(extension,p,4);
- strlower(extension); /* XXXXXXX */
+ check_extension = True;
+ StrnCpy( extension, p, 4 );
+ strlower( extension ); /* XXXXXXX */
}
- for (i=0;i<mangled_stack_len;i++)
+ for( i=0; i<mangled_stack_len; i++ )
{
- strcpy(tmpname,mangled_stack[i]);
+ strcpy(tmpname,mangled_stack[i]);
+ mangle_name_83(tmpname);
+ if( strequal(tmpname,s) )
+ {
+ strcpy(s,mangled_stack[i]);
+ break;
+ }
+ if( check_extension && !strchr(mangled_stack[i],'.') )
+ {
+ pstrcpy(tmpname,mangled_stack[i]);
+ strcat(tmpname,extension);
mangle_name_83(tmpname);
- if (strequal(tmpname,s))
- {
- strcpy(s,mangled_stack[i]);
- break;
- }
- if (check_extension && !strchr(mangled_stack[i],'.'))
- {
- strcpy(tmpname,mangled_stack[i]);
- strcat(tmpname,extension);
- mangle_name_83(tmpname);
- if (strequal(tmpname,s))
- {
- strcpy(s,mangled_stack[i]);
- strcat(s,extension);
- break;
- }
- }
+ if( strequal(tmpname,s) )
+ {
+ strcpy(s,mangled_stack[i]);
+ strcat(s,extension);
+ break;
+ }
+ }
}
- if (i < mangled_stack_len)
+ if( i < mangled_stack_len )
{
- DEBUG(3,("Found %s on mangled stack as %s\n",s,mangled_stack[i]));
- array_promote(mangled_stack[0],sizeof(fstring),i);
- return(True);
+ DEBUG(3,("Found %s on mangled stack as %s\n",s,mangled_stack[i]));
+ array_promote(mangled_stack[0],sizeof(fstring),i);
+ return(True);
}
return(False);
-}
+ } /* check_mangled_stack */
+
-static char *map_filename(char *s, /* This is null terminated */
- char *pattern, /* This isn't. */
- int len) /* This is the length of pattern. */
-{
+/* End of the mangled stack section.
+ * -------------------------------------------------------------------------- **
+ */
+
+
+static char *map_filename( char *s, /* This is null terminated */
+ char *pattern, /* This isn't. */
+ int len ) /* This is the length of pattern. */
+ {
static pstring matching_bit; /* The bit of the string which matches */
/* a * in pattern if indeed there is a * */
char *sp; /* Pointer into s. */
@@ -304,57 +350,68 @@ 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 == '*')) {
+ if( (len == 1) && (*pattern == '*') )
+ {
return NULL; /* Impossible, too ambiguous for */
- /* words! */
- }
+ } /* words! */
while ((*sp) /* Not the end of the string. */
&& (*pp) /* Not the end of the pattern. */
&& (*sp == *pp) /* The two match. */
- && (*pp != '*')) { /* No wildcard. */
+ && (*pp != '*')) /* No wildcard. */
+ {
sp++; /* Keep looking. */
pp++;
- }
- if (!*sp && !*pp) /* End of pattern. */
- return matching_bit; /* Simple match. Return empty string. */
- if (*pp == '*') {
+ }
+
+ if( !*sp && !*pp ) /* End of pattern. */
+ return( matching_bit ); /* Simple match. Return empty string. */
+
+ if (*pp == '*')
+ {
pp++; /* Always interrested in the chacter */
/* after the '*' */
- if (!*pp) { /* It is at the end of the pattern. */
+ if (!*pp) /* It is at the end of the pattern. */
+ {
StrnCpy(matching_bit, s, sp-s);
return matching_bit;
- } else {
+ }
+ else
+ {
/* The next character in pattern must match a character further */
/* along s than sp so look for that character. */
match_start = sp;
- while ((*sp) /* Not the end of s. */
+ while( (*sp) /* Not the end of s. */
&& (*sp != *pp)) /* Not the same */
sp++; /* Keep looking. */
- if (!*sp) { /* Got to the end without a match. */
+ if (!*sp) /* Got to the end without a match. */
+ {
return NULL;
- } else { /* Still hope for a match. */
+ } /* Still hope for a match. */
+ else
+ {
/* Now sp should point to a matching character. */
StrnCpy(matching_bit, match_start, sp-match_start);
/* Back to needing a stright match again. */
- while ((*sp) /* Not the end of the string. */
+ while( (*sp) /* Not the end of the string. */
&& (*pp) /* Not the end of the pattern. */
- && (*sp == *pp)) { /* The two match. */
+ && (*sp == *pp) ) /* The two match. */
+ {
sp++; /* Keep looking. */
pp++;
- }
+ }
if (!*sp && !*pp) /* Both at end so it matched */
return matching_bit;
else
return NULL;
+ }
}
}
- }
return NULL; /* No match. */
-}
+ } /* map_filename */
/* this is the magic char used for mangling */
@@ -362,40 +419,39 @@ char magic_char = '~';
/****************************************************************************
-determine whther is name could be a mangled name
+return True if the name could be a mangled name
****************************************************************************/
-BOOL is_mangled(char *s)
-{
+BOOL is_mangled( char *s )
+ {
char *m = strchr(s,magic_char);
- if (!m) return(False);
- /* we use two base 36 chars efore the extension */
- if (m[1] == '.' || m[1] == 0 ||
+ if( !m )
+ return(False);
+
+ /* we use two base 36 chars before the extension */
+ if( m[1] == '.' || m[1] == 0 ||
m[2] == '.' || m[2] == 0 ||
- (m[3] != '.' && m[3] != 0))
- return(is_mangled(m+1));
+ (m[3] != '.' && m[3] != 0) )
+ return( is_mangled(m+1) );
/* it could be */
return(True);
-}
+ } /* is_mangled */
/****************************************************************************
return a base 36 character. v must be from 0 to 35.
****************************************************************************/
-static char base36(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 base36(unsigned int v)
+ {
+ static char basechars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ return basechars[v % 36];
+ } /* base36 */
static void do_fwd_mangled_map(char *s, char *MangledMap)
-{
+ {
/* MangledMap is a series of name pairs in () separated by spaces.
* If s matches the first of the pair then the name given is the
* second of the pair. A * means any number of any character and if
@@ -415,22 +471,25 @@ static void do_fwd_mangled_map(char *s, char *MangledMap)
char *np; /* Points into new_string. */
DEBUG(5,("Mangled Mapping '%s' map '%s'\n", s, MangledMap));
- while (*start) {
+ 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 == ')')))
end++;
- if (!*end) {
+ if (!*end)
+ {
start = end;
continue; /* Always check for the end. */
- }
+ }
DEBUG(5,("End of first in pair '%s'\n", end));
- if ((match_string = map_filename(s, start, end-start))) {
+ if ((match_string = map_filename(s, start, end-start)))
+ {
DEBUG(5,("Found a match\n"));
/* Found a match. */
start = end+1; /* Point to start of what it is to become. */
@@ -441,39 +500,42 @@ static void do_fwd_mangled_map(char *s, char *MangledMap)
&& (*end != ')') /* Not the end of the pattern. */
&& (*end != '*')) /* Not a wildcard. */
*np++ = *end++;
- if (!*end) {
+ if (!*end)
+ {
start = end;
continue; /* Always check for the end. */
- }
- if (*end == '*') {
- strcpy(np, match_string);
+ }
+ if (*end == '*')
+ {
+ pstrcpy(np, match_string);
np += strlen(match_string);
end++; /* Skip the '*' */
while ((*end) /* Not the end of string. */
&& (*end != ')') /* Not the end of the pattern. */
&& (*end != '*')) /* Not a wildcard. */
*np++ = *end++;
- }
- if (!*end) {
+ }
+ if (!*end)
+ {
start = end;
continue; /* Always check for the end. */
- }
+ }
*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 */
/* anymore. */
start++;
- }
-}
+ }
+ } /* do_fwd_mangled_map */
/****************************************************************************
do the actual mangling to 8.3 format
****************************************************************************/
void mangle_name_83(char *s)
-{
+ {
int csum = str_checksum(s);
char *p;
char extension[4];
@@ -485,60 +547,127 @@ void mangle_name_83(char *s)
base[0]=0;
p = strrchr(s,'.');
- if (p && (strlen(p+1)<4) )
+ if( p && (strlen(p+1) < (size_t)4) )
{
- BOOL all_normal = (strisnormal(p+1)); /* XXXXXXXXX */
- if (all_normal && p[1] != 0)
- {
- *p = 0;
- csum = str_checksum(s);
- *p = '.';
- }
+ BOOL all_normal = (strisnormal(p+1)); /* XXXXXXXXX */
+
+ if (all_normal && p[1] != 0)
+ {
+ *p = 0;
+ csum = str_checksum(s);
+ *p = '.';
+ }
}
-
strupper(s);
DEBUG(5,("Mangling name %s to ",s));
- if (p)
+ if( p )
{
- if (p == s)
- strcpy(extension,"___");
- else
- {
- *p++ = 0;
- while (*p && extlen < 3)
- {
- if (isdoschar(*p) && *p != '.')
- extension[extlen++] = *p;
- p++;
- }
- extension[extlen] = 0;
- }
+ if (p == s)
+ strcpy(extension,"___");
+ else
+ {
+ *p++ = 0;
+ while (*p && extlen < 3)
+ {
+ 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);
- sprintf(s,"%s%c%c%c",base,magic_char,base36(csum/36),base36(csum%36));
+ sprintf(s,"%s%c%c%c",base,magic_char,base36(csum/36),base36(csum%36));
- if (*extension)
+ if( *extension )
{
- strcat(s,".");
- strcat(s,extension);
+ strcat(s,".");
+ strcat(s,extension);
}
DEBUG(5,("%s\n",s));
-}
+
+ } /* mangle_name_83 */
@@ -546,65 +675,74 @@ void mangle_name_83(char *s)
work out if a name is illegal, even for long names
******************************************************************/
static BOOL illegal_name(char *name)
-{
+ {
static unsigned char illegal[256];
static BOOL initialised=False;
unsigned char *s;
- if (!initialised) {
- char *ill = "*\\/?<>|\":{}";
+ if( !initialised )
+ {
+ char *ill = "*\\/?<>|\":";
initialised = True;
bzero((char *)illegal,256);
- for (s = (unsigned char *)ill; *s; s++)
+ for( s = (unsigned char *)ill; *s; s++ )
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++;
}
- }
-#else
- for (s = (unsigned char *)name;*s;s++)
- if (illegal[*s]) return(True);
-#endif
+ 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);
+ }
return(False);
-}
+ } /* illegal_name */
/****************************************************************************
convert a filename to DOS format. return True if successful.
****************************************************************************/
BOOL name_map_mangle(char *OutName,BOOL need83,int snum)
-{
+ {
#ifdef MANGLE_LONG_FILENAMES
- if (!need83 && illegal_name(OutName)) need83 = True;
+ if( !need83 && illegal_name(OutName) )
+ need83 = True;
#endif
/* apply any name mappings */
{
- char *map = lp_mangled_map(snum);
- if (map && *map)
- do_fwd_mangled_map(OutName,map);
+ char *map = lp_mangled_map(snum);
+
+ if (map && *map)
+ do_fwd_mangled_map(OutName,map);
}
/* check if it's already in 8.3 format */
- if (need83 && !is_8_3(OutName)) {
- if (!lp_manglednames(snum)) return(False);
+ if( need83 && !is_8_3(OutName, True) )
+ {
+ if( !lp_manglednames(snum) )
+ return(False);
/* mangle it into 8.3 */
push_mangled_name(OutName);
mangle_name_83(OutName);
- }
+ }
return(True);
-}
-
+ } /* name_map_mangle */
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..185fc68f5a3 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));
@@ -662,49 +887,51 @@ BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd, BOOL
return(False);
}
- smb_pass = get_smbpwnam(user);
- if(!smb_pass)
+ /* non-null username indicates search by username not smb userid */
+ smb_pass = get_smbpwd_entry(user, 0);
+ 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 +954,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 +1013,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 +1054,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 +1126,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 +1148,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 +1161,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 +1183,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 +1193,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 +1210,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 +1245,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 +1256,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 +1297,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 +1386,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 +1449,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 +1467,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 +1476,140 @@ 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;
- 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);
+ if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) {
+ DEBUG(1,("password server %s refused IPC$ connect\n", cli.desthost));
+ return False;
+ }
- send_smb(password_client,outbuf);
- ret = receive_smb(password_client,inbuf,5000);
- if (!ret || CVAL(inbuf,smb_rcls) != 0) {
- DEBUG(1,("password server %s rejected the password\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;
+ }
- /* 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.privilages == 0) {
+ DEBUG(1,("password server %s gave guest privilages\n", cli.desthost));
+ cli_tdis(&cli);
+ return False;
+ }
- DEBUG(3,("password server %s accepted the password\n",pserver));
+ 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;
+ }
-#ifndef KEEP_PASSWORD_SERVER_OPEN
- close(password_client); password_client= -1;
-#endif
+ DEBUG(3,("password server %s accepted the password\n", cli.desthost));
- return(True);
+ cli_tdis(&cli);
+
+ return(True);
}
diff --git a/source/smbd/pipes.c b/source/smbd/pipes.c
new file mode 100644
index 00000000000..e2f704e6af9
--- /dev/null
+++ b/source/smbd/pipes.c
@@ -0,0 +1,322 @@
+/*
+ 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 char magic_char;
+extern BOOL case_sensitive;
+extern pstring sesssetup_user;
+extern int Client;
+extern fstring myworkgroup;
+
+#define VALID_PNUM(pnum) (((pnum) >= 0) && ((pnum) < MAX_OPEN_PIPES))
+#define OPEN_PNUM(pnum) (VALID_PNUM(pnum) && Pipes[pnum].open)
+#define PNUM_OK(pnum,c) (OPEN_PNUM(pnum) && (c)==Pipes[pnum].cnum)
+
+/* this macro should always be used to extract an pnum (smb_fid) from
+ a packet to ensure chaining works correctly */
+#define GETPNUM(buf,where) (chain_pnum!= -1?chain_pnum:SVAL(buf,where))
+
+char * known_pipes [] =
+{
+ "lsarpc",
+#if NTDOMAIN
+ "NETLOGON",
+ "srvsvc",
+ "wkssvc",
+ "samr",
+#endif
+ NULL
+};
+
+/****************************************************************************
+ reply to an open and X on a named pipe
+
+ 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 pnum = -1;
+ int smb_ofun = SVAL(inbuf,smb_vwv8);
+ int size=0,fmode=0,mtime=0,rmode=0;
+ int i;
+
+ /* 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_ofun |= 0x10; /* Add Create it not exists flag */
+
+ pnum = open_rpc_pipe_hnd(fname, cnum);
+ if (pnum < 0) return(ERROR(ERRSRV,ERRnofids));
+
+ /* Prepare the reply */
+ set_message(outbuf,15,0,True);
+
+ /* 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, pnum + 0x800); /* mark file handle up into high range */
+ 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,0);
+
+ return chain_reply(inbuf,outbuf,length,bufsize);
+}
+
+
+/****************************************************************************
+ reply to a close
+****************************************************************************/
+int reply_pipe_close(char *inbuf,char *outbuf)
+{
+ int pnum = get_rpc_pipe_num(inbuf,smb_vwv0);
+ int cnum = SVAL(inbuf,smb_tid);
+ int outsize = set_message(outbuf,0,0,True);
+
+ DEBUG(5,("reply_pipe_close: pnum:%x cnum:%x\n", pnum, cnum));
+
+ if (!close_rpc_pipe_hnd(pnum, cnum)) return(ERROR(ERRDOS,ERRbadfid));
+
+ return(outsize);
+}
+
+
+/****************************************************************************
+ api_LsarpcSNPHS
+
+ SetNamedPipeHandleState on \PIPE\lsarpc.
+****************************************************************************/
+BOOL api_LsarpcSNPHS(int pnum, int cnum, char *param)
+{
+ uint16 id;
+
+ if (!param) return False;
+
+ id = param[0] + (param[1] << 8);
+ DEBUG(4,("lsarpc SetNamedPipeHandleState to code %x\n",id));
+
+ return set_rpc_pipe_hnd_state(pnum, cnum, id);
+}
+
+
+/****************************************************************************
+ 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..562d8fd5db5
--- /dev/null
+++ b/source/smbd/quotas.c
@@ -0,0 +1,664 @@
+#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);
+
+ seteuid(euser_id); /* Restore the original uid status. */
+
+ 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);
+
+ seteuid(euser_id); /* Restore the original uid status. */
+
+ 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
+ {
+ seteuid(euser_id); /* Restore the original uid status. */
+ 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..2c646d99f5b 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,99 @@ 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.
+*/
+ /* non-null user name indicates search by username not by smb userid */
+ smb_pass = get_smbpwd_entry(user, 0);
+
+ if (!smb_pass)
+ {
+ /* lkclXXXX: if workstation entry doesn't exist, indicate logon failure */
+ DEBUG(4,("Workstation trust account %s doesn't exist.",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_LOGON_FAILURE, 0xc000)); /* decimal 109 NT error, 0xc000 */
+ }
+ else
+ {
+ /* PAXX: This is the NO LOGON workstation trust account stuff */
+ /* lkclXXXX: if the workstation *does* exist, indicate failure differently! */
+ DEBUG(4,("No 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_NOLOGON_WORKSTATION_TRUST_ACCOUNT, 0xc000)); /* decimal 409 NT error, 0xc000 */
+ }
+
+ 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 +557,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 (!(lp_security() == SEC_SERVER && server_validate(inbuf)) &&
+ if(!guest && strequal(user,lp_guestaccount(-1)) && (*smb_apasswd == 0))
+ guest = True;
+
+ 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 +619,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 +642,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 +675,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 +688,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 +734,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 +753,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 +788,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 +809,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 +824,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 +898,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 +924,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 +975,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 +997,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 +1015,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 +1171,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 +1224,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 +1234,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 +1253,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 +1266,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 +1318,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 +1342,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 +1351,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 +1389,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 +1408,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));
+ }
+
+ 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(fnum,cnum,fname,O_RDWR | O_CREAT | O_TRUNC,unixmode);
+ /* 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 +1478,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 +1495,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 +1555,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 +1580,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 +1618,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 +1635,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 +1653,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 +1676,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 +1716,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 +1728,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 +1750,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 +1767,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 +1809,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 +1833,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 +1854,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 +1876,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 +1883,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 +1891,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 +1981,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 +1994,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 +2114,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 +2144,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 +2151,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 +2178,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 +2194,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 +2227,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);
@@ -1914,7 +2296,12 @@ int reply_close(char *inbuf,char *outbuf)
cnum = SVAL(inbuf,smb_tid);
+ /* If it's an IPC, pass off to the pipe handler. */
+ if (IS_IPC(cnum))
+ return reply_pipe_close(inbuf,outbuf);
+
fnum = GETFNUM(inbuf,smb_vwv0);
+
CHECK_FNUM(fnum,cnum);
if(HAS_CACHED_ERROR(fnum)) {
@@ -1924,17 +2311,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 +2359,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 +2397,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 +2429,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 +2440,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 +2476,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 +2534,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 +2557,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 +2570,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 +2593,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 +2606,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 +2649,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 +2670,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 +2735,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 +2761,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 +2831,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 +2949,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 +3024,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 +3071,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 +3140,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,20 +3152,29 @@ 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);
+ if (!can_rename(fname,cnum)) {
+ DEBUG(6,("rename %s refused\n", fname));
+ continue;
+ }
+ pstrcpy(destname,newname);
- if (!resolve_wildcards(fname,destname)) continue;
+ if (!resolve_wildcards(fname,destname)) {
+ DEBUG(6,("resolve_wildcards %s %s failed\n",
+ fname, destname));
+ continue;
+ }
if (file_exist(destname,NULL)) {
- error = 183;
- continue;
+ DEBUG(6,("file_exist %s\n",
+ destname));
+ error = 183;
+ continue;
}
if (!sys_rename(fname,destname)) count++;
DEBUG(3,("reply_mv : doing rename on %s -> %s\n",fname,destname));
@@ -2565,7 +3187,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 +3214,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 +3230,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 +3239,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 +3284,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 +3302,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 +3349,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 +3361,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 +3381,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 +3415,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 +3444,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 +3457,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 +3465,55 @@ 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)
+ {
+ /* Sanity check - ensure a pure oplock break is not a
+ chained request. */
+ if(CVAL(inbuf,smb_vwv0) != 0xff)
+ DEBUG(0,("reply_lockingX: Error : pure oplock break is a chained %d request !\n",
+ (unsigned int)CVAL(inbuf,smb_vwv0) ));
+ 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 +3545,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 +3565,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 +3589,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 +3604,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 +3636,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 +3825,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 +3874,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 +3901,3 @@ int reply_getattrE(char *inbuf,char *outbuf)
return(outsize);
}
-
-
-
-
-
diff --git a/source/smbd/server.c b/source/smbd/server.c
index 5d8facef33f..3f4f6c70347 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));
- Files[fnum].fd = sys_open(fname,flags,mode);
+ /* File was already open. */
+ if((flags & O_CREAT) && (flags & O_EXCL)) {
+ fd_ptr->ref_count--;
+ errno = EEXIST;
+ return;
+ }
+
+ /*
+ * 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;
+ }
+
+ } 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 ((Files[fnum].fd>=0) &&
+ 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,64 @@ 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);
+
+ if(fs_p->granted_oplock == True)
+ global_oplocks_open--;
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 +1492,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 +1540,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 +1636,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,fcbopen = %d, flags = %d) = %d\n",
+ deny_mode,old_deny_mode,old_open_mode,
+ share->pid,fname, fcbopen, *flags, 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 +1750,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 +1764,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 +1786,226 @@ 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(oplock_request && (num_share_modes == 0) && lp_oplocks(SNUM(cnum)) &&
+ !IS_VETO_OPLOCK_PATH(cnum,fname))
+ {
+ fs_p->granted_oplock = True;
+ global_oplocks_open++;
+ port = oplock_port;
- if (!share_pid)
- share_mode_pending = True;
+ DEBUG(5,("open_file_shared: granted oplock (%x) on file %s, \
+dev = %x, inode = %x\n", oplock_request, fname, dev, inode));
+
+ }
+ 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);
+ truncate_unless_locked(fnum,cnum,token,&share_locked);
}
-}
-
-
-/*******************************************************************
-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;
- }
- }
+ 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 +2014,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 +2033,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 +2093,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 +2199,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 +2220,6 @@ struct
{0,0,0}
};
-
/****************************************************************************
create an error packet from errno
****************************************************************************/
@@ -2063,15 +2239,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 +2296,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 +2322,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 +2332,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 +2357,760 @@ 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(3,("%s oplock_break: called for dev = %x, inode = %x. Current \
+global_oplocks_open = %d\n", timestring(), 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,("%s oplock_break: cannot find open file with dev = %x, inode = %x (fnum = %d) \
+allowing break to succeed.\n", timestring(), 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,("%s oplock_break: file %s (fnum = %d, dev = %x, inode = %x) has no oplock. \
+Allowing break to succeed regardless.\n", timestring(), 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);
+
+ /* We need this in case a readraw crosses on the wire. */
+ 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,("%s oplock_break: end of file from client\n", timestring()));
+
+ if (smb_read_error == READ_ERROR)
+ DEBUG(0,("%s oplock_break: receive_smb error (%s)\n",
+ timestring(), strerror(errno)));
+
+ if (smb_read_error == READ_TIMEOUT)
+ DEBUG(0,("%s oplock_break: receive_smb timed out after %d seconds.\n",
+ timestring(), OPLOCK_BREAK_TIMEOUT));
+
+ DEBUG(0,("%s oplock_break failed for file %s (fnum = %d, dev = %x, \
+inode = %x).\n", timestring(), fsp->name, fnum, dev, inode));
+ shutdown_server = True;
+ break;
+ }
+ process_smb(inbuf, outbuf);
+
+ /*
+ * Die if we go over the time limit.
+ */
+
+ if((time(NULL) - start_time) > OPLOCK_BREAK_TIMEOUT)
+ {
+ DEBUG(0,("%s oplock_break: no break received from client within \
+%d seconds.\n", timestring(), OPLOCK_BREAK_TIMEOUT));
+ DEBUG(0,("%s oplock_break failed for file %s (fnum = %d, dev = %x, \
+inode = %x).\n", timestring(), fsp->name, fnum, dev, inode));
+ shutdown_server = True;
+ break;
+ }
+ }
+
+ /* We need this in case a readraw crossed on the wire. */
+ if(global_oplock_break)
+ global_oplock_break = False;
+
+ /*
+ * If the client did not respond we must die.
+ */
+
+ if(shutdown_server)
+ {
+ DEBUG(0,("%s oplock_break: client failure in break - shutting down this smbd.\n",
+ timestring()));
+ 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(3,("%s oplock_break: returning success for fnum = %d, dev = %x, inode = %x. Current \
+global_oplocks_open = %d\n", timestring(), 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,("%s request_oplock_break: sending a oplock break message to pid %d on port %d \
+for dev = %x, inode = %x\n", timestring(), 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,("%s 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",
+ timestring(), 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 + OPLOCK_BREAK_TIMEOUT_FUDGEFACTOR) 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+OPLOCK_BREAK_TIMEOUT_FUDGEFACTOR) * 1000) == False)
+ {
+ if(smb_read_error == READ_TIMEOUT)
+ {
+ DEBUG(0,("%s request_oplock_break: no response received to oplock break request to \
+pid %d on port %d for dev = %x, inode = %x\n", timestring(), share_entry->pid,
+ share_entry->op_port, dev, inode));
+ /*
+ * This is a hack to make handling of failing clients more robust.
+ * If a oplock break response message is not received in the timeout
+ * period we may assume that the smbd servicing that client holding
+ * the oplock has died and the client changes were lost anyway, so
+ * we should continue to try and open the file.
+ */
+ break;
+ }
+ else
+ DEBUG(0,("%s 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", timestring, 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,("%s request_oplock_break: invalid message length received. Ignoring\n",
+ timestring()));
+ 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,("%s request_oplock_break: received other message whilst awaiting \
+oplock break response from pid %d on port %d for dev = %x, inode = %x.\n",
+ timestring(), 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,("%s request_oplock_break: broke oplock.\n", timestring()));
+
return True;
}
+/****************************************************************************
+Get the next SMB packet, doing the local message processing automatically.
+****************************************************************************/
+
+BOOL receive_next_smb(int smbfd, int oplockfd, char *inbuf, int bufsize, int timeout)
+{
+ BOOL got_smb = False;
+ BOOL ret;
+
+ do
+ {
+ ret = receive_message_or_smb(smbfd,oplockfd,inbuf,bufsize,
+ timeout,&got_smb);
+
+ if(ret && !got_smb)
+ {
+ /* Deal with oplock break requests from other smbd's. */
+ process_local_message(oplock_sock, inbuf, bufsize);
+ continue;
+ }
+ }
+ while(ret && !got_smb);
+
+ return ret;
+}
/****************************************************************************
check if a snum is in use
@@ -2276,10 +3134,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 +3157,8 @@ BOOL reload_services(BOOL test)
reopen_logs();
+ load_interfaces();
+
{
extern int Client;
if (Client != -1) {
@@ -2307,7 +3167,7 @@ BOOL reload_services(BOOL test)
}
}
- create_mangled_stack(lp_mangledstack());
+ reset_mangled_stack( lp_mangledstack() );
/* this forces service parameters to be flushed */
become_service(-1,True);
@@ -2322,13 +3182,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 +3196,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 +3212,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 +3252,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 +3279,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 +3389,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 +3408,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 +3418,30 @@ 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;
+ pcon->veto_oplock_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 +3449,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 +3465,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 +3473,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 +3504,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 +3525,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 +3544,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 +3558,27 @@ 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)));
+ set_namearray( &pcon->veto_oplock_list, lp_veto_oplocks(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 +3595,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 +3686,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 +3716,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 +3761,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;
+
+ 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);
- if (lp_readraw() && lp_writeraw())
- capabilities |= 1;
+ 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 +3921,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 +3960,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 +4007,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 +4024,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 +4031,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 +4040,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 +4054,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 +4068,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 +4084,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 +4099,10 @@ void close_cnum(int cnum, int uid)
Connections[cnum].ngroups = 0;
}
+ free_namearray(Connections[cnum].veto_list);
+ free_namearray(Connections[cnum].hide_list);
+ free_namearray(Connections[cnum].veto_oplock_list);
+
string_set(&Connections[cnum].user,"");
string_set(&Connections[cnum].dirpath,"");
string_set(&Connections[cnum].connectpath,"");
@@ -3229,7 +4127,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 +4138,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 +4199,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 +4212,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 +4272,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 +4295,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 +4338,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 +4355,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 +4365,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 +4430,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 +4444,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 +4459,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 +4487,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 +4585,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 +4654,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));
-
- /* and copy the data from the reply to the right spot */
- memcpy(outbuf2,obuf+smb_wct,outsize - smb_wct);
+ outsize2 = switch_message(smb_com2,inbuf2,outbuf2,size-chain_size,
+ bufsize-chain_size);
- /* free the allocated buffers */
- if (ibuf) free(ibuf-SMB_ALIGNMENT);
- if (obuf) free(obuf-SMB_ALIGNMENT);
+ /* 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;
- 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 +4759,13 @@ 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;
+ reset_chain_pnum();
bzero(outbuf,smb_size);
@@ -3875,24 +4789,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 +4818,120 @@ 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;
-
+ /* re-initialise the timezone */
+ TimeInit();
+
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;
+ }
+
+ /* 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 (msg_type == 0)
- show_msg(InBuffer);
+ if (Connections[i].num_files_open > 0 ||
+ (t-Connections[i].lastused)<deadtime)
+ allidle = False;
+ }
- 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 (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 +4941,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,15 +4959,36 @@ 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;
}
+ /* for RPC pipes */
+ init_rpc_pipe_hnd();
+
+#ifdef NTDOMAIN
+ /* for LSA handles */
+ init_lsa_policy_hnd();
+#endif
+
init_dptrs();
}
/****************************************************************************
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 +5008,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 +5048,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 +5065,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 +5119,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 +5149,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 +5171,62 @@ int main(int argc,char *argv[])
become_daemon();
}
- if (open_sockets(is_daemon,port))
- {
- /* possibly reload the services file. */
- reload_services(True);
+ if (!directory_exist(lp_lockdir(), NULL)) {
+ mkdir(lp_lockdir(), 0755);
+ }
- maxxmit = MIN(lp_maxxmit(),BUFFER_SIZE);
+ if (*pidFile)
+ {
+ int fd;
+ char buf[20];
- if (*lp_rootdir())
- {
- if (sys_chroot(lp_rootdir()) == 0)
- DEBUG(2,("%s changed root to %s\n",timestring(),lp_rootdir()));
- }
+ 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 (!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..0ca678b7682 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;
@@ -31,6 +30,8 @@ extern connection_struct Connections[];
extern files_struct Files[];
extern BOOL case_sensitive;
extern int Client;
+extern int oplock_sock;
+extern int smb_read_error;
/****************************************************************************
Send the required number of replies back.
@@ -41,13 +42,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 +70,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 +168,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 +186,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 +195,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 +237,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 +253,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 +288,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 +308,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 +321,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 +329,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 +340,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 +352,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 +370,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 +392,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 +411,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 +426,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 +444,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 +460,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 +472,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 +488,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 +506,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 +537,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 +574,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 +597,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 +646,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 +972,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 +989,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 +1062,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 +1116,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 +1145,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 +1154,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 +1183,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 +1216,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 +1241,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 +1252,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 +1281,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 +1304,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 +1343,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 +1381,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 +1482,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 +1590,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 +1689,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,13 +1704,19 @@ 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)
+ BOOL ret;
+
+ ret = receive_next_smb(Client,oplock_sock,inbuf,bufsize,
+ SMB_SECONDARY_WAIT);
+
+ if((ret && (CVAL(inbuf, smb_com) != SMBtranss2)) || !ret)
{
outsize = set_message(outbuf,0,0,True);
- DEBUG(2,("Invalid secondary trans2 packet\n"));
+ if(ret)
+ DEBUG(0,("reply_trans2: Invalid secondary trans2 packet\n"));
+ else
+ DEBUG(0,("reply_trans2: %s in getting secondary trans2 response.\n",
+ (smb_read_error == READ_ERROR) ? "error" : "timeout" ));
free(params);
free(data);
return(ERROR(ERRSRV,ERRerror));
@@ -1572,6 +1727,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..b36fa4df067
--- /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 = conn->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/ubiqx/COPYING.LIB b/source/ubiqx/COPYING.LIB
new file mode 100644
index 00000000000..8c8377da464
--- /dev/null
+++ b/source/ubiqx/COPYING.LIB
@@ -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/source/ubiqx/README.UBI b/source/ubiqx/README.UBI
new file mode 100644
index 00000000000..2c1c0430fb9
--- /dev/null
+++ b/source/ubiqx/README.UBI
@@ -0,0 +1,15 @@
+Thu Oct 16 11:07:18 CDT 1997
+
+Files in the samba/source/ubiqx 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.LIB. 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 more info and additional
+available modules.
+
+Chris Hertel
+Samba Team
+samba-bugs@samba.anu.edu.au
diff --git a/source/ubiqx/ubi_AVLtree.c b/source/ubiqx/ubi_AVLtree.c
new file mode 100644
index 00000000000..29ecc747408
--- /dev/null
+++ b/source/ubiqx/ubi_AVLtree.c
@@ -0,0 +1,689 @@
+/* ========================================================================== **
+ * ubi_AVLtree.c
+ *
+ * Copyright (C) 1991-1997 by Christopher R. Hertel
+ *
+ * Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ *
+ * This module provides an implementation of AVL height balanced binary
+ * trees. (Adelson-Velskii, Landis 1962)
+ *
+ * This file implements the core of the height-balanced (AVL) tree management
+ * routines. The header file, ubi_AVLtree.h, contains function prototypes
+ * for all "exported" functions.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * 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 2.4 1997/07/26 04:36:20 crh
+ * Andrew Leppard, aka "Grazgur", discovered that I still had my brains tied
+ * on backwards with respect to node deletion. I did some more digging and
+ * discovered that I was not changing the balance values correctly in the
+ * single rotation functions. Double rotation was working correctly because
+ * the formula for changing the balance values is the same for insertion or
+ * deletion. Not so for single rotation.
+ *
+ * I have tested the fix by loading the tree with over 44 thousand names,
+ * deleting 2,629 of them (all those in which the second character is 'u')
+ * and then walking the tree recursively to verify that the balance factor of
+ * each node is correct. Passed.
+ *
+ * Thanks Andrew!
+ *
+ * Also:
+ * + Changed ubi_TRUE and ubi_FALSE to ubi_trTRUE and ubi_trFALSE.
+ * + Rewrote the ubi_tr<func> macros because they weren't doing what I'd
+ * hoped they would do (see the bottom of the header file). They work now.
+ *
+ * Revision 2.3 1997/06/03 04:41:35 crh
+ * Changed TRUE and FALSE to ubi_TRUE and ubi_FALSE to avoid causing
+ * problems.
+ *
+ * Revision 2.2 1995/10/03 22:16:01 CRH
+ * Ubisized!
+ *
+ * Revision 2.1 95/03/09 23:45:59 CRH
+ * Added the ModuleID static string and function. These modules are now
+ * self-identifying.
+ *
+ * Revision 2.0 95/03/05 14:10:51 CRH
+ * This revision of ubi_AVLtree coincides with revision 2.0 of ubi_BinTree,
+ * and so includes all of the changes to that module. In addition, a bug in
+ * the node deletion process has been fixed.
+ *
+ * After rewriting the Locate() function in ubi_BinTree, I decided that it was
+ * time to overhaul this module. In the process, I discovered a bug related
+ * to node deletion. To fix the bug, I wrote function Debalance(). A quick
+ * glance will show that it is very similar to the Rebalance() function. In
+ * previous versions of this module, I tried to include the functionality of
+ * Debalance() within Rebalance(), with poor results.
+ *
+ * Revision 1.0 93/10/15 22:58:56 CRH
+ * With this revision, I have added a set of #define's that provide a single,
+ * standard API to all existing tree modules. Until now, each of the three
+ * existing modules had a different function and typedef prefix, as follows:
+ *
+ * Module Prefix
+ * ubi_BinTree ubi_bt
+ * ubi_AVLtree ubi_avl
+ * ubi_SplayTree ubi_spt
+ *
+ * To further complicate matters, only those portions of the base module
+ * (ubi_BinTree) that were superceeded in the new module had the new names.
+ * For example, if you were using ubi_AVLtree, the AVL node structure was
+ * named "ubi_avlNode", but the root structure was still "ubi_btRoot". Using
+ * SplayTree, the locate function was called "ubi_sptLocate", but the next
+ * and previous functions remained "ubi_btNext" and "ubi_btPrev".
+ *
+ * This was not too terrible if you were familiar with the modules and knew
+ * exactly which tree model you wanted to use. If you wanted to be able to
+ * change modules (for speed comparisons, etc), things could get messy very
+ * quickly.
+ *
+ * So, I have added a set of defined names that get redefined in any of the
+ * descendant modules. To use this standardized interface in your code,
+ * simply replace all occurances of "ubi_bt", "ubi_avl", and "ubi_spt" with
+ * "ubi_tr". The "ubi_tr" names will resolve to the correct function or
+ * datatype names for the module that you are using. Just remember to
+ * include the header for that module in your program file. Because these
+ * names are handled by the preprocessor, there is no added run-time
+ * overhead.
+ *
+ * Note that the original names do still exist, and can be used if you wish
+ * to write code directly to a specific module. This should probably only be
+ * done if you are planning to implement a new descendant type, such as
+ * red/black trees. CRH
+ *
+ * V0.0 - May, 1990 - Written by Christopher R. Hertel (CRH).
+ *
+ * ========================================================================= **
+ */
+
+#include "ubi_AVLtree.h" /* Header for THIS module. */
+#include <stdlib.h> /* Standard C definitions, etc. */
+
+/* ========================================================================== **
+ * Static data.
+ */
+
+static char ModuleID[] = "ubi_AVLtree\n\
+\tRevision: 2.4\n\
+\tDate: 1997/07/26 04:36:20\n\
+\tAuthor: crh\n";
+
+/* ========================================================================== **
+ * The next set of functions are the AVL balancing routines. There are left
+ * and right, single and double rotations. The rotation routines handle the
+ * rotations and reconnect all tree pointers that might get confused by the
+ * rotations. A pointer to the new subtree root node is returned.
+ *
+ * Note that L1 and R1 are identical, except that all the RIGHTs and LEFTs
+ * are reversed. The same is true for L2 and R2. I'm sure that there is
+ * a clever way to reduce the amount of code by combining these functions,
+ * but it might involve additional overhead, and it would probably be a pain
+ * to read, debug, etc.
+ * -------------------------------------------------------------------------- **
+ */
+
+static ubi_avlNodePtr L1( ubi_avlNodePtr p )
+ /* ------------------------------------------------------------------------ **
+ * Single rotate left.
+ *
+ * Input: p - Pointer to the root of a tree (possibly a subtree).
+ * Output: A pointer to the new root of the same subtree (now that node
+ * p has been moved).
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_avlNodePtr tmp;
+
+ tmp = p->Link[RIGHT];
+ p->Link[RIGHT] = tmp->Link[LEFT];
+ tmp->Link[LEFT] = p;
+
+ tmp->Link[PARENT] = p->Link[PARENT];
+ tmp->gender = p->gender;
+ if(tmp->Link[PARENT])
+ (tmp->Link[PARENT])->Link[(tmp->gender)] = tmp;
+ p->Link[PARENT] = tmp;
+ p->gender = LEFT;
+ if( p->Link[RIGHT] )
+ {
+ p->Link[RIGHT]->Link[PARENT] = p;
+ (p->Link[RIGHT])->gender = RIGHT;
+ }
+ p->balance -= Normalize( tmp->balance );
+ (tmp->balance)--;
+ return( tmp );
+ } /* L1 */
+
+static ubi_avlNodePtr R1( ubi_avlNodePtr p )
+ /* ------------------------------------------------------------------------ **
+ * Single rotate right.
+ *
+ * Input: p - Pointer to the root of a tree (possibly a subtree).
+ * Output: A pointer to the new root of the same subtree (now that node
+ * p has been moved).
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_avlNodePtr tmp;
+
+ tmp = p->Link[LEFT];
+ p->Link[LEFT] = tmp->Link[RIGHT];
+ tmp->Link[RIGHT] = p;
+
+ tmp->Link[PARENT] = p->Link[PARENT];
+ tmp->gender = p->gender;
+ if(tmp->Link[PARENT])
+ (tmp->Link[PARENT])->Link[(tmp->gender)] = tmp;
+ p->Link[PARENT] = tmp;
+ p->gender = RIGHT;
+ if(p->Link[LEFT])
+ {
+ p->Link[LEFT]->Link[PARENT] = p;
+ p->Link[LEFT]->gender = LEFT;
+ }
+ p->balance -= Normalize( tmp->balance );
+ (tmp->balance)++;
+ return( tmp );
+ } /* R1 */
+
+static ubi_avlNodePtr L2( ubi_avlNodePtr tree )
+ /* ------------------------------------------------------------------------ **
+ * Double rotate left.
+ *
+ * Input: p - Pointer to the root of a tree (possibly a subtree).
+ * Output: A pointer to the new root of the same subtree (now that node
+ * p has been moved).
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_avlNodePtr tmp, newroot;
+
+ tmp = tree->Link[RIGHT];
+ newroot = tmp->Link[LEFT];
+ tmp->Link[LEFT] = newroot->Link[RIGHT];
+ newroot->Link[RIGHT] = tmp;
+ tree->Link[RIGHT] = newroot->Link[LEFT];
+ newroot->Link[LEFT] = tree;
+
+ newroot->Link[PARENT] = tree->Link[PARENT];
+ newroot->gender = tree->gender;
+ tree->Link[PARENT] = newroot;
+ tree->gender = LEFT;
+ tmp->Link[PARENT] = newroot;
+ tmp->gender = RIGHT;
+
+ if( tree->Link[RIGHT] )
+ {
+ tree->Link[RIGHT]->Link[PARENT] = tree;
+ tree->Link[RIGHT]->gender = RIGHT;
+ }
+ if( tmp->Link[LEFT] )
+ {
+ tmp->Link[LEFT]->Link[PARENT] = tmp;
+ tmp->Link[LEFT]->gender = LEFT;
+ }
+ if(newroot->Link[PARENT])
+ newroot->Link[PARENT]->Link[newroot->gender] = newroot;
+
+ switch( newroot->balance )
+ {
+ case LEFT :
+ tree->balance = EQUAL; tmp->balance = RIGHT; break;
+ case EQUAL:
+ tree->balance = EQUAL; tmp->balance = EQUAL; break;
+ case RIGHT:
+ tree->balance = LEFT; tmp->balance = EQUAL; break;
+ }
+ newroot->balance = EQUAL;
+ return( newroot );
+ } /* L2 */
+
+static ubi_avlNodePtr R2( ubi_avlNodePtr tree )
+ /* ------------------------------------------------------------------------ **
+ * Double rotate right.
+ *
+ * Input: p - Pointer to the root of a tree (possibly a subtree).
+ * Output: A pointer to the new root of the same subtree (now that node
+ * p has been moved).
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_avlNodePtr tmp, newroot;
+
+ tmp = tree->Link[LEFT];
+ newroot = tmp->Link[RIGHT];
+ tmp->Link[RIGHT] = newroot->Link[LEFT];
+ newroot->Link[LEFT] = tmp;
+ tree->Link[LEFT] = newroot->Link[RIGHT];
+ newroot->Link[RIGHT] = tree;
+
+ newroot->Link[PARENT] = tree->Link[PARENT];
+ newroot->gender = tree->gender;
+ tree->Link[PARENT] = newroot;
+ tree->gender = RIGHT;
+ tmp->Link[PARENT] = newroot;
+ tmp->gender = LEFT;
+
+ if( tree->Link[LEFT] )
+ {
+ tree->Link[LEFT]->Link[PARENT] = tree;
+ tree->Link[LEFT]->gender = LEFT;
+ }
+ if( tmp->Link[RIGHT] )
+ {
+ tmp->Link[RIGHT]->Link[PARENT] = tmp;
+ tmp->Link[RIGHT]->gender = RIGHT;
+ }
+ if(newroot->Link[PARENT])
+ newroot->Link[PARENT]->Link[newroot->gender] = newroot;
+
+ switch( newroot->balance )
+ {
+ case LEFT :
+ tree->balance = RIGHT; tmp->balance = EQUAL; break;
+ case EQUAL :
+ tree->balance = EQUAL; tmp->balance = EQUAL; break;
+ case RIGHT :
+ tree->balance = EQUAL; tmp->balance = LEFT; break;
+ }
+ newroot->balance = EQUAL;
+ return( newroot );
+ } /* R2 */
+
+
+static ubi_avlNodePtr Adjust( ubi_avlNodePtr p, char LorR )
+ /* ------------------------------------------------------------------------ **
+ * Adjust the balance value at node *p. If necessary, rotate the subtree
+ * rooted at p.
+ *
+ * Input: p - A pointer to the node to be adjusted. One of the
+ * subtrees of this node has changed height, so the
+ * balance value at this node must be adjusted, possibly
+ * by rotating the tree at this node.
+ * LorR - Indicates the TALLER subtree.
+ *
+ * Output: A pointer to the (possibly new) root node of the subtree.
+ *
+ * Notes: This function may be called after a node has been added *or*
+ * deleted, so LorR indicates the TALLER subtree.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ if( p->balance != LorR )
+ p->balance += Normalize(LorR);
+ else
+ {
+ char tallerbal; /* Balance value of the root of the taller subtree of p. */
+
+ tallerbal = p->Link[LorR]->balance;
+ if( ( EQUAL == tallerbal ) || ( p->balance == tallerbal ) )
+ p = ( (LEFT==LorR) ? R1(p) : L1(p) ); /* single rotation */
+ else
+ p = ( (LEFT==LorR) ? R2(p) : L2(p) ); /* double rotation */
+ }
+ return( p );
+ } /* Adjust */
+
+static ubi_avlNodePtr Rebalance( ubi_avlNodePtr Root,
+ ubi_avlNodePtr subtree,
+ char LorR )
+ /* ------------------------------------------------------------------------ **
+ * Rebalance the tree following an insertion.
+ *
+ * Input: Root - A pointer to the root node of the whole tree.
+ * subtree - A pointer to the node that has just gained a new
+ * child.
+ * LorR - Gender of the child that has just been gained.
+ *
+ * Output: A pointer to the (possibly new) root of the AVL tree.
+ * Rebalancing the tree moves nodes around a bit, so the node
+ * that *was* the root, may not be the root when we're finished.
+ *
+ * Notes: Rebalance() must walk up the tree from where we are (which is
+ * where the latest change occurred), rebalancing the subtrees
+ * along the way. The rebalancing operation can stop if the
+ * change at the current subtree root won't affect the rest of
+ * the tree. In the case of an addition, if a subtree root's
+ * balance becomes EQUAL, then we know that the height of that
+ * subtree has not changed, so we can exit.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ while( subtree )
+ {
+ subtree = Adjust( subtree, LorR );
+ if( PARENT == subtree->gender )
+ return( subtree );
+ if( EQUAL == subtree->balance )
+ return( Root );
+ LorR = subtree->gender;
+ subtree = subtree->Link[PARENT];
+ }
+ return( Root );
+ } /* Rebalance */
+
+static ubi_avlNodePtr Debalance( ubi_avlNodePtr Root,
+ ubi_avlNodePtr subtree,
+ char LorR )
+ /* ------------------------------------------------------------------------ **
+ * Rebalance the tree following a deletion.
+ *
+ * Input: Root - A pointer to the root node of the whole tree.
+ * subtree - A pointer to the node who's child has just "left the
+ * nest".
+ * LorR - Gender of the child that left.
+ *
+ * Output: A pointer to the (possibly new) root of the AVL tree.
+ * Rebalancing the tree moves nodes around a bit, so the node
+ * that *was* the root, may not be the root when we're finished.
+ *
+ * Notes: Debalance() is subtly different from Rebalance() (above) in
+ * two respects.
+ * * When it calls Adjust(), it passes the *opposite* of LorR.
+ * This is because LorR, as passed into Debalance() indicates
+ * the shorter subtree. As we move up the tree, LorR is
+ * assigned the gender of the node that we are leaving (i.e.,
+ * the subtree that we just rebalanced).
+ * * We know that a subtree has not changed height if the
+ * balance becomes LEFT or RIGHT. This is the *opposite* of
+ * what happens in Rebalance().
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ while( subtree )
+ {
+ subtree = Adjust( subtree, RevWay(LorR) );
+ if( PARENT == subtree->gender )
+ return( subtree );
+ if( EQUAL != subtree->balance )
+ return( Root );
+ LorR = subtree->gender;
+ subtree = subtree->Link[PARENT];
+ }
+ return( Root );
+ } /* Debalance */
+
+
+/* -------------------------------------------------------------------------- **
+ * The next two functions are used for general tree manipulation. They are
+ * each slightly different from their ubi_BinTree counterparts.
+ * -------------------------------------------------------------------------- **
+ */
+
+static void ReplaceNode( ubi_avlNodePtr *parent,
+ ubi_avlNodePtr oldnode,
+ ubi_avlNodePtr newnode )
+ /* ------------------------------------------------------------------------ **
+ * Remove node oldnode from the tree, replacing it with node newnode.
+ *
+ * Input:
+ * parent - A pointer to he parent pointer of the node to be
+ * replaced. <parent> may point to the Link[] field of
+ * a parent node, or it may indicate the root pointer at
+ * the top of the tree.
+ * oldnode - A pointer to the node that is to be replaced.
+ * newnode - A pointer to the node that is to be installed in the
+ * place of <*oldnode>.
+ *
+ * Notes: Don't forget to free oldnode.
+ * The only difference between this function and the ubi_bt
+ * version is that the node size is sizeof( ubi_avlNode ), not
+ * sizeof( ubi_btNode ).
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ register int i;
+ register int avlNodeSize = sizeof( ubi_avlNode );
+
+ for( i = 0; i < avlNodeSize; i++ )
+ ((unsigned char *)newnode)[i] = ((unsigned char *)oldnode)[i];
+ (*parent) = newnode;
+
+ if(oldnode->Link[LEFT ] )
+ (oldnode->Link[LEFT ])->Link[PARENT] = newnode;
+ if(oldnode->Link[RIGHT] )
+ (oldnode->Link[RIGHT])->Link[PARENT] = newnode;
+ } /* ReplaceNode */
+
+static void SwapNodes( ubi_btRootPtr RootPtr,
+ ubi_avlNodePtr Node1,
+ ubi_avlNodePtr Node2 )
+ /* ------------------------------------------------------------------------ **
+ * This function swaps two nodes in the tree. Node1 will take the place of
+ * Node2, and Node2 will fill in the space left vacant by Node 1.
+ *
+ * Input:
+ * RootPtr - pointer to the tree header structure for this tree.
+ * Node1 - \
+ * > These are the two nodes which are to be swapped.
+ * Node2 - /
+ *
+ * Notes:
+ * This function does a three step swap, using a dummy node as a place
+ * holder. This function is used by ubi_avlRemove().
+ * The only difference between this function and its ubi_bt counterpart
+ * is that the nodes are ubi_avlNodes, not ubi_btNodes.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_avlNodePtr *Parent;
+ ubi_avlNode dummy;
+ ubi_avlNodePtr dummy_p = &dummy;
+
+ if( Node1->Link[PARENT] )
+ Parent = &((Node1->Link[PARENT])->Link[Node1->gender]);
+ else
+ Parent = (ubi_avlNodePtr *)&(RootPtr->root);
+ ReplaceNode( Parent, Node1, dummy_p );
+
+ if( Node2->Link[PARENT] )
+ Parent = &((Node2->Link[PARENT])->Link[Node2->gender]);
+ else
+ Parent = (ubi_avlNodePtr *)&(RootPtr->root);
+ ReplaceNode( Parent, Node2, Node1 );
+
+ if( dummy_p->Link[PARENT] )
+ Parent = &((dummy_p->Link[PARENT])->Link[dummy_p->gender]);
+ else
+ Parent = (ubi_avlNodePtr *)&(RootPtr->root);
+ ReplaceNode( Parent, dummy_p, Node2 );
+ } /* SwapNodes */
+
+
+/* ========================================================================== **
+ * Public, exported (ie. not static-ly declared) functions...
+ * -------------------------------------------------------------------------- **
+ */
+
+ubi_avlNodePtr ubi_avlInitNode( ubi_avlNodePtr NodePtr )
+ /* ------------------------------------------------------------------------ **
+ * Initialize a tree node.
+ *
+ * Input: NodePtr - pointer to a ubi_btNode structure to be
+ * initialized.
+ * Output: a pointer to the initialized ubi_avlNode structure (ie. the
+ * same as the input pointer).
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ (void)ubi_btInitNode( (ubi_btNodePtr)NodePtr );
+ NodePtr->balance = EQUAL;
+ return( NodePtr );
+ } /* ubi_avlInitNode */
+
+ubi_trBool ubi_avlInsert( ubi_btRootPtr RootPtr,
+ ubi_avlNodePtr NewNode,
+ ubi_btItemPtr ItemPtr,
+ ubi_avlNodePtr *OldNode )
+ /* ------------------------------------------------------------------------ **
+ * This function uses a non-recursive algorithm to add a new element to
+ * the tree.
+ *
+ * Input: RootPtr - a pointer to the ubi_btRoot structure that indicates
+ * the root of the tree to which NewNode is to be added.
+ * NewNode - a pointer to an ubi_avlNode structure that is NOT
+ * part of any tree.
+ * ItemPtr - A pointer to the sort key that is stored within
+ * *NewNode. ItemPtr MUST point to information stored
+ * in *NewNode or an EXACT DUPLICATE. The key data
+ * indicated by ItemPtr is used to place the new node
+ * into the tree.
+ * OldNode - a pointer to an ubi_btNodePtr. When searching
+ * the tree, a duplicate node may be found. If
+ * duplicates are allowed, then the new node will
+ * be simply placed into the tree. If duplicates
+ * are not allowed, however, then one of two things
+ * may happen.
+ * 1) if overwritting *is not* allowed, this
+ * function will return FALSE (indicating that
+ * the new node could not be inserted), and
+ * *OldNode will point to the duplicate that is
+ * still in the tree.
+ * 2) if overwritting *is* allowed, then this
+ * function will swap **OldNode for *NewNode.
+ * In this case, *OldNode will point to the node
+ * that was removed (thus allowing you to free
+ * the node).
+ * ** If you are using overwrite mode, ALWAYS **
+ * ** check the return value of this parameter! **
+ * Note: You may pass NULL in this parameter, the
+ * function knows how to cope. If you do this,
+ * however, there will be no way to return a
+ * pointer to an old (ie. replaced) node (which is
+ * a problem if you are using overwrite mode).
+ *
+ * Output: a boolean value indicating success or failure. The function
+ * will return FALSE if the node could not be added to the tree.
+ * Such failure will only occur if duplicates are not allowed,
+ * nodes cannot be overwritten, AND a duplicate key was found
+ * within the tree.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_avlNodePtr OtherP;
+
+ if( !(OldNode) ) OldNode = &OtherP;
+ if( ubi_btInsert( RootPtr,
+ (ubi_btNodePtr)NewNode,
+ ItemPtr,
+ (ubi_btNodePtr *)OldNode ) )
+ {
+ if( (*OldNode) )
+ NewNode->balance = (*OldNode)->balance;
+ else
+ {
+ NewNode->balance = EQUAL;
+ RootPtr->root = (ubi_btNodePtr)Rebalance( (ubi_avlNodePtr)RootPtr->root,
+ NewNode->Link[PARENT],
+ NewNode->gender );
+ }
+ return( ubi_trTRUE );
+ }
+ return( ubi_trFALSE ); /* Failure: could not replace an existing node. */
+ } /* ubi_avlInsert */
+
+ubi_avlNodePtr ubi_avlRemove( ubi_btRootPtr RootPtr,
+ ubi_avlNodePtr DeadNode )
+ /* ------------------------------------------------------------------------ **
+ * This function removes the indicated node from the tree, after which the
+ * tree is rebalanced.
+ *
+ * Input: RootPtr - A pointer to the header of the tree that contains
+ * the node to be removed.
+ * DeadNode - A pointer to the node that will be removed.
+ *
+ * Output: This function returns a pointer to the node that was removed
+ * from the tree (ie. the same as DeadNode).
+ *
+ * Note: The node MUST be in the tree indicated by RootPtr. If not,
+ * strange and evil things will happen to your trees.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_btNodePtr p,
+ *parentp;
+
+ /* if the node has both left and right subtrees, then we have to swap
+ * it with another node.
+ */
+ if( (DeadNode->Link[LEFT]) && (DeadNode->Link[RIGHT]) )
+ SwapNodes( RootPtr, DeadNode, ubi_trPrev( DeadNode ) );
+
+ /* The parent of the node to be deleted may be another node, or it may be
+ * the root of the tree. Since we're not sure, it's best just to have
+ * a pointer to the parent pointer, whatever it is.
+ */
+ if( DeadNode->Link[PARENT] )
+ parentp = (ubi_btNodePtr *)
+ &((DeadNode->Link[PARENT])->Link[(DeadNode->gender)]);
+ else
+ parentp = &( RootPtr->root );
+
+ /* Now link the parent to the only grand-child. Patch up the gender and
+ * such, and rebalance.
+ */
+ if( EQUAL == DeadNode->balance )
+ (*parentp) = NULL;
+ else
+ {
+ p = (ubi_btNodePtr)(DeadNode->Link[(DeadNode->balance)]);
+ p->Link[PARENT] = (ubi_btNodePtr)DeadNode->Link[PARENT];
+ p->gender = DeadNode->gender;
+ (*parentp) = p;
+ }
+ RootPtr->root = (ubi_btNodePtr)Debalance( (ubi_avlNodePtr)RootPtr->root,
+ DeadNode->Link[PARENT],
+ DeadNode->gender );
+
+ (RootPtr->count)--;
+ return( DeadNode );
+ } /* ubi_avlRemove */
+
+int ubi_avlModuleID( int size, char *list[] )
+ /* ------------------------------------------------------------------------ **
+ * Returns a set of strings that identify the module.
+ *
+ * Input: size - The number of elements in the array <list>.
+ * list - An array of pointers of type (char *). This array
+ * should, initially, be empty. This function will fill
+ * in the array with pointers to strings.
+ * Output: The number of elements of <list> that were used. If this value
+ * is less than <size>, the values of the remaining elements are
+ * not guaranteed.
+ *
+ * Notes: Please keep in mind that the pointers returned indicate strings
+ * stored in static memory. Don't free() them, don't write over
+ * them, etc. Just read them.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ if( size > 0 )
+ {
+ list[0] = ModuleID;
+ if( size > 1 )
+ return( 1 + ubi_btModuleID( --size, &(list[1]) ) );
+ return( 1 );
+ }
+ return( 0 );
+ } /* ubi_avlModuleID */
+
+/* ============================== The End ============================== */
diff --git a/source/ubiqx/ubi_AVLtree.h b/source/ubiqx/ubi_AVLtree.h
new file mode 100644
index 00000000000..b86f24a412b
--- /dev/null
+++ b/source/ubiqx/ubi_AVLtree.h
@@ -0,0 +1,331 @@
+#ifndef ubi_AVLtree_H
+#define ubi_AVLtree_H
+/* ========================================================================== **
+ * ubi_AVLtree.h
+ *
+ * Copyright (C) 1991-1997 by Christopher R. Hertel
+ *
+ * Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ *
+ * This module provides an implementation of AVL height balanced binary
+ * trees. (Adelson-Velskii, Landis 1962)
+ *
+ * This header file contains the basic AVL structure and pointer typedefs
+ * as well as the prototypes needed to access the functions in the AVL
+ * module ubi_AVLtree. The .c file implements the low-level height balancing
+ * routines that manage the AVL tree, plus all of the basic primops for
+ * adding, searching for, and deleting nodes.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * 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 2.4 1997/07/26 04:36:23 crh
+ * Andrew Leppard, aka "Grazgur", discovered that I still had my brains tied
+ * on backwards with respect to node deletion. I did some more digging and
+ * discovered that I was not changing the balance values correctly in the
+ * single rotation functions. Double rotation was working correctly because
+ * the formula for changing the balance values is the same for insertion or
+ * deletion. Not so for single rotation.
+ *
+ * I have tested the fix by loading the tree with over 44 thousand names,
+ * deleting 2,629 of them (all those in which the second character is 'u')
+ * and then walking the tree recursively to verify that the balance factor of
+ * each node is correct. Passed.
+ *
+ * Thanks Andrew!
+ *
+ * Also:
+ * + Changed ubi_TRUE and ubi_FALSE to ubi_trTRUE and ubi_trFALSE.
+ * + Rewrote the ubi_tr<func> macros because they weren't doing what I'd
+ * hoped they would do (see the bottom of the header file). They work now.
+ *
+ * Revision 2.3 1997/06/03 05:22:07 crh
+ * Changed TRUE and FALSE to ubi_TRUE and ubi_FALSE to avoid causing
+ * problems.
+ *
+ * Revision 2.2 1995/10/03 22:15:47 CRH
+ * Ubisized!
+ *
+ * Revision 2.1 95/03/09 23:46:44 CRH
+ * Added the ModuleID static string and function. These modules are now
+ * self-identifying.
+ *
+ * Revision 2.0 95/03/05 14:11:22 CRH
+ * This revision of ubi_AVLtree coincides with revision 2.0 of ubi_BinTree,
+ * and so includes all of the changes to that module. In addition, a bug in
+ * the node deletion process has been fixed.
+ *
+ * After rewriting the Locate() function in ubi_BinTree, I decided that it was
+ * time to overhaul this module. In the process, I discovered a bug related
+ * to node deletion. To fix the bug, I wrote function Debalance(). A quick
+ * glance will show that it is very similar to the Rebalance() function. In
+ * previous versions of this module, I tried to include the functionality of
+ * Debalance() within Rebalance(), with poor results.
+ *
+ * Revision 1.0 93/10/15 22:58:48 CRH
+ * With this revision, I have added a set of #define's that provide a single,
+ * standard API to all existing tree modules. Until now, each of the three
+ * existing modules had a different function and typedef prefix, as follows:
+ *
+ * Module Prefix
+ * ubi_BinTree ubi_bt
+ * ubi_AVLtree ubi_avl
+ * ubi_SplayTree ubi_spt
+ *
+ * To further complicate matters, only those portions of the base module
+ * (ubi_BinTree) that were superceeded in the new module had the new names.
+ * For example, if you were using ubi_AVLtree, the AVL node structure was
+ * named "ubi_avlNode", but the root structure was still "ubi_btRoot". Using
+ * SplayTree, the locate function was called "ubi_sptLocate", but the next
+ * and previous functions remained "ubi_btNext" and "ubi_btPrev".
+ *
+ * This was not too terrible if you were familiar with the modules and knew
+ * exactly which tree model you wanted to use. If you wanted to be able to
+ * change modules (for speed comparisons, etc), things could get messy very
+ * quickly.
+ *
+ * So, I have added a set of defined names that get redefined in any of the
+ * descendant modules. To use this standardized interface in your code,
+ * simply replace all occurances of "ubi_bt", "ubi_avl", and "ubi_spt" with
+ * "ubi_tr". The "ubi_tr" names will resolve to the correct function or
+ * datatype names for the module that you are using. Just remember to
+ * include the header for that module in your program file. Because these
+ * names are handled by the preprocessor, there is no added run-time
+ * overhead.
+ *
+ * Note that the original names do still exist, and can be used if you wish
+ * to write code directly to a specific module. This should probably only be
+ * done if you are planning to implement a new descendant type, such as
+ * red/black trees. CRH
+ *
+ * V0.0 - May, 1990 - Written by Christopher R. Hertel (CRH).
+ *
+ * ========================================================================= **
+ */
+
+#include "ubi_BinTree.h" /* Base erg binary tree support. */
+
+/* ------------------------------------------------------------------------- **
+ * AVL Tree Node Structure: This structure defines the basic elements of
+ * the AVL tree nodes. In general you *SHOULD NOT PLAY WITH THESE
+ * FIELDS*! But, of course, I have to put the structure into this
+ * header so that you can use the structure as a building block.
+ *
+ * The fields are as follows:
+ * Link - An array of pointers. These pointers are manipulated by the
+ * BT and AVL routines, and indicate the left and right child
+ * nodes, plus the parent node. By keeping track of the parent
+ * pointer, we avoid the need for recursive routines or hand-
+ * tooled stacks to keep track of our path back to the root.
+ * The use of these pointers is subject to change without
+ * notice.
+ * gender - For tree rebalancing purposes, it is necessary that each node
+ * know whether it is the left or right child of its parent, or
+ * if it is the root. This information is stored in this field.
+ * balance - This field is also needed for AVL balancing purposes. It
+ * indicates which subtree of the current node is longer, or if
+ * the subtrees are, in fact, balanced with respect to each
+ * other.
+ * ------------------------------------------------------------------------- **
+ */
+
+typedef struct ubi_avlNodeStruct {
+ struct ubi_avlNodeStruct
+ *Link[3]; /* Normal Binary Tree Node type. */
+ char gender; /* The node is either the RIGHT or LEFT child of its */
+ /* parent, or is the root node. */
+ char balance; /* In an AVL tree, each node is the root of a subtree */
+ /* that may be balanced, or be one node longer to the */
+ /* right or left. This field keeps track of the */
+ /* balance value of each node. */
+ } ubi_avlNode; /* Typedef'd name for an avl tree node. */
+
+typedef ubi_avlNode *ubi_avlNodePtr; /* a Pointer to an AVL node */
+
+/* -------------------------------------------------------------------------- **
+ * Function prototypes.
+ * -------------------------------------------------------------------------- **
+ */
+
+ubi_avlNodePtr ubi_avlInitNode( ubi_avlNodePtr NodePtr );
+ /* ------------------------------------------------------------------------ **
+ * Initialize a tree node.
+ *
+ * Input: NodePtr - a pointer to a ubi_btNode structure to be
+ * initialized.
+ * Output: a pointer to the initialized ubi_avlNode structure (ie. the
+ * same as the input pointer).
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_trBool ubi_avlInsert( ubi_btRootPtr RootPtr,
+ ubi_avlNodePtr NewNode,
+ ubi_btItemPtr ItemPtr,
+ ubi_avlNodePtr *OldNode );
+ /* ------------------------------------------------------------------------ **
+ * This function uses a non-recursive algorithm to add a new element to
+ * the tree.
+ *
+ * Input: RootPtr - a pointer to the ubi_btRoot structure that indicates
+ * the root of the tree to which NewNode is to be added.
+ * NewNode - a pointer to an ubi_avlNode structure that is NOT
+ * part of any tree.
+ * ItemPtr - A pointer to the sort key that is stored within
+ * *NewNode. ItemPtr MUST point to information stored
+ * in *NewNode or an EXACT DUPLICATE. The key data
+ * indicated by ItemPtr is used to place the new node
+ * into the tree.
+ * OldNode - a pointer to an ubi_btNodePtr. When searching
+ * the tree, a duplicate node may be found. If
+ * duplicates are allowed, then the new node will
+ * be simply placed into the tree. If duplicates
+ * are not allowed, however, then one of two things
+ * may happen.
+ * 1) if overwritting *is not* allowed, this
+ * function will return FALSE (indicating that
+ * the new node could not be inserted), and
+ * *OldNode will point to the duplicate that is
+ * still in the tree.
+ * 2) if overwritting *is* allowed, then this
+ * function will swap **OldNode for *NewNode.
+ * In this case, *OldNode will point to the node
+ * that was removed (thus allowing you to free
+ * the node).
+ * ** If you are using overwrite mode, ALWAYS **
+ * ** check the return value of this parameter! **
+ * Note: You may pass NULL in this parameter, the
+ * function knows how to cope. If you do this,
+ * however, there will be no way to return a
+ * pointer to an old (ie. replaced) node (which is
+ * a problem if you are using overwrite mode).
+ *
+ * Output: a boolean value indicating success or failure. The function
+ * will return FALSE if the node could not be added to the tree.
+ * Such failure will only occur if duplicates are not allowed,
+ * nodes cannot be overwritten, AND a duplicate key was found
+ * within the tree.
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_avlNodePtr ubi_avlRemove( ubi_btRootPtr RootPtr,
+ ubi_avlNodePtr DeadNode );
+ /* ------------------------------------------------------------------------ **
+ * This function removes the indicated node from the tree, after which the
+ * tree is rebalanced.
+ *
+ * Input: RootPtr - A pointer to the header of the tree that contains
+ * the node to be removed.
+ * DeadNode - A pointer to the node that will be removed.
+ *
+ * Output: This function returns a pointer to the node that was removed
+ * from the tree (ie. the same as DeadNode).
+ *
+ * Note: The node MUST be in the tree indicated by RootPtr. If not,
+ * strange and evil things will happen to your trees.
+ * ------------------------------------------------------------------------ **
+ */
+
+int ubi_avlModuleID( int size, char *list[] );
+ /* ------------------------------------------------------------------------ **
+ * Returns a set of strings that identify the module.
+ *
+ * Input: size - The number of elements in the array <list>.
+ * list - An array of pointers of type (char *). This array
+ * should, initially, be empty. This function will fill
+ * in the array with pointers to strings.
+ * Output: The number of elements of <list> that were used. If this value
+ * is less than <size>, the values of the remaining elements are
+ * not guaranteed.
+ *
+ * Notes: Please keep in mind that the pointers returned indicate strings
+ * stored in static memory. Don't free() them, don't write over
+ * them, etc. Just read them.
+ * ------------------------------------------------------------------------ **
+ */
+
+/* -------------------------------------------------------------------------- **
+ * Masquarade...
+ *
+ * This set of defines allows you to write programs that will use any of the
+ * implemented binary tree modules (currently BinTree, AVLtree, and SplayTree).
+ * Instead of using ubi_avl... or ubi_bt, use ubi_tr... and select the tree
+ * type by including the appropriate module header.
+ */
+
+#undef ubi_trNode
+#undef ubi_trNodePtr
+#define ubi_trNode ubi_avlNode
+#define ubi_trNodePtr ubi_avlNodePtr
+
+#undef ubi_trInitNode
+#define ubi_trInitNode( Np ) ubi_avlInitNode( (ubi_avlNodePtr)(Np) )
+
+#undef ubi_trInsert
+#define ubi_trInsert( Rp, Nn, Ip, On ) \
+ ubi_avlInsert( (ubi_btRootPtr)(Rp), (ubi_avlNodePtr)(Nn), \
+ (ubi_btItemPtr)(Ip), (ubi_avlNodePtr *)(On) )
+
+#undef ubi_trRemove
+#define ubi_trRemove( Rp, Dn ) \
+ ubi_avlRemove( (ubi_btRootPtr)(Rp), (ubi_avlNodePtr)(Dn) )
+
+#undef ubi_trLocate
+#define ubi_trLocate( Rp, Ip, Op ) \
+ (ubi_avlNodePtr)ubi_btLocate( (ubi_btRootPtr)(Rp), \
+ (ubi_btItemPtr)(Ip), \
+ (ubi_trCompOps)(Op) )
+
+#undef ubi_trFind
+#define ubi_trFind( Rp, Ip ) \
+ (ubi_avlNodePtr)ubi_btFind( (ubi_btRootPtr)(Rp), (ubi_btItemPtr)(Ip) )
+
+#undef ubi_trNext
+#define ubi_trNext( P ) (ubi_avlNodePtr)ubi_btNext( (ubi_btNodePtr)(P) )
+
+#undef ubi_trPrev
+#define ubi_trPrev( P ) (ubi_avlNodePtr)ubi_btPrev( (ubi_btNodePtr)(P) )
+
+#undef ubi_trFirst
+#define ubi_trFirst( P ) (ubi_avlNodePtr)ubi_btFirst( (ubi_btNodePtr)(P) )
+
+#undef ubi_trLast
+#define ubi_trLast( P ) (ubi_avlNodePtr)ubi_btLast( (ubi_btNodePtr)(P) )
+
+#undef ubi_trFirstOf
+#define ubi_trFirstOf( Rp, Ip, P ) \
+ (ubi_avlNodePtr)ubi_btFirstOf( (ubi_btRootPtr)(Rp), \
+ (ubi_btItemPtr)(Ip), \
+ (ubi_btNodePtr)(P) )
+
+#undef ubi_trLastOf
+#define ubi_trLastOf( Rp, Ip, P ) \
+ (ubi_avlNodePtr)ubi_btLastOf( (ubi_btRootPtr)(Rp), \
+ (ubi_btItemPtr)(Ip), \
+ (ubi_btNodePtr)(P) )
+
+#undef ubi_trLeafNode
+#define ubi_trLeafNode( Nd ) \
+ (ubi_avlNodePtr)ubi_btLeafNode( (ubi_btNodePtr)(Nd) )
+
+#undef ubi_trModuleID
+#define ubi_trModuleID( s, l ) ubi_avlModuleID( s, l )
+
+
+/* =========================== End ubi_AVLtree.h =========================== */
+#endif /* ubi_AVLtree_H */
diff --git a/source/ubiqx/ubi_BinTree.c b/source/ubiqx/ubi_BinTree.c
new file mode 100644
index 00000000000..68e819a14b2
--- /dev/null
+++ b/source/ubiqx/ubi_BinTree.c
@@ -0,0 +1,1032 @@
+/* ========================================================================== **
+ * ubi_BinTree.c
+ *
+ * Copyright (C) 1991-1997 by Christopher R. Hertel
+ *
+ * Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ *
+ * ubi_BinTree manages a simple binary tree. Nothing fancy here. No height
+ * balancing, no restructuring. Still, a good tool for creating short, low-
+ * overhead sorted lists of things that need to be found in a hurry.
+ *
+ * In addition, this module provides a good basis for creating other types
+ * of binary tree handling modules.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * 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 2.4 1997/07/26 04:11:10 crh
+ * + Just to be annoying I changed ubi_TRUE and ubi_FALSE to ubi_trTRUE
+ * and ubi_trFALSE.
+ * + There is now a type ubi_trBool to go with ubi_trTRUE and ubi_trFALSE.
+ * + There used to be something called "ubi_TypeDefs.h". I got rid of it.
+ * + Added function ubi_btLeafNode().
+ *
+ * Revision 2.3 1997/06/03 05:16:17 crh
+ * Changed TRUE and FALSE to ubi_TRUE and ubi_FALSE to avoid conflicts.
+ * Also changed the interface to function InitTree(). See the comments
+ * for this function for more information.
+ *
+ * Revision 2.2 1995/10/03 22:00:07 CRH
+ * Ubisized!
+ *
+ * Revision 2.1 95/03/09 23:37:10 CRH
+ * Added the ModuleID static string and function. These modules are now
+ * self-identifying.
+ *
+ * Revision 2.0 95/02/27 22:00:17 CRH
+ * Revision 2.0 of this program includes the following changes:
+ *
+ * 1) A fix to a major typo in the RepaceNode() function.
+ * 2) The addition of the static function Border().
+ * 3) The addition of the public functions FirstOf() and LastOf(), which
+ * use Border(). These functions are used with trees that allow
+ * duplicate keys.
+ * 4) A complete rewrite of the Locate() function. Locate() now accepts
+ * a "comparison" operator.
+ * 5) Overall enhancements to both code and comments.
+ *
+ * I decided to give this a new major rev number because the interface has
+ * changed. In particular, there are two new functions, and changes to the
+ * Locate() function.
+ *
+ * Revision 1.0 93/10/15 22:44:59 CRH
+ * With this revision, I have added a set of #define's that provide a single,
+ * standard API to all existing tree modules. Until now, each of the three
+ * existing modules had a different function and typedef prefix, as follows:
+ *
+ * Module Prefix
+ * ubi_BinTree ubi_bt
+ * ubi_AVLtree ubi_avl
+ * ubi_SplayTree ubi_spt
+ *
+ * To further complicate matters, only those portions of the base module
+ * (ubi_BinTree) that were superceeded in the new module had the new names.
+ * For example, if you were using ubi_AVLtree, the AVL node structure was
+ * named "ubi_avlNode", but the root structure was still "ubi_btRoot". Using
+ * SplayTree, the locate function was called "ubi_sptLocate", but the next
+ * and previous functions remained "ubi_btNext" and "ubi_btPrev".
+ *
+ * This was not too terrible if you were familiar with the modules and knew
+ * exactly which tree model you wanted to use. If you wanted to be able to
+ * change modules (for speed comparisons, etc), things could get messy very
+ * quickly.
+ *
+ * So, I have added a set of defined names that get redefined in any of the
+ * descendant modules. To use this standardized interface in your code,
+ * simply replace all occurances of "ubi_bt", "ubi_avl", and "ubi_spt" with
+ * "ubi_tr". The "ubi_tr" names will resolve to the correct function or
+ * datatype names for the module that you are using. Just remember to
+ * include the header for that module in your program file. Because these
+ * names are handled by the preprocessor, there is no added run-time
+ * overhead.
+ *
+ * Note that the original names do still exist, and can be used if you wish
+ * to write code directly to a specific module. This should probably only be
+ * done if you are planning to implement a new descendant type, such as
+ * red/black trees. CRH
+ *
+ * V0.0 - June, 1991 - Written by Christopher R. Hertel (CRH).
+ *
+ * ========================================================================== **
+ */
+
+#include "ubi_BinTree.h" /* Header for this module */
+#include <stdlib.h> /* Standard C definitions. */
+
+/* ========================================================================== **
+ * Static data.
+ */
+
+static char ModuleID[] = "ubi_BinTree\n\
+\tRevision: 2.4\n\
+\tDate: 1997/07/26 04:11:10\n\
+\tAuthor: crh\n";
+
+/* ========================================================================== **
+ * Internal (private) functions.
+ */
+
+static ubi_btNodePtr qFind( ubi_btCompFunc cmp,
+ ubi_btItemPtr FindMe,
+ register ubi_btNodePtr p )
+ /* ------------------------------------------------------------------------ **
+ * This function performs a non-recursive search of a tree for a node
+ * matching a specific key. It is called "qFind()" because it is
+ * faster that TreeFind (below).
+ *
+ * Input:
+ * cmp - a pointer to the tree's comparison function.
+ * FindMe - a pointer to the key value for which to search.
+ * p - a pointer to the starting point of the search. <p>
+ * is considered to be the root of a subtree, and only
+ * the subtree will be searched.
+ *
+ * Output:
+ * A pointer to a node with a key that matches the key indicated by
+ * FindMe, or NULL if no such node was found.
+ *
+ * Note: In a tree that allows duplicates, the pointer returned *might
+ * not* point to the (sequentially) first occurance of the
+ * desired key.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ char tmp;
+
+ while( p && (( tmp = AbNormal((*cmp)(FindMe, p)) ) != EQUAL) )
+ p = p->Link[tmp];
+
+ return( p );
+ } /* qFind */
+
+static ubi_btNodePtr TreeFind( ubi_btItemPtr findme,
+ ubi_btNodePtr p,
+ ubi_btNodePtr *parentp,
+ char *gender,
+ ubi_btCompFunc CmpFunc )
+ /* ------------------------------------------------------------------------ **
+ * TreeFind() searches a tree for a given value (findme). It will return a
+ * pointer to the target node, if found, or NULL if the target node was not
+ * found.
+ *
+ * TreeFind() also returns, via parameters, a pointer to the parent of the
+ * target node, and a LEFT or RIGHT value indicating which child of the
+ * parent is the target node. *If the target is not found*, then these
+ * values indicate the place at which the target *should be found*. This
+ * is useful when inserting a new node into a tree or searching for nodes
+ * "near" the target node.
+ *
+ * The parameters are:
+ *
+ * findme - is a pointer to the key information to be searched for.
+ * p - points to the root of the tree to be searched.
+ * parentp - will return a pointer to a pointer to the !parent! of the
+ * target node, which can be especially usefull if the target
+ * was not found.
+ * gender - returns LEFT or RIGHT to indicate which child of *parentp
+ * was last searched.
+ * CmpFunc - points to the comparison function.
+ *
+ * This function is called by ubi_btLocate() and ubi_btInsert().
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ register ubi_btNodePtr tmp_p = p;
+ ubi_btNodePtr tmp_pp = NULL;
+ char tmp_sex = EQUAL;
+ char tmp_cmp;
+
+ while( tmp_p && (EQUAL != (tmp_cmp = AbNormal((*CmpFunc)(findme, tmp_p)))) )
+ {
+ tmp_pp = tmp_p; /* Keep track of previous node. */
+ tmp_sex = tmp_cmp; /* Keep track of sex of child. */
+ tmp_p = tmp_p->Link[tmp_cmp]; /* Go to child. */
+ }
+ *parentp = tmp_pp; /* Return results. */
+ *gender = tmp_sex;
+ return( tmp_p );
+ } /* TreeFind */
+
+static void ReplaceNode( ubi_btNodePtr *parent,
+ ubi_btNodePtr oldnode,
+ ubi_btNodePtr newnode )
+ /* ------------------------------------------------------------------ *
+ * Remove node oldnode from the tree, replacing it with node newnode.
+ *
+ * Input:
+ * parent - A pointer to he parent pointer of the node to be
+ * replaced. <parent> may point to the Link[] field of
+ * a parent node, or it may indicate the root pointer at
+ * the top of the tree.
+ * oldnode - A pointer to the node that is to be replaced.
+ * newnode - A pointer to the node that is to be installed in the
+ * place of <*oldnode>.
+ *
+ * Notes: Don't forget to free oldnode.
+ * Also, this function used to have a really nasty typo
+ * bug. "oldnode" and "newnode" were swapped in the line
+ * that now reads:
+ * ((unsigned char *)newnode)[i] = ((unsigned char *)oldnode)[i];
+ * Bleah!
+ * ------------------------------------------------------------------ *
+ */
+ {
+ register int i;
+ register int btNodeSize = sizeof( ubi_btNode );
+
+ for( i = 0; i < btNodeSize; i++ ) /* Copy node internals to new node. */
+ ((unsigned char *)newnode)[i] = ((unsigned char *)oldnode)[i];
+ (*parent) = newnode; /* Old node's parent points to new child. */
+ /* Now tell the children about their new step-parent. */
+ if( oldnode->Link[LEFT ] ) (oldnode->Link[LEFT ])->Link[PARENT] = newnode;
+ if( oldnode->Link[RIGHT] ) (oldnode->Link[RIGHT])->Link[PARENT] = newnode;
+ } /* ReplaceNode */
+
+static void SwapNodes( ubi_btRootPtr RootPtr,
+ ubi_btNodePtr Node1,
+ ubi_btNodePtr Node2 )
+ /* ------------------------------------------------------------------------ **
+ * This function swaps two nodes in the tree. Node1 will take the place of
+ * Node2, and Node2 will fill in the space left vacant by Node 1.
+ *
+ * Input:
+ * RootPtr - pointer to the tree header structure for this tree.
+ * Node1 - \
+ * > These are the two nodes which are to be swapped.
+ * Node2 - /
+ *
+ * Notes:
+ * This function does a three step swap, using a dummy node as a place
+ * holder. This function is used by ubi_btRemove().
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_btNodePtr *Parent;
+ ubi_btNode dummy;
+ ubi_btNodePtr dummy_p = &dummy;
+
+ /* Replace Node 1 with the dummy, thus removing Node1 from the tree. */
+ if( Node1->Link[PARENT] )
+ Parent = &((Node1->Link[PARENT])->Link[Node1->gender]);
+ else
+ Parent = &(RootPtr->root);
+ ReplaceNode( Parent, Node1, dummy_p );
+
+ /* Swap Node 1 with Node 2, placing Node 1 back into the tree. */
+ if( Node2->Link[PARENT] )
+ Parent = &((Node2->Link[PARENT])->Link[Node2->gender]);
+ else
+ Parent = &(RootPtr->root);
+ ReplaceNode( Parent, Node2, Node1 );
+
+ /* Swap Node 2 and the dummy, thus placing Node 2 back into the tree. */
+ if( dummy_p->Link[PARENT] )
+ Parent = &((dummy_p->Link[PARENT])->Link[dummy_p->gender]);
+ else
+ Parent = &(RootPtr->root);
+ ReplaceNode( Parent, dummy_p, Node2 );
+ } /* SwapNodes */
+
+/* -------------------------------------------------------------------------- **
+ * These routines allow you to walk through the tree, forwards or backwards.
+ */
+
+static ubi_btNodePtr SubSlide( register ubi_btNodePtr P,
+ register char whichway )
+ /* ------------------------------------------------------------------------ **
+ * Slide down the side of a subtree.
+ *
+ * Given a starting node, this function returns a pointer to the LEFT-, or
+ * RIGHT-most descendent, *or* (if whichway is PARENT) to the tree root.
+ *
+ * Input: P - a pointer to a starting place.
+ * whichway - the direction (LEFT, RIGHT, or PARENT) in which to
+ * travel.
+ * Output: A pointer to a node that is either the root, or has no
+ * whichway-th child but is within the subtree of P. Note that
+ * the return value may be the same as P. The return value *will
+ * be* NULL if P is NULL.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_btNodePtr Q = NULL;
+
+ while( P )
+ {
+ Q = P;
+ P = P->Link[ whichway ];
+ }
+ return( Q );
+ } /* SubSlide */
+
+static ubi_btNodePtr Neighbor( register ubi_btNodePtr P,
+ register char whichway )
+ /* ------------------------------------------------------------------------ **
+ * Given starting point p, return the (key order) next or preceeding node
+ * in the tree.
+ *
+ * Input: P - Pointer to our starting place node.
+ * whichway - the direction in which to travel to find the
+ * neighbor, i.e., the RIGHT neighbor or the LEFT
+ * neighbor.
+ *
+ * Output: A pointer to the neighboring node, or NULL if P was NULL.
+ *
+ * Notes: If whichway is PARENT, the results are unpredictable.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ if( P )
+ {
+ if( P->Link[ whichway ] )
+ return( SubSlide( P->Link[ whichway ], (char)RevWay(whichway) ) );
+ else
+ while( P->Link[ PARENT ] )
+ {
+ if( (P->Link[ PARENT ])->Link[ whichway ] == P )
+ P = P->Link[ PARENT ];
+ else
+ return( P->Link[ PARENT ] );
+ }
+ }
+ return( NULL );
+ } /* Neighbor */
+
+static ubi_btNodePtr Border( ubi_btRootPtr RootPtr,
+ ubi_btItemPtr FindMe,
+ ubi_btNodePtr p,
+ char whichway )
+ /* ------------------------------------------------------------------------ **
+ * Given starting point p, which has a key value equal to *FindMe, locate
+ * the first (index order) node with the same key value.
+ *
+ * This function is useful in trees that have can have duplicate keys.
+ * For example, consider the following tree:
+ * Tree Traversal
+ * 2 If <p> points to the root and <whichway> is RIGHT, 3
+ * / \ then the return value will be a pointer to the / \
+ * 2 2 RIGHT child of the root node. The tree on 2 5
+ * / / \ the right shows the order of traversal. / / \
+ * 1 2 3 1 4 6
+ *
+ * Input: RootPtr - Pointer to the tree root structure.
+ * FindMe - Key value for comparisons.
+ * p - Pointer to the starting-point node.
+ * whichway - the direction in which to travel to find the
+ * neighbor, i.e., the RIGHT neighbor or the LEFT
+ * neighbor.
+ *
+ * Output: A pointer to the first (index, or "traversal", order) node with
+ * a Key value that matches *FindMe.
+ *
+ * Notes: If whichway is PARENT, or if the tree does not allow duplicate
+ * keys, this function will return <p>.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ register ubi_btNodePtr q;
+
+ /* Exit if there's nothing that can be done. */
+ if( !Dups_OK( RootPtr ) || (PARENT == whichway) )
+ return( p );
+
+ /* First, if needed, move up the tree. We need to get to the root of the
+ * subtree that contains all of the matching nodes.
+ */
+ q = p->Link[PARENT];
+ while( q && (EQUAL == AbNormal( (*(RootPtr->cmp))(FindMe, q) )) )
+ {
+ p = q;
+ q = p->Link[PARENT];
+ }
+
+ /* Next, move back down in the "whichway" direction. */
+ q = p->Link[whichway];
+ while( q )
+ {
+ if( q = qFind( RootPtr->cmp, FindMe, q ) )
+ {
+ p = q;
+ q = p->Link[whichway];
+ }
+ }
+ return( p );
+ } /* Border */
+
+
+/* ========================================================================== **
+ * Exported utilities.
+ */
+
+long ubi_btSgn( register long x )
+ /* ------------------------------------------------------------------------ **
+ * Return the sign of x; {negative,zero,positive} ==> {-1, 0, 1}.
+ *
+ * Input: x - a signed long integer value.
+ *
+ * Output: the "sign" of x, represented as follows:
+ * -1 == negative
+ * 0 == zero (no sign)
+ * 1 == positive
+ *
+ * Note: This utility is provided in order to facilitate the conversion
+ * of C comparison function return values into BinTree direction
+ * values: {LEFT, PARENT, EQUAL}. It is INCORPORATED into the
+ * AbNormal() conversion macro!
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ return( (x)?((x>0)?(1):(-1)):(0) );
+ } /* ubi_btSgn */
+
+ubi_btNodePtr ubi_btInitNode( ubi_btNodePtr NodePtr )
+ /* ------------------------------------------------------------------------ **
+ * Initialize a tree node.
+ *
+ * Input: a pointer to a ubi_btNode structure to be initialized.
+ * Output: a pointer to the initialized ubi_btNode structure (ie. the
+ * same as the input pointer).
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ NodePtr->Link[ LEFT ] = NULL;
+ NodePtr->Link[ PARENT ] = NULL;
+ NodePtr->Link[ RIGHT ] = NULL;
+ NodePtr->gender = EQUAL;
+ return( NodePtr );
+ } /* ubi_btInitNode */
+
+ubi_btRootPtr ubi_btInitTree( ubi_btRootPtr RootPtr,
+ ubi_btCompFunc CompFunc,
+ unsigned char Flags )
+ /* ------------------------------------------------------------------------ **
+ * Initialize the fields of a Tree Root header structure.
+ *
+ * Input: RootPtr - a pointer to an ubi_btRoot structure to be
+ * initialized.
+ * CompFunc - a pointer to a comparison function that will be used
+ * whenever nodes in the tree must be compared against
+ * outside values.
+ * Flags - One bytes worth of flags. Flags include
+ * ubi_trOVERWRITE and ubi_trDUPKEY. See the header
+ * file for more info.
+ *
+ * Output: a pointer to the initialized ubi_btRoot structure (ie. the
+ * same value as RootPtr).
+ *
+ * Note: The interface to this function has changed from that of
+ * previous versions. The <Flags> parameter replaces two
+ * boolean parameters that had the same basic effect.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ if( RootPtr )
+ {
+ RootPtr->root = NULL;
+ RootPtr->count = 0L;
+ RootPtr->cmp = CompFunc;
+ RootPtr->flags = (Flags & ubi_trDUPKEY) ? ubi_trDUPKEY : Flags;
+ } /* There are only two supported flags, and they are
+ * mutually exclusive. ubi_trDUPKEY takes precedence
+ * over ubi_trOVERWRITE.
+ */
+ return( RootPtr );
+ } /* ubi_btInitTree */
+
+ubi_trBool ubi_btInsert( ubi_btRootPtr RootPtr,
+ ubi_btNodePtr NewNode,
+ ubi_btItemPtr ItemPtr,
+ ubi_btNodePtr *OldNode )
+ /* ------------------------------------------------------------------------ **
+ * This function uses a non-recursive algorithm to add a new element to the
+ * tree.
+ *
+ * Input: RootPtr - a pointer to the ubi_btRoot structure that indicates
+ * the root of the tree to which NewNode is to be added.
+ * NewNode - a pointer to an ubi_btNode structure that is NOT
+ * part of any tree.
+ * ItemPtr - A pointer to the sort key that is stored within
+ * *NewNode. ItemPtr MUST point to information stored
+ * in *NewNode or an EXACT DUPLICATE. The key data
+ * indicated by ItemPtr is used to place the new node
+ * into the tree.
+ * OldNode - a pointer to an ubi_btNodePtr. When searching
+ * the tree, a duplicate node may be found. If
+ * duplicates are allowed, then the new node will
+ * be simply placed into the tree. If duplicates
+ * are not allowed, however, then one of two things
+ * may happen.
+ * 1) if overwritting *is not* allowed, this
+ * function will return FALSE (indicating that
+ * the new node could not be inserted), and
+ * *OldNode will point to the duplicate that is
+ * still in the tree.
+ * 2) if overwritting *is* allowed, then this
+ * function will swap **OldNode for *NewNode.
+ * In this case, *OldNode will point to the node
+ * that was removed (thus allowing you to free
+ * the node).
+ * ** If you are using overwrite mode, ALWAYS **
+ * ** check the return value of this parameter! **
+ * Note: You may pass NULL in this parameter, the
+ * function knows how to cope. If you do this,
+ * however, there will be no way to return a
+ * pointer to an old (ie. replaced) node (which is
+ * a problem if you are using overwrite mode).
+ *
+ * Output: a boolean value indicating success or failure. The function
+ * will return FALSE if the node could not be added to the tree.
+ * Such failure will only occur if duplicates are not allowed,
+ * nodes cannot be overwritten, AND a duplicate key was found
+ * within the tree.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_btNodePtr OtherP,
+ parent = NULL;
+ char tmp;
+
+ if( !(OldNode) ) /* If they didn't give us a pointer, supply our own. */
+ OldNode = &OtherP;
+
+ (void)ubi_btInitNode( NewNode ); /* Init the new node's BinTree fields. */
+
+ /* Find a place for the new node. */
+ *OldNode = TreeFind(ItemPtr, (RootPtr->root), &parent, &tmp, (RootPtr->cmp));
+
+ /* Now add the node to the tree... */
+ if (!(*OldNode)) /* The easy one: we have a space for a new node! */
+ {
+ if (!(parent))
+ RootPtr->root = NewNode;
+ else
+ {
+ parent->Link[tmp] = NewNode;
+ NewNode->Link[PARENT] = parent;
+ NewNode->gender = tmp;
+ }
+ (RootPtr->count)++;
+ return( ubi_trTRUE );
+ }
+
+ /* If we reach this point, we know that a duplicate node exists. This
+ * section adds the node to the tree if duplicate keys are allowed.
+ */
+ if( Dups_OK(RootPtr) ) /* Key exists, add duplicate */
+ {
+ ubi_btNodePtr q;
+
+ tmp = RIGHT;
+ q = (*OldNode);
+ *OldNode = NULL;
+ while( q )
+ {
+ parent = q;
+ if( tmp == EQUAL ) tmp = RIGHT;
+ q = q->Link[tmp];
+ if ( q )
+ tmp = AbNormal( (*(RootPtr->cmp))(ItemPtr, q) );
+ }
+ parent->Link[tmp] = NewNode;
+ NewNode->Link[PARENT] = parent;
+ NewNode->gender = tmp;
+ (RootPtr->count)++;
+ return( ubi_trTRUE );
+ }
+
+ /* If we get to *this* point, we know that we are not allowed to have
+ * duplicate nodes, but our node keys match, so... may we replace the
+ * old one?
+ */
+ if( Ovwt_OK(RootPtr) ) /* Key exists, we replace */
+ {
+ if (!(parent))
+ ReplaceNode( &(RootPtr->root), *OldNode, NewNode );
+ else
+ ReplaceNode( &(parent->Link[(*OldNode)->gender]), *OldNode, NewNode );
+ return( ubi_trTRUE );
+ }
+
+ return( ubi_trFALSE ); /* Failure: could not replace an existing node. */
+ } /* ubi_btInsert */
+
+ubi_btNodePtr ubi_btRemove( ubi_btRootPtr RootPtr,
+ ubi_btNodePtr DeadNode )
+ /* ------------------------------------------------------------------------ **
+ * This function removes the indicated node from the tree.
+ *
+ * Input: RootPtr - A pointer to the header of the tree that contains
+ * the node to be removed.
+ * DeadNode - A pointer to the node that will be removed.
+ *
+ * Output: This function returns a pointer to the node that was removed
+ * from the tree (ie. the same as DeadNode).
+ *
+ * Note: The node MUST be in the tree indicated by RootPtr. If not,
+ * strange and evil things will happen to your trees.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_btNodePtr p,
+ *parentp;
+ char tmp;
+
+ /* if the node has both left and right subtrees, then we have to swap
+ * it with another node. The other node we choose will be the Prev()ious
+ * node, which is garunteed to have no RIGHT child.
+ */
+ if( (DeadNode->Link[LEFT]) && (DeadNode->Link[RIGHT]) )
+ SwapNodes( RootPtr, DeadNode, ubi_btPrev( DeadNode ) );
+
+ /* The parent of the node to be deleted may be another node, or it may be
+ * the root of the tree. Since we're not sure, it's best just to have
+ * a pointer to the parent pointer, whatever it is.
+ */
+ if (DeadNode->Link[PARENT])
+ parentp = &((DeadNode->Link[PARENT])->Link[DeadNode->gender]);
+ else
+ parentp = &( RootPtr->root );
+
+ /* Now link the parent to the only grand-child and patch up the gender. */
+ tmp = ((DeadNode->Link[LEFT])?LEFT:RIGHT);
+
+ p = (DeadNode->Link[tmp]);
+ if( p )
+ {
+ p->Link[PARENT] = DeadNode->Link[PARENT];
+ p->gender = DeadNode->gender;
+ }
+ (*parentp) = p;
+
+ /* Finished, reduce the node count and return. */
+ (RootPtr->count)--;
+ return( DeadNode );
+ } /* ubi_btRemove */
+
+ubi_btNodePtr ubi_btLocate( ubi_btRootPtr RootPtr,
+ ubi_btItemPtr FindMe,
+ ubi_trCompOps CompOp )
+ /* ------------------------------------------------------------------------ **
+ * The purpose of ubi_btLocate() is to find a node or set of nodes given
+ * a target value and a "comparison operator". The Locate() function is
+ * more flexible and (in the case of trees that may contain dupicate keys)
+ * more precise than the ubi_btFind() function. The latter is faster,
+ * but it only searches for exact matches and, if the tree contains
+ * duplicates, Find() may return a pointer to any one of the duplicate-
+ * keyed records.
+ *
+ * Input:
+ * RootPtr - A pointer to the header of the tree to be searched.
+ * FindMe - An ubi_btItemPtr that indicates the key for which to
+ * search.
+ * CompOp - One of the following:
+ * CompOp Return a pointer to the node with
+ * ------ ---------------------------------
+ * ubi_trLT - the last key value that is less
+ * than FindMe.
+ * ubi_trLE - the first key matching FindMe, or
+ * the last key that is less than
+ * FindMe.
+ * ubi_trEQ - the first key matching FindMe.
+ * ubi_trGE - the first key matching FindMe, or the
+ * first key greater than FindMe.
+ * ubi_trGT - the first key greater than FindMe.
+ * Output:
+ * A pointer to the node matching the criteria listed above under
+ * CompOp, or NULL if no node matched the criteria.
+ *
+ * Notes:
+ * In the case of trees with duplicate keys, Locate() will behave as
+ * follows:
+ *
+ * Find: 3 Find: 3
+ * Keys: 1 2 2 2 3 3 3 3 3 4 4 Keys: 1 1 2 2 2 4 4 5 5 5 6
+ * ^ ^ ^ ^ ^
+ * LT EQ GT LE GE
+ *
+ * That is, when returning a pointer to a node with a key that is LESS
+ * THAN the target key (FindMe), Locate() will return a pointer to the
+ * LAST matching node.
+ * When returning a pointer to a node with a key that is GREATER
+ * THAN the target key (FindMe), Locate() will return a pointer to the
+ * FIRST matching node.
+ *
+ * See Also: ubi_btFind(), ubi_btFirstOf(), ubi_btLastOf().
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ register ubi_btNodePtr p;
+ ubi_btNodePtr parent;
+ char whichkid;
+
+ /* Start by searching for a matching node. */
+ p = TreeFind( FindMe,
+ RootPtr->root,
+ &parent,
+ &whichkid,
+ RootPtr->cmp );
+
+ if( p ) /* If we have found a match, we can resolve as follows: */
+ {
+ switch( CompOp )
+ {
+ case ubi_trLT: /* It's just a jump to the left... */
+ p = Border( RootPtr, FindMe, p, LEFT );
+ return( Neighbor( p, LEFT ) );
+ case ubi_trGT: /* ...and then a jump to the right. */
+ p = Border( RootPtr, FindMe, p, RIGHT );
+ return( Neighbor( p, RIGHT ) );
+ }
+ p = Border( RootPtr, FindMe, p, LEFT );
+ return( p );
+ }
+
+ /* Else, no match. */
+ if( ubi_trEQ == CompOp ) /* If we were looking for an exact match... */
+ return( NULL ); /* ...forget it. */
+
+ /* We can still return a valid result for GT, GE, LE, and LT.
+ * <parent> points to a node with a value that is either just before or
+ * just after the target value.
+ * Remaining possibilities are LT and GT (including LE & GE).
+ */
+ if( (ubi_trLT == CompOp) || (ubi_trLE == CompOp) )
+ return( (LEFT == whichkid) ? Neighbor( parent, whichkid ) : parent );
+ else
+ return( (RIGHT == whichkid) ? Neighbor( parent, whichkid ) : parent );
+ } /* ubi_btLocate */
+
+ubi_btNodePtr ubi_btFind( ubi_btRootPtr RootPtr,
+ ubi_btItemPtr FindMe )
+ /* ------------------------------------------------------------------------ **
+ * This function performs a non-recursive search of a tree for any node
+ * matching a specific key.
+ *
+ * Input:
+ * RootPtr - a pointer to the header of the tree to be searched.
+ * FindMe - a pointer to the key value for which to search.
+ *
+ * Output:
+ * A pointer to a node with a key that matches the key indicated by
+ * FindMe, or NULL if no such node was found.
+ *
+ * Note: In a tree that allows duplicates, the pointer returned *might
+ * not* point to the (sequentially) first occurance of the
+ * desired key. In such a tree, it may be more useful to use
+ * ubi_btLocate().
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ return( qFind( RootPtr->cmp, FindMe, RootPtr->root ) );
+ } /* ubi_btFind */
+
+ubi_btNodePtr ubi_btNext( ubi_btNodePtr P )
+ /* ------------------------------------------------------------------------ **
+ * Given the node indicated by P, find the (sorted order) Next node in the
+ * tree.
+ * Input: P - a pointer to a node that exists in a binary tree.
+ * Output: A pointer to the "next" node in the tree, or NULL if P pointed
+ * to the "last" node in the tree or was NULL.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ return( Neighbor( P, RIGHT ) );
+ } /* ubi_btNext */
+
+ubi_btNodePtr ubi_btPrev( ubi_btNodePtr P )
+ /* ------------------------------------------------------------------------ **
+ * Given the node indicated by P, find the (sorted order) Previous node in
+ * the tree.
+ * Input: P - a pointer to a node that exists in a binary tree.
+ * Output: A pointer to the "previous" node in the tree, or NULL if P
+ * pointed to the "first" node in the tree or was NULL.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ return( Neighbor( P, LEFT ) );
+ } /* ubi_btPrev */
+
+ubi_btNodePtr ubi_btFirst( ubi_btNodePtr P )
+ /* ------------------------------------------------------------------------ **
+ * Given the node indicated by P, find the (sorted order) First node in the
+ * subtree of which *P is the root.
+ * Input: P - a pointer to a node that exists in a binary tree.
+ * Output: A pointer to the "first" node in a subtree that has *P as its
+ * root. This function will return NULL only if P is NULL.
+ * Note: In general, you will be passing in the value of the root field
+ * of an ubi_btRoot structure.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ return( SubSlide( P, LEFT ) );
+ } /* ubi_btFirst */
+
+ubi_btNodePtr ubi_btLast( ubi_btNodePtr P )
+ /* ------------------------------------------------------------------------ **
+ * Given the node indicated by P, find the (sorted order) Last node in the
+ * subtree of which *P is the root.
+ * Input: P - a pointer to a node that exists in a binary tree.
+ * Output: A pointer to the "last" node in a subtree that has *P as its
+ * root. This function will return NULL only if P is NULL.
+ * Note: In general, you will be passing in the value of the root field
+ * of an ubi_btRoot structure.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ return( SubSlide( P, RIGHT ) );
+ } /* ubi_btLast */
+
+ubi_btNodePtr ubi_btFirstOf( ubi_btRootPtr RootPtr,
+ ubi_btItemPtr MatchMe,
+ ubi_btNodePtr p )
+ /* ------------------------------------------------------------------------ **
+ * Given a tree that a allows duplicate keys, and a pointer to a node in
+ * the tree, this function will return a pointer to the first (traversal
+ * order) node with the same key value.
+ *
+ * Input: RootPtr - A pointer to the root of the tree.
+ * MatchMe - A pointer to the key value. This should probably
+ * point to the key within node *p.
+ * p - A pointer to a node in the tree.
+ * Output: A pointer to the first node in the set of nodes with keys
+ * matching <FindMe>.
+ * Notes: Node *p MUST be in the set of nodes with keys matching
+ * <FindMe>. If not, this function will return NULL.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ /* If our starting point is invalid, return NULL. */
+ if( !p || AbNormal( (*(RootPtr->cmp))( MatchMe, p ) != EQUAL ) )
+ return( NULL );
+ return( Border( RootPtr, MatchMe, p, LEFT ) );
+ } /* ubi_btFirstOf */
+
+ubi_btNodePtr ubi_btLastOf( ubi_btRootPtr RootPtr,
+ ubi_btItemPtr MatchMe,
+ ubi_btNodePtr p )
+ /* ------------------------------------------------------------------------ **
+ * Given a tree that a allows duplicate keys, and a pointer to a node in
+ * the tree, this function will return a pointer to the last (traversal
+ * order) node with the same key value.
+ *
+ * Input: RootPtr - A pointer to the root of the tree.
+ * MatchMe - A pointer to the key value. This should probably
+ * point to the key within node *p.
+ * p - A pointer to a node in the tree.
+ * Output: A pointer to the last node in the set of nodes with keys
+ * matching <FindMe>.
+ * Notes: Node *p MUST be in the set of nodes with keys matching
+ * <FindMe>. If not, this function will return NULL.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ /* If our starting point is invalid, return NULL. */
+ if( !p || AbNormal( (*(RootPtr->cmp))( MatchMe, p ) != EQUAL ) )
+ return( NULL );
+ return( Border( RootPtr, MatchMe, p, RIGHT ) );
+ } /* ubi_btLastOf */
+
+ubi_trBool ubi_btTraverse( ubi_btRootPtr RootPtr,
+ ubi_btActionRtn EachNode,
+ void *UserData )
+ /* ------------------------------------------------------------------------ **
+ * Traverse a tree in sorted order (non-recursively). At each node, call
+ * (*EachNode)(), passing a pointer to the current node, and UserData as the
+ * second parameter.
+ * Input: RootPtr - a pointer to an ubi_btRoot structure that indicates
+ * the tree to be traversed.
+ * EachNode - a pointer to a function to be called at each node
+ * as the node is visited.
+ * UserData - a generic pointer that may point to anything that
+ * you choose.
+ * Output: A boolean value. FALSE if the tree is empty, otherwise TRUE.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_btNodePtr p;
+
+ if( !(p = ubi_btFirst( RootPtr->root )) ) return( ubi_trFALSE );
+
+ while( p )
+ {
+ EachNode( p, UserData );
+ p = ubi_btNext( p );
+ }
+ return( ubi_trTRUE );
+ } /* ubi_btTraverse */
+
+ubi_trBool ubi_btKillTree( ubi_btRootPtr RootPtr,
+ ubi_btKillNodeRtn FreeNode )
+ /* ------------------------------------------------------------------------ **
+ * Delete an entire tree (non-recursively) and reinitialize the ubi_btRoot
+ * structure. Note that this function will return FALSE if either parameter
+ * is NULL.
+ *
+ * Input: RootPtr - a pointer to an ubi_btRoot structure that indicates
+ * the root of the tree to delete.
+ * FreeNode - a function that will be called for each node in the
+ * tree to deallocate the memory used by the node.
+ *
+ * Output: A boolean value. FALSE if either input parameter was NULL, else
+ * TRUE.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_btNodePtr p, q;
+
+ if( !(RootPtr) || !(FreeNode) )
+ return( ubi_trFALSE );
+
+ p = ubi_btFirst( RootPtr->root );
+ while( p )
+ {
+ q = p;
+ while( q->Link[RIGHT] )
+ q = SubSlide( q->Link[RIGHT], LEFT );
+ p = q->Link[PARENT];
+ if( p )
+ p->Link[ ((p->Link[LEFT] == q)?LEFT:RIGHT) ] = NULL;
+ FreeNode((void *)q);
+ }
+
+ (void)ubi_btInitTree( RootPtr,
+ RootPtr->cmp,
+ RootPtr->flags );
+ return( ubi_trTRUE );
+ } /* ubi_btKillTree */
+
+ubi_btNodePtr ubi_btLeafNode( ubi_btNodePtr leader )
+ /* ------------------------------------------------------------------------ **
+ * Returns a pointer to a leaf node.
+ *
+ * Input: leader - Pointer to a node at which to start the descent.
+ *
+ * Output: A pointer to a leaf node selected in a somewhat arbitrary
+ * manner.
+ *
+ * Notes: I wrote this function because I was using splay trees as a
+ * database cache. The cache had a maximum size on it, and I
+ * needed a way of choosing a node to sacrifice if the cache
+ * became full. In a splay tree, less recently accessed nodes
+ * tend toward the bottom of the tree, meaning that leaf nodes
+ * are good candidates for removal. (I really can't think of
+ * any other reason to use this function.)
+ * + In a simple binary tree or an AVL tree, the most recently
+ * added nodes tend to be nearer the bottom, making this a *bad*
+ * way to choose which node to remove from the cache.
+ * + Randomizing the traversal order is probably a good idea. You
+ * can improve the randomization of leaf node selection by passing
+ * in pointers to nodes other than the root node each time. A
+ * pointer to any node in the tree will do. Of course, if you
+ * pass a pointer to a leaf node you'll get the same thing back.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_btNodePtr follower = NULL;
+ int whichway = LEFT;
+
+ while( NULL != leader )
+ {
+ follower = leader;
+ leader = follower->Link[ whichway ];
+ if( NULL == leader )
+ {
+ whichway = RevWay( whichway );
+ leader = follower->Link[ whichway ];
+ }
+ }
+
+ return( follower );
+ } /* ubi_btLeafNode */
+
+int ubi_btModuleID( int size, char *list[] )
+ /* ------------------------------------------------------------------------ **
+ * Returns a set of strings that identify the module.
+ *
+ * Input: size - The number of elements in the array <list>.
+ * list - An array of pointers of type (char *). This array
+ * should, initially, be empty. This function will fill
+ * in the array with pointers to strings.
+ * Output: The number of elements of <list> that were used. If this value
+ * is less than <size>, the values of the remaining elements are
+ * not guaranteed.
+ *
+ * Notes: Please keep in mind that the pointers returned indicate strings
+ * stored in static memory. Don't free() them, don't write over
+ * them, etc. Just read them.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ if( size > 0 )
+ {
+ list[0] = ModuleID;
+ if( size > 1 )
+ list[1] = NULL;
+ return( 1 );
+ }
+ return( 0 );
+ } /* ubi_btModuleID */
+
+
+/* ========================================================================== */
diff --git a/source/ubiqx/ubi_BinTree.h b/source/ubiqx/ubi_BinTree.h
new file mode 100644
index 00000000000..ee512989f98
--- /dev/null
+++ b/source/ubiqx/ubi_BinTree.h
@@ -0,0 +1,735 @@
+#ifndef ubi_BinTree_H
+#define ubi_BinTree_H
+/* ========================================================================== **
+ * ubi_BinTree.h
+ *
+ * Copyright (C) 1991-1997 by Christopher R. Hertel
+ *
+ * Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ *
+ * ubi_BinTree manages a simple binary tree. Nothing fancy here. No height
+ * balancing, no restructuring. Still, a good tool for creating short, low-
+ * overhead sorted lists of things that need to be found in a hurry.
+ *
+ * In addition, this module provides a good basis for creating other types
+ * of binary tree handling modules.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * 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 2.4 1997/07/26 04:11:14 crh
+ * + Just to be annoying I changed ubi_TRUE and ubi_FALSE to ubi_trTRUE
+ * and ubi_trFALSE.
+ * + There is now a type ubi_trBool to go with ubi_trTRUE and ubi_trFALSE.
+ * + There used to be something called "ubi_TypeDefs.h". I got rid of it.
+ * + Added function ubi_btLeafNode().
+ *
+ * Revision 2.3 1997/06/03 05:15:27 crh
+ * Changed TRUE and FALSE to ubi_TRUE and ubi_FALSE to avoid conflicts.
+ * Also changed the interface to function InitTree(). See the comments
+ * for this function for more information.
+ *
+ * Revision 2.2 1995/10/03 22:00:40 CRH
+ * Ubisized!
+ *
+ * Revision 2.1 95/03/09 23:43:46 CRH
+ * Added the ModuleID static string and function. These modules are now
+ * self-identifying.
+ *
+ * Revision 2.0 95/02/27 22:00:33 CRH
+ * Revision 2.0 of this program includes the following changes:
+ *
+ * 1) A fix to a major typo in the RepaceNode() function.
+ * 2) The addition of the static function Border().
+ * 3) The addition of the public functions FirstOf() and LastOf(), which
+ * use Border(). These functions are used with trees that allow
+ * duplicate keys.
+ * 4) A complete rewrite of the Locate() function. Locate() now accepts
+ * a "comparison" operator.
+ * 5) Overall enhancements to both code and comments.
+ *
+ * I decided to give this a new major rev number because the interface has
+ * changed. In particular, there are two new functions, and changes to the
+ * Locate() function.
+ *
+ * Revision 1.0 93/10/15 22:55:04 CRH
+ * With this revision, I have added a set of #define's that provide a single,
+ * standard API to all existing tree modules. Until now, each of the three
+ * existing modules had a different function and typedef prefix, as follows:
+ *
+ * Module Prefix
+ * ubi_BinTree ubi_bt
+ * ubi_AVLtree ubi_avl
+ * ubi_SplayTree ubi_spt
+ *
+ * To further complicate matters, only those portions of the base module
+ * (ubi_BinTree) that were superceeded in the new module had the new names.
+ * For example, if you were using ubi_AVLtree, the AVL node structure was
+ * named "ubi_avlNode", but the root structure was still "ubi_btRoot". Using
+ * SplayTree, the locate function was called "ubi_sptLocate", but the next
+ * and previous functions remained "ubi_btNext" and "ubi_btPrev".
+ *
+ * This was not too terrible if you were familiar with the modules and knew
+ * exactly which tree model you wanted to use. If you wanted to be able to
+ * change modules (for speed comparisons, etc), things could get messy very
+ * quickly.
+ *
+ * So, I have added a set of defined names that get redefined in any of the
+ * descendant modules. To use this standardized interface in your code,
+ * simply replace all occurances of "ubi_bt", "ubi_avl", and "ubi_spt" with
+ * "ubi_tr". The "ubi_tr" names will resolve to the correct function or
+ * datatype names for the module that you are using. Just remember to
+ * include the header for that module in your program file. Because these
+ * names are handled by the preprocessor, there is no added run-time
+ * overhead.
+ *
+ * Note that the original names do still exist, and can be used if you wish
+ * to write code directly to a specific module. This should probably only be
+ * done if you are planning to implement a new descendant type, such as
+ * red/black trees. CRH
+ *
+ * V0.0 - June, 1991 - Written by Christopher R. Hertel (CRH).
+ *
+ * ========================================================================== **
+ */
+
+/* -------------------------------------------------------------------------- **
+ * Macros and constants.
+ *
+ * General purpose:
+ * ubi_trTRUE - Boolean TRUE.
+ * ubi_trFALSE - Boolean FALSE.
+ *
+ * Flags used in the tree header:
+ * ubi_trOVERWRITE - This flag indicates that an existing node may be
+ * overwritten by a new node with a matching key.
+ * ubi_trDUPKEY - This flag indicates that the tree allows duplicate
+ * keys. If the tree does allow duplicates, the
+ * overwrite flag is ignored.
+ *
+ * Node link array index constants: (Each node has an array of three
+ * pointers. One to the left, one to the right, and one back to the
+ * parent.)
+ * LEFT - Left child pointer.
+ * PARENT - Parent pointer.
+ * RIGHT - Right child pointer.
+ * EQUAL - Synonym for PARENT.
+ *
+ * ubi_trCompOps: These values are used in the ubi_trLocate() function.
+ * ubi_trLT - request the first instance of the greatest key less than
+ * the search key.
+ * ubi_trLE - request the first instance of the greatest key that is less
+ * than or equal to the search key.
+ * ubi_trEQ - request the first instance of key that is equal to the
+ * search key.
+ * ubi_trGE - request the first instance of a key that is greater than
+ * or equal to the search key.
+ * ubi_trGT - request the first instance of the first key that is greater
+ * than the search key.
+ * -------------------------------------------------------------------------- **
+ */
+
+#define ubi_trTRUE 0xFF
+#define ubi_trFALSE 0x00
+
+#define ubi_trOVERWRITE 0x01 /* Turn on allow overwrite */
+#define ubi_trDUPKEY 0x02 /* Turn on allow duplicate keys */
+
+/* Pointer array index constants... */
+#define LEFT 0x00
+#define PARENT 0x01
+#define RIGHT 0x02
+#define EQUAL PARENT
+
+typedef enum {
+ ubi_trLT = 1,
+ ubi_trLE,
+ ubi_trEQ,
+ ubi_trGE,
+ ubi_trGT
+ } ubi_trCompOps;
+
+/* -------------------------------------------------------------------------- **
+ * These three macros allow simple manipulation of pointer index values (LEFT,
+ * RIGHT, and PARENT).
+ *
+ * Normalize() - converts {LEFT, PARENT, RIGHT} into {-1, 0 ,1}. C
+ * uses {negative, zero, positive} values to indicate
+ * {less than, equal to, greater than}.
+ * AbNormal() - converts {negative, zero, positive} to {LEFT, PARENT,
+ * RIGHT} (opposite of Normalize()). Note: C comparison
+ * functions, such as strcmp(), return {negative, zero,
+ * positive} values, which are not necessarily {-1, 0,
+ * 1}. This macro uses the the ubi_btSgn() function to
+ * compensate.
+ * RevWay() - converts LEFT to RIGHT and RIGHT to LEFT. PARENT (EQUAL)
+ * is left as is.
+ * -------------------------------------------------------------------------- **
+ */
+#define Normalize(W) ((char)((W)-EQUAL))
+#define AbNormal(W) ((char)( EQUAL+((char)ubi_btSgn( (W) )) ))
+#define RevWay(W) ((char)((W)==LEFT?RIGHT:((W)==RIGHT?LEFT:EQUAL)))
+
+/* -------------------------------------------------------------------------- **
+ * These macros allow us to quickly read the values of the OVERWRITE and
+ * DUPlicate KEY bits of the tree root flags field.
+ * -------------------------------------------------------------------------- **
+ */
+#define Dups_OK(A) ((ubi_trDUPKEY & ((A)->flags))?(ubi_trTRUE):(ubi_trFALSE))
+#define Ovwt_OK(A) ((ubi_trOVERWRITE & ((A)->flags))?(ubi_trTRUE):(ubi_trFALSE))
+
+/* -------------------------------------------------------------------------- **
+ * Typedefs...
+ *
+ * ubi_trBool - Your typcial true or false...
+ *
+ * Item Pointer: The ubi_btItemPtr is a generic pointer. It is used to
+ * indicate a key that is being searched for within the tree.
+ * Searching occurs whenever the ubi_trFind(), ubi_trLocate(),
+ * or ubi_trInsert() functions are called.
+ * -------------------------------------------------------------------------- **
+ */
+
+typedef unsigned char ubi_trBool;
+
+typedef void *ubi_btItemPtr; /* A pointer to data within a node. */
+
+/* ------------------------------------------------------------------------- **
+ * Binary Tree Node Structure: This structure defines the basic elements of
+ * the tree nodes. In general you *SHOULD NOT PLAY WITH THESE FIELDS*!
+ * But, of course, I have to put the structure into this header so that
+ * you can use it as a building block.
+ *
+ * The fields are as follows:
+ * Link - an array of pointers. These pointers are manipulated by
+ * the BT routines. The pointers indicate the left and right
+ * child nodes and the parent node. By keeping track of the
+ * parent pointer, we avoid the need for recursive routines or
+ * hand-tooled stacks to keep track of our path back to the
+ * root. The use of these pointers is subject to change without
+ * notice.
+ * gender - a one-byte field indicating whether the node is the RIGHT or
+ * LEFT child of its parent. If the node is the root of the
+ * tree, gender will be PARENT.
+ * ------------------------------------------------------------------------- **
+ */
+typedef struct ubi_btNodeStruct {
+ struct ubi_btNodeStruct *Link[ 3 ];
+ char gender;
+ } ubi_btNode;
+
+typedef ubi_btNode *ubi_btNodePtr; /* Pointer to an ubi_btNode structure. */
+
+/* ------------------------------------------------------------------------- **
+ * The next three typedefs define standard function types used by the binary
+ * tree management routines. In particular:
+ *
+ * ubi_btCompFunc is a pointer to a comparison function. Comparison
+ * functions are passed an ubi_btItemPtr and an
+ * ubi_btNodePtr. They return a value that is (<0), 0,
+ * or (>0) to indicate that the Item is (respectively)
+ * "less than", "equal to", or "greater than" the Item
+ * contained within the node. (See ubi_btInitTree()).
+ * ubi_btActionRtn is a pointer to a function that may be called for each
+ * node visited when performing a tree traversal (see
+ * ubi_btTraverse()). The function will be passed two
+ * parameters: the first is a pointer to a node in the
+ * tree, the second is a generic pointer that may point to
+ * anything that you like.
+ * ubi_btKillNodeRtn is a pointer to a function that will deallocate the
+ * memory used by a node (see ubi_btKillTree()). Since
+ * memory management is left up to you, deallocation may
+ * mean anything that you want it to mean. Just remember
+ * that the tree *will* be destroyed and that none of the
+ * node pointers will be valid any more.
+ * ------------------------------------------------------------------------- **
+ */
+
+typedef int (*ubi_btCompFunc)( ubi_btItemPtr, ubi_btNodePtr );
+
+typedef void (*ubi_btActionRtn)( ubi_btNodePtr, void * );
+
+typedef void (*ubi_btKillNodeRtn)( ubi_btNodePtr );
+
+/* -------------------------------------------------------------------------- **
+ * Tree Root Structure: This structure gives us a convenient handle for
+ * accessing whole AVL trees. The fields are:
+ * root - A pointer to the root node of the AVL tree.
+ * count - A count of the number of nodes stored in the tree.
+ * cmp - A pointer to the comparison routine to be used when building or
+ * searching the tree.
+ * flags - A set of bit flags. Two flags are currently defined:
+ *
+ * ubi_trOVERWRITE - If set, this flag indicates that a new node should
+ * (bit 0x01) overwrite an old node if the two have identical
+ * keys (ie., the keys are equal).
+ * ubi_trDUPKEY - If set, this flag indicates that the tree is
+ * (bit 0x02) allowed to contain nodes with duplicate keys.
+ *
+ * NOTE: ubi_trInsert() tests ubi_trDUPKEY before ubi_trOVERWRITE.
+ *
+ * All of these values are set when you initialize the root structure by
+ * calling ubi_trInitTree().
+ * -------------------------------------------------------------------------- **
+ */
+
+typedef struct {
+ ubi_btNodePtr root; /* A pointer to the root node of the tree */
+ unsigned long count; /* A count of the number of nodes in the tree */
+ ubi_btCompFunc cmp; /* A pointer to the tree's comparison function */
+ unsigned char flags; /* Overwrite Y|N, Duplicate keys Y|N... */
+ } ubi_btRoot;
+
+typedef ubi_btRoot *ubi_btRootPtr; /* Pointer to an ubi_btRoot structure. */
+
+
+/* -------------------------------------------------------------------------- **
+ * Function Prototypes.
+ */
+
+long ubi_btSgn( long x );
+ /* ------------------------------------------------------------------------ **
+ * Return the sign of x; {negative,zero,positive} ==> {-1, 0, 1}.
+ *
+ * Input: x - a signed long integer value.
+ *
+ * Output: the "sign" of x, represented as follows:
+ * -1 == negative
+ * 0 == zero (no sign)
+ * 1 == positive
+ *
+ * Note: This utility is provided in order to facilitate the conversion
+ * of C comparison function return values into BinTree direction
+ * values: {LEFT, PARENT, EQUAL}. It is INCORPORATED into the
+ * AbNormal() conversion macro!
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_btNodePtr ubi_btInitNode( ubi_btNodePtr NodePtr );
+ /* ------------------------------------------------------------------------ **
+ * Initialize a tree node.
+ *
+ * Input: a pointer to a ubi_btNode structure to be initialized.
+ * Output: a pointer to the initialized ubi_btNode structure (ie. the
+ * same as the input pointer).
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_btRootPtr ubi_btInitTree( ubi_btRootPtr RootPtr,
+ ubi_btCompFunc CompFunc,
+ unsigned char Flags );
+ /* ------------------------------------------------------------------------ **
+ * Initialize the fields of a Tree Root header structure.
+ *
+ * Input: RootPtr - a pointer to an ubi_btRoot structure to be
+ * initialized.
+ * CompFunc - a pointer to a comparison function that will be used
+ * whenever nodes in the tree must be compared against
+ * outside values.
+ * Flags - One bytes worth of flags. Flags include
+ * ubi_trOVERWRITE and ubi_trDUPKEY. See the header
+ * file for more info.
+ *
+ * Output: a pointer to the initialized ubi_btRoot structure (ie. the
+ * same value as RootPtr).
+ *
+ * Note: The interface to this function has changed from that of
+ * previous versions. The <Flags> parameter replaces two
+ * boolean parameters that had the same basic effect.
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_trBool ubi_btInsert( ubi_btRootPtr RootPtr,
+ ubi_btNodePtr NewNode,
+ ubi_btItemPtr ItemPtr,
+ ubi_btNodePtr *OldNode );
+ /* ------------------------------------------------------------------------ **
+ * This function uses a non-recursive algorithm to add a new element to the
+ * tree.
+ *
+ * Input: RootPtr - a pointer to the ubi_btRoot structure that indicates
+ * the root of the tree to which NewNode is to be added.
+ * NewNode - a pointer to an ubi_btNode structure that is NOT
+ * part of any tree.
+ * ItemPtr - A pointer to the sort key that is stored within
+ * *NewNode. ItemPtr MUST point to information stored
+ * in *NewNode or an EXACT DUPLICATE. The key data
+ * indicated by ItemPtr is used to place the new node
+ * into the tree.
+ * OldNode - a pointer to an ubi_btNodePtr. When searching
+ * the tree, a duplicate node may be found. If
+ * duplicates are allowed, then the new node will
+ * be simply placed into the tree. If duplicates
+ * are not allowed, however, then one of two things
+ * may happen.
+ * 1) if overwritting *is not* allowed, this
+ * function will return FALSE (indicating that
+ * the new node could not be inserted), and
+ * *OldNode will point to the duplicate that is
+ * still in the tree.
+ * 2) if overwritting *is* allowed, then this
+ * function will swap **OldNode for *NewNode.
+ * In this case, *OldNode will point to the node
+ * that was removed (thus allowing you to free
+ * the node).
+ * ** If you are using overwrite mode, ALWAYS **
+ * ** check the return value of this parameter! **
+ * Note: You may pass NULL in this parameter, the
+ * function knows how to cope. If you do this,
+ * however, there will be no way to return a
+ * pointer to an old (ie. replaced) node (which is
+ * a problem if you are using overwrite mode).
+ *
+ * Output: a boolean value indicating success or failure. The function
+ * will return FALSE if the node could not be added to the tree.
+ * Such failure will only occur if duplicates are not allowed,
+ * nodes cannot be overwritten, AND a duplicate key was found
+ * within the tree.
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_btNodePtr ubi_btRemove( ubi_btRootPtr RootPtr,
+ ubi_btNodePtr DeadNode );
+ /* ------------------------------------------------------------------------ **
+ * This function removes the indicated node from the tree.
+ *
+ * Input: RootPtr - A pointer to the header of the tree that contains
+ * the node to be removed.
+ * DeadNode - A pointer to the node that will be removed.
+ *
+ * Output: This function returns a pointer to the node that was removed
+ * from the tree (ie. the same as DeadNode).
+ *
+ * Note: The node MUST be in the tree indicated by RootPtr. If not,
+ * strange and evil things will happen to your trees.
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_btNodePtr ubi_btLocate( ubi_btRootPtr RootPtr,
+ ubi_btItemPtr FindMe,
+ ubi_trCompOps CompOp );
+ /* ------------------------------------------------------------------------ **
+ * The purpose of ubi_btLocate() is to find a node or set of nodes given
+ * a target value and a "comparison operator". The Locate() function is
+ * more flexible and (in the case of trees that may contain dupicate keys)
+ * more precise than the ubi_btFind() function. The latter is faster,
+ * but it only searches for exact matches and, if the tree contains
+ * duplicates, Find() may return a pointer to any one of the duplicate-
+ * keyed records.
+ *
+ * Input:
+ * RootPtr - A pointer to the header of the tree to be searched.
+ * FindMe - An ubi_btItemPtr that indicates the key for which to
+ * search.
+ * CompOp - One of the following:
+ * CompOp Return a pointer to the node with
+ * ------ ---------------------------------
+ * ubi_trLT - the last key value that is less
+ * than FindMe.
+ * ubi_trLE - the first key matching FindMe, or
+ * the last key that is less than
+ * FindMe.
+ * ubi_trEQ - the first key matching FindMe.
+ * ubi_trGE - the first key matching FindMe, or the
+ * first key greater than FindMe.
+ * ubi_trGT - the first key greater than FindMe.
+ * Output:
+ * A pointer to the node matching the criteria listed above under
+ * CompOp, or NULL if no node matched the criteria.
+ *
+ * Notes:
+ * In the case of trees with duplicate keys, Locate() will behave as
+ * follows:
+ *
+ * Find: 3 Find: 3
+ * Keys: 1 2 2 2 3 3 3 3 3 4 4 Keys: 1 1 2 2 2 4 4 5 5 5 6
+ * ^ ^ ^ ^ ^
+ * LT EQ GT LE GE
+ *
+ * That is, when returning a pointer to a node with a key that is LESS
+ * THAN the target key (FindMe), Locate() will return a pointer to the
+ * LAST matching node.
+ * When returning a pointer to a node with a key that is GREATER
+ * THAN the target key (FindMe), Locate() will return a pointer to the
+ * FIRST matching node.
+ *
+ * See Also: ubi_btFind(), ubi_btFirstOf(), ubi_btLastOf().
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_btNodePtr ubi_btFind( ubi_btRootPtr RootPtr,
+ ubi_btItemPtr FindMe );
+ /* ------------------------------------------------------------------------ **
+ * This function performs a non-recursive search of a tree for any node
+ * matching a specific key.
+ *
+ * Input:
+ * RootPtr - a pointer to the header of the tree to be searched.
+ * FindMe - a pointer to the key value for which to search.
+ *
+ * Output:
+ * A pointer to a node with a key that matches the key indicated by
+ * FindMe, or NULL if no such node was found.
+ *
+ * Note: In a tree that allows duplicates, the pointer returned *might
+ * not* point to the (sequentially) first occurance of the
+ * desired key. In such a tree, it may be more useful to use
+ * ubi_btLocate().
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_btNodePtr ubi_btNext( ubi_btNodePtr P );
+ /* ------------------------------------------------------------------------ **
+ * Given the node indicated by P, find the (sorted order) Next node in the
+ * tree.
+ * Input: P - a pointer to a node that exists in a binary tree.
+ * Output: A pointer to the "next" node in the tree, or NULL if P pointed
+ * to the "last" node in the tree or was NULL.
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_btNodePtr ubi_btPrev( ubi_btNodePtr P );
+ /* ------------------------------------------------------------------------ **
+ * Given the node indicated by P, find the (sorted order) Previous node in
+ * the tree.
+ * Input: P - a pointer to a node that exists in a binary tree.
+ * Output: A pointer to the "previous" node in the tree, or NULL if P
+ * pointed to the "first" node in the tree or was NULL.
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_btNodePtr ubi_btFirst( ubi_btNodePtr P );
+ /* ------------------------------------------------------------------------ **
+ * Given the node indicated by P, find the (sorted order) First node in the
+ * subtree of which *P is the root.
+ * Input: P - a pointer to a node that exists in a binary tree.
+ * Output: A pointer to the "first" node in a subtree that has *P as its
+ * root. This function will return NULL only if P is NULL.
+ * Note: In general, you will be passing in the value of the root field
+ * of an ubi_btRoot structure.
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_btNodePtr ubi_btLast( ubi_btNodePtr P );
+ /* ------------------------------------------------------------------------ **
+ * Given the node indicated by P, find the (sorted order) Last node in the
+ * subtree of which *P is the root.
+ * Input: P - a pointer to a node that exists in a binary tree.
+ * Output: A pointer to the "last" node in a subtree that has *P as its
+ * root. This function will return NULL only if P is NULL.
+ * Note: In general, you will be passing in the value of the root field
+ * of an ubi_btRoot structure.
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_btNodePtr ubi_btFirstOf( ubi_btRootPtr RootPtr,
+ ubi_btItemPtr MatchMe,
+ ubi_btNodePtr p );
+ /* ------------------------------------------------------------------------ **
+ * Given a tree that a allows duplicate keys, and a pointer to a node in
+ * the tree, this function will return a pointer to the first (traversal
+ * order) node with the same key value.
+ *
+ * Input: RootPtr - A pointer to the root of the tree.
+ * MatchMe - A pointer to the key value. This should probably
+ * point to the key within node *p.
+ * p - A pointer to a node in the tree.
+ * Output: A pointer to the first node in the set of nodes with keys
+ * matching <FindMe>.
+ * Notes: Node *p MUST be in the set of nodes with keys matching
+ * <FindMe>. If not, this function will return NULL.
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_btNodePtr ubi_btLastOf( ubi_btRootPtr RootPtr,
+ ubi_btItemPtr MatchMe,
+ ubi_btNodePtr p );
+ /* ------------------------------------------------------------------------ **
+ * Given a tree that a allows duplicate keys, and a pointer to a node in
+ * the tree, this function will return a pointer to the last (traversal
+ * order) node with the same key value.
+ *
+ * Input: RootPtr - A pointer to the root of the tree.
+ * MatchMe - A pointer to the key value. This should probably
+ * point to the key within node *p.
+ * p - A pointer to a node in the tree.
+ * Output: A pointer to the last node in the set of nodes with keys
+ * matching <FindMe>.
+ * Notes: Node *p MUST be in the set of nodes with keys matching
+ * <FindMe>. If not, this function will return NULL.
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_trBool ubi_btTraverse( ubi_btRootPtr RootPtr,
+ ubi_btActionRtn EachNode,
+ void *UserData );
+ /* ------------------------------------------------------------------------ **
+ * Traverse a tree in sorted order (non-recursively). At each node, call
+ * (*EachNode)(), passing a pointer to the current node, and UserData as the
+ * second parameter.
+ * Input: RootPtr - a pointer to an ubi_btRoot structure that indicates
+ * the tree to be traversed.
+ * EachNode - a pointer to a function to be called at each node
+ * as the node is visited.
+ * UserData - a generic pointer that may point to anything that
+ * you choose.
+ * Output: A boolean value. FALSE if the tree is empty, otherwise TRUE.
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_trBool ubi_btKillTree( ubi_btRootPtr RootPtr,
+ ubi_btKillNodeRtn FreeNode );
+ /* ------------------------------------------------------------------------ **
+ * Delete an entire tree (non-recursively) and reinitialize the ubi_btRoot
+ * structure. Note that this function will return FALSE if either parameter
+ * is NULL.
+ *
+ * Input: RootPtr - a pointer to an ubi_btRoot structure that indicates
+ * the root of the tree to delete.
+ * FreeNode - a function that will be called for each node in the
+ * tree to deallocate the memory used by the node.
+ *
+ * Output: A boolean value. FALSE if either input parameter was NULL, else
+ * TRUE.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_btNodePtr ubi_btLeafNode( ubi_btNodePtr leader );
+ /* ------------------------------------------------------------------------ **
+ * Returns a pointer to a leaf node.
+ *
+ * Input: leader - Pointer to a node at which to start the descent.
+ *
+ * Output: A pointer to a leaf node selected in a somewhat arbitrary
+ * manner.
+ *
+ * Notes: I wrote this function because I was using splay trees as a
+ * database cache. The cache had a maximum size on it, and I
+ * needed a way of choosing a node to sacrifice if the cache
+ * became full. In a splay tree, less recently accessed nodes
+ * tend toward the bottom of the tree, meaning that leaf nodes
+ * are good candidates for removal. (I really can't think of
+ * any other reason to use this function.)
+ * + In a simple binary tree or an AVL tree, the most recently
+ * added nodes tend to be nearer the bottom, making this a *bad*
+ * way to choose which node to remove from the cache.
+ * + Randomizing the traversal order is probably a good idea. You
+ * can improve the randomization of leaf node selection by passing
+ * in pointers to nodes other than the root node each time. A
+ * pointer to any node in the tree will do. Of course, if you
+ * pass a pointer to a leaf node you'll get the same thing back.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+
+int ubi_btModuleID( int size, char *list[] );
+ /* ------------------------------------------------------------------------ **
+ * Returns a set of strings that identify the module.
+ *
+ * Input: size - The number of elements in the array <list>.
+ * list - An array of pointers of type (char *). This array
+ * should, initially, be empty. This function will fill
+ * in the array with pointers to strings.
+ * Output: The number of elements of <list> that were used. If this value
+ * is less than <size>, the values of the remaining elements are
+ * not guaranteed.
+ *
+ * Notes: Please keep in mind that the pointers returned indicate strings
+ * stored in static memory. Don't free() them, don't write over
+ * them, etc. Just read them.
+ * ------------------------------------------------------------------------ **
+ */
+
+/* -------------------------------------------------------------------------- **
+ * Masquarade...
+ *
+ * This set of defines allows you to write programs that will use any of the
+ * implemented binary tree modules (currently BinTree, AVLtree, and SplayTree).
+ * Instead of using ubi_bt..., use ubi_tr..., and select the tree type by
+ * including the appropriate module header.
+ */
+
+#define ubi_trItemPtr ubi_btItemPtr
+
+#define ubi_trNode ubi_btNode
+#define ubi_trNodePtr ubi_btNodePtr
+
+#define ubi_trRoot ubi_btRoot
+#define ubi_trRootPtr ubi_btRootPtr
+
+#define ubi_trCompFunc ubi_btCompFunc
+#define ubi_trActionRtn ubi_btActionRtn
+#define ubi_trKillNodeRtn ubi_btKillNodeRtn
+
+#define ubi_trSgn( x ) ubi_btSgn( x )
+
+#define ubi_trInitNode( Np ) ubi_btInitNode( (ubi_btNodePtr)(Np) )
+
+#define ubi_trInitTree( Rp, Cf, Fl ) \
+ ubi_btInitTree( (ubi_btRootPtr)(Rp), (ubi_btCompFunc)(Cf), (Fl) )
+
+#define ubi_trInsert( Rp, Nn, Ip, On ) \
+ ubi_btInsert( (ubi_btRootPtr)(Rp), (ubi_btNodePtr)(Nn), \
+ (ubi_btItemPtr)(Ip), (ubi_btNodePtr *)(On) )
+
+#define ubi_trRemove( Rp, Dn ) \
+ ubi_btRemove( (ubi_btRootPtr)(Rp), (ubi_btNodePtr)(Dn) )
+
+#define ubi_trLocate( Rp, Ip, Op ) \
+ ubi_btLocate( (ubi_btRootPtr)(Rp), \
+ (ubi_btItemPtr)(Ip), \
+ (ubi_trCompOps)(Op) )
+
+#define ubi_trFind( Rp, Ip ) \
+ ubi_btFind( (ubi_btRootPtr)(Rp), (ubi_btItemPtr)(Ip) )
+
+#define ubi_trNext( P ) ubi_btNext( (ubi_btNodePtr)(P) )
+
+#define ubi_trPrev( P ) ubi_btPrev( (ubi_btNodePtr)(P) )
+
+#define ubi_trFirst( P ) ubi_btFirst( (ubi_btNodePtr)(P) )
+
+#define ubi_trLast( P ) ubi_btLast( (ubi_btNodePtr)(P) )
+
+#define ubi_trFirstOf( Rp, Ip, P ) \
+ ubi_btFirstOf( (ubi_btRootPtr)(Rp), \
+ (ubi_btItemPtr)(Ip), \
+ (ubi_btNodePtr)(P) )
+
+#define ubi_trLastOf( Rp, Ip, P ) \
+ ubi_btLastOf( (ubi_btRootPtr)(Rp), \
+ (ubi_btItemPtr)(Ip), \
+ (ubi_btNodePtr)(P) )
+
+#define ubi_trTraverse( Rp, En, Ud ) \
+ ubi_btTraverse((ubi_btRootPtr)(Rp), (ubi_btActionRtn)(En), (void *)(Ud))
+
+#define ubi_trKillTree( Rp, Fn ) \
+ ubi_btKillTree( (ubi_btRootPtr)(Rp), (ubi_btKillNodeRtn)(Fn) )
+
+#define ubi_trLeafNode( Nd ) \
+ ubi_btLeafNode( (ubi_btNodePtr)(Nd) )
+
+#define ubi_trModuleID( s, l ) ubi_btModuleID( s, l )
+
+/* ========================================================================== */
+#endif /* ubi_BinTree_H */
diff --git a/source/ubiqx/ubi_SplayTree.c b/source/ubiqx/ubi_SplayTree.c
new file mode 100644
index 00000000000..88be2ba9f49
--- /dev/null
+++ b/source/ubiqx/ubi_SplayTree.c
@@ -0,0 +1,462 @@
+/* ========================================================================== **
+ * ubi_SplayTree.c
+ *
+ * Copyright (C) 1993-1995 by Christopher R. Hertel
+ *
+ * Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ *
+ * This module implements "splay" trees. Splay trees are binary trees
+ * that are rearranged (splayed) whenever a node is accessed. The
+ * splaying process *tends* to make the tree bushier (improves balance),
+ * and the nodes that are accessed most frequently *tend* to be closer to
+ * the top.
+ *
+ * References: "Self-Adjusting Binary Search Trees", by Daniel Sleator and
+ * Robert Tarjan. Journal of the Association for Computing
+ * Machinery Vol 32, No. 3, July 1985 pp. 652-686
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * 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 2.5 1997/07/26 04:15:42 crh
+ * + Cleaned up a few minor syntax annoyances that gcc discovered for me.
+ * + Changed ubi_TRUE and ubi_FALSE to ubi_trTRUE and ubi_trFALSE.
+ *
+ * Revision 2.4 1997/06/03 04:42:21 crh
+ * Changed TRUE and FALSE to ubi_TRUE and ubi_FALSE to avoid causing
+ * problems.
+ *
+ * Revision 2.3 1995/10/03 22:19:07 CRH
+ * Ubisized!
+ * Also, added the function ubi_sptSplay().
+ *
+ * Revision 2.1 95/03/09 23:54:42 CRH
+ * Added the ModuleID static string and function. These modules are now
+ * self-identifying.
+ *
+ * Revision 2.0 95/02/27 22:34:46 CRH
+ * This module was updated to match the interface changes made to the
+ * ubi_BinTree module. In particular, the interface to the Locate() function
+ * has changed. See ubi_BinTree for more information on changes and new
+ * functions.
+ *
+ * The revision number was also upped to match ubi_BinTree.
+ *
+ * Revision 1.1 93/10/18 20:35:16 CRH
+ * I removed the hard-coded logical device names from the include file
+ * specifications. CRH
+ *
+ * Revision 1.0 93/10/15 23:00:15 CRH
+ * With this revision, I have added a set of #define's that provide a single,
+ * standard API to all existing tree modules. Until now, each of the three
+ * existing modules had a different function and typedef prefix, as follows:
+ *
+ * Module Prefix
+ * ubi_BinTree ubi_bt
+ * ubi_AVLtree ubi_avl
+ * ubi_SplayTree ubi_spt
+ *
+ * To further complicate matters, only those portions of the base module
+ * (ubi_BinTree) that were superceeded in the new module had the new names.
+ * For example, if you were using ubi_AVLtree, the AVL node structure was
+ * named "ubi_avlNode", but the root structure was still "ubi_btRoot". Using
+ * SplayTree, the locate function was called "ubi_sptLocate", but the next
+ * and previous functions remained "ubi_btNext" and "ubi_btPrev".
+ *
+ * This was not too terrible if you were familiar with the modules and knew
+ * exactly which tree model you wanted to use. If you wanted to be able to
+ * change modules (for speed comparisons, etc), things could get messy very
+ * quickly.
+ *
+ * So, I have added a set of defined names that get redefined in any of the
+ * descendant modules. To use this standardized interface in your code,
+ * simply replace all occurances of "ubi_bt", "ubi_avl", and "ubi_spt" with
+ * "ubi_tr". The "ubi_tr" names will resolve to the correct function or
+ * datatype names for the module that you are using. Just remember to
+ * include the header for that module in your program file. Because these
+ * names are handled by the preprocessor, there is no added run-time
+ * overhead.
+ *
+ * Note that the original names do still exist, and can be used if you wish
+ * to write code directly to a specific module. This should probably only be
+ * done if you are planning to implement a new descendant type, such as
+ * red/black trees. CRH
+ *
+ * Revision 0.1 93/04/25 22:03:32 CRH
+ * Simply changed the <exec/types.h> #include reference the .c file to
+ * use <stdlib.h> instead. The latter is portable, the former is not.
+ *
+ * Revision 0.0 93/04/21 23:05:52 CRH
+ * Initial version, written by Christopher R. Hertel.
+ * This module implements Splay Trees using the ubi_BinTree module as a basis.
+ *
+ * ========================================================================== **
+ */
+
+#include <stdlib.h> /* Defines NULL for us. */
+#include "ubi_SplayTree.h" /* Header for THIS module. */
+
+/* ========================================================================== **
+ * Static data.
+ */
+
+static char ModuleID[] = "ubi_SplayTree\n\
+\tRevision: 2.5\n\
+\tDate: 1997/07/26 04:15:42\n\
+\tAuthor: crh\n";
+
+
+/* ========================================================================== **
+ * Private functions...
+ */
+
+static void Rotate( ubi_btNodePtr p )
+ /* ------------------------------------------------------------------------ **
+ * This function performs a single rotation, moving node *p up one level
+ * in the tree.
+ *
+ * Input: p - a pointer to an ubi_btNode in a tree.
+ *
+ * Output: None.
+ *
+ * Notes: This implements a single rotation in either direction (left
+ * or right). This is the basic building block of all splay
+ * tree rotations.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_btNodePtr parentp;
+ ubi_btNodePtr tmp;
+ char way;
+ char revway;
+
+ parentp = p->Link[PARENT]; /* Find parent. */
+
+ if( parentp ) /* If no parent, then we're already the root. */
+ {
+ way = p->gender;
+ revway = RevWay(way);
+ tmp = p->Link[revway];
+
+ parentp->Link[way] = tmp;
+ if( tmp )
+ {
+ tmp->Link[PARENT] = parentp;
+ tmp->gender = way;
+ }
+
+ tmp = parentp->Link[PARENT];
+ p->Link[PARENT] = tmp;
+ p->gender = parentp->gender;
+ if( tmp )
+ tmp->Link[p->gender] = p;
+
+ parentp->Link[PARENT] = p;
+ parentp->gender = revway;
+ p->Link[revway] = parentp;
+ }
+ } /* Rotate */
+
+static ubi_btNodePtr Splay( ubi_btNodePtr SplayWithMe )
+ /* ------------------------------------------------------------------------ **
+ * Move the node indicated by SplayWithMe to the root of the tree by
+ * splaying the tree.
+ *
+ * Input: SplayWithMe - A pointer to an ubi_btNode within a tree.
+ *
+ * Output: A pointer to the root of the splay tree (i.e., the same as
+ * SplayWithMe).
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_btNodePtr parent;
+
+ while( (parent = SplayWithMe->Link[PARENT]) )
+ {
+ if( parent->gender == SplayWithMe->gender ) /* Zig-Zig */
+ Rotate( parent );
+ else
+ {
+ if( EQUAL != parent->gender ) /* Zig-Zag */
+ Rotate( SplayWithMe );
+ }
+ Rotate( SplayWithMe ); /* Zig */
+ } /* while */
+ return( SplayWithMe );
+ } /* Splay */
+
+/* ========================================================================== **
+ * Exported utilities.
+ */
+
+ubi_trBool ubi_sptInsert( ubi_btRootPtr RootPtr,
+ ubi_btNodePtr NewNode,
+ ubi_btItemPtr ItemPtr,
+ ubi_btNodePtr *OldNode )
+ /* ------------------------------------------------------------------------ **
+ * This function uses a non-recursive algorithm to add a new element to the
+ * splay tree.
+ *
+ * Input: RootPtr - a pointer to the ubi_btRoot structure that indicates
+ * the root of the tree to which NewNode is to be added.
+ * NewNode - a pointer to an ubi_btNode structure that is NOT
+ * part of any tree.
+ * ItemPtr - A pointer to the sort key that is stored within
+ * *NewNode. ItemPtr MUST point to information stored
+ * in *NewNode or an EXACT DUPLICATE. The key data
+ * indicated by ItemPtr is used to place the new node
+ * into the tree.
+ * OldNode - a pointer to an ubi_btNodePtr. When searching
+ * the tree, a duplicate node may be found. If
+ * duplicates are allowed, then the new node will
+ * be simply placed into the tree. If duplicates
+ * are not allowed, however, then one of two things
+ * may happen.
+ * 1) if overwritting *is not* allowed, this
+ * function will return FALSE (indicating that
+ * the new node could not be inserted), and
+ * *OldNode will point to the duplicate that is
+ * still in the tree.
+ * 2) if overwritting *is* allowed, then this
+ * function will swap **OldNode for *NewNode.
+ * In this case, *OldNode will point to the node
+ * that was removed (thus allowing you to free
+ * the node).
+ * ** If you are using overwrite mode, ALWAYS **
+ * ** check the return value of this parameter! **
+ * Note: You may pass NULL in this parameter, the
+ * function knows how to cope. If you do this,
+ * however, there will be no way to return a
+ * pointer to an old (ie. replaced) node (which is
+ * a problem if you are using overwrite mode).
+ *
+ * Output: a boolean value indicating success or failure. The function
+ * will return FALSE if the node could not be added to the tree.
+ * Such failure will only occur if duplicates are not allowed,
+ * nodes cannot be overwritten, AND a duplicate key was found
+ * within the tree.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_btNodePtr OtherP;
+
+ if( !(OldNode) )
+ OldNode = &OtherP;
+
+ if( ubi_btInsert( RootPtr, NewNode, ItemPtr, OldNode ) )
+ {
+ RootPtr->root = Splay( NewNode );
+ return( ubi_trTRUE );
+ }
+
+ /* Splay the unreplacable, duplicate keyed, unique, old node. */
+ RootPtr->root = Splay( (*OldNode) );
+ return( ubi_trFALSE );
+ } /* ubi_sptInsert */
+
+ubi_btNodePtr ubi_sptRemove( ubi_btRootPtr RootPtr, ubi_btNodePtr DeadNode )
+ /* ------------------------------------------------------------------------ **
+ * This function removes the indicated node from the tree.
+ *
+ * Input: RootPtr - A pointer to the header of the tree that contains
+ * the node to be removed.
+ * DeadNode - A pointer to the node that will be removed.
+ *
+ * Output: This function returns a pointer to the node that was removed
+ * from the tree (ie. the same as DeadNode).
+ *
+ * Note: The node MUST be in the tree indicated by RootPtr. If not,
+ * strange and evil things will happen to your trees.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_btNodePtr p;
+
+ (void)Splay( DeadNode ); /* Move dead node to root. */
+ if( (p = DeadNode->Link[LEFT]) ) /* If left subtree exists... */
+ {
+ ubi_btNodePtr q = DeadNode->Link[RIGHT];
+
+ p->Link[PARENT] = NULL; /* Left subtree node becomes root.*/
+ p->gender = PARENT;
+ p = ubi_btLast( p ); /* Find rightmost left tree node..*/
+ p->Link[RIGHT] = q; /* ...attach right tree. */
+ if( q )
+ q->Link[PARENT] = p;
+ RootPtr->root = Splay( p ); /* Resplay at p. */
+ }
+ else
+ {
+ if( (p = DeadNode->Link[RIGHT]) ) /* No left, but right subtree... */
+ { /* ...exists... */
+ p->Link[PARENT] = NULL; /* Right subtree root becomes... */
+ p->gender = PARENT; /* ...overall tree root. */
+ RootPtr->root = p;
+ }
+ else
+ RootPtr->root = NULL; /* No subtrees => empty tree. */
+ }
+
+ (RootPtr->count)--; /* Decrement node count. */
+ return( DeadNode ); /* Return pointer to pruned node. */
+ } /* ubi_sptRemove */
+
+ubi_btNodePtr ubi_sptLocate( ubi_btRootPtr RootPtr,
+ ubi_btItemPtr FindMe,
+ ubi_trCompOps CompOp )
+ /* ------------------------------------------------------------------------ **
+ * The purpose of ubi_btLocate() is to find a node or set of nodes given
+ * a target value and a "comparison operator". The Locate() function is
+ * more flexible and (in the case of trees that may contain dupicate keys)
+ * more precise than the ubi_btFind() function. The latter is faster,
+ * but it only searches for exact matches and, if the tree contains
+ * duplicates, Find() may return a pointer to any one of the duplicate-
+ * keyed records.
+ *
+ * Input:
+ * RootPtr - A pointer to the header of the tree to be searched.
+ * FindMe - An ubi_btItemPtr that indicates the key for which to
+ * search.
+ * CompOp - One of the following:
+ * CompOp Return a pointer to the node with
+ * ------ ---------------------------------
+ * ubi_trLT - the last key value that is less
+ * than FindMe.
+ * ubi_trLE - the first key matching FindMe, or
+ * the last key that is less than
+ * FindMe.
+ * ubi_trEQ - the first key matching FindMe.
+ * ubi_trGE - the first key matching FindMe, or the
+ * first key greater than FindMe.
+ * ubi_trGT - the first key greater than FindMe.
+ * Output:
+ * A pointer to the node matching the criteria listed above under
+ * CompOp, or NULL if no node matched the criteria.
+ *
+ * Notes:
+ * In the case of trees with duplicate keys, Locate() will behave as
+ * follows:
+ *
+ * Find: 3 Find: 3
+ * Keys: 1 2 2 2 3 3 3 3 3 4 4 Keys: 1 1 2 2 2 4 4 5 5 5 6
+ * ^ ^ ^ ^ ^
+ * LT EQ GT LE GE
+ *
+ * That is, when returning a pointer to a node with a key that is LESS
+ * THAN the target key (FindMe), Locate() will return a pointer to the
+ * LAST matching node.
+ * When returning a pointer to a node with a key that is GREATER
+ * THAN the target key (FindMe), Locate() will return a pointer to the
+ * FIRST matching node.
+ *
+ * See Also: ubi_btFind(), ubi_btFirstOf(), ubi_btLastOf().
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_btNodePtr p;
+
+ p = ubi_btLocate( RootPtr, FindMe, CompOp );
+ if( p )
+ RootPtr->root = Splay( p );
+ return( p );
+ } /* ubi_sptLocate */
+
+ubi_btNodePtr ubi_sptFind( ubi_btRootPtr RootPtr,
+ ubi_btItemPtr FindMe )
+ /* ------------------------------------------------------------------------ **
+ * This function performs a non-recursive search of a tree for any node
+ * matching a specific key.
+ *
+ * Input:
+ * RootPtr - a pointer to the header of the tree to be searched.
+ * FindMe - a pointer to the key value for which to search.
+ *
+ * Output:
+ * A pointer to a node with a key that matches the key indicated by
+ * FindMe, or NULL if no such node was found.
+ *
+ * Note: In a tree that allows duplicates, the pointer returned *might
+ * not* point to the (sequentially) first occurance of the
+ * desired key. In such a tree, it may be more useful to use
+ * ubi_sptLocate().
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_btNodePtr p;
+
+ p = ubi_btFind( RootPtr, FindMe );
+ if( p )
+ RootPtr->root = Splay( p );
+ return( p );
+ } /* ubi_sptFind */
+
+void ubi_sptSplay( ubi_btRootPtr RootPtr,
+ ubi_btNodePtr SplayMe )
+ /* ------------------------------------------------------------------------ **
+ * This function allows you to splay the tree at a given node, thus moving
+ * the node to the top of the tree.
+ *
+ * Input:
+ * RootPtr - a pointer to the header of the tree to be splayed.
+ * SplayMe - a pointer to a node within the tree. This will become
+ * the new root node.
+ * Output: None.
+ *
+ * Notes: This is an uncharacteristic function for this group of modules
+ * in that it provides access to the internal balancing routines,
+ * which would normally be hidden.
+ * Splaying the tree will not damage it (assuming that I've done
+ * *my* job), but there is overhead involved. I don't recommend
+ * that you use this function unless you understand the underlying
+ * Splay Tree principles involved.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ RootPtr->root = Splay( SplayMe );
+ } /* ubi_sptSplay */
+
+int ubi_sptModuleID( int size, char *list[] )
+ /* ------------------------------------------------------------------------ **
+ * Returns a set of strings that identify the module.
+ *
+ * Input: size - The number of elements in the array <list>.
+ * list - An array of pointers of type (char *). This array
+ * should, initially, be empty. This function will fill
+ * in the array with pointers to strings.
+ * Output: The number of elements of <list> that were used. If this value
+ * is less than <size>, the values of the remaining elements are
+ * not guaranteed.
+ *
+ * Notes: Please keep in mind that the pointers returned indicate strings
+ * stored in static memory. Don't free() them, don't write over
+ * them, etc. Just read them.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ if( size > 0 )
+ {
+ list[0] = ModuleID;
+ if( size > 1 )
+ return( 1 + ubi_btModuleID( --size, &(list[1]) ) );
+ return( 1 );
+ }
+ return( 0 );
+ } /* ubi_sptModuleID */
+
+/* ================================ The End ================================= */
diff --git a/source/ubiqx/ubi_SplayTree.h b/source/ubiqx/ubi_SplayTree.h
new file mode 100644
index 00000000000..7585d532cea
--- /dev/null
+++ b/source/ubiqx/ubi_SplayTree.h
@@ -0,0 +1,329 @@
+#ifndef ubi_SplayTree_H
+#define ubi_SplayTree_H
+/* ========================================================================== **
+ * ubi_SplayTree.h
+ *
+ * Copyright (C) 1993,1995 by Christopher R. Hertel
+ *
+ * Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ *
+ * This module implements "splay" trees. Splay trees are binary trees
+ * that are rearranged (splayed) whenever a node is accessed. The
+ * splaying process *tends* to make the tree bushier (improves balance),
+ * and the nodes that are accessed most frequently *tend* to be closer to
+ * the top.
+ *
+ * References: "Self-Adjusting Binary Search Trees", by Daniel Sleator and
+ * Robert Tarjan. Journal of the Association for Computing
+ * Machinery Vol 32, No. 3, July 1985 pp. 652-686
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * 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 2.5 1997/07/26 04:15:46 crh
+ * + Cleaned up a few minor syntax annoyances that gcc discovered for me.
+ * + Changed ubi_TRUE and ubi_FALSE to ubi_trTRUE and ubi_trFALSE.
+ *
+ * Revision 2.4 1997/06/03 05:22:56 crh
+ * Changed TRUE and FALSE to ubi_TRUE and ubi_FALSE to avoid causing
+ * problems.
+ *
+ * Revision 2.3 1995/10/03 22:19:37 CRH
+ * Ubisized!
+ * Also, added the function ubi_sptSplay().
+ *
+ * Revision 2.1 95/03/09 23:55:04 CRH
+ * Added the ModuleID static string and function. These modules are now
+ * self-identifying.
+ *
+ * Revision 2.0 95/02/27 22:34:55 CRH
+ * This module was updated to match the interface changes made to the
+ * ubi_BinTree module. In particular, the interface to the Locate() function
+ * has changed. See ubi_BinTree for more information on changes and new
+ * functions.
+ *
+ * The revision number was also upped to match ubi_BinTree.
+ *
+ *
+ * Revision 1.0 93/10/15 22:59:36 CRH
+ * With this revision, I have added a set of #define's that provide a single,
+ * standard API to all existing tree modules. Until now, each of the three
+ * existing modules had a different function and typedef prefix, as follows:
+ *
+ * Module Prefix
+ * ubi_BinTree ubi_bt
+ * ubi_AVLtree ubi_avl
+ * ubi_SplayTree ubi_spt
+ *
+ * To further complicate matters, only those portions of the base module
+ * (ubi_BinTree) that were superceeded in the new module had the new names.
+ * For example, if you were using ubi_AVLtree, the AVL node structure was
+ * named "ubi_avlNode", but the root structure was still "ubi_btRoot". Using
+ * SplayTree, the locate function was called "ubi_sptLocate", but the next
+ * and previous functions remained "ubi_btNext" and "ubi_btPrev".
+ *
+ * This was not too terrible if you were familiar with the modules and knew
+ * exactly which tree model you wanted to use. If you wanted to be able to
+ * change modules (for speed comparisons, etc), things could get messy very
+ * quickly.
+ *
+ * So, I have added a set of defined names that get redefined in any of the
+ * descendant modules. To use this standardized interface in your code,
+ * simply replace all occurances of "ubi_bt", "ubi_avl", and "ubi_spt" with
+ * "ubi_tr". The "ubi_tr" names will resolve to the correct function or
+ * datatype names for the module that you are using. Just remember to
+ * include the header for that module in your program file. Because these
+ * names are handled by the preprocessor, there is no added run-time
+ * overhead.
+ *
+ * Note that the original names do still exist, and can be used if you wish
+ * to write code directly to a specific module. This should probably only be
+ * done if you are planning to implement a new descendant type, such as
+ * red/black trees. CRH
+ *
+ * Revision 0.0 93/04/21 23:07:13 CRH
+ * Initial version, written by Christopher R. Hertel.
+ * This module implements Splay Trees using the ubi_BinTree module as a basis.
+ *
+ * ========================================================================== **
+ */
+
+#include "ubi_BinTree.h" /* Base binary tree functions, types, etc. */
+
+/* ========================================================================== **
+ * Function prototypes...
+ */
+
+ubi_trBool ubi_sptInsert( ubi_btRootPtr RootPtr,
+ ubi_btNodePtr NewNode,
+ ubi_btItemPtr ItemPtr,
+ ubi_btNodePtr *OldNode );
+ /* ------------------------------------------------------------------------ **
+ * This function uses a non-recursive algorithm to add a new element to the
+ * splay tree.
+ *
+ * Input: RootPtr - a pointer to the ubi_btRoot structure that indicates
+ * the root of the tree to which NewNode is to be added.
+ * NewNode - a pointer to an ubi_btNode structure that is NOT
+ * part of any tree.
+ * ItemPtr - A pointer to the sort key that is stored within
+ * *NewNode. ItemPtr MUST point to information stored
+ * in *NewNode or an EXACT DUPLICATE. The key data
+ * indicated by ItemPtr is used to place the new node
+ * into the tree.
+ * OldNode - a pointer to an ubi_btNodePtr. When searching
+ * the tree, a duplicate node may be found. If
+ * duplicates are allowed, then the new node will
+ * be simply placed into the tree. If duplicates
+ * are not allowed, however, then one of two things
+ * may happen.
+ * 1) if overwritting *is not* allowed, this
+ * function will return FALSE (indicating that
+ * the new node could not be inserted), and
+ * *OldNode will point to the duplicate that is
+ * still in the tree.
+ * 2) if overwritting *is* allowed, then this
+ * function will swap **OldNode for *NewNode.
+ * In this case, *OldNode will point to the node
+ * that was removed (thus allowing you to free
+ * the node).
+ * ** If you are using overwrite mode, ALWAYS **
+ * ** check the return value of this parameter! **
+ * Note: You may pass NULL in this parameter, the
+ * function knows how to cope. If you do this,
+ * however, there will be no way to return a
+ * pointer to an old (ie. replaced) node (which is
+ * a problem if you are using overwrite mode).
+ *
+ * Output: a boolean value indicating success or failure. The function
+ * will return FALSE if the node could not be added to the tree.
+ * Such failure will only occur if duplicates are not allowed,
+ * nodes cannot be overwritten, AND a duplicate key was found
+ * within the tree.
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_btNodePtr ubi_sptRemove( ubi_btRootPtr RootPtr, ubi_btNodePtr DeadNode );
+ /* ------------------------------------------------------------------------ **
+ * This function removes the indicated node from the tree.
+ *
+ * Input: RootPtr - A pointer to the header of the tree that contains
+ * the node to be removed.
+ * DeadNode - A pointer to the node that will be removed.
+ *
+ * Output: This function returns a pointer to the node that was removed
+ * from the tree (ie. the same as DeadNode).
+ *
+ * Note: The node MUST be in the tree indicated by RootPtr. If not,
+ * strange and evil things will happen to your trees.
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_btNodePtr ubi_sptLocate( ubi_btRootPtr RootPtr,
+ ubi_btItemPtr FindMe,
+ ubi_trCompOps CompOp );
+ /* ------------------------------------------------------------------------ **
+ * The purpose of ubi_btLocate() is to find a node or set of nodes given
+ * a target value and a "comparison operator". The Locate() function is
+ * more flexible and (in the case of trees that may contain dupicate keys)
+ * more precise than the ubi_btFind() function. The latter is faster,
+ * but it only searches for exact matches and, if the tree contains
+ * duplicates, Find() may return a pointer to any one of the duplicate-
+ * keyed records.
+ *
+ * Input:
+ * RootPtr - A pointer to the header of the tree to be searched.
+ * FindMe - An ubi_btItemPtr that indicates the key for which to
+ * search.
+ * CompOp - One of the following:
+ * CompOp Return a pointer to the node with
+ * ------ ---------------------------------
+ * ubi_trLT - the last key value that is less
+ * than FindMe.
+ * ubi_trLE - the first key matching FindMe, or
+ * the last key that is less than
+ * FindMe.
+ * ubi_trEQ - the first key matching FindMe.
+ * ubi_trGE - the first key matching FindMe, or the
+ * first key greater than FindMe.
+ * ubi_trGT - the first key greater than FindMe.
+ * Output:
+ * A pointer to the node matching the criteria listed above under
+ * CompOp, or NULL if no node matched the criteria.
+ *
+ * Notes:
+ * In the case of trees with duplicate keys, Locate() will behave as
+ * follows:
+ *
+ * Find: 3 Find: 3
+ * Keys: 1 2 2 2 3 3 3 3 3 4 4 Keys: 1 1 2 2 2 4 4 5 5 5 6
+ * ^ ^ ^ ^ ^
+ * LT EQ GT LE GE
+ *
+ * That is, when returning a pointer to a node with a key that is LESS
+ * THAN the target key (FindMe), Locate() will return a pointer to the
+ * LAST matching node.
+ * When returning a pointer to a node with a key that is GREATER
+ * THAN the target key (FindMe), Locate() will return a pointer to the
+ * FIRST matching node.
+ *
+ * See Also: ubi_btFind(), ubi_btFirstOf(), ubi_btLastOf().
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_btNodePtr ubi_sptFind( ubi_btRootPtr RootPtr,
+ ubi_btItemPtr FindMe );
+ /* ------------------------------------------------------------------------ **
+ * This function performs a non-recursive search of a tree for any node
+ * matching a specific key.
+ *
+ * Input:
+ * RootPtr - a pointer to the header of the tree to be searched.
+ * FindMe - a pointer to the key value for which to search.
+ *
+ * Output:
+ * A pointer to a node with a key that matches the key indicated by
+ * FindMe, or NULL if no such node was found.
+ *
+ * Note: In a tree that allows duplicates, the pointer returned *might
+ * not* point to the (sequentially) first occurance of the
+ * desired key. In such a tree, it may be more useful to use
+ * ubi_sptLocate().
+ * ------------------------------------------------------------------------ **
+ */
+
+void ubi_sptSplay( ubi_btRootPtr RootPtr,
+ ubi_btNodePtr SplayMe );
+ /* ------------------------------------------------------------------------ **
+ * This function allows you to splay the tree at a given node, thus moving
+ * the node to the top of the tree.
+ *
+ * Input:
+ * RootPtr - a pointer to the header of the tree to be splayed.
+ * SplayMe - a pointer to a node within the tree. This will become
+ * the new root node.
+ * Output: None.
+ *
+ * Notes: This is an uncharacteristic function for this group of modules
+ * in that it provides access to the internal balancing routines,
+ * which would normally be hidden.
+ * Splaying the tree will not damage it (assuming that I've done
+ * *my* job), but there is overhead involved. I don't recommend
+ * that you use this function unless you understand the underlying
+ * Splay Tree principles involved.
+ * ------------------------------------------------------------------------ **
+ */
+
+int ubi_sptModuleID( int size, char *list[] );
+ /* ------------------------------------------------------------------------ **
+ * Returns a set of strings that identify the module.
+ *
+ * Input: size - The number of elements in the array <list>.
+ * list - An array of pointers of type (char *). This array
+ * should, initially, be empty. This function will fill
+ * in the array with pointers to strings.
+ * Output: The number of elements of <list> that were used. If this value
+ * is less than <size>, the values of the remaining elements are
+ * not guaranteed.
+ *
+ * Notes: Please keep in mind that the pointers returned indicate strings
+ * stored in static memory. Don't free() them, don't write over
+ * them, etc. Just read them.
+ * ------------------------------------------------------------------------ **
+ */
+
+/* -------------------------------------------------------------------------- **
+ * Masquarade...
+ *
+ * This set of defines allows you to write programs that will use any of the
+ * implemented binary tree modules (currently BinTree, AVLtree, and SplayTree).
+ * Instead of using ubi_bt..., use ubi_tr..., and select the tree type by
+ * including the appropriate module header.
+ */
+
+#undef ubi_trInsert
+#undef ubi_trRemove
+#undef ubi_trLocate
+#undef ubi_trFind
+#undef ubi_trModuleID
+
+#define ubi_trInsert( Rp, Nn, Ip, On ) \
+ ubi_sptInsert( (ubi_btRootPtr)(Rp), (ubi_btNodePtr)(Nn), \
+ (ubi_btItemPtr)(Ip), (ubi_btNodePtr *)(On) )
+
+#define ubi_trRemove( Rp, Dn ) \
+ ubi_sptRemove( (ubi_btRootPtr)(Rp), (ubi_btNodePtr)(Dn) )
+
+#define ubi_trLocate( Rp, Ip, Op ) \
+ ubi_sptLocate( (ubi_btRootPtr)(Rp), \
+ (ubi_btItemPtr)(Ip), \
+ (ubi_trCompOps)(Op) )
+
+#define ubi_trFind( Rp, Ip ) \
+ ubi_sptFind( (ubi_btRootPtr)(Rp), (ubi_btItemPtr)(Ip) )
+
+#define ubi_trModuleID( s, l ) ubi_sptModuleID( s, l )
+
+/* ================================ The End ================================= */
+#endif /* ubi_SplayTree_H */
+
+
+
+
+
diff --git a/source/ubiqx/ubi_StackQueue.c b/source/ubiqx/ubi_StackQueue.c
new file mode 100644
index 00000000000..19e4f785a0b
--- /dev/null
+++ b/source/ubiqx/ubi_StackQueue.c
@@ -0,0 +1,149 @@
+/* ========================================================================== **
+ * ubi_StackQueue.c
+ *
+ * Copyright (C) 1997 by Christopher R. Hertel
+ *
+ * Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ * This module implements simple queues and stacks using a singly linked
+ * list.
+ * -------------------------------------------------------------------------- **
+ *
+ * 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.
+ *
+ * -------------------------------------------------------------------------- **
+ * This module uses a singly-linked list to implement both a queue and a
+ * stack. For a queue, entries are added at the tail and removed from the
+ * head of the list. For a stack, the entries are entered and removed from
+ * the head of the list. A traversal of the list will always start at the
+ * head of the list and proceed toward the tail. This is all mind-numbingly
+ * simple, but I'm surprised by the number of programs out there which
+ * re-implement this a dozen or so times.
+ *
+ * Note: When the list header is initialized, the Tail pointer is set to
+ * point to the Head pointer. This simplifies the InsTail function
+ * at little or no cost to InsHead or Remove. The one problem is
+ * that you can't initialize a stack or queue headerby simply zeroing
+ * it out. One sure way to initialize the header is to call
+ * ubi_sqInit(). Another option would be something like this:
+ *
+ * static ubi_sqList MyList = { NULL, (ubi_sqNodePtr)&MyList, 0 };
+ *
+ * See ubi_sqInit() and the ubi_sqList structure for more info.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * Revision 0.1 1997/10/24 02:47:52 crh
+ * Initial revision.
+ *
+ * ========================================================================== **
+ */
+
+#include "ubi_StackQueue.h"
+
+/* ========================================================================== **
+ * Functions...
+ */
+
+ubi_sqListPtr ubi_sqInit( ubi_sqListPtr ListPtr )
+ /* ------------------------------------------------------------------------ **
+ * Initialize a stack & queue header.
+ *
+ * Input: ListPtr - A pointer to the list header 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 = (ubi_sqNodePtr)ListPtr;
+ ListPtr->count = 0;
+ return( ListPtr );
+ } /* ubi_sqInit */
+
+ubi_sqNodePtr ubi_sqInsHead( ubi_sqListPtr ListPtr, ubi_sqNodePtr New )
+ /* ------------------------------------------------------------------------ **
+ * Insert a new node at the head of the list (push).
+ *
+ * Input: ListPtr - A pointer to the stack into which the node is to
+ * be inserted.
+ * New - Pointer to the node that is to be pushed onto the
+ * stack.
+ *
+ * Output: A pointer to the node that was added to the list (i.e., same
+ * same as <New>).
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ if( NULL == ListPtr->Head ) /* If list is empty, must change tail ptr. */
+ ListPtr->Tail = New;
+ New->Next = ListPtr->Head;
+ ListPtr->Head = New;
+ ++(ListPtr->count);
+ return( New );
+ } /* ubi_sqInsHead */
+
+ubi_sqNodePtr ubi_sqInsTail( ubi_sqListPtr ListPtr, ubi_sqNodePtr New )
+ /* ------------------------------------------------------------------------ **
+ * Add a new node to the tail of the list (enqueue).
+ *
+ * Input: ListPtr - A pointer to the queue into which the node is to
+ * be inserted.
+ * New - Pointer to the node that is to be enqueued.
+ *
+ * Output: A pointer to the node that was inserted into the queue (i.e.,
+ * the same as <New>).
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ListPtr->Tail->Next = New;
+ ListPtr->Tail = New;
+ New->Next = NULL;
+ ++(ListPtr->count);
+ return( New );
+ } /* ubi_sqInsTail */
+
+ubi_sqNodePtr ubi_sqRemove( ubi_sqListPtr ListPtr )
+ /* ------------------------------------------------------------------------ **
+ * Remove the frontmost entry from the queue, or topmost entry from the
+ * stack.
+ *
+ * Input: ListPtr - A pointer to the list from which the node is to be
+ * removed.
+ *
+ * Output: A pointer to the node that was removed.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_sqNodePtr Old = ListPtr->Head;
+
+ if( NULL != Old )
+ {
+ if( NULL == Old->Next )
+ ListPtr->Tail = (ubi_sqNodePtr)ListPtr;
+ ListPtr->Head = Old->Next;
+ --(ListPtr->count);
+ }
+ return( Old );
+ } /* ubi_sqRemove */
+
+
+/* ================================ The End ================================= */
diff --git a/source/ubiqx/ubi_StackQueue.h b/source/ubiqx/ubi_StackQueue.h
new file mode 100644
index 00000000000..69fe7bebe5e
--- /dev/null
+++ b/source/ubiqx/ubi_StackQueue.h
@@ -0,0 +1,180 @@
+#ifndef ubi_StackQueue_H
+#define ubi_StackQueue_H
+/* ========================================================================== **
+ * ubi_StackQueue.h
+ *
+ * Copyright (C) 1997 by Christopher R. Hertel
+ *
+ * Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ * This module implements simple queues and stacks using a singly linked
+ * list.
+ * -------------------------------------------------------------------------- **
+ *
+ * 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.
+ *
+ * -------------------------------------------------------------------------- **
+ * This module uses a singly-linked list to implement both a queue and a
+ * stack. For a queue, entries are added at the tail and removed from the
+ * head of the list. For a stack, the entries are entered and removed from
+ * the head of the list. A traversal of the list will always start at the
+ * head of the list and proceed toward the tail. This is all mind-numbingly
+ * simple, but I'm surprised by the number of programs out there which
+ * re-implement this a dozen or so times.
+ *
+ * Note: When the list header is initialized, the Tail pointer is set to
+ * point to the Head pointer. This simplifies the InsTail function
+ * at little or no cost to InsHead or Remove. The one problem is
+ * that you can't initialize a stack or queue headerby simply zeroing
+ * it out. One sure way to initialize the header is to call
+ * ubi_sqInit(). Another option would be something like this:
+ *
+ * static ubi_sqList MyList = { NULL, (ubi_sqNodePtr)&MyList, 0 };
+ *
+ * See ubi_sqInit() and the ubi_sqList structure for more info.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * Revision 0.1 1997/10/24 02:48:23 crh
+ * Initial revision.
+ *
+ * ========================================================================== **
+ */
+
+#include <stdlib.h>
+
+
+/* ========================================================================== **
+ * Typedefs...
+ *
+ * ubi_sqNode - This is the basic node structure.
+ * ubi_sqNodePtr - Pointer to a node.
+ * ubi_sqList - This is the stack & queue header structure.
+ * ubi_sqListPtr - Pointer to a stack & queue header.
+ *
+ */
+
+typedef struct ubi_sqListNode
+ {
+ struct ubi_sqListNode *Next;
+ } ubi_sqNode;
+
+typedef ubi_sqNode *ubi_sqNodePtr;
+
+typedef struct
+ {
+ ubi_sqNodePtr Head;
+ ubi_sqNodePtr Tail;
+ unsigned long count;
+ } ubi_sqList;
+
+typedef ubi_sqList *ubi_sqListPtr;
+
+/* ========================================================================== **
+ * Macros...
+ *
+ * ubi_sqEnqueue - Add a new node at the tail of a queue.
+ * ubi_sqDequeue - Remove a node from the head of the queue.
+ * ubi_sqPush - Add a new node at the head of the queue.
+ * ubi_sqPop - Remove a node from the head of the queue (same as Dequeue).
+ * ubi_sqFirst - Return a pointer to the frontmost node in the queue.
+ * ubi_sqNext - Given a node, return a pointer to the next node.
+ * ubi_sqLast - Return a pointer to the last (valid) node in the queue.
+ *
+ * Note that all of these provide type casting of the parameters. The
+ * Enqueue/Dequeue macros are nothing more than nice front-ends to the
+ * Insert and Remove operations.
+ *
+ */
+
+#define ubi_sqEnqueue( L, N ) \
+ ubi_sqInsTail( (ubi_sqListPtr)(L), (ubi_sqNodePtr)(N) )
+
+#define ubi_sqDequeue( L ) ubi_sqRemove( (ubi_sqListPtr)(L) )
+
+#define ubi_sqPush( L, N ) \
+ ubi_sqInsHead( (ubi_sqListPtr)(L), (ubi_sqNodePtr)(N) )
+
+#define ubi_sqPop ubi_sqDequeue
+
+#define ubi_sqFirst( L ) (((ubi_sqListPtr)(L))->Head)
+
+#define ubi_sqNext( N ) (((ubi_sqNodePtr)(N))->Next)
+
+#define ubi_sqLast( L ) \
+ ( (((ubi_sqListPtr)(L))->Head) ? (((ubi_sqListPtr)(L))->Tail) : NULL )
+
+
+/* ========================================================================== **
+ * Function prototypes...
+ */
+
+ubi_sqListPtr ubi_sqInit( ubi_sqListPtr ListPtr );
+ /* ------------------------------------------------------------------------ **
+ * Initialize a stack & queue header.
+ *
+ * Input: ListPtr - A pointer to the list header that is to be
+ * initialized for use.
+ *
+ * Output: A pointer to the initialized list header (i.e., same as
+ * <ListPtr>).
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_sqNodePtr ubi_sqInsHead( ubi_sqListPtr ListPtr, ubi_sqNodePtr New );
+ /* ------------------------------------------------------------------------ **
+ * Insert a new node at the head of the list (push).
+ *
+ * Input: ListPtr - A pointer to the stack into which the node is to
+ * be inserted.
+ * New - Pointer to the node that is to be pushed onto the
+ * stack.
+ *
+ * Output: A pointer to the node that was added to the list (i.e., same
+ * same as <New>).
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_sqNodePtr ubi_sqInsTail( ubi_sqListPtr ListPtr, ubi_sqNodePtr New );
+ /* ------------------------------------------------------------------------ **
+ * Add a new node to the tail of the list (enqueue).
+ *
+ * Input: ListPtr - A pointer to the queue into which the node is to
+ * be inserted.
+ * New - Pointer to the node that is to be enqueued.
+ *
+ * Output: A pointer to the node that was inserted into the queue (i.e.,
+ * the same as <New>).
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_sqNodePtr ubi_sqRemove( ubi_sqListPtr ListPtr );
+ /* ------------------------------------------------------------------------ **
+ * Remove the frontmost entry from the queue, or topmost entry from the
+ * stack.
+ *
+ * Input: ListPtr - A pointer to the list from which the node is to be
+ * removed.
+ *
+ * Output: A pointer to the node that was removed.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+/* ================================ The End ================================= */
+#endif /* ubi_StackQueue_H */
diff --git a/source/ubiqx/ubi_dLinkList.c b/source/ubiqx/ubi_dLinkList.c
new file mode 100644
index 00000000000..5d970a9ca13
--- /dev/null
+++ b/source/ubiqx/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/ubiqx/ubi_dLinkList.h b/source/ubiqx/ubi_dLinkList.h
new file mode 100644
index 00000000000..1facf92d3b1
--- /dev/null
+++ b/source/ubiqx/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/ubiqx/ubi_sLinkList.c b/source/ubiqx/ubi_sLinkList.c
new file mode 100644
index 00000000000..5414d5f71de
--- /dev/null
+++ b/source/ubiqx/ubi_sLinkList.c
@@ -0,0 +1,112 @@
+/* ========================================================================== **
+ * ubi_sLinkList.c
+ *
+ * Copyright (C) 1997 by Christopher R. Hertel
+ *
+ * Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ * This module implements a really simple singly-linked list.
+ * -------------------------------------------------------------------------- **
+ *
+ * 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.2 1997/10/21 03:35:18 crh
+ * Added parameter <After> in function Insert(). Made necessary changes
+ * to macro AddHead() and added macro AddHere().
+ *
+ * Revision 0.1 1997/10/16 02:53:45 crh
+ * Initial Revision.
+ *
+ * ========================================================================== **
+ */
+
+#include "ubi_sLinkList.h"
+
+/* ========================================================================== **
+ * Functions...
+ */
+
+ubi_slListPtr ubi_slInitList( ubi_slListPtr ListPtr )
+ /* ------------------------------------------------------------------------ **
+ * Initialize a singly-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->count = 0;
+ return( ListPtr );
+ } /* ubi_slInitList */
+
+ubi_slNodePtr ubi_slInsert( ubi_slListPtr ListPtr,
+ ubi_slNodePtr New,
+ ubi_slNodePtr After )
+ /* ------------------------------------------------------------------------ **
+ * Insert a new node at the head of the list.
+ *
+ * Input: ListPtr - A pointer to the list into which the node is to
+ * be inserted.
+ * New - Pointer to the node that is to be added to the list.
+ * After - Pointer to a list in a node after which the new node
+ * will be inserted. If NULL, then the new node will
+ * be added at the head of the list.
+ *
+ * Output: A pointer to the node that was inserted into the list (i.e.,
+ * the same as <New>).
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_slNodePtr *PredPtr;
+
+ PredPtr = ( NULL == After ) ? &(ListPtr->Head) : &(After->Next);
+ New->Next = *PredPtr;
+ *PredPtr = New;
+ ++(ListPtr->count);
+ return( New );
+ } /* ubi_slInsert */
+
+ubi_slNodePtr ubi_slRemove( ubi_slListPtr ListPtr )
+ /* ------------------------------------------------------------------------ **
+ * Remove a node from the head of the list.
+ *
+ * Input: ListPtr - A pointer to the list from which the node is to be
+ * removed.
+ *
+ * Output: A pointer to the node that was removed.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_slNodePtr Old = ListPtr->Head;
+
+ if( NULL != Old )
+ {
+ ListPtr->Head = Old->Next;
+ --(ListPtr->count);
+ }
+ return( Old );
+ } /* ubi_slRemove */
+
+
+/* ================================ The End ================================= */
diff --git a/source/ubiqx/ubi_sLinkList.h b/source/ubiqx/ubi_sLinkList.h
new file mode 100644
index 00000000000..7d546f06e95
--- /dev/null
+++ b/source/ubiqx/ubi_sLinkList.h
@@ -0,0 +1,145 @@
+#ifndef ubi_sLinkList_H
+#define ubi_sLinkList_H
+/* ========================================================================== **
+ * ubi_sLinkList.h
+ *
+ * Copyright (C) 1997 by Christopher R. Hertel
+ *
+ * Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ * This module implements a really simple singly-linked list.
+ * -------------------------------------------------------------------------- **
+ *
+ * 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.2 1997/10/21 03:36:14 crh
+ * Added parameter <After> in function Insert(). Made necessary changes
+ * to macro AddHead() and added macro AddHere().
+ *
+ * Revision 0.1 1997/10/16 02:54:08 crh
+ * Initial Revision.
+ *
+ * ========================================================================== **
+ */
+
+#include <stdlib.h>
+
+
+/* ========================================================================== **
+ * Typedefs...
+ *
+ * ubi_slNode - This is the basic node structure.
+ * ubi_slNodePtr - Pointer to a node.
+ * ubi_slList - This is the list header structure.
+ * ubi_slListPtr - Pointer to a List (i.e., a list header structure).
+ *
+ */
+
+typedef struct ubi_slListNode
+ {
+ struct ubi_slListNode *Next;
+ } ubi_slNode;
+
+typedef ubi_slNode *ubi_slNodePtr;
+
+typedef struct
+ {
+ ubi_slNodePtr Head;
+ unsigned long count;
+ } ubi_slList;
+
+typedef ubi_slList *ubi_slListPtr;
+
+/* ========================================================================== **
+ * Macros...
+ *
+ * ubi_slAddHead - Add a new node at the head of the list.
+ * ubi_slRemHead - Remove the node at the head of the list, if any.
+ * ubi_slFirst - Return a pointer to the first node in the list, if any.
+ * ubi_slNext - Given a node, return a pointer to the next 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_slAddHead( L, N ) \
+ ubi_slInsert( (ubi_slListPtr)(L), (ubi_slNodePtr)(N), NULL )
+
+#define ubi_slAddHere( L, N, P ) \
+ ubi_slInsert( (ubi_slListPtr)(L), \
+ (ubi_slNodePtr)(N), \
+ (ubi_slNodePtr)(P) )
+
+#define ubi_slRemHead( L ) ubi_slRemove( (ubi_slListPtr)(L) )
+
+#define ubi_slFirst( L ) (((ubi_slListPtr)(L))->Head)
+
+#define ubi_slNext( N ) (((ubi_slNodePtr)(N))->Next)
+
+
+/* ========================================================================== **
+ * Function prototypes...
+ */
+
+ubi_slListPtr ubi_slInitList( ubi_slListPtr ListPtr );
+ /* ------------------------------------------------------------------------ **
+ * Initialize a singly-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_slNodePtr ubi_slInsert( ubi_slListPtr ListPtr,
+ ubi_slNodePtr New,
+ ubi_slNodePtr After );
+ /* ------------------------------------------------------------------------ **
+ * Insert a new node at the head of the list.
+ *
+ * Input: ListPtr - A pointer to the list into which the node is to
+ * be inserted.
+ * New - Pointer to the node that is to be added to the list.
+ * After - Pointer to a list in a node after which the new node
+ * will be inserted. If NULL, then the new node will
+ * be added at the head of the list.
+ *
+ * Output: A pointer to the node that was inserted into the list (i.e.,
+ * the same as <New>).
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_slNodePtr ubi_slRemove( ubi_slListPtr ListPtr );
+ /* ------------------------------------------------------------------------ **
+ * Remove a node from the head of the list.
+ *
+ * Input: ListPtr - A pointer to the list from which the node is to be
+ * removed.
+ *
+ * Output: A pointer to the node that was removed.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+/* ================================ The End ================================= */
+#endif /* ubi_sLinkList_H */
diff --git a/source/utils/make_printerdef.c b/source/utils/make_printerdef.c
new file mode 100644
index 00000000000..22621112739
--- /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 = NULL;
+ 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..1f74d7a130f 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;
}
@@ -99,8 +77,12 @@ static void usage(void)
printf("Version %s\n",VERSION);
printf("\t-d debuglevel set the debuglevel\n");
printf("\t-B broadcast address the address to use for broadcasts\n");
+ printf("\t-U unicast address the address to use for unicast\n");
printf("\t-M searches for a master browser\n");
+ printf("\t-R set recursion desired in packet\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,14 +93,20 @@ 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;
+ BOOL recursion_desired = False;
+
DEBUGLEVEL = 1;
*lookup = 0;
@@ -128,18 +116,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:SMrhAR")) != 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':
@@ -148,13 +141,25 @@ int main(int argc,char *argv[])
case 'S':
find_status = True;
break;
+ case 'R':
+ recursion_desired = True;
+ break;
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 +170,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 +216,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,recursion_desired,
+ 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..225b7fde83d 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;
@@ -51,7 +48,7 @@ static int gethexpwd(char *p, char *pwd)
return (True);
}
-struct smb_passwd *
+static struct smb_passwd *
_my_get_smbpwnam(FILE * fp, char *name, BOOL * valid_old_pwd,
BOOL *got_valid_nt_entry, long *pwd_seekpos)
{
@@ -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/utils/torture.c b/source/utils/torture.c
new file mode 100644
index 00000000000..8711af3fe1a
--- /dev/null
+++ b/source/utils/torture.c
@@ -0,0 +1,919 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SMB torture tester
+ 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 fstring host, workgroup, share, password, username, myname;
+static int max_protocol = PROTOCOL_NT1;
+static char *sockops="";
+
+
+static struct timeval tp1,tp2;
+
+static void start_timer()
+{
+ gettimeofday(&tp1,NULL);
+}
+
+static double end_timer()
+{
+ gettimeofday(&tp2,NULL);
+ return((tp2.tv_sec - tp1.tv_sec) +
+ (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
+}
+
+
+static BOOL open_connection(struct cli_state *c)
+{
+ if (!cli_initialise(c) || !cli_connect(c, host, NULL)) {
+ printf("Failed to connect with %s\n", host);
+ return False;
+ }
+
+ if (!cli_session_request(c, host, 0x20, myname)) {
+ printf("%s rejected the session\n",host);
+ cli_shutdown(c);
+ return False;
+ }
+
+ c->protocol = max_protocol;
+
+ if (!cli_negprot(c)) {
+ printf("%s rejected the negprot (%s)\n",host, cli_errstr(c));
+ cli_shutdown(c);
+ return False;
+ }
+
+ if (!cli_session_setup(c, username, password, strlen(password),
+ "", 0, workgroup)) {
+ printf("%s rejected the sessionsetup (%s)\n", host, cli_errstr(c));
+ cli_shutdown(c);
+ return False;
+ }
+
+ if (!cli_send_tconX(c, share, "A:", password, strlen(password)+1)) {
+ printf("%s refused tree connect (%s)\n", host, cli_errstr(c));
+ cli_shutdown(c);
+ return False;
+ }
+
+ return True;
+}
+
+
+
+static void close_connection(struct cli_state *c)
+{
+ if (!cli_tdis(c)) {
+ printf("tdis failed (%s)\n", cli_errstr(c));
+ }
+
+ cli_shutdown(c);
+}
+
+
+static BOOL wait_lock(struct cli_state *c, int fnum, uint32 offset, uint32 len)
+{
+ while (!cli_lock(c, fnum, offset, len, -1)) {
+ int eclass, num;
+ cli_error(c, &eclass, &num);
+ if (eclass != ERRDOS || num != ERRlock) {
+ printf("lock failed (%s)\n",
+ cli_errstr(c));
+ return False;
+ }
+ }
+ return True;
+}
+
+
+static BOOL rw_torture(struct cli_state *c, int numops)
+{
+ char *lockfname = "\\torture.lck";
+ fstring fname;
+ int fnum;
+ int fnum2;
+ int pid2, pid = getpid();
+ int i;
+
+ fnum2 = cli_open(c, lockfname, O_RDWR | O_CREAT | O_EXCL,
+ DENY_NONE);
+ if (fnum2 == -1)
+ fnum2 = cli_open(c, lockfname, O_RDWR, DENY_NONE);
+ if (fnum2 == -1) {
+ printf("open of %s failed (%s)\n", lockfname, cli_errstr(c));
+ return False;
+ }
+
+
+ for (i=0;i<numops;i++) {
+ unsigned n = (unsigned)random()%10;
+ if (i % 10 == 0) {
+ printf("%d\r", i); fflush(stdout);
+ }
+ sprintf(fname,"\\torture.%u", n);
+
+ if (!wait_lock(c, fnum2, n*sizeof(int), sizeof(int))) {
+ return False;
+ }
+
+ fnum = cli_open(c, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
+ if (fnum == -1) {
+ printf("open failed (%s)\n", cli_errstr(c));
+ break;
+ }
+
+ if (cli_write(c, fnum, (char *)&pid, 0, sizeof(pid)) != sizeof(pid)) {
+ printf("write failed (%s)\n", cli_errstr(c));
+ }
+
+ pid2 = 0;
+
+ if (cli_read(c, fnum, (char *)&pid2, 0, sizeof(pid)) != sizeof(pid)) {
+ printf("read failed (%s)\n", cli_errstr(c));
+ }
+
+ if (pid2 != pid) {
+ printf("data corruption!\n");
+ }
+
+ if (!cli_close(c, fnum)) {
+ printf("close failed (%s)\n", cli_errstr(c));
+ }
+
+ if (!cli_unlink(c, fname)) {
+ printf("unlink failed (%s)\n", cli_errstr(c));
+ }
+
+ if (!cli_unlock(c, fnum2, n*sizeof(int), sizeof(int), -1)) {
+ printf("unlock failed (%s)\n", cli_errstr(c));
+ }
+ }
+
+ cli_close(c, fnum2);
+ cli_unlink(c, lockfname);
+
+ printf("%d\n", i);
+
+ return True;
+}
+
+static void usage(void)
+{
+ printf("Usage: smbtorture \\\\server\\share <options>\n");
+
+ printf("\t-U user%%pass\n");
+ printf("\t-N numprocs\n");
+ printf("\t-n my_netbios_name\n");
+ printf("\t-W workgroup\n");
+ printf("\t-o num_operations\n");
+ printf("\t-O socket_options\n");
+ printf("\t-m maximum protocol\n");
+ printf("\n");
+
+ exit(1);
+}
+
+
+
+static void run_torture(int numops)
+{
+ static struct cli_state cli;
+
+ if (open_connection(&cli)) {
+ cli_sockopt(&cli, sockops);
+
+ printf("pid %d OK\n", getpid());
+
+ rw_torture(&cli, numops);
+
+ close_connection(&cli);
+ }
+}
+
+/*
+ This test checks for two things:
+
+ 1) correct support for retaining locks over a close (ie. the server
+ must not use posix semantics)
+ 2) support for lock timeouts
+ */
+static void run_locktest1(void)
+{
+ static struct cli_state cli1, cli2;
+ char *fname = "\\locktest.lck";
+ int fnum1, fnum2, fnum3;
+ time_t t1, t2;
+
+ if (!open_connection(&cli1) || !open_connection(&cli2)) {
+ return;
+ }
+ cli_sockopt(&cli1, sockops);
+ cli_sockopt(&cli2, sockops);
+
+ printf("starting locktest1\n");
+
+ cli_unlink(&cli1, fname);
+
+ fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return;
+ }
+ fnum2 = cli_open(&cli1, fname, O_RDWR, DENY_NONE);
+ if (fnum2 == -1) {
+ printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return;
+ }
+ fnum3 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
+ if (fnum3 == -1) {
+ printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli2));
+ return;
+ }
+
+ if (!cli_lock(&cli1, fnum1, 0, 4, 0)) {
+ printf("lock1 failed (%s)\n", cli_errstr(&cli1));
+ return;
+ }
+
+
+ if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
+ printf("lock2 succeeded! This is a locking bug\n");
+ return;
+ } else {
+ int eclass, num;
+ cli_error(&cli2, &eclass, &num);
+ if (eclass != ERRDOS || num != ERRlock) {
+ printf("error should have been ERRDOS/ERRlock (%s)\n",
+ cli_errstr(&cli2));
+ return;
+ }
+ }
+
+
+ printf("Testing lock timeouts\n");
+ t1 = time(NULL);
+ if (cli_lock(&cli2, fnum3, 0, 4, 10*1000)) {
+ printf("lock3 succeeded! This is a locking bug\n");
+ return;
+ } else {
+ int eclass, num;
+ cli_error(&cli2, &eclass, &num);
+ if (eclass != ERRDOS || num != ERRlock) {
+ printf("error should have been ERRDOS/ERRlock (%s)\n",
+ cli_errstr(&cli2));
+ return;
+ }
+ }
+ t2 = time(NULL);
+
+ if (t2 - t1 < 5) {
+ printf("error: This server appears not to support timed lock requests\n");
+ }
+
+ if (!cli_close(&cli1, fnum2)) {
+ printf("close1 failed (%s)\n", cli_errstr(&cli1));
+ return;
+ }
+
+ if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
+ printf("lock4 succeeded! This is a locking bug\n");
+ return;
+ } else {
+ int eclass, num;
+ cli_error(&cli2, &eclass, &num);
+ if (eclass != ERRDOS || num != ERRlock) {
+ printf("error should have been ERRDOS/ERRlock (%s)\n",
+ cli_errstr(&cli2));
+ return;
+ }
+ }
+
+ if (!cli_close(&cli1, fnum1)) {
+ printf("close2 failed (%s)\n", cli_errstr(&cli1));
+ return;
+ }
+
+ if (!cli_close(&cli2, fnum3)) {
+ printf("close3 failed (%s)\n", cli_errstr(&cli2));
+ return;
+ }
+
+ if (!cli_unlink(&cli1, fname)) {
+ printf("unlink failed (%s)\n", cli_errstr(&cli1));
+ return;
+ }
+
+
+ close_connection(&cli1);
+ close_connection(&cli2);
+
+ printf("Passed locktest1\n");
+}
+
+
+/*
+ This test checks that
+
+ 1) the server supports multiple locking contexts on the one SMB
+ connection, distinguished by PID.
+
+ 2) the server correctly fails overlapping locks made by the same PID (this
+ goes against POSIX behaviour, which is why it is tricky to implement)
+
+ 3) the server denies unlock requests by an incorrect client PID
+*/
+static void run_locktest2(void)
+{
+ static struct cli_state cli;
+ char *fname = "\\locktest.lck";
+ int fnum1, fnum2, fnum3;
+
+ if (!open_connection(&cli)) {
+ return;
+ }
+
+ cli_sockopt(&cli, sockops);
+
+ printf("starting locktest2\n");
+
+ cli_unlink(&cli, fname);
+
+ cli_setpid(&cli, 1);
+
+ fnum1 = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
+ return;
+ }
+
+ fnum2 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
+ if (fnum2 == -1) {
+ printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli));
+ return;
+ }
+
+ cli_setpid(&cli, 2);
+
+ fnum3 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
+ if (fnum3 == -1) {
+ printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli));
+ return;
+ }
+
+ cli_setpid(&cli, 1);
+
+ if (!cli_lock(&cli, fnum1, 0, 4, 0)) {
+ printf("lock1 failed (%s)\n", cli_errstr(&cli));
+ return;
+ }
+
+ if (cli_lock(&cli, fnum2, 0, 4, 0)) {
+ printf("lock2 succeeded! This is a locking bug\n");
+ } else {
+ int eclass, num;
+ cli_error(&cli, &eclass, &num);
+ if (eclass != ERRDOS || num != ERRlock) {
+ printf("error should have been ERRDOS/ERRlock (%s)\n",
+ cli_errstr(&cli));
+ return;
+ }
+ }
+
+ cli_setpid(&cli, 2);
+
+ if (cli_unlock(&cli, fnum1, 0, 4, 0)) {
+ printf("unlock1 succeeded! This is a locking bug\n");
+ }
+
+ if (cli_lock(&cli, fnum3, 0, 4, 0)) {
+ printf("lock3 succeeded! This is a locking bug\n");
+ } else {
+ int eclass, num;
+ cli_error(&cli, &eclass, &num);
+ if (eclass != ERRDOS || num != ERRlock) {
+ printf("error should have been ERRDOS/ERRlock (%s)\n",
+ cli_errstr(&cli));
+ return;
+ }
+ }
+
+ cli_setpid(&cli, 1);
+
+ if (!cli_close(&cli, fnum1)) {
+ printf("close1 failed (%s)\n", cli_errstr(&cli));
+ return;
+ }
+
+ if (!cli_close(&cli, fnum2)) {
+ printf("close2 failed (%s)\n", cli_errstr(&cli));
+ return;
+ }
+
+ if (!cli_close(&cli, fnum3)) {
+ printf("close3 failed (%s)\n", cli_errstr(&cli));
+ return;
+ }
+
+ close_connection(&cli);
+
+ printf("locktest2 finished\n");
+}
+
+
+/*
+ This test checks that
+
+ 1) the server supports the full offset range in lock requests
+*/
+static void run_locktest3(int numops)
+{
+ static struct cli_state cli1, cli2;
+ char *fname = "\\locktest.lck";
+ int fnum1, fnum2, i;
+ uint32 offset;
+
+#define NEXT_OFFSET offset += (~(uint32)0) / numops
+
+ if (!open_connection(&cli1) || !open_connection(&cli2)) {
+ return;
+ }
+ cli_sockopt(&cli1, sockops);
+ cli_sockopt(&cli2, sockops);
+
+ printf("starting locktest3\n");
+
+ cli_unlink(&cli1, fname);
+
+ fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return;
+ }
+ fnum2 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
+ if (fnum2 == -1) {
+ printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli2));
+ return;
+ }
+
+ for (offset=i=0;i<numops;i++) {
+ NEXT_OFFSET;
+ if (!cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
+ printf("lock1 %d failed (%s)\n",
+ i,
+ cli_errstr(&cli1));
+ return;
+ }
+
+ if (!cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
+ printf("lock2 %d failed (%s)\n",
+ i,
+ cli_errstr(&cli1));
+ return;
+ }
+ }
+
+ for (offset=i=0;i<numops;i++) {
+ NEXT_OFFSET;
+
+ if (cli_lock(&cli1, fnum1, offset-2, 1, 0)) {
+ printf("error: lock1 %d succeeded!\n", i);
+ return;
+ }
+
+ if (cli_lock(&cli2, fnum2, offset-1, 1, 0)) {
+ printf("error: lock2 %d succeeded!\n", i);
+ return;
+ }
+
+ if (cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
+ printf("error: lock3 %d succeeded!\n", i);
+ return;
+ }
+
+ if (cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
+ printf("error: lock4 %d succeeded!\n", i);
+ return;
+ }
+ }
+
+ for (offset=i=0;i<numops;i++) {
+ NEXT_OFFSET;
+
+ if (!cli_unlock(&cli1, fnum1, offset-1, 1, 0)) {
+ printf("unlock1 %d failed (%s)\n",
+ i,
+ cli_errstr(&cli1));
+ return;
+ }
+
+ if (!cli_unlock(&cli2, fnum2, offset-2, 1, 0)) {
+ printf("unlock2 %d failed (%s)\n",
+ i,
+ cli_errstr(&cli1));
+ return;
+ }
+ }
+
+ if (!cli_close(&cli1, fnum1)) {
+ printf("close1 failed (%s)\n", cli_errstr(&cli1));
+ }
+
+ if (!cli_close(&cli2, fnum2)) {
+ printf("close2 failed (%s)\n", cli_errstr(&cli2));
+ }
+
+ if (!cli_unlink(&cli1, fname)) {
+ printf("unlink failed (%s)\n", cli_errstr(&cli1));
+ return;
+ }
+
+ close_connection(&cli1);
+ close_connection(&cli2);
+
+ printf("finished locktest3\n");
+}
+
+
+/*
+ This test checks that
+
+ 1) the server does not allow an unlink on a file that is open
+*/
+static void run_unlinktest(void)
+{
+ static struct cli_state cli;
+ char *fname = "\\unlink.tst";
+ int fnum;
+
+ if (!open_connection(&cli)) {
+ return;
+ }
+
+ cli_sockopt(&cli, sockops);
+
+ printf("starting unlink test\n");
+
+ cli_unlink(&cli, fname);
+
+ cli_setpid(&cli, 1);
+
+ fnum = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
+ return;
+ }
+
+ if (cli_unlink(&cli, fname)) {
+ printf("error: server allowed unlink on an open file\n");
+ }
+
+ cli_close(&cli, fnum);
+ cli_unlink(&cli, fname);
+
+ close_connection(&cli);
+
+ printf("unlink test finished\n");
+}
+
+
+
+static void browse_callback(char *sname, uint32 stype, char *comment)
+{
+ printf("\t%20.20s %08x %s\n", sname, stype, comment);
+}
+
+
+/*
+ This test checks the browse list code
+
+*/
+static void run_browsetest(void)
+{
+ static struct cli_state cli;
+
+ printf("starting browse test\n");
+
+ if (!open_connection(&cli)) {
+ return;
+ }
+
+ printf("domain list:\n");
+ cli_NetServerEnum(&cli, workgroup,
+ SV_TYPE_DOMAIN_ENUM,
+ browse_callback);
+
+ printf("machine list:\n");
+ cli_NetServerEnum(&cli, workgroup,
+ SV_TYPE_ALL,
+ browse_callback);
+
+ close_connection(&cli);
+
+ printf("browse test finished\n");
+}
+
+
+/*
+ This checks how the getatr calls works
+*/
+static void run_attrtest(void)
+{
+ static struct cli_state cli;
+ int fnum;
+ time_t t, t2;
+ char *fname = "\\attrib.tst";
+
+ printf("starting attrib test\n");
+
+ if (!open_connection(&cli)) {
+ return;
+ }
+
+ cli_unlink(&cli, fname);
+ fnum = cli_open(&cli, fname,
+ O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+ cli_close(&cli, fnum);
+ if (!cli_getatr(&cli, fname, NULL, NULL, &t)) {
+ printf("getatr failed (%s)\n", cli_errstr(&cli));
+ }
+
+ if (abs(t - time(NULL)) > 2) {
+ printf("ERROR: SMBgetatr bug. time is %s",
+ ctime(&t));
+ t = time(NULL);
+ }
+
+ t2 = t-60*60*24; /* 1 day ago */
+
+ if (!cli_setatr(&cli, fname, 0, t2)) {
+ printf("setatr failed (%s)\n", cli_errstr(&cli));
+ }
+
+ if (!cli_getatr(&cli, fname, NULL, NULL, &t)) {
+ printf("getatr failed (%s)\n", cli_errstr(&cli));
+ }
+
+ if (t != t2) {
+ printf("ERROR: getatr/setatr bug. times are\n%s",
+ ctime(&t));
+ printf("%s", ctime(&t2));
+ }
+
+ cli_unlink(&cli, fname);
+
+ close_connection(&cli);
+
+ printf("attrib test finished\n");
+}
+
+
+/*
+ This checks a couple of trans2 calls
+*/
+static void run_trans2test(void)
+{
+ static struct cli_state cli;
+ int fnum;
+ uint32 size;
+ time_t c_time, a_time, m_time, w_time, m_time2;
+ char *fname = "\\trans2.tst";
+ char *dname = "\\trans2";
+ char *fname2 = "\\trans2\\trans2.tst";
+
+ printf("starting trans2 test\n");
+
+ if (!open_connection(&cli)) {
+ return;
+ }
+
+ cli_unlink(&cli, fname);
+ fnum = cli_open(&cli, fname,
+ O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+ if (!cli_qfileinfo(&cli, fnum, &c_time, &a_time, &m_time, &size)) {
+ printf("ERROR: qfileinfo failed (%s)\n", cli_errstr(&cli));
+ }
+ cli_close(&cli, fnum);
+
+ sleep(2);
+
+ cli_unlink(&cli, fname);
+ fnum = cli_open(&cli, fname,
+ O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+ cli_close(&cli, fnum);
+
+ if (!cli_qpathinfo(&cli, fname, &c_time, &a_time, &m_time, &size)) {
+ printf("ERROR: qpathinfo failed (%s)\n", cli_errstr(&cli));
+ } else {
+ if (c_time != m_time) {
+ printf("create time=%s", ctime(&c_time));
+ printf("modify time=%s", ctime(&m_time));
+ printf("This system appears to have sticky create times\n");
+ }
+ if (a_time % (60*60) == 0) {
+ printf("access time=%s", ctime(&a_time));
+ printf("This system appears to set a midnight access time\n");
+ }
+
+ if (abs(m_time - time(NULL)) > 60*60*24*7) {
+ printf("ERROR: totally incorrect times - maybe word reversed?\n");
+ }
+ }
+
+
+ cli_unlink(&cli, fname);
+ fnum = cli_open(&cli, fname,
+ O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+ cli_close(&cli, fnum);
+ if (!cli_qpathinfo2(&cli, fname, &c_time, &a_time, &m_time,
+ &w_time, &size)) {
+ printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
+ } else {
+ if (w_time < 60*60*24*2) {
+ printf("write time=%s", ctime(&w_time));
+ printf("This system appears to set a initial 0 write time\n");
+ }
+ }
+
+ cli_unlink(&cli, fname);
+
+
+ /* check if the server updates the directory modification time
+ when creating a new file */
+ if (!cli_mkdir(&cli, dname)) {
+ printf("ERROR: mkdir failed (%s)\n", cli_errstr(&cli));
+ }
+ sleep(3);
+ if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time,
+ &w_time, &size)) {
+ printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
+ }
+
+ fnum = cli_open(&cli, fname2,
+ O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+ cli_write(&cli, fnum, (char *)&fnum, 0, sizeof(fnum));
+ cli_close(&cli, fnum);
+ if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time2,
+ &w_time, &size)) {
+ printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
+ } else {
+ if (m_time2 == m_time)
+ printf("This system does not update directory modification times\n");
+ }
+ cli_unlink(&cli, fname2);
+ cli_rmdir(&cli, dname);
+
+
+ close_connection(&cli);
+
+ printf("trans2 test finished\n");
+}
+
+
+static void create_procs(int nprocs, int numops)
+{
+ int i, status;
+
+ for (i=0;i<nprocs;i++) {
+ if (fork() == 0) {
+ int mypid = getpid();
+ srandom(mypid ^ time(NULL));
+ run_torture(numops);
+ _exit(0);
+ }
+ }
+
+ for (i=0;i<nprocs;i++)
+ waitpid(0, &status, 0);
+}
+
+
+
+/****************************************************************************
+ main program
+****************************************************************************/
+ int main(int argc,char *argv[])
+{
+ int nprocs=1, numops=100;
+ int opt;
+ char *p;
+ int gotpass = 0;
+ extern char *optarg;
+ extern int optind;
+ extern FILE *dbf;
+
+ dbf = stdout;
+
+ charset_initialise();
+
+ if (argc < 2) {
+ usage();
+ }
+
+ if (strncmp(argv[1], "\\\\", 2)) {
+ usage();
+ }
+
+ fstrcpy(host, &argv[1][2]);
+ p = strchr(&host[2],'\\');
+ if (!p) {
+ usage();
+ }
+ *p = 0;
+ fstrcpy(share, p+1);
+
+ get_myname(myname,NULL);
+
+ if (*username == 0 && getenv("LOGNAME")) {
+ strcpy(username,getenv("LOGNAME"));
+ }
+
+ argc--;
+ argv++;
+
+
+ while ((opt = getopt(argc, argv, "hW:U:n:N:O:o:m:")) != EOF) {
+ switch (opt) {
+ case 'W':
+ fstrcpy(workgroup,optarg);
+ break;
+ case 'm':
+ max_protocol = interpret_protocol(optarg, max_protocol);
+ break;
+ case 'N':
+ nprocs = atoi(optarg);
+ break;
+ case 'o':
+ numops = atoi(optarg);
+ break;
+ case 'O':
+ sockops = optarg;
+ break;
+ case 'n':
+ fstrcpy(myname, optarg);
+ break;
+ case 'U':
+ strcpy(username,optarg);
+ p = strchr(username,'%');
+ if (p) {
+ *p = 0;
+ strcpy(password, p+1);
+ gotpass = 1;
+ }
+ break;
+ default:
+ printf("Unknown option %c (%d)\n", (char)opt, opt);
+ usage();
+ }
+ }
+
+
+ while (!gotpass) {
+ p = getpass("Password:");
+ if (p) {
+ strcpy(password, p);
+ gotpass = 1;
+ }
+ }
+
+ printf("host=%s share=%s user=%s myname=%s\n",
+ host, share, username, myname);
+
+ start_timer();
+ create_procs(nprocs, numops);
+ printf("rw_torture: %g secs\n", end_timer());
+
+ run_locktest1();
+ run_locktest2();
+ run_locktest3(numops);
+ run_unlinktest();
+ run_browsetest();
+ run_attrtest();
+ run_trans2test();
+
+ return(0);
+}
+
+
diff --git a/source/web/cgi.c b/source/web/cgi.c
new file mode 100644
index 00000000000..f165c56110b
--- /dev/null
+++ b/source/web/cgi.c
@@ -0,0 +1,621 @@
+/*
+ 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 <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pwd.h>
+
+#define MAX_VARIABLES 10000
+
+#ifdef DEBUG_COMMENTS
+extern void print_title(char *fmt, ...);
+#endif
+
+struct var {
+ char *name;
+ char *value;
+};
+
+static struct var variables[MAX_VARIABLES];
+static int num_variables;
+static int content_length;
+static int request_post;
+static int request_get;
+static char *query_string;
+
+static void unescape(char *buf)
+{
+ char *p=buf;
+
+ while ((p=strchr(p,'+')))
+ *p = ' ';
+
+ p = buf;
+
+ while (p && *p && (p=strchr(p,'%'))) {
+ int c1 = p[1];
+ int c2 = p[2];
+
+ 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 {p++; continue;}
+
+ 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 {p++; continue;}
+
+ *p = (c1<<4) | c2;
+
+ memcpy(p+1, p+3, strlen(p+3)+1);
+ p++;
+ }
+}
+
+
+static char *grab_line(FILE *f, int *cl)
+{
+ char *ret;
+ int i = 0;
+ int len = 1024;
+
+ ret = (char *)malloc(len);
+ if (!ret) return NULL;
+
+
+ while ((*cl)) {
+ int c = fgetc(f);
+ (*cl)--;
+
+ if (c == EOF) {
+ (*cl) = 0;
+ break;
+ }
+
+ if (c == '\r') continue;
+
+ if (strchr("\n&", c)) break;
+
+ ret[i++] = c;
+
+ if (i == len-1) {
+ char *ret2;
+ ret2 = (char *)realloc(ret, len*2);
+ if (!ret2) return ret;
+ len *= 2;
+ ret = ret2;
+ }
+ }
+
+
+ ret[i] = 0;
+ return ret;
+}
+
+/***************************************************************************
+ load all the variables passed to the CGI program. May have multiple variables
+ with the same name and the same or different values. Takes a file parameter
+ for simulating CGI invocation eg loading saved preferences.
+ ***************************************************************************/
+void cgi_load_variables(FILE *f1)
+{
+ FILE *f = f1;
+ static char *line;
+ char *p, *s, *tok;
+ int len;
+
+#ifdef DEBUG_COMMENTS
+ char dummy[100]="";
+ print_title(dummy);
+ printf("<!== Start dump in cgi_load_variables() %s ==>\n",__FILE__);
+#endif
+
+ if (!f1) {
+ f = stdin;
+ if (!content_length) {
+ p = getenv("CONTENT_LENGTH");
+ len = p?atoi(p):0;
+ } else {
+ len = content_length;
+ }
+ } else {
+ fseek(f, 0, SEEK_END);
+ len = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ }
+
+
+ if (len > 0 &&
+ (f1 || request_post ||
+ ((s=getenv("REQUEST_METHOD")) &&
+ strcasecmp(s,"POST")==0))) {
+ while (len && (line=grab_line(f, &len))) {
+ p = strchr(line,'=');
+ if (!p) continue;
+
+ *p = 0;
+
+ variables[num_variables].name = strdup(line);
+ variables[num_variables].value = strdup(p+1);
+
+ free(line);
+
+ if (!variables[num_variables].name ||
+ !variables[num_variables].value)
+ continue;
+
+ unescape(variables[num_variables].value);
+ unescape(variables[num_variables].name);
+
+#ifdef DEBUG_COMMENTS
+ printf("<!== POST var %s has value \"%s\" ==>\n",
+ variables[num_variables].name,
+ variables[num_variables].value);
+#endif
+
+ num_variables++;
+ if (num_variables == MAX_VARIABLES) break;
+ }
+ }
+
+ if (f1) {
+#ifdef DEBUG_COMMENTS
+ printf("<!== End dump in cgi_load_variables() ==>\n");
+#endif
+ return;
+ }
+
+ fclose(stdin);
+
+ if ((s=query_string) || (s=getenv("QUERY_STRING"))) {
+ for (tok=strtok(s,"&;");tok;tok=strtok(NULL,"&;")) {
+ p = strchr(tok,'=');
+ if (!p) continue;
+
+ *p = 0;
+
+ variables[num_variables].name = strdup(tok);
+ variables[num_variables].value = strdup(p+1);
+
+ if (!variables[num_variables].name ||
+ !variables[num_variables].value)
+ continue;
+
+ unescape(variables[num_variables].value);
+ unescape(variables[num_variables].name);
+
+#ifdef DEBUG_COMMENTS
+ printf("<!== Commandline var %s has value \"%s\" ==>\n",
+ variables[num_variables].name,
+ variables[num_variables].value);
+#endif
+ num_variables++;
+ if (num_variables == MAX_VARIABLES) break;
+ }
+
+ }
+#ifdef DEBUG_COMMENTS
+ printf("<!== End dump in cgi_load_variables() ==>\n");
+#endif
+}
+
+
+/***************************************************************************
+ find a variable passed via CGI
+ Doesn't quite do what you think in the case of POST text variables, because
+ if they exist they might have a value of "" or even " ", depending on the
+ browser. Also doesn't allow for variables[] containing multiple variables
+ with the same name and the same or different values.
+ ***************************************************************************/
+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 a particular cgi variable
+ ***************************************************************************/
+char *cgi_vnum(int i, char **name)
+{
+ if (i < 0 || i >= num_variables) return NULL;
+ *name = variables[i].name;
+ return variables[i].value;
+}
+
+/***************************************************************************
+ 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;
+}
+
+/***************************************************************************
+like strdup() but quotes < > and &
+ ***************************************************************************/
+char *quotedup(char *s)
+{
+ int i, n=0;
+ int len;
+ char *ret;
+ char *d;
+
+ if (!s) return strdup("");
+
+ len = strlen(s);
+
+ for (i=0;i<len;i++)
+ if (s[i] == '<' || s[i] == '>' || s[i] == '&')
+ n++;
+
+ ret = malloc(len + n*6 + 1);
+
+ if (!ret) return NULL;
+
+ d = ret;
+
+ for (i=0;i<len;i++) {
+ switch (s[i]) {
+ case '<':
+ strcpy(d, "&lt;");
+ d += 4;
+ break;
+
+ case '>':
+ strcpy(d, "&gt;");
+ d += 4;
+ break;
+
+ case '&':
+ strcpy(d, "&amp;");
+ d += 5;
+ break;
+
+ default:
+ *d++ = s[i];
+ }
+ }
+
+ *d = 0;
+
+ return ret;
+}
+
+
+/***************************************************************************
+like strdup() but quotes a wide range of characters
+ ***************************************************************************/
+char *urlquote(char *s)
+{
+ int i, n=0;
+ int len;
+ char *ret;
+ char *d;
+ char *qlist = "\"\n\r'&<> \t+;";
+
+ if (!s) return strdup("");
+
+ len = strlen(s);
+
+ for (i=0;i<len;i++)
+ if (strchr(qlist, s[i])) n++;
+
+ ret = malloc(len + n*2 + 1);
+
+ if (!ret) return NULL;
+
+ d = ret;
+
+ for (i=0;i<len;i++) {
+ if (strchr(qlist,s[i])) {
+ sprintf(d, "%%%02X", (int)s[i]);
+ d += 3;
+ } else {
+ *d++ = s[i];
+ }
+ }
+
+ *d = 0;
+
+ return ret;
+}
+
+
+/***************************************************************************
+like strdup() but quotes " characters
+ ***************************************************************************/
+char *quotequotes(char *s)
+{
+ int i, n=0;
+ int len;
+ char *ret;
+ char *d;
+
+ if (!s) return strdup("");
+
+ len = strlen(s);
+
+ for (i=0;i<len;i++)
+ if (s[i] == '"')
+ n++;
+
+ ret = malloc(len + n*6 + 1);
+
+ if (!ret) return NULL;
+
+ d = ret;
+
+ for (i=0;i<len;i++) {
+ switch (s[i]) {
+ case '"':
+ strcpy(d, "&quot;");
+ d += 6;
+ break;
+
+ default:
+ *d++ = s[i];
+ }
+ }
+
+ *d = 0;
+
+ return ret;
+}
+
+
+/***************************************************************************
+quote spaces in a buffer
+ ***************************************************************************/
+void quote_spaces(char *buf)
+{
+ while (*buf) {
+ if (*buf == ' ') *buf = '+';
+ buf++;
+ }
+}
+
+
+
+/***************************************************************************
+tell a browser about a fatal error in the http processing
+ ***************************************************************************/
+static void cgi_setup_error(char *err, char *header, char *info)
+{
+ printf("HTTP/1.1 %s\r\n%sConnection: close\r\nContent-Type: text/html\r\n\r\n<HTML><HEAD><TITLE>%s</TITLE></HEAD><BODY><H1>%s</H1>%s<p></BODY></HTML>\r\n", err, header, err, err, info);
+ exit(0);
+}
+
+
+/***************************************************************************
+decode a base64 string in-place - simple and slow algorithm
+ ***************************************************************************/
+static void base64_decode(char *s)
+{
+ char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ int bit_offset, byte_offset, idx, i;
+ unsigned char *d = (unsigned char *)s;
+ char *p;
+
+ i=0;
+
+ while (*s && (p=strchr(b64,*s))) {
+ idx = (int)(p - b64);
+ byte_offset = (i*6)/8;
+ bit_offset = (i*6)%8;
+ d[byte_offset] &= ~((1<<(8-bit_offset))-1);
+ if (bit_offset < 3) {
+ d[byte_offset] |= (idx << (2-bit_offset));
+ } else {
+ d[byte_offset] |= (idx >> (bit_offset-2));
+ d[byte_offset+1] = 0;
+ d[byte_offset+1] |= (idx << (8-(bit_offset-2))) & 0xFF;
+ }
+ s++; i++;
+ }
+}
+
+
+/***************************************************************************
+handle a http authentication line
+ ***************************************************************************/
+static int cgi_handle_authorization(char *line)
+{
+ char *p, *user, *pass;
+ struct passwd *pwd;
+ int ret=0;
+
+ if (strncasecmp(line,"Basic ", 6)) {
+ cgi_setup_error("401 Bad Authorization", "",
+ "Only basic authorization is understood");
+ }
+ line += 6;
+ while (line[0] == ' ') line++;
+ base64_decode(line);
+ if (!(p=strchr(line,':'))) {
+ cgi_setup_error("401 Bad Authorization", "",
+ "username/password must be supplied");
+ }
+ *p = 0;
+ user = line;
+ pass = p+1;
+
+ /* currently only allow connections as root */
+ if (strcasecmp(user,"root")) {
+ cgi_setup_error("401 Bad Authorization", "",
+ "incorrect username/password");
+ }
+
+ pwd = getpwnam(user);
+
+ if (!strcmp((char *)crypt(pass, pwd->pw_passwd),pwd->pw_passwd)) {
+ ret = 1;
+ }
+
+ memset(pass, 0, strlen(pass));
+
+ return ret;
+}
+
+
+/***************************************************************************
+handle a file download
+ ***************************************************************************/
+static void cgi_download(char *file)
+{
+ struct stat st;
+ char buf[1024];
+ int fd, l, i;
+ char *p;
+
+ /* sanitise the filename */
+ for (i=0;file[i];i++) {
+ if (!isalnum(file[i]) && !strchr("/.-_", file[i])) {
+ cgi_setup_error("404 File Not Found","",
+ "Illegal character in filename");
+ }
+ }
+
+ if (strstr(file,"..")) {
+ cgi_setup_error("404 File Not Found","",
+ "Relative paths not allowed");
+ }
+
+ if (!file_exist(file, &st)) {
+ cgi_setup_error("404 File Not Found","",
+ "The requested file was not found");
+ }
+ fd = open(file,O_RDONLY);
+ if (fd == -1) {
+ cgi_setup_error("404 File Not Found","",
+ "The requested file was not found");
+ }
+ printf("HTTP/1.1 200 OK\r\n");
+ if ((p=strrchr(file,'.'))) {
+ if (strcmp(p,".gif")==0 || strcmp(p,".jpg")==0) {
+ printf("Content-Type: image/gif\r\n");
+ } else {
+ printf("Content-Type: text/html\r\n");
+ }
+ }
+ printf("Content-Length: %d\r\n\r\n", (int)st.st_size);
+ while ((l=read(fd,buf,sizeof(buf)))>0) {
+ fwrite(buf, 1, l, stdout);
+ }
+ close(fd);
+ exit(0);
+}
+
+
+/***************************************************************************
+setup the cgi framework, handling the possability that this program is either
+run as a true cgi program by a web browser or is itself a mini web server
+ ***************************************************************************/
+void cgi_setup(char *rootdir)
+{
+ int authenticated = 0;
+ char line[1024];
+ char *url=NULL;
+ char *p;
+
+ if (chdir(rootdir)) {
+ cgi_setup_error("400 Server Error", "",
+ "chdir failed - the server is not configured correctly");
+ }
+
+ if (getenv("CONTENT_LENGTH") || getenv("REQUEST_METHOD")) {
+ /* assume we are running under a real web server */
+ return;
+ }
+
+ /* we are a mini-web server. We need to read the request from stdin
+ and handle authentication etc */
+ while (fgets(line, sizeof(line)-1, stdin)) {
+ if (line[0] == '\r' || line[0] == '\n') break;
+ if (strncasecmp(line,"GET ", 4)==0) {
+ request_get = 1;
+ url = strdup(&line[4]);
+ } else if (strncasecmp(line,"POST ", 5)==0) {
+ request_post = 1;
+ url = strdup(&line[5]);
+ } else if (strncasecmp(line,"PUT ", 4)==0) {
+ cgi_setup_error("400 Bad Request", "",
+ "This server does not accept PUT requests");
+ } else if (strncasecmp(line,"Authorization: ", 15)==0) {
+ authenticated = cgi_handle_authorization(&line[15]);
+ } else if (strncasecmp(line,"Content-Length: ", 16)==0) {
+ content_length = atoi(&line[16]);
+ }
+ /* ignore all other requests! */
+ }
+
+ if (!authenticated) {
+ cgi_setup_error("401 Authorization Required",
+ "WWW-Authenticate: Basic realm=\"root\"\r\n",
+ "You must be authenticated to use this service");
+ }
+
+ if (!url) {
+ cgi_setup_error("400 Bad Request", "",
+ "You must specify a GET or POST request");
+ }
+
+ /* trim the URL */
+ if ((p = strchr(url,' ')) || (p=strchr(url,'\t'))) {
+ *p = 0;
+ }
+ while (*url && strchr("\r\n",url[strlen(url)-1])) {
+ url[strlen(url)-1] = 0;
+ }
+
+ /* anything following a ? in the URL is part of the query string */
+ if ((p=strchr(url,'?'))) {
+ query_string = p+1;
+ *p = 0;
+ }
+
+ if (strcmp(url,"/")) {
+ cgi_download(url+1);
+ }
+
+ printf("HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Type: text/html\r\n\r\n");
+
+}
+
+
diff --git a/source/wsmbconf.c b/source/wsmbconf.c
new file mode 100644
index 00000000000..8abdd6d3985
--- /dev/null
+++ b/source/wsmbconf.c
@@ -0,0 +1,237 @@
+/*
+ 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
+
+static pstring servicesf = CONFIGFILE;
+
+
+/* start the page with standard stuff */
+static void print_header(void)
+{
+ 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");
+}
+
+/* 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. */
+static int load_config(void)
+{
+ setuid(0);
+ if (!lp_load(servicesf,False)) {
+ printf("<b>Can't load %s - using defaults</b><p>\n",
+ servicesf);
+ }
+ return 1;
+}
+
+
+static int save_reload(void)
+{
+ FILE *f;
+
+ f = fopen(servicesf,"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(servicesf,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 char *optarg;
+ extern int optind;
+ extern FILE *dbf;
+ int opt;
+
+ dbf = fopen("/dev/null", "w");
+
+ if (!dbf) dbf = stderr;
+
+ cgi_setup(WEB_ROOT);
+
+
+ while ((opt = getopt(argc, argv,"s:")) != EOF) {
+ switch (opt) {
+ case 's':
+ pstrcpy(servicesf,optarg);
+ break;
+ }
+ }
+
+
+ print_header();
+
+ charset_initialise();
+
+ if (load_config()) {
+ cgi_load_variables(NULL);
+ 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;
+}