Compare commits

..

10 Commits
v0.5 ... v0.15

Author SHA1 Message Date
ncpfs archive import
b8ce93c8bd Import ncpfs 0.15 2026-04-28 20:39:57 +02:00
ncpfs archive import
7bef99df0f Import ncpfs 0.14 2026-04-28 20:39:57 +02:00
ncpfs archive import
d31ec2ab61 Import ncpfs 0.13 2026-04-28 20:39:57 +02:00
ncpfs archive import
1ee60bade6 Import ncpfs 0.12 2026-04-28 20:39:57 +02:00
ncpfs archive import
20589ca203 Import ncpfs 0.11 2026-04-28 20:39:57 +02:00
ncpfs archive import
517e207709 Import ncpfs 0.10 2026-04-28 20:39:57 +02:00
ncpfs archive import
5d4b23a5c1 Import ncpfs 0.9 2026-04-28 20:39:57 +02:00
ncpfs archive import
c6124785a9 Import ncpfs 0.8 2026-04-28 20:39:57 +02:00
ncpfs archive import
f2bcb2c71e Import ncpfs 0.7 2026-04-28 20:39:57 +02:00
ncpfs archive import
e05e55a64a Import ncpfs 0.6 2026-04-28 20:39:57 +02:00
74 changed files with 8461 additions and 2949 deletions

BIN
.downloads/ncpfs-0.10.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.11.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.12.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.13.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.14.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.15.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.6.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.7.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.8.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.9.tgz Normal file

Binary file not shown.

23
BUGS
View File

@@ -3,11 +3,7 @@ them to be bugs.
But there are really problems that might be fixed in the future.
Invalid directory timestamps:
I did not yet find out how to get valid timestamps for directories
from a NetWare server. So I simply return 0, which means 01.01.70. If
anybody knows how to get these values, please mail
lendecke@namu01.gwdg.de.
-------------------------------------------------------------------------------
'df' returns 0:
Free disk space is distributed among the volumes in NetWare. df is
@@ -15,3 +11,20 @@ only able to report one number per mounted filesystem. As connections
are quite expensive for NetWare (with lwared that might change ...), I
rejected the alternative to mount only a single volume for a unix
mount point. So I simply return 0.
-------------------------------------------------------------------------------
If you use Linux 1.2.x, In your kernel log there will appear messages
like
Nov 25 16:09:08 lx01 kernel: alloc_skb called nonatomically from interrupt 0000002e
These are a bit annoying, but completely harmless.
-------------------------------------------------------------------------------
ncpfs has a problem with NetWare 4.1, when files are created. I think
NW4.1 does not like some of the creation mode bits. If somebody with
access to a NW4.1 server could compile the kernel module for 1.2 with
-DDEBUG_NCP=2, and send me the syslog output gzipped/uuencoded, I
might find out more about that problem.

24
Changes Normal file
View File

@@ -0,0 +1,24 @@
I only began this file with ncpfs-0.12. If you're interested in older
versions, you can find them on linux01.gwdg.de:/pub/ncpfs/old.
ncpfs-0.14 -> ncpfs-0.15
- A bug fixed that made normal mounting impossible. It was too late
yesterday. Sorry
- Manpage for pserver.c
ncpfs-0.13 -> ncpfs-0.14
- Improvements of manual pages by B. Galliart <bgallia@luc.edu> and
Terry Dawson <terry@perf.no.itg.telecom.com.au>
- fsinfo
- pserver.c. Please see this as ALPHA software. There is no
documentation, and it is not tested enough. But it might be useful for
you.
ncpfs-0.12 -> ncpfs-0.13
- support for automatic loading of ncpfs.o by kerneld.
Thanks to Steven N. Hirsch <hirsch@emba.uvm.edu>.
- A subtle problem in the read routines has been removed by Uwe Bonnes
<bon@elektron.ikp.physik.th-darmstadt.de>. Thanks a lot.

View File

@@ -2,76 +2,60 @@
# Makefile for the linux ncp-filesystem routines.
#
INCLUDES = -I/usr/src/linux/include
# KERNEL = 1.2
CFLAGS = -Wall -Wstrict-prototypes -O2 -DMODULE -fomit-frame-pointer \
$(INCLUDES) \
# -DDEBUG_NCP=2 -DDEBUG_NCP_MALLOC
# -DDEBUG_NCP_MALLOC
TOPDIR = $(shell pwd)
CC = gcc -D__KERNEL__ -I.
AS = as
ARCH = i386
BINDIR = /usr/local/bin
INTERM_BINDIR = $(TOPDIR)/bin
SUBDIRS = util ipx-0.75 man
.c.s:
$(CC) $(CFLAGS) -S $<
.c.o:
$(CC) $(CFLAGS) -c $<
.s.o:
$(AS) -o $*.o $<
#
# The following 2 lines are for those who use Kernel version 1.2.x.
# If you have a kernel later than 1.3.53, please comment out the
# the following lines. You have to recompile your kernel
# and say 'y' when 'make config' asks you for IPX and ncpfs.
#
#SUBDIRS += kernel-1.2/src
#INCLUDES = -I$(TOPDIR)/kernel-1.2
OBJS= dir.o inode.o file.o sock.o ioctl.o ncplib.o
# If you are using kerneld to autoload ncp support,
# uncomment this (kerneld is in linux since about 1.3.57):
# KERNELD = -DHAVE_KERNELD
all: ncpfs.o ncpmount ncptest
export INCLUDES BINDIR INTERM_BINDIR KERNELD
ncpfs.o: $(OBJS)
$(LD) -r -o ncpfs.o $(OBJS)
ncplib.o: ncplib.c ncplib.h
$(CC) $(CFLAGS) -finline-functions -c $<
ncpmount: ncpmount.o ncplib_user.o nwcrypt.o
gcc -o ncpmount ncpmount.o ncplib_user.o nwcrypt.o
ncpmount.o: ncpmount.c
gcc -c ncpmount.c -Wall -I. -g
ncptest: ncptest.o ncplib_user.o nwcrypt.o
gcc -o ncptest ncptest.o ncplib_user.o nwcrypt.o
ncptest.o: ncptest.c
gcc -c ncptest.c -Wall -I. -g
ncplib_user.o: ncplib_user.c ncplib_user.h
gcc -c ncplib_user.c -Wall -I. -g
nwcrypt.o: nwcrypt.c
gcc -c -O2 -Wall nwcrypt.c
all:
for i in $(SUBDIRS); do make -C $$i; done
dep:
$(CPP) -M $(INCLUDES) *.c > .depend
for i in $(SUBDIRS); do make -C $$i dep; done
install:
for i in $(SUBDIRS); do make -C $$i install; done
clean:
rm -f *.o *~
rm -f `find . -type f -name '*.o' -print`
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 -f ncpmount ncptest .depend $(DISTFILE) *.out
rm -fr $(INTERM_BINDIR)/* ncpfs.tgz
make -C util realclean
modules: ncpfs.o
SRCPATH=$(shell pwd)
SRCDIR=$(shell basename $(SRCPATH))
DISTFILE=$(SRCDIR).tgz
BACKUPFILE=ncpfs01.tgz
HOME=/home/me
backup:
(rm -f $(DISTFILE); cd ..; tar cvf - $(SRCDIR) | gzip -1 \
> $(HOME)/tarz/backup/$(BACKUPFILE))
(cd $(HOME)/tarz/backup; ls -l $(BACKUPFILE); mcopy $(BACKUPFILE) a:)
dist: tgz
make dep
make all
dist: realclean
rm -fr mnt
tgz: realclean
(cd ..; \
tar cvf - $(SRCDIR) | \
gzip -9 > $(DISTFILE); \

87
README
View File

@@ -1,26 +1,49 @@
This is version 0.5 of ncpfs, a free NetWare client for Linux. For me
it works with 1.3.39, although this version has severe problems with
the socket layer. Your connection will block after you have sent 64k
of requests to the server. Alan Cox told me he would like to have that
fixed in 1.3.42 or so.
This is ncpfs, a free NetWare client filesystem for Linux. Besides
some little utilities it also contains nprint, which enables you to
print on NetWare print queues.
I know that this piece of software is VERY incomplete, I have to
apologize for that. But I thought I should make it publically
available, because I have tried to ask several people about the legal
status of the code. I did not get very satisfying answers. So I publish
ncpfs to open it for criticism. If nobody complains, I will go on
working.
INSTALLATION
To install ncpfs, just type 'make', 'insmod ncpfs.o' and then
'ncpmount server mount-point'.
The installation of ncpfs depends on the kernel version you are
using. For kernel 1.2, you should simply type 'make' and look at
what's in the bin/ directory after that. Please be sure that your
kernel resides in /usr/src/linux, because the file
kernel-1.2/src/sock.c has to refer directly to it.
Please note that your IPX system has to be configured correctly. There
has to be a route to the internal network of your server. Please see
the file start_ipx for an example.
If you use Kernel 1.3, please be sure that you use at least
1.3.54. ncpfs does NOT work with any earlier 1.3.x kernel, especially
not with 1.3.53, although this one has a fs/ncpfs/ subdirectory.
If you use Kernel 1.3.54 or later, you might have to recompile your
kernel. With these kernels, the kernel part of ncpfs is already
included in the main source tree. If you want to use ncpfs, you should
say 'y' to 'make config' when you are asked for IPX, and again when it
asks for ncpfs. After you have rebooted with the new kernel, 'cat
/proc/filesystems' should show you a line saying that the kernel knows
ncpfs.
With Kernel 1.3.54 or later you also have to modify the Makefile in the
directory you found this README in. Please see the Makefile for the
necessary modifications. Then typing 'make' should work with no
problem.
USING NCPFS
Please note that your IPX system has to be configured correctly. If
you want to take the 'Plug-and-Play' route, you can simply say
'ipx_configure --auto_interface=on --auto_primary=on'. If ncpmount
does not work immediately, you should wait for about 1 minute and try
again. In that period, an IPX packet should have passed by and your
network interface should have configured itself automatically.
If all that does not work and you want to do the configuration by
hand, note that there has to be a route to the internal network of
your server. Please see the file util/start_ipx for an example.
I use tools written by Greg Page, Caldera. I hope I did not do too
much harm to their business. For your convenience I included the file
ipx.tar made available by Caldera.
much harm to their business. For your convenience I included the
contents of the file ipx.tar made available by Caldera.
My main source of information is a book written in german by Manfred
Hill and Ralf Zessin, "Netzwerkprogrammierung in C", IWT Verlag GmbH,
@@ -30,7 +53,7 @@ programming. If you know about the concepts and possibilities of NCP,
Ralph Brown's interrupt list becomes much more readable. It's much
easier to find undocumented information if you know what to look for!
For the curious: the file ncplib_user.[ch] is a library that makes it
For the curious: the files ncplib.[ch] are a library that makes it
possible to send NCP requests to the server over a mounted
directory. I use it to keep the encryption stuff out of the kernel by
logging in from user space. Look at the file ncptest.c for other
@@ -40,6 +63,21 @@ free NetWare API for Linux! I would be happy to receive your comments
on this.
THANKS
I do not want to leave those unmentioned, who have helped me with
ncpfs.
The most enthusiastic user and tester is certainly Uwe Bonnes
<bon@elektron.ikp.physik.th-darmstadt.de>. So far he's the only one
who has contributed something, namely manpages and corretions to
existing manpages.
Ales Dyrak has written lwared, which was the initial start for ncpfs.
Alan Cox has found some bugs I would probably never have found.
LIMITATIONS (compare these with smbfs :-)
The limitations ncpfs has are the natural limitations of the NCP
@@ -61,3 +99,14 @@ different. You can never know when the client will access the file-id
you offered, so you would have to cache the inode numbers
indefinitely long. I think this should not be done in kernel mode, as
it would require an unlimited amount of RAM.
Those who looked at the kernel code a bit closer will have found out
that the last section is a little white lie. As I found out after the
first version of ncpfs, NetWare does indeed offer something like inode
numbers, although are only unique per volume. So one way to make ncpfs
re-exportable by nfs is to allocate a superblock per volume and show
the inode numbers to the user. I was just too lazy to do this
yet. Maybe once we will force Novell to make NetWare NFS
affordable... ;-)
Have fun with ncpfs!

81
ioctl.c
View File

@@ -1,81 +0,0 @@
/*
* ioctl.c
*
* Copyright (C) 1995 by Volker Lendecke
*
*/
/* #include <linux/module.h>*/
#include <asm/segment.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ncp_fs.h>
#include <linux/ioctl.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/ncp.h>
int
ncp_ioctl (struct inode * inode, struct file * filp,
unsigned int cmd, unsigned long arg)
{
int result;
struct ncp_ioctl_request request;
struct ncp_server *server;
switch(cmd) {
case NCP_IOC_NCPREQUEST:
if (!suser()) {
return -EPERM;
}
if ((result = verify_area(VERIFY_READ, (char *)arg,
sizeof(request))) != 0) {
return result;
}
memcpy_fromfs(&request, (struct ncp_ioctl_request *)arg,
sizeof(request));
if ( (request.function > 255)
|| (request.size >
NCP_PACKET_SIZE - sizeof(struct ncp_request_header))) {
return -EINVAL;
}
if ((result = verify_area(VERIFY_WRITE, (char *)request.data,
NCP_PACKET_SIZE)) != 0) {
return result;
}
server = NCP_SERVER(inode);
ncp_lock_server(server);
/* FIXME: We hack around in the server's structures
here to be able to use ncp_request */
server->has_subfunction = 0;
server->current_size =
request.size + sizeof(struct ncp_request_header);
memcpy_fromfs(&(server->
packet[sizeof(struct ncp_request_header)]),
request.data, request.size);
ncp_request(server, request.function);
DPRINTK("ncp_ioctl: copy %d bytes\n",
server->reply_size);
memcpy_tofs(request.data, server->packet,
server->reply_size);
ncp_unlock_server(server);
return server->reply_size;
default:
return -EINVAL;
}
return -EINVAL;
}

30
ipx-0.75/Makefile Normal file
View File

@@ -0,0 +1,30 @@
CFLAGS = -O2 -Wall
UTILS = $(INTERM_BINDIR)/ipx_configure $(INTERM_BINDIR)/ipx_interface \
$(INTERM_BINDIR)/ipx_internal_net $(INTERM_BINDIR)/ipx_route
all: $(UTILS)
$(INTERM_BINDIR)/ipx_configure: ipx_configure.o
$(CC) -s -o $(INTERM_BINDIR)/ipx_configure ipx_configure.o
$(INTERM_BINDIR)/ipx_interface: ipx_interface.o
$(CC) -s -o $(INTERM_BINDIR)/ipx_interface ipx_interface.o
$(INTERM_BINDIR)/ipx_internal_net: ipx_internal_net.o
$(CC) -s -o $(INTERM_BINDIR)/ipx_internal_net ipx_internal_net.o
$(INTERM_BINDIR)/ipx_route: ipx_route.o
$(CC) -s -o $(INTERM_BINDIR)/ipx_route ipx_route.o
dep:
$(CPP) -M $(INCLUDES) *.c > .depend
clean:
rm -f $(UTILS) *.o rip sap ipxrcv ipxsend
install: $(UTILS)
for i in $(UTILS); \
do \
install --strip $$i $(BINDIR); \
done

65
ipx-0.75/README Normal file
View File

@@ -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.

125
ipx-0.75/ipx_configure.c Normal file
View File

@@ -0,0 +1,125 @@
#include <stdio.h>
#include <unistd.h>
#include <ctype.h>
#include <getopt.h>
#include <strings.h>
#include <linux/ipx.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
struct option options[] = {
{ "auto_primary", required_argument, NULL, 1 },
{ "auto_interface", required_argument, NULL, 2 },
{ "help", no_argument, NULL, 3},
{ NULL, 0, NULL, 0 }
};
char *progname;
void
usage(void)
{
fprintf(stderr,
"Usage: %s --auto_primary=[on|off]\n\
Usage: %s --auto_interface=[on|off]\n\
Usage: %s --help\n\
Usage: %s\n", progname, progname, progname, progname);
}
int
map_string_to_bool(char *optarg)
{
if ((strcasecmp(optarg, "ON") == 0) ||
(strcasecmp(optarg, "TRUE") == 0) ||
(strcasecmp(optarg, "SET") == 0) ||
(strcasecmp(optarg, "YES") == 0)) {
return 1;
} else if ((strcasecmp(optarg, "OFF") == 0) ||
(strcasecmp(optarg, "FALSE") == 0) ||
(strcasecmp(optarg, "CLEAR") == 0) ||
(strcasecmp(optarg, "NO") == 0)) {
return 0;
}
return -1;
}
int
main(int argc, char **argv)
{
int s;
int result;
char errmsg[80];
char val;
int option_index = 0;
int got_auto_pri = 0;
int got_auto_itf = 0;
ipx_config_data data;
progname = argv[0];
s = socket(AF_IPX, SOCK_DGRAM, AF_IPX);
if (s < 0) {
sprintf(errmsg, "%s: socket", progname);
perror(errmsg);
exit(-1);
}
sprintf(errmsg, "%s: ioctl", progname);
while ((result = getopt_long(argc, argv, "", options,
&option_index)) != -1) {
switch (result) {
case 1:
if (got_auto_pri)
break;
got_auto_pri++;
val = map_string_to_bool(optarg);
if (val < 0) {
usage();
exit(-1);
}
result = ioctl(s, SIOCAIPXPRISLT, &val);
if (result < 0) {
perror(errmsg);
exit(-1);
}
break;
case 2:
if (got_auto_itf)
break;
got_auto_itf++;
val = map_string_to_bool(optarg);
if (val < 0) {
usage();
exit(-1);
}
result = ioctl(s, SIOCAIPXITFCRT, &val);
if (result < 0) {
perror(errmsg);
exit(-1);
}
break;
case 3:
usage();
break;
}
}
result = ioctl(s, SIOCIPXCFGDATA, &data);
if (result < 0) {
perror(errmsg);
exit(-1);
}
if (argc == 1) {
fprintf(stdout, "Auto Primary Select is %s\n\
Auto Interface Create is %s\n",
(data.ipxcfg_auto_select_primary) ? "ON" : "OFF",
(data.ipxcfg_auto_create_interfaces) ? "ON" : "OFF");
}
exit(0);
}

303
ipx-0.75/ipx_interface.c Normal file
View File

@@ -0,0 +1,303 @@
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <strings.h>
#include <netinet/in.h>
#include <linux/ipx.h>
#include <linux/if.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
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;
}

195
ipx-0.75/ipx_internal_net.c Normal file
View File

@@ -0,0 +1,195 @@
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <strings.h>
#include <netinet/in.h>
#include <linux/ipx.h>
#include <linux/if.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
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;
}

215
ipx-0.75/ipx_route.c Normal file
View File

@@ -0,0 +1,215 @@
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <strings.h>
#include <netinet/in.h>
#include <linux/ipx.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/route.h>
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;
}

52
ipx-0.75/ipxrcv.c Normal file
View File

@@ -0,0 +1,52 @@
#include <stdio.h>
#include <sys/types.h>
#include <linux/ipx.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <errno.h>
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;
}

46
ipx-0.75/ipxsend.c Normal file
View File

@@ -0,0 +1,46 @@
#include <stdio.h>
#include <sys/types.h>
#include <linux/ipx.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <errno.h>
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;
}

68
ipx-0.75/rip.c Normal file
View File

@@ -0,0 +1,68 @@
#include <stdio.h>
#include <sys/types.h>
#include <linux/ipx.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <errno.h>
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++;
}
}
}

96
ipx-0.75/sap.c Normal file
View File

@@ -0,0 +1,96 @@
#include <stdio.h>
#include <sys/types.h>
#include <linux/ipx.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <errno.h>
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++;
}
}
}

BIN
ipx.tar

Binary file not shown.

View File

@@ -1,53 +0,0 @@
/*
IPX support library
Copyright (C) 1994, 1995 Ales Dryak <e-mail: A.Dryak@sh.cvut.cz>
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 <string.h>
#include <linux/ipx.h>
#define IPX_SAP_PTYPE (0x04)
#define IPX_SAP_PORT (0x0452)
#define IPX_SAP_FILE_SERVER (0x004)
#define IPX_BROADCAST_NODE "\xff\xff\xff\xff\xff\xff"
#define IPX_THIS_NODE "\0\0\0\0\0\0"
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

View File

@@ -9,6 +9,7 @@
#define _LINUX_NCP_H
#include <linux/types.h>
#include <linux/ipx.h>
#define NCP_PTYPE (0x11)
#define NCP_PORT (0x0451)
@@ -45,11 +46,15 @@ struct ncp_reply_header {
#define NCP_BINDERY_USER (0x0001)
#define NCP_BINDERY_UGROUP (0x0002)
#define NCP_BINDERY_PQUEUE (0x0003)
#define NCP_BINDERY_FSERVER (0x0004)
#define NCP_BINDERY_NAME_LEN (48)
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 {
@@ -58,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)
@@ -177,6 +187,39 @@ struct nw_info_struct
__u8 entryName[256] __attribute__ ((packed));
};
/* modify mask - use with MODIFY_DOS_INFO structure */
#define DM_ATTRIBUTES (0x0002L)
#define DM_CREATE_DATE (0x0004L)
#define DM_CREATE_TIME (0x0008L)
#define DM_CREATOR_ID (0x0010L)
#define DM_ARCHIVE_DATE (0x0020L)
#define DM_ARCHIVE_TIME (0x0040L)
#define DM_ARCHIVER_ID (0x0080L)
#define DM_MODIFY_DATE (0x0100L)
#define DM_MODIFY_TIME (0x0200L)
#define DM_MODIFIER_ID (0x0400L)
#define DM_LAST_ACCESS_DATE (0x0800L)
#define DM_INHERITED_RIGHTS_MASK (0x1000L)
#define DM_MAXIMUM_SPACE (0x2000L)
struct nw_modify_dos_info
{
__u32 attributes __attribute__ ((packed));
__u16 creationDate __attribute__ ((packed));
__u16 creationTime __attribute__ ((packed));
__u32 creatorID __attribute__ ((packed));
__u16 modifyDate __attribute__ ((packed));
__u16 modifyTime __attribute__ ((packed));
__u32 modifierID __attribute__ ((packed));
__u16 archiveDate __attribute__ ((packed));
__u16 archiveTime __attribute__ ((packed));
__u32 archiverID __attribute__ ((packed));
__u16 lastAccessDate __attribute__ ((packed));
__u16 inheritanceGrantMask __attribute__ ((packed));
__u16 inheritanceRevokeMask __attribute__ ((packed));
__u32 maximumSpace __attribute__ ((packed));
};
struct nw_file_info {
struct nw_info_struct i;
int opened;
@@ -229,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));

View File

