summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiles Bader <miles@gnu.org>1997-05-27 01:49:49 +0000
committerMiles Bader <miles@gnu.org>1997-05-27 01:49:49 +0000
commit60ce5e1e96837e07170f0ea80393af60f1e7e395 (patch)
tree5cafdf234dccc5e7457e24fda110c21a9e94a73e
parent2266f58d69f71acd70188db66c26d5d56e39eaf3 (diff)
Initial checkin
-rw-r--r--libshouldbeinlibc/idvec-impgids.c119
-rw-r--r--libshouldbeinlibc/idvec-rep.c162
-rw-r--r--libshouldbeinlibc/idvec-verify.c215
-rw-r--r--libshouldbeinlibc/ugids-argp.c148
-rw-r--r--libshouldbeinlibc/ugids-auth.c52
-rw-r--r--libshouldbeinlibc/ugids-imply.c35
-rw-r--r--libshouldbeinlibc/ugids-merge.c109
-rw-r--r--libshouldbeinlibc/ugids-posix.c97
-rw-r--r--libshouldbeinlibc/ugids-rep.c118
-rw-r--r--libshouldbeinlibc/ugids-subtract.c130
-rw-r--r--libshouldbeinlibc/ugids-verify.c63
-rw-r--r--libshouldbeinlibc/ugids-xinl.c25
-rw-r--r--libshouldbeinlibc/ugids.c99
-rw-r--r--libshouldbeinlibc/ugids.h186
14 files changed, 1558 insertions, 0 deletions
diff --git a/libshouldbeinlibc/idvec-impgids.c b/libshouldbeinlibc/idvec-impgids.c
new file mode 100644
index 00000000..97c849a2
--- /dev/null
+++ b/libshouldbeinlibc/idvec-impgids.c
@@ -0,0 +1,119 @@
+/* Add gids implied by a user
+
+ 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 <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 ();
+#if 0 /* Glibc doesn't have getgrouplist yet. */
+ gid_t _gids[NUM_STATIC_GIDS], *gids = _gids;
+ size_t maxgids = NUM_STATIC_GIDS;
+ size_t 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);
+ }
+#else
+ if (! cache)
+ err = ENOMEM;
+ else
+ err = idvec_add_new (cache, pw->pw_gid);
+#endif
+
+ 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)
+{
+ int i;
+ error_t err = 0;
+ for (i = 0; i < uids->num && !err; i++)
+ err = _merge_implied_gids (gids, uids->ids[i]);
+ return err;
+}
diff --git a/libshouldbeinlibc/idvec-rep.c b/libshouldbeinlibc/idvec-rep.c
new file mode 100644
index 00000000..2fa1be03
--- /dev/null
+++ b/libshouldbeinlibc/idvec-rep.c
@@ -0,0 +1,162 @@
+/* idvec string representation
+
+ 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 <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)
+ {
+ 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..ef344115
--- /dev/null
+++ b/libshouldbeinlibc/idvec-verify.c
@@ -0,0 +1,215 @@
+/* Verify user passwords
+
+ 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 <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <idvec.h>
+#include <grp.h>
+#include <pwd.h>
+
+extern char *crypt (const char *string, const char salt[2]);
+#pragma weak crypt
+
+static error_t verify_id (); /* FWD */
+
+/* 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, which defaults to the standard libc function getpass) 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. */
+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))
+{
+ if (have_uids && idvec_contains (have_uids, 0))
+ /* Root can do anything. */
+ return 0;
+ else
+ {
+ int multiple; /* 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 (uids && gids)
+ /* Calculate which groups we need not ask about because they are
+ implied by the uids which we 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);
+
+ multiple =
+ (((uids ? uids->num : 0)
+ + (gids ? gids->num : 0)
+ - implied_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, wheel_uid, getpass_fn);
+ else
+ {
+ int i;
+
+ 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, wheel_uid, getpass_fn);
+ }
+
+ 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, wheel_uid, getpass_fn);
+ }
+ }
+
+ 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, int wheel_uid,
+ char *(*getpass_fn)(const char *prompt))
+{
+ int err;
+ char *name = 0, *password = 0;
+ char *prompt = 0, *unencrypted, *encrypted;
+ char id_lookup_buf[1024];
+
+ if (id >= 0)
+ do
+ {
+ if (is_group)
+ {
+ struct group _gr, *gr;
+ if (getgrgid_r (id, &_gr, id_lookup_buf, sizeof id_lookup_buf, &gr)
+ == 0)
+ {
+ password = gr->gr_passwd;
+ name = gr->gr_name;
+ }
+ }
+ else
+ {
+ struct passwd _pw, *pw;
+ if (getpwuid_r (id, &_pw, id_lookup_buf, sizeof id_lookup_buf, &pw)
+ == 0)
+ {
+ password = pw->pw_passwd;
+ name = pw->pw_name;
+ }
+ }
+ 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
+ /* If ID == 0 && !IS_GROUP, then this means that the system is
+ really fucked up (there's no root password entry), so instead
+ just don't ask for a password at all (if an intruder has
+ succeeded in preventing the lookup somehow, he probably could
+ have just provided his own result anyway). */
+ name = "uh-oh";
+ }
+ while (! name);
+
+ if (!password || !*password)
+ /* No password! */
+ return 0;
+
+ if (! getpass_fn)
+ getpass_fn = getpass;
+
+ 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);
+ if (prompt)
+ {
+ unencrypted = (*getpass_fn) (prompt);
+ free (prompt);
+ }
+ else
+ unencrypted = (*getpass_fn) ("Password:");
+
+ if (crypt)
+ {
+ encrypted = crypt (unencrypted, password);
+ if (! encrypted)
+ /* Something went wrong. */
+ return errno;
+ }
+ else
+ encrypted = unencrypted;
+
+ err = EINVAL; /* Assume an invalid password. */
+
+ if (encrypted && strcmp (encrypted, password) == 0)
+ err = 0; /* Password correct! */
+ 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 = getpwuid (wheel_uid);
+ encrypted = crypt (unencrypted, pw->pw_passwd);
+ if (pw && encrypted && strcmp (encrypted, pw->pw_passwd) == 0)
+ err = 0; /* *this* password is correct! */
+ }
+
+ /* Paranoia may destroya. */
+ memset (unencrypted, 0, strlen (unencrypted));
+
+ return err;
+}
diff --git a/libshouldbeinlibc/ugids-argp.c b/libshouldbeinlibc/ugids-argp.c
new file mode 100644
index 00000000..d80f27f7
--- /dev/null
+++ b/libshouldbeinlibc/ugids-argp.c
@@ -0,0 +1,148 @@
+/* Parse 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 <hurd.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <argp.h>
+#include <pwd.h>
+#include <grp.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;
+ if (getpwnam_r (arg, &_pw, id_lookup_buf, sizeof id_lookup_buf, &pw)
+ == 0)
+ uid = pw->pw_uid;
+ else
+ {
+ argp_failure (state, 10, 0, "%s: Unknown user", arg);
+ return EINVAL;
+ }
+ }
+
+ 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;
+ if (getgrnam_r (arg, &_gr, id_lookup_buf, sizeof id_lookup_buf, &gr)
+ == 0)
+ return ugids_add_gid (ugids, gr->gr_gid, key == 'G');
+ else
+ {
+ argp_failure (state, 11, 0, "%s: Unknown group", arg);
+ return EINVAL;
+ }
+ }
+
+ 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..89af3848
--- /dev/null
+++ b/libshouldbeinlibc/ugids-auth.c
@@ -0,0 +1,52 @@
+/* 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 <stdlib.h>
+#include <hurd.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, auth_t from, auth_t *auth)
+{
+ auth_t cur_auth = getauth ();
+ error_t err =
+ auth_makeauth (cur_auth, &from, MACH_MSG_TYPE_COPY_SEND,
+ (from == MACH_PORT_NULL) ? 0 : 1,
+ 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..9c2a8a2c
--- /dev/null
+++ b/libshouldbeinlibc/ugids-imply.c
@@ -0,0 +1,35 @@
+/* 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 <stdlib.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..924e1ed9
--- /dev/null
+++ b/libshouldbeinlibc/ugids-merge.c
@@ -0,0 +1,109 @@
+/* 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 <stdlib.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..b8ed8e74
--- /dev/null
+++ b/libshouldbeinlibc/ugids-posix.c
@@ -0,0 +1,97 @@
+/* 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 };
+
+ err = idvec_merge_implied_gids (&imp_gids, &uids);
+ if (! err)
+ {
+ 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;
+ }
+
+ /* 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..eecba20e
--- /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 <stdlib.h>
+#include <stdio.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.c b/libshouldbeinlibc/ugids-verify.c
new file mode 100644
index 00000000..b2400bec
--- /dev/null
+++ b/libshouldbeinlibc/ugids-verify.c
@@ -0,0 +1,63 @@
+/* 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 <stdlib.h>
+#include <string.h>
+#include <hurd.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <argp.h>
+#include <pwd.h>
+#include <grp.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 (with
+ GETPASS, which defaults to the standard libc function getpass) 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. */
+error_t
+ugids_verify (const struct ugids *ugids,
+ const struct idvec *have_uids, const struct idvec *have_gids,
+ char *(*getpass_fn)(const char *prompt))
+{
+ 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);
+
+ 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..f472e1ec
--- /dev/null
+++ b/libshouldbeinlibc/ugids-xinl.c
@@ -0,0 +1,25 @@
+/* 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_EI
+#undef __OPTIMIZE__
+#define __OPTIMIZE__
+#include "ugids.h"
diff --git a/libshouldbeinlibc/ugids.c b/libshouldbeinlibc/ugids.c
new file mode 100644
index 00000000..5ccb9334
--- /dev/null
+++ b/libshouldbeinlibc/ugids.c
@@ -0,0 +1,99 @@
+/* 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 "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 appropiate 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;
+
+ err = idvec_merge_implied_gids (&imp_gids, &uids);
+ if (! err)
+ {
+ /* Now remove any gids we already know about from IMP_GIDS. For gids
+ that weren't in the appropiate 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..3293d55f
--- /dev/null
+++ b/libshouldbeinlibc/ugids.h
@@ -0,0 +1,186 @@
+/* Uid/gid parsing/frobbing
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __UGIDS_H__
+#define __UGIDS_H__
+
+#include <stdlib.h> /* For inline function stuff. */
+#include <idvec.h>
+
+#ifndef UGIDS_EI
+#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 ();
+
+/* 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);
+}
+
+/* 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 (with
+ GETPASS, which defaults to the standard libc function getpass) 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. */
+error_t ugids_verify (const struct ugids *ugids,
+ const struct idvec *have_uids,
+ const struct idvec *have_gids,
+ char *(*getpass_fn)(const char *prompt));
+
+/* 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, auth_t 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__