Compare commits

...

1 Commits
v0.16 ... v0.17

Author SHA1 Message Date
ncpfs archive import
1fa124bd7c Import ncpfs 0.17 2026-04-28 20:39:57 +02:00
36 changed files with 1594 additions and 226 deletions

BIN
.downloads/ncpfs-0.17.tgz Normal file

Binary file not shown.

20
Changes
View File

@@ -1,6 +1,26 @@
I only began this file with ncpfs-0.12. If you're interested in older 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 linux01.gwdg.de:/pub/ncpfs/old.
ncpfs-0.16 -> ncpfs-0.17
- Changed the name of fsinfo to nwfsinfo, to avoid a name clash with
the X windows utility. Thanks to Henning Brockfeld
<Henning.Brockfeld@lrz.uni-muenchen.de> for this hint. (still
waiting for your scripts.. :-))
- made nwmsg available. This enables you to receive NetWare user
broadcast messages. Please note that you need at least kernel 1.3.68
for this feature.
- pserver now prints debugging output via syslog().
- Included ipxdump, a nice little utility, that has helped some
people.
- And now the big one: you can re-export ncpfs-mounted directories
with nfsd! You have to mount single volumes by specifying -V volume
to ncpmount, and call nfsd and mountd with the option --re-export.
See the manual page of ncpmount for more information. Please note
that I will send Linus the required patch on 1. March 1996, so you
will have to use kernel 1.2.13 or wait at least for 1.3.70.
ncpfs-0.15 -> ncpfs-0.16 ncpfs-0.15 -> ncpfs-0.16
- Included ipx-1.0, made available by Greg Page <greg@caldera.com>, - Included ipx-1.0, made available by Greg Page <greg@caldera.com>,

View File

@@ -2,10 +2,11 @@
# Makefile for the linux ncp-filesystem routines. # Makefile for the linux ncp-filesystem routines.
# #
VERSION = 0.16 VERSION = 0.17
TOPDIR = $(shell pwd) TOPDIR = $(shell pwd)
BINDIR = /usr/local/bin BINDIR = /usr/local/bin
SBINDIR = /sbin
INTERM_BINDIR = $(TOPDIR)/bin INTERM_BINDIR = $(TOPDIR)/bin
SUBDIRS = util ipx-1.0 man SUBDIRS = util ipx-1.0 man
@@ -15,14 +16,14 @@ SUBDIRS = util ipx-1.0 man
# the following lines. You have to recompile your kernel # the following lines. You have to recompile your kernel
# and say 'y' when 'make config' asks you for IPX and ncpfs. # and say 'y' when 'make config' asks you for IPX and ncpfs.
# #
#SUBDIRS += kernel-1.2/src SUBDIRS += kernel-1.2/src
#INCLUDES = -I$(TOPDIR)/kernel-1.2 INCLUDES = -I$(TOPDIR)/kernel-1.2
# If you are using kerneld to autoload ncp support, # If you are using kerneld to autoload ncp support,
# uncomment this (kerneld is in linux since about 1.3.57): # uncomment this (kerneld is in linux since about 1.3.57):
# KERNELD = -DHAVE_KERNELD #KERNELD = -DHAVE_KERNELD
export INCLUDES BINDIR INTERM_BINDIR KERNELD VERSION export INCLUDES BINDIR INTERM_BINDIR SBINDIR KERNELD VERSION
all: all:
for i in $(SUBDIRS); do make -C $$i; done for i in $(SUBDIRS); do make -C $$i; done

26
README
View File

@@ -78,6 +78,8 @@ Ales Dyrak has written lwared, which was the initial start for ncpfs.
Alan Cox has found some bugs I would probably never have found. Alan Cox has found some bugs I would probably never have found.
Look at the file Changes for others.
LIMITATIONS (compare these with smbfs :-) LIMITATIONS (compare these with smbfs :-)
@@ -87,27 +89,7 @@ limitation is the lack of uid, gid and permission information per
file. You have to assign those values once for a complete mounted file. You have to assign those values once for a complete mounted
directory. directory.
The second limitation is just as annoying as the first: You cannot You will not be able to access servers that require packet
re-export a ncp-mounted directory by nfs. It is not possible because signatures. This seems to be one of Novell's bigger secrets :-(.
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.
Those who looked at the kernel code a bit closer will have found out
that the last section is a little white lie. As I found out after the
first version of ncpfs, NetWare does indeed offer something like inode
numbers, although are only unique per volume. So one way to make ncpfs
re-exportable by nfs is to allocate a superblock per volume and show
the inode numbers to the user. I was just too lazy to do this
yet. Maybe once we will force Novell to make NetWare NFS
affordable... ;-)
Have fun with ncpfs! Have fun with ncpfs!

35
ipxdump/Makefile Normal file
View File

@@ -0,0 +1,35 @@
EXEC= ipxdump ipxparse
CFLAGS= -Wall -O2
OBJECTS= ipxutil.o
all: $(EXEC)
ipxdump: ipxdump.o $(OBJECTS)
$(CC) -o $@ ipxdump.o $(CFLAGS) $(OBJECTS)
ipxparse: ipxparse.o $(OBJECTS)
$(CC) -o $@ ipxparse.o $(CFLAGS) $(OBJECTS)
clean:
rm -f *.o $(EXEC) *~
modules: ncpfs.o
SRCPATH=$(shell pwd)
SRCDIR=$(shell basename $(SRCPATH))
DISTFILE=$(SRCDIR).tgz
mrproper: clean
rm -f $(DISTFILE)
dist: tgz
make all
tgz: mrproper
(cd ..; \
tar cvf - $(SRCDIR) | \
gzip -9 > $(DISTFILE); \
mv $(DISTFILE) $(SRCDIR))

45
ipxdump/README Normal file
View File

@@ -0,0 +1,45 @@
This is a VERY stupid packet sniffer for IPX ethernet packets.
=============================================
! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
! ! ! S E C U R I T Y W A R N I N G ! ! !
! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
=============================================
If you are using unencrypted passwords, and use this tool to send a
dump to somebody else or store it on a computer, you might very well
store passwords there. So, be VERY careful! This is exactly the kind
of tools Novell designed the encrypted passwords for (or against).
I hacked it together to be able to help people with problems with
ncpfs. The socket handling was taken from Statnet-2.0.
You can use it to watch commercial NetWare clients when they talk to
servers. I divided the program into 2 parts, ipxdump and ipxparse.
ipxdump simply pumps all the IPX frames it receives to stdout.
If you use ipxdump to watch a workstation, you can use the simple
filter function ipxdump provides. You can call ipxdump with the node
address of the workstation you want to watch. This way only the
packets this workstation sends and receives are monitored. As an
example, I call ipxdump as
./ipxdump 00001B038B11
to look at my 286/10MHz test 'workstation'. ipxdump still generates
huge amounts of data, so you should be very careful to start it just
before you perform the operation (such as file creation for OS/2
clients with NW4.1 as a server, or a 'dir' on a directory with long
and short file names, or an encrypted password change ;-)) and stop it
directly after that. And, please gzip -9 and uuencode it before you
send it to anybody.
ipxparse will eventually take apart the dump that ipxdump
generates. They can as well be used in a pipe. Currently ipxparse does
not do anything sensible, but that will definitely change.
Volker Lendecke
<lendecke@namu01.gwdg.de>

247
ipxdump/ipxdump.c Normal file
View File

@@ -0,0 +1,247 @@
/* ipxdump.c */
/* Copyright 1996 Volker Lendecke, Goettingen, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <linux/if_ether.h>
#include <strings.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <signal.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <netinet/protocols.h>
#include <stdio.h>
#include <time.h>
#include <signal.h>
#include "ipxutil.h"
struct ipx_address
{
unsigned long net;
unsigned char node[IPX_NODE_LEN];
unsigned short sock;
};
struct ipx_packet
{
unsigned short ipx_checksum;
#define IPX_NO_CHECKSUM 0xFFFF
unsigned short ipx_pktsize;
unsigned char ipx_tctrl;
unsigned char ipx_type;
#define IPX_TYPE_UNKNOWN 0x00
#define IPX_TYPE_RIP 0x01 /* may also be 0 */
#define IPX_TYPE_SAP 0x04 /* may also be 0 */
#define IPX_TYPE_SPX 0x05 /* Not yet implemented */
#define IPX_TYPE_NCP 0x11 /* $lots for docs on this (SPIT) */
#define IPX_TYPE_PPROP 0x14 /* complicated flood fill brdcast [Not supported] */
struct ipx_address ipx_dest __attribute__ ((packed));
struct ipx_address ipx_source __attribute__ ((packed));
};
void handle_frame (unsigned char *buf, int length, struct sockaddr *saddr);
void handle_ipx (unsigned char *buf);
static int filter = 0;
static IPXNode filter_node;
static int exit_request = 0;
static void
int_handler()
{
exit_request = 1;
}
void
main (int argc, char *argv[])
{
int sd;
struct ifreq ifr, oldifr;
char *device = "eth0";
struct sockaddr saddr;
int sizeaddr;
unsigned char buf[4096];
int length;
signal(SIGINT, int_handler);
if (argc > 1)
{
if (ipx_sscanf_node(argv[1], filter_node) != 0)
{
fprintf(stderr, "usage: %s [node]\n", argv[0]);
exit(1);
}
filter = 1;
}
if ((sd = socket (AF_INET, SOCK_PACKET, htons (ETH_P_ALL))) < 0)
{
perror ("Can't get socket");
fprintf(stderr, "You must run %s as root\n", argv[0]);
exit (1);
}
/* SET PROMISC */
strcpy (oldifr.ifr_name, device);
if (ioctl (sd, SIOCGIFFLAGS, &oldifr) < 0)
{
close (sd);
perror ("Can't get flags");
exit (2);
}
/* This should be rewritten to cooperate with other net tools */
ifr = oldifr;
ifr.ifr_flags |= IFF_PROMISC;
if (ioctl (sd, SIOCSIFFLAGS, &ifr) < 0)
{
close (sd);
perror ("Can't set flags");
exit (3);
}
while ( exit_request == 0 )
{
/* This is the main data-gathering loop; keep it small
and fast */
sizeaddr = sizeof(saddr);
length = recvfrom (sd, buf, sizeof(buf), 0,
&saddr, &sizeaddr);
if (length < 0 ) continue;
handle_frame (buf, length, &saddr);
}
/* This should be rewritten to cooperate with other net tools */
if (ioctl (sd, SIOCSIFFLAGS, &oldifr) < 0)
{
close (sd);
perror ("Can't set flags");
exit (4);
}
close (sd);
exit (0);
}
void
handle_ipx (unsigned char *buf)
{
int i;
struct ipx_packet *h = (struct ipx_packet *)buf;
struct sockaddr_ipx s_addr;
struct sockaddr_ipx d_addr;
int length = ntohs(h->ipx_pktsize);
memset(&s_addr, 0, sizeof(s_addr));
memset(&d_addr, 0, sizeof(d_addr));
memcpy(s_addr.sipx_node, h->ipx_source.node, sizeof(s_addr.sipx_node));
s_addr.sipx_port = h->ipx_source.sock;
s_addr.sipx_network = h->ipx_source.net;
memcpy(d_addr.sipx_node, h->ipx_dest.node, sizeof(d_addr.sipx_node));
d_addr.sipx_port = h->ipx_dest.sock;
d_addr.sipx_network = h->ipx_dest.net;
if (filter != 0)
{
if ( (memcmp(filter_node, s_addr.sipx_node,
sizeof(filter_node)) != 0)
&& (memcmp(filter_node, d_addr.sipx_node,
sizeof(filter_node)) != 0))
{
/* Not for us */
return;
}
}
for (i = 0; i < length; i++)
{
printf("%2.2X", buf[i]);
}
printf("\n");
if (!isatty(STDOUT_FILENO))
{
fflush(stdout);
}
}
void
handle_other (unsigned char *buf, int length, struct sockaddr *saddr)
{
struct ethhdr *eth = (struct ethhdr *)buf;
unsigned char *p = &(buf[sizeof(struct ethhdr)]);
if (ntohs(eth->h_proto) < 1536)
{
/* This is a magic hack to spot IPX packets. Older
* Novell breaks the protocol design and runs IPX over
* 802.3 without an 802.2 LLC layer. We look for FFFF
* which isnt a used 802.2 SSAP/DSAP. This won't work
* for fault tolerant netware but does for the rest.
*/
if (*(unsigned short *)p == 0xffff)
{
printf("802.3 ");
handle_ipx(p);
return;
}
if ( (*(unsigned short *)p == htons(0xe0e0))
&& (p[2] == 0x03))
{
printf("802.2 ");
handle_ipx(p+3);
return;
}
if (memcmp(p, "\252\252\003\000\000\000\201\067", 8) == 0)
{
printf("snap ");
handle_ipx(p+8);
return;
}
}
}
void
handle_frame (unsigned char *buf, int length, struct sockaddr *saddr)
{
/* Ethernet packet type ID field */
unsigned short packet_type = ((struct ethhdr *)buf)->h_proto;
switch( packet_type )
{
case __constant_ntohs(ETH_P_IPX):
printf("EtherII ");
handle_ipx(&(buf[sizeof(struct ethhdr)]));
break;
default:
handle_other(buf, length, saddr);
break;
}
}

