Pour cela nous allons d'abord apporter une petite modification au file system
FFS, puis implémenter l'appel système correspondant Afin d'obtenir CECI.
Nous allons reprendre l'idée des flags en les modifiant afin qu'un utilisateur
quelconque puisse appeler un nouvel appel système pour cacher un fichier ou
un répertoire . Les fichiers cachés par un utilisateur non root, le seront
pour tout le monde sauf root. Par contre les fichiers ou répertoires cachés par
le super utilisateur pourront être invisible par le système entier.
Les fichiers ne seront cachés que le secure level sera > 0.
L'introduction dans le noyau de ces routines ralentissent sensiblement l'accès aux fichiers,
En effet dans l'implémentation initiale de readdir (sur les architectures little endian) le contenu du répertoire est recopié dans les structures uio sans aucunes vérifications.
L'implémentation que nous allons rajouter va devoir vérifier un à un les fichiers du répertoire
Les différentes phases à effectuer sont :
/* * Definitions of flags stored in file flags word. * * Super-user and owner changeable flags. */ #define UF_SETTABLE 0x0000ffff /* mask of owner changeable flags */ #define UF_NODUMP 0x00000001 /* do not dump file */ #define UF_IMMUTABLE 0x00000002 /* file may not be changed */ #define UF_APPEND 0x00000004 /* writes to file may only append */ #define UF_OPAQUE 0x00000008 /* directory is opaque wrt. union */ #define UF_USERHIDE 0x00000010 /* user hidden file <== ICI */ #define UF_GROUPHIDE 0x00000020 /* group hidden file <== ICI */ #define UF_OTHERHIDE 0x00000040 /* other hidden file <== ICI */ /* * Super-user changeable flags. */ #define SF_SETTABLE 0xffff0000 /* mask of superuser changeable flags */ #define SF_ARCHIVED 0x00010000 /* file is archived */ #define SF_IMMUTABLE 0x00020000 /* file may not be changed */ #define SF_APPEND 0x00040000 /* writes to file may only append */ #define SF_HIDE 0x00100000 /* system hidden file <== ICI */Nous allons modifier l'appel système qui récupère les noms des fichiers d'un répertoire (la fonction readdir). Cette fonction se trouve dans le répertoire /usr/src/sys/ufs/ufs/ufs_vnops.c et se nomme ufs_readdir.
[...] ligne 1582 #if (BYTE_ORDER == LITTLE_ENDIAN) if (ap->a_vp->v_mount->mnt_maxsymlinklen > 0) { struct dirent *dp; dp = (struct dirent *)uio->uio_iov->iov_base; if ((!(error = VOP_READ(ap->a_vp, uio, 0, ap->a_cred))) && (securelevel > 0)) hide_ffs_file(ap, dp, count - uio->uio_resid); /* ICI */ } else { struct dirent *dp, *edp; struct uio auio; [...]Comme nous allons créer deux nouvelles fonctions il faut les mettre dans le .h correspondant (ufs_extern.h) :
[...] Ligne 59 struct dirent; __BEGIN_DECLS int is_a_ffs_hide_file __P((struct vop_readdir_args *, u_int32_t)); void hide_ffs_file __P((struct vop_readdir_args *, struct dirent *dp, int)); [...]
int is_a_ffs_hide_file(ap, inode_number) struct vop_readdir_args *ap; u_int32_t inode_number; { struct vnode *vnode; struct inode *inode; int result; result = 0; if (!VFS_VGET(ap->a_vp->v_mount, inode_number, &vnode)) { inode = VTOI(vnode); result = (inode->i_ffs_flags & SF_HIDE); if ((ap->a_cred->cr_uid != inode->i_ffs_uid) && (ap->a_cred->cr_gid != inode->i_ffs_gid)) result |= (inode->i_ffs_flags & UF_OTHERHIDE); else { if (ap->a_cred->cr_uid == inode->i_ffs_uid) result |= (inode->i_ffs_flags & UF_USERHIDE); else if (ap->a_cred->cr_gid == inode->i_ffs_gid) result |= (inode->i_ffs_flags & UF_GROUPHIDE); } vput(vnode); } return ((ap->a_cred->cr_uid)?result:(result & SF_HIDE)); }La fonction hide_ffs_file modifie la structure dirent passée en paramètre. Si un fichier ne doit pas apparaitre on modifie le champ d_reclen de l'élement précécent de la structure pour qu'il pointe sur la prochaine entrée qui n'est pas cachée, de plus nous mettons a zéro les données qui doivent être cachées.
void hide_ffs_file(ap, dp, len) struct vop_readdir_args *ap; struct dirent *dp; int len; { struct dirent *dp_prev; struct dirent *end; int tmp; end = (struct dirent *)((char *)dp + len); dp_prev = dp; if ((dp < end) && (dp->d_reclen > 0)) dp = (struct dirent *)((char *) dp + dp->d_reclen); while (dp < end) { while ((is_a_ffs_hide_file(ap, dp->d_fileno)) && (dp < end)) { if (!(dp->d_reclen > 0)) return; dp_prev->d_reclen += dp->d_reclen; tmp = dp->d_reclen; bzero(dp, tmp); dp = (struct dirent *)((char *) dp + tmp); } if (!(dp->d_reclen > 0)) return; dp = (struct dirent *)((char *) dp + dp->d_reclen); dp_prev = (struct dirent *)((char *) dp_prev + dp_prev->d_reclen); } }Nous pouvons dès maintenant tester notre petite modification après avoir recompilé le noyau. Nous n'avons qu'a utiliser l'appel système chflags a qui nous passons un flag de type UF_USERHIDE (0x00000010) dans cet exemple :
root /tmp >cat > chflags.c int main(int argc, char **argv) { int error; if (argc >1) { error = chflags(argv[1], 0x00000010); printf("error = %d\n", error); } } root /tmp >cc chflags.c root /tmp >mkdir titi root /tmp >chmod 755 titi root /tmp >./a.out titi error = 0 root /tmp >whoami root root /tmp >ls -l total 34 -rwx------ 1 root wheel 14758 Nov 14 23:00 a.out -rw------- 1 root wheel 142 Nov 14 22:59 chflags.c drwx------ 2 root wheel 512 Nov 14 23:00 titi root /tmp >su modu modu /tmp >ls -l total 32 -rwx------ 1 root wheel 14758 Nov 14 23:00 a.out -rw------- 1 root wheel 142 Nov 14 22:59 chflags.c modu /tmp >cd titi modu /tmp/titi >pwd pwd: getcwd: No such file or directory modu /tmp/titi >Nous voyons donc que le répertoire existe mais qu'il ne nous apparait plus . Par contre certaines commandes ne marcherons plus dans ces répertoires cachés (exemple pwd).
modu /usr/src/sys/kern >tail -1 syscalls.master 260 STD { int sys_chview(const char *path, u_int flags); } modu /usr/src/sys/kern >
modu /usr/src/sys/kern >make modu /usr/src/sys/kern >tail -2 syscalls.c "chview", /* 260 = chview */ }; root /usr/src/sys/kern >
modu /usr/src/sys/kern >grep -B5 -A32 sys_view vfs_syscalls.c /* * Change view of a file given a path name. */ /* ARGSUSED */ int sys_chview(p, v, retval) struct proc *p; void *v; register_t *retval; { register struct sys_chflags_args /* { syscallarg(char *) path; syscallarg(unsigned int) flags; } */*uap = v; register struct vnode *vp; struct vattr vattr; int error; struct nameidata nd; NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); if ((error = namei(&nd)) != 0) return (error); vp = nd.ni_vp; VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); if (vp->v_mount->mnt_flag & MNT_RDONLY) error = EROFS; else if (SCARG(uap, flags) == VNOVAL) error = EINVAL; else { VATTR_NULL(&vattr); vattr.va_flags = SCARG(uap, flags); error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); } vput(vp); return (error); } modu /usr/src/sys/kern >
modu /usr/src/sys/kern >grep vop_setattr /usr/src/sys/ufs/ffs/ffs_vnops.c { &vop_setattr_desc, ufs_setattr }, /* setattr */ { &vop_setattr_desc, ufs_setattr }, /* setattr */ { &vop_setattr_desc, ufs_setattr }, /* setattr */ modu /usr/src/sys/kern >
modu /usr/src/sys/kern >grep -A5 -B1 SF_IMMUTABLE /usr/src/sys/ufs/ufs/ufs_vnops.c if (cred->cr_uid == 0) { if ((ip->i_ffs_flags & (SF_IMMUTABLE | SF_APPEND))&& securelevel > 0) return (EPERM); ip->i_ffs_flags = vap->va_flags; } else { if (ip->i_ffs_flags & (SF_IMMUTABLE | SF_APPEND) || (vap->va_flags & UF_SETTABLE) != vap->va_flags) return (EPERM); /* ICI */ ip->i_ffs_flags &= SF_SETTABLE; ip->i_ffs_flags |= (vap->va_flags & UF_SETTABLE); } modu /usr/src/sys/kern >
modu /usr/src/lib/libc >grep chview sys/Makefile.inc ASM= accept.o access.o acct.o adjtime.o bind.o chdir.o chflags.o chview.o chmod.o \ modu /usr/src/lib/libc >
modu /usr/src/lib/libc >cp /usr/src/sys/sys/syscall* /usr/include/sys/ modu /usr/src/lib/libc >cp /usr/src/sys/sys/stat.h /usr/include/sys/ modu /usr/src/lib/libc >make && make installEt voilà, c'est fini, il ne reste plus qu'à tester le tout:
modu ~/work/doc >cat > chview.c #include <sys/stat.h> int main(int argc, char **argv) { if (argc > 2) { if (!strcmp(argv[1], "user")) return (chview(argv[2], UF_USERHIDE)); if (!strcmp(argv[1], "group")) return (chview(argv[2], UF_GROUPHIDE)); if (!strcmp(argv[1], "other")) return (chview(argv[2], UF_OTHERHIDE)); if (!strcmp(argv[1], "sys")) return (chview(argv[2], SF_HIDE)); } return (-1); } modu ~/work/doc >cc chview.c -o chview modu ~/work/doc >touch user group other modu ~/work/doc >mkdir titi && ls -l total 58 -rw------- 1 modu work 149 Nov 21 20:40 chview.c -rwx------ 1 modu work 14758 Nov 21 20:40 chview -rw-r--r-- 1 modu work 11853 Nov 21 20:40 syscall drwx------ 2 modu work 512 Nov 21 20:38 titi -rwx------ 1 modu work 0 Nov 21 20:38 user -rwx------ 1 modu work 0 Nov 21 20:38 group -rwx------ 1 modu work 0 Nov 21 20:38 other modu ~/work/doc >id uid=1001(modu) gid=1000(work) groups=1000(work) modu ~/work/doc >./chview user user modu ~/work/doc >./chview user titi modu ~/work/doc >./chview group group modu ~/work/doc >./chview other other modu ~/work/doc >ls -la total 56 -rw------- 1 modu work 354 Nov 21 20:40 chview.c -rwx------ 1 modu work 14758 Nov 21 20:37 chview -rw-r--r-- 1 modu work 11033 Nov 21 20:40 syscall -rwx------ 1 modu work 0 Nov 21 20:38 group -rwx------ 1 modu work 0 Nov 21 20:38 other modu ~/work/doc >cd titi modu ~/work/doc/titi >ls -la ; cd .. total 4 drwx------ 2 modu modu 512 Nov 21 20:38 . drwxr-xr-x 3 modu modu 512 Nov 21 20:39 .. modu ~/work/doc >su uidzero uidzero /home/work/doc >id uid=1002(uidzero) gid=1000(work) groups=1000(work) uidzero /home/modu/work/doc >ls -la total 58 -rw------- 1 modu work 149 Nov 21 20:40 chview.c -rwx------ 1 modu work 14758 Nov 21 20:40 chview -rw-r--r-- 1 modu work 11853 Nov 21 20:40 syscall drwx------ 2 modu work 512 Nov 21 20:38 titi -rwx------ 1 modu work 0 Nov 21 20:38 user -rwx------ 1 modu work 0 Nov 21 20:38 other uidzero /home/modu/work/doc >su #whoami root #ls -la total 58 -rw------- 1 modu work 149 Nov 21 20:40 chview.c -rwx------ 1 modu work 14758 Nov 21 20:40 chview -rw-r--r-- 1 modu work 11853 Nov 21 20:40 syscall drwx------ 2 modu work 512 Nov 21 20:38 titi -rwx------ 1 modu work 0 Nov 21 20:38 user -rwx------ 1 modu work 0 Nov 21 20:38 group -rwx------ 1 modu work 0 Nov 21 20:38 other #Vous pouvez évidemment faire des combinaison de flags, en ajouter, en retirer, ou même mettre le fichier en immuable après l'avoir caché.