diff options
-rw-r--r-- | libshouldbeinlibc/idvec-impgids.c | 119 | ||||
-rw-r--r-- | libshouldbeinlibc/idvec-rep.c | 162 | ||||
-rw-r--r-- | libshouldbeinlibc/idvec-verify.c | 215 | ||||
-rw-r--r-- | libshouldbeinlibc/ugids-argp.c | 148 | ||||
-rw-r--r-- | libshouldbeinlibc/ugids-auth.c | 52 | ||||
-rw-r--r-- | libshouldbeinlibc/ugids-imply.c | 35 | ||||
-rw-r--r-- | libshouldbeinlibc/ugids-merge.c | 109 | ||||
-rw-r--r-- | libshouldbeinlibc/ugids-posix.c | 97 | ||||
-rw-r--r-- | libshouldbeinlibc/ugids-rep.c | 118 | ||||
-rw-r--r-- | libshouldbeinlibc/ugids-subtract.c | 130 | ||||
-rw-r--r-- | libshouldbeinlibc/ugids-verify.c | 63 | ||||
-rw-r--r-- | libshouldbeinlibc/ugids-xinl.c | 25 | ||||
-rw-r--r-- | libshouldbeinlibc/ugids.c | 99 | ||||
-rw-r--r-- | libshouldbeinlibc/ugids.h | 186 |
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__ |