diff -urN linux-2.0.33.dist/fs/Config.in linux/fs/Config.in --- linux-2.0.33.dist/fs/Config.in Sat Sep 6 05:43:59 1997 +++ linux/fs/Config.in Wed Feb 11 12:20:32 1998 @@ -33,6 +33,9 @@ fi if [ "$CONFIG_IPX" != "n" ]; then tristate 'NCP filesystem support (to mount NetWare volumes)' CONFIG_NCP_FS + if [ "$CONFIG_NCP_FS" != "n" ]; then + source fs/ncpfs/Config.in + fi fi tristate 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS tristate 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS diff -urN linux-2.0.33.dist/fs/ncpfs/Config.in linux/fs/ncpfs/Config.in --- linux-2.0.33.dist/fs/ncpfs/Config.in Thu Jan 1 01:00:00 1970 +++ linux/fs/ncpfs/Config.in Thu Feb 12 16:54:39 1998 @@ -0,0 +1,9 @@ +# +# NCP Filesystem configuration +# +bool ' Packet singatures' CONFIG_NCPFS_PACKET_SIGNING +bool ' Proprietary file locking' CONFIG_NCPFS_IOCTL_LOCKING +bool ' Clear remove/delete inhibit when needed' CONFIG_NCPFS_STRONG +bool ' Use NFS namespace if available' CONFIG_NCPFS_NFS_NS +bool ' Use LONG (OS/2) namespace if available' CONFIG_NCPFS_OS2_NS +bool ' Allow mounting of volume subdirectories' CONFIG_NCPFS_MOUNT_SUBDIR diff -urN linux-2.0.33.dist/fs/ncpfs/Makefile linux/fs/ncpfs/Makefile --- linux-2.0.33.dist/fs/ncpfs/Makefile Thu Feb 22 14:20:19 1996 +++ linux/fs/ncpfs/Makefile Wed Dec 17 18:14:02 1997 @@ -8,7 +8,8 @@ # Note 2! The CFLAGS definitions are now in the main makefile... O_TARGET := ncpfs.o -O_OBJS := dir.o file.o inode.o ioctl.o mmap.o ncplib_kernel.o sock.o +O_OBJS := dir.o file.o inode.o ioctl.o mmap.o ncplib_kernel.o sock.o \ + ncpsign_kernel.o M_OBJS := $(O_TARGET) # If you want debugging output, please uncomment the following line diff -urN linux-2.0.33.dist/fs/ncpfs/dir.c linux/fs/ncpfs/dir.c --- linux-2.0.33.dist/fs/ncpfs/dir.c Fri Aug 15 06:02:34 1997 +++ linux/fs/ncpfs/dir.c Wed Feb 18 17:39:37 1998 @@ -5,6 +5,8 @@ * */ +#include + #include #include #include @@ -103,7 +105,14 @@ static inline int ncp_preserve_case(struct inode *i) { - return (ncp_namespace(i) == NW_NS_OS2); + return +#ifdef CONFIG_NCPFS_OS2_NS + (ncp_namespace(i) == NW_NS_OS2) || +#endif /* CONFIG_NCPFS_OS2_NS */ +#ifdef CONFIG_NCPFS_NFS_NS + (ncp_namespace(i) == NW_NS_NFS) || +#endif /* CONFIG_NCPFS_NFS_NS */ + 0; } static struct file_operations ncp_dir_operations = { @@ -157,7 +166,7 @@ ncp_info_ino(struct ncp_server *server, struct ncp_inode_info *info) { return ncp_single_volume(server) - ? info->finfo.i.dirEntNum : (ino_t)info; + ? (info->finfo.i.dirEntNum == server->root.finfo.i.dirEntNum)?0:info->finfo.i.dirEntNum: (ino_t)info; } static inline int @@ -937,6 +946,7 @@ { struct nw_file_info finfo; __u8 _name[len+1]; + int error; *result = NULL; @@ -961,15 +971,18 @@ } lock_super(dir->i_sb); - if (ncp_open_create_file_or_subdir(NCP_SERVER(dir), + if ((error = ncp_open_create_file_or_subdir(NCP_SERVER(dir), NCP_ISTRUCT(dir), _name, OC_MODE_CREATE|OC_MODE_OPEN| OC_MODE_REPLACE, 0, AR_READ|AR_WRITE, - &finfo) != 0) + &finfo)) != 0) { unlock_super(dir->i_sb); iput(dir); + if (error == 0x87) { + return -ENAMETOOLONG; + } return -EACCES; } @@ -1095,6 +1108,65 @@ return error; } + +#ifdef CONFIG_NCPFS_STRONG +/* try to delete a readonly file (NW R bit set) */ + +static int +ncp_force_unlink(struct inode *dir,char *name,int len) +{ + int res=0x9c,res2; + struct inode *_inode; + struct iattr ia; + + /* remove the Read-Only flag on the NW server */ + + dir->i_count++; + res2=ncp_lookup(dir,name,len,&_inode); + if (res2) + { + goto leave_me; /* abort operation */ + } + memset(&ia,0,sizeof(struct iattr)); + ia.ia_mode = _inode->i_mode; + ia.ia_mode |= NCP_SERVER(dir)->m.file_mode & 0222; /* set write bits */ + ia.ia_valid = ATTR_MODE; + + res2=ncp_notify_change(_inode,&ia); + if (res2) + { + iput(_inode); + goto leave_me; + } + + /* now try again the delete operation */ + + res2 = ncp_del_file_or_subdir(NCP_SERVER(dir),NCP_ISTRUCT(dir),name); + + res=res2; /* save status to use as return value */ + + res=res2; + if (res2) /* delete failed, set R bit again */ + { + memset(&ia,0,sizeof(struct iattr)); + ia.ia_mode = _inode->i_mode; + ia.ia_mode &= ~(NCP_SERVER(dir)->m.file_mode & 0222); /* clear write bits */ + ia.ia_valid = ATTR_MODE; + + res2=ncp_notify_change(_inode,&ia); + if (res2) + { + iput(_inode); + goto leave_me; + } + } + iput(_inode); + + leave_me: + return(res); +} +#endif /* CONFIG_NCPFS_STRONG */ + static int ncp_unlink(struct inode *dir, const char *name, int len) { @@ -1126,14 +1198,21 @@ str_upper(_name); } - if ((error = ncp_del_file_or_subdir(NCP_SERVER(dir), - NCP_ISTRUCT(dir), - _name)) == 0) - { - ncp_invalid_dir_cache(dir); - } - else - { + error = ncp_del_file_or_subdir(NCP_SERVER(dir), + NCP_ISTRUCT(dir), + _name); +#ifdef CONFIG_NCPFS_STRONG + if (error == 0x9c && NCP_SERVER(dir)->m.flags & NCP_MOUNT_STRONG) /* readonly */ + { + error = ncp_force_unlink(dir,_name,len); /* special treatment */ + } +#endif /* CONFIG_NCPFS_STRONG */ + + if (error == 0) { + ncp_invalid_dir_cache(dir); + } else if (error == 0xFF) { + error = -ENOENT; + } else { error = -EACCES; } } @@ -1141,6 +1220,83 @@ return error; } +#ifdef CONFIG_NCPFS_STRONG +static int +ncp_force_rename(struct inode *old_dir, const char *old_name, char *_old_name, int old_len, + struct inode *new_dir, const char *new_name, char *_new_name, int new_len) +{ + int res=0x90,res2; + char _rename_old[old_len+1]; + char _rename_new[new_len+1]; + struct inode *_inode,*x_dir; + struct iattr ia; + + strncpy(_rename_old,old_name,old_len); + _rename_old[old_len] = 0; + strncpy(_rename_new,new_name,new_len); + _rename_new[new_len] = 0; + + /* remove the Read-Only flag on the NW server */ + + old_dir->i_count++; + res2=ncp_lookup(old_dir,_rename_old,old_len,&_inode); + if (res2) + { + goto leave_me; + } + memset(&ia,0,sizeof(struct iattr)); + ia.ia_mode = _inode->i_mode; + ia.ia_mode |= NCP_SERVER(old_dir)->m.file_mode & 0222; /* set write bits */ + ia.ia_valid = ATTR_MODE; + + res2=ncp_notify_change(_inode,&ia); + if (res2) + { + iput(_inode); + goto leave_me; + } + + /* now try again the rename operation */ + res2 = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir), + NCP_ISTRUCT(old_dir), _old_name, + NCP_ISTRUCT(new_dir), _new_name); + + res=res2; + if (!res2) /* rename succeeded, get a new inode for the new file */ + { + x_dir=new_dir; + new_dir->i_count++; + iput(_inode); + res2=ncp_lookup(new_dir,_rename_new,new_len,&_inode); + if (res2) + { + goto leave_me; + } + } + else + { + x_dir=old_dir; + } + + memset(&ia,0,sizeof(struct iattr)); + ia.ia_mode = _inode->i_mode; + ia.ia_mode &= ~(NCP_SERVER(x_dir)->m.file_mode & 0222); /* clear write bits */ + ia.ia_valid = ATTR_MODE; + + res2=ncp_notify_change(_inode,&ia); + iput(_inode); + if (res2) + { + printk(KERN_INFO "ncpfs: ncp_notify_change (2) failed: %08x\n",res2); + goto leave_me; + } + + leave_me: + return(res); +} +#endif /* CONFIG_NCPFS_STRONG */ + + static int ncp_rename(struct inode *old_dir, const char *old_name, int old_len, struct inode *new_dir, const char *new_name, int new_len, @@ -1197,14 +1353,26 @@ NCP_ISTRUCT(old_dir), _old_name, NCP_ISTRUCT(new_dir), _new_name); - if (res == 0) +#ifdef CONFIG_NCPFS_STRONG + if (res == 0x90 && NCP_SERVER(old_dir)->m.flags & NCP_MOUNT_STRONG) /* file is readonly */ { - ncp_invalid_dir_cache(old_dir); - ncp_invalid_dir_cache(new_dir); - } + res=ncp_force_rename(old_dir,old_name,_old_name,old_len,new_dir,new_name,_new_name,new_len); + } +#endif /* CONFIG_NCPFS_STRONG */ + + if (res == 0) + { + ncp_invalid_dir_cache(old_dir); + ncp_invalid_dir_cache(new_dir); + } else { - res = -EACCES; + if (res == 0x9E) + res = -ENAMETOOLONG; + else if (res == 0xFF) + res = -ENOENT; + else + res = -EACCES; } finished: diff -urN linux-2.0.33.dist/fs/ncpfs/inode.c linux/fs/ncpfs/inode.c --- linux-2.0.33.dist/fs/ncpfs/inode.c Tue Aug 5 18:33:12 1997 +++ linux/fs/ncpfs/inode.c Thu Feb 12 12:19:16 1998 @@ -32,7 +32,6 @@ static void ncp_read_inode(struct inode *); static void ncp_put_super(struct super_block *); static void ncp_statfs(struct super_block *sb, struct statfs *buf, int bufsiz); -static int ncp_notify_change(struct inode *inode, struct iattr *attr); static struct super_operations ncp_sops = { ncp_read_inode, /* read inode */ @@ -83,6 +82,9 @@ else { inode->i_mode = NCP_SERVER(inode)->m.file_mode; +#if 1 + if (NCP_ISTRUCT(inode)->attributes & /* 0x60001 incl. DiRi */ 1) inode->i_mode &= ~0222; +#endif inode->i_size = NCP_ISTRUCT(inode)->dataStreamSize; } @@ -144,10 +146,11 @@ */ lock_super(sb); - if (inode->i_count > 1) { -printk("ncp_put_inode: inode in use device %s, inode %ld, count=%d\n", -kdevname(inode->i_dev), inode->i_ino, inode->i_count); - goto unlock; + if (inode->i_count > 1) + { + printk("ncp_put_inode: inode in use device %s, inode %ld, count=%d\n", + kdevname(inode->i_dev), inode->i_ino, inode->i_count); + goto unlock; } DDPRINTK("ncp_put_inode: put %s\n", @@ -198,6 +201,9 @@ struct file *msg_filp; kdev_t dev = sb->s_dev; int error; +#ifdef CONFIG_NCPFS_PACKET_SIGNING + int options; +#endif if (data == NULL) { @@ -274,7 +280,10 @@ server->packet = NULL; server->buffer_size = 0; server->conn_status = 0; - +#ifdef CONFIG_NCPFS_PACKET_SIGNING + server->sign_wanted = 0; + server->sign_active = 0; +#endif server->m = *data; server->m.file_mode = (server->m.file_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFREG; @@ -342,6 +351,29 @@ goto disconnect; } +#ifdef CONFIG_NCPFS_PACKET_SIGNING + if (ncp_negotiate_size_and_options(server, NCP_DEFAULT_BUFSIZE, + NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0) + { + if (options != NCP_DEFAULT_OPTIONS) + { + if (ncp_negotiate_size_and_options(server, + NCP_DEFAULT_BUFSIZE, + options & 2, + &(server->buffer_size), &options) != 0) + + { + sb->s_dev = 0; + printk("ncp_read_super: " + "could not set options\n"); + goto disconnect; + } + } + if (options & 2) + server->sign_wanted = 1; + } + else +#endif /* CONFIG_NCPFS_PACKET_SIGNING */ if (ncp_negotiate_buffersize(server, NCP_DEFAULT_BUFSIZE, &(server->buffer_size)) != 0) { @@ -449,7 +481,7 @@ memcpy_tofs(buf, &tmp, bufsiz); } -static int +int ncp_notify_change(struct inode *inode, struct iattr *attr) { int result = 0; @@ -479,6 +511,33 @@ info_mask = 0; memset(&info, 0, sizeof(info)); + +#if 1 + if ((attr->ia_valid & ATTR_MODE) != 0) + { + if (NCP_ISTRUCT(inode)->attributes & aDIR) + { + return -EPERM; + } + else + { + umode_t newmode; + + info_mask |= DM_ATTRIBUTES; + newmode=attr->ia_mode; + newmode &= NCP_SERVER(inode)->m.file_mode; + + if (newmode & 0222) /* any write bit set */ + { + info.attributes &= ~0x60001; + } + else + { + info.attributes |= 0x60001; + } + } + } +#endif if ((attr->ia_valid & ATTR_CTIME) != 0) { diff -urN linux-2.0.33.dist/fs/ncpfs/ioctl.c linux/fs/ncpfs/ioctl.c --- linux-2.0.33.dist/fs/ncpfs/ioctl.c Fri Mar 22 11:58:41 1996 +++ linux/fs/ncpfs/ioctl.c Thu Feb 12 18:35:32 1998 @@ -5,6 +5,8 @@ * */ +#include + #include #include #include @@ -13,6 +15,7 @@ #include #include #include +#include "ncplib_kernel.h" int ncp_ioctl (struct inode * inode, struct file * filp, @@ -151,6 +154,242 @@ } put_fs_word(server->m.mounted_uid, (uid_t*) arg); return 0; + +#if 0 + case NCP_IOC_GETMOUNTUID_INT: + if ( (permission(inode, MAY_READ) != 0) + && (current->uid != server->m.mounted_uid)) + { + return -EACCES; + } + + if ((result = verify_area(VERIFY_WRITE, (unsigned int*)arg, + sizeof(unsigned int))) != 0) + { + return result; + } + { + unsigned int tmp=server->m.mounted_uid; + put_fs_long(tmp, (unsigned int*) arg); + } + return 0; +#endif + +#ifdef CONFIG_NCPFS_MOUNT_SUBDIR + case NCP_IOC_GETROOT: + { + struct ncp_setroot_ioctl sr; + + if ( (permission(inode, MAY_READ) != 0) + && (current->uid != server->m.mounted_uid)) + { + return -EACCES; + } + if (server->m.mounted_vol[0]) { + sr.volNumber = server->root.finfo.i.volNumber; + sr.dirEntNum = server->root.finfo.i.dirEntNum; + sr.namespace = server->name_space[sr.volNumber]; + } else { + sr.volNumber = -1; + sr.namespace = 0; + sr.dirEntNum = 0; + } + if ((result = verify_area(VERIFY_WRITE, + (struct ncp_setroot_ioctl*)arg, + sizeof(sr))) != 0) + { + return result; + } + memcpy_tofs((struct ncp_setroot_ioctl*)arg, + &sr, sizeof(sr)); + return 0; + } + case NCP_IOC_SETROOT: + { + struct ncp_setroot_ioctl sr; + + if ( (permission(inode, MAY_WRITE) != 0) + && (current->uid != server->m.mounted_uid)) + { + return -EACCES; + } + if ((result = verify_area(VERIFY_READ, + (struct ncp_setroot_ioctl*)arg, + sizeof(sr))) != 0) + { + return result; + } + memcpy_fromfs(&sr, (struct ncp_setroot_ioctl*)arg, sizeof(sr)); + if (sr.volNumber < 0) { + server->m.mounted_vol[0] = 0; + server->root.finfo.i.volNumber = 0; + server->root.finfo.i.dirEntNum = 0; + } else if (sr.volNumber >= NCP_NUMBER_OF_VOLUMES) { + return -EINVAL; + } else { + if (ncp_mount_subdir(server, sr.volNumber, sr.namespace, sr.dirEntNum)) { + return -ENOENT; + } + } + return 0; + } +#endif /* CONFIG_NCPFS_MOUNT_SUBDIR */ + +#ifdef CONFIG_NCPFS_PACKET_SIGNING + case NCP_IOC_SIGN_INIT: + if ((permission(inode, MAY_WRITE) != 0) + && (current->uid != server->m.mounted_uid)) + { + return -EACCES; + } + if ((result = verify_area(VERIFY_READ, (struct ncp_sign_init*)arg, + sizeof(struct ncp_sign_init))) != 0) + { + return result; + } + if (server->sign_active) + { + return -EINVAL; + } + if (server->sign_wanted) + { + struct ncp_sign_init sign; + + memcpy_fromfs(&sign, (struct ncp_sign_init *) arg, + sizeof(sign)); + memcpy(server->sign_root,sign.sign_root,8); + memcpy(server->sign_last,sign.sign_last,16); + server->sign_active = 1; + } + /* ignore when signatures not wanted */ + return 0; + + case NCP_IOC_SIGN_WANTED: + if ( (permission(inode, MAY_READ) != 0) + && (current->uid != server->m.mounted_uid)) + { + return -EACCES; + } + if ((result = verify_area(VERIFY_WRITE, (int*) arg, + sizeof(int))) != 0) + { + return result; + } + /* Should not it be put_fs_long? Vandrove@vc.cvut.cz */ + put_fs_word(server->sign_wanted, (int*) arg); + return 0; + + case NCP_IOC_SET_SIGN_WANTED: + { + int newstate; + + if ( (permission(inode, MAY_WRITE) != 0) + && (current->uid != server->m.mounted_uid)) + { + return -EACCES; + } + if ((result = verify_area(VERIFY_READ, (int*) arg, + sizeof(int))) != 0) + { + return result; + } + /* get only low 8 bits... */ + newstate = get_fs_byte((unsigned char*)arg); + if (server->sign_active) { + /* cannot turn signatures OFF when active */ + if (!newstate) return -EINVAL; + } else { + server->sign_wanted = newstate != 0; + } + return 0; + } + +#endif /* CONFIG_NCPFS_PACKET_SIGNING */ + +#ifdef CONFIG_NCPFS_IOCTL_LOCKING + case NCP_IOC_LOCKUNLOCK: + if ( (permission(inode, MAY_WRITE) != 0) + && (current->uid != server->m.mounted_uid)) + { + return -EACCES; + } + { + struct ncp_lock_ioctl rqdata; + struct nw_file_info *finfo; + int result; + + if ((result = verify_area(VERIFY_READ, + (struct ncp_lock_ioctl*)arg, + sizeof(rqdata))) != 0) + { + return result; + } + memcpy_fromfs(&rqdata, (struct ncp_lock_ioctl*)arg, + sizeof(rqdata)); + if (rqdata.origin != 0) + return -EINVAL; + /* check for cmd */ + switch (rqdata.cmd) { + case NCP_LOCK_EX: + case NCP_LOCK_SH: + if (rqdata.timeout == 0) + rqdata.timeout = NCP_LOCK_DEFAULT_TIMEOUT; + else if (rqdata.timeout > NCP_LOCK_MAX_TIMEOUT) + rqdata.timeout = NCP_LOCK_MAX_TIMEOUT; + break; + case NCP_LOCK_LOG: + rqdata.timeout = NCP_LOCK_DEFAULT_TIMEOUT; /* has no effect */ + case NCP_LOCK_CLEAR: + break; + default: + return -EINVAL; + } + if ((result = ncp_make_open(inode, O_RDWR)) != 0) + { + return result; + } + if (!ncp_conn_valid(server)) + { + return -EIO; + } + if (!S_ISREG(inode->i_mode)) + { + return -EISDIR; + } + finfo=NCP_FINFO(inode); + if (!finfo->opened) + { + return -EBADFD; + } + if (rqdata.cmd == NCP_LOCK_CLEAR) + { + result = ncp_ClearPhysicalRecord(NCP_SERVER(inode), + finfo->file_handle, + rqdata.offset, + rqdata.length); + if (result > 0) result = 0; /* no such lock */ + } + else + { + int lockcmd; + + switch (rqdata.cmd) + { + case NCP_LOCK_EX: lockcmd=1; break; + case NCP_LOCK_SH: lockcmd=3; break; + default: lockcmd=0; break; + } + result = ncp_LogPhysicalRecord(NCP_SERVER(inode), + finfo->file_handle, + lockcmd, + rqdata.offset, + rqdata.length, + rqdata.timeout); + if (result > 0) result = -EAGAIN; + } + return result; + } +#endif /* CONFIG_NCPFS_IOCTL_LOCKING */ default: return -EINVAL; diff -urN linux-2.0.33.dist/fs/ncpfs/ncplib_kernel.c linux/fs/ncpfs/ncplib_kernel.c --- linux-2.0.33.dist/fs/ncpfs/ncplib_kernel.c Thu Jul 18 14:52:00 1996 +++ linux/fs/ncpfs/ncplib_kernel.c Fri Feb 27 12:23:41 1998 @@ -5,6 +5,8 @@ * */ +#include + #include "ncplib_kernel.h" typedef __u8 byte; @@ -129,6 +131,33 @@ return *(dword *)(ncp_reply_data(server, offset)); } + +/* options: + * bit 0 ipx checksum + * bit 1 packet signing + */ +int +ncp_negotiate_size_and_options(struct ncp_server *server, + int size, int options, int *ret_size, int *ret_options) { + int result; + + ncp_init_request(server); + ncp_add_word(server, htons(size)); + ncp_add_byte(server, options); + + if ((result = ncp_request(server, 0x61)) != 0) + { + ncp_unlock_server(server); + return result; + } + + *ret_size = min(ntohs(ncp_reply_word(server, 0)), size); + *ret_options = ncp_reply_byte(server, 4); + + ncp_unlock_server(server); + return 0; +} + int ncp_negotiate_buffersize(struct ncp_server *server, int size, int *target) @@ -261,7 +290,7 @@ ncp_add_byte(server, 6); /* subfunction */ ncp_add_byte(server, server->name_space[vol_num]); ncp_add_byte(server, server->name_space[vol_num]); - ncp_add_word(server, 0xff); /* get all */ + ncp_add_word(server, 0x8006); /* get all */ ncp_add_dword(server, RIM_ALL); ncp_add_handle_path(server, vol_num, dir_base, 1, path); @@ -277,8 +306,9 @@ } static inline int -ncp_has_os2_namespace(struct ncp_server *server, __u8 volume) +ncp_get_known_namespace(struct ncp_server *server, __u8 volume) { +#if defined(CONFIG_NCPFS_OS2_NS) || defined(CONFIG_NCPFS_NFS_NS) int result; __u8 *namespace; __u16 no_namespaces; @@ -291,9 +321,10 @@ if ((result = ncp_request(server, 87)) != 0) { ncp_unlock_server(server); - return 0; + return NW_NS_DOS; } + result=NW_NS_DOS; no_namespaces = ncp_reply_word(server, 0); namespace = ncp_reply_data(server, 2); @@ -301,16 +332,104 @@ { DPRINTK("get_namespaces: found %d on %d\n", *namespace,volume); - if (*namespace == 4) +#ifdef CONFIG_NCPFS_NFS_NS + if ((*namespace == NW_NS_NFS) && !(server->m.flags&NCP_MOUNT_NO_NFS)) + { + result = NW_NS_NFS; + break; + } +#endif /* CONFIG_NCPFS_NFS_NS */ +#ifdef CONFIG_NCPFS_OS2_NS + if ((*namespace == NW_NS_OS2) && !(server->m.flags&NCP_MOUNT_NO_OS2)) { - DPRINTK("get_namespaces: found OS2\n"); - ncp_unlock_server(server); - return 1; + result = NW_NS_OS2; } +#endif /* CONFIG_NCPFS_OS2_NS */ namespace += 1; no_namespaces -= 1; } ncp_unlock_server(server); + return result; +#else /* neither OS2 nor NFS - only DOS */ + return NW_NS_DOS; +#endif /* defined(CONFIG_NCPFS_OS2_NS) || defined(CONFIG_NCPFS_NFS_NS) */ +} + +static int +ncp_ObtainSpecificDirBase(struct ncp_server *server, + __u8 nsSrc, __u8 nsDst, __u8 vol_num, __u32 dir_base, + char *path, /* At most 1 component */ + __u32 *dirEntNum) +{ + int result; + + ncp_init_request(server); + ncp_add_byte(server, 6); /* subfunction */ + ncp_add_byte(server, nsSrc); + ncp_add_byte(server, nsDst); + ncp_add_word(server, 0x8006); /* get all */ + ncp_add_dword(server, RIM_ALL); + ncp_add_handle_path(server, vol_num, dir_base, 1, path); + + if ((result = ncp_request(server, 87)) != 0) + { + ncp_unlock_server(server); + return result; + } + + if (dirEntNum) + *dirEntNum = ncp_reply_dword(server, 0x30); + ncp_unlock_server(server); + return 0; +} + +int +ncp_mount_subdir(struct ncp_server *server, + __u8 volNumber, + __u8 srcNS, __u32 dirEntNum) +{ + int dstNS; + int result; + __u32 newDirEnt; + + dstNS = ncp_get_known_namespace(server, volNumber); + if ((result = ncp_ObtainSpecificDirBase(server, srcNS, dstNS, volNumber, + dirEntNum, NULL, &newDirEnt)) != 0) + { + return result; + } + server->name_space[volNumber] = dstNS; + server->root.finfo.i.volNumber = volNumber; + server->root.finfo.i.dirEntNum = newDirEnt; + server->m.mounted_vol[1] = 0; + server->m.mounted_vol[0] = 'X'; + return 0; +} + +static int +ncp_obtain_DOS_dir_base(struct ncp_server *server, + struct nw_info_struct* file, + char *path, /* At most 1 component */ + __u32 *DOS_dir_base) +{ + int result; + + ncp_init_request(server); + ncp_add_byte(server, 6); /* subfunction */ + ncp_add_byte(server, server->name_space[file->volNumber]); + ncp_add_byte(server, server->name_space[file->volNumber]); + ncp_add_word(server, 0x8006); /* get all */ + ncp_add_dword(server, RIM_DIRECTORY); + ncp_add_handle_path(server, file->volNumber, file->dirEntNum, 1, path); + + if ((result = ncp_request(server, 87)) != 0) + { + ncp_unlock_server(server); + return result; + } + + if (DOS_dir_base) *DOS_dir_base=ncp_reply_dword(server, 0x34); + ncp_unlock_server(server); return 0; } @@ -348,7 +467,8 @@ target->volNumber = volnum = ncp_reply_byte(server, 8); ncp_unlock_server(server); - server->name_space[volnum] = ncp_has_os2_namespace(server,volnum)?4:0; + server->name_space[volnum] = + ncp_get_known_namespace(server, volnum); DPRINTK("lookup_vol: namespace[%d] = %d\n", volnum, server->name_space[volnum]); @@ -383,25 +503,44 @@ return result; } -int -ncp_del_file_or_subdir(struct ncp_server *server, - struct nw_info_struct *dir, char *name) +static int +ncp_DeleteNSEntry(struct ncp_server *server, + __u8 have_dir_base, __u8 volume, __u32 dir_base, + char* name, __u8 ns, int attr) { int result; ncp_init_request(server); ncp_add_byte(server, 8); /* subfunction */ - ncp_add_byte(server, server->name_space[dir->volNumber]); + ncp_add_byte(server, ns); /* namespace */ ncp_add_byte(server, 0); /* reserved */ - ncp_add_word(server, 0x8006); /* search attribs: all */ - ncp_add_handle_path(server, dir->volNumber, - dir->dirEntNum, 1, name); + ncp_add_word(server, attr); /* search attribs */ + ncp_add_handle_path(server, volume, dir_base, have_dir_base, name); result = ncp_request(server, 87); ncp_unlock_server(server); return result; } +int +ncp_del_file_or_subdir(struct ncp_server *server, + struct nw_info_struct *dir, char *name) +{ +#ifdef CONFIG_NCPFS_NFS_NS + if (server->name_space[dir->volNumber]==NW_NS_NFS) + { + __u32 DOS_dir_base; + int result; + + result=ncp_obtain_DOS_dir_base(server, dir, name, &DOS_dir_base); + if (result) return result; + return ncp_DeleteNSEntry(server, 1, dir->volNumber, DOS_dir_base, NULL, NW_NS_DOS, 0x8006); + } + else +#endif /* CONFIG_NCPFS_NFS_NS */ + return ncp_DeleteNSEntry(server, 1, dir->volNumber, dir->dirEntNum, name, server->name_space[dir->volNumber], 0x8006); +} + static inline void ConvertToNWfromDWORD ( __u32 sfd , __u8 ret[6] ) { @@ -428,7 +567,7 @@ if ((create_attributes & aDIR) != 0) { search_attribs |= 0x8000; -} + } ncp_init_request(server); ncp_add_byte(server, 1); /* subfunction */ @@ -464,7 +603,7 @@ if (dir != NULL) { /* in target there's a new finfo to fill */ - ncp_extract_file_info(ncp_reply_data(server, 5), &(target->i)); + ncp_extract_file_info(ncp_reply_data(server, 6), &(target->i)); } ConvertToNWfromDWORD(target->server_file_handle, target->file_handle); @@ -511,12 +650,21 @@ ncp_add_byte(server, 3); /* subfunction */ ncp_add_byte(server, server->name_space[seq->volNumber]); ncp_add_byte(server, 0); /* data stream (???) */ - ncp_add_word(server, 0xffff); /* Search attribs */ + ncp_add_word(server, 0x8006); /* Search attribs */ ncp_add_dword(server, RIM_ALL); /* return info mask */ ncp_add_mem(server, seq, 9); - ncp_add_byte(server, 2); /* 2 byte pattern */ - ncp_add_byte(server, 0xff); /* following is a wildcard */ - ncp_add_byte(server, '*'); +#ifdef CONFIG_NCPFS_NFS_NS + if (server->name_space[seq->volNumber]==NW_NS_NFS) + { + ncp_add_byte(server, 0); + } + else +#endif /* CONFIG_NCPFS_NFS_NS */ + { + ncp_add_byte(server, 2); /* 2 byte pattern */ + ncp_add_byte(server, 0xff); /* following is a wildcard */ + ncp_add_byte(server, '*'); + } if ((result = ncp_request(server, 87)) != 0) { @@ -532,9 +680,9 @@ } int -ncp_ren_or_mov_file_or_subdir(struct ncp_server *server, - struct nw_info_struct *old_dir, char *old_name, - struct nw_info_struct *new_dir, char *new_name) +ncp_RenameNSEntry(struct ncp_server *server, + struct nw_info_struct *old_dir, char *old_name, int old_type, + struct nw_info_struct *new_dir, char *new_name) { int result; @@ -546,7 +694,7 @@ ncp_add_byte(server, 4); /* subfunction */ ncp_add_byte(server, server->name_space[old_dir->volNumber]); ncp_add_byte(server, 1); /* rename flag */ - ncp_add_word(server, 0x8006); /* search attributes */ + ncp_add_word(server, old_type); /* search attributes */ /* source Handle Path */ ncp_add_byte(server, old_dir->volNumber); @@ -570,6 +718,31 @@ return result; } +int +ncp_ren_or_mov_file_or_subdir(struct ncp_server *server, + struct nw_info_struct *old_dir, char *old_name, + struct nw_info_struct *new_dir, char *new_name) +{ + int result; + int old_type = 0x0006; + +/* If somebody can do it atomic, call me... vandrove@vc.cvut.cz */ + result = ncp_RenameNSEntry(server, old_dir, old_name, old_type, + new_dir, new_name); + if (result == 0xFF) /* File Not Found, try directory */ + { + old_type = 0x0016; + result = ncp_RenameNSEntry(server, old_dir, old_name, old_type, + new_dir, new_name); + } + if (result != 0x92) return result; /* All except NO_FILES_RENAMED */ + result = ncp_del_file_or_subdir(server, new_dir, new_name); + if (result != 0) return -EACCES; + result = ncp_RenameNSEntry(server, old_dir, old_name, old_type, + new_dir, new_name); + return result; +} + /* We have to transfer to/from user space */ int @@ -624,4 +797,49 @@ ncp_unlock_server(server); return 0; } + +#ifdef CONFIG_NCPFS_IOCTL_LOCKING +int +ncp_LogPhysicalRecord(struct ncp_server *server, const char *file_id, + __u8 locktype, __u32 offset, __u32 length, __u16 timeout) +{ + int result; + + ncp_init_request(server); + ncp_add_byte(server, locktype); + ncp_add_mem(server, file_id, 6); + ncp_add_dword(server, htonl(offset)); + ncp_add_dword(server, htonl(length)); + ncp_add_word(server, htons(timeout)); + + if ((result = ncp_request(server, 0x1A)) != 0) + { + ncp_unlock_server(server); + return result; + } + ncp_unlock_server(server); + return 0; +} + +int +ncp_ClearPhysicalRecord(struct ncp_server *server, const char *file_id, + __u32 offset, __u32 length) +{ + int result; + + ncp_init_request(server); + ncp_add_byte(server, 0); /* who knows... lanalyzer says that */ + ncp_add_mem(server, file_id, 6); + ncp_add_dword(server, htonl(offset)); + ncp_add_dword(server, htonl(length)); + + if ((result = ncp_request(server, 0x1E)) != 0) + { + ncp_unlock_server(server); + return result; + } + ncp_unlock_server(server); + return 0; +} +#endif /* CONFIG_NCPFS_IOCTL_LOCKING */ diff -urN linux-2.0.33.dist/fs/ncpfs/ncplib_kernel.h linux/fs/ncpfs/ncplib_kernel.h --- linux-2.0.33.dist/fs/ncpfs/ncplib_kernel.h Thu Oct 16 00:26:30 1997 +++ linux/fs/ncpfs/ncplib_kernel.h Fri Feb 27 12:26:33 1998 @@ -8,6 +8,8 @@ #ifndef _NCPLIB_H #define _NCPLIB_H +#include + #include #include #include @@ -23,6 +25,9 @@ #include int +ncp_negotiate_size_and_options(struct ncp_server *server, int size, + int options, int *ret_size, int *ret_options); +int ncp_negotiate_buffersize(struct ncp_server *server, int size, int *target); int @@ -165,5 +170,22 @@ struct nw_info_struct *old_dir, char *old_name, struct nw_info_struct *new_dir, char *new_name); +#ifdef CONFIG_NCPFS_IOCTL_LOCKING +int +ncp_LogPhysicalRecord(struct ncp_server *server, + const char *file_id, __u8 locktype, + __u32 offset, __u32 length, __u16 timeout); + +int +ncp_ClearPhysicalRecord(struct ncp_server *server, + const char *file_id, + __u32 offset, __u32 length); +#endif /* CONFIG_NCPFS_IOCTL_LOCKING */ + +#ifdef CONFIG_NCPFS_MOUNT_SUBDIR +int +ncp_mount_subdir(struct ncp_server* server, __u8 volNumber, + __u8 srcNS, __u32 srcDirEntNum); +#endif /* CONFIG_NCPFS_MOUNT_SUBDIR */ #endif /* _NCPLIB_H */ diff -urN linux-2.0.33.dist/fs/ncpfs/ncpsign_kernel.c linux/fs/ncpfs/ncpsign_kernel.c --- linux-2.0.33.dist/fs/ncpfs/ncpsign_kernel.c Thu Jan 1 01:00:00 1970 +++ linux/fs/ncpfs/ncpsign_kernel.c Wed Feb 11 12:31:41 1998 @@ -0,0 +1,125 @@ +/* + * ncpsign_kernel.c + * + * Arne de Bruijn (arne@knoware.nl), 1997 + * + */ + +#include + +#ifdef CONFIG_NCPFS_PACKET_SIGNING + +#if 0 +#ifdef MODULE +#include +#include +#endif +#endif + +#include +#include +#if 0 +#include +#include +#endif +#include "ncpsign_kernel.h" + +#define rol32(i,c) (((((i)&0xffffffff)<>(32-c))) +/* i386: 32-bit, little endian, handles mis-alignment */ +#ifdef __i386__ +#define GET_LE32(p) (*(int *)(p)) +#define PUT_LE32(p,v) { *(int *)(p)=v; } +#else +/* from include/ncplib.h */ +#define BVAL(buf,pos) (((__u8 *)(buf))[pos]) +#define PVAL(buf,pos) ((unsigned)BVAL(buf,pos)) +#define BSET(buf,pos,val) (BVAL(buf,pos) = (val)) + +static inline word +WVAL_LH(__u8 * buf, int pos) +{ + return PVAL(buf, pos) | PVAL(buf, pos + 1) << 8; +} +static inline dword +DVAL_LH(__u8 * buf, int pos) +{ + return WVAL_LH(buf, pos) | WVAL_LH(buf, pos + 2) << 16; +} +static inline void +WSET_LH(__u8 * buf, int pos, word val) +{ + BSET(buf, pos, val & 0xff); + BSET(buf, pos + 1, val >> 8); +} +static inline void +DSET_LH(__u8 * buf, int pos, dword val) +{ + WSET_LH(buf, pos, val & 0xffff); + WSET_LH(buf, pos + 2, val >> 16); +} + +#define GET_LE32(p) DVAL_LH(p,0) +#define PUT_LE32(p,v) DSET_LH(p,0,v) +#endif + +#define min(a,b) ((a)<(b)?(a):(b)) + +static void nwsign(char *r_data1, char *r_data2, char *outdata) { + int i; + unsigned int w0,w1,w2,w3; + static int rbit[4]={0, 2, 1, 3}; +#ifdef __i386__ + unsigned int *data2=(int *)r_data2; +#else + unsigned int data2[16]; + for (i=0;i<16;i++) + data2[i]=GET_LE32(r_data2+(i<<2)); +#endif + w0=GET_LE32(r_data1); + w1=GET_LE32(r_data1+4); + w2=GET_LE32(r_data1+8); + w3=GET_LE32(r_data1+12); + for (i=0;i<16;i+=4) { + w0=rol32(w0 + ((w1 & w2) | ((~w1) & w3)) + data2[i+0],3); + w3=rol32(w3 + ((w0 & w1) | ((~w0) & w2)) + data2[i+1],7); + w2=rol32(w2 + ((w3 & w0) | ((~w3) & w1)) + data2[i+2],11); + w1=rol32(w1 + ((w2 & w3) | ((~w2) & w0)) + data2[i+3],19); + } + for (i=0;i<4;i++) { + w0=rol32(w0 + (((w2 | w3) & w1) | (w2 & w3)) + 0x5a827999 + data2[i+0],3); + w3=rol32(w3 + (((w1 | w2) & w0) | (w1 & w2)) + 0x5a827999 + data2[i+4],5); + w2=rol32(w2 + (((w0 | w1) & w3) | (w0 & w1)) + 0x5a827999 + data2[i+8],9); + w1=rol32(w1 + (((w3 | w0) & w2) | (w3 & w0)) + 0x5a827999 + data2[i+12],13); + } + for (i=0;i<4;i++) { + w0=rol32(w0 + ((w1 ^ w2) ^ w3) + 0x6ed9eba1 + data2[rbit[i]+0],3); + w3=rol32(w3 + ((w0 ^ w1) ^ w2) + 0x6ed9eba1 + data2[rbit[i]+8],9); + w2=rol32(w2 + ((w3 ^ w0) ^ w1) + 0x6ed9eba1 + data2[rbit[i]+4],11); + w1=rol32(w1 + ((w2 ^ w3) ^ w0) + 0x6ed9eba1 + data2[rbit[i]+12],15); + } + PUT_LE32(outdata,(w0+GET_LE32(r_data1)) & 0xffffffff); + PUT_LE32(outdata+4,(w1+GET_LE32(r_data1+4)) & 0xffffffff); + PUT_LE32(outdata+8,(w2+GET_LE32(r_data1+8)) & 0xffffffff); + PUT_LE32(outdata+12,(w3+GET_LE32(r_data1+12)) & 0xffffffff); +} + +/* 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]; + + 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((*size)-sizeof(struct ncp_request_header)+1,52)); + + nwsign(server->sign_last,data,server->sign_last); + + memcpy(server->packet+(*size),server->sign_last,8); + (*size)+=8; +} + +#endif /* CONFIG_NCPFS_PACKET_SIGNING */ + diff -urN linux-2.0.33.dist/fs/ncpfs/ncpsign_kernel.h linux/fs/ncpfs/ncpsign_kernel.h --- linux-2.0.33.dist/fs/ncpfs/ncpsign_kernel.h Thu Jan 1 01:00:00 1970 +++ linux/fs/ncpfs/ncpsign_kernel.h Fri Feb 27 12:26:47 1998 @@ -0,0 +1,16 @@ +/* + * ncpsign_kernel.h + * + * Arne de Bruijn (arne@knoware.nl), 1997 + * + */ + +#ifndef _NCPSIGN_KERNEL_H +#define _NCPSIGN_KERNEL_H + +#include +#include + +void sign_packet(struct ncp_server *server, int *size); + +#endif diff -urN linux-2.0.33.dist/fs/ncpfs/sock.c linux/fs/ncpfs/sock.c --- linux-2.0.33.dist/fs/ncpfs/sock.c Tue Nov 18 00:25:52 1997 +++ linux/fs/ncpfs/sock.c Wed Feb 11 20:08:48 1998 @@ -7,6 +7,8 @@ * */ +#include + #include #include #include @@ -25,6 +27,7 @@ #include #include +#include "ncpsign_kernel.h" #define _S(nr) (1<<((nr)-1)) static int _recvfrom(struct socket *sock, unsigned char *ubuf, @@ -562,7 +565,12 @@ printk("ncpfs: Server not locked!\n"); return -EIO; } - +#ifdef CONFIG_NCPFS_PACKET_SIGNING + if (server->sign_active) + { + sign_packet(server, &size); + } +#endif /* CONFIG_NCPFS_PACKET_SIGNING */ if (!ncp_conn_valid(server)) { return -EIO; diff -urN linux-2.0.33.dist/include/linux/ncp_fs.h linux/include/linux/ncp_fs.h --- linux-2.0.33.dist/include/linux/ncp_fs.h Tue Dec 2 23:20:18 1997 +++ linux/include/linux/ncp_fs.h Fri Feb 27 12:26:33 1998 @@ -29,7 +29,7 @@ struct ncp_fs_info { int version; struct sockaddr_ipx addr; - uid_t mounted_uid; + __kernel_uid_t mounted_uid; int connection; /* Connection number the server assigned us */ int buffer_size; /* The negotiated buffer size, to be used for read/write requests! */ @@ -38,13 +38,50 @@ __u32 directory_id; }; +struct ncp_sign_init +{ + char sign_root[8]; + char sign_last[16]; +}; + +struct ncp_lock_ioctl +{ +#define NCP_LOCK_LOG 0 +#define NCP_LOCK_SH 1 +#define NCP_LOCK_EX 2 +#define NCP_LOCK_CLEAR 256 + int cmd; + int origin; + unsigned int offset; + unsigned int length; +#define NCP_LOCK_DEFAULT_TIMEOUT 18 +#define NCP_LOCK_MAX_TIMEOUT 180 + int timeout; +}; + +struct ncp_setroot_ioctl +{ + int volNumber; + int namespace; + __u32 dirEntNum; +}; + #define NCP_IOC_NCPREQUEST _IOR('n', 1, struct ncp_ioctl_request) -#define NCP_IOC_GETMOUNTUID _IOW('n', 2, uid_t) +#define NCP_IOC_GETMOUNTUID _IOW('n', 2, __kernel_uid_t) +#define NCP_IOC_GETMOUNTUID_INT _IOW('n', 2, unsigned int) #define NCP_IOC_CONN_LOGGED_IN _IO('n', 3) #define NCP_GET_FS_INFO_VERSION (1) #define NCP_IOC_GET_FS_INFO _IOWR('n', 4, struct ncp_fs_info) +#define NCP_IOC_SIGN_INIT _IOR('n', 5, struct ncp_sign_init) +#define NCP_IOC_SIGN_WANTED _IOR('n', 6, int) +#define NCP_IOC_SET_SIGN_WANTED _IOW('n', 6, int) + +#define NCP_IOC_LOCKUNLOCK _IOR('n', 7, struct ncp_lock_ioctl) + +#define NCP_IOC_GETROOT _IOW('n', 8, struct ncp_setroot_ioctl) +#define NCP_IOC_SETROOT _IOR('n', 8, struct ncp_setroot_ioctl) /* * The packet size to allocate. One page should be enough. */ @@ -142,6 +179,7 @@ unsigned int cmd, unsigned long arg); /* linux/fs/ncpfs/inode.c */ +int ncp_notify_change(struct inode *inode, struct iattr *attr); struct super_block *ncp_read_super(struct super_block *sb, void *raw_data, int silent); extern int init_ncp_fs(void); diff -urN linux-2.0.33.dist/include/linux/ncp_fs_sb.h linux/include/linux/ncp_fs_sb.h --- linux-2.0.33.dist/include/linux/ncp_fs_sb.h Thu Nov 13 05:47:42 1997 +++ linux/include/linux/ncp_fs_sb.h Fri Feb 27 12:26:33 1998 @@ -14,6 +14,7 @@ #ifdef __KERNEL__ #define NCP_DEFAULT_BUFSIZE 1024 +#define NCP_DEFAULT_OPTIONS 0 /* 2 for packet signatures */ struct ncp_server { @@ -57,6 +58,12 @@ struct ncp_inode_info root; char root_path; /* '\0' */ + +/* info for packet signing */ + int sign_wanted; /* 1=Server needs signed packets */ + int sign_active; /* 0=don't do signing, 1=do */ + char sign_root[8]; /* generated from password and encr. key */ + char sign_last[16]; }; static inline int diff -urN linux-2.0.33.dist/include/linux/ncp_mount.h linux/include/linux/ncp_mount.h --- linux-2.0.33.dist/include/linux/ncp_mount.h Thu Nov 13 05:47:42 1997 +++ linux/include/linux/ncp_mount.h Fri Feb 27 12:22:18 1998 @@ -21,13 +21,16 @@ /* Values for flags */ #define NCP_MOUNT_SOFT 0x0001 #define NCP_MOUNT_INTR 0x0002 +#define NCP_MOUNT_STRONG 0x0004 /* enable delete/rename of r/o files */ +#define NCP_MOUNT_NO_OS2 0x0008 +#define NCP_MOUNT_NO_NFS 0x0010 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; /* Message notifications come here */ - uid_t mounted_uid; /* Who may umount() this filesystem? */ + __kernel_uid_t mounted_uid; /* Who may umount() this filesystem? */ struct sockaddr_ipx serv_addr; unsigned char server_name[NCP_BINDERY_NAME_LEN]; @@ -40,10 +43,10 @@ unsigned int retry_count; /* And how often should I retry? */ unsigned int flags; - uid_t uid; - gid_t gid; - mode_t file_mode; - mode_t dir_mode; + __kernel_uid_t uid; + __kernel_gid_t gid; + __kernel_mode_t file_mode; + __kernel_mode_t dir_mode; }; #endif diff -urN linux-2.0.33.dist/init/patches/ncpfsnfs.pinfo linux/init/patches/ncpfsnfs.pinfo --- linux-2.0.33.dist/init/patches/ncpfsnfs.pinfo Thu Jan 1 01:00:00 1970 +++ linux/init/patches/ncpfsnfs.pinfo Thu Feb 12 20:50:38 1998 @@ -0,0 +1 @@ +NCPFS extensions 2.0.11.15 (Petr Vandrovec , Arne de Bruijn and more)