commit 5b89fe9f28c204a093c5891b84f70a2cdd9aaeca Author: Mario Fetka Date: Sun Nov 13 00:38:55 2011 +0100 mars_nwe-0.95.pl00 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 +