345
ipxdump/ipxparse.c Normal file
View File

@@ -0,0 +1,345 @@
/* ipxparse.c */
/* Copyright 1996 Volker Lendecke, Goettingen, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <linux/if_ether.h>
#include <strings.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <signal.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <netinet/protocols.h>
#include <stdio.h>
#include <time.h>
#include <signal.h>
#include <ctype.h>
#include "ipxutil.h"
struct ipx_address
{
unsigned long net;
unsigned char node[IPX_NODE_LEN];
unsigned short sock;
};
struct ipx_packet
{
unsigned short ipx_checksum;
#define IPX_NO_CHECKSUM 0xFFFF
unsigned short ipx_pktsize;
unsigned char ipx_tctrl;
unsigned char ipx_type;
#define IPX_TYPE_UNKNOWN 0x00
#define IPX_TYPE_RIP 0x01 /* may also be 0 */
#define IPX_TYPE_SAP 0x04 /* may also be 0 */
#define IPX_TYPE_SPX 0x05 /* Not yet implemented */
#define IPX_TYPE_NCP 0x11 /* $lots for docs on this (SPIT) */
#define IPX_TYPE_PPROP 0x14 /* complicated flood fill brdcast [Not supported] */
struct ipx_address ipx_dest __attribute__ ((packed));
struct ipx_address ipx_source __attribute__ ((packed));
};
#define NCP_ALLOC_SLOT_REQUEST (0x1111)
#define NCP_REQUEST (0x2222)
#define NCP_DEALLOC_SLOT_REQUEST (0x5555)
struct ncp_request_header {
__u16 type __attribute__ ((packed));
__u8 sequence __attribute__ ((packed));
__u8 conn_low __attribute__ ((packed));
__u8 task __attribute__ ((packed));
__u8 conn_high __attribute__ ((packed));
__u8 function __attribute__ ((packed));
__u8 data[0] __attribute__ ((packed));
};
#define NCP_REPLY (0x3333)
#define NCP_POSITIVE_ACK (0x9999)
struct ncp_reply_header {
__u16 type __attribute__ ((packed));
__u8 sequence __attribute__ ((packed));
__u8 conn_low __attribute__ ((packed));
__u8 task __attribute__ ((packed));
__u8 conn_high __attribute__ ((packed));
__u8 completion_code __attribute__ ((packed));
__u8 connection_state __attribute__ ((packed));
__u8 data[0] __attribute__ ((packed));
};
void handle_ipx (unsigned char *buf, int length, char *frame, int no);
void handle_ncp (struct sockaddr_ipx *source,
struct sockaddr_ipx *target,
unsigned char *buf, int length, int no);
void
handle_ipx (unsigned char *buf, int length, char *frame, int no)
{
struct ipx_packet *h = (struct ipx_packet *)buf;
struct sockaddr_ipx s_addr;
struct sockaddr_ipx d_addr;
memset(&s_addr, 0, sizeof(s_addr));
memset(&d_addr, 0, sizeof(d_addr));
memcpy(s_addr.sipx_node, h->ipx_source.node, sizeof(s_addr.sipx_node));
s_addr.sipx_port = h->ipx_source.sock;
s_addr.sipx_network = h->ipx_source.net;
memcpy(d_addr.sipx_node, h->ipx_dest.node, sizeof(d_addr.sipx_node));
d_addr.sipx_port = h->ipx_dest.sock;
d_addr.sipx_network = h->ipx_dest.net;
printf("%6.6d %s from ", no, frame);
ipx_print_saddr(&s_addr);
printf(" to ");
ipx_print_saddr(&d_addr);
printf("\n");
if ( (ntohs(s_addr.sipx_port) == 0x451)
|| (ntohs(d_addr.sipx_port) == 0x451))
{
handle_ncp(&s_addr, &d_addr, buf + sizeof(struct ipx_packet),
length - sizeof(struct ipx_packet), no);
}
}
void handle_ncp (struct sockaddr_ipx *source,
struct sockaddr_ipx *target,
unsigned char *buf, int length, int no)
{
struct ncp_request_header *rq = (struct ncp_request_header *)buf;
struct ncp_reply_header *rs = (struct ncp_reply_header *)buf;
unsigned char *data = NULL;
int data_length = 0;
int i;
if (ntohs(rq->type) == NCP_REQUEST)
{
/* Request */
printf("NCP request: conn: %-5d, seq: %-3d, task: %-3d, ",
rq->conn_low + 256 * rq->conn_high,
rq->sequence, rq->task);
data = buf + sizeof(struct ncp_request_header);
data_length = length - sizeof(struct ncp_request_header);
switch(rq->function)
{
case 87:
printf("fn: %-3d, subfn: %-3d\n",
rq->function, data[0]);
switch(data[0])
{
case 1:
{
unsigned char *p = &(data[0]);
printf("Open Create File or Subdirectory\n");
printf("Name Space: %d\n", p[1]);
printf("Open Create Mode: %x\n", p[2]);
printf("Search Attributes: %x\n",
*(__u16 *)&(p[3]));
printf("Return Information Mask: %x\n",
(unsigned int)(*(__u32 *)&(p[5])));
printf("Desired Access Rights: %x\n",
*(__u16 *)&(p[9]));
break;
}
case 2:
printf("Initialize Search\n");
break;
case 3:
printf("Search for File or Subdirectory\n");
break;
case 6:
printf("Obtain File Or Subdirectory "
"Information\n");
break;
case 8:
printf("Delete a File Or Subdirectory\n");
break;
}
data += 1;
data_length -= 1;
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]);
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);
}
}
if (ntohs(rs->type) == NCP_REPLY)
{
printf("NCP respons: conn: %-5d, seq: %-3d, task: %-3d, ",
rs->conn_low + 256 * rs->conn_high,
rs->sequence, rs->task);
printf("compl: %-3d, conn_st: %-3d\n",
rs->completion_code, rs->connection_state);
data = buf + sizeof(struct ncp_reply_header);
data_length = length - sizeof(struct ncp_reply_header);
}
if (data == NULL)
{
data = buf;
data_length = length;
}
i = 0;
while (i < data_length)
{
int j;
for (j = i; j < i+16; j++)
{
if (j >= data_length)
{
printf(" ");
}
else
{
printf("%-2.2X", data[j]);
}
}
printf(" ");
for (j = i; j < i+16; j++)
{
if (j >= data_length)
{
break;
}
if (isprint(data[j]))
{
printf("%c", data[j]);
}
else
{
printf(".");
}
}
printf("\n");
i += 16;
}
printf("\n");
}
void
main (int argc, char *argv[])
{
unsigned char buf[16384];
unsigned char packet[8192];
unsigned char *b;
int len;
int i = 1;
while (fgets(buf, sizeof(buf), stdin) != NULL)
{
if (strlen(buf) == sizeof(buf)-1)
{
fprintf(stderr, "line too long\n");
exit(1);
}
b = strchr(buf, ' ');
if (b == NULL)
{
fprintf(stderr, "illegal line format\n");
exit(1);
}
*b = '\0';
b += 1;
len = 0;
while ((b[0] != '\0') && (b[1] != '\0'))
{
unsigned int value;
if (sscanf(b, "%2x", &value) != 1)
{
fprintf(stderr, "illegal packet\n");
exit(1);
}
packet[len] = value;
b += 2;
len += 1;
}
handle_ipx(packet, len, buf, i);
i += 1;
}
exit (0);
}

129
ipxdump/ipxutil.c Normal file
View File

