diff options
Diffstat (limited to 'usr.sbin/sysinstall/user.c')
-rw-r--r-- | usr.sbin/sysinstall/user.c | 751 |
1 files changed, 0 insertions, 751 deletions
diff --git a/usr.sbin/sysinstall/user.c b/usr.sbin/sysinstall/user.c deleted file mode 100644 index 72b6716..0000000 --- a/usr.sbin/sysinstall/user.c +++ /dev/null @@ -1,751 +0,0 @@ -/* - * $FreeBSD$ - * - * 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. - * Jordan K Hubbard. 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 "sysinstall.h" -#include <ctype.h> -#include <sys/param.h> -#include <sysexits.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 11 -#define GMEMB_FIELD_LEN 64 -#define UNAME_FIELD_LEN MAXLOGNAME -#define UID_FIELD_LEN 11 -#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 -#define PASSWD_FIELD_LEN 32 - -/* 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], - passwd[PASSWD_FIELD_LEN], - confpasswd[PASSWD_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 - 1 - -/* The group configuration menu. */ -static Layout groupLayout[] = { -#define LAYOUT_GNAME 0 - { 4, 10, 20, GNAME_FIELD_LEN - 1, - "Group name:", "The alphanumeric name of the new group (mandatory)", - gname, STRINGOBJ, NULL }, -#define LAYOUT_GID 1 - { 4, 38, 10, GID_FIELD_LEN - 1, - "GID:", "The numerical ID for this group (leave blank for automatic choice)", - gid, STRINGOBJ, NULL }, -#define LAYOUT_GMEMB 2 - { 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_OKBUTTON 3 - { 18, 15, 0, 0, - "OK", "Select this if you are happy with these settings", - &okbutton, BUTTONOBJ, NULL }, -#define LAYOUT_CANCELBUTTON 4 - { 18, 35, 0, 0, - "CANCEL", "Select this if you wish to cancel this screen", - &cancelbutton, BUTTONOBJ, NULL }, - LAYOUT_END, -}; - -/* The user configuration menu. */ -static Layout userLayout[] = { -#define LAYOUT_UNAME 0 - { 2, 6, 16, UNAME_FIELD_LEN - 1, - "Login ID:", "The login name of the new user (mandatory)", - uname, STRINGOBJ, NULL }, -#define LAYOUT_UID 1 - { 2, 23, 8, UID_FIELD_LEN - 1, - "UID:", "The numerical ID for this user (leave blank for automatic choice)", - uid, STRINGOBJ, NULL }, -#define LAYOUT_UGROUP 2 - { 2, 33, 8, UGROUP_FIELD_LEN - 1, - "Group:", "The login group name for this user (leave blank for automatic choice)", - ugroup, STRINGOBJ, NULL }, -#define LAYOUT_PASSWD 3 - { 6, 6, 20, PASSWD_FIELD_LEN - 1, - "Password:", "The password for this user (enter this field with care!)", - passwd, NO_ECHO_OBJ(STRINGOBJ), NULL }, -#define LAYOUT_CONFPASSWD 4 - { 6, 28, 20, PASSWD_FIELD_LEN - 1, - "Confirm Password:", "Confirm what you typed for the password", - confpasswd, NO_ECHO_OBJ(STRINGOBJ), NULL }, -#define LAYOUT_GECOS 5 - { 10, 6, 33, GECOS_FIELD_LEN - 1, - "Full name:", "The user's full name (comment)", - gecos, STRINGOBJ, NULL }, -#define LAYOUT_UMEMB 6 - { 10, 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_HOMEDIR 7 - { 14, 6, 20, HOMEDIR_FIELD_LEN - 1, - "Home directory:", "The user's home directory (leave blank for default)", - homedir, STRINGOBJ, NULL }, -#define LAYOUT_SHELL 8 - { 14, 29, 29, SHELL_FIELD_LEN - 1, - "Login shell:", "The user's login shell (leave blank for default)", - shell, STRINGOBJ, NULL }, -#define LAYOUT_U_OKBUTTON 9 - { 18, 15, 0, 0, - "OK", "Select this if you are happy with these settings", - &okbutton, BUTTONOBJ, NULL }, -#define LAYOUT_U_CANCELBUTTON 10 - { 18, 35, 0, 0, - "CANCEL", "Select this if you wish to cancel this screen", - &cancelbutton, BUTTONOBJ, NULL }, - LAYOUT_END, -}; - -/* 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; - unsigned 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("%s", tmp) == 0) { - feepout("This group name is already in use."); - return 0; - } - if (strlen(gid) > 0) { - lgid = strtoul(gid, &cp, 10); - if (lgid == 0 || lgid > GID_MAX || (*cp != '\0' && !isspace(*cp))) { - feepout("The GID must be a number between 1 and 4294967295."); - 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, the group member list feature\n" - "is currently not yet implemented."); - return 0; -#endif - } - - return 1; -} - -/* - * Ask pw(8) to fill in the blanks for us. - * Works solely on the global variables. - */ - -static void -completeGroup(void) -{ - int pfd[2], i; - char tmp[256], *cp; - ssize_t l; - size_t amnt; - pid_t pid; - char *vec[4] = - { - "pw", "group", "next", 0 - }; - - pipe (pfd); - if ((pid = fork()) == 0) - { - /* The kiddy. */ - dup2(pfd[1], 1); - dup2(pfd[1], 2); - for (i = getdtablesize(); i > 2; i--) - close(i); - - 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) || WEXITSTATUS(i) != 0) - /* ignore by now */ - return; - if ((cp = strchr(tmp, '\n')) != NULL) - *cp = '\0'; - strncpy(gid, tmp, sizeof gid); - } -} - -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; - - 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]); - } - } -#undef VEC_GNAME -#undef VEC_GID -} - -int -userAddGroup(dialogMenuItem *self) -{ - WINDOW *ds_win, *save; - ComposeObj *obj = NULL; - int n = 0, cancel = FALSE, ret; - int max, firsttime = TRUE; - - 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 */ - if (!(ds_win = openLayoutDialog(USER_HELPFILE, " User and Group Management ", - USER_DIALOG_X, USER_DIALOG_Y, USER_DIALOG_WIDTH, USER_DIALOG_HEIGHT))) { - beep(); - msgConfirm("Cannot open addgroup dialog window!!"); - return(DITEM_FAILURE); - } - - /* Draw a group entry box */ - draw_box(ds_win, USER_DIALOG_Y + 2, USER_DIALOG_X + 8, USER_DIALOG_HEIGHT - 8, - 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); - - /* Some more initialisation before we go into the main input loop */ - obj = initLayoutDialog(ds_win, groupLayout, USER_DIALOG_X, USER_DIALOG_Y, &max); - -reenter: - cancelbutton = okbutton = 0; - if (firsttime) { - /* fill in the blanks, well, just the GID */ - completeGroup(); - RefreshStringObj(groupLayout[LAYOUT_GID].obj); - firsttime = FALSE; - } - - while (layoutDialogLoop(ds_win, groupLayout, &obj, &n, max, &cancelbutton, &cancel)); - - if (!cancel && !verifyGroupSettings()) - goto reenter; - - /* Clear this crap off the screen */ - delwin(ds_win); - dialog_clear_norefresh(); - use_helpfile(NULL); - - if (!cancel) { - addGroup(ds_win); - ret = DITEM_SUCCESS; - } - else - ret = DITEM_FAILURE; - restorescr(save); - return ret; -} - -/* Check for the settings on the screen. */ - -static int -verifyUserSettings(WINDOW *ds_win) -{ - char tmp[256], *cp; - unsigned 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", uname); - if (vsystem("%s", tmp) == 0) { - feepout("This user name is already in use."); - return 0; - } - if (strlen(uid) > 0) { - luid = strtoul(uid, &cp, 10); - if (luid == 0 || luid > UID_MAX || (*cp != '\0' && !isspace(*cp))) { - feepout("The UID must be a number between 1 and 4294967295."); - return 0; - } - } - if (strcmp(passwd, confpasswd)) { - feepout("Passwords don't match"); - return 0; - } - if ((homedir[0]!=0) && (homedir[0]!='/')) { - feepout("The pathname for home directories must begin with a '/'."); - return 0; - } - if (strlen(shell) > 0) { - setusershell(); - 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; -} - -/* - * Ask pw(8) to fill in the blanks for us. - * Works solely on the global variables. - */ - -static void -completeUser(void) -{ - int pfd[2], i; - char tmp[256], *cp, *cp2; - ssize_t l; - size_t amnt; - pid_t pid; - char *vec[7] = - { - "pw", "user", "add", "-N", "-n", 0, 0 - }; -#define VEC_UNAME 5 - - 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_UNAME] = uname; - - 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) || WEXITSTATUS(i) != 0) - /* ignore by now */ - return; - if ((cp = strchr(tmp, '\n')) != NULL) - *cp = '\0'; - if ((cp = strchr(tmp, ':')) == NULL || (cp = strchr(++cp, ':')) == NULL) - return; - cp++; - if ((cp2 = strchr(cp, ':')) == NULL) - return; - *cp2++ = '\0'; - strncpy(uid, cp, sizeof uid); - cp = cp2; - if ((cp2 = strchr(cp, ':')) == NULL) - return; - *cp2++ = '\0'; -#ifdef notyet /* XXX pw user add -g doesn't accept a numerical GID */ - strncpy(ugroup, cp, sizeof ugroup); -#endif - cp = cp2; - if ((cp2 = strchr(cp, ':')) == NULL || (cp2 = strchr(++cp2, ':')) == NULL || - (cp = cp2 = strchr(++cp2, ':')) == NULL || (cp2 = strchr(++cp2, ':')) == NULL) - return; - *cp2++ = '\0'; - cp++; - strncpy(gecos, cp, sizeof gecos); - cp = cp2; - if ((cp2 = strchr(cp, ':')) == NULL) - return; - *cp2++ = '\0'; - if (*cp2) - strncpy(shell, cp2, sizeof shell); - } -#undef VEC_UNAME -} - -static void -addUser(WINDOW *ds_win) -{ - char tmp[256], *msg; - int pfd[2], ipfd[2], i, j; - 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 -h 0 - */ - char *vec[21] = - { - "pw", "user", "add", "-m", "-n", /* ... */ - }; -#define VEC_UNAME 5 - - msgNotify("Adding user \"%s\"...", uname); - - pipe (pfd); - pipe (ipfd); - if ((pid = fork()) == 0) - { - /* The kiddy. */ - dup2(ipfd[0], 0); - dup2(pfd[1], 1); - dup2(pfd[1], 2); - for (i = getdtablesize(); i > 2; i--) - close(i); - - vec[i = VEC_UNAME] = uname; - i++; -#define ADDVEC(var, option) do { if (strlen(var) > 0) { vec[i++] = option; vec[i++] = var; } } while (0) - ADDVEC(ugroup, "-g"); - ADDVEC(uid, "-u"); - ADDVEC(gecos, "-c"); - ADDVEC(homedir, "-d"); - ADDVEC(shell, "-s"); - ADDVEC(umemb, "-G"); - if (passwd[0]) { - vec[i++] = "-h"; - vec[i++] = "0"; - } - vec[i] = 0; - - execv("/usr/sbin/pw", vec); - msgDebug("Cannot execv() /usr/sbin/pw.\n"); - _exit(99); - } - else - { - /* The oldie. */ - close(pfd[1]); - close(ipfd[0]); - - if (passwd[0]) - write(ipfd[1], passwd, strlen(passwd)); - close(ipfd[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)) - { - j = WTERMSIG(i); - msg = "The `pw' command exited with signal %d.\n"; - goto sysfail; - } - else if((j = WEXITSTATUS(i))) - { - i = 0; - if(strncmp(tmp, "pw: ", 4) == 0) - i = 4; - tmp[sizeof tmp - 1] = '\0'; /* sanity */ - if (j == EX_DATAERR || j == EX_NOUSER || j == EX_SOFTWARE) - msgConfirm("The `pw' command exited with an error status.\n" - "Its error message was:\n\n%s", - &tmp[i]); - else - { - msg = "The `pw' command exited with unexpected status %d.\n"; - sysfail: - msgDebug(msg, j); - msgDebug("Command stdout and stderr was:\n\n%s", tmp); - msgConfirm(msg, j); - } - } - else if (!passwd[0]) - 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); - } -#undef VEC_UNAME -#undef ADDVEC -} - -int -userAddUser(dialogMenuItem *self) -{ - WINDOW *ds_win, *save; - ComposeObj *obj = NULL; - int n = 0, cancel = FALSE, ret; - int max, firsttime = TRUE, filled=0; - - 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 */ - if (!(ds_win = openLayoutDialog(USER_HELPFILE, " User and Group Management ", - USER_DIALOG_X, USER_DIALOG_Y, USER_DIALOG_WIDTH, USER_DIALOG_HEIGHT))) { - beep(); - msgConfirm("Cannot open adduser dialog window!!"); - return(DITEM_FAILURE); - } - - /* Draw a user entry box */ - draw_box(ds_win, USER_DIALOG_Y + 1, USER_DIALOG_X + 3, USER_DIALOG_HEIGHT - 6, - USER_DIALOG_WIDTH - 6, dialog_attr, border_attr); - wattrset(ds_win, dialog_attr); - mvwaddstr(ds_win, USER_DIALOG_Y + 1, USER_DIALOG_X + 24, " Add a new user "); - - CLEAR(uname); - CLEAR(uid); - CLEAR(ugroup); - CLEAR(gecos); - CLEAR(passwd); - CLEAR(confpasswd); - CLEAR(umemb); - CLEAR(homedir); - CLEAR(shell); - - /* Some more initialisation before we go into the main input loop */ - obj = initLayoutDialog(ds_win, userLayout, USER_DIALOG_X, USER_DIALOG_Y, &max); - -reenter: - cancelbutton = okbutton = 0; - if (firsttime) { - /* fill in the blanks, well, just the GID */ - completeUser(); - RefreshStringObj(userLayout[LAYOUT_UID].obj); - RefreshStringObj(userLayout[LAYOUT_UGROUP].obj); - RefreshStringObj(userLayout[LAYOUT_GECOS].obj); - RefreshStringObj(userLayout[LAYOUT_UMEMB].obj); - RefreshStringObj(userLayout[LAYOUT_HOMEDIR].obj); - RefreshStringObj(userLayout[LAYOUT_SHELL].obj); - firsttime = FALSE; - } - - while (layoutDialogLoop(ds_win, userLayout, &obj, &n, max, &cancelbutton, &cancel)) { - /* Prevent this from being irritating if user really means NO */ - if (filled < 3) { - if ((uname[0]) && !homedir[0]) { - SAFE_STRCPY(homedir,"/home/"); - strcat(homedir,uname); - RefreshStringObj(userLayout[LAYOUT_HOMEDIR].obj); - ++filled; - } - } - }; - - if (!cancel && !verifyUserSettings(ds_win)) - goto reenter; - - /* Clear this crap off the screen */ - delwin(ds_win); - dialog_clear_norefresh(); - use_helpfile(NULL); - - if (!cancel) { - addUser(ds_win); - ret = DITEM_SUCCESS; - } - else - ret = DITEM_FAILURE; - restorescr(save); - return ret; -} - |