Import ncpfs 0.6
This commit is contained in:
BIN
.downloads/ncpfs-0.6.tgz
Normal file
BIN
.downloads/ncpfs-0.6.tgz
Normal file
Binary file not shown.
14
BUGS
14
BUGS
@@ -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.
|
||||
|
||||
71
Makefile
71
Makefile
@@ -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
32
README
@@ -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
|
||||
|
||||
@@ -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;
|
||||
@@ -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
67
kernel-1.3/src/Makefile
Normal 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
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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, '*');
|
||||
@@ -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);
|
||||
42
man/ipx_configure.8
Normal file
42
man/ipx_configure.8
Normal 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
190
man/ncpmount.8
Normal 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
28
man/ncpumount.8
Normal 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)
|
||||
@@ -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
46
util/Makefile
Normal 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
125
util/ipx_configure.c
Normal 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);
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
@@ -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)
|
||||
@@ -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,
|
||||
@@ -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 *)∝
|
||||
|
||||
|
||||
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";
|
||||
@@ -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
197
util/ncpumount.c
Normal 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:
|
||||
*/
|
||||
Reference in New Issue
Block a user