Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1fa124bd7c |
BIN
.downloads/ncpfs-0.17.tgz
Normal file
BIN
.downloads/ncpfs-0.17.tgz
Normal file
Binary file not shown.
20
Changes
20
Changes
@@ -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>,
|
||||||
|
|||||||
11
Makefile
11
Makefile
@@ -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
26
README
@@ -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
35
ipxdump/Makefile
Normal 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
45
ipxdump/README
Normal 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
247
ipxdump/ipxdump.c
Normal 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
345
ipxdump/ipxparse.c
Normal 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
129
ipxdump/ipxutil.c
Normal 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
65
ipxdump/ipxutil.h
Normal 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
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* ncp_fs.h
|
* ncp.h
|
||||||
*
|
*
|
||||||
* Copyright (C) 1995 by Volker Lendecke
|
* Copyright (C) 1995 by Volker Lendecke
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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? */
|
||||||
|
|||||||
@@ -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
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
33
man/nwmsg.8
Normal 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)
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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])
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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:
|
|
||||||
*/
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* nwprint.c
|
* nprint.c
|
||||||
*
|
*
|
||||||
* Send data to a NetWare print queue.
|
* Send data to a NetWare print queue.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -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
219
util/nwmsg.c
Normal 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;
|
||||||
|
}
|
||||||
@@ -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)))
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user