2 * The new sysinstall program.
4 * This is probably the last program in the `sysinstall' line - the next
5 * generation being essentially a complete rewrite.
10 * Coranth Gryphon. All rights reserved.
12 * Jordan K. Hubbard. All rights reserved.
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer,
19 * verbatim and that no modifications are made prior to this
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
25 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR THEIR PETS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 #include "sysinstall.h"
40 #include <sys/param.h>
44 /* This doesn't change until FTP itself changes */
46 #define FTP_NAME "ftp"
47 #define MOTD_FILE "ftpmotd"
49 /* These change if we want to use different defaults */
53 #define FTP_GROUP "ftp"
54 #define FTP_UPLOAD "incoming"
55 #define FTP_COMMENT "Anonymous FTP Admin"
56 #define FTP_HOMEDIR "/var/ftp"
58 #define ANONFTP_HELPFILE "anonftp"
60 /* Set up the structure to hold configuration information */
61 /* Note that this is only what we could fit onto the one screen */
65 char homedir[64]; /* Home Dir for Anon FTP */
66 char group[32]; /* Group */
67 char uid[8]; /* UID */
68 char comment[64]; /* PWD Comment */
69 char upload[32]; /* Upload Dir */
74 #define ANONFTP_HOMEDIR_LEN 64
75 #define ANONFTP_COMMENT_LEN 64
76 #define ANONFTP_UPLOAD_LEN 32
77 #define ANONFTP_GROUP_LEN 32
78 #define ANONFTP_UID_LEN 8
80 static int okbutton, cancelbutton;
82 /* What the screen size is meant to be */
83 #define ANONFTP_DIALOG_Y 0
84 #define ANONFTP_DIALOG_X 8
85 #define ANONFTP_DIALOG_WIDTH COLS - 16
86 #define ANONFTP_DIALOG_HEIGHT LINES - 2
88 static Layout layout[] = {
90 { 2, 3, 8, ANONFTP_UID_LEN - 1,
91 "UID:", "What user ID to assign to FTP Admin",
92 tconf.uid, STRINGOBJ, NULL },
93 #define LAYOUT_GROUP 1
94 { 2, 15, 15, ANONFTP_GROUP_LEN - 1,
95 "Group:", "Group name that ftp process belongs to",
96 tconf.group, STRINGOBJ, NULL },
97 #define LAYOUT_COMMENT 2
98 { 2, 35, 24, ANONFTP_COMMENT_LEN - 1,
99 "Comment:", "Password file comment for FTP Admin",
100 tconf.comment, STRINGOBJ, NULL },
101 #define LAYOUT_HOMEDIR 3
102 { 9, 10, 43, ANONFTP_HOMEDIR_LEN - 1,
103 "FTP Root Directory:",
104 "The top directory to chroot to when doing anonymous ftp",
105 tconf.homedir, STRINGOBJ, NULL },
106 #define LAYOUT_UPLOAD 4
107 { 14, 20, 22, ANONFTP_UPLOAD_LEN - 1,
108 "Upload Subdirectory:", "Designated sub-directory that holds uploads (leave empty for none)",
109 tconf.upload, STRINGOBJ, NULL },
110 #define LAYOUT_OKBUTTON 5
112 "OK", "Select this if you are happy with these settings",
113 &okbutton, BUTTONOBJ, NULL },
114 #define LAYOUT_CANCELBUTTON 6
116 "CANCEL", "Select this if you wish to cancel this screen",
117 &cancelbutton, BUTTONOBJ, NULL },
131 if ((gid = atoi(tconf.group)) <= 0) {
132 if (!(tgrp = getgrnam(tconf.group))) {
133 /* group does not exist, create it by name */
135 tptr = msgGetInput("14", "What group ID to use for group %s ?", tconf.group);
136 if (tptr && *tptr && ((gid = atoi(tptr)) > 0)) {
137 if ((fptr = fopen(_PATH_GROUP,"a"))) {
138 fprintf(fptr,"%s:*:%d:%s\n",tconf.group,gid,FTP_NAME);
148 else if (!getgrgid(gid)) {
149 /* group does not exist, create it by number */
151 tptr = msgGetInput("ftp", "What group name to use for gid %d ?", gid);
153 SAFE_STRCPY(tconf.group, tptr);
154 if ((tgrp = getgrnam(tconf.group))) {
157 else if ((fptr = fopen(_PATH_GROUP,"a"))) {
158 fprintf(fptr,"%s:*:%d:%s\n",tconf.group,gid,FTP_NAME);
164 if ((tpw = getpwnam(FTP_NAME))) {
165 if (tpw->pw_uid != FTP_UID)
166 msgConfirm("FTP user already exists with a different uid.");
168 return DITEM_SUCCESS; /* succeeds if already exists */
171 sprintf(pwline, "%s:*:%s:%d::0:0:%s:%s:/nonexistent\n", FTP_NAME, tconf.uid, gid, tconf.comment, tconf.homedir);
173 fptr = fopen(_PATH_MASTERPASSWD,"a");
175 msgConfirm("Could not open master password file.");
176 return DITEM_FAILURE;
178 fprintf(fptr, "%s", pwline);
180 msgNotify("Remaking password file: %s", _PATH_MASTERPASSWD);
181 vsystem("pwd_mkdb -p %s", _PATH_MASTERPASSWD);
182 return DITEM_SUCCESS | DITEM_RESTORE;
185 /* This is it - how to get the setup values */
187 anonftpOpenDialog(void)
190 ComposeObj *obj = NULL;
191 int n = 0, cancel = FALSE;
194 WINDOW *w = savescr();
196 /* We need a curses window */
197 if (!(ds_win = openLayoutDialog(ANONFTP_HELPFILE, " Anonymous FTP Configuration ",
198 ANONFTP_DIALOG_X, ANONFTP_DIALOG_Y, ANONFTP_DIALOG_WIDTH, ANONFTP_DIALOG_HEIGHT))) {
200 msgConfirm("Cannot open anonymous ftp dialog window!!");
202 return DITEM_FAILURE;
205 /* Draw a sub-box for the path configuration */
206 draw_box(ds_win, ANONFTP_DIALOG_Y + 7, ANONFTP_DIALOG_X + 8,
207 ANONFTP_DIALOG_HEIGHT - 11, ANONFTP_DIALOG_WIDTH - 17,
208 dialog_attr, border_attr);
209 wattrset(ds_win, dialog_attr);
210 sprintf(title, " Path Configuration ");
211 mvwaddstr(ds_win, ANONFTP_DIALOG_Y + 7, ANONFTP_DIALOG_X + 22, title);
213 /** Initialize the config Data Structure **/
214 bzero(&tconf, sizeof(tconf));
216 SAFE_STRCPY(tconf.group, FTP_GROUP);
217 SAFE_STRCPY(tconf.upload, FTP_UPLOAD);
218 SAFE_STRCPY(tconf.comment, FTP_COMMENT);
219 SAFE_STRCPY(tconf.homedir, FTP_HOMEDIR);
220 sprintf(tconf.uid, "%d", FTP_UID);
222 /* Some more initialisation before we go into the main input loop */
223 obj = initLayoutDialog(ds_win, layout, ANONFTP_DIALOG_X, ANONFTP_DIALOG_Y, &max);
225 cancelbutton = okbutton = 0;
226 while (layoutDialogLoop(ds_win, layout, &obj, &n, max, &cancelbutton, &cancel));
228 /* Clear this crap off the screen */
233 return DITEM_FAILURE;
234 return DITEM_SUCCESS;
238 configAnonFTP(dialogMenuItem *self __unused)
243 if (msgYesNo("Anonymous FTP permits un-authenticated users to connect to the system\n"
244 "FTP server, if FTP service is enabled. Anonymous users are\n"
245 "restricted to a specific subset of the file system, and the default\n"
246 "configuration provides a drop-box incoming directory to which uploads\n"
247 "are permitted. You must separately enable both inetd(8), and enable\n"
248 "ftpd(8) in inetd.conf(5) for FTP services to be available. If you\n"
249 "did not do so earlier, you will have the opportunity to enable inetd(8)\n"
251 "If you want the server to be read-only you should leave the upload\n"
252 "directory option empty and add the -r command-line option to ftpd(8)\n"
253 "in inetd.conf(5)\n\n"
254 "Do you wish to continue configuring anonymous FTP?")) {
255 return DITEM_FAILURE;
261 i = anonftpOpenDialog();
262 if (DITEM_STATUS(i) != DITEM_SUCCESS) {
263 msgConfirm("Configuration of Anonymous FTP cancelled per user request.");
267 /*** Use defaults for any invalid values ***/
268 if (atoi(tconf.uid) <= 0)
269 sprintf(tconf.uid, "%d", FTP_UID);
272 SAFE_STRCPY(tconf.group, FTP_GROUP);
274 /*** If the user did not specify a directory, use default ***/
276 if (tconf.homedir[strlen(tconf.homedir) - 1] == '/')
277 tconf.homedir[strlen(tconf.homedir) - 1] = '\0';
279 if (!tconf.homedir[0])
280 SAFE_STRCPY(tconf.homedir, FTP_HOMEDIR);
282 /*** If HomeDir does not exist, create it ***/
284 if (!directory_exists(tconf.homedir))
285 vsystem("mkdir -p %s", tconf.homedir);
287 if (directory_exists(tconf.homedir)) {
288 msgNotify("Configuring %s for use by anon FTP.", tconf.homedir);
289 vsystem("chmod 555 %s && chown root:%s %s", tconf.homedir, tconf.group, tconf.homedir);
290 vsystem("mkdir %s/etc && chmod 555 %s/etc", tconf.homedir, tconf.homedir);
291 vsystem("mkdir -p %s/pub", tconf.homedir);
292 if (tconf.upload[0]) {
293 vsystem("mkdir -p %s/%s", tconf.homedir, tconf.upload);
294 vsystem("chmod 1777 %s/%s", tconf.homedir, tconf.upload);
297 if (DITEM_STATUS(createFtpUser()) == DITEM_SUCCESS) {
298 msgNotify("Copying password information for anon FTP.");
299 vsystem("awk -F: '{if ((substr($1, 1, 1) != \"+\") && (substr($1, 1, 1) != \"-\") && ($3 < 10 || $1 == \"ftp\")) print $0}' /etc/master.passwd > %s/etc/master.passwd", tconf.homedir);
300 vsystem("/usr/sbin/pwd_mkdb -d %s/etc %s/etc/master.passwd && chmod 444 %s/etc/pwd.db", tconf.homedir, tconf.homedir, tconf.homedir);
301 vsystem("rm -f %s/etc/master.passwd %s/etc/spwd.db", tconf.homedir, tconf.homedir);
302 vsystem("awk -F: '!/^#/ {if ((substr($1, 1, 1) != \"+\") && (substr($1, 1, 1) != \"-\") && ($3 < 100)) printf \"%%s:*:%%s:\\n\", $1, $3}' /etc/group > %s/etc/group && chmod 444 %s/etc/group", tconf.homedir, tconf.homedir);
303 vsystem("chown -R root:%s %s/pub", tconf.group, tconf.homedir);
306 msgConfirm("Unable to create FTP user! Anonymous FTP setup failed.");
310 if (!msgYesNo("Create a welcome message file for anonymous FTP users?")) {
312 vsystem("echo Your welcome message here. > %s/etc/%s", tconf.homedir, MOTD_FILE);
313 sprintf(cmd, "%s %s/etc/%s", variable_get(VAR_EDITOR), tconf.homedir, MOTD_FILE);
314 if (!systemExecute(cmd))
321 msgConfirm("Invalid Directory: %s\n"
322 "Anonymous FTP will not be set up.", tconf.homedir);
325 if (DITEM_STATUS(i) == DITEM_SUCCESS)
326 variable_set2("anon_ftp", "YES", 0);
327 return i | DITEM_RESTORE;