summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
Diffstat (limited to 'utils')
-rw-r--r--utils/frobauth-mod.c177
-rw-r--r--utils/frobauth.c282
-rw-r--r--utils/frobauth.h68
-rw-r--r--utils/nonsugid.c60
-rw-r--r--utils/pids.c232
-rw-r--r--utils/pids.h47
-rw-r--r--utils/rmauth.c121
-rw-r--r--utils/setauth.c132
-rw-r--r--utils/unsu.c90
9 files changed, 1209 insertions, 0 deletions
diff --git a/utils/frobauth-mod.c b/utils/frobauth-mod.c
new file mode 100644
index 00000000..8606e783
--- /dev/null
+++ b/utils/frobauth-mod.c
@@ -0,0 +1,177 @@
+/* Modify the current authentication selected processes
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <hurd.h>
+#include <error.h>
+
+#include "frobauth.h"
+
+/* For every pid in FROBAUTH, call MODIFY to change its argument UGIDS from
+ the current authentication to what it should be; CHANGE is whatever ids
+ the user specified. If the user specifies the --verbose flags, PRINT_INFO
+ is called after successfully installing the new authentication in each
+ process, to print a message about what happened. True is returned if no
+ errors occur, although most errors do not cause termination, and error
+ messages are printed for them. */
+error_t
+frobauth_modify (struct frobauth *frobauth,
+ error_t (*modify) (struct ugids *ugids,
+ const struct ugids *change,
+ pid_t pid, void *hook),
+ void (*print_info) (const struct ugids *new,
+ const struct ugids *old,
+ const struct ugids *change,
+ pid_t pid, void *hook),
+ void *hook)
+{
+ int i;
+ int ok = 1;
+ pid_t cur_pid = getpid ();
+ process_t proc_server = getproc ();
+
+ /* Map MODIFY over all pids. */
+ for (i = 0; i < frobauth->num_pids; i++)
+ if (frobauth->pids[i] != cur_pid)
+ {
+ mach_port_t msgport;
+ pid_t pid = frobauth->pids[i];
+ error_t err = proc_getmsgport (proc_server, pid, &msgport);
+
+ if (err)
+ error (0, err, "%d: Cannot get message port", pid);
+ else
+ {
+ task_t task;
+
+ err = proc_pid2task (proc_server, pid, &task);
+ if (err)
+ error (0, err, "%d", pid);
+ else
+ {
+ auth_t old_auth;
+
+ err = msg_get_init_port (msgport, task, INIT_PORT_AUTH,
+ &old_auth);
+ if (err)
+ error (0, err, "%d: Cannot get auth port", pid);
+ else
+ {
+ struct ugids old = UGIDS_INIT;
+
+ err = ugids_merge_auth (&old, old_auth);
+
+ if (err)
+ error (0, err, "%d: Cannot get auth port ids", pid);
+ else
+ {
+ struct ugids new = UGIDS_INIT;
+
+ /* Assume all gids that can be implied by some uid are
+ only present for that reason. */
+ ugids_imply_all (&old);
+
+ err = ugids_set (&new, &old);
+
+ err = (*modify) (&new, &frobauth->ugids, pid, hook);
+ if (err)
+ error (99, err, "%d: Cannot modify ids", pid);
+ else if (! ugids_equal (&new, &old))
+ {
+ if (! frobauth->dry_run)
+ {
+ auth_t new_auth;
+ err =
+ ugids_make_auth (&new, old_auth, &new_auth);
+ if (err)
+ error (0, err,
+ "%d: Authentication failure", pid);
+ else
+ {
+ err =
+ msg_set_init_port (msgport, task,
+ INIT_PORT_AUTH,
+ new_auth,
+ MACH_MSG_TYPE_MOVE_SEND);
+ if (err)
+ error (0, err, "%d", pid);
+ else if (new.eff_uids.num == 0
+ ? old.eff_uids.num > 0
+ : (old.eff_uids.num == 0
+ || (new.eff_uids.ids[0]
+ != old.eff_uids.ids[0])))
+ /* Now change the process's owner. */
+ {
+ process_t proc;
+ err =
+ proc_pid2proc (proc_server, pid,
+ &proc);
+ if (err)
+ error (0, err,
+ "%d: Cannot get proc port",
+ pid);
+ else
+ {
+ if (new.eff_uids.num == 0)
+ err =
+ proc_setowner (proc, 0, 1);
+ else
+ err = proc_setowner
+ (proc, new.eff_uids.ids[0], 0);
+ if (err)
+ error
+ (0, err,
+ "%d: Cannot set process owner",
+ pid);
+ mach_port_deallocate
+ (mach_task_self (), proc);
+ }
+ }
+ }
+
+ }
+
+ if (frobauth->verbose && !err)
+ (*print_info) (&new, &old, &frobauth->ugids,
+ pid, hook);
+
+ }
+ else if (frobauth->verbose)
+ printf ("%d: Nothing changed\n", pid);
+
+ ugids_fini (&new);
+ }
+
+ ugids_fini (&old);
+ mach_port_deallocate (mach_task_self (), old_auth);
+ }
+ mach_port_deallocate (mach_task_self (), task);
+ }
+ mach_port_deallocate (mach_task_self (), msgport);
+ }
+
+ if (err)
+ ok = 0; /* Something didn't work. */
+ }
+
+ return ok;
+}
diff --git a/utils/frobauth.c b/utils/frobauth.c
new file mode 100644
index 00000000..ccb7c3bb
--- /dev/null
+++ b/utils/frobauth.c
@@ -0,0 +1,282 @@
+/* Common interface for auth frobbing utilities
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This file is rather a mess of intertwined argps; it shoud be redone as a
+ single level once argp can handle dynamic option frobbing. XXX */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <hurd.h>
+#include <hurd/process.h>
+
+#include "frobauth.h"
+#include "ugids.h"
+#include "pids.h"
+
+static struct argp common_argp;
+static struct argp fr_ugids_argp;
+
+static const struct argp_option common_options[] =
+{
+ {"verbose", 'v', 0, 0, "Print informational messages"},
+ {"dry-run", 'n', 0, 0, "Don't do anything, just print what would be done"},
+ { 0 }
+};
+static struct argp_child common_child_argps[] =
+{
+ { &pids_argp, 0, "Process selection:" },
+ { 0 }
+};
+
+static const char common_args_doc[] = "USER...";
+static const char common_doc[] =
+ "\vBy default, all processes in the current login collection are selected";
+
+static struct argp_child ugids_child_argps[] =
+{
+ { &ugids_argp, 0, "User/group ids:" },
+ { 0 }
+};
+
+/* An argp on top of the base frobauth argp that provides switchable
+ effective/available ids (XXX this junk should be moved into a single argp
+ [indeed, into ugids_argp] once argp can deal with the init routine
+ frobbing the argp source). */
+static const struct argp_option ea_options[] =
+{
+ {"available", 'a', 0, 0, "USER... specifies available ids"},
+ {"effective", 'e', 0, 0, "USER... specifies effective ids"},
+ { 0 }
+};
+
+static struct argp_child ea_posix_child_argps[] =
+{
+ { &common_argp },
+ { &fr_ugids_argp },
+ { 0 }
+};
+
+static struct argp_child no_ugids_child_argps[] =
+{
+ { &common_argp },
+ { 0 }
+};
+
+/* This holds state information that's only active during parsing. */
+struct frobauth_argp_state
+{
+ struct frobauth *frobauth;
+ struct pids_argp_params pids_argp_params;
+ struct ugids_argp_params ugids_argp_params;
+};
+
+static error_t
+common_parse_opt (int key, char *arg, struct argp_state *state)
+{
+ struct frobauth_argp_state *fs = state->input;
+ struct frobauth *frobauth = fs->frobauth;
+
+ switch (key)
+ {
+ case 'v':
+ frobauth->verbose = 1; break;
+ case 'n':
+ frobauth->dry_run = 1; break;
+
+ case ARGP_KEY_END:
+ if (frobauth->num_pids == 0)
+ /* No pids specified! By default, do the current login collection. */
+ {
+ pid_t lid;
+ error_t err = proc_getloginid (getproc (), getpid (), &lid);
+
+ if (err)
+ argp_failure (state, 2, err,
+ "Couldn't get current login collection");
+
+ err = add_fn_pids (&frobauth->pids, &frobauth->num_pids,
+ lid, proc_getloginpids);
+ if (err)
+ argp_failure (state, 3, err,
+ "%d: Couldn't get login collection pids", lid);
+
+ return err;
+ }
+ break;
+
+ case ARGP_KEY_INIT:
+ bzero (fs, sizeof *fs);
+ fs->frobauth = frobauth;
+ fs->pids_argp_params.pids = &frobauth->pids;
+ fs->pids_argp_params.num_pids = &frobauth->num_pids;
+ state->child_inputs[0] = &fs->pids_argp_params;
+ break;
+
+ case ARGP_KEY_SUCCESS:
+ case ARGP_KEY_ERROR:
+ free (fs);
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static error_t
+ugids_parse_opt (int key, char *arg, struct argp_state *state)
+{
+ struct frobauth_argp_state *fs = state->input;
+ struct frobauth *frobauth = fs->frobauth;
+
+ switch (key)
+ {
+ case ARGP_KEY_INIT:
+ fs->ugids_argp_params.ugids = &frobauth->ugids;
+ fs->ugids_argp_params.parse_user_args = 1;
+ fs->ugids_argp_params.default_user = frobauth->default_user;
+ fs->ugids_argp_params.require_ids = frobauth->require_ids;
+ fs->pids_argp_params.pids = &frobauth->pids;
+ fs->pids_argp_params.num_pids = &frobauth->num_pids;
+
+ state->child_inputs[0] = &fs->ugids_argp_params;
+
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static error_t
+ea_parse_opt (int key, char *arg, struct argp_state *state)
+{
+ struct frobauth_argp_state *fs = state->hook;
+
+ switch (key)
+ {
+ case 'a':
+ fs->ugids_argp_params.user_args_are_available = 1;
+ break;
+ case 'e':
+ fs->ugids_argp_params.user_args_are_effective = 1;
+ break;
+
+ case ARGP_KEY_ARG:
+ if (!fs->ugids_argp_params.user_args_are_effective
+ && !fs->ugids_argp_params.user_args_are_available)
+ /* Default to effective. */
+ fs->ugids_argp_params.user_args_are_effective = 1;
+
+ /* Let someone else parse the arg. */
+ return ARGP_ERR_UNKNOWN;
+
+ case ARGP_KEY_INIT:
+ /* Initialize inputs for child parsers. */
+ fs = state->hook = malloc (sizeof (struct frobauth_argp_state));
+ if (! fs)
+ return ENOMEM;
+
+ fs->frobauth = state->input;
+ state->child_inputs[0] = fs; /* Pass our state to the common parser. */
+ state->child_inputs[1] = fs; /* Pass our state to the common parser. */
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static error_t
+posix_parse_opt (int key, char *arg, struct argp_state *state)
+{
+ struct frobauth_argp_state *fs = state->hook;
+
+ switch (key)
+ {
+ case ARGP_KEY_INIT:
+ /* Initialize inputs for child parsers. */
+ fs = state->hook = malloc (sizeof (struct frobauth_argp_state));
+ if (! fs)
+ return ENOMEM;
+
+ fs->frobauth = state->input;
+ state->child_inputs[0] = fs; /* Pass our state to the common parser. */
+ state->child_inputs[1] = fs; /* Pass our state to the common parser. */
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static error_t
+no_ugids_parse_opt (int key, char *arg, struct argp_state *state)
+{
+ struct frobauth_argp_state *fs = state->hook;
+
+ switch (key)
+ {
+ case ARGP_KEY_INIT:
+ /* Initialize inputs for child parsers. */
+ fs = state->hook = malloc (sizeof (struct frobauth_argp_state));
+ if (! fs)
+ return ENOMEM;
+
+ fs->frobauth = state->input;
+ state->child_inputs[0] = fs; /* Pass our state to the common parser. */
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static struct argp common_argp =
+{
+ common_options, common_parse_opt, 0, common_doc, common_child_argps
+};
+static struct argp fr_ugids_argp =
+{
+ 0, ugids_parse_opt, 0, 0, ugids_child_argps
+};
+
+/* Parse frobauth args/options, where user args are added as single ids to
+ either the effective or available ids. */
+struct argp frobauth_ea_argp =
+{
+ ea_options, ea_parse_opt, 0, 0, ea_posix_child_argps
+};
+
+/* Parse frobauth args/options, where user args are added as posix user. */
+struct argp frobauth_posix_argp =
+{
+ 0, posix_parse_opt, 0, 0, ea_posix_child_argps
+};
+
+/* Parse frobauth args/options, where user args are added as posix user. */
+struct argp frobauth_no_ugids_argp =
+{
+ 0, no_ugids_parse_opt, 0, 0, no_ugids_child_argps
+};
diff --git a/utils/frobauth.h b/utils/frobauth.h
new file mode 100644
index 00000000..0423337e
--- /dev/null
+++ b/utils/frobauth.h
@@ -0,0 +1,68 @@
+/* Common interface for auth frobbing utilities
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __FROBAUTH_H__
+#define __FROBAUTH_H__
+
+#include <sys/types.h>
+#include <ugids.h>
+#include <argp.h>
+
+/* Structure describing which processes to frob, and how to frob them. */
+struct frobauth
+{
+ struct ugids ugids;
+ pid_t *pids;
+ size_t num_pids;
+ int verbose, dry_run; /* User options */
+ uid_t default_user; /* If none specified; -1 means none. */
+ int require_ids; /* If true, require some ids be specified. */
+};
+
+#define FROBAUTH_INIT { UGIDS_INIT, 0, 0, 0, 0, -1 }
+
+/* For every pid in FROBAUTH, call MODIFY to change its argument UGIDS from
+ the current authentication to what it should be; CHANGE is whatever ids
+ the user specified. If the user specifies the --verbose flags, PRINT_INFO
+ is called after successfully installing the new authentication in each
+ process, to print a message about what happened. True is returned if no
+ errors occur, although most errors do not cause termination, and error
+ messages are printed for them. */
+error_t frobauth_modify (struct frobauth *frobauth,
+ error_t (*modify) (struct ugids *ugids,
+ const struct ugids *change,
+ pid_t pid, void *hook),
+ void (*print_info) (const struct ugids *new,
+ const struct ugids *old,
+ const struct ugids *change,
+ pid_t pid, void *hook),
+ void *hook);
+
+/* Parse frobauth args/options, where user args are added as single ids to
+ either the effective or available ids. */
+extern struct argp frobauth_ea_argp;
+
+/* Parse frobauth args/options, where user args are added as posix user. */
+extern struct argp frobauth_posix_argp;
+
+/* Parse frobauth args/options, with no user specifications. */
+extern struct argp frobauth_no_ugids_argp;
+
+#endif /* __FROBAUTH_H__ */
diff --git a/utils/nonsugid.c b/utils/nonsugid.c
new file mode 100644
index 00000000..ad3a2176
--- /dev/null
+++ b/utils/nonsugid.c
@@ -0,0 +1,60 @@
+/* Get our ids, minus any setuid result
+
+ Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <errno.h>
+#include <idvec.h>
+#include <hurd.h>
+
+/* Make sure that the [UG]IDS are filled in. To make them useful for
+ su'ing, each is the avail ids with all effective ids but the first
+ appended; this gets rid of the effect of being suid, and is useful as a
+ new process's avail id list (e.g., the real id is right). */
+error_t
+get_nonsugid_ids (struct idvec *uids, struct idvec *gids)
+{
+ if (uids->num == 0 && gids->num == 0)
+ {
+ error_t err = 0;
+ static auth_t auth = MACH_PORT_NULL;
+ struct idvec *p_eff_uids = make_idvec ();
+ struct idvec *p_eff_gids = make_idvec ();
+
+ if (!p_eff_uids || !p_eff_gids)
+ err = ENOMEM;
+
+ if (auth == MACH_PORT_NULL)
+ auth = getauth ();
+
+ if (! err)
+ err = idvec_merge_auth (p_eff_uids, uids, p_eff_gids, gids, auth);
+ if (! err)
+ {
+ idvec_delete (p_eff_uids, 0); /* Counteract setuid. */
+ idvec_delete (p_eff_gids, 0);
+ err = idvec_merge (uids, p_eff_uids);
+ if (! err)
+ err = idvec_merge (gids, p_eff_gids);
+ }
+
+ return err;
+ }
+ else
+ return 0;
+}
diff --git a/utils/pids.c b/utils/pids.c
new file mode 100644
index 00000000..ea759247
--- /dev/null
+++ b/utils/pids.c
@@ -0,0 +1,232 @@
+/* Pid parsing/frobbing
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <argp.h>
+#include <hurd.h>
+#include <hurd/process.h>
+#include <mach.h>
+
+#include "parse.h"
+#include "pids.h"
+
+static process_t _proc_server = MACH_PORT_NULL;
+
+/* Return this process's proc server. */
+static inline process_t
+proc_server ()
+{
+ if (_proc_server == MACH_PORT_NULL)
+ _proc_server = getproc ();
+ return _proc_server;
+}
+
+/* Add the pids returned in vm_allocated memory by calling PIDS_FN with ID as
+ an argument to PIDS and NUM_PIDS, reallocating it in malloced memory. */
+error_t
+add_fn_pids (pid_t **pids, size_t *num_pids, unsigned id,
+ error_t (*pids_fn)(process_t proc, pid_t id,
+ pid_t **pids, unsigned *num_pids))
+{
+ size_t num_new_pids = 25;
+ pid_t _new_pids[num_new_pids], *new_pids = _new_pids;
+ error_t err = (*pids_fn)(proc_server (), id, &new_pids, &num_new_pids);
+
+ if (! err)
+ {
+ size_t new_sz = *num_pids + num_new_pids;
+ pid_t *new = realloc (*pids, new_sz * sizeof (pid_t));
+ if (new)
+ {
+ bcopy (new_pids, new + (*num_pids * sizeof (pid_t)),
+ num_new_pids * sizeof (pid_t));
+ *pids = new;
+ *num_pids = new_sz;
+ }
+ else
+ err = ENOMEM;
+ if (new_pids != _new_pids)
+ vm_deallocate (mach_task_self (), (vm_address_t)new_pids,
+ num_new_pids * sizeof (pid_t));
+ }
+
+ return err;
+}
+
+/* Add PID to PIDS and NUM_PIDS, reallocating it in malloced memory. */
+error_t
+add_pid (pid_t **pids, size_t *num_pids, pid_t pid)
+{
+ size_t new_sz = *num_pids + 1;
+ pid_t *new = realloc (*pids, new_sz * sizeof (pid_t));
+
+ if (new)
+ {
+ new[new_sz - 1] = pid;
+ *pids = new;
+ *num_pids = new_sz;
+ return 0;
+ }
+ else
+ return ENOMEM;
+}
+
+struct pids_parse_state
+{
+ struct pids_argp_params *params;
+ struct argp_state *state;
+};
+
+/* Returns our session id. */
+static pid_t
+current_sid (struct argp_state *state)
+{
+ pid_t sid = -1;
+ error_t err = proc_getsid (proc_server (), getpid (), &sid);
+ if (err)
+ argp_failure (state, 2, err, "Couldn't get current session id");
+ return sid;
+}
+
+/* Returns our login collection id. */
+static pid_t
+current_lid (struct argp_state *state)
+{
+ pid_t lid = -1;
+ error_t err = proc_getloginid (proc_server (), getpid (), &lid);
+ if (err)
+ argp_failure (state, 2, err, "Couldn't get current login collection");
+ return lid;
+}
+
+/* Add a specific process to be printed out. */
+static error_t
+parse_pid (unsigned pid, struct argp_state *state)
+{
+ struct pids_argp_params *params = state->input;
+ error_t err = add_pid (params->pids, params->num_pids, pid);
+ if (err)
+ argp_failure (state, 2, err, "%d: Cannot add process", pid);
+ return err;
+}
+
+/* Print out all process from the given session. */
+static error_t
+parse_sid (unsigned sid, struct argp_state *state)
+{
+ struct pids_argp_params *params = state->input;
+ error_t err =
+ add_fn_pids (params->pids, params->num_pids, sid, proc_getsessionpids);
+ if (err)
+ argp_failure (state, 2, err, "%d: Cannot add session", sid);
+ return err;
+}
+
+/* Print out all process from the given login collection. */
+static error_t
+parse_lid (unsigned lid, struct argp_state *state)
+{
+ struct pids_argp_params *params = state->input;
+ error_t err =
+ add_fn_pids (params->pids, params->num_pids, lid, proc_getloginpids);
+ if (err)
+ argp_failure (state, 2, err, "%d: Cannot add login collection", lid);
+ return err;
+}
+
+/* Print out all process from the given process group. */
+static error_t
+parse_pgrp (unsigned pgrp, struct argp_state *state)
+{
+ struct pids_argp_params *params = state->input;
+ error_t err =
+ add_fn_pids (params->pids, params->num_pids, pgrp, proc_getpgrppids);
+ if (err)
+ argp_failure (state, 2, err, "%d: Cannot add process group", pgrp);
+ return err;
+}
+
+#define OA OPTION_ARG_OPTIONAL
+
+/* Options for PIDS_ARGP. */
+static const struct argp_option options[] =
+{
+ {"login", 'L', "LID", OA, "Processes from the login"
+ " collection LID (which defaults that of"
+ " the current process)"},
+ {"lid", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
+ {"pid", 'p', "PID", 0, "The process PID"},
+ {"pgrp", 'P', "PGRP", 0, "Processes in process group PGRP"},
+ {"session", 'S', "SID", OA, "Processes from the session SID"
+ " (which defaults to that of the"
+ " current process)"},
+ {"sid", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
+ {0, 0}
+};
+
+/* Parse one option/arg for PIDS_ARGP. */
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ struct pids_argp_params *params = state->input;
+
+ switch (key)
+ {
+ case 'p':
+ return
+ parse_numlist (arg, parse_pid, NULL, NULL, "process id", state);
+ case 'S':
+ return
+ parse_numlist (arg, parse_sid, current_sid, NULL, "session id", state);
+ case 'L':
+ return
+ parse_numlist (arg, parse_lid, current_lid, NULL, "login collection",
+ state);
+ case 'P':
+ return
+ parse_numlist (arg, parse_pgrp, NULL, NULL, "process group", state);
+
+ case ARGP_KEY_ARG:
+ if (params->parse_pid_args)
+ return parse_numlist (arg, parse_pid, NULL, NULL, "process id", state);
+ /* Else fall through */
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+}
+
+/* Filtering of help output strings for PIDS_ARGP. */
+static char *
+help_filter (int key, const char *text, void *input)
+{
+ struct pids_argp_params *params = input;
+
+ /* Describe the optional behavior of parsing normal args as pids. */
+ if (key == ARGP_KEY_HELP_ARGS_DOC && params->parse_pid_args)
+ return strdup ("[PID...]");
+
+ return (char *)text;
+}
+
+/* A parser for selecting a set of pids. */
+struct argp pids_argp = { options, parse_opt, 0, 0, 0, help_filter };
diff --git a/utils/pids.h b/utils/pids.h
new file mode 100644
index 00000000..8b192b5a
--- /dev/null
+++ b/utils/pids.h
@@ -0,0 +1,47 @@
+/* Pid parsing/frobbing
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __PIDS_H__
+#define __PIDS_H__
+
+/* Add the pids returned in vm_allocated memory by calling PIDS_FN with ID as
+ an argument to PIDS and NUM_PIDS, reallocating it in malloced memory. */
+extern error_t add_fn_pids (pid_t **pids, size_t *num_pids, unsigned id,
+ error_t (*pids_fn)(process_t proc, pid_t id,
+ pid_t **pids, size_t *num_pids));
+
+/* Add PID to PIDS and NUM_PIDS, reallocating it in malloced memory. */
+extern error_t add_pid (pid_t **pids, size_t *num_pids, pid_t pid);
+
+/* Params to be passed as the input when parsing PIDS_ARGP. */
+struct pids_argp_params
+{
+ /* Array to be extended with parsed pids. */
+ pid_t **pids;
+ size_t *num_pids;
+
+ /* If true, parse non-option arguments as pids. */
+ int parse_pid_args;
+};
+
+/* A parser for selecting a set of pids. */
+extern struct argp pids_argp;
+
+#endif __PIDS_H__
diff --git a/utils/rmauth.c b/utils/rmauth.c
new file mode 100644
index 00000000..56d6a6a4
--- /dev/null
+++ b/utils/rmauth.c
@@ -0,0 +1,121 @@
+/* Remove authentication from selected processes
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <hurd.h>
+#include <argp.h>
+#include <error.h>
+#include <version.h>
+
+#include "frobauth.h"
+
+const char *argp_program_version = STANDARD_HURD_VERSION (rmauth);
+
+static const struct argp_option options[] =
+{
+#ifndef UNSU
+ {"save", 's', 0, 0, "Save removed effective ids as available ids"},
+#endif
+ { 0 }
+};
+
+#ifdef UNSU
+static struct argp_child child_argps[] = {{ &frobauth_posix_argp }, { 0 }};
+#else
+static struct argp_child child_argps[] = {{ &frobauth_ea_argp }, { 0 }};
+#endif
+
+static char doc[] =
+ "Remove user/group ids from the authentication of selected processes";
+
+void
+main (int argc, char *argv[])
+{
+ int save = 0; /* save effective ids */
+ struct frobauth frobauth = FROBAUTH_INIT;
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ case 's': save = 1; break;
+ case ARGP_KEY_INIT:
+ state->child_inputs[0] = state->input; break;
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+ /* Modify UGIDS, to be what PID's new authentication should be, UGIDS is
+ what the user specified. */
+ error_t modify (struct ugids *ugids, const struct ugids *remove,
+ pid_t pid, void *hook)
+ {
+ error_t err = 0;
+ struct ugids saved = UGIDS_INIT;
+
+ if (save)
+ ugids_set (&saved, ugids);
+
+ err = ugids_subtract (ugids, remove);
+
+ if (save)
+ {
+ ugids_subtract (&saved, ugids);
+ ugids_save (&saved);
+ ugids_merge (ugids, &saved);
+ }
+
+ return err;
+ }
+ void print_info (const struct ugids *new,
+ const struct ugids *old,
+ const struct ugids *removed,
+ pid_t pid, void *hook)
+ {
+ char *delta_rep;
+ struct ugids delta = UGIDS_INIT;
+
+ ugids_set (&delta, old);
+ ugids_subtract (&delta, new);
+
+ delta_rep = ugids_rep (&delta, 1, 1, 0, 0, 0);
+ printf ("%d: Removed %s\n", pid, delta_rep);
+
+ free (delta_rep);
+ ugids_fini (&delta);
+ }
+ struct argp argp = { options, parse_opt, 0, doc, child_argps };
+
+#ifdef UNSU
+ frobauth.default_user = 0;
+#endif
+ frobauth.require_ids = 1;
+
+ /* Parse our command line. This shouldn't ever return an error. */
+ argp_parse (&argp, argc, argv, 0, 0, &frobauth);
+
+ if (frobauth_modify (&frobauth, modify, print_info, 0))
+ exit (0);
+ else
+ exit (1);
+}
diff --git a/utils/setauth.c b/utils/setauth.c
new file mode 100644
index 00000000..92b6816a
--- /dev/null
+++ b/utils/setauth.c
@@ -0,0 +1,132 @@
+/* Change the authentication of selected processes
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <hurd.h>
+#include <argp.h>
+#include <error.h>
+#include <version.h>
+
+#include "frobauth.h"
+
+const char *argp_program_version = STANDARD_HURD_VERSION (setauth);
+
+#define OPT_NO_SAVE 1
+
+static const struct argp_option options[] =
+{
+#ifdef SU
+ {"no-save", OPT_NO_SAVE, 0, 0, "Don't save removed effective ids as available ids"},
+#else
+ {"save", 's', 0, 0, "Save removed effective ids as available ids"},
+#endif
+ {"keep", 'k', 0, 0, "Keep old ids in addition to the new ones"},
+ { 0 }
+};
+
+static struct argp_child child_argps[] = {{ &frobauth_posix_argp }, { 0 }};
+
+static char doc[] =
+ "Change the authentication of selected processes";
+
+extern error_t
+get_nonsugid_ids (struct idvec *uids, struct idvec *gids);
+
+void
+main (int argc, char *argv[])
+{
+ error_t err;
+ int save = 0, keep = 0;
+ struct idvec have_uids = IDVEC_INIT, have_gids = IDVEC_INIT;
+ struct frobauth frobauth = FROBAUTH_INIT;
+
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ case 's': save = 1; break;
+ case 'k': keep = 1; break;
+ case OPT_NO_SAVE: save = 0; break;
+ case ARGP_KEY_INIT:
+ state->child_inputs[0] = state->input; break;
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+ /* Modify UGIDS, to be what PID's new authentication should be, UGIDS is
+ what the user specified. */
+ error_t modify (struct ugids *ugids, const struct ugids *new,
+ pid_t pid, void *hook)
+ {
+ struct ugids old = UGIDS_INIT;
+ ugids_set (&old, ugids);
+
+ ugids_set (ugids, new);
+
+ if (keep)
+ ugids_merge (ugids, &old);
+ if (save)
+ {
+ ugids_save (&old);
+ ugids_merge (ugids, &old);
+ }
+
+ return 0;
+ }
+ void print_info (const struct ugids *new,
+ const struct ugids *old,
+ const struct ugids *user,
+ pid_t pid, void *hook)
+ {
+ char *new_rep = ugids_rep (new, 1, 1, 0, 0, 0);
+ printf ("%d: Changed auth to %s\n", pid, new_rep);
+ free (new_rep);
+ }
+ struct argp argp = { options, parse_opt, 0, doc, child_argps };
+
+#ifdef SU
+ frobauth.default_user = 0;
+ save = 1; /* Default to saving ids */
+#endif
+
+ /* Parse our command line. This shouldn't ever return an error. */
+ argp_parse (&argp, argc, argv, 0, 0, &frobauth);
+
+ /* See what the invoking user is authorized to do. */
+ err = get_nonsugid_ids (&have_uids, &have_gids);
+ if (err)
+ error (52, err, "Cannot get invoking authentication");
+
+ /* Check passwords. */
+ err = ugids_verify (&frobauth.ugids, &have_uids, &have_gids, 0);
+ if (err == EINVAL)
+ error (15, 0, "Invalid password");
+ else if (err)
+ error (16, err, "Cannot verify authentication");
+
+ if (frobauth_modify (&frobauth, modify, print_info, 0))
+ exit (0);
+ else
+ exit (1);
+}
diff --git a/utils/unsu.c b/utils/unsu.c
new file mode 100644
index 00000000..4672821b
--- /dev/null
+++ b/utils/unsu.c
@@ -0,0 +1,90 @@
+/* Attempt to undo a previous su
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <hurd.h>
+#include <argp.h>
+#include <error.h>
+#include <version.h>
+
+#include "frobauth.h"
+#include "pids.h"
+
+const char *argp_program_version = STANDARD_HURD_VERSION (rmauth);
+
+static struct argp_child child_argps[] = {{ &frobauth_no_ugids_argp }, { 0 }};
+
+static char doc[] =
+ "Attempt to undo a previous su"
+ "\vThis command is convenient, but will only correctly undo a limited"
+ " subset of possible su commands. It works by simply deleting all"
+ " current effective ids and the first two available ids, and then"
+ " making the first remaining available id the current effective id.";
+
+void
+main (int argc, char *argv[])
+{
+ struct frobauth frobauth = FROBAUTH_INIT;
+
+ /* Modify UGIDS, to be what PID's new authentication should be, NOISE is
+ ignored. */
+ error_t modify (struct ugids *ugids, const struct ugids *noise,
+ pid_t pid, void *hook)
+ {
+ error_t err = 0;
+
+ idvec_clear (&ugids->eff_uids);
+ idvec_clear (&ugids->eff_gids);
+ idvec_clear (&ugids->imp_eff_gids);
+
+ idvec_delete (&ugids->avail_uids, 0);
+ idvec_delete (&ugids->avail_uids, 0);
+
+ idvec_delete (&ugids->avail_gids, 0);
+ idvec_delete (&ugids->avail_gids, 0);
+ idvec_keep (&ugids->imp_avail_gids, &ugids->avail_gids);
+
+ if (ugids->avail_uids.num > 0)
+ err = ugids_set_posix_user (ugids, ugids->avail_uids.ids[0]);
+
+ return err;
+ }
+ void print_info (const struct ugids *new,
+ const struct ugids *old,
+ const struct ugids *removed,
+ pid_t pid, void *hook)
+ {
+ char *new_rep = ugids_rep (new, 1, 1, 0, 0, 0);
+ printf ("%d: Changed auth to %s\n", pid, new_rep);
+ free (new_rep);
+ }
+ struct argp argp = { 0, 0, 0, doc, child_argps };
+
+ /* Parse our command line. This shouldn't ever return an error. */
+ argp_parse (&argp, argc, argv, 0, 0, &frobauth);
+
+ if (frobauth_modify (&frobauth, modify, print_info, 0))
+ exit (0);
+ else
+ exit (1);
+}