diff options
Diffstat (limited to 'utils/login.c')
-rw-r--r-- | utils/login.c | 101 |
1 files changed, 52 insertions, 49 deletions
diff --git a/utils/login.c b/utils/login.c index c22a379a..cad3b1ed 100644 --- a/utils/login.c +++ b/utils/login.c @@ -1,8 +1,8 @@ /* Hurdish login - Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. + Copyright (C) 1995,96,97,98,99,2002 Free Software Foundation, Inc. - Written by Miles Bader <miles@gnu.ai.mit.edu> + Written by Miles Bader <miles@gnu.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -32,6 +32,7 @@ #include <time.h> #include <assert.h> #include <version.h> +#include <sys/mman.h> #include <netinet/in.h> #include <arpa/inet.h> @@ -139,7 +140,7 @@ cat (mach_port_t node, char *str) { write (0, data, data_len); if (data != buf) - vm_deallocate (mach_task_self (), (vm_address_t)data, data_len); + munmap (data, data_len); } } if (err) @@ -187,7 +188,9 @@ add_utmp_entry (char *args, unsigned args_len, int inherit_host) { struct utmp *old_utmp; strncpy (utmp.ut_line, basename (tty), sizeof (utmp.ut_line)); + setutent (); old_utmp = getutline (&utmp); + endutent (); if (old_utmp) { if (! host) @@ -207,7 +210,7 @@ add_utmp_entry (char *args, unsigned args_len, int inherit_host) /* Lookup the host HOST, and add entries for VIA (the host name), and VIA_ADDR (the dotted decimal address) to ARGS & ARGS_LEN. */ static error_t -add_canonical_host (char **args, unsigned *args_len, char *host) +add_canonical_host (char **args, size_t *args_len, char *host) { struct hostent *he = gethostbyname (host); @@ -244,7 +247,7 @@ add_canonical_host (char **args, unsigned *args_len, char *host) /* Add the `=' separated environment entry ENTRY to ENV & ENV_LEN, exiting with an error message if we can't. */ static void -add_entry (char **env, unsigned *env_len, char *entry) +add_entry (char **env, size_t *env_len, char *entry) { char *name = strsep (&entry, "="); error_t err = envz_add (env, env_len, name, entry); @@ -269,7 +272,7 @@ check_owned (process_t proc_server, pid_t pid, int *owned) { *owned = !(pi->state & PI_NOTOWNED); if (pi != &_pi) - vm_deallocate (mach_task_self (), (vm_address_t)pi, pi_size); + munmap (pi, pi_size); } return err; @@ -294,7 +297,7 @@ kill_login (process_t proc_server, pid_t pid, int sig) if (pids[i] != self) kill (pids[i], sig); if (pids != _pids) - vm_deallocate (mach_task_self (), (vm_address_t)pids, num_pids); + munmap (pids, num_pids); } } while (!err && num_pids > 0); @@ -365,7 +368,7 @@ dog (time_t timeout, pid_t pid, char **argv) } } -void +int main(int argc, char *argv[]) { int i; @@ -374,15 +377,15 @@ main(int argc, char *argv[]) char *path; error_t err = 0; char *args = 0; /* The login parameters */ - unsigned args_len = 0; + size_t args_len = 0; char *args_defs = 0; /* Defaults for login parameters. */ - unsigned args_defs_len = 0; + size_t args_defs_len = 0; char *env = 0; /* The new environment. */ - unsigned env_len = 0; + size_t env_len = 0; char *env_defs = 0; /* Defaults for the environment. */ - unsigned env_defs_len = 0; + size_t env_defs_len = 0; char *parent_env = 0; /* The environment we got from our parent */ - unsigned parent_env_len = 0; + size_t parent_env_len = 0; int no_environ = 0; /* If false, use the env as default params. */ int no_args = 0; /* If false, put login params in the env. */ int inherit_environ = 0; /* True if we shouldn't clear our env. */ @@ -391,11 +394,11 @@ main(int argc, char *argv[]) int paranoid = 0; /* Admit no knowledge. */ int retry = 0; /* For some failures, exec a login shell. */ char *retry_args = 0; /* Args passed when retrying. */ - unsigned retry_args_len = 0; + size_t retry_args_len = 0; char *shell = 0; /* The shell program to run. */ char *sh_arg0 = 0; /* The shell's argv[0]. */ char *sh_args = 0; /* The args to the shell. */ - unsigned sh_args_len = 0; + size_t sh_args_len = 0; int shell_arg = 0; /* If there are shell args, use the first as the shell name. */ struct ugids ugids = UGIDS_INIT; /* Authorization of the new shell. */ @@ -403,7 +406,6 @@ main(int argc, char *argv[]) struct idvec parent_uids = IDVEC_INIT; /* Parent uids, -SETUID. */ struct idvec parent_gids = IDVEC_INIT; /* Parent gids, -SETGID. */ mach_port_t exec; /* The shell executable. */ - mach_port_t cwd; /* The child's CWD. */ mach_port_t root; /* The child's root directory. */ mach_port_t ports[INIT_PORT_MAX]; /* Init ports for the new process. */ int ints[INIT_INT_MAX]; /* Init ints for it. */ @@ -438,7 +440,6 @@ main(int argc, char *argv[]) int retry_argc; char **retry_argv; char *via = envz_get (args, args_len, "VIA"); - extern void _argp_unlock_xxx (); /* Secret unknown function. */ if (fmt) error (retry ? 0 : code, err, fmt, str); /* May exit... */ @@ -454,7 +455,6 @@ main(int argc, char *argv[]) argz_extract (retry_args, retry_args_len, retry_argv); /* Reinvoke ourselves with no userids or anything; shouldn't return. */ - _argp_unlock_xxx (); /* Hack to get around problems with getopt. */ main (retry_argc, retry_argv); exit (code); /* But if it does... */ } @@ -580,12 +580,17 @@ main(int argc, char *argv[]) /* Parse our options. */ argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, 0); - /* Check passwords where necessary. */ - err = ugids_verify (&ugids, &parent_uids, &parent_gids, 0); - if (err == EINVAL) + /* Check passwords where necessary. If no_passwd is set, then our parent + guarantees identity itself (where it is allowed), but otherwise + we want every UID fully checked. */ + err = ugids_verify_make_auth (&ugids, + no_passwd ? &parent_uids : 0, + no_passwd ? &parent_gids : 0, + 0, 0, 0, 0, &auth); + if (err == EACCES) fail (5, 0, "Invalid password", 0); else if (err) - error (5, err, "Checking passwords"); + error (5, err, "Authentication failure"); /* Now that we've parsed the command line, put together all these environments we've gotten from various places. There are two targets: @@ -608,13 +613,13 @@ main(int argc, char *argv[]) { struct passwd *pw; char *passwd = 0; /* Login parameters from /etc/passwd */ - unsigned passwd_len = 0; + size_t passwd_len = 0; /* Decide which password entry to get parameters from. */ if (ugids.eff_uids.num > 0) pw = getpwuid (ugids.eff_uids.ids[0]); /* Effective uid */ else if (ugids.avail_uids.num > 0) - pw = getpwuid (ugids.eff_uids.ids[0]); /* Auxiliary uid */ + pw = getpwuid (ugids.avail_uids.ids[0]); /* Auxiliary uid */ else /* No user! Try to used the `not-logged-in' user to set various parameters. */ @@ -642,14 +647,12 @@ main(int argc, char *argv[]) free (passwd); } - err = ugids_make_auth (&ugids, MACH_PORT_NULL, &auth); - if (err) - fail (3, err, "Authentication failure", 0); - err = proc_getsid (proc_server, pid, &sid); assert_perror (err); /* This should never fail. */ - if (!no_login && parent_uids.num != 0) + if (!no_login + && (parent_uids.num != 0 + || ugids.eff_uids.num + ugids.avail_uids.num > 0)) /* Make a new login collection (but only for real users). */ { char *user = envz_get (args, args_len, "USER"); @@ -660,7 +663,7 @@ main(int argc, char *argv[]) if (ugids.eff_uids.num + ugids.avail_uids.num == 0) /* We're transiting from having some uids to having none, which means this is probably a new login session. Unless specified otherwise, - set a timer to kill this session if it hasn't aquired any ids by + set a timer to kill this session if it hasn't acquired any ids by then. Note that we fork off the timer process before clearing the process owner: because we're interested in killing unowned processes, proc's in-same-login-session rule should apply to us @@ -690,6 +693,7 @@ main(int argc, char *argv[]) for (i = 0; i < INIT_PORT_MAX; i++) ports[i] = MACH_PORT_NULL; ports[INIT_PORT_PROC] = getproc (); + ports[INIT_PORT_CTTYID] = getcttyid (); ports[INIT_PORT_CRDIR] = getcrdir (); /* May be replaced below. */ ports[INIT_PORT_CWDIR] = getcwdir (); /* " */ @@ -698,11 +702,10 @@ main(int argc, char *argv[]) if (err) error (40, err, "Port reauth failure"); - /* These are the default values for the child's root/cwd. We don't want to + /* These are the default values for the child's root. We don't want to modify PORTS just yet, because we use it to do child-authenticated lookups. */ root = ports[INIT_PORT_CRDIR]; - cwd = ports[INIT_PORT_CWDIR]; /* Find the shell executable (we copy the name, as ARGS may be changed). */ if (shell_arg && sh_args && *sh_args) @@ -757,13 +760,15 @@ main(int argc, char *argv[]) arg = envz_get (args, args_len, "HOME"); if (arg && *arg) { - cwd = child_lookup (arg, 0, O_RDONLY); + mach_port_t cwd = child_lookup (arg, 0, O_RDONLY); if (cwd == MACH_PORT_NULL) { error (0, errno, "%s", arg); error (0, 0, "Using HOME=/"); envz_add (&args, &args_len, "HOME", "/"); } + else + ports[INIT_PORT_CWDIR] = cwd; } arg = envz_get (args, args_len, "ROOT"); @@ -813,25 +818,24 @@ main(int argc, char *argv[]) if (no_login) sh_arg0 = shell_base; + else if (ugids.eff_uids.num + ugids.avail_uids.num == 0) + /* Use a special format for the argv[0] of a login prompt shell, + so that `ps' shows something informative in the COMMAND field. + This string must begin with a `-', the convention to tell the + shell to be a login shell (i.e. run .profile and the like). */ + err = (asprintf (&sh_arg0, "-login prompt (%s)", shell_base) == -1 + ? ENOMEM : 0); else - { - sh_arg0 = malloc (strlen (shell_base) + 2); - if (! sh_arg0) - err = ENOMEM; - else - /* Prepend the name with a `-', as is the odd custom. */ - { - sh_arg0[0] = '-'; - strcpy (sh_arg0 + 1, shell_base); - } - } + /* Prepend a `-' to the name, which is the ancient canonical + way to tell the shell that it's a login shell. */ + err = asprintf (&sh_arg0, "-%s", shell_base) == -1 ? ENOMEM : 0; } if (! err) err = argz_insert (&sh_args, &sh_args_len, sh_args, sh_arg0); if (err) error (21, err, "Error building shell args"); - /* Maybe output the message of the day. Note that we we the child's + /* Maybe output the message of the day. Note that we use the child's authentication to do it, so that this program can't be used to read arbitrary files! */ arg = envz_get (args, args_len, "MOTD"); @@ -851,16 +855,15 @@ main(int argc, char *argv[]) } /* Now that we don't need to use PORTS for lookups anymore, put the correct - ROOT and CWD in. */ + ROOT in. */ ports[INIT_PORT_CRDIR] = root; - ports[INIT_PORT_CWDIR] = cwd; /* Get rid of any accumulated null entries in env. */ envz_strip (&env, &env_len); /* No more authentications to fail, so cross our fingers and add our utmp entry. */ - + if (pid == sid) /* Only add utmp entries for the session leader. */ add_utmp_entry (args, args_len, !idvec_contains (&parent_uids, 0)); @@ -888,5 +891,5 @@ main(int argc, char *argv[]) if (err) error(5, err, "%s", shell); - exit(0); + return 0; } |