diff options
-rw-r--r-- | utils/addu.c | 444 |
1 files changed, 0 insertions, 444 deletions
diff --git a/utils/addu.c b/utils/addu.c deleted file mode 100644 index 2313d020..00000000 --- a/utils/addu.c +++ /dev/null @@ -1,444 +0,0 @@ -/* Add a user to some process(es) - - 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. */ - -/* XXX NOTE: This program is a real hack job, with large chunks of code cut - out of ps and login; the code should be shared in some fashion instead. */ - -#include <hurd.h> -#include <stdio.h> -#include <stdlib.h> -#include <assert.h> -#include <string.h> -#include <ctype.h> -#include <unistd.h> -#include <argp.h> -#include <pwd.h> -#include <grp.h> -#include <idvec.h> -#include <ps.h> -#include <error.h> -#include <version.h> - -#include "psout.h" - -const char *argp_program_version = STANDARD_HURD_VERSION (ps); - -#define OA OPTION_ARG_OPTIONAL - -static const struct argp_option options[] = -{ - {0,0,0,0, "Which ids to add:"}, - {"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,0,0, "Whic processes to add to:"}, - {"login", 'L', "LID", OA, "Processes from the login" - " collection LID (which defaults that of" - " the current process)"}, - {"lid", 0, 0, OPTION_ALIAS | OPTION_HIDDEN}, - {"pid", 'p', "PID", 0, "The process PID"}, - {"pgrp", 'P', "PGRP", 0, "Processes in process group PGRP"}, - {"session", 'S', "SID", OA, "Processes from the session SID" - " (which defaults to the sid of the" - " current process)"}, - {"sid", 0, 0, OPTION_ALIAS | OPTION_HIDDEN}, - {0, 0} -}; - -char *args_doc = "USER..."; -char *doc = -"Add USER to the userids of the selected processes" -"\vBy default, all processes in the current login collection are selected"; - -/* For each string in the comma-separated list in ARG, call ADD_FN; if ARG is - empty and DEFAULT_ADD_FN isn't NULL, then call DEFAULT_ADD_FN instead. */ -static void -_parse_strlist (char *arg, - void (*add_fn)(const char *str), void (*default_add_fn)(), - const char *type_name) -{ - if (arg) - while (isspace(*arg)) - arg++; - - if (arg == NULL || *arg == '\0') - if (default_add_fn) - (*default_add_fn)(); - else - error(7, 0, "Empty %s list", type_name); - else - { - char *end = arg; - - void mark_end() - { - *end++ = '\0'; - while (isspace(*end)) - end++; - } - void parse_element() - { - if (*arg == '\0') - error(7, 0, "Empty element in %s list", type_name); - (*add_fn)(arg); - arg = end; - } - - while (*end != '\0') - switch (*end) - { - case ' ': case '\t': - mark_end(); - if (*end == ',') - mark_end(); - parse_element(); - break; - case ',': - mark_end(); - parse_element(); - break; - default: - end++; - } - - parse_element(); - } -} - -/* For each numeric string in the comma-separated list in ARG, call ADD_FN; - if ARG is empty and DEFAULT_FN isn't NULL, then call DEF_FN to get a number, - and call ADD_FN on that, otherwise signal an error. If any member of the - list isn't a number, and LOOKUP_FN isn't NULL, then it is called to return - an integer for the string. LOOKUP_FN should signal an error itself it - there's some problem parsing the string. */ -static void -parse_numlist (char *arg, - void (*add_fn)(unsigned num), - int (*default_fn)(), - int (*lookup_fn)(const char *str), - const char *type_name) -{ - void default_num_add() { (*add_fn)((*default_fn)()); } - void add_num_str(const char *str) - { - const char *p; - for (p = str; *p != '\0'; p++) - if (!isdigit(*p)) - { - if (lookup_fn) - (*add_fn)((*lookup_fn)(str)); - else - error (7, 0, "%s: Invalid %s", p, type_name); - return; - } - (*add_fn)(atoi(str)); - } - _parse_strlist(arg, add_num_str, default_fn ? default_num_add : 0, - type_name); -} - -static process_t proc_server; - -/* Returns our session id. */ -static pid_t -current_sid() -{ - pid_t sid; - error_t err = proc_getsid(proc_server, getpid(), &sid); - if (err) - error(2, err, "Couldn't get current session id"); - return sid; -} - -/* Returns our login collection id. */ -static pid_t -current_lid() -{ - pid_t lid; - error_t err = proc_getloginid(proc_server, getpid(), &lid); - if (err) - error(2, err, "Couldn't get current login collection") ; - return lid; -} - -/* Returns the UID for the user called NAME. */ -static int -lookup_user(const char *name) -{ - struct passwd *pw = getpwnam(name); - if (pw == NULL) - error(2, 0, "%s: Unknown user", name); - return pw->pw_uid; -} - -void -main (int argc, char *argv[]) -{ - error_t err; - struct proc_stat_list *procset; - struct ps_context *context; - struct idvec *eff_uids = make_idvec (); /* The UIDs of the new shell. */ - struct idvec *eff_gids = make_idvec (); /* The EFF_GIDs. */ - struct idvec *avail_uids = make_idvec (); /* The aux UIDs of the new shell. */ - struct idvec *avail_gids = make_idvec (); /* The aux EFF_GIDs. */ - struct idvec *parent_uids = make_idvec (); /* Parent uids, -SETUID. */ - struct idvec *parent_gids = make_idvec (); /* Parent gids, -SETGID. */ - auth_t auth, parent_auth = getauth (); - - /* Add a specific process to be printed out. */ - void add_pid (unsigned pid) - { - struct proc_stat *ps; - - err = proc_stat_list_add_pid (procset, pid, &ps); - if (err) - error (2, err, "%d: Cannot add process", pid); - - /* See if this process actually exists. */ - proc_stat_set_flags (ps, PSTAT_PROC_INFO); - if (! proc_stat_has (ps, PSTAT_PROC_INFO)) - error (99, 0, "%d: Unknown process", pid); - } - /* Print out all process from the given session. */ - void add_sid(unsigned sid) - { - err = proc_stat_list_add_session (procset, sid, 0, 0); - if (err) - error(2, err, "%u: Cannot add session", sid); - } - /* Print out all process from the given login collection. */ - void add_lid(unsigned lid) - { - error_t err = proc_stat_list_add_login_coll (procset, lid, 0, 0); - if (err) - error(2, err, "%u: Cannot add login collection", lid); - } - /* Print out all process from the given process group. */ - void add_pgrp(unsigned pgrp) - { - error_t err = proc_stat_list_add_pgrp (procset, pgrp, 0, 0); - if (err) - error(2, err, "%u: Cannot add process group", pgrp); - } - - /* 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). */ - 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, "Cannot get uids"); - } - } - - /* Returns true if the *caller* of this login program has UID. */ - 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. */ - int parent_has_gid (gid_t gid) - { - need_parent_ids (); - return idvec_contains (parent_gids, gid); - } - /* Returns the number of parent uids. */ - int count_parent_uids () - { - need_parent_ids (); - return parent_uids->num; - } - /* Returns the number of parent gids. */ - 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) - { - extern char *crypt (const char *string, const char salt[2]); -#ifndef HAVE_CRYPT -#pragma weak crypt -#endif - char *prompt, *unencrypted, *encrypted; - - if (!password || !*password - || idvec_contains (is_group ? eff_gids : eff_uids, id) - || idvec_contains (is_group ? avail_gids : avail_uids, id) - || 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); - if (crypt) - { - encrypted = crypt (unencrypted, password); - /* Paranoia may destroya. */ - memset (unencrypted, 0, strlen (unencrypted)); - - if (! encrypted) - /* Something went wrong. */ - error (51, errno, "Password encryption failed"); - } - else - encrypted = unencrypted; - - if (name) - free (prompt); - - if (strcmp (encrypted, password) != 0) - error (50, 0, "Incorrect password"); - } - - error_t parse_opt (int key, char *arg, struct argp_state *state) - { - switch (key) - { - case 'p': - parse_numlist(arg, add_pid, NULL, NULL, "process id"); - break; - case 'S': - parse_numlist(arg, add_sid, current_sid, NULL, "session id"); - break; - case 'L': - parse_numlist(arg, add_lid, current_lid, NULL, "login collection"); - break; - case 'P': - parse_numlist(arg, add_pgrp, NULL, NULL, "process group"); - break; - - case 'u': - case 'U': - case ARGP_KEY_ARG: - { - struct passwd *pw = - isdigit (*arg) ? getpwuid (atoi (arg)) : getpwnam (arg); - /* True if this is the user arg and there were no user options. */ - int only_user = - (key == ARGP_KEY_ARG - && eff_uids->num == 0 && avail_uids->num <= count_parent_uids () - && eff_gids->num == 0 && avail_gids->num <= count_parent_gids ()); - - if (! pw) - argp_failure (state, 10, 0, "%s: Unknown user", arg); - - /* If it's not nobody, make sure we're authorized. */ - verify_passwd (only_user ? 0 : pw->pw_name, pw->pw_passwd, - pw->pw_uid, 0); - - if (key == 'U') - /* Add available ids instead of effective ones. */ - idvec_add_new (avail_uids, pw->pw_uid); - else - idvec_add_new (eff_uids, pw->pw_uid); - } - break; - - case 'g': - case 'G': - { - struct group *gr = - isdigit (*arg) ? getgrgid (atoi (arg)) : getgrnam (arg); - if (! gr) - argp_failure (state, 11, 0, "%s: Unknown group", arg); - verify_passwd (gr->gr_name, gr->gr_passwd, gr->gr_gid, 1); - idvec_add_new (key == 'g' ? eff_gids : avail_gids, gr->gr_gid); - } - break; - - default: - return ARGP_ERR_UNKNOWN; - } - return 0; - } - error_t frob_proc (struct proc_stat *ps) - { - if (! (ps->flags & PSTAT_MSGPORT)) - error (0, 0, "%d: Cannot get message port", ps->pid); - else - { - error_t err = msg_add_auth (ps->msgport, auth); - if (err) - error (0, err, "%d: Cannot add authentication", ps->pid); - } - return 0; - } - - struct argp argp = { options, parse_opt, args_doc, doc}; - - proc_server = getproc(); - - err = ps_context_create (proc_server, &context); - if (err) - error(1, err, "ps_context_create"); - - err = proc_stat_list_create(context, &procset); - if (err) - error(1, err, "proc_stat_list_create"); - - /* Parse our command line. This shouldn't ever return an error. */ - argp_parse (&argp, argc, argv, 0, 0, 0); - - err = - auth_makeauth (getauth (), 0, MACH_MSG_TYPE_COPY_SEND, 0, - eff_uids->ids, eff_uids->num, - avail_uids->ids, avail_uids->num, - eff_gids->ids, eff_gids->num, - avail_gids->ids, avail_gids->num, - &auth); - if (err) - error (3, err, "Authentication failure"); - - proc_stat_list_set_flags (procset, PSTAT_TASK | PSTAT_MSGPORT); - proc_stat_list_for_each (procset, frob_proc); - - exit (0); -} |