@@ -0,0 +1,129 @@
/*
IPX support library - general functions
Copyright (C) 1994, 1995 Ales Dryak <e-mail: A.Dryak@sh.cvut.cz>
Copyright (C) 1996, Volker Lendecke <lendecke@namu01.gwdg.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <string.h>
#include <netinet/in.h>
#include "ipxutil.h"
void
ipx_fprint_node(FILE *file, IPXNode node)
{
fprintf(file,"%02X%02X%02X%02X%02X%02X",
(unsigned char)node[0],
(unsigned char)node[1],
(unsigned char)node[2],
(unsigned char)node[3],
(unsigned char)node[4],
(unsigned char)node[5]
);
}
void
ipx_fprint_network(FILE *file, IPXNet net)
{
fprintf(file,"%08lX",net);
}
void
ipx_fprint_port(FILE *file, IPXPort port)
{
fprintf(file,"%04X",port);
}
void
ipx_fprint_saddr(FILE *file, struct sockaddr_ipx *sipx)
{
ipx_fprint_network(file,ntohl(sipx->sipx_network));
fprintf(file,":");
ipx_fprint_node(file,sipx->sipx_node);
fprintf(file,":");
ipx_fprint_port(file,ntohs(sipx->sipx_port));
}
void
ipx_print_node(IPXNode node)
{
ipx_fprint_node(stdout,node);
}
void
ipx_print_network(IPXNet net)
{
ipx_fprint_network(stdout,net);
}
void
ipx_print_port(IPXPort port)
{
ipx_fprint_port(stdout,port);
}
void
ipx_print_saddr(struct sockaddr_ipx *sipx)
{
ipx_fprint_saddr(stdout,sipx);
}
void
ipx_assign_node(IPXNode dest, IPXNode src)
{
memcpy(dest,src,sizeof(IPXNode));
}
int
ipx_node_equal(IPXNode n1, IPXNode n2)
{
return memcmp(n1,n2,sizeof(n1))==0;
}
int
ipx_sscanf_node(char *buf, IPXNode node)
{
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 -1;
}
for (i=0; i<6; i++)
{
node[i] = n[i];
}
return 0;
}
int
ipx_sscanf_net(char *buf, IPXNet *target)
{
if (sscanf(buf, "%8lX", target) == 1)
{
return 0;
}
return -1;
}
IPXNode ipx_this_node={0,0,0,0,0,0};
IPXNode ipx_broadcast_node={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
char ipx_err_string[IPX_MAX_ERROR+1]="no error detected";

65
ipxdump/ipxutil.h Normal file
View File

@@ -0,0 +1,65 @@
/*
IPX support library
Copyright (C) 1994, 1995 Ales Dryak <e-mail: A.Dryak@sh.cvut.cz>
Copyright (C) 1996, Volker Lendecke <lendecke@namu01.gwdg.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __IPXUTIL_H__
#define __IPXUTIL_H__
#include <stdio.h>
#include <linux/ipx.h>
#define IPX_MAX_ERROR (255)
#define IPX_THIS_NET (0)
#define IPX_THIS_NODE (ipx_this_node)
#define IPX_BROADCAST (ipx_broadcast_node)
#define IPX_AUTO_PORT (0)
#define IPX_USER_PTYPE (0)
#define IPX_IS_INTERNAL (1)
typedef unsigned char IPXNode[6];
typedef unsigned long int IPXNet;
typedef unsigned short int IPXPort;
typedef unsigned short int hop_t;
typedef unsigned short int tick_t;
void ipx_print_node(IPXNode node);
void ipx_print_network(IPXNet net);
void ipx_print_port(IPXPort port);
void ipx_print_saddr(struct sockaddr_ipx* sipx);
void ipx_fprint_node(FILE* file,IPXNode node);
void ipx_fprint_network(FILE* file,IPXNet net);
void ipx_fprint_port(FILE* file,IPXPort port);
void ipx_fprint_saddr(FILE* file,struct sockaddr_ipx* sipx);
int ipx_sscanf_node(char *buf, IPXNode node);
int ipx_sscanf_net(char *buf, IPXNet *target);
void ipx_assign_node(IPXNode dest,IPXNode src);
int ipx_node_equal(IPXNode n1,IPXNode n2);
extern IPXNode ipx_this_node;
extern IPXNode ipx_broadcast_node;
extern char ipx_err_string[IPX_MAX_ERROR+1];
#endif

View File

@@ -1,5 +1,5 @@
/* /*
* ncp_fs.h * ncp.h
* *
* Copyright (C) 1995 by Volker Lendecke * Copyright (C) 1995 by Volker Lendecke
* *

View File

@@ -42,6 +42,7 @@ struct ncp_fs_info {
#define NCP_IOC_NCPREQUEST _IOR('n', 1, unsigned char *) #define NCP_IOC_NCPREQUEST _IOR('n', 1, unsigned char *)
#define NCP_IOC_GETMOUNTUID _IOR('u', 1, uid_t) #define NCP_IOC_GETMOUNTUID _IOR('u', 1, uid_t)
#define NCP_IOC_CONN_LOGGED_IN _IO('l', 1)
#define NCP_GET_FS_INFO_VERSION (1) #define NCP_GET_FS_INFO_VERSION (1)
#define NCP_IOC_GET_FS_INFO _IOWR('i', 1, unsigned char *) #define NCP_IOC_GET_FS_INFO _IOWR('i', 1, unsigned char *)
@@ -126,9 +127,12 @@ extern struct inode_operations ncp_dir_inode_operations;
void ncp_free_inode_info(struct ncp_inode_info *i); void ncp_free_inode_info(struct ncp_inode_info *i);
void ncp_free_all_inodes(struct ncp_server *server); void ncp_free_all_inodes(struct ncp_server *server);
void ncp_init_root(struct ncp_server *server); void ncp_init_root(struct ncp_server *server);
int ncp_conn_logged_in(struct ncp_server *server);
int ncp_stat_root(struct ncp_server *server); int ncp_stat_root(struct ncp_server *server);
void ncp_init_dir_cache(void); void ncp_init_dir_cache(void);
void ncp_invalid_dir_cache(unsigned long ino); void ncp_invalid_dir_cache(struct inode *ino);
struct ncp_inode_info *ncp_find_inode(struct inode *inode);
ino_t ncp_info_ino(struct ncp_server *server, struct ncp_inode_info *info);
void ncp_invalidate_all_inodes(struct ncp_server *server); void ncp_invalidate_all_inodes(struct ncp_server *server);
void ncp_free_dir_cache(void); void ncp_free_dir_cache(void);
int ncp_date_dos2unix(__u16 time, __u16 date); int ncp_date_dos2unix(__u16 time, __u16 date);

View File

@@ -28,6 +28,7 @@ struct ncp_inode_info {
number of references in memory */ number of references in memory */
struct ncp_inode_info *dir; struct ncp_inode_info *dir;
struct ncp_inode_info *next, *prev; struct ncp_inode_info *next, *prev;
struct inode *inode;
struct nw_file_info finfo; struct nw_file_info finfo;
}; };

View File

@@ -22,7 +22,6 @@ struct ncp_server {
it completely. */ it completely. */
struct file *ncp_filp; /* File pointer to ncp socket */ struct file *ncp_filp; /* File pointer to ncp socket */
struct file *wdog_filp; /* File pointer to wdog socket */ struct file *wdog_filp; /* File pointer to wdog socket */
void *data_ready; /* The wdog socket gets a new void *data_ready; /* The wdog socket gets a new
data_ready callback. We store the data_ready callback. We store the
@@ -35,7 +34,8 @@ struct ncp_server {
u8 completion; /* Status message from server */ u8 completion; /* Status message from server */
u8 conn_status; /* Bit 4 = 1 ==> Server going down, no u8 conn_status; /* Bit 4 = 1 ==> Server going down, no
requests allowed anymore */ requests allowed anymore.
Bit 0 = 1 ==> Server is down. */
int buffer_size; /* Negotiated bufsize */ int buffer_size; /* Negotiated bufsize */
@@ -56,6 +56,18 @@ struct ncp_server {
char root_path; /* '\0' */ char root_path; /* '\0' */
}; };
static inline int
ncp_conn_valid(struct ncp_server *server)
{
return ((server->conn_status & 0x11) == 0);
}
static inline void
ncp_invalidate_conn(struct ncp_server *server)
{
server->conn_status |= 0x01;
}
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif #endif

View File

