Compare commits

..

6 Commits
v0.1 ... v0.7

Author SHA1 Message Date
ncpfs archive import
f2bcb2c71e Import ncpfs 0.7 2026-04-28 20:39:57 +02:00
ncpfs archive import
e05e55a64a Import ncpfs 0.6 2026-04-28 20:39:57 +02:00
ncpfs archive import
eb9c79840a Import ncpfs 0.5 2026-04-28 20:39:57 +02:00
ncpfs archive import
8fa4442004 Import ncpfs 0.4 2026-04-28 20:39:57 +02:00
ncpfs archive import
aaa3c6e7cc Import ncpfs 0.3 2026-04-28 20:39:57 +02:00
ncpfs archive import
f6e0a67e78 Import ncpfs 0.2 2026-04-28 20:39:57 +02:00
58 changed files with 9550 additions and 1765 deletions

BIN
.downloads/ncpfs-0.2.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.3.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.4.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.5.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.6.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.7.tgz Normal file

Binary file not shown.

19
BUGS Normal file
View File

@@ -0,0 +1,19 @@
Maybe you want to look at LIMITATIONS in README. Some might consider
them to be bugs.
But there are really problems that might be fixed in the future.
'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,67 +2,43 @@
# Makefile for the linux ncp-filesystem routines.
#
INCLUDES = -I/usr/src/linux/include
KERNEL = 1.2
CFLAGS = -Wall -Wstrict-prototypes -O2 -DMODULE -fomit-frame-pointer \
$(INCLUDES) \
# -DDEBUG_NCP=1 -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= inode.o dir.o file.o sock.o ioctl.o ncplib.o nwcrypt.o
all: ncpfs.o ncpmount
ncpfs.o: $(OBJS)
$(LD) -r -o ncpfs.o $(OBJS)
ncpmount: ncpmount.o
gcc -o ncpmount ncpmount.o
ncpmount.o: ncpmount.c
gcc -c ncpmount.c -Wall -I. -g
ncplib_user.o: ncplib.o
gcc -c ncplib.c -Wall -I. -g -o ncplib_user.o
nwcrypt.o: nwcrypt.c
gcc -c -O2 -Wall nwcrypt.c
ncpumount: ncpumount.o
gcc -o ncpumount ncpumount.o
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 -fr ncpmount ncpumount .depend $(DISTFILE) mnt
rm -fr bin/* ncpfs.tgz
make -C util realclean
modules: ncpfs.o
SRCPATH=$(shell pwd)
SRCDIR=$(shell basename $(SRCPATH))
DISTFILE=$(SRCDIR).tgz
BACKUPFILE=ncpfs01.tgz
HOME=/home/me
backup:
(rm -f $(DISTFILE); cd ..; tar cvf - $(SRCDIR) | gzip -1 \
> $(HOME)/tarz/backup/$(BACKUPFILE))
(cd $(HOME)/tarz/backup; ls -l $(BACKUPFILE); mcopy $(BACKUPFILE) a:)
dist: realclean
(cd ..; \

151
README
View File

@@ -1,90 +1,73 @@
This is version 0.1 of ncpfs, a free NetWare client for Linux. For me
it works with 1.3.32 and 1.3.35.
This is version 0.7 of ncpfs, a free NetWare client filesystem for
Linux. This one currently works with Kernel 1.2.13. I do not know
whether it works with any other kernel of the 1.2.x series, I only
used it with 1.2.13.
I know that this piece of software is VERY incomplete, as it only
gives you read-only access. 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.
Due to problems in the 1.3.x IPX kernel code, ncpfs-0.7 does NOT work
with any 1.3.x kernel up to 1.3.44, although there is a kernel-1.3
subdirectory. It compiles fine and seems to work, but any connection
will block after a very short time. Please be patient. I'm sure this
will be solved. If you follow the kernel development closely, you
might want to try ncpfs with a kernel later than 1.3.44, but I can not
promise anything. To try it with 1.3, simply change the variable
KERNEL in the Makefile from 1.2 to 1.3 and continue as usual.
To install ncpfs, just type 'make', 'insmod ncpfs.o' and
'ncpmount server mount-point user password'. Please note that your IPX
system has to be configured correctly. There has to be a route to the
internal network of your server. I use tools from the dosemu-0.60.3
distribution to do this. Once again I have to apologize for this
cryptic description, but before I'm sure that I'm allowed to do all
this I will not do more.
I read that Novell is not very open when it comes to technical details
of the Netware Core Protocol. This might be especially true for the
encryption stuff. I took the necessary code from Dr. Dobb's Journal
11/93, Undocumented Corner. I asked Jon Erickson <jon@ddj.com> about
the legal status of this piece of code:
---
Date: Thu, 12 Oct 1995 13:44:18 +0100
From: Volker Lendecke <lendecke>
To: jon@ddj.com
Subject: legal status of your source code?
Hello!
I hope that you're the right one to write to, you are the first on your WWW
server. If you are not, could you please forward this message to the right
person? Thanks.
I'm currently exploring the possibility to write a free (in the GNU GPL
sense) NCP filesystem, which would allow me to access a novell server
transparently. For that I would like to use the encryption functions you
published in DDJ 11/93, Undocumented Corner. I would make some cosmetic
changes, such as other indentations, minor code changes and so on. But I do
not know if that allows me to publish this code under GPL. One alternative
would be to publish a diff against your listing, but that would probably
contain much of your code as well, and it would be very inconvenient for
the average user.
I think that you have some kind of standard procedure for such a
case. Please tell me what I should do.
Many thanks in advance,
Volker
+=================================================================+
! Volker Lendecke Internet: lendecke@namu01.gwdg.de !
! D-37081 Goettingen, Germany !
+=================================================================+
--
I got the following answer:
---
From: Jon Erickson <jon@ddj.com>
X-Mailer: SCO System V Mail (version 3.2)
To: lendecke@namu01.gwdg.de
Subject: Re: legal status of your source code?
Date: Thu, 12 Oct 95 5:42:56 PDT
Volker,
Code from Dr. Dobb's Journal related articles is provided for
anyone to use. Clearly, the author of the article should be
given credit.
Jon Erickson
---
With this answer in mind, I took the code and made it a bit more
C-like. The original seemed to be translated by a mechanical pascal->c
translator. Jon's answer encouraged me to publish nwcrypt.c under the
GPL. If anybody who knows more about copyright and sees any problems
with this, please tell me.
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.
Please note that your IPX system has to be configured correctly. If
you want to take the 'Plug-and-Play' route, you can simply say
'ipx_configure --auto_interface=on --auto_primary=on'. If ncpmount
does not work immediately, you should wait for about 1 minute and try
again. In that period, an IPX packet should have passed by and your
network interface should have configured itself automatically.
If all that does not work and you want to do the configuration by
hand, note that there has to be a route to the internal network of
your server. Please see the file util/start_ipx for an example.
I use tools written by Greg Page, Caldera. I hope I did not do too
much harm to their business. For your convenience I included the file
ipx.tar made available by Caldera.
My main source of information is a book written in german by Manfred
Hill and Ralf Zessin, "Netzwerkprogrammierung in C", IWT Verlag GmbH,
1995, ISBN 3-88322-491-X. It contains quite a lot of typographical and
other errors, but I find it very valuable as an introduction to NCP
programming. If you know about the concepts and possibilities of NCP,
Ralph Brown's interrupt list becomes much more readable. It's much
easier to find undocumented information if you know what to look for!
For the curious: the file ncplib_user.[ch] is a library that makes it
possible to send NCP requests to the server over a mounted
directory. I use it to keep the encryption stuff out of the kernel by
logging in from user space. Look at the file ncptest.c for other
possible uses. I use ncptest to check my assumptions about the widely
undocumented NetWare Core Protocol. Maybe this is the beginning of a
free NetWare API for Linux! I would be happy to receive your comments
on this.
LIMITATIONS (compare these with smbfs :-)
The limitations ncpfs has are the natural limitations of the NCP
protocol, which was designed with MS-DOS based PCs in mind. The first
limitation is the lack of uid, gid and permission information per
file. You have to assign those values once for a complete mounted
directory.
The second limitation is just as annoying as the first: You cannot
re-export a ncp-mounted directory by nfs. It is not possible because
the NFS protocol defines access to files through unique file handles,
which can be mapped to the device and inode numbers in unix NFS
servers. NCP does not have unique numbers per file, you only have the
path name. I implemented a caching scheme for inode numbers, which
gives unique inode numbers for every open file in the system. This is
just sufficient for local use of the files, because you can tell when
an inode number can be discarded. With NFS the situation is
different. You can never know when the client will access the file-id
you offered, so you would have to cache the inode numbers
indefinitely long. I think this should not be done in kernel mode, as
it would require an unlimited amount of RAM.

282
kernel-1.2/linux/ncp.h Normal file
View File

@@ -0,0 +1,282 @@
/*
* ncp_fs.h
*
* Copyright (C) 1995 by Volker Lendecke
*
*/
#ifndef _LINUX_NCP_H
#define _LINUX_NCP_H
#include <linux/types.h>
#define NCP_PTYPE (0x11)
#define NCP_PORT (0x0451)
#define NCP_ALLOC_SLOT_REQUEST (0x1111)
#define NCP_REQUEST (0x2222)
#define NCP_DEALLOC_SLOT_REQUEST (0x5555)
struct ncp_request_header {
__u16 type __attribute__ ((packed));
__u8 sequence __attribute__ ((packed));
__u8 conn_low __attribute__ ((packed));
__u8 task __attribute__ ((packed));
__u8 conn_high __attribute__ ((packed));
__u8 function __attribute__ ((packed));
__u8 data[0] __attribute__ ((packed));
};
#define NCP_REPLY (0x3333)
#define NCP_POSITIVE_ACK (0x9999)
struct ncp_reply_header {
__u16 type __attribute__ ((packed));
__u8 sequence __attribute__ ((packed));
__u8 conn_low __attribute__ ((packed));
__u8 task __attribute__ ((packed));
__u8 conn_high __attribute__ ((packed));
__u8 completion_code __attribute__ ((packed));
__u8 connection_state __attribute__ ((packed));
__u8 data[0] __attribute__ ((packed));
};
#define NCP_BINDERY_USER (0x0001)
#define NCP_BINDERY_UGROUP (0x0002)
#define NCP_BINDERY_PQUEUE (0x0003)
#define NCP_BINDERY_FSERVER (0x0004)
#define NCP_BINDERY_NAME_LEN (48)
struct ncp_bindery_object {
__u32 object_id;
__u16 object_type;
__u8 object_name[NCP_BINDERY_NAME_LEN];
};
struct nw_property {
__u8 value[128];
__u8 more_flag;
__u8 property_flag;
};
#define NCP_VOLNAME_LEN (16)
#define NCP_NUMBER_OF_VOLUMES (64)
struct ncp_volume_info {
__u32 total_blocks;
__u32 free_blocks;
__u32 purgeable_blocks;
__u32 not_yet_purgeable_blocks;
__u32 total_dir_entries;
__u32 available_dir_entries;
__u8 sectors_per_block;
char volume_name[NCP_VOLNAME_LEN+1];
};
struct ncp_filesearch_info {
__u8 volume_number;
__u16 directory_id;
__u16 sequence_no;
__u8 access_rights;
};
#define NCP_MAX_FILENAME 14
/* these define the attribute byte as seen by NCP */
#define aRONLY (1L<<0)
#define aHIDDEN (1L<<1)
#define aSYSTEM (1L<<2)
#define aEXECUTE (1L<<3)
#define aDIR (1L<<4)
#define aARCH (1L<<5)
#define AR_READ (0x01)
#define AR_WRITE (0x02)
#define AR_EXCLUSIVE (0x20)
#define NCP_FILE_ID_LEN 6
struct ncp_file_info {
__u8 file_id[NCP_FILE_ID_LEN];
char file_name[NCP_MAX_FILENAME+1];
__u8 file_attributes;
__u8 file_mode;
__u32 file_length;
__u16 creation_date;
__u16 access_date;
__u16 update_date;
__u16 update_time;
};
/* Defines for ReturnInformationMask */
#define RIM_NAME (0x0001L)
#define RIM_SPACE_ALLOCATED (0x0002L)
#define RIM_ATTRIBUTES (0x0004L)
#define RIM_DATA_SIZE (0x0008L)
#define RIM_TOTAL_SIZE (0x0010L)
#define RIM_EXT_ATTR_INFO (0x0020L)
#define RIM_ARCHIVE (0x0040L)
#define RIM_MODIFY (0x0080L)
#define RIM_CREATION (0x0100L)
#define RIM_OWNING_NAMESPACE (0x0200L)
#define RIM_DIRECTORY (0x0400L)
#define RIM_RIGHTS (0x0800L)
#define RIM_ALL (0x0FFFL)
#define RIM_COMPRESSED_INFO (0x80000000L)
/* open/create modes */
#define OC_MODE_OPEN 0x01
#define OC_MODE_TRUNCATE 0x02
#define OC_MODE_REPLACE 0x02
#define OC_MODE_CREATE 0x08
/* open/create results */
#define OC_ACTION_NONE 0x00
#define OC_ACTION_OPEN 0x01
#define OC_ACTION_CREATE 0x02
#define OC_ACTION_TRUNCATE 0x04
#define OC_ACTION_REPLACE 0x04
/* access rights attributes */
#ifndef AR_READ_ONLY
#define AR_READ_ONLY 0x0001
#define AR_WRITE_ONLY 0x0002
#define AR_DENY_READ 0x0004
#define AR_DENY_WRITE 0x0008
#define AR_COMPATIBILITY 0x0010
#define AR_WRITE_THROUGH 0x0040
#define AR_OPEN_COMPRESSED 0x0100
#endif
struct nw_info_struct
{
__u32 spaceAlloc __attribute__ ((packed));
__u32 attributes __attribute__ ((packed));
__u16 flags __attribute__ ((packed));
__u32 dataStreamSize __attribute__ ((packed));
__u32 totalStreamSize __attribute__ ((packed));
__u16 numberOfStreams __attribute__ ((packed));
__u16 creationTime __attribute__ ((packed));
__u16 creationDate __attribute__ ((packed));
__u32 creatorID __attribute__ ((packed));
__u16 modifyTime __attribute__ ((packed));
__u16 modifyDate __attribute__ ((packed));
__u32 modifierID __attribute__ ((packed));
__u16 lastAccessDate __attribute__ ((packed));
__u16 archiveTime __attribute__ ((packed));
__u16 archiveDate __attribute__ ((packed));
__u32 archiverID __attribute__ ((packed));
__u16 inheritedRightsMask __attribute__ ((packed));
__u32 dirEntNum __attribute__ ((packed));
__u32 DosDirNum __attribute__ ((packed));
__u32 volNumber __attribute__ ((packed));
__u32 EADataSize __attribute__ ((packed));
__u32 EAKeyCount __attribute__ ((packed));
__u32 EAKeySize __attribute__ ((packed));
__u32 NSCreator __attribute__ ((packed));
__u8 nameLen __attribute__ ((packed));
__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;
int access;
__u32 server_file_handle __attribute__ ((packed));
__u8 open_create_action __attribute__ ((packed));
__u8 file_handle[6] __attribute__ ((packed));
};
struct nw_search_sequence {
__u8 volNumber __attribute__ ((packed));
__u32 dirBase __attribute__ ((packed));
__u32 sequence __attribute__ ((packed));
};
struct nw_queue_job_entry {
__u16 InUse __attribute__ ((packed));
__u32 prev __attribute__ ((packed));
__u32 next __attribute__ ((packed));
__u32 ClientStation __attribute__ ((packed));
__u32 ClientTask __attribute__ ((packed));
__u32 ClientObjectID __attribute__ ((packed));
__u32 TargetServerID __attribute__ ((packed));
__u8 TargetExecTime[6] __attribute__ ((packed));
__u8 JobEntryTime[6] __attribute__ ((packed));
__u32 JobNumber __attribute__ ((packed));
__u16 JobType __attribute__ ((packed));
__u16 JobPosition __attribute__ ((packed));
__u16 JobControlFlags __attribute__ ((packed));
__u8 FileNameLen __attribute__ ((packed));
char JobFileName[13] __attribute__ ((packed));
__u32 JobFileHandle __attribute__ ((packed));
__u32 ServerStation __attribute__ ((packed));
__u32 ServerTaskNumber __attribute__ ((packed));
__u32 ServerObjectID __attribute__ ((packed));
char JobTextDescription[50] __attribute__ ((packed));
char ClientRecordArea[152] __attribute__ ((packed));
};
struct queue_job {
struct nw_queue_job_entry j;
__u8 file_handle[6];
};
#define QJE_OPER_HOLD 0x80
#define QJE_USER_HOLD 0x40
#define QJE_ENTRYOPEN 0x20
#define QJE_SERV_RESTART 0x10
#define QJE_SERV_AUTO 0x08
/* ClientRecordArea for print jobs */
struct print_job_record {
__u8 Version __attribute__ ((packed));
__u16 TabSize __attribute__ ((packed));
__u16 Copies __attribute__ ((packed));
__u8 CtrlFlags __attribute__ ((packed));
__u16 Lines __attribute__ ((packed));
__u16 Rows __attribute__ ((packed));
char FormName[16] __attribute__ ((packed));
__u8 Reserved[6] __attribute__ ((packed));
char Banner[13] __attribute__ ((packed));
char FnameBanner[13] __attribute__ ((packed));
char FnameHeader[14] __attribute__ ((packed));
char Path[80] __attribute__ ((packed));
};
#endif /* _LINUX_NCP_H */

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.
@@ -50,11 +51,12 @@ struct ncp_ioctl_request {
#define NCP_SUPER_MAGIC 0x564c
#define NCP_SBP(sb) ((struct ncp_server *)(sb->u.generic_sbp))
#define NCP_INOP(inode) ((struct ncp_inode_info *)(inode->u.generic_ip))
#define NCP_SBP(sb) ((struct ncp_server *)((sb)->u.generic_sbp))
#define NCP_INOP(inode) ((struct ncp_inode_info *)((inode)->u.generic_ip))
#define NCP_SERVER(inode) NCP_SBP(inode->i_sb)
#define NCP_SERVER(inode) NCP_SBP((inode)->i_sb)
#define NCP_FINFO(inode) (&(NCP_INOP(inode)->finfo))
#define NCP_ISTRUCT(inode) (&(NCP_FINFO(inode)->i))
static inline int min(int a, int b) {
return a<b ? a : b;
@@ -116,6 +118,9 @@ void ncp_init_dir_cache(void);
void ncp_invalid_dir_cache(unsigned long ino);
void ncp_invalidate_all_inodes(struct ncp_server *server);
void ncp_free_dir_cache(void);
int ncp_date_dos2unix(__u16 time, __u16 date);
void ncp_date_unix2dos(int unix_date, __u16 *time, __u16 *date);
/* linux/fs/ncpfs/ioctl.c */
int ncp_ioctl (struct inode * inode, struct file * filp,
@@ -124,7 +129,6 @@ int ncp_ioctl (struct inode * inode, struct file * filp,
/* linux/fs/ncpfs/inode.c */
struct super_block *ncp_read_super(struct super_block *sb,
void *raw_data, int silent);
int ncp_notify_change(struct inode *inode, struct iattr *attr);
void ncp_invalidate_connection(struct ncp_server *server);
int ncp_conn_is_valid(struct ncp_server *server);

View File

@@ -0,0 +1,35 @@
/*
* ncp_fs_i.h
*
* Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
*
*/
#ifndef _LINUX_NCP_FS_I
#define _LINUX_NCP_FS_I
#include <linux/ncp.h>
#ifdef __KERNEL__
enum ncp_inode_state {
INODE_VALID = 19, /* Inode currently in use */
INODE_LOOKED_UP, /* directly before iget */
INODE_CACHED, /* in a path to an inode which is in use */
INODE_INVALID
};
/*
* ncp fs inode data (in memory only)
*/
struct ncp_inode_info {
enum ncp_inode_state state;
int nused; /* for directories:
number of references in memory */
struct ncp_inode_info *dir;
struct ncp_inode_info *next, *prev;
struct nw_file_info finfo;
};
#endif
#endif

67
kernel-1.2/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=1 -DDEBUG_NCP_MALLOC
# -DDEBUG_NCP_MALLOC
CC = gcc -D__KERNEL__ -I.
AS = as
ARCH = i386
.c.s:
$(CC) $(CFLAGS) -S $<
.c.o:
$(CC) $(CFLAGS) -c $<
.s.o:
$(AS) -o $*.o $<
OBJS= dir.o inode.o file.o sock.o ioctl.o ncplib.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

965
kernel-1.2/src/dir.c Normal file
View File

@@ -0,0 +1,965 @@
/*
* dir.c
*
* Copyright (C) 1995 by Volker Lendecke
*
*/
#include <linux/config.h>
#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
#else
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
#endif
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/stat.h>
#include <linux/kernel.h>
#include <linux/malloc.h>
#include <linux/mm.h>
#include <linux/ncp_fs.h>
#include <asm/segment.h>
#include <linux/errno.h>
#include "ncplib.h"
struct ncp_dirent {
struct nw_info_struct i;
struct nw_search_sequence s; /* given back for i */
unsigned long f_pos;
};
static int
ncp_dir_read(struct inode *inode, struct file *filp, char *buf, int count);
static int
ncp_readdir(struct inode *inode, struct file *filp,
struct dirent *dirent, int count);
static int
ncp_read_volume_list(struct ncp_server *server, int start_with,
int cache_size);
static int
ncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos,
int cache_size, struct ncp_dirent *entry);
static struct inode *
ncp_iget(struct inode *dir, struct nw_file_info *finfo);
static struct ncp_inode_info *
ncp_find_inode(struct inode *dir, const char *name);
static int
ncp_lookup(struct inode *dir, const char *__name,
int len, struct inode **result);
static int
ncp_create(struct inode *dir, const char *name, int len, int mode,
struct inode **result);
static int
ncp_mkdir(struct inode *dir, const char *name, int len, int mode);
static int
ncp_rmdir(struct inode *dir, const char *name, int len);
static int
ncp_unlink(struct inode *dir, const char *name, int len);
static int
ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
struct inode *new_dir, const char *new_name, int new_len);
static inline void
str_upper(char *name)
{
while (*name) {
if (*name >= 'a' && *name <= 'z')
*name -= ('a' - 'A');
name++;
}
}
static inline void
str_lower(char *name)
{
while (*name) {
if (*name >= 'A' && *name <= 'Z')
*name += ('a' - 'A');
name ++;
}
}
static struct file_operations ncp_dir_operations = {
NULL, /* lseek - default */
ncp_dir_read, /* read - bad */
NULL, /* write - bad */
ncp_readdir, /* readdir */
NULL, /* select - default */
ncp_ioctl, /* ioctl - default */
NULL, /* mmap */
NULL, /* no special open code */
NULL, /* no special release code */
NULL /* fsync */
};
struct inode_operations ncp_dir_inode_operations = {
&ncp_dir_operations, /* default directory file ops */
ncp_create, /* create */
ncp_lookup, /* lookup */
NULL, /* link */
ncp_unlink, /* unlink */
NULL, /* symlink */
ncp_mkdir, /* mkdir */
ncp_rmdir, /* rmdir */
NULL, /* mknod */
ncp_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
NULL, /* truncate */
NULL, /* permission */
NULL /* smap */
};
static int
ncp_dir_read(struct inode *inode, struct file *filp, char *buf, int count)
{
return -EISDIR;
}
#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
#define ROUND_UP(x) (((x)+3) & ~3)
/* In ncpfs, we have unique inodes across all mounted filesystems, for
all inodes that are in memory. That's why it's enough to index the
directory cache by the inode number. */
static unsigned long c_ino = 0;
static int c_size;
static int c_seen_eof;
static int c_last_returned_index;
static struct ncp_dirent* c_entry = NULL;
static int
ncp_readdir(struct inode *inode, struct file *filp,
struct dirent *dirent, int count)
{
int result, i = 0;
int index = 0;
struct ncp_dirent *entry = NULL;
struct ncp_server *server = NCP_SERVER(inode);
struct ncp_inode_info *dir = (struct ncp_inode_info *)(inode->i_ino);
int filldir(struct dirent *dirent,
const char *name, int len,
int f_pos, ino_t ino)
{
memcpy_tofs(dirent->d_name, name, len);
put_fs_byte(0, &(dirent->d_name[len]));
put_fs_long(ino, &dirent->d_ino);
put_fs_word(len, &dirent->d_reclen);
put_fs_word(f_pos, &dirent->d_off);
return 1;
}
DDPRINTK("ncp_readdir: filp->f_pos = %d\n", (int)filp->f_pos);
DDPRINTK("ncp_readdir: inode->i_ino = %ld, c_ino = %ld\n",
inode->i_ino, c_ino);
if (!inode || !S_ISDIR(inode->i_mode)) {
printk("ncp_readdir: inode is NULL or not a directory\n");
return -EBADF;
}
if (c_entry == NULL)
{
i = sizeof (struct ncp_dirent) * NCP_READDIR_CACHE_SIZE;
c_entry = (struct ncp_dirent *) ncp_kmalloc(i, GFP_KERNEL);
if (c_entry == NULL) {
printk("ncp_readdir: no MEMORY for cache\n");
return -ENOMEM;
}
}
if (filp->f_pos == 0) {
ncp_invalid_dir_cache(inode->i_ino);
if (filldir(dirent,".",1, filp->f_pos, (int)dir) < 0) {
return 0;
}
filp->f_pos += 1;
return ROUND_UP(NAME_OFFSET(dirent)+i+1);
}
if (filp->f_pos == 1) {
if (filldir(dirent,"..",2, filp->f_pos, (int)(dir->dir)) < 0) {
return 0;
}
filp->f_pos += 1;
return ROUND_UP(NAME_OFFSET(dirent)+i+1);
}
if (inode->i_ino == c_ino) {
for (i = 0; i < c_size; i++) {
if (filp->f_pos == c_entry[i].f_pos) {
entry = &c_entry[i];
c_last_returned_index = i;
index = i;
break;
}
}
if ((entry == NULL) && c_seen_eof)
return 0;
}
if (entry == NULL) {
DPRINTK("ncp_readdir: Not found in cache.\n");
if (inode->i_ino == (int)&(server->root)) {
result = ncp_read_volume_list(server, filp->f_pos,
NCP_READDIR_CACHE_SIZE);
DPRINTK("ncp_read_volume_list returned %d\n", result);
} else {
result = ncp_do_readdir(server, inode, filp->f_pos,
NCP_READDIR_CACHE_SIZE,
c_entry);
DPRINTK("ncp_readdir returned %d\n", result);
}
if (result < 0) {
c_ino = 0;
return result;
}
if (result > 0) {
c_seen_eof = (result < NCP_READDIR_CACHE_SIZE);
c_ino = inode->i_ino;
c_size = result;
entry = c_entry;
c_last_returned_index = 0;
index = 0;
for (i = 0; i < c_size; i++) {
str_lower(c_entry[i].i.entryName);
}
}
}
if (entry == NULL) {
/* Nothing found, even from a ncp call */
return 0;
}
if (index < c_size) {
/* We found it. For getwd(), we have to return the
correct inode in d_ino if the inode is currently in
use. Otherwise the inode number does not
matter. (You can argue a lot about this..) */
struct ncp_inode_info *ino_info;
ino_info = ncp_find_inode(inode, entry->i.entryName);
/* Some programs seem to be confused about a zero
inode number, so we set it to one. Thanks to
Gordon Chaffee for this one. */
if (ino_info == NULL) {
ino_info = (struct ncp_inode_info *) 1;
}
DDPRINTK("ncp_readdir: entry->path= %s\n", entry->i.entryName);
DDPRINTK("ncp_readdir: entry->f_pos = %ld\n", entry->f_pos);
if (filldir(dirent, entry->i.entryName, entry->i.nameLen,
entry->f_pos, (ino_t)ino_info) < 0) {
return 0;
}
filp->f_pos += 1;
index += 1;
entry += 1;
return ROUND_UP(NAME_OFFSET(dirent)+i+1);
}
return 0;
}
static int
ncp_read_volume_list(struct ncp_server *server, int fpos, int cache_size)
{
struct ncp_dirent *entry = c_entry;
int total_count = 2;
int i;
#if 1
if (fpos < 2) {
printk("OOPS, we expect fpos >= 2");
fpos = 2;
}
#endif
for (i=0; i<NCP_NUMBER_OF_VOLUMES; i++) {
struct ncp_volume_info info;
if (ncp_get_volume_info_with_number(server, i, &info) != 0) {
return total_count;
}
if (strlen(info.volume_name) > 0) {
if (total_count < fpos) {
DPRINTK("ncp_read_volumes: skipped vol: %s\n",
info.volume_name);
} else if (total_count >= fpos + cache_size) {
return (total_count - fpos);
} else {
DPRINTK("ncp_read_volumes: found vol: %s\n",
info.volume_name);
if (ncp_do_lookup(server, NULL,
info.volume_name,
&(entry->i)) != 0) {
printk("ncpfs: could not lookup vol "
"%s\n", info.volume_name);
continue;
}
entry->f_pos = total_count;
entry += 1;
}
total_count += 1;
}
}
return (total_count - fpos);
}
static int
ncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos,
int cache_size, struct ncp_dirent *entry)
{
static struct nw_search_sequence seq;
static struct inode *last_dir;
static int total_count;
#if 1
if (fpos < 2) {
printk("OOPS, we expect fpos >= 2");
fpos = 2;
}
#endif
DPRINTK("ncp_do_readdir: fpos = %d\n", fpos);
if (fpos == 2) {
last_dir = NULL;
total_count = 2;
}
if ((fpos != total_count) || (dir != last_dir)) {
total_count = 2;
last_dir = dir;
DPRINTK("ncp_do_readdir: re-used seq for %s\n",
NCP_ISTRUCT(dir)->entryName);
if (ncp_initialize_search(server, NCP_ISTRUCT(dir), &seq)!=0) {
DPRINTK("ncp_init_search failed\n");
return total_count - fpos;
}
}
while (total_count < fpos + cache_size) {
if (ncp_search_for_file_or_subdir(server, &seq,
&(entry->i)) != 0) {
return total_count - fpos;
}
if (total_count < fpos) {
DPRINTK("ncp_do_readdir: skipped file: %s\n",
entry->i.entryName);
} else {
DDPRINTK("ncp_do_r: file: %s, f_pos=%d,total_count=%d",
entry->i.entryName, fpos, total_count);
entry->s = seq;
entry->f_pos = total_count;
entry += 1;
}
total_count += 1;
}
return (total_count - fpos);
}
void
ncp_init_dir_cache(void)
{
c_ino = 0;
c_entry = NULL;
}
void
ncp_invalid_dir_cache(unsigned long ino)
{
if (ino == c_ino) {
c_ino = 0;
c_seen_eof = 0;
}
}
void
ncp_free_dir_cache(void)
{
DPRINTK("ncp_free_dir_cache: enter\n");
if (c_entry == NULL)
return;
ncp_kfree_s(c_entry,
sizeof(struct ncp_dirent) * NCP_READDIR_CACHE_SIZE);
c_entry = NULL;
DPRINTK("ncp_free_dir_cache: exit\n");
}
static struct inode *
ncp_iget(struct inode *dir, struct nw_file_info *finfo)
{
struct inode *inode;
struct ncp_inode_info *new_inode_info;
struct ncp_inode_info *root;
if (!dir) {
printk("ncp_iget: dir is NULL\n");
return NULL;
}
if (!finfo) {
printk("ncp_iget: finfo is NULL\n");
return NULL;
}
new_inode_info = ncp_kmalloc(sizeof(struct ncp_inode_info),
GFP_KERNEL);
if (new_inode_info == NULL) {
printk("ncp_iget: could not alloc mem for %s\n",
finfo->i.entryName);
return NULL;
}
new_inode_info->state = INODE_LOOKED_UP;
new_inode_info->nused = 0;
new_inode_info->dir = NCP_INOP(dir);
new_inode_info->finfo = *finfo;
NCP_INOP(dir)->nused += 1;
/* We have to link the new inode_info into the doubly linked
list of inode_infos to make a complete linear search
possible. */
root = &(NCP_SERVER(dir)->root);
new_inode_info->prev = root;
new_inode_info->next = root->next;
root->next->prev = new_inode_info;
root->next = new_inode_info;
if (!(inode = iget(dir->i_sb, (int)new_inode_info))) {
printk("ncp_iget: iget failed!");
return NULL;
}
return inode;
}
void
ncp_free_inode_info(struct ncp_inode_info *i)
{
if (i == NULL) {
printk("ncp_free_inode: i == NULL\n");
return;
}
i->state = INODE_CACHED;
while ((i->nused == 0) && (i->state == INODE_CACHED)) {
struct ncp_inode_info *dir = i->dir;
i->next->prev = i->prev;
i->prev->next = i->next;
DDPRINTK("ncp_free_inode_info: freeing %s\n",
i->finfo.i.entryName);
ncp_kfree_s(i, sizeof(struct ncp_inode_info));
if (dir == i) return;
(dir->nused)--;
i = dir;
}
}
void
ncp_init_root(struct ncp_server *server)
{
struct ncp_inode_info *root = &(server->root);
struct nw_info_struct *i = &(root->finfo.i);
unsigned short dummy;
DPRINTK("ncp_init_root: server %s\n", server->m.server_name);
DPRINTK("ncp_init_root: i = %x\n", (int)i);
root->finfo.opened = 0;
i->attributes = aDIR;
i->dataStreamSize = 1024;
ncp_date_unix2dos(0, &(i->creationTime), &(i->creationDate));
ncp_date_unix2dos(0, &(i->modifyTime), &(i->modifyDate));
ncp_date_unix2dos(0, &dummy, &(i->lastAccessDate));
i->nameLen = 0;
i->entryName[0] = '\0';
root->state = INODE_LOOKED_UP;
root->nused = 1;
root->dir = root;
root->next = root->prev = root;
return;
}
void
ncp_free_all_inodes(struct ncp_server *server)
{
/* Here nothing should be to do. I do not know whether it's
better to leave some memory allocated or be stuck in an
endless loop */
#if 1
struct ncp_inode_info *root = &(server->root);
if (root->next != root) {
printk("ncp_free_all_inodes: INODES LEFT!!!\n");
}
while (root->next != root) {
printk("ncp_free_all_inodes: freeing inode\n");
ncp_free_inode_info(root->next);
/* In case we have an endless loop.. */
schedule();
}
#endif
return;
}
/* We will search the inode that belongs to this name, currently by a
complete linear search through the inodes belonging to this
filesystem. This has to be fixed. */
static struct ncp_inode_info *
ncp_find_inode(struct inode *dir, const char *name)
{
struct ncp_server *server = NCP_SERVER(dir);
struct nw_info_struct *dir_info = NCP_ISTRUCT(dir);
struct ncp_inode_info *result = &(server->root);
if (name == NULL) {
return NULL;
}
do {
if ( (result->finfo.i.DosDirNum == dir_info->DosDirNum)
&& (strcmp(result->finfo.i.entryName, name) == 0))
return result;
result = result->next;
} while (result != &(server->root));
return NULL;
}
static int
ncp_lookup(struct inode *dir, const char *__name, int len,
struct inode **result)
{
struct nw_file_info finfo;
struct ncp_server *server;
struct ncp_inode_info *result_info;
int found_in_cache;
*result = NULL;
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("ncp_lookup: inode is NULL or not a directory.\n");
iput(dir);
return -ENOENT;
}
DDPRINTK("ncp_lookup: %s, len %d\n", __name, len);
server = NCP_SERVER(dir);
/* Fast cheat for . */
if (len == 0 || (len == 1 && __name[0] == '.')) {
*result = dir;
return 0;
}
/* ..and for .. */
if (len == 2 && __name[0] == '.' && __name[1] == '.') {
*result = iget(dir->i_sb, (int)(NCP_INOP(dir)->dir));
iput(dir);
if (*result == 0)
return -EACCES;
else
return 0;
}
result_info = ncp_find_inode(dir, __name);
if (result_info != 0) {
if (result_info->state == INODE_CACHED)
result_info->state = INODE_LOOKED_UP;
/* Here we convert the inode_info address into an
inode number */
*result = iget(dir->i_sb, (int)result_info);
iput(dir);
if (*result == NULL) {
return -EACCES;
}
return 0;
}
/* If the file is in the dir cache, we do not have to ask the
server. */
found_in_cache = 0;
if (dir->i_ino == c_ino) {
int first = c_last_returned_index;
int i;
i = first;
do {
DDPRINTK("ncp_lookup: trying index: %d, name: %s\n",
i, c_entry[i].i.entryName);
if (strcmp(c_entry[i].i.entryName, __name) == 0) {
DPRINTK("ncp_lookup: found in cache!\n");
finfo.i = c_entry[i].i;
found_in_cache = 1;
break;
}
i = (i + 1) % c_size;
} while (i != first);
}
if (found_in_cache == 0) {
char this_name[len+1];
memcpy(this_name, __name, len);
this_name[len] = 0;
str_upper(this_name);
DDPRINTK("ncp_lookup: do_lookup on %s/%s\n",
NCP_ISTRUCT(dir)->entryName, this_name);
if (ncp_do_lookup(server,
dir->i_ino == (int)&(NCP_SERVER(dir)->root)
? NULL : NCP_ISTRUCT(dir),
this_name,
&(finfo.i)) != 0) {
iput(dir);
return -ENOENT;
}
}
finfo.opened = 0;
str_lower(finfo.i.entryName);
if (!(*result = ncp_iget(dir, &finfo))) {
iput(dir);
return -EACCES;
}
iput(dir);
return 0;
}
static int
ncp_create(struct inode *dir, const char *name, int len, int mode,
struct inode **result)
{
struct nw_file_info finfo;
__u8 _name[len+1];
*result = NULL;
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("ncp_create: inode is NULL or not a directory\n");
iput(dir);
return -ENOENT;
}
strncpy(_name, name, len);
_name[len] = '\0';
str_upper(_name);
if (ncp_open_create_file_or_subdir(NCP_SERVER(dir),
NCP_ISTRUCT(dir), _name,
OC_MODE_CREATE|OC_MODE_OPEN,
0, AR_READ|AR_WRITE,
&finfo) != 0) {
iput(dir);
return -EACCES;
}
ncp_invalid_dir_cache(dir->i_ino);
str_lower(finfo.i.entryName);
finfo.access = O_RDWR;
if (!(*result = ncp_iget(dir, &finfo)) < 0) {
ncp_close_file(NCP_SERVER(dir), finfo.file_handle);
iput(dir);
return -EINVAL;
}
iput(dir);
return 0;
}
static int
ncp_mkdir(struct inode *dir, const char *name, int len, int mode)
{
int error;
struct nw_file_info new_dir;
__u8 _name[len+1];
strncpy(_name, name, len);
_name[len] = '\0';
str_upper(_name);
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("ncp_mkdir: inode is NULL or not a directory\n");
iput(dir);
return -ENOENT;
}
if (ncp_open_create_file_or_subdir(NCP_SERVER(dir),
NCP_ISTRUCT(dir), _name,
OC_MODE_CREATE, aDIR, 0xffff,
&new_dir) != 0) {
error = -EACCES;
} else {
error = 0;
ncp_invalid_dir_cache(dir->i_ino);
}
iput(dir);
return error;
}
static int
ncp_rmdir(struct inode *dir, const char *name, int len)
{
int error;
__u8 _name[len+1];
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("ncp_rmdir: inode is NULL or not a directory\n");
iput(dir);
return -ENOENT;
}
if (ncp_find_inode(dir, name) != NULL) {
error = -EBUSY;
}
else
{
strncpy(_name, name, len);
_name[len] = '\0';
str_upper(_name);
if ((error = ncp_del_file_or_subdir(NCP_SERVER(dir),
NCP_ISTRUCT(dir),
_name)) == 0) {
ncp_invalid_dir_cache(dir->i_ino);
}
else
{
error = -EINVAL;
}
}
iput(dir);
return error;
}
static int
ncp_unlink(struct inode *dir, const char *name, int len)
{
int error;
__u8 _name[len+1];
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("ncp_unlink: inode is NULL or not a directory\n");
iput(dir);
return -ENOENT;
}
if (ncp_find_inode(dir, name) != NULL) {
error = -EBUSY;
}
else
{
strncpy(_name, name, len);
_name[len] = '\0';
str_upper(_name);
if ((error = ncp_del_file_or_subdir(NCP_SERVER(dir),
NCP_ISTRUCT(dir),
_name)) == 0) {
ncp_invalid_dir_cache(dir->i_ino);
}
else
{
error = -EINVAL;
}
}
iput(dir);
return error;
}
static int
ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
struct inode *new_dir, const char *new_name, int new_len)
{
int res;
char _old_name[old_len+1];
char _new_name[new_len+1];
if (!old_dir || !S_ISDIR(old_dir->i_mode)) {
printk("ncp_rename: old inode is NULL or not a directory\n");
res = -ENOENT;
goto finished;
}
if (!new_dir || !S_ISDIR(new_dir->i_mode)) {
printk("ncp_rename: new inode is NULL or not a directory\n");
res = -ENOENT;
goto finished;
}
if ( (ncp_find_inode(old_dir, old_name) != NULL)
|| (ncp_find_inode(new_dir, new_name) != NULL)) {
res = -EBUSY;
goto finished;
}
strncpy(_old_name, old_name, old_len);
_old_name[old_len] = '\0';
str_upper(_old_name);
strncpy(_new_name, new_name, new_len);
_new_name[old_len] = '\0';
str_upper(_new_name);
res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
NCP_ISTRUCT(old_dir), _old_name,
NCP_ISTRUCT(new_dir), _new_name);
if (res == 0) {
ncp_invalid_dir_cache(old_dir->i_ino);
ncp_invalid_dir_cache(new_dir->i_ino);
}
else
{
res = -EACCES;
}
finished:
iput(old_dir);
iput(new_dir);
return res;
}
/* The following routines are taken directly from msdos-fs */
/* Linear day numbers of the respective 1sts in non-leap years. */
static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
/* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
extern struct timezone sys_tz;
static int
utc2local(int time)
{
return time - sys_tz.tz_minuteswest*60;
}
static int
local2utc(int time)
{
return time + sys_tz.tz_minuteswest*60;
}
/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
int
ncp_date_dos2unix(unsigned short time,unsigned short date)
{
int month,year,secs;
month = ((date >> 5) & 15)-1;
year = date >> 9;
secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
month < 2 ? 1 : 0)+3653);
/* days since 1.1.70 plus 80's leap day */
return local2utc(secs);
}
/* Convert linear UNIX date to a MS-DOS time/date pair. */
void
ncp_date_unix2dos(int unix_date,unsigned short *time, unsigned short *date)
{
int day,year,nl_day,month;
unix_date = utc2local(unix_date);
*time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
(((unix_date/3600) % 24) << 11);
day = unix_date/86400-3652;
year = day/365;
if ((year+3)/4+365*year > day) year--;
day -= (year+3)/4+365*year;
if (day == 59 && !(year & 3)) {
nl_day = day;
month = 2;
}
else {
nl_day = (year & 3) || day <= 59 ? day : day-1;
for (month = 0; month < 12; month++)
if (day_n[month] > nl_day) break;
}
*date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9);
}

