1/*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License as
4 * published by the Free Software Foundation; either version 2 of
5 * the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
15 * MA 02111-1307 USA
16 */
17/*
18 * Part of Very Secure FTPd
19 * License: GPL v2
20 * Author: Chris Evans
21 * privops.c
22 *
23 * Code implementing the privileged operations that the unprivileged client
24 * might request.
25 * Look for suitable paranoia in this file.
26 */
27
28#include "privops.h"
29#include "session.h"
30#include "sysdeputil.h"
31#include "sysutil.h"
32#include "utility.h"
33#include "str.h"
34#include "tunables.h"
35#include "defs.h"
36#include "logging.h"
37#include <string.h>
38#include <stdlib.h>
39#include <stdio.h>
40#include <bcmnvram.h>
41
42/* File private functions */
43static enum EVSFPrivopLoginResult handle_anonymous_login(
44  struct vsf_session* p_sess, const struct mystr* p_pass_str);
45static enum EVSFPrivopLoginResult handle_local_login(
46  struct vsf_session* p_sess, const struct mystr* p_user_str,
47  const struct mystr* p_pass_str);
48static void setup_username_globals(struct vsf_session* p_sess,
49                                   const struct mystr* p_str);
50static enum EVSFPrivopLoginResult handle_login(
51  struct vsf_session* p_sess, const struct mystr* p_user_str,
52  const struct mystr* p_pass_str);
53
54int
55vsf_privop_get_ftp_port_sock(struct vsf_session* p_sess)
56{
57  static struct vsf_sysutil_sockaddr* p_sockaddr;
58  int retval;
59  int s = vsf_sysutil_get_ipsock(p_sess->p_local_addr);
60  vsf_sysutil_activate_reuseaddr(s);
61  vsf_sysutil_sockaddr_clone(&p_sockaddr, p_sess->p_local_addr);
62  vsf_sysutil_sockaddr_set_port(p_sockaddr, tunable_ftp_data_port);
63  retval = vsf_sysutil_bind(s, p_sockaddr);
64  if (retval != 0)
65  {
66    die("vsf_sysutil_bind");
67  }
68  return s;
69}
70
71void
72vsf_privop_do_file_chown(struct vsf_session* p_sess, int fd)
73{
74  static struct vsf_sysutil_statbuf* s_p_statbuf;
75  vsf_sysutil_fstat(fd, &s_p_statbuf);
76  /* Do nothing if it is already owned by the desired user. */
77  if (vsf_sysutil_statbuf_get_uid(s_p_statbuf) ==
78      p_sess->anon_upload_chown_uid)
79  {
80    return;
81  }
82  /* Drop it like a hot potato unless it's a regular file owned by
83   * the the anonymous ftp user
84   */
85  if (p_sess->anon_upload_chown_uid == -1 ||
86      !vsf_sysutil_statbuf_is_regfile(s_p_statbuf) ||
87      (vsf_sysutil_statbuf_get_uid(s_p_statbuf) != p_sess->anon_ftp_uid &&
88       vsf_sysutil_statbuf_get_uid(s_p_statbuf) != p_sess->guest_user_uid))
89  {
90    die("invalid fd in cmd_process_chown");
91  }
92  /* SECURITY! You need an OS which strips SUID/SGID bits on chown(),
93   * otherwise a compromise of the FTP user will lead to compromise of
94   * the "anon_upload_chown_uid" user (think chmod +s).
95   */
96  vsf_sysutil_fchown(fd, p_sess->anon_upload_chown_uid, -1);
97}
98
99enum EVSFPrivopLoginResult
100vsf_privop_do_login(struct vsf_session* p_sess,
101                    const struct mystr* p_pass_str)
102{
103  enum EVSFPrivopLoginResult result =
104    handle_login(p_sess, &p_sess->user_str, p_pass_str);
105  vsf_log_start_entry(p_sess, kVSFLogEntryLogin);
106  if (result == kVSFLoginFail)
107  {
108    vsf_log_do_log(p_sess, 0);
109  }
110  else
111  {
112    vsf_log_do_log(p_sess, 1);
113  }
114  return result;
115}
116
117static enum EVSFPrivopLoginResult
118handle_login(struct vsf_session* p_sess, const struct mystr* p_user_str,
119             const struct mystr* p_pass_str)
120{
121  /* Do not assume PAM can cope with dodgy input, even though it
122   * almost certainly can.
123   */
124  int anonymous_login = 0;
125  unsigned int len = str_getlen(p_user_str);
126  if (len == 0 || len > VSFTP_USERNAME_MAX)
127  {
128    return kVSFLoginFail;
129  }
130  /* Throw out dodgy start characters */
131  if (!vsf_sysutil_isalnum(str_get_char_at(p_user_str, 0)))
132  {
133    return kVSFLoginFail;
134  }
135  /* Throw out non-printable characters and space in username */
136  if (str_contains_space(p_user_str) ||
137      str_contains_unprintable(p_user_str))
138  {
139    return kVSFLoginFail;
140  }
141  /* Throw out excessive length passwords */
142  len = str_getlen(p_pass_str);
143  if (len > VSFTP_PASSWORD_MAX)
144  {
145    return kVSFLoginFail;
146  }
147  /* Check for an anonymous login or "real" login */
148  if (tunable_anonymous_enable)
149  {
150    struct mystr upper_str = INIT_MYSTR;
151    str_copy(&upper_str, p_user_str);
152    str_upper(&upper_str);
153    if (
154//    	str_equal_text(&upper_str, "FTP") ||	// Jiahao
155        str_equal_text(&upper_str, "ANONYMOUS")
156       )
157    {
158      anonymous_login = 1;
159    }
160    str_free(&upper_str);
161  }
162  {
163    enum EVSFPrivopLoginResult result = kVSFLoginFail;
164    if (anonymous_login)
165    {
166      result = handle_anonymous_login(p_sess, p_pass_str);
167    }
168    else
169    {
170      result = handle_local_login(p_sess, p_user_str, p_pass_str);
171    }
172    return result;
173  }
174}
175
176static enum EVSFPrivopLoginResult
177handle_anonymous_login(struct vsf_session* p_sess,
178                       const struct mystr* p_pass_str)
179{
180  if (!str_isempty(&p_sess->banned_email_str) &&
181      str_contains_line(&p_sess->banned_email_str, p_pass_str))
182  {
183    return kVSFLoginFail;
184  }
185  if (!str_isempty(&p_sess->email_passwords_str) &&
186      (!str_contains_line(&p_sess->email_passwords_str, p_pass_str) ||
187       str_isempty(p_pass_str)))
188  {
189    return kVSFLoginFail;
190  }
191  /* Store the anonymous identity string */
192  str_copy(&p_sess->anon_pass_str, p_pass_str);
193  if (str_isempty(&p_sess->anon_pass_str))
194  {
195    str_alloc_text(&p_sess->anon_pass_str, "?");
196  }
197  /* "Fix" any characters which might upset the log processing */
198  str_replace_char(&p_sess->anon_pass_str, ' ', '_');
199  str_replace_char(&p_sess->anon_pass_str, '\n', '?');
200  {
201    struct mystr ftp_username_str = INIT_MYSTR;
202    str_alloc_text(&ftp_username_str, tunable_ftp_username);
203    setup_username_globals(p_sess, &ftp_username_str);
204    str_free(&ftp_username_str);
205  }
206  str_free(&p_sess->banned_email_str);
207  str_free(&p_sess->email_passwords_str);
208  return kVSFLoginAnon;
209}
210
211static enum EVSFPrivopLoginResult
212handle_local_login(struct vsf_session* p_sess,
213                   const struct mystr* p_user_str,
214                   const struct mystr* p_pass_str)
215{
216  if (!vsf_sysdep_check_auth(p_user_str, p_pass_str, &p_sess->remote_ip_str))
217  {
218    return kVSFLoginFail;
219  }
220  setup_username_globals(p_sess, p_user_str);
221  return kVSFLoginReal;
222}
223
224static void
225setup_username_globals(struct vsf_session* p_sess, const struct mystr* p_str)
226{
227// 2007.08 James {
228  //int snum, unum, i, j;
229  //char user[64], user1[64], wright[384], tmpstr[64];
230// 2007.08 James }
231
232  str_copy(&p_sess->user_str, p_str);
233  if (tunable_setproctitle_enable)
234  {
235    struct mystr prefix_str = INIT_MYSTR;
236    str_copy(&prefix_str, &p_sess->remote_ip_str);
237    str_append_char(&prefix_str, '/');
238    str_append_str(&prefix_str, p_str);
239    vsf_sysutil_set_proctitle_prefix(&prefix_str);
240    str_free(&prefix_str);
241  }
242
243// 2007.08 James {
244  p_sess->write_enable = 1;
245  /*char cwdpath[VSFTP_PATH_MAX];
246  vsf_sysutil_getcwd(cwdpath, VSFTP_PATH_MAX);
247
248	if (nvram_match("st_ftp_mode", "1"))
249	{
250		p_sess->write_enable = 1;
251		return;
252	}
253
254	unum = atoi(nvram_safe_get("acc_num"));
255	for(i=-1;i<unum;i++)
256	{
257		if (i==-1)
258		{
259			strcpy(user, "Guest");
260			strcpy(user1, "anonymous");
261		}
262		else
263		{
264			sprintf(tmpstr, "acc_username%d", i);
265			strcpy(user, nvram_safe_get(tmpstr));
266			strcpy(user1, user);
267		}
268
269		if(strcmp(str_getbuf(p_str), user1)==0)
270		{
271			snum = atoi(nvram_safe_get("sh_num"));
272
273			for(j=0;j<snum;j++)
274			{
275				sprintf(tmpstr, "sh_wright%d", j);
276				strcpy(wright, nvram_safe_get(tmpstr));
277
278				if (test_user(wright, user)==1)
279				{
280					p_sess->write_enable = 1;
281					return;
282				}
283			}
284
285			p_sess->write_enable = 0;
286			return;
287		}
288	}
289
290	p_sess->write_enable = 0;*/
291// 2007.08 James }
292	return;
293
294}
295
296