Compare commits

...

6 Commits

Author SHA1 Message Date
ncpfs archive import
b36a27bedb Import ncpfs 2.0.0 2026-04-28 20:39:58 +02:00
ncpfs archive import
7d0e3d011b Import ncpfs 0.24 2026-04-28 20:39:58 +02:00
ncpfs archive import
84cb1f167d Import ncpfs 0.23 2026-04-28 20:39:58 +02:00
ncpfs archive import
64f006632a Import ncpfs 0.22 2026-04-28 20:39:58 +02:00
ncpfs archive import
92f749a943 Import ncpfs 0.21 2026-04-28 20:39:58 +02:00
ncpfs archive import
6cb56005ea Import ncpfs 0.20 2026-04-28 20:39:58 +02:00
35 changed files with 2153 additions and 203 deletions

BIN
.downloads/ncpfs-0.20.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.21.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.22.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.23.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.24.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-2.0.0.tgz Normal file

Binary file not shown.

49
Changes
View File

@@ -1,5 +1,52 @@
I only began this file with ncpfs-0.12. If you're interested in older
versions, you can find them on linux01.gwdg.de:/pub/ncpfs/old.
versions, you can find them on ftp.gwdg.de:/pub/linux/misc/ncpfs/old.
ncpfs-0.24 -> ncpfs-2.0.0
- Changed the numbering scheme :-).
- Added npasswd. Many thanks to Guntram Blom for his work!
- Hopefully improved error messages a bit
- Hopefully made slist a bit more robust
ncpfs-0.23 -> ncpfs-0.24
- Fixed a bug that made it impossible to umount a filesystem after you
tried 'mkdir .' or 'mkdir ..'.
- Fixed a bad race condition when opening files.
- Made the default timeout values more robust.
ncpfs-0.22 -> ncpfs-0.23
- Fixed a memory allocation problem in nwmsg.c. Thanks to
Andrew Ross <anr1001@hermes.cam.ac.uk>
- slist hopefully does not ask for a password anymore.
- cleaned up error messages a bit.
- ncpmount now calls modprobe instead of insmod.
ncpfs-0.21 -> ncpfs-0.22
- removed a bad race condition in kernel-1.2/src/dir.c.
- handle 0x9999-responses from the ncp server correctly.
- Bindery functions in ncplib.c by Brian G. Reid (breid@tim.com)
- set blocksize to 512 to satisfy 'du -k'
ncpfs-0.20 -> ncpfs-0.21
- Included two bugfixes in ncplib.c found by Jeff Buhrt
<buhrt@iquest.net>.
- Included a bugfix in kernel code that could only show for servers
that do not support namespace calls. I should have tried ncpfs
against lwared... Thanks to Neil Turton <ndt1001@chu.cam.ac.uk> for
this fix.
ncpfs-0.19 -> ncpfs-0.20
- Changed the home site for ncpfs from linux01.gwdg.de:/pub/ncpfs
to ftp.gwdg.de:/pub/linux/misc/ncpfs. linux01 will remain available,
but we would like to reduce the load on that machine. Sites
mirroring linux01 please redirect your mirror software to
ftp.gwdg.de. Thanks.
- Removed a bug in ncplib.c that made slist require a full
login. Thanks to Neil Turton <ndt1001@chu.cam.ac.uk> for the hint.
- The first real user contribution: ncopy by Brian G. Reid
(breid@tim.com) and Tom C. Henderson (thenderson@tim.com). Many
thanks to you! If you find bugs in ncopy, tell them, not me ;-)
- Handle expired passwords. Thanks to "Mathew Lim" <M.Lim@sp.ac.sg>
for the hint.
ncpfs-0.18 -> ncpfs-0.19

33
FAQ
View File

@@ -4,6 +4,39 @@ enough.
-------------------------------------------------------------------------------
Q: The ncpfs utilities like slist or ncpmount tell me that they can
not find a server, although I'm sure there are servers on my
net. What's wrong?
You probably used
ipx_configure --auto_interface=on --auto_primary=on
and you have Windows (95?) workstations on your network. Windows 95
makes Linux configure IPX interfaces for non-existent frame types. To
solve this problem, you have to configure your IPX interface manually
with the command
ipx_interface add -p <device> <frame>
For <device> use eth0, eth1 or whatever you network adapter is
called. The value for <frame> must match the frame type used on your
network. Possible values are 802.2, 802.3, SNAP and EtherII.
-------------------------------------------------------------------------------
Q: I have difficulties with NetWare 4.1. What can I do?
To be honest, I do not really know. Currently my only test equipment
is a NetWare 3.11 server. You should make your 4.1 Server as
3.x-compatible as it can be. As I do not know 4.1, you are on your own
doing this.
A promising hint that has already helped some people is to switch off
packet signatures on the 4.1 server, as ncpfs does not support them.
-------------------------------------------------------------------------------
Q: Does ncpfs support long file names, using the OS/2 namespace?
No. Not yet. I still have to sort out how that really works. But it should

View File

@@ -2,31 +2,29 @@
# Makefile for the linux ncp-filesystem routines.
#
VERSION = 0.19
TOPDIR = $(shell pwd)
BINDIR = /usr/local/bin
SBINDIR = /sbin
INTERM_BINDIR = $(TOPDIR)/bin
SUBDIRS = util ipx-1.0 man
#
# The following 2 lines are for those who use Kernel version 1.2.x.
# If you have a kernel later than 1.3.53, please comment out the
# the following lines. You have to recompile your kernel
# and say 'y' when 'make config' asks you for IPX and ncpfs.
#
SUBDIRS += kernel-1.2/src
INCLUDES = -I$(TOPDIR)/kernel-1.2
VERSION = 2.0.0
# If you are using kerneld to autoload ncp support,
# uncomment this (kerneld is in linux since about 1.3.57):
#KERNELD = -DHAVE_KERNELD
TOPDIR = $(shell pwd)
BINDIR = /usr/local/bin
SBINDIR = /sbin
INTERM_BINDIR = $(TOPDIR)/bin
SUBDIRS = util ipx-1.0 man
KVERSION=$(shell uname -r | cut -b3)
ifeq ($(KVERSION),2)
SUBDIRS += kernel-1.2/src
INCLUDES = -I$(TOPDIR)/kernel-1.2
endif
export INCLUDES BINDIR INTERM_BINDIR SBINDIR KERNELD VERSION
all:
for i in $(SUBDIRS); do make -C $$i; done
for i in $(SUBDIRS); do make -C $$i all; done
dep:
for i in $(SUBDIRS); do make -C $$i dep; done
@@ -44,6 +42,7 @@ clean:
mrproper: clean
rm -fr $(INTERM_BINDIR)/* ncpfs.tgz
make -C util mrproper
(cd daemon; make clean)
modules: ncpfs.o
@@ -51,7 +50,13 @@ SRCPATH=$(shell pwd)
SRCDIR=$(shell basename $(SRCPATH))
DISTFILE=$(SRCDIR).tgz
dist: tgz
dist: mrproper
mv daemon ..
(cd ..; \
tar cvf - $(SRCDIR) | \
gzip -9 > $(DISTFILE); \
mv $(DISTFILE) $(SRCDIR))
mv ../daemon .
make dep
make all

21
README
View File

@@ -3,8 +3,22 @@ some little utilities it also contains nprint, which enables you to
print on NetWare print queues. The opposite side, pserver, is also
provided.
I'm planning major changes in the structure of ncpfs for Linux 2.1.x
which will break the binary compatibility. So I changed the numbering
scheme for ncpfs. ncpfs-2.0.x will be the version to be used with
Linux 2.0.0 and older kernels, and ncpfs-2.1.x will be the version for
the development kernels.
INSTALLATION
Before you start the installation, make sure that your kernel has IPX
support compiled in. When 'make config' asks you for
The IPX protocol (CONFIG_IPX) [N/y/m/?]
simply answer 'y'. Probably you do not need the full internal net that
you are asked for next.
The installation of ncpfs depends on the kernel version you are
using. For kernel 1.2, you should simply type 'make' and look at
what's in the bin/ directory after that. Please be sure that your
@@ -22,11 +36,8 @@ asks for ncpfs. After you have rebooted with the new kernel, 'cat
/proc/filesystems' should show you a line saying that the kernel knows
ncpfs.
With Kernel 1.3.71 or later you also have to modify the Makefile in the
directory you found this README in. Please see the Makefile for the
necessary modifications. Then typing 'make' should work with no
problem.
If you are running kerneld, please uncomment the corresponding line in
the Makefile to reflect this.
HELP

View File

@@ -12,6 +12,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <errno.h>
struct option options[] = {
{ "auto_primary", required_argument, NULL, 1 },
@@ -66,8 +67,14 @@ main(int argc, char **argv)
s = socket(AF_IPX, SOCK_DGRAM, AF_IPX);
if (s < 0) {
int old_errno = errno;
sprintf(errmsg, "%s: socket", progname);
perror(errmsg);
if (old_errno == -EINVAL)
{
fprintf(stderr, "Probably you have no IPX support in "
"your kernel\n");
}
exit(-1);
}

View File

@@ -15,6 +15,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <errno.h>
static struct ifreq id;
static char *progname;
@@ -118,8 +119,14 @@ ipx_add_interface(int argc, char **argv)
s = socket(AF_IPX, SOCK_DGRAM, AF_IPX);
if (s < 0) {
int old_errno = errno;
sprintf(errmsg, "%s: socket", progname);
perror(errmsg);
if (old_errno == -EINVAL)
{
fprintf(stderr, "Probably you have no IPX support in "
"your kernel\n");
}
exit(-1);
}

View File

@@ -236,7 +236,7 @@ handle_frame (unsigned char *buf, int length, struct sockaddr *saddr)
switch( packet_type )
{
case __constant_ntohs(ETH_P_IPX):
handle_ipx("EtherII ", &(buf[sizeof(struct ethhdr)]));
handle_ipx("EtherII", &(buf[sizeof(struct ethhdr)]));
break;
default:
handle_other(buf, length, saddr);

View File

@@ -275,6 +275,124 @@ void handle_ncp (struct sockaddr_ipx *source,
switch(rq->function)
{
case 20:
printf("fn: %-3d\n", rq->function);
printf("Get File Server Date and Time\n");
break;
case 21:
printf("fn: %-3d, subfn: %-3d\n",
rq->function, data[2]);
switch(data[2])
{
case 0:
printf("Send Broadcast Message\n");
break;
case 1:
printf("Get Broadcast Message\n");
break;
}
data += 3;
data_length -= 3;
break;
case 22:
printf("fn: %-3d, subfn: %-3d\n",
rq->function, data[2]);
switch(data[2])
{
case 00:
printf("Set Directory Handle\n");
break;
case 01:
printf("Get Directory Path\n");
break;
case 18:
printf("Allocate Permanent Dir Handle\n");
break;
case 20:
printf("Deallocate Directory Handle\n");
break;
case 21:
printf("Get Volume Info with handle\n");
break;
}
data += 3;
data_length -= 3;
break;
case 23:
printf("fn: %-3d, subfn: %-3d\n", rq->function,
data[2]);
switch(data[2])
{
case 17:
printf("Get Fileserver Information\n");
break;
case 23:
printf("Get Crypt Key\n");
break;
case 24:
printf("Encrypted Login\n");
break;
case 28:
printf("Get Connection Information\n");
break;
case 53:
printf("Get Bindery Object ID\n");
break;
case 55:
printf("Scan Bindery Object\n");
break;
case 61:
printf("Read Property Value\n");
break;
case 62:
printf("Write Property Value\n");
break;
case 70:
printf("Get Bindery Access Level\n");
break;
}
data += 3;
data_length -= 3;
break;
case 24:
printf("fn: %-3d\n", rq->function);
printf("End of Job\n");
break;
case 34:
printf("fn: %-3d, subfn: %-3d\n", rq->function,
data[2]);
data += 3;
data_length -= 3;
break;
case 62:
printf("fn: %-3d\n", rq->function);
printf("File Search Initialize\n");
break;
case 63:
printf("fn: %-3d\n", rq->function);
printf("File Search Continue\n");
break;
case 64:
printf("fn: %-3d\n", rq->function);
printf("Search for a file\n");
break;
case 66:
printf("fn: %-3d\n", rq->function);
printf("Close File\n");
break;
case 72:
printf("fn: %-3d\n", rq->function);
printf("Read from File\n");
break;
case 73:
printf("fn: %-3d\n", rq->function);
printf("Write to File\n");
break;
case 75:
printf("fn: %-3d\n", rq->function);
printf("Set File Time Date Stamp\n");
break;
case 87:
printf("fn: %-3d, subfn: %-3d\n",
rq->function, data[0]);
@@ -311,86 +429,6 @@ void handle_ncp (struct sockaddr_ipx *source,
data += 1;
data_length -= 1;
break;
case 21:
printf("fn: %-3d, subfn: %-3d\n",
rq->function, data[2]);
switch(data[2])
{
case 0:
printf("Send Broadcast Message\n");
break;
case 1:
printf("Get Broadcast Message\n");
break;
}
data += 3;
data_length -= 3;
break;
case 22:
printf("fn: %-3d, subfn: %-3d\n",
rq->function, data[2]);
switch(data[2])
{
case 21:
printf("Get Volume Info with handle\n");
break;
}
data += 3;
data_length -= 3;
break;
case 23:
printf("fn: %-3d, subfn: %-3d\n", rq->function,
data[2]);
switch(data[2])
{
case 17:
printf("Get Fileserver Information\n");
break;
case 28:
printf("Get Connection Information\n");
break;
case 55:
printf("Scan Bindery Object\n");
break;
}
data += 3;
data_length -= 3;
break;
case 24:
printf("fn: %-3d\n", rq->function);
printf("End of Job\n");
break;
case 34:
printf("fn: %-3d, subfn: %-3d\n", rq->function,
data[2]);
data += 3;
data_length -= 3;
break;
case 62:
printf("fn: %-3d\n", rq->function);
printf("File Search Initialize\n");
break;
case 63:
printf("fn: %-3d\n", rq->function);
printf("File Search Continue\n");
break;
case 64:
printf("fn: %-3d\n", rq->function);
printf("Search for a file\n");
break;
case 66:
printf("fn: %-3d\n", rq->function);
printf("Close File\n");
break;
case 73:
printf("fn: %-3d\n", rq->function);
printf("Write to File\n");
break;
case 75:
printf("fn: %-3d\n", rq->function);
printf("Set File Time Date Stamp\n");
break;
default:
printf("fn: %-3d\n", rq->function);
}

View File

@@ -61,7 +61,7 @@ struct ncp_fs_info {
#define NCP_READDIR_CACHE_SIZE 64
#define NCP_MAX_RPC_TIMEOUT (60) /* 6 seconds */
#define NCP_MAX_RPC_TIMEOUT (6*HZ)
/* Guess, what 0x564c is :-) */
#define NCP_SUPER_MAGIC 0x564c

