Includes cleanup.
[uftps.git] / uftps.c
blobad237ec29e12d010f516dc164b6669b567896e0c
1 /*
2 * User FTP Server, Share folders over FTP without being root.
3 * Copyright (C) 2008 Isaac Jurado
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License as published by the Free Software
7 * Foundation; either version 2 of the License, or (at your option) any later
8 * version.
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13 * details.
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "uftps.h"
21 #include <sys/wait.h>
22 #include <signal.h>
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <stdio.h>
27 struct _SessionScope SS; /* SS --> Session State*/
31 * clid_finish
33 * Reaper function. For "zombies".
35 static void child_finish (int sig)
37 while (waitpid(-1, NULL, WNOHANG) > 0)
38 debug("Collecting children");
43 * end
45 * End. What where you expecting?
47 static void end (int sig)
49 notice("Signal caught, exiting");
50 exit(EXIT_SUCCESS);
55 * Main program. Opens the command port until a client requests a connection.
56 * Then the server is forked the child will manage all that client's requests.
58 * Attending multiple clients is necessary to allow some clients (like lftp(1))
59 * perform multiple concurrent jops. Like moving current transfer to de
60 * background and then browse through directories.
62 * Also note that here the root directory is fixed. As we can't protect with
63 * chroot(), due to de lack of privilege, we must do a series of safety checks
64 * to simulate that behaviour. Because of this, some strong restrictions have
65 * arised; which could reduce de number of FTP clients compatible with this
66 * server.
69 int main (int argc, char **argv)
71 int bind_sk, cmd_sk, e, yes;
72 int port = DEFAULT_PORT;
73 struct sigaction my_sa;
74 struct sockaddr_in sai;
75 socklen_t sai_len = sizeof(struct sockaddr_in);
77 setlinebuf(stdout);
79 if (argc > 1)
81 port = atoi(argv[1]) & 0x00FFFF;
82 if (port <= 1024)
83 fatal("This port number is restricted");
86 /* Signal handling */
87 sigfillset(&my_sa.sa_mask);
88 my_sa.sa_flags = SA_RESTART;
89 my_sa.sa_handler = child_finish;
90 sigaction(SIGCHLD, &my_sa, NULL);
92 my_sa.sa_flags = SA_NOMASK;
93 my_sa.sa_handler = end;
94 sigaction(SIGINT, &my_sa, NULL);
96 /* Connection handling */
97 sai.sin_family = AF_INET;
98 sai.sin_port = htons(port);
99 sai.sin_addr.s_addr = INADDR_ANY;
101 bind_sk = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
102 if (bind_sk == -1)
103 fatal("Creating main server socket");
105 yes = 1;
106 setsockopt(bind_sk, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
107 e = bind(bind_sk, (struct sockaddr *) &sai, sai_len);
108 if (e == -1)
109 fatal("Binding main server socket");
111 e = listen(bind_sk, 5);
112 if (e == -1)
113 fatal("Listening at main server socket");
115 notice("UFTPS listening on port %d (TCP)", port);
116 notice("Use CTRL + C to finish");
117 notice("If you want to use a different port, specify it as the only argument in the command line");
119 /* Main server loop (accepting connections) */
120 do {
121 sai_len = sizeof(struct sockaddr_in);
122 cmd_sk = accept(bind_sk, (struct sockaddr *) &sai, &sai_len);
123 if (cmd_sk == -1)
125 error("Accepting incoming connection");
126 continue;
129 e = fork();
130 if (e == 0)
132 /*** CHILD ***/
133 e = close(bind_sk);
134 if (e == -1)
135 error("Closing server socket from child");
137 init_session(cmd_sk);
138 command_loop();
140 else
142 /*** PARENT ***/
143 if (e == -1)
144 error("Could not create a child process");
146 e = close(cmd_sk);
147 if (e == -1)
148 error("Closing control channel %d from parent",
149 cmd_sk);
151 } while (1);
153 return EXIT_SUCCESS;