Compare commits

...

2 Commits
v0.1 ... v0.3

Author SHA1 Message Date
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
21 changed files with 1497 additions and 245 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.

17
BUGS Normal file
View File

@@ -0,0 +1,17 @@
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.
Invalid directory timestamps:
I did not yet find out how to get valid timestamps for directories
from a NetWare server. So I simply return 0, which means 01.01.70. If
anybody knows how to get these values, please mail
lendecke@namu01.gwdg.de.
'df' returns 0:
Free disk space is distributed among the volumes in NetWare. df is
only able to report one number per mounted filesystem. As connections
are quite expensive for NetWare (with lwared that might change ...), I
rejected the alternative to mount only a single volume for a unix
mount point. So I simply return 0.

13
Changes Normal file
View File

@@ -0,0 +1,13 @@
ncpfs-0.2 -> ncpfs-0.3
- removed bug in get_pname_static
- removed bug in 'ncpmount -n'
- fake '.' and '..'
- return 0 for df and directory timestamps. See file BUGS
ncpfs-0.1 -> ncpfs-0.2
- should be compileable with gcc other than 2.7.0
- first attempt at read/write access
- more complete ncpmount.c
- included file ipx.tar

View File

@@ -22,26 +22,29 @@ ARCH = i386
OBJS= inode.o dir.o file.o sock.o ioctl.o ncplib.o nwcrypt.o
all: ncpfs.o ncpmount
all: ncpfs.o ncpmount ncptest
ncpfs.o: $(OBJS)
$(LD) -r -o ncpfs.o $(OBJS)
ncpmount: ncpmount.o
ncpmount: ncpmount.o
gcc -o ncpmount ncpmount.o
ncpmount.o: ncpmount.c
gcc -c ncpmount.c -Wall -I. -g
ncptest: ncptest.o ncplib_user.o nwcrypt.o
gcc -o ncptest ncptest.o ncplib_user.o nwcrypt.o
ncptest.o: ncptest.c
gcc -c ncptest.c -Wall -I. -g
ncplib_user.o: ncplib.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
dep:
$(CPP) -M $(INCLUDES) *.c > .depend
@@ -49,7 +52,7 @@ clean:
rm -f *.o *~
realclean: clean
rm -fr ncpmount ncpumount .depend $(DISTFILE) mnt
rm -fr ncpmount ncptest .depend $(DISTFILE) mnt *.out
modules: ncpfs.o

139
README
View File

@@ -1,90 +1,79 @@
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.2 of ncpfs, a free NetWare client for Linux. For me
it works with 1.3.32
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.
I know that this piece of software is VERY incomplete, I have to
apologize for that. But I thought I should make it publically
available, because I have tried to ask several people about the legal
status of the code. I did not get very satisfying answers. So I publish
ncpfs to open it for criticism. If nobody complains, I will go on
working.
To install ncpfs, just type 'make', '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.
To install ncpfs, just type 'make', 'insmod ncpfs.o' and then
'ncpmount server mount-point'. Please note that your IPX system has to
be configured correctly. There has to be a route to the internal
network of your server. Please see the file 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!
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:
MAILING LIST
There is a mailing list for discussing lwared and ncpfs. Here's the
message I received after subscribing:
---
Date: Thu, 12 Oct 1995 13:44:18 +0100
From: Volker Lendecke <lendecke>
To: jon@ddj.com
Subject: legal status of your source code?
Thank you for your subscription to the list "linware".
Topics for the list:
- discussing LinWare server, its features, installation problems and bugs
- using IPX protocol under Linux
- IPX routing and router daemons under Linux
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
Send your list postings to address: "linware@sh.cvut.cz"
Send your list control commands to address: "listserv@sh.cvut.cz"
---
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.
You can subscribe to this list by sending a message with a line
'add your_name@your_host linware' to listserv@sh.cvut.cz .
NCPLIB
For the curious: the file ncplib.c is usable from user space as well.
Look at the file ncptest.c for a possible use. 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.

352
dir.c
View File

