Added a specific reply function for the data channel.
[uftps.git] / open_data_channel.c
blob183930664c0f9f7fa5d083ebb0b670d3fdd01751
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 <arpa/inet.h>
22 #include <unistd.h>
26 * Open a data channel in passive mode. Return the socket of the data channel
27 * if successful, -1 on any failure.
29 static int passive_connection (void)
31 int sk, e;
32 struct sockaddr_in sai;
33 socklen_t sai_len = sizeof(struct sockaddr_in);
35 sk = accept(SS.passive_sk, NULL, NULL);
37 /* Passive socket not needed anymore */
38 close(SS.passive_sk);
39 SS.passive_sk = -1;
41 if (sk == -1)
42 return -1;
44 /* Check if this new connection comes from the same IP as the client */
45 e = getpeername(sk, (struct sockaddr *) &sai, &sai_len);
46 if (e == -1 || sai.sin_addr.s_addr != SS.client_address.sin_addr.s_addr)
48 if (e == -1)
49 error("Getting remote data socket address");
50 else
51 warning("A different client (%s) connected to a passive socket",
52 inet_ntoa(sai.sin_addr));
53 close(sk);
54 return -1;
57 return sk;
62 * Open a data channel in active mode. Return the socket of the data channel if
63 * successful, -1 on any failure.
65 * Note that peer IP check is not needed here because it was performed directly
66 * on the PORT request.
68 static int active_connection (void)
70 int sk, e;
72 sk = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
73 if (sk == -1)
74 return -1;
76 e = connect(sk, (struct sockaddr *) &SS.port_destination,
77 sizeof(struct sockaddr_in));
78 if (e == -1)
80 error("Initiating active data connection");
81 close(sk);
82 return -1;
85 return sk;
90 * Open the data channel. When successful, the "data_sk" session field is set
91 * to the data channel socket and zero is returned. If the connection
92 * establishment fails, -1 is returned and the client is notified.
94 int open_data_channel (void)
96 int sk;
98 switch (SS.mode)
100 case ACTIVE_MODE:
101 sk = active_connection();
102 break;
103 case PASSIVE_MODE:
104 sk = passive_connection();
105 break;
106 case DEFAULT_MODE:
107 default:
108 warning("No data transfer mode selected");
109 reply_c("425 Default data transfer mode unsupported.\r\n");
110 return -1;
113 SS.mode = DEFAULT_MODE;
115 if (sk == -1)
117 error("Opening data connection");
118 reply_c("425 Can't open data connection.\r\n");
119 return -1;
122 SS.data_sk = sk;
123 return 0;