diff options
author | Justus Winter <justus@gnupg.org> | 2016-04-18 22:02:19 +0200 |
---|---|---|
committer | Justus Winter <justus@gnupg.org> | 2016-04-18 22:02:19 +0200 |
commit | 6641b7cd7570aeb5349be4ad429cd0e5de09fb1c (patch) | |
tree | 7d89269056e7f29fb9819311fb25df73175bf55a | |
parent | 401a913be8b107d760a9991a4929f7a434931f12 (diff) |
add patch series
5 files changed, 1926 insertions, 0 deletions
diff --git a/debian/patches/gpg0001-trans-add-identity-translator.patch b/debian/patches/gpg0001-trans-add-identity-translator.patch new file mode 100644 index 00000000..6e1b3187 --- /dev/null +++ b/debian/patches/gpg0001-trans-add-identity-translator.patch @@ -0,0 +1,941 @@ +From 7e72e8a337c58e6cb6badff8be4381dc180d8277 Mon Sep 17 00:00:00 2001 +From: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Sat, 23 Jan 2016 00:14:56 +0100 +Subject: [PATCH hurd 1/4] trans: add identity translator + +The 'identity' translator is the simplest possible translator. It +computes the identity function of Hurdish RPC translations. + +* trans/Makefile: Add new files. +* trans/chroot.c: New file. +* trans/chroot.h: Likewise. +* trans/identity.c: Likewise. +--- + trans/Makefile | 7 +- + trans/chroot.c | 724 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + trans/chroot.h | 34 +++ + trans/identity.c | 113 +++++++++ + 4 files changed, 875 insertions(+), 3 deletions(-) + create mode 100644 trans/chroot.c + create mode 100644 trans/chroot.h + create mode 100644 trans/identity.c + +diff --git a/trans/Makefile b/trans/Makefile +index 65b51d1..e4eba0a 100644 +--- a/trans/Makefile ++++ b/trans/Makefile +@@ -21,10 +21,10 @@ makemode := servers + + targets = symlink firmlink ifsock magic null fifo new-fifo fwd crash \ + password hello hello-mt streamio fakeroot proxy-defpager remap \ +- mtab ++ mtab identity + SRCS = ifsock.c symlink.c magic.c null.c fifo.c new-fifo.c fwd.c \ + crash.c firmlink.c password.c hello.c hello-mt.c streamio.c \ +- fakeroot.c proxy-defpager.c remap.c mtab.c ++ fakeroot.c proxy-defpager.c remap.c mtab.c chroot.c identity.c + OBJS = $(SRCS:.c=.o) fsysServer.o ifsockServer.o passwordServer.o \ + crashServer.o crash_replyUser.o msgServer.o \ + default_pagerServer.o default_pagerUser.o \ +@@ -65,7 +65,8 @@ proxy-defpager: default_pagerServer.o default_pagerUser.o + streamio: device_replyServer.o + symlink: fsysServer.o + +-fakeroot: ../libnetfs/libnetfs.a ++identity: chroot.o ++fakeroot identity: ../libnetfs/libnetfs.a + fifo new-fifo: ../libpipe/libpipe.a + crash fifo firmlink hello hello-mt ifsock magic mtab new-fifo null password proxy-defpager remap streamio: ../libtrivfs/libtrivfs.a + $(targets): ../libfshelp/libfshelp.a \ +diff --git a/trans/chroot.c b/trans/chroot.c +new file mode 100644 +index 0000000..0055d6c +--- /dev/null ++++ b/trans/chroot.c +@@ -0,0 +1,724 @@ ++/* chroot.c -- support for writing chrooting translators ++ Copyright (C) 2002, 2003, 2008, 2013, 2016 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or ++ modify it under the terms of the GNU General Public License as ++ published by the Free Software Foundation; either version 2, or (at ++ your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, but ++ WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ ++ ++#include <argz.h> ++#include <argp.h> ++#include <dirent.h> ++#include <error.h> ++#include <hurd/netfs.h> ++#include <stddef.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <fcntl.h> ++#include <sys/mman.h> ++#include <sys/stat.h> ++#include <pthread.h> ++#include <hurd/ihash.h> ++#include <hurd/paths.h> ++#include <sys/types.h> ++#include <sys/wait.h> ++#include <unistd.h> ++ ++#include <version.h> ++ ++#include "chroot.h" ++ ++#include "libnetfs/fs_S.h" ++#include "libnetfs/io_S.h" ++#include "libnetfs/fsys_S.h" ++#include "libports/notify_S.h" ++#include "libports/interrupt_S.h" ++ ++/* Make a new virtual node. Always consumes the ports. If ++ successful, NP will be locked. */ ++error_t __attribute__ ((weak)) ++chroot_new_node (file_t file, size_t size, struct node **np) ++{ ++ error_t err; ++ struct netnode *nn; ++ ++ *np = netfs_make_node_alloc (sizeof *nn + size); ++ if (*np == NULL) ++ { ++ mach_port_deallocate (mach_task_self (), file); ++ return ENOMEM; ++ } ++ nn = netfs_node_netnode (*np); ++ nn->file = file; ++ return 0; ++} ++ ++/* Node NP has no more references; free all its associated storage. */ ++void ++netfs_node_norefs (struct node *np) ++{ ++ pthread_mutex_unlock (&np->lock); ++ ++ chroot_node_norefs (np); ++ mach_port_deallocate (mach_task_self (), netfs_node_netnode (np)->file); ++ free (np); ++} ++ ++/* This is the cleanup function we install in netfs_protid_class. If ++ the associated nodes reference count would also drop to zero, and ++ the node has no faked attributes, we destroy it as well. */ ++static void ++chroot_netfs_release_protid (void *cookie) ++{ ++ netfs_release_protid (cookie); ++ ++ int cports = ports_count_class (netfs_control_class); ++ int nports = ports_count_class (netfs_protid_class); ++ ports_enable_class (netfs_control_class); ++ ports_enable_class (netfs_protid_class); ++ if (cports == 0 && nports == 0) ++ { ++ /* The last client is gone. Our job is done. */ ++ error_t err = netfs_shutdown (0); ++ if (! err) ++ exit (EXIT_SUCCESS); ++ ++ /* If netfs_shutdown returns EBUSY, we lost a race against ++ fsys_goaway. Hence we ignore this error. */ ++ if (err != EBUSY) ++ error (1, err, "netfs_shutdown"); ++ } ++} ++ ++error_t __attribute__ ((weak)) ++chroot_init (void) ++{ ++ /* Install our own clean routine. */ ++ netfs_protid_class->clean_routine = chroot_netfs_release_protid; ++ return 0; ++} ++ ++/* This is called by netfs_S_fsys_getroot. */ ++error_t __attribute__ ((weak)) ++netfs_check_open_permissions (struct iouser *user, struct node *np, ++ int flags, int newnode) ++{ ++ return 0; /* XXX */ ++} ++ ++error_t __attribute__ ((weak)) ++netfs_S_dir_lookup (struct protid *diruser, ++ char *filename, ++ int flags, ++ mode_t mode, ++ retry_type *do_retry, ++ char *retry_name, ++ mach_port_t *retry_port, ++ mach_msg_type_name_t *retry_port_type) ++{ ++ struct node *dnp, *np; ++ error_t err; ++ struct protid *newpi; ++ struct iouser *user; ++ file_t file; ++ file_t dir; ++ ++ if (!diruser) ++ return EOPNOTSUPP; ++ ++ dnp = diruser->po->np; ++ ++ //error (0, 0, "dir_lookup (#uids: %d, %s, flags %x, ...)", diruser->user->uids->num, filename, flags); ++ ++ dir = netfs_node_netnode (dnp)->file; ++ err = dir_lookup (dir, filename, flags, mode, do_retry, retry_name, &file); ++ if (err) ++ return err; ++ ++ switch (*do_retry) ++ { ++ case FS_RETRY_NORMAL: ++ break; ++ ++ case FS_RETRY_REAUTH: ++ /* Fallthrough. */ ++ ++ case FS_RETRY_MAGICAL: ++ *retry_port = file; ++ *retry_port_type = MACH_MSG_TYPE_MOVE_SEND; ++ return 0; ++ ++ default: ++ /* Invalid response to our dir_lookup request. */ ++ if (MACH_PORT_VALID (file)) ++ mach_port_deallocate (mach_task_self (), file); ++ *retry_port = MACH_PORT_NULL; ++ *retry_port_type = MACH_MSG_TYPE_COPY_SEND; ++ return EOPNOTSUPP; ++ } ++ ++ /* We have a new port to an underlying node. ++ Find or make our corresponding virtual node. */ ++ ++ np = 0; ++ ++ err = chroot_new_node (file, 0, &np); ++ if (!err) ++ err = netfs_validate_stat (np, diruser->user); ++ if (err) ++ goto lose; ++ ++ assert (*do_retry == FS_RETRY_NORMAL); ++ flags &= ~(O_CREAT|O_EXCL|O_NOLINK|O_NOTRANS|O_NONBLOCK); ++ ++ err = iohelp_dup_iouser (&user, diruser->user); ++ if (!err) ++ { ++ newpi = netfs_make_protid (netfs_make_peropen (np, flags, diruser->po), ++ user); ++ if (! newpi) ++ { ++ iohelp_free_iouser (user); ++ err = errno; ++ } ++ else ++ { ++ *retry_port = ports_get_right (newpi); ++ *retry_port_type = MACH_MSG_TYPE_MAKE_SEND; ++ ports_port_deref (newpi); ++ } ++ } ++ ++ lose: ++ if (dir != netfs_node_netnode (dnp)->file) ++ mach_port_deallocate (mach_task_self (), dir); ++ if (np != NULL) ++ netfs_nput (np); ++ return err; ++} ++ ++/* The user may define this function. Attempt to set the passive ++ translator record for FILE to ARGZ (of length ARGZLEN) for user ++ CRED. */ ++error_t __attribute__ ((weak)) ++netfs_set_translator (struct iouser *cred, struct node *np, ++ char *argz, size_t argzlen) ++{ ++ return file_set_translator (netfs_node_netnode (np)->file, ++ FS_TRANS_EXCL|FS_TRANS_SET, ++ 0, 0, ++ argz, argzlen, ++ MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND); ++} ++ ++/* These callbacks are used only by the standard netfs_S_dir_lookup, ++ which we do not use. But the shared library requires us to define them. */ ++error_t __attribute__ ((weak)) ++netfs_attempt_lookup (struct iouser *user, struct node *dir, ++ char *name, struct node **np) ++{ ++ assert (! "should not be here"); ++ return EIEIO; ++} ++ ++error_t __attribute__ ((weak)) ++netfs_attempt_create_file (struct iouser *user, struct node *dir, ++ char *name, mode_t mode, struct node **np) ++{ ++ assert (! "should not be here"); ++ return EIEIO; ++} ++ ++/* Make sure that NP->nn_stat is filled with the most current information. ++ CRED identifies the user responsible for the operation. NP is locked. */ ++error_t __attribute__ ((weak)) ++netfs_validate_stat (struct node *np, struct iouser *cred) ++{ ++ struct stat st; ++ error_t err = io_stat (netfs_node_netnode (np)->file, &st); ++ if (err) ++ return err; ++ ++ np->nn_stat = st; ++ /* XXX */ ++ np->nn_translated = S_ISLNK (st.st_mode) ? S_IFLNK : 0; ++ ++ return 0; ++} ++ ++error_t __attribute__ ((weak)) ++netfs_attempt_chown (struct iouser *cred, struct node *np, ++ uid_t uid, uid_t gid) ++{ ++ if (! cred) ++ return EOPNOTSUPP; ++ return file_chown (netfs_node_netnode (np)->file, uid, gid); ++} ++ ++error_t __attribute__ ((weak)) ++netfs_attempt_chauthor (struct iouser *cred, struct node *np, uid_t author) ++{ ++ if (! cred) ++ return EOPNOTSUPP; ++ return file_chauthor (netfs_node_netnode (np)->file, author); ++} ++ ++/* This should attempt a chmod call for the user specified by CRED on ++ locked node NODE, to change the mode to MODE. Unlike the normal Unix ++ and Hurd meaning of chmod, this function is also used to attempt to ++ change files into other types. If such a transition is attempted which ++ is impossible, then return EOPNOTSUPP. */ ++error_t __attribute__ ((weak)) ++netfs_attempt_chmod (struct iouser *cred, struct node *np, mode_t mode) ++{ ++ if (! cred) ++ return EOPNOTSUPP; ++ return file_chmod (netfs_node_netnode (np)->file, mode); ++} ++ ++/* The user must define this function. Attempt to turn locked node NP ++ (user CRED) into a symlink with target NAME. */ ++error_t __attribute__ ((weak)) ++netfs_attempt_mksymlink (struct iouser *cred, struct node *np, char *name) ++{ ++ int namelen = strlen (name) + 1; ++ char trans[sizeof _HURD_SYMLINK + namelen]; ++ memcpy (trans, _HURD_SYMLINK, sizeof _HURD_SYMLINK); ++ memcpy (&trans[sizeof _HURD_SYMLINK], name, namelen); ++ return file_set_translator (netfs_node_netnode (np)->file, ++ FS_TRANS_EXCL|FS_TRANS_SET, ++ FS_TRANS_EXCL|FS_TRANS_SET, 0, ++ trans, sizeof trans, ++ MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND); ++} ++ ++error_t __attribute__ ((weak)) ++netfs_attempt_mkdev (struct iouser *cred, struct node *np, ++ mode_t type, dev_t indexes) ++{ ++ char *trans = 0; ++ int translen = asprintf (&trans, "%s%c%d%c%d", ++ S_ISCHR (type) ? _HURD_CHRDEV : _HURD_BLKDEV, ++ '\0', major (indexes), '\0', minor (indexes)); ++ if (trans == 0) ++ return ENOMEM; ++ else ++ { ++ error_t err = file_set_translator (netfs_node_netnode (np)->file, ++ FS_TRANS_EXCL|FS_TRANS_SET, ++ FS_TRANS_EXCL|FS_TRANS_SET, 0, ++ trans, translen + 1, ++ MACH_PORT_NULL, ++ MACH_MSG_TYPE_COPY_SEND); ++ free (trans); ++ return err; ++ } ++} ++ ++error_t __attribute__ ((weak)) ++netfs_attempt_chflags (struct iouser *cred, struct node *np, int flags) ++{ ++ return file_chflags (netfs_node_netnode (np)->file, flags); ++} ++ ++error_t __attribute__ ((weak)) ++netfs_attempt_utimes (struct iouser *cred, struct node *np, ++ struct timespec *atime, struct timespec *mtime) ++{ ++ union tv ++ { ++ struct timeval tv; ++ time_value_t tvt; ++ }; ++ union tv a, m; ++ if (atime) ++ { ++ TIMESPEC_TO_TIMEVAL (&a.tv, atime); ++ } ++ else ++ a.tv.tv_sec = a.tv.tv_usec = -1; ++ if (mtime) ++ { ++ TIMESPEC_TO_TIMEVAL (&m.tv, mtime); ++ } ++ else ++ m.tv.tv_sec = m.tv.tv_usec = -1; ++ ++ return file_utimes (netfs_node_netnode (np)->file, a.tvt, m.tvt); ++} ++ ++error_t __attribute__ ((weak)) ++netfs_attempt_set_size (struct iouser *cred, struct node *np, off_t size) ++{ ++ return file_set_size (netfs_node_netnode (np)->file, size); ++} ++ ++error_t __attribute__ ((weak)) ++netfs_attempt_statfs (struct iouser *cred, struct node *np, struct statfs *st) ++{ ++ return file_statfs (netfs_node_netnode (np)->file, st); ++} ++ ++error_t __attribute__ ((weak)) ++netfs_attempt_sync (struct iouser *cred, struct node *np, int wait) ++{ ++ return file_sync (netfs_node_netnode (np)->file, wait, 0); ++} ++ ++error_t __attribute__ ((weak)) ++netfs_attempt_syncfs (struct iouser *cred, int wait) ++{ ++ return 0; ++} ++ ++error_t __attribute__ ((weak)) ++netfs_attempt_mkdir (struct iouser *user, struct node *dir, ++ char *name, mode_t mode) ++{ ++ return dir_mkdir (netfs_node_netnode (dir)->file, name, mode | S_IRWXU); ++} ++ ++ ++/* XXX ++ Removing a node should mark the netnode so that it is GC'd when ++ it has no hard refs. ++ */ ++ ++error_t __attribute__ ((weak)) ++netfs_attempt_unlink (struct iouser *user, struct node *dir, char *name) ++{ ++ return dir_unlink (netfs_node_netnode (dir)->file, name); ++} ++ ++error_t __attribute__ ((weak)) ++netfs_attempt_rename (struct iouser *user, struct node *fromdir, ++ char *fromname, struct node *todir, ++ char *toname, int excl) ++{ ++ return dir_rename (netfs_node_netnode (fromdir)->file, fromname, ++ netfs_node_netnode (todir)->file, toname, excl); ++} ++ ++error_t __attribute__ ((weak)) ++netfs_attempt_rmdir (struct iouser *user, ++ struct node *dir, char *name) ++{ ++ return dir_rmdir (netfs_node_netnode (dir)->file, name); ++} ++ ++error_t __attribute__ ((weak)) ++netfs_attempt_link (struct iouser *user, struct node *dir, ++ struct node *file, char *name, int excl) ++{ ++ return dir_link (netfs_node_netnode (dir)->file, ++ netfs_node_netnode (file)->file, name, excl); ++} ++ ++error_t __attribute__ ((weak)) ++netfs_attempt_mkfile (struct iouser *user, struct node *dir, ++ mode_t mode, struct node **np) ++{ ++ file_t newfile; ++ error_t err = dir_mkfile (netfs_node_netnode (dir)->file, O_RDWR|O_EXEC, ++ mode, &newfile); ++ pthread_mutex_unlock (&dir->lock); ++ if (err) ++ return err; ++ ++ err = chroot_new_node (newfile, 0, np); ++ if (err) ++ return err; ++ ++ pthread_mutex_unlock (&(*np)->lock); ++ return err; ++} ++ ++error_t __attribute__ ((weak)) ++netfs_attempt_readlink (struct iouser *user, struct node *np, char *buf) ++{ ++ char transbuf[sizeof _HURD_SYMLINK + np->nn_stat.st_size + 1]; ++ char *trans = transbuf; ++ size_t translen = sizeof transbuf; ++ error_t err = file_get_translator (netfs_node_netnode (np)->file, ++ &trans, &translen); ++ if (err == 0) ++ { ++ if (translen < sizeof _HURD_SYMLINK ++ || memcmp (trans, _HURD_SYMLINK, sizeof _HURD_SYMLINK) != 0) ++ err = EINVAL; ++ else ++ { ++ assert (translen <= sizeof _HURD_SYMLINK + np->nn_stat.st_size + 1); ++ memcpy (buf, &trans[sizeof _HURD_SYMLINK], ++ translen - sizeof _HURD_SYMLINK); ++ } ++ if (trans != transbuf) ++ munmap (trans, translen); ++ } ++ return err; ++} ++ ++error_t __attribute__ ((weak)) ++netfs_get_dirents (struct iouser *cred, struct node *dir, ++ int entry, int nentries, char **data, ++ mach_msg_type_number_t *datacnt, ++ vm_size_t bufsize, int *amt) ++{ ++ error_t err; ++ err = dir_readdir (netfs_node_netnode (dir)->file, data, datacnt, ++ entry, nentries, bufsize, amt); ++ return err; ++} ++ ++error_t __attribute__ ((weak)) ++netfs_attempt_read (struct iouser *cred, struct node *np, ++ off_t offset, size_t *len, void *data) ++{ ++ char *buf = data; ++ error_t err = io_read (netfs_node_netnode (np)->file, ++ &buf, len, offset, *len); ++ if (err == 0 && buf != data) ++ { ++ memcpy (data, buf, *len); ++ munmap (buf, *len); ++ } ++ return err; ++} ++ ++error_t __attribute__ ((weak)) ++netfs_attempt_write (struct iouser *cred, struct node *np, ++ off_t offset, size_t *len, void *data) ++{ ++ return io_write (netfs_node_netnode (np)->file, data, *len, offset, len); ++} ++ ++error_t __attribute__ ((weak)) ++netfs_report_access (struct iouser *cred, struct node *np, int *types) ++{ ++ return file_check_access (netfs_node_netnode (np)->file, types); ++} ++ ++error_t __attribute__ ((weak)) ++netfs_file_get_storage_info (struct iouser *cred, ++ struct node *np, ++ mach_port_t **ports, ++ mach_msg_type_name_t *ports_type, ++ mach_msg_type_number_t *num_ports, ++ int **ints, ++ mach_msg_type_number_t *num_ints, ++ off_t **offsets, ++ mach_msg_type_number_t *num_offsets, ++ char **data, ++ mach_msg_type_number_t *data_len) ++{ ++ *ports_type = MACH_MSG_TYPE_MOVE_SEND; ++ return file_get_storage_info (netfs_node_netnode (np)->file, ++ ports, num_ports, ++ ints, num_ints, ++ offsets, num_offsets, ++ data, data_len); ++} ++ ++error_t __attribute__ ((weak)) ++netfs_S_file_exec (struct protid *user, ++ task_t task, ++ int flags, ++ char *argv, ++ size_t argvlen, ++ char *envp, ++ size_t envplen, ++ mach_port_t *fds, ++ size_t fdslen, ++ mach_port_t *portarray, ++ size_t portarraylen, ++ int *intarray, ++ size_t intarraylen, ++ mach_port_t *deallocnames, ++ size_t deallocnameslen, ++ mach_port_t *destroynames, ++ size_t destroynameslen) ++{ ++ error_t err; ++ file_t file; ++ ++ if (!user) ++ return EOPNOTSUPP; ++ ++ file = netfs_node_netnode (user->po->np)->file; ++ err = mach_port_mod_refs (mach_task_self (), ++ file, MACH_PORT_RIGHT_SEND, 1); ++ ++ if (!err) ++ { ++ /* We cannot use MACH_MSG_TYPE_MOVE_SEND because we might need to ++ retry an interrupted call that would have consumed the rights. */ ++ err = file_exec (file, task, flags, argv, argvlen, ++ envp, envplen, fds, MACH_MSG_TYPE_COPY_SEND, fdslen, ++ portarray, MACH_MSG_TYPE_COPY_SEND, portarraylen, ++ intarray, intarraylen, deallocnames, deallocnameslen, ++ destroynames, destroynameslen); ++ mach_port_deallocate (mach_task_self (), file); ++ } ++ ++ if (err == 0) ++ { ++ size_t i; ++ mach_port_deallocate (mach_task_self (), task); ++ for (i = 0; i < fdslen; ++i) ++ mach_port_deallocate (mach_task_self (), fds[i]); ++ for (i = 0; i < portarraylen; ++i) ++ mach_port_deallocate (mach_task_self (), portarray[i]); ++ } ++ return err; ++} ++ ++error_t __attribute__ ((weak)) ++netfs_S_io_map (struct protid *user, ++ mach_port_t *rdobj, mach_msg_type_name_t *rdobjtype, ++ mach_port_t *wrobj, mach_msg_type_name_t *wrobjtype) ++{ ++ if (!user) ++ return EOPNOTSUPP; ++ *rdobjtype = *wrobjtype = MACH_MSG_TYPE_MOVE_SEND; ++ ++ return io_map (netfs_node_netnode (user->po->np)->file, rdobj, wrobj); ++} ++ ++error_t __attribute__ ((weak)) ++netfs_S_io_map_cntl (struct protid *user, ++ mach_port_t *obj, ++ mach_msg_type_name_t *objtype) ++{ ++ if (!user) ++ return EOPNOTSUPP; ++ *objtype = MACH_MSG_TYPE_MOVE_SEND; ++ ++ return io_map_cntl (netfs_node_netnode (user->po->np)->file, obj); ++} ++ ++error_t __attribute__ ((weak)) ++netfs_S_io_identity (struct protid *user, ++ mach_port_t *id, ++ mach_msg_type_name_t *idtype, ++ mach_port_t *fsys, ++ mach_msg_type_name_t *fsystype, ++ ino_t *fileno) ++{ ++ if (!user) ++ return EOPNOTSUPP; ++ ++ *idtype = *fsystype = MACH_MSG_TYPE_MOVE_SEND; ++ ++ return io_identity (netfs_node_netnode (user->po->np)->file, ++ id, fsys, fileno); ++} ++ ++#define NETFS_S_SIMPLE(name) \ ++error_t __attribute__ ((weak)) \ ++netfs_S_##name (struct protid *user) \ ++{ \ ++ if (!user) \ ++ return EOPNOTSUPP; \ ++ \ ++ return name (netfs_node_netnode (user->po->np)->file); \ ++} ++ ++NETFS_S_SIMPLE (io_get_conch) ++NETFS_S_SIMPLE (io_release_conch) ++NETFS_S_SIMPLE (io_eofnotify) ++NETFS_S_SIMPLE (io_readnotify) ++NETFS_S_SIMPLE (io_readsleep) ++NETFS_S_SIMPLE (io_sigio) ++ ++error_t __attribute__ ((weak)) ++netfs_S_io_prenotify (struct protid *user, ++ vm_offset_t start, vm_offset_t stop) ++{ ++ if (!user) ++ return EOPNOTSUPP; ++ ++ return io_prenotify (netfs_node_netnode (user->po->np)->file, start, stop); ++} ++ ++error_t __attribute__ ((weak)) ++netfs_S_io_postnotify (struct protid *user, ++ vm_offset_t start, vm_offset_t stop) ++{ ++ if (!user) ++ return EOPNOTSUPP; ++ ++ return io_postnotify (netfs_node_netnode (user->po->np)->file, start, stop); ++} ++ ++/* This overrides the library's definition. */ ++int __attribute__ ((weak)) ++netfs_demuxer (mach_msg_header_t *inp, ++ mach_msg_header_t *outp) ++{ ++ mig_routine_t routine; ++ if ((routine = netfs_io_server_routine (inp)) || ++ (routine = netfs_fs_server_routine (inp)) || ++ (routine = ports_notify_server_routine (inp)) || ++ (routine = netfs_fsys_server_routine (inp)) || ++ /* XXX we should intercept interrupt_operation and do ++ the ports_S_interrupt_operation work as well as ++ sending an interrupt_operation to the underlying file. ++ */ ++ (routine = ports_interrupt_server_routine (inp))) ++ { ++ (*routine) (inp, outp); ++ return TRUE; ++ } ++ else ++ { ++ /* We didn't recognize the message ID, so pass the message through ++ unchanged to the underlying file. */ ++ struct protid *cred; ++ if (MACH_MSGH_BITS_LOCAL (inp->msgh_bits) == ++ MACH_MSG_TYPE_PROTECTED_PAYLOAD) ++ cred = ports_lookup_payload (netfs_port_bucket, ++ inp->msgh_protected_payload, ++ netfs_protid_class); ++ else ++ cred = ports_lookup_port (netfs_port_bucket, ++ inp->msgh_local_port, ++ netfs_protid_class); ++ if (cred == 0) ++ /* This must be an unknown message on our fsys control port. */ ++ return 0; ++ else ++ { ++ error_t err; ++ assert (MACH_MSGH_BITS_LOCAL (inp->msgh_bits) ++ == MACH_MSG_TYPE_MOVE_SEND ++ || MACH_MSGH_BITS_LOCAL (inp->msgh_bits) ++ == MACH_MSG_TYPE_PROTECTED_PAYLOAD); ++ inp->msgh_bits = (inp->msgh_bits & MACH_MSGH_BITS_COMPLEX) ++ | MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, ++ MACH_MSGH_BITS_REMOTE (inp->msgh_bits)); ++ inp->msgh_local_port = inp->msgh_remote_port; /* reply port */ ++ inp->msgh_remote_port = netfs_node_netnode (cred->po->np)->file; ++ err = mach_msg (inp, MACH_SEND_MSG, inp->msgh_size, 0, ++ MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, ++ MACH_PORT_NULL); ++ if (err) ++ ((mig_reply_header_t *) outp)->RetCode = err; ++ else ++ /* We already sent the message, so the server loop ++ shouldn't do it again. */ ++ ((mig_reply_header_t *) outp)->RetCode = MIG_NO_REPLY; ++ ports_port_deref (cred); ++ return 1; ++ } ++ } ++} +diff --git a/trans/chroot.h b/trans/chroot.h +new file mode 100644 +index 0000000..057a251 +--- /dev/null ++++ b/trans/chroot.h +@@ -0,0 +1,34 @@ ++#ifndef __HURD_CHROOT_H__ ++#define __HURD_CHROOT_H__ ++ ++struct netnode ++{ ++ file_t file; /* port on real file */ ++}; ++ ++struct chroot_node; ++ ++error_t chroot_init (void); ++ ++/* Make a new virtual node. Always consumes the ports. If ++ successful, NP will be locked. */ ++error_t chroot_new_node (file_t file, size_t size, struct node **np); ++ ++/* Users must implement this. */ ++void chroot_node_norefs (struct node *np); ++ ++/* Return the address of the chroot_node for NODE. NODE must have been ++ allocated using chroot_new_node. */ ++static inline struct chroot_node * ++chroot_node (struct node *node) ++{ ++ return (struct chroot_node *) ((char *) netfs_node_netnode (node) ++ + sizeof (struct netnode)); ++} ++ ++// XXX ++pthread_mutex_t idport_ihash_lock; ++struct hurd_ihash idport_ihash; ++ ++ ++#endif /* __HURD_CHROOT_H__ */ +diff --git a/trans/identity.c b/trans/identity.c +new file mode 100644 +index 0000000..875fc4f +--- /dev/null ++++ b/trans/identity.c +@@ -0,0 +1,113 @@ ++/* identity -- a translator interposing file RPCs. ++ Copyright (C) 2016 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or ++ modify it under the terms of the GNU General Public License as ++ published by the Free Software Foundation; either version 2, or (at ++ your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, but ++ WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ ++ ++#include <argp.h> ++#include <error.h> ++#include <fcntl.h> ++#include <hurd/netfs.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <unistd.h> ++ ++#include <version.h> ++ ++#include "chroot.h" ++ ++const char *argp_program_version = STANDARD_HURD_VERSION (identity); ++ ++char *netfs_server_name = "identity"; ++char *netfs_server_version = HURD_VERSION; ++int netfs_maxsymlinks = 16; /* arbitrary */ ++ ++struct chroot_node ++{ ++}; ++ ++void ++chroot_node_norefs (struct node *np) ++{ ++} ++ ++ ++static struct argp_option options[] = ++{ ++ {0} ++}; ++ ++static char *args_doc = ""; ++static char *doc = ++ "The identity translator relays file RPCs without changing them." ++ "\v" ++ "It can be used in conjunction with settrans --chroot to implement " ++ "a hurdish chroot utility."; ++ ++static error_t ++parse_opt (int key, char *arg, struct argp_state *state) ++{ ++ switch (key) ++ { ++ default: ++ return ARGP_ERR_UNKNOWN; ++ } ++ return 0; ++} ++ ++int ++main (int argc, char **argv) ++{ ++ error_t err; ++ mach_port_t bootstrap; ++ ++ struct argp argp = ++ { ++ .options = options, ++ .parser = parse_opt, ++ .args_doc = args_doc, ++ .doc = doc, ++ }; ++ ++ /* Parse our command line arguments (all none of them). */ ++ argp_parse (&argp, argc, argv, 0, 0, 0); ++ ++ task_get_bootstrap_port (mach_task_self (), &bootstrap); ++ if (! MACH_PORT_VALID (bootstrap)) ++ error (1, 0, "Must be started as a translator"); ++ ++ netfs_init (); ++ chroot_init (); ++ ++ /* Get our underlying node (we presume it's a directory) and use ++ that to make the root node of the filesystem. */ ++ err = chroot_new_node (netfs_startup (bootstrap, O_READ), ++ sizeof (struct chroot_node), &netfs_root_node); ++ if (err) ++ error (5, err, "Cannot create root node"); ++ ++ err = netfs_validate_stat (netfs_root_node, 0); ++ if (err) ++ error (6, err, "Cannot stat underlying node"); ++ ++ netfs_root_node->nn_stat.st_mode &= ~(S_IPTRANS | S_IATRANS); ++ netfs_root_node->nn_stat.st_mode |= S_IROOT; ++ pthread_mutex_unlock (&netfs_root_node->lock); ++ ++ netfs_server_loop (); /* Never returns. */ ++ ++ /*NOTREACHED*/ ++ return 0; ++} +-- +2.1.4 + diff --git a/debian/patches/gpg0002-trans-add-transparent-GnuPG-translator.patch b/debian/patches/gpg0002-trans-add-transparent-GnuPG-translator.patch new file mode 100644 index 00000000..323ef96c --- /dev/null +++ b/debian/patches/gpg0002-trans-add-transparent-GnuPG-translator.patch @@ -0,0 +1,890 @@ +From f3dde907bc9bae67710eb47cb9d43748bbee278c Mon Sep 17 00:00:00 2001 +From: Justus Winter <justus@gnupg.org> +Date: Thu, 24 Mar 2016 22:55:54 +0100 +Subject: [PATCH hurd 2/4] trans: add transparent GnuPG translator + +* trans/Makefile: Add new file. +* trans/gpg.c: New file. +* utils/Makefile: Add new file. +* utils/gpg-env.sh: New file. +--- + trans/Makefile | 9 +- + trans/gpg.c | 682 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + utils/Makefile | 6 +- + utils/gpg-env.sh | 122 ++++++++++ + 4 files changed, 812 insertions(+), 7 deletions(-) + create mode 100644 trans/gpg.c + create mode 100644 utils/gpg-env.sh + +diff --git a/trans/Makefile b/trans/Makefile +index e4eba0a..422d499 100644 +--- a/trans/Makefile ++++ b/trans/Makefile +@@ -21,10 +21,11 @@ makemode := servers + + targets = symlink firmlink ifsock magic null fifo new-fifo fwd crash \ + password hello hello-mt streamio fakeroot proxy-defpager remap \ +- mtab identity ++ mtab identity gpg + SRCS = ifsock.c symlink.c magic.c null.c fifo.c new-fifo.c fwd.c \ + crash.c firmlink.c password.c hello.c hello-mt.c streamio.c \ +- fakeroot.c proxy-defpager.c remap.c mtab.c chroot.c identity.c ++ fakeroot.c proxy-defpager.c remap.c mtab.c chroot.c identity.c \ ++ gpg.c + OBJS = $(SRCS:.c=.o) fsysServer.o ifsockServer.o passwordServer.o \ + crashServer.o crash_replyUser.o msgServer.o \ + default_pagerServer.o default_pagerUser.o \ +@@ -65,8 +66,8 @@ proxy-defpager: default_pagerServer.o default_pagerUser.o + streamio: device_replyServer.o + symlink: fsysServer.o + +-identity: chroot.o +-fakeroot identity: ../libnetfs/libnetfs.a ++identity gpg: chroot.o ++fakeroot identity gpg: ../libnetfs/libnetfs.a + fifo new-fifo: ../libpipe/libpipe.a + crash fifo firmlink hello hello-mt ifsock magic mtab new-fifo null password proxy-defpager remap streamio: ../libtrivfs/libtrivfs.a + $(targets): ../libfshelp/libfshelp.a \ +diff --git a/trans/gpg.c b/trans/gpg.c +new file mode 100644 +index 0000000..abdea7c +--- /dev/null ++++ b/trans/gpg.c +@@ -0,0 +1,682 @@ ++/* gpg -- a translator for encrypting, decrypting, and verifying files ++ Copyright (C) 2016 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or ++ modify it under the terms of the GNU General Public License as ++ published by the Free Software Foundation; either version 2, or (at ++ your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, but ++ WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ ++ ++#include <argz.h> ++#include <argp.h> ++#include <dirent.h> ++#include <error.h> ++#include <hurd/netfs.h> ++#include <stddef.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <fcntl.h> ++#include <sys/mman.h> ++#include <sys/stat.h> ++#include <pthread.h> ++#include <hurd/ihash.h> ++#include <hurd/paths.h> ++#include <sys/types.h> ++#include <sys/wait.h> ++#include <unistd.h> ++ ++#include <version.h> ++ ++#include "chroot.h" ++ ++#include "libnetfs/fs_S.h" ++#include "libnetfs/io_S.h" ++#include "libnetfs/fsys_S.h" ++#include "libports/notify_S.h" ++#include "libports/interrupt_S.h" ++ ++const char *argp_program_version = STANDARD_HURD_VERSION (gpg); ++ ++char *netfs_server_name = "gpg"; ++char *netfs_server_version = HURD_VERSION; ++int netfs_maxsymlinks = 16; /* arbitrary */ ++ ++struct chroot_node ++{ ++ unsigned int encrypt:1; ++ file_t shadow_file; ++}; ++ ++#define GPG_DEFAULT_FILENAME "/usr/bin/gpg2" ++static char* gpg_filename = GPG_DEFAULT_FILENAME; ++static file_t gpg_file; ++ ++int symmetric; ++char *recipients; ++size_t recipients_len; ++ ++static error_t ++execute_gpg (mach_port_t in, mach_port_t out, mach_port_t extra, ++ char *argz, size_t argz_len, pid_t *pid) ++{ ++ error_t err; ++ task_t task; ++ process_t proc; ++ mach_port_t ports[INIT_PORT_MAX]; ++ mach_port_t fds[STDERR_FILENO + 2]; ++ int ints[INIT_INT_MAX]; ++ int i; ++ ++ for (i = 0; i < INIT_PORT_MAX; i++) ++ ports[i] = MACH_PORT_NULL; ++ for (i = 0; i < STDERR_FILENO + 2; i++) ++ fds[i] = MACH_PORT_NULL; ++ memset (ints, 0, INIT_INT_MAX * sizeof(int)); ++ ++ ports[INIT_PORT_CWDIR] = getcwdir (); ++ ports[INIT_PORT_CRDIR] = getcrdir (); ++ ports[INIT_PORT_AUTH] = getauth (); ++ fds[STDIN_FILENO] = in; ++ fds[STDOUT_FILENO] = out; ++ fds[STDERR_FILENO] = getdport (STDERR_FILENO); ++ fds[STDERR_FILENO+1] = extra; ++ ++ err = task_create (mach_task_self (), 0, &task); ++ if (err) ++ goto lose; ++ ++ proc = getproc (); ++ proc_child (proc, task); ++ ++ /* Try and exec GnuPG in TASK... */ ++ err = file_exec (gpg_file, task, EXEC_DEFAULTS, ++ argz, argz_len, 0, 0, ++ fds, MACH_MSG_TYPE_COPY_SEND, STDERR_FILENO + 2, ++ ports, MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX, ++ ints, INIT_INT_MAX, 0, 0, 0, 0); ++ if (err) ++ goto lose; ++ ++ err = proc_task2pid (proc, task, pid); ++ ++ lose: ++ for (i = 0; i < INIT_PORT_MAX; i++) ++ mach_port_deallocate (mach_task_self (), ports[i]); ++ mach_port_deallocate (mach_task_self (), fds[STDERR_FILENO]); ++ return err; ++} ++ ++error_t ++clone_file (file_t file, file_t *new_file) ++{ ++ error_t err; ++ off_t newp; ++ retry_type do_retry; ++ string_t retry_name; ++ err = dir_lookup (file, "", O_RDONLY, 0, &do_retry, retry_name, new_file); ++ if (err) ++ return err; ++ return io_seek (*new_file, 0, SEEK_SET, &newp); ++} ++ ++static int ++gpg_verify (file_t sigfile, file_t orig_file) ++{ ++ error_t err; ++ file_t file; ++ pid_t pid; ++ char *argz = NULL; ++ size_t argz_len = 0; ++ err = clone_file (orig_file, &file); ++ if (err) ++ return 0; ++ ++ argz_add (&argz, &argz_len, "gpg2"); ++ argz_add (&argz, &argz_len, "--verify"); ++ argz_add (&argz, &argz_len, "/dev/fd/3"); ++ argz_add (&argz, &argz_len, "-"); ++ err = execute_gpg (file, getdport (STDERR_FILENO), sigfile, argz, argz_len, &pid); ++ mach_port_deallocate (mach_task_self (), file); ++ if (err) ++ { ++ error (0, err, "execute_gpg"); ++ return 0; ++ } ++ ++ int status; ++ while (waitpid (pid, &status, 0) == (pid_t)-1 && errno == EINTR) ++ { } ++ ++ return WIFEXITED (status) && WEXITSTATUS (status) == 0; ++} ++ ++static int ++gpg_decrypt (file_t cipherfile, file_t plainfile) ++{ ++ error_t err; ++ pid_t pid; ++ char *argz = NULL; ++ size_t argz_len = 0; ++ ++ argz_add (&argz, &argz_len, "gpg2"); ++ argz_add (&argz, &argz_len, "--output"); ++ argz_add (&argz, &argz_len, "-"); ++ err = execute_gpg (cipherfile, plainfile, MACH_PORT_NULL, ++ argz, argz_len, &pid); ++ if (err) ++ { ++ error (0, err, "execute_gpg"); ++ return 0; ++ } ++ ++ int status; ++ while (waitpid (pid, &status, 0) == (pid_t)-1 && errno == EINTR) ++ { } ++ ++ return WIFEXITED (status) && WEXITSTATUS (status) == 0; ++} ++ ++static int ++gpg_encrypt (file_t plainfile, file_t cipherfile) ++{ ++ error_t err; ++ pid_t pid; ++ char *argz = NULL; ++ size_t argz_len = 0; ++ ++ argz_add (&argz, &argz_len, "gpg2"); ++ argz_add (&argz, &argz_len, "--output"); ++ argz_add (&argz, &argz_len, "-"); ++ if (recipients) ++ { ++ char *recipient; ++ argz_add (&argz, &argz_len, "--encrypt"); ++ for (recipient = recipients; ++ recipient; ++ recipient = argz_next (recipients, recipients_len, recipient)) ++ { ++ argz_add (&argz, &argz_len, "--recipient"); ++ argz_add (&argz, &argz_len, recipient); ++ } ++ } ++ if (symmetric) ++ argz_add (&argz, &argz_len, "--symmetric"); ++ ++ err = execute_gpg (plainfile, cipherfile, MACH_PORT_NULL, ++ argz, argz_len, &pid); ++ if (err) ++ { ++ error (0, err, "execute_gpg"); ++ return 0; ++ } ++ ++ int status; ++ while (waitpid (pid, &status, 0) == (pid_t)-1 && errno == EINTR) ++ { } ++ ++ return WIFEXITED (status) && WEXITSTATUS (status) == 0; ++} ++ ++static error_t ++make_tmp_file (file_t *file) ++{ ++ char name[] = "/tmp/gpgtmp-XXXXXX"; ++ int fd; ++ ++ fd = mkstemp (name); ++ if (fd == -1) ++ return errno; ++ if (unlink (name) == -1) ++ return errno; ++ *file = getdport (fd); ++ close (fd); ++ return 0; ++} ++ ++error_t ++netfs_S_dir_lookup (struct protid *diruser, ++ char *filename, ++ int flags, ++ mode_t mode, ++ retry_type *do_retry, ++ char *retry_name, ++ mach_port_t *retry_port, ++ mach_msg_type_name_t *retry_port_type) ++{ ++ struct node *dnp, *np; ++ error_t err; ++ struct protid *newpi; ++ struct iouser *user; ++ file_t file; ++ file_t dir; ++ ++ if (! diruser) ++ return EOPNOTSUPP; ++ ++ dnp = diruser->po->np; ++ ++ dir = netfs_node_netnode (dnp)->file; ++ err = dir_lookup (dir, filename, ++ flags & (O_NOLINK|O_RDWR|O_EXEC|O_CREAT|O_EXCL|O_NONBLOCK), ++ mode, do_retry, retry_name, &file); ++ if (err == ENOENT) ++ { ++ file_t gpgfile; ++ char *gpgname; ++ asprintf (&gpgname, "%s.gpg", filename); ++ gpgfile = file_name_lookup_under (dir, gpgname, O_RDONLY, 0); ++ if (MACH_PORT_VALID (gpgfile)) ++ { ++ file_t tmpfile; ++ int ok; ++ off_t newp; ++ ++ err = make_tmp_file (&tmpfile); ++ if (err) ++ return err; ++ ++ ok = gpg_decrypt (gpgfile, tmpfile); ++ mach_port_deallocate (mach_task_self (), gpgfile); ++ if (! ok) ++ { ++ mach_port_deallocate (mach_task_self (), tmpfile); ++ return EIO; ++ } ++ ++ err = io_seek (tmpfile, 0, SEEK_SET, &newp); ++ if (err) ++ { ++ mach_port_deallocate (mach_task_self (), tmpfile); ++ return err; ++ } ++ ++ *do_retry = FS_RETRY_NORMAL; ++ retry_name[0] = 0; ++ *retry_port = tmpfile; ++ *retry_port_type = MACH_MSG_TYPE_MOVE_SEND; ++ return 0; ++ } ++ free (gpgname); ++ } ++ ++ if (err) ++ return err; ++ ++ switch (*do_retry) ++ { ++ case FS_RETRY_NORMAL: ++ break; ++ ++ case FS_RETRY_REAUTH: ++ error (0, 0, "FS_RETRY_REAUTH"); ++ /* Fallthrough. */ ++ ++ case FS_RETRY_MAGICAL: ++ *retry_port = file; ++ *retry_port_type = MACH_MSG_TYPE_MOVE_SEND; ++ return 0; ++ ++ default: ++ /* Invalid response to our dir_lookup request. */ ++ if (MACH_PORT_VALID (file)) ++ mach_port_deallocate (mach_task_self (), file); ++ *retry_port = MACH_PORT_NULL; ++ *retry_port_type = MACH_MSG_TYPE_COPY_SEND; ++ return EOPNOTSUPP; ++ } ++ ++ /* We have a new port to an underlying node. ++ Find or make our corresponding virtual node. */ ++ ++ np = 0; ++ ++ pthread_mutex_lock (&dnp->lock); ++ err = chroot_new_node (file, sizeof (struct chroot_node), &np); ++ pthread_mutex_unlock (&dnp->lock); ++ if (!err) ++ { ++ chroot_node (np)->encrypt = chroot_node (dnp)->encrypt; ++ chroot_node (np)->shadow_file = MACH_PORT_NULL; ++ err = netfs_validate_stat (np, diruser->user); ++ } ++ if (err) ++ goto lose; ++ ++ if (chroot_node (np)->encrypt && flags & O_WRITE ++ && strncmp (filename, "dev/", 4) != 0) ++ { ++ char *ciphname; ++ asprintf (&ciphname, "%s.gpg", filename); ++ if (ciphname == NULL) ++ { ++ err = errno; ++ goto lose; ++ } ++ ++ /* Fixup name. */ ++ err = dir_link (dir, file, ciphname, 0); ++ free (ciphname); ++ if (err) ++ return err; ++ ++ err = dir_unlink (dir, filename); ++ if (err) ++ return err; ++ ++ err = make_tmp_file (&chroot_node (np)->shadow_file); ++ if (err) ++ return err; ++ } ++ ++ if (retry_name[0] == 0) ++ { ++ file_t sig; ++ char *signame; ++ ++ asprintf (&signame, "%s.sig", filename); ++ if (signame == NULL) ++ { ++ err = errno; ++ goto lose; ++ } ++ ++ sig = file_name_lookup_under (dir, signame, O_RDONLY, 0); ++ if (MACH_PORT_VALID (sig)) ++ { ++ if (! gpg_verify (sig, file)) ++ err = EIO; ++ free (signame); ++ signame = NULL; ++ mach_port_deallocate (mach_task_self (), sig); ++ if (err) ++ goto lose; ++ } ++ free (signame); ++ } ++ ++ assert (*do_retry == FS_RETRY_NORMAL); ++ flags &= ~(O_CREAT|O_EXCL|O_NOLINK|O_NOTRANS|O_NONBLOCK); ++ ++ err = iohelp_dup_iouser (&user, diruser->user); ++ if (!err) ++ { ++ newpi = netfs_make_protid (netfs_make_peropen (np, flags, diruser->po), ++ user); ++ if (! newpi) ++ { ++ iohelp_free_iouser (user); ++ err = errno; ++ } ++ else ++ { ++ *retry_port = ports_get_right (newpi); ++ *retry_port_type = MACH_MSG_TYPE_MAKE_SEND; ++ ports_port_deref (newpi); ++ } ++ } ++ ++ lose: ++ if (dir != netfs_node_netnode (dnp)->file) ++ mach_port_deallocate (mach_task_self (), dir); ++ if (np != NULL) ++ netfs_nput (np); ++ return err; ++} ++ ++error_t ++netfs_attempt_mkfile (struct iouser *user, struct node *dir, ++ mode_t mode, struct node **np) ++{ ++ file_t newfile; ++ error_t err = dir_mkfile (netfs_node_netnode (dir)->file, O_RDWR|O_EXEC, ++ mode, &newfile); ++ pthread_mutex_unlock (&dir->lock); ++ if (err) ++ return err; ++ ++ err = chroot_new_node (newfile, sizeof (struct chroot_node), np); ++ if (err) ++ return err; ++ ++ if (chroot_node (dir)->encrypt) ++ { ++ err = make_tmp_file (&chroot_node (*np)->shadow_file); ++ if (err) ++ return err; ++ } ++ else ++ chroot_node (*np)->shadow_file = MACH_PORT_NULL; ++ ++ pthread_mutex_unlock (&(*np)->lock); ++ return err; ++} ++ ++error_t ++netfs_attempt_read (struct iouser *cred, struct node *np, ++ off_t offset, size_t *len, void *data) ++{ ++ struct chroot_node *n = chroot_node (np); ++ char *buf = data; ++ error_t err = io_read (n->shadow_file ?: netfs_node_netnode (np)->file, ++ &buf, len, offset, *len); ++ if (err == 0 && buf != data) ++ { ++ memcpy (data, buf, *len); ++ munmap (buf, *len); ++ } ++ return err; ++} ++ ++error_t ++netfs_attempt_write (struct iouser *cred, struct node *np, ++ off_t offset, size_t *len, void *data) ++{ ++ struct chroot_node *n = chroot_node (np); ++ return io_write (n->shadow_file ?: netfs_node_netnode (np)->file, ++ data, *len, offset, len); ++} ++ ++error_t ++netfs_attempt_sync (struct iouser *cred, struct node *np, int wait) ++{ ++ error_t err; ++ file_t gpg_file = netfs_node_netnode (np)->file; ++ struct chroot_node *n = chroot_node (np); ++ ++ err = file_sync (n->shadow_file ?: gpg_file, wait, 0); ++ if (err) ++ return err; ++ ++ if (wait && MACH_PORT_VALID (n->shadow_file)) ++ { ++ file_t shadow_file; ++ off_t newp; ++ ++ err = clone_file (n->shadow_file, &shadow_file); ++ if (err) ++ return err; ++ ++ err = io_seek (gpg_file, 0, SEEK_SET, &newp); ++ if (err) ++ return err; ++ ++ err = gpg_encrypt (shadow_file, gpg_file); ++ if (err) ++ return err; ++ ++ mach_port_deallocate (mach_task_self (), shadow_file); ++ err = file_sync (gpg_file, wait, 0); ++ } ++ ++ return err; ++} ++ ++ ++error_t ++netfs_attempt_link (struct iouser *user, struct node *dir, ++ struct node *file, char *name, int excl) ++{ ++ /* XXX translate name if file is encrypted. */ ++ return dir_link (netfs_node_netnode (dir)->file, ++ netfs_node_netnode (file)->file, name, excl); ++} ++ ++void ++chroot_node_norefs (struct node *np) ++{ ++ error_t err; ++ file_t gpg_file = netfs_node_netnode (np)->file; ++ struct chroot_node *n = chroot_node (np); ++ if (n->encrypt) ++ { ++ off_t newp; ++ ++ err = io_seek (n->shadow_file, 0, SEEK_SET, &newp); ++ if (err) ++ return; ++ ++ err = io_seek (gpg_file, 0, SEEK_SET, &newp); ++ if (err) ++ return; ++ ++ err = gpg_encrypt (n->shadow_file, gpg_file); ++ if (err) ++ return; ++ ++ mach_port_deallocate (mach_task_self (), n->shadow_file); ++ } ++} ++ ++ ++error_t ++netfs_get_dirents (struct iouser *cred, struct node *dir, ++ int entry, int nentries, char **data, ++ mach_msg_type_number_t *datacnt, ++ vm_size_t bufsize, int *amt) ++{ ++ error_t err; ++ char *ptr; ++ struct dirent *dent; ++ err = dir_readdir (netfs_node_netnode (dir)->file, data, datacnt, ++ entry, nentries, bufsize, amt); ++ if (err) ++ return err; ++ ++ for (ptr = *data, dent = (struct dirent *) ptr; ++ ptr - *data < *datacnt; ++ ptr += dent->d_reclen, dent = (struct dirent *) ptr) ++ { ++ size_t len = strlen (dent->d_name); ++ if (len > 4 && strcmp (&dent->d_name[len - 4], ".gpg") == 0) ++ memset (&dent->d_name[len - 4], 0, 4); ++ } ++ ++ return 0; ++} ++ ++#define OPT_GPG_PROGRAM -1 ++ ++static struct argp_option options[] = ++{ ++ {NULL, 0, NULL, 0, "How to encrypt:", 1}, ++ {"recipient", 'r', "NAME", 0, "Encrypt for user NAME. " ++ "Can be given multiple times.", 1}, ++ {"symmetric", 'c', NULL, 0, "Encrypt with a password.", 1}, ++ {NULL, 0, NULL, 0, "Advanced options:", 2}, ++ {"gpg-program", OPT_GPG_PROGRAM, "FILENAME", 0, ++ "Path to the GNU Privacy Guard executable ["GPG_DEFAULT_FILENAME"].", 2}, ++ {0} ++}; ++ ++static char *args_doc = ""; ++static char *doc = "Transparently encrypt, decrypt, and verify signatures" ++ " using GnuPG." ++ "\vFor everyday use, the commands 'encrypt', 'decrypt', and 'verify'" ++ " offer a simple and convenient frontend for this translator."; ++ ++static error_t ++parse_opt (int key, char *arg, struct argp_state *state) ++{ ++ error_t err; ++ switch (key) ++ { ++ case 'r': ++ err = argz_add (&recipients, &recipients_len, arg); ++ if (err) ++ error (1, err, "argz_add"); ++ break; ++ ++ case 'c': ++ symmetric = 1; ++ break; ++ ++ case OPT_GPG_PROGRAM: ++ gpg_filename = arg; ++ break; ++ ++ default: ++ return ARGP_ERR_UNKNOWN; ++ } ++ return 0; ++} ++ ++int ++main (int argc, char **argv) ++{ ++ error_t err; ++ mach_port_t bootstrap; ++ ++ struct argp argp = ++ { ++ .options = options, ++ .parser = parse_opt, ++ .args_doc = args_doc, ++ .doc = doc, ++ }; ++ ++ /* Parse our command line arguments (all none of them). */ ++ argp_parse (&argp, argc, argv, 0, 0, 0); ++ ++ task_get_bootstrap_port (mach_task_self (), &bootstrap); ++ if (! MACH_PORT_VALID (bootstrap)) ++ error (1, 0, "Must be started as a translator"); ++ ++ gpg_file = file_name_lookup (gpg_filename, O_EXEC, 0); ++ if (! MACH_PORT_VALID (gpg_file)) ++ error (1, errno, "%s", gpg_filename); ++ ++ netfs_init (); ++ chroot_init (); ++ ++ /* Get our underlying node (we presume it's a directory) and use ++ that to make the root node of the filesystem. */ ++ err = chroot_new_node (netfs_startup (bootstrap, O_READ), ++ sizeof (struct chroot_node), &netfs_root_node); ++ if (err) ++ error (5, err, "Cannot create root node"); ++ ++ err = netfs_validate_stat (netfs_root_node, 0); ++ if (err) ++ error (6, err, "Cannot stat underlying node"); ++ ++ netfs_root_node->nn_stat.st_mode &= ~(S_IPTRANS | S_IATRANS); ++ netfs_root_node->nn_stat.st_mode |= S_IROOT; ++ pthread_mutex_unlock (&netfs_root_node->lock); ++ ++ chroot_node (netfs_root_node)->encrypt = 1; ++ chroot_node (netfs_root_node)->shadow_file = MACH_PORT_NULL; ++ ++ netfs_server_loop (); /* Never returns. */ ++ ++ /*NOTREACHED*/ ++ return 0; ++} +diff --git a/utils/Makefile b/utils/Makefile +index d2ef9e8..aa6ff34 100644 +--- a/utils/Makefile ++++ b/utils/Makefile +@@ -22,16 +22,16 @@ targets = shd ps settrans showtrans syncfs fsysopts \ + storeinfo login w uptime ids loginpr sush vmstat portinfo \ + devprobe vminfo addauth rmauth unsu setauth ftpcp ftpdir storecat \ + storeread msgport rpctrace mount gcore fakeauth fakeroot remap \ +- umount nullauth rpcscan vmallocate ++ umount nullauth rpcscan vmallocate gpg-env + +-special-targets = loginpr sush uptime fakeroot remap ++special-targets = loginpr sush uptime fakeroot remap gpg-env + SRCS = shd.c ps.c settrans.c syncfs.c showtrans.c addauth.c rmauth.c \ + fsysopts.c storeinfo.c login.c loginpr.sh sush.sh w.c \ + uptime.sh psout.c ids.c vmstat.c portinfo.c devprobe.c vminfo.c \ + parse.c frobauth.c frobauth-mod.c setauth.c pids.c nonsugid.c \ + unsu.c ftpcp.c ftpdir.c storeread.c storecat.c msgport.c \ + rpctrace.c mount.c gcore.c fakeauth.c fakeroot.sh remap.sh \ +- nullauth.c match-options.c msgids.c rpcscan.c ++ nullauth.c match-options.c msgids.c rpcscan.c gpg-env.sh + + OBJS = $(filter-out %.sh,$(SRCS:.c=.o)) + HURDLIBS = ps ihash store fshelp ports ftpconn shouldbeinlibc +diff --git a/utils/gpg-env.sh b/utils/gpg-env.sh +new file mode 100644 +index 0000000..cd3c9d5 +--- /dev/null ++++ b/utils/gpg-env.sh +@@ -0,0 +1,122 @@ ++#!/bin/sh ++# Execute a command in an environment which encrypts, decrypts, and ++# verifies files on demand. ++# ++# Copyright (C) 2016 Free Software Foundation, Inc. ++# ++# This file is part of the GNU Hurd. ++# ++# The GNU Hurd is free software; you can redistribute it and/or ++# modify it under the terms of the GNU General Public License as ++# published by the Free Software Foundation; either version 2, or (at ++# your option) any later version. ++# ++# The GNU Hurd is distributed in the hope that it will be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++# General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++# ++ ++USAGE="Usage: ++ [gpg-env] encrypt for RECIPIENT [RECIPIENT...] -- [OPTION...] [COMMAND...] ++ [gpg-env] encrypt with password [OPTION...] [COMMAND...] ++ [gpg-env] decrypt [OPTION...] [COMMAND...] ++ [gpg-env] decrypt with password [OPTION...] [COMMAND...] ++ [gpg-env] verify [OPTION...] [COMMAND...]" ++DOC="Execute COMMAND in an environment where files are automatically ++encrypted, decrypted and verified." ++ ++help() ++{ ++ [ "$1" ] && echo "$1 ++" ++ echo "$USAGE" ++ echo "" ++ echo "$DOC" ++ echo "" ++ echo " -?, --help Give this help list" ++ echo " --usage Give a short usage message" ++ echo " -V, --version Print program version" ++ [ "$1" ] && exit 1 || exit 0 ++} ++ ++if [ "$(basename $0)" = "gpg-env.sh" ] \ ++ || [ "$(basename $0)" = "gpg-env" ]; then ++ ACTION="$1" ++ if [ ! "$ACTION" ]; then ++ help "No action given." ++ fi ++ shift ++else ++ ACTION="$(basename $0)" ++fi ++ ++case "$ACTION" in ++ "encrypt") ;; ++ "decrypt") ;; ++ "verify") ;; ++ *) ++ help "Invalid action '$ACTION'." ++esac ++ ++ENCRYPT="" ++if [ "$ACTION" = "encrypt" ]; then ++ if [ "$1" = "with" ] && [ "$2" = "password" ]; then ++ ENCRYPT="--symmetric" ++ shift 2 ++ elif [ "$1" = "for" ]; then ++ shift ++ while [ "$#" -gt 0 ] && [ "x$1" != "x--" ]; do ++ ENCRYPT="$ENCRYPT --recipient $1" ++ shift ++ done ++ if [ "$ENCRYPT" = "" ]; then ++ echo "No recipients given." ++ exit 1 ++ fi ++ if [ "x$1" = "x--" ]; then ++ shift ++ elif [ "$#" -eq 0 ]; then ++ # it's ok if there are no more arguments ++ : ++ else ++ echo "Recipient list must be terminated using '--'." ++ exit 1 ++ fi ++ fi ++fi ++ ++while [ "$#" -gt 0 ]; do ++ case "$1" in ++ --help|"-?") ++ help ++ ;; ++ --usage) ++ echo "$USAGE" ++ echo "Options: [-V?] [--help] [--usage] [--version]" ++ exit 0;; ++ --version|-V) ++ echo "STANDARD_HURD_VERSION_gpg-env_"; exit 0;; ++ --) ++ shift ++ break ++ ;; ++ *) ++ break ++ esac ++done ++ ++if [ $# -eq 0 ]; then ++ set -- ${SHELL:-/bin/sh} ++fi ++ ++# We exec settrans, which execs the target command in the chroot ++# context provided by /hurd/gpg. ++exec /bin/settrans \ ++ --chroot-chdir "$PWD" \ ++ --chroot "$@" -- \ ++ / /hurd/gpg $ENCRYPT +-- +2.1.4 + diff --git a/debian/patches/gpg0003-libdiskfs-perform-synchronous-operations-in-periodic.patch b/debian/patches/gpg0003-libdiskfs-perform-synchronous-operations-in-periodic.patch new file mode 100644 index 00000000..0f6e1d35 --- /dev/null +++ b/debian/patches/gpg0003-libdiskfs-perform-synchronous-operations-in-periodic.patch @@ -0,0 +1,29 @@ +From 046833d473c3d10cec736676da7035b7282b56ea Mon Sep 17 00:00:00 2001 +From: Justus Winter <justus@gnupg.org> +Date: Sun, 17 Apr 2016 19:52:26 +0200 +Subject: [PATCH hurd 3/4] libdiskfs: perform synchronous operations in + periodic sync + +* libdiskfs/sync-interval.c (periodic_sync): Set wait flag. +--- + libdiskfs/sync-interval.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libdiskfs/sync-interval.c b/libdiskfs/sync-interval.c +index 14405f2..ea6e758 100644 +--- a/libdiskfs/sync-interval.c ++++ b/libdiskfs/sync-interval.c +@@ -120,8 +120,8 @@ periodic_sync (void * arg) + will have held the lock while it did its work. */ + if (_diskfs_diskdirty) + { +- diskfs_sync_everything (0); +- diskfs_set_hypermetadata (0, 0); ++ diskfs_sync_everything (1); ++ diskfs_set_hypermetadata (1, 0); + } + pthread_rwlock_unlock (&diskfs_fsys_lock); + } +-- +2.1.4 + diff --git a/debian/patches/gpg0004-libdiskfs-xxx-log-periodic-syncs.patch b/debian/patches/gpg0004-libdiskfs-xxx-log-periodic-syncs.patch new file mode 100644 index 00000000..3d36b2fe --- /dev/null +++ b/debian/patches/gpg0004-libdiskfs-xxx-log-periodic-syncs.patch @@ -0,0 +1,62 @@ +From 011cbfbcceab7673ccf33a17b1751b4afd6792f7 Mon Sep 17 00:00:00 2001 +From: Justus Winter <justus@gnupg.org> +Date: Sun, 17 Apr 2016 19:09:52 +0200 +Subject: [PATCH hurd 4/4] libdiskfs: xxx log periodic syncs + +--- + libdiskfs/init-main.c | 3 +++ + libdiskfs/sync-interval.c | 8 ++++++++ + 2 files changed, 11 insertions(+) + +diff --git a/libdiskfs/init-main.c b/libdiskfs/init-main.c +index 3e03ae4..72cf62a 100644 +--- a/libdiskfs/init-main.c ++++ b/libdiskfs/init-main.c +@@ -22,6 +22,7 @@ + #include <assert.h> + #include <error.h> + #include <hurd/store.h> ++#include <syslog.h> + + struct store * + diskfs_init_main (struct argp *startup_argp, +@@ -44,6 +45,8 @@ diskfs_init_main (struct argp *startup_argp, + if (err) + error (2, err, "store_parsed_name"); + ++ openlog (diskfs_disk_name, LOG_CONS, LOG_DAEMON); ++ + /* This must come after the args have been parsed, as this is where the + host priv ports are set for booting. */ + diskfs_console_stdio (); +diff --git a/libdiskfs/sync-interval.c b/libdiskfs/sync-interval.c +index ea6e758..a090ecd 100644 +--- a/libdiskfs/sync-interval.c ++++ b/libdiskfs/sync-interval.c +@@ -20,6 +20,7 @@ + #include <errno.h> + #include <pthread.h> + #include <unistd.h> ++#include <syslog.h> + + #include <hurd/fsys.h> + +@@ -120,8 +121,15 @@ periodic_sync (void * arg) + will have held the lock while it did its work. */ + if (_diskfs_diskdirty) + { ++ time_t start, stop; ++ time (&start); + diskfs_sync_everything (1); + diskfs_set_hypermetadata (1, 0); ++ time (&stop); ++ ++ if (stop - start > 1) ++ syslog (LOG_NOTICE, "Periodic global sync took %ds.", ++ stop - start); + } + pthread_rwlock_unlock (&diskfs_fsys_lock); + } +-- +2.1.4 + diff --git a/debian/patches/series b/debian/patches/series index 10bff006..f2755c5e 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -41,3 +41,7 @@ fs_unification0002-libnetfs-rename-error-to-err.patch fs_unification0003-libnetfs-rename-diruser-to-dircred.patch fs_unification0004-libdiskfs-cosmetic-changes.patch fs_unification0005-YYY-Unify-the-short-circuit-translator-logic.patch +gpg0001-trans-add-identity-translator.patch +gpg0002-trans-add-transparent-GnuPG-translator.patch +gpg0003-libdiskfs-perform-synchronous-operations-in-periodic.patch +gpg0004-libdiskfs-xxx-log-periodic-syncs.patch |