@@ -1,4 +1,4 @@
/*
/*
* dir.c
*
* Copyright (C) 1995 by Volker Lendecke
@@ -60,6 +60,23 @@ 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 int
date_dos2unix(unsigned short time,unsigned short date);
@@ -103,15 +120,15 @@ static struct file_operations ncp_dir_operations = {
struct inode_operations ncp_dir_inode_operations = {
&ncp_dir_operations, /* default directory file ops */
NULL, /* create */
ncp_create, /* create */
ncp_lookup, /* lookup */
NULL, /* link */
NULL, /* unlink */
ncp_unlink, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
ncp_mkdir, /* mkdir */
ncp_rmdir, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
ncp_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
@@ -286,13 +303,34 @@ ncp_readdir(struct inode *inode, struct file *filp,
}
static int
ncp_read_volume_list(struct ncp_server *server, int start_with, int cache_size)
ncp_read_volume_list(struct ncp_server *server, int fpos, int cache_size)
{
struct ncp_dirent *entry = c_entry;
int total_count = 0;
int i;
void fill_one(char *name)
{
if (total_count < fpos) {
DPRINTK("ncp_do_readdir: skipped file: %s\n", name);
} else if (total_count >= fpos + cache_size) {
return;
} else {
DPRINTK("ncp_do_readdir: found file: %s\n", name);
entry->attr = aDIR;
entry->mtime = 0;
entry->ctime = 0;
entry->atime = 0;
entry->size = 1024;
entry->f_pos = total_count;
strcpy(entry->path, name);
entry += 1;
}
total_count += 1;
}
for (i=0; i<NCP_NUMBER_OF_VOLUMES; i++) {
struct ncp_volume_info info;
@@ -302,29 +340,12 @@ ncp_read_volume_list(struct ncp_server *server, int start_with, int cache_size)
}
if (strlen(info.volume_name) > 0) {
if (total_count < start_with) {
DPRINTK("ncp_read_volumes: skipped vol: %s\n",
info.volume_name);
} else if (total_count >= start_with + cache_size) {
return (total_count - start_with);
} else {
DPRINTK("ncp_read_volumes: found vol %s\n",
info.volume_name);
entry->attr = aDIR;
entry->mtime = 0;
entry->ctime = 0;
entry->atime = 0;
entry->size = 1024;
entry->f_pos = total_count;
strcpy(entry->path, info.volume_name);
entry += 1;
}
total_count += 1;
fill_one(info.volume_name);
}
}
return (total_count - start_with);
fill_one(".");
fill_one("..");
return (total_count - fpos);
}
static int
@@ -336,6 +357,41 @@ ncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos,
int total_count = 0;
void fill_one(int attr, char *name,
int upd_time, int upd_date,
int cr_date, int ac_date, int length)
{
if (total_count < fpos) {
DPRINTK("ncp_do_readdir: skipped file: %s\n", name);
} else if (total_count >= fpos + cache_size) {
return;
} else {
DPRINTK("ncp_do_readdir: found file: %s\n", name);
entry->attr = attr;
if ((attr & aDIR) == 0) {
entry->mtime = date_dos2unix(upd_time,
upd_date);
entry->ctime = date_dos2unix(0, cr_date);
entry->atime = date_dos2unix(0, ac_date);
entry->size = length;
} else {
/* Sorry, I do not know how to get the
* values for directories :-(. Mail
* lendecke@namu01.gwdg.de if you
* know more. */
entry->mtime = 0;
entry->ctime = 0;
entry->atime = 0;
entry->size = 1024;
}
entry->f_pos = total_count;
strcpy(entry->path, name);
entry += 1;
}
total_count += 1;
}
void doit(int attr) {
if (ncp_file_search_init(server, 0, NCP_FINFO(dir)->path,
@@ -346,36 +402,20 @@ ncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos,
while (ncp_file_search_continue(server, &fsinfo, attr, "*",
&finfo) == 0) {
fill_one(attr, finfo.file_name,
finfo.update_time, finfo.update_date,
finfo.creation_date, finfo.access_date,
finfo.file_length);
if (total_count < fpos) {
DPRINTK("ncp_do_readdir: skipped file: %s\n",
finfo.file_name);
} else if (total_count >= fpos + cache_size) {
return;
} else {
DPRINTK("ncp_do_readdir: found file: %s\n",
finfo.file_name);
entry->attr = attr;
entry->mtime =
date_dos2unix(finfo.update_time,
finfo.update_date);
entry->ctime =
date_dos2unix(0, finfo.creation_date);
entry->atime =
date_dos2unix(0, finfo.access_date);
;
entry->size = (attr & aDIR) != 0 ?
1024 : finfo.file_length;
entry->f_pos = total_count;
strcpy(entry->path, finfo.file_name);
entry += 1;
}
total_count += 1;
}
return;
}
fill_one(aDIR, ".", 0, 0, 0, 0, 0);
fill_one(aDIR, "..", 0, 0, 0, 0, 0);
doit(0);
doit(aDIR);
@@ -437,7 +477,7 @@ get_pname_static(struct inode *dir, const char *name, int len,
}
#endif
DPRINTK("get_pname_static: parentname = %s, len = %d\n",
DDPRINTK("get_pname_static: parentname = %s, len = %d\n",
parentname, parentlen);
if (len > NCP_MAXNAMELEN) {
@@ -458,16 +498,16 @@ get_pname_static(struct inode *dir, const char *name, int len,
char *pos = strrchr(parentname, '\\');
if ( (pos == NULL)
&& (parentlen == 0)) {
&& ( (parentname[parentlen-1] == ':')
|| (parentlen == 0))) {
/* We're at the top */
path[0] = '\\';
path[1] = '\0';
*res_len = 2;
path[0] = '\0';
*res_len = 0;
return 0;
}
if (pos == NULL) {
printk("ncp_make_name: Bad parent NCP-name: %s",
@@ -481,7 +521,6 @@ get_pname_static(struct inode *dir, const char *name, int len,
path[len] = '\0';
}
else if (parentlen == 0) {
memcpy(path, name, len);
path[len] = ':';
path[len+1] = '\0';
@@ -501,7 +540,7 @@ get_pname_static(struct inode *dir, const char *name, int len,
*res_len = len;
DPRINTK("get_pname: path = %s, *pathlen = %d\n",
DDPRINTK("get_pname: path = %s, *pathlen = %d\n",
path, *res_len);
return 0;
}
@@ -771,10 +810,10 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
i, c_entry[i].path);
if (strcmp(c_entry[i].path, __name) == 0) {
DPRINTK("ncp_lookup: found in cache!\n");
finfo = c_entry[i];
finfo.path = NULL; /* It's not ours! */
found_in_cache = 1;
break;
finfo = c_entry[i];
finfo.path = NULL; /* It's not ours! */
found_in_cache = 1;
break;
}
i = (i + 1) % c_size;
DDPRINTK("ncp_lookup: index %d, name %s failed\n",
@@ -845,10 +884,191 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
return 0;
}
static int
ncp_create(struct inode *dir, const char *name, int len, int mode,
struct inode **result)
{
int error;
char *path = NULL;
struct ncp_dirent entry;
struct ncp_file_info finfo;
struct ncp_dirent *ino_finfo;
*result = NULL;
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("ncp_create: inode is NULL or not a directory\n");
iput(dir);
return -ENOENT;
}
/* The following are taken directly from msdos-fs */
/* Now we will have to build up an NCP filename. */
if ((error = get_pname(dir, name, len, &path, &len)) < 0) {
iput(dir);
return error;
}
if (ncp_create_newfile(NCP_SERVER(dir), 0, path, 0, &finfo) != 0) {
put_pname(path);
iput(dir);
return -EACCES;
}
entry.attr = finfo.file_attributes;
entry.mtime = date_dos2unix(finfo.update_time,
finfo.update_date);
entry.ctime = date_dos2unix(0, finfo.creation_date);
entry.atime = date_dos2unix(0, finfo.access_date);
entry.size = 0;
ncp_invalid_dir_cache(dir->i_ino);
if (!(*result = ncp_iget(dir, path, &entry)) < 0) {
ncp_close_file(NCP_SERVER(dir), finfo.file_id);
put_pname(path);
iput(dir);
return error;
}
ino_finfo = &(NCP_INOP(*result)->finfo);
ino_finfo->opened = 1;
ino_finfo->access = O_RDWR;
memcpy(&(ino_finfo->file_id), finfo.file_id, NCP_FILE_ID_LEN);
iput(dir);
return 0;
}
static int
ncp_mkdir(struct inode *dir, const char *name, int len, int mode)
{
int error;
char path[NCP_MAXPATHLEN];
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("ncp_mkdir: inode is NULL or not a directory\n");
iput(dir);
return -ENOENT;
}
/* Now we will have to build up an NCP filename. */
if ((error = get_pname_static(dir, name, len, path, &len)) < 0) {
iput(dir);
return error;
}
if ((error = ncp_create_directory(NCP_SERVER(dir), 0, path,
0xff)) == 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;
char path[NCP_MAXPATHLEN];
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("ncp_rmdir: inode is NULL or not a directory\n");
iput(dir);
return -ENOENT;
}
if ((error = get_pname_static(dir, name, len, path, &len)) < 0) {
iput(dir);
return error;
}
if (ncp_find_inode(NCP_SERVER(dir), path) != NULL) {
error = -EBUSY;
} else {
if ((error = ncp_delete_directory(NCP_SERVER(dir),
0, path)) == 0) {
ncp_invalid_dir_cache(dir->i_ino);
}
}
iput(dir);
return error;
}
static int
ncp_unlink(struct inode *dir, const char *name, int len)
{
int error;
char path[NCP_MAXPATHLEN];
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("ncp_unlink: inode is NULL or not a directory\n");
iput(dir);
return -ENOENT;
}
if ((error = get_pname_static(dir, name, len, path, &len)) < 0) {
iput(dir);
return error;
}
if (ncp_find_inode(NCP_SERVER(dir), path) != NULL) {
error = -EBUSY;
} else {
if ((error = ncp_erase_file(NCP_SERVER(dir), 0, path,
0)) == 0)
ncp_invalid_dir_cache(dir->i_ino);
}
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_path[NCP_MAXPATHLEN], new_path[NCP_MAXPATHLEN];
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;
}
res = get_pname_static(old_dir, old_name, old_len, old_path, &old_len);
if (res < 0) {
goto finished;
}
res = get_pname_static(new_dir, new_name, new_len, new_path, &new_len);
if (res < 0) {
goto finished;
}
if ( (ncp_find_inode(NCP_SERVER(old_dir), old_path) != NULL)
|| (ncp_find_inode(NCP_SERVER(new_dir), new_path) != NULL)) {
res = -EBUSY;
goto finished;
}
res = ncp_rename_file(NCP_SERVER(old_dir), 0, old_path, 0,0, new_path);
if (res == 0) {
ncp_invalid_dir_cache(old_dir->i_ino);
ncp_invalid_dir_cache(new_dir->i_ino);
}
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. */

83
file.c
View File

@@ -93,9 +93,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 +101,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;
@@ -145,10 +145,85 @@ ncp_file_read(struct inode *inode, struct file *file, char *buf, int count)
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_FINFO(inode)->path);
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_id,
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_FINFO(inode)->path);
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 */

79
inode.c
View File

@@ -34,15 +34,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
};
@@ -328,6 +330,79 @@ 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);
}
/* DO MORE */
static int
ncp_notify_change(struct inode *inode, struct iattr *attr)
{
int error = 0;
if ((error = inode_change_ok(inode, attr)) < 0)
return error;
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;
if ((attr->ia_valid & ATTR_SIZE) != 0) {
struct ncp_file_info finfo;
struct ncp_dirent *dirent = NCP_FINFO(inode);
DPRINTK("ncpfs: trying to change size of %s to %ld\n",
dirent->path, attr->ia_size);
if (attr->ia_size != 0) {
return -EPERM;
}
if (NCP_FINFO(inode)->opened != 0) {
ncp_close_file(NCP_SERVER(inode), dirent->file_id);
dirent->opened = 0;
}
if (ncp_create_file(NCP_SERVER(inode), 0,
dirent->path, 0, &finfo) == 0) {
ncp_close_file(NCP_SERVER(inode), finfo.file_id);
dirent->opened = 0;
}
error = 0;
}
ncp_invalid_dir_cache((unsigned long)(NCP_INOP(inode)->dir));
return error;
}
#ifdef DEBUG_NCP_MALLOC
int ncp_malloced;

