diff options
author | 2000-06-17 17:16:04 +0000 | |
---|---|---|
committer | 2000-06-17 17:16:04 +0000 | |
commit | e992cbe461beb200ab4a608f15221ab77469ac6f (patch) | |
tree | 396d8bca32faf371a2a7330a5b07e23144b8f5d4 | |
parent | some silly error repairs (diff) | |
download | wireguard-openbsd-e992cbe461beb200ab4a608f15221ab77469ac6f.tar.xz wireguard-openbsd-e992cbe461beb200ab4a608f15221ab77469ac6f.zip |
initial import of tcfs.
27 files changed, 3556 insertions, 5 deletions
diff --git a/sys/conf/files b/sys/conf/files index 396c56abcb8..9fbf1874a92 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,4 +1,4 @@ -# $OpenBSD: files,v 1.168 2000/06/12 17:23:49 itojun Exp $ +# $OpenBSD: files,v 1.169 2000/06/17 17:16:04 provos Exp $ # $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 @@ -434,6 +434,21 @@ file miscfs/kernfs/kernfs_vnops.c kernfs file miscfs/nullfs/null_subr.c nullfs file miscfs/nullfs/null_vfsops.c nullfs file miscfs/nullfs/null_vnops.c nullfs +file miscfs/tcfs/tcfs_subr.c tcfs +file miscfs/tcfs/tcfs_vfsops.c tcfs +file miscfs/tcfs/tcfs_vnops.c tcfs +file miscfs/tcfs/tcfs_attr.c tcfs +file miscfs/tcfs/tcfs_cipher_TDES.c tcfs +file miscfs/tcfs/tcfs_cipher_BLOWFISH.c tcfs +file miscfs/tcfs/tcfs_cipher_conf.c tcfs +file miscfs/tcfs/tcfs_cipher_none.c tcfs +file miscfs/tcfs/tcfs_cmd.c tcfs +file miscfs/tcfs/tcfs_crypto.c tcfs +file miscfs/tcfs/tcfs_dir.c tcfs +file miscfs/tcfs/tcfs_fileinfo.c tcfs +file miscfs/tcfs/tcfs_interp.c tcfs +file miscfs/tcfs/tcfs_keytab.c tcfs +file miscfs/tcfs/tcfs_rw.c tcfs file miscfs/portal/portal_vfsops.c portal file miscfs/portal/portal_vnops.c portal file miscfs/procfs/procfs_ctl.c procfs diff --git a/sys/kern/vfs_conf.c b/sys/kern/vfs_conf.c index a08299bdaca..96c7a45c921 100644 --- a/sys/kern/vfs_conf.c +++ b/sys/kern/vfs_conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vfs_conf.c,v 1.14 2000/02/07 04:53:33 assar Exp $ */ +/* $OpenBSD: vfs_conf.c,v 1.15 2000/06/17 17:16:05 provos Exp $ */ /* $NetBSD: vfs_conf.c,v 1.21.4.1 1995/11/01 00:06:26 jtc Exp $ */ /* @@ -151,6 +151,10 @@ extern struct vfsops ext2fs_vfsops; extern struct vfsops xfs_vfsops; #endif +#ifdef TCFS +extern struct vfsops tcfs_vfsops; +#endif + /* * Set up the filesystem operations for vnodes. */ @@ -239,6 +243,10 @@ static struct vfsconf vfsconflist[] = { { &kernfs_vfsops, MOUNT_KERNFS, 11, 0, 0, NULL, NULL }, #endif +#ifdef TCFS + { &tcfs_vfsops, MOUNT_TCFS, 22, 0, 0, NULL, NULL }, +#endif + }; @@ -285,6 +293,7 @@ extern struct vnodeopv_desc ext2fs_vnodeop_opv_desc; extern struct vnodeopv_desc ext2fs_specop_opv_desc; extern struct vnodeopv_desc ext2fs_fifoop_opv_desc; extern struct vnodeopv_desc xfs_vnodeop_opv_desc; +extern struct vnodeopv_desc tcfs_vnodeop_opv_desc; struct vnodeopv_desc *vfs_opv_descs[] = { &sync_vnodeop_opv_desc, @@ -361,5 +370,9 @@ struct vnodeopv_desc *vfs_opv_descs[] = { #ifdef XFS &xfs_vnodeop_opv_desc, #endif +#ifdef TCFS + &tcfs_vnodeop_opv_desc, +#endif + NULL }; diff --git a/sys/miscfs/tcfs/tcfs.h b/sys/miscfs/tcfs/tcfs.h new file mode 100644 index 00000000000..d801376fe37 --- /dev/null +++ b/sys/miscfs/tcfs/tcfs.h @@ -0,0 +1,89 @@ +#ifndef _TCFS_MOUNT_H_ +#include "tcfs_mount.h" +#endif + +#ifdef _KERNEL +/* + * A cache of vnode references + */ +struct tcfs_node { + LIST_ENTRY(tcfs_node) tcfs_hash; /* Hash list */ + struct vnode *tcfs_lowervp; /* VREFed once */ + struct vnode *tcfs_vnode; /* Back pointer */ +}; + +extern int tcfs_node_create __P((struct mount *mp, struct vnode *target, struct vnode **vpp, int lockit)); + +#define MOUNTTOTCFSMOUNT(mp) ((struct tcfs_mount *)((mp)->mnt_data)) +#define VTOTCFS(vp) ((struct tcfs_node *)(vp)->v_data) +#define TCFSTOV(xp) ((xp)->tcfs_vnode) +#ifdef TCFS_DIAGNOSTIC +extern struct vnode *tcfs_checkvp __P((struct vnode *vp, char *fil, int lno)); +#define TCFSVPTOLOWERVP(vp) tcfs_checkvp((vp), __FILE__, __LINE__) +#else +#define TCFSVPTOLOWERVP(vp) (VTOTCFS(vp)->tcfs_lowervp) +#endif + +#define TCFS_VP2UKT(vp) ((MOUNTTOTCFSMOUNT(((vp)->v_mount)))->tcfs_uid_kt) +#define TCFS_VP2GKT(vp) ((MOUNTTOTCFSMOUNT(((vp)->v_mount)))->tcfs_gid_kt) + +#define tcfs_fhtovp ((int (*) __P((struct mount *, struct fid *, \ + struct vnode **)))eopnotsupp) +#define tcfs_vptofh ((int (*) __P((struct vnode *, struct fid *)))eopnotsupp) + +extern int (**tcfs_vnodeop_p) __P((void *)); +extern struct vfsops tcfs_vfsops; + +int tcfs_init __P((struct vfsconf *)); + +#define BLOCKSIZE 1024 +#define SBLOCKSIZE 8 + +#define ABS(a) ((a)>=0?(a):(-a)) + +/* variabili esterne */ + + +/* prototyphes */ + +int tcfs_bypass __P((void *)); +int tcfs_open __P((void *)); +int tcfs_getattr __P((void *)); +int tcfs_setattr __P((void *)); +int tcfs_inactive __P((void *)); +int tcfs_reclaim __P((void *)); +int tcfs_print __P((void *)); +int tcfs_strategy __P((void *)); +int tcfs_bwrite __P((void *)); +int tcfs_lock __P((void *)); +int tcfs_unlock __P((void *)); +int tcfs_islocked __P((void *)); +int tcfs_read __P((void *)); +int tcfs_readdir __P((void *)); +int tcfs_write __P((void *)); +int tcfs_create __P((void *)); +int tcfs_mknod __P((void *)); +int tcfs_mkdir __P((void *)); +int tcfs_link __P((void *)); +int tcfs_symlink __P((void *)); +int tcfs_rename __P((void *)); +int tcfs_lookup __P((void *)); + +void *tcfs_getukey(struct ucred *, struct proc *, struct vnode *); +void *tcfs_getpkey(struct ucred *, struct proc *, struct vnode *); +void *tcfs_getgkey(struct ucred *, struct proc *, struct vnode *); +int tcfs_checkukey(struct ucred *, struct proc *, struct vnode *); +int tcfs_checkpkey(struct ucred *, struct proc *, struct vnode *); +int tcfs_checkgkey(struct ucred *, struct proc *, struct vnode *); +int tcfs_exec_cmd(struct tcfs_mount*, struct tcfs_args *); +int tcfs_init_mp(struct tcfs_mount*, struct tcfs_args *); +int tcfs_set_status(struct tcfs_mount *, struct tcfs_args *, int); + +#define TCFS_CHECK_AKEY(c,p,v) (\ + tcfs_checkukey((c),(p),(v)) || \ + tcfs_checkpkey((c),(p),(v)) || \ + tcfs_checkgkey((c),(p),(v)) ) + +#endif /* _KERNEL */ + + diff --git a/sys/miscfs/tcfs/tcfs_attr.c b/sys/miscfs/tcfs/tcfs_attr.c new file mode 100644 index 00000000000..de5efa2aa8f --- /dev/null +++ b/sys/miscfs/tcfs/tcfs_attr.c @@ -0,0 +1,129 @@ +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/vnode.h> +#include <sys/mount.h> +#include <sys/namei.h> +#include <sys/malloc.h> +#include <sys/buf.h> +#include <miscfs/tcfs/tcfs.h> +#include "tcfs_rw.h" + +int +tcfs_getattr(v) + void *v; +{ + struct vop_getattr_args *ap = v; + int error; + tcfs_fileinfo i; + if ((error = tcfs_bypass(ap)) != 0) + return (error); + /* Requires that arguments be restored. */ + + ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; + i.flag=ap->a_vap->va_flags; + ap->a_vap->va_size-=FI_SPURE(&i); + + return (0); +} + + +int +tcfs_setattr(v) +void *v; +{ + struct vop_setattr_args *a = v; + struct vattr *ap; + u_quad_t size=0; + tcfs_fileinfo i,n; + int error,sp=0; + + + i=tcfs_xgetflags(a->a_vp,a->a_p,a->a_cred); + ap=a->a_vap; + + if(FI_GSHAR(&i)) + { + if(!tcfs_getgkey(a->a_cred,a->a_p,a->a_vp)) + { + return EACCES; + } + } + else + { + if (!tcfs_getpkey(a->a_cred,a->a_p,a->a_vp)) + if (!tcfs_getukey(a->a_cred,a->a_p,a->a_vp)) + { + return EACCES; + } + } + + if ((ap->va_flags)!=VNOVAL) + { + + + n.flag=ap->va_flags; + n.end_of_file=i.end_of_file; + + if((FI_CFLAG(&n)&&FI_GSHAR(&i))||(FI_GSHAR(&n)&&FI_CFLAG(&i))) + { + return EACCES; + } + + if(FI_SPURE(&n)!=FI_SPURE(&i)) + { + /* le spure no (le settano solo write e trunc) */ + return EACCES; + } + + if(FI_CFLAG(&n)&&(!FI_CFLAG(&i))) + { + sp=tcfs_ed(a->a_vp, a->a_p, a->a_cred, &n); + FI_SET_SP(&n,sp); + } + + if((!FI_CFLAG(&n))&&FI_CFLAG(&i)) + { + sp=tcfs_ed(a->a_vp, a->a_p, a->a_cred, &n); + FI_SET_SP(&n,0); + } + + if(FI_GSHAR(&n)&&(!FI_GSHAR(&i))) + { + sp=tcfs_ed(a->a_vp, a->a_p, a->a_cred, &n); + FI_SET_SP(&n,sp); + } + + if((!FI_GSHAR(&n))&&FI_GSHAR(&i)) + { + sp=tcfs_ed(a->a_vp, a->a_p, a->a_cred, &n); + FI_SET_SP(&n,0); + } + + + ap->va_flags=i.flag=n.flag; + if(a->a_vp->v_type==VREG) + { + ap->va_size=FI_ENDOF(&i)+sp; + error=tcfs_xsetflags(a->a_vp, a->a_p,a->a_cred,&i); + } + return tcfs_bypass((void*)v); + } + if ((ap->va_size)!=VNOVAL) + { + + if(ap->va_size == 0) + size=0; + else + size=(u_quad_t)(D_PFOFF(ap->va_size)+1); + + FI_SET_SP(&i,(size-ap->va_size)); + ap->va_size=size; + error=tcfs_xsetflags(a->a_vp, a->a_p,a->a_cred,&i); + } + + return tcfs_bypass((void*)v); +} + diff --git a/sys/miscfs/tcfs/tcfs_cipher.h b/sys/miscfs/tcfs/tcfs_cipher.h new file mode 100644 index 00000000000..cb09bfd6d29 --- /dev/null +++ b/sys/miscfs/tcfs/tcfs_cipher.h @@ -0,0 +1,84 @@ +#ifndef _TCFS_MOUNT_H_ +#include "tcfs_mount.h" +#endif + +#define _TCFS_CIPHER_H_ +#define MaxNumOfCipher 8 +#define MaxCipherNameLen 8 + +enum { + C_TDES=0,C_BLOW=2 + } ; + +struct tcfs_cipher + { + char cipher_desc[MaxCipherNameLen]; + int cipher_version; + int cipher_keysize; + void *(*init_key)(char*); + void (*cleanup_key)(void*); + void (*encrypt)(char*, int, void*); + void (*decrypt)(char*, int, void*); + }; + +extern struct tcfs_cipher tcfs_cipher_vect[MaxNumOfCipher]; + +#define TCFS_MP_CIPHER(mp) (((struct tcfs_mount*)(mp))->tcfs_cipher_num) + +#define TCFS_CIPHER_KEYSIZE(mp)\ + (tcfs_cipher_vect[TCFS_MP_CIPHER((mp))].cipher_keysize) + +#define TCFS_CIPHER_VERSION(mp)\ + (tcfs_cipher_vect[TCFS_MP_CIPHER((mp))].cipher_version) + +#define TCFS_CIPHER_DESC(mp)\ + (tcfs_cipher_vect[TCFS_MP_CIPHER((mp))].cipher_desc) + +static __inline void *TCFS_INIT_KEY(struct tcfs_mount *,char *); +static __inline void *TCFS_INIT_KEY(struct tcfs_mount *mp, char *tok) +{ + return (tcfs_cipher_vect[TCFS_MP_CIPHER((mp))].init_key((tok))); +} + +static __inline void TCFS_CLEANUP_KEY(struct tcfs_mount*,void*); +static __inline void TCFS_CLEANUP_KEY(struct tcfs_mount* mp,void* tok) +{ + (tcfs_cipher_vect[TCFS_MP_CIPHER((mp))].cleanup_key((tok))); + return; +} +static __inline void TCFS_ENCRYPT(struct tcfs_mount*,char*,int,void*); +static __inline void TCFS_ENCRYPT(struct tcfs_mount *mp,char *blk,int len,void *key) +{ + (tcfs_cipher_vect[TCFS_MP_CIPHER((mp))].encrypt((blk),(len),(key))); + return; +} +static __inline void TCFS_DECRYPT(struct tcfs_mount*,char*,int,void*); +static __inline void TCFS_DECRYPT(struct tcfs_mount *mp,char *blk,int len,void *key) +{ + (tcfs_cipher_vect[TCFS_MP_CIPHER((mp))].decrypt((blk),(len),(key))); + return; +} + +void mkencrypt (struct tcfs_mount *, char *, int, void*); +void mkdecrypt (struct tcfs_mount *, char *, int, void*); + +/* prototipi funzioni */ + +void *cnone_init_key(char *); +void cnone_cleanup_key(void*); +void cnone_encrypt(char *, int , void*); +void cnone_decrypt(char *, int , void*); +#define NONE_KEYSIZE 0 + +void *TDES_init_key(char *); +void TDES_cleanup_key(void*); +void TDES_encrypt(char *, int , void*); +void TDES_decrypt(char *, int , void*); +#define TDES_KEYSIZE 8 + +void *BLOWFISH_init_key(char *); +void BLOWFISH_cleanup_key(void*); +void BLOWFISH_encrypt(char *, int , void*); +void BLOWFISH_decrypt(char *, int , void*); +#define BLOWFISH_KEYSIZE 8 + diff --git a/sys/miscfs/tcfs/tcfs_cipher_BLOWFISH.c b/sys/miscfs/tcfs/tcfs_cipher_BLOWFISH.c new file mode 100644 index 00000000000..dc1424edbac --- /dev/null +++ b/sys/miscfs/tcfs/tcfs_cipher_BLOWFISH.c @@ -0,0 +1,40 @@ +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include "tcfs_cipher.h" +#include "crypto/blf.h" + + +void * +BLOWFISH_init_key (char *key) +{ + blf_ctx *ks=NULL; + + ks=(blf_ctx *)malloc (sizeof (blf_ctx), M_FREE, M_NOWAIT); + if (!ks) + return NULL; + + blf_key (ks, key, BLOWFISH_KEYSIZE); + + return (void *)ks; +} + +void +BLOWFISH_cleanup_key(void *k) +{ + free((blf_ctx *)k, M_FREE); +} + +void +BLOWFISH_encrypt(char *block, int nb, void *key) +{ + char iv[] = {'\0','\0','\0','\0','\0','\0','\0','\0'}; + blf_cbc_encrypt((blf_ctx *)key, iv, block, nb); +} + +void +BLOWFISH_decrypt(char *block, int nb, void *key) +{ + char iv[] = {'\0','\0','\0','\0','\0','\0','\0','\0'}; + blf_cbc_decrypt((blf_ctx *)key, iv, block, nb); +} diff --git a/sys/miscfs/tcfs/tcfs_cipher_TDES.c b/sys/miscfs/tcfs/tcfs_cipher_TDES.c new file mode 100644 index 00000000000..b7e77dd84e8 --- /dev/null +++ b/sys/miscfs/tcfs/tcfs_cipher_TDES.c @@ -0,0 +1,73 @@ +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include "tcfs_cipher.h" +#include <crypto/des_locl.h> +#include <crypto/des.h> + +void *TDES_init_key (char *key) +{ + des_key_schedule *ks; + + ks=(des_key_schedule *)malloc (2*sizeof (des_key_schedule), M_FREE,M_NOWAIT); + if (!ks) + return NULL; + + des_set_key ((des_cblock *)key, ks[0]); + des_set_key ((des_cblock *)(key+8), ks[1]); + + return (void *)ks; +} + +void TDES_cleanup_key(void *k) +{ +/* tcfs_keytab_dispnode does it + free((des_key_schedule*)k,M_FREE); +*/ +} + +void TDES_encrypt(char *block, int nb, void *key) +{ + unsigned long * xi; + int i; + char *tmp; + des_key_schedule *ks=(des_key_schedule *)key; + xi=(long *)block; + tmp=block; + des_ecb3_encrypt((des_cblock *)tmp,(des_cblock *)tmp,ks[0],ks[1],ks[0],DES_ENCRYPT); + tmp+=8; + for (i=1;i<nb/8;i++) { + *(xi+2)^=*xi; + *(xi+3)^=*(xi+1); + des_ecb3_encrypt((des_cblock *)tmp,(des_cblock *)tmp,ks[0],ks[1],ks[0],DES_ENCRYPT); + tmp+=8; + xi+=2; + } +} + +void TDES_decrypt(char *block, int nb, void *key) +{ + unsigned long * xi,xo[2],xa[2]; + int i; + char *tmp; + des_key_schedule *ks=(des_key_schedule *)key; + + xi=(long *)block; + tmp=block; + xo[0]=*xi; xo[1]=*(xi+1); + des_ecb3_encrypt((des_cblock *)tmp,(des_cblock *)tmp,ks[0],ks[1],ks[0],DES_DECRYPT); + tmp+=8; + xi=(long *)tmp; + for (i=1;i<nb/8;i++) { + xa[0]=*xi; xa[1]=*(xi+1); + des_ecb3_encrypt((des_cblock *)tmp,(des_cblock *)tmp,ks[0],ks[1],ks[0],DES_DECRYPT); + *(xi)^=xo[0]; + *(xi+1)^=xo[1]; + xo[0]=xa[0]; + xo[1]=xa[1]; + tmp+=8; + xi+=2; + } +} + + diff --git a/sys/miscfs/tcfs/tcfs_cipher_conf.c b/sys/miscfs/tcfs/tcfs_cipher_conf.c new file mode 100644 index 00000000000..bd86f8b2c00 --- /dev/null +++ b/sys/miscfs/tcfs/tcfs_cipher_conf.c @@ -0,0 +1,21 @@ +#include "tcfs_cipher.h" + +struct tcfs_cipher tcfs_cipher_vect[]={ + {"3des",0,TDES_KEYSIZE,TDES_init_key,TDES_cleanup_key, + TDES_encrypt,TDES_decrypt}, + {"none",0,0,cnone_init_key,cnone_cleanup_key, + cnone_encrypt,cnone_decrypt}, + {"bfish",0,BLOWFISH_KEYSIZE,BLOWFISH_init_key,BLOWFISH_cleanup_key, + BLOWFISH_encrypt,BLOWFISH_decrypt}, + {"none",0,0,cnone_init_key,cnone_cleanup_key, + cnone_encrypt,cnone_decrypt}, + {"none",0,0,cnone_init_key,cnone_cleanup_key, + cnone_encrypt,cnone_decrypt}, + {"none",0,0,cnone_init_key,cnone_cleanup_key, + cnone_encrypt,cnone_decrypt}, + {"none",0,0,cnone_init_key,cnone_cleanup_key, + cnone_encrypt,cnone_decrypt}, + {"none",0,0,cnone_init_key,cnone_cleanup_key, + cnone_encrypt,cnone_decrypt}, +}; + diff --git a/sys/miscfs/tcfs/tcfs_cipher_none.c b/sys/miscfs/tcfs/tcfs_cipher_none.c new file mode 100644 index 00000000000..fd107ab228f --- /dev/null +++ b/sys/miscfs/tcfs/tcfs_cipher_none.c @@ -0,0 +1,18 @@ +#include "tcfs_cipher.h" + +void *cnone_init_key (char *key) +{ + return (void *)key; +} + +void cnone_cleanup_key(void *k) +{ +} + +void cnone_encrypt(char *block, int nb, void *key) +{ +} + +void cnone_decrypt(char *block, int nb, void *key) +{ +} diff --git a/sys/miscfs/tcfs/tcfs_cmd.c b/sys/miscfs/tcfs/tcfs_cmd.c new file mode 100644 index 00000000000..d8da2b8d221 --- /dev/null +++ b/sys/miscfs/tcfs/tcfs_cmd.c @@ -0,0 +1,205 @@ +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/vnode.h> +#include <sys/mount.h> +#include <sys/namei.h> +#include <sys/malloc.h> +#include <sys/buf.h> +#include <miscfs/tcfs/tcfs.h> +#include "tcfs_rw.h" +#ifndef _TCFS_KEYTAB_H_ +#include "tcfs_keytab.h" +#endif +#include "tcfs_cmd.h" +#include "tcfs_cipher.h" + +int tcfs_init_mp(struct tcfs_mount *mp, struct tcfs_args *req) +{ + int result=0; + int status=0; + + if (!(mp->tcfs_uid_kt=tcfs_keytab_init())) + { + result= ENOMEM; + status= ALLOCATION_FAILED; + } + else + { + if (!(mp->tcfs_gid_kt=tcfs_keytab_init())) + { + tcfs_keytab_dispose(mp->tcfs_uid_kt); + status= ALLOCATION_FAILED; + result= ENOMEM; + } + else + { + if ((req->cipher_num>=MaxNumOfCipher)|| + (tcfs_cipher_vect[req->cipher_num].cipher_keysize==0)) + { + result=EINVAL; + status=BAD_CIPHER_NUMBER; + tcfs_keytab_dispose(mp->tcfs_uid_kt); + tcfs_keytab_dispose(mp->tcfs_gid_kt); + } + else + mp->tcfs_cipher_num=req->cipher_num; + } + } + + (void)tcfs_set_status(mp,req,status); + return result; +} + +int tcfs_exec_cmd(struct tcfs_mount *mp, struct tcfs_args *req) +{ + void *ks; + int result=0; + int status=0; + + + switch (req->cmd) + { + case TCFS_PUT_UIDKEY: + ks=TCFS_INIT_KEY(mp,req->tcfs_key); + if(!ks) + { + result= ENOMEM; + status= ALLOCATION_FAILED; + break; + } + result=tcfs_keytab_push_uid(mp->tcfs_uid_kt,req->user,ks); + if(result) + { + TCFS_CLEANUP_KEY(mp,ks); + status=PUSHKEY_ERROR; + } + break; + + case TCFS_RM_UIDKEY: + result = tcfs_keytab_rm_uid(mp->tcfs_uid_kt,req->user); + status=(result?RMKEY_ERROR:TCFS_OK); + break; + + case TCFS_PUT_PIDKEY: + ks=TCFS_INIT_KEY(mp,req->tcfs_key); + if(!ks) + { + result= ENOMEM; + status= ALLOCATION_FAILED; + break; + } + result=tcfs_keytab_push_pid(mp->tcfs_uid_kt,req->user,req->proc,ks); + if(result) + { + TCFS_CLEANUP_KEY(mp,ks); + status=PUSHKEY_ERROR; + } + break; + + case TCFS_RM_PIDKEY: + result=tcfs_keytab_rm_pid(mp->tcfs_uid_kt,req->user,req->proc); + status=(result?RMKEY_ERROR:TCFS_OK); + break; + + case TCFS_PUT_GIDKEY: + result=tcfs_keytab_push_gid(mp,mp->tcfs_gid_kt,req->user,req->group,req->treshold,req->tcfs_key); + + status=(result?PUSHKEY_ERROR:TCFS_OK); + break; + + case TCFS_RM_GIDKEY: + result= tcfs_keytab_rm_gid(mp->tcfs_gid_kt,req->user,req->group); + status=(result?RMKEY_ERROR:TCFS_OK); + break; + + case TCFS_GET_STATUS: + return tcfs_set_status(mp,req,TCFS_OK); + } + (void)tcfs_set_status(mp,req,status); + return result; +} + +int tcfs_set_status(struct tcfs_mount *mp, struct tcfs_args *req, int error) +{ + req->st.status=error; + req->st.tcfs_version=TCFS_VERSION_NUM; + + if(error!=TCFS_OK) + return error; + + req->st.n_ukey=mp->tcfs_uid_kt->cnt; + req->st.n_gkey=mp->tcfs_gid_kt->cnt; + strncpy(req->st.cipher_desc,TCFS_CIPHER_DESC(mp),MaxCipherNameLen); + req->st.cipher_keysize=TCFS_CIPHER_KEYSIZE(mp); + req->st.cipher_version=TCFS_CIPHER_VERSION(mp); + + return error; +} + +int tcfs_checkukey(struct ucred *c, struct proc *p, struct vnode *vp) +{ + return tcfs_keytab_check_uid(TCFS_VP2UKT(vp),c->cr_uid); +} + +void *tcfs_getukey(struct ucred *c, struct proc *p, struct vnode *vp) +{ + tcfs_keytab_node *n; + + n=tcfs_keytab_fetch_uid(TCFS_VP2UKT(vp),c->cr_uid); + + if(n) + return n->kn_key; + else + { + return (void*)NULL; + } +} +int tcfs_checkpkey(struct ucred *c, struct proc *p, struct vnode *vp) +{ + struct proc *cp; + if(!p) + cp=curproc; + else + cp=p; + + return tcfs_keytab_check_pid(TCFS_VP2UKT(vp),c->cr_uid,cp->p_pid); +} + +void *tcfs_getpkey(struct ucred *c, struct proc *p, struct vnode *vp) +{ + tcfs_keytab_node *n; + struct proc *cp; + + if(!p) + cp=curproc; + else + cp=p; + + n=tcfs_keytab_fetch_pid(TCFS_VP2UKT(vp),c->cr_uid,cp->p_pid); + + if(n) + return n->kn_key; + else + return (void*)NULL; +} + +int tcfs_checkgkey(struct ucred *c, struct proc *p, struct vnode *vp) +{ + return tcfs_keytab_check_uid(TCFS_VP2GKT(vp),c->cr_gid); +} + +void *tcfs_getgkey(struct ucred *c, struct proc *p, struct vnode *vp) +{ + tcfs_keytab_node *n; + + n=tcfs_keytab_fetch_gid(TCFS_VP2GKT(vp),c->cr_gid); + + if(n) + return n->kn_key; + else + return (void*)NULL; +} + diff --git a/sys/miscfs/tcfs/tcfs_cmd.h b/sys/miscfs/tcfs/tcfs_cmd.h new file mode 100644 index 00000000000..a4b7d841dbc --- /dev/null +++ b/sys/miscfs/tcfs/tcfs_cmd.h @@ -0,0 +1,17 @@ +/* tcfs commands */ +#define TCFS_PUT_UIDKEY 1 +#define TCFS_RM_UIDKEY 2 +#define TCFS_PUT_PIDKEY 3 +#define TCFS_RM_PIDKEY 4 +#define TCFS_PUT_GIDKEY 5 +#define TCFS_RM_GIDKEY 6 +#define TCFS_GET_STATUS 7 + +/* tcfs errors */ +#define TCFS_OK 0 +#define UNKNOWN_COMMAND 1 +#define BAD_CIPHER_NUMBER 2 +#define PUSHKEY_ERROR 3 +#define RMKEY_ERROR 3 +#define ALLOCATION_FAILED 4 + diff --git a/sys/miscfs/tcfs/tcfs_crypto.c b/sys/miscfs/tcfs/tcfs_crypto.c new file mode 100644 index 00000000000..e9d1782ffa3 --- /dev/null +++ b/sys/miscfs/tcfs/tcfs_crypto.c @@ -0,0 +1,38 @@ +#include "tcfs_cipher.h" + +#define BLOCKSIZE 1024 +#define SBLOCKSIZE 8 +#define MIN(a,b) ((a)<(b)?(a):(b)) +#define D_NOBLK(o) ((o)/BLOCKSIZE+(o%BLOCKSIZE?1:0)) + + +void mkencrypt(struct tcfs_mount *mp,char *block,int nb, void* ks) +{ + int i,r; + char *tmp; + + tmp=block; + r=nb; + for(i=0;i<D_NOBLK(nb)&&r>0;i++) + { + TCFS_ENCRYPT(mp,tmp,MIN(BLOCKSIZE,r),ks); + tmp+=BLOCKSIZE; + r-=BLOCKSIZE; + } +} + +void mkdecrypt(struct tcfs_mount *mp,char *block,int nb,void* ks) +{ + int i,r; + char *tmp; + + tmp=block; + r=nb; + for(i=0;i<D_NOBLK(nb)&&r>0;i++) + { + TCFS_DECRYPT(mp, tmp,MIN(BLOCKSIZE,r),ks); + tmp+=BLOCKSIZE; + r-=BLOCKSIZE; + } +} + diff --git a/sys/miscfs/tcfs/tcfs_dir.c b/sys/miscfs/tcfs/tcfs_dir.c new file mode 100644 index 00000000000..f58ae871056 --- /dev/null +++ b/sys/miscfs/tcfs/tcfs_dir.c @@ -0,0 +1,188 @@ +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/vnode.h> +#include <sys/mount.h> +#include <sys/namei.h> +#include <sys/malloc.h> +#include <sys/buf.h> +#include <sys/dirent.h> +#include <miscfs/tcfs/tcfs.h> +#include "tcfs_rw.h" + +int tcfs_new_direntry (void *, tcfs_fileinfo *); + +int tcfs_new_direntry(void *v , tcfs_fileinfo *i) +{ + struct vop_create_args *x; + struct ucred *cr; + struct proc *pr; + int err; + + x=(struct vop_create_args *)v; + cr=x->a_cnp->cn_cred; + pr=x->a_cnp->cn_proc; + + if(!TCFS_CHECK_AKEY(cr,pr,x->a_dvp)) + return tcfs_bypass(v); + + /* Per i file speciali e per i link, niente flags (per ora)*/ + if((x->a_desc==VDESC(vop_mknod))|| + (x->a_desc==VDESC(vop_symlink))|| + (x->a_desc==VDESC(vop_link))) + { + err=tcfs_bypass(v); + return err; + } + + if(!(err=tcfs_bypass(v))) + err=tcfs_xsetflags(*(x->a_vpp),pr,cr,i); + + return err; +} + +int tcfs_create(v) +void *v; +{ + struct vop_create_args *x; + struct ucred *cr; + struct proc *pr; + tcfs_fileinfo i; + + x=(struct vop_create_args *)v; + cr=x->a_cnp->cn_cred; + pr=x->a_cnp->cn_proc; + i=tcfs_xgetflags(x->a_dvp,pr,cr); + + if(FI_CFLAG(&i)||FI_GSHAR(&i)) + return tcfs_new_direntry(v,&i); + else + return tcfs_bypass(v); +} + +int tcfs_mknod(v) +void *v; +{ + struct vop_mknod_args *x; + struct ucred *cr; + struct proc *pr; + tcfs_fileinfo i; + + x=(struct vop_mknod_args *)v; + cr=x->a_cnp->cn_cred; + pr=x->a_cnp->cn_proc; + i=tcfs_xgetflags(x->a_dvp,pr,cr); + + if(FI_CFLAG(&i)||FI_GSHAR(&i)) + return tcfs_new_direntry(v,&i); + else + return tcfs_bypass(v); +} + +int tcfs_mkdir(v) +void *v; +{ + struct vop_mkdir_args *x; + struct ucred *cr; + struct proc *pr; + tcfs_fileinfo i; + + x=(struct vop_mkdir_args *)v; + cr=x->a_cnp->cn_cred; + pr=x->a_cnp->cn_proc; + i=tcfs_xgetflags(x->a_dvp,pr,cr); + + if(FI_CFLAG(&i)||FI_GSHAR(&i)) + return tcfs_new_direntry(v,&i); + else + return tcfs_bypass(v); +} + +int tcfs_link(v) +void *v; +{ + struct vop_link_args *x; + struct ucred *cr; + struct proc *pr; + tcfs_fileinfo i; + + x=(struct vop_link_args *)v; + cr=x->a_cnp->cn_cred; + pr=x->a_cnp->cn_proc; + i=tcfs_xgetflags(x->a_dvp,pr,cr); + + if(FI_CFLAG(&i)||FI_GSHAR(&i)) + return tcfs_new_direntry(v,&i); + else + return tcfs_bypass(v); +} + +int tcfs_symlink(v) +void *v; +{ + struct vop_symlink_args *x; + struct ucred *cr; + struct proc *pr; + tcfs_fileinfo i; + + x=(struct vop_symlink_args *)v; + cr=x->a_cnp->cn_cred; + pr=x->a_cnp->cn_proc; + i=tcfs_xgetflags(x->a_dvp,pr,cr); + + if(FI_CFLAG(&i)||FI_GSHAR(&i)) + return tcfs_new_direntry(v,&i); + else + return tcfs_bypass(v); +} + +int tcfs_readdir(v) +void *v; +{ +/* + tcfs_fileinfo i; + struct vop_readdir_args *a=(struct vop_readdir_args*)v; + struct dirent *s,*d,*e; + char *p; + int err; + off_t offset; + int req,resid; + + + i=tcfs_xgetflags(a->a_vp,a->a_uio->uio_procp,a->a_cred); + offset=a->a_uio->uio_offset; + req=a->a_uio->uio_resid; + p=a->a_uio->uio_iov->iov_base; + + err=tcfs_bypass(v); + resid=a->a_uio->uio_resid; + + s=(struct dirent*)p; + e=(struct dirent*)a->a_uio->uio_iov->iov_base; + + if( (!FI_CFLAG(&i)) && (!FI_GSHAR(&i)) ) + return err; + + for(d=s; d<e && d->d_reclen;d=(struct dirent*)((char*)d+d->d_reclen)) + { + if(!d->d_fileno) + continue; + if((d->d_namlen==1 && d->d_name[0]=='.') || + (d->d_namlen==2 && d->d_name[0]=='.' && d->d_name[1]=='.')) + continue; + + if(d->d_namlen) + d->d_name[0]--; + } + return err; +*/ + return tcfs_bypass(v); +} + +int tcfs_rename(v) +void *v; +{ + return tcfs_bypass(v); +} diff --git a/sys/miscfs/tcfs/tcfs_fileinfo.c b/sys/miscfs/tcfs/tcfs_fileinfo.c new file mode 100644 index 00000000000..7077ee8f134 --- /dev/null +++ b/sys/miscfs/tcfs/tcfs_fileinfo.c @@ -0,0 +1,75 @@ +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/vnode.h> +#include <sys/mount.h> +#include <sys/namei.h> +#include <sys/malloc.h> +#include <sys/buf.h> +#include <sys/stat.h> +#include <miscfs/tcfs/tcfs.h> +#include "tcfs_rw.h" + + +tcfs_fileinfo tcfs_xgetflags(struct vnode *v, struct proc *p, struct ucred *c) +{ + tcfs_fileinfo r; + struct vop_getattr_args x; + struct vattr att; + int retval; + + att=va_null; + x.a_desc=VDESC(vop_getattr); + x.a_vp=v; + x.a_vap=&att; + x.a_cred=c; + x.a_p=p; + + retval=tcfs_bypass((void*)&x); + r.flag=(unsigned long)(x.a_vap->va_flags); + r.end_of_file=x.a_vap->va_size; + + return r; +} + +int tcfs_xsetflags(struct vnode *v, struct proc *p, struct ucred *c, tcfs_fileinfo *i) +{ + struct vop_setattr_args x; + struct vattr att; + int retval; + + att=va_null; + + att.va_flags=i->flag; + + x.a_desc=VDESC(vop_setattr); + x.a_vp=v; + x.a_vap=&att; + x.a_cred=c; + x.a_p=p; + + retval=tcfs_bypass((void*)&x); + return retval; +} + + + +tcfs_fileinfo tcfs_get_fileinfo(void *a) +{ + struct vop_read_args *arg; + + arg=(struct vop_read_args*)a; + return tcfs_xgetflags(arg->a_vp,arg->a_uio->uio_procp,arg->a_cred); +} + + +int tcfs_set_fileinfo(void *a, tcfs_fileinfo *i) +{ + struct vop_read_args *arg; + + arg=(struct vop_read_args*)a; + return tcfs_xsetflags(arg->a_vp, arg->a_uio->uio_procp,arg->a_cred,i); ; +} + diff --git a/sys/miscfs/tcfs/tcfs_fileinfo.h b/sys/miscfs/tcfs/tcfs_fileinfo.h new file mode 100644 index 00000000000..e64eff4fc75 --- /dev/null +++ b/sys/miscfs/tcfs/tcfs_fileinfo.h @@ -0,0 +1,34 @@ +/* Gestione informazioni sui files cifrati +*/ + + +typedef struct { + unsigned long flag; + unsigned int end_of_file; + } tcfs_fileinfo; + +#define MBFLAG 0x00000010 +#define SPFLAG 0x000000e0 +#define GSFLAG 0x00000100 + +#define FI_CFLAG(x) (((x)->flag&MBFLAG)>>4) +#define FI_SPURE(x) (((x)->flag&SPFLAG)>>5) +#define FI_GSHAR(x) (((x)->flag&GSFLAG)>>8) +#define FI_ENDOF(x) ((x)->end_of_file) + +#define FI_SET_CF(x,y) ((x)->flag=\ + ((x)->flag & (~MBFLAG))|((y<<4)&MBFLAG)) + +#define FI_SET_SP(x,y) ((x)->flag=\ + ((x)->flag & (~SPFLAG))|((y<<5)&SPFLAG)) + +#define FI_SET_GS(x,y) ((x)->flag=\ + ((x)->flag & (~GSFLAG))|((y<<8)&GSFLAG)) + +/* prototipi */ + +tcfs_fileinfo tcfs_get_fileinfo(void *); +tcfs_fileinfo tcfs_xgetflags(struct vnode *,struct proc *,struct ucred*); +int tcfs_set_fileinfo(void *, tcfs_fileinfo *); +int tcfs_xsetflags(struct vnode *, struct proc *, struct ucred *, tcfs_fileinfo *); + diff --git a/sys/miscfs/tcfs/tcfs_interp.c b/sys/miscfs/tcfs/tcfs_interp.c new file mode 100644 index 00000000000..3647a046be6 --- /dev/null +++ b/sys/miscfs/tcfs/tcfs_interp.c @@ -0,0 +1,128 @@ +#include<sys/types.h> +#include<sys/malloc.h> +#include<sys/errno.h> +#include "tcfs_keytab.h" +#include "tcfs_cipher.h" + +int interp(tcfs_grp_data *,unsigned char *); +void doinverse(void); + +static int inverse[]={ + 0,1,129,86,193,103,43,147,225,200,180,187,150,178, + 202,120,241,121,100,230,90,49,222,190,75,72,89,238, + 101,195,60,199,249,148,189,235,50,132,115,145,45,163, + 153,6,111,40,95,175,166,21,36,126,173,97,119,243,179,248, + 226,61,30,59,228,102,253,87,74,234,223,149,246,181,25, + 169,66,24,186,247,201,244,151,165,210,96,205,127,3,65, + 184,26,20,209,176,152,216,46,83,53,139,135,18,28,63,5, + 215,164,177,245,188,224,250,44,218,116,124,38,113,134, + 159,54,15,17,158,140,114,220,51,85,255,2,172,206,37,143, + 117,99,240,242,203,98,123,144,219,133,141,39,213,7,33,69, + 12,80,93,42,252,194,229,239,122,118,204,174,211,41,105, + 81,48,237,231,73,192,254,130,52,161,47,92,106,13,56,10, + 71,233,191,88,232,76,11,108,34,23,183,170,4,155,29,198, + 227,196,31,9,78,14,138,160,84,131,221,236,91,82,162,217, + 146,251,104,94,212,112,142,125,207,22,68,109,8,58,197, + 62,156,19,168,185,182,67,35,208,167,27,157,136,16,137, + 55,79,107,70,77,57,32,110,214,154,64,171,128,256 +}; + +union bobbit { + unsigned char byte; + struct { + unsigned char b1:1; + unsigned char b2:1; + unsigned char b3:1; + unsigned char b4:1; + unsigned char b5:1; + unsigned char b6:1; + unsigned char b7:1; + unsigned char b8:1; + } bf; +}; + +#define mod(a) ((unsigned int)((a)%257)) +/* +unsigned int mod(long a) +{ + return (unsigned int) a%257; +} +*/ + +int interp(tcfs_grp_data *gd,unsigned char *gidkey) +{ + unsigned int tp,kkk; + int i=0,j,l,idx; + tcfs_grp_uinfo ktmp[MAXUSRPERGRP],*gui; + unsigned int inv,ttt; + union bobbit obits; + int k; + + k=gd->gd_k; + + for (i=0;i<MAXUSRPERGRP && i<k;i++) + { + gui=&(gd->gd_part[i]); + if(!IS_SET_GUI(*gui)) + continue; + ktmp[i].gui_uid=gui->gui_uid; + + for(l=0;l<KEYSIZE/8;l++){ + obits.byte=gui->gui_tcfskey[9*l+8]; + ktmp[i].gui_tcfskey[8*l+0]=mod(obits.bf.b1<<8 | gui->gui_tcfskey[9*l+0]); + ktmp[i].gui_tcfskey[8*l+1]=mod(obits.bf.b2<<8 | gui->gui_tcfskey[9*l+1]); + ktmp[i].gui_tcfskey[8*l+2]=mod(obits.bf.b3<<8 | gui->gui_tcfskey[9*l+2]); + ktmp[i].gui_tcfskey[8*l+3]=mod(obits.bf.b4<<8 | gui->gui_tcfskey[9*l+3]); + ktmp[i].gui_tcfskey[8*l+4]=mod(obits.bf.b5<<8 | gui->gui_tcfskey[9*l+4]); + ktmp[i].gui_tcfskey[8*l+5]=mod(obits.bf.b6<<8 | gui->gui_tcfskey[9*l+5]); + ktmp[i].gui_tcfskey[8*l+6]=mod(obits.bf.b7<<8 | gui->gui_tcfskey[9*l+6]); + ktmp[i].gui_tcfskey[8*l+7]=mod(obits.bf.b8<<8 | gui->gui_tcfskey[9*l+7]); + } + + i++; + } + + for (idx=0;idx<KEYSIZE;idx++) { + kkk=0; + for (i=0;i<k;i++) { + tp=1; + for (j=0;j<k;j++) { + if (j!=i) { + inv = inverse[mod(ktmp[i].gui_uid-ktmp[j].gui_uid)]; + ttt = mod(inv * mod(-ktmp[j].gui_uid)); + tp = mod(tp * ttt); + } + } + tp *= mod(ktmp[i].gui_tcfskey[idx]); + kkk=(tp+kkk); + } + gidkey[idx]=(unsigned char)mod(kkk); + } + return 0; +} + +void doinverse(void) +{ + int i,j; + for (i=0;i<257;i++) { + for (j=0;j<257;j++) { + if (mod((i*j))==1) + inverse[i]=j; + } + } +} + +int tcfs_interp(struct tcfs_mount *mp, tcfs_keytab_node* x) +{ + void *ks; + char key[KEYSIZE]; + + interp(x->kn_data,key); + ks=TCFS_INIT_KEY(mp,key); + if (!ks) + return ENOMEM; + + x->kn_key=ks; + return TCFS_OK; +} + diff --git a/sys/miscfs/tcfs/tcfs_keytab.c b/sys/miscfs/tcfs/tcfs_keytab.c new file mode 100644 index 00000000000..89fbfa9f602 --- /dev/null +++ b/sys/miscfs/tcfs/tcfs_keytab.c @@ -0,0 +1,457 @@ +#include<sys/errno.h> +#include<sys/types.h> +#include<sys/systm.h> +#ifndef _TCFS_KEYTAB_H_ +#include "tcfs_keytab.h" +#endif +#include<sys/malloc.h> + +tcfs_keytab_node *tcfs_keytab_newnode() +{ + tcfs_keytab_node *n; + + n=(tcfs_keytab_node*)malloc(sizeof(tcfs_keytab_node),M_FREE,M_NOWAIT); + if(!n) + return n; + + n->kn_key=(void*)0; + n->kn_data=(tcfs_grp_data*)0; + n->kn_type=CLEAN; + n->kn_n=n->kn_p=NIL; + return n; +} + +tcfs_keytab_node *tcfs_keytab_newgidnode() +{ + tcfs_keytab_node *n; + tcfs_grp_data *gd; + int i; + + n=tcfs_keytab_newnode(); + if(!n) + return n; + + gd=(tcfs_grp_data*)malloc(sizeof(tcfs_grp_data),M_FREE,M_NOWAIT); + if(!gd) + { + tcfs_keytab_dispnode(n); + return NIL; + } + gd->gd_n=0; + gd->gd_k=0; + for(i=0;i<MAXUSRPERGRP;i++); + { + gd->gd_part[i].gui_flag=GUI_CLEAN; + gd->gd_part[i].gui_uid=65535; /* nobody */ + } + + n->kn_data=gd; + n->kn_type=GID_KEY; + n->kn_key=(void*)0; + + return n; +} + + + +void tcfs_keytab_dispnode(tcfs_keytab_node *n) +{ + if(n->kn_key) + free(n->kn_key,M_FREE); + + + if(n->kn_data) + free(n->kn_data,M_FREE); + + if(n) + free(n,M_FREE); +} + + + +tcfs_keytab *tcfs_keytab_init() +{ + tcfs_keytab *x; + int i; + + x=(tcfs_keytab*)malloc(sizeof(tcfs_keytab),M_FREE,M_NOWAIT); + if (!x) + return x; + + x->cnt=0; + + for(i=0;i<KEYTABSIZE;i++) /*una bzero o simile magari */ + x->node[i]=NIL; + + return x; +} + +void tcfs_keytab_dispose(tcfs_keytab *kt) +{ + tcfs_keytab_node *p,*q; + int i=0; + + if(kt->cnt) + for(i=0;i<KEYTABSIZE;i++) + { + p=kt->node[i]; + while(p!=NIL) + { + q=p->kn_n; + tcfs_keytab_dispnode(p); + p=q; + } + } + + free(kt,M_FREE); +} + +int tcfs_keytab_check_uid(tcfs_keytab *t, uid_t uid) +{ + int pos; + tcfs_keytab_node *p; + + pos=tcfs_keytab_hash(uid); + p=t->node[pos]; + + while(p!=NIL) + { + if (IS_UID_NODE(p) && p->kn_uid==uid) + return 1; + p=p->kn_n; + } + return 0; +} + + +tcfs_keytab_node *tcfs_keytab_fetch_uid(tcfs_keytab *t, uid_t uid) +{ + tcfs_keytab_node *p; + int pos; + + pos=tcfs_keytab_hash(uid); + p=t->node[pos]; + while(p!=NIL) + { + if(IS_UID_NODE(p) && p->kn_uid==uid) + break; + p=p->kn_n; + } + return p; +} + +int tcfs_keytab_check_gid(tcfs_keytab *t, gid_t gid) +{ + tcfs_keytab_node *p; + int pos; + + pos=tcfs_keytab_hash(gid); + p=t->node[pos]; + + while (p!=NIL) + { + if(IS_GID_NODE(p) && p->kn_gid==gid && IS_READY_GD(p->kn_data)) + return 1; + p=p->kn_n; + } + return 0; +} + + +tcfs_keytab_node *tcfs_keytab_fetch_gid(tcfs_keytab *t, gid_t gid) +{ + tcfs_keytab_node *p; + int pos; + + pos=tcfs_keytab_hash(gid); + p=t->node[pos]; + while(p!=NIL) + { + if(IS_GID_NODE(p) && p->kn_gid==gid) + break; + p=p->kn_n; + } + return p; +} + + + +int tcfs_keytab_check_pid(tcfs_keytab *t, uid_t uid, pid_t pid) +{ + int pos; + tcfs_keytab_node *p; + + pos=tcfs_keytab_hash(pid); + p=t->node[pos]; + + while(p!=NIL) + { + if (IS_PID_NODE(p) && p->kn_pid==pid && p->kn_uid==uid) + return 1; + p=p->kn_n; + } + return 0; +} + +tcfs_keytab_node *tcfs_keytab_fetch_pid(tcfs_keytab *t, uid_t uid, pid_t pid) +{ + tcfs_keytab_node *p; + int pos; + + pos=tcfs_keytab_hash(pid); + p=t->node[pos]; + + while(p!=NIL) + { + if(IS_PID_NODE(p) && p->kn_pid==pid && p->kn_uid==uid) + break; + p=p->kn_n; + } + return p; +} + +int tcfs_keytab_push_pid(tcfs_keytab *t, uid_t uid, pid_t pid, void *ks) +{ + int pos=0; + tcfs_keytab_node *p,*q; + + if(tcfs_keytab_fetch_pid(t,uid,pid)!=NIL) + return EINVAL; + + q=tcfs_keytab_newnode(); + if(!q) + return ENOMEM; + + pos=tcfs_keytab_hash(pid); + + p=t->node[pos]; + q->kn_n=p; + if(p!=NIL) + p->kn_p=q; + t->node[pos]=q; + t->cnt++; + + q->kn_uid=uid; + q->kn_pid=pid; + q->kn_key=ks; + q->kn_type=PID_KEY; + + return TCFS_OK; +} + +int tcfs_keytab_push_uid(tcfs_keytab *t, uid_t uid, void *key) +{ + int pos=0; + tcfs_keytab_node *p,*q; + + + if(tcfs_keytab_fetch_uid(t,uid)!=NIL) + return EINVAL; + + q=tcfs_keytab_newnode(); + if(!q) + return ENOMEM; + + pos=tcfs_keytab_hash(uid); + + p=t->node[pos]; + q->kn_n=p; + if(p!=NIL) + p->kn_p=q; + t->node[pos]=q; + t->cnt++; + + q->kn_uid=uid; + q->kn_pid=0; + q->kn_key=key; + q->kn_type=UID_KEY; + + return TCFS_OK; +} + +int tcfs_keytab_push_gidpart(struct tcfs_mount *mp,tcfs_keytab_node *kn,uid_t uid, gid_t gid, int k,char *key) +{ + int i=0; + int first=-1; + tcfs_grp_data *p; + + p=kn->kn_data; + + if(IS_FULL_GD(p)) + return EINVAL; + + for (i=0;i<MAXUSRPERGRP;i++) + { + if(first<0 && !IS_SET_GUI(p->gd_part[i])) + { + first=i; + continue; + } + if(IS_SET_GUI(p->gd_part[i]) && + p->gd_part[i].gui_uid==uid) + return EINVAL; + } + + p->gd_part[first].gui_uid=uid; + p->gd_part[first].gui_flag=GUI_SET; + memcpy(p->gd_part[first].gui_tcfskey,key,KEYPARTSIZE); + if(IS_CLEAN_GD(p)) + p->gd_k=k; + + p->gd_n++; + + if(IS_READY_GD(p)&&(!kn->kn_key)) + tcfs_interp(mp,kn); + + return TCFS_OK; +} + +int tcfs_keytab_rm_gidpart(tcfs_keytab_node *kn, uid_t uid, gid_t gid) +{ + int i=0; + tcfs_grp_data *p; + + p=kn->kn_data; + + if(IS_CLEAN_GD(p)) + return EINVAL; + + for (i=0;i<MAXUSRPERGRP;i++) + if(IS_SET_GUI(p->gd_part[i])) + if(p->gd_part[i].gui_uid==uid) + { + p->gd_part[i].gui_flag=GUI_CLEAN; + break; + } + + if (i==MAXUSRPERGRP) + return EINVAL; + + p->gd_n--; + + if(!IS_READY_GD(p)) + if(kn->kn_key) + { + free(kn->kn_key,M_FREE); + kn->kn_key=(void*)0; + } + + return TCFS_OK; +} + +int tcfs_keytab_push_gid(struct tcfs_mount *mp,tcfs_keytab *t, uid_t uid, gid_t gid, int k, char* key) +{ + int pos=0; + tcfs_keytab_node *p,*q,*r; + + q=r=tcfs_keytab_fetch_gid(t,gid); + + if(r==NIL) + { + q=tcfs_keytab_newgidnode(); + if(!q) + return ENOMEM; + + pos=tcfs_keytab_hash(gid); + + p=t->node[pos]; + q->kn_n=p; + if(p!=NIL) + p->kn_p=q; + t->node[pos]=q; + t->cnt++; + + q->kn_gid=gid; + q->kn_pid=0; + q->kn_uid=0; + } + + return tcfs_keytab_push_gidpart(mp,q,uid,gid,k,key); +} + +int tcfs_keytab_rm_uid(tcfs_keytab *t, uid_t uid) +{ + int pos=0; + tcfs_keytab_node *p; + + p=tcfs_keytab_fetch_uid(t,uid); + if(p==NIL) + return EINVAL; + + if(p->kn_p==NIL) + { + pos=tcfs_keytab_hash(uid); + t->node[pos]=p->kn_n; + } + else + p->kn_p->kn_n=p->kn_n; + + if(p->kn_n!=NIL) + p->kn_n->kn_p=p->kn_p; + + t->cnt--; + tcfs_keytab_dispnode(p); + + return TCFS_OK; +} + +int tcfs_keytab_rm_pid(tcfs_keytab *t, uid_t uid, pid_t pid) +{ + int pos=0; + tcfs_keytab_node *p; + + p=tcfs_keytab_fetch_pid(t,uid,pid); + if(p==NIL) + return EINVAL; + + if(p->kn_p==NIL) + { + pos=tcfs_keytab_hash(pid); + t->node[pos]=p->kn_n; + } + else + p->kn_p->kn_n=p->kn_n; + + if(p->kn_n!=NIL) + p->kn_n->kn_p=p->kn_p; + + t->cnt--; + tcfs_keytab_dispnode(p); + + return TCFS_OK; +} + +int tcfs_keytab_rm_gid(tcfs_keytab *t, uid_t uid, gid_t gid) +{ + int pos=0,ret=0; + tcfs_keytab_node *p; + + p=tcfs_keytab_fetch_gid(t,gid); + if(p==NIL) + return EINVAL; + + ret=tcfs_keytab_rm_gidpart(p,uid,gid); + + if (ret) + return ret; + + if(!IS_CLEAN_GD(p->kn_data)) + return TCFS_OK; + + if(p->kn_p==NIL) + { + pos=tcfs_keytab_hash(gid); + t->node[pos]=p->kn_n; + } + else + p->kn_p->kn_n=p->kn_n; + + if(p->kn_n!=NIL) + p->kn_n->kn_p=p->kn_p; + + t->cnt--; + tcfs_keytab_dispnode(p); + + return TCFS_OK; +} + diff --git a/sys/miscfs/tcfs/tcfs_keytab.h b/sys/miscfs/tcfs/tcfs_keytab.h new file mode 100644 index 00000000000..6da7ce49e82 --- /dev/null +++ b/sys/miscfs/tcfs/tcfs_keytab.h @@ -0,0 +1,97 @@ +#ifndef _SYS_TYPES_H_ +#include "sys/types.h" +#endif +#ifndef _TCFS_MOUNT_H_ +struct tcfs_mount; +#endif + +#define _TCFS_KEYTAB_H_ +#define KEYTABSIZE 20 +#define KEYSIZE 8 +#define KEYPARTSIZE (KEYSIZE+KEYSIZE/8) + +#define CLEAN 0x00 +#define PID_BIT 0x01 +#define UID_KEY 0x02 +#define GID_KEY 0x04 +#define PID_KEY (PID_BIT|UID_KEY) + +#define IS_GID_NODE(np) (((np)->kn_type)&GID_KEY) +#define IS_UID_NODE(np) (((np)->kn_type)&UID_KEY) +#define IS_PID_NODE(np) ((((np)->kn_type)&PID_BIT)&&(IS_UID_NODE((np)))) + +#ifndef TCFS_OK +#define TCFS_OK 0 +#endif + +#define MAXUSRPERGRP 10 + +typedef struct + { + unsigned char gui_flag; + uid_t gui_uid; + unsigned char gui_tcfskey[KEYPARTSIZE]; + } tcfs_grp_uinfo; + +#define GUI_CLEAN 0 +#define GUI_SET 1 +#define IS_SET_GUI(gui) ((gui).gui_flag==GUI_SET) + +typedef struct _grp_data { + int gd_flag; + int gd_n; + int gd_k; + tcfs_grp_uinfo gd_part[MAXUSRPERGRP]; + } tcfs_grp_data; + +#define IS_CLEAN_GD(gd) ((gd)->gd_n==0) +#define IS_FULL_GD(gd) ((gd)->gd_n==MAXUSRPERGRP) +#define IS_READY_GD(gd) (((gd)->gd_n)>=((gd)->gd_k)) + +typedef struct _kn { + pid_t kn_pid; + uid_t kn_uid; + gid_t kn_gid; + unsigned int kn_type; + + void *kn_key; + tcfs_grp_data *kn_data; + + struct _kn *kn_n; + struct _kn *kn_p; +} tcfs_keytab_node; + +typedef struct _kt { + unsigned int cnt; + tcfs_keytab_node* node[KEYTABSIZE]; + } tcfs_keytab; + +#define NIL ((tcfs_keytab_node*)0) + +#ifdef _HAVE_HASH_ +int _tcfs_keytab_hash(unsigned int); +#define tcfs_keytab_hash(x) _tcfs_keytab_hash((unsigned int)(x)) +#else +#define tcfs_keytab_hash(u) ((u)%KEYTABSIZE) +#endif + +tcfs_keytab_node *tcfs_keytab_newnode(void); +tcfs_keytab_node *tcfs_keytab_newgidnode(void); +void tcfs_keytab_dispnode(tcfs_keytab_node*); +tcfs_keytab *tcfs_keytab_init(void); +void tcfs_keytab_dispose(tcfs_keytab*); +tcfs_keytab_node *tcfs_keytab_fetch_uid(tcfs_keytab *, uid_t); +int tcfs_keytab_push_gidpart(struct tcfs_mount *,tcfs_keytab_node *,uid_t, gid_t,int,char*); +tcfs_keytab_node *tcfs_keytab_fetch_gid(tcfs_keytab *, gid_t); +tcfs_keytab_node *tcfs_keytab_fetch_pid(tcfs_keytab *, uid_t, pid_t); +int tcfs_keytab_push_uid(tcfs_keytab*, uid_t, void* ); +int tcfs_keytab_push_pid(tcfs_keytab*, uid_t, pid_t, void* ); +int tcfs_keytab_push_gid(struct tcfs_mount *,tcfs_keytab*, uid_t, gid_t,int,char*); +int tcfs_keytab_rm_uid(tcfs_keytab*, uid_t); +int tcfs_keytab_rm_pid(tcfs_keytab*, uid_t, pid_t); +int tcfs_keytab_rm_gidpart(tcfs_keytab_node *,uid_t, gid_t); +int tcfs_keytab_rm_gid(tcfs_keytab*, uid_t, gid_t); +int tcfs_interp(struct tcfs_mount *, tcfs_keytab_node*); +int tcfs_keytab_check_uid(tcfs_keytab *, uid_t); +int tcfs_keytab_check_pid(tcfs_keytab *, uid_t, pid_t); +int tcfs_keytab_check_gid(tcfs_keytab *, gid_t); diff --git a/sys/miscfs/tcfs/tcfs_mount.h b/sys/miscfs/tcfs/tcfs_mount.h new file mode 100644 index 00000000000..59e863f3482 --- /dev/null +++ b/sys/miscfs/tcfs/tcfs_mount.h @@ -0,0 +1,39 @@ +#ifndef _TCFS_KEYTAB_H_ +#include "tcfs_keytab.h" +#endif +#define _TCFS_MOUNT_H_ + +#ifndef _TCFS_VERSION_H_ +#include "tcfs_version.h" +#endif + +#define MaxCipherNameLen 8 +struct tcfs_status { + int status; + int n_ukey; + int n_gkey; + int tcfs_version; + char cipher_desc[MaxCipherNameLen]; + int cipher_keysize; + int cipher_version; + }; +struct tcfs_args { + char *target; /* Target of loopback */ + char *tcfs_key; /* chiave */ + int cipher_num; + int cmd; /* direttiva */ + uid_t user; /* utente */ + pid_t proc; /* processo */ + gid_t group; /* gruppo */ + int treshold; /* soglia grpkey */ + struct tcfs_status st; +}; + +struct tcfs_mount { + struct mount *tcfsm_vfs; + struct vnode *tcfsm_rootvp; /* Reference to root tcfs_node */ + void* ks; + tcfs_keytab *tcfs_uid_kt; + tcfs_keytab *tcfs_gid_kt; + int tcfs_cipher_num; +}; diff --git a/sys/miscfs/tcfs/tcfs_rw.c b/sys/miscfs/tcfs/tcfs_rw.c new file mode 100644 index 00000000000..7b11e12bc16 --- /dev/null +++ b/sys/miscfs/tcfs/tcfs_rw.c @@ -0,0 +1,616 @@ +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/vnode.h> +#include <sys/mount.h> +#include <sys/namei.h> +#include <sys/malloc.h> +#include <sys/buf.h> +#include <miscfs/tcfs/tcfs.h> +#include "tcfs_rw.h" +#include "tcfs_cipher.h" + +tcfs_opinfo tcfs_get_opinfo(void *a) +{ + struct vop_read_args *arg; + tcfs_opinfo r; + tcfs_fileinfo *i; + int iscr=0; + + + arg=(struct vop_read_args*)a; + + r.i=tcfs_get_fileinfo(a); + i=&(r.i); + + iscr=FI_CFLAG(i)||FI_GSHAR(i); + + if(!iscr) + { + r.tcfs_op_desc=TCFS_NONE; + return r; + } + + + r.off=arg->a_uio->uio_offset; + r.req=arg->a_uio->uio_resid; + + if(arg->a_uio->uio_rw==UIO_READ) + { + if(r.off<FI_ENDOF(i)-FI_SPURE(i)) + { + r.tcfs_op_desc=TCFS_READ_C1; + r.out_boff=BOFF(&r); + r.out_foff= + (LAST(&r)>FI_ENDOF(i)-FI_SPURE(i)?FI_ENDOF(i):P_FOFF(&r)); + r.in_boff=r.out_boff; + r.in_foff=r.out_foff; + return r; + } + else + { + r.tcfs_op_desc=TCFS_READ_C2; + r.out_boff=0; + r.out_foff=0; + return r; + } + } + if(arg->a_uio->uio_rw==UIO_WRITE) + { + if(arg->a_ioflag&IO_APPEND) + { + r.off=FI_ENDOF(i)-FI_SPURE(i); + arg->a_ioflag&=~(IO_APPEND); + } + if(LAST(&r)<FI_ENDOF(i)-FI_SPURE(i)) + { + if (FI_ENDOF(i)-FI_SPURE(i)-LAST(&r)>BLOCKSIZE) + { + r.tcfs_op_desc=TCFS_WRITE_C1; + r.out_boff=BOFF(&r); + r.out_foff=FOFF(&r); + r.in_boff=r.out_boff; + r.in_foff=r.out_foff; + return r; + } + else + { + r.tcfs_op_desc=TCFS_WRITE_C2; + r.out_boff=BOFF(&r); + r.out_foff=FI_ENDOF(i)-1; + r.in_boff=r.out_boff; + r.in_foff=r.out_foff; + return r; + } + } + if(LAST(&r)>=FI_ENDOF(i)-FI_SPURE(i)) + { + r.out_boff=BOFF(&r); + r.out_foff=P_FOFF(&r); + if (r.off<=FI_ENDOF(i)-FI_SPURE(i)) + { + r.tcfs_op_desc=TCFS_WRITE_C3; + r.in_boff=r.out_boff; + r.in_foff=r.out_foff; + return r; + } + else + if(D_BOFF(FI_ENDOF(i))==D_BOFF(r.off)) + { + r.tcfs_op_desc=TCFS_WRITE_C4; + r.in_boff=r.out_boff; + r.in_foff=r.out_foff; + return r; + } + else + { + r.tcfs_op_desc=TCFS_WRITE_C5; + r.in_boff=D_BOFF(FI_ENDOF(i)); + r.in_foff=D_FOFF(FI_ENDOF(i)); + r.out_boff=BOFF(&r); + r.out_foff=P_FOFF(&r); + return r; + } + } + } + return r; +} + +char *tcfs_new_uio_obs(struct uio *old, struct uio **new, int off, int bufsize) +{ + char *buffer; + struct uio *u; + struct iovec *n; + + u=malloc(sizeof(struct uio),M_FREE,M_NOWAIT); + if(!u) + return (char*)0; + n=malloc(sizeof(struct iovec),M_FREE,M_NOWAIT); + if(!n) + { + free(u,M_FREE); + return (char*)0; + } + buffer=malloc(bufsize,M_FREE,M_NOWAIT); + if(!buffer) + { + free(u,M_FREE); + free(n,M_FREE); + return (char*)0; + } + + + u->uio_offset=off; + u->uio_resid=bufsize; + u->uio_iovcnt=1; + u->uio_segflg=UIO_SYSSPACE; + u->uio_rw=old->uio_rw; + u->uio_procp=old->uio_procp; + u->uio_iov=n; + n->iov_base=buffer; + n->iov_len=bufsize; + + + *new=u; + return buffer; +} + +char *tcfs_new_uio_i(struct uio *old, struct uio **new,tcfs_opinfo *r) +{ + int bufsize; + char *buffer=NULL; + + + switch(r->tcfs_op_desc) + { + case TCFS_READ_C2: + buffer=(char*)0; + return buffer; + default: + case TCFS_READ_C1: + case TCFS_WRITE_C1: + case TCFS_WRITE_C2: + case TCFS_WRITE_C3: + bufsize=r->in_foff-r->in_boff+1; + break; + } + + return tcfs_new_uio_obs(old,new,r->in_boff,bufsize); +} + + +void tcfs_dispose_new_uio(struct uio *vec) +{ + void *p,*q; + p=(void*)vec; + q=(void*)vec->uio_iov; + + free(p,M_FREE); + free(q,M_FREE); +} + +int +tcfs_read(v) + void *v; +{ + char *buffer, /* buffer per la read interna */ + *buffp, /* puntatore all'inizio dei dati utili */ + *buffpf; /* puntatore alla fine dei dati utili */ + + int bufsize=0; /* taglia del buffer allocato */ + + struct uio + *new, /* puntatore all'uio rifatto */ + *old; /* puntatore all'uio originale */ + + int terr, /* val. ritorno read interna */ + chdap, /* caratteri da passare */ + chread, /* caratteri letti dalla read int. */ + r_off, /* offset raggiunto */ + e_spure; /* spure effettivamente letti */ + + struct vop_read_args *arg; + tcfs_opinfo f; + tcfs_fileinfo *i; + + struct ucred *ucred; + struct proc *procp; + + struct tcfs_mount *mp; + void *ks; + + + f=tcfs_get_opinfo(v); + + if(f.tcfs_op_desc==TCFS_NONE) + return tcfs_bypass(v); + + i=&(f.i); + + arg=(struct vop_read_args *)v; + mp=MOUNTTOTCFSMOUNT(arg->a_vp->v_mount); + ucred=arg->a_cred; + procp=arg->a_uio->uio_procp; + + if(FI_GSHAR(i)) + { + ks=tcfs_getgkey(ucred,procp,arg->a_vp); + if(!ks) + { + return EACCES; + } + } + else + { + ks=tcfs_getpkey(ucred,procp,arg->a_vp); + if (!ks) + ks=tcfs_getukey(ucred,procp,arg->a_vp); + if (!ks) + return EACCES; + } + + old=arg->a_uio; + buffer=tcfs_new_uio_i(old,&new,&f); + + if (buffer==(char*)0) + return 0; + + arg->a_uio=new; + bufsize=f.out_foff-f.out_boff+1; + + terr=tcfs_bypass(arg); + chread=bufsize-new->uio_resid; + + + mkdecrypt(mp,buffer,chread,ks); + + + r_off=f.out_boff+chread; + + if(r_off>=FI_ENDOF(i)) + e_spure=FI_SPURE(i); + else + if(r_off>FI_ENDOF(i)-FI_SPURE(i)) + e_spure=FI_SPURE(i)-FI_ENDOF(i)+r_off; + else + e_spure=0; + + buffp=buffer+ROFF(&f); + if (chread>ROFF(&f)) + { + chdap=MIN(f.req,chread-ROFF(&f)-e_spure); + buffpf=buffp+chdap; + + uiomove(buffp,chdap,old); + } + arg->a_uio=old; + tcfs_dispose_new_uio(new); + free(buffer,M_FREE); + + return terr; +} + +int +tcfs_write(v) + void *v; +{ + char *buffer, /* buffer per la read interna */ + *buffp, /* puntatore all'inizio dei dati utili */ + *buffpf; /* puntatore alla fine dei dati utili */ + + struct uio + *tmp, /* uio per la dimensione di un blocco */ + *old; /* puntatore all'uio originale della chiamata */ + + + int bufsize, /* num. caratteri req. read interna */ + terr, /* val. ritorno read interna */ + chdap, /* caratteri da passare */ + chread=0, /* caratteri letti dalla read int. */ + chwrote,e_chwrote, + spure=0; /* ho scritto fino a qui */ + + tcfs_opinfo f; + tcfs_fileinfo *i; + + struct vop_read_args *arg; + struct ucred *ucred; + struct proc *procp; + void *ks; + struct tcfs_mount *mp; + + int e; + + + arg=(struct vop_read_args *)v; + ucred=arg->a_cred; + procp=arg->a_uio->uio_procp; + mp=MOUNTTOTCFSMOUNT(arg->a_vp->v_mount); + + + f=tcfs_get_opinfo(arg); + + if (f.tcfs_op_desc==TCFS_NONE) + return tcfs_bypass(v); + + i=&(f.i); + + if(FI_GSHAR(i)) + { + ks=tcfs_getgkey(ucred,procp,arg->a_vp); + if(!ks) + return EACCES; + } + else + { + ks=tcfs_getpkey(ucred,procp,arg->a_vp); + if (!ks) + ks=tcfs_getukey(ucred,procp,arg->a_vp); + if (!ks) + return EACCES; + } + + old=arg->a_uio; + + buffer=(char*)tcfs_new_uio_i(old,&tmp,&f); + if (buffer==(char*)0) + return EFAULT; + + arg->a_uio=tmp; + arg->a_desc=VDESC(vop_read); + arg->a_uio->uio_rw=UIO_READ; + + bufsize=f.in_foff-f.in_boff+1; + + + + terr=tcfs_bypass(arg); + + switch(f.tcfs_op_desc) + { + case TCFS_WRITE_C1: + case TCFS_WRITE_C2: + if(tmp->uio_resid!=0) + goto ret; + + chread=bufsize; + break; + + case TCFS_WRITE_C3: + case TCFS_WRITE_C4: + if(tmp->uio_resid!=(P_FOFF(&f)-FI_ENDOF(i)+1)) + goto ret; + + chread=bufsize; + break; + + case TCFS_WRITE_C5: + if(tmp->uio_resid!=(D_FOFF(FI_ENDOF(i))-FI_ENDOF(i)+1)) + goto ret; + chread=bufsize; + } + + mkdecrypt(mp,buffer,chread,ks); + + + if(f.tcfs_op_desc==TCFS_WRITE_C4) + { + + for(e=FI_ENDOF(i)-FI_SPURE(i);e<f.off;e++) + *(buffer+e-f.out_boff)='\0'; + + } + + + if(f.tcfs_op_desc!=TCFS_WRITE_C5) + { + + buffp=buffer+ROFF(&f); + chdap=f.req; + buffpf=buffp+chdap; + + uiomove(buffp,chdap,old); + + } /*if not TCFS_WRITE_C5 */ + else + { + for(e=FI_ENDOF(i)-FI_SPURE(i)-f.in_boff;e<bufsize;e++) + *(buffer+e)='\0'; + } + + mkencrypt(mp,buffer,bufsize,ks); + + arg->a_desc=VDESC(vop_write); + arg->a_uio->uio_rw=UIO_WRITE; + arg->a_uio->uio_resid=bufsize; + arg->a_uio->uio_offset=f.in_boff; + arg->a_uio->uio_iov->iov_base=buffer; + arg->a_uio->uio_iov->iov_len=bufsize; + terr=tcfs_bypass(arg); + + if (f.tcfs_op_desc==TCFS_WRITE_C5) + { + + tcfs_dispose_new_uio(tmp); + free(buffer,M_FREE); + + bufsize=f.out_foff-f.out_boff+1; + buffer=tcfs_new_uio_obs(old,&tmp,f.out_boff,bufsize); + arg->a_uio=tmp; + arg->a_desc=VDESC(vop_write); + arg->a_uio->uio_rw=UIO_WRITE; + + for(e=0;e<ROFF(&f);e++) + *(buffer+e)='\0'; + + buffp=buffer+ROFF(&f); + chdap=f.req; + buffpf=buffp+chdap; + + uiomove(buffp,chdap,old); + mkencrypt(mp,buffer,bufsize,ks); + terr=tcfs_bypass(arg); + + } + + chwrote=bufsize-tmp->uio_resid; + e_chwrote=MIN(f.req,chwrote-ROFF(&f)); + + switch(f.tcfs_op_desc) + { + case TCFS_WRITE_C1: + case TCFS_WRITE_C2: + break; + case TCFS_WRITE_C3: + if ((f.in_boff+chwrote)>FI_ENDOF(i)-FI_SPURE(i)) + { + + + if(chwrote>f.req){ + spure=D_SPURE(f.off+f.req); + } else + { + spure=D_SPURE(f.out_boff+chwrote); + } + + FI_SET_SP(i,spure); + tcfs_set_fileinfo(v,i); + } + break; + case TCFS_WRITE_C4: + case TCFS_WRITE_C5: + spure=D_SPURE(f.off+f.req); + FI_SET_SP(i,spure); + tcfs_set_fileinfo(v,i); + break; + + } + + + old->uio_resid=f.req-e_chwrote; + +ret: + arg->a_uio=old; + tcfs_dispose_new_uio(tmp); + free(buffer,M_FREE); + return terr; +} + +int tcfs_ed(struct vnode *v,struct proc *p,struct ucred *c, tcfs_fileinfo *i) +{ + struct vop_read_args ra; + struct vop_write_args wa; + struct uio *u; + struct iovec *n; + char *buff; + unsigned long csize,resid,w_resid; + unsigned long size,w_size; + int bufsize,e; + int retval,sp; + void *ks; + int encr=0; + struct tcfs_mount *mp; + + mp=MOUNTTOTCFSMOUNT(v->v_mount); + encr=FI_CFLAG(i)||FI_GSHAR(i); + + + if(v->v_type!=VREG) + return 0; + + if(FI_GSHAR(i)) + { + ks=tcfs_getgkey(c,p,v); + if(!ks) + return EACCES; + } + else + { + + ks=tcfs_getpkey(c,p,v); + if (!ks) + ks=tcfs_getukey(c,p,v); + if (!ks) + { + return EACCES; + } + + } + + u=malloc(sizeof(struct uio),M_FREE,M_NOWAIT); + n=malloc(sizeof(struct iovec),M_FREE,M_NOWAIT); + + + size=FI_ENDOF(i); + + if(encr) + { + w_size=D_PFOFF(size); + sp=D_SPURE(size); + } + else + { + w_size=size-FI_SPURE(i); + sp=-FI_SPURE(i); + } + + csize=0; + resid=size; + w_resid=w_size; + + bufsize=BLOCKSIZE; + + buff=malloc(BLOCKSIZE,M_FREE,M_NOWAIT); + + u->uio_offset=0; + u->uio_resid=bufsize; + u->uio_iovcnt=1; + u->uio_segflg=UIO_SYSSPACE; + u->uio_procp=p; + u->uio_iov=n; + + wa.a_desc=VDESC(vop_write); + ra.a_desc=VDESC(vop_read); + wa.a_vp=ra.a_vp=v; + wa.a_cred=ra.a_cred=c; + wa.a_ioflag=ra.a_ioflag=0; + wa.a_uio=ra.a_uio=u; + + + for(e=0;e<=D_NOBLK(size);e++) + { + + int x,y; + + u->uio_offset=csize; + u->uio_rw=UIO_READ; + n->iov_base=buff; + n->iov_len=u->uio_resid=x=MIN(bufsize,resid+1); + + retval=tcfs_bypass((void*)&ra); + + + u->uio_offset=csize; + u->uio_rw=UIO_WRITE; + n->iov_base=buff; + n->iov_len=u->uio_resid=y=MIN(bufsize,w_resid+1); + + if(!encr) + mkdecrypt(mp,buff,x,ks); + else + mkencrypt(mp,buff,y,ks); + + retval=tcfs_bypass((void*)&wa); + + resid-=x; csize+=x; + w_resid-=y; + + /* I should call the scheduler here */ + } + + tcfs_dispose_new_uio(u); + return sp; +} + diff --git a/sys/miscfs/tcfs/tcfs_rw.h b/sys/miscfs/tcfs/tcfs_rw.h new file mode 100644 index 00000000000..a8e2db60891 --- /dev/null +++ b/sys/miscfs/tcfs/tcfs_rw.h @@ -0,0 +1,52 @@ +/* Gestione informazioni sui files cifrati +*/ +#include <miscfs/tcfs/tcfs_fileinfo.h> + +typedef struct { + tcfs_fileinfo i; + int off; + int req; + int tcfs_op_desc; + int in_boff; + int in_foff; + int out_boff; + int out_foff; + } tcfs_opinfo; + + + +/* tcfs_opinfo x */ + +#define ROFF(x) ((x)->off%BLOCKSIZE) +#define LAST(x) ((x)->off+(x)->req-1) +#define BOFF(x) (((x)->off/BLOCKSIZE)*BLOCKSIZE) +#define FOFF(x) (LAST((x))+BLOCKSIZE-(LAST((x))%BLOCKSIZE+1)) +#define P_BOFF(x) (((x)->off/SBLOCKSIZE)*SBLOCKSIZE) +#define P_FOFF(x) (LAST((x))+SBLOCKSIZE-(LAST((x))%SBLOCKSIZE+1)) +#define SPURE(x) ((x)->req%SBLOCKSIZE?(SBLOCKSIZE-(x)->req%SBLOCKSIZE):0) + +/* int o */ +#define D_BOFF(o) (((o)/BLOCKSIZE)*BLOCKSIZE) +#define D_FOFF(o) ((o)+BLOCKSIZE-((o)%BLOCKSIZE+1)) +#define D_PFOFF(o) ((o)+SBLOCKSIZE-((o)%SBLOCKSIZE+1)) +#define D_SPURE(o) ((o)%SBLOCKSIZE?(SBLOCKSIZE-(o)%SBLOCKSIZE):0) +#define D_NOBLK(o) ((o)/BLOCKSIZE+(o%BLOCKSIZE?1:0)) + +#define TCFS_NONE 0 +#define TCFS_READ_C1 1 +#define TCFS_READ_C2 2 +#define TCFS_WRITE_C1 3 +#define TCFS_WRITE_C2 4 +#define TCFS_WRITE_C3 5 +#define TCFS_WRITE_C4 6 +#define TCFS_WRITE_C5 7 + +/* prototyphes */ + +char *tcfs_new_uio_i(struct uio*,struct uio**,tcfs_opinfo*); +char *tcfs_new_uio_obs(struct uio*,struct uio**,int off, int ireq); +void tcfs_dispose_new_uio(struct uio *); +void dispose_new_uio(struct uio *); +int tcfs_ed(struct vnode*, struct proc*, struct ucred *, tcfs_fileinfo *); +tcfs_opinfo tcfs_get_opinfo(void*); + diff --git a/sys/miscfs/tcfs/tcfs_subr.c b/sys/miscfs/tcfs/tcfs_subr.c new file mode 100644 index 00000000000..9d329efee94 --- /dev/null +++ b/sys/miscfs/tcfs/tcfs_subr.c @@ -0,0 +1,355 @@ +/* $OpenBSD: tcfs_subr.c,v 1.1 2000/06/17 17:16:07 provos Exp $ */ +/* $NetBSD: tcfs_subr.c,v 1.6 1996/05/10 22:50:52 jtk Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software donated to Berkeley by + * Jan-Simon Pendry. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: Id: lofs_subr.c,v 1.11 1992/05/30 10:05:43 jsp Exp + * @(#)tcfs_subr.c 8.4 (Berkeley) 1/21/94 + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/vnode.h> +#include <sys/mount.h> +#include <sys/namei.h> +#include <sys/malloc.h> +#include <miscfs/specfs/specdev.h> +#include <miscfs/tcfs/tcfs.h> + +#define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */ +#define NTCFSNODECACHE 16 + +/* + * Null layer cache: + * Each cache entry holds a reference to the lower vnode + * along with a pointer to the alias vnode. When an + * entry is added the lower vnode is VREF'd. When the + * alias is removed the lower vnode is vrele'd. + */ + +#define TCFS_NHASH(vp) \ + (&tcfs_node_hashtbl[(((u_long)vp)>>LOG2_SIZEVNODE) & tcfs_node_hash]) +LIST_HEAD(tcfs_node_hashhead, tcfs_node) *tcfs_node_hashtbl; +u_long tcfs_node_hash; + +static struct vnode * + tcfs_node_find __P((struct mount *, struct vnode *)); +static int + tcfs_node_alloc __P((struct mount *, struct vnode *, struct vnode **)); +/* + * Initialise cache headers + */ +/*ARGSUSED*/ +int +tcfs_init(vfsp) + struct vfsconf *vfsp; +{ + +#ifdef TCFS_DIAGNOSTIC + printf("tcfs_init\n"); /* printed during system boot */ +#endif + tcfs_node_hashtbl = hashinit(NTCFSNODECACHE, M_CACHE, M_WAITOK, &tcfs_node_hash); + return (0); +} + +/* + * Return a VREF'ed alias for lower vnode if already exists, else 0. + */ +static struct vnode * +tcfs_node_find(mp, lowervp) + struct mount *mp; + struct vnode *lowervp; +{ + struct tcfs_node_hashhead *hd; + struct tcfs_node *a; + struct vnode *vp; + struct proc *p = curproc; + + /* + * Find hash base, and then search the (two-way) linked + * list looking for a tcfs_node structure which is referencing + * the lower vnode. If found, the increment the tcfs_node + * reference count (but NOT the lower vnode's VREF counter). + */ + hd = TCFS_NHASH(lowervp); +loop: + for (a = hd->lh_first; a != 0; a = a->tcfs_hash.le_next) { + if (a->tcfs_lowervp == lowervp && TCFSTOV(a)->v_mount == mp) { + vp = TCFSTOV(a); + /* + * We need vget for the VXLOCK + * stuff, but we don't want to lock + * the lower node. + */ + if (vget(vp, 0, p)) { + printf ("tcfs_node_find: vget failed.\n"); + goto loop; + }; + return (vp); + } + } + + return NULLVP; +} + + +/* + * Make a new tcfs_node node. + * Vp is the alias vnode, lowervp is the lower vnode. + * Maintain a reference to lowervp. + */ +static int +tcfs_node_alloc(mp, lowervp, vpp) + struct mount *mp; + struct vnode *lowervp; + struct vnode **vpp; +{ + struct tcfs_node_hashhead *hd; + struct tcfs_node *xp; + struct vnode *vp, *nvp; + int error; + extern int (**dead_vnodeop_p) __P((void *)); + struct proc *p = curproc; + + + MALLOC(xp, struct tcfs_node *, sizeof(struct tcfs_node), M_TEMP, + M_WAITOK); + + if ((error = getnewvnode(VT_TCFS, mp, tcfs_vnodeop_p, vpp)) != 0) { + FREE (xp, M_TEMP); + return (error); + } + + vp = *vpp; + vp->v_type = lowervp->v_type; + + if (vp->v_type == VBLK || vp->v_type == VCHR) { + MALLOC(vp->v_specinfo, struct specinfo *, + sizeof(struct specinfo), M_VNODE, M_WAITOK); + vp->v_rdev = lowervp->v_rdev; + } + + vp->v_data = xp; + xp->tcfs_vnode = vp; + xp->tcfs_lowervp = lowervp; + /* + * Before we insert our new node onto the hash chains, + * check to see if someone else has beaten us to it. + * (We could have slept in MALLOC.) + */ + if ((nvp = tcfs_node_find(mp, lowervp)) != NULL) { + *vpp = nvp; + + /* free the substructures we've allocated. */ + FREE(xp, M_TEMP); + if (vp->v_type == VBLK || vp->v_type == VCHR) + FREE(vp->v_specinfo, M_VNODE); + + vp->v_type = VBAD; /* node is discarded */ + vp->v_op = dead_vnodeop_p; /* so ops will still work */ + vrele(vp); /* get rid of it. */ + return (0); + } + + /* + * XXX if it's a device node, it needs to be checkalias()ed. + * however, for locking reasons, that's just not possible. + * so we have to do most of the dirty work inline. Note that + * this is a limited case; we know that there's going to be + * an alias, and we know that that alias will be a "real" + * device node, i.e. not tagged VT_NON. + */ + if (vp->v_type == VBLK || vp->v_type == VCHR) { + struct vnode *cvp, **cvpp; + + cvpp = &speclisth[SPECHASH(vp->v_rdev)]; +loop: + for (cvp = *cvpp; cvp; cvp = cvp->v_specnext) { + if (vp->v_rdev != cvp->v_rdev || + vp->v_type != cvp->v_type) + continue; + + /* + * Alias, but not in use, so flush it out. + */ + if (cvp->v_usecount == 0) { + vgone(cvp); + goto loop; + } + if (vget(cvp, 0, p)) /* can't lock; will die! */ + goto loop; + break; + } + + vp->v_hashchain = cvpp; + vp->v_specnext = *cvpp; + vp->v_specmountpoint = NULL; + *cvpp = vp; +#ifdef DIAGNOSTIC + if (cvp == NULLVP) + panic("tcfs_node_alloc: no alias for device"); +#endif + vp->v_flag |= VALIASED; + cvp->v_flag |= VALIASED; + vrele(cvp); + } + /* XXX end of transmogrified checkalias() */ + + VREF(lowervp); /* Extra VREF will be vrele'd in tcfs_node_create */ + hd = TCFS_NHASH(lowervp); + LIST_INSERT_HEAD(hd, xp, tcfs_hash); + return (0); +} + + +/* + * Try to find an existing tcfs_node vnode refering + * to it, otherwise make a new tcfs_node vnode which + * contains a reference to the lower vnode. + * + * >>> we assume that the lower node is already locked upon entry, so we mark + * the upper node as locked too (if caller requests it). <<< + */ +int +tcfs_node_create(mp, lowervp, newvpp, takelock) + struct mount *mp; + struct vnode *lowervp; + struct vnode **newvpp; + int takelock; +{ + struct vnode *aliasvp; + + if ((aliasvp = tcfs_node_find(mp, lowervp)) != NULL) { + /* + * tcfs_node_find has taken another reference + * to the alias vnode. + */ +#ifdef TCFS_DIAGNOSTIC + vprint("tcfs_node_create: exists", aliasvp); +#endif + /* VREF(aliasvp); --- done in tcfs_node_find */ + } else { + int error; + + /* + * Get new vnode. + */ +#ifdef TCFS_DIAGNOSTIC + printf("tcfs_node_create: create new alias vnode\n"); +#endif + + /* + * Make new vnode reference the tcfs_node. + */ + if ((error = tcfs_node_alloc(mp, lowervp, &aliasvp)) != 0) + return error; + + /* + * aliasvp is already VREF'd by getnewvnode() + */ + } + + vrele(lowervp); + +#ifdef DIAGNOSTIC + if (lowervp->v_usecount < 1) { + /* Should never happen... */ + vprint("tcfs_node_create: alias", aliasvp); + panic("tcfs_node_create: lower has 0 usecount."); + }; +#endif + +#ifdef TCFS_DIAGNOSTIC + vprint("tcfs_node_create: alias", aliasvp); +#endif + + *newvpp = aliasvp; + return (0); +} + +#ifdef TCFS_DIAGNOSTIC +int tcfs_checkvp_barrier = 1; +struct vnode * +tcfs_checkvp(vp, fil, lno) + struct vnode *vp; + char *fil; + int lno; +{ + struct tcfs_node *a = VTOTCFS(vp); +#ifdef notyet + /* + * Can't do this check because vop_reclaim runs + * with a funny vop vector. + */ + if (vp->v_op != tcfs_vnodeop_p) { + printf ("tcfs_checkvp: on non-tcfs-node\n"); + while (tcfs_checkvp_barrier) /*WAIT*/ ; + panic("tcfs_checkvp"); + }; +#endif + if (a->tcfs_lowervp == TCFS) { + /* Should never happen */ + int i; u_long *p; + printf("vp = %p, ZERO ptr\n", vp); + for (p = (u_long *) a, i = 0; i < 8; i++) + printf(" %lx", p[i]); + printf("\n"); + /* wait for debugger */ + while (tcfs_checkvp_barrier) /*WAIT*/ ; + panic("tcfs_checkvp"); + } + if (a->tcfs_lowervp->v_usecount < 1) { + int i; u_long *p; + printf("vp = %p, unref'ed lowervp\n", vp); + for (p = (u_long *) a, i = 0; i < 8; i++) + printf(" %lx", p[i]); + printf("\n"); + /* wait for debugger */ + while (tcfs_checkvp_barrier) /*WAIT*/ ; + panic ("tcfs with unref'ed lowervp"); + }; +#ifdef notyet + printf("tcfs %p/%d -> %p/%d [%s, %d]\n", + TCFSTOV(a), TCFSTOV(a)->v_usecount, + a->tcfs_lowervp, a->tcfs_lowervp->v_usecount, + fil, lno); +#endif + return a->tcfs_lowervp; +} +#endif diff --git a/sys/miscfs/tcfs/tcfs_version.h b/sys/miscfs/tcfs/tcfs_version.h new file mode 100644 index 00000000000..fb88b344dcd --- /dev/null +++ b/sys/miscfs/tcfs/tcfs_version.h @@ -0,0 +1,3 @@ +#define _TCFS_VERSION_H_ +#define TCFS_VERSION_NUM 0 + diff --git a/sys/miscfs/tcfs/tcfs_vfsops.c b/sys/miscfs/tcfs/tcfs_vfsops.c new file mode 100644 index 00000000000..df84c99db55 --- /dev/null +++ b/sys/miscfs/tcfs/tcfs_vfsops.c @@ -0,0 +1,329 @@ +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/vnode.h> +#include <sys/mount.h> +#include <sys/namei.h> +#include <sys/malloc.h> +#include <miscfs/tcfs/tcfs.h> + +int tcfs_mount __P((struct mount *, const char *, caddr_t, + struct nameidata *, struct proc *)); +int tcfs_start __P((struct mount *, int, struct proc *)); +int tcfs_unmount __P((struct mount *, int, struct proc *)); +int tcfs_root __P((struct mount *, struct vnode **)); +int tcfs_quotactl __P((struct mount *, int, uid_t, caddr_t, + struct proc *)); +int tcfs_statfs __P((struct mount *, struct statfs *, struct proc *)); +int tcfs_sync __P((struct mount *, int, struct ucred *, struct proc *)); +int tcfs_vget __P((struct mount *, ino_t, struct vnode **)); + +/* + * Mount tcfs layer + */ +int +tcfs_mount(mp, path, data, ndp, p) + struct mount *mp; + const char *path; + caddr_t data; + struct nameidata *ndp; + struct proc *p; +{ + int error = 0; + struct tcfs_args args; + struct vnode *lowerrootvp, *vp; + struct vnode *tcfsm_rootvp; + struct tcfs_mount *xmp; + size_t size; + int tcfs_error=0; + +#ifdef TCFS_DIAGNOSTIC + printf("tcfs_mount(mp = %p)\n", mp); +#endif + + /* + * Get argument + */ + error = copyin(data, (caddr_t)&args, sizeof(struct tcfs_args)); + if (error) + return (error); + + /* receiving user directives */ + if (mp->mnt_flag & MNT_UPDATE) { + int i; + i=tcfs_exec_cmd(MOUNTTOTCFSMOUNT(mp),&args); + copyout((caddr_t)&args,data,sizeof(struct tcfs_args)); + return i; + } + + /* + * Find lower node + */ + NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT|LOCKLEAF, + UIO_USERSPACE, args.target, p); + if ((error = namei(ndp)) != 0) + return (error); + + /* + * Sanity check on lower vnode + */ + lowerrootvp = ndp->ni_vp; + + vrele(ndp->ni_dvp); + ndp->ni_dvp = NULL; + + if (lowerrootvp->v_type != VDIR) { + vput(lowerrootvp); + return (EINVAL); + } + + xmp = (struct tcfs_mount *) malloc(sizeof(struct tcfs_mount), + M_UFSMNT, M_WAITOK); /* XXX */ + + /* + * Save reference to underlying FS + */ + xmp->tcfsm_vfs = lowerrootvp->v_mount; + + /* + * Save reference. Each mount also holds + * a reference on the root vnode. + */ + error = tcfs_node_create(mp, lowerrootvp, &vp, 1); + /* + * Unlock the node (either the lower or the alias) + */ + VOP_UNLOCK(vp, 0, p); + /* + * Make sure the node alias worked + */ + if (error) { + vrele(lowerrootvp); + free(xmp, M_UFSMNT); /* XXX */ + return (error); + } + + /* + * Keep a held reference to the root vnode. + * It is vrele'd in tcfs_unmount. + */ + tcfsm_rootvp = vp; + tcfsm_rootvp->v_flag |= VROOT; + xmp->tcfsm_rootvp = tcfsm_rootvp; + if (TCFSVPTOLOWERVP(tcfsm_rootvp)->v_mount->mnt_flag & MNT_LOCAL) + mp->mnt_flag |= MNT_LOCAL; + mp->mnt_data = (qaddr_t) xmp; + vfs_getnewfsid(mp); + + (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); + bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); + (void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, + &size); + bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); +#ifdef TCFS_DIAGNOSTIC + printf("tcfs_mount: lower %s, alias at %s\n", + mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); +#endif + + tcfs_error=tcfs_init_mp(xmp,&args); + copyout((caddr_t)&args,data,sizeof(struct tcfs_args)); + return (tcfs_error); + +} + +/* + * VFS start. Nothing needed here - the start routine + * on the underlying filesystem will have been called + * when that filesystem was mounted. + */ +int +tcfs_start(mp, flags, p) + struct mount *mp; + int flags; + struct proc *p; +{ + + return (0); + /* return VFS_START(MOUNTTOTCFSMOUNT(mp)->tcfsm_vfs, flags, p); */ +} + +/* + * Free reference to tcfs layer + */ +int +tcfs_unmount(mp, mntflags, p) + struct mount *mp; + int mntflags; + struct proc *p; +{ + struct vnode *tcfsm_rootvp = MOUNTTOTCFSMOUNT(mp)->tcfsm_rootvp; + int error; + int flags = 0; + +#ifdef TCFS_DIAGNOSTIC + printf("tcfs_unmount(mp = %p)\n", mp); +#endif + + if (mntflags & MNT_FORCE) { + flags |= FORCECLOSE; + } + + /* + * Clear out buffer cache. I don't think we + * ever get anything cached at this level at the + * moment, but who knows... + */ +#if 0 + mntflushbuf(mp, 0); + if (mntinvalbuf(mp, 1)) + return (EBUSY); +#endif + if (tcfsm_rootvp->v_usecount > 1) + return (EBUSY); + if ((error = vflush(mp, tcfsm_rootvp, flags)) != 0) + return (error); + +#ifdef TCFS_DIAGNOSTIC + vprint("alias root of lower", tcfsm_rootvp); +#endif + /* + * Release reference on underlying root vnode + */ + vrele(tcfsm_rootvp); + /* + * And blow it away for future re-use + */ + vgone(tcfsm_rootvp); + /* + * Finally, throw away the tcfs_mount structure + */ + + tcfs_keytab_dispose(MOUNTTOTCFSMOUNT(mp)->tcfs_uid_kt); + tcfs_keytab_dispose(MOUNTTOTCFSMOUNT(mp)->tcfs_gid_kt); + + + free(mp->mnt_data, M_UFSMNT); /* XXX */ + mp->mnt_data = 0; + return 0; +} + +int +tcfs_root(mp, vpp) + struct mount *mp; + struct vnode **vpp; +{ + struct vnode *vp; + struct proc *p = curproc; + +#ifdef TCFS_DIAGNOSTIC + printf("tcfs_root(mp = %p, vp = %p->%p)\n", mp, + MOUNTTOTCFSMOUNT(mp)->tcfsm_rootvp, + TCFSVPTOLOWERVP(MOUNTTOTCFSMOUNT(mp)->tcfsm_rootvp) + ); +#endif + + /* + * Return locked reference to root. + */ + vp = MOUNTTOTCFSMOUNT(mp)->tcfsm_rootvp; + VREF(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); + *vpp = vp; + return 0; +} + +int +tcfs_quotactl(mp, cmd, uid, arg, p) + struct mount *mp; + int cmd; + uid_t uid; + caddr_t arg; + struct proc *p; +{ + + return VFS_QUOTACTL(MOUNTTOTCFSMOUNT(mp)->tcfsm_vfs, cmd, uid, arg, p); +} + +int +tcfs_statfs(mp, sbp, p) + struct mount *mp; + struct statfs *sbp; + struct proc *p; +{ + int error; + struct statfs mstat; + +#ifdef TCFS_DIAGNOSTIC + printf("tcfs_statfs(mp = %p, vp = %p->%p)\n", mp, + MOUNTTOTCFSMOUNT(mp)->tcfsm_rootvp, + TCFSVPTOLOWERVP(MOUNTTOTCFSMOUNT(mp)->tcfsm_rootvp) + ); +#endif + + bzero(&mstat, sizeof(mstat)); + + error = VFS_STATFS(MOUNTTOTCFSMOUNT(mp)->tcfsm_vfs, &mstat, p); + if (error) + return (error); + + /* now copy across the "interesting" information and fake the rest */ + sbp->f_flags = mstat.f_flags; + sbp->f_bsize = mstat.f_bsize; + sbp->f_iosize = mstat.f_iosize; + sbp->f_blocks = mstat.f_blocks; + sbp->f_bfree = mstat.f_bfree; + sbp->f_bavail = mstat.f_bavail; + sbp->f_files = mstat.f_files; + sbp->f_ffree = mstat.f_ffree; + if (sbp != &mp->mnt_stat) { + bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); + bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); + bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); + } + strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN); + return (0); +} + +int +tcfs_sync(mp, waitfor, cred, p) + struct mount *mp; + int waitfor; + struct ucred *cred; + struct proc *p; +{ + + /* + * XXX - Assumes no data cached at tcfs layer. + */ + return (0); +} + +int +tcfs_vget(mp, ino, vpp) + struct mount *mp; + ino_t ino; + struct vnode **vpp; +{ + + return VFS_VGET(MOUNTTOTCFSMOUNT(mp)->tcfsm_vfs, ino, vpp); +} + +#define tcfs_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \ + size_t, struct proc *)))eopnotsupp) + +struct vfsops tcfs_vfsops = { + tcfs_mount, + tcfs_start, + tcfs_unmount, + tcfs_root, + tcfs_quotactl, + tcfs_statfs, + tcfs_sync, + tcfs_vget, + tcfs_fhtovp, + tcfs_vptofh, + tcfs_init, + tcfs_sysctl +}; diff --git a/sys/miscfs/tcfs/tcfs_vnops.c b/sys/miscfs/tcfs/tcfs_vnops.c new file mode 100644 index 00000000000..eb824b34ee5 --- /dev/null +++ b/sys/miscfs/tcfs/tcfs_vnops.c @@ -0,0 +1,435 @@ +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/vnode.h> +#include <sys/mount.h> +#include <sys/namei.h> +#include <sys/malloc.h> +#include <sys/buf.h> +#include <miscfs/tcfs/tcfs.h> + + +int tcfs_bug_bypass = 0; /* for debugging: enables bypass printf'ing */ + +int tcfs_bypass __P((void *)); +int tcfs_getattr __P((void *)); +int tcfs_setattr __P((void *)); +int tcfs_inactive __P((void *)); +int tcfs_reclaim __P((void *)); +int tcfs_print __P((void *)); +int tcfs_strategy __P((void *)); +int tcfs_bwrite __P((void *)); +int tcfs_lock __P((void *)); +int tcfs_unlock __P((void *)); +int tcfs_islocked __P((void *)); +int tcfs_read __P((void *)); +int tcfs_readdir __P((void *)); +int tcfs_write __P((void *)); +int tcfs_create __P((void *)); +int tcfs_mknod __P((void *)); +int tcfs_mkdir __P((void *)); +int tcfs_link __P((void *)); +int tcfs_symlink __P((void *)); +int tcfs_rename __P((void *)); +int tcfs_lookup __P((void *)); + +int +tcfs_bypass(v) + void *v; +{ + struct vop_generic_args /* { + struct vnodeop_desc *a_desc; + <other random data follows, presumably> + } */ *ap = v; + register struct vnode **this_vp_p; + int error; + struct vnode *old_vps[VDESC_MAX_VPS]; + struct vnode **vps_p[VDESC_MAX_VPS]; + struct vnode ***vppp; + struct vnodeop_desc *descp = ap->a_desc; + int reles, i; + + if (tcfs_bug_bypass) + printf ("tcfs_bypass: %s\n", descp->vdesc_name); + +#ifdef SAFETY + /* + * We require at least one vp. + */ + if (descp->vdesc_vp_offsets == TCFS || + descp->vdesc_vp_offsets[0] == VDESC_NO_OFFSET) + panic ("tcfs_bypass: no vp's in map."); +#endif + + /* + * Map the vnodes going in. + * Later, we'll invoke the operation based on + * the first mapped vnode's operation vector. + */ + reles = descp->vdesc_flags; + for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) { + if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET) + break; /* bail out at end of list */ + vps_p[i] = this_vp_p = + VOPARG_OFFSETTO(struct vnode**,descp->vdesc_vp_offsets[i],ap); + /* + * We're not guaranteed that any but the first vnode + * are of our type. Check for and don't map any + * that aren't. (We must always map first vp or vclean fails.) + */ + if (i && (*this_vp_p == NULLVP || + (*this_vp_p)->v_op != tcfs_vnodeop_p)) { + old_vps[i] = NULLVP; + } else { + old_vps[i] = *this_vp_p; + *(vps_p[i]) = TCFSVPTOLOWERVP(*this_vp_p); + /* + * XXX - Several operations have the side effect + * of vrele'ing their vp's. We must account for + * that. (This should go away in the future.) + */ + if (reles & 1) + VREF(*this_vp_p); + } + + } + + /* + * Call the operation on the lower layer + * with the modified argument structure. + */ + error = VCALL(*(vps_p[0]), descp->vdesc_offset, ap); + + /* + * Maintain the illusion of call-by-value + * by restoring vnodes in the argument structure + * to their original value. + */ + reles = descp->vdesc_flags; + for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) { + if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET) + break; /* bail out at end of list */ + if (old_vps[i] != NULLVP) { + *(vps_p[i]) = old_vps[i]; + if (reles & 1) { + vrele(*(vps_p[i])); + } + } + + /* + * Map the possible out-going vpp + * (Assumes that the lower layer always returns + * a VREF'ed vpp unless it gets an error.) + */ + if (descp->vdesc_vpp_offset != VDESC_NO_OFFSET && + !(descp->vdesc_flags & VDESC_NOMAP_VPP) && + !error) { + /* + * XXX - even though some ops have vpp returned vp's, + * several ops actually vrele this before returning. + * We must avoid these ops. + * (This should go away when these ops are regularized.) + */ + if (descp->vdesc_flags & VDESC_VPP_WILLRELE) + goto out; + vppp = VOPARG_OFFSETTO(struct vnode***, + descp->vdesc_vpp_offset,ap); + /* + * This assumes that **vppp is a locked vnode (it is always + * so as of this writing, NetBSD-current 1995/02/16) + * + * (don't want to lock it if being called on behalf + * of lookup--it plays weird locking games depending + * on whether or not it's looking up ".", "..", etc. + */ + error = tcfs_node_create(old_vps[0]->v_mount, **vppp, *vppp, + descp == &vop_lookup_desc ? 0 : 1); + } + } + + out: + return (error); + +} + + +/* + * We must handle open to be able to catch MNT_NODEV and friends. + */ +int +tcfs_open(v) + void *v; +{ + struct vop_open_args *ap = v; + struct vnode *vp = ap->a_vp; + enum vtype lower_type = VTOTCFS(vp)->tcfs_lowervp->v_type; + + + if (((lower_type == VBLK) || (lower_type == VCHR)) && + (vp->v_mount->mnt_flag & MNT_NODEV)) + return ENXIO; + + return tcfs_bypass(ap); +} + +int +tcfs_inactive(v) + void *v; +{ + struct vop_inactive_args *ap = v; + + /* + * Do nothing (and _don't_ bypass). + * Wait to vrele lowervp until reclaim, + * so that until then our tcfs_node is in the + * cache and reusable. + * + * NEEDSWORK: Someday, consider inactive'ing + * the lowervp and then trying to reactivate it + * with capabilities (v_id) + * like they do in the name lookup cache code. + * That's too much work for now. + */ + VOP_UNLOCK(ap->a_vp, 0, ap->a_p); + + return (0); +} + +int +tcfs_reclaim(v) + void *v; +{ + struct vop_reclaim_args /* { + struct vnode *a_vp; + } */ *ap = v; + struct vnode *vp = ap->a_vp; + struct tcfs_node *xp = VTOTCFS(vp); + struct vnode *lowervp = xp->tcfs_lowervp; + + /* + * Note: in vop_reclaim, vp->v_op == dead_vnodeop_p, + * so we can't call VOPs on ourself. + */ + /* After this assignment, this node will not be re-used. */ + xp->tcfs_lowervp = NULL; + LIST_REMOVE(xp, tcfs_hash); + FREE(vp->v_data, M_TEMP); + vp->v_data = NULL; + vrele (lowervp); + return (0); +} + + +int +tcfs_print(v) + void *v; +{ + struct vop_print_args /* { + struct vnode *a_vp; + } */ *ap = v; + register struct vnode *vp = ap->a_vp; + + printf ("\ttag VT_TCFS, vp=%p, lowervp=%p\n", vp, TCFSVPTOLOWERVP(vp)); + vprint("tcfs lowervp", TCFSVPTOLOWERVP(vp)); + return (0); +} + + +/* + * XXX - vop_strategy must be hand coded because it has no + * vnode in its arguments. + * This goes away with a merged VM/buffer cache. + */ +int +tcfs_strategy(v) + void *v; +{ + struct vop_strategy_args /* { + struct buf *a_bp; + } */ *ap = v; + struct buf *bp = ap->a_bp; + int error; + struct vnode *savedvp; + + savedvp = bp->b_vp; + bp->b_vp = TCFSVPTOLOWERVP(bp->b_vp); + + error = VOP_STRATEGY(bp); + + bp->b_vp = savedvp; + + return (error); +} + + +/* + * XXX - like vop_strategy, vop_bwrite must be hand coded because it has no + * vnode in its arguments. + * This goes away with a merged VM/buffer cache. + */ +int +tcfs_bwrite(v) + void *v; +{ + struct vop_bwrite_args /* { + struct buf *a_bp; + } */ *ap = v; + struct buf *bp = ap->a_bp; + int error; + struct vnode *savedvp; + + savedvp = bp->b_vp; + bp->b_vp = TCFSVPTOLOWERVP(bp->b_vp); + + error = VOP_BWRITE(bp); + + bp->b_vp = savedvp; + + return (error); +} + +/* + * We need a separate tcfs lock routine, to avoid deadlocks at reclaim time. + * If a process holds the lower-vnode locked when it tries to reclaim + * the tcfs upper-vnode, _and_ tcfs_bypass is used as the locking operation, + * then a process can end up locking against itself. + * This has been observed when a tcfs mount is set up to "tunnel" beneath a + * union mount (that setup is useful if you still wish to be able to access + * the non-union version of either the above or below union layer) + */ +int +tcfs_lock(v) + void *v; +{ + struct vop_lock_args *ap = v; + +#if 0 + vop_generic_lock(ap); +#endif + if ((ap->a_flags & LK_TYPE_MASK) == LK_DRAIN) + return (0); + ap->a_flags &= ~LK_INTERLOCK; + + return (tcfs_bypass((struct vop_generic_args *)ap)); +} + +int +tcfs_unlock(v) + void *v; +{ + struct vop_unlock_args *ap = v; +#if 0 + vop_generic_unlock(ap); +#endif + ap->a_flags &= ~LK_INTERLOCK; + + return (tcfs_bypass((struct vop_generic_args *)ap)); +} + +int +tcfs_islocked(v) + void *v; +{ + /* XXX */ + return (0); +} + +int +tcfs_lookup(v) + void *v; +{ + register struct vop_lookup_args /* { + struct vnodeop_desc *a_desc; + struct vnode *a_dvp; + struct vnode **a_vpp; + struct componentname *a_cnp; + } */ *ap = v; + register int error; + int flags = ap->a_cnp->cn_flags; + struct componentname *cnp = ap->a_cnp; +#if 0 + register struct vnode *dvp, *vp; + struct proc *p = cnp->cn_proc; + struct vop_unlock_args unlockargs; + struct vop_lock_args lockargs; +#endif + +#ifdef TCFS_DIAGNOSTIC + printf("tcfs_lookup: dvp=%lx, name='%s'\n", + ap->a_dvp, cnp->cn_nameptr); +#endif + + if ((flags & ISLASTCN) && (ap->a_dvp->v_mount->mnt_flag & MNT_RDONLY) && + (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) + return (EROFS); + error = tcfs_bypass((struct vop_generic_args *)ap); + if (error == EJUSTRETURN && (flags & ISLASTCN) && + (ap->a_dvp->v_mount->mnt_flag & MNT_RDONLY) && + (cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)) + error = EROFS; + +#if 0 + /* + * We must do the same locking and unlocking at this layer as + * is done in the layers below us. We could figure this out + * based on the error return and the LASTCN, LOCKPARENT, and + * LOCKLEAF flags. However, it is more expidient to just find + * out the state of the lower level vnodes and set ours to the + * same state. + */ + dvp = ap->a_dvp; + vp = *ap->a_vpp; + if (dvp == vp) + return (error); + if (!VOP_ISLOCKED(dvp)) { + unlockargs.a_vp = dvp; + unlockargs.a_flags = 0; + unlockargs.a_p = p; + vop_generic_unlock(&unlockargs); + } + if (vp != TCFSVP && VOP_ISLOCKED(vp)) { + lockargs.a_vp = vp; + lockargs.a_flags = LK_SHARED; + lockargs.a_p = p; + vop_generic_lock(&lockargs); + } +#endif + return (error); +} + +/* + * Global vfs data structures + */ +int (**tcfs_vnodeop_p) __P((void *)); +struct vnodeopv_entry_desc tcfs_vnodeop_entries[] = { + { &vop_default_desc, tcfs_bypass }, + + { &vop_getattr_desc, tcfs_getattr }, + { &vop_setattr_desc, tcfs_setattr }, + { &vop_inactive_desc, tcfs_inactive }, + { &vop_reclaim_desc, tcfs_reclaim }, + { &vop_print_desc, tcfs_print }, + + { &vop_lock_desc, tcfs_lock }, + { &vop_unlock_desc, tcfs_unlock }, + { &vop_islocked_desc, tcfs_islocked }, + { &vop_lookup_desc, tcfs_lookup }, /* special locking frob */ + + { &vop_strategy_desc, tcfs_strategy }, + { &vop_bwrite_desc, tcfs_bwrite }, + { &vop_read_desc, tcfs_read }, + { &vop_readdir_desc, tcfs_readdir }, + { &vop_write_desc, tcfs_write }, + { &vop_create_desc, tcfs_create }, + { &vop_mknod_desc, tcfs_mknod }, + { &vop_mkdir_desc, tcfs_mkdir }, + { &vop_link_desc, tcfs_link }, + { &vop_rename_desc, tcfs_rename }, + { &vop_symlink_desc, tcfs_symlink }, + { (struct vnodeop_desc*)NULL, (int(*) __P((void *)))NULL } +}; +struct vnodeopv_desc tcfs_vnodeop_opv_desc = + { &tcfs_vnodeop_p, tcfs_vnodeop_entries }; + diff --git a/sys/sys/mount.h b/sys/sys/mount.h index 261dea541d0..451817c8483 100644 --- a/sys/sys/mount.h +++ b/sys/sys/mount.h @@ -1,4 +1,4 @@ -/* $OpenBSD: mount.h,v 1.36 2000/05/22 17:29:06 mickey Exp $ */ +/* $OpenBSD: mount.h,v 1.37 2000/06/17 17:16:04 provos Exp $ */ /* $NetBSD: mount.h,v 1.48 1996/02/18 11:55:47 fvdl Exp $ */ /* @@ -317,6 +317,7 @@ struct ostatfs { #define MOUNT_EXT2FS "ext2fs" /* Second Extended Filesystem */ #define MOUNT_NCPFS "ncpfs" /* NetWare Network File System */ #define MOUNT_XFS "xfs" /* xfs */ +#define MOUNT_TCFS "tcfs" /* tcfs */ /* * Structure per mounted file system. Each mounted file system has an diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index b5c2175d2fd..47ffb2e8af3 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -1,4 +1,4 @@ -/* $OpenBSD: vnode.h,v 1.24 2000/05/22 13:48:40 provos Exp $ */ +/* $OpenBSD: vnode.h,v 1.25 2000/06/17 17:16:05 provos Exp $ */ /* $NetBSD: vnode.h,v 1.38 1996/02/29 20:59:05 cgd Exp $ */ /* @@ -68,7 +68,7 @@ enum vtype { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO, VBAD }; enum vtagtype { VT_NON, VT_UFS, VT_NFS, VT_MFS, VT_MSDOSFS, VT_LFS, VT_LOFS, VT_FDESC, VT_PORTAL, VT_NULL, VT_UMAP, VT_KERNFS, VT_PROCFS, VT_AFS, VT_ISOFS, - VT_UNION, VT_ADOSFS, VT_EXT2FS, VT_NCPFS, VT_VFS, VT_XFS + VT_UNION, VT_ADOSFS, VT_EXT2FS, VT_NCPFS, VT_VFS, VT_XFS, VT_TCFS }; /* |