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.
7 * $FreeBSD: src/release/sysinstall/anonFTP.c,v 1.29.2.4 2002/08/09 20:34:23 schweikh Exp $
8 * $DragonFly: src/release/sysinstall/Attic/anonFTP.c,v 1.2 2003/06/17 04:27:21 dillon Exp $
11 * Coranth Gryphon. All rights reserved.
13 * Jordan K. Hubbard. All rights reserved.
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer,
20 * verbatim and that no modifications are made prior to this
22 * 2. Redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution.
26 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR THEIR PETS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 #include "sysinstall.h"
41 #include <sys/param.h>
45 /* This doesn't change until FTP itself changes */
47 #define FTP_NAME "ftp"
48 #define MOTD_FILE "ftpmotd"
50 /* These change if we want to use different defaults */
54 #define FTP_GROUP "operator"
55 #define FTP_UPLOAD "incoming"
56 #define FTP_COMMENT "Anonymous FTP Admin"
57 #define FTP_HOMEDIR "/var/ftp"
59 #define ANONFTP_HELPFILE "anonftp"
61 /* Set up the structure to hold configuration information */
62 /* Note that this is only what we could fit onto the one screen */
66 char homedir[64]; /* Home Dir for Anon FTP */
67 char group[32]; /* Group */
68 char uid[8]; /* UID */
69 char comment[64]; /* PWD Comment */
70 char upload[32]; /* Upload Dir */
75 #define ANONFTP_HOMEDIR_LEN 64
76 #define ANONFTP_COMMENT_LEN 64
77 #define ANONFTP_UPLOAD_LEN 32
78 #define ANONFTP_GROUP_LEN 32
79 #define ANONFTP_UID_LEN 8
81 static int okbutton, cancelbutton;
83 /* What the screen size is meant to be */
84 #define ANONFTP_DIALOG_Y 0
85 #define ANONFTP_DIALOG_X 8
86 #define ANONFTP_DIALOG_WIDTH COLS - 16
87 #define ANONFTP_DIALOG_HEIGHT LINES - 2
89 static Layout layout[] = {
91 { 2, 3, 8, ANONFTP_UID_LEN - 1,
92 "UID:", "What user ID to assign to FTP Admin",
93 tconf.uid, STRINGOBJ, NULL },
94 #define LAYOUT_GROUP 1
95 { 2, 15, 15, ANONFTP_GROUP_LEN - 1,
96 "Group:", "Group name that ftp process belongs to",
97 tconf.group, STRINGOBJ, NULL },
98 #define LAYOUT_COMMENT 2
99 { 2, 35, 24, ANONFTP_COMMENT_LEN - 1,
100 "Comment:", "Password file comment for FTP Admin",
101 tconf.comment, STRINGOBJ, NULL },
102 #define LAYOUT_HOMEDIR 3
103 { 9, 10, 43, ANONFTP_HOMEDIR_LEN - 1,
104 "FTP Root Directory:",
105 "The top directory to chroot to when doing anonymous ftp",
106 tconf.homedir, STRINGOBJ, NULL },
107 #define LAYOUT_UPLOAD 4
108 { 14, 20, 22, ANONFTP_UPLOAD_LEN - 1,
109 "Upload Subdirectory:", "Designated sub-directory that holds uploads",
110 tconf.upload, STRINGOBJ, NULL },
111 #define LAYOUT_OKBUTTON 5
113 "OK", "Select this if you are happy with these settings",
114 &okbutton, BUTTONOBJ, NULL },
115 #define LAYOUT_CANCELBUTTON 6
117 "CANCEL", "Select this if you wish to cancel this screen",
118 &cancelbutton, BUTTONOBJ, NULL },
132 if ((gid = atoi(tconf.group)) <= 0) {
133 if (!(tgrp = getgrnam(tconf.group))) {
134 /* group does not exist, create it by name */
136 tptr = msgGetInput("14", "What group ID to use for group %s ?", tconf.group);
137 if (tptr && *tptr && ((gid = atoi(tptr)) > 0)) {
138 if ((fptr = fopen(_PATH_GROUP,"a"))) {
139 fprintf(fptr,"%s:*:%d:%s\n",tconf.group,gid,FTP_NAME);
149 else if (!getgrgid(gid)) {
150 /* group does not exist, create it by number */
152 tptr = msgGetInput("14", "What group name to use for gid %d ?", gid);
154 SAFE_STRCPY(tconf.group, tptr);
155 if ((tgrp = getgrnam(tconf.group))) {
158 else if ((fptr = fopen(_PATH_GROUP,"a"))) {
159 fprintf(fptr,"%s:*:%d:%s\n",tconf.group,gid,FTP_NAME);
165 if ((tpw = getpwnam(FTP_NAME))) {
166 if (tpw->pw_uid != FTP_UID)
167 msgConfirm("FTP user already exists with a different uid.");
169 return DITEM_SUCCESS; /* succeeds if already exists */
172 sprintf(pwline, "%s:*:%s:%d::0:0:%s:%s:/nonexistent\n", FTP_NAME, tconf.uid, gid, tconf.comment, tconf.homedir);
174 fptr = fopen(_PATH_MASTERPASSWD,"a");
176 msgConfirm("Could not open master password file.");
177 return DITEM_FAILURE;
179 fprintf(fptr, "%s", pwline);
181 msgNotify("Remaking password file: %s", _PATH_MASTERPASSWD);
182 vsystem("pwd_mkdb -p %s", _PATH_MASTERPASSWD);
183 return DITEM_SUCCESS | DITEM_RESTORE;
186 /* This is it - how to get the setup values */
188 anonftpOpenDialog(void)
191 ComposeObj *obj = NULL;
192 int n = 0, cancel = FALSE;
195 WINDOW *w = savescr();
197 /* We need a curses window */
198 if (!(ds_win = openLayoutDialog(ANONFTP_HELPFILE, " Anonymous FTP Configuration ",
199 ANONFTP_DIALOG_X, ANONFTP_DIALOG_Y, ANONFTP_DIALOG_WIDTH, ANONFTP_DIALOG_HEIGHT))) {
201 msgConfirm("Cannot open anonymous ftp dialog window!!");
203 return DITEM_FAILURE;
206 /* Draw a sub-box for the path configuration */
207 draw_box(ds_win, ANONFTP_DIALOG_Y + 7, ANONFTP_DIALOG_X + 8,
208 ANONFTP_DIALOG_HEIGHT - 11, ANONFTP_DIALOG_WIDTH - 17,
209 dialog_attr, border_attr);
210 wattrset(ds_win, dialog_attr);
211 sprintf(title, " Path Configuration ");
212 mvwaddstr(ds_win, ANONFTP_DIALOG_Y + 7, ANONFTP_DIALOG_X + 22, title);
214 /** Initialize the config Data Structure **/
215 bzero(&tconf, sizeof(tconf));
217 SAFE_STRCPY(tconf.group, FTP_GROUP);
218 SAFE_STRCPY(tconf.upload, FTP_UPLOAD);
219 SAFE_STRCPY(tconf.comment, FTP_COMMENT);
220 SAFE_STRCPY(tconf.homedir, FTP_HOMEDIR);
221 sprintf(tconf.uid, "%d", FTP_UID);
223 /* Some more initialisation before we go into the main input loop */
224 obj = initLayoutDialog(ds_win, layout, ANONFTP_DIALOG_X, ANONFTP_DIALOG_Y, &max);
226 cancelbutton = okbutton = 0;
227 while (layoutDialogLoop(ds_win, layout, &obj, &n, max, &cancelbutton, &cancel));
229 /* Clear this crap off the screen */
234 return DITEM_FAILURE;
235 return DITEM_SUCCESS;
239 configAnonFTP(dialogMenuItem *self __unused)
244 if (msgYesNo("Anonymous FTP permits un-authenticated users to connect to the system\n"
245 "FTP server, if FTP service is enabled. Anonymous users are\n"
246 "restricted to a specific subset of the file system, and the default\n"
247 "configuration provides a drop-box incoming directory to which uploads\n"
248 "are permitted. You must separately enable both inetd(8), and enable\n"
249 "ftpd(8) in inetd.conf(5) for FTP services to be available. If you\n"
250 "did not do so earlier, you will have the opportunity to enable inetd(8)\n"
252 "Do you wish to continue configuring anonymous FTP?")) {
253 return DITEM_FAILURE;
259 i = anonftpOpenDialog();
260 if (DITEM_STATUS(i) != DITEM_SUCCESS) {
261 msgConfirm("Configuration of Anonymous FTP cancelled per user request.");
265 /*** Use defaults for any invalid values ***/
266 if (atoi(tconf.uid) <= 0)
267 sprintf(tconf.uid, "%d", FTP_UID);
270 SAFE_STRCPY(tconf.group, FTP_GROUP);
272 if (!tconf.upload[0])
273 SAFE_STRCPY(tconf.upload, FTP_UPLOAD);
275 /*** If the user did not specify a directory, use default ***/
277 if (tconf.homedir[strlen(tconf.homedir) - 1] == '/')
278 tconf.homedir[strlen(tconf.homedir) - 1] = '\0';
280 if (!tconf.homedir[0])
281 SAFE_STRCPY(tconf.homedir, FTP_HOMEDIR);
283 /*** If HomeDir does not exist, create it ***/
285 if (!directory_exists(tconf.homedir))
286 vsystem("mkdir -p %s", tconf.homedir);
288 if (directory_exists(tconf.homedir)) {
289 msgNotify("Configuring %s for use by anon FTP.", tconf.homedir);
290 vsystem("chmod 555 %s && chown root.%s %s", tconf.homedir, tconf.group, tconf.homedir);
291 vsystem("mkdir %s/bin && chmod 555 %s/bin", tconf.homedir, tconf.homedir);
292 vsystem("cp /bin/ls %s/bin && chmod 111 %s/bin/ls", tconf.homedir, tconf.homedir);
293 vsystem("cp /bin/date %s/bin && chmod 111 %s/bin/date", tconf.homedir, tconf.homedir);
294 vsystem("mkdir %s/etc && chmod 555 %s/etc", tconf.homedir, tconf.homedir);
295 vsystem("mkdir -p %s/pub", tconf.homedir);
296 vsystem("mkdir -p %s/%s", tconf.homedir, tconf.upload);
297 vsystem("chmod 1777 %s/%s", tconf.homedir, tconf.upload);
299 if (DITEM_STATUS(createFtpUser()) == DITEM_SUCCESS) {
300 msgNotify("Copying password information for anon FTP.");
301 vsystem("awk -F: '{if ($3 < 10 || $1 == \"ftp\") print $0}' /etc/passwd > %s/etc/passwd && chmod 444 %s/etc/passwd", tconf.homedir, tconf.homedir);
302 vsystem("awk -F: '{if ($3 < 100) print $0}' /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;