diff options
| author | Jordan K. Hubbard <jkh@FreeBSD.org> | 1996-12-09 06:02:36 +0000 |
|---|---|---|
| committer | Jordan K. Hubbard <jkh@FreeBSD.org> | 1996-12-09 06:02:36 +0000 |
| commit | 325403f9596de195bb802b53936f5700d3e514c1 (patch) | |
| tree | c397ac2f0ca96773e57d858dac092400ce2f74d9 | |
| parent | c2ce3df1da95df019f1b7f136fabce0cb9a485af (diff) | |
Notes
| -rw-r--r-- | release/sysinstall/Makefile | 3 | ||||
| -rw-r--r-- | release/sysinstall/help/usermgmt.hlp | 91 | ||||
| -rw-r--r-- | release/sysinstall/menus.c | 23 | ||||
| -rw-r--r-- | release/sysinstall/network.c | 8 | ||||
| -rw-r--r-- | release/sysinstall/sysinstall.h | 7 | ||||
| -rw-r--r-- | release/sysinstall/system.c | 4 | ||||
| -rw-r--r-- | release/sysinstall/user.c | 750 | ||||
| -rw-r--r-- | usr.sbin/sade/Makefile | 3 | ||||
| -rw-r--r-- | usr.sbin/sade/menus.c | 23 | ||||
| -rw-r--r-- | usr.sbin/sade/sade.h | 7 | ||||
| -rw-r--r-- | usr.sbin/sade/system.c | 4 | ||||
| -rw-r--r-- | usr.sbin/sysinstall/Makefile | 3 | ||||
| -rw-r--r-- | usr.sbin/sysinstall/help/usermgmt.hlp | 91 | ||||
| -rw-r--r-- | usr.sbin/sysinstall/menus.c | 23 | ||||
| -rw-r--r-- | usr.sbin/sysinstall/network.c | 8 | ||||
| -rw-r--r-- | usr.sbin/sysinstall/sysinstall.h | 7 | ||||
| -rw-r--r-- | usr.sbin/sysinstall/system.c | 4 | ||||
| -rw-r--r-- | usr.sbin/sysinstall/user.c | 750 |
18 files changed, 1777 insertions, 32 deletions
diff --git a/release/sysinstall/Makefile b/release/sysinstall/Makefile index b09ec9994d6e..10abd4cadd92 100644 --- a/release/sysinstall/Makefile +++ b/release/sysinstall/Makefile @@ -11,7 +11,7 @@ SRCS= anonFTP.c apache.c attr.c cdrom.c command.c config.c devices.c \ ftp_strat.c globals.c index.c install.c installUpgrade.c \ keymap.c label.c lndir.c main.c makedevs.c media.c menus.c misc.c \ msg.c network.c nfs.c options.c package.c samba.c system.c \ - tape.c tcpip.c termcap.c ufs.c variable.c wizard.c \ + tape.c tcpip.c termcap.c ufs.c user.c variable.c wizard.c \ uc_eisa.c uc_isa.c uc_kmem.c uc_list.c uc_main.c uc_pci.c \ uc_scsi.c @@ -23,7 +23,6 @@ CFLAGS+= -DUC_PRIVATE -DKERN_NO_SYMBOLS -DSAVE_USERCONFIG DPADD= ${LIBDIALOG} ${LIBNCURSES} ${LIBMYTINFO} ${LIBUTIL} ${LIBDISK} LDADD= -ldialog -lncurses -lmytinfo -lutil -ldisk - makedevs.c: Makefile rtermcap keymap.h rm -f makedevs.tmp echo '#include <sys/types.h>' > makedevs.tmp diff --git a/release/sysinstall/help/usermgmt.hlp b/release/sysinstall/help/usermgmt.hlp new file mode 100644 index 000000000000..3798b490f7a1 --- /dev/null +++ b/release/sysinstall/help/usermgmt.hlp @@ -0,0 +1,91 @@ +These screens allow you to add groups and users to your system. + +You can move through the fields with the TAB, BACK-TAB and RETURN +keys. To edit a field, use DELETE or BACKSPACE. You may also use ^A +(control-A) to go to the beginning of the line, ^E (control-E) to go +to the end, ^F (control-F) to go forward a character, ^B (control-B) +to go backward one character, ^D (control-D) to delete the character +under the cursor and ^K (control-K) to delete to the end of the line. +Basically, the standard EMACS motion sequences. + +When you're done with this form, select OK. + + +User groups +=========== + +It's certainly almost generally a good idea to first create a new +group for your users. Common names for such a group are "users", or +even simply "other". Group names are used to control file access +permissions for users that belong to the same group. Several group +names are already used for system files. + +The numerical user or group IDs are often nothing you want to care for +explicitly. If you don't fill in these fields, the system will chose +reasonable defaults. However, these numbers (rather than the +associated names) are what the operating system actually uses to +distinguish users and groups -- hence they should normally be unique +to each person or group, respectively. + +(The initial membership list for a new group is currently +unimplemented, sorry.) + + +Users +===== + +The user's login ID is a short (8 characters) alphanumeric ID the user +must enter when logging into the system. It's often the initial +letters of the user's name, and commonly used in lower case. It's +also the local mail name for this user (though it's possible to also +setup more descriptive mail alias names later). + +The user's login group determines which group access rights the user +will initally get when logging in. If an additional list of groups is +provided where the user will become a member of, (s)he will also be +able to access files of those groups later without providing any +additional password etc. Except for the "wheel" case mentioned below, +the additional group membership list should normally not contain the +login group again. + +Some of the system's groups have a special meaning. In particular, +members of group "wheel" are the only people who are later allowed to +become superuser using the command su(1). So if you're going to add a +new user who should later perform administrative tasks, don't forget +to add him to this group! (Well, ``he'' will most likely be yourself +in the very first place. :) + +Also, members of group "operator" will by default get permissions for +minor administrative operations, like performing system backups, or +shutting down the system -- without first becoming superuser! So, +take care with adding people to this group. + +The ``full name'' field serves as a comment only. It is also used by +mail frontends to determine the real name of the user, hence you +should actually fill in the first and last name of this user. By +convention, this field can be divided into comma-separated subfields, +where the office location, the work phone number, and the home phone +number follow the full name of the user. + +The home directory is the directory in the filesystem where the user +is being logged into, and where his personalized setup files (``dot +files'', since they usually begin with a `.' and are not displayed by +the ls(1) command by default) will be looked up. It is often created +under /usr/home/ or /home/. + +Finally, the shell is the user's initial command interpreter. The +default shell is /bin/sh, some users prefer the more historic +/bin/csh. Other, often more user-friendly and comfortable shells can +be found in the ports and packages collection. + + +Passwords +========= + +Note that new users will be established with no allowable password, so +they cannot login immediately. Instead, someone with superuser +privileges has to run the command ``passwd <user>'' (where <user> is +to be replaced with the actual login name for this user) on behalf of +the new user, so (s)he can enter his/her password. Since the password +won't be echoed on the screen, it must be entered twice. This should +never be done across a network, to prevent password-sniffing. diff --git a/release/sysinstall/menus.c b/release/sysinstall/menus.c index dc20fcfb82f3..348c6b4a0e4d 100644 --- a/release/sysinstall/menus.c +++ b/release/sysinstall/menus.c @@ -4,7 +4,7 @@ * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * - * $Id: menus.c,v 1.98 1996/11/29 23:52:20 jkh Exp $ + * $Id: menus.c,v 1.99 1996/12/08 12:27:57 jkh Exp $ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. @@ -207,8 +207,7 @@ DMenu MenuIndex = { "Leave the index page by selecting Cancel [TAB-ENTER].", "Use PageUp or PageDown to move through this menu faster!", NULL, - { { "Add User", "Add users to the system.", NULL, dmenuSystemCommand, NULL, "adduser -config_create ; adduser -s" }, - { "Anon FTP", "Configure anonymous FTP logins.", dmenuVarCheck, configAnonFTP, NULL, "anon_ftp" }, + { { "Anon FTP", "Configure anonymous FTP logins.", dmenuVarCheck, configAnonFTP, NULL, "anon_ftp" }, { "Commit", "Commit any pending actions (dangerous!)", NULL, installCustomCommit }, { "Console settings", "Customize system console behavior.", NULL, dmenuSubmenu, NULL, &MenuSyscons }, { "Configure", "The system configuration menu.", NULL, dmenuSubmenu, NULL, &MenuConfigure }, @@ -269,6 +268,7 @@ DMenu MenuIndex = { { "Time Zone", "Set the system's time zone.", NULL, dmenuSystemCommand, NULL, "rm -f /etc/wall_cmos_clock /etc/localtime; tzsetup" }, { "Upgrade", "Upgrade an existing system.", NULL, installUpgrade }, { "Usage", "Quick start - How to use this menu system.", NULL, dmenuDisplayFile, NULL, "usage" }, + { "User Management", "Add user and group information.", NULL, dmenuSubmenu, NULL, &MenuUsermgmt }, { "WEB Server", "Configure host as a WWW server.", dmenuVarCheck, configApache, NULL, "apache_httpd" }, { "XFree86, Fonts", "XFree86 Font selection menu.", NULL, dmenuSubmenu, NULL, &MenuXF86SelectFonts }, { "XFree86, Server", "XFree86 Server selection menu.", NULL, dmenuSubmenu, NULL, &MenuXF86SelectServer }, @@ -1008,8 +1008,8 @@ DMenu MenuConfigure = { "software not provided in the base distributions.", "Press F1 for more information on these options", "configure", - { { "1 Add User", "Add users to the system", - NULL, dmenuSystemCommand, NULL, "adduser -config_create ; adduser -s" }, + { { "1 User Management", "Add user and group information", + NULL, dmenuSubmenu, NULL, &MenuUsermgmt }, { "2 Console", "Customize system console behavior", NULL, dmenuSubmenu, NULL, &MenuSyscons }, { "3 Time Zone", "Set which time zone you're in", @@ -1268,3 +1268,16 @@ DMenu MenuSysconsFont = { "font8x8=koi8-r-8x8,font8x14=koi8-r-8x14,font8x16=koi8-r-8x16" }, { NULL } }, }; + +DMenu MenuUsermgmt = { + DMENU_NORMAL_TYPE, + "User and group management", + "The submenus here allow to manipulate user groups and\n" + "login accounts.\n", + "Configure your user groups and users", + NULL, + { { "Add group", "Add a new user group to the system.", NULL, userAddGroup }, + { "Add user", "Add a new user to the system.", NULL, userAddUser }, + { "Exit", "Exit this menu (returning to previous)", NULL, dmenuExit }, + { NULL } }, +}; diff --git a/release/sysinstall/network.c b/release/sysinstall/network.c index e0d46810e931..c416f59b0c27 100644 --- a/release/sysinstall/network.c +++ b/release/sysinstall/network.c @@ -4,7 +4,7 @@ * This is probably the last attempt in the `sysinstall' line, the next * generation being slated to essentially a complete rewrite. * - * $Id: network.c,v 1.16 1996/08/03 10:11:26 jkh Exp $ + * $Id: network.c,v 1.17 1996/12/08 12:27:58 jkh Exp $ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. @@ -16,6 +16,7 @@ * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. + * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. @@ -92,6 +93,11 @@ mediaInitNetwork(Device *dev) return FALSE; else strcpy(attach, val); + /* + * Doing this with vsystem() is actually bogus since we should be storing the pid of slattach + * in dev->private for later killing. It's just too convenient to call vsystem(), however, + * rather than constructing a proper argument for exec() so we punt on doing slip right for now. + */ if (vsystem(attach)) { msgConfirm("slattach returned a bad status! Please verify that\n" "the command is correct and try again."); diff --git a/release/sysinstall/sysinstall.h b/release/sysinstall/sysinstall.h index b24257736201..ddc81116c41a 100644 --- a/release/sysinstall/sysinstall.h +++ b/release/sysinstall/sysinstall.h @@ -4,7 +4,7 @@ * This is probably the last attempt in the `sysinstall' line, the next * generation being slated to essentially a complete rewrite. * - * $Id: sysinstall.h,v 1.86 1996/11/09 16:47:08 joerg Exp $ + * $Id: sysinstall.h,v 1.87 1996/11/09 18:12:17 jkh Exp $ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. @@ -342,6 +342,7 @@ extern DMenu MenuXF86SelectPC98Server; /* XFree86 server distribution menu */ extern DMenu MenuXF86SelectFonts; /* XFree86 font selection menu */ extern DMenu MenuDiskDevices; /* Disk devices menu */ extern DMenu MenuHTMLDoc; /* HTML Documentation menu */ +extern DMenu MenuUsermgmt; /* User management menu */ /*** Prototypes ***/ @@ -631,6 +632,10 @@ extern void mediaShutdownUFS(Device *dev); extern Boolean mediaInitUFS(Device *dev); extern int mediaGetUFS(Device *dev, char *file, Boolean probe); +/* user.c */ +extern int userAddGroup(dialogMenuItem *self); +extern int userAddUser(dialogMenuItem *self); + /* variable.c */ extern void variable_set(char *var); extern void variable_set2(char *name, char *value); diff --git a/release/sysinstall/system.c b/release/sysinstall/system.c index c6580abf9d53..86e3a04059b5 100644 --- a/release/sysinstall/system.c +++ b/release/sysinstall/system.c @@ -4,7 +4,7 @@ * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * - * $Id: system.c,v 1.65 1996/10/01 04:56:34 jkh Exp $ + * $Id: system.c,v 1.66 1996/10/01 12:13:29 jkh Exp $ * * Jordan Hubbard * @@ -292,7 +292,7 @@ systemCreateHoloshell(void) struct termios foo; extern int login_tty(int); - for (i = 0; i < 64; i++) + for (i = getdtablesize(); i; i--) close(i); DebugFD = fd = open("/dev/ttyv3", O_RDWR); ioctl(0, TIOCSCTTY, &fd); diff --git a/release/sysinstall/user.c b/release/sysinstall/user.c new file mode 100644 index 000000000000..e87ac7cba2b9 --- /dev/null +++ b/release/sysinstall/user.c @@ -0,0 +1,750 @@ +/* + * $Id$ + * + * Copyright (c) 1996 + * Jörg Wunsch. All rights reserved. + * + * The basic structure has been taken from tcpip.c, which is: + * + * Copyright (c) 1995 + * Gary J Palmer. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * verbatim and that no modifications are made prior to this + * point in the file. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/param.h> +#include <string.h> +#include <dialog.h> +#include "ui_objects.h" +#include "dir.h" +#include "dialog.priv.h" +#include "colors.h" +#include "sysinstall.h" + +/* The help file for the user mgmt screen */ +#define USER_HELPFILE "usermgmt" + +/* XXX should they be moved out to sysinstall.h? */ +#define GNAME_FIELD_LEN 32 +#define GID_FIELD_LEN 10 +#define GMEMB_FIELD_LEN 64 + +#define UNAME_FIELD_LEN 32 +#define UID_FIELD_LEN 10 +#define UGROUP_FIELD_LEN GNAME_FIELD_LEN +#define GECOS_FIELD_LEN 64 +#define UMEMB_FIELD_LEN GMEMB_FIELD_LEN +#define HOMEDIR_FIELD_LEN 48 +#define SHELL_FIELD_LEN 48 + +/* These are nasty, but they make the layout structure a lot easier ... */ + +static char gname[GNAME_FIELD_LEN], + gid[GID_FIELD_LEN], + gmemb[GMEMB_FIELD_LEN], + uname[UNAME_FIELD_LEN], + uid[UID_FIELD_LEN], + ugroup[UGROUP_FIELD_LEN], + gecos[GECOS_FIELD_LEN], + umemb[UMEMB_FIELD_LEN], + homedir[HOMEDIR_FIELD_LEN], + shell[SHELL_FIELD_LEN]; +#define CLEAR(v) memset(v, 0, sizeof v) + +static int okbutton, cancelbutton; + + +/* What the screen size is meant to be */ +#define USER_DIALOG_Y 0 +#define USER_DIALOG_X 8 +#define USER_DIALOG_WIDTH COLS - 16 +#define USER_DIALOG_HEIGHT LINES - 2 + +/* The screen layout structure */ +typedef struct _layout { + int y; /* x & Y co-ordinates */ + int x; + int len; /* The size of the dialog on the screen */ + int maxlen; /* How much the user can type in ... */ + char *prompt; /* The string for the prompt */ + char *help; /* The display for the help line */ + void *var; /* The var to set when this changes */ + int type; /* The type of the dialog to create */ + void *obj; /* The obj pointer returned by libdialog */ +} Layout; + +/* The group configuration menu. */ +static Layout groupLayout[] = { +{ 4, 10, 20, GNAME_FIELD_LEN - 1, + "Group name:", "The alphanumeric name of the new group (mandatory)", + gname, STRINGOBJ, NULL }, +#define LAYOUT_GNAME 0 +{ 4, 38, 10, GID_FIELD_LEN - 1, + "GID:", "The numerical ID for this group (leave blank for automatic choice)", + gid, STRINGOBJ, NULL }, +#define LAYOUT_GID 1 +{ 11, 10, 40, GMEMB_FIELD_LEN - 1, + "Group members:", "Who belongs to this group (i.e., gets access rights for it)", + gmemb, STRINGOBJ, NULL }, +#define LAYOUT_GMEMB 2 +{ 18, 15, 0, 0, + "OK", "Select this if you are happy with these settings", + &okbutton, BUTTONOBJ, NULL }, +#define LAYOUT_OKBUTTON 3 +{ 18, 35, 0, 0, + "CANCEL", "Select this if you wish to cancel this screen", + &cancelbutton, BUTTONOBJ, NULL }, +#define LAYOUT_CANCELBUTTON 4 + +{ NULL }, +}; + +/* The user configuration menu. */ +static Layout userLayout[] = { +{ 3, 6, 20, UNAME_FIELD_LEN - 1, + "Login ID:", "The login name of the new user (mandatory)", + uname, STRINGOBJ, NULL }, +#define LAYOUT_UNAME 0 +{ 3, 29, 10, UID_FIELD_LEN - 1, + "UID:", "The numerical ID for this user (leave blank for automatic choice)", + uid, STRINGOBJ, NULL }, +#define LAYOUT_UID 1 +{ 3, 43, 15, UGROUP_FIELD_LEN - 1, + "Group:", "The login group name for this user (mandatory)", + ugroup, STRINGOBJ, NULL }, +#define LAYOUT_UGROUP 2 +{ 8, 6, 33, GECOS_FIELD_LEN - 1, + "Full name:", "The user's full name (comment)", + gecos, STRINGOBJ, NULL }, +#define LAYOUT_GECOS 3 +{ 8, 43, 15, UMEMB_FIELD_LEN - 1, + "Member groups:", "The groups this user belongs to (i.e. gets access rights for)", + umemb, STRINGOBJ, NULL }, +#define LAYOUT_UMEMB 4 +{ 13, 6, 20, HOMEDIR_FIELD_LEN - 1, + "Home directory:", "The user's home directory (leave blank for default)", + homedir, STRINGOBJ, NULL }, +#define LAYOUT_HOMEDIR 5 +{ 13, 29, 29, SHELL_FIELD_LEN - 1, + "Login shell:", "The user's login shell (leave blank for default)", + shell, STRINGOBJ, NULL }, +#define LAYOUT_SHELL 6 +{ 18, 15, 0, 0, + "OK", "Select this if you are happy with these settings", + &okbutton, BUTTONOBJ, NULL }, +#define LAYOUT_U_OKBUTTON 7 +{ 18, 35, 0, 0, + "CANCEL", "Select this if you wish to cancel this screen", + &cancelbutton, BUTTONOBJ, NULL }, +#define LAYOUT_U_CANCELBUTTON 8 + +{ NULL }, +}; + +/* whine */ +static void +feepout(char *msg) +{ + beep(); + dialog_notify(msg); +} + +/* Check for the settings on the screen. */ + +static int +verifyGroupSettings(void) +{ + char tmp[256], *cp; + long lgid; + + if (strlen(gname) == 0) { + feepout("The group name field must not be empty!"); + return 0; + } + snprintf(tmp, 256, "pw group show -q -n %s > /dev/null", gname); + if (vsystem(tmp) == 0) { + feepout("This group name is already in use."); + return 0; + } + if (strlen(gid) > 0) { + lgid = strtol(gid, &cp, 10); + if (lgid < 0 || lgid >= 65536 || (*cp != '\0' && !isspace(*cp))) { + feepout("The GID must be a number between 1 and 65535."); + return 0; + } + } + if (strlen(gmemb) > 0) { + if (strpbrk(gmemb, " \t") != NULL) { + feepout("The group member list must not contain any whitespace;\n" + "use commas to separate the names."); + return 0; + } +#ifndef notyet /* XXX */ + feepout("Sorry, this feature is currently not yet implemented.\n"); + return 0; +#endif + } + + return 1; +} + +static void +addGroup(WINDOW *ds_win) +{ + char tmp[256]; + int pfd[2], i; + ssize_t l; + size_t amnt; + pid_t pid; + char *vec[8] = + { + "pw", "group", "add", "-n", 0, "-g", 0, 0 + }; +#define VEC_GNAME 4 +#define VEC_GID 6 + + msgNotify("Adding group \"%s\"...", gname); + + pipe (pfd); + if ((pid = fork()) == 0) + { + /* The kiddy. */ + dup2(pfd[1], 1); + dup2(pfd[1], 2); + for (i = getdtablesize(); i > 2; i--) + close(i); + + vec[VEC_GNAME] = gname; + + if (strlen(gid) > 0) + vec[VEC_GID] = gid; + else + vec[VEC_GID - 1] = 0; + + chroot(variable_get(VAR_INSTALL_ROOT)); + execv("/usr/sbin/pw", vec); + msgDebug("Cannot execv() /usr/sbin/pw.\n"); + _exit(99); + } + else + { + /* The oldie. */ + close(pfd[1]); + amnt = sizeof tmp; + i = 0; + while((l = read(pfd[0], &tmp[i], amnt)) > 0) + { + amnt -= l; + i += l; + if (amnt == 0) + { + close(pfd[0]); + break; + } + } + close(pfd[0]); + tmp[i] = '\0'; + waitpid(pid, &i, 0); + if (WIFSIGNALED(i)) + msgDebug("pw(8) exited with signal %d.\n", WTERMSIG(i)); + else if(WEXITSTATUS(i)) + { + i = 0; + if(strncmp(tmp, "pw: ", 4) == 0) + i = 4; + tmp[sizeof tmp - 1] = '\0'; /* sanity */ + msgConfirm("The `pw' command exited with an error status.\n" + "Its error message was:\n\n%s", + &tmp[i]); + } + } +} + +int +userAddGroup(dialogMenuItem *self) +{ + WINDOW *ds_win, *save; + ComposeObj *obj = NULL; + ComposeObj *first, *last; + int n=0, quit=FALSE, cancel=FALSE, ret; + int max; + char help[FILENAME_MAX]; + + if (RunningAsInit && !strstr(variable_get(SYSTEM_STATE), "install")) { + msgConfirm("This option may only be used after the system is installed, sorry!"); + return DITEM_FAILURE; + } + + save = savescr(); + dialog_clear_norefresh(); + /* We need a curses window */ + ds_win = newwin(LINES, COLS, 0, 0); + if (ds_win == 0) + msgFatal("Cannot open AddGroup dialog window!!"); + + /* Say where our help comes from */ + use_helpfile(systemHelpFile(USER_HELPFILE, help)); + + /* Setup a nice screen for us to splat stuff onto */ + draw_box(ds_win, USER_DIALOG_Y, USER_DIALOG_X, USER_DIALOG_HEIGHT, USER_DIALOG_WIDTH, + dialog_attr, border_attr); + wattrset(ds_win, dialog_attr); + mvwaddstr(ds_win, USER_DIALOG_Y, USER_DIALOG_X + 18, " Users and Group Management "); + draw_box(ds_win, USER_DIALOG_Y + 2, USER_DIALOG_X + 8, USER_DIALOG_HEIGHT - 6, + USER_DIALOG_WIDTH - 17, dialog_attr, border_attr); + wattrset(ds_win, dialog_attr); + mvwaddstr(ds_win, USER_DIALOG_Y + 2, USER_DIALOG_X + 22, " Add a new group "); + + CLEAR(gname); + CLEAR(gid); + CLEAR(gmemb); + + /* Loop over the layout list, create the objects, and add them + onto the chain of objects that dialog uses for traversal*/ + n = 0; +#define lt groupLayout[n] + while (lt.help != NULL) { + switch (lt.type) { + case STRINGOBJ: + lt.obj = NewStringObj(ds_win, lt.prompt, lt.var, + lt.y + USER_DIALOG_Y, lt.x + USER_DIALOG_X, + lt.len, lt.maxlen); + break; + + case BUTTONOBJ: + lt.obj = NewButtonObj(ds_win, lt.prompt, lt.var, + lt.y + USER_DIALOG_Y, lt.x + USER_DIALOG_X); + break; + + default: + msgFatal("Don't support this object yet!"); + } + AddObj(&obj, lt.type, (void *) lt.obj); + n++; + } + max = n - 1; + + /* Find the last object we can traverse to */ + last = obj; + while (last->next) + last = last->next; + + /* Find the first object in the list */ + first = obj; + for (first = obj; first->prev; first = first->prev); + + /* Some more initialisation before we go into the main input loop */ + n = 0; + cancelbutton = okbutton = 0; + + /* Incoming user data - DUCK! */ + while (!quit) { + char help_line[80]; + int i, len = strlen(lt.help); + + /* Display the help line at the bottom of the screen */ + for (i = 0; i < 79; i++) + help_line[i] = (i < len) ? lt.help[i] : ' '; + help_line[i] = '\0'; + use_helpline(help_line); + display_helpline(ds_win, LINES - 1, COLS - 1); + + /* Ask for libdialog to do its stuff */ + ret = PollObj(&obj); + + /* Handle special case stuff that libdialog misses. Sigh */ + switch (ret) { + /* Bail out */ + case SEL_ESC: + quit = TRUE, cancel=TRUE; + break; + + /* This doesn't work for list dialogs. Oh well. Perhaps + should special case the move from the OK button ``up'' + to make it go to the interface list, but then it gets + awkward for the user to go back and correct screw up's + in the per-interface section */ + + case KEY_DOWN: + case SEL_TAB: + case SEL_CR: + if (n < max) + ++n; + else + n = 0; + break; + + /* The user has pressed enter over a button object */ + case SEL_BUTTON: + if (cancelbutton) + cancel = TRUE, quit = TRUE; + else { + if (verifyGroupSettings()) + quit = TRUE; + } + break; + + case KEY_UP: + case SEL_BACKTAB: + if (n) + --n; + else + n = max; + break; + + case KEY_F(1): + display_helpfile(); + + /* They tried some key combination we don't support - tell them! */ + default: + beep(); + } + } +#undef lt + + /* Clear this crap off the screen */ + dialog_clear_norefresh(); + use_helpfile(NULL); + + if (!cancel) { + addGroup(ds_win); + restorescr(save); + return DITEM_SUCCESS; + } + restorescr(save); + return DITEM_FAILURE; +} + +/* Check for the settings on the screen. */ + +static int +verifyUserSettings(WINDOW *ds_win) +{ + char tmp[256], *cp; + long luid; + WINDOW *save; + int rv; + + if (strlen(uname) == 0) { + feepout("The user name field must not be empty!"); + return 0; + } + snprintf(tmp, 256, "pw user show -q -n %s > /dev/null", gname); + if (vsystem(tmp) == 0) { + feepout("This user name is already in use."); + return 0; + } + if (strlen(uid) > 0) { + luid = strtol(uid, &cp, 10); + if (luid < 0 || luid >= 65536 || (*cp != '\0' && !isspace(*cp))) { + feepout("The UID must be a number between 1 and 65535."); + return 0; + } + } + if (strlen(ugroup) == 0) { + feepout("The login group field must not be empty!"); + return 0; + } + snprintf(tmp, 256, "pw group show -q -n %s > /dev/null", ugroup); + if (vsystem(tmp) != 0) { + feepout("This group name does not yet exist."); + return 0; + } + if (strlen(shell) > 0) { + while((cp = getusershell()) != NULL) + if (strcmp(cp, shell) == 0) + break; + endusershell(); + if (cp == NULL) { + save = savescr(); + rv = msgYesNo("Warning:\n\n" + "The requested shell \"%s\" is not\n" + "a valid user shell.\n\n" + "Use it anyway?\n", shell); + restorescr(save); + wrefresh(ds_win); + if (rv != DITEM_SUCCESS) + return 0; + } + + } + + if (strlen(umemb) > 0) { + if (strpbrk(umemb, " \t") != NULL) { + feepout("The member groups list must not contain any whitespace;\n" + "use commas to separate the names."); + return 0; + } + } + + return 1; +} + +static void +addUser(WINDOW *ds_win) +{ + char tmp[256]; + int pfd[2], i; + ssize_t l; + size_t amnt; + pid_t pid; + /* + * Maximal list: + * pw user add -m -n uname -g grp -u uid -c comment -d homedir -s shell -G grplist + */ + char *vec[18] = + { + "pw", "user", "add", "-m", "-n", /* ... */ + }; +#define VEC_UNAME 5 + + msgNotify("Adding user \"%s\"...", uname); + + pipe (pfd); + if ((pid = fork()) == 0) + { + /* The kiddy. */ + dup2(pfd[1], 1); + dup2(pfd[1], 2); + for (i = getdtablesize(); i > 2; i--) + close(i); + + vec[i = VEC_UNAME] = uname; + i++; + vec[i++] = "-g"; + vec[i++] = ugroup; +#define ADDVEC(var, option) do { if (strlen(var) > 0) { vec[i++] = option; vec[i++] = var; } } while (0) + ADDVEC(uid, "-u"); + ADDVEC(gecos, "-c"); + ADDVEC(homedir, "-h"); + ADDVEC(shell, "-s"); + ADDVEC(umemb, "-G"); + vec[i] = 0; + + chroot(variable_get(VAR_INSTALL_ROOT)); + execv("/usr/sbin/pw", vec); + msgDebug("Cannot execv() /usr/sbin/pw.\n"); + _exit(99); + } + else + { + /* The oldie. */ + close(pfd[1]); + amnt = sizeof tmp; + i = 0; + while((l = read(pfd[0], &tmp[i], amnt)) > 0) + { + amnt -= l; + i += l; + if (amnt == 0) + { + close(pfd[0]); + break; + } + } + close(pfd[0]); + tmp[i] = '\0'; + waitpid(pid, &i, 0); + if (WIFSIGNALED(i)) + msgDebug("pw(8) exited with signal %d.\n", WTERMSIG(i)); + else if(WEXITSTATUS(i)) + { + i = 0; + if(strncmp(tmp, "pw: ", 4) == 0) + i = 4; + tmp[sizeof tmp - 1] = '\0'; /* sanity */ + msgConfirm("The `pw' command exited with an error status.\n" + "Its error message was:\n\n%s", + &tmp[i]); + } + else + msgConfirm("You will need to enter a password for this user\n" + "later, using the passwd(1) command from the shell.\n\n" + "The account for `%s' is currently still disabled.", + uname); + } +} + +int +userAddUser(dialogMenuItem *self) +{ + WINDOW *ds_win, *save; + ComposeObj *obj = NULL; + ComposeObj *first, *last; + int n=0, quit=FALSE, cancel=FALSE, ret; + int max; + char help[FILENAME_MAX]; + + if (RunningAsInit && !strstr(variable_get(SYSTEM_STATE), "install")) { + msgConfirm("This option may only be used after the system is installed, sorry!"); + return DITEM_FAILURE; + } + + save = savescr(); + dialog_clear_norefresh(); + /* We need a curses window */ + ds_win = newwin(LINES, COLS, 0, 0); + if (ds_win == 0) + msgFatal("Cannot open AddUser dialog window!!"); + + /* Say where our help comes from */ + use_helpfile(systemHelpFile(USER_HELPFILE, help)); + + /* Setup a nice screen for us to splat stuff onto */ + draw_box(ds_win, USER_DIALOG_Y, USER_DIALOG_X, USER_DIALOG_HEIGHT, USER_DIALOG_WIDTH, + dialog_attr, border_attr); + wattrset(ds_win, dialog_attr); + mvwaddstr(ds_win, USER_DIALOG_Y, USER_DIALOG_X + 18, " Users and Group Management "); + draw_box(ds_win, USER_DIALOG_Y + 1, USER_DIALOG_X + 3, USER_DIALOG_HEIGHT - 5, + USER_DIALOG_WIDTH - 6, dialog_attr, border_attr); + wattrset(ds_win, dialog_attr); + mvwaddstr(ds_win, USER_DIALOG_Y + 1, USER_DIALOG_X + 22, " Add a new user "); + + CLEAR(uname); + CLEAR(uid); + CLEAR(ugroup); + CLEAR(gecos); + CLEAR(umemb); + CLEAR(homedir); + CLEAR(shell); + + /* Loop over the layout list, create the objects, and add them + onto the chain of objects that dialog uses for traversal*/ + n = 0; +#define lt userLayout[n] + while (lt.help != NULL) { + switch (lt.type) { + case STRINGOBJ: + lt.obj = NewStringObj(ds_win, lt.prompt, lt.var, + lt.y + USER_DIALOG_Y, lt.x + USER_DIALOG_X, + lt.len, lt.maxlen); + break; + + case BUTTONOBJ: + lt.obj = NewButtonObj(ds_win, lt.prompt, lt.var, + lt.y + USER_DIALOG_Y, lt.x + USER_DIALOG_X); + break; + + default: + msgFatal("Don't support this object yet!"); + } + AddObj(&obj, lt.type, (void *) lt.obj); + n++; + } + max = n - 1; + + /* Find the last object we can traverse to */ + last = obj; + while (last->next) + last = last->next; + + /* Find the first object in the list */ + first = obj; + for (first = obj; first->prev; first = first->prev); + + /* Some more initialisation before we go into the main input loop */ + n = 0; + cancelbutton = okbutton = 0; + + /* Incoming user data - DUCK! */ + while (!quit) { + char help_line[80]; + int i, len = strlen(lt.help); + + /* Display the help line at the bottom of the screen */ + for (i = 0; i < 79; i++) + help_line[i] = (i < len) ? lt.help[i] : ' '; + help_line[i] = '\0'; + use_helpline(help_line); + display_helpline(ds_win, LINES - 1, COLS - 1); + + /* Ask for libdialog to do its stuff */ + ret = PollObj(&obj); + + /* Handle special case stuff that libdialog misses. Sigh */ + switch (ret) { + /* Bail out */ + case SEL_ESC: + quit = TRUE, cancel=TRUE; + break; + + /* This doesn't work for list dialogs. Oh well. Perhaps + should special case the move from the OK button ``up'' + to make it go to the interface list, but then it gets + awkward for the user to go back and correct screw up's + in the per-interface section */ + + case KEY_DOWN: + case SEL_TAB: + case SEL_CR: + if (n < max) + ++n; + else + n = 0; + break; + + /* The user has pressed enter over a button object */ + case SEL_BUTTON: + if (cancelbutton) + cancel = TRUE, quit = TRUE; + else { + if (verifyUserSettings(ds_win)) + quit = TRUE; + } + break; + + case KEY_UP: + case SEL_BACKTAB: + if (n) + --n; + else + n = max; + break; + + case KEY_F(1): + display_helpfile(); + + /* They tried some key combination we don't support - tell them! */ + default: + beep(); + } + } +#undef lt + + /* Clear this crap off the screen */ + dialog_clear_norefresh(); + use_helpfile(NULL); + + if (!cancel) { + addUser(ds_win); + restorescr(save); + return DITEM_SUCCESS; + } + restorescr(save); + return DITEM_FAILURE; +} + diff --git a/usr.sbin/sade/Makefile b/usr.sbin/sade/Makefile index b09ec9994d6e..10abd4cadd92 100644 --- a/usr.sbin/sade/Makefile +++ b/usr.sbin/sade/Makefile @@ -11,7 +11,7 @@ SRCS= anonFTP.c apache.c attr.c cdrom.c command.c config.c devices.c \ ftp_strat.c globals.c index.c install.c installUpgrade.c \ keymap.c label.c lndir.c main.c makedevs.c media.c menus.c misc.c \ msg.c network.c nfs.c options.c package.c samba.c system.c \ - tape.c tcpip.c termcap.c ufs.c variable.c wizard.c \ + tape.c tcpip.c termcap.c ufs.c user.c variable.c wizard.c \ uc_eisa.c uc_isa.c uc_kmem.c uc_list.c uc_main.c uc_pci.c \ uc_scsi.c @@ -23,7 +23,6 @@ CFLAGS+= -DUC_PRIVATE -DKERN_NO_SYMBOLS -DSAVE_USERCONFIG DPADD= ${LIBDIALOG} ${LIBNCURSES} ${LIBMYTINFO} ${LIBUTIL} ${LIBDISK} LDADD= -ldialog -lncurses -lmytinfo -lutil -ldisk - makedevs.c: Makefile rtermcap keymap.h rm -f makedevs.tmp echo '#include <sys/types.h>' > makedevs.tmp diff --git a/usr.sbin/sade/menus.c b/usr.sbin/sade/menus.c index dc20fcfb82f3..348c6b4a0e4d 100644 --- a/usr.sbin/sade/menus.c +++ b/usr.sbin/sade/menus.c @@ -4,7 +4,7 @@ * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * - * $Id: menus.c,v 1.98 1996/11/29 23:52:20 jkh Exp $ + * $Id: menus.c,v 1.99 1996/12/08 12:27:57 jkh Exp $ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. @@ -207,8 +207,7 @@ DMenu MenuIndex = { "Leave the index page by selecting Cancel [TAB-ENTER].", "Use PageUp or PageDown to move through this menu faster!", NULL, - { { "Add User", "Add users to the system.", NULL, dmenuSystemCommand, NULL, "adduser -config_create ; adduser -s" }, - { "Anon FTP", "Configure anonymous FTP logins.", dmenuVarCheck, configAnonFTP, NULL, "anon_ftp" }, + { { "Anon FTP", "Configure anonymous FTP logins.", dmenuVarCheck, configAnonFTP, NULL, "anon_ftp" }, { "Commit", "Commit any pending actions (dangerous!)", NULL, installCustomCommit }, { "Console settings", "Customize system console behavior.", NULL, dmenuSubmenu, NULL, &MenuSyscons }, { "Configure", "The system configuration menu.", NULL, dmenuSubmenu, NULL, &MenuConfigure }, @@ -269,6 +268,7 @@ DMenu MenuIndex = { { "Time Zone", "Set the system's time zone.", NULL, dmenuSystemCommand, NULL, "rm -f /etc/wall_cmos_clock /etc/localtime; tzsetup" }, { "Upgrade", "Upgrade an existing system.", NULL, installUpgrade }, { "Usage", "Quick start - How to use this menu system.", NULL, dmenuDisplayFile, NULL, "usage" }, + { "User Management", "Add user and group information.", NULL, dmenuSubmenu, NULL, &MenuUsermgmt }, { "WEB Server", "Configure host as a WWW server.", dmenuVarCheck, configApache, NULL, "apache_httpd" }, { "XFree86, Fonts", "XFree86 Font selection menu.", NULL, dmenuSubmenu, NULL, &MenuXF86SelectFonts }, { "XFree86, Server", "XFree86 Server selection menu.", NULL, dmenuSubmenu, NULL, &MenuXF86SelectServer }, @@ -1008,8 +1008,8 @@ DMenu MenuConfigure = { "software not provided in the base distributions.", "Press F1 for more information on these options", "configure", - { { "1 Add User", "Add users to the system", - NULL, dmenuSystemCommand, NULL, "adduser -config_create ; adduser -s" }, + { { "1 User Management", "Add user and group information", + NULL, dmenuSubmenu, NULL, &MenuUsermgmt }, { "2 Console", "Customize system console behavior", NULL, dmenuSubmenu, NULL, &MenuSyscons }, { "3 Time Zone", "Set which time zone you're in", @@ -1268,3 +1268,16 @@ DMenu MenuSysconsFont = { "font8x8=koi8-r-8x8,font8x14=koi8-r-8x14,font8x16=koi8-r-8x16" }, { NULL } }, }; + +DMenu MenuUsermgmt = { + DMENU_NORMAL_TYPE, + "User and group management", + "The submenus here allow to manipulate user groups and\n" + "login accounts.\n", + "Configure your user groups and users", + NULL, + { { "Add group", "Add a new user group to the system.", NULL, userAddGroup }, + { "Add user", "Add a new user to the system.", NULL, userAddUser }, + { "Exit", "Exit this menu (returning to previous)", NULL, dmenuExit }, + { NULL } }, +}; diff --git a/usr.sbin/sade/sade.h b/usr.sbin/sade/sade.h index b24257736201..ddc81116c41a 100644 --- a/usr.sbin/sade/sade.h +++ b/usr.sbin/sade/sade.h @@ -4,7 +4,7 @@ * This is probably the last attempt in the `sysinstall' line, the next * generation being slated to essentially a complete rewrite. * - * $Id: sysinstall.h,v 1.86 1996/11/09 16:47:08 joerg Exp $ + * $Id: sysinstall.h,v 1.87 1996/11/09 18:12:17 jkh Exp $ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. @@ -342,6 +342,7 @@ extern DMenu MenuXF86SelectPC98Server; /* XFree86 server distribution menu */ extern DMenu MenuXF86SelectFonts; /* XFree86 font selection menu */ extern DMenu MenuDiskDevices; /* Disk devices menu */ extern DMenu MenuHTMLDoc; /* HTML Documentation menu */ +extern DMenu MenuUsermgmt; /* User management menu */ /*** Prototypes ***/ @@ -631,6 +632,10 @@ extern void mediaShutdownUFS(Device *dev); extern Boolean mediaInitUFS(Device *dev); extern int mediaGetUFS(Device *dev, char *file, Boolean probe); +/* user.c */ +extern int userAddGroup(dialogMenuItem *self); +extern int userAddUser(dialogMenuItem *self); + /* variable.c */ extern void variable_set(char *var); extern void variable_set2(char *name, char *value); diff --git a/usr.sbin/sade/system.c b/usr.sbin/sade/system.c index c6580abf9d53..86e3a04059b5 100644 --- a/usr.sbin/sade/system.c +++ b/usr.sbin/sade/system.c @@ -4,7 +4,7 @@ * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * - * $Id: system.c,v 1.65 1996/10/01 04:56:34 jkh Exp $ + * $Id: system.c,v 1.66 1996/10/01 12:13:29 jkh Exp $ * * Jordan Hubbard * @@ -292,7 +292,7 @@ systemCreateHoloshell(void) struct termios foo; extern int login_tty(int); - for (i = 0; i < 64; i++) + for (i = getdtablesize(); i; i--) close(i); DebugFD = fd = open("/dev/ttyv3", O_RDWR); ioctl(0, TIOCSCTTY, &fd); diff --git a/usr.sbin/sysinstall/Makefile b/usr.sbin/sysinstall/Makefile index b09ec9994d6e..10abd4cadd92 100644 --- a/usr.sbin/sysinstall/Makefile +++ b/usr.sbin/sysinstall/Makefile @@ -11,7 +11,7 @@ SRCS= anonFTP.c apache.c attr.c cdrom.c command.c config.c devices.c \ ftp_strat.c globals.c index.c install.c installUpgrade.c \ keymap.c label.c lndir.c main.c makedevs.c media.c menus.c misc.c \ msg.c network.c nfs.c options.c package.c samba.c system.c \ - tape.c tcpip.c termcap.c ufs.c variable.c wizard.c \ + tape.c tcpip.c termcap.c ufs.c user.c variable.c wizard.c \ uc_eisa.c uc_isa.c uc_kmem.c uc_list.c uc_main.c uc_pci.c \ uc_scsi.c @@ -23,7 +23,6 @@ CFLAGS+= -DUC_PRIVATE -DKERN_NO_SYMBOLS -DSAVE_USERCONFIG DPADD= ${LIBDIALOG} ${LIBNCURSES} ${LIBMYTINFO} ${LIBUTIL} ${LIBDISK} LDADD= -ldialog -lncurses -lmytinfo -lutil -ldisk - makedevs.c: Makefile rtermcap keymap.h rm -f makedevs.tmp echo '#include <sys/types.h>' > makedevs.tmp diff --git a/usr.sbin/sysinstall/help/usermgmt.hlp b/usr.sbin/sysinstall/help/usermgmt.hlp new file mode 100644 index 000000000000..3798b490f7a1 --- /dev/null +++ b/usr.sbin/sysinstall/help/usermgmt.hlp @@ -0,0 +1,91 @@ +These screens allow you to add groups and users to your system. + +You can move through the fields with the TAB, BACK-TAB and RETURN +keys. To edit a field, use DELETE or BACKSPACE. You may also use ^A +(control-A) to go to the beginning of the line, ^E (control-E) to go +to the end, ^F (control-F) to go forward a character, ^B (control-B) +to go backward one character, ^D (control-D) to delete the character +under the cursor and ^K (control-K) to delete to the end of the line. +Basically, the standard EMACS motion sequences. + +When you're done with this form, select OK. + + +User groups +=========== + +It's certainly almost generally a good idea to first create a new +group for your users. Common names for such a group are "users", or +even simply "other". Group names are used to control file access +permissions for users that belong to the same group. Several group +names are already used for system files. + +The numerical user or group IDs are often nothing you want to care for +explicitly. If you don't fill in these fields, the system will chose +reasonable defaults. However, these numbers (rather than the +associated names) are what the operating system actually uses to +distinguish users and groups -- hence they should normally be unique +to each person or group, respectively. + +(The initial membership list for a new group is currently +unimplemented, sorry.) + + +Users +===== + +The user's login ID is a short (8 characters) alphanumeric ID the user +must enter when logging into the system. It's often the initial +letters of the user's name, and commonly used in lower case. It's +also the local mail name for this user (though it's possible to also +setup more descriptive mail alias names later). + +The user's login group determines which group access rights the user +will initally get when logging in. If an additional list of groups is +provided where the user will become a member of, (s)he will also be +able to access files of those groups later without providing any +additional password etc. Except for the "wheel" case mentioned below, +the additional group membership list should normally not contain the +login group again. + +Some of the system's groups have a special meaning. In particular, +members of group "wheel" are the only people who are later allowed to +become superuser using the command su(1). So if you're going to add a +new user who should later perform administrative tasks, don't forget +to add him to this group! (Well, ``he'' will most likely be yourself +in the very first place. :) + +Also, members of group "operator" will by default get permissions for +minor administrative operations, like performing system backups, or +shutting down the system -- without first becoming superuser! So, +take care with adding people to this group. + +The ``full name'' field serves as a comment only. It is also used by +mail frontends to determine the real name of the user, hence you +should actually fill in the first and last name of this user. By +convention, this field can be divided into comma-separated subfields, +where the office location, the work phone number, and the home phone +number follow the full name of the user. + +The home directory is the directory in the filesystem where the user +is being logged into, and where his personalized setup files (``dot +files'', since they usually begin with a `.' and are not displayed by +the ls(1) command by default) will be looked up. It is often created +under /usr/home/ or /home/. + +Finally, the shell is the user's initial command interpreter. The +default shell is /bin/sh, some users prefer the more historic +/bin/csh. Other, often more user-friendly and comfortable shells can +be found in the ports and packages collection. + + +Passwords +========= + +Note that new users will be established with no allowable password, so +they cannot login immediately. Instead, someone with superuser +privileges has to run the command ``passwd <user>'' (where <user> is +to be replaced with the actual login name for this user) on behalf of +the new user, so (s)he can enter his/her password. Since the password +won't be echoed on the screen, it must be entered twice. This should +never be done across a network, to prevent password-sniffing. diff --git a/usr.sbin/sysinstall/menus.c b/usr.sbin/sysinstall/menus.c index dc20fcfb82f3..348c6b4a0e4d 100644 --- a/usr.sbin/sysinstall/menus.c +++ b/usr.sbin/sysinstall/menus.c @@ -4,7 +4,7 @@ * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * - * $Id: menus.c,v 1.98 1996/11/29 23:52:20 jkh Exp $ + * $Id: menus.c,v 1.99 1996/12/08 12:27:57 jkh Exp $ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. @@ -207,8 +207,7 @@ DMenu MenuIndex = { "Leave the index page by selecting Cancel [TAB-ENTER].", "Use PageUp or PageDown to move through this menu faster!", NULL, - { { "Add User", "Add users to the system.", NULL, dmenuSystemCommand, NULL, "adduser -config_create ; adduser -s" }, - { "Anon FTP", "Configure anonymous FTP logins.", dmenuVarCheck, configAnonFTP, NULL, "anon_ftp" }, + { { "Anon FTP", "Configure anonymous FTP logins.", dmenuVarCheck, configAnonFTP, NULL, "anon_ftp" }, { "Commit", "Commit any pending actions (dangerous!)", NULL, installCustomCommit }, { "Console settings", "Customize system console behavior.", NULL, dmenuSubmenu, NULL, &MenuSyscons }, { "Configure", "The system configuration menu.", NULL, dmenuSubmenu, NULL, &MenuConfigure }, @@ -269,6 +268,7 @@ DMenu MenuIndex = { { "Time Zone", "Set the system's time zone.", NULL, dmenuSystemCommand, NULL, "rm -f /etc/wall_cmos_clock /etc/localtime; tzsetup" }, { "Upgrade", "Upgrade an existing system.", NULL, installUpgrade }, { "Usage", "Quick start - How to use this menu system.", NULL, dmenuDisplayFile, NULL, "usage" }, + { "User Management", "Add user and group information.", NULL, dmenuSubmenu, NULL, &MenuUsermgmt }, { "WEB Server", "Configure host as a WWW server.", dmenuVarCheck, configApache, NULL, "apache_httpd" }, { "XFree86, Fonts", "XFree86 Font selection menu.", NULL, dmenuSubmenu, NULL, &MenuXF86SelectFonts }, { "XFree86, Server", "XFree86 Server selection menu.", NULL, dmenuSubmenu, NULL, &MenuXF86SelectServer }, @@ -1008,8 +1008,8 @@ DMenu MenuConfigure = { "software not provided in the base distributions.", "Press F1 for more information on these options", "configure", - { { "1 Add User", "Add users to the system", - NULL, dmenuSystemCommand, NULL, "adduser -config_create ; adduser -s" }, + { { "1 User Management", "Add user and group information", + NULL, dmenuSubmenu, NULL, &MenuUsermgmt }, { "2 Console", "Customize system console behavior", NULL, dmenuSubmenu, NULL, &MenuSyscons }, { "3 Time Zone", "Set which time zone you're in", @@ -1268,3 +1268,16 @@ DMenu MenuSysconsFont = { "font8x8=koi8-r-8x8,font8x14=koi8-r-8x14,font8x16=koi8-r-8x16" }, { NULL } }, }; + +DMenu MenuUsermgmt = { + DMENU_NORMAL_TYPE, + "User and group management", + "The submenus here allow to manipulate user groups and\n" + "login accounts.\n", + "Configure your user groups and users", + NULL, + { { "Add group", "Add a new user group to the system.", NULL, userAddGroup }, + { "Add user", "Add a new user to the system.", NULL, userAddUser }, + { "Exit", "Exit this menu (returning to previous)", NULL, dmenuExit }, + { NULL } }, +}; diff --git a/usr.sbin/sysinstall/network.c b/usr.sbin/sysinstall/network.c index e0d46810e931..c416f59b0c27 100644 --- a/usr.sbin/sysinstall/network.c +++ b/usr.sbin/sysinstall/network.c @@ -4,7 +4,7 @@ * This is probably the last attempt in the `sysinstall' line, the next * generation being slated to essentially a complete rewrite. * - * $Id: network.c,v 1.16 1996/08/03 10:11:26 jkh Exp $ + * $Id: network.c,v 1.17 1996/12/08 12:27:58 jkh Exp $ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. @@ -16,6 +16,7 @@ * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. + * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. @@ -92,6 +93,11 @@ mediaInitNetwork(Device *dev) return FALSE; else strcpy(attach, val); + /* + * Doing this with vsystem() is actually bogus since we should be storing the pid of slattach + * in dev->private for later killing. It's just too convenient to call vsystem(), however, + * rather than constructing a proper argument for exec() so we punt on doing slip right for now. + */ if (vsystem(attach)) { msgConfirm("slattach returned a bad status! Please verify that\n" "the command is correct and try again."); diff --git a/usr.sbin/sysinstall/sysinstall.h b/usr.sbin/sysinstall/sysinstall.h index b24257736201..ddc81116c41a 100644 --- a/usr.sbin/sysinstall/sysinstall.h +++ b/usr.sbin/sysinstall/sysinstall.h @@ -4,7 +4,7 @@ * This is probably the last attempt in the `sysinstall' line, the next * generation being slated to essentially a complete rewrite. * - * $Id: sysinstall.h,v 1.86 1996/11/09 16:47:08 joerg Exp $ + * $Id: sysinstall.h,v 1.87 1996/11/09 18:12:17 jkh Exp $ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. @@ -342,6 +342,7 @@ extern DMenu MenuXF86SelectPC98Server; /* XFree86 server distribution menu */ extern DMenu MenuXF86SelectFonts; /* XFree86 font selection menu */ extern DMenu MenuDiskDevices; /* Disk devices menu */ extern DMenu MenuHTMLDoc; /* HTML Documentation menu */ +extern DMenu MenuUsermgmt; /* User management menu */ /*** Prototypes ***/ @@ -631,6 +632,10 @@ extern void mediaShutdownUFS(Device *dev); extern Boolean mediaInitUFS(Device *dev); extern int mediaGetUFS(Device *dev, char *file, Boolean probe); +/* user.c */ +extern int userAddGroup(dialogMenuItem *self); +extern int userAddUser(dialogMenuItem *self); + /* variable.c */ extern void variable_set(char *var); extern void variable_set2(char *name, char *value); diff --git a/usr.sbin/sysinstall/system.c b/usr.sbin/sysinstall/system.c index c6580abf9d53..86e3a04059b5 100644 --- a/usr.sbin/sysinstall/system.c +++ b/usr.sbin/sysinstall/system.c @@ -4,7 +4,7 @@ * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * - * $Id: system.c,v 1.65 1996/10/01 04:56:34 jkh Exp $ + * $Id: system.c,v 1.66 1996/10/01 12:13:29 jkh Exp $ * * Jordan Hubbard * @@ -292,7 +292,7 @@ systemCreateHoloshell(void) struct termios foo; extern int login_tty(int); - for (i = 0; i < 64; i++) + for (i = getdtablesize(); i; i--) close(i); DebugFD = fd = open("/dev/ttyv3", O_RDWR); ioctl(0, TIOCSCTTY, &fd); diff --git a/usr.sbin/sysinstall/user.c b/usr.sbin/sysinstall/user.c new file mode 100644 index 000000000000..e87ac7cba2b9 --- /dev/null +++ b/usr.sbin/sysinstall/user.c @@ -0,0 +1,750 @@ +/* + * $Id$ + * + * Copyright (c) 1996 + * Jörg Wunsch. All rights reserved. + * + * The basic structure has been taken from tcpip.c, which is: + * + * Copyright (c) 1995 + * Gary J Palmer. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * verbatim and that no modifications are made prior to this + * point in the file. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/param.h> +#include <string.h> +#include <dialog.h> +#include "ui_objects.h" +#include "dir.h" +#include "dialog.priv.h" +#include "colors.h" +#include "sysinstall.h" + +/* The help file for the user mgmt screen */ +#define USER_HELPFILE "usermgmt" + +/* XXX should they be moved out to sysinstall.h? */ +#define GNAME_FIELD_LEN 32 +#define GID_FIELD_LEN 10 +#define GMEMB_FIELD_LEN 64 + +#define UNAME_FIELD_LEN 32 +#define UID_FIELD_LEN 10 +#define UGROUP_FIELD_LEN GNAME_FIELD_LEN +#define GECOS_FIELD_LEN 64 +#define UMEMB_FIELD_LEN GMEMB_FIELD_LEN +#define HOMEDIR_FIELD_LEN 48 +#define SHELL_FIELD_LEN 48 + +/* These are nasty, but they make the layout structure a lot easier ... */ + +static char gname[GNAME_FIELD_LEN], + gid[GID_FIELD_LEN], + gmemb[GMEMB_FIELD_LEN], + uname[UNAME_FIELD_LEN], + uid[UID_FIELD_LEN], + ugroup[UGROUP_FIELD_LEN], + gecos[GECOS_FIELD_LEN], + umemb[UMEMB_FIELD_LEN], + homedir[HOMEDIR_FIELD_LEN], + shell[SHELL_FIELD_LEN]; +#define CLEAR(v) memset(v, 0, sizeof v) + +static int okbutton, cancelbutton; + + +/* What the screen size is meant to be */ +#define USER_DIALOG_Y 0 +#define USER_DIALOG_X 8 +#define USER_DIALOG_WIDTH COLS - 16 +#define USER_DIALOG_HEIGHT LINES - 2 + +/* The screen layout structure */ +typedef struct _layout { + int y; /* x & Y co-ordinates */ + int x; + int len; /* The size of the dialog on the screen */ + int maxlen; /* How much the user can type in ... */ + char *prompt; /* The string for the prompt */ + char *help; /* The display for the help line */ + void *var; /* The var to set when this changes */ + int type; /* The type of the dialog to create */ + void *obj; /* The obj pointer returned by libdialog */ +} Layout; + +/* The group configuration menu. */ +static Layout groupLayout[] = { +{ 4, 10, 20, GNAME_FIELD_LEN - 1, + "Group name:", "The alphanumeric name of the new group (mandatory)", + gname, STRINGOBJ, NULL }, +#define LAYOUT_GNAME 0 +{ 4, 38, 10, GID_FIELD_LEN - 1, + "GID:", "The numerical ID for this group (leave blank for automatic choice)", + gid, STRINGOBJ, NULL }, +#define LAYOUT_GID 1 +{ 11, 10, 40, GMEMB_FIELD_LEN - 1, + "Group members:", "Who belongs to this group (i.e., gets access rights for it)", + gmemb, STRINGOBJ, NULL }, +#define LAYOUT_GMEMB 2 +{ 18, 15, 0, 0, + "OK", "Select this if you are happy with these settings", + &okbutton, BUTTONOBJ, NULL }, +#define LAYOUT_OKBUTTON 3 +{ 18, 35, 0, 0, + "CANCEL", "Select this if you wish to cancel this screen", + &cancelbutton, BUTTONOBJ, NULL }, +#define LAYOUT_CANCELBUTTON 4 + +{ NULL }, +}; + +/* The user configuration menu. */ +static Layout userLayout[] = { +{ 3, 6, 20, UNAME_FIELD_LEN - 1, + "Login ID:", "The login name of the new user (mandatory)", + uname, STRINGOBJ, NULL }, +#define LAYOUT_UNAME 0 +{ 3, 29, 10, UID_FIELD_LEN - 1, + "UID:", "The numerical ID for this user (leave blank for automatic choice)", + uid, STRINGOBJ, NULL }, +#define LAYOUT_UID 1 +{ 3, 43, 15, UGROUP_FIELD_LEN - 1, + "Group:", "The login group name for this user (mandatory)", + ugroup, STRINGOBJ, NULL }, +#define LAYOUT_UGROUP 2 +{ 8, 6, 33, GECOS_FIELD_LEN - 1, + "Full name:", "The user's full name (comment)", + gecos, STRINGOBJ, NULL }, +#define LAYOUT_GECOS 3 +{ 8, 43, 15, UMEMB_FIELD_LEN - 1, + "Member groups:", "The groups this user belongs to (i.e. gets access rights for)", + umemb, STRINGOBJ, NULL }, +#define LAYOUT_UMEMB 4 +{ 13, 6, 20, HOMEDIR_FIELD_LEN - 1, + "Home directory:", "The user's home directory (leave blank for default)", + homedir, STRINGOBJ, NULL }, +#define LAYOUT_HOMEDIR 5 +{ 13, 29, 29, SHELL_FIELD_LEN - 1, + "Login shell:", "The user's login shell (leave blank for default)", + shell, STRINGOBJ, NULL }, +#define LAYOUT_SHELL 6 +{ 18, 15, 0, 0, + "OK", "Select this if you are happy with these settings", + &okbutton, BUTTONOBJ, NULL }, +#define LAYOUT_U_OKBUTTON 7 +{ 18, 35, 0, 0, + "CANCEL", "Select this if you wish to cancel this screen", + &cancelbutton, BUTTONOBJ, NULL }, +#define LAYOUT_U_CANCELBUTTON 8 + +{ NULL }, +}; + +/* whine */ +static void +feepout(char *msg) +{ + beep(); + dialog_notify(msg); +} + +/* Check for the settings on the screen. */ + +static int +verifyGroupSettings(void) +{ + char tmp[256], *cp; + long lgid; + + if (strlen(gname) == 0) { + feepout("The group name field must not be empty!"); + return 0; + } + snprintf(tmp, 256, "pw group show -q -n %s > /dev/null", gname); + if (vsystem(tmp) == 0) { + feepout("This group name is already in use."); + return 0; + } + if (strlen(gid) > 0) { + lgid = strtol(gid, &cp, 10); + if (lgid < 0 || lgid >= 65536 || (*cp != '\0' && !isspace(*cp))) { + feepout("The GID must be a number between 1 and 65535."); + return 0; + } + } + if (strlen(gmemb) > 0) { + if (strpbrk(gmemb, " \t") != NULL) { + feepout("The group member list must not contain any whitespace;\n" + "use commas to separate the names."); + return 0; + } +#ifndef notyet /* XXX */ + feepout("Sorry, this feature is currently not yet implemented.\n"); + return 0; +#endif + } + + return 1; +} + +static void +addGroup(WINDOW *ds_win) +{ + char tmp[256]; + int pfd[2], i; + ssize_t l; + size_t amnt; + pid_t pid; + char *vec[8] = + { + "pw", "group", "add", "-n", 0, "-g", 0, 0 + }; +#define VEC_GNAME 4 +#define VEC_GID 6 + + msgNotify("Adding group \"%s\"...", gname); + + pipe (pfd); + if ((pid = fork()) == 0) + { + /* The kiddy. */ + dup2(pfd[1], 1); + dup2(pfd[1], 2); + for (i = getdtablesize(); i > 2; i--) + close(i); + + vec[VEC_GNAME] = gname; + + if (strlen(gid) > 0) + vec[VEC_GID] = gid; + else + vec[VEC_GID - 1] = 0; + + chroot(variable_get(VAR_INSTALL_ROOT)); + execv("/usr/sbin/pw", vec); + msgDebug("Cannot execv() /usr/sbin/pw.\n"); + _exit(99); + } + else + { + /* The oldie. */ + close(pfd[1]); + amnt = sizeof tmp; + i = 0; + while((l = read(pfd[0], &tmp[i], amnt)) > 0) + { + amnt -= l; + i += l; + if (amnt == 0) + { + close(pfd[0]); + break; + } + } + close(pfd[0]); + tmp[i] = '\0'; + waitpid(pid, &i, 0); + if (WIFSIGNALED(i)) + msgDebug("pw(8) exited with signal %d.\n", WTERMSIG(i)); + else if(WEXITSTATUS(i)) + { + i = 0; + if(strncmp(tmp, "pw: ", 4) == 0) + i = 4; + tmp[sizeof tmp - 1] = '\0'; /* sanity */ + msgConfirm("The `pw' command exited with an error status.\n" + "Its error message was:\n\n%s", + &tmp[i]); + } + } +} + +int +userAddGroup(dialogMenuItem *self) +{ + WINDOW *ds_win, *save; + ComposeObj *obj = NULL; + ComposeObj *first, *last; + int n=0, quit=FALSE, cancel=FALSE, ret; + int max; + char help[FILENAME_MAX]; + + if (RunningAsInit && !strstr(variable_get(SYSTEM_STATE), "install")) { + msgConfirm("This option may only be used after the system is installed, sorry!"); + return DITEM_FAILURE; + } + + save = savescr(); + dialog_clear_norefresh(); + /* We need a curses window */ + ds_win = newwin(LINES, COLS, 0, 0); + if (ds_win == 0) + msgFatal("Cannot open AddGroup dialog window!!"); + + /* Say where our help comes from */ + use_helpfile(systemHelpFile(USER_HELPFILE, help)); + + /* Setup a nice screen for us to splat stuff onto */ + draw_box(ds_win, USER_DIALOG_Y, USER_DIALOG_X, USER_DIALOG_HEIGHT, USER_DIALOG_WIDTH, + dialog_attr, border_attr); + wattrset(ds_win, dialog_attr); + mvwaddstr(ds_win, USER_DIALOG_Y, USER_DIALOG_X + 18, " Users and Group Management "); + draw_box(ds_win, USER_DIALOG_Y + 2, USER_DIALOG_X + 8, USER_DIALOG_HEIGHT - 6, + USER_DIALOG_WIDTH - 17, dialog_attr, border_attr); + wattrset(ds_win, dialog_attr); + mvwaddstr(ds_win, USER_DIALOG_Y + 2, USER_DIALOG_X + 22, " Add a new group "); + + CLEAR(gname); + CLEAR(gid); + CLEAR(gmemb); + + /* Loop over the layout list, create the objects, and add them + onto the chain of objects that dialog uses for traversal*/ + n = 0; +#define lt groupLayout[n] + while (lt.help != NULL) { + switch (lt.type) { + case STRINGOBJ: + lt.obj = NewStringObj(ds_win, lt.prompt, lt.var, + lt.y + USER_DIALOG_Y, lt.x + USER_DIALOG_X, + lt.len, lt.maxlen); + break; + + case BUTTONOBJ: + lt.obj = NewButtonObj(ds_win, lt.prompt, lt.var, + lt.y + USER_DIALOG_Y, lt.x + USER_DIALOG_X); + break; + + default: + msgFatal("Don't support this object yet!"); + } + AddObj(&obj, lt.type, (void *) lt.obj); + n++; + } + max = n - 1; + + /* Find the last object we can traverse to */ + last = obj; + while (last->next) + last = last->next; + + /* Find the first object in the list */ + first = obj; + for (first = obj; first->prev; first = first->prev); + + /* Some more initialisation before we go into the main input loop */ + n = 0; + cancelbutton = okbutton = 0; + + /* Incoming user data - DUCK! */ + while (!quit) { + char help_line[80]; + int i, len = strlen(lt.help); + + /* Display the help line at the bottom of the screen */ + for (i = 0; i < 79; i++) + help_line[i] = (i < len) ? lt.help[i] : ' '; + help_line[i] = '\0'; + use_helpline(help_line); + display_helpline(ds_win, LINES - 1, COLS - 1); + + /* Ask for libdialog to do its stuff */ + ret = PollObj(&obj); + + /* Handle special case stuff that libdialog misses. Sigh */ + switch (ret) { + /* Bail out */ + case SEL_ESC: + quit = TRUE, cancel=TRUE; + break; + + /* This doesn't work for list dialogs. Oh well. Perhaps + should special case the move from the OK button ``up'' + to make it go to the interface list, but then it gets + awkward for the user to go back and correct screw up's + in the per-interface section */ + + case KEY_DOWN: + case SEL_TAB: + case SEL_CR: + if (n < max) + ++n; + else + n = 0; + break; + + /* The user has pressed enter over a button object */ + case SEL_BUTTON: + if (cancelbutton) + cancel = TRUE, quit = TRUE; + else { + if (verifyGroupSettings()) + quit = TRUE; + } + break; + + case KEY_UP: + case SEL_BACKTAB: + if (n) + --n; + else + n = max; + break; + + case KEY_F(1): + display_helpfile(); + + /* They tried some key combination we don't support - tell them! */ + default: + beep(); + } + } +#undef lt + + /* Clear this crap off the screen */ + dialog_clear_norefresh(); + use_helpfile(NULL); + + if (!cancel) { + addGroup(ds_win); + restorescr(save); + return DITEM_SUCCESS; + } + restorescr(save); + return DITEM_FAILURE; +} + +/* Check for the settings on the screen. */ + +static int +verifyUserSettings(WINDOW *ds_win) +{ + char tmp[256], *cp; + long luid; + WINDOW *save; + int rv; + + if (strlen(uname) == 0) { + feepout("The user name field must not be empty!"); + return 0; + } + snprintf(tmp, 256, "pw user show -q -n %s > /dev/null", gname); + if (vsystem(tmp) == 0) { + feepout("This user name is already in use."); + return 0; + } + if (strlen(uid) > 0) { + luid = strtol(uid, &cp, 10); + if (luid < 0 || luid >= 65536 || (*cp != '\0' && !isspace(*cp))) { + feepout("The UID must be a number between 1 and 65535."); + return 0; + } + } + if (strlen(ugroup) == 0) { + feepout("The login group field must not be empty!"); + return 0; + } + snprintf(tmp, 256, "pw group show -q -n %s > /dev/null", ugroup); + if (vsystem(tmp) != 0) { + feepout("This group name does not yet exist."); + return 0; + } + if (strlen(shell) > 0) { + while((cp = getusershell()) != NULL) + if (strcmp(cp, shell) == 0) + break; + endusershell(); + if (cp == NULL) { + save = savescr(); + rv = msgYesNo("Warning:\n\n" + "The requested shell \"%s\" is not\n" + "a valid user shell.\n\n" + "Use it anyway?\n", shell); + restorescr(save); + wrefresh(ds_win); + if (rv != DITEM_SUCCESS) + return 0; + } + + } + + if (strlen(umemb) > 0) { + if (strpbrk(umemb, " \t") != NULL) { + feepout("The member groups list must not contain any whitespace;\n" + "use commas to separate the names."); + return 0; + } + } + + return 1; +} + +static void +addUser(WINDOW *ds_win) +{ + char tmp[256]; + int pfd[2], i; + ssize_t l; + size_t amnt; + pid_t pid; + /* + * Maximal list: + * pw user add -m -n uname -g grp -u uid -c comment -d homedir -s shell -G grplist + */ + char *vec[18] = + { + "pw", "user", "add", "-m", "-n", /* ... */ + }; +#define VEC_UNAME 5 + + msgNotify("Adding user \"%s\"...", uname); + + pipe (pfd); + if ((pid = fork()) == 0) + { + /* The kiddy. */ + dup2(pfd[1], 1); + dup2(pfd[1], 2); + for (i = getdtablesize(); i > 2; i--) + close(i); + + vec[i = VEC_UNAME] = uname; + i++; + vec[i++] = "-g"; + vec[i++] = ugroup; +#define ADDVEC(var, option) do { if (strlen(var) > 0) { vec[i++] = option; vec[i++] = var; } } while (0) + ADDVEC(uid, "-u"); + ADDVEC(gecos, "-c"); + ADDVEC(homedir, "-h"); + ADDVEC(shell, "-s"); + ADDVEC(umemb, "-G"); + vec[i] = 0; + + chroot(variable_get(VAR_INSTALL_ROOT)); + execv("/usr/sbin/pw", vec); + msgDebug("Cannot execv() /usr/sbin/pw.\n"); + _exit(99); + } + else + { + /* The oldie. */ + close(pfd[1]); + amnt = sizeof tmp; + i = 0; + while((l = read(pfd[0], &tmp[i], amnt)) > 0) + { + amnt -= l; + i += l; + if (amnt == 0) + { + close(pfd[0]); + break; + } + } + close(pfd[0]); + tmp[i] = '\0'; + waitpid(pid, &i, 0); + if (WIFSIGNALED(i)) + msgDebug("pw(8) exited with signal %d.\n", WTERMSIG(i)); + else if(WEXITSTATUS(i)) + { + i = 0; + if(strncmp(tmp, "pw: ", 4) == 0) + i = 4; + tmp[sizeof tmp - 1] = '\0'; /* sanity */ + msgConfirm("The `pw' command exited with an error status.\n" + "Its error message was:\n\n%s", + &tmp[i]); + } + else + msgConfirm("You will need to enter a password for this user\n" + "later, using the passwd(1) command from the shell.\n\n" + "The account for `%s' is currently still disabled.", + uname); + } +} + +int +userAddUser(dialogMenuItem *self) +{ + WINDOW *ds_win, *save; + ComposeObj *obj = NULL; + ComposeObj *first, *last; + int n=0, quit=FALSE, cancel=FALSE, ret; + int max; + char help[FILENAME_MAX]; + + if (RunningAsInit && !strstr(variable_get(SYSTEM_STATE), "install")) { + msgConfirm("This option may only be used after the system is installed, sorry!"); + return DITEM_FAILURE; + } + + save = savescr(); + dialog_clear_norefresh(); + /* We need a curses window */ + ds_win = newwin(LINES, COLS, 0, 0); + if (ds_win == 0) + msgFatal("Cannot open AddUser dialog window!!"); + + /* Say where our help comes from */ + use_helpfile(systemHelpFile(USER_HELPFILE, help)); + + /* Setup a nice screen for us to splat stuff onto */ + draw_box(ds_win, USER_DIALOG_Y, USER_DIALOG_X, USER_DIALOG_HEIGHT, USER_DIALOG_WIDTH, + dialog_attr, border_attr); + wattrset(ds_win, dialog_attr); + mvwaddstr(ds_win, USER_DIALOG_Y, USER_DIALOG_X + 18, " Users and Group Management "); + draw_box(ds_win, USER_DIALOG_Y + 1, USER_DIALOG_X + 3, USER_DIALOG_HEIGHT - 5, + USER_DIALOG_WIDTH - 6, dialog_attr, border_attr); + wattrset(ds_win, dialog_attr); + mvwaddstr(ds_win, USER_DIALOG_Y + 1, USER_DIALOG_X + 22, " Add a new user "); + + CLEAR(uname); + CLEAR(uid); + CLEAR(ugroup); + CLEAR(gecos); + CLEAR(umemb); + CLEAR(homedir); + CLEAR(shell); + + /* Loop over the layout list, create the objects, and add them + onto the chain of objects that dialog uses for traversal*/ + n = 0; +#define lt userLayout[n] + while (lt.help != NULL) { + switch (lt.type) { + case STRINGOBJ: + lt.obj = NewStringObj(ds_win, lt.prompt, lt.var, + lt.y + USER_DIALOG_Y, lt.x + USER_DIALOG_X, + lt.len, lt.maxlen); + break; + + case BUTTONOBJ: + lt.obj = NewButtonObj(ds_win, lt.prompt, lt.var, + lt.y + USER_DIALOG_Y, lt.x + USER_DIALOG_X); + break; + + default: + msgFatal("Don't support this object yet!"); + } + AddObj(&obj, lt.type, (void *) lt.obj); + n++; + } + max = n - 1; + + /* Find the last object we can traverse to */ + last = obj; + while (last->next) + last = last->next; + + /* Find the first object in the list */ + first = obj; + for (first = obj; first->prev; first = first->prev); + + /* Some more initialisation before we go into the main input loop */ + n = 0; + cancelbutton = okbutton = 0; + + /* Incoming user data - DUCK! */ + while (!quit) { + char help_line[80]; + int i, len = strlen(lt.help); + + /* Display the help line at the bottom of the screen */ + for (i = 0; i < 79; i++) + help_line[i] = (i < len) ? lt.help[i] : ' '; + help_line[i] = '\0'; + use_helpline(help_line); + display_helpline(ds_win, LINES - 1, COLS - 1); + + /* Ask for libdialog to do its stuff */ + ret = PollObj(&obj); + + /* Handle special case stuff that libdialog misses. Sigh */ + switch (ret) { + /* Bail out */ + case SEL_ESC: + quit = TRUE, cancel=TRUE; + break; + + /* This doesn't work for list dialogs. Oh well. Perhaps + should special case the move from the OK button ``up'' + to make it go to the interface list, but then it gets + awkward for the user to go back and correct screw up's + in the per-interface section */ + + case KEY_DOWN: + case SEL_TAB: + case SEL_CR: + if (n < max) + ++n; + else + n = 0; + break; + + /* The user has pressed enter over a button object */ + case SEL_BUTTON: + if (cancelbutton) + cancel = TRUE, quit = TRUE; + else { + if (verifyUserSettings(ds_win)) + quit = TRUE; + } + break; + + case KEY_UP: + case SEL_BACKTAB: + if (n) + --n; + else + n = max; + break; + + case KEY_F(1): + display_helpfile(); + + /* They tried some key combination we don't support - tell them! */ + default: + beep(); + } + } +#undef lt + + /* Clear this crap off the screen */ + dialog_clear_norefresh(); + use_helpfile(NULL); + + if (!cancel) { + addUser(ds_win); + restorescr(save); + return DITEM_SUCCESS; + } + restorescr(save); + return DITEM_FAILURE; +} + |