@@ -26,7 +26,25 @@ struct ncp_ioctl_request {
char *data;
};
struct ncp_fs_info {
int version;
struct sockaddr_ipx addr;
uid_t mounted_uid;
int connection; /* Connection number the server assigned us */
int buffer_size; /* The negotiated buffer size, to be
used for read/write requests! */
/* Not used yet, but here some day the namespace numbers will be
stored. */
int volume_number;
__u32 directory_id;
};
#define NCP_IOC_NCPREQUEST _IOR('n', 1, unsigned char *)
#define NCP_IOC_GETMOUNTUID _IOR('u', 1, uid_t)
#define NCP_GET_FS_INFO_VERSION (1)
#define NCP_IOC_GET_FS_INFO _IOWR('i', 1, unsigned char *)
/*
* The packet size to allocate. One page should be enough.
@@ -57,10 +75,6 @@ struct ncp_ioctl_request {
#define NCP_FINFO(inode) (&(NCP_INOP(inode)->finfo))
#define NCP_ISTRUCT(inode) (&(NCP_FINFO(inode)->i))
static inline int min(int a, int b) {
return a<b ? a : b;
}
#ifdef DEBUG_NCP_MALLOC
#include <linux/malloc.h>

View File

@@ -13,10 +13,10 @@
#ifdef __KERNEL__
enum ncp_inode_state {
INODE_VALID = 19, /* Inode currently in use */
INODE_LOOKED_UP, /* directly before iget */
INODE_CACHED, /* in a path to an inode which is in use */
INODE_INVALID
NCP_INODE_VALID = 19, /* Inode currently in use */
NCP_INODE_LOOKED_UP, /* directly before iget */
NCP_INODE_CACHED, /* in a path to an inode which is in use */
NCP_INODE_INVALID
};
/*

65
kernel-1.2/src/Makefile Normal file
View File

@@ -0,0 +1,65 @@
#
# Makefile for the linux ncp-filesystem routines.
#
CFLAGS = -Wall -Wstrict-prototypes -O2 -DMODULE -fomit-frame-pointer \
$(INCLUDES) \
# -DDEBUG_NCP=1 -DDEBUG_NCP_MALLOC
# -DDEBUG_NCP_MALLOC
CC = gcc -D__KERNEL__ -I.
AS = as
ARCH = i386
.c.s:
$(CC) $(CFLAGS) -S $<
.c.o:
$(CC) $(CFLAGS) -c $<
.s.o:
$(AS) -o $*.o $<
OBJS= dir.o inode.o file.o sock.o ioctl.o ncplib_kernel.o mmap.o
all: $(INTERM_BINDIR)/ncpfs.o
$(INTERM_BINDIR)/ncpfs.o: $(OBJS)
$(LD) -r -o $@ $(OBJS)
ncplib_kernel.o: ncplib_kernel.c ncplib_kernel.h
$(CC) $(CFLAGS) -finline-functions -c $<
dep:
$(CPP) -M $(INCLUDES) *.c > .depend
clean:
rm -f *.o *~
realclean: clean
rm -f ncpmount ncptest .depend $(DISTFILE) *.out
modules: ncpfs.o
SRCPATH=$(shell pwd)
SRCDIR=$(shell basename $(SRCPATH))
DISTFILE=$(SRCDIR).tgz
BACKUPFILE=ncpfs01.tgz
HOME=/home/me
backup:
(rm -f $(DISTFILE); cd ..; tar cvf - $(SRCDIR) | gzip -1 \
> $(HOME)/tarz/backup/$(BACKUPFILE))
(cd $(HOME)/tarz/backup; ls -l $(BACKUPFILE); mcopy $(BACKUPFILE) a:)
dist: realclean
rm -fr mnt
(cd ..; \
tar cvf - $(SRCDIR) | \
gzip -9 > $(DISTFILE); \
mv $(DISTFILE) $(SRCDIR))
#
# include a dependency file if one exists
#
ifeq (.depend,$(wildcard .depend))
include .depend
endif

View File

@@ -5,7 +5,11 @@
*
*/
/* #include <linux/module.h>*/
#include <linux/config.h>
#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
#endif
#include <linux/sched.h>
#include <linux/errno.h>
@@ -16,7 +20,7 @@
#include <linux/ncp_fs.h>
#include <asm/segment.h>
#include <linux/errno.h>
#include "ncplib.h"
#include "ncplib_kernel.h"
struct ncp_dirent {
struct nw_info_struct i;
@@ -29,7 +33,8 @@ ncp_dir_read(struct inode *inode, struct file *filp, char *buf, int count);
static int
ncp_readdir(struct inode *inode, struct file *filp,
void *dirent, filldir_t filldir);
struct dirent *dirent, int count);
static int
ncp_read_volume_list(struct ncp_server *server, int start_with,
int cache_size);
@@ -68,9 +73,12 @@ ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
static inline void
str_upper(char *name)
{
while (*name) {
while (*name)
{
if (*name >= 'a' && *name <= 'z')
{
*name -= ('a' - 'A');
}
name++;
}
}
@@ -78,9 +86,12 @@ str_upper(char *name)
static inline void
str_lower(char *name)
{
while (*name) {
while (*name)
{
if (*name >= 'A' && *name <= 'Z')
{
*name += ('a' - 'A');
}
name ++;
}
}
@@ -92,7 +103,7 @@ static struct file_operations ncp_dir_operations = {
ncp_readdir, /* readdir */
NULL, /* select - default */
ncp_ioctl, /* ioctl - default */
NULL, /* mmap */
NULL, /* mmap */
NULL, /* no special open code */
NULL, /* no special release code */
NULL /* fsync */
@@ -124,6 +135,9 @@ ncp_dir_read(struct inode *inode, struct file *filp, char *buf, int count)
return -EISDIR;
}
#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
#define ROUND_UP(x) (((x)+3) & ~3)
/* In ncpfs, we have unique inodes across all mounted filesystems, for
all inodes that are in memory. That's why it's enough to index the
directory cache by the inode number. */
@@ -136,7 +150,7 @@ static struct ncp_dirent* c_entry = NULL;
static int
ncp_readdir(struct inode *inode, struct file *filp,
void *dirent, filldir_t filldir)
struct dirent *dirent, int count)
{
int result, i = 0;
int index = 0;
@@ -144,11 +158,24 @@ ncp_readdir(struct inode *inode, struct file *filp,
struct ncp_server *server = NCP_SERVER(inode);
struct ncp_inode_info *dir = (struct ncp_inode_info *)(inode->i_ino);
int filldir(struct dirent *dirent,
const char *name, int len,
int f_pos, ino_t ino)
{
memcpy_tofs(dirent->d_name, name, len);
put_fs_byte(0, &(dirent->d_name[len]));
put_fs_long(ino, &dirent->d_ino);
put_fs_word(len, &dirent->d_reclen);
put_fs_word(f_pos, &dirent->d_off);
return 1;
}
DDPRINTK("ncp_readdir: filp->f_pos = %d\n", (int)filp->f_pos);
DDPRINTK("ncp_readdir: inode->i_ino = %ld, c_ino = %ld\n",
inode->i_ino, c_ino);
if (!inode || !S_ISDIR(inode->i_mode)) {
if (!inode || !S_ISDIR(inode->i_mode))
{
printk("ncp_readdir: inode is NULL or not a directory\n");
return -EBADF;
}
@@ -157,32 +184,40 @@ ncp_readdir(struct inode *inode, struct file *filp,
{
i = sizeof (struct ncp_dirent) * NCP_READDIR_CACHE_SIZE;
c_entry = (struct ncp_dirent *) ncp_kmalloc(i, GFP_KERNEL);
if (c_entry == NULL) {
if (c_entry == NULL)
{
printk("ncp_readdir: no MEMORY for cache\n");
return -ENOMEM;
}
}
if (filp->f_pos == 0) {
if (filp->f_pos == 0)
{
ncp_invalid_dir_cache(inode->i_ino);
if (filldir(dirent,".",1, filp->f_pos, (int)dir) < 0) {
if (filldir(dirent,".",1, filp->f_pos, (int)dir) < 0)
{
return 0;
}
filp->f_pos += 1;
return ROUND_UP(NAME_OFFSET(dirent)+i+1);
}
if (filp->f_pos == 1) {
if (filldir(dirent,"..",2, filp->f_pos, (int)(dir->dir)) < 0) {
if (filp->f_pos == 1)
{
if (filldir(dirent,"..",2, filp->f_pos, (int)(dir->dir)) < 0)
{
return 0;
}
filp->f_pos += 1;
return ROUND_UP(NAME_OFFSET(dirent)+i+1);
}
if (inode->i_ino == c_ino) {
for (i = 0; i < c_size; i++) {
if (filp->f_pos == c_entry[i].f_pos) {
if (inode->i_ino == c_ino)
{
for (i = 0; i < c_size; i++)
{
if (filp->f_pos == c_entry[i].f_pos)
{
entry = &c_entry[i];
c_last_returned_index = i;
index = i;
@@ -190,33 +225,38 @@ ncp_readdir(struct inode *inode, struct file *filp,
}
}
if ((entry == NULL) && c_seen_eof)
{
return 0;
}
}
if (entry == NULL) {
DPRINTK("ncp_readdir: Not found in cache.\n");
if (inode->i_ino == (int)&(server->root)) {
if (entry == NULL)
{
DDPRINTK("ncp_readdir: Not found in cache.\n");
if (inode->i_ino == (int)&(server->root))
{
result = ncp_read_volume_list(server, filp->f_pos,
NCP_READDIR_CACHE_SIZE);
DPRINTK("ncp_read_volume_list returned %d\n", result);
} else {
}
else
{
result = ncp_do_readdir(server, inode, filp->f_pos,
NCP_READDIR_CACHE_SIZE,
c_entry);
DPRINTK("ncp_readdir returned %d\n", result);
}
if (result < 0) {
if (result < 0)
{
c_ino = 0;
return result;
}
if (result > 0) {
if (result > 0)
{
c_seen_eof = (result < NCP_READDIR_CACHE_SIZE);
c_ino = inode->i_ino;
c_size = result;
@@ -224,19 +264,21 @@ ncp_readdir(struct inode *inode, struct file *filp,
c_last_returned_index = 0;
index = 0;
for (i = 0; i < c_size; i++) {
for (i = 0; i < c_size; i++)
{
str_lower(c_entry[i].i.entryName);
}
}
}
if (entry == NULL) {
if (entry == NULL)
{
/* Nothing found, even from a ncp call */
return 0;
}
while (index < c_size) {
if (index < c_size)
{
/* We found it. For getwd(), we have to return the
correct inode in d_ino if the inode is currently in
use. Otherwise the inode number does not
@@ -244,12 +286,12 @@ ncp_readdir(struct inode *inode, struct file *filp,
struct ncp_inode_info *ino_info;
ino_info = ncp_find_inode(inode, entry->i.entryName);
/* Some programs seem to be confused about a zero
inode number, so we set it to one. Thanks to
Gordon Chaffee for this one. */
if (ino_info == NULL) {
if (ino_info == NULL)
{
ino_info = (struct ncp_inode_info *) 1;
}
@@ -257,19 +299,15 @@ ncp_readdir(struct inode *inode, struct file *filp,
DDPRINTK("ncp_readdir: entry->f_pos = %ld\n", entry->f_pos);
if (filldir(dirent, entry->i.entryName, entry->i.nameLen,
entry->f_pos, (ino_t)ino_info) < 0) {
break;
entry->f_pos, (ino_t)ino_info) < 0)
{
return 0;
}
if ( (inode->i_ino != c_ino)
|| (entry->f_pos != filp->f_pos)) {
/* Someone has destroyed the cache while we slept
in filldir */
break;
}
filp->f_pos += 1;
index += 1;
entry += 1;
return ROUND_UP(NAME_OFFSET(dirent)+i+1);
}
return 0;
}
@@ -283,33 +321,42 @@ ncp_read_volume_list(struct ncp_server *server, int fpos, int cache_size)
int i;
#if 1
if (fpos < 2) {
if (fpos < 2)
{
printk("OOPS, we expect fpos >= 2");
fpos = 2;
}
fpos = 2;
#endif
for (i=0; i<NCP_NUMBER_OF_VOLUMES; i++) {
for (i=0; i<NCP_NUMBER_OF_VOLUMES; i++)
{
struct ncp_volume_info info;
if (ncp_get_volume_info_with_number(server, i, &info) != 0) {
if (ncp_get_volume_info_with_number(server, i, &info) != 0)
{
return total_count;
}
if (strlen(info.volume_name) > 0) {
if (total_count < fpos) {
if (strlen(info.volume_name) > 0)
{
if (total_count < fpos)
{
DPRINTK("ncp_read_volumes: skipped vol: %s\n",
info.volume_name);
} else if (total_count >= fpos + cache_size) {
}
else if (total_count >= fpos + cache_size)
{
return (total_count - fpos);
} else {
}
else
{
DPRINTK("ncp_read_volumes: found vol: %s\n",
info.volume_name);
if (ncp_do_lookup(server, NULL,
info.volume_name,
&(entry->i)) != 0) {
&(entry->i)) != 0)
{
printk("ncpfs: could not lookup vol "
"%s\n", info.volume_name);
continue;
@@ -321,7 +368,6 @@ ncp_read_volume_list(struct ncp_server *server, int fpos, int cache_size)
total_count += 1;
}
}
return (total_count - fpos);
}
@@ -329,41 +375,63 @@ static int
ncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos,
int cache_size, struct ncp_dirent *entry)
{
struct nw_search_sequence seq;
int total_count = 2;
static struct nw_search_sequence seq;
static struct inode *last_dir;
static int total_count;
#if 1
if (fpos < 2) {
if (fpos < 2)
{
printk("OOPS, we expect fpos >= 2");
fpos = 2;
}
fpos = 2;
#endif
DPRINTK("ncp_do_readdir: fpos = %d\n", fpos);
if (ncp_initialize_search(server, NCP_ISTRUCT(dir), &seq) != 0) {
DPRINTK("ncp_init_search failed\n");
return total_count - fpos;
if (fpos == 2)
{
last_dir = NULL;
total_count = 2;
}
while (total_count < fpos + cache_size) {
if ((fpos != total_count) || (dir != last_dir))
{
total_count = 2;
last_dir = dir;
DPRINTK("ncp_do_readdir: re-used seq for %s\n",
NCP_ISTRUCT(dir)->entryName);
if (ncp_initialize_search(server, NCP_ISTRUCT(dir), &seq)!=0)
{
DPRINTK("ncp_init_search failed\n");
return total_count - fpos;
}
}
while (total_count < fpos + cache_size)
{
if (ncp_search_for_file_or_subdir(server, &seq,
&(entry->i)) != 0) {
&(entry->i)) != 0)
{
return total_count - fpos;
}
if (total_count < fpos) {
if (total_count < fpos)
{
DPRINTK("ncp_do_readdir: skipped file: %s\n",
entry->i.entryName);
} else {
DPRINTK("ncp_do_readdir: found file: %s\n",
entry->i.entryName);
}
else
{
DDPRINTK("ncp_do_r: file: %s, f_pos=%d,total_count=%d",
entry->i.entryName, fpos, total_count);
entry->s = seq;
entry->f_pos = total_count;
entry += 1;
}
total_count += 1;
}
return (total_count - fpos);
}
@@ -377,7 +445,8 @@ ncp_init_dir_cache(void)
void
ncp_invalid_dir_cache(unsigned long ino)
{
if (ino == c_ino) {
if (ino == c_ino)
{
c_ino = 0;
c_seen_eof = 0;
}
@@ -389,7 +458,9 @@ ncp_free_dir_cache(void)
DPRINTK("ncp_free_dir_cache: enter\n");
if (c_entry == NULL)
{
return;
}
ncp_kfree_s(c_entry,
sizeof(struct ncp_dirent) * NCP_READDIR_CACHE_SIZE);
@@ -406,12 +477,14 @@ ncp_iget(struct inode *dir, struct nw_file_info *finfo)
struct ncp_inode_info *new_inode_info;
struct ncp_inode_info *root;
if (!dir) {
if (dir == NULL)
{
printk("ncp_iget: dir is NULL\n");
return NULL;
}
if (!finfo) {
if (finfo == NULL)
{
printk("ncp_iget: finfo is NULL\n");
return NULL;
}
@@ -419,13 +492,14 @@ ncp_iget(struct inode *dir, struct nw_file_info *finfo)
new_inode_info = ncp_kmalloc(sizeof(struct ncp_inode_info),
GFP_KERNEL);
if (new_inode_info == NULL) {
if (new_inode_info == NULL)
{
printk("ncp_iget: could not alloc mem for %s\n",
finfo->i.entryName);
return NULL;
}
new_inode_info->state = INODE_LOOKED_UP;
new_inode_info->state = NCP_INODE_LOOKED_UP;
new_inode_info->nused = 0;
new_inode_info->dir = NCP_INOP(dir);
new_inode_info->finfo = *finfo;
@@ -443,7 +517,8 @@ ncp_iget(struct inode *dir, struct nw_file_info *finfo)
root->next->prev = new_inode_info;
root->next = new_inode_info;
if (!(inode = iget(dir->i_sb, (int)new_inode_info))) {
if (!(inode = iget(dir->i_sb, (int)new_inode_info)))
{
printk("ncp_iget: iget failed!");
return NULL;
}
@@ -454,13 +529,15 @@ ncp_iget(struct inode *dir, struct nw_file_info *finfo)
void
ncp_free_inode_info(struct ncp_inode_info *i)
{
if (i == NULL) {
if (i == NULL)
{
printk("ncp_free_inode: i == NULL\n");
return;
}
i->state = INODE_CACHED;
while ((i->nused == 0) && (i->state == INODE_CACHED)) {
i->state = NCP_INODE_CACHED;
while ((i->nused == 0) && (i->state == NCP_INODE_CACHED))
{
struct ncp_inode_info *dir = i->dir;
i->next->prev = i->prev;
@@ -485,19 +562,19 @@ ncp_init_root(struct ncp_server *server)
struct nw_info_struct *i = &(root->finfo.i);
unsigned short dummy;
DPRINTK("ncp_init_root: server %s\n", server->m.server_name);
DPRINTK("ncp_init_root: i = %x\n", (int)i);
root->finfo.opened = 0;
i->attributes = aDIR;
i->dataStreamSize = 1024;
i->volNumber = NCP_NUMBER_OF_VOLUMES+1; /* illegal volnum */
ncp_date_unix2dos(0, &(i->creationTime), &(i->creationDate));
ncp_date_unix2dos(0, &(i->modifyTime), &(i->modifyDate));
ncp_date_unix2dos(0, &dummy, &(i->lastAccessDate));
i->nameLen = 0;
i->entryName[0] = '\0';
root->state = INODE_LOOKED_UP;
root->state = NCP_INODE_LOOKED_UP;
root->nused = 1;
root->dir = root;
root->next = root->prev = root;
@@ -513,11 +590,13 @@ ncp_free_all_inodes(struct ncp_server *server)
#if 1
struct ncp_inode_info *root = &(server->root);
if (root->next != root) {
if (root->next != root)
{
printk("ncp_free_all_inodes: INODES LEFT!!!\n");
}
while (root->next != root) {
while (root->next != root)
{
printk("ncp_free_all_inodes: freeing inode\n");
ncp_free_inode_info(root->next);
/* In case we have an endless loop.. */
@@ -538,17 +617,23 @@ ncp_find_inode(struct inode *dir, const char *name)
struct nw_info_struct *dir_info = NCP_ISTRUCT(dir);
struct ncp_inode_info *result = &(server->root);
if (name == NULL) {
if (name == NULL)
{
return NULL;
}
do {
if ( (result->finfo.i.DosDirNum == dir_info->DosDirNum)
do
{
if ( (result->dir->finfo.i.DosDirNum == dir_info->DosDirNum)
&& (result->dir->finfo.i.volNumber == dir_info->volNumber)
&& (strcmp(result->finfo.i.entryName, name) == 0))
{
return result;
}
result = result->next;
} while (result != &(server->root));
}
while (result != &(server->root));
return NULL;
}
@@ -562,9 +647,12 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
struct ncp_inode_info *result_info;
int found_in_cache;
char name[len+1];
*result = NULL;
if (!dir || !S_ISDIR(dir->i_mode)) {
if (!dir || !S_ISDIR(dir->i_mode))
{
printk("ncp_lookup: inode is NULL or not a directory.\n");
iput(dir);
return -ENOENT;
@@ -575,27 +663,45 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
server = NCP_SERVER(dir);
/* Fast cheat for . */
if (len == 0 || (len == 1 && __name[0] == '.')) {
if (len == 0 || (len == 1 && __name[0] == '.'))
{
*result = dir;
return 0;
}
/* ..and for .. */
if (len == 2 && __name[0] == '.' && __name[1] == '.') {
*result = iget(dir->i_sb, (int)(NCP_INOP(dir)->dir));
if (len == 2 && __name[0] == '.' && __name[1] == '.')
{
struct ncp_inode_info *parent = NCP_INOP(dir)->dir;
if (parent->state == NCP_INODE_CACHED)
{
parent->state = NCP_INODE_LOOKED_UP;
}
*result = iget(dir->i_sb, (int)parent);
iput(dir);
if (*result == 0)
{
return -EACCES;
}
else
{
return 0;
}
}
result_info = ncp_find_inode(dir, __name);
memcpy(name, __name, len);
name[len] = 0;
if (result_info != 0) {
result_info = ncp_find_inode(dir, name);
if (result_info->state == INODE_CACHED)
result_info->state = INODE_LOOKED_UP;
if (result_info != 0)
{
if (result_info->state == NCP_INODE_CACHED)
{
result_info->state = NCP_INODE_LOOKED_UP;
}
/* Here we convert the inode_info address into an
inode number */
@@ -603,7 +709,8 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
*result = iget(dir->i_sb, (int)result_info);
iput(dir);
if (*result == NULL) {
if (*result == NULL)
{
return -EACCES;
}
@@ -615,40 +722,41 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
found_in_cache = 0;
if (dir->i_ino == c_ino) {
if (dir->i_ino == c_ino)
{
int first = c_last_returned_index;
int i;
i = first;
do {
do
{
DDPRINTK("ncp_lookup: trying index: %d, name: %s\n",
i, c_entry[i].i.entryName);
if (strcmp(c_entry[i].i.entryName, __name) == 0) {
if (strcmp(c_entry[i].i.entryName, name) == 0)
{
DPRINTK("ncp_lookup: found in cache!\n");
finfo.i = c_entry[i].i;
found_in_cache = 1;
break;
}
i = (i + 1) % c_size;
} while (i != first);
}
while (i != first);
}
if (found_in_cache == 0) {
char this_name[len+1];
memcpy(this_name, __name, len);
this_name[len] = 0;
str_upper(this_name);
if (found_in_cache == 0)
{
str_upper(name);
DDPRINTK("ncp_lookup: do_lookup on %s/%s\n",
NCP_ISTRUCT(dir)->entryName, this_name);
NCP_ISTRUCT(dir)->entryName, name);
if (ncp_do_lookup(server,
dir->i_ino == (int)&(NCP_SERVER(dir)->root)
? NULL : NCP_ISTRUCT(dir),
this_name,
&(finfo.i)) != 0) {
name, &(finfo.i)) != 0)
{
iput(dir);
return -ENOENT;
}
@@ -657,7 +765,8 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
finfo.opened = 0;
str_lower(finfo.i.entryName);
if (!(*result = ncp_iget(dir, &finfo))) {
if (!(*result = ncp_iget(dir, &finfo)))
{
iput(dir);
return -EACCES;
}
@@ -675,7 +784,8 @@ ncp_create(struct inode *dir, const char *name, int len, int mode,
*result = NULL;
if (!dir || !S_ISDIR(dir->i_mode)) {
if (!dir || !S_ISDIR(dir->i_mode))
{
printk("ncp_create: inode is NULL or not a directory\n");
iput(dir);
return -ENOENT;
@@ -689,7 +799,8 @@ ncp_create(struct inode *dir, const char *name, int len, int mode,
NCP_ISTRUCT(dir), _name,
OC_MODE_CREATE|OC_MODE_OPEN,
0, AR_READ|AR_WRITE,
&finfo) != 0) {
&finfo) != 0)
{
iput(dir);
return -EACCES;
}
@@ -699,7 +810,8 @@ ncp_create(struct inode *dir, const char *name, int len, int mode,
str_lower(finfo.i.entryName);
finfo.access = O_RDWR;
if (!(*result = ncp_iget(dir, &finfo)) < 0) {
if (!(*result = ncp_iget(dir, &finfo)) < 0)
{
ncp_close_file(NCP_SERVER(dir), finfo.file_handle);
iput(dir);
return -EINVAL;
@@ -716,11 +828,20 @@ ncp_mkdir(struct inode *dir, const char *name, int len, int mode)
struct nw_file_info new_dir;
__u8 _name[len+1];
if ( (name[0] == '.')
&& ( (len == 1)
|| ( (len == 2)
&& (name[1] == '.'))))
{
return -EEXIST;
}
strncpy(_name, name, len);
_name[len] = '\0';
str_upper(_name);
if (!dir || !S_ISDIR(dir->i_mode)) {
if (!dir || !S_ISDIR(dir->i_mode))
{
printk("ncp_mkdir: inode is NULL or not a directory\n");
iput(dir);
return -ENOENT;
@@ -729,9 +850,12 @@ ncp_mkdir(struct inode *dir, const char *name, int len, int mode)
if (ncp_open_create_file_or_subdir(NCP_SERVER(dir),
NCP_ISTRUCT(dir), _name,
OC_MODE_CREATE, aDIR, 0xffff,
&new_dir) != 0) {
&new_dir) != 0)
{
error = -EACCES;
} else {
}
else
{
error = 0;
ncp_invalid_dir_cache(dir->i_ino);
}
@@ -746,12 +870,14 @@ ncp_rmdir(struct inode *dir, const char *name, int len)
int error;
__u8 _name[len+1];
if (!dir || !S_ISDIR(dir->i_mode)) {
if (!dir || !S_ISDIR(dir->i_mode))
{
printk("ncp_rmdir: inode is NULL or not a directory\n");
iput(dir);
return -ENOENT;
}
if (ncp_find_inode(dir, name) != NULL) {
if (ncp_find_inode(dir, name) != NULL)
{
error = -EBUSY;
}
else
@@ -763,7 +889,8 @@ ncp_rmdir(struct inode *dir, const char *name, int len)
if ((error = ncp_del_file_or_subdir(NCP_SERVER(dir),
NCP_ISTRUCT(dir),
_name)) == 0) {
_name)) == 0)
{
ncp_invalid_dir_cache(dir->i_ino);
}
else
@@ -781,24 +908,26 @@ ncp_unlink(struct inode *dir, const char *name, int len)
int error;
__u8 _name[len+1];
if (!dir || !S_ISDIR(dir->i_mode)) {
if (!dir || !S_ISDIR(dir->i_mode))
{
printk("ncp_unlink: inode is NULL or not a directory\n");
iput(dir);
return -ENOENT;
}
if (ncp_find_inode(dir, name) != NULL) {
if (ncp_find_inode(dir, name) != NULL)
{
error = -EBUSY;
}
else
{
strncpy(_name, name, len);
_name[len] = '\0';
str_upper(_name);
if ((error = ncp_del_file_or_subdir(NCP_SERVER(dir),
NCP_ISTRUCT(dir),
_name)) == 0) {
_name)) == 0)
{
ncp_invalid_dir_cache(dir->i_ino);
}
else
@@ -818,20 +947,23 @@ ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
char _old_name[old_len+1];
char _new_name[new_len+1];
if (!old_dir || !S_ISDIR(old_dir->i_mode)) {
if (!old_dir || !S_ISDIR(old_dir->i_mode))
{
printk("ncp_rename: old inode is NULL or not a directory\n");
res = -ENOENT;
goto finished;
}
if (!new_dir || !S_ISDIR(new_dir->i_mode)) {
if (!new_dir || !S_ISDIR(new_dir->i_mode))
{
printk("ncp_rename: new inode is NULL or not a directory\n");
res = -ENOENT;
goto finished;
}
if ( (ncp_find_inode(old_dir, old_name) != NULL)
|| (ncp_find_inode(new_dir, new_name) != NULL)) {
|| (ncp_find_inode(new_dir, new_name) != NULL))
{
res = -EBUSY;
goto finished;
}
@@ -841,14 +973,15 @@ ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
str_upper(_old_name);
strncpy(_new_name, new_name, new_len);
_new_name[old_len] = '\0';
_new_name[new_len] = '\0';
str_upper(_new_name);
res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
NCP_ISTRUCT(old_dir), _old_name,
NCP_ISTRUCT(new_dir), _new_name);
if (res == 0) {
if (res == 0)
{
ncp_invalid_dir_cache(old_dir->i_ino);
ncp_invalid_dir_cache(new_dir->i_ino);
}

View File

@@ -5,7 +5,11 @@
*
*/
/* #include <linux/module.h>*/
#include <linux/config.h>
#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
#endif
#include <asm/segment.h>
#include <asm/system.h>
@@ -17,9 +21,14 @@
#include <linux/stat.h>
#include <linux/mm.h>
#include <linux/ncp_fs.h>
#include "ncplib.h"
#include "ncplib_kernel.h"
#include <linux/malloc.h>
static inline int min(int a, int b)
{
return a<b ? a : b;
}
static int
ncp_fsync(struct inode *inode, struct file *file)
{
@@ -31,7 +40,8 @@ ncp_make_open(struct inode *i, int right)
{
struct nw_file_info *finfo;
if (i == NULL) {
if (i == NULL)
{
printk("ncp_make_open: got NULL inode\n");
return -EINVAL;
}
@@ -40,23 +50,27 @@ ncp_make_open(struct inode *i, int right)
DPRINTK("ncp_make_open: dirent->opened = %d\n", finfo->opened);
if (finfo->opened == 0) {
if (finfo->opened == 0)
{
/* tries max. rights */
if (ncp_open_create_file_or_subdir(NCP_SERVER(i),
NULL, NULL,
OC_MODE_OPEN, 0,
AR_READ | AR_WRITE,
finfo) == 0) {
finfo) == 0)
{
finfo->access = O_RDWR;
}
else if (ncp_open_create_file_or_subdir(NCP_SERVER(i),
NULL, NULL,
OC_MODE_OPEN, 0,
AR_READ,
finfo) == 0) {
finfo) == 0)
{
finfo->access = O_RDONLY;
} else {
}
else
{
return -EACCES;
}
}
@@ -74,18 +88,20 @@ ncp_make_open(struct inode *i, int right)
static int
ncp_file_read(struct inode *inode, struct file *file, char *buf, int count)
{
int bufsize, to_read, already_read;
int bufsize, already_read;
off_t pos;
int errno;
DPRINTK("ncp_file_read: enter %s\n", NCP_ISTRUCT(inode)->entryName);
if (!inode) {
if (inode == NULL)
{
DPRINTK("ncp_file_read: inode = NULL\n");
return -EINVAL;
}
if (!S_ISREG(inode->i_mode)) {
if (!S_ISREG(inode->i_mode))
{
DPRINTK("ncp_file_read: read from non-file, mode %07o\n",
inode->i_mode);
return -EINVAL;
@@ -94,33 +110,34 @@ ncp_file_read(struct inode *inode, struct file *file, char *buf, int count)
pos = file->f_pos;
if (pos + count > inode->i_size)
{
count = inode->i_size - pos;
}
if (count <= 0)
{
return 0;
}
if ((errno = ncp_make_open(inode, O_RDONLY)) != 0)
{
return errno;
}
bufsize = NCP_SERVER(inode)->buffer_size;
already_read = 0;
/* First read in as much as possible for each bufsize. */
while (already_read < count) {
while (already_read < count)
{
int read_this_time;
if ((pos % bufsize) != 0) {
to_read = bufsize - (pos % bufsize);
} else {
to_read = bufsize;
}
to_read = min(to_read, count - already_read);
int to_read = min(bufsize - (pos % bufsize),
count - already_read);
if (ncp_read(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
pos, to_read, buf, &read_this_time) != 0) {
pos, to_read, buf, &read_this_time) != 0)
{
return -EIO; /* This is not exact, i know.. */
}
@@ -128,14 +145,19 @@ ncp_file_read(struct inode *inode, struct file *file, char *buf, int count)
buf += read_this_time;
already_read += read_this_time;
if (read_this_time < to_read) {
if (read_this_time < to_read)
{
break;
}
}
file->f_pos = pos;
if (!IS_RDONLY(inode)) inode->i_atime = CURRENT_TIME;
if (!IS_RDONLY(inode))
{
inode->i_atime = CURRENT_TIME;
}
inode->i_dirt = 1;
DPRINTK("ncp_file_read: exit %s\n", NCP_ISTRUCT(inode)->entryName);
@@ -144,19 +166,21 @@ ncp_file_read(struct inode *inode, struct file *file, char *buf, int count)
}
static int
ncp_file_write(struct inode *inode, struct file *file, const char *buf,
ncp_file_write(struct inode *inode, struct file *file, char *buf,
int count)
{
int bufsize, to_write, already_written;
int bufsize, already_written;
off_t pos;
int errno;
if (!inode) {
if (inode == NULL)
{
DPRINTK("ncp_file_write: inode = NULL\n");
return -EINVAL;
}
if (!S_ISREG(inode->i_mode)) {
if (!S_ISREG(inode->i_mode))
{
DPRINTK("ncp_file_write: write to non-file, mode %07o\n",
inode->i_mode);
return -EINVAL;
@@ -165,33 +189,35 @@ ncp_file_write(struct inode *inode, struct file *file, const char *buf,
DPRINTK("ncp_file_write: enter %s\n", NCP_ISTRUCT(inode)->entryName);
if (count <= 0)
{
return 0;
}
if ((errno = ncp_make_open(inode, O_RDWR)) != 0)
{
return errno;
}
pos = file->f_pos;
if (file->f_flags & O_APPEND)
{
pos = inode->i_size;
}
bufsize = NCP_SERVER(inode)->buffer_size;
already_written = 0;
while (already_written < count) {
while (already_written < count)
{
int written_this_time;
int to_write = min(bufsize - (pos % bufsize),
count - already_written);
if ((pos % bufsize) != 0) {
to_write = bufsize - (pos % bufsize);
} else {
to_write = bufsize;
}
to_write = min(to_write, count - already_written);
if (ncp_write(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
pos, to_write, buf, &written_this_time) != 0) {
pos, to_write, buf, &written_this_time) != 0)
{
return -EIO;
}
@@ -199,7 +225,8 @@ ncp_file_write(struct inode *inode, struct file *file, const char *buf,
buf += written_this_time;
already_written += written_this_time;
if (written_this_time < to_write) {
if (written_this_time < to_write)
{
break;
}
}
@@ -209,7 +236,8 @@ ncp_file_write(struct inode *inode, struct file *file, const char *buf,
file->f_pos = pos;
if (pos > inode->i_size) {
if (pos > inode->i_size)
{
inode->i_size = pos;
}
@@ -225,7 +253,7 @@ static struct file_operations ncp_file_operations = {
NULL, /* readdir - bad */
NULL, /* select - default */
ncp_ioctl, /* ioctl */
NULL, /* mmap */
ncp_mmap, /* mmap */
NULL, /* open */
NULL, /* release */
ncp_fsync, /* fsync */

View File

@@ -5,7 +5,14 @@
*
*/
#include <linux/config.h>
#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
#else
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
#endif
#include <asm/system.h>
#include <asm/segment.h>
@@ -20,14 +27,14 @@
#include <linux/locks.h>
#include <linux/fcntl.h>
#include <linux/malloc.h>
#include "ncplib.h"
#include "ncplib_kernel.h"
extern int close_fp(struct file *filp);
static void ncp_put_inode(struct inode *);
static void ncp_read_inode(struct inode *);
static void ncp_put_super(struct super_block *);
static void ncp_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
static void ncp_statfs(struct super_block *sb, struct statfs *stat);
static int ncp_notify_change(struct inode *inode, struct iattr *attr);
static struct super_operations ncp_sops = {
@@ -39,7 +46,7 @@ static struct super_operations ncp_sops = {
NULL, /* write superblock */
ncp_statfs, /* stat filesystem */
NULL
};
};
/* ncp_read_inode: Called from iget, it only traverses the allocated
ncp_inode_info's and initializes the inode from the data found
@@ -61,20 +68,25 @@ ncp_read_inode(struct inode *inode)
struct ncp_inode_info *root = &(NCP_SERVER(inode)->root);
struct ncp_inode_info *check_info = root;
do {
if (inode_info == check_info) {
if (check_info->state == INODE_LOOKED_UP) {
do
{
if (inode_info == check_info)
{
if (check_info->state == NCP_INODE_LOOKED_UP)
{
DDPRINTK("ncp_read_inode: found it!\n");
goto good;
}
else {
else
{
printk("ncp_read_inode: "
"state != INODE_LOOKED_UP\n");
"state != NCP_INODE_LOOKED_UP\n");
goto good;
}
}
check_info = check_info->next;
} while (check_info != root);
}
while (check_info != root);
/* Ok, now we're in trouble. The inode info is not there. What
should we do now??? */
@@ -85,17 +97,18 @@ ncp_read_inode(struct inode *inode)
DDPRINTK("ncp_read_inode: read entry %s\n",
inode_info->finfo.i.entryName);
#endif
inode_info->state = INODE_VALID;
inode_info->state = NCP_INODE_VALID;
NCP_INOP(inode) = inode_info;
if (NCP_ISTRUCT(inode)->attributes & aDIR) {
if (NCP_ISTRUCT(inode)->attributes & aDIR)
{
inode->i_mode = NCP_SERVER(inode)->m.dir_mode;
/* for directories in dataStreamSize seems to be some
Object ID ??? */
inode->i_size = 0;
inode->i_size = 512;
}
else
else
{
inode->i_mode = NCP_SERVER(inode)->m.file_mode;
inode->i_size = NCP_ISTRUCT(inode)->dataStreamSize;
@@ -108,11 +121,16 @@ ncp_read_inode(struct inode *inode)
inode->i_gid = NCP_SERVER(inode)->m.gid;
inode->i_blksize = 1024;
inode->i_rdev = 0;
if ((inode->i_blksize != 0) && (inode->i_size != 0))
{
inode->i_blocks =
(inode->i_size - 1) / inode->i_blksize + 1;
}
else
{
inode->i_blocks = 0;
}
inode->i_mtime = ncp_date_dos2unix(NCP_ISTRUCT(inode)->modifyTime,
NCP_ISTRUCT(inode)->modifyDate);
@@ -122,12 +140,17 @@ ncp_read_inode(struct inode *inode)
NCP_ISTRUCT(inode)->lastAccessDate);
if (S_ISREG(inode->i_mode))
{
inode->i_op = &ncp_file_inode_operations;
}
else if (S_ISDIR(inode->i_mode))
{
inode->i_op = &ncp_dir_inode_operations;
}
else
{
inode->i_op = NULL;
}
}
static void
@@ -135,19 +158,24 @@ ncp_put_inode(struct inode *inode)
{
struct nw_file_info *finfo = NCP_FINFO(inode);
if (finfo->opened != 0) {
if (ncp_close_file(NCP_SERVER(inode), finfo->file_handle)!=0) {
if (finfo->opened != 0)
{
if (ncp_close_file(NCP_SERVER(inode), finfo->file_handle)!=0)
{
/* We can't do anything but complain. */
printk("ncp_put_inode: could not close\n");
}
}
DDPRINTK("ncp_put_inode: put %s\n",
finfo->i.entryName);
ncp_free_inode_info(NCP_INOP(inode));
if (S_ISDIR(inode->i_mode)) {
DPRINTK("ncp_put_inode: put directory %ld\n",
inode->i_ino);
if (S_ISDIR(inode->i_mode))
{
DDPRINTK("ncp_put_inode: put directory %ld\n",
inode->i_ino);
ncp_invalid_dir_cache(inode->i_ino);
}
@@ -161,25 +189,27 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
struct ncp_server *server;
struct file *ncp_filp;
struct file *wdog_filp;
kdev_t dev = sb->s_dev;
dev_t dev = sb->s_dev;
int error;
if (!data) {
if (data == NULL)
{
printk("ncp_read_super: missing data argument\n");
sb->s_dev = 0;
return NULL;
}
if (data->version != NCP_MOUNT_VERSION) {
if (data->version != NCP_MOUNT_VERSION)
{
printk("ncp warning: mount version %s than kernel\n",
(data->version < NCP_MOUNT_VERSION) ?
"older" : "newer");
}
if ( (data->ncp_fd >= NR_OPEN)
|| ((ncp_filp = current->files->fd[data->ncp_fd]) == NULL)
|| (!S_ISSOCK(ncp_filp->f_inode->i_mode))) {
|| (!S_ISSOCK(ncp_filp->f_inode->i_mode)))
{
printk("ncp_read_super: invalid ncp socket\n");
sb->s_dev = 0;
return NULL;
@@ -187,7 +217,8 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
if ( (data->wdog_fd >= NR_OPEN)
|| ((wdog_filp = current->files->fd[data->wdog_fd]) == NULL)
|| (!S_ISSOCK(wdog_filp->f_inode->i_mode))) {
|| (!S_ISSOCK(wdog_filp->f_inode->i_mode)))
{
printk("ncp_read_super: invalid wdog socket\n");
sb->s_dev = 0;
return NULL;
@@ -197,7 +228,8 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
server = (struct ncp_server *)ncp_kmalloc(sizeof(struct ncp_server),
GFP_KERNEL);
if (server == NULL) {
if (server == NULL)
{
printk("ncp_read_super: could not alloc ncp_server\n");
return NULL;
}
@@ -231,7 +263,8 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
server->packet_size = NCP_PACKET_SIZE;
server->packet = ncp_kmalloc(NCP_PACKET_SIZE, GFP_KERNEL);
if (server->packet == NULL) {
if (server->packet == NULL)
{
printk("ncpfs: could not alloc packet\n");
error = -ENOMEM;
unlock_super(sb);
@@ -244,7 +277,8 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
* Make the connection to the server
*/
if (ncp_catch_watchdog(server) != 0) {
if (ncp_catch_watchdog(server) != 0)
{
printk("ncp_read_super: Could not catch watchdog\n");
error = -EINVAL;
unlock_super(sb);
@@ -256,7 +290,8 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
ncp_unlock_server(server);
unlock_super(sb);
if (error < 0) {
if (error < 0)
{
sb->s_dev = 0;
printk("ncp_read_super: Failed connection, bailing out "
"(error = %d).\n", -error);
@@ -267,14 +302,16 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
DPRINTK("ncp_read_super: NCP_SBP(sb) = %x\n", (int)NCP_SBP(sb));
if (!(sb->s_mounted = iget(sb, (int)&(server->root)))) {
if (!(sb->s_mounted = iget(sb, (int)&(server->root))))
{
sb->s_dev = 0;
printk("ncp_read_super: get root inode failed\n");
goto disconnect;
}
if (ncp_negotiate_buffersize(server, NCP_DEFAULT_BUFSIZE,
&(server->buffer_size)) != 0) {
&(server->buffer_size)) != 0)
{
sb->s_dev = 0;
printk("ncp_read_super: could not get bufsize\n");
goto disconnect;
@@ -282,14 +319,6 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
/* if (ncp_login_user(server, server->m.username,
server->m.password) != 0) {
sb->s_dev = 0;
printk("ncp_read_super: login failed\n");
goto disconnect;
}
*/
MOD_INC_USE_COUNT;
return sb;
@@ -336,7 +365,7 @@ ncp_put_super(struct super_block *sb)
}
static void
ncp_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
ncp_statfs(struct super_block *sb, struct statfs *stat)
{
struct statfs tmp;
@@ -354,14 +383,15 @@ ncp_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
tmp.f_files = -1;
tmp.f_ffree = -1;
tmp.f_namelen = 12;
memcpy_tofs(buf, &tmp, bufsiz);
memcpy_tofs(stat, &tmp, sizeof(tmp));
}
/* DO MORE */
static int
ncp_notify_change(struct inode *inode, struct iattr *attr)
{
int result = 0;
int info_mask;
struct nw_modify_dos_info info;
if ((result = inode_change_ok(inode, attr)) < 0)
return result;
@@ -379,14 +409,62 @@ ncp_notify_change(struct inode *inode, struct iattr *attr)
~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO))))
return -EPERM;
if ((attr->ia_valid & ATTR_SIZE) != 0) {
info_mask = 0;
memset(&info, 0, sizeof(info));
if ((attr->ia_valid & ATTR_CTIME) != 0)
{
info_mask |= (DM_CREATE_TIME|DM_CREATE_DATE);
ncp_date_unix2dos(attr->ia_ctime,
&(info.creationTime), &(info.creationDate));
}
if ((attr->ia_valid & ATTR_MTIME) != 0)
{
info_mask |= (DM_MODIFY_TIME|DM_MODIFY_DATE);
ncp_date_unix2dos(attr->ia_mtime,
&(info.modifyTime), &(info.modifyDate));
}
if ((attr->ia_valid & ATTR_ATIME) != 0)
{
__u16 dummy;
info_mask |= (DM_LAST_ACCESS_DATE);
ncp_date_unix2dos(attr->ia_ctime,
&(dummy), &(info.lastAccessDate));
}
if (info_mask != 0)
{
if ((result =
ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
NCP_ISTRUCT(inode),
info_mask,
&info)) != 0)
{
result = -EACCES;
if (info_mask == (DM_CREATE_TIME|DM_CREATE_DATE))
{
/* NetWare seems not to allow this. I
do not know why. So, just tell the
user everything went fine. This is
a terrible hack, but I do not know
how to do this correctly. */
result = 0;
}
}
}
if ((attr->ia_valid & ATTR_SIZE) != 0)
{
int written;
DPRINTK("ncpfs: trying to change size of %s to %ld\n",
NCP_ISTRUCT(inode)->entryName, attr->ia_size);
if ((result = ncp_make_open(inode, O_RDWR)) < 0) {
if ((result = ncp_make_open(inode, O_RDWR)) < 0)
{
return -EACCES;
}
@@ -414,6 +492,8 @@ int ncp_current_malloced;
#ifdef MODULE
char kernel_version[] = UTS_RELEASE;
static struct file_system_type ncp_fs_type = {
ncp_read_super, "ncpfs", 0, NULL
};

134
kernel-1.2/src/ioctl.c Normal file
View File

@@ -0,0 +1,134 @@
/*
* ioctl.c
*
* Copyright (C) 1995 by Volker Lendecke
*
*/
#include <linux/config.h>
#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
#endif
#include <asm/segment.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ncp_fs.h>
#include <linux/ioctl.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/ncp.h>
int
ncp_ioctl (struct inode * inode, struct file * filp,
unsigned int cmd, unsigned long arg)
{
int result;
struct ncp_ioctl_request request;
struct ncp_fs_info info;
struct ncp_server *server = NCP_SERVER(inode);
switch(cmd) {
case NCP_IOC_NCPREQUEST:
if ( (permission(inode, MAY_WRITE) != 0)
&& (current->uid != server->m.mounted_uid))
{
return -EACCES;
}
if ((result = verify_area(VERIFY_READ, (char *)arg,
sizeof(request))) != 0)
{
return result;
}
memcpy_fromfs(&request, (struct ncp_ioctl_request *)arg,
sizeof(request));
if ( (request.function > 255)
|| (request.size >
NCP_PACKET_SIZE - sizeof(struct ncp_request_header)))
{
return -EINVAL;
}
if ((result = verify_area(VERIFY_WRITE, (char *)request.data,
NCP_PACKET_SIZE)) != 0)
{
return result;
}
ncp_lock_server(server);
/* FIXME: We hack around in the server's structures
here to be able to use ncp_request */
server->has_subfunction = 0;
server->current_size = request.size;
memcpy_fromfs(server->packet, request.data, request.size);
ncp_request(server, request.function);
DPRINTK("ncp_ioctl: copy %d bytes\n",
server->reply_size);
memcpy_tofs(request.data, server->packet, server->reply_size);
ncp_unlock_server(server);
return server->reply_size;
case NCP_IOC_GET_FS_INFO:
if ( (permission(inode, MAY_WRITE) != 0)
&& (current->uid != server->m.mounted_uid))
{
return -EACCES;
}
if ((result = verify_area(VERIFY_WRITE, (char *)arg,
sizeof(info))) != 0)
{
return result;
}
memcpy_fromfs(&info, (struct ncp_fs_info *)arg,
sizeof(info));
if (info.version != NCP_GET_FS_INFO_VERSION)
{
DPRINTK("info.version invalid: %d\n", info.version);
return -EINVAL;
}
info.addr = server->m.serv_addr;
info.mounted_uid = server->m.mounted_uid;
info.connection = server->connection;
info.buffer_size = server->buffer_size;
memcpy_tofs((struct ncp_fs_info *)arg, &info, sizeof(info));
return 0;
case NCP_IOC_GETMOUNTUID:
if ( (permission(inode, MAY_READ) != 0)
&& (current->uid != server->m.mounted_uid))
{
return -EACCES;
}
if ((result = verify_area(VERIFY_WRITE, (uid_t*) arg,
sizeof(uid_t))) != 0)
{
return result;
}
put_fs_word(server->m.mounted_uid, (uid_t*) arg);
return 0;
default:
return -EINVAL;
}
return -EINVAL;
}

152
kernel-1.2/src/mmap.c Normal file
View File

@@ -0,0 +1,152 @@
/*
* mmap.c
*
* Copyright (C) 1995 by Volker Lendecke
*
*/
#include <linux/config.h>
#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
#endif
#include <linux/stat.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/shm.h>
#include <linux/errno.h>
#include <linux/mman.h>
#include <linux/string.h>
#include <linux/malloc.h>
#include <linux/fcntl.h>
#include <linux/ncp_fs.h>
#include "ncplib_kernel.h"
#include <asm/segment.h>
#include <asm/system.h>
static inline int min(int a, int b)
{
return a<b ? a : b;
}
/*
* Fill in the supplied page for mmap
*/
static unsigned long
ncp_file_mmap_nopage(struct vm_area_struct * area,
unsigned long address, unsigned long page, int no_share)
{
struct inode * inode = area->vm_inode;
unsigned int clear;
unsigned long tmp;
int bufsize;
int pos;
unsigned short fs;
address &= PAGE_MASK;
pos = address - area->vm_start + area->vm_offset;
clear = 0;
if (address + PAGE_SIZE > area->vm_end)
{
clear = address + PAGE_SIZE - area->vm_end;
}
/* what we can read in one go */
bufsize = NCP_SERVER(inode)->buffer_size;
fs = get_fs();
set_fs(get_ds());
if (ncp_make_open(inode, O_RDONLY) < 0)
{
clear = PAGE_SIZE;
}
else
{
int already_read = 0;
int count = PAGE_SIZE - clear;
int to_read;
while (already_read < count)
{
int read_this_time;
if ((pos % bufsize) != 0)
{
to_read = bufsize - (pos % bufsize);
}
else
{
to_read = bufsize;
}
to_read = min(to_read, count - already_read);
if (ncp_read(NCP_SERVER(inode),
NCP_FINFO(inode)->file_handle,
pos, to_read,
(char *)(page + already_read),
&read_this_time) != 0)
{
read_this_time = 0;
}
pos += read_this_time;
already_read += read_this_time;
if (read_this_time < to_read)
{
break;
}
}
}
set_fs(fs);
tmp = page + PAGE_SIZE;
while (clear--) {
*(char *)--tmp = 0;
}
return page;
}
struct vm_operations_struct ncp_file_mmap = {
NULL, /* open */
NULL, /* close */
NULL, /* unmap */
NULL, /* protect */
NULL, /* sync */
NULL, /* advise */
ncp_file_mmap_nopage, /* nopage */
NULL, /* wppage */
NULL, /* swapout */
NULL, /* swapin */
};
/* This is used for a general mmap of a ncp file */
int
ncp_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)
{
DPRINTK("ncp_mmap: called\n");
/* only PAGE_COW or read-only supported now */
if (vma->vm_flags & VM_SHARED)
return -EINVAL;
if (!inode->i_sb || !S_ISREG(inode->i_mode))
return -EACCES;
if (!IS_RDONLY(inode)) {
inode->i_atime = CURRENT_TIME;
inode->i_dirt = 1;
}
vma->vm_inode = inode;
inode->i_count++;
vma->vm_ops = &ncp_file_mmap;
return 0;
}

View File

@@ -1,14 +1,25 @@
#include "ncplib.h"
#include "nwcrypt.h"
#include <linux/config.h>
#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
#endif
#include "ncplib_kernel.h"
typedef __u8 byte;
typedef __u16 word;
typedef __u32 dword;
static inline int min(int a, int b)
{
return a<b ? a : b;
}
static void
assert_server_locked(struct ncp_server *server)
{
if (server->lock == 0) {
if (server->lock == 0)
{
DPRINTK("ncpfs: server not locked!\n");
}
}
@@ -41,7 +52,7 @@ ncp_add_dword(struct ncp_server *server, dword x)
}
static void
ncp_add_mem(struct ncp_server *server, const char *source, int size)
ncp_add_mem(struct ncp_server *server, const void *source, int size)
{
assert_server_locked(server);
memcpy(&(server->packet[server->current_size]), source, size);
@@ -63,7 +74,8 @@ ncp_add_pstring(struct ncp_server *server, const char *s)
{
int len = strlen(s);
assert_server_locked(server);
if (len > 255) {
if (len > 255)
{
DPRINTK("ncpfs: string too long: %s\n", s);
len = 255;
}
@@ -118,14 +130,15 @@ ncp_reply_dword(struct ncp_server *server, int offset)
int
ncp_negotiate_buffersize(struct ncp_server *server,
int size, int *target) {
int size, int *target)
{
int result;
ncp_init_request(server);
ncp_add_word(server, htons(size));
if ((result = ncp_request(server, 33)) != 0) {
if ((result = ncp_request(server, 33)) != 0)
{
ncp_unlock_server(server);
return result;
}
@@ -146,7 +159,8 @@ ncp_get_volume_info_with_number(struct ncp_server *server, int n,
ncp_init_request_s(server, 44);
ncp_add_byte(server, n);
if ((result = ncp_request(server, 22)) != 0) {
if ((result = ncp_request(server, 22)) != 0)
{
ncp_unlock_server(server);
return result;
}
@@ -162,7 +176,8 @@ ncp_get_volume_info_with_number(struct ncp_server *server, int n,
memset(&(target->volume_name), 0, sizeof(target->volume_name));
len = ncp_reply_byte(server, 29);
if (len > NCP_VOLNAME_LEN) {
if (len > NCP_VOLNAME_LEN)
{
DPRINTK("ncpfs: volume name too long: %d\n", len);
ncp_unlock_server(server);
return -EIO;
@@ -181,7 +196,8 @@ ncp_get_volume_number(struct ncp_server *server, const char *name, int *target)
ncp_init_request_s(server, 5);
ncp_add_pstring(server, name);
if ((result = ncp_request(server, 22)) != 0) {
if ((result = ncp_request(server, 22)) != 0)
{
ncp_unlock_server(server);
return result;
}
@@ -200,7 +216,8 @@ ncp_close_file(struct ncp_server *server, const char *file_id)
ncp_add_byte(server, 0);
ncp_add_mem(server, file_id, 6);
if ((result = ncp_request(server, 66)) != 0) {
if ((result = ncp_request(server, 66)) != 0)
{
ncp_unlock_server(server);
return result;
}
@@ -217,12 +234,16 @@ ncp_add_handle_path(struct ncp_server *server,
{
ncp_add_byte(server, vol_num);
ncp_add_dword(server, dir_base);
if (have_dir_base != 0) {
if (have_dir_base != 0)
{
ncp_add_byte(server, 1); /* dir_base */
} else {
}
else
{
ncp_add_byte(server, 0xff); /* no handle */
}
if (path != NULL) {
if (path != NULL)
{
ncp_add_byte(server, 1); /* 1 component */
ncp_add_pstring(server, path);
}
@@ -258,11 +279,13 @@ ncp_do_lookup(struct ncp_server *server,
int result;
char *volname = NULL;
if (target == NULL) {
if (target == NULL)
{
return -EINVAL;
}
if (dir == NULL) {
if (dir == NULL)
{
DDPRINTK("ncp_do_lookup: looking up vol %s\n", path);
@@ -276,7 +299,8 @@ ncp_do_lookup(struct ncp_server *server,
ncp_add_handle_path(server, 0, 0, 0, /* no handle */
path);
if ((result = ncp_request(server, 87)) != 0) {
if ((result = ncp_request(server, 87)) != 0)
{
ncp_unlock_server(server);
return result;
}
@@ -302,14 +326,16 @@ ncp_do_lookup(struct ncp_server *server,
ncp_add_handle_path(server, vol_num, dir_base, 1,
path);
if ((result = ncp_request(server, 87)) != 0) {
if ((result = ncp_request(server, 87)) != 0)
{
ncp_unlock_server(server);
return result;
}
ncp_extract_file_info(ncp_reply_data(server, 0), target);
if (volname != NULL) {
if (volname != NULL)
{
target->nameLen = strlen(volname);
strcpy(target->entryName, volname);
}
@@ -318,6 +344,35 @@ ncp_do_lookup(struct ncp_server *server,
return 0;
}
int
ncp_modify_file_or_subdir_dos_info(struct ncp_server *server,
struct nw_info_struct *file,
__u32 info_mask,
struct nw_modify_dos_info *info)
{
int result;
ncp_init_request(server);
ncp_add_byte(server, 7); /* subfunction */
ncp_add_byte(server, 0); /* dos name space */
ncp_add_byte(server, 0); /* reserved */
ncp_add_word(server, 0x8006); /* search attribs: all */
ncp_add_dword(server, info_mask);
ncp_add_mem(server, info, sizeof(*info));
ncp_add_handle_path(server, file->volNumber,
file->DosDirNum, 1, NULL);
if ((result = ncp_request(server, 87)) != 0)
{
ncp_unlock_server(server);
return result;
}
ncp_unlock_server(server);
return 0;
}
int
ncp_del_file_or_subdir(struct ncp_server *server,
struct nw_info_struct *dir, char *name)
@@ -332,7 +387,8 @@ ncp_del_file_or_subdir(struct ncp_server *server,
ncp_add_handle_path(server, dir->volNumber,
dir->DosDirNum, 1, name);
if ((result = ncp_request(server, 87)) != 0) {
if ((result = ncp_request(server, 87)) != 0)
{
ncp_unlock_server(server);
return result;
}
@@ -373,16 +429,20 @@ ncp_open_create_file_or_subdir(struct ncp_server *server,
for directories */
ncp_add_word(server, desired_acc_rights);
if (dir != NULL) {
if (dir != NULL)
{
ncp_add_handle_path(server, dir->volNumber,
dir->DosDirNum, 1, name);
} else {
}
else
{
ncp_add_handle_path(server,
target->i.volNumber, target->i.DosDirNum,
1, NULL);
}
if ((result = ncp_request(server, 87)) != 0) {
if ((result = ncp_request(server, 87)) != 0)
{
ncp_unlock_server(server);
return result;
}
@@ -391,7 +451,8 @@ ncp_open_create_file_or_subdir(struct ncp_server *server,
target->server_file_handle = ncp_reply_dword(server, 0);
target->open_create_action = ncp_reply_byte(server, 4);
if (dir != NULL) {
if (dir != NULL)
{
/* in target there's a new finfo to fill */
ncp_extract_file_info(ncp_reply_data(server, 5), &(target->i));
}
@@ -416,7 +477,8 @@ ncp_initialize_search(struct ncp_server *server,
ncp_add_byte(server, 0); /* reserved */
ncp_add_handle_path(server, dir->volNumber, dir->DosDirNum, 1, NULL);
if ((result = ncp_request(server, 87)) != 0) {
if ((result = ncp_request(server, 87)) != 0)
{
ncp_unlock_server(server);
return result;
}
@@ -441,12 +503,13 @@ ncp_search_for_file_or_subdir(struct ncp_server *server,
ncp_add_byte(server, 0); /* data stream (???) */
ncp_add_word(server, 0xffff); /* Search attribs */
ncp_add_dword(server, RIM_ALL); /* return info mask */
ncp_add_mem(server, (unsigned char *)seq, 9);
ncp_add_mem(server, seq, 9);
ncp_add_byte(server, 2); /* 2 byte pattern */
ncp_add_byte(server, 0xff); /* following is a wildcard */
ncp_add_byte(server, '*');
if ((result = ncp_request(server, 87)) != 0) {
if ((result = ncp_request(server, 87)) != 0)
{
ncp_unlock_server(server);
return result;
}
@@ -512,14 +575,15 @@ ncp_read(struct ncp_server *server, const char *file_id,
ncp_add_dword(server, htonl(offset));
ncp_add_word(server, htons(to_read));
if ((result = ncp_request(server, 72)) != 0) {
if ((result = ncp_request(server, 72)) != 0)
{
ncp_unlock_server(server);
return result;
}
*bytes_read = ntohs(ncp_reply_word(server, 0));
memcpy_tofs(target, ncp_reply_data(server, 2), *bytes_read);
memcpy_tofs(target, ncp_reply_data(server, 2+(offset&1)), *bytes_read);
ncp_unlock_server(server);
return 0;
@@ -539,7 +603,8 @@ ncp_write(struct ncp_server *server, const char *file_id,
ncp_add_word(server, htons(to_write));
ncp_add_mem_fromfs(server, source, to_write);
if ((result = ncp_request(server, 73)) != 0) {
if ((result = ncp_request(server, 73)) != 0)
{
ncp_unlock_server(server);
return result;
}

View File

@@ -119,6 +119,12 @@ ncp_do_lookup(struct ncp_server *server,
char *path, /* may only be one component */
struct nw_info_struct *target);
int
ncp_modify_file_or_subdir_dos_info(struct ncp_server *server,
struct nw_info_struct *file,
__u32 info_mask,
struct nw_modify_dos_info *info);
int
ncp_del_file_or_subdir(struct ncp_server *server,
struct nw_info_struct *dir, char *name);

View File

@@ -7,7 +7,11 @@
*
*/
/* #include <linux/module.h> */
#include <linux/config.h>
#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
#endif
#include <linux/sched.h>
#include <linux/ncp_fs.h>
@@ -25,52 +29,10 @@
#include <linux/ncp.h>
#include <linux/ncp_fs.h>
#include <linux/ncp_fs_sb.h>
#include <net/sock.h>
#include "/usr/src/linux/net/inet/sock.h"
#define _S(nr) (1<<((nr)-1))
static int _recvfrom(struct socket *sock, unsigned char *ubuf,
int size, int noblock, unsigned flags,
struct sockaddr_ipx *sa, int *addr_len)
{
struct iovec iov;
struct msghdr msg;
iov.iov_base = ubuf;
iov.iov_len = size;
msg.msg_name = (void *)sa;
msg.msg_namelen = 0;
if (addr_len)
msg.msg_namelen = *addr_len;
msg.msg_accrights = NULL;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
return sock->ops->recvmsg(sock, &msg, size, noblock, flags, addr_len);
}
static int _sendto(struct socket *sock, const void *buff,
int len, int nonblock, unsigned flags,
struct sockaddr_ipx *sa, int addr_len)
{
struct iovec iov;
struct msghdr msg;
iov.iov_base = (void *)buff;
iov.iov_len = len;
msg.msg_name = (void *)sa;
msg.msg_namelen = addr_len;
msg.msg_accrights = NULL;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
return sock->ops->sendmsg(sock, &msg, len, nonblock, flags);
}
static void
ncp_wdog_data_ready(struct sock *sk, int len)
{
@@ -80,15 +42,16 @@ ncp_wdog_data_ready(struct sock *sk, int len)
{
unsigned char packet_buf[2];
struct sockaddr_ipx sender;
int addr_len;
int addr_len = sizeof(struct sockaddr_ipx);
int result;
unsigned short fs;
fs = get_fs();
set_fs(get_ds());
result = _recvfrom(sock, (void *)packet_buf, 2, 1, 0,
&sender, &addr_len);
result = sock->ops->recvfrom(sock, (void *)packet_buf, 2, 1, 0,
(struct sockaddr *)&sender,
&addr_len);
if ( (result != 2)
|| (packet_buf[1] != '?')
@@ -96,16 +59,19 @@ ncp_wdog_data_ready(struct sock *sk, int len)
)
{
/* Error, throw away the complete packet */
_recvfrom(sock, (void *)packet_buf, 2, 1, 0,
&sender, &addr_len);
sock->ops->recvfrom(sock, (void *)packet_buf, 2, 1, 0,
(struct sockaddr *)&sender,
&addr_len);
printk("ncpfs: got strange packet on watchdog "
"socket\n");
} else {
}
else
{
int result;
DPRINTK("ncpfs: got watchdog from:\n");
DPRINTK("ncpfs: %08lX:%02X%02X%02X%02X%02X%02X:%04X,"
DDPRINTK("ncpfs: got watchdog from:\n");
DDPRINTK("ncpfs: %08lX:%02X%02X%02X%02X%02X%02X:%04X,"
" conn:%02X,type:%c\n",
htonl(sender.sipx_network),
sender.sipx_node[0], sender.sipx_node[1],
@@ -115,9 +81,11 @@ ncp_wdog_data_ready(struct sock *sk, int len)
packet_buf[0], packet_buf[1]);
packet_buf[1] = 'Y';
result = _sendto(sock, (void *)packet_buf, 2, 1, 0,
&sender, sizeof(sender));
DPRINTK("send result: %d\n", result);
result = sock->ops->sendto(sock, (void *)packet_buf,
2, 1, 0,
(struct sockaddr *)&sender,
sizeof(sender));
DDPRINTK("send result: %d\n", result);
}
set_fs(fs);
}
@@ -135,8 +103,8 @@ ncp_catch_watchdog(struct ncp_server *server)
if ( (server == NULL)
|| ((file = server->wdog_filp) == NULL)
|| ((inode = file->f_inode) == NULL)
|| (!S_ISSOCK(inode->i_mode))) {
|| (!S_ISSOCK(inode->i_mode)))
{
printk("ncp_catch_watchdog: did not get valid server!\n");
server->data_ready = NULL;
return -EINVAL;
@@ -144,7 +112,8 @@ ncp_catch_watchdog(struct ncp_server *server)
sock = &(inode->u.socket_i);
if (sock->type != SOCK_DGRAM) {
if (sock->type != SOCK_DGRAM)
{
printk("ncp_catch_watchdog: did not get SOCK_STREAM\n");
server->data_ready = NULL;
return -EINVAL;
@@ -152,7 +121,8 @@ ncp_catch_watchdog(struct ncp_server *server)
sk = (struct sock *)(sock->data);
if (sk == NULL) {
if (sk == NULL)
{
printk("ncp_catch_watchdog: sk == NULL");
server->data_ready = NULL;
return -EINVAL;
@@ -162,7 +132,8 @@ ncp_catch_watchdog(struct ncp_server *server)
(unsigned int)(sk->data_ready),
(unsigned int)(server->data_ready));
if (sk->data_ready == ncp_wdog_data_ready) {
if (sk->data_ready == ncp_wdog_data_ready)
{
printk("ncp_catch_watchdog: already done\n");
return -EINVAL;
}
@@ -183,8 +154,8 @@ ncp_dont_catch_watchdog(struct ncp_server *server)
if ( (server == NULL)
|| ((file = server->wdog_filp) == NULL)
|| ((inode = file->f_inode) == NULL)
|| (!S_ISSOCK(inode->i_mode))) {
|| (!S_ISSOCK(inode->i_mode)))
{
printk("ncp_dont_catch_watchdog: "
"did not get valid server!\n");
return -EINVAL;
@@ -192,25 +163,29 @@ ncp_dont_catch_watchdog(struct ncp_server *server)
sock = &(inode->u.socket_i);
if (sock->type != SOCK_DGRAM) {
if (sock->type != SOCK_DGRAM)
{
printk("ncp_dont_catch_watchdog: did not get SOCK_STREAM\n");
return -EINVAL;
}
sk = (struct sock *)(sock->data);
if (sk == NULL) {
if (sk == NULL)
{
printk("ncp_dont_catch_watchdog: sk == NULL");
return -EINVAL;
}
if (server->data_ready == NULL) {
if (server->data_ready == NULL)
{
printk("ncp_dont_catch_watchdog: "
"server->data_ready == NULL\n");
return -EINVAL;
}
if (sk->data_ready != ncp_wdog_data_ready) {
if (sk->data_ready != ncp_wdog_data_ready)
{
printk("ncp_dont_catch_watchdog: "
"sk->data_callback != ncp_data_callback\n");
return -EINVAL;
@@ -247,7 +222,6 @@ do_ncp_rpc_call(struct ncp_server *server, int size)
int timeout;
int retrans;
int major_timeout_seen;
char *server_name;
int n;
int addrlen;
unsigned long old_mask;
@@ -263,7 +237,8 @@ do_ncp_rpc_call(struct ncp_server *server, int size)
inode = file->f_inode;
select = file->f_op->select;
sock = &inode->u.socket_i;
if (!sock) {
if (!sock)
{
printk("ncp_rpc_call: socki_lookup failed\n");
return -EBADF;
}
@@ -271,22 +246,22 @@ do_ncp_rpc_call(struct ncp_server *server, int size)
max_timeout = NCP_MAX_RPC_TIMEOUT*HZ/10;
retrans = server->m.retry_count;
major_timeout_seen = 0;
server_name = server->m.server_name;
old_mask = current->blocked;
current->blocked |= ~(_S(SIGKILL)
#if 0
| _S(SIGSTOP)
#endif
| ((server->m.flags & NCP_MOUNT_INTR)
? ((current->sig->action[SIGINT - 1].sa_handler == SIG_DFL
? ((current->sigaction[SIGINT - 1].sa_handler == SIG_DFL
? _S(SIGINT) : 0)
| (current->sig->action[SIGQUIT - 1].sa_handler == SIG_DFL
| (current->sigaction[SIGQUIT - 1].sa_handler == SIG_DFL
? _S(SIGQUIT) : 0))
: 0));
fs = get_fs();
set_fs(get_ds());
for (n = 0, timeout = init_timeout; ; n++, timeout <<= 1) {
/* DDPRINTK("ncpfs: %08lX:%02X%02X%02X%02X%02X%02X:%04X\n",
for (n = 0, timeout = init_timeout; ; n++, timeout <<= 1)
{
DDPRINTK("ncpfs: %08lX:%02X%02X%02X%02X%02X%02X:%04X\n",
htonl(server->m.serv_addr.sipx_network),
server->m.serv_addr.sipx_node[0],
server->m.serv_addr.sipx_node[1],
@@ -294,7 +269,7 @@ do_ncp_rpc_call(struct ncp_server *server, int size)
server->m.serv_addr.sipx_node[3],
server->m.serv_addr.sipx_node[4],
server->m.serv_addr.sipx_node[5],
ntohs(server->m.serv_addr.sipx_port));*/
ntohs(server->m.serv_addr.sipx_port));
DDPRINTK("ncpfs: req.typ: %04X, con: %d, "
"seq: %d",
request.type,
@@ -303,10 +278,12 @@ do_ncp_rpc_call(struct ncp_server *server, int size)
DDPRINTK(" func: %d\n",
request.function);
result = _sendto(sock, (void *) start, size, 0, 0,
&(server->m.serv_addr),
sizeof(server->m.serv_addr));
if (result < 0) {
result = sock->ops->sendto(sock, (void *) start, size, 0, 0,
(struct sockaddr *)
&(server->m.serv_addr),
sizeof(server->m.serv_addr));
if (result < 0)
{
printk("ncp_rpc_call: send error = %d\n", result);
break;
}
@@ -315,39 +292,42 @@ do_ncp_rpc_call(struct ncp_server *server, int size)
wait_table.entry = &entry;
current->state = TASK_INTERRUPTIBLE;
if ( !select(inode, file, SEL_IN, &wait_table)
&& !select(inode, file, SEL_IN, NULL)) {
if (timeout > max_timeout) {
&& !select(inode, file, SEL_IN, NULL))
{
if (timeout > max_timeout)
{
/* JEJB/JSP 2/7/94
* This is useful to see if the system is
* hanging */
printk("NCP max timeout reached on %s\n",
server_name);
printk("NCP max timeout reached\n");
timeout = max_timeout;
}
current->timeout = jiffies + timeout;
schedule();
remove_wait_queue(entry.wait_address, &entry.wait);
current->state = TASK_RUNNING;
if (current->signal & ~current->blocked) {
if (current->signal & ~current->blocked)
{
current->timeout = 0;
result = -ERESTARTSYS;
break;
}
if (!current->timeout) {
if (!current->timeout)
{
if (n < retrans)
continue;
if (server->m.flags & NCP_MOUNT_SOFT) {
printk("NCP server %s not responding, "
"timed out\n", server_name);
if (server->m.flags & NCP_MOUNT_SOFT)
{
printk("NCP server not responding\n");
result = -EIO;
break;
}
n = 0;
timeout = init_timeout;
init_timeout <<= 1;
if (!major_timeout_seen) {
printk("NCP server %s not responding, "
"still trying\n", server_name);
if (!major_timeout_seen)
{
printk("NCP server not responding\n");
}
major_timeout_seen = 1;
continue;
@@ -363,30 +343,36 @@ do_ncp_rpc_call(struct ncp_server *server, int size)
/* Get the header from the next packet using a peek, so keep it
* on the recv queue. If it is wrong, it will be some reply
* we don't now need, so discard it */
result = _recvfrom(sock, (void *)&reply,
sizeof(reply), 1, MSG_PEEK,
NULL, &addrlen);
if (result < 0) {
if (result == -EAGAIN) {
result = sock->ops->recvfrom(sock, (void *)&reply,
sizeof(reply), 1, MSG_PEEK,
NULL, &addrlen);
if (result < 0)
{
if (result == -EAGAIN)
{
DPRINTK("ncp_rpc_call: bad select ready\n");
goto re_select;
}
if (result == -ECONNREFUSED) {
if (result == -ECONNREFUSED)
{
DPRINTK("ncp_rpc_call: server playing coy\n");
goto re_select;
}
if (result != -ERESTARTSYS) {
if (result != -ERESTARTSYS)
{
printk("ncp_rpc_call: recv error = %d\n",
-result);
}
break;
}
if ( (result == sizeof(reply))
&& (reply.type == NCP_POSITIVE_ACK)) {
&& (reply.type == NCP_POSITIVE_ACK))
{
/* Throw away the packet */
DPRINTK("ncp_rpc_call: got positive acknowledge\n");
_recvfrom(sock, (void *)&reply, sizeof(reply), 1, 0,
NULL, &addrlen);
sock->ops->recvfrom(sock, (void *)&reply,
sizeof(reply), 1, 0,
NULL, &addrlen);
goto re_select;
}
@@ -403,17 +389,18 @@ do_ncp_rpc_call(struct ncp_server *server, int size)
|| ( (reply.sequence == request.sequence)
&& (reply.conn_low == request.conn_low)
/* seem to get wrong task from NW311 && (reply.task == request.task)*/
&& (reply.conn_high == request.conn_high)))) {
&& (reply.conn_high == request.conn_high))))
{
if (major_timeout_seen)
printk("NCP server %s OK\n", server_name);
printk("NCP server OK\n");
break;
}
/* JEJB/JSP 2/7/94
* we have xid mismatch, so discard the packet and start
* again. What a hack! but I can't call recvfrom with
* a null buffer yet. */
_recvfrom(sock, (void *)&reply, sizeof(reply), 1, 0, NULL,
&addrlen);
sock->ops->recvfrom(sock, (void *)&reply, sizeof(reply), 1, 0,
NULL, &addrlen);
#if 1
printk("ncp_rpc_call: reply mismatch\n");
#endif
@@ -423,11 +410,14 @@ do_ncp_rpc_call(struct ncp_server *server, int size)
* we have the correct reply, so read into the correct place and
* return it
*/
result = _recvfrom(sock, (void *)start, server->packet_size, 1, 0,
NULL, &addrlen);
if (result < 0) {
result = sock->ops->recvfrom(sock, (void *)start, server->packet_size,
1, 0, NULL, &addrlen);
if (result < 0)
{
printk("NCP: notice message: result=%d\n", result);
} else if (result < sizeof(struct ncp_reply_header)) {
}
else if (result < sizeof(struct ncp_reply_header))
{
printk("NCP: just caught a too small read memory size..., "
"email to NET channel\n");
printk("NCP: result=%d,addrlen=%d\n", result, addrlen);
@@ -447,7 +437,8 @@ do_ncp_rpc_call(struct ncp_server *server, int size)
static int
ncp_do_request(struct ncp_server *server, int size)
{
if (server->lock == 0) {
if (server->lock == 0)
{
printk("ncpfs: Server not locked!\n");
return -EIO;
}
@@ -471,7 +462,8 @@ ncp_request(struct ncp_server *server, int function)
int result;
if (server->has_subfunction != 0) {
if (server->has_subfunction != 0)
{
*(__u16 *)&(h->data[0]) = request_size - 2;
}
@@ -484,7 +476,8 @@ ncp_request(struct ncp_server *server, int function)
h->task = (current->pid) & 0xff;
h->function = function;
if ((result = ncp_do_request(server, request_size + sizeof(*h))) < 0) {
if ((result = ncp_do_request(server, request_size + sizeof(*h))) < 0)
{
DPRINTK("ncp_request_error: %d\n", result);
return result;
}
@@ -496,7 +489,8 @@ ncp_request(struct ncp_server *server, int function)
result = reply->completion_code;
if (result != 0) {
if (result != 0)
{
DPRINTK("ncp_completion_code: %d\n", result);
}
return result;
@@ -518,7 +512,8 @@ ncp_connect(struct ncp_server *server)
h->task = (current->pid) & 0xff;
h->function = 0;
if ((result = ncp_do_request(server, sizeof(*h))) < 0) {
if ((result = ncp_do_request(server, sizeof(*h))) < 0)
{
return result;
}
@@ -548,9 +543,10 @@ ncp_disconnect(struct ncp_server *server)
void
ncp_lock_server(struct ncp_server *server)
{
#if 1
#if 0
/* For testing, only 1 process */
if (server->lock != 0) {
if (server->lock != 0)
{
DPRINTK("ncpfs: server locked!!!\n");
}
#endif
@@ -562,7 +558,8 @@ ncp_lock_server(struct ncp_server *server)
void
ncp_unlock_server(struct ncp_server *server)
{
if (server->lock != 1) {
if (server->lock != 1)
{
printk("ncp_unlock_server: was not locked!\n");
}

1
linux
View File

@@ -1 +0,0 @@
.

16
man/Makefile Normal file
View File

@@ -0,0 +1,16 @@
MAN1= slist nprint pqlist
MAN5= nwclient
MAN8= ncpmount ncpumount ipx_configure ipx_interface ipx_internal_net ipx_route
all:
dep:
install:
for i in $(MAN1); do install $$i.1 -m 755 /usr/local/man/man1; done
for i in $(MAN5); do install $$i.5 -m 755 /usr/local/man/man5; done
for i in $(MAN8); do install $$i.8 -m 755 /usr/local/man/man8; done
clean:

47
man/ipx_configure.8 Normal file
View File

@@ -0,0 +1,47 @@
.TH IPX_CONFIGURE 8 "IPX Utilities" "Caldera, Inc."
.SH NAME
ipx_configure \- display/configure IPX behavior
.SH SYNOPSIS
.B ipx_configure
[\-\-help]
[\-\-auto_interface=[on|off]]
[\-\-auto_primary=[on|off]]
.SH DESCRIPTION
.B ipx_configure
displays or configures IPX behavior with respect to automatic IPX
interface detection. IPX can be configured to automatically create
interfaces as they are detected. It can also be configured to
automatically select a primary interface when none is explicitly
selected. By default, it is configured to
.B NOT
have this behavior.
Without arguments,
.B ipx_configure
returns the current configuration state. The behavior with
arguments is described in the section
.B OPTIONS.
.SS OPTIONS
.TP
.I "\-\-auto_interface=[on|off]"
This argument enables or disables the feature that will automatically detect
whether IPX is use on a network interface. If
.B on
and IPX packets are seen on an interface that interface will be automatically
flagged as an IPX interface. The default setting is
.B off.
.TP
.I "\-\-auto_primary=[on|off]"
This argument enables or disables the feature that will automatically select
which IPX interface will be the primary IPX interface. The default setting is
.B off.
.TP
.I "\-\-help"
Displays summarised usage instructions.
.SH FILES
.I /proc/net/ipx_interface
.SH BUGS
This functionality really belongs in
.B
ifconfig(8).
.SH AUTHOR
Greg Page <greg.page@caldera.com>

60
man/ipx_interface.8 Normal file
View File

@@ -0,0 +1,60 @@
.TH IPX_INTERFACE 8 "IPX Utilities" "Caldera, Inc."
.SH NAME
ipx_interface \- add, delete, or display IPX interface configuration.
.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 the configuration of the specified IPX interface.
.P
An IPX interface is the item to which IPX sockets are bound.
An IPX interface has an associated IPX Network Number, a physical device
and frame type. A sample IPX Interface might look like:
.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 flagged as the
.B PRIMARY
interface. The IPX network number may optionally be specified. If it is not
specified it is set to 0 which indicates it should be automatically detected
by analysis of the existing IPX 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 network number associated with a specified
device and frame type combination.
.TP
.I help
This option displays summarised usage instructions.
.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 <greg.page@caldera.com>

32
man/ipx_internal_net.8 Normal file
View File

@@ -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 <greg.page@caldera.com>

24
man/ipx_route.8 Normal file
View File

@@ -0,0 +1,24 @@
.TH IPX_ROUTE 8 "IPX Utilities" "Caldera, Inc."
.SH NAME
ipx_route \- add or delete an 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 software stores only one route to any target network.
.SS OPTIONS
.TP
.I add
This option is used to configure a 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 <greg.page@caldera.com>

219
man/ncpmount.8 Normal file
View File

@@ -0,0 +1,219 @@
.TH NCPMOUNT 8 12/27/1995 ncpmount ncpmount
.SH NAME
ncpmount \- mount all volumes of a specified Novell fileserver.
.SH SYNOPSIS
.B ncpmount
[
.B -h
] [
.B -S
.I server
] [
.B -U
.I user name
] [
.B -P
.I password
|
.B -n
] [
.B -C
] [
.B -c
.I client name
] [
.B -u
.I uid
] [
.B -g
.I gid
] [
.B -f
.I file mode
] [
.B -d
.I dir mode
]
mount-point
.SH DESCRIPTION
This program is used to mount all volumes of the specified NetWare Fileserver
under the specified mount point.
.B ncpfs
is a linux filesystem which understands the NCP protocol. This is the
protocol Novell NetWare clients use to talk to NetWare servers. ncpfs
was inspired by
.B lwared,
a free NetWare emulator for Linux written by Ales Dryak. See
ftp://klokan.sh.cvut.cz/pub/linux for this very intersting program.
.B ncpmount
when invoked with all appropriate arguments attaches, logs in and
mounts all of the volumes associated with the specified fileserver that are
readable by the user id under the specified mount point.
.B ncpmount
when invoked without any arguments specifying the fileserver, user id and
password checks the file
.I $HOME/.nwclient
to find a file server, a user name and possibly a password to use for the
specified mount point. See nwclient(5) for more information. Please note
that the access permissions of .nwclient MUST be 600, for security reasons.
.SH OPTIONS
.B mount-point
.RS 3
.B mount-point
is the directory you want to mount the filesystem over. Its function is the
the same as for a normal mount command.
If the real uid of the caller is not root,
.B ncpmount
checks whether the user is allowed to mount a filesystem on the
mount-point. So it should be safe to make
.B ncpmount
setuid root. The filesystem stores the uid of the user who called
ncpmount. So
.B ncpumount
can check whether the caller is allowed to unmount the filesystem.
.RE
.B -S
.I server
.RS 3
.B server
is the name of the server you want to use.
.RE
.B -h
.RS 3
.B -h
is used to print out a short help text.
.RE
.B -C
.RS 3
By default passwords are converted to uppercase before they are sent
to the server because most servers require this. This option disables this
feature ensuring that passwords are sent without any case conversion.
.RE
.B -n
.RS 3
.B -n
must be specified for logins that do not have a password configured.
.RE
.B -P
.I password
.RS 3
specifies the password to use for the Netware user id.
If neither
.B -n
nor the
.B -P
arguments are specified ncpmount will prompt for a password. This
makes it difficult to use in scripts such as /etc/rc. If you want to
have ncpmount work automatically from a script you must include the
appropriate option and be very careful to ensure that appopriate file
permissions are set for the script that includes your password to
ensure that others can not read it.
.RE
.B -U
.I user name
.RS 3
Specifies the Netware user id to use when logging in to the fileserver. If
this option is not specified then ncpmount will attempt to login to the
fileserver using the Linux login id of the user invoking ncpmount.
.RE
.B -u
.I uid,
.B -g
.I gid
.RS 3
ncpmount does not yet implement a scheme for mapping NetWare users/groups
to Linux users/groups. Linux requires that each file has an owner and group id.
With
.B -u
and
.B -g
you can tell ncpmount which id's it should assign to the files in the
mounted directory.
The defaults for these values are the current uid and gid.
.RE
.B -c
.I user name
.RS 3
.B -c
names the user who is the
.I owner
of the connection, where owner does not refer to file ownership (that
"owner" is set by the -u argument), but the owner of the mount, ie: who
is allowed to call ncpumount on this mount. The default owner of the
connection and the mount is the user who called ncpmount. This option
allows you to specify that some other user should be set as the owner.
In this this way it is possible to mount a public read-only directory,
but to allow the lp daemon to print on NetWare queues. This is
possible because only users who have write permissions on a directory
may issue ncp requests over a connection. The exception to this rule
is the 'mount owner', who is also granted 'request permission'.
.RE
.B -f
.I file mode,
.B -d
.I dir mode
.RS 3
Like
.B -u
and
.B -g,
these options are used to determine what permissions should be assigned
files and directories of the mounted volumes. The values must be specified
as octal numbers. The default values are taken from the current umask, where
the file mode is the current umask, and the dir mode adds execute permissions
where the file mode gives read permissions.
Note that these permissions can differ from the rights the server
gives to us. If you do not have write permissions on the server, you
can very well choose a file mode that tells that you have. This
certainly cannot override the restrictions imposed by the server.
.RE
.SH NOTES
You must configure the IPX subsystem before ncpmount will work.
It is especially important that there is a route to the internal network
of your server.
.SH ENVIRONMENT VARIABLES
.B USER / LOGNAME
.RS 3
The variables USER or LOGNAME may contain the username of the person
using the client. USER is tried first. If it's emtpy, LOGNAME is
tried.
.RE
.SH DIAGNOSTICS
Most diagnostics issued by ncpfs are logged by syslogd. Normally
nothing is printed, only error situations are logged there.
.SH SEE ALSO
.B syslogd(8), ncpumount(8)
.SH CREDITS
ncpfs would not have been possible without lwared, written by Ales
Dryak (A.Dryak@sh.cvut.cz).
The encryption code was taken from Dr. Dobbs's Journal 11/93. There
Pawel Szczerbina described it in an article on NCP.
The ncpfs code was initially hacked from smbfs by Volker Lendecke
(lendecke@namu01.gwdg.de). smbfs was put together by Paal-Kr. Engstad
(pke@engstad.ingok.hitos.no) and later polished by Volker.

29
man/ncpumount.8 Normal file
View File

@@ -0,0 +1,29 @@
.TH NCPUMOUNT 8 12/27/1995 ncpumount ncpumount
.SH NAME
ncpumount \- unmount a NetWare filesystem mounted with ncpmount.
.SH SYNOPSIS
.B ncpumount
.B mount-point
.SH DESCRIPTION
This utility unmounts a NetWare filesystem that was previously mounted
with the ncpmount utility. If the this utility is made suid root then
non-root users will also be able to make use of it.
.B ncpumount
has been written to give normal linux-users more control over their
resources. It is safe to install this program suid root, because only
the user who has mounted a filesystem is allowed to unmount it again.
For root it is not necessary to use ncpumount. The normal umount
program works perfectly well, but it would certainly be problematic to
make umount setuid root.
.SH OPTIONS
.B mount-point
.RS 3
.B mount-point
is the directory you want to unmount.
.SH SEE ALSO
.B ncpmount(8)

222
man/nprint.1 Normal file
View File

@@ -0,0 +1,222 @@
.TH NPRINT 1 12/27/1995 nprint nprint
.SH NAME
nprint \- NetWare print client
.SH SYNOPSIS
.B nprint
[
.B -S
.I server
] [
.B -h
] [
.B -U
.I user name
] [
.B -P
.I password
|
.B -n
] [
.B -C
] [
.B -q
.I queue name
] [
.B -d
.I job description
] [
.B -p
.I path name
] [
.B -b
.I banner name
] [
.B -f
.I file name in banner
] [
.B -l
.I lines
] [
.B -r
.I rows
] [
.B -c
.I copies
] [
.B -t
.I tab size
] [
.B -T
] [
.B -N
] [
.B -F
.I form number
]
.B file
.SH DESCRIPTION
With
.B nprint,
you can print files on print queues of a NetWare file server.
There are a lot of options, so you should probably wrap some default
configurations into some shell scripts.
.B nprint
looks up the file
.I $HOME/.nwclient
to find a file server, a user name and possibly a password. See
nwclient(5) for more information. Please note that the access
permissions of .nwclient MUST be 600, for security reasons.
.SH OPTIONS
.B file
.RS 3
.B file
is the name of the file you want to print. If file is '-', or no
filename is given, standard input is used.
.RE
.B -h
.RS 3
.B -h
is used to print out a short help text.
.RE
.B -S
.I server
.RS 3
.B server
is the name of the server you want to use.
.RE
.B -U
.I user
.RS 3
.B user
is the user name to use for the print request at the server.
.RE
.B -P
.I password
.RS 3
.B password
is the password to use for the print request at the server. If neither
.B -n
nor
.B -P
are given, and the user has no open connection to the server, nprint
prompts for a password.
.RE
.B -n
.RS 3
.B -n
should be given if no password is required for the print request.
.RE
.B -C
.RS 3
By default, passwords are converted to uppercase before they are sent
to the server, because most servers require this. You can turn off
this conversion by
.B -C.
.RE
.B -q
.I queue name
.RS 3
.B queue name
is the name of the print queue to use at the print server. At
present, you must specify it in upper case characters.
.RE
.B -d
.I job description
.RS 3
.B job description
is the string that appears in pconsole when you list the jobs for the
print queue. It is also printed somewhere on the top of the banner
page.
.RE
.B -p
.I pathname
.RS 3
.B pathname
is the string you want to be printed on the banner page in the field
'path'.
.RE
.B -b
.I bannername
.RS 3
.B bannername
is the string (up to 12 characters) you want to appear on the lower
part of the banner page.
.RE
.B -f
.I filename
.RS 3
.B filename
is the string (up to 12 characters) you want to appear on the upper
part of the banner page. Default: the name of the file that is
printed, or 'stdin'.
.RE
.B -l
.I lines
.RS 3
.B lines
is the number of lines to put on one page. Default: 66
.RE
.B -r
.I rows
.RS 3
.B rows
is the number of rows to put on one page. Default: 80
.RE
.B -c
.I copies
.RS 3
.B copies
tells the print server to the specified number of copies. Default: 1
.RE
.B -t
.I tabs
.RS 3
.B tabs
is the number of spaces to print for a Tab-Character. Default: 8
.RE
.B -T
.RS 3
tells the print server to expand Tab-Character and use 8 spaces
.RE
.B -N
.RS 3
tells the print server
.B not
to use Form Feeds
.RE
.B -F
.I form number
.RS 3
.B form number
is the the number of the form to be put into the printer. If it's
different from the one currently in the printer, your job is only
printed if a printer operator has put in the correct form.
.RE
.SH SEE ALSO
.B nwclient(5), slist(1), pqlist(1), ncpmount(8), ncpumount(8)
.SH CREDITS
nprint was written by Volker Lendecke (lendecke@namu01.gwdg.de)

55
man/nwclient.5 Normal file
View File

@@ -0,0 +1,55 @@
.TH NWCLIENT 5 12/27/1995 nwmount nwmount
.SH NAME
nwclient \- configuration file for NWClient program suite
.SH DESCRIPTION
This manual page describes the rather simple format of the file
.B $HOME/.nwclient,
the configuration file for the NWClient program suite.
.SH FILE FORMAT
The file
.B $HOME/.nwclient
consists of several lines, each describing a NWClient
connection. Lines beginning with # and empty lines are ignored as
comments.
Because you can store passwords in .nwclient, the user programs will
only scan .nwclient when only the file owner has access rights to
the file. The file must be have permissions 0600.
To specify a NWClient connection, the name of the file server, the
user name to be used and a password is necessary. The server name and
the user name are specified as SERVER/USER, and the password is
separated by a blank. The password field can be omitted. In this case
the user programs will ask you for a password. If you specify the
password to be just a dash, then no password is used.
The first valid specification has a special meaning: If the user does
not name a server on the command line, the first specification is used
as a 'preferred connection'.
An example might be the following:
# The preferred connection, the user is asked
# for a password
FS311/ME
# And a passwordless account on another server
CD-SERV/GUEST -
With these lines in $HOME/.nwclient, calling 'nwmount /mnt' will mount
the the file server FS311 with user name ME on /mnt after asking the
user for a password.
\'nwmount -S cd-serv /cd' will silently mount the server cd-serv on /cd.
.B nprint
,
.B pqlist
and other user programs that require a valid login also look up
.I $HOME/.nwclient
to find a file server, a user name and possibly a password.
Please note that the access permissions of .nwclient MUST be 600, for
security reasons.
.SH SEE ALSO
.B ncpmount(8), ncpumount(8), slist(1), pqlist(1), nprint(1)

105
man/pqlist.1 Normal file
View File

@@ -0,0 +1,105 @@
.TH PQLIST 1 01/10/1996 pqlist pqlist
.SH NAME
pqlist \- List available NetWare print queues
.SH SYNOPSIS
.B pqlist
[
.B -h
] [
.B -S
.I server
] [
.B -U
.I user name
] [
.B -P
.I password
|
.B -n
] [
.B -C
] [
.I pattern
]
.SH DESCRIPTION
.B pqlist
lists all the NetWare print queues available to you on some server.
If you are already connected to some server, this one is used.
If pqlist does not print to a tty, the decorative header line is
not printed, so that you can count the printing queue available
on your server by doing
pqlist -S server | wc -l
.B pqlist
looks up the file
.I $HOME/.nwclient
to find a file server, a user name and possibly a password. See
nwclient(5) for more information. Please note that the access
permissions of .nwclient MUST be 600, for security reasons.
.SH OPTIONS
.B pattern
.RS 3
.B pattern
is used to list only selected queues. You can use wildcards in the
pattern, but you have to be careful to prevent shell interpretation of
wildcards like '*'.
.RE
.B -h
.RS 3
.B -h
is used to print out a short help text.
.RE
.B -S
.I server
.RS 3
.B server
is the name of the server you want to use.
.RE
.B -U
.I user name
.RS 3
If the user name your NetWare administrator gave to you differs
from your unix user-id, you should use
.B -U
to tell the server about you NetWare user name.
.RE
.B -P
.I password
.RS 3
You may want to give the password required by the server on the
command line. You should be careful to use passwords in scripts.
.RE
.B -n
.RS 3
.B -n
should be given to mount shares which do not require a password to log in.
If neither
.B -n
nor
.B -P
are given, pqlist prompts for a password.
.RE
.B -C
.RS 3
By default, passwords are converted to uppercase before they are sent
to the server, because most servers require this. You can turn off
this conversion by
.B -C.
.RE
.SH SEE ALSO
.B nwclient(5), nprint(1), slist(1), ncpmount(8), ncpumount(8)
.SH CREDITS
pqlist was written by Volker Lendecke (lendecke@namu01.gwdg.de)

142
man/pserver.1 Normal file
View File

@@ -0,0 +1,142 @@
.TH PSERVER 1 02/10/1996 pserver pserver
.SH NAME
pserver \- NetWare print server
.SH SYNOPSIS
.B pserver
[
.B -S
.I server
] [
.B -h
] [
.B -U
.I user name
] [
.B -P
.I password
|
.B -n
] [
.B -C
] [
.B -q
.I queue name
] [
.B -c
.I command
] [
.B -j
.I job type
] [
.B -t
.I timeout
] [
.B -d
]
.SH DESCRIPTION
.B pserver
is a program that connects to print queues on NetWare servers and
feeds incoming print jobs to the Linux printing system.
.SH OPTIONS
.B -h
.RS 3
.B -h
is used to print out a short help text.
.RE
.B -S
.I server
.RS 3
.B server
is the name of the server you want to use.
.RE
.B -U
.I user
.RS 3
.B user
is the print server name at the server.
.RE
.B -P
.I password
.RS 3
.B password
is the password to use for the print server at the server. If neither
.B -n
nor
.B -P
are given, and the user has no open connection to the server, pserver
prompts for a password.
.RE
.B -n
.RS 3
.B -n
should be given if the print server does not require a password.
.RE
.B -C
.RS 3
By default, passwords are converted to uppercase before they are sent
to the server, because most servers require this. You can turn off
this conversion by
.B -C.
.RE
.B -q
.I queue name
.RS 3
.B queue name
is the name of the print queue you want to service.
.RE
.B -c
.I command
.RS 3
When a job is received from the print queue, pserver forks off a new
process, and feeds the job file to stdin.
.I command
is the printing command that is executed for each job. The default
command is 'lpr'.
.RE
.B -j
.I job type
.RS 3
Each job in a NetWare print queue has a job type. For print jobs, this
corresponds to the number of the form the job should be printed
on. You can tell pserver that it should only receive jobs for one
specific form from the queue. The default is -1, which means that
everything is received.
.RE
.B -t
.I timeout
.RS 3
Pserver is not informed by NetWare servers when new jobs arrive. So a
polling scheme has to be used. When there are no jobs to service,
.I timeout
tells pserver how long to wait between two requests. The default is 30
seconds. When a job is finished, pserver asks the NetWare server
immediately for a new job, and does not wait
.I timeout
seconds.
.RE
.B -d
.RS 3
Normally, pserver daemonizes itself.
.B -d
tells it not to do so. This is useful if you want to see the
diagnostic messages that are printed when a error occurs.
.RE
.SH SEE ALSO
.B nwclient(5), slist(1), pqlist(1), ncpmount(8), ncpumount(8)
.SH CREDITS
pserver was written by Volker Lendecke (lendecke@namu01.gwdg.de)

43
man/slist.1 Normal file
View File

@@ -0,0 +1,43 @@
.TH SLIST 1 01/07/1996 slist slist
.SH NAME
slist \- Lists available NetWare Servers
.SH SYNOPSIS
.B slist
[
.I pattern
]
.SH DESCRIPTION
.B slist
lists all NetWare Servers available in your network.
If slist does not print to a tty, the decorative header line is not
printed, so that you can count the servers on your network by doing
slist | wc -l
.SH OPTIONS
.B pattern
.RS 3
.B pattern
is used to list only servers whose names match the specified pattern. For a
server to be listed, the pattern must match the full server name. You can use
wildcards for the pattern, but you must protect these wildcards from any
command line expansion by quoting. Case doesn't matter.
.RE
.SH EXAMPLE
.TP
slist "I*"
.TP
or
.TP
slist "i*"
List all available Netware servers on your Network, that begin with an "I".
.SH SEE ALSO
.B ncpmount(8), ncpumount(8), pqlist(1), nprint(1)
.SH CREDITS
slist was written by Volker Lendecke (lendecke@namu01.gwdg.de)

View File

@@ -1,14 +1,17 @@
Begin3
Title: ncpfs
Version: 0.5
Entered-date: 17. November 1995
Version: 0.15
Entered-date: 10. February 1996
Description: With ncpfs you can mount volumes of your novell
server under Linux.
server under Linux. You need kernel 1.2.x or
1.3.54 and above. ncpfs does NOT work with any 1.3.x
kernel below 1.3.54.
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
~50k ncpfs-0.5.tgz
~ 1k ncpfs-0.5.lsm
Alternate-site: sunsite.unc.edu:/pub/system/Filesystems/
~70k ncpfs-0.15.tgz
~ 1k ncpfs-0.15.lsm
Copying-policy: GPL
End

File diff suppressed because it is too large Load Diff

View File

@@ -1,168 +0,0 @@
#ifndef _NCPLIB_H
#define _NCPLIB_H
#include <linux/types.h>
#include <linux/ncp.h>
#include <linux/ncp_fs.h>
struct ncp_server {
int current_size;
int has_subfunction;
int mount_fid;
int silent;
int ncp_reply_size;
char *packet;
int lock;
char ncp_data[NCP_PACKET_SIZE];
};
#include <linux/ncp.h>
int
ncp_negotiate_buffersize(struct ncp_server *server, int size,
int *target);
int
ncp_get_encryption_key(struct ncp_server *server,
char *target);
int
ncp_get_bindery_object_id(struct ncp_server *server,
int object_type, char *object_name,
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,
struct nw_property *target);
int
ncp_login_encrypted(struct ncp_server *server,
struct ncp_bindery_object *object,
unsigned char *key,
unsigned char *passwd);
int
ncp_login_user(struct ncp_server *server,
unsigned char *username,
unsigned char *password);
int
ncp_get_volume_info_with_number(struct ncp_server *server, int n,
struct ncp_volume_info *target);
int
ncp_get_volume_number(struct ncp_server *server, const char *name,
int *target);
int
ncp_file_search_init(struct ncp_server *server,
int dir_handle, const char *path,
struct ncp_filesearch_info *target);
int
ncp_file_search_continue(struct ncp_server *server,
struct ncp_filesearch_info *fsinfo,
int attributes, const char *path,
struct ncp_file_info *target);
int
ncp_get_finfo(struct ncp_server *server,
int dir_handle, const char *path, const char *name,
struct ncp_file_info *target);
int
ncp_open_file(struct ncp_server *server,
int dir_handle, const char *path,
int attr, int access,
struct ncp_file_info *target);
int
ncp_close_file(struct ncp_server *server, const char *file_id);
int
ncp_create_newfile(struct ncp_server *server,
int dir_handle, const char *path,
int attr,
struct ncp_file_info *target);
int
ncp_create_file(struct ncp_server *server,
int dir_handle, const char *path,
int attr,
struct ncp_file_info *target);
int
ncp_erase_file(struct ncp_server *server,
int dir_handle, const char *path,
int attr);
int
ncp_rename_file(struct ncp_server *server,
int old_handle, const char *old_path,
int attr,
int new_handle, const char *new_path);
int
ncp_create_directory(struct ncp_server *server,
int dir_handle, const char *path,
int inherit_mask);
int
ncp_delete_directory(struct ncp_server *server,
int dir_handle, const char *path);
int
ncp_rename_directory(struct ncp_server *server,
int dir_handle,
const char *old_path, const char *new_path);
int
ncp_read(struct ncp_server *server, const char *file_id,
__u32 offset, __u16 to_read,
char *target, int *bytes_read);
int
ncp_write(struct ncp_server *server, const char *file_id,
__u32 offset, __u16 to_write,
const char *source, int *bytes_written);
int
ncp_do_lookup(struct ncp_server *server,
struct nw_info_struct *dir,
char *path, /* may only be one component */
struct nw_info_struct *target);
int
ncp_del_file_or_subdir(struct ncp_server *server,
struct nw_info_struct *dir, char *name);
int
ncp_open_create_file_or_subdir(struct ncp_server *server,
struct nw_info_struct *dir, char *name,
int open_create_mode,
__u32 create_attributes,
int desired_acc_rights,
struct nw_file_info *target);
int
ncp_initialize_search(struct ncp_server *server,
struct nw_info_struct *dir,
struct nw_search_sequence *target);
int
ncp_search_for_file_or_subdir(struct ncp_server *server,
struct nw_search_sequence *seq,
struct nw_info_struct *target);
int
ncp_ren_or_mov_file_or_subdir(struct ncp_server *server,
struct nw_info_struct *old_dir, char *old_name,
struct nw_info_struct *new_dir, char *new_name);
int
ncp_create_queue_job_and_file(struct ncp_server *server,
__u32 queue_id,
struct queue_job *job);
int
ncp_close_file_and_start_job(struct ncp_server *server,
__u32 queue_id,
struct queue_job *job);
#endif /* _NCPLIB_H */

View File

@@ -1,696 +0,0 @@
/*
* ncpmount.c
*
* Copyright (C) 1995 by Volker Lendecke
*
*/
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <pwd.h>
#include <grp.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/stat.h>
#include <sys/types.h>
/* #include <sys/wait.h> */ /* generates a warning here */
extern pid_t waitpid(pid_t, int *, int);
#include <sys/errno.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <stdlib.h>
#include <sys/mount.h>
#include <mntent.h>
#include <linux/ipx.h>
#include <linux/fs.h>
#include <linux/ncp.h>
#include <linux/ncp_fs.h>
#include <linux/ncp_mount.h>
#include "ipxutil.h"
#include "ncplib_user.h"
static char *progname;
static void
str_upper(char *name)
{
while (*name) {
*name = toupper(*name);
name = name + 1;
}
}
static void
usage(void)
{
printf("usage: %s server mount-point [options]\n", progname);
printf("Try `%s -h' for more information\n", progname);
}
static void
help(void)
{
printf("\n");
printf("usage: %s server mount-point [options]\n", progname);
printf("\n"
"-U username Username sent to server\n"
"-u uid uid the mounted files get\n"
"-g gid gid the mounted files get\n"
"-f mode permission the files get (octal notation)\n"
"-d mode permission the dirs get (octal notation)\n"
"-C Don't convert password to uppercase\n"
"-P password Use this password\n"
"-n Do not use any password\n"
" If neither -P nor -n are given, you are\n"
" asked for a password.\n"
"-h print this help text\n"
"\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)
{
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)
{
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;
int packets;
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(0x0001);
*(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;
if (sendto(sock, data, 4, 0,
(struct sockaddr *)&ipxs, sizeof(ipxs)) < 0) {
perror("sendto");
goto finished;
}
packets = 10;
while (packets > 0) {
packets -= 1;
FD_ZERO(&rd); FD_ZERO(&wr); FD_ZERO(&ex);
FD_SET(sock, &rd);
tv.tv_sec = timeout;
tv.tv_usec = 0;
if (select(sock+1, &rd, &wr, &ex, &tv) == -1) {
perror("select");
goto finished;
}
if (FD_ISSET(sock, &rd)) {
int len = recv(sock, data, 1024, 0);
int i;
struct sap_server_ident *ident;
for (i = 2; i < len; i += 64) {
ident = (struct sap_server_ident *)(data+i);
if ( (strncmp(name,ident->server_name,
name_len)==0)
&& (name_len < 48)
&& (ident->server_name[name_len] == '\0'))
{
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;
goto finished;
}
}
}
else
{
printf("nobody answered, server %s not found\n",
name);
exit(1);
}
}
finished:
close(sock);
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)
{
int opt;
struct passwd *pwd;
struct group *grp;
*got_password = 0;
*upcase_password = 1;
while ((opt = getopt (argc, argv, "Cp:s:c:U:u:g:f:d:m:P:n")) != EOF) {
switch (opt) {
case 'C':
*upcase_password = 0;
break;
case 'U':
if (strlen(optarg) > 63) {
fprintf(stderr, "Username too long: %s\n",
optarg);
return 1;
}
strcpy(data->username, optarg);
break;
case 'u':
if (isdigit(optarg[0])) {
data->uid = atoi(optarg);
} else {
pwd = getpwnam(optarg);
if (pwd == NULL) {
fprintf(stderr, "Unknown user: %s\n",
optarg);
return 1;
}
data->uid = pwd->pw_uid;
}
break;
case 'g':
if (isdigit(optarg[0])) {
data->gid = atoi(optarg);
} else {
grp = getgrnam(optarg);
if (grp == NULL) {
fprintf(stderr, "Unknown group: %s\n",
optarg);
return 1;
}
data->gid = grp->gr_gid;
}
break;
case 'f':
data->file_mode = strtol(optarg, NULL, 8);
break;
case 'd':
data->dir_mode = strtol(optarg, NULL, 8);
break;
case 'P':
strcpy(data->password, optarg);
*got_password = 1;
break;
case 'n':
data->password[0] = '\0';
*got_password = 1;
break;
default:
return -1;
}
}
return 0;
}
/* Returns 0 if the filesystem is in the kernel after this routine
completes */
static int
load_ncpfs()
{
FILE *fver, *ffs;
char s[1024];
char modname[1024];
char *p, *p1;
pid_t pid;
int status;
/* Check if ncpfs is in the kernel */
ffs = fopen("/proc/filesystems", "r");
if (ffs == NULL) {
perror("Error: \"/proc/filesystems\" could not be read:");
return -1;
}
p = NULL;
while (! feof(ffs)) {
p1 = fgets(s, sizeof(s), ffs);
if (p1) {
p = strstr(s, "ncpfs");
if (p) {
break;
}
}
}
fclose(ffs);
if (p) {
return 0;
}
fver = fopen("/proc/version", "r");
if (fver == NULL) {
perror("Error: \"/proc/version\" could not be read:");
return -1;
}
fgets(s, 1024, fver);
fclose(fver);
p = strstr(s, "version ");
if (p == NULL) {
version_error:
fprintf(stderr, "Error: Unable to determine the Linux version"
"from \"/proc/version\n");
return -1;
}
p = strchr(p, ' ') + 1;
p1 = strchr(p, ' ');
if (p1 == NULL) {
goto version_error;
}
strcpy(modname, "/lib/modules/");
strncat(modname, p, p1 - p);
strcat(modname, "/ncpfs.o");
/* system() function without signal handling, from Stevens */
if ((pid = fork()) < 0) {
return 1;
} else if (pid == 0) {
/* child */
execl("/sbin/insmod", "insmod", modname, NULL);
_exit(127); /* execl error */
} else {
/* parent */
while (waitpid(pid, &status, 0) < 0) {
if (errno != EINTR) {
status = -1;
break;
}
}
}
return status;
}
/* Check whether user is allowed to mount on the specified mount point */
static int
mount_ok(struct stat *st)
{
if (!S_ISDIR(st->st_mode))
{
errno = ENOTDIR;
return -1;
}
if ( (getuid() != 0)
&& ( (getuid() != st->st_uid)
|| ((st->st_mode & S_IRWXU) != S_IRWXU)))
{
errno = EPERM;
return -1;
}
return 0;
}
int
main(int argc, char *argv[])
{
struct ncp_mount_data data;
struct sockaddr_ipx addr;
struct stat st;
struct ncp_server serv;
struct ncp_server *server = &serv;
int fd;
int Got_Password;
int Upcase_Password;
int um;
unsigned int flags;
char hostname[MAXHOSTNAMELEN + 1];
char *server_name;
char mount_point[MAXPATHLEN];
struct mntent ment;
FILE *mtab;
int ncp_sock, wdog_sock;
progname = argv[0];
if (geteuid() != 0) {
fprintf(stderr, "%s must be installed suid root\n", progname);
exit(1);
}
memset(&data, 0, sizeof(struct ncp_mount_data));
memset(hostname, '\0', MAXHOSTNAMELEN+1);
gethostname(hostname, MAXHOSTNAMELEN);
if (argc < 3) {
if ( (argc == 2)
&& (argv[1][0] == '-')
&& (argv[1][1] == 'h')
&& (argv[1][2] == '\0')) {
help();
return 0;
}
else
{
usage();
return -1;
}
}
server_name = argv[1];
str_upper(server_name);
realpath(argv[2], mount_point);
argv += 2;
argc -= 2;
if (stat(mount_point, &st) == -1) {
fprintf(stderr, "could not find mount point %s: %s\n",
mount_point, strerror(errno));
exit(1);
}
if (mount_ok(&st) != 0) {
fprintf(stderr, "cannot to mount on %s: %s\n",
mount_point, strerror(errno));
exit(1);
}
ncp_sock = socket(AF_IPX, SOCK_DGRAM, PF_IPX);
if (ncp_sock == -1) {
fprintf(stderr, "could not open ncp socket: %s\n",
strerror(errno));
exit(1);
}
wdog_sock = socket(AF_IPX, SOCK_DGRAM, PF_IPX);
if (wdog_sock == -1) {
fprintf(stderr, "could not open wdog socket: %s\n",
strerror(errno));
exit(1);
}
addr.sipx_type = NCP_PTYPE;
if (bind(ncp_sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
fprintf(stderr, "bind(ncp_sock, ): %s\n",
strerror(errno));
exit(1);
}
if (bind(wdog_sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
fprintf(stderr, "bind(wdog_sock, ): %s\n",
strerror(errno));
exit(1);
}
if (ipx_sap_find_server(server_name, IPX_SAP_FILE_SERVER,
3, &addr) != 0) {
fprintf(stderr, "could not find server %s\n", server_name);
exit(1);
}
/* Check if the ncpfs filesystem is in the kernel. If not, attempt
* to load the ncpfs module */
if (load_ncpfs() != 0) {
fprintf(stderr, "Error: Unable to start ncpfs, exiting...\n");
exit(1);
}
data.version = NCP_MOUNT_VERSION;
data.ncp_fd = ncp_sock;
data.wdog_fd = wdog_sock;
data.mounted_uid = getuid();
data.serv_addr = addr;
strcpy(data.server_name, server_name);
data.time_out = 20; /* 2 seconds */
data.retry_count = 2;
/* getuid() gives us the real uid, who may umount the fs */
data.mounted_uid = getuid();
if (getenv("USER")) {
strcpy(data.username, getenv("USER"));
str_upper(data.username);
}
if (data.username[0] == 0 && getenv("LOGNAME"))
{
strcpy(data.username,getenv("LOGNAME"));
str_upper(data.username);
}
data.uid = getuid();
data.gid = getgid();
um = umask(0);
umask(um);
data.file_mode = (S_IRWXU|S_IRWXG|S_IRWXO) & ~um;
data.dir_mode = 0;
if (parse_args(argc, argv, &data, &Got_Password,
&Upcase_Password) != 0) {
usage();
return -1;
}
if (data.dir_mode == 0) {
data.dir_mode = data.file_mode;
if ((data.dir_mode & S_IRUSR) != 0)
data.dir_mode |= S_IXUSR;
if ((data.dir_mode & S_IRGRP) != 0)
data.dir_mode |= S_IXGRP;
if ((data.dir_mode & S_IROTH) != 0)
data.dir_mode |= S_IXOTH;
}
if (Got_Password == 0) {
strcpy(data.password, getpass("Password: "));
}
if (Upcase_Password == 1) {
str_upper(data.password);
}
if (data.server_name[0] == '\0') {
strcpy(data.server_name, server_name);
str_upper(data.server_name);
}
flags = MS_MGC_VAL;
if (mount(NULL, mount_point, "ncpfs",
flags, (char *)&data) < 0) {
printf("mount failed\n");
close(wdog_sock);
close(ncp_sock);
printf("Maybe you have no route to the internal net "
"of your server.\n");
return -1;
}
close(ncp_sock);
close(wdog_sock);
server->mount_fid = open(mount_point, O_RDONLY, 0);
server->silent = 1;
if (server->mount_fid == -1) {
fprintf(stderr, "Could not open %s: %s\n",
mount_point, strerror(errno));
umount(mount_point);
return -1;
}
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;
}
ment.mnt_fsname = server_name;
ment.mnt_dir = mount_point;
ment.mnt_type = "ncpfs";
ment.mnt_opts = "rw";
ment.mnt_freq = 0;
ment.mnt_passno= 0;
if ((fd = open(MOUNTED"~", O_RDWR|O_CREAT|O_EXCL, 0600)) == -1)
{
fprintf(stderr, "Can't get "MOUNTED"~ lock file");
return 1;
}
close(fd);
if ((mtab = setmntent(MOUNTED, "a+")) == NULL)
{
fprintf(stderr, "Can't open " MOUNTED);
return 1;
}
if (addmntent(mtab, &ment) == 1)
{
fprintf(stderr, "Can't write mount entry");
return 1;
}
if (fchmod(fileno(mtab), 0644) == -1)
{
fprintf(stderr, "Can't set perms on "MOUNTED);
return 1;
}
endmntent(mtab);
if (unlink(MOUNTED"~") == -1)
{
fprintf(stderr, "Can't remove "MOUNTED"~");
return 1;
}
return 0;
}

407
ncptest.c
View File

@@ -1,407 +0,0 @@
/*
* ncptest.c
*
* Copyright (C) 1995 by Volker Lendecke
*
*/
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <pwd.h>
#include <grp.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ioctl.h>
/* #include <sys/wait.h> */ /* generates a warning here */
extern pid_t waitpid(pid_t, int *, int);
#include <sys/errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <stdlib.h>
#include <sys/mount.h>
#include <mntent.h>
#include <linux/ipx.h>
#include <linux/fs.h>
#include <linux/ncp.h>
#include <linux/ncp_fs.h>
#include <linux/ncp_mount.h>
#include "ncplib_user.h"
#include "ipxutil.h"
static char *progname;
static char *mount_point;
void
test_filesearch(struct ncp_server *server)
{
struct ncp_filesearch_info fsinfo;
struct ncp_file_info finfo;
if (ncp_file_search_init(server, 0, "sys:\\public", &fsinfo) != 0) {
printf("could not fs init\n");
return;
}
while (ncp_file_search_continue(server, &fsinfo,
0,
"*", &finfo) == 0) {
printf("name: %s\n", finfo.file_name);
}
return;
}
void
test_getfinfo(struct ncp_server *server)
{
struct ncp_file_info finfo;
ncp_get_finfo(server, 0, "sys:", "public", &finfo);
ncp_get_finfo(server, 0, "sys:login", "login.exe", &finfo);
}
void
testopen(struct ncp_server *server)
{
struct ncp_file_info finfo;
char buf[1025];
int bytes_read;
ncp_open_file(server, 0, "sys:\\etc\\samples\\protocol", 0,
AR_READ|AR_WRITE,
&finfo);
if (ncp_read(server, finfo.file_id, 0, 1024, buf, &bytes_read) == 0) {
printf("bytes: %d\n", bytes_read);
buf[bytes_read]=0;
puts(buf);
}
ncp_close_file(server, finfo.file_id);
}
void
testcreate(struct ncp_server *server)
{
if (ncp_rename_file(server, 0, "sys:\\me\\blub.txt", 0,
0, "sys:\\me\\blub1.txt") != 0) {
printf("create war nix\n");
}
if (ncp_create_directory(server, 0, "sys:\\me\\blubdir", 0xff) != 0) {
printf("mkdir war nix\n");
}
if (ncp_rename_directory(server, 0, "sys:\\me\\blubdir",
"\\me\\blubneu") != 0) {
printf("mvdir war nix\n");
return;
}
if (ncp_delete_directory(server, 0, "sys:\\me\\blubneu") != 0) {
printf("rmdir war nix\n");
return;
}
}
void
test_lookup(struct ncp_server *server)
{
struct nw_info_struct sys;
struct nw_info_struct me;
struct nw_file_info blub;
if (ncp_do_lookup(server, NULL, "SYS", &sys) != 0) {
printf("lookup error\n");
return;
}
if (ncp_do_lookup(server, &sys, "ME", &me) != 0) {
printf("lookup error\n");
return;
}
if (ncp_open_create_file_or_subdir(server, &me, "BLUB.TXT",
OC_MODE_CREATE, 0, 0xffff,
&blub) != 0) {
printf("open error\n");
return;
}
return;
}
void
test_trunc(struct ncp_server *server)
{
struct nw_info_struct sys;
struct nw_info_struct me;
struct nw_file_info blub;
int written;
if (ncp_do_lookup(server, NULL, "SYS", &sys) != 0) {
printf("lookup error\n");
return;
}
if (ncp_do_lookup(server, &sys, "ME", &me) != 0) {
printf("lookup error\n");
return;
}
if (ncp_do_lookup(server, &me, "BLUB.TXT", &(blub.i)) != 0) {
printf("lookup error\n");
return;
}
if (ncp_open_create_file_or_subdir(server, &(blub.i), NULL,
OC_MODE_OPEN, 0, AR_READ | AR_WRITE,
&blub) != 0) {
printf("open error\n");
return;
}
if (ncp_write(server, blub.file_handle, 4, 0, "", &written) != 0) {
printf("trunc error\n");
return;
}
if (ncp_close_file(server, blub.file_handle) != 0) {
printf("close error\n");
return;
}
return;
}
void
test_ls(struct ncp_server *server)
{
struct nw_info_struct sys;
struct nw_search_sequence seq;
struct nw_info_struct found;
int res;
if (ncp_do_lookup(server, NULL, "SYS", &sys) != 0) {
printf("lookup error\n");
return;
}
if (ncp_initialize_search(server, &sys, &seq) != 0) {
printf("init error\n");
return;
}
while ((res=ncp_search_for_file_or_subdir(server,&seq,&found)) == 0) {
printf("found %s: %s\n",
(found.attributes & aDIR) ? "dir " : "file",
found.entryName);
}
if (res == 0xfe) {
printf("result: no more files\n");
}
else
{
printf("other error: %x\n", res);
}
return;
}
void
test_ren(struct ncp_server *server)
{
struct nw_info_struct sys;
struct nw_info_struct me;
if (ncp_do_lookup(server, NULL, "SYS", &sys) != 0) {
printf("lookup error\n");
return;
}
if (ncp_do_lookup(server, &sys, "ME", &me) != 0) {
printf("lookup error\n");
return;
}
if (ncp_ren_or_mov_file_or_subdir(server, &me, "BLUB.TXT",
&me, "BLUB1.TXT") != 0) {
printf("ren error\n");
return;
}
}
void
test_rm(struct ncp_server *server)
{
struct nw_info_struct sys;
struct nw_info_struct me;
if (ncp_do_lookup(server, NULL, "SYS", &sys) != 0) {
printf("lookup error\n");
return;
}
if (ncp_do_lookup(server, &sys, "ME", &me) != 0) {
printf("lookup error\n");
return;
}
if (ncp_del_file_or_subdir(server, &me, "BLUB1.TXT") != 0) {
printf("ren error\n");
return;
}
}
void
test_mkdir(struct ncp_server *server)
{
struct nw_info_struct sys;
struct nw_info_struct me;
struct nw_file_info dir1;
struct nw_file_info dir2;
if (ncp_do_lookup(server, NULL, "SYS", &sys) != 0) {
printf("lookup error\n");
return;
}
if (ncp_do_lookup(server, &sys, "ME", &me) != 0) {
printf("lookup error\n");
return;
}
if (ncp_open_create_file_or_subdir(server, &me, "DIR1",
OC_MODE_CREATE, aDIR, 0xffff, &dir1)
!= 0) {
printf("mkdir1 error\n");
return;
}
if (ncp_open_create_file_or_subdir(server, &me, "DIR2",
OC_MODE_CREATE, aDIR, 0xffff, &dir2)
!= 0) {
printf("mkdir2 error\n");
return;
}
if (ncp_del_file_or_subdir(server, &me, "DIR1") != 0) {
printf("rmdir error\n");
return;
}
}
void
test_print(struct ncp_server *server)
{
struct ncp_bindery_object q;
struct queue_job j;
struct print_job_record pj;
int written;
if (ncp_get_bindery_object_id(server, NCP_BINDERY_PQUEUE,
"Q_DJ500", &q) != 0) {
printf("get oid error\n");
return;
}
memset(&j, 0, sizeof(j));
j.j.TargetServerID = 0xffffffff; /* any server */
memset(&(j.j.TargetExecTime), 0xff, sizeof(j.j.TargetExecTime)); /* at once */
j.j.JobType = 0xffff;
strcpy(j.j.JobTextDescription, "Test Job");
memset(&pj, 0, sizeof(pj));
pj.Version = 0;
pj.TabSize = 0;
pj.Copies = 1;
pj.CtrlFlags = 0;
pj.Lines = 0;
pj.Rows = 0;
strcpy(pj.FormName, "");
strcpy(pj.Banner, "");
strcpy(pj.FnameBanner, "");
strcpy(pj.FnameHeader, "");
strcpy(pj.Path, "");
memcpy(j.j.ClientRecordArea, &pj, sizeof(pj));
if (ncp_create_queue_job_and_file(server, q.object_id, &j) != 0) {
printf("create error\n");
return;
}
if (ncp_write(server, j.file_handle, 0, 5, "hallo", &written) != 0) {
printf("write error\n");
return;
}
if (ncp_close_file_and_start_job(server, q.object_id, &j) != 0) {
printf("close error\n");
return;
}
return;
}
int
main(int argc, char **argv)
{
struct stat st;
struct ncp_server serv;
struct ncp_server *server = &serv;
progname = argv[0];
if (geteuid() != 0) {
fprintf(stderr, "%s must be installed suid root\n", progname);
exit(1);
}
if (argc == 2) {
mount_point = argv[1];
} else {
fprintf(stderr, "usage: %s mount-point\n", progname);
printf("defaulting to %s mnt\n", progname);
mount_point = "mnt";
}
if (stat(mount_point, &st) == -1) {
fprintf(stderr, "could not find mount point %s: %s\n",
mount_point, strerror(errno));
exit(1);
}
server->mount_fid = open(mount_point, O_RDONLY, 0);
server->silent = 0;
if (server->mount_fid == -1) {
fprintf(stderr, "Could not open %s: %s\n",
mount_point, strerror(errno));
return -1;
}
#if 0
for (i=0; i<5; i++) {
struct ncp_volume_info info;
ncp_get_volume_info_with_number(server, i, &info);
printf("vol %d: %s\n", i, info.volume_name);
}
test_filesearch(server);
test_getfinfo(server);
test_mkdir(server);
test_ls(server);
#endif
test_trunc(server);
return 0;
}

View File

@@ -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);

47
util/Makefile Normal file
View File

@@ -0,0 +1,47 @@
#
# Makefile for the linux ncp-filesystem routines.
#
UTIL_EXECS = ncpmount ncpumount nprint slist pqlist fsinfo pserver
UTILS = $(addprefix $(INTERM_BINDIR)/,$(UTIL_EXECS))
UIDUTILS = ncpmount ncpumount
#CFLAGS = -Wall $(INCLUDES) $(KERNELD) -g
CFLAGS = -Wall $(INCLUDES) $(KERNELD) -O2
CC = gcc
all: $(UTILS) ncptest
install: all
for i in $(UTIL_EXECS); \
do install --strip $(INTERM_BINDIR)/$$i -m 755 $(BINDIR); done
for i in $(UIDUTILS); do chmod 4755 $(BINDIR)/$$i; done
$(UTILS): $(addsuffix .o,$(UTIL_EXECS)) ncplib.o
$(CC) -o $@ $(addsuffix .o,$(notdir $@)) ncplib.o
ncplib.o: ncplib.c ncplib.h
$(CC) $(CFLAGS) -finline-functions -c ncplib.c
test: test.o ncplib.o
$(CC) -o test test.o ncplib.o
ncptest: ncptest.o ncplib.o
$(CC) -o ncptest ncptest.o ncplib.o
dep:
$(CPP) -M $(INCLUDES) *.c > .depend
clean:
rm -f *.o *~ slist test ncptest
realclean: clean
rm -f $(UTILS) .depend $(DISTFILE)
#
# include a dependency file if one exists
#
ifeq (.depend,$(wildcard .depend))
include .depend
endif

78
util/fsinfo.c Normal file
View File

@@ -0,0 +1,78 @@
/*
* fsinfo.c
*
* Print the info strings of a server, maybe sometime more.
*
* Copyright (C) 1996 by Volker Lendecke
*
*/
#include <stdio.h>
#include <unistd.h>
#include "ncplib.h"
int
main(int argc, char **argv)
{
struct ncp_conn conn;
int opt;
if (ncp_initialize(&conn, &argc, argv, 0) != 0)
{
perror("Could not open connection");
return 1;
}
while ((opt = getopt(argc, argv, "dt")) != EOF)
{
switch(opt)
{
case 'd':
{
char strings[512];
char *s;
if (ncp_get_file_server_description_strings(&conn,
strings)
!= 0)
{
perror("could not get strings");
ncp_close(&conn);
return 1;
}
s = strings;
while (s < strings+512)
{
if (strlen(s) == 0)
{
break;
}
puts(s);
s += strlen(s)+1;
}
break;
}
case 't':
{
time_t t;
if (ncp_get_file_server_time(&conn, &t) != 0)
{
perror("could not get server time");
ncp_close(&conn);
return 1;
}
fputs(ctime(&t), stdout);
break;
}
default:
printf("unknown option: %c\n", opt);
break;
}
}
ncp_close(&conn);
return 0;
}

93
util/ipxlib.h Normal file
View File

@@ -0,0 +1,93 @@
/*
* ipxlib.h
*
* Copyright (C) 1995 by Volker Lendecke
*
*/
#ifndef _IPXLIB_H
#define _IPXLIB_H
#include <linux/types.h>
#include <linux/ncp.h>
#include <linux/ncp_fs.h>
#include <linux/ipx.h>
#include <stdio.h>
typedef unsigned long IPXNet;
typedef unsigned short IPXPort;
typedef unsigned char IPXNode[IPX_NODE_LEN];
#define IPX_USER_PTYPE (0x00)
#define IPX_RIP_PTYPE (0x01)
#define IPX_SAP_PTYPE (0x04)
#define IPX_AUTO_PORT (0x0000)
#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")
#define IPX_THIS_NET (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);
void
ipx_fprint_node(FILE *file, IPXNode node);
void
ipx_fprint_network(FILE *file, IPXNet net);
void
ipx_fprint_port(FILE *file, IPXPort port);
void
ipx_fprint_saddr(FILE *file, struct sockaddr_ipx* sipx);
int
ipx_sscanf_node(char *buf, unsigned char node[IPX_NODE_LEN]);
void
ipx_assign_node(IPXNode dest, IPXNode src);
int
ipx_node_equal(IPXNode n1,IPXNode n2);
#endif /* _IPXLIB_H */

2741
util/ncplib.c Normal file

File diff suppressed because it is too large Load Diff

331
util/ncplib.h Normal file
View File

@@ -0,0 +1,331 @@
/*
* ncplib.h
*
* Copyright (C) 1995, 1996 by Volker Lendecke
*
*/
#ifndef _NCPLIB_H
#define _NCPLIB_H
#include <linux/types.h>
#include <linux/ncp.h>
#include <linux/ncp_fs.h>
#include <linux/ipx.h>
#include <sys/param.h>
#include <stdio.h>
#include <time.h>
#include "ipxlib.h"
#ifndef memzero
#include <string.h>
#define memzero(object) memset(&(object), 0, sizeof(object))
#endif
void
str_upper(char *name);
enum connect_state {
NOT_CONNECTED = 0,
CONN_PERMANENT,
CONN_TEMPORARY
};
struct ncp_conn {
enum connect_state is_connected;
char server[NCP_BINDERY_NAME_LEN];
char user [NCP_BINDERY_NAME_LEN];
struct ncp_fs_info i;
/* Fields for use with permanent connections */
int mount_fid;
char mount_point[MAXPATHLEN];
/* Fields for use with temporary connections */
int ncp_sock;
int wdog_sock;
int wdog_pid;
__u8 sequence;
int completion;
int conn_status;
int reply_size;
/* Fields used to setup ncp requests */
int current_size;
int has_subfunction;
int verbose;
int ncp_reply_size;
int lock;
char packet[NCP_PACKET_SIZE];
};
struct ncp_conn_spec {
char server[NCP_BINDERY_NAME_LEN];
char user[NCP_BINDERY_NAME_LEN];
uid_t uid;
int login_type; /* NCP_BINDERY_USER / NCP_BINDERY_PSERVER */
char password[NCP_BINDERY_NAME_LEN];
};
struct ncp_search_seq {
struct nw_search_sequence s;
int namespace;
};
/* ncp_initialize is the main entry point for user programs which want
to connect to a NetWare Server. It looks for -S, -U, -P and -n in
the argument list, opens the connection and removes the arguments
from the list. It was designed after the X Windows init
functions. */
int
ncp_initialize(struct ncp_conn *conn,
int *argc, char **argv,
int login_necessary);
/* You can login as another object by this procedure. As a first use
pserver comes to mind. */
int
ncp_initialize_as(struct ncp_conn *conn,
int *argc, char **argv,
int login_necessary, int login_type);
/* Open an existing permanent connection */
int
ncp_open(struct ncp_conn *conn,
const struct ncp_conn_spec *spec);
/* Open a connection on an existing mount point */
int
ncp_open_mount(struct ncp_conn *conn,
const char *mount_point);
/* Detach from and destroy a permanent connection */
int
ncp_destroy_permanent(struct ncp_conn *conn);
/* Create a temporary connection */
int
ncp_open_temporary(struct ncp_conn *conn,
const struct ncp_conn_spec *spec);
/* Detach from a permanent connection or destroy a temporary
connection */
int
ncp_close(struct ncp_conn *conn);
/* like getmntent, get_ncp_conn_ent scans /etc/mtab for usable
connections */
struct ncp_conn_ent {
char server[NCP_BINDERY_NAME_LEN];
char user[NCP_BINDERY_NAME_LEN];
uid_t uid;
char mount_point[MAXPATHLEN];
};
struct ncp_conn_ent *
ncp_get_conn_ent(FILE *filep);
#define NWCLIENT (".nwclient")
#define NWC_NOPASSWORD ("-")
/* find an appropriate connection */
struct ncp_conn_spec *
ncp_find_conn_spec(const char *server, const char *user, const char *password,
uid_t uid);
int
ncp_get_file_server_description_strings(struct ncp_conn *conn,
char target[512]);
int
ncp_get_file_server_time(struct ncp_conn *conn, time_t *target);
int
ncp_get_connlist(struct ncp_conn *conn, __u32 last_id,
__u16 object_type, const char *object_name,
int *returned_no, __u16 conn_numbers[256]);
int
ncp_get_encryption_key(struct ncp_conn *conn,
char *target);
int
ncp_get_bindery_object_id(struct ncp_conn *conn,
__u16 object_type,
const char *object_name,
struct ncp_bindery_object *target);
int
ncp_scan_bindery_object(struct ncp_conn *conn,
__u32 last_id, __u16 object_type, char *search_string,
struct ncp_bindery_object *target);
int
ncp_read_property_value(struct ncp_conn *conn,
int object_type, const char *object_name,
int segment, const char *prop_name,
struct nw_property *target);
int
ncp_login_encrypted(struct ncp_conn *conn,
const struct ncp_bindery_object *object,
const unsigned char *key,
const unsigned char *passwd);
int
ncp_login_user(struct ncp_conn *conn,
const unsigned char *username,
const unsigned char *password);
int
ncp_get_volume_info_with_number(struct ncp_conn *conn, int n,
struct ncp_volume_info *target);
int
ncp_get_volume_number(struct ncp_conn *conn, const char *name,
int *target);
int
ncp_file_search_init(struct ncp_conn *conn,
int dir_handle, const char *path,
struct ncp_filesearch_info *target);
int
ncp_file_search_continue(struct ncp_conn *conn,
struct ncp_filesearch_info *fsinfo,
int attributes, const char *path,
struct ncp_file_info *target);
int
ncp_get_finfo(struct ncp_conn *conn,
int dir_handle, const char *path, const char *name,
struct ncp_file_info *target);
int
ncp_open_file(struct ncp_conn *conn,
int dir_handle, const char *path,
int attr, int access,
struct ncp_file_info *target);
int
ncp_close_file(struct ncp_conn *conn, const char *file_id);
int
ncp_create_newfile(struct ncp_conn *conn,
int dir_handle, const char *path,
int attr,
struct ncp_file_info *target);
int
ncp_create_file(struct ncp_conn *conn,
int dir_handle, const char *path,
int attr,
struct ncp_file_info *target);
int
ncp_erase_file(struct ncp_conn *conn,
int dir_handle, const char *path,
int attr);
int
ncp_rename_file(struct ncp_conn *conn,
int old_handle, const char *old_path,
int attr,
int new_handle, const char *new_path);
int
ncp_create_directory(struct ncp_conn *conn,
int dir_handle, const char *path,
int inherit_mask);
int
ncp_delete_directory(struct ncp_conn *conn,
int dir_handle, const char *path);
int
ncp_rename_directory(struct ncp_conn *conn,
int dir_handle,
const char *old_path, const char *new_path);
int
ncp_read(struct ncp_conn *conn, const char *file_id,
off_t offset, size_t count, char *target);
int
ncp_write(struct ncp_conn *conn, const char *file_id,
off_t offset, size_t count, const char *source);
int
ncp_do_lookup(struct ncp_conn *conn,
struct nw_info_struct *dir,
char *path, /* may only be one component */
struct nw_info_struct *target);
int
ncp_modify_file_or_subdir_dos_info(struct ncp_conn *conn,
struct nw_info_struct *file,
__u32 info_mask,
struct nw_modify_dos_info *info);
int
ncp_del_file_or_subdir(struct ncp_conn *conn,
struct nw_info_struct *dir, char *name);
int
ncp_open_create_file_or_subdir(struct ncp_conn *conn,
struct nw_info_struct *dir, char *name,
int open_create_mode,
__u32 create_attributes,
int desired_acc_rights,
struct nw_file_info *target);
int
ncp_initialize_search(struct ncp_conn *conn,
const struct nw_info_struct *dir,
int namespace,
struct ncp_search_seq *target);
int
ncp_search_for_file_or_subdir(struct ncp_conn *conn,
struct ncp_search_seq *seq,
struct nw_info_struct *target);
int
ncp_ren_or_mov_file_or_subdir(struct ncp_conn *conn,
struct nw_info_struct *old_dir, char *old_name,
struct nw_info_struct *new_dir, char *new_name);
int
ncp_create_queue_job_and_file(struct ncp_conn *conn,
__u32 queue_id,
struct queue_job *job);
int
ncp_close_file_and_start_job(struct ncp_conn *conn,
__u32 queue_id,
struct queue_job *job);
int
ncp_attach_to_queue(struct ncp_conn *conn,
__u32 queue_id);
int
ncp_detach_from_queue(struct ncp_conn *conn,
__u32 queue_id);
int
ncp_service_queue_job(struct ncp_conn *conn, __u32 queue_id, __u16 job_type,
struct queue_job *job);
int
ncp_finish_servicing_job(struct ncp_conn *conn, __u32 queue_id,
__u32 job_number, __u32 charge_info);
int
ncp_abort_servicing_job(struct ncp_conn *conn, __u32 queue_id,
__u32 job_number);
#endif /* _NCPLIB_H */

522
util/ncpmount.c Normal file
View File

@@ -0,0 +1,522 @@
/*
* nwmount.c
*
* Copyright (C) 1995 by Volker Lendecke
*
* 1/20/96 - Steven N. Hirsch (hirsch@emba.uvm.edu)
*
* If the ncpfs support is not loaded and we are using kerneld to
* autoload modules, then we don't want to do it here. I added
* a conditional which leaves out the test and load code.
*
* Even if we _do_ want ncpmount to load the module, passing a
* fully-qualified pathname to insmod causes it to bypass a
* path search. This may lead to ncpfs.o not being found on
* some systems.
*/
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <pwd.h>
#include <grp.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/stat.h>
#include <sys/types.h>
/* #include <sys/wait.h> */ /* generates a warning here */
extern pid_t waitpid(pid_t, int *, int);
#include <sys/errno.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <stdlib.h>
#include <sys/mount.h>
#include <mntent.h>
#include <linux/ipx.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <linux/ncp.h>
#include <linux/ncp_fs.h>
#include <linux/ncp_mount.h>
#include "ncplib.h"
static char *progname;
static void usage(void);
static void help(void);
#ifndef HAVE_KERNELD
/* Returns 0 if the filesystem is in the kernel after this routine
completes */
static int
load_ncpfs(void)
{
FILE *ffs;
char s[1024];
char *p, *p1;
pid_t pid;
int status;
/* Check if ncpfs is in the kernel */
ffs = fopen("/proc/filesystems", "r");
if (ffs == NULL)
{
perror("Error: \"/proc/filesystems\" could not be read:");
return -1;
}
p = NULL;
while (! feof(ffs))
{
p1 = fgets(s, sizeof(s), ffs);
if (p1)
{
p = strstr(s, "ncpfs");
if (p)
{
break;
}
}
}
fclose(ffs);
if (p)
{
return 0;
}
/* system() function without signal handling, from Stevens */
if ((pid = fork()) < 0)
{
return 1;
}
else if (pid == 0)
{
/* child */
execl("/sbin/insmod", "insmod", "ncpfs", NULL);
_exit(127); /* execl error */
}
else
{
/* parent */
while (waitpid(pid, &status, 0) < 0)
{
if (errno != EINTR)
{
status = -1;
break;
}
}
}
return status;
}
#endif /* HAVE_KERNELD */
/* Check whether user is allowed to mount on the specified mount point */
static int
mount_ok(struct stat *st)
{
if (!S_ISDIR(st->st_mode))
{
errno = ENOTDIR;
return -1;
}
if ( (getuid() != 0)
&& ( (getuid() != st->st_uid)
|| ((st->st_mode & S_IRWXU) != S_IRWXU)))
{
errno = EPERM;
return -1;
}
return 0;
}
int
main(int argc, char *argv[])
{
struct ncp_mount_data data;
struct stat st;
char mount_name[256];
int fd, result;
struct sockaddr_ipx addr;
int addrlen;
int upcase_password;
int um;
unsigned int flags;
char mount_point[MAXPATHLEN];
struct mntent ment;
FILE *mtab;
char *server = NULL;
char *user = NULL;
char *password = NULL;
struct ncp_conn_spec *spec;
uid_t conn_uid = getuid();
struct ncp_conn conn;
int opt;
progname = argv[0];
memzero(data); memzero(spec); memzero(conn);
if (geteuid() != 0)
{
fprintf(stderr, "%s must be installed suid root\n", progname);
exit(1);
}
data.uid = getuid();
data.gid = getgid();
um = umask(0);
umask(um);
data.file_mode = (S_IRWXU|S_IRWXG|S_IRWXO) & ~um;
data.dir_mode = 0;
upcase_password = 1;
while ((opt = getopt (argc, argv, "CS:U:c:u:g:f:d:P:nh")) != EOF)
{
switch (opt)
{
case 'C':
upcase_password = 0;
break;
case 'S':
if (strlen(optarg) >= sizeof(spec->server))
{
fprintf(stderr, "Servername too long:%s\n",
optarg);
return 1;
}
server = optarg;
break;
case 'U':
if (strlen(optarg) >= sizeof(spec->user))
{
fprintf(stderr, "Username too long: %s\n",
optarg);
return 1;
}
user = optarg;
break;
case 'c':
if (isdigit(optarg[0]))
{
conn_uid = atoi(optarg);
}
else
{
struct passwd *pwd = getpwnam(optarg);
if (pwd == NULL)
{
fprintf(stderr, "Unknown user: %s\n",
optarg);
return 1;
}
conn_uid = pwd->pw_uid;
}
break;
case 'u':
if (isdigit(optarg[0]))
{
data.uid = atoi(optarg);
}
else
{
struct passwd *pwd = getpwnam(optarg);
if (pwd == NULL)
{
fprintf(stderr, "Unknown user: %s\n",
optarg);
return 1;
}
data.uid = pwd->pw_uid;
}
break;
case 'g':
if (isdigit(optarg[0]))
{
data.gid = atoi(optarg);
}
else
{
struct group *grp = getgrnam(optarg);
if (grp == NULL)
{
fprintf(stderr, "Unknown group: %s\n",
optarg);
return 1;
}
data.gid = grp->gr_gid;
}
break;
case 'f':
data.file_mode = strtol(optarg, NULL, 8);
break;
case 'd':
data.dir_mode = strtol(optarg, NULL, 8);
break;
case 'P':
if (strlen(optarg) >= sizeof(spec->password))
{
printf("password too long\n");
exit(1);
}
password = optarg;
break;
case 'n':
password = "";
break;
case 'h':
help();
exit(1);
default:
usage();
return -1;
}
}
if ((spec = ncp_find_conn_spec(server, user, password, data.uid))
== NULL)
{
fprintf(stderr, "Could not find valid server/user\n");
exit(1);
}
if (upcase_password != 0)
{
str_upper(spec->password);
}
if (optind != argc-1)
{
usage();
return -1;
}
realpath(argv[optind], mount_point);
if (stat(mount_point, &st) == -1)
{
fprintf(stderr, "could not find mount point %s: %s\n",
mount_point, strerror(errno));
exit(1);
}
if (mount_ok(&st) != 0)
{
fprintf(stderr, "cannot to mount on %s: %s\n",
mount_point, strerror(errno));
exit(1);
}
#ifndef HAVE_KERNELD
/* Check if the ncpfs filesystem is in the kernel. If not, attempt
* to load the ncpfs module */
if (load_ncpfs() != 0)
{
fprintf(stderr, "Error: Unable to load ncpfs, exiting...\n");
exit(1);
}
#endif
data.version = NCP_MOUNT_VERSION;
data.mounted_uid = conn_uid;
if (data.dir_mode == 0)
{
data.dir_mode = data.file_mode;
if ((data.dir_mode & S_IRUSR) != 0)
data.dir_mode |= S_IXUSR;
if ((data.dir_mode & S_IRGRP) != 0)
data.dir_mode |= S_IXGRP;
if ((data.dir_mode & S_IROTH) != 0)
data.dir_mode |= S_IXOTH;
}
if (ncp_open(&conn, spec) != 0)
{
fprintf(stderr, "could not connect to server %s: %s\n",
server, strerror(errno));
exit(1);
}
if (conn.is_connected == CONN_PERMANENT)
{
fprintf(stderr,
"You already have mounted server %s\nas user "
"%s\non mount point %s\n", spec->server, spec->user,
conn.mount_point);
ncp_close(&conn);
exit(1);
}
data.serv_addr = conn.i.addr;
ncp_close(&conn);
data.ncp_fd = socket(AF_IPX, SOCK_DGRAM, PF_IPX);
if (data.ncp_fd == -1)
{
fprintf(stderr, "could not open ncp socket: %s\n",
strerror(errno));
exit(1);
}
data.wdog_fd = socket(AF_IPX, SOCK_DGRAM, PF_IPX);
if (data.wdog_fd == -1)
{
fprintf(stderr, "could not open wdog socket: %s\n",
strerror(errno));
exit(1);
}
memzero(addr);
addr.sipx_type = NCP_PTYPE;
if (bind(data.ncp_fd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
{
fprintf(stderr, "\nbind: %s\n",
strerror(errno));
fprintf(stderr,
"\nMaybe you want to use \n"
"ipx_configure --auto_interface=on --auto_primary=on\n"
"and try again after waiting a minute.\n\n");
exit(1);
}
addrlen = sizeof(addr);
if (getsockname(data.ncp_fd, (struct sockaddr *)&addr, &addrlen)==-1)
{
perror("getsockname ncp socket");
close(data.ncp_fd); close(data.wdog_fd);
exit(1);
}
addr.sipx_port = htons(ntohs(addr.sipx_port) + 1);
if (bind(data.wdog_fd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
{
fprintf(stderr, "bind(wdog_sock, ): %s\n",
strerror(errno));
exit(1);
}
flags = MS_MGC_VAL;
data.time_out = 20;
data.retry_count = 2;
result = mount(NULL, mount_point, "ncpfs", flags, (char *)&data);
if (result < 0)
{
printf("mount failed\n");
exit(1);
}
if ( (ncp_open_mount(&conn, mount_point) != 0)
|| (ncp_login_user(&conn, spec->user, spec->password) != 0))
{
fprintf(stderr, "%s: login failed\n", strerror(errno));
ncp_close(&conn);
umount(mount_point);
exit(1);
}
ncp_close(&conn);
strcpy(mount_name, spec->server);
strcat(mount_name, "/");
strcat(mount_name, spec->user);
ment.mnt_fsname = mount_name;
ment.mnt_dir = mount_point;
ment.mnt_type = "ncpfs";
ment.mnt_opts = "rw";
ment.mnt_freq = 0;
ment.mnt_passno= 0;
if ((fd = open(MOUNTED"~", O_RDWR|O_CREAT|O_EXCL, 0600)) == -1)
{
fprintf(stderr, "Can't get "MOUNTED"~ lock file");
exit(1);
}
close(fd);
if ((mtab = setmntent(MOUNTED, "a+")) == NULL)
{
fprintf(stderr, "Can't open " MOUNTED);
exit(1);
}
if (addmntent(mtab, &ment) == 1)
{
fprintf(stderr, "Can't write mount entry");
exit(1);
}
if (fchmod(fileno(mtab), 0644) == -1)
{
fprintf(stderr, "Can't set perms on "MOUNTED);
exit(1);
}
endmntent(mtab);
if (unlink(MOUNTED"~") == -1)
{
fprintf(stderr, "Can't remove "MOUNTED"~");
exit(1);
}
return 0;
}
static void
usage(void)
{
printf("usage: %s [options] mount-point\n", progname);
printf("Try `%s -h' for more information\n", progname);
}
static void
help(void)
{
printf("\n");
printf("usage: %s [options] mount-point\n", progname);
printf("\n"
"-S server Server name to be used\n"
"-U username Username sent to server\n"
"-u uid uid the mounted files get\n"
"-g gid gid the mounted files get\n"
"-f mode permission the files get (octal notation)\n"
"-d mode permission the dirs get (octal notation)\n"
"-c uid uid to identify the connection to mount on\n"
" Only makes sense for root\n"
"-C Don't convert password to uppercase\n"
"-P password Use this password\n"
"-n Do not use any password\n"
" If neither -P nor -n are given, you are\n"
" asked for a password.\n"
"-h print this help text\n"
"\n");
}

164
util/ncptest.c Normal file
View File

@@ -0,0 +1,164 @@
/*
* ncptest.c
*
* Copyright (C) 1995 by Volker Lendecke
*
*/
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <pwd.h>
#include <grp.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ioctl.h>
/* #include <sys/wait.h> */ /* generates a warning here */
extern pid_t waitpid(pid_t, int *, int);
#include <sys/errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <stdlib.h>
#include <sys/mount.h>
#include <mntent.h>
#include <linux/ipx.h>
#include <linux/fs.h>
#include <linux/ncp.h>
#include <linux/ncp_fs.h>
#include <linux/ncp_mount.h>
#include "ncplib.h"
void
test_print(struct ncp_conn *conn)
{
struct ncp_bindery_object q;
struct queue_job j;
struct print_job_record pj;
int written;
if (ncp_get_bindery_object_id(conn, NCP_BINDERY_PQUEUE,
"Q_DJ500", &q) != 0) {
printf("get oid error\n");
return;
}
memset(&j, 0, sizeof(j));
j.j.TargetServerID = 0xffffffff; /* any server */
/* at once */
memset(&(j.j.TargetExecTime), 0xff, sizeof(j.j.TargetExecTime));
j.j.JobType = htons(0);
strcpy(j.j.JobTextDescription, "Test Job");
memset(&pj, 0, sizeof(pj));
pj.Version = 0;
pj.TabSize = 8;
pj.Copies = htons(1);
pj.CtrlFlags = 0;
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));
if (ncp_create_queue_job_and_file(conn, q.object_id, &j) != 0) {
printf("create error\n");
return;
}
if ((written = ncp_write(conn, j.file_handle, 0, 15,
"hallo, wie geht's?")) < 0) {
printf("write error\n");
return;
}
if (ncp_close_file_and_start_job(conn, q.object_id, &j) != 0) {
printf("close error\n");
return;
}
return;
}
void
test_ls(struct ncp_conn *server)
{
struct nw_info_struct sys;
struct nw_info_struct public;
struct ncp_search_seq seq;
struct nw_info_struct found;
int res;
if (ncp_do_lookup(server, NULL, "SYS", &sys) != 0)
{
printf("lookup error\n");
return;
}
if (ncp_do_lookup(server, &sys, "PUBLIC", &public) != 0)
{
printf("lookup public error\n");
return;
}
if (ncp_initialize_search(server, &public, 4, &seq) != 0)
{
printf("init error\n");
return;
}
while ((res=ncp_search_for_file_or_subdir(server,&seq,&found)) == 0)
{
printf("found %s: %s\n",
(found.attributes & aDIR) ? "dir " : "file",
found.entryName);
}
if (res == 0xfe)
{
printf("result: no more files\n");
}
else
{
printf("other error: %x\n", res);
}
return;
}
void
test_connlist(struct ncp_conn *conn)
{
__u16 conn_list[256];
int no;
ncp_get_connlist(conn, 0, NCP_BINDERY_USER, "*", &no, conn_list);
return;
}
int
main(int argc, char *argv[])
{
struct ncp_conn conn;
if (ncp_initialize(&conn, &argc, argv, 1) != 0)
{
perror("ncp_initialize");
return 1;
}
test_connlist(&conn);
ncp_close(&conn);
return 0;
}

197
util/ncpumount.c Normal file
View File

@@ -0,0 +1,197 @@
/*
* nwumount.c
*
* Copyright (C) 1995 by Volker Lendecke
*
*/
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <pwd.h>
#include <grp.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/stat.h>
#include <sys/types.h>
/* #include <sys/wait.h> */ /* generates a warning here */
extern pid_t waitpid(pid_t, int *, int);
#include <sys/errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <stdlib.h>
#include <sys/mount.h>
#include <mntent.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <linux/ncp.h>
#include <linux/ncp_mount.h>
#include <linux/ncp_fs.h>
static char *progname;
static void
usage(void)
{
printf("usage: %s mount-point\n", progname);
}
static int
umount_ok(const char *mount_point)
{
int fid = open(mount_point, O_RDONLY, 0);
uid_t mount_uid;
if (fid == -1) {
fprintf(stderr, "Could not open %s: %s\n",
mount_point, strerror(errno));
return -1;
}
if (ioctl(fid, NCP_IOC_GETMOUNTUID, &mount_uid) != 0) {
fprintf(stderr, "%s probably not ncp-filesystem\n",
mount_point);
return -1;
}
if ( (getuid() != 0)
&& (mount_uid != getuid())) {
fprintf(stderr, "You are not allowed to umount %s\n",
mount_point);
return -1;
}
close(fid);
return 0;
}
/* Make a canonical pathname from PATH. Returns a freshly malloced string.
It is up the *caller* to ensure that the PATH is sensible. i.e.
canonicalize ("/dev/fd0/.") returns "/dev/fd0" even though ``/dev/fd0/.''
is not a legal pathname for ``/dev/fd0.'' Anything we cannot parse
we return unmodified. */
char *
canonicalize (const char *path)
{
char *canonical = malloc (PATH_MAX + 1);
if (path == NULL)
return NULL;
if (realpath (path, canonical))
return canonical;
strcpy (canonical, path);
return canonical;
}
int
main(int argc, char *argv[])
{
int fd;
char* mount_point;
struct mntent *mnt;
FILE* mtab;
FILE* new_mtab;
progname = argv[0];
if (geteuid() != 0) {
fprintf(stderr, "%s must be installed suid root\n", progname);
exit(1);
}
if (argc != 2) {
usage();
exit(1);
}
mount_point = canonicalize(argv[1]);
if (umount_ok(mount_point) != 0) {
exit(1);
}
if (umount(mount_point) != 0) {
fprintf(stderr, "Could not umount %s: %s\n",
mount_point, strerror(errno));
exit(1);
}
if ((fd = open(MOUNTED"~", O_RDWR|O_CREAT|O_EXCL, 0600)) == -1)
{
fprintf(stderr, "Can't get "MOUNTED"~ lock file");
return 1;
}
close(fd);
if ((mtab = setmntent(MOUNTED, "r")) == NULL) {
fprintf(stderr, "Can't open " MOUNTED ": %s\n",
strerror(errno));
return 1;
}
#define MOUNTED_TMP MOUNTED".tmp"
if ((new_mtab = setmntent(MOUNTED_TMP, "w")) == NULL) {
fprintf(stderr, "Can't open " MOUNTED_TMP ": %s\n",
strerror(errno));
endmntent(mtab);
return 1;
}
while ((mnt = getmntent(mtab)) != NULL) {
if (strcmp(mnt->mnt_dir, mount_point) != 0) {
addmntent(new_mtab, mnt);
}
}
endmntent(mtab);
if (fchmod (fileno (new_mtab), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) {
fprintf(stderr, "Error changing mode of %s: %s\n",
MOUNTED_TMP, strerror(errno));
exit(1);
}
endmntent(new_mtab);
if (rename(MOUNTED_TMP, MOUNTED) < 0) {
fprintf(stderr, "Cannot rename %s to %s: %s\n",
MOUNTED, MOUNTED_TMP, strerror(errno));
exit(1);
}
if (unlink(MOUNTED"~") == -1)
{
fprintf(stderr, "Can't remove "MOUNTED"~");
return 1;
}
return 0;
}
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-indent-level: 8
* c-brace-imaginary-offset: 0
* c-brace-offset: -8
* c-argdecl-indent: 8
* c-label-offset: -8
* c-continued-statement-offset: 8
* c-continued-brace-offset: 0
* End:
*/

339
util/nprint.c Normal file
View File

@@ -0,0 +1,339 @@
/*
* nwprint.c
*
* Send data to a NetWare print queue.
*
* Copyright (C) 1995 by Volker Lendecke
*
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <ctype.h>
#include "ncplib.h"
static char *progname;
static void
usage(void);
static void help(void);
void
main(int argc, char *argv[])
{
struct ncp_conn conn;
char default_queue[] = "*";
char *queue = default_queue;
int opt;
struct ncp_bindery_object q;
struct queue_job j;
struct print_job_record pj;
int written, read_this_time;
char buf[8192];
char *file_name;
int file;
progname = argv[0];
memzero(j); memzero(pj); memzero(q); memzero(conn);
if ( (argc == 2)
&& (strcmp(argv[1], "-h") == 0))
{
help();
exit(0);
}
if (ncp_initialize(&conn, &argc, argv, 1) != 0)
{
perror("Could not open connection");
exit(1);
}
/*
* Fill in default values for print job
*/
j.j.TargetServerID = 0xffffffff; /* any server */
/* at once */
memset(&(j.j.TargetExecTime), 0xff, sizeof(j.j.TargetExecTime));
j.j.JobType = htons(0);
strcpy(j.j.JobTextDescription, "No Description");
pj.Version = 0;
pj.TabSize = 8;
pj.Copies = htons(1);
pj.CtrlFlags = 0;
pj.Lines = htons(66);
pj.Rows = htons(80);
strcpy(pj.FnameHeader, "stdin");
while ((opt = getopt(argc, argv, "hq:d:p:b:f:l:r:c:t:F:TN"))!=EOF)
{
switch (opt) {
case 'h':
help();
ncp_close(&conn);
exit(1);
case 'p':
/* Path */
pj.CtrlFlags |= PRINT_BANNER;
if (strlen(optarg) >= sizeof(pj.Path))
{
strncpy(pj.Path, optarg,
sizeof(pj.Path));
}
else
{
strcpy(pj.Path, optarg);
}
break;
case 'b':
/* Banner Name */
pj.CtrlFlags |= PRINT_BANNER;
if (strlen(optarg) >= sizeof(pj.BannerName))
{
strncpy(pj.BannerName, optarg,
sizeof(pj.BannerName));
}
else
{
strcpy(pj.BannerName, optarg);
}
break;
case 'f':
/* File Name in Banner */
pj.CtrlFlags |= PRINT_BANNER;
if (strlen(optarg) >= sizeof(pj.FnameBanner))
{
strncpy(pj.FnameBanner, optarg,
sizeof(pj.FnameBanner));
}
else
{
strcpy(pj.FnameBanner, optarg);
}
break;
case 'l':
/* lines, default: 66 */
if ((atoi(optarg) < 0) || (atoi(optarg) > 65535))
{
fprintf(stderr,
"invalid line number: %s\n", optarg);
break;
}
pj.Lines = htons(atoi(optarg));
pj.CtrlFlags |= EXPAND_TABS;
break;
case 'r':
/* rows, default: 80 */
if ((atoi(optarg) < 0) || (atoi(optarg) > 65535))
{
fprintf(stderr,
"invalid row number: %s\n", optarg);
break;
}
pj.Rows = htons(atoi(optarg));
pj.CtrlFlags |= EXPAND_TABS;
break;
case 'c':
/* copies, default: 1 */
if ((atoi(optarg) < 0) || (atoi(optarg) > 65000))
{
fprintf(stderr,
"invalid copies: %s\n", optarg);
break;
}
pj.Copies = htons(atoi(optarg));
pj.CtrlFlags |= EXPAND_TABS;
break;
case 't':
/* tab size, default: 8 */
if ((atoi(optarg) < 0) || (atoi(optarg) > 255))
{
fprintf(stderr,
"invalid tab size: %s\n", optarg);
break;
}
pj.TabSize = atoi(optarg);
pj.CtrlFlags |= EXPAND_TABS;
break;
case 'T':
/* expand tabs, default tabsize: 8 */
pj.CtrlFlags |= EXPAND_TABS;
break;
case 'N':
/* no form feed */
pj.CtrlFlags |= NO_FORM_FEED;
break;
case 'F':
/* Form number, default: 0 */
if ((atoi(optarg) < 0) || (atoi(optarg) > 255))
{
fprintf(stderr,
"invalid form number: %s\n", optarg);
break;
}
j.j.JobType = htons(atoi(optarg));
break;
case 'q':
/* Queue name to print on, default: '*' */
if (strlen(optarg) >= NCP_BINDERY_NAME_LEN)
{
printf("queue name too long: %s\n",
optarg);
exit(1);
}
queue = optarg;
break;
case 'd':
/* Job Description */
pj.CtrlFlags |= PRINT_BANNER;
if (strlen(optarg) >= sizeof(j.j.JobTextDescription))
{
strncpy(j.j.JobTextDescription, optarg,
sizeof(j.j.JobTextDescription));
}
else
{
strcpy(j.j.JobTextDescription, optarg);
}
break;
default:
usage();
exit(1);
}
}
if (optind != argc-1)
{
usage();
exit(1);
}
file_name = argv[optind];
if (strcmp(file_name, "-") == 0)
{
file = 0; /* stdin */
}
else
{
file = open(file_name, O_RDONLY, 0);
if (file < 0)
{
perror("could not open file");
exit(1);
}
if (strlen(file_name) >= sizeof(pj.FnameHeader))
{
strncpy(pj.FnameHeader, file_name,
sizeof(pj.FnameHeader));
}
else
{
strcpy(pj.FnameHeader, file_name);
}
if (strlen(pj.FnameBanner) == 0)
{
if (strlen(file_name) >= sizeof(pj.FnameBanner))
{
strncpy(pj.FnameBanner, file_name,
sizeof(pj.FnameBanner));
}
else
{
strcpy(pj.FnameBanner, file_name);
}
}
}
memcpy(j.j.ClientRecordArea, &pj, sizeof(pj));
str_upper(queue);
if (ncp_scan_bindery_object(&conn, 0xffffffff, NCP_BINDERY_PQUEUE,
queue, &q) != 0)
{
printf("could not find queue %s\n", queue);
return;
}
if (ncp_create_queue_job_and_file(&conn, q.object_id, &j) != 0)
{
printf("create error\n");
return;
}
written = 0;
do
{
read_this_time = read(file, buf, sizeof(buf));
if (read_this_time < 0)
{
break;
}
if (ncp_write(&conn, j.file_handle,
written, read_this_time, buf) < read_this_time)
{
break;
}
written += read_this_time;
} while (read_this_time > 0);
close(file);
if (ncp_close_file_and_start_job(&conn, q.object_id, &j) != 0) {
printf("close error\n");
return;
}
ncp_close(&conn);
}
static void
usage(void)
{
fprintf(stderr, "usage: %s [options] file\n", progname);
exit(1);
}
static void
help(void)
{
printf("\n");
printf("usage: %s [options] file\n", progname);
printf("\n"
"-S server Server name to be used\n"
"-U username Username sent to server\n"
"-P password Use this password\n"
"-n Do not use any password\n"
"-C Don't convert password to uppercase\n"
"-q queue name Name of the printing queue to use\n"
"-d job desc Job description\n"
"-p path name Path name to appear on banner\n"
"-b bannername Banner name (up to 12 chars)\n"
"-f filename Filename to appear on banner\n"
"-l lines Number of lines per page\n"
"-r rows Number of rows per page\n"
"-t tab Number of spaces per tab\n"
"-T Print server tab expantion\n"
"-N Surpress print server form feeds\n"
"-F form # Form number to print on\n"
"-h print this help text\n"
"\n");
}

View File

@@ -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,8 +141,8 @@ shuffle1(buf32 temp, unsigned char *target)
}
void
shuffle(unsigned char *lon, const unsigned char *buf, int buflen,
static void
shuffle(const unsigned char *lon, const unsigned char *buf, int buflen,
unsigned char *target)
{
int b2, d, s;
@@ -191,8 +190,10 @@ shuffle(unsigned char *lon, const unsigned char *buf, int buflen,
}
void
nw_encrypt(unsigned char *fra,unsigned char *buf,unsigned char *til)
static void
nw_encrypt(const unsigned char *fra,
const unsigned char *buf,
unsigned char *til)
{
buf32 k;
int s;

75
util/pqlist.c Normal file
View File

@@ -0,0 +1,75 @@
/*
* pqlist.c
*
* List all print queues on a server
*
* Copyright (C) 1996 by Volker Lendecke
*
*/
#include <stdio.h>
#include <unistd.h>
#include <ctype.h>
#include "ncplib.h"
int
main(int argc, char **argv)
{
struct ncp_conn conn;
struct ncp_bindery_object q;
int found = 0;
char default_pattern[] = "*";
char *pattern = default_pattern;
char *p;
if (ncp_initialize(&conn, &argc, argv, 1) != 0)
{
perror("Could not open connection");
return 1;
}
if (argc > 2)
{
fprintf(stderr, "usage: %s [options] [pattern]\n", argv[0]);
return 1;
}
if (argc == 2)
{
pattern = argv[1];
}
for (p = pattern; *p != '\0'; p++)
{
*p = toupper(*p);
}
if (isatty(1))
{
printf("\nServer: %s\n", conn.server);
printf("%-52s%-10s\n"
"-----------------------------------------------"
"-------------\n",
"Print queue name",
"Queue ID");
}
q.object_id = 0xffffffff;
while (ncp_scan_bindery_object(&conn, q.object_id,
NCP_BINDERY_PQUEUE, "*", &q) == 0)
{
found = 1;
printf("%-52s", q.object_name);
printf("%08x\n", q.object_id);
}
if ((found == 0) && (isatty(1)))
{
printf("No queues found\n");
}
ncp_close(&conn);
return 0;
}

338
util/pserver.c Normal file
View File

@@ -0,0 +1,338 @@
/*
* pserver.c
*
* Copyright (C) 1996 by Volker Lendecke
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include "ncplib.h"
struct nw_queue {
struct ncp_conn *conn;
char queue_name[NCP_BINDERY_NAME_LEN];
__u32 queue_id;
__u16 job_type;
char *command;
};
static struct nw_queue q;
static int term_request;
static char *progname;
static int
init_queue(struct ncp_conn *conn, char *queue_name,
char *command, struct nw_queue *q);
static int
poll_queue(struct nw_queue *q);
static void
usage(void)
{
fprintf(stderr, "usage: %s [options] file\n", progname);
exit(1);
}
static void
help(void)
{
printf("\n");
printf("usage: %s [options]\n", progname);
printf("\n"
"-S server Server name to be used\n"
"-U username Print Server name sent to server\n"
"-P password Use this password\n"
"-n Do not use any password\n"
"-C Don't convert password to uppercase\n"
"-q queue name Name of the printing queue to use\n"
"-c command Name of print command, default: 'lpr'\n"
"-j job type Type of job (Form number) to service\n"
"-t timeout Polling interval, default: 30 sec\n"
"-d Debug: don't daemonize\n"
"-h print this help text\n"
"\n");
}
#ifndef NCP_BINDERY_PSERVER
#define NCP_BINDERY_PSERVER (0x0007)
#endif
static void
terminate_handler()
{
signal(SIGTERM,terminate_handler);
signal(SIGINT, terminate_handler);
term_request=1;
}
static void
daemonize()
{
int fd,c;
if ((c = fork()) > 0) exit(0);
if (c < 0)
{
fprintf(stderr, "ipxripd: can't fork: %s\n",strerror(errno));
exit(1);
}
close(0);
close(1);
close(2);
if ((fd = open("/dev/tty", O_RDWR)) >= 0)
{
ioctl(fd, TIOCNOTTY, NULL);
close(fd);
}
}
int
main(int argc, char *argv[])
{
struct ncp_conn conn;
int poll_timeout = 30;
int opt;
int job_type = 0xffff;
int debug = 0;
int i;
char *queue_name = NULL;
char default_command[] = "lpr";
char *command = default_command;
progname = argv[0];
for (i = 1; i < argc; i += 1)
{
if ( (strcmp(argv[i], "-h") == 0)
|| (strcmp(argv[i], "-?") == 0))
{
help();
exit(0);
}
}
for (i = 1; i < argc; i += 1)
{
if (strcmp(argv[i], "-d") == 0)
{
debug = 1;
break;
}
}
if (debug == 0)
{
daemonize();
}
if (ncp_initialize_as(&conn, &argc, argv, 1, NCP_BINDERY_PSERVER) != 0)
{
perror("Could not open connection");
return 1;
}
while ((opt = getopt(argc, argv, "q:c:j:t:dh")) != EOF)
{
switch (opt)
{
case 'q':
queue_name = optarg;
break;
case 'c':
command = optarg;
break;
case 'j':
job_type = atoi(optarg);
break;
case 't':
poll_timeout = atoi(optarg);
break;
case 'd':
debug = 1;
break;
case 'h':
break;
default:
usage();
return -1;
}
}
if (argc != optind)
{
usage();
return -1;
}
memzero(q);
if (queue_name == NULL)
{
fprintf(stderr, "You must specify a queue\n");
return 1;
}
if (init_queue(&conn, queue_name, command, &q) != 0)
{
perror("Could not init queue");
ncp_close(&conn);
return 1;
}
q.job_type = job_type;
term_request = 0;
signal(SIGTERM,terminate_handler);
signal(SIGINT, terminate_handler);
while (1)
{
if ( (poll_queue(&q) != 0)
&& (term_request == 0))
{
continue;
}
if (term_request != 0)
{
break;
}
sleep(poll_timeout);
}
ncp_detach_from_queue(&conn, q.queue_id);
ncp_close(&conn);
return 0;
}
static int
init_queue(struct ncp_conn *conn, char *queue_name, char *command,
struct nw_queue *q)
{
struct ncp_bindery_object obj;
str_upper(queue_name);
q->conn = conn;
q->command = command;
if (ncp_get_bindery_object_id(conn, NCP_BINDERY_PQUEUE,
queue_name, &obj) != 0)
{
fprintf(stderr, "Queue %s not found\n", queue_name);
return -1;
}
q->queue_id = obj.object_id;
memcpy(q->queue_name, obj.object_name, sizeof(q->queue_name));
if (ncp_attach_to_queue(conn, q->queue_id) != 0)
{
fprintf(stderr, "Could not attach to queue %s\n",
queue_name);
return -1;
}
return 0;
}
static int
poll_queue(struct nw_queue *q)
{
struct queue_job job;
int fd[2];
int pid;
if (ncp_service_queue_job(q->conn, q->queue_id, q->job_type,
&job) != 0)
{
/* No job for us */
return 0;
}
if (pipe(fd) < 0)
{
perror("pipe");
goto fail;
}
if ((pid = fork()) < 0)
{
perror("fork");
goto fail;
}
if (pid > 0)
{
/* parent */
char buf[1024];
size_t result;
off_t offset = 0;
close(fd[0]); /* close read end */
while ((result = ncp_read(q->conn, job.file_handle, offset,
sizeof(buf), buf)) > 0)
{
offset += result;
if (write(fd[1], buf, result) != result)
{
goto fail;
}
}
close(fd[1]); /* and close write end */
if (waitpid(pid, NULL, 0) < 0)
{
perror("waitpid");
}
}
else
{
/* child */
close(fd[1]); /* close write end */
if (fd[0] != STDIN_FILENO)
{
if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO)
{
perror("dup2");
close(fd[0]);
exit(1);
}
close(fd[0]);
}
execl("/bin/sh", "sh", "-c", q->command, NULL);
perror("exec");
close(fd[0]);
exit(1);
}
ncp_finish_servicing_job(q->conn, q->queue_id, job.j.JobNumber,0);
return 1;
fail:
ncp_abort_servicing_job(q->conn, q->queue_id, job.j.JobNumber);
/* We tell that we did not have a job to avoid overloading
when something's wrong */
return 0;
}

91
util/slist.c Normal file
View File

@@ -0,0 +1,91 @@
/*
* slist.c
*
* List all file server that are known in the IPX network.
*
* Copyright (C) 1995 by Volker Lendecke
*
*/
#include "ncplib.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
void
main(int argc, char *argv[])
{
struct ncp_conn conn;
struct ncp_bindery_object obj;
int found = 0;
char default_pattern[] = "*";
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);
}
if (ncp_initialize(&conn, &argc, argv, 0) != 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(&conn, obj.object_id,
NCP_BINDERY_FSERVER, pattern,
&obj) == 0)
{
struct nw_property prop;
struct prop_net_address *naddr
= (struct prop_net_address *)&prop;
found = 1;
printf("%-52s", obj.object_name);
if (ncp_read_property_value(&conn, 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_close(&conn);
}

View File

@@ -3,6 +3,5 @@
# abcd is my ipx network number and 1234 my server's internal network number.
# 00001b038b11 is the server's node number.
#
ipx_interface add -p eth0 EtherII 10
ipx_route add 1992 10 00001b3bc0c9
ipx_route add 1234 10 00001b038b11
ipx_interface add -p eth0 EtherII 1234
ipx_route add 10 1234 00001b039949