View File

@@ -5,10 +5,15 @@
*
*/
/* #include <linux/module.h>*/
#include <linux/config.h>
#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
#else
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
#endif
#include <asm/segment.h>
@@ -33,41 +38,43 @@ ncp_fsync(struct inode *inode, struct file *file)
int
ncp_make_open(struct inode *i, int right)
{
struct ncp_dirent *dirent;
struct nw_file_info *finfo;
if (i == NULL) {
printk("ncp_make_open: got NULL inode\n");
return -EINVAL;
}
dirent = &(NCP_INOP(i)->finfo);
finfo = NCP_FINFO(i);
DPRINTK("ncp_make_open: dirent->opened = %d\n", dirent->opened);
DPRINTK("ncp_make_open: dirent->opened = %d\n", finfo->opened);
if ((dirent->opened) == 0) {
struct ncp_file_info finfo;
if (finfo->opened == 0) {
/* tries max. rights */
if (ncp_open_file(NCP_SERVER(i), 0, dirent->path, 0,
AR_READ | AR_WRITE, &finfo) == 0) {
dirent->access = O_RDWR;
if (ncp_open_create_file_or_subdir(NCP_SERVER(i),
NULL, NULL,
OC_MODE_OPEN, 0,
AR_READ | AR_WRITE,
finfo) == 0) {
finfo->access = O_RDWR;
}
else if (ncp_open_file(NCP_SERVER(i), 0, dirent->path, 0,
AR_READ, &finfo) == 0) {
dirent->access = O_RDONLY;
else if (ncp_open_create_file_or_subdir(NCP_SERVER(i),
NULL, NULL,
OC_MODE_OPEN, 0,
AR_READ,
finfo) == 0) {
finfo->access = O_RDONLY;
} else {
return -EACCES;
}
dirent->opened = 1;
memcpy(&(dirent->file_id), finfo.file_id, NCP_FILE_ID_LEN);
}
if ( ((right == O_RDONLY) && ( (dirent->access == O_RDONLY)
|| (dirent->access == O_RDWR)))
|| ((right == O_WRONLY) && ( (dirent->access == O_WRONLY)
|| (dirent->access == O_RDWR)))
|| ((right == O_RDWR) && (dirent->access == O_RDWR)))
if ( ((right == O_RDONLY) && ( (finfo->access == O_RDONLY)
|| (finfo->access == O_RDWR)))
|| ((right == O_WRONLY) && ( (finfo->access == O_WRONLY)
|| (finfo->access == O_RDWR)))
|| ((right == O_RDWR) && (finfo->access == O_RDWR)))
return 0;
return -EACCES;
@@ -80,7 +87,7 @@ ncp_file_read(struct inode *inode, struct file *file, char *buf, int count)
off_t pos;
int errno;
DPRINTK("ncp_file_read: enter %s\n", NCP_FINFO(inode)->path);
DPRINTK("ncp_file_read: enter %s\n", NCP_ISTRUCT(inode)->entryName);
if (!inode) {
DPRINTK("ncp_file_read: inode = NULL\n");
@@ -93,9 +100,6 @@ ncp_file_read(struct inode *inode, struct file *file, char *buf, int count)
return -EINVAL;
}
if ((errno = ncp_make_open(inode, O_RDONLY)) != 0)
return errno;
pos = file->f_pos;
if (pos + count > inode->i_size)
@@ -104,6 +108,9 @@ ncp_file_read(struct inode *inode, struct file *file, char *buf, int count)
if (count <= 0)
return 0;
if ((errno = ncp_make_open(inode, O_RDONLY)) != 0)
return errno;
bufsize = NCP_SERVER(inode)->buffer_size;
already_read = 0;
@@ -121,7 +128,7 @@ ncp_file_read(struct inode *inode, struct file *file, char *buf, int count)
to_read = min(to_read, count - already_read);
if (ncp_read(NCP_SERVER(inode), NCP_FINFO(inode)->file_id,
if (ncp_read(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
pos, to_read, buf, &read_this_time) != 0) {
return -EIO; /* This is not exact, i know.. */
}
@@ -140,15 +147,90 @@ ncp_file_read(struct inode *inode, struct file *file, char *buf, int count)
if (!IS_RDONLY(inode)) inode->i_atime = CURRENT_TIME;
inode->i_dirt = 1;
DPRINTK("ncp_file_read: exit %s\n", NCP_FINFO(inode)->path);
DPRINTK("ncp_file_read: exit %s\n", NCP_ISTRUCT(inode)->entryName);
return already_read;
}
static int
ncp_file_write(struct inode *inode, struct file *file, char *buf,
int count)
{
int bufsize, to_write, already_written;
off_t pos;
int errno;
if (!inode) {
DPRINTK("ncp_file_write: inode = NULL\n");
return -EINVAL;
}
if (!S_ISREG(inode->i_mode)) {
DPRINTK("ncp_file_write: write to non-file, mode %07o\n",
inode->i_mode);
return -EINVAL;
}
DPRINTK("ncp_file_write: enter %s\n", NCP_ISTRUCT(inode)->entryName);
if (count <= 0)
return 0;
if ((errno = ncp_make_open(inode, O_RDWR)) != 0)
return errno;
pos = file->f_pos;
if (file->f_flags & O_APPEND)
pos = inode->i_size;
bufsize = NCP_SERVER(inode)->buffer_size;
already_written = 0;
while (already_written < count) {
int written_this_time;
if ((pos % bufsize) != 0) {
to_write = bufsize - (pos % bufsize);
} else {
to_write = bufsize;
}
to_write = min(to_write, count - already_written);
if (ncp_write(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
pos, to_write, buf, &written_this_time) != 0) {
return -EIO;
}
pos += written_this_time;
buf += written_this_time;
already_written += written_this_time;
if (written_this_time < to_write) {
break;
}
}
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_dirt = 1;
file->f_pos = pos;
if (pos > inode->i_size) {
inode->i_size = pos;
}
DPRINTK("ncp_file_write: exit %s\n", NCP_ISTRUCT(inode)->entryName);
return already_written;
}
static struct file_operations ncp_file_operations = {
NULL, /* lseek - default */
ncp_file_read, /* read */
NULL, /* write */
ncp_file_write, /* write */
NULL, /* readdir - bad */
NULL, /* select - default */
ncp_ioctl, /* ioctl */

490
kernel-1.2/src/inode.c Normal file
View File

@@ -0,0 +1,490 @@
/*
* inode.c
*
* Copyright (C) 1995 by Volker Lendecke
*
*/
#include <linux/config.h>
#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
#else
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
#endif
#include <asm/system.h>
#include <asm/segment.h>
#include <linux/sched.h>
#include <linux/ncp_fs.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/locks.h>
#include <linux/fcntl.h>
#include <linux/malloc.h>
#include "ncplib.h"
extern int close_fp(struct file *filp);
static void ncp_put_inode(struct inode *);
static void ncp_read_inode(struct inode *);
static void ncp_put_super(struct super_block *);
static void ncp_statfs(struct super_block *sb, struct statfs *stat);
static int ncp_notify_change(struct inode *inode, struct iattr *attr);
static struct super_operations ncp_sops = {
ncp_read_inode, /* read inode */
ncp_notify_change, /* notify change */
NULL, /* write inode */
ncp_put_inode, /* put inode */
ncp_put_super, /* put superblock */
NULL, /* write superblock */
ncp_statfs, /* stat filesystem */
NULL
};
/* ncp_read_inode: Called from iget, it only traverses the allocated
ncp_inode_info's and initializes the inode from the data found
there. It does not allocate or deallocate anything. */
static void
ncp_read_inode(struct inode *inode)
{
/* Our task should be extremely simple here. We only have to
look up the infomation somebody else (ncp_iget) put into
the inode tree. The address of this information is the
inode->i_ino. Just to make sure everything went well, we
check it's there. */
struct ncp_inode_info *inode_info
= (struct ncp_inode_info *)(inode->i_ino);
#if 1
struct ncp_inode_info *root = &(NCP_SERVER(inode)->root);
struct ncp_inode_info *check_info = root;
do {
if (inode_info == check_info) {
if (check_info->state == INODE_LOOKED_UP) {
DDPRINTK("ncp_read_inode: found it!\n");
goto good;
}
else {
printk("ncp_read_inode: "
"state != INODE_LOOKED_UP\n");
goto good;
}
}
check_info = check_info->next;
} while (check_info != root);
/* Ok, now we're in trouble. The inode info is not there. What
should we do now??? */
printk("ncp_read_inode: inode info not found\n");
return;
good:
DDPRINTK("ncp_read_inode: read entry %s\n",
inode_info->finfo.i.entryName);
#endif
inode_info->state = INODE_VALID;
NCP_INOP(inode) = inode_info;
if (NCP_ISTRUCT(inode)->attributes & aDIR) {
inode->i_mode = NCP_SERVER(inode)->m.dir_mode;
/* for directories in dataStreamSize seems to be some
Object ID ??? */
inode->i_size = 0;
}
else
{
inode->i_mode = NCP_SERVER(inode)->m.file_mode;
inode->i_size = NCP_ISTRUCT(inode)->dataStreamSize;
}
DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
inode->i_nlink = 1;
inode->i_uid = NCP_SERVER(inode)->m.uid;
inode->i_gid = NCP_SERVER(inode)->m.gid;
inode->i_blksize = 1024;
inode->i_rdev = 0;
if ((inode->i_blksize != 0) && (inode->i_size != 0))
inode->i_blocks =
(inode->i_size - 1) / inode->i_blksize + 1;
else
inode->i_blocks = 0;
inode->i_mtime = ncp_date_dos2unix(NCP_ISTRUCT(inode)->modifyTime,
NCP_ISTRUCT(inode)->modifyDate);
inode->i_ctime = ncp_date_dos2unix(NCP_ISTRUCT(inode)->creationTime,
NCP_ISTRUCT(inode)->creationDate);
inode->i_atime = ncp_date_dos2unix(0,
NCP_ISTRUCT(inode)->lastAccessDate);
if (S_ISREG(inode->i_mode))
inode->i_op = &ncp_file_inode_operations;
else if (S_ISDIR(inode->i_mode))
inode->i_op = &ncp_dir_inode_operations;
else
inode->i_op = NULL;
}
static void
ncp_put_inode(struct inode *inode)
{
struct nw_file_info *finfo = NCP_FINFO(inode);
if (finfo->opened != 0) {
if (ncp_close_file(NCP_SERVER(inode), finfo->file_handle)!=0) {
/* We can't do anything but complain. */
printk("ncp_put_inode: could not close\n");
}
}
ncp_free_inode_info(NCP_INOP(inode));
if (S_ISDIR(inode->i_mode)) {
DDPRINTK("ncp_put_inode: put directory %ld\n",
inode->i_ino);
ncp_invalid_dir_cache(inode->i_ino);
}
clear_inode(inode);
}
struct super_block *
ncp_read_super(struct super_block *sb, void *raw_data, int silent)
{
struct ncp_mount_data *data = (struct ncp_mount_data *) raw_data;
struct ncp_server *server;
struct file *ncp_filp;
struct file *wdog_filp;
dev_t dev = sb->s_dev;
int error;
if (!data) {
printk("ncp_read_super: missing data argument\n");
sb->s_dev = 0;
return NULL;
}
if (data->version != NCP_MOUNT_VERSION) {
printk("ncp warning: mount version %s than kernel\n",
(data->version < NCP_MOUNT_VERSION) ?
"older" : "newer");
}
if ( (data->ncp_fd >= NR_OPEN)
|| ((ncp_filp = current->files->fd[data->ncp_fd]) == NULL)
|| (!S_ISSOCK(ncp_filp->f_inode->i_mode))) {
printk("ncp_read_super: invalid ncp socket\n");
sb->s_dev = 0;
return NULL;
}
if ( (data->wdog_fd >= NR_OPEN)
|| ((wdog_filp = current->files->fd[data->wdog_fd]) == NULL)
|| (!S_ISSOCK(wdog_filp->f_inode->i_mode))) {
printk("ncp_read_super: invalid wdog socket\n");
sb->s_dev = 0;
return NULL;
}
/* We must malloc our own super-block info */
server = (struct ncp_server *)ncp_kmalloc(sizeof(struct ncp_server),
GFP_KERNEL);
if (server == NULL) {
printk("ncp_read_super: could not alloc ncp_server\n");
return NULL;
}
ncp_filp->f_count += 1;
wdog_filp->f_count += 1;
lock_super(sb);
NCP_SBP(sb) = server;
sb->s_blocksize = 1024; /* Eh... Is this correct? */
sb->s_blocksize_bits = 10;
sb->s_magic = NCP_SUPER_MAGIC;
sb->s_dev = dev;
sb->s_op = &ncp_sops;
server->ncp_filp = ncp_filp;
server->wdog_filp = wdog_filp;
server->lock = 0;
server->wait = NULL;
server->packet = NULL;
server->buffer_size = 0;
server->m = *data;
server->m.file_mode = (server->m.file_mode &
(S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFREG;
server->m.dir_mode = (server->m.dir_mode &
(S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFDIR;
server->packet_size = NCP_PACKET_SIZE;
server->packet = ncp_kmalloc(NCP_PACKET_SIZE, GFP_KERNEL);
if (server->packet == NULL) {
printk("ncpfs: could not alloc packet\n");
error = -ENOMEM;
unlock_super(sb);
goto fail;
}
ncp_init_root(server);
/*
* Make the connection to the server
*/
if (ncp_catch_watchdog(server) != 0) {
printk("ncp_read_super: Could not catch watchdog\n");
error = -EINVAL;
unlock_super(sb);
goto fail;
}
ncp_lock_server(server);
error = ncp_connect(server);
ncp_unlock_server(server);
unlock_super(sb);
if (error < 0) {
sb->s_dev = 0;
printk("ncp_read_super: Failed connection, bailing out "
"(error = %d).\n", -error);
ncp_kfree_s(server->packet, server->packet_size);
ncp_dont_catch_watchdog(server);
goto fail;
}
DPRINTK("ncp_read_super: NCP_SBP(sb) = %x\n", (int)NCP_SBP(sb));
if (!(sb->s_mounted = iget(sb, (int)&(server->root)))) {
sb->s_dev = 0;
printk("ncp_read_super: get root inode failed\n");
goto disconnect;
}
if (ncp_negotiate_buffersize(server, NCP_DEFAULT_BUFSIZE,
&(server->buffer_size)) != 0) {
sb->s_dev = 0;
printk("ncp_read_super: could not get bufsize\n");
goto disconnect;
}
DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
/* if (ncp_login_user(server, server->m.username,
server->m.password) != 0) {
sb->s_dev = 0;
printk("ncp_read_super: login failed\n");
goto disconnect;
}
*/
MOD_INC_USE_COUNT;
return sb;
disconnect:
ncp_lock_server(server);
ncp_disconnect(server);
ncp_unlock_server(server);
ncp_kfree_s(server->packet, server->packet_size);
ncp_dont_catch_watchdog(server);
fail:
ncp_filp->f_count -= 1;
wdog_filp->f_count -= 1;
ncp_kfree_s(NCP_SBP(sb), sizeof(struct ncp_server));
return NULL;
}
static void
ncp_put_super(struct super_block *sb)
{
struct ncp_server *server = NCP_SBP(sb);
lock_super(sb);
ncp_lock_server(server);
ncp_disconnect(server);
ncp_unlock_server(server);
close_fp(server->ncp_filp);
ncp_dont_catch_watchdog(server);
close_fp(server->wdog_filp);
ncp_free_all_inodes(server);
ncp_kfree_s(server->packet, server->packet_size);
sb->s_dev = 0;
ncp_kfree_s(NCP_SBP(sb), sizeof(struct ncp_server));
NCP_SBP(sb) = NULL;
unlock_super(sb);
MOD_DEC_USE_COUNT;
}
static void
ncp_statfs(struct super_block *sb, struct statfs *stat)
{
struct statfs tmp;
/* We cannot say how much disk space is left on a mounted
NetWare Server, because free space is distributed over
volumes, and the current user might have disk quotas. So
free space is not that simple to determine. Our decision
here is to err conservatively. */
tmp.f_type = NCP_SUPER_MAGIC;
tmp.f_bsize = 512;
tmp.f_blocks = 0;
tmp.f_bfree = 0;
tmp.f_bavail = 0;
tmp.f_files = -1;
tmp.f_ffree = -1;
tmp.f_namelen = 12;
memcpy_tofs(stat, &tmp, sizeof(tmp));
}
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;
if (((attr->ia_valid & ATTR_UID) &&
(attr->ia_uid != NCP_SERVER(inode)->m.uid)))
return -EPERM;
if (((attr->ia_valid & ATTR_GID) &&
(attr->ia_uid != NCP_SERVER(inode)->m.gid)))
return -EPERM;
if (((attr->ia_valid & ATTR_MODE) &&
(attr->ia_mode &
~(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;
DPRINTK("ncpfs: trying to change size of %s to %ld\n",
NCP_ISTRUCT(inode)->entryName, attr->ia_size);
if ((result = ncp_make_open(inode, O_RDWR)) < 0) {
return -EACCES;
}
ncp_write(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
attr->ia_size, 0, "", &written);
/* According to ndir, the changes only take effect after
closing the file */
ncp_close_file(NCP_SERVER(inode),
NCP_FINFO(inode)->file_handle);
NCP_FINFO(inode)->opened = 0;
result = 0;
}
ncp_invalid_dir_cache((unsigned long)(NCP_INOP(inode)->dir));
return result;
}
#ifdef DEBUG_NCP_MALLOC
int ncp_malloced;
int ncp_current_malloced;
#endif
#ifdef MODULE
char kernel_version[] = UTS_RELEASE;
static struct file_system_type ncp_fs_type = {
ncp_read_super, "ncpfs", 0, NULL
};
int
init_module( void)
{
DPRINTK("ncpfs: init_module called\n");
#ifdef DEBUG_NCP_MALLOC
ncp_malloced = 0;
ncp_current_malloced = 0;
#endif
ncp_init_dir_cache();
register_filesystem(&ncp_fs_type);
return 0;
}
void
cleanup_module(void)
{
DPRINTK("ncpfs: cleanup_module called\n");
ncp_free_dir_cache();
unregister_filesystem(&ncp_fs_type);
#ifdef DEBUG_NCP_MALLOC
printk("ncp_malloced: %d\n", ncp_malloced);
printk("ncp_current_malloced: %d\n", ncp_current_malloced);
#endif
}
#endif

View File

@@ -4,6 +4,7 @@
* Copyright (C) 1995 by Volker Lendecke
*
*/
#include <linux/config.h>
#ifdef MODULE
#include <linux/module.h>
@@ -65,9 +66,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);
@@ -80,6 +80,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;
}

590
kernel-1.2/src/ncplib.c Normal file
View File

@@ -0,0 +1,590 @@
#include <linux/config.h>
#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
#else
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
#endif
#include "ncplib.h"
typedef __u8 byte;
typedef __u16 word;
typedef __u32 dword;
static void
assert_server_locked(struct ncp_server *server)
{
if (server->lock == 0) {
DPRINTK("ncpfs: server not locked!\n");
}
}
static void
ncp_add_byte(struct ncp_server *server, byte x)
{
assert_server_locked(server);
*(byte *)(&(server->packet[server->current_size])) = x;
server->current_size += 1;
return;
}
static void
ncp_add_word(struct ncp_server *server, word x)
{
assert_server_locked(server);
*(word *)(&(server->packet[server->current_size])) = x;
server->current_size += 2;
return;
}
static void
ncp_add_dword(struct ncp_server *server, dword x)
{
assert_server_locked(server);
*(dword *)(&(server->packet[server->current_size])) = x;
server->current_size += 4;
return;
}
static void
ncp_add_mem(struct ncp_server *server, const void *source, int size)
{
assert_server_locked(server);
memcpy(&(server->packet[server->current_size]), source, size);
server->current_size += size;
return;
}
static void
ncp_add_mem_fromfs(struct ncp_server *server, const char *source, int size)
{
assert_server_locked(server);
memcpy_fromfs(&(server->packet[server->current_size]), source, size);
server->current_size += size;
return;
}
static void
ncp_add_pstring(struct ncp_server *server, const char *s)
{
int len = strlen(s);
assert_server_locked(server);
if (len > 255) {
DPRINTK("ncpfs: string too long: %s\n", s);
len = 255;
}
ncp_add_byte(server, len);
ncp_add_mem(server, s, len);
return;
}
static void
ncp_init_request(struct ncp_server *server)
{
ncp_lock_server(server);
server->current_size = sizeof(struct ncp_request_header);
server->has_subfunction = 0;
}
static void
ncp_init_request_s(struct ncp_server *server, int subfunction)
{
ncp_init_request(server);
ncp_add_word(server, 0); /* preliminary size */
ncp_add_byte(server, subfunction);
server->has_subfunction = 1;
}
static char *
ncp_reply_data(struct ncp_server *server, int offset)
{
return &(server->packet[sizeof(struct ncp_reply_header) + offset]);
}
static byte
ncp_reply_byte(struct ncp_server *server, int offset)
{
return *(byte *)(ncp_reply_data(server, offset));
}
static word
ncp_reply_word(struct ncp_server *server, int offset)
{
return *(word *)(ncp_reply_data(server, offset));
}
static dword
ncp_reply_dword(struct ncp_server *server, int offset)
{
return *(dword *)(ncp_reply_data(server, offset));
}
int
ncp_negotiate_buffersize(struct ncp_server *server,
int size, int *target) {
int result;
ncp_init_request(server);
ncp_add_word(server, htons(size));
if ((result = ncp_request(server, 33)) != 0) {
ncp_unlock_server(server);
return result;
}
*target =min(ntohs(ncp_reply_word(server, 0)), size);
ncp_unlock_server(server);
return 0;
}
int
ncp_get_volume_info_with_number(struct ncp_server *server, int n,
struct ncp_volume_info *target)
{
int result;
int len;
ncp_init_request_s(server, 44);
ncp_add_byte(server, n);
if ((result = ncp_request(server, 22)) != 0) {
ncp_unlock_server(server);
return result;
}
target->total_blocks = ncp_reply_dword(server, 0);
target->free_blocks = ncp_reply_dword(server, 4);
target->purgeable_blocks = ncp_reply_dword(server, 8);
target->not_yet_purgeable_blocks = ncp_reply_dword(server, 12);
target->total_dir_entries = ncp_reply_dword(server, 16);
target->available_dir_entries = ncp_reply_dword(server, 20);
target->sectors_per_block = ncp_reply_byte(server, 28);
memset(&(target->volume_name), 0, sizeof(target->volume_name));
len = ncp_reply_byte(server, 29);
if (len > NCP_VOLNAME_LEN) {
DPRINTK("ncpfs: volume name too long: %d\n", len);
ncp_unlock_server(server);
return -EIO;
}
memcpy(&(target->volume_name), ncp_reply_data(server, 30), len);
ncp_unlock_server(server);
return 0;
}
int
ncp_get_volume_number(struct ncp_server *server, const char *name, int *target)
{
int result;
ncp_init_request_s(server, 5);
ncp_add_pstring(server, name);
if ((result = ncp_request(server, 22)) != 0) {
ncp_unlock_server(server);
return result;
}
*target = ncp_reply_byte(server, 0);
ncp_unlock_server(server);
return 0;
}
int
ncp_close_file(struct ncp_server *server, const char *file_id)
{
int result;
ncp_init_request(server);
ncp_add_byte(server, 0);
ncp_add_mem(server, file_id, 6);
if ((result = ncp_request(server, 66)) != 0) {
ncp_unlock_server(server);
return result;
}
ncp_unlock_server(server);
return 0;
}
static void
ncp_add_handle_path(struct ncp_server *server,
__u8 vol_num,
__u32 dir_base, int have_dir_base,
char *path)
{
ncp_add_byte(server, vol_num);
ncp_add_dword(server, dir_base);
if (have_dir_base != 0) {
ncp_add_byte(server, 1); /* dir_base */
} else {
ncp_add_byte(server, 0xff); /* no handle */
}
if (path != NULL) {
ncp_add_byte(server, 1); /* 1 component */
ncp_add_pstring(server, path);
}
else
{
ncp_add_byte(server, 0);
}
}
static void
ncp_extract_file_info(void *structure, struct nw_info_struct *target)
{
__u8 *name_len;
const int info_struct_size = sizeof(struct nw_info_struct) - 257;
memcpy(target, structure, info_struct_size);
name_len = structure + info_struct_size;
target->nameLen = *name_len;
strncpy(target->entryName, name_len+1, *name_len);
target->entryName[*name_len] = '\0';
return;
}
int
ncp_do_lookup(struct ncp_server *server,
struct nw_info_struct *dir,
char *path, /* may only be one component */
struct nw_info_struct *target)
{
__u8 vol_num;
__u32 dir_base;
int result;
char *volname = NULL;
if (target == NULL) {
return -EINVAL;
}
if (dir == NULL) {
DDPRINTK("ncp_do_lookup: looking up vol %s\n", path);
/* Access a volume's root directory */
ncp_init_request(server);
ncp_add_byte(server, 22); /* subfunction */
ncp_add_byte(server, 0); /* dos name space */
ncp_add_byte(server, 0); /* reserved */
ncp_add_byte(server, 0); /* reserved */
ncp_add_byte(server, 0); /* reserved */
ncp_add_handle_path(server, 0, 0, 0, /* no handle */
path);
if ((result = ncp_request(server, 87)) != 0) {
ncp_unlock_server(server);
return result;
}
dir_base = ncp_reply_dword(server, 4);
vol_num = ncp_reply_byte (server, 8);
ncp_unlock_server(server);
volname = path;
path = NULL;
}
else
{
vol_num = dir->volNumber;
dir_base = dir->DosDirNum;
}
ncp_init_request(server);
ncp_add_byte(server, 6); /* subfunction */
ncp_add_byte(server, 0); /* dos name space */
ncp_add_byte(server, 0); /* dos name space as dest */
ncp_add_word(server, 0xff); /* get all */
ncp_add_dword(server, RIM_ALL);
ncp_add_handle_path(server, vol_num, dir_base, 1,
path);
if ((result = ncp_request(server, 87)) != 0) {
ncp_unlock_server(server);
return result;
}
ncp_extract_file_info(ncp_reply_data(server, 0), target);
if (volname != NULL) {
target->nameLen = strlen(volname);
strcpy(target->entryName, volname);
}
ncp_unlock_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)
{
int result;
ncp_init_request(server);
ncp_add_byte(server, 8); /* 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_handle_path(server, dir->volNumber,
dir->DosDirNum, 1, name);
if ((result = ncp_request(server, 87)) != 0) {
ncp_unlock_server(server);
return result;
}
ncp_unlock_server(server);
return 0;
}
static inline void
ConvertToNWfromDWORD ( __u32 sfd , __u8 ret[6] )
{
__u16 *dest = (__u16 *) ret;
memcpy(&(dest[1]), &sfd, 4);
dest[0] = dest[1] + 1;
return;
}
/* If both dir and name are NULL, then in target there's already a
looked-up entry that wants to be opened. */
int
ncp_open_create_file_or_subdir(struct ncp_server *server,
struct nw_info_struct *dir, char *name,
int open_create_mode,
__u32 create_attributes,
int desired_acc_rights,
struct nw_file_info *target)
{
int result;
ncp_init_request(server);
ncp_add_byte(server, 1); /* subfunction */
ncp_add_byte(server, 0); /* dos name space */
ncp_add_byte(server, open_create_mode);
ncp_add_word(server, 0x8006);
ncp_add_dword(server, RIM_ALL);
ncp_add_dword(server, create_attributes);
/* The desired acc rights seem to be the inherited rights mask
for directories */
ncp_add_word(server, desired_acc_rights);
if (dir != NULL) {
ncp_add_handle_path(server, dir->volNumber,
dir->DosDirNum, 1, name);
} else {
ncp_add_handle_path(server,
target->i.volNumber, target->i.DosDirNum,
1, NULL);
}
if ((result = ncp_request(server, 87)) != 0) {
ncp_unlock_server(server);
return result;
}
target->opened = 1;
target->server_file_handle = ncp_reply_dword(server, 0);
target->open_create_action = ncp_reply_byte(server, 4);
if (dir != NULL) {
/* in target there's a new finfo to fill */
ncp_extract_file_info(ncp_reply_data(server, 5), &(target->i));
}
ConvertToNWfromDWORD(target->server_file_handle, target->file_handle);
ncp_unlock_server(server);
return 0;
}
int
ncp_initialize_search(struct ncp_server *server,
struct nw_info_struct *dir,
struct nw_search_sequence *target)
{
int result;
ncp_init_request(server);
ncp_add_byte(server, 2); /* subfunction */
ncp_add_byte(server, 0); /* dos name space */
ncp_add_byte(server, 0); /* reserved */
ncp_add_handle_path(server, dir->volNumber, dir->DosDirNum, 1, NULL);
if ((result = ncp_request(server, 87)) != 0) {
ncp_unlock_server(server);
return result;
}
memcpy(target, ncp_reply_data(server, 0), sizeof(*target));
ncp_unlock_server(server);
return 0;
}
/* Search for everything */
int
ncp_search_for_file_or_subdir(struct ncp_server *server,
struct nw_search_sequence *seq,
struct nw_info_struct *target)
{
int result;
ncp_init_request(server);
ncp_add_byte(server, 3); /* subfunction */
ncp_add_byte(server, 0); /* dos name space */
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, seq, 9);
ncp_add_byte(server, 2); /* 2 byte pattern */
ncp_add_byte(server, 0xff); /* following is a wildcard */
ncp_add_byte(server, '*');
if ((result = ncp_request(server, 87)) != 0) {
ncp_unlock_server(server);
return result;
}
memcpy(seq, ncp_reply_data(server, 0), sizeof(*seq));
ncp_extract_file_info(ncp_reply_data(server, 10), target);
ncp_unlock_server(server);
return 0;
}
int
ncp_ren_or_mov_file_or_subdir(struct ncp_server *server,
struct nw_info_struct *old_dir, char *old_name,
struct nw_info_struct *new_dir, char *new_name)
{
int result;
if ( (old_dir == NULL) || (old_name == NULL)
|| (new_dir == NULL) || (new_name == NULL))
return -EINVAL;
ncp_init_request(server);
ncp_add_byte(server, 4); /* subfunction */
ncp_add_byte(server, 0); /* dos name space */
ncp_add_byte(server, 1); /* rename flag */
ncp_add_word(server, 0x8006); /* search attributes */
/* source Handle Path */
ncp_add_byte(server, old_dir->volNumber);
ncp_add_dword(server, old_dir->DosDirNum);
ncp_add_byte(server, 1);
ncp_add_byte(server, 1); /* 1 source component */
/* dest Handle Path */
ncp_add_byte(server, new_dir->volNumber);
ncp_add_dword(server, new_dir->DosDirNum);
ncp_add_byte(server, 1);
ncp_add_byte(server, 1); /* 1 destination component */
/* source path string */
ncp_add_pstring(server, old_name);
/* dest path string */
ncp_add_pstring(server, new_name);
result = ncp_request(server, 87);
ncp_unlock_server(server);
return result;
}
/* We have to transfer to/from user space */
int
ncp_read(struct ncp_server *server, const char *file_id,
__u32 offset, __u16 to_read,
char *target, int *bytes_read)
{
int result;
ncp_init_request(server);
ncp_add_byte(server, 0);
ncp_add_mem(server, file_id, 6);
ncp_add_dword(server, htonl(offset));
ncp_add_word(server, htons(to_read));
if ((result = ncp_request(server, 72)) != 0) {
ncp_unlock_server(server);
return result;
}
*bytes_read = ntohs(ncp_reply_word(server, 0));
memcpy_tofs(target, ncp_reply_data(server, 2), *bytes_read);
ncp_unlock_server(server);
return 0;
}
int
ncp_write(struct ncp_server *server, const char *file_id,
__u32 offset, __u16 to_write,
const char *source, int *bytes_written)
{
int result;
ncp_init_request(server);
ncp_add_byte(server, 0);
ncp_add_mem(server, file_id, 6);
ncp_add_dword(server, htonl(offset));
ncp_add_word(server, htons(to_write));
ncp_add_mem_fromfs(server, source, to_write);
if ((result = ncp_request(server, 73)) != 0) {
ncp_unlock_server(server);
return result;
}
*bytes_written = to_write;
ncp_unlock_server(server);
return 0;
}

156
kernel-1.2/src/ncplib.h Normal file
View File

@@ -0,0 +1,156 @@
#ifndef _NCPLIB_H
#define _NCPLIB_H
#include <linux/fs.h>
#include <linux/ncp.h>
#include <linux/ncp_fs.h>
#include <linux/ncp_fs_sb.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/malloc.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <asm/segment.h>
#include <asm/string.h>
#include <linux/ncp.h>
int
ncp_negotiate_buffersize(struct ncp_server *server, int size,
int *target);
int
ncp_get_encryption_key(struct ncp_server *server,
char *target);
int
ncp_get_bindery_object_id(struct ncp_server *server,
int object_type, char *object_name,
struct ncp_bindery_object *target);
int
ncp_login_encrypted(struct ncp_server *server,
struct ncp_bindery_object *object,
unsigned char *key,
unsigned char *passwd);
int
ncp_login_user(struct ncp_server *server,
unsigned char *username,
unsigned char *password);
int
ncp_get_volume_info_with_number(struct ncp_server *server, int n,
struct ncp_volume_info *target);
int
ncp_get_volume_number(struct ncp_server *server, const char *name,
int *target);
int
ncp_file_search_init(struct ncp_server *server,
int dir_handle, const char *path,
struct ncp_filesearch_info *target);
int
ncp_file_search_continue(struct ncp_server *server,
struct ncp_filesearch_info *fsinfo,
int attributes, const char *path,
struct ncp_file_info *target);
int
ncp_get_finfo(struct ncp_server *server,
int dir_handle, const char *path, const char *name,
struct ncp_file_info *target);
int
ncp_open_file(struct ncp_server *server,
int dir_handle, const char *path,
int attr, int access,
struct ncp_file_info *target);
int
ncp_close_file(struct ncp_server *server, const char *file_id);
int
ncp_create_newfile(struct ncp_server *server,
int dir_handle, const char *path,
int attr,
struct ncp_file_info *target);
int
ncp_create_file(struct ncp_server *server,
int dir_handle, const char *path,
int attr,
struct ncp_file_info *target);
int
ncp_erase_file(struct ncp_server *server,
int dir_handle, const char *path,
int attr);
int
ncp_rename_file(struct ncp_server *server,
int old_handle, const char *old_path,
int attr,
int new_handle, const char *new_path);
int
ncp_create_directory(struct ncp_server *server,
int dir_handle, const char *path,
int inherit_mask);
int
ncp_delete_directory(struct ncp_server *server,
int dir_handle, const char *path);
int
ncp_rename_directory(struct ncp_server *server,
int dir_handle,
const char *old_path, const char *new_path);
int
ncp_read(struct ncp_server *server, const char *file_id,
__u32 offset, __u16 to_read,
char *target, int *bytes_read);
int
ncp_write(struct ncp_server *server, const char *file_id,
__u32 offset, __u16 to_write,
const char *source, int *bytes_written);
int
ncp_do_lookup(struct ncp_server *server,
struct nw_info_struct *dir,
char *path, /* may only be one component */
struct nw_info_struct *target);
int
ncp_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,
int open_create_mode,
__u32 create_attributes,
int desired_acc_rights,
struct nw_file_info *target);
int
ncp_initialize_search(struct ncp_server *server,
struct nw_info_struct *dir,
struct nw_search_sequence *target);
int
ncp_search_for_file_or_subdir(struct ncp_server *server,
struct nw_search_sequence *seq,
struct nw_info_struct *target);
int
ncp_ren_or_mov_file_or_subdir(struct ncp_server *server,
struct nw_info_struct *old_dir, char *old_name,
struct nw_info_struct *new_dir, char *new_name);
#endif /* _NCPLIB_H */

View File

@@ -11,6 +11,9 @@
#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
#else
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
#endif
#include <linux/sched.h>
@@ -29,11 +32,10 @@
#include <linux/ncp.h>
#include <linux/ncp_fs.h>
#include <linux/ncp_fs_sb.h>
#include <net/sock.h>
#include "/usr/src/linux/net/inet/sock.h"
#define _S(nr) (1<<((nr)-1))
static void
ncp_wdog_data_ready(struct sock *sk, int len)
{
@@ -43,7 +45,7 @@ ncp_wdog_data_ready(struct sock *sk, int len)
{
unsigned char packet_buf[2];
struct sockaddr_ipx sender;
int addr_len;
int addr_len = sizeof(struct sockaddr_ipx);
int result;
unsigned short fs;
@@ -80,11 +82,11 @@ ncp_wdog_data_ready(struct sock *sk, int len)
packet_buf[0], packet_buf[1]);
packet_buf[1] = 'Y';
result = sock->ops->
sendto(sock, (void *)packet_buf, 2, 1, 0,
(struct sockaddr *)&sender,
sizeof(sender));
printk("send result: %d\n", result);
result = sock->ops->sendto(sock, (void *)packet_buf,
2, 1, 0,
(struct sockaddr *)&sender,
sizeof(sender));
DPRINTK("send result: %d\n", result);
}
set_fs(fs);
}
@@ -245,9 +247,9 @@ do_ncp_rpc_call(struct ncp_server *server, int size)
| _S(SIGSTOP)
#endif
| ((server->m.flags & NCP_MOUNT_INTR)
? ((current->sig->action[SIGINT - 1].sa_handler == SIG_DFL
? ((current->sigaction[SIGINT - 1].sa_handler == SIG_DFL
? _S(SIGINT) : 0)
| (current->sig->action[SIGQUIT - 1].sa_handler == SIG_DFL
| (current->sigaction[SIGQUIT - 1].sa_handler == SIG_DFL
? _S(SIGQUIT) : 0))
: 0));
fs = get_fs();
@@ -262,19 +264,18 @@ do_ncp_rpc_call(struct ncp_server *server, int size)
server->m.serv_addr.sipx_node[4],
server->m.serv_addr.sipx_node[5],
ntohs(server->m.serv_addr.sipx_port));
DDPRINTK("ncpfs: req.typ: %04X, con: %d, tsk: %d, "
"seq: %d\n",
DDPRINTK("ncpfs: req.typ: %04X, con: %d, "
"seq: %d",
request.type,
(request.conn_high << 8) + request.conn_low,
request.task,
request.sequence);
DDPRINTK("ncpfs: req.func: %d\n",
DDPRINTK(" func: %d\n",
request.function);
result = sock->ops->
sendto(sock, (void *) start, size, 0, 0,
(struct sockaddr *)&(server->m.serv_addr),
sizeof(server->m.serv_addr));
result = sock->ops->sendto(sock, (void *) start, size, 0, 0,
(struct sockaddr *)
&(server->m.serv_addr),
sizeof(server->m.serv_addr));
if (result < 0) {
printk("ncp_rpc_call: send error = %d\n", result);
break;
@@ -354,9 +355,9 @@ do_ncp_rpc_call(struct ncp_server *server, int size)
&& (reply.type == NCP_POSITIVE_ACK)) {
/* Throw away the packet */
DPRINTK("ncp_rpc_call: got positive acknowledge\n");
(void)sock->ops->recvfrom(sock, (void *)&reply,
sizeof(reply), 1, 0, NULL,
&addrlen);
sock->ops->recvfrom(sock, (void *)&reply,
sizeof(reply), 1, 0,
NULL, &addrlen);
goto re_select;
}
@@ -382,9 +383,8 @@ do_ncp_rpc_call(struct ncp_server *server, int size)
* we have xid mismatch, so discard the packet and start
* again. What a hack! but I can't call recvfrom with
* a null buffer yet. */
(void)sock->ops->recvfrom(sock, (void *)&reply,
sizeof(reply), 1, 0, NULL,
&addrlen);
sock->ops->recvfrom(sock, (void *)&reply, sizeof(reply), 1, 0,
NULL, &addrlen);
#if 1
printk("ncp_rpc_call: reply mismatch\n");
#endif
@@ -394,9 +394,8 @@ do_ncp_rpc_call(struct ncp_server *server, int size)
* we have the correct reply, so read into the correct place and
* return it
*/
result=sock->ops->recvfrom(sock, (void *)start,
server->packet_size, 1, 0, NULL,
&addrlen);
result = sock->ops->recvfrom(sock, (void *)start, server->packet_size,
1, 0, NULL, &addrlen);
if (result < 0) {
printk("NCP: notice message: result=%d\n", result);
} else if (result < sizeof(struct ncp_reply_header)) {
@@ -457,6 +456,7 @@ ncp_request(struct ncp_server *server, int function)
h->function = function;
if ((result = ncp_do_request(server, request_size + sizeof(*h))) < 0) {
DPRINTK("ncp_request_error: %d\n", result);
return result;
}
@@ -465,8 +465,12 @@ ncp_request(struct ncp_server *server, int function)
server->reply_size = result;
server->ncp_reply_size = result - sizeof(struct ncp_reply_header);
return reply->completion_code;
result = reply->completion_code;
if (result != 0) {
DPRINTK("ncp_completion_code: %d\n", result);
}
return result;
}
int
@@ -515,6 +519,12 @@ ncp_disconnect(struct ncp_server *server)
void
ncp_lock_server(struct ncp_server *server)
{
#if 1
/* For testing, only 1 process */
if (server->lock != 0) {
DPRINTK("ncpfs: server locked!!!\n");
}
#endif
while (server->lock)
sleep_on(&server->wait);
server->lock = 1;

284
kernel-1.3/linux/ncp.h Normal file
View File

@@ -0,0 +1,284 @@
/*
* ncp_fs.h
*
* Copyright (C) 1995 by Volker Lendecke
*
*/
#ifndef _LINUX_NCP_H
#define _LINUX_NCP_H
#error "Please use kernel 1.2.13"
#include <linux/types.h>
#define NCP_PTYPE (0x11)
#define NCP_PORT (0x0451)
#define NCP_ALLOC_SLOT_REQUEST (0x1111)
#define NCP_REQUEST (0x2222)
#define NCP_DEALLOC_SLOT_REQUEST (0x5555)
struct ncp_request_header {
__u16 type __attribute__ ((packed));
__u8 sequence __attribute__ ((packed));
__u8 conn_low __attribute__ ((packed));
__u8 task __attribute__ ((packed));
__u8 conn_high __attribute__ ((packed));
__u8 function __attribute__ ((packed));
__u8 data[0] __attribute__ ((packed));
};
#define NCP_REPLY (0x3333)
#define NCP_POSITIVE_ACK (0x9999)
struct ncp_reply_header {
__u16 type __attribute__ ((packed));
__u8 sequence __attribute__ ((packed));
__u8 conn_low __attribute__ ((packed));
__u8 task __attribute__ ((packed));
__u8 conn_high __attribute__ ((packed));
__u8 completion_code __attribute__ ((packed));
__u8 connection_state __attribute__ ((packed));
__u8 data[0] __attribute__ ((packed));
};
#define NCP_BINDERY_USER (0x0001)
#define NCP_BINDERY_UGROUP (0x0002)
#define NCP_BINDERY_PQUEUE (0x0003)
#define NCP_BINDERY_FSERVER (0x0004)
#define NCP_BINDERY_NAME_LEN (48)
struct ncp_bindery_object {
__u32 object_id;
__u16 object_type;
__u8 object_name[NCP_BINDERY_NAME_LEN];
};
struct nw_property {
__u8 value[128];
__u8 more_flag;
__u8 property_flag;
};
#define NCP_VOLNAME_LEN (16)
#define NCP_NUMBER_OF_VOLUMES (64)
struct ncp_volume_info {
__u32 total_blocks;
__u32 free_blocks;
__u32 purgeable_blocks;
__u32 not_yet_purgeable_blocks;
__u32 total_dir_entries;
__u32 available_dir_entries;
__u8 sectors_per_block;
char volume_name[NCP_VOLNAME_LEN+1];
};
struct ncp_filesearch_info {
__u8 volume_number;
__u16 directory_id;
__u16 sequence_no;
__u8 access_rights;
};
#define NCP_MAX_FILENAME 14
/* these define the attribute byte as seen by NCP */
#define aRONLY (1L<<0)
#define aHIDDEN (1L<<1)
#define aSYSTEM (1L<<2)
#define aEXECUTE (1L<<3)
#define aDIR (1L<<4)
#define aARCH (1L<<5)
#define AR_READ (0x01)
#define AR_WRITE (0x02)
#define AR_EXCLUSIVE (0x20)
#define NCP_FILE_ID_LEN 6
struct ncp_file_info {
__u8 file_id[NCP_FILE_ID_LEN];
char file_name[NCP_MAX_FILENAME+1];
__u8 file_attributes;
__u8 file_mode;
__u32 file_length;
__u16 creation_date;
__u16 access_date;
__u16 update_date;
__u16 update_time;
};
/* Defines for ReturnInformationMask */
#define RIM_NAME (0x0001L)
#define RIM_SPACE_ALLOCATED (0x0002L)
#define RIM_ATTRIBUTES (0x0004L)
#define RIM_DATA_SIZE (0x0008L)
#define RIM_TOTAL_SIZE (0x0010L)
#define RIM_EXT_ATTR_INFO (0x0020L)
#define RIM_ARCHIVE (0x0040L)
#define RIM_MODIFY (0x0080L)
#define RIM_CREATION (0x0100L)
#define RIM_OWNING_NAMESPACE (0x0200L)
#define RIM_DIRECTORY (0x0400L)
#define RIM_RIGHTS (0x0800L)
#define RIM_ALL (0x0FFFL)
#define RIM_COMPRESSED_INFO (0x80000000L)
/* open/create modes */
#define OC_MODE_OPEN 0x01
#define OC_MODE_TRUNCATE 0x02
#define OC_MODE_REPLACE 0x02
#define OC_MODE_CREATE 0x08
/* open/create results */
#define OC_ACTION_NONE 0x00
#define OC_ACTION_OPEN 0x01
#define OC_ACTION_CREATE 0x02
#define OC_ACTION_TRUNCATE 0x04
#define OC_ACTION_REPLACE 0x04
/* access rights attributes */
#ifndef AR_READ_ONLY
#define AR_READ_ONLY 0x0001
#define AR_WRITE_ONLY 0x0002
#define AR_DENY_READ 0x0004
#define AR_DENY_WRITE 0x0008
#define AR_COMPATIBILITY 0x0010
#define AR_WRITE_THROUGH 0x0040
#define AR_OPEN_COMPRESSED 0x0100
#endif
struct nw_info_struct
{
__u32 spaceAlloc __attribute__ ((packed));
__u32 attributes __attribute__ ((packed));
__u16 flags __attribute__ ((packed));
__u32 dataStreamSize __attribute__ ((packed));
__u32 totalStreamSize __attribute__ ((packed));
__u16 numberOfStreams __attribute__ ((packed));
__u16 creationTime __attribute__ ((packed));
__u16 creationDate __attribute__ ((packed));
__u32 creatorID __attribute__ ((packed));
__u16 modifyTime __attribute__ ((packed));
__u16 modifyDate __attribute__ ((packed));
__u32 modifierID __attribute__ ((packed));
__u16 lastAccessDate __attribute__ ((packed));
__u16 archiveTime __attribute__ ((packed));
__u16 archiveDate __attribute__ ((packed));
__u32 archiverID __attribute__ ((packed));
__u16 inheritedRightsMask __attribute__ ((packed));
__u32 dirEntNum __attribute__ ((packed));
__u32 DosDirNum __attribute__ ((packed));
__u32 volNumber __attribute__ ((packed));
__u32 EADataSize __attribute__ ((packed));
__u32 EAKeyCount __attribute__ ((packed));
__u32 EAKeySize __attribute__ ((packed));
__u32 NSCreator __attribute__ ((packed));
__u8 nameLen __attribute__ ((packed));
__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;
int access;
__u32 server_file_handle __attribute__ ((packed));
__u8 open_create_action __attribute__ ((packed));
__u8 file_handle[6] __attribute__ ((packed));
};
struct nw_search_sequence {
__u8 volNumber __attribute__ ((packed));
__u32 dirBase __attribute__ ((packed));
__u32 sequence __attribute__ ((packed));
};
struct nw_queue_job_entry {
__u16 InUse __attribute__ ((packed));
__u32 prev __attribute__ ((packed));
__u32 next __attribute__ ((packed));
__u32 ClientStation __attribute__ ((packed));
__u32 ClientTask __attribute__ ((packed));
__u32 ClientObjectID __attribute__ ((packed));
__u32 TargetServerID __attribute__ ((packed));
__u8 TargetExecTime[6] __attribute__ ((packed));
__u8 JobEntryTime[6] __attribute__ ((packed));
__u32 JobNumber __attribute__ ((packed));
__u16 JobType __attribute__ ((packed));
__u16 JobPosition __attribute__ ((packed));
__u16 JobControlFlags __attribute__ ((packed));
__u8 FileNameLen __attribute__ ((packed));
char JobFileName[13] __attribute__ ((packed));
__u32 JobFileHandle __attribute__ ((packed));
__u32 ServerStation __attribute__ ((packed));
__u32 ServerTaskNumber __attribute__ ((packed));
__u32 ServerObjectID __attribute__ ((packed));
char JobTextDescription[50] __attribute__ ((packed));
char ClientRecordArea[152] __attribute__ ((packed));
};
struct queue_job {
struct nw_queue_job_entry j;
__u8 file_handle[6];
};
#define QJE_OPER_HOLD 0x80
#define QJE_USER_HOLD 0x40
#define QJE_ENTRYOPEN 0x20
#define QJE_SERV_RESTART 0x10
#define QJE_SERV_AUTO 0x08
/* ClientRecordArea for print jobs */
struct print_job_record {
__u8 Version __attribute__ ((packed));
__u16 TabSize __attribute__ ((packed));
__u16 Copies __attribute__ ((packed));
__u8 CtrlFlags __attribute__ ((packed));
__u16 Lines __attribute__ ((packed));
__u16 Rows __attribute__ ((packed));
char FormName[16] __attribute__ ((packed));
__u8 Reserved[6] __attribute__ ((packed));
char Banner[13] __attribute__ ((packed));
char FnameBanner[13] __attribute__ ((packed));
char FnameHeader[14] __attribute__ ((packed));
char Path[80] __attribute__ ((packed));
};
#endif /* _LINUX_NCP_H */

149
kernel-1.3/linux/ncp_fs.h Normal file
View File

@@ -0,0 +1,149 @@
/*
* ncp_fs.h
*
* Copyright (C) 1995 by Volker Lendecke
*
*/
#ifndef _LINUX_NCP_FS_H
#define _LINUX_NCP_FS_H
#include <linux/fs.h>
#include <linux/in.h>
#include <linux/types.h>
#include <linux/ncp_mount.h>
#include <linux/ncp_fs_sb.h>
#include <linux/ncp_fs_i.h>
/*
* ioctl commands
*/
struct ncp_ioctl_request {
unsigned int function;
unsigned int size;
char *data;
};
#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.
*/
#define NCP_PACKET_SIZE 4070
#define NCP_MAXPATHLEN 255
#define NCP_MAXNAMELEN 14
#ifdef __KERNEL__
/* The readdir cache size controls how many directory entries are
* cached.
*/
#define NCP_READDIR_CACHE_SIZE 64
#define NCP_MAX_RPC_TIMEOUT (60) /* 6 seconds */
/* Guess, what 0x564c is :-) */
#define NCP_SUPER_MAGIC 0x564c
#define NCP_SBP(sb) ((struct ncp_server *)((sb)->u.generic_sbp))
#define NCP_INOP(inode) ((struct ncp_inode_info *)((inode)->u.generic_ip))
#define NCP_SERVER(inode) NCP_SBP((inode)->i_sb)
#define NCP_FINFO(inode) (&(NCP_INOP(inode)->finfo))
#define NCP_ISTRUCT(inode) (&(NCP_FINFO(inode)->i))
static inline int min(int a, int b) {
return a<b ? a : b;
}
#ifdef DEBUG_NCP_MALLOC
#include <linux/malloc.h>
extern int ncp_malloced;
extern int ncp_current_malloced;
static inline void *
ncp_kmalloc(unsigned int size, int priority)
{
ncp_malloced += 1;
ncp_current_malloced += 1;
return kmalloc(size, priority);
}
static inline void
ncp_kfree_s(void *obj, int size)
{
ncp_current_malloced -= 1;
kfree_s(obj, size);
}
#else /* DEBUG_NCP_MALLOC */
#define ncp_kmalloc(s,p) kmalloc(s,p)
#define ncp_kfree_s(o,s) kfree_s(o,s)
#endif /* DEBUG_NCP_MALLOC */
#if DEBUG_NCP > 0
#define DPRINTK(format, args...) printk(format , ## args)
#else
#define DPRINTK(format, args...)
#endif
#if DEBUG_NCP > 1
#define DDPRINTK(format, args...) printk(format , ## args)
#else
#define DDPRINTK(format, args...)
#endif
/* linux/fs/ncpfs/file.c */
extern struct inode_operations ncp_file_inode_operations;
int ncp_make_open(struct inode *i, int right);
/* linux/fs/ncpfs/dir.c */
extern struct inode_operations ncp_dir_inode_operations;
void ncp_free_inode_info(struct ncp_inode_info *i);
void ncp_free_all_inodes(struct ncp_server *server);
void ncp_init_root(struct ncp_server *server);
int ncp_stat_root(struct ncp_server *server);
void ncp_init_dir_cache(void);
void ncp_invalid_dir_cache(unsigned long ino);
void ncp_invalidate_all_inodes(struct ncp_server *server);
void ncp_free_dir_cache(void);
int ncp_date_dos2unix(__u16 time, __u16 date);
void ncp_date_unix2dos(int unix_date, __u16 *time, __u16 *date);
/* linux/fs/ncpfs/ioctl.c */
int ncp_ioctl (struct inode * inode, struct file * filp,
unsigned int cmd, unsigned long arg);
/* linux/fs/ncpfs/inode.c */
struct super_block *ncp_read_super(struct super_block *sb,
void *raw_data, int silent);
void ncp_invalidate_connection(struct ncp_server *server);
int ncp_conn_is_valid(struct ncp_server *server);
/* linux/fs/ncpfs/sock.c */
int ncp_request(struct ncp_server *server, int function);
int ncp_connect(struct ncp_server *server);
int ncp_disconnect(struct ncp_server *server);
int ncp_catch_watchdog(struct ncp_server *server);
int ncp_dont_catch_watchdog(struct ncp_server *server);
void ncp_lock_server(struct ncp_server *server);
void ncp_unlock_server(struct ncp_server *server);
/* linux/fs/ncpfs/mmap.c */
int ncp_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma);
#endif /* __KERNEL__ */
#endif /* _LINUX_NCP_FS_H */

View File

@@ -0,0 +1,35 @@
/*
* ncp_fs_i.h
*
* Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
*
*/
#ifndef _LINUX_NCP_FS_I
#define _LINUX_NCP_FS_I
#include <linux/ncp.h>
#ifdef __KERNEL__
enum ncp_inode_state {
INODE_VALID = 19, /* Inode currently in use */
INODE_LOOKED_UP, /* directly before iget */
INODE_CACHED, /* in a path to an inode which is in use */
INODE_INVALID
};
/*
* ncp fs inode data (in memory only)
*/
struct ncp_inode_info {
enum ncp_inode_state state;
int nused; /* for directories:
number of references in memory */
struct ncp_inode_info *dir;
struct ncp_inode_info *next, *prev;
struct nw_file_info finfo;
};
#endif
#endif

View File

@@ -0,0 +1,61 @@
/*
* ncp_fs_sb.h
*
* Copyright (C) 1995 by Volker Lendecke
*
*/
#ifndef _NCP_FS_SB
#define _NCP_FS_SB
#include <linux/ncp_mount.h>
#include <linux/types.h>
#ifdef __KERNEL__
#define NCP_DEFAULT_BUFSIZE 1024
struct ncp_server {
struct ncp_mount_data m; /* Nearly all of the mount data is of
interest for us later, so we store
it completely. */
struct file *ncp_filp; /* File pointer to ncp socket */
struct file *wdog_filp; /* File pointer to wdog socket */
void *data_ready; /* The wdog socket gets a new
data_ready callback. We store the
old one for checking purposes and
to reset it on unmounting. */
u8 sequence;
u8 task;
u16 connection; /* Remote connection number */
u8 completion; /* Status message from server */
u8 conn_status; /* Bit 4 = 1 ==> Server going down, no
requests allowed anymore */
int buffer_size; /* Negotiated bufsize */
int reply_size; /* Size of last reply */
int packet_size;
unsigned char *packet; /* Here we prepare requests and
receive replies */
int lock; /* To prevent mismatch in protocols. */
struct wait_queue *wait;
int current_size; /* for packet preparation */
int has_subfunction;
int ncp_reply_size;
struct ncp_inode_info root;
char root_path; /* '\0' */
};
#endif /* __KERNEL__ */
#endif

View File

@@ -0,0 +1,49 @@
/*
* ncp_mount.h
*
* Copyright (C) 1995 by Volker Lendecke
*
*/
#ifndef _LINUX_NCP_MOUNT_H
#define _LINUX_NCP_MOUNT_H
#include <linux/types.h>
#include <linux/ipx.h>
#include <linux/ncp.h>
#include <linux/ncp_fs_i.h>
#define NCP_MOUNT_VERSION 1
#define NCP_USERNAME_LEN (NCP_BINDERY_NAME_LEN)
#define NCP_PASSWORD_LEN 20
/* Values for flags */
#define NCP_MOUNT_SOFT 0x0001
#define NCP_MOUNT_INTR 0x0002
struct ncp_mount_data {
int version;
unsigned int ncp_fd; /* The socket to the ncp port */
unsigned int wdog_fd; /* Watchdog packets come here */
unsigned int message_fd; /* Not used yet, maybe for messages */
uid_t mounted_uid; /* Who may umount() this filesystem? */
struct sockaddr_ipx serv_addr;
unsigned char server_name[49];
unsigned char username[NCP_USERNAME_LEN+1];
unsigned char password[NCP_PASSWORD_LEN+1];
unsigned int time_out; /* How long should I wait after
sending a NCP request? */
unsigned int retry_count; /* And how often should I retry? */
unsigned int flags;
uid_t uid;
gid_t gid;
mode_t file_mode;
mode_t dir_mode;
};
#endif

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

File diff suppressed because it is too large Load Diff

247
kernel-1.3/src/file.c Normal file
View File

@@ -0,0 +1,247 @@
/*
* file.c
*
* Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
*
*/
#include <asm/segment.h>
#include <asm/system.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/stat.h>
#include <linux/mm.h>
#include <linux/ncp_fs.h>
#include "ncplib.h"
#include <linux/malloc.h>
static int
ncp_fsync(struct inode *inode, struct file *file)
{
return 0;
}
int
ncp_make_open(struct inode *i, int right)
{
struct nw_file_info *finfo;
if (i == NULL) {
printk("ncp_make_open: got NULL inode\n");
return -EINVAL;
}
finfo = NCP_FINFO(i);
DPRINTK("ncp_make_open: dirent->opened = %d\n", finfo->opened);
if (finfo->opened == 0) {
/* tries max. rights */
if (ncp_open_create_file_or_subdir(NCP_SERVER(i),
NULL, NULL,
OC_MODE_OPEN, 0,
AR_READ | AR_WRITE,
finfo) == 0) {
finfo->access = O_RDWR;
}
else if (ncp_open_create_file_or_subdir(NCP_SERVER(i),
NULL, NULL,
OC_MODE_OPEN, 0,
AR_READ,
finfo) == 0) {
finfo->access = O_RDONLY;
} else {
return -EACCES;
}
}
if ( ((right == O_RDONLY) && ( (finfo->access == O_RDONLY)
|| (finfo->access == O_RDWR)))
|| ((right == O_WRONLY) && ( (finfo->access == O_WRONLY)
|| (finfo->access == O_RDWR)))
|| ((right == O_RDWR) && (finfo->access == O_RDWR)))
return 0;
return -EACCES;
}
static int
ncp_file_read(struct inode *inode, struct file *file, char *buf, int count)
{
int bufsize, to_read, already_read;
off_t pos;
int errno;
DPRINTK("ncp_file_read: enter %s\n", NCP_ISTRUCT(inode)->entryName);
if (!inode) {
DPRINTK("ncp_file_read: inode = NULL\n");
return -EINVAL;
}
if (!S_ISREG(inode->i_mode)) {
DPRINTK("ncp_file_read: read from non-file, mode %07o\n",
inode->i_mode);
return -EINVAL;
}
pos = file->f_pos;
if (pos + count > inode->i_size)
count = inode->i_size - pos;
if (count <= 0)
return 0;
if ((errno = ncp_make_open(inode, O_RDONLY)) != 0)
return errno;
bufsize = NCP_SERVER(inode)->buffer_size;
already_read = 0;
/* First read in as much as possible for each bufsize. */
while (already_read < count) {
int read_this_time;
if ((pos % bufsize) != 0) {
to_read = bufsize - (pos % bufsize);
} else {
to_read = bufsize;
}
to_read = min(to_read, count - already_read);
if (ncp_read(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
pos, to_read, buf, &read_this_time) != 0) {
return -EIO; /* This is not exact, i know.. */
}
pos += read_this_time;
buf += read_this_time;
already_read += read_this_time;
if (read_this_time < to_read) {
break;
}
}
file->f_pos = pos;
if (!IS_RDONLY(inode)) inode->i_atime = CURRENT_TIME;
inode->i_dirt = 1;
DPRINTK("ncp_file_read: exit %s\n", NCP_ISTRUCT(inode)->entryName);
return already_read;
}
static int
ncp_file_write(struct inode *inode, struct file *file, const char *buf,
int count)
{
int bufsize, to_write, already_written;
off_t pos;
int errno;
if (!inode) {
DPRINTK("ncp_file_write: inode = NULL\n");
return -EINVAL;
}
if (!S_ISREG(inode->i_mode)) {
DPRINTK("ncp_file_write: write to non-file, mode %07o\n",
inode->i_mode);
return -EINVAL;
}
DPRINTK("ncp_file_write: enter %s\n", NCP_ISTRUCT(inode)->entryName);
if (count <= 0)
return 0;
if ((errno = ncp_make_open(inode, O_RDWR)) != 0)
return errno;
pos = file->f_pos;
if (file->f_flags & O_APPEND)
pos = inode->i_size;
bufsize = NCP_SERVER(inode)->buffer_size;
already_written = 0;
while (already_written < count) {
int written_this_time;
if ((pos % bufsize) != 0) {
to_write = bufsize - (pos % bufsize);
} else {
to_write = bufsize;
}
to_write = min(to_write, count - already_written);
if (ncp_write(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
pos, to_write, buf, &written_this_time) != 0) {
return -EIO;
}
pos += written_this_time;
buf += written_this_time;
already_written += written_this_time;
if (written_this_time < to_write) {
break;
}
}
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_dirt = 1;
file->f_pos = pos;
if (pos > inode->i_size) {
inode->i_size = pos;
}
DPRINTK("ncp_file_write: exit %s\n", NCP_ISTRUCT(inode)->entryName);
return already_written;
}
static struct file_operations ncp_file_operations = {
NULL, /* lseek - default */
ncp_file_read, /* read */
ncp_file_write, /* write */
NULL, /* readdir - bad */
NULL, /* select - default */
ncp_ioctl, /* ioctl */
NULL, /* mmap */
NULL, /* open */
NULL, /* release */
ncp_fsync, /* fsync */
};
struct inode_operations ncp_file_inode_operations = {
&ncp_file_operations, /* default file operations */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
NULL /* truncate */
};

View File

@@ -5,14 +5,7 @@
*
*/
#include <linux/config.h>
#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
#else
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
#endif
#include <asm/system.h>
#include <asm/segment.h>
@@ -34,15 +27,17 @@ extern int close_fp(struct file *filp);
static void ncp_put_inode(struct inode *);
static void ncp_read_inode(struct inode *);
static void ncp_put_super(struct super_block *);
static void ncp_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
static int ncp_notify_change(struct inode *inode, struct iattr *attr);
static struct super_operations ncp_sops = {
ncp_read_inode, /* read inode */
NULL, /* notify change */
ncp_notify_change, /* notify change */
NULL, /* write inode */
ncp_put_inode, /* put inode */
ncp_put_super, /* put superblock */
NULL, /* write superblock */
NULL, /* stat filesystem */
ncp_statfs, /* stat filesystem */
NULL
};
@@ -75,7 +70,7 @@ ncp_read_inode(struct inode *inode)
else {
printk("ncp_read_inode: "
"state != INODE_LOOKED_UP\n");
return;
goto good;
}
}
check_info = check_info->next;
@@ -87,22 +82,30 @@ ncp_read_inode(struct inode *inode)
return;
good:
DDPRINTK("ncp_read_inode: read entry %s\n",
inode_info->finfo.i.entryName);
#endif
inode_info->state = INODE_VALID;
NCP_INOP(inode) = inode_info;
if (NCP_INOP(inode)->finfo.attr & aDIR)
if (NCP_ISTRUCT(inode)->attributes & aDIR) {
inode->i_mode = NCP_SERVER(inode)->m.dir_mode;
/* for directories in dataStreamSize seems to be some
Object ID ??? */
inode->i_size = 0;
}
else
{
inode->i_mode = NCP_SERVER(inode)->m.file_mode;
inode->i_size = NCP_ISTRUCT(inode)->dataStreamSize;
}
DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
inode->i_nlink = 1;
inode->i_uid = NCP_SERVER(inode)->m.uid;
inode->i_gid = NCP_SERVER(inode)->m.gid;
inode->i_size = NCP_INOP(inode)->finfo.size;
inode->i_blksize = 1024;
inode->i_rdev = 0;
if ((inode->i_blksize != 0) && (inode->i_size != 0))
@@ -111,9 +114,12 @@ ncp_read_inode(struct inode *inode)
else
inode->i_blocks = 0;
inode->i_mtime = NCP_INOP(inode)->finfo.mtime;
inode->i_ctime = NCP_INOP(inode)->finfo.ctime;
inode->i_atime = NCP_INOP(inode)->finfo.atime;
inode->i_mtime = ncp_date_dos2unix(NCP_ISTRUCT(inode)->modifyTime,
NCP_ISTRUCT(inode)->modifyDate);
inode->i_ctime = ncp_date_dos2unix(NCP_ISTRUCT(inode)->creationTime,
NCP_ISTRUCT(inode)->creationDate);
inode->i_atime = ncp_date_dos2unix(0,
NCP_ISTRUCT(inode)->lastAccessDate);
if (S_ISREG(inode->i_mode))
inode->i_op = &ncp_file_inode_operations;
@@ -127,11 +133,11 @@ ncp_read_inode(struct inode *inode)
static void
ncp_put_inode(struct inode *inode)
{
struct ncp_dirent *finfo = NCP_FINFO(inode);
struct nw_file_info *finfo = NCP_FINFO(inode);
if (finfo->opened != 0) {
if (ncp_close_file(NCP_SERVER(inode), finfo->file_id) != 0) {
if (ncp_close_file(NCP_SERVER(inode), finfo->file_handle)!=0) {
/* We can't do anything but complain. */
printk("ncp_put_inode: could not close\n");
}
@@ -276,12 +282,13 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
if (ncp_login_user(server, server->m.username,
/* if (ncp_login_user(server, server->m.username,
server->m.password) != 0) {
sb->s_dev = 0;
printk("ncp_read_super: login failed\n");
goto disconnect;
}
*/
MOD_INC_USE_COUNT;
return sb;
@@ -328,6 +335,110 @@ ncp_put_super(struct super_block *sb)
MOD_DEC_USE_COUNT;
}
static void
ncp_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
{
struct statfs tmp;
/* We cannot say how much disk space is left on a mounted
NetWare Server, because free space is distributed over
volumes, and the current user might have disk quotas. So
free space is not that simple to determine. Our decision
here is to err conservatively. */
tmp.f_type = NCP_SUPER_MAGIC;
tmp.f_bsize = 512;
tmp.f_blocks = 0;
tmp.f_bfree = 0;
tmp.f_bavail = 0;
tmp.f_files = -1;
tmp.f_ffree = -1;
tmp.f_namelen = 12;
memcpy_tofs(buf, &tmp, bufsiz);
}
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;
if (((attr->ia_valid & ATTR_UID) &&
(attr->ia_uid != NCP_SERVER(inode)->m.uid)))
return -EPERM;
if (((attr->ia_valid & ATTR_GID) &&
(attr->ia_uid != NCP_SERVER(inode)->m.gid)))
return -EPERM;
if (((attr->ia_valid & ATTR_MODE) &&
(attr->ia_mode &
~(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;
DPRINTK("ncpfs: trying to change size of %s to %ld\n",
NCP_ISTRUCT(inode)->entryName, attr->ia_size);
if ((result = ncp_make_open(inode, O_RDWR)) < 0) {
return -EACCES;
}
ncp_write(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
attr->ia_size, 0, "", &written);
/* According to ndir, the changes only take effect after
closing the file */
ncp_close_file(NCP_SERVER(inode),
NCP_FINFO(inode)->file_handle);
NCP_FINFO(inode)->opened = 0;
result = 0;
}
ncp_invalid_dir_cache((unsigned long)(NCP_INOP(inode)->dir));
return result;
}
#ifdef DEBUG_NCP_MALLOC
int ncp_malloced;
@@ -336,11 +447,6 @@ int ncp_current_malloced;
#ifdef MODULE
char kernel_version[] = UTS_RELEASE;
/* looks ugly, taken from gcc-info */
/* static void *shut_up_gcc = (&shut_up_gcc, kernel_version);*/
static struct file_system_type ncp_fs_type = {
ncp_read_super, "ncpfs", 0, NULL
};

88
kernel-1.3/src/ioctl.c Normal file
View File

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

579
kernel-1.3/src/ncplib.c Normal file
View File

@@ -0,0 +1,579 @@
#include "ncplib.h"
typedef __u8 byte;
typedef __u16 word;
typedef __u32 dword;
static void
assert_server_locked(struct ncp_server *server)
{
if (server->lock == 0) {
DPRINTK("ncpfs: server not locked!\n");
}
}
static void
ncp_add_byte(struct ncp_server *server, byte x)
{
assert_server_locked(server);
*(byte *)(&(server->packet[server->current_size])) = x;
server->current_size += 1;
return;
}
static void
ncp_add_word(struct ncp_server *server, word x)
{
assert_server_locked(server);
*(word *)(&(server->packet[server->current_size])) = x;
server->current_size += 2;
return;
}
static void
ncp_add_dword(struct ncp_server *server, dword x)
{
assert_server_locked(server);
*(dword *)(&(server->packet[server->current_size])) = x;
server->current_size += 4;
return;
}
static void
ncp_add_mem(struct ncp_server *server, const void *source, int size)
{
assert_server_locked(server);
memcpy(&(server->packet[server->current_size]), source, size);
server->current_size += size;
return;
}
static void
ncp_add_mem_fromfs(struct ncp_server *server, const char *source, int size)
{
assert_server_locked(server);
memcpy_fromfs(&(server->packet[server->current_size]), source, size);
server->current_size += size;
return;
}
static void
ncp_add_pstring(struct ncp_server *server, const char *s)
{
int len = strlen(s);
assert_server_locked(server);
if (len > 255) {
DPRINTK("ncpfs: string too long: %s\n", s);
len = 255;
}
ncp_add_byte(server, len);
ncp_add_mem(server, s, len);
return;
}
static void
ncp_init_request(struct ncp_server *server)
{
ncp_lock_server(server);
server->current_size = sizeof(struct ncp_request_header);
server->has_subfunction = 0;
}
static void
ncp_init_request_s(struct ncp_server *server, int subfunction)
{
ncp_init_request(server);
ncp_add_word(server, 0); /* preliminary size */
ncp_add_byte(server, subfunction);
server->has_subfunction = 1;
}
static char *
ncp_reply_data(struct ncp_server *server, int offset)
{
return &(server->packet[sizeof(struct ncp_reply_header) + offset]);
}
static byte
ncp_reply_byte(struct ncp_server *server, int offset)
{
return *(byte *)(ncp_reply_data(server, offset));
}
static word
ncp_reply_word(struct ncp_server *server, int offset)
{
return *(word *)(ncp_reply_data(server, offset));
}
static dword
ncp_reply_dword(struct ncp_server *server, int offset)
{
return *(dword *)(ncp_reply_data(server, offset));
}
int
ncp_negotiate_buffersize(struct ncp_server *server,
int size, int *target) {
int result;
ncp_init_request(server);
ncp_add_word(server, htons(size));
if ((result = ncp_request(server, 33)) != 0) {
ncp_unlock_server(server);
return result;
}
*target =min(ntohs(ncp_reply_word(server, 0)), size);
ncp_unlock_server(server);
return 0;
}
int
ncp_get_volume_info_with_number(struct ncp_server *server, int n,
struct ncp_volume_info *target)
{
int result;
int len;
ncp_init_request_s(server, 44);
ncp_add_byte(server, n);
if ((result = ncp_request(server, 22)) != 0) {
ncp_unlock_server(server);
return result;
}
target->total_blocks = ncp_reply_dword(server, 0);
target->free_blocks = ncp_reply_dword(server, 4);
target->purgeable_blocks = ncp_reply_dword(server, 8);
target->not_yet_purgeable_blocks = ncp_reply_dword(server, 12);
target->total_dir_entries = ncp_reply_dword(server, 16);
target->available_dir_entries = ncp_reply_dword(server, 20);
target->sectors_per_block = ncp_reply_byte(server, 28);
memset(&(target->volume_name), 0, sizeof(target->volume_name));
len = ncp_reply_byte(server, 29);
if (len > NCP_VOLNAME_LEN) {
DPRINTK("ncpfs: volume name too long: %d\n", len);
ncp_unlock_server(server);
return -EIO;
}
memcpy(&(target->volume_name), ncp_reply_data(server, 30), len);
ncp_unlock_server(server);
return 0;
}
int
ncp_get_volume_number(struct ncp_server *server, const char *name, int *target)
{
int result;
ncp_init_request_s(server, 5);
ncp_add_pstring(server, name);
if ((result = ncp_request(server, 22)) != 0) {
ncp_unlock_server(server);
return result;
}
*target = ncp_reply_byte(server, 0);
ncp_unlock_server(server);
return 0;
}
int
ncp_close_file(struct ncp_server *server, const char *file_id)
{
int result;
ncp_init_request(server);
ncp_add_byte(server, 0);
ncp_add_mem(server, file_id, 6);
if ((result = ncp_request(server, 66)) != 0) {
ncp_unlock_server(server);
return result;
}
ncp_unlock_server(server);
return 0;
}
static void
ncp_add_handle_path(struct ncp_server *server,
__u8 vol_num,
__u32 dir_base, int have_dir_base,
char *path)
{
ncp_add_byte(server, vol_num);
ncp_add_dword(server, dir_base);
if (have_dir_base != 0) {
ncp_add_byte(server, 1); /* dir_base */
} else {
ncp_add_byte(server, 0xff); /* no handle */
}
if (path != NULL) {
ncp_add_byte(server, 1); /* 1 component */
ncp_add_pstring(server, path);
}
else
{
ncp_add_byte(server, 0);
}
}
static void
ncp_extract_file_info(void *structure, struct nw_info_struct *target)
{
__u8 *name_len;
const int info_struct_size = sizeof(struct nw_info_struct) - 257;
memcpy(target, structure, info_struct_size);
name_len = structure + info_struct_size;
target->nameLen = *name_len;
strncpy(target->entryName, name_len+1, *name_len);
target->entryName[*name_len] = '\0';
return;
}
int
ncp_do_lookup(struct ncp_server *server,
struct nw_info_struct *dir,
char *path, /* may only be one component */
struct nw_info_struct *target)
{
__u8 vol_num;
__u32 dir_base;
int result;
char *volname = NULL;
if (target == NULL) {
return -EINVAL;
}
if (dir == NULL) {
DDPRINTK("ncp_do_lookup: looking up vol %s\n", path);
/* Access a volume's root directory */
ncp_init_request(server);
ncp_add_byte(server, 22); /* subfunction */
ncp_add_byte(server, 0); /* dos name space */
ncp_add_byte(server, 0); /* reserved */
ncp_add_byte(server, 0); /* reserved */
ncp_add_byte(server, 0); /* reserved */
ncp_add_handle_path(server, 0, 0, 0, /* no handle */
path);
if ((result = ncp_request(server, 87)) != 0) {
ncp_unlock_server(server);
return result;
}
dir_base = ncp_reply_dword(server, 4);
vol_num = ncp_reply_byte (server, 8);
ncp_unlock_server(server);
volname = path;
path = NULL;
}
else
{
vol_num = dir->volNumber;
dir_base = dir->DosDirNum;
}
ncp_init_request(server);
ncp_add_byte(server, 6); /* subfunction */
ncp_add_byte(server, 0); /* dos name space */
ncp_add_byte(server, 0); /* dos name space as dest */
ncp_add_word(server, 0xff); /* get all */
ncp_add_dword(server, RIM_ALL);
ncp_add_handle_path(server, vol_num, dir_base, 1,
path);
if ((result = ncp_request(server, 87)) != 0) {
ncp_unlock_server(server);
return result;
}
ncp_extract_file_info(ncp_reply_data(server, 0), target);
if (volname != NULL) {
target->nameLen = strlen(volname);
strcpy(target->entryName, volname);
}
ncp_unlock_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)
{
int result;
ncp_init_request(server);
ncp_add_byte(server, 8); /* 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_handle_path(server, dir->volNumber,
dir->DosDirNum, 1, name);
if ((result = ncp_request(server, 87)) != 0) {
ncp_unlock_server(server);
return result;
}
ncp_unlock_server(server);
return 0;
}
static inline void
ConvertToNWfromDWORD ( __u32 sfd , __u8 ret[6] )
{
__u16 *dest = (__u16 *) ret;
memcpy(&(dest[1]), &sfd, 4);
dest[0] = dest[1] + 1;
return;
}
/* If both dir and name are NULL, then in target there's already a
looked-up entry that wants to be opened. */
int
ncp_open_create_file_or_subdir(struct ncp_server *server,
struct nw_info_struct *dir, char *name,
int open_create_mode,
__u32 create_attributes,
int desired_acc_rights,
struct nw_file_info *target)
{
int result;
ncp_init_request(server);
ncp_add_byte(server, 1); /* subfunction */
ncp_add_byte(server, 0); /* dos name space */
ncp_add_byte(server, open_create_mode);
ncp_add_word(server, 0x8006);
ncp_add_dword(server, RIM_ALL);
ncp_add_dword(server, create_attributes);
/* The desired acc rights seem to be the inherited rights mask
for directories */
ncp_add_word(server, desired_acc_rights);
if (dir != NULL) {
ncp_add_handle_path(server, dir->volNumber,
dir->DosDirNum, 1, name);
} else {
ncp_add_handle_path(server,
target->i.volNumber, target->i.DosDirNum,
1, NULL);
}
if ((result = ncp_request(server, 87)) != 0) {
ncp_unlock_server(server);
return result;
}
target->opened = 1;
target->server_file_handle = ncp_reply_dword(server, 0);
target->open_create_action = ncp_reply_byte(server, 4);
if (dir != NULL) {
/* in target there's a new finfo to fill */
ncp_extract_file_info(ncp_reply_data(server, 5), &(target->i));
}
ConvertToNWfromDWORD(target->server_file_handle, target->file_handle);
ncp_unlock_server(server);
return 0;
}
int
ncp_initialize_search(struct ncp_server *server,
struct nw_info_struct *dir,
struct nw_search_sequence *target)
{
int result;
ncp_init_request(server);
ncp_add_byte(server, 2); /* subfunction */
ncp_add_byte(server, 0); /* dos name space */
ncp_add_byte(server, 0); /* reserved */
ncp_add_handle_path(server, dir->volNumber, dir->DosDirNum, 1, NULL);
if ((result = ncp_request(server, 87)) != 0) {
ncp_unlock_server(server);
return result;
}
memcpy(target, ncp_reply_data(server, 0), sizeof(*target));
ncp_unlock_server(server);
return 0;
}
/* Search for everything */
int
ncp_search_for_file_or_subdir(struct ncp_server *server,
struct nw_search_sequence *seq,
struct nw_info_struct *target)
{
int result;
ncp_init_request(server);
ncp_add_byte(server, 3); /* subfunction */
ncp_add_byte(server, 0); /* dos name space */
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, seq, 9);
ncp_add_byte(server, 2); /* 2 byte pattern */
ncp_add_byte(server, 0xff); /* following is a wildcard */
ncp_add_byte(server, '*');
if ((result = ncp_request(server, 87)) != 0) {
ncp_unlock_server(server);
return result;
}
memcpy(seq, ncp_reply_data(server, 0), sizeof(*seq));
ncp_extract_file_info(ncp_reply_data(server, 10), target);
ncp_unlock_server(server);
return 0;
}
int
ncp_ren_or_mov_file_or_subdir(struct ncp_server *server,
struct nw_info_struct *old_dir, char *old_name,
struct nw_info_struct *new_dir, char *new_name)
{
int result;
if ( (old_dir == NULL) || (old_name == NULL)
|| (new_dir == NULL) || (new_name == NULL))
return -EINVAL;
ncp_init_request(server);
ncp_add_byte(server, 4); /* subfunction */
ncp_add_byte(server, 0); /* dos name space */
ncp_add_byte(server, 1); /* rename flag */
ncp_add_word(server, 0x8006); /* search attributes */
/* source Handle Path */
ncp_add_byte(server, old_dir->volNumber);
ncp_add_dword(server, old_dir->DosDirNum);
ncp_add_byte(server, 1);
ncp_add_byte(server, 1); /* 1 source component */
/* dest Handle Path */
ncp_add_byte(server, new_dir->volNumber);
ncp_add_dword(server, new_dir->DosDirNum);
ncp_add_byte(server, 1);
ncp_add_byte(server, 1); /* 1 destination component */
/* source path string */
ncp_add_pstring(server, old_name);
/* dest path string */
ncp_add_pstring(server, new_name);
result = ncp_request(server, 87);
ncp_unlock_server(server);
return result;
}
/* We have to transfer to/from user space */
int
ncp_read(struct ncp_server *server, const char *file_id,
__u32 offset, __u16 to_read,
char *target, int *bytes_read)
{
int result;
ncp_init_request(server);
ncp_add_byte(server, 0);
ncp_add_mem(server, file_id, 6);
ncp_add_dword(server, htonl(offset));
ncp_add_word(server, htons(to_read));
if ((result = ncp_request(server, 72)) != 0) {
ncp_unlock_server(server);
return result;
}
*bytes_read = ntohs(ncp_reply_word(server, 0));
memcpy_tofs(target, ncp_reply_data(server, 2), *bytes_read);
ncp_unlock_server(server);
return 0;
}
int
ncp_write(struct ncp_server *server, const char *file_id,
__u32 offset, __u16 to_write,
const char *source, int *bytes_written)
{
int result;
ncp_init_request(server);
ncp_add_byte(server, 0);
ncp_add_mem(server, file_id, 6);
ncp_add_dword(server, htonl(offset));
ncp_add_word(server, htons(to_write));
ncp_add_mem_fromfs(server, source, to_write);
if ((result = ncp_request(server, 73)) != 0) {
ncp_unlock_server(server);
return result;
}
*bytes_written = to_write;
ncp_unlock_server(server);
return 0;
}

156
kernel-1.3/src/ncplib.h Normal file
View File

@@ -0,0 +1,156 @@
#ifndef _NCPLIB_H
#define _NCPLIB_H
#include <linux/fs.h>
#include <linux/ncp.h>
#include <linux/ncp_fs.h>
#include <linux/ncp_fs_sb.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/malloc.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <asm/segment.h>
#include <asm/string.h>
#include <linux/ncp.h>
int
ncp_negotiate_buffersize(struct ncp_server *server, int size,
int *target);
int
ncp_get_encryption_key(struct ncp_server *server,
char *target);
int
ncp_get_bindery_object_id(struct ncp_server *server,
int object_type, char *object_name,
struct ncp_bindery_object *target);
int
ncp_login_encrypted(struct ncp_server *server,
struct ncp_bindery_object *object,
unsigned char *key,
unsigned char *passwd);
int
ncp_login_user(struct ncp_server *server,
unsigned char *username,
unsigned char *password);
int
ncp_get_volume_info_with_number(struct ncp_server *server, int n,
struct ncp_volume_info *target);
int
ncp_get_volume_number(struct ncp_server *server, const char *name,
int *target);
int
ncp_file_search_init(struct ncp_server *server,
int dir_handle, const char *path,
struct ncp_filesearch_info *target);
int
ncp_file_search_continue(struct ncp_server *server,
struct ncp_filesearch_info *fsinfo,
int attributes, const char *path,
struct ncp_file_info *target);
int
ncp_get_finfo(struct ncp_server *server,
int dir_handle, const char *path, const char *name,
struct ncp_file_info *target);
int
ncp_open_file(struct ncp_server *server,
int dir_handle, const char *path,
int attr, int access,
struct ncp_file_info *target);
int
ncp_close_file(struct ncp_server *server, const char *file_id);
int
ncp_create_newfile(struct ncp_server *server,
int dir_handle, const char *path,
int attr,
struct ncp_file_info *target);
int
ncp_create_file(struct ncp_server *server,
int dir_handle, const char *path,
int attr,
struct ncp_file_info *target);
int
ncp_erase_file(struct ncp_server *server,
int dir_handle, const char *path,
int attr);
int
ncp_rename_file(struct ncp_server *server,
int old_handle, const char *old_path,
int attr,
int new_handle, const char *new_path);
int
ncp_create_directory(struct ncp_server *server,
int dir_handle, const char *path,
int inherit_mask);
int
ncp_delete_directory(struct ncp_server *server,
int dir_handle, const char *path);
int
ncp_rename_directory(struct ncp_server *server,
int dir_handle,
const char *old_path, const char *new_path);
int
ncp_read(struct ncp_server *server, const char *file_id,
__u32 offset, __u16 to_read,
char *target, int *bytes_read);
int
ncp_write(struct ncp_server *server, const char *file_id,
__u32 offset, __u16 to_write,
const char *source, int *bytes_written);
int
ncp_do_lookup(struct ncp_server *server,
struct nw_info_struct *dir,
char *path, /* may only be one component */
struct nw_info_struct *target);
int
ncp_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,
int open_create_mode,
__u32 create_attributes,
int desired_acc_rights,
struct nw_file_info *target);
int
ncp_initialize_search(struct ncp_server *server,
struct nw_info_struct *dir,
struct nw_search_sequence *target);
int
ncp_search_for_file_or_subdir(struct ncp_server *server,
struct nw_search_sequence *seq,
struct nw_info_struct *target);
int
ncp_ren_or_mov_file_or_subdir(struct ncp_server *server,
struct nw_info_struct *old_dir, char *old_name,
struct nw_info_struct *new_dir, char *new_name);
#endif /* _NCPLIB_H */

570
kernel-1.3/src/sock.c Normal file
View File

@@ -0,0 +1,570 @@
/*
* linux/fs/ncp/sock.c
*
* Copyright (C) 1992, 1993 Rick Sladkey
*
* Modified 1995 by Volker Lendecke to be usable for ncp
*
*/
#include <linux/sched.h>
#include <linux/ncp_fs.h>
#include <linux/errno.h>
#include <linux/socket.h>
#include <linux/fcntl.h>
#include <linux/stat.h>
#include <asm/segment.h>
#include <linux/in.h>
#include <linux/net.h>
#include <linux/mm.h>
#include <linux/netdevice.h>
#include <linux/ipx.h>
#include <linux/ncp.h>
#include <linux/ncp_fs.h>
#include <linux/ncp_fs_sb.h>
#include <net/sock.h>
#define _S(nr) (1<<((nr)-1))
static int _recvfrom(struct socket *sock, unsigned char *ubuf,
int size, int noblock, unsigned flags,
struct sockaddr_ipx *sa, int *addr_len)
{
struct iovec iov;
struct msghdr msg;
iov.iov_base = ubuf;
iov.iov_len = size;
msg.msg_name = (void *)sa;
msg.msg_namelen = 0;
if (addr_len)
msg.msg_namelen = *addr_len;
msg.msg_accrights = NULL;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
return sock->ops->recvmsg(sock, &msg, size, noblock, flags, addr_len);
}
static int _sendto(struct socket *sock, const void *buff,
int len, int nonblock, unsigned flags,
struct sockaddr_ipx *sa, int addr_len)
{
struct iovec iov;
struct msghdr msg;
iov.iov_base = (void *)buff;
iov.iov_len = len;
msg.msg_name = (void *)sa;
msg.msg_namelen = addr_len;
msg.msg_accrights = NULL;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
return sock->ops->sendmsg(sock, &msg, len, nonblock, flags);
}
static void
ncp_wdog_data_ready(struct sock *sk, int len)
{
struct socket *sock = sk->socket;
if (!sk->dead)
{
unsigned char packet_buf[2];
struct sockaddr_ipx sender;
int addr_len = sizeof(struct sockaddr_ipx);
int result;
unsigned short fs;
fs = get_fs();
set_fs(get_ds());
result = _recvfrom(sock, (void *)packet_buf, 2, 1, 0,
&sender, &addr_len);
if ( (result != 2)
|| (packet_buf[1] != '?')
/* How to check connection number here? */
)
{
/* Error, throw away the complete packet */
_recvfrom(sock, (void *)packet_buf, 2, 1, 0,
&sender, &addr_len);
printk("ncpfs: got strange packet on watchdog "
"socket\n");
} else {
int result;
DPRINTK("ncpfs: got watchdog from:\n");
DPRINTK("ncpfs: %08lX:%02X%02X%02X%02X%02X%02X:%04X,"
" conn:%02X,type:%c\n",
htonl(sender.sipx_network),
sender.sipx_node[0], sender.sipx_node[1],
sender.sipx_node[2], sender.sipx_node[3],
sender.sipx_node[4], sender.sipx_node[5],
ntohs(sender.sipx_port),
packet_buf[0], packet_buf[1]);
packet_buf[1] = 'Y';
result = _sendto(sock, (void *)packet_buf, 2, 1, 0,
&sender, sizeof(sender));
DPRINTK("send result: %d\n", result);
}
set_fs(fs);
}
}
int
ncp_catch_watchdog(struct ncp_server *server)
{
struct file *file;
struct inode *inode;
struct socket *sock;
struct sock *sk;
if ( (server == NULL)
|| ((file = server->wdog_filp) == NULL)
|| ((inode = file->f_inode) == NULL)
|| (!S_ISSOCK(inode->i_mode))) {
printk("ncp_catch_watchdog: did not get valid server!\n");
server->data_ready = NULL;
return -EINVAL;
}
sock = &(inode->u.socket_i);
if (sock->type != SOCK_DGRAM) {
printk("ncp_catch_watchdog: did not get SOCK_STREAM\n");
server->data_ready = NULL;
return -EINVAL;
}
sk = (struct sock *)(sock->data);
if (sk == NULL) {
printk("ncp_catch_watchdog: sk == NULL");
server->data_ready = NULL;
return -EINVAL;
}
DDPRINTK("ncp_catch_watchdog.: sk->d_r = %x, server->d_r = %x\n",
(unsigned int)(sk->data_ready),
(unsigned int)(server->data_ready));
if (sk->data_ready == ncp_wdog_data_ready) {
printk("ncp_catch_watchdog: already done\n");
return -EINVAL;
}
server->data_ready = sk->data_ready;
sk->data_ready = ncp_wdog_data_ready;
return 0;
}
int
ncp_dont_catch_watchdog(struct ncp_server *server)
{
struct file *file;
struct inode *inode;
struct socket *sock;
struct sock *sk;
if ( (server == NULL)
|| ((file = server->wdog_filp) == NULL)
|| ((inode = file->f_inode) == NULL)
|| (!S_ISSOCK(inode->i_mode))) {
printk("ncp_dont_catch_watchdog: "
"did not get valid server!\n");
return -EINVAL;
}
sock = &(inode->u.socket_i);
if (sock->type != SOCK_DGRAM) {
printk("ncp_dont_catch_watchdog: did not get SOCK_STREAM\n");
return -EINVAL;
}
sk = (struct sock *)(sock->data);
if (sk == NULL) {
printk("ncp_dont_catch_watchdog: sk == NULL");
return -EINVAL;
}
if (server->data_ready == NULL) {
printk("ncp_dont_catch_watchdog: "
"server->data_ready == NULL\n");
return -EINVAL;
}
if (sk->data_ready != ncp_wdog_data_ready) {
printk("ncp_dont_catch_watchdog: "
"sk->data_callback != ncp_data_callback\n");
return -EINVAL;
}
DDPRINTK("ncp_dont_catch_watchdog: sk->d_r = %x, server->d_r = %x\n",
(unsigned int)(sk->data_ready),
(unsigned int)(server->data_ready));
sk->data_ready = server->data_ready;
server->data_ready = NULL;
return 0;
}
#define NCP_SLACK_SPACE 1024
#define _S(nr) (1<<((nr)-1))
static int
do_ncp_rpc_call(struct ncp_server *server, int size)
{
struct file *file;
struct inode *inode;
struct socket *sock;
unsigned short fs;
int result;
char *start = server->packet;
select_table wait_table;
struct select_table_entry entry;
int (*select) (struct inode *, struct file *, int, select_table *);
int init_timeout, max_timeout;
int timeout;
int retrans;
int major_timeout_seen;
char *server_name;
int n;
int addrlen;
unsigned long old_mask;
/* We have to check the result, so store the complete header */
struct ncp_request_header request =
*((struct ncp_request_header *)(server->packet));
struct ncp_reply_header reply;
file = server->ncp_filp;
inode = file->f_inode;
select = file->f_op->select;
sock = &inode->u.socket_i;
if (!sock) {
printk("ncp_rpc_call: socki_lookup failed\n");
return -EBADF;
}
init_timeout = server->m.time_out;
max_timeout = NCP_MAX_RPC_TIMEOUT*HZ/10;
retrans = server->m.retry_count;
major_timeout_seen = 0;
server_name = server->m.server_name;
old_mask = current->blocked;
current->blocked |= ~(_S(SIGKILL)
#if 0
| _S(SIGSTOP)
#endif
| ((server->m.flags & NCP_MOUNT_INTR)
? ((current->sig->action[SIGINT - 1].sa_handler == SIG_DFL
? _S(SIGINT) : 0)
| (current->sig->action[SIGQUIT - 1].sa_handler == SIG_DFL
? _S(SIGQUIT) : 0))
: 0));
fs = get_fs();
set_fs(get_ds());
for (n = 0, timeout = init_timeout; ; n++, timeout <<= 1) {
/* DDPRINTK("ncpfs: %08lX:%02X%02X%02X%02X%02X%02X:%04X\n",
htonl(server->m.serv_addr.sipx_network),
server->m.serv_addr.sipx_node[0],
server->m.serv_addr.sipx_node[1],
server->m.serv_addr.sipx_node[2],
server->m.serv_addr.sipx_node[3],
server->m.serv_addr.sipx_node[4],
server->m.serv_addr.sipx_node[5],
ntohs(server->m.serv_addr.sipx_port));*/
DDPRINTK("ncpfs: req.typ: %04X, con: %d, "
"seq: %d",
request.type,
(request.conn_high << 8) + request.conn_low,
request.sequence);
DDPRINTK(" func: %d\n",
request.function);
result = _sendto(sock, (void *) start, size, 0, 0,
&(server->m.serv_addr),
sizeof(server->m.serv_addr));
if (result < 0) {
printk("ncp_rpc_call: send error = %d\n", result);
break;
}
re_select:
wait_table.nr = 0;
wait_table.entry = &entry;
current->state = TASK_INTERRUPTIBLE;
if ( !select(inode, file, SEL_IN, &wait_table)
&& !select(inode, file, SEL_IN, NULL)) {
if (timeout > max_timeout) {
/* JEJB/JSP 2/7/94
* This is useful to see if the system is
* hanging */
printk("NCP max timeout reached on %s\n",
server_name);
timeout = max_timeout;
}
current->timeout = jiffies + timeout;
schedule();
remove_wait_queue(entry.wait_address, &entry.wait);
current->state = TASK_RUNNING;
if (current->signal & ~current->blocked) {
current->timeout = 0;
result = -ERESTARTSYS;
break;
}
if (!current->timeout) {
if (n < retrans)
continue;
if (server->m.flags & NCP_MOUNT_SOFT) {
printk("NCP server %s not responding, "
"timed out\n", server_name);
result = -EIO;
break;
}
n = 0;
timeout = init_timeout;
init_timeout <<= 1;
if (!major_timeout_seen) {
printk("NCP server %s not responding, "
"still trying\n", server_name);
}
major_timeout_seen = 1;
continue;
}
else
current->timeout = 0;
}
else if (wait_table.nr)
remove_wait_queue(entry.wait_address, &entry.wait);
current->state = TASK_RUNNING;
addrlen = 0;
/* Get the header from the next packet using a peek, so keep it
* on the recv queue. If it is wrong, it will be some reply
* we don't now need, so discard it */
result = _recvfrom(sock, (void *)&reply,
sizeof(reply), 1, MSG_PEEK,
NULL, &addrlen);
if (result < 0) {
if (result == -EAGAIN) {
DPRINTK("ncp_rpc_call: bad select ready\n");
goto re_select;
}
if (result == -ECONNREFUSED) {
DPRINTK("ncp_rpc_call: server playing coy\n");
goto re_select;
}
if (result != -ERESTARTSYS) {
printk("ncp_rpc_call: recv error = %d\n",
-result);
}
break;
}
if ( (result == sizeof(reply))
&& (reply.type == NCP_POSITIVE_ACK)) {
/* Throw away the packet */
DPRINTK("ncp_rpc_call: got positive acknowledge\n");
_recvfrom(sock, (void *)&reply, sizeof(reply), 1, 0,
NULL, &addrlen);
goto re_select;
}
DDPRINTK("ncpfs: rep.typ: %04X, con: %d, tsk: %d,"
"seq: %d\n",
reply.type,
(reply.conn_high << 8) + reply.conn_low,
reply.task,
reply.sequence);
if ( (result >= sizeof(reply))
&& (reply.type == NCP_REPLY)
&& ( (request.type == NCP_ALLOC_SLOT_REQUEST)
|| ( (reply.sequence == request.sequence)
&& (reply.conn_low == request.conn_low)
/* seem to get wrong task from NW311 && (reply.task == request.task)*/
&& (reply.conn_high == request.conn_high)))) {
if (major_timeout_seen)
printk("NCP server %s OK\n", server_name);
break;
}
/* JEJB/JSP 2/7/94
* we have xid mismatch, so discard the packet and start
* again. What a hack! but I can't call recvfrom with
* a null buffer yet. */
_recvfrom(sock, (void *)&reply, sizeof(reply), 1, 0, NULL,
&addrlen);
#if 1
printk("ncp_rpc_call: reply mismatch\n");
#endif
goto re_select;
}
/*
* we have the correct reply, so read into the correct place and
* return it
*/
result = _recvfrom(sock, (void *)start, server->packet_size, 1, 0,
NULL, &addrlen);
if (result < 0) {
printk("NCP: notice message: result=%d\n", result);
} else if (result < sizeof(struct ncp_reply_header)) {
printk("NCP: just caught a too small read memory size..., "
"email to NET channel\n");
printk("NCP: result=%d,addrlen=%d\n", result, addrlen);
result = -EIO;
}
current->blocked = old_mask;
set_fs(fs);
return result;
}
/*
* We need the server to be locked here, so check!
*/
static int
ncp_do_request(struct ncp_server *server, int size)
{
if (server->lock == 0) {
printk("ncpfs: Server not locked!\n");
return -EIO;
}
return do_ncp_rpc_call(server, size);
}
/* ncp_do_request assures that at least a complete reply header is
* received. It assumes that server->current_size contains the ncp
* request size */
int
ncp_request(struct ncp_server *server, int function)
{
struct ncp_request_header *h
= (struct ncp_request_header *)(server->packet);
struct ncp_reply_header *reply
= (struct ncp_reply_header *)(server->packet);
int request_size = server->current_size
- sizeof(struct ncp_request_header);
int result;
if (server->has_subfunction != 0) {
*(__u16 *)&(h->data[0]) = request_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 = (current->pid) & 0xff;
h->function = function;
if ((result = ncp_do_request(server, request_size + sizeof(*h))) < 0) {
DPRINTK("ncp_request_error: %d\n", result);
return result;
}
server->completion = reply->completion_code;
server->conn_status = reply->connection_state;
server->reply_size = result;
server->ncp_reply_size = result - sizeof(struct ncp_reply_header);
result = reply->completion_code;
if (result != 0) {
DPRINTK("ncp_completion_code: %d\n", result);
}
return result;
}
int
ncp_connect(struct ncp_server *server)
{
struct ncp_request_header *h
= (struct ncp_request_header *)(server->packet);
int result;
h->type = NCP_ALLOC_SLOT_REQUEST;
server->sequence = 0;
h->sequence = server->sequence;
h->conn_low = 0xff;
h->conn_high = 0xff;
h->task = (current->pid) & 0xff;
h->function = 0;
if ((result = ncp_do_request(server, sizeof(*h))) < 0) {
return result;
}
server->sequence = 0;
server->connection = h->conn_low + (h->conn_high * 256);
return 0;
}
int
ncp_disconnect(struct ncp_server *server)
{
struct ncp_request_header *h
= (struct ncp_request_header *)(server->packet);
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 = (current->pid) & 0xff;
h->function = 0;
return ncp_do_request(server, sizeof(*h));
}
void
ncp_lock_server(struct ncp_server *server)
{
#if 1
/* For testing, only 1 process */
if (server->lock != 0) {
DPRINTK("ncpfs: server locked!!!\n");
}
#endif
while (server->lock)
sleep_on(&server->wait);
server->lock = 1;
}
void
ncp_unlock_server(struct ncp_server *server)
{
if (server->lock != 1) {
printk("ncp_unlock_server: was not locked!\n");
}
server->lock = 0;
wake_up(&server->wait);
}

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)

101
ncp.h
View File

@@ -1,101 +0,0 @@
/*
* ncp_fs.h
*
* Copyright (C) 1995 by Volker Lendecke
*
*/
#ifndef _LINUX_NCP_H
#define _LINUX_NCP_H
#include <linux/types.h>
#define NCP_PTYPE (0x17)
#define NCP_PORT (0x0451)
#define NCP_ALLOC_SLOT_REQUEST (0x1111)
#define NCP_REQUEST (0x2222)
#define NCP_DEALLOC_SLOT_REQUEST (0x5555)
struct ncp_request_header {
__u16 type;
__u8 sequence;
__u8 conn_low;
__u8 task;
__u8 conn_high;
__u8 function;
__u8 data[0]; /* Depends upon request type */
} __attribute__ ((packed));
#define NCP_REPLY (0x3333)
#define NCP_POSITIVE_ACK (0x9999)
struct ncp_reply_header {
__u16 type;
__u8 sequence;
__u8 conn_low;
__u8 task;
__u8 conn_high;
__u8 completion_code;
__u8 connection_state;
__u8 data[0]; /* Depends upon request type */
} __attribute__ ((packed));
#define NCP_BINDERY_USER (0x0001)
#define NCP_BINDERY_NAME_LEN (48)
struct ncp_bindery_object {
__u32 object_id;
__u16 object_type;
__u8 object_name[NCP_BINDERY_NAME_LEN];
};
#define NCP_VOLNAME_LEN (16)
#define NCP_NUMBER_OF_VOLUMES (64)
struct ncp_volume_info {
__u32 total_blocks;
__u32 free_blocks;
__u32 purgeable_blocks;
__u32 not_yet_purgeable_blocks;
__u32 total_dir_entries;
__u32 available_dir_entries;
__u8 sectors_per_block;
char volume_name[NCP_VOLNAME_LEN+1];
};
struct ncp_filesearch_info {
__u8 volume_number;
__u16 directory_id;
__u16 sequence_no;
__u8 access_rights;
};
#define NCP_MAX_FILENAME 14
/* these define the attribute byte as seen by NCP */
#define aRONLY (1L<<0)
#define aHIDDEN (1L<<1)
#define aSYSTEM (1L<<2)
#define aEXECUTE (1L<<3)
#define aDIR (1L<<4)
#define aARCH (1L<<5)
#define AR_READ (0x01)
#define AR_WRITE (0x02)
#define AR_EXCLUSIVE (0x20)
#define NCP_FILE_ID_LEN 6
struct ncp_file_info {
__u8 file_id[NCP_FILE_ID_LEN];
char file_name[NCP_MAX_FILENAME+1];
__u8 file_attributes;
__u8 file_mode;
__u32 file_length;
__u16 creation_date;
__u16 access_date;
__u16 update_date;
__u16 update_time;
};
#endif /* _LINUX_NCP_H */

View File

@@ -1,59 +0,0 @@
/*
* ncp_fs_i.h
*
* Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
*
*/
#ifndef _LINUX_NCP_FS_I
#define _LINUX_NCP_FS_I
#include <linux/ncp.h>
#ifdef __KERNEL__
/*
* Contains all relevant data on a NCP networked file.
*/
struct ncp_dirent {
int opened; /* is it open on the fileserver? */
__u8 file_id[NCP_FILE_ID_LEN];
__u32 attr; /* Attribute fields, NCP value. Either
only lower 8 bits used or upper
bits contain extended attributs */
__u32 size; /* File size. */
time_t atime, /* Times, as seen by the server, normalized */
mtime, /* to UTC. The ugly conversion happens in */
ctime; /* proc.c */
__u16 access; /* Access bits. */
__u16 next_search; /* Next search index, for proc_readdir */
unsigned long f_pos; /* for ncp_readdir */
char *path; /* Complete path, MS-DOS notation, with '\' */
int len; /* Namelength. */
};
enum ncp_inode_state {
INODE_VALID = 19, /* Inode currently in use */
INODE_LOOKED_UP, /* directly before iget */
INODE_CACHED, /* in a path to an inode which is in use */
INODE_INVALID
};
/*
* ncp fs inode data (in memory only)
*/
struct ncp_inode_info {
enum ncp_inode_state state;
int nused; /* for directories:
number of references in memory */
struct ncp_inode_info *dir;
struct ncp_inode_info *next, *prev;
struct ncp_dirent finfo;
};
#endif
#endif

View File

@@ -1,14 +1,14 @@
Begin3
Title: ncpfs
Version: 0.1
Entered-date: 19. October 1995
Version: 0.7
Entered-date: 26. November 1995
Description: With ncpfs you can mount volumes of your novell
server under Linux.
Keywords: filesystem kernel ncp novell
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/smbfs
~30k ncpfs-0.1.tgz
~ 1k ncpfs-0.1.lsm
Primary-site: linux01.gwdg.de:/pub/ncpfs
~80k ncpfs-0.7.tgz
~ 1k ncpfs-0.7.lsm
Copying-policy: GPL
End

598
ncplib.c
View File

@@ -1,598 +0,0 @@
#include "ncplib.h"
#include "nwcrypt.h"
typedef __u8 byte;
typedef __u16 word;
typedef __u32 dword;
#ifdef __KERNEL__
#define ncp_printf DPRINTK
#else
#include <sys/ioctl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#define ncp_printf printf
static void
assert_server_locked(struct ncp_server *server);
static void
assert_server_not_locked(struct ncp_server *server)
{
if (server->lock != 0) {
ncp_printf("ncpfs: server already locked!\n");
}
}
static void
ncp_lock_server(struct ncp_server *server)
{
assert_server_not_locked(server);
server->lock = 1;
}
static void
ncp_unlock_server(struct ncp_server *server)
{
assert_server_locked(server);
server->lock = 0;
}
static int
ncp_request(struct ncp_server *server, int function) {
struct ncp_reply_header *reply
= (struct ncp_reply_header *)(server->packet);
struct ncp_ioctl_request request;
int result;
assert_server_locked(server);
if (server->has_subfunction != 0) {
*(word *)(server->packet) = server->current_size - 2;
}
request.function = function;
request.size = server->current_size;
request.data = server->packet;
if ((result = ioctl(server->mount_fid, NCP_IOC_NCPREQUEST,
&request)) < 0) {
return result;
}
server->ncp_reply_size = result - sizeof(struct ncp_reply_header);
return reply->completion_code;
}
static inline int
min(int a, int b) {
if (a<b)
return a;
else
return b;
}
#endif
static void
assert_server_locked(struct ncp_server *server)
{
if (server->lock == 0) {
ncp_printf("ncpfs: server not locked!\n");
}
}
static void
ncp_add_byte(struct ncp_server *server, byte x)
{
assert_server_locked(server);
*(byte *)(&(server->packet[server->current_size])) = x;
server->current_size += 1;
return;
}
static void
ncp_add_word(struct ncp_server *server, word x)
{
assert_server_locked(server);
*(word *)(&(server->packet[server->current_size])) = x;
server->current_size += 2;
return;
}
static void
ncp_add_dword(struct ncp_server *server, dword x)
{
assert_server_locked(server);
*(dword *)(&(server->packet[server->current_size])) = x;
server->current_size += 4;
return;
}
static void
ncp_add_mem(struct ncp_server *server, const char *source, int size)
{
assert_server_locked(server);
memcpy(&(server->packet[server->current_size]), source, size);
server->current_size += size;
return;
}
static void
ncp_add_pstring(struct ncp_server *server, const char *s)
{
int len = strlen(s);
assert_server_locked(server);
if (len > 255) {
ncp_printf("ncpfs: string too long: %s\n", s);
len = 255;
}
ncp_add_byte(server, len);
ncp_add_mem(server, s, len);
return;
}
static void
ncp_init_request(struct ncp_server *server)
{
ncp_lock_server(server);
#ifdef __KERNEL__
server->current_size = sizeof(struct ncp_request_header);
#else
server->current_size = 0;
server->packet = server->ncp_data;
#endif
server->has_subfunction = 0;
}
static void
ncp_init_request_s(struct ncp_server *server, int subfunction)
{
ncp_init_request(server);
ncp_add_word(server, 0); /* preliminary size */
ncp_add_byte(server, subfunction);
server->has_subfunction = 1;
}
static char *
ncp_reply_data(struct ncp_server *server, int offset)
{
return &(server->packet[sizeof(struct ncp_reply_header) + offset]);
}
static byte
ncp_reply_byte(struct ncp_server *server, int offset)
{
return *(byte *)(ncp_reply_data(server, offset));
}
static word
ncp_reply_word(struct ncp_server *server, int offset)
{
return *(word *)(ncp_reply_data(server, offset));
}
static dword
ncp_reply_dword(struct ncp_server *server, int offset)
{
return *(dword *)(ncp_reply_data(server, offset));
}
int
ncp_negotiate_buffersize(struct ncp_server *server,
int size, int *target) {
int result;
ncp_init_request(server);
ncp_add_word(server, htons(size));
if ((result = ncp_request(server, 33)) < 0) {
ncp_printf("ncp_request_error: %d\n", result);
ncp_unlock_server(server);
return result;
}
*target =min(ntohs(ncp_reply_word(server, 0)), size);
ncp_unlock_server(server);
return 0;
}
/*
* result is a 8-byte buffer
*/
int
ncp_get_encryption_key(struct ncp_server *server,
char *target)
{
int result;
ncp_init_request_s(server, 23);
if ((result = ncp_request(server, 23)) != 0) {
ncp_printf("ncp_request_error: %d\n", result);
ncp_unlock_server(server);
return result;
}
if (server->ncp_reply_size < 8) {
ncp_printf("ncp_reply_size %d < 8\n",
server->ncp_reply_size);
ncp_unlock_server(server);
return result;
}
memcpy(target, ncp_reply_data(server, 0), 8);
ncp_unlock_server(server);
return 0;
}
int
ncp_get_bindery_object_id(struct ncp_server *server,
int object_type, char *object_name,
struct ncp_bindery_object *target)
{
int result;
ncp_init_request_s(server, 53);
ncp_add_word(server, ntohs(object_type));
ncp_add_pstring(server, object_name);
if ((result = ncp_request(server, 23)) != 0) {
ncp_printf("ncp_request_error: %d\n", result);
ncp_unlock_server(server);
return result;
}
if (server->ncp_reply_size < 54) {
ncp_printf("ncp_reply_size %d < 54\n",
server->ncp_reply_size);
ncp_unlock_server(server);
return result;
}
target->object_id = ntohl(ncp_reply_dword(server, 0));
target->object_type = ntohs(ncp_reply_word (server, 4));
memcpy(target->object_name, ncp_reply_data(server, 6), 48);
ncp_unlock_server(server);
return 0;
}
int
ncp_login_encrypted(struct ncp_server *server,
struct ncp_bindery_object *object,
unsigned char *key,
unsigned char *passwd)
{
dword tmpID = htonl(object->object_id);
unsigned char buf[128];
unsigned char encrypted[8];
int result;
shuffle((byte *)&tmpID, passwd, strlen(passwd), buf);
nw_encrypt(key, buf, encrypted);
ncp_init_request_s(server, 24);
ncp_add_mem(server, encrypted, 8);
ncp_add_word(server, htons(object->object_type));
ncp_add_pstring(server, object->object_name);
if ((result = ncp_request(server, 23)) != 0) {
ncp_printf("ncp_request_error: %d\n", result);
ncp_unlock_server(server);
return result;
}
ncp_unlock_server(server);
return 0;
}
int
ncp_login_user(struct ncp_server *server,
unsigned char *username,
unsigned char *password)
{
int result;
unsigned char ncp_key[8];
struct ncp_bindery_object user;
if ((result = ncp_get_encryption_key(server, ncp_key)) != 0) {
return result;
}
if ((result = ncp_get_bindery_object_id(server, NCP_BINDERY_USER,
username, &user)) != 0) {
return result;
}
if ((result = ncp_login_encrypted(server, &user,
ncp_key, password)) != 0) {
return result;
}
return 0;
}
int
ncp_get_volume_info_with_number(struct ncp_server *server, int n,
struct ncp_volume_info *target)
{
int result;
int len;
ncp_init_request_s(server, 44);
ncp_add_byte(server, n);
if ((result = ncp_request(server, 22)) != 0) {
ncp_printf("ncp_request_error: %d\n", result);
ncp_unlock_server(server);
return result;
}
target->total_blocks = ncp_reply_dword(server, 0);
target->free_blocks = ncp_reply_dword(server, 4);
target->purgeable_blocks = ncp_reply_dword(server, 8);
target->not_yet_purgeable_blocks = ncp_reply_dword(server, 12);
target->total_dir_entries = ncp_reply_dword(server, 16);
target->available_dir_entries = ncp_reply_dword(server, 20);
target->sectors_per_block = ncp_reply_byte(server, 28);
memset(&(target->volume_name), 0, sizeof(target->volume_name));
len = ncp_reply_byte(server, 29);
if (len > NCP_VOLNAME_LEN) {
ncp_printf("ncpfs: volume name too long: %d\n", len);
ncp_unlock_server(server);
return -EIO;
}
memcpy(&(target->volume_name), ncp_reply_data(server, 30), len);
ncp_unlock_server(server);
return 0;
}
int
ncp_get_volume_number(struct ncp_server *server, const char *name, int *target)
{
int result;
ncp_init_request_s(server, 5);
ncp_add_pstring(server, name);
if ((result = ncp_request(server, 22)) != 0) {
ncp_printf("ncp_request_error: %d\n", result);
ncp_unlock_server(server);
return result;
}
*target = ncp_reply_byte(server, 0);
ncp_unlock_server(server);
return 0;
}
int
ncp_file_search_init(struct ncp_server *server,
int dir_handle, const char *path,
struct ncp_filesearch_info *target)
{
int result;
ncp_init_request(server);
ncp_add_byte(server, dir_handle);
ncp_add_pstring(server, path);
if ((result = ncp_request(server, 62)) != 0) {
ncp_printf("ncp_request_error: %d\n", result);
ncp_unlock_server(server);
return result;
}
target->volume_number = ncp_reply_byte(server, 0);
target->directory_id = ntohs(ncp_reply_word(server, 1));
target->sequence_no = ntohs(ncp_reply_word(server, 3));
target->access_rights = ncp_reply_byte(server, 5);
ncp_unlock_server(server);
return 0;
}
int
ncp_file_search_continue(struct ncp_server *server,
struct ncp_filesearch_info *fsinfo,
int attributes, const char *name,
struct ncp_file_info *target)
{
int result;
ncp_init_request(server);
ncp_add_byte(server, fsinfo->volume_number);
ncp_add_word(server, htons(fsinfo->directory_id));
ncp_add_word(server, htons(fsinfo->sequence_no));
ncp_add_byte(server, attributes);
ncp_add_pstring(server, name);
if ((result = ncp_request(server, 63)) != 0) {
ncp_printf("ncp_request_error: %d\n", result);
ncp_unlock_server(server);
return result;
}
fsinfo->sequence_no = ntohs(ncp_reply_word(server, 0));
memset(&(target->file_name), 0, sizeof(target->file_name));
memcpy(&(target->file_name), ncp_reply_data(server, 4),
NCP_MAX_FILENAME);
target->file_attributes = ncp_reply_byte(server, 18);
target->file_mode = ncp_reply_byte(server, 19);
target->file_length = ntohl(ncp_reply_dword(server, 20));
target->creation_date = ntohs(ncp_reply_word(server, 24));
target->access_date = ntohs(ncp_reply_word(server, 26));
target->update_date = ntohs(ncp_reply_word(server, 28));
target->update_time = ntohs(ncp_reply_word(server, 30));
ncp_unlock_server(server);
return 0;
}
int
ncp_get_finfo(struct ncp_server *server,
int dir_handle, const char *path, const char *name,
struct ncp_file_info *target)
{
int result;
struct ncp_filesearch_info fsinfo;
if ((result = ncp_file_search_init(server, dir_handle, path,
&fsinfo)) != 0) {
return result;
}
if ((result = ncp_file_search_continue(server, &fsinfo, 0, name,
target)) == 0) {
return result;
}
if ((result = ncp_file_search_init(server, dir_handle, path,
&fsinfo)) != 0) {
return result;
}
return ncp_file_search_continue(server, &fsinfo, aDIR, name, target);
}
int
ncp_open_file(struct ncp_server *server,
int dir_handle, const char *path,
int attr, int access,
struct ncp_file_info *target)
{
int result;
ncp_init_request(server);
ncp_add_byte(server, dir_handle);
ncp_add_byte(server, attr);
ncp_add_byte(server, access);
ncp_add_pstring(server, path);
if ((result = ncp_request(server, 76)) != 0) {
ncp_printf("ncp_request_error: %d\n", result);
ncp_unlock_server(server);
return result;
}
memcpy(&(target->file_id), ncp_reply_data(server, 0),
NCP_FILE_ID_LEN);
memset(&(target->file_name), 0, sizeof(target->file_name));
memcpy(&(target->file_name), ncp_reply_data(server, 8),
NCP_MAX_FILENAME);
target->file_attributes = ncp_reply_byte(server, 22);
target->file_mode = ncp_reply_byte(server, 23);
target->file_length = ntohl(ncp_reply_dword(server, 24));
target->creation_date = ntohs(ncp_reply_word(server, 28));
target->access_date = ntohs(ncp_reply_word(server, 30));
target->update_date = ntohs(ncp_reply_word(server, 32));
target->update_time = ntohs(ncp_reply_word(server, 34));
ncp_unlock_server(server);
return 0;
}
int
ncp_close_file(struct ncp_server *server, const char *file_id)
{
int result;
ncp_init_request(server);
ncp_add_byte(server, 0);
ncp_add_mem(server, file_id, 6);
if ((result = ncp_request(server, 66)) != 0) {
ncp_printf("ncp_request_error: %d\n", result);
ncp_unlock_server(server);
return result;
}
ncp_unlock_server(server);
return 0;
}
#ifndef __KERNEL__
int
ncp_read(struct ncp_server *server, const char *file_id,
__u32 offset, __u16 to_read,
char *target, int *bytes_read)
{
int result;
ncp_init_request(server);
ncp_add_byte(server, 0);
ncp_add_mem(server, file_id, 6);
ncp_add_dword(server, htonl(offset));
ncp_add_word(server, htons(to_read));
if ((result = ncp_request(server, 72)) != 0) {
ncp_printf("ncp_request_error: %d\n", result);
ncp_unlock_server(server);
return result;
}
*bytes_read = ntohs(ncp_reply_word(server, 0));
memcpy(target, ncp_reply_data(server, 2), *bytes_read);
ncp_unlock_server(server);
return 0;
}
#else
/* We have to read into user space */
int
ncp_read(struct ncp_server *server, const char *file_id,
__u32 offset, __u16 to_read,
char *target, int *bytes_read)
{
int result;
ncp_init_request(server);
ncp_add_byte(server, 0);
ncp_add_mem(server, file_id, 6);
ncp_add_dword(server, htonl(offset));
ncp_add_word(server, htons(to_read));
if ((result = ncp_request(server, 72)) != 0) {
ncp_printf("ncp_request_error: %d\n", result);
ncp_unlock_server(server);
return result;
}
*bytes_read = ntohs(ncp_reply_word(server, 0));
memcpy_tofs(target, ncp_reply_data(server, 2), *bytes_read);
ncp_unlock_server(server);
return 0;
}
#endif

102
ncplib.h
View File

@@ -1,102 +0,0 @@
#ifndef _NCPLIB_H
#define _NCPLIB_H
#ifdef __KERNEL__
#include <linux/config.h>
#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
#endif
#include <linux/fs.h>
#include <linux/ncp.h>
#include <linux/ncp_fs.h>
#include <linux/ncp_fs_sb.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/malloc.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <asm/segment.h>
#include <asm/string.h>
#else
#include <linux/types.h>
#include <linux/ncp.h>
#include <linux/ncp_fs.h>
struct ncp_server {
int current_size;
int has_subfunction;
int mount_fid;
int ncp_reply_size;
char *packet;
int lock;
char ncp_data[NCP_PACKET_SIZE];
};
#endif __KERNEL__
#include <linux/ncp.h>
int
ncp_negotiate_buffersize(struct ncp_server *server, int size,
int *target);
int
ncp_get_encryption_key(struct ncp_server *server,
char *target);
int
ncp_get_bindery_object_id(struct ncp_server *server,
int object_type, char *object_name,
struct ncp_bindery_object *target);
int
ncp_login_encrypted(struct ncp_server *server,
struct ncp_bindery_object *object,
unsigned char *key,
unsigned char *passwd);
int
ncp_login_user(struct ncp_server *server,
unsigned char *username,
unsigned char *password);
int
ncp_get_volume_info_with_number(struct ncp_server *server, int n,
struct ncp_volume_info *target);
int
ncp_get_volume_number(struct ncp_server *server, const char *name,
int *target);
int
ncp_file_search_init(struct ncp_server *server,
int dir_handle, const char *path,
struct ncp_filesearch_info *target);
int
ncp_file_search_continue(struct ncp_server *server,
struct ncp_filesearch_info *fsinfo,
int attributes, const char *path,
struct ncp_file_info *target);
int
ncp_get_finfo(struct ncp_server *server,
int dir_handle, const char *path, const char *name,
struct ncp_file_info *target);
int
ncp_open_file(struct ncp_server *server,
int dir_handle, const char *path,
int attr, int access,
struct ncp_file_info *target);
int
ncp_close_file(struct ncp_server *server, const char *file_id);
int
ncp_read(struct ncp_server *server, const char *file_id,
__u32 start, __u16 to_read,
char *target, int *bytes_read);
#endif /* _NCPLIB_H */

View File

@@ -1,332 +0,0 @@
/*
* ncpmount.c
*
* Copyright (C) 1995 by Volker Lendecke
*
*/
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <pwd.h>
#include <grp.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ioctl.h>
/* #include <sys/wait.h> */ /* generates a warning here */
extern pid_t waitpid(pid_t, int *, int);
#include <sys/errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <stdlib.h>
#include <sys/mount.h>
#include <mntent.h>
#include <linux/ipx.h>
#include <linux/fs.h>
#include <linux/ncp.h>
#include <linux/ncp_fs.h>
#include <linux/ncp_mount.h>
#include "ipxutil.h"
static char *progname;
static char *mount_point;
static char *server_name;
struct sap_query {
unsigned short query_type; /* net order */
unsigned short server_type; /* net order */
};
struct sap_server_ident {
unsigned short server_type;
char server_name[48];
IPXNet server_network;
IPXNode server_node;
IPXPort server_port;
unsigned short intermediate_network;
} __attribute__ ((packed));
void
ipx_fprint_node(FILE* file,IPXNode node)
{
fprintf(file,"%02X%02X%02X%02X%02X%02X",
(unsigned char)node[0],
(unsigned char)node[1],
(unsigned char)node[2],
(unsigned char)node[3],
(unsigned char)node[4],
(unsigned char)node[5]
);
}
void
ipx_fprint_network(FILE* file,IPXNet net)
{
fprintf(file,"%08lX",ntohl(net));
}
void
ipx_fprint_port(FILE* file,IPXPort port)
{
fprintf(file,"%04X",ntohs(port));
}
void
ipx_fprint_saddr(FILE* file,struct sockaddr_ipx* sipx)
{
ipx_fprint_network(file,sipx->sipx_network);
fprintf(file,":");
ipx_fprint_node(file,sipx->sipx_node);
fprintf(file,":");
ipx_fprint_port(file,sipx->sipx_port);
}
void
ipx_print_node(IPXNode node)
{
ipx_fprint_node(stdout,node);
}
void
ipx_print_network(IPXNet net)
{
ipx_fprint_network(stdout,net);
}
void
ipx_print_port(IPXPort port)
{
ipx_fprint_port(stdout,port);
}
void
ipx_print_saddr(struct sockaddr_ipx* sipx)
{
ipx_fprint_saddr(stdout,sipx);
}
int
ipx_sap_find_server(char *name, int server_type, int timeout,
struct sockaddr_ipx *result)
{
struct sockaddr_ipx ipxs;
char data[1024];
int sock;
int opt;
int res = -1;
int name_len = strlen(name);
fd_set rd, wr, ex;
struct timeval tv;
if (name_len > 48) {
return -1;
}
sock=socket(AF_IPX,SOCK_DGRAM,PF_IPX);
if (sock==-1) {
return -1;
}
opt=1;
/* Permit broadcast output */
if(setsockopt(sock,SOL_SOCKET,SO_BROADCAST, &opt,sizeof(opt))==-1)
{
perror("setsockopt");
goto finished;
}
memset(&ipxs, 0, sizeof(ipxs));
ipxs.sipx_family=AF_IPX;
ipxs.sipx_network=htonl(0x0);
ipxs.sipx_port=htons(0x0);
ipxs.sipx_type=IPX_SAP_PTYPE;
if(bind(sock,(struct sockaddr*)&ipxs,sizeof(ipxs))==-1)
{
perror("bind");
goto finished;
}
*(unsigned short *)data = htons(0x0001);
*(unsigned short *)&(data[2]) = htons(server_type);
memset(&ipxs, 0, sizeof(ipxs));
ipxs.sipx_family=AF_IPX;
ipxs.sipx_network=htonl(0x0);
ipx_assign_node(ipxs.sipx_node, IPX_BROADCAST_NODE);
ipxs.sipx_port=htons(IPX_SAP_PORT);
ipxs.sipx_type=IPX_SAP_PTYPE;
if (sendto(sock, data, 4, 0,
(struct sockaddr *)&ipxs, sizeof(ipxs)) < 0) {
perror("sendto");
goto finished;
}
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;
}
}
}
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;
}
int
main(int argc, char **argv)
{
struct ncp_mount_data data;
struct stat st;
struct sockaddr_ipx addr;
int ncp_sock, wdog_sock;
int flags;
progname = argv[0];
if (geteuid() != 0) {
fprintf(stderr, "%s must be installed suid root\n", progname);
exit(1);
}
memset(&data, 0, sizeof(struct ncp_mount_data));
if (argc != 5) {
fprintf(stderr, "usage: %s server mount-point"
" user password\n", progname);
exit(1);
}
server_name = argv[1];
mount_point = argv[2];
if (stat(mount_point, &st) == -1) {
fprintf(stderr, "could not find mount point %s: %s\n",
mount_point, strerror(errno));
exit(1);
}
ncp_sock = socket(AF_IPX, SOCK_DGRAM, PF_IPX);
if (ncp_sock == -1) {
fprintf(stderr, "could not open ncp socket: %s\n",
strerror(errno));
exit(1);
}
wdog_sock = socket(AF_IPX, SOCK_DGRAM, PF_IPX);
if (wdog_sock == -1) {
fprintf(stderr, "could not open wdog socket: %s\n",
strerror(errno));
exit(1);
}
addr.sipx_type = NCP_PTYPE;
if (bind(ncp_sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
fprintf(stderr, "bind(ncp_sock, ): %s\n",
strerror(errno));
exit(1);
}
if (bind(wdog_sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
fprintf(stderr, "bind(wdog_sock, ): %s\n",
strerror(errno));
exit(1);
}
if (ipx_sap_find_server(server_name, IPX_SAP_FILE_SERVER,
3, &addr) != 0) {
fprintf(stderr, "could not find server %s\n", server_name);
exit(1);
}
printf("server: ");
ipx_fprint_saddr(stdout, &addr);
printf("\n");
data.version = NCP_MOUNT_VERSION;
data.ncp_fd = ncp_sock;
data.wdog_fd = wdog_sock;
data.mounted_uid = getuid();
data.serv_addr = addr;
strcpy(data.server_name, server_name);
data.time_out = 20; /* 2 seconds */
data.retry_count = 2;
data.uid = 501; /* me */
data.gid = 100; /* users */
data.file_mode = data.dir_mode = S_IRWXU|S_IRWXG|S_IRWXO;
strcpy(data.username, argv[3]);
strcpy(data.password, argv[4]);
flags = MS_MGC_VAL;
if (mount(NULL, mount_point, "ncpfs", flags, (char *)&data) < 0) {
perror("mount error");
fprintf(stderr, "Maybe you should try your password in "
"upper case\n");
return -1;
}
close(ncp_sock);
close(wdog_sock);
return 0;
}

View File

@@ -1,3 +0,0 @@
#!/bin/sh
ipx_interface add -p eth0 EtherII abcd
ipx_route add 1234 abcd 00001b038b11

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) -O2
CC = gcc
all: $(UTILS)
ncpmount: ncpmount.o ncplib_user.o nwcrypt.o
$(CC) -o ncpmount ncpmount.o ncplib_user.o nwcrypt.o
cp ncpmount $(BINDIR)
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

BIN
util/ipx.tar Normal file

Binary file not shown.

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,19 +27,42 @@
#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"
#ifndef IPX_NODE_LEN
#define IPX_NODE_LEN (6)
#endif
typedef unsigned long IPXNet;
typedef unsigned short IPXPort;
typedef unsigned char IPXNode[IPX_NODE_LEN];
void ipx_print_node(IPXNode node);
void ipx_print_network(IPXNet net);
void ipx_print_port(IPXPort port);

1460
util/ncplib_user.c Normal file

File diff suppressed because it is too large Load Diff

204
util/ncplib_user.h Normal file
View File

@@ -0,0 +1,204 @@
#ifndef _NCPLIB_H
#define _NCPLIB_H
#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 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);
int
ncp_get_encryption_key(struct ncp_server *server,
char *target);
int
ncp_get_bindery_object_id(struct ncp_server *server,
int object_type, char *object_name,
struct ncp_bindery_object *target);
int
ncp_read_property_value(struct ncp_server *server,
int object_type, char *object_name,
int segment, char *prop_name,
struct nw_property *target);
int
ncp_login_encrypted(struct ncp_server *server,
struct ncp_bindery_object *object,
unsigned char *key,
unsigned char *passwd);
int
ncp_login_user(struct ncp_server *server,
unsigned char *username,
unsigned char *password);
int
ncp_get_volume_info_with_number(struct ncp_server *server, int n,
struct ncp_volume_info *target);
int
ncp_get_volume_number(struct ncp_server *server, const char *name,
int *target);
int
ncp_file_search_init(struct ncp_server *server,
int dir_handle, const char *path,
struct ncp_filesearch_info *target);
int
ncp_file_search_continue(struct ncp_server *server,
struct ncp_filesearch_info *fsinfo,
int attributes, const char *path,
struct ncp_file_info *target);
int
ncp_get_finfo(struct ncp_server *server,
int dir_handle, const char *path, const char *name,
struct ncp_file_info *target);
int
ncp_open_file(struct ncp_server *server,
int dir_handle, const char *path,
int attr, int access,
struct ncp_file_info *target);
int
ncp_close_file(struct ncp_server *server, const char *file_id);
int
ncp_create_newfile(struct ncp_server *server,
int dir_handle, const char *path,
int attr,
struct ncp_file_info *target);
int
ncp_create_file(struct ncp_server *server,
int dir_handle, const char *path,
int attr,
struct ncp_file_info *target);
int
ncp_erase_file(struct ncp_server *server,
int dir_handle, const char *path,
int attr);
int
ncp_rename_file(struct ncp_server *server,
int old_handle, const char *old_path,
int attr,
int new_handle, const char *new_path);
int
ncp_create_directory(struct ncp_server *server,
int dir_handle, const char *path,
int inherit_mask);
int
ncp_delete_directory(struct ncp_server *server,
int dir_handle, const char *path);
int
ncp_rename_directory(struct ncp_server *server,
int dir_handle,
const char *old_path, const char *new_path);
int
ncp_read(struct ncp_server *server, const char *file_id,
__u32 offset, __u16 to_read,
char *target, int *bytes_read);
int
ncp_write(struct ncp_server *server, const char *file_id,
__u32 offset, __u16 to_write,
const char *source, int *bytes_written);
int
ncp_do_lookup(struct ncp_server *server,
struct nw_info_struct *dir,
char *path, /* may only be one component */
struct nw_info_struct *target);
int
ncp_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,
int open_create_mode,
__u32 create_attributes,
int desired_acc_rights,
struct nw_file_info *target);
int
ncp_initialize_search(struct ncp_server *server,
struct nw_info_struct *dir,
struct nw_search_sequence *target);
int
ncp_search_for_file_or_subdir(struct ncp_server *server,
struct nw_search_sequence *seq,
struct nw_info_struct *target);
int
ncp_ren_or_mov_file_or_subdir(struct ncp_server *server,
struct nw_info_struct *old_dir, char *old_name,
struct nw_info_struct *new_dir, char *new_name);
int
ncp_create_queue_job_and_file(struct ncp_server *server,
__u32 queue_id,
struct queue_job *job);
int
ncp_close_file_and_start_job(struct ncp_server *server,
__u32 queue_id,
struct queue_job *job);
#endif /* _NCPLIB_H */

866
util/ncpmount.c Normal file
View File

@@ -0,0 +1,866 @@
/*
* ncpmount.c
*
* Copyright (C) 1995 by Volker Lendecke
*
*/
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <pwd.h>
#include <grp.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/stat.h>
#include <sys/types.h>
/* #include <sys/wait.h> */ /* generates a warning here */
extern pid_t waitpid(pid_t, int *, int);
#include <sys/errno.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <stdlib.h>
#include <sys/mount.h>
#include <mntent.h>
#include <linux/ipx.h>
#include <linux/route.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <linux/ncp.h>
#include <linux/ncp_fs.h>
#include <linux/ncp_mount.h>
#include "ipxutil.h"
#include "ncplib_user.h"
static char *progname;
static void
str_upper(char *name)
{
while (*name) {
*name = toupper(*name);
name = name + 1;
}
}
static void
usage(void)
{
printf("usage: %s server mount-point [options]\n", progname);
printf("Try `%s -h' for more information\n", progname);
}
static void
help(void)
{
printf("\n");
printf("usage: %s server mount-point [options]\n", progname);
printf("\n"
"-U username Username sent to server\n"
"-u uid uid the mounted files get\n"
"-g gid gid the mounted files get\n"
"-f mode permission the files get (octal notation)\n"
"-d mode permission the dirs get (octal notation)\n"
"-C Don't convert password to uppercase\n"
"-P password Use this password\n"
"-n Do not use any password\n"
" If neither -P nor -n are given, you are\n"
" asked for a password.\n"
"-h print this help text\n"
"\n");
}
struct sap_query {
unsigned short query_type; /* net order */
unsigned short server_type; /* net order */
};
struct sap_server_ident {
unsigned short server_type __attribute__ ((packed));
char server_name[48] __attribute__ ((packed));
IPXNet server_network __attribute__ ((packed));
IPXNode server_node __attribute__ ((packed));
IPXPort server_port __attribute__ ((packed));
unsigned short intermediate_network __attribute__ ((packed));
};
void
ipx_fprint_node(FILE* file,IPXNode node)
{
fprintf(file,"%02X%02X%02X%02X%02X%02X",
(unsigned char)node[0],
(unsigned char)node[1],
(unsigned char)node[2],
(unsigned char)node[3],
(unsigned char)node[4],
(unsigned char)node[5]
);
}
void
ipx_fprint_network(FILE* file,IPXNet net)
{
fprintf(file,"%08lX",ntohl(net));
}
void
ipx_fprint_port(FILE* file,IPXPort port)
{
fprintf(file,"%04X",ntohs(port));
}
void
ipx_fprint_saddr(FILE* file,struct sockaddr_ipx* sipx)
{
ipx_fprint_network(file,sipx->sipx_network);
fprintf(file,":");
ipx_fprint_node(file,sipx->sipx_node);
fprintf(file,":");
ipx_fprint_port(file,sipx->sipx_port);
}
void
ipx_print_node(IPXNode node)
{
ipx_fprint_node(stdout,node);
}
void
ipx_print_network(IPXNet net)
{
ipx_fprint_network(stdout,net);
}
void
ipx_print_port(IPXPort port)
{
ipx_fprint_port(stdout,port);
}
void
ipx_print_saddr(struct sockaddr_ipx* sipx)
{
ipx_fprint_saddr(stdout,sipx);
}
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)
{
struct sockaddr_ipx ipxs;
char data[1024];
int sock;
int opt;
int res = -1;
int name_len = strlen(name);
fd_set rd, wr, ex;
struct timeval tv;
struct sap_server_ident *ident;
struct ncp_server server;
struct nw_property prop;
struct net_address
{
__u32 network __attribute__ ((packed));
__u8 node[6] __attribute__ ((packed));
__u16 port __attribute__ ((packed));
} *n_addr = (struct net_address *)&prop;
if (name_len > 48) {
return -1;
}
sock=socket(AF_IPX,SOCK_DGRAM,PF_IPX);
if (sock==-1) {
return -1;
}
opt=1;
/* Permit broadcast output */
if(setsockopt(sock,SOL_SOCKET,SO_BROADCAST, &opt,sizeof(opt))==-1)
{
perror("setsockopt");
goto finished;
}
memset(&ipxs, 0, sizeof(ipxs));
ipxs.sipx_family=AF_IPX;
ipxs.sipx_network=htonl(0x0);
ipxs.sipx_port=htons(0x0);
ipxs.sipx_type=IPX_SAP_PTYPE;
if(bind(sock,(struct sockaddr*)&ipxs,sizeof(ipxs))==-1)
{
perror("bind");
goto finished;
}
*(unsigned short *)data = htons(IPX_SAP_NEAREST_QUERY);
*(unsigned short *)&(data[2]) = htons(server_type);
memset(&ipxs, 0, sizeof(ipxs));
ipxs.sipx_family=AF_IPX;
ipxs.sipx_network=htonl(0x0);
ipx_assign_node(ipxs.sipx_node, IPX_BROADCAST_NODE);
ipxs.sipx_port=htons(IPX_SAP_PORT);
ipxs.sipx_type=IPX_SAP_PTYPE;
if (sendto(sock, data, 4, 0,
(struct sockaddr *)&ipxs, sizeof(ipxs)) < 0)
{
perror("sendto");
goto finished;
}
do
{
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)
{
goto finished;
}
if (FD_ISSET(sock, &rd))
{
int len = recv(sock, data, 1024, 0);
if (len < 96)
{
continue;
}
}
else
{
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;
}
int
ipx_sscanf_node(char *buf, unsigned char node[6])
{
int i;
int n[6];
if ((i = sscanf(buf, "%2x%2x%2x%2x%2x%2x",
&(n[0]), &(n[1]), &(n[2]),
&(n[3]), &(n[4]), &(n[5]))) != 6) {
return i;
}
for (i=0; i<6; i++) {
node[i] = n[i];
}
return 6;
}
static int
parse_args(int argc, char *argv[], struct ncp_mount_data *data,
int *got_password, int *upcase_password)
{
int opt;
struct passwd *pwd;
struct group *grp;
*got_password = 0;
*upcase_password = 1;
while ((opt = getopt (argc, argv, "Cp:s:c:U:u:g:f:d:m:P:n")) != EOF) {
switch (opt) {
case 'C':
*upcase_password = 0;
break;
case 'U':
if (strlen(optarg) > 63) {
fprintf(stderr, "Username too long: %s\n",
optarg);
return 1;
}
strcpy(data->username, optarg);
break;
case 'u':
if (isdigit(optarg[0])) {
data->uid = atoi(optarg);
} else {
pwd = getpwnam(optarg);
if (pwd == NULL) {
fprintf(stderr, "Unknown user: %s\n",
optarg);
return 1;
}
data->uid = pwd->pw_uid;
}
break;
case 'g':
if (isdigit(optarg[0])) {
data->gid = atoi(optarg);
} else {
grp = getgrnam(optarg);
if (grp == NULL) {
fprintf(stderr, "Unknown group: %s\n",
optarg);
return 1;
}
data->gid = grp->gr_gid;
}
break;
case 'f':
data->file_mode = strtol(optarg, NULL, 8);
break;
case 'd':
data->dir_mode = strtol(optarg, NULL, 8);
break;
case 'P':
strcpy(data->password, optarg);
*got_password = 1;
break;
case 'n':
data->password[0] = '\0';
*got_password = 1;
break;
default:
return -1;
}
}
return 0;
}
/* Returns 0 if the filesystem is in the kernel after this routine
completes */
static int
load_ncpfs()
{
FILE *fver, *ffs;
char s[1024];
char modname[1024];
char *p, *p1;
pid_t pid;
int status;
/* Check if ncpfs is in the kernel */
ffs = fopen("/proc/filesystems", "r");
if (ffs == NULL) {
perror("Error: \"/proc/filesystems\" could not be read:");
return -1;
}
p = NULL;
while (! feof(ffs)) {
p1 = fgets(s, sizeof(s), ffs);
if (p1) {
p = strstr(s, "ncpfs");
if (p) {
break;
}
}
}
fclose(ffs);
if (p) {
return 0;
}
fver = fopen("/proc/version", "r");
if (fver == NULL) {
perror("Error: \"/proc/version\" could not be read:");
return -1;
}
fgets(s, 1024, fver);
fclose(fver);
p = strstr(s, "version ");
if (p == NULL) {
version_error:
fprintf(stderr, "Error: Unable to determine the Linux version"
"from \"/proc/version\n");
return -1;
}
p = strchr(p, ' ') + 1;
p1 = strchr(p, ' ');
if (p1 == NULL) {
goto version_error;
}
strcpy(modname, "/lib/modules/");
strncat(modname, p, p1 - p);
strcat(modname, "/ncpfs.o");
/* system() function without signal handling, from Stevens */
if ((pid = fork()) < 0) {
return 1;
} else if (pid == 0) {
/* child */
execl("/sbin/insmod", "insmod", modname, NULL);
_exit(127); /* execl error */
} else {
/* parent */
while (waitpid(pid, &status, 0) < 0) {
if (errno != EINTR) {
status = -1;
break;
}
}
}
return status;
}
/* Check whether user is allowed to mount on the specified mount point */
static int
mount_ok(struct stat *st)
{
if (!S_ISDIR(st->st_mode))
{
errno = ENOTDIR;
return -1;
}
if ( (getuid() != 0)
&& ( (getuid() != st->st_uid)
|| ((st->st_mode & S_IRWXU) != S_IRWXU)))
{
errno = EPERM;
return -1;
}
return 0;
}
int
main(int argc, char *argv[])
{
struct ncp_mount_data data;
struct sockaddr_ipx addr;
struct stat st;
struct ncp_server serv;
struct ncp_server *server = &serv;
char mount_name[256];
int fd;
int Got_Password;
int Upcase_Password;
int um;
unsigned int flags;
char hostname[MAXHOSTNAMELEN + 1];
char *server_name;
char mount_point[MAXPATHLEN];
struct mntent ment;
FILE *mtab;
int ncp_sock, wdog_sock;
progname = argv[0];
if (geteuid() != 0) {
fprintf(stderr, "%s must be installed suid root\n", progname);
exit(1);
}
memset(&data, 0, sizeof(struct ncp_mount_data));
memset(hostname, '\0', MAXHOSTNAMELEN+1);
gethostname(hostname, MAXHOSTNAMELEN);
if (argc < 3) {
if ( (argc == 2)
&& (argv[1][0] == '-')
&& (argv[1][1] == 'h')
&& (argv[1][2] == '\0')) {
help();
return 0;
}
else
{
usage();
return -1;
}
}
server_name = argv[1];
str_upper(server_name);
realpath(argv[2], mount_point);
argv += 2;
argc -= 2;
if (stat(mount_point, &st) == -1) {
fprintf(stderr, "could not find mount point %s: %s\n",
mount_point, strerror(errno));
exit(1);
}
if (mount_ok(&st) != 0) {
fprintf(stderr, "cannot to mount on %s: %s\n",
mount_point, strerror(errno));
exit(1);
}
ncp_sock = socket(AF_IPX, SOCK_DGRAM, PF_IPX);
if (ncp_sock == -1) {
fprintf(stderr, "could not open ncp socket: %s\n",
strerror(errno));
exit(1);
}
wdog_sock = socket(AF_IPX, SOCK_DGRAM, PF_IPX);
if (wdog_sock == -1) {
fprintf(stderr, "could not open wdog socket: %s\n",
strerror(errno));
exit(1);
}
addr.sipx_type = NCP_PTYPE;
if (bind(ncp_sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
fprintf(stderr, "\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);
}
if (bind(wdog_sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
fprintf(stderr, "bind(wdog_sock, ): %s\n",
strerror(errno));
exit(1);
}
if (ipx_sap_find_server(server_name, IPX_SAP_FILE_SERVER,
3, &addr) != 0) {
fprintf(stderr, "could not find server %s\n", server_name);
exit(1);
}
/* Check if the ncpfs filesystem is in the kernel. If not, attempt
* to load the ncpfs module */
if (load_ncpfs() != 0) {
fprintf(stderr, "Error: Unable to start ncpfs, exiting...\n");
exit(1);
}
data.version = NCP_MOUNT_VERSION;
data.ncp_fd = ncp_sock;
data.wdog_fd = wdog_sock;
data.mounted_uid = getuid();
data.serv_addr = addr;
strcpy(data.server_name, server_name);
data.time_out = 20; /* 2 seconds */
data.retry_count = 2;
/* getuid() gives us the real uid, who may umount the fs */
data.mounted_uid = getuid();
if (getenv("USER")) {
strcpy(data.username, getenv("USER"));
str_upper(data.username);
}
if (data.username[0] == 0 && getenv("LOGNAME"))
{
strcpy(data.username,getenv("LOGNAME"));
str_upper(data.username);
}
data.uid = getuid();
data.gid = getgid();
um = umask(0);
umask(um);
data.file_mode = (S_IRWXU|S_IRWXG|S_IRWXO) & ~um;
data.dir_mode = 0;
if (parse_args(argc, argv, &data, &Got_Password,
&Upcase_Password) != 0) {
usage();
return -1;
}
if (data.dir_mode == 0) {
data.dir_mode = data.file_mode;
if ((data.dir_mode & S_IRUSR) != 0)
data.dir_mode |= S_IXUSR;
if ((data.dir_mode & S_IRGRP) != 0)
data.dir_mode |= S_IXGRP;
if ((data.dir_mode & S_IROTH) != 0)
data.dir_mode |= S_IXOTH;
}
if (Got_Password == 0) {
strcpy(data.password, getpass("Password: "));
}
if (Upcase_Password == 1) {
str_upper(data.password);
}
if (data.server_name[0] == '\0') {
strcpy(data.server_name, server_name);
str_upper(data.server_name);
}
flags = MS_MGC_VAL;
if (mount(NULL, mount_point, "ncpfs",
flags, (char *)&data) < 0) {
printf("mount failed\n");
close(wdog_sock);
close(ncp_sock);
return -1;
}
close(ncp_sock);
close(wdog_sock);
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");
fprintf(stderr,
"should try to type the username and\n"
"password in UPPERCASE.\n");
close(server->mount_fid);
umount(mount_point);
return -1;
}
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";
ment.mnt_freq = 0;
ment.mnt_passno= 0;
if ((fd = open(MOUNTED"~", O_RDWR|O_CREAT|O_EXCL, 0600)) == -1)
{
fprintf(stderr, "Can't get "MOUNTED"~ lock file");
return 1;
}
close(fd);
if ((mtab = setmntent(MOUNTED, "a+")) == NULL)
{
fprintf(stderr, "Can't open " MOUNTED);
return 1;
}
if (addmntent(mtab, &ment) == 1)
{
fprintf(stderr, "Can't write mount entry");
return 1;
}
if (fchmod(fileno(mtab), 0644) == -1)
{
fprintf(stderr, "Can't set perms on "MOUNTED);
return 1;
}
endmntent(mtab);
if (unlink(MOUNTED"~") == -1)
{
fprintf(stderr, "Can't remove "MOUNTED"~");
return 1;
}
return 0;
}

639
util/ncptest.c Normal file
View File

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

View File

@@ -1,9 +1,7 @@
/*$*********************************************************
$*
$* This code has been taken from DDJ 11/93, from an
$* article by Pawel Szczerbina. Please read the file
$* README for my questions about the legal status of
$* this code.
$* article by Pawel Szczerbina.
$*
$* Password encryption routines follow.
$* Converted to C from Barry Nance's Pascal
@@ -15,6 +13,77 @@ $* October 1995.
$*
$**********************************************************/
/****************************************************************************
I read that Novell is not very open when it comes to technical details
of the Netware Core Protocol. This might be especially true for the
encryption stuff. I took the necessary code from Dr. Dobb's Journal
11/93, Undocumented Corner. I asked Jon Erickson <jon@ddj.com> about
the legal status of this piece of code:
---
Date: Thu, 12 Oct 1995 13:44:18 +0100
From: Volker Lendecke <lendecke>
To: jon@ddj.com
Subject: legal status of your source code?
Hello!
I hope that you're the right one to write to, you are the first on your WWW
server. If you are not, could you please forward this message to the right
person? Thanks.
I'm currently exploring the possibility to write a free (in the GNU GPL
sense) NCP filesystem, which would allow me to access a novell server
transparently. For that I would like to use the encryption functions you
published in DDJ 11/93, Undocumented Corner. I would make some cosmetic
changes, such as other indentations, minor code changes and so on. But I do
not know if that allows me to publish this code under GPL. One alternative
would be to publish a diff against your listing, but that would probably
contain much of your code as well, and it would be very inconvenient for
the average user.
I think that you have some kind of standard procedure for such a
case. Please tell me what I should do.
Many thanks in advance,
Volker
+=================================================================+
! Volker Lendecke Internet: lendecke@namu01.gwdg.de !
! D-37081 Goettingen, Germany !
+=================================================================+
--
I got the following answer:
---
From: Jon Erickson <jon@ddj.com>
X-Mailer: SCO System V Mail (version 3.2)
To: lendecke@namu01.gwdg.de
Subject: Re: legal status of your source code?
Date: Thu, 12 Oct 95 5:42:56 PDT
Volker,
Code from Dr. Dobb's Journal related articles is provided for
anyone to use. Clearly, the author of the article should be
given credit.
Jon Erickson
---
With this answer in mind, I took the code and made it a bit more
C-like. The original seemed to be translated by a mechanical pascal->c
translator. Jon's answer encouraged me to publish nwcrypt.c under the
GPL. If anybody who knows more about copyright and sees any problems
with this, please tell me.
****************************************************************************/
/******************* Data types ***************************/
typedef unsigned char buf32[32];
typedef unsigned char buf16[16];

7
util/start_ipx Executable file
View File

@@ -0,0 +1,7 @@
#!/bin/sh
#
# abcd is my ipx network number and 1234 my server's internal network number.
# 00001b038b11 is the server's node number.
#
ipx_interface add -p eth0 EtherII 10
ipx_route add 1234 10 00001b038b11