]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - usr.sbin/sysinstall/user.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / usr.sbin / sysinstall / user.c
1 /*
2  * $FreeBSD$
3  *
4  * Copyright (c) 1996
5  *      Jörg Wunsch. All rights reserved.
6  *
7  * The basic structure has been taken from tcpip.c, which is:
8  *
9  * Copyright (c) 1995
10  *      Gary J Palmer. All rights reserved.
11  *      Jordan K Hubbard. All rights reserved.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer,
18  *    verbatim and that no modifications are made prior to this
19  *    point in the file.
20  * 2. Redistributions in binary form must reproduce the above copyright
21  *    notice, this list of conditions and the following disclaimer in the
22  *    documentation and/or other materials provided with the distribution.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
30  * OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
32  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  *
35  */
36
37 #include "sysinstall.h"
38 #include <utmp.h>
39 #include <ctype.h>
40 #include <sys/param.h>
41 #include <sysexits.h>
42
43 /* The help file for the user mgmt screen */
44 #define USER_HELPFILE           "usermgmt"
45
46 /* XXX should they be moved out to sysinstall.h? */
47 #define GNAME_FIELD_LEN 32
48 #define GID_FIELD_LEN 11
49 #define GMEMB_FIELD_LEN 64
50
51 #define UID_FIELD_LEN 11
52 #define UGROUP_FIELD_LEN GNAME_FIELD_LEN
53 #define GECOS_FIELD_LEN 64
54 #define UMEMB_FIELD_LEN GMEMB_FIELD_LEN
55 #define HOMEDIR_FIELD_LEN 48
56 #define SHELL_FIELD_LEN 48
57 #define PASSWD_FIELD_LEN 32
58
59 /* These are nasty, but they make the layout structure a lot easier ... */
60
61 static char gname[GNAME_FIELD_LEN],
62         gid[GID_FIELD_LEN],
63         gmemb[GMEMB_FIELD_LEN],
64         uname[UT_NAMESIZE + 1],
65         passwd[PASSWD_FIELD_LEN],
66         confpasswd[PASSWD_FIELD_LEN],
67         uid[UID_FIELD_LEN],
68         ugroup[UGROUP_FIELD_LEN],
69         gecos[GECOS_FIELD_LEN],
70         umemb[UMEMB_FIELD_LEN],
71         homedir[HOMEDIR_FIELD_LEN],
72         shell[SHELL_FIELD_LEN];
73 #define CLEAR(v)        memset(v, 0, sizeof v)
74
75 static int      okbutton, cancelbutton;
76
77
78 /* What the screen size is meant to be */
79 #define USER_DIALOG_Y           0
80 #define USER_DIALOG_X           8
81 #define USER_DIALOG_WIDTH       COLS - 16
82 #define USER_DIALOG_HEIGHT      LINES - 1
83
84 /* The group configuration menu. */
85 static Layout groupLayout[] = {
86 #define LAYOUT_GNAME            0
87     { 4, 10, 20, GNAME_FIELD_LEN - 1,
88       "Group name:", "The alphanumeric name of the new group (mandatory)",
89       gname, STRINGOBJ, NULL },
90 #define LAYOUT_GID              1
91     { 4, 38, 10, GID_FIELD_LEN - 1,
92       "GID:", "The numerical ID for this group (leave blank for automatic choice)",
93       gid, STRINGOBJ, NULL },
94 #define LAYOUT_GMEMB            2
95     { 11, 10, 40, GMEMB_FIELD_LEN - 1,
96       "Group members:", "Who belongs to this group (i.e., gets access rights for it)",
97       gmemb, STRINGOBJ, NULL },
98 #define LAYOUT_OKBUTTON         3
99     { 18, 15, 0, 0,
100       "OK", "Select this if you are happy with these settings",
101       &okbutton, BUTTONOBJ, NULL },
102 #define LAYOUT_CANCELBUTTON     4
103     { 18, 35, 0, 0,
104       "CANCEL", "Select this if you wish to cancel this screen",
105       &cancelbutton, BUTTONOBJ, NULL },
106     LAYOUT_END,
107 };
108
109 /* The user configuration menu. */
110 static Layout userLayout[] = {
111 #define LAYOUT_UNAME            0
112     { 2, 6, UT_NAMESIZE, UT_NAMESIZE + 1,
113       "Login ID:", "The login name of the new user (mandatory)",
114       uname, STRINGOBJ, NULL },
115 #define LAYOUT_UID              1
116     { 2, 23, 8, UID_FIELD_LEN - 1,
117       "UID:", "The numerical ID for this user (leave blank for automatic choice)",
118       uid, STRINGOBJ, NULL },
119 #define LAYOUT_UGROUP           2
120     { 2, 33, 8, UGROUP_FIELD_LEN - 1,
121       "Group:", "The login group name for this user (leave blank for automatic choice)",
122       ugroup, STRINGOBJ, NULL },
123 #define LAYOUT_PASSWD           3
124     { 6, 6, 20, PASSWD_FIELD_LEN - 1,
125       "Password:", "The password for this user (enter this field with care!)",
126       passwd, NO_ECHO_OBJ(STRINGOBJ), NULL },
127 #define LAYOUT_CONFPASSWD       4
128     { 6, 28, 20, PASSWD_FIELD_LEN - 1,
129       "Confirm Password:", "Confirm what you typed for the password",
130       confpasswd, NO_ECHO_OBJ(STRINGOBJ), NULL },
131 #define LAYOUT_GECOS            5
132     { 10, 6, 33, GECOS_FIELD_LEN - 1,
133       "Full name:", "The user's full name (comment)",
134       gecos, STRINGOBJ, NULL },
135 #define LAYOUT_UMEMB            6
136     { 10, 43, 15, UMEMB_FIELD_LEN - 1,
137       "Member groups:", "The groups this user belongs to (i.e. gets access rights for)",
138       umemb, STRINGOBJ, NULL },
139 #define LAYOUT_HOMEDIR          7
140     { 14, 6, 20, HOMEDIR_FIELD_LEN - 1,
141       "Home directory:", "The user's home directory (leave blank for default)",
142       homedir, STRINGOBJ, NULL },
143 #define LAYOUT_SHELL            8
144     { 14, 29, 29, SHELL_FIELD_LEN - 1,
145       "Login shell:", "The user's login shell (leave blank for default)",
146       shell, STRINGOBJ, NULL },
147 #define LAYOUT_U_OKBUTTON       9
148     { 18, 15, 0, 0,
149       "OK", "Select this if you are happy with these settings",
150         &okbutton, BUTTONOBJ, NULL },
151 #define LAYOUT_U_CANCELBUTTON   10
152     { 18, 35, 0, 0,
153       "CANCEL", "Select this if you wish to cancel this screen",
154       &cancelbutton, BUTTONOBJ, NULL },
155     LAYOUT_END,
156 };
157
158 /* whine */
159 static void
160 feepout(char *msg)
161 {
162     beep();
163     dialog_notify(msg);
164 }
165
166 /* Check for the settings on the screen. */
167
168 static int
169 verifyGroupSettings(void)
170 {
171     char tmp[256], *cp;
172     unsigned long lgid;
173
174     if (strlen(gname) == 0) {
175         feepout("The group name field must not be empty!");
176         return 0;
177     }
178     snprintf(tmp, 256, "pw group show -q -n %s > /dev/null", gname);
179     if (vsystem("%s", tmp) == 0) {
180         feepout("This group name is already in use.");
181         return 0;
182     }
183     if (strlen(gid) > 0) {
184         lgid = strtoul(gid, &cp, 10);
185         if (lgid == 0 || lgid > GID_MAX || (*cp != '\0' && !isspace(*cp))) {
186             feepout("The GID must be a number between 1 and 4294967295.");
187             return 0;
188         }
189     }
190     if (strlen(gmemb) > 0) {
191         if (strpbrk(gmemb, " \t") != NULL) {
192             feepout("The group member list must not contain any whitespace;\n"
193                     "use commas to separate the names.");
194             return 0;
195         }
196 #ifndef notyet  /* XXX */
197         feepout("Sorry, the group member list feature\n"
198                 "is currently not yet implemented.");
199         return 0;
200 #endif
201     }
202
203     return 1;
204 }
205
206 /*
207  * Ask pw(8) to fill in the blanks for us.
208  * Works solely on the global variables.
209  */
210
211 static void
212 completeGroup(void)
213 {
214     int pfd[2], i;
215     char tmp[256], *cp;
216     ssize_t l;
217     size_t amnt;
218     pid_t pid;
219     char *vec[4] =
220     {
221         "pw", "group", "next", 0
222     };
223
224     pipe (pfd);
225     if ((pid = fork()) == 0)
226     {
227         /* The kiddy. */
228         dup2(pfd[1], 1);
229         dup2(pfd[1], 2);
230         for (i = getdtablesize(); i > 2; i--)
231             close(i);
232
233         execv("/usr/sbin/pw", vec);
234         msgDebug("Cannot execv() /usr/sbin/pw.\n");
235         _exit(99);
236     }
237     else
238     {
239         /* The oldie. */
240         close(pfd[1]);
241         amnt = sizeof tmp;
242         i = 0;
243         while((l = read(pfd[0], &tmp[i], amnt)) > 0)
244         {
245             amnt -= l;
246             i += l;
247             if (amnt == 0)
248             {
249                 close(pfd[0]);
250                 break;
251             }
252         }
253         close(pfd[0]);
254         tmp[i] = '\0';
255         waitpid(pid, &i, 0);
256         if (WIFSIGNALED(i) || WEXITSTATUS(i) != 0)
257             /* ignore by now */
258             return;
259         if ((cp = strchr(tmp, '\n')) != NULL)
260             *cp = '\0';
261         strncpy(gid, tmp, sizeof gid);
262     }
263 }
264
265 static void
266 addGroup(WINDOW *ds_win)
267 {
268     char tmp[256];
269     int pfd[2], i;
270     ssize_t l;
271     size_t amnt;
272     pid_t pid;
273     char *vec[8] =
274     {
275         "pw", "group", "add", "-n", 0, "-g", 0, 0
276     };
277 #define VEC_GNAME 4
278 #define VEC_GID 6
279
280     msgNotify("Adding group \"%s\"...", gname);
281
282     pipe (pfd);
283     if ((pid = fork()) == 0)
284     {
285         /* The kiddy. */
286         dup2(pfd[1], 1);
287         dup2(pfd[1], 2);
288         for (i = getdtablesize(); i > 2; i--)
289             close(i);
290
291         vec[VEC_GNAME] = gname;
292
293         if (strlen(gid) > 0)
294             vec[VEC_GID] = gid;
295         else
296             vec[VEC_GID - 1] = 0;
297
298         execv("/usr/sbin/pw", vec);
299         msgDebug("Cannot execv() /usr/sbin/pw.\n");
300         _exit(99);
301     }
302     else
303     {
304         /* The oldie. */
305         close(pfd[1]);
306         amnt = sizeof tmp;
307         i = 0;
308         while((l = read(pfd[0], &tmp[i], amnt)) > 0)
309         {
310             amnt -= l;
311             i += l;
312             if (amnt == 0)
313             {
314                 close(pfd[0]);
315                 break;
316             }
317         }
318         close(pfd[0]);
319         tmp[i] = '\0';
320         waitpid(pid, &i, 0);
321         if (WIFSIGNALED(i))
322             msgDebug("pw(8) exited with signal %d.\n", WTERMSIG(i));
323         else if(WEXITSTATUS(i))
324         {
325             i = 0;
326             if(strncmp(tmp, "pw: ", 4) == 0)
327                 i = 4;
328             tmp[sizeof tmp - 1] = '\0'; /* sanity */
329             msgConfirm("The `pw' command exited with an error status.\n"
330                        "Its error message was:\n\n%s",
331                        &tmp[i]);
332         }
333     }
334 #undef VEC_GNAME
335 #undef VEC_GID
336 }
337
338 int
339 userAddGroup(dialogMenuItem *self)
340 {
341     WINDOW              *ds_win, *save;
342     ComposeObj          *obj = NULL;
343     int                 n = 0, cancel = FALSE, ret;
344     int                 max, firsttime = TRUE;
345
346     if (RunningAsInit && !strstr(variable_get(SYSTEM_STATE), "install")) {
347         msgConfirm("This option may only be used after the system is installed, sorry!");
348         return DITEM_FAILURE;
349     }
350
351     save = savescr();
352     dialog_clear_norefresh();
353     /* We need a curses window */
354     if (!(ds_win = openLayoutDialog(USER_HELPFILE, " User and Group Management ",
355                                     USER_DIALOG_X, USER_DIALOG_Y, USER_DIALOG_WIDTH, USER_DIALOG_HEIGHT))) {
356         beep();
357         msgConfirm("Cannot open addgroup dialog window!!");
358         return(DITEM_FAILURE);
359     }
360
361     /* Draw a group entry box */
362     draw_box(ds_win, USER_DIALOG_Y + 2, USER_DIALOG_X + 8, USER_DIALOG_HEIGHT - 8,
363              USER_DIALOG_WIDTH - 17, dialog_attr, border_attr);
364     wattrset(ds_win, dialog_attr);
365     mvwaddstr(ds_win, USER_DIALOG_Y + 2, USER_DIALOG_X + 22, " Add a new group ");
366
367     CLEAR(gname);
368     CLEAR(gid);
369     CLEAR(gmemb);
370
371     /* Some more initialisation before we go into the main input loop */
372     obj = initLayoutDialog(ds_win, groupLayout, USER_DIALOG_X, USER_DIALOG_Y, &max);
373
374 reenter:
375     cancelbutton = okbutton = 0;
376     if (firsttime) {
377         /* fill in the blanks, well, just the GID */
378         completeGroup();
379         RefreshStringObj(groupLayout[LAYOUT_GID].obj);
380         firsttime = FALSE;
381     }
382
383     while (layoutDialogLoop(ds_win, groupLayout, &obj, &n, max, &cancelbutton, &cancel));
384
385     if (!cancel && !verifyGroupSettings())
386         goto reenter;
387
388     /* Clear this crap off the screen */
389     delwin(ds_win);
390     dialog_clear_norefresh();
391     use_helpfile(NULL);
392
393     if (!cancel) {
394         addGroup(ds_win);
395         ret = DITEM_SUCCESS;
396     }
397     else
398         ret = DITEM_FAILURE;
399     restorescr(save);
400     return ret;
401 }
402
403 /* Check for the settings on the screen. */
404
405 static int
406 verifyUserSettings(WINDOW *ds_win)
407 {
408     char tmp[256], *cp;
409     unsigned long luid;
410     WINDOW *save;
411     int rv;
412
413     if (strlen(uname) == 0) {
414         feepout("The user name field must not be empty!");
415         return 0;
416     }
417     snprintf(tmp, 256, "pw user show -q -n %s > /dev/null", uname);
418     if (vsystem("%s", tmp) == 0) {
419         feepout("This user name is already in use.");
420         return 0;
421     }
422     if (strlen(uid) > 0) {
423         luid = strtoul(uid, &cp, 10);
424         if (luid == 0 || luid > UID_MAX || (*cp != '\0' && !isspace(*cp))) {
425             feepout("The UID must be a number between 1 and 4294967295.");
426             return 0;
427         }
428     }
429     if (strcmp(passwd, confpasswd)) {
430         feepout("Passwords don't match");
431         return 0;
432     }
433     if ((homedir[0]!=0) && (homedir[0]!='/')) {
434         feepout("The pathname for home directories must begin with a '/'.");
435         return 0;
436     }
437     if (strlen(shell) > 0) {
438         setusershell();
439         while((cp = getusershell()) != NULL)
440             if (strcmp(cp, shell) == 0)
441                 break;
442         endusershell();
443         if (cp == NULL) {
444             save = savescr();
445             rv = msgYesNo("Warning:\n\n"
446                           "The requested shell \"%s\" is not\n"
447                           "a valid user shell.\n\n"
448                           "Use it anyway?\n", shell);
449             restorescr(save);
450             wrefresh(ds_win);
451             if (rv != DITEM_SUCCESS)
452                 return 0;
453         }
454         
455     }
456
457     if (strlen(umemb) > 0) {
458         if (strpbrk(umemb, " \t") != NULL) {
459             feepout("The member groups list must not contain any whitespace;\n"
460                     "use commas to separate the names.");
461             return 0;
462         }
463     }
464
465     return 1;
466 }
467
468 /*
469  * Ask pw(8) to fill in the blanks for us.
470  * Works solely on the global variables.
471  */
472
473 static void
474 completeUser(void)
475 {
476     int pfd[2], i;
477     char tmp[256], *cp, *cp2;
478     ssize_t l;
479     size_t amnt;
480     pid_t pid;
481     char *vec[7] =
482     {
483         "pw", "user", "add", "-N", "-n", 0, 0
484     };
485 #define VEC_UNAME 5
486
487     pipe (pfd);
488     if ((pid = fork()) == 0)
489     {
490         /* The kiddy. */
491         dup2(pfd[1], 1);
492         dup2(pfd[1], 2);
493         for (i = getdtablesize(); i > 2; i--)
494             close(i);
495
496         vec[VEC_UNAME] = uname;
497
498         execv("/usr/sbin/pw", vec);
499         msgDebug("Cannot execv() /usr/sbin/pw.\n");
500         _exit(99);
501     }
502     else
503     {
504         /* The oldie. */
505         close(pfd[1]);
506         amnt = sizeof tmp;
507         i = 0;
508         while((l = read(pfd[0], &tmp[i], amnt)) > 0)
509         {
510             amnt -= l;
511             i += l;
512             if (amnt == 0)
513             {
514                 close(pfd[0]);
515                 break;
516             }
517         }
518         close(pfd[0]);
519         tmp[i] = '\0';
520         waitpid(pid, &i, 0);
521         if (WIFSIGNALED(i) || WEXITSTATUS(i) != 0)
522             /* ignore by now */
523             return;
524         if ((cp = strchr(tmp, '\n')) != NULL)
525             *cp = '\0';
526         if ((cp = strchr(tmp, ':')) == NULL || (cp = strchr(++cp, ':')) == NULL)
527             return;
528         cp++;
529         if ((cp2 = strchr(cp, ':')) == NULL)
530             return;
531         *cp2++ = '\0';
532         strncpy(uid, cp, sizeof uid);
533         cp = cp2;
534         if ((cp2 = strchr(cp, ':')) == NULL)
535             return;
536         *cp2++ = '\0';
537 #ifdef notyet /* XXX pw user add -g doesn't accept a numerical GID */
538         strncpy(ugroup, cp, sizeof ugroup);
539 #endif
540         cp = cp2;
541         if ((cp2 = strchr(cp, ':')) == NULL || (cp2 = strchr(++cp2, ':')) == NULL ||
542             (cp = cp2 = strchr(++cp2, ':')) == NULL || (cp2 = strchr(++cp2, ':')) == NULL)
543             return;
544         *cp2++ = '\0';
545         cp++;
546         strncpy(gecos, cp, sizeof gecos);
547         cp = cp2;
548         if ((cp2 = strchr(cp, ':')) == NULL)
549             return;
550         *cp2++ = '\0';
551         if (*cp2)
552             strncpy(shell, cp2, sizeof shell);
553     }
554 #undef VEC_UNAME
555 }
556
557 static void
558 addUser(WINDOW *ds_win)
559 {
560     char tmp[256], *msg;
561     int pfd[2], ipfd[2], i, j;
562     ssize_t l;
563     size_t amnt;
564     pid_t pid;
565     /*
566      * Maximal list:
567      * pw user add -m -n uname -g grp -u uid -c comment -d homedir -s shell -G grplist -h 0
568      */
569     char *vec[21] =
570     {
571         "pw", "user", "add", "-m", "-n", /* ... */
572     };
573 #define VEC_UNAME 5
574
575     msgNotify("Adding user \"%s\"...", uname);
576
577     pipe (pfd);
578     pipe (ipfd);
579     if ((pid = fork()) == 0)
580     {
581         /* The kiddy. */
582         dup2(ipfd[0], 0);
583         dup2(pfd[1], 1);
584         dup2(pfd[1], 2);
585         for (i = getdtablesize(); i > 2; i--)
586             close(i);
587
588         vec[i = VEC_UNAME] = uname;
589         i++;
590 #define ADDVEC(var, option) do { if (strlen(var) > 0) { vec[i++] = option; vec[i++] = var; } } while (0)
591         ADDVEC(ugroup, "-g");
592         ADDVEC(uid, "-u");
593         ADDVEC(gecos, "-c");
594         ADDVEC(homedir, "-d");
595         ADDVEC(shell, "-s");
596         ADDVEC(umemb, "-G");
597         if (passwd[0]) {
598             vec[i++] = "-h";
599             vec[i++] = "0";
600         }
601         vec[i] = 0;
602
603         execv("/usr/sbin/pw", vec);
604         msgDebug("Cannot execv() /usr/sbin/pw.\n");
605         _exit(99);
606     }
607     else
608     {
609         /* The oldie. */
610         close(pfd[1]);
611         close(ipfd[0]);
612
613         if (passwd[0])
614             write(ipfd[1], passwd, strlen(passwd));
615         close(ipfd[1]);
616         amnt = sizeof tmp;
617         i = 0;
618         while((l = read(pfd[0], &tmp[i], amnt)) > 0)
619         {
620             amnt -= l;
621             i += l;
622             if (amnt == 0)
623             {
624                 close(pfd[0]);
625                 break;
626             }
627         }
628         close(pfd[0]);
629         tmp[i] = '\0';
630         waitpid(pid, &i, 0);
631         if (WIFSIGNALED(i))
632         {
633             j = WTERMSIG(i);
634             msg = "The `pw' command exited with signal %d.\n";
635             goto sysfail;
636         }
637         else if((j = WEXITSTATUS(i)))
638         {
639             i = 0;
640             if(strncmp(tmp, "pw: ", 4) == 0)
641                 i = 4;
642             tmp[sizeof tmp - 1] = '\0'; /* sanity */
643             if (j == EX_DATAERR || j == EX_NOUSER || j == EX_SOFTWARE)
644                 msgConfirm("The `pw' command exited with an error status.\n"
645                            "Its error message was:\n\n%s",
646                            &tmp[i]);
647             else
648             {
649                 msg = "The `pw' command exited with unexpected status %d.\n";
650         sysfail:
651                 msgDebug(msg, j);
652                 msgDebug("Command stdout and stderr was:\n\n%s", tmp);
653                 msgConfirm(msg, j);
654             }
655         }
656         else if (!passwd[0])
657             msgConfirm("You will need to enter a password for this user\n"
658                        "later, using the passwd(1) command from the shell.\n\n"
659                        "The account for `%s' is currently still disabled.",
660                        uname);
661     }
662 #undef VEC_UNAME
663 #undef ADDVEC
664 }
665
666 int
667 userAddUser(dialogMenuItem *self)
668 {
669     WINDOW              *ds_win, *save;
670     ComposeObj          *obj = NULL;
671     int                 n = 0, cancel = FALSE, ret;
672     int                 max, firsttime = TRUE, filled=0;
673
674     if (RunningAsInit && !strstr(variable_get(SYSTEM_STATE), "install")) {
675         msgConfirm("This option may only be used after the system is installed, sorry!");
676         return DITEM_FAILURE;
677     }
678
679     save = savescr();
680     dialog_clear_norefresh();
681
682     /* We need a curses window */
683     if (!(ds_win = openLayoutDialog(USER_HELPFILE, " User and Group Management ",
684                                     USER_DIALOG_X, USER_DIALOG_Y, USER_DIALOG_WIDTH, USER_DIALOG_HEIGHT))) {
685         beep();
686         msgConfirm("Cannot open adduser dialog window!!");
687         return(DITEM_FAILURE);
688     }
689
690     /* Draw a user entry box */
691     draw_box(ds_win, USER_DIALOG_Y + 1, USER_DIALOG_X + 3, USER_DIALOG_HEIGHT - 6,
692              USER_DIALOG_WIDTH - 6, dialog_attr, border_attr);
693     wattrset(ds_win, dialog_attr);
694     mvwaddstr(ds_win, USER_DIALOG_Y + 1, USER_DIALOG_X + 24, " Add a new user ");
695
696     CLEAR(uname);
697     CLEAR(uid);
698     CLEAR(ugroup);
699     CLEAR(gecos);
700     CLEAR(passwd);
701     CLEAR(confpasswd);
702     CLEAR(umemb);
703     CLEAR(homedir);
704     CLEAR(shell);
705
706     /* Some more initialisation before we go into the main input loop */
707     obj = initLayoutDialog(ds_win, userLayout, USER_DIALOG_X, USER_DIALOG_Y, &max);
708     
709 reenter:
710     cancelbutton = okbutton = 0;
711     if (firsttime) {
712         /* fill in the blanks, well, just the GID */
713         completeUser();
714         RefreshStringObj(userLayout[LAYOUT_UID].obj);
715         RefreshStringObj(userLayout[LAYOUT_UGROUP].obj);
716         RefreshStringObj(userLayout[LAYOUT_GECOS].obj);
717         RefreshStringObj(userLayout[LAYOUT_UMEMB].obj);
718         RefreshStringObj(userLayout[LAYOUT_HOMEDIR].obj);
719         RefreshStringObj(userLayout[LAYOUT_SHELL].obj);
720         firsttime = FALSE;
721     }
722
723     while (layoutDialogLoop(ds_win, userLayout, &obj, &n, max, &cancelbutton, &cancel)) {
724         /* Prevent this from being irritating if user really means NO */
725         if (filled < 3) {
726           if ((uname[0]) && !homedir[0]) {
727               SAFE_STRCPY(homedir,"/home/");
728               strcat(homedir,uname);
729               RefreshStringObj(userLayout[LAYOUT_HOMEDIR].obj);
730               ++filled;
731             }
732         }
733     };
734
735     if (!cancel && !verifyUserSettings(ds_win))
736         goto reenter;
737
738     /* Clear this crap off the screen */
739     delwin(ds_win);
740     dialog_clear_norefresh();
741     use_helpfile(NULL);
742
743     if (!cancel) {
744         addUser(ds_win);
745         ret = DITEM_SUCCESS;
746     }
747     else
748         ret = DITEM_FAILURE;
749     restorescr(save);
750     return ret;
751 }
752