@@ -13,7 +13,7 @@
#include <linux/ncp.h> #include <linux/ncp.h>
#include <linux/ncp_fs_i.h> #include <linux/ncp_fs_i.h>
#define NCP_MOUNT_VERSION 1 #define NCP_MOUNT_VERSION 2
#define NCP_USERNAME_LEN (NCP_BINDERY_NAME_LEN) #define NCP_USERNAME_LEN (NCP_BINDERY_NAME_LEN)
#define NCP_PASSWORD_LEN 20 #define NCP_PASSWORD_LEN 20
@@ -26,14 +26,14 @@ struct ncp_mount_data {
int version; int version;
unsigned int ncp_fd; /* The socket to the ncp port */ unsigned int ncp_fd; /* The socket to the ncp port */
unsigned int wdog_fd; /* Watchdog packets come here */ unsigned int wdog_fd; /* Watchdog packets come here */
unsigned int message_fd; /* Not used yet, maybe for messages */ unsigned int message_fd; /* Message notifications come here */
uid_t mounted_uid; /* Who may umount() this filesystem? */ uid_t mounted_uid; /* Who may umount() this filesystem? */
struct sockaddr_ipx serv_addr; struct sockaddr_ipx serv_addr;
unsigned char server_name[49]; unsigned char server_name[NCP_BINDERY_NAME_LEN];
unsigned char username[NCP_USERNAME_LEN+1]; unsigned char mount_point[PATH_MAX+1];
unsigned char password[NCP_PASSWORD_LEN+1]; unsigned char mounted_vol[NCP_VOLNAME_LEN+1];
unsigned int time_out; /* How long should I wait after unsigned int time_out; /* How long should I wait after
sending a NCP request? */ sending a NCP request? */

View File

@@ -47,7 +47,7 @@ static struct inode *
ncp_iget(struct inode *dir, struct nw_file_info *finfo); ncp_iget(struct inode *dir, struct nw_file_info *finfo);
static struct ncp_inode_info * static struct ncp_inode_info *
ncp_find_inode(struct inode *dir, const char *name); ncp_find_dir_inode(struct inode *dir, const char *name);
static int static int
ncp_lookup(struct inode *dir, const char *__name, ncp_lookup(struct inode *dir, const char *__name,
@@ -102,7 +102,7 @@ static struct file_operations ncp_dir_operations = {
NULL, /* write - bad */ NULL, /* write - bad */
ncp_readdir, /* readdir */ ncp_readdir, /* readdir */
NULL, /* select - default */ NULL, /* select - default */
ncp_ioctl, /* ioctl - default */ ncp_ioctl, /* ioctl */
NULL, /* mmap */ NULL, /* mmap */
NULL, /* no special open code */ NULL, /* no special open code */
NULL, /* no special release code */ NULL, /* no special release code */
@@ -129,6 +129,58 @@ struct inode_operations ncp_dir_inode_operations = {
}; };
/* Here we encapsulate the inode number handling that depends upon the
* mount mode: When we mount a complete server, the memory address of
* the npc_inode_info is used as an inode. When only a single volume
* is mounted, then the DosDirNum is used as the inode number. As this
* is unique for the complete volume, this should enable the NFS
* exportability of a ncpfs-mounted volume.
*/
static inline int
ncp_single_volume(struct ncp_server *server)
{
return (server->m.mounted_vol[0] != '\0');
}
inline ino_t
ncp_info_ino(struct ncp_server *server, struct ncp_inode_info *info)
{
return ncp_single_volume(server)
? info->finfo.i.DosDirNum : (ino_t)info;
}
static inline int
ncp_is_server_root(struct inode *inode)
{
struct ncp_server *s = NCP_SERVER(inode);
return ( (!ncp_single_volume(s))
&& (inode->i_ino == ncp_info_ino(s, &(s->root))));
}
struct ncp_inode_info *
ncp_find_inode(struct inode *inode)
{
struct ncp_server *server = NCP_SERVER(inode);
struct ncp_inode_info *root = &(server->root);
struct ncp_inode_info *this = root;
ino_t ino = inode->i_ino;
do
{
if (ino == ncp_info_ino(server, this))
{
return this;
}
this = this->next;
}
while (this != root);
return NULL;
}
static int static int
ncp_dir_read(struct inode *inode, struct file *filp, char *buf, int count) ncp_dir_read(struct inode *inode, struct file *filp, char *buf, int count)
{ {
@@ -142,6 +194,7 @@ ncp_dir_read(struct inode *inode, struct file *filp, char *buf, int count)
all inodes that are in memory. That's why it's enough to index the all inodes that are in memory. That's why it's enough to index the
directory cache by the inode number. */ directory cache by the inode number. */
static int c_dev = 0;
static unsigned long c_ino = 0; static unsigned long c_ino = 0;
static int c_size; static int c_size;
static int c_seen_eof; static int c_seen_eof;
@@ -156,7 +209,7 @@ ncp_readdir(struct inode *inode, struct file *filp,
int index = 0; int index = 0;
struct ncp_dirent *entry = NULL; struct ncp_dirent *entry = NULL;
struct ncp_server *server = NCP_SERVER(inode); struct ncp_server *server = NCP_SERVER(inode);
struct ncp_inode_info *dir = (struct ncp_inode_info *)(inode->i_ino); struct ncp_inode_info *dir = NCP_INOP(inode);
int filldir(struct dirent *dirent, int filldir(struct dirent *dirent,
const char *name, int len, const char *name, int len,
@@ -170,9 +223,9 @@ ncp_readdir(struct inode *inode, struct file *filp,
return 1; return 1;
} }
DDPRINTK("ncp_readdir: filp->f_pos = %d\n", (int)filp->f_pos); DPRINTK("ncp_readdir: filp->f_pos = %d\n", (int)filp->f_pos);
DDPRINTK("ncp_readdir: inode->i_ino = %ld, c_ino = %ld\n", DPRINTK("ncp_readdir: inode->i_ino = %ld, c_ino = %ld\n",
inode->i_ino, c_ino); inode->i_ino, c_ino);
if (!inode || !S_ISDIR(inode->i_mode)) if (!inode || !S_ISDIR(inode->i_mode))
{ {
@@ -180,6 +233,11 @@ ncp_readdir(struct inode *inode, struct file *filp,
return -EBADF; return -EBADF;
} }
if (!ncp_conn_valid(server))
{
return -EIO;
}
if (c_entry == NULL) if (c_entry == NULL)
{ {
i = sizeof (struct ncp_dirent) * NCP_READDIR_CACHE_SIZE; i = sizeof (struct ncp_dirent) * NCP_READDIR_CACHE_SIZE;
@@ -193,8 +251,9 @@ ncp_readdir(struct inode *inode, struct file *filp,
if (filp->f_pos == 0) if (filp->f_pos == 0)
{ {
ncp_invalid_dir_cache(inode->i_ino); ncp_invalid_dir_cache(inode);
if (filldir(dirent,".",1, filp->f_pos, (int)dir) < 0) if (filldir(dirent,".",1, filp->f_pos,
ncp_info_ino(server, dir)) < 0)
{ {
return 0; return 0;
} }
@@ -204,7 +263,8 @@ ncp_readdir(struct inode *inode, struct file *filp,
if (filp->f_pos == 1) if (filp->f_pos == 1)
{ {
if (filldir(dirent,"..",2, filp->f_pos, (int)(dir->dir)) < 0) if (filldir(dirent,"..",2, filp->f_pos,
ncp_info_ino(server, dir->dir)) < 0)
{ {
return 0; return 0;
} }
@@ -212,7 +272,7 @@ ncp_readdir(struct inode *inode, struct file *filp,
return ROUND_UP(NAME_OFFSET(dirent)+i+1); return ROUND_UP(NAME_OFFSET(dirent)+i+1);
} }
if (inode->i_ino == c_ino) if ((inode->i_dev == c_dev) && (inode->i_ino == c_ino))
{ {
for (i = 0; i < c_size; i++) for (i = 0; i < c_size; i++)
{ {
@@ -234,7 +294,7 @@ ncp_readdir(struct inode *inode, struct file *filp,
{ {
DDPRINTK("ncp_readdir: Not found in cache.\n"); DDPRINTK("ncp_readdir: Not found in cache.\n");
if (inode->i_ino == (int)&(server->root)) if (ncp_is_server_root(inode))
{ {
result = ncp_read_volume_list(server, filp->f_pos, result = ncp_read_volume_list(server, filp->f_pos,
NCP_READDIR_CACHE_SIZE); NCP_READDIR_CACHE_SIZE);
@@ -251,6 +311,7 @@ ncp_readdir(struct inode *inode, struct file *filp,
if (result < 0) if (result < 0)
{ {
c_dev = 0;
c_ino = 0; c_ino = 0;
return result; return result;
} }
@@ -258,6 +319,7 @@ ncp_readdir(struct inode *inode, struct file *filp,
if (result > 0) if (result > 0)
{ {
c_seen_eof = (result < NCP_READDIR_CACHE_SIZE); c_seen_eof = (result < NCP_READDIR_CACHE_SIZE);
c_dev = inode->i_dev;
c_ino = inode->i_ino; c_ino = inode->i_ino;
c_size = result; c_size = result;
entry = c_entry; entry = c_entry;
@@ -284,22 +346,33 @@ ncp_readdir(struct inode *inode, struct file *filp,
use. Otherwise the inode number does not use. Otherwise the inode number does not
matter. (You can argue a lot about this..) */ matter. (You can argue a lot about this..) */
struct ncp_inode_info *ino_info; ino_t ino;
ino_info = ncp_find_inode(inode, entry->i.entryName);
/* Some programs seem to be confused about a zero if (ncp_single_volume(server))
inode number, so we set it to one. Thanks to
Gordon Chaffee for this one. */
if (ino_info == NULL)
{ {
ino_info = (struct ncp_inode_info *) 1; ino = (ino_t)(entry->i.DosDirNum);
} }
else
{
struct ncp_inode_info *ino_info;
ino_info = ncp_find_dir_inode(inode,
entry->i.entryName);
DDPRINTK("ncp_readdir: entry->path= %s\n", entry->i.entryName); /* Some programs seem to be confused about a
DDPRINTK("ncp_readdir: entry->f_pos = %ld\n", entry->f_pos); * zero inode number, so we set it to one.
* Thanks to Gordon Chaffee for this one. */
if (ino_info == NULL)
{
ino_info = (struct ncp_inode_info *) 1;
}
ino = (ino_t)(ino_info);
}
DPRINTK("ncp_readdir: entry->path= %s\n", entry->i.entryName);
DPRINTK("ncp_readdir: entry->f_pos = %ld\n", entry->f_pos);
if (filldir(dirent, entry->i.entryName, entry->i.nameLen, if (filldir(dirent, entry->i.entryName, entry->i.nameLen,
entry->f_pos, (ino_t)ino_info) < 0) entry->f_pos, ino) < 0)
{ {
return 0; return 0;
} }
@@ -353,9 +426,9 @@ ncp_read_volume_list(struct ncp_server *server, int fpos, int cache_size)
DPRINTK("ncp_read_volumes: found vol: %s\n", DPRINTK("ncp_read_volumes: found vol: %s\n",
info.volume_name); info.volume_name);
if (ncp_do_lookup(server, NULL, if (ncp_lookup_volume(server,
info.volume_name, info.volume_name,
&(entry->i)) != 0) &(entry->i)) != 0)
{ {
printk("ncpfs: could not lookup vol " printk("ncpfs: could not lookup vol "
"%s\n", info.volume_name); "%s\n", info.volume_name);
@@ -438,15 +511,17 @@ ncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos,
void void
ncp_init_dir_cache(void) ncp_init_dir_cache(void)
{ {
c_dev = 0;
c_ino = 0; c_ino = 0;
c_entry = NULL; c_entry = NULL;
} }
void void
ncp_invalid_dir_cache(unsigned long ino) ncp_invalid_dir_cache(struct inode *inode)
{ {
if (ino == c_ino) if ((inode->i_dev == c_dev) && (inode->i_ino == c_ino))
{ {
c_dev = 0;
c_ino = 0; c_ino = 0;
c_seen_eof = 0; c_seen_eof = 0;
} }
@@ -517,7 +592,8 @@ ncp_iget(struct inode *dir, struct nw_file_info *finfo)
root->next->prev = new_inode_info; root->next->prev = new_inode_info;
root->next = new_inode_info; root->next = new_inode_info;
if (!(inode = iget(dir->i_sb, (int)new_inode_info))) if (!(inode = iget(dir->i_sb, ncp_info_ino(NCP_SERVER(dir),
new_inode_info))))
{ {
printk("ncp_iget: iget failed!"); printk("ncp_iget: iget failed!");
return NULL; return NULL;
@@ -567,6 +643,7 @@ ncp_init_root(struct ncp_server *server)
root->finfo.opened = 0; root->finfo.opened = 0;
i->attributes = aDIR; i->attributes = aDIR;
i->dataStreamSize = 1024; i->dataStreamSize = 1024;
i->DosDirNum = 0;
i->volNumber = NCP_NUMBER_OF_VOLUMES+1; /* illegal volnum */ i->volNumber = NCP_NUMBER_OF_VOLUMES+1; /* illegal volnum */
ncp_date_unix2dos(0, &(i->creationTime), &(i->creationDate)); ncp_date_unix2dos(0, &(i->creationTime), &(i->creationDate));
ncp_date_unix2dos(0, &(i->modifyTime), &(i->modifyDate)); ncp_date_unix2dos(0, &(i->modifyTime), &(i->modifyDate));
@@ -581,6 +658,25 @@ ncp_init_root(struct ncp_server *server)
return; return;
} }
int
ncp_conn_logged_in(struct ncp_server *server)
{
if (server->m.mounted_vol[0] == '\0')
{
return 0;
}
str_upper(server->m.mounted_vol);
if (ncp_lookup_volume(server, server->m.mounted_vol,
&(server->root.finfo.i)) != 0)
{
return -ENOENT;
}
str_lower(server->root.finfo.i.entryName);
return 0;
}
void void
ncp_free_all_inodes(struct ncp_server *server) ncp_free_all_inodes(struct ncp_server *server)
{ {
@@ -611,7 +707,7 @@ ncp_free_all_inodes(struct ncp_server *server)
complete linear search through the inodes belonging to this complete linear search through the inodes belonging to this
filesystem. This has to be fixed. */ filesystem. This has to be fixed. */
static struct ncp_inode_info * static struct ncp_inode_info *
ncp_find_inode(struct inode *dir, const char *name) ncp_find_dir_inode(struct inode *dir, const char *name)
{ {
struct ncp_server *server = NCP_SERVER(dir); struct ncp_server *server = NCP_SERVER(dir);
struct nw_info_struct *dir_info = NCP_ISTRUCT(dir); struct nw_info_struct *dir_info = NCP_ISTRUCT(dir);
@@ -658,9 +754,14 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
return -ENOENT; return -ENOENT;
} }
DDPRINTK("ncp_lookup: %s, len %d\n", __name, len);
server = NCP_SERVER(dir); server = NCP_SERVER(dir);
if (!ncp_conn_valid(server))
{
iput(dir);
return -EIO;
}
DDPRINTK("ncp_lookup: %s, len %d\n", __name, len);
/* Fast cheat for . */ /* Fast cheat for . */
if (len == 0 || (len == 1 && __name[0] == '.')) if (len == 0 || (len == 1 && __name[0] == '.'))
@@ -679,7 +780,7 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
parent->state = NCP_INODE_LOOKED_UP; parent->state = NCP_INODE_LOOKED_UP;
} }
*result = iget(dir->i_sb, (int)parent); *result = iget(dir->i_sb, ncp_info_ino(server, parent));
iput(dir); iput(dir);
if (*result == 0) if (*result == 0)
{ {
@@ -694,7 +795,7 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
memcpy(name, __name, len); memcpy(name, __name, len);
name[len] = 0; name[len] = 0;
result_info = ncp_find_inode(dir, name); result_info = ncp_find_dir_inode(dir, name);
if (result_info != 0) if (result_info != 0)
{ {
@@ -706,7 +807,7 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
/* Here we convert the inode_info address into an /* Here we convert the inode_info address into an
inode number */ inode number */
*result = iget(dir->i_sb, (int)result_info); *result = iget(dir->i_sb, ncp_info_ino(server, result_info));
iput(dir); iput(dir);
if (*result == NULL) if (*result == NULL)
@@ -722,7 +823,7 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
found_in_cache = 0; found_in_cache = 0;
if (dir->i_ino == c_ino) if ((dir->i_dev == c_dev) && (dir->i_ino == c_ino))
{ {
int first = c_last_returned_index; int first = c_last_returned_index;
int i; int i;
@@ -747,15 +848,24 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
if (found_in_cache == 0) if (found_in_cache == 0)
{ {
int res;
str_upper(name); str_upper(name);
DDPRINTK("ncp_lookup: do_lookup on %s/%s\n", DDPRINTK("ncp_lookup: do_lookup on %s/%s\n",
NCP_ISTRUCT(dir)->entryName, name); NCP_ISTRUCT(dir)->entryName, name);
if (ncp_do_lookup(server, if (ncp_is_server_root(dir))
dir->i_ino == (int)&(NCP_SERVER(dir)->root) {
? NULL : NCP_ISTRUCT(dir), res = ncp_lookup_volume(server, name, &(finfo.i));
name, &(finfo.i)) != 0) }
else
{
res = ncp_obtain_info(server,
NCP_ISTRUCT(dir)->volNumber,
NCP_ISTRUCT(dir)->DosDirNum,
name, &(finfo.i));
}
if (res != 0)
{ {
iput(dir); iput(dir);
return -ENOENT; return -ENOENT;
@@ -790,6 +900,11 @@ ncp_create(struct inode *dir, const char *name, int len, int mode,
iput(dir); iput(dir);
return -ENOENT; return -ENOENT;
} }
if (!ncp_conn_valid(NCP_SERVER(dir)))
{
iput(dir);
return -EIO;
}
strncpy(_name, name, len); strncpy(_name, name, len);
_name[len] = '\0'; _name[len] = '\0';
@@ -806,7 +921,7 @@ ncp_create(struct inode *dir, const char *name, int len, int mode,
return -EACCES; return -EACCES;
} }
ncp_invalid_dir_cache(dir->i_ino); ncp_invalid_dir_cache(dir);
str_lower(finfo.i.entryName); str_lower(finfo.i.entryName);
finfo.access = O_RDWR; finfo.access = O_RDWR;
@@ -847,6 +962,11 @@ ncp_mkdir(struct inode *dir, const char *name, int len, int mode)
iput(dir); iput(dir);
return -ENOENT; return -ENOENT;
} }
if (!ncp_conn_valid(NCP_SERVER(dir)))
{
iput(dir);
return -EIO;
}
if (ncp_open_create_file_or_subdir(NCP_SERVER(dir), if (ncp_open_create_file_or_subdir(NCP_SERVER(dir),
NCP_ISTRUCT(dir), _name, NCP_ISTRUCT(dir), _name,
@@ -858,7 +978,7 @@ ncp_mkdir(struct inode *dir, const char *name, int len, int mode)
else else
{ {
error = 0; error = 0;
ncp_invalid_dir_cache(dir->i_ino); ncp_invalid_dir_cache(dir);
} }
iput(dir); iput(dir);
@@ -877,8 +997,14 @@ ncp_rmdir(struct inode *dir, const char *name, int len)
iput(dir); iput(dir);
return -ENOENT; return -ENOENT;
} }
if (ncp_find_inode(dir, name) != NULL) if (!ncp_conn_valid(NCP_SERVER(dir)))
{ {
iput(dir);
return -EIO;
}
if (ncp_find_dir_inode(dir, name) != NULL)
{
iput(dir);
error = -EBUSY; error = -EBUSY;
} }
else else
@@ -892,7 +1018,7 @@ ncp_rmdir(struct inode *dir, const char *name, int len)
NCP_ISTRUCT(dir), NCP_ISTRUCT(dir),
_name)) == 0) _name)) == 0)
{ {
ncp_invalid_dir_cache(dir->i_ino); ncp_invalid_dir_cache(dir);
} }
else else
{ {
@@ -915,8 +1041,14 @@ ncp_unlink(struct inode *dir, const char *name, int len)
iput(dir); iput(dir);
return -ENOENT; return -ENOENT;
} }
if (ncp_find_inode(dir, name) != NULL) if (!ncp_conn_valid(NCP_SERVER(dir)))
{ {
iput(dir);
return -EIO;
}
if (ncp_find_dir_inode(dir, name) != NULL)
{
iput(dir);
error = -EBUSY; error = -EBUSY;
} }
else else
@@ -929,7 +1061,7 @@ ncp_unlink(struct inode *dir, const char *name, int len)
NCP_ISTRUCT(dir), NCP_ISTRUCT(dir),
_name)) == 0) _name)) == 0)
{ {
ncp_invalid_dir_cache(dir->i_ino); ncp_invalid_dir_cache(dir);
} }
else else
{ {
@@ -955,6 +1087,12 @@ ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
goto finished; goto finished;
} }
if (!ncp_conn_valid(NCP_SERVER(old_dir)))
{
res = -EIO;
goto finished;
}
if (!new_dir || !S_ISDIR(new_dir->i_mode)) if (!new_dir || !S_ISDIR(new_dir->i_mode))
{ {
printk("ncp_rename: new inode is NULL or not a directory\n"); printk("ncp_rename: new inode is NULL or not a directory\n");
@@ -962,8 +1100,8 @@ ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
goto finished; goto finished;
} }
if ( (ncp_find_inode(old_dir, old_name) != NULL) if ( (ncp_find_dir_inode(old_dir, old_name) != NULL)
|| (ncp_find_inode(new_dir, new_name) != NULL)) || (ncp_find_dir_inode(new_dir, new_name) != NULL))
{ {
res = -EBUSY; res = -EBUSY;
goto finished; goto finished;
@@ -983,8 +1121,8 @@ ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
if (res == 0) if (res == 0)
{ {
ncp_invalid_dir_cache(old_dir->i_ino); ncp_invalid_dir_cache(old_dir);
ncp_invalid_dir_cache(new_dir->i_ino); ncp_invalid_dir_cache(new_dir);
} }
else else
{ {

View File

@@ -99,6 +99,10 @@ ncp_file_read(struct inode *inode, struct file *file, char *buf, int count)
DPRINTK("ncp_file_read: inode = NULL\n"); DPRINTK("ncp_file_read: inode = NULL\n");
return -EINVAL; return -EINVAL;
} }
if (!ncp_conn_valid(NCP_SERVER(inode)))
{
return -EIO;
}
if (!S_ISREG(inode->i_mode)) if (!S_ISREG(inode->i_mode))
{ {
@@ -178,6 +182,10 @@ ncp_file_write(struct inode *inode, struct file *file, char *buf,
DPRINTK("ncp_file_write: inode = NULL\n"); DPRINTK("ncp_file_write: inode = NULL\n");
return -EINVAL; return -EINVAL;
} }
if (!ncp_conn_valid(NCP_SERVER(inode)))
{
return -EIO;
}
if (!S_ISREG(inode->i_mode)) if (!S_ISREG(inode->i_mode))
{ {
@@ -239,6 +247,7 @@ ncp_file_write(struct inode *inode, struct file *file, char *buf,
if (pos > inode->i_size) if (pos > inode->i_size)
{ {
inode->i_size = pos; inode->i_size = pos;
ncp_invalid_dir_cache(NCP_INOP(inode)->dir->inode);
} }
DPRINTK("ncp_file_write: exit %s\n", NCP_ISTRUCT(inode)->entryName); DPRINTK("ncp_file_write: exit %s\n", NCP_ISTRUCT(inode)->entryName);

View File

@@ -61,50 +61,25 @@ ncp_read_inode(struct inode *inode)
inode->i_ino. Just to make sure everything went well, we inode->i_ino. Just to make sure everything went well, we
check it's there. */ check it's there. */
struct ncp_inode_info *inode_info struct ncp_inode_info *inode_info = ncp_find_inode(inode);
= (struct ncp_inode_info *)(inode->i_ino);
#if 1 if (inode_info == NULL)
struct ncp_inode_info *root = &(NCP_SERVER(inode)->root);
struct ncp_inode_info *check_info = root;
do
{ {
if (inode_info == check_info) /* Ok, now we're in trouble. The inode info is not there. What
{ should we do now??? */
if (check_info->state == NCP_INODE_LOOKED_UP) printk("ncp_read_inode: inode info not found\n");
{ return;
DDPRINTK("ncp_read_inode: found it!\n"); }
goto good;
}
else
{
printk("ncp_read_inode: "
"state != NCP_INODE_LOOKED_UP\n");
goto good;
}
}
check_info = check_info->next;
}
while (check_info != root);
/* Ok, now we're in trouble. The inode info is not there. What
should we do now??? */
printk("ncp_read_inode: inode info not found\n");
return;
good:
DDPRINTK("ncp_read_inode: read entry %s\n",
inode_info->finfo.i.entryName);
#endif
inode_info->state = NCP_INODE_VALID; inode_info->state = NCP_INODE_VALID;
NCP_INOP(inode) = inode_info; NCP_INOP(inode) = inode_info;
inode_info->inode = inode;
if (NCP_ISTRUCT(inode)->attributes & aDIR) if (NCP_ISTRUCT(inode)->attributes & aDIR)
{ {
inode->i_mode = NCP_SERVER(inode)->m.dir_mode; inode->i_mode = NCP_SERVER(inode)->m.dir_mode;
/* for directories in dataStreamSize seems to be some /* for directories dataStreamSize seems to be some
Object ID ??? */ Object ID ??? */
inode->i_size = 512; inode->i_size = 512;
} }
@@ -176,7 +151,7 @@ ncp_put_inode(struct inode *inode)
{ {
DDPRINTK("ncp_put_inode: put directory %ld\n", DDPRINTK("ncp_put_inode: put directory %ld\n",
inode->i_ino); inode->i_ino);
ncp_invalid_dir_cache(inode->i_ino); ncp_invalid_dir_cache(inode);
} }
clear_inode(inode); clear_inode(inode);
@@ -204,6 +179,8 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
printk("ncp warning: mount version %s than kernel\n", printk("ncp warning: mount version %s than kernel\n",
(data->version < NCP_MOUNT_VERSION) ? (data->version < NCP_MOUNT_VERSION) ?
"older" : "newer"); "older" : "newer");
sb->s_dev = 0;
return NULL;
} }
if ( (data->ncp_fd >= NR_OPEN) if ( (data->ncp_fd >= NR_OPEN)
@@ -253,6 +230,7 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
server->wait = NULL; server->wait = NULL;
server->packet = NULL; server->packet = NULL;
server->buffer_size = 0; server->buffer_size = 0;
server->conn_status = 0;
server->m = *data; server->m = *data;
server->m.file_mode = (server->m.file_mode & server->m.file_mode = (server->m.file_mode &
@@ -302,7 +280,7 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
DPRINTK("ncp_read_super: NCP_SBP(sb) = %x\n", (int)NCP_SBP(sb)); DPRINTK("ncp_read_super: NCP_SBP(sb) = %x\n", (int)NCP_SBP(sb));
if (!(sb->s_mounted = iget(sb, (int)&(server->root)))) if (!(sb->s_mounted = iget(sb, ncp_info_ino(server, &(server->root)))))
{ {
sb->s_dev = 0; sb->s_dev = 0;
printk("ncp_read_super: get root inode failed\n"); printk("ncp_read_super: get root inode failed\n");
@@ -393,6 +371,11 @@ ncp_notify_change(struct inode *inode, struct iattr *attr)
int info_mask; int info_mask;
struct nw_modify_dos_info info; struct nw_modify_dos_info info;
if (!ncp_conn_valid(NCP_SERVER(inode)))
{
return -EIO;
}
if ((result = inode_change_ok(inode, attr)) < 0) if ((result = inode_change_ok(inode, attr)) < 0)
return result; return result;
@@ -480,7 +463,7 @@ ncp_notify_change(struct inode *inode, struct iattr *attr)
result = 0; result = 0;
} }
ncp_invalid_dir_cache((unsigned long)(NCP_INOP(inode)->dir)); ncp_invalid_dir_cache(NCP_INOP(inode)->dir->inode);
return result; return result;
} }

View File

@@ -79,6 +79,16 @@ ncp_ioctl (struct inode * inode, struct file * filp,
return server->reply_size; return server->reply_size;
case NCP_IOC_CONN_LOGGED_IN:
if ( (permission(inode, MAY_WRITE) != 0)
&& (current->uid != server->m.mounted_uid))
{
return -EACCES;
}
return ncp_conn_logged_in(server);
case NCP_IOC_GET_FS_INFO: case NCP_IOC_GET_FS_INFO:
if ( (permission(inode, MAY_WRITE) != 0) if ( (permission(inode, MAY_WRITE) != 0)

View File

@@ -135,6 +135,11 @@ ncp_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)
{ {
DPRINTK("ncp_mmap: called\n"); DPRINTK("ncp_mmap: called\n");
if (!ncp_conn_valid(NCP_SERVER(inode)))
{
return -EIO;
}
/* only PAGE_COW or read-only supported now */ /* only PAGE_COW or read-only supported now */
if (vma->vm_flags & VM_SHARED) if (vma->vm_flags & VM_SHARED)
return -EINVAL; return -EINVAL;

View File

@@ -267,64 +267,26 @@ ncp_extract_file_info(void *structure, struct nw_info_struct *target)
return; return;
} }
int int
ncp_do_lookup(struct ncp_server *server, ncp_obtain_info(struct ncp_server *server,
struct nw_info_struct *dir, __u8 vol_num, __u32 dir_base,
char *path, /* may only be one component */ char *path, /* At most 1 component */
struct nw_info_struct *target) struct nw_info_struct *target)
{ {
__u8 vol_num;
__u32 dir_base;
int result; int result;
char *volname = NULL;
if (target == NULL) if (target == NULL)
{ {
return -EINVAL; return -EINVAL;
} }
if (dir == NULL)
{
DDPRINTK("ncp_do_lookup: looking up vol %s\n", path);
/* Access a volume's root directory */
ncp_init_request(server);
ncp_add_byte(server, 22); /* subfunction */
ncp_add_byte(server, 0); /* dos name space */
ncp_add_byte(server, 0); /* reserved */
ncp_add_byte(server, 0); /* reserved */
ncp_add_byte(server, 0); /* reserved */
ncp_add_handle_path(server, 0, 0, 0, /* no handle */
path);
if ((result = ncp_request(server, 87)) != 0)
{
ncp_unlock_server(server);
return result;
}
dir_base = ncp_reply_dword(server, 4);
vol_num = ncp_reply_byte (server, 8);
ncp_unlock_server(server);
volname = path;
path = NULL;
}
else
{
vol_num = dir->volNumber;
dir_base = dir->DosDirNum;
}
ncp_init_request(server); ncp_init_request(server);
ncp_add_byte(server, 6); /* subfunction */ ncp_add_byte(server, 6); /* subfunction */
ncp_add_byte(server, 0); /* dos name space */ ncp_add_byte(server, 0); /* dos name space */
ncp_add_byte(server, 0); /* dos name space as dest */ ncp_add_byte(server, 0); /* dos name space as dest */
ncp_add_word(server, 0xff); /* get all */ ncp_add_word(server, 0xff); /* get all */
ncp_add_dword(server, RIM_ALL); ncp_add_dword(server, RIM_ALL);
ncp_add_handle_path(server, vol_num, dir_base, 1, ncp_add_handle_path(server, vol_num, dir_base, 1, path);
path);
if ((result = ncp_request(server, 87)) != 0) if ((result = ncp_request(server, 87)) != 0)
{ {
@@ -333,14 +295,54 @@ ncp_do_lookup(struct ncp_server *server,
} }
ncp_extract_file_info(ncp_reply_data(server, 0), target); ncp_extract_file_info(ncp_reply_data(server, 0), target);
ncp_unlock_server(server);
return 0;
}
if (volname != NULL) int
ncp_lookup_volume(struct ncp_server *server,
char *volname,
struct nw_info_struct *target)
{
int result;
__u8 vol_num;
__u32 dir_base;
DPRINTK("ncp_lookup_volume: looking up vol %s\n", volname);
ncp_init_request(server);
ncp_add_byte(server, 22); /* Subfunction: Generate dir handle */
ncp_add_byte(server, 0); /* DOS name space */
ncp_add_byte(server, 0); /* reserved */
ncp_add_byte(server, 0); /* reserved */
ncp_add_byte(server, 0); /* reserved */
ncp_add_byte(server, 0); /* faked volume number */
ncp_add_dword(server, 0); /* faked dir_base */
ncp_add_byte(server, 0xff); /* Don't have a dir_base */
ncp_add_byte(server, 1); /* 1 path component */
ncp_add_pstring(server, volname);
if ((result = ncp_request(server, 87)) != 0)
{ {
target->nameLen = strlen(volname); ncp_unlock_server(server);
strcpy(target->entryName, volname); return result;
} }
dir_base = ncp_reply_dword(server, 4);
vol_num = ncp_reply_byte(server, 8);
ncp_unlock_server(server); ncp_unlock_server(server);
if ((result = ncp_obtain_info(server, vol_num, dir_base, NULL,
target)) != 0)
{
return result;
}
DPRINTK("ncp_lookup_volume: attribs = %X\n", target->attributes);
target->nameLen = strlen(volname);
strcpy(target->entryName, volname);
return 0; return 0;
} }

View File

@@ -114,10 +114,16 @@ ncp_write(struct ncp_server *server, const char *file_id,
const char *source, int *bytes_written); const char *source, int *bytes_written);
int int
ncp_do_lookup(struct ncp_server *server, ncp_obtain_info(struct ncp_server *server,
struct nw_info_struct *dir, __u8 vol_num, __u32 dir_base,
char *path, /* may only be one component */ char *path, /* At most 1 component */
struct nw_info_struct *target); struct nw_info_struct *target);
int
ncp_lookup_volume(struct ncp_server *server,
char *volname,
struct nw_info_struct *target);
int int
ncp_modify_file_or_subdir_dos_info(struct ncp_server *server, ncp_modify_file_or_subdir_dos_info(struct ncp_server *server,

View File

@@ -491,7 +491,7 @@ ncp_request(struct ncp_server *server, int function)
if (result != 0) if (result != 0)
{ {
DPRINTK("ncp_completion_code: %d\n", result); DPRINTK("ncp_completion_code: %x\n", result);
} }
return result; return result;
} }

View File

@@ -34,6 +34,9 @@ ncpmount \- mount all volumes of a specified Novell fileserver.
.B -d .B -d
.I dir mode .I dir mode
] [ ] [
.B -V
.I volume
] [
.B -v .B -v
] ]
mount-point mount-point
@@ -188,6 +191,36 @@ can very well choose a file mode that tells that you have. This
certainly cannot override the restrictions imposed by the server. certainly cannot override the restrictions imposed by the server.
.RE .RE
.B -V
.I volume
.RS 3
There are 2 general ways you can mount a NetWare server's disk space:
Either you can mount all volumes under one directory, or you can mount
only a single volume.
When you choose to mount the complete disk space at once, you have the
advantage that only one Linux mount point and only one
NetWare connection is used for all the volumes of this server. Both of
these are limited resources. (Although raising the number of Linux
mount points is significantly cheaper than raising the number of
available NetWare connections ;-))
When you specify to mount a single volume by using the option
.B -V
.I volume,
you have the big advantage that nfsd is able to re-export this mounted
directory. You must invoke
.B nfsd
and
.B mountd
with the option
.I --re-export
to make nfsd re-export ncpfs mounted directories. This uses one Linux
mount point and one NetWare connection per mounted volume. Maybe
sometime in the future I will make it possible to mount all volumes on
different mount points, using only one connection.
.RE
.B -v .B -v
.RS 3 .RS 3
Print ncpfs version number Print ncpfs version number
@@ -212,7 +245,7 @@ Most diagnostics issued by ncpfs are logged by syslogd. Normally
nothing is printed, only error situations are logged there. nothing is printed, only error situations are logged there.
.SH SEE ALSO .SH SEE ALSO
.B syslogd(8), ncpumount(8) .B syslogd(8), ncpumount(8), nfsd(8), mountd(8)
.SH CREDITS .SH CREDITS
ncpfs would not have been possible without lwared, written by Ales ncpfs would not have been possible without lwared, written by Ales

33
man/nwmsg.8 Normal file
View File

@@ -0,0 +1,33 @@
.TH NWMSG 8 02/29/1996 nwmsg nwmsg
.SH NAME
nwmsg \- Deliver NetWare user broadcast messages
.SH SYNOPSIS
.B nwmsg
.I mount-point
.SH DESCRIPTION
.B nwmsg
is called by kerneld when a broadcast message arrives from a NetWare
server.
.B nwmsg
fetches this message via the mount point and delivers it to
the user using the same way write(1) uses.
Please note that
.I kerneld
must run when broadcast messages should be delivered to users.
NetWare servers can send asynchronous broadcast messages to users,
either on explicit request by another user, or when the server is
shutdown. The client workstation is informed about this event by an
IPX packet on a special socket, the message socket.
This can happen at any time, so the user has to be informed about this
event whenever it appears. I chose to use the kerneld feature of the
Linux kernel to call the program nwmsg. For nwmsg, I used the relevant
parts of the
.I write
program, so you can expect the NetWare broadcast
messages to appear where user messages would appear.
.SH SEE ALSO
ncpmount(8), kerneld(8), write(1)

View File

@@ -1,7 +1,7 @@
Begin3 Begin3
Title: ncpfs Title: ncpfs
Version: 0.16 Version: 0.17
Entered-date: 21. February 1996 Entered-date: 29. February 1996
Description: With ncpfs you can mount volumes of your netware Description: With ncpfs you can mount volumes of your netware
server under Linux. You can also print to netware server under Linux. You can also print to netware
print queues and spool netware print queues to the print queues and spool netware print queues to the
@@ -13,7 +13,7 @@ Author: lendecke@namu01.gwdg.de (Volker Lendecke)
Maintained-by: lendecke@namu01.gwdg.de (Volker Lendecke) Maintained-by: lendecke@namu01.gwdg.de (Volker Lendecke)
Primary-site: linux01.gwdg.de:/pub/ncpfs Primary-site: linux01.gwdg.de:/pub/ncpfs
Alternate-site: sunsite.unc.edu:/pub/system/Filesystems/ Alternate-site: sunsite.unc.edu:/pub/system/Filesystems/
~73k ncpfs-0.16.tgz ~81k ncpfs-0.17.tgz
~ 1k ncpfs-0.16.lsm ~ 1k ncpfs-0.17.lsm
Copying-policy: GPL Copying-policy: GPL
End End

View File

@@ -2,9 +2,12 @@
# Makefile for the linux ncp-filesystem routines. # Makefile for the linux ncp-filesystem routines.
# #
UTIL_EXECS = ncpmount ncpumount nprint slist pqlist fsinfo pserver USERUTILS = slist pqlist nwfsinfo pserver
UTILS = $(addprefix $(INTERM_BINDIR)/,$(UTIL_EXECS))
UIDUTILS = ncpmount ncpumount UIDUTILS = ncpmount ncpumount
SBINUTILS = nwmsg
UTIL_EXECS = $(USERUTILS) $(UIDUTILS) $(SBINUTILS)
UTILS = $(addprefix $(INTERM_BINDIR)/,$(UTIL_EXECS))
#CFLAGS = -Wall $(INCLUDES) $(KERNELD) -g -DNCPFS_VERSION=\"$(VERSION)\" #CFLAGS = -Wall $(INCLUDES) $(KERNELD) -g -DNCPFS_VERSION=\"$(VERSION)\"
CFLAGS = -Wall $(INCLUDES) $(KERNELD) -O2 -DNCPFS_VERSION=\"$(VERSION)\" CFLAGS = -Wall $(INCLUDES) $(KERNELD) -O2 -DNCPFS_VERSION=\"$(VERSION)\"
@@ -14,8 +17,11 @@ all: $(UTILS) ncptest
install: all install: all
for i in $(UTIL_EXECS); \ for i in $(UTIL_EXECS); \
do install --strip $(INTERM_BINDIR)/$$i -m 755 $(BINDIR); done do install $(INTERM_BINDIR)/$$i -m 755 $(BINDIR); done
for i in $(UIDUTILS); do chmod 4755 $(BINDIR)/$$i; done for i in $(UIDUTILS); \
do install $(INTERM_BINDIR)/$$i -m 4755 $(BINDIR); done
for i in $(SBINUTILS); \
do install $(INTERM_BINDIR)/$$i -m 755 $(SBINDIR); done
$(UTILS): $(addsuffix .o,$(UTIL_EXECS)) ncplib.o $(UTILS): $(addsuffix .o,$(UTIL_EXECS)) ncplib.o
$(CC) -o $@ $(addsuffix .o,$(notdir $@)) ncplib.o $(CC) -o $@ $(addsuffix .o,$(notdir $@)) ncplib.o

View File

@@ -2742,6 +2742,36 @@ ncp_write(struct ncp_conn *conn, const char *file_id,
return already_written; return already_written;
} }
int
ncp_copy_file(struct ncp_conn *conn,
const char source_file[6],
const char target_file[6],
__u32 source_offset,
__u32 target_offset,
__u32 count,
__u32 *copied_count)
{
int result;
ncp_init_request(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);
if ((result = ncp_request(conn, 74)) != 0)
{
ncp_unlock_conn(conn);
return result;
}
*copied_count = ncp_reply_dword(conn, 0);
return 0;
}
int int
ncp_get_broadcast_message(struct ncp_conn *conn, char message[256]) ncp_get_broadcast_message(struct ncp_conn *conn, char message[256])
{ {

View File

@@ -257,6 +257,15 @@ int
ncp_write(struct ncp_conn *conn, const char *file_id, ncp_write(struct ncp_conn *conn, const char *file_id,
off_t offset, size_t count, const char *source); off_t offset, size_t count, const char *source);
int
ncp_copy_file(struct ncp_conn *conn,
const char source_file[6],
const char target_file[6],
__u32 source_offset,
__u32 target_offset,
__u32 count,
__u32 *copied_count);
int int
ncp_do_lookup(struct ncp_conn *conn, ncp_do_lookup(struct ncp_conn *conn,
struct nw_info_struct *dir, struct nw_info_struct *dir,

View File

@@ -195,7 +195,7 @@ main(int argc, char *argv[])
upcase_password = 1; upcase_password = 1;
while ((opt = getopt (argc, argv, "CS:U:c:u:g:f:d:P:nhv")) != EOF) while ((opt = getopt (argc, argv, "CS:U:c:u:g:f:d:P:nhvV:")) != EOF)
{ {
switch (opt) switch (opt)
{ {
@@ -285,6 +285,14 @@ main(int argc, char *argv[])
} }
password = optarg; password = optarg;
break; break;
case 'V':
if (strlen(optarg) >= sizeof(data.mounted_vol))
{
printf("Volume too long: %s\n", optarg);
exit(1);
}
strcpy(data.mounted_vol, optarg);
break;
case 'n': case 'n':
password = ""; password = "";
break; break;
@@ -346,6 +354,7 @@ main(int argc, char *argv[])
data.version = NCP_MOUNT_VERSION; data.version = NCP_MOUNT_VERSION;
data.mounted_uid = conn_uid; data.mounted_uid = conn_uid;
memcpy(data.server_name, spec->server, sizeof(data.server_name));
if (data.dir_mode == 0) if (data.dir_mode == 0)
{ {
@@ -466,7 +475,8 @@ main(int argc, char *argv[])
} }
if ( (ncp_open_mount(&conn, mount_point) != 0) if ( (ncp_open_mount(&conn, mount_point) != 0)
|| (ncp_login_user(&conn, spec->user, spec->password) != 0)) || (ncp_login_user(&conn, spec->user, spec->password) != 0)
|| (ioctl(conn.mount_fid, NCP_IOC_CONN_LOGGED_IN, NULL) != 0))
{ {
fprintf(stderr, "%s: login failed\n", strerror(errno)); fprintf(stderr, "%s: login failed\n", strerror(errno));
ncp_close(&conn); ncp_close(&conn);

View File

@@ -178,20 +178,3 @@ main(int argc, char *argv[])
return 0; return 0;
} }
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-indent-level: 8
* c-brace-imaginary-offset: 0
* c-brace-offset: -8
* c-argdecl-indent: 8
* c-label-offset: -8
* c-continued-statement-offset: 8
* c-continued-brace-offset: 0
* End:
*/

View File

@@ -1,5 +1,5 @@
/* /*
* nwprint.c * nprint.c
* *
* Send data to a NetWare print queue. * Send data to a NetWare print queue.
* *

View File

@@ -1,5 +1,5 @@
/* /*
* fsinfo.c * nwfsinfo.c
* *
* Print the info strings of a server, maybe sometime more. * Print the info strings of a server, maybe sometime more.
* *

219
util/nwmsg.c Normal file
View File

@@ -0,0 +1,219 @@
/*
* nwmsg.c
*
* Fetch NetWare broadcast messages and write to the user
*
* Copyright (C) 1996 by Volker Lendecke
*
*/
#include <pwd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <unistd.h>
#include <syslog.h>
#include <signal.h>
#include <paths.h>
#include <utmp.h>
#include <mntent.h>
#include "ncplib.h"
static int search_utmp(char *user, char *tty);
static char *progname;
void
main(int argc, char *argv[])
{
struct ncp_conn conn;
char message[256];
struct ncp_fs_info info;
struct passwd *pwd;
char tty[256];
char tty_path[256];
FILE *tty_file;
FILE *mtab;
struct mntent *mnt;
progname = argv[0];
openlog("nwmsg", LOG_PID, LOG_LPR);
if (argc != 2)
{
fprintf(stderr, "usage: %s mount-point\n",
progname);
exit(1);
}
if (ncp_open_mount(&conn, argv[1]) != 0)
{
fprintf(stderr, "%s: could not open connection %s\n",
progname, argv[1]);
exit(1);
}
if (ncp_get_broadcast_message(&conn, message) != 0)
{
fprintf(stderr, "%s: could not get broadcast message\n",
progname);
ncp_close(&conn);
exit(1);
}
if (strlen(message) == 0)
{
syslog(LOG_DEBUG, "no message");
exit(0);
}
#if 0
syslog(LOG_DEBUG, "message: %s", message);
#endif
info.version = NCP_GET_FS_INFO_VERSION;
if (ioctl(conn.mount_fid, NCP_IOC_GET_FS_INFO, &info) < 0)
{
fprintf(stderr, "%s: could not ioctl on connection: %s\n",
progname, strerror(errno));
ncp_close(&conn);
exit(1);
}
ncp_close(&conn);
if ((pwd = getpwuid(info.mounted_uid)) == NULL)
{
fprintf(stderr, "%s: user %d not known\n",
progname, info.mounted_uid);
exit(1);
}
if ((mtab = fopen(MOUNTED, "r")) == NULL)
{
fprintf(stderr, "%s: can't open %s\n",
progname, MOUNTED);
exit(1);
}
while ((mnt = getmntent(mtab)) != NULL)
{
if (strcmp(mnt->mnt_dir, conn.mount_point) == 0)
{
break;
}
}
if (mnt == NULL)
{
syslog(LOG_DEBUG, "cannot find mtab entry\n");
}
if (search_utmp(pwd->pw_name, tty) != 0)
{
exit(1);
}
sprintf(tty_path, "/dev/%s", tty);
if ((tty_file = fopen(tty_path, "w")) == NULL)
{
fprintf(stderr, "%s: cannot open %s: %s\n",
progname, tty_path, strerror(errno));
exit(1);
}
fprintf(tty_file, "\r\n\007\007\007Message from NetWare Server: %s\n",
mnt->mnt_fsname);
fprintf(tty_file, "%s\n", message);
fclose(tty_file);
fclose(mtab);
return;
}
/* The following routines have been taken from util-linux-2.5's write.c */
/*
* term_chk - check that a terminal exists, and get the message bit
* and the access time
*/
static int
term_chk(char *tty, int *msgsokP, time_t *atimeP, int *showerror)
{
struct stat s;
char path[MAXPATHLEN];
(void)sprintf(path, "/dev/%s", tty);
if (stat(path, &s) < 0) {
if (showerror)
(void)fprintf(stderr,
"write: %s: %s\n", path, strerror(errno));
return(1);
}
*msgsokP = (s.st_mode & (S_IWRITE >> 3)) != 0; /* group write bit */
*atimeP = s.st_atime;
return(0);
}
/*
* search_utmp - search utmp for the "best" terminal to write to
*
* Ignores terminals with messages disabled, and of the rest, returns
* the one with the most recent access time. Returns as value the number
* of the user's terminals with messages enabled, or -1 if the user is
* not logged in at all.
*
* Special case for writing to yourself - ignore the terminal you're
* writing from, unless that's the only terminal with messages enabled.
*/
static int
search_utmp(char *user, char *tty)
{
struct utmp u;
time_t bestatime, atime;
int ufd, nloggedttys, nttys, msgsok, user_is_me;
char atty[sizeof(u.ut_line) + 1];
if ((ufd = open(_PATH_UTMP, O_RDONLY)) < 0) {
perror("utmp");
return -1;
}
nloggedttys = nttys = 0;
bestatime = 0;
user_is_me = 0;
while (read(ufd, (char *) &u, sizeof(u)) == sizeof(u))
if (strncmp(user, u.ut_name, sizeof(u.ut_name)) == 0) {
++nloggedttys;
(void)strncpy(atty, u.ut_line, sizeof(u.ut_line));
atty[sizeof(u.ut_line)] = '\0';
if (term_chk(atty, &msgsok, &atime, 0))
continue; /* bad term? skip */
if (!msgsok)
continue; /* skip ttys with msgs off */
if (u.ut_type != USER_PROCESS)
continue; /* it's not a valid entry */
++nttys;
if (atime > bestatime) {
bestatime = atime;
(void)strcpy(tty, atty);
}
}
(void)close(ufd);
if (nloggedttys == 0) {
(void)fprintf(stderr, "write: %s is not logged in\n", user);
return -1;
}
return 0;
}

View File

@@ -62,7 +62,7 @@ main(int argc, char **argv)
{ {
found = 1; found = 1;
printf("%-52s", q.object_name); printf("%-52s", q.object_name);
printf("%08X\n", q.object_id); printf("%08X\n", (unsigned int)q.object_id);
} }
if ((found == 0) && (isatty(1))) if ((found == 0) && (isatty(1)))

View File

@@ -9,10 +9,12 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <syslog.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/stat.h>
#include <signal.h> #include <signal.h>
#include "ncplib.h" #include "ncplib.h"
@@ -77,26 +79,29 @@ terminate_handler()
term_request=1; term_request=1;
} }
static void /* Daemon_init is taken from Stevens, Adv. Unix programming */
daemonize() static int
daemon_init(void)
{ {
int fd,c; pid_t pid;
if ((c = fork()) > 0) exit(0); if ((pid = fork()) < 0)
if (c < 0) {
{ return -1;
fprintf(stderr, "ipxripd: can't fork: %s\n",strerror(errno)); }
exit(1); else if (pid != 0)
{
exit(0); /* parent vanishes */
} }
/* child process */
setsid();
chdir("/");
umask(0);
close(0); close(0);
close(1); close(1);
close(2); close(2);
if ((fd = open("/dev/tty", O_RDWR)) >= 0) return 0;
{
ioctl(fd, TIOCNOTTY, NULL);
close(fd);
}
} }
int int
@@ -137,7 +142,8 @@ main(int argc, char *argv[])
if (debug == 0) if (debug == 0)
{ {
daemonize(); daemon_init();
openlog("pserver", LOG_PID, LOG_LPR);
} }
if (ncp_initialize_as(&conn, &argc, argv, 1, NCP_BINDERY_PSERVER) != 0) if (ncp_initialize_as(&conn, &argc, argv, 1, NCP_BINDERY_PSERVER) != 0)
@@ -268,13 +274,13 @@ poll_queue(struct nw_queue *q)
if (pipe(fd) < 0) if (pipe(fd) < 0)
{ {
perror("pipe"); syslog(LOG_ERR, "pipe error: %m");
goto fail; goto fail;
} }
if ((pid = fork()) < 0) if ((pid = fork()) < 0)
{ {
perror("fork"); syslog(LOG_ERR, "fork error: %m");
goto fail; goto fail;
} }
@@ -301,7 +307,7 @@ poll_queue(struct nw_queue *q)
if (waitpid(pid, NULL, 0) < 0) if (waitpid(pid, NULL, 0) < 0)
{ {
perror("waitpid"); syslog(LOG_ERR, "waitpid: %m\n");
} }
} }
else else
@@ -314,7 +320,7 @@ poll_queue(struct nw_queue *q)
{ {
if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO)
{ {
perror("dup2"); syslog(LOG_ERR, "dup2 error: %m\n");
close(fd[0]); close(fd[0]);
exit(1); exit(1);
} }
@@ -322,7 +328,7 @@ poll_queue(struct nw_queue *q)
} }
execl("/bin/sh", "sh", "-c", q->command, NULL); execl("/bin/sh", "sh", "-c", q->command, NULL);
perror("exec"); syslog(LOG_ERR, "exec error: %m\n");
close(fd[0]); close(fd[0]);
exit(1); exit(1);
} }