diff options
author | Michael I. Bushnell <mib@gnu.org> | 1996-07-18 04:35:29 +0000 |
---|---|---|
committer | Michael I. Bushnell <mib@gnu.org> | 1996-07-18 04:35:29 +0000 |
commit | 94cef36797600d11a50d09828fa80df8a73dfd1c (patch) | |
tree | b7cba9afef95489eedef534d3e6946eb13f595ba /utils/x.c | |
parent | 88dbbbf9e48e24f1ac007c1e4eeffd9caf8e2fad (diff) |
*** empty log message ***
Diffstat (limited to 'utils/x.c')
-rw-r--r-- | utils/x.c | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/utils/x.c b/utils/x.c new file mode 100644 index 00000000..0e4f7e02 --- /dev/null +++ b/utils/x.c @@ -0,0 +1,248 @@ +/* Hurdish su + + Copyright (C) 1996 Free Software Foundation, Inc. + + Written by Miles Bader <miles@gnu.ai.mit.edu> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <hurd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <paths.h> +#include <ctype.h> +#include <utmp.h> +#include <pwd.h> +#include <grp.h> +#include <netdb.h> +#include <time.h> + +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <sys/fcntl.h> + +#include <argp.h> +#include <argz.h> +#include <envz.h> +#include <idvec.h> +#include <error.h> +#include <timefmt.h> +#include <hurd/lookup.h> + +static struct argp_option options[] = +{ + {"add", 'a', "USER", 0, "Add following ids"}, + {"remove", 'r', "USER", 0, "Remove following ids"}, + {"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, 0} +}; +static char *args_doc = "[USER...]"; +static char *doc = + "A USER specified as an argument adds (or removes) that user's groups as" + " well. When removing groups implied by such an argument, the groups to" + " which uids remaining in the process after any we remove are ignored." +"\nUids and groups specified with options are used as-is."; + +/* Full set of desired authorization. XXX msg_del_auth doesn't allow such + fine control. */ +struct auth +{ + struct idvec euids, egids; /* Effective ids. */ + struct idvec auids, agids; /* Available ids. */ +}; + +/* Ids of our parent process, with the effect of this program being su'd + removed. */ +static struct idvec parent_uids = {0}, parent_gids = {0}; + +/* Make sure that the parent_[ug]ids are filled in. To make them useful for + su'ing, each is the avail ids with all effective ids but the first + appended; this gets rid of the effect of login being suid, and is useful + as the new process's avail id list (e.g., the real id is right). */ +static void +need_parent_ids () +{ + if (parent_uids.num == 0 && parent_gids.num == 0) + { + struct idvec *p_eff_uids = make_idvec (); + struct idvec *p_eff_gids = make_idvec (); + if (!p_eff_uids || !p_eff_gids) + err = ENOMEM; + if (! err) + err = idvec_merge_auth (p_eff_uids, parent_uids, + p_eff_gids, parent_gids, + parent_auth); + if (! err) + { + idvec_delete (p_eff_uids, 0); /* Counteract setuid. */ + idvec_delete (p_eff_gids, 0); + err = idvec_merge (parent_uids, p_eff_uids); + if (! err) + err = idvec_merge (parent_gids, p_eff_gids); + } + if (err) + error (39, err, "Can't get uids"); + } +} + +/* Returns true if the *caller* of this login program has UID. */ +static int +parent_has_uid (uid_t uid) +{ + need_parent_ids (); + return idvec_contains (parent_uids, uid); +} +/* Returns true if the *caller* of this login program has GID. */ +static int +parent_has_gid (gid_t gid) +{ + need_parent_ids (); + return idvec_contains (parent_gids, gid); +} +/* Returns the number of parent uids. */ +static int +count_parent_uids () +{ + need_parent_ids (); + return parent_uids.num; +} +/* Returns the number of parent gids. */ +static int +count_parent_gids () +{ + need_parent_ids (); + return parent_gids.num; +} + +/* Make sure the user should be allowed to do this. */ +void verify_passwd (const char *name, const char *password, + uid_t id, int is_group, structh auth *auth) +{ + extern char *crypt (const char salt[2], const char *string); + char *prompt, *unencrypted, *encrypted; + + if (!password || !*password + || idvec_contains (is_group ? auth->egids : auth->euids, id) + || idvec_contains (is_group ? auth->agids : auth->auids, id) + || (no_passwd + && (parent_has_uid (0) + || (is_group ? parent_has_uid (id) : parent_has_gid (id))))) + return; /* Already got this one. */ + + if (name) + asprintf (&prompt, "Password for %s%s:", + is_group ? "group " : "", name); + else + prompt = "Password:"; + + unencrypted = getpass (prompt); + encrypted = crypt (unencrypted, password); + /* Paranoia may destroya. */ + memset (unencrypted, 0, strlen (unencrypted)); + + if (name) + free (prompt); + + if (strcmp (encrypted, password) != 0) + error (50, 0, "Incorrect password", 0); +} + +void +main(int argc, char *argv[]) +{ + int i; + error_t err = 0; + struct auth add, remove; + + /* Parse our options... */ + error_t parse_opt (int key, char *arg, struct argp_state *state) + { + switch (key) + { + case ARGP_KEY_NO_ARGS: + arg = "0"; /* root */ + /* fall through. */ + + case 'u': + case 'U': + { + struct passwd *pw = + isdigit (*user) ? getpwuid (atoi (user)) : getpwnam (user); + /* True if this is the user arg and there were no user options. */ + + if (! pw) + error (10, 0, "%s: Unknown user", user); + + verify_passwd (state->argv[state->next] ? pw->pw_name : 0, + pw->pw_passwd, pw->pw_uid, 0, &auth); + + if (key == 'u') + idvec_add_new (&auth.euids, pw->pw_uid); + else if (key == 'U') + /* Add available ids instead of effective ones. */ + idvec_add_new (&auth.auids, pw->pw_uid); + else + /* A plain argument. Add both the specified user and any + associated groups. */ + { + /* Effective */ + idvec_add_new (&auth.euids, 0, pw->pw_uid); + idvec_add_new (&auth.egids, 0, pw->pw_gid); + } + } + break; + + case 'g': + case 'G': + { + struct group *gr = + isdigit (*arg) ? getgrgid (atoi (arg)) : getgrnam (arg); + if (! gr) + error (11, 0, "%s: Unknown group", arg); + verify_passwd (gr->gr_name, gr->gr_passwd, gr->gr_gid, 1, &auth); + idvec_add_new (key == 'g' ? &auth.egids : &auth.agids, gr->gr_gid); + } + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; + } + struct argp argp = {options, parse_opt, args_doc, doc}; + + bzero (add, sizeof add); + bzero (remove, sizeof remove); + + + err = + auth_makeauth (getauth (), 0, MACH_MSG_TYPE_COPY_SEND, 0, + &auth.euids->ids, &auth.euids->num, + &auth.auids->ids, &auth.auids->num, + &auth.egids->ids, &auth.egids->num, + &auth.agids->ids, &auth.agids->num, + &auth); + if (err) + error (3, err, "Authentication failure", 0); + + + exit(0); +} |