From 5b89fe9f28c204a093c5891b84f70a2cdd9aaeca Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Sun, 13 Nov 2011 00:38:55 +0100 Subject: [PATCH] mars_nwe-0.95.pl00 --- COPYING | 339 +++++++++ INSTALL | 41 ++ Makefile | 71 ++ README | 79 ++ README.ger | 95 +++ config.h | 11 + connect.c | 1748 +++++++++++++++++++++++++++++++++++++++++++++ emutli.c | 504 +++++++++++++ emutli.h | 125 ++++ examples/config.h | 9 + examples/mk.li | 25 + examples/nw.ini | 53 ++ makefile.unx | 195 +++++ mars_nwe.lsm | 15 + ncpserv.c | 1350 ++++++++++++++++++++++++++++++++++ net.h | 405 +++++++++++ net1.c | 168 +++++ net1.h | 37 + netinit.c | 308 ++++++++ netn.c | 34 + nwclient.c | 746 +++++++++++++++++++ nwconn.c | 1370 +++++++++++++++++++++++++++++++++++ nwdbm.c | 1161 ++++++++++++++++++++++++++++++ nwdbm.h | 170 +++++ nwserv.c | 1014 ++++++++++++++++++++++++++ tools.c | 214 ++++++ tools.h | 61 ++ 27 files changed, 10348 insertions(+) create mode 100644 COPYING create mode 100644 INSTALL create mode 100644 Makefile create mode 100644 README create mode 100644 README.ger create mode 100644 config.h create mode 100644 connect.c create mode 100644 emutli.c create mode 100644 emutli.h create mode 100644 examples/config.h create mode 100755 examples/mk.li create mode 100644 examples/nw.ini create mode 100644 makefile.unx create mode 100644 mars_nwe.lsm create mode 100644 ncpserv.c create mode 100644 net.h create mode 100644 net1.c create mode 100644 net1.h create mode 100644 netinit.c create mode 100644 netn.c create mode 100644 nwclient.c create mode 100644 nwconn.c create mode 100644 nwdbm.c create mode 100644 nwdbm.h create mode 100644 nwserv.c create mode 100644 tools.c create mode 100644 tools.h diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..a43ea21 --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + 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. + + + Copyright (C) 19yy + + 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. + + , 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/INSTALL b/INSTALL new file mode 100644 index 0000000..f6b5529 --- /dev/null +++ b/INSTALL @@ -0,0 +1,41 @@ +************** GERMAN ******************** +=========> Programme erzeugen <=================== +1. make aufrufen. +2. mk.li und config.h evtl. anpassen +3. make aufrufen. +=========> Konfigurieren <=================== +nw.ini bearbeiten ! +=========> Installieren <=================== +"make install" +evtl. "make install_ini" um eine installierte ini Datei +zu *ueberschreiben* . +=========> Starten <=================== +nwserv starten ( als root !! ) +mit Linux Version 1.2.13 getestet. +Der Linux Kernel muss mit IPX Unterstuetzung erzeugt worden sein. +IPX-Interface bzw. Routen werden durch das Programm automatisch +angelegt, falls in der nw.ini Datei eine +Networknummer > 0 angegeben wurde. + +************** ENGLISH ******************* +=========> create programs <=================== +1. call make. +2. perhaps you must modify mk.li and config.h +3. call make +=========> configure <=================== +modify nw.ini ! +=========> install <=================== +"make install" +"make install_ini" to overwrite your old _installed_ ini. +=========> start programs <=================== +call nwserv ( as root !! ) + +tested with Linux Version 1.2.13. +the linux-kernel must be configured with IPX=Y. +ipx-interface and ipx-routes are setup by the program if the +network number in nw.ini is set > 0. + +Viel Erfolg / good Luck :-) + +Martin + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0c5ed36 --- /dev/null +++ b/Makefile @@ -0,0 +1,71 @@ +# Makefile mars_nwe: 16-Nov-95 +VPATH= +all: rmeflag mk.li config.h nw.ini + @if [ -r .eflag ] ; then \ + echo ""; \ + echo "********************************************************"; \ + cat .eflag; rm -f .eflag; \ + echo "";\ + echo "Please make your changes and run make again"; \ + echo "********************************************************"; \ + echo "";\ + echo ""; else ./mk.li && (\ + if [ -r .mk.notes ] ; then echo "" ; \ + echo ""; \ + echo "********************************************************" ; \ + echo ""; \ + cat .mk.notes; rm .mk.notes ; \ + echo ""; \ + echo "********************************************************" ; \ + echo ""; echo "" ; fi ) fi + +install: + ./mk.li $@ + +install_ini: nw.ini + ./mk.li $@ + +clean: mk.li nw.ini + ./mk.li $@ + +distrib: mk.li nw.ini + ./mk.li $@ + +mk.li: examples/mk.li + @if [ -r $@ ] ; then \ + cp -f $@ $@.org && ( \ + echo "********************************************************"; \ + echo "";\ + echo "saved: $@ -> $@.org, there is a new examples/$@"; \ + echo "";\ + echo "********************************************************"; \ + echo "" ) ; fi + @ echo "" + @ echo "" + @ - cp -i examples/$@ . + @ touch -c $@ + @ echo "" + @ echo "********************************************************" + @ echo "" + @ echo "perhaps $@ is new and you need to edit it." + @ echo "" + @ echo "********************************************************" + @ echo "" + @ echo "" > .eflag + +config.h: examples/config.h + @if [ -r $@ ] ; then echo "note:examples/$@ is newer then $@" >> .eflag ;\ + echo "$@ will be touched now" >> .eflag; touch -c $@ ; \ + else cp examples/$@ . ; \ + echo "$@ created (from examples/$@) Please edit $@" >> .eflag;\ + echo "and change it to your requirements." >> .eflag ; fi + +rmeflag: + @ - rm -f .eflag + +nw.ini: examples/nw.ini + @if [ -r $@ ] ; then echo "note:examples/$@ is newer then $@" > .mk.notes ; \ + echo "$@ will be touched now" >> .mk.notes; touch -c $@ ; \ + else cp -a examples/$@ . ; \ + echo "$@ created (from examples/$@) Please edit $@" > .mk.notes;\ + echo "and change it to your requirements." >> .mk.notes ; fi diff --git a/README b/README new file mode 100644 index 0000000..01541ac --- /dev/null +++ b/README @@ -0,0 +1,79 @@ +(C)opyright (C) 1993,1995 Martin Stover, Marburg, Germany + +to compile and install, please read INSTALL ! + +This is a little try to emulate some functions from +a NOVELL-SERVER under UNIX (LINUX). +The first version I have written 1993 on a USL1.1 +with TLI-Code. +1994 I have ported it to LINUX. This was easy, because +I only have to write a small TLI->SOCKET emu. + +Unfortunately I had no full description of the NCP-calls, +so many of the calls based on trying. :-( + +WARNING: this code has still many BUG's !! + +BINDERY: this are the *.pag and *.dir files. + These files are generated by the first starting + of mars_nwe and are filled with the minimal + needed Objects and Properties. + USER is SUPERVISOR with no password. + +NETWORK: If there is a real Novell-Server on the + same net-line, then the NETWORK Number of + the network device in nw.ini should match + the NETWORK Number of the Novell-Server. + +LINUX +KERNEL: the only linux-kernel depending files + are emutli.[hc]. + +short description of the processes. +1) nwserv : the main program.Initiates all and starts 'ncpserv'. + sends broadcasts, wdogs, sap and rip packets. + If nwserv is started with a parameter, then the simple + test client 'nwclient', only for debugging, is started. + +2) ncpserv: opens NCP-Socket and handles NCP-Requests. + When there comes NCP-Request 0x1111 (Get Connection Nr) + then there will be started a new process 'nwconn'. + Every client-ncp-request reaches nwconn over + ncpserv. + +3) nwconn: will be started for every connection. Is connected + to ncpserv with a pipe. + +Problems and TODO: +Many:-( +Here is a short list. + +o - Some Problems with the IPX-kernelcode. + Frame Ethernet_ii isn't ok since linux-kernel > 1.1.??. + with linux-kernel 1.1.44 is was still ok. + trouble with some linux-kernel 1.3.xx + +o - make routing better. + +o - making printing better. + +o - login's with password's. + +o - clean the code !!! + +o - make bindery code more complete. + +o - and much more ... + +Have luck with tryimg. :) + + Martin +(mstover@kool.f.eunet.de) + +BTW: The kick to make mars_nwe public was the +publication of linware ( lwared ), the Novell-Server-Emulator +from Ales Dryak (A.Dryak@sh.cvut.cz). +I hope both products kann make profit from each other. +-----> SuperNOS ala Linux ;-) +Novell don't want to make it anymore. :-( + diff --git a/README.ger b/README.ger new file mode 100644 index 0000000..e15e7aa --- /dev/null +++ b/README.ger @@ -0,0 +1,95 @@ +(C)opyright (C) 1993,1995 Martin Stover, Marburg + +Hilfe zum Kompilieren bzw. Installieren siehe in 'INSTALL' ! + +Dieses ist ein kleiner Versuch Grundfunktionen +eines Novell Servers unter UNIX (LINUX) zur Verfuegung +zu stellen. Die erste Version entstand 1993 auf einer USL1.1 +mittels TLI-Code und wurde 1994, mittels +dem modul 'emutli' (TLI -> SOCKETS) nach Linux portiert. + +Leider stand mir eine vollstaendige Beschreibung der NCP-Calls +nicht zur Verfuegung, so da die Behandlung vieler Calls +auf Vermutungen bzw. Ausprobieren basieren. :-( + +WARNUNG: Es gibt noch viele Bugs !! + +z.Z. forked nwserv nicht automatisch. Er kann jederzeit +abgebrochen und neu gestartet werden. + +Kernel muss mit IPX Unterstuetzung erzeugt worden sein. +IPX-Routen werden automatisch angelegt. + +Anmerkungen: +BINDERY: besteht aus den *.pag und *.dir Dateien. + diese Dateien werden, falls nicht vorhanden, + erzeugt und mit den Grundobjekten und Grundproperties + gefuellt. Ein automatisch angelegter USER + ist SUPERVISOR ohne Passwort. + +NETWORK: Falls auch ein Novellserver am gleichem + Strang haengt, sollte die NETWORK Nummer + des Netzwerk Devices von mars_nwe auf + die des Novellservers gesetzt werden. + +LINUX +KERNEL: Die einzigen Linux kernelabhaengigen + Dateien sind emutli.[hc] + +Beschreibung der Prozesse +1) nwserv : Hauptprogramm, initialisiert alles und startet 'ncpserv'. + schickt Broadcasts, bearbeitet SAP, RIP und WDog-Pakete + Falls nwserv mit beliebigen Parameter gestartet wird, + wird der `Testclient` Code (nwclient.c) fuer Debugging + Zwecke abgearbeitet. + +2) ncpserv: oeffnet NCP-Socket und behandelt NCP-Requests. + Bei NCP-Request 0x1111 (Get Connection Nr) wird fuer + jede Connection neuer Prozess 'nwconn' gestartet. + Jeder Client Request gelangt ueber NCP-SOCKET + nach ncpserv. + +3) nwconn: Wird fuer jede Connection angelegt. Ist mit + nwserv ueber eine PIPE verbunden, erzeugt + einen Client-Schreib Socket. + + +PROBLEME bzw. TODO's: +Vieles :-( +Hier nur eine *kleine* Auswahl. + +o - Frame Ethernet_ii geht nicht (mehr) + Liegt wohl am Kernel-ipx-Code. ?? + mit Kernel-Version 1.1.44 funktionierte es noch. + einige Kernel 1.3.xx funktionieren nicht. + +o - Routing verbessern. + +o - Drucken verbessern. + +o - Login nur mit unencrypted Passwords. + Ich kenne den Crypt-Algorithmus nicht. :-( + Habe ihn aber jetzt bei lwared (linware) gesehen :-) + +o - Saeubern !! + +o - Bindery Code vervollstaendigen. + +o - und und ... + +Viel Spa beim Ausprobieren. :) + +Ueber Erweiterungen, Korrekturen und insbesonderes der Beschreibung +der fehlenden bzw. fehlerhaften NCP-Calls wuerde ich mich freuen. + + + Martin +(mstover@kool.f.eunet.de) + +PS: Den Anstoss, mars_nwe zu veroeffentlichen, gab die +Veroeffentlichung von linware ( lwared ), dem Novell-Server-Emulator +von Ales Dryak (A.Dryak@sh.cvut.cz). +Vielleicht koennen beide Produkte voneinander profitieren. +-----> SuperNOS ala Linux ;-) +Novell will es ja leider nicht mehr machen. :-( + diff --git a/config.h b/config.h new file mode 100644 index 0000000..073d927 --- /dev/null +++ b/config.h @@ -0,0 +1,11 @@ +/* config.h: 18-Nov-95 */ +/* this config is needed by make and by cc */ +#define FILENAME_NW_INI "./nw.ini" /* location of ini (conf) file */ +#define PATHNAME_PROGS "." /* path location of progs */ + +#define MAX_CONNECTIONS 5 /* max. Number of Connections */ +#define MAX_NW_VOLS 10 /* max. Volumes */ + +#define PATHNAME_BINDERY "/tmp" /* path location of bindery */ + +#define _WDOG_TESTING_ diff --git a/connect.c b/connect.c new file mode 100644 index 0000000..10ca1f0 --- /dev/null +++ b/connect.c @@ -0,0 +1,1748 @@ +/* connect.h 21-Nov-95 */ +/* (C)opyright (C) 1993,1995 Martin Stover, Marburg, Germany + * + * 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 "net.h" + +#include + +#include + +#include +extern int errno; + +#define TEST_FNAME "PRINT.000" +static int test_handle=-1; + +typedef struct { + int fd; /* von System bei Open bzw. Create */ + long offd; /* aktueller File Offset */ + time_t tmodi; /* modification TIME */ + char name[256]; /* UNIX Dateiname */ +} FILE_HANDLE; + +typedef struct { + DIR *f; + char unixname[256]; /* kompletter unixname */ + ino_t inode; /* Unix Inode */ + time_t timestamp; /* fr letzte Allocierung */ + char *kpath; /* Ein Zeichen nach unixname */ + uint8 vol_options; /* Suchoptions */ + uint8 volume; /* Volume Number */ +} DIR_HANDLE; + +typedef struct { + uint8 *sysname; /* VOL_NAME */ + uint8 *unixname; /* UNIX-Verzeichnis */ + uint8 options; /* *_1_* alles in Kleinbuchstaben */ +} NW_VOL; + +typedef struct { + uint8 path[256]; /* directory */ + uint8 fn[256]; /* file */ + int volume; /* Volume Number */ + int has_wild; /* fn has wildcards */ +} NW_PATH; + +typedef struct { + ino_t inode; /* Unix Inode dieses Verzeichnisses */ + time_t timestamp; /* Zeitmarke */ + uint8 *path; /* path ab Volume */ + uint8 volume; /* Welches Volume */ + uint8 is_temp; /* 0:perm. 1:temp 2: spez. temp */ + uint8 drive; /* driveletter */ + uint8 task; /* actual task */ +} NW_DIR; + +#define MAX_NW_DIRS 255 +static NW_DIR dirs[MAX_NW_DIRS]; +static int used_dirs=0; +static NW_VOL vols[MAX_NW_VOLS]; +static int used_vols=0; + +static int connect_is_init = 0; + +#define MAX_FILEHANDLES 80 +#define MAX_DIRHANDLES 80 + +static FILE_HANDLE file_handles[MAX_FILEHANDLES]; +static DIR_HANDLE dir_handles[MAX_DIRHANDLES]; + +static int anz_fhandles=0; +static int anz_dirhandles=0; + +static char *build_unix_name(NW_PATH *nwpath, int modus) +/* + * returns complete UNIX path + * modus & 1 : ignore fn, (only path) + * modus & 2 : no '/' at end + */ +{ + static char unixname[300]; /* must be big enouugh */ + int volume = nwpath->volume; + char *p, *pp; + if (volume < 0 || volume >= used_vols) { + fprintf(stderr, "build_unix_name volume=%d not ok\n", volume); + strcpy(unixname, "ZZZZZZZZZZZZ"); /* vorsichthalber */ + return(unixname); + } + strcpy(unixname, vols[volume].unixname); /* first UNIXNAME VOLUME */ + + p = pp = unixname+strlen(unixname); + strcpy(p, nwpath->path); /* now the path */ + p += strlen(nwpath->path); + if ( (!(modus & 1)) && nwpath->fn[0]) + strcpy(p, nwpath->fn); /* und jetzt fn */ + else if ((modus & 2) && (*(p-1) == '/')) *(p-1) = '\0'; + if (vols[volume].options & 1) downstr((uint8*)pp); + return(unixname); +} + +static int new_file_handle(void) +{ + int rethandle = -1; + FILE_HANDLE *fh=NULL; + while (++rethandle < anz_fhandles) { + if (file_handles[rethandle].fd < 0) { /* empty slot */ + fh = &(file_handles[rethandle]); + rethandle++; + break; + } + } + if (fh == NULL) { + if (anz_fhandles < MAX_FILEHANDLES) { + fh=&(file_handles[anz_fhandles]); + rethandle = ++anz_fhandles; + } else return(0); /* no free handle anymore */ + } + /* init handle */ + fh->fd = -1; + fh->offd = 0L; + fh->tmodi = 0L; + fh->name[0] = '\0'; + return(rethandle); +} + +static int free_file_handle(int fhandle) +{ + if (fhandle > 0 && (fhandle <= anz_fhandles)) { + FILE_HANDLE *fh=&(file_handles[fhandle-1]); + if (fh->fd > -1) { + close(fh->fd); + fh->fd = -1; + if (fh->tmodi > 0L) { + /* now set date and time */ + struct utimbuf ut; + ut.actime = ut.modtime = fh->tmodi; + utime(fh->name, &ut); + } + } + if (fhandle == anz_fhandles) { + /* was last */ + anz_fhandles--; + while (anz_fhandles && file_handles[anz_fhandles-1].fd < 0) + anz_fhandles--; + } + return(0); + } + return(-0x88); /* wrong filehandle */ +} + +static int new_dir_handle(ino_t inode, NW_PATH *nwpath) +/* + * RETURN=errorcode (<0) or dir_handle + */ +{ + int rethandle; + DIR_HANDLE *fh = NULL; + time_t akttime = time(NULL); + time_t last_time = akttime; + int thandle = 0; + int nhandle = 0; + for (rethandle=0; rethandle < anz_dirhandles; rethandle++){ + fh=&(dir_handles[rethandle]); + if (fh->f == (DIR*) NULL) { + if (!nhandle) nhandle = rethandle+1; + } else if (fh->inode == inode && fh->volume == nwpath->volume){ + /* Dieser hat Vorrang */ + if (fh->f) closedir(fh->f); + fh->f = NULL; + fh->timestamp = akttime; + nhandle = rethandle+1; + break; + } else if (fh->timestamp < last_time){ + thandle = rethandle+1; + last_time = fh->timestamp; + } + } + if (!nhandle){ + if (anz_dirhandles < MAX_DIRHANDLES) { + fh=&(dir_handles[anz_dirhandles]); + rethandle = ++anz_dirhandles; + } else { + fh=&(dir_handles[thandle-1]); + if (fh->f) closedir(fh->f); + fh->f = NULL; + rethandle = thandle; + } + } else rethandle=nhandle; + + /* init dir_handle */ + fh=&(dir_handles[rethandle-1]); + strcpy(fh->unixname, build_unix_name(nwpath, 0)); + if ((fh->f = opendir(fh->unixname)) != (DIR*) NULL){ + fh->kpath = fh->unixname + strlen(fh->unixname); + fh->volume = nwpath->volume; + fh->vol_options = vols[fh->volume].options; + fh->inode = inode; + fh->timestamp = akttime; + } else { + fh->f = (DIR*)NULL; + fh->unixname[0] = '\0'; + fh->vol_options = 0; + fh->kpath = (char*)NULL; + rethandle = -0x9c; + } + return(rethandle); +} + +static int free_dir_handle(int dhandle) +{ + if (dhandle > 0 && --dhandle < anz_dirhandles) { + DIR_HANDLE *fh=&(dir_handles[dhandle]); + if (fh->f != (DIR*) NULL) { + closedir(fh->f); + fh->f = (DIR*)NULL; + } + while (anz_dirhandles && dir_handles[anz_dirhandles-1].f == (DIR*)NULL) + anz_dirhandles--; + return(0); + } + return(-0x88); /* wrong dir_handle */ +} + + +static char *get_nwpath_name(NW_PATH *p) +/* for debugging */ +{ +static char nwpathname[300]; + char volname[100]; + if (p->volume < 0 || p->volume >= used_vols) { + sprintf(volname, "<%d=NOT-OK>", (int)p->volume); + } else strcpy(volname, vols[p->volume].sysname); + sprintf(nwpathname, "%s:%s%s", volname, p->path, p->fn); + return(nwpathname); +} + +static int x_str_match(uint8 *s, uint8 *p) +{ + uint8 pc, sc; + uint state = 0; + uint8 anf, ende; + int not = 0; + uint found = 0; + while ( (pc = *p++) != 0) { + switch (state){ + case 0 : + switch (pc) { + case '\\': /* beliebiges Folgezeichen */ + if (*p++ != *s++) return(0); + break; + + case '?' : if (! *s++) return(0); /* one character */ + break; + + case '.' : if (!*s && !*p) return(1); /* point at end */ + if (pc != *s++) return(0); + if (*p == '*') return(1); + break; + + case '*' : if (!*p) { + uint8 *ss=s; + while (*ss) if (*ss++ == '.') return(0); + return(1); /* last star */ + } + while (*s){ + if (x_str_match(s, p) == 1) return(1); + ++s; + } + return((*p == '.' && *(p+1) == '*') ? 1 : 0); + + case '[' : if ( (*p == '!') || (*p == '^') ){ + ++p; + not = 1; + } + state = 1; + continue; + + default : if (pc != *s++) return(0); /* normal char */ + break; + + } /* switch */ + break; + + case 1 : /* Bereich von Zeichen */ + sc = *s++; + found = not; + if (!sc) return(0); + do { + if (pc == '\\') pc = *(p++); + if (!pc) return(0); + anf = pc; + if (*p == '-' && *(p+1) != ']'){ + ende = *(++p); + p++; + } + else ende = anf; + if (found == not) { /* only if not found */ + if (anf == sc || (anf <= sc && sc <= ende)) + found = !not; + } + } while ((pc = *(p++)) != ']'); + if (! found ) return(0); + not = 0; + found = 0; + state = 0; + break; + + default : break; + } /* switch */ + } /* while */ + return ( (*s) ? 0 : 1); +} + +static int str_match(uint8 *s, uint8 *p, uint8 options) +{ + uint8 *ss=s; + int len=0; + int pf=0; + for (; *ss; ss++){ + len++; + if (*ss == '.') { + if (pf++) return(0); /* Kein 2. Punkt */ + len=0; + } else { + if ((pf && len > 3) || len > 8) return(0); + if (options & 1){ /* only downshift chars */ + if (*ss >= 'A' && *ss <= 'Z') return(0); + } else { /* only upshift chars */ + if (*ss >= 'a' && *ss <= 'z') return(0); + } + } + } + return(x_str_match(s, p)); +} + +static int get_dir_entry(NW_PATH *nwpath, + int *sequence, + int attrib, + struct stat *statb) + +/* returns 1 if OK and 0 if not OK */ +{ + struct dirent* dirbuff; + DIR *f; + int okflag=0; + char xkpath[256]; + uint8 entry[256]; + int volume = nwpath->volume; + uint8 soptions; + if (volume < 0 || volume >= used_vols) return(0); /* something wrong */ + else soptions = vols[volume].options; + strcpy(entry, nwpath->fn); + if (soptions & 1) downstr(entry); /* now downshift chars */ + + nwpath->fn[0] = '\0'; + strcpy(xkpath, build_unix_name(nwpath, 1|2)); + DPRINTF(("get_dir_entry attrib=0x%x path:%s:, xkpath:%s:, entry:%s:\n", + attrib, nwpath->path, xkpath, entry)); + + if ((f=opendir(xkpath)) != (DIR*)NULL) { + char *kpath=xkpath+strlen(xkpath); + *kpath++ = '/'; + if (*sequence == MAX_U16) *sequence = 0; + else seekdir(f, (long)*sequence); + + while ((dirbuff = readdir(f)) != (struct dirent*)NULL){ + okflag = 0; + if (dirbuff->d_ino) { + uint8 *name=(uint8*)(dirbuff->d_name); + okflag = (name[0] != '.' && + ( (entry[0] == '*' && entry[1] == '\0') + || (!strcmp(name, entry)) + || str_match(name, entry, soptions))); + if (okflag) { + *kpath = '\0'; + strcpy(kpath, name); + if (!stat(xkpath, statb)) { + okflag = ( ( ( (statb->st_mode & S_IFMT) == S_IFDIR) && (attrib & 0x10)) + || ( ( (statb->st_mode & S_IFMT) != S_IFDIR) && !(attrib & 0x10))); + if (okflag){ + strcpy(nwpath->fn, name); + if (soptions & 1) upstr(nwpath->fn); + DPRINTF(("FOUND=:%s: attrib=0x%x\n", nwpath->fn, statb->st_mode)); + break; /* ready */ + } + } else okflag = 0; + } + XDPRINTF((4, "NAME=:%s: OKFLAG %d\n", name, okflag)); + } /* if */ + } /* while */ + *sequence = (int) telldir(f); + closedir(f); + } /* if */ + return(okflag); +} + +static int get_dh_entry(DIR_HANDLE *dh, + uint8 *search, + int *sequence, + int attrib, + struct stat *statb) + +/* returns 1 if OK and 0 if not OK */ +{ + DIR *f = dh->f; + int okflag = 0; + if (f != (DIR*)NULL) { + struct dirent* dirbuff; + uint8 entry[256]; + strmaxcpy(entry, search, 255); + + if (dh->vol_options & 1) downstr(entry); + if ( (uint16)*sequence == MAX_U16) *sequence = 0; + seekdir(f, (long) *sequence); + + DPRINTF(("get_dh_entry attrib=0x%x path:%s:, entry:%s:\n", + attrib, dh->unixname, entry)); + + while ((dirbuff = readdir(f)) != (struct dirent*)NULL){ + okflag = 0; + if (dirbuff->d_ino) { + uint8 *name=(uint8*)(dirbuff->d_name); + okflag = (name[0] != '.' && ( + (!strcmp(name, entry)) || + (entry[0] == '*' && entry[1] == '\0') + || str_match(name, entry, dh->vol_options))); + + if (okflag) { + strcpy(dh->kpath, name); + DPRINTF(("get_dh_entry Name=%s unixname=%s\n", + name, dh->unixname)); + + if (!stat(dh->unixname, statb)) { + okflag = ( (( (statb->st_mode & S_IFMT) == S_IFDIR) && (attrib & 0x10)) + || (((statb->st_mode & S_IFMT) != S_IFDIR) && !(attrib & 0x10))); + if (okflag){ + strcpy(search, name); + if (dh->vol_options & 1) upstr(search); + break; /* Bin fertig */ + } + } else okflag = 0; + } + } /* if */ + } /* while */ + dh->kpath[0] = '\0'; + *sequence = (int) telldir(f); + } /* if */ + return(okflag); +} + +static void build_path_fn( uint8 *vol, + uint8 *path, + uint8 *fn, + int *has_wild, + uint8 *data, + int len) + +/* is called from build_path */ +{ + uint8 *p = NULL; + uint8 *p1 = path; + *vol = '\0'; + *has_wild = 0; /* no wild char */ + while (len-- && *data){ + if (*data == 0xae) *p1++ = '.'; + else if (*data > 0x60 && *data < 0x7b) { + *p1++ = *data - 0x20; /* all is upshift */ + } else if (*data == 0xaa|| *data == '*' ) { + *p1++ = '*'; + (*has_wild)++; + } else if (*data == 0xbf|| *data == '?' ) { + *p1++ = '?'; + (*has_wild)++; + } else if (*data == '/' || *data == '\\') { + *p1++ = '/'; + p = p1; + } else if (*data == ':') { /* extract volume */ + int len = (int) (p1 - path); + memcpy(vol, path, len); + vol[len] = '\0'; + p1 = path; + } else *p1++ = *data; + data++; + } + *p1 = '\0'; + if (fn != NULL) { /* if with filename */ + if (p != NULL){ /* exist directory-path */ + strcpy(fn, p); + *p = '\0'; + } else { /* only filename */ + strcpy(fn, path); + *path= '\0'; + } + } +} + +static int build_path( NW_PATH *path, + uint8 *data, + int len, + int only_dir) +/* + * fills path structur with the right values + * if only_dir > 0, then the full path will be interpreted + * as directory, in the other way, the last segment of path + * will be interpreted as fn. + * returns -0x98, if volume is wrong + */ +{ + uint8 vol[20]; + build_path_fn(vol, path->path, + (only_dir) ? (uint8)NULL + : path->fn, + &(path->has_wild), + data, len); + + path->volume = -1; + if (only_dir) path->fn[0] = '\0'; + + if (vol[0]) { /* there is a volume in path */ + int j = used_vols; + while (j--) { + if (!strcmp(vols[j].sysname, vol)) { + path->volume = j; + break; + } + } + if (path->volume < 0) return(-0x98); + } + + return(0); +} + +static int nw_path_ok(NW_PATH *nwpath) +/* returns UNIX inode of path */ +{ + int j = 0; + NW_DIR *d=&(dirs[0]); + struct stat stbuff; + int result = -0x9c; /* wrong path */ + + while (j++ < (int)used_dirs){ + if (d->inode && d->volume == nwpath->volume + && !strcmp(nwpath->path, d->path)){ + return(d->inode); + } + d++; + } /* while */ + + if (!stat(build_unix_name(nwpath, 1 | 2 ), &stbuff)){ + if ((stbuff.st_mode & S_IFMT) == S_IFDIR) result=stbuff.st_ino; + } + + return(result); +} + +static int build_verz_name(NW_PATH *nwpath, /* gets complete path */ + int dir_handle) /* search with dirhandle */ + +/* return -completition code or inode */ +{ + uint8 searchpath[256]; + uint8 *p=searchpath; + int completition=0; + + strcpy(searchpath, nwpath->path); /* save path */ + + if (nwpath->volume > -1) { /* absolute path */ + nwpath->path[0] = '\0'; + } else { /* volume not kwown yet, I must get it about dir_handle */ + if (dir_handle > 0 && + --dir_handle < (int)used_dirs && dirs[dir_handle].inode){ + nwpath->volume = dirs[dir_handle].volume; + if (searchpath[0] == '/') { /* absolute path */ + p++; + nwpath->path[0] = '\0'; + } else /* get path from dir_handle */ + strcpy(nwpath->path, dirs[dir_handle].path); + } else return(-0x9b); /* wrong dir handle */ + } + + if (*p) { + uint8 *panf = nwpath->path; + uint8 *p1 = panf+strlen((char*)panf); + uint8 *a = p; + uint8 w; + int state = 0; + while ((!completition) && (w = *p++) > 0){ + if (!state){ + DPRINTF(("in build_verz_name path=:%s:\n", nwpath->path)); + if (w == '.') state = 20; + else if (w == '/') state = 30; + else state++; + } else if (state < 9){ + if (w == '.') state = 10; + else if (w == '/') state = 30; + else state++; + } else if (state == 9) completition= -0x9c; /* something wrong */ + else if (state < 14){ + if (w == '.') return(-0x9c); + else if (w == '/') state = 30; + else state++; + } else if (state == 14) completition= -0x9c; /* something wrong */ + else if (state == 20){ + if (w == '/') state = 30; + else if (w != '.') completition= -0x9c; /* something wrong */ + } + if (state == 30 || !*p) { /* now action */ + uint8 *xpath=a; + int len = (int)(p-a); + if (len && state == 30) --len; /* '/' stoert hier */ + a = p; + if (len) { + if (*xpath == '.') { + uint8 *xp=xpath+1; + if (*xp == '.') { + while (*xp++ == '.' && completition > -1) { + p1--; /* steht nun auf letztem Zeichen '/' od. ':' */ + if (p1 < panf) completition = -0x9c ; + /* Falscher Pfad, denn weiter zurueck gehts nicht */ + else { + while (p1 > panf && *(--p1) != '/');; + if (p1 == panf) *p1='\0'; + else *(++p1) = '\0'; + } + } + } + } else { + memcpy(p1, xpath, len); + p1 += len; + *p1++ = '/'; + *p1 = '\0'; + } + } /* if len */ + state = 0; + } + } + } + if (!completition) completition = nw_path_ok(nwpath); + return(completition); +} + +static int get_kpl_path(NW_PATH *nwpath, int dirhandle, + uint8 *data, int len, int only_dir) +/* + * if ok then the inode of dir will be returned + * else a negativ errcode will be returned + */ +{ + int completition = build_path(nwpath, data, len, only_dir); + if (!completition) completition = build_verz_name(nwpath, dirhandle); + return(completition); +} + +static void un_date_2_nw(time_t time, uint8 *d) +{ + struct tm *s_tm=localtime(&time); + uint16 xdate=s_tm->tm_year - 80; + xdate <<= 4; + xdate |= s_tm->tm_mon+1; + xdate <<= 5; + xdate |= s_tm->tm_mday; + U16_TO_BE16(xdate, d); +} + +static time_t nw_2_un_time(uint8 *d, uint8 *t) +{ + uint16 xdate = GET_BE16(d); + uint16 xtime = (t != (uint8*) NULL) ? GET_BE16(t) : 0; + + int year = (xdate >> 9) + 80; + int month = (xdate >> 5) & 0x0F; + int day = xdate & 0x1f; + int hour = xtime >> 11; + int minu = (xtime >> 5) & 0x3f; + int sec = xtime & 0x1f; + struct tm s_tm; + s_tm.tm_year = year; + s_tm.tm_mon = month-1; + s_tm.tm_mday = day; + s_tm.tm_hour = hour; + s_tm.tm_min = minu; + s_tm.tm_sec = sec; + return(mktime(&s_tm)); +} + +static void un_time_2_nw(time_t time, uint8 *d) +{ + struct tm *s_tm=localtime(&time); + uint16 xdate=s_tm->tm_hour; + xdate <<= 6; + xdate |= s_tm->tm_min; + xdate <<= 5; + xdate |= (s_tm->tm_sec / 2); + U16_TO_BE16(xdate, d); +} + +static int get_file_attrib(NW_FILE_INFO *f, struct stat *stb, + NW_PATH *nwpath) +{ + strncpy(f->name, nwpath->fn, sizeof(f->name)); + /* Attribute */ + /* 0x20 Archive Flag */ + /* 0x80 Sharable */ /* TLINK (TCC 2.0) don't like it ???? */ + if (!strcmp(nwpath->fn, "TURBOC.$LN")) f->attrib = 0x20; + else f->attrib = 0x80; + f->ext_attrib = 0; + un_date_2_nw(stb->st_mtime, f->create_date); + un_date_2_nw(stb->st_atime, f->acces_date ); + un_date_2_nw(stb->st_mtime, f->modify_date); + un_time_2_nw(stb->st_mtime, f->modify_time); + U32_TO_BE32(stb->st_size, f->size); + return(1); +} + +static int get_dir_attrib(NW_DIR_INFO *d, struct stat *stb, + NW_PATH *nwpath) +{ + strncpy(d->name, nwpath->fn, sizeof(d->name)); + d->attrib = 0x10; /* Verzeichnis */ + d->ext_attrib = 0xff; /* effektive rights ?? */ + + un_date_2_nw(stb->st_mtime, d->create_date); + un_time_2_nw(stb->st_mtime, d->create_time); + + U32_TO_BE32(1L, d->owner_id); + d->access_right_mask = 0; + d->reserved = 0; + U16_TO_BE16(0, d->next_search); + return(1); +} + + +int nw_creat_open_file(int dir_handle, uint8 *data, int len, + NW_FILE_INFO *info, int attrib, int access, int creatmode) +/* + * creatmode: 0 = open, 1 = creat, 2 = creatnew + * attrib ?? + * access: 0x1=read, 0x2=write + */ +{ + int fhandle=new_file_handle(); + + if (fhandle){ + FILE_HANDLE *fh=&(file_handles[fhandle-1]); + NW_PATH nwpath; + int completition = get_kpl_path(&nwpath, dir_handle, data, len, 0); + +#ifdef TEST_FNAME + int got_testfn = 0; + if (!nw_debug){ + if (strstr(nwpath.fn, TEST_FNAME)){ + nw_debug = 99; + got_testfn++; + } + } +#endif + + if (completition > -1) { + struct stat stbuff; + completition = -0xff; /* no File Found */ + strcpy(fh->name, build_unix_name(&nwpath, 0)); + + if (creatmode) { /* creat File */ + if (creatmode & 0x2) { /* creatnew */ + if (!stat(fh->name, &stbuff)) { + DPRINTF(("CREAT File exist!! :%s:\n", fh->name)); + fh->fd = -1; + completition = -0x85; /* No Priv */ + } else { + DPRINTF(("CREAT FILE:%s: Handle=%d\n", fh->name, fhandle)); + fh->fd = creat(fh->name, 0777); + if (fh->fd < 0) completition = -0x84; /* no create Rights */ + } + } else { + DPRINTF(("CREAT FILE, ever with attrib:0x%x, access:0x%x, fh->name:%s: handle:%d\n", + attrib, access, fh->name, fhandle)); + fh->fd = open(fh->name, O_CREAT|O_TRUNC|O_RDWR, 0777); + if (fh->fd < 0) completition = -0x85; /* no delete /create Rights */ + } + + if (fh->fd > -1) { + close(fh->fd); + fh->fd = open(fh->name, O_RDWR); + fh->offd = 0L; + stat(fh->name, &stbuff); + } + } else { + int statr = stat(fh->name, &stbuff); + int acm = (access & 2) ? (int) O_RDWR /*|O_CREAT*/ : (int)O_RDONLY; + if ( (!statr && (stbuff.st_mode & S_IFMT) != S_IFDIR) + || (statr && (acm & O_CREAT))){ + DPRINTF(("OPEN FILE with attrib:0x%x, access:0x%x, fh->name:%s: fhandle=%d\n",attrib,access, fh->name, fhandle)); + fh->fd = open(fh->name, acm, 0777); + fh->offd = 0L; + if (fh->fd > -1) { + if (statr) stat(fh->name, &stbuff); + } else completition = -0x9a; + } + + } + + if (fh->fd > -1) { + get_file_attrib(info, &stbuff, &nwpath); +#ifdef TEST_FNAME + if (got_testfn) test_handle = fhandle; +#endif + return(fhandle); + } + } + + DPRINTF(("OPEN FILE not OK ! fh->name:%s: fhandle=%d\n",fh->name, fhandle)); + free_file_handle(fhandle); +#ifdef TEST_FNAME + if (got_testfn) { + test_handle = -1; + nw_debug = -99; + } +#endif + return(completition); + } else return(-0x81); /* no more File Handles */ +} + +int nw_delete_datei(int dir_handle, uint8 *data, int len) +/* TODO: handle wildcards !!! */ +{ + NW_PATH nwpath; + int completition = get_kpl_path(&nwpath, dir_handle, data, len, 0); + if (completition > -1) { + char unname[256]; + struct stat stbuff; + strcpy(unname, build_unix_name(&nwpath, 0)); + DPRINTF(("DELETE FILE unname:%s:\n", unname)); + if (!stat(unname, &stbuff)){ + if (!unlink(unname)) return(0); + return(-0x8a); /* NO Delete Privileges */ + } else completition= -0xff; /* No Files Found */ + } + return(completition); +} + +int nw_chmod_datei(int dir_handle, uint8 *data, int len, int modus) +{ + char unname[256]; + struct stat stbuff; + int completition=-0x9c; + NW_PATH nwpath; + build_path(&nwpath, data, len, 0); + if (nwpath.fn[0] != '.') { /* Files with . at the beginning are not ok */ + completition = build_verz_name(&nwpath, dir_handle); + } + if (completition < 0) return(completition); + strcpy(unname, build_unix_name(&nwpath, 2)); + DPRINTF(("CHMOD DATEI unname:%s:\n", unname)); + if (!stat(unname, &stbuff)){ + return(0); + } + return(-0x9c); /* wrong path */ +} + +int nw_close_datei(int fhandle) +{ + if (fhandle > 0 && (fhandle <= anz_fhandles)) { + FILE_HANDLE *fh=&(file_handles[fhandle-1]); + if (fh->fd > -1) { + close(fh->fd); + fh->fd = -1; + if (fh->tmodi > 0L) { + struct utimbuf ut; + ut.actime = ut.modtime = fh->tmodi; + utime(fh->name, &ut); + } +#ifdef TEST_FNAME + if (fhandle == test_handle) { + test_handle = -1; + nw_debug = -99; + } +#endif + return(free_file_handle(fhandle)); + } + } + return(-0x88); /* wrong filehandle */ +} + + +int nw_read_datei(int fhandle, uint8 *data, int size, uint32 offset) +{ + if (fhandle > 0 && (--fhandle < anz_fhandles)) { + FILE_HANDLE *fh=&(file_handles[fhandle]); + if (fh->fd > -1) { + if (fh->offd != (long)offset) + fh->offd=lseek(fh->fd, offset, SEEK_SET); + if (fh->offd > -1L) { + size = read(fh->fd, data, size); + fh->offd+=(long)size; + } else size = -1; + return(size); + } + } + return(- 0x88); /* wrong filehandle */ +} + +int nw_seek_datei(int fhandle, int modus) +{ + if (fhandle > 0 && (--fhandle < anz_fhandles)) { + FILE_HANDLE *fh=&(file_handles[fhandle]); + if (fh->fd > -1) { + int size=-0xfb; + if (!modus) { + if ( (size=fh->offd=lseek(fh->fd, 0L, SEEK_END)) < 0L) + size = -1; + } + return(size); + } + } + return(-0x88); /* wrong filehandle */ +} + + +int nw_write_datei(int fhandle, uint8 *data, int size, uint32 offset) +{ + if (fhandle > 0 && (--fhandle < anz_fhandles)) { + FILE_HANDLE *fh=&(file_handles[fhandle]); + if (fh->fd > -1) { + if (fh->offd != (long)offset) + fh->offd = lseek(fh->fd, offset, SEEK_SET); + if (size) { + if (fh->offd > -1L) { + size = write(fh->fd, data, size); + fh->offd+=(long)size; + } else size = -1; + return(size); + } else { /* strip FILE */ + /* TODO: for LINUX */ + struct flock flockd; + int result= /* -1 */ 0; + flockd.l_type = 0; + flockd.l_whence = SEEK_SET; + flockd.l_start = offset; + flockd.l_len = 0; +#if HAVE_TLI + result = fcntl(fh->fd, F_FREESP, &flockd); + DPRINTF(("File %s is stripped, result=%d\n", fh->name, result)); +#endif + return(result); + } + } + } + return(- 0x88); /* wrong filehandle */ +} + +int nw_server_copy(int qfhandle, uint32 qoffset, + int zfhandle, uint32 zoffset, + uint32 size) +{ + if (qfhandle > 0 && (--qfhandle < anz_fhandles) + && zfhandle > 0 && (--zfhandle < anz_fhandles) ) { + FILE_HANDLE *fhq=&(file_handles[qfhandle]); + FILE_HANDLE *fhz=&(file_handles[zfhandle]); + int retsize = -1; + if (fhq->fd > -1 && fhz->fd > -1) { + char buff[2048]; + int wsize; + if (lseek(fhq->fd, qoffset, SEEK_SET) > -1L && + lseek(fhz->fd, zoffset, SEEK_SET) > -1L) { + retsize = 0; + while (size && !retsize) { + int xsize = read(fhq->fd, buff, min(size, (uint32)sizeof(buff))); + if (xsize > 0){ + if ((wsize =write(fhz->fd, buff, xsize)) != xsize) { + retsize = -0x1; /* out of Disk SPace */ + break; + } else { + size -= (uint32)xsize; + retsize += wsize; + } + } else { + if (xsize < 0) retsize=-0x93; /* no read privilegs */ + break; + } + } + } + fhq->offd = -1L; + fhz->offd = -1L; +/* + if (!retsize) (retsize=fhz->offd=lseek(fhz->fd, 0L, SEEK_END)); +*/ + return(retsize); + } + } + return(- 0x88); /* Falscher Filehandle */ +} + + +int nw_lock_datei(int fhandle, int offset, int size, int do_lock) +{ + if (fhandle > 0 && (--fhandle < anz_fhandles)) { + FILE_HANDLE *fh=&(file_handles[fhandle]); + if (fh->fd > -1) { + struct flock flockd; + int result; + flockd.l_type = (do_lock) ? F_WRLCK : F_UNLCK; + flockd.l_whence = SEEK_SET; + flockd.l_start = offset; + flockd.l_len = size; + result = fcntl(fh->fd, F_SETLK, &flockd); + if (!result) return(0); + else return(-0x21); /* LOCK Violation */ + } + } + return(-0x88); /* wrong filehandle */ +} + +int nw_mk_rd_dir(int dir_handle, uint8 *data, int len, int mode) +{ + NW_PATH nwpath; + int completition = get_kpl_path(&nwpath, dir_handle, data, len, !mode); + + if (completition > -1) { + char unname[256]; + strcpy(unname, build_unix_name(&nwpath, 2)); +#if 0 + if (unname[0] && unname[1]) { + char *p=unname+strlen(unname)-1; + if (*p=='/') *p = '\0'; + } +#endif + + if (mode) { + DPRINTF(("MKDIR dirname:%s:\n", unname)); + if (!mkdir(unname, 0777)) return(0); + completition = -0x84; /* No Create Priv.*/ /* -0x9f Direktory Aktive */ + } else { /* rmdir */ + DPRINTF(("RMDIR dirname:%s:\n", unname)); + if (!rmdir(unname)) { + NW_DIR *d=&(dirs[0]); + int j = 0; + while (j++ < (int)used_dirs){ + if (d->inode == completition) d->inode = 0; + d++; + } + completition = 0; + } else if (errno & EEXIST) + completition = -0xa0; /* dir not empty */ + else completition = -0x8a; /* No privilegs */ + } + } + return(completition); +} + +int mv_file(int qdirhandle, uint8 *q, int qlen, + int zdirhandle, uint8 *z, int zlen) +{ + NW_PATH quellpath; + NW_PATH zielpath; + int completition=get_kpl_path(&quellpath, qdirhandle, q, qlen, 0); + if (!completition > -1){ + completition=get_kpl_path(&zielpath, zdirhandle, z, zlen, 0); + if (completition > -1){ + char unquelle[256]; + char unziel[256]; + strcpy(unquelle, build_unix_name(&quellpath,0)); + strcpy(unziel, build_unix_name(&zielpath,0)); + if (!link(unquelle, unziel)){ + if (unlink(unquelle)) { + completition=-0x9c; + /* TODO: here completition must be no pernmissions */ + unlink(unziel); + } + } else { + if (errno & EEXIST) + completition=-0x91; /* allready exist */ + else if (errno & EXDEV) + completition=-0x9a; /* cross devices */ + else completition=-0x9c; /* wrong path */ + } + } + } + return(completition); +} + + +static int change_dir_entry( NW_DIR *dir, int volume, + uint8 *path, ino_t inode, + int driveletter, int is_temp, + int new_entry, int task) +{ + if (new_entry || (dir->inode && dir->is_temp != 2)) { + new_str(dir->path, path); + dir->inode = inode; + dir->volume = (uint8) volume; + dir->timestamp = time(NULL); + if (driveletter > -1) { + dir->drive = (uint8) driveletter; + dir->task = (uint8)task; + } else { + if (task < (int)dir->task) dir->task = (uint8) task; + } + if (is_temp > -1) dir->is_temp = (uint8) is_temp; + return(0); + } else { + if (!dir->inode) return(-0x9b); /* wrong handle */ + else return(-0xfa); /* temp remap Error */ + } +} + +int nw_init_connect(void) +/* Cann be called when ever you want */ +{ + uint8 *login = (uint8*) "LOGIN/"; + NW_PATH nwlogin; + FILE *f=open_nw_ini(); + if (f != (FILE*) NULL){ + uint8 buff[256]; + struct stat stbuff; + int k = MAX_NW_DIRS; + NW_DIR *d = &(dirs[0]); + strcpy(nwlogin.path, login); + nwlogin.fn[0] = '\0'; + nwlogin.volume = 0; + + while (k--) { + if (connect_is_init) xfree(d->path); + else d->path = NULL; + d->volume = 0; + d->inode = 0; + d->is_temp = 0; + d->drive = 0; + d++; + } + if (!connect_is_init) { + k = -1; + connect_is_init++; + while (++k < MAX_NW_VOLS) { + vols[k].unixname = NULL; + vols[k].sysname = NULL; + vols[k].options = 0; + } + } else { + k = 0; + while (k++ < anz_fhandles) free_file_handle(k); + k = 0; + while (k++ < anz_dirhandles) free_dir_handle(k); + } + used_vols = 0; + + while (fgets((char*)buff, sizeof(buff), f) != NULL && used_vols < MAX_NW_VOLS){ + int len = strlen(buff); + int j =-1; + while (++j < len){ + if (buff[j] == '#') { + buff[j] = '\0'; + len = j; + break; + } + } + if (len > 3){ + int what=0; + uint8 sysname[256]; + uint8 unixname[256]; + char optionstr[256]; + char *p; + int len; + int founds = sscanf((char*)buff, "%d %s %s %s", &what, sysname, unixname, optionstr); + if (founds > 2 && what == 1) { + new_str(vols[used_vols].sysname, sysname); + len = strlen(unixname); + if (unixname[len-1] != '/') { + unixname[len++] = '/'; + unixname[len] = '\0'; + } + vols[used_vols].options = 0; + new_str(vols[used_vols].unixname, unixname); + if (founds > 3) { + for (p=optionstr; *p; p++) { + switch (*p) { + case 'k' : vols[used_vols].options |= 1; + default : break; + } + } + } + used_vols++; + } + } + } + fclose(f); + if (stat(build_unix_name(&nwlogin, 0), &stbuff)) { + perror("Stat error in nw_init_connect, Abbruch"); + return(-1); + } + (void)change_dir_entry(&(dirs[0]), 0, nwlogin.path, stbuff.st_ino, + 0, 0, 1, 0); + /* first Handle must be known und must not be temp */ + /* and has no Drive-Character */ + used_dirs = 1; + anz_fhandles = 0; + anz_dirhandles = 0; + return(0); + } else return(-1); +} + +int nw_free_handles(int task) +/* + * if task==0 then all is initialized + * else the temp handles of the actuell task and greater + * are deleted. I hope it is right. !?? + */ +{ + if (!task) return(nw_init_connect()); + else { + NW_DIR *d = &(dirs[0]); + int k = used_dirs; + while (k--) { + if (d->is_temp && d->task >= task) { + xfree(d->path); + d->volume = 0; + d->inode = 0; + d->is_temp = 0; + d->drive = 0; + } + d++; + } + } + return(0); +} + +int insert_new_dir(NW_PATH *nwpath, int inode, int drive, int is_temp, int task) +{ + int j = 0; + time_t lowtime = time(NULL); + int freehandle = 0; + int timedhandle = 0; + + /* first look, wether drive is allready in use */ + for (j = 0; j < (int)used_dirs; j++) { + NW_DIR *d = &(dirs[j]); + if (d->inode && !is_temp && !d->is_temp && (int)d->drive == drive) { + (void)change_dir_entry(d, nwpath->volume, nwpath->path, inode, drive, is_temp, 1, task); + return(++j); + } else if (!d->inode) freehandle = j+1; + else if (d->is_temp && d->timestamp < lowtime) { + timedhandle = j+1; + lowtime = d->timestamp; + } + } + if (!freehandle && used_dirs < MAX_NW_DIRS) freehandle = ++used_dirs; + if (!freehandle) freehandle = timedhandle; + if (freehandle){ + (void)change_dir_entry(&(dirs[freehandle-1]), + nwpath->volume, nwpath->path, inode, + drive, is_temp, 1, task); + while (used_dirs > freehandle && !dirs[used_dirs-1].inode) used_dirs--; + return(freehandle); + } else return(-0x9d); /* no dir Handles */ +} + +int nw_search(uint8 *info, + int dirhandle, int searchsequence, + int search_attrib, uint8 *data, int len) + +{ + NW_PATH nwpath; + int completition = get_kpl_path(&nwpath, dirhandle, data, len, 0); + DPRINTF(("nw_search path:%s:, fn:%s:, completition:0x%x\n", + nwpath.path, nwpath.fn, completition)); + if (completition > -1) { + struct stat stbuff; + + if (get_dir_entry(&nwpath, + &searchsequence, + search_attrib, + &stbuff)){ + + if (search_attrib & 0x10) { + get_dir_attrib((NW_DIR_INFO*)info, &stbuff, + &nwpath); + } else { + get_file_attrib((NW_FILE_INFO*)info, &stbuff, + &nwpath); + } + return(searchsequence); + } else return(-0xff); /* not found */ + } else return(completition); /* Falscher Pfad */ +} + +int nw_dir_search(uint8 *info, + int dirhandle, int searchsequence, + int search_attrib, uint8 *data, int len) + +{ + NW_PATH nwpath; + int completition=-0x9c; + build_path(&nwpath, data, len, 0); + if (dirhandle > 0 && --dirhandle < anz_dirhandles){ + DIR_HANDLE *dh = &(dir_handles[dirhandle]); + struct stat stbuff; + if (get_dh_entry(dh, + nwpath.fn, + &searchsequence, + search_attrib, + &stbuff)){ + + /* + if ( (stbuff.st_mode & S_IFMT) == S_IFDIR) { + */ + + if (search_attrib & 0x10) { + get_dir_attrib((NW_DIR_INFO*)info, &stbuff, + &nwpath); + } else { + get_file_attrib((NW_FILE_INFO*)info, &stbuff, + &nwpath); + } + + return(searchsequence); + } else return(-0xff); /* not found */ + } else return(completition); /* wrong path */ +} + +int nw_alloc_dir_handle( int dir_handle, /* Suche ab Pfad dirhandle */ + uint8 *data, /* zusaetzl. Pfad */ + int len, /* Lnge DATA */ + int driveletter, /* A .. Z normal */ + int is_temphandle, /* temporaeres Handle 1 */ + /* spez. temp Handle 2 */ + int task) /* Prozess Task */ +{ + NW_PATH nwpath; + int inode=get_kpl_path(&nwpath, dir_handle, data, len, 1); + if (inode > -1) + inode = insert_new_dir(&nwpath, inode, driveletter, is_temphandle, task); + DPRINTF(("Allocate %shandle:%s, Handle=%d, drive=%d, result=0x%x\n", + (is_temphandle) ? "Temp" : "Perm", get_nwpath_name(&nwpath), + dir_handle, driveletter, inode)); + return(inode); +} + +int nw_open_dir_handle( int dir_handle, + uint8 *data, /* extra path */ + int len, /* len of DATA */ + + int *volume, /* Volume */ + int *dir_id, + int *searchsequence) + +/* + * Routine liefert Handle aehnlich Filehandle. + * Handle kann in der Suchroutine verwendet werden + * RETURN=Fehlercode ( <0 ) od. ACCES Rights +*/ + +{ + NW_PATH nwpath; + int completition = get_kpl_path(&nwpath, dir_handle, data, len, 1); + DPRINTF(("NW_OPEN_DIR: completition = 0x%x; nwpath= %s\n", + (int)completition, + get_nwpath_name(&nwpath) )); + + if (completition > -1) { + completition = new_dir_handle((ino_t)completition, &nwpath); + if (completition > -1) { + DIR_HANDLE *fh = &(dir_handles[completition-1]); + *volume = fh->volume; + *dir_id = completition; + *searchsequence = MAX_U16; + completition = 0xff; /* Alle Rechte */ + } + DPRINTF(("NW_OPEN_DIR_2: completition = 0x%x\n", + (int)completition)); + } + return(completition); +} + +int nw_free_dir_handle(int dir_handle) +{ + if (dir_handle && --dir_handle < (int)used_dirs) { + NW_DIR *d=&(dirs[dir_handle]); + if (!d->inode) return(-0x9b); /* Falscher Handle */ + else { + d->inode = 0; + xfree(d->path); + } + return(0); + } else return(-0x9b); /* wrong handle */ +} + +int nw_set_dir_handle(int targetdir, int dir_handle, + uint8 *data, int len, int task) +/* targetdirs gets path of dirhandle + data */ +{ + NW_PATH nwpath; + int inode = get_kpl_path(&nwpath, dir_handle, data, len, 1); + if (inode > -1){ + if (targetdir > 0 && --targetdir < used_dirs + && dirs[targetdir].is_temp != 2) { /* not a spez. temphandle */ + DPRINTF(("Change dhandle:%d -> %s:\n", targetdir+1, get_nwpath_name(&nwpath))); + return(change_dir_entry(&dirs[targetdir], nwpath.volume, nwpath.path, inode, -1, -1, 0, task)); + /* here the existing handle is only modified */ + } else return(-0x9b); /* BAD DIR Handle */ + } + return(inode); /* invalid PATH */ +} + +int nw_get_directory_path(int dir_handle, uint8 *name) +{ + int result = -0x9b; + name[0] = '\0'; + if (dir_handle > 0 && --dir_handle < (int)used_dirs) { + int volume = dirs[dir_handle].volume; + if (volume < used_vols){ + result=sprintf((char*)name, "%s:%s", vols[volume].sysname, dirs[dir_handle].path); + if (name[result-1] == '/') name[--result] = '\0'; + } else result = -0x98; + } + DPRINTF(("nw_get_directory_path:%s: Handle=%d, result=0x%x\n", name, dir_handle+1, result)); + return(result); +} + +int nw_get_vol_number(int dir_handle) +/* Get Volume Nummmer with Handle */ +{ + int result = -0x9b; /* Falsches Handle */ + if (dir_handle > 0 && --dir_handle < (int)used_dirs) { + result = dirs[dir_handle].volume; + if (result >= used_vols) result = -0x98; /* Falsches Volume */ + } + DPRINTF(("nw_get_vol_number:0x%x: von Handle=%d\n", result, dir_handle+1)); + return(result); +} + +int nw_get_volume_number(uint8 *volname, int namelen) +/* Get Volume Number with name */ +/* returns Volume Nummer or if error < 0 */ +{ + int result = -0x98; /* Volume not exist */ + uint8 vname[255]; + int j = used_vols; + strmaxcpy((char*)vname, (char*)volname, namelen); + upstr(vname); + while (j--) { + if (!strcmp(vols[j].sysname, vname)) { + result = j; + break; + } + } + DPRINTF(("GET_VOLUME_NUMBER of:%s: result = 0x%x\n", vname, result)); + return(result); +} + +int nw_get_volume_name(int volnr, uint8 *volname) +/* returns < 0 if error, else len of volname */ +{ + int result = -0x98; /* Volume not exist */; + if (volnr < used_vols) { + strcpy(volname, vols[volnr].sysname); + result = strlen(volname); + } else volname[0] = '\0'; + DPRINTF(("GET_VOLUME_NAME von:%d = %s: ,result=0x%x\n", volnr, volname, result)); + return(result); +} + +int nw_get_eff_dir_rights(int dir_handle, uint8 *data, int len) +{ + char unname[256]; + struct stat stbuff; + NW_PATH nwpath; + int completition = get_kpl_path(&nwpath, dir_handle, data, len, 1); + if (completition < 0) return(completition); + strcpy(unname, build_unix_name(&nwpath, 0)); + if (stat(unname, &stbuff) || (stbuff.st_mode & S_IFMT) != S_IFDIR) { + completition = -0x9c; + } else completition=0xff; /* alle Rechte */ + return(completition); +} + +int nw_set_fdate_time(uint32 fhandle, uint8 *datum, uint8 *zeit) +{ + if (fhandle > 0 && (--fhandle < anz_fhandles) ) { + FILE_HANDLE *fh=&(file_handles[fhandle]); + if (fh->fd > -1) { + fh->tmodi = nw_2_un_time(datum, zeit); + return(0); + } + } + return(-0x88); /* wrong filehandle */ +} + + +static int s_nw_scan_dir_info(int dir_handle, + uint8 *data, int len, uint8 *subnr, + uint8 *subname, uint8 *subdatetime, + uint8 *owner, uint8 *wild) +{ + int volume; + int searchsequenz; + int dir_id; + int rights = nw_open_dir_handle(dir_handle, data, len, + &volume, &dir_id, &searchsequenz); + + DPRINTF(("SCAN_DIR: rights = 0x%x, subnr = %d\n", + (int)rights, (int)GET_BE16(subnr))); + + if (rights > -1) { + DIR_HANDLE *dh = &(dir_handles[dir_id-1]); + struct stat stbuff; + int searchsequence = MAX_U16; + + uint16 dirsequenz = GET_BE16(subnr); + uint16 aktsequenz = 0; + uint8 dirname[256]; + + if (!dirsequenz) dirsequenz++; + + strcpy(dirname, wild); + while ( get_dh_entry( dh, + dirname, + &searchsequence, + 0x10, + &stbuff) ) { + + DPRINTF(("SCAN_DIR: von %s, found %s:\n", dh->unixname, dirname)); + if (++aktsequenz == dirsequenz) { /* actual found */ + U16_TO_BE16(aktsequenz, subnr); + strncpy(subname, dirname, 16); + U32_TO_BE32(1L, owner); /* erstmal */ + un_date_2_nw(stbuff.st_mtime, subdatetime); + un_time_2_nw(stbuff.st_mtime, subdatetime+2); + return(0xff); + } + strcpy(dirname, wild); + + } /* while */ + /* return(-0x9c); NO MORE INFO */ + return(-0xff); + } + return(rights); +} + +int nw_scan_dir_info(int dir_handle, uint8 *data, int len, uint8 *subnr, + uint8 *subname, uint8 *subdatetime, uint8 *owner) +{ + int k = len; + char *p = data+len; + uint8 dirname[256]; + while (k--) { + uint8 c = *--p; + if (c == '/' || c == '\\' || c == ':') { + p++; + k++; + break; + } + } + if (len /* && k < len */) { + strmaxcpy(dirname, p, len-k); + len = k; + } else strcpy(dirname, "*"); + return(s_nw_scan_dir_info(dir_handle, data, len, subnr, + subname, subdatetime, owner, dirname)); +} + +int nw_get_fs_usage(char *volname, struct fs_usage *fsu) +/* returns 0 if OK, else errocode < 0 */ +{ + int volnr = nw_get_volume_number(volname, strlen(volname)); + return((volnr>-1 && !get_fs_usage(vols[volnr].unixname, fsu)) ? 0 : -1); +} + + +/* NAMESPACE routines */ +int nw_generate_dir_path(uint8 *nwpathstruct, + uint8 *ns_dir_base, uint8 *dos_dir_base) +/* returns Volume Number >=0 or errcode < 0 if error */ +{ + return(-0xfb); /* TODO: complete call */ +} + + + + + + + +/* minimal queue handling to enable very simple printing */ +/* qick and dirty !!!!!!!!!!!!!!! */ + +#define MAX_JOBS 5 /* max. open queue jobs for one connection */ +static int anz_jobs=0; +QUEUE_JOB *queue_jobs[MAX_JOBS]; + +static QUEUE_JOB *give_new_queue_job(void) +{ + int k=-1; + while (++k < anz_jobs) { + QUEUE_JOB *p=queue_jobs[k]; + if (!p->record_in_use[0] && !p->record_in_use[1]) /* free slot */ + return(p); + } + if (anz_jobs < MAX_JOBS) { + QUEUE_JOB **pp=&(queue_jobs[anz_jobs++]); + *pp = (QUEUE_JOB *) xmalloc(sizeof(QUEUE_JOB)); + memset(*pp, 0, sizeof(QUEUE_JOB)); + (*pp)->job_id[0] = anz_jobs; + return(*pp); + } + return(NULL); +} + +static void free_queue_job(int q_id) +{ + if (q_id > 0 && q_id <= anz_jobs) { + QUEUE_JOB **pp=&(queue_jobs[q_id-1]); + uint32 fhandle = (uint32) GET_BE16((*pp)->job_file_handle); + if (fhandle > 0) nw_close_datei(fhandle); + if (q_id == anz_jobs) { + xfree(*pp); + --anz_jobs; + } else { + memset(*pp, 0, sizeof(QUEUE_JOB)); + (*pp)->job_id[0] = q_id; + } + } +} + +int nw_creat_queue(int connection, uint8 *queue_id, uint8 *queue_job, + uint8 *dirname, int dir_nam_len) +{ + QUEUE_JOB job_buff; + QUEUE_JOB *jo = give_new_queue_job(); + uint32 q_id = GET_BE32(queue_id); + NW_FILE_INFO fnfo; + int result = -0xff; + DPRINTF(("NW_CREAT_Q:dlen=%d, dirname=%s\n", dir_nam_len, dirname)); + if (NULL != jo) { + struct tm *s_tm; + time_t timer; + int jo_id = (int) jo->job_id[0]; + memcpy(jo, queue_job, sizeof(QUEUE_JOB)); + jo->job_id[0] = (uint8) jo_id; + + U16_TO_BE16(0xffff, jo->record_in_use); + U32_TO_BE32(0x0, jo->record_previous); + U32_TO_BE32(0x0, jo->record_next); + + memset(jo->client_connection, 0, 4); + jo->client_connection[0] = (uint8)connection; + memset(jo->client_task, 0, 4); + jo->client_task[0] = (uint8)0xfe; /* ?? */ + + U32_TO_BE32(1, jo->client_id); /* SU */ + + time(&timer); + s_tm = localtime(&timer); + jo->job_entry_time[0] = (uint8) s_tm->tm_year; + jo->job_entry_time[1] = (uint8) s_tm->tm_mon+1; + jo->job_entry_time[2] = (uint8) s_tm->tm_mday; + jo->job_entry_time[3] = (uint8) s_tm->tm_hour; + jo->job_entry_time[4] = (uint8) s_tm->tm_min; + jo->job_entry_time[5] = (uint8) s_tm->tm_sec; + + jo->job_typ[0] = 0x0; /* 0xd0;*/ + jo->job_typ[1] = 0x0; + jo->job_position[0] = 0x1; + jo->job_position[1] = 0x0; + jo->job_control_flags[0] |= 0x20; + jo->job_control_flags[1] = 0x0; + + jo->job_file_name[0] + = sprintf(jo->job_file_name+1, "%07X%d.%03d", q_id, jo_id, connection); + result=nw_alloc_dir_handle(0, dirname, dir_nam_len, 99, 2, 1); + + if (result > -1) + result = nw_creat_open_file(result, jo->job_file_name+1, + (int)jo->job_file_name[0], + &fnfo, 0x6, 0x6, 1); + + DPRINTF(("creat print queue bez=`%s` handle=%d\n", jo->job_bez, result)); + + if (result > -1) { + U16_TO_BE16((uint16)result, jo->job_file_handle); + U16_TO_BE16(0, jo->job_file_handle+2); + result = 0; + } + U32_TO_BE32(0, jo->server_station); + U32_TO_BE32(0, jo->server_task); + U32_TO_BE32(0, jo->server_id); + if (!result) memcpy(queue_job, jo, sizeof(QUEUE_JOB)); + else free_queue_job(jo_id); + } + return(result); +} + +int nw_close_file_queue(uint8 *queue_id, uint8 *job_id, + uint8 *prc, int prc_len) +{ + int result = 0; + int jo_id = (int) *job_id; + DPRINTF(("nw_close_file_queue JOB=%d\n", jo_id)); + if (jo_id > 0 && jo_id <= anz_jobs){ + QUEUE_JOB *jo=queue_jobs[jo_id-1]; + int fhandle = (int) GET_BE16(jo->job_file_handle); + if (fhandle > 0 && fhandle <= anz_fhandles) { + FILE_HANDLE *fh=&(file_handles[fhandle-1]); + char unixname[300]; + char printcommand[256]; + FILE *f=NULL; + strmaxcpy(unixname, fh->name, sizeof(unixname)-1); + strmaxcpy(printcommand, prc, prc_len); + nw_close_datei(fhandle); + U16_TO_BE16((uint16)0, jo->job_file_handle); + U16_TO_BE16(0xff00, jo->record_in_use); + if (NULL != (f = fopen(unixname, "r"))) { + int is_ok = 0; + FILE *fout = popen(printcommand, "w"); + if (fout) { + char buff[1024]; + int k; + is_ok++; + while ((k = fread(buff, 1, sizeof(buff), f)) > 0) { + if (1 != fwrite(buff, k, 1, fout)) is_ok=0; + } + pclose(fout); + } else + DPRINTF(("Cannot open pipe `%s`\n", "lpr")); + + fclose(f); + if (is_ok) unlink(unixname); + } else DPRINTF(("Cannot open queue-file `%s`\n", unixname)); + } else + DPRINTF(("nw_close_file_queue fhandle=%d\n", fhandle)); + free_queue_job(jo_id); + } + return(result); +} + + diff --git a/emutli.c b/emutli.c new file mode 100644 index 0000000..70045ad --- /dev/null +++ b/emutli.c @@ -0,0 +1,504 @@ +/* emutli.c 17-Nov-95 */ + +/* + * One short try to emulate TLI with SOCKETS. + */ + +/* (C)opyright (C) 1993,1995 Martin Stover, Marburg, Germany + * + * 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. + */ + +/* + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * Some of the Code in this module is stolen from the following + * Programms: ipx_interface, ipx_route, ipx_configure, which was + * written by Greg Page, Caldera, Inc. + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + */ +#include +#include +#include +#include +#include +#include +#include +#include "net.h" +#include +#include +#include +#include +#include +#include + + +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +static int locipxdebug=0; +static int have_ipx_started=0; + + +static void set_sock_debug(int sock) +{ + if (setsockopt(sock, SOL_SOCKET, SO_DEBUG, &locipxdebug, sizeof(int))==-1){ + perror("setsockopt SO_DEBUG"); + } +} + +static void sock2ipxadr(ipxAddr_t *i, struct sockaddr_ipx *so) +{ + memcpy(i->net, &so->sipx_network, IPX_NET_SIZE + IPX_NODE_SIZE); + memcpy(i->sock, &so->sipx_port, 2); +} + +static void ipx2sockadr(struct sockaddr_ipx *so, ipxAddr_t *i) +{ + memcpy(&so->sipx_network, i->net, IPX_NET_SIZE + IPX_NODE_SIZE); + memcpy(&so->sipx_port, i->sock, 2); +} + +void set_emu_tli(int ipx_debug) +{ + locipxdebug = ipx_debug; +} + +int init_ipx(char *device, + uint32 *network, + uint32 intnet, + int frame, + char *frame_name, + int ipx_debug) +{ + int sock=-1; + int result=-1; + +#ifndef OLD_KERNEL_IPX + struct ifreq id; + struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)&id.ifr_addr; + int i; + memset(&id, 0, sizeof(struct ifreq)); + strcpy(id.ifr_name, device); + locipxdebug = ipx_debug; + + sock = socket(AF_IPX, SOCK_DGRAM, AF_IPX); + if (socket < 0) { + perror("EMUTLI:init_ipx"); + exit(1); + } + + /* NUN DEBUG ein bzw. ausschalten */ + set_sock_debug(sock); + + /* remove old ipx_interface */ + if (*network) { + sipx->sipx_network = 0L; + sipx->sipx_special = IPX_INTERNAL; + sipx->sipx_family = AF_IPX; + sipx->sipx_action = IPX_DLTITF; + (void) ioctl(sock, SIOCSIFADDR, &id); + + sipx->sipx_special = IPX_PRIMARY; + sipx->sipx_network = 0L; + sipx->sipx_family = AF_IPX; + sipx->sipx_type = frame; + sipx->sipx_action = IPX_DLTITF; + (void) ioctl(sock, SIOCSIFADDR, &id); + have_ipx_started++; + } + + sipx->sipx_special = IPX_PRIMARY; /* IPX_SPECIAL_NONE */ + /* IPX_INTERNAL */ + /* IPX_PRIMARY */ + + sipx->sipx_network = htonl(*network); + sipx->sipx_type = frame; + sipx->sipx_family = AF_IPX; + sipx->sipx_action = IPX_CRTITF; /* anlegen */ + /* IPX_DLTITF ist loeschen */ + + i = 0; + do { + result = ioctl(sock, SIOCSIFADDR, &id); + } while ((++i < 5) && (result < 0) && (errno == EAGAIN)); + + if (result) { + switch (errno) { + case EEXIST: + DPRINTF(("Primary network already selected.\n")); + result = 0; /* not a reallly error */ + break; + + case EADDRINUSE: + fprintf(stderr, "Network number (0X%08lX) already in use.\n", + htonl(sipx->sipx_network)); + break; + + case EPROTONOSUPPORT: + fprintf(stderr, "Invalid frame type (%s).\n", + frame_name); + break; + + case ENODEV: + fprintf(stderr, "No such device (%s).\n", + id.ifr_name); + break; + + case ENETDOWN: + fprintf(stderr, "Requested device (%s) is down.\n", + id.ifr_name); + break; + case EINVAL: + fprintf(stderr, "Invalid device (%s).\n", + id.ifr_name); + break; + + case EAGAIN: + fprintf(stderr, "Insufficient memory to create interface.\n"); + break; + + default: + perror("ioctl:SIOCSIFADDR"); + break; + } /* switch */ + } + +#else /* alte Kernel Version vor ???? */ + struct ipx_route_def rt; + locipxdebug = ipx_debug; + rt.ipx_network=htonl(*network); + rt.ipx_router_network=IPX_ROUTE_NO_ROUTER; + strncpy(rt.ipx_device,"eth0",16); + rt.ipx_flags=frame; + sock=socket(AF_IPX,SOCK_DGRAM,PF_IPX); + if(sock==-1) { + perror("EMUTLI:init_ipx"); + exit(1); + } + set_sock_debug(sock); + result = ioctl(sock,SIOCADDRT,(void *)&rt); + if (result && errno == EEXIST) result =0; + if (result) perror("ioctl"); +#endif + +#if 1 + if (!*network) { + struct sockaddr_ipx ipxs; + int maxplen=sizeof(struct sockaddr_ipx); + memset((char*)&ipxs, 0, sizeof(struct sockaddr_ipx)); + ipxs.sipx_family=AF_IPX; + if (bind(sock, (struct sockaddr*)&ipxs, sizeof(struct sockaddr_ipx))==-1){ + perror("EMUTLI:init_ipx"); + result = -1; + } else { + if (getsockname(sock, (struct sockaddr*)&ipxs, &maxplen) == -1){ + perror("EMUTLI:init_ipx"); + result = -1; + } else *network=ntohl(ipxs.sipx_network); + } + if (sock > -1) close(sock); + } +#endif + close(sock); + if (result) exit(1); + return(result); +} + +void exit_ipx(char *devname, uint32 network, int frame) +{ + if (have_ipx_started) { + int sock=-1; + int result=-1; + struct ifreq id; + struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)&id.ifr_addr; + int i; + memset(&id, 0, sizeof(struct ifreq)); + strcpy(id.ifr_name, devname); + sock = socket(AF_IPX, SOCK_DGRAM, AF_IPX); + if (socket < 0) { + perror("EMUTLI:exit_ipx"); + return; + } + /* Switch DEBUG off */ + locipxdebug = 0; + set_sock_debug(sock); + + /* remove routes */ + sipx->sipx_network = 0L; + sipx->sipx_special = IPX_INTERNAL; + sipx->sipx_family = AF_IPX; + sipx->sipx_action = IPX_DLTITF; + (void) ioctl(sock, SIOCSIFADDR, &id); + + sipx->sipx_special = IPX_PRIMARY; + sipx->sipx_network = 0L; + sipx->sipx_family = AF_IPX; + sipx->sipx_type = frame; + sipx->sipx_action = IPX_DLTITF; + (void) ioctl(sock, SIOCSIFADDR, &id); + close(sock); + } +} + +void myipx_route_add(unsigned char *dest_net, + unsigned char *route_net, + unsigned char *route_node) +{ + struct rtentry rd; + int i; + int result; + int sock; + /* Router */ + struct sockaddr_ipx *sr = (struct sockaddr_ipx *)&rd.rt_gateway; + /* Target */ + struct sockaddr_ipx *st = (struct sockaddr_ipx *)&rd.rt_dst; + + rd.rt_flags = RTF_GATEWAY; + memcpy(&(st->sipx_network), dest_net, IPX_NET_SIZE); + memcpy(&(sr->sipx_network), route_net, IPX_NET_SIZE); + memcpy(sr->sipx_node, route_node, IPX_NODE_SIZE); + + if ( (sock = socket(AF_IPX, SOCK_DGRAM, AF_IPX)) < 0){ + perror("EMUTLI:myipx_route_add"); + return; + } + + sr->sipx_family = st->sipx_family = AF_IPX; + i = 0; + do { + result = ioctl(sock, SIOCADDRT, &rd); + i++; + } while ((i < 5) && (result < 0) && (errno == EAGAIN)); + + if (result) { + switch (errno) { + case ENETUNREACH: + fprintf(stderr, "Router network (%08X) not reachable.\n", + htonl(sr->sipx_network)); + break; + + case EEXIST: + case EADDRINUSE: + break; + + default: + perror("add route ioctl"); + break; + } + } + close(sock); +} + +void myipx_route_del(unsigned char *net) +{ + struct rtentry rd; + int i; + int result; + int sock; + /* Router */ + struct sockaddr_ipx *sr = (struct sockaddr_ipx *)&rd.rt_gateway; + /* Target */ + struct sockaddr_ipx *st = (struct sockaddr_ipx *)&rd.rt_dst; + rd.rt_flags = RTF_GATEWAY; + memcpy(&(st->sipx_network), net, IPX_NET_SIZE); + + if ( (sock = socket(AF_IPX, SOCK_DGRAM, AF_IPX)) < 0){ + perror("EMUTLI:myipx_route_del"); + return; + } + sr->sipx_family = st->sipx_family = AF_IPX; + + i = 0; + do { + result = ioctl(sock, SIOCDELRT, &rd); + i++; + } while ((i < 5) && (result < 0) && (errno == EAGAIN)); + /* errors doesn't matter here */ + + close(sock); +} + + +int t_open(char *name, int open_mode, char * p) +{ + int opt=1; + int sock = socket(AF_IPX, SOCK_DGRAM, AF_IPX); + if (sock < 0) return(sock); + + /* NUN DEBUG ein bzw. ausschalten */ + set_sock_debug(sock); + + /* NUN Broadcast erlauben */ + if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &opt,sizeof(opt))==-1){ + perror("setsockopt SO_BROADCAST"); + close(sock); + return(-1); + } + return(sock); +} + +int t_bind(int sock, struct t_bind *a_in, struct t_bind *a_out) +{ + struct sockaddr_ipx ipxs; + int maxplen=sizeof(struct sockaddr_ipx); + memset((char*)&ipxs, 0, sizeof(struct sockaddr_ipx)); + ipxs.sipx_family=AF_IPX; + + if (a_in != (struct t_bind*) NULL + && a_in->addr.len == sizeof(ipxAddr_t)) + ipx2sockadr(&ipxs, (ipxAddr_t*) (a_in->addr.buf)); + + ipxs.sipx_network = 0L; + + if (bind(sock, (struct sockaddr*)&ipxs, sizeof(struct sockaddr_ipx))==-1) { + char xx[100]; + sprintf(xx, "TLI-BIND socket Nr:0x%x", (int)GET_BE16(&(ipxs.sipx_port))); + perror(xx); + return(-1); + } + if (a_out != (struct t_bind*) NULL) { + if (getsockname(sock, (struct sockaddr*)&ipxs, &maxplen) == -1){ + perror("TLI-GETSOCKNAME"); + return(-1); + } + sock2ipxadr((ipxAddr_t*) (a_out->addr.buf), &ipxs); + DPRINTF(("T_BIND ADR=%s\n", visable_ipx_adr((ipxAddr_t *) a_out->addr.buf ) )); + } + return(0); +} + +int t_unbind(int sock) +{ + return(0); +} + + +int t_errno=0; +void t_error(char *s) +{ + perror(s); + t_errno=0; +} + +int t_close(int fd) +{ + return(close(fd)); +} + + +int poll( struct pollfd *fds, unsigned long nfds, int timeout) +/* z.Z. nur POLL-IN */ +{ + fd_set readfs; + /* + fd_set writefs; + fd_set exceptfs; + */ + struct pollfd *p = fds; + struct timeval time_out; + int k = (int)nfds; + int result=-1; + int high_f=0; + FD_ZERO(&readfs); + /* + FD_ZERO(&writefs); + FD_ZERO(&exceptfs); + */ + while (k--){ + if (p->fd > -1 && (p->events & POLLIN)) { + FD_SET(p->fd, &readfs); + if (p->fd > high_f) high_f = p->fd; + } + p->revents=0; + p++; + } + if (timeout > 1000) { + time_out.tv_sec = timeout / 1000; + time_out.tv_usec = 0; + } else { + time_out.tv_sec = 0; + time_out.tv_usec = timeout*1000; + } + result = select(high_f+1, &readfs, NULL, NULL, &time_out); + if (result < 0) return(-1); + if (result) { + int rest=result; + k = (int)nfds; + p = fds; + while (k--){ + if (p->fd > -1 && FD_ISSET(p->fd, &readfs)){ + p->revents = POLLIN; + if (! --rest) break; /* fertig */ + } + p++; + } + } + return(result); +} + +int t_rcvudata(int fd, struct t_unitdata *ud, int *flags) +{ + struct sockaddr_ipx ipxs; + int sz = sizeof(struct sockaddr_ipx); + int result; + ipxs.sipx_family=AF_IPX; + if (ud->addr.maxlen < sizeof(ipxAddr_t)) return(-1); + result = recvfrom(fd, ud->udata.buf, ud->udata.maxlen, 0, + (struct sockaddr *) &ipxs, &sz); + + if (result < 0) return(result); + if (ud->opt.maxlen) { + *((uint8*)ud->opt.buf) = ipxs.sipx_type; + ud->opt.len = 1; + } + ud->udata.len=result; + sock2ipxadr((ipxAddr_t*) (ud->addr.buf), &ipxs); + ud->addr.len = sizeof(ipxAddr_t); + return(result); +} + + +int t_sndudata(int fd, struct t_unitdata *ud) +{ + int result; + struct sockaddr_ipx ipxs; + memset(&ipxs, 0, sizeof(struct sockaddr_ipx)); + ipxs.sipx_family=AF_IPX; + + if (ud->addr.len != sizeof(ipxAddr_t)) return(-1); + ipx2sockadr(&ipxs, (ipxAddr_t*) (ud->addr.buf)); + ipxs.sipx_type = (ud->opt.len) ? (uint8) *((uint8*)(ud->opt.buf)) : 0; + + result = sendto(fd,(void *)ud->udata.buf, + ud->udata.len, 0, (struct sockaddr *) &ipxs, sizeof(ipxs)); + + if (result<0) { + char xx[100]; + sprintf(xx, "t_sndudata->result=%d, errno=%d\n", result, errno); + perror(xx); + } + return(result); +} + + +int t_rcvuderr(int fd, struct t_uderr *ud) +{ + return(0); +} + diff --git a/emutli.h b/emutli.h new file mode 100644 index 0000000..6045b5e --- /dev/null +++ b/emutli.h @@ -0,0 +1,125 @@ +/* emutli.h 11-Sep-95 */ + +/* (C)opyright (C) 1993,1995 Martin Stover, Marburg, Germany + * + * 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 + +typedef unsigned char uint8; +typedef unsigned short int uint16; +typedef unsigned long int uint32; + +#define IPX_NET_SIZE 4 +#define IPX_NODE_SIZE 6 +#define IPX_SOCK_SIZE 2 + +typedef struct { + uint8 net[IPX_NET_SIZE]; + uint8 node[IPX_NODE_SIZE]; + uint8 sock[IPX_SOCK_SIZE]; + } ipxAddr_t; + +#define IPXCMPNODE(a, b) ( \ + ((char *)(a))[0] == ((char*)(b))[0] && \ + ((char *)(a))[1] == ((char*)(b))[1] && \ + ((char *)(a))[2] == ((char*)(b))[2] && \ + ((char *)(a))[3] == ((char*)(b))[3] && \ + ((char *)(a))[4] == ((char*)(b))[4] && \ + ((char *)(a))[5] == ((char*)(b))[5] \ +) + +struct netbuf { + unsigned int maxlen; + unsigned int len; + char *buf; +}; + +struct t_bind { + struct netbuf addr; + unsigned int qlen; +}; + + +struct t_unitdata { + struct netbuf addr; /* address */ + struct netbuf opt; /* options */ + struct netbuf udata; /* userdata */ +}; + +struct t_uderr { + struct netbuf addr; /* address */ + struct netbuf opt; /* options */ + long error; /* eroorcode */ +}; + +struct pollfd { + int fd; + short events; + short revents; +}; + +#define POLLIN 0x0001 /* fd readable */ +#define POLLPRI 0x0002 /* high priority */ + +#define TOUTSTATE 6 /* out of state */ + +extern int poll(struct pollfd *fds, unsigned long nfds, int timeout); +extern int t_open(char *name, int open_mode, char *p); +extern int t_bind(int sock, struct t_bind *a_in, struct t_bind *a_out); +extern int t_unbind(int sock); +extern void t_error(char *s); +extern int t_close(int fd); +extern int t_rcvudata(int fd, struct t_unitdata *ud, int *flags); +extern int t_rcvuderr(int fd, struct t_uderr *ud); +extern int t_sndudata(int fd, struct t_unitdata *ud); + +extern int init_ipx(char *device, uint32 *network, + uint32 intnet, + int frame, + char *frame_name, + int ipx_debug); + +extern void exit_ipx(char *devname, uint32 network, int frame); + +extern void myipx_route_add(unsigned char *dest_net, + unsigned char *route_net, + unsigned char *route_node); + +extern void myipx_route_del(unsigned char *net); + +extern void set_emu_tli(int ipx_debug); + + +#ifndef IPX_FRAME_8022 +#define OLD_KERNEL_IPX 1 +#define IPX_FRAME_8022 IPX_RT_8022 +#endif + +#ifndef IPX_FRAME_8023 +#define IPX_FRAME_8023 0 +#endif + +#ifndef IPX_FRAME_SNAP +#define IPX_FRAME_SNAP IPX_RT_SNAP +#endif + +#ifndef IPX_FRAME_ETHERII +#define IPX_FRAME_ETHERII IPX_RT_BLUEBOOK +#endif + + + diff --git a/examples/config.h b/examples/config.h new file mode 100644 index 0000000..6556fe3 --- /dev/null +++ b/examples/config.h @@ -0,0 +1,9 @@ +/* config.h: 22-Nov-95 */ +/* this config is needed by make and by cc */ +#define FILENAME_NW_INI "./nw.ini" /* full name of ini (conf) file */ +#define PATHNAME_PROGS "." /* path location of progs */ +#define PATHNAME_BINDERY "." /* path location of bindery */ + +#define MAX_CONNECTIONS 5 /* max. Number of Connections */ +#define MAX_NW_VOLS 10 /* max. Volumes */ + diff --git a/examples/mk.li b/examples/mk.li new file mode 100755 index 0000000..a583d9a --- /dev/null +++ b/examples/mk.li @@ -0,0 +1,25 @@ +#!/bin/sh +# mk.li 16-Nov-95 ### +# + +mk() +{ + MYBASE=`pwd`; + ERRFILE=$TMP/`basename $MYBASE`.err; + rm -f $ERRFILE; + if [ ! -d obj ] ; then mkdir obj; fi + cd obj; + $MAKE -f ../makefile.unx $@ 2>&1 | tee $ERRFILE; + cd ..; + chmod 666 $ERRFILE +} + +export CC=cc +export CCP="cc -E" +#export CFLAGS="-pipe -O2 -fomit-frame-pointer" +#problems gcc2.5.8 ^^^^^^^^^^^^^^^^^^^^^^^^ +export CFLAGS="-pipe" +export HOSTCFLAGS="-DLINUX" +export TMP=/tmp +MAKE=make +mk $@ diff --git a/examples/nw.ini b/examples/nw.ini new file mode 100644 index 0000000..7428979 --- /dev/null +++ b/examples/nw.ini @@ -0,0 +1,53 @@ +# (C)opyright 1993, 1995, Martin Stover, Softwareentwicklung, Marburg +# MAR.S NW-Server Emulator +# Einfache Konfiguration, alles ab # ist Kommentar. +# Jeder Eintrag beginnt mit einer Zahl und dann folgt der Inhalt. +# simple configuration, all after # is ignored. +# Every entry begins with a number and then the meet follows. +# entry 1 VOLUMES (max. 5) entry 1 +# Volumename Volumepath Options (k=lowercase) +1 SYS /u3/SYS/ # SYS 1 +#################################### +# Die folgenden Volumes sind optional. +# the following volumes are optional. +#1 SYS1 /u3/SYS1/ # SYS 2 +#1 TMP /tmp/ k # TMP downshift +#1 CD /cdrom k # CDROM allways downshift +# Falls lowercase nicht gesetzt ist, werden GROSSBUCHSTABEN erwartet. +# If lowercase is not set then all filenames are upshift. +# SYS, der Name darf auch anders lauten, muss +# eingerichtet sein mit den folgenden Verzeichnissen: +# LOGIN, PUBLIC, SYSTEM, MAIL. +# SYS, may be named diffent but must be setup and must +# contains the following Directories: LOGIN, PUBLIC, SYSTEM, MAIL +############################# +# Eintrag 2 fuer den Servername. +# falls nicht gesetzt, wird hostname (in GROSSBUCHSTABEN) verwendet. +# entry 2 for the servername. If not set, then the hostname (upshift) +# will be taken. +#2 MAR1 # Servername +# entry 4: # +# NETWORK NUMBER, DEVICE, Frame-Typ +4 0x10 eth0 802.3 +# Frames=ethernet_ii od. 802.2 od. 802.3 od SNAP (default 802.3) +# ACHTUNG ethernet_ii geht leider seit LINUX > V 1.1.44 nicht mehr. +# aktuell getestet nur mit 802.3 !!!!! +# actual testet with 802.3 !! +###################################### +# z.Z. werden _alle_ Connections mit folgender UID bzw. GID gestartet. +# wird noch geaendert werden. +# _all_ connections will be started with the following UID and GID. +# will be change one time. +10 200 # GID +11 201 # UID +############################# +# entry 21 for simple print queues, dynamic +# QUEUE NAME, Q_DIRECTORY, UNIX-print-command (pipe) +21 Q1 SYS:/PRINT/Q1 lpr +#21 Q2 SYS:/PRINT/Q2 lpr -C printer2 +############################# +# >= 100 debug flags +100 0 # debug IPX KERNEL (0 / 1) +101 1 # debug NWSERV +102 0 # debug NCPSERV +103 0 # debug NWCONN diff --git a/makefile.unx b/makefile.unx new file mode 100644 index 0000000..41f4a70 --- /dev/null +++ b/makefile.unx @@ -0,0 +1,195 @@ +# makefile.unx 15-Nov-95 +VPATH=.. +O=.o +C=.c + +DEBUG=-DDB +V_H=0 +V_L=95 +DISTRIB=mars_nwe +PATCHF=$(DISTRIB)p$(V_H).$(V_L) +STERN=* + +#if 0 +DESTMAKEFILE=Makefile.o +all: $(DESTMAKEFILE) + $(MAKE) -f $(DESTMAKEFILE) n_$@ + +clean: $(DESTMAKEFILE) + $(MAKE) -f $(DESTMAKEFILE) n_$@ + +distclean: $(DESTMAKEFILE) + $(MAKE) -f $(DESTMAKEFILE) n_$@ + +install: $(DESTMAKEFILE) + $(MAKE) -f $(DESTMAKEFILE) n_$@ + +install_ini: $(DESTMAKEFILE) + $(MAKE) -f $(DESTMAKEFILE) n_$@ + +diff: $(DESTMAKEFILE) + $(MAKE) -f $(DESTMAKEFILE) n_$@ + +distrib: $(DESTMAKEFILE) + $(MAKE) -f $(DESTMAKEFILE) n_$@ + +distrib_bin: $(DESTMAKEFILE) + $(MAKE) -f $(DESTMAKEFILE) n_$@ + +$(DESTMAKEFILE): makefile.unx config.h + rm -f $@ + cp ../makefile.unx makefile.c + $(CPP) $(HOSTCFLAGS) -I$(VPATH) makefile.c > $@ + rm -f makefile.c +#endif + + +PROG1=netinit +PROG2=nwserv +PROG3=nwconn +PROG4=ncpserv +PROG5=nwclient + +#ifdef LINUX +EMUTLIOBJ=emutli$(O) +PROG1= +NDBMLIB=-ldbm +NSLLIB= +#else +NDBMLIB=/usr/ucblib/libucb.a +NSLLIB=-lnsl +#endif + +PROGS=$(PROG1) $(PROG2) $(PROG3) $(PROG4) $(PROG5) + + +#include "config.h" +#ifdef FILENAME_NW_INI +M_FILENAME_NW_INI=FILENAME_NW_INI +#else +M_FILENAME_NW_INI="./nw.ini" +#endif + +#ifdef PATHNAME_PROGS +M_PATHNAME_PROGS=PATHNAME_PROGS +#else +M_PATHNAME_PROGS="." +#endif + +OBJ1= $(EMUTLIOBJ) net1$(O) tools$(O) +OBJ2= $(OBJ1) +#nwdbm$(O) +OBJ3= $(OBJ1) connect$(O) +OBJ4= $(OBJ1) nwdbm$(O) +OBJ5= $(OBJ1) + +OBJS= net1$(O) tools$(O) connect$(O) nwdbm$(O) \ + $(PROG2)$(O) $(PROG3)$(O) $(PROG4)$(O) $(PROG5)$(O) + +$(PROG1): $(PROG1)$(O) $(OBJ1) + $(CC) -o ../$(PROG1) $(PROG1)$(O) $(OBJ1) $(NSLLIB) + +$(PROG2): $(PROG2)$(O) $(OBJ2) + $(CC) -o ../$(PROG2) $(PROG2)$(O) $(OBJ2) $(NSLLIB) + +#$(CC) -o ../$(PROG2) $(PROG2)$(O) $(OBJ2) $(NDBMLIB) $(NSLLIB) + +$(PROG3): $(PROG3)$(O) $(OBJ3) + $(CC) -o ../$(PROG3) $(PROG3)$(O) $(OBJ3) $(NSLLIB) + +$(PROG4): $(PROG4)$(O) $(OBJ4) + $(CC) -o ../$(PROG4) $(PROG4)$(O) $(OBJ4) $(NDBMLIB) $(NSLLIB) + +$(PROG5): $(PROG5)$(O) $(OBJ5) + $(CC) -o ../$(PROG5) $(PROG5)$(O) $(OBJ5) $(NSLLIB) + +$(OBJS): net.h config.h + +$(C)$(O): + $(CC) -c $(CFLAGS) $(HOSTCFLAGS) $(DEBUG) -D_VERSION_H_=$(V_H) -D_VERSION_L_=$(V_L) $< + +n_all: $(PROGS) + +n_install_ini: + cd .. && install -m 664 nw.ini $(M_FILENAME_NW_INI) && cd obj + +n_install: + cd .. && install -d $(M_PATHNAME_PROGS) && cd obj + cd .. && install $(PROGS) $(M_PATHNAME_PROGS) && cd obj + @cd .. && (if [ -r $(M_FILENAME_NW_INI) ] ; then \ +echo ""; \ +echo "********************************************************"; \ +echo ""; \ +echo "$(M_FILENAME_NW_INI) exist."; \ +echo "to overwrite it with nw.ini, make install_ini";\ +echo ""; \ +echo "********************************************************"; \ +echo ""; \ +else \ +install -m 664 nw.ini $(M_FILENAME_NW_INI); \ +echo ""; \ +echo "********************************************************"; \ +echo ""; \ +echo "$(M_FILENAME_NW_INI) created from nw.ini"; \ +echo ""; \ +echo "********************************************************"; \ +echo ""; \ +fi; cd obj ) + +n_clean1: + cd .. && (rm -f ~* examples/~* examples/.e.pck; cd obj) + +n_clean: n_clean1 + rm -f *.o + cd .. && (rm -f $(PROGS); cd obj ) + +n_distclean: n_clean + cd .. && (rm -f *.dir *.pag; cd obj) + +n_diff: n_clean1 + cd .. && (rm -rf obj/../$(DISTRIB) \ +; mkdir $(DISTRIB) \ +; mkdir $(DISTRIB)/examples \ +; ln -f \ + $(STERN).[ch] \ + makefile.unx \ + Makefile \ + COPYING \ + README \ + README.ger \ + INSTALL \ + $(DISTRIB).lsm \ + $(DISTRIB)/. \ +; ln -f \ + examples/$(STERN) \ + $(DISTRIB)/examples/. \ +; makepatch $(DISTRIB).org $(DISTRIB) > $(PATCHF) \ +; gzip -9 -f $(PATCHF) \ +; cd obj ) + +n_distrib: n_diff + -mkdir /tmp/x + cd .. && (tar cvzf $(DISTRIB).tgz $(DISTRIB) \ +; uue $(DISTRIB).tgz \ +; cp -a $(DISTRIB)/$(DISTRIB).lsm /tmp/yy \ +; echo "" >> /tmp/yy \ +; echo "" >> /tmp/yy \ +; cat $(DISTRIB).uue >> /tmp/yy \ +; chmod 664 /tmp/yy \ +; rm $(DISTRIB).uue \ +; mv $(DISTRIB).tgz /tmp/x/. \ +; cp -a $(DISTRIB)/$(DISTRIB).lsm /tmp/x/. \ +; cd obj ) + +n_distrib_bin: + cd .. && (tar cvzf /tmp/$(DISTRIB).bin.tgz \ + $(PROGS) \ + COPYING \ + INSTALL \ + README \ + README.ger \ + $(DISTRIB).lsm \ + examples \ +; cd obj) + + diff --git a/mars_nwe.lsm b/mars_nwe.lsm new file mode 100644 index 0000000..6544507 --- /dev/null +++ b/mars_nwe.lsm @@ -0,0 +1,15 @@ +Begin3 +Title: mars_nwe +Version: 0.95 +Entered-date: 22-Nov-95 +Description: simple novell-server-emulator (src),beta + needs no kernelchanges, usefull for testing ipx + file-services, bindery-services, printing-services +Keywords: novell, netware, server, ipx, ncp, tli +Author: mstover@kool.f.eunet.de (Martin Stover) +Maintained-by: mstover@kool.f.eunet.de (Martin Stover) +Primary-site: linux01.gwdg.de /pub/??? + 80kB mars_nwe.tgz +Platforms: Linux (1.2.xx testet, others should work) +Copying-policy: GNU +End diff --git a/ncpserv.c b/ncpserv.c new file mode 100644 index 0000000..259df47 --- /dev/null +++ b/ncpserv.c @@ -0,0 +1,1350 @@ +/* ncpserv.c, 22-Nov-95 */ + +/* (C)opyright (C) 1993,1995 Martin Stover, Marburg, Germany + * + * 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 "net.h" +#include "nwdbm.h" + +int conn_gid; +int conn_uid; + +int nwconn_debug=0; +int ipxdebug=0; + +static int ncp_fd = -1; +static uint8 ipx_in_data[IPX_MAX_DATA+500]; /* space for additional data */ +static NCPREQUEST *ncprequest = (NCPREQUEST*)&ipx_in_data; +static struct t_unitdata ud; +static int in_len=0; +static uint8 ipx_pack_typ=17; +static ipxAddr_t from_addr; /* aktuelle Anforderungsaddresse */ +static ipxAddr_t my_addr; +static int rcv_flags = 0; +static char my_nwname[50]; +static time_t akttime; + +static void write_to_nwserv(int what, int connection, char *data, int size) +{ + switch (what) { + case 0x2222 : /* insert wdog connection */ + write(FD_NWSERV, &what, sizeof(int)); + write(FD_NWSERV, &connection, sizeof(int)); + write(FD_NWSERV, data, size); /* ipxAddr_t */ + break; + + case 0x4444 : /* tell the wdog there's no need to look */ + case 0x6666 : /* the connection ist closed */ + case 0x8888 : /* send to client that server holds message */ + write(FD_NWSERV, &what, sizeof(int)); + write(FD_NWSERV, &connection, sizeof(int)); + break; + + default : break; + } +} + +static int open_ncp_socket() +{ + struct t_bind bind; + ncp_fd=t_open("/dev/ipx", O_RDWR, NULL); + if (ncp_fd < 0) { + t_error("t_open !Ok"); + return(-1); + } + U16_TO_BE16(SOCK_NCP, my_addr.sock); /* NCP_SOCKET */ + bind.addr.len = sizeof(ipxAddr_t); + bind.addr.maxlen = sizeof(ipxAddr_t); + bind.addr.buf = (char*)&my_addr; + bind.qlen = 0; /* immer */ + if (t_bind(ncp_fd, &bind, &bind) < 0){ + t_error("t_bind in open_ncp_socket !OK"); + close(ncp_fd); + return(-1); + } + return(0); +} + +typedef struct { + int fd; /* writepipe */ + int pid; /* pid from son */ + ipxAddr_t client_adr; /* address client */ + uint32 object_id; /* logged object */ + /* 0 = not logged in */ + uint8 crypt_key[8]; /* password generierung */ + + uint8 message[60]; /* saved BCastmessage */ + int sequence; /* previous sequence */ + int retry; /* one reply being serviced is sent */ + time_t last_access; /* time of last 0x2222 request */ + time_t t_login; /* login time */ +} CONNECTION; + +static CONNECTION connections[MAX_CONNECTIONS]; +static int anz_connect=0; /* aktuelle Connections */ + +static int new_conn_nr(void) +{ + int j = -1; + if (!anz_connect){ /* alles initialisieren */ + j = MAX_CONNECTIONS; + while (j--) { + connections[j].fd = -1; + connections[j].message[0] = '\0'; + } + anz_connect++; + return(1); + } + j = -1; + while (++j < MAX_CONNECTIONS) { + if (connections[j].fd < 0) { + connections[j].message[0] = '\0'; + if (++j > anz_connect) anz_connect=j; + return(j); + } + } + return(0); /* nichts frei */ +} + +int free_conn_nr(int nr) +{ + if (nr && --nr < anz_connect) { + connections[nr].fd = -1; + return(0); + } + return(-1); +} + +int find_conn_nr(ipxAddr_t *addr) +{ + int j = -1; + while (++j < anz_connect) { + if (connections[j].fd > -1 && + !memcmp((char*)&(connections[j].client_adr), + (char*)addr, sizeof(ipxAddr_t))) return(++j); + } + return(0); +} + +void clear_connection(int conn) +{ + write_to_nwserv(0x6666, conn, NULL, 0); + if (conn > 0 && --conn < anz_connect) { + CONNECTION *c = &connections[conn]; + if (c->fd > -1) { + close(c->fd); + c->fd = -1; + if (c->pid > -1) { + kill(c->pid, SIGTERM); /* hier nochmal's killen */ + c->pid = -1; + } + } + c->object_id = 0; + conn = anz_connect; + while (conn--) { + CONNECTION *c = &connections[conn]; + if (c->fd < 0) anz_connect--; + else break; + } + } +} + +int find_get_conn_nr(ipxAddr_t *addr) +{ + int connection=find_conn_nr(addr); + if (!connection){ + if ((connection = new_conn_nr()) > 0){ + CONNECTION *c=&(connections[connection-1]); + int fds[2]; + memcpy((char*) &(c->client_adr), (char *)addr, sizeof(ipxAddr_t)); + if (pipe(fds) < 0) { + perror("find_get_conn_nr, pipe"); + free_conn_nr(connection); + return(0); + } else { + int akt_pid = getpid(); + int pid = fork(); + if (pid < 0) { + perror("find_get_conn_nr, fork"); + free_conn_nr(connection); + close(fds[0]); + close(fds[1]); + return(0); + } + if (pid == 0) { + /* new process */ + char *progname="nwconn"; + char pathname[300]; + char pidstr[20]; + char connstr[20]; + char addrstr[100]; + char gidstr[10]; + char uidstr[10]; + char db_str1[5]; + char db_str2[5]; + int j = 2; + close(fds[1]); /* no writing */ + dup2(fds[0], 0); /* becomes stdin */ + close(fds[0]); /* not needed */ + + while (j++ < 100) close(j); /* close all > stderr */ + + sprintf(pidstr, "%d", akt_pid); + sprintf(connstr, "%d", connection); + + sprintf(gidstr, "%d", conn_gid); + sprintf(uidstr, "%d", conn_uid); + + sprintf(db_str1, "%d", nwconn_debug); + + sprintf(db_str2, "%d", ipxdebug); + + ipx_addr_to_adr(addrstr, addr); + execl(get_exec_path(pathname, progname), progname, + pidstr, addrstr, connstr, + gidstr, uidstr, + db_str1, + db_str2, NULL); + exit(1); /* normaly not reached */ + } + c->pid = pid; + c->fd = fds[1]; + close(fds[0]); /* no need to read */ + XDPRINTF((5, "AFTER FORK new PROCESS =%d, connection=%d\n", pid, connection)); + } + } + } + if (connection) write_to_nwserv(0x2222, connection, (char*)addr, sizeof(ipxAddr_t)); + return(connection); +} + +static void get_login_time(uint8 login_time[], CONNECTION *cx) +{ + struct tm *s_tm = localtime(&(cx->t_login)); + + login_time[0] = s_tm->tm_year; + login_time[1] = s_tm->tm_mon+1; + login_time[2] = s_tm->tm_mday; + + login_time[3] = s_tm->tm_hour; + login_time[4] = s_tm->tm_min; + login_time[5] = s_tm->tm_sec; + login_time[6] = s_tm->tm_wday; +} + + +static int handle_fxx(CONNECTION *c, int gelen, int func) +/* here are handled the global 0x15, 0x17 functions */ +{ + IPX_DATA ipxoutdata; + NCPRESPONSE *ncpresponse = (NCPRESPONSE*)&ipxoutdata; + uint8 *responsedata = ((uint8*)&ipxoutdata)+sizeof(NCPRESPONSE); + uint8 *requestdata = ((uint8*)ncprequest)+sizeof(NCPREQUEST); + + uint8 len = *(requestdata+1); + uint8 ufunc = *(requestdata+2); + uint8 *rdata = requestdata+3; + uint8 completition = 0; + uint8 connect_status= 0; + int data_len = 0; + + if (nw_debug){ + int j = gelen - sizeof(NCPREQUEST); + if (nw_debug){ + DPRINTF(("NCP 0x%x REQUEST:ufunc:0x%x\n", func, ufunc)); + if (j > 0){ + uint8 *p=requestdata; + DPRINTF(("len %d, DATA:", j)); + while (j--) { + int c = *p++; + if (c > 32 && c < 127) DPRINTF((",\'%c\'", (char) c)); + else DPRINTF((",0x%x", c)); + } + DPRINTF(("\n")); + } + } + } + + if (0x15 == func) { + switch (ufunc) { /* Messages */ + case 0x0 : { /* Send Broadcast Message (old) */ + int anz_conns = (int)*(rdata); /* Number of connections */ + uint8 *conns = rdata+1; /* connectionslist */ + int msglen = *(conns+anz_conns); + uint8 *msg = conns+anz_conns+1; + uint8 *p = responsedata; + int one_found = 0; + int k = -1; + *p++ = (uint8) anz_conns; + while (++k < anz_conns) { + int connr = (int) (*conns++); + int result = 0xff; /* target not ok */ + CONNECTION *cn; + if (connr > 0 && --connr < anz_connect + && ((cn = &connections[connr]))->fd > -1 ) { + if (!cn->message[0]) { + strmaxcpy(cn->message, msg, min(58, msglen)); + result = 0; /* Ok */ + } else result = 0xfc; /* server holds message */ + write_to_nwserv(0x8888, connr+1, NULL, 0); + one_found++; + } + *p++ = (uint8)result; + } + if (one_found) data_len = anz_conns+1; + else completition=0xff; + } + break; + + case 0x01: { /* Get Broadcast Message (old) */ + *responsedata = (uint8) strmaxcpy(responsedata+1, c->message, 58); + c->message[0] = '\0'; + data_len = (int)(*responsedata) + 1; + } + break; + + case 0x03: { /* Enable Broadcasts */ + ;;; + DPRINTF(("TODO: enable Broadcasts\n")); + } + break; + + case 0x09: { /* Broadcast to CONSOLE */ + char message[60]; + strmaxcpy(message, rdata+1, min(59, *rdata)); + fprintf(stderr, "\n:%s\n", message); + } + break; + + case 0xa: /* Send Broadcast Message (new) */ + case 0xb: /* Get Broadcast Message (new) */ + default : return(-1); /* not handled */ + } /* switch */ + } else if (0x17 == func) { /* Fileserver Enviro */ + switch (ufunc) { + case 0x01 : { /* Change User Password OLD */ + completition=0xff; + } + break; + + case 0x0c : { /* Verify Serialization */ + completition=0xff; + } + break; + + case 0x0e : { /* Get Disk Utilization */ + completition=0xff; + } + break; + + case 0x11 : { /* Get FileServer Info */ + struct XDATA { + uint8 servername[48]; + uint8 version; /* 3 */ + uint8 subversion; /* 11 */ + uint8 maxconnections[2]; + uint8 connection_in_use[2]; + uint8 max_volumes[2]; + uint8 os_revision; + uint8 sft_level; + uint8 tts_level; + uint8 peak_connection[2]; + uint8 accounting_version; + uint8 vap_version; + uint8 queuing_version; + uint8 print_server_version; + uint8 virtual_console_version; + uint8 security_level; + uint8 internet_bridge_version; + uint8 reserved[60]; + } *xdata = (struct XDATA*) responsedata; + memset(xdata, 0, sizeof(struct XDATA)); + strcpy(xdata->servername, my_nwname); + xdata->version = 3; + xdata->subversion = 11; + U16_TO_BE16(MAX_CONNECTIONS, xdata->maxconnections); + U16_TO_BE16(anz_connect, xdata->connection_in_use); + U16_TO_BE16(MAX_NW_VOLS, xdata->max_volumes); + data_len = sizeof(struct XDATA); + } break; + + case 0x12 : { /* Get Network Serial Number */ + struct XDATA { + uint8 serial_number[4]; + uint8 appl_number[2]; + } *xdata = (struct XDATA*) responsedata; + /* serial-number 4-Byte */ + U32_TO_BE32(0x44444444, xdata->serial_number); + /* applikation-number 2-Byte */ + U16_TO_BE16(0x2222, xdata->appl_number); + data_len = sizeof(struct XDATA); + } + break; + + case 0x13 : { /* Get Connection Internet Address */ + int conn = (int)*(rdata); /* Connection Nr */ + if (conn && --conn < anz_connect + && connections[conn].fd > -1 ) { + CONNECTION *cx=&(connections[conn]); + data_len = sizeof(ipxAddr_t); + memcpy(responsedata, (char*)&(cx->client_adr), data_len); + } else completition = 0xff; + } break; + + case 0x14 : { /* Login Objekt, unencrypted passwords */ + uint8 *p = rdata; + uint8 *p1 = p+3 + *(p+2); /* here is password */ + int result; + NETOBJ obj; + char password[80]; + obj.type = GET_BE16(p); + strmaxcpy((char*)obj.name, (char*)(p+3), (int) *(p+2)); + upstr(obj.name); + strmaxcpy(password, (char*)(p1+1), + max(sizeof(password)-1, (int) *p1)); + DPRINTF(("LOGIN unencrypted PW NAME='%s', PASSW='%s'\n", + obj.name, password)); + if (0 == (result = find_obj_id(&obj, 0))) { + /* TODO: check password !!!!!!! */ + ;; + } + if (!result) { + c->object_id = obj.id; /* actuell Object ID */ + c->t_login = akttime; /* u. login Time */ + } else completition = (uint8) -result; + } break; + + + case 0x16 : { /* Get Connection Info, OLD */ + struct XDATA { + uint8 object_id[4]; + uint8 object_type[2]; + uint8 object_name[48]; + uint8 login_time[7]; + uint8 reserved; + } *xdata = (struct XDATA*) responsedata; + int conn = (uint16)*(rdata); /* Connection Nr */ + memset(xdata, 0, sizeof(struct XDATA)); + data_len = sizeof(struct XDATA); + if (conn && conn <= anz_connect + && connections[conn-1].fd > -1 ) { + CONNECTION *cx=&(connections[conn-1]); + NETOBJ obj; + int result; + obj.id = cx->object_id; + result = nw_get_obj(&obj); + if (!result) { + memset(xdata, 0, sizeof(struct XDATA)); + U32_TO_BE32(obj.id, xdata->object_id); + U16_TO_BE16(obj.type, xdata->object_type); + strncpy(xdata->object_name, obj.name, 48); + get_login_time(xdata->login_time, cx); + } /* else completition = (uint8)(-result); */ + } else if (!conn || conn > MAX_CONNECTIONS) { + data_len = 0; + completition = 0xfd; + } + } break; + + case 0x17 : { /* get crypt key */ + int k = sizeof(c->crypt_key); + uint8 *p = c->crypt_key; + uint8 *pp = responsedata; + data_len = k; + while (k--) *pp++ = *p++ = (uint8) rand(); + } + break; + + case 0x18 : { /* crypt_keyed LOGIN */ + uint8 *p = rdata+sizeof(c->crypt_key); + NETOBJ obj; + int result; + obj.type = GET_BE16(p); + strmaxcpy((char*)obj.name, (char*)(p+3), *(p+2)); + upstr(obj.name); + DPRINTF(("LOGIN CRYPTED PW NAME='%s'\n",obj.name)); + if (0 == (result = find_obj_id(&obj, 0))) { + /* TODO: check password !!!!!!! */ + ;; + } + if (!result) { + c->object_id = obj.id; /* actuell Object */ + c->t_login = akttime; /* and login time */ + } else completition = (uint8) -result; + } + break; + + case 0x1c : { /* Get Connection Info, new */ + struct XDATA { + uint8 object_id[4]; + uint8 object_type[2]; + uint8 object_name[48]; + uint8 login_time[7]; + uint8 reserved; + } *xdata = (struct XDATA*) responsedata; + int conn = (uint16)*(rdata); /* Connection Nr */ + if (conn && --conn < anz_connect){ + CONNECTION *cx=&(connections[conn]); + NETOBJ obj; + int result; + obj.id = cx->object_id; + result = nw_get_obj(&obj); + if (!result) { + memset(xdata, 0, sizeof(struct XDATA)); + U32_TO_BE32(obj.id, xdata->object_id); + U16_TO_BE16(obj.type, xdata->object_type); + strncpy(xdata->object_name, obj.name, 48); + get_login_time(xdata->login_time, cx); + data_len = sizeof(struct XDATA); + } else completition = (uint8)(-result); + } else completition = 0xff; + } break; + + + case 0x32 : { /* Create Bindery Object */ + NETOBJ obj; + int result; + uint8 *p = rdata; + obj.flags = *p++; + obj.security = *p++; + obj.type = GET_BE16(p); + strmaxcpy((char*)obj.name, (char*)p+3, (int) *(p+2)); + result = nw_create_obj(&obj, 0); + if (result < 0) completition = (uint8) -result; + } break; + + case 0x33 : { /* delete OBJECT */ + uint8 *p = rdata; + int result; + NETOBJ obj; + obj.type = GET_BE16(p); + strmaxcpy((char*)obj.name, (char*)(p+3), (int) *(p+2)); + result = nw_delete_obj(&obj); + if (result < 0) completition = (uint8) -result; + } break; + + case 0x34 : { /* rename OBJECT, only SU */ + uint8 *p = rdata; + int result; + NETOBJ obj; + uint8 newname[256]; + uint8 *p1 = p+3 + *(p+2); /* new Name Length */ + obj.type = GET_BE16(p); + strmaxcpy((char*)obj.name, (char*)(p+3), (int) *(p+2)); + strmaxcpy((char*)newname, (char*)(p1+1), (int) *(p1)); + result = nw_rename_obj(&obj, newname); + if (result) completition = (uint8) -result; + } break; + + + case 0x35 : { /* get Bindery Object ID */ + struct XDATA { + uint8 object_id[4]; + uint8 object_type[2]; + uint8 object_name[48]; + } *xdata = (struct XDATA*) responsedata; + uint8 *p = rdata; + int result; + NETOBJ obj; + obj.type = GET_BE16(p); + strmaxcpy((char*)obj.name, (char*)(p+3), (int) *(p+2)); + result = find_obj_id(&obj, 0); + if (!result){ + U32_TO_BE32(obj.id, xdata->object_id); + U16_TO_BE16(obj.type, xdata->object_type); + strncpy(xdata->object_name, obj.name, 48); + data_len = sizeof(struct XDATA); + } else completition = (uint8) -result; + } break; + + case 0x36 : { /* get Bindery Object Name */ + struct XDATA { + uint8 object_id[4]; + uint8 object_type[2]; + uint8 object_name[48]; + } *xdata = (struct XDATA*) responsedata; + uint8 *p = rdata; + int result; + NETOBJ obj; + obj.id = GET_BE32(p); + result = nw_get_obj(&obj); + if (!result){ + U32_TO_BE32(obj.id, xdata->object_id); + U16_TO_BE16(obj.type, xdata->object_type); + strncpy(xdata->object_name, obj.name, 48); + data_len = sizeof(struct XDATA); + } else completition = (uint8) -result; + } break; + + case 0x37 : { /* Scan Bindery Object */ + struct XDATA { + uint8 object_id[4]; + uint8 object_type[2]; + uint8 object_name[48]; + uint8 object_flag; + uint8 object_security; + uint8 object_has_properties; + } *xdata = (struct XDATA*) responsedata; + uint32 last_obj_id = GET_BE32(rdata); + uint8 *p = rdata+4; + int result; + NETOBJ obj; + obj.type = GET_BE16(p); + strmaxcpy((char*)obj.name, (char*)(p+3),(int) *(p+2)); + result = find_obj_id(&obj, last_obj_id); + if (!result){ + U32_TO_BE32(obj.id, xdata->object_id); + U16_TO_BE16(obj.type, xdata->object_type); + strncpy(xdata->object_name, obj.name, 48); + xdata->object_flag = obj.flags; + xdata->object_security = obj.security; + if (nw_obj_has_prop(&obj) > 0) + xdata->object_has_properties = 0xff; + else xdata->object_has_properties = 0; + data_len = sizeof(struct XDATA); + } else completition = (uint8) -result; + } + break; + + case 0x38 : { /* change Bindery Objekt Security */ + /* only SU ! */ + uint8 *p = rdata; + int result; + NETOBJ obj; + obj.type = GET_BE16(p+1); + strmaxcpy((char*)obj.name, (char*)(p+4), (int) *(p+3)); + result = nw_change_obj_security(&obj, (int)*p); + } break; + + case 0x39 : { /* create Property */ + uint8 *p = rdata; + int object_type = GET_BE16(p); + int object_namlen = (int) *(p+=2); + uint8 *object_name = ++p; + int prop_flags = (int) *(p+=object_namlen); + int prop_security = (int) *(++p); + int prop_namlen = (int) *(++p); + uint8 *prop_name = ++p; + int result = nw_create_prop( object_type, + object_name, object_namlen, + prop_name, prop_namlen, + prop_flags, prop_security); + if (result) completition = (uint8) -result; + } break; + + + case 0x3a : { /* delete property */ + uint8 *p = rdata; + int object_type = GET_BE16(p); + int object_namlen = (int) *(p+2); + uint8 *object_name= p+3; + int prop_namlen = (int) *(p+3+object_namlen); + uint8 *prop_name = p+4+object_namlen; + int result = nw_delete_property( object_type, + object_name, object_namlen, + prop_name, prop_namlen); + if (result < 0) completition = (uint8) -result; + } break; + + + + case 0x3b : { /* Change Prop Security */ + uint8 *p = rdata; + int object_type = GET_BE16(p); + int object_namlen = (int) *(p+=2); + uint8 *object_name= ++p; + int prop_security = (int) *(p+=object_namlen); + int prop_namlen = (int) *(++p); + uint8 *prop_name = ++p; + int result = nw_change_prop_security(object_type, + object_name, object_namlen, + prop_name, prop_namlen, prop_security); + if (result) completition = (uint8) -result; + } break; + + case 0x3c : { /* Scan Property */ + struct XDATA { + uint8 prop_name[16]; + uint8 flags; /* set=2, dynamic=1 */ + uint8 security; + uint8 akt_scan[4]; + uint8 has_value; /* ff, if there are Prop's Values */ + uint8 weisnicht; + } *xdata = (struct XDATA*) responsedata; + uint8 *p = rdata; + int object_type = GET_BE16(p); + int object_namlen = (int) *(p+2); + uint8 *object_name = (p+=3); + uint32 last_scan = GET_BE32((p+object_namlen)); + uint8 prop_namlen = (int)* (p+=object_namlen+4); + uint8 *prop_name = ++p; + NETPROP prop; + int result = nw_scan_property(&prop, + object_type, object_name, object_namlen, + prop_name, prop_namlen, &last_scan); + if (result > -1) { + strncpy(xdata->prop_name, + prop.name, sizeof(xdata->prop_name)); + U32_TO_BE32(last_scan, xdata->akt_scan); + xdata->flags = prop.flags; + xdata->security = prop.security; + xdata->has_value = (uint8) result; + xdata->weisnicht = 0x0; + data_len = sizeof(struct XDATA); + } else completition = (uint8) -result; + } break; + + case 0x3d : { /* read Bindery Property Value */ + struct XDATA { + uint8 property_value[128]; + uint8 more_segments; + uint8 property_flags; + } *xdata = (struct XDATA*) responsedata; + uint8 *p = rdata; + int object_type = GET_BE16(p); + int object_namlen = (int) *(p+2); + uint8 *object_name= p+3; + int segment_nr = (int) *(p+3+object_namlen); + int prop_namlen = (int) *(p+4+object_namlen); + uint8 *prop_name = p+5+object_namlen; + int result = nw_get_prop_val( object_type, + object_name, object_namlen, + segment_nr, + prop_name, prop_namlen, + xdata->property_value, + &(xdata->more_segments), + &(xdata->property_flags)); + if (!result){ + data_len = sizeof(struct XDATA); + } else completition = (uint8) -result; + } break; + + case 0x3e : { /* write Bindery Property Value */ + uint8 *p = rdata; + int object_type = GET_BE16(p); + int object_namlen = (int) *(p+2); + uint8 *object_name= p+3; + int segment_nr = (int) *(p+3+object_namlen); + int erase_segment = (int) *(p+4+object_namlen); + int prop_namlen = (int) *(p+5+object_namlen); + uint8 *prop_name = p+6+object_namlen; + uint8 *valdata = p+6+object_namlen+prop_namlen; + int result = nw_write_prop_value( object_type, + object_name, object_namlen, + segment_nr, erase_segment, + prop_name, prop_namlen, + valdata); + if (result) completition = (uint8) -result; + } break; + + + case 0x40: { /* change object password */ + ; + } break; + + case 0x41 : { /* add Bindery Object to Set */ + uint8 *p = rdata; + int object_type = GET_BE16(p); + int object_namlen = (int) *(p+=2); + uint8 *object_name= ++p; + int prop_namlen = (int) *(p+=object_namlen); + uint8 *prop_name = ++p; + int member_type = GET_BE16(p+prop_namlen); + int member_namlen = (int) *(p+=(prop_namlen+2)); + uint8 *member_name= ++p; + int result = nw_add_obj_to_set( object_type, + object_name, object_namlen, + prop_name, prop_namlen, + member_type, + member_name, member_namlen); + if (result) completition = (uint8) -result; + } break; + + case 0x42 : { /* delete Bindery Object from Set */ + uint8 *p = rdata; + int object_type = GET_BE16(p); + int object_namlen = (int) *(p+=2); + uint8 *object_name= ++p; + int prop_namlen = (int) *(p+=object_namlen); + uint8 *prop_name = ++p; + int member_type = GET_BE16(p+prop_namlen); + int member_namlen = (int) *(p+=(prop_namlen+2)); + uint8 *member_name= ++p; + int result = nw_delete_obj_from_set( object_type, + object_name, object_namlen, + prop_name, prop_namlen, + member_type, + member_name, member_namlen); + if (result) completition = (uint8) -result; + } break; + + case 0x43 : { /* is Bindery Object in Set */ + uint8 *p = rdata; + int object_type = GET_BE16(p); + int object_namlen = (int) *(p+=2); + uint8 *object_name= ++p; + int prop_namlen = (int) *(p+=object_namlen); + uint8 *prop_name = ++p; + int member_type = GET_BE16(p+prop_namlen); + int member_namlen = (int) *(p+=(prop_namlen+2)); + uint8 *member_name= ++p; + int result = nw_is_obj_in_set( object_type, + object_name, object_namlen, + prop_name, prop_namlen, + member_type, + member_name, member_namlen); + if (result) completition = (uint8) -result; + } break; + + + case 0x44 : { /* CLOSE BINDERY */ + ; + } break; + + case 0x45 : { /* OPEN BINDERY */ + ; + } break; + + + case 0x46 : { /* GET BINDERY ACCES LEVEL */ +#if 0 + struct XDATA { + uint8 acces_level; + uint8 object_id[4]; + } *xdata = (struct XDATA*) responsedata; +#else + uint8 *xdata = responsedata; +#endif + + NETOBJ obj; + obj.id = c->object_id; + if (0 != obj.id) { + int result = nw_get_obj(&obj); + if (!result) { + *xdata = obj.security; + U32_TO_BE32(obj.id, (xdata+1)); + DPRINTF(("ACCESS LEVEL:=0x%x, obj=0x%lx\n", + (int) obj.security, obj.id)); + data_len = 5; + } else completition = (uint8)-result; + } else { + *xdata = 0; + memset(xdata+1, 0xff, 4); + data_len = 5; + } + } + break; + + + case 0x47 : { /* SCAN BINDERY OBJECT TRUSTEE PATH */ + /* TODO !!! */ + completition = (uint8)0xff; + } + break; + + case 0x48 : { /* GET BINDERY ACCES LEVEL from OBJECT ??? */ + struct XDATA { + uint8 acces_level; + } *xdata = (struct XDATA*) responsedata; + NETOBJ obj; + int result; + obj.id = GET_BE32(rdata); + result = nw_get_obj(&obj); + if (!result) { + xdata->acces_level = obj.security; + data_len = sizeof(struct XDATA); + } else completition = (uint8)-result; + } + break; + + case 0x49 : { /* IS CALLING STATION A MANAGER */ + NETOBJ obj; + int result; + obj.id = GET_BE32(rdata); + /* TODO !! */ + completition = 0; /* here allways Manager */ + /* not manager, then completition = 0xff */ + } + break; + + case 0x4a : { /* keyed verify password */ + uint8 *p = rdata+sizeof(c->crypt_key); + NETOBJ obj; + int result; + obj.type = GET_BE16(p); + strmaxcpy((char*)obj.name, (char*)(p+3), *(p+2)); + upstr(obj.name); + DPRINTF(("TODO:Keyed Verify PW from OBJECT='%s'\n",obj.name)); + if (0 == (result = find_obj_id(&obj, 0))) { + /* TODO: check password !!!!!!! */ + ;; + } + if (!result) { + ;;; + } else + completition = (uint8) -result; + } + break; + + case 0x4b : { /* keyed change pasword */ + uint8 *p = rdata+sizeof(c->crypt_key); + NETOBJ obj; + int result; + uint8 *pw; + int pw_len; + obj.type = GET_BE16(p); + p+=2; + strmaxcpy((char*)obj.name, (char*)(p+1), *p); + upstr(obj.name); + p += (*p+1); /* here is now password */ + DPRINTF(("TODO:Keyed Change PW from OBJECT='%s'\n",obj.name)); + if (0 == (result = find_obj_id(&obj, 0))) { + /* TODO: check password !!!!!!! */ + ;; + } + if (!result) { + ;;; + /* completition = 0xff; (password not ok) */ + } else + completition = 0xff; /* password not ok) */ + /* completition = (uint8) -result; */ + } + break; + +#if 0 + case 0x4c : { /* List Relations of an Object */ + + + } break; +#endif + + + case 0x64 : { /* Create Queue */ + /* !!!!!! TO DO */ + DPRINTF(("Create QUEUE ??\n")); + } break; + + case 0x66 : { /* Read Queue Current Status */ + /* !!!!!! TO DO */ + NETOBJ obj; + obj.id = GET_BE32(rdata); + DPRINTF(("READ QUEUE STATUS von Q=0x%lx\n", obj.id)); + completition=0xd5; /* no Queue Job */ + }break; + + case 0x6B : { /* Get Queue Job List, old */ + /* !!!!!! TO DO */ + NETOBJ obj; + obj.id = GET_BE32(rdata); + DPRINTF(("GET QUEUE JOB LIST von Q=0x%lx\n", obj.id)); + completition=0xd5; /* no Queue Job */ + }break; + + case 0x6C : { /* Get Queue Job Entry */ + /* !!!!!! TODO */ + NETOBJ obj; + obj.id = GET_BE32(rdata); + DPRINTF(("TODO: GET QUEUE JOB ENTRY von Q=0x%lx\n", obj.id)); + completition=0xd5; /* no Queue Job */ + }break; + + case 0x79: { /* creat queue job and file */ + uint32 q_id = GET_BE32(rdata); + uint8 *dir_name = rdata+4+280+1; + int result = nw_get_q_dirname(q_id, dir_name); + if (result > -1) { + *(dir_name-1) = result; + in_len = 295 + result; + return(-1); /* nwconn must do the rest !!!!! */ + } else completition = (uint8) -result; + } + break; + + case 0x7f: { /* close file and start queue */ + uint32 q_id = GET_BE32(rdata); + uint8 *prc = rdata+4+4+1; + int result = nw_get_q_prcommand(q_id, prc); + if (result > -1) { + *(prc-1) = result; + in_len = 19 + result; + return(-1); /* nwconn must do the rest !!!!! */ + } else completition = (uint8) -result; + } + break; + + case 0xc8 : { /* CHECK CONSOLE PRIVILEGES */ + DPRINTF(("TODO: CHECK CONSOLE PRIV \n")); + /* !!!!!! TODO completition=0xc6 (no rights) */ + } break; + + case 0xc9 : { /* GET FILE SERVER DESCRIPTION STRINGs */ + char *company = "Mars"; + char *revision = "Version %d.%d"; + char *revision_date= "22-Nov-95"; + char *copyright = "(C)opyright Martin Stover"; + int k=strlen(company)+1; + + memset(responsedata, 0, 512); + strcpy(responsedata, company); + k += (1+sprintf(responsedata+k, revision, + _VERSION_H_, _VERSION_L_ )); + strcpy(responsedata+k, revision_date); + k += (strlen(revision_date)+1); + strcpy(responsedata+k, copyright); + k += (strlen(copyright)+1); + data_len = k; + } break; + + case 0xcd : { /* GET FILE SERVER LOGIN STATUS */ + struct XDATA { + uint8 login_allowed; /* 0 NO , 1 YES */ + } *xdata = (struct XDATA*) responsedata; + xdata->login_allowed = 1; + data_len = 1; + } + break; + + case 0xd1 : /* Send Console Broadcast (old) */ + { + uint8 *p = rdata; + int anz_conns = (int) *p++; + uint8 *co = p; + int msglen = (int) *(p+anz_conns); + char *msg = p+anz_conns+1; + int k = -1; + if (anz_conns) { + while (++k < anz_conns) { + int conn= (int) *co++; + if (conn == ncprequest->connection) { + strmaxcpy(c->message, msg, min(58, msglen)); + connect_status = 0x40; /* don't know why */ + } else if (conn && --conn < anz_connect) { + CONNECTION *cc= &(connections[conn]); + if (cc->object_id) { /* if logged */ + strmaxcpy(cc->message, msg, min(58, msglen)); + write_to_nwserv(0x8888, conn+1, NULL, 0); + } + } + } + } else { + strmaxcpy(c->message, msg, min(58, msglen)); + connect_status = 0x40; /* don't know why */ + } + } + break; +#if 0 + case 0xfd : /* Send Console Broadcast (new) */ + return(-1); /* nicht erkannt */ + break; + + case 0xd3 : { /* down File Server */ + } + break; +#endif + default : return(-1); /* not known here */ + } /* switch */ + } else return(-1); /* not kwown here */ + + U16_TO_BE16(0x3333, ncpresponse->type); + ncpresponse->sequence = ncprequest->sequence; + ncpresponse->connection = ncprequest->connection; + ncpresponse->reserved = 0; + ncpresponse->completition = completition; + ncpresponse->connect_status = connect_status; + data_len=write(c->fd, (char*)ncpresponse, + sizeof(NCPRESPONSE) + data_len); + DPRINTF(("0x%x 0x%x compl:0x%x, write to %d, anz = %d\n", + func, (int)ufunc, (int) completition, c->fd, data_len)); + return(0); /* ok */ +} + +static void ncp_response(int type, int sequence, + int connection, int task, + int completition, int connect_status, + int data_len) +{ + IPX_DATA ipx_out_data; + NCPRESPONSE *ncpresponse=(NCPRESPONSE*)&ipx_out_data; + U16_TO_BE16(type, ncpresponse->type); + ncpresponse->sequence = (uint8) sequence; + ncpresponse->connection = (uint8) connection; + ncpresponse->task = (uint8) task; + ncpresponse->reserved = 0; + ncpresponse->completition = (uint8)completition; + ncpresponse->connect_status = (uint8)connect_status; + if (nw_debug){ + char comment[80]; + sprintf(comment, "NCP-RESP compl=0x%x ", completition); + send_ipx_data(ncp_fd, 17, sizeof(NCPRESPONSE) + data_len, + (char *) ncpresponse, + &from_addr, comment); + } else + send_ipx_data(ncp_fd, 17, sizeof(NCPRESPONSE) + data_len, + (char *) ncpresponse, + &from_addr, NULL); +} + +static void sig_child(int isig) +{ + int k=-1; + int status; + int pid=wait(&status); + while (++k < anz_connect) { + CONNECTION *c = &connections[k]; + if (c->pid == pid) { + clear_connection(k+1); + break; + } + } + signal(SIGCHLD, sig_child); +} + +static int fl_got_hup=0; +static void sig_hup(int rsig) +{ + signal(SIGHUP, SIG_IGN); + fl_got_hup++; + signal(SIGHUP, sig_hup); +} + +void set_sig(void) +{ + signal(SIGCHLD, sig_child); + signal(SIGHUP, sig_hup); +} + +static void handle_bind_calls(uint8 *p) +{ + int func = (int) *p; + p += 2; + switch (func) { + case 0x01 : + { /* insert NET_ADDRESS */ + NETOBJ obj; + obj.type = GET_BE16(p); + p += 2; + strmaxcpy(obj.name, p+1, *p); + p += (*p+1); + nw_new_create_prop(0, obj.name, obj.type, O_FL_DYNA, 0x40, + "NET_ADDRESS", P_FL_DYNA|P_FL_ITEM, 0x40, + (char *)p, sizeof(ipxAddr_t)); + } + break; + + case 0x02 : + { /* delete complete Object */ + NETOBJ obj; + obj.type = GET_BE16(p); + p += 2; + strmaxcpy(obj.name, p+1, *p); + nw_delete_obj(&obj); /* also deletes all properties */ + } + break; + + default : break; + } +} + +static int handle_ctrl(void) +{ + int what; + int conn; + int result = 0; + int data_len = read(0, (char*)&what, sizeof(what)); + if (data_len == sizeof(what)) { + DPRINTF(("NCPSERV:GOT CTRL what=0x%x\n", what)); + switch (what) { + case 0x5555 : /* clear_connection */ + data_len = read(0, (char*)&conn, sizeof(conn)); + if (sizeof(int) == data_len) clear_connection(conn); + break; + + case 0x3333 : /* 'bindery' calls */ + if (sizeof(conn) == read(0, (char*)&conn, sizeof(conn))) { + uint8 *buff = xmalloc(conn+10); + XDPRINTF((2, "0x3333 len=%d\n", conn)); + if (conn == read(0, (char*)buff, conn)) + handle_bind_calls(buff); + else + DPRINTF(("0x3333 protokoll error:len=%d\n", conn)); + xfree(buff); + } + break; + + case 0xeeee: + get_ini_debug(2); + break; + + default : break; + } /* switch */ + result++; + } else DPRINTF(("NCPSERV:GOT CTRL size=%d\n", data_len)); + return(result); +} + +static void handle_hup(void) +{ + signal(SIGHUP, SIG_IGN); + XDPRINTF((2, "HANDLE_HUP_BEGIN\n")); + fl_got_hup = handle_ctrl(); + XDPRINTF((2, "HANDLE_HUP_END fl_got_hup=%d\n", fl_got_hup)); + signal(SIGHUP, sig_hup); +} + +int main(int argc, char *argv[]) +{ + int result; + int type; + + if (argc != 8) { + fprintf(stderr, "usage ncpserv address nwname GID UID debug1 debug2 debug3\n"); + exit(1); + } + strncpy(my_nwname, argv[1], 48); + my_nwname[47] = '\0'; + adr_to_ipx_addr(&my_addr, argv[2]); + nw_init_dbm(my_nwname, &my_addr); + + sscanf(argv[3], "%d", &conn_gid); + sscanf(argv[4], "%d", &conn_uid); + + sscanf(argv[5], "%d", &nw_debug); + sscanf(argv[6], "%d", &nwconn_debug); + sscanf(argv[7], "%d", &ipxdebug); + +#ifdef LINUX + set_emu_tli(ipxdebug); +#endif + + if (open_ncp_socket()) exit(1); + ud.opt.len = sizeof(ipx_pack_typ); + ud.opt.maxlen = sizeof(ipx_pack_typ); + ud.opt.buf = (char*)&ipx_pack_typ; /* gets actual Typ */ + + ud.addr.len = sizeof(ipxAddr_t); + ud.addr.maxlen = sizeof(ipxAddr_t); + ud.addr.buf = (char*)&from_addr; + + ud.udata.len = IPX_MAX_DATA; + ud.udata.maxlen = IPX_MAX_DATA; + ud.udata.buf = (char*)&ipx_in_data; + set_sig(); + fcntl(0, F_SETFL, O_NONBLOCK); /* non blocking input pipe */ + while (1) { + time(&akttime); + if ((result = t_rcvudata(ncp_fd, &ud, &rcv_flags)) > -1){ + in_len = ud.udata.len; + if (fl_got_hup) handle_hup(); + XDPRINTF((10, "NCPSERV-LOOP von %s\n", visable_ipx_adr(&from_addr))); + if ((type = GET_BE16(ncprequest->type)) == 0x2222 || type == 0x5555) { + int connection = (int)ncprequest->connection; + XDPRINTF((10, "GOT 0x%x in NCPSERV connection=%d\n", type, connection)); + if ( connection > 0 && connection <= anz_connect) { + CONNECTION *c = &(connections[connection-1]); + if (!memcmp(&from_addr, &(c->client_adr), sizeof(ipxAddr_t))) { + if (c->fd > -1){ + if (type == 0x2222) { + int sent_here = 1; + int func = ncprequest->function; + int diff_time = akttime - c->last_access; + c->last_access = akttime; + + if (diff_time > 50) /* after max. 50 seconds */ + write_to_nwserv(0x4444, connection, NULL,0); + /* tell the wdog there's no need to look */ + + if (ncprequest->sequence == c->sequence + && !c->retry++) { + /* perhaps nwconn is busy */ + ncp_response(0x9999, ncprequest->sequence, + connection, 0, 0x0, 0, 0); + DPRINTF(("Send Request being serviced to connection:%d\n", connection)); + continue; + } + + switch (func) { + case 0x15 : /* Messages */ + case 0x17 : /* File Server Environment */ + sent_here = handle_fxx(c, in_len, func); + break; + default : break; + } /* switch */ + + if (sent_here) { + int anz=write(c->fd, (char*)ncprequest, in_len); + XDPRINTF((10, "write to %d, anz = %d\n", c->fd, anz)); + if (func == 0x19) { /* logout */ + c->object_id = 0; /* not LOGGED */ + } + } + c->sequence = ncprequest->sequence; /* save last sequence */ + c->retry = 0; + continue; + } else { /* 0x5555 */ + if ( (uint8) (c->sequence+1) == (uint8) ncprequest->sequence) { + clear_connection(ncprequest->connection); + ncp_response(0x3333, + ncprequest->sequence, + connection, + 1, 0x0, 0, 0); + continue; + } + } + } + XDPRINTF((10, "c->fd = %d\n", c->fd)); + } + } + /* here someting is wrong */ + XDPRINTF((0, "GOT 0x%x connection=%d of %d conns not OK in NCPSERV\n", + type, ncprequest->connection, anz_connect)); + ncp_response(0x3333, ncprequest->sequence, + ncprequest->connection, + 0, 0xf9, 0, 0); + } else if (type == 0x1111) { + /* GIVE CONNECTION Nr connection */ + int connection = find_get_conn_nr(&from_addr); + DPRINTF(("GIVE CONNECTION NR=%d in NCPSERV\n", connection)); + if (connection) { + CONNECTION *c = &(connections[connection-1]); + int anz; + c->message[0] = '\0'; + c->object_id = 0; /* firsttime set 0 for NOT LOGGED */ + c->sequence = 0; + anz=write(c->fd, (char*)ncprequest, in_len); + XDPRINTF((10, "write to oldconn %d, anz = %d\n", c->fd, anz)); + } else /* no free connection */ + ncp_response(0x3333, 0, 0, 0, 0xf9, 0, 0); + } else { + int connection = (int)ncprequest->connection; + int sequence = (int)ncprequest->sequence; + XDPRINTF((0, "UNKNOWN TYPE: 0x%x\n", type)); + ncp_response(0x3333, sequence, connection, + 1, 0xfb, 0, 0); + } + } else { + if (fl_got_hup) handle_hup(); + else t_error("NCPSERV t_rcvudata"); + } + } + printf("LEAVE ncpserv\n"); + t_unbind(ncp_fd); + t_close(ncp_fd); + return(0); +} + + + diff --git a/net.h b/net.h new file mode 100644 index 0000000..84df862 --- /dev/null +++ b/net.h @@ -0,0 +1,405 @@ +/* net.h 20-Nov-95 */ + +/* (C)opyright (C) 1993,1995 Martin Stover, Marburg, Germany + * + * 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. + */ + + +#ifndef _M_NET_H_ +#define _M_NET_H_ +#include +#include +#include +#include + +#ifndef LINUX +/* z.B. USL */ +# include "sys/tiuser.h" +#endif + +#include "sys/fcntl.h" +#include "sys/types.h" +#include "unistd.h" +#include +#include + +#ifndef LINUX +# include "stropts.h" +# include "poll.h" +# include "sys/nwctypes.h" +# include "sys/stream.h" +/* # include "common.h" */ +/* # include "portable.h" , needed ??? */ +# include "sys/ipx_app.h" +#else +# include "emutli.h" /* TLI-EMULATION */ +#endif + +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#define U16_TO_BE16(u, b) { uint16 a=(u); \ + *( (uint8*) (b) ) = *( ((uint8*) (&a)) +1); \ + *( ((uint8*) (b)) +1) = *( (uint8*) (&a)); } + +#define U32_TO_BE32(u, ar) { uint32 a= (u); uint8 *b= ((uint8*)(ar))+3; \ + *b-- = (uint8)a; a >>= 8; \ + *b-- = (uint8)a; a >>= 8; \ + *b-- = (uint8)a; a >>= 8; \ + *b = (uint8)a; } + +#define GET_BE16(b) ( (int) *(((uint8*)(b))+1) \ + | ( ( (int) *( (uint8*)(b) ) << 8) ) ) + +#define GET_BE32(b) ( (uint32) *(((uint8*)(b))+3) \ + | ( ((uint32) *(((uint8*)(b))+2)) << 8) \ + | ( ((uint32) *(((uint8*)(b))+1)) << 16) \ + | ( ((uint32) *( (uint8*)(b) ) << 24) ) ) + + +#define MAX_U32 ((uint32)0xffffffffL) +#define MAX_U16 ((uint16)0xffff) + +#define IPX_MAX_DATA /* 1058 */ 546 +#define MAX_SERVER_NAME 48 + +typedef union { + struct S_SIP { /* Server Identification Packet, siehe auch SAP */ + uint8 response_type[2]; /*hi-lo */ + /* 2 periodic bzw. Shutdown */ + /* bzw. General Service Response */ + /* 4 nearest Service Response */ + uint8 server_type[2]; /*hi-lo */ + /* 0x0 unknown */ + /* 0x1 user */ + /* 0x2 user/group */ + /* 0x3 Print Queue */ + /* 0x4 File Server */ + /* 0x5 Job Server */ + /* 0x6 Gateway */ + /* 0x7 Printserver */ + /* 0x9 Archive Server */ + /* 0x24 Remote Bridge Server */ + /* 0x47 Advertising Print Server */ + /* 0x107 Netware 386 */ + /* 0xFFFF (-1) WILD */ + + uint8 server_name[MAX_SERVER_NAME]; + ipxAddr_t server_adr; + uint8 intermediate_networks[2]; /* hi-lo */ + /* normal 0 */ + /* down 16 */ + } sip; /* Server Identifikation Packet */ + struct S_SQP { /* Service Query Packet */ + uint8 query_type[2]; /* hi low */ + /* 1 general Service Query */ + /* 3 nearest Server Query */ + uint8 server_type[2]; /* hi low s.o. */ + } sqp; + struct S_SAP { + uint8 sap_operation[2]; /* hi-low */ + struct S_SAPS { + uint8 server_type[2]; + uint8 server_name[MAX_SERVER_NAME]; + ipxAddr_t server_adr; + uint8 server_hops[2]; + } saps; + } sap; + + struct S_WDOG { /* Watchdog */ + uint8 connid; /* connection ID */ + uint8 status; /* STATUS */ + } wdog; + struct S_CONFREQ { /* IPX Diagnose */ + uint8 count; + uint8 ex_node[6]; + } confreq; + struct S_RIP { /* ROUTING */ + uint8 operation[2]; /* 1 request, 2 response */ + uint8 network[4]; + uint8 hops[2]; /* Anzahl Routerspassagen um Netzwerk zu Erreichen */ + uint8 ticks[2]; /* Zeit in 1/18 sec. um Netzwerk Nummer zu erreichen */ + } rip; + struct S_DIAGRESP { + uint8 majorversion; + uint8 minorversion; + uint8 spx_diag_sock[2]; /* SPX Diagnose SOCKET */ + uint8 anz; /* Anzahl Componente */ + /* .... Componente + * uint8 id; 0:IPX/SPX, 1: BRIGDE Driver, 2: Shell driver + * 3: Shell, 4: VAP Shell + * + * extented 5: external Bridge, 6 Files Server/Bridge + * 7: non dedicated IPX/SPX + * + * extented haben folgende Zusatzfelder + * uint8 count; Anzahl Local Networks + * jetzt pro Network + * uint8 type; 0: LAN-Board, + * 1: non dedicated File/Sever(virtuelles Board) + * 2: redirected remote Line; + * + * uint8 net; Netwerk Adresse + * uint8 node; Node + * + * + */ + } diaresp; + struct S_NCPRESPONSE { + uint8 type[2]; /* 0x3333 */ + uint8 sequence; + uint8 connection; /* low connection */ + uint8 task; + uint8 reserved; /* high connection */ + uint8 completition; /* bzw. ERROR CODE */ + uint8 connect_status; + } ncpresponse; + struct S_NCPREQUEST { + uint8 type[2]; /* 0x1111 od 0x2222 */ + uint8 sequence; + uint8 connection; /* low connection */ + uint8 task; + uint8 reserved; /* high connection */ + uint8 function; /* Function */ + } ncprequest; + char data[IPX_MAX_DATA]; +} IPX_DATA; + +typedef struct S_SIP SIP; +typedef struct S_SQP SQP; +typedef struct S_SAP SAP; +typedef struct S_SAPS SAPS; +typedef struct S_RIP RIP; + +typedef struct S_CONFREQ CONFREQ; +typedef struct S_DIAGRESP DIAGRESP; +typedef struct S_NCPRESPONSE NCPRESPONSE; +typedef struct S_NCPREQUEST NCPREQUEST; + +/* SOCKETS */ +#define SOCK_ROUTE 0x0001 /* Routing Information */ +#define SOCK_ECHO 0x0002 /* Echo Protokoll Packet */ +#define SOCK_ERROR 0x0003 /* Error Handler Packet */ +#define SOCK_NCP 0x0451 /* File Service CORE */ +#define SOCK_SAP 0x0452 /* SAP Service Advertising Packet */ +#define SOCK_RIP 0x0453 /* Routing Information Packet */ +#define SOCK_NETBIOS 0x0455 /* NET BIOS Packet */ +#define SOCK_DIAGNOSE 0x0456 /* Diagnostic Packet */ +#define SOCK_NVT 0x8063 /* NVT (Netzerk Virtual Terminal) */ +/* PACKET TYPES */ + +#define PACKT_0 0 /* unknown */ +#define PACKT_ROUTE 1 /* Routing Information */ +#define PACKT_ECHO 2 /* Echo Packet */ +#define PACKT_ERROR 3 /* Error Packet */ +#define PACKT_EXCH 4 /* Packet Exchange Packet */ +#define PACKT_SPX 5 /* SPX Packet */ + /* 16 - 31 Experimental */ +#define PACKT_CORE 17 /* Core Protokoll (NCP) */ + + +#define FD_NWSERV 3 /* one after stderr */ + + +/* ===================> config.h <======================= */ +#include "config.h" + +#ifndef MAX_CONNECTIONS +# define MAX_CONNECTIONS 5 /* maximum Number of Connections */ +#endif + +#ifndef MAX_NW_VOLS +# define MAX_NW_VOLS 10 +#endif + +#ifndef FILENAME_NW_INI +# define FILENAME_NW_INI "./nw.ini" /* location of ini (conf) file */ +#endif + +#ifndef PATHNAME_BINDERY +# define PATHNAME_BINDERY "." /* location of bindery files */ +#endif + +#include "net1.h" +/* connect.c */ +typedef struct { + uint8 name[14]; /* filename in DOS format */ + uint8 attrib; /* Attribute */ + uint8 ext_attrib; /* File Execute Type */ + uint8 size[4]; /* size of file */ + uint8 create_date[2]; + uint8 acces_date[2]; + uint8 modify_date[2]; + uint8 modify_time[2]; +} NW_FILE_INFO; + +typedef struct { + uint8 name[14]; /* dirname */ + uint8 attrib; + uint8 ext_attrib; + uint8 create_date[2]; + uint8 create_time[2]; + uint8 owner_id[4]; + uint8 access_right_mask; + uint8 reserved; /* future use */ + uint8 next_search[2]; +} NW_DIR_INFO; + +typedef struct { + uint8 record_in_use[2]; + uint8 record_previous[4]; + uint8 record_next[4]; + uint8 client_connection[4]; + uint8 client_task[4]; + uint8 client_id[4]; + + uint8 target_id[4]; /* 0xff, 0xff, 0xff, 0xff */ + uint8 target_execute_time[6]; /* alles 0xff */ + uint8 job_entry_time[6]; /* ?? alles 0 */ + uint8 job_id[4]; /* ?? alles 0 HI-LOW */ + uint8 job_typ[2]; /* z.B. Printform HI-LOW */ + uint8 job_position[2]; /* ?? alles 0 low-high ? */ + uint8 job_control_flags[2]; /* z.B 0x10, 0x00 */ + /* 0x80 operator hold flag */ + /* 0x40 user hold flag */ + /* 0x20 entry open flag */ + /* 0x10 service restart flag */ + /* 0x08 autostart flag */ + + uint8 job_file_name[14]; /* len + DOS filename */ + uint8 job_file_handle[4]; + uint8 server_station[4]; + uint8 server_task[4]; + uint8 server_id[4]; + uint8 job_bez[50]; /* "LPT1 Catch" */ + uint8 client_area[152]; +} QUEUE_JOB; + +typedef struct { + uint8 version; /* normal 0x0 */ + uint8 tabsize; /* normal 0x8 */ + uint8 anz_copies[2]; /* Anzahl Copien HI-LOW */ + uint8 print_flags[2]; /* z.B fuer Banner */ + uint8 max_lines[2]; + uint8 max_chars[2]; + uint8 form_name[16]; /* "UNKNOWN" */ + uint8 reserved[6]; + uint8 banner_user_name[13]; /* Username */ + uint8 bannner_file_name[13]; + uint8 bannner_header_file_name[14]; + uint8 file_path_name[80]; +} QUEUE_PRINT_AREA; + +typedef struct { + uint8 volume; + uint8 base[4]; /* Base or Handle */ + uint8 flag; /* 0=base, 1=handle, 0xff=not path nor handle */ + uint8 components; /* nmbrs of pathes, components */ + uint8 pathes[1]; /* form len+name */ +} NW_HPATH; + + +extern int nw_init_connect(void); +extern int nw_free_handles(int task); + +extern int nw_creat_open_file(int dir_handle, uint8 *data, int len, + NW_FILE_INFO *info, int attrib, int access, int mode); + +extern int nw_read_datei(int fhandle, uint8 *data, int size, uint32 offset); +extern int nw_seek_datei(int fhandle, int modus); +extern int nw_write_datei(int fhandle, uint8 *data, int size, uint32 offset); +extern int nw_lock_datei(int fhandle, int offset, int size, int do_lock); +extern int nw_close_datei(int fhandle); + +extern int nw_server_copy(int qfhandle, uint32 qoffset, + int zfhandle, uint32 zoffset, + uint32 size); + +extern int nw_delete_datei(int dir_handle, uint8 *data, int len); +extern int nw_chmod_datei(int dir_handle, uint8 *data, int len, int modus); + +extern int mv_file(int qdirhandle, uint8 *q, int qlen, + int zdirhandle, uint8 *z, int zlen); + + + +extern int nw_mk_rd_dir(int dir_handle, uint8 *data, int len, int mode); + +extern int nw_search(uint8 *info, + int dirhandle, int searchsequence, + int search_attrib, uint8 *data, int len); + +extern int nw_dir_search(uint8 *info, + int dirhandle, int searchsequence, + int search_attrib, uint8 *data, int len); + + +extern int nw_find_dir_handle( int dir_handle, + uint8 *data, /* zustzlicher Pfad */ + int len); /* Lnge Pfad */ + +extern int nw_alloc_dir_handle( + int dir_handle, /* Suche ab Pfad dirhandle */ + uint8 *data, /* zustzl. Pfad */ + int len, /* Lnge DATA */ + int driveletter, /* A .. Z normal */ + int is_temphandle, /* temporres Handle 1 */ + /* spez. temp Handle 2 */ + int task); /* Prozess Task */ + + +extern int nw_open_dir_handle( int dir_handle, + uint8 *data, /* zustzlicher Pfad */ + int len, /* Lnge DATA */ + int *volume, /* Volume */ + int *dir_id, /* hnlich Filehandle */ + int *searchsequence); + + +extern int nw_free_dir_handle(int dir_handle); + +extern int nw_set_dir_handle(int targetdir, int dir_handle, + uint8 *data, int len, int task); + +extern int nw_get_directory_path(int dir_handle, uint8 *name); + +extern int nw_get_vol_number(int dir_handle); + +extern int nw_get_volume_number(uint8 *volname, int namelen); +extern int nw_get_volume_name(int volnr, uint8 *volname); + + + +extern int nw_get_eff_dir_rights(int dir_handle, uint8 *data, int len); + +extern int nw_set_fdate_time(uint32 fhandle, uint8 *datum, uint8 *zeit); +extern int nw_scan_dir_info(int dir_handle, uint8 *data, int len, + uint8 *subnr, uint8 *subname, + uint8 *subdatetime, uint8 *owner); + + +extern int nw_generate_dir_path(uint8 *nwpathstruct, + uint8 *ns_dir_base, uint8 *dos_dir_base); + +#include "tools.h" + +extern int nw_get_fs_usage(char *volname, struct fs_usage *fsu); + +#endif diff --git a/net1.c b/net1.c new file mode 100644 index 0000000..f1d8947 --- /dev/null +++ b/net1.c @@ -0,0 +1,168 @@ +/* net1.c, 11-Sep-95 */ + +/* (C)opyright (C) 1993,1995 Martin Stover, Marburg, Germany + * + * 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 "net.h" + +#if HAVE_TLI +void print_t_info(struct t_info *t) +{ + DPRINTF(("T_INFO:addr %ld, options %ld, tsdu %ld, etsdu %ld\n", + t->addr, t->options,t->tsdu, t->etsdu)); + DPRINTF(("connect %ld, discon %ld, servtype %ld\n", + t->connect, t->discon,t->servtype)); +#if 0 + struct t_info { + long addr; /* size of protocol address */ + long options; /* size of protocol options */ + long tsdu; /* size of max transport service data unit */ + long etsdu; /* size of max expedited tsdu */ + long connect; /* max data for connection primitives */ + long discon; /* max data for disconnect primitives */ + long servtype; /* provider service type */ +#endif +} +#endif + +char *visable_ipx_adr(ipxAddr_t *p) +{ +static char str[200]; + sprintf(str,"net=%x:%x:%x:%x, node=%x:%x:%x:%x:%x:%x, sock=%02x:%02x", + (int)p->net[0], (int)p->net[1], (int)p->net[2], (int)p->net[3], + (int)p->node[0], (int)p->node[1], (int)p->node[2], (int)p->node[3], + (int)p->node[4], (int)p->node[5], (int)p->sock[0], (int)p->sock[1]); + return(str); +} + +void print_ipx_addr(ipxAddr_t *p) +{ + DPRINTF(("%s\n", visable_ipx_adr(p))); +} + +void print_ud_data(struct t_unitdata *ud) +{ + int packet_typ = *(int*)(ud->opt.buf); + int data_len = ud->udata.len; + IPX_DATA *ipxdata = (IPX_DATA *)(ud->udata.buf); + DPRINTF(("DATA-LEN %d, PACKET-TYPE %d von:", + data_len, packet_typ)); + /* hierin steht nun Addresse u. Node des Senders */ + print_ipx_addr((ipxAddr_t *)(ud->addr.buf)); + if (packet_typ == PACKT_CORE) { + DPRINTF(("Query Type 0x%x, Server Type 0x%xd\n", + GET_BE16(ipxdata->sqp.query_type), + GET_BE16(ipxdata->sqp.server_type))); + } else if (data_len > sizeof(SIP)){ + SAP *sap = &(ipxdata->sap); + SAPS *saps = &(ipxdata->sap.saps); + int sap_operation = GET_BE16(sap->sap_operation); + DPRINTF(("SAP-OPERATION %d\n", sap_operation)); + while (data_len >= sizeof(SAPS)){ + DPRINTF(("Name:%s:, typ:0x%x\n",saps->server_name, + GET_BE16(saps->server_type))); + print_ipx_addr(&(saps->server_adr)); + saps++; + data_len -= sizeof(SAPS); + } + } else print_ipx_data(ipxdata); +} + +void print_ipx_data(IPX_DATA *p) +{ + print_sip_data(&(p->sip)); +} + +void print_sip_data(SIP *sip) +{ + DPRINTF(("Name:%s:,response_type:0x%x,server_typ:0x%x\n",sip->server_name, + GET_BE16(sip->response_type), GET_BE16(sip->server_type))); + print_ipx_addr(&(sip->server_adr)); +} + +void adr_to_ipx_addr(ipxAddr_t *p, char *s) +{ + int net0, net1, net2, net3; + int node0, node1, node2, node3, node4, node5; + int sock0, sock1; + sscanf(s, "%x.%x.%x.%x,%x.%x.%x.%x.%x.%x,%x.%x", + &net0, &net1, &net2, &net3, + &node0, &node1, &node2, &node3, &node4, &node5, + &sock0, &sock1); + p->net[0] = net0; + p->net[1] = net1; + p->net[2] = net2; + p->net[3] = net3; + p->node[0] = node0; + p->node[1] = node1; + p->node[2] = node2; + p->node[3] = node3; + p->node[4] = node4; + p->node[5] = node5; + p->sock[0] = sock0; + p->sock[1] = sock1; +} + +void ipx_addr_to_adr(char *s, ipxAddr_t *p) +{ + sprintf(s, "%x.%x.%x.%x,%x.%x.%x.%x.%x.%x,%x.%x", + (int)p->net[0] , + (int)p->net[1] , + (int)p->net[2] , + (int)p->net[3] , + (int)p->node[0], + (int)p->node[1], + (int)p->node[2], + (int)p->node[3], + (int)p->node[4], + (int)p->node[5], + (int)p->sock[0], + (int)p->sock[1]); +} + + +int send_ipx_data(int fd, int pack_typ, + int data_len, char *data, + ipxAddr_t *to_addr, char *comment) +{ + struct t_unitdata ud; + uint8 ipx_pack_typ = (uint8) pack_typ; + + ud.opt.len = sizeof(ipx_pack_typ); + ud.opt.maxlen = sizeof(ipx_pack_typ); + ud.opt.buf = (char*)&ipx_pack_typ; + ud.addr.len = sizeof(ipxAddr_t); + ud.addr.maxlen = sizeof(ipxAddr_t); + ud.udata.buf = (char*)data; + ud.udata.len = data_len; + ud.udata.maxlen = data_len; + ud.addr.buf = (char*)to_addr; + if (comment != NULL) DPRINTF(("%s TO: ", comment)); + if (nw_debug)print_ipx_addr(to_addr); + if (t_sndudata(fd, &ud) < 0){ + t_error("t_sndudata !OK"); + return(-1); + } + return(0); +} + + + + + + + diff --git a/net1.h b/net1.h new file mode 100644 index 0000000..ad49025 --- /dev/null +++ b/net1.h @@ -0,0 +1,37 @@ +/* net1.h 11-Sep-95 */ + +/* (C)opyright (C) 1993,1995 Martin Stover, Marburg, Germany + * + * 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. + */ + + +#ifndef LINUX +extern void print_t_info(struct t_info *t); +extern void print_ud_data(struct t_unitdata *ud); +#endif + +extern char *visable_ipx_adr(ipxAddr_t *p); +extern void print_ipx_addr(ipxAddr_t *p); +extern void print_ipx_data(IPX_DATA *p); +extern void print_sip_data(SIP *sip); + +extern void adr_to_ipx_addr(ipxAddr_t *p, char *s); +extern void ipx_addr_to_adr(char *s, ipxAddr_t *p); + +extern int send_ipx_data(int fd, int pack_typ, + int data_len, char *data, + ipxAddr_t *to_addr, char *comment); + diff --git a/netinit.c b/netinit.c new file mode 100644 index 0000000..0027ad5 --- /dev/null +++ b/netinit.c @@ -0,0 +1,308 @@ +/* netinit.c 11-Sep-95 */ +/* Initialisierung VON IPX u. SPX unter USL 1.1 */ +/* 'emuliert' Teil von NPSD */ + +/* (C)opyright (C) 1993,1995 Martin Stover, Marburg, Germany + * + * 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 "net.h" +#include +#define NET_DEBUG 1 +#define MY_NETWORK 0x10 +#if NET_DEBUG +void print_adaptinfo(FILE *fout, ipxAdapterInfo_t *ai, char *s) +{ + if (s != NULL) + fprintf(fout, "\n---- %s ----\n", s); + fprintf(fout, +"dl_primitive = %lu \n\ +dl_max_sdu = %lu \n\ +dl_min_sdu = %lu \n\ +dl_addr_length = %lu \n\ +dl_mac_type = %lu \n\ +dl_reserved = %lu \n\ +dl_current_state = %lu \n\ +dl_sap_length = %ld \n\ +dl_service_mode = %lu \n\ +dl_qos_length = %lu \n\ +dl_qos_offset = %lu \n\ +dl_qos_range_length = %lu \n\ +dl_qos_range_offset = %lu \n\ +dl_provider_style = %lu \n\ +dl_addr_offset = %lu \n\ +dl_version = %lu \n\ +dl_brdcst_addr_length = %lu \n\ +dl_brdcst_addr_offset = %lu \n\ +dl_growth = %lu \n", + ai->dl_primitive, + ai->dl_max_sdu, + ai->dl_min_sdu, + ai->dl_addr_length, + ai->dl_mac_type, + ai->dl_reserved, + ai->dl_current_state, + ai->dl_sap_length, + ai->dl_service_mode, + ai->dl_qos_length, + ai->dl_qos_offset, + ai->dl_qos_range_length, + ai->dl_qos_range_offset, + ai->dl_provider_style, + ai->dl_addr_offset, + ai->dl_version, + ai->dl_brdcst_addr_length, + ai->dl_brdcst_addr_offset, + ai->dl_growth); + fflush(fout); +} + +void print_netinfo(FILE *fout, netInfo_t *ni, char *s) +{ + ipxAdapterInfo_t *ai = &(ni->adapInfo); + if (s != NULL) + fprintf(fout, "\n---- %s ----\n", s); + fprintf(fout, "Lan:%lx, state:%lx, err:%lx, netw:%lx, mux:%lx, node:%x.%x.%x.%x.%x.%x\n", + ni->lan, ni->state, ni->streamError, ni->network, + ni->muxId, + (int)ni->nodeAddress[0], + (int)ni->nodeAddress[1], + (int)ni->nodeAddress[2], + (int)ni->nodeAddress[3], + (int)ni->nodeAddress[4], + (int)ni->nodeAddress[5]); + print_adaptinfo(fout, ai, NULL); +} +#else +#define print_adaptinfo(fout, ai, s) +#define print_netinfo(fout, ni, s) +#endif + + +int main(int argc, char **argv) +{ + int ipx0fd=open("/dev/ipx0", O_RDWR); + if (ipx0fd > -1) { + int lan0fd=open("/dev/lan0", O_RDWR); + if (lan0fd > -1) { + struct strioctl str1, str2, str3, str4; + int ipxfd; + int j = -1; + long max_adapter=0; + netInfo_t netinfo; + long info_req = DL_INFO_REQ; + ipxAdapterInfo_t *ai = &(netinfo.adapInfo); + dl_bind_req_t bind_req; + struct { + dl_bind_ack_t b; + uint8 addr[8]; /* Adresse */ + } bind_ack; + int muxid; + int flagsp=0; + int ilen; + struct strbuf cntr1; +#if NET_DEBUG + FILE *fout = fopen("xyz", "w+"); +#endif + /* DL_INFO */ + cntr1.maxlen = 4; + cntr1.len = 4; + cntr1.buf = (char *)&info_req; + putmsg(lan0fd, &cntr1, NULL, 0); + cntr1.maxlen = sizeof(ipxAdapterInfo_t); + cntr1.len = 0; + cntr1.buf = (char*)ai; + if ((ilen=getmsg(lan0fd, &cntr1, NULL, &flagsp)) > 0) { + char dummy[100]; + cntr1.maxlen = sizeof(dummy); + cntr1.len = 0; + cntr1.buf = dummy; + flagsp = 0; + getmsg(lan0fd, &cntr1, NULL, &flagsp); + fprintf(stderr, "DL_INFO getmsg=%d bzw. %d > 0\n", ilen, cntr1.len); + } + print_adaptinfo(fout, ai, "nach DL_INFO"); + /* ----------------------------------------------- */ + bind_req.dl_primitive = DL_BIND_REQ; + bind_req.dl_sap = 0x8137; /* SAP Type fr NetWare */ + bind_req.dl_max_conind = 1; + bind_req.dl_service_mode = DL_CLDLS; /* 2 */ + bind_req.dl_conn_mgmt = 0; + bind_req.dl_xidtest_flg = 1; + + cntr1.maxlen = sizeof(dl_bind_req_t); + cntr1.len = sizeof(dl_bind_req_t); + cntr1.buf = (char*)&bind_req; + putmsg(lan0fd, &cntr1, NULL, 0); + + memset(&bind_ack, 0, sizeof(bind_ack)); + bind_ack.b.dl_primitive = DL_BIND_REQ; + cntr1.maxlen = sizeof(bind_ack); + cntr1.len = 0; + cntr1.buf = (char*)&bind_ack; + flagsp = 0; + getmsg(lan0fd, &cntr1, NULL, &flagsp); + fprintf(stderr, "BIND ACK:sap 0x%x, addr_len %d, addr_offs %d\n \ + addr=0x%x:0x%x:0x%x:0x%x:0x%x:0x%x:0x%x:0x%x\n" , + bind_ack.b.dl_sap, bind_ack.b.dl_addr_length, bind_ack.b.dl_addr_offset, + (int)bind_ack.addr[0], + (int)bind_ack.addr[1], + (int)bind_ack.addr[2], + (int)bind_ack.addr[3], + (int)bind_ack.addr[4], + (int)bind_ack.addr[5], + (int)bind_ack.addr[6], + (int)bind_ack.addr[7]); + + + /* DL_INFO */ + cntr1.maxlen = 4; + cntr1.len = 4; + cntr1.buf = (char *)&info_req; + putmsg(lan0fd, &cntr1, NULL, 0); + cntr1.maxlen = sizeof(ipxAdapterInfo_t); + cntr1.len = 0; + cntr1.buf = (char*)ai; + if ((ilen=getmsg(lan0fd, &cntr1, NULL, &flagsp)) > 0) { + char dummy[100]; + cntr1.maxlen = sizeof(dummy); + cntr1.len = 0; + cntr1.buf = dummy; + flagsp = 0; + getmsg(lan0fd, &cntr1, NULL, &flagsp); + fprintf(stderr, "DL_INFO getmsg=%d bzw. %d > 0\n", ilen, cntr1.len); + } + print_adaptinfo(fout, ai, "nach DL_INFO 2"); + /* ----------------------------------------------- */ + + str1.ic_cmd = IPX_GET_MAX_CONNECTED_LANS; + str1.ic_timout = 0; + str1.ic_len = 4; + str1.ic_dp = (char*)&max_adapter; + ioctl(ipx0fd, I_STR, &str1); + + printf("Max Adapter %ld\n", max_adapter); + muxid = ioctl(ipx0fd, I_LINK, lan0fd); /* LINK */ + +/*-----------------------------------------------*/ + + /* + str3.ic_cmd = IPX_SET_FRAME_TYPE_8023; + str3.ic_len = 0; + str3.ic_timout = 5; + str3.ic_dp = 0; + ioctl(ipx0fd, I_STR, &str3); + */ + /* + str2.ic_cmd = IPX_SET_FRAME_TYPE_SNAP; + */ + /* + str2.ic_cmd = IPX_SET_FRAME_TYPE_8022; + */ + str2.ic_timout = 0; + str2.ic_len = sizeof(netinfo); + str2.ic_dp = (char*)&netinfo; + netinfo.lan = 0; + netinfo.state = 0; + netinfo.network = MY_NETWORK; + netinfo.muxId = muxid; + netinfo.nodeAddress[0] = bind_ack.addr[0]; /* 0x00 */ + netinfo.nodeAddress[1] = bind_ack.addr[1]; /* 0x80 */ + netinfo.nodeAddress[2] = bind_ack.addr[2]; /* 0x48 */ + netinfo.nodeAddress[3] = bind_ack.addr[3]; /* 0x83 */ + netinfo.nodeAddress[4] = bind_ack.addr[4]; /* 0x14 */ + netinfo.nodeAddress[5] = bind_ack.addr[5]; /* 0x3f */ + /* + ai->dl_primitive = DL_INFO_REQ ; + ioctl(ipx0fd, I_STR, &str2); + print_netinfo(fout, &netinfo, "nach SET_FRAME"); + */ + + str3.ic_cmd = IPX_SET_LAN_INFO; + str3.ic_len = sizeof(netinfo); + str3.ic_timout = 5; + str3.ic_dp = (char*)&netinfo; + ioctl(ipx0fd, I_STR, &str3); + print_netinfo(fout, &netinfo, "nach IPX_SET_LAN_INFO"); + +#if 0 + if ((ipxfd = open("/dev/ipx", O_RDWR)) > -1){ + int spxfd = open("/dev/nspxd", O_RDWR); + if (spxfd > -1){ + int pid=-1; + int akt_pid = getpid(); + char *progname = "nwserv"; + muxid = ioctl(spxfd, I_LINK, ipxfd); + str4.ic_cmd = IPX_SET_SPX; + str4.ic_len = 0; + str4.ic_timout = 5; + str4.ic_dp = (char*) NULL; + ioctl(spxfd, I_STR, &str4); + close(ipxfd); + pid=fork(); + if (pid == 0) { /* Child */ + close(spxfd); + close(ipx0fd); + close(lan0fd); + execl(progname, progname, (argc > 1) ? *(argv+1) : NULL, NULL); + /* Falls nicht OK Calling Prozess killen */ + kill(akt_pid, SIGTERM); + kill(akt_pid, SIGQUIT); + exit (1); + } + if (pid > -1){ + pause(); + kill(pid, SIGTERM); /* Tchter killen */ + kill(pid, SIGQUIT); + } else perror("nwserv not running"); + close(spxfd); + } else { + perror("spx not open"); + close(ipxfd); + } + } else perror("ipx not open"); +#else + if ((ipxfd = open("/dev/ipx", O_RDWR)) > -1){ + int pid=-1; + int akt_pid = getpid(); + char *progname = "nwserv"; + close(ipxfd); + pid=fork(); + if (pid == 0) { /* Child */ + close(ipx0fd); + close(lan0fd); + execl(progname, progname, (argc > 1) ? *(argv+1) : NULL, NULL); + /* Falls nicht OK Calling Prozess killen */ + kill(akt_pid, SIGTERM); + kill(akt_pid, SIGQUIT); + exit (1); + } + if (pid > -1){ + pause(); + kill(pid, SIGTERM); /* Tchter killen */ + kill(pid, SIGQUIT); + } else perror("nwserv not running"); + } else perror("ipx not open"); +#endif + + close(lan0fd); +#if NET_DEBUG + fclose(fout); +#endif + } else perror("lan0 not open"); + close(ipx0fd); + } else perror("ipx0 not open"); +} diff --git a/netn.c b/netn.c new file mode 100644 index 0000000..7a05174 --- /dev/null +++ b/netn.c @@ -0,0 +1,34 @@ +/* netr.c 11-Sep-95 */ + +/* (C)opyright (C) 1993,1995 Martin Stover, Marburg, Germany + * + * 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 "net.h" + +int main() +{ + int ipx_fd = test1(SOCK_NCP); + if (ipx_fd > -1) { + if (t_unbind(ipx_fd) < 0){ + t_error("t_unbind !OK"); + } + t_close(ipx_fd); + } + return(0); +} + diff --git a/nwclient.c b/nwclient.c new file mode 100644 index 0000000..fafe076 --- /dev/null +++ b/nwclient.c @@ -0,0 +1,746 @@ +/* nwclient.c: 12-Nov-95 */ +/* + * Einfacher Testclient, wird von nwserv (im Client Modus) gestartet + * Dieses Modul hilft dabei, NCP Responses eines + * echten NW Servers zu analysieren. + * Beim 'echten' NW Server mu 'allow unencryted passwords' gesetzt + * sein. + */ + +/* (C)opyright (C) 1993,1995 Martin Stover, Marburg, Germany + * + * 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 "net.h" + +static ipxAddr_t serv_addr; +static ipxAddr_t my_addr; +static int fd_ipx; +static int fd_wdog; + +static int open_socket() +{ + int ipx_fd=t_open("/dev/ipx", O_RDWR, NULL); + struct t_bind bind; + if (ipx_fd < 0) { + t_error("t_open !Ok"); + return(-1); + } + U16_TO_BE16(0, my_addr.sock); + bind.addr.len = sizeof(ipxAddr_t); + bind.addr.maxlen = sizeof(ipxAddr_t); + bind.addr.buf = (char*)&my_addr; + bind.qlen = 0; /* immer */ + if (t_bind(ipx_fd, &bind, &bind) < 0){ + t_error("t_bind !OK"); + t_close(ipx_fd); + return(-1); + } + XDPRINTF((0,"socket bound TO %s\n", visable_ipx_adr(&my_addr) )); + return(ipx_fd); +} + +static int init_client() +{ + return( (fd_ipx = open_socket()) > -1 + && (fd_wdog = open_socket()) > -1 ? 0 : 1); +} + +/* DATA OUT */ +static IPX_DATA ipxdata_out; +static NCPREQUEST *ncprequest =(NCPREQUEST*)&ipxdata_out; +static uint8 *requestdata=((uint8*)&ipxdata_out)+sizeof(NCPREQUEST); + +static void ncp_request(int type, int sequence, + int connection, int task, + int reserved, int function, + int data_len, char *komment) + +{ + U16_TO_BE16(type, ncprequest->type); + ncprequest->sequence = (uint8) sequence; + ncprequest->connection = (uint8) connection; + ncprequest->task = (uint8) task; + ncprequest->reserved = (uint8) reserved; + ncprequest->function = (uint8) function; + { + int j = data_len; + DPRINTF(("NCP REQUEST: type:0x%x, seq:%d, conn:%d, task:%d, reserved:0x%x, func:0x%x\n", + type, sequence, connection, task, reserved, function)); + if (j > 0){ + uint8 *p=requestdata; + DPRINTF(("len %d, DATA:", j)); + while (j--) { + int c = *p++; + if (c > 32 && c < 127) DPRINTF((",\'%c\'", (char) c)); + else DPRINTF((",0x%x", c)); + } + DPRINTF(("\n")); + } + } + send_ipx_data(fd_ipx, 17, sizeof(NCPREQUEST) + data_len, + (char *) ncprequest, + &serv_addr, komment); +} + +/* DATA IN */ + +static IPX_DATA ipxdata_in; +static NCPRESPONSE *ncpresponse = (NCPRESPONSE*)&ipxdata_in; +static uint8 *responsedata = ((uint8*)&ipxdata_in) + sizeof(NCPRESPONSE); + +/* -------------------------------------- */ +static int sequence=0; + +static int handle_event(void) +{ + struct t_unitdata ud; + ipxAddr_t source_adr; + uint8 ipx_pack_typ; + int flags = 0; + + ud.opt.len = sizeof(ipx_pack_typ); + ud.opt.maxlen = sizeof(ipx_pack_typ); + ud.opt.buf = (char*)&ipx_pack_typ; /* bekommt aktuellen Typ */ + + ud.addr.len = sizeof(ipxAddr_t); + ud.addr.maxlen = sizeof(ipxAddr_t); + + ud.addr.buf = (char*)&source_adr; + + ud.udata.len = sizeof(IPX_DATA); + ud.udata.maxlen = sizeof(IPX_DATA); + ud.udata.buf = (char*)&ipxdata_in; + + if (t_rcvudata(fd_ipx, &ud, &flags) < 0){ + struct t_uderr uderr; + ipxAddr_t erradr; + uint8 err_pack_typ; + uderr.addr.len = sizeof(ipxAddr_t); + uderr.addr.maxlen = sizeof(ipxAddr_t); + uderr.addr.buf = (char*)&erradr; + uderr.opt.len = sizeof(err_pack_typ); + uderr.opt.maxlen = sizeof(err_pack_typ); + uderr.opt.buf = (char*)&err_pack_typ; /* bekommt aktuellen Typ */ + ud.addr.buf = (char*)&source_adr; + t_rcvuderr(fd_ipx, &uderr); + DPRINTF(("Error from %s, Code = 0x%lx\n", visable_ipx_adr(&erradr), uderr.error)); + t_error("t_rcvudata !OK"); + return(-1); + } else { + int responselen = ud.udata.len - sizeof(NCPRESPONSE); + int j = responselen; + + int sequence = (int)ncpresponse->sequence; + int connection = (int)ncpresponse->connection; + int task = (int)ncpresponse->task; + int reserved = (int)ncpresponse->reserved; + int completition = (int)ncpresponse->completition; + int connect_status = (int)ncpresponse->connect_status; + int type = GET_BE16(ncpresponse->type); + + DPRINTF(("Ptyp:%d von: %s, len=%d\n", (int)ipx_pack_typ, visable_ipx_adr(&source_adr), responselen)); + DPRINTF(("RESPONSE:t:0x%x, seq:%d, conn:%d, task:%d, res:0x%x, complet.:0x%x, connect:0x%x\n", + type, sequence, connection, task, reserved, completition, connect_status)); + + if (j > 0){ + uint8 *p=responsedata; + DPRINTF(("len %d, DATA:", j)); + while (j--) { + int c = *p++; + if (c > 32 && c < 127) DPRINTF((",\'%c\'", (char) c)); + else DPRINTF((",0x%x", c)); + } + DPRINTF(("\n")); + } + } + + if (sequence == ncpresponse->sequence) { + sequence++; + return((int)(ncpresponse->completition)); + } + return(-1); +} + +/* ------------------------------------------------------ */ +static int connection=0; + +#define RDATA(xdata, xfunc, xcomment) \ +memcpy(requestdata, (xdata), sizeof(xdata)); \ +ncp_request(0x2222, sequence, connection, 1, 0, \ + (xfunc), sizeof(data), (xcomment)) + +#define ODATA(xfunc, xcomment) \ +ncp_request(0x2222, sequence, connection, 1, 0, \ + (xfunc), 0, (xcomment)) + +#define VDATA(xfunc, xsize, xcomment) \ +ncp_request(0x2222, sequence, connection, 1, 0, \ + (xfunc), (xsize), (xcomment)) + + +static int get_conn_nr(void) +{ + ncp_request(0x1111, sequence, 0xff, 0, 0xff, 0, + 0, "Get Connection Nr."); + if (!handle_event()) { + connection = ncpresponse->connection; + DPRINTF(("NWCLIENT GOT CONNECTION NR:%d\n", connection)); + return(0); + } + return(-1); +} + +static int get_pkt_size(void) +{ + uint8 data[] = {0x4, 0}; /* wanted ?? SIZE */ + RDATA(data, 0x21, "Get Pktsize"); + if (!handle_event()) { + DPRINTF(("NWCLIENT GOT PACKET SIZE =:%d\n", (int)GET_BE16(responsedata))); + return(0); + } + return(-1); +} + +static int get_server_info(void) +{ + uint8 data[] = {0, 1, 0x11}; + RDATA(data, 0x17, "Get FileServer Info"); + if (!handle_event()) { + DPRINTF(("NWCLIENT GOT SERVER INFO von=:%s\n", responsedata )); + return(0); + } + return(-1); +} + +static int do_17_17(void) +{ + uint8 data[] = {0, 1, 0x17}; + RDATA(data, 0x17, "Do_17_17"); + if (!handle_event()) { + return(0); + } + return(-1); +} + +static int get_network_serial_number(void) +{ + uint8 data[] = {0, 1, 0x12}; + RDATA(data, 0x17, "Get Network Serial Number"); + if (!handle_event()) return(0); + return(-1); +} + + +static int get_connect(void) +{ + ODATA(0x19, "get CONNECT ??"); + if (!handle_event()) { + return(0); + } + return(-1); +} + +static int get_server_time(void) +{ + ODATA(0x14, "get SERVER TIME"); + if (!handle_event()) { + return(0); + } + return(-1); +} + +typedef struct { + uint8 volume; + uint8 dir_id[2]; +} DIR_IDS; + +static int file_search_init(DIR_IDS *di, int dirhandle, char *path) +{ + uint8 *p=requestdata; + int pathlen=path ? strlen(path) : 0; + *p++ = (uint8) dirhandle; + *p++ = (uint8) pathlen; + if (pathlen) memcpy(p, path, pathlen); + VDATA(0x3e, pathlen+2, "FILE SEARCH INIT"); + if (!handle_event()) { + if (di) memcpy(di, responsedata, 3); + DPRINTF(("NWCLIENT GOT FILES SEARCH INIT HANDLE=:%d\n", + (int)GET_BE16(responsedata+1) )); + return( (int) *(responsedata+3) ); /* access */ + } + return(-1); +} + +static int file_search_cont(DIR_IDS *di, int seq, + int attrib, char *path) +{ + uint8 *p=requestdata; + int pathlen=path ? strlen(path) : 0; + memcpy(p, di, 3); + p+=3; + U16_TO_BE16((uint16)seq, p); + p+=2; + *p++ = (uint8) attrib; + *p++ = (uint8) pathlen; + if (pathlen) memcpy(p, path, pathlen); + VDATA(0x3f, pathlen+7, "FILE SEARCH CONT"); + if (!handle_event()) { + int dir_id = GET_BE16(responsedata+2); + seq = GET_BE16(responsedata); + DPRINTF(("GOT SEARCH CONT dir_id=%d, seq=%d\n", dir_id, seq)); + return(seq); + } + return(-1); +} + +static int allocate_dir_handle(int dirhandle, + int drive, + char *path, + int temp) +{ + uint8 *p=requestdata; + uint8 pathlen= (path) ? strlen(path) : 0; + *p++ = 0; + *p++ = pathlen+4; + + if (!temp) *p++ = 0x12; /* permanent */ + else if (temp == 1) *p++=0x13; /* temp */ + else *p++ = 0x16; /* spez. temp */ + *p++ = dirhandle; + *p++ = drive; + *p++ = pathlen; + memcpy(p, path, pathlen); + VDATA(0x16, pathlen+6 , "ALLOCATE DIR HANDLE"); + if (!handle_event()) return((int) *responsedata); + return(-1); +} + +static void scan_irgendwas(int dirhandle, int attrib, char *name) +{ + uint8 *p = requestdata; + int namlen = strlen(name); + *p++ = 0; + *p++ = namlen+6; + *p++ = 0x0f; + U16_TO_BE16(MAX_U16, p); + p+=2; + *p++ = dirhandle; + *p++ = attrib; + *p++ = namlen; + memcpy(p, name, namlen); + VDATA(0x16, namlen+8, "SCAN IRGENDWAS"); + if (!handle_event()) { + ; + } +} + +static void scan_file_trustees(int dirhandle, int attrib, char *name) +{ + uint8 *p = requestdata; + int namlen = strlen(name); + *p++ = 0; + *p++ = namlen+8; + *p++ = 0x1e; + *p++ = dirhandle; + *p++ = attrib; + U32_TO_BE32(MAX_U32, p); + p+=4; + *p++ = namlen; + memcpy(p, name, namlen); + VDATA(0x16, namlen+10, "SCAN FILE TRUST"); + if (!handle_event()) { + ; + } +} + + +static int get_dir_path(int dirhandle) +{ + uint8 *p=requestdata; + *p++ = 0; + *p++ = 2; + *p++ = 1; + *p = (uint8) dirhandle; + VDATA(0x16, 4, "GET DIR PATH"); + if (!handle_event()) { + ; + } + return(0); +} + +static void get_connection_info(int conn) +/* liefert Connection INFO */ +{ + uint8 *p=requestdata; + *p++ = 0; + *p++ = 2; + *p++ = 0x16; + *p = (uint8) conn; + VDATA(0x17, 4, "GET CONNECTION INFO"); + if (!handle_event()) { + ;; + } +} + + +static int get_bindery_access(void) +/* liefert ACCESS LEVEL und CONNECTION BIND ID */ +{ + uint8 data[] = {0, 1, 0x46}; + RDATA(data, 0x17, "Get Bindery ACCESS ??"); + if (!handle_event()) { + return(0); + } + return(-1); +} + +static int scan_bindery_object(int type, char *name, uint32 lastid) +{ + uint8 *p = requestdata; + int namlen = strlen(name); + *p++ = 0; + *p++ = namlen+8; + *p++ = 0x37; + U32_TO_BE32(lastid, p); + p+=4; + U16_TO_BE16(type, p); + p+=2; + *p++=namlen; + memcpy(p, name, namlen); + VDATA(0x17, namlen+10,"Scan Bindery Object"); + if (!handle_event()) { + ; + } + return(0); +} + +static int scan_bindery_property(int type, char *name, char *propname, uint32 *lastid) +{ + uint8 *p = requestdata; + int namlen = strlen(name); + int propnamlen = strlen(propname); + *p++ = 0; + *p++ = namlen+9 + propnamlen; + *p++ = 0x3c; + U16_TO_BE16(type, p); + p+=2; + *p++ = namlen; + memcpy(p, name, namlen); + U32_TO_BE32(*lastid, (p+=namlen)); + + *(p+=4) = propnamlen; + memcpy(++p, propname, propnamlen); + + VDATA(0x17, namlen+propnamlen+11,"Scan Bindery Property"); + + if (!handle_event()) { + /* + *lastid = GET_BE32(responsedata + 20); + */ + *lastid = GET_BE32(responsedata + 18); + + return(0); + } else return(-1); +} + + + +static int get_bindery_object_id(int type, char *name) +{ + uint8 *p = requestdata; + int namlen = strlen(name); + *p++ = 0; + *p++ = namlen+4; + *p++ = 0x35; + U16_TO_BE16(type, p); + p+=2; + *p++=namlen; + memcpy(p, name, namlen); + VDATA(0x17, namlen+6, "GET BINDERY OBJECT ID"); + if (!handle_event()) { + DPRINTF(("GOT BIND OBJ ID=0x%lx\n", GET_BE32(responsedata))); + } + return(0); +} + +static void send_console_broadcast(char *message) +{ + uint8 *p = requestdata; + int len = strlen(message); + *p++ = 0; + *p++ = len+3; + *p++ = 0xd1; + U16_TO_BE16(len, p); + p+=2; + memcpy(p, message, len); + VDATA(0x17, len+5, "SEND CONSOLE BROADCAST"); + if (!handle_event()) { + ;; + } +} + + + +static int get_bindery_object_name(uint32 id) +{ + uint8 *p = requestdata; + *p++ = 0; + *p++ = 5; + *p++ = 0x36; + U32_TO_BE32(id, p); + VDATA(0x17, 7, "GET BINDERY OBJECT NAME"); + if (!handle_event()) { + ; + } + return(0); +} + + +static int get_volume_restriction_for_obj(uint32 id, int volnr) +{ + uint8 *p = requestdata; + *p++ = 0; + *p++ = 6; + *p++ = 0x29; + *p++ = (uint8)volnr; + U32_TO_BE32(id, p); + VDATA(0x16, 8, "GET VOLUME RESTRICTION FOR OBJ"); + if (!handle_event()) { + ; + } + return(0); +} + + +static int login_object(int type, char *name, char *password) +{ + uint8 *p = requestdata; + int namlen = strlen(name); + int passlen = (password) ? strlen(password) : 0; + *p++ = 0; + *p++ = namlen+passlen+5; + *p++ = 0x14; + U16_TO_BE16(type, p); + p+=2; + *p++ = namlen; + memcpy(p, name, namlen); + p += namlen; + if (passlen) memcpy(p, password, passlen); + else *p=0; + VDATA(0x17, namlen+7+passlen, "LOGIN OBJECT"); + if (!handle_event()) { + ; + } + return(0); +} + + +static void test_xx() +{ + uint8 data[] = {0x0,0x1c,0xf,0xff,0xff,0x0,0x0,0x16,'S','Y','S',':','S','Y','S','T','E','M','\\','N','E','T','$','O','B','J','.','O','L','D'} ; + RDATA(data, 0x17, "test_xx"); + if (!handle_event()) { + ; + } +} + + + +static int open_datei(int dirhandle, int attrib, int ext_attrib, char *name) +{ + uint8 *p = requestdata; + int namlen = strlen(name); + *p++ = dirhandle; + *p++ = attrib; + *p++ = ext_attrib; + *p++ = namlen; + memcpy(p, name, namlen); + VDATA(0x4c, namlen+4, "OPEN_DATEI"); + if (!handle_event()) { + return( (int) GET_BE32(responsedata)); + } else return(-1); +} + +static int read_datei(int fh, int offs, int size) +{ + uint8 *p = requestdata; + *p++ = 0; + U32_TO_BE32(fh, p); + p+=6; + U32_TO_BE32(offs, p); + p+=4; + U16_TO_BE16(size, p); + VDATA(0x48, 13, "READ_DATEI"); + if (!handle_event()) { + return( (int) GET_BE16(responsedata)); + } else return(-1); +} + + + + +static void test1(void) +{ + int dirhandle = allocate_dir_handle(0, 'F', "SYS:PUBLIC", 0); + if (dirhandle > -1) { + scan_file_trustees(dirhandle, 6, "NET$LOG.DAT"); + scan_irgendwas(dirhandle, 6, "NET$LOG.DAT"); + } +} + +static void test2(void) +{ + DIR_IDS di; + if (file_search_init(&di, 1, "\\MAIL") > -1) { + file_search_cont(&di, 0xffff, 0x10, "\252"); + } +} + + +static void teste_reads(void) +{ + int fh = open_datei(0, 0x4e, 0x11, "SYS:/LOGIN/SLIST.EXE"); + int gelesen=0; + if (fh > -1) { + int offs=0; + int size = read_datei(fh, offs, 0x200); + while (size > 0) { + offs +=size; + gelesen+=size; + size = read_datei(fh, offs, 0x200); + } + } + DPRINTF(("%d Bytes readed\n", gelesen)); +} + +static void test_wdog(void) +{ + struct t_unitdata ud; + ipxAddr_t source_adr; + IPX_DATA ipx_data_buff; + uint8 ipx_pack_typ; + int flags = 0; + + ud.opt.len = sizeof(ipx_pack_typ); + ud.opt.maxlen = sizeof(ipx_pack_typ); + ud.opt.buf = (char*)&ipx_pack_typ; /* bekommt aktuellen Typ */ + + ud.addr.len = sizeof(ipxAddr_t); + ud.addr.maxlen = sizeof(ipxAddr_t); + + ud.addr.buf = (char*)&source_adr; + + ud.udata.len = sizeof(IPX_DATA); + ud.udata.maxlen = sizeof(IPX_DATA); + ud.udata.buf = (char*)&ipx_data_buff; + while (1) { + if (t_rcvudata(fd_wdog, &ud, &flags) < 0){ + struct t_uderr uderr; + ipxAddr_t erradr; + uint8 err_pack_typ; + uderr.addr.len = sizeof(ipxAddr_t); + uderr.addr.maxlen = sizeof(ipxAddr_t); + uderr.addr.buf = (char*)&erradr; + uderr.opt.len = sizeof(err_pack_typ); + uderr.opt.maxlen = sizeof(err_pack_typ); + uderr.opt.buf = (char*)&err_pack_typ; /* bekommt aktuellen Typ */ + ud.addr.buf = (char*)&source_adr; + t_rcvuderr(fd_ipx, &uderr); + DPRINTF(("Error from %s, Code = 0x%lx\n", visable_ipx_adr(&erradr), uderr.error)); + t_error("t_rcvudata !OK"); + return; + } else { + DPRINTF(("WDOG Packet von:%s, len=%d connid=%d, status=%d\n", + visable_ipx_adr(&source_adr), + (int)ud.udata.len, (int) ipx_data_buff.wdog.connid, + (int)ipx_data_buff.wdog.status)); + if (ipx_data_buff.wdog.status == '?') { + ipx_data_buff.wdog.status = 'Y'; + send_ipx_data(fd_wdog, 17, 2, + (char *) &ipx_data_buff, + &source_adr, "WDOG REPLY"); + } + } + } +} + +/* --------------------------------------------------------- */ +int main(int argc, char **argv) +{ + nw_debug = 1; /* dieses Modul dient nur zum Debuggen !! */ + + if (argc != 3) { + fprintf(stderr, "usage: nwclient MY_ADDR SERVER_ADDR\n"); + exit(1); + } + + DPRINTF(("NWCLIENT MYADDR=%s, SERVER=%s \n", *(argv+1), *(argv+2) )); + + adr_to_ipx_addr(&my_addr, *(argv+1)); + adr_to_ipx_addr(&serv_addr, *(argv+2)); + + if (init_client()) exit(1); + /* ------------------------------------------ */ + + get_conn_nr(); + get_server_info(); + get_pkt_size(); + get_connect(); + get_server_time(); + + file_search_init(NULL, 1, NULL); + get_bindery_access(); + get_bindery_object_id(1, "SUPERVISOR"); + + do_17_17(); + + login_object(1, "SUPERVISOR", NULL); + + get_network_serial_number(); + get_bindery_access(); + + scan_bindery_object(1, "*", MAX_U32); + scan_bindery_object(1, "*", 1); + + { + uint32 lastid = MAX_U32; + while (!scan_bindery_property(1, "NOBODY", "*", &lastid));; + } + get_volume_restriction_for_obj(1, 0); + + test1(); + test2(); + + get_connection_info(0); + get_connection_info(1); + get_connection_info(2); + get_connection_info(3); + + send_console_broadcast("Hello Console !!!!"); + + teste_reads(); + + + test_wdog(); + /*-----------------------------------------------*/ + t_unbind(fd_ipx); + t_close(fd_ipx); + t_unbind(fd_wdog); + t_close(fd_wdog); + return(0); +} + diff --git a/nwconn.c b/nwconn.c new file mode 100644 index 0000000..d538ca6 --- /dev/null +++ b/nwconn.c @@ -0,0 +1,1370 @@ +/* nwconn.c 20-Nov-95 */ +/* one process / connection */ + +/* (C)opyright (C) 1993,1995 Martin Stover, Marburg, Germany + * + * 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 "net.h" +static int default_uid=-1; +static int default_gid=-1; + +static int ipxdebug=0; + +static int father_pid = -1; +static ipxAddr_t from_addr; +static ipxAddr_t my_addr; +static struct t_unitdata ud; +static int ipx_fd = -1; +static uint8 ipx_pack_typ = PACKT_CORE; +static int last_sequence = -9999; + +static IPX_DATA ipxdata; +static NCPRESPONSE *ncpresponse=(NCPRESPONSE*)&ipxdata; +static uint8 *responsedata=((uint8*)&ipxdata)+sizeof(NCPRESPONSE); + +static int requestlen; +static uint8 readbuff[IPX_MAX_DATA+500]; + +static NCPREQUEST *ncprequest = (NCPREQUEST*)readbuff; +static uint8 *requestdata = readbuff + sizeof(NCPREQUEST); +static int ncp_type; + +static int open_ipx_socket() +{ + struct t_bind bind; + ipx_fd=t_open("/dev/ipx", O_RDWR, NULL); + if (ipx_fd < 0) { + t_error("t_open !Ok"); + return(-1); + } + U16_TO_BE16(0, my_addr.sock); /* actual write socket */ + bind.addr.len = sizeof(ipxAddr_t); + bind.addr.maxlen = sizeof(ipxAddr_t); + bind.addr.buf = (char*)&my_addr; + bind.qlen = 0; /* allways */ + if (t_bind(ipx_fd, &bind, &bind) < 0){ + t_error("t_bind !OK"); + close(ipx_fd); + return(-1); + } + DPRINTF(("NWCONN OpenSocket: %s\n", + visable_ipx_adr((ipxAddr_t *) bind.addr.buf))); + return(0); +} + +static void set_default_guid(void) +{ + setgid(default_gid); + setuid(default_uid); +} + +static int ncp_response(int sequence, + int completition, int data_len) + +{ + ncpresponse->sequence = (uint8) sequence; + ncpresponse->completition = (uint8) completition; + last_sequence = sequence; + DPRINTF(("NWCONN NCP_RESP seq:%d, conn:%d, compl=0x%x TO %s\n", + (int)ncpresponse->sequence, (int) ncpresponse->connection, (int)completition, + visable_ipx_adr((ipxAddr_t *) ud.addr.buf))); + + ud.udata.len = ud.udata.maxlen = sizeof(NCPRESPONSE) + data_len; + if (t_sndudata(ipx_fd, &ud) < 0){ + t_error("t_sndudata in NWCONN !OK"); + return(-1); + } + return(0); +} + + +static int test_handle = -1; +static void handle_ncp_serv() +{ + int data_len = 0; + int sequence = (int)ncprequest->sequence; + int task = (int)ncprequest->task; + int reserved = (int)ncprequest->reserved; + int function = (int)ncprequest->function; + int completition = 0; /* first set */ + int org_nw_debug = nw_debug; + int do_druck = 0; + + if (last_sequence == sequence && ncp_type != 0x1111){ /* send the same again */ + if (t_sndudata(ipx_fd, &ud) < 0){ + t_error("t_sndudata !OK"); + } + DPRINTF(("Sequence %d is written twice\n", sequence)); + return; + } + + if (!nw_debug && ( + /* + function == 0x43 || + function == 0x4c || + function == 0x4d || + function == 0x4a || + */ + function == 0x11 + ) ) nw_debug=1; + + + if (nw_debug){ + int j = requestlen; + if (nw_debug == 1 + && (function==0x48 || function == 0x49)) /* read or write */ + nw_debug=0; + if (nw_debug == 2 + && (function==0x48)) /* read */ + nw_debug=0; + + if (nw_debug){ + do_druck=2; + DPRINTF(("NCP REQUEST:type:0x%x, seq:%d, task:%d, reserved:0x%x, func:0x%x\n", + ncp_type, sequence, task, reserved, function)); + if (j > 0){ + uint8 *p=requestdata; + DPRINTF(("len %d, DATA:", j)); + while (j--) { + int c = *p++; + if (c > 32 && c < 127) DPRINTF((",\'%c\'", (char) c)); + else DPRINTF((",0x%x", c)); + } + DPRINTF(("\n")); + } + } + } + + if (ncp_type == 0x2222) { + switch (function) { + case 0x12 : { /* Get Volume Info with Number */ + int volume = (int)*requestdata; + struct XDATA { + uint8 sec_per_block[2]; + uint8 total_blocks[2]; + uint8 avail_blocks[2]; + uint8 total_dirs[2]; + uint8 avail_dirs[2]; + uint8 name[16]; + uint8 removable[2]; + } *xdata = (struct XDATA*) responsedata; + int result; + memset(xdata, 0, sizeof(struct XDATA)); + if ((result = nw_get_volume_name(volume, xdata->name))>-1){ + struct fs_usage fsp; + if (!nw_get_fs_usage(xdata->name, &fsp)) { + U16_TO_BE16(38, xdata->sec_per_block); /* hard coded */ + U16_TO_BE16(fsp.fsu_blocks, xdata->total_blocks); + U16_TO_BE16(fsp.fsu_bavail, xdata->avail_blocks); + U16_TO_BE16(fsp.fsu_files, xdata->total_dirs); + U16_TO_BE16(fsp.fsu_ffree, xdata->avail_dirs); + U16_TO_BE16(0, xdata->removable); + } + data_len = sizeof(struct XDATA); + } else completition = (uint8) -result; + } break; + + case 0x14 : { /* GET DATE und TIME */ + struct SERVER_DATE { + uint8 year; + uint8 mon; + uint8 day; + uint8 std; + uint8 min; + uint8 sec; + uint8 day_of_week; + } *mydate = (struct SERVER_DATE*) responsedata; + struct tm *s_tm; + time_t timer; + time(&timer); + s_tm = localtime(&timer); + mydate->year = (uint8) s_tm->tm_year; + mydate->mon = (uint8) s_tm->tm_mon+1; + mydate->day = (uint8) s_tm->tm_mday; + + mydate->std = (uint8) s_tm->tm_hour; + mydate->min = (uint8) s_tm->tm_min; + mydate->sec = (uint8) s_tm->tm_sec; + mydate->day_of_week = (uint8) s_tm->tm_wday; /* Wochentag */ + data_len = sizeof(struct SERVER_DATE); + } + break; + + + case 0x16 : { + uint8 len = *(requestdata+1); + uint8 *p = requestdata +2; + if (0 == *p){ + /****** * SetDirektoryHandle *************/ + struct INPUT { + uint8 header[7]; /* Requestheader */ + uint8 filler; /* 0x0 */ + uint8 datalen; + uint8 type; /* 0x0 */ + uint8 target_dir_handle; /* Verzeichnis Handle zu ndern */ + uint8 source_dir_handle; /* Verzeichnis Handle */ + uint8 pathlen; + uint8 path[2]; + } *input = (struct INPUT *) (ncprequest); + completition = + (uint8)-nw_set_dir_handle((int)input->target_dir_handle, + (int)input->source_dir_handle, + input->path, + (int)input->pathlen, task); + + } else if (1 == *p){ /* liefert Verzeichnis Namen */ + /* Dir_handles */ + /******** GetDirektoryPATH ***************/ + struct INPUT { + uint8 header[7]; /* Requestheader */ + uint8 filler; /* 0x0 */ + uint8 datalen; /* 0x2 */ + uint8 type; /* 0x1 */ + uint8 dir_handle; /* Verzeichnis Handle */ + } *input = (struct INPUT *) (ncprequest); + struct XDATA { + uint8 len; + uint8 name[256]; + } *xdata = (struct XDATA*) responsedata; + int result = nw_get_directory_path((int)input->dir_handle, xdata->name); + if (result > -1){ + xdata->len = (uint8) result; + data_len = result + 1; + xdata->name[result] = '\0'; + DPRINTF(("GetDirektoryPATH=%s\n", xdata->name)); + } else completition = (uint8)-result; + } else if (2 == *p){ /* Scan Direktory Information */ + /******** Scan Dir Info ****************/ + struct INPUT { + uint8 header[7]; /* Requestheader */ + uint8 filler; /* 0x0 */ + uint8 datalen; /* */ + uint8 type; /* 0x2 */ + uint8 dir_handle; /* Verzeichnis Handle */ + uint8 sub_dir_nmbr[2]; /* HI LOW */ + uint8 len; /* kann auch 0 sein */ + uint8 path[2]; + } *input = (struct INPUT *) (ncprequest); + struct XDATA { + uint8 sub_dir_name[16]; + uint8 create_date_time[4]; + uint8 owner_id[4]; /* HI LOW */ + uint8 max_right_mask; + uint8 reserved; /* Reserved by Novell */ + uint8 sub_dir_nmbr[2]; /* HI LOW */ + } *xdata = (struct XDATA*) responsedata; + int result; + memcpy(xdata->sub_dir_nmbr, input->sub_dir_nmbr, 2); + result = nw_scan_dir_info((int)input->dir_handle, + input->path, (int)input->len, + xdata->sub_dir_nmbr, xdata->sub_dir_name, + xdata->create_date_time, xdata->owner_id); + if (result > -1){ + xdata->max_right_mask = (uint8)result; + data_len = sizeof(struct XDATA); + DPRINTF(("Scan Dir Info max_right_mask=%d\n", (int)result)); + } else completition = (uint8)-result; + } else if (*p == 0x3){ /* Get Direktory Rights */ + /******** Get Eff Dir Rights ****************/ + struct XDATA { + uint8 eff_right_mask; /* Effektive Right to Dir, old! */ + } *xdata = (struct XDATA*) responsedata; + int result = nw_get_eff_dir_rights((int)*(p+1), p+3, (int)*(p+2)); + if (result > -1) { + xdata->eff_right_mask = (uint8) result; + data_len = 1; + DPRINTF(("Get eff Dir Rights=%d\n", (int)result)); + } else completition = (uint8) -result; + } else if (*p == 0x4){ /* Modify Max Right MAsk */ + /******** MODIFY MAX RIGHT MASK ****************/ + /* NO REPLY !! */ + completition = 0xfb; /* TODO */ + } else if (*p == 0x5){ /* Get Volume Number 0 .. 31 */ + /******** GetVolume Number ***************/ + /* p+1 = namelen */ + /* p+2 = data z.b 'SYS' */ + struct XDATA { + uint8 volume; /* Nummer */ + } *xdata = (struct XDATA*) responsedata; + int result = nw_get_volume_number(p+2, (int)*(p+1)); + if (result > -1) { + xdata->volume = (uint8) result; + data_len = 1; + } else completition = (uint8) -result; + } else if (*p == 0x6){ /* Get Volume Name von 0 .. 31 */ + /******** Get Volume Name ***************/ + struct XDATA { + uint8 namelen; + uint8 name[16]; + } *xdata = (struct XDATA*) responsedata; + int result = nw_get_volume_name((int)*(p+1), xdata->name); + if (result > -1) { + xdata->namelen = (uint8) result; + data_len = sizeof(struct XDATA); + } else completition = (uint8) -result; + } else if (*p == 0xa){ /* legt Verzeichnis an */ + /******** Create Dir *********************/ + int dir_handle = (int) *(p+1); + int rightmask = (int) *(p+2); + int pathlen = (int) *(p+3); + uint8 *path = p+4; + int code = nw_mk_rd_dir(dir_handle, path, pathlen, 1); + if (code) completition = (uint8) -code; + } else if (*p == 0xb){ /* lscht Verzeichnis */ + /******** Delete DIR *********************/ + int dir_handle = (int) *(p+1); + int reserved = (int) *(p+2); /* Res. by NOVELL */ + int pathlen = (int) *(p+3); + uint8 *path = p+4; + int code = nw_mk_rd_dir(dir_handle, path, pathlen, 0); + if (code) completition = (uint8) -code; + } else if (*p == 0xd){ /* Add Trustees to DIR */ + /******** GetDirektoryPATH ***************/ + struct INPUT { + uint8 header[7]; /* Requestheader */ + uint8 filler; /* 0x0 */ + uint8 datalen; + uint8 type; + uint8 dir_handle; /* Verzeichnis Handle */ + uint8 trustee_id[4]; /* Trustee Object ID */ + uint8 trustee_right_mask; + uint8 pathlen; + uint8 path; + } *input = (struct INPUT *) (ncprequest); + /* TODO !!!!!!!!!!!!!!!!!!!! */ + do_druck++; + } else if (*p == 0x12 /* Allocate Permanent Dir Handle */ + + /******** Allocate Permanent DIR Handle **/ + || *p == 0x13 /* Allocate Temp Dir Handle */ + /******** Allocate Temp DIR Handle **/ + || *p == 0x16) { /* Allocate spez Temp Dir Handle */ + /******** Allocate spez temp DIR Handle **/ + struct XDATA { + uint8 dirhandle; /* new Dir Handle */ + uint8 right_mask; /* 0xff effektive Right MAsk ? */ + } *xdata = (struct XDATA*) responsedata; + int dirhandle = nw_alloc_dir_handle( + (int) *(p+1), + p+4, + (int)*(p+3), + (int)*(p+2), + (*p==0x12) ? 0 + : ((*p==0x13) ? 1 : 2), task); + if (dirhandle > -1){ + xdata->dirhandle = (uint8) dirhandle; + xdata->right_mask = 0xff; + data_len = sizeof(struct XDATA); + } else completition = (uint8) -dirhandle; + + } else if (*p == 0x14){ /* deallocate Dir Handle */ + /******** Free DIR Handle ****************/ + int err_code = nw_free_dir_handle((int)*(p+1)); + if (err_code) completition = (uint8) -err_code; + } else if (*p == 0x15){ /* liefert Volume Information */ + /******** Get Volume Info with Handle ****/ + struct XDATA { + uint8 reserve1; + uint8 len; + uint8 total_blocks[2]; + uint8 avail_blocks[2]; + uint8 total_dirs[2]; /* anz dirs */ + uint8 avail_dirs[2]; /* free dirs */ + uint8 name[16]; /* SYS Name */ + uint8 removable[2]; + } *xdata = (struct XDATA*)responsedata; + int result = nw_get_vol_number((int)*(p+1)); + memset(xdata, 0, sizeof(struct XDATA)); + if (result > -1) { + result = nw_get_volume_name(result, xdata->name); + if (result > -1) { + struct fs_usage fsp; + if (!nw_get_fs_usage(xdata->name, &fsp)) { + xdata->len = 8; /* blocks entries */ + U16_TO_BE16(fsp.fsu_blocks, xdata->total_blocks); + U16_TO_BE16(fsp.fsu_bavail, xdata->avail_blocks); + U16_TO_BE16(fsp.fsu_files, xdata->total_dirs); + U16_TO_BE16(fsp.fsu_ffree, xdata->avail_dirs); + U16_TO_BE16(0, xdata->removable); + } + data_len = sizeof(struct XDATA); + DPRINTF(("GIVE VOLUME INFO von :%s:\n", xdata->name)); + result = 0; + } + } + completition = (uint8)-result; + } else if (*p == 0x19){ /* Set Directory Information */ + struct INPUT { + uint8 header[7]; /* Requestheader */ + uint8 filler; /* 0x0 */ + uint8 datalen; + uint8 sub_func; + uint8 dir_handle; /* Verzeichnis Handle */ + uint8 trustee_id[4]; /* Trustee Object ID */ + uint8 trustee_right_mask; + uint8 pathlen; + uint8 path; + } *input = (struct INPUT *) (ncprequest); + /* No REPLY */ + completition = 0xfb; /* !!!!! TODO !!!! */ + } else if (*p == 0x1a){ /* Get Pathname of A Volume Dir Pair */ + struct INPUT { + uint8 header[7]; /* Requestheader */ + uint8 filler; /* 0x0 */ + uint8 datalen; + uint8 sub_func; + uint8 volume; + uint8 dir_entry[2]; + } *input = (struct INPUT *) (ncprequest); + struct XDATA { + uint8 pathlen; + uint8 pathname; + } *xdata = (struct XDATA*)responsedata; + completition = 0xfb; /* !!!!! Machen !!!! */ + } else if (*p == 0x1e){ /* liefert Trustees ?? */ + /* des Dir_handles + PATH */ + struct INPUT { + uint8 header[7]; /* Requestheader */ + uint8 filler; /* 0x0 */ + uint8 datalen; /* 0x2 */ + uint8 type; /* 0x1e */ + uint8 dir_handle; /* Verzeichnis Handle */ + uint8 attrib; /* Attrib ?? 0x6 */ + uint8 reserve1[4]; /* alles 0xff */ + uint8 len; + uint8 data[2]; + } *input = (struct INPUT *) (ncprequest); + NW_FILE_INFO f; + struct XDATA { + uint8 unknown[15]; + uint8 namlen; + uint8 name[14]; + } *xdata = (struct XDATA*)responsedata; + int len=input->len; + int searchsequence = nw_search( (uint8*) + &(f), + (int)input->dir_handle, + MAX_U16, + (int) input->attrib, + input->data, len); + if (searchsequence > -1){ + memset(xdata, 0, 132); + xdata->namlen = min(14, strlen(f.name)); + memcpy(xdata->name, f.name, xdata->namlen); + } else completition = (uint8) - searchsequence; + } else if (*p == 0x20){ /* testet ??*/ + struct XDATA { + uint8 res1; /* 0x0 */ + } *xdata = (struct XDATA*) responsedata; + xdata->res1 = 0x0; + data_len = 1; + } else if (*p == 0x21) { + /* change Vol restrictions for Obj */ + uint8 volnr = *(p+1); + uint32 id = GET_BE32(p+2); + uint32 blocks = GET_BE32(p+6); + DPRINTF(("Change vol restriction vol=%d, id=0x%lx, Blocks=0x%lx", + (int)volnr, id, blocks)); + } else if (*p == 0x22) { + /* remove Vol restrictions for Obj */ + uint8 volnr = *(p+1); + uint32 id = GET_BE32(p+2); + DPRINTF(("Renmove vol restriction vol=%d, id=0x%lx", + (int)volnr, id)); + + } else if (*p == 0x25){ /* setting FILE INFO ??*/ + /* TODO !!!!!!!!!!!!!!!!!!!! */ + do_druck++; + } else if (*p == 0x27){ /* Add Trustees to DIR ?? */ + struct INPUT { + uint8 header[7]; /* Requestheader */ + uint8 filler; /* 0x0 */ + uint8 datalen; /* 0x2 */ + uint8 type; /* 0x27 */ + uint8 dir_handle; /* Verzeichnis Handle */ + uint8 trustee_id[4]; /* Trustee Object ID */ + uint8 trustee_right_mask; + uint8 weis_nicht; /* ??? z.B. 0x0 */ + uint8 pathlen; + uint8 path; + } *input = (struct INPUT *) (ncprequest); + /* TODO !!!!!!!!!!!!!!!!!!!! */ + do_druck++; + } else if (*p == 0x29){ + /* read volume restrictions for an object */ + uint8 volnr = *(p+1); + uint32 id = GET_BE32(p+2); + struct XDATA { + uint8 weisnicht[8]; /* ?????? */ + } *xdata = (struct XDATA*) responsedata; + DPRINTF(("Get vol restriction vol=%d, id=0x%lx", + (int)volnr, id)); + memset(xdata, 0, sizeof(struct XDATA)); + data_len=sizeof(struct XDATA); + } else if (*p == 0x2a){ /* Get Eff. Dir Rights ??*/ + /* from Dir_handles + PATH */ + struct XDATA { + uint8 eff_rights; /* Effektive Right to Dir */ + uint8 unkwown_data; /* 0x1 */ + } *xdata = (struct XDATA*) responsedata; + NW_DIR_INFO d; + int len=(int)*(p+2); + int searchsequence; + if (len) + searchsequence = nw_search((uint8*)&(d), + (int)*(p+1), /* dir_handle */ + MAX_U16, + (int) 0x10, /* only dirs ?? */ + p+3, /* path */ + len); /* pathlen */ + else { + searchsequence = nw_get_eff_dir_rights( + (int)*(p+1), + p+3, + len); + if (searchsequence > -1) + d.ext_attrib = searchsequence; + } + if (searchsequence > -1){ + xdata->eff_rights = d.ext_attrib; + xdata->unkwown_data = 0x1; + data_len = sizeof(struct XDATA); + } else completition = (uint8) - searchsequence; + } else if (*p == 0x2c){ + /* Get Volume and Purge Information */ + /* new Call since V3.11 */ + /* ncpfs need this call */ + int volume = (int) *(p+1); + struct XDATA { + uint8 total_blocks[4]; + uint8 avail_blocks[4]; + uint8 purgeable_blocks[4]; + uint8 not_purgeable_blocks[4]; + uint8 total_dirs[4]; + uint8 avail_dirs[4]; + uint8 reserved_by_novell[4]; + uint8 sec_per_block; + uint8 namlen; + uint8 name[1]; + } *xdata = (struct XDATA*) responsedata; + char name[100]; + int result = nw_get_volume_name(volume, name); + if (result > -1){ + struct fs_usage fsp; + memset(xdata, 0, sizeof(struct XDATA)); + if (!nw_get_fs_usage(name, &fsp)) { + xdata->sec_per_block = 38; /* hard coded */ + U32_TO_BE32(fsp.fsu_blocks, xdata->total_blocks); + U32_TO_BE32(fsp.fsu_bavail, xdata->avail_blocks); + U32_TO_BE32(fsp.fsu_files, xdata->total_dirs); + U32_TO_BE32(fsp.fsu_ffree, xdata->avail_dirs); + } + xdata->namlen = strlen(name); + strmaxcpy(xdata->name, name, xdata->namlen); + data_len = xdata->namlen + 30; + } else completition = (uint8) -result; + } else if (*p == 0x2d){ + /* Get Direktory Information */ + int dir_handle = (int) *(p+1); + struct XDATA { + uint8 total_blocks[4]; + uint8 avail_blocks[4]; + uint8 total_dirs[4]; + uint8 avail_dirs[4]; + uint8 reserved_by_novell[4]; + uint8 sec_per_block; + uint8 namlen; + uint8 name[1]; /* Volume Name */ + } *xdata = (struct XDATA*) responsedata; + int result = nw_get_vol_number(dir_handle); + char name[100]; + if (result > -1) + result = nw_get_volume_name(result, name); + if (result > -1) { + struct fs_usage fsp; + memset(xdata, 0, sizeof(struct XDATA)); + if (!nw_get_fs_usage(name, &fsp)) { + xdata->sec_per_block = 38; /* hard coded */ + U32_TO_BE32(fsp.fsu_blocks, xdata->total_blocks); + U32_TO_BE32(fsp.fsu_bavail, xdata->avail_blocks); + U32_TO_BE32(fsp.fsu_files, xdata->total_dirs); + U32_TO_BE32(fsp.fsu_ffree, xdata->avail_dirs); + } + xdata->namlen = strlen(name); + strmaxcpy(xdata->name, name, xdata->namlen); + data_len = xdata->namlen + 22; + } else completition = (uint8) -result; + } else if (*p == 0x2e){ /* RENAME DATEI */ + completition = 0xfb; /* TODO: !!! */ + } else completition = 0xfb; /* unkwown request */ + } + break; + +#if 1 + case 0x17 : { /* FILE SERVER ENVIRONMENT */ + uint8 len = *(requestdata+1); + uint8 ufunc = *(requestdata+2); + switch (ufunc) { + case 0x0f: { /* Scan File Information */ + struct INPUT { + uint8 header[7]; /* Requestheader */ + uint8 div[3]; /* 0, len + ufunc */ + uint8 sequence[2]; /* z.B. 0xff, 0xff */ + + uint8 dir_handle; + uint8 search_attrib; /* 0: NONE */ + /* 02: HIDDEN */ + /* 04: SYSTEM */ + /* 06: BOTH */ + /* 0x10: DIR */ + uint8 len; + uint8 data[2]; /* Name */ + } *input = (struct INPUT *)ncprequest; + + struct OUTPUT { + uint8 sequence[2]; /* next sequence */ + NW_FILE_INFO f; + uint8 owner_id[4]; + uint8 archive_date[2]; + uint8 archive_time[2]; + uint8 reserved[56]; + } *xdata = (struct OUTPUT*)responsedata; + int len = input->len; + int searchsequence; + memset(xdata, 0, sizeof(struct OUTPUT)); + + searchsequence = nw_search( (uint8*) &(xdata->f), + (int)input->dir_handle, + (int) GET_BE16(input->sequence), + (int) input->search_attrib, + input->data, len); + + if (searchsequence > -1) { + U16_TO_BE16((uint16) searchsequence, xdata->sequence); + U32_TO_BE32(1L, xdata->owner_id); /* Supervisor */ + data_len = sizeof(struct OUTPUT); + } else completition = (uint8) (- searchsequence); + } + break; + + case 0x10: { /* Set File Information */ + completition = 0xfb; + } + break; + + case 0x79: { /* creat queue job and file */ + /* somme of this call is handled in ncpserv !! */ + struct INPUT { + uint8 header[7]; /* Requestheader */ + uint8 packetlen[2]; /* low high */ + uint8 func; /* 0x79 */ + uint8 queue_id[4]; /* Queue ID */ + uint8 queue_job[280]; + /* this is added by ncpserv */ + uint8 dir_nam_len; /* len of dirname */ + uint8 dir_name[1]; + } *input = (struct INPUT *) (ncprequest); + int result = nw_creat_queue(ncpresponse->connection, + input->queue_id, + input->queue_job, + input->dir_name, + (int)input->dir_nam_len); + if (!result) { + data_len = 78; + memcpy(responsedata, input->queue_job, data_len); + } else completition= (uint8)-result; + } + break; + + case 0x7f: { /* close file and start queue */ + struct INPUT { + uint8 header[7]; /* Requestheader */ + uint8 packetlen[2]; /* low high */ + uint8 func; /* 0x7f */ + uint8 queue_id[4]; /* Queue ID */ + uint8 job_id[4]; /* result from creat queue */ + /* this is added by ncpserv */ + uint8 prc_len; /* len of printcommand */ + uint8 prc[1]; /* printcommand */ + } *input = (struct INPUT *) (ncprequest); + int result = nw_close_file_queue(input->queue_id, + input->job_id, + input->prc, + input->prc_len); + if (result < 0) completition = (uint8)-result; + } + break; + + case 0xf3: { /* Map Direktory Number TO PATH */ + DPRINTF(("TODO: Map Direktory Number TO PATH\n")); + completition = 0xff; + } + break; + + case 0xf4: { /* Map PATH TO Dir Entry */ + DPRINTF(("TODO: Map PATH TO Dir Entry\n")); + completition = 0xff; + } + break; + + default : completition = 0xfb; + break; + } /* switch (ufunc) */ + } /* case 0x17 */ + break; +#endif + + case 0x18 : /* End of Job */ + nw_free_handles((task > 0) ? task : 1); + break; + + case 0x19 : /* logout, some of this call is handled in ncpserv. */ + nw_free_handles(0); + set_default_guid(); + break; + + case 0x1a : /* lock file */ + case 0x1e : /* unlock file */ + { + struct INPUT { + uint8 header[7]; /* Requestheader */ + uint8 reserve; /* 0x1 */ + uint8 fhandle[4]; /* Filehandle */ + uint8 ext_fhandle[2]; /* all zero */ + uint8 offset[4]; + uint8 size[4]; + uint8 weisnicht[2]; /* lock timeout ??? */ + } *input = (struct INPUT *)ncprequest; + int fhandle = GET_BE32(input->fhandle); + int offset = GET_BE32(input->offset); + int size = GET_BE32(input->size); + completition = (uint8)(-nw_lock_datei(fhandle, + offset, size, + (int)(function == 0x1a))); + } + break; + + case 0x21 : { /* Negotiate Buffer Size, Packetsize */ + int wantsize = GET_BE16((uint8*)ncprequest); + uint8 *getsize=responsedata; + U16_TO_BE16(min(0x200, wantsize), getsize); + data_len = 2; + } + break; + +#if 0 + case 0x22 : /* div TTS Calls */ + break; +#endif + + + case 0x3e : { /* FILE SEARCH INIT */ + /* returns dhandle for searchings */ + int dir_handle = (int)*requestdata; + int len = (int)*(requestdata+1); /* pathlen */ + uint8 *p = requestdata+2; /* path */ + struct XDATA { + uint8 volume; /* Volume */ + uint8 dir_id[2]; /* Direktory ID */ + uint8 searchsequenz[2]; + uint8 dir_rights; /* Rights */ + } *xdata= (struct XDATA*) responsedata; + int volume; + int searchsequenz; + int dir_id; + int rights = nw_open_dir_handle(dir_handle, p, len, + &volume, &dir_id, &searchsequenz); + if (rights >-1) { + xdata->volume = (uint8)volume; + U16_TO_BE16((uint16)dir_id, xdata->dir_id); + U16_TO_BE16((uint16)searchsequenz, xdata->searchsequenz); + xdata->dir_rights = (uint8)rights; + data_len = sizeof(struct XDATA); + } else completition = (uint8) -rights; + } break; + + case 0x3d : { /* commit file, flush file buffers */ + struct INPUT { + uint8 header[7]; /* Requestheader */ + uint8 reserve; + uint8 fhandle[4]; /* filehandle */ + uint8 ext_fhandle[2]; /* all zero */ + } *input = (struct INPUT *)ncprequest; + uint32 fhandle = GET_BE32(input->fhandle); + DPRINTF(("TODO: COMMIT FILE:fhandle=%ld\n", fhandle)); + /* TODO */ + ; + } break; + + case 0x3f : { /* file search continue */ + /* Dir_id is from file search init */ + struct INPUT { + uint8 header[7]; /* Requestheader */ + uint8 volume; /* Volume ID */ + uint8 dir_id[2]; /* von File Search Init */ + uint8 searchsequence[2]; /* FRAGE Sequence FFFF ertster Eintrag */ + uint8 search_attrib; /* Attribute */ + /* 0 none, + 2 HIDDEN, + * 4 System , + 6 Both, + * 0x10 Dir + */ + uint8 len; /* Weitere Lnge */ + uint8 data[2]; /* Dateiname mit Wild */ + } *input = (struct INPUT *) (ncprequest); + int len=input->len ; /* FN Length */ + struct OUTPUT { + uint8 searchsequence[2]; /* FRAGE Sequence */ + uint8 dir_id[2]; /* Direktory ID */ + /* is correct !! */ + union { + NW_DIR_INFO d; + NW_FILE_INFO f; + } u; + } *xdata = (struct OUTPUT*)responsedata; + + int searchsequence = nw_dir_search( (uint8*) &(xdata->u), + (int) GET_BE16(input->dir_id), + (int) GET_BE16(input->searchsequence), + (int) input->search_attrib, + input->data, len); + if (searchsequence > -1) { + U16_TO_BE16((uint16) searchsequence, xdata->searchsequence); + memcpy(xdata->dir_id, input->dir_id, 2); + data_len = sizeof(struct OUTPUT); + } else completition = (uint8) (- searchsequence); + } + break; + + case 0x40 : /* GET File Mode ?? */ + { + struct INPUT { + uint8 header[7]; /* Requestheader */ + uint8 sequenz[2]; /* z.B. 0xff, 0xff */ + uint8 dir_handle; /* z.B 0x1 */ + uint8 search_attrib; /* z.B. 0x6 */ + uint8 len; + uint8 data[2]; /* Name */ + } *input = (struct INPUT *)ncprequest; + struct OUTPUT { + uint8 sequenz[2]; /* Antwort Sequenz */ + uint8 reserve2[2]; /* z.B 0x0 0x0 */ + union { + NW_DIR_INFO d; + NW_FILE_INFO f; + } u; + } *xdata = (struct OUTPUT*)responsedata; + int len = input->len; + uint8 my_sequenz[2]; + int searchsequence; + memcpy(my_sequenz, input->sequenz, 2); + searchsequence = nw_search( (uint8*) &(xdata->u), + (int)input->dir_handle, + (int) GET_BE16(my_sequenz), + (int) input->search_attrib, + input->data, len); + if (searchsequence > -1) { + U16_TO_BE16((uint16) searchsequence, xdata->sequenz); + data_len = sizeof(struct OUTPUT); + } else completition = (uint8) (- searchsequence); + } + break; + + case 0x42 : /* close file */ + { + struct INPUT { + uint8 header[7]; /* Requestheader */ + uint8 reserve; + uint8 fhandle[4]; /* filehandle */ + uint8 ext_fhandle[2]; /* all zero */ + } *input = (struct INPUT *)ncprequest; + uint32 fhandle = GET_BE32(input->fhandle); + completition = (uint8)(-nw_close_datei(fhandle)); + if (!completition && fhandle == test_handle) { + do_druck++; + test_handle = -1; + } + } + break; + + case 0x43 : /* creat file, overwrite if exist */ + case 0x4D : /* create new file */ + { + struct INPUT { + uint8 header[7]; /* Requestheader */ + uint8 dirhandle; + uint8 attribute; /* creat Attribute */ + uint8 len; + uint8 data[1]; /* Name */ + } *input = (struct INPUT *)ncprequest; + struct OUTPUT { + uint8 fhandle[4]; /* Filehandle */ + uint8 extfhandle[2]; + uint8 reserved[2]; /* rese. by NOVELL */ + NW_FILE_INFO fileinfo; + } *xdata= (struct OUTPUT*)responsedata; + int fhandle=nw_creat_open_file( + (int)input->dirhandle, + input->data, + (int)input->len, + &(xdata->fileinfo), + (int)input->attribute, + 0, + (function==0x43) ? 1 : 2); + if (fhandle > -1){ + data_len = sizeof(struct OUTPUT); + U32_TO_BE32(fhandle, xdata->fhandle); + U16_TO_BE16(0, xdata->extfhandle); + U16_TO_BE16(0, xdata->reserved); + +#ifdef TEST_FNAME + input->data[input->len] = '\0'; + if (strstr(input->data, TEST_FNAME)){ + test_handle = fhandle; + do_druck++; + } +#endif + } else completition = (uint8) (-fhandle); + } + break; + + case 0x44 : /* file(s) delete */ + { + struct INPUT { + uint8 header[7]; /* Requestheader */ + uint8 dirhandle; /* 0x0 */ + uint8 searchattributes; + /* 0 none, 2 Hidden, 4 System, 6 Both */ + uint8 len; + uint8 data[2]; /* Name */ + } *input = (struct INPUT *)ncprequest; + int err_code = nw_delete_datei((int)input->dirhandle, + input->data, (int)input->len); + if (err_code < 0) + completition = (uint8) -err_code; + } + break; + + case 0x45 : /* rename file */ + { + struct INPUT { + uint8 header[7]; /* Requestheader */ + uint8 dir_handle; /* ?? 0x1 */ + uint8 reserve1; /* z.B. 0x2 */ + uint8 len; + uint8 data[2]; /* Name */ + } *input = (struct INPUT *)ncprequest; + uint8 *p = input->data+input->len; /* reserve z.B. 0x1 */ + /* + 1 = len2 */ + /* + 1 = data2 */ + int errcode = mv_file( + (int)input->dir_handle, input->data,(int)input->len, + (int)input->dir_handle, p+2, (int)*(p+1) ); + + if (errcode < 0) completition = (uint8) -errcode; + } + break; + + case 0x46 : /* chmod Datei ??? */ + { + struct INPUT { + uint8 header[7]; /* Requestheader */ + uint8 attrib; /* 0x80, od 0x0 */ + /* 0x80 z.B. fr Sharable */ + uint8 dir_handle; /* ??? z.B.0x1 */ + uint8 modus; /* z.B.0x6 */ + uint8 len; + uint8 data[2]; /* Name */ + } *input = (struct INPUT *)ncprequest; + completition = + (uint8) (-nw_chmod_datei((int)input->dir_handle, + input->data, (int)input->len, + (int)input->modus)); + } + break; + + case 0x47 : /* move pointer to end of file ???? */ + /* and return filesize ? */ + { + struct INPUT { + uint8 header[7]; /* Requestheader */ + uint8 filler; + uint8 fhandle[4]; /* Dateihandle */ + uint8 ext_filehandle[2]; /* ?? alles 0 */ + } *input = (struct INPUT *)ncprequest; + struct OUTPUT { + uint8 size[4]; /* Position ??? */ + } *xdata=(struct OUTPUT*)responsedata; + int fhandle = GET_BE32(input->fhandle); + int size = nw_seek_datei(fhandle, 0); + if (size > -1) { + data_len = sizeof(struct OUTPUT); + U32_TO_BE32(size, xdata->size); + } + else completition = (uint8) -size; + } + break; + + + case 0x48 : /* read file */ + { + struct INPUT { + uint8 header[7]; /* Requestheader */ + uint8 filler; + uint8 fhandle[4]; /* filehandle */ + uint8 reserve[2]; /* alles 0 */ + uint8 offset[4]; /* alles 0 */ + uint8 max_size[2]; /* zu lesende Bytes */ + } *input = (struct INPUT *)ncprequest; + struct OUTPUT { + uint8 size[2]; /* Lese Bytes */ + uint8 data[1072]; /* max data */ + } *xdata=(struct OUTPUT*)responsedata; + int fhandle = GET_BE32(input->fhandle); + int max_size = GET_BE16(input->max_size); + off_t offset = GET_BE32(input->offset); + int zusatz = (offset & 1) ? 1 : 0; + int size = nw_read_datei(fhandle, + xdata->data+zusatz, + max_size, + offset); + + if (fhandle == test_handle) do_druck++; + if (size > -1) { + U16_TO_BE16(size, xdata->size); + data_len=size+zusatz+2; + } else completition = (uint8) -size; + } + break; + + case 0x49 : { /* write file */ + struct INPUT { + uint8 header[7]; /* Requestheader */ + + uint8 filler; /* 0 Filler ?? */ + uint8 fhandle[4]; /* Dateihandle */ + uint8 ext_handle[2]; + uint8 offset[4]; /* SEEK OFFSET */ + uint8 size[2]; /* Datasize */ + uint8 data[2]; /* Schreibdaten */ + } *input = (struct INPUT *)ncprequest; + off_t offset = GET_BE32(input->offset); + int fhandle = GET_BE32(input->fhandle); + int input_size = GET_BE16(input->size); + int size = nw_write_datei(fhandle, + input->data, + input_size, + offset); + if (fhandle == test_handle) do_druck++; + if (size < 0) + completition = (uint8) -size; + } + break; + + + case 0x4a : { /* File SERVER COPY */ + /* should be OK */ + struct INPUT { + uint8 header[7]; /* Requestheader */ + uint8 reserved; /* Reserved by Novell */ + uint8 qfhandle[4]; /* Quellfile */ + uint8 reserve1[2]; /* ext Filehandle */ + uint8 zfhandle[4]; /* Zielfile */ + uint8 reserve2[2]; /* ext Filehandle */ + uint8 qoffset[4]; /* Quellfile Offset */ + uint8 zoffset[4]; /* Zielfile Offset */ + uint8 size[4]; /* Anzahl */ + } *input = (struct INPUT *)ncprequest; + int qfhandle = GET_BE32(input->qfhandle); + int zfhandle = GET_BE32(input->zfhandle); + off_t qoffset = GET_BE32(input->qoffset); + off_t zoffset = GET_BE32(input->zoffset); + uint32 input_size = GET_BE32(input->size); + int size = nw_server_copy(qfhandle, qoffset, + zfhandle, zoffset, + input_size); + if (size < 0) completition = (uint8) -size; + else { + struct OUTPUT { + uint8 zsize[4]; /* real transfered Bytes */ + } *xdata= (struct OUTPUT*)responsedata; + U32_TO_BE32(size, xdata->zsize); + data_len = sizeof(struct OUTPUT); + } + } + break; + + + case 0x4b : { /* set date of file, file will be closed later */ + struct INPUT { + uint8 header[7]; /* Requestheader */ + uint8 filler; + uint8 fhandle[4]; /* Dateihandle */ + uint8 reserve[2]; /* ext Filehandle ??? */ + uint8 zeit[2]; /* time */ + uint8 datum[2]; /* date */ + } *input = (struct INPUT *)ncprequest; + int result = nw_set_fdate_time(GET_BE32(input->fhandle), + input->datum, input->zeit); + if (result <0) completition = (uint8) -result; + } + break; + + case 0x4c : { /* open file */ + struct INPUT { + uint8 header[7]; /* Requestheader */ + uint8 dirhandle; /* Dirhandle */ + uint8 attrib; /* z.B. 0x6 od. 0x4e */ + /* O_RDWR|TRUNC 0x6, O_RDONLY 0x6 */ + + uint8 access; /* z.B. 0x9 od 0x11 od. 0x13 */ + /* O_RDWR|TRUNC 0x13, O_RDONLY 0x11 */ + /* O_RDWR|TRUNC|O_DENYNONE 0x3 */ + /* 0x10 BINAERMODUS ?? */ + /* 0x02 do write */ + uint8 len; /* namelaenge */ + uint8 data[2]; /* Name */ + } *input = (struct INPUT *)ncprequest; + struct OUTPUT { + uint8 fhandle[4]; /* Dateihandle */ + uint8 ext_fhandle[2]; /* z.B 0x0 0x0 */ + uint8 reserve2[2]; /* z.B 0x0 0x0 */ + NW_FILE_INFO fileinfo; + } *xdata= (struct OUTPUT*)responsedata; + int fhandle=nw_creat_open_file((int)input->dirhandle, + input->data, input->len, + &(xdata->fileinfo), + (int)input->attrib, + (int)input->access, 0); + + if (fhandle > -1){ + U32_TO_BE32(fhandle, xdata->fhandle); + U16_TO_BE16(0, xdata->ext_fhandle); + U16_TO_BE16(0, xdata->reserve2); + + data_len = sizeof(struct OUTPUT); +#ifdef TEST_FNAME + input->data[input->len] = '\0'; + if (strstr(input->data, TEST_FNAME)){ + test_handle = fhandle; + do_druck++; + } +#endif + + } else completition = (uint8) (-fhandle); + } + break; + +#if 0 + case 0x57 : /* some new calls */ + { + uint8 ufunc = *(requestdata); + completition = 0xfb; /* erstmal */ + if (ufunc == 0x02) { /* Initialize Search */ + uint8 namespace=*(requestdata+1); + uint8 reserved=*(requestdata+2); + /* NW PATH STRUC */ + } else if (ufunc == 0x07) { /* Modify File or Dir Info */ + uint8 namespace=*(requestdata+1); + } else if (ufunc == 0x09) { /* Set short Dir Handle*/ + uint8 namespace=*(requestdata+1); + uint8 datastream=*(requestdata+2); + uint8 desthandle=*(requestdata+3); + /* 1 Byte Reserved */ + /* NWPATH STRUC */ + } else if (ufunc == 0x15) { /* Get Path String from short dir neu*/ + uint8 namespace=*(requestdata+1); + uint8 short_dir_handle=*(requestdata+2); + } else if (ufunc == 0x16) { + /* Generate Dir BASE and VolNumber */ + uint8 namespace = *(requestdata+1); + uint8 *nwpathstruct = requestdata+4; + struct OUTPUT { + uint8 ns_dir_base[4]; /* BASEHANDLE */ + uint8 dos_dir_base[4]; /* BASEHANDLE */ + uint8 volume; /* Volumenumber*/ + } *xdata= (struct OUTPUT*)responsedata; + int result = nw_generate_dir_path(nwpathstruct, + xdata->ns_dir_base, xdata->dos_dir_base); + if (result >-1) { + data_len = sizeof(struct OUTPUT); + xdata->volume = result; + completition=0; + } else completition = (uint8)(-result); + } else if (ufunc == 0x0c) { /* alloc short dir Handle */ + uint8 namespace = *(requestdata+1); + int allocatemode = GET_BE16(requestdata+2); + /* NWPATH STRUC */ + } else if (ufunc == 0x1a) { /* Get Huge NS Info neu*/ + uint8 namespace=*(requestdata+1); + } else if (ufunc == 0x1c) { /* GetFullPathString neu*/ + uint8 snamespace=*(requestdata+1); + uint8 dnamespace=*(requestdata+2); + } else if (ufunc == 0x1d) { /* GetEffDirRights neu*/ + uint8 namespace=*(requestdata+1); + } + } break; +#endif + +#if 0 + case 0x61 : { /* Negotiate Buffer Size, Packetsize new ??? */ + /* same request as 0x21 */ + } +#endif + + default : completition = 0xfb; /* unknown request */ + break; + + } /* switch function */ + } else if (ncp_type == 0x1111) { + (void) nw_init_connect(); + last_sequence = -9999; + } else { + printf("WRONG TYPE 0x%x IN NWCONN\n", ncp_type); + completition = 0xfb; + } + if (completition == 0xfb || (do_druck == 1)) { /* UNKWON FUNCTION od. TYPE */ + int x_nw_debug = nw_debug; + if (!nw_debug || do_druck == 1) { + int j = requestlen; + nw_debug = 1; + DPRINTF(("NCP REQUEST: seq:%d, task:%d, reserved:0x%x, func:0x%x\n", + sequence, task, reserved, function)); + if (j > 0){ + uint8 *p=requestdata; + DPRINTF(("len %d, DATA:", j)); + while (j--) { + int c = *p++; + if (c > 32 && c < 127) DPRINTF((",\'%c\'", (char) c)); + else DPRINTF((",0x%x", c)); + } + DPRINTF(("\n")); + } + } + if (completition == 0xfb) + DPRINTF(("UNKNOWN FUNCTION od. TYPE: 0x%x\n", function)); + else if (data_len){ + int j = data_len; + uint8 *p = responsedata; + DPRINTF(("RSPONSE: len %d, DATA:", data_len)); + while (j--) { + int c = *p++; + if (c > 32 && c < 127) DPRINTF((",\'%c\'", (char) c)); + else DPRINTF((",0x%x", c)); + } + DPRINTF(("\n")); + } + nw_debug = x_nw_debug; + } + + ncp_response(sequence, completition, data_len); + if (nw_debug != 99 && nw_debug != -99) nw_debug = org_nw_debug; + else if (nw_debug == -99) nw_debug = 0; +} + +static int fl_get_debug=0; +static void get_new_debug(void) +{ + get_ini_debug(3); + fl_get_debug=0; +} + +static void sig_hup(int rsig) +{ + signal(SIGHUP, SIG_IGN); + fl_get_debug++; + signal(SIGHUP, sig_hup); +} + +extern int t_errno; +int main(int argc, char **argv) +{ + int completition = 0; + if (argc != 8) { + printf("usage nwconn PID FROM_ADDR Connection UID GID Debug1 Debugipx\n"); + exit(1); + } else father_pid = atoi(*(argv+1)); + + DPRINTF(("FATHER PID=%d, ADDR=%s CON:%s\n", father_pid, *(argv+2), *(argv+3))); + adr_to_ipx_addr(&from_addr, *(argv+2)); + + default_gid = atoi(*(argv+4)); + default_uid = atoi(*(argv+5)); + nw_debug = atoi(*(argv+6)); + ipxdebug = atoi(*(argv+7)); + +#ifdef LINUX + set_emu_tli(ipxdebug); +#endif + if (nw_init_connect()) exit(1); + + last_sequence = -9999; + if (open_ipx_socket()) exit(1); + + set_default_guid(); + + ud.opt.len = sizeof(uint8); + ud.opt.maxlen = sizeof(uint8); + ud.opt.buf = (char*)&ipx_pack_typ; + + ud.addr.len = sizeof(ipxAddr_t); + ud.addr.maxlen = sizeof(ipxAddr_t); + ud.addr.buf = (char*)&from_addr; + ud.udata.buf = (char*)&ipxdata; + U16_TO_BE16(0x3333, ncpresponse->type); + ncpresponse->task = (uint8) 1; /* allways 1 */ + ncpresponse->reserved = (uint8) 0; /* allways 0 */ + ncpresponse->connection = (uint8) atoi(*(argv+3)); + + signal(SIGHUP, sig_hup); + + while (1) { + int data_len = read(0, readbuff, sizeof(readbuff)); + ncpresponse->connect_status = (uint8) 0; + if (data_len > 0) { + if (fl_get_debug) get_new_debug(); + XDPRINTF((99, "NWCONN GOT DATA len = %d\n",data_len)); + + if ((ncp_type = (int)GET_BE16(ncprequest->type)) == 0x3333) { + /* OK for direct sending */ + data_len -= sizeof(NCPRESPONSE); + XDPRINTF((99, "NWCONN:direct sending:type 0x3333, completition=0x%x, len=%d\n", + (int)(ncprequest->function), data_len)); + if (data_len) memcpy(responsedata, readbuff+sizeof(NCPRESPONSE), data_len); + ncpresponse->connect_status = ((NCPRESPONSE*)readbuff)->connect_status; + ncp_response((int)(ncprequest->sequence), (int)(ncprequest->function), data_len); + } else { /* this calls I must handle */ + requestlen = data_len - sizeof(NCPREQUEST); + handle_ncp_serv(); + } + + } else if (data_len < 0) { + if (fl_get_debug) get_new_debug(); + else break; + } + } + close(0); + + if (ipx_fd > -1){ + while ((completition = t_unbind(ipx_fd)) < 0) { + if (t_errno != TOUTSTATE) break; + } + t_close(ipx_fd); + } + return(0); +} diff --git a/nwdbm.c b/nwdbm.c new file mode 100644 index 0000000..5096f27 --- /dev/null +++ b/nwdbm.c @@ -0,0 +1,1161 @@ +/* nwdbm.c 22-Nov-95 data base for mars_nwe */ +/* (C)opyright (C) 1993,1995 Martin Stover, Marburg, Germany + * + * 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 code is only called from the process 'ncpserv' + * So, there is no need for locking or something else. + */ + +#include "net.h" +#include "nwdbm.h" +#ifdef LINUX +# include +#else +# include +#endif + +static char *fnprop = "nwprop"; +static char *fnval = "nwval"; +static char *fnobj = "nwobj"; + +static datum key; +static datum data; +static DBM *my_dbm=NULL; + +static int dbminit(char *s) +{ + char buff[256]; + sprintf(buff, "%s/%s", PATHNAME_BINDERY, s); + my_dbm = dbm_open(buff, O_RDWR|O_CREAT, 0666); + return( (my_dbm == NULL) ? -1 : 0); +} + +static int dbmclose() +{ + if (my_dbm != NULL) { + dbm_close(my_dbm); + my_dbm = NULL; + } + return(0); +} + +#define firstkey() dbm_firstkey(my_dbm) +#define nextkey(key) dbm_nextkey(my_dbm) +#define delete(key) dbm_delete(my_dbm, key) +#define fetch(key) dbm_fetch(my_dbm, key) +#define store(key, content) dbm_store(my_dbm, key, content, DBM_REPLACE) + + +static int name_match(uint8 *s, uint8 *p) +{ + uint8 pc; + while ( (pc = *p++) != 0){ + switch (pc) { + + case '?' : if (!*s++) return(0); /* simple char */ + break; + + case '*' : if (!*p) return(1); /* last star */ + while (*s) { + if (name_match(s, p) == 1) return(1); + ++s; + } + return(0); + + default : if (pc != *s++) return(0); /* normal char */ + break; + } /* switch */ + } /* while */ + return ( (*s) ? 0 : 1); +} + +int find_obj_id(NETOBJ *o, uint32 last_obj_id) +{ + int result = -0xfc; /* no Object */ + DPRINTF(("findobj_id OBJ=%s, type=0x%x, lastid=0x%lx \n", + o->name, (int)o->type, last_obj_id)); + + if (!dbminit(fnobj)){ + + key = firstkey(); + if (last_obj_id && (last_obj_id != MAX_U32)){ + int flag = 0; + while (key.dptr != NULL && !flag) { + if ( ((NETOBJ*)(key.dptr))->id == last_obj_id) flag++; + key = nextkey(key); + } + } + + while (key.dptr != NULL && result) { + data = fetch(key); + if (data.dptr != NULL){ + NETOBJ *obj = (NETOBJ*)data.dptr; + if ( ( ((int)obj->type == (int)o->type) || o->type == MAX_U16) && + name_match(obj->name, o->name)) { + DPRINTF(("found OBJ=%s, id=0x%lx\n", obj->name, obj->id)); + result = 0; + memcpy((char *)o, (char*)obj, sizeof(NETOBJ)); + } else { + XDPRINTF((3,"not found,but NAME=%s, type=0x%x, id=0x%lx \n", + obj->name, (int)obj->type, obj->id)); + } + } + if (result) key = nextkey(key); + } /* while */ + + } else result = -0xff; + dbmclose(); + return(result); +} + +static int loc_delete_property(uint32 obj_id, uint8 *prop_name, uint8 prop_id) +/* deletes Object property or properties */ +/* wildcards allowed in property name */ +{ + uint8 xset[256]; + int result = -0xfb; /* no property */ + memset(xset, 0, sizeof(xset)); + if (!prop_id) { + DPRINTF(("loc_delete_property obj_id=%d, prop=%s\n", obj_id, prop_name)); + if (!dbminit(fnprop)){ + for (key = firstkey(); key.dptr != NULL; key = nextkey(key)) { + NETPROP *p=(NETPROP*)key.dptr; + if (p->obj_id == obj_id) { + data = fetch(key); + p = (NETPROP*)data.dptr; + if (p != NULL && name_match(p->name, prop_name)){ + DPRINTF(("found prop: %s, id=%d for deleting\n", p->name, (int)p->id)); + if ((int)(p->id) > result) result = (int)(p->id); + xset[p->id]++; + } + } + } /* for */ + } else result = -0xff; + dbmclose(); + } else { + DPRINTF(("loc_delete_property obj_id=%d, prop_id=%d\n", obj_id, (int)prop_id)); + xset[prop_id]++; + result = prop_id; + } + if (result > 0) { + if (!dbminit(fnval)){ + int k; + NETVAL val; + key.dptr = (char*)&val; + key.dsize = NETVAL_KEY_SIZE; + val.obj_id = obj_id; + for (k = 1; k <= result; k++){ + if (xset[k]){ + int l = 0; + val.prop_id = (uint8)k; + while (l++ < 255) { + val.segment = (uint8)l; + if (delete(key)) break; + } + } + } /* for */ + } else result=-0xff; + dbmclose(); + if (result > 0) { + if (!dbminit(fnprop)){ /* now delete properties */ + int k; + NETPROP prop; + key.dptr = (char*)∝ + key.dsize = NETPROP_KEY_SIZE; + prop.obj_id = obj_id; + for (k = (prop_id) ? prop_id : 1; k <= result; k++){ + if (xset[k]){ + prop.id = (uint8)k; + if (delete(key)) { + result = -0xf6; + break; + } + } + } /* for */ + if (result > 0) result=0; + } else result=-0xff; + dbmclose(); + } + } + return(result); +} + +static int loc_delete_obj(uint32 objid) +{ + int result=0; + (void)loc_delete_property(objid, (uint8*)"*", 0); + if (!dbminit(fnobj)){ + key.dptr = (char*)&objid; + key.dsize = NETOBJ_KEY_SIZE; + if (delete(key)) result = -0xff; + } else result = -0xff; + dbmclose(); + return(result); +} + +int nw_delete_obj(NETOBJ *obj) +{ + int result = find_obj_id(obj, 0); + DPRINTF(("nw_delete_obj obj_id=%d, obj_name=%s\n", obj->id, obj->name)); + if (!result) result=loc_delete_obj(obj->id); + return(result); +} + +int nw_rename_obj(NETOBJ *o, uint8 *newname) +/* rename object */ +{ + int result = find_obj_id(o, 0); + if (!result) { + result = -0xff; + if (!dbminit(fnobj)){ + key.dsize = NETOBJ_KEY_SIZE; + key.dptr = (char*)o; + data = fetch(key); + if (data.dptr != NULL){ + NETOBJ *obj=(NETOBJ*)data.dptr; + DPRINTF(("rename_obj:got OBJ name=%s, id = 0x%x,\n", obj->name, (int)obj->id)); + strncpy(obj->name, newname, 48); + if (!store(key, data)) result=0; + } + } + dbmclose(); + } + return(result); +} + +int nw_change_obj_security(NETOBJ *o, int newsecurity) +/* change Security of Object */ +{ + int result = find_obj_id(o, 0); + if (!result) { + result = -0xff; + if (!dbminit(fnobj)){ + key.dsize = NETOBJ_KEY_SIZE; + key.dptr = (char*)o; + data = fetch(key); + if (data.dptr != NULL){ + NETOBJ *obj=(NETOBJ*)data.dptr; + DPRINTF(("change_obj_security:got OBJ name=%s, id = 0x%x,\n", obj->name, (int)obj->id)); + obj->security = (uint8) newsecurity; + if (!store(key, data)) result=0; + } + } + dbmclose(); + } + return(result); +} + +int nw_get_obj(NETOBJ *o) +{ + int result = -0xfc; /* no Object */ + DPRINTF(("nw_get_obj von OBJ id = 0x%x,\n", (int)o->id)); + if (!dbminit(fnobj)){ + key.dsize = NETOBJ_KEY_SIZE; + key.dptr = (char*)o; + data = fetch(key); + if (data.dptr != NULL){ + NETOBJ *obj=(NETOBJ*)data.dptr; + DPRINTF(("got OBJ name=%s, id = 0x%x,\n", obj->name, (int)obj->id)); + memcpy(o, data.dptr, sizeof(NETOBJ)); + result = 0; + } + } else result = -0xff; + dbmclose(); + return(result); +} + +static int find_prop_id(NETPROP *p, uint32 obj_id, int last_prop_id) +{ + int result = -0xfb; /* no Property */ + DPRINTF(("find Prop id von name=0x%x:%s, lastid=%d\n", + obj_id, p->name, last_prop_id)); + if (!dbminit(fnprop)){ + int flag = (last_prop_id) ? 0 : 1; + for (key = firstkey(); key.dptr != NULL; key = nextkey(key)) { + NETPROP *prop=(NETPROP*)key.dptr; + if (prop->obj_id == obj_id) { + if (!flag) flag = (last_prop_id == prop->id); + else { + data = fetch(key); + prop = (NETPROP*)data.dptr; + if (data.dptr != NULL && name_match(prop->name, p->name) ) { + DPRINTF(("found PROP %s, id=0x%x\n", prop->name, (int) prop->id)); + result = 0; + memcpy(p, prop, sizeof(NETPROP)); + break; + } + } + } + } + } else result = -0xff; + dbmclose(); + return(result); +} + +#define find_first_prop_id(p, obj_id) \ + find_prop_id((p), (obj_id), 0) + + +static int loc_change_prop_security(NETPROP *p, uint32 obj_id) +{ + int result = -0xfb; /* no Property */ + DPRINTF(("loc_change_prop_security Prop id von name=0x%x:%s\n", obj_id, p->name)); + if (!dbminit(fnprop)){ + for (key = firstkey(); key.dptr != NULL; key = nextkey(key)) { + NETPROP *prop=(NETPROP*)key.dptr; + if (prop->obj_id == obj_id) { + data = fetch(key); + prop = (NETPROP*)data.dptr; + if (data.dptr != NULL && name_match(prop->name, p->name) ) { + uint8 security = p->security; + DPRINTF(("found PROP %s, id=0x%x\n", prop->name, (int) prop->id)); + result = 0; + memcpy(p, prop, sizeof(NETPROP)); + p->security = security; + data.dptr = (char*)p; + data.dsize = sizeof(NETPROP); + key.dptr = (char *)p; + key.dsize = NETPROP_KEY_SIZE; + if (store(key, data)) result=-0xff; + break; + } + } + } + } else result = -0xff; + dbmclose(); + return(result); +} + + +static int loc_get_prop_val(uint32 obj_id, int prop_id, int segment, + uint8 *property_value, uint8 *more_segments) +{ + int result = -0xec; /* no such Segment */ + NETVAL val; + if (!dbminit(fnval)){ + key.dsize = NETVAL_KEY_SIZE; + key.dptr = (char*)&val; + val.obj_id = obj_id; + val.prop_id = (uint8)prop_id; + val.segment = (uint8)segment; + data = fetch(key); + if (data.dptr != NULL){ + NETVAL *v = (NETVAL*)data.dptr; + if (NULL != property_value) memcpy(property_value, v->value, 128); + DPRINTF(("found VAL 0x%x, %d, %d\n", obj_id, prop_id, segment)); + result = 0; + val.segment++; + data = fetch(key); + if (NULL != more_segments) + *more_segments = (data.dptr != NULL) ? 0xff : 0; + } + } else result = -0xff; + dbmclose(); + return(result); +} + + +int prop_find_member(uint32 obj_id, int prop_id, uint32 member_id) +{ + int result = -0xea; /* no such member */ + NETVAL val; + if (!dbminit(fnval)){ + key.dsize = NETVAL_KEY_SIZE; + key.dptr = (char*)&val; + val.obj_id = obj_id; + val.prop_id = (uint8)prop_id; + val.segment = (uint8)1; + data = fetch(key); + if (data.dptr != NULL){ + NETVAL *v = (NETVAL*)data.dptr; + uint8 *p=v->value; + int k=0; + DPRINTF(("found VAL 0x%x, %d\n", obj_id, prop_id)); + while (k++ < 32){ + uint32 id = GET_BE32(p); + if (id == member_id) { + result = 0; + break; + } else p += 4; + } + } + } else result = -0xff; + dbmclose(); + return(result); +} + +int prop_add_member(uint32 obj_id, int prop_id, uint32 member_id) +{ + int result = 0; /* OK */ + NETVAL val; + if (!dbminit(fnval)){ + key.dsize = NETVAL_KEY_SIZE; + key.dptr = (char*)&val; + val.obj_id = obj_id; + val.prop_id = (uint8)prop_id; + val.segment = (uint8)0; + while (!result) { + val.segment++; + data = fetch(key); + if (data.dptr != NULL){ + NETVAL *v = (NETVAL*)data.dptr; + uint8 *p = v->value; + int k = 0; + while (k++ < 32){ + uint32 null_id = 0; + if (!memcmp(p, (char*)&null_id, 4)) { + U32_TO_BE32(member_id, p); + memcpy(&val, v, sizeof(NETVAL)); + data.dptr = (char*)&val; + key.dptr = (char*)&val; + if (store(key, data)) result=-0xff; + goto L1; + } else p += 4; + } + } else { + memset(val.value, 0, 128); + U32_TO_BE32(member_id, val.value); + data.dptr = (char*)&val; + data.dsize = sizeof(NETVAL); + if (store(key, data)) result=-0xff; + goto L1; + } + } /* while */ + } else result = -0xff; +L1: + dbmclose(); + return(result); +} + +int prop_delete_member(uint32 obj_id, int prop_id, uint32 member_id) +{ + int result = -0xea; /* no such member */ + NETVAL val; + if (!dbminit(fnval)){ + key.dsize = NETVAL_KEY_SIZE; + key.dptr = (char*)&val; + val.obj_id = obj_id; + val.prop_id = (uint8)prop_id; + val.segment = (uint8)0; + data = fetch(key); + while (result) { + val.segment++; + data = fetch(key); + if (data.dptr != NULL) { + NETVAL *v = (NETVAL*)data.dptr; + uint8 *p = v->value; + int k = 0; + while (k++ < 32){ + if (GET_BE32(p) == member_id) { + memset(p, 0, 4); + memcpy(&val, v, sizeof(NETVAL)); + data.dptr = (char*)&val; + if (store(key, data)) result=-0xff; + else result=0; + goto L1; + } else p += 4; + } + } else break; + } + } else result = -0xff; +L1: + dbmclose(); + return(result); +} + +int ins_prop_val(uint32 obj_id, uint8 prop_id, int segment, + uint8 *property_value, int erase_segments) +{ + int result = -0xec; /* no such Segment */ + if (!dbminit(fnval)){ + NETVAL val; + int flag = 1; + key.dsize = NETVAL_KEY_SIZE; + key.dptr = (char*)&val; + val.obj_id = obj_id; + val.prop_id = (uint8)prop_id; + if (segment > 1) { + val.segment = segment-1; + data = fetch(key); + if (data.dptr == NULL) flag = 0; + } + if (flag){ + val.segment = segment; + memcpy(val.value, property_value, 128); + data.dsize = sizeof(NETVAL); + data.dptr = (char*)&val; + if (!store(key, data)) { + result = 0; + if (erase_segments == 0xff){ + val.segment++; + while (!delete(key)) val.segment++; + } + } + } + } else result = -0xff; + dbmclose(); + return(result); +} + +int nw_get_prop_val_by_obj_id(uint32 obj_id, + int segment_nr, + uint8 *prop_name, int prop_namlen, + uint8 *property_value, + uint8 *more_segments, + uint8 *property_flags) +{ + NETPROP prop; + int result=-0xff; + strmaxcpy((char*)prop.name, (char*)prop_name, prop_namlen); + DPRINTF(("nw_get_prop_val_by_obj_id,id=0x%x, prop=%s, segment=%d\n", + obj_id, prop.name, segment_nr)); + + if ((result=find_first_prop_id(&prop, obj_id))==0){ + if ((result=loc_get_prop_val(obj_id, prop.id, segment_nr, + property_value, more_segments)) == 0){ + *property_flags = prop.flags; + } + } + return(result); +} + +int nw_get_prop_val(int object_type, + uint8 *object_name, int object_namlen, + int segment_nr, + uint8 *prop_name, int prop_namlen, + uint8 *property_value, + uint8 *more_segments, + uint8 *property_flags) +{ + NETOBJ obj; + int result=-0xff; + strmaxcpy((char*)obj.name, (char*)object_name, object_namlen); + obj.type = (uint16) object_type; + if ((result = find_obj_id(&obj, 0)) == 0){ + result = nw_get_prop_val_by_obj_id(obj.id, + segment_nr, + prop_name, prop_namlen, + property_value, + more_segments, + property_flags); + } + return(result); +} + +int nw_delete_property(int object_type, + uint8 *object_name, int object_namlen, + uint8 *prop_name, int prop_namlen) +{ + NETOBJ obj; + uint8 prop_name_x[20]; + int result=-0xff; + strmaxcpy((char*)obj.name, (char*)object_name, object_namlen); + strmaxcpy((char*)prop_name_x, (char*)prop_name, prop_namlen); + DPRINTF(("nw_delete_property obj=%s, prop=%s, type=0x%x\n", + obj.name, prop_name_x, object_type)); + obj.type = (uint16) object_type; + if ((result = find_obj_id(&obj, 0)) == 0){ + result = loc_delete_property(obj.id, prop_name_x, 0); + } + return(result); +} + +int nw_is_obj_in_set(int object_type, + uint8 *object_name, int object_namlen, + uint8 *prop_name, int prop_namlen, + int member_type, + uint8 *member_name, int member_namlen) +{ + NETOBJ obj; + NETOBJ mobj; + NETPROP prop; + int result=-0xff; + strmaxcpy((char*)obj.name, (char*)object_name, object_namlen); + strmaxcpy((char*)mobj.name, (char*)member_name, member_namlen); + strmaxcpy((char*)prop.name, (char*)prop_name, prop_namlen); + DPRINTF(("nw_is_obj_in_set obj=%s,0x%x, member=%s,0x%x, prop=%s\n", + obj.name, object_type, mobj.name, member_type, prop.name)); + obj.type = (uint16) object_type; + mobj.type = (uint16) member_type; + if ((result = find_obj_id(&obj, 0)) == 0){ + result=find_first_prop_id(&prop, obj.id); + if (!result) + result = find_obj_id(&mobj, 0); + if (!result) + result = prop_find_member(obj.id, (int)prop.id, mobj.id); + } + return(result); +} + +int nw_add_obj_to_set(int object_type, + uint8 *object_name, int object_namlen, + uint8 *prop_name, int prop_namlen, + int member_type, + uint8 *member_name, int member_namlen) +{ + NETOBJ obj; + NETOBJ mobj; + NETPROP prop; + int result=-0xff; + strmaxcpy((char*)obj.name, (char*)object_name, object_namlen); + strmaxcpy((char*)mobj.name, (char*)member_name, member_namlen); + strmaxcpy((char*)prop.name, (char*)prop_name, prop_namlen); + DPRINTF(("nw_add_obj_to_set obj=%s,0x%x, member=%s,0x%x, prop=%s\n", + obj.name, object_type, mobj.name, member_type, prop.name)); + obj.type = (uint16) object_type; + mobj.type = (uint16) member_type; + if ((result = find_obj_id(&obj, 0)) == 0){ + result=find_first_prop_id(&prop, obj.id); + if (!result) + result = find_obj_id(&mobj, 0); + if (!result) + result = prop_add_member(obj.id, (int)prop.id, mobj.id); + } + return(result); +} + +int nw_delete_obj_from_set(int object_type, + uint8 *object_name, int object_namlen, + uint8 *prop_name, int prop_namlen, + int member_type, + uint8 *member_name, int member_namlen) +{ + NETOBJ obj; + NETOBJ mobj; + NETPROP prop; + int result=-0xff; + strmaxcpy((char*)obj.name, (char*)object_name, object_namlen); + strmaxcpy((char*)mobj.name, (char*)member_name, member_namlen); + strmaxcpy((char*)prop.name, (char*)prop_name, prop_namlen); + DPRINTF(("nw_delete_obj_from_set obj=%s,0x%x, member=%s,0x%x, prop=%s\n", + obj.name, object_type, mobj.name, member_type, prop.name)); + obj.type = (uint16) object_type; + mobj.type = (uint16) member_type; + if ((result = find_obj_id(&obj, 0)) == 0){ + result=find_first_prop_id(&prop, obj.id); + if (!result) + result = find_obj_id(&mobj, 0); + if (!result) + result = prop_delete_member(obj.id, (int)prop.id, mobj.id); + } + return(result); +} + + +int nw_write_prop_value(int object_type, + uint8 *object_name, int object_namlen, + int segment_nr, int erase_segments, + uint8 *prop_name, int prop_namlen, + uint8 *property_value) +{ + NETOBJ obj; + NETPROP prop; + int result=-0xff; + strmaxcpy((char*)obj.name, (char*)object_name, object_namlen); + strmaxcpy((char*)prop.name, (char*)prop_name, prop_namlen); + DPRINTF(("nw_write_prop_value obj=%s, prop=%s, type=0x%x, segment=%d\n", + obj.name, prop.name, object_type, segment_nr)); + obj.type = (uint16) object_type; + + if ((result = find_obj_id(&obj, 0)) == 0){ + if ((result=find_first_prop_id(&prop, obj.id))==0){ + result=ins_prop_val(obj.id, prop.id, segment_nr, + property_value, erase_segments); + + } + } + return(result); +} + + +int nw_change_prop_security(int object_type, + uint8 *object_name, int object_namlen, + uint8 *prop_name, int prop_namlen, + int prop_security) +{ + NETOBJ obj; + NETPROP prop; + int result=-0xff; + strmaxcpy((char*)obj.name, (char*)object_name, object_namlen); + strmaxcpy((char*)prop.name, (char*)prop_name, prop_namlen); + prop.security = (uint8)prop_security; + DPRINTF(("nw_change_prop_security obj=%s,0x%x, prop=%s\n", + obj.name, object_type, prop.name)); + obj.type = (uint16) object_type; + if ((result = find_obj_id(&obj, 0)) == 0){ + result=loc_change_prop_security(&prop, obj.id); + } + return(result); +} + +int nw_scan_property(NETPROP *prop, + int object_type, + uint8 *object_name, + int object_namlen, + uint8 *prop_name, + int prop_namlen, + uint32 *last_scan) +{ + NETOBJ obj; + int result; + strmaxcpy((char*)obj.name, (char*)object_name, object_namlen); + strmaxcpy((char*)prop->name, (char*)prop_name, prop_namlen); + DPRINTF(("nw_scan_property obj=%s, prop=%s, type=0x%x, last_scan=0x%lx\n", + obj.name, prop->name, object_type, *last_scan)); + obj.type = (uint16) object_type; + + if ((result = find_obj_id(&obj, 0)) == 0){ + int last_prop_id; + if (*last_scan == MAX_U32) *last_scan = 0; + last_prop_id = *last_scan; + if ((result=find_prop_id(prop, obj.id, last_prop_id))==0){ + *last_scan = prop->id; + if (!loc_get_prop_val(obj.id, prop->id, 1, + NULL, NULL)) + result = 0xff; /* Has prop Values */ + } + } + return(result); +} + +int nw_get_prop_val_str(uint32 q_id, char *propname, uint8 *buff) +/* for simple prop val strings */ +{ + uint8 more_segments; + uint8 property_flags; + int result=nw_get_prop_val_by_obj_id(q_id, 1, propname, strlen(propname), + buff, &more_segments, &property_flags); + if (result > -1) { + result=strlen(buff); + DPRINTF(("nw_get_prop_val_str:%s len=%d, name=`%s`\n", propname, result, buff)); + } else + DPRINTF(("nw_get_prop_val_str:%s, result=0x%x\n", propname, result)); + return(result); +} + +int nw_create_obj(NETOBJ *obj, uint32 wanted_id) +/* + * Routine creates object + * wants OBJ name and OBJ-Type, returns obj.id. + * if wanted_id > 0 and object don't exist then + * wanted_id should be taken as obj_id. +*/ +{ + int result = 0; /* OK */ + DPRINTF(("creat OBJ=%s,type=0x%x\n", obj->name, (int)obj->type)); + if (!dbminit(fnobj)){ + for (key = firstkey(); key.dptr != NULL; key = nextkey(key)) { + data = fetch(key); + if (data.dptr){ + NETOBJ *o=(NETOBJ*)data.dptr; + if (o->type == obj->type && !strcmp(o->name, obj->name)){ + obj->id = o->id; /* fill ID */ + result = -0xee; /* already exist */ + break; + } + } + } + if (!result){ + obj->id = (wanted_id) ? wanted_id -1 : 0; + key.dsize = NETOBJ_KEY_SIZE; + key.dptr = (char*)obj; + while(1) { + obj->id++; + data = fetch(key); + if (data.dptr == NULL) break; + } + data.dsize = sizeof(NETOBJ); + data.dptr = (char*)obj; + if (store(key, data)) result = -0xff; + } + } else result = -0xff; + dbmclose(); + return(result); +} + +int nw_obj_has_prop(NETOBJ *obj) +{ + int result = (dbminit(fnprop)) ? -0xff : 0; + if (!result){ + for (key = firstkey(); key.dptr != NULL; key = nextkey(key)) { + NETPROP *p=(NETPROP*)key.dptr; + if (p->obj_id == obj->id) { + result = 1; + break; + } + } + } + dbmclose(); + return(result); +} + + +int nw_create_obj_prop(NETOBJ *obj, NETPROP *prop) +{ + int result=0; + if (!dbminit(fnprop)){ + uint8 founds[256]; + memset((char*)founds, 0, sizeof(founds) ); + for (key = firstkey(); key.dptr != NULL; key = nextkey(key)) { + NETPROP *p=(NETPROP*)key.dptr; + if (p->obj_id == obj->id) { + data = fetch(key); + p = (NETPROP*)data.dptr; + if (data.dptr != NULL && !strcmp(prop->name, p->name)){ + prop->id = p->id; + prop->obj_id = obj->id; + result = -0xed; /* Property exists */ + break; + } else founds[p->id]++; + } + } + if (!result){ + int k = 0; + while (++k < sizeof(founds) ) { + if (!founds[k]) break; /* free slot */ + } + key.dsize = NETPROP_KEY_SIZE; + key.dptr = (char *)prop; + data.dsize = sizeof(NETPROP); + data.dptr = (char *)prop; + prop->obj_id = obj->id; + prop->id = (uint8)k; + if (store(key, data)) result = -0xff; + } + } else result = -0xff; + dbmclose(); + return(result); +} + + +int nw_create_prop(int object_type, + uint8 *object_name, int object_namlen, + uint8 *prop_name, int prop_namlen, + int prop_flags, int prop_security) +/* creats property for an object */ +{ + NETOBJ obj; + NETPROP prop; + int result=-0xff; + strmaxcpy((char*)obj.name, (char*)object_name, object_namlen); + strmaxcpy((char*)prop.name, (char*)prop_name, prop_namlen); + DPRINTF(("nw_create_prop obj=%s, prop=%s, type=0x%x\n", + obj.name, prop.name, object_type)); + obj.type = (uint16) object_type; + if ((result = find_obj_id(&obj, 0)) == 0){ + prop.flags = (uint8)prop_flags; + prop.security = (uint8)prop_security; + result = nw_create_obj_prop(&obj, &prop); + } + return(result); +} + +uint32 nw_new_create_prop(uint32 wanted_id, + char *objname, int objtype, int objflags, int objsecurity, + char *propname, int propflags, int propsecurity, + char *value, int valuesize) +/* + * creats new property value, if needed creats Object + * and the property, if valuesize == 0, then only obj or property + * will be created, returns obj-id + */ +{ + NETOBJ obj; + NETPROP prop; + if (objname && *objname){ + strmaxcpy(obj.name, objname, sizeof(obj.name)); + obj.type = (uint8)objtype; + obj.flags = (uint8)objflags; + obj.security = (uint8)objsecurity; + obj.id = 0; /* Erstmal */ + nw_create_obj(&obj, wanted_id); + } else obj.id = wanted_id; + strmaxcpy(prop.name, propname, sizeof(prop.name)); + prop.flags = (uint8)propflags; + prop.security = (uint8)propsecurity; + nw_create_obj_prop(&obj, &prop); + if (valuesize){ + uint8 locvalue[128]; + memset(locvalue, 0, sizeof(locvalue)); + memcpy(locvalue, value, min(sizeof(locvalue), valuesize)); + ins_prop_val(obj.id, prop.id, 1, locvalue, 0xff); + } + return(obj.id); +} + +static void create_nw_db(char *fn, int allways) +{ + char fname[200]; + struct stat stbuff; + sprintf(fname, "%s/%s.dir", PATHNAME_BINDERY, fn); + if (allways || stat(fname, &stbuff)){ + int fd = open(fname, O_CREAT | O_TRUNC | O_RDWR, 0666); + if (fd > -1) close(fd); + } + sprintf(fname, "%s/%s.pag", PATHNAME_BINDERY, fn); + if (allways || stat(fname, &stbuff)){ + int fd = open(fname, O_CREAT | O_TRUNC | O_RDWR, 0666); + if (fd > -1) close(fd); + } +} + +static void add_pr_queue(uint32 q_id, + char *q_name, char *q_directory, + char *q_command, + uint32 su_id, uint32 ge_id) +{ + uint8 buff[12]; + DPRINTF(("ADD Q=%s, V=%s, C=%s\n", q_name, q_directory, q_command)); + U32_TO_BE32(su_id, buff); + q_id = + nw_new_create_prop(q_id, q_name, 0x3, O_FL_DYNA, 0x31, + "Q_OPERATORS", P_FL_SET, 0x31, + (char*)buff, 4); + + nw_new_create_prop(q_id ,NULL, 0 , 0 , 0 , + "Q_DIRECTORY", P_FL_ITEM, 0x33, + q_directory, strlen(q_directory)); + + /* this is a own property to handler the print job !!! */ + nw_new_create_prop(q_id ,NULL, 0 , 0 , 0 , + "Q_UNIX_PRINT", P_FL_ITEM| P_FL_DYNA, 0x33, + q_command, strlen(q_command)); + + U32_TO_BE32(ge_id, buff); + nw_new_create_prop(q_id , NULL, 0 , 0 , 0 , + "Q_USERS", P_FL_SET, 0x31, + (char*)buff, 4); + +#if 0 + nw_new_create_prop(q_id , NULL, 0 , 0 , 0 , + "Q_SERVERS", P_FL_SET, 0x31, + NULL, 0); +#endif + + +} + +static void nw_fill_standard(char *servername, ipxAddr_t *adr) +/* fills the Standardproperties */ +{ + char serverna[50]; + uint8 buff[12]; + uint32 su_id = 0x00000001; + uint32 ge_id = 0x01000001; + uint32 guest_id = 0x02000001; + uint32 serv_id = 0x03000001; + uint32 nbo_id = 0x0B000001; + uint32 ngr_id = 0x0C000001; + uint32 ps1_id = 0x0D000001; + uint32 q1_id = 0x0E000001; + struct { + uint8 account_exp_date[3]; + uint8 account_disable_flag; + uint8 password_exp_date[3]; + uint8 grace_logins_remain; + uint8 password_exp_internal[2]; + uint8 grace_login_reset; + uint8 minimum_password; + uint8 max_connections[2]; + uint8 login_time_map[42]; + uint8 last_log_time[6]; + uint8 restriction_flags; + uint8 reserved; + uint8 max_disk_usage[4]; + uint8 bad_logins[2]; + uint8 next_reset_time[4]; + uint8 bad_logins_address[12]; + } login_control; + + U32_TO_BE32(ge_id, buff); + su_id = /* Typ Flags Security */ + nw_new_create_prop(su_id, "SUPERVISOR", 0x1 , 0x0, 0x33, + "GROUPS_I'M_IN", P_FL_SET, 0x31, + (char*)buff, 4); + + nw_new_create_prop(su_id, NULL, 0x1, 0, 0, + "IDENTIFICATION", P_FL_ITEM, 0x31, + "SUPERVISOR LONG", 15); + + nw_new_create_prop(su_id, NULL , 0 , 0 , 0 , + "SECURITY_EQUALS", P_FL_SET, 0x32, + (char*)buff, 4); + + memset(&login_control, 0, sizeof(login_control)); + login_control.grace_logins_remain = 0xff; + login_control.grace_login_reset = 0xff; + memset(login_control.login_time_map, 0xff, + sizeof(login_control.login_time_map)); + + login_control.max_disk_usage[0] = 0x7f; + login_control.max_disk_usage[1] = 0xff; + login_control.max_disk_usage[2] = 0xff; + login_control.max_disk_usage[3] = 0xff; + + nw_new_create_prop(su_id, NULL , 0 , 0 , 0 , + "LOGIN_CONTROL", P_FL_ITEM, 0x32, + NULL, 0); +#if 0 + (char*)&login_control, sizeof(login_control)); +#endif +#if 0 + nw_new_create_prop(su_id, NULL , 0 , 0 , 0 , + "USER_DEFAULTS", P_FL_ITEM, 0x31, + ((char*)(&login_control))+4, + sizeof(login_control) -4); +#endif + U32_TO_BE32(ge_id, buff); + guest_id = + nw_new_create_prop(guest_id, "GUEST", 0x1, 0x0, 0x31, + "GROUPS_I'M_IN", P_FL_SET, 0x31, + (char*)buff, 4); + + nw_new_create_prop(guest_id, NULL , 0, 0, 0, + "SECURITY_EQUALS", P_FL_SET, 0x32, + (char*)buff, 4); + + nbo_id = + nw_new_create_prop(nbo_id, "NOBODY", 0x1, 0x0, 0x31, + "GROUPS_I'M_IN", P_FL_SET, 0x31, + (char*)buff, 4); + + nw_new_create_prop(nbo_id, NULL , 0, 0, 0, + "SECURITY_EQUALS", P_FL_SET, 0x32, + (char*)buff, 4); + + U32_TO_BE32(su_id, buff); + U32_TO_BE32(guest_id, buff+4); + U32_TO_BE32(nbo_id, buff+8); + + ge_id = + nw_new_create_prop(ge_id, "EVERYONE", 0x2, 0x0, 0x31, + "GROUP_MEMBERS", P_FL_SET, 0x31, + (char*)buff, 12); + + ngr_id = + nw_new_create_prop(ngr_id, "NOGROUP", 0x2, 0x0, 0x31, + "GROUP_MEMBERS", P_FL_SET, 0x31, + NULL, 0); + + { + FILE *f=open_nw_ini(); + if (f){ + char buff[500]; + int what; + while (0 != (what =get_ini_entry(f, 21, (char*)buff, sizeof(buff)))) { + char name[100]; + char directory[200]; + char command[200]; + char *p=buff; + char *pp=name; + char c; + int state=0; + while (0 != (c = *p++)) { + if (c == 32 || c == '\t') { + if (!(state & 1)) { + *pp = '\0'; + state++; + } + } else { + if (state & 1){ + if (state == 1) { + pp=directory; + state++; + } else { + strcpy(command, p-1); + if (*command) state++; + break; + } + } + *pp++ = c; + } + } + *pp='\0'; + if (state == 4) { + upstr(name); + add_pr_queue(q1_id, name, directory, command, su_id, ge_id); + q1_id++; + } + } /* while */ + fclose(f); + } + } + strmaxcpy(serverna, servername, 48); + upstr(serverna); + nw_new_create_prop(serv_id, serverna, 0x4, O_FL_DYNA, 0x40, + "NET_ADDRESS", P_FL_ITEM | P_FL_DYNA, 0x40, + (char*)adr, sizeof(ipxAddr_t)); +} + +void nw_init_dbm(char *servername, ipxAddr_t *adr) +/* + * routine inits bindery + * all dynamic objects and properties will be deletet. + * and the allways needed properties will be created + * if not exist. + */ +{ + int anz=0; + uint32 objs[10000]; /* max.10000 Objekte */ + uint8 props[10000]; /* max 10000 Properties */ + + create_nw_db(fnobj, 0); + create_nw_db(fnprop, 0); + create_nw_db(fnval, 0); + + if (!dbminit(fnobj)){ + for (key = firstkey(); key.dptr != NULL; key = nextkey(key)) { + data = fetch(key); + if (data.dptr) { + NETOBJ *obj=(NETOBJ*)data.dptr; + if (obj->flags & O_FL_DYNA) /* Dynamisch */ + objs[anz++] = obj->id; + } + } + } + dbmclose(); + while (anz--) loc_delete_obj(objs[anz]); /* Now delete */ + anz = 0; + if (!dbminit(fnprop)){ + for (key = firstkey(); key.dptr != NULL; key = nextkey(key)) { + data = fetch(key); + if (data.dptr) { + NETPROP *prop=(NETPROP*)data.dptr; + if (prop->flags & P_FL_DYNA) { /* Dynamisch */ + objs[anz] = prop->obj_id; + props[anz++] = prop->id; + } + } + } + } + dbmclose(); + while (anz--) loc_delete_property(objs[anz], (char*)NULL, props[anz]); /* Nun lschen */ + nw_fill_standard(servername, adr); +} + +/* ============> this should becomes queue.c or similar < ============== */ + +int nw_get_q_dirname(uint32 q_id, uint8 *buff) +{ + return(nw_get_prop_val_str(q_id, "Q_DIRECTORY", buff)); +} + +int nw_get_q_prcommand(uint32 q_id, uint8 *buff) +{ + return(nw_get_prop_val_str(q_id, "Q_UNIX_PRINT", buff)); +} diff --git a/nwdbm.h b/nwdbm.h new file mode 100644 index 0000000..39cf183 --- /dev/null +++ b/nwdbm.h @@ -0,0 +1,170 @@ +/* nwdbm.h 11-Sep-95 */ +/* (C)opyright (C) 1993,1995 Martin Stover, Marburg, Germany + * + * 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. + */ + +#define NETOBJ_KEY_SIZE 4 + +typedef struct { + uint32 id; /* Objekt ID */ + /* --------------- */ + uint8 name[48]; + uint16 type; + uint8 flags; /* statisch, dynamisch */ + uint8 security; +} NETOBJ; + +#define NETPROP_KEY_SIZE 5 +typedef struct { + uint32 obj_id; /* ID OBJECT */ + uint8 id; /* PROPERTY id */ + /* --------------- */ + uint8 name[16]; + uint8 flags; /* statisch, dynamisch */ + uint8 security; +} NETPROP; + +#define NETVAL_KEY_SIZE 6 +typedef struct { + uint32 obj_id; /* ID OBJECT */ + uint8 prop_id; /* PROPERTY id */ + uint8 segment; /* Segment Nr */ + /* --------------- */ + uint8 value[128]; /* Inhalt */ +} NETVAL; + +/* Object Flags */ +#define O_FL_STAT 0x0 +#define O_FL_DYNA 0x1 + +/* Property Flags */ +/* BIT 7 */ +#define P_FL_STAT 0x0 +#define P_FL_DYNA 0x1 +/* BIT 6 */ +#define P_FL_ITEM 0x0 +#define P_FL_SET 0x2 + +extern int nw_get_prop(int object_type, + uint8 *object_name, int object_namlen, + int segment_nr, + uint8 *prop_name, int prop_namlen, + uint8 *property_value, + uint8 *more_segments, + uint8 *property_flags); + + + +extern int find_obj_id(NETOBJ *o, uint32 last_obj_id); + +extern int nw_delete_obj(NETOBJ *obj); +extern int nw_rename_obj(NETOBJ *o, uint8 *newname); +extern int nw_change_obj_security(NETOBJ *o, int newsecurity); +extern int nw_get_obj(NETOBJ *o); + + +extern int prop_find_member(uint32 obj_id, int prop_id, uint32 member_id); +extern int prop_add_member(uint32 obj_id, int prop_id, uint32 member_id); +extern int prop_delete_member(uint32 obj_id, int prop_id, uint32 member_id); + + + +extern int ins_prop_val(uint32 obj_id, uint8 prop_id, int segment, + uint8 *property_value, int erase_segments); + + +extern int nw_get_prop_val_by_obj_id(uint32 obj_id, + int segment_nr, + uint8 *prop_name, int prop_namlen, + uint8 *property_value, + uint8 *more_segments, + uint8 *property_flags); + +extern int nw_get_prop_val(int object_type, + uint8 *object_name, int object_namlen, + int segment_nr, + uint8 *prop_name, int prop_namlen, + uint8 *property_value, + uint8 *more_segments, + uint8 *property_flags); + +extern int nw_delete_property(int object_type, + uint8 *object_name, int object_namlen, + uint8 *prop_name, int prop_namlen); + + +extern int nw_is_obj_in_set(int object_type, + uint8 *object_name, int object_namlen, + uint8 *prop_name, int prop_namlen, + int member_type, + uint8 *member_name, int member_namlen); + + +extern int nw_add_obj_to_set(int object_type, + uint8 *object_name, int object_namlen, + uint8 *prop_name, int prop_namlen, + int member_type, + uint8 *member_name, int member_namlen); + +extern int nw_delete_obj_from_set(int object_type, + uint8 *object_name, int object_namlen, + uint8 *prop_name, int prop_namlen, + int member_type, + uint8 *member_name, int member_namlen); + + + +extern int nw_write_prop_value(int object_type, + uint8 *object_name, int object_namlen, + int segment_nr, int erase_segments, + uint8 *prop_name, int prop_namlen, + uint8 *property_value); + + +extern int nw_change_prop_security(int object_type, + uint8 *object_name, int object_namlen, + uint8 *prop_name, int prop_namlen, + int prop_security); + +extern int nw_scan_property(NETPROP *prop, + int object_type, + uint8 *object_name, + int object_namlen, + uint8 *prop_name, + int prop_namlen, + uint32 *last_scan); + +extern int nw_create_obj(NETOBJ *obj, uint32 wanted_id); + + +extern int nw_obj_has_prop(NETOBJ *obj); + + +extern int nw_create_obj_prop(NETOBJ *obj, NETPROP *prop); + +extern int nw_create_prop(int object_type, + uint8 *object_name, int object_namlen, + uint8 *prop_name, int prop_namlen, + int prop_flags, int prop_security); + + +extern uint32 nw_new_create_prop(uint32 wanted_id, + char *objname, int objtype, int objflags, int objsecurity, + char *propname, int propflags, int propsecurity, + char *value, int valuesize); + +extern void nw_init_dbm(char *servername, ipxAddr_t *adr); + diff --git a/nwserv.c b/nwserv.c new file mode 100644 index 0000000..1247ea2 --- /dev/null +++ b/nwserv.c @@ -0,0 +1,1014 @@ +/* nwserv.c 22-Nov-95 */ +/* (C)opyright (C) 1993,1995 Martin Stover, Marburg, Germany + * + * 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 "net.h" + +static int conn_gid=1; +static int conn_uid=1; + +static int ncpserv_debug=0; +static int nwconn_debug=0; + +#define MY_BROADCAST_SLOT 0 /* Server Broadcast OUT */ +#define WDOG_SLOT 1 /* Watchdog send + recv */ + +#define SAP_SLOT 2 +#define RIP_SLOT 3 +#define ROUTE_SLOT 4 +#define DIAG_SLOT 5 +#if 0 +#define ECHO_SLOT 6 +#define ERR_SLOT 7 +#endif + +uint16 ipx_sock_nummern[]={ 0, /* auto sock */ + 0, /* auto sock */ + SOCK_SAP, + SOCK_RIP, + SOCK_ROUTE, + SOCK_DIAGNOSE +#if 0 + , + SOCK_ECHO, + SOCK_ERROR, +#endif + }; + +#define NEEDED_SOCKETS (sizeof(ipx_sock_nummern) / sizeof(uint16)) +#define NEEDED_POLLS (NEEDED_SOCKETS+1) + +static uint16 sock_nummern [NEEDED_SOCKETS]; + +static int sockfd [NEEDED_SOCKETS]; + +static struct pollfd polls[NEEDED_POLLS]; + +static ipxAddr_t my_server_adr; /* Address of this server */ +static uint16 spx_diag_socket; /* SPX DIAGNOSE SOCKET */ +static ipxAddr_t nw386_adr; /* Address of NW-TEST Server */ +static int nw386_found = 0; +static int client_mode = 0; + +static uint32 network = 0x0L; +static uint32 internal_net = 0x0L; +static char my_nwname[50]; + +static int ipxdebug = 0; +static int pid_ncpserv = -1; +static int fd_ncpserv_out = -1; /* ctrl-pipe out to ncpserv */ +static int fd_ncpserv_in = -1; /* ctrl-pipe in from ncpserv */ + +#ifndef LINUX +static int frame=0; +#else +static int frame=IPX_FRAME_8023; +static char devname[40]; +#endif +static time_t akttime_stamp; + +static int bytes_to_write_to_ncpserv=0; + +static void inform_ncpserv(void) +{ + if (bytes_to_write_to_ncpserv) { + kill(pid_ncpserv, SIGHUP); /* tell ncpserv to read input */ + bytes_to_write_to_ncpserv=0; + } +} + +static void write_to_ncpserv(int what, int connection, + char *data, int data_size) +{ + switch (what) { + case 0x5555 : /* kill connection */ + bytes_to_write_to_ncpserv += + write(fd_ncpserv_out, (char*) &what, sizeof(int)); + bytes_to_write_to_ncpserv += + write(fd_ncpserv_out, (char*) &connection, sizeof(int)); + break; + + case 0x3333 : /* 'bindery' calls */ + bytes_to_write_to_ncpserv += + write(fd_ncpserv_out, (char*) &what, sizeof(int)); + bytes_to_write_to_ncpserv += + write(fd_ncpserv_out, (char*) &data_size, sizeof(int)); + bytes_to_write_to_ncpserv += + write(fd_ncpserv_out, data, data_size); + break; + + default : break; + } + if (bytes_to_write_to_ncpserv > 255) inform_ncpserv(); +} + +static void ins_del_bind_net_addr(char *name, ipxAddr_t *adr) +{ + uint8 buf[1024]; + uint8 *p = buf; + int len = 0; + if (NULL != adr) { /* insert */ + *p=0x01; + p+=2; len+=2; + U16_TO_BE16(0x4, p); + p+=2; len+=2; + *p = strlen(name); + strmaxcpy(p+1, name, *p); + len += (*p+1); p+=(*p + 1); + memcpy(p, adr, sizeof(ipxAddr_t)); + len+=sizeof(ipxAddr_t); + } else { /* delete */ + *p=0x02; + p+=2; len+=2; + U16_TO_BE16(0x4, p); + p+=2; len+=2; + *p = strlen(name); + strmaxcpy(p+1, name, *p); + len += (*p+1); p+=(*p + 1); + } + write_to_ncpserv(0x3333, 0, buf, len); +} + +static int open_ipx_socket(uint16 sock_nr, int nr, int open_mode) +{ + int ipx_fd=t_open("/dev/ipx", open_mode, NULL); + struct t_bind bind; + if (ipx_fd < 0) { + t_error("t_open !Ok"); + return(-1); + } + U16_TO_BE16(sock_nr, my_server_adr.sock); /* actual read socket */ + bind.addr.len = sizeof(ipxAddr_t); + bind.addr.maxlen = sizeof(ipxAddr_t); + bind.addr.buf = (char*)&my_server_adr; + bind.qlen = 0; /* immer */ + if (t_bind(ipx_fd, &bind, &bind) < 0){ + char sxx[200]; + sprintf(sxx,"NWSERV:t_bind !OK in open_ipx_socket, sock=%d", sock_nr); + t_error(sxx); + t_close(ipx_fd); + return(-1); + } + sock_nummern[nr] = GET_BE16(my_server_adr.sock); /* really socket nmbr */ + if (nw_debug) print_ipx_addr(&my_server_adr); + return(ipx_fd); +} + +static int start_ncpserv(char *nwname, ipxAddr_t *addr) +{ + int fds_out[2]; + int fds_in[2]; + int pid; + if (pipe(fds_out) < 0 || pipe(fds_in) < 0) return(-1); + + switch (pid=fork()) { + case 0 : { /* new Process */ + char *progname="ncpserv"; + char addrstr[100]; + char pathname[300]; + + char gidstr[10]; + char uidstr[10]; + + char debug1[5]; + char debug2[5]; + char debug3[5]; + + int j = FD_NWSERV; + close(fds_out[1]); /* no need to write */ + dup2(fds_out[0], 0); /* becommes stdin */ + close(fds_out[0]); /* no longer needed */ + + close(fds_in[0]); /* no need to read */ + dup2(fds_in[1], FD_NWSERV); /* becommes fd FD_NWSERV */ + close(fds_in[1]); /* no longer needed */ + while (j++ < 100) close(j); /* close all > 4 */ + + ipx_addr_to_adr(addrstr, addr); + sprintf(gidstr, "%d", conn_gid); + sprintf(uidstr, "%d", conn_uid); + + sprintf(debug1, "%d", ncpserv_debug); + sprintf(debug2, "%d", nwconn_debug); + sprintf(debug3, "%d", ipxdebug); + + execl(get_exec_path(pathname, progname), progname, + nwname, addrstr, + gidstr, uidstr, + debug1, debug2, debug3, NULL); + + exit(1); + } + break; + + case -1: close(fds_out[0]); + close(fds_out[1]); + close(fds_in[0]); + close(fds_in[1]); + return(-1); /* error */ + } + fds_out[0] = -1; + fd_ncpserv_out = fds_out[1]; + fds_in[1] = -1; + fd_ncpserv_in = fds_in[0]; + pid_ncpserv = pid; + return(0); /* OK */ +} + +static int start_nwclient(void) +{ + switch (fork()){ + case 0 : { /* new Process */ + char *progname="nwclient"; + char pathname[300]; + char my_addrstr[100]; + char serv_addrstr[100]; + ipx_addr_to_adr(my_addrstr, &my_server_adr); + ipx_addr_to_adr(serv_addrstr, &nw386_adr); + execl(get_exec_path(pathname, progname), progname, + my_addrstr, serv_addrstr, NULL); + } + exit(1); + + case -1: return(-1); /* error */ + } + return(0); /* OK */ +} + +/* =========================== WDOG =============================== */ +static void send_wdog_packet(ipxAddr_t *addr, int conn, int what) +{ + uint8 data[2]; + data[0] = (uint8) conn; + data[1] = (uint8) what; + send_ipx_data(sockfd[WDOG_SLOT], 17, 2, data, addr, "WDOG"); +} + +static void send_bcast_packet(ipxAddr_t *addr, int conn, int signature) +{ + uint8 data[2]; + data[0] = (uint8) conn; + data[1] = (uint8) signature; + /* signatures + * '!' = broadcast waiting inform + * '@' = sft_iii server change over inform. + */ + send_ipx_data(sockfd[WDOG_SLOT], 17, 2, data, addr, "BCAST"); +} + +typedef struct { + ipxAddr_t addr; /* address of client */ + time_t last_time; /* last wdog packet sent */ + int counter; /* max. 11 packets */ +} CONN; + +static CONN conns[MAX_CONNECTIONS]; +static int hi_conn=0; + +static void insert_wdog_conn(int conn, ipxAddr_t *adr) +{ + if (conn > 0 && conn <= MAX_CONNECTIONS) { + CONN *c; + while (hi_conn < conn) { + c=&(conns[hi_conn++]); + memset(c, 0, sizeof(CONN)); + } + c=&(conns[--conn]); + c->last_time = akttime_stamp; + c->counter = 0; + if (NULL != adr) memcpy(&(c->addr), adr, sizeof(ipxAddr_t)); + } +} + +static void reset_wdog_conn(int conn) +{ + if (conn > 0 && --conn < hi_conn) { + CONN *c=&(conns[conn]); + c->last_time = akttime_stamp; + c->counter = 0; + } +} + +static void remove_wdog_conn(int conn) +{ + if (conn > 0 && --conn < hi_conn) { + CONN *c=&(conns[conn]); + memset(c, 0, sizeof(CONN)); + if (conn + 1 == hi_conn) { + while (hi_conn) { + CONN *c=&(conns[hi_conn-1]); + if (!c->last_time) hi_conn--; + else break; + } + } + } +} + +#ifdef _WDOG_TESTING_ +/* for testing */ +# define WDOG_TRIE_AFTER_SEC 1 +# define MAX_WDOG_TRIES 1 +#else +# define WDOG_TRIE_AFTER_SEC 300 /* ca. 5 min. */ +# define MAX_WDOG_TRIES 11 /* Standardtries */ +#endif + +static void send_wdogs(void) +{ + int k = hi_conn; + while (k--) { + CONN *c = &(conns[k]); + if (c->last_time) { + time_t t_diff = akttime_stamp - c->last_time; + if (c->counter || t_diff > WDOG_TRIE_AFTER_SEC) { /* max. 5 minutes */ + if (c->counter > MAX_WDOG_TRIES) { + /* now its enough with trying */ + /* clear connection */ + write_to_ncpserv(0x5555, k+1, NULL, 0); + } else { + ipxAddr_t adr; + c->last_time = akttime_stamp; + memcpy(&adr, &(c->addr), sizeof(ipxAddr_t)); + U16_TO_BE16(GET_BE16(adr.sock)+1, adr.sock); + send_wdog_packet(&adr, k+1, '?'); + } + c->counter++; + } + } + } +} + +static void send_bcasts(int conn) +{ + if (conn > 0 && --conn < hi_conn) { + CONN *c = &(conns[conn]); + ipxAddr_t adr; + memcpy(&adr, &(c->addr), sizeof(ipxAddr_t)); + U16_TO_BE16(GET_BE16(adr.sock)+2, adr.sock); + send_bcast_packet(&adr, conn+1, '!'); /* notify */ + } +} + +/* =========================== SERVER BROADCAST ======================== */ +static int send_broadcast(int fd, int firsttime, int down) +/* periodic Broadcast Message */ +{ + IPX_DATA ipx_data; + int ipx_pack_typ = 17; + ipxAddr_t wild; + + memset(&wild, 0, sizeof(ipxAddr_t)); + U32_TO_BE32(network, wild.net); + memset(wild.node, 0xFF, IPX_NODE_SIZE); + U16_TO_BE16(SOCK_SAP, wild.sock); + memset(&ipx_data, 0, sizeof(ipx_data.sip)); + strcpy(ipx_data.sip.server_name, my_nwname); + memcpy(&ipx_data.sip.server_adr, &my_server_adr, sizeof(ipxAddr_t)); + U16_TO_BE16(SOCK_NCP, ipx_data.sip.server_adr.sock); + /* NCP SOCKET verwenden */ + + if (firsttime && start_ncpserv(ipx_data.sip.server_name, + &ipx_data.sip.server_adr)) return(-1); + + U16_TO_BE16(2, ipx_data.sip.response_type); /* General */ + U16_TO_BE16(4, ipx_data.sip.server_type); /* Fileserver */ + + if (down) { + U16_TO_BE16(16, ipx_data.sip.intermediate_networks); + } else { + U16_TO_BE16(1, ipx_data.sip.intermediate_networks); + /* I think 1 is ok here */ + } + send_ipx_data(fd, ipx_pack_typ, + sizeof(ipx_data.sip), + (char *)&(ipx_data.sip), + &wild, "SIP Broadcast"); + + return(0); +} + +static void send_server_respons(int fd, uint8 ipx_pack_typ, + int respond_typ, int server_typ, + ipxAddr_t *to_addr) +{ + IPX_DATA ipx_data; + memset(&ipx_data, 0, sizeof(ipx_data.sip)); + strcpy(ipx_data.sip.server_name, my_nwname); + memcpy(&ipx_data.sip.server_adr, &my_server_adr, sizeof(ipxAddr_t)); + + U16_TO_BE16(SOCK_NCP, ipx_data.sip.server_adr.sock); + /* NCP SOCKET verwenden */ + + U16_TO_BE16(respond_typ, ipx_data.sip.response_type); + U16_TO_BE16(server_typ, ipx_data.sip.server_type); + U16_TO_BE16(0, ipx_data.sip.intermediate_networks); + send_ipx_data(fd, ipx_pack_typ, + sizeof(ipx_data.sip), + (char *)&(ipx_data.sip), + to_addr, "Server Response"); +} + +void get_server_data(char *name, + ipxAddr_t *adr, + ipxAddr_t *from_addr) +{ +#ifdef LINUX + if (memcmp(adr->net, my_server_adr.net, IPX_NET_SIZE)) + /* don't add our own netroute twice */ + myipx_route_add(adr->net, from_addr->net, from_addr->node); +#endif + if (!nw386_found) { + memcpy(&nw386_adr, adr, sizeof(ipxAddr_t)); + nw386_found++; + if (client_mode) { + start_nwclient(); + client_mode = 0; /* only start once */ + } + } + DPRINTF(("NW386 %s found at:%s\n", name, visable_ipx_adr(adr))); + ins_del_bind_net_addr(name, adr); +} + +void handle_sap(int fd, + int ipx_pack_typ, + int data_len, + IPX_DATA *ipxdata, + ipxAddr_t *from_addr) +{ + int query_type = GET_BE16(ipxdata->sqp.query_type); + int server_type = GET_BE16(ipxdata->sqp.server_type); + if (query_type == 3) { + DPRINTF(("SAP NEAREST SERVER request typ=%d von %s\n", server_type, visable_ipx_adr(from_addr))); + if (server_type == 4) { + /* Get Nearest File Server */ + send_server_respons(fd, ipx_pack_typ, + 4, server_type, from_addr); + } + } else if (query_type == 1) { /* general Request */ + DPRINTF(("SAP GENERAL request server_type =%d\n", server_type)); + if (server_type == 4) { + /* Get General File Server Request */ + send_server_respons(fd, ipx_pack_typ, + 4, server_type, from_addr); + } + } else if (query_type == 2) { /* periodic general or shutdown response */ + DPRINTF(("SAP PERIODIC response von %s\n", visable_ipx_adr(from_addr))); + if (server_type == 4) { /* from Fileserver */ + DPRINTF(("FROM SERVER intermediate=%d\n", + GET_BE16(ipxdata->sip.intermediate_networks))); + if (16 == GET_BE16(ipxdata->sip.intermediate_networks)) { + /* shutdown */ + if (memcmp(ipxdata->sip.server_adr.net, + my_server_adr.net, IPX_NET_SIZE)) { + /* don't kill our own netroute */ + DPRINTF(("SERVER %s IS GOING DOWN\n", ipxdata->sip.server_name)); + ins_del_bind_net_addr(ipxdata->sip.server_name, NULL); +#ifdef LINUX + myipx_route_del(ipxdata->sip.server_adr.net); +#endif + } else { + DPRINTF(("SHUTDOWN RESPONSE from SERVER %s\n", ipxdata->sip.server_name)); + } + } else { + get_server_data(ipxdata->sip.server_name, &(ipxdata->sip.server_adr), + from_addr); + } + } + } else if (query_type == 4) { /* nearests Service Response */ + DPRINTF(("SAP nearest Service response\n")); + if (server_type == 4){ + get_server_data(ipxdata->sip.server_name, &(ipxdata->sip.server_adr), + from_addr); + } + } else DPRINTF(("UNKNOWN SAP query %x, server %x\n", query_type, server_type)); +} + +static void send_rip(ipxAddr_t *from_addr) +{ + RIP rip; + ipxAddr_t to_addr; + memset(&rip, 0, sizeof(RIP)); + if (from_addr) memcpy(&to_addr, from_addr, sizeof(ipxAddr_t)); + else { + memset(&to_addr, 0, sizeof(ipxAddr_t)); + U32_TO_BE32(network, to_addr.net); + memset(to_addr.node, 0xFF, IPX_NODE_SIZE); + U16_TO_BE16(SOCK_RIP, to_addr.sock); + } + memcpy(rip.network, my_server_adr.net, IPX_NET_SIZE); + U16_TO_BE16(2, rip.operation); /* rip response or general */ + U16_TO_BE16(1, rip.ticks); /* on ethernets allways 1 Tick */ + U16_TO_BE16(0, rip.hops); + send_ipx_data(sockfd[RIP_SLOT], + 1, + sizeof(RIP), + (char *)&rip, + &to_addr, "SEND RIP"); +} + +static void handle_rip(int fd, int ipx_pack_typ, + int data_len, IPX_DATA *ipxdata, + ipxAddr_t *from_addr) +{ + int operation = GET_BE16(ipxdata->rip.operation); + int hops = GET_BE16(ipxdata->rip.hops); + int ticks = GET_BE16(ipxdata->rip.ticks); + DPRINTF(("Rip %s hops %d, ticks %d, network:%02x.%02x.%02x.%02x\n", + (operation == 1) ? "Request" : "Response", + hops, ticks, + (int)ipxdata->rip.network[0], + (int)ipxdata->rip.network[1], + (int)ipxdata->rip.network[2], + (int)ipxdata->rip.network[3])); + if (operation == 1) { /* rip request */ + send_rip(from_addr); + } else if (operation != 2) /* NICHT RIP response */ + DPRINTF(("UNKNOWN RIP operation %d\n", operation)); +} + +/* +** Task state constants (IPX Connection States) +** +** +** IPX_TASK_FREE - Task node is currently on the free list +** IPX_TASK_INUSE - Task has been allocated for use +** IPX_TASK_TRANSMIT - Packet has been transmitted (SendPacket) +** IPX_TASK_TIMEDOUT - Task has been disabled due to watchdog or +** retry fail +** IPX_TASK_DYING - Last NCP Response had Bad Connection Status +** Bit (Server Gone or Connection Gone). +** IPX_TASK_CONNECTED - Task is connected by address to the server +** IPX_TASK_BURST - A Packet Burst transaction is in progress +** +*/ +#if 0 +#define IPX_TASK_FREE 0 /* Not in use */ +#define IPX_TASK_INUSE (1<<0) /* In use */ +#define IPX_TASK_TRANSMIT (1<<1) /* Packet on the wire */ +#define IPX_TASK_TIMEDOUT (1<<2) /* Connection is timed out */ +#define IPX_TASK_DYING (1<<3) /* Connection no longer valid */ +#define IPX_TASK_CONNECTED (1<<4) /* Connection in place */ +#define IPX_TASK_BURST (1<<5) /* Packet Burst in progress */ + +#define CONN_STATUS_BAD_CONNECTION 0x01 +#define CONN_STATUS_NO_SLOTS_AVAIL 0x04 +#define CONN_STATUS_SERVER_DOWN 0x10 +#define CONN_STATUS_MESSSAGE_WAITING 0x01 +#endif + + +static void response_ipx_diag(int fd, int ipx_pack_typ, + ipxAddr_t *to_addr) +{ + IPX_DATA ipxdata; + DIAGRESP *dia = &ipxdata.diaresp; + uint8 *p = (uint8*) (dia+1); + int datalen = sizeof(DIAGRESP); /* erstmal */ + dia->majorversion = 1; + dia->minorversion = 1; + U16_TO_BE16(spx_diag_socket, dia->spx_diag_sock); + dia->anz = 3; + *p++ = 0; /* IPX/SPX */ + datalen++; + *p++ = 1; /* Bridge Driver */ + datalen++; + /* Jetzt extended */ + *p++ = 6; /* Fileserver/Bridge (internal) */ + datalen++; + *p++ = 1; /* Anz. Networks */ + datalen++; + *p++ = 0; /* LAN BOARD */ + datalen++; + memcpy(p, my_server_adr.net, IPX_NET_SIZE); + p += IPX_NET_SIZE; + datalen += IPX_NET_SIZE; + memcpy(p, my_server_adr.node, IPX_NODE_SIZE); + datalen += IPX_NODE_SIZE; + send_ipx_data(fd, ipx_pack_typ, + datalen, + (char*)&ipxdata, + to_addr, "DIAG Response"); +} + +static void handle_diag(int fd, int ipx_pack_typ, + int data_len, IPX_DATA *ipxdata, + ipxAddr_t *from_addr) +/* should handle CONFIGURATION REQUESTS one time */ +{ + CONFREQ *conf = &(ipxdata->confreq); + int count = (int) conf->count; + int j = count; + uint8 *exnodes = conf->ex_node; + while (j--) { + if IPXCMPNODE(exnodes, my_server_adr.node) { + DPRINTF(("NO RESPONSE TO DIAG\n")); + return; + } + exnodes += IPX_NODE_SIZE; + } + DPRINTF(("DIAG Request, ipx_pack_typ %d, data_len %d, count %d\n", + (int)ipx_pack_typ, data_len, count)); + response_ipx_diag(fd, ipx_pack_typ, from_addr); +} + +static void handle_event(int fd, uint16 socknr, int slot) +{ + struct t_unitdata ud; + ipxAddr_t source_adr; + uint8 ipx_pack_typ; + IPX_DATA ipx_data_buff; + int flags = 0; + + ud.opt.len = sizeof(ipx_pack_typ); + ud.opt.maxlen = sizeof(ipx_pack_typ); + ud.opt.buf = (char*)&ipx_pack_typ; /* gets actual typ */ + + ud.addr.len = sizeof(ipxAddr_t); + ud.addr.maxlen = sizeof(ipxAddr_t); + + ud.addr.buf = (char*)&source_adr; + ud.udata.len = IPX_MAX_DATA; + ud.udata.maxlen = IPX_MAX_DATA; + ud.udata.buf = (char*)&ipx_data_buff; + + if (t_rcvudata(fd, &ud, &flags) < 0){ + struct t_uderr uderr; + ipxAddr_t erradr; + uint8 err_pack_typ; + uderr.addr.len = sizeof(ipxAddr_t); + uderr.addr.maxlen = sizeof(ipxAddr_t); + uderr.addr.buf = (char*)&erradr; + uderr.opt.len = sizeof(err_pack_typ); + uderr.opt.maxlen = sizeof(err_pack_typ); + uderr.opt.buf = (char*)&err_pack_typ; /* get actual typ */ + ud.addr.buf = (char*)&source_adr; + t_rcvuderr(fd, &uderr); + DPRINTF(("Error from %s, Code = 0x%lx\n", visable_ipx_adr(&erradr), uderr.error)); + t_error("t_rcvudata !OK"); + return; + } + + DPRINTF(("Ptyp:%d von: %s\n", (int)ipx_pack_typ, visable_ipx_adr(&source_adr) )); + + if IPXCMPNODE(source_adr.node, my_server_adr.node) { + int source_sock = (int) GET_BE16(source_adr.sock); + if ( source_sock == sock_nummern[MY_BROADCAST_SLOT] + || source_sock == sock_nummern[WDOG_SLOT] + || source_sock == SOCK_RIP) { + DPRINTF(("OWN Packet, ignored\n")); + return; + } + /* it also can be Packets from DOSEMU OR ncpfs on this machine */ + DPRINTF(("Packet from OWN maschine:sock=0x%x\n", source_sock)); + } + + switch (socknr) { + case SOCK_SAP : handle_sap( fd, (int) ipx_pack_typ, ud.udata.len, &ipx_data_buff, &source_adr); break; + case SOCK_RIP : handle_rip( fd, (int) ipx_pack_typ, ud.udata.len, &ipx_data_buff, &source_adr); break; + case SOCK_DIAGNOSE : handle_diag(fd, (int) ipx_pack_typ, ud.udata.len, &ipx_data_buff, &source_adr); break; + + default : + if (WDOG_SLOT == slot) { /* this is a watchdog packet */ + DPRINTF(("WDOG Packet len=%d connid=%d, status=%d\n", + (int)ud.udata.len, (int) ipx_data_buff.wdog.connid, + (int)ipx_data_buff.wdog.status)); + if (2 == ud.udata.len) { + if ('Y' == ipx_data_buff.wdog.status) + reset_wdog_conn(ipx_data_buff.wdog.connid); + } + } else { + uint8 *p = (uint8*)&ipx_data_buff; + int k = 0; + DPRINTF(("UNKNOWN")); + while (k++ < ud.udata.len){ + DPRINTF((" %x", (int) *p++)); + } + DPRINTF(("\n")); + /* + print_ud_data(&ud); + */ + } + break; + } +} + +static void get_server(void) +{ + if (!nw386_found) { /* no other server was found yet. */ + SQP sqp; + ipxAddr_t wild; + memset(&wild, 0, sizeof(ipxAddr_t)); + memset(wild.node, 0xFF, IPX_NODE_SIZE); + U32_TO_BE32(network, wild.net); + U16_TO_BE16(SOCK_SAP, wild.sock); + U16_TO_BE16(3, sqp.query_type); + U16_TO_BE16(4, sqp.server_type); + send_ipx_data(sockfd[SAP_SLOT], 17, sizeof(SQP), + (char*)&sqp, &wild, "SERVER Query"); + } +} + +static void get_ini(void) +{ + FILE *f=open_nw_ini(); + char *frname=NULL; +#ifdef LINUX + strcpy(devname, "eth0"); /* default */ +#endif + gethostname(my_nwname, 48); + upstr(my_nwname); + if (f){ + char buff[500]; + int what; + while (0 != (what =get_ini_entry(f, 0, (char*)buff, sizeof(buff)))) { + char inhalt[500]; + char inhalt2[500]; + char inhalt3[500]; + char dummy; + int anz; + if ((anz=sscanf((char*)buff, "%s %s %s", inhalt, inhalt2, inhalt3)) > 0) { + switch (what) { + case 2 : strncpy(my_nwname, inhalt, 48); + my_nwname[47] = '\0'; + upstr(my_nwname); + break; + +#ifdef LINUX + case 3 : + if (sscanf(inhalt, "%ld%c", &internal_net, &dummy) != 1) + sscanf(inhalt, "%lx", &internal_net); + break; +#endif + + case 4 : + if (sscanf(inhalt, "%ld%c", &network, &dummy) != 1) + sscanf(inhalt, "%lx", &network); +#ifdef LINUX + if (anz > 1) { + strncpy(devname, inhalt2, sizeof(devname)); + devname[sizeof(devname)-1] = '\0'; + } + if (anz > 2) { + upstr(inhalt3); + if (!strcmp(inhalt3, "802.3")) frame=IPX_FRAME_8023; + else if (!strcmp(inhalt3, "802.2")) + frame=IPX_FRAME_8022; + else if (!strcmp(inhalt3, "SNAP")) + frame=IPX_FRAME_SNAP; + else if (!strcmp(inhalt3, "ETHERNET_II")) + frame=IPX_FRAME_ETHERII; + } +#endif + break; + + case 10 : + sscanf(inhalt, "%d", &conn_gid); + break; + + case 11 : + sscanf(inhalt, "%d", &conn_uid); + break; + + case 100 : + sscanf(inhalt, "%d", &ipxdebug); + break; + + case 101 : + sscanf(inhalt, "%d", &nw_debug); + break; + + case 102 : + sscanf(inhalt, "%d", &ncpserv_debug); + break; + + case 103 : + sscanf(inhalt, "%d", &nwconn_debug); + break; + + default : break; + } /* switch */ + } /* if */ + } /* while */ + fclose(f); + } + +#ifdef LINUX + switch (frame) { + case IPX_FRAME_8022 : frname = "802.2"; break; + case IPX_FRAME_8023 : frname = "802.3"; break; + case IPX_FRAME_SNAP : frname = "SNAP"; break; + case IPX_FRAME_ETHERII : frname = "ETHERNET_II";break; + default : break; + } /* switch */ +#else + frname = "ETHERNET_II"; +#endif + fprintf(stdout, + "Servername='%s', NETWORK='0x%lx', NODE='0x%lx'\n", + my_nwname, network, internal_net); + +#ifdef LINUX + fprintf(stdout, "Device=%s, Frame=%s\n", devname, frname); + init_ipx(devname, &network, internal_net, frame, frname, ipxdebug); + fprintf(stdout, "NETWORK is=0x%lx\n", network); +#endif +} + +static void send_down_broadcast(void) +{ + int j = 20; + while (j--) send_broadcast(sockfd[MY_BROADCAST_SLOT], 0, 1); +} + +static void close_all(void) +{ + int j = NEEDED_SOCKETS; + if (pid_ncpserv > 0) { + if (fd_ncpserv_out > -1) close(fd_ncpserv_out); + if (fd_ncpserv_in > -1) close(fd_ncpserv_in); + kill(pid_ncpserv, SIGTERM); /* terminate ncpserv */ + kill(pid_ncpserv, SIGKILL); /* kill ncpserv */ + } + while (j--) { + t_unbind(sockfd[j]); + t_close(sockfd[j]); + } +#ifdef LINUX + fprintf(stdout, "Close Device=%s\n", devname); + exit_ipx(devname, network, frame); +#endif +} + +static void sig_quit(int rsig) +{ + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGTERM, SIG_IGN); + signal(SIGHUP, SIG_IGN); + signal(SIGPIPE, SIG_IGN); + send_down_broadcast(); + close_all(); + exit(1); +} + +static int fl_get_debug=0; +static void get_new_debug(void) +{ + get_ini_debug(1); + fl_get_debug=0; +} + +static void sig_hup(int rsig) +{ + signal(SIGHUP, SIG_IGN); + fl_get_debug++; + signal(SIGHUP, sig_hup); +} + +static void set_sigs(void) +{ + signal(SIGTERM, sig_quit); + signal(SIGQUIT, sig_quit); + signal(SIGINT, sig_quit); + signal(SIGPIPE, SIG_IGN); + signal(SIGHUP, sig_hup); +} + +int main(int argc, char **argv) +{ + int j = -1; + tzset(); + if (argc > 1) client_mode++; + /* in client mode the testprog 'nwclient' will be startet. */ + + get_ini(); + + while (++j < NEEDED_POLLS) { + polls[j].events = POLLIN|POLLPRI; + polls[j].revents = 0; + if (j < NEEDED_SOCKETS) { + int fd = open_ipx_socket(ipx_sock_nummern[j], j, O_RDWR); + if (fd < 0) { + while (j--) { + t_unbind(sockfd[j]); + t_close(sockfd[j]); + } + return(1); + } else { + sockfd[j] = fd; + polls[j].fd = fd; + } + } else { + polls[j].fd = -1; + } + } + + if (!send_broadcast(sockfd[MY_BROADCAST_SLOT], 1, 0)) { + /* Jetzt POLLEN */ + + time_t broadtime; + time(&broadtime); + set_sigs(); + + polls[NEEDED_SOCKETS].fd = fd_ncpserv_in; + + while (1) { + int anz_poll = poll(polls, NEEDED_POLLS, + (!client_mode) ? 30000 : 15000); + + if (fl_get_debug) get_new_debug(); + + time(&akttime_stamp); + if (anz_poll > 0) { /* i have to work */ + struct pollfd *p = &polls[0]; + j = -1; + while (++j < NEEDED_POLLS) { + if (p->revents){ + if (j < NEEDED_SOCKETS) { /* socket */ + /* + DPRINTF(("POLL %d, SOCKET %x, ", p->revents, sock_nummern[j])); + */ + if (p->revents & ~POLLIN) perror("STREAM error"); + else handle_event(p->fd, sock_nummern[j], j); + } else { /* fd_ncpserv_in */ + DPRINTF(("POLL %d, fh=%d\n", p->revents, p->fd)); + if (p->revents & ~POLLIN) perror("STREAM error"); + else { + if (p->fd == fd_ncpserv_in) { + int what; + int conn; + ipxAddr_t adr; + + if (sizeof(int) == read(fd_ncpserv_in, + (char*)&what, sizeof(int))) { + DPRINTF(("GOT ncpserv_in what=0x%x\n", what)); + switch (what) { + case 0x2222 : /* insert wdog connection */ + if (sizeof(int) == read(fd_ncpserv_in, + (char*)&conn, sizeof(int)) + && sizeof(ipxAddr_t) == read(fd_ncpserv_in, + (char*)&adr, sizeof(ipxAddr_t))) + insert_wdog_conn(conn, &adr); + break; + + case 0x4444 : /* reset wdog connection */ + if (sizeof(int) == read(fd_ncpserv_in, + (char*)&conn, sizeof(int))) + reset_wdog_conn(conn); + break; + + case 0x6666 : /* remove wdog connection */ + if (sizeof(int) == read(fd_ncpserv_in, + (char*)&conn, sizeof(int))) + remove_wdog_conn(conn); + break; + + case 0x8888 : /* bcast message */ + if (sizeof(int) == read(fd_ncpserv_in, + (char*)&conn, sizeof(int))) + send_bcasts(conn); + break; + + default : break; + } + } + } + } + } + if (! --anz_poll) break; + } /* if */ + p++; + } /* while */ + } else { + /* if (anz_poll < 0) perror("POLL error"); */ + if (nw_debug > 2) DPRINTF(("POLLING ...\n")); + } + if (akttime_stamp - broadtime > 59) { /* ca. 60 seconds */ + send_wdogs(); + send_broadcast(sockfd[MY_BROADCAST_SLOT], 0, 0); + send_rip(NULL); + get_server(); + inform_ncpserv(); + broadtime = akttime_stamp; + } else if (client_mode) get_server(); /* Here more often */ + } /* while */ + send_down_broadcast(); + } + close_all(); + return(0); +} + diff --git a/tools.c b/tools.c new file mode 100644 index 0000000..cf10aa6 --- /dev/null +++ b/tools.c @@ -0,0 +1,214 @@ +/* tools.c 18-Nov-95 */ +/* (C)opyright (C) 1993,1995 Martin Stover, Marburg, Germany + * + * 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 "net.h" +#include +#include + +int nw_debug=0; + +char *xmalloc(uint size) +{ + char *p = (size) ? (char *)malloc(size) : (char*)NULL; + if (p == (char *)NULL && size){ + fprintf(stderr, "not enough core, need %d Bytes\n", size); + exit(1); + } + return(p); +} + +void x_x_xfree(char **p) +{ + if (*p != (char *)NULL){ + free(*p); + *p = (char*)NULL; + } +} + +int strmaxcpy(char *dest, char *source, int len) +{ + int slen = (source != (char *)NULL) ? min(len, strlen(source)) : 0; + if (slen) memcpy(dest, source, slen); + dest[slen] = '\0'; + return(slen); +} + +int x_x_xnewstr(uint8 **p, uint8 *s) +{ + int len = (s == NULL) ? 0 : strlen(s); + if (*p != (uint8 *)NULL) free((char*)*p); + *p = (uint8*)xmalloc(len+1); + if (len) strcpy((char*)(*p), (char*)s); + else **p = '\0'; + return (len); +} + +void dprintf(char *p, ...) +{ + va_list ap; + if (nw_debug){ + va_start(ap, p); + vprintf(p, ap); + va_end(ap); + fflush(stdout); + } +} + +void xdprintf(int dlevel, char *p, ...) +{ + va_list ap; + if (nw_debug >= dlevel) { + va_start(ap, p); + vprintf(p, ap); + va_end(ap); + fflush(stdout); + } +} + +FILE *open_nw_ini(void) +{ + char *fname=FILENAME_NW_INI; + FILE *f=fopen(fname, "r"); + if (f == (FILE*)NULL) fprintf(stderr, "Cannot open ini file `%s`\n", fname); + return(f); +} + +int get_ini_entry(FILE *f, int entry, char *str, int strsize) +/* liefert ini_entry zurueck bzw. 0, falls nichts gefunden */ +{ + char buff[512]; + int do_open = ((FILE*) NULL == f); + if (do_open) f = open_nw_ini(); + if ((FILE*) NULL != f) { + while (fgets((char*)buff, sizeof(buff), f) != NULL){ + int len = strlen(buff); + char *ppi = NULL; + int se = 0; + int j = -1; + while (++j < len){ + char *pp=(buff+j); + if (*pp == '#' || *pp == '\r' || *pp == '\n') { + *pp = '\0'; + len = j; + break; + } else if ( *pp == 32 || *pp == '\t') { + if (!se) se = j; + } else if ((!ppi) && se) { + ppi = pp; + } + } + if (len > se+1 && se > 0 && se < 4 && ppi){ + char sx[10]; + int fentry; + strmaxcpy(sx, buff, se); + fentry = atoi(sx); + if (fentry > 0 && ((!entry) || entry == fentry)) { + strmaxcpy(str, ppi, strsize-1); + if (do_open) fclose(f); + return(fentry); + } + } + } /* while */ + if (do_open) fclose(f); + } + return(0); +} + +char *get_exec_path(char *buff, char *progname) +{ + sprintf(buff, "%s/%s", PATHNAME_PROGS, progname); + return(buff); +} + + +void get_ini_debug(int what) +/* what: + * 1 = nwserv + * 2 = ncpserv + * 3 = nwconn + */ +{ + char buff[10]; + if (get_ini_entry(NULL, 100+what, buff, sizeof(buff))) { + int debug; + if (1==sscanf(buff, "%d", &debug)) nw_debug=debug; + } +} + +uint8 down_char(uint8 ch) +{ + if (ch > 64 && ch < 91) return(ch + 32); + switch(ch){ + case 142: ch = 132; break; + case 153: ch = 148; break; + case 154: ch = 129; break; + default :break; + } + return(ch); +} + +uint8 up_char(uint8 ch) +{ + if (ch > 96 && ch < 123) return(ch - 32); + switch(ch) { + case 132: ch = 142; break; + case 148: ch = 153; break; + case 129: ch = 154; break; + default : break; + } + return(ch); +} + +uint8 *upstr(uint8 *s) +{ + if (!s) return((uint8*)NULL); + for (;*s;s++) *s=up_char(*s); + return(s); +} + +uint8 *downstr(uint8 *s) +{ + if (!s) return((uint8*)NULL); + for (;*s;s++) *s=down_char(*s); + return(s); +} + +/* next is stolen from GNU-fileutils */ +static long adjust_blocks (long blocks, int fromsize, int tosize) +{ + if (fromsize == tosize) /* E.g., from 512 to 512. */ + return blocks; + else if (fromsize > tosize) /* E.g., from 2048 to 512. */ + return blocks * (fromsize / tosize); + else /* E.g., from 256 to 512. */ + return (blocks + (blocks < 0 ? -1 : 1)) / (tosize / fromsize); +} + + +int get_fs_usage(char *path, struct fs_usage *fsp) +{ + struct statfs fsd; + if (statfs (path, &fsd) < 0) return (-1); +#define convert_blocks(b) adjust_blocks ((b), fsd.f_bsize, 512) + fsp->fsu_blocks = convert_blocks (fsd.f_blocks); + fsp->fsu_bfree = convert_blocks (fsd.f_bfree); + fsp->fsu_bavail = convert_blocks (fsd.f_bavail); + fsp->fsu_files = fsd.f_files; + fsp->fsu_ffree = fsd.f_ffree; + return(0); +} diff --git a/tools.h b/tools.h new file mode 100644 index 0000000..46853c1 --- /dev/null +++ b/tools.h @@ -0,0 +1,61 @@ +/* tools.h : 14-Nov-95 */ + +/* (C)opyright (C) 1993,1995 Martin Stover, Marburg, Germany + * + * 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. + */ + +extern void x_x_xfree(char **p); +extern int x_x_xnewstr(uint8 **p, uint8 *s); + +#define xfree(p) x_x_xfree((char **)&(p)) +#define new_str(p, s) x_x_xnewstr((uint8 **)&(p), s) + +extern char *xmalloc(uint size); +extern int strmaxcpy(char *dest, char *source, int len); +extern void dprintf(char *p, ...); +extern void xdprintf(int dlevel, char *p, ...); +extern FILE *open_nw_ini(void); +extern int get_ini_entry(FILE *f, int entry, char *str, int strsize); +extern char *get_exec_path(char *buff, char *progname); +extern void get_ini_debug(int what); + +extern uint8 down_char(uint8 ch); +extern uint8 up_char(uint8 ch); +extern uint8 *downstr(uint8 *s); +extern uint8 *upstr(uint8 *s); + + +/* stolen from GNU-fileutils */ +/* Space usage statistics for a filesystem. Blocks are 512-byte. */ +struct fs_usage { + long fsu_blocks; /* Total blocks. */ + long fsu_bfree; /* Free blocks available to superuser. */ + long fsu_bavail; /* Free blocks available to non-superuser. */ + long fsu_files; /* Total file nodes. */ + long fsu_ffree; /* Free file nodes. */ +}; +extern int get_fs_usage(char *path, struct fs_usage *fsp); + + +extern int nw_debug; +#ifdef DB +# define DPRINTF(x) dprintf x +# define XDPRINTF(x) xdprintf x +#else +# define DPRINTF(x) /* */ +# define XDPRINTF(x) /* */ +#endif +