summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiles Bader <miles@gnu.org>1996-01-30 20:32:03 +0000
committerMiles Bader <miles@gnu.org>1996-01-30 20:32:03 +0000
commit3479cccbb76b4311591eab33c95ab43a79956ee7 (patch)
tree9b2288484981476532184cd2c373f8c0cd5c802f
parent3a0852c8f1c0b64ab3105fe3595d553b81ed4882 (diff)
(main):
Put LOGNAME in the environ even if it was already. Try to set the default path using confstr(). Call setlogin(). Turn on RETRY when the -h option is specified. (options, main): Change the -R/--retry option so that the optional argument is an argument to add to those passed to login when retrying, and remove all the hardwired arguments (except propagating -h/--via). (main, default_args): Replace the BACKUP_SHELL param with BACKUP_SHELLS, which is a list of things to try. The default includes both bash and the /bin/sh. (default_args, options, main): Get rid of the -n/--nobody option and variables, making it an additional login parameter. (add_utmp_entry): Get rid of declaration for login(). (copied_args): Add "USER". (default_args, default_env): Make the default path just /bin.
-rw-r--r--utils/login.c160
1 files changed, 100 insertions, 60 deletions
diff --git a/utils/login.c b/utils/login.c
index 8e7b7ec6..37bac81d 100644
--- a/utils/login.c
+++ b/utils/login.c
@@ -1,6 +1,6 @@
/* Hurdish login
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -56,38 +56,38 @@ hurd_file_name_path_lookup (error_t (*use_init_port)
int flags, mode_t mode,
file_t *result);
-#define DEFAULT_NOBODY "login"
-
-#define _PATH_MOTD "/etc/motd" /* XXX */
-
/* Defaults for various login parameters. */
char *default_args[] = {
- "SHELL=" _PATH_BSHELL,
- "BACKUP_SHELL=" _PATH_BSHELL, /* shell to use if we can't exec SHELL. */
- "HOME=/etc/login",
+ "SHELL=/bin/bash",
+ /* A ':' separated list of what to try if can't exec user's shell. */
+ "BACKUP_SHELLS=/bin/bash:" _PATH_BSHELL,
+ "HOME=/etc/login", /* Initial WD. */
"USER=login",
"UMASK=0",
"NAME=Not logged in",
"HUSHLOGIN=.hushlogin", /* Looked up relative new home dir. */
- "MOTD=" _PATH_MOTD,
- "PATH=" _PATH_DEFPATH,
+ "MOTD=/etc/motd",
+ "PATH=/bin",
+ "NOBODY=login",
0
};
/* Default values for the new environment. */
char *default_env[] = {
- "PATH=" _PATH_DEFPATH,
+ "PATH=/bin",
0
};
/* Which things are copied from the login parameters into the environment. */
-char *copied_args[] = { "SHELL", "HOME", "NAME", "VIA", "VIA_ADDR", "PATH", 0 };
+char *copied_args[] = {
+ "USER", "SHELL", "HOME", "NAME", "VIA", "VIA_ADDR", "PATH", 0
+};
static struct argp_option options[] =
{
{"arg0", '0', "ARG", 0, "Make ARG the shell's argv[0]"},
{"environ", 'e', "ENTRY", 0, "Add ENTRY to the environment"},
{"environ-default", 'E', "ENTRY", 0, "Use ENTRY as a default environment variable"},
- {"no-args", 'x', 0, 0, "Don't login args into the environment"},
+ {"no-args", 'x', 0, 0, "Don't put login args into the environment"},
{"arg", 'a', "ARG", 0, "Add login parameter ARG"},
{"arg-default", 'A', "ARG", 0, "Use ARG as a default login parameter"},
{"no-environ", 'X', 0, 0, "Don't add the parent environment as default login params"},
@@ -97,8 +97,6 @@ static struct argp_option options[] =
{"avail-group",'G',"GROUP", 0, "Add GROUP to the available groups"},
{"no-login", 'L', 0, 0, "Don't modify the shells argv[0] to look"
" like a login shell"},
- {"nobody", 'n', "USER", 0, "Use USER's passwd entry to fetch the default"
- " login params if there are no uids (default `" DEFAULT_NOBODY "')"},
{"inherit-environ", 'p', 0, 0, "Inherit the parent's environment"},
{"via", 'h', "HOST", 0, "This login is from HOST"},
{"no-passwd", 'f', 0, 0, "Don't ask for passwords"},
@@ -106,9 +104,10 @@ static struct argp_option options[] =
{"paranoid", 'P', 0, 0, "Don't admit that a user doesn't exist"},
{"keep", 'k', 0, 0, "Keep the old available ids, and save the old"
"effective ids as available ids"},
- {"shell-arg", 'S', 0, 0, "Use the first shell arg as the shell to invoke"},
- {"retry", 'R', "SHELL", OPTION_ARG_OPTIONAL,
- "Re-exec SHELL (default login) with no users after non-fatal errors"},
+ {"shell-from-args", 'S', 0, 0, "Use the first shell arg as the shell to invoke"},
+ {"retry", 'R', "ARG", OPTION_ARG_OPTIONAL,
+ "Re-exec login with no users after non-fatal errors; if ARG is supplied,"
+ "add it to the list of args passed to login when retrying"},
{0, 0}
};
static char *args_doc = "[USER [ARG...]]";
@@ -177,7 +176,6 @@ get_utmp_host ()
static void
add_utmp_entry (char *args, unsigned args_len, int tty_fd, int inherit_host)
{
- extern void login (struct utmp *); /* in libutil */
struct utmp utmp;
char bogus_tty[sizeof (_PATH_TTY) + 2];
char *tty = ttyname (0), *host;
@@ -267,7 +265,6 @@ main(int argc, char *argv[])
io_t node;
char *arg, *path;
error_t err = 0;
- char *nobody = DEFAULT_NOBODY; /* Where to get params if there is no user. */
char *args = 0; /* The login parameters */
unsigned args_len = 0;
char *passwd = 0; /* Login parameters from /etc/passwd */
@@ -287,21 +284,22 @@ main(int argc, char *argv[])
int no_passwd = 0; /* Don't bother verifying what we're doing. */
int no_utmp = 0; /* Don't put an entry in utmp. */
int no_login = 0; /* Don't prepend `-' to the shells argv[0]. */
- int retry = 0; /* For some failures, exec a login shell. */
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;
+ 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;
int shell_arg = 0; /* If there are shell args, use the first as
the shell name. */
- char *retry_shell = 0; /* Optionally use this shell for retries. */
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. */
- 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;
mach_port_t exec; /* The shell executable. */
mach_port_t cwd; /* The child's CWD. */
mach_port_t root; /* The child's root directory. */
@@ -311,7 +309,7 @@ main(int argc, char *argv[])
mach_port_t auth; /* The new shell's authentication. */
mach_port_t proc_server = getproc ();
mach_port_t parent_auth = getauth ();
-
+
/* These three functions are to do child-authenticated lookups. See
<hurd/lookup.h> for an explanation. */
error_t use_child_init_port (int which, error_t (*operate)(mach_port_t))
@@ -335,22 +333,26 @@ main(int argc, char *argv[])
exec a default login shell, otherwise exit with CODE (must be non-0). */
void fail (int code, error_t err, char *fmt, const char *str)
{
- /* Two 0's at end, so we can fill in the first with the shell arg. */
- char *retry_argv[] =
- {argv[0], "-aMOTD", "-aHOME", "-e_LOGIN_RETRY=yes", "-p", 0, 0};
- int retry_argc = (sizeof retry_argv / sizeof retry_argv[0]) - 1;
+ int retry_argc;
+ char **retry_argv;
+ char *via = envz_get (args, args_len, "VIA");
error (retry ? 0 : code, err, fmt, str); /* May exit... */
- if (retry_shell)
- asprintf (&retry_argv[retry_argc++ - 1], "-aSHELL=%s", retry_shell);
+ if (via)
+ envz_add (&retry_args, &retry_args_len, "--via", via);
+ argz_insert (&retry_args, &retry_args_len, retry_args, argv[0]);
+
+ retry_argc = argz_count (retry_args, retry_args_len);
+ retry_argv = alloca ((retry_argc + 1) * sizeof (char *));
+ 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... */
}
-
+
/* 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
@@ -393,7 +395,7 @@ main(int argc, char *argv[])
need_parent_ids ();
return idvec_contains (parent_gids, gid);
}
-
+
/* 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)
@@ -426,13 +428,12 @@ main(int argc, char *argv[])
if (strcmp (encrypted, password) != 0)
fail (50, 0, "Incorrect password", 0);
}
-
+
/* Parse our options... */
error_t parse_opt (int key, char *arg, struct argp_state *state)
{
switch (key)
{
- case 'n': nobody = arg; break;
case 'p': inherit_environ = 1; break;
case 'x': no_args = 1; break;
case 'X': no_environ = 1; break;
@@ -441,14 +442,27 @@ main(int argc, char *argv[])
case 'a': add_entry (&args, &args_len, arg); break;
case 'A': add_entry (&args_defs, &args_defs_len, arg); break;
case '0': sh_arg0 = arg; break;
- case 'h': add_canonical_host (&args, &args_len, arg); break;
case 'z': no_utmp = 1; break;
case 'L': no_login = 1; break;
case 'f': no_passwd = 1; break;
- case 'R': retry = 1; retry_shell = arg; break;
case 'P': paranoid = 1; break;
case 'S': shell_arg = 1; break;
+ case 'R':
+ retry = 1;
+ if (arg)
+ {
+ err = argz_add (&retry_args, &retry_args_len, arg);
+ if (err)
+ error (10, err, "Adding retry arg %s", arg);
+ }
+ break;
+
+ case 'h':
+ add_canonical_host (&args, &args_len, arg);
+ retry = 1;
+ break;
+
case 'k':
need_parent_ids ();
idvec_merge (avail_uids, parent_uids);
@@ -468,7 +482,7 @@ main(int argc, char *argv[])
if (strcmp (arg, "-") == 0)
arg = 0; /* Just like there weren't any args at all. */
/* Fall through to deal with adding the user. */
-
+
case 'u':
case 'U':
case ARGP_KEY_NO_ARGS:
@@ -476,7 +490,7 @@ main(int argc, char *argv[])
/* USER is whom to look up. If it's 0, then we hit the end of
the sh_args without seeing a user, so we want to add defaults
values for `nobody'. */
- char *user = arg ?: nobody;
+ char *user = arg ?: envz_get (args, args_len, "NOBODY");
struct passwd *pw =
isdigit (*user) ? getpwuid (atoi (user)) : getpwnam (user);
/* True if this is the user arg and there were no user options. */
@@ -536,7 +550,7 @@ main(int argc, char *argv[])
}
}
break;
-
+
case 'g':
case 'G':
{
@@ -554,7 +568,7 @@ main(int argc, char *argv[])
return 0;
}
struct argp argp = {options, parse_opt, args_doc, doc};
-
+
/* Don't allow logins if the nologin file exists. */
node = file_name_lookup (_PATH_NOLOGIN, O_RDONLY, 0);
if (node != MACH_PORT_NULL)
@@ -567,6 +581,18 @@ main(int argc, char *argv[])
err = argz_create (default_args, &args_defs, &args_defs_len);
if (! err)
err = argz_create (default_env, &env_defs, &env_defs_len);
+ if (! err)
+ /* Set the default path using confstr() if possible. */
+ {
+ size_t path_len = confstr (_CS_PATH, 0, 0);
+ if (path_len > 0)
+ {
+ char path[path_len];
+ path_len = confstr (_CS_PATH, path, path_len);
+ if (path_len > 0)
+ err = envz_add (&env_defs, &env_defs_len, "PATH", path);
+ }
+ }
if (err)
error (23, err, "adding defaults");
@@ -574,7 +600,7 @@ main(int argc, char *argv[])
/* Parse our options. */
argp_parse (&argp, argc, argv, 0, 0);
-
+
/* Now that we've parsed the command line, put together all these
environments we've gotten from various places. There are two targets:
(1) the login parameters, and (2) the child environment.
@@ -602,7 +628,7 @@ main(int argc, char *argv[])
err = envz_merge (&args, &args_len, args_defs, args_defs_len, 0);
if (err)
error (24, err, "merging parameters");
-
+
/* Make sure the new process has a real uid/gid (we add the ids twice, for
posix compatibility, once for the real id, and again for the saved). */
if (avail_uids->num == 0 && eff_uids->num > 0)
@@ -626,11 +652,18 @@ main(int argc, char *argv[])
if (err)
fail (3, err, "Authentication failure", 0);
- proc_make_login_coll (proc_server);
+ if (! no_login)
+ {
+ char *user = envz_get (args, args_len, "USER");
+ if (user && *user)
+ setlogin (user);
+ proc_make_login_coll (proc_server);
+ }
+
if (eff_uids->num > 0)
proc_setowner (proc_server, eff_uids->ids[0]);
/* XXX else clear the owner, once there's a proc call to do it. */
-
+
/* Now start constructing the exec arguments. */
bzero (ints, sizeof (*ints) * INIT_INT_MAX);
arg = envz_get (args, args_len, "UMASK");
@@ -655,7 +688,7 @@ main(int argc, char *argv[])
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)
/* Special case for su mode: get the shell from the args if poss. */
@@ -676,11 +709,20 @@ main(int argc, char *argv[])
exec = shell ? child_lookup (shell, path, O_EXEC) : MACH_PORT_NULL;
if (exec == MACH_PORT_NULL)
{
- char *backup = envz_get (args, args_len, "BACKUP_SHELL");
+ char *backup = 0;
+ char *backups = envz_get (args, args_len, "BACKUP_SHELLS");
err = errno; /* Save original lookup errno. */
- if (backup && *backup && (!shell || strcmp (shell, backup) != 0))
- exec = child_lookup (backup, path, O_EXEC);
+ if (backups && *backups)
+ {
+ backups = strdupa (backups); /* Copy so we can trash it. */
+ while (exec == MACH_PORT_NULL && backups)
+ {
+ backup = strsep (&backups, ":, ");
+ if (*backup && (!shell || strcmp (shell, backup) != 0))
+ exec = child_lookup (backup, path, O_EXEC);
+ }
+ }
/* Give the error message, but only exit if we couldn't default. */
if (exec == MACH_PORT_NULL)
@@ -694,7 +736,7 @@ main(int argc, char *argv[])
envz_add (&args, &args_len, "SHELL", shell);
err = 0; /* Don't emit random err msgs later! */
}
-
+
/* Now maybe change the cwd/root in the child. */
arg = envz_get (args, args_len, "HOME");
@@ -716,7 +758,7 @@ main(int argc, char *argv[])
if (root == MACH_PORT_NULL)
fail (40, errno, "%s", arg);
}
-
+
/* Build the child environment. */
if (! no_args)
/* We can't just merge ARGS, because it may contain the parent
@@ -724,6 +766,8 @@ main(int argc, char *argv[])
we pick out only those values of args which actually *are* args. */
{
char **name;
+ char *user = envz_get (args, args_len, "USER");
+
for (name = copied_args; *name && !err; name++)
if (! envz_get (env, env_len, *name))
{
@@ -732,13 +776,9 @@ main(int argc, char *argv[])
err = envz_add (&env, &env_len, *name, val);
}
- if (!err && !envz_entry (args, args_len, "LOGNAME"))
+ if (user)
/* Copy the user arg into the environment as LOGNAME. */
- {
- char *user = envz_get (args, args_len, "USER");
- if (user)
- err = envz_add (&env, &env_len, "LOGNAME", user);
- }
+ err = envz_add (&env, &env_len, "LOGNAME", user);
}
if (! err && inherit_environ)
err = envz_merge (&env, &env_len, parent_env, parent_env_len, 0);
@@ -775,7 +815,7 @@ main(int argc, char *argv[])
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
authentication to do it, so that this program can't be used to read
arbitrary files! */