From 5d4b23a5c12314d30165dcfa8ee0f805005d8458 Mon Sep 17 00:00:00 2001 From: ncpfs archive import Date: Tue, 28 Apr 2026 20:39:57 +0200 Subject: [PATCH] Import ncpfs 0.9 --- .downloads/ncpfs-0.9.tgz | Bin 0 -> 81290 bytes Makefile | 8 +- README | 8 +- ipx-0.75/Makefile | 30 ++ ipx-0.75/README | 65 +++ {util => ipx-0.75}/ipx_configure.c | 0 ipx-0.75/ipx_interface.c | 303 ++++++++++++ ipx-0.75/ipx_internal_net.c | 195 ++++++++ ipx-0.75/ipx_route.c | 215 +++++++++ ipx-0.75/ipxrcv.c | 52 ++ ipx-0.75/ipxsend.c | 46 ++ ipx-0.75/rip.c | 68 +++ ipx-0.75/sap.c | 96 ++++ kernel-1.2/linux/ncp.h | 22 +- kernel-1.2/src/Makefile | 4 +- kernel-1.2/src/dir.c | 2 +- kernel-1.2/src/file.c | 2 +- kernel-1.2/src/inode.c | 2 +- kernel-1.2/src/{ncplib.c => ncplib_kernel.c} | 2 +- kernel-1.2/src/{ncplib.h => ncplib_kernel.h} | 0 kernel-1.3/linux/ncp.h | 22 +- kernel-1.3/src/Makefile | 4 +- kernel-1.3/src/dir.c | 2 +- kernel-1.3/src/file.c | 2 +- kernel-1.3/src/inode.c | 4 +- kernel-1.3/src/{ncplib.c => ncplib_kernel.c} | 2 +- kernel-1.3/src/{ncplib.h => ncplib_kernel.h} | 0 man/ipx_interface.8 | 61 +++ man/ipx_internal_net.8 | 32 ++ man/ipx_route.8 | 24 + man/ncpmount.8 | 2 +- man/ncpumount.8 | 2 +- man/slist.1 | 44 ++ ncpfs-0.8.lsm => ncpfs-0.9.lsm | 8 +- util/Makefile | 24 +- util/ipx.tar | Bin 40960 -> 0 bytes util/ipxutil.h | 76 --- util/{ncplib_user.c => ncplib.c} | 471 ++++++++++++++++--- util/{ncplib_user.h => ncplib.h} | 71 ++- util/ncpmount.c | 323 ++----------- util/ncptest.c | 146 ++---- util/nwcrypt.c | 7 +- util/nwcrypt.h | 5 - util/slist.c | 77 +++ 44 files changed, 1925 insertions(+), 604 deletions(-) create mode 100644 .downloads/ncpfs-0.9.tgz create mode 100644 ipx-0.75/Makefile create mode 100644 ipx-0.75/README rename {util => ipx-0.75}/ipx_configure.c (100%) create mode 100644 ipx-0.75/ipx_interface.c create mode 100644 ipx-0.75/ipx_internal_net.c create mode 100644 ipx-0.75/ipx_route.c create mode 100644 ipx-0.75/ipxrcv.c create mode 100644 ipx-0.75/ipxsend.c create mode 100644 ipx-0.75/rip.c create mode 100644 ipx-0.75/sap.c rename kernel-1.2/src/{ncplib.c => ncplib_kernel.c} (99%) rename kernel-1.2/src/{ncplib.h => ncplib_kernel.h} (100%) rename kernel-1.3/src/{ncplib.c => ncplib_kernel.c} (99%) rename kernel-1.3/src/{ncplib.h => ncplib_kernel.h} (100%) create mode 100644 man/ipx_interface.8 create mode 100644 man/ipx_internal_net.8 create mode 100644 man/ipx_route.8 create mode 100644 man/slist.1 rename ncpfs-0.8.lsm => ncpfs-0.9.lsm (73%) delete mode 100644 util/ipx.tar delete mode 100644 util/ipxutil.h rename util/{ncplib_user.c => ncplib.c} (79%) rename util/{ncplib_user.h => ncplib.h} (70%) delete mode 100644 util/nwcrypt.h create mode 100644 util/slist.c diff --git a/.downloads/ncpfs-0.9.tgz b/.downloads/ncpfs-0.9.tgz new file mode 100644 index 0000000000000000000000000000000000000000..fd44950a84237f6d7822071e8299e4e4ed1b6716 GIT binary patch literal 81290 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 ne4S!gOD)-(cL(F59E6X~KUkG#nVJ(^ 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 O#N(eaYraPS@C5+Oqx|Rq literal 0 HcmV?d00001 diff --git a/Makefile b/Makefile index f567a11..b1017b9 100644 --- a/Makefile +++ b/Makefile @@ -6,13 +6,13 @@ KERNEL = 1.2 INCLUDES = -I/usr/src/linux/include -Ikernel BINDIR = ./bin +SUBDIRS = kernel-$(KERNEL)/src util ipx-0.75 CFLAGS = -Wall $(INCLUDES) CC = gcc all: kernel - make -C util - make -C kernel/src ncpfs.o + for i in $(SUBDIRS); do make -C $$i; done cp kernel/src/ncpfs.o bin kernel: @@ -20,7 +20,7 @@ kernel: ln -s kernel-$(KERNEL) kernel dep: - $(CPP) -M $(INCLUDES) *.c > .depend + for i in $(SUBDIRS); do make -C $$i dep; done clean: rm -f kernel @@ -28,7 +28,7 @@ clean: rm -f `find . -type f -name '*~' -print` rm -f `find . -type f -name '.depend' -print` rm -f `find . -type f -name '*.out' -print` - + for i in $(SUBDIRS); do make -C $$i clean; done realclean: clean rm -fr bin/* ncpfs.tgz diff --git a/README b/README index 9d9feec..814a0c5 100644 --- a/README +++ b/README @@ -1,14 +1,14 @@ -This is version 0.7 of ncpfs, a free NetWare client filesystem for +This is version 0.8 of ncpfs, a free NetWare client filesystem for Linux. This one currently works with Kernel 1.2.13. I do not know whether it works with any other kernel of the 1.2.x series, I only used it with 1.2.13. -Due to problems in the 1.3.x IPX kernel code, ncpfs-0.7 does NOT work -with any 1.3.x kernel up to 1.3.44, although there is a kernel-1.3 +Due to problems in the 1.3.x IPX kernel code, ncpfs-0.8 does NOT work +with any 1.3.x kernel up to 1.3.45, although there is a kernel-1.3 subdirectory. It compiles fine and seems to work, but any connection will block after a very short time. Please be patient. I'm sure this will be solved. If you follow the kernel development closely, you -might want to try ncpfs with a kernel later than 1.3.44, but I can not +might want to try ncpfs with a kernel later than 1.3.45, but I can not promise anything. To try it with 1.3, simply change the variable KERNEL in the Makefile from 1.2 to 1.3 and continue as usual. diff --git a/ipx-0.75/Makefile b/ipx-0.75/Makefile new file mode 100644 index 0000000..9670636 --- /dev/null +++ b/ipx-0.75/Makefile @@ -0,0 +1,30 @@ +CFLAGS = -O2 -Wall +BINDIR = ../bin +UTILS = $(BINDIR)/ipx_configure $(BINDIR)/ipx_interface \ + $(BINDIR)/ipx_internal_net $(BINDIR)/ipx_route + +all: $(UTILS) + +$(BINDIR)/ipx_configure: ipx_configure.o + $(CC) -o $(BINDIR)/ipx_configure ipx_configure.o + +$(BINDIR)/ipx_interface: ipx_interface.o + $(CC) -o $(BINDIR)/ipx_interface ipx_interface.o + +$(BINDIR)/ipx_internal_net: ipx_internal_net.o + $(CC) -o $(BINDIR)/ipx_internal_net ipx_internal_net.o + +$(BINDIR)/ipx_route: ipx_route.o + $(CC) -o $(BINDIR)/ipx_route ipx_route.o + + +clean: + rm -f $(UTILS) *.o rip sap ipxrcv ipxsend + +install: $(UTILS) + for i in $(UTILS); \ + do \ + install --strip $$i /sbin; \ + install $$i.8 /usr/man/man8; \ + done + diff --git a/ipx-0.75/README b/ipx-0.75/README new file mode 100644 index 0000000..dcc4e88 --- /dev/null +++ b/ipx-0.75/README @@ -0,0 +1,65 @@ +This file contains a very short introduction to the IPX implementation +on Linux. Feel free to forward comments (especially suggested additions) +to greg@caldera.com. + +The following are important definitions in understanding the descriptions +in this README file. + +IPX Interface - This is the item to which IPX sockets are bound. +An IPX interface corresponds to an IPX Network Number which corresponds +to a physical device and frame type. A sample IPX Interface would be: +Network Number: 0x00ABCDEF +Device: Eth0 +Frame Type: 802.2. +The particular interface is selected during binding by using the +Network Number (see sample code below). + +Primary Interface - The interface that is selected by default when +binding a socket. This is selected when binding by using +a network number of 0 (see sample code below). + +Internal Network - This is a special kind of IPX interface that does +not have a physical device or frame type. It is used to provide +a route-independent address for service providers. Internal network +numbers are optional; however, when one is present it is also the +Primary Interface. + +This tar file contains the following IPX utilities: + +ipx_interface.c +This program is used to create an IPX interface. + +ipx_internal_net.c +This program is used to create an IPX Internal Network number. + +ipx_route.c +This program creates an IPX route. + +ipx_configure.c +This program is used to read/write two configuration parameters: + AUTO INTERFACE CREATE - IPX should/shouldn't automatically create + an IPX interface when it discovers one that has not been + registered via ipx_interface above. + AUTO PRIMARY SELECT - IPX should/shouldn't automatically select + a primary interface when it one an interface exists and + none are designated as the primary. Manual designation + is performed via ipx_interface. + +By default, these are both turned off. + +The following are sample IPX programs: + +ipxrcv.c and ipxsend.c +ipxsend will send a single packet to an instance of ipxrcv running on the +same machine. It uses getsockname(2) to determine the address to which to +send the packet. +rip.c +rip passively monitors the rip traffic on the attached IPX network. +sap.c +sap passively monitors the sap traffic on the attached IPX network. + +There are three files in /proc/net that relate to IPX. +ipx_interface contains the list of IPX interfaces. +ipx_route contains the list of IPX routes. +ipx contains the list of IPX sockets in use. + diff --git a/util/ipx_configure.c b/ipx-0.75/ipx_configure.c similarity index 100% rename from util/ipx_configure.c rename to ipx-0.75/ipx_configure.c diff --git a/ipx-0.75/ipx_interface.c b/ipx-0.75/ipx_interface.c new file mode 100644 index 0000000..ec67751 --- /dev/null +++ b/ipx-0.75/ipx_interface.c @@ -0,0 +1,303 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct ifreq id; +static char *progname; + +void +usage(void) +{ + fprintf(stderr, "Usage: %s add [-p] device frame_type [net_number]\n\ +Usage: %s del device frame_type\n\ +Usage: %s check device frame_type\n", progname, progname, progname); + exit(-1); +} + +struct frame_type { + char *ft_name; + unsigned char ft_val; +} frame_types[] = { + {"802.2", IPX_FRAME_8022}, + {"802.3", IPX_FRAME_8023}, + {"SNAP", IPX_FRAME_SNAP}, + {"EtherII", IPX_FRAME_ETHERII} +}; + +#define NFTYPES (sizeof(frame_types)/sizeof(struct frame_type)) + +int +lookup_frame_type(char *frame) +{ + int j; + + for (j = 0; (j < NFTYPES) && + (strcasecmp(frame_types[j].ft_name, frame)); + j++) + ; + + if (j != NFTYPES) + return j; + + fprintf(stderr, "%s: Frame type must be", progname); + for (j = 0; j < NFTYPES; j++) { + fprintf(stderr, "%s%s", + (j == NFTYPES-1) ? " or " : " ", + frame_types[j].ft_name); + } + fprintf(stderr, ".\n"); + return -1; +} + +int +ipx_add_interface(int argc, char **argv) +{ + struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)&id.ifr_addr; + int s; + int result; + unsigned long netnum; + char errmsg[80]; + int i, fti = 0; + char c; + + sipx->sipx_special = IPX_SPECIAL_NONE; + sipx->sipx_network = 0L; + sipx->sipx_type = IPX_FRAME_NONE; + while ((c = getopt(argc, argv, "p")) > 0) { + switch (c) { + case 'p': sipx->sipx_special = IPX_PRIMARY; break; + } + } + + if (((i = (argc - optind)) < 2) || (i > 3)) { + usage(); + } + + for (i = optind; i < argc; i++) { + switch (i-optind) { + case 0: /* Physical Device - Required */ + strcpy(id.ifr_name, argv[i]); + break; + case 1: /* Frame Type - Required */ + fti = lookup_frame_type(argv[i]); + if (fti < 0) + exit(-1); + sipx->sipx_type = frame_types[fti].ft_val; + break; + + case 2: /* Network Number - Optional */ + netnum = strtoul(argv[i], (char **)NULL, 16); + if (netnum == 0xffffffffL) { + fprintf(stderr, + "%s: Inappropriate network number %08lX\n", + progname, netnum); + exit(-1); + } + sipx->sipx_network = htonl(netnum); + break; + } + } + + s = socket(AF_IPX, SOCK_DGRAM, AF_IPX); + if (s < 0) { + sprintf(errmsg, "%s: socket", progname); + perror(errmsg); + exit(-1); + } + + i = 0; + sipx->sipx_family = AF_IPX; + sipx->sipx_action = IPX_CRTITF; + do { + result = ioctl(s, SIOCSIFADDR, &id); + i++; + } while ((i < 5) && (result < 0) && (errno == EAGAIN)); + + if (result == 0) exit(0); + + switch (errno) { + case EEXIST: + fprintf(stderr, "%s: Primary network already selected.\n", + progname); + break; + case EADDRINUSE: + fprintf(stderr, "%s: Network number (%08lX) already in use.\n", + progname, htonl(sipx->sipx_network)); + break; + case EPROTONOSUPPORT: + fprintf(stderr, "%s: Invalid frame type (%s).\n", + progname, frame_types[fti].ft_name); + break; + case ENODEV: + fprintf(stderr, "%s: No such device (%s).\n", progname, + id.ifr_name); + break; + case ENETDOWN: + fprintf(stderr, "%s: Requested device (%s) is down.\n", progname, + id.ifr_name); + break; + case EINVAL: + fprintf(stderr, "%s: Invalid device (%s).\n", progname, + id.ifr_name); + break; + case EAGAIN: + fprintf(stderr, + "%s: Insufficient memory to create interface.\n", + progname); + break; + default: + sprintf(errmsg, "%s: ioctl", progname); + perror(errmsg); + break; + } + exit(-1); +} + +int +ipx_del_interface(int argc, char **argv) +{ + struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)&id.ifr_addr; + int s; + int result; + char errmsg[80]; + int fti; + + if (argc != 3) { + usage(); + } + + sipx->sipx_network = 0L; + strcpy(id.ifr_name, argv[1]); + fti = lookup_frame_type(argv[2]); + if (fti < 0) + exit(-1); + sipx->sipx_type = frame_types[fti].ft_val; + + s = socket(AF_IPX, SOCK_DGRAM, AF_IPX); + if (s < 0) { + sprintf(errmsg, "%s: socket", progname); + perror(errmsg); + exit(-1); + } + sipx->sipx_action = IPX_DLTITF; + sipx->sipx_family = AF_IPX; + result = ioctl(s, SIOCSIFADDR, &id); + if (result == 0) exit(0); + + switch (errno) { + case EPROTONOSUPPORT: + fprintf(stderr, "%s: Invalid frame type (%s).\n", + progname, frame_types[fti].ft_name); + break; + case ENODEV: + fprintf(stderr, "%s: No such device (%s).\n", progname, + id.ifr_name); + break; + case EINVAL: + fprintf(stderr, "%s: No such IPX interface %s %s.\n", progname, + id.ifr_name, frame_types[fti].ft_name); + break; + default: + sprintf(errmsg, "%s: ioctl", progname); + perror(errmsg); + break; + } + exit(-1); +} + +int +ipx_check_interface(int argc, char **argv) +{ + struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)&id.ifr_addr; + int s; + int result; + char errmsg[80]; + int fti; + + if (argc != 3) { + usage(); + } + + sipx->sipx_network = 0L; + strcpy(id.ifr_name, argv[1]); + fti = lookup_frame_type(argv[2]); + if (fti < 0) + exit(-1); + sipx->sipx_type = frame_types[fti].ft_val; + + s = socket(AF_IPX, SOCK_DGRAM, AF_IPX); + if (s < 0) { + sprintf(errmsg, "%s: socket", progname); + perror(errmsg); + exit(-1); + } + sipx->sipx_family = AF_IPX; + result = ioctl(s, SIOCGIFADDR, &id); + if (result == 0) { + printf( + "IPX Address for (%s, %s) is %08lX:%02X%02X%02X%02X%02X%02X.\n", + argv[1], frame_types[fti].ft_name, + htonl(sipx->sipx_network), sipx->sipx_node[0], + sipx->sipx_node[1], sipx->sipx_node[2], + sipx->sipx_node[3], sipx->sipx_node[4], + sipx->sipx_node[5]); + exit(0); + } + + switch (errno) { + case EPROTONOSUPPORT: + fprintf(stderr, "%s: Invalid frame type (%s).\n", + progname, frame_types[fti].ft_name); + break; + case ENODEV: + fprintf(stderr, "%s: No such device (%s).\n", progname, + id.ifr_name); + break; + case EADDRNOTAVAIL: + fprintf(stderr, "%s: No such IPX interface %s %s.\n", progname, + id.ifr_name, frame_types[fti].ft_name); + break; + default: + sprintf(errmsg, "%s: ioctl", progname); + perror(errmsg); + break; + } + exit(-1); +} + +int +main(int argc, char **argv) +{ + int i; + + progname = argv[0]; + if (argc < 2) { + usage(); + exit(-1); + } + + if (strncasecmp(argv[1], "add", 3) == 0) { + for (i = 1; i < (argc-1); i++) + argv[i] = argv[i+1]; + ipx_add_interface(argc-1, argv); + } else if (strncasecmp(argv[1], "del", 3) == 0) { + for (i = 1; i < (argc-1); i++) + argv[i] = argv[i+1]; + ipx_del_interface(argc-1, argv); + } else if (strncasecmp(argv[1], "check", 5) == 0) { + for (i = 1; i < (argc-1); i++) + argv[i] = argv[i+1]; + ipx_check_interface(argc-1, argv); + } + usage(); + return 0; +} diff --git a/ipx-0.75/ipx_internal_net.c b/ipx-0.75/ipx_internal_net.c new file mode 100644 index 0000000..54cb234 --- /dev/null +++ b/ipx-0.75/ipx_internal_net.c @@ -0,0 +1,195 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct ifreq id; +static char *progname; + +void +usage(void) +{ + fprintf(stderr, "Usage: %s add net_number(hex) node(hex)\n\ +Usage: %s del\n", progname, progname); + exit(-1); +} + +int +map_char_to_val(char dig) +{ + char digit = tolower(dig); + if ((digit >= '0') && (digit <= '9')) { + return digit - '0'; + } else if ((digit >= 'a') && (digit <= 'f')) { + return (10 + (digit - 'a')); + } else { + return 0; + } +} + +int +ipx_add_internal_net(int argc, char **argv) +{ + struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)&id.ifr_addr; + int s; + int result; + unsigned long netnum; + char errmsg[80]; + int nodelen; + char *node; + char tmpnode[13]; + unsigned char *tout; + char *tin; + int i; + + if (argc != 3) { + usage(); + } + + netnum = strtoul(argv[1], (char **)NULL, 16); + if ((netnum == 0L) || (netnum == 0xffffffffL)) { + fprintf(stderr, "%s: Inappropriate network number %08lX\n", + progname, netnum); + exit(-1); + } + + node = argv[2]; + nodelen = strlen(node); + if (nodelen > 12) { + fprintf(stderr, "%s: Node length is too long (> 12).\n", progname); + exit(-1); + } + + for (i = 0; (i < nodelen) && isxdigit(node[i]); i++) + ; + + if (i < nodelen) { + fprintf(stderr, "%s: Invalid value in node, must be hex digits.\n", + progname); + exit(-1); + } + + strcpy(tmpnode, "000000000000"); + memcpy(&(tmpnode[12-nodelen]), node, nodelen); + for (tin = tmpnode, tout = sipx->sipx_node; *tin != '\0'; tin += 2, tout++) { + *tout = (unsigned char) map_char_to_val(*tin); + *tout <<= 4; + *tout |= (unsigned char) map_char_to_val(*(tin+1)); + } + + if ((memcmp(sipx->sipx_node, "\0\0\0\0\0\0\0\0", IPX_NODE_LEN) == 0) || + (memcmp(sipx->sipx_node, "\377\377\377\377\377\377", IPX_NODE_LEN) == 0)){ + fprintf(stderr, "%s: Node is invalid.\n", progname); + exit(-1); + } + + sipx->sipx_network = htonl(netnum); + sipx->sipx_type = IPX_FRAME_NONE; + sipx->sipx_special = IPX_INTERNAL; + s = socket(AF_IPX, SOCK_DGRAM, AF_IPX); + if (s < 0) { + sprintf(errmsg, "%s: socket", progname); + perror(errmsg); + exit(-1); + } + + sipx->sipx_family = AF_IPX; + sipx->sipx_action = IPX_CRTITF; + i = 0; + do { + result = ioctl(s, SIOCSIFADDR, &id); + i++; + } while ((i < 5) && (result < 0) && (errno == EAGAIN)); + + if (result == 0) exit(0); + + switch (errno) { + case EEXIST: + fprintf(stderr, "%s: Primary network already selected.\n", + progname); + break; + case EADDRINUSE: + fprintf(stderr, "%s: Network number (%08lX) already in use.\n", + progname, htonl(sipx->sipx_network)); + break; + case EAGAIN: + fprintf(stderr, + "%s: Insufficient memory to create internal net.\n", + progname); + break; + default: + sprintf(errmsg, "%s: ioctl", progname); + perror(errmsg); + break; + } + exit(-1); +} + +int +ipx_del_internal_net(int argc, char **argv) +{ + struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)&id.ifr_addr; + int s; + int result; + char errmsg[80]; + + if (argc != 1) { + usage(); + } + + sipx->sipx_network = 0L; + sipx->sipx_special = IPX_INTERNAL; + s = socket(AF_IPX, SOCK_DGRAM, AF_IPX); + if (s < 0) { + sprintf(errmsg, "%s: socket", progname); + perror(errmsg); + exit(-1); + } + sipx->sipx_family = AF_IPX; + sipx->sipx_action = IPX_DLTITF; + result = ioctl(s, SIOCSIFADDR, &id); + if (result == 0) exit(0); + + switch (errno) { + case ENOENT: + fprintf(stderr, "%s: No internal network configured.\n", progname); + break; + default: + sprintf(errmsg, "%s: ioctl", progname); + perror(errmsg); + break; + } + exit(-1); +} + +int +main(int argc, char **argv) +{ + int i; + + progname = argv[0]; + if (argc < 2) { + usage(); + exit(-1); + } + + if (strncasecmp(argv[1], "add", 3) == 0) { + for (i = 1; i < (argc-1); i++) + argv[i] = argv[i+1]; + ipx_add_internal_net(argc-1, argv); + } else if (strncasecmp(argv[1], "del", 3) == 0) { + for (i = 1; i < (argc-1); i++) + argv[i] = argv[i+1]; + ipx_del_internal_net(argc-1, argv); + } + usage(); + return 0; +} + diff --git a/ipx-0.75/ipx_route.c b/ipx-0.75/ipx_route.c new file mode 100644 index 0000000..1e991c0 --- /dev/null +++ b/ipx-0.75/ipx_route.c @@ -0,0 +1,215 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct rtentry rd; +static char *progname; + +int +map_char_to_val(char dig) +{ + char digit = tolower(dig); + if ((digit >= '0') && (digit <= '9')) { + return digit - '0'; + } else if ((digit >= 'a') && (digit <= 'f')) { + return (10 + (digit - 'a')); + } else { + return 0; + } +} + +void +usage(void) +{ + fprintf(stderr, + "Usage: %s add network(hex) router_network(hex) router_node(hex)\n\ +Usage: %s del network(hex)\n", progname, progname); + exit(-1); +} + +int +ipx_add_route(int argc, char **argv) +{ + /* Router */ + struct sockaddr_ipx *sr = (struct sockaddr_ipx *)&rd.rt_gateway; + /* Target */ + struct sockaddr_ipx *st = (struct sockaddr_ipx *)&rd.rt_dst; + int s; + int result; + int nodelen; + int i; + unsigned long netnum; + char errmsg[80]; + char *node; + char *tin; + char tmpnode[13]; + unsigned char *tout; + + if (argc != 4) + usage(); + + /* Network Number */ + netnum = strtoul(argv[1], (char **)NULL, 16); + if ((netnum == 0xffffffffL) || (netnum == 0L)) { + fprintf(stderr, "%s: Inappropriate network number %08lX\n", + progname, netnum); + exit(-1); + } + rd.rt_flags = RTF_GATEWAY; + st->sipx_network = htonl(netnum); + + /* Router Network Number */ + netnum = strtoul(argv[2], (char **)NULL, 16); + if ((netnum == 0xffffffffL) || (netnum == 0L)) { + fprintf(stderr, "%s: Inappropriate network number %08lX\n", + progname, netnum); + exit(-1); + } + sr->sipx_network = htonl(netnum); + + /* Router Node */ + node = argv[3]; + nodelen = strlen(node); + if (nodelen > 12) { + fprintf(stderr, "%s: Node length is too long (> 12).\n", + progname); + exit(-1); + } + + for (i = 0; (i < nodelen) && isxdigit(node[i]); i++) + ; + + if (i < nodelen) { + fprintf(stderr, "%s: Invalid value in node, must be hex digits.\n", + progname); + exit(-1); + } + + strcpy(tmpnode, "000000000000"); + memcpy(&(tmpnode[12-nodelen]), node, nodelen); + for (tin = tmpnode, tout = sr->sipx_node; *tin != '\0'; tin += 2, tout++) { + *tout = (unsigned char) map_char_to_val(*tin); + *tout <<= 4; + *tout |= (unsigned char) map_char_to_val(*(tin+1)); + } + + if ((memcmp(sr->sipx_node, "\0\0\0\0\0\0\0\0", IPX_NODE_LEN) == 0) || + (memcmp(sr->sipx_node, "\377\377\377\377\377\377", IPX_NODE_LEN) == 0)){ + fprintf(stderr, "%s: Node (%s) is invalid.\n", progname, tmpnode); + exit(-1); + } + + s = socket(AF_IPX, SOCK_DGRAM, AF_IPX); + if (s < 0) { + sprintf(errmsg, "%s: socket", progname); + perror(errmsg); + exit(-1); + } + + sr->sipx_family = st->sipx_family = AF_IPX; + i = 0; + do { + result = ioctl(s, SIOCADDRT, &rd); + i++; + } while ((i < 5) && (result < 0) && (errno == EAGAIN)); + + if (result == 0) exit(0); + + switch (errno) { + case ENETUNREACH: + fprintf(stderr, "%s: Router network (%08lX) not reachable.\n", + progname, htonl(sr->sipx_network)); + break; + default: + sprintf(errmsg, "%s: ioctl", progname); + perror(errmsg); + break; + } + exit(-1); +} + +int +ipx_del_route(int argc, char **argv) +{ + /* Router */ + struct sockaddr_ipx *sr = (struct sockaddr_ipx *)&rd.rt_gateway; + /* Target */ + struct sockaddr_ipx *st = (struct sockaddr_ipx *)&rd.rt_dst; + int s; + int result; + unsigned long netnum; + char errmsg[80]; + + if (argc != 2) { + usage(); + } + + rd.rt_flags = RTF_GATEWAY; + /* Network Number */ + netnum = strtoul(argv[1], (char **)NULL, 16); + if ((netnum == 0xffffffffL) || (netnum == 0L)) { + fprintf(stderr, "%s: Inappropriate network number %08lX.\n", + progname, netnum); + exit(-1); + } + st->sipx_network = htonl(netnum); + + st->sipx_family = sr->sipx_family = AF_IPX; + s = socket(AF_IPX, SOCK_DGRAM, AF_IPX); + if (s < 0) { + sprintf(errmsg, "%s: socket", progname); + perror(errmsg); + exit(-1); + } + result = ioctl(s, SIOCDELRT, &rd); + if (result == 0) exit(0); + + switch (errno) { + case ENOENT: + fprintf(stderr, "%s: Route not found for network %08lX.\n", + progname, netnum); + break; + case EPERM: + fprintf(stderr, "%s: Network %08lX is directly connected.\n", + progname, netnum); + break; + default: + sprintf(errmsg, "%s: ioctl", progname); + perror(errmsg); + break; + } + exit(-1); +} + +int +main(int argc, char **argv) +{ + int i; + + progname = argv[0]; + if (argc < 2) { + usage(); + exit(-1); + } + + if (strncasecmp(argv[1], "add", 3) == 0) { + for (i = 1; i < (argc-1); i++) + argv[i] = argv[i+1]; + ipx_add_route(argc-1, argv); + } else if (strncasecmp(argv[1], "del", 3) == 0) { + for (i = 1; i < (argc-1); i++) + argv[i] = argv[i+1]; + ipx_del_route(argc-1, argv); + } + usage(); + return 0; +} diff --git a/ipx-0.75/ipxrcv.c b/ipx-0.75/ipxrcv.c new file mode 100644 index 0000000..2a71e64 --- /dev/null +++ b/ipx-0.75/ipxrcv.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include +#include + +int +main(int argc, char **argv) +{ + struct sockaddr_ipx sipx; + int s; + int result; + char msg[100]; + int len; + + s = socket(AF_IPX, SOCK_DGRAM, AF_IPX); + if (s < 0) { + perror("IPX: socket: "); + exit(-1); + } + sipx.sipx_family = AF_IPX; + sipx.sipx_network = 0; + sipx.sipx_port = htons(0x5000); + sipx.sipx_type = 17; + len = sizeof(sipx); + result = bind(s, (struct sockaddr *)&sipx, sizeof(sipx)); + if (result < 0) { + perror("IPX: bind: "); + exit(-1); + } + + msg[0] = '\0'; + result = recvfrom(s, msg, sizeof(msg), 0, (struct sockaddr *)&sipx, + &len); + if (result < 0) { + perror("IPX: recvfrom: "); + } + + printf("From %08lX:%02X%02X%02X%02X%02X%02X:%04X\n", + htonl(sipx.sipx_network), + sipx.sipx_node[0], sipx.sipx_node[1], + sipx.sipx_node[2], sipx.sipx_node[3], + sipx.sipx_node[4], sipx.sipx_node[5], + htons(sipx.sipx_port)); + printf("\tGot \"%s\"\n", msg); + return 0; +} + + + + diff --git a/ipx-0.75/ipxsend.c b/ipx-0.75/ipxsend.c new file mode 100644 index 0000000..f999fee --- /dev/null +++ b/ipx-0.75/ipxsend.c @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include +#include + +int +main(int argc, char **argv) +{ + struct sockaddr_ipx sipx; + int s; + int result; + char msg[100] = "Hi Mom"; + int len = sizeof(sipx); + + s = socket(AF_IPX, SOCK_DGRAM, AF_IPX); + if (s < 0) { + perror("IPX: socket: "); + exit(-1); + } + sipx.sipx_family = AF_IPX; + sipx.sipx_network = 0; + sipx.sipx_port = 0; + sipx.sipx_type = 17; + + result = bind(s, (struct sockaddr *)&sipx, sizeof(sipx)); + if (result < 0) { + perror("IPX: bind: "); + exit(-1); + } + + result = getsockname(s, (struct sockaddr *)&sipx, &len); + sipx.sipx_port = htons(0x5000); + result = sendto(s, msg, sizeof(msg), 0, (struct sockaddr *)&sipx, + sizeof(sipx)); + if (result < 0) { + perror("IPX: send: "); + exit(-1); + } + return 0; +} + + + + diff --git a/ipx-0.75/rip.c b/ipx-0.75/rip.c new file mode 100644 index 0000000..762df7d --- /dev/null +++ b/ipx-0.75/rip.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include +#include + +struct rip_data { + unsigned long rip_net; + unsigned short rip_hops __attribute__ ((packed)); + unsigned short rip_ticks __attribute__ ((packed)); +}; + +int +main(int argc, char **argv) +{ + struct sockaddr_ipx sipx; + int result; + int s; + char msg[1024]; + int len; + char *bptr; + struct rip_data *rp; + + s = socket(AF_IPX, SOCK_DGRAM, AF_IPX); + if (s < 0) { + perror("IPX: socket: "); + exit(-1); + } + sipx.sipx_family = AF_IPX; + sipx.sipx_network = 0; + sipx.sipx_port = htons(0x453); + sipx.sipx_type = 17; + result = bind(s, (struct sockaddr *)&sipx, sizeof(sipx)); + if (result < 0) { + perror("IPX: bind: "); + exit(-1); + } + + while (1) { + len = sizeof(sipx); + result = recvfrom(s, msg, sizeof(msg), 0, + (struct sockaddr *)&sipx, &len); + if (result < 0) { + perror("IPX: recvfrom"); + exit(-1); + } + bptr = msg; + result -= 2; + printf("RIP packet from: %08lX:%02X%02X%02X%02X%02X%02X\n", + htonl(sipx.sipx_network), + sipx.sipx_node[0], sipx.sipx_node[1], + sipx.sipx_node[2], sipx.sipx_node[3], + sipx.sipx_node[4], sipx.sipx_node[5]); + bptr += 2; + rp = (struct rip_data *) bptr; + while (result >= sizeof(struct rip_data)) { + printf("\tNET: %08lX HOPS: %d\n", ntohl(rp->rip_net), + ntohs(rp->rip_hops)); + result -= sizeof(struct rip_data); + rp++; + } + } +} + + + + diff --git a/ipx-0.75/sap.c b/ipx-0.75/sap.c new file mode 100644 index 0000000..594e52d --- /dev/null +++ b/ipx-0.75/sap.c @@ -0,0 +1,96 @@ +#include +#include +#include +#include +#include +#include + + +struct sap_data { + unsigned short sap_type __attribute__ ((packed)); + char sap_name[48] __attribute__ ((packed)); + unsigned long sap_net __attribute__ ((packed)); + unsigned char sap_node[6] __attribute__ ((packed)); + unsigned short sap_sock __attribute__ ((packed)); + unsigned short sap_hops __attribute__ ((packed)); +}; + +int +main(int argc, char **argv) +{ + int s; + int result; + struct sockaddr_ipx sipx; + char msg[1024]; + long val = 0; + int len; + char *bptr; + struct sap_data *sp; + + s = socket(AF_IPX, SOCK_DGRAM, AF_IPX); + if (s < 0) { + perror("IPX: socket: "); + exit(-1); + } + + result = setsockopt(s, SOL_SOCKET, SO_DEBUG, &val, 4); + if (result < 0) { + perror("IPX: setsockopt: "); + exit(-1); + } + + sipx.sipx_family = PF_IPX; + sipx.sipx_network = 0L; + sipx.sipx_port = htons(0x452); + sipx.sipx_type = 17; + + result = bind(s, (struct sockaddr *)&sipx, sizeof(sipx)); + if (result < 0) { + perror("IPX: bind: "); + exit(-1); + } + + while (1) { + len = 1024; + result = recvfrom(s, msg, sizeof(msg), 0, + (struct sockaddr *)&sipx, &len); + if (result < 0) { + perror("IPX: recvfrom: "); + exit(-1); + } + bptr = msg; + result -= 2; + printf("SAP: OP is %x %x\n", bptr[0], bptr[1]); + printf("Length is %d\n", result); + if (bptr[1] != 2) + continue; + + bptr += 2; + sp = (struct sap_data *) bptr; + while (result >= sizeof(struct sap_data)) { + int i; + + sp->sap_name[32] = '\0'; + for (i = 31; (i > 0) && (sp->sap_name[i] == '_'); i--); + i++; + sp->sap_name[i] = '\0'; + printf("NAME: %s TYPE: %x HOPS: %x\n", sp->sap_name, + ntohs(sp->sap_type), ntohs(sp->sap_hops)); + printf("%lx:%x %x %x %x %x %x: %x\n", + ntohl(sp->sap_net), + sp->sap_node[0], + sp->sap_node[1], + sp->sap_node[2], + sp->sap_node[3], + sp->sap_node[4], + sp->sap_node[5], + ntohs(sp->sap_sock)); + result -= sizeof(struct sap_data); + sp++; + } + } +} + + + + diff --git a/kernel-1.2/linux/ncp.h b/kernel-1.2/linux/ncp.h index 83ffefd..895c5ae 100644 --- a/kernel-1.2/linux/ncp.h +++ b/kernel-1.2/linux/ncp.h @@ -9,6 +9,7 @@ #define _LINUX_NCP_H #include +#include #define NCP_PTYPE (0x11) #define NCP_PORT (0x0451) @@ -51,6 +52,9 @@ struct ncp_bindery_object { __u32 object_id; __u16 object_type; __u8 object_name[NCP_BINDERY_NAME_LEN]; + __u8 object_flags; + __u8 object_security; + __u8 object_has_prop; }; struct nw_property { @@ -59,6 +63,11 @@ struct nw_property { __u8 property_flag; }; +struct prop_net_address { + __u32 network __attribute__ ((packed)); + __u8 node[IPX_NODE_LEN] __attribute__ ((packed)); + __u16 port __attribute__ ((packed)); +}; #define NCP_VOLNAME_LEN (16) #define NCP_NUMBER_OF_VOLUMES (64) @@ -263,16 +272,23 @@ struct queue_job { /* ClientRecordArea for print jobs */ +#define KEEP_ON 0x0400 +#define NO_FORM_FEED 0x0800 +#define NOTIFICATION 0x1000 +#define DELETE_FILE 0x2000 +#define EXPAND_TABS 0x4000 +#define PRINT_BANNER 0x8000 + struct print_job_record { __u8 Version __attribute__ ((packed)); - __u16 TabSize __attribute__ ((packed)); + __u8 TabSize __attribute__ ((packed)); __u16 Copies __attribute__ ((packed)); - __u8 CtrlFlags __attribute__ ((packed)); + __u16 CtrlFlags __attribute__ ((packed)); __u16 Lines __attribute__ ((packed)); __u16 Rows __attribute__ ((packed)); char FormName[16] __attribute__ ((packed)); __u8 Reserved[6] __attribute__ ((packed)); - char Banner[13] __attribute__ ((packed)); + char BannerName[13] __attribute__ ((packed)); char FnameBanner[13] __attribute__ ((packed)); char FnameHeader[14] __attribute__ ((packed)); char Path[80] __attribute__ ((packed)); diff --git a/kernel-1.2/src/Makefile b/kernel-1.2/src/Makefile index 7477eb1..d52c0f1 100644 --- a/kernel-1.2/src/Makefile +++ b/kernel-1.2/src/Makefile @@ -20,14 +20,14 @@ ARCH = i386 .s.o: $(AS) -o $*.o $< -OBJS= dir.o inode.o file.o sock.o ioctl.o ncplib.o +OBJS= dir.o inode.o file.o sock.o ioctl.o ncplib_kernel.o all: ncpfs.o ncpfs.o: $(OBJS) $(LD) -r -o ncpfs.o $(OBJS) -ncplib.o: ncplib.c ncplib.h +ncplib_kernel.o: ncplib_kernel.c ncplib_kernel.h $(CC) $(CFLAGS) -finline-functions -c $< dep: diff --git a/kernel-1.2/src/dir.c b/kernel-1.2/src/dir.c index 070afe0..eca38ba 100644 --- a/kernel-1.2/src/dir.c +++ b/kernel-1.2/src/dir.c @@ -23,7 +23,7 @@ #include #include #include -#include "ncplib.h" +#include "ncplib_kernel.h" struct ncp_dirent { struct nw_info_struct i; diff --git a/kernel-1.2/src/file.c b/kernel-1.2/src/file.c index 0ad8185..c2f0b95 100644 --- a/kernel-1.2/src/file.c +++ b/kernel-1.2/src/file.c @@ -26,7 +26,7 @@ #include #include #include -#include "ncplib.h" +#include "ncplib_kernel.h" #include static int diff --git a/kernel-1.2/src/inode.c b/kernel-1.2/src/inode.c index 780aa08..7bc5459 100644 --- a/kernel-1.2/src/inode.c +++ b/kernel-1.2/src/inode.c @@ -27,7 +27,7 @@ #include #include #include -#include "ncplib.h" +#include "ncplib_kernel.h" extern int close_fp(struct file *filp); diff --git a/kernel-1.2/src/ncplib.c b/kernel-1.2/src/ncplib_kernel.c similarity index 99% rename from kernel-1.2/src/ncplib.c rename to kernel-1.2/src/ncplib_kernel.c index f751233..a614c3b 100644 --- a/kernel-1.2/src/ncplib.c +++ b/kernel-1.2/src/ncplib_kernel.c @@ -9,7 +9,7 @@ -#include "ncplib.h" +#include "ncplib_kernel.h" typedef __u8 byte; typedef __u16 word; diff --git a/kernel-1.2/src/ncplib.h b/kernel-1.2/src/ncplib_kernel.h similarity index 100% rename from kernel-1.2/src/ncplib.h rename to kernel-1.2/src/ncplib_kernel.h diff --git a/kernel-1.3/linux/ncp.h b/kernel-1.3/linux/ncp.h index 6a9627d..df1772e 100644 --- a/kernel-1.3/linux/ncp.h +++ b/kernel-1.3/linux/ncp.h @@ -11,6 +11,7 @@ #error "Please use kernel 1.2.13" #include +#include #define NCP_PTYPE (0x11) #define NCP_PORT (0x0451) @@ -53,6 +54,9 @@ struct ncp_bindery_object { __u32 object_id; __u16 object_type; __u8 object_name[NCP_BINDERY_NAME_LEN]; + __u8 object_flags; + __u8 object_security; + __u8 object_has_prop; }; struct nw_property { @@ -61,6 +65,11 @@ struct nw_property { __u8 property_flag; }; +struct prop_net_address { + __u32 network __attribute__ ((packed)); + __u8 node[IPX_NODE_LEN] __attribute__ ((packed)); + __u16 port __attribute__ ((packed)); +}; #define NCP_VOLNAME_LEN (16) #define NCP_NUMBER_OF_VOLUMES (64) @@ -265,16 +274,23 @@ struct queue_job { /* ClientRecordArea for print jobs */ +#define KEEP_ON 0x0400 +#define NO_FORM_FEED 0x0800 +#define NOTIFICATION 0x1000 +#define DELETE_FILE 0x2000 +#define EXPAND_TABS 0x4000 +#define PRINT_BANNER 0x8000 + struct print_job_record { __u8 Version __attribute__ ((packed)); - __u16 TabSize __attribute__ ((packed)); + __u8 TabSize __attribute__ ((packed)); __u16 Copies __attribute__ ((packed)); - __u8 CtrlFlags __attribute__ ((packed)); + __u16 CtrlFlags __attribute__ ((packed)); __u16 Lines __attribute__ ((packed)); __u16 Rows __attribute__ ((packed)); char FormName[16] __attribute__ ((packed)); __u8 Reserved[6] __attribute__ ((packed)); - char Banner[13] __attribute__ ((packed)); + char BannerName[13] __attribute__ ((packed)); char FnameBanner[13] __attribute__ ((packed)); char FnameHeader[14] __attribute__ ((packed)); char Path[80] __attribute__ ((packed)); diff --git a/kernel-1.3/src/Makefile b/kernel-1.3/src/Makefile index 7477eb1..d52c0f1 100644 --- a/kernel-1.3/src/Makefile +++ b/kernel-1.3/src/Makefile @@ -20,14 +20,14 @@ ARCH = i386 .s.o: $(AS) -o $*.o $< -OBJS= dir.o inode.o file.o sock.o ioctl.o ncplib.o +OBJS= dir.o inode.o file.o sock.o ioctl.o ncplib_kernel.o all: ncpfs.o ncpfs.o: $(OBJS) $(LD) -r -o ncpfs.o $(OBJS) -ncplib.o: ncplib.c ncplib.h +ncplib_kernel.o: ncplib_kernel.c ncplib_kernel.h $(CC) $(CFLAGS) -finline-functions -c $< dep: diff --git a/kernel-1.3/src/dir.c b/kernel-1.3/src/dir.c index 4f1f9b2..c419466 100644 --- a/kernel-1.3/src/dir.c +++ b/kernel-1.3/src/dir.c @@ -14,7 +14,7 @@ #include #include #include -#include "ncplib.h" +#include "ncplib_kernel.h" struct ncp_dirent { struct nw_info_struct i; diff --git a/kernel-1.3/src/file.c b/kernel-1.3/src/file.c index 6d40afc..fb125f8 100644 --- a/kernel-1.3/src/file.c +++ b/kernel-1.3/src/file.c @@ -15,7 +15,7 @@ #include #include #include -#include "ncplib.h" +#include "ncplib_kernel.h" #include static int diff --git a/kernel-1.3/src/inode.c b/kernel-1.3/src/inode.c index 517690f..1254622 100644 --- a/kernel-1.3/src/inode.c +++ b/kernel-1.3/src/inode.c @@ -20,7 +20,7 @@ #include #include #include -#include "ncplib.h" +#include "ncplib_kernel.h" extern int close_fp(struct file *filp); @@ -142,7 +142,7 @@ ncp_put_inode(struct inode *inode) printk("ncp_put_inode: could not close\n"); } } - + DDPRINTK("ncp_put_inode: put %s\n", finfo->i.entryName); diff --git a/kernel-1.3/src/ncplib.c b/kernel-1.3/src/ncplib_kernel.c similarity index 99% rename from kernel-1.3/src/ncplib.c rename to kernel-1.3/src/ncplib_kernel.c index 7a14317..7947199 100644 --- a/kernel-1.3/src/ncplib.c +++ b/kernel-1.3/src/ncplib_kernel.c @@ -1,4 +1,4 @@ -#include "ncplib.h" +#include "ncplib_kernel.h" typedef __u8 byte; typedef __u16 word; diff --git a/kernel-1.3/src/ncplib.h b/kernel-1.3/src/ncplib_kernel.h similarity index 100% rename from kernel-1.3/src/ncplib.h rename to kernel-1.3/src/ncplib_kernel.h diff --git a/man/ipx_interface.8 b/man/ipx_interface.8 new file mode 100644 index 0000000..55eae22 --- /dev/null +++ b/man/ipx_interface.8 @@ -0,0 +1,61 @@ +.TH IPX_INTERFACE 8 "IPX Utilities" "Caldera, Inc." +.SH NAME +ipx_interface \- add, delete, or display an IPX interface +.SH SYNOPSIS +.B ipx_interface +add [-p] device frame_type [network number] +.LP +.B ipx_interface +del device frame_type +.LP +.B ipx_interface +check device frame_type +.LP +.B ipx_interface +help +.SH DESCRIPTION +.B ipx_interface +adds, deletes, or displays IPX interfaces depending on the option selected. +.P +An IPX interface is the item to which IPX sockets are bound. +An IPX interface corresponds to an IPX Network Number which corresponds +to a physical device and frame type. A sample IPX Interface would be: +.LP +Network Number: 0x00ABCDEF +.LP +Device: Eth0 +.LP +Frame Type: 802.2. +.P +There is a special IPX interface per host known as the +.B PRIMARY +or default interface. +.SS OPTIONS +.TP +.I add +This option is used to create an IPX interface. If the +.B -p +flag is used, the interface is made +.B +PRIMARY. +The network number can be optionally assigned. If it is not assigned, it +is set to 0 which indicates it should be detected from the traffic on the +network. +.TP +.I del +This option is used to delete an IPX interface. +.TP +.I check +This option is used to display the device, frame type, and network number +of an IPX interface. +.TP +.I help +This option displays information about the utility. +.SH FILES +.I /proc/net/ipx_interface /proc/net/ipx_route +.SH BUGS +This functionality really belongs in +.B +ifconfig(8). +.SH AUTHOR +Greg Page diff --git a/man/ipx_internal_net.8 b/man/ipx_internal_net.8 new file mode 100644 index 0000000..fbe21ef --- /dev/null +++ b/man/ipx_internal_net.8 @@ -0,0 +1,32 @@ +.TH IPX_INTERNAL_NET 8 "IPX Utilities" "Caldera, Inc." +.SH NAME +ipx_internal_net \- add or delete the IPX internal network +.SH SYNOPSIS +.B ipx_internal_net +add network_number node_number +.LP +.B ipx_internal_net +del +.SH DESCRIPTION +.B ipx_internal_net +adds or deletes the IPX internal network. +An IPX internal network is a special kind of IPX interface that does +not have a physical device or frame type. It is used to provide +a route-independent address for service providers. Internal networks +are optional; however, when one is present it is also the +Primary Interface. There can only be one internal network per host. +.SS OPTIONS +.TP +.I add +This option is used to create the IPX internal network. +.TP +.I del +This option is used to delete the IPX internal network. +.SH FILES +.I /proc/net/ipx_interface /proc/net/ipx_route +.SH BUGS +This functionality really belongs in +.B +ifconfig(8). +.SH AUTHOR +Greg Page diff --git a/man/ipx_route.8 b/man/ipx_route.8 new file mode 100644 index 0000000..2f8eb3e --- /dev/null +++ b/man/ipx_route.8 @@ -0,0 +1,24 @@ +.TH IPX_ROUTE 8 "IPX Utilities" "Caldera, Inc." +.SH NAME +ipx_route \- add or delete IPX route +.SH SYNOPSIS +.B ipx_route +add target_network router_network router_node +.LP +.B ipx_route +del target_network +.SH DESCRIPTION +.B ipx_route +adds or deletes an IPX route. +The kernel IPX stores only one route per target network at a time. +.SS OPTIONS +.TP +.I add +This option is used to set up the route to a target network. +.TP +.I del +This option is used to delete the route to a target network. +.SH FILES +.I /proc/net/ipx_interface /proc/net/ipx_route +.SH AUTHOR +Greg Page diff --git a/man/ncpmount.8 b/man/ncpmount.8 index a168c3c..53e9b21 100644 --- a/man/ncpmount.8 +++ b/man/ncpmount.8 @@ -1,4 +1,4 @@ -.TH NCPMOUNT 8 25/11/1995 ncpmount ncpmount +.TH NCPMOUNT 8 11/25/1995 ncpmount ncpmount .SH NAME ncpmount \- mount program for ncpfs .SH SYNOPSIS diff --git a/man/ncpumount.8 b/man/ncpumount.8 index 6724407..633ecb6 100644 --- a/man/ncpumount.8 +++ b/man/ncpumount.8 @@ -1,4 +1,4 @@ -.TH NCPUMOUNT 8 25/11/1995 ncpumount ncpumount +.TH NCPUMOUNT 8 11/25/1995 ncpumount ncpumount .SH NAME ncpumount \- umount for normal users .SH SYNOPSIS diff --git a/man/slist.1 b/man/slist.1 new file mode 100644 index 0000000..539b148 --- /dev/null +++ b/man/slist.1 @@ -0,0 +1,44 @@ +.TH SLIST 1 12/02/1995 slist slist +.SH NAME +slist \- list all know NetWare file servers +.SH SYNOPSIS +.B slist +[pattern] + +.SH DESCRIPTION +With +.B slist +you can list all NetWare file servers that are known in your IPX network. +.B slist +is modeled after the well-know DOS utility. As an option, you can give +a wildcard pattern to slist. This can be convienient if you want to +know whether a specific server is reachable, of if your IPX network +contains a lot of servers. + +The pattern is converted to upper case, because NetWare stores only upper-case name. So you can find out whether you can access FS311 by typing + +.RS 3 +slist fs311 +.RE + +Please note that the decorative header is +.I not +printed if slist prints to a pipe. So you can count the number of file +servers simply by typing + +.RS 3 +slist | wc -l +.RE + +.SH BUGS +You might need superuser privileges to run slist. This sounds paradox, +but if your IPX routing table is not administered by an IPX routing +daemon, slist needs to add a route to the internal network of the +server that's nearest to you. For ncpmount, this is no problem, as it +has to be suid root anyway. So you could make slist setuid root. This +should be safe, because slist does not do much. The second option is +to run an IPX routing daemon, which automatically adjusts your routing +tables. + +.SH AUTHOR +Volker Lendecke diff --git a/ncpfs-0.8.lsm b/ncpfs-0.9.lsm similarity index 73% rename from ncpfs-0.8.lsm rename to ncpfs-0.9.lsm index add35e5..c9029bf 100644 --- a/ncpfs-0.8.lsm +++ b/ncpfs-0.9.lsm @@ -1,14 +1,14 @@ Begin3 Title: ncpfs -Version: 0.8 -Entered-date: 28. November 1995 +Version: 0.9 +Entered-date: 02. December 1995 Description: With ncpfs you can mount volumes of your novell server under Linux. Keywords: filesystem kernel ncp novell netware Author: lendecke@namu01.gwdg.de (Volker Lendecke) Maintained-by: lendecke@namu01.gwdg.de (Volker Lendecke) Primary-site: linux01.gwdg.de:/pub/ncpfs - ~80k ncpfs-0.8.tgz - ~ 1k ncpfs-0.8.lsm + ~81k ncpfs-0.9.tgz + ~ 1k ncpfs-0.9.lsm Copying-policy: GPL End diff --git a/util/Makefile b/util/Makefile index 7fd9f60..ec9d9e2 100644 --- a/util/Makefile +++ b/util/Makefile @@ -4,30 +4,24 @@ INCLUDES = -I/usr/src/linux/include -I../kernel BINDIR = ../bin -UTILS = ncpmount ncpumount ncptest ipx_configure +UTILS = $(BINDIR)/ncpmount $(BINDIR)/ncpumount $(BINDIR)/slist ncptest CFLAGS = -Wall $(INCLUDES) -O2 CC = gcc all: $(UTILS) -ncpmount: ncpmount.o ncplib_user.o nwcrypt.o - $(CC) -o ncpmount ncpmount.o ncplib_user.o nwcrypt.o - cp ncpmount $(BINDIR) +$(BINDIR)/ncpmount: ncpmount.o ncplib.o + $(CC) -o $(BINDIR)/ncpmount ncpmount.o ncplib.o -ncpumount: ncpumount.o ncplib_user.o nwcrypt.o - $(CC) -o ncpumount ncpumount.o ncplib_user.o nwcrypt.o - cp ncpumount $(BINDIR) +$(BINDIR)/ncpumount: ncpumount.o ncplib.o + $(CC) -o $(BINDIR)/ncpumount ncpumount.o ncplib.o -ipx_configure: ipx_configure.c - $(CC) $(CFLAGS) ipx_configure.c -o ipx_configure - cp ipx_configure $(BINDIR) +$(BINDIR)/slist: slist.o ncplib.o + $(CC) -o $(BINDIR)/slist slist.o ncplib.o -ncptest: ncptest.o ncplib_user.o nwcrypt.o - $(CC) -o ncptest ncptest.o ncplib_user.o nwcrypt.o - -nwcrypt.o: nwcrypt.c - $(CC) -c -O3 -Wall nwcrypt.c +ncptest: ncptest.o ncplib.o + $(CC) -o ncptest ncptest.o ncplib.o dep: $(CPP) -M $(INCLUDES) *.c > .depend diff --git a/util/ipx.tar b/util/ipx.tar deleted file mode 100644 index f4b1ecc452032c6207247fc2a63298bc2bd48c34..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40960 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 KZU%nL8TfzWQ*EID diff --git a/util/ipxutil.h b/util/ipxutil.h deleted file mode 100644 index 9b6e1e2..0000000 --- a/util/ipxutil.h +++ /dev/null @@ -1,76 +0,0 @@ - -/* - - IPX support library - - Copyright (C) 1994, 1995 Ales Dryak - - 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 __IPXUTIL_H__ - -#define __IPXUTIL_H__ - -#include -#include - -#define IPX_RIP_PTYPE (0x01) -#define IPX_SAP_PTYPE (0x04) -#define IPX_SAP_PORT (0x0452) -#define IPX_RIP_PORT (0x0453) - -#define IPX_SAP_GENERAL_QUERY (0x0001) -#define IPX_SAP_GENERAL_RESPONSE (0x0002) -#define IPX_SAP_NEAREST_QUERY (0x0003) -#define IPX_SAP_NEAREST_RESPONSE (0x0004) - -#define IPX_SAP_FILE_SERVER (0x0004) - -#define IPX_RIP_REQUEST (0x1) -#define IPX_RIP_RESPONSE (0x2) - -struct ipx_rip_packet { - __u16 operation __attribute__ ((packed)); - struct ipx_rt_def { - __u32 network __attribute__ ((packed)); - __u16 hops __attribute__ ((packed)); - __u16 ticks __attribute__ ((packed)); - } rt[1] __attribute__ ((packed)); -}; - -#define IPX_BROADCAST_NODE "\xff\xff\xff\xff\xff\xff" -#define IPX_THIS_NODE "\0\0\0\0\0\0" - -#ifndef IPX_NODE_LEN -#define IPX_NODE_LEN (6) -#endif - -typedef unsigned long IPXNet; -typedef unsigned short IPXPort; -typedef unsigned char IPXNode[IPX_NODE_LEN]; - - -void ipx_print_node(IPXNode node); -void ipx_print_network(IPXNet net); -void ipx_print_port(IPXPort port); -void ipx_print_saddr(struct sockaddr_ipx* sipx); - -static __inline__ void -ipx_assign_node(IPXNode dest, IPXNode src) { - memcpy(dest, src, IPX_NODE_LEN); -} - -#endif diff --git a/util/ncplib_user.c b/util/ncplib.c similarity index 79% rename from util/ncplib_user.c rename to util/ncplib.c index 4f08c16..aaa6c28 100644 --- a/util/ncplib_user.c +++ b/util/ncplib.c @@ -1,5 +1,4 @@ -#include "ncplib_user.h" -#include "nwcrypt.h" +#include "ncplib.h" typedef __u8 byte; typedef __u16 word; @@ -17,7 +16,93 @@ extern pid_t wait(int *); #include #include #include -#include "ipxutil.h" +#include + +/* I know it's terrible to include a .c file here, but I want to keep + the file nwcrypt.c intact and separate for legal reasons */ +#include "nwcrypt.c" + +void +ipx_fprint_node(FILE* file,IPXNode node) +{ + fprintf(file,"%02X%02X%02X%02X%02X%02X", + (unsigned char)node[0], + (unsigned char)node[1], + (unsigned char)node[2], + (unsigned char)node[3], + (unsigned char)node[4], + (unsigned char)node[5] + ); +} + +void +ipx_fprint_network(FILE* file,IPXNet net) +{ + fprintf(file,"%08lX",ntohl(net)); +} + +void +ipx_fprint_port(FILE* file,IPXPort port) +{ + fprintf(file,"%04X",ntohs(port)); +} + +void +ipx_fprint_saddr(FILE* file,struct sockaddr_ipx* sipx) +{ + ipx_fprint_network(file,sipx->sipx_network); + fprintf(file,":"); + ipx_fprint_node(file,sipx->sipx_node); + fprintf(file,":"); + ipx_fprint_port(file,sipx->sipx_port); +} + +void +ipx_print_node(IPXNode node) +{ + ipx_fprint_node(stdout,node); +} + +void +ipx_print_network(IPXNet net) +{ + ipx_fprint_network(stdout,net); +} + +void +ipx_print_port(IPXPort port) +{ + ipx_fprint_port(stdout,port); +} + +void +ipx_print_saddr(struct sockaddr_ipx* sipx) +{ + ipx_fprint_saddr(stdout,sipx); +} + +int +ipx_sscanf_node(char *buf, unsigned char node[6]) +{ + int i; + int n[6]; + + if ((i = sscanf(buf, "%2x%2x%2x%2x%2x%2x", + &(n[0]), &(n[1]), &(n[2]), + &(n[3]), &(n[4]), &(n[5]))) != 6) { + return i; + } + + for (i=0; i<6; i++) { + node[i] = n[i]; + } + return 6; +} + +void +ipx_assign_node(IPXNode dest, IPXNode src) { + memcpy(dest, src, IPX_NODE_LEN); +} #define ncp_printf printf @@ -79,17 +164,57 @@ ncp_ioctl_request(struct ncp_server *server, int function) { return result; } +static int +ipx_recvfrom(int sock, void *buf, int len, unsigned int flags, + struct sockaddr_ipx *sender, int *addrlen, int timeout) +{ + fd_set rd, wr, ex; + struct timeval tv; + int result; + + FD_ZERO(&rd); FD_ZERO(&wr); FD_ZERO(&ex); + FD_SET(sock, &rd); + + tv.tv_sec = timeout; + tv.tv_usec = 0; + + if ((result = select(sock+1, &rd, &wr, &ex, &tv)) == -1) { + return result; + } + + if (FD_ISSET(sock, &rd)) { + result = recvfrom(sock, buf, len, flags, + (struct sockaddr *)sender, addrlen); + } + else + { + result = -1; + errno = ETIMEDOUT; + } + return result; +} + +static int +ipx_recv(int sock, void *buf, int len, unsigned int flags, int timeout) +{ + struct sockaddr_ipx sender; + int addrlen = sizeof(sender); + + return ipx_recvfrom(sock, buf, len, flags, &sender, &addrlen, timeout); +} + + static int do_ncp_call(struct ncp_server *server, int request_size) { struct ncp_request_header request = *((struct ncp_request_header *)(&(server->ncp_data))); - fd_set rd, wr, ex; - struct timeval tv; - int result; int retries = 3; + int len; + struct ncp_reply_header *r = + (struct ncp_reply_header *)&(server->ncp_data); while (retries > 0) { retries -= 1; @@ -104,37 +229,21 @@ do_ncp_call(struct ncp_server *server, int request_size) } re_select: - FD_ZERO(&rd); FD_ZERO(&wr); FD_ZERO(&ex); - FD_SET(server->ncp_sock, &rd); - - tv.tv_sec = 3; - tv.tv_usec = 0; - - if (select(server->ncp_sock+1, &rd, &wr, &ex, &tv) == -1) { - perror("select"); - return -1; - } - - if (FD_ISSET(server->ncp_sock, &rd)) { - int len = recv(server->ncp_sock, - server->ncp_data, NCP_PACKET_SIZE, - 0); - struct ncp_reply_header *r = - (struct ncp_reply_header *)&(server->ncp_data); + len = ipx_recv(server->ncp_sock, + server->ncp_data, NCP_PACKET_SIZE, 0, 1); - if ( (len == sizeof(*r)) - && (r->type == NCP_POSITIVE_ACK)) { - goto re_select; - } - if ( (len >= sizeof(*r)) - && (r->type == NCP_REPLY) - && ( (request.type == NCP_ALLOC_SLOT_REQUEST) - || ( (r->sequence == request.sequence) - && (r->conn_low == request.conn_low) - && (r->conn_high == request.conn_high)))) { - server->reply_size = len; - break; - } + if ( (len == sizeof(*r)) + && (r->type == NCP_POSITIVE_ACK)) { + goto re_select; + } + if ( (len >= sizeof(*r)) + && (r->type == NCP_REPLY) + && ( (request.type == NCP_ALLOC_SLOT_REQUEST) + || ( (r->sequence == request.sequence) + && (r->conn_low == request.conn_low) + && (r->conn_high == request.conn_high)))) { + server->reply_size = len; + break; } } return 0; @@ -189,8 +298,6 @@ install_wdog(struct ncp_server *server) int pid; int sock = server->wdog_sock; - fd_set rd, wr, ex; - struct timeval tv; char buf[1024]; struct sockaddr_ipx sender; int sizeofaddr = sizeof(struct sockaddr_ipx); @@ -209,17 +316,10 @@ install_wdog(struct ncp_server *server) while (1) { - FD_ZERO(&rd); FD_ZERO(&wr); FD_ZERO(&ex); - FD_SET(sock, &rd); - /* every 120 seconds we look if our parent is still alive */ - tv.tv_sec = 120; - tv.tv_usec = 0; - - if (select(sock+1, &rd, &wr, &ex, &tv) == -1) { - continue; - } + pktsize = ipx_recvfrom(sock, buf, sizeof(buf), 0, + &sender, &sizeofaddr, 120); if (getppid() != parent_pid) { /* our parent has died, so nothing to do @@ -227,31 +327,121 @@ install_wdog(struct ncp_server *server) exit(0); } - if (FD_ISSET(sock, &rd)) { - pktsize = recvfrom(sock, buf, sizeof(buf), 0, - (struct sockaddr *)&sender, - &sizeofaddr); - if (pktsize < 0) { - perror("recvfrom"); - continue; - } - if ( (pktsize != 2) - || (buf[1] != '?')) { - continue; - } - buf[1] = 'Y'; - pktsize = sendto(sock, buf, 2, 0, - (struct sockaddr *)&sender, - sizeof(sender)); - if (pktsize < 0) { - perror("send"); - } + if ( (pktsize != 2) + || (buf[1] != '?')) { + continue; } + + buf[1] = 'Y'; + pktsize = sendto(sock, buf, 2, 0, + (struct sockaddr *)&sender, + sizeof(sender)); } } +static int +ipx_make_reachable(IPXNet network) +{ + struct rtentry rt_def; + /* Router */ + struct sockaddr_ipx *sr = (struct sockaddr_ipx *)&rt_def.rt_gateway; + /* Target */ + struct sockaddr_ipx *st = (struct sockaddr_ipx *)&rt_def.rt_dst; + + struct ipx_rip_packet rip; + struct sockaddr_ipx addr; + int addrlen; + int sock; + int opt; + int res=-1; + int i; + int packets; + + if (geteuid() != 0) { + errno = EPERM; + return -1; + } + + memset(&rip, 0, sizeof(rip)); + + sock = socket(AF_IPX, SOCK_DGRAM, PF_IPX); + + if (sock == -1) { + return -1; + } + + opt=1; + /* Permit broadcast output */ + if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &opt,sizeof(opt)) != 0){ + goto finished; + } + + memset(&addr, 0, sizeof(addr)); + addr.sipx_family=AF_IPX; + addr.sipx_network=htonl(0x0); + addr.sipx_port=htons(0x0); + addr.sipx_type=IPX_RIP_PTYPE; + + if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) != 0) { + goto finished; + } + + addr.sipx_family = AF_IPX; + addr.sipx_network = htonl(0x0); + addr.sipx_port = htons(IPX_RIP_PORT); + addr.sipx_type = IPX_RIP_PTYPE; + ipx_assign_node(addr.sipx_node, IPX_BROADCAST_NODE); + + rip.operation = htons(IPX_RIP_REQUEST); + rip.rt[0].network = htonl(network); + + if (sendto(sock, &rip, sizeof(rip), 0, + (struct sockaddr *)&addr, sizeof(addr)) < 0) { + goto finished; + } + + packets = 3; + do + { + int len; + + if (packets == 0) { + goto finished; + } + + addrlen = sizeof(struct sockaddr_ipx); + + len = ipx_recvfrom(sock, &rip, sizeof(rip),0, sr, &addrlen, 1); + if (len < sizeof(rip)) { + packets = packets - 1; + continue; + } + } while (ntohs(rip.operation) != IPX_RIP_RESPONSE); + + if (rip.rt[0].network != htonl(network)) { + goto finished; + } + + rt_def.rt_flags = RTF_GATEWAY; + st->sipx_network = htonl(network); + sr->sipx_family = st->sipx_family = AF_IPX; + i = 0; + do { + res = ioctl(sock, SIOCADDRT, &rt_def); + i++; + } while ((i < 5) && (res < 0) && (errno == EAGAIN)); + + finished: + close(sock); + + if (res != 0) { + errno = ENETUNREACH; + } + return res; +} + int -ncp_connect(struct ncp_server *server) +ncp_connect_addr(struct ncp_server *server, const struct sockaddr_ipx *target) { struct ncp_request_header *h = (struct ncp_request_header *)&(server->ncp_data); @@ -263,6 +453,7 @@ ncp_connect(struct ncp_server *server) int ncp_port, wdog_port; server->is_connected = NOT_CONNECTED; + server->silent = 1; ncp_sock = socket(AF_IPX, SOCK_DGRAM, PF_IPX); if (ncp_sock == -1) { @@ -323,6 +514,7 @@ ncp_connect(struct ncp_server *server) h->type = NCP_ALLOC_SLOT_REQUEST; server->sequence = 0; + server->addr = *target; h->sequence = server->sequence; h->conn_low = 0xff; h->conn_high = 0xff; @@ -330,10 +522,17 @@ ncp_connect(struct ncp_server *server) h->function = 0; if (do_ncp_call(server, sizeof(*h)) != 0) { - int saved_errno = errno; - close(ncp_sock); close(wdog_sock); - errno = saved_errno; - return -1; + + if ( (errno != ENETUNREACH) + || (ipx_make_reachable(htonl(target->sipx_network)) != 0) + || (do_ncp_call(server, sizeof(*h)) != 0)) { + + int saved_errno = errno; + + close(ncp_sock); close(wdog_sock); + errno = saved_errno; + return -1; + } } install_wdog(server); @@ -346,6 +545,107 @@ ncp_connect(struct ncp_server *server) return 0; } +static int +ipx_sap_find_nearest(int server_type, struct sockaddr_ipx *result) +{ + struct sockaddr_ipx addr; + char data[1024]; + int sock; + int opt; + int res = -1; + int saved_errno; + int packets; + int len; + + struct sap_server_ident *ident; + + sock=socket(AF_IPX,SOCK_DGRAM,PF_IPX); + if (sock==-1) { + return -1; + } + + opt=1; + /* Permit broadcast output */ + if(setsockopt(sock,SOL_SOCKET,SO_BROADCAST, &opt,sizeof(opt))==-1) + { + goto finished; + } + + memset(&addr, 0, sizeof(addr)); + addr.sipx_family=AF_IPX; + addr.sipx_network=htonl(0x0); + addr.sipx_port=htons(0x0); + addr.sipx_type=IPX_SAP_PTYPE; + + if(bind(sock,(struct sockaddr*)&addr,sizeof(addr))==-1) + { + goto finished; + } + + *(unsigned short *)data = htons(IPX_SAP_NEAREST_QUERY); + *(unsigned short *)&(data[2]) = htons(server_type); + + memset(&addr, 0, sizeof(addr)); + addr.sipx_family=AF_IPX; + addr.sipx_network=htonl(0x0); + ipx_assign_node(addr.sipx_node, IPX_BROADCAST_NODE); + addr.sipx_port=htons(IPX_SAP_PORT); + addr.sipx_type=IPX_SAP_PTYPE; + + if (sendto(sock, data, 4, 0, + (struct sockaddr *)&addr, sizeof(addr)) < 0) + { + goto finished; + } + + packets = 5; + do + { + len = ipx_recv(sock, data, 1024, 0, 1); + if (len < 66) { + packets = packets - 1; + continue; + } + } while (ntohs(*((__u16 *)data)) != IPX_SAP_NEAREST_RESPONSE); + + ident = (struct sap_server_ident *)(data+2); + + result->sipx_family = AF_IPX; + result->sipx_network = ident->server_network; + result->sipx_port = ident->server_port; + ipx_assign_node(result->sipx_node, ident->server_node); + + res = 0; + + finished: + saved_errno = errno; + close(sock); + errno = saved_errno; + return res; +} + + +static int +ncp_connect_any(struct ncp_server *server) +{ + struct sockaddr_ipx addr; + + if (ipx_sap_find_nearest(IPX_SAP_FILE_SERVER, &addr) != 0) { + return -1; + } + + return ncp_connect_addr(server, &addr); +} + +int +ncp_connect(struct ncp_server *server, const char *name) +{ + if (name == NULL) { + return ncp_connect_any(server); + } + return -1; +} + static int ncp_user_disconnect(struct ncp_server *server) { @@ -610,6 +910,35 @@ ncp_get_bindery_object_id(struct ncp_server *server, return 0; } +int +ncp_scan_bindery_object(struct ncp_server *server, + __u32 last_id, __u16 object_type, char *search_string, + struct ncp_bindery_object *target) +{ + int result; + ncp_init_request_s(server, 55); + ncp_add_dword(server, htonl(last_id)); + ncp_add_word(server, htons(object_type)); + ncp_add_pstring(server, search_string); + + if ((result = ncp_request(server, 23)) != 0) { + ncp_unlock_server(server); + return result; + } + + target->object_id = ntohl(ncp_reply_dword(server, 0)); + target->object_type = ntohs(ncp_reply_word(server, 4)); + memcpy(target->object_name, ncp_reply_data(server, 6), + NCP_BINDERY_NAME_LEN); + target->object_flags = ncp_reply_byte(server, 54); + target->object_security = ncp_reply_byte(server, 55); + target->object_has_prop = ncp_reply_byte(server, 56); + + ncp_unlock_server(server); + return 0; +} + + int ncp_read_property_value(struct ncp_server *server, int object_type, char *object_name, diff --git a/util/ncplib_user.h b/util/ncplib.h similarity index 70% rename from util/ncplib_user.h rename to util/ncplib.h index 6541cd2..a97cb28 100644 --- a/util/ncplib_user.h +++ b/util/ncplib.h @@ -6,6 +6,68 @@ #include #include +typedef unsigned long IPXNet; +typedef unsigned short IPXPort; +typedef unsigned char IPXNode[IPX_NODE_LEN]; + +#define IPX_RIP_PTYPE (0x01) +#define IPX_SAP_PTYPE (0x04) +#define IPX_SAP_PORT (0x0452) +#define IPX_RIP_PORT (0x0453) + +#define IPX_SAP_GENERAL_QUERY (0x0001) +#define IPX_SAP_GENERAL_RESPONSE (0x0002) +#define IPX_SAP_NEAREST_QUERY (0x0003) +#define IPX_SAP_NEAREST_RESPONSE (0x0004) + +#define IPX_SAP_FILE_SERVER (0x0004) + +struct sap_query { + unsigned short query_type; /* net order */ + unsigned short server_type; /* net order */ +}; + +struct sap_server_ident { + unsigned short server_type __attribute__ ((packed)); + char server_name[48] __attribute__ ((packed)); + IPXNet server_network __attribute__ ((packed)); + IPXNode server_node __attribute__ ((packed)); + IPXPort server_port __attribute__ ((packed)); + unsigned short intermediate_network __attribute__ ((packed)); +}; + +#define IPX_RIP_REQUEST (0x1) +#define IPX_RIP_RESPONSE (0x2) + +struct ipx_rip_packet { + __u16 operation __attribute__ ((packed)); + struct ipx_rt_def { + __u32 network __attribute__ ((packed)); + __u16 hops __attribute__ ((packed)); + __u16 ticks __attribute__ ((packed)); + } rt[1] __attribute__ ((packed)); +}; + +#define IPX_BROADCAST_NODE "\xff\xff\xff\xff\xff\xff" +#define IPX_THIS_NODE "\0\0\0\0\0\0" + +#ifndef IPX_NODE_LEN +#define IPX_NODE_LEN (6) +#endif + +void +ipx_print_node(IPXNode node); +void +ipx_print_network(IPXNet net); +void +ipx_print_port(IPXPort port); +void +ipx_print_saddr(struct sockaddr_ipx* sipx); +int +ipx_sscanf_node(char *buf, unsigned char node[IPX_NODE_LEN]); +void +ipx_assign_node(IPXNode dest, IPXNode src); + enum connect_state { NOT_CONNECTED = 0, CONN_MOUNTED, @@ -43,7 +105,10 @@ int ncp_connect_mount(struct ncp_server *server, const char *mount_point); int -ncp_connect(struct ncp_server *server); +ncp_connect_addr(struct ncp_server *server, const struct sockaddr_ipx *target); + +int +ncp_connect(struct ncp_server *server, const char *server_name); int ncp_disconnect(struct ncp_server *server); @@ -59,6 +124,10 @@ ncp_get_bindery_object_id(struct ncp_server *server, int object_type, char *object_name, struct ncp_bindery_object *target); int +ncp_scan_bindery_object(struct ncp_server *server, + __u32 last_id, __u16 object_type, char *search_string, + struct ncp_bindery_object *target); +int ncp_read_property_value(struct ncp_server *server, int object_type, char *object_name, int segment, char *prop_name, diff --git a/util/ncpmount.c b/util/ncpmount.c index 9bda3dc..59b4e0f 100644 --- a/util/ncpmount.c +++ b/util/ncpmount.c @@ -28,15 +28,13 @@ extern pid_t waitpid(pid_t, int *, int); #include #include #include -#include #include #include #include #include #include -#include "ipxutil.h" -#include "ncplib_user.h" +#include "ncplib.h" static char *progname; @@ -77,105 +75,34 @@ help(void) "\n"); } -struct sap_query { - unsigned short query_type; /* net order */ - unsigned short server_type; /* net order */ -}; - -struct sap_server_ident { - unsigned short server_type __attribute__ ((packed)); - char server_name[48] __attribute__ ((packed)); - IPXNet server_network __attribute__ ((packed)); - IPXNode server_node __attribute__ ((packed)); - IPXPort server_port __attribute__ ((packed)); - unsigned short intermediate_network __attribute__ ((packed)); -}; - -void -ipx_fprint_node(FILE* file,IPXNode node) +int +ipx_sap_find_server(char *name, int server_type, int timeout, + struct sockaddr_ipx *result) { - fprintf(file,"%02X%02X%02X%02X%02X%02X", - (unsigned char)node[0], - (unsigned char)node[1], - (unsigned char)node[2], - (unsigned char)node[3], - (unsigned char)node[4], - (unsigned char)node[5] - ); -} - -void -ipx_fprint_network(FILE* file,IPXNet net) -{ - fprintf(file,"%08lX",ntohl(net)); -} - -void -ipx_fprint_port(FILE* file,IPXPort port) -{ - fprintf(file,"%04X",ntohs(port)); -} - -void -ipx_fprint_saddr(FILE* file,struct sockaddr_ipx* sipx) -{ - ipx_fprint_network(file,sipx->sipx_network); - fprintf(file,":"); - ipx_fprint_node(file,sipx->sipx_node); - fprintf(file,":"); - ipx_fprint_port(file,sipx->sipx_port); -} - -void -ipx_print_node(IPXNode node) -{ - ipx_fprint_node(stdout,node); -} - -void -ipx_print_network(IPXNet net) -{ - ipx_fprint_network(stdout,net); -} - -void -ipx_print_port(IPXPort port) -{ - ipx_fprint_port(stdout,port); -} - -void -ipx_print_saddr(struct sockaddr_ipx* sipx) -{ - ipx_fprint_saddr(stdout,sipx); -} - -static int -ipx_make_reachable(__u32 network) -{ - struct rtentry rt_def; - /* Router */ - struct sockaddr_ipx *sr = (struct sockaddr_ipx *)&rt_def.rt_gateway; - /* Target */ - struct sockaddr_ipx *st = (struct sockaddr_ipx *)&rt_def.rt_dst; - - fd_set rd, wr, ex; - struct timeval tv; - - struct ipx_rip_packet rip; struct sockaddr_ipx addr; - int addrlen; + char data[1024]; int sock; int opt; - int res=-1; - int i; + int res = -1; + int name_len = strlen(name); + fd_set rd, wr, ex; + struct timeval tv; + struct sap_server_ident *ident; - sock = socket(AF_IPX, SOCK_DGRAM, PF_IPX); + struct ncp_server server; + struct nw_property prop; + struct prop_net_address *n_addr = (struct prop_net_address *)∝ - if (sock == -1) { + + if (name_len > 48) { return -1; } + sock=socket(AF_IPX,SOCK_DGRAM,PF_IPX); + if (sock==-1) { + return -1; + } + opt=1; /* Permit broadcast output */ if(setsockopt(sock,SOL_SOCKET,SO_BROADCAST, &opt,sizeof(opt))==-1) @@ -188,7 +115,7 @@ ipx_make_reachable(__u32 network) addr.sipx_family=AF_IPX; addr.sipx_network=htonl(0x0); addr.sipx_port=htons(0x0); - addr.sipx_type=IPX_RIP_PTYPE; + addr.sipx_type=IPX_SAP_PTYPE; if(bind(sock,(struct sockaddr*)&addr,sizeof(addr))==-1) { @@ -196,153 +123,18 @@ ipx_make_reachable(__u32 network) goto finished; } - addr.sipx_family = AF_IPX; - addr.sipx_network = htonl(0x0); - addr.sipx_port = htons(IPX_RIP_PORT); - addr.sipx_type = IPX_RIP_PTYPE; - ipx_assign_node(addr.sipx_node, IPX_BROADCAST_NODE); - - rip.operation = htons(IPX_RIP_REQUEST); - rip.rt[0].network = htonl(network); - - if (sendto(sock, &rip, sizeof(rip), 0, - (struct sockaddr *)&addr, sizeof(addr)) < 0) { - perror("sendto"); - goto finished; - } - - do - { - - FD_ZERO(&rd); FD_ZERO(&wr); FD_ZERO(&ex); - FD_SET(sock, &rd); - - tv.tv_sec = 3; - tv.tv_usec = 0; - - if (select(sock+1, &rd, &wr, &ex, &tv) == -1) - { - goto finished; - } - - if (FD_ISSET(sock, &rd)) - { - int len; - - addrlen = sizeof(struct sockaddr_ipx); - - len = recvfrom(sock, &rip, sizeof(rip), 0, - (struct sockaddr *)sr, &addrlen); - - if (len < sizeof(rip)) - { - continue; - } - } - else - { - goto finished; - } - } while (ntohs(rip.operation) != IPX_RIP_RESPONSE); - - if (rip.rt[0].network != htonl(network)) { - goto finished; - } - - rt_def.rt_flags = RTF_GATEWAY; - st->sipx_network = htonl(network); - sr->sipx_family = st->sipx_family = AF_IPX; - i = 0; - do { - res = ioctl(sock, SIOCADDRT, &rt_def); - i++; - } while ((i < 5) && (res < 0) && (errno == EAGAIN)); - - if (res != 0) { - - switch (errno) { - case ENETUNREACH: - fprintf(stderr, - "%s: Router network (%08lX) not reachable.\n", - progname, htonl(sr->sipx_network)); - break; - default: - perror("ioctl"); - break; - } - goto finished; - } - - finished: - close(sock); - return res; -} - -int -ipx_sap_find_server(char *name, int server_type, int timeout, - struct sockaddr_ipx *result) -{ - struct sockaddr_ipx ipxs; - char data[1024]; - int sock; - int opt; - int res = -1; - int name_len = strlen(name); - fd_set rd, wr, ex; - struct timeval tv; - struct sap_server_ident *ident; - - struct ncp_server server; - struct nw_property prop; - struct net_address - { - __u32 network __attribute__ ((packed)); - __u8 node[6] __attribute__ ((packed)); - __u16 port __attribute__ ((packed)); - } *n_addr = (struct net_address *)∝ - - - if (name_len > 48) { - return -1; - } - - sock=socket(AF_IPX,SOCK_DGRAM,PF_IPX); - if (sock==-1) { - return -1; - } - - opt=1; - /* Permit broadcast output */ - if(setsockopt(sock,SOL_SOCKET,SO_BROADCAST, &opt,sizeof(opt))==-1) - { - perror("setsockopt"); - goto finished; - } - - memset(&ipxs, 0, sizeof(ipxs)); - ipxs.sipx_family=AF_IPX; - ipxs.sipx_network=htonl(0x0); - ipxs.sipx_port=htons(0x0); - ipxs.sipx_type=IPX_SAP_PTYPE; - - if(bind(sock,(struct sockaddr*)&ipxs,sizeof(ipxs))==-1) - { - perror("bind"); - goto finished; - } - *(unsigned short *)data = htons(IPX_SAP_NEAREST_QUERY); *(unsigned short *)&(data[2]) = htons(server_type); - memset(&ipxs, 0, sizeof(ipxs)); - ipxs.sipx_family=AF_IPX; - ipxs.sipx_network=htonl(0x0); - ipx_assign_node(ipxs.sipx_node, IPX_BROADCAST_NODE); - ipxs.sipx_port=htons(IPX_SAP_PORT); - ipxs.sipx_type=IPX_SAP_PTYPE; + memset(&addr, 0, sizeof(addr)); + addr.sipx_family=AF_IPX; + addr.sipx_network=htonl(0x0); + ipx_assign_node(addr.sipx_node, IPX_BROADCAST_NODE); + addr.sipx_port=htons(IPX_SAP_PORT); + addr.sipx_type=IPX_SAP_PTYPE; if (sendto(sock, data, 4, 0, - (struct sockaddr *)&ipxs, sizeof(ipxs)) < 0) + (struct sockaddr *)&addr, sizeof(addr)) < 0) { perror("sendto"); goto finished; @@ -385,18 +177,13 @@ ipx_sap_find_server(char *name, int server_type, int timeout, route to the server's internal network. Because this one request is not very expensive, we always do it. */ - server.addr.sipx_family = AF_IPX; - server.addr.sipx_network = ident->server_network; - server.addr.sipx_port = ident->server_port; - ipx_assign_node(server.addr.sipx_node, ident->server_node); + addr.sipx_family = AF_IPX; + addr.sipx_network = ident->server_network; + addr.sipx_port = ident->server_port; + ipx_assign_node(addr.sipx_node, ident->server_node); - if (ncp_connect(&server) != 0) - { - if ( (errno != ENETUNREACH) - || (ipx_make_reachable(ntohl(server.addr.sipx_network))!=0) - || (ncp_connect(&server) != 0)) { - goto finished; - } + if (ncp_connect_addr(&server, &addr) != 0) { + goto finished; } if (ncp_read_property_value(&server, NCP_BINDERY_FSERVER, @@ -407,8 +194,7 @@ ipx_sap_find_server(char *name, int server_type, int timeout, goto finished; } - if (ncp_disconnect(&server) != 0) - { + if (ncp_disconnect(&server) != 0) { goto finished; } @@ -420,19 +206,8 @@ ipx_sap_find_server(char *name, int server_type, int timeout, /* Now we connect to the ultimate target, again with a test for reachability. This time nothing is done except connecting. */ - server.addr = *result; - - if (ncp_connect(&server) != 0) - { - if ( (errno != ENETUNREACH) - || (ipx_make_reachable(ntohl(server.addr.sipx_network))!=0) - || (ncp_connect(&server) != 0)) { - goto finished; - } - } - - if (ncp_disconnect(&server) != 0) - { + if ( (ncp_connect_addr(&server, result) != 0) + || (ncp_disconnect(&server) != 0)) { goto finished; } @@ -444,24 +219,6 @@ ipx_sap_find_server(char *name, int server_type, int timeout, return res; } -int -ipx_sscanf_node(char *buf, unsigned char node[6]) -{ - int i; - int n[6]; - - if ((i = sscanf(buf, "%2x%2x%2x%2x%2x%2x", - &(n[0]), &(n[1]), &(n[2]), - &(n[3]), &(n[4]), &(n[5]))) != 6) { - return i; - } - - for (i=0; i<6; i++) { - node[i] = n[i]; - } - return 6; -} - static int parse_args(int argc, char *argv[], struct ncp_mount_data *data, int *got_password, int *upcase_password) @@ -664,7 +421,8 @@ main(int argc, char *argv[]) exit(1); } - memset(&data, 0, sizeof(struct ncp_mount_data)); + memset(&data, 0, sizeof(data)); + memset(&serv, 0, sizeof(serv)); memset(hostname, '\0', MAXHOSTNAMELEN+1); gethostname(hostname, MAXHOSTNAMELEN); @@ -832,9 +590,6 @@ main(int argc, char *argv[]) if (ncp_login_user(server, data.username, data.password) != 0) { fprintf(stderr, "login failed\n"); - fprintf(stderr, - "should try to type the username and\n" - "password in UPPERCASE.\n"); close(server->mount_fid); umount(mount_point); return -1; diff --git a/util/ncptest.c b/util/ncptest.c index 33da516..8bd5c01 100644 --- a/util/ncptest.c +++ b/util/ncptest.c @@ -35,8 +35,7 @@ extern pid_t waitpid(pid_t, int *, int); #include #include #include -#include "ncplib_user.h" -#include "ipxutil.h" +#include "ncplib.h" static char *progname; @@ -49,79 +48,6 @@ str_upper(char *name) } } -struct sap_query { - unsigned short query_type; /* net order */ - unsigned short server_type; /* net order */ -}; - -struct sap_server_ident { - unsigned short server_type __attribute__ ((packed)); - char server_name[48] __attribute__ ((packed)); - IPXNet server_network __attribute__ ((packed)); - IPXNode server_node __attribute__ ((packed)); - IPXPort server_port __attribute__ ((packed)); - unsigned short intermediate_network __attribute__ ((packed)); -}; - -void -ipx_fprint_node(FILE* file,IPXNode node) -{ - fprintf(file,"%02X%02X%02X%02X%02X%02X", - (unsigned char)node[0], - (unsigned char)node[1], - (unsigned char)node[2], - (unsigned char)node[3], - (unsigned char)node[4], - (unsigned char)node[5] - ); -} - -void -ipx_fprint_network(FILE* file,IPXNet net) -{ - fprintf(file,"%08lX",ntohl(net)); -} - -void -ipx_fprint_port(FILE* file,IPXPort port) -{ - fprintf(file,"%04X",ntohs(port)); -} - -void -ipx_fprint_saddr(FILE* file,struct sockaddr_ipx* sipx) -{ - ipx_fprint_network(file,sipx->sipx_network); - fprintf(file,":"); - ipx_fprint_node(file,sipx->sipx_node); - fprintf(file,":"); - ipx_fprint_port(file,sipx->sipx_port); -} - -void -ipx_print_node(IPXNode node) -{ - ipx_fprint_node(stdout,node); -} - -void -ipx_print_network(IPXNet net) -{ - ipx_fprint_network(stdout,net); -} - -void -ipx_print_port(IPXPort port) -{ - ipx_fprint_port(stdout,port); -} - -void -ipx_print_saddr(struct sockaddr_ipx* sipx) -{ - ipx_fprint_saddr(stdout,sipx); -} - int ipx_sap_find_server(char *_name, int server_type, int timeout, struct sockaddr_ipx *result) @@ -237,25 +163,6 @@ ipx_sap_find_server(char *_name, int server_type, int timeout, return res; } -int -ipx_sscanf_node(char *buf, unsigned char node[6]) -{ - int i; - int n[6]; - - if ((i = sscanf(buf, "%2x%2x%2x%2x%2x%2x", - &(n[0]), &(n[1]), &(n[2]), - &(n[3]), &(n[4]), &(n[5]))) != 6) { - return i; - } - - for (i=0; i<6; i++) { - node[i] = n[i]; - } - return 6; -} - - void test_filesearch(struct ncp_server *server) { @@ -560,21 +467,21 @@ test_print(struct ncp_server *server) j.j.TargetServerID = 0xffffffff; /* any server */ memset(&(j.j.TargetExecTime), 0xff, sizeof(j.j.TargetExecTime)); /* at once */ - j.j.JobType = 0xffff; + j.j.JobType = htons(0); strcpy(j.j.JobTextDescription, "Test Job"); memset(&pj, 0, sizeof(pj)); pj.Version = 0; - pj.TabSize = 0; - pj.Copies = 1; + pj.TabSize = 8; + pj.Copies = htons(1); pj.CtrlFlags = 0; - pj.Lines = 0; - pj.Rows = 0; - strcpy(pj.FormName, ""); - strcpy(pj.Banner, ""); - strcpy(pj.FnameBanner, ""); - strcpy(pj.FnameHeader, ""); + pj.Lines = htons(66); + pj.Rows = htons(80); + strcpy(pj.FormName, "test"); + strcpy(pj.BannerName, "BannerName"); + strcpy(pj.FnameBanner, "BannerFile"); + strcpy(pj.FnameHeader, "HeaderName"); strcpy(pj.Path, ""); memcpy(j.j.ClientRecordArea, &pj, sizeof(pj)); @@ -584,7 +491,8 @@ test_print(struct ncp_server *server) return; } - if (ncp_write(server, j.file_handle, 0, 5, "hallo", &written) != 0) { + if (ncp_write(server, j.file_handle, 0, 5, "hallo, wie geht's?", + &written) != 0) { printf("write error\n"); return; } @@ -597,29 +505,37 @@ test_print(struct ncp_server *server) return; } - - +void +test_slist(struct ncp_server *server) +{ + struct ncp_bindery_object obj; + + obj.object_id = 0xffffffff; + + while (ncp_scan_bindery_object(server, obj.object_id, + 0xffff, "*", + &obj) == 0) { + printf("%s\n", obj.object_name); + } + return; +} int main(int argc, char **argv) { struct ncp_server serv; struct ncp_server *server = &serv; + struct sockaddr_ipx addr; progname = argv[0]; - if (argc != 2) { - printf("usage: %s server\n", argv[0]); - exit(1); - } - - if (ipx_sap_find_server(argv[1], IPX_SAP_FILE_SERVER, - 3, &(serv.addr)) != 0) { + if (ipx_sap_find_server("nw311", IPX_SAP_FILE_SERVER, + 3, &addr) != 0) { printf("could not find server %s\n", argv[1]); exit(1); } - if (ncp_connect(server) != 0) { + if (ncp_connect_addr(server, &addr) != 0) { printf("could not connect\n"); exit(1); } @@ -629,7 +545,7 @@ main(int argc, char **argv) exit(1); } - getchar(); + test_slist(server); ncp_disconnect(server); diff --git a/util/nwcrypt.c b/util/nwcrypt.c index d12e1c2..9c403bd 100644 --- a/util/nwcrypt.c +++ b/util/nwcrypt.c @@ -89,9 +89,8 @@ typedef unsigned char buf32[32]; typedef unsigned char buf16[16]; typedef unsigned char buf8[8]; typedef unsigned char buf4[4]; -typedef unsigned char u8; -static u8 encrypttable[256] = +static unsigned char encrypttable[256] = {0x7,0x8,0x0,0x8,0x6,0x4,0xE,0x4,0x5,0xC,0x1,0x7,0xB,0xF,0xA,0x8, 0xF,0x8,0xC,0xC,0x9,0x4,0x1,0xE,0x4,0x6,0x2,0x4,0x0,0xA,0xB,0x9, 0x2,0xF,0xB,0x1,0xD,0x2,0x1,0x9,0x5,0xE,0x7,0x0,0x0,0x2,0x6,0x6, @@ -142,7 +141,7 @@ shuffle1(buf32 temp, unsigned char *target) } -void +static void shuffle(unsigned char *lon, const unsigned char *buf, int buflen, unsigned char *target) { @@ -191,7 +190,7 @@ shuffle(unsigned char *lon, const unsigned char *buf, int buflen, } -void +static void nw_encrypt(unsigned char *fra,unsigned char *buf,unsigned char *til) { buf32 k; diff --git a/util/nwcrypt.h b/util/nwcrypt.h deleted file mode 100644 index a2f4b64..0000000 --- a/util/nwcrypt.h +++ /dev/null @@ -1,5 +0,0 @@ -void -shuffle(unsigned char *lon, const unsigned char *buf, int buflen, - unsigned char *target); -void -nw_encrypt(unsigned char *fra,unsigned char *buf,unsigned char *til); diff --git a/util/slist.c b/util/slist.c new file mode 100644 index 0000000..8694679 --- /dev/null +++ b/util/slist.c @@ -0,0 +1,77 @@ +#include "ncplib.h" +#include +#include +#include +#include +#include + +void +main(int argc, char *argv[]) +{ + struct ncp_server server; + struct ncp_bindery_object obj; + int found = 0; + char default_pattern[2] = "*"; + char *pattern = default_pattern; + char *p; + + if (argc > 2) { + printf("usage: %s [pattern]\n", argv[0]); + exit(1); + } + + if (argc == 2) { + pattern = argv[1]; + } + + for (p = pattern; *p != '\0'; p++) { + *p = toupper(*p); + } + + memset(&server, 0, sizeof(server)); + + if (ncp_connect(&server, NULL) != 0) { + perror("ncp_connect"); + exit(1); + } + + if (isatty(1)) { + printf("\n%-52s%-10s%-12s\n" + "-----------------------------------------------" + "---------------------------\n", + "Known NetWare File Servers", + "Network", + "Node Address"); + } + + obj.object_id = 0xffffffff; + + while (ncp_scan_bindery_object(&server, obj.object_id, + NCP_BINDERY_FSERVER, pattern, + &obj) == 0) { + + struct nw_property prop; + struct prop_net_address *naddr + = (struct prop_net_address *)∝ + + found = 1; + + printf("%-52s", obj.object_name); + + if (ncp_read_property_value(&server, NCP_BINDERY_FSERVER, + obj.object_name, 1, "NET_ADDRESS", + &prop) == 0) { + ipx_print_network(naddr->network); + printf(" "); + ipx_print_node(naddr->node); + } + printf("\n"); + } + + if ((found == 0) && (isatty(1))) { + printf("No servers found\n"); + } + + ncp_disconnect(&server); +} +