diff options
Diffstat (limited to 'debian')
-rw-r--r-- | debian/patches/gpg0001-trans-add-transparent-GnuPG-translator.patch | 1826 |
1 files changed, 0 insertions, 1826 deletions
diff --git a/debian/patches/gpg0001-trans-add-transparent-GnuPG-translator.patch b/debian/patches/gpg0001-trans-add-transparent-GnuPG-translator.patch deleted file mode 100644 index d6fe3e7c..00000000 --- a/debian/patches/gpg0001-trans-add-transparent-GnuPG-translator.patch +++ /dev/null @@ -1,1826 +0,0 @@ -From ff80f49389c117d3a19dae3d0e9548ebed96e528 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] trans: add transparent GnuPG translator - -* trans/Makefile: Add new files. -* trans/chroot.c: New file. -* trans/chroot.h: Likewise. -* trans/gpg.c: Likewise. -* trans/identity.c: Likewise. -* utils/gpg-env.sh: Likewise. ---- - trans/Makefile | 8 +- - trans/chroot.c | 768 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ - trans/chroot.h | 34 +++ - trans/gpg.c | 679 ++++++++++++++++++++++++++++++++++++++++++++++++ - trans/identity.c | 113 ++++++++ - utils/Makefile | 6 +- - utils/gpg-env.sh | 121 +++++++++ - 7 files changed, 1723 insertions(+), 6 deletions(-) - create mode 100644 trans/chroot.c - create mode 100644 trans/chroot.h - create mode 100644 trans/gpg.c - create mode 100644 trans/identity.c - create mode 100755 utils/gpg-env.sh - -diff --git a/trans/Makefile b/trans/Makefile -index 65b51d1..e3d89c2 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 -+ mtab gpg 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 gpg.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 +66,8 @@ proxy-defpager: default_pagerServer.o default_pagerUser.o - streamio: device_replyServer.o - symlink: fsysServer.o - --fakeroot: ../libnetfs/libnetfs.a -+gpg identity: chroot.o -+fakeroot gpg 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..089ad84 ---- /dev/null -+++ b/trans/chroot.c -@@ -0,0 +1,768 @@ -+/* 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 -+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 == 0) -+ { -+ mach_port_deallocate (mach_task_self (), file); -+ return ENOMEM; -+ } -+ nn = netfs_node_netnode (*np); -+ nn->file = file; -+ return 0; -+ -+ lose: -+ mach_port_deallocate (mach_task_self (), file); -+ free (*np); -+ *np = NULL; -+ return err; -+} -+ -+/* Node NP has no more references; free all its associated storage. */ -+void -+netfs_node_norefs (struct node *np) -+{ -+ pthread_mutex_unlock (&np->lock); -+ pthread_spin_unlock (&netfs_node_refcnt_lock); -+ -+ chroot_node_norefs (np); -+ mach_port_deallocate (mach_task_self (), netfs_node_netnode (np)->file); -+ free (np); -+ -+ pthread_spin_lock (&netfs_node_refcnt_lock); -+} -+ -+/* 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 -+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 -+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; -+ mach_port_t file; -+ -+ if (!diruser) -+ return EOPNOTSUPP; -+ -+ dnp = diruser->po->np; -+ -+ mach_port_t 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) -+ { -+ /* xxx deref stuff */ -+ 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; -+ -+ redo_hash_lookup: -+ pthread_mutex_lock (&dnp->lock); -+ err = chroot_new_node (file, 0, &np); -+ pthread_mutex_unlock (&dnp->lock); -+ 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 -+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, -+ FS_TRANS_EXCL|FS_TRANS_SET, 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 -+netfs_attempt_lookup (struct iouser *user, struct node *dir, -+ char *name, struct node **np) -+{ -+ assert (! "should not be here"); -+ return EIEIO; -+} -+ -+error_t -+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 -+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; -+ np->nn_translated = S_ISLNK (st.st_mode) ? S_IFLNK : 0; -+ -+ return 0; -+} -+ -+error_t -+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 -+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 -+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 -+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 -+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 -+netfs_attempt_chflags (struct iouser *cred, struct node *np, int flags) -+{ -+ return file_chflags (netfs_node_netnode (np)->file, flags); -+} -+ -+error_t -+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 -+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 -+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 -+netfs_attempt_syncfs (struct iouser *cred, int wait) -+{ -+ return 0; -+} -+ -+error_t -+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 -+netfs_attempt_unlink (struct iouser *user, struct node *dir, char *name) -+{ -+ return dir_unlink (netfs_node_netnode (dir)->file, name); -+} -+ -+error_t -+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 -+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 -+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 -+netfs_report_access (struct iouser *cred, struct node *np, int *types) -+{ -+ return file_check_access (netfs_node_netnode (np)->file, types); -+} -+ -+error_t -+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); -+} -+ -+kern_return_t -+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; -+ -+ pthread_mutex_lock (&user->po->np->lock); -+ file = netfs_node_netnode (user->po->np)->file; -+ err = mach_port_mod_refs (mach_task_self (), -+ file, MACH_PORT_RIGHT_SEND, 1); -+ pthread_mutex_unlock (&user->po->np->lock); -+ -+ 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 (netfs_node_netnode (user->po->np)->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 -+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) -+{ -+ error_t err; -+ -+ if (!user) -+ return EOPNOTSUPP; -+ *rdobjtype = *wrobjtype = MACH_MSG_TYPE_MOVE_SEND; -+ -+ pthread_mutex_lock (&user->po->np->lock); -+ err = io_map (netfs_node_netnode (user->po->np)->file, rdobj, wrobj); -+ pthread_mutex_unlock (&user->po->np->lock); -+ return err; -+} -+ -+error_t -+netfs_S_io_map_cntl (struct protid *user, -+ mach_port_t *obj, -+ mach_msg_type_name_t *objtype) -+{ -+ error_t err; -+ -+ if (!user) -+ return EOPNOTSUPP; -+ *objtype = MACH_MSG_TYPE_MOVE_SEND; -+ -+ pthread_mutex_lock (&user->po->np->lock); -+ err = io_map_cntl (netfs_node_netnode (user->po->np)->file, obj); -+ pthread_mutex_unlock (&user->po->np->lock); -+ return err; -+} -+ -+error_t -+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) -+{ -+ error_t err; -+ -+ if (!user) -+ return EOPNOTSUPP; -+ -+ *idtype = *fsystype = MACH_MSG_TYPE_MOVE_SEND; -+ -+ pthread_mutex_lock (&user->po->np->lock); -+ err = io_identity (netfs_node_netnode (user->po->np)->file, -+ id, fsys, fileno); -+ pthread_mutex_unlock (&user->po->np->lock); -+ return err; -+} -+ -+#define NETFS_S_SIMPLE(name) \ -+error_t \ -+netfs_S_##name (struct protid *user) \ -+{ \ -+ error_t err; \ -+ \ -+ if (!user) \ -+ return EOPNOTSUPP; \ -+ \ -+ pthread_mutex_lock (&user->po->np->lock); \ -+ err = name (netfs_node_netnode (user->po->np)->file); \ -+ pthread_mutex_unlock (&user->po->np->lock); \ -+ return err; \ -+} -+ -+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 -+netfs_S_io_prenotify (struct protid *user, -+ vm_offset_t start, vm_offset_t stop) -+{ -+ error_t err; -+ -+ if (!user) -+ return EOPNOTSUPP; -+ -+ pthread_mutex_lock (&user->po->np->lock); -+ err = io_prenotify (netfs_node_netnode (user->po->np)->file, start, stop); -+ pthread_mutex_unlock (&user->po->np->lock); -+ return err; -+} -+ -+error_t -+netfs_S_io_postnotify (struct protid *user, -+ vm_offset_t start, vm_offset_t stop) -+{ -+ error_t err; -+ -+ if (!user) -+ return EOPNOTSUPP; -+ -+ pthread_mutex_lock (&user->po->np->lock); -+ err = io_postnotify (netfs_node_netnode (user->po->np)->file, start, stop); -+ pthread_mutex_unlock (&user->po->np->lock); -+ return err; -+} -+ -+/* This overrides the library's definition. */ -+int -+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); -+ assert_perror (err); /* XXX should synthesize reply */ -+ ports_port_deref (cred); -+ /* We already sent the message, so the server loop shouldn't do it again. */ -+ ((mig_reply_header_t *) outp)->RetCode = MIG_NO_REPLY; -+ 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/gpg.c b/trans/gpg.c -new file mode 100644 -index 0000000..c974473 ---- /dev/null -+++ b/trans/gpg.c -@@ -0,0 +1,679 @@ -+/* 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, "--always-trust"); // XXX -+ 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; -+ mach_port_t file; -+ -+ if (!diruser) -+ return EOPNOTSUPP; -+ -+ dnp = diruser->po->np; -+ -+ mach_port_t 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) -+ { -+ /* xxx deref stuff */ -+ 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; -+ -+ redo_hash_lookup: -+ 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); -+ //err = dir_mkfile (dir, flags, mode, &chroot_node (np)->shadow_file); -+ if (err) -+ return err; -+ } -+ -+ if (retry_name[0] == 0) -+ { -+ file_t sig; -+ char *signame; -+ asprintf (&signame, "%s.sig", filename); -+ 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; -+ error (0, 0, "%s: encrypting %d", __FUNCTION__, n->shadow_file); -+ 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 = "XXX." -+"\vXXX."; -+ -+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; // XXX -+ chroot_node (netfs_root_node)->shadow_file = MACH_PORT_NULL; -+ -+ netfs_server_loop (); /* Never returns. */ -+ -+ /*NOTREACHED*/ -+ return 0; -+} -diff --git a/trans/identity.c b/trans/identity.c -new file mode 100644 -index 0000000..260dd3e ---- /dev/null -+++ b/trans/identity.c -@@ -0,0 +1,113 @@ -+/* identity -- an 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; -+} -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 100755 -index 0000000..4e4128b ---- /dev/null -+++ b/utils/gpg-env.sh -@@ -0,0 +1,121 @@ -+#!/bin/sh -+# Execute a command in an environment which encrypts, decrypts, and -+# verifies files on demand. -+# -+# Copyright (C) 2002, 2013, 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: -+ [$0] encrypt for RECIPIENT [RECIPIENT...] -- [OPTION...] [COMMAND...] -+ [$0] encrypt with password [OPTION...] [COMMAND...] -+ [$0] decrypt [OPTION...] [COMMAND...] -+ [$0] decrypt with password [OPTION...] [COMMAND...] -+ [$0] verify [OPTION...] [COMMAND...]" -+DOC="Execute COMMAND in an environment where files are automatically -+encrypted, decrypted and verified." -+ -+help() -+{ -+ [ "$1" ] && echo "$1 -+" -+ echo "$USAGE" -+ 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 - |