1 /* Copyright 2003-2008 Wang, Chun-Pin All rights reserved. */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <sys/types.h>
5 #include <unistd.h>
6 #include <sys/types.h>
7 #include <syslog.h>
8 #include <string.h>
9 #include <paths.h>
10 #include <time.h>
11 #include <sys/stat.h>
12 #include <limits.h>
13 #include <grp.h>
14 #include <arpa/ftp.h>
15
16 #include "pathnames.h"
17 #include "smbftpd.h"
18 #include "restrict.h"
19 #include "ssl.h"
20 #include "auth.h"
21
22 extern smbftpd_share_t *smbftpd_shares;
23 extern smbftpd_conf_t smbftpd_conf;
24 extern smbftpd_session_t smbftpd_session;
25
26 extern int login_attempts;
27 extern int askpasswd;
28
29 #ifndef LINE_MAX
30 #define LINE_MAX 2048
31 #endif
32
33 /**
34 * Terminate login as previous user, if any, resetting state;
35 * Used when USER command is given or login fails.
36 */
end_login(void)37 void end_login(void)
38 {
39 (void) seteuid(0);
40 if (smbftpd_session.logged_in && smbftpd_conf.do_wtmp_log && !smbftpd_session.chroot)
41 smbftpd_logwtmp(NULL, NULL); // We don't do logwtmp in chroot, because it won't work anyway
42
43
44 if (smbftpd_conf.transfer_log_path) {
45 smbftpd_xferlog_close();
46 }
47
48 smbftpd_valid_share_free(&smbftpd_session.valid_shares);
49 if (smbftpd_session.home) {
50 free(smbftpd_session.home);
51 }
52 bzero(&smbftpd_session, sizeof(smbftpd_session));
53 }
54
55 /**
56 * Performing password authentication. The USER command shoule send first.
57 *
58 * @param passwd
59 */
cmd_pass(const char * passwd)60 void cmd_pass(const char *passwd)
61 {
62 int login_failed = 1;
63 FILE *fd;
64 char *chroot_dir = NULL, *home_dir = NULL;
65 const char *dir = NULL;
66
67 #ifdef WITH_SSL
68 if (!smbftpd_session.ssl_ctrl.ssl_active_flag &&
69 !(smbftpd_conf.security_policy & SECURITY_POLICY_NOSECURE)) {
70 reply_noformat(504, "TLS/SSL protection required.");
71 return;
72 }
73 #endif /* WITH_SSL */
74
75 if (smbftpd_session.logged_in || askpasswd == 0) {
76 reply_noformat(503, "Login with USER first.");
77 return;
78 }
79
80 askpasswd = 0;
81 if (!smbftpd_session.guest) {
82
83 if (smbftpd_session.pw_user == NULL) {
84 /* failure below */
85 goto skip;
86 }
87
88 if ((*passwd == '\0') && (smbftpd_conf.empty_passwd_login == 0)) {
89 reply_noformat(530, "Empty password is not allowed.");
90 if (login_attempts++ >= 5) {
91 syslog(LOG_NOTICE,
92 "repeated login failures from %s",
93 smbftpd_session.remotehost);
94 exit(0);
95 }
96 return;
97 }
98
99 if (0 == smbftpd_auth_check(smbftpd_session.username, passwd)) {
100 login_failed = 0;
101 }
102 skip:
103 /*
104 * If login_failed == 1, the user failed the authentication check
105 * above. If rval == 0, either PAM or local authentication
106 * succeeded.
107 */
108 if (login_failed) {
109 reply_noformat(530, "Login incorrect.");
110 if (smbftpd_conf.log_command) {
111 syslog(LOG_NOTICE,
112 "FTP LOGIN FAILED FROM %s",
113 smbftpd_session.remotehost);
114 syslog(LOG_AUTHPRIV | LOG_NOTICE,
115 "FTP LOGIN FAILED FROM %s, %s",
116 smbftpd_session.remotehost, smbftpd_session.username);
117 }
118 smbftpd_session.pw_user = NULL;
119 if (login_attempts++ >= 5) {
120 syslog(LOG_NOTICE,
121 "repeated login failures from %s",
122 smbftpd_session.remotehost);
123 exit(0);
124 }
125 return;
126 }
127 }
128 login_attempts = 0; /* this time successful */
129 if (setegid(smbftpd_session.pw_user->pw_gid) < 0) {
130 reply_noformat(550, "Can't set gid.");
131 return;
132 }
133
134 /* May be overridden by login.conf */
135 (void) umask(smbftpd_conf.umask);
136
137 #ifdef __FreeBSD__
138 setlogin(smbftpd_session.username);
139 #endif
140 (void) initgroups(smbftpd_session.pw_user->pw_name, smbftpd_session.pw_user->pw_gid);
141
142 /* open xfer log before chroot */
143 if (smbftpd_conf.transfer_log_path) {
144 smbftpd_xferlog_open(smbftpd_conf.transfer_log_path);
145 }
146
147 smbftpd_session.logged_in = 1;
148 smbftpd_session.transfer_type = TYPE_I;
149
150 /* Get FTP configuration and limitions for current user*/
151 smbftpd_session.mode = smbftpd_mode_get(smbftpd_conf.default_mode,
152 smbftpd_conf.exception_list, smbftpd_session.username);
153
154 smbftpd_session.max_upload_rate = smbftpd_transfer_rate_get(smbftpd_conf.max_upload_rate,
155 smbftpd_session.username);
156 smbftpd_session.max_download_rate = smbftpd_transfer_rate_get(smbftpd_conf.max_download_rate,
157 smbftpd_session.username);
158 smbftpd_valid_share_free(&smbftpd_session.valid_shares);
159
160 smbftpd_session.byte_uploaded = 0;
161 smbftpd_session.byte_downloaded = 0;
162
163 if (smbftpd_session.guest) {
164 home_dir = strdup(smbftpd_session.pw_user->pw_dir);
165 } else {
166 home_dir = smbftpd_auth_get_home(smbftpd_session.username);
167 }
168 if (home_dir == NULL) {
169 reply_noformat(550, "Can't get home dir.");
170 goto bad;
171 }
172
173 if (smbftpd_session.guest && smbftpd_session.mode != MODE_SMB) {
174 dir = smbftpd_session.pw_user->pw_dir;
175 } else {
176 dir = smbftpd_chroot_path_get(smbftpd_conf.chroot_set, smbftpd_session.username);
177 }
178 if (dir) {
179 smbftpd_session.chroot = 1;
180 smbftpd_session.mode = MODE_NORMAL;
181
182 if (dir[0] == '/') {
183 chroot_dir = strdup(dir); /* so it can be freed */
184 } else if (dir[0] == '~') {
185 asprintf(&chroot_dir, "%s/%s", home_dir, dir+1);
186 } else {
187 asprintf(&chroot_dir, "%s/%s", home_dir, dir);
188 }
189 if (chroot_dir == NULL)
190 fatalerror("Ran out of memory.");
191
192 free(home_dir);
193 home_dir = NULL;
194
195 smbftpd_session.home = strdup("/");
196 if (smbftpd_session.home == NULL) {
197 fatalerror("Ran out of memory.");
198 }
199
200 /*
201 * Finally, do chroot()
202 */
203 if (chroot(chroot_dir) < 0) {
204 reply_noformat(550, "Can't change root.");
205 goto bad;
206 }
207 } else {/* real user w/o chroot */
208 if (smbftpd_session.mode == MODE_SMB) {
209
210 if (0 != smbftpd_valid_share_get(smbftpd_session.username, home_dir,
211 smbftpd_shares, &smbftpd_session.valid_shares)) {
212 fatalerror("Ran out of memory.");
213 }
214 free(home_dir);
215 home_dir = NULL;
216
217 smbftpd_session.home = strdup(PATH_SMB_FTPD_ROOT);
218 } else {
219 smbftpd_session.home = home_dir;
220 }
221 }
222 if (smbftpd_session.home == NULL) {
223 fatalerror("Ran out of memory.");
224 }
225
226 if (smbftpd_conf.do_wtmp_log && !smbftpd_session.chroot) {
227 smbftpd_logwtmp(smbftpd_session.username, smbftpd_session.remotehost);
228 }
229
230 /*
231 * Set euid *before* doing chdir() so
232 * a) the user won't be carried to a directory that he couldn't reach
233 * on his own due to no permission to upper path components,
234 * b) NFS mounted homedirs w/restrictive permissions will be accessible
235 * (uid 0 has no root power over NFS if not mapped explicitly.)
236 */
237 if (seteuid(smbftpd_session.pw_user->pw_uid) < 0) {
238 reply_noformat(550, "Can't set uid.");
239 goto bad;
240 }
241
242 if (chdir(smbftpd_session.home) < 0) {
243 if (smbftpd_session.guest || smbftpd_session.chroot || smbftpd_session.mode == MODE_SMB) {
244 reply_noformat(550, "Can't change to base directory.");
245 goto bad;
246 } else {
247 if (chdir("/") < 0) {
248 reply_noformat(550, "Root is inaccessible.");
249 goto bad;
250 }
251 reply_noformat(LONG_REPLY(230), "No directory! Logging in with home=/.");
252 }
253 }
254
255 /*
256 * Display a login message, if it exists.
257 * N.B. reply(230,) must follow the message.
258 */
259 fd = fopen(PATH_FTPLOGINMESG, "r");
260 if (fd != NULL) {
261 char *cp, line[LINE_MAX];
262
263 while (fgets(line, sizeof(line), fd) != NULL) {
264 if ((cp = strchr(line, '\n')) != NULL)
265 *cp = '\0';
266 reply_noformat(LONG_REPLY(230), line);
267 }
268 (void) smbftpd_socket_fflush(stdout, 0);
269 (void) fclose(fd);
270 }
271 if (smbftpd_session.guest) {
272
273 reply_noformat(230, "Guest login ok, access restrictions apply.");
274
275 proc_title_init("%s: anonymous/%s", smbftpd_session.remotehost, passwd);
276
277 if (smbftpd_conf.log_command)
278 syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
279 smbftpd_session.remotehost, passwd);
280 } else {
281 if (smbftpd_session.chroot)
282 reply(230, "User %s logged in, "
283 "access restrictions apply.", smbftpd_session.username);
284 else
285 reply(230, "User %s logged in.", smbftpd_session.username);
286
287 proc_title_init("%s: user/%s", smbftpd_session.remotehost, smbftpd_session.username);
288
289 if (smbftpd_conf.log_command)
290 syslog(LOG_INFO, "FTP LOGIN FROM %s as %s",
291 smbftpd_session.remotehost, smbftpd_session.username);
292 }
293
294 if (chroot_dir)
295 free(chroot_dir);
296 return;
297 bad:
298 /* Forget all about it... */
299 if (chroot_dir)
300 free(chroot_dir);
301 end_login();
302 }
303