diff --git a/.downloads/ncpfs-0.17.tgz b/.downloads/ncpfs-0.17.tgz new file mode 100644 index 0000000..a06aec5 Binary files /dev/null and b/.downloads/ncpfs-0.17.tgz differ diff --git a/Changes b/Changes index fc712e9..8fbd2d2 100644 --- a/Changes +++ b/Changes @@ -1,6 +1,26 @@ 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. +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 + 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 - Included ipx-1.0, made available by Greg Page , diff --git a/Makefile b/Makefile index 22ef024..f6c8a25 100644 --- a/Makefile +++ b/Makefile @@ -2,10 +2,11 @@ # Makefile for the linux ncp-filesystem routines. # -VERSION = 0.16 +VERSION = 0.17 TOPDIR = $(shell pwd) BINDIR = /usr/local/bin +SBINDIR = /sbin INTERM_BINDIR = $(TOPDIR)/bin 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 # and say 'y' when 'make config' asks you for IPX and ncpfs. # -#SUBDIRS += kernel-1.2/src -#INCLUDES = -I$(TOPDIR)/kernel-1.2 +SUBDIRS += kernel-1.2/src +INCLUDES = -I$(TOPDIR)/kernel-1.2 # If you are using kerneld to autoload ncp support, # 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: for i in $(SUBDIRS); do make -C $$i; done diff --git a/README b/README index c8fc29a..8fd7d96 100644 --- a/README +++ b/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. +Look at the file Changes for others. + 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 directory. -The second limitation is just as annoying as the first: You cannot -re-export a ncp-mounted directory by nfs. It is not possible because -the NFS protocol defines access to files through unique file handles, -which can be mapped to the device and inode numbers in unix NFS -servers. NCP does not have unique numbers per file, you only have the -path name. I implemented a caching scheme for inode numbers, which -gives unique inode numbers for every open file in the system. This is -just sufficient for local use of the files, because you can tell when -an inode number can be discarded. With NFS the situation is -different. You can never know when the client will access the file-id -you offered, so you would have to cache the inode numbers -indefinitely long. I think this should not be done in kernel mode, as -it would require an unlimited amount of RAM. - -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... ;-) +You will not be able to access servers that require packet +signatures. This seems to be one of Novell's bigger secrets :-(. Have fun with ncpfs! diff --git a/ipxdump/Makefile b/ipxdump/Makefile new file mode 100644 index 0000000..b67fab8 --- /dev/null +++ b/ipxdump/Makefile @@ -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)) + diff --git a/ipxdump/README b/ipxdump/README new file mode 100644 index 0000000..f4607e2 --- /dev/null +++ b/ipxdump/README @@ -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 + \ No newline at end of file diff --git a/ipxdump/ipxdump.c b/ipxdump/ipxdump.c new file mode 100644 index 0000000..6d6ff20 --- /dev/null +++ b/ipxdump/ipxdump.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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; + } +} diff --git a/ipxdump/ipxparse.c b/ipxdump/ipxparse.c new file mode 100644 index 0000000..c6023ae --- /dev/null +++ b/ipxdump/ipxparse.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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); +} + diff --git a/ipxdump/ipxutil.c b/ipxdump/ipxutil.c new file mode 100644 index 0000000..7af985d --- /dev/null +++ b/ipxdump/ipxutil.c @@ -0,0 +1,129 @@ +/* + IPX support library - general functions + + Copyright (C) 1994, 1995 Ales Dryak + Copyright (C) 1996, Volker Lendecke + + 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 +#include +#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"; diff --git a/ipxdump/ipxutil.h b/ipxdump/ipxutil.h new file mode 100644 index 0000000..b5588ff --- /dev/null +++ b/ipxdump/ipxutil.h @@ -0,0 +1,65 @@ +/* + + IPX support library + + Copyright (C) 1994, 1995 Ales Dryak + Copyright (C) 1996, Volker Lendecke + + 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 +#include + +#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 diff --git a/kernel-1.2/linux/ncp.h b/kernel-1.2/linux/ncp.h index 895c5ae..ab3f653 100644 --- a/kernel-1.2/linux/ncp.h +++ b/kernel-1.2/linux/ncp.h @@ -1,5 +1,5 @@ /* - * ncp_fs.h + * ncp.h * * Copyright (C) 1995 by Volker Lendecke * diff --git a/kernel-1.2/linux/ncp_fs.h b/kernel-1.2/linux/ncp_fs.h index fb2cd44..5dab842 100644 --- a/kernel-1.2/linux/ncp_fs.h +++ b/kernel-1.2/linux/ncp_fs.h @@ -42,6 +42,7 @@ struct ncp_fs_info { #define NCP_IOC_NCPREQUEST _IOR('n', 1, unsigned char *) #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_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_all_inodes(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); 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_free_dir_cache(void); int ncp_date_dos2unix(__u16 time, __u16 date); diff --git a/kernel-1.2/linux/ncp_fs_i.h b/kernel-1.2/linux/ncp_fs_i.h index a72fb07..c0ab3da 100644 --- a/kernel-1.2/linux/ncp_fs_i.h +++ b/kernel-1.2/linux/ncp_fs_i.h @@ -28,6 +28,7 @@ struct ncp_inode_info { number of references in memory */ struct ncp_inode_info *dir; struct ncp_inode_info *next, *prev; + struct inode *inode; struct nw_file_info finfo; }; diff --git a/kernel-1.2/linux/ncp_fs_sb.h b/kernel-1.2/linux/ncp_fs_sb.h index fc5e955..26e76ac 100644 --- a/kernel-1.2/linux/ncp_fs_sb.h +++ b/kernel-1.2/linux/ncp_fs_sb.h @@ -22,7 +22,6 @@ struct ncp_server { it completely. */ struct file *ncp_filp; /* File pointer to ncp socket */ - struct file *wdog_filp; /* File pointer to wdog socket */ void *data_ready; /* The wdog socket gets a new data_ready callback. We store the @@ -35,7 +34,8 @@ struct ncp_server { u8 completion; /* Status message from server */ 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 */ @@ -56,6 +56,18 @@ struct ncp_server { 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 diff --git a/kernel-1.2/linux/ncp_mount.h b/kernel-1.2/linux/ncp_mount.h index 83007be..cbc58aa 100644 --- a/kernel-1.2/linux/ncp_mount.h +++ b/kernel-1.2/linux/ncp_mount.h @@ -13,7 +13,7 @@ #include #include -#define NCP_MOUNT_VERSION 1 +#define NCP_MOUNT_VERSION 2 #define NCP_USERNAME_LEN (NCP_BINDERY_NAME_LEN) #define NCP_PASSWORD_LEN 20 @@ -26,14 +26,14 @@ struct ncp_mount_data { int version; unsigned int ncp_fd; /* The socket to the ncp port */ unsigned int wdog_fd; /* Watchdog packets come here */ - unsigned int message_fd; /* Not used yet, maybe for messages */ + unsigned int message_fd; /* Message notifications come here */ uid_t mounted_uid; /* Who may umount() this filesystem? */ 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 password[NCP_PASSWORD_LEN+1]; + unsigned char mount_point[PATH_MAX+1]; + unsigned char mounted_vol[NCP_VOLNAME_LEN+1]; unsigned int time_out; /* How long should I wait after sending a NCP request? */ diff --git a/kernel-1.2/src/dir.c b/kernel-1.2/src/dir.c index 5747571..46ae470 100644 --- a/kernel-1.2/src/dir.c +++ b/kernel-1.2/src/dir.c @@ -47,7 +47,7 @@ static struct inode * ncp_iget(struct inode *dir, struct nw_file_info *finfo); static struct ncp_inode_info * -ncp_find_inode(struct inode *dir, const char *name); +ncp_find_dir_inode(struct inode *dir, const char *name); static int ncp_lookup(struct inode *dir, const char *__name, @@ -102,7 +102,7 @@ static struct file_operations ncp_dir_operations = { NULL, /* write - bad */ ncp_readdir, /* readdir */ NULL, /* select - default */ - ncp_ioctl, /* ioctl - default */ + ncp_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* no special open 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 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 directory cache by the inode number. */ +static int c_dev = 0; static unsigned long c_ino = 0; static int c_size; static int c_seen_eof; @@ -156,7 +209,7 @@ ncp_readdir(struct inode *inode, struct file *filp, int index = 0; struct ncp_dirent *entry = NULL; struct ncp_server *server = NCP_SERVER(inode); - struct ncp_inode_info *dir = (struct ncp_inode_info *)(inode->i_ino); + struct ncp_inode_info *dir = NCP_INOP(inode); int filldir(struct dirent *dirent, const char *name, int len, @@ -170,9 +223,9 @@ ncp_readdir(struct inode *inode, struct file *filp, return 1; } - DDPRINTK("ncp_readdir: filp->f_pos = %d\n", (int)filp->f_pos); - DDPRINTK("ncp_readdir: inode->i_ino = %ld, c_ino = %ld\n", - inode->i_ino, c_ino); + DPRINTK("ncp_readdir: filp->f_pos = %d\n", (int)filp->f_pos); + DPRINTK("ncp_readdir: inode->i_ino = %ld, c_ino = %ld\n", + inode->i_ino, c_ino); if (!inode || !S_ISDIR(inode->i_mode)) { @@ -180,6 +233,11 @@ ncp_readdir(struct inode *inode, struct file *filp, return -EBADF; } + if (!ncp_conn_valid(server)) + { + return -EIO; + } + if (c_entry == NULL) { 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) { - ncp_invalid_dir_cache(inode->i_ino); - if (filldir(dirent,".",1, filp->f_pos, (int)dir) < 0) + ncp_invalid_dir_cache(inode); + if (filldir(dirent,".",1, filp->f_pos, + ncp_info_ino(server, dir)) < 0) { return 0; } @@ -204,7 +263,8 @@ ncp_readdir(struct inode *inode, struct file *filp, 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; } @@ -212,7 +272,7 @@ ncp_readdir(struct inode *inode, struct file *filp, 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++) { @@ -234,7 +294,7 @@ ncp_readdir(struct inode *inode, struct file *filp, { 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, NCP_READDIR_CACHE_SIZE); @@ -251,6 +311,7 @@ ncp_readdir(struct inode *inode, struct file *filp, if (result < 0) { + c_dev = 0; c_ino = 0; return result; } @@ -258,6 +319,7 @@ ncp_readdir(struct inode *inode, struct file *filp, if (result > 0) { c_seen_eof = (result < NCP_READDIR_CACHE_SIZE); + c_dev = inode->i_dev; c_ino = inode->i_ino; c_size = result; entry = c_entry; @@ -282,24 +344,35 @@ ncp_readdir(struct inode *inode, struct file *filp, /* We found it. For getwd(), we have to return the correct inode in d_ino if the inode is currently in use. Otherwise the inode number does not - matter. (You can argue a lot about this..) */ + matter. (You can argue a lot about this..) */ - struct ncp_inode_info *ino_info; - ino_info = ncp_find_inode(inode, entry->i.entryName); + ino_t ino; - /* Some programs seem to be confused about a zero - inode number, so we set it to one. Thanks to - Gordon Chaffee for this one. */ - if (ino_info == NULL) + if (ncp_single_volume(server)) { - 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); - DDPRINTK("ncp_readdir: entry->f_pos = %ld\n", entry->f_pos); + /* Some programs seem to be confused about a + * zero inode number, so we set it to one. + * Thanks to Gordon Chaffee for this one. */ + if (ino_info == NULL) + { + ino_info = (struct ncp_inode_info *) 1; + } + 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, - entry->f_pos, (ino_t)ino_info) < 0) + entry->f_pos, ino) < 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", info.volume_name); - if (ncp_do_lookup(server, NULL, - info.volume_name, - &(entry->i)) != 0) + if (ncp_lookup_volume(server, + info.volume_name, + &(entry->i)) != 0) { printk("ncpfs: could not lookup vol " "%s\n", info.volume_name); @@ -438,15 +511,17 @@ ncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos, void ncp_init_dir_cache(void) { + c_dev = 0; c_ino = 0; c_entry = NULL; } 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_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 = 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!"); return NULL; @@ -567,6 +643,7 @@ ncp_init_root(struct ncp_server *server) root->finfo.opened = 0; i->attributes = aDIR; i->dataStreamSize = 1024; + i->DosDirNum = 0; i->volNumber = NCP_NUMBER_OF_VOLUMES+1; /* illegal volnum */ ncp_date_unix2dos(0, &(i->creationTime), &(i->creationDate)); ncp_date_unix2dos(0, &(i->modifyTime), &(i->modifyDate)); @@ -581,6 +658,25 @@ ncp_init_root(struct ncp_server *server) 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 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 filesystem. This has to be fixed. */ 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 nw_info_struct *dir_info = NCP_ISTRUCT(dir); @@ -658,9 +754,14 @@ ncp_lookup(struct inode *dir, const char *__name, int len, return -ENOENT; } - DDPRINTK("ncp_lookup: %s, len %d\n", __name, len); - 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 . */ 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; } - *result = iget(dir->i_sb, (int)parent); + *result = iget(dir->i_sb, ncp_info_ino(server, parent)); iput(dir); if (*result == 0) { @@ -694,7 +795,7 @@ ncp_lookup(struct inode *dir, const char *__name, int len, memcpy(name, __name, len); name[len] = 0; - result_info = ncp_find_inode(dir, name); + result_info = ncp_find_dir_inode(dir, name); 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 inode number */ - *result = iget(dir->i_sb, (int)result_info); + *result = iget(dir->i_sb, ncp_info_ino(server, result_info)); iput(dir); if (*result == NULL) @@ -722,7 +823,7 @@ ncp_lookup(struct inode *dir, const char *__name, int len, 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 i; @@ -747,15 +848,24 @@ ncp_lookup(struct inode *dir, const char *__name, int len, if (found_in_cache == 0) { + int res; str_upper(name); DDPRINTK("ncp_lookup: do_lookup on %s/%s\n", NCP_ISTRUCT(dir)->entryName, name); - if (ncp_do_lookup(server, - dir->i_ino == (int)&(NCP_SERVER(dir)->root) - ? NULL : NCP_ISTRUCT(dir), - name, &(finfo.i)) != 0) + if (ncp_is_server_root(dir)) + { + res = ncp_lookup_volume(server, name, &(finfo.i)); + } + else + { + res = ncp_obtain_info(server, + NCP_ISTRUCT(dir)->volNumber, + NCP_ISTRUCT(dir)->DosDirNum, + name, &(finfo.i)); + } + if (res != 0) { iput(dir); return -ENOENT; @@ -790,6 +900,11 @@ ncp_create(struct inode *dir, const char *name, int len, int mode, iput(dir); return -ENOENT; } + if (!ncp_conn_valid(NCP_SERVER(dir))) + { + iput(dir); + return -EIO; + } strncpy(_name, name, len); _name[len] = '\0'; @@ -806,7 +921,7 @@ ncp_create(struct inode *dir, const char *name, int len, int mode, return -EACCES; } - ncp_invalid_dir_cache(dir->i_ino); + ncp_invalid_dir_cache(dir); str_lower(finfo.i.entryName); finfo.access = O_RDWR; @@ -847,6 +962,11 @@ ncp_mkdir(struct inode *dir, const char *name, int len, int mode) iput(dir); return -ENOENT; } + if (!ncp_conn_valid(NCP_SERVER(dir))) + { + iput(dir); + return -EIO; + } if (ncp_open_create_file_or_subdir(NCP_SERVER(dir), NCP_ISTRUCT(dir), _name, @@ -858,7 +978,7 @@ ncp_mkdir(struct inode *dir, const char *name, int len, int mode) else { error = 0; - ncp_invalid_dir_cache(dir->i_ino); + ncp_invalid_dir_cache(dir); } iput(dir); @@ -877,8 +997,14 @@ ncp_rmdir(struct inode *dir, const char *name, int len) iput(dir); 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; } else @@ -892,7 +1018,7 @@ ncp_rmdir(struct inode *dir, const char *name, int len) NCP_ISTRUCT(dir), _name)) == 0) { - ncp_invalid_dir_cache(dir->i_ino); + ncp_invalid_dir_cache(dir); } else { @@ -915,8 +1041,14 @@ ncp_unlink(struct inode *dir, const char *name, int len) iput(dir); 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; } else @@ -929,7 +1061,7 @@ ncp_unlink(struct inode *dir, const char *name, int len) NCP_ISTRUCT(dir), _name)) == 0) { - ncp_invalid_dir_cache(dir->i_ino); + ncp_invalid_dir_cache(dir); } else { @@ -955,6 +1087,12 @@ ncp_rename(struct inode *old_dir, const char *old_name, int old_len, goto finished; } + if (!ncp_conn_valid(NCP_SERVER(old_dir))) + { + res = -EIO; + goto finished; + } + if (!new_dir || !S_ISDIR(new_dir->i_mode)) { 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; } - if ( (ncp_find_inode(old_dir, old_name) != NULL) - || (ncp_find_inode(new_dir, new_name) != NULL)) + if ( (ncp_find_dir_inode(old_dir, old_name) != NULL) + || (ncp_find_dir_inode(new_dir, new_name) != NULL)) { res = -EBUSY; goto finished; @@ -983,8 +1121,8 @@ ncp_rename(struct inode *old_dir, const char *old_name, int old_len, if (res == 0) { - ncp_invalid_dir_cache(old_dir->i_ino); - ncp_invalid_dir_cache(new_dir->i_ino); + ncp_invalid_dir_cache(old_dir); + ncp_invalid_dir_cache(new_dir); } else { diff --git a/kernel-1.2/src/file.c b/kernel-1.2/src/file.c index 0770b0d..6032c07 100644 --- a/kernel-1.2/src/file.c +++ b/kernel-1.2/src/file.c @@ -99,6 +99,10 @@ ncp_file_read(struct inode *inode, struct file *file, char *buf, int count) DPRINTK("ncp_file_read: inode = NULL\n"); return -EINVAL; } + if (!ncp_conn_valid(NCP_SERVER(inode))) + { + return -EIO; + } 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"); return -EINVAL; } + if (!ncp_conn_valid(NCP_SERVER(inode))) + { + return -EIO; + } 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) { inode->i_size = pos; + ncp_invalid_dir_cache(NCP_INOP(inode)->dir->inode); } DPRINTK("ncp_file_write: exit %s\n", NCP_ISTRUCT(inode)->entryName); diff --git a/kernel-1.2/src/inode.c b/kernel-1.2/src/inode.c index f85fe62..0add779 100644 --- a/kernel-1.2/src/inode.c +++ b/kernel-1.2/src/inode.c @@ -61,50 +61,25 @@ ncp_read_inode(struct inode *inode) inode->i_ino. Just to make sure everything went well, we check it's there. */ - struct ncp_inode_info *inode_info - = (struct ncp_inode_info *)(inode->i_ino); + struct ncp_inode_info *inode_info = ncp_find_inode(inode); -#if 1 - struct ncp_inode_info *root = &(NCP_SERVER(inode)->root); - struct ncp_inode_info *check_info = root; - - do + if (inode_info == NULL) { - if (inode_info == check_info) - { - if (check_info->state == NCP_INODE_LOOKED_UP) - { - 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; + } - /* 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; NCP_INOP(inode) = inode_info; + inode_info->inode = inode; if (NCP_ISTRUCT(inode)->attributes & aDIR) { 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 ??? */ inode->i_size = 512; } @@ -176,7 +151,7 @@ ncp_put_inode(struct inode *inode) { DDPRINTK("ncp_put_inode: put directory %ld\n", inode->i_ino); - ncp_invalid_dir_cache(inode->i_ino); + ncp_invalid_dir_cache(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", (data->version < NCP_MOUNT_VERSION) ? "older" : "newer"); + sb->s_dev = 0; + return NULL; } 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->packet = NULL; server->buffer_size = 0; + server->conn_status = 0; server->m = *data; 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)); - 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; 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; struct nw_modify_dos_info info; + if (!ncp_conn_valid(NCP_SERVER(inode))) + { + return -EIO; + } + if ((result = inode_change_ok(inode, attr)) < 0) return result; @@ -480,7 +463,7 @@ ncp_notify_change(struct inode *inode, struct iattr *attr) result = 0; } - ncp_invalid_dir_cache((unsigned long)(NCP_INOP(inode)->dir)); + ncp_invalid_dir_cache(NCP_INOP(inode)->dir->inode); return result; } diff --git a/kernel-1.2/src/ioctl.c b/kernel-1.2/src/ioctl.c index 3b85ea9..beb6951 100644 --- a/kernel-1.2/src/ioctl.c +++ b/kernel-1.2/src/ioctl.c @@ -79,6 +79,16 @@ ncp_ioctl (struct inode * inode, struct file * filp, 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: if ( (permission(inode, MAY_WRITE) != 0) diff --git a/kernel-1.2/src/mmap.c b/kernel-1.2/src/mmap.c index f585f00..344f6eb 100644 --- a/kernel-1.2/src/mmap.c +++ b/kernel-1.2/src/mmap.c @@ -135,6 +135,11 @@ ncp_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma) { DPRINTK("ncp_mmap: called\n"); + if (!ncp_conn_valid(NCP_SERVER(inode))) + { + return -EIO; + } + /* only PAGE_COW or read-only supported now */ if (vma->vm_flags & VM_SHARED) return -EINVAL; diff --git a/kernel-1.2/src/ncplib_kernel.c b/kernel-1.2/src/ncplib_kernel.c index bcbd667..09e0ef9 100644 --- a/kernel-1.2/src/ncplib_kernel.c +++ b/kernel-1.2/src/ncplib_kernel.c @@ -266,56 +266,19 @@ ncp_extract_file_info(void *structure, struct nw_info_struct *target) target->entryName[*name_len] = '\0'; return; } - int -ncp_do_lookup(struct ncp_server *server, - struct nw_info_struct *dir, - char *path, /* may only be one component */ - struct nw_info_struct *target) +ncp_obtain_info(struct ncp_server *server, + __u8 vol_num, __u32 dir_base, + char *path, /* At most 1 component */ + struct nw_info_struct *target) { - __u8 vol_num; - __u32 dir_base; int result; - char *volname = NULL; if (target == NULL) { return -EINVAL; } - - if (dir == NULL) - { - - DDPRINTK("ncp_do_lookup: looking up vol %s\n", path); - - /* Access a volume's root directory */ - ncp_init_request(server); - ncp_add_byte(server, 22); /* subfunction */ - ncp_add_byte(server, 0); /* dos name space */ - ncp_add_byte(server, 0); /* reserved */ - ncp_add_byte(server, 0); /* reserved */ - ncp_add_byte(server, 0); /* reserved */ - ncp_add_handle_path(server, 0, 0, 0, /* no handle */ - path); - - if ((result = ncp_request(server, 87)) != 0) - { - ncp_unlock_server(server); - return result; - } - - dir_base = ncp_reply_dword(server, 4); - vol_num = ncp_reply_byte (server, 8); - ncp_unlock_server(server); - volname = path; - path = NULL; - } - else - { - vol_num = dir->volNumber; - dir_base = dir->DosDirNum; - } ncp_init_request(server); ncp_add_byte(server, 6); /* subfunction */ @@ -323,8 +286,7 @@ ncp_do_lookup(struct ncp_server *server, ncp_add_byte(server, 0); /* dos name space as dest */ ncp_add_word(server, 0xff); /* get all */ ncp_add_dword(server, RIM_ALL); - ncp_add_handle_path(server, vol_num, dir_base, 1, - path); + ncp_add_handle_path(server, vol_num, dir_base, 1, path); 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_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); - strcpy(target->entryName, volname); + ncp_unlock_server(server); + return result; } + dir_base = ncp_reply_dword(server, 4); + vol_num = ncp_reply_byte(server, 8); 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; } diff --git a/kernel-1.2/src/ncplib_kernel.h b/kernel-1.2/src/ncplib_kernel.h index 3278cdf..8d46aa6 100644 --- a/kernel-1.2/src/ncplib_kernel.h +++ b/kernel-1.2/src/ncplib_kernel.h @@ -114,10 +114,16 @@ ncp_write(struct ncp_server *server, const char *file_id, const char *source, int *bytes_written); int -ncp_do_lookup(struct ncp_server *server, - struct nw_info_struct *dir, - char *path, /* may only be one component */ - struct nw_info_struct *target); +ncp_obtain_info(struct ncp_server *server, + __u8 vol_num, __u32 dir_base, + char *path, /* At most 1 component */ + struct nw_info_struct *target); + +int +ncp_lookup_volume(struct ncp_server *server, + char *volname, + struct nw_info_struct *target); + int ncp_modify_file_or_subdir_dos_info(struct ncp_server *server, diff --git a/kernel-1.2/src/sock.c b/kernel-1.2/src/sock.c index cc519a1..bb48a3d 100644 --- a/kernel-1.2/src/sock.c +++ b/kernel-1.2/src/sock.c @@ -491,7 +491,7 @@ ncp_request(struct ncp_server *server, int function) if (result != 0) { - DPRINTK("ncp_completion_code: %d\n", result); + DPRINTK("ncp_completion_code: %x\n", result); } return result; } diff --git a/man/ncpmount.8 b/man/ncpmount.8 index e15b1ef..6c68d2c 100644 --- a/man/ncpmount.8 +++ b/man/ncpmount.8 @@ -34,6 +34,9 @@ ncpmount \- mount all volumes of a specified Novell fileserver. .B -d .I dir mode ] [ +.B -V +.I volume +] [ .B -v ] 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. .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 .RS 3 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. .SH SEE ALSO -.B syslogd(8), ncpumount(8) +.B syslogd(8), ncpumount(8), nfsd(8), mountd(8) .SH CREDITS ncpfs would not have been possible without lwared, written by Ales diff --git a/man/nwmsg.8 b/man/nwmsg.8 new file mode 100644 index 0000000..a4d538b --- /dev/null +++ b/man/nwmsg.8 @@ -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) \ No newline at end of file diff --git a/ncpfs-0.16.lsm b/ncpfs-0.17.lsm similarity index 83% rename from ncpfs-0.16.lsm rename to ncpfs-0.17.lsm index 1476842..9928716 100644 --- a/ncpfs-0.16.lsm +++ b/ncpfs-0.17.lsm @@ -1,7 +1,7 @@ Begin3 Title: ncpfs -Version: 0.16 -Entered-date: 21. February 1996 +Version: 0.17 +Entered-date: 29. February 1996 Description: With ncpfs you can mount volumes of your netware server under Linux. You can also print to netware print queues and spool netware print queues to the @@ -13,7 +13,7 @@ Author: lendecke@namu01.gwdg.de (Volker Lendecke) Maintained-by: lendecke@namu01.gwdg.de (Volker Lendecke) Primary-site: linux01.gwdg.de:/pub/ncpfs Alternate-site: sunsite.unc.edu:/pub/system/Filesystems/ - ~73k ncpfs-0.16.tgz - ~ 1k ncpfs-0.16.lsm + ~81k ncpfs-0.17.tgz + ~ 1k ncpfs-0.17.lsm Copying-policy: GPL End diff --git a/util/Makefile b/util/Makefile index bb42bbb..6434b38 100644 --- a/util/Makefile +++ b/util/Makefile @@ -2,9 +2,12 @@ # Makefile for the linux ncp-filesystem routines. # -UTIL_EXECS = ncpmount ncpumount nprint slist pqlist fsinfo pserver -UTILS = $(addprefix $(INTERM_BINDIR)/,$(UTIL_EXECS)) +USERUTILS = slist pqlist nwfsinfo pserver 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) -O2 -DNCPFS_VERSION=\"$(VERSION)\" @@ -14,8 +17,11 @@ all: $(UTILS) ncptest install: all for i in $(UTIL_EXECS); \ - do install --strip $(INTERM_BINDIR)/$$i -m 755 $(BINDIR); done - for i in $(UIDUTILS); do chmod 4755 $(BINDIR)/$$i; done + do install $(INTERM_BINDIR)/$$i -m 755 $(BINDIR); 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 $(CC) -o $@ $(addsuffix .o,$(notdir $@)) ncplib.o diff --git a/util/ncplib.c b/util/ncplib.c index 949d1af..b5124a1 100644 --- a/util/ncplib.c +++ b/util/ncplib.c @@ -2742,6 +2742,36 @@ ncp_write(struct ncp_conn *conn, const char *file_id, 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 ncp_get_broadcast_message(struct ncp_conn *conn, char message[256]) { diff --git a/util/ncplib.h b/util/ncplib.h index 942e4f1..1352706 100644 --- a/util/ncplib.h +++ b/util/ncplib.h @@ -257,6 +257,15 @@ int ncp_write(struct ncp_conn *conn, const char *file_id, 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 ncp_do_lookup(struct ncp_conn *conn, struct nw_info_struct *dir, diff --git a/util/ncpmount.c b/util/ncpmount.c index ba275c9..d7efae9 100644 --- a/util/ncpmount.c +++ b/util/ncpmount.c @@ -195,7 +195,7 @@ main(int argc, char *argv[]) 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) { @@ -285,6 +285,14 @@ main(int argc, char *argv[]) } password = optarg; 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': password = ""; break; @@ -346,6 +354,7 @@ main(int argc, char *argv[]) data.version = NCP_MOUNT_VERSION; data.mounted_uid = conn_uid; + memcpy(data.server_name, spec->server, sizeof(data.server_name)); if (data.dir_mode == 0) { @@ -466,7 +475,8 @@ main(int argc, char *argv[]) } 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)); ncp_close(&conn); diff --git a/util/ncpumount.c b/util/ncpumount.c index 5b76bd4..2c72bf5 100644 --- a/util/ncpumount.c +++ b/util/ncpumount.c @@ -178,20 +178,3 @@ main(int argc, char *argv[]) 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: - */ diff --git a/util/nprint.c b/util/nprint.c index f2e41c7..e476be3 100644 --- a/util/nprint.c +++ b/util/nprint.c @@ -1,5 +1,5 @@ /* - * nwprint.c + * nprint.c * * Send data to a NetWare print queue. * diff --git a/util/fsinfo.c b/util/nwfsinfo.c similarity index 98% rename from util/fsinfo.c rename to util/nwfsinfo.c index 3b86fcb..7aec919 100644 --- a/util/fsinfo.c +++ b/util/nwfsinfo.c @@ -1,5 +1,5 @@ /* - * fsinfo.c + * nwfsinfo.c * * Print the info strings of a server, maybe sometime more. * diff --git a/util/nwmsg.c b/util/nwmsg.c new file mode 100644 index 0000000..490d09a --- /dev/null +++ b/util/nwmsg.c @@ -0,0 +1,219 @@ +/* + * nwmsg.c + * + * Fetch NetWare broadcast messages and write to the user + * + * Copyright (C) 1996 by Volker Lendecke + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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; +} diff --git a/util/pqlist.c b/util/pqlist.c index 0449326..325ea03 100644 --- a/util/pqlist.c +++ b/util/pqlist.c @@ -62,7 +62,7 @@ main(int argc, char **argv) { found = 1; printf("%-52s", q.object_name); - printf("%08X\n", q.object_id); + printf("%08X\n", (unsigned int)q.object_id); } if ((found == 0) && (isatty(1))) diff --git a/util/pserver.c b/util/pserver.c index f19b5ad..3a2ac81 100644 --- a/util/pserver.c +++ b/util/pserver.c @@ -9,10 +9,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include "ncplib.h" @@ -77,26 +79,29 @@ terminate_handler() term_request=1; } -static void -daemonize() +/* Daemon_init is taken from Stevens, Adv. Unix programming */ +static int +daemon_init(void) { - int fd,c; - - if ((c = fork()) > 0) exit(0); - if (c < 0) - { - fprintf(stderr, "ipxripd: can't fork: %s\n",strerror(errno)); - exit(1); + pid_t pid; + + if ((pid = fork()) < 0) + { + return -1; + } + else if (pid != 0) + { + exit(0); /* parent vanishes */ } + /* child process */ + setsid(); + chdir("/"); + umask(0); close(0); close(1); close(2); - if ((fd = open("/dev/tty", O_RDWR)) >= 0) - { - ioctl(fd, TIOCNOTTY, NULL); - close(fd); - } + return 0; } int @@ -137,12 +142,13 @@ main(int argc, char *argv[]) if (debug == 0) { - daemonize(); + daemon_init(); + openlog("pserver", LOG_PID, LOG_LPR); } if (ncp_initialize_as(&conn, &argc, argv, 1, NCP_BINDERY_PSERVER) != 0) { - perror("Could not open connection"); + perror("Could not open connection"); return 1; } @@ -268,13 +274,13 @@ poll_queue(struct nw_queue *q) if (pipe(fd) < 0) { - perror("pipe"); + syslog(LOG_ERR, "pipe error: %m"); goto fail; } if ((pid = fork()) < 0) { - perror("fork"); + syslog(LOG_ERR, "fork error: %m"); goto fail; } @@ -301,7 +307,7 @@ poll_queue(struct nw_queue *q) if (waitpid(pid, NULL, 0) < 0) { - perror("waitpid"); + syslog(LOG_ERR, "waitpid: %m\n"); } } else @@ -314,7 +320,7 @@ poll_queue(struct nw_queue *q) { if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) { - perror("dup2"); + syslog(LOG_ERR, "dup2 error: %m\n"); close(fd[0]); exit(1); } @@ -322,7 +328,7 @@ poll_queue(struct nw_queue *q) } execl("/bin/sh", "sh", "-c", q->command, NULL); - perror("exec"); + syslog(LOG_ERR, "exec error: %m\n"); close(fd[0]); exit(1); }