summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorMichael I. Bushnell <mib@gnu.org>1994-07-21 19:03:46 +0000
committerMichael I. Bushnell <mib@gnu.org>1994-07-21 19:03:46 +0000
commit1cde8b2682dc438ef0aafa37c4a8ca9863b1e33f (patch)
tree5eeba5d1f8aa7e8e559805e67b2203f4a1a0fd98 /utils
parent3e0f07c7d45f5e6ba6cff0215656db105a5e20af (diff)
Initial revision
Diffstat (limited to 'utils')
-rw-r--r--utils/old-ps.c152
-rw-r--r--utils/shd.c366
-rw-r--r--utils/su.c461
3 files changed, 979 insertions, 0 deletions
diff --git a/utils/old-ps.c b/utils/old-ps.c
new file mode 100644
index 00000000..0ff927e3
--- /dev/null
+++ b/utils/old-ps.c
@@ -0,0 +1,152 @@
+/*
+ Copyright (C) 1994 Free Software Foundation
+
+ 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 <hurd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+/* return a string describing the amount of memory SIZE represents. */
+char *
+mem_str (vm_size_t size)
+{
+ char *ret = malloc (10);
+ char *spec=" KMG";
+ int dec = 0;
+
+ while (size > 1000)
+ {
+ dec = size % 1000;
+ size /= 1000;
+ spec++;
+ }
+
+ if (size >= 100)
+ sprintf (ret, "%d%c", size, *spec);
+ else if (size >= 10)
+ sprintf (ret, "%d.%d%c", size, dec / 100, *spec);
+ else
+ sprintf (ret, "%d.%d%c", size, dec / 10, *spec);
+
+ return ret;
+}
+
+/* Return a string representing time T. */
+char *
+time_str (time_value_t *t)
+{
+ char *ret = malloc (20);
+ int time;
+
+ time = t->seconds * 1000000 + t->microseconds;
+ sprintf (ret, "%.2f", (double)time / 1000000.0 );
+ return ret;
+}
+
+/* Print a string describing the args of proc PID */
+void
+print_args_str (process_t proc, pid_t pid)
+{
+ char *args;
+ u_int nargs = 0;
+ char *p;
+ error_t err;
+
+ err = proc_getprocargs (proc, pid, &args, &nargs);
+ if (err)
+ return;
+ p = args;
+ while (p - args < nargs)
+ {
+ printf ("%s ", p);
+ p = strchr (p, '\0') + 1;
+ }
+ vm_deallocate (mach_task_self (), (vm_address_t) args, nargs);
+}
+
+
+/* Very simple PS */
+int
+main ()
+{
+ process_t proc;
+ pid_t pids[20];
+ pid_t *pp = pids;
+ u_int npids = 20;
+ int ind;
+ struct thread_basic_info tbi;
+ struct thread_sched_info tsi;
+
+#if 0
+ stdout = mach_open_devstream (getdport (1), "w");
+#endif
+
+ puts ("PID\tUSER\tPP\tPG\tSS\tVMem\tRSS\tPRI\t%CPU\tUser\tSystem\tArgs");
+ proc = getproc ();
+ proc_getallpids (proc, &pp, &npids);
+ for (ind = 0; ind < npids; ind++)
+ {
+ int procinfobuf[0];
+ struct procinfo *pi = (struct procinfo *) procinfobuf;
+ u_int pisize = 0;
+ int i;
+
+ proc_getprocinfo (proc, pp[ind], (int **)&pi, &pisize);
+
+ if (pi->state & PI_NOPARENT)
+ continue;
+
+ bzero (&tbi, sizeof tbi);
+ bzero (&tsi, sizeof tsi);
+ for (i = 0; i < pi->nthreads; i++)
+ {
+ tsi.base_priority += pi->threadinfos[i].pis_si.base_priority;
+ tsi.cur_priority += pi->threadinfos[i].pis_si.cur_priority;
+ tbi.cpu_usage += pi->threadinfos[i].pis_bi.cpu_usage;
+ tbi.user_time.seconds += pi->threadinfos[i].pis_bi.user_time.seconds;
+ tbi.user_time.microseconds
+ += pi->threadinfos[i].pis_bi.user_time.microseconds;
+ tbi.system_time.seconds
+ += pi->threadinfos[i].pis_bi.system_time.seconds;
+ tbi.system_time.microseconds
+ += pi->threadinfos[i].pis_bi.system_time.microseconds;
+ }
+ tsi.base_priority /= pi->nthreads;
+ tsi.cur_priority /= pi->nthreads;
+ tbi.user_time.seconds += tbi.user_time.microseconds / 1000000;
+ tbi.user_time.microseconds %= 1000000;
+ tbi.system_time.seconds += tbi.system_time.microseconds / 1000000;
+ tbi.system_time.microseconds %= 1000000;
+ printf ("%d\t%d\t%d\t%d\t%d\t%s\t%s\t%d/%d\t%d\t%s\t%s\t",
+ pp[ind],
+ (pi->state & PI_NOTOWNED) ? -1 : pi->owner,
+ pi->ppid,
+ pi->pgrp,
+ pi->session,
+ mem_str (pi->taskinfo.virtual_size),
+ mem_str (pi->taskinfo.resident_size),
+ tsi.base_priority,
+ tsi.cur_priority,
+ tbi.cpu_usage,
+ time_str (&tbi.user_time),
+ time_str (&tbi.system_time));
+ print_args_str (proc, pp[ind]);
+ putchar ('\n');
+ }
+ return 0;
+}
diff --git a/utils/shd.c b/utils/shd.c
new file mode 100644
index 00000000..c85ff07d
--- /dev/null
+++ b/utils/shd.c
@@ -0,0 +1,366 @@
+/*
+ Copyright (C) 1994 Free Software Foundation
+
+ 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 <sys/types.h>
+#include <hurd.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <device/device.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <hurd/exec.h>
+
+mach_port_t proc;
+int pause_startup = 0;
+
+void
+reap (pid_t waitfor)
+{
+ pid_t pid;
+ int status;
+
+ while (1)
+ {
+ pid = waitpid (WAIT_ANY, &status, WUNTRACED | (waitfor ? 0 : WNOHANG));
+
+ if (pid == -1)
+ {
+ if (errno != ESRCH && errno != EWOULDBLOCK)
+ perror ("waitpid");
+ return;
+ }
+ else if (WIFEXITED (status))
+ printf ("PID %d exit status %d\n",
+ pid, WEXITSTATUS (status));
+ else if (WIFSIGNALED (status))
+ printf ("PID %d %s\n",
+ pid, strsignal (WTERMSIG (status)));
+ else if (WIFSTOPPED (status))
+ printf ("PID %d stopped: %s\n",
+ pid, strsignal (WSTOPSIG (status)));
+ else
+ printf ("PID %d bizarre status %#x\n", pid, status);
+
+ if (pid == waitfor)
+ waitfor = 0;
+ }
+}
+
+pid_t
+run (char **argv, int fd0, int fd1)
+{
+ file_t file;
+ char *program;
+
+ if (strchr (argv[0], '/') != NULL)
+ program = argv[0];
+ else
+ {
+ size_t len = strlen (argv[0]);
+ const char bin[] = "/bin/";
+ program = alloca (sizeof bin + len);
+ memcpy (program, bin, sizeof bin - 1);
+ memcpy (&program[sizeof bin - 1], argv[0], len + 1);
+ }
+
+ file = path_lookup (program, O_EXEC, 0);
+ if (file == MACH_PORT_NULL)
+ {
+ perror (program);
+ return -1;
+ }
+ else
+ {
+ task_t task;
+ pid_t pid;
+
+ if (errno = task_create (mach_task_self (), 0, &task))
+ {
+ perror ("task_create");
+ pid = -1;
+ }
+ else
+ {
+ int save0, save1;
+
+ inline int movefd (int from, int to, int *save)
+ {
+ if (from == to)
+ return 0;
+ *save = dup (to);
+ if (*save < 0)
+ {
+ perror ("dup");
+ return -1;
+ }
+ if (dup2 (from, to) != to)
+ {
+ perror ("dup2");
+ return -1;
+ }
+ close (from);
+ return 0;
+ }
+ inline int restorefd (int from, int to, int *save)
+ {
+ if (from == to)
+ return 0;
+ if (dup2 (*save, to) != to)
+ {
+ perror ("dup2");
+ return -1;
+ }
+ close (*save);
+ return 0;
+ }
+
+ pid = task2pid (task);
+ if (pid == -1)
+ perror ("task2pid"), pid = 0;
+ if (errno = proc_child (proc, task))
+ perror ("proc_child");
+ if (pause_startup)
+ {
+ printf ("Pausing...");
+ fflush (stdout);
+ getchar ();
+ }
+
+ if (movefd (fd0, 0, &save0) ||
+ movefd (fd1, 1, &save1))
+ return -1;
+
+ errno = _hurd_exec (task, file, argv, environ);
+
+ if (restorefd (fd0, 0, &save0) ||
+ restorefd (fd1, 1, &save1))
+ return -1;
+
+ if (errno)
+ {
+ perror ("_hurd_exec");
+ if (errno = task_terminate (task))
+ perror ("task_terminate");
+ }
+ mach_port_deallocate (mach_task_self (), task);
+
+ }
+ mach_port_deallocate (mach_task_self (), file);
+
+ return pid;
+ }
+}
+
+void
+command (int argc, char **argv)
+{
+ pid_t pid;
+ int bg;
+ int i, start;
+ int fds[2] = { 0, 1 };
+
+ if (bg = !strcmp (argv[argc - 1], "&"))
+ argv[--argc] = NULL;
+
+ start = 0;
+ for (i = 1; i < argc; ++i)
+ if (! strcmp (argv[i], "|"))
+ {
+ int fd0 = fds[0];
+ argv[i] = NULL;
+ if (pipe (fds))
+ {
+ perror ("pipe");
+ return;
+ }
+ pid = run (argv + start, fd0, fds[1]);
+ if (pid < 0)
+ return;
+ start = i + 1;
+ }
+
+ pid = run (argv + start, fds[0], 1);
+
+ if (fds[0] != 0)
+ close (fds[0]);
+ if (fds[1] != 1)
+ close (fds[1]);
+
+ reap (bg ? 0 : pid);
+}
+
+
+int
+main ()
+{
+ char *linebuf = NULL;
+ size_t linebufsize = 0;
+
+ proc = getproc ();
+ assert (proc);
+
+#if 0
+ {
+ error_t err;
+ mach_port_t outp;
+ mach_port_t hostp, masterd;
+ err = proc_getprivports (proc, &hostp, &masterd);
+ assert (!err);
+
+ err = device_open (masterd, D_WRITE|D_READ, "console", &outp);
+ assert (!err);
+
+ stdin = mach_open_devstream (outp, "r");
+ stdout = stderr = mach_open_devstream (outp, "w+");
+ }
+#endif
+
+ /* Kludge to give boot a port to the auth server. */
+ exec_init (getdport (0), getauth (),
+ MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND);
+
+ atexit ((void (*) (void)) &sync);
+
+ while (1)
+ {
+ ssize_t n;
+
+ sync ();
+ printf ("# ");
+ fflush (stdout);
+ n = getline (&linebuf, &linebufsize, stdin);
+ if (n == -1)
+ {
+ if (feof (stdin))
+ return 0;
+ perror ("getline");
+ continue;
+ }
+
+ if (linebuf[n - 1] == '\n')
+ linebuf[--n] = '\0';
+
+ if (n > 0)
+ {
+ char *argv[(n + 1) / 2 + 1];
+ int argc;
+ char *line, *p;
+
+ line = linebuf;
+ argc = 0;
+ while ((p = strsep (&line, " \t\n\f\v")) != NULL)
+ argv[argc++] = p;
+ argv[argc] = NULL;
+
+ if (!strcmp (argv[0], "exit"))
+ {
+ reap (0);
+ exit (0);
+ }
+ else if (!strcmp (argv[0], "pause"))
+ pause_startup = 1;
+ else if (!strcmp (argv[0], "nopause"))
+ pause_startup = 0;
+ else if (!strcmp (argv[0], "kill"))
+ {
+ if (argc == 1)
+ fprintf (stderr, "Usage: kill PID ...\n");
+ else
+ {
+ int pid;
+ task_t task;
+ int i;
+ for (i = 1; i < argc; i++)
+ {
+ pid = atoi (argv[i]);
+ printf ("Killing pid %d\n", pid);
+ if (pid)
+ {
+ proc_pid2task (proc, pid, &task);
+ task_terminate (task);
+ mach_port_deallocate (mach_task_self (), task);
+ }
+ }
+ }
+ }
+ else if (!strcmp (argv[0], "cd"))
+ {
+ if (argc != 2)
+ fprintf (stderr, "Usage: cd DIRECTORY\n");
+ else if (chdir (argv[1]))
+ perror ("chdir");
+ }
+ else if (!strcmp (argv[0], "exec"))
+ {
+ if (argc == 1)
+ fprintf (stderr, "Usage: exec PROGRAM [ARGS...]\n");
+ else
+ {
+ char *program;
+ if (strchr (argv[1], '/') != NULL)
+ program = argv[1];
+ else
+ {
+ size_t len = strlen (argv[1]);
+ const char bin[] = "/bin/";
+ program = alloca (sizeof bin + len);
+ memcpy (program, bin, sizeof bin - 1);
+ memcpy (&program[sizeof bin - 1], argv[1], len + 1);
+ }
+ if (execv (program, &argv[1]) == 0)
+ fprintf (stderr, "execv (%s) returned 0!\n", program);
+ else
+ perror ("execv");
+ }
+ }
+ else if (!strcmp (argv[0], "setenv"))
+ {
+ if (argc != 3)
+ fprintf (stderr, "Usage: setenv VAR VALUE\n");
+ else if (setenv (argv[1], argv[2], 1))
+ perror ("setenv");
+ }
+ else if (!strcmp (argv[0], "fork"))
+ {
+ pid_t pid = fork ();
+ switch (pid)
+ {
+ case -1:
+ perror ("fork");
+ break;
+ case 0:
+ printf ("I am the child, PID %d.\n", (int) getpid ());
+ break;
+ default:
+ printf ("I am the parent of child with PID %d.\n", pid);
+ reap (argc == 2 && !strcmp (argv[1], "&") ? 0 : pid);
+ break;
+ }
+ }
+ else
+ command (argc, argv);
+ }
+ reap (0);
+ fflush (stderr);
+ }
+}
+
+
diff --git a/utils/su.c b/utils/su.c
new file mode 100644
index 00000000..3bff70ad
--- /dev/null
+++ b/utils/su.c
@@ -0,0 +1,461 @@
+/* `su' for GNU Hurd.
+ Copyright (C) 1994 Free Software Foundation
+ Written by Roland McGrath.
+
+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 the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Unlike Unix su, this program does not spawn a subshell. Instead, it
+ adds or removes (with the -r flag) auth rights to all the processes in
+ the current login. Note that the addition and removal of rights to a
+ particular process is voluntary; the process doesn't get them unless
+ it's listening for the right rpc (which the C library normally does),
+ and it doesn't have to release any of the rights it has when requested
+ (though the C library does this automatically in most programs).
+
+ The -r flag allows you to easily be authorized or not authorized for any
+ number of users (uids and gid sets). This program is not intelligent,
+ however. The -r flag always removes whatever gids the specified user
+ has. If some other user you have obtained authorization for has some of
+ the same gids, it will remove them. The C library could be intelligent
+ enough to look up the groups of all the uids it has, and make sure it
+ has at least those. */
+
+#include <stdlib.h>
+#include <hurd.h>
+#include <pwd.h>
+#include <grp.h>
+#include <termios.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <getopt.h>
+#include <hurd/msg.h>
+#include <assert.h>
+
+process_t proc; /* Our proc server port. */
+
+/* Command line flags. */
+int remove_ids = 0; /* -r: Remove ids instead of adding them. */
+
+const struct option longopts[] =
+ {
+ { "remove", 0, 0, 'r' },
+ { "uid", 0, 0, 'u' },
+ { "gid", 0, 0, 'g' },
+ { "loginuser", 0, 0, 'l' },
+ { "pid", 0, 0, 'p' },
+ { "pgrp", 0, 0, 'G' },
+ { "loginid", 0, 0, 'i' },
+ { 0, }
+ };
+
+/* These functions return a malloc'd array of ids that can be passed to
+ make_auth_handle or used in del_auth messages. They check authorization
+ and return NULL on failure. */
+unsigned int *get_uid (const char *user); /* From a named user or UID. */
+unsigned int *get_gid (const char *user); /* From a named group or GID. */
+unsigned int *get_user (const char *user); /* All ids for a named user. */
+
+int apply_ids (unsigned int *ids, pid_t, int);
+int apply_ids_to_pids (unsigned int *ids, unsigned int, pid_t *, int);
+int apply_ids_to_pgrp (unsigned int *ids, pid_t);
+int apply_ids_to_loginid (unsigned int *ids, int);
+
+int check_password (const char *name, const char *password);
+
+
+int
+main (int argc, char **argv)
+{
+ int c;
+ int status;
+ enum { user, group, loginuser, loginid, pid, pgrp } mode = loginuser;
+ unsigned int *idsets[argc];
+ unsigned int ididx = 0, loginidx = 0, pididx = 0, pgrpidx = 0;
+ int loginids[argc];
+ pid_t pids[argc], pgrps[argc];
+ unsigned int i, j;
+
+ proc = getproc (); /* Used often. */
+
+ while ((c = getopt_long (argc, argv, "--rgulpiG", longopts, NULL)) != EOF)
+ switch (c)
+ {
+ case 'r':
+ remove_ids = 1;
+ break;
+
+ case 'u':
+ mode = user;
+ break;
+ case 'g':
+ mode = group;
+ break;
+ case 'l':
+ mode = loginuser;
+ break;
+ case 'p':
+ mode = pid;
+ break;
+ case 'i':
+ mode = loginid;
+ break;
+ case 'G':
+ mode = pgrp;
+ break;
+
+ case '\0': /* Non-option argument. */
+ switch (mode)
+ {
+ case user:
+ idsets[ididx++] = get_uid (optarg);
+ break;
+ case group:
+ idsets[ididx++] = get_gid (optarg);
+ break;
+ case loginuser:
+ idsets[ididx++] = get_user (optarg);
+ break;
+
+ case pid:
+ pids[pididx++] = atoi (optarg);
+ break;
+ case loginid:
+ loginids[loginidx++] = atoi (optarg);
+ break;
+ case pgrp:
+ pgrps[pgrpidx++] = atoi (optarg);
+ break;
+ }
+ break;
+
+ case '?':
+ default:
+ fprintf (stderr, "Usage: %s [-r|--remove]\n\
+ [-u|--uid UID...] [-g|--gid GID...] [-l|--loginuser USER...]\n\
+ [-p|--pid PID...] [-i|--loginid ID...] [-G|--pgrp PGRP...]\n",
+ program_invocation_short_name);
+ exit (1);
+ }
+
+ if (ididx == 0)
+ /* No ids specified; default is "su root". */
+ idsets[ididx++] = get_user ("root");
+
+ if (pididx == 0 && loginidx == 0 && pgrpidx == 0)
+ /* No processes specified; default is current login collection. */
+ if (errno = proc_getloginid (proc, getpid (), &loginids[loginidx++]))
+ {
+ perror ("proc_getloginid");
+ return 1;
+ }
+
+ status = 0;
+
+ for (j = 0; j < ididx; ++j)
+ status |= apply_ids_to_pids (idsets[j], pididx, pids, 0);
+
+ for (i = 0; i < loginidx; ++i)
+ {
+ for (j = 0; j < loginidx; ++j)
+ status |= apply_ids_to_loginid (idsets[j], loginids[i]);
+ }
+
+ for (i = 0; i < pgrpidx; ++i)
+ {
+ for (j = 0; j < pgrpidx; ++j)
+ status |= apply_ids_to_loginid (idsets[j], pgrps[i]);
+ }
+
+
+ return status;
+}
+
+/* Turn USER into a list of ids, giving USER's primary uid and gid from the
+ passwd file and all the groups that USER appears in in the group file. */
+
+unsigned int *
+get_user (const char *user)
+{
+ struct passwd *p;
+ unsigned int ngids, *ids;
+
+ p = getpwnam (user);
+ if (p == NULL)
+ {
+ fprintf (stderr, "%s: User `%s' not found\n",
+ program_invocation_short_name, user);
+ return NULL;
+ }
+
+ if (! check_password (user, p->pw_passwd))
+ return NULL;
+
+ /* We don't need to change our own gids, but it doesn't really hurt,
+ and initgroups does all the work for us. */
+ if (initgroups (user, p->pw_gid) < 0)
+ {
+ perror ("initgroups");
+ return NULL;
+ }
+ ngids = getgroups (0, NULL);
+ if ((int) ngids < 0)
+ {
+ getgroups_lost:
+ perror ("getgroups");
+ return NULL;
+ }
+ assert (sizeof (*ids) == sizeof (gid_t));
+ ids = malloc ((3 + ngids) * sizeof (*ids));
+ ids[0] = 1;
+ ids[1] = p->pw_uid;
+ ids[2] = getgroups (ngids, &ids[3]);
+ if ((int) ids[2] < 0)
+ goto getgroups_lost;
+
+ return ids;
+}
+
+/* Return an id list containing just the uid of USER. */
+
+unsigned int *
+get_uid (const char *user)
+{
+ struct passwd *p;
+ unsigned int *ids;
+ uid_t uid;
+ char *uend;
+
+ uid = strtoul (user, &uend, 10);
+ if (uend && *uend == '\0')
+ {
+ if (remove_ids || getuid () == 0)
+ /* No need to verify. */
+ p = NULL;
+ else
+ {
+ p = getpwuid (uid);
+ if (p == NULL)
+ {
+ fprintf (stderr, "%s: UID %u not found\n",
+ program_invocation_short_name, uid);
+ return NULL;
+ }
+ }
+ }
+ else
+ {
+ p = getpwnam (user);
+ if (p == NULL)
+ {
+ fprintf (stderr, "%s: User `%s' not found\n",
+ program_invocation_short_name, user);
+ return NULL;
+ }
+ }
+
+ if (p != NULL && ! check_password (user, p->pw_passwd))
+ return NULL;
+
+ ids = malloc (3 * sizeof (*ids));
+ ids[0] = 1;
+ ids[1] = p->pw_uid;
+ ids[2] = 0;
+
+ return ids;
+}
+
+/* Return an id list containing just the gid of GROUP. */
+
+unsigned int *
+get_gid (const char *group)
+{
+ struct group *g;
+ unsigned int *ids;
+ gid_t gid;
+ char *gend;
+
+ gid = strtoul (group, &gend, 10);
+ if (gend && *gend == '\0')
+ {
+ if (remove_ids || getuid () == 0)
+ /* No need to verify. */
+ g = NULL;
+ else
+ {
+ g = getgrgid (gid);
+ if (g == NULL)
+ {
+ fprintf (stderr, "%s: GID %u not found\n",
+ program_invocation_short_name, gid);
+ return NULL;
+ }
+ }
+ }
+ else
+ {
+ g = getgrnam (group);
+ if (g == NULL)
+ {
+ fprintf (stderr, "%s: Group `%s' not found\n",
+ program_invocation_short_name, group);
+ return NULL;
+ }
+ }
+
+ if (g != NULL && ! check_password (group, g->gr_passwd))
+ return NULL;
+
+ ids = malloc (3 * sizeof (*ids));
+ ids[0] = 0;
+ ids[1] = 1;
+ ids[2] = g->gr_gid;
+
+ return ids;
+}
+
+/* Add or delete (under -r) the ids indicated by IDS to/from PID. If
+ IGNORE_BAD_PID is nonzero, return success if PID does not exist.
+ Returns zero if successful, nonzero on error (after printing message). */
+
+int
+apply_ids (unsigned int *ids, pid_t pid, int ignore_bad_pid)
+{
+ error_t err;
+ auth_t auth;
+
+ if (! ids)
+ return 0;
+
+ if (! remove_ids)
+ if (errno = auth_makeauth (getauth (), NULL, MACH_MSG_TYPE_COPY_SEND, 0,
+ &ids[1], ids[0], NULL, 0,
+ &ids[1 + ids[0] + 1], ids[1 + ids[0]], NULL, 0,
+ &auth))
+ {
+ perror ("auth_makeauth");
+ return 1;
+ }
+
+ err = HURD_MSGPORT_RPC (proc_getmsgport (proc, pid, &msgport),
+ proc_pid2task (proc, pid, &refport),
+ remove_ids ?
+ del_auth (msgport, refport,
+ &ids[1], ids[0],
+ &ids[1 + ids[0] + 1],
+ ids[1 + ids[0]]) :
+ add_auth (msgport, auth));
+ if (err &&
+ (!ignore_bad_pid || (err != ESRCH && err != MIG_SERVER_DIED)))
+ {
+ fprintf (stderr, "%s: error in %s_auth from PID %d: %s\n",
+ program_invocation_short_name,
+ remove_ids ? "del" : "add", pid, strerror (err));
+ return 1;
+ }
+ else
+ return 0;
+}
+
+int
+apply_ids_to_pids (unsigned int *ids, unsigned int npids, pid_t pids[],
+ int ignore_bad_pid)
+{
+ int status = 0;
+ unsigned int i;
+
+ for (i = 0; i < npids; ++i)
+ status |= apply_ids (ids, pids[i], ignore_bad_pid);
+
+ return status;
+}
+
+int
+apply_ids_to_loginid (unsigned int *ids, int loginid)
+{
+ unsigned int npids = 20;
+ pid_t pidbuf[20], *pids = pidbuf;
+ int status;
+ error_t err;
+
+ if (err = proc_getloginpids (proc, loginid, &pids, &npids))
+ {
+ fprintf (stderr, "%s: proc_getloginpids failed for loginid %d: %s\n",
+ program_invocation_short_name, loginid, strerror (err));
+ return 1;
+ }
+
+ status = apply_ids_to_pids (ids, npids, pids, 1);
+
+ if (pids != pidbuf)
+ vm_deallocate (mach_task_self (),
+ (vm_address_t) pids, npids * sizeof (pid_t));
+
+ return status;
+}
+
+int
+apply_ids_to_pgrp (unsigned int *ids, pid_t pgrp)
+{
+ unsigned int npids = 20;
+ pid_t pidbuf[20], *pids = pidbuf;
+ int status;
+ error_t err;
+
+ if (err = proc_getpgrppids (proc, pgrp, &pids, &npids))
+ {
+ fprintf (stderr, "%s: proc_getpgrppids failed for pgrp %d: %s\n",
+ program_invocation_short_name, pgrp, strerror (err));
+ return 1;
+ }
+
+ status = apply_ids_to_pids (ids, npids, pids, 1);
+
+ if (pids != pidbuf)
+ vm_deallocate (mach_task_self (),
+ (vm_address_t) pids, npids * sizeof (pid_t));
+
+ return status;
+}
+
+/* Return 1 if the user gives the correct password matching the encrypted
+ string PASSWORD, 0 if not. Return 1 without asking for a password if
+ run by uid 0 or if PASSWORD is an empty password, and always under -r.
+ Always prints a message before returning 0. */
+
+int
+check_password (const char *name, const char *password)
+{
+ extern char *crypt (const char salt[2], const char *string);
+ char *unencrypted, *encrypted;
+ static char *prompt = NULL;
+
+ if (remove_ids || getuid () == 0 || password == NULL || password[0] == '\0')
+ return 1;
+
+ asprintf (&prompt, "%s's Password:", name);
+ unencrypted = getpass (prompt);
+ encrypted = crypt (unencrypted, password);
+ memset (unencrypted, 0, strlen (unencrypted)); /* Paranoia may destroya. */
+
+ if (!strcmp (encrypted, password))
+ return 1;
+
+ fprintf (stderr, "%s: Access denied for `%s'\n",
+ program_invocation_short_name, name);
+ return 0;
+}