Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/heimdal/appl/ftp/ftpd/ftpd.c
34907 views
1
/*
2
* Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994
3
* The Regents of the University of California. All rights reserved.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
* 3. All advertising materials mentioning features or use of this software
14
* must display the following acknowledgement:
15
* This product includes software developed by the University of
16
* California, Berkeley and its contributors.
17
* 4. Neither the name of the University nor the names of its contributors
18
* may be used to endorse or promote products derived from this software
19
* without specific prior written permission.
20
*
21
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31
* SUCH DAMAGE.
32
*/
33
34
#define FTP_NAMES
35
#include "ftpd_locl.h"
36
#ifdef KRB5
37
#include <krb5.h>
38
#endif
39
#include "getarg.h"
40
41
RCSID("$Id$");
42
43
static char version[] = "Version 6.00";
44
45
extern off_t restart_point;
46
extern char cbuf[];
47
48
struct sockaddr_storage ctrl_addr_ss;
49
struct sockaddr *ctrl_addr = (struct sockaddr *)&ctrl_addr_ss;
50
51
struct sockaddr_storage data_source_ss;
52
struct sockaddr *data_source = (struct sockaddr *)&data_source_ss;
53
54
struct sockaddr_storage data_dest_ss;
55
struct sockaddr *data_dest = (struct sockaddr *)&data_dest_ss;
56
57
struct sockaddr_storage his_addr_ss;
58
struct sockaddr *his_addr = (struct sockaddr *)&his_addr_ss;
59
60
struct sockaddr_storage pasv_addr_ss;
61
struct sockaddr *pasv_addr = (struct sockaddr *)&pasv_addr_ss;
62
63
int data;
64
int logged_in;
65
struct passwd *pw;
66
int debug = 0;
67
int ftpd_timeout = 900; /* timeout after 15 minutes of inactivity */
68
int maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */
69
int restricted_data_ports = 1;
70
int logging;
71
int guest;
72
int dochroot;
73
int type;
74
int form;
75
int stru; /* avoid C keyword */
76
int mode;
77
int usedefault = 1; /* for data transfers */
78
int pdata = -1; /* for passive mode */
79
int allow_insecure_oob = 1;
80
static int transflag;
81
static int urgflag;
82
off_t file_size;
83
off_t byte_count;
84
#if !defined(CMASK) || CMASK == 0
85
#undef CMASK
86
#define CMASK 027
87
#endif
88
int defumask = CMASK; /* default umask value */
89
int guest_umask = 0777; /* Paranoia for anonymous users */
90
char tmpline[10240];
91
char hostname[MaxHostNameLen];
92
char remotehost[MaxHostNameLen];
93
static char ttyline[20];
94
int paranoid = 1;
95
96
#define AUTH_PLAIN (1 << 0) /* allow sending passwords */
97
#define AUTH_OTP (1 << 1) /* passwords are one-time */
98
#define AUTH_FTP (1 << 2) /* allow anonymous login */
99
100
static int auth_level = 0; /* Only allow kerberos login by default */
101
102
/*
103
* Timeout intervals for retrying connections
104
* to hosts that don't accept PORT cmds. This
105
* is a kludge, but given the problems with TCP...
106
*/
107
#define SWAITMAX 90 /* wait at most 90 seconds */
108
#define SWAITINT 5 /* interval between retries */
109
110
int swaitmax = SWAITMAX;
111
int swaitint = SWAITINT;
112
113
#ifdef HAVE_SETPROCTITLE
114
char proctitle[BUFSIZ]; /* initial part of title */
115
#endif /* HAVE_SETPROCTITLE */
116
117
#define LOGCMD(cmd, file) \
118
if (logging > 1) \
119
syslog(LOG_INFO,"%s %s%s", cmd, \
120
*(file) == '/' ? "" : curdir(), file);
121
#define LOGCMD2(cmd, file1, file2) \
122
if (logging > 1) \
123
syslog(LOG_INFO,"%s %s%s %s%s", cmd, \
124
*(file1) == '/' ? "" : curdir(), file1, \
125
*(file2) == '/' ? "" : curdir(), file2);
126
#define LOGBYTES(cmd, file, cnt) \
127
if (logging > 1) { \
128
if (cnt == (off_t)-1) \
129
syslog(LOG_INFO,"%s %s%s", cmd, \
130
*(file) == '/' ? "" : curdir(), file); \
131
else \
132
syslog(LOG_INFO, "%s %s%s = %ld bytes", \
133
cmd, (*(file) == '/') ? "" : curdir(), file, (long)cnt); \
134
}
135
136
static void ack (char *);
137
static void myoob (int);
138
static int handleoobcmd(void);
139
static int checkuser (char *, char *);
140
static int checkaccess (char *);
141
static FILE *dataconn (const char *, off_t, const char *);
142
static void dolog (struct sockaddr *, int);
143
static void end_login (void);
144
static FILE *getdatasock (const char *, int);
145
static char *gunique (char *);
146
static RETSIGTYPE lostconn (int);
147
static int receive_data (FILE *, FILE *);
148
static void send_data (FILE *, FILE *);
149
static struct passwd * sgetpwnam (char *);
150
151
static char *
152
curdir(void)
153
{
154
static char path[MaxPathLen+1]; /* path + '/' + '\0' */
155
156
if (getcwd(path, sizeof(path)-1) == NULL)
157
return ("");
158
if (path[1] != '\0') /* special case for root dir. */
159
strlcat(path, "/", sizeof(path));
160
/* For guest account, skip / since it's chrooted */
161
return (guest ? path+1 : path);
162
}
163
164
#ifndef LINE_MAX
165
#define LINE_MAX 1024
166
#endif
167
168
static int
169
parse_auth_level(char *str)
170
{
171
char *p;
172
int ret = 0;
173
char *foo = NULL;
174
175
for(p = strtok_r(str, ",", &foo);
176
p;
177
p = strtok_r(NULL, ",", &foo)) {
178
if(strcmp(p, "user") == 0)
179
;
180
#ifdef OTP
181
else if(strcmp(p, "otp") == 0)
182
ret |= AUTH_PLAIN|AUTH_OTP;
183
#endif
184
else if(strcmp(p, "ftp") == 0 ||
185
strcmp(p, "safe") == 0)
186
ret |= AUTH_FTP;
187
else if(strcmp(p, "plain") == 0)
188
ret |= AUTH_PLAIN;
189
else if(strcmp(p, "none") == 0)
190
ret |= AUTH_PLAIN|AUTH_FTP;
191
else
192
warnx("bad value for -a: `%s'", p);
193
}
194
return ret;
195
}
196
197
/*
198
* Print usage and die.
199
*/
200
201
static int interactive_flag;
202
static char *guest_umask_string;
203
static char *port_string;
204
static char *umask_string;
205
static char *auth_string;
206
207
int use_builtin_ls = -1;
208
209
static int help_flag;
210
static int version_flag;
211
212
static const char *good_chars = "+-=_,.";
213
214
struct getargs args[] = {
215
{ NULL, 'a', arg_string, &auth_string, "required authentication" },
216
{ NULL, 'i', arg_flag, &interactive_flag, "don't assume stdin is a socket" },
217
{ NULL, 'p', arg_string, &port_string, "what port to listen to" },
218
{ NULL, 'g', arg_string, &guest_umask_string, "umask for guest logins" },
219
{ NULL, 'l', arg_counter, &logging, "log more stuff", "" },
220
{ NULL, 't', arg_integer, &ftpd_timeout, "initial timeout" },
221
{ NULL, 'T', arg_integer, &maxtimeout, "max timeout" },
222
{ NULL, 'u', arg_string, &umask_string, "umask for user logins" },
223
{ NULL, 'U', arg_negative_flag, &restricted_data_ports, "don't use high data ports" },
224
{ NULL, 'd', arg_flag, &debug, "enable debugging" },
225
{ NULL, 'v', arg_flag, &debug, "enable debugging" },
226
{ "builtin-ls", 'B', arg_flag, &use_builtin_ls, "use built-in ls to list files" },
227
{ "good-chars", 0, arg_string, &good_chars, "allowed anonymous upload filename chars" },
228
{ "insecure-oob", 'I', arg_negative_flag, &allow_insecure_oob, "don't allow insecure OOB ABOR/STAT" },
229
#ifdef KRB5
230
{ "gss-bindings", 0, arg_flag, &ftp_do_gss_bindings, "Require GSS-API bindings", NULL},
231
#endif
232
{ "version", 0, arg_flag, &version_flag },
233
{ "help", 'h', arg_flag, &help_flag }
234
};
235
236
static int num_args = sizeof(args) / sizeof(args[0]);
237
238
static void
239
usage (int code)
240
{
241
arg_printusage(args, num_args, NULL, "");
242
exit (code);
243
}
244
245
/* output contents of a file */
246
static int
247
show_file(const char *file, int code)
248
{
249
FILE *f;
250
char buf[128];
251
252
f = fopen(file, "r");
253
if(f == NULL)
254
return -1;
255
while(fgets(buf, sizeof(buf), f)){
256
buf[strcspn(buf, "\r\n")] = '\0';
257
lreply(code, "%s", buf);
258
}
259
fclose(f);
260
return 0;
261
}
262
263
int
264
main(int argc, char **argv)
265
{
266
socklen_t his_addr_len, ctrl_addr_len;
267
int on = 1;
268
int port;
269
struct servent *sp;
270
271
int optind = 0;
272
273
setprogname (argv[0]);
274
275
if(getarg(args, num_args, argc, argv, &optind))
276
usage(1);
277
278
if(help_flag)
279
usage(0);
280
281
if(version_flag) {
282
print_version(NULL);
283
exit(0);
284
}
285
286
if(auth_string)
287
auth_level = parse_auth_level(auth_string);
288
{
289
char *p;
290
long val = 0;
291
292
if(guest_umask_string) {
293
val = strtol(guest_umask_string, &p, 8);
294
if (*p != '\0' || val < 0)
295
warnx("bad value for -g");
296
else
297
guest_umask = val;
298
}
299
if(umask_string) {
300
val = strtol(umask_string, &p, 8);
301
if (*p != '\0' || val < 0)
302
warnx("bad value for -u");
303
else
304
defumask = val;
305
}
306
}
307
sp = getservbyname("ftp", "tcp");
308
if(sp)
309
port = sp->s_port;
310
else
311
port = htons(21);
312
if(port_string) {
313
sp = getservbyname(port_string, "tcp");
314
if(sp)
315
port = sp->s_port;
316
else
317
if(isdigit((unsigned char)port_string[0]))
318
port = htons(atoi(port_string));
319
else
320
warnx("bad value for -p");
321
}
322
323
if (maxtimeout < ftpd_timeout)
324
maxtimeout = ftpd_timeout;
325
326
#if 0
327
if (ftpd_timeout > maxtimeout)
328
ftpd_timeout = maxtimeout;
329
#endif
330
331
if(interactive_flag)
332
mini_inetd(port, NULL);
333
334
/*
335
* LOG_NDELAY sets up the logging connection immediately,
336
* necessary for anonymous ftp's that chroot and can't do it later.
337
*/
338
openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
339
his_addr_len = sizeof(his_addr_ss);
340
if (getpeername(STDIN_FILENO, his_addr, &his_addr_len) < 0) {
341
syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
342
exit(1);
343
}
344
ctrl_addr_len = sizeof(ctrl_addr_ss);
345
if (getsockname(STDIN_FILENO, ctrl_addr, &ctrl_addr_len) < 0) {
346
syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
347
exit(1);
348
}
349
#if defined(IP_TOS)
350
if (ctrl_addr->sa_family == AF_INET)
351
socket_set_tos(STDIN_FILENO, IP_TOS);
352
#endif
353
data_source->sa_family = ctrl_addr->sa_family;
354
socket_set_port (data_source,
355
htons(ntohs(socket_get_port(ctrl_addr)) - 1));
356
357
/* set this here so it can be put in wtmp */
358
snprintf(ttyline, sizeof(ttyline), "ftp%u", (unsigned)getpid());
359
360
361
/* freopen(_PATH_DEVNULL, "w", stderr); */
362
signal(SIGPIPE, lostconn);
363
signal(SIGCHLD, SIG_IGN);
364
#ifdef SIGURG
365
if (signal(SIGURG, myoob) == SIG_ERR)
366
syslog(LOG_ERR, "signal: %m");
367
#endif
368
369
/* Try to handle urgent data inline */
370
#if defined(SO_OOBINLINE) && defined(HAVE_SETSOCKOPT)
371
if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (void *)&on,
372
sizeof(on)) < 0)
373
syslog(LOG_ERR, "setsockopt: %m");
374
#endif
375
376
#ifdef F_SETOWN
377
if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
378
syslog(LOG_ERR, "fcntl F_SETOWN: %m");
379
#endif
380
dolog(his_addr, his_addr_len);
381
/*
382
* Set up default state
383
*/
384
data = -1;
385
type = TYPE_A;
386
form = FORM_N;
387
stru = STRU_F;
388
mode = MODE_S;
389
tmpline[0] = '\0';
390
391
/* If logins are disabled, print out the message. */
392
if(show_file(_PATH_NOLOGIN, 530) == 0) {
393
reply(530, "System not available.");
394
exit(0);
395
}
396
show_file(_PATH_FTPWELCOME, 220);
397
/* reply(220,) must follow */
398
gethostname(hostname, sizeof(hostname));
399
400
reply(220, "%s FTP server (%s"
401
#ifdef KRB5
402
"+%s"
403
#endif
404
") ready.", hostname, version
405
#ifdef KRB5
406
,heimdal_version
407
#endif
408
);
409
410
for (;;)
411
yyparse();
412
/* NOTREACHED */
413
}
414
415
static RETSIGTYPE
416
lostconn(int signo)
417
{
418
419
if (debug)
420
syslog(LOG_DEBUG, "lost connection");
421
dologout(-1);
422
}
423
424
/*
425
* Helper function for sgetpwnam().
426
*/
427
static char *
428
sgetsave(char *s)
429
{
430
char *new = strdup(s);
431
432
if (new == NULL) {
433
perror_reply(421, "Local resource failure: malloc");
434
dologout(1);
435
/* NOTREACHED */
436
}
437
return new;
438
}
439
440
/*
441
* Save the result of a getpwnam. Used for USER command, since
442
* the data returned must not be clobbered by any other command
443
* (e.g., globbing).
444
*/
445
static struct passwd *
446
sgetpwnam(char *name)
447
{
448
static struct passwd save;
449
struct passwd *p;
450
451
if ((p = k_getpwnam(name)) == NULL)
452
return (p);
453
if (save.pw_name) {
454
free(save.pw_name);
455
free(save.pw_passwd);
456
free(save.pw_gecos);
457
free(save.pw_dir);
458
free(save.pw_shell);
459
}
460
save = *p;
461
save.pw_name = sgetsave(p->pw_name);
462
save.pw_passwd = sgetsave(p->pw_passwd);
463
save.pw_gecos = sgetsave(p->pw_gecos);
464
save.pw_dir = sgetsave(p->pw_dir);
465
save.pw_shell = sgetsave(p->pw_shell);
466
return (&save);
467
}
468
469
static int login_attempts; /* number of failed login attempts */
470
static int askpasswd; /* had user command, ask for passwd */
471
static char curname[10]; /* current USER name */
472
#ifdef OTP
473
OtpContext otp_ctx;
474
#endif
475
476
/*
477
* USER command.
478
* Sets global passwd pointer pw if named account exists and is acceptable;
479
* sets askpasswd if a PASS command is expected. If logged in previously,
480
* need to reset state. If name is "ftp" or "anonymous", the name is not in
481
* _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
482
* If account doesn't exist, ask for passwd anyway. Otherwise, check user
483
* requesting login privileges. Disallow anyone who does not have a standard
484
* shell as returned by getusershell(). Disallow anyone mentioned in the file
485
* _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
486
*/
487
void
488
user(char *name)
489
{
490
char *cp, *shell;
491
492
if(auth_level == 0 && !sec_complete){
493
reply(530, "No login allowed without authorization.");
494
return;
495
}
496
497
if (logged_in) {
498
if (guest) {
499
reply(530, "Can't change user from guest login.");
500
return;
501
} else if (dochroot) {
502
reply(530, "Can't change user from chroot user.");
503
return;
504
}
505
end_login();
506
}
507
508
guest = 0;
509
if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
510
if ((auth_level & AUTH_FTP) == 0 ||
511
checkaccess("ftp") ||
512
checkaccess("anonymous"))
513
reply(530, "User %s access denied.", name);
514
else if ((pw = sgetpwnam("ftp")) != NULL) {
515
guest = 1;
516
defumask = guest_umask; /* paranoia for incoming */
517
askpasswd = 1;
518
reply(331, "Guest login ok, type your name as password.");
519
} else
520
reply(530, "User %s unknown.", name);
521
if (!askpasswd && logging) {
522
char data_addr[256];
523
524
if (inet_ntop (his_addr->sa_family,
525
socket_get_address(his_addr),
526
data_addr, sizeof(data_addr)) == NULL)
527
strlcpy (data_addr, "unknown address",
528
sizeof(data_addr));
529
530
syslog(LOG_NOTICE,
531
"ANONYMOUS FTP LOGIN REFUSED FROM %s(%s)",
532
remotehost, data_addr);
533
}
534
return;
535
}
536
if((auth_level & AUTH_PLAIN) == 0 && !sec_complete){
537
reply(530, "Only authorized and anonymous login allowed.");
538
return;
539
}
540
if ((pw = sgetpwnam(name))) {
541
if ((shell = pw->pw_shell) == NULL || *shell == 0)
542
shell = _PATH_BSHELL;
543
while ((cp = getusershell()) != NULL)
544
if (strcmp(cp, shell) == 0)
545
break;
546
endusershell();
547
548
if (cp == NULL || checkaccess(name)) {
549
reply(530, "User %s access denied.", name);
550
if (logging) {
551
char data_addr[256];
552
553
if (inet_ntop (his_addr->sa_family,
554
socket_get_address(his_addr),
555
data_addr,
556
sizeof(data_addr)) == NULL)
557
strlcpy (data_addr,
558
"unknown address",
559
sizeof(data_addr));
560
561
syslog(LOG_NOTICE,
562
"FTP LOGIN REFUSED FROM %s(%s), %s",
563
remotehost,
564
data_addr,
565
name);
566
}
567
pw = (struct passwd *) NULL;
568
return;
569
}
570
}
571
if (logging)
572
strlcpy(curname, name, sizeof(curname));
573
if(sec_complete) {
574
if(sec_userok(name) == 0) {
575
do_login(232, name);
576
sec_session(name);
577
} else
578
reply(530, "User %s access denied.", name);
579
} else {
580
#ifdef OTP
581
char ss[256];
582
583
if (otp_challenge(&otp_ctx, name, ss, sizeof(ss)) == 0) {
584
reply(331, "Password %s for %s required.",
585
ss, name);
586
askpasswd = 1;
587
} else
588
#endif
589
if ((auth_level & AUTH_OTP) == 0) {
590
reply(331, "Password required for %s.", name);
591
askpasswd = 1;
592
} else {
593
#ifdef OTP
594
char *s;
595
596
if ((s = otp_error (&otp_ctx)) != NULL)
597
lreply(530, "OTP: %s", s);
598
#endif
599
reply(530,
600
"Only authorized, anonymous"
601
#ifdef OTP
602
" and OTP "
603
#endif
604
"login allowed.");
605
}
606
607
}
608
/*
609
* Delay before reading passwd after first failed
610
* attempt to slow down passwd-guessing programs.
611
*/
612
if (login_attempts)
613
sleep(login_attempts);
614
}
615
616
/*
617
* Check if a user is in the file "fname"
618
*/
619
static int
620
checkuser(char *fname, char *name)
621
{
622
FILE *fd;
623
int found = 0;
624
char *p, line[BUFSIZ];
625
626
if ((fd = fopen(fname, "r")) != NULL) {
627
while (fgets(line, sizeof(line), fd) != NULL)
628
if ((p = strchr(line, '\n')) != NULL) {
629
*p = '\0';
630
if (line[0] == '#')
631
continue;
632
if (strcmp(line, name) == 0) {
633
found = 1;
634
break;
635
}
636
}
637
fclose(fd);
638
}
639
return (found);
640
}
641
642
643
/*
644
* Determine whether a user has access, based on information in
645
* _PATH_FTPUSERS. The users are listed one per line, with `allow'
646
* or `deny' after the username. If anything other than `allow', or
647
* just nothing, is given after the username, `deny' is assumed.
648
*
649
* If the user is not found in the file, but the pseudo-user `*' is,
650
* the permission is taken from that line.
651
*
652
* This preserves the old semantics where if a user was listed in the
653
* file he was denied, otherwise he was allowed.
654
*
655
* Return 1 if the user is denied, or 0 if he is allowed. */
656
657
static int
658
match(const char *pattern, const char *string)
659
{
660
return fnmatch(pattern, string, FNM_NOESCAPE);
661
}
662
663
static int
664
checkaccess(char *name)
665
{
666
#define ALLOWED 0
667
#define NOT_ALLOWED 1
668
FILE *fd;
669
int allowed = ALLOWED;
670
char *user, *perm, line[BUFSIZ];
671
char *foo;
672
673
fd = fopen(_PATH_FTPUSERS, "r");
674
675
if(fd == NULL)
676
return allowed;
677
678
while (fgets(line, sizeof(line), fd) != NULL) {
679
foo = NULL;
680
user = strtok_r(line, " \t\n", &foo);
681
if (user == NULL || user[0] == '#')
682
continue;
683
perm = strtok_r(NULL, " \t\n", &foo);
684
if (match(user, name) == 0){
685
if(perm && strcmp(perm, "allow") == 0)
686
allowed = ALLOWED;
687
else
688
allowed = NOT_ALLOWED;
689
break;
690
}
691
}
692
fclose(fd);
693
return allowed;
694
}
695
#undef ALLOWED
696
#undef NOT_ALLOWED
697
698
699
int do_login(int code, char *passwd)
700
{
701
login_attempts = 0; /* this time successful */
702
if (setegid((gid_t)pw->pw_gid) < 0) {
703
reply(550, "Can't set gid.");
704
return -1;
705
}
706
initgroups(pw->pw_name, pw->pw_gid);
707
#if defined(KRB5)
708
if(k_hasafs())
709
k_setpag();
710
#endif
711
712
/* open wtmp before chroot */
713
ftpd_logwtmp(ttyline, pw->pw_name, remotehost);
714
logged_in = 1;
715
716
dochroot = checkuser(_PATH_FTPCHROOT, pw->pw_name);
717
if (guest) {
718
/*
719
* We MUST do a chdir() after the chroot. Otherwise
720
* the old current directory will be accessible as "."
721
* outside the new root!
722
*/
723
if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
724
reply(550, "Can't set guest privileges.");
725
return -1;
726
}
727
} else if (dochroot) {
728
if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
729
reply(550, "Can't change root.");
730
return -1;
731
}
732
} else if (chdir(pw->pw_dir) < 0) {
733
if (chdir("/") < 0) {
734
reply(530, "User %s: can't change directory to %s.",
735
pw->pw_name, pw->pw_dir);
736
return -1;
737
} else
738
lreply(code, "No directory! Logging in with home=/");
739
}
740
if (seteuid((uid_t)pw->pw_uid) < 0) {
741
reply(550, "Can't set uid.");
742
return -1;
743
}
744
745
if(use_builtin_ls == -1) {
746
struct stat st;
747
/* if /bin/ls exist and is a regular file, use it, otherwise
748
use built-in ls */
749
if(stat("/bin/ls", &st) == 0 &&
750
S_ISREG(st.st_mode))
751
use_builtin_ls = 0;
752
else
753
use_builtin_ls = 1;
754
}
755
756
/*
757
* Display a login message, if it exists.
758
* N.B. reply(code,) must follow the message.
759
*/
760
show_file(_PATH_FTPLOGINMESG, code);
761
if(show_file(_PATH_ISSUE_NET, code) != 0)
762
show_file(_PATH_ISSUE, code);
763
if (guest) {
764
reply(code, "Guest login ok, access restrictions apply.");
765
#ifdef HAVE_SETPROCTITLE
766
snprintf (proctitle, sizeof(proctitle),
767
"%s: anonymous/%s",
768
remotehost,
769
passwd);
770
setproctitle("%s", proctitle);
771
#endif /* HAVE_SETPROCTITLE */
772
if (logging) {
773
char data_addr[256];
774
775
if (inet_ntop (his_addr->sa_family,
776
socket_get_address(his_addr),
777
data_addr, sizeof(data_addr)) == NULL)
778
strlcpy (data_addr, "unknown address",
779
sizeof(data_addr));
780
781
syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s(%s), %s",
782
remotehost,
783
data_addr,
784
passwd);
785
}
786
} else {
787
reply(code, "User %s logged in.", pw->pw_name);
788
#ifdef HAVE_SETPROCTITLE
789
snprintf(proctitle, sizeof(proctitle), "%s: %s", remotehost, pw->pw_name);
790
setproctitle("%s", proctitle);
791
#endif /* HAVE_SETPROCTITLE */
792
if (logging) {
793
char data_addr[256];
794
795
if (inet_ntop (his_addr->sa_family,
796
socket_get_address(his_addr),
797
data_addr, sizeof(data_addr)) == NULL)
798
strlcpy (data_addr, "unknown address",
799
sizeof(data_addr));
800
801
syslog(LOG_INFO, "FTP LOGIN FROM %s(%s) as %s",
802
remotehost,
803
data_addr,
804
pw->pw_name);
805
}
806
}
807
umask(defumask);
808
return 0;
809
}
810
811
/*
812
* Terminate login as previous user, if any, resetting state;
813
* used when USER command is given or login fails.
814
*/
815
static void
816
end_login(void)
817
{
818
819
if (seteuid((uid_t)0) < 0)
820
fatal("Failed to seteuid");
821
if (logged_in)
822
ftpd_logwtmp(ttyline, "", "");
823
pw = NULL;
824
logged_in = 0;
825
guest = 0;
826
dochroot = 0;
827
}
828
829
#ifdef KRB5
830
static int
831
krb5_verify(struct passwd *pwd, char *passwd)
832
{
833
krb5_context context;
834
krb5_ccache id;
835
krb5_principal princ;
836
krb5_error_code ret;
837
838
ret = krb5_init_context(&context);
839
if(ret)
840
return ret;
841
842
ret = krb5_parse_name(context, pwd->pw_name, &princ);
843
if(ret){
844
krb5_free_context(context);
845
return ret;
846
}
847
ret = krb5_cc_new_unique(context, "MEMORY", NULL, &id);
848
if(ret){
849
krb5_free_principal(context, princ);
850
krb5_free_context(context);
851
return ret;
852
}
853
ret = krb5_verify_user(context,
854
princ,
855
id,
856
passwd,
857
1,
858
NULL);
859
krb5_free_principal(context, princ);
860
if (k_hasafs()) {
861
krb5_afslog_uid_home(context, id,NULL, NULL,pwd->pw_uid, pwd->pw_dir);
862
}
863
krb5_cc_destroy(context, id);
864
krb5_free_context (context);
865
if(ret)
866
return ret;
867
return 0;
868
}
869
#endif /* KRB5 */
870
871
void
872
pass(char *passwd)
873
{
874
int rval;
875
876
/* some clients insists on sending a password */
877
if (logged_in && askpasswd == 0){
878
reply(230, "Password not necessary");
879
return;
880
}
881
882
if (logged_in || askpasswd == 0) {
883
reply(503, "Login with USER first.");
884
return;
885
}
886
askpasswd = 0;
887
rval = 1;
888
if (!guest) { /* "ftp" is only account allowed no password */
889
if (pw == NULL)
890
rval = 1; /* failure below */
891
#ifdef OTP
892
else if (otp_verify_user (&otp_ctx, passwd) == 0) {
893
rval = 0;
894
}
895
#endif
896
else if((auth_level & AUTH_OTP) == 0) {
897
#ifdef KRB5
898
rval = krb5_verify(pw, passwd);
899
#endif
900
if (rval)
901
rval = unix_verify_user(pw->pw_name, passwd);
902
} else {
903
#ifdef OTP
904
char *s;
905
if ((s = otp_error(&otp_ctx)) != NULL)
906
lreply(530, "OTP: %s", s);
907
#endif
908
}
909
memset (passwd, 0, strlen(passwd));
910
911
/*
912
* If rval == 1, the user failed the authentication
913
* check above. If rval == 0, either Kerberos or
914
* local authentication succeeded.
915
*/
916
if (rval) {
917
char data_addr[256];
918
919
if (inet_ntop (his_addr->sa_family,
920
socket_get_address(his_addr),
921
data_addr, sizeof(data_addr)) == NULL)
922
strlcpy (data_addr, "unknown address",
923
sizeof(data_addr));
924
925
reply(530, "Login incorrect.");
926
if (logging)
927
syslog(LOG_NOTICE,
928
"FTP LOGIN FAILED FROM %s(%s), %s",
929
remotehost,
930
data_addr,
931
curname);
932
pw = NULL;
933
if (login_attempts++ >= 5) {
934
syslog(LOG_NOTICE,
935
"repeated login failures from %s(%s)",
936
remotehost,
937
data_addr);
938
exit(0);
939
}
940
return;
941
}
942
}
943
if(!do_login(230, passwd))
944
return;
945
946
/* Forget all about it... */
947
end_login();
948
}
949
950
void
951
retrieve(const char *cmd, char *name)
952
{
953
FILE *fin = NULL, *dout;
954
struct stat st;
955
int (*closefunc) (FILE *);
956
char line[BUFSIZ];
957
958
959
if (cmd == 0) {
960
fin = fopen(name, "r");
961
closefunc = fclose;
962
st.st_size = 0;
963
if(fin == NULL){
964
int save_errno = errno;
965
struct cmds {
966
const char *ext;
967
const char *cmd;
968
const char *rev_cmd;
969
} cmds[] = {
970
{".tar", "/bin/gtar cPf - %s", NULL},
971
{".tar.gz", "/bin/gtar zcPf - %s", NULL},
972
{".tar.Z", "/bin/gtar ZcPf - %s", NULL},
973
{".gz", "/bin/gzip -c -- %s", "/bin/gzip -c -d -- %s"},
974
{".Z", "/bin/compress -c -- %s", "/bin/uncompress -c -- %s"},
975
{NULL, NULL}
976
};
977
struct cmds *p;
978
for(p = cmds; p->ext; p++){
979
char *tail = name + strlen(name) - strlen(p->ext);
980
char c = *tail;
981
982
if(strcmp(tail, p->ext) == 0 &&
983
(*tail = 0) == 0 &&
984
access(name, R_OK) == 0){
985
snprintf (line, sizeof(line), p->cmd, name);
986
*tail = c;
987
break;
988
}
989
*tail = c;
990
if (p->rev_cmd != NULL) {
991
char *ext;
992
int ret;
993
994
ret = asprintf(&ext, "%s%s", name, p->ext);
995
if (ret != -1) {
996
if (access(ext, R_OK) == 0) {
997
snprintf (line, sizeof(line),
998
p->rev_cmd, ext);
999
free(ext);
1000
break;
1001
}
1002
free(ext);
1003
}
1004
}
1005
1006
}
1007
if(p->ext){
1008
fin = ftpd_popen(line, "r", 0, 0);
1009
closefunc = ftpd_pclose;
1010
st.st_size = -1;
1011
cmd = line;
1012
} else
1013
errno = save_errno;
1014
}
1015
} else {
1016
snprintf(line, sizeof(line), cmd, name);
1017
name = line;
1018
fin = ftpd_popen(line, "r", 1, 0);
1019
closefunc = ftpd_pclose;
1020
st.st_size = -1;
1021
}
1022
if (fin == NULL) {
1023
if (errno != 0) {
1024
perror_reply(550, name);
1025
if (cmd == 0) {
1026
LOGCMD("get", name);
1027
}
1028
}
1029
return;
1030
}
1031
byte_count = -1;
1032
if (cmd == 0){
1033
if(fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode)) {
1034
reply(550, "%s: not a plain file.", name);
1035
goto done;
1036
}
1037
}
1038
if (restart_point) {
1039
if (type == TYPE_A) {
1040
off_t i, n;
1041
int c;
1042
1043
n = restart_point;
1044
i = 0;
1045
while (i++ < n) {
1046
if ((c=getc(fin)) == EOF) {
1047
perror_reply(550, name);
1048
goto done;
1049
}
1050
if (c == '\n')
1051
i++;
1052
}
1053
} else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
1054
perror_reply(550, name);
1055
goto done;
1056
}
1057
}
1058
dout = dataconn(name, st.st_size, "w");
1059
if (dout == NULL)
1060
goto done;
1061
set_buffer_size(fileno(dout), 0);
1062
send_data(fin, dout);
1063
fclose(dout);
1064
data = -1;
1065
pdata = -1;
1066
done:
1067
if (cmd == 0)
1068
LOGBYTES("get", name, byte_count);
1069
(*closefunc)(fin);
1070
}
1071
1072
/* filename sanity check */
1073
1074
int
1075
filename_check(char *filename)
1076
{
1077
char *p;
1078
1079
p = strrchr(filename, '/');
1080
if(p)
1081
filename = p + 1;
1082
1083
p = filename;
1084
1085
if(isalnum((unsigned char)*p)){
1086
p++;
1087
while(*p && (isalnum((unsigned char)*p) || strchr(good_chars, (unsigned char)*p)))
1088
p++;
1089
if(*p == '\0')
1090
return 0;
1091
}
1092
lreply(553, "\"%s\" is not an acceptable filename.", filename);
1093
lreply(553, "The filename must start with an alphanumeric "
1094
"character and must only");
1095
reply(553, "consist of alphanumeric characters or any of the following: %s",
1096
good_chars);
1097
return 1;
1098
}
1099
1100
void
1101
do_store(char *name, char *mode, int unique)
1102
{
1103
FILE *fout, *din;
1104
struct stat st;
1105
int (*closefunc) (FILE *);
1106
1107
if(guest && filename_check(name))
1108
return;
1109
if (unique) {
1110
char *uname;
1111
if (stat(name, &st) == 0) {
1112
if ((uname = gunique(name)) == NULL)
1113
return;
1114
name = uname;
1115
}
1116
LOGCMD(*mode == 'w' ? "put" : "append", name);
1117
}
1118
1119
if (restart_point)
1120
mode = "r+";
1121
fout = fopen(name, mode);
1122
closefunc = fclose;
1123
if (fout == NULL) {
1124
perror_reply(553, name);
1125
LOGCMD(*mode == 'w' ? "put" : "append", name);
1126
return;
1127
}
1128
byte_count = -1;
1129
if (restart_point) {
1130
if (type == TYPE_A) {
1131
off_t i, n;
1132
int c;
1133
1134
n = restart_point;
1135
i = 0;
1136
while (i++ < n) {
1137
if ((c=getc(fout)) == EOF) {
1138
perror_reply(550, name);
1139
goto done;
1140
}
1141
if (c == '\n')
1142
i++;
1143
}
1144
/*
1145
* We must do this seek to "current" position
1146
* because we are changing from reading to
1147
* writing.
1148
*/
1149
if (fseek(fout, 0L, SEEK_CUR) < 0) {
1150
perror_reply(550, name);
1151
goto done;
1152
}
1153
} else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
1154
perror_reply(550, name);
1155
goto done;
1156
}
1157
}
1158
din = dataconn(name, (off_t)-1, "r");
1159
if (din == NULL)
1160
goto done;
1161
set_buffer_size(fileno(din), 1);
1162
if (receive_data(din, fout) == 0) {
1163
if((*closefunc)(fout) < 0)
1164
perror_reply(552, name);
1165
else {
1166
if (unique)
1167
reply(226, "Transfer complete (unique file name:%s).",
1168
name);
1169
else
1170
reply(226, "Transfer complete.");
1171
}
1172
} else
1173
(*closefunc)(fout);
1174
fclose(din);
1175
data = -1;
1176
pdata = -1;
1177
done:
1178
LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count);
1179
}
1180
1181
static FILE *
1182
getdatasock(const char *mode, int domain)
1183
{
1184
int s, t, tries;
1185
1186
if (data >= 0)
1187
return (fdopen(data, mode));
1188
if (seteuid(0) < 0)
1189
fatal("Failed to seteuid");
1190
s = socket(domain, SOCK_STREAM, 0);
1191
if (s < 0)
1192
goto bad;
1193
socket_set_reuseaddr (s, 1);
1194
/* anchor socket to avoid multi-homing problems */
1195
socket_set_address_and_port (data_source,
1196
socket_get_address (ctrl_addr),
1197
socket_get_port (data_source));
1198
1199
for (tries = 1; ; tries++) {
1200
if (bind(s, data_source,
1201
socket_sockaddr_size (data_source)) >= 0)
1202
break;
1203
if (errno != EADDRINUSE || tries > 10)
1204
goto bad;
1205
sleep(tries);
1206
}
1207
if (seteuid(pw->pw_uid) < 0)
1208
fatal("Failed to seteuid");
1209
#ifdef IPTOS_THROUGHPUT
1210
socket_set_tos (s, IPTOS_THROUGHPUT);
1211
#endif
1212
return (fdopen(s, mode));
1213
bad:
1214
/* Return the real value of errno (close may change it) */
1215
t = errno;
1216
if (seteuid((uid_t)pw->pw_uid) < 0)
1217
fatal("Failed to seteuid");
1218
close(s);
1219
errno = t;
1220
return (NULL);
1221
}
1222
1223
static int
1224
accept_with_timeout(int socket,
1225
struct sockaddr *address,
1226
socklen_t *address_len,
1227
struct timeval *timeout)
1228
{
1229
int ret;
1230
fd_set rfd;
1231
FD_ZERO(&rfd);
1232
FD_SET(socket, &rfd);
1233
ret = select(socket + 1, &rfd, NULL, NULL, timeout);
1234
if(ret < 0)
1235
return ret;
1236
if(ret == 0) {
1237
errno = ETIMEDOUT;
1238
return -1;
1239
}
1240
return accept(socket, address, address_len);
1241
}
1242
1243
static FILE *
1244
dataconn(const char *name, off_t size, const char *mode)
1245
{
1246
char sizebuf[32];
1247
FILE *file;
1248
int domain, retry = 0;
1249
1250
file_size = size;
1251
byte_count = 0;
1252
if (size >= 0)
1253
snprintf(sizebuf, sizeof(sizebuf), " (%ld bytes)", (long)size);
1254
else
1255
*sizebuf = '\0';
1256
if (pdata >= 0) {
1257
struct sockaddr_storage from_ss;
1258
struct sockaddr *from = (struct sockaddr *)&from_ss;
1259
struct timeval timeout;
1260
int s;
1261
socklen_t fromlen = sizeof(from_ss);
1262
1263
timeout.tv_sec = 15;
1264
timeout.tv_usec = 0;
1265
s = accept_with_timeout(pdata, from, &fromlen, &timeout);
1266
if (s < 0) {
1267
reply(425, "Can't open data connection.");
1268
close(pdata);
1269
pdata = -1;
1270
return (NULL);
1271
}
1272
close(pdata);
1273
pdata = s;
1274
#if defined(IPTOS_THROUGHPUT)
1275
if (from->sa_family == AF_INET)
1276
socket_set_tos(s, IPTOS_THROUGHPUT);
1277
#endif
1278
reply(150, "Opening %s mode data connection for '%s'%s.",
1279
type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1280
return (fdopen(pdata, mode));
1281
}
1282
if (data >= 0) {
1283
reply(125, "Using existing data connection for '%s'%s.",
1284
name, sizebuf);
1285
usedefault = 1;
1286
return (fdopen(data, mode));
1287
}
1288
if (usedefault)
1289
data_dest = his_addr;
1290
usedefault = 1;
1291
/*
1292
* Default to using the same socket type as the ctrl address,
1293
* unless we know the type of the data address.
1294
*/
1295
domain = data_dest->sa_family;
1296
if (domain == PF_UNSPEC)
1297
domain = ctrl_addr->sa_family;
1298
1299
file = getdatasock(mode, domain);
1300
if (file == NULL) {
1301
char data_addr[256];
1302
1303
if (inet_ntop (data_source->sa_family,
1304
socket_get_address(data_source),
1305
data_addr, sizeof(data_addr)) == NULL)
1306
strlcpy (data_addr, "unknown address",
1307
sizeof(data_addr));
1308
1309
reply(425, "Can't create data socket (%s,%d): %s.",
1310
data_addr,
1311
socket_get_port (data_source),
1312
strerror(errno));
1313
return (NULL);
1314
}
1315
data = fileno(file);
1316
while (connect(data, data_dest,
1317
socket_sockaddr_size(data_dest)) < 0) {
1318
if (errno == EADDRINUSE && retry < swaitmax) {
1319
sleep(swaitint);
1320
retry += swaitint;
1321
continue;
1322
}
1323
perror_reply(425, "Can't build data connection");
1324
fclose(file);
1325
data = -1;
1326
return (NULL);
1327
}
1328
reply(150, "Opening %s mode data connection for '%s'%s.",
1329
type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1330
return (file);
1331
}
1332
1333
/*
1334
* Tranfer the contents of "instr" to "outstr" peer using the appropriate
1335
* encapsulation of the data subject * to Mode, Structure, and Type.
1336
*
1337
* NB: Form isn't handled.
1338
*/
1339
static void
1340
send_data(FILE *instr, FILE *outstr)
1341
{
1342
int c, cnt, filefd, netfd;
1343
static char *buf;
1344
static size_t bufsize;
1345
1346
transflag = 1;
1347
switch (type) {
1348
1349
case TYPE_A:
1350
while ((c = getc(instr)) != EOF) {
1351
if (urgflag && handleoobcmd())
1352
return;
1353
byte_count++;
1354
if(c == '\n')
1355
sec_putc('\r', outstr);
1356
sec_putc(c, outstr);
1357
}
1358
sec_fflush(outstr);
1359
transflag = 0;
1360
urgflag = 0;
1361
if (ferror(instr))
1362
goto file_err;
1363
if (ferror(outstr))
1364
goto data_err;
1365
reply(226, "Transfer complete.");
1366
return;
1367
1368
case TYPE_I:
1369
case TYPE_L:
1370
#if 0 /* XXX handle urg flag */
1371
#if defined(HAVE_MMAP) && !defined(NO_MMAP)
1372
#ifndef MAP_FAILED
1373
#define MAP_FAILED (-1)
1374
#endif
1375
{
1376
struct stat st;
1377
char *chunk;
1378
int in = fileno(instr);
1379
if(fstat(in, &st) == 0 && S_ISREG(st.st_mode)
1380
&& st.st_size > 0) {
1381
/*
1382
* mmap zero bytes has potential of loosing, don't do it.
1383
*/
1384
chunk = mmap(0, st.st_size, PROT_READ,
1385
MAP_SHARED, in, 0);
1386
if((void *)chunk != (void *)MAP_FAILED) {
1387
cnt = st.st_size - restart_point;
1388
sec_write(fileno(outstr), chunk + restart_point, cnt);
1389
if (munmap(chunk, st.st_size) < 0)
1390
warn ("munmap");
1391
sec_fflush(outstr);
1392
byte_count = cnt;
1393
transflag = 0;
1394
urgflag = 0;
1395
}
1396
}
1397
}
1398
#endif
1399
#endif
1400
if(transflag) {
1401
struct stat st;
1402
1403
netfd = fileno(outstr);
1404
filefd = fileno(instr);
1405
buf = alloc_buffer (buf, &bufsize,
1406
fstat(filefd, &st) >= 0 ? &st : NULL);
1407
if (buf == NULL) {
1408
transflag = 0;
1409
urgflag = 0;
1410
perror_reply(451, "Local resource failure: malloc");
1411
return;
1412
}
1413
while ((cnt = read(filefd, buf, bufsize)) > 0 &&
1414
sec_write(netfd, buf, cnt) == cnt) {
1415
byte_count += cnt;
1416
if (urgflag && handleoobcmd())
1417
return;
1418
}
1419
sec_fflush(outstr); /* to end an encrypted stream */
1420
transflag = 0;
1421
urgflag = 0;
1422
if (cnt != 0) {
1423
if (cnt < 0)
1424
goto file_err;
1425
goto data_err;
1426
}
1427
}
1428
reply(226, "Transfer complete.");
1429
return;
1430
default:
1431
transflag = 0;
1432
urgflag = 0;
1433
reply(550, "Unimplemented TYPE %d in send_data", type);
1434
return;
1435
}
1436
1437
data_err:
1438
transflag = 0;
1439
urgflag = 0;
1440
perror_reply(426, "Data connection");
1441
return;
1442
1443
file_err:
1444
transflag = 0;
1445
urgflag = 0;
1446
perror_reply(551, "Error on input file");
1447
}
1448
1449
/*
1450
* Transfer data from peer to "outstr" using the appropriate encapulation of
1451
* the data subject to Mode, Structure, and Type.
1452
*
1453
* N.B.: Form isn't handled.
1454
*/
1455
static int
1456
receive_data(FILE *instr, FILE *outstr)
1457
{
1458
int cnt, bare_lfs = 0;
1459
static char *buf;
1460
static size_t bufsize;
1461
struct stat st;
1462
1463
transflag = 1;
1464
1465
buf = alloc_buffer (buf, &bufsize,
1466
fstat(fileno(outstr), &st) >= 0 ? &st : NULL);
1467
if (buf == NULL) {
1468
transflag = 0;
1469
urgflag = 0;
1470
perror_reply(451, "Local resource failure: malloc");
1471
return -1;
1472
}
1473
1474
switch (type) {
1475
1476
case TYPE_I:
1477
case TYPE_L:
1478
while ((cnt = sec_read(fileno(instr), buf, bufsize)) > 0) {
1479
if (write(fileno(outstr), buf, cnt) != cnt)
1480
goto file_err;
1481
byte_count += cnt;
1482
if (urgflag && handleoobcmd())
1483
return (-1);
1484
}
1485
if (cnt < 0)
1486
goto data_err;
1487
transflag = 0;
1488
urgflag = 0;
1489
return (0);
1490
1491
case TYPE_E:
1492
reply(553, "TYPE E not implemented.");
1493
transflag = 0;
1494
urgflag = 0;
1495
return (-1);
1496
1497
case TYPE_A:
1498
{
1499
char *p, *q;
1500
int cr_flag = 0;
1501
while ((cnt = sec_read(fileno(instr),
1502
buf + cr_flag,
1503
bufsize - cr_flag)) > 0){
1504
if (urgflag && handleoobcmd())
1505
return (-1);
1506
byte_count += cnt;
1507
cnt += cr_flag;
1508
cr_flag = 0;
1509
for(p = buf, q = buf; p < buf + cnt;) {
1510
if(*p == '\n')
1511
bare_lfs++;
1512
if(*p == '\r') {
1513
if(p == buf + cnt - 1){
1514
cr_flag = 1;
1515
p++;
1516
continue;
1517
}else if(p[1] == '\n'){
1518
*q++ = '\n';
1519
p += 2;
1520
continue;
1521
}
1522
}
1523
*q++ = *p++;
1524
}
1525
fwrite(buf, q - buf, 1, outstr);
1526
if(cr_flag)
1527
buf[0] = '\r';
1528
}
1529
if(cr_flag)
1530
putc('\r', outstr);
1531
fflush(outstr);
1532
if (ferror(instr))
1533
goto data_err;
1534
if (ferror(outstr))
1535
goto file_err;
1536
transflag = 0;
1537
urgflag = 0;
1538
if (bare_lfs) {
1539
lreply(226, "WARNING! %d bare linefeeds received in ASCII mode\r\n"
1540
" File may not have transferred correctly.\r\n",
1541
bare_lfs);
1542
}
1543
return (0);
1544
}
1545
default:
1546
reply(550, "Unimplemented TYPE %d in receive_data", type);
1547
transflag = 0;
1548
urgflag = 0;
1549
return (-1);
1550
}
1551
1552
data_err:
1553
transflag = 0;
1554
urgflag = 0;
1555
perror_reply(426, "Data Connection");
1556
return (-1);
1557
1558
file_err:
1559
transflag = 0;
1560
urgflag = 0;
1561
perror_reply(452, "Error writing file");
1562
return (-1);
1563
}
1564
1565
void
1566
statfilecmd(char *filename)
1567
{
1568
FILE *fin;
1569
int c;
1570
char line[LINE_MAX];
1571
1572
snprintf(line, sizeof(line), "/bin/ls -la -- %s", filename);
1573
fin = ftpd_popen(line, "r", 1, 0);
1574
lreply(211, "status of %s:", filename);
1575
while ((c = getc(fin)) != EOF) {
1576
if (c == '\n') {
1577
if (ferror(stdout)){
1578
perror_reply(421, "control connection");
1579
ftpd_pclose(fin);
1580
dologout(1);
1581
/* NOTREACHED */
1582
}
1583
if (ferror(fin)) {
1584
perror_reply(551, filename);
1585
ftpd_pclose(fin);
1586
return;
1587
}
1588
putc('\r', stdout);
1589
}
1590
putc(c, stdout);
1591
}
1592
ftpd_pclose(fin);
1593
reply(211, "End of Status");
1594
}
1595
1596
void
1597
statcmd(void)
1598
{
1599
#if 0
1600
struct sockaddr_in *sin;
1601
u_char *a, *p;
1602
1603
lreply(211, "%s FTP server (%s) status:", hostname, version);
1604
printf(" %s\r\n", version);
1605
printf(" Connected to %s", remotehost);
1606
if (!isdigit((unsigned char)remotehost[0]))
1607
printf(" (%s)", inet_ntoa(his_addr.sin_addr));
1608
printf("\r\n");
1609
if (logged_in) {
1610
if (guest)
1611
printf(" Logged in anonymously\r\n");
1612
else
1613
printf(" Logged in as %s\r\n", pw->pw_name);
1614
} else if (askpasswd)
1615
printf(" Waiting for password\r\n");
1616
else
1617
printf(" Waiting for user name\r\n");
1618
printf(" TYPE: %s", typenames[type]);
1619
if (type == TYPE_A || type == TYPE_E)
1620
printf(", FORM: %s", formnames[form]);
1621
if (type == TYPE_L)
1622
#if NBBY == 8
1623
printf(" %d", NBBY);
1624
#else
1625
printf(" %d", bytesize); /* need definition! */
1626
#endif
1627
printf("; STRUcture: %s; transfer MODE: %s\r\n",
1628
strunames[stru], modenames[mode]);
1629
if (data != -1)
1630
printf(" Data connection open\r\n");
1631
else if (pdata != -1) {
1632
printf(" in Passive mode");
1633
sin = &pasv_addr;
1634
goto printaddr;
1635
} else if (usedefault == 0) {
1636
printf(" PORT");
1637
sin = &data_dest;
1638
printaddr:
1639
a = (u_char *) &sin->sin_addr;
1640
p = (u_char *) &sin->sin_port;
1641
#define UC(b) (((int) b) & 0xff)
1642
printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]),
1643
UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
1644
#undef UC
1645
} else
1646
printf(" No data connection\r\n");
1647
#endif
1648
reply(211, "End of status");
1649
}
1650
1651
void
1652
fatal(char *s)
1653
{
1654
1655
reply(451, "Error in server: %s\n", s);
1656
reply(221, "Closing connection due to server error.");
1657
dologout(0);
1658
/* NOTREACHED */
1659
}
1660
1661
static void
1662
int_reply(int, char *, const char *, va_list)
1663
#ifdef __GNUC__
1664
__attribute__ ((format (printf, 3, 0)))
1665
#endif
1666
;
1667
1668
static void
1669
int_reply(int n, char *c, const char *fmt, va_list ap)
1670
{
1671
char buf[10240];
1672
char *p;
1673
p=buf;
1674
if(n){
1675
snprintf(p, sizeof(buf), "%d%s", n, c);
1676
p+=strlen(p);
1677
}
1678
vsnprintf(p, sizeof(buf) - strlen(p), fmt, ap);
1679
p+=strlen(p);
1680
snprintf(p, sizeof(buf) - strlen(p), "\r\n");
1681
p+=strlen(p);
1682
sec_fprintf(stdout, "%s", buf);
1683
fflush(stdout);
1684
if (debug)
1685
syslog(LOG_DEBUG, "<--- %s- ", buf);
1686
}
1687
1688
void
1689
reply(int n, const char *fmt, ...)
1690
{
1691
va_list ap;
1692
va_start(ap, fmt);
1693
int_reply(n, " ", fmt, ap);
1694
delete_ftp_command();
1695
va_end(ap);
1696
}
1697
1698
void
1699
lreply(int n, const char *fmt, ...)
1700
{
1701
va_list ap;
1702
va_start(ap, fmt);
1703
int_reply(n, "-", fmt, ap);
1704
va_end(ap);
1705
}
1706
1707
void
1708
nreply(const char *fmt, ...)
1709
{
1710
va_list ap;
1711
va_start(ap, fmt);
1712
int_reply(0, NULL, fmt, ap);
1713
va_end(ap);
1714
}
1715
1716
static void
1717
ack(char *s)
1718
{
1719
1720
reply(250, "%s command successful.", s);
1721
}
1722
1723
void
1724
nack(char *s)
1725
{
1726
1727
reply(502, "%s command not implemented.", s);
1728
}
1729
1730
void
1731
do_delete(char *name)
1732
{
1733
struct stat st;
1734
1735
LOGCMD("delete", name);
1736
if (stat(name, &st) < 0) {
1737
perror_reply(550, name);
1738
return;
1739
}
1740
if (S_ISDIR(st.st_mode)) {
1741
if (rmdir(name) < 0) {
1742
perror_reply(550, name);
1743
return;
1744
}
1745
goto done;
1746
}
1747
if (unlink(name) < 0) {
1748
perror_reply(550, name);
1749
return;
1750
}
1751
done:
1752
ack("DELE");
1753
}
1754
1755
void
1756
cwd(const char *path)
1757
{
1758
1759
if (chdir(path) < 0)
1760
perror_reply(550, path);
1761
else
1762
ack("CWD");
1763
}
1764
1765
void
1766
makedir(char *name)
1767
{
1768
1769
LOGCMD("mkdir", name);
1770
if(guest && filename_check(name))
1771
return;
1772
if (mkdir(name, 0777) < 0)
1773
perror_reply(550, name);
1774
else{
1775
if(guest)
1776
chmod(name, 0700); /* guest has umask 777 */
1777
reply(257, "MKD command successful.");
1778
}
1779
}
1780
1781
void
1782
removedir(char *name)
1783
{
1784
1785
LOGCMD("rmdir", name);
1786
if (rmdir(name) < 0)
1787
perror_reply(550, name);
1788
else
1789
ack("RMD");
1790
}
1791
1792
void
1793
pwd(void)
1794
{
1795
char path[MaxPathLen];
1796
char *ret;
1797
1798
/* SunOS has a broken getcwd that does popen(pwd) (!!!), this
1799
* failes miserably when running chroot
1800
*/
1801
ret = getcwd(path, sizeof(path));
1802
if (ret == NULL)
1803
reply(550, "%s.", strerror(errno));
1804
else
1805
reply(257, "\"%s\" is current directory.", path);
1806
}
1807
1808
char *
1809
renamefrom(char *name)
1810
{
1811
struct stat st;
1812
1813
if (stat(name, &st) < 0) {
1814
perror_reply(550, name);
1815
return NULL;
1816
}
1817
reply(350, "File exists, ready for destination name");
1818
return (name);
1819
}
1820
1821
void
1822
renamecmd(char *from, char *to)
1823
{
1824
1825
LOGCMD2("rename", from, to);
1826
if(guest && filename_check(to))
1827
return;
1828
if (rename(from, to) < 0)
1829
perror_reply(550, "rename");
1830
else
1831
ack("RNTO");
1832
}
1833
1834
static void
1835
dolog(struct sockaddr *sa, int len)
1836
{
1837
getnameinfo_verified (sa, len, remotehost, sizeof(remotehost),
1838
NULL, 0, 0);
1839
#ifdef HAVE_SETPROCTITLE
1840
snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
1841
setproctitle("%s", proctitle);
1842
#endif /* HAVE_SETPROCTITLE */
1843
1844
if (logging) {
1845
char data_addr[256];
1846
1847
if (inet_ntop (his_addr->sa_family,
1848
socket_get_address(his_addr),
1849
data_addr, sizeof(data_addr)) == NULL)
1850
strlcpy (data_addr, "unknown address",
1851
sizeof(data_addr));
1852
1853
1854
syslog(LOG_INFO, "connection from %s(%s)",
1855
remotehost,
1856
data_addr);
1857
}
1858
}
1859
1860
/*
1861
* Record logout in wtmp file
1862
* and exit with supplied status.
1863
*/
1864
void
1865
dologout(int status)
1866
{
1867
transflag = 0;
1868
urgflag = 0;
1869
if (logged_in) {
1870
#if KRB5
1871
cond_kdestroy();
1872
#endif
1873
seteuid((uid_t)0); /* No need to check, we call exit() below */
1874
ftpd_logwtmp(ttyline, "", "");
1875
}
1876
/* beware of flushing buffers after a SIGPIPE */
1877
#ifdef XXX
1878
exit(status);
1879
#else
1880
_exit(status);
1881
#endif
1882
}
1883
1884
void abor(void)
1885
{
1886
if (!transflag)
1887
return;
1888
reply(426, "Transfer aborted. Data connection closed.");
1889
reply(226, "Abort successful");
1890
transflag = 0;
1891
}
1892
1893
static void
1894
myoob(int signo)
1895
{
1896
urgflag = 1;
1897
}
1898
1899
static char *
1900
mec_space(char *p)
1901
{
1902
while(isspace(*(unsigned char *)p))
1903
p++;
1904
return p;
1905
}
1906
1907
static int
1908
handleoobcmd(void)
1909
{
1910
char *cp;
1911
1912
/* only process if transfer occurring */
1913
if (!transflag)
1914
return 0;
1915
1916
urgflag = 0;
1917
1918
cp = tmpline;
1919
if (ftpd_getline(cp, sizeof(tmpline)) == NULL) {
1920
reply(221, "You could at least say goodbye.");
1921
dologout(0);
1922
}
1923
1924
if (strncasecmp("MIC", cp, 3) == 0) {
1925
mec(mec_space(cp + 3), prot_safe);
1926
} else if (strncasecmp("CONF", cp, 4) == 0) {
1927
mec(mec_space(cp + 4), prot_confidential);
1928
} else if (strncasecmp("ENC", cp, 3) == 0) {
1929
mec(mec_space(cp + 3), prot_private);
1930
} else if (!allow_insecure_oob) {
1931
reply(533, "Command protection level denied "
1932
"for paranoid reasons.");
1933
goto out;
1934
}
1935
1936
if (secure_command())
1937
cp = ftp_command;
1938
1939
if (strcasecmp(cp, "ABOR\r\n") == 0) {
1940
abor();
1941
} else if (strcasecmp(cp, "STAT\r\n") == 0) {
1942
if (file_size != (off_t) -1)
1943
reply(213, "Status: %ld of %ld bytes transferred",
1944
(long)byte_count,
1945
(long)file_size);
1946
else
1947
reply(213, "Status: %ld bytes transferred",
1948
(long)byte_count);
1949
}
1950
out:
1951
return (transflag == 0);
1952
}
1953
1954
/*
1955
* Note: a response of 425 is not mentioned as a possible response to
1956
* the PASV command in RFC959. However, it has been blessed as
1957
* a legitimate response by Jon Postel in a telephone conversation
1958
* with Rick Adams on 25 Jan 89.
1959
*/
1960
void
1961
pasv(void)
1962
{
1963
socklen_t len;
1964
char *p, *a;
1965
struct sockaddr_in *sin;
1966
1967
if (ctrl_addr->sa_family != AF_INET) {
1968
reply(425,
1969
"You cannot do PASV with something that's not IPv4");
1970
return;
1971
}
1972
1973
if(pdata != -1)
1974
close(pdata);
1975
1976
pdata = socket(ctrl_addr->sa_family, SOCK_STREAM, 0);
1977
if (pdata < 0) {
1978
perror_reply(425, "Can't open passive connection");
1979
return;
1980
}
1981
pasv_addr->sa_family = ctrl_addr->sa_family;
1982
socket_set_address_and_port (pasv_addr,
1983
socket_get_address (ctrl_addr),
1984
0);
1985
socket_set_portrange(pdata, restricted_data_ports,
1986
pasv_addr->sa_family);
1987
if (seteuid(0) < 0)
1988
fatal("Failed to seteuid");
1989
if (bind(pdata, pasv_addr, socket_sockaddr_size (pasv_addr)) < 0) {
1990
if (seteuid(pw->pw_uid) < 0)
1991
fatal("Failed to seteuid");
1992
goto pasv_error;
1993
}
1994
if (seteuid(pw->pw_uid) < 0)
1995
fatal("Failed to seteuid");
1996
len = sizeof(pasv_addr_ss);
1997
if (getsockname(pdata, pasv_addr, &len) < 0)
1998
goto pasv_error;
1999
if (listen(pdata, 1) < 0)
2000
goto pasv_error;
2001
sin = (struct sockaddr_in *)pasv_addr;
2002
a = (char *) &sin->sin_addr;
2003
p = (char *) &sin->sin_port;
2004
2005
#define UC(b) (((int) b) & 0xff)
2006
2007
reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
2008
UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
2009
return;
2010
2011
pasv_error:
2012
close(pdata);
2013
pdata = -1;
2014
perror_reply(425, "Can't open passive connection");
2015
return;
2016
}
2017
2018
void
2019
epsv(char *proto)
2020
{
2021
socklen_t len;
2022
2023
pdata = socket(ctrl_addr->sa_family, SOCK_STREAM, 0);
2024
if (pdata < 0) {
2025
perror_reply(425, "Can't open passive connection");
2026
return;
2027
}
2028
pasv_addr->sa_family = ctrl_addr->sa_family;
2029
socket_set_address_and_port (pasv_addr,
2030
socket_get_address (ctrl_addr),
2031
0);
2032
socket_set_portrange(pdata, restricted_data_ports,
2033
pasv_addr->sa_family);
2034
if (seteuid(0) < 0)
2035
fatal("Failed to seteuid");
2036
if (bind(pdata, pasv_addr, socket_sockaddr_size (pasv_addr)) < 0) {
2037
if (seteuid(pw->pw_uid))
2038
fatal("Failed to seteuid");
2039
goto pasv_error;
2040
}
2041
if (seteuid(pw->pw_uid) < 0)
2042
fatal("Failed to seteuid");
2043
len = sizeof(pasv_addr_ss);
2044
if (getsockname(pdata, pasv_addr, &len) < 0)
2045
goto pasv_error;
2046
if (listen(pdata, 1) < 0)
2047
goto pasv_error;
2048
2049
reply(229, "Entering Extended Passive Mode (|||%d|)",
2050
ntohs(socket_get_port (pasv_addr)));
2051
return;
2052
2053
pasv_error:
2054
close(pdata);
2055
pdata = -1;
2056
perror_reply(425, "Can't open passive connection");
2057
return;
2058
}
2059
2060
void
2061
eprt(char *str)
2062
{
2063
char *end;
2064
char sep;
2065
int af;
2066
int ret;
2067
int port;
2068
2069
usedefault = 0;
2070
if (pdata >= 0) {
2071
close(pdata);
2072
pdata = -1;
2073
}
2074
2075
sep = *str++;
2076
if (sep == '\0') {
2077
reply(500, "Bad syntax in EPRT");
2078
return;
2079
}
2080
af = strtol (str, &end, 0);
2081
if (af == 0 || *end != sep) {
2082
reply(500, "Bad syntax in EPRT");
2083
return;
2084
}
2085
str = end + 1;
2086
switch (af) {
2087
#ifdef HAVE_IPV6
2088
case 2 :
2089
data_dest->sa_family = AF_INET6;
2090
break;
2091
#endif
2092
case 1 :
2093
data_dest->sa_family = AF_INET;
2094
break;
2095
default :
2096
reply(522, "Network protocol %d not supported, use (1"
2097
#ifdef HAVE_IPV6
2098
",2"
2099
#endif
2100
")", af);
2101
return;
2102
}
2103
end = strchr (str, sep);
2104
if (end == NULL) {
2105
reply(500, "Bad syntax in EPRT");
2106
return;
2107
}
2108
*end = '\0';
2109
ret = inet_pton (data_dest->sa_family, str,
2110
socket_get_address (data_dest));
2111
2112
if (ret != 1) {
2113
reply(500, "Bad address syntax in EPRT");
2114
return;
2115
}
2116
str = end + 1;
2117
port = strtol (str, &end, 0);
2118
if (port == 0 || *end != sep) {
2119
reply(500, "Bad port syntax in EPRT");
2120
return;
2121
}
2122
if (port < IPPORT_RESERVED) {
2123
reply(500, "Bad port in invalid range in EPRT");
2124
return;
2125
}
2126
socket_set_port (data_dest, htons(port));
2127
2128
if (paranoid &&
2129
(data_dest->sa_family != his_addr->sa_family ||
2130
memcmp(socket_get_address(data_dest), socket_get_address(his_addr), socket_sockaddr_size(data_dest)) != 0))
2131
{
2132
reply(500, "Bad address in EPRT");
2133
}
2134
reply(200, "EPRT command successful.");
2135
}
2136
2137
/*
2138
* Generate unique name for file with basename "local".
2139
* The file named "local" is already known to exist.
2140
* Generates failure reply on error.
2141
*/
2142
static char *
2143
gunique(char *local)
2144
{
2145
static char new[MaxPathLen];
2146
struct stat st;
2147
int count;
2148
char *cp;
2149
2150
cp = strrchr(local, '/');
2151
if (cp)
2152
*cp = '\0';
2153
if (stat(cp ? local : ".", &st) < 0) {
2154
perror_reply(553, cp ? local : ".");
2155
return NULL;
2156
}
2157
if (cp)
2158
*cp = '/';
2159
for (count = 1; count < 100; count++) {
2160
snprintf (new, sizeof(new), "%s.%d", local, count);
2161
if (stat(new, &st) < 0)
2162
return (new);
2163
}
2164
reply(452, "Unique file name cannot be created.");
2165
return (NULL);
2166
}
2167
2168
/*
2169
* Format and send reply containing system error number.
2170
*/
2171
void
2172
perror_reply(int code, const char *string)
2173
{
2174
reply(code, "%s: %s.", string, strerror(errno));
2175
}
2176
2177
static char *onefile[] = {
2178
"",
2179
0
2180
};
2181
2182
void
2183
list_file(char *file)
2184
{
2185
if(use_builtin_ls) {
2186
FILE *dout;
2187
dout = dataconn(file, -1, "w");
2188
if (dout == NULL)
2189
return;
2190
set_buffer_size(fileno(dout), 0);
2191
if(builtin_ls(dout, file) == 0)
2192
reply(226, "Transfer complete.");
2193
else
2194
reply(451, "Requested action aborted. Local error in processing.");
2195
fclose(dout);
2196
data = -1;
2197
pdata = -1;
2198
} else {
2199
#ifdef HAVE_LS_A
2200
const char *cmd = "/bin/ls -lA %s";
2201
#else
2202
const char *cmd = "/bin/ls -la %s";
2203
#endif
2204
retrieve(cmd, file);
2205
}
2206
}
2207
2208
void
2209
send_file_list(char *whichf)
2210
{
2211
struct stat st;
2212
DIR *dirp = NULL;
2213
struct dirent *dir;
2214
FILE *dout = NULL;
2215
char **dirlist, *dirname;
2216
int simple = 0;
2217
int freeglob = 0;
2218
glob_t gl;
2219
char buf[MaxPathLen];
2220
2221
if (strpbrk(whichf, "~{[*?") != NULL) {
2222
int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE|
2223
#ifdef GLOB_MAXPATH
2224
GLOB_MAXPATH
2225
#else
2226
GLOB_LIMIT
2227
#endif
2228
;
2229
2230
memset(&gl, 0, sizeof(gl));
2231
freeglob = 1;
2232
if (glob(whichf, flags, 0, &gl)) {
2233
reply(550, "not found");
2234
goto out;
2235
} else if (gl.gl_pathc == 0) {
2236
errno = ENOENT;
2237
perror_reply(550, whichf);
2238
goto out;
2239
}
2240
dirlist = gl.gl_pathv;
2241
} else {
2242
onefile[0] = whichf;
2243
dirlist = onefile;
2244
simple = 1;
2245
}
2246
2247
while ((dirname = *dirlist++)) {
2248
2249
if (urgflag && handleoobcmd())
2250
goto out;
2251
2252
if (stat(dirname, &st) < 0) {
2253
/*
2254
* If user typed "ls -l", etc, and the client
2255
* used NLST, do what the user meant.
2256
*/
2257
if (dirname[0] == '-' && *dirlist == NULL &&
2258
transflag == 0) {
2259
list_file(dirname);
2260
goto out;
2261
}
2262
perror_reply(550, whichf);
2263
goto out;
2264
}
2265
2266
if (S_ISREG(st.st_mode)) {
2267
if (dout == NULL) {
2268
dout = dataconn("file list", (off_t)-1, "w");
2269
if (dout == NULL)
2270
goto out;
2271
transflag = 1;
2272
}
2273
snprintf(buf, sizeof(buf), "%s%s\n", dirname,
2274
type == TYPE_A ? "\r" : "");
2275
sec_write(fileno(dout), buf, strlen(buf));
2276
byte_count += strlen(dirname) + 1;
2277
continue;
2278
} else if (!S_ISDIR(st.st_mode))
2279
continue;
2280
2281
if ((dirp = opendir(dirname)) == NULL)
2282
continue;
2283
2284
while ((dir = readdir(dirp)) != NULL) {
2285
char nbuf[MaxPathLen];
2286
2287
if (urgflag && handleoobcmd())
2288
goto out;
2289
2290
if (!strcmp(dir->d_name, "."))
2291
continue;
2292
if (!strcmp(dir->d_name, ".."))
2293
continue;
2294
2295
snprintf(nbuf, sizeof(nbuf), "%s/%s", dirname, dir->d_name);
2296
2297
/*
2298
* We have to do a stat to insure it's
2299
* not a directory or special file.
2300
*/
2301
if (simple || (stat(nbuf, &st) == 0 &&
2302
S_ISREG(st.st_mode))) {
2303
if (dout == NULL) {
2304
dout = dataconn("file list", (off_t)-1, "w");
2305
if (dout == NULL)
2306
goto out;
2307
transflag = 1;
2308
}
2309
if(strncmp(nbuf, "./", 2) == 0)
2310
snprintf(buf, sizeof(buf), "%s%s\n", nbuf +2,
2311
type == TYPE_A ? "\r" : "");
2312
else
2313
snprintf(buf, sizeof(buf), "%s%s\n", nbuf,
2314
type == TYPE_A ? "\r" : "");
2315
sec_write(fileno(dout), buf, strlen(buf));
2316
byte_count += strlen(nbuf) + 1;
2317
}
2318
}
2319
closedir(dirp);
2320
}
2321
if (dout == NULL)
2322
reply(550, "No files found.");
2323
else if (ferror(dout) != 0)
2324
perror_reply(550, "Data connection");
2325
else
2326
reply(226, "Transfer complete.");
2327
2328
out:
2329
transflag = 0;
2330
if (dout != NULL){
2331
sec_write(fileno(dout), buf, 0); /* XXX flush */
2332
2333
fclose(dout);
2334
}
2335
data = -1;
2336
pdata = -1;
2337
if (freeglob)
2338
globfree(&gl);
2339
}
2340
2341
2342
int
2343
find(char *pattern)
2344
{
2345
char line[1024];
2346
FILE *f;
2347
2348
snprintf(line, sizeof(line),
2349
"/bin/locate -d %s -- %s",
2350
ftp_rooted("/etc/locatedb"),
2351
pattern);
2352
f = ftpd_popen(line, "r", 1, 1);
2353
if(f == NULL){
2354
perror_reply(550, "/bin/locate");
2355
return 1;
2356
}
2357
lreply(200, "Output from find.");
2358
while(fgets(line, sizeof(line), f)){
2359
if(line[strlen(line)-1] == '\n')
2360
line[strlen(line)-1] = 0;
2361
nreply("%s", line);
2362
}
2363
reply(200, "Done");
2364
ftpd_pclose(f);
2365
return 0;
2366
}
2367
2368
2369