diff options
author | Miles Bader <miles@gnu.org> | 1995-12-13 01:18:36 +0000 |
---|---|---|
committer | Miles Bader <miles@gnu.org> | 1995-12-13 01:18:36 +0000 |
commit | e701ce3121922c3f7e07172fc44c166724cce112 (patch) | |
tree | 29074006b4be7ed1b4903a2da2dbea67f7828411 /utils/login.c | |
parent | cf6fecaaf1dcc3f7c32086186200044a164f70c1 (diff) |
Initial revision
Diffstat (limited to 'utils/login.c')
-rw-r--r-- | utils/login.c | 295 |
1 files changed, 295 insertions, 0 deletions
diff --git a/utils/login.c b/utils/login.c new file mode 100644 index 00000000..0cab4934 --- /dev/null +++ b/utils/login.c @@ -0,0 +1,295 @@ +/* Hurdish login + + Copyright (C) 1995 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 <argp.h> +#include <argz.h> +#include <unistd.h> +#include <paths.h> +#include <error.h> +#include <ctype.h> +#include <pwd.h> +#include <grp.h> +#include <sys/fcntl.h> + +#define DEFAULT_SHELL _PATH_BSHELL +#define DEFAULT_PATH _PATH_DEFPATH +#define DEFAULT_HOME "/u/nobody" +#define DEFAULT_UMASK 0 + +static struct argp_option options[] = +{ + {"shell", 's', "SHELL", 0, "Use SHELL as the new shell"}, + {"arg", 'a', "ARG", 0, "Add ARG to the shell's arguments"}, + {"arg0", '0', "ARG", 0, "Make ARG the shell's argv[0]"}, + {"environ", 'e', "ENTRY", 0, "Add ENTRY to the environment"}, + {"user", 'u', "USER", 0, "Add USER to the uids in the new shell"}, + {"aux-user", 'U', "USER", 0, "Add USER to the aux uids in the new shell"}, + {"group", 'g', "GROUP", 0, "Add GROUP to the gids in the new shell"}, + {"aux-group", 'G', "GROUP", 0, "Add GROUP to the aux gids in the new shell"}, + {"home", 'h', "DIR", 0, "Make DIR the CWD of the new shell"}, + {"umask", 'm', "MASK", 0, "Make UMASK the new shell's umask"}, + {"path", 'p', "PATH", 0, "Path put in environment by default"}, + {"no-environ", 'E', 0, 0, "Don't put default entries into the new environment"}, + {0, 0} +}; +static char *args_doc = "[USER...]"; +static char *doc = 0; + +/* These functions should be moved into argz.c in libshouldbelibc. */ + +/* Add BUF, of length BUF_)LEN to the argz vector in ARGZ & ARGZ_LEN. */ +static error_t +argz_append (char **argz, unsigned *argz_len, char *buf, unsigned buf_len) +{ + unsigned new_argz_len = *argz_len + buf_len; + char *new_argz = realloc (*argz, new_argz_len); + if (new_argz) + { + bcopy (buf, new_argz + *argz_len, buf_len); + *argz = new_argz; + *argz_len = new_argz_len; + return 0; + } + else + return ENOMEM; +} + +/* Add STR to the argz vector in ARGZ & ARGZ_LEN. This should be moved into + argz.c in libshouldbelibc. */ +static error_t +argz_add (char **argz, unsigned *argz_len, char *str) +{ + return argz_append (argz, argz_len, str, strlen (str) + 1); +} + +typedef unsigned id_t; + +struct ids +{ + id_t *ids; + unsigned num, alloced; +}; + +struct +ids *make_ids () +{ + struct ids *ids = malloc (sizeof (struct ids)); + if (!ids) + error(8, ENOMEM, "Can't allocate id list"); + ids->ids = 0; + ids->num = ids->alloced = 0; + return ids; +} + +void +ids_add (struct ids *ids, id_t id) +{ + if (ids->alloced == ids->num) + { + ids->alloced = ids->alloced * 2 + 1; + ids->ids = realloc (ids->ids, ids->alloced * sizeof (id_t)); + if (ids->ids == NULL) + error(8, ENOMEM, "Can't allocate id list"); + } + + ids->ids[ids->num++] = id; +} + +void +main(int argc, char *argv[]) +{ + error_t err; + int umask = DEFAULT_UMASK; + char *shell = 0; /* The shell program to run. */ + char *home = 0; /* The new home directory. */ + char *path = DEFAULT_PATH; /* The path put in environment. */ + char *arg0 = 0; /* The shell's argv[0]. */ + char *args = 0; /* The args to the shell. */ + unsigned args_len = 0; + char *env = 0; /* The new environment. */ + unsigned env_len = 0; + int no_environ = 0; /* True if we shouldn't add default entries. */ + struct ids *uids = make_ids (); /* The UIDs of the new shell. */ + struct ids *gids = make_ids (); /* The GIDs. */ + struct ids *aux_uids = make_ids (); /* The aux UIDs of the new shell. */ + struct ids *aux_gids = make_ids (); /* The aux GIDs. */ + mach_port_t exec_node; /* The shell executable. */ + mach_port_t home_node; /* The home directory node. */ + mach_port_t ports[INIT_PORT_MAX]; + int ints[INIT_INT_MAX]; + mach_port_t dtable[3]; /* File descriptors passed. */ + char *argz = 0; /* The shell's arg vector. */ + unsigned argz_len = 0; + mach_port_t auth; /* The auth port for the new shell. */ + mach_port_t auth_server = getauth (); + mach_port_t proc_server = getproc (); + + /* Parse our options... */ + error_t parse_opt (int key, char *arg, struct argp_state *state) + { + switch (key) + { + case 's': shell = arg; break; + case 'm': umask = strtoul (arg, 0, 8); break; + case 'h': home = arg; break; + case 'p': path = arg; break; + + case 'e': + err = argz_add (&env, &env_len, arg); + if (err) + error (8, err, "Adding %s", arg); + break; + case 'a': + err = argz_add (&args, &args_len, arg); + if (err) + error (9, err, "Adding %s", arg); + break; + case '0': + arg0 = arg; + break; + + case ARGP_KEY_ARG: + case 'u': + case 'U': + { + struct passwd *pw = + isdigit (*arg) ? getpwuid (atoi (arg)) : getpwnam (arg); + if (! pw) + error (10, 0, "%s: Unknown user", arg); + + /* Should check password here. */ + + if (key != 'U') + { + ids_add (uids, pw->pw_uid); + ids_add (gids, pw->pw_gid); + + /* Add reasonable defaults. */ + if (! home && pw->pw_dir) + home = strdup (pw->pw_dir); + if (! shell && pw->pw_shell) + shell = strdup (pw->pw_shell); + } + else + { + ids_add (aux_uids, pw->pw_uid); + ids_add (aux_uids, 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); + + /* Should check password here. */ + + ids_add (key == 'g' ? gids : aux_gids, gr->gr_gid); + } + break; + + default: return EINVAL; + } + return 0; + } + struct argp argp = {options, parse_opt, args_doc, doc}; + + argp_parse (&argp, argc, argv, 0, 0); + + if (! shell) + shell = DEFAULT_SHELL; + if (! arg0) + arg0 = shell; + if (! home) + home = DEFAULT_HOME; + + argz_add (&argz, &argz_len, arg0); + argz_append (&argz, &argz_len, args, args_len); + + if (! no_environ) + { + char *entry; + asprintf (&entry, "HOME=%s", home); + argz_add (&env, &env_len, entry); + free (entry); + asprintf (&entry, "SHELL=%s", shell); + argz_add (&env, &env_len, entry); + free (entry); + if (path) + { + asprintf (&entry, "PATH=%s", path); + argz_add (&env, &env_len, entry); + free (entry); + } + } + + exec_node = file_name_lookup (shell, O_EXEC, 0); + if (exec_node == MACH_PORT_NULL) + error (1, errno, "%s", shell); + + home_node = file_name_lookup (home, O_RDONLY, 0); + if (home_node == MACH_PORT_NULL) + error (2, errno, "%s", home); + + err = + auth_makeauth (auth_server, 0, MACH_MSG_TYPE_COPY_SEND, 0, + uids->ids, uids->num, gids->ids, gids->num, + aux_uids->ids, aux_uids->num, aux_gids->ids, aux_gids->num, + &auth); + if (err) + error (3, err, "authenticating"); + + bzero (ports, sizeof (*ports) * INIT_PORT_MAX); + ports[INIT_PORT_CRDIR] = getcrdir (); + ports[INIT_PORT_CWDIR] = home_node; + ports[INIT_PORT_AUTH] = auth; + ports[INIT_PORT_PROC] = proc_server; + + bzero (ints, sizeof (*ints) * INIT_INT_MAX); + ints[INIT_UMASK] = umask; + + dtable[0] = getdport (0); + dtable[1] = getdport (1); + dtable[2] = getdport (2); + + err = file_exec (exec_node, mach_task_self (), +#if 0 + EXEC_NEWTASK | EXEC_DEFAULTS | EXEC_SECURE, +#else + 0, +#endif + argz, argz_len, env, env_len, + dtable, MACH_MSG_TYPE_COPY_SEND, 3, + ports, MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX, + ints, INIT_INT_MAX, + 0, 0, 0, 0); + if (err) + error(5, err, "%s", shell); + + exit(0); +} |