Import ncpfs 0.6

This commit is contained in:
ncpfs archive import
2026-04-28 20:39:57 +02:00
parent eb9c79840a
commit e05e55a64a
34 changed files with 1794 additions and 183 deletions

BIN
.downloads/ncpfs-0.6.tgz Normal file

Binary file not shown.

14
BUGS
View File

@@ -3,15 +3,17 @@ 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
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.
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. Maybe this will be
fixed in the future.

View File

@@ -2,76 +2,45 @@
# Makefile for the linux ncp-filesystem routines.
#
INCLUDES = -I/usr/src/linux/include
KERNEL = 1.3
CFLAGS = -Wall -Wstrict-prototypes -O2 -DMODULE -fomit-frame-pointer \
$(INCLUDES) \
# -DDEBUG_NCP=2 -DDEBUG_NCP_MALLOC
# -DDEBUG_NCP_MALLOC
INCLUDES = -I/usr/src/linux/include -Ikernel
BINDIR = ./bin
CC = gcc -D__KERNEL__ -I.
AS = as
ARCH = i386
CFLAGS = -Wall $(INCLUDES)
CC = gcc
.c.s:
$(CC) $(CFLAGS) -S $<
.c.o:
$(CC) $(CFLAGS) -c $<
.s.o:
$(AS) -o $*.o $<
all: kernel
make -C util
make -C kernel/src ncpfs.o
cp kernel/src/ncpfs.o bin
OBJS= dir.o inode.o file.o sock.o ioctl.o ncplib.o
all: ncpfs.o ncpmount ncptest
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
kernel:
rm -f kernel
ln -s kernel-$(KERNEL) kernel
dep:
$(CPP) -M $(INCLUDES) *.c > .depend
clean:
rm -f *.o *~
rm -f kernel
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`
realclean: clean
rm -f ncpmount ncptest .depend $(DISTFILE) *.out
rm -fr bin/* ncpfs.tgz util/mnt
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: realclean
rm -fr mnt
(cd ..; \
tar cvf - $(SRCDIR) | \
gzip -9 > $(DISTFILE); \

32
README
View File

@@ -1,22 +1,22 @@
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 version 0.6 of ncpfs, a free NetWare client for Linux. You
need at least kernel 1.3.44 for this version. It does NOT work with
any lower one, especially not with version 1.2.x.
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.
To install ncpfs, just type 'make'. After that, you find the
neccessary kernel module and the mounting tools in ./bin. Type 'insmod
ncpfs.o' and then 'ncpmount server mount-point'. For further
information, please look at the manual pages in ./man.
To install ncpfs, just type 'make', 'insmod ncpfs.o' and then
'ncpmount server mount-point'.
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.
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 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

View File

@@ -45,6 +45,7 @@ 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;
@@ -177,6 +178,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;

View File

@@ -27,6 +27,7 @@ struct ncp_ioctl_request {
};
#define NCP_IOC_NCPREQUEST _IOR('n', 1, unsigned char *)
#define NCP_IOC_GETMOUNTUID _IOR('u', 1, uid_t)
/*
* The packet size to allocate. One page should be enough.

67
kernel-1.3/src/Makefile Normal file
View File

@@ -0,0 +1,67 @@
#
# Makefile for the linux ncp-filesystem routines.
#
INCLUDES = -I/usr/src/linux/include -I..
CFLAGS = -Wall -Wstrict-prototypes -O2 -DMODULE -fomit-frame-pointer \
$(INCLUDES) \
# -DDEBUG_NCP=2 -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.o
all: ncpfs.o
ncpfs.o: $(OBJS)
$(LD) -r -o ncpfs.o $(OBJS)
ncplib.o: ncplib.c ncplib.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

@@ -357,11 +357,12 @@ ncp_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
memcpy_tofs(buf, &tmp, bufsiz);
}
/* 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,6 +380,38 @@ ncp_notify_change(struct inode *inode, struct iattr *attr)
~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO))))
return -EPERM;
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 ((attr->ia_valid & ATTR_SIZE) != 0) {
int written;

View File

@@ -58,9 +58,8 @@ ncp_ioctl (struct inode * inode, struct file * filp,
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);
memcpy_fromfs(server->packet, request.data,
request.size+sizeof(struct ncp_request_header));
ncp_request(server, request.function);
@@ -73,6 +72,15 @@ ncp_ioctl (struct inode * inode, struct file * filp,
ncp_unlock_server(server);
return server->reply_size;
case NCP_IOC_GETMOUNTUID:
if ((result = verify_area(VERIFY_WRITE, (uid_t*) arg,
sizeof(uid_t))) != 0) {
return result;
}
put_fs_word(NCP_SERVER(inode)->m.mounted_uid, (uid_t*) arg);
return 0;
default:
return -EINVAL;
}

View File

@@ -1,5 +1,4 @@
#include "ncplib.h"
#include "nwcrypt.h"
typedef __u8 byte;
typedef __u16 word;
@@ -41,7 +40,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);
@@ -318,6 +317,34 @@ 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)
@@ -441,7 +468,7 @@ 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, '*');

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

1
linux
View File

@@ -1 +0,0 @@
.

42
man/ipx_configure.8 Normal file
View File

@@ -0,0 +1,42 @@
.TH IPX_CONFIGURE 8 "IPX Utilities" "Caldera, Inc."
.SH NAME
ipx_configure \- query/configure IPX behavior
.SH SYNOPSIS
.B ipx_configure
[\-\-help]
[\-\-auto_interface=[on|off]]
[\-\-auto_primary=[on|off]]
.SH DESCRIPTION
.B ipx_configure
queries 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 either turns on or off the behavior of automatically creating
interfaces.
.TP
.I "\-\-auto_primary=[on|off]"
This argument either turns on or off the behavior of automatically selecting
a primary interface.
.TP
.I "\-\-help"
Print out information about utility.
.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>

190
man/ncpmount.8 Normal file
View File

@@ -0,0 +1,190 @@
.TH NCPMOUNT 8 25/11/1995 ncpmount ncpmount
.SH NAME
ncpmount \- mount program for ncpfs
.SH SYNOPSIS
.B ncpmount
.B server mount-point
[
.B -h
] [
.B -n
.I
] [
.B -P
.I password
] [
.B -C
] [
.B -s
.I server name
] [
.B -c
.I client name
] [
.B -U
.I user name
] [
.B -u
.I uid
] [
.B -g
.I gid
] [
.B -f
.I file mode
] [
.B -d
.I dir mode
]
.SH DESCRIPTION
This program is an interface to the NCP filesystem.
.B ncpfs
is a 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.
.SH OPTIONS
.B server
.RS 3
.B server
is the name of the server you want to use on the server.
.RE
.B mount-point
.RS 3
.B mount-point
is the directory you want to mount the filesystem over. It's the same
as in the 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 -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. You can turn off
this conversion by
.B -C.
.RE
.B -n
.RS 3
.B -n
should be given to mount shares which do not require a password to log in.
.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.
If neither
.B -n
nor
.B -P
are given, ncpmount prompts for a password. This makes it difficult to
use in scripts such as /etc/rc. But that's not ncpmount's fault, but a
general problem with the fact that you need a password on every
login. If anybody has a satisfying solution to this problem, please
tell me.
.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 -u
.I uid,
.B -g
.I gid
.RS 3
Currently I did not implement a mapping from NetWare users/groups to
unix users/groups. Unix requires that each file has an owner
and a group it belongs to. With
.B -u
and
.B -g
you can tell ncpmount which id's it should assign to the files in the
mounted direcory.
The defaults for these values are the current uid and gid.
.RE
.B -f
.I file mode,
.B -d
.I dir mode
.RS 3
Like
.B -u
and
.B -g,
these options are also used to cover deficiencies in the
implementation of ncpfs. I did not implement a scheme to map NetWare
permissions to unix permissions. So ncpmount has to be told which
permissions it should assign to the mounted files and direcories. The
values have to be given 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
If you have difficulties in mounting, please make sure that you have configured your ipx subsystem correctly. 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.

28
man/ncpumount.8 Normal file
View File

@@ -0,0 +1,28 @@
.TH NCPUMOUNT 8 25/11/1995 ncpumount ncpumount
.SH NAME
ncpumount \- umount for normal users
.SH SYNOPSIS
.B ncpumount
.B mount-point
.SH DESCRIPTION
With this program, normal users can unmount ncp-filesystems, provided
that it is suid root.
.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)

View File

@@ -1,14 +1,14 @@
Begin3
Title: ncpfs
Version: 0.5
Entered-date: 17. November 1995
Version: 0.6
Entered-date: 25. November 1995
Description: With ncpfs you can mount volumes of your novell
server under Linux.
Keywords: filesystem kernel ncp novell netware
Author: lendecke@namu01.gwdg.de (Volker Lendecke)
Maintained-by: lendecke@namu01.gwdg.de (Volker Lendecke)
Primary-site: linux01.gwdg.de:/pub/ncpfs
~50k ncpfs-0.5.tgz
~ 1k ncpfs-0.5.lsm
~59k ncpfs-0.6.tgz
~ 1k ncpfs-0.6.lsm
Copying-policy: GPL
End

46
util/Makefile Normal file
View File

@@ -0,0 +1,46 @@
#
# Makefile for the linux ncp-filesystem routines.
#
INCLUDES = -I/usr/src/linux/include -I../kernel
BINDIR = ../bin
UTILS = ncpmount ncpumount ncptest ipx_configure
CFLAGS = -Wall $(INCLUDES) -g
CC = gcc
all: $(UTILS)
ncpmount: ncpmount.o ncplib_user.o nwcrypt.o
$(CC) -o ncpmount ncpmount.o ncplib_user.o nwcrypt.o
cp ncpmount $(BINDIR)
ncpumount: ncpumount.o ncplib_user.o nwcrypt.o
$(CC) -o ncpumount ncpumount.o ncplib_user.o nwcrypt.o
cp ncpumount $(BINDIR)
ipx_configure: ipx_configure.c
$(CC) $(CFLAGS) ipx_configure.c -o ipx_configure
cp ipx_configure $(BINDIR)
ncptest: ncptest.o ncplib_user.o nwcrypt.o
$(CC) -o ncptest ncptest.o ncplib_user.o nwcrypt.o
nwcrypt.o: nwcrypt.c
$(CC) -c -O3 -Wall nwcrypt.c
dep:
$(CPP) -M $(INCLUDES) *.c > .depend
clean:
rm -f *.o *~
realclean: clean
rm -f $(UTILS) .depend $(DISTFILE)
#
# include a dependency file if one exists
#
ifeq (.depend,$(wildcard .depend))
include .depend
endif

125
util/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);
}

View File

@@ -27,10 +27,29 @@
#include <string.h>
#include <linux/ipx.h>
#define IPX_RIP_PTYPE (0x01)
#define IPX_SAP_PTYPE (0x04)
#define IPX_SAP_PORT (0x0452)
#define IPX_RIP_PORT (0x0453)
#define IPX_SAP_FILE_SERVER (0x004)
#define IPX_SAP_GENERAL_QUERY (0x0001)
#define IPX_SAP_GENERAL_RESPONSE (0x0002)
#define IPX_SAP_NEAREST_QUERY (0x0003)
#define IPX_SAP_NEAREST_RESPONSE (0x0004)
#define IPX_SAP_FILE_SERVER (0x0004)
#define IPX_RIP_REQUEST (0x1)
#define IPX_RIP_RESPONSE (0x2)
struct ipx_rip_packet {
__u16 operation __attribute__ ((packed));
struct ipx_rt_def {
__u32 network __attribute__ ((packed));
__u16 hops __attribute__ ((packed));
__u16 ticks __attribute__ ((packed));
} rt[1] __attribute__ ((packed));
};
#define IPX_BROADCAST_NODE "\xff\xff\xff\xff\xff\xff"
#define IPX_THIS_NODE "\0\0\0\0\0\0"

View File

@@ -6,9 +6,17 @@ typedef __u16 word;
typedef __u32 dword;
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include "ipxutil.h"
#define ncp_printf printf
@@ -38,10 +46,10 @@ ncp_unlock_server(struct ncp_server *server)
}
static int
ncp_request(struct ncp_server *server, int function) {
ncp_ioctl_request(struct ncp_server *server, int function) {
struct ncp_reply_header *reply
= (struct ncp_reply_header *)(server->packet);
= (struct ncp_reply_header *)(server->ncp_data);
struct ncp_ioctl_request request;
int result;
@@ -53,7 +61,7 @@ ncp_request(struct ncp_server *server, int function) {
request.function = function;
request.size = server->current_size;
request.data = server->packet;
request.data = server->ncp_data;
if ((result = ioctl(server->mount_fid, NCP_IOC_NCPREQUEST,
&request)) < 0) {
@@ -70,6 +78,347 @@ ncp_request(struct ncp_server *server, int function) {
return result;
}
static int
do_ncp_call(struct ncp_server *server, int request_size)
{
struct ncp_request_header request =
*((struct ncp_request_header *)(&(server->ncp_data)));
fd_set rd, wr, ex;
struct timeval tv;
int result;
int retries = 3;
while (retries > 0) {
retries -= 1;
result = sendto(server->ncp_sock, server->ncp_data,
request_size,
0, (struct sockaddr *)&(server->addr),
sizeof(server->addr));
if (result < 0) {
return result;
}
re_select:
FD_ZERO(&rd); FD_ZERO(&wr); FD_ZERO(&ex);
FD_SET(server->ncp_sock, &rd);
tv.tv_sec = 3;
tv.tv_usec = 0;
if (select(server->ncp_sock+1, &rd, &wr, &ex, &tv) == -1) {
perror("select");
return -1;
}
if (FD_ISSET(server->ncp_sock, &rd)) {
int len = recv(server->ncp_sock,
server->ncp_data, NCP_PACKET_SIZE,
0);
struct ncp_reply_header *r =
(struct ncp_reply_header *)&(server->ncp_data);
if ( (len == sizeof(*r))
&& (r->type == NCP_POSITIVE_ACK)) {
goto re_select;
}
if ( (len >= sizeof(*r))
&& (r->type == NCP_REPLY)
&& ( (request.type == NCP_ALLOC_SLOT_REQUEST)
|| ( (r->sequence == request.sequence)
&& (r->conn_low == request.conn_low)
&& (r->conn_high == request.conn_high)))) {
server->reply_size = len;
break;
}
}
}
return 0;
}
static int
ncp_user_request(struct ncp_server *server, int function)
{
struct ncp_request_header *h =
(struct ncp_request_header *)&(server->ncp_data);
struct ncp_reply_header *r =
(struct ncp_reply_header *)&(server->ncp_data);
int result;
assert_server_locked(server);
if (server->has_subfunction != 0) {
*(__u16 *)(server->packet) = server->current_size - 2;
}
h->type = NCP_REQUEST;
server->sequence += 1;
h->sequence = server->sequence;
h->conn_low = (server->connection) & 0xff;
h->conn_high = ((server->connection) & 0xff00) >> 8;
h->task = 1;
h->function = function;
if (do_ncp_call(server, server->current_size + sizeof(*h)) != 0) {
return -1;
}
server->completion = r->completion_code;
server->conn_status = r->connection_state;
server->ncp_reply_size =
server->reply_size - sizeof(struct ncp_reply_header);
result = r->completion_code;
if (result != 0) {
ncp_printf("ncp_completion_code: %d\n", result);
}
return result;
}
int
install_wdog(struct ncp_server *server)
{
int parent_pid = getpid();
int pid;
int sock = server->wdog_sock;
fd_set rd, wr, ex;
struct timeval tv;
char buf[1024];
struct sockaddr_ipx sender;
int sizeofaddr = sizeof(struct sockaddr_ipx);
int pktsize;
if ((pid = fork()) < 0) {
return -1;
}
if (pid != 0) {
/* Parent, should go on as usual */
server->wdog_pid = pid;
return 0;
}
while (1) {
FD_ZERO(&rd); FD_ZERO(&wr); FD_ZERO(&ex);
FD_SET(sock, &rd);
/* every 120 seconds we look if our parent is
still alive */
tv.tv_sec = 120;
tv.tv_usec = 0;
if (select(sock+1, &rd, &wr, &ex, &tv) == -1) {
continue;
}
if (getppid() != parent_pid) {
/* our parent has died, so nothing to do
anymore */
exit(0);
}
if (FD_ISSET(sock, &rd)) {
pktsize = recvfrom(sock, buf, sizeof(buf), 0,
(struct sockaddr *)&sender,
&sizeofaddr);
if (pktsize < 0) {
perror("recvfrom");
continue;
}
if ( (pktsize != 2)
|| (buf[1] != '?')) {
continue;
}
buf[1] = 'Y';
pktsize = sendto(sock, buf, 2, 0,
(struct sockaddr *)&sender,
sizeof(sender));
if (pktsize < 0) {
perror("send");
}
}
}
}
int
ncp_connect(struct ncp_server *server)
{
struct ncp_request_header *h =
(struct ncp_request_header *)&(server->ncp_data);
struct sockaddr_ipx addr;
int len = sizeof(struct sockaddr_ipx);
int ncp_sock, wdog_sock;
int ncp_port, wdog_port;
server->is_connected = NOT_CONNECTED;
ncp_sock = socket(AF_IPX, SOCK_DGRAM, PF_IPX);
if (ncp_sock == -1) {
perror("open ncp socket");
return -1;
}
wdog_sock = socket(AF_IPX, SOCK_DGRAM, PF_IPX);
if (wdog_sock == -1) {
perror("open wdog socket");
close(ncp_sock);
return -1;
}
addr.sipx_family = AF_IPX;
addr.sipx_network = htonl(0x0);
ipx_assign_node(addr.sipx_node, IPX_THIS_NODE);
addr.sipx_port = htons(0x0);
addr.sipx_type = NCP_PTYPE;
if (bind(ncp_sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
perror("bind ncp socket");
close(ncp_sock); close(wdog_sock);
return -1;
}
if (bind(wdog_sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
perror("bind wdog socket");
close(ncp_sock); close(wdog_sock);
return -1;
}
if ( (getsockname(ncp_sock, (struct sockaddr *)&addr, &len) != 0)
|| (len != sizeof(struct sockaddr_ipx))) {
perror("getsockname ncp socket");
close(ncp_sock); close(wdog_sock);
return -1;
}
ncp_port = ntohs(addr.sipx_port);
if ( (getsockname(wdog_sock, (struct sockaddr *)&addr, &len) != 0)
|| (len != sizeof(struct sockaddr_ipx))) {
perror("getsockname wdog socket");
close(wdog_sock); close(wdog_sock);
return -1;
}
wdog_port = ntohs(addr.sipx_port);
if (wdog_port != ncp_port+1) {
fprintf(stderr, "did not alloc 2 consecutive ports\n");
close(ncp_sock); close(wdog_sock);
return -1;
}
server->ncp_sock = ncp_sock;
server->wdog_sock = wdog_sock;
h->type = NCP_ALLOC_SLOT_REQUEST;
server->sequence = 0;
h->sequence = server->sequence;
h->conn_low = 0xff;
h->conn_high = 0xff;
h->task = 1;
h->function = 0;
if (do_ncp_call(server, sizeof(*h)) != 0) {
int saved_errno = errno;
close(ncp_sock); close(wdog_sock);
errno = saved_errno;
return -1;
}
install_wdog(server);
server->sequence = 0;
server->connection = h->conn_low + (h->conn_high * 256);
server->is_connected = CONN_SOCKET;
return 0;
}
static int
ncp_user_disconnect(struct ncp_server *server)
{
struct ncp_request_header *h
= (struct ncp_request_header *)(server->ncp_data);
int result;
h->type = NCP_DEALLOC_SLOT_REQUEST;
server->sequence += 1;
h->sequence = server->sequence;
h->conn_low = (server->connection) & 0xff;
h->conn_high = ((server->connection) & 0xff00) >> 8;
h->task = 1;
h->function = 0;
if ((result = do_ncp_call(server, sizeof(*h))) != 0) {
return result;
}
close(server->ncp_sock);
close(server->wdog_sock);
kill(server->wdog_pid, SIGTERM);
wait(NULL);
return 0;
}
int
ncp_disconnect(struct ncp_server *server)
{
int result = -1;
switch (server->is_connected) {
case CONN_MOUNTED:
result = close(server->mount_fid);
case CONN_SOCKET:
result = ncp_user_disconnect(server);
default:
}
if (result >= 0) {
server->is_connected = NOT_CONNECTED;
}
return result;
}
int
ncp_connect_mount(struct ncp_server *server, const char *mount_point)
{
server->mount_fid = open(mount_point, O_RDONLY, 0);
if (server->mount_fid == -1) {
return -1;
}
server->is_connected = CONN_MOUNTED;
return 0;
}
static int
ncp_request(struct ncp_server *server, int function)
{
switch (server->is_connected) {
case CONN_MOUNTED:
return ncp_ioctl_request(server, function);
case CONN_SOCKET:
return ncp_user_request(server, function);
default:
}
return -ENOTCONN;
}
static inline int
min(int a, int b) {
if (a<b)
@@ -142,7 +491,8 @@ ncp_init_request(struct ncp_server *server)
ncp_lock_server(server);
server->current_size = 0;
server->packet = server->ncp_data;
server->packet =
&(server->ncp_data[sizeof(struct ncp_request_header)]);
server->has_subfunction = 0;
}
@@ -160,7 +510,7 @@ ncp_init_request_s(struct ncp_server *server, int subfunction)
static char *
ncp_reply_data(struct ncp_server *server, int offset)
{
return &(server->packet[sizeof(struct ncp_reply_header) + offset]);
return &(server->ncp_data[sizeof(struct ncp_reply_header) + offset]);
}
static byte
@@ -813,6 +1163,36 @@ 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)

View File

@@ -4,21 +4,50 @@
#include <linux/types.h>
#include <linux/ncp.h>
#include <linux/ncp_fs.h>
#include <linux/ipx.h>
enum connect_state {
NOT_CONNECTED = 0,
CONN_MOUNTED,
CONN_SOCKET
};
struct ncp_server {
int current_size;
int has_subfunction;
int mount_fid;
int silent;
int ncp_reply_size;
char *packet;
int lock;
enum connect_state is_connected;
int mount_fid;
struct sockaddr_ipx addr;
int ncp_sock;
int wdog_sock;
int wdog_pid;
__u8 sequence;
__u16 connection;
int completion;
int conn_status;
int reply_size;
char ncp_data[NCP_PACKET_SIZE];
};
#include <linux/ncp.h>
int
ncp_connect_mount(struct ncp_server *server, const char *mount_point);
int
ncp_connect(struct ncp_server *server);
int
ncp_disconnect(struct ncp_server *server);
int
ncp_negotiate_buffersize(struct ncp_server *server, int size,
int *target);
@@ -128,10 +157,17 @@ 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);
int
ncp_open_create_file_or_subdir(struct ncp_server *server,
struct nw_info_struct *dir, char *name,

View File

@@ -28,6 +28,8 @@ extern pid_t waitpid(pid_t, int *, int);
#include <sys/mount.h>
#include <mntent.h>
#include <linux/ipx.h>
#include <linux/route.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <linux/ncp.h>
@@ -148,6 +150,134 @@ ipx_print_saddr(struct sockaddr_ipx* sipx)
ipx_fprint_saddr(stdout,sipx);
}
static int
ipx_make_reachable(__u32 network)
{
struct rtentry rt_def;
/* Router */
struct sockaddr_ipx *sr = (struct sockaddr_ipx *)&rt_def.rt_gateway;
/* Target */
struct sockaddr_ipx *st = (struct sockaddr_ipx *)&rt_def.rt_dst;
fd_set rd, wr, ex;
struct timeval tv;
struct ipx_rip_packet rip;
struct sockaddr_ipx addr;
int addrlen;
int sock;
int opt;
int res=-1;
int i;
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(&addr, 0, sizeof(addr));
addr.sipx_family=AF_IPX;
addr.sipx_network=htonl(0x0);
addr.sipx_port=htons(0x0);
addr.sipx_type=IPX_RIP_PTYPE;
if(bind(sock,(struct sockaddr*)&addr,sizeof(addr))==-1)
{
perror("bind");
goto finished;
}
addr.sipx_family = AF_IPX;
addr.sipx_network = htonl(0x0);
addr.sipx_port = htons(IPX_RIP_PORT);
addr.sipx_type = IPX_RIP_PTYPE;
ipx_assign_node(addr.sipx_node, IPX_BROADCAST_NODE);
rip.operation = htons(IPX_RIP_REQUEST);
rip.rt[0].network = htonl(network);
if (sendto(sock, &rip, sizeof(rip), 0,
(struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("sendto");
goto finished;
}
do
{
FD_ZERO(&rd); FD_ZERO(&wr); FD_ZERO(&ex);
FD_SET(sock, &rd);
tv.tv_sec = 3;
tv.tv_usec = 0;
if (select(sock+1, &rd, &wr, &ex, &tv) == -1)
{
goto finished;
}
if (FD_ISSET(sock, &rd))
{
int len;
addrlen = sizeof(struct sockaddr_ipx);
len = recvfrom(sock, &rip, sizeof(rip), 0,
(struct sockaddr *)sr, &addrlen);
if (len < sizeof(rip))
{
continue;
}
}
else
{
goto finished;
}
} while (ntohs(rip.operation) != IPX_RIP_RESPONSE);
if (rip.rt[0].network != htonl(network)) {
goto finished;
}
rt_def.rt_flags = RTF_GATEWAY;
st->sipx_network = htonl(network);
sr->sipx_family = st->sipx_family = AF_IPX;
i = 0;
do {
res = ioctl(sock, SIOCADDRT, &rt_def);
i++;
} while ((i < 5) && (res < 0) && (errno == EAGAIN));
if (res != 0) {
switch (errno) {
case ENETUNREACH:
fprintf(stderr,
"%s: Router network (%08lX) not reachable.\n",
progname, htonl(sr->sipx_network));
break;
default:
perror("ioctl");
break;
}
goto finished;
}
finished:
close(sock);
return res;
}
int
ipx_sap_find_server(char *name, int server_type, int timeout,
struct sockaddr_ipx *result)
@@ -160,16 +290,26 @@ ipx_sap_find_server(char *name, int server_type, int timeout,
int name_len = strlen(name);
fd_set rd, wr, ex;
struct timeval tv;
int packets;
struct sap_server_ident *ident;
struct ncp_server server;
struct nw_property prop;
struct net_address
{
__u32 network __attribute__ ((packed));
__u8 node[6] __attribute__ ((packed));
__u16 port __attribute__ ((packed));
} *n_addr = (struct net_address *)&prop;
if (name_len > 48) {
return -1;
}
return -1;
}
sock=socket(AF_IPX,SOCK_DGRAM,PF_IPX);
if (sock==-1) {
return -1;
}
return -1;
}
opt=1;
/* Permit broadcast output */
@@ -191,7 +331,7 @@ ipx_sap_find_server(char *name, int server_type, int timeout,
goto finished;
}
*(unsigned short *)data = htons(0x0001);
*(unsigned short *)data = htons(IPX_SAP_NEAREST_QUERY);
*(unsigned short *)&(data[2]) = htons(server_type);
memset(&ipxs, 0, sizeof(ipxs));
@@ -202,58 +342,83 @@ ipx_sap_find_server(char *name, int server_type, int timeout,
ipxs.sipx_type=IPX_SAP_PTYPE;
if (sendto(sock, data, 4, 0,
(struct sockaddr *)&ipxs, sizeof(ipxs)) < 0) {
(struct sockaddr *)&ipxs, sizeof(ipxs)) < 0)
{
perror("sendto");
goto finished;
}
packets = 10;
while (packets > 0) {
do
{
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");
if (select(sock+1, &rd, &wr, &ex, &tv) == -1)
{
goto finished;
}
if (FD_ISSET(sock, &rd)) {
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;
}
if (len < 96)
{
continue;
}
}
else
{
printf("nobody answered, server %s not found\n",
name);
exit(1);
goto finished;
}
} while (ntohs(*((__u16 *)data)) != IPX_SAP_NEAREST_RESPONSE);
ident = (struct sap_server_ident *)(data+2);
/* If the server we got back is the correct one, we normally
would not need to ask for the NET_ADDRESS property. But we
try to connect anyway to check whether there's a valid
route to the server's internal network. Because this one
request is not very expensive, we always do it. */
server.addr.sipx_family = AF_IPX;
server.addr.sipx_network = ident->server_network;
server.addr.sipx_port = ident->server_port;
ipx_assign_node(server.addr.sipx_node, ident->server_node);
if (ncp_connect(&server) != 0)
{
if ( (errno != ENETUNREACH)
|| (ipx_make_reachable(ntohl(server.addr.sipx_network))!=0)
|| (ncp_connect(&server) != 0)) {
goto finished;
}
}
if (ncp_read_property_value(&server, NCP_BINDERY_FSERVER,
name, 1, "NET_ADDRESS",
&prop) != 0)
{
ncp_disconnect(&server);
goto finished;
}
if (ncp_disconnect(&server) != 0)
{
goto finished;
}
result->sipx_family = AF_IPX;
result->sipx_network = n_addr->network;
result->sipx_port = n_addr->port;
ipx_assign_node(result->sipx_node, n_addr->node);
res = 0;
finished:
close(sock);
return res;
@@ -455,6 +620,7 @@ main(int argc, char *argv[])
struct stat st;
struct ncp_server serv;
struct ncp_server *server = &serv;
char mount_name[256];
int fd;
int Got_Password;
@@ -536,8 +702,12 @@ main(int argc, char *argv[])
addr.sipx_type = NCP_PTYPE;
if (bind(ncp_sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
fprintf(stderr, "bind(ncp_sock, ): %s\n",
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);
}
@@ -626,23 +796,19 @@ main(int argc, char *argv[])
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) {
if (ncp_connect_mount(server, mount_point) != 0) {
fprintf(stderr, "Could not open %s: %s\n",
mount_point, strerror(errno));
umount(mount_point);
return -1;
}
server->silent = 1;
if (ncp_login_user(server, data.username, data.password) != 0) {
fprintf(stderr, "login failed\n");
@@ -654,7 +820,11 @@ main(int argc, char *argv[])
return -1;
}
ment.mnt_fsname = server_name;
strcpy(mount_name, server_name);
strcat(mount_name, "/");
strcat(mount_name, data.username);
ment.mnt_fsname = mount_name;
ment.mnt_dir = mount_point;
ment.mnt_type = "ncpfs";
ment.mnt_opts = "rw";

View File

@@ -39,7 +39,222 @@ extern pid_t waitpid(pid_t, int *, int);
#include "ipxutil.h"
static char *progname;
static char *mount_point;
static void
str_upper(char *name)
{
while (*name) {
*name = toupper(*name);
name = name + 1;
}
}
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;
char name[strlen(_name)+1];
int name_len = strlen(_name);
fd_set rd, wr, ex;
struct timeval tv;
int packets;
if (name_len > 48) {
return -1;
}
strcpy(name, _name);
str_upper(name);
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;
}
void
test_filesearch(struct ncp_server *server)
@@ -178,6 +393,43 @@ test_trunc(struct ncp_server *server)
return;
}
void
test_touch(struct ncp_server *server)
{
struct nw_info_struct sys;
struct nw_info_struct me;
struct nw_info_struct blub;
int info_mask;
struct nw_modify_dos_info info;
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) != 0) {
printf("lookup error\n");
return;
}
info_mask = 0;
memset(&info, 0, sizeof(info));
info_mask |= DM_MODIFY_DATE;
info_mask |= DM_MODIFY_TIME;
if (ncp_modify_file_or_subdir_dos_info(server, &blub, info_mask,
&info) != 0) {
printf("modify error\n");
return;
}
return;
}
void
test_ls(struct ncp_server *server)
{
@@ -351,57 +603,37 @@ test_print(struct ncp_server *server)
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 (argc != 2) {
printf("usage: %s server\n", argv[0]);
exit(1);
}
if (ipx_sap_find_server(argv[1], IPX_SAP_FILE_SERVER,
3, &(serv.addr)) != 0) {
printf("could not find server %s\n", argv[1]);
exit(1);
}
if (ncp_connect(server) != 0) {
printf("could not connect\n");
exit(1);
}
if (ncp_login_user(server, "me", "ME") != 0) {
printf("login error\n");
exit(1);
}
test_touch(server);
ncp_disconnect(server);
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;
}

197
util/ncpumount.c Normal file
View File

@@ -0,0 +1,197 @@
/*
* ncpumount.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:
*/