Fix more __stdcall issues. Move the __stdcall into the function typedefs
[dragonfly.git] / release / sysinstall / anonFTP.c
1 /*
2  * The new sysinstall program.
3  *
4  * This is probably the last program in the `sysinstall' line - the next
5  * generation being essentially a complete rewrite.
6  *
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 $
9  *
10  * Copyright (c) 1995
11  *      Coranth Gryphon.  All rights reserved.
12  * Copyright (c) 1996
13  *      Jordan K. Hubbard.  All rights reserved.
14  *
15  * Redistribution and use in source and binary forms, with or without
16  * modification, are permitted provided that the following conditions
17  * are met:
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
21  *    point in the file.
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.
25  *
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
36  * SUCH DAMAGE.
37  *
38  */
39
40 #include "sysinstall.h"
41 #include <sys/param.h>
42 #include <pwd.h>
43 #include <grp.h>
44
45 /* This doesn't change until FTP itself changes */
46
47 #define FTP_NAME        "ftp"
48 #define MOTD_FILE       "ftpmotd"
49
50 /* These change if we want to use different defaults */
51
52 #define FTP_UID         14
53 #define FTP_GID         5
54 #define FTP_GROUP       "operator"
55 #define FTP_UPLOAD      "incoming"
56 #define FTP_COMMENT     "Anonymous FTP Admin"
57 #define FTP_HOMEDIR     "/var/ftp"
58
59 #define ANONFTP_HELPFILE "anonftp"
60
61 /* Set up the structure to hold configuration information */
62 /* Note that this is only what we could fit onto the one screen */
63
64 typedef struct
65 {
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 */
71 } FTPConf;
72
73 static FTPConf tconf;
74
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
80
81 static int      okbutton, cancelbutton;
82
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
88
89 static Layout layout[] = {
90 #define LAYOUT_UID              0
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
112     { 19, 15, 0, 0,
113       "OK", "Select this if you are happy with these settings",
114       &okbutton, BUTTONOBJ, NULL },
115 #define LAYOUT_CANCELBUTTON     6
116     { 19, 35, 0, 0,
117       "CANCEL", "Select this if you wish to cancel this screen",
118       &cancelbutton, BUTTONOBJ, NULL },
119     { NULL },
120 };
121
122 static int
123 createFtpUser(void)
124 {
125     struct passwd *tpw;
126     struct group  *tgrp;
127     char pwline[256];
128     char *tptr;
129     int gid;
130     FILE *fptr;
131     
132     if ((gid = atoi(tconf.group)) <= 0) {
133         if (!(tgrp = getgrnam(tconf.group))) {
134             /* group does not exist, create it by name */
135             
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);
140                     fclose(fptr);
141                 }
142             }
143             else
144                 gid = FTP_GID;
145         }
146         else
147             gid = tgrp->gr_gid;
148     }
149     else if (!getgrgid(gid)) {
150         /* group does not exist, create it by number */
151         
152         tptr = msgGetInput("14", "What group name to use for gid %d ?", gid);
153         if (tptr && *tptr) {
154             SAFE_STRCPY(tconf.group, tptr);
155             if ((tgrp = getgrnam(tconf.group))) {
156                 gid = tgrp->gr_gid;
157             }
158             else if ((fptr = fopen(_PATH_GROUP,"a"))) {
159                 fprintf(fptr,"%s:*:%d:%s\n",tconf.group,gid,FTP_NAME);
160                 fclose(fptr);
161             }
162         }
163     }
164     
165     if ((tpw = getpwnam(FTP_NAME))) {
166         if (tpw->pw_uid != FTP_UID)
167             msgConfirm("FTP user already exists with a different uid.");
168         
169         return DITEM_SUCCESS;   /* succeeds if already exists */
170     }
171     
172     sprintf(pwline, "%s:*:%s:%d::0:0:%s:%s:/nonexistent\n", FTP_NAME, tconf.uid, gid, tconf.comment, tconf.homedir);
173     
174     fptr = fopen(_PATH_MASTERPASSWD,"a");
175     if (! fptr) {
176         msgConfirm("Could not open master password file.");
177         return DITEM_FAILURE;
178     }
179     fprintf(fptr, "%s", pwline);
180     fclose(fptr);
181     msgNotify("Remaking password file: %s", _PATH_MASTERPASSWD);
182     vsystem("pwd_mkdb -p %s", _PATH_MASTERPASSWD);
183     return DITEM_SUCCESS | DITEM_RESTORE;
184 }
185
186 /* This is it - how to get the setup values */
187 static int
188 anonftpOpenDialog(void)
189 {
190     WINDOW              *ds_win;
191     ComposeObj          *obj = NULL;
192     int                 n = 0, cancel = FALSE;
193     int                 max;
194     char                title[80];
195     WINDOW              *w = savescr();
196
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))) {
200         beep();
201         msgConfirm("Cannot open anonymous ftp dialog window!!");
202         restorescr(w);
203         return DITEM_FAILURE;
204     }
205     
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);
213     
214     /** Initialize the config Data Structure **/
215     bzero(&tconf, sizeof(tconf));
216     
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);
222     
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);
225
226     cancelbutton = okbutton = 0;
227     while (layoutDialogLoop(ds_win, layout, &obj, &n, max, &cancelbutton, &cancel));
228
229     /* Clear this crap off the screen */
230     delwin(ds_win);
231     use_helpfile(NULL);
232     restorescr(w);
233     if (cancel)
234         return DITEM_FAILURE;
235     return DITEM_SUCCESS;
236 }
237
238 int
239 configAnonFTP(dialogMenuItem *self __unused)
240 {
241     int i;
242
243
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"
251                  "again later.\n\n"
252                  "Do you wish to continue configuring anonymous FTP?")) {
253         return DITEM_FAILURE;
254     }
255     
256     /* Be optimistic */
257     i = DITEM_SUCCESS;
258     
259     i = anonftpOpenDialog();
260     if (DITEM_STATUS(i) != DITEM_SUCCESS) {
261         msgConfirm("Configuration of Anonymous FTP cancelled per user request.");
262         return i;
263     }
264     
265     /*** Use defaults for any invalid values ***/
266     if (atoi(tconf.uid) <= 0)
267         sprintf(tconf.uid, "%d", FTP_UID);
268     
269     if (!tconf.group[0])
270         SAFE_STRCPY(tconf.group, FTP_GROUP);
271     
272     if (!tconf.upload[0])
273         SAFE_STRCPY(tconf.upload, FTP_UPLOAD);
274     
275     /*** If the user did not specify a directory, use default ***/
276     
277     if (tconf.homedir[strlen(tconf.homedir) - 1] == '/')
278         tconf.homedir[strlen(tconf.homedir) - 1] = '\0';
279     
280     if (!tconf.homedir[0])
281         SAFE_STRCPY(tconf.homedir, FTP_HOMEDIR);
282     
283     /*** If HomeDir does not exist, create it ***/
284     
285     if (!directory_exists(tconf.homedir))
286         vsystem("mkdir -p %s", tconf.homedir);
287     
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);
298         
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);
304         }
305         else {
306             msgConfirm("Unable to create FTP user!  Anonymous FTP setup failed.");
307             i = DITEM_FAILURE;
308         }
309         
310         if (!msgYesNo("Create a welcome message file for anonymous FTP users?")) {
311             char cmd[256];
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))
315                 i = DITEM_SUCCESS;
316             else
317                 i = DITEM_FAILURE;
318         }
319     }
320     else {
321         msgConfirm("Invalid Directory: %s\n"
322                    "Anonymous FTP will not be set up.", tconf.homedir);
323         i = DITEM_FAILURE;
324     }
325     if (DITEM_STATUS(i) == DITEM_SUCCESS)
326         variable_set2("anon_ftp", "YES", 0);
327     return i | DITEM_RESTORE;
328 }