Commit aaf390a1 authored by Linus Torvalds's avatar Linus Torvalds

Merge http://ncpfs.bkbits.net/linux-2.5

into penguin.transmeta.com:/home/penguin/torvalds/repositories/kernel/linux
parents 985dcc74 3034ecfc
......@@ -5,7 +5,7 @@
obj-$(CONFIG_NCP_FS) += ncpfs.o
ncpfs-objs := dir.o file.o inode.o ioctl.o mmap.o ncplib_kernel.o sock.o \
ncpsign_kernel.o
ncpsign_kernel.o getopt.o
ifeq ($(CONFIG_NCPFS_EXTRAS),y)
ncpfs-objs += symlink.o
endif
......
/*
* getopt.c
*/
#include <linux/kernel.h>
#include <linux/string.h>
#include <asm/errno.h>
#include "getopt.h"
/**
* ncp_getopt - option parser
* @caller: name of the caller, for error messages
* @options: the options string
* @opts: an array of &struct option entries controlling parser operations
* @optopt: output; will contain the current option
* @optarg: output; will contain the value (if one exists)
* @flag: output; may be NULL; should point to a long for or'ing flags
* @value: output; may be NULL; will be overwritten with the integer value
* of the current argument.
*
* Helper to parse options on the format used by mount ("a=b,c=d,e,f").
* Returns opts->val if a matching entry in the 'opts' array is found,
* 0 when no more tokens are found, -1 if an error is encountered.
*/
int ncp_getopt(const char *caller, char **options, const struct ncp_option *opts,
char **optopt, char **optarg, unsigned long *value)
{
char *token;
char *val;
do {
if ((token = strsep(options, ",")) == NULL)
return 0;
} while (*token == '\0');
if (optopt)
*optopt = token;
if ((val = strchr (token, '=')) != NULL) {
*val++ = 0;
}
*optarg = val;
for (; opts->name; opts++) {
if (!strcmp(opts->name, token)) {
if (!val) {
if (opts->has_arg & OPT_NOPARAM) {
return opts->val;
}
printk(KERN_INFO "%s: the %s option requires an argument\n",
caller, token);
return -EINVAL;
}
if (opts->has_arg & OPT_INT) {
char* v;
*value = simple_strtoul(val, &v, 0);
if (!*v) {
return opts->val;
}
printk(KERN_INFO "%s: invalid numeric value in %s=%s\n",
caller, token, val);
return -EDOM;
}
if (opts->has_arg & OPT_STRING) {
return opts->val;
}
printk(KERN_INFO "%s: unexpected argument %s to the %s option\n",
caller, val, token);
return -EINVAL;
}
}
printk(KERN_INFO "%s: Unrecognized mount option %s\n", caller, token);
return -EOPNOTSUPP;
}
#ifndef _LINUX_GETOPT_H
#define _LINUX_GETOPT_H
#define OPT_NOPARAM 1
#define OPT_INT 2
#define OPT_STRING 4
struct ncp_option {
const char *name;
unsigned int has_arg;
int val;
};
extern int ncp_getopt(const char *caller, char **options, const struct ncp_option *opts,
char **optopt, char **optarg, unsigned long *value);
#endif /* _LINUX_GETOPT_H */
......@@ -31,7 +31,10 @@
#include <linux/ncp_fs.h>
#include <net/sock.h>
#include "ncplib_kernel.h"
#include "getopt.h"
static void ncp_delete_inode(struct inode *);
static void ncp_put_super(struct super_block *);
......@@ -283,6 +286,103 @@ ncp_delete_inode(struct inode *inode)
clear_inode(inode);
}
static void ncp_stop_tasks(struct ncp_server *server) {
struct sock* sk = server->ncp_sock->sk;
sk->error_report = server->error_report;
sk->data_ready = server->data_ready;
sk->write_space = server->write_space;
del_timer_sync(&server->timeout_tm);
flush_scheduled_tasks();
}
static const struct ncp_option ncp_opts[] = {
{ "uid", OPT_INT, 'u' },
{ "gid", OPT_INT, 'g' },
{ "owner", OPT_INT, 'o' },
{ "mode", OPT_INT, 'm' },
{ "dirmode", OPT_INT, 'd' },
{ "timeout", OPT_INT, 't' },
{ "retry", OPT_INT, 'r' },
{ "flags", OPT_INT, 'f' },
{ "wdogpid", OPT_INT, 'w' },
{ "ncpfd", OPT_INT, 'n' },
{ "infofd", OPT_INT, 'i' }, /* v5 */
{ "version", OPT_INT, 'v' },
{ NULL, 0, 0 } };
static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) {
int optval;
char *optarg;
unsigned long optint;
int version = 0;
data->flags = 0;
data->int_flags = 0;
data->mounted_uid = 0;
data->wdog_pid = -1;
data->ncp_fd = ~0;
data->time_out = 10;
data->retry_count = 20;
data->uid = 0;
data->gid = 0;
data->file_mode = 0600;
data->dir_mode = 0700;
data->info_fd = -1;
data->mounted_vol[0] = 0;
while ((optval = ncp_getopt("ncpfs", &options, ncp_opts, NULL, &optarg, &optint)) != 0) {
if (optval < 0)
return optval;
switch (optval) {
case 'u':
data->uid = optint;
break;
case 'g':
data->gid = optint;
break;
case 'o':
data->mounted_uid = optint;
break;
case 'm':
data->file_mode = optint;
break;
case 'd':
data->dir_mode = optint;
break;
case 't':
data->time_out = optint;
break;
case 'r':
data->retry_count = optint;
break;
case 'f':
data->flags = optint;
break;
case 'w':
data->wdog_pid = optint;
break;
case 'n':
data->ncp_fd = optint;
break;
case 'i':
data->info_fd = optint;
break;
case 'v':
if (optint < NCP_MOUNT_VERSION_V4) {
return -ECHRNG;
}
if (optint > NCP_MOUNT_VERSION_V5) {
return -ECHRNG;
}
version = optint;
break;
}
}
return 0;
}
static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
{
struct ncp_mount_data_kernel data;
......@@ -323,6 +423,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
data.gid = md->gid;
data.file_mode = md->file_mode;
data.dir_mode = md->dir_mode;
data.info_fd = -1;
memcpy(data.mounted_vol, md->mounted_vol,
NCP_VOLNAME_LEN+1);
}
......@@ -342,12 +443,18 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
data.gid = md->gid;
data.file_mode = md->file_mode;
data.dir_mode = md->dir_mode;
data.info_fd = -1;
data.mounted_vol[0] = 0;
}
break;
default:
error = -ECHRNG;
if (*(__u32*)raw_data == cpu_to_be32(0x76657273)) {
error = ncp_parse_options(&data, raw_data);
}
if (error)
goto out;
break;
}
error = -EBADF;
ncp_filp = fget(data.ncp_fd);
......@@ -376,6 +483,28 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
memset(server, 0, sizeof(*server));
server->ncp_filp = ncp_filp;
server->ncp_sock = sock;
if (data.info_fd != -1) {
struct socket *info_sock;
error = -EBADF;
server->info_filp = fget(data.info_fd);
if (!server->info_filp)
goto out_fput;
error = -ENOTSOCK;
sock_inode = server->info_filp->f_dentry->d_inode;
if (!S_ISSOCK(sock_inode->i_mode))
goto out_fput2;
info_sock = SOCKET_I(sock_inode);
if (!info_sock)
goto out_fput2;
error = -EBADFD;
if (info_sock->type != SOCK_STREAM)
goto out_fput2;
server->info_sock = info_sock;
}
/* server->lock = 0; */
init_MUTEX(&server->sem);
server->packet = NULL;
......@@ -413,6 +542,16 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
server->dentry_ttl = 0; /* no caching */
INIT_LIST_HEAD(&server->tx.requests);
init_MUTEX(&server->rcv.creq_sem);
server->tx.creq = NULL;
server->rcv.creq = NULL;
server->data_ready = sock->sk->data_ready;
server->write_space = sock->sk->write_space;
server->error_report = sock->sk->error_report;
sock->sk->user_data = server;
init_timer(&server->timeout_tm);
#undef NCP_PACKET_SIZE
#define NCP_PACKET_SIZE 131072
error = -ENOMEM;
......@@ -421,6 +560,22 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
if (server->packet == NULL)
goto out_nls;
sock->sk->data_ready = ncp_tcp_data_ready;
sock->sk->error_report = ncp_tcp_error_report;
if (sock->type == SOCK_STREAM) {
server->rcv.ptr = (unsigned char*)&server->rcv.buf;
server->rcv.len = 10;
server->rcv.state = 0;
INIT_TQUEUE(&server->rcv.tq, ncp_tcp_rcv_proc, server);
INIT_TQUEUE(&server->tx.tq, ncp_tcp_tx_proc, server);
sock->sk->write_space = ncp_tcp_write_space;
} else {
INIT_TQUEUE(&server->rcv.tq, ncpdgram_rcv_proc, server);
INIT_TQUEUE(&server->timeout_tq, ncpdgram_timeout_proc, server);
server->timeout_tm.data = (unsigned long)server;
server->timeout_tm.function = ncpdgram_timeout_call;
}
ncp_lock_server(server);
error = ncp_connect(server);
ncp_unlock_server(server);
......@@ -495,12 +650,16 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
ncp_disconnect(server);
ncp_unlock_server(server);
out_packet:
ncp_stop_tasks(server);
vfree(server->packet);
out_nls:
#ifdef CONFIG_NCPFS_NLS
unload_nls(server->nls_io);
unload_nls(server->nls_vol);
#endif
out_fput2:
if (server->info_filp)
fput(server->info_filp);
out_fput:
/* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
*
......@@ -522,6 +681,8 @@ static void ncp_put_super(struct super_block *sb)
ncp_disconnect(server);
ncp_unlock_server(server);
ncp_stop_tasks(server);
#ifdef CONFIG_NCPFS_NLS
/* unload the NLS charsets */
if (server->nls_vol)
......@@ -536,6 +697,8 @@ static void ncp_put_super(struct super_block *sb)
}
#endif /* CONFIG_NCPFS_NLS */
if (server->info_filp)
fput(server->info_filp);
fput(server->ncp_filp);
kill_proc(server->m.wdog_pid, SIGTERM, 1);
......
......@@ -424,7 +424,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
if (user.object_name_len) {
newname = ncp_kmalloc(user.object_name_len, GFP_USER);
if (!newname) return -ENOMEM;
if (copy_from_user(newname, user.object_name, sizeof(user))) {
if (copy_from_user(newname, user.object_name, user.object_name_len)) {
ncp_kfree_s(newname, user.object_name_len);
return -EFAULT;
}
......
......@@ -341,6 +341,7 @@ void ncp_extract_file_info(void *structure, struct nw_info_struct *target)
target->nameLen = *name_len;
memcpy(target->entryName, name_len + 1, *name_len);
target->entryName[*name_len] = '\0';
target->volNumber = le32_to_cpu(target->volNumber);
return;
}
......@@ -475,7 +476,7 @@ ncp_get_known_namespace(struct ncp_server *server, __u8 volume)
}
result = NW_NS_DOS;
no_namespaces = ncp_reply_word(server, 0);
no_namespaces = le16_to_cpu(ncp_reply_word(server, 0));
namespace = ncp_reply_data(server, 2);
while (no_namespaces > 0) {
......
......@@ -93,19 +93,35 @@ static void nwsign(char *r_data1, char *r_data2, char *outdata) {
/* Make a signature for the current packet and add it at the end of the */
/* packet. */
void sign_packet(struct ncp_server *server, int *size) {
char data[64];
void __sign_packet(struct ncp_server *server, const char *packet, size_t size, __u32 totalsize, void *sign_buff) {
unsigned char data[64];
memset(data,0,64);
memcpy(data,server->sign_root,8);
PUT_LE32(data+8,(*size));
memcpy(data+12,server->packet+sizeof(struct ncp_request_header)-1,
min_t(unsigned int,(*size)-sizeof(struct ncp_request_header)+1,52));
memcpy(data, server->sign_root, 8);
*(__u32*)(data + 8) = totalsize;
if (size < 52) {
memcpy(data + 12, packet, size);
memset(data + 12 + size, 0, 52 - size);
} else {
memcpy(data + 12, packet, 52);
}
nwsign(server->sign_last, data, server->sign_last);
memcpy(sign_buff, server->sign_last, 8);
}
nwsign(server->sign_last,data,server->sign_last);
int sign_verify_reply(struct ncp_server *server, const char *packet, size_t size, __u32 totalsize, const void *sign_buff) {
unsigned char data[64];
unsigned char hash[16];
memcpy(server->packet+(*size),server->sign_last,8);
(*size)+=8;
memcpy(data, server->sign_root, 8);
*(__u32*)(data + 8) = totalsize;
if (size < 52) {
memcpy(data + 12, packet, size);
memset(data + 12 + size, 0, 52 - size);
} else {
memcpy(data + 12, packet, 52);
}
nwsign(server->sign_last, data, hash);
return memcmp(sign_buff, hash, 8);
}
#endif /* CONFIG_NCPFS_PACKET_SIGNING */
......
......@@ -10,6 +10,19 @@
#include <linux/ncp_fs.h>
void sign_packet(struct ncp_server *server, int *size);
#ifdef CONFIG_NCPFS_PACKET_SIGNING
void __sign_packet(struct ncp_server *server, const char *data, size_t size, __u32 totalsize, void *sign_buff);
int sign_verify_reply(struct ncp_server *server, const char *data, size_t size, __u32 totalsize, const void *sign_buff);
#endif
static inline size_t sign_packet(struct ncp_server *server, const char *data, size_t size, __u32 totalsize, void *sign_buff) {
#ifdef CONFIG_NCPFS_PACKET_SIGNING
if (server->sign_active) {
__sign_packet(server, data, size, totalsize, sign_buff);
return 8;
}
#endif
return 0;
}
#endif
This diff is collapsed.
......@@ -30,6 +30,7 @@ struct ncp_request_header {
};
#define NCP_REPLY (0x3333)
#define NCP_WATCHDOG (0x3E3E)
#define NCP_POSITIVE_ACK (0x9999)
struct ncp_reply_header {
......
......@@ -13,6 +13,8 @@
#ifdef __KERNEL__
#include <linux/tqueue.h>
#define NCP_DEFAULT_OPTIONS 0 /* 2 for packet signatures */
struct ncp_server {
......@@ -24,6 +26,9 @@ struct ncp_server {
__u8 name_space[NCP_NUMBER_OF_VOLUMES + 2];
struct file *ncp_filp; /* File pointer to ncp socket */
struct socket *ncp_sock;/* ncp socket */
struct file *info_filp;
struct socket *info_sock;
u8 sequence;
u8 task;
......@@ -79,8 +84,54 @@ struct ncp_server {
/* miscellaneous */
unsigned int flags;
spinlock_t requests_lock; /* Lock accesses to tx.requests, tx.creq and rcv.creq when STREAM mode */
void (*data_ready)(struct sock* sk, int len);
void (*error_report)(struct sock* sk);
void (*write_space)(struct sock* sk); /* STREAM mode only */
struct {
struct tq_struct tq; /* STREAM/DGRAM: data/error ready */
struct ncp_request_reply* creq; /* STREAM/DGRAM: awaiting reply from this request */
struct semaphore creq_sem; /* DGRAM only: lock accesses to rcv.creq */
unsigned int state; /* STREAM only: receiver state */
struct {
__u32 magic __attribute__((packed));
__u32 len __attribute__((packed));
__u16 type __attribute__((packed));
__u16 p1 __attribute__((packed));
__u16 p2 __attribute__((packed));
__u16 p3 __attribute__((packed));
__u16 type2 __attribute__((packed));
} buf; /* STREAM only: temporary buffer */
unsigned char* ptr; /* STREAM only: pointer to data */
size_t len; /* STREAM only: length of data to receive */
} rcv;
struct {
struct list_head requests; /* STREAM only: queued requests */
struct tq_struct tq; /* STREAM only: transmitter ready */
struct ncp_request_reply* creq; /* STREAM only: currently transmitted entry */
} tx;
struct timer_list timeout_tm; /* DGRAM only: timeout timer */
struct tq_struct timeout_tq; /* DGRAM only: associated queue, we run timers from process context */
int timeout_last; /* DGRAM only: current timeout length */
int timeout_retries; /* DGRAM only: retries left */
struct {
size_t len;
__u8 data[128];
} unexpected_packet;
};
extern void ncp_tcp_rcv_proc(void *server);
extern void ncp_tcp_tx_proc(void *server);
extern void ncpdgram_rcv_proc(void *server);
extern void ncpdgram_timeout_proc(void *server);
extern void ncpdgram_timeout_call(unsigned long server);
extern void ncp_tcp_data_ready(struct sock* sk, int len);
extern void ncp_tcp_write_space(struct sock* sk);
extern void ncp_tcp_error_report(struct sock* sk);
#define NCP_FLAG_UTF8 1
#define NCP_CLR_FLAG(server, flag) ((server)->flags &= ~(flag))
......
......@@ -11,7 +11,7 @@
#include <linux/types.h>
#include <linux/ncp.h>
#define NCP_MOUNT_VERSION 3
#define NCP_MOUNT_VERSION 3 /* Binary */
/* Values for flags */
#define NCP_MOUNT_SOFT 0x0001
......@@ -41,7 +41,7 @@ struct ncp_mount_data {
__kernel_mode_t dir_mode;
};
#define NCP_MOUNT_VERSION_V4 (4)
#define NCP_MOUNT_VERSION_V4 (4) /* Binary or text */
struct ncp_mount_data_v4 {
int version;
......@@ -66,6 +66,8 @@ struct ncp_mount_data_v4 {
unsigned long dir_mode;
};
#define NCP_MOUNT_VERSION_V5 (5) /* Text only */
#ifdef __KERNEL__
struct ncp_mount_data_kernel {
......@@ -83,6 +85,7 @@ struct ncp_mount_data_kernel {
__kernel_gid32_t gid;
__kernel_mode_t file_mode;
__kernel_mode_t dir_mode;
int info_fd;
};
#endif /* __KERNEL__ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment