summaryrefslogtreecommitdiff
path: root/libshouldbeinlibc
diff options
context:
space:
mode:
Diffstat (limited to 'libshouldbeinlibc')
-rw-r--r--libshouldbeinlibc/Makefile37
-rw-r--r--libshouldbeinlibc/cacheq.c143
-rw-r--r--libshouldbeinlibc/cacheq.h87
-rw-r--r--libshouldbeinlibc/canon-host.c57
-rw-r--r--libshouldbeinlibc/exec-reauth.c108
-rw-r--r--libshouldbeinlibc/fsysops.c96
-rw-r--r--libshouldbeinlibc/idvec-auth.c85
-rw-r--r--libshouldbeinlibc/idvec-funcs.c2
-rw-r--r--libshouldbeinlibc/idvec-impgids.c115
-rw-r--r--libshouldbeinlibc/idvec-rep.c164
-rw-r--r--libshouldbeinlibc/idvec-verify.c362
-rw-r--r--libshouldbeinlibc/idvec.c339
-rw-r--r--libshouldbeinlibc/idvec.h236
-rw-r--r--libshouldbeinlibc/lcm.c46
-rw-r--r--libshouldbeinlibc/localhost.c75
-rw-r--r--libshouldbeinlibc/maptime-funcs.c5
-rw-r--r--libshouldbeinlibc/maptime.c84
-rw-r--r--libshouldbeinlibc/maptime.h61
-rw-r--r--libshouldbeinlibc/nullauth.c45
-rw-r--r--libshouldbeinlibc/nullauth.h31
-rw-r--r--libshouldbeinlibc/portinfo.c158
-rw-r--r--libshouldbeinlibc/portinfo.h58
-rw-r--r--libshouldbeinlibc/portxlate.c179
-rw-r--r--libshouldbeinlibc/portxlate.h67
-rw-r--r--libshouldbeinlibc/shared-dom.c54
-rw-r--r--libshouldbeinlibc/termsize.c54
-rw-r--r--libshouldbeinlibc/timefmt.c359
-rw-r--r--libshouldbeinlibc/timefmt.h58
-rw-r--r--libshouldbeinlibc/ugids-argp.c174
-rw-r--r--libshouldbeinlibc/ugids-auth.c53
-rw-r--r--libshouldbeinlibc/ugids-imply.c36
-rw-r--r--libshouldbeinlibc/ugids-merge.c110
-rw-r--r--libshouldbeinlibc/ugids-posix.c95
-rw-r--r--libshouldbeinlibc/ugids-rep.c118
-rw-r--r--libshouldbeinlibc/ugids-subtract.c130
-rw-r--r--libshouldbeinlibc/ugids-verify-auth.c185
-rw-r--r--libshouldbeinlibc/ugids-verify.c65
-rw-r--r--libshouldbeinlibc/ugids-xinl.c23
-rw-r--r--libshouldbeinlibc/ugids.c98
-rw-r--r--libshouldbeinlibc/ugids.h231
-rw-r--r--libshouldbeinlibc/wire.c186
-rw-r--r--libshouldbeinlibc/wire.h26
-rw-r--r--libshouldbeinlibc/xportinfo.c69
43 files changed, 4764 insertions, 0 deletions
diff --git a/libshouldbeinlibc/Makefile b/libshouldbeinlibc/Makefile
new file mode 100644
index 00000000..14a7939d
--- /dev/null
+++ b/libshouldbeinlibc/Makefile
@@ -0,0 +1,37 @@
+# Makefile for libshouldbeinlibc
+#
+# Copyright (C) 1995,96,97,98,99,2002,2012 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+dir := libshouldbeinlibc
+makemode := library
+
+libname = libshouldbeinlibc
+SRCS = termsize.c timefmt.c exec-reauth.c maptime-funcs.c \
+ canon-host.c maptime.c shared-dom.c localhost.c wire.c portinfo.c \
+ xportinfo.c portxlate.c lcm.c cacheq.c fsysops.c \
+ idvec.c idvec-auth.c idvec-funcs.c \
+ idvec-impgids.c idvec-verify.c idvec-rep.c \
+ ugids.c ugids-argp.c ugids-rep.c ugids-verify.c ugids-subtract.c \
+ ugids-auth.c ugids-xinl.c ugids-merge.c ugids-imply.c ugids-posix.c \
+ ugids-verify-auth.c nullauth.c
+installhdrs = idvec.h timefmt.h maptime.h \
+ wire.h portinfo.h portxlate.h cacheq.h ugids.h nullauth.h
+installhdrsubdir = .
+
+OBJS = $(SRCS:.c=.o)
+
+include ../Makeconf
diff --git a/libshouldbeinlibc/cacheq.c b/libshouldbeinlibc/cacheq.c
new file mode 100644
index 00000000..c1be59c0
--- /dev/null
+++ b/libshouldbeinlibc/cacheq.c
@@ -0,0 +1,143 @@
+/* Helper functions for maintaining a fixed-size lru-ordered queue
+
+ Copyright (C) 1996, 1998 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 <string.h>
+#include <stdlib.h>
+
+#include "cacheq.h"
+
+/* Move ENTRY to the most-recently-used end of CACHEQ. */
+void
+cacheq_make_mru (struct cacheq *cq, void *entry)
+{
+ struct cacheq_hdr *h = entry;
+
+ if (h != cq->mru)
+ {
+ /* First remove it. We known H->prev isn't 0 because H wasn't
+ previously == MRU. */
+ ((struct cacheq_hdr *)h->prev)->next = h->next;
+ if (h->next)
+ ((struct cacheq_hdr *)h->next)->prev = h->prev;
+ else
+ cq->lru = h->prev;
+
+ /* Now make it MRU. */
+ h->next = cq->mru;
+ h->prev = 0;
+ ((struct cacheq_hdr *)cq->mru)->prev = h;
+ cq->mru = h;
+ }
+}
+
+/* Move ENTRY to the least-recently-used end of CACHEQ. */
+void
+cacheq_make_lru (struct cacheq *cq, void *entry)
+{
+ struct cacheq_hdr *h = entry;
+
+ if (h != cq->lru)
+ {
+ /* First remove it. We known H->next isn't 0 because H wasn't
+ previously == LRU. */
+ ((struct cacheq_hdr *)h->next)->prev = h->prev;
+ if (h->prev)
+ ((struct cacheq_hdr *)h->prev)->next = h->next;
+ else
+ cq->mru = h->next;
+
+ /* Now make it LRU. */
+ h->prev = cq->lru;
+ h->next = 0;
+ ((struct cacheq_hdr *)cq->lru)->next = h;
+ cq->lru = h;
+ }
+}
+
+/* Change CQ's size to be LENGTH entries. */
+error_t
+cacheq_set_length (struct cacheq *cq, int length)
+{
+ if (length != cq->length)
+ {
+ size_t esz = cq->entry_size;
+ void *new_entries = malloc (esz * length);
+ /* Source entries. */
+ struct cacheq_hdr *fh = cq->mru;
+ /* Destination entries (and limit). */
+ struct cacheq_hdr *th = new_entries;
+ struct cacheq_hdr *end = new_entries + esz * (length - 1);
+ struct cacheq_hdr *prev_th = 0;
+
+ if (! new_entries)
+ return ENOMEM;
+
+ while (fh || th)
+ {
+ struct cacheq_hdr *next_th =
+ (!th || th >= end) ? 0 : (void *)th + esz;
+
+ if (fh && th)
+ bcopy (fh, th, esz); /* Copy the bits in a moved entry. */
+ else if (th)
+ bzero (th, esz); /* Zero the bits in a new entry. */
+
+ if (th)
+ /* Fixup headers. */
+ {
+ th->prev = prev_th;
+ th->next = next_th;
+ }
+
+ /* Call user hooks as appropriate. */
+ if (fh && th)
+ {
+ if (cq->move_entry)
+ (*cq->move_entry) (fh, th);
+ }
+ else if (th)
+ {
+ if (cq->init_entry)
+ (*cq->init_entry) (th);
+ }
+ else
+ {
+ if (cq->finalize_entry)
+ (*cq->finalize_entry) (fh);
+ }
+
+ if (fh)
+ fh = fh->next;
+ if (th)
+ {
+ prev_th = th;
+ th = next_th;
+ }
+ }
+
+ free (cq->entries);
+ cq->entries = new_entries;
+ cq->mru = new_entries;
+ cq->lru = prev_th;
+ cq->length = length;
+ }
+
+ return 0;
+}
diff --git a/libshouldbeinlibc/cacheq.h b/libshouldbeinlibc/cacheq.h
new file mode 100644
index 00000000..a221a7a7
--- /dev/null
+++ b/libshouldbeinlibc/cacheq.h
@@ -0,0 +1,87 @@
+/* Helper functions for maintaining a fixed-size lru-ordered queue
+
+ Copyright (C) 1996 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 __CACHEQ_H__
+#define __CACHEQ_H__
+
+#include <stddef.h>
+#include <errno.h>
+
+/* This header occurs at the start of every cacheq entry. */
+struct cacheq_hdr
+{
+ /* Next and prev entries in the cache, linked in LRU order. These are of
+ type `void *' so that it's conveient to iterate through the list using a
+ variable pointing to a structure that contains the header, by using
+ something like `VAR = VAR->hdr.next'. */
+ void *next, *prev;
+};
+
+/* A cacheq. Note that this structure is laid out to allow convenient use as
+ static initialized data. */
+struct cacheq
+{
+ /* The size of each entry, including its cacheq_hdr. */
+ size_t entry_size;
+
+ /* If non-0, then when making new entries (for instance, when the cacheq is
+ initialized, or when its size is increased), this function is called on
+ each new entry (with it's header already initialized). If this function
+ isn't defined, then each entry is simply zeroed. */
+ void (*init_entry) (void *entry);
+
+ /* When an entry is moved from one place in memory to another (for
+ instance, changing the size of the cache, new storage is used), this is
+ called for each entry, with FROM and TO the old and new locations of the
+ entry (and TO contains a bitwise copy of FROM). This is often useful
+ when the entry points to something that contains a backpointer to it. */
+ void (*move_entry) (void *from, void *to);
+
+ /* When entries are removed for some reason (for instance, when reducing
+ the size of the cacheq), this function is called on each. */
+ void (*finalize_entry) (void *entry);
+
+ /* The number of entries in the cache. This number is fixed. */
+ int length;
+
+ /* A buffer holding malloc'd memory for all the entries -- NUM_ENTRIES
+ entries of size ENTRY_SIZE. */
+ void *entries;
+
+ /* The least, and most, recently used entries in the cache. These point to
+ either end of a linked list composed of all the elements of the cache.
+ This list will always be the same length -- if an element is `removed',
+ its entry is simply marked inactive, and moved to the LRU end of the list
+ so it will be reused first. These pointers are of type `void *' so they
+ can be conveniently used by client code (see comment in struct
+ cacheq_hdr). */
+ void *lru, *mru;
+};
+
+/* Move ENTRY to the most-recently-used end of CACHEQ. */
+void cacheq_make_mru (struct cacheq *cq, void *entry);
+
+/* Move ENTRY to the least-recently-used end of CACHEQ. */
+void cacheq_make_lru (struct cacheq *cq, void *entry);
+
+/* Change CQ's size to be LENGTH entries. */
+error_t cacheq_set_length (struct cacheq *cq, int length);
+
+#endif /* __CACHEQ_H__ */
diff --git a/libshouldbeinlibc/canon-host.c b/libshouldbeinlibc/canon-host.c
new file mode 100644
index 00000000..41068d30
--- /dev/null
+++ b/libshouldbeinlibc/canon-host.c
@@ -0,0 +1,57 @@
+/* Host name canonicalization
+
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ [This file is from sh-utils/lib; maybe something can be done to share them.]
+
+ 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 <string.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+/* Returns the canonical hostname associated with HOST (allocated in a static
+ buffer), or 0 if it can't be determined. */
+char *
+canon_host (char *host)
+{
+ struct hostent *he = gethostbyname (host);
+
+ if (he)
+ {
+ char *addr = 0;
+
+ /* Try and get an ascii version of the numeric host address. */
+ switch (he->h_addrtype)
+ {
+ case AF_INET:
+ addr = inet_ntoa (*(struct in_addr *)he->h_addr);
+ break;
+ }
+
+ if (addr && strcmp (he->h_name, addr) == 0)
+ /* gethostbyname() cheated! Lookup the host name via the address
+ this time to get the actual host name. */
+ he = gethostbyaddr (he->h_addr, he->h_length, he->h_addrtype);
+
+ if (he)
+ return he->h_name;
+ }
+
+ return 0;
+}
diff --git a/libshouldbeinlibc/exec-reauth.c b/libshouldbeinlibc/exec-reauth.c
new file mode 100644
index 00000000..263b1408
--- /dev/null
+++ b/libshouldbeinlibc/exec-reauth.c
@@ -0,0 +1,108 @@
+/* Re-authentication in preparation for an exec
+
+ Copyright (C) 1995, 96, 98, 2000 Free Software Foundation, Inc.
+
+ Stolen by Miles Bader <miles@gnu.ai.mit.edu>, but really
+ written by Michael I. Bushnell p/BSG <mib@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 <mach.h>
+#include <hurd/auth.h>
+#include <hurd/io.h>
+#include <hurd/process.h>
+
+/* Re-authenticates the ports in PORTS and FDS appropriately (replacing
+ PORTS[INIT_PORT_AUTH] with AUTH) for a following exec using the auth port
+ AUTH. Each replaced port has a reference consumed; if an error is
+ returned, then PORTS and FDS may contain a mixture of old and new ports,
+ however AUTH will only be placed in PORTS upon success. If SECURE is
+ true, then it is assumed the exec will use EXEC_SECURE, and certain ports
+ may be replaced by MACH_PORT_NULL, with the expectation that exec will
+ fill these in itself; if all ports should be re-authenticated, use 0 for
+ this argument, regardless of whether EXEC_SECURE will be used. If
+ MUST_REAUTH is true, then any failure to re-authenticate a port will
+ result in the function return the error, otherwise, such failures are
+ silently ignored. */
+error_t
+exec_reauth (auth_t auth, int secure, int must_reauth,
+ mach_port_t *ports, unsigned num_ports,
+ mach_port_t *fds, unsigned num_fds)
+{
+ unsigned int i;
+ error_t err = 0;
+
+ error_t reauth (mach_port_t *port, int isproc)
+ {
+ if (*port != MACH_PORT_NULL)
+ {
+ mach_port_t newport;
+ mach_port_t ref = mach_reply_port ();
+ error_t err =
+ (isproc ? proc_reauthenticate : io_reauthenticate)
+ (*port, ref, MACH_MSG_TYPE_MAKE_SEND);
+
+ /* MAKE_SEND is safe here because we destroy REF ourselves. */
+
+ if (!err)
+ err = auth_user_authenticate (auth, ref, MACH_MSG_TYPE_MAKE_SEND,
+ &newport);
+ mach_port_mod_refs (mach_task_self (), ref, MACH_PORT_RIGHT_RECEIVE, -1);
+ if (err)
+ {
+ if (must_reauth)
+ return err;
+ /* Nothing Happens. */
+ }
+ else
+ {
+ if (isproc)
+ mach_port_deallocate (mach_task_self (), newport);
+ else
+ {
+ mach_port_deallocate (mach_task_self (), *port);
+ *port = newport;
+ }
+ }
+ }
+ return 0;
+ }
+
+ /* Re-authenticate all the ports we are handing to the user
+ with this new port, and install the new auth port in ports. */
+ for (i = 0; i < num_fds && !err; ++i)
+ err = reauth (&fds[i], 0);
+
+ if (!err)
+ {
+ if (secure)
+ /* Not worth doing; the exec server will just do it again. */
+ ports[INIT_PORT_CRDIR] = MACH_PORT_NULL;
+ else
+ err = reauth (&ports[INIT_PORT_CRDIR], 0);
+ }
+ if (!err)
+ err = reauth (&ports[INIT_PORT_PROC], 1);
+ if (!err)
+ err = reauth (&ports[INIT_PORT_CWDIR], 0);
+
+ if (!err)
+ {
+ mach_port_deallocate (mach_task_self (), ports[INIT_PORT_AUTH]);
+ ports[INIT_PORT_AUTH] = auth;
+ }
+
+ return 0;
+}
diff --git a/libshouldbeinlibc/fsysops.c b/libshouldbeinlibc/fsysops.c
new file mode 100644
index 00000000..dbcae672
--- /dev/null
+++ b/libshouldbeinlibc/fsysops.c
@@ -0,0 +1,96 @@
+/* Some handy utility routines for fsys control ports
+
+ Copyright (C) 1996, 1999 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#include <errno.h>
+#include <argz.h>
+#include <mach.h>
+#include <sys/mman.h>
+#include <hurd/fsys.h>
+#include <string.h>
+
+/* Make FSYS readonly or writable. */
+error_t
+fsys_set_readonly (fsys_t fsys, int readonly)
+{
+ error_t err;
+ char *opts = readonly ? "--readonly" : "--writable";
+ size_t opts_len = strlen (opts) + 1;
+ err = fsys_set_options (fsys, opts, opts_len, 0);
+ if (err == EINVAL)
+ err = EOPNOTSUPP;
+ return err;
+}
+
+/* Ask FSYS whether it's readonly, returning the result in READONLY; we don't
+ really have a good method for this, other than asking for it's options and
+ looking for `--readonly' or `--writable'. If we see neither, return
+ EOPNOTSUPP. */
+error_t
+fsys_get_readonly (fsys_t fsys, int *readonly)
+{
+ error_t err;
+ char _opts[200], *opts = _opts;
+ size_t opts_len = sizeof opts;
+
+ err = fsys_get_options (fsys, &opts, &opts_len);
+ if (! err)
+ {
+ char *opt;
+ int ok = 0;
+
+ for (opt = opts
+ ; !ok && opt && opt < opts + opts_len
+ ; opt = argz_next (opts, opts_len, opt))
+ if (strcasecmp (opt, "--readonly") == 0)
+ {
+ *readonly = 1;
+ ok = 1;
+ }
+ else if (strcasecmp (opt, "--writable") == 0)
+ {
+ *readonly = 0;
+ ok = 1;
+ }
+
+ if (! ok)
+ err = EOPNOTSUPP; /* So far as we know... */
+
+ if (opts != _opts)
+ /* Free out-of-line memory returned by fsys_get_options. */
+ munmap (opts, opts_len);
+ }
+
+ return err;
+}
+
+/* Tell FSYS to remount itself. */
+error_t
+fsys_update (fsys_t fsys, int readonly)
+{
+ error_t err;
+ char *opts = "--update";
+ size_t opts_len = strlen (opts) + 1;
+ err = fsys_set_options (fsys, opts, opts_len, 0);
+ if (err == EINVAL)
+ err = EOPNOTSUPP;
+ return err;
+}
diff --git a/libshouldbeinlibc/idvec-auth.c b/libshouldbeinlibc/idvec-auth.c
new file mode 100644
index 00000000..1858bd6a
--- /dev/null
+++ b/libshouldbeinlibc/idvec-auth.c
@@ -0,0 +1,85 @@
+/* Idvec functions that interact with an auth server
+
+ Copyright (C) 1995, 1998, 1999, 2001, 2002, 2008
+ Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.org>
+
+ 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 <mach.h>
+#include <sys/mman.h>
+#include <hurd/auth.h>
+#include <errno.h>
+
+#include "idvec.h"
+
+/* Add to all of EFF_UIDS, AVAIL_UIDS, EFF_GIDS, AVAIL_GIDS (as if with
+ idvec_merge_ids()) the ids associated with the auth port AUTH. Any of
+ these parameters may be NULL if that information isn't desired. */
+error_t
+idvec_merge_auth (struct idvec *eff_uids, struct idvec *avail_uids,
+ struct idvec *eff_gids, struct idvec *avail_gids,
+ auth_t auth)
+{
+ error_t err;
+ uid_t eff_uid_buf[10], avail_uid_buf[20];
+ uid_t *_eff_uids = eff_uid_buf, *_avail_uids = avail_uid_buf;
+ size_t num_eff_uids = 10, num_avail_uids = 20;
+ uid_t eff_gid_buf[10], avail_gid_buf[20];
+ uid_t *_eff_gids = eff_gid_buf, *_avail_gids = avail_gid_buf;
+ size_t num_eff_gids = 10, num_avail_gids = 20;
+
+ err = auth_getids (auth,
+ &_eff_uids, &num_eff_uids, &_avail_uids, &num_avail_uids,
+ &_eff_gids, &num_eff_gids, &_avail_gids, &num_avail_gids);
+ if (err)
+ return err;
+
+ if (eff_uids)
+ err = idvec_grow (eff_uids, num_eff_uids);
+ if (avail_uids && !err)
+ err = idvec_grow (avail_uids, num_avail_uids);
+ if (eff_gids && !err)
+ err = idvec_grow (eff_gids, num_eff_gids);
+ if (avail_gids && !err)
+ err = idvec_grow (avail_gids, num_avail_gids);
+
+ if (!err)
+ /* Now that we've ensured there's enough space, none of these should
+ return an error. */
+ {
+ if (eff_uids)
+ idvec_merge_ids (eff_uids, _eff_uids, num_eff_uids);
+ if (avail_uids)
+ idvec_merge_ids (avail_uids, _avail_uids, num_avail_uids);
+ if (eff_gids)
+ idvec_merge_ids (eff_gids, _eff_gids, num_eff_gids);
+ if (avail_gids)
+ idvec_merge_ids (avail_gids, _avail_gids, num_avail_gids);
+ }
+
+ /* Deallocate any out-of-line memory we got back. */
+ if (_eff_uids != eff_uid_buf)
+ munmap ((caddr_t) _eff_uids, num_eff_uids * sizeof (uid_t));
+ if (_avail_uids != avail_uid_buf)
+ munmap ((caddr_t) _avail_uids, num_avail_uids * sizeof (uid_t));
+ if (_eff_gids != eff_gid_buf)
+ munmap ((caddr_t) _eff_gids, num_eff_gids * sizeof (gid_t));
+ if (_avail_gids != avail_gid_buf)
+ munmap ((caddr_t) _avail_gids, num_avail_gids * sizeof (gid_t));
+
+ return err;
+}
diff --git a/libshouldbeinlibc/idvec-funcs.c b/libshouldbeinlibc/idvec-funcs.c
new file mode 100644
index 00000000..3bb0318d
--- /dev/null
+++ b/libshouldbeinlibc/idvec-funcs.c
@@ -0,0 +1,2 @@
+#define IDVEC_DEFINE_EI
+#include "idvec.h"
diff --git a/libshouldbeinlibc/idvec-impgids.c b/libshouldbeinlibc/idvec-impgids.c
new file mode 100644
index 00000000..d89f4873
--- /dev/null
+++ b/libshouldbeinlibc/idvec-impgids.c
@@ -0,0 +1,115 @@
+/* Add gids implied by a user
+
+ Copyright (C) 1997, 2001, 2014 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 <errno.h>
+#include <idvec.h>
+#include <pwd.h>
+#include <grp.h>
+
+#define NUM_STATIC_GIDS 100 /* Initial size of static gid array. */
+
+/* The set of gids implied by a uid. */
+struct uid_implies
+{
+ uid_t uid; /* this uid... */
+ struct idvec *implies; /* implies these gids. */
+ struct uid_implies *next;
+};
+
+/* Cache of previously calculated results for add_implied_gids. */
+static struct uid_implies *uid_implies_cache = 0;
+
+/* Add to IMPLIED_GIDS those group ids implied by the user UID. */
+static error_t
+_merge_implied_gids (struct idvec *implied_gids, uid_t uid)
+{
+ struct uid_implies *ui;
+
+ for (ui = uid_implies_cache; ui; ui = ui->next)
+ if (ui->uid == uid)
+ return idvec_merge (implied_gids, ui->implies);
+
+ {
+ error_t err = 0;
+ struct passwd *pw = getpwuid (uid);
+
+ if (! pw)
+ err = EINVAL;
+ else
+ {
+ struct idvec *cache = make_idvec ();
+ gid_t _gids[NUM_STATIC_GIDS], *gids = _gids;
+ int maxgids = NUM_STATIC_GIDS;
+ int ngids = getgrouplist (pw->pw_name, pw->pw_gid, gids, &maxgids);
+
+ if (ngids == -1)
+ {
+ gids = malloc (maxgids * sizeof (gid_t));
+ if (! gids)
+ err = ENOMEM;
+ else
+ ngids = getgrouplist (pw->pw_name, pw->pw_gid, gids, &maxgids);
+ }
+
+ if (! cache)
+ err = ENOMEM;
+
+ if (! err)
+ {
+ err = idvec_merge_ids (cache, gids, ngids);
+ if (gids != _gids)
+ free (gids);
+ }
+
+ if (! err)
+ {
+ idvec_merge (implied_gids, cache);
+ ui = malloc (sizeof (struct uid_implies));
+ if (ui)
+ {
+ ui->uid = uid;
+ ui->implies = cache;
+ ui->next = uid_implies_cache;
+ uid_implies_cache = ui;
+ }
+ else
+ idvec_free (cache);
+ }
+ }
+
+ return err;
+ }
+}
+
+/* Add to GIDS those group ids implied by the users in UIDS. */
+error_t
+idvec_merge_implied_gids (struct idvec *gids, const struct idvec *uids)
+{
+ unsigned int i;
+ error_t err = 0;
+ for (i = 0; i < uids->num; i++)
+ {
+ error_t this_err = _merge_implied_gids (gids, uids->ids[i]);
+ if (this_err && !err)
+ err = this_err;
+ }
+ return err;
+}
diff --git a/libshouldbeinlibc/idvec-rep.c b/libshouldbeinlibc/idvec-rep.c
new file mode 100644
index 00000000..16408a4d
--- /dev/null
+++ b/libshouldbeinlibc/idvec-rep.c
@@ -0,0 +1,164 @@
+/* idvec string representation
+
+ Copyright (C) 1996, 1997, 1998 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 <string.h>
+#include <unistd.h>
+#include <idvec.h>
+#include <grp.h>
+#include <pwd.h>
+
+/* Return a string representation of the ids in IDVEC, each id separated by
+ the string SEP (default ","). SHOW_VALUES and SHOW_NAMES reflect how each
+ id is printed (if SHOW_NAMES is true values are used where names aren't
+ available); if both are true, the `VALUE(NAME)' format is used.
+ ID_NAME_FN is used to map each id to a name; it should return a malloced
+ string, which will be freed here. The empty string is returned for an
+ empty list, and 0 for an allocation error. */
+char *
+idvec_rep (const struct idvec *idvec, int show_values, int show_names,
+ char *(*id_name_fn) (uid_t id), const char *sep)
+{
+ size_t sep_len;
+ char *rep = 0;
+ size_t rep_len = 0, rep_sz = 0;
+
+ int ensure_room (size_t amount)
+ {
+ size_t end = rep_len + amount;
+ if (end > rep_sz)
+ {
+ size_t new_sz = rep_sz + end;
+ char *new_rep = realloc (rep, new_sz);
+ if (new_rep)
+ {
+ rep = new_rep;
+ rep_sz = new_sz;
+ }
+ else
+ return 0;
+ }
+ return 1;
+ }
+ int add_id (uid_t val, char *name)
+ {
+ if (!name || show_values)
+ {
+ if (! ensure_room (10))
+ return 0;
+ rep_len += snprintf (rep + rep_len, 10, "%d", val);
+ }
+ if (name)
+ {
+ size_t nlen = strlen (name) + 3;
+ if (! ensure_room (nlen))
+ {
+ free (name);
+ return 0;
+ }
+ rep_len +=
+ snprintf (rep + rep_len, nlen, show_values ? "(%s)" : "%s", name);
+ free (name);
+ }
+ return 1;
+ }
+
+ if (! sep)
+ sep = ",";
+ sep_len = strlen (sep);
+
+ if (idvec->num > 0)
+ {
+ unsigned int i;
+
+ for (i = 0; i < idvec->num; i++)
+ {
+ char *name = 0;
+ uid_t val = idvec->ids[i];
+
+ if (i > 0)
+ {
+ if (ensure_room (sep_len))
+ {
+ strcpy (rep + rep_len, sep);
+ rep_len += sep_len;
+ }
+ else
+ break;
+ }
+
+ if (show_names || !show_values)
+ name = (*id_name_fn) (val);
+ if (! add_id (val, name))
+ break;
+ }
+
+ if (i < idvec->num)
+ {
+ free (rep);
+ return 0;
+ }
+
+ return rep;
+ }
+
+ return strdup ("");
+}
+
+/* Return a malloced string with the name of the user UID. */
+static char *
+lookup_uid (uid_t uid)
+{
+ char buf[1024];
+ struct passwd _pw, *pw;
+ if (getpwuid_r (uid, &_pw, buf, sizeof buf, &pw) == 0)
+ return strdup (pw->pw_name);
+ else
+ return 0;
+}
+
+/* Return a malloced string with the name of the group GID. */
+static char *
+lookup_gid (gid_t gid)
+{
+ char buf[1024];
+ struct group _gr, *gr;
+ if (getgrgid_r (gid, &_gr, buf, sizeof buf, &gr) == 0)
+ return strdup (gr->gr_name);
+ else
+ return 0;
+}
+
+/* Like idvec_rep, mapping ids to user names. */
+char *
+idvec_uids_rep (const struct idvec *idvec, int show_values, int show_names,
+ const char *sep)
+{
+ return idvec_rep (idvec, show_values, show_names, lookup_uid, sep);
+}
+
+/* Like idvec_rep, mapping ids to group names. */
+char *
+idvec_gids_rep (const struct idvec *idvec, int show_values, int show_names,
+ const char *sep)
+{
+ return idvec_rep (idvec, show_values, show_names, lookup_gid, sep);
+}
diff --git a/libshouldbeinlibc/idvec-verify.c b/libshouldbeinlibc/idvec-verify.c
new file mode 100644
index 00000000..4d9b6dbe
--- /dev/null
+++ b/libshouldbeinlibc/idvec-verify.c
@@ -0,0 +1,362 @@
+/* Verify user passwords
+
+ Copyright (C) 1996, 1997, 1998, 1999, 2002, 2008
+ Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+
+ 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 <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <idvec.h>
+#include <grp.h>
+#include <pwd.h>
+#include <shadow.h>
+#include <crypt.h>
+
+#define SHADOW_PASSWORD_STRING "x" /* pw_passwd contents for shadow passwd */
+
+#pragma weak crypt
+
+static error_t verify_id (); /* FWD */
+
+/* Get a password from the user, returning it in malloced storage. */
+static char *
+get_passwd (const char *prompt,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook)
+{
+ char *st = getpass (prompt);
+ if (st)
+ st = strdup (st);
+ return st;
+}
+
+/* Verify PASSWORD using /etc/passwd (and maybe /etc/shadow). */
+static error_t
+verify_passwd (const char *password,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook)
+{
+ const char *encrypted;
+ int wheel_uid = (intptr_t)hook;
+ const char *sys_encrypted;
+
+ if (! pwd_or_grp)
+ /* No password db entry for ID; if ID is root, the system is probably
+ really fucked up, so grant it (heh). */
+ return (id == 0 ? 0 : EACCES);
+
+ /* The encrypted password in the passwd db. */
+ sys_encrypted =
+ (is_group
+ ? ((struct passwd *)pwd_or_grp)->pw_passwd
+ : ((struct group *)pwd_or_grp)->gr_passwd);
+
+ if (sys_encrypted[0] == '\0')
+ return 0; /* No password. */
+
+ if (crypt)
+ /* Encrypt the password entered by the user (SYS_ENCRYPTED is the salt). */
+ encrypted = crypt (password, sys_encrypted);
+ else
+ /* No crypt on this system! Use plain-text passwords. */
+ encrypted = password;
+
+ if (! encrypted)
+ /* Crypt failed. */
+ return errno;
+
+ /* See whether the user's password matches the system one. */
+ if (strcmp (encrypted, sys_encrypted) == 0)
+ /* Password check succeeded. */
+ return 0;
+ else if (id == 0 && !is_group && wheel_uid)
+ /* Special hack: a user attempting to gain root access can use
+ their own password (instead of root's) if they're in group 0. */
+ {
+ struct passwd _pw, *pw;
+ char lookup_buf[1024];
+ char sp_lookup_buf[1024];
+
+ const char *check_shadow (struct passwd *pw)
+ {
+ if (strcmp (pw->pw_passwd, SHADOW_PASSWORD_STRING) == 0)
+ {
+ /* When encrypted password is "x", try shadow passwords. */
+ struct spwd _sp, *sp;
+ if (getspnam_r (pw->pw_name, &_sp, sp_lookup_buf,
+ sizeof sp_lookup_buf, &sp) == 0)
+ return sp->sp_pwdp;
+ }
+ return pw->pw_passwd;
+ }
+
+ if (getpwuid_r (wheel_uid, &_pw, lookup_buf, sizeof lookup_buf, &pw))
+ return errno ?: EINVAL;
+
+ sys_encrypted = check_shadow (pw);
+
+ encrypted = crypt (password, sys_encrypted);
+ if (! encrypted)
+ /* Crypt failed. */
+ return errno;
+
+ if (strcmp (encrypted, sys_encrypted) == 0)
+ /* *this* password is correct! */
+ return 0;
+ }
+
+ return EACCES;
+}
+
+/* Make sure the user has the right to the ids in UIDS and GIDS, given that
+ we know he already has HAVE_UIDS and HAVE_GIDS, asking for passwords (with
+ GETPASS_FN) where necessary; any of the arguments may be 0, which is
+ treated the same as if they were empty. 0 is returned if access should be
+ allowed, otherwise EINVAL if an incorrect password was entered, or an
+ error relating to resource failure. Any uid/gid < 0 will be guaranteed to
+ fail regardless of what the user types. GETPASS_FN should ask for a
+ password from the user, and return it in malloced storage; it defaults to
+ using the standard libc function getpass. If VERIFY_FN is 0, then the
+ users password will be encrypted with crypt and compared with the
+ password/group entry's encrypted password, otherwise, VERIFY_FN will be
+ called to check the entered password's validity; it should return 0 if the
+ given password is correct, or an error code. The common arguments to
+ GETPASS_FN and VERIFY_FN are: ID, the user/group id; IS_GROUP, true if its
+ a group, or false if a user; PWD_OR_GRP, a pointer to either the passwd or
+ group entry for ID, and HOOK, containing the appropriate hook passed into
+ idvec_verify. */
+error_t
+idvec_verify (const struct idvec *uids, const struct idvec *gids,
+ const struct idvec *have_uids, const struct idvec *have_gids,
+ char *(*getpass_fn) (const char *prompt,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *getpass_hook,
+ error_t (*verify_fn) (const char *password,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *verify_hook)
+{
+ if (have_uids && idvec_contains (have_uids, 0))
+ /* Root can do anything. */
+ return 0;
+ else
+ {
+ unsigned int i;
+ int multiple = 0; /* Asking for multiple ids? */
+ error_t err = 0; /* Our return status. */
+ struct idvec implied_gids = IDVEC_INIT; /* Gids implied by uids. */
+ /* If we already are in group 0 (`wheel'), this user's password can be
+ used to get root privileges instead of root's. */
+ int wheel_uid =
+ ((have_uids && have_gids
+ && (idvec_contains (have_gids, 0) && have_uids->num > 0))
+ ? have_uids->ids[0]
+ : 0);
+
+ if (! verify_fn)
+ {
+ verify_fn = verify_passwd;
+ verify_hook = (void *)(intptr_t)wheel_uid;
+ }
+
+ /* See if there are multiple ids in contention, in which case we should
+ name each user/group as we ask for its password. */
+ if (uids && gids)
+ {
+ int num_non_implied_gids = 0;
+
+ /* Calculate which groups we need not ask about because they are
+ implied by the uids which we (will) have verified. Note that we
+ ignore any errors; at most, it means we will ask for too many
+ passwords. */
+ idvec_merge_implied_gids (&implied_gids, uids);
+
+ for (i = 0; i < gids->num; i++)
+ if (! idvec_contains (&implied_gids, gids->ids[i]))
+ num_non_implied_gids++;
+
+ multiple = (uids->num + num_non_implied_gids) > 1;
+ }
+ else if (uids)
+ multiple = uids->num > 1;
+ else if (gids)
+ multiple = gids->num > 1;
+
+ if (uids && idvec_contains (uids, 0))
+ /* root is being asked for, which, once granted will provide access for
+ all the others. */
+ err = verify_id (0, 0, multiple,
+ getpass_fn, getpass_hook, verify_fn, verify_hook);
+ else
+ {
+ if (uids)
+ /* Check uids */
+ for (i = 0; i < uids->num && !err; i++)
+ {
+ uid_t uid = uids->ids[i];
+ if (!have_uids || !idvec_contains (have_uids, uid))
+ err = verify_id (uid, 0, multiple,
+ getpass_fn, getpass_hook, verify_fn, verify_hook);
+ }
+
+ if (gids)
+ /* Check gids */
+ for (i = 0; i < gids->num && !err; i++)
+ {
+ gid_t gid = gids->ids[i];
+ if ((!have_gids || !idvec_contains (have_gids, gid))
+ && !idvec_contains (&implied_gids, gid))
+ err = verify_id (gid, 1, multiple,
+ getpass_fn, getpass_hook, verify_fn, verify_hook);
+ }
+ }
+
+ idvec_fini (&implied_gids);
+
+ return err;
+ }
+}
+
+/* Verify that the user should be allowed to assume the indentity of the
+ user/group ID (depending on whether IS_GROUP is false/true). If MULTIPLE
+ is true, then this is one of multiple ids being verified, so */
+static error_t
+verify_id (uid_t id, int is_group, int multiple,
+ char *(*getpass_fn) (const char *prompt,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *getpass_hook,
+ error_t (*verify_fn) (const char *password,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *verify_hook)
+{
+ int err;
+ void *pwd_or_grp = 0;
+ char *name = 0;
+ char *prompt = 0, *password;
+ char id_lookup_buf[1024];
+ char sp_lookup_buf[1024];
+
+ /* VERIFY_FN should have been defaulted in idvec_verify if necessary. */
+ assert (verify_fn);
+
+ if (id != (uid_t) -1)
+ do
+ {
+ if (is_group)
+ {
+ struct group _gr, *gr;
+ if (getgrgid_r (id, &_gr, id_lookup_buf, sizeof id_lookup_buf, &gr)
+ == 0)
+ {
+ if (!gr->gr_passwd || !*gr->gr_passwd)
+ return (*verify_fn) ("", id, 1, gr, verify_hook);
+ name = gr->gr_name;
+ pwd_or_grp = gr;
+ }
+ }
+ else
+ {
+ struct passwd _pw, *pw;
+ if (getpwuid_r (id, &_pw, id_lookup_buf, sizeof id_lookup_buf, &pw)
+ == 0)
+ {
+ if (strcmp (pw->pw_passwd, SHADOW_PASSWORD_STRING) == 0)
+ {
+ /* When encrypted password is "x", check shadow
+ passwords to see if there is an empty password. */
+ struct spwd _sp, *sp;
+ if (getspnam_r (pw->pw_name, &_sp, sp_lookup_buf,
+ sizeof sp_lookup_buf, &sp) == 0)
+ /* The storage for the password string is in
+ SP_LOOKUP_BUF, a local variable in this function.
+ We Know that the only use of PW->pw_passwd will be
+ in the VERIFY_FN call in this function, and that
+ the pointer will not be stored past the call. */
+ pw->pw_passwd = sp->sp_pwdp;
+ }
+
+ if (pw->pw_passwd[0] == '\0')
+ return (*verify_fn) ("", id, 0, pw, verify_hook);
+ name = pw->pw_name;
+ pwd_or_grp = pw;
+ }
+ }
+ if (! name)
+ {
+ /* [ug]id lookup failed! */
+ if (id != 0 || is_group)
+ /* If ID != 0, then it's probably just an unknown id, so ask for
+ the root password instead -- root should be able to do
+ anything. */
+ {
+ id = 0; /* Root */
+ is_group = 0; /* uid */
+ multiple = 1; /* Explicitly ask for root's password. */
+ }
+ else
+ /* No password entry for root. */
+ name = "root";
+ }
+ }
+ while (! name);
+
+ if (! getpass_fn)
+ /* Default GETPASS_FN to using getpass. */
+ getpass_fn = get_passwd;
+
+ if (multiple)
+ {
+ if (name)
+ asprintf (&prompt, "Password for %s%s:",
+ is_group ? "group " : "", name);
+ else
+ asprintf (&prompt, "Password for %s %d:",
+ is_group ? "group" : "user", id);
+ }
+
+ /* Prompt the user for the password. */
+ if (prompt)
+ {
+ password =
+ (*getpass_fn) (prompt, id, is_group, pwd_or_grp, getpass_hook);
+ free (prompt);
+ }
+ else
+ password =
+ (*getpass_fn) ("Password:", id, is_group, pwd_or_grp, getpass_hook);
+
+ /* Check the user's answer. */
+ if (password)
+ {
+ err = (*verify_fn) (password, id, is_group, pwd_or_grp, verify_hook);
+
+ /* Paranoia may destroya. */
+ memset (password, 0, strlen (password));
+
+ free (password);
+ }
+ else
+ err = EACCES;
+
+ return err;
+}
diff --git a/libshouldbeinlibc/idvec.c b/libshouldbeinlibc/idvec.c
new file mode 100644
index 00000000..7fdee104
--- /dev/null
+++ b/libshouldbeinlibc/idvec.c
@@ -0,0 +1,339 @@
+/* Routines for vectors of uids/gids
+
+ Copyright (C) 1995, 1996, 1997, 1998, 1999 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 <malloc.h>
+#include <string.h>
+
+#include "idvec.h"
+
+/* Return a new, empty, idvec, or NULL if there wasn't enough memory. */
+struct idvec *
+make_idvec ()
+{
+ struct idvec *idvec = malloc (sizeof (struct idvec));
+ if (idvec)
+ {
+ idvec->alloced = idvec->num = 0;
+ idvec->ids = 0;
+ }
+ return idvec;
+}
+
+/* Free's IDVEC, but not the storage pointed to by the IDS field. */
+void
+idvec_free_wrapper (struct idvec *idvec)
+{
+ free (idvec);
+}
+
+void
+idvec_free_contents (struct idvec *idvec)
+{
+ if (idvec->alloced)
+ free (idvec->ids);
+}
+
+void
+idvec_free (struct idvec *idvec)
+{
+ idvec_free_contents (idvec);
+ idvec_free_wrapper (idvec);
+}
+
+/* Ensure that IDVEC has enough spaced allocated to hold NUM ids, thus
+ ensuring that any subsequent ids added won't return a memory allocation
+ error unless it would result in more ids that NUM. ENOMEM is returned if
+ a memory allocation error occurs. */
+error_t
+idvec_ensure (struct idvec *idvec, unsigned num)
+{
+ if (num > idvec->alloced)
+ {
+ uid_t *_ids = realloc (idvec->ids, num * sizeof (uid_t));
+ if (! _ids)
+ return ENOMEM;
+ idvec->ids = _ids;
+ idvec->alloced = num;
+ }
+ return 0;
+}
+
+/* Like idvec_ensure(), but takes INC, the increment of the number of ids
+ already in IDVEC as an argument. */
+error_t
+idvec_grow (struct idvec *idvec, unsigned inc)
+{
+ return idvec_ensure (idvec, idvec->num + inc);
+}
+
+/* Returns true if IDVEC contains ID, at or after position POS. */
+int
+idvec_tail_contains (const struct idvec *idvec, unsigned pos, uid_t id)
+{
+ uid_t *ids = idvec->ids, *end = ids + idvec->num, *p = ids + pos;
+ while (p < end)
+ if (*p++ == id)
+ return 1;
+ return 0;
+}
+
+/* Insert ID into IDVEC at position POS, returning ENOMEM if there wasn't
+ enough memory, or 0. */
+error_t
+idvec_insert (struct idvec *idvec, unsigned pos, uid_t id)
+{
+ error_t err = 0;
+ unsigned num = idvec->num;
+ unsigned new_num = (pos < num ? num + 1 : pos + 1);
+
+ if (idvec->alloced == num)
+ /* If we seem to be growing by just one, actually prealloc some more. */
+ err = idvec_ensure (idvec, new_num + num);
+ else
+ err = idvec_ensure (idvec, new_num);
+
+ if (! err)
+ {
+ uid_t *ids = idvec->ids;
+ if (pos < num)
+ bcopy (ids + pos, ids + pos + 1, (num - pos) * sizeof (uid_t));
+ else if (pos > num)
+ bzero (ids + num, (pos - num) * sizeof (uid_t));
+ ids[pos] = id;
+ idvec->num = new_num;
+ }
+
+ return err;
+}
+
+/* Add ID onto the end of IDVEC, returning ENOMEM if there's not enough memory,
+ or 0. */
+error_t
+idvec_add (struct idvec *idvec, uid_t id)
+{
+ return idvec_insert (idvec, idvec->num, id);
+}
+
+/* If IDVEC doesn't contain ID, add it onto the end, returning ENOMEM if
+ there's not enough memory; otherwise, do nothing. */
+error_t
+idvec_add_new (struct idvec *idvec, uid_t id)
+{
+ if (idvec_contains (idvec, id))
+ return 0;
+ else
+ return idvec_add (idvec, id);
+}
+
+/* If IDVEC doesn't contain ID at position POS or after, insert it at POS,
+ returning ENOMEM if there's not enough memory; otherwise, do nothing. */
+error_t
+idvec_insert_new (struct idvec *idvec, unsigned pos, uid_t id)
+{
+ if (idvec_tail_contains (idvec, pos, id))
+ return 0;
+ else
+ return idvec_insert (idvec, pos, id);
+}
+
+/* Set the ids in IDVEC to IDS (NUM elements long); delete whatever
+ the previous ids were. */
+error_t
+idvec_set_ids (struct idvec *idvec, const uid_t *ids, unsigned num)
+{
+ error_t err;
+
+ err = idvec_ensure (idvec, num);
+ if (!err)
+ {
+ bcopy (ids, idvec->ids, num * sizeof (uid_t));
+ idvec->num = num;
+ }
+ return err;
+}
+
+/* Like idvec_set_ids, but get the new ids from new. */
+error_t
+idvec_set (struct idvec *idvec, const struct idvec *new)
+{
+ return idvec_set_ids (idvec, new->ids, new->num);
+}
+
+/* Adds each id in the vector IDS (NUM elements long) to IDVEC, as long as it
+ wasn't previously in IDVEC. */
+error_t
+idvec_merge_ids (struct idvec *idvec, const uid_t *ids, unsigned num)
+{
+ error_t err = 0;
+ unsigned num_old = idvec->num;
+ while (num-- > 0 && !err)
+ {
+ unsigned int i;
+ for (i = 0; i < num_old; i++)
+ if (idvec->ids[i] == *ids)
+ break;
+ if (i == num_old)
+ err = idvec_add (idvec, *ids);
+ ids++;
+ }
+ return err;
+}
+
+/* Adds each id from NEW to IDVEC, as if with idvec_add_new(). */
+error_t
+idvec_merge (struct idvec *idvec, const struct idvec *new)
+{
+ return idvec_merge_ids (idvec, new->ids, new->num);
+}
+
+/* Remove any occurrences of ID in IDVEC after position POS.
+ Returns true if anything was done. */
+int
+idvec_remove (struct idvec *idvec, unsigned pos, uid_t id)
+{
+ if (pos < idvec->num)
+ {
+ int left = idvec->num - pos;
+ uid_t *ids = idvec->ids + pos, *targ = ids;
+ while (left--)
+ {
+ if (*ids != id)
+ {
+ if (ids != targ)
+ *targ = *ids;
+ targ++;
+ }
+ ids++;
+ }
+ if (ids == targ)
+ return 0;
+ idvec->num = targ - idvec->ids;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+/* Remove all ids in SUB from IDVEC, returning true if anything was done. */
+int
+idvec_subtract (struct idvec *idvec, const struct idvec *sub)
+{
+ unsigned int i;
+ int done = 0;
+ for (i = 0; i < sub->num; i++)
+ done |= idvec_remove (idvec, 0, sub->ids[i]);
+ return done;
+}
+
+/* Remove all ids from IDVEC that are *not* in KEEP, returning true if
+ anything was changed. */
+int
+idvec_keep (struct idvec *idvec, const struct idvec *keep)
+{
+ uid_t *old = idvec->ids, *new = old, *end = old + idvec->num;
+
+ while (old < end)
+ {
+ uid_t id = *old++;
+ if (idvec_contains (keep, id))
+ {
+ if (old != new)
+ *new = id;
+ new++;
+ }
+ }
+
+ if (old != new)
+ {
+ idvec->num = new - idvec->ids;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+/* Deleted the id at position POS in IDVEC. */
+void
+idvec_delete (struct idvec *idvec, unsigned pos)
+{
+ unsigned num = idvec->num;
+ if (pos < num)
+ {
+ uid_t *ids = idvec->ids;
+ idvec->num = --num;
+ if (num > pos)
+ bcopy (ids + pos + 1, ids + pos, (num - pos) * sizeof (uid_t));
+ }
+}
+
+/* Insert ID at position POS in IDVEC, remove any instances of ID previously
+ present at POS or after. ENOMEM is returned if there's not enough memory,
+ otherwise 0. */
+error_t
+idvec_insert_only (struct idvec *idvec, unsigned pos, uid_t id)
+{
+ if (idvec->num > pos && idvec->ids[pos] == id)
+ return 0;
+ else
+ {
+ idvec_remove (idvec, pos, id);
+ return idvec_insert (idvec, pos, id);
+ }
+}
+
+/* EFF and AVAIL should be idvec's corresponding to a processes
+ effective and available ids. ID replaces the first id in EFF, and,
+ if there are any IDs in AVAIL, replaces the second ID in AVAIL;
+ what it replaces in any case is preserved by adding it to AVAIL if
+ not already present. In addition, the If SECURE is non-NULL, and
+ ID was not previously present in either EFF or AVAIL, then *SECURE
+ is set to true. ENOMEM is returned if a malloc fails, otherwise 0.
+ The return parameters are only touched if this call succeeds. */
+error_t
+idvec_setid (struct idvec *eff, struct idvec *avail, uid_t id, int *secure)
+{
+ error_t err;
+ /* True if ID was not previously present in either EFF or AVAIL. */
+ int _secure = !idvec_contains (eff, id) && !idvec_contains (avail, id);
+
+ if (eff->num > 0)
+ {
+ /* If there are any old effective ids, we replace eff[0] with
+ ID, and try to preserve the old eff[0] by putting it in AVAIL
+ list if necessary. */
+ err = idvec_add_new (avail, eff->ids[0]);
+ if (!err)
+ eff->ids[0] = id;
+ }
+ else
+ /* No previous effective ids, just make ID the first one. */
+ err = idvec_add (eff, id);
+
+ if (avail->num > 0 && !err)
+ err = idvec_insert_only (avail, 1, id);
+
+ if (err)
+ return err;
+
+ if (_secure && secure && !*secure)
+ *secure = 1;
+
+ return 0;
+}
diff --git a/libshouldbeinlibc/idvec.h b/libshouldbeinlibc/idvec.h
new file mode 100644
index 00000000..d6ec1553
--- /dev/null
+++ b/libshouldbeinlibc/idvec.h
@@ -0,0 +1,236 @@
+/* Routines for vectors of uids/gids
+
+ Copyright (C) 1995,96,97,99,2001 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+
+ 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 __IDVEC_H__
+#define __IDVEC_H__
+
+#include <sys/types.h>
+#include <hurd/hurd_types.h>
+#include <string.h>
+#include <features.h>
+
+#ifdef IDVEC_DEFINE_EI
+#define IDVEC_EI
+#else
+#define IDVEC_EI __extern_inline
+#endif
+
+struct idvec
+{
+ uid_t *ids;
+ unsigned num, alloced;
+};
+
+#define IDVEC_INIT { 0 }
+
+/* Return a new, empty, idvec, or NULL if there wasn't enough memory. */
+struct idvec *make_idvec (void);
+
+/* Free the storage pointed to by IDVEC->ids. */
+void idvec_free_contents (struct idvec *idvec);
+#define idvec_fini idvec_free_contents
+
+/* Free IDVEC, but not the storage pointed to by the IDS field. */
+void idvec_free_wrapper (struct idvec *idvec);
+
+/* Free IDVEC and any storage associated with it. */
+void idvec_free (struct idvec *idvec);
+
+extern void idvec_clear (struct idvec *idvec);
+
+extern int idvec_is_empty (const struct idvec *idvec);
+
+extern int idvec_equal (const struct idvec *idvec1, const struct idvec *idvec2);
+
+#if defined(__USE_EXTERN_INLINES) || defined(IDVEC_DEFINE_EI)
+
+/* Mark IDVEC as not containing any ids. */
+IDVEC_EI void
+idvec_clear (struct idvec *idvec)
+{
+ idvec->num = 0;
+}
+
+/* Returns true if IDVEC contains no ids. */
+IDVEC_EI int
+idvec_is_empty (const struct idvec *idvec)
+{
+ return idvec->num == 0;
+}
+
+/* Return true if IDVEC1 has contents identical to IDVEC2. */
+IDVEC_EI int
+idvec_equal (const struct idvec *idvec1, const struct idvec *idvec2)
+{
+ size_t num = idvec1->num;
+ return idvec2->num == num
+ && (num == 0
+ || memcmp (idvec1->ids, idvec2->ids, num * sizeof *idvec1->ids) == 0);
+}
+
+#endif /* Use extern inlines. */
+
+/* Ensure that IDVEC has enough spaced allocated to hold NUM ids, thus
+ ensuring that any subsequent ids added won't return a memory allocation
+ error unless it would result in more ids that NUM. ENOMEM is returned if
+ a memory allocation error occurs. */
+error_t idvec_ensure (struct idvec *idvec, unsigned num);
+
+/* Like idvec_ensure(), but takes INC, the increment of the number of ids
+ already in IDVEC as an argument. */
+error_t idvec_grow (struct idvec *idvec, unsigned inc);
+
+/* Returns true if IDVEC contains ID, at or after position POS. */
+int idvec_tail_contains (const struct idvec *idvec, unsigned pos, uid_t id);
+
+extern int idvec_contains (const struct idvec *idvec, uid_t id);
+
+#if defined(__USE_EXTERN_INLINES) || defined(IDVEC_DEFINE_EI)
+
+/* Returns true if IDVEC contains ID. */
+IDVEC_EI int
+idvec_contains (const struct idvec *idvec, uid_t id)
+{
+ return idvec_tail_contains (idvec, 0, id);
+}
+
+#endif /* Use extern inlines. */
+
+/* Insert ID into IDVEC at position POS, returning ENOMEM if there wasn't
+ enough memory, or 0. */
+error_t idvec_insert (struct idvec *idvec, unsigned pos, uid_t id);
+
+/* Add ID onto the end of IDVEC, returning ENOMEM if there's not enough memory,
+ or 0. */
+error_t idvec_add (struct idvec *idvec, uid_t id);
+
+/* If IDVEC doesn't contain ID, add it onto the end, returning ENOMEM if
+ there's not enough memory; otherwise, do nothing. */
+error_t idvec_add_new (struct idvec *idvec, uid_t id);
+
+/* If IDVEC doesn't contain ID at position POS or after, insert it at POS,
+ returning ENOMEM if there's not enough memory; otherwise, do nothing. */
+error_t idvec_insert_new (struct idvec *idvec, unsigned pos, uid_t id);
+
+/* Set the ids in IDVEC to IDS (NUM elements long); delete whatever
+ the previous ids were. */
+error_t idvec_set_ids (struct idvec *idvec, const uid_t *ids, unsigned num);
+
+/* Like idvec_set_ids, but get the new ids from new. */
+error_t idvec_set (struct idvec *idvec, const struct idvec *new);
+
+/* Adds each id in the vector IDS (NUM elements long) to IDVEC, as if with
+ idvec_add_new(). */
+error_t idvec_merge_ids (struct idvec *idvec, const uid_t *ids, unsigned num);
+
+/* Adds each id from NEW to IDVEC, as if with idvec_add_new(). */
+error_t idvec_merge (struct idvec *idvec, const struct idvec *new);
+
+/* Remove all ids in SUB from IDVEC, returning true if anything was done. */
+int idvec_subtract (struct idvec *idvec, const struct idvec *sub);
+
+/* Remove all ids from IDVEC that are *not* in KEEP, returning true if
+ anything was changed. */
+int idvec_keep (struct idvec *idvec, const struct idvec *keep);
+
+/* Remove any occurrences of ID in IDVEC after position POS> Returns true if
+ anything was done. */
+int idvec_remove (struct idvec *idvec, unsigned pos, uid_t id);
+
+/* Deleted the id at position POS in IDVEC. */
+void idvec_delete (struct idvec *idvec, unsigned pos);
+
+/* Insert ID at position POS in IDVEC, remove any instances of ID previously
+ present at POS or after. ENOMEM is returned if there's not enough memory,
+ otherwise 0. */
+error_t idvec_insert_only (struct idvec *idvec, unsigned pos, uid_t id);
+
+/* EFF and AVAIL should be idvec's corresponding to a process's
+ effective and available ids. ID replaces the first id in EFF, and,
+ if there are any IDs in AVAIL, replaces the second ID in AVAIL;
+ what it replaces in any case is preserved by adding it to AVAIL if
+ not already present. In addition, the If SECURE is non-NULL, and
+ ID was not previously present in either EFF or AVAIL, then *SECURE
+ is set to true. ENOMEM is returned if a malloc fails, otherwise 0.
+ The return parameters are only touched if this call succeeds. */
+error_t idvec_setid (struct idvec *eff, struct idvec *avail, uid_t id,
+ int *secure);
+
+/* Add to all of EFF_UIDS, AVAIL_UIDS, EFF_GIDS, AVAIL_GIDS (as if with
+ idvec_merge) the ids associated with the auth port AUTH. Any of these
+ parameters may be NULL if that information isn't desired. */
+error_t idvec_merge_auth (struct idvec *eff_uids, struct idvec *avail_uids,
+ struct idvec *eff_gids, struct idvec *avail_gids,
+ auth_t auth);
+
+/* Add to GIDS those group ids implied by the users in UIDS. */
+error_t idvec_merge_implied_gids (struct idvec *gids, const struct idvec *uids);
+
+/* Make sure the user has the right to the ids in UIDS and GIDS, given that
+ we know he already has HAVE_UIDS and HAVE_GIDS, asking for passwords (with
+ GETPASS_FN) where necessary; any of the arguments may be 0, which is
+ treated the same as if they were empty. 0 is returned if access should be
+ allowed, otherwise EINVAL if an incorrect password was entered, or an
+ error relating to resource failure. Any uid/gid < 0 will be guaranteed to
+ fail regardless of what the user types. GETPASS_FN should ask for a
+ password from the user, and return it in malloced storage; it defaults to
+ using the standard libc function getpass. If VERIFY_FN is 0, then the
+ users password will be encrypted with crypt and compared with the
+ password/group entry's encrypted password, otherwise, VERIFY_FN will be
+ called to check the entered password's validity; it should return 0 if the
+ given password is correct, or an error code. The common arguments to
+ GETPASS_FN and VERIFY_FN are: ID, the user/group id; IS_GROUP, true if its
+ a group, or false if a user; PWD_OR_GRP, a pointer to either the passwd or
+ group entry for ID, and HOOK, containing the appropriate hook passed into
+ idvec_verify. */
+error_t idvec_verify (const struct idvec *uids, const struct idvec *gids,
+ const struct idvec *have_uids,
+ const struct idvec *have_gids,
+ char *(*getpass_fn) (const char *prompt,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *getpass_hook,
+ error_t (*verify_fn) (const char *password,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *verify_hook);
+
+/* Return a string representation of the ids in IDVEC, each id separated by
+ the string SEP (default ","). SHOW_VALUES and SHOW_NAMES reflect how each
+ id is printed (if SHOW_NAMES is true values are used where names aren't
+ available); if both are true, the `VALUE(NAME)' format is used.
+ ID_NAME_FN is used to map each id to a name; it should return a malloced
+ string, which will be freed here. The empty string is returned for an
+ empty list, and 0 for an allocation error. */
+char *idvec_rep (const struct idvec *idvec,
+ int show_values, int show_names,
+ char *(*id_name_fn) (uid_t id),
+ const char *sep);
+
+/* Like idvec_rep, mapping ids to user names. */
+char *idvec_uids_rep (const struct idvec *idvec,
+ int show_values, int show_names,
+ const char *sep);
+
+/* Like idvec_rep, mapping ids to group names. */
+char *idvec_gids_rep (const struct idvec *idvec,
+ int show_values, int show_names,
+ const char *sep);
+
+#endif /* __IDVEC_H__ */
diff --git a/libshouldbeinlibc/lcm.c b/libshouldbeinlibc/lcm.c
new file mode 100644
index 00000000..606f4eba
--- /dev/null
+++ b/libshouldbeinlibc/lcm.c
@@ -0,0 +1,46 @@
+/* Lcm (least common multiple), and gcd (greatest common divisor)
+
+ Copyright (C) 1996 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+/* There are probably more efficient ways to do these... */
+
+/* Return the greatest common divisor of p & q. */
+inline long
+gcd (long p, long q)
+{
+ if (p == 0)
+ return q;
+ else if (q == 0)
+ return p;
+ else if (p == q)
+ return p;
+ else if (q > p)
+ return gcd (q, p);
+ else
+ return gcd (q, p % q);
+}
+
+/* Return the least common multiple of p & q. */
+long
+lcm (long p, long q)
+{
+ return (p / gcd (p, q)) * q;
+}
diff --git a/libshouldbeinlibc/localhost.c b/libshouldbeinlibc/localhost.c
new file mode 100644
index 00000000..9b7d4e09
--- /dev/null
+++ b/libshouldbeinlibc/localhost.c
@@ -0,0 +1,75 @@
+/* A slightly more convenient wrapper for gethostname
+
+ Copyright (C) 1996 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 <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* Return the name of the localhost. This is just a wrapper for gethostname,
+ which takes care of allocating a big enough buffer, and caches the result
+ after the first call (so the result should be copied before modification).
+ If something goes wrong, 0 is returned, and errno set. */
+char *
+localhost ()
+{
+ static char *buf = 0;
+ static size_t buf_len = 0;
+
+ if (! buf)
+ {
+ do {
+ errno = 0;
+
+ if (buf) {
+ char *new;
+ buf_len += buf_len;
+ new = realloc (buf, buf_len);
+ if (! new)
+ {
+ free (buf);
+ buf = 0;
+ errno = ENOMEM;
+ return 0;
+ }
+ else
+ buf = new;
+ } else {
+ buf_len = 128; /* Initial guess */
+ buf = malloc (buf_len);
+ if (! buf)
+ {
+ errno = ENOMEM;
+ return 0;
+ }
+ }
+ } while ((gethostname(buf, buf_len) == 0 && !memchr (buf, '\0', buf_len))
+ || errno == ENAMETOOLONG);
+
+ if (errno)
+ /* gethostname failed, abort. */
+ {
+ free (buf);
+ buf = 0;
+ }
+ }
+
+ return buf;
+}
diff --git a/libshouldbeinlibc/maptime-funcs.c b/libshouldbeinlibc/maptime-funcs.c
new file mode 100644
index 00000000..080e3ae6
--- /dev/null
+++ b/libshouldbeinlibc/maptime-funcs.c
@@ -0,0 +1,5 @@
+#define MAPTIME_DEFINE_EI
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include "maptime.h"
diff --git a/libshouldbeinlibc/maptime.c b/libshouldbeinlibc/maptime.c
new file mode 100644
index 00000000..f0b69db4
--- /dev/null
+++ b/libshouldbeinlibc/maptime.c
@@ -0,0 +1,84 @@
+/* Support for mach's mapped time
+
+ Copyright (C) 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 <fcntl.h>
+#include <hurd.h>
+#include <device/device.h>
+
+#include "maptime.h"
+
+/* Return the mach mapped time page in MTIME. If USE_MACH_DEV is false, then
+ the hurd time device DEV_NAME, or "/dev/time" if DEV_NAME is 0, is
+ used. If USE_MACH_DEV is true, the mach device DEV_NAME, or "time" if
+ DEV_NAME is 0, is used; this is a privileged operation. The mapped time
+ may be converted to a struct timeval at any time using maptime_read. */
+error_t
+maptime_map (int use_mach_dev, char *dev_name,
+ volatile struct mapped_time_value **mtime)
+{
+ error_t err;
+ mach_port_t memobj;
+
+ if (use_mach_dev)
+ {
+ device_t device;
+ mach_port_t device_master;
+
+ err = get_privileged_ports (0, &device_master);
+ if (err)
+ return err;
+
+ err = device_open (device_master, 0, dev_name ?: "time", &device);
+ mach_port_deallocate (mach_task_self (), device_master);
+ if (err)
+ return err;
+
+ err = device_map (device, VM_PROT_READ, 0, sizeof *mtime, &memobj, 0);
+
+ /* Deallocate the device port. The mapping is independent of
+ this port. */
+ mach_port_deallocate (mach_task_self (), device);
+ }
+ else
+ {
+ mach_port_t wr_memobj;
+ file_t node = file_name_lookup (dev_name ?: "/dev/time", O_RDONLY, 0);
+
+ if (node == MACH_PORT_NULL)
+ return errno;
+
+ err = io_map (node, &memobj, &wr_memobj);
+ if (!err && wr_memobj != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), wr_memobj);
+
+ mach_port_deallocate (mach_task_self (), node);
+ }
+
+ if (! err)
+ {
+ *mtime = 0;
+ err =
+ vm_map (mach_task_self (), (vm_address_t *)mtime, sizeof *mtime, 0, 1,
+ memobj, 0, 0, VM_PROT_READ, VM_PROT_READ, VM_INHERIT_NONE);
+ mach_port_deallocate (mach_task_self (), memobj);
+ }
+
+ return err;
+}
diff --git a/libshouldbeinlibc/maptime.h b/libshouldbeinlibc/maptime.h
new file mode 100644
index 00000000..947ad640
--- /dev/null
+++ b/libshouldbeinlibc/maptime.h
@@ -0,0 +1,61 @@
+/* Support for mach's mapped time
+
+ Copyright (C) 1996, 1997, 2000, 2007 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.org>
+
+ 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 __MAPTIME_H__
+#define __MAPTIME_H__
+
+#include <mach/time_value.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <features.h>
+
+#ifdef MAPTIME_DEFINE_EI
+#define MAPTIME_EI
+#else
+#define MAPTIME_EI __extern_inline
+#endif
+
+/* Return the mach mapped time page in MTIME. If USE_MACH_DEV is false, then
+ the hurd time device DEV_NAME, or "/dev/time" if DEV_NAME is 0, is
+ used. If USE_MACH_DEV is true, the mach device DEV_NAME, or "time" if
+ DEV_NAME is 0, is used; this is a privileged operation. The mapped time
+ may be converted to a struct timeval at any time using maptime_read. */
+error_t maptime_map (int use_mach_dev, char *dev_name,
+ volatile struct mapped_time_value **mtime);
+
+extern void maptime_read (volatile struct mapped_time_value *mtime, struct timeval *tv);
+
+#if defined(__USE_EXTERN_INLINES) || defined(MAPTIME_DEFINE_EI)
+
+/* Read the current time from MTIME into TV. This should be very fast. */
+MAPTIME_EI void
+maptime_read (volatile struct mapped_time_value *mtime, struct timeval *tv)
+{
+ do
+ {
+ tv->tv_sec = mtime->seconds;
+ tv->tv_usec = mtime->microseconds;
+ }
+ while (tv->tv_sec != mtime->check_seconds);
+}
+
+#endif /* Use extern inlines. */
+
+#endif /* __MAPTIME_H__ */
diff --git a/libshouldbeinlibc/nullauth.c b/libshouldbeinlibc/nullauth.c
new file mode 100644
index 00000000..3a98e558
--- /dev/null
+++ b/libshouldbeinlibc/nullauth.c
@@ -0,0 +1,45 @@
+/* Drop all authentication credentials.
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ Written by Justus Winter <4winter@informatik.uni-hamburg.de>
+
+ This file is part of the GNU Hurd.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#include <hurd.h>
+
+/* Obtain an empty authentication handle and use it for further
+ authentication purposes. This effectively drops all Unix
+ privileges. */
+error_t
+setnullauth (void)
+{
+ error_t err;
+
+ auth_t nullauth;
+ err = auth_makeauth (getauth (),
+ NULL, MACH_MSG_TYPE_COPY_SEND, 0,
+ NULL, 0,
+ NULL, 0,
+ NULL, 0,
+ NULL, 0,
+ &nullauth);
+ if (err)
+ return err;
+
+ err = setauth (nullauth);
+ return err;
+}
diff --git a/libshouldbeinlibc/nullauth.h b/libshouldbeinlibc/nullauth.h
new file mode 100644
index 00000000..efdb5f3a
--- /dev/null
+++ b/libshouldbeinlibc/nullauth.h
@@ -0,0 +1,31 @@
+/* Drop all authentication credentials.
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ Written by Justus Winter <4winter@informatik.uni-hamburg.de>
+
+ This file is part of the GNU Hurd.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#ifndef __NULLAUTH_H__
+#define __NULLAUTH_H__
+
+/* Obtain an empty authentication handle and use it for further
+ authentication purposes. This effectively drops all Unix
+ privileges. */
+error_t
+setnullauth (void);
+
+#endif /* __NULLAUTH_H__ */
diff --git a/libshouldbeinlibc/portinfo.c b/libshouldbeinlibc/portinfo.c
new file mode 100644
index 00000000..e6305c6e
--- /dev/null
+++ b/libshouldbeinlibc/portinfo.c
@@ -0,0 +1,158 @@
+/* Print information about a task's ports
+
+ Copyright (C) 1996,98,99,2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+
+ 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 <sys/mman.h>
+
+#include "portinfo.h"
+
+/* Prints info about NAME in TASK to STREAM, in a way described by the flags
+ in SHOW. If TYPE is non-zero, it should be what mach_port_type returns
+ for NAME. */
+error_t
+print_port_info (mach_port_t name, mach_port_type_t type, task_t task,
+ unsigned show, FILE *stream)
+{
+ int hex_names = (show & PORTINFO_HEX_NAMES);
+ int first = 1;
+ void comma ()
+ {
+ if (first)
+ first = 0;
+ else
+ fprintf (stream, ", ");
+ }
+ void prefs (mach_port_right_t right)
+ {
+ mach_port_urefs_t refs;
+ error_t err = mach_port_get_refs (task, name, right, &refs);
+ if (! err)
+ fprintf (stream, " (refs: %zu)", refs);
+ }
+
+ if (type == 0)
+ {
+ error_t err = mach_port_type (task, name, &type);
+ if (err)
+ return err;
+ }
+
+ fprintf (stream, hex_names ? "%#6zx: " : "%6zd: ", name);
+
+ if (type & MACH_PORT_TYPE_RECEIVE)
+ {
+ comma ();
+ fprintf (stream, "receive");
+ if (show & PORTINFO_DETAILS)
+ {
+ struct mach_port_status status;
+ error_t err = mach_port_get_receive_status (task, name, &status);
+ if (! err)
+ {
+ fprintf (stream, " (");
+ if (status.mps_pset != MACH_PORT_NULL)
+ fprintf (stream,
+ hex_names ? "port-set: %#zx, " : "port-set: %zd, ",
+ status.mps_pset);
+ fprintf (stream, "seqno: %zu", status.mps_seqno);
+ if (status.mps_mscount)
+ fprintf (stream, ", ms-count: %zu", status.mps_mscount);
+ if (status.mps_qlimit != MACH_PORT_QLIMIT_DEFAULT)
+ fprintf (stream, ", qlimit: %zu", status.mps_qlimit);
+ if (status.mps_msgcount)
+ fprintf (stream, ", msgs: %zu", status.mps_msgcount);
+ fprintf (stream, "%s%s%s)",
+ status.mps_srights ? ", send-rights" : "",
+ status.mps_pdrequest ? ", pd-req" : "",
+ status.mps_nsrequest ? ", ns-req" : "");
+ }
+ }
+ }
+ if (type & MACH_PORT_TYPE_SEND)
+ {
+ comma ();
+ fprintf (stream, "send");
+ if (show & PORTINFO_DETAILS)
+ prefs (MACH_PORT_RIGHT_SEND);
+ }
+ if (type & MACH_PORT_TYPE_SEND_ONCE)
+ {
+ comma ();
+ fprintf (stream, "send-once");
+ }
+ if (type & MACH_PORT_TYPE_DEAD_NAME)
+ {
+ comma ();
+ fprintf (stream, "dead-name");
+ if (show & PORTINFO_DETAILS)
+ prefs (MACH_PORT_RIGHT_DEAD_NAME);
+ }
+ if (type & MACH_PORT_TYPE_PORT_SET)
+ {
+ comma ();
+ fprintf (stream, "port-set");
+ if (show & PORTINFO_DETAILS)
+ {
+ mach_port_t *members = 0;
+ mach_msg_type_number_t members_len = 0, i;
+ error_t err =
+ mach_port_get_set_status (task, name, &members, &members_len);
+ if (! err)
+ {
+ if (members_len == 0)
+ fprintf (stream, " (empty)");
+ else
+ {
+ fprintf (stream, hex_names ? " (%#zx" : " (%zu", members[0]);
+ for (i = 1; i < members_len; i++)
+ fprintf (stream, hex_names ? ", %#zx" : ", %zu",
+ members[i]);
+ fprintf (stream, ")");
+ munmap ((caddr_t) members, members_len * sizeof *members);
+ }
+ }
+ }
+ }
+ putc ('\n', stream);
+
+ return 0;
+}
+
+/* Prints info about every port in TASK that has a type in ONLY to STREAM. */
+error_t
+print_task_ports_info (task_t task, mach_port_type_t only,
+ unsigned show, FILE *stream)
+{
+ mach_port_t *names = 0;
+ mach_port_type_t *types = 0;
+ mach_msg_type_number_t names_len = 0, types_len = 0, i;
+ error_t err = mach_port_names (task, &names, &names_len, &types, &types_len);
+
+ if (err)
+ return err;
+
+ for (i = 0; i < names_len; i++)
+ if (types[i] & only)
+ print_port_info (names[i], types[i], task, show, stream);
+
+ munmap ((caddr_t) names, names_len * sizeof *names);
+ munmap ((caddr_t) types, types_len * sizeof *types);
+
+ return 0;
+}
diff --git a/libshouldbeinlibc/portinfo.h b/libshouldbeinlibc/portinfo.h
new file mode 100644
index 00000000..143c2898
--- /dev/null
+++ b/libshouldbeinlibc/portinfo.h
@@ -0,0 +1,58 @@
+/* Print information about a task's ports
+
+ Copyright (C) 1996, 1999 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 __PORTINFO_H__
+#define __PORTINFO_H__
+
+#include <stdio.h>
+#include <errno.h>
+#include <mach.h>
+
+#include <portxlate.h>
+
+/* Flags describing what to show. */
+#define PORTINFO_DETAILS 0x1
+#define PORTINFO_MEMBERS 0x4
+#define PORTINFO_HEX_NAMES 0x8
+
+/* Prints info about NAME in TASK to STREAM, in a way described by the flags
+ in SHOW. If TYPE is non-zero, it should be what mach_port_type returns
+ for NAME. */
+error_t print_port_info (mach_port_t name, mach_port_type_t type, task_t task,
+ unsigned show, FILE *stream);
+
+/* Prints info about every port in TASK that has a type in ONLY to STREAM. */
+error_t print_task_ports_info (task_t task, mach_port_type_t only,
+ unsigned show, FILE *stream);
+
+/* Prints info about NAME translated through X to STREAM, in a way described
+ by the flags in SHOW. If TYPE is non-zero, it should be what
+ mach_port_type returns for NAME in X->to_task. */
+error_t print_xlated_port_info (mach_port_t name, mach_port_type_t type,
+ struct port_name_xlator *x,
+ unsigned show, FILE *stream);
+
+/* Prints info about every port common to both tasks in X, but only if the
+ port in X->from_task has a type in ONLY, to STREAM. */
+error_t print_xlated_task_ports_info (struct port_name_xlator *x,
+ mach_port_type_t only,
+ unsigned show, FILE *stream);
+
+#endif /* __PORTINFO_H__ */
diff --git a/libshouldbeinlibc/portxlate.c b/libshouldbeinlibc/portxlate.c
new file mode 100644
index 00000000..f78abbf1
--- /dev/null
+++ b/libshouldbeinlibc/portxlate.c
@@ -0,0 +1,179 @@
+/* Translate mach port names between two tasks
+
+ Copyright (C) 1996,99,2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+
+ 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 <sys/types.h>
+#include <sys/mman.h>
+
+#include "portxlate.h"
+
+/* Return a new port name translator translating names between FROM_TASK and
+ TO_TASK, in XLATOR, or an error. */
+error_t
+port_name_xlator_create (mach_port_t from_task, mach_port_t to_task,
+ struct port_name_xlator **xlator)
+{
+ error_t err;
+ struct port_name_xlator *x = malloc (sizeof (struct port_name_xlator));
+
+ if (! x)
+ return ENOMEM;
+
+ mach_port_mod_refs (mach_task_self (), from_task, MACH_PORT_RIGHT_SEND, +1);
+ x->from_task = from_task;
+ mach_port_mod_refs (mach_task_self (), to_task, MACH_PORT_RIGHT_SEND, +1);
+ x->to_task = to_task;
+ x->to_names = 0;
+ x->to_types = 0;
+ x->to_names_len = 0;
+ x->to_types_len = 0;
+
+ /* Cache a list of names in TO_TASK. */
+ err = mach_port_names (to_task,
+ &x->to_names, &x->to_names_len,
+ &x->to_types, &x->to_types_len);
+
+ if (! err)
+ /* Make an array to hold ports from TO_TASK which have been translated
+ into our namespace. */
+ {
+ x->ports = malloc (sizeof (mach_port_t) * x->to_names_len);
+ if (x->ports)
+ {
+ unsigned int i;
+ for (i = 0; i < x->to_names_len; i++)
+ x->ports[i] = MACH_PORT_NULL;
+ }
+ else
+ {
+ munmap ((caddr_t) x->to_names,
+ x->to_names_len * sizeof (mach_port_t));
+ munmap ((caddr_t) x->to_types,
+ x->to_types_len * sizeof (mach_port_type_t));
+
+ mach_port_deallocate (mach_task_self (), x->to_task);
+ mach_port_deallocate (mach_task_self (), x->from_task);
+
+ err = ENOMEM;
+ }
+ }
+
+ if (err)
+ free (x);
+ else
+ *xlator = x;
+
+ return err;
+}
+
+/* Free the port name translator X and any resources it holds. */
+void
+port_name_xlator_free (struct port_name_xlator *x)
+{
+ unsigned int i;
+
+ for (i = 0; i < x->to_names_len; i++)
+ if (x->ports[i] != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), x->ports[i]);
+ free (x->ports);
+
+ munmap ((caddr_t) x->to_names, x->to_names_len * sizeof (mach_port_t));
+ munmap ((caddr_t) x->to_types, x->to_types_len * sizeof (mach_port_type_t));
+
+ mach_port_deallocate (mach_task_self (), x->to_task);
+ mach_port_deallocate (mach_task_self (), x->from_task);
+
+ free (x);
+}
+
+/* Translate the port FROM between the tasks in X, returning the translated
+ name in TO, and the types of TO in TO_TYPE, or an error. If TYPE is
+ non-zero, it should be what mach_port_type returns for FROM. */
+error_t
+port_name_xlator_xlate (struct port_name_xlator *x,
+ mach_port_t from, mach_port_type_t from_type,
+ mach_port_t *to, mach_port_type_t *to_type)
+{
+ error_t err;
+ mach_port_t port;
+ mach_msg_type_number_t i;
+ mach_msg_type_name_t aquired_type;
+ mach_msg_type_name_t valid_to_types;
+
+ if (from_type == 0)
+ {
+ error_t err = mach_port_type (x->from_task, from, &from_type);
+ if (err)
+ return err;
+ }
+
+ if (from_type & MACH_PORT_TYPE_RECEIVE)
+ valid_to_types = MACH_PORT_TYPE_SEND;
+ else if (from_type & MACH_PORT_TYPE_SEND)
+ valid_to_types = MACH_PORT_TYPE_SEND | MACH_PORT_TYPE_RECEIVE;
+ else
+ return EKERN_INVALID_RIGHT;
+
+ /* Translate the name FROM, in FROM_TASK's namespace into our namespace. */
+ err =
+ mach_port_extract_right (x->from_task, from,
+ ((from_type & MACH_PORT_TYPE_RECEIVE)
+ ? MACH_MSG_TYPE_MAKE_SEND
+ : MACH_MSG_TYPE_COPY_SEND),
+ &port,
+ &aquired_type);
+
+ if (err)
+ return err;
+
+ /* Look for likely candidates in TO_TASK's namespace to test against PORT. */
+ for (i = 0; i < x->to_names_len; i++)
+ {
+ if (x->ports[i] == MACH_PORT_NULL && (x->to_types[i] & valid_to_types))
+ /* Port I shows possibilities... */
+ {
+ err =
+ mach_port_extract_right (x->to_task,
+ x->to_names[i],
+ ((x->to_types[i] & MACH_PORT_TYPE_RECEIVE)
+ ? MACH_MSG_TYPE_MAKE_SEND
+ : MACH_MSG_TYPE_COPY_SEND),
+ &x->ports[i],
+ &aquired_type);
+ if (err)
+ x->to_types[i] = 0; /* Don't try to fetch this port again. */
+ }
+
+ if (x->ports[i] == port)
+ /* We win! Port I in TO_TASK is the same as PORT. */
+ break;
+ }
+
+ mach_port_deallocate (mach_task_self (), port);
+
+ if (i < x->to_names_len)
+ /* Port I is the right translation; return its name in TO_TASK. */
+ {
+ *to = x->to_names[i];
+ *to_type = x->to_types[i];
+ return 0;
+ }
+ else
+ return EKERN_INVALID_NAME;
+}
diff --git a/libshouldbeinlibc/portxlate.h b/libshouldbeinlibc/portxlate.h
new file mode 100644
index 00000000..13ddb148
--- /dev/null
+++ b/libshouldbeinlibc/portxlate.h
@@ -0,0 +1,67 @@
+/* Translate mach port names between two tasks
+
+ Copyright (C) 1996 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 __PORTXLATE_H__
+#define __PORTXLATE_H__
+
+#include <errno.h>
+#include <mach.h>
+
+/* A data structure specifying two tasks, and info used to translate port
+ names between them. */
+struct port_name_xlator
+{
+ /* The tasks between which we are translating port names. */
+ mach_port_t from_task;
+ mach_port_t to_task;
+
+ /* True if we're translating receive rights in FROM_TASK; otherwise, we're
+ translating send rights. */
+ int from_is_receive;
+
+ /* Arrays of port names and type masks from TO_TASK, fetched by
+ mach_port_names. These are vm_allocated. */
+ mach_port_t *to_names;
+ mach_msg_type_number_t to_names_len;
+ mach_port_type_t *to_types;
+ mach_msg_type_number_t to_types_len;
+
+ /* An array of rights in the current task to the ports in TO_NAMES/TO_TASK,
+ or MACH_PORT_NULL, indicating that none has been fetched yet.
+ This vector is malloced. */
+ mach_port_t *ports;
+};
+
+/* Return a new port name translator translating names between FROM_TASK and
+ TO_TASK, in XLATOR, or an error. */
+error_t port_name_xlator_create (mach_port_t from_task, mach_port_t to_task,
+ struct port_name_xlator **xlator);
+
+/* Free the port name translator X and any resources it holds. */
+void port_name_xlator_free (struct port_name_xlator *x);
+
+/* Translate the port FROM between the tasks in X, returning the translated
+ name in TO, and the types of TO in TO_TYPE, or an error. If TYPE is
+ non-zero, it should be what mach_port_type returns for FROM. */
+error_t port_name_xlator_xlate (struct port_name_xlator *x,
+ mach_port_t from, mach_port_type_t from_type,
+ mach_port_t *to, mach_port_type_t *to_type);
+
+#endif /* __PORTXLATE_H__ */
diff --git a/libshouldbeinlibc/shared-dom.c b/libshouldbeinlibc/shared-dom.c
new file mode 100644
index 00000000..0115fced
--- /dev/null
+++ b/libshouldbeinlibc/shared-dom.c
@@ -0,0 +1,54 @@
+/* Deduce the shared portion of two hostnames
+
+ Copyright (C) 1996 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 <string.h>
+
+/* Returns a pointer into HOST1 that is the part of the domain shared with
+ HOST2. If the two do not share anything, the return value will point to
+ the end of HOST1. If either host is NULL, NULL is returned. */
+char *
+shared_domain (char *host1, char *host2)
+{
+ char *shared, *e1, *e2;
+
+ if (!host1 || !host2)
+ return 0;
+
+ /* Now compare HOST1 and HOST2 from the end. */
+ e2 = host2 + strlen (host2);
+ e1 = host1 + strlen (host1);
+ shared = e1;
+
+ /* Ignore `absolute' syntax. */
+ if (*e1 == '.')
+ e1--;
+ if (*e2 == '.')
+ e2--;
+
+ while (e1 > host1 && e2 > host2 && *e2 == *e1)
+ {
+ if (*e1 == '.')
+ shared = e1; /* A common domain level has been passed. */
+ e1--;
+ e2--;
+ }
+
+ return shared;
+}
diff --git a/libshouldbeinlibc/termsize.c b/libshouldbeinlibc/termsize.c
new file mode 100644
index 00000000..46666975
--- /dev/null
+++ b/libshouldbeinlibc/termsize.c
@@ -0,0 +1,54 @@
+/* Function to try and deduce what size the terminal is
+
+ Copyright (C) 1995 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 <sys/ioctl.h>
+
+/* Returns what we think is the size of the terminal attached to
+ file descriptor FD, of type TYPE, in WIDTH and/or HEIGHT. If FD is
+ negative, the terminal isn't queried, and if TYPE is NULL, it isn't used.
+ Both WIDTH and HEIGHT may be NULL if only partial information is needed.
+ True is returned upon success. Even if false is returned, both output
+ values are still written, with 0 for unknown, in case partial information
+ is useful. */
+int
+deduce_term_size (int fd, char *type, int *width, int *height)
+{
+ int w = 0, h = 0;
+ struct winsize ws;
+
+ if (fd >= 0 && ioctl (fd, TIOCGWINSZ, &ws) == 0)
+ /* Look at the actual terminal. */
+ {
+ w = ws.ws_col;
+ h = ws.ws_row;
+ }
+ if (((width && !w) || (height && !h)) && type)
+ /* Try the terminal type. */
+ {
+ /* XXX */
+ }
+
+ if (width)
+ *width = w;
+ if (height)
+ *height = h;
+
+ return (!width || w) && (!height && h);
+}
diff --git a/libshouldbeinlibc/timefmt.c b/libshouldbeinlibc/timefmt.c
new file mode 100644
index 00000000..a28f58bd
--- /dev/null
+++ b/libshouldbeinlibc/timefmt.c
@@ -0,0 +1,359 @@
+/* Routines for formatting time
+
+ Copyright (C) 1995, 1996 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 <string.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "timefmt.h"
+
+#define SECOND 1
+#define MINUTE 60
+#define HOUR (60*MINUTE)
+#define DAY (24*HOUR)
+#define WEEK (7*DAY)
+#define MONTH (31*DAY) /* Not strictly accurate, but oh well. */
+#define YEAR (365*DAY) /* ditto */
+
+/* Returns the number of digits in the integer N. */
+static unsigned
+int_len (unsigned n)
+{
+ unsigned len = 1;
+ while (n >= 10)
+ {
+ n /= 10;
+ len++;
+ }
+ return len;
+}
+
+/* Returns TV1 divided by TV2. */
+static unsigned
+tv_div (struct timeval *tv1, struct timeval *tv2)
+{
+ return
+ tv2->tv_sec
+ ? tv1->tv_sec / tv2->tv_sec
+ : (tv1->tv_usec / tv2->tv_usec
+ + (tv1->tv_sec ? tv1->tv_sec * 1000000 / tv2->tv_usec : 0));
+}
+
+/* Returns true if TV is zero. */
+static inline int
+tv_is_zero (struct timeval *tv)
+{
+ return tv->tv_sec == 0 && tv->tv_usec == 0;
+}
+
+/* Returns true if TV1 >= TV2. */
+static inline int
+tv_is_ge (struct timeval *tv1, struct timeval *tv2)
+{
+ return
+ tv1->tv_sec > tv2->tv_sec
+ || (tv1->tv_sec == tv2->tv_sec && tv1->tv_usec >= tv2->tv_usec);
+}
+
+/* Format into BUF & BUF_LEN the time interval represented by TV, trying to
+ make the result less than WIDTH characters wide. The number of characters
+ used is returned. */
+size_t
+fmt_named_interval (struct timeval *tv, size_t width,
+ char *buf, size_t buf_len)
+{
+ struct tscale
+ {
+ struct timeval thresh; /* Minimum time to use this scale. */
+ struct timeval unit; /* Unit this scale is based on. */
+ struct timeval frac_thresh; /* If a emitting a single digit of precision
+ will cause at least this much error, also
+ emit a single fraction digit. */
+ char *sfxs[5]; /* Names to use, in descending length. */
+ }
+ time_scales[] =
+ {
+ {{2*YEAR, 0}, {YEAR, 0}, {MONTH, 0},{" years", "years", "yrs", "y", 0 }},
+ {{3*MONTH, 0}, {MONTH, 0}, {WEEK, 0}, {" months","months","mo", 0 }},
+ {{2*WEEK, 0}, {WEEK, 0}, {DAY, 0}, {" weeks", "weeks", "wks", "w", 0 }},
+ {{2*DAY, 0}, {DAY, 0}, {HOUR, 0}, {" days", "days", "dys", "d", 0 }},
+ {{2*HOUR, 0}, {HOUR, 0}, {MINUTE, 0},{" hours","hours", "hrs", "h", 0 }},
+ {{2*MINUTE, 0},{MINUTE, 0},{1, 0}, {" minutes","min", "mi", "m", 0 }},
+ {{1, 100000}, {1, 0}, {0, 100000},{" seconds", "sec", "s", 0 }},
+ {{1, 0}, {1, 0}, {0, 0}, {" second", "sec", "s", 0 }},
+ {{0, 1100}, {0, 1000}, {0, 100}, {" milliseconds", "ms", 0 }},
+ {{0, 1000}, {0, 1000}, {0, 0}, {" millisecond", "ms", 0 }},
+ {{0, 2}, {0, 1}, {0, 0}, {" microseconds", "us", 0 }},
+ {{0, 1}, {0, 1}, {0, 0}, {" microsecond", "us", 0 }},
+ {{0, 0} }
+ };
+ struct tscale *ts = time_scales;
+
+ if (width <= 0 || width >= buf_len)
+ width = buf_len - 1;
+
+ for (ts = time_scales; !tv_is_zero (&ts->thresh); ts++)
+ if (tv_is_ge (tv, &ts->thresh))
+ {
+ char **sfx;
+ struct timeval *u = &ts->unit;
+ unsigned num = tv_div (tv, u);
+ unsigned frac = 0;
+ unsigned num_len = int_len (num);
+
+ if (num < 10
+ && !tv_is_zero (&ts->frac_thresh)
+ && tv_is_ge (tv, &ts->frac_thresh))
+ /* Calculate another place of prec, but only for low numbers. */
+ {
+ /* TV times 10. */
+ struct timeval tv10 =
+ { tv->tv_sec * 10 + tv->tv_usec / 100000,
+ (tv->tv_usec % 100000) * 10 };
+ frac = tv_div (&tv10, u) - num * 10;
+ if (frac)
+ num_len += 2; /* Account for the extra `.' + DIGIT. */
+ }
+
+ /* While we have a choice, find a suffix that fits in WIDTH. */
+ for (sfx = ts->sfxs; sfx[1]; sfx++)
+ if (num_len + strlen (*sfx) <= width)
+ break;
+
+ if (!sfx[1] && frac)
+ /* We couldn't find a suffix that fits, and we're printing a
+ fraction digit. Sacrifice the fraction to make it fit. */
+ {
+ num_len -= 2;
+ frac = 0;
+ for (sfx = ts->sfxs; sfx[1]; sfx++)
+ if (num_len + strlen (*sfx) <= width)
+ break;
+ }
+
+ if (!sfx[1])
+ /* Still couldn't find a suffix that fits. Oh well, use the best. */
+ sfx--;
+
+ if (frac)
+ return snprintf (buf, buf_len, "%d.%d%s", num, frac, *sfx);
+ else
+ return snprintf (buf, buf_len, "%d%s", num, *sfx);
+ }
+
+ return sprintf (buf, "0"); /* Whatever */
+}
+
+/* Prints the number of units of size UNIT in *SECS, subtracting them from
+ *SECS, to BUF (the result *must* fit!), followed by SUFFIX; if the number
+ of units is zero, however, and *LEADING_ZEROS is false, print nothing (and
+ if something *is* printed, set *LEADING_ZEROS to true). MIN_WIDTH is the
+ minimum *total width* (including other fields) needed to print these
+ units. WIDTH is the amount of (total) space available. The number of
+ characters printed is returned. */
+static size_t
+add_field (int *secs, int unit, int *leading_zeros,
+ size_t min_width, char *suffix,
+ size_t width, char *buf)
+{
+ int units = *secs / unit;
+ if (units || (width >= min_width && *leading_zeros))
+ {
+ *secs -= units * unit;
+ *leading_zeros = 1;
+ return
+ sprintf (buf,
+ (width == min_width ? "%d%s"
+ : width == min_width + 1 ? "%2d%s"
+ : "%02d%s"),
+ units, suffix);
+ }
+ else
+ return 0;
+}
+
+/* Format into BUF & BUF_LEN the time interval represented by TV, using
+ HH:MM:SS notation where possible, with FRAC_PLACES digits after the
+ decimal point, and trying to make the result less than WIDTH characters
+ wide. If LEADING_ZEROS is true, then any fields that are zero-valued, but
+ would fit in the given width are printed. If FRAC_PLACES is negative,
+ then any space remaining after printing the time, up to WIDTH, is used for
+ the fraction. The number of characters used is returned. */
+size_t
+fmt_seconds (struct timeval *tv, int leading_zeros, int frac_places,
+ size_t width, char *buf, size_t buf_len)
+{
+ char *p = buf;
+ int secs = tv->tv_sec;
+
+ if (width <= 0 || width >= buf_len)
+ width = buf_len - 1;
+
+ if (tv->tv_sec > DAY)
+ return fmt_named_interval (tv, width, buf, buf_len);
+
+ if (frac_places > 0)
+ width -= frac_places + 1;
+
+ /* See if this time won't fit at all in fixed format. */
+ if ((secs > 10*HOUR && width < 8)
+ || (secs > HOUR && width < 7)
+ || (secs > 10*MINUTE && width < 5)
+ || (secs > MINUTE && width < 4)
+ || (secs > 10 && width < 2)
+ || width < 1)
+ return fmt_named_interval (tv, width, buf, buf_len);
+
+ p += add_field (&secs, HOUR, &leading_zeros, 7, ":", width, p);
+ p += add_field (&secs, MINUTE, &leading_zeros, 4, ":", width, p);
+ p += add_field (&secs, SECOND, &leading_zeros, 1, "", width, p);
+
+ if (frac_places < 0 && (p - buf) < (int) width - 2)
+ /* If FRAC_PLACES is < 0, then use any space remaining before WIDTH. */
+ frac_places = width - (p - buf) - 1;
+
+ if (frac_places > 0)
+ /* Print fractions of a second. */
+ {
+ int frac = tv->tv_usec, i;
+ for (i = 6; i > frac_places; i--)
+ frac /= 10;
+ return (p - buf) + sprintf (p, ".%0*d", frac_places, frac);
+ }
+ else
+ return (p - buf);
+}
+
+/* Format into BUF & BUF_LEN the time interval represented by TV, using HH:MM
+ notation where possible, and trying to make the result less than WIDTH
+ characters wide. If LEADING_ZEROS is true, then any fields that are
+ zero-valued, but would fit in the given width are printed. The number of
+ characters used is returned. */
+size_t
+fmt_minutes (struct timeval *tv, int leading_zeros,
+ size_t width, char *buf, size_t buf_len)
+{
+ char *p = buf;
+ int secs = tv->tv_sec;
+
+ if (width <= 0 || width >= buf_len)
+ width = buf_len - 1;
+
+ if (secs > DAY)
+ return fmt_named_interval (tv, width, buf, buf_len);
+
+ /* See if this time won't fit at all in fixed format. */
+ if ((secs > 10*HOUR && width < 5)
+ || (secs > HOUR && width < 4)
+ || (secs > 10*MINUTE && width < 2)
+ || width < 1)
+ return fmt_named_interval (tv, width, buf, buf_len);
+
+ p += add_field (&secs, HOUR, &leading_zeros, 4, ":", width, p);
+ p += add_field (&secs, MINUTE, &leading_zeros, 1, "", width, p);
+
+ return p - buf;
+}
+
+/* Format into BUF & BUF_LEN the absolute time represented by TV. An attempt
+ is made to fit the result in less than WIDTH characters, by omitting
+ fields implied by the current time, NOW (if NOW is 0, then no assumption
+ is made, so the resulting times will be somewhat long). The number of
+ characters used is returned. */
+size_t
+fmt_past_time (struct timeval *tv, struct timeval *now,
+ size_t width, char *buf, size_t buf_len)
+{
+ static char *time_fmts[] = { "%-r", "%-l:%M%p", "%-l%p", 0 };
+ static char *week_fmts[] = { "%A", "%a", 0 };
+ static char *month_fmts[] = { "%A %-d", "%a %-d", "%a%-d", 0 };
+ static char *date_fmts[] =
+ { "%A, %-d %B", "%a, %-d %b", "%-d %B", "%-d %b", "%-d%b", 0 };
+ static char *year_fmts[] =
+ { "%A, %-d %B %Y", "%a, %-d %b %Y", "%a, %-d %b %y", "%-d %b %y", "%-d%b%y", 0 };
+ struct tm tm;
+ int used = 0; /* Number of characters generated. */
+ long diff = now ? (now->tv_sec - tv->tv_sec) : tv->tv_sec;
+
+ if (diff < 0)
+ diff = -diff; /* XXX */
+
+ bcopy (localtime ((time_t *) &tv->tv_sec), &tm, sizeof tm);
+
+ if (width <= 0 || width >= buf_len)
+ width = buf_len - 1;
+
+ if (diff < DAY)
+ {
+ char **fmt;
+ for (fmt = time_fmts; *fmt && !used; fmt++)
+ used = strftime (buf, width + 1, *fmt, &tm);
+ if (! used)
+ /* Nothing worked, perhaps WIDTH is too small, but BUF_LEN will work.
+ We know FMT is one past the end the array, so FMT[-1] should be
+ the shortest possible option. */
+ used = strftime (buf, buf_len, fmt[-1], &tm);
+ }
+ else
+ {
+ static char *seps[] = { ", ", " ", "", 0 };
+ char **fmt, **dfmt, **dfmts, **sep;
+
+ if (diff < WEEK)
+ dfmts = week_fmts;
+ else if (diff < MONTH)
+ dfmts = month_fmts;
+ else if (diff < YEAR)
+ dfmts = date_fmts;
+ else
+ dfmts = year_fmts;
+
+ /* This ordering (date varying most quickly, then the separator, then
+ the time) preserves time detail as long as possible, and seems to
+ produce a graceful degradation of the result with decreasing widths. */
+ for (fmt = time_fmts; *fmt && !used; fmt++)
+ for (sep = seps; *sep && !used; sep++)
+ for (dfmt = dfmts; *dfmt && !used; dfmt++)
+ {
+ char whole_fmt[strlen (*dfmt) + strlen (*sep) + strlen (*fmt) + 1];
+ char *end = whole_fmt;
+
+ end = stpcpy (end, *dfmt);
+ end = stpcpy (end, *sep);
+ stpcpy (end, *fmt);
+
+ used = strftime (buf, width + 1, whole_fmt, &tm);
+ }
+
+ if (! used)
+ /* No concatenated formats worked, try just date formats. */
+ for (dfmt = dfmts; *dfmt && !used; dfmt++)
+ used = strftime (buf, width + 1, *dfmt, &tm);
+
+ if (! used)
+ /* Absolutely nothing has worked, perhaps WIDTH is too small, but
+ BUF_LEN will work. We know DFMT is one past the end the array, so
+ DFMT[-1] should be the shortest possible option. */
+ used = strftime (buf, buf_len, dfmt[-1], &tm);
+ }
+
+ return used;
+}
diff --git a/libshouldbeinlibc/timefmt.h b/libshouldbeinlibc/timefmt.h
new file mode 100644
index 00000000..134cf56a
--- /dev/null
+++ b/libshouldbeinlibc/timefmt.h
@@ -0,0 +1,58 @@
+/* Routines for formatting time
+
+ Copyright (C) 1995, 1996 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 __TIMEFMT_H__
+#define __TIMEFMT_H__
+
+struct timeval;
+
+/* Format into BUF & BUF_LEN the time interval represented by TV, trying to
+ make the result less than WIDTH characters wide. The number of characters
+ used is returned. */
+size_t fmt_named_interval (struct timeval *tv, size_t width,
+ char *buf, size_t buf_len);
+
+/* Format into BUF & BUF_LEN the time interval represented by TV, using
+ HH:MM:SS notation where possible, with FRAC_PLACES digits after the
+ decimal point, and trying to make the result less than WIDTH characters
+ wide. If LEADING_ZEROS is true, then any fields that are zero-valued, but
+ would fit in the given width are printed. If FRAC_PLACES is negative,
+ then any space remaining after printing the time, up to WIDTH, is used for
+ the fraction. The number of characters used is returned. */
+size_t fmt_seconds (struct timeval *tv, int leading_zeros, int frac_places,
+ size_t width, char *buf, size_t buf_len);
+
+/* Format into BUF & BUF_LEN the time interval represented by TV, using HH:MM
+ notation where possible, and trying to make the result less than WIDTH
+ characters wide. If LEADING_ZEROS is true, then any fields that are
+ zero-valued, but would fit in the given width are printed. The number of
+ characters used is returned. */
+size_t fmt_minutes (struct timeval *tv, int leading_zeros,
+ size_t width, char *buf, size_t buf_len);
+
+/* Format into BUF & BUF_LEN the absolute time represented by TV. An attempt
+ is made to fit the result in less than WIDTH characters, by omitting
+ fields implied by the current time, NOW (if NOW is 0, then no assumptions
+ are made, so the resulting times will be somewhat long). The number of
+ characters used is returned. */
+size_t fmt_past_time (struct timeval *tv, struct timeval *now,
+ size_t width, char *buf, size_t buf_len);
+
+#endif /* __TIMEFMT_H__ */
diff --git a/libshouldbeinlibc/ugids-argp.c b/libshouldbeinlibc/ugids-argp.c
new file mode 100644
index 00000000..43a54d70
--- /dev/null
+++ b/libshouldbeinlibc/ugids-argp.c
@@ -0,0 +1,174 @@
+/* Parse user and group ids
+
+ Copyright (C) 1997, 1999, 2008 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 <string.h>
+#include <ctype.h>
+#include <argp.h>
+#include <pwd.h>
+#include <grp.h>
+#include <errno.h>
+
+#include "ugids.h"
+
+#define OA OPTION_ARG_OPTIONAL
+
+static const struct argp_option options[] =
+{
+ {"user", 'u', "USER", 0, "Add USER to the effective uids"},
+ {"avail-user",'U', "USER", 0, "Add USER to the available uids"},
+ {"group", 'g', "GROUP", 0, "Add GROUP to the effective groups"},
+ {"avail-group",'G',"GROUP", 0, "Add GROUP to the available groups"},
+ { 0 }
+};
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ char id_lookup_buf[1024];
+ struct ugids_argp_params *params = state->input;
+ struct ugids *ugids = params->ugids;
+
+ switch (key)
+ {
+ uid_t uid;
+
+ case 'u':
+ case 'U':
+ case ARGP_KEY_ARG:
+ case ARGP_KEY_END:
+ if (key == ARGP_KEY_ARG && !params->parse_user_args)
+ /* Let someone else parse this argument. */
+ return ARGP_ERR_UNKNOWN;
+
+ if (key == ARGP_KEY_END)
+ {
+ if (ugids_is_empty (ugids))
+ {
+ if (params->default_user >= 0)
+ uid = params->default_user;
+ else if (params->require_ids)
+ {
+ argp_error (state, "No ids specified");
+ return EINVAL;
+ }
+ else
+ break;
+ }
+ else
+ break;
+ }
+ else if (isdigit (*arg))
+ uid = atoi (arg);
+ else if (strcmp (arg, "-") == 0)
+ break;
+ else
+ {
+ struct passwd _pw, *pw;
+ int err;
+ err = getpwnam_r (arg, &_pw, id_lookup_buf,
+ sizeof id_lookup_buf, &pw);
+ if (err == 0)
+ {
+ if (pw == NULL)
+ {
+ argp_failure (state, 10, 0, "%s: Unknown user", arg);
+ return EINVAL;
+ }
+
+ uid = pw->pw_uid;
+ }
+ else
+ {
+ argp_failure (state, 12, err,
+ "Could not get uid for user: %s", arg);
+ return err;
+ }
+ }
+
+ if (key == ARGP_KEY_ARG || key == ARGP_KEY_END)
+ {
+ /* A user arg, which means add the user, and any appropriate
+ groups. */
+ if (!params->user_args_are_effective
+ && !params->user_args_are_available)
+ return ugids_set_posix_user (ugids, uid);
+ else
+ {
+ error_t err = 0;
+ if (params->user_args_are_effective)
+ err = ugids_add_user (ugids, uid, 0);
+ if (!err && params->user_args_are_available)
+ err = ugids_add_user (ugids, uid, 1);
+ return err;
+ }
+ }
+ else
+ /* Add an individual specific effective/auxiliary uid. */
+ return ugids_add_uid (ugids, uid, key == 'U');
+
+ case 'g':
+ case 'G':
+ if (isdigit (*arg))
+ return ugids_add_gid (ugids, atoi (arg), key == 'G');
+ else
+ {
+ struct group _gr, *gr;
+ int err = getgrnam_r (arg, &_gr, id_lookup_buf,
+ sizeof id_lookup_buf, &gr);
+ if (err == 0)
+ {
+ if (gr == NULL)
+ {
+ argp_failure (state, 11, 0, "%s: Unknown group", arg);
+ return EINVAL;
+ }
+
+ return ugids_add_gid (ugids, gr->gr_gid, key == 'G');
+ }
+ else
+ {
+ argp_failure (state, 13, err,
+ "Could not get gid for group: %s", arg);
+ return err;
+ }
+ }
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+/* Filtering of help output strings for UGIDS_ARGP. */
+static char *
+help_filter (int key, const char *text, void *input)
+{
+ struct ugids_argp_params *params = input;
+
+ /* Describe the optional behavior of parsing normal args as ugids. */
+ if (key == ARGP_KEY_HELP_ARGS_DOC && params->parse_user_args)
+ return strdup ("[USER...]");
+
+ return (char *)text;
+}
+
+/* A parser for selecting a set of ugids. */
+struct argp ugids_argp = { options, parse_opt, 0, 0, 0, help_filter };
diff --git a/libshouldbeinlibc/ugids-auth.c b/libshouldbeinlibc/ugids-auth.c
new file mode 100644
index 00000000..0e4f84dc
--- /dev/null
+++ b/libshouldbeinlibc/ugids-auth.c
@@ -0,0 +1,53 @@
+/* Translate user and group ids to/from auth ports
+
+ 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 <hurd.h>
+
+#include "idvec.h"
+#include "ugids.h"
+
+/* Make an auth port from UGIDS and return it in AUTH, using authority in
+ both the auth port FROM and the current auth port. */
+error_t
+ugids_make_auth (const struct ugids *ugids,
+ const auth_t *from, size_t num_from,
+ auth_t *auth)
+{
+ auth_t cur_auth = getauth ();
+ error_t err =
+ auth_makeauth (cur_auth, (auth_t *)from, MACH_MSG_TYPE_COPY_SEND, num_from,
+ ugids->eff_uids.ids, ugids->eff_uids.num,
+ ugids->avail_uids.ids, ugids->avail_uids.num,
+ ugids->eff_gids.ids, ugids->eff_gids.num,
+ ugids->avail_gids.ids, ugids->avail_gids.num,
+ auth);
+ mach_port_deallocate (mach_task_self (), cur_auth);
+ return err;
+}
+
+/* Merge the ids from the auth port AUTH into UGIDS. */
+error_t
+ugids_merge_auth (struct ugids *ugids, auth_t auth)
+{
+ return
+ idvec_merge_auth (&ugids->eff_uids, &ugids->avail_uids,
+ &ugids->eff_gids, &ugids->avail_gids,
+ auth);
+}
diff --git a/libshouldbeinlibc/ugids-imply.c b/libshouldbeinlibc/ugids-imply.c
new file mode 100644
index 00000000..272ba664
--- /dev/null
+++ b/libshouldbeinlibc/ugids-imply.c
@@ -0,0 +1,36 @@
+/* Calculate implied group ids from user ids
+
+ 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 <errno.h>
+
+#include "idvec.h"
+#include "ugids.h"
+
+/* Mark as implied all gids in UGIDS that can be implied from its uids. */
+error_t
+ugids_imply_all (struct ugids *ugids)
+{
+ error_t err;
+ err = idvec_merge_implied_gids (&ugids->imp_eff_gids, &ugids->eff_uids);
+ if (! err)
+ err =
+ idvec_merge_implied_gids (&ugids->imp_avail_gids, &ugids->avail_uids);
+ return err;
+}
diff --git a/libshouldbeinlibc/ugids-merge.c b/libshouldbeinlibc/ugids-merge.c
new file mode 100644
index 00000000..f97da07c
--- /dev/null
+++ b/libshouldbeinlibc/ugids-merge.c
@@ -0,0 +1,110 @@
+/* Merging of ugids
+
+ 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 <errno.h>
+
+#include "idvec.h"
+#include "ugids.h"
+
+static error_t
+_merge_gids (struct idvec *gids, struct idvec *gids_imp,
+ const struct idvec *new, const struct idvec *new_imp)
+{
+ error_t err;
+ /* Gids that exist in both GIDS and NEW can only be implied in the result
+ if they are implied in both; here GIDS_STRONG and NEW_STRONG contain
+ those gids which shouldn't be implied in the result because they are not
+ in either of the sources. */
+ struct idvec gids_strong = IDVEC_INIT;
+ struct idvec new_strong = IDVEC_INIT;
+
+ err = idvec_set (&gids_strong, gids);
+ if (! err)
+ err = idvec_set (&new_strong, new);
+ if (! err)
+ {
+ idvec_subtract (&gids_strong, gids_imp);
+ idvec_subtract (&new_strong, new_imp);
+
+ err = idvec_merge (gids, new);
+ if (! err)
+ {
+ err = idvec_merge (gids_imp, new_imp);
+ if (! err)
+ {
+ idvec_subtract (gids_imp, &gids_strong);
+ idvec_subtract (gids_imp, &new_strong);
+ }
+ }
+ }
+
+ idvec_fini (&gids_strong);
+ idvec_fini (&new_strong);
+
+ return err;
+}
+
+/* Add all ids in NEW to UGIDS. */
+error_t
+ugids_merge (struct ugids *ugids, const struct ugids *new)
+{
+ error_t err;
+ err = idvec_merge (&ugids->eff_uids, &new->eff_uids);
+ if (! err)
+ err = idvec_merge (&ugids->avail_uids, &new->avail_uids);
+ if (! err)
+ err = _merge_gids (&ugids->eff_gids, &ugids->imp_eff_gids,
+ &new->eff_gids, &new->imp_eff_gids);
+ if (! err)
+ err = _merge_gids (&ugids->avail_gids, &ugids->imp_avail_gids,
+ &new->avail_gids, &new->imp_avail_gids);
+ return err;
+}
+
+/* Set the ids in UGIDS to those in NEW. */
+error_t
+ugids_set (struct ugids *ugids, const struct ugids *new)
+{
+ idvec_clear (&ugids->eff_uids);
+ idvec_clear (&ugids->eff_gids);
+ idvec_clear (&ugids->avail_uids);
+ idvec_clear (&ugids->avail_gids);
+ idvec_clear (&ugids->imp_eff_gids);
+ idvec_clear (&ugids->imp_avail_gids);
+ return ugids_merge (ugids, new);
+}
+
+/* Save any effective ids in UGIDS by merging them into the available ids,
+ and removing them from the effective ones. */
+error_t
+ugids_save (struct ugids *ugids)
+{
+ error_t err = idvec_merge (&ugids->avail_uids, &ugids->eff_uids);
+ if (! err)
+ err = _merge_gids (&ugids->avail_gids, &ugids->imp_avail_gids,
+ &ugids->eff_gids, &ugids->imp_eff_gids);
+ if (! err)
+ {
+ idvec_clear (&ugids->eff_uids);
+ idvec_clear (&ugids->eff_gids);
+ idvec_clear (&ugids->imp_eff_gids);
+ }
+ return err;
+}
diff --git a/libshouldbeinlibc/ugids-posix.c b/libshouldbeinlibc/ugids-posix.c
new file mode 100644
index 00000000..35d73e32
--- /dev/null
+++ b/libshouldbeinlibc/ugids-posix.c
@@ -0,0 +1,95 @@
+/* Set posix-compatible ugids
+
+ 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 "ugids.h"
+
+/* Install UID into UGIDS as the main user, making sure that the posix
+ `real' and `saved' uid slots are filled in, and similarly add all
+ groups to which UID belongs. */
+error_t
+ugids_set_posix_user (struct ugids *ugids, uid_t uid)
+{
+ error_t err;
+ struct idvec imp_gids = IDVEC_INIT;
+ uid_t uids_ids[] = { uid };
+ struct idvec uids = { uids_ids, 1 };
+
+ error_t update_real (struct idvec *avail_ids, uid_t id)
+ {
+ if (avail_ids->num == 0
+ || !idvec_tail_contains (avail_ids, 1, avail_ids->ids[0]))
+ return idvec_insert (avail_ids, 0, id);
+ else
+ avail_ids->ids[0] = id;
+ return 0;
+ }
+
+ idvec_merge_implied_gids (&imp_gids, &uids);
+
+ /* Try to add UID. */
+ err = idvec_insert_only (&ugids->eff_uids, 0, uid); /* Effective */
+ if (! err)
+ err = update_real (&ugids->avail_uids, uid); /* Real */
+ if (! err)
+ err = idvec_insert_only (&ugids->avail_uids, 1, uid); /* Saved */
+
+ if (!err && imp_gids.num > 0)
+ /* Now do the gids. */
+ {
+ /* The main gid associated with UID (usually from /etc/passwd). */
+ gid_t gid = imp_gids.ids[0];
+ /* True if GID was already an available gid. */
+ int gid_was_avail = idvec_contains (&ugids->avail_gids, gid);
+
+ /* Update the implied sets for the gids: they're implied unless
+ they were present as non-implied gids before. Here we
+ remove existing effective gids from the IMP_GIDS before we
+ added it to the implied sets -- if some of those gids were
+ actually implied, they'll already be present in the implied
+ set. */
+ idvec_subtract (&imp_gids, &ugids->eff_gids);
+
+ /* Now add GID, as effective, real, and saved gids. */
+ if (! err) /* Effective */
+ err = idvec_insert_only (&ugids->eff_gids, 0, gid);
+ if (! err) /* Real */
+ err = update_real (&ugids->avail_gids, gid);
+ if (! err) /* Saved */
+ err = idvec_insert_only (&ugids->avail_gids, 1, gid);
+
+ /* Mark GID as implied in the available gids unless it was already
+ present (in which case its implied status is already settled). */
+ if (!err && !gid_was_avail)
+ err = idvec_add (&ugids->imp_avail_gids, gid);
+
+ /* Add the other implied gids to the end of the effective gids. */
+ if (! err)
+ err = idvec_merge (&ugids->eff_gids, &imp_gids);
+ /* And make them implied. */
+ if (! err)
+ err = idvec_merge (&ugids->imp_eff_gids, &imp_gids);
+ }
+
+ idvec_fini (&imp_gids);
+
+ return err;
+}
diff --git a/libshouldbeinlibc/ugids-rep.c b/libshouldbeinlibc/ugids-rep.c
new file mode 100644
index 00000000..3e6e59d5
--- /dev/null
+++ b/libshouldbeinlibc/ugids-rep.c
@@ -0,0 +1,118 @@
+/* String representation of ugids
+
+ 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 <string.h>
+
+#include "ugids.h"
+
+/* Return a string representation of the ids in UGIDS. SHOW_VALUES and
+ SHOW_NAMES reflect how each id is printed (if SHOW_NAMES is true values
+ are used where names aren't available); if both are true, the
+ `VALUE(NAME)' format is used. ID_SEP, TYPE_SEP, and HDR_SEP contain the
+ strings that separate, respectively, multiple ids of a particular type
+ (default ","), the various types of ids (default ", "), and the name of
+ each type from its ids (default ": "). The empty string is returned for
+ an empty list, and 0 for an allocation error. */
+char *
+ugids_rep (const struct ugids *ugids, int show_values, int show_names,
+ const char *id_sep, const char *type_sep, const char *hdr_sep)
+{
+ size_t type_sep_len, hdr_sep_len;
+ int first = 1;
+ char *rep = 0; /* Result */
+ size_t len = 0; /* Total length of result. */
+ char *euid_rep = 0, *egid_rep = 0, *auid_rep = 0, *agid_rep = 0;
+
+ /* Calculate the rep for NAME, with ids IDS, returning the rep for the ids
+ in REP, and updates LEN to include everything needed by this type (the
+ length of *REP *plus* the length of NAME and any separators). True is
+ returned unless an allocation error occurs. */
+ int type_rep (const char *name, const struct idvec *ids, int is_group,
+ char **rep)
+ {
+ if (ids->num > 0)
+ {
+ if (first)
+ first = 0;
+ else
+ len += type_sep_len;
+ len += strlen (name);
+ len += hdr_sep_len;
+ *rep =
+ (is_group ? idvec_gids_rep : idvec_uids_rep)
+ (ids, show_values, show_names, id_sep);
+ if (*rep)
+ len += strlen (*rep);
+ else
+ return 0;
+ }
+ return 1;
+ }
+ void add_type_rep (char **to, const char *name, const char *rep)
+ {
+ if (rep)
+ {
+ if (first)
+ first = 0;
+ else
+ *to = stpcpy (*to, type_sep);
+ *to = stpcpy (*to, name);
+ *to = stpcpy (*to, hdr_sep);
+ *to = stpcpy (*to, rep);
+ }
+ }
+
+ if (! type_sep)
+ type_sep = ", ";
+ if (! hdr_sep)
+ hdr_sep = ": ";
+
+ type_sep_len = strlen (type_sep);
+ hdr_sep_len = strlen (hdr_sep);
+
+ if (type_rep ("euids", &ugids->eff_uids, 0, &euid_rep)
+ && type_rep ("egids", &ugids->eff_gids, 1, &egid_rep)
+ && type_rep ("auids", &ugids->avail_uids, 0, &auid_rep)
+ && type_rep ("agids", &ugids->avail_gids, 1, &agid_rep))
+ {
+ char *p = malloc (len + 1);
+ if (p)
+ {
+ rep = p;
+ first = 1;
+ add_type_rep (&p, "euids", euid_rep);
+ add_type_rep (&p, "egids", egid_rep);
+ add_type_rep (&p, "auids", auid_rep);
+ add_type_rep (&p, "agids", agid_rep);
+ }
+ }
+
+ if (euid_rep)
+ free (euid_rep);
+ if (egid_rep)
+ free (egid_rep);
+ if (auid_rep)
+ free (auid_rep);
+ if (agid_rep)
+ free (agid_rep);
+
+ return rep;
+}
diff --git a/libshouldbeinlibc/ugids-subtract.c b/libshouldbeinlibc/ugids-subtract.c
new file mode 100644
index 00000000..b56e397b
--- /dev/null
+++ b/libshouldbeinlibc/ugids-subtract.c
@@ -0,0 +1,130 @@
+/* Subtract one set of user and group ids from another
+
+ 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 <errno.h>
+
+#include "idvec.h"
+#include "ugids.h"
+
+/* Remove the gids in SUB from those in GIDS, except where they are implied
+ in SUB (as represented by SUB_IMP), but not in GIDS (as represented by
+ GIDS_IMP). */
+static
+error_t _sub_gids (struct idvec *gids, struct idvec *gids_imp,
+ const struct idvec *sub, const struct idvec *sub_imp)
+{
+ error_t err;
+ /* What we'll remove from GIDS. */
+ struct idvec delta = IDVEC_INIT;
+ /* Those implied ids in SUB that we *won't* remove, because they're not
+ also implied in GIDS. */
+ struct idvec delta_suppress = IDVEC_INIT;
+
+ err = idvec_set (&delta, sub);
+ if (! err)
+ err = idvec_set (&delta_suppress, sub_imp);
+ if (! err)
+ {
+ /* Don't suppress those implied ids that are implied in both. */
+ idvec_subtract (&delta_suppress, gids_imp);
+ idvec_subtract (&delta, &delta_suppress);
+
+ /* Actually remove the gids. */
+ idvec_subtract (gids, &delta);
+ }
+
+ idvec_fini (&delta);
+ idvec_fini (&delta_suppress);
+
+ return err;
+}
+
+/* Remove the in SUB from those in GIDS, except where they are implied
+ in SUB (as represented by SUB_IMP), but not in GIDS (as represented by
+ GIDS_IMP). */
+static
+error_t _sub (struct idvec *uids, struct idvec *gids, struct idvec *gids_imp,
+ const struct idvec *sub_uids,
+ const struct idvec *sub_gids, const struct idvec *sub_gids_imp)
+{
+ error_t err;
+ struct idvec new_uids = IDVEC_INIT; /* The set of uids after subtraction. */
+ struct idvec no_sub_gids = IDVEC_INIT; /* Gids we *don't* want to remove
+ from GIDS, despite what's in
+ SUB_GIDS. */
+ struct idvec new_sub_gids = IDVEC_INIT;
+ struct idvec new_sub_gids_imp = IDVEC_INIT;
+
+ err = idvec_set (&new_uids, uids);
+ if (! err)
+ err = idvec_set (&new_sub_gids, sub_gids);
+ if (! err)
+ err = idvec_set (&new_sub_gids_imp, sub_gids_imp);
+ if (! err)
+ {
+ idvec_subtract (&new_uids, sub_uids);
+
+ err = idvec_merge_implied_gids (&no_sub_gids, &new_uids);
+ if (! err)
+ {
+ /* NO_SUB_GIDS is the intersection of implied gids in GIDS,
+ implied gids in SUB_GIDS, and implied gids after the subtraction
+ of uids -- we don't want to remove those implied gids because we
+ can't be sure which uids implied them (as there will be
+ appropriately implicative uids left after the subtraction). */
+ idvec_keep (&no_sub_gids, gids_imp);
+ idvec_keep (&no_sub_gids, sub_gids_imp);
+
+ /* Remove those gids we don't want to subtract. */
+ idvec_subtract (&new_sub_gids, &no_sub_gids);
+ idvec_subtract (&new_sub_gids_imp, &no_sub_gids);
+
+ /* Do the group subtraction. */
+ err = _sub_gids (gids, gids_imp, &new_sub_gids, &new_sub_gids_imp);
+ if (! err)
+ /* Finally, if no problems, do the uid subtraction. */
+ err = idvec_set (uids, &new_uids);
+ }
+ }
+
+ idvec_fini (&new_uids);
+ idvec_fini (&no_sub_gids);
+ idvec_fini (&new_sub_gids);
+ idvec_fini (&new_sub_gids_imp);
+
+ return err;
+}
+
+/* Remove the ids in SUB from those in UGIDS. */
+error_t
+ugids_subtract (struct ugids *ugids, const struct ugids *sub)
+{
+ error_t err =
+ _sub (&ugids->eff_uids, &ugids->eff_gids, &ugids->imp_eff_gids,
+ &sub->eff_uids, &sub->eff_gids, &sub->imp_eff_gids);
+
+ if (! err)
+ /* If this second call to _sub fails, ugids will be in an inconsistent
+ state, but oh well. */
+ err = _sub (&ugids->avail_uids, &ugids->avail_gids, &ugids->imp_avail_gids,
+ &sub->avail_uids, &sub->avail_gids, &sub->imp_avail_gids);
+
+ return err;
+}
diff --git a/libshouldbeinlibc/ugids-verify-auth.c b/libshouldbeinlibc/ugids-verify-auth.c
new file mode 100644
index 00000000..0e85b1b6
--- /dev/null
+++ b/libshouldbeinlibc/ugids-verify-auth.c
@@ -0,0 +1,185 @@
+/* Verify user/group passwords and authenticate accordingly
+
+ Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <stdlib.h>
+#include <hurd.h>
+
+#include <hurd/paths.h>
+#include <hurd/password.h>
+
+#include "idvec.h"
+#include "ugids.h"
+
+/* Accumulated information from authentication various passwords. */
+struct svma_state
+{
+ /* The password server. */
+ file_t server;
+
+ /* An auth port for each password that was verify by the server. */
+ auth_t *auths;
+ size_t num_auths;
+};
+
+/* Append the auth ports in AUTHS, of length NUM_AUTHS, to the auth port
+ vector in SS, returning 0 if successful, or an error. */
+static error_t
+svma_state_add_auths (struct svma_state *ss,
+ const auth_t *auths, size_t num_auths)
+{
+ auth_t *new = realloc (ss->auths,
+ (ss->num_auths + num_auths) * sizeof (auth_t));
+ if (new)
+ {
+ ss->auths = new;
+ while (num_auths--)
+ ss->auths[ss->num_auths++] = *auths++;
+ return 0;
+ }
+ else
+ return ENOMEM;
+}
+
+/* Get authentication from PASSWORD using the hurd password server. */
+static error_t
+server_verify_make_auth (const char *password,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook)
+{
+ auth_t auth;
+ struct svma_state *svma_state = hook;
+ error_t (*check) (io_t server, uid_t id, const char *passwd, auth_t *auth) =
+ is_group ? password_check_group : password_check_user;
+ error_t err = (*check) (svma_state->server, id, password, &auth);
+
+ if (! err)
+ /* PASSWORD checked out ok; the corresponding authentication is in AUTH. */
+ {
+ err = svma_state_add_auths (svma_state, &auth, 1);
+ if (err)
+ mach_port_deallocate (mach_task_self (), auth);
+ }
+
+ return err;
+}
+
+/* Verify that we have the right to the ids in UGIDS, given that we already
+ possess those in HAVE_UIDS and HAVE_GIDS (asking for passwords where
+ necessary), and return corresponding authentication in AUTH; the auth
+ ports in FROM, of length NUM_FROM, are used to supplement the auth port of
+ the current process if necessary. 0 is returned if access should be
+ allowed, otherwise EINVAL if an incorrect password was entered, or an
+ error relating to resource failure. GETPASS_FN and GETPASS_HOOK are as
+ for the idvec_verify function in <idvec.h>. */
+error_t
+ugids_verify_make_auth (const struct ugids *ugids,
+ const struct idvec *have_uids,
+ const struct idvec *have_gids,
+ char *(*getpass_fn) (const char *prompt,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *getpass_hook,
+ const auth_t *from, size_t num_from,
+ auth_t *auth)
+{
+ error_t err;
+ /* By default, get authentication from the password server. */
+ struct svma_state svma_state;
+ error_t (*verify_fn) (const char *password,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook)
+ = server_verify_make_auth;
+ void *verify_hook = &svma_state;
+
+ /* Try to open the hurd password server. */
+ svma_state.server = file_name_lookup (_SERVERS_PASSWORD, 0, 0);
+
+ if (svma_state.server == MACH_PORT_NULL)
+ /* Can't open the password server, try to use our own authority in
+ the traditional unix manner. */
+ {
+ verify_fn = 0;
+ verify_hook = 0;
+ }
+ else
+ {
+ /* Must initialize list to empty so svma_state_add_auths works. */
+ svma_state.auths = NULL;
+ svma_state.num_auths = 0;
+ }
+
+ /* Check passwords. */
+ err = ugids_verify (ugids, have_uids, have_gids,
+ getpass_fn, getpass_hook, verify_fn, verify_hook);
+
+ if (! err)
+ {
+ /* The user apparently has access to all the ids, try to grant the
+ corresponding authentication. */
+ if (verify_fn)
+ /* Merge the authentication we got from the password server into our
+ result. */
+ {
+ if (num_from > 0)
+ /* Use FROM as well as the passwords to get authentication. */
+ err = svma_state_add_auths (&svma_state, from, num_from);
+
+ if (! err)
+ {
+ auth_t cur_auth = getauth ();
+
+ err =
+ auth_makeauth (cur_auth,
+ svma_state.auths, MACH_MSG_TYPE_COPY_SEND,
+ svma_state.num_auths,
+ ugids->eff_uids.ids, ugids->eff_uids.num,
+ ugids->avail_uids.ids, ugids->avail_uids.num,
+ ugids->eff_gids.ids, ugids->eff_gids.num,
+ ugids->avail_gids.ids, ugids->avail_gids.num,
+ auth);
+ mach_port_deallocate (mach_task_self (), cur_auth);
+
+ /* Avoid deallocating FROM when we clean up SVMA_STATE. */
+ svma_state.num_auths -= num_from;
+ }
+ }
+ else
+ /* Try to authenticate the old fashioned way... */
+ err = ugids_make_auth (ugids, from, num_from, auth);
+ }
+
+ if (verify_fn)
+ /* Clean up any left over state. */
+ {
+ unsigned int i;
+
+ /* Get rid of auth ports. */
+ for (i = 0; i < svma_state.num_auths; i++)
+ mach_port_deallocate (mach_task_self (), svma_state.auths[i]);
+
+ /* Close password server. */
+ mach_port_deallocate (mach_task_self (), svma_state.server);
+
+ if (svma_state.num_auths > 0)
+ free (svma_state.auths);
+ }
+
+ return err;
+}
diff --git a/libshouldbeinlibc/ugids-verify.c b/libshouldbeinlibc/ugids-verify.c
new file mode 100644
index 00000000..5686bdf8
--- /dev/null
+++ b/libshouldbeinlibc/ugids-verify.c
@@ -0,0 +1,65 @@
+/* Verify user/group passwords
+
+ 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 <hurd.h>
+#include <argp.h>
+
+#include "idvec.h"
+#include "ugids.h"
+
+/* Verify that we have the right to the ids in UGIDS, given that we already
+ possess those in HAVE_UIDS and HAVE_GIDS, asking for passwords where
+ necessary. 0 is returned if access should be allowed, otherwise
+ EINVAL if an incorrect password was entered, or an error relating to
+ resource failure. The GETPASS_FN, GETPASS_HOOK, VERIFY_FN, and
+ VERIFY_HOOK arguments are as for the idvec_verify function (in <idvec.h>). */
+error_t
+ugids_verify (const struct ugids *ugids,
+ const struct idvec *have_uids, const struct idvec *have_gids,
+ char *(*getpass_fn) (const char *prompt,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *getpass_hook,
+ error_t (*verify_fn) (const char *password,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *verify_hook)
+{
+ error_t err;
+ struct idvec check_uids = IDVEC_INIT; /* User-ids to verify. */
+ struct idvec check_gids = IDVEC_INIT; /* group-ids to verify. */
+
+ err = idvec_merge (&check_uids, &ugids->eff_uids);
+ if (! err)
+ err = idvec_merge (&check_uids, &ugids->avail_uids);
+ if (! err)
+ err = idvec_merge (&check_gids, &ugids->eff_gids);
+ if (! err)
+ err = idvec_merge (&check_gids, &ugids->avail_gids);
+
+ if (! err)
+ err = idvec_verify (&check_uids, &check_gids, have_uids, have_gids,
+ getpass_fn, getpass_hook, verify_fn, verify_hook);
+
+ idvec_fini (&check_uids);
+ idvec_fini (&check_gids);
+
+ return err;
+}
diff --git a/libshouldbeinlibc/ugids-xinl.c b/libshouldbeinlibc/ugids-xinl.c
new file mode 100644
index 00000000..107de8b9
--- /dev/null
+++ b/libshouldbeinlibc/ugids-xinl.c
@@ -0,0 +1,23 @@
+/* Real definitions for extern inline functions in ugids.h
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#define UGIDS_DEFINE_EI
+#include "ugids.h"
diff --git a/libshouldbeinlibc/ugids.c b/libshouldbeinlibc/ugids.c
new file mode 100644
index 00000000..db1ce3c8
--- /dev/null
+++ b/libshouldbeinlibc/ugids.c
@@ -0,0 +1,98 @@
+/* Frob user and group ids
+
+ 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 <string.h>
+
+#include "idvec.h"
+#include "ugids.h"
+
+/* Return a new ugids structure, or 0 if an allocation error occurs. */
+struct ugids *
+make_ugids ()
+{
+ struct ugids *u = malloc (sizeof (struct ugids));
+ if (u)
+ bzero (u, sizeof *u);
+ return u;
+}
+
+/* Add a new uid to UGIDS. If AVAIL is true, it's added to the avail uids
+ instead of the effective ones. */
+error_t
+ugids_add_uid (struct ugids *ugids, uid_t uid, int avail)
+{
+ return idvec_add_new (avail ? &ugids->avail_uids : &ugids->eff_uids, uid);
+}
+
+/* Add a new gid to UGIDS. If AVAIL is true, it's added to the avail gids
+ instead of the effective ones. */
+error_t
+ugids_add_gid (struct ugids *ugids, gid_t gid, int avail)
+{
+ error_t err =
+ idvec_add_new (avail ? &ugids->avail_gids : &ugids->eff_gids, gid);
+ if (! err)
+ /* Since this gid is now explicit, remove it from the appropriate implied
+ set. */
+ idvec_remove (avail ? &ugids->imp_avail_gids : &ugids->imp_eff_gids,
+ 0, gid);
+ return err;
+}
+
+/* Add UID to UGIDS, plus any gids to which that user belongs. If AVAIL is
+ true, the are added to the avail gids instead of the effective ones. */
+error_t
+ugids_add_user (struct ugids *ugids, uid_t uid, int avail)
+{
+ error_t err;
+ struct idvec imp_gids = IDVEC_INIT;
+ uid_t uids_ids[] = { uid };
+ struct idvec uids = { uids_ids, 1 };
+ struct idvec *gids = avail ? &ugids->avail_gids : &ugids->eff_gids;
+
+ idvec_merge_implied_gids (&imp_gids, &uids);
+
+ /* Now remove any gids we already know about from IMP_GIDS. For gids
+ that weren't in the appropriate implied set before, this will
+ ensure that they remain out after we merge IMP_GIDS into it, and
+ ones that *were*, they will remain so. */
+ idvec_subtract (&imp_gids, gids);
+
+ /* Try to add UID. */
+ err = idvec_add_new (avail ? &ugids->avail_uids : &ugids->eff_uids, uid);
+
+ if (! err)
+ /* Now that we've added UID, we can add appropriate implied gids.
+ [If this fails, UGIDS will be an inconsistent state, but things
+ are probably fucked anyhow] */
+ err =
+ idvec_merge (avail ? &ugids->avail_gids : &ugids->eff_gids,
+ &imp_gids);
+ if (! err)
+ err = idvec_merge ((avail
+ ? &ugids->imp_avail_gids
+ : &ugids->imp_eff_gids),
+ &imp_gids);
+
+ idvec_fini (&imp_gids);
+
+ return err;
+}
diff --git a/libshouldbeinlibc/ugids.h b/libshouldbeinlibc/ugids.h
new file mode 100644
index 00000000..5d0e1134
--- /dev/null
+++ b/libshouldbeinlibc/ugids.h
@@ -0,0 +1,231 @@
+/* Uid/gid parsing/frobbing
+
+ Copyright (C) 1997,2001 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.org>
+
+ 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 __UGIDS_H__
+#define __UGIDS_H__
+
+#include <stdlib.h> /* For inline function stuff. */
+#include <idvec.h>
+#include <features.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#ifdef UGIDS_DEFINE_EI
+#define UGIDS_EI
+#else
+#define UGIDS_EI __extern_inline
+#endif
+
+/* A structure holding a set of the common various types of ids. */
+struct ugids
+{
+ struct idvec eff_uids; /* Effective UIDs */
+ struct idvec eff_gids; /* Effective GIDs */
+ struct idvec avail_uids; /* Available UIDs */
+ struct idvec avail_gids; /* Available GIDs */
+
+ /* These should be a subset of EFF/AVAIL_GIDS, containing those gids which
+ are present only by implication from uids in EFF/AVAIL_UIDS. */
+ struct idvec imp_eff_gids;
+ struct idvec imp_avail_gids;
+};
+
+#define UGIDS_INIT { IDVEC_INIT, IDVEC_INIT, IDVEC_INIT, IDVEC_INIT, IDVEC_INIT, IDVEC_INIT }
+
+/* Return a new ugids structure, or 0 if an allocation error occurs. */
+struct ugids *make_ugids ();
+
+extern void ugids_fini (struct ugids *ugids);
+
+extern void ugids_free (struct ugids *ugids);
+
+extern int ugids_is_empty (const struct ugids *ugids);
+
+extern int ugids_equal (const struct ugids *ugids1, const struct ugids *ugids2);
+
+#if defined(__USE_EXTERN_INLINES) || defined(UGIDS_DEFINE_EI)
+
+/* Free all resources used by UGIDS except UGIDS itself. */
+UGIDS_EI void
+ugids_fini (struct ugids *ugids)
+{
+ idvec_fini (&ugids->eff_uids);
+ idvec_fini (&ugids->eff_gids);
+ idvec_fini (&ugids->avail_uids);
+ idvec_fini (&ugids->avail_gids);
+ idvec_fini (&ugids->imp_eff_gids);
+ idvec_fini (&ugids->imp_avail_gids);
+}
+
+/* Free all resources used by UGIDS. */
+UGIDS_EI void
+ugids_free (struct ugids *ugids)
+{
+ ugids_fini (ugids);
+ free (ugids);
+}
+
+/* Return true if UGIDS contains no ids. */
+UGIDS_EI int
+ugids_is_empty (const struct ugids *ugids)
+{
+ /* We needn't test the imp_*_gids vectors because they are subsets of the
+ corresponding *_gids vectors. */
+ return
+ idvec_is_empty (&ugids->eff_uids)
+ && idvec_is_empty (&ugids->eff_gids)
+ && idvec_is_empty (&ugids->avail_uids)
+ && idvec_is_empty (&ugids->avail_gids);
+}
+
+/* Free all resources used by UGIDS except UGIDS itself. */
+UGIDS_EI int
+ugids_equal (const struct ugids *ugids1, const struct ugids *ugids2)
+{
+ return
+ idvec_equal (&ugids1->eff_uids, &ugids2->eff_uids)
+ && idvec_equal (&ugids1->eff_gids, &ugids2->eff_gids)
+ && idvec_equal (&ugids1->avail_uids, &ugids2->avail_uids)
+ && idvec_equal (&ugids1->avail_gids, &ugids2->avail_gids)
+ && idvec_equal (&ugids1->imp_eff_gids, &ugids2->imp_eff_gids)
+ && idvec_equal (&ugids1->imp_avail_gids, &ugids2->imp_avail_gids);
+}
+
+#endif /* Use extern inlines. */
+
+/* Add all ids in NEW to UGIDS. */
+error_t ugids_merge (struct ugids *ugids, const struct ugids *new);
+
+/* Set the ids in UGIDS to those in NEW. */
+error_t ugids_set (struct ugids *ugids, const struct ugids *new);
+
+/* Remove the ids in SUB from those in UGIDS. */
+error_t ugids_subtract (struct ugids *ugids, const struct ugids *sub);
+
+/* Mark as implied all gids in UGIDS that can be implied from its uids. */
+error_t ugids_imply_all (struct ugids *ugids);
+
+/* Save any effective ids in UGIDS by merging them into the available ids,
+ and removing them from the effective ones. */
+error_t ugids_save (struct ugids *ugids);
+
+/* Verify that we have the right to the ids in UGIDS, given that we already
+ possess those in HAVE_UIDS and HAVE_GIDS, asking for passwords where
+ necessary. 0 is returned if access should be allowed, otherwise
+ EINVAL if an incorrect password was entered, or an error relating to
+ resource failure. The GETPASS_FN, GETPASS_HOOK, VERIFY_FN, and
+ VERIFY_HOOK arguments are as for the idvec_verify function (in <idvec.h>). */
+error_t ugids_verify (const struct ugids *ugids,
+ const struct idvec *have_uids,
+ const struct idvec *have_gids,
+ char *(*getpass_fn) (const char *prompt,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *getpass_hook,
+ error_t (*verify_fn) (const char *password,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *verify_hook);
+
+/* Make an auth port from UGIDS and return it in AUTH, using authority in
+ both the auth port FROM and the current auth port. */
+error_t ugids_make_auth (const struct ugids *ugids,
+ const auth_t *from, size_t num_from,
+ auth_t *auth);
+
+/* Verify that we have the right to the ids in UGIDS, given that we already
+ possess those in HAVE_UIDS and HAVE_GIDS (asking for passwords where
+ necessary), and return corresponding authentication in AUTH; the auth
+ ports in FROM, of length NUM_FROM, are used to supplement the auth port of
+ the current process if necessary. 0 is returned if access should be
+ allowed, otherwise EINVAL if an incorrect password was entered, or an
+ error relating to resource failure. GETPASS_FN and GETPASS_HOOK are as
+ for the idvec_verify function in <idvec.h>. */
+error_t ugids_verify_make_auth (const struct ugids *ugids,
+ const struct idvec *have_uids,
+ const struct idvec *have_gids,
+ char *(*getpass_fn) (const char *prompt,
+ uid_t id, int is_group,
+ void *pwd_or_grp,
+ void *hook),
+ void *getpass_hook,
+ const auth_t *from, size_t num_from,
+ auth_t *auth);
+
+/* Merge the ids from the auth port AUTH into UGIDS. */
+error_t ugids_merge_auth (struct ugids *ugids, auth_t auth);
+
+/* Return a string representation of the ids in UGIDS. SHOW_VALUES and
+ SHOW_NAMES reflect how each id is printed (if SHOW_NAMES is true values
+ are used where names aren't available); if both are true, the
+ `VALUE(NAME)' format is used. ID_SEP, TYPE_SEP, and HDR_SEP contain the
+ strings that separate, respectively, multiple ids of a particular type
+ (default ","), the various types of ids (default ", "), and the name of
+ each type from its ids (default ": "). The empty string is returned for
+ an empty list, and 0 for an allocation error. */
+char *ugids_rep (const struct ugids *ugids, int show_values, int show_names,
+ const char *id_sep, const char *type_sep,
+ const char *hdr_sep);
+
+/* Add a new uid to UGIDS. If AVAIL is true, it's added to the avail uids
+ instead of the effective ones. */
+error_t ugids_add_uid (struct ugids *ugids, uid_t uid, int avail);
+
+/* Add a new gid to UGIDS. If AVAIL is true, it's added to the avail gids
+ instead of the effective ones. */
+error_t ugids_add_gid (struct ugids *ugids, gid_t gid, int avail);
+
+/* Add UID to UGIDS, plus any gids to which that user belongs. If AVAIL is
+ true, the are added to the avail gids instead of the effective ones. */
+error_t ugids_add_user (struct ugids *ugids, uid_t uid, int avail);
+
+/* Install UID into UGIDS as the main user, making sure that the posix
+ `real' and `saved' uid slots are filled in, and similarly add all
+ groups to which UID belongs. */
+error_t ugids_set_posix_user (struct ugids *ugids, uid_t uid);
+
+/* Params to be passed as the input when parsing UGIDS_ARGP. */
+struct ugids_argp_params
+{
+ /* Parsed ids should be added here. */
+ struct ugids *ugids;
+
+ /* If true, parse multiple args as user otherwise, parse none. */
+ int parse_user_args;
+
+ /* If true, and PARSE_USER_ARGS is true, add user args to the available
+ ids, not the effective ones. If both are true, add them to both.
+ If both are false, use the special ugids_set_posix_user instead (which
+ sets both, in a particular way). */
+ int user_args_are_effective;
+ int user_args_are_available;
+
+ /* If >= 0, a user that should be added if none are specified on the
+ command line (following the same rules). */
+ int default_user;
+
+ /* If true, at least one id has to be specified. */
+ int require_ids;
+};
+
+/* A parser for selecting a set of ugids. */
+extern struct argp ugids_argp;
+
+#endif /* __UGIDS_H__ */
diff --git a/libshouldbeinlibc/wire.c b/libshouldbeinlibc/wire.c
new file mode 100644
index 00000000..ca5d32b1
--- /dev/null
+++ b/libshouldbeinlibc/wire.c
@@ -0,0 +1,186 @@
+/* Function to wire down text and data (including from shared libraries)
+ Copyright (C) 1996,99,2000,01,02 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+
+#include <link.h>
+#include <dlfcn.h>
+#include <hurd.h>
+#include <error.h>
+#include <elf.h>
+
+#pragma weak _DYNAMIC
+#pragma weak dlopen
+#pragma weak dlclose
+#pragma weak dlerror
+#pragma weak dlsym
+#ifndef RTLD_NOLOAD
+#define RTLD_NOLOAD 0
+#endif
+
+/* Find the list of shared objects */
+static struct link_map *
+loaded (void)
+{
+ ElfW(Dyn) *d;
+
+ if (&_DYNAMIC == 0) /* statically linked */
+ return 0;
+
+ for (d = _DYNAMIC; d->d_tag != DT_NULL; ++d)
+ if (d->d_tag == DT_DEBUG)
+ {
+ struct r_debug *r = (void *) d->d_un.d_ptr;
+ return r->r_map;
+ }
+
+ return 0; /* ld broken */
+}
+
+/* Compute the extent of a particular shared object. */
+static ElfW(Addr)
+map_extent (struct link_map *map)
+{
+ /* In fact, LIB == MAP, but doing it this way makes it entirely kosher. */
+ void *lib = dlopen (map->l_name, RTLD_NOLOAD);
+ if (lib == 0)
+ {
+ error (2, 0, "cannot dlopen %s: %s", map->l_name, dlerror ());
+ /* NOTREACHED */
+ return 0;
+ }
+ else
+ {
+ /* Find the _end symbol's runtime address and subtract the load base. */
+ void *end = dlsym (lib, "_end");
+ if (end == 0)
+ error (2, 0, "cannot wire library %s with no _end symbol: %s",
+ map->l_name, dlerror ());
+ dlclose (lib);
+ return (ElfW(Addr)) end - map->l_addr;
+ }
+}
+
+/* Wire down all memory currently allocated at START for LEN bytes;
+ host_priv is the privileged host port. */
+static void
+wire_segment_internal (vm_address_t start,
+ vm_size_t len,
+ host_priv_t host_priv)
+{
+ vm_address_t addr;
+ vm_size_t size;
+ vm_prot_t protection;
+ vm_prot_t max_protection;
+ vm_inherit_t inheritance;
+ boolean_t shared;
+ mach_port_t object_name;
+ vm_offset_t offset;
+ error_t err;
+ volatile char *poke;
+
+ do
+ {
+ addr = start;
+ err = vm_region (mach_task_self (), &addr, &size, &protection,
+ &max_protection, &inheritance, &shared, &object_name,
+ &offset);
+ if (err)
+ return;
+
+ /* The current region begins at ADDR and is SIZE long. If it
+ extends beyond the LEN, prune it. */
+ if (addr + size > start + len)
+ size = len - (addr - start);
+
+ /* Set protection to allow all access possible */
+ vm_protect (mach_task_self (), addr, size, 0, max_protection);
+
+ /* Generate write faults */
+ for (poke = (char *) addr;
+ (vm_address_t) poke < addr + size;
+ poke += vm_page_size)
+ *poke = *poke;
+
+ /* Wire pages */
+ vm_wire (host_priv, mach_task_self (), addr, size, max_protection);
+
+ /* Set protection back to what it was */
+ vm_protect (mach_task_self (), addr, size, 0, protection);
+
+
+ mach_port_deallocate (mach_task_self (), object_name);
+
+ len -= (addr - start) + size;
+ start = addr + size;
+ }
+ while (len);
+}
+
+/* Wire down all memory currently allocated at START for LEN bytes. */
+void
+wire_segment (vm_address_t start,
+ vm_size_t len)
+{
+ mach_port_t host, device;
+ error_t err;
+
+ err = get_privileged_ports (&host, &device);
+ if (!err)
+ {
+ wire_segment_internal (start, len, host);
+ mach_port_deallocate (mach_task_self (), host);
+ mach_port_deallocate (mach_task_self (), device);
+ }
+}
+
+
+/* Wire down all the text and data (including from shared libraries)
+ for the current program. */
+void
+wire_task_self ()
+{
+ struct link_map *map;
+ mach_port_t host, device;
+ error_t err;
+ extern char _edata, _etext, __data_start;
+
+ err = get_privileged_ports (&host, &device);
+ if (err)
+ return;
+
+ map = loaded ();
+ if (!map)
+ {
+ extern void _start ();
+ vm_address_t text_start = (vm_address_t) &_start;
+ wire_segment_internal (text_start,
+ (vm_size_t) (&_etext - text_start),
+ host);
+ wire_segment_internal ((vm_address_t) &__data_start,
+ (vm_size_t) (&_edata - &__data_start),
+ host);
+ }
+ else
+ while (map)
+ wire_segment ((vm_address_t) map->l_addr, map_extent (map));
+
+ mach_port_deallocate (mach_task_self (), host);
+ mach_port_deallocate (mach_task_self (), device);
+}
diff --git a/libshouldbeinlibc/wire.h b/libshouldbeinlibc/wire.h
new file mode 100644
index 00000000..6783cc50
--- /dev/null
+++ b/libshouldbeinlibc/wire.h
@@ -0,0 +1,26 @@
+/* Function to wire down text and data (including from shared libraries)
+ Copyright (C) 1996 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+/* Wire down all the text and data (including from shared libraries)
+ for the current program. */
+void wire_task_self (void);
+
+/* Wire down all memory currently allocated at START for LEN bytes. */
+void wire_segment (vm_address_t start, vm_size_t len);
diff --git a/libshouldbeinlibc/xportinfo.c b/libshouldbeinlibc/xportinfo.c
new file mode 100644
index 00000000..cce6fb6c
--- /dev/null
+++ b/libshouldbeinlibc/xportinfo.c
@@ -0,0 +1,69 @@
+/* Print information about a port, with the name translated between tasks
+
+ Copyright (C) 1996, 1999 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 <sys/types.h>
+#include <sys/mman.h>
+
+#include "portinfo.h"
+
+/* Prints info about NAME translated through X to STREAM, in a way described
+ by the flags in SHOW. If TYPE is non-zero, it should be what
+ mach_port_type returns for NAME in X->to_task. */
+error_t
+print_xlated_port_info (mach_port_t name, mach_port_type_t type,
+ struct port_name_xlator *x,
+ unsigned show, FILE *stream)
+{
+ mach_port_t old_name = name;
+ error_t err = port_name_xlator_xlate (x, name, type, &name, &type);
+ if (! err)
+ {
+ fprintf (stream, (show & PORTINFO_HEX_NAMES) ? "%#6zx => " : "%6zd => ",
+ old_name);
+ err = print_port_info (name, type, x->to_task, show, stream);
+ }
+ return err;
+}
+
+/* Prints info about every port common to both tasks in X, but only if the
+ port in X->from_task has a type in ONLY, to STREAM. */
+error_t
+print_xlated_task_ports_info (struct port_name_xlator *x,
+ mach_port_type_t only,
+ unsigned show, FILE *stream)
+{
+ mach_port_t *names = 0;
+ mach_port_type_t *types = 0;
+ mach_msg_type_number_t names_len = 0, types_len = 0, i;
+ error_t err =
+ mach_port_names (x->from_task, &names, &names_len, &types, &types_len);
+
+ if (err)
+ return err;
+
+ for (i = 0; i < names_len; i++)
+ if (types[i] & only)
+ print_xlated_port_info (names[i], types[i], x, show, stream);
+
+ munmap ((caddr_t) names, names_len * sizeof *names);
+ munmap ((caddr_t) types, types_len * sizeof *types);
+
+ return 0;
+}