BIN
ipx.tar Normal file

Binary file not shown.

34
ncp.h
View File

@@ -18,28 +18,28 @@
#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));
__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;
__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));
__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)

View File

@@ -50,10 +50,10 @@ 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))
static inline int min(int a, int b) {
@@ -124,7 +124,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

@@ -1,14 +1,14 @@
Begin3
Title: ncpfs
Version: 0.1
Entered-date: 19. October 1995
Version: 0.3
Entered-date: 01. 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
~45k ncpfs-0.3.tgz
~ 1k ncpfs-0.3.lsm
Copying-policy: GPL
End

237
ncplib.c
View File

@@ -126,6 +126,19 @@ ncp_add_mem(struct ncp_server *server, const char *source, int size)
return;
}
#ifdef __KERNEL__
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;
}
#endif
static void
ncp_add_pstring(struct ncp_server *server, const char *s)
{
@@ -536,6 +549,176 @@ ncp_close_file(struct ncp_server *server, const char *file_id)
return 0;
}
static int
ncp_do_create(struct ncp_server *server,
int dir_handle, const char *path,
int attr,
struct ncp_file_info *target,
int function)
{
int result;
ncp_init_request(server);
ncp_add_byte(server, dir_handle);
ncp_add_byte(server, attr);
ncp_add_pstring(server, path);
if ((result = ncp_request(server, function)) != 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_create_newfile(struct ncp_server *server,
int dir_handle, const char *path,
int attr,
struct ncp_file_info *target)
{
return ncp_do_create(server, dir_handle, path, attr, target, 77);
}
int
ncp_create_file(struct ncp_server *server,
int dir_handle, const char *path,
int attr,
struct ncp_file_info *target)
{
return ncp_do_create(server, dir_handle, path, attr, target, 67);
}
int
ncp_erase_file(struct ncp_server *server,
int dir_handle, const char *path,
int attr)
{
int result;
ncp_init_request(server);
ncp_add_byte(server, dir_handle);
ncp_add_byte(server, attr);
ncp_add_pstring(server, path);
if ((result = ncp_request(server, 68)) != 0) {
ncp_printf("ncp_request_error: %d\n", result);
ncp_unlock_server(server);
return result;
}
ncp_unlock_server(server);
return 0;
}
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 result;
ncp_init_request(server);
ncp_add_byte(server, old_handle);
ncp_add_byte(server, attr);
ncp_add_pstring(server, old_path);
ncp_add_byte(server, new_handle);
ncp_add_pstring(server, new_path);
if ((result = ncp_request(server, 69)) != 0) {
ncp_printf("ncp_request_error: %d\n", result);
ncp_unlock_server(server);
return result;
}
ncp_unlock_server(server);
return 0;
}
int
ncp_create_directory(struct ncp_server *server,
int dir_handle, const char *path,
int inherit_mask)
{
int result;
ncp_init_request_s(server, 10);
ncp_add_byte(server, dir_handle);
ncp_add_byte(server, inherit_mask);
ncp_add_pstring(server, path);
if ((result = ncp_request(server, 22)) != 0) {
ncp_printf("ncp_request_error: %d\n", result);
ncp_unlock_server(server);
return result;
}
ncp_unlock_server(server);
return 0;
}
int
ncp_delete_directory(struct ncp_server *server,
int dir_handle, const char *path)
{
int result;
ncp_init_request_s(server, 11);
ncp_add_byte(server, dir_handle);
ncp_add_byte(server, 0); /* reserved */
ncp_add_pstring(server, path);
if ((result = ncp_request(server, 22)) != 0) {
ncp_printf("ncp_request_error: %d\n", result);
ncp_unlock_server(server);
return result;
}
ncp_unlock_server(server);
return 0;
}
int
ncp_rename_directory(struct ncp_server *server,
int dir_handle,
const char *old_path, const char *new_path)
{
int result;
ncp_init_request_s(server, 15);
ncp_add_byte(server, dir_handle);
ncp_add_pstring(server, old_path);
ncp_add_pstring(server, new_path);
if ((result = ncp_request(server, 22)) != 0) {
ncp_printf("ncp_request_error: %d\n", result);
ncp_unlock_server(server);
return result;
}
ncp_unlock_server(server);
return 0;
}
#ifndef __KERNEL__
int
@@ -565,9 +748,35 @@ ncp_read(struct ncp_server *server, const char *file_id,
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(server, source, to_write);
if ((result = ncp_request(server, 73)) != 0) {
ncp_printf("ncp_request_error: %d\n", result);
ncp_unlock_server(server);
return result;
}
*bytes_written = to_write;
ncp_unlock_server(server);
return 0;
}
#else
/* We have to read into user space */
/* We have to transfer to/from user space */
int
ncp_read(struct ncp_server *server, const char *file_id,
__u32 offset, __u16 to_read,
@@ -595,4 +804,30 @@ ncp_read(struct ncp_server *server, const char *file_id,
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_printf("ncp_request_error: %d\n", result);
ncp_unlock_server(server);
return result;
}
*bytes_written = to_write;
ncp_unlock_server(server);
return 0;
}
#endif

View File

@@ -94,9 +94,51 @@ ncp_open_file(struct ncp_server *server,
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 start, __u16 to_read,
__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);
#endif /* _NCPLIB_H */

View File

@@ -15,13 +15,11 @@
#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 <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
@@ -38,8 +36,54 @@ extern pid_t waitpid(pid_t, int *, int);
#include "ipxutil.h"
static char *progname;
static char *mount_point;
static char *server_name;
static void
str_upper(char *name)
{
while (*name) {
*name = toupper(*name);
name = name + 1;
}
}
static char *
fullpath(const char *p)
{
char path[MAXPATHLEN];
if (realpath(p, path) == NULL)
return strdup(p);
else
return strdup(path);
}
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 */
@@ -47,15 +91,14 @@ struct sap_query {
};
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));
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)
{
@@ -212,33 +255,217 @@ ipx_sap_find_server(char *name, int server_type, int timeout,
return res;
}
int ipx_sscanf_node(char *buf, unsigned char node[6])
int
ipx_sscanf_node(char *buf, unsigned char node[6])
{
int i;
int n[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;
}
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;
for (i=0; i<6; i++) {
node[i] = n[i];
}
return 6;
}
int
main(int argc, char **argv)
static int
parse_args(int argc, char *argv[], struct ncp_mount_data *data,
int *got_password, int *upcase_password)
{
struct ncp_mount_data data;
struct stat st;
struct sockaddr_ipx addr;
int ncp_sock, wdog_sock;
int flags;
int opt;
struct passwd *pwd;
struct group *grp;
progname = argv[0];
*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;
int fd;
int Got_Password;
int Upcase_Password;
int um;
unsigned int flags;
char hostname[MAXHOSTNAMELEN + 1];
char *server_name;
char *mount_point;
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);
@@ -247,22 +474,43 @@ main(int argc, char **argv)
memset(&data, 0, sizeof(struct ncp_mount_data));
if (argc != 5) {
fprintf(stderr, "usage: %s server mount-point"
" user password\n", progname);
exit(1);
}
memset(hostname, '\0', MAXHOSTNAMELEN+1);
gethostname(hostname, MAXHOSTNAMELEN);
server_name = argv[1];
mount_point = argv[2];
if (argc < 3) {
if ( (argc == 2)
&& (argv[1][0] == '-')
&& (argv[1][1] == 'h')
&& (argv[1][2] == '\0')) {
if (stat(mount_point, &st) == -1) {
help();
return 0;
}
else
{
usage();
return -1;
}
}
server_name = argv[1];
mount_point = argv[2];
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",
@@ -297,10 +545,13 @@ main(int argc, char **argv)
exit(1);
}
printf("server: ");
ipx_fprint_saddr(stdout, &addr);
printf("\n");
/* 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;
@@ -309,24 +560,111 @@ main(int argc, char **argv)
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]);
/* 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) {
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");
close(wdog_sock);
close(ncp_sock);
printf("Maybe you should try to type the username and\n"
"password in UPPERCASE.\n");
return -1;
}
close(ncp_sock);
close(wdog_sock);
return 0;
}
ment.mnt_fsname = server_name;
ment.mnt_dir = fullpath(mount_point);
ment.mnt_type = "ncpfs";
ment.mnt_opts = "rw";
ment.mnt_freq = 0;
ment.mnt_passno= 0;
mount_point = ment.mnt_dir;
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;
}

173
ncptest.c Normal file
View File

@@ -0,0 +1,173 @@
/*
* 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 "ncplib.h"
#include "ipxutil.h"
static char *progname;
static char *mount_point;
void
test_filesearch(struct ncp_server *server)
{
struct ncp_filesearch_info fsinfo;
struct ncp_file_info finfo;
if (ncp_file_search_init(server, 0, "sys:\\public", &fsinfo) != 0) {
printf("could not fs init\n");
return;
}
while (ncp_file_search_continue(server, &fsinfo,
0,
"*", &finfo) == 0) {
printf("name: %s\n", finfo.file_name);
}
return;
}
void
test_getfinfo(struct ncp_server *server)
{
struct ncp_file_info finfo;
ncp_get_finfo(server, 0, "sys:", "public", &finfo);
ncp_get_finfo(server, 0, "sys:login", "login.exe", &finfo);
}
void
testopen(struct ncp_server *server)
{
struct ncp_file_info finfo;
char buf[1025];
int bytes_read;
ncp_open_file(server, 0, "sys:\\etc\\samples\\protocol", 0,
AR_READ|AR_WRITE,
&finfo);
if (ncp_read(server, finfo.file_id, 0, 1024, buf, &bytes_read) == 0) {
printf("bytes: %d\n", bytes_read);
buf[bytes_read]=0;
puts(buf);
}
ncp_close_file(server, finfo.file_id);
}
void
testcreate(struct ncp_server *server)
{
if (ncp_rename_file(server, 0, "sys:\\me\\blub.txt", 0,
0, "sys:\\me\\blub1.txt") != 0) {
printf("create war nix\n");
}
if (ncp_create_directory(server, 0, "sys:\\me\\blubdir", 0xff) != 0) {
printf("mkdir war nix\n");
}
if (ncp_rename_directory(server, 0, "sys:\\me\\blubdir",
"\\me\\blubneu") != 0) {
printf("mvdir war nix\n");
return;
}
if (ncp_delete_directory(server, 0, "sys:\\me\\blubneu") != 0) {
printf("rmdir war nix\n");
return;
}
}
int
main(int argc, char **argv)
{
struct ncp_mount_data data;
struct stat st;
struct ncp_server serv;
struct ncp_server *server = &serv;
progname = argv[0];
if (geteuid() != 0) {
fprintf(stderr, "%s must be installed suid root\n", progname);
exit(1);
}
memset(&data, 0, sizeof(struct ncp_mount_data));
if (argc == 2) {
mount_point = argv[1];
} else {
fprintf(stderr, "usage: %s mount-point\n", progname);
printf("defaulting to %s mnt\n", progname);
mount_point = "mnt";
}
if (stat(mount_point, &st) == -1) {
fprintf(stderr, "could not find mount point %s: %s\n",
mount_point, strerror(errno));
exit(1);
}
server->mount_fid = open(mount_point, O_RDONLY, 0);
if (server->mount_fid == -1) {
fprintf(stderr, "Could not open %s: %s\n",
mount_point, strerror(errno));
return -1;
}
#if 0
for (i=0; i<5; i++) {
struct ncp_volume_info info;
ncp_get_volume_info_with_number(server, i, &info);
printf("vol %d: %s\n", i, info.volume_name);
}
test_filesearch(server);
test_getfinfo(server);
#endif
testcreate(server);
return 0;
}

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

2
sock.c
View File

@@ -84,7 +84,7 @@ ncp_wdog_data_ready(struct sock *sk, int len)
sendto(sock, (void *)packet_buf, 2, 1, 0,
(struct sockaddr *)&sender,
sizeof(sender));
printk("send result: %d\n", result);
DPRINTK("send result: %d\n", result);
}
set_fs(fs);
}

7
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 abcd
ipx_route add 1234 abcd 00001b038b11

View File

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