View File

@@ -20,6 +20,7 @@
#include <linux/ncp_fs.h>
#include <asm/segment.h>
#include <linux/errno.h>
#include <linux/locks.h>
#include "ncplib_kernel.h"
struct ncp_dirent {
@@ -200,12 +201,30 @@ static int c_size;
static int c_seen_eof;
static int c_last_returned_index;
static struct ncp_dirent* c_entry = NULL;
static int c_lock = 0;
static struct wait_queue *c_wait = NULL;
static inline void
ncp_lock_dircache(void)
{
while (c_lock)
sleep_on(&c_wait);
c_lock = 1;
}
static inline void
ncp_unlock_dircache(void)
{
c_lock = 0;
wake_up(&c_wait);
}
static int
ncp_readdir(struct inode *inode, struct file *filp,
struct dirent *dirent, int count)
{
int result, i = 0;
int result = 0;
int i = 0;
int index = 0;
struct ncp_dirent *entry = NULL;
struct ncp_server *server = NCP_SERVER(inode);
@@ -238,6 +257,7 @@ ncp_readdir(struct inode *inode, struct file *filp,
return -EIO;
}
ncp_lock_dircache();
if (c_entry == NULL)
{
i = sizeof (struct ncp_dirent) * NCP_READDIR_CACHE_SIZE;
@@ -245,7 +265,8 @@ ncp_readdir(struct inode *inode, struct file *filp,
if (c_entry == NULL)
{
printk("ncp_readdir: no MEMORY for cache\n");
return -ENOMEM;
result = -ENOMEM;
goto finished;
}
}
@@ -255,10 +276,11 @@ ncp_readdir(struct inode *inode, struct file *filp,
if (filldir(dirent,".",1, filp->f_pos,
ncp_info_ino(server, dir)) < 0)
{
return 0;
goto finished;
}
filp->f_pos += 1;
return ROUND_UP(NAME_OFFSET(dirent)+i+1);
result = ROUND_UP(NAME_OFFSET(dirent)+i+1);
goto finished;
}
if (filp->f_pos == 1)
@@ -266,10 +288,11 @@ ncp_readdir(struct inode *inode, struct file *filp,
if (filldir(dirent,"..",2, filp->f_pos,
ncp_info_ino(server, dir->dir)) < 0)
{
return 0;
goto finished;
}
filp->f_pos += 1;
return ROUND_UP(NAME_OFFSET(dirent)+i+1);
result = ROUND_UP(NAME_OFFSET(dirent)+i+1);
goto finished;
}
if ((inode->i_dev == c_dev) && (inode->i_ino == c_ino))
@@ -286,42 +309,44 @@ ncp_readdir(struct inode *inode, struct file *filp,
}
if ((entry == NULL) && c_seen_eof)
{
return 0;
goto finished;
}
}
if (entry == NULL)
{
int entries;
DDPRINTK("ncp_readdir: Not found in cache.\n");
if (ncp_is_server_root(inode))
{
result = ncp_read_volume_list(server, filp->f_pos,
NCP_READDIR_CACHE_SIZE);
DPRINTK("ncp_read_volume_list returned %d\n", result);
entries = ncp_read_volume_list(server, filp->f_pos,
NCP_READDIR_CACHE_SIZE);
DPRINTK("ncp_read_volume_list returned %d\n", entries);
}
else
{
result = ncp_do_readdir(server, inode, filp->f_pos,
NCP_READDIR_CACHE_SIZE,
c_entry);
DPRINTK("ncp_readdir returned %d\n", result);
entries = ncp_do_readdir(server, inode, filp->f_pos,
NCP_READDIR_CACHE_SIZE,
c_entry);
DPRINTK("ncp_readdir returned %d\n", entries);
}
if (result < 0)
if (entries < 0)
{
c_dev = 0;
c_ino = 0;
return result;
result = entries;
goto finished;
}
if (result > 0)
if (entries > 0)
{
c_seen_eof = (result < NCP_READDIR_CACHE_SIZE);
c_seen_eof = (entries < NCP_READDIR_CACHE_SIZE);
c_dev = inode->i_dev;
c_ino = inode->i_ino;
c_size = result;
c_size = entries;
entry = c_entry;
c_last_returned_index = 0;
index = 0;
@@ -336,7 +361,7 @@ ncp_readdir(struct inode *inode, struct file *filp,
if (entry == NULL)
{
/* Nothing found, even from a ncp call */
return 0;
goto finished;
}
if (index < c_size)
@@ -374,15 +399,18 @@ ncp_readdir(struct inode *inode, struct file *filp,
if (filldir(dirent, entry->i.entryName, entry->i.nameLen,
entry->f_pos, ino) < 0)
{
return 0;
goto finished;
}
filp->f_pos += 1;
index += 1;
entry += 1;
return ROUND_UP(NAME_OFFSET(dirent)+i+1);
result = ROUND_UP(NAME_OFFSET(dirent)+i+1);
goto finished;
}
return 0;
finished:
ncp_unlock_dircache();
return result;
}
static int
@@ -407,7 +435,7 @@ ncp_read_volume_list(struct ncp_server *server, int fpos, int cache_size)
if (ncp_get_volume_info_with_number(server, i, &info) != 0)
{
return total_count;
return (total_count - fpos);
}
if (strlen(info.volume_name) > 0)
@@ -800,7 +828,7 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
memcpy(name, __name, len);
name[len] = 0;
lock_super(dir->i_sb);
result_info = ncp_find_dir_inode(dir, name);
if (result_info != 0)
@@ -814,6 +842,7 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
inode number */
*result = iget(dir->i_sb, ncp_info_ino(server, result_info));
unlock_super(dir->i_sb);
iput(dir);
if (*result == NULL)
@@ -828,7 +857,9 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
server. */
found_in_cache = 0;
ncp_lock_dircache();
if ((dir->i_dev == c_dev) && (dir->i_ino == c_ino))
{
int first = c_last_returned_index;
@@ -851,6 +882,7 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
}
while (i != first);
}
ncp_unlock_dircache();
if (found_in_cache == 0)
{
@@ -873,6 +905,7 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
}
if (res != 0)
{
unlock_super(dir->i_sb);
iput(dir);
return -ENOENT;
}
@@ -883,10 +916,12 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
if (!(*result = ncp_iget(dir, &finfo)))
{
unlock_super(dir->i_sb);
iput(dir);
return -EACCES;
}
unlock_super(dir->i_sb);
iput(dir);
return 0;
}
@@ -916,6 +951,7 @@ ncp_create(struct inode *dir, const char *name, int len, int mode,
_name[len] = '\0';
str_upper(_name);
lock_super(dir->i_sb);
if (ncp_open_create_file_or_subdir(NCP_SERVER(dir),
NCP_ISTRUCT(dir), _name,
OC_MODE_CREATE|OC_MODE_OPEN|
@@ -923,6 +959,7 @@ ncp_create(struct inode *dir, const char *name, int len, int mode,
0, AR_READ|AR_WRITE,
&finfo) != 0)
{
unlock_super(dir->i_sb);
iput(dir);
return -EACCES;
}
@@ -935,10 +972,12 @@ ncp_create(struct inode *dir, const char *name, int len, int mode,
if (!(*result = ncp_iget(dir, &finfo)) < 0)
{
ncp_close_file(NCP_SERVER(dir), finfo.file_handle);
unlock_super(dir->i_sb);
iput(dir);
return -EINVAL;
}
unlock_super(dir->i_sb);
iput(dir);
return 0;
}
@@ -955,6 +994,7 @@ ncp_mkdir(struct inode *dir, const char *name, int len, int mode)
|| ( (len == 2)
&& (name[1] == '.'))))
{
iput(dir);
return -EEXIST;
}

View File

@@ -21,6 +21,7 @@
#include <linux/stat.h>
#include <linux/mm.h>
#include <linux/ncp_fs.h>
#include <linux/locks.h>
#include "ncplib_kernel.h"
#include <linux/malloc.h>
@@ -50,8 +51,10 @@ ncp_make_open(struct inode *i, int right)
DPRINTK("ncp_make_open: dirent->opened = %d\n", finfo->opened);
lock_super(i->i_sb);
if (finfo->opened == 0)
{
finfo->access = -1;
/* tries max. rights */
if (ncp_open_create_file_or_subdir(NCP_SERVER(i),
NULL, NULL,
@@ -69,12 +72,10 @@ ncp_make_open(struct inode *i, int right)
{
finfo->access = O_RDONLY;
}
else
{
return -EACCES;
}
}
unlock_super(i->i_sb);
if ( ((right == O_RDONLY) && ( (finfo->access == O_RDONLY)
|| (finfo->access == O_RDWR)))
|| ((right == O_WRONLY) && ( (finfo->access == O_WRONLY)

View File

@@ -94,7 +94,7 @@ ncp_read_inode(struct inode *inode)
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_blksize = 512;
inode->i_rdev = 0;
if ((inode->i_blksize != 0) && (inode->i_size != 0))
@@ -132,7 +132,9 @@ static void
ncp_put_inode(struct inode *inode)
{
struct nw_file_info *finfo = NCP_FINFO(inode);
struct super_block *sb = inode->i_sb;
lock_super(sb);
if (finfo->opened != 0)
{
if (ncp_close_file(NCP_SERVER(inode), finfo->file_handle)!=0)
@@ -155,6 +157,7 @@ ncp_put_inode(struct inode *inode)
}
clear_inode(inode);
unlock_super(sb);
}
struct super_block *

View File

@@ -222,6 +222,7 @@ do_ncp_rpc_call(struct ncp_server *server, int size)
int timeout;
int retrans;
int major_timeout_seen;
int acknowledge_seen;
int n;
int addrlen;
unsigned long old_mask;
@@ -243,7 +244,8 @@ do_ncp_rpc_call(struct ncp_server *server, int size)
return -EBADF;
}
init_timeout = server->m.time_out;
max_timeout = NCP_MAX_RPC_TIMEOUT*HZ/10;
max_timeout = NCP_MAX_RPC_TIMEOUT;
acknowledge_seen = 0;
retrans = server->m.retry_count;
major_timeout_seen = 0;
old_mask = current->blocked;
@@ -296,11 +298,14 @@ do_ncp_rpc_call(struct ncp_server *server, int size)
{
if (timeout > max_timeout)
{
/* JEJB/JSP 2/7/94
* This is useful to see if the system is
* hanging */
printk("NCP max timeout reached\n");
timeout = max_timeout;
/* JEJB/JSP 2/7/94
* This is useful to see if the system is
* hanging */
if (acknowledge_seen == 0)
{
printk("NCP max timeout reached\n");
}
timeout = max_timeout;
}
current->timeout = jiffies + timeout;
schedule();
@@ -373,6 +378,9 @@ do_ncp_rpc_call(struct ncp_server *server, int size)
sock->ops->recvfrom(sock, (void *)&reply,
sizeof(reply), 1, 0,
NULL, &addrlen);
n = 0;
timeout = max_timeout;
acknowledge_seen = 1;
goto re_select;
}

View File

@@ -1,4 +1,4 @@
MAN1= slist nprint pqlist nsend pserver
MAN1= slist nprint pqlist nsend pserver ncopy npasswd
MAN5= nwclient
MAN8= ncpmount ncpumount ipx_configure ipx_interface ipx_internal_net \
ipx_route nwmsg

96
man/ncopy.1 Normal file
View File

@@ -0,0 +1,96 @@
.\"
.\" Man page for the ncopy program
.\"
.TH NCOPY 1 17/03/1996 ncopy ncopy
.SH NAME
ncopy \- NetWare file copy
.SH SYNOPSIS
.B ncopy -V
.B ncopy
[
.B -vn
]
[
.B -s
.I amount
]
.B file destinationfile|directory
.B ncopy
[
.B -vn
]
[
.B -s
.I amount
]
.B file1
[
.B file2 ...
]
.B directory
.SH DESCRIPTION
With
.B ncopy
you can copy files to different locations on a single NetWare file
server without generating excess network traffic. The program uses
a NetWare function to do the copy rather than transferring the file
across the network for both the read and write.
If the last argument is a directory,
.B ncopy
will copy the source file(s) into the directory. If only two files
are given and the last argument is not a directory, it will copy the
source file to the destination file.
If the source and destination files are not on the same NetWare server
(or are not on NetWare servers at all),
.B ncopy
will do a normal file copy.
.SH OPTIONS
.B -V
.RS 3
Show version number and exit
.RE
.B -v
.RS 3
Verbose copy. Will show current file and percentage completion.
.RE
.B -n
.RS 3
Nice NetWare copy. Will sleep for a second between copying blocks on
the NetWare server. Gives other people a chance to do some work on
the NetWare server when you are copying large files. This has no
effect if you are not copying on a NetWare server.
.RE
.B -s
.I amount
.RS 3
Nice time slice factor. Used in conjunction with the
.B -n
option, this specifies the number of 100K blocks to copy before sleeping.
Default is 10. (1 Megabyte)
.RE
.SH BUGS
.B ncopy
cannot recurse into directories.
Does not work on NetWare volumes mounted with the
.I -V
option to
.B ncpmount.
.SH "SEE ALSO"
.B ncpmount(8), ncpumount(8)
.SH CREDITS
ncopy was written by Brian G. Reid (breid@tim.com) and
Tom C. Henderson (thenderson@tim.com).
Many thanks to Volker Lendecke (lendecke@namu01.gwdg.de) for the ncpfs
and ncplib which made ncopy possible.

55
man/npasswd.1 Normal file
View File

@@ -0,0 +1,55 @@
.TH NPASSWD 1 06/22/1996 npasswd npasswd
.SH NAME
npasswd \- Change a user's password
.SH SYNOPSIS
.B npasswd
[
.B -h
] [
.B -S
.I server
] [
.B -U
.I user name
]
.B -t
.I object type
]
.SH DESCRIPTION
With
.B npasswd,
you can change your password on a NetWare server.
.B npasswd
asks for the old password and twice for the new password. Then it
changes the password on the server.
.SH OPTIONS
.B -h
.RS 3
With -h npasswd prints a little help text.
.RE
.B -S
.I server
.RS 3
is the name of the server you want to use.
.RE
.B -U
.I user name
.RS 3
is the name of the bindery object whose password is to be changed.
.RE
.B -t
.I object type
.RS 3
is the bindery object type of the object whose password is to be
changed.
.RE
.SH CREDITS
npasswd would not have been possible without the work of Guntram
Blom. Look at nwcrypt.c for his work.

View File

@@ -1,19 +0,0 @@
Begin3
Title: ncpfs
Version: 0.19
Entered-date: 22. March 1996
Description: With ncpfs you can mount volumes of your netware
server under Linux. You can also print to netware
print queues and spool netware print queues to the
Linux printing system. You need kernel 1.2.x or
1.3.54 and above. ncpfs does NOT work with any 1.3.x
kernel below 1.3.54.
Keywords: filesystem ncp novell netware printing
Author: lendecke@namu01.gwdg.de (Volker Lendecke)
Maintained-by: lendecke@namu01.gwdg.de (Volker Lendecke)
Primary-site: linux01.gwdg.de:/pub/ncpfs
Alternate-site: sunsite.unc.edu:/pub/system/Filesystems/
~103k ncpfs-0.19.tgz
~ 1k ncpfs-0.19.lsm
Copying-policy: GPL
End

19
ncpfs-2.0.0.lsm Normal file
View File

@@ -0,0 +1,19 @@
Begin3
Title: ncpfs
Version: 2.0.0
Entered-date: 22. June 1996
Description: With ncpfs you can mount volumes of your netware
server under Linux. You can also print to netware
print queues and spool netware print queues to the
Linux printing system. You need kernel 1.2.x or
1.3.71 and above. ncpfs does NOT work with any 1.3.x
kernel below 1.3.71.
Keywords: filesystem ncp novell netware printing
Author: lendecke@namu01.Num.Math.Uni-Goettingen.de (Volker Lendecke)
Maintained-by: lendecke@namu01.Num.Math.Uni-Goettingen.de (Volker Lendecke)
Primary-site: ftp.gwdg.de:/pub/linux/misc/ncpfs
Alternate-site: sunsite.unc.edu:/pub/system/Filesystems/ncpfs
~120k ncpfs-2.0.0.tgz
~ 1k ncpfs-2.0.0.lsm
Copying-policy: GPL
End

View File

@@ -2,7 +2,7 @@
# Makefile for the linux ncp-filesystem routines.
#
USERUTILS = slist pqlist nwfsinfo pserver nprint nsend
USERUTILS = slist pqlist nwfsinfo pserver nprint nsend ncopy npasswd
UIDUTILS = ncpmount ncpumount
SBINUTILS = nwmsg
@@ -13,6 +13,9 @@ UTILS = $(addprefix $(INTERM_BINDIR)/,$(UTIL_EXECS))
CFLAGS = -Wall $(INCLUDES) $(KERNELD) -O2 -DNCPFS_VERSION=\"$(VERSION)\"
CC = gcc
default:
make -C ..
all: $(UTILS) ncptest
install: all

849
util/ncopy.c Normal file
View File

@@ -0,0 +1,849 @@
/****************************************************************************
* ncopy.c
*
* Copy file on a Netware server without Network Traffic
*
* Copyright (C) 1996 by Brian Reid and Tom Henderson.
*
* Send bug reports for ncopy to "breid@tim.com"
*
* Still to do: support recursive copy with two arguments
* Both must be directories. (similar to rcp -r)
*
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <ctype.h>
#include <mntent.h>
#include <fcntl.h>
#include <signal.h>
#include "ncplib.h"
struct NCPMountRec
{
char *mountDir;
char *server;
struct ncp_conn *conn;
};
/****************************************************************************
* Globals:
*
*/
const char *VersionStr = "0.1";
char * ProgramName;
struct NCPMountRec *NcpMountTable = NULL;
int ncpCount = 0;
/* (initialized) command options */
int optVersion=0; /* -V TRUE if just want version */
int optVerbose=0; /* -v TRUE if want verbose output */
int optNice=0; /* -n TRUE if we are cooperative (nice) */
int optNiceFactorSel=0; /* -s TRUE if we selected a nice factor */
int optNiceFactor=10; /* -s arg, number of 100K blocks to copy
before sleeping for a second */
__u32 CopyBlockSize = 100000; /* Size of the default block copy size */
unsigned int NiceSleepTime=1; /* Number of seconds to sleep in Nice Mode */
int BlocksCopied=0; /* Number of blocks copied */
int MaxNcopyRetries=25; /* Maximum number of times to retry a failed
copy before giving up */
/* Globals needed for signal handlers */
int OutputOpen=0; /* True if the ncp output file is open */
struct ncp_conn *CurrentConn = NULL; /* Connection of output file */
struct ncp_file_info *CurrentFile = NULL; /* File info of output file */
/* Signal control structures */
static struct sigaction sHangupSig;
static struct sigaction sInterruptSig;
static struct sigaction sQuitSig;
static struct sigaction sTermSig;
/****************************************************************************
*
*/
static void usage()
{
fprintf(stderr,"usage: %s [-V]\n", ProgramName);
fprintf(stderr," %s [-vn] [-s amt] sourcefile destinationfile|directory\n", ProgramName);
fprintf(stderr," %s [-vn] [-s amt] sourcefile [...] directory\n", ProgramName);
}
/****************************************************************************
* Return pointer to last component of the path.
* Returned string may have one or more "/" left on the end.
* ("/" returns pointer to "/", null returns pointer to null)
* Return pointer to original string if no "/" in string. (except at end)
*/
static const char *myBaseName(const char *path)
{
const char *p;
for(p = &path[strlen(path)]; p != path; p--) { /* skip ENDING "/" chars */
if(*p && *p != '/') break;
}
if(p==path) return p;
for( ; p != path || *p == '/'; p--) {
if(*p == '/') return ++p;
}
return p;
}
/****************************************************************************
*
*/
static const char *notDir(const char *path)
{
struct stat buf;
static const char *notDirectory="not a directory";
if(stat(path, &buf)) return strerror(errno); /* no permission? not exist? */
if(!S_ISDIR(buf.st_mode)) return notDirectory; /* not a directory */
return (char *) 0; /* OK */
}
/****************************************************************************
*
*/
static int handleOptions(const int argc, char * const argv[])
{
int opt;
while ((opt = getopt(argc, argv, "vVns:")) != EOF)
{
switch (opt) {
case 'V': /* Version */
optVersion=1;
break;
case 'v': /* Verbose output */
optVerbose=1;
break;
case 'n': /* Nice, cooperative copy */
optNice=1;
break;
case 's': /* Nice Factor */
optNiceFactorSel=1;
optNiceFactor=atoi(optarg);
if (optNiceFactor < 1) {
fprintf(stderr,"%s: -s option requires positive numeric argument > 0\n",
ProgramName);
return 1;
}
break;
default: /* invalid options or options without required arguments */
return 1;
}
continue;
}
return 0;
}
/****************************************************************************
* TODO: if recursive flag last MUST be a directory, even if only 2 args.
*/
static int validateFileArgs(const int argc, char * const argv[])
{
const char *p;
if (argc == 0) {
fprintf(stderr,"%s: No arguments specified.\n", ProgramName);
return 1;
}
if(argc == 1) {
fprintf(stderr,"%s: No destination specified.\n", ProgramName);
return 1;
}
if((argc > 2) && (p=notDir(argv[argc-1]))) { /* last arg MUST be dir */
fprintf(stderr,"%s: %s: %s\n", ProgramName, argv[argc-1], p);
return 1;
}
return 0;
}
/****************************************************************************
* Duplicate a string.
*/
char *duplicateStr(const char *InStr)
{
char *dup;
if (!InStr) return NULL;
dup = (char*)malloc(strlen(InStr)+1);
if (dup)
strcpy(dup,InStr);
return dup;
}
/****************************************************************************
* load a table of ncpfs mount points.
*/
int loadMountTable()
{
FILE *mountedFile;
struct mntent *mountEntry = NULL;
ncpCount = 0;
if ( (mountedFile = fopen(MOUNTED,"r")) == NULL) {
fprintf(stderr,"ncopy: cannot open %s, %s\n",MOUNTED,strerror(errno));
return 1;
}
while ( (mountEntry = getmntent(mountedFile)) != NULL) {
if (!strcmp(mountEntry->mnt_type,"ncpfs"))
ncpCount++;
}
if (ncpCount) {
NcpMountTable = (struct NCPMountRec*)
malloc(ncpCount * sizeof(struct NCPMountRec));
if (!NcpMountTable) {
fprintf(stderr,"Out of memory\n");
fclose(mountedFile);
return 1;
}
fseek(mountedFile,0,SEEK_SET);
ncpCount = 0;
while ( (mountEntry = getmntent(mountedFile)) != NULL) {
if (!strcmp(mountEntry->mnt_type,"ncpfs")) {
NcpMountTable[ncpCount].mountDir = duplicateStr(mountEntry->mnt_dir);
NcpMountTable[ncpCount].server =
duplicateStr(mountEntry->mnt_fsname);
NcpMountTable[ncpCount].conn = NULL;
ncpCount++;
}
}
}
fclose(mountedFile);
return 0;
}
/****************************************************************************
* Releases the table of ncpfs mount points.
*/
void releaseMountTable()
{
int loop;
if (!ncpCount) return;
for (loop = ncpCount; loop; loop--,ncpCount--) {
if (NcpMountTable[loop-1].conn) {
ncp_close(NcpMountTable[loop-1].conn);
NcpMountTable[loop-1].conn = NULL;
}
free(NcpMountTable[loop-1].server);
free(NcpMountTable[loop-1].mountDir);
}
free(NcpMountTable);
}
/****************************************************************************
* Finds the index into the mount point table that enables ncp copy for
* the file.
* Returns -1 if the files do not reference the same server.
*/
int ncpIndex(const char *InputFile, const char *OutputFile)
{
int loop;
char *mountDir;
if (!ncpCount) return -1;
for (loop = 0; loop < ncpCount; loop++) {
mountDir = NcpMountTable[loop].mountDir;
if (!strncmp(mountDir,InputFile,strlen(mountDir)) &&
!strncmp(mountDir,OutputFile,strlen(mountDir))) return loop;
}
return -1;
}
/****************************************************************************
* Does a regular buffered file copy.
* This is used if we cannot use the Netware file copy.
*/
int normalFileCopy(const char *InputFile, const char *OutputFile,
char *Buffer,int BufferSize,
const char *paramInputFile,
const char *paramOutputFile)
{
int fdIn, fdOut;
long fileSize,totalSize;
struct stat statBuf;
fdIn = open(InputFile,O_RDONLY);
if (fdIn == -1) {
fprintf(stderr,"%s: Cannot open %s, %s\n",ProgramName,paramInputFile,
strerror(errno));
return 1;
}
if (fstat(fdIn,&statBuf)) {
fprintf(stderr,"%s: Cannot stat %s, %s\n",ProgramName,paramInputFile,
strerror(errno));
close(fdIn);
return 1;
}
if(S_ISDIR(statBuf.st_mode)) {
close(fdIn);
fprintf(stderr,"%s: %s: omitting directory\n",ProgramName,paramInputFile);
return 0; /* At this point, don't consider this a fatal error */
}
fdOut = open(OutputFile,O_CREAT | O_TRUNC | O_WRONLY,statBuf.st_mode);
if (fdOut == -1) {
fprintf(stderr,"%s: Cannot create %s, %s\n",ProgramName,paramOutputFile,
strerror(errno));
close(fdIn);
return 1;
}
fileSize = lseek(fdIn,0,SEEK_END);
if (fileSize < 0) {
fprintf(stderr,"%s: lseek error on %s, %s\n",ProgramName,paramInputFile,
strerror(errno));
close(fdOut);
close(fdIn);
return 1;
}
lseek(fdIn,0,SEEK_SET);
if (optVerbose) {
printf("Normal copy: %s -> %s 0%%",paramInputFile,paramOutputFile);
fflush(stdout);
}
totalSize = fileSize;
while (fileSize) {
int currentMove;
int writeAmt;
currentMove = (fileSize > BufferSize) ? BufferSize : fileSize;
if (read(fdIn,Buffer,currentMove) != currentMove) {
fprintf(stderr,"%s: Error reading %s, %s\n",ProgramName,paramInputFile,
strerror(errno));
close(fdIn);
close(fdOut);
return 1;
}
writeAmt = write(fdOut,Buffer,currentMove);
if (writeAmt < 0) {
fprintf(stderr,"%s: Error writing %s, %s\n",ProgramName,paramOutputFile,
strerror(errno));
close(fdIn);
close(fdOut);
return 1;
} else if (writeAmt == 0) {
fprintf(stderr,"%s: Out of space on destination device writing %s\n",
ProgramName,OutputFile);
close(fdIn);
close(fdOut);
return 1;
}
fileSize -= currentMove;
if (optVerbose) {
printf("\rNormal copy: %s -> %s %ld%%",paramInputFile,paramOutputFile,(100 - (fileSize * 100/totalSize)));
fflush(stdout);
}
}
close(fdOut);
close(fdIn);
if (optVerbose)
printf("\n");
return 0;
}
/****************************************************************************
* Converts a string to upper case.
* Netware file names need to be all upper case.
*/
char *upString(char *str)
{
char *alias = str;
while (*alias) {
*alias = toupper(*alias);
++alias;
}
return str;
}
/****************************************************************************
* Locates the first occurrance of a single character in the input string.
* returns -1 if the character is not found.
*/
int stringPosition(const char *str,char token)
{
const char *alias = str;
while (*alias) {
if (*alias == token) return alias - str;
alias++;
}
return -1;
}
/****************************************************************************
* Walks up the directory path building info structures along the way
* in order to get a dir_handle.
* This will mangle the input "FileString", leaving just the file name
* component in it when it is finished.
*/
int getDirHandle(struct ncp_conn *conn, char *FileString, __u8 *NewDirHandle)
{
struct nw_info_struct info1,info2;
int currentLevel = 0;
int k;
struct nw_info_struct *parentInfo = NULL;
struct nw_info_struct *currentInfo = NULL;
while ( (k = stringPosition(FileString,'/')) >= 0) {
FileString[k] = 0;
if (!currentLevel) {
parentInfo = NULL;
currentInfo = &info1;
} else if (currentLevel % 2) {
parentInfo = &info1;
currentInfo = &info2;
} else {
parentInfo = &info2;
currentInfo = &info1;
}
if (ncp_do_lookup(conn, parentInfo, FileString,
currentInfo) != 0) {
fprintf(stderr,"%s: Ncp lookup failed on directory %s--%s\n",
ProgramName,FileString,strerror(errno));
return 1;
}
++currentLevel;
memmove(FileString,FileString+k+1,strlen(FileString+k+1)+1);
}
if (ncp_alloc_short_dir_handle(conn, currentInfo, NCP_ALLOC_TEMPORARY,
NewDirHandle) != 0) {
fprintf(stderr,"%s: Ncp alloc dir handle failed--%s\n",
ProgramName,strerror(errno));
return 1;
}
return 0;
}
/****************************************************************************
* Interfaces with the ncplib to do the netware copy of the file.
*/
int netwareCopyFile(int ncpMountIndex, const char *sourcefile,
const char *destfile,
const char *paramInputFile,
const char *paramOutputFile)
{
__u8 source_dir_handle;
__u8 dest_dir_handle;
struct ncp_file_info source_file;
struct ncp_file_info dest_file;
__u32 amountCopied;
__u32 amtLeft;
__u32 totalSize;
__u32 sourceOff;
__u32 thisMove;
int stroffset;
int retValue;
char *sourceDup;
char *destDup;
struct ncp_conn *sourceconn;
int retryCount;
long err = 0;
/* Establish a connection to a Netware mount point if
one is not already established. */
if (!NcpMountTable[ncpMountIndex].conn) {
NcpMountTable[ncpMountIndex].conn =
ncp_open_mount(NcpMountTable[ncpMountIndex].mountDir,&err);
if (err) {
com_err(ProgramName,err,"opening ncp connection on mount point %s",
NcpMountTable[ncpMountIndex].mountDir);
return 2;
}
}
sourceconn = NcpMountTable[ncpMountIndex].conn;
/* Duplicate and upper case the file names so we do not trample
on the input strings */
stroffset = strlen(NcpMountTable[ncpMountIndex].mountDir) + 1;
sourceDup = duplicateStr(sourcefile+stroffset);
destDup = duplicateStr(destfile+stroffset);
if (!sourceDup || !destDup) {
fprintf(stderr,"%s: Malloc failed duplicating file names\n",
ProgramName);
return 2;
}
upString(sourceDup);
upString(destDup);
/* Get Handles to the input and output directories */
if (getDirHandle(sourceconn,sourceDup,&source_dir_handle) ||
getDirHandle(sourceconn,destDup,&dest_dir_handle)) {
free(sourceDup);
free(destDup);
return 1;
}
/* Open the input and output files. */
if (ncp_open_file(sourceconn, source_dir_handle, sourceDup,0,AR_READ,
&source_file) != 0) {
fprintf(stderr,"%s: Cannot open %s--%s\n",
ProgramName,paramInputFile,strerror(errno));
free(sourceDup);
free(destDup);
return 1;
}
if (ncp_create_file(sourceconn, dest_dir_handle, destDup,
source_file.file_attributes, &dest_file) != 0) {
fprintf(stderr,"%s: Cannot create %s--%s\n",ProgramName, paramOutputFile,
strerror(errno));
ncp_close_file(sourceconn,source_file.file_id);
free(sourceDup);
free(destDup);
return 1;
}
/* Set globals in case a signal happens while copying */
CurrentConn = sourceconn;
CurrentFile = &dest_file;
OutputOpen = 1;
free(sourceDup);
free(destDup);
retValue = 0;
if (optVerbose) {
printf("NetWare copy: %s -> %s 0%%",paramInputFile,paramOutputFile);
fflush(stdout);
}
/* The main copy loop. */
amtLeft = totalSize = source_file.file_length;
sourceOff = 0;
retryCount = 0;
while (amtLeft && retryCount < MaxNcopyRetries) {
int ncopyRetValue;
if (amtLeft > CopyBlockSize)
thisMove = CopyBlockSize;
else
thisMove = amtLeft;
/* If we are being nice and we've copied enough blocks, go to sleep */
if (optNice) {
if (BlocksCopied == optNiceFactor) {
sleep(NiceSleepTime);
BlocksCopied=0;
} else
++BlocksCopied;
}
ncopyRetValue = ncp_copy_file(sourceconn, source_file.file_id,
dest_file.file_id, sourceOff,sourceOff,
thisMove,&amountCopied);
if (ncopyRetValue != 0) {
/* In my testing this only happens when you run out of space
on the server.
Netware seems to wait a bit before reporting space recently
free'd. I will just wait a bit before bombin */
sleep(1); /* Sleep for a second and try again */
retryCount++;
amountCopied = thisMove = 0;
}
if (amountCopied != thisMove) {
fprintf(stderr,"%s: Warning, amountCopied (%u) != thisMove (%u)\n",
ProgramName,(unsigned int)amountCopied,(unsigned int)thisMove);
}
#ifdef NCOPY_DEBUG
fprintf(stderr,"Copied %u (actual %u)\n",(unsigned int)thisMove,
(unsigned int)amountCopied);
#endif
amtLeft -= amountCopied;
sourceOff += amountCopied;
if (optVerbose) {
printf("\rNetWare copy: %s -> %s %ld%%",paramInputFile,paramOutputFile,
(100 - (long)((float)amtLeft /(float)totalSize * 100.0)));
if (retryCount)
printf(" %d retries",retryCount);
fflush(stdout);
}
}
if (retryCount >= MaxNcopyRetries)
retValue = 1;
if (optVerbose)
printf("\n");
if (ncp_close_file(sourceconn,dest_file.file_id) != 0) {
fprintf(stderr,"%s: Close failed for %s\n",ProgramName,paramOutputFile);
retValue = 1;
}
/* Clear signal handling globals */
OutputOpen = 0;
CurrentConn = NULL;
CurrentFile = NULL;
if (ncp_close_file(sourceconn,source_file.file_id) != 0) {
fprintf(stderr,"%s: Close failed for %s\n",ProgramName,paramInputFile);
retValue = 1;
}
if (ncp_dealloc_dir_handle(sourceconn, dest_dir_handle) != 0)
{
fprintf(stderr,"%s: Dealloc dir handle error for %s\n",ProgramName,
paramOutputFile);
retValue = 1;
}
if (ncp_dealloc_dir_handle(sourceconn, source_dir_handle) != 0)
{
fprintf(stderr,"%s: Dealloc dir handle error for %s\n",ProgramName,
paramInputFile);
retValue = 1;
}
return retValue;
}
/****************************************************************************
* Decides whether to use the traditional file copy or the netware remote
* file copy.
*/
int copyFiles(const char *realsource, const char *realdestination,
const char *paraminputfile, const char *paramoutputfile)
{
int oldUMask;
char fileBuffer[24000];
int retVal = 0;
int ncpMountIndex = ncpIndex(realsource,realdestination);
#ifdef NCOPY_DEBUG
printf("Real Source '%s'\n"
"Real Dest '%s'\n"
"Param Src '%s'\n"
"Param Dest '%s'\n",realsource,realdestination,paraminputfile,
paramoutputfile);
#endif
oldUMask = umask(0);
if (ncpMountIndex < 0)
retVal = normalFileCopy(realsource,realdestination,fileBuffer,
sizeof(fileBuffer),
paraminputfile,paramoutputfile);
else
retVal = netwareCopyFile(ncpMountIndex,realsource,realdestination,
paraminputfile,paramoutputfile);
umask(oldUMask);
return retVal;
}
/****************************************************************************
*
* HERE
*
* Brian may NEED "fake" path if he prints error messages?
* or I may need a way to get his error messages so I can
* print them with the "fake" path.
* My current error messages are on the REAL path, which would be confusing...
*
* (1-source problem, 2-destination problem, 3-other fatal)
* We need to decide when to exit or continue the loop,
* and what to return when we do exit the loop.
* Is it failure if 3 files are to be copied, and 1 fails?
* If one copy fails, we stay in the loop, right?
* Is it failure if destination fails?
* Do we Stay in the loop?
*/
static int copyRealPaths(const char *source, const char *destination)
{
char realsource[MAXPATHLEN*2];
char realdestination[MAXPATHLEN*2];
char dirPart[MAXPATHLEN+1];
char filePart[MAXPATHLEN+1];
const char *p;
if(realpath(source, realsource) == 0) { /* the source must at least exist */
fprintf(stderr,"%s: %s: %s\n",
ProgramName, source, strerror(errno));
return 1; /* indicate a "source" problem */
}
if(realpath(destination, realdestination) == 0) {/* dest file missing? OK */
strncpy(dirPart, destination, MAXPATHLEN); /* but "dirpart" must work */
dirPart[MAXPATHLEN] = 0;
p=myBaseName(dirPart);
strcpy(filePart, p);
dirPart[p - dirPart] = 0; /* isolates "directory" part from "file part" */
if(realpath(dirPart, realdestination) == 0) {
fprintf(stderr,"%s: %s: %s\n",
ProgramName, dirPart, strerror(errno));
return 2; /* indicate a "destination" problem */
}
if(*realdestination != '/' || *(realdestination+1)) strcat(realdestination, "/");
strcat(realdestination, filePart);
}
/* becomes prog exit code */
/* Test Cases: (Where file/dir may or may not exist)
* "", file, file/, dir, dir/
* /, //, /dir, /dir/, /file, /file/,
* /tmp/file, /tmp/file/, tmp/file, tmp/file/,
* /tmp/dir, /tmp/dir/, tmp/dir, tmp/dir/
*/
return copyFiles(realsource, realdestination,source,destination);
}
/****************************************************************************
* guaranteed argc is at least 2 and
* if argc > 2 last parameter is a directory
* by validateFileArgs()
*/
static int handleFileArgs(int argc, char * const argv[])
{
int loop;
const char *destination;
int copyStatus;
int returnCode=0; /* default program exit code */
const char *baseNamePtr;
char destinationfile[MAXPATHLEN*2];
destination=argv[argc-1]; /* get LAST argument */
for (loop = 0; loop < (argc-1); loop++) { /* all file arguments, but last */
strncpy(destinationfile, destination, MAXPATHLEN);
destinationfile[MAXPATHLEN]=0;
if((argc > 2) || (!notDir(argv[argc-1]))) { /* destination is a dir */
if(*destinationfile != '/' || *(destinationfile+1)) strcat(destinationfile,"/");
baseNamePtr=myBaseName(argv[loop]); /* get the file name */
strcat(destinationfile,baseNamePtr); /* add it on end of directory */
}
copyStatus=copyRealPaths(argv[loop], destinationfile); /* do the copy */
if(copyStatus > 1) return copyStatus; /* fatal failure? bye */
if(copyStatus == 1) returnCode=1; /* a partial failure? we can continue */
}
return returnCode; /* return what will be the program exit code */
}
/****************************************************************************
*
*/
static void handleSignals(int sigNumber)
{
/* Ignore Signal Handling while cleaning up */
/* SIGHUP */
sHangupSig.sa_handler=SIG_IGN;
if(sigaction(SIGHUP, &sHangupSig, NULL) == -1) {
fprintf(stderr,"%s: Reset to ignore SIGHUP signal failed: %s",
ProgramName, strerror(errno));
}
/* SIGINT */
sInterruptSig.sa_handler=SIG_IGN;
if(sigaction(SIGINT, &sInterruptSig, NULL) == -1) {
fprintf(stderr,"%s: Reset to ignore SIGINT signal failed: %s",
ProgramName, strerror(errno));
}
/* SIGQUIT */
sQuitSig.sa_handler=SIG_IGN;
if(sigaction(SIGQUIT, &sQuitSig, NULL) == -1) {
fprintf(stderr,"%s: Reset to ignore SIGQUIT signal failed: %s",
ProgramName, strerror(errno));
}
/* SIGTERM */
sTermSig.sa_handler=SIG_IGN;
if(sigaction(SIGTERM, &sTermSig, NULL) == -1) {
fprintf(stderr,"%s: Reset to ignore SIGTERM signal failed: %s",
ProgramName, strerror(errno));
}
/* If we don't close the ncp output file, we have to ncpumount and
ncpmount before we can get rid of it. */
if (OutputOpen) {
/* Issue a warning if we cannot close the file */
/* If an error occurs we probably have to umount/mount to
remove the file */
if (ncp_close_file(CurrentConn,CurrentFile->file_id) != 0) {
fprintf(stderr,"%s: unclean close of output file",ProgramName);
}
OutputOpen = 0;
}
exit(128 + sigNumber);
}
/****************************************************************************
* We'll trap Hangup, Interrupt, Quit or Terminate
*/
static int trapSignals()
{
if(sigaction(SIGHUP, NULL, &sHangupSig)) { /* init structure fields */
fprintf(stderr,"%s: Get HANGUP signal action failed: %s",
ProgramName, strerror(errno));
return 1;
}
sHangupSig.sa_handler = handleSignals;
if(sigaction(SIGHUP, &sHangupSig, NULL) == -1) {
fprintf(stderr,"%s: Reset HANGUP signal action failed: %s",
ProgramName, strerror(errno));
return 1;
}
if(sigaction(SIGINT, NULL, &sInterruptSig)) { /* init structure fields */
fprintf(stderr,"%s: Get INTERRUPT signal action failed: %s",
ProgramName, strerror(errno));
return 1;
}
sInterruptSig.sa_handler = handleSignals;
if(sigaction(SIGINT, &sInterruptSig, NULL) == -1) {
fprintf(stderr,"%s: Reset INTERRUPT signal action failed: %s",
ProgramName, strerror(errno));
return 1;
}
if(sigaction(SIGQUIT, NULL, &sQuitSig)) { /* init structure fields */
fprintf(stderr,"%s: Get QUIT signal action failed: %s",
ProgramName, strerror(errno));
return 1;
}
sQuitSig.sa_handler = handleSignals;
if(sigaction(SIGQUIT, &sQuitSig, NULL) == -1) {
fprintf(stderr,"%s: Reset QUIT signal action failed: %s",
ProgramName, strerror(errno));
return 1;
}
if(sigaction(SIGTERM, NULL, &sTermSig)) { /* init structure fields */
fprintf(stderr,"%s: Get TERMINATE signal action failed: %s",
ProgramName, strerror(errno));
return 1;
}
sTermSig.sa_handler = handleSignals;
if(sigaction(SIGTERM, &sTermSig, NULL) == -1) {
fprintf(stderr,"%s: Reset TERMINATE signal action failed: %s",
ProgramName, strerror(errno));
return 1;
}
return 0;
}
/****************************************************************************
*
*/
int main(int argc, char * const argv[])
{
int returnCode;
ProgramName=argv[0];
if(handleOptions(argc, argv)) { /* bad option, missing option parameter */
usage();
return 1;
}
if(optVersion) { /* only option not requiring any arguments */
printf("%s version %s\n", ProgramName, VersionStr);
return 0;
}
if(validateFileArgs(argc - optind, argv + optind)) {
usage();
return 1;
}
if(trapSignals()) return 1;
loadMountTable();
returnCode = handleFileArgs(argc - optind, argv + optind);
releaseMountTable();
return returnCode;
}

View File

@@ -237,6 +237,10 @@ ipx_sap_find_nearest(int server_type, struct sockaddr_ipx *result,
if ((sock = socket(AF_IPX,SOCK_DGRAM,PF_IPX)) < 0)
{
if (errno == EINVAL)
{
return NCPL_ET_NO_IPX;
}
return errno;
}
@@ -255,6 +259,10 @@ ipx_sap_find_nearest(int server_type, struct sockaddr_ipx *result,
if(bind(sock,(struct sockaddr*)&addr,sizeof(addr))==-1)
{
if (errno == EADDRNOTAVAIL)
{
errno = NCPL_ET_NO_INTERFACE;
}
goto finished;
}
@@ -340,7 +348,11 @@ ipx_make_reachable(IPXNet network)
if (sock == -1)
{
return -1;
if (errno == EINVAL)
{
return NCPL_ET_NO_IPX;
}
return errno;
}
opt=1;
@@ -516,7 +528,7 @@ do_ncp_call(struct ncp_conn *conn, int request_size)
*((struct ncp_request_header *)(&(conn->packet)));
int result;
int retries = 3;
int retries = 20;
int len;
long err;
struct ncp_reply_header *r =
@@ -538,7 +550,7 @@ do_ncp_call(struct ncp_conn *conn, int request_size)
re_select:
len = ipx_recv(conn->ncp_sock,
conn->packet, NCP_PACKET_SIZE, 0, 1, &err);
conn->packet, NCP_PACKET_SIZE, 0, 3, &err);
if ( (len == sizeof(*r))
&& (r->type == NCP_POSITIVE_ACK))
@@ -591,6 +603,8 @@ ncp_mount_request(struct ncp_conn *conn, int function)
return result;
}
conn->completion = reply->completion_code;
conn->conn_status = reply->connection_state;
conn->ncp_reply_size = result - sizeof(struct ncp_reply_header);
if ((reply->completion_code != 0) && (conn->verbose != 0))
@@ -751,9 +765,10 @@ ncp_connect_any(struct ncp_conn *conn, int wdog_needed)
char name[NCP_BINDERY_NAME_LEN];
long result;
if (ipx_sap_find_nearest(IPX_SAP_FILE_SERVER, &addr, name) != 0)
if ((result = ipx_sap_find_nearest(IPX_SAP_FILE_SERVER,
&addr, name)) != 0)
{
return -1;
return result;
}
if ((result = ncp_connect_addr(conn, &addr, wdog_needed)) != 0)
@@ -833,13 +848,19 @@ ncp_find_fileserver(const char *server_name, long *err)
result.sipx_network = n_addr->network;
result.sipx_port = n_addr->port;
ipx_assign_node(result.sipx_node, n_addr->node);
/* To make the final server reachable, we connect again. See
above. (When can we rely on all users running ipxd??? :-)) */
memzero(conn);
if ( ((*err = ncp_connect_addr(&conn, &result, 0)) != 0)
|| ((*err = ncp_do_close(&conn)) != 0))
{
return NULL;
}
return &result;
}
static long
ncp_open_temporary(struct ncp_conn *conn,
const struct ncp_conn_spec *spec)
@@ -887,6 +908,8 @@ ncp_find_permanent(const struct ncp_conn_spec *spec)
int mount_fid;
struct ncp_fs_info i;
initialize_NCPL_error_table();
if ((mtab = fopen(MOUNTED, "r")) == NULL)
{
return NULL;
@@ -960,8 +983,16 @@ ncp_open_permanent(struct ncp_conn *conn,
conn->mount_fid = open(mount_point, O_RDONLY, 0);
conn->i.version = NCP_GET_FS_INFO_VERSION;
ioctl(conn->mount_fid, NCP_IOC_GET_FS_INFO, &(conn->i));
strncpy(conn->server, spec->server, sizeof(conn->server));
strncpy(conn->user, spec->user, sizeof(conn->user));
if (spec != NULL)
{
strncpy(conn->server, spec->server, sizeof(conn->server));
strncpy(conn->user, spec->user, sizeof(conn->user));
}
else
{
memset(conn->server, '\0', sizeof(conn->server));
memset(conn->user, '\0', sizeof(conn->user));
}
strcpy(conn->mount_point, mount_point);
conn->is_connected = CONN_PERMANENT;
return 0;
@@ -972,6 +1003,8 @@ ncp_open(const struct ncp_conn_spec *spec, long *err)
{
struct ncp_conn *result;
initialize_NCPL_error_table();
result = malloc(sizeof(struct ncp_conn));
if (result == NULL)
@@ -1001,6 +1034,8 @@ ncp_open_mount(const char *mount_point, long *err)
{
struct ncp_conn *result;
initialize_NCPL_error_table();
if (strlen(mount_point) >= sizeof(result->mount_point))
{
*err = ENAMETOOLONG;
@@ -1288,7 +1323,7 @@ ncp_fopen_nwc(const char *user, const char *mode)
struct ncp_conn_spec *
ncp_find_conn_spec(const char *server, const char *user, const char *password,
uid_t uid, long *err)
int login_necessary, uid_t uid, long *err)
{
static struct ncp_conn_spec spec;
@@ -1297,6 +1332,8 @@ ncp_find_conn_spec(const char *server, const char *user, const char *password,
FILE *nwc;
struct ncp_conn_spec *nwc_ent;
initialize_NCPL_error_table();
*err = 0;
memzero(spec);
spec.uid = getuid();
@@ -1383,6 +1420,12 @@ ncp_find_conn_spec(const char *server, const char *user, const char *password,
}
}
if (login_necessary == 0)
{
memset(spec.user, 0, sizeof(spec.user));
memset(spec.password, 0, sizeof(spec.password));
}
if (strlen(spec.user) == 0)
{
return &spec;
@@ -1500,12 +1543,21 @@ ncp_initialize_as(int *argc, char **argv,
i += 1;
}
if ((spec = ncp_find_conn_spec(server, user, password,
getuid(), err)) == NULL)
{
return NULL;
}
spec = ncp_find_conn_spec(server, user, password, login_necessary,
getuid(), err);
if (spec == NULL)
{
if (login_necessary != 0)
{
return NULL;
}
else
{
return ncp_open(NULL, err);
}
}
spec->login_type = login_type;
if (login_necessary == 0)
@@ -1789,7 +1841,7 @@ ncp_send_broadcast(struct ncp_conn *conn,
}
/*
* result is a 8-byte buffer
* target is a 8-byte buffer
*/
long
ncp_get_encryption_key(struct ncp_conn *conn,
@@ -1846,6 +1898,27 @@ ncp_get_bindery_object_id(struct ncp_conn *conn,
return 0;
}
long
ncp_get_bindery_object_name(struct ncp_conn *conn,
__u32 object_id,
struct ncp_bindery_object *target)
{
long result;
ncp_init_request_s(conn, 54);
ncp_add_dword(conn, htonl(object_id));
if ((result = ncp_request(conn, 23)) != 0) {
ncp_unlock_conn(conn);
return result;
}
target->object_id = ntohl(ncp_reply_dword(conn, 0));
target->object_type = ntohs(ncp_reply_word (conn, 4));
memcpy(target->object_name, ncp_reply_data(conn, 6), 48);
ncp_unlock_conn(conn);
return 0;
}
long
ncp_scan_bindery_object(struct ncp_conn *conn,
__u32 last_id, __u16 object_type, char *search_string,
@@ -1874,6 +1947,40 @@ ncp_scan_bindery_object(struct ncp_conn *conn,
return 0;
}
long
ncp_create_bindery_object(struct ncp_conn *conn,
__u16 object_type,
const char *object_name,
__u8 object_security,
__u8 object_status)
{
long result;
ncp_init_request_s(conn, 50);
ncp_add_byte(conn, object_status);
ncp_add_byte(conn, object_security);
ncp_add_word(conn, htons(object_type));
ncp_add_pstring(conn, object_name);
result = ncp_request(conn, 23);
ncp_unlock_conn(conn);
return result;
}
long
ncp_delete_bindery_object(struct ncp_conn *conn,
__u16 object_type,
const char *object_name)
{
long result;
ncp_init_request_s(conn, 51);
ncp_add_word(conn, htons(object_type));
ncp_add_pstring(conn, object_name);
result = ncp_request(conn, 23);
ncp_unlock_conn(conn);
return result;
}
long
ncp_read_property_value(struct ncp_conn *conn,
@@ -1900,6 +2007,149 @@ ncp_read_property_value(struct ncp_conn *conn,
return 0;
}
long
ncp_scan_property(struct ncp_conn *conn,
__u16 object_type, const char *object_name,
__u32 last_id, char *search_string,
struct ncp_property_info *property_info)
{
long result;
ncp_init_request_s(conn, 60);
ncp_add_word(conn, htons(object_type));
ncp_add_pstring(conn, object_name);
ncp_add_dword(conn, htonl(last_id));
ncp_add_pstring(conn, search_string);
if ((result = ncp_request(conn, 23)) != 0) {
ncp_unlock_conn(conn);
return result;
}
memcpy(property_info->property_name,ncp_reply_data(conn, 0), 16);
property_info->property_flags = ncp_reply_byte(conn,16);
property_info->property_security = ncp_reply_byte(conn,17);
property_info->search_instance = ntohl(ncp_reply_dword(conn,18));
property_info->value_available_flag = ncp_reply_byte(conn,22);
property_info->more_properties_flag = ncp_reply_byte(conn,23);
ncp_unlock_conn(conn);
return 0;
}
long
ncp_add_object_to_set(struct ncp_conn *conn,
__u16 object_type, const char *object_name,
const char *property_name,
__u16 member_type,
const char *member_name)
{
long result;
ncp_init_request_s(conn, 65);
ncp_add_word(conn, htons(object_type));
ncp_add_pstring(conn, object_name);
ncp_add_pstring(conn, property_name);
ncp_add_word(conn, htons(member_type));
ncp_add_pstring(conn, member_name);
result = ncp_request(conn, 23);
ncp_unlock_conn(conn);
return result;
}
long
ncp_change_property_security(struct ncp_conn *conn,
__u16 object_type, const char *object_name,
const char *property_name,
__u8 property_security)
{
long result;
ncp_init_request_s(conn, 59);
ncp_add_word(conn, htons(object_type));
ncp_add_pstring(conn, object_name);
ncp_add_byte(conn, property_security);
ncp_add_pstring(conn, property_name);
result = ncp_request(conn, 23);
ncp_unlock_conn(conn);
return result;
}
long
ncp_create_property(struct ncp_conn *conn,
__u16 object_type, const char *object_name,
const char *property_name,
__u8 property_flags, __u8 property_security)
{
long result;
ncp_init_request_s(conn, 57);
ncp_add_word(conn, htons(object_type));
ncp_add_pstring(conn, object_name);
ncp_add_byte(conn, property_flags);
ncp_add_byte(conn, property_security);
ncp_add_pstring(conn, property_name);
result = ncp_request(conn, 23);
ncp_unlock_conn(conn);
return result;
}
long
ncp_delete_object_from_set(struct ncp_conn *conn,
__u16 object_type, const char *object_name,
const char *property_name,
__u16 member_type,
const char *member_name)
{
long result;
ncp_init_request_s(conn, 66);
ncp_add_word(conn, htons(object_type));
ncp_add_pstring(conn, object_name);
ncp_add_pstring(conn, property_name);
ncp_add_word(conn, htons(member_type));
ncp_add_pstring(conn, member_name);
result = ncp_request(conn, 23);
ncp_unlock_conn(conn);
return result;
}
long
ncp_delete_property(struct ncp_conn *conn,
__u16 object_type, const char *object_name,
const char *property_name)
{
long result;
ncp_init_request_s(conn, 58);
ncp_add_word(conn, htons(object_type));
ncp_add_pstring(conn, object_name);
ncp_add_pstring(conn, property_name);
result = ncp_request(conn, 23);
ncp_unlock_conn(conn);
return result;
}
long
ncp_write_property_value(struct ncp_conn *conn,
__u16 object_type, const char *object_name,
const char *property_name,
__u8 segment,
struct nw_property *property_value)
{
long result;
ncp_init_request_s(conn, 62);
ncp_add_word(conn, htons(object_type));
ncp_add_pstring(conn, object_name);
ncp_add_byte(conn,segment);
ncp_add_byte(conn, property_value->more_flag);
ncp_add_pstring(conn, property_name);
ncp_add_mem(conn, property_value->value, 128);
result = ncp_request(conn, 23);
ncp_unlock_conn(conn);
return result;
}
long
ncp_login_encrypted(struct ncp_conn *conn,
const struct ncp_bindery_object *object,
@@ -1924,6 +2174,43 @@ ncp_login_encrypted(struct ncp_conn *conn,
return result;
}
long
ncp_change_login_passwd(struct ncp_conn *conn,
const struct ncp_bindery_object *object,
const unsigned char *key,
const unsigned char *oldpasswd,
const unsigned char *newpasswd)
{
long id = htonl(object->object_id);
unsigned char cryptkey[8];
unsigned char newpwd[16]; /* new passwd as stored by server */
unsigned char oldpwd[16]; /* old passwd as stored by server */
unsigned char len;
long result;
memcpy(cryptkey, key, 8);
shuffle((byte *)&id, oldpasswd, strlen(oldpasswd), oldpwd);
shuffle((byte *)&id, newpasswd, strlen(newpasswd), newpwd);
nw_encrypt(cryptkey, oldpwd, cryptkey);
newpassencrypt(oldpwd, newpwd, newpwd);
newpassencrypt(oldpwd+8, newpwd+8, newpwd+8);
if ((len = strlen(newpasswd)) > 63)
{
len = 63;
}
len = ((len ^ oldpwd[0] ^ oldpwd[1]) & 0x7f) | 0x40;
ncp_init_request_s(conn, 75);
ncp_add_mem(conn, cryptkey, 8);
ncp_add_word(conn, htons(object->object_type));
ncp_add_pstring(conn, object->object_name);
ncp_add_byte(conn, len);
ncp_add_mem(conn, newpwd, 16);
result = ncp_request(conn, 23);
ncp_unlock_conn(conn);
return result;
}
long
ncp_login_user(struct ncp_conn *conn,
const unsigned char *username,
@@ -1952,8 +2239,27 @@ ncp_login_object(struct ncp_conn *conn,
}
if ((result = ncp_login_encrypted(conn, &user,
ncp_key, password)) != 0) {
return result;
ncp_key, password)) != 0)
{
struct nw_property p;
struct ncp_prop_login_control *l
= (struct ncp_prop_login_control *)&p;
if (conn->completion != NCP_GRACE_PERIOD)
{
return result;
}
fprintf(stderr, "Your password has expired\n");
if ((result = ncp_read_property_value(conn, NCP_BINDERY_USER,
username, 1,
"LOGIN_CONTROL",
&p)) == 0)
{
fprintf(stderr, "You have %d login attempts left\n",
l->GraceLogins);
}
}
return 0;
}
@@ -2858,9 +3164,9 @@ ncp_copy_file(struct ncp_conn *conn,
ncp_add_byte(conn, 0); /* reserved */
ncp_add_mem(conn, source_file, 6);
ncp_add_mem(conn, target_file, 6);
ncp_add_dword(conn, source_offset);
ncp_add_dword(conn, target_offset);
ncp_add_dword(conn, count);
ncp_add_dword(conn, htonl(source_offset));
ncp_add_dword(conn, htonl(target_offset));
ncp_add_dword(conn, htonl(count));
if ((result = ncp_request(conn, 74)) != 0)
{
@@ -2868,7 +3174,7 @@ ncp_copy_file(struct ncp_conn *conn,
return result;
}
*copied_count = ncp_reply_dword(conn, 0);
*copied_count = ntohl(ncp_reply_dword(conn, 0));
ncp_unlock_conn(conn);
return 0;
}

View File

@@ -79,6 +79,15 @@ struct ncp_search_seq {
int namespace;
};
struct ncp_property_info {
__u8 property_name[16];
__u8 property_flags;
__u8 property_security;
__u32 search_instance;
__u8 value_available_flag;
__u8 more_properties_flag;
};
/* ncp_initialize is the main entry point for user programs which want
to connect to a NetWare Server. It looks for -S, -U, -P and -n in
the argument list, opens the connection and removes the arguments
@@ -95,7 +104,7 @@ ncp_initialize_as(int *argc, char **argv,
int login_necessary, int login_type, long *err);
/* Open an existing permanent connection */
/* Open a connection */
struct ncp_conn *
ncp_open(const struct ncp_conn_spec *spec, long *err);
@@ -137,7 +146,7 @@ ncp_get_conn_ent(FILE *filep);
struct ncp_conn_spec *
ncp_find_conn_spec(const char *server, const char *user, const char *password,
uid_t uid, long *err);
int login_necessary, uid_t uid, long *err);
long
ncp_get_file_server_description_strings(struct ncp_conn *conn,
@@ -165,19 +174,106 @@ ncp_get_bindery_object_id(struct ncp_conn *conn,
const char *object_name,
struct ncp_bindery_object *target);
long
ncp_get_bindery_object_name(struct ncp_conn *conn,
__u32 object_id,
struct ncp_bindery_object *target);
long
ncp_scan_bindery_object(struct ncp_conn *conn,
__u32 last_id, __u16 object_type, char *search_string,
struct ncp_bindery_object *target);
long
ncp_create_bindery_object(struct ncp_conn *conn,
__u16 object_type,
const char *object_name,
__u8 object_security,
__u8 object_status);
long
ncp_delete_bindery_object(struct ncp_conn *conn,
__u16 object_type,
const char *object_name);
long
ncp_change_object_security(struct ncp_conn *conn,
__u16 object_type,
const char *object_name,
__u8 security);
struct ncp_prop_login_control {
__u8 AccountExpireDate[3] __attribute__ ((packed));
__u8 Disabled __attribute__ ((packed));
__u8 PasswordExpireDate[3] __attribute__ ((packed));
__u8 GraceLogins __attribute__ ((packed));
__u16 PasswordExpireInterval __attribute__ ((packed));
__u8 MaxGraceLogins __attribute__ ((packed));
__u8 MinPasswordLength __attribute__ ((packed));
__u16 MaxConnections __attribute__ ((packed));
__u8 ConnectionTimeMask[42] __attribute__ ((packed));
__u8 LastLogin[6] __attribute__ ((packed));
__u8 RestrictionMask __attribute__ ((packed));
__u8 reserved __attribute__ ((packed));
__u32 MaxDiskUsage __attribute__ ((packed));
__u16 BadLoginCount __attribute__ ((packed));
__u32 BadLoginCountDown __attribute__ ((packed));
__u8 LastIntruder[8] __attribute__ ((packed));
};
long
ncp_read_property_value(struct ncp_conn *conn,
int object_type, const char *object_name,
int segment, const char *prop_name,
struct nw_property *target);
long
ncp_scan_property(struct ncp_conn *conn,
__u16 object_type, const char *object_name,
__u32 last_id, char *search_string,
struct ncp_property_info *property_info);
long
ncp_add_object_to_set(struct ncp_conn *conn,
__u16 object_type, const char *object_name,
const char *property_name,
__u16 member_type,
const char *member_name);
long
ncp_change_property_security(struct ncp_conn *conn,
__u16 object_type, const char *object_name,
const char *property_name,
__u8 property_security);
long
ncp_create_property(struct ncp_conn *conn,
__u16 object_type, const char *object_name,
const char *property_name,
__u8 property_flags, __u8 property_security);
long
ncp_delete_object_from_set(struct ncp_conn *conn,
__u16 object_type, const char *object_name,
const char *property_name,
__u16 member_type,
const char *member_name);
long
ncp_delete_property(struct ncp_conn *conn,
__u16 object_type, const char *object_name,
const char *property_name);
long
ncp_write_property_value(struct ncp_conn *conn,
__u16 object_type, const char *object_name,
const char *property_name,
__u8 segment,
struct nw_property *property_value);
long
ncp_login_encrypted(struct ncp_conn *conn,
const struct ncp_bindery_object *object,
const unsigned char *key,
const unsigned char *passwd);
long
ncp_change_login_passwd(struct ncp_conn *conn,
const struct ncp_bindery_object *object,
const unsigned char *key,
const unsigned char *oldpasswd,
const unsigned char *newpasswd);
#define NCP_GRACE_PERIOD (0xdf)
long
ncp_login_user(struct ncp_conn *conn,
const unsigned char *username,

View File

@@ -18,4 +18,22 @@ ec NCPL_ET_MSG_TOO_LONG,
ec NCPL_ET_NO_SPEC,
"Could not find valid connection spec"
ec NCPL_ET_INVALID_MODE,
"$HOME/.nwclient has invalid mode"
ec NCPL_ET_LOGIN_DENIED,
"Login denied"
ec NCPL_ET_NO_INTERFACE,
"No primary IPX interface found"
ec NCPL_ET_NO_PASSWORD,
"Could not get password"
ec NCPL_ET_PWD_TOO_LONG,
"Password too long"
ec NCPL_ET_NO_IPX,
"Could not alloc IPX socket. Probably no IPX support in kernel."
end

View File

@@ -10,7 +10,7 @@
* a conditional which leaves out the test and load code.
*
* Even if we _do_ want ncpmount to load the module, passing a
* fully-qualified pathname to insmod causes it to bypass a
* fully-qualified pathname to modprobe causes it to bypass a
* path search. This may lead to ncpfs.o not being found on
* some systems.
*/
@@ -102,7 +102,7 @@ load_ncpfs(void)
else if (pid == 0)
{
/* child */
execl("/sbin/insmod", "insmod", "ncpfs", NULL);
execl("/sbin/modprobe", "modprobe", "ncpfs", NULL);
_exit(127); /* execl error */
}
else
@@ -321,7 +321,7 @@ main(int argc, char *argv[])
}
}
if ((spec = ncp_find_conn_spec(server, user, password, data.uid, &err))
if ((spec = ncp_find_conn_spec(server,user,password,1, data.uid, &err))
== NULL)
{
com_err(progname, err, "in find_conn_spec");
@@ -484,12 +484,42 @@ main(int argc, char *argv[])
exit(1);
}
if ( ((conn = ncp_open_mount(mount_point, &err)) == NULL)
|| ((err = ncp_login_user(conn, spec->user, spec->password)) != 0)
|| ((err = ioctl(conn->mount_fid, NCP_IOC_CONN_LOGGED_IN,
NULL)) != 0))
if ((conn = ncp_open_mount(mount_point, &err)) == NULL)
{
com_err("ncpmount", err, "in login");
com_err("ncpmount", err, "attempt to open mount point");
umount(mount_point);
exit(1);
}
if ((err = ncp_login_user(conn, spec->user, spec->password)) != 0)
{
struct nw_property p;
struct ncp_prop_login_control *l
= (struct ncp_prop_login_control *)&p;
if (conn->completion != NCP_GRACE_PERIOD)
{
com_err("ncpmount", err, "in login");
fprintf(stderr, "Login denied\n");
ncp_close(conn);
umount(mount_point);
exit(1);
}
fprintf(stderr, "Your password has expired\n");
if ((err = ncp_read_property_value(conn, NCP_BINDERY_USER,
spec->user, 1,
"LOGIN_CONTROL", &p)) == 0)
{
fprintf(stderr, "You have %d login attempts left\n",
l->GraceLogins);
}
}
if ((err = ioctl(conn->mount_fid, NCP_IOC_CONN_LOGGED_IN, NULL)) != 0)
{
com_err("ncpmount", err, "in logged_indication");
ncp_close(conn);
umount(mount_point);
exit(1);

View File

@@ -106,7 +106,30 @@ test_create(struct ncp_conn *conn)
return;
}
}
int
test_change(struct ncp_conn *conn)
{
long result;
unsigned char ncp_key[8];
struct ncp_bindery_object user;
if ((result = ncp_get_encryption_key(conn, ncp_key)) != 0) {
return result;
}
if ((result = ncp_get_bindery_object_id(conn, 1,
"ME", &user)) != 0) {
return result;
}
if ((result = ncp_change_login_passwd(conn, &user, ncp_key,
"MEE", "ME")) != 0)
{
return result;
}
return 0;
}
int
main(int argc, char *argv[])
@@ -120,7 +143,7 @@ main(int argc, char *argv[])
return 1;
}
test_send(conn);
test_change(conn);
ncp_close(conn);
return 0;
}

144
util/npasswd.c Normal file
View File

@@ -0,0 +1,144 @@
/*
* npasswd.c
*
* Change a bindery object's password
*
* Copyright (C) 1996 by Volker Lendecke
*
*/
#include "ncplib.h"
#include <unistd.h>
#include <stdlib.h>
static char *progname;
static void
usage(void)
{
fprintf(stderr, "usage: %s [options]\n", progname);
}
static void
help(void)
{
printf("\n");
printf("usage: %s [options]\n", progname);
printf("\n"
"-h Print this help text\n"
"-S server Server name to be used\n"
"-U username Username sent to server\n"
"-t type Object type (decimal value)\n"
"\n");
}
int
main(int argc, char *argv[])
{
struct ncp_conn_spec *spec;
struct ncp_conn *conn;
char *server = NULL;
char *object_name = NULL;
int object_type = NCP_BINDERY_USER;
unsigned char ncp_key[8];
struct ncp_bindery_object user;
long err;
char *str;
char oldpass[200], newpass1[200], newpass2[200];
int opt;
progname = argv[0];
while ((opt = getopt(argc, argv, "hS:U:t:")) != EOF)
{
switch(opt) {
case 'S':
server = optarg;
break;
case 'U':
object_name = optarg;
break;
case 't':
object_type = atoi(optarg);
break;
case 'h':
help();
exit(1);
default:
usage();
exit(1);
}
}
spec = ncp_find_conn_spec(server, object_name, "",
1, getuid(), &err);
if (spec == NULL)
{
com_err(argv[0], err, "trying to find server");
exit(1);
}
spec->login_type = object_type;
printf("Changing password for user %s on server %s\n",
spec->user, spec->server);
str = getpass("Enter old password: ");
if (strlen(str) >= sizeof(oldpass))
{
printf("Password too long\n");
exit(1);
}
strcpy(oldpass, str);
str = getpass("Enter new password: ");
if (strlen(str) >= sizeof(newpass1))
{
printf("Password too long\n");
exit(1);
}
strcpy(newpass1, str);
str = getpass("Re-Enter new password: ");
if (strlen(str) >= sizeof(newpass2))
{
printf("Password too long\n");
exit(1);
}
strcpy(newpass2, str);
str_upper(oldpass);
str_upper(newpass1);
str_upper(newpass2);
if (strcmp(newpass1, newpass2) != 0)
{
printf("You mistype the new password, try again\n");
exit(1);
}
strcpy(spec->password, oldpass);
if ((conn = ncp_open(spec, &err)) == NULL)
{
com_err(argv[0], err, "when trying to open connection");
exit(1);
}
if ( ((err = ncp_get_encryption_key(conn, ncp_key)) != 0)
|| ((err = ncp_get_bindery_object_id(conn, 1, spec->user,
&user)) != 0)
|| ((err = ncp_change_login_passwd(conn, &user, ncp_key,
oldpass, newpass1)) != 0))
{
com_err(argv[0], err, "trying to change password");
}
ncp_close(conn);
return 0;
}

View File

@@ -209,3 +209,131 @@ nw_encrypt(const unsigned char *fra,
}
/*****************************************************************************/
/* */
/* The following code was contributed by */
/* Guntram Blohm <gbl%th7csun1@str.daimler-benz.com> */
/* */
/*****************************************************************************/
/* server side (mars etc.) should:
* store the *encrypted* password internally (output from shuffle)
* verify if nw_encrypt(cryptkey from GetCryptKey, old stored password)
== cryptkey in EncryptedChangePassword request buffer (this means
old password was correct)
* decrypt new password in request buffer using (yet to write) inverse of
newpassencrypt with old stored password as parameter
* compute the length of the unencrypted new password as len ^ (first byte of
old internal password) ^ (second byte of old internal password)
*/
static char
newshuffle[256+16] = {
0x0f, 0x08, 0x05, 0x07, 0x0c, 0x02, 0x0e, 0x09,
0x00, 0x01, 0x06, 0x0d, 0x03, 0x04, 0x0b, 0x0a,
0x02, 0x0c, 0x0e, 0x06, 0x0f, 0x00, 0x01, 0x08,
0x0d, 0x03, 0x0a, 0x04, 0x09, 0x0b, 0x05, 0x07,
0x05, 0x02, 0x09, 0x0f, 0x0c, 0x04, 0x0d, 0x00,
0x0e, 0x0a, 0x06, 0x08, 0x0b, 0x01, 0x03, 0x07,
0x0f, 0x0d, 0x02, 0x06, 0x07, 0x08, 0x05, 0x09,
0x00, 0x04, 0x0c, 0x03, 0x01, 0x0a, 0x0b, 0x0e,
0x05, 0x0e, 0x02, 0x0b, 0x0d, 0x0a, 0x07, 0x00,
0x08, 0x06, 0x04, 0x01, 0x0f, 0x0c, 0x03, 0x09,
0x08, 0x02, 0x0f, 0x0a, 0x05, 0x09, 0x06, 0x0c,
0x00, 0x0b, 0x01, 0x0d, 0x07, 0x03, 0x04, 0x0e,
0x0e, 0x08, 0x00, 0x09, 0x04, 0x0b, 0x02, 0x07,
0x0c, 0x03, 0x0a, 0x05, 0x0d, 0x01, 0x06, 0x0f,
0x01, 0x04, 0x08, 0x0a, 0x0d, 0x0b, 0x07, 0x0e,
0x05, 0x0f, 0x03, 0x09, 0x00, 0x02, 0x06, 0x0c,
0x05, 0x03, 0x0c, 0x08, 0x0b, 0x02, 0x0e, 0x0a,
0x04, 0x01, 0x0d, 0x00, 0x06, 0x07, 0x0f, 0x09,
0x06, 0x00, 0x0b, 0x0e, 0x0d, 0x04, 0x0c, 0x0f,
0x07, 0x02, 0x08, 0x0a, 0x01, 0x05, 0x03, 0x09,
0x0b, 0x05, 0x0a, 0x0e, 0x0f, 0x01, 0x0c, 0x00,
0x06, 0x04, 0x02, 0x09, 0x03, 0x0d, 0x07, 0x08,
0x07, 0x02, 0x0a, 0x00, 0x0e, 0x08, 0x0f, 0x04,
0x0c, 0x0b, 0x09, 0x01, 0x05, 0x0d, 0x03, 0x06,
0x07, 0x04, 0x0f, 0x09, 0x05, 0x01, 0x0c, 0x0b,
0x00, 0x03, 0x08, 0x0e, 0x02, 0x0a, 0x06, 0x0d,
0x09, 0x04, 0x08, 0x00, 0x0a, 0x03, 0x01, 0x0c,
0x05, 0x0f, 0x07, 0x02, 0x0b, 0x0e, 0x06, 0x0d,
0x09, 0x05, 0x04, 0x07, 0x0e, 0x08, 0x03, 0x01,
0x0d, 0x0b, 0x0c, 0x02, 0x00, 0x0f, 0x06, 0x0a,
0x09, 0x0a, 0x0b, 0x0d, 0x05, 0x03, 0x0f, 0x00,
0x01, 0x0c, 0x08, 0x07, 0x06, 0x04, 0x0e, 0x02,
0x03, 0x0e, 0x0f, 0x02, 0x0d, 0x0c, 0x04, 0x05,
0x09, 0x06, 0x00, 0x01, 0x0b, 0x07, 0x0a, 0x08,
};
/*
* verschluesseln des neuen Passworts fuer keyed change password
* Verwendung:
* - Shuffle (aus nwcrypt.c) altes passwort nach old (16 bytes)
* - shuffle neues passwort nach new (16 bytes)
* - nwpassencrypt (diese Funktion) zweimal aufrufen fuer je 8 bytes:
* nwpassencrypt(old+0, new+0, out+0)
* nwpassencrypt(old+8, new+8, out+8)
* - NCP-Buffer aufbauen:
* 2 byte Laenge im Hi-Lo-Format
* 1 byte Funktion (0x4b)
* 8 byte (nwcrypt Ergebnis analog login/verify password)
* 2 byte Objecttype
* 1 byte Objectname-Laenge
* n byte Objectname
* 1 byte (Laenge des eingegebenen neuen Passworts ^ old[0] ^ old[1])&0x7f|0x40
* 16 byte (Ergebnis dieser Funktion doppelt aufgerufen, s.o.)
*/
/*
* Encrypt the new password for keyed change password
* For info on how to use this function, look at ncp_change_login_passwd
* in ncplib.c.
*/
static void
newpassencrypt(char *old, char *new, char *out)
{
char *p, *bx;
char copy[8];
int i, di, ax;
char cl, dl, ch;
memcpy(copy, new, 8);
for (i=0; i<16; i++)
{
for (di=0, ax=0, p=old; di<8; di++, ax+=0x20, p++)
{
cl=newshuffle[(((copy[di]^*p)>>4)&0x0f)+ax+0x10]<<4;
dl=newshuffle[((copy[di]^*p)&0xf)+ax];
copy[di]=cl|dl;
}
ch=old[7];
for (bx=old+7; bx>old; bx--)
{
*bx=((bx[-1]>>4)&0x0f)|((*bx)<<4);
}
*old=((ch>>4)&0x0f)|(*old)<<4;
memset(out, '\0', 8);
for (di=0; di<16; di++)
{
if (newshuffle[di+0x100]&1)
ch=((copy[newshuffle[di+0x100]/2]>>4)&0x0f);
else
ch=copy[newshuffle[di+0x100]/2]&0x0f;
out[di/2]|=((di&1) ? ch<<4 : ch);
}
memcpy(copy, out, 8);
}
}

View File

@@ -32,6 +32,7 @@ main(int argc, char *argv[])
{
struct ncp_conn *conn;
char message[256];
char *mount_point;
struct ncp_fs_info info;
struct passwd *pwd;
char tty[256];
@@ -53,7 +54,8 @@ main(int argc, char *argv[])
exit(1);
}
if ((conn = ncp_open_mount(argv[1], &err)) == NULL)
mount_point = argv[1];
if ((conn = ncp_open_mount(mount_point, &err)) == NULL)
{
com_err(progname, err, "in ncp_open_mount");
exit(1);
@@ -104,7 +106,7 @@ main(int argc, char *argv[])
while ((mnt = getmntent(mtab)) != NULL)
{
if (strcmp(mnt->mnt_dir, conn->mount_point) == 0)
if (strcmp(mnt->mnt_dir, mount_point) == 0)
{
break;
}

View File

@@ -41,9 +41,9 @@ main(int argc, char *argv[])
*p = toupper(*p);
}
if ((conn = ncp_initialize(&argc, argv, 0, &err)) == NULL)
if ((conn = ncp_open(NULL, &err)) == NULL)
{
com_err(argv[0], err, "in ncp_initialize");
com_err(argv[0], err, "in ncp_open");
exit(1);
}