summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--release/sysinstall/Makefile3
-rw-r--r--release/sysinstall/help/usermgmt.hlp91
-rw-r--r--release/sysinstall/menus.c23
-rw-r--r--release/sysinstall/network.c8
-rw-r--r--release/sysinstall/sysinstall.h7
-rw-r--r--release/sysinstall/system.c4
-rw-r--r--release/sysinstall/user.c750
-rw-r--r--usr.sbin/sade/Makefile3
-rw-r--r--usr.sbin/sade/menus.c23
-rw-r--r--usr.sbin/sade/sade.h7
-rw-r--r--usr.sbin/sade/system.c4
-rw-r--r--usr.sbin/sysinstall/Makefile3
-rw-r--r--usr.sbin/sysinstall/help/usermgmt.hlp91
-rw-r--r--usr.sbin/sysinstall/menus.c23
-rw-r--r--usr.sbin/sysinstall/network.c8
-rw-r--r--usr.sbin/sysinstall/sysinstall.h7
-rw-r--r--usr.sbin/sysinstall/system.c4
-rw-r--r--usr.sbin/sysinstall/user.c750
18 files changed, 1777 insertions, 32 deletions
diff --git a/release/sysinstall/Makefile b/release/sysinstall/Makefile
index b09ec99..10abd4c 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 0000000..3798b49
--- /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 dc20fcf..348c6b4 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 e0d4681..c416f59 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 b242577..ddc8111 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 c6580ab..86e3a04 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 0000000..e87ac7c
--- /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 b09ec99..10abd4c 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 dc20fcf..348c6b4 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 b242577..ddc8111 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 c6580ab..86e3a04 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 b09ec99..10abd4c 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 0000000..3798b49
--- /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 dc20fcf..348c6b4 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 e0d4681..c416f59 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 b242577..ddc8111 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 c6580ab..86e3a04 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 0000000..e87ac7c
--- /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;
+}
+
OpenPOWER on